You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@doris.apache.org by mo...@apache.org on 2022/06/24 02:42:19 UTC
[doris] branch master updated: [feature-wip](multi-catalog) support to switch catalog (#10381)
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 516f5b1789 [feature-wip](multi-catalog) support to switch catalog (#10381)
516f5b1789 is described below
commit 516f5b17894233771e86e17e6a950296b1ac596e
Author: Ashin Gau <As...@users.noreply.github.com>
AuthorDate: Fri Jun 24 10:42:13 2022 +0800
[feature-wip](multi-catalog) support to switch catalog (#10381)
Add `switch catalog` stmt with privilege check
---
fe/fe-core/src/main/cup/sql_parser.cup | 15 +-
.../doris/analysis/AlterCatalogNameStmt.java | 20 +--
.../doris/analysis/AlterCatalogPropertyStmt.java | 20 +--
.../apache/doris/analysis/CreateCatalogStmt.java | 13 +-
.../org/apache/doris/analysis/DropCatalogStmt.java | 19 +--
.../java/org/apache/doris/analysis/GrantStmt.java | 10 +-
.../{DropCatalogStmt.java => SwitchStmt.java} | 55 +++----
.../java/org/apache/doris/catalog/Catalog.java | 9 ++
.../java/org/apache/doris/common/ErrorCode.java | 5 +-
.../java/org/apache/doris/common/util/Util.java | 28 ++++
.../org/apache/doris/datasource/DataSourceMgr.java | 27 +++-
.../apache/doris/mysql/privilege/DbPrivTable.java | 18 +++
.../org/apache/doris/mysql/privilege/PaloAuth.java | 52 ++++++-
.../doris/mysql/privilege/TablePrivTable.java | 17 +++
.../java/org/apache/doris/qe/StmtExecutor.java | 15 ++
fe/fe-core/src/main/jflex/sql_scanner.flex | 1 +
.../doris/analysis/AlterCatalogNameStmtTest.java | 2 +-
.../doris/analysis/AlterCatalogPropsStmtTest.java | 2 +-
.../doris/analysis/CreateCatalogStmtTest.java | 2 +-
.../apache/doris/analysis/DropCatalogStmtTest.java | 2 +-
.../org/apache/doris/analysis/SwitchStmtTest.java | 161 +++++++++++++++++++++
.../org/apache/doris/utframe/UtFrameUtils.java | 14 +-
22 files changed, 406 insertions(+), 101 deletions(-)
diff --git a/fe/fe-core/src/main/cup/sql_parser.cup b/fe/fe-core/src/main/cup/sql_parser.cup
index 0a1b969218..3b1404fc2e 100644
--- a/fe/fe-core/src/main/cup/sql_parser.cup
+++ b/fe/fe-core/src/main/cup/sql_parser.cup
@@ -278,7 +278,8 @@ terminal String KW_ADD, KW_ADMIN, KW_AFTER, KW_AGGREGATE, KW_ALIAS, KW_ALL, KW_A
KW_WARNINGS, KW_WEEK, KW_WHEN, KW_WHITELIST, KW_WHERE, KW_WITH, KW_WORK, KW_WRITE,
KW_YEAR,
KW_NOT_NULL,
- KW_CATALOG, KW_CATALOGS;
+ KW_CATALOG, KW_CATALOGS,
+ KW_SWITCH;
terminal COMMA, COLON, DOT, DOTDOTDOT, AT, STAR, LPAREN, RPAREN, SEMICOLON, LBRACKET, RBRACKET, DIVIDE, MOD, ADD, SUBTRACT;
terminal BITAND, BITOR, BITXOR, BITNOT;
@@ -301,7 +302,7 @@ nonterminal StatementBase stmt, show_stmt, show_param, help_stmt, load_stmt,
show_routine_load_stmt, show_routine_load_task_stmt, show_create_routine_load_stmt,
describe_stmt, alter_stmt,
use_stmt, kill_stmt, drop_stmt, recover_stmt, grant_stmt, revoke_stmt, create_stmt, set_stmt, sync_stmt, cancel_stmt, cancel_param, delete_stmt,
- link_stmt, migrate_stmt, enter_stmt, transaction_stmt, unsupported_stmt, export_stmt, admin_stmt, truncate_stmt,
+ link_stmt, migrate_stmt, switch_stmt, enter_stmt, transaction_stmt, unsupported_stmt, export_stmt, admin_stmt, truncate_stmt,
import_columns_stmt, import_delete_on_stmt, import_sequence_stmt, import_where_stmt, install_plugin_stmt, uninstall_plugin_stmt,
import_preceding_filter_stmt, unlock_tables_stmt, lock_tables_stmt, refresh_stmt;
@@ -670,6 +671,8 @@ stmt ::=
{: RESULT = query; :}
| migrate_stmt:query
{: RESULT = query; :}
+ | switch_stmt:stmt
+ {: RESULT = stmt; :}
| enter_stmt:enter
{: RESULT = enter; :}
| query_stmt:query
@@ -3422,6 +3425,14 @@ opt_set_qualifier ::=
{: RESULT = Qualifier.ALL; :}
;
+// Change catalog
+switch_stmt ::=
+ KW_SWITCH ident:catalog
+ {:
+ RESULT = new SwitchStmt(catalog);
+ :}
+ ;
+
// Change cluster
enter_stmt ::=
KW_ENTER ident:cluster
diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/AlterCatalogNameStmt.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/AlterCatalogNameStmt.java
index e8eb8bb473..67776bf510 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/analysis/AlterCatalogNameStmt.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/AlterCatalogNameStmt.java
@@ -17,18 +17,14 @@
package org.apache.doris.analysis;
-
-import org.apache.doris.analysis.CompoundPredicate.Operator;
import org.apache.doris.catalog.Catalog;
import org.apache.doris.common.AnalysisException;
-import org.apache.doris.common.Config;
import org.apache.doris.common.ErrorCode;
import org.apache.doris.common.ErrorReport;
import org.apache.doris.common.FeNameFormat;
import org.apache.doris.common.UserException;
+import org.apache.doris.common.util.Util;
import org.apache.doris.datasource.InternalDataSource;
-import org.apache.doris.mysql.privilege.PaloPrivilege;
-import org.apache.doris.mysql.privilege.PrivBitSet;
import org.apache.doris.mysql.privilege.PrivPredicate;
import org.apache.doris.qe.ConnectContext;
@@ -57,21 +53,15 @@ public class AlterCatalogNameStmt extends DdlStmt {
@Override
public void analyze(Analyzer analyzer) throws UserException {
super.analyze(analyzer);
- if (!Config.enable_multi_catalog) {
- throw new AnalysisException("The multi-catalog feature is still in experiment, and you can enable it "
- + "manually by set fe configuration named `enable_multi_catalog` to be ture.");
- }
- if (Strings.isNullOrEmpty(catalogName)) {
- throw new AnalysisException("Datasource name is not set");
- }
+ Util.checkCatalogAllRules(catalogName);
if (catalogName.equals(InternalDataSource.INTERNAL_DS_NAME)) {
throw new AnalysisException("Internal catalog can't be alter.");
}
- if (!Catalog.getCurrentCatalog().getAuth().checkGlobalPriv(ConnectContext.get(),
- PrivPredicate.of(PrivBitSet.of(PaloPrivilege.ADMIN_PRIV, PaloPrivilege.ALTER_PRIV), Operator.OR))) {
- ErrorReport.reportAnalysisException(ErrorCode.ERR_DBACCESS_DENIED_ERROR,
+ if (!Catalog.getCurrentCatalog().getAuth().checkCtlPriv(
+ ConnectContext.get(), catalogName, PrivPredicate.ALTER)) {
+ ErrorReport.reportAnalysisException(ErrorCode.ERR_CATALOG_ACCESS_DENIED,
analyzer.getQualifiedUser(), catalogName);
}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/AlterCatalogPropertyStmt.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/AlterCatalogPropertyStmt.java
index 7f39780eca..a19bf67fa0 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/analysis/AlterCatalogPropertyStmt.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/AlterCatalogPropertyStmt.java
@@ -17,14 +17,17 @@
package org.apache.doris.analysis;
+import org.apache.doris.catalog.Catalog;
import org.apache.doris.common.AnalysisException;
-import org.apache.doris.common.Config;
+import org.apache.doris.common.ErrorCode;
+import org.apache.doris.common.ErrorReport;
import org.apache.doris.common.FeNameFormat;
import org.apache.doris.common.UserException;
import org.apache.doris.common.util.PrintableMap;
+import org.apache.doris.common.util.Util;
import org.apache.doris.datasource.InternalDataSource;
-
-import com.google.common.base.Strings;
+import org.apache.doris.mysql.privilege.PrivPredicate;
+import org.apache.doris.qe.ConnectContext;
import java.util.Map;
@@ -51,12 +54,11 @@ public class AlterCatalogPropertyStmt extends DdlStmt {
@Override
public void analyze(Analyzer analyzer) throws UserException {
super.analyze(analyzer);
- if (!Config.enable_multi_catalog) {
- throw new AnalysisException("The multi-catalog feature is still in experiment, and you can enable it "
- + "manually by set fe configuration named `enable_multi_catalog` to be ture.");
- }
- if (Strings.isNullOrEmpty(catalogName)) {
- throw new AnalysisException("Datasource name is not set");
+ Util.checkCatalogAllRules(catalogName);
+ if (!Catalog.getCurrentCatalog().getAuth().checkCtlPriv(
+ ConnectContext.get(), catalogName, PrivPredicate.ALTER)) {
+ ErrorReport.reportAnalysisException(ErrorCode.ERR_CATALOG_ACCESS_DENIED,
+ analyzer.getQualifiedUser(), catalogName);
}
if (catalogName.equals(InternalDataSource.INTERNAL_DS_NAME)) {
diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/CreateCatalogStmt.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/CreateCatalogStmt.java
index ee89675d6c..d7ddd3320c 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/analysis/CreateCatalogStmt.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/CreateCatalogStmt.java
@@ -19,12 +19,12 @@ package org.apache.doris.analysis;
import org.apache.doris.catalog.Catalog;
import org.apache.doris.common.AnalysisException;
-import org.apache.doris.common.Config;
import org.apache.doris.common.ErrorCode;
import org.apache.doris.common.ErrorReport;
import org.apache.doris.common.FeNameFormat;
import org.apache.doris.common.UserException;
import org.apache.doris.common.util.PrintableMap;
+import org.apache.doris.common.util.Util;
import org.apache.doris.datasource.InternalDataSource;
import org.apache.doris.mysql.privilege.PrivPredicate;
import org.apache.doris.qe.ConnectContext;
@@ -64,17 +64,14 @@ public class CreateCatalogStmt extends DdlStmt {
@Override
public void analyze(Analyzer analyzer) throws UserException {
super.analyze(analyzer);
- if (!Config.enable_multi_catalog) {
- throw new AnalysisException("The multi-catalog feature is still in experiment, and you can enable it "
- + "manually by set fe configuration named `enable_multi_catalog` to be ture.");
- }
+ Util.checkCatalogAllRules(catalogName);
if (catalogName.equals(InternalDataSource.INTERNAL_DS_NAME)) {
throw new AnalysisException("Internal catalog name can't be create.");
}
- FeNameFormat.checkCommonName("catalog", catalogName);
- if (!Catalog.getCurrentCatalog().getAuth().checkGlobalPriv(ConnectContext.get(), PrivPredicate.CREATE)) {
- ErrorReport.reportAnalysisException(ErrorCode.ERR_DBACCESS_DENIED_ERROR,
+ if (!Catalog.getCurrentCatalog().getAuth().checkCtlPriv(
+ ConnectContext.get(), catalogName, PrivPredicate.CREATE)) {
+ ErrorReport.reportAnalysisException(ErrorCode.ERR_CATALOG_ACCESS_DENIED,
analyzer.getQualifiedUser(), catalogName);
}
FeNameFormat.checkCatalogProperties(properties);
diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/DropCatalogStmt.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/DropCatalogStmt.java
index aa620b17a4..6e5233916f 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/analysis/DropCatalogStmt.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/DropCatalogStmt.java
@@ -19,16 +19,14 @@ package org.apache.doris.analysis;
import org.apache.doris.catalog.Catalog;
import org.apache.doris.common.AnalysisException;
-import org.apache.doris.common.Config;
import org.apache.doris.common.ErrorCode;
import org.apache.doris.common.ErrorReport;
import org.apache.doris.common.UserException;
+import org.apache.doris.common.util.Util;
import org.apache.doris.datasource.InternalDataSource;
import org.apache.doris.mysql.privilege.PrivPredicate;
import org.apache.doris.qe.ConnectContext;
-import com.google.common.base.Strings;
-
/**
* Statement for drop a catalog.
*/
@@ -52,21 +50,16 @@ public class DropCatalogStmt extends DdlStmt {
@Override
public void analyze(Analyzer analyzer) throws UserException {
super.analyze(analyzer);
- if (!Config.enable_multi_catalog) {
- throw new AnalysisException("The multi-catalog feature is still in experiment, and you can enable it "
- + "manually by set fe configuration named `enable_multi_catalog` to be ture.");
- }
- if (Strings.isNullOrEmpty(catalogName)) {
- throw new AnalysisException("Datasource name is not set");
- }
+ Util.checkCatalogAllRules(catalogName);
if (catalogName.equals(InternalDataSource.INTERNAL_DS_NAME)) {
throw new AnalysisException("Internal catalog can't be drop.");
}
- if (!Catalog.getCurrentCatalog().getAuth().checkGlobalPriv(ConnectContext.get(), PrivPredicate.DROP)) {
- ErrorReport.reportAnalysisException(ErrorCode.ERR_DBACCESS_DENIED_ERROR,
- ConnectContext.get().getQualifiedUser(), catalogName);
+ if (!Catalog.getCurrentCatalog().getAuth().checkCtlPriv(
+ ConnectContext.get(), catalogName, PrivPredicate.DROP)) {
+ ErrorReport.reportAnalysisException(ErrorCode.ERR_CATALOG_ACCESS_DENIED,
+ analyzer.getQualifiedUser(), catalogName);
}
}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/GrantStmt.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/GrantStmt.java
index 4ad8fe8073..9d5cf88967 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/analysis/GrantStmt.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/GrantStmt.java
@@ -168,15 +168,21 @@ public class GrantStmt extends DdlStmt {
if (!Catalog.getCurrentCatalog().getAuth().checkGlobalPriv(ConnectContext.get(), PrivPredicate.GRANT)) {
ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ACCESS_DENIED_ERROR, "GRANT");
}
+ } else if (tblPattern.getPrivLevel() == PrivLevel.CATALOG) {
+ if (!Catalog.getCurrentCatalog().getAuth().checkCtlPriv(ConnectContext.get(),
+ tblPattern.getQualifiedCtl(), PrivPredicate.GRANT)) {
+ ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ACCESS_DENIED_ERROR, "GRANT");
+ }
} else if (tblPattern.getPrivLevel() == PrivLevel.DATABASE) {
if (!Catalog.getCurrentCatalog().getAuth().checkDbPriv(ConnectContext.get(),
- tblPattern.getQualifiedDb(), PrivPredicate.GRANT)) {
+ tblPattern.getQualifiedCtl(), tblPattern.getQualifiedDb(), PrivPredicate.GRANT)) {
ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ACCESS_DENIED_ERROR, "GRANT");
}
} else {
// table level
if (!Catalog.getCurrentCatalog().getAuth().checkTblPriv(ConnectContext.get(),
- tblPattern.getQualifiedDb(), tblPattern.getTbl(), PrivPredicate.GRANT)) {
+ tblPattern.getQualifiedCtl(), tblPattern.getQualifiedDb(),
+ tblPattern.getTbl(), PrivPredicate.GRANT)) {
ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ACCESS_DENIED_ERROR, "GRANT");
}
}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/DropCatalogStmt.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/SwitchStmt.java
similarity index 52%
copy from fe/fe-core/src/main/java/org/apache/doris/analysis/DropCatalogStmt.java
copy to fe/fe-core/src/main/java/org/apache/doris/analysis/SwitchStmt.java
index aa620b17a4..cf47511863 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/analysis/DropCatalogStmt.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/SwitchStmt.java
@@ -18,65 +18,48 @@
package org.apache.doris.analysis;
import org.apache.doris.catalog.Catalog;
-import org.apache.doris.common.AnalysisException;
-import org.apache.doris.common.Config;
import org.apache.doris.common.ErrorCode;
import org.apache.doris.common.ErrorReport;
import org.apache.doris.common.UserException;
-import org.apache.doris.datasource.InternalDataSource;
+import org.apache.doris.common.util.Util;
import org.apache.doris.mysql.privilege.PrivPredicate;
import org.apache.doris.qe.ConnectContext;
-import com.google.common.base.Strings;
-
-/**
- * Statement for drop a catalog.
- */
-public class DropCatalogStmt extends DdlStmt {
- private final boolean ifExists;
+public class SwitchStmt extends StatementBase {
private final String catalogName;
- public DropCatalogStmt(boolean ifExists, String catalogName) {
- this.ifExists = ifExists;
+ public SwitchStmt(String catalogName) {
this.catalogName = catalogName;
}
- public boolean isSetIfExists() {
- return ifExists;
+ public String getCatalogName() {
+ return catalogName;
}
- public String getCatalogName() {
- return this.catalogName;
+ @Override
+ public String toSql() {
+ return "SWITCH `" + catalogName + "`";
}
@Override
+ public String toString() {
+ return toSql();
+ }
+
public void analyze(Analyzer analyzer) throws UserException {
super.analyze(analyzer);
- if (!Config.enable_multi_catalog) {
- throw new AnalysisException("The multi-catalog feature is still in experiment, and you can enable it "
- + "manually by set fe configuration named `enable_multi_catalog` to be ture.");
- }
- if (Strings.isNullOrEmpty(catalogName)) {
- throw new AnalysisException("Datasource name is not set");
- }
- if (catalogName.equals(InternalDataSource.INTERNAL_DS_NAME)) {
- throw new AnalysisException("Internal catalog can't be drop.");
- }
+ Util.checkCatalogAllRules(catalogName);
- if (!Catalog.getCurrentCatalog().getAuth().checkGlobalPriv(ConnectContext.get(), PrivPredicate.DROP)) {
- ErrorReport.reportAnalysisException(ErrorCode.ERR_DBACCESS_DENIED_ERROR,
- ConnectContext.get().getQualifiedUser(), catalogName);
+ if (!Catalog.getCurrentCatalog().getAuth().checkCtlPriv(
+ ConnectContext.get(), catalogName, PrivPredicate.SHOW)) {
+ ErrorReport.reportAnalysisException(
+ ErrorCode.ERR_CATALOG_ACCESS_DENIED, analyzer.getQualifiedUser(), catalogName);
}
}
@Override
- public String toSql() {
- return "DROP CATALOG " + "`" + catalogName + "`";
- }
-
- @Override
- public String toString() {
- return toSql();
+ public RedirectStatus getRedirectStatus() {
+ return RedirectStatus.NO_FORWARD;
}
}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/Catalog.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/Catalog.java
index 4abd66d200..4b8c6a14da 100755
--- a/fe/fe-core/src/main/java/org/apache/doris/catalog/Catalog.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/Catalog.java
@@ -4218,6 +4218,15 @@ public class Catalog {
this.alter.getClusterHandler().cancel(stmt);
}
+ // Switch catalog of this sesseion.
+ public void changeCatalog(ConnectContext ctx, String catalogName) throws DdlException {
+ if (dataSourceMgr.getCatalogNullable(catalogName) == null) {
+ throw new DdlException(ErrorCode.ERR_UNKNOWN_CATALOG.formatErrorMsg(
+ catalogName), ErrorCode.ERR_UNKNOWN_CATALOG);
+ }
+ ctx.changeDefaultCatalog(catalogName);
+ }
+
// Change current database of this session.
public void changeDb(ConnectContext ctx, String qualifiedDb) throws DdlException {
if (!auth.checkDbPriv(ctx, qualifiedDb, PrivPredicate.SHOW)) {
diff --git a/fe/fe-core/src/main/java/org/apache/doris/common/ErrorCode.java b/fe/fe-core/src/main/java/org/apache/doris/common/ErrorCode.java
index a8f73b9773..4fdd640b4e 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/common/ErrorCode.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/common/ErrorCode.java
@@ -1686,7 +1686,10 @@ public enum ErrorCode {
+ "Use `SHOW PARTITIONS FROM %s` to see the currently partitions of this table. "),
ERROR_SQL_AND_LIMITATIONS_SET_IN_ONE_RULE(5084, new byte[]{'4', '2', '0', '0', '0'},
"sql/sqlHash and partition_num/tablet_num/cardinality cannot be set in one rule."),
- ERR_WRONG_CATALOG_NAME(5085, new byte[]{'4', '2', '0', '0', '0'}, "Incorrect catalog name '%s'");
+ ERR_WRONG_CATALOG_NAME(5085, new byte[]{'4', '2', '0', '0', '0'}, "Incorrect catalog name '%s'"),
+ ERR_UNKNOWN_CATALOG(5086, new byte[]{'4', '2', '0', '0', '0'}, "Unknown catalog '%s'"),
+ ERR_CATALOG_ACCESS_DENIED(5087, new byte[]{'4', '2', '0', '0', '0'},
+ "Access denied for user '%s' to catalog '%s'");
// This is error code
private final int code;
diff --git a/fe/fe-core/src/main/java/org/apache/doris/common/util/Util.java b/fe/fe-core/src/main/java/org/apache/doris/common/util/Util.java
index a63c40223e..b2857d26f3 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/common/util/Util.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/common/util/Util.java
@@ -20,6 +20,9 @@ package org.apache.doris.common.util;
import org.apache.doris.catalog.Column;
import org.apache.doris.catalog.PrimitiveType;
import org.apache.doris.common.AnalysisException;
+import org.apache.doris.common.Config;
+import org.apache.doris.common.FeNameFormat;
+import org.apache.doris.datasource.InternalDataSource;
import org.apache.doris.qe.ConnectContext;
import com.google.common.base.Preconditions;
@@ -457,4 +460,29 @@ public class Util {
}
return s;
}
+
+ /**
+ * Multi-catalog feature is in experiment, and should be enabled by user manually.
+ */
+ public static void checkCatalogEnabled() throws AnalysisException {
+ if (!Config.enable_multi_catalog) {
+ throw new AnalysisException("The multi-catalog feature is still in experiment, and you can enable it "
+ + "manually by set fe configuration named `enable_multi_catalog` to be ture.");
+ }
+ }
+
+ /**
+ * Check all rules of catalog.
+ */
+ public static void checkCatalogAllRules(String catalog) throws AnalysisException {
+ checkCatalogEnabled();
+
+ if (Strings.isNullOrEmpty(catalog)) {
+ throw new AnalysisException("Catalog name is empty.");
+ }
+
+ if (!catalog.equals(InternalDataSource.INTERNAL_DS_NAME)) {
+ FeNameFormat.checkCommonName("catalog", catalog);
+ }
+ }
}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/datasource/DataSourceMgr.java b/fe/fe-core/src/main/java/org/apache/doris/datasource/DataSourceMgr.java
index 1192eb2b22..d77cc9a18d 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/datasource/DataSourceMgr.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/datasource/DataSourceMgr.java
@@ -25,11 +25,15 @@ import org.apache.doris.analysis.ShowCatalogStmt;
import org.apache.doris.catalog.Catalog;
import org.apache.doris.common.AnalysisException;
import org.apache.doris.common.DdlException;
+import org.apache.doris.common.ErrorCode;
+import org.apache.doris.common.ErrorReport;
import org.apache.doris.common.UserException;
import org.apache.doris.common.io.Text;
import org.apache.doris.common.io.Writable;
+import org.apache.doris.mysql.privilege.PrivPredicate;
import org.apache.doris.persist.OperationType;
import org.apache.doris.persist.gson.GsonUtils;
+import org.apache.doris.qe.ConnectContext;
import org.apache.doris.qe.ShowResultSet;
import com.google.common.collect.Lists;
@@ -150,6 +154,13 @@ public class DataSourceMgr implements Writable {
Catalog.getCurrentCatalog().getEditLog().logDatasourceLog(OperationType.OP_ALTER_DS_PROPS, log);
}
+ /**
+ * Get catalog, or null if not exists.
+ */
+ public DataSourceIf getCatalogNullable(String catalogName) {
+ return nameToCatalogs.get(catalogName);
+ }
+
/**
* List all catalog or get the special catalog with a name.
*/
@@ -159,16 +170,24 @@ public class DataSourceMgr implements Writable {
try {
if (showStmt.getCatalogName() == null) {
for (DataSourceIf ds : nameToCatalogs.values()) {
- List<String> row = Lists.newArrayList();
- row.add(ds.getName());
- row.add(ds.getType());
- rows.add(row);
+ if (Catalog.getCurrentCatalog().getAuth().checkCtlPriv(
+ ConnectContext.get(), ds.getName(), PrivPredicate.SHOW)) {
+ List<String> row = Lists.newArrayList();
+ row.add(ds.getName());
+ row.add(ds.getType());
+ rows.add(row);
+ }
}
} else {
if (!nameToCatalogs.containsKey(showStmt.getCatalogName())) {
throw new AnalysisException("No catalog found with name: " + showStmt.getCatalogName());
}
DataSourceIf ds = nameToCatalogs.get(showStmt.getCatalogName());
+ if (!Catalog.getCurrentCatalog().getAuth().checkCtlPriv(
+ ConnectContext.get(), ds.getName(), PrivPredicate.SHOW)) {
+ ErrorReport.reportAnalysisException(ErrorCode.ERR_CATALOG_ACCESS_DENIED,
+ ConnectContext.get().getQualifiedUser(), ds.getName());
+ }
for (Map.Entry<String, String> elem : ds.getProperties().entrySet()) {
List<String> row = Lists.newArrayList();
row.add(elem.getKey());
diff --git a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/DbPrivTable.java b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/DbPrivTable.java
index 87ef9ad50e..961cd1cb8c 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/DbPrivTable.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/DbPrivTable.java
@@ -21,6 +21,7 @@ import org.apache.doris.analysis.UserIdentity;
import org.apache.doris.common.io.Text;
import org.apache.doris.qe.ConnectContext;
+import com.google.common.base.Preconditions;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -66,6 +67,23 @@ public class DbPrivTable extends PrivTable {
savedPrivs.or(matchedEntry.getPrivSet());
}
+ public boolean hasPrivsOfCatalog(UserIdentity currentUser, String ctl) {
+ for (PrivEntry entry : entries) {
+ DbPrivEntry dbPrivEntry = (DbPrivEntry) entry;
+
+ if (!dbPrivEntry.match(currentUser, true)) {
+ continue;
+ }
+
+ // check catalog
+ Preconditions.checkState(!dbPrivEntry.isAnyCtl());
+ if (dbPrivEntry.getCtlPattern().match(ctl)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
public boolean hasClusterPriv(ConnectContext ctx, String clusterName) {
for (PrivEntry entry : entries) {
DbPrivEntry dbPrivEntry = (DbPrivEntry) entry;
diff --git a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/PaloAuth.java b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/PaloAuth.java
index 9459f14ed9..e54232e024 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/PaloAuth.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/PaloAuth.java
@@ -353,6 +353,35 @@ public class PaloAuth implements Writable {
return false;
}
+ public boolean checkCtlPriv(ConnectContext ctx, String ctl, PrivPredicate wanted) {
+ return checkCtlPriv(ctx.getCurrentUserIdentity(), ctl, wanted);
+ }
+
+ public boolean checkCtlPriv(UserIdentity currentUser, String ctl, PrivPredicate wanted) {
+ if (!Config.enable_auth_check) {
+ return true;
+ }
+ if (wanted.getPrivs().containsNodePriv()) {
+ LOG.debug("should not check NODE priv in catalog level. user: {}, catalog: {}",
+ currentUser, ctl);
+ return false;
+ }
+
+ PrivBitSet savedPrivs = PrivBitSet.of();
+ if (checkGlobalInternal(currentUser, wanted, savedPrivs)
+ || checkCatalogInternal(currentUser, ctl, wanted, savedPrivs)) {
+ return true;
+ }
+
+ // if user has any privs of databases or tables in this catalog, and the wanted priv is SHOW, return true
+ if (ctl != null && wanted == PrivPredicate.SHOW && checkAnyPrivWithinCatalog(currentUser, ctl)) {
+ return true;
+ }
+
+ LOG.debug("failed to get wanted privs: {}, granted: {}", wanted, savedPrivs);
+ return false;
+ }
+
public boolean checkDbPriv(ConnectContext ctx, String qualifiedDb, PrivPredicate wanted) {
return checkDbPriv(ctx.getCurrentUserIdentity(), qualifiedDb, wanted);
}
@@ -361,6 +390,10 @@ public class PaloAuth implements Writable {
return checkDbPriv(currentUser, DEFAULT_CATALOG, db, wanted);
}
+ public boolean checkDbPriv(ConnectContext ctx, String ctl, String db, PrivPredicate wanted) {
+ return checkDbPriv(ctx.getCurrentUserIdentity(), ctl, db, wanted);
+ }
+
/*
* Check if 'user'@'host' on 'db' has 'wanted' priv.
* If the given db is null, which means it will no check if database name is matched.
@@ -383,7 +416,7 @@ public class PaloAuth implements Writable {
}
// if user has any privs of table in this db, and the wanted priv is SHOW, return true
- if (ctl != null && db != null && wanted == PrivPredicate.SHOW && checkTblWithDb(currentUser, ctl, db)) {
+ if (ctl != null && db != null && wanted == PrivPredicate.SHOW && checkAnyPrivWithinDb(currentUser, ctl, db)) {
return true;
}
@@ -391,12 +424,27 @@ public class PaloAuth implements Writable {
return false;
}
+ /*
+ * User may not have privs on a catalog, but have privs of databases or tables in this catalog.
+ * So we have to check if user has any privs of databases or tables in this catalog.
+ * if so, the catalog should be visible to this user.
+ */
+ private boolean checkAnyPrivWithinCatalog(UserIdentity currentUser, String ctl) {
+ readLock();
+ try {
+ return dbPrivTable.hasPrivsOfCatalog(currentUser, ctl)
+ || tablePrivTable.hasPrivsOfCatalog(currentUser, ctl);
+ } finally {
+ readUnlock();
+ }
+ }
+
/*
* User may not have privs on a database, but have privs of tables in this database.
* So we have to check if user has any privs of tables in this database.
* if so, the database should be visible to this user.
*/
- private boolean checkTblWithDb(UserIdentity currentUser, String ctl, String db) {
+ private boolean checkAnyPrivWithinDb(UserIdentity currentUser, String ctl, String db) {
readLock();
try {
return (isLdapAuthEnabled() && LdapPrivsChecker.hasPrivsOfDb(currentUser, db))
diff --git a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/TablePrivTable.java b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/TablePrivTable.java
index 475452ac29..c4ded036f1 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/TablePrivTable.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/TablePrivTable.java
@@ -69,6 +69,23 @@ public class TablePrivTable extends PrivTable {
savedPrivs.or(matchedEntry.getPrivSet());
}
+ public boolean hasPrivsOfCatalog(UserIdentity currentUser, String ctl) {
+ for (PrivEntry entry : entries) {
+ TablePrivEntry tblPrivEntry = (TablePrivEntry) entry;
+
+ if (!tblPrivEntry.match(currentUser, true)) {
+ continue;
+ }
+
+ // check catalog
+ Preconditions.checkState(!tblPrivEntry.isAnyCtl());
+ if (tblPrivEntry.getCtlPattern().match(ctl)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
public boolean hasPrivsOfDb(UserIdentity currentUser, String ctl, String db) {
for (PrivEntry entry : entries) {
TablePrivEntry tblPrivEntry = (TablePrivEntry) entry;
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 e9e6d4e215..ba4ab0d200 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
@@ -44,6 +44,7 @@ import org.apache.doris.analysis.SqlScanner;
import org.apache.doris.analysis.StatementBase;
import org.apache.doris.analysis.StmtRewriter;
import org.apache.doris.analysis.StringLiteral;
+import org.apache.doris.analysis.SwitchStmt;
import org.apache.doris.analysis.TransactionBeginStmt;
import org.apache.doris.analysis.TransactionCommitStmt;
import org.apache.doris.analysis.TransactionRollbackStmt;
@@ -414,6 +415,8 @@ public class StmtExecutor implements ProfileWriter {
handleSetStmt();
} else if (parsedStmt instanceof EnterStmt) {
handleEnterStmt();
+ } else if (parsedStmt instanceof SwitchStmt) {
+ handleSwitchStmt();
} else if (parsedStmt instanceof UseStmt) {
handleUseStmt();
} else if (parsedStmt instanceof TransactionStmt) {
@@ -1410,6 +1413,18 @@ public class StmtExecutor implements ProfileWriter {
context.getState().setOk();
}
+ // Process switch catalog
+ private void handleSwitchStmt() throws AnalysisException {
+ SwitchStmt switchStmt = (SwitchStmt) parsedStmt;
+ try {
+ context.getCatalog().changeCatalog(context, switchStmt.getCatalogName());
+ } catch (DdlException e) {
+ context.getState().setError(e.getMysqlErrorCode(), e.getMessage());
+ return;
+ }
+ context.getState().setOk();
+ }
+
// Process use statement.
private void handleUseStmt() throws AnalysisException {
UseStmt useStmt = (UseStmt) parsedStmt;
diff --git a/fe/fe-core/src/main/jflex/sql_scanner.flex b/fe/fe-core/src/main/jflex/sql_scanner.flex
index f7d3638c2a..ecc4a59b65 100644
--- a/fe/fe-core/src/main/jflex/sql_scanner.flex
+++ b/fe/fe-core/src/main/jflex/sql_scanner.flex
@@ -435,6 +435,7 @@ import org.apache.doris.qe.SqlModeHelper;
keywordMap.put("not_null", new Integer(SqlParserSymbols.KW_NOT_NULL));
keywordMap.put("catalog", new Integer(SqlParserSymbols.KW_CATALOG));
keywordMap.put("catalogs", new Integer(SqlParserSymbols.KW_CATALOGS));
+ keywordMap.put("switch", new Integer(SqlParserSymbols.KW_SWITCH));
}
// map from token id to token description
diff --git a/fe/fe-core/src/test/java/org/apache/doris/analysis/AlterCatalogNameStmtTest.java b/fe/fe-core/src/test/java/org/apache/doris/analysis/AlterCatalogNameStmtTest.java
index c7f3e393d0..25c05d05dd 100644
--- a/fe/fe-core/src/test/java/org/apache/doris/analysis/AlterCatalogNameStmtTest.java
+++ b/fe/fe-core/src/test/java/org/apache/doris/analysis/AlterCatalogNameStmtTest.java
@@ -43,7 +43,7 @@ public class AlterCatalogNameStmtTest {
Config.enable_multi_catalog = true;
analyzer = AccessTestUtil.fetchAdminAnalyzer(false);
MockedAuth.mockedAuth(auth);
- MockedAuth.mockedConnectContext(ctx, "root", "127.0.0.1");
+ MockedAuth.mockedConnectContext(ctx, "root", "%");
}
@Test
diff --git a/fe/fe-core/src/test/java/org/apache/doris/analysis/AlterCatalogPropsStmtTest.java b/fe/fe-core/src/test/java/org/apache/doris/analysis/AlterCatalogPropsStmtTest.java
index 821d65498a..d1b8f09b55 100644
--- a/fe/fe-core/src/test/java/org/apache/doris/analysis/AlterCatalogPropsStmtTest.java
+++ b/fe/fe-core/src/test/java/org/apache/doris/analysis/AlterCatalogPropsStmtTest.java
@@ -46,7 +46,7 @@ public class AlterCatalogPropsStmtTest {
Config.enable_multi_catalog = true;
analyzer = AccessTestUtil.fetchAdminAnalyzer(false);
MockedAuth.mockedAuth(auth);
- MockedAuth.mockedConnectContext(ctx, "root", "127.0.0.1");
+ MockedAuth.mockedConnectContext(ctx, "root", "%");
}
@Test
diff --git a/fe/fe-core/src/test/java/org/apache/doris/analysis/CreateCatalogStmtTest.java b/fe/fe-core/src/test/java/org/apache/doris/analysis/CreateCatalogStmtTest.java
index 4d61e6c219..1313991c03 100644
--- a/fe/fe-core/src/test/java/org/apache/doris/analysis/CreateCatalogStmtTest.java
+++ b/fe/fe-core/src/test/java/org/apache/doris/analysis/CreateCatalogStmtTest.java
@@ -47,7 +47,7 @@ public class CreateCatalogStmtTest {
Config.enable_multi_catalog = true;
analyzer = AccessTestUtil.fetchAdminAnalyzer(true);
MockedAuth.mockedAuth(auth);
- MockedAuth.mockedConnectContext(ctx, "root", "127.0.0.1");
+ MockedAuth.mockedConnectContext(ctx, "root", "%");
}
@Test
diff --git a/fe/fe-core/src/test/java/org/apache/doris/analysis/DropCatalogStmtTest.java b/fe/fe-core/src/test/java/org/apache/doris/analysis/DropCatalogStmtTest.java
index 36357bfc7e..5ff0ce6056 100644
--- a/fe/fe-core/src/test/java/org/apache/doris/analysis/DropCatalogStmtTest.java
+++ b/fe/fe-core/src/test/java/org/apache/doris/analysis/DropCatalogStmtTest.java
@@ -44,7 +44,7 @@ public class DropCatalogStmtTest {
Config.enable_multi_catalog = true;
analyzer = AccessTestUtil.fetchAdminAnalyzer(true);
MockedAuth.mockedAuth(auth);
- MockedAuth.mockedConnectContext(ctx, "root", "127.0.0.1");
+ MockedAuth.mockedConnectContext(ctx, "root", "%");
}
@Test
diff --git a/fe/fe-core/src/test/java/org/apache/doris/analysis/SwitchStmtTest.java b/fe/fe-core/src/test/java/org/apache/doris/analysis/SwitchStmtTest.java
new file mode 100644
index 0000000000..d90a8a68d2
--- /dev/null
+++ b/fe/fe-core/src/test/java/org/apache/doris/analysis/SwitchStmtTest.java
@@ -0,0 +1,161 @@
+// 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.analysis;
+
+import org.apache.doris.catalog.Catalog;
+import org.apache.doris.common.AnalysisException;
+import org.apache.doris.common.Config;
+import org.apache.doris.datasource.InternalDataSource;
+import org.apache.doris.mysql.privilege.PaloAuth;
+import org.apache.doris.qe.ConnectContext;
+import org.apache.doris.utframe.DorisAssert;
+import org.apache.doris.utframe.UtFrameUtils;
+
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.util.List;
+import java.util.UUID;
+
+public class SwitchStmtTest {
+ private static String runningDir = "fe/mocked/DemoTest/" + UUID.randomUUID().toString() + "/";
+ private static DorisAssert dorisAssert;
+ private static String clusterName = "default_cluster";
+
+ private static PaloAuth auth;
+ private static Catalog catalog;
+ private static UserIdentity user1;
+ private static UserIdentity user2;
+
+ @AfterClass
+ public static void tearDown() throws Exception {
+ UtFrameUtils.cleanDorisFeDir(runningDir);
+ }
+
+ @BeforeClass
+ public static void setUp() throws Exception {
+ Config.enable_multi_catalog = true;
+ UtFrameUtils.createDorisCluster(runningDir);
+
+ // use root to initialize.
+ ConnectContext rootCtx = UtFrameUtils.createDefaultCtx();
+ catalog = Catalog.getCurrentCatalog();
+ auth = catalog.getAuth();
+
+ // grant with no catalog is switched, internal catalog works.
+ CreateRoleStmt createRole1 = (CreateRoleStmt) UtFrameUtils.parseAndAnalyzeStmt("create role role1;", rootCtx);
+ auth.createRole(createRole1);
+ GrantStmt grantRole1 = (GrantStmt) UtFrameUtils.parseAndAnalyzeStmt(
+ "grant grant_priv on tpch.* to role 'role1';", rootCtx);
+ auth.grant(grantRole1);
+ // user1 can't switch to hive
+ auth.createUser((CreateUserStmt) UtFrameUtils.parseAndAnalyzeStmt(
+ "create user 'user1'@'%' identified by 'pwd1' default role 'role1';", rootCtx));
+ user1 = new UserIdentity("user1", "%");
+ user1.analyze(clusterName);
+
+ // create catalog
+ CreateCatalogStmt hiveCatalog = (CreateCatalogStmt) UtFrameUtils.parseAndAnalyzeStmt(
+ "create catalog hive properties('type' = 'hms', 'hive.metastore.uris' = 'thrift://192.168.0.1:9083');",
+ rootCtx);
+ catalog.getDataSourceMgr().createCatalog(hiveCatalog);
+ CreateCatalogStmt iceBergCatalog = (CreateCatalogStmt) UtFrameUtils.parseAndAnalyzeStmt(
+ "create catalog iceberg properties('type' = 'hms', 'iceberg.hive.metastore.uris' = 'thrift://192.168.0.1:9083');",
+ rootCtx);
+ catalog.getDataSourceMgr().createCatalog(iceBergCatalog);
+
+ // switch to hive.
+ SwitchStmt switchHive = (SwitchStmt) UtFrameUtils.parseAndAnalyzeStmt("switch hive;", rootCtx);
+ catalog.changeCatalog(rootCtx, switchHive.getCatalogName());
+ CreateRoleStmt createRole2 = (CreateRoleStmt) UtFrameUtils.parseAndAnalyzeStmt("create role role2;", rootCtx);
+ auth.createRole(createRole2);
+ GrantStmt grantRole2 = (GrantStmt) UtFrameUtils.parseAndAnalyzeStmt(
+ "grant grant_priv on tpch.customer to role 'role2';", rootCtx);
+ auth.grant(grantRole2);
+ auth.createUser((CreateUserStmt) UtFrameUtils.parseAndAnalyzeStmt(
+ "create user 'user2'@'%' identified by 'pwd2' default role 'role2';", rootCtx));
+ user2 = new UserIdentity("user2", "%");
+ user2.analyze(clusterName);
+ }
+
+ @Test
+ public void testSwitchCommand() throws Exception {
+ // mock the login of user1
+ ConnectContext user1Ctx = UtFrameUtils.createDefaultCtx(user1, "127.0.0.1");
+ // user1 can switch to internal catalog
+ UtFrameUtils.parseAndAnalyzeStmt("switch " + InternalDataSource.INTERNAL_DS_NAME + ";", user1Ctx);
+ Assert.assertEquals(InternalDataSource.INTERNAL_DS_NAME, user1Ctx.getDefaultCatalog());
+ // user1 can't switch to hive
+ try {
+ UtFrameUtils.parseAndAnalyzeStmt("switch hive;", user1Ctx);
+ Assert.fail("user1 switch to hive with no privilege.");
+ } catch (AnalysisException e) {
+ Assert.assertEquals(e.getMessage(),
+ "errCode = 2, detailMessage = Access denied for user 'default_cluster:user1' to catalog 'hive'");
+ }
+ Assert.assertEquals(InternalDataSource.INTERNAL_DS_NAME, user1Ctx.getDefaultCatalog());
+
+ // mock the login of user2
+ ConnectContext user2Ctx = UtFrameUtils.createDefaultCtx(user2, "127.0.0.1");
+ // user2 can switch to internal catalog
+ UtFrameUtils.parseAndAnalyzeStmt("switch " + InternalDataSource.INTERNAL_DS_NAME + ";", user2Ctx);
+ Assert.assertEquals(InternalDataSource.INTERNAL_DS_NAME, user2Ctx.getDefaultCatalog());
+ // user2 can switch to hive
+ SwitchStmt switchHive = (SwitchStmt) UtFrameUtils.parseAndAnalyzeStmt("switch hive;", user2Ctx);
+ catalog.changeCatalog(user2Ctx, switchHive.getCatalogName());
+ Assert.assertEquals(user2Ctx.getDefaultCatalog(), "hive");
+ // user2 can grant select_priv to tpch.customer
+ GrantStmt user2GrantHiveTable = (GrantStmt) UtFrameUtils.parseAndAnalyzeStmt(
+ "grant select_priv on tpch.customer to 'user2'@'%';", user2Ctx);
+ auth.grant(user2GrantHiveTable);
+ }
+
+ @Test
+ public void testShowCatalogStmtWithPrivileges() throws Exception {
+ // mock the login of user1
+ ConnectContext user1Ctx = UtFrameUtils.createDefaultCtx(user1, "127.0.0.1");
+ ShowCatalogStmt user1Show = (ShowCatalogStmt) UtFrameUtils.parseAndAnalyzeStmt("show catalogs;", user1Ctx);
+ List<List<String>> user1ShowResult = catalog.getDataSourceMgr().showCatalogs(user1Show).getResultRows();
+ Assert.assertEquals(user1ShowResult.size(), 1);
+ Assert.assertEquals(user1ShowResult.get(0).get(0), InternalDataSource.INTERNAL_DS_NAME);
+
+ // mock the login of user1
+ ConnectContext user2Ctx = UtFrameUtils.createDefaultCtx(user2, "127.0.0.1");
+ ShowCatalogStmt user2Show = (ShowCatalogStmt) UtFrameUtils.parseAndAnalyzeStmt("show catalogs;", user2Ctx);
+ List<List<String>> user2ShowResult = catalog.getDataSourceMgr().showCatalogs(user2Show).getResultRows();
+ Assert.assertEquals(user2ShowResult.size(), 2);
+ Assert.assertTrue(user2ShowResult.stream().map(l -> l.get(0)).anyMatch(c -> c.equals("hive")));
+
+ // access denied
+ ShowCatalogStmt user2ShowHive = (ShowCatalogStmt) UtFrameUtils.parseAndAnalyzeStmt("show catalog hive;",
+ user2Ctx);
+ List<List<String>> user2ShowHiveResult = catalog.getDataSourceMgr().showCatalogs(user2ShowHive).getResultRows();
+ Assert.assertTrue(
+ user2ShowHiveResult.stream().map(l -> l.get(0)).anyMatch(c -> c.equals("hive.metastore.uris")));
+ try {
+ catalog.getDataSourceMgr().showCatalogs(
+ (ShowCatalogStmt) UtFrameUtils.parseAndAnalyzeStmt("show catalog iceberg;", user2Ctx));
+ Assert.fail("");
+ } catch (AnalysisException e) {
+ Assert.assertEquals(e.getMessage(),
+ "errCode = 2, detailMessage = Access denied for user 'default_cluster:user2' to catalog 'iceberg'");
+ }
+ }
+}
diff --git a/fe/fe-core/src/test/java/org/apache/doris/utframe/UtFrameUtils.java b/fe/fe-core/src/test/java/org/apache/doris/utframe/UtFrameUtils.java
index 9bbf6278b7..e822667383 100644
--- a/fe/fe-core/src/test/java/org/apache/doris/utframe/UtFrameUtils.java
+++ b/fe/fe-core/src/test/java/org/apache/doris/utframe/UtFrameUtils.java
@@ -31,7 +31,6 @@ import org.apache.doris.common.Config;
import org.apache.doris.common.DdlException;
import org.apache.doris.common.FeConstants;
import org.apache.doris.common.util.SqlParserUtils;
-import org.apache.doris.mysql.privilege.PaloAuth;
import org.apache.doris.planner.Planner;
import org.apache.doris.qe.ConnectContext;
import org.apache.doris.qe.OriginStatement;
@@ -74,18 +73,23 @@ import java.util.UUID;
public class UtFrameUtils {
// Help to create a mocked ConnectContext.
- public static ConnectContext createDefaultCtx() throws IOException {
+ public static ConnectContext createDefaultCtx(UserIdentity userIdentity, String remoteIp) throws IOException {
SocketChannel channel = SocketChannel.open();
ConnectContext ctx = new ConnectContext(channel);
ctx.setCluster(SystemInfoService.DEFAULT_CLUSTER);
- ctx.setCurrentUserIdentity(UserIdentity.ROOT);
- ctx.setQualifiedUser(PaloAuth.ROOT_USER);
- ctx.setRemoteIP("127.0.0.1");
+ ctx.setCurrentUserIdentity(userIdentity);
+ ctx.setQualifiedUser(userIdentity.getQualifiedUser());
+ ctx.setRemoteIP(remoteIp);
ctx.setCatalog(Catalog.getCurrentCatalog());
ctx.setThreadLocalInfo();
return ctx;
}
+ // Help to create a mocked ConnectContext for root.
+ public static ConnectContext createDefaultCtx() throws IOException {
+ return createDefaultCtx(UserIdentity.ROOT, "127.0.0.1");
+ }
+
// Parse an origin stmt and analyze it. Return a StatementBase instance.
public static StatementBase parseAndAnalyzeStmt(String originStmt, ConnectContext ctx)
throws Exception {
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org