github-actions[bot] commented on code in PR #68299:
URL: https://github.com/apache/doris/pull/68299#discussion_r4059309558
##########
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ShowCatalogCommand.java:
##########
@@ -65,9 +96,104 @@ public ShowResultSet doRun(ConnectContext ctx, StmtExecutor
executor) throws Exc
.showCatalogs(catalogName, pattern, ctx.getCurrentCatalog() !=
null
? ctx.getCurrentCatalog().getName() : null);
+ if (whereClause == null) {
+ return new ShowResultSet(getMetaData(), rows);
+ }
+
+ rows = executeFilter(ctx, rows);
return new ShowResultSet(getMetaData(), rows);
}
+ private List<NamedExpression> toExpressions(List<String> row) {
+ return ImmutableList.of(
+ new Alias(new BigIntLiteral(Long.parseLong(row.get(0))),
"CatalogId"),
+ stringAlias(row.get(1), "CatalogName"),
+ stringAlias(row.get(2), "Type"),
+ stringAlias(row.get(3), "IsCurrent"),
+ stringAlias(row.get(4), "CreateTime"),
+ stringAlias(row.get(5), "LastUpdateTime"),
+ stringAlias(row.get(6), "Comment"),
+ stringAlias(row.get(7), "ErrorMsg"));
+ }
+
+ private List<NamedExpression> nullRow() {
+ return ImmutableList.of(
+ new Alias(new NullLiteral(BigIntType.INSTANCE), "CatalogId"),
+ new Alias(new NullLiteral(StringType.INSTANCE), "CatalogName"),
+ new Alias(new NullLiteral(StringType.INSTANCE), "Type"),
+ new Alias(new NullLiteral(StringType.INSTANCE), "IsCurrent"),
+ new Alias(new NullLiteral(StringType.INSTANCE), "CreateTime"),
+ new Alias(new NullLiteral(StringType.INSTANCE),
"LastUpdateTime"),
+ new Alias(new NullLiteral(StringType.INSTANCE), "Comment"),
+ new Alias(new NullLiteral(StringType.INSTANCE), "ErrorMsg"));
+ }
+
+ private NamedExpression stringAlias(String value, String name) {
+ Expression literal = value == null ||
FeConstants.null_string.equals(value)
+ ? new NullLiteral(StringType.INSTANCE) : new
StringLiteral(value);
+ return new Alias(literal, name);
+ }
+
+ private List<List<String>> executeFilter(ConnectContext outerContext,
List<List<String>> rows) throws Exception {
+ ConnectContext filterContext = buildFilterContext(outerContext);
+ try (AutoCloseConnectContext ignored = new
AutoCloseConnectContext(filterContext)) {
+ // The SHOW predicate must not replace the statement, state, or
query id being audited by the caller.
+ if (rows.isEmpty()) {
+ executeFilterPlan(filterContext, filterPlan(nullRow(), true));
+ return rows;
+ }
+
+ // Multi-row VALUES plans require BE execution. Filtering one row
at a time keeps this path in FE
+ // and preserves the CatalogMgr order instead of applying a
different SQL string collation.
+ List<List<String>> filteredRows = new ArrayList<>(rows.size());
+ for (List<String> row : rows) {
+ filteredRows.addAll(executeFilterPlan(filterContext,
filterPlan(toExpressions(row), false)));
+ }
+ return filteredRows;
+ }
+ }
+
+ private LogicalPlan filterPlan(List<NamedExpression> value, boolean empty)
{
+ LogicalPlan input = new UnboundInlineTable(ImmutableList.of(value));
+ if (empty) {
+ // Keep a typed zero-row relation so invalid WHERE expressions are
still rejected.
+ input = new LogicalLimit<>(0, 0, LimitPhase.ORIGIN, input);
+ }
+ return new UnboundResultSink<>(new
LogicalFilter<>(ImmutableSet.of(whereClause), input));
+ }
+
+ private List<List<String>> executeFilterPlan(ConnectContext filterContext,
LogicalPlan plan) throws Exception {
+ StatementContext statementContext = new StatementContext(
+ filterContext, new OriginStatement(toString(), 0));
+ filterContext.setStatementContext(statementContext);
+ LogicalPlanAdapter adapter = new LogicalPlanAdapter(plan,
statementContext);
+ NereidsPlanner planner = new NereidsPlanner(statementContext);
+ planner.plan(adapter, filterContext.getSessionVariable().toThrift());
+ Optional<ResultSet> resultSet = planner.handleQueryInFe(adapter);
+ if (!resultSet.isPresent()) {
+ throw new IllegalStateException("SHOW CATALOGS filter must be
executable in FE");
+ }
+ return resultSet.get().getResultRows();
+ }
+
+ private ConnectContext buildFilterContext(ConnectContext outerContext) {
+ ConnectContext filterContext = new ConnectContext();
+
filterContext.setSessionVariable(VariableMgr.cloneSessionVariable(outerContext.getSessionVariable()));
Review Comment:
[P1] Preserve the caller's SQL-observable session state in the isolated
evaluation context. This fresh context does not copy user variables, connection
id, last query id, or the original statement clock: after `SET
@wanted='internal'`, `SHOW CATALOGS WHERE CatalogName=@wanted` fails as an
unsupported variable, and `connection_id()`/`last_query_id()` fold against
default clone values. This is separate from the fixed outer-state mutation—the
wrapper restores correctly, but the predicate reads a different session. Please
use a complete purpose-built snapshot (while isolating mutable execution state)
and add session-dependent predicate coverage.
##########
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ShowCatalogCommand.java:
##########
@@ -65,9 +96,104 @@ public ShowResultSet doRun(ConnectContext ctx, StmtExecutor
executor) throws Exc
.showCatalogs(catalogName, pattern, ctx.getCurrentCatalog() !=
null
? ctx.getCurrentCatalog().getName() : null);
+ if (whereClause == null) {
+ return new ShowResultSet(getMetaData(), rows);
+ }
+
+ rows = executeFilter(ctx, rows);
return new ShowResultSet(getMetaData(), rows);
}
+ private List<NamedExpression> toExpressions(List<String> row) {
+ return ImmutableList.of(
+ new Alias(new BigIntLiteral(Long.parseLong(row.get(0))),
"CatalogId"),
+ stringAlias(row.get(1), "CatalogName"),
+ stringAlias(row.get(2), "Type"),
+ stringAlias(row.get(3), "IsCurrent"),
+ stringAlias(row.get(4), "CreateTime"),
+ stringAlias(row.get(5), "LastUpdateTime"),
+ stringAlias(row.get(6), "Comment"),
+ stringAlias(row.get(7), "ErrorMsg"));
+ }
+
+ private List<NamedExpression> nullRow() {
+ return ImmutableList.of(
+ new Alias(new NullLiteral(BigIntType.INSTANCE), "CatalogId"),
+ new Alias(new NullLiteral(StringType.INSTANCE), "CatalogName"),
+ new Alias(new NullLiteral(StringType.INSTANCE), "Type"),
+ new Alias(new NullLiteral(StringType.INSTANCE), "IsCurrent"),
+ new Alias(new NullLiteral(StringType.INSTANCE), "CreateTime"),
+ new Alias(new NullLiteral(StringType.INSTANCE),
"LastUpdateTime"),
+ new Alias(new NullLiteral(StringType.INSTANCE), "Comment"),
+ new Alias(new NullLiteral(StringType.INSTANCE), "ErrorMsg"));
+ }
+
+ private NamedExpression stringAlias(String value, String name) {
+ Expression literal = value == null ||
FeConstants.null_string.equals(value)
+ ? new NullLiteral(StringType.INSTANCE) : new
StringLiteral(value);
+ return new Alias(literal, name);
+ }
+
+ private List<List<String>> executeFilter(ConnectContext outerContext,
List<List<String>> rows) throws Exception {
+ ConnectContext filterContext = buildFilterContext(outerContext);
+ try (AutoCloseConnectContext ignored = new
AutoCloseConnectContext(filterContext)) {
+ // The SHOW predicate must not replace the statement, state, or
query id being audited by the caller.
+ if (rows.isEmpty()) {
+ executeFilterPlan(filterContext, filterPlan(nullRow(), true));
+ return rows;
+ }
+
+ // Multi-row VALUES plans require BE execution. Filtering one row
at a time keeps this path in FE
+ // and preserves the CatalogMgr order instead of applying a
different SQL string collation.
+ List<List<String>> filteredRows = new ArrayList<>(rows.size());
+ for (List<String> row : rows) {
+ filteredRows.addAll(executeFilterPlan(filterContext,
filterPlan(toExpressions(row), false)));
+ }
+ return filteredRows;
+ }
+ }
+
+ private LogicalPlan filterPlan(List<NamedExpression> value, boolean empty)
{
+ LogicalPlan input = new UnboundInlineTable(ImmutableList.of(value));
+ if (empty) {
+ // Keep a typed zero-row relation so invalid WHERE expressions are
still rejected.
+ input = new LogicalLimit<>(0, 0, LimitPhase.ORIGIN, input);
+ }
+ return new UnboundResultSink<>(new
LogicalFilter<>(ImmutableSet.of(whereClause), input));
+ }
+
+ private List<List<String>> executeFilterPlan(ConnectContext filterContext,
LogicalPlan plan) throws Exception {
+ StatementContext statementContext = new StatementContext(
+ filterContext, new OriginStatement(toString(), 0));
+ filterContext.setStatementContext(statementContext);
+ LogicalPlanAdapter adapter = new LogicalPlanAdapter(plan,
statementContext);
+ NereidsPlanner planner = new NereidsPlanner(statementContext);
+ planner.plan(adapter, filterContext.getSessionVariable().toThrift());
+ Optional<ResultSet> resultSet = planner.handleQueryInFe(adapter);
+ if (!resultSet.isPresent()) {
+ throw new IllegalStateException("SHOW CATALOGS filter must be
executable in FE");
+ }
+ return resultSet.get().getResultRows();
+ }
+
+ private ConnectContext buildFilterContext(ConnectContext outerContext) {
+ ConnectContext filterContext = new ConnectContext();
+
filterContext.setSessionVariable(VariableMgr.cloneSessionVariable(outerContext.getSessionVariable()));
+ filterContext.setEnv(Env.getCurrentEnv());
+ filterContext.changeDefaultCatalog(outerContext.getDefaultCatalog());
+ filterContext.setDatabase(outerContext.getDatabase());
Review Comment:
[P1] Preserve the existing dropped-current-catalog behavior when building
this context. `query_p0/show/test_show_catalogs.groovy` explicitly switches to
a catalog, drops that current catalog, and requires plain `SHOW CATALOGS` to
remain valid. In that state line 183 copies the stale name, then `setDatabase`
unconditionally calls `getCurrentCatalog().getDb(db)`, so adding any WHERE
clause now NPEs before filtering. Please copy the nullable namespace without
resolving it against a missing catalog and extend that regression with a WHERE
form.
##########
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ShowCatalogCommand.java:
##########
@@ -65,9 +96,104 @@ public ShowResultSet doRun(ConnectContext ctx, StmtExecutor
executor) throws Exc
.showCatalogs(catalogName, pattern, ctx.getCurrentCatalog() !=
null
? ctx.getCurrentCatalog().getName() : null);
+ if (whereClause == null) {
+ return new ShowResultSet(getMetaData(), rows);
+ }
+
+ rows = executeFilter(ctx, rows);
return new ShowResultSet(getMetaData(), rows);
}
+ private List<NamedExpression> toExpressions(List<String> row) {
+ return ImmutableList.of(
+ new Alias(new BigIntLiteral(Long.parseLong(row.get(0))),
"CatalogId"),
+ stringAlias(row.get(1), "CatalogName"),
+ stringAlias(row.get(2), "Type"),
+ stringAlias(row.get(3), "IsCurrent"),
+ stringAlias(row.get(4), "CreateTime"),
+ stringAlias(row.get(5), "LastUpdateTime"),
+ stringAlias(row.get(6), "Comment"),
+ stringAlias(row.get(7), "ErrorMsg"));
+ }
+
+ private List<NamedExpression> nullRow() {
+ return ImmutableList.of(
+ new Alias(new NullLiteral(BigIntType.INSTANCE), "CatalogId"),
+ new Alias(new NullLiteral(StringType.INSTANCE), "CatalogName"),
+ new Alias(new NullLiteral(StringType.INSTANCE), "Type"),
+ new Alias(new NullLiteral(StringType.INSTANCE), "IsCurrent"),
+ new Alias(new NullLiteral(StringType.INSTANCE), "CreateTime"),
+ new Alias(new NullLiteral(StringType.INSTANCE),
"LastUpdateTime"),
+ new Alias(new NullLiteral(StringType.INSTANCE), "Comment"),
+ new Alias(new NullLiteral(StringType.INSTANCE), "ErrorMsg"));
+ }
+
+ private NamedExpression stringAlias(String value, String name) {
+ Expression literal = value == null ||
FeConstants.null_string.equals(value)
+ ? new NullLiteral(StringType.INSTANCE) : new
StringLiteral(value);
+ return new Alias(literal, name);
+ }
+
+ private List<List<String>> executeFilter(ConnectContext outerContext,
List<List<String>> rows) throws Exception {
+ ConnectContext filterContext = buildFilterContext(outerContext);
+ try (AutoCloseConnectContext ignored = new
AutoCloseConnectContext(filterContext)) {
+ // The SHOW predicate must not replace the statement, state, or
query id being audited by the caller.
+ if (rows.isEmpty()) {
+ executeFilterPlan(filterContext, filterPlan(nullRow(), true));
+ return rows;
+ }
+
+ // Multi-row VALUES plans require BE execution. Filtering one row
at a time keeps this path in FE
+ // and preserves the CatalogMgr order instead of applying a
different SQL string collation.
+ List<List<String>> filteredRows = new ArrayList<>(rows.size());
+ for (List<String> row : rows) {
+ filteredRows.addAll(executeFilterPlan(filterContext,
filterPlan(toExpressions(row), false)));
Review Comment:
[P2] Install the per-row `StatementContext` before constructing these
aliases. At this call site Java evaluates `toExpressions(row)` first, while the
installed fresh `ConnectContext` still has no statement context, so every
`Alias` draws from `StatementScopeIdGenerator`'s shared test-only fallback.
That generator uses an unsynchronized `nextId++`; concurrent SHOWs can
therefore give two columns in one row the same ExprId. Because `SlotReference`
equality is ExprId-only and `generateReplaceMap` uses `putIfAbsent`, a
predicate on `Type` can then be substituted with the earlier `CatalogName`
literal and silently return the wrong row set. Please allocate these IDs from
the installed per-row context and add concurrent uniqueness coverage.
##########
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ShowCatalogCommand.java:
##########
@@ -65,9 +96,104 @@ public ShowResultSet doRun(ConnectContext ctx, StmtExecutor
executor) throws Exc
.showCatalogs(catalogName, pattern, ctx.getCurrentCatalog() !=
null
? ctx.getCurrentCatalog().getName() : null);
+ if (whereClause == null) {
+ return new ShowResultSet(getMetaData(), rows);
+ }
+
+ rows = executeFilter(ctx, rows);
return new ShowResultSet(getMetaData(), rows);
}
+ private List<NamedExpression> toExpressions(List<String> row) {
+ return ImmutableList.of(
+ new Alias(new BigIntLiteral(Long.parseLong(row.get(0))),
"CatalogId"),
+ stringAlias(row.get(1), "CatalogName"),
+ stringAlias(row.get(2), "Type"),
+ stringAlias(row.get(3), "IsCurrent"),
+ stringAlias(row.get(4), "CreateTime"),
+ stringAlias(row.get(5), "LastUpdateTime"),
+ stringAlias(row.get(6), "Comment"),
+ stringAlias(row.get(7), "ErrorMsg"));
+ }
+
+ private List<NamedExpression> nullRow() {
+ return ImmutableList.of(
+ new Alias(new NullLiteral(BigIntType.INSTANCE), "CatalogId"),
+ new Alias(new NullLiteral(StringType.INSTANCE), "CatalogName"),
+ new Alias(new NullLiteral(StringType.INSTANCE), "Type"),
+ new Alias(new NullLiteral(StringType.INSTANCE), "IsCurrent"),
+ new Alias(new NullLiteral(StringType.INSTANCE), "CreateTime"),
+ new Alias(new NullLiteral(StringType.INSTANCE),
"LastUpdateTime"),
+ new Alias(new NullLiteral(StringType.INSTANCE), "Comment"),
+ new Alias(new NullLiteral(StringType.INSTANCE), "ErrorMsg"));
+ }
+
+ private NamedExpression stringAlias(String value, String name) {
+ Expression literal = value == null ||
FeConstants.null_string.equals(value)
+ ? new NullLiteral(StringType.INSTANCE) : new
StringLiteral(value);
+ return new Alias(literal, name);
+ }
+
+ private List<List<String>> executeFilter(ConnectContext outerContext,
List<List<String>> rows) throws Exception {
+ ConnectContext filterContext = buildFilterContext(outerContext);
+ try (AutoCloseConnectContext ignored = new
AutoCloseConnectContext(filterContext)) {
+ // The SHOW predicate must not replace the statement, state, or
query id being audited by the caller.
+ if (rows.isEmpty()) {
+ executeFilterPlan(filterContext, filterPlan(nullRow(), true));
+ return rows;
+ }
+
+ // Multi-row VALUES plans require BE execution. Filtering one row
at a time keeps this path in FE
+ // and preserves the CatalogMgr order instead of applying a
different SQL string collation.
+ List<List<String>> filteredRows = new ArrayList<>(rows.size());
+ for (List<String> row : rows) {
+ filteredRows.addAll(executeFilterPlan(filterContext,
filterPlan(toExpressions(row), false)));
+ }
+ return filteredRows;
+ }
+ }
+
+ private LogicalPlan filterPlan(List<NamedExpression> value, boolean empty)
{
+ LogicalPlan input = new UnboundInlineTable(ImmutableList.of(value));
+ if (empty) {
+ // Keep a typed zero-row relation so invalid WHERE expressions are
still rejected.
+ input = new LogicalLimit<>(0, 0, LimitPhase.ORIGIN, input);
+ }
+ return new UnboundResultSink<>(new
LogicalFilter<>(ImmutableSet.of(whereClause), input));
+ }
+
+ private List<List<String>> executeFilterPlan(ConnectContext filterContext,
LogicalPlan plan) throws Exception {
+ StatementContext statementContext = new StatementContext(
+ filterContext, new OriginStatement(toString(), 0));
+ filterContext.setStatementContext(statementContext);
+ LogicalPlanAdapter adapter = new LogicalPlanAdapter(plan,
statementContext);
+ NereidsPlanner planner = new NereidsPlanner(statementContext);
+ planner.plan(adapter, filterContext.getSessionVariable().toThrift());
+ Optional<ResultSet> resultSet = planner.handleQueryInFe(adapter);
Review Comment:
[P1] Keep these synthetic per-row plans out of the global SQL cache. With
default `enable_sql_cache=true`, every iteration uses this same full SHOW text,
and `handleQueryInFe` caches the first one-row (or empty) result. For two
matching catalogs, the first execution assembles both rows, but the next
identical canonical command can be replaced before parsing by that first
partial `LogicalSqlCache`; it also has no catalog-list or SHOW-grant dependency
to invalidate after metadata/privilege changes. Please disable cache admission
for this internal evaluation and add a connection-level test that executes the
same two-match SHOW twice.
##########
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ShowCatalogCommand.java:
##########
@@ -65,9 +96,104 @@ public ShowResultSet doRun(ConnectContext ctx, StmtExecutor
executor) throws Exc
.showCatalogs(catalogName, pattern, ctx.getCurrentCatalog() !=
null
? ctx.getCurrentCatalog().getName() : null);
+ if (whereClause == null) {
+ return new ShowResultSet(getMetaData(), rows);
+ }
+
+ rows = executeFilter(ctx, rows);
return new ShowResultSet(getMetaData(), rows);
}
+ private List<NamedExpression> toExpressions(List<String> row) {
+ return ImmutableList.of(
+ new Alias(new BigIntLiteral(Long.parseLong(row.get(0))),
"CatalogId"),
+ stringAlias(row.get(1), "CatalogName"),
+ stringAlias(row.get(2), "Type"),
+ stringAlias(row.get(3), "IsCurrent"),
+ stringAlias(row.get(4), "CreateTime"),
+ stringAlias(row.get(5), "LastUpdateTime"),
+ stringAlias(row.get(6), "Comment"),
+ stringAlias(row.get(7), "ErrorMsg"));
+ }
+
+ private List<NamedExpression> nullRow() {
+ return ImmutableList.of(
+ new Alias(new NullLiteral(BigIntType.INSTANCE), "CatalogId"),
+ new Alias(new NullLiteral(StringType.INSTANCE), "CatalogName"),
+ new Alias(new NullLiteral(StringType.INSTANCE), "Type"),
+ new Alias(new NullLiteral(StringType.INSTANCE), "IsCurrent"),
+ new Alias(new NullLiteral(StringType.INSTANCE), "CreateTime"),
+ new Alias(new NullLiteral(StringType.INSTANCE),
"LastUpdateTime"),
+ new Alias(new NullLiteral(StringType.INSTANCE), "Comment"),
+ new Alias(new NullLiteral(StringType.INSTANCE), "ErrorMsg"));
+ }
+
+ private NamedExpression stringAlias(String value, String name) {
+ Expression literal = value == null ||
FeConstants.null_string.equals(value)
+ ? new NullLiteral(StringType.INSTANCE) : new
StringLiteral(value);
+ return new Alias(literal, name);
+ }
+
+ private List<List<String>> executeFilter(ConnectContext outerContext,
List<List<String>> rows) throws Exception {
+ ConnectContext filterContext = buildFilterContext(outerContext);
+ try (AutoCloseConnectContext ignored = new
AutoCloseConnectContext(filterContext)) {
+ // The SHOW predicate must not replace the statement, state, or
query id being audited by the caller.
+ if (rows.isEmpty()) {
+ executeFilterPlan(filterContext, filterPlan(nullRow(), true));
+ return rows;
+ }
+
+ // Multi-row VALUES plans require BE execution. Filtering one row
at a time keeps this path in FE
+ // and preserves the CatalogMgr order instead of applying a
different SQL string collation.
+ List<List<String>> filteredRows = new ArrayList<>(rows.size());
+ for (List<String> row : rows) {
+ filteredRows.addAll(executeFilterPlan(filterContext,
filterPlan(toExpressions(row), false)));
+ }
+ return filteredRows;
+ }
+ }
+
+ private LogicalPlan filterPlan(List<NamedExpression> value, boolean empty)
{
+ LogicalPlan input = new UnboundInlineTable(ImmutableList.of(value));
+ if (empty) {
+ // Keep a typed zero-row relation so invalid WHERE expressions are
still rejected.
+ input = new LogicalLimit<>(0, 0, LimitPhase.ORIGIN, input);
+ }
+ return new UnboundResultSink<>(new
LogicalFilter<>(ImmutableSet.of(whereClause), input));
+ }
+
+ private List<List<String>> executeFilterPlan(ConnectContext filterContext,
LogicalPlan plan) throws Exception {
+ StatementContext statementContext = new StatementContext(
+ filterContext, new OriginStatement(toString(), 0));
+ filterContext.setStatementContext(statementContext);
+ LogicalPlanAdapter adapter = new LogicalPlanAdapter(plan,
statementContext);
+ NereidsPlanner planner = new NereidsPlanner(statementContext);
+ planner.plan(adapter, filterContext.getSessionVariable().toThrift());
+ Optional<ResultSet> resultSet = planner.handleQueryInFe(adapter);
+ if (!resultSet.isPresent()) {
Review Comment:
[P1] Do not require every valid WHERE predicate to fold entirely in FE. For
example, `SHOW CATALOGS WHERE hex(CatalogName) = '696E7465726E616C'` is
accepted, but `hex` has no FE executable registration, so the reduced tree
still contains `PhysicalFilter`. That node is not `ComputeResultSet`;
`handleQueryInFe` returns empty and this path throws the internal invariant
instead of evaluating the valid predicate. Please execute the full accepted
expression language (or deliberately validate a narrower language with a
user-facing analysis error) and cover a non-FE-foldable scalar.
##########
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ShowCatalogCommand.java:
##########
@@ -65,9 +96,104 @@ public ShowResultSet doRun(ConnectContext ctx, StmtExecutor
executor) throws Exc
.showCatalogs(catalogName, pattern, ctx.getCurrentCatalog() !=
null
? ctx.getCurrentCatalog().getName() : null);
+ if (whereClause == null) {
+ return new ShowResultSet(getMetaData(), rows);
+ }
+
+ rows = executeFilter(ctx, rows);
return new ShowResultSet(getMetaData(), rows);
}
+ private List<NamedExpression> toExpressions(List<String> row) {
+ return ImmutableList.of(
+ new Alias(new BigIntLiteral(Long.parseLong(row.get(0))),
"CatalogId"),
+ stringAlias(row.get(1), "CatalogName"),
+ stringAlias(row.get(2), "Type"),
+ stringAlias(row.get(3), "IsCurrent"),
+ stringAlias(row.get(4), "CreateTime"),
+ stringAlias(row.get(5), "LastUpdateTime"),
+ stringAlias(row.get(6), "Comment"),
+ stringAlias(row.get(7), "ErrorMsg"));
+ }
+
+ private List<NamedExpression> nullRow() {
+ return ImmutableList.of(
+ new Alias(new NullLiteral(BigIntType.INSTANCE), "CatalogId"),
+ new Alias(new NullLiteral(StringType.INSTANCE), "CatalogName"),
+ new Alias(new NullLiteral(StringType.INSTANCE), "Type"),
+ new Alias(new NullLiteral(StringType.INSTANCE), "IsCurrent"),
+ new Alias(new NullLiteral(StringType.INSTANCE), "CreateTime"),
+ new Alias(new NullLiteral(StringType.INSTANCE),
"LastUpdateTime"),
+ new Alias(new NullLiteral(StringType.INSTANCE), "Comment"),
+ new Alias(new NullLiteral(StringType.INSTANCE), "ErrorMsg"));
+ }
+
+ private NamedExpression stringAlias(String value, String name) {
+ Expression literal = value == null ||
FeConstants.null_string.equals(value)
+ ? new NullLiteral(StringType.INSTANCE) : new
StringLiteral(value);
+ return new Alias(literal, name);
+ }
+
+ private List<List<String>> executeFilter(ConnectContext outerContext,
List<List<String>> rows) throws Exception {
+ ConnectContext filterContext = buildFilterContext(outerContext);
+ try (AutoCloseConnectContext ignored = new
AutoCloseConnectContext(filterContext)) {
+ // The SHOW predicate must not replace the statement, state, or
query id being audited by the caller.
+ if (rows.isEmpty()) {
+ executeFilterPlan(filterContext, filterPlan(nullRow(), true));
+ return rows;
+ }
+
+ // Multi-row VALUES plans require BE execution. Filtering one row
at a time keeps this path in FE
+ // and preserves the CatalogMgr order instead of applying a
different SQL string collation.
+ List<List<String>> filteredRows = new ArrayList<>(rows.size());
+ for (List<String> row : rows) {
+ filteredRows.addAll(executeFilterPlan(filterContext,
filterPlan(toExpressions(row), false)));
+ }
+ return filteredRows;
+ }
+ }
+
+ private LogicalPlan filterPlan(List<NamedExpression> value, boolean empty)
{
+ LogicalPlan input = new UnboundInlineTable(ImmutableList.of(value));
+ if (empty) {
+ // Keep a typed zero-row relation so invalid WHERE expressions are
still rejected.
+ input = new LogicalLimit<>(0, 0, LimitPhase.ORIGIN, input);
+ }
+ return new UnboundResultSink<>(new
LogicalFilter<>(ImmutableSet.of(whereClause), input));
+ }
+
+ private List<List<String>> executeFilterPlan(ConnectContext filterContext,
LogicalPlan plan) throws Exception {
+ StatementContext statementContext = new StatementContext(
Review Comment:
[P1] Preserve bound server-prepared parameters in this inner statement
context. COM_STMT_EXECUTE has already placed the literal for `SHOW CATALOGS
WHERE CatalogName = ?` in the caller's `StatementContext`, but this replacement
context starts with an empty `idToPlaceholderRealExpr`. Since it is no longer
in prepare stage, `ExpressionAnalyzer.visitPlaceholder` receives no real
expression and the parameterized SHOW fails during analysis instead of
filtering. Please carry the execution's placeholder bindings into this isolated
context (or bind the retained predicate before replacing it) and add a
server-prepared regression with a bound catalog name.
##########
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ShowCatalogCommand.java:
##########
@@ -65,9 +96,104 @@ public ShowResultSet doRun(ConnectContext ctx, StmtExecutor
executor) throws Exc
.showCatalogs(catalogName, pattern, ctx.getCurrentCatalog() !=
null
? ctx.getCurrentCatalog().getName() : null);
+ if (whereClause == null) {
+ return new ShowResultSet(getMetaData(), rows);
+ }
+
+ rows = executeFilter(ctx, rows);
return new ShowResultSet(getMetaData(), rows);
}
+ private List<NamedExpression> toExpressions(List<String> row) {
+ return ImmutableList.of(
+ new Alias(new BigIntLiteral(Long.parseLong(row.get(0))),
"CatalogId"),
+ stringAlias(row.get(1), "CatalogName"),
+ stringAlias(row.get(2), "Type"),
+ stringAlias(row.get(3), "IsCurrent"),
+ stringAlias(row.get(4), "CreateTime"),
+ stringAlias(row.get(5), "LastUpdateTime"),
+ stringAlias(row.get(6), "Comment"),
+ stringAlias(row.get(7), "ErrorMsg"));
+ }
+
+ private List<NamedExpression> nullRow() {
+ return ImmutableList.of(
+ new Alias(new NullLiteral(BigIntType.INSTANCE), "CatalogId"),
+ new Alias(new NullLiteral(StringType.INSTANCE), "CatalogName"),
+ new Alias(new NullLiteral(StringType.INSTANCE), "Type"),
+ new Alias(new NullLiteral(StringType.INSTANCE), "IsCurrent"),
+ new Alias(new NullLiteral(StringType.INSTANCE), "CreateTime"),
+ new Alias(new NullLiteral(StringType.INSTANCE),
"LastUpdateTime"),
+ new Alias(new NullLiteral(StringType.INSTANCE), "Comment"),
+ new Alias(new NullLiteral(StringType.INSTANCE), "ErrorMsg"));
+ }
+
+ private NamedExpression stringAlias(String value, String name) {
+ Expression literal = value == null ||
FeConstants.null_string.equals(value)
+ ? new NullLiteral(StringType.INSTANCE) : new
StringLiteral(value);
+ return new Alias(literal, name);
+ }
+
+ private List<List<String>> executeFilter(ConnectContext outerContext,
List<List<String>> rows) throws Exception {
+ ConnectContext filterContext = buildFilterContext(outerContext);
+ try (AutoCloseConnectContext ignored = new
AutoCloseConnectContext(filterContext)) {
+ // The SHOW predicate must not replace the statement, state, or
query id being audited by the caller.
+ if (rows.isEmpty()) {
+ executeFilterPlan(filterContext, filterPlan(nullRow(), true));
+ return rows;
+ }
+
+ // Multi-row VALUES plans require BE execution. Filtering one row
at a time keeps this path in FE
+ // and preserves the CatalogMgr order instead of applying a
different SQL string collation.
+ List<List<String>> filteredRows = new ArrayList<>(rows.size());
+ for (List<String> row : rows) {
Review Comment:
[P2] Avoid running a complete Nereids planning/translation cycle once per
visible catalog. Each iteration creates a fresh planner and calls `plan`, which
reaches analysis, rewrites, memo optimization, post-processing, fragment
splitting, and physical translation; `CatalogMgr.showCatalogs` places no bound
on the number of external catalogs. This makes one metadata filter consume
planner CPU and allocations proportional to catalog count. Please bind/plan
once for the row set (carrying an ordinal if needed to retain manager order),
or compile the predicate once for repeated row evaluation.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]