This is an automated email from the ASF dual-hosted git repository.

jackietien pushed a commit to branch ty/object_type
in repository https://gitbox.apache.org/repos/asf/iotdb.git

commit 590f3b03d87fa723f581f7593a7ccf4f1a927520
Author: Weihao Li <[email protected]>
AuthorDate: Mon Dec 15 18:05:43 2025 +0800

    Add state predicate push down for system table current_queries (#16904)
    
    (cherry picked from commit 2710cb3db653d8c674495647bd34cd5afdbc3544)
---
 .../informationschema/IoTDBCurrentQueriesIT.java   |   9 +-
 .../InformationSchemaContentSupplierFactory.java   |  30 ++++++-
 .../iotdb/db/queryengine/plan/Coordinator.java     |  33 +++++++
 .../plan/planner/TableOperatorGenerator.java       |   1 +
 .../optimizations/PushPredicateIntoTableScan.java  | 100 +++++++++++++++++++++
 .../planner/assertions/ColumnReference.java        |  10 +--
 .../planner/assertions/PlanMatchPattern.java       |  20 +++--
 .../informationschema/CurrentQueriesTest.java      |  77 ++++++++++++++++
 8 files changed, 259 insertions(+), 21 deletions(-)

diff --git 
a/integration-test/src/test/java/org/apache/iotdb/relational/it/query/recent/informationschema/IoTDBCurrentQueriesIT.java
 
b/integration-test/src/test/java/org/apache/iotdb/relational/it/query/recent/informationschema/IoTDBCurrentQueriesIT.java
index a68bd92b50b..4f9c8cab794 100644
--- 
a/integration-test/src/test/java/org/apache/iotdb/relational/it/query/recent/informationschema/IoTDBCurrentQueriesIT.java
+++ 
b/integration-test/src/test/java/org/apache/iotdb/relational/it/query/recent/informationschema/IoTDBCurrentQueriesIT.java
@@ -83,7 +83,7 @@ public class IoTDBCurrentQueriesIT {
       statement.execute("set configuration \"query_cost_stat_window\"='1'");
 
       // 1. query current_queries table
-      String sql = "SELECT * FROM current_queries";
+      String sql = "SELECT * FROM current_queries WHERE state='RUNNING'";
       ResultSet resultSet = statement.executeQuery(sql);
       ResultSetMetaData metaData = resultSet.getMetaData();
       Assert.assertEquals(CURRENT_QUERIES_COLUMN_NUM, 
metaData.getColumnCount());
@@ -116,7 +116,7 @@ public class IoTDBCurrentQueriesIT {
       Assert.assertEquals(61, rowNum);
 
       // 3. requery current_queries table
-      sql = "SELECT * FROM current_queries";
+      sql = "SELECT * FROM current_queries WHERE state='FINISHED'";
       resultSet = statement.executeQuery(sql);
       metaData = resultSet.getMetaData();
       Assert.assertEquals(CURRENT_QUERIES_COLUMN_NUM, 
metaData.getColumnCount());
@@ -128,13 +128,14 @@ public class IoTDBCurrentQueriesIT {
         }
         rowNum++;
       }
-      // three rows in the result, 2 FINISHED and 1 RUNNING
-      Assert.assertEquals(3, rowNum);
+      // two rows in the result, 2 FINISHED
+      Assert.assertEquals(2, rowNum);
       Assert.assertEquals(2, finishedQueries);
       resultSet.close();
 
       // 4. test the expired QueryInfo was evicted
       Thread.sleep(61_001);
+      sql = "SELECT * FROM current_queries";
       resultSet = statement.executeQuery(sql);
       rowNum = 0;
       while (resultSet.next()) {
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/relational/InformationSchemaContentSupplierFactory.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/relational/InformationSchemaContentSupplierFactory.java
index 76d84c741de..fe0727ec3f2 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/relational/InformationSchemaContentSupplierFactory.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/relational/InformationSchemaContentSupplierFactory.java
@@ -69,11 +69,15 @@ import org.apache.iotdb.db.protocol.session.IClientSession;
 import org.apache.iotdb.db.protocol.session.SessionManager;
 import org.apache.iotdb.db.queryengine.common.ConnectionInfo;
 import org.apache.iotdb.db.queryengine.common.QueryId;
+import org.apache.iotdb.db.queryengine.execution.QueryState;
 import org.apache.iotdb.db.queryengine.plan.Coordinator;
 import org.apache.iotdb.db.queryengine.plan.execution.IQueryExecution;
 import 
org.apache.iotdb.db.queryengine.plan.execution.config.metadata.relational.ShowCreateViewTask;
 import 
org.apache.iotdb.db.queryengine.plan.relational.function.TableBuiltinTableFunction;
 import org.apache.iotdb.db.queryengine.plan.relational.security.AccessControl;
+import 
org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ComparisonExpression;
+import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Expression;
+import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.StringLiteral;
 import 
org.apache.iotdb.db.queryengine.plan.relational.sql.util.ReservedIdentifiers;
 import org.apache.iotdb.db.relational.grammar.sql.RelationalSqlKeywords;
 import org.apache.iotdb.db.schemaengine.table.InformationSchemaUtils;
@@ -130,7 +134,10 @@ public class InformationSchemaContentSupplierFactory {
   private InformationSchemaContentSupplierFactory() {}
 
   public static Iterator<TsBlock> getSupplier(
-      final String tableName, final List<TSDataType> dataTypes, final 
UserEntity userEntity) {
+      final String tableName,
+      final List<TSDataType> dataTypes,
+      Expression predicate,
+      final UserEntity userEntity) {
     try {
       switch (tableName) {
         case InformationSchema.QUERIES:
@@ -168,7 +175,7 @@ public class InformationSchemaContentSupplierFactory {
         case InformationSchema.CONNECTIONS:
           return new ConnectionsSupplier(dataTypes, userEntity);
         case InformationSchema.CURRENT_QUERIES:
-          return new CurrentQueriesSupplier(dataTypes, userEntity);
+          return new CurrentQueriesSupplier(dataTypes, predicate, userEntity);
         case InformationSchema.QUERIES_COSTS_HISTOGRAM:
           return new QueriesCostsHistogramSupplier(dataTypes, userEntity);
         default:
@@ -1188,9 +1195,24 @@ public class InformationSchemaContentSupplierFactory {
     private int nextConsumedIndex;
     private List<Coordinator.StatedQueriesInfo> queriesInfo;
 
-    private CurrentQueriesSupplier(final List<TSDataType> dataTypes, final 
UserEntity userEntity) {
+    private CurrentQueriesSupplier(
+        final List<TSDataType> dataTypes, Expression predicate, final 
UserEntity userEntity) {
       super(dataTypes);
-      queriesInfo = Coordinator.getInstance().getCurrentQueriesInfo();
+
+      if (predicate == null) {
+        queriesInfo = Coordinator.getInstance().getCurrentQueriesInfo();
+      } else if (QueryState.RUNNING
+          .toString()
+          .equals(((StringLiteral) ((ComparisonExpression) 
predicate).getRight()).getValue())) {
+        queriesInfo = Coordinator.getInstance().getRunningQueriesInfos();
+      } else if (QueryState.FINISHED
+          .toString()
+          .equals(((StringLiteral) ((ComparisonExpression) 
predicate).getRight()).getValue())) {
+        queriesInfo = Coordinator.getInstance().getFinishedQueriesInfos();
+      } else {
+        queriesInfo = Collections.emptyList();
+      }
+
       try {
         accessControl.checkUserGlobalSysPrivilege(userEntity);
       } catch (final AccessDeniedException e) {
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/Coordinator.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/Coordinator.java
index 78cdee720da..57e3d071074 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/Coordinator.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/Coordinator.java
@@ -865,6 +865,39 @@ public class Coordinator {
     }
   }
 
+  public List<StatedQueriesInfo> getRunningQueriesInfos() {
+    long currentTime = System.currentTimeMillis();
+    return getAllQueryExecutions().stream()
+        .map(
+            queryExecution ->
+                new StatedQueriesInfo(
+                    QueryState.RUNNING,
+                    queryExecution.getQueryId(),
+                    queryExecution.getStartExecutionTime(),
+                    DEFAULT_END_TIME,
+                    (currentTime - queryExecution.getStartExecutionTime()) / 
1000,
+                    queryExecution.getExecuteSQL().orElse("UNKNOWN"),
+                    queryExecution.getUser(),
+                    queryExecution.getClientHostname()))
+        .collect(Collectors.toList());
+  }
+
+  public List<StatedQueriesInfo> getFinishedQueriesInfos() {
+    long currentTime = System.currentTimeMillis();
+    List<StatedQueriesInfo> result = new ArrayList<>();
+    Iterator<QueryInfo> historyQueriesIterator = currentQueriesInfo.iterator();
+    long needRecordTime = currentTime - CONFIG.getQueryCostStatWindow() * 60 * 
1_000L;
+    while (historyQueriesIterator.hasNext()) {
+      QueryInfo queryInfo = historyQueriesIterator.next();
+      if (queryInfo.endTime < needRecordTime) {
+        // out of time window, ignore it
+      } else {
+        result.add(new StatedQueriesInfo(QueryState.FINISHED, queryInfo));
+      }
+    }
+    return result;
+  }
+
   public List<StatedQueriesInfo> getCurrentQueriesInfo() {
     List<IQueryExecution> runningQueries = getAllQueryExecutions();
     Set<String> runningQueryIdSet =
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/TableOperatorGenerator.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/TableOperatorGenerator.java
index c29ceaff04f..68036f9d514 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/TableOperatorGenerator.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/TableOperatorGenerator.java
@@ -1296,6 +1296,7 @@ public class TableOperatorGenerator extends 
PlanVisitor<Operator, LocalExecution
         getSupplier(
             node.getQualifiedObjectName().getObjectName(),
             dataTypes,
+            node.getPushDownPredicate(),
             context
                 .getDriverContext()
                 .getFragmentInstanceContext()
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/PushPredicateIntoTableScan.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/PushPredicateIntoTableScan.java
index fab09a2e3f5..55905f67682 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/PushPredicateIntoTableScan.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/PushPredicateIntoTableScan.java
@@ -56,6 +56,7 @@ import 
org.apache.iotdb.db.queryengine.plan.relational.planner.node.AggregationN
 import 
org.apache.iotdb.db.queryengine.plan.relational.planner.node.AssignUniqueId;
 import 
org.apache.iotdb.db.queryengine.plan.relational.planner.node.DeviceTableScanNode;
 import org.apache.iotdb.db.queryengine.plan.relational.planner.node.FilterNode;
+import 
org.apache.iotdb.db.queryengine.plan.relational.planner.node.InformationSchemaTableScanNode;
 import org.apache.iotdb.db.queryengine.plan.relational.planner.node.JoinNode;
 import 
org.apache.iotdb.db.queryengine.plan.relational.planner.node.ProjectNode;
 import 
org.apache.iotdb.db.queryengine.plan.relational.planner.node.SemiJoinNode;
@@ -68,6 +69,7 @@ import 
org.apache.iotdb.db.queryengine.plan.relational.sql.ast.FunctionCall;
 import 
org.apache.iotdb.db.queryengine.plan.relational.sql.ast.LogicalExpression;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Node;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.NullLiteral;
+import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.StringLiteral;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.SymbolReference;
 import org.apache.iotdb.db.utils.TimestampPrecisionUtils;
 
@@ -99,6 +101,8 @@ import static 
com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkState;
 import static com.google.common.collect.ImmutableMap.toImmutableMap;
 import static java.util.Objects.requireNonNull;
+import static 
org.apache.iotdb.commons.schema.column.ColumnHeaderConstant.STATE_TABLE_MODEL;
+import static 
org.apache.iotdb.commons.schema.table.InformationSchema.CURRENT_QUERIES;
 import static 
org.apache.iotdb.commons.schema.table.column.TsTableColumnCategory.ATTRIBUTE;
 import static 
org.apache.iotdb.commons.schema.table.column.TsTableColumnCategory.FIELD;
 import static 
org.apache.iotdb.commons.schema.table.column.TsTableColumnCategory.TIME;
@@ -440,6 +444,102 @@ public class PushPredicateIntoTableScan implements 
PlanOptimizer {
       return output;
     }
 
+    @Override
+    public PlanNode visitInformationSchemaTableScan(
+        InformationSchemaTableScanNode node, RewriteContext context) {
+      // no predicate or table is not current_queries, just return dierectly
+      if (TRUE_LITERAL.equals(context.inheritedPredicate)) {
+        return node;
+      }
+
+      // push-down for CURRENT_QUERIES
+      if 
(CURRENT_QUERIES.equals(node.getQualifiedObjectName().getObjectName())) {
+        SplitExpression splitExpression = 
splitCurrentQueriesPredicate(context.inheritedPredicate);
+        // exist expressions can push down to scan operator
+        if (!splitExpression.getExpressionsCanPushDown().isEmpty()) {
+          List<Expression> expressions = 
splitExpression.getExpressionsCanPushDown();
+          checkState(expressions.size() == 1, "Unexpected number of 
expressions in table scan");
+          node.setPushDownPredicate(expressions.get(0));
+        }
+
+        // exist expressions cannot push down
+        if (!splitExpression.getExpressionsCannotPushDown().isEmpty()) {
+          List<Expression> expressions = 
splitExpression.getExpressionsCannotPushDown();
+          return new FilterNode(
+              queryId.genPlanNodeId(),
+              node,
+              expressions.size() == 1
+                  ? expressions.get(0)
+                  : new LogicalExpression(LogicalExpression.Operator.AND, 
expressions));
+        }
+        return node;
+      }
+
+      FilterNode filterNode =
+          new FilterNode(queryId.genPlanNodeId(), node, 
context.inheritedPredicate);
+      context.inheritedPredicate = TRUE_LITERAL;
+      return filterNode;
+    }
+
+    private SplitExpression splitCurrentQueriesPredicate(Expression predicate) 
{
+      List<Expression> expressionsCanPushDown = new ArrayList<>();
+      List<Expression> expressionsCannotPushDown = new ArrayList<>();
+
+      if (predicate instanceof LogicalExpression
+          && ((LogicalExpression) predicate).getOperator() == 
LogicalExpression.Operator.AND) {
+
+        // predicate like state = 'xxx' can be push down
+        // Note: the optimizer CanonicalizeExpressionRewriter will ensure the 
predicate like 'xxx' =
+        // state will be canonicalized to state = 'xxx'
+        boolean hasExpressionPushDown = false;
+        for (Expression expression : ((LogicalExpression) 
predicate).getTerms()) {
+          if (isStateComparedWithConstant(expression) && 
!hasExpressionPushDown) {
+            // if there are more than one state = 'xxx' terms, only add first 
to push-down candidate
+            expressionsCanPushDown.add(expression);
+            hasExpressionPushDown = true;
+          } else {
+            expressionsCannotPushDown.add(expression);
+          }
+        }
+
+        return new SplitExpression(
+            Collections.emptyList(), expressionsCanPushDown, 
expressionsCannotPushDown, null);
+      }
+
+      if (isStateComparedWithConstant(predicate)) {
+        expressionsCanPushDown.add(predicate);
+      } else {
+        expressionsCannotPushDown.add(predicate);
+      }
+
+      return new SplitExpression(
+          Collections.emptyList(), expressionsCanPushDown, 
expressionsCannotPushDown, null);
+    }
+
+    private boolean isStateComparedWithConstant(Expression expression) {
+      if (!(expression instanceof ComparisonExpression)) {
+        return false;
+      }
+
+      ComparisonExpression comparisonExpression = (ComparisonExpression) 
expression;
+
+      if (ComparisonExpression.Operator.EQUAL != 
comparisonExpression.getOperator()) {
+        return false;
+      }
+
+      if (!(comparisonExpression.getLeft() instanceof SymbolReference)
+          || !STATE_TABLE_MODEL.equals(
+              ((SymbolReference) comparisonExpression.getLeft()).getName())) {
+        return false;
+      }
+
+      if (!(comparisonExpression.getRight() instanceof StringLiteral)) {
+        return false;
+      }
+
+      return true;
+    }
+
     @Override
     public PlanNode visitDeviceTableScan(
         DeviceTableScanNode tableScanNode, RewriteContext context) {
diff --git 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/planner/assertions/ColumnReference.java
 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/planner/assertions/ColumnReference.java
index 6dc2e6d9f96..a93176c19a8 100644
--- 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/planner/assertions/ColumnReference.java
+++ 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/planner/assertions/ColumnReference.java
@@ -25,7 +25,7 @@ import 
org.apache.iotdb.db.queryengine.plan.relational.metadata.ColumnSchema;
 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.AggregationTableScanNode;
-import 
org.apache.iotdb.db.queryengine.plan.relational.planner.node.DeviceTableScanNode;
+import 
org.apache.iotdb.db.queryengine.plan.relational.planner.node.TableScanNode;
 
 import java.util.Map;
 import java.util.Optional;
@@ -49,10 +49,10 @@ public class ColumnReference implements RvalueMatcher {
     String actualTableName;
     Map<Symbol, ColumnSchema> assignments;
 
-    if (node instanceof DeviceTableScanNode) {
-      DeviceTableScanNode deviceTableScanNode = (DeviceTableScanNode) node;
-      actualTableName = 
deviceTableScanNode.getQualifiedObjectName().toString();
-      assignments = deviceTableScanNode.getAssignments();
+    if (node instanceof TableScanNode) {
+      TableScanNode tableScanNode = (TableScanNode) node;
+      actualTableName = tableScanNode.getQualifiedObjectName().toString();
+      assignments = tableScanNode.getAssignments();
     }
     /*else if (node instanceof IndexSourceNode indexSourceNode) {
         tableHandle = indexSourceNode.getTableHandle();
diff --git 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/planner/assertions/PlanMatchPattern.java
 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/planner/assertions/PlanMatchPattern.java
index 9146f46eeca..3ec60536aec 100644
--- 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/planner/assertions/PlanMatchPattern.java
+++ 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/planner/assertions/PlanMatchPattern.java
@@ -149,14 +149,18 @@ public final class PlanMatchPattern {
 
   public static PlanMatchPattern infoSchemaTableScan(
       String expectedTableName, Optional<Integer> dataNodeId, List<String> 
outputSymbols) {
-    return node(InformationSchemaTableScanNode.class)
-        .with(
-            new InformationSchemaTableScanMatcher(
-                expectedTableName,
-                Optional.empty(),
-                outputSymbols,
-                Collections.emptySet(),
-                dataNodeId));
+    PlanMatchPattern pattern =
+        node(InformationSchemaTableScanNode.class)
+            .with(
+                new InformationSchemaTableScanMatcher(
+                    expectedTableName,
+                    Optional.empty(),
+                    outputSymbols,
+                    Collections.emptySet(),
+                    dataNodeId));
+    outputSymbols.forEach(
+        symbol -> pattern.withAlias(symbol, new 
ColumnReference(expectedTableName, symbol)));
+    return pattern;
   }
 
   public static PlanMatchPattern treeDeviceViewTableScan(
diff --git 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/planner/informationschema/CurrentQueriesTest.java
 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/planner/informationschema/CurrentQueriesTest.java
index 1e3163321ec..c2f4eb68399 100644
--- 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/planner/informationschema/CurrentQueriesTest.java
+++ 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/planner/informationschema/CurrentQueriesTest.java
@@ -20,6 +20,9 @@ package 
org.apache.iotdb.db.queryengine.plan.relational.planner.informationschem
 
 import org.apache.iotdb.db.queryengine.plan.planner.plan.LogicalQueryPlan;
 import org.apache.iotdb.db.queryengine.plan.relational.planner.PlanTester;
+import 
org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ComparisonExpression;
+import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.StringLiteral;
+import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.SymbolReference;
 
 import com.google.common.collect.ImmutableList;
 import org.junit.Test;
@@ -40,8 +43,10 @@ import static 
org.apache.iotdb.commons.schema.column.ColumnHeaderConstant.USER_T
 import static 
org.apache.iotdb.db.queryengine.plan.relational.planner.assertions.PlanAssert.assertPlan;
 import static 
org.apache.iotdb.db.queryengine.plan.relational.planner.assertions.PlanMatchPattern.collect;
 import static 
org.apache.iotdb.db.queryengine.plan.relational.planner.assertions.PlanMatchPattern.exchange;
+import static 
org.apache.iotdb.db.queryengine.plan.relational.planner.assertions.PlanMatchPattern.filter;
 import static 
org.apache.iotdb.db.queryengine.plan.relational.planner.assertions.PlanMatchPattern.infoSchemaTableScan;
 import static 
org.apache.iotdb.db.queryengine.plan.relational.planner.assertions.PlanMatchPattern.output;
+import static 
org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ComparisonExpression.Operator.EQUAL;
 
 public class CurrentQueriesTest {
   private final PlanTester planTester = new PlanTester();
@@ -80,6 +85,78 @@ public class CurrentQueriesTest {
         infoSchemaTableScan("information_schema.current_queries", 
Optional.of(2)));
   }
 
+  @Test
+  public void testCurrentQueriesFilterPushDown() {
+    // Normal case
+    LogicalQueryPlan logicalQueryPlan =
+        planTester.createPlan(
+            "select * from information_schema.current_queries where 
state='RUNNING'");
+    assertPlan(
+        logicalQueryPlan,
+        output(
+            infoSchemaTableScan(
+                "information_schema.current_queries",
+                Optional.empty(),
+                ImmutableList.of(
+                    QUERY_ID_TABLE_MODEL,
+                    STATE_TABLE_MODEL,
+                    START_TIME_TABLE_MODEL,
+                    END_TIME_TABLE_MODEL,
+                    DATA_NODE_ID_TABLE_MODEL,
+                    COST_TIME,
+                    STATEMENT_TABLE_MODEL,
+                    USER_TABLE_MODEL,
+                    CLIENT_IP))));
+
+    // mixed push down and cannot push down term
+    logicalQueryPlan =
+        planTester.createPlan(
+            "select * from information_schema.current_queries where 
state='RUNNING' and query_id='1'");
+    assertPlan(
+        logicalQueryPlan,
+        output(
+            filter(
+                new ComparisonExpression(
+                    EQUAL, new SymbolReference(QUERY_ID_TABLE_MODEL), new 
StringLiteral("1")),
+                infoSchemaTableScan(
+                    "information_schema.current_queries",
+                    Optional.empty(),
+                    ImmutableList.of(
+                        QUERY_ID_TABLE_MODEL,
+                        STATE_TABLE_MODEL,
+                        START_TIME_TABLE_MODEL,
+                        END_TIME_TABLE_MODEL,
+                        DATA_NODE_ID_TABLE_MODEL,
+                        COST_TIME,
+                        STATEMENT_TABLE_MODEL,
+                        USER_TABLE_MODEL,
+                        CLIENT_IP)))));
+
+    // More than one state='xxx' terms
+    logicalQueryPlan =
+        planTester.createPlan(
+            "select * from information_schema.current_queries where 
state='RUNNING' and state='xx'");
+    assertPlan(
+        logicalQueryPlan,
+        output(
+            filter(
+                new ComparisonExpression(
+                    EQUAL, new SymbolReference(STATE_TABLE_MODEL), new 
StringLiteral("xx")),
+                infoSchemaTableScan(
+                    "information_schema.current_queries",
+                    Optional.empty(),
+                    ImmutableList.of(
+                        QUERY_ID_TABLE_MODEL,
+                        STATE_TABLE_MODEL,
+                        START_TIME_TABLE_MODEL,
+                        END_TIME_TABLE_MODEL,
+                        DATA_NODE_ID_TABLE_MODEL,
+                        COST_TIME,
+                        STATEMENT_TABLE_MODEL,
+                        USER_TABLE_MODEL,
+                        CLIENT_IP)))));
+  }
+
   @Test
   public void testQueriesCostsHistogram() {
     LogicalQueryPlan logicalQueryPlan =

Reply via email to