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 a92992d530..75250fb204 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 @@ -18,7 +18,6 @@ package org.apache.doris.catalog; import org.apache.doris.catalog.TableIf.TableType; -import org.apache.doris.cluster.ClusterNamespace; import org.apache.doris.common.AnalysisException; import org.apache.doris.common.Config; import org.apache.doris.common.DdlException; @@ -758,14 +757,6 @@ public class Database extends MetaObject implements Writable, DatabaseIf return FunctionUtil.getFunctions(name2Function); } - public boolean isInfoSchemaDb() { - 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); @@ -907,4 +898,11 @@ public class Database extends MetaObject implements Writable, DatabaseIf
public String toString() { return toJson(); } + + // Return ture if database is created for mysql compatibility. + // Currently, we have two dbs that are created for this purpose, InformationSchemaDb and MysqlDb, + public boolean isMysqlCompatibleDatabase() { + return false; + } + } diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/InfoSchemaDb.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/InfoSchemaDb.java index 23a6bf3478..32143fd589 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/catalog/InfoSchemaDb.java +++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/InfoSchemaDb.java @@ -18,76 +18,29 @@ package org.apache.doris.catalog; import org.apache.doris.cluster.ClusterNamespace; -import org.apache.doris.common.Pair; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; // Information schema used for MySQL compatible. -public class InfoSchemaDb extends Database { +public class InfoSchemaDb extends MysqlCompatibleDatabase { public static final String DATABASE_NAME = "information_schema"; public static final long DATABASE_ID = 0L; public InfoSchemaDb() { super(DATABASE_ID, DATABASE_NAME); - initTables(); } public InfoSchemaDb(String cluster) { super(DATABASE_ID, ClusterNamespace.getFullName(cluster, DATABASE_NAME)); - initTables(); } @Override - public Pair createTableWithLock(Table table, boolean isReplay, boolean setIfNotExist) { - return Pair.of(false, false); - } - - @Override - public boolean createTable(Table table) { - // Do nothing. - return false; - } - - @Override - public void dropTable(String name) { - // Do nothing. - } - - @Override - public void write(DataOutput out) throws IOException { - // Do nothing - } - - public void readFields(DataInput in) throws IOException { - throw new IOException("Not support."); - } - - private void initTables() { + protected void initTables() { for (Table table : SchemaTable.TABLE_MAP.values()) { super.createTable(table); } } @Override - public Table getTableNullable(String name) { - return super.getTableNullable(name.toLowerCase()); - } - - public static String getFullInfoSchemaDbName(String cluster) { - return ClusterNamespace.getFullName(cluster, DATABASE_NAME); - } - - public static boolean isInfoSchemaDb(String dbName) { - if (dbName == null) { - return false; - } - String[] ele = dbName.split(ClusterNamespace.CLUSTER_DELIMITER); - String newDbName = dbName; - if (ele.length == 2) { - newDbName = ele[1]; - } - return DATABASE_NAME.equalsIgnoreCase(newDbName); + public boolean createTable(Table table) { + return false; } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/MysqlCompatibleDatabase.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/MysqlCompatibleDatabase.java new file mode 100644 index 0000000000..1d4aa62dc9 --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/MysqlCompatibleDatabase.java @@ -0,0 +1,101 @@ +// 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.common.Pair; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +/** + * Abstract class for all databases created for mysql compatibility. + */ +public abstract class MysqlCompatibleDatabase extends Database { + public static int COUNT = 0; + + public MysqlCompatibleDatabase(long id, String name) { + super(id, name); + initTables(); + } + + /** + * Internal database is not persisted to bdb, it will be created when fe starts. + * So driven class should implement this function to create table. + */ + protected abstract void initTables(); + + /** + * 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 super.createTable(table); + } + + @Override + public void dropTable(String name) { + // Do nothing + } + + /** + * MysqlCompatibleDatabase will not be persisted to bdb. + * It will be constructed everytime the fe starts. See + * {@link org.apache.doris.datasource.InternalCatalog#InternalCatalog()} + */ + @Override + public void write(DataOutput out) throws IOException { + throw new IOException("Not support"); + } + + /** + * MysqlCompatibleDatabase should not be read from bdb. + */ + @Override + public void readFields(DataInput in) throws IOException { + throw new IOException("Not support."); + } + + @Override + public boolean isMysqlCompatibleDatabase() { + return true; + } + + /** + * This method must be re-implemented since {@link Env#createView(CreateViewStmt)} + * will call this method. And create view should not succeed under this database. + */ + @Override + public Pair createTableWithLock(Table table, boolean isReplay, boolean setIfNotExist) { + return Pair.of(false, false); + } + + /** + * All tables of mysql compatible database has case-insensitive name + * */ + @Override + public Table getTableNullable(String name) { + return super.getTableNullable(name.toLowerCase()); + } +} 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 index 9c91fd2d70..5e6bd65507 100644 --- 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 @@ -17,15 +17,7 @@ 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. @@ -40,7 +32,7 @@ import java.io.IOException; * 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 class MysqlDb extends MysqlCompatibleDatabase { public static final String DATABASE_NAME = "mysql"; /** * Database created by user will have database id starting from 10000 {@link Env#NEXT_ID_INIT_VALUE}. @@ -53,82 +45,21 @@ public class MysqlDb extends Database { */ 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 createTableWithLock(Table table, boolean isReplay, boolean setIfNotExist) { - return Pair.of(false, false); - } + public void initTables() {} - - /** - * 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 e7b762ef29..09e61ec59b 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() || db.isMysqlDb()) { + if (db.isMysqlCompatibleDatabase()) { 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 c70c9f0771..acaa0284c4 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.MysqlCompatibleDatabase; import org.apache.doris.catalog.MysqlDb; import org.apache.doris.catalog.MysqlTable; import org.apache.doris.catalog.OdbcTable; @@ -187,7 +188,6 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Map.Entry; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; @@ -217,11 +217,12 @@ public class InternalCatalog implements CatalogIf { public InternalCatalog() { // create internal databases - List internalDbs = new ArrayList<>(); - internalDbs.add(new InfoSchemaDb(SystemInfoService.DEFAULT_CLUSTER)); - internalDbs.add(new MysqlDb(SystemInfoService.DEFAULT_CLUSTER)); + List mysqlCompatibleDatabases = new ArrayList<>(); + mysqlCompatibleDatabases.add(new InfoSchemaDb(SystemInfoService.DEFAULT_CLUSTER)); + mysqlCompatibleDatabases.add(new MysqlDb(SystemInfoService.DEFAULT_CLUSTER)); + MysqlCompatibleDatabase.COUNT = 2; - for (Database idb : internalDbs) { + for (MysqlCompatibleDatabase idb : mysqlCompatibleDatabases) { // do not call unprotectedCreateDb, because it will cause loop recursive when initializing Env singleton idToDb.put(idb.getId(), idb); fullNameToDb.put(idb.getFullName(), idb); @@ -856,6 +857,10 @@ public class InternalCatalog implements CatalogIf { // check database Database db = (Database) getDbOrDdlException(dbName); + if (db.isMysqlCompatibleDatabase()) { + throw new DdlException("Drop table from this database is not allowed."); + } + db.writeLockOrDdlException(); try { Table table = db.getTableNullable(tableName); @@ -1074,7 +1079,7 @@ public class InternalCatalog implements CatalogIf { // check if db exists Database db = getDbOrDdlException(dbName); // InfoSchemaDb and MysqlDb can not create table manually - if (db instanceof InfoSchemaDb || db instanceof MysqlDb) { + if (db.isMysqlCompatibleDatabase()) { ErrorReport.reportDdlException(ErrorCode.ERR_CANT_CREATE_TABLE, tableName, ErrorCode.ERR_CANT_CREATE_TABLE.getCode(), "not supported create table in this database"); } @@ -3080,14 +3085,19 @@ public class InternalCatalog implements CatalogIf { public long saveDb(CountingDataOutputStream dos, long checksum) throws IOException { // 2 is for information_schema db & mysql db, which does not need to be persisted. - int dbCount = idToDb.size() - 2; + // And internal database could not be dropped, so we assert dbCount >= 0 + int dbCount = idToDb.size() - MysqlCompatibleDatabase.COUNT; + if (dbCount < 0) { + throw new IOException("Invalid database count"); + } + checksum ^= dbCount; dos.writeInt(dbCount); + for (Map.Entry entry : idToDb.entrySet()) { Database db = entry.getValue(); - String dbName = db.getFullName(); - // Don't write information_schema & mysql db meta - if (!InfoSchemaDb.isInfoSchemaDb(dbName) && !MysqlDb.isMysqlDb(dbName)) { + // Don't write internal database meta. + if (!db.isMysqlCompatibleDatabase()) { 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 fbece00f13..c1dc8f4380 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,8 +198,7 @@ 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() - || ((Database) db).isMysqlDb()) { + if (db == null || !(db instanceof Database) || ((Database) db).isMysqlCompatibleDatabase()) { 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 fefdf48b28..22f2d41cfa 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() || db.isMysqlDb()) { + if (db.isMysqlCompatibleDatabase()) { continue; } 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 da6b16a1f3..87d509bbb4 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() || db.isMysqlDb()) { + if (db.isMysqlCompatibleDatabase()) { continue; } try { diff --git a/fe/fe-core/src/test/java/org/apache/doris/catalog/InfoSchemaDbTest.java b/fe/fe-core/src/test/java/org/apache/doris/catalog/InfoSchemaDbTest.java index ca33ad0bba..9abb1322e6 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/catalog/InfoSchemaDbTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/catalog/InfoSchemaDbTest.java @@ -32,7 +32,7 @@ public class InfoSchemaDbTest { Assert.assertFalse(db.createTable(null)); Assert.assertFalse(db.createTableWithLock(null, false, false).first); db.dropTable("authors"); - db.write(null); + Assert.assertThrows(IOException.class, () -> db.write(null)); Assert.assertNull(db.getTableNullable("authors")); } } 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 index ebf7b661ea..788780202b 100644 --- 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 @@ -32,7 +32,7 @@ public class MysqlDbTest { Assert.assertFalse(db.createTable(null)); Assert.assertFalse(db.createTableWithLock(null, false, false).first); db.dropTable("authors"); - db.write(null); + Assert.assertThrows(IOException.class, () -> db.write(null)); Assert.assertNull(db.getTableNullable("authors")); }