This is an automated email from the ASF dual-hosted git repository.
jackietien 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 eea9de150eb Add FilterScanCombine optimize rule
eea9de150eb is described below
commit eea9de150eb46f13b0e8db590777b3e84d366565
Author: Beyyes <[email protected]>
AuthorDate: Tue Jun 11 12:05:40 2024 +0800
Add FilterScanCombine optimize rule
---
.../db/queryengine/common/MPPQueryContext.java | 15 ++
.../relational/ColumnTransformerBuilder.java | 2 +-
...a => PredicateCombineIntoTableScanChecker.java} | 71 ++++---
....java => PredicatePushIntoMetadataChecker.java} | 11 +-
.../plan/relational/planner/LogicalPlanner.java | 4 +-
.../plan/relational/planner/RelationPlanner.java | 12 +-
.../ExtractCommonPredicatesExpressionRewriter.java | 2 +-
.../relational/planner/node/TableScanNode.java | 22 +-
.../planner/optimizations/FilterScanCombine.java | 227 +++++++++++++++++++++
.../planner/optimizations/IndexScan.java | 67 +++---
.../planner/optimizations/PredicatePushDown.java | 125 ------------
.../planner/optimizations/PruneUnUsedColumns.java | 14 ++
.../plan/relational/analyzer/AnalyzerTest.java | 53 ++++-
13 files changed, 408 insertions(+), 217 deletions(-)
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/MPPQueryContext.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/MPPQueryContext.java
index 988224da729..1f9b24c713b 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/MPPQueryContext.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/MPPQueryContext.java
@@ -27,6 +27,7 @@ import org.apache.iotdb.db.queryengine.plan.analyze.QueryType;
import org.apache.iotdb.db.queryengine.plan.analyze.TypeProvider;
import org.apache.iotdb.db.queryengine.plan.analyze.lock.SchemaLockType;
import org.apache.iotdb.db.queryengine.plan.planner.LocalExecutionPlanner;
+import org.apache.iotdb.db.queryengine.plan.relational.sql.tree.Expression;
import org.apache.iotdb.db.queryengine.statistics.QueryPlanStatistics;
import org.apache.tsfile.read.filter.basic.Filter;
@@ -89,6 +90,11 @@ public class MPPQueryContext {
private final LocalExecutionPlanner LOCAL_EXECUTION_PLANNER =
LocalExecutionPlanner.getInstance();
+ // splits predicate expression in table model into three parts,
+ // index 0 represents metadataExpressions, index 1 represents
expressionsCanPushDownToOperator,
+ // index 2 represents expressionsCannotPushDownToOperator
+ private List<List<Expression>> tableModelPredicateExpressions;
+
public MPPQueryContext(QueryId queryId) {
this.queryId = queryId;
this.endPointBlackList = new LinkedList<>();
@@ -312,6 +318,15 @@ public class MPPQueryContext {
queryPlanStatistics.setLogicalOptimizationCost(logicalOptimizeCost);
}
+ public List<List<Expression>> getTableModelPredicateExpressions() {
+ return tableModelPredicateExpressions;
+ }
+
+ public void setTableModelPredicateExpressions(
+ List<List<Expression>> tableModelPredicateExpressions) {
+ this.tableModelPredicateExpressions = tableModelPredicateExpressions;
+ }
+
// region =========== FE memory related, make sure its not called
concurrently ===========
/**
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/relational/ColumnTransformerBuilder.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/relational/ColumnTransformerBuilder.java
index fb405d1c62e..b911e2f0da4 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/relational/ColumnTransformerBuilder.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/relational/ColumnTransformerBuilder.java
@@ -113,7 +113,7 @@ import java.util.Optional;
import java.util.stream.Collectors;
import static com.google.common.base.Preconditions.checkArgument;
-import static
org.apache.iotdb.db.queryengine.plan.relational.analyzer.predicate.PredicatePushIntoIndexScanChecker.isStringLiteral;
+import static
org.apache.iotdb.db.queryengine.plan.relational.analyzer.predicate.PredicatePushIntoMetadataChecker.isStringLiteral;
import static
org.apache.iotdb.db.queryengine.plan.relational.type.InternalTypeManager.getTSDataType;
import static
org.apache.iotdb.db.queryengine.plan.relational.type.TypeSignatureTranslator.toTypeSignature;
import static org.apache.tsfile.read.common.type.BinaryType.TEXT;
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/predicate/PredicatePushIntoIndexScanChecker.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/predicate/PredicateCombineIntoTableScanChecker.java
similarity index 68%
copy from
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/predicate/PredicatePushIntoIndexScanChecker.java
copy to
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/predicate/PredicateCombineIntoTableScanChecker.java
index f7d2c1764a3..03b717f3fe6 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/predicate/PredicatePushIntoIndexScanChecker.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/predicate/PredicateCombineIntoTableScanChecker.java
@@ -32,20 +32,24 @@ import
org.apache.iotdb.db.queryengine.plan.relational.sql.tree.NotExpression;
import
org.apache.iotdb.db.queryengine.plan.relational.sql.tree.NullIfExpression;
import
org.apache.iotdb.db.queryengine.plan.relational.sql.tree.SearchedCaseExpression;
import
org.apache.iotdb.db.queryengine.plan.relational.sql.tree.SimpleCaseExpression;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.tree.StringLiteral;
import
org.apache.iotdb.db.queryengine.plan.relational.sql.tree.SymbolReference;
import java.util.List;
import java.util.Set;
+import static
org.apache.iotdb.db.queryengine.plan.relational.analyzer.predicate.PredicatePushIntoScanChecker.isLiteral;
import static
org.apache.iotdb.db.queryengine.plan.relational.analyzer.predicate.PredicatePushIntoScanChecker.isSymbolReference;
-public class PredicatePushIntoIndexScanChecker extends
PredicateVisitor<Boolean, Void> {
+public class PredicateCombineIntoTableScanChecker extends
PredicateVisitor<Boolean, Void> {
- private final Set<String> idOrAttributeColumnNames;
+ private final Set<String> measurementColumns;
- public PredicatePushIntoIndexScanChecker(Set<String>
idOrAttributeColumnNames) {
- this.idOrAttributeColumnNames = idOrAttributeColumnNames;
+ public static boolean check(Set<String> measurementColumns, Expression
expression) {
+ return new
PredicateCombineIntoTableScanChecker(measurementColumns).process(expression);
+ }
+
+ public PredicateCombineIntoTableScanChecker(Set<String> measurementColumns) {
+ this.measurementColumns = measurementColumns;
}
@Override
@@ -54,7 +58,7 @@ public class PredicatePushIntoIndexScanChecker extends
PredicateVisitor<Boolean,
}
@Override
- protected Boolean visitInPredicate(InPredicate node, Void context) {
+ protected Boolean visitNotExpression(NotExpression node, Void context) {
return Boolean.FALSE;
}
@@ -64,53 +68,64 @@ public class PredicatePushIntoIndexScanChecker extends
PredicateVisitor<Boolean,
}
@Override
- protected Boolean visitIsNotNullPredicate(IsNotNullPredicate node, Void
context) {
- return Boolean.FALSE;
+ protected Boolean visitInPredicate(InPredicate node, Void context) {
+ return isMeasurementColumn(node.getValue());
}
@Override
protected Boolean visitLikePredicate(LikePredicate node, Void context) {
- return Boolean.FALSE;
+ return isMeasurementColumn(node.getValue())
+ && isLiteral(node.getPattern())
+ &&
node.getEscape().map(PredicatePushIntoScanChecker::isLiteral).orElse(true);
}
@Override
protected Boolean visitLogicalExpression(LogicalExpression node, Void
context) {
if (node.getOperator() == LogicalExpression.Operator.AND) {
- throw new IllegalStateException("Shouldn't have AND operator in index
scan expression.");
+ throw new IllegalStateException(
+ "Shouldn't have AND operator in
PredicateCombineIntoTableScanChecker.");
}
+
List<Expression> children = node.getTerms();
for (Expression child : children) {
Boolean result = process(child, context);
if (result == null) {
- throw new IllegalStateException("Should never return null.");
+ throw new IllegalStateException(
+ "Should never return null in
PredicateCombineIntoTableScanChecker.");
}
if (!result) {
return Boolean.FALSE;
}
}
+
return Boolean.TRUE;
}
@Override
- protected Boolean visitNotExpression(NotExpression node, Void context) {
- return Boolean.FALSE;
+ protected Boolean visitComparisonExpression(ComparisonExpression node, Void
context) {
+ return (isMeasurementColumn(node.getLeft()) && isLiteral(node.getRight()))
+ || (isMeasurementColumn(node.getRight()) && isLiteral(node.getLeft()));
}
@Override
- protected Boolean visitComparisonExpression(ComparisonExpression node, Void
context) {
- if (node.getOperator() == ComparisonExpression.Operator.EQUAL) {
- return (isIdOrAttributeColumn(node.getLeft()) &&
isStringLiteral(node.getRight()))
- || (isIdOrAttributeColumn(node.getRight()) &&
isStringLiteral(node.getLeft()));
- } else {
- return Boolean.FALSE;
- }
+ protected Boolean visitBetweenPredicate(BetweenPredicate node, Void context)
{
+ return (isMeasurementColumn(node.getValue())
+ && isLiteral(node.getMin())
+ && isLiteral(node.getMax()))
+ || (isLiteral(node.getValue())
+ && isMeasurementColumn(node.getMin())
+ && isLiteral(node.getMax()))
+ || (isLiteral(node.getValue())
+ && isLiteral(node.getMin())
+ && isMeasurementColumn(node.getMax()));
}
- private boolean isIdOrAttributeColumn(Expression expression) {
- return isSymbolReference(expression)
- && idOrAttributeColumnNames.contains(((SymbolReference)
expression).getName());
+ @Override
+ protected Boolean visitIsNotNullPredicate(IsNotNullPredicate node, Void
context) {
+ return isMeasurementColumn(node.getValue());
}
+ // expression below will be supported later
@Override
protected Boolean visitSimpleCaseExpression(SimpleCaseExpression node, Void
context) {
return Boolean.FALSE;
@@ -131,12 +146,8 @@ public class PredicatePushIntoIndexScanChecker extends
PredicateVisitor<Boolean,
return Boolean.FALSE;
}
- @Override
- protected Boolean visitBetweenPredicate(BetweenPredicate node, Void context)
{
- return Boolean.FALSE;
- }
-
- public static boolean isStringLiteral(Expression expression) {
- return expression instanceof StringLiteral;
+ private boolean isMeasurementColumn(Expression expression) {
+ return isSymbolReference(expression)
+ && measurementColumns.contains(((SymbolReference)
expression).getName());
}
}
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/predicate/PredicatePushIntoIndexScanChecker.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/predicate/PredicatePushIntoMetadataChecker.java
similarity index 91%
rename from
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/predicate/PredicatePushIntoIndexScanChecker.java
rename to
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/predicate/PredicatePushIntoMetadataChecker.java
index f7d2c1764a3..62551a24b84 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/predicate/PredicatePushIntoIndexScanChecker.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/predicate/PredicatePushIntoMetadataChecker.java
@@ -40,11 +40,15 @@ import java.util.Set;
import static
org.apache.iotdb.db.queryengine.plan.relational.analyzer.predicate.PredicatePushIntoScanChecker.isSymbolReference;
-public class PredicatePushIntoIndexScanChecker extends
PredicateVisitor<Boolean, Void> {
+public class PredicatePushIntoMetadataChecker extends
PredicateVisitor<Boolean, Void> {
private final Set<String> idOrAttributeColumnNames;
- public PredicatePushIntoIndexScanChecker(Set<String>
idOrAttributeColumnNames) {
+ public static boolean check(Set<String> idOrAttributeColumnNames, Expression
expression) {
+ return new
PredicatePushIntoMetadataChecker(idOrAttributeColumnNames).process(expression);
+ }
+
+ public PredicatePushIntoMetadataChecker(Set<String>
idOrAttributeColumnNames) {
this.idOrAttributeColumnNames = idOrAttributeColumnNames;
}
@@ -76,7 +80,8 @@ public class PredicatePushIntoIndexScanChecker extends
PredicateVisitor<Boolean,
@Override
protected Boolean visitLogicalExpression(LogicalExpression node, Void
context) {
if (node.getOperator() == LogicalExpression.Operator.AND) {
- throw new IllegalStateException("Shouldn't have AND operator in index
scan expression.");
+ throw new IllegalStateException(
+ "Shouldn't have AND operator in PredicatePushIntoMetadataChecker.");
}
List<Expression> children = node.getTerms();
for (Expression child : children) {
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/LogicalPlanner.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/LogicalPlanner.java
index dfc2bfae5a2..f1ce49f1c14 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/LogicalPlanner.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/LogicalPlanner.java
@@ -28,8 +28,8 @@ import
org.apache.iotdb.db.queryengine.plan.relational.analyzer.Field;
import org.apache.iotdb.db.queryengine.plan.relational.analyzer.RelationType;
import org.apache.iotdb.db.queryengine.plan.relational.metadata.Metadata;
import org.apache.iotdb.db.queryengine.plan.relational.planner.node.OutputNode;
+import
org.apache.iotdb.db.queryengine.plan.relational.planner.optimizations.FilterScanCombine;
import
org.apache.iotdb.db.queryengine.plan.relational.planner.optimizations.IndexScan;
-import
org.apache.iotdb.db.queryengine.plan.relational.planner.optimizations.PredicatePushDown;
import
org.apache.iotdb.db.queryengine.plan.relational.planner.optimizations.PruneUnUsedColumns;
import
org.apache.iotdb.db.queryengine.plan.relational.planner.optimizations.RelationalPlanOptimizer;
import
org.apache.iotdb.db.queryengine.plan.relational.planner.optimizations.RemoveRedundantIdentityProjections;
@@ -79,7 +79,7 @@ public class LogicalPlanner {
Arrays.asList(
new SimplifyExpressions(),
new PruneUnUsedColumns(),
- new PredicatePushDown(),
+ new FilterScanCombine(),
new RemoveRedundantIdentityProjections(),
new IndexScan());
}
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/RelationPlanner.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/RelationPlanner.java
index c09e5d67caa..d39b008a8ca 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/RelationPlanner.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/RelationPlanner.java
@@ -13,7 +13,6 @@
*/
package org.apache.iotdb.db.queryengine.plan.relational.planner;
-import org.apache.iotdb.commons.schema.table.column.TsTableColumnCategory;
import org.apache.iotdb.db.queryengine.common.MPPQueryContext;
import org.apache.iotdb.db.queryengine.common.QueryId;
import org.apache.iotdb.db.queryengine.common.SessionInfo;
@@ -41,7 +40,6 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import java.util.Collection;
-import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -94,12 +92,11 @@ public class RelationPlanner extends
AstVisitor<RelationPlan, Void> {
expansion.getRoot(), expansion.getScope(),
expansion.getFieldMappings());
}
- Map<Symbol, Integer> idAndAttributeIndexMap = new HashMap<>();
Scope scope = analysis.getScope(table);
ImmutableList.Builder<Symbol> outputSymbolsBuilder =
ImmutableList.builder();
ImmutableMap.Builder<Symbol, ColumnSchema> symbolToColumnSchema =
ImmutableMap.builder();
Collection<Field> fields = scope.getRelationType().getAllFields();
- int IDIdx = 0, attributeIdx = 0;
+
for (Field field : fields) {
Symbol symbol = symbolAllocator.newSymbol(field);
outputSymbolsBuilder.add(symbol);
@@ -107,12 +104,6 @@ public class RelationPlanner extends
AstVisitor<RelationPlan, Void> {
symbol,
new ColumnSchema(
field.getName().get(), field.getType(), field.isHidden(),
field.getColumnCategory()));
-
- if (TsTableColumnCategory.ID.equals(field.getColumnCategory())) {
- idAndAttributeIndexMap.put(symbol, IDIdx++);
- } else if
(TsTableColumnCategory.ATTRIBUTE.equals(field.getColumnCategory())) {
- idAndAttributeIndexMap.put(symbol, attributeIdx++);
- }
}
List<Symbol> outputSymbols = outputSymbolsBuilder.build();
@@ -123,7 +114,6 @@ public class RelationPlanner extends
AstVisitor<RelationPlan, Void> {
outputSymbols,
symbolToColumnSchema.build());
- tableScanNode.setIdAndAttributeIndexMap(idAndAttributeIndexMap);
return new RelationPlan(tableScanNode, scope, outputSymbols);
// Collection<Field> fields =
analysis.getMaterializedViewStorageTableFields(node);
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/ir/ExtractCommonPredicatesExpressionRewriter.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/ir/ExtractCommonPredicatesExpressionRewriter.java
index 92a5f96e3e7..3789b793c29 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/ir/ExtractCommonPredicatesExpressionRewriter.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/ir/ExtractCommonPredicatesExpressionRewriter.java
@@ -163,7 +163,7 @@ public final class
ExtractCommonPredicatesExpressionRewriter {
}
private Set<Expression> filterDeterministicPredicates(List<Expression>
predicates) {
- return predicates.stream().filter(expression ->
isDeterministic(expression)).collect(toSet());
+ return
predicates.stream().filter(DeterminismEvaluator::isDeterministic).collect(toSet());
}
private static <T> List<T> removeAll(Collection<T> collection,
Collection<T> elementsToRemove) {
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 6fd46d63678..846a64bcfdf 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
@@ -164,6 +164,13 @@ public class TableScanNode extends SourceNode {
}
ReadWriteIOUtils.write(scanOrder.ordinal(), byteBuffer);
+
+ if (pushDownPredicate != null) {
+ ReadWriteIOUtils.write(true, byteBuffer);
+ Expression.serialize(pushDownPredicate, byteBuffer);
+ } else {
+ ReadWriteIOUtils.write(false, byteBuffer);
+ }
}
@Override
@@ -194,6 +201,13 @@ public class TableScanNode extends SourceNode {
}
ReadWriteIOUtils.write(scanOrder.ordinal(), stream);
+
+ if (pushDownPredicate != null) {
+ ReadWriteIOUtils.write(true, stream);
+ Expression.serialize(pushDownPredicate, stream);
+ } else {
+ ReadWriteIOUtils.write(false, stream);
+ }
}
public static TableScanNode deserialize(ByteBuffer byteBuffer) {
@@ -226,6 +240,12 @@ public class TableScanNode extends SourceNode {
Ordering scanOrder =
Ordering.values()[ReadWriteIOUtils.readInt(byteBuffer)];
+ Expression pushDownPredicate = null;
+ boolean hasPushDownPredicate = ReadWriteIOUtils.readBool(byteBuffer);
+ if (hasPushDownPredicate) {
+ pushDownPredicate = Expression.deserialize(byteBuffer);
+ }
+
PlanNodeId planNodeId = PlanNodeId.deserialize(byteBuffer);
return new TableScanNode(
@@ -236,7 +256,7 @@ public class TableScanNode extends SourceNode {
deviceEntries,
idAndAttributeIndexMap,
scanOrder,
- null);
+ pushDownPredicate);
}
@Override
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/FilterScanCombine.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/FilterScanCombine.java
new file mode 100644
index 00000000000..e02fa012123
--- /dev/null
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/FilterScanCombine.java
@@ -0,0 +1,227 @@
+/*
+ * 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.optimizations;
+
+import org.apache.iotdb.db.queryengine.common.MPPQueryContext;
+import org.apache.iotdb.db.queryengine.common.SessionInfo;
+import org.apache.iotdb.db.queryengine.plan.analyze.IPartitionFetcher;
+import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNode;
+import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanVisitor;
+import
org.apache.iotdb.db.queryengine.plan.planner.plan.node.process.MultiChildProcessNode;
+import
org.apache.iotdb.db.queryengine.plan.planner.plan.node.process.SingleChildProcessNode;
+import org.apache.iotdb.db.queryengine.plan.relational.analyzer.Analysis;
+import
org.apache.iotdb.db.queryengine.plan.relational.analyzer.predicate.PredicateCombineIntoTableScanChecker;
+import
org.apache.iotdb.db.queryengine.plan.relational.analyzer.predicate.PredicatePushIntoMetadataChecker;
+import org.apache.iotdb.db.queryengine.plan.relational.metadata.Metadata;
+import org.apache.iotdb.db.queryengine.plan.relational.planner.Symbol;
+import org.apache.iotdb.db.queryengine.plan.relational.planner.node.FilterNode;
+import
org.apache.iotdb.db.queryengine.plan.relational.planner.node.TableScanNode;
+import org.apache.iotdb.db.queryengine.plan.relational.sql.tree.Expression;
+import org.apache.iotdb.db.queryengine.plan.relational.sql.tree.FunctionCall;
+import
org.apache.iotdb.db.queryengine.plan.relational.sql.tree.LogicalExpression;
+import org.apache.iotdb.db.queryengine.plan.relational.sql.tree.Node;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import static
org.apache.iotdb.commons.schema.table.column.TsTableColumnCategory.MEASUREMENT;
+
+/**
+ * After the optimized rule {@link SimplifyExpressions} finished, predicate
expression in FilterNode
+ * has been transformed to conjunctive normal forms(CNF).
+ *
+ * <p>In this class, we examine each expression in CNFs, determine how to use
it, in metadata query,
+ * or pushed down into ScanOperators, or it can only be used in FilterNode
above with TableScanNode.
+ *
+ * <p>Notice that, when aggregation, multi-table, join are introduced, this
optimization rule need
+ * to be adapted.
+ */
+public class FilterScanCombine implements RelationalPlanOptimizer {
+
+ @Override
+ public PlanNode optimize(
+ PlanNode planNode,
+ Analysis analysis,
+ Metadata metadata,
+ IPartitionFetcher partitionFetcher,
+ SessionInfo sessionInfo,
+ MPPQueryContext queryContext) {
+
+ if (!analysis.hasValueFilter()) {
+ return planNode;
+ }
+
+ return planNode.accept(new Rewriter(), new RewriterContext(queryContext));
+ }
+
+ private static class Rewriter extends PlanVisitor<PlanNode, RewriterContext>
{
+
+ @Override
+ public PlanNode visitPlan(PlanNode node, RewriterContext context) {
+ throw new IllegalArgumentException(
+ String.format("Unexpected plan node: %s in TableModel
PredicatePushDown", node));
+ }
+
+ @Override
+ public PlanNode visitSingleChildProcess(SingleChildProcessNode node,
RewriterContext context) {
+ PlanNode rewrittenChild = node.getChild().accept(this, context);
+ node.setChild(rewrittenChild);
+ return node;
+ }
+
+ @Override
+ public PlanNode visitMultiChildProcess(MultiChildProcessNode node,
RewriterContext context) {
+ List<PlanNode> rewrittenChildren = new ArrayList<>();
+ for (PlanNode child : node.getChildren()) {
+ rewrittenChildren.add(child.accept(this, context));
+ }
+ node.setChildren(rewrittenChildren);
+ return node;
+ }
+
+ @Override
+ public PlanNode visitFilter(FilterNode node, RewriterContext context) {
+ context.filterNode = node;
+
+ if (node.getPredicate() != null) {
+ // when exist diff function, predicate can not be pushed down
+ if (containsDiffFunction(node.getPredicate())) {
+ context.pushDownPredicate = null;
+ return node;
+ }
+
+ context.pushDownPredicate = node.getPredicate();
+ return node.getChild().accept(this, context);
+ } else {
+ throw new IllegalStateException(
+ "Filter node has no predicate, node: " + node.getPlanNodeId());
+ }
+ }
+
+ @Override
+ public PlanNode visitTableScan(TableScanNode node, RewriterContext
context) {
+ // has diff in FilterNode
+ if (context.pushDownPredicate == null) {
+ node.setPushDownPredicate(null);
+ return node;
+ }
+
+ context.queryContext.setTableModelPredicateExpressions(
+ splitConjunctionExpressions(context, node));
+
+ // exist expressions can push down to scan operator
+ if
(!context.queryContext.getTableModelPredicateExpressions().get(1).isEmpty()) {
+ List<Expression> expressions =
+ context.queryContext.getTableModelPredicateExpressions().get(1);
+ node.setPushDownPredicate(
+ expressions.size() == 1
+ ? expressions.get(0)
+ : new LogicalExpression(LogicalExpression.Operator.AND,
expressions));
+ } else {
+ node.setPushDownPredicate(null);
+ }
+
+ // exist expressions can not push down to scan operator
+ if
(!context.queryContext.getTableModelPredicateExpressions().get(2).isEmpty()) {
+ List<Expression> expressions =
+ context.queryContext.getTableModelPredicateExpressions().get(2);
+ return new FilterNode(
+ context.queryContext.getQueryId().genPlanNodeId(),
+ node,
+ expressions.size() == 1
+ ? expressions.get(0)
+ : new LogicalExpression(LogicalExpression.Operator.AND,
expressions));
+ }
+
+ return node;
+ }
+ }
+
+ private static List<List<Expression>> splitConjunctionExpressions(
+ RewriterContext context, TableScanNode node) {
+ Expression predicate = context.pushDownPredicate;
+
+ Set<String> idOrAttributeColumnNames =
+ node.getIdAndAttributeIndexMap().keySet().stream()
+ .map(Symbol::getName)
+ .collect(Collectors.toSet());
+
+ Set<String> measurementColumnNames =
+ node.getAssignments().entrySet().stream()
+ .filter(e -> MEASUREMENT.equals(e.getValue().getColumnCategory()))
+ .map(e -> e.getKey().getName())
+ .collect(Collectors.toSet());
+
+ List<Expression> metadataExpressions = new ArrayList<>();
+ List<Expression> expressionsCanPushDown = new ArrayList<>();
+ List<Expression> expressionsCannotPushDown = new ArrayList<>();
+
+ if (predicate instanceof LogicalExpression
+ && ((LogicalExpression) predicate).getOperator() ==
LogicalExpression.Operator.AND) {
+
+ for (Expression expression : ((LogicalExpression) predicate).getTerms())
{
+ if (PredicatePushIntoMetadataChecker.check(idOrAttributeColumnNames,
expression)) {
+ metadataExpressions.add(expression);
+ } else if
(PredicateCombineIntoTableScanChecker.check(measurementColumnNames,
expression)) {
+ expressionsCanPushDown.add(expression);
+ } else {
+ expressionsCannotPushDown.add(expression);
+ }
+ }
+
+ return Arrays.asList(metadataExpressions, expressionsCanPushDown,
expressionsCannotPushDown);
+ }
+
+ if (PredicatePushIntoMetadataChecker.check(idOrAttributeColumnNames,
predicate)) {
+ metadataExpressions.add(predicate);
+ } else if
(PredicateCombineIntoTableScanChecker.check(measurementColumnNames, predicate))
{
+ expressionsCanPushDown.add(predicate);
+ } else {
+ expressionsCannotPushDown.add(predicate);
+ }
+
+ return Arrays.asList(metadataExpressions, expressionsCanPushDown,
expressionsCannotPushDown);
+ }
+
+ static boolean containsDiffFunction(Expression expression) {
+ if (expression instanceof FunctionCall
+ && "diff".equalsIgnoreCase(((FunctionCall)
expression).getName().toString())) {
+ return true;
+ }
+
+ if (!expression.getChildren().isEmpty()) {
+ for (Node node : expression.getChildren()) {
+ if (containsDiffFunction((Expression) node)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ private static class RewriterContext {
+ Expression pushDownPredicate;
+ MPPQueryContext queryContext;
+ FilterNode filterNode;
+
+ public RewriterContext(MPPQueryContext queryContext) {
+ this.queryContext = queryContext;
+ }
+ }
+}
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/IndexScan.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/IndexScan.java
index fd3fe00bd9f..e2f4a1f3be5 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/IndexScan.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/IndexScan.java
@@ -27,7 +27,6 @@ import
org.apache.iotdb.db.queryengine.plan.analyze.IPartitionFetcher;
import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNode;
import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanVisitor;
import org.apache.iotdb.db.queryengine.plan.relational.analyzer.Analysis;
-import
org.apache.iotdb.db.queryengine.plan.relational.analyzer.predicate.PredicatePushIntoIndexScanChecker;
import org.apache.iotdb.db.queryengine.plan.relational.metadata.DeviceEntry;
import org.apache.iotdb.db.queryengine.plan.relational.metadata.Metadata;
import
org.apache.iotdb.db.queryengine.plan.relational.metadata.QualifiedObjectName;
@@ -35,7 +34,6 @@ import
org.apache.iotdb.db.queryengine.plan.relational.planner.Symbol;
import org.apache.iotdb.db.queryengine.plan.relational.planner.node.FilterNode;
import
org.apache.iotdb.db.queryengine.plan.relational.planner.node.TableScanNode;
import org.apache.iotdb.db.queryengine.plan.relational.sql.tree.Expression;
-import
org.apache.iotdb.db.queryengine.plan.relational.sql.tree.LogicalExpression;
import org.apache.tsfile.file.metadata.StringArrayDeviceID;
import org.apache.tsfile.read.filter.basic.Filter;
@@ -85,26 +83,37 @@ public class IndexScan implements RelationalPlanOptimizer {
@Override
public PlanNode visitFilter(FilterNode node, RewriterContext context) {
context.setPredicate(node.getPredicate());
+ context.setFilterNode(node);
node.getChild().accept(this, context);
return node;
}
@Override
public PlanNode visitTableScan(TableScanNode node, RewriterContext
context) {
- List<String> attributeColumns =
- node.getAssignments().entrySet().stream()
- .filter(e -> e.getValue().getColumnCategory().equals(ATTRIBUTE))
- .map(e -> e.getKey().getName())
- .collect(Collectors.toList());
- List<Expression> conjExpressions =
getConjunctionExpressions(context.getPredicate(), node);
+ // only when exist diff predicate in FilterNode, context.predicate will
not equal null
+ if (context.predicate == null) {
+ context.predicate = node.getPushDownPredicate();
+ }
+
+ List<Expression> metadataExpressions =
+ context.queryContext.getTableModelPredicateExpressions() == null
+ ||
context.queryContext.getTableModelPredicateExpressions().get(0).isEmpty()
+ ? Collections.emptyList()
+ :
context.queryContext.getTableModelPredicateExpressions().get(0);
String dbName = context.getSessionInfo().getDatabaseName().get();
+ List<String> attributeColumns =
+ node.getOutputSymbols().stream()
+ .filter(
+ symbol ->
ATTRIBUTE.equals(node.getAssignments().get(symbol).getColumnCategory()))
+ .map(Symbol::getName)
+ .collect(Collectors.toList());
List<DeviceEntry> deviceEntries =
context
.getMetadata()
.indexScan(
new QualifiedObjectName(dbName,
node.getQualifiedTableName()),
- conjExpressions,
+ metadataExpressions,
attributeColumns);
node.setDeviceEntries(deviceEntries);
@@ -151,37 +160,6 @@ public class IndexScan implements RelationalPlanOptimizer {
}
}
- private static List<Expression> getConjunctionExpressions(
- Expression predicate, TableScanNode node) {
- if (predicate == null) {
- return Collections.emptyList();
- }
-
- Set<String> idOrAttributeColumnNames =
- node.getIdAndAttributeIndexMap().keySet().stream()
- .map(Symbol::getName)
- .collect(Collectors.toSet());
- if (predicate instanceof LogicalExpression
- && ((LogicalExpression) predicate).getOperator() ==
LogicalExpression.Operator.AND) {
- List<Expression> resultExpressions = new ArrayList<>();
- for (Expression subExpression : ((LogicalExpression)
predicate).getTerms()) {
- if (Boolean.TRUE.equals(
- new PredicatePushIntoIndexScanChecker(idOrAttributeColumnNames)
- .process(subExpression))) {
- resultExpressions.add(subExpression);
- }
- }
- return resultExpressions;
- }
-
- if (Boolean.FALSE.equals(
- new
PredicatePushIntoIndexScanChecker(idOrAttributeColumnNames).process(predicate)))
{
- return Collections.emptyList();
- } else {
- return Collections.singletonList(predicate);
- }
- }
-
private static DataPartition fetchDataPartitionByDevices(
Set<String> deviceSet,
String database,
@@ -219,6 +197,7 @@ public class IndexScan implements RelationalPlanOptimizer {
private final Analysis analysis;
private final IPartitionFetcher partitionFetcher;
private final MPPQueryContext queryContext;
+ private FilterNode filterNode;
RewriterContext(
Expression predicate,
@@ -266,5 +245,13 @@ public class IndexScan implements RelationalPlanOptimizer {
public MPPQueryContext getQueryContext() {
return queryContext;
}
+
+ public FilterNode getFilterNode() {
+ return filterNode;
+ }
+
+ public void setFilterNode(FilterNode filterNode) {
+ this.filterNode = filterNode;
+ }
}
}
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/PredicatePushDown.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/PredicatePushDown.java
deleted file mode 100644
index ae05611ce08..00000000000
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/PredicatePushDown.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * 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.optimizations;
-
-import org.apache.iotdb.db.queryengine.common.MPPQueryContext;
-import org.apache.iotdb.db.queryengine.common.SessionInfo;
-import org.apache.iotdb.db.queryengine.plan.analyze.IPartitionFetcher;
-import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNode;
-import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanVisitor;
-import
org.apache.iotdb.db.queryengine.plan.planner.plan.node.process.MultiChildProcessNode;
-import
org.apache.iotdb.db.queryengine.plan.planner.plan.node.process.SingleChildProcessNode;
-import org.apache.iotdb.db.queryengine.plan.relational.analyzer.Analysis;
-import org.apache.iotdb.db.queryengine.plan.relational.metadata.Metadata;
-import org.apache.iotdb.db.queryengine.plan.relational.planner.node.FilterNode;
-import
org.apache.iotdb.db.queryengine.plan.relational.planner.node.TableScanNode;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.tree.Expression;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.tree.FunctionCall;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.tree.Node;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/** Push down predicate to TableScanNode as possible. */
-public class PredicatePushDown implements RelationalPlanOptimizer {
-
- @Override
- public PlanNode optimize(
- PlanNode planNode,
- Analysis analysis,
- Metadata metadata,
- IPartitionFetcher partitionFetcher,
- SessionInfo sessionInfo,
- MPPQueryContext context) {
-
- if (!analysis.hasValueFilter()) {
- return planNode;
- }
-
- return planNode.accept(new Rewriter(), new RewriterContext());
- }
-
- private static class Rewriter extends PlanVisitor<PlanNode, RewriterContext>
{
-
- @Override
- public PlanNode visitPlan(PlanNode node, RewriterContext context) {
- throw new IllegalArgumentException(
- String.format("Unexpected plan node: %s in TableModel
PredicatePushDown", node));
- }
-
- @Override
- public PlanNode visitSingleChildProcess(SingleChildProcessNode node,
RewriterContext context) {
- PlanNode rewrittenChild = node.getChild().accept(this, context);
- node.setChild(rewrittenChild);
- return node;
- }
-
- @Override
- public PlanNode visitMultiChildProcess(MultiChildProcessNode node,
RewriterContext context) {
- List<PlanNode> rewrittenChildren = new ArrayList<>();
- for (PlanNode child : node.getChildren()) {
- rewrittenChildren.add(child.accept(this, context));
- }
- node.setChildren(rewrittenChildren);
- return node;
- }
-
- @Override
- public PlanNode visitFilter(FilterNode node, RewriterContext context) {
- if (node.getPredicate() != null) {
- // when exist diff function, predicate can not be pushed down
- if (containsDiffFunction(node.getPredicate())) {
- return node;
- }
-
- context.pushDownPredicate = node.getPredicate();
- node.getChild().accept(this, context);
-
- // remove FilterNode after push down
- return node.getChild();
- }
-
- node.getChild().accept(this, context);
- return node;
- }
-
- @Override
- public PlanNode visitTableScan(TableScanNode node, RewriterContext
context) {
- node.setPushDownPredicate(context.pushDownPredicate);
- return node;
- }
- }
-
- static boolean containsDiffFunction(Expression expression) {
- if (expression instanceof FunctionCall
- && "diff".equalsIgnoreCase(((FunctionCall)
expression).getName().toString())) {
- return true;
- }
-
- if (!expression.getChildren().isEmpty()) {
- for (Node node : expression.getChildren()) {
- if (containsDiffFunction((Expression) node)) {
- return true;
- }
- }
- }
-
- return false;
- }
-
- private static class RewriterContext {
- Expression pushDownPredicate;
- }
-}
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/PruneUnUsedColumns.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/PruneUnUsedColumns.java
index d6310c37dc0..c3b0a12c01b 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/PruneUnUsedColumns.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/PruneUnUsedColumns.java
@@ -14,6 +14,7 @@
package org.apache.iotdb.db.queryengine.plan.relational.planner.optimizations;
+import org.apache.iotdb.commons.schema.table.column.TsTableColumnCategory;
import org.apache.iotdb.db.queryengine.common.MPPQueryContext;
import org.apache.iotdb.db.queryengine.common.SessionInfo;
import org.apache.iotdb.db.queryengine.plan.analyze.IPartitionFetcher;
@@ -119,6 +120,19 @@ public class PruneUnUsedColumns implements
RelationalPlanOptimizer {
}
node.setOutputSymbols(newOutputSymbols);
node.setAssignments(newAssignments);
+
+ int IDIdx = 0, attributeIdx = 0;
+ Map<Symbol, Integer> idAndAttributeIndexMap = new
HashMap<>(node.getAssignments().size());
+ for (Symbol symbol : node.getOutputSymbols()) {
+ ColumnSchema columnSchema = node.getAssignments().get(symbol);
+ if (TsTableColumnCategory.ID.equals(columnSchema.getColumnCategory()))
{
+ idAndAttributeIndexMap.put(symbol, IDIdx++);
+ } else if
(TsTableColumnCategory.ATTRIBUTE.equals(columnSchema.getColumnCategory())) {
+ idAndAttributeIndexMap.put(symbol, attributeIdx++);
+ }
+ }
+ node.setIdAndAttributeIndexMap(idAndAttributeIndexMap);
+
return node;
}
}
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 a2a3b56fc8d..681205bb499 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
@@ -51,6 +51,7 @@ import
org.apache.iotdb.db.queryengine.plan.relational.planner.node.ProjectNode;
import
org.apache.iotdb.db.queryengine.plan.relational.planner.node.TableScanNode;
import org.apache.iotdb.db.queryengine.plan.relational.security.AccessControl;
import org.apache.iotdb.db.queryengine.plan.relational.sql.parser.SqlParser;
+import
org.apache.iotdb.db.queryengine.plan.relational.sql.tree.LogicalExpression;
import org.apache.iotdb.db.queryengine.plan.relational.sql.tree.Statement;
import org.apache.iotdb.mpp.rpc.thrift.TRegionRouteReq;
@@ -300,7 +301,7 @@ public class AnalyzerTest {
context, metadata, sessionInfo, getFakePartitionFetcher(),
WarningCollector.NOOP);
logicalQueryPlan = logicalPlanner.plan(actualAnalysis);
rootNode = logicalQueryPlan.getRootNode();
- PlanNode tableScanNode =
rootNode.getChildren().get(0).getChildren().get(0);
+ tableScanNode = (TableScanNode)
rootNode.getChildren().get(0).getChildren().get(0);
assertEquals(
Arrays.asList("time", "tag1", "attr1", "s1"),
tableScanNode.getOutputColumnNames());
@@ -315,7 +316,7 @@ public class AnalyzerTest {
context, metadata, sessionInfo, getFakePartitionFetcher(),
WarningCollector.NOOP);
logicalQueryPlan = logicalPlanner.plan(actualAnalysis);
rootNode = logicalQueryPlan.getRootNode();
- tableScanNode = rootNode.getChildren().get(0).getChildren().get(0);
+ tableScanNode = (TableScanNode)
rootNode.getChildren().get(0).getChildren().get(0);
assertEquals(
Arrays.asList("time", "tag1", "tag2", "attr1", "s1", "s2"),
tableScanNode.getOutputColumnNames());
@@ -330,10 +331,26 @@ public class AnalyzerTest {
context, metadata, sessionInfo, getFakePartitionFetcher(),
WarningCollector.NOOP)
.plan(actualAnalysis);
rootNode = logicalQueryPlan.getRootNode();
- tableScanNode = rootNode.getChildren().get(0).getChildren().get(0);
+ assertTrue(rootNode.getChildren().get(0).getChildren().get(0) instanceof
FilterNode);
+ tableScanNode =
+ (TableScanNode)
rootNode.getChildren().get(0).getChildren().get(0).getChildren().get(0);
assertEquals(
Arrays.asList("time", "tag1", "attr2", "s1", "s2", "s3"),
tableScanNode.getOutputColumnNames());
+
+ // 4. project with not all attributes, to test the rightness of
PruneUnUsedColumns
+ sql = "SELECT tag2, attr2, s2 FROM table1";
+ actualAnalysis = analyzeSQL(sql, metadata);
+ context = new MPPQueryContext(sql, queryId, sessionInfo, null, null);
+ logicalQueryPlan =
+ new LogicalPlanner(
+ context, metadata, sessionInfo, getFakePartitionFetcher(),
WarningCollector.NOOP)
+ .plan(actualAnalysis);
+ rootNode = logicalQueryPlan.getRootNode();
+ tableScanNode = (TableScanNode)
rootNode.getChildren().get(0).getChildren().get(0);
+ assertEquals(
+ Arrays.asList("time", "tag2", "attr2", "s2"),
tableScanNode.getOutputColumnNames());
+ assertEquals(2, tableScanNode.getIdAndAttributeIndexMap().size());
}
@Test
@@ -434,6 +451,36 @@ public class AnalyzerTest {
rootNode = logicalQueryPlan.getRootNode();
}
+ @Test
+ public void predicatePushDownTest() throws IoTDBException {
+ // `is null expression`, `not expression` cannot be pushed down into
TableScanOperator
+ sql =
+ "SELECT *, s1/2, s2+1 FROM table1 WHERE tag1 in ('A', 'B') and tag2 =
'C' "
+ + "and s2 iS NUll and S1 = 6 and s3 < 8.0 and tAG1 LIKE '%m'";
+ context = new MPPQueryContext(sql, queryId, sessionInfo, null, null);
+ actualAnalysis = analyzeSQL(sql, metadata);
+ logicalQueryPlan =
+ new LogicalPlanner(
+ context, metadata, sessionInfo, getFakePartitionFetcher(),
WarningCollector.NOOP)
+ .plan(actualAnalysis);
+ rootNode = logicalQueryPlan.getRootNode();
+ assertTrue(rootNode instanceof OutputNode);
+ assertTrue(rootNode.getChildren().get(0) instanceof ProjectNode);
+ assertTrue(rootNode.getChildren().get(0).getChildren().get(0) instanceof
FilterNode);
+ FilterNode filterNode = (FilterNode)
rootNode.getChildren().get(0).getChildren().get(0);
+ assertTrue(filterNode.getPredicate() instanceof LogicalExpression);
+ assertEquals(3, ((LogicalExpression)
filterNode.getPredicate()).getTerms().size());
+ assertTrue(
+ rootNode.getChildren().get(0).getChildren().get(0).getChildren().get(0)
+ instanceof TableScanNode);
+ tableScanNode =
+ (TableScanNode)
rootNode.getChildren().get(0).getChildren().get(0).getChildren().get(0);
+ assertTrue(
+ tableScanNode.getPushDownPredicate() != null
+ && tableScanNode.getPushDownPredicate() instanceof
LogicalExpression);
+ assertEquals(2, ((LogicalExpression)
tableScanNode.getPushDownPredicate()).getTerms().size());
+ }
+
public static Analysis analyzeSQL(String sql, Metadata metadata) {
try {
SqlParser sqlParser = new SqlParser();