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 2dd10b990ef6cd..d9697e0fad8eec 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 @@ -40,6 +40,7 @@ statement | DROP (PROCEDURE | PROC) (IF EXISTS)? name=multipartIdentifier #dropProcedure | SHOW PROCEDURE STATUS (LIKE pattern=valueExpression | whereClause)? #showProcedureStatus | SHOW CREATE PROCEDURE name=multipartIdentifier #showCreateProcedure + | ADMIN? SHOW type=(FRONTEND | BACKEND) CONFIG (LIKE pattern=valueExpression)? (FROM backendId=INTEGER_VALUE)? #showConfig ; statementBase diff --git a/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/PLParser.g4 b/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/PLParser.g4 index e967da2f95502c..7051cac0ca0008 100644 --- a/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/PLParser.g4 +++ b/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/PLParser.g4 @@ -101,6 +101,7 @@ stmt : | drop_procedure_stmt | show_procedure_stmt | show_create_procedure_stmt + | show_config_stmt | exec_stmt | exit_stmt | fetch_stmt @@ -343,6 +344,10 @@ show_create_procedure_stmt: SHOW CREATE PROCEDURE name=multipartIdentifier ; +show_config_stmt: + SHOW type=(FRONTEND | BACKEND) CONFIG (LIKE pattern=valueExpression)? (FROM backendId=INTEGER_VALUE)? + ; + create_routine_params : LEFT_PAREN RIGHT_PAREN | LEFT_PAREN create_routine_param_item (COMMA create_routine_param_item)* RIGHT_PAREN diff --git a/fe/fe-core/src/main/cup/sql_parser.cup b/fe/fe-core/src/main/cup/sql_parser.cup index 5f0d6da3628039..0cd8dcef5a507e 100644 --- a/fe/fe-core/src/main/cup/sql_parser.cup +++ b/fe/fe-core/src/main/cup/sql_parser.cup @@ -60,6 +60,7 @@ import org.apache.doris.load.loadv2.LoadTask; import org.apache.doris.policy.PolicyTypeEnum; import org.apache.doris.resource.workloadschedpolicy.WorkloadConditionMeta; import org.apache.doris.resource.workloadschedpolicy.WorkloadActionMeta; +import org.apache.doris.system.NodeType; import com.google.common.collect.Lists; import com.google.common.collect.Maps; @@ -4711,7 +4712,15 @@ show_param ::= :} | KW_FRONTEND KW_CONFIG opt_wild_where {: - RESULT = new ShowConfigStmt(AdminSetConfigStmt.ConfigType.FRONTEND, parser.wild); + RESULT = new ShowConfigStmt(NodeType.FRONTEND, parser.wild); + :} + | KW_BACKEND KW_CONFIG opt_wild_where + {: + RESULT = new ShowConfigStmt(NodeType.BACKEND, parser.wild); + :} + | KW_BACKEND KW_CONFIG opt_wild_where KW_FROM INTEGER_LITERAL:backendId + {: + RESULT = new ShowConfigStmt(NodeType.BACKEND, parser.wild, backendId); :} | KW_TABLET KW_STORAGE KW_FORMAT {: @@ -7850,20 +7859,28 @@ admin_stmt ::= :} | KW_ADMIN KW_SET KW_FRONTEND KW_CONFIG opt_key_value_map:configs {: - RESULT = new AdminSetConfigStmt(AdminSetConfigStmt.ConfigType.FRONTEND, configs, false); + RESULT = new AdminSetConfigStmt(NodeType.FRONTEND, configs, false); :} | KW_ADMIN KW_SET KW_ALL KW_FRONTENDS KW_CONFIG opt_key_value_map:configs {: - RESULT = new AdminSetConfigStmt(AdminSetConfigStmt.ConfigType.FRONTEND, configs, true); + RESULT = new AdminSetConfigStmt(NodeType.FRONTEND, configs, true); :} | KW_ADMIN KW_SET KW_FRONTEND KW_CONFIG opt_key_value_map:configs KW_ALL {: - RESULT = new AdminSetConfigStmt(AdminSetConfigStmt.ConfigType.FRONTEND, configs, true); + RESULT = new AdminSetConfigStmt(NodeType.FRONTEND, configs, true); :} // deprecated | KW_ADMIN KW_SHOW KW_FRONTEND KW_CONFIG opt_wild_where {: - RESULT = new ShowConfigStmt(AdminSetConfigStmt.ConfigType.FRONTEND, parser.wild); + RESULT = new ShowConfigStmt(NodeType.FRONTEND, parser.wild); + :} + | KW_ADMIN KW_SHOW KW_BACKEND KW_CONFIG opt_wild_where + {: + RESULT = new ShowConfigStmt(NodeType.BACKEND, parser.wild); + :} + | KW_ADMIN KW_SHOW KW_BACKEND KW_CONFIG opt_wild_where KW_FROM INTEGER_LITERAL:backendId + {: + RESULT = new ShowConfigStmt(NodeType.BACKEND, parser.wild, backendId); :} | KW_ADMIN KW_CHECK KW_TABLET LPAREN integer_list:tabletIds RPAREN opt_properties:properties {: diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/AdminSetConfigStmt.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/AdminSetConfigStmt.java index 1d2e22ee878b13..0de5ee0807d0ee 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/AdminSetConfigStmt.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/AdminSetConfigStmt.java @@ -26,6 +26,7 @@ import org.apache.doris.mysql.privilege.PrivPredicate; import org.apache.doris.qe.ConnectContext; import org.apache.doris.qe.OriginStatement; +import org.apache.doris.system.NodeType; import com.google.common.collect.Maps; @@ -34,18 +35,13 @@ // admin set frontend config ("key" = "value"); public class AdminSetConfigStmt extends DdlStmt { - public enum ConfigType { - FRONTEND, - BACKEND - } - private boolean applyToAll; - private ConfigType type; + private NodeType type; private Map configs; private RedirectStatus redirectStatus = RedirectStatus.NO_FORWARD; - public AdminSetConfigStmt(ConfigType type, Map configs, boolean applyToAll) { + public AdminSetConfigStmt(NodeType type, Map configs, boolean applyToAll) { this.type = type; this.configs = configs; if (this.configs == null) { @@ -62,7 +58,7 @@ public AdminSetConfigStmt(ConfigType type, Map configs, boolean } } - public ConfigType getType() { + public NodeType getType() { return type; } @@ -86,7 +82,7 @@ public void analyze(Analyzer analyzer) throws AnalysisException, UserException { ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ACCESS_DENIED_ERROR, "ADMIN"); } - if (type != ConfigType.FRONTEND) { + if (type != NodeType.FRONTEND) { throw new AnalysisException("Only support setting Frontend configs now"); } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowConfigStmt.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowConfigStmt.java index 62b91a32420efe..b32c91d4a6662e 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowConfigStmt.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowConfigStmt.java @@ -17,35 +17,48 @@ package org.apache.doris.analysis; -import org.apache.doris.analysis.AdminSetConfigStmt.ConfigType; 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.ErrorCode; import org.apache.doris.common.ErrorReport; import org.apache.doris.common.UserException; import org.apache.doris.mysql.privilege.PrivPredicate; import org.apache.doris.qe.ConnectContext; import org.apache.doris.qe.ShowResultSetMetaData; +import org.apache.doris.system.NodeType; import com.google.common.collect.ImmutableList; // show frontend config; -public class ShowConfigStmt extends ShowStmt { - public static final ImmutableList TITLE_NAMES = new ImmutableList.Builder().add("Key").add( +public class ShowConfigStmt extends ShowStmt implements NotFallbackInParser { + public static final ImmutableList FE_TITLE_NAMES = new ImmutableList.Builder().add("Key").add( "Value").add("Type").add("IsMutable").add("MasterOnly").add("Comment").build(); - private ConfigType type; + public static final ImmutableList BE_TITLE_NAMES = new ImmutableList.Builder().add("BackendId") + .add("Host").add("Key").add("Value").add("Type").add("IsMutable").build(); + + private NodeType type; private String pattern; - public ShowConfigStmt(ConfigType type, String pattern) { + private long backendId; + + private boolean isShowSingleBackend; + + public ShowConfigStmt(NodeType type, String pattern) { + this.type = type; + this.pattern = pattern; + } + + public ShowConfigStmt(NodeType type, String pattern, long backendId) { this.type = type; this.pattern = pattern; + this.backendId = backendId; + this.isShowSingleBackend = true; } - public ConfigType getType() { + public NodeType getType() { return type; } @@ -53,31 +66,45 @@ public String getPattern() { return pattern; } + public long getBackendId() { + return backendId; + } + + public boolean isShowSingleBackend() { + return isShowSingleBackend; + } + @Override - public void analyze(Analyzer analyzer) throws AnalysisException, UserException { + public void analyze(Analyzer analyzer) throws UserException { super.analyze(analyzer); // check auth if (!Env.getCurrentEnv().getAccessManager().checkGlobalPriv(ConnectContext.get(), PrivPredicate.ADMIN)) { ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ACCESS_DENIED_ERROR, "ADMIN"); } - - if (type != ConfigType.FRONTEND) { - throw new AnalysisException("Only support setting Frontend configs now"); - } } @Override public ShowResultSetMetaData getMetaData() { ShowResultSetMetaData.Builder builder = ShowResultSetMetaData.builder(); - for (String title : TITLE_NAMES) { - builder.addColumn(new Column(title, ScalarType.createVarchar(30))); + if (type == NodeType.FRONTEND) { + for (String title : FE_TITLE_NAMES) { + builder.addColumn(new Column(title, ScalarType.createVarchar(30))); + } + } else { + for (String title : BE_TITLE_NAMES) { + builder.addColumn(new Column(title, ScalarType.createVarchar(30))); + } } return builder.build(); } @Override public RedirectStatus getRedirectStatus() { + // no need forward to master for backend config + if (type == NodeType.BACKEND) { + return RedirectStatus.NO_FORWARD; + } if (ConnectContext.get().getSessionVariable().getForwardToMaster()) { return RedirectStatus.FORWARD_NO_SYNC; } else { 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 d1890a0333ba13..0f849b27039f62 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 @@ -172,6 +172,7 @@ import org.apache.doris.nereids.DorisParser.SelectColumnClauseContext; import org.apache.doris.nereids.DorisParser.SelectHintContext; import org.apache.doris.nereids.DorisParser.SetOperationContext; +import org.apache.doris.nereids.DorisParser.ShowConfigContext; import org.apache.doris.nereids.DorisParser.ShowConstraintContext; import org.apache.doris.nereids.DorisParser.ShowCreateMTMVContext; import org.apache.doris.nereids.DorisParser.ShowCreateProcedureContext; @@ -390,6 +391,7 @@ import org.apache.doris.nereids.trees.plans.commands.PauseMTMVCommand; import org.apache.doris.nereids.trees.plans.commands.RefreshMTMVCommand; import org.apache.doris.nereids.trees.plans.commands.ResumeMTMVCommand; +import org.apache.doris.nereids.trees.plans.commands.ShowConfigCommand; import org.apache.doris.nereids.trees.plans.commands.ShowConstraintsCommand; import org.apache.doris.nereids.trees.plans.commands.ShowCreateMTMVCommand; import org.apache.doris.nereids.trees.plans.commands.ShowCreateProcedureCommand; @@ -472,6 +474,7 @@ import org.apache.doris.policy.PolicyTypeEnum; import org.apache.doris.qe.ConnectContext; import org.apache.doris.qe.SqlModeHelper; +import org.apache.doris.system.NodeType; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; @@ -3683,4 +3686,24 @@ public LogicalPlan visitCreateTableLike(CreateTableLikeContext ctx) { rollupNames, withAllRollUp); return new CreateTableLikeCommand(info); } + + @Override + public LogicalPlan visitShowConfig(ShowConfigContext ctx) { + ShowConfigCommand command; + if (ctx.type.getText().equalsIgnoreCase(NodeType.FRONTEND.name())) { + command = new ShowConfigCommand(NodeType.FRONTEND); + } else { + command = new ShowConfigCommand(NodeType.BACKEND); + } + if (ctx.LIKE() != null && ctx.pattern != null) { + Like like = new Like(new UnboundSlot("ProcedureName"), getExpression(ctx.pattern)); + String pattern = ((Literal) like.child(1)).getStringValue(); + command.setPattern(pattern); + } + if (ctx.FROM() != null && ctx.backendId != null) { + long backendId = Long.parseLong(ctx.backendId.getText()); + command.setBackendId(backendId); + } + return command; + } } 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 e4f0f4c102e54e..9f451732bdc886 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 @@ -163,5 +163,6 @@ public enum PlanType { CREATE_TABLE_LIKE_COMMAND, PREPARED_COMMAND, - EXECUTE_COMMAND + EXECUTE_COMMAND, + SHOW_CONFIG_COMMAND } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ShowConfigCommand.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ShowConfigCommand.java new file mode 100644 index 00000000000000..b139d0a5772639 --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ShowConfigCommand.java @@ -0,0 +1,171 @@ +// 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.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.ConfigBase; +import org.apache.doris.common.PatternMatcher; +import org.apache.doris.common.PatternMatcherWrapper; +import org.apache.doris.nereids.trees.plans.PlanType; +import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor; +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 org.apache.doris.system.Backend; +import org.apache.doris.system.NodeType; +import org.apache.doris.system.SystemInfoService; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; +import org.json.JSONArray; + +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.URL; +import java.net.URLConnection; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; + +/** + * show frontend/backend config +*/ +public class ShowConfigCommand extends Command implements NoForward { + + public static final ImmutableList FE_TITLE_NAMES = new ImmutableList.Builder().add("Key").add( + "Value").add("Type").add("IsMutable").add("MasterOnly").add("Comment").build(); + public static final ImmutableList BE_TITLE_NAMES = new ImmutableList.Builder().add("BackendId") + .add("Host").add("Key").add("Value").add("Type").add("IsMutable").build(); + + private final NodeType nodeType; + private String pattern; + private long backendId; + private boolean isShowSingleBackend; + + public ShowConfigCommand(NodeType nodeType) { + super(PlanType.SHOW_CONFIG_COMMAND); + this.nodeType = nodeType; + } + + public void setPattern(String pattern) { + this.pattern = pattern; + } + + public void setBackendId(long backendId) { + this.backendId = backendId; + this.isShowSingleBackend = true; + } + + private ShowResultSetMetaData getMetaData(ImmutableList metaNames) { + ShowResultSetMetaData.Builder builder = ShowResultSetMetaData.builder(); + for (String title : metaNames) { + builder.addColumn(new Column(title, ScalarType.createStringType())); + } + return builder.build(); + } + + private ShowResultSet handShowFrontendConfig() throws AnalysisException { + List> results; + PatternMatcher matcher = null; + if (pattern != null) { + matcher = PatternMatcherWrapper.createMysqlPattern(pattern, CaseSensibility.CONFIG.getCaseSensibility()); + } + results = ConfigBase.getConfigInfo(matcher); + // Sort all configs by config key. + results.sort(Comparator.comparing(o -> o.get(0))); + return new ShowResultSet(getMetaData(FE_TITLE_NAMES), results); + } + + private ShowResultSet handShowBackendConfig() throws AnalysisException { + List> results = new ArrayList<>(); + List backendIds; + final SystemInfoService systemInfoService = Env.getCurrentSystemInfo(); + if (isShowSingleBackend) { + if (systemInfoService.getBackend(backendId) == null) { + throw new AnalysisException("Backend " + backendId + " not exists"); + } + Backend backend = systemInfoService.getBackend(backendId); + if (!backend.isAlive()) { + throw new AnalysisException("Backend " + backendId + " is not alive"); + } + backendIds = Lists.newArrayList(backendId); + } else { + backendIds = systemInfoService.getAllBackendIds(true); + } + + PatternMatcher matcher = null; + if (pattern != null) { + matcher = PatternMatcherWrapper.createMysqlPattern(pattern, CaseSensibility.CONFIG.getCaseSensibility()); + } + for (long beId : backendIds) { + Backend backend = systemInfoService.getBackend(beId); + String host = backend.getHost(); + int httpPort = backend.getHttpPort(); + String urlString = String.format("http://%s:%d/api/show_config", host, httpPort); + try { + URL url = new URL(urlString); + URLConnection urlConnection = url.openConnection(); + InputStream inputStream = urlConnection.getInputStream(); + BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); + while (reader.ready()) { + // line's format like [["k1","v1"], ["k2","v2"]] + String line = reader.readLine(); + JSONArray outer = new JSONArray(line); + for (int i = 0; i < outer.length(); ++i) { + // [key, type, value, isMutable] + JSONArray inner = outer.getJSONArray(i); + if (matcher == null || matcher.match(inner.getString(0))) { + List rows = Lists.newArrayList(); + rows.add(String.valueOf(beId)); + rows.add(host); + rows.add(inner.getString(0)); // key + rows.add(inner.getString(2)); // value + rows.add(inner.getString(1)); // Type + rows.add(inner.getString(3)); // isMutable + results.add(rows); + } + } + } + } catch (Exception e) { + throw new AnalysisException( + String.format("Can’t get backend config, backendId: %d, host: %s", beId, host)); + } + } + return new ShowResultSet(getMetaData(BE_TITLE_NAMES), results); + } + + @Override + public void run(ConnectContext ctx, StmtExecutor executor) throws Exception { + if (nodeType == NodeType.FRONTEND) { + executor.sendResultSet(handShowFrontendConfig()); + } else { + executor.sendResultSet(handShowBackendConfig()); + } + } + + @Override + public R accept(PlanVisitor visitor, C context) { + return visitor.visitShowConfigCommand(this, context); + } +} 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 541dbd498495a2..a180505d42e47b 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 @@ -41,6 +41,7 @@ import org.apache.doris.nereids.trees.plans.commands.PauseMTMVCommand; import org.apache.doris.nereids.trees.plans.commands.RefreshMTMVCommand; import org.apache.doris.nereids.trees.plans.commands.ResumeMTMVCommand; +import org.apache.doris.nereids.trees.plans.commands.ShowConfigCommand; import org.apache.doris.nereids.trees.plans.commands.ShowConstraintsCommand; import org.apache.doris.nereids.trees.plans.commands.ShowCreateMTMVCommand; import org.apache.doris.nereids.trees.plans.commands.ShowCreateProcedureCommand; @@ -186,4 +187,8 @@ default R visitUnsupportedCommand(UnsupportedCommand unsupportedCommand, C conte default R visitCreateTableLikeCommand(CreateTableLikeCommand createTableLikeCommand, C context) { return visitCommand(createTableLikeCommand, context); } + + default R visitShowConfigCommand(ShowConfigCommand showConfigCommand, C context) { + return visitCommand(showConfigCommand, context); + } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/qe/ShowExecutor.java b/fe/fe-core/src/main/java/org/apache/doris/qe/ShowExecutor.java index 56a88bbd6505c7..f5dd6e441a950a 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/qe/ShowExecutor.java +++ b/fe/fe-core/src/main/java/org/apache/doris/qe/ShowExecutor.java @@ -232,6 +232,7 @@ import org.apache.doris.statistics.util.StatisticsUtil; import org.apache.doris.system.Backend; import org.apache.doris.system.Diagnoser; +import org.apache.doris.system.NodeType; import org.apache.doris.system.SystemInfoService; import org.apache.doris.task.AgentBatchTask; import org.apache.doris.task.AgentClient; @@ -258,6 +259,7 @@ import org.apache.commons.lang3.StringUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.json.JSONArray; import java.io.BufferedReader; import java.io.InputStream; @@ -2389,17 +2391,80 @@ private void handleAdminShowTabletDistribution() throws AnalysisException { private void handleAdminShowConfig() throws AnalysisException { ShowConfigStmt showStmt = (ShowConfigStmt) stmt; - List> results; + if (showStmt.getType() == NodeType.FRONTEND) { + List> results; + PatternMatcher matcher = null; + if (showStmt.getPattern() != null) { + matcher = PatternMatcherWrapper.createMysqlPattern(showStmt.getPattern(), + CaseSensibility.CONFIG.getCaseSensibility()); + } + results = ConfigBase.getConfigInfo(matcher); + // Sort all configs by config key. + results.sort(Comparator.comparing(o -> o.get(0))); + resultSet = new ShowResultSet(showStmt.getMetaData(), results); + } else { + handShowBackendConfig(showStmt); + } + } + + private void handShowBackendConfig(ShowConfigStmt stmt) throws AnalysisException { + List> results = new ArrayList<>(); + List backendIds; + final SystemInfoService systemInfoService = Env.getCurrentSystemInfo(); + if (stmt.isShowSingleBackend()) { + long backendId = stmt.getBackendId(); + if (systemInfoService.getBackend(backendId) == null) { + throw new AnalysisException("Backend " + backendId + " not exists"); + } + Backend backend = systemInfoService.getBackend(backendId); + if (!backend.isAlive()) { + throw new AnalysisException("Backend " + backendId + " is not alive"); + } + backendIds = Lists.newArrayList(backendId); + } else { + backendIds = systemInfoService.getAllBackendIds(true); + } PatternMatcher matcher = null; - if (showStmt.getPattern() != null) { - matcher = PatternMatcherWrapper.createMysqlPattern(showStmt.getPattern(), + if (stmt.getPattern() != null) { + matcher = PatternMatcherWrapper.createMysqlPattern(stmt.getPattern(), CaseSensibility.CONFIG.getCaseSensibility()); } - results = ConfigBase.getConfigInfo(matcher); - // Sort all configs by config key. - results.sort(Comparator.comparing(o -> o.get(0))); - resultSet = new ShowResultSet(showStmt.getMetaData(), results); + for (long beId : backendIds) { + Backend backend = systemInfoService.getBackend(beId); + String host = backend.getHost(); + int httpPort = backend.getHttpPort(); + String urlString = String.format("http://%s:%d/api/show_config", host, httpPort); + try { + URL url = new URL(urlString); + URLConnection urlConnection = url.openConnection(); + InputStream inputStream = urlConnection.getInputStream(); + BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); + while (reader.ready()) { + // line's format like [["k1","v1"], ["k2","v2"]] + String line = reader.readLine(); + JSONArray outer = new JSONArray(line); + for (int i = 0; i < outer.length(); ++i) { + // [key, type, value, isMutable] + JSONArray inner = outer.getJSONArray(i); + if (matcher == null || matcher.match(inner.getString(0))) { + List rows = Lists.newArrayList(); + rows.add(String.valueOf(beId)); + rows.add(host); + rows.add(inner.getString(0)); // key + rows.add(inner.getString(2)); // value + rows.add(inner.getString(1)); // Type + rows.add(inner.getString(3)); // isMutable + results.add(rows); + } + } + } + } catch (Exception e) { + throw new AnalysisException( + String.format("Can’t get backend config, backendId: %d, host: %s", beId, host)); + } + } + resultSet = new ShowResultSet(stmt.getMetaData(), results); } private void handleShowSmallFiles() throws AnalysisException { diff --git a/fe/fe-core/src/main/java/org/apache/doris/system/NodeType.java b/fe/fe-core/src/main/java/org/apache/doris/system/NodeType.java new file mode 100644 index 00000000000000..f101fea3141850 --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/system/NodeType.java @@ -0,0 +1,23 @@ +// 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.system; + +public enum NodeType { + FRONTEND, + BACKEND +} diff --git a/regression-test/suites/show_p0/test_show_backend_config.groovy b/regression-test/suites/show_p0/test_show_backend_config.groovy new file mode 100644 index 00000000000000..b2e0bea26c1fe6 --- /dev/null +++ b/regression-test/suites/show_p0/test_show_backend_config.groovy @@ -0,0 +1,57 @@ +// 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_backend_config") { + + def userName = "test_show_backends_config_user" + def passwd = "12345" + + sql """drop user if exists ${userName}""" + sql """create user ${userName} identified by '${passwd}'""" + sql """grant ADMIN_PRIV on *.*.* to ${userName}""" + + def checkResult = {results, beId, bePort -> + for (def row in results) { + if (row.BackendId == beId && row.Key == "be_port") { + assertEquals(bePort, row.Value); + break; + } + } + } + + connect(user = userName, password = passwd, url = context.config.jdbcUrl) { + def backends = sql_return_maparray """ show backends """ + def beId = backends[0].BackendId + def bePort = backends[0].BePort + + def result1 = sql_return_maparray """show backend config""" + checkResult result1, beId, bePort + + // test with pattern + def result2 = sql_return_maparray """show backend config like 'be_port' """ + checkResult result2, beId, bePort + + // test from beId + def result3 = sql_return_maparray """show backend config from ${beId} """ + checkResult result3, beId, bePort + + // test from beId with pattern + def result4 = sql_return_maparray """show backend config like 'be_port' from ${beId}""" + checkResult result4, beId, bePort + } +} +