JackieTien97 commented on code in PR #12780:
URL: https://github.com/apache/iotdb/pull/12780#discussion_r1650574072
##########
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/QueryPlanner.java:
##########
@@ -240,34 +236,17 @@ private PlanBuilder planFrom(QuerySpecification node) {
}
}
- private PlanBuilder filter(PlanBuilder planBuilder, Expression predicate) {
+ private PlanBuilder filter(PlanBuilder subPlan, Expression predicate) {
if (predicate == null) {
- return planBuilder;
+ return subPlan;
}
- Pair<Expression, Boolean> resultPair = extractGlobalTimeFilter(predicate);
- Expression globalTimePredicate = null;
- if (resultPair.left != null) {
- globalTimePredicate =
-
ExpressionTranslateVisitor.translateToSymbolReference(resultPair.left,
planBuilder);
-
- queryContext.setGlobalTimeFilter(
- globalTimePredicate.accept(new
ConvertPredicateToTimeFilterVisitor(), null));
- }
- boolean hasValueFilter = resultPair.right;
- if (!hasValueFilter) {
- return planBuilder;
- }
+ // planBuilder = subqueryPlanner.handleSubqueries(subPlan, predicate,
+ // analysis.getSubqueries(node));
analysis.setHasValueFilter(true);
Review Comment:
```suggestion
```
##########
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/QueryPlanner.java:
##########
@@ -139,34 +136,33 @@ public RelationPlan plan(QuerySpecification node) {
// translated
// aggregations are visible.
List<Expression> orderByAggregates =
analysis.getOrderByAggregates(node.getOrderBy().get());
- builder =
- builder.appendProjections(orderByAggregates, analysis,
symbolAllocator, queryContext);
+ builder = builder.appendProjections(orderByAggregates,
symbolAllocator, queryContext);
}
// Add projections for the outputs of SELECT, but stack them on top of
the ones from the FROM
// clause so both are visible
// when resolving the ORDER BY clause.
- // TODO this appendProjections may be removed
- builder = builder.appendProjections(outputs, analysis, symbolAllocator,
queryContext);
+ builder = builder.appendProjections(outputs, symbolAllocator,
queryContext);
// The new scope is the composite of the fields from the FROM and SELECT
clause (local nested
// scopes). Fields from the bottom of
// the scope stack need to be placed first to match the expected layout
for nested scopes.
- // List<Symbol> newFields = new ArrayList<>();
+ List<Symbol> newFields = new ArrayList<>();
// newFields.addAll(builder.getTranslations().getFieldSymbols());
// outputs.stream()
// .map(builder::translate)
// .forEach(newFields::add);
- // builder =
builder.withScope(analysis.getScope(node.getOrderBy().get()), newFields);
+ builder = builder.withScope(analysis.getScope(node.getOrderBy().get()),
newFields);
}
List<Expression> orderBy = analysis.getOrderByExpressions(node);
- if (!orderBy.isEmpty()) {
+ // TODO this appendProjections may be removed
Review Comment:
```suggestion
```
##########
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/QueryPlanner.java:
##########
@@ -139,34 +136,33 @@ public RelationPlan plan(QuerySpecification node) {
// translated
// aggregations are visible.
List<Expression> orderByAggregates =
analysis.getOrderByAggregates(node.getOrderBy().get());
- builder =
- builder.appendProjections(orderByAggregates, analysis,
symbolAllocator, queryContext);
+ builder = builder.appendProjections(orderByAggregates,
symbolAllocator, queryContext);
}
// Add projections for the outputs of SELECT, but stack them on top of
the ones from the FROM
// clause so both are visible
// when resolving the ORDER BY clause.
- // TODO this appendProjections may be removed
- builder = builder.appendProjections(outputs, analysis, symbolAllocator,
queryContext);
+ builder = builder.appendProjections(outputs, symbolAllocator,
queryContext);
// The new scope is the composite of the fields from the FROM and SELECT
clause (local nested
// scopes). Fields from the bottom of
// the scope stack need to be placed first to match the expected layout
for nested scopes.
- // List<Symbol> newFields = new ArrayList<>();
+ List<Symbol> newFields = new ArrayList<>();
// newFields.addAll(builder.getTranslations().getFieldSymbols());
// outputs.stream()
// .map(builder::translate)
// .forEach(newFields::add);
Review Comment:
```suggestion
newFields.addAll(builder.getTranslations().getFieldSymbols());
outputs.stream()
.map(builder::translate)
.forEach(newFields::add);
```
##########
iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/AnalyzerTest.java:
##########
@@ -204,8 +204,10 @@ public void singleTableWithFilterTest() {
logicalQueryPlan = logicalPlanner.plan(actualAnalysis);
rootNode = logicalQueryPlan.getRootNode();
assertTrue(rootNode instanceof OutputNode);
- assertTrue(((OutputNode) rootNode).getChild() instanceof TableScanNode);
- tableScanNode = (TableScanNode) ((OutputNode) rootNode).getChild();
+ assertTrue(((OutputNode) rootNode).getChild() instanceof FilterNode);
Review Comment:
add todo for gaofei, once he implements his part, we should change back here.
##########
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/TranslationMap.java:
##########
@@ -0,0 +1,353 @@
+/*
+ * Licensed 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.iotdb.db.queryengine.plan.relational.planner;
+
+import org.apache.iotdb.db.queryengine.plan.relational.analyzer.Analysis;
+import org.apache.iotdb.db.queryengine.plan.relational.analyzer.NodeRef;
+import org.apache.iotdb.db.queryengine.plan.relational.analyzer.ResolvedField;
+import org.apache.iotdb.db.queryengine.plan.relational.analyzer.Scope;
+import
org.apache.iotdb.db.queryengine.plan.relational.planner.ir.ExpressionRewriter;
+import
org.apache.iotdb.db.queryengine.plan.relational.planner.ir.ExpressionTreeRewriter;
+import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Expression;
+import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.FieldReference;
+import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.FunctionCall;
+import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Identifier;
+import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.SymbolReference;
+import org.apache.iotdb.db.queryengine.plan.relational.sql.util.AstUtil;
+
+import com.google.common.collect.ImmutableMap;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Verify.verify;
+import static java.lang.String.format;
+import static java.util.Objects.requireNonNull;
+import static
org.apache.iotdb.db.queryengine.plan.relational.planner.ScopeAware.scopeAwareKey;
+
+/**
+ * Keeps mappings of fields and AST expressions to symbols in the current plan
within query
+ * boundary.
+ *
+ * <p>AST and IR expressions use the same class hierarchy ({@link
+ * org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Expression}, but
differ in the following
+ * ways:
+ * <li>AST expressions contain Identifiers, while IR expressions contain
SymbolReferences
+ * <li>FunctionCalls in AST expressions are SQL function names. In IR
expressions, they contain an
+ * encoded name representing a resolved function
+ */
+public class TranslationMap {
+ // all expressions are rewritten in terms of fields declared by this
relation plan
+ private final Scope scope;
+ private final Analysis analysis;
+ private final Optional<TranslationMap> outerContext;
+ // TODO unused now
+ private final PlannerContext plannerContext;
+
+ // current mappings of underlying field -> symbol for translating direct
field references
+ private final Symbol[] fieldSymbols;
+
+ // current mappings of sub-expressions -> symbol
+ private final Map<ScopeAware<Expression>, Symbol> astToSymbols;
+ // TODO unused now
+ private final Map<NodeRef<Expression>, Symbol> substitutions;
+
+ public TranslationMap(
+ Optional<TranslationMap> outerContext,
+ Scope scope,
+ Analysis analysis,
+ List<Symbol> fieldSymbols,
+ PlannerContext plannerContext) {
+ this(
+ outerContext,
+ scope,
+ analysis,
+ fieldSymbols.toArray(new Symbol[0]).clone(),
+ ImmutableMap.of(),
+ ImmutableMap.of(),
+ plannerContext);
+ }
+
+ public TranslationMap(
+ Optional<TranslationMap> outerContext,
+ Scope scope,
+ Analysis analysis,
+ List<Symbol> fieldSymbols,
+ Map<ScopeAware<Expression>, Symbol> astToSymbols,
+ PlannerContext plannerContext) {
+ this(
+ outerContext,
+ scope,
+ analysis,
+ fieldSymbols.toArray(new Symbol[0]),
+ astToSymbols,
+ ImmutableMap.of(),
+ plannerContext);
+ }
+
+ public TranslationMap(
+ Optional<TranslationMap> outerContext,
+ Scope scope,
+ Analysis analysis,
+ Symbol[] fieldSymbols,
+ Map<ScopeAware<Expression>, Symbol> astToSymbols,
+ Map<NodeRef<Expression>, Symbol> substitutions,
+ PlannerContext plannerContext) {
+ this.outerContext = requireNonNull(outerContext, "outerContext is null");
+ this.scope = requireNonNull(scope, "scope is null");
+ this.analysis = requireNonNull(analysis, "analysis is null");
+ this.plannerContext = requireNonNull(plannerContext, "plannerContext is
null");
+ this.substitutions = ImmutableMap.copyOf(substitutions);
+
+ requireNonNull(fieldSymbols, "fieldSymbols is null");
+ this.fieldSymbols = fieldSymbols.clone();
+
+ requireNonNull(astToSymbols, "astToSymbols is null");
+ this.astToSymbols = ImmutableMap.copyOf(astToSymbols);
+
+ checkArgument(
+ scope.getLocalScopeFieldCount() == fieldSymbols.length,
+ "scope: %s, fields mappings: %s",
+ scope.getRelationType().getAllFieldCount(),
+ fieldSymbols.length);
+
+ astToSymbols.keySet().stream()
+ .map(ScopeAware::getNode)
+ .forEach(TranslationMap::verifyAstExpression);
+ }
+
+ public TranslationMap withScope(Scope scope, List<Symbol> fields) {
+ return new TranslationMap(
+ outerContext,
+ scope,
+ analysis,
+ fields.toArray(new Symbol[0]),
+ astToSymbols,
+ substitutions,
+ plannerContext);
+ }
+
+ public TranslationMap withNewMappings(
+ Map<ScopeAware<Expression>, Symbol> mappings, List<Symbol> fields) {
+ return new TranslationMap(outerContext, scope, analysis, fields, mappings,
plannerContext);
+ }
+
+ public TranslationMap withAdditionalMappings(Map<ScopeAware<Expression>,
Symbol> mappings) {
+ Map<ScopeAware<Expression>, Symbol> newMappings = new HashMap<>();
+ newMappings.putAll(this.astToSymbols);
+ newMappings.putAll(mappings);
+
+ return new TranslationMap(
+ outerContext, scope, analysis, fieldSymbols, newMappings,
substitutions, plannerContext);
+ }
+
+ public TranslationMap
withAdditionalIdentityMappings(Map<NodeRef<Expression>, Symbol> mappings) {
+ Map<NodeRef<Expression>, Symbol> newMappings = new HashMap<>();
+ newMappings.putAll(this.substitutions);
+ newMappings.putAll(mappings);
+
+ return new TranslationMap(
+ outerContext, scope, analysis, fieldSymbols, astToSymbols,
newMappings, plannerContext);
+ }
+
+ public List<Symbol> getFieldSymbolsList() {
+ return Collections.unmodifiableList(Arrays.asList(fieldSymbols));
+ }
+
+ public Symbol[] getFieldSymbols() {
+ return fieldSymbols;
+ }
+
+ public Map<ScopeAware<Expression>, Symbol> getMappings() {
+ return astToSymbols;
+ }
+
+ public Analysis getAnalysis() {
+ return analysis;
+ }
+
+ public boolean canTranslate(Expression expression) {
+ verifyAstExpression(expression);
+
+ if (astToSymbols.containsKey(scopeAwareKey(expression, analysis, scope))
+ || substitutions.containsKey(NodeRef.of(expression))
+ || expression instanceof FieldReference) {
+ return true;
+ }
+
+ if (analysis.isColumnReference(expression)) {
+ ResolvedField field =
analysis.getColumnReferenceFields().get(NodeRef.of(expression));
+ return scope.isLocalScope(field.getScope());
+ }
+
+ return false;
+ }
+
+ public Expression rewrite(Expression expression) {
+ verifyAstExpression(expression);
+ verify(
+ analysis.isAnalyzed(expression),
+ "Expression is not analyzed (%s): %s",
+ expression.getClass().getName(),
+ expression);
+
+ return ExpressionTreeRewriter.rewriteWith(
+ new ExpressionRewriter<Void>() {
+ @Override
+ protected Expression rewriteExpression(
+ Expression node, Void context, ExpressionTreeRewriter<Void>
treeRewriter) {
+ Optional<SymbolReference> mapped = tryGetMapping(node);
+ if (mapped.isPresent()) {
+ return mapped.get();
+ }
+
+ return treeRewriter.defaultRewrite(node, context);
+ }
+
+ @Override
+ public Expression rewriteFieldReference(
+ FieldReference node, Void context, ExpressionTreeRewriter<Void>
treeRewriter) {
+ Optional<SymbolReference> mapped = tryGetMapping(node);
+ if (mapped.isPresent()) {
+ return mapped.get();
+ }
+
+ return getSymbolForColumn(node)
+ .map(Symbol::toSymbolReference)
+ .orElseThrow(
+ () ->
+ new IllegalStateException(
+ format(
+ "No symbol mapping for node '%s' (%s)",
+ node, node.getFieldIndex())));
+ }
+
+ @Override
+ public Expression rewriteIdentifier(
+ Identifier node, Void context, ExpressionTreeRewriter<Void>
treeRewriter) {
+ Optional<SymbolReference> mapped = tryGetMapping(node);
+ if (mapped.isPresent()) {
+ return mapped.get();
+ }
+
+ return getSymbolForColumn(node)
+ .map(symbol -> (Expression) symbol.toSymbolReference())
+ .orElseGet(() -> node);
+ }
+
+ @Override
+ public Expression rewriteFunctionCall(
+ FunctionCall node, Void context, ExpressionTreeRewriter<Void>
treeRewriter) {
+ Optional<SymbolReference> mapped = tryGetMapping(node);
+ if (mapped.isPresent()) {
+ return mapped.get();
+ }
+
+ // ResolvedFunction resolvedFunction =
analysis.getResolvedFunction(node);
+ // checkArgument(resolvedFunction != null, "Function has not been
analyzed: %s", node);
+
+ List<Expression> newArguments =
+ node.getArguments().stream()
+ .map(argument -> rewrite(argument))
+ .collect(Collectors.toList());
+ return new FunctionCall(node.getName(), node.isDistinct(),
newArguments);
+ }
+
+ /* @Override
+ public Expression rewriteLikePredicate(LikePredicate node, Void
context, ExpressionTreeRewriter<Void> treeRewriter)
+ {
+ Optional<SymbolReference> mapped = tryGetMapping(node);
+ if (mapped.isPresent()) {
+ return mapped.get();
+ }
+
+ Expression value = treeRewriter.rewrite(node.getValue(), context);
+ Expression pattern = treeRewriter.rewrite(node.getPattern(),
context);
+ Optional<Expression> escape = node.getEscape().map(e ->
treeRewriter.rewrite(e, context));
+
+ FunctionCall patternCall;
+ if (escape.isPresent()) {
+ patternCall =
BuiltinFunctionCallBuilder.resolve(plannerContext.getMetadata())
+ .setName(LIKE_PATTERN_FUNCTION_NAME)
+ .addArgument(analysis.getType(node.getPattern()),
pattern)
+ .addArgument(analysis.getType(node.getEscape().get()),
escape.get())
+ .build();
+ }
+ else {
+ patternCall =
BuiltinFunctionCallBuilder.resolve(plannerContext.getMetadata())
+ .setName(LIKE_PATTERN_FUNCTION_NAME)
+ .addArgument(analysis.getType(node.getPattern()),
pattern)
+ .build();
+ }
+
+ FunctionCall call =
BuiltinFunctionCallBuilder.resolve(plannerContext.getMetadata())
+ .setName(LIKE_FUNCTION_NAME)
+ .addArgument(analysis.getType(node.getValue()), value)
+ .addArgument(LIKE_PATTERN, patternCall)
+ .build();
+
+ return coerceIfNecessary(node, call);
+ }*/
Review Comment:
```suggestion
/* @Override
public Expression rewriteLikePredicate(LikePredicate node, Void
context, ExpressionTreeRewriter<Void> treeRewriter)
{
Optional<SymbolReference> mapped = tryGetMapping(node);
if (mapped.isPresent()) {
return mapped.get();
}
Expression value = treeRewriter.rewrite(node.getValue(),
context);
Expression pattern = treeRewriter.rewrite(node.getPattern(),
context);
Optional<Expression> escape = node.getEscape().map(e ->
treeRewriter.rewrite(e, context));
return escape.isPresent()? new LikePredicate(value, pattern,
escape) : new LikePredicate(value, pattern)
}*/
```
--
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]