This is an automated email from the ASF dual-hosted git repository. morningman pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/master by this push: new 04d26ddf22 [feature-wip](multi-catalog)Support use catalog.db and show databases from catalog stmt (#11338) 04d26ddf22 is described below commit 04d26ddf2256ebd8353ed769611edeb33b8efced Author: huangzhaowei <huangzhaowei....@bytedance.com> AuthorDate: Thu Aug 11 09:50:32 2022 +0800 [feature-wip](multi-catalog)Support use catalog.db and show databases from catalog stmt (#11338) Support use catalog.db and show databases from catalog stmt. --- .../Show-Statements/SHOW-DATABASES.md | 51 ++++++++++++++- .../sql-reference/Utility-Statements/USE.md | 13 +++- .../Show-Statements/SHOW-DATABASES.md | 53 +++++++++++++++- .../sql-reference/Utility-Statements/USE.md | 13 +++- fe/fe-core/src/main/cup/sql_parser.cup | 12 ++++ .../java/org/apache/doris/analysis/ShowDbStmt.java | 14 +++++ .../java/org/apache/doris/analysis/UseStmt.java | 18 +++++- .../java/org/apache/doris/qe/ConnectContext.java | 12 +++- .../java/org/apache/doris/qe/ConnectProcessor.java | 31 ++++++++- .../java/org/apache/doris/qe/ShowExecutor.java | 7 ++- .../java/org/apache/doris/qe/StmtExecutor.java | 3 + .../org/apache/doris/analysis/ShowDbStmtTest.java | 8 +++ .../org/apache/doris/analysis/UseStmtTest.java | 10 +++ .../java/org/apache/doris/qe/ShowExecutorTest.java | 10 +++ .../java/org/apache/doris/qe/StmtExecutorTest.java | 73 ++++++++++++++++++++++ 15 files changed, 316 insertions(+), 12 deletions(-) diff --git a/docs/en/docs/sql-manual/sql-reference/Show-Statements/SHOW-DATABASES.md b/docs/en/docs/sql-manual/sql-reference/Show-Statements/SHOW-DATABASES.md index e8461e1fd4..c2e972b5d5 100644 --- a/docs/en/docs/sql-manual/sql-reference/Show-Statements/SHOW-DATABASES.md +++ b/docs/en/docs/sql-manual/sql-reference/Show-Statements/SHOW-DATABASES.md @@ -37,10 +37,59 @@ This statement is used to display the currently visible db grammar: ```sql -SHOW DATABASES; +SHOW DATABASES [FROM catalog] [filter expr]; ```` +illustrate: +1. `SHOW DATABASES` will get all database names from current catalog. +2. `SHOW DATABASES FROM catalog` will all database names from the catalog named 'catalog'. +3. `SHOW DATABASES filter_expr` will get filtered database names from current catalog. +4. `SHOW DATABASES FROM catalog filter_expr` is not support yet. + ### Example +1. Display all the database names from current catalog. + + ```sql + SHOW DATABASES; + ```` + + ```` + +--------------------+ + | Database | + +--------------------+ + | test | + | information_schema | + +--------------------+ + ```` + +2. Display all database names from the catalog named 'hms_catalog'. + + ```sql + SHOW DATABASES from hms_catalog; + ```` + + ```` + +---------------+ + | Database | + +---------------+ + | default | + | tpch | + +---------------+ + ```` + +3. Display the filtered database names from current catalog with the expr 'like'. + + ```sql + SHOW DATABASES like 'infor%'; + ```` + + ```` + +--------------------+ + | Database | + +--------------------+ + | information_schema | + +--------------------+ + ```` ### Keywords diff --git a/docs/en/docs/sql-manual/sql-reference/Utility-Statements/USE.md b/docs/en/docs/sql-manual/sql-reference/Utility-Statements/USE.md index 79cab5508e..2b847fe974 100644 --- a/docs/en/docs/sql-manual/sql-reference/Utility-Statements/USE.md +++ b/docs/en/docs/sql-manual/sql-reference/Utility-Statements/USE.md @@ -37,17 +37,26 @@ The USE command allows us to use the database grammar: ````SQL -USE <DATABASE_NAME> +USE <[CATALOG_NAME].DATABASE_NAME> ```` +illustrate: +1. `USE CATALOG_NAME.DATABASE_NAME` will switch the current catalog into `CATALOG_NAME` and then change the current database into `DATABASE_NAME` + ### Example -1. If the demo database exists, try accessing it: +1. If the demo database exists in current catalog, try accessing it: ```sql mysql> use demo; Database changed ```` +2. If the demo database exists in catalog hms_catalog, try switching the catalog and accessing it: + + ```sql + mysql> use hms_catalog.demo; + Database changed + ```` ### Keywords diff --git a/docs/zh-CN/docs/sql-manual/sql-reference/Show-Statements/SHOW-DATABASES.md b/docs/zh-CN/docs/sql-manual/sql-reference/Show-Statements/SHOW-DATABASES.md index c173368e63..8517fec0be 100644 --- a/docs/zh-CN/docs/sql-manual/sql-reference/Show-Statements/SHOW-DATABASES.md +++ b/docs/zh-CN/docs/sql-manual/sql-reference/Show-Statements/SHOW-DATABASES.md @@ -37,10 +37,59 @@ SHOW DATABASES 语法: ```sql -SHOW DATABASES; -``` +SHOW DATABASES [FROM catalog] [filter expr]; +```` + +说明: +1. `SHOW DATABASES` 会展示当前所有的数据库名称. +2. `SHOW DATABASES FROM catalog` 会展示`catalog`中所有的数据库名称. +3. `SHOW DATABASES filter_expr` 会展示当前所有经过过滤后的数据库名称. +4. `SHOW DATABASES FROM catalog filter_expr` 这种语法不支持. ### Example +1. 展示当前所有的数据库名称. + + ```sql + SHOW DATABASES; + ```` + + ```` + +--------------------+ + | Database | + +--------------------+ + | test | + | information_schema | + +--------------------+ + ```` + +2. 会展示`hms_catalog`中所有的数据库名称. + + ```sql + SHOW DATABASES from hms_catalog; + ```` + + ```` + +---------------+ + | Database | + +---------------+ + | default | + | tpch | + +---------------+ + ```` + +3. 展示当前所有经过表示式`like 'infor%'`过滤后的数据库名称. + + ```sql + SHOW DATABASES like 'infor%'; + ```` + + ```` + +--------------------+ + | Database | + +--------------------+ + | information_schema | + +--------------------+ + ```` ### Keywords diff --git a/docs/zh-CN/docs/sql-manual/sql-reference/Utility-Statements/USE.md b/docs/zh-CN/docs/sql-manual/sql-reference/Utility-Statements/USE.md index 152d0814ec..bbec269b9e 100644 --- a/docs/zh-CN/docs/sql-manual/sql-reference/Utility-Statements/USE.md +++ b/docs/zh-CN/docs/sql-manual/sql-reference/Utility-Statements/USE.md @@ -37,18 +37,27 @@ USE 命令可以让我们来使用数据库 语法: ```SQL -USE <DATABASE_NAME> +USE <[CATALOG_NAME].DATABASE_NAME> ``` +说明: +1. 使用`USE CATALOG_NAME.DATABASE_NAME`, 会先将当前的Catalog切换为`CATALOG_NAME`, 然后再讲当前的Database切换为`DATABASE_NAME` + ### Example -1. 如果 demo 数据库存在,尝试存取它: +1. 如果 demo 数据库存在,尝试使用它: ```sql mysql> use demo; Database changed ``` +2. 如果 demo 数据库在hms_catalog的Catalog下存在,尝试切换到hms_catalog, 并使用它: + + ```sql + mysql> use hms_catalog.demo; + Database changed + ```` ### Keywords USE diff --git a/fe/fe-core/src/main/cup/sql_parser.cup b/fe/fe-core/src/main/cup/sql_parser.cup index a953b62b8d..9ca18f39c0 100644 --- a/fe/fe-core/src/main/cup/sql_parser.cup +++ b/fe/fe-core/src/main/cup/sql_parser.cup @@ -2842,6 +2842,10 @@ show_param ::= {: RESULT = new ShowDbStmt(parser.wild, parser.where); :} + | KW_DATABASES KW_FROM ident:catalogName + {: + RESULT = new ShowDbStmt(null, null, catalogName); + :} /* show database id */ | KW_DATABASE INTEGER_LITERAL:dbId {: @@ -2851,6 +2855,10 @@ show_param ::= {: RESULT = new ShowDbStmt(parser.wild, parser.where); :} + | KW_SCHEMAS KW_FROM ident:catalogName + {: + RESULT = new ShowDbStmt(null, null, catalogName); + :} /* Catalog */ | KW_CATALOGS {: @@ -3569,6 +3577,10 @@ use_stmt ::= {: RESULT = new UseStmt(db); :} + | KW_USE ident:ctl DOT ident:db + {: + RESULT = new UseStmt(ctl, db); + :} ; // Insert statement diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowDbStmt.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowDbStmt.java index ddd582515a..30a6dbebf7 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowDbStmt.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowDbStmt.java @@ -38,6 +38,7 @@ public class ShowDbStmt extends ShowStmt { .build(); private String pattern; + private String catalogName; private Expr where; private SelectStmt selectStmt; @@ -50,10 +51,20 @@ public class ShowDbStmt extends ShowStmt { this.where = where; } + public ShowDbStmt(String pattern, Expr where, String catalogName) { + this.pattern = pattern; + this.where = where; + this.catalogName = catalogName; + } + public String getPattern() { return pattern; } + public String getCatalogName() { + return catalogName; + } + @Override public void analyze(Analyzer analyzer) throws AnalysisException, UserException { super.analyze(analyzer); @@ -87,6 +98,9 @@ public class ShowDbStmt extends ShowStmt { if (pattern != null) { sb.append(" LIKE '").append(pattern).append("'"); } + if (catalogName != null) { + sb.append(" FROM ").append(catalogName); + } return sb.toString(); } diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/UseStmt.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/UseStmt.java index d5fc1e74c2..be516b36f4 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/UseStmt.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/UseStmt.java @@ -35,19 +35,35 @@ import org.apache.logging.log4j.Logger; */ public class UseStmt extends StatementBase { private static final Logger LOG = LogManager.getLogger(UseStmt.class); + private String catalogName; private String database; public UseStmt(String db) { database = db; } + public UseStmt(String catalogName, String db) { + this.catalogName = catalogName; + this.database = db; + } + public String getDatabase() { return database; } + public String getCatalogName() { + return catalogName; + } + @Override public String toSql() { - return "USE `" + database + "`"; + StringBuilder sb = new StringBuilder(); + sb.append("USE "); + if (catalogName != null) { + sb.append("`").append(catalogName).append("`."); + } + sb.append("`").append(database).append("`"); + return sb.toString(); } @Override diff --git a/fe/fe-core/src/main/java/org/apache/doris/qe/ConnectContext.java b/fe/fe-core/src/main/java/org/apache/doris/qe/ConnectContext.java index 5409f75615..ff85fb08e1 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/qe/ConnectContext.java +++ b/fe/fe-core/src/main/java/org/apache/doris/qe/ConnectContext.java @@ -425,10 +425,18 @@ public class ConnectContext { public DataSourceIf getCurrentDataSource() { // defaultCatalog is switched by SwitchStmt, so we don't need to check to exist of catalog. + return getDataSource(defaultCatalog); + } + + /** + * Maybe return when catalogName is not exist. So need to check nullable. + */ + public DataSourceIf getDataSource(String catalogName) { + String realCatalogName = catalogName == null ? defaultCatalog : catalogName; if (env == null) { - return Env.getCurrentEnv().getDataSourceMgr().getCatalog(defaultCatalog); + return Env.getCurrentEnv().getDataSourceMgr().getCatalog(realCatalogName); } - return env.getDataSourceMgr().getCatalog(defaultCatalog); + return env.getDataSourceMgr().getCatalog(realCatalogName); } public void changeDefaultCatalog(String catalogName) { diff --git a/fe/fe-core/src/main/java/org/apache/doris/qe/ConnectProcessor.java b/fe/fe-core/src/main/java/org/apache/doris/qe/ConnectProcessor.java index a9b18776e1..ad7d8fe5e8 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/qe/ConnectProcessor.java +++ b/fe/fe-core/src/main/java/org/apache/doris/qe/ConnectProcessor.java @@ -39,6 +39,7 @@ import org.apache.doris.common.Pair; import org.apache.doris.common.UserException; import org.apache.doris.common.util.DebugUtil; import org.apache.doris.common.util.SqlParserUtils; +import org.apache.doris.datasource.DataSourceIf; import org.apache.doris.metric.MetricRepo; import org.apache.doris.mysql.MysqlChannel; import org.apache.doris.mysql.MysqlCommand; @@ -89,13 +90,41 @@ public class ConnectProcessor { // COM_INIT_DB: change current database of this session. private void handleInitDb() { - String dbName = new String(packetBuf.array(), 1, packetBuf.limit() - 1); + String fullDbName = new String(packetBuf.array(), 1, packetBuf.limit() - 1); if (Strings.isNullOrEmpty(ctx.getClusterName())) { ctx.getState().setError(ErrorCode.ERR_CLUSTER_NAME_NULL, "Please enter cluster"); return; } + String catalogName = null; + String dbName = null; + String[] dbNames = fullDbName.split("\\."); + if (dbNames.length == 1) { + dbName = fullDbName; + } else if (dbNames.length == 2) { + catalogName = dbNames[0]; + dbName = dbNames[1]; + } else if (dbNames.length > 2) { + ctx.getState().setError(ErrorCode.ERR_BAD_DB_ERROR, "Only one dot can be in the name: " + fullDbName); + return; + } dbName = ClusterNamespace.getFullName(ctx.getClusterName(), dbName); + + // check catalog and db exists + if (catalogName != null) { + DataSourceIf dataSourceIf = ctx.getEnv().getDataSourceMgr().getCatalogNullable(catalogName); + if (dataSourceIf == null) { + ctx.getState().setError(ErrorCode.ERR_BAD_DB_ERROR, "No match catalog in doris: " + fullDbName); + return; + } + if (dataSourceIf.getDbNullable(dbName) == null) { + ctx.getState().setError(ErrorCode.ERR_BAD_DB_ERROR, "No match database in doris: " + fullDbName); + return; + } + } try { + if (catalogName != null) { + ctx.getEnv().changeCatalog(ctx, catalogName); + } ctx.getEnv().changeDb(ctx, dbName); } catch (DdlException e) { ctx.getState().setError(e.getMysqlErrorCode(), e.getMessage()); diff --git a/fe/fe-core/src/main/java/org/apache/doris/qe/ShowExecutor.java b/fe/fe-core/src/main/java/org/apache/doris/qe/ShowExecutor.java index 7809c968ca..f89cb3dd9c 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/qe/ShowExecutor.java +++ b/fe/fe-core/src/main/java/org/apache/doris/qe/ShowExecutor.java @@ -156,6 +156,7 @@ import org.apache.doris.common.util.ProfileManager; import org.apache.doris.common.util.RuntimeProfile; import org.apache.doris.common.util.TimeUtils; import org.apache.doris.common.util.Util; +import org.apache.doris.datasource.DataSourceIf; import org.apache.doris.external.iceberg.IcebergTableCreationRecord; import org.apache.doris.load.DeleteHandler; import org.apache.doris.load.ExportJob; @@ -658,7 +659,11 @@ public class ShowExecutor { ShowDbStmt showDbStmt = (ShowDbStmt) stmt; List<List<String>> rows = Lists.newArrayList(); // cluster feature is deprecated. - List<String> dbNames = ctx.getCurrentDataSource().getDbNames(); + DataSourceIf dataSourceIf = ctx.getDataSource(showDbStmt.getCatalogName()); + if (dataSourceIf == null) { + throw new AnalysisException("No catalog found with name " + showDbStmt.getCatalogName()); + } + List<String> dbNames = dataSourceIf.getDbNames(); PatternMatcher matcher = null; if (showDbStmt.getPattern() != null) { matcher = PatternMatcher.createMysqlPattern(showDbStmt.getPattern(), diff --git a/fe/fe-core/src/main/java/org/apache/doris/qe/StmtExecutor.java b/fe/fe-core/src/main/java/org/apache/doris/qe/StmtExecutor.java index c1edb216da..266b412c83 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/qe/StmtExecutor.java +++ b/fe/fe-core/src/main/java/org/apache/doris/qe/StmtExecutor.java @@ -1494,6 +1494,9 @@ public class StmtExecutor implements ProfileWriter { if (Strings.isNullOrEmpty(useStmt.getClusterName())) { ErrorReport.reportAnalysisException(ErrorCode.ERR_CLUSTER_NO_SELECT_CLUSTER); } + if (useStmt.getCatalogName() != null) { + context.getEnv().changeCatalog(context, useStmt.getCatalogName()); + } context.getEnv().changeDb(context, useStmt.getDatabase()); } catch (DdlException e) { context.getState().setError(e.getMysqlErrorCode(), e.getMessage()); diff --git a/fe/fe-core/src/test/java/org/apache/doris/analysis/ShowDbStmtTest.java b/fe/fe-core/src/test/java/org/apache/doris/analysis/ShowDbStmtTest.java index 9a2da0f12f..234767941f 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/analysis/ShowDbStmtTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/analysis/ShowDbStmtTest.java @@ -40,5 +40,13 @@ public class ShowDbStmtTest { Assert.assertEquals("SHOW DATABASES LIKE 'abc'", stmt.toString()); Assert.assertEquals(1, stmt.getMetaData().getColumnCount()); Assert.assertEquals("Database", stmt.getMetaData().getColumn(0).getName()); + + stmt = new ShowDbStmt(null, null, "cn"); + stmt.analyze(analyzer); + Assert.assertEquals("cn", stmt.getCatalogName()); + Assert.assertNull(stmt.getPattern()); + Assert.assertEquals("SHOW DATABASES FROM cn", stmt.toString()); + Assert.assertEquals(1, stmt.getMetaData().getColumnCount()); + Assert.assertEquals("Database", stmt.getMetaData().getColumn(0).getName()); } } diff --git a/fe/fe-core/src/test/java/org/apache/doris/analysis/UseStmtTest.java b/fe/fe-core/src/test/java/org/apache/doris/analysis/UseStmtTest.java index 841cfe4909..e93249533a 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/analysis/UseStmtTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/analysis/UseStmtTest.java @@ -59,4 +59,14 @@ public class UseStmtTest { Assert.fail("No exception throws."); } + + + @Test + public void testFromCatalog() throws UserException, AnalysisException { + UseStmt stmt = new UseStmt("cn", "testDb"); + stmt.analyze(analyzer); + Assert.assertEquals("USE `cn`.`testCluster:testDb`", stmt.toString()); + Assert.assertEquals("testCluster:testDb", stmt.getDatabase()); + Assert.assertEquals("cn", stmt.getCatalogName()); + } } diff --git a/fe/fe-core/src/test/java/org/apache/doris/qe/ShowExecutorTest.java b/fe/fe-core/src/test/java/org/apache/doris/qe/ShowExecutorTest.java index 1bb4cabdf6..b051f1973b 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/qe/ShowExecutorTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/qe/ShowExecutorTest.java @@ -289,6 +289,16 @@ public class ShowExecutorTest { Assert.assertFalse(resultSet.next()); } + @Test + public void testShowDbFromCatalog() throws AnalysisException { + ShowDbStmt stmt = new ShowDbStmt(null, null, InternalDataSource.INTERNAL_DS_NAME); + ShowExecutor executor = new ShowExecutor(ctx, stmt); + ShowResultSet resultSet = executor.execute(); + + Assert.assertTrue(resultSet.next()); + Assert.assertEquals("testDb", resultSet.getString(0)); + } + @Test public void testShowDbPriv() throws AnalysisException { ShowDbStmt stmt = new ShowDbStmt(null); diff --git a/fe/fe-core/src/test/java/org/apache/doris/qe/StmtExecutorTest.java b/fe/fe-core/src/test/java/org/apache/doris/qe/StmtExecutorTest.java index 28d67d12d0..87ca5e61a6 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/qe/StmtExecutorTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/qe/StmtExecutorTest.java @@ -34,6 +34,7 @@ import org.apache.doris.catalog.Env; import org.apache.doris.common.DdlException; import org.apache.doris.common.jmockit.Deencapsulation; import org.apache.doris.common.util.RuntimeProfile; +import org.apache.doris.datasource.InternalDataSource; import org.apache.doris.metric.MetricRepo; import org.apache.doris.mysql.MysqlChannel; import org.apache.doris.mysql.MysqlSerializer; @@ -736,4 +737,76 @@ public class StmtExecutorTest { Assert.assertEquals(QueryState.MysqlStateType.ERR, state.getStateType()); } + + @Test + public void testUseWithCatalog(@Mocked UseStmt useStmt, @Mocked SqlParser parser) throws Exception { + new Expectations() { + { + useStmt.analyze((Analyzer) any); + minTimes = 0; + + useStmt.getDatabase(); + minTimes = 0; + result = "testCluster:testDb"; + + useStmt.getRedirectStatus(); + minTimes = 0; + result = RedirectStatus.NO_FORWARD; + + useStmt.getClusterName(); + minTimes = 0; + result = "testCluster"; + + useStmt.getCatalogName(); + minTimes = 0; + result = InternalDataSource.INTERNAL_DS_NAME; + + Symbol symbol = new Symbol(0, Lists.newArrayList(useStmt)); + parser.parse(); + minTimes = 0; + result = symbol; + } + }; + + StmtExecutor executor = new StmtExecutor(ctx, ""); + executor.execute(); + + Assert.assertEquals(QueryState.MysqlStateType.OK, state.getStateType()); + } + + @Test + public void testUseWithCatalogFail(@Mocked UseStmt useStmt, @Mocked SqlParser parser) throws Exception { + new Expectations() { + { + useStmt.analyze((Analyzer) any); + minTimes = 0; + + useStmt.getDatabase(); + minTimes = 0; + result = "blockDb"; + + useStmt.getRedirectStatus(); + minTimes = 0; + result = RedirectStatus.NO_FORWARD; + + useStmt.getClusterName(); + minTimes = 0; + result = "testCluster"; + + useStmt.getCatalogName(); + minTimes = 0; + result = "testcatalog"; + + Symbol symbol = new Symbol(0, Lists.newArrayList(useStmt)); + parser.parse(); + minTimes = 0; + result = symbol; + } + }; + + StmtExecutor executor = new StmtExecutor(ctx, ""); + executor.execute(); + + Assert.assertEquals(QueryState.MysqlStateType.ERR, state.getStateType()); + } } --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org For additional commands, e-mail: commits-h...@doris.apache.org