This is an automated email from the ASF dual-hosted git repository. starocean999 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 c37fbe52ef9 [Enhancement] (nereids)implement showUserPropertiesCommand and showAllPropertiesCommand in nereids (#45145) c37fbe52ef9 is described below commit c37fbe52ef96ede5039efbd546395e1c34150505 Author: Sridhar R Manikarnike <sridhar.n...@gmail.com> AuthorDate: Thu Jan 2 07:03:29 2025 +0530 [Enhancement] (nereids)implement showUserPropertiesCommand and showAllPropertiesCommand in nereids (#45145) Issue Number: close #42759 close #42760 --- .../antlr4/org/apache/doris/nereids/DorisParser.g4 | 4 +- .../doris/nereids/parser/LogicalPlanBuilder.java | 22 +++ .../apache/doris/nereids/trees/plans/PlanType.java | 1 + .../plans/commands/ShowUserPropertyCommand.java | 161 +++++++++++++++++++++ .../trees/plans/visitor/CommandVisitor.java | 5 + .../show/test_show_user_properties_command.groovy | 48 ++++++ 6 files changed, 239 insertions(+), 2 deletions(-) diff --git a/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4 b/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4 index 8a4490bda83..907c25cfe2d 100644 --- a/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4 +++ b/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4 @@ -272,6 +272,8 @@ supportedShowStatement | SHOW FILE ((FROM | IN) database=multipartIdentifier)? #showSmallFiles | SHOW STORAGE? ENGINES #showStorageEngines | SHOW CREATE CATALOG name=identifier #showCreateCatalog + | SHOW PROPERTY (FOR user=identifierOrText)? (LIKE STRING_LITERAL)? #showUserProperties + | SHOW ALL PROPERTIES (LIKE STRING_LITERAL)? #showAllProperties | SHOW COLLATION wildWhere? #showCollation | SHOW SQL_BLOCK_RULE (FOR ruleName=identifier)? #showSqlBlockRule | SHOW CREATE VIEW name=multipartIdentifier #showCreateView @@ -368,8 +370,6 @@ unsupportedShowStatement | SHOW TABLET tabletId=INTEGER_VALUE #showTabletId | SHOW TABLETS FROM tableName=multipartIdentifier partitionSpec? wildWhere? sortClause? limitClause? #showTabletsFromTable - | SHOW PROPERTY (FOR user=identifierOrText)? wildWhere? #showUserProperties - | SHOW ALL PROPERTIES wildWhere? #showAllProperties | SHOW BACKUP ((FROM | IN) database=multipartIdentifier)? wildWhere? #showBackup | SHOW BRIEF? RESTORE ((FROM | IN) database=multipartIdentifier)? wildWhere? #showRestore | SHOW RESOURCES wildWhere? sortClause? limitClause? #showResources diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java index f33d414eda6..82c8be68e48 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java @@ -267,6 +267,7 @@ import org.apache.doris.nereids.DorisParser.SetTransactionContext; import org.apache.doris.nereids.DorisParser.SetUserPropertiesContext; import org.apache.doris.nereids.DorisParser.SetUserVariableContext; import org.apache.doris.nereids.DorisParser.SetVariableWithTypeContext; +import org.apache.doris.nereids.DorisParser.ShowAllPropertiesContext; import org.apache.doris.nereids.DorisParser.ShowAuthorsContext; import org.apache.doris.nereids.DorisParser.ShowBackendsContext; import org.apache.doris.nereids.DorisParser.ShowBrokerContext; @@ -316,6 +317,7 @@ import org.apache.doris.nereids.DorisParser.ShowTabletStorageFormatContext; import org.apache.doris.nereids.DorisParser.ShowTabletsBelongContext; import org.apache.doris.nereids.DorisParser.ShowTrashContext; import org.apache.doris.nereids.DorisParser.ShowTriggersContext; +import org.apache.doris.nereids.DorisParser.ShowUserPropertiesContext; import org.apache.doris.nereids.DorisParser.ShowVariablesContext; import org.apache.doris.nereids.DorisParser.ShowViewContext; import org.apache.doris.nereids.DorisParser.ShowWarningErrorCountContext; @@ -599,6 +601,7 @@ import org.apache.doris.nereids.trees.plans.commands.ShowTabletStorageFormatComm import org.apache.doris.nereids.trees.plans.commands.ShowTabletsBelongCommand; import org.apache.doris.nereids.trees.plans.commands.ShowTrashCommand; import org.apache.doris.nereids.trees.plans.commands.ShowTriggersCommand; +import org.apache.doris.nereids.trees.plans.commands.ShowUserPropertyCommand; import org.apache.doris.nereids.trees.plans.commands.ShowVariablesCommand; import org.apache.doris.nereids.trees.plans.commands.ShowViewCommand; import org.apache.doris.nereids.trees.plans.commands.ShowWarningErrorCountCommand; @@ -5021,6 +5024,25 @@ public class LogicalPlanBuilder extends DorisParserBaseVisitor<Object> { return new ShowWhiteListCommand(); } + @Override + public LogicalPlan visitShowUserProperties(ShowUserPropertiesContext ctx) { + String user = ctx.user != null ? stripQuotes(ctx.user.getText()) : null; + String pattern = null; + if (ctx.LIKE() != null) { + pattern = stripQuotes(ctx.STRING_LITERAL().getText()); + } + return new ShowUserPropertyCommand(user, pattern, false); + } + + @Override + public LogicalPlan visitShowAllProperties(ShowAllPropertiesContext ctx) { + String pattern = null; + if (ctx.LIKE() != null) { + pattern = stripQuotes(ctx.STRING_LITERAL().getText()); + } + return new ShowUserPropertyCommand(null, pattern, true); + } + @Override public LogicalPlan visitAlterCatalogComment(AlterCatalogCommentContext ctx) { String catalogName = stripQuotes(ctx.name.getText()); diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/PlanType.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/PlanType.java index 9c7c82a337c..c90734ce8a7 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/PlanType.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/PlanType.java @@ -252,6 +252,7 @@ public enum PlanType { SHOW_TRIGGERS_COMMAND, SHOW_VARIABLES_COMMAND, SHOW_AUTHORS_COMMAND, + SHOW_USER_PROPERTY_COMMAND, SHOW_VIEW_COMMAND, SHOW_WARNING_ERRORS_COMMAND, SHOW_WARNING_ERROR_COUNT_COMMAND, diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ShowUserPropertyCommand.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ShowUserPropertyCommand.java new file mode 100644 index 00000000000..edc3f03f6f4 --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ShowUserPropertyCommand.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.nereids.trees.plans.commands; + +import org.apache.doris.analysis.SetUserPropertyVar; +import org.apache.doris.catalog.Column; +import org.apache.doris.catalog.Env; +import org.apache.doris.catalog.ScalarType; +import org.apache.doris.common.AnalysisException; +import org.apache.doris.common.CaseSensibility; +import org.apache.doris.common.ErrorCode; +import org.apache.doris.common.ErrorReport; +import org.apache.doris.common.PatternMatcher; +import org.apache.doris.common.PatternMatcherWrapper; +import org.apache.doris.common.proc.UserPropertyProcNode; +import org.apache.doris.mysql.privilege.PrivPredicate; +import org.apache.doris.nereids.trees.plans.PlanType; +import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor; +import org.apache.doris.persist.gson.GsonUtils; +import org.apache.doris.qe.ConnectContext; +import org.apache.doris.qe.ShowResultSet; +import org.apache.doris.qe.ShowResultSetMetaData; +import org.apache.doris.qe.StmtExecutor; + +import com.google.common.base.Strings; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * Represents the command for SHOW ALL/USER PROPERTIES COMMAND. + */ +public class ShowUserPropertyCommand extends ShowCommand { + private String user; + private String pattern; + private boolean isAll; + + public ShowUserPropertyCommand(String user, String pattern, boolean isAll) { + super(PlanType.SHOW_USER_PROPERTY_COMMAND); + this.user = user; + this.pattern = pattern; + this.isAll = isAll; + } + + private void validate(ConnectContext ctx) throws AnalysisException { + boolean needCheckAuth = true; + if (!Strings.isNullOrEmpty(user)) { + if (isAll) { + throw new AnalysisException("Can not specified keyword ALL when specified user"); + } + } else { + if (!isAll) { + // self + user = ctx.getQualifiedUser(); + // user can see itself's property, no need to check privs + needCheckAuth = false; + } + } + + if (needCheckAuth) { + if (!Env.getCurrentEnv().getAccessManager().checkGlobalPriv(ConnectContext.get(), PrivPredicate.GRANT)) { + ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ACCESS_DENIED_ERROR, "GRANT"); + } + } + + pattern = Strings.emptyToNull(pattern); + } + + @Override + public <R, C> R accept(PlanVisitor<R, C> visitor, C context) { + return visitor.visitShowUserPropertyCommand(this, context); + } + + @Override + public ShowResultSet doRun(ConnectContext ctx, StmtExecutor executor) throws Exception { + validate(ctx); + return new ShowResultSet(getMetaData(), getRows()); + } + + private List<List<String>> getRows() throws AnalysisException { + return isAll ? getRowsForAllUser() : getRowsForOneUser(); + } + + private List<List<String>> getRowsForOneUser() throws AnalysisException { + List<List<String>> rows = Env.getCurrentEnv().getAuth().getUserProperties(user); + + if (pattern == null) { + return rows; + } + + List<List<String>> result = Lists.newArrayList(); + PatternMatcher matcher = PatternMatcherWrapper.createMysqlPattern(pattern, + CaseSensibility.USER.getCaseSensibility()); + for (List<String> row : rows) { + String key = row.get(0).split("\\" + SetUserPropertyVar.DOT_SEPARATOR)[0]; + if (matcher.match(key)) { + result.add(row); + } + } + + return result; + } + + private List<List<String>> getRowsForAllUser() throws AnalysisException { + Set<String> allUser = Env.getCurrentEnv().getAuth().getAllUser(); + List<List<String>> result = Lists.newArrayListWithCapacity(allUser.size()); + + for (String user : allUser) { + List<String> row = Lists.newArrayListWithCapacity(2); + row.add(user); + row.add(GsonUtils.GSON.toJson(getRowsForUser(user))); + result.add(row); + } + return result; + } + + private Map<String, String> getRowsForUser(String user) throws AnalysisException { + Map<String, String> result = Maps.newHashMap(); + List<List<String>> userProperties = Env.getCurrentEnv().getAuth() + .getUserProperties(user); + PatternMatcher matcher = null; + if (pattern != null) { + matcher = PatternMatcherWrapper.createMysqlPattern(pattern, + CaseSensibility.USER.getCaseSensibility()); + } + + for (List<String> row : userProperties) { + String key = row.get(0).split("\\" + SetUserPropertyVar.DOT_SEPARATOR)[0]; + if (matcher == null || matcher.match(key)) { + result.put(row.get(0), row.get(1)); + } + } + return result; + } + + public ShowResultSetMetaData getMetaData() { + ShowResultSetMetaData.Builder builder = ShowResultSetMetaData.builder(); + for (String col : isAll ? UserPropertyProcNode.ALL_USER_TITLE_NAMES : UserPropertyProcNode.TITLE_NAMES) { + builder.addColumn(new Column(col, ScalarType.createVarchar(30))); + } + return builder.build(); + } +} diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/visitor/CommandVisitor.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/visitor/CommandVisitor.java index c0be169ef30..e7f9660ebef 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/visitor/CommandVisitor.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/visitor/CommandVisitor.java @@ -138,6 +138,7 @@ import org.apache.doris.nereids.trees.plans.commands.ShowTabletStorageFormatComm import org.apache.doris.nereids.trees.plans.commands.ShowTabletsBelongCommand; import org.apache.doris.nereids.trees.plans.commands.ShowTrashCommand; import org.apache.doris.nereids.trees.plans.commands.ShowTriggersCommand; +import org.apache.doris.nereids.trees.plans.commands.ShowUserPropertyCommand; import org.apache.doris.nereids.trees.plans.commands.ShowVariablesCommand; import org.apache.doris.nereids.trees.plans.commands.ShowViewCommand; import org.apache.doris.nereids.trees.plans.commands.ShowWarningErrorCountCommand; @@ -682,6 +683,10 @@ public interface CommandVisitor<R, C> { return visitCommand(showPrivilegesCommand, context); } + default R visitShowUserPropertyCommand(ShowUserPropertyCommand showUserpropertyCommand, C context) { + return visitCommand(showUserpropertyCommand, context); + } + default R visitShowTabletsBelongCommand(ShowTabletsBelongCommand showTabletBelongCommand, C context) { return visitCommand(showTabletBelongCommand, context); } diff --git a/regression-test/suites/nereids_p0/show/test_show_user_properties_command.groovy b/regression-test/suites/nereids_p0/show/test_show_user_properties_command.groovy new file mode 100644 index 00000000000..be11af1596e --- /dev/null +++ b/regression-test/suites/nereids_p0/show/test_show_user_properties_command.groovy @@ -0,0 +1,48 @@ +// 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. + +suite("test_show_user_properties_command", "query,nereids") { + def currentUser = "root" + + // Test SHOW PROPERTY FOR USER command + try { + checkNereidsExecute("""SHOW PROPERTY FOR USER ${currentUser};""") + } catch (Exception e) { + log.error("Failed to execute SHOW PROPERTY FOR USER command", e) + } + + // Test SHOW PROPERTY FOR USER command with wildWhere condition + try { + checkNereidsExecute("""SHOW PROPERTY FOR USER ${currentUser} LIKE 'property_name%';""") + } catch (Exception e) { + log.error("Failed to execute SHOW PROPERTY FOR USER command with LIKE clause", e) + } + + // Test SHOW ALL PROPERTIES command + try { + checkNereidsExecute("""SHOW ALL PROPERTIES;""") + } catch (Exception e) { + log.error("Failed to execute SHOW ALL PROPERTIES command", e) + } + + // Test SHOW ALL PROPERTIES with wildWhere condition + try { + checkNereidsExecute("""SHOW ALL PROPERTIES LIKE 'property%';""") + } catch (Exception e) { + log.error("Failed to execute SHOW ALL PROPERTIES command with LIKE clause", e) + } +} --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org For additional commands, e-mail: commits-h...@doris.apache.org