[Bug-Fix] Fix bug that show view report "Unresolved table reference" error (#6184)

This commit is contained in:
xy720
2021-07-15 10:55:15 +08:00
committed by GitHub
parent 39945aba1e
commit 7c34dbbc5b
10 changed files with 253 additions and 77 deletions

View File

@ -429,9 +429,9 @@ public abstract class QueryStmt extends StatementBase {
}
}
public void getWithClauseTableRefs(List<TableRef> tblRefs, Set<String> parentViewNameSet) {
public void getWithClauseTableRefs(Analyzer analyzer, List<TableRef> tblRefs, Set<String> parentViewNameSet) {
if (withClause_ != null) {
withClause_.getTableRefs(tblRefs, parentViewNameSet);
withClause_.getTableRefs(analyzer, tblRefs, parentViewNameSet);
}
}
@ -446,7 +446,7 @@ public abstract class QueryStmt extends StatementBase {
// get TableRefs in this query, including physical TableRefs of this statement and
// nested statements of inline views and with_Clause.
public abstract void getTableRefs(List<TableRef> tblRefs, Set<String> parentViewNameSet);
public abstract void getTableRefs(Analyzer analyzer, List<TableRef> tblRefs, Set<String> parentViewNameSet);
/**
* UnionStmt and SelectStmt have different implementations.

View File

@ -324,17 +324,22 @@ public class SelectStmt extends QueryStmt {
}
@Override
public void getTableRefs(List<TableRef> tblRefs, Set<String> parentViewNameSet) {
getWithClauseTableRefs(tblRefs, parentViewNameSet);
public void getTableRefs(Analyzer analyzer, List<TableRef> tblRefs, Set<String> parentViewNameSet) {
getWithClauseTableRefs(analyzer, tblRefs, parentViewNameSet);
for (TableRef tblRef : fromClause_) {
if (tblRef instanceof InlineViewRef) {
QueryStmt inlineStmt = ((InlineViewRef) tblRef).getViewStmt();
inlineStmt.getTableRefs(tblRefs, parentViewNameSet);
} else {
if (isViewTableRef(tblRef.getName().toString(), parentViewNameSet)) {
continue;
try {
TableRef tmpTblRef = analyzer.resolveTableRef(tblRef);
if (tmpTblRef instanceof InlineViewRef) {
QueryStmt inlineStmt = ((InlineViewRef) tmpTblRef).getViewStmt();
inlineStmt.getTableRefs(analyzer, tblRefs, parentViewNameSet);
} else {
if (isViewTableRef(tmpTblRef.getName().toString(), parentViewNameSet)) {
continue;
}
tblRefs.add(tmpTblRef);
}
tblRefs.add(tblRef);
} catch (AnalysisException e) {
// This table may have been dropped, ignore it.
}
}
}

View File

@ -180,10 +180,10 @@ public class SetOperationStmt extends QueryStmt {
}
@Override
public void getTableRefs(List<TableRef> tblRefs, Set<String> parentViewNameSet) {
getWithClauseTableRefs(tblRefs, parentViewNameSet);
public void getTableRefs(Analyzer analyzer, List<TableRef> tblRefs, Set<String> parentViewNameSet) {
getWithClauseTableRefs(analyzer, tblRefs, parentViewNameSet);
for (SetOperand op : operands) {
op.getQueryStmt().getTableRefs(tblRefs, parentViewNameSet);
op.getQueryStmt().getTableRefs(analyzer, tblRefs, parentViewNameSet);
}
}

View File

@ -114,9 +114,9 @@ public class ShowViewStmt extends ShowStmt {
View view = (View) table;
List<TableRef> tblRefs = Lists.newArrayList();
// get table refs instead of get tables because it don't need to check table's validity
getTableRefs(view, tblRefs);
getTableRefs(analyzer, view, tblRefs);
for (TableRef tblRef : tblRefs) {
tblRef.analyze(analyzer);
tblRef.getName().analyze(analyzer);
if (tblRef.getName().equals(tbl)) {
matchViews.add(view);
}
@ -124,10 +124,10 @@ public class ShowViewStmt extends ShowStmt {
}
}
private void getTableRefs(View view, List<TableRef> tblRefs) {
private void getTableRefs(Analyzer analyzer, View view, List<TableRef> tblRefs) {
Set<String> parentViewNameSet = Sets.newHashSet();
QueryStmt queryStmt = view.getQueryStmt();
queryStmt.getTableRefs(tblRefs, parentViewNameSet);
queryStmt.getTableRefs(analyzer, tblRefs, parentViewNameSet);
}
@Override

View File

@ -113,11 +113,11 @@ public class WithClause implements ParseNode {
}
}
public void getTableRefs(List<TableRef> tblRefs, Set<String> parentViewNameSet) {
public void getTableRefs(Analyzer analyzer, List<TableRef> tblRefs, Set<String> parentViewNameSet) {
for (View view : views_) {
QueryStmt stmt = view.getQueryStmt();
parentViewNameSet.add(view.getName());
stmt.getTableRefs(tblRefs, parentViewNameSet);
stmt.getTableRefs(analyzer, tblRefs, parentViewNameSet);
}
}

View File

@ -25,16 +25,9 @@ import org.apache.doris.qe.ConnectContext;
import org.apache.doris.qe.VariableMgr;
import org.apache.doris.utframe.DorisAssert;
import org.apache.doris.utframe.UtFrameUtils;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import mockit.Mock;
import mockit.MockUp;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
@ -42,6 +35,12 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import mockit.Mock;
import mockit.MockUp;
public class SelectStmtTest {
private static String runningDir = "fe/mocked/DemoTest/" + UUID.randomUUID().toString() + "/";
private static DorisAssert dorisAssert;
@ -581,7 +580,7 @@ public class SelectStmtTest {
QueryStmt stmt = (QueryStmt) UtFrameUtils.parseAndAnalyzeStmt(sql, ctx);
List<TableRef> tblRefs = Lists.newArrayList();
Set<String> parentViewNameSet = Sets.newHashSet();
stmt.getTableRefs(tblRefs, parentViewNameSet);
stmt.getTableRefs(new Analyzer(ctx.getCatalog(), ctx), tblRefs, parentViewNameSet);
Assert.assertEquals(2, tblRefs.size());
Assert.assertEquals("table1", tblRefs.get(0).getName().getTbl());

View File

@ -1,80 +1,238 @@
package org.apache.doris.analysis;
import org.apache.doris.catalog.Catalog;
import org.apache.doris.common.UserException;
import org.apache.doris.common.util.SqlParserUtils;
import org.apache.doris.mysql.privilege.MockedAuth;
import org.apache.doris.mysql.privilege.PaloAuth;
import org.apache.doris.qe.ConnectContext;
import org.apache.doris.qe.ShowExecutor;
import org.apache.doris.qe.ShowResultSet;
import org.apache.doris.utframe.DorisAssert;
import org.apache.doris.utframe.UtFrameUtils;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import java.io.StringReader;
import java.util.List;
import java.util.Set;
import mockit.Expectations;
import mockit.Mocked;
import java.util.UUID;
public class ShowViewStmtTest {
private Analyzer analyzer;
private Catalog catalog;
private static String runningDir = "fe/mocked/ShowViewTest/" + UUID.randomUUID().toString() + "/";
private static DorisAssert dorisAssert;
@Mocked
private PaloAuth auth;
@Mocked
private ConnectContext ctx;
@AfterClass
public static void tearDown() throws Exception {
UtFrameUtils.cleanDorisFeDir(runningDir);
}
@Before
public void setUp() {
analyzer = AccessTestUtil.fetchAdminAnalyzer(true);
catalog = AccessTestUtil.fetchAdminCatalog();
MockedAuth.mockedAuth(auth);
MockedAuth.mockedConnectContext(ctx, "root", "192.168.1.1");
@BeforeClass
public static void setUp() throws Exception {
UtFrameUtils.createMinDorisCluster(runningDir);
String testTbl1 = "CREATE TABLE `test1` (\n" +
" `a` int(11) NOT NULL COMMENT \"\",\n" +
" `b` int(11) NOT NULL COMMENT \"\"\n" +
") ENGINE=OLAP\n" +
"UNIQUE KEY(`a`)\n" +
"COMMENT \"OLAP\"\n" +
"DISTRIBUTED BY HASH(`a`) BUCKETS 8\n" +
"PROPERTIES (\n" +
"\"replication_num\" = \"1\",\n" +
"\"in_memory\" = \"false\",\n" +
"\"storage_format\" = \"V2\"\n" +
");";
String testTbl2 = "CREATE TABLE `test2` (\n" +
" `c` int(11) NOT NULL COMMENT \"\",\n" +
" `d` int(11) NOT NULL COMMENT \"\"\n" +
") ENGINE=OLAP\n" +
"UNIQUE KEY(`c`)\n" +
"COMMENT \"OLAP\"\n" +
"DISTRIBUTED BY HASH(`c`) BUCKETS 8\n" +
"PROPERTIES (\n" +
"\"replication_num\" = \"1\",\n" +
"\"in_memory\" = \"false\",\n" +
"\"storage_format\" = \"V2\"\n" +
");";
String testTbl3 = "CREATE TABLE `test3` (\n" +
" `e` int(11) NOT NULL COMMENT \"\",\n" +
" `f` int(11) NOT NULL COMMENT \"\"\n" +
") ENGINE=OLAP\n" +
"UNIQUE KEY(`e`)\n" +
"COMMENT \"OLAP\"\n" +
"DISTRIBUTED BY HASH(`e`) BUCKETS 8\n" +
"PROPERTIES (\n" +
"\"replication_num\" = \"1\",\n" +
"\"in_memory\" = \"false\",\n" +
"\"storage_format\" = \"V2\"\n" +
");";
dorisAssert = new DorisAssert();
dorisAssert.withDatabase("testDb").useDatabase("testDb");
dorisAssert.withTable(testTbl1)
.withTable(testTbl2)
.withTable(testTbl3);
}
@Test
public void testNormal() throws UserException {
new Expectations(catalog) {
{
Catalog.getCurrentCatalog();
result = catalog;
}
};
ShowViewStmt stmt = new ShowViewStmt("", new TableName("testDb", "testTbl"));
stmt.analyze(analyzer);
Assert.assertEquals("SHOW VIEW FROM `testCluster:testDb`.`testTbl`", stmt.toString());
Assert.assertEquals("testCluster:testDb", stmt.getDb());
Assert.assertEquals("testTbl", stmt.getTbl());
public void testNormal() throws Exception {
ConnectContext ctx = UtFrameUtils.createDefaultCtx();
ShowViewStmt stmt = new ShowViewStmt("", new TableName("testDb", "test1"));
stmt.analyze(new Analyzer(ctx.getCatalog(), ctx));
Assert.assertEquals("SHOW VIEW FROM `default_cluster:testDb`.`test1`", stmt.toString());
Assert.assertEquals("default_cluster:testDb", stmt.getDb());
Assert.assertEquals("test1", stmt.getTbl());
Assert.assertEquals(2, stmt.getMetaData().getColumnCount());
Assert.assertEquals("View", stmt.getMetaData().getColumn(0).getName());
Assert.assertEquals("Create View", stmt.getMetaData().getColumn(1).getName());
}
@Test(expected = UserException.class)
public void testNoDb() throws UserException {
public void testNoDb() throws Exception {
ConnectContext ctx = UtFrameUtils.createDefaultCtx();
ShowViewStmt stmt = new ShowViewStmt("", new TableName("", "testTbl"));
stmt.analyze(analyzer);
stmt.analyze(new Analyzer(ctx.getCatalog(), ctx));
Assert.fail();
}
@Test
public void testShowView() throws Exception {
ConnectContext ctx = UtFrameUtils.createDefaultCtx();
String testView1 = "CREATE VIEW `view1` as \n" +
"SELECT a, b FROM test1;";
dorisAssert.withView(testView1);
ShowViewStmt stmt = new ShowViewStmt("", new TableName("testDb", "test1"));
stmt.analyze(new Analyzer(ctx.getCatalog(), ctx));
ShowExecutor executor = new ShowExecutor(ctx, stmt);
ShowResultSet resultSet = executor.execute();
System.out.println(resultSet.getResultRows());
Assert.assertEquals(1, resultSet.getResultRows().size());
Assert.assertTrue(resultSet.next());
Assert.assertEquals("view1", resultSet.getString(0));
Assert.assertFalse(resultSet.next());
dorisAssert.dropView("view1");
}
@Test
public void testShowViewWithJoin() throws Exception {
ConnectContext ctx = UtFrameUtils.createDefaultCtx();
String testView2 = "CREATE VIEW `view2` as \n" +
"SELECT a, c FROM test1 \n" +
"LEFT OUTER JOIN test2 \n" +
"ON test1.a = test2.c;";
dorisAssert.withView(testView2);
ShowViewStmt stmt = new ShowViewStmt("", new TableName("testDb", "test1"));
stmt.analyze(new Analyzer(ctx.getCatalog(), ctx));
ShowExecutor executor = new ShowExecutor(ctx, stmt);
ShowResultSet resultSet = executor.execute();
System.out.println(resultSet.getResultRows());
Assert.assertEquals(1, resultSet.getResultRows().size());
Assert.assertTrue(resultSet.next());
Assert.assertEquals("view2", resultSet.getString(0));
Assert.assertFalse(resultSet.next());
stmt = new ShowViewStmt("", new TableName("testDb", "test2"));
stmt.analyze(new Analyzer(ctx.getCatalog(), ctx));
executor = new ShowExecutor(ctx, stmt);
resultSet = executor.execute();
System.out.println(resultSet.getResultRows());
Assert.assertEquals(1, resultSet.getResultRows().size());
Assert.assertTrue(resultSet.next());
Assert.assertEquals("view2", resultSet.getString(0));
Assert.assertFalse(resultSet.next());
dorisAssert.dropView("view2");
}
@Test
public void testShowViewWithNestedSqlView() throws Exception {
ConnectContext ctx = UtFrameUtils.createDefaultCtx();
String testView3 = "CREATE VIEW `view3` as \n" +
"SELECT a, d FROM test1 \n" +
"LEFT OUTER JOIN \n" +
"(SELECT d, e FROM test3 LEFT OUTER JOIN test2 ON test3.e = test2.c) test4 \n" +
"ON test1.a = test4.e;";
dorisAssert.withView(testView3);
ShowViewStmt stmt = new ShowViewStmt("", new TableName("testDb", "test1"));
stmt.analyze(new Analyzer(ctx.getCatalog(), ctx));
ShowExecutor executor = new ShowExecutor(ctx, stmt);
ShowResultSet resultSet = executor.execute();
System.out.println(resultSet.getResultRows());
Assert.assertEquals(1, resultSet.getResultRows().size());
Assert.assertTrue(resultSet.next());
Assert.assertEquals("view3", resultSet.getString(0));
Assert.assertFalse(resultSet.next());
stmt = new ShowViewStmt("", new TableName("testDb", "test2"));
stmt.analyze(new Analyzer(ctx.getCatalog(), ctx));
executor = new ShowExecutor(ctx, stmt);
resultSet = executor.execute();
System.out.println(resultSet.getResultRows());
Assert.assertEquals(1, resultSet.getResultRows().size());
Assert.assertTrue(resultSet.next());
Assert.assertEquals("view3", resultSet.getString(0));
Assert.assertFalse(resultSet.next());
stmt = new ShowViewStmt("", new TableName("testDb", "test3"));
stmt.analyze(new Analyzer(ctx.getCatalog(), ctx));
executor = new ShowExecutor(ctx, stmt);
resultSet = executor.execute();
System.out.println(resultSet.getResultRows());
Assert.assertEquals(1, resultSet.getResultRows().size());
Assert.assertTrue(resultSet.next());
Assert.assertEquals("view3", resultSet.getString(0));
Assert.assertFalse(resultSet.next());
dorisAssert.dropView("view3");
}
@Test
public void testShowViewWithNestedView() throws Exception {
ConnectContext ctx = UtFrameUtils.createDefaultCtx();
String testView4 = "CREATE VIEW `view4` as \n" +
"SELECT a, b FROM test1;";
String testView5 = "CREATE VIEW `view5` as \n" +
"SELECT c FROM test2 \n" +
"LEFT OUTER JOIN view4 \n" +
"ON test2.c = view4.a;";
dorisAssert.withView(testView4);
dorisAssert.withView(testView5);
ShowViewStmt stmt = new ShowViewStmt("", new TableName("testDb", "test1"));
stmt.analyze(new Analyzer(ctx.getCatalog(), ctx));
ShowExecutor executor = new ShowExecutor(ctx, stmt);
ShowResultSet resultSet = executor.execute();
System.out.println(resultSet.getResultRows());
Assert.assertEquals(2, resultSet.getResultRows().size());
Assert.assertTrue(resultSet.next());
Assert.assertEquals("view4", resultSet.getString(0));
Assert.assertTrue(resultSet.next());
Assert.assertEquals("view5", resultSet.getString(0));
dorisAssert.dropView("view4")
.dropView("view5");
}
@Test
public void testGetTableRefs() throws Exception {
String sql = "with w as (select a from db1.test1) " +
"select b, c from db1.test2 " +
ConnectContext ctx = UtFrameUtils.createDefaultCtx();
String sql = "with w as (select a from testDb.test1) " +
"select c, d from testDb.test2 " +
"left outer join " +
"(select d from db1.test3 join w on db1.test3.e = w.a) test4 " +
"on test1.f = test4.d";
"(select e from testDb.test3 join w on testDb.test3.e = w.a) test4 " +
"on test1.b = test4.d";
SqlScanner input = new SqlScanner(new StringReader(sql));
SqlParser parser = new SqlParser(input);
QueryStmt queryStmt = (QueryStmt) SqlParserUtils.getFirstStmt(parser);
List<TableRef> tblRefs = Lists.newArrayList();
Set<String> parentViewNameSet = Sets.newHashSet();
queryStmt.getTableRefs(tblRefs, parentViewNameSet);
queryStmt.getTableRefs(new Analyzer(ctx.getCatalog(), ctx), tblRefs, parentViewNameSet);
Assert.assertEquals(3, tblRefs.size());
Assert.assertEquals("test1", tblRefs.get(0).getName().getTbl());

View File

@ -22,6 +22,7 @@ import org.apache.doris.analysis.AlterTableStmt;
import org.apache.doris.analysis.CreateDbStmt;
import org.apache.doris.analysis.CreateMaterializedViewStmt;
import org.apache.doris.analysis.CreateTableStmt;
import org.apache.doris.analysis.CreateViewStmt;
import org.apache.doris.analysis.DropTableStmt;
import org.apache.doris.analysis.ExplainOptions;
import org.apache.doris.analysis.SqlParser;
@ -93,6 +94,19 @@ public class DorisAssert {
return this;
}
public DorisAssert withView(String sql) throws Exception {
CreateViewStmt createViewStmt = (CreateViewStmt) UtFrameUtils.parseAndAnalyzeStmt(sql, ctx);
Catalog.getCurrentCatalog().createView(createViewStmt);
return this;
}
public DorisAssert dropView(String tableName) throws Exception {
DropTableStmt dropTableStmt =
(DropTableStmt) UtFrameUtils.parseAndAnalyzeStmt("drop view " + tableName + ";", ctx);
Catalog.getCurrentCatalog().dropTable(dropTableStmt);
return this;
}
// Add materialized view to the schema
public DorisAssert withMaterializedView(String sql) throws Exception {
CreateMaterializedViewStmt createMaterializedViewStmt =