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

Reply via email to