This is an automated email from the ASF dual-hosted git repository.
caogaofei pushed a commit to branch ty/TableModelGrammar
in repository https://gitbox.apache.org/repos/asf/iotdb.git
The following commit(s) were added to refs/heads/ty/TableModelGrammar by this
push:
new 9e80bc0b006 fix SymbolReference, FieldReference; add
extractGlobalTimeFilter
new 81815dd3f8e Merge branch 'ty/TableModelGrammar' of
github.com:apache/iotdb into ty/TableModelGrammar
9e80bc0b006 is described below
commit 9e80bc0b00676d2fd52c8137a3a61d8502747ec5
Author: Beyyes <[email protected]>
AuthorDate: Tue Apr 16 23:32:23 2024 +0800
fix SymbolReference, FieldReference; add extractGlobalTimeFilter
---
.../plan/relational/analyzer/Analysis.java | 9 +
.../plan/relational/planner/PlanBuilder.java | 41 +-
.../plan/relational/planner/PredicateUtils.java | 415 +++++++++++++++++++++
.../plan/relational/planner/QueryPlanner.java | 22 +-
.../relational/planner/node/TableScanNode.java | 2 +-
.../plan/relational/analyzer/AnalyzerTest.java | 9 +-
.../relational/planner/PredicateUtilsTest.java | 52 +++
.../db/relational/sql/tree/LogicalExpression.java | 6 +-
8 files changed, 538 insertions(+), 18 deletions(-)
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/Analysis.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/Analysis.java
index 3465a6b45d2..e2d603fe479 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/Analysis.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/Analysis.java
@@ -28,6 +28,7 @@ import
org.apache.iotdb.db.queryengine.plan.relational.metadata.TableSchema;
import org.apache.iotdb.db.queryengine.plan.relational.security.AccessControl;
import org.apache.iotdb.db.queryengine.plan.relational.security.Identity;
import org.apache.iotdb.db.relational.sql.tree.AllColumns;
+import org.apache.iotdb.db.relational.sql.tree.DataType;
import org.apache.iotdb.db.relational.sql.tree.ExistsPredicate;
import org.apache.iotdb.db.relational.sql.tree.Expression;
import org.apache.iotdb.db.relational.sql.tree.FunctionCall;
@@ -171,6 +172,10 @@ public class Analysis implements IAnalysis {
return namedQueries.get(NodeRef.of(table));
}
+ public boolean isAnalyzed(Expression expression) {
+ return expression instanceof DataType ||
types.containsKey(NodeRef.of(expression));
+ }
+
public void registerNamedQuery(Table tableReference, Query query) {
requireNonNull(tableReference, "tableReference is null");
requireNonNull(query, "query is null");
@@ -338,6 +343,10 @@ public class Analysis implements IAnalysis {
return where.get(NodeRef.<Node>of(node));
}
+ public Map<NodeRef<Node>, Expression> getWhereMap() {
+ return this.where;
+ }
+
public void setOrderByExpressions(Node node, List<Expression> items) {
orderByExpressions.put(NodeRef.of(node), ImmutableList.copyOf(items));
}
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/PlanBuilder.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/PlanBuilder.java
index 49f93ed3e66..289f88acdc6 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/PlanBuilder.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/PlanBuilder.java
@@ -20,6 +20,7 @@ import
org.apache.iotdb.db.queryengine.plan.relational.analyzer.Analysis;
import org.apache.iotdb.db.queryengine.plan.relational.analyzer.Scope;
import
org.apache.iotdb.db.queryengine.plan.relational.planner.node.ProjectNode;
import org.apache.iotdb.db.relational.sql.tree.Expression;
+import org.apache.iotdb.db.relational.sql.tree.FieldReference;
import com.google.common.collect.ImmutableMap;
@@ -29,16 +30,21 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
+import static com.google.common.base.Verify.verify;
import static java.util.Objects.requireNonNull;
public class PlanBuilder {
private final PlanNode root;
- public PlanBuilder(PlanNode root) {
+ // current mappings of underlying field -> symbol for translating direct
field references
+ private final Symbol[] fieldSymbols;
+
+ public PlanBuilder(PlanNode root, Symbol[] fieldSymbols) {
requireNonNull(root, "root is null");
this.root = root;
+ this.fieldSymbols = fieldSymbols;
}
public static PlanBuilder newPlanBuilder(
@@ -51,21 +57,41 @@ public class PlanBuilder {
Analysis analysis,
Map<ScopeAware<Expression>, Symbol> mappings,
SessionInfo session) {
- return new PlanBuilder(plan.getRoot());
+ return new PlanBuilder(plan.getRoot(), plan.getFieldMappings().toArray(new
Symbol[0]));
}
public PlanBuilder withNewRoot(PlanNode root) {
- return new PlanBuilder(root);
+ return new PlanBuilder(root, fieldSymbols);
}
public PlanBuilder withScope(Scope scope, List<Symbol> fields) {
- return new PlanBuilder(root);
+ return new PlanBuilder(root, fields.toArray(new Symbol[0]));
}
public PlanNode getRoot() {
return root;
}
+ public Symbol[] getFieldSymbols() {
+ return this.fieldSymbols;
+ }
+
+ public Symbol translate(Analysis analysis, Expression expression) {
+ verify(
+ analysis.isAnalyzed(expression),
+ "Expression is not analyzed (%s): %s",
+ expression.getClass().getName(),
+ expression);
+ Expression ret = translate(expression, true);
+ return Symbol.from(ret);
+ }
+
+ private Expression translate(Expression expression, boolean isRoot) {
+ if (expression instanceof FieldReference) {}
+
+ return expression;
+ }
+
public <T extends Expression> PlanBuilder appendProjections(
Iterable<T> expressions,
Analysis analysis,
@@ -85,7 +111,9 @@ public class PlanBuilder {
for (T expression : expressions) {
// Skip any expressions that have already been translated and recorded
in the
// translation map, or that are duplicated in the list of exp
- if (!mappings.containsKey(expression) &&
!set.contains(expression.toString())) {
+ if (!mappings.containsKey(expression)
+ && !set.contains(expression.toString())
+ && !(expression instanceof FieldReference)) {
set.add(expression.toString());
Symbol symbol = symbolAllocator.newSymbol("expr",
analysis.getType(expression));
projections.put(symbol, expression);
@@ -93,6 +121,7 @@ public class PlanBuilder {
}
}
- return new PlanBuilder(new ProjectNode(idAllocator.genPlanNodeId(), root,
projections.build()));
+ return new PlanBuilder(
+ new ProjectNode(idAllocator.genPlanNodeId(), root,
projections.build()), fieldSymbols);
}
}
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/PredicateUtils.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/PredicateUtils.java
new file mode 100644
index 00000000000..0ae8c9444f5
--- /dev/null
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/PredicateUtils.java
@@ -0,0 +1,415 @@
+/*
+ * 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.iotdb.db.queryengine.plan.relational.planner;
+
+import
org.apache.iotdb.db.queryengine.plan.expression.UnknownExpressionTypeException;
+import org.apache.iotdb.db.relational.sql.tree.ComparisonExpression;
+import org.apache.iotdb.db.relational.sql.tree.Expression;
+import org.apache.iotdb.db.relational.sql.tree.Identifier;
+import org.apache.iotdb.db.relational.sql.tree.InPredicate;
+import org.apache.iotdb.db.relational.sql.tree.LogicalExpression;
+import org.apache.iotdb.db.relational.sql.tree.LongLiteral;
+import org.apache.iotdb.tsfile.utils.Pair;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import static org.apache.commons.jexl3.parser.ParserConstants.and;
+import static org.apache.iotdb.commons.conf.IoTDBConstant.TIME;
+import static
org.apache.iotdb.db.relational.sql.tree.BooleanLiteral.TRUE_LITERAL;
+import static
org.apache.iotdb.db.relational.sql.tree.LogicalExpression.Operator.AND;
+import static
org.apache.iotdb.db.relational.sql.tree.LogicalExpression.Operator.OR;
+import static org.apache.iotdb.db.relational.sql.tree.LogicalExpression.and;
+import static org.apache.iotdb.db.relational.sql.tree.LogicalExpression.or;
+
+public class PredicateUtils {
+
+ private PredicateUtils() {
+ // util class
+ }
+
+ /**
+ * TODO consider more expression types
+ *
+ * <p>Extract global time predicate from query predicate.
+ *
+ * @param predicate raw query predicate
+ * @param canRewrite determined by the father of current expression
+ * @param isFirstOr whether it is the first LogicOrExpression encountered
+ * @return left is global time predicate, right is whether it has value
filter
+ * @throws UnknownExpressionTypeException unknown expression type
+ */
+ public static Pair<Expression, Boolean> extractGlobalTimePredicate(
+ Expression predicate, boolean canRewrite, boolean isFirstOr) {
+ if (predicate instanceof LogicalExpression
+ && ((LogicalExpression) predicate).getOperator().equals(AND)) {
+ Pair<Expression, Boolean> leftResultPair =
+ extractGlobalTimePredicate(
+ ((LogicalExpression) predicate).getTerms().get(0), canRewrite,
isFirstOr);
+ Pair<Expression, Boolean> rightResultPair =
+ extractGlobalTimePredicate(
+ ((LogicalExpression) predicate).getTerms().get(1), canRewrite,
isFirstOr);
+
+ // rewrite predicate to avoid duplicate calculation on time filter
+ // If Left-child or Right-child does not contain value filter
+ // We can set it to true in Predicate Tree
+ if (canRewrite) {
+ LogicalExpression logicalExpression = (LogicalExpression) predicate;
+ Expression newLeftExpression = null, newRightExpression = null;
+ if (leftResultPair.left != null && !leftResultPair.right) {
+ newLeftExpression = TRUE_LITERAL;
+ }
+ if (rightResultPair.left != null && !rightResultPair.right) {
+ newRightExpression = TRUE_LITERAL;
+ }
+ if (newLeftExpression != null || newRightExpression != null) {
+ logicalExpression.setTerms(
+ Arrays.asList(
+ newLeftExpression != null
+ ? newLeftExpression
+ : logicalExpression.getTerms().get(0),
+ newRightExpression != null
+ ? newRightExpression
+ : logicalExpression.getTerms().get(1)));
+ }
+ }
+
+ if (leftResultPair.left != null && rightResultPair.left != null) {
+ return new Pair<>(
+ and(leftResultPair.left, rightResultPair.left),
+ leftResultPair.right || rightResultPair.right);
+ } else if (leftResultPair.left != null) {
+ return new Pair<>(leftResultPair.left, true);
+ } else if (rightResultPair.left != null) {
+ return new Pair<>(rightResultPair.left, true);
+ }
+ return new Pair<>(null, true);
+ } else if (predicate instanceof LogicalExpression
+ && ((LogicalExpression) predicate).getOperator().equals(OR)) {
+ Pair<Expression, Boolean> leftResultPair =
+ extractGlobalTimePredicate(
+ ((LogicalExpression) predicate).getTerms().get(0), false, false);
+ Pair<Expression, Boolean> rightResultPair =
+ extractGlobalTimePredicate(
+ ((LogicalExpression) predicate).getTerms().get(1), false, false);
+
+ if (leftResultPair.left != null && rightResultPair.left != null) {
+ if (Boolean.TRUE.equals(isFirstOr && !leftResultPair.right &&
!rightResultPair.right)) {
+ ((LogicalExpression) predicate).getTerms().set(0, TRUE_LITERAL);
+ ((LogicalExpression) predicate).getTerms().set(0, TRUE_LITERAL);
+ }
+ return new Pair<>(
+ or(leftResultPair.left, rightResultPair.left),
+ leftResultPair.right || rightResultPair.right);
+ }
+ return new Pair<>(null, true);
+ }
+ // else if
(predicate.getExpressionType().equals(ExpressionType.LOGIC_NOT)) {
+ // Pair<Expression, Boolean> childResultPair =
+ // extractGlobalTimePredicate(
+ // ((UnaryExpression) predicate).getExpression(), canRewrite,
isFirstOr);
+ // if (childResultPair.left != null) {
+ // return new Pair<>(not(childResultPair.left),
childResultPair.right);
+ // }
+ // return new Pair<>(null, true);
+ // }
+ else if (predicate instanceof ComparisonExpression) {
+ Expression leftExpression = ((ComparisonExpression) predicate).getLeft();
+ Expression rightExpression = ((ComparisonExpression)
predicate).getRight();
+ if (checkIsTimeFilter(leftExpression, rightExpression)
+ || checkIsTimeFilter(rightExpression, leftExpression)) {
+ return new Pair<>(predicate, false);
+ }
+ return new Pair<>(null, true);
+ }
+ // else if (predicate instanceof LIKE)
+ // || predicate.getExpressionType().equals(ExpressionType.REGEXP)) {
+ // // time filter don't support LIKE and REGEXP
+ // return new Pair<>(null, true);
+ // }
+
+ // else if (predicate instanceof BetweenPredicate) {
+ // Expression firstExpression = ((TernaryExpression)
predicate).getFirstExpression();
+ // Expression secondExpression = ((TernaryExpression)
predicate).getSecondExpression();
+ // Expression thirdExpression = ((TernaryExpression)
predicate).getThirdExpression();
+ //
+ // boolean isTimeFilter = false;
+ // if
(firstExpression.getExpressionType().equals(ExpressionType.TIMESTAMP)) {
+ // isTimeFilter = checkBetweenConstantSatisfy(secondExpression,
thirdExpression);
+ // } else if
(secondExpression.getExpressionType().equals(ExpressionType.TIMESTAMP)) {
+ // isTimeFilter = checkBetweenConstantSatisfy(firstExpression,
thirdExpression);
+ // } else if
(thirdExpression.getExpressionType().equals(ExpressionType.TIMESTAMP)) {
+ // isTimeFilter = checkBetweenConstantSatisfy(secondExpression,
firstExpression);
+ // }
+ // if (isTimeFilter) {
+ // return new Pair<>(predicate, false);
+ // }
+ // return new Pair<>(null, true);
+ // }
+
+ else if (predicate instanceof InPredicate) {
+ // time filter don't support IS_NULL
+ return new Pair<>(null, true);
+ }
+ // else if (predicate.getExpressionType().equals(ExpressionType.IN)) {
+ // Expression timeExpression = ((InExpression)
predicate).getExpression();
+ // if
(timeExpression.getExpressionType().equals(ExpressionType.TIMESTAMP)) {
+ // return new Pair<>(predicate, false);
+ // }
+ // return new Pair<>(null, true);
+ // }
+ // else if
(predicate.getExpressionType().equals(ExpressionType.TIMESERIES)
+ // ||
predicate.getExpressionType().equals(ExpressionType.CONSTANT)) {
+ // return new Pair<>(null, true);
+ // }
+ // else if
(predicate.getExpressionType().equals(ExpressionType.CASE_WHEN_THEN)) {
+ // return new Pair<>(null, true);
+ // }
+ // else if
(ExpressionType.FUNCTION.equals(predicate.getExpressionType())) {
+ // return new Pair<>(null, true);
+ // }
+ else {
+ throw new IllegalStateException(
+ "Unsupported expression in extractGlobalTimePredicate: " +
predicate);
+ }
+ }
+
+ private static boolean checkIsTimeFilter(Expression timeExpression,
Expression valueExpression) {
+ return timeExpression instanceof Identifier
+ && ((Identifier) timeExpression).getValue().equalsIgnoreCase(TIME)
+ && valueExpression instanceof LongLiteral;
+ }
+
+ // private static boolean checkBetweenConstantSatisfy(Expression e1,
Expression e2) {
+ // return e1.isConstantOperand()
+ // && e2.isConstantOperand()
+ // && ((ConstantOperand) e1).getDataType() == TSDataType.INT64
+ // && ((ConstantOperand) e2).getDataType() == TSDataType.INT64
+ // && (Long.parseLong(((ConstantOperand) e1).getValueString())
+ // <= Long.parseLong(((ConstantOperand) e2).getValueString()));
+ // }
+
+ /**
+ * Check if the given expression contains time filter.
+ *
+ * @param predicate given expression
+ * @return true if the given expression contains time filter
+ */
+ // public static boolean checkIfTimeFilterExist(Expression predicate) {
+ // return new TimeFilterExistChecker().process(predicate, null);
+ // }
+
+ /**
+ * Recursively removes all use of the not() operator in a predicate by
replacing all instances of
+ * not(x) with the inverse(x),
+ *
+ * <p>eg: not(and(eq(), not(eq(y))) -> or(notEq(), eq(y))
+ *
+ * <p>The returned predicate should have the same meaning as the original,
but without the use of
+ * the not() operator.
+ *
+ * <p>See also {@link PredicateUtils#reversePredicate(Expression)}, which is
used to do the
+ * inversion.
+ *
+ * @param predicate the predicate to remove not() from
+ * @return the predicate with all not() operators removed
+ */
+ // public static Expression predicateRemoveNot(Expression predicate) {
+ // if (predicate.getExpressionType().equals(ExpressionType.LOGIC_AND)) {
+ // return ExpressionFactory.and(
+ // predicateRemoveNot(((BinaryExpression)
predicate).getLeftExpression()),
+ // predicateRemoveNot(((BinaryExpression)
predicate).getRightExpression()));
+ // } else if
(predicate.getExpressionType().equals(ExpressionType.LOGIC_OR)) {
+ // return ExpressionFactory.or(
+ // predicateRemoveNot(((BinaryExpression)
predicate).getLeftExpression()),
+ // predicateRemoveNot(((BinaryExpression)
predicate).getRightExpression()));
+ // } else if
(predicate.getExpressionType().equals(ExpressionType.LOGIC_NOT)) {
+ // return reversePredicate(((LogicNotExpression)
predicate).getExpression());
+ // }
+ // return predicate;
+ // }
+
+ /**
+ * Converts a predicate to its logical inverse. The returned predicate
should be equivalent to
+ * not(p), but without the use of a not() operator.
+ *
+ * <p>See also {@link PredicateUtils#predicateRemoveNot(Expression)}, which
can remove the use of
+ * all not() operators without inverting the overall predicate.
+ *
+ * @param predicate given predicate
+ * @return the predicate after reversing
+ */
+ // public static Expression reversePredicate(Expression predicate) {
+ // return new ReversePredicateVisitor().process(predicate, null);
+ // }
+
+ /**
+ * Simplify the given predicate (Remove the NULL and TRUE/FALSE expression).
+ *
+ * @param predicate given predicate
+ * @return the predicate after simplifying
+ */
+ // public static Expression simplifyPredicate(Expression predicate) {
+ // return new PredicateSimplifier().process(predicate, null);
+ // }
+
+ /**
+ * Convert the given predicate to time filter.
+ *
+ * <p>Note: the supplied predicate must not contain any instances of the
not() operator as this is
+ * not supported by this filter. The supplied predicate should first be run
through {@link
+ * PredicateUtils#predicateRemoveNot(Expression)} to rewrite it in a form
that doesn't make use of
+ * the not() operator.
+ *
+ * @param predicate given predicate
+ * @return the time filter converted from the given predicate
+ */
+ // public static Filter convertPredicateToTimeFilter(Expression predicate) {
+ // if (predicate == null) {
+ // return null;
+ // }
+ // return predicate.accept(new ConvertPredicateToTimeFilterVisitor(),
null);
+ // }
+
+ // public static Filter convertPredicateToFilter(
+ // Expression predicate,
+ // List<String> allMeasurements,
+ // boolean isBuildPlanUseTemplate,
+ // TypeProvider typeProvider) {
+ // if (predicate == null) {
+ // return null;
+ // }
+ // return predicate.accept(
+ // new ConvertPredicateToFilterVisitor(),
+ // new ConvertPredicateToFilterVisitor.Context(
+ // allMeasurements, isBuildPlanUseTemplate, typeProvider));
+ // }
+
+ /**
+ * Combine the given conjuncts into a single expression using "and".
+ *
+ * @param conjuncts given conjuncts
+ * @return the expression combined by the given conjuncts
+ */
+ public static Expression combineConjuncts(List<Expression> conjuncts) {
+ if (conjuncts.size() == 1) {
+ return conjuncts.get(0);
+ }
+ return constructRightDeepTreeWithAnd(conjuncts);
+ }
+
+ private static Expression constructRightDeepTreeWithAnd(List<Expression>
conjuncts) {
+ // TODO: consider other structures of tree
+ if (conjuncts.size() == 2) {
+ return and(conjuncts.get(0), conjuncts.get(1));
+ } else {
+ return and(
+ conjuncts.get(0), constructRightDeepTreeWithAnd(conjuncts.subList(1,
conjuncts.size())));
+ }
+ }
+
+ public static Expression removeDuplicateConjunct(Expression predicate) {
+ if (predicate == null) {
+ return null;
+ }
+ Set<Expression> conjuncts = new HashSet<>();
+ extractConjuncts(predicate, conjuncts);
+ return combineConjuncts(new ArrayList<>(conjuncts));
+ }
+
+ public static List<Expression> extractConjuncts(Expression predicate) {
+ Set<Expression> conjuncts = new HashSet<>();
+ extractConjuncts(predicate, conjuncts);
+ return new ArrayList<>(conjuncts);
+ }
+
+ private static void extractConjuncts(Expression predicate, Set<Expression>
conjuncts) {
+ if (predicate instanceof LogicalExpression
+ && ((LogicalExpression) predicate).getOperator() == AND) {
+ extractConjuncts(((LogicalExpression) predicate).getTerms().get(0),
conjuncts);
+ extractConjuncts(((LogicalExpression) predicate).getTerms().get(1),
conjuncts);
+ } else {
+ conjuncts.add(predicate);
+ }
+ }
+
+ /**
+ * Extract the source symbol (full path for non-aligned path, device path
for aligned path) from
+ * the given predicate. If the predicate contains multiple source symbols,
return null.
+ *
+ * @param predicate given predicate
+ * @return the source symbol extracted from the given predicate
+ */
+ // public static PartialPath extractPredicateSourceSymbol(Expression
predicate) {
+ // List<Expression> sourceExpressions =
ExpressionAnalyzer.searchSourceExpressions(predicate);
+ // Set<PartialPath> sourcePaths =
+ // sourceExpressions.stream()
+ // .map(expression -> ((TimeSeriesOperand) expression).getPath())
+ // .collect(Collectors.toSet());
+ // Iterator<PartialPath> pathIterator = sourcePaths.iterator();
+ // MeasurementPath firstPath = (MeasurementPath) pathIterator.next();
+ //
+ // if (sourcePaths.size() == 1) {
+ // // only contain one source path, can be push down
+ // return firstPath.isUnderAlignedEntity() ? firstPath.getDevicePath()
: firstPath;
+ // }
+ //
+ // // sourcePaths contain more than one path, can be push down when
+ // // these paths under on aligned device
+ // if (!firstPath.isUnderAlignedEntity()) {
+ // return null;
+ // }
+ // PartialPath checkedDevice = firstPath.getDevicePath();
+ // while (pathIterator.hasNext()) {
+ // MeasurementPath path = (MeasurementPath) pathIterator.next();
+ // if (!path.isUnderAlignedEntity() ||
!path.getDevicePath().equals(checkedDevice)) {
+ // return null;
+ // }
+ // }
+ // return checkedDevice;
+ // }
+
+ /**
+ * Check if the given predicate can be pushed down from FilterNode to
ScanNode.
+ *
+ * <p>The predicate <b>cannot</b> be pushed down if it satisfies the
following conditions:
+ * <li>predicate contains IS_NULL
+ *
+ * @param predicate given predicate
+ * @return true if the given predicate can be pushed down to source
+ */
+ // public static boolean predicateCanPushDownToSource(Expression predicate)
{
+ // return new PredicateCanPushDownToSourceChecker().process(predicate,
null);
+ // }
+
+ /**
+ * Check if the given predicate can be pushed into ScanOperator and execute
using the {@link
+ * Filter} interface.
+ *
+ * @param predicate given predicate
+ * @return true if the given predicate can be pushed into ScanOperator
+ */
+ // public static boolean predicateCanPushIntoScan(Expression predicate) {
+ // return new PredicatePushIntoScanChecker().process(predicate, null);
+ // }
+}
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/QueryPlanner.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/QueryPlanner.java
index 616a7c5c2c1..f301a3cebec 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/QueryPlanner.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/QueryPlanner.java
@@ -24,6 +24,7 @@ import
org.apache.iotdb.db.queryengine.plan.relational.planner.node.OffsetNode;
import org.apache.iotdb.db.queryengine.plan.relational.planner.node.SortNode;
import org.apache.iotdb.db.relational.sql.tree.Delete;
import org.apache.iotdb.db.relational.sql.tree.Expression;
+import org.apache.iotdb.db.relational.sql.tree.FieldReference;
import org.apache.iotdb.db.relational.sql.tree.Node;
import org.apache.iotdb.db.relational.sql.tree.Offset;
import org.apache.iotdb.db.relational.sql.tree.OrderBy;
@@ -32,6 +33,7 @@ import org.apache.iotdb.db.relational.sql.tree.QueryBody;
import org.apache.iotdb.db.relational.sql.tree.QuerySpecification;
import org.apache.iotdb.db.relational.sql.tree.SortItem;
import org.apache.iotdb.tsfile.read.common.type.Type;
+import org.apache.iotdb.tsfile.utils.Pair;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
@@ -47,6 +49,7 @@ import static
com.google.common.collect.ImmutableList.toImmutableList;
import static java.util.Objects.requireNonNull;
import static
org.apache.iotdb.db.queryengine.plan.relational.planner.OrderingTranslator.sortItemToSortOrder;
import static
org.apache.iotdb.db.queryengine.plan.relational.planner.PlanBuilder.newPlanBuilder;
+import static
org.apache.iotdb.db.queryengine.plan.relational.planner.PredicateUtils.extractGlobalTimePredicate;
public class QueryPlanner {
private final Analysis analysis;
@@ -104,7 +107,7 @@ public class QueryPlanner {
builder = builder.appendProjections(outputs, analysis, symbolAllocator,
idAllocator);
return new RelationPlan(
- builder.getRoot(), analysis.getScope(query), computeOutputs(builder,
outputs));
+ builder.getRoot(), analysis.getScope(query), computeOutputs(builder,
analysis, outputs));
}
public RelationPlan plan(QuerySpecification node) {
@@ -171,7 +174,7 @@ public class QueryPlanner {
builder = builder.appendProjections(outputs, analysis, symbolAllocator,
idAllocator);
return new RelationPlan(
- builder.getRoot(), analysis.getScope(node), computeOutputs(builder,
outputs));
+ builder.getRoot(), analysis.getScope(node), computeOutputs(builder,
analysis, outputs));
// TODO handle aggregate, having, distinct, subQuery later
}
@@ -201,10 +204,17 @@ public class QueryPlanner {
}
private static List<Symbol> computeOutputs(
- PlanBuilder builder, List<Expression> outputExpressions) {
+ PlanBuilder builder, Analysis analysis, List<Expression>
outputExpressions) {
ImmutableList.Builder<Symbol> outputSymbols = ImmutableList.builder();
for (Expression expression : outputExpressions) {
- outputSymbols.add(new Symbol(expression.toString()));
+ // Symbol symbol = builder.translate(analysis, expression);
+ // outputSymbols.add(symbol);
+ Symbol symbol = null;
+ if (expression instanceof FieldReference) {
+ FieldReference reference = (FieldReference) expression;
+ symbol = builder.getFieldSymbols()[reference.getFieldIndex()];
+ }
+ outputSymbols.add(symbol != null ? symbol : new
Symbol(expression.toString()));
}
return outputSymbols.build();
}
@@ -233,10 +243,12 @@ public class QueryPlanner {
return subPlan;
}
- // subPlan = subqueryPlanner.handleSubqueries(subPlan, predicate,
analysis.getSubqueries(node));
+ Pair<Expression, Boolean> ret = extractGlobalTimePredicate(predicate,
true, true);
return subPlan.withNewRoot(
new FilterNode(idAllocator.genPlanNodeId(), subPlan.getRoot(),
predicate));
+
+ // subPlan = subqueryPlanner.handleSubqueries(subPlan, predicate,
analysis.getSubqueries(node));
}
public static Expression coerceIfNecessary(
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/TableScanNode.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/TableScanNode.java
index 7af35991103..ca271871f5b 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/TableScanNode.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/TableScanNode.java
@@ -26,7 +26,7 @@ public class TableScanNode extends PlanNode {
private final Map<Symbol, ColumnSchema> assignments;
private List<DeviceEntry> deviceEntries;
- private Map<Symbol, Integer> attributesMap;
+ private Map<Symbol, Integer> idAndAttributeIndexMap;
// The order to traverse the data.
// Currently, we only support TIMESTAMP_ASC and TIMESTAMP_DESC here.
diff --git
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/AnalyzerTest.java
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/AnalyzerTest.java
index 8bb2cecd3bc..34eca515305 100644
---
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/AnalyzerTest.java
+++
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/AnalyzerTest.java
@@ -60,9 +60,7 @@ import static org.mockito.ArgumentMatchers.eq;
public class AnalyzerTest {
- private final SqlParser sqlParser = new SqlParser();
-
- private final NopAccessControl nopAccessControl = new NopAccessControl();
+ private static final NopAccessControl nopAccessControl = new
NopAccessControl();
@Test
public void testMockQuery() throws OperatorNotFoundException {
@@ -133,7 +131,7 @@ public class AnalyzerTest {
@Test
public void testSingleTableQuery() throws IoTDBException {
// no sort
- String sql = "SELECT tag1 as tt, tag2, attr1, s1+1 FROM table1 ";
+ String sql = "SELECT tag1 as tt, tag2, attr1, s1+1 FROM table1 where
time>1 and s1>1";
// + "WHERE time>1 AND tag1='A' OR s2>3";
Metadata metadata = new TestMatadata();
@@ -151,8 +149,9 @@ public class AnalyzerTest {
System.out.println(result);
}
- private Analysis analyzeSQL(String sql, Metadata metadata) {
+ public static Analysis analyzeSQL(String sql, Metadata metadata) {
try {
+ SqlParser sqlParser = new SqlParser();
Statement statement = sqlParser.createStatement(sql);
SessionInfo session = new SessionInfo(0, "test", ZoneId.systemDefault(),
"testdb");
StatementAnalyzerFactory statementAnalyzerFactory =
diff --git
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/planner/PredicateUtilsTest.java
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/planner/PredicateUtilsTest.java
new file mode 100644
index 00000000000..cb369a8839c
--- /dev/null
+++
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/planner/PredicateUtilsTest.java
@@ -0,0 +1,52 @@
+/*
+ * 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.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.TestMatadata;
+import org.apache.iotdb.db.queryengine.plan.relational.metadata.Metadata;
+import org.apache.iotdb.db.relational.sql.tree.Expression;
+import org.apache.iotdb.tsfile.utils.Pair;
+
+import org.junit.Test;
+
+import static
org.apache.iotdb.db.queryengine.plan.relational.analyzer.AnalyzerTest.analyzeSQL;
+import static
org.apache.iotdb.db.queryengine.plan.relational.planner.PredicateUtils.extractGlobalTimePredicate;
+
+public class PredicateUtilsTest {
+ @Test
+ public void extractGlobalTimePredicateTest() {
+ String sql = "SELECT tag1 FROM table1 where time>1 and s1>1";
+ Metadata metadata = new TestMatadata();
+
+ Analysis actualAnalysis = analyzeSQL(sql, metadata);
+ Pair<Expression, Boolean> ret =
+ extractGlobalTimePredicate(
+ actualAnalysis.getWhereMap().values().iterator().next(), true,
true);
+ System.out.println(ret.getLeft());
+
+ sql = "SELECT tag1 FROM table1 where time>1 and s1>1 or tag1='A'";
+ actualAnalysis = analyzeSQL(sql, metadata);
+ ret =
+ extractGlobalTimePredicate(
+ actualAnalysis.getWhereMap().values().iterator().next(), true,
true);
+ System.out.println(ret.getLeft());
+ }
+}
diff --git
a/iotdb-core/relational-parser/src/main/java/org/apache/iotdb/db/relational/sql/tree/LogicalExpression.java
b/iotdb-core/relational-parser/src/main/java/org/apache/iotdb/db/relational/sql/tree/LogicalExpression.java
index c99c764e56d..a5eea3e4a77 100644
---
a/iotdb-core/relational-parser/src/main/java/org/apache/iotdb/db/relational/sql/tree/LogicalExpression.java
+++
b/iotdb-core/relational-parser/src/main/java/org/apache/iotdb/db/relational/sql/tree/LogicalExpression.java
@@ -45,7 +45,7 @@ public class LogicalExpression extends Expression {
}
private final Operator operator;
- private final List<Expression> terms;
+ private List<Expression> terms;
public LogicalExpression(Operator operator, List<Expression> terms) {
super(null);
@@ -69,6 +69,10 @@ public class LogicalExpression extends Expression {
return terms;
}
+ public void setTerms(List<Expression> terms) {
+ this.terms = ImmutableList.copyOf(terms);
+ }
+
@Override
public <R, C> R accept(AstVisitor<R, C> visitor, C context) {
return visitor.visitLogicalExpression(this, context);