This is an automated email from the ASF dual-hosted git repository. yiguolei 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 ad8a8203a2 [fix](mysql compatibility) add an internal database mysql to improve mysql compatibility (#22868) ad8a8203a2 is described below commit ad8a8203a2771ac81b3252586a884eca53d1094c Author: hzq <seuhezhiqi...@163.com> AuthorDate: Mon Aug 14 17:03:11 2023 +0800 [fix](mysql compatibility) add an internal database mysql to improve mysql compatibility (#22868) --- .../java/org/apache/doris/analysis/DropDbStmt.java | 6 +- .../java/org/apache/doris/catalog/Database.java | 4 + .../java/org/apache/doris/catalog/MysqlDb.java | 134 +++++++++++++++++++++ .../java/org/apache/doris/clone/TabletChecker.java | 2 +- .../apache/doris/datasource/InternalCatalog.java | 31 +++-- .../org/apache/doris/httpv2/rest/ShowAction.java | 3 +- .../master/PartitionInMemoryInfoCollector.java | 2 +- .../apache/doris/mysql/privilege/RoleManager.java | 11 +- .../transaction/DbUsedDataQuotaInfoCollector.java | 2 +- .../java/org/apache/doris/catalog/MysqlDbTest.java | 39 ++++++ 10 files changed, 214 insertions(+), 20 deletions(-) diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/DropDbStmt.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/DropDbStmt.java index 86915b654b..2172477c29 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/DropDbStmt.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/DropDbStmt.java @@ -19,6 +19,7 @@ package org.apache.doris.analysis; import org.apache.doris.catalog.Env; import org.apache.doris.catalog.InfoSchemaDb; +import org.apache.doris.catalog.MysqlDb; import org.apache.doris.cluster.ClusterNamespace; import org.apache.doris.common.ErrorCode; import org.apache.doris.common.ErrorReport; @@ -59,8 +60,9 @@ public class DropDbStmt extends DdlStmt { ErrorReport.reportAnalysisException(ErrorCode.ERR_WRONG_DB_NAME, dbName); } dbName = ClusterNamespace.getFullName(getClusterName(), dbName); - // Don't allowed to drop 'information_schema' - if (dbName.equalsIgnoreCase(ClusterNamespace.getFullName(getClusterName(), InfoSchemaDb.DATABASE_NAME))) { + // Don't allowed to drop 'information_schema' & 'mysql' + if (dbName.equalsIgnoreCase(ClusterNamespace.getFullName(getClusterName(), InfoSchemaDb.DATABASE_NAME)) + || dbName.equalsIgnoreCase(ClusterNamespace.getFullName(getClusterName(), MysqlDb.DATABASE_NAME))) { ErrorReport.reportAnalysisException(ErrorCode.ERR_DBACCESS_DENIED_ERROR, analyzer.getQualifiedUser(), dbName); } diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/Database.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/Database.java index 54f1b6ce8b..a92992d530 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/catalog/Database.java +++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/Database.java @@ -762,6 +762,10 @@ public class Database extends MetaObject implements Writable, DatabaseIf<Table> return ClusterNamespace.getNameFromFullName(fullQualifiedName).equalsIgnoreCase(InfoSchemaDb.DATABASE_NAME); } + public boolean isMysqlDb() { + return ClusterNamespace.getNameFromFullName(fullQualifiedName).equalsIgnoreCase(MysqlDb.DATABASE_NAME); + } + public synchronized void addEncryptKey(EncryptKey encryptKey, boolean ifNotExists) throws UserException { if (addEncryptKeyImpl(encryptKey, false, ifNotExists)) { Env.getCurrentEnv().getEditLog().logAddEncryptKey(encryptKey); diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/MysqlDb.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/MysqlDb.java new file mode 100644 index 0000000000..9c91fd2d70 --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/MysqlDb.java @@ -0,0 +1,134 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.doris.catalog; + +import org.apache.doris.alter.Alter; +import org.apache.doris.analysis.AlterTableStmt; +import org.apache.doris.analysis.CreateViewStmt; +import org.apache.doris.cluster.ClusterNamespace; +import org.apache.doris.common.Pair; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +/** + * This class is used for MySQL compatibility. + * The mysqldump requires this database to make some + * command arguments like --all-databases work as expected. + * Otherwise, commands like + * <p> + * mysqldump -u root -p --all-databases + * </p> + * will dump nothing. + * Native mysql has many system tables like slow_log under mysql database, + * but currently we do not create any tables under mysql database of doris. + * We will add useful system tables in the future. +*/ +public class MysqlDb extends Database { + public static final String DATABASE_NAME = "mysql"; + /** + * Database created by user will have database id starting from 10000 {@link Env#NEXT_ID_INIT_VALUE}. + * InfoSchemaDb takes id 0, so we assign id 1 to MysqlDb. + */ + public static final long DATABASE_ID = 1L; + + /** + * For test + */ + public MysqlDb() { + super(DATABASE_ID, DATABASE_NAME); + initTables(); + } + + public MysqlDb(String cluster) { + super(DATABASE_ID, ClusterNamespace.getFullName(cluster, DATABASE_NAME)); + initTables(); + } + + /** + * Do nothing for now. + * If we need tables of mysql database in the future, create a MysqlTable class like {@link SchemaTable} + */ + private void initTables() { + } + + /** + * This method must be re-implemented since {@link Env#createView(CreateViewStmt)} + * will call this method. And create view should not succeed on this database. + */ + @Override + public Pair<Boolean, Boolean> createTableWithLock(Table table, boolean isReplay, boolean setIfNotExist) { + return Pair.of(false, false); + } + + + /** + * Currently, rename a table of InfoSchemaDb will throw exception + * {@link Alter#processAlterTable(AlterTableStmt)} + * so we follow this design. + * @note: Rename a table of mysql database in MYSQL ls allowed. + */ + @Override + public boolean createTable(Table table) { + return false; + } + + @Override + public void dropTable(String name) { + // Do nothing. + } + + /** + * MysqlDb is not persistent to bdb. It will be constructed everytime the fe starts. + * {@link org.apache.doris.datasource.InternalCatalog#InternalCatalog()} + */ + @Override + public void write(DataOutput out) throws IOException { + // Do nothing + } + + /** + * Same with {@link InfoSchemaDb#readFields(DataInput)} + */ + @Override + public void readFields(DataInput in) throws IOException { + throw new IOException("Not support."); + } + + /** + * Same with {@link InfoSchemaDb#getTableNullable(String)} + */ + @Override + public Table getTableNullable(String name) { + return super.getTableNullable(name.toLowerCase()); + } + + public static boolean isMysqlDb(String dbName) { + if (dbName == null) { + return false; + } + + String[] elements = dbName.split(ClusterNamespace.CLUSTER_DELIMITER); + String newDbName = dbName; + if (elements.length == 2) { + newDbName = elements[1]; + } + return DATABASE_NAME.equalsIgnoreCase(newDbName); + } +} diff --git a/fe/fe-core/src/main/java/org/apache/doris/clone/TabletChecker.java b/fe/fe-core/src/main/java/org/apache/doris/clone/TabletChecker.java index 2b8bddbf9c..e7b762ef29 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/clone/TabletChecker.java +++ b/fe/fe-core/src/main/java/org/apache/doris/clone/TabletChecker.java @@ -281,7 +281,7 @@ public class TabletChecker extends MasterDaemon { continue; } - if (db.isInfoSchemaDb()) { + if (db.isInfoSchemaDb() || db.isMysqlDb()) { continue; } diff --git a/fe/fe-core/src/main/java/org/apache/doris/datasource/InternalCatalog.java b/fe/fe-core/src/main/java/org/apache/doris/datasource/InternalCatalog.java index bedd5d4740..c70c9f0771 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/datasource/InternalCatalog.java +++ b/fe/fe-core/src/main/java/org/apache/doris/datasource/InternalCatalog.java @@ -80,6 +80,7 @@ import org.apache.doris.catalog.MaterializedIndex.IndexState; import org.apache.doris.catalog.MaterializedIndexMeta; import org.apache.doris.catalog.MaterializedView; import org.apache.doris.catalog.MetaIdGenerator.IdGeneratorBuffer; +import org.apache.doris.catalog.MysqlDb; import org.apache.doris.catalog.MysqlTable; import org.apache.doris.catalog.OdbcTable; import org.apache.doris.catalog.OlapTable; @@ -215,12 +216,16 @@ public class InternalCatalog implements CatalogIf<Database> { private IcebergTableCreationRecordMgr icebergTableCreationRecordMgr = new IcebergTableCreationRecordMgr(); public InternalCatalog() { - // create info schema db - final InfoSchemaDb db = new InfoSchemaDb(SystemInfoService.DEFAULT_CLUSTER); - db.setClusterName(SystemInfoService.DEFAULT_CLUSTER); - // do not call unprotectedCreateDb, because it will cause loop recursive when initializing Env singleton - idToDb.put(db.getId(), db); - fullNameToDb.put(db.getFullName(), db); + // create internal databases + List<Database> internalDbs = new ArrayList<>(); + internalDbs.add(new InfoSchemaDb(SystemInfoService.DEFAULT_CLUSTER)); + internalDbs.add(new MysqlDb(SystemInfoService.DEFAULT_CLUSTER)); + + for (Database idb : internalDbs) { + // do not call unprotectedCreateDb, because it will cause loop recursive when initializing Env singleton + idToDb.put(idb.getId(), idb); + fullNameToDb.put(idb.getFullName(), idb); + } } @Override @@ -1067,9 +1072,9 @@ public class InternalCatalog implements CatalogIf<Database> { String tableName = stmt.getTableName(); // check if db exists - Database db = (Database) getDbOrDdlException(dbName); - // InfoSchemaDb can not create table - if (db instanceof InfoSchemaDb) { + Database db = getDbOrDdlException(dbName); + // InfoSchemaDb and MysqlDb can not create table manually + if (db instanceof InfoSchemaDb || db instanceof MysqlDb) { ErrorReport.reportDdlException(ErrorCode.ERR_CANT_CREATE_TABLE, tableName, ErrorCode.ERR_CANT_CREATE_TABLE.getCode(), "not supported create table in this database"); } @@ -3074,15 +3079,15 @@ public class InternalCatalog implements CatalogIf<Database> { } public long saveDb(CountingDataOutputStream dos, long checksum) throws IOException { - // 1 is for information_schema db, which does not need to be persisted. - int dbCount = idToDb.size() - 1; + // 2 is for information_schema db & mysql db, which does not need to be persisted. + int dbCount = idToDb.size() - 2; checksum ^= dbCount; dos.writeInt(dbCount); for (Map.Entry<Long, Database> entry : idToDb.entrySet()) { Database db = entry.getValue(); String dbName = db.getFullName(); - // Don't write information_schema db meta - if (!InfoSchemaDb.isInfoSchemaDb(dbName)) { + // Don't write information_schema & mysql db meta + if (!InfoSchemaDb.isInfoSchemaDb(dbName) && !MysqlDb.isMysqlDb(dbName)) { checksum ^= entry.getKey(); db.write(dos); } diff --git a/fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/ShowAction.java b/fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/ShowAction.java index 8a0c7da4b2..fbece00f13 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/ShowAction.java +++ b/fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/ShowAction.java @@ -198,7 +198,8 @@ public class ShowAction extends RestBaseController { } else { for (long dbId : Env.getCurrentInternalCatalog().getDbIds()) { DatabaseIf db = Env.getCurrentInternalCatalog().getDbNullable(dbId); - if (db == null || !(db instanceof Database) || ((Database) db).isInfoSchemaDb()) { + if (db == null || !(db instanceof Database) || ((Database) db).isInfoSchemaDb() + || ((Database) db).isMysqlDb()) { continue; } totalSize += getDataSizeOfDatabase(db); diff --git a/fe/fe-core/src/main/java/org/apache/doris/master/PartitionInMemoryInfoCollector.java b/fe/fe-core/src/main/java/org/apache/doris/master/PartitionInMemoryInfoCollector.java index 8bd02cb186..fefdf48b28 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/master/PartitionInMemoryInfoCollector.java +++ b/fe/fe-core/src/main/java/org/apache/doris/master/PartitionInMemoryInfoCollector.java @@ -56,7 +56,7 @@ public class PartitionInMemoryInfoCollector extends MasterDaemon { LOG.warn("Database [" + dbId + "] does not exist, skip to update database used data quota"); continue; } - if (db.isInfoSchemaDb()) { + if (db.isInfoSchemaDb() || db.isMysqlDb()) { continue; } try { diff --git a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/RoleManager.java b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/RoleManager.java index 6d1a669c4f..285534d297 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/RoleManager.java +++ b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/RoleManager.java @@ -23,6 +23,7 @@ import org.apache.doris.analysis.UserIdentity; import org.apache.doris.analysis.WorkloadGroupPattern; import org.apache.doris.catalog.Env; import org.apache.doris.catalog.InfoSchemaDb; +import org.apache.doris.catalog.MysqlDb; import org.apache.doris.cluster.ClusterNamespace; import org.apache.doris.common.AnalysisException; import org.apache.doris.common.DdlException; @@ -189,13 +190,21 @@ public class RoleManager implements Writable { if (roles.containsKey(userDefaultRoleName)) { return roles.get(userDefaultRoleName); } - // grant read privs to database information_schema + // grant read privs to database information_schema & mysql TablePattern tblPattern = new TablePattern(Auth.DEFAULT_CATALOG, InfoSchemaDb.DATABASE_NAME, "*"); try { tblPattern.analyze(SystemInfoService.DEFAULT_CLUSTER); } catch (AnalysisException e) { LOG.warn("should not happen", e); } + + tblPattern = new TablePattern(Auth.DEFAULT_CATALOG, MysqlDb.DATABASE_NAME, "*"); + try { + tblPattern.analyze(SystemInfoService.DEFAULT_CLUSTER); + } catch (AnalysisException e) { + LOG.warn("should not happen", e); + } + // grant read privs of default workload group WorkloadGroupPattern workloadGroupPattern = new WorkloadGroupPattern(WorkloadGroupMgr.DEFAULT_GROUP_NAME); try { diff --git a/fe/fe-core/src/main/java/org/apache/doris/transaction/DbUsedDataQuotaInfoCollector.java b/fe/fe-core/src/main/java/org/apache/doris/transaction/DbUsedDataQuotaInfoCollector.java index 25c7a3bd65..da6b16a1f3 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/transaction/DbUsedDataQuotaInfoCollector.java +++ b/fe/fe-core/src/main/java/org/apache/doris/transaction/DbUsedDataQuotaInfoCollector.java @@ -50,7 +50,7 @@ public class DbUsedDataQuotaInfoCollector extends MasterDaemon { LOG.warn("Database [" + dbId + "] does not exist, skip to update database used data quota"); continue; } - if (db.isInfoSchemaDb()) { + if (db.isInfoSchemaDb() || db.isMysqlDb()) { continue; } try { diff --git a/fe/fe-core/src/test/java/org/apache/doris/catalog/MysqlDbTest.java b/fe/fe-core/src/test/java/org/apache/doris/catalog/MysqlDbTest.java new file mode 100644 index 0000000000..ebf7b661ea --- /dev/null +++ b/fe/fe-core/src/test/java/org/apache/doris/catalog/MysqlDbTest.java @@ -0,0 +1,39 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.doris.catalog; + +import org.apache.doris.common.DdlException; + +import org.junit.Assert; +import org.junit.Test; + +import java.io.IOException; + +public class MysqlDbTest { + @Test + public void testNormal() throws IOException, DdlException { + Database db = new MysqlDb(); + + Assert.assertFalse(db.createTable(null)); + Assert.assertFalse(db.createTableWithLock(null, false, false).first); + db.dropTable("authors"); + db.write(null); + Assert.assertNull(db.getTableNullable("authors")); + } + +} --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org For additional commands, e-mail: commits-h...@doris.apache.org