[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.
This commit is contained in:
@ -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
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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());
|
||||
|
||||
@ -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(),
|
||||
|
||||
@ -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());
|
||||
|
||||
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user