You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iotdb.apache.org by ju...@apache.org on 2026/06/05 04:05:50 UTC

(iotdb) branch insert-values-constant-folding created (now 96ed42c0d73)

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

Caideyipi pushed a change to branch insert-values-constant-folding
in repository https://gitbox.apache.org/repos/asf/iotdb.git


      at 96ed42c0d73 Support constant folding for insert values

This branch includes the following new commits:

     new 96ed42c0d73 Support constant folding for insert values

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



(iotdb) 01/01: Support constant folding for insert values

Posted by ju...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

Caideyipi pushed a commit to branch insert-values-constant-folding
in repository https://gitbox.apache.org/repos/asf/iotdb.git

commit 96ed42c0d73d776a4107726ed9fbb0658f4c03da
Author: Caideyipi <87...@users.noreply.github.com>
AuthorDate: Fri Jun 5 12:05:00 2026 +0800

    Support constant folding for insert values
---
 .../it/session/IoTDBSessionRelationalIT.java       |   14 +-
 .../relational/analyzer/StatementAnalyzer.java     |    6 +
 .../plan/relational/sql/ast/InsertValues.java      |  292 ++
 .../plan/relational/sql/parser/AstBuilder.java     | 4356 --------------------
 .../plan/relational/sql/util/AstUtil.java          |  137 -
 5 files changed, 310 insertions(+), 4495 deletions(-)

diff --git a/integration-test/src/test/java/org/apache/iotdb/relational/it/session/IoTDBSessionRelationalIT.java b/integration-test/src/test/java/org/apache/iotdb/relational/it/session/IoTDBSessionRelationalIT.java
index fc9855a9835..151d981f81f 100644
--- a/integration-test/src/test/java/org/apache/iotdb/relational/it/session/IoTDBSessionRelationalIT.java
+++ b/integration-test/src/test/java/org/apache/iotdb/relational/it/session/IoTDBSessionRelationalIT.java
@@ -271,7 +271,9 @@ public class IoTDBSessionRelationalIT {
         session.executeNonQueryStatement("insert into wrong_time values(1+1,'bb','cc','dd')");
         fail("No exception thrown");
       } catch (StatementExecutionException e) {
-        assertEquals("701: Unsupported expression: (1 + 1)", e.getMessage());
+        assertEquals(
+            "701: Insert expression must be constant after constant folding: (1 + 1) (folded to (1 + 1))",
+            e.getMessage());
       }
       try {
         session.executeNonQueryStatement("insert into wrong_time values(1.0,'bb','cc','dd')");
@@ -333,6 +335,14 @@ public class IoTDBSessionRelationalIT {
                 row, "tag:" + row, "attr:" + row, row));
       }
 
+      session.executeNonQueryStatement(
+          "INSERT INTO table1 (time, tag1, attr1, m1) "
+              + "VALUES (if(true, 50, 0), if(true, 'tag:50', 'x'), "
+              + "if(false, 'x', 'attr:50'), if(true, 50.0, 0.0))");
+      session.executeNonQueryStatement(
+          "INSERT INTO table1 VALUES (if(true, 51, 0), if(true, 'tag:51', 'x'), "
+              + "if(true, 'attr:51', 'x'), if(false, 0, 51))");
+
       SessionDataSet dataSet = session.executeQueryStatement("select * from table1 order by time");
       int cnt = 0;
       while (dataSet.hasNext()) {
@@ -343,7 +353,7 @@ public class IoTDBSessionRelationalIT {
         assertEquals(timestamp * 1.0, rowRecord.getFields().get(3).getDoubleV(), 0.0001);
         cnt++;
       }
-      assertEquals(50, cnt);
+      assertEquals(52, cnt);
 
       // sql cannot create column
       assertThrows(
diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/StatementAnalyzer.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/StatementAnalyzer.java
index d0779ee24a5..6b9cefadc14 100644
--- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/StatementAnalyzer.java
+++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/StatementAnalyzer.java
@@ -178,6 +178,7 @@ import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Insert;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.InsertRow;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.InsertRows;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.InsertTablet;
+import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.InsertValues;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.LoadTsFile;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.PipeEnriched;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Property;
@@ -791,6 +792,11 @@ public class StatementAnalyzer {
     }
 
     private Scope visitInsert(WrappedInsertStatement insert, Optional<Scope> scope) {
+      if (insert instanceof InsertValues) {
+        ((InsertValues) insert)
+            .materialize(new PlannerContext(metadata, typeManager), sessionContext);
+      }
+
       final Scope ret = Scope.create();
 
       final MPPQueryContext context = insert.getContext();
diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/InsertValues.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/InsertValues.java
new file mode 100644
index 00000000000..ce15e2d9f41
--- /dev/null
+++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/InsertValues.java
@@ -0,0 +1,292 @@
+/*
+ * 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.sql.ast;
+
+import org.apache.iotdb.calc.exception.QueryProcessException;
+import org.apache.iotdb.commons.exception.SemanticException;
+import org.apache.iotdb.commons.path.PartialPath;
+import org.apache.iotdb.commons.queryengine.common.SessionInfo;
+import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.Expression;
+import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.Identifier;
+import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.Row;
+import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.Values;
+import org.apache.iotdb.commons.queryengine.utils.TimestampPrecisionUtils;
+import org.apache.iotdb.commons.schema.table.TsTable;
+import org.apache.iotdb.commons.schema.table.column.TsTableColumnCategory;
+import org.apache.iotdb.commons.schema.table.column.TsTableColumnSchema;
+import org.apache.iotdb.commons.utils.CommonDateTimeUtils;
+import org.apache.iotdb.db.i18n.DataNodeQueryMessages;
+import org.apache.iotdb.db.queryengine.plan.relational.planner.PlannerContext;
+import org.apache.iotdb.db.queryengine.plan.relational.sql.util.AstUtil;
+import org.apache.iotdb.db.queryengine.plan.statement.crud.InsertRowStatement;
+import org.apache.iotdb.db.queryengine.plan.statement.crud.InsertRowsStatement;
+import org.apache.iotdb.db.schemaengine.table.DataNodeTableCache;
+
+import org.apache.tsfile.enums.TSDataType;
+import org.apache.tsfile.write.schema.MeasurementSchema;
+
+import javax.annotation.Nullable;
+
+import java.time.ZoneId;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static java.util.Objects.requireNonNull;
+import static org.apache.iotdb.commons.schema.table.column.TsTableColumnCategory.TIME;
+
+public class InsertValues extends InsertRows {
+
+  private final String databaseName;
+  private final String tableName;
+  @Nullable private final List<String> columnNames;
+  private final List<List<Expression>> rows;
+  private final ZoneId zoneId;
+  private boolean materialized;
+
+  public InsertValues(
+      final String databaseName,
+      final String tableName,
+      @Nullable final List<Identifier> columnIdentifiers,
+      final Values values,
+      final ZoneId zoneId) {
+    super(createPlaceholderStatement(databaseName), null);
+    this.databaseName = requireNonNull(databaseName, "databaseName is null");
+    this.tableName = requireNonNull(tableName, "tableName is null");
+    this.columnNames =
+        columnIdentifiers == null
+            ? null
+            : columnIdentifiers.stream().map(Identifier::getValue).collect(Collectors.toList());
+    this.rows =
+        requireNonNull(values, "values is null").getRows().stream()
+            .map(InsertValues::normalizeRow)
+            .collect(Collectors.toList());
+    this.zoneId = requireNonNull(zoneId, "zoneId is null");
+  }
+
+  public void materialize(PlannerContext plannerContext, SessionInfo session) {
+    if (materialized) {
+      return;
+    }
+
+    InsertRowsStatement insertRowsStatement = new InsertRowsStatement();
+    insertRowsStatement.setInsertRowStatementList(
+        columnNames == null
+            ? toInsertRowStatementsWithTableSchema(plannerContext, session)
+            : toInsertRowStatementsWithColumns(plannerContext, session));
+    insertRowsStatement.setWriteToTable(true);
+    insertRowsStatement.setDatabaseName(databaseName);
+    setInnerTreeStatement(insertRowsStatement);
+    materialized = true;
+  }
+
+  private static InsertRowsStatement createPlaceholderStatement(String databaseName) {
+    InsertRowsStatement statement = new InsertRowsStatement();
+    statement.setInsertRowStatementList(Collections.emptyList());
+    statement.setWriteToTable(true);
+    statement.setDatabaseName(databaseName);
+    return statement;
+  }
+
+  private static List<Expression> normalizeRow(Expression row) {
+    if (row instanceof Row) {
+      return ((Row) row).getItems();
+    }
+    return Collections.singletonList(row);
+  }
+
+  private List<InsertRowStatement> toInsertRowStatementsWithTableSchema(
+      PlannerContext plannerContext, SessionInfo session) {
+    final TsTable table = getTable();
+    return rows.stream()
+        .map(row -> toInsertRowStatement(row, table, plannerContext, session))
+        .collect(Collectors.toList());
+  }
+
+  private List<InsertRowStatement> toInsertRowStatementsWithColumns(
+      PlannerContext plannerContext, SessionInfo session) {
+    final List<String> nonTimeColumnNames = new ArrayList<>(columnNames);
+    final int timeColumnIndex = findTimeColumnIndex(nonTimeColumnNames);
+    if (timeColumnIndex != -1) {
+      nonTimeColumnNames.remove(timeColumnIndex);
+    }
+    if (timeColumnIndex == -1 && rows.size() > 1) {
+      throw new SemanticException(DataNodeQueryMessages.NEED_TIMESTAMPS_WHEN_INSERT_MULTI_ROWS);
+    }
+
+    final String[] nonTimeColumnArray = nonTimeColumnNames.toArray(new String[0]);
+    return rows.stream()
+        .map(
+            row ->
+                toInsertRowStatement(
+                    row, timeColumnIndex, nonTimeColumnArray, plannerContext, session))
+        .collect(Collectors.toList());
+  }
+
+  private TsTable getTable() {
+    TsTable table = DataNodeTableCache.getInstance().getTable(databaseName, tableName);
+    if (table == null) {
+      throw new SemanticException(
+          "Insert target table does not exist: " + databaseName + "." + tableName);
+    }
+    return table;
+  }
+
+  private int findTimeColumnIndex(final List<String> columnNames) {
+    List<TsTableColumnSchema> timeColumnCandidates =
+        getTable().getColumnList().stream()
+            .filter(column -> column.getColumnCategory() == TIME)
+            .collect(Collectors.toList());
+    if (timeColumnCandidates.size() != 1) {
+      throw new SemanticException(
+          DataNodeQueryMessages.THE_TABLE_SHOULD_ONLY_HAVE_ONE_COLUMN_FOUND);
+    }
+
+    int timeColumnIndex = -1;
+    String timeColumnName = timeColumnCandidates.get(0).getColumnName();
+    for (int i = 0; i < columnNames.size(); i++) {
+      if (timeColumnName.equalsIgnoreCase(columnNames.get(i))) {
+        if (timeColumnIndex == -1) {
+          timeColumnIndex = i;
+        } else {
+          throw new SemanticException(
+              DataNodeQueryMessages.ONE_ROW_SHOULD_ONLY_HAVE_ONE_TIME_VALUE);
+        }
+      }
+    }
+    return timeColumnIndex;
+  }
+
+  private InsertRowStatement toInsertRowStatement(
+      List<Expression> expressions,
+      TsTable table,
+      PlannerContext plannerContext,
+      SessionInfo session) {
+    InsertRowStatement insertRowStatement = new InsertRowStatement();
+    insertRowStatement.setWriteToTable(true);
+    insertRowStatement.setDevicePath(new PartialPath(new String[] {table.getTableName()}));
+
+    List<TsTableColumnSchema> columnList = table.getColumnList();
+    if (expressions.size() != columnList.size()) {
+      throw new SemanticException(
+          "expressions and columns do not match, expressions size: "
+              + expressions.size()
+              + ", columns size: "
+              + columnList.size());
+    }
+
+    String[] nonTimeColumnNames = new String[columnList.size() - 1];
+    Object[] nonTimeValues = new Object[columnList.size() - 1];
+    TsTableColumnCategory[] nonTimeColumnCategories =
+        new TsTableColumnCategory[columnList.size() - 1];
+    MeasurementSchema[] columnSchemas = new MeasurementSchema[columnList.size() - 1];
+    TSDataType[] dataTypes = new TSDataType[columnList.size() - 1];
+    int nonTimeColumnIndex = 0;
+    long timestamp = -1;
+    for (int i = 0; i < columnList.size(); i++) {
+      TsTableColumnSchema columnSchema = columnList.get(i);
+      Expression expression = expressions.get(i);
+
+      if (columnSchema.getColumnCategory().equals(TIME)) {
+        timestamp = AstUtil.expressionToTimestamp(expression, zoneId, plannerContext, session);
+      } else {
+        Object value = AstUtil.expressionToTsValue(expression, plannerContext, session);
+        nonTimeValues[nonTimeColumnIndex] = value;
+        nonTimeColumnNames[nonTimeColumnIndex] = columnSchema.getColumnName();
+        dataTypes[nonTimeColumnIndex] = columnSchema.getDataType();
+        nonTimeColumnCategories[nonTimeColumnIndex] = columnSchema.getColumnCategory();
+        columnSchemas[nonTimeColumnIndex] =
+            new MeasurementSchema(columnSchema.getColumnName(), columnSchema.getDataType());
+        nonTimeColumnIndex++;
+      }
+    }
+
+    TimestampPrecisionUtils.checkTimestampPrecision(timestamp);
+    insertRowStatement.setTime(timestamp);
+    insertRowStatement.setMeasurements(nonTimeColumnNames);
+    insertRowStatement.setDataTypes(dataTypes);
+    insertRowStatement.setMeasurementSchemas(columnSchemas);
+    insertRowStatement.setValues(nonTimeValues);
+    insertRowStatement.setColumnCategories(nonTimeColumnCategories);
+    insertRowStatement.setNeedInferType(false);
+    insertRowStatement.setDatabaseName(databaseName);
+
+    try {
+      insertRowStatement.transferType(zoneId);
+    } catch (QueryProcessException e) {
+      throw new SemanticException(e);
+    }
+    return insertRowStatement;
+  }
+
+  private InsertRowStatement toInsertRowStatement(
+      List<Expression> expressions,
+      int timeColumnIndex,
+      String[] nonTimeColumnNames,
+      PlannerContext plannerContext,
+      SessionInfo session) {
+    InsertRowStatement insertRowStatement = new InsertRowStatement();
+    insertRowStatement.setWriteToTable(true);
+    insertRowStatement.setDevicePath(new PartialPath(new String[] {tableName}));
+    long timestamp;
+    int nonTimeColumnCount;
+    if (timeColumnIndex == -1) {
+      timestamp = CommonDateTimeUtils.currentTime();
+      nonTimeColumnCount = expressions.size();
+    } else {
+      if (timeColumnIndex >= expressions.size()) {
+        throw new SemanticException(
+            String.format(
+                "TimeColumnIndex out of bound: %d-%d", timeColumnIndex, expressions.size()));
+      }
+
+      timestamp =
+          AstUtil.expressionToTimestamp(
+              expressions.get(timeColumnIndex), zoneId, plannerContext, session);
+      nonTimeColumnCount = expressions.size() - 1;
+    }
+
+    if (nonTimeColumnCount != nonTimeColumnNames.length) {
+      throw new SemanticException(
+          String.format(
+              "Inconsistent numbers of non-time column names and values: %d-%d",
+              nonTimeColumnNames.length, nonTimeColumnCount));
+    }
+
+    TimestampPrecisionUtils.checkTimestampPrecision(timestamp);
+    insertRowStatement.setTime(timestamp);
+    insertRowStatement.setMeasurements(nonTimeColumnNames);
+
+    Object[] values = new Object[nonTimeColumnNames.length];
+    int valuePosition = 0;
+    for (int i = 0; i < expressions.size(); i++) {
+      if (i != timeColumnIndex) {
+        values[valuePosition++] =
+            AstUtil.expressionToTsValue(expressions.get(i), plannerContext, session);
+      }
+    }
+
+    insertRowStatement.setValues(values);
+    insertRowStatement.setNeedInferType(true);
+    insertRowStatement.setDatabaseName(databaseName);
+    return insertRowStatement;
+  }
+}
diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/parser/AstBuilder.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/parser/AstBuilder.java
deleted file mode 100644
index 25d68eba6be..00000000000
--- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/parser/AstBuilder.java
+++ /dev/null
@@ -1,4356 +0,0 @@
-/*
- * 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.sql.parser;
-
-import org.apache.iotdb.calc.exception.QueryProcessException;
-import org.apache.iotdb.common.rpc.thrift.TConsensusGroupType;
-import org.apache.iotdb.commons.auth.entity.PrivilegeType;
-import org.apache.iotdb.commons.cluster.NodeStatus;
-import org.apache.iotdb.commons.conf.CommonDescriptor;
-import org.apache.iotdb.commons.exception.IllegalPathException;
-import org.apache.iotdb.commons.exception.SemanticException;
-import org.apache.iotdb.commons.path.PartialPath;
-import org.apache.iotdb.commons.queryengine.common.SqlDialect;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.AliasedRelation;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.AllColumns;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.AllRows;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.AnchorPattern;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.ArithmeticBinaryExpression;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.ArithmeticUnaryExpression;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.BetweenPredicate;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.BinaryLiteral;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.BooleanLiteral;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.Cast;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.CoalesceExpression;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.Columns;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.ComparisonExpression;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.CurrentDatabase;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.CurrentTime;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.CurrentUser;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.DataType;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.DataTypeParameter;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.DereferenceExpression;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.DoubleLiteral;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.EmptyPattern;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.Except;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.ExcludedPattern;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.ExistsPredicate;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.Expression;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.Extract;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.Fill;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.FrameBound;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.FunctionCall;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.GenericDataType;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.GroupBy;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.GroupingElement;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.GroupingSets;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.Identifier;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.IfExpression;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.InListExpression;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.InPredicate;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.Intersect;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.IsNotNullPredicate;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.IsNullPredicate;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.Join;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.JoinCriteria;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.JoinOn;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.JoinUsing;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.LikePredicate;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.Limit;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.Literal;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.LogicalExpression;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.LongLiteral;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.MeasureDefinition;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.NaturalJoin;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.Node;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.NodeLocation;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.NotExpression;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.NullIfExpression;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.NullLiteral;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.NumericParameter;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.Offset;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.OneOrMoreQuantifier;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.OrderBy;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.Parameter;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.PatternAlternation;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.PatternConcatenation;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.PatternPermutation;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.PatternQuantifier;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.PatternRecognitionRelation;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.PatternRecognitionRelation.RowsPerMatch;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.PatternVariable;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.ProcessingMode;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.QualifiedName;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.QuantifiedComparisonExpression;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.QuantifiedPattern;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.Query;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.QueryBody;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.QuerySpecification;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.RangeQuantifier;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.Relation;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.Row;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.RowPattern;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.SearchedCaseExpression;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.Select;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.SelectItem;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.SimpleCaseExpression;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.SimpleGroupBy;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.SingleColumn;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.SkipTo;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.SortItem;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.Statement;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.StringLiteral;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.SubqueryExpression;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.SubsetDefinition;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.Table;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.TableExpressionType;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.TableFunctionArgument;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.TableFunctionInvocation;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.TableFunctionTableArgument;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.TableSubquery;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.TimeDurationLiteral;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.Trim;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.TypeParameter;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.Union;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.Values;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.VariableDefinition;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.WhenClause;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.Window;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.WindowDefinition;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.WindowFrame;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.WindowReference;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.WindowSpecification;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.With;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.WithQuery;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.ZeroOrMoreQuantifier;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.ZeroOrOneQuantifier;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.parser.ParsingException;
-import org.apache.iotdb.commons.queryengine.utils.TimestampPrecisionUtils;
-import org.apache.iotdb.commons.schema.cache.CacheClearOptions;
-import org.apache.iotdb.commons.schema.table.InformationSchema;
-import org.apache.iotdb.commons.schema.table.TsTable;
-import org.apache.iotdb.commons.schema.table.column.TsTableColumnCategory;
-import org.apache.iotdb.commons.schema.table.column.TsTableColumnSchema;
-import org.apache.iotdb.commons.udf.builtin.relational.TableBuiltinScalarFunction;
-import org.apache.iotdb.commons.utils.CommonDateTimeUtils;
-import org.apache.iotdb.commons.utils.PathUtils;
-import org.apache.iotdb.db.i18n.DataNodeQueryMessages;
-import org.apache.iotdb.db.protocol.session.IClientSession;
-import org.apache.iotdb.db.queryengine.execution.operator.process.copyto.CopyToOptions;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.AddColumn;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.AlterColumnDataType;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.AlterDB;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.AlterPipe;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.AsofJoinOn;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ClearCache;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ColumnDefinition;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.CopyTo;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.CountDB;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.CountDevice;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.CountStatement;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.CreateDB;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.CreateFunction;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.CreateIndex;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.CreateModel;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.CreatePipe;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.CreatePipePlugin;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.CreateTable;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.CreateTopic;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.CreateTraining;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.CreateView;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Deallocate;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Delete;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.DeleteDevice;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.DescribeTable;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.DropColumn;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.DropDB;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.DropFunction;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.DropIndex;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.DropModel;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.DropPipe;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.DropPipePlugin;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.DropSubscription;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.DropTable;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.DropTopic;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Execute;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ExecuteImmediate;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Explain;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ExplainAnalyze;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ExtendRegion;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Flush;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Insert;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.InsertRows;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.KillQuery;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.LoadConfiguration;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.LoadModel;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.LoadTsFile;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.MigrateRegion;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Prepare;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Property;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ReconstructRegion;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.RelationalAuthorStatement;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.RemoveAINode;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.RemoveConfigNode;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.RemoveDataNode;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.RemoveRegion;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.RenameColumn;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.RenameTable;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.SetColumnComment;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.SetConfiguration;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.SetProperties;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.SetSqlDialect;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.SetSystemStatus;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.SetTableComment;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ShowAIDevices;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ShowAINodes;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ShowAvailableUrls;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ShowCluster;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ShowClusterId;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ShowConfigNodes;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ShowConfiguration;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ShowCurrentDatabase;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ShowCurrentSqlDialect;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ShowCurrentTimestamp;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ShowCurrentUser;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ShowDB;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ShowDataNodes;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ShowDevice;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ShowExternalService;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ShowFunctions;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ShowIndex;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ShowLoadedModels;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ShowModels;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ShowPipePlugins;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ShowPipes;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ShowQueriesStatement;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ShowRegions;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ShowStatement;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ShowSubscriptions;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ShowTables;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ShowTopics;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ShowVariables;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ShowVersion;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.StartPipe;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.StartRepairData;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.StopPipe;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.StopRepairData;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.UnloadModel;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Update;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.UpdateAssignment;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Use;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ViewFieldDefinition;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.util.AstUtil;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.util.QueryUtil;
-import org.apache.iotdb.db.queryengine.plan.relational.type.AuthorRType;
-import org.apache.iotdb.db.queryengine.plan.statement.StatementType;
-import org.apache.iotdb.db.queryengine.plan.statement.crud.InsertRowStatement;
-import org.apache.iotdb.db.queryengine.plan.statement.crud.InsertRowsStatement;
-import org.apache.iotdb.db.queryengine.plan.statement.sys.FlushStatement;
-import org.apache.iotdb.db.queryengine.plan.statement.sys.LoadConfigurationStatement;
-import org.apache.iotdb.db.queryengine.plan.statement.sys.SetConfigurationStatement;
-import org.apache.iotdb.db.queryengine.plan.statement.sys.SetSystemStatusStatement;
-import org.apache.iotdb.db.queryengine.plan.statement.sys.ShowConfigurationStatement;
-import org.apache.iotdb.db.queryengine.plan.statement.sys.StartRepairDataStatement;
-import org.apache.iotdb.db.queryengine.plan.statement.sys.StopRepairDataStatement;
-import org.apache.iotdb.db.relational.grammar.sql.RelationalSqlBaseVisitor;
-import org.apache.iotdb.db.relational.grammar.sql.RelationalSqlLexer;
-import org.apache.iotdb.db.relational.grammar.sql.RelationalSqlParser;
-import org.apache.iotdb.db.schemaengine.table.DataNodeTableCache;
-import org.apache.iotdb.db.storageengine.load.config.LoadTsFileConfigurator;
-import org.apache.iotdb.db.utils.DataNodeDateTimeUtils;
-
-import com.google.common.collect.ImmutableList;
-import org.antlr.v4.runtime.ParserRuleContext;
-import org.antlr.v4.runtime.Token;
-import org.antlr.v4.runtime.tree.ParseTree;
-import org.antlr.v4.runtime.tree.TerminalNode;
-import org.apache.tsfile.common.constant.TsFileConstant;
-import org.apache.tsfile.enums.TSDataType;
-import org.apache.tsfile.utils.TimeDuration;
-import org.apache.tsfile.write.schema.MeasurementSchema;
-
-import javax.annotation.Nullable;
-
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.time.ZoneId;
-import java.util.ArrayDeque;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Deque;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.Set;
-import java.util.function.Function;
-import java.util.stream.Collectors;
-
-import static com.google.common.collect.ImmutableList.toImmutableList;
-import static java.lang.Long.parseLong;
-import static java.util.Locale.ENGLISH;
-import static java.util.Objects.requireNonNull;
-import static java.util.stream.Collectors.toList;
-import static org.apache.iotdb.calc.utils.constant.SqlConstant.APPROX_COUNT_DISTINCT;
-import static org.apache.iotdb.calc.utils.constant.SqlConstant.APPROX_MOST_FREQUENT;
-import static org.apache.iotdb.calc.utils.constant.SqlConstant.APPROX_PERCENTILE;
-import static org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.AnchorPattern.Type.PARTITION_END;
-import static org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.AnchorPattern.Type.PARTITION_START;
-import static org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.GroupingSets.Type.CUBE;
-import static org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.GroupingSets.Type.EXPLICIT;
-import static org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.GroupingSets.Type.ROLLUP;
-import static org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.PatternRecognitionRelation.RowsPerMatch.ALL_OMIT_EMPTY;
-import static org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.PatternRecognitionRelation.RowsPerMatch.ALL_SHOW_EMPTY;
-import static org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.PatternRecognitionRelation.RowsPerMatch.ALL_WITH_UNMATCHED;
-import static org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.PatternRecognitionRelation.RowsPerMatch.ONE;
-import static org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.ProcessingMode.Mode.FINAL;
-import static org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.ProcessingMode.Mode.RUNNING;
-import static org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.QualifiedName.mapIdentifier;
-import static org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.SkipTo.skipPastLastRow;
-import static org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.SkipTo.skipToFirst;
-import static org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.SkipTo.skipToLast;
-import static org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.SkipTo.skipToNextRow;
-import static org.apache.iotdb.commons.schema.column.ColumnHeaderConstant.DATA_NODE_ID_TABLE_MODEL;
-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.TAG;
-import static org.apache.iotdb.commons.schema.table.column.TsTableColumnCategory.TIME;
-import static org.apache.iotdb.commons.udf.builtin.relational.TableBuiltinScalarFunction.DATE_BIN;
-import static org.apache.iotdb.db.queryengine.plan.execution.config.TableConfigTaskVisitor.DATABASE_NOT_SPECIFIED;
-import static org.apache.iotdb.db.queryengine.plan.parser.ASTVisitor.SERVICE_MANAGEMENT_NOT_SUPPORTED;
-import static org.apache.iotdb.db.queryengine.plan.parser.ASTVisitor.parseDateTimeFormat;
-import static org.apache.iotdb.db.queryengine.plan.parser.ASTVisitor.parseIdentifier;
-import static org.apache.iotdb.db.queryengine.plan.parser.ASTVisitor.parseNodeString;
-import static org.apache.iotdb.db.queryengine.plan.parser.ASTVisitor.parseStringLiteral;
-import static org.apache.iotdb.db.queryengine.plan.relational.sql.ast.AsofJoinOn.constructAsofJoinOn;
-import static org.apache.iotdb.db.queryengine.plan.relational.sql.util.QueryUtil.selectList;
-import static org.apache.iotdb.db.queryengine.plan.relational.sql.util.QueryUtil.table;
-
-public class AstBuilder extends RelationalSqlBaseVisitor<Node> {
-
-  private int parameterPosition;
-
-  @Nullable private final NodeLocation baseLocation;
-
-  private final ZoneId zoneId;
-
-  private final IClientSession clientSession;
-
-  AstBuilder(@Nullable NodeLocation baseLocation, ZoneId zoneId, IClientSession clientSession) {
-    this.baseLocation = baseLocation;
-    this.zoneId = zoneId;
-    this.clientSession = clientSession;
-  }
-
-  @Override
-  public Node visitSingleStatement(RelationalSqlParser.SingleStatementContext ctx) {
-    Statement statement = (Statement) visit(ctx.statement());
-    statement.setDebug(ctx.DEBUG() != null);
-    return statement;
-  }
-
-  @Override
-  public Node visitStandaloneExpression(RelationalSqlParser.StandaloneExpressionContext context) {
-    return visit(context.expression());
-  }
-
-  @Override
-  public Node visitStandaloneType(RelationalSqlParser.StandaloneTypeContext context) {
-    return visit(context.type());
-  }
-
-  @Override
-  public Node visitStandaloneRowPattern(RelationalSqlParser.StandaloneRowPatternContext context) {
-    return visit(context.rowPattern());
-  }
-
-  // ******************* statements **********************
-  @Override
-  public Node visitUseDatabaseStatement(RelationalSqlParser.UseDatabaseStatementContext ctx) {
-    return new Use(getLocation(ctx), lowerIdentifier((Identifier) visit(ctx.database)));
-  }
-
-  public static Identifier lowerIdentifier(Identifier identifier) {
-    if (identifier.getLocation().isPresent()) {
-      return new Identifier(
-          identifier.getLocation().get(), mapIdentifier(identifier), identifier.isDelimited());
-    } else {
-      return new Identifier(mapIdentifier(identifier), identifier.isDelimited());
-    }
-  }
-
-  @Override
-  public Node visitShowDatabasesStatement(
-      final RelationalSqlParser.ShowDatabasesStatementContext ctx) {
-    return new ShowDB(getLocation(ctx), Objects.nonNull(ctx.DETAILS()));
-  }
-
-  @Override
-  public Node visitCountDatabasesStatement(
-      final RelationalSqlParser.CountDatabasesStatementContext ctx) {
-    return new CountDB(getLocation(ctx));
-  }
-
-  @Override
-  public Node visitCreateDbStatement(final RelationalSqlParser.CreateDbStatementContext ctx) {
-    List<Property> properties = ImmutableList.of();
-    if (ctx.properties() != null) {
-      properties = visit(ctx.properties().propertyAssignments().property(), Property.class);
-    }
-
-    return new CreateDB(
-        getLocation(ctx),
-        ctx.EXISTS() != null,
-        ((Identifier) visit(ctx.database)).getValue(),
-        properties);
-  }
-
-  @Override
-  public Node visitAlterDbStatement(final RelationalSqlParser.AlterDbStatementContext ctx) {
-    List<Property> properties = ImmutableList.of();
-    if (ctx.propertyAssignments() != null) {
-      properties = visit(ctx.propertyAssignments().property(), Property.class);
-    }
-
-    return new AlterDB(
-        getLocation(ctx),
-        ctx.EXISTS() != null,
-        ((Identifier) visit(ctx.database)).getValue(),
-        properties);
-  }
-
-  @Override
-  public Node visitDropDbStatement(final RelationalSqlParser.DropDbStatementContext ctx) {
-    return new DropDB(
-        getLocation(ctx), lowerIdentifier((Identifier) visit(ctx.database)), ctx.EXISTS() != null);
-  }
-
-  @Override
-  public Node visitCreateTableStatement(final RelationalSqlParser.CreateTableStatementContext ctx) {
-    List<Property> properties = ImmutableList.of();
-    if (ctx.properties() != null) {
-      properties = visit(ctx.properties().propertyAssignments().property(), Property.class);
-    }
-    return new CreateTable(
-        getLocation(ctx),
-        getQualifiedName(ctx.qualifiedName()),
-        visit(ctx.columnDefinition(), ColumnDefinition.class),
-        ctx.EXISTS() != null,
-        ctx.charsetDesc() == null
-            ? null
-            : ((Identifier) visit(ctx.charsetDesc().identifierOrString())).getValue(),
-        ctx.comment() == null ? null : ((StringLiteral) visit(ctx.comment().string())).getValue(),
-        properties);
-  }
-
-  @Override
-  public Node visitColumnDefinition(final RelationalSqlParser.ColumnDefinitionContext ctx) {
-    return new ColumnDefinition(
-        getLocation(ctx),
-        lowerIdentifier((Identifier) visit(ctx.identifier())),
-        Objects.nonNull(ctx.type()) ? (DataType) visit(ctx.type()) : null,
-        getColumnCategory(ctx.columnCategory),
-        ctx.charsetName() == null
-            ? null
-            : ((Identifier) visit(ctx.charsetName().identifier())).getValue(),
-        ctx.comment() == null ? null : ((StringLiteral) visit(ctx.comment().string())).getValue());
-  }
-
-  @Override
-  public Node visitDropTableStatement(final RelationalSqlParser.DropTableStatementContext ctx) {
-    return new DropTable(
-        getLocation(ctx), getQualifiedName(ctx.qualifiedName()), ctx.EXISTS() != null, false);
-  }
-
-  @Override
-  public Node visitShowTableStatement(final RelationalSqlParser.ShowTableStatementContext ctx) {
-    return Objects.nonNull(ctx.database)
-        ? new ShowTables(
-            getLocation(ctx),
-            lowerIdentifier((Identifier) visit(ctx.database)),
-            Objects.nonNull(ctx.DETAILS()))
-        : new ShowTables(getLocation(ctx), Objects.nonNull(ctx.DETAILS()));
-  }
-
-  @Override
-  public Node visitDescTableStatement(final RelationalSqlParser.DescTableStatementContext ctx) {
-    return new DescribeTable(
-        getLocation(ctx), getQualifiedName(ctx.table), Objects.nonNull(ctx.DETAILS()), null);
-  }
-
-  @Override
-  public Node visitRenameTable(final RelationalSqlParser.RenameTableContext ctx) {
-    return new RenameTable(
-        getLocation(ctx),
-        getQualifiedName(ctx.from),
-        lowerIdentifier((Identifier) visit(ctx.to)),
-        Objects.nonNull(ctx.EXISTS()),
-        false);
-  }
-
-  @Override
-  public Node visitAddColumn(final RelationalSqlParser.AddColumnContext ctx) {
-    return new AddColumn(
-        getLocation(ctx),
-        getQualifiedName(ctx.tableName),
-        (ColumnDefinition) visit(ctx.column),
-        ctx.EXISTS().size() == (Objects.nonNull(ctx.NOT()) ? 2 : 1),
-        Objects.nonNull(ctx.NOT()),
-        false);
-  }
-
-  @Override
-  public Node visitRenameColumn(final RelationalSqlParser.RenameColumnContext ctx) {
-    return new RenameColumn(
-        getLocation(ctx),
-        getQualifiedName(ctx.tableName),
-        (Identifier) visit(ctx.from),
-        (Identifier) visit(ctx.to),
-        ctx.EXISTS().stream()
-            .anyMatch(
-                node ->
-                    node.getSymbol().getTokenIndex() < ctx.COLUMN().getSymbol().getTokenIndex()),
-        ctx.EXISTS().stream()
-            .anyMatch(
-                node ->
-                    node.getSymbol().getTokenIndex() > ctx.COLUMN().getSymbol().getTokenIndex()),
-        false);
-  }
-
-  @Override
-  public Node visitDropColumn(final RelationalSqlParser.DropColumnContext ctx) {
-    return new DropColumn(
-        getLocation(ctx),
-        getQualifiedName(ctx.tableName),
-        lowerIdentifier((Identifier) visit(ctx.column)),
-        ctx.EXISTS().stream()
-            .anyMatch(
-                node ->
-                    node.getSymbol().getTokenIndex() < ctx.COLUMN().getSymbol().getTokenIndex()),
-        ctx.EXISTS().stream()
-            .anyMatch(
-                node ->
-                    node.getSymbol().getTokenIndex() > ctx.COLUMN().getSymbol().getTokenIndex()),
-        false);
-  }
-
-  @Override
-  public Node visitSetTableProperties(final RelationalSqlParser.SetTablePropertiesContext ctx) {
-    List<Property> properties = ImmutableList.of();
-    if (ctx.propertyAssignments() != null) {
-      properties = visit(ctx.propertyAssignments().property(), Property.class);
-    }
-    return new SetProperties(
-        getLocation(ctx),
-        SetProperties.Type.TABLE,
-        getQualifiedName(ctx.qualifiedName()),
-        properties,
-        Objects.nonNull(ctx.EXISTS()));
-  }
-
-  @Override
-  public Node visitShowCreateTableStatement(
-      final RelationalSqlParser.ShowCreateTableStatementContext ctx) {
-    return new DescribeTable(
-        getLocation(ctx), getQualifiedName(ctx.qualifiedName()), false, Boolean.FALSE);
-  }
-
-  @Override
-  public Node visitAlterColumnDataType(RelationalSqlParser.AlterColumnDataTypeContext ctx) {
-    QualifiedName tableName = getQualifiedName(ctx.tableName);
-    Identifier columnName = lowerIdentifier((Identifier) visit(ctx.identifier()));
-    DataType dataType = (DataType) visit(ctx.new_type);
-    boolean ifTableExists =
-        ctx.EXISTS().stream()
-            .anyMatch(
-                node ->
-                    node.getSymbol().getTokenIndex() < ctx.COLUMN().getSymbol().getTokenIndex());
-    boolean ifColumnExists =
-        ctx.EXISTS().stream()
-            .anyMatch(
-                node ->
-                    node.getSymbol().getTokenIndex() > ctx.COLUMN().getSymbol().getTokenIndex());
-    return new AlterColumnDataType(
-        getLocation(ctx), tableName, columnName, dataType, ifTableExists, ifColumnExists, false);
-  }
-
-  @Override
-  public Node visitCommentTable(final RelationalSqlParser.CommentTableContext ctx) {
-    return new SetTableComment(
-        getLocation(ctx),
-        getQualifiedName(ctx.qualifiedName()),
-        false,
-        Objects.nonNull(ctx.string()) ? ((StringLiteral) visit(ctx.string())).getValue() : null,
-        false);
-  }
-
-  @Override
-  public Node visitCommentView(final RelationalSqlParser.CommentViewContext ctx) {
-    return new SetTableComment(
-        getLocation(ctx),
-        getQualifiedName(ctx.qualifiedName()),
-        false,
-        Objects.nonNull(ctx.string()) ? ((StringLiteral) visit(ctx.string())).getValue() : null,
-        true);
-  }
-
-  @Override
-  public Node visitCommentColumn(final RelationalSqlParser.CommentColumnContext ctx) {
-    return new SetColumnComment(
-        getLocation(ctx),
-        getQualifiedName(ctx.qualifiedName()),
-        lowerIdentifier((Identifier) visit(ctx.column)),
-        false,
-        false,
-        Objects.nonNull(ctx.string()) ? ((StringLiteral) visit(ctx.string())).getValue() : null);
-  }
-
-  @Override
-  public Node visitCreateViewStatement(final RelationalSqlParser.CreateViewStatementContext ctx) {
-    List<Property> properties = ImmutableList.of();
-    if (ctx.properties() != null) {
-      properties = visit(ctx.properties().propertyAssignments().property(), Property.class);
-    }
-    return new CreateView(
-        getLocation(ctx),
-        getQualifiedName(ctx.qualifiedName()),
-        visit(ctx.viewColumnDefinition(), ColumnDefinition.class),
-        null,
-        ctx.comment() == null ? null : ((StringLiteral) visit(ctx.comment().string())).getValue(),
-        properties,
-        parsePrefixPath(ctx.prefixPath()),
-        Objects.nonNull(ctx.REPLACE()),
-        Objects.nonNull(ctx.RESTRICT()));
-  }
-
-  @Override
-  public Node visitRenameTableView(final RelationalSqlParser.RenameTableViewContext ctx) {
-    return new RenameTable(
-        getLocation(ctx),
-        getQualifiedName(ctx.from),
-        lowerIdentifier((Identifier) visit(ctx.to)),
-        Objects.nonNull(ctx.EXISTS()),
-        true);
-  }
-
-  @Override
-  public Node visitAddViewColumn(final RelationalSqlParser.AddViewColumnContext ctx) {
-    return new AddColumn(
-        getLocation(ctx),
-        getQualifiedName(ctx.viewName),
-        (ColumnDefinition) visit(ctx.viewColumnDefinition()),
-        ctx.EXISTS().size() == (Objects.nonNull(ctx.NOT()) ? 2 : 1),
-        Objects.nonNull(ctx.NOT()),
-        true);
-  }
-
-  @Override
-  public Node visitRenameViewColumn(final RelationalSqlParser.RenameViewColumnContext ctx) {
-    return new RenameColumn(
-        getLocation(ctx),
-        getQualifiedName(ctx.viewName),
-        (Identifier) visit(ctx.from),
-        (Identifier) visit(ctx.to),
-        ctx.EXISTS().stream()
-            .anyMatch(
-                node ->
-                    node.getSymbol().getTokenIndex() < ctx.COLUMN().getSymbol().getTokenIndex()),
-        ctx.EXISTS().stream()
-            .anyMatch(
-                node ->
-                    node.getSymbol().getTokenIndex() > ctx.COLUMN().getSymbol().getTokenIndex()),
-        true);
-  }
-
-  @Override
-  public Node visitDropViewColumn(final RelationalSqlParser.DropViewColumnContext ctx) {
-    return new DropColumn(
-        getLocation(ctx),
-        getQualifiedName(ctx.viewName),
-        lowerIdentifier((Identifier) visit(ctx.column)),
-        ctx.EXISTS().stream()
-            .anyMatch(
-                node ->
-                    node.getSymbol().getTokenIndex() < ctx.COLUMN().getSymbol().getTokenIndex()),
-        ctx.EXISTS().stream()
-            .anyMatch(
-                node ->
-                    node.getSymbol().getTokenIndex() > ctx.COLUMN().getSymbol().getTokenIndex()),
-        true);
-  }
-
-  @Override
-  public Node visitSetTableViewProperties(
-      final RelationalSqlParser.SetTableViewPropertiesContext ctx) {
-    List<Property> properties = ImmutableList.of();
-    if (ctx.propertyAssignments() != null) {
-      properties = visit(ctx.propertyAssignments().property(), Property.class);
-    }
-    return new SetProperties(
-        getLocation(ctx),
-        SetProperties.Type.TREE_VIEW,
-        getQualifiedName(ctx.qualifiedName()),
-        properties,
-        Objects.nonNull(ctx.EXISTS()));
-  }
-
-  @Override
-  public Node visitViewColumnDefinition(final RelationalSqlParser.ViewColumnDefinitionContext ctx) {
-    final Identifier rawColumnName = (Identifier) visit(ctx.identifier().get(0));
-    final Identifier columnName = lowerIdentifier(rawColumnName);
-    final TsTableColumnCategory columnCategory = getColumnCategory(ctx.columnCategory);
-    Identifier originalMeasurement = null;
-
-    if (Objects.nonNull(ctx.FROM())) {
-      originalMeasurement = (Identifier) visit(ctx.original_measurement);
-    } else if (columnCategory == FIELD && !columnName.equals(rawColumnName)) {
-      originalMeasurement = rawColumnName;
-    }
-
-    return columnCategory == FIELD
-        ? new ViewFieldDefinition(
-            getLocation(ctx),
-            columnName,
-            Objects.nonNull(ctx.type()) ? (DataType) visit(ctx.type()) : null,
-            null,
-            ctx.comment() == null
-                ? null
-                : ((StringLiteral) visit(ctx.comment().string())).getValue(),
-            originalMeasurement)
-        : new ColumnDefinition(
-            getLocation(ctx),
-            columnName,
-            Objects.nonNull(ctx.type()) ? (DataType) visit(ctx.type()) : null,
-            columnCategory,
-            null,
-            ctx.comment() == null
-                ? null
-                : ((StringLiteral) visit(ctx.comment().string())).getValue());
-  }
-
-  private PartialPath parsePrefixPath(final RelationalSqlParser.PrefixPathContext ctx) {
-    final List<RelationalSqlParser.NodeNameContext> nodeNames = ctx.nodeName();
-    final StringBuilder builder = new StringBuilder("root.");
-    for (int i = 0; i < nodeNames.size(); i++) {
-      if (nodeNames.get(i).nodeNameWithoutWildcard() != null) {
-        builder
-            .append("`")
-            .append(
-                parseNodeString(
-                    ((Identifier) visit(nodeNames.get(i).nodeNameWithoutWildcard().identifier()))
-                        .getValue()))
-            .append("`")
-            .append(i == nodeNames.size() - 1 ? "" : ".");
-      } else {
-        builder.append(nodeNames.get(i).getText());
-      }
-    }
-    try {
-      return new PartialPath(builder.toString());
-    } catch (final IllegalPathException e) {
-      throw new SemanticException(e);
-    }
-  }
-
-  @Override
-  public Node visitDropViewStatement(final RelationalSqlParser.DropViewStatementContext ctx) {
-    return new DropTable(
-        getLocation(ctx), getQualifiedName(ctx.qualifiedName()), ctx.EXISTS() != null, true);
-  }
-
-  @Override
-  public Node visitShowCreateViewStatement(
-      final RelationalSqlParser.ShowCreateViewStatementContext ctx) {
-    return new DescribeTable(
-        getLocation(ctx), getQualifiedName(ctx.qualifiedName()), false, Boolean.TRUE);
-  }
-
-  @Override
-  public Node visitCreateIndexStatement(RelationalSqlParser.CreateIndexStatementContext ctx) {
-    return new CreateIndex(
-        getLocation(ctx),
-        getQualifiedName(ctx.tableName),
-        lowerIdentifier((Identifier) visit(ctx.indexName)),
-        visit(ctx.identifierList().identifier(), Identifier.class));
-  }
-
-  @Override
-  public Node visitDropIndexStatement(RelationalSqlParser.DropIndexStatementContext ctx) {
-    return new DropIndex(
-        getLocation(ctx),
-        getQualifiedName(ctx.tableName),
-        lowerIdentifier((Identifier) visit(ctx.indexName)));
-  }
-
-  @Override
-  public Node visitShowIndexStatement(RelationalSqlParser.ShowIndexStatementContext ctx) {
-    return new ShowIndex(getLocation(ctx), getQualifiedName(ctx.tableName));
-  }
-
-  @Override
-  public Node visitInsertStatement(final RelationalSqlParser.InsertStatementContext ctx) {
-    final QualifiedName qualifiedName = getQualifiedName(ctx.tableName);
-    String tableName = qualifiedName.getSuffix();
-    String databaseName =
-        qualifiedName
-            .getPrefix()
-            .map(QualifiedName::toString)
-            .orElse(clientSession.getDatabaseName());
-    if (databaseName == null) {
-      throw new SemanticException(DATABASE_NOT_SPECIFIED);
-    }
-    tableName = tableName.toLowerCase();
-    databaseName = databaseName.toLowerCase();
-
-    final Query query = (Query) visit(ctx.query());
-    if (ctx.columnAliases() != null) {
-      final List<Identifier> identifiers =
-          visit(ctx.columnAliases().identifier(), Identifier.class);
-      if (query.getQueryBody() instanceof Values) {
-        return visitInsertValues(
-            databaseName, tableName, identifiers, ((Values) query.getQueryBody()));
-      } else {
-        return new Insert(new Table(qualifiedName), identifiers, query);
-      }
-    } else {
-      return query.getQueryBody() instanceof Values
-          ? visitInsertValues(
-              databaseName,
-              DataNodeTableCache.getInstance().getTable(databaseName, tableName),
-              ((Values) query.getQueryBody()))
-          : new Insert(new Table(qualifiedName), query);
-    }
-  }
-
-  private Node visitInsertValues(
-      final String databaseName, final TsTable table, final Values queryBody) {
-    final List<Expression> rows = queryBody.getRows();
-    final List<InsertRowStatement> rowStatements =
-        rows.stream()
-            .map(
-                r -> {
-                  List<Expression> expressions;
-                  if (r instanceof Row) {
-                    expressions = ((Row) r).getItems();
-                  } else if (r instanceof Literal) {
-                    expressions = Collections.singletonList(r);
-                  } else {
-                    throw new SemanticException(DataNodeQueryMessages.UNEXPECTED_EXPRESSION_2 + r);
-                  }
-                  return toInsertRowStatement(expressions, table, databaseName);
-                })
-            .collect(toList());
-
-    InsertRowsStatement insertRowsStatement = new InsertRowsStatement();
-    insertRowsStatement.setInsertRowStatementList(rowStatements);
-    insertRowsStatement.setWriteToTable(true);
-    return new InsertRows(insertRowsStatement, null);
-  }
-
-  private Node visitInsertValues(
-      final String databaseName,
-      final String tableName,
-      final List<Identifier> identifiers,
-      final Values queryBody) {
-    final List<String> columnNames =
-        identifiers.stream().map(Identifier::getValue).collect(toList());
-    int timeColumnIndex = -1;
-
-    // retrieve the table schema to identify the actual time column
-    TsTable table = DataNodeTableCache.getInstance().getTable(databaseName, tableName);
-    List<TsTableColumnSchema> timeColumnCandidates =
-        table.getColumnList().stream()
-            .filter(col -> col.getColumnCategory() == TIME)
-            .collect(toList());
-    if (timeColumnCandidates.size() != 1) {
-      throw new SemanticException(
-          DataNodeQueryMessages.THE_TABLE_SHOULD_ONLY_HAVE_ONE_COLUMN_FOUND);
-    } else {
-      // locate the time column index in the input identifiers if time column exists in the schema
-      for (int i = 0; i < columnNames.size(); i++) {
-        if (timeColumnCandidates.get(0).getColumnName().equalsIgnoreCase(columnNames.get(i))) {
-          if (timeColumnIndex == -1) {
-            timeColumnIndex = i;
-          } else {
-            throw new SemanticException(
-                DataNodeQueryMessages.ONE_ROW_SHOULD_ONLY_HAVE_ONE_TIME_VALUE);
-          }
-        }
-      }
-    }
-
-    if (timeColumnIndex != -1) {
-      columnNames.remove(timeColumnIndex);
-    }
-
-    List<Expression> rows = queryBody.getRows();
-    if (timeColumnIndex == -1 && rows.size() > 1) {
-      throw new SemanticException(DataNodeQueryMessages.NEED_TIMESTAMPS_WHEN_INSERT_MULTI_ROWS);
-    }
-    int finalTimeColumnIndex = timeColumnIndex;
-    List<InsertRowStatement> rowStatements =
-        rows.stream()
-            .map(
-                r -> {
-                  List<Expression> expressions;
-                  if (r instanceof Row) {
-                    expressions = ((Row) r).getItems();
-                  } else if (r instanceof Literal) {
-                    expressions = Collections.singletonList(r);
-                  } else {
-                    throw new SemanticException(DataNodeQueryMessages.UNEXPECTED_EXPRESSION_2 + r);
-                  }
-                  String[] columnNameArray = columnNames.toArray(new String[0]);
-                  return toInsertRowStatement(
-                      expressions,
-                      finalTimeColumnIndex,
-                      columnNameArray,
-                      tableName,
-                      databaseName,
-                      columnNames.size());
-                })
-            .collect(toList());
-
-    InsertRowsStatement insertRowsStatement = new InsertRowsStatement();
-    insertRowsStatement.setInsertRowStatementList(rowStatements);
-    insertRowsStatement.setWriteToTable(true);
-    return new InsertRows(insertRowsStatement, null);
-  }
-
-  private InsertRowStatement toInsertRowStatement(
-      List<Expression> expressions, TsTable table, String databaseName) {
-    InsertRowStatement insertRowStatement = new InsertRowStatement();
-    insertRowStatement.setWriteToTable(true);
-    insertRowStatement.setDevicePath(new PartialPath(new String[] {table.getTableName()}));
-
-    List<TsTableColumnSchema> columnList = table.getColumnList();
-    if (expressions.size() != columnList.size()) {
-      throw new SemanticException(
-          "expressions and columns do not match, expressions size: "
-              + expressions.size()
-              + ", columns size: "
-              + columnList.size());
-    }
-
-    String[] nonTimeColumnNames = new String[columnList.size() - 1];
-    Object[] nonTimeValues = new Object[columnList.size() - 1];
-    TsTableColumnCategory[] nonTimeColumnCategories =
-        new TsTableColumnCategory[columnList.size() - 1];
-    MeasurementSchema[] columnSchemas = new MeasurementSchema[columnList.size() - 1];
-    TSDataType[] dataTypes = new TSDataType[columnList.size() - 1];
-    int nonTimeColumnIndex = 0;
-    long timestamp = -1;
-    for (int i = 0; i < columnList.size(); i++) {
-      TsTableColumnSchema columnSchema = columnList.get(i);
-      Expression expression = expressions.get(i);
-
-      if (columnSchema.getColumnCategory().equals(TIME)) {
-        timestamp = AstUtil.expressionToTimestamp(expression, zoneId);
-      } else {
-        Object value = AstUtil.expressionToTsValue(expression);
-        nonTimeValues[nonTimeColumnIndex] = value;
-        nonTimeColumnNames[nonTimeColumnIndex] = columnSchema.getColumnName();
-        dataTypes[nonTimeColumnIndex] = columnSchema.getDataType();
-        nonTimeColumnCategories[nonTimeColumnIndex] = columnSchema.getColumnCategory();
-        columnSchemas[nonTimeColumnIndex] =
-            new MeasurementSchema(columnSchema.getColumnName(), columnSchema.getDataType());
-        nonTimeColumnIndex++;
-      }
-    }
-
-    TimestampPrecisionUtils.checkTimestampPrecision(timestamp);
-    insertRowStatement.setTime(timestamp);
-    insertRowStatement.setMeasurements(nonTimeColumnNames);
-    insertRowStatement.setDataTypes(dataTypes);
-    insertRowStatement.setMeasurementSchemas(columnSchemas);
-    insertRowStatement.setValues(nonTimeValues);
-    insertRowStatement.setColumnCategories(nonTimeColumnCategories);
-    insertRowStatement.setNeedInferType(false);
-    insertRowStatement.setDatabaseName(databaseName);
-
-    try {
-      insertRowStatement.transferType(zoneId);
-    } catch (QueryProcessException e) {
-      throw new SemanticException(e);
-    }
-    return insertRowStatement;
-  }
-
-  private InsertRowStatement toInsertRowStatement(
-      List<Expression> expressions,
-      int timeColumnIndex,
-      String[] nonTimeColumnNames,
-      String tableName,
-      String databaseName,
-      int columnSize) {
-    InsertRowStatement insertRowStatement = new InsertRowStatement();
-    insertRowStatement.setWriteToTable(true);
-    insertRowStatement.setDevicePath(new PartialPath(new String[] {tableName}));
-    long timestamp;
-    int nonTimeColCnt;
-    if (timeColumnIndex == -1) {
-      timestamp = CommonDateTimeUtils.currentTime();
-      nonTimeColCnt = expressions.size();
-    } else {
-      if (timeColumnIndex >= expressions.size()) {
-        throw new SemanticException(
-            String.format(
-                "TimeColumnIndex out of bound: %d-%d", timeColumnIndex, expressions.size()));
-      }
-
-      Expression timeExpression = expressions.get(timeColumnIndex);
-      if (timeExpression instanceof LongLiteral) {
-        timestamp = ((LongLiteral) timeExpression).getParsedValue();
-      } else if (timeExpression instanceof NullLiteral) {
-        throw new SemanticException(DataNodeQueryMessages.TIMESTAMP_CANNOT_BE_NULL);
-      } else {
-        timestamp =
-            parseDateTimeFormat(
-                ((StringLiteral) timeExpression).getValue(),
-                CommonDateTimeUtils.currentTime(),
-                zoneId);
-      }
-      nonTimeColCnt = expressions.size() - 1;
-    }
-
-    if (nonTimeColCnt != nonTimeColumnNames.length) {
-      throw new SemanticException(
-          String.format(
-              "Inconsistent numbers of non-time column names and values: %d-%d",
-              nonTimeColumnNames.length, nonTimeColCnt));
-    }
-
-    TimestampPrecisionUtils.checkTimestampPrecision(timestamp);
-    insertRowStatement.setTime(timestamp);
-    insertRowStatement.setMeasurements(nonTimeColumnNames);
-
-    Object[] values = new Object[nonTimeColumnNames.length];
-    int valuePos = 0;
-    for (int i = 0; i < expressions.size(); i++) {
-      if (i != timeColumnIndex) {
-        values[valuePos++] = AstUtil.expressionToTsValue(expressions.get(i));
-      }
-    }
-
-    insertRowStatement.setValues(values);
-    insertRowStatement.setNeedInferType(true);
-    insertRowStatement.setDatabaseName(databaseName);
-    return insertRowStatement;
-  }
-
-  @Override
-  public Node visitDeleteStatement(RelationalSqlParser.DeleteStatementContext ctx) {
-    if (ctx.booleanExpression() != null) {
-      return new Delete(
-          getLocation(ctx),
-          new Table(getLocation(ctx), getQualifiedName(ctx.tableName)),
-          (Expression) visit(ctx.booleanExpression()));
-    } else {
-      return new Delete(
-          getLocation(ctx), new Table(getLocation(ctx), getQualifiedName(ctx.tableName)));
-    }
-  }
-
-  @Override
-  public Node visitUpdateStatement(final RelationalSqlParser.UpdateStatementContext ctx) {
-    return new Update(
-        getLocation(ctx),
-        new Table(getLocation(ctx), getQualifiedName(ctx.qualifiedName())),
-        visit(ctx.updateAssignment(), UpdateAssignment.class),
-        Objects.nonNull(ctx.booleanExpression())
-            ? (Expression) visit(ctx.booleanExpression())
-            : null);
-  }
-
-  @Override
-  public Node visitDeleteDeviceStatement(
-      final RelationalSqlParser.DeleteDeviceStatementContext ctx) {
-    return new DeleteDevice(
-        getLocation(ctx),
-        new Table(getLocation(ctx), getQualifiedName(ctx.qualifiedName())),
-        Objects.nonNull(ctx.booleanExpression())
-            ? (Expression) visit(ctx.booleanExpression())
-            : null);
-  }
-
-  @Override
-  public Node visitUpdateAssignment(RelationalSqlParser.UpdateAssignmentContext ctx) {
-    return new UpdateAssignment(
-        (Identifier) visit(ctx.identifier()), (Expression) visit(ctx.expression()));
-  }
-
-  @Override
-  public Node visitCreateFunctionStatement(RelationalSqlParser.CreateFunctionStatementContext ctx) {
-    final String udfName = ((Identifier) visit(ctx.udfName)).getValue();
-    final String className = ((Identifier) visit(ctx.className)).getValue();
-    if (ctx.uriClause() == null) {
-      return new CreateFunction(getLocation(ctx), udfName, className);
-    } else {
-      String uriString = parseAndValidateURI(ctx.uriClause());
-      return new CreateFunction(getLocation(ctx), udfName, className, uriString);
-    }
-  }
-
-  @Override
-  public Node visitUriClause(RelationalSqlParser.UriClauseContext ctx) {
-    return super.visitUriClause(ctx);
-  }
-
-  @Override
-  public Node visitDropFunctionStatement(RelationalSqlParser.DropFunctionStatementContext ctx) {
-    final String udfName = ((Identifier) visit(ctx.udfName)).getValue();
-    return new DropFunction(getLocation(ctx), udfName);
-  }
-
-  @Override
-  public Node visitShowFunctionsStatement(RelationalSqlParser.ShowFunctionsStatementContext ctx) {
-    return new ShowFunctions();
-  }
-
-  @Override
-  public Node visitCreateServiceStatement(RelationalSqlParser.CreateServiceStatementContext ctx) {
-    throw new UnsupportedOperationException(SERVICE_MANAGEMENT_NOT_SUPPORTED);
-  }
-
-  @Override
-  public Node visitStartServiceStatement(RelationalSqlParser.StartServiceStatementContext ctx) {
-    throw new UnsupportedOperationException(SERVICE_MANAGEMENT_NOT_SUPPORTED);
-  }
-
-  @Override
-  public Node visitStopServiceStatement(RelationalSqlParser.StopServiceStatementContext ctx) {
-    throw new UnsupportedOperationException(SERVICE_MANAGEMENT_NOT_SUPPORTED);
-  }
-
-  @Override
-  public Node visitDropServiceStatement(RelationalSqlParser.DropServiceStatementContext ctx) {
-    throw new UnsupportedOperationException(SERVICE_MANAGEMENT_NOT_SUPPORTED);
-  }
-
-  @Override
-  public Node visitShowServiceStatement(RelationalSqlParser.ShowServiceStatementContext ctx) {
-    // show services on all DNs
-    Optional<Expression> where = Optional.empty();
-    if (ctx.ON() != null) {
-      where =
-          Optional.of(
-              new ComparisonExpression(
-                  ComparisonExpression.Operator.EQUAL,
-                  new Identifier(DATA_NODE_ID_TABLE_MODEL),
-                  new LongLiteral(ctx.targetDataNodeId.getText())));
-    }
-    return new ShowExternalService(
-        getLocation(ctx),
-        InformationSchema.SERVICES,
-        where,
-        Optional.empty(),
-        Optional.empty(),
-        Optional.empty());
-  }
-
-  @Override
-  public Node visitLoadTsFileStatement(RelationalSqlParser.LoadTsFileStatementContext ctx) {
-    final Map<String, String> withAttributes =
-        ctx.loadFileWithAttributesClause() != null
-            ? parseLoadFileWithAttributeClauses(
-                ctx.loadFileWithAttributesClause().loadFileWithAttributeClause())
-            : new HashMap<>();
-
-    withAttributes.forEach(LoadTsFileConfigurator::validateParameters);
-    LoadTsFileConfigurator.validateSynonymParameters(withAttributes);
-    return new LoadTsFile(
-        getLocation(ctx), ((StringLiteral) visit(ctx.fileName)).getValue(), withAttributes);
-  }
-
-  private Map<String, String> parseLoadFileWithAttributeClauses(
-      List<RelationalSqlParser.LoadFileWithAttributeClauseContext> contexts) {
-    final Map<String, String> withAttributesMap = new HashMap<>();
-    for (RelationalSqlParser.LoadFileWithAttributeClauseContext context : contexts) {
-      withAttributesMap.put(
-          ((StringLiteral) visit(context.loadFileWithKey)).getValue(),
-          ((StringLiteral) visit(context.loadFileWithValue)).getValue());
-    }
-    return withAttributesMap;
-  }
-
-  @Override
-  public Node visitCreatePipeStatement(RelationalSqlParser.CreatePipeStatementContext ctx) {
-    final String pipeName = ((Identifier) visit(ctx.identifier())).getValue();
-    final boolean hasIfNotExistsCondition =
-        ctx.IF() != null && ctx.NOT() != null && ctx.EXISTS() != null;
-
-    final Map<String, String> extractorAttributes =
-        ctx.extractorAttributesClause() != null
-            ? parseExtractorAttributesClause(
-                ctx.extractorAttributesClause().extractorAttributeClause())
-            : new HashMap<>(); // DO NOT USE Collections.emptyMap() here
-    final Map<String, String> processorAttributes =
-        ctx.processorAttributesClause() != null
-            ? parseProcessorAttributesClause(
-                ctx.processorAttributesClause().processorAttributeClause())
-            : new HashMap<>(); // DO NOT USE Collections.emptyMap() here
-    final Map<String, String> connectorAttributes =
-        ctx.connectorAttributesClause() != null
-            ? parseConnectorAttributesClause(
-                ctx.connectorAttributesClause().connectorAttributeClause())
-            : parseConnectorAttributesClause(
-                ctx.connectorAttributesWithoutWithSinkClause().connectorAttributeClause());
-
-    return new CreatePipe(
-        pipeName,
-        hasIfNotExistsCondition,
-        extractorAttributes,
-        processorAttributes,
-        connectorAttributes);
-  }
-
-  private Map<String, String> parseExtractorAttributesClause(
-      List<RelationalSqlParser.ExtractorAttributeClauseContext> contexts) {
-    final Map<String, String> extractorMap = new HashMap<>();
-    for (RelationalSqlParser.ExtractorAttributeClauseContext context : contexts) {
-      extractorMap.put(
-          ((StringLiteral) visit(context.extractorKey)).getValue(),
-          ((StringLiteral) visit(context.extractorValue)).getValue());
-    }
-    return extractorMap;
-  }
-
-  private Map<String, String> parseProcessorAttributesClause(
-      List<RelationalSqlParser.ProcessorAttributeClauseContext> contexts) {
-    final Map<String, String> processorMap = new HashMap<>();
-    for (RelationalSqlParser.ProcessorAttributeClauseContext context : contexts) {
-      processorMap.put(
-          ((StringLiteral) visit(context.processorKey)).getValue(),
-          ((StringLiteral) visit(context.processorValue)).getValue());
-    }
-    return processorMap;
-  }
-
-  private Map<String, String> parseConnectorAttributesClause(
-      List<RelationalSqlParser.ConnectorAttributeClauseContext> contexts) {
-    final Map<String, String> connectorMap = new HashMap<>();
-    for (RelationalSqlParser.ConnectorAttributeClauseContext context : contexts) {
-      connectorMap.put(
-          ((StringLiteral) visit(context.connectorKey)).getValue(),
-          ((StringLiteral) visit(context.connectorValue)).getValue());
-    }
-    return connectorMap;
-  }
-
-  @Override
-  public Node visitAlterPipeStatement(RelationalSqlParser.AlterPipeStatementContext ctx) {
-    final String pipeName = ((Identifier) visit(ctx.identifier())).getValue();
-    final boolean hasIfExistsCondition = ctx.IF() != null && ctx.EXISTS() != null;
-
-    final Map<String, String> extractorAttributes;
-    final boolean isReplaceAllExtractorAttributes;
-    if (ctx.alterExtractorAttributesClause() != null) {
-      extractorAttributes =
-          parseExtractorAttributesClause(
-              ctx.alterExtractorAttributesClause().extractorAttributeClause());
-      isReplaceAllExtractorAttributes =
-          Objects.nonNull(ctx.alterExtractorAttributesClause().REPLACE());
-    } else {
-      extractorAttributes = new HashMap<>(); // DO NOT USE Collections.emptyMap() here
-      isReplaceAllExtractorAttributes = false;
-    }
-
-    final Map<String, String> processorAttributes;
-    final boolean isReplaceAllProcessorAttributes;
-    if (ctx.alterProcessorAttributesClause() != null) {
-      processorAttributes =
-          parseProcessorAttributesClause(
-              ctx.alterProcessorAttributesClause().processorAttributeClause());
-      isReplaceAllProcessorAttributes =
-          Objects.nonNull(ctx.alterProcessorAttributesClause().REPLACE());
-    } else {
-      processorAttributes = new HashMap<>(); // DO NOT USE Collections.emptyMap() here
-      isReplaceAllProcessorAttributes = false;
-    }
-
-    final Map<String, String> connectorAttributes;
-    final boolean isReplaceAllConnectorAttributes;
-    if (ctx.alterConnectorAttributesClause() != null) {
-      connectorAttributes =
-          parseConnectorAttributesClause(
-              ctx.alterConnectorAttributesClause().connectorAttributeClause());
-      isReplaceAllConnectorAttributes =
-          Objects.nonNull(ctx.alterConnectorAttributesClause().REPLACE());
-    } else {
-      connectorAttributes = new HashMap<>(); // DO NOT USE Collections.emptyMap() here
-      isReplaceAllConnectorAttributes = false;
-    }
-
-    return new AlterPipe(
-        pipeName,
-        hasIfExistsCondition,
-        extractorAttributes,
-        processorAttributes,
-        connectorAttributes,
-        isReplaceAllExtractorAttributes,
-        isReplaceAllProcessorAttributes,
-        isReplaceAllConnectorAttributes);
-  }
-
-  @Override
-  public Node visitDropPipeStatement(RelationalSqlParser.DropPipeStatementContext ctx) {
-    final String pipeName = ((Identifier) visit(ctx.identifier())).getValue();
-    final boolean hasIfExistsCondition = ctx.IF() != null && ctx.EXISTS() != null;
-    return new DropPipe(pipeName, hasIfExistsCondition);
-  }
-
-  @Override
-  public Node visitStartPipeStatement(RelationalSqlParser.StartPipeStatementContext ctx) {
-    return new StartPipe(((Identifier) visit(ctx.identifier())).getValue());
-  }
-
-  @Override
-  public Node visitStopPipeStatement(RelationalSqlParser.StopPipeStatementContext ctx) {
-    return new StopPipe(((Identifier) visit(ctx.identifier())).getValue());
-  }
-
-  @Override
-  public Node visitShowPipesStatement(RelationalSqlParser.ShowPipesStatementContext ctx) {
-    final String pipeName =
-        getIdentifierIfPresent(ctx.identifier()).map(Identifier::getValue).orElse(null);
-    final boolean hasWhereClause = ctx.WHERE() != null;
-    return new ShowPipes(pipeName, hasWhereClause);
-  }
-
-  @Override
-  public Node visitCreatePipePluginStatement(
-      RelationalSqlParser.CreatePipePluginStatementContext ctx) {
-    final String pluginName = ((Identifier) visit(ctx.identifier())).getValue();
-    final boolean hasIfNotExistsCondition =
-        ctx.IF() != null && ctx.NOT() != null && ctx.EXISTS() != null;
-    final String className = ((StringLiteral) visit(ctx.className)).getValue();
-    final String uriString = parseAndValidateURI(ctx.uriClause());
-    return new CreatePipePlugin(pluginName, hasIfNotExistsCondition, className, uriString);
-  }
-
-  private String parseAndValidateURI(RelationalSqlParser.UriClauseContext ctx) {
-    final String uriString =
-        ctx.uri.identifier() != null
-            ? ((Identifier) visit(ctx.uri.identifier())).getValue()
-            : ((StringLiteral) visit(ctx.uri.string())).getValue();
-    try {
-      new URI(uriString);
-    } catch (URISyntaxException e) {
-      throw new SemanticException(String.format(DataNodeQueryMessages.INVALID_URI, uriString));
-    }
-    return uriString;
-  }
-
-  @Override
-  public Node visitDropPipePluginStatement(RelationalSqlParser.DropPipePluginStatementContext ctx) {
-    final String pluginName = ((Identifier) visit(ctx.identifier())).getValue();
-    final boolean hasIfExistsCondition = ctx.IF() != null && ctx.EXISTS() != null;
-    return new DropPipePlugin(pluginName, hasIfExistsCondition);
-  }
-
-  @Override
-  public Node visitShowPipePluginsStatement(
-      RelationalSqlParser.ShowPipePluginsStatementContext ctx) {
-    return new ShowPipePlugins();
-  }
-
-  @Override
-  public Node visitCreateTopicStatement(RelationalSqlParser.CreateTopicStatementContext ctx) {
-    final String topicName = ((Identifier) visit(ctx.identifier())).getValue();
-    final boolean hasIfNotExistsCondition =
-        ctx.IF() != null && ctx.NOT() != null && ctx.EXISTS() != null;
-
-    final Map<String, String> topicAttributes =
-        ctx.topicAttributesClause() != null
-            ? parseTopicAttributesClause(ctx.topicAttributesClause().topicAttributeClause())
-            : new HashMap<>(); // DO NOT USE Collections.emptyMap() here
-
-    return new CreateTopic(topicName, hasIfNotExistsCondition, topicAttributes);
-  }
-
-  private Map<String, String> parseTopicAttributesClause(
-      List<RelationalSqlParser.TopicAttributeClauseContext> contexts) {
-    final Map<String, String> tppicMap = new HashMap<>();
-    for (RelationalSqlParser.TopicAttributeClauseContext context : contexts) {
-      tppicMap.put(
-          ((StringLiteral) visit(context.topicKey)).getValue(),
-          ((StringLiteral) visit(context.topicValue)).getValue());
-    }
-    return tppicMap;
-  }
-
-  @Override
-  public Node visitDropTopicStatement(RelationalSqlParser.DropTopicStatementContext ctx) {
-    final String topicName = ((Identifier) visit(ctx.identifier())).getValue();
-    final boolean hasIfExistsCondition = ctx.IF() != null && ctx.EXISTS() != null;
-    return new DropTopic(topicName, hasIfExistsCondition);
-  }
-
-  @Override
-  public Node visitShowTopicsStatement(RelationalSqlParser.ShowTopicsStatementContext ctx) {
-    final String topicName =
-        getIdentifierIfPresent(ctx.identifier()).map(Identifier::getValue).orElse(null);
-    return new ShowTopics(topicName);
-  }
-
-  @Override
-  public Node visitShowSubscriptionsStatement(
-      RelationalSqlParser.ShowSubscriptionsStatementContext ctx) {
-    final String topicName =
-        getIdentifierIfPresent(ctx.identifier()).map(Identifier::getValue).orElse(null);
-    return new ShowSubscriptions(topicName);
-  }
-
-  @Override
-  public Node visitDropSubscriptionStatement(
-      RelationalSqlParser.DropSubscriptionStatementContext ctx) {
-    final String subscriptionId = ((Identifier) visit(ctx.identifier())).getValue();
-    final boolean hasIfExistsCondition = ctx.IF() != null && ctx.EXISTS() != null;
-    return new DropSubscription(subscriptionId, hasIfExistsCondition);
-  }
-
-  @Override
-  public Node visitShowDevicesStatement(final RelationalSqlParser.ShowDevicesStatementContext ctx) {
-    final QualifiedName name = getQualifiedName(ctx.tableName);
-    return InformationSchema.INFORMATION_DATABASE.equals(
-            name.getPrefix().map(QualifiedName::toString).orElse(clientSession.getDatabaseName()))
-        ? new ShowStatement(
-            getLocation(ctx),
-            name.getSuffix(),
-            visitIfPresent(ctx.where, Expression.class),
-            Optional.empty(),
-            visitIfPresent(ctx.limitOffsetClause().offset, Offset.class),
-            visitIfPresent(ctx.limitOffsetClause().limit, Node.class))
-        : new ShowDevice(
-            getLocation(ctx),
-            new Table(getLocation(ctx), name),
-            visitIfPresent(ctx.where, Expression.class).orElse(null),
-            visitIfPresent(ctx.limitOffsetClause().offset, Offset.class).orElse(null),
-            visitIfPresent(ctx.limitOffsetClause().limit, Node.class).orElse(null));
-  }
-
-  @Override
-  public Node visitCountDevicesStatement(
-      final RelationalSqlParser.CountDevicesStatementContext ctx) {
-    final QualifiedName name = getQualifiedName(ctx.tableName);
-    return InformationSchema.INFORMATION_DATABASE.equals(
-            name.getPrefix().map(QualifiedName::toString).orElse(clientSession.getDatabaseName()))
-        ? new CountStatement(
-            getLocation(ctx), name.getSuffix(), visitIfPresent(ctx.where, Expression.class))
-        : new CountDevice(
-            getLocation(ctx),
-            new Table(getLocation(ctx), name),
-            visitIfPresent(ctx.where, Expression.class).orElse(null));
-  }
-
-  @Override
-  public Node visitShowClusterStatement(RelationalSqlParser.ShowClusterStatementContext ctx) {
-    boolean details = ctx.DETAILS() != null;
-    return new ShowCluster(details);
-  }
-
-  @Override
-  public Node visitShowRegionsStatement(RelationalSqlParser.ShowRegionsStatementContext ctx) {
-    TConsensusGroupType regionType = null;
-    if (ctx.DATA() != null) {
-      regionType = TConsensusGroupType.DataRegion;
-    } else if (ctx.SCHEMA() != null) {
-      regionType = TConsensusGroupType.SchemaRegion;
-    }
-    return new ShowRegions(
-        regionType,
-        Objects.nonNull(ctx.identifier())
-            ? ((Identifier) visit(ctx.identifier())).getValue()
-            : null,
-        null);
-  }
-
-  @Override
-  public Node visitShowDataNodesStatement(RelationalSqlParser.ShowDataNodesStatementContext ctx) {
-    return new ShowDataNodes();
-  }
-
-  @Override
-  public Node visitShowAvailableUrlsStatement(
-      RelationalSqlParser.ShowAvailableUrlsStatementContext ctx) {
-    return new ShowAvailableUrls();
-  }
-
-  @Override
-  public Node visitShowConfigNodesStatement(
-      RelationalSqlParser.ShowConfigNodesStatementContext ctx) {
-    return new ShowConfigNodes();
-  }
-
-  @Override
-  public Node visitShowAINodesStatement(RelationalSqlParser.ShowAINodesStatementContext ctx) {
-    return new ShowAINodes();
-  }
-
-  @Override
-  public Node visitShowClusterIdStatement(RelationalSqlParser.ShowClusterIdStatementContext ctx) {
-    return new ShowClusterId(getLocation(ctx));
-  }
-
-  @Override
-  public Node visitShowRegionIdStatement(RelationalSqlParser.ShowRegionIdStatementContext ctx) {
-    throw new SemanticException(DataNodeQueryMessages.SHOW_REGION_ID_IS_NOT_SUPPORTED_YET);
-  }
-
-  @Override
-  public Node visitShowTimeSlotListStatement(
-      RelationalSqlParser.ShowTimeSlotListStatementContext ctx) {
-    throw new SemanticException(DataNodeQueryMessages.SHOW_TIME_SLOT_IS_NOT_SUPPORTED_YET);
-  }
-
-  @Override
-  public Node visitCountTimeSlotListStatement(
-      RelationalSqlParser.CountTimeSlotListStatementContext ctx) {
-    throw new SemanticException(DataNodeQueryMessages.COUNT_TIME_SLOT_IS_NOT_SUPPORTED_YET);
-  }
-
-  @Override
-  public Node visitShowSeriesSlotListStatement(
-      RelationalSqlParser.ShowSeriesSlotListStatementContext ctx) {
-    throw new SemanticException(DataNodeQueryMessages.SHOW_SERIES_SLOT_IS_NOT_SUPPORTED_YET);
-  }
-
-  @Override
-  public Node visitMigrateRegionStatement(RelationalSqlParser.MigrateRegionStatementContext ctx) {
-    return new MigrateRegion(
-        Integer.parseInt(ctx.regionId.getText()),
-        Integer.parseInt(ctx.fromId.getText()),
-        Integer.parseInt(ctx.toId.getText()));
-  }
-
-  @Override
-  public Node visitReconstructRegionStatement(
-      RelationalSqlParser.ReconstructRegionStatementContext ctx) {
-    int dataNodeId = Integer.parseInt(ctx.targetDataNodeId.getText());
-    List<Integer> regionIds =
-        ctx.regionIds.stream()
-            .map(Token::getText)
-            .map(Integer::parseInt)
-            .collect(Collectors.toList());
-    return new ReconstructRegion(dataNodeId, regionIds);
-  }
-
-  @Override
-  public Node visitExtendRegionStatement(RelationalSqlParser.ExtendRegionStatementContext ctx) {
-    List<Integer> regionIds =
-        ctx.regionIds.stream().map(token -> Integer.parseInt(token.getText())).collect(toList());
-    return new ExtendRegion(regionIds, Integer.parseInt(ctx.targetDataNodeId.getText()));
-  }
-
-  @Override
-  public Node visitRemoveRegionStatement(RelationalSqlParser.RemoveRegionStatementContext ctx) {
-    List<Integer> regionIds =
-        ctx.regionIds.stream().map(token -> Integer.parseInt(token.getText())).collect(toList());
-    return new RemoveRegion(regionIds, Integer.parseInt(ctx.targetDataNodeId.getText()));
-  }
-
-  @Override
-  public Node visitRemoveDataNodeStatement(RelationalSqlParser.RemoveDataNodeStatementContext ctx) {
-    List<Integer> nodeIds =
-        Collections.singletonList(Integer.parseInt(ctx.INTEGER_VALUE().getText()));
-    return new RemoveDataNode(nodeIds);
-  }
-
-  @Override
-  public Node visitRemoveConfigNodeStatement(
-      RelationalSqlParser.RemoveConfigNodeStatementContext ctx) {
-    Integer nodeId = Integer.parseInt(ctx.INTEGER_VALUE().getText());
-    return new RemoveConfigNode(nodeId);
-  }
-
-  @Override
-  public Node visitRemoveAINodeStatement(RelationalSqlParser.RemoveAINodeStatementContext ctx) {
-    return new RemoveAINode();
-  }
-
-  @Override
-  public Node visitFlushStatement(final RelationalSqlParser.FlushStatementContext ctx) {
-    final FlushStatement flushStatement = new FlushStatement(StatementType.FLUSH);
-    List<String> databases = null;
-    if (ctx.booleanValue() != null) {
-      flushStatement.setSeq(Boolean.parseBoolean(ctx.booleanValue().getText()));
-    }
-    flushStatement.setOnCluster(
-        ctx.localOrClusterMode() == null || ctx.localOrClusterMode().LOCAL() == null);
-    if (ctx.identifier() != null) {
-      databases =
-          getIdentifiers(ctx.identifier()).stream().map(Identifier::getValue).collect(toList());
-    }
-    flushStatement.setDatabases(databases);
-    return new Flush(flushStatement, null);
-  }
-
-  @Override
-  public Node visitClearCacheStatement(final RelationalSqlParser.ClearCacheStatementContext ctx) {
-    final Set<CacheClearOptions> options;
-    final RelationalSqlParser.ClearCacheOptionsContext context = ctx.clearCacheOptions();
-
-    if (Objects.isNull(context)) {
-      options = Collections.singleton(CacheClearOptions.DEFAULT);
-    } else if (context.ATTRIBUTE() != null) {
-      options = Collections.singleton(CacheClearOptions.TABLE_ATTRIBUTE);
-    } else if (context.QUERY() != null) {
-      options = Collections.singleton(CacheClearOptions.QUERY);
-    } else if (context.AUTH() != null) {
-      options = Collections.singleton(CacheClearOptions.AUTH);
-    } else {
-      options =
-          new HashSet<>(
-              Arrays.asList(
-                  CacheClearOptions.TABLE_ATTRIBUTE,
-                  CacheClearOptions.TREE_SCHEMA,
-                  CacheClearOptions.QUERY,
-                  CacheClearOptions.AUTH));
-    }
-    return new ClearCache(
-        Objects.isNull(ctx.localOrClusterMode())
-            || Objects.nonNull(ctx.localOrClusterMode().CLUSTER()),
-        options);
-  }
-
-  @Override
-  public Node visitSetSystemStatusStatement(
-      RelationalSqlParser.SetSystemStatusStatementContext ctx) {
-    SetSystemStatusStatement setSystemStatusStatement = new SetSystemStatusStatement();
-    setSystemStatusStatement.setOnCluster(
-        ctx.localOrClusterMode() == null || ctx.localOrClusterMode().LOCAL() == null);
-    if (ctx.RUNNING() != null) {
-      setSystemStatusStatement.setStatus(NodeStatus.Running);
-    } else if (ctx.READONLY() != null) {
-      setSystemStatusStatement.setStatus(NodeStatus.ReadOnly);
-    } else {
-      throw new SemanticException(
-          DataNodeQueryMessages.UNKNOWN_SYSTEM_STATUS_IN_SET_SYSTEM_COMMAND);
-    }
-    return new SetSystemStatus(setSystemStatusStatement, null);
-  }
-
-  @Override
-  public Node visitShowVersionStatement(RelationalSqlParser.ShowVersionStatementContext ctx) {
-    return new ShowVersion(getLocation(ctx));
-  }
-
-  @Override
-  public Node visitShowCurrentSqlDialectStatement(
-      RelationalSqlParser.ShowCurrentSqlDialectStatementContext ctx) {
-    return new ShowCurrentSqlDialect(getLocation(ctx));
-  }
-
-  @Override
-  public Node visitSetSqlDialectStatement(RelationalSqlParser.SetSqlDialectStatementContext ctx) {
-    return new SetSqlDialect(
-        ctx.TABLE() == null ? SqlDialect.TREE : SqlDialect.TABLE, getLocation(ctx));
-  }
-
-  @Override
-  public Node visitShowCurrentDatabaseStatement(
-      RelationalSqlParser.ShowCurrentDatabaseStatementContext ctx) {
-    return new ShowCurrentDatabase(getLocation(ctx));
-  }
-
-  @Override
-  public Node visitShowCurrentUserStatement(
-      RelationalSqlParser.ShowCurrentUserStatementContext ctx) {
-    return new ShowCurrentUser(getLocation(ctx));
-  }
-
-  @Override
-  public Node visitShowVariablesStatement(RelationalSqlParser.ShowVariablesStatementContext ctx) {
-    return new ShowVariables(getLocation(ctx));
-  }
-
-  @Override
-  public Node visitShowCurrentTimestampStatement(
-      RelationalSqlParser.ShowCurrentTimestampStatementContext ctx) {
-    return new ShowCurrentTimestamp(getLocation(ctx));
-  }
-
-  @Override
-  public Node visitShowQueriesStatement(RelationalSqlParser.ShowQueriesStatementContext ctx) {
-    Optional<OrderBy> orderBy = Optional.empty();
-    if (ctx.ORDER() != null) {
-      orderBy =
-          Optional.of(new OrderBy(getLocation(ctx.ORDER()), visit(ctx.sortItem(), SortItem.class)));
-    }
-
-    Optional<Offset> offset = Optional.empty();
-    if (ctx.limitOffsetClause().OFFSET() != null) {
-      offset = visitIfPresent(ctx.limitOffsetClause().offset, Offset.class);
-    }
-
-    Optional<Node> limit = Optional.empty();
-    if (ctx.limitOffsetClause().LIMIT() != null) {
-      if (ctx.limitOffsetClause().limit == null) {
-        throw new IllegalStateException(DataNodeQueryMessages.MISSING_LIMIT_VALUE);
-      }
-      limit = visitIfPresent(ctx.limitOffsetClause().limit, Node.class);
-    }
-
-    return new ShowQueriesStatement(
-        getLocation(ctx),
-        InformationSchema.QUERIES,
-        visitIfPresent(ctx.where, Expression.class),
-        orderBy,
-        offset,
-        limit);
-  }
-
-  @Override
-  public Node visitKillQueryStatement(RelationalSqlParser.KillQueryStatementContext ctx) {
-    if (ctx.queryId == null) {
-      return new KillQuery(null, getLocation(ctx));
-    }
-    return new KillQuery(((StringLiteral) visit(ctx.queryId)).getValue(), getLocation(ctx));
-  }
-
-  @Override
-  public Node visitLoadConfigurationStatement(
-      RelationalSqlParser.LoadConfigurationStatementContext ctx) {
-    LoadConfigurationStatement loadConfigurationStatement =
-        new LoadConfigurationStatement(StatementType.LOAD_CONFIGURATION);
-    loadConfigurationStatement.setOnCluster(
-        ctx.localOrClusterMode() == null || ctx.localOrClusterMode().LOCAL() == null);
-    return new LoadConfiguration(loadConfigurationStatement, null);
-  }
-
-  @Override
-  public Node visitSetConfigurationStatement(
-      RelationalSqlParser.SetConfigurationStatementContext ctx) {
-    SetConfigurationStatement setConfigurationStatement =
-        new SetConfigurationStatement(StatementType.SET_CONFIGURATION);
-    int nodeId =
-        Integer.parseInt(ctx.INTEGER_VALUE() == null ? "-1" : ctx.INTEGER_VALUE().getText());
-    Map<String, String> configItems = new HashMap<>();
-    List<Property> properties = ImmutableList.of();
-    if (ctx.propertyAssignments() != null) {
-      properties = visit(ctx.propertyAssignments().property(), Property.class);
-    }
-    for (Property property : properties) {
-      String key = property.getName().getValue();
-      Expression propertyValue = property.getNonDefaultValue();
-      if (!propertyValue.getExpressionType().equals(TableExpressionType.STRING_LITERAL)) {
-        throw new SemanticException(
-            propertyValue.getExpressionType()
-                + " is not supported for property value of 'set configuration'. "
-                + "Note that the syntax for 'set configuration' in the tree model is not exactly the same as that in the table model.");
-      }
-      String value = ((StringLiteral) propertyValue).getValue();
-      configItems.put(key.trim(), value.trim());
-    }
-    setConfigurationStatement.setNodeId(nodeId);
-    setConfigurationStatement.setConfigItems(configItems);
-    return new SetConfiguration(setConfigurationStatement, null);
-  }
-
-  @Override
-  public Node visitShowConfigurationStatement(
-      RelationalSqlParser.ShowConfigurationStatementContext ctx) {
-    ShowConfigurationStatement showConfigurationStatement;
-    boolean withDescription = ctx.DESC() != null;
-    boolean showAllConfiguration = (ctx.ALL() != null);
-    int nodeId = ctx.nodeId == null ? -1 : Integer.parseInt(ctx.nodeId.getText());
-    showConfigurationStatement =
-        new ShowConfigurationStatement(showAllConfiguration, nodeId, withDescription);
-    return new ShowConfiguration(showConfigurationStatement, null);
-  }
-
-  @Override
-  public Node visitStartRepairDataStatement(
-      RelationalSqlParser.StartRepairDataStatementContext ctx) {
-    StartRepairDataStatement startRepairDataStatement =
-        new StartRepairDataStatement(StatementType.START_REPAIR_DATA);
-    startRepairDataStatement.setOnCluster(
-        ctx.localOrClusterMode() == null || ctx.localOrClusterMode().LOCAL() == null);
-    return new StartRepairData(startRepairDataStatement, null);
-  }
-
-  @Override
-  public Node visitStopRepairDataStatement(RelationalSqlParser.StopRepairDataStatementContext ctx) {
-    StopRepairDataStatement stopRepairDataStatement =
-        new StopRepairDataStatement(StatementType.STOP_REPAIR_DATA);
-    stopRepairDataStatement.setOnCluster(
-        ctx.localOrClusterMode() == null || ctx.localOrClusterMode().LOCAL() == null);
-    return new StopRepairData(stopRepairDataStatement, null);
-  }
-
-  @Override
-  public Node visitLocalOrClusterMode(RelationalSqlParser.LocalOrClusterModeContext ctx) {
-    return super.visitLocalOrClusterMode(ctx);
-  }
-
-  @Override
-  public Node visitStatementDefault(RelationalSqlParser.StatementDefaultContext ctx) {
-    return super.visitStatementDefault(ctx);
-  }
-
-  @Override
-  public Node visitExplain(RelationalSqlParser.ExplainContext ctx) {
-    Statement innerStatement;
-    if (ctx.query() != null) {
-      innerStatement = (Statement) visit(ctx.query());
-    } else if (ctx.executeStatement() != null) {
-      innerStatement = (Statement) visit(ctx.executeStatement());
-    } else {
-      innerStatement = (Statement) visit(ctx.executeImmediateStatement());
-    }
-    return new Explain(getLocation(ctx), innerStatement);
-  }
-
-  @Override
-  public Node visitExplainAnalyze(RelationalSqlParser.ExplainAnalyzeContext ctx) {
-    Statement innerStatement;
-    if (ctx.query() != null) {
-      innerStatement = (Statement) visit(ctx.query());
-    } else if (ctx.executeStatement() != null) {
-      innerStatement = (Statement) visit(ctx.executeStatement());
-    } else {
-      innerStatement = (Statement) visit(ctx.executeImmediateStatement());
-    }
-    return new ExplainAnalyze(getLocation(ctx), ctx.VERBOSE() != null, innerStatement);
-  }
-
-  // ********************** author expressions ********************
-  private String parseUsernameWithRoot(RelationalSqlParser.UsernameWithRootContext ctx) {
-    String src =
-        ctx.identifier() != null ? ((Identifier) visit(ctx.identifier())).getValue() : "root";
-    if (src.startsWith(TsFileConstant.BACK_QUOTE_STRING)
-        && src.endsWith(TsFileConstant.BACK_QUOTE_STRING)) {
-      src =
-          src.substring(1, src.length() - 1)
-              .replace(TsFileConstant.DOUBLE_BACK_QUOTE_STRING, TsFileConstant.BACK_QUOTE_STRING);
-    }
-    return src;
-  }
-
-  @Override
-  public Node visitCreateUserStatement(RelationalSqlParser.CreateUserStatementContext ctx) {
-    RelationalAuthorStatement stmt = new RelationalAuthorStatement(AuthorRType.CREATE_USER);
-    stmt.setUserName(parseUsernameWithRoot(ctx.userName));
-    String password = ((StringLiteral) visit(ctx.password)).getValue();
-    stmt.setPassword(password);
-    return stmt;
-  }
-
-  @Override
-  public Node visitCreateRoleStatement(RelationalSqlParser.CreateRoleStatementContext ctx) {
-    RelationalAuthorStatement stmt = new RelationalAuthorStatement(AuthorRType.CREATE_ROLE);
-    stmt.setRoleName(((Identifier) visit(ctx.roleName)).getValue());
-    return stmt;
-  }
-
-  @Override
-  public Node visitDropUserStatement(RelationalSqlParser.DropUserStatementContext ctx) {
-    RelationalAuthorStatement stmt = new RelationalAuthorStatement(AuthorRType.DROP_USER);
-    stmt.setUserName(parseUsernameWithRoot(ctx.userName));
-    return stmt;
-  }
-
-  @Override
-  public Node visitDropRoleStatement(RelationalSqlParser.DropRoleStatementContext ctx) {
-    RelationalAuthorStatement stmt = new RelationalAuthorStatement(AuthorRType.DROP_ROLE);
-    stmt.setRoleName(((Identifier) visit(ctx.roleName)).getValue());
-    return stmt;
-  }
-
-  @Override
-  public Node visitAlterUserStatement(RelationalSqlParser.AlterUserStatementContext ctx) {
-    RelationalAuthorStatement stmt = new RelationalAuthorStatement(AuthorRType.UPDATE_USER);
-    stmt.setUserName(parseUsernameWithRoot(ctx.userName));
-    String password = ((StringLiteral) visit(ctx.password)).getValue();
-    stmt.setPassword(password);
-    return stmt;
-  }
-
-  // Unlock User
-  @Override
-  public Node visitAlterUserAccountUnlockStatement(
-      RelationalSqlParser.AlterUserAccountUnlockStatementContext ctx) {
-    String usernameWithRootWithOptionalHost = ctx.usernameWithRootWithOptionalHost().getText();
-    String[] parts = usernameWithRootWithOptionalHost.split("@", 2);
-    String username = parts[0];
-    String host = parts.length > 1 ? parts[1] : null;
-
-    RelationalAuthorStatement stmt = new RelationalAuthorStatement(AuthorRType.ACCOUNT_UNLOCK);
-    stmt.setUserName(parseIdentifier(username));
-    if (host != null) {
-      stmt.setLoginAddr(parseStringLiteral(host));
-    }
-    return stmt;
-  }
-
-  @Override
-  public Node visitRenameUserStatement(RelationalSqlParser.RenameUserStatementContext ctx) {
-    RelationalAuthorStatement stmt = new RelationalAuthorStatement(AuthorRType.RENAME_USER);
-    stmt.setUserName(parseUsernameWithRoot(ctx.username));
-    stmt.setNewUsername(parseUsernameWithRoot(ctx.newUsername));
-    return stmt;
-  }
-
-  @Override
-  public Node visitGrantUserRoleStatement(RelationalSqlParser.GrantUserRoleStatementContext ctx) {
-    RelationalAuthorStatement stmt = new RelationalAuthorStatement(AuthorRType.GRANT_USER_ROLE);
-    stmt.setUserName(parseUsernameWithRoot(ctx.userName));
-    stmt.setRoleName(((Identifier) visit(ctx.roleName)).getValue());
-    return stmt;
-  }
-
-  @Override
-  public Node visitRevokeUserRoleStatement(RelationalSqlParser.RevokeUserRoleStatementContext ctx) {
-    RelationalAuthorStatement stmt = new RelationalAuthorStatement(AuthorRType.REVOKE_USER_ROLE);
-    stmt.setUserName(parseUsernameWithRoot(ctx.userName));
-    stmt.setRoleName(((Identifier) visit(ctx.roleName)).getValue());
-    return stmt;
-  }
-
-  @Override
-  public Node visitListUserPrivilegeStatement(
-      RelationalSqlParser.ListUserPrivilegeStatementContext ctx) {
-    RelationalAuthorStatement stmt = new RelationalAuthorStatement(AuthorRType.LIST_USER_PRIV);
-    stmt.setUserName(parseUsernameWithRoot(ctx.userName));
-    return stmt;
-  }
-
-  @Override
-  public Node visitListRolePrivilegeStatement(
-      RelationalSqlParser.ListRolePrivilegeStatementContext ctx) {
-    RelationalAuthorStatement stmt = new RelationalAuthorStatement(AuthorRType.LIST_ROLE_PRIV);
-    stmt.setRoleName(((Identifier) visit(ctx.roleName)).getValue());
-    return stmt;
-  }
-
-  @Override
-  public Node visitListUserStatement(RelationalSqlParser.ListUserStatementContext ctx) {
-    RelationalAuthorStatement stmt = new RelationalAuthorStatement(AuthorRType.LIST_USER);
-    if (ctx.OF() != null) {
-      stmt.setRoleName(((Identifier) visit(ctx.roleName)).getValue());
-    }
-    return stmt;
-  }
-
-  @Override
-  public Node visitListRoleStatement(RelationalSqlParser.ListRoleStatementContext ctx) {
-    RelationalAuthorStatement stmt = new RelationalAuthorStatement(AuthorRType.LIST_ROLE);
-    if (ctx.OF() != null) {
-      stmt.setUserName(parseUsernameWithRoot(ctx.userName));
-    }
-    return stmt;
-  }
-
-  private Set<PrivilegeType> parseSystemPrivilege(RelationalSqlParser.SystemPrivilegesContext ctx) {
-    List<RelationalSqlParser.SystemPrivilegeContext> privilegeContexts = ctx.systemPrivilege();
-    Set<PrivilegeType> privileges = new HashSet<>();
-    for (RelationalSqlParser.SystemPrivilegeContext privilege : privilegeContexts) {
-      PrivilegeType privilegeType = PrivilegeType.valueOf(privilege.getText().toUpperCase());
-      if (privilegeType.isDeprecated()) {
-        throw new SemanticException(
-            "Privilege type "
-                + privilege.getText().toUpperCase()
-                + " is deprecated, use "
-                + privilegeType.getReplacedPrivilegeType()
-                + " to instead it");
-      }
-      privileges.add(privilegeType);
-    }
-    return privileges;
-  }
-
-  private Set<PrivilegeType> parseRelationalPrivilege(
-      RelationalSqlParser.ObjectPrivilegesContext ctx) {
-    Set<PrivilegeType> privileges = new HashSet<>();
-    if (ctx.ALL() != null) {
-      for (PrivilegeType privilegeType : PrivilegeType.values()) {
-        if (privilegeType.isRelationalPrivilege()) {
-          privileges.add(privilegeType);
-        }
-      }
-    } else {
-      List<RelationalSqlParser.ObjectPrivilegeContext> privilegeContexts = ctx.objectPrivilege();
-      for (RelationalSqlParser.ObjectPrivilegeContext privilege : privilegeContexts) {
-        privileges.add(PrivilegeType.valueOf(privilege.getText().toUpperCase()));
-      }
-    }
-    return privileges;
-  }
-
-  @Override
-  public Node visitGrantStatement(RelationalSqlParser.GrantStatementContext ctx) {
-    boolean toUser;
-    String name;
-    toUser = ctx.holderType().getText().equalsIgnoreCase("user");
-    name = (((Identifier) visit(ctx.holderName)).getValue());
-    if (!CommonDescriptor.getInstance().getConfig().getEnableGrantOption()
-        && ctx.grantOpt() != null) {
-      throw new SemanticException(
-          "Grant Option is disabled, Please check the parameter enable_grant_option.");
-    }
-    boolean grantOption = ctx.grantOpt() != null;
-    boolean toTable;
-    Set<PrivilegeType> privileges;
-    // SYSTEM PRIVILEGES OR ALL PRIVILEGES
-    if (ctx.privilegeObjectScope().ON() == null) {
-      if (ctx.privilegeObjectScope().ALL() != null) {
-        return new RelationalAuthorStatement(
-            toUser ? AuthorRType.GRANT_USER_ALL : AuthorRType.GRANT_ROLE_ALL,
-            toUser ? name : "",
-            toUser ? "" : name,
-            grantOption);
-      } else {
-        privileges = parseSystemPrivilege(ctx.privilegeObjectScope().systemPrivileges());
-        return new RelationalAuthorStatement(
-            toUser ? AuthorRType.GRANT_USER_SYS : AuthorRType.GRANT_ROLE_SYS,
-            privileges,
-            toUser ? name : "",
-            toUser ? "" : name,
-            grantOption);
-      }
-    } else {
-      privileges = parseRelationalPrivilege(ctx.privilegeObjectScope().objectPrivileges());
-      // ON TABLE / DB
-      if (ctx.privilegeObjectScope().objectType() != null) {
-        toTable = ctx.privilegeObjectScope().objectType().getText().equalsIgnoreCase("table");
-        String databaseName = "";
-        if (toTable) {
-          databaseName = clientSession.getDatabaseName();
-          if (databaseName == null) {
-            throw new SemanticException(DataNodeQueryMessages.DATABASE_IS_NOT_SET_YET);
-          }
-        }
-        String obj = ((Identifier) (visit(ctx.privilegeObjectScope().objectName))).getValue();
-        return new RelationalAuthorStatement(
-            toUser
-                ? toTable ? AuthorRType.GRANT_USER_TB : AuthorRType.GRANT_USER_DB
-                : toTable ? AuthorRType.GRANT_ROLE_TB : AuthorRType.GRANT_ROLE_DB,
-            toUser ? name : "",
-            toUser ? "" : name,
-            toTable ? databaseName.toLowerCase() : obj.toLowerCase(),
-            toTable ? obj.toLowerCase() : "",
-            privileges,
-            grantOption,
-            null);
-      } else if (ctx.privilegeObjectScope().objectScope() != null) {
-        String db =
-            ((Identifier) (visit(ctx.privilegeObjectScope().objectScope().dbname)))
-                .getValue()
-                .toLowerCase();
-        String tb =
-            ((Identifier) (visit(ctx.privilegeObjectScope().objectScope().tbname)))
-                .getValue()
-                .toLowerCase();
-        return new RelationalAuthorStatement(
-            toUser ? AuthorRType.GRANT_USER_TB : AuthorRType.GRANT_ROLE_TB,
-            toUser ? name : "",
-            toUser ? "" : name,
-            db,
-            tb,
-            privileges,
-            grantOption,
-            null);
-      } else if (ctx.privilegeObjectScope().ANY() != null) {
-        return new RelationalAuthorStatement(
-            toUser ? AuthorRType.GRANT_USER_ANY : AuthorRType.GRANT_ROLE_ANY,
-            privileges,
-            toUser ? name : "",
-            toUser ? "" : name,
-            grantOption);
-      }
-    }
-    // will not get here.
-    throw new SemanticException(DataNodeQueryMessages.AUTHOR_STATEMENT_PARSER_ERROR);
-  }
-
-  public Node visitRevokeStatement(RelationalSqlParser.RevokeStatementContext ctx) {
-    boolean fromUser;
-    String name;
-    fromUser = ctx.holderType().getText().equalsIgnoreCase("user");
-    name = (((Identifier) visit(ctx.holderName)).getValue());
-    boolean grantOption = ctx.revokeGrantOpt() != null;
-    boolean fromTable = false;
-    Set<PrivilegeType> privileges = new HashSet<>();
-
-    // SYSTEM PRIVILEGES OR ALL PRIVILEGES
-    if (ctx.privilegeObjectScope().ON() == null) {
-      if (ctx.privilegeObjectScope().ALL() != null) {
-        return new RelationalAuthorStatement(
-            fromUser ? AuthorRType.REVOKE_USER_ALL : AuthorRType.REVOKE_ROLE_ALL,
-            fromUser ? name : "",
-            fromUser ? "" : name,
-            grantOption);
-      } else {
-        privileges = parseSystemPrivilege(ctx.privilegeObjectScope().systemPrivileges());
-        return new RelationalAuthorStatement(
-            fromUser ? AuthorRType.REVOKE_USER_SYS : AuthorRType.REVOKE_ROLE_SYS,
-            privileges,
-            fromUser ? name : "",
-            fromUser ? "" : name,
-            grantOption);
-      }
-    } else {
-      privileges = parseRelationalPrivilege(ctx.privilegeObjectScope().objectPrivileges());
-      boolean revokeAll = ctx.privilegeObjectScope().objectPrivileges().ALL() != null;
-      String databaseName = "";
-      String tableName = "";
-
-      // ON TABLE / DB
-      if (ctx.privilegeObjectScope().objectType() != null) {
-        fromTable = ctx.privilegeObjectScope().objectType().getText().equalsIgnoreCase("table");
-        if (fromTable) {
-          databaseName = clientSession.getDatabaseName();
-          if (databaseName == null) {
-            throw new SemanticException(DataNodeQueryMessages.DATABASE_IS_NOT_SET_YET);
-          }
-          tableName =
-              ((Identifier) (visit(ctx.privilegeObjectScope().objectName)))
-                  .getValue()
-                  .toLowerCase();
-        } else {
-          databaseName =
-              ((Identifier) (visit(ctx.privilegeObjectScope().objectName)))
-                  .getValue()
-                  .toLowerCase();
-        }
-      } else if (ctx.privilegeObjectScope().objectScope() != null) {
-        fromTable = true;
-        databaseName =
-            ((Identifier) (visit(ctx.privilegeObjectScope().objectScope().dbname)))
-                .getValue()
-                .toLowerCase();
-        tableName =
-            ((Identifier) (visit(ctx.privilegeObjectScope().objectScope().tbname)))
-                .getValue()
-                .toLowerCase();
-      }
-
-      // The REVOKE ALL command can revoke privileges for users, databases, and tables.
-      // When AuthorRType is REVOKE_USER_ALL:
-      // If both database and table are empty, it clears all privileges globally.
-      // If a database is specified (non-empty), it revokes all privileges within that database
-      // scope.
-      // If a table is specified (non-empty), it revokes privileges specifically for that table.
-      // For operations involving the ANY scope, REVOKE_USER_ALL cannot be combined with
-      // database/table
-      // specifications. However, since ALL privileges are resolved as concrete privileges in this
-      // context,
-      // equivalent effects can be achieved by supplementing with REVOKE_USER_ANY operations.
-
-      if (revokeAll && ctx.privilegeObjectScope().ANY() == null) {
-        return new RelationalAuthorStatement(
-            fromUser ? AuthorRType.REVOKE_USER_ALL : AuthorRType.REVOKE_ROLE_ALL,
-            fromUser ? name : "",
-            fromUser ? "" : name,
-            databaseName,
-            tableName,
-            Collections.emptySet(),
-            grantOption,
-            null);
-      } else if (ctx.privilegeObjectScope().ANY() != null) {
-        return new RelationalAuthorStatement(
-            fromUser ? AuthorRType.REVOKE_USER_ANY : AuthorRType.REVOKE_ROLE_ANY,
-            privileges,
-            fromUser ? name : "",
-            fromUser ? "" : name,
-            grantOption);
-      } else {
-        return new RelationalAuthorStatement(
-            fromUser
-                ? fromTable ? AuthorRType.REVOKE_USER_TB : AuthorRType.REVOKE_USER_DB
-                : fromTable ? AuthorRType.REVOKE_ROLE_TB : AuthorRType.REVOKE_ROLE_DB,
-            fromUser ? name : "",
-            fromUser ? "" : name,
-            databaseName,
-            tableName,
-            privileges,
-            grantOption,
-            null);
-      }
-    }
-  }
-
-  @Override
-  public Node visitCopyToStatement(RelationalSqlParser.CopyToStatementContext ctx) {
-    RelationalSqlParser.CopyToStatementOptionsContext optionsContext = ctx.copyToStatementOptions();
-    String targetFileName = parseStringLiteral(ctx.fileName.getText());
-    CopyToOptions.Builder copyToOptionsBuilder = new CopyToOptions.Builder();
-    if (optionsContext != null) {
-      for (RelationalSqlParser.CopyToStatementOptionContext context :
-          optionsContext.copyToStatementOption()) {
-        addCopyToOption(copyToOptionsBuilder, context);
-      }
-    }
-    Statement queryNode = null;
-    if (ctx.tableName != null) {
-      QualifiedName qualifiedName = getQualifiedName(ctx.tableName);
-      if (ctx.tableColumns != null) {
-        List<RelationalSqlParser.IdentifierContext> identifierList =
-            ctx.identifierList().identifier();
-        SelectItem[] selectItems = new SelectItem[identifierList.size()];
-        for (int i = 0; i < identifierList.size(); i++) {
-          Identifier identifier = (Identifier) visit(identifierList.get(i));
-          selectItems[i] = new SingleColumn(identifier, identifier);
-        }
-        queryNode = QueryUtil.simpleQuery(selectList(selectItems), table(qualifiedName));
-      } else {
-        queryNode = QueryUtil.simpleQuery(selectList(new AllColumns()), table(qualifiedName));
-      }
-    } else {
-      queryNode = (Statement) visit(ctx.query());
-    }
-    return new CopyTo(queryNode, targetFileName, copyToOptionsBuilder.build());
-  }
-
-  private void addCopyToOption(
-      CopyToOptions.Builder builder, RelationalSqlParser.CopyToStatementOptionContext context) {
-    if (context.FORMAT() != null) {
-      Identifier formatIdentifier = (Identifier) visit(context.identifier());
-      String formatText = formatIdentifier.getValue().toUpperCase();
-      try {
-        builder.withFormat(CopyToOptions.Format.valueOf(formatText));
-      } catch (IllegalArgumentException e) {
-        String supportedFormats =
-            Arrays.stream(CopyToOptions.Format.values())
-                .map(Enum::name)
-                .collect(Collectors.joining(", "));
-        throw new SemanticException(
-            String.format(
-                "Unsupported COPY TO format '%s'. Supported formats: %s",
-                formatIdentifier.getValue(), supportedFormats));
-      }
-    } else if (context.TABLE() != null) {
-      Identifier targetTableIdentifier = (Identifier) visit(context.identifier());
-      builder.withTargetTableName(targetTableIdentifier.getValue());
-    } else if (context.TIME() != null) {
-      Identifier targetTimeColumnIdentifier = (Identifier) visit(context.identifier());
-      builder.withTargetTimeColumn(targetTimeColumnIdentifier.getValue());
-    } else if (context.TAGS() != null) {
-      List<RelationalSqlParser.IdentifierContext> identifierList =
-          context.identifierList().identifier();
-      Set<String> targetTagColumns = new LinkedHashSet<>(identifierList.size());
-      for (RelationalSqlParser.IdentifierContext identifierContext : identifierList) {
-        targetTagColumns.add(((Identifier) visit(identifierContext)).getValue());
-      }
-      builder.withTargetTagColumns(targetTagColumns);
-    } else if (context.MEMORY_THRESHOLD() != null) {
-      builder.withMemoryThreshold(parseLong(context.INTEGER_VALUE().getText()));
-    }
-  }
-
-  // ********************** query expressions ********************
-  @Override
-  public Node visitQuery(RelationalSqlParser.QueryContext ctx) {
-    Query body = (Query) visit(ctx.queryNoWith());
-
-    return new Query(
-        getLocation(ctx),
-        visitIfPresent(ctx.with(), With.class),
-        body.getQueryBody(),
-        body.getFill(),
-        body.getOrderBy(),
-        body.getOffset(),
-        body.getLimit());
-  }
-
-  @Override
-  public Node visitWith(RelationalSqlParser.WithContext ctx) {
-    return new With(
-        getLocation(ctx), ctx.RECURSIVE() != null, visit(ctx.namedQuery(), WithQuery.class));
-  }
-
-  @Override
-  public Node visitNamedQuery(RelationalSqlParser.NamedQueryContext ctx) {
-    if (ctx.columnAliases() != null) {
-      List<Identifier> columns = visit(ctx.columnAliases().identifier(), Identifier.class);
-      return new WithQuery(
-          getLocation(ctx),
-          (Identifier) visit(ctx.name),
-          (Query) visit(ctx.query()),
-          columns,
-          ctx.MATERIALIZED() != null);
-    } else {
-      return new WithQuery(
-          getLocation(ctx),
-          (Identifier) visit(ctx.name),
-          (Query) visit(ctx.query()),
-          ctx.MATERIALIZED() != null);
-    }
-  }
-
-  @Override
-  public Node visitQueryNoWith(RelationalSqlParser.QueryNoWithContext ctx) {
-    QueryBody term = (QueryBody) visit(ctx.queryTerm());
-
-    Optional<Fill> fill = Optional.empty();
-    if (ctx.fillClause() != null) {
-      fill = visitIfPresent(ctx.fillClause().fillMethod(), Fill.class);
-    }
-
-    Optional<OrderBy> orderBy = Optional.empty();
-    if (ctx.ORDER() != null) {
-      orderBy =
-          Optional.of(new OrderBy(getLocation(ctx.ORDER()), visit(ctx.sortItem(), SortItem.class)));
-    }
-
-    Optional<Offset> offset = Optional.empty();
-    if (ctx.limitOffsetClause().OFFSET() != null) {
-      offset = visitIfPresent(ctx.limitOffsetClause().offset, Offset.class);
-    }
-
-    Optional<Node> limit = Optional.empty();
-    if (ctx.limitOffsetClause().LIMIT() != null) {
-      if (ctx.limitOffsetClause().limit == null) {
-        throw new IllegalStateException(DataNodeQueryMessages.MISSING_LIMIT_VALUE);
-      }
-      limit = visitIfPresent(ctx.limitOffsetClause().limit, Node.class);
-    }
-
-    if (term instanceof QuerySpecification) {
-      // When we have a simple query specification
-      // followed by order by, offset, limit or fetch,
-      // fold the order by, limit, offset or fetch clauses
-      // into the query specification (analyzer/planner
-      // expects this structure to resolve references with respect
-      // to columns defined in the query specification)
-      final QuerySpecification query = (QuerySpecification) term;
-
-      return new Query(
-          getLocation(ctx),
-          Optional.empty(),
-          new QuerySpecification(
-              getLocation(ctx),
-              query.getSelect(),
-              query.getFrom(),
-              query.getWhere(),
-              query.getGroupBy(),
-              query.getHaving(),
-              fill,
-              query.getWindows(),
-              orderBy,
-              offset,
-              limit),
-          Optional.empty(),
-          Optional.empty(),
-          Optional.empty(),
-          Optional.empty());
-    }
-
-    return new Query(getLocation(ctx), Optional.empty(), term, fill, orderBy, offset, limit);
-  }
-
-  @Override
-  public Node visitPreviousFill(RelationalSqlParser.PreviousFillContext ctx) {
-    TimeDuration timeBound = null;
-    LongLiteral timeColumn = null;
-    List<LongLiteral> fillGroupingElements = null;
-    if (ctx.timeBoundClause() != null) {
-      timeBound =
-          DataNodeDateTimeUtils.constructTimeDuration(
-              ctx.timeBoundClause().timeDuration().getText());
-
-      if (timeBound.monthDuration != 0 && timeBound.nonMonthDuration != 0) {
-        throw new SemanticException(
-            "Simultaneous setting of monthly and non-monthly intervals is not supported.");
-      }
-    }
-
-    if (ctx.timeColumnClause() != null) {
-      timeColumn =
-          new LongLiteral(
-              getLocation(ctx.timeColumnClause().INTEGER_VALUE()),
-              ctx.timeColumnClause().INTEGER_VALUE().getText());
-    }
-
-    if (ctx.fillGroupClause() != null) {
-      fillGroupingElements =
-          ctx.fillGroupClause().INTEGER_VALUE().stream()
-              .map(index -> new LongLiteral(getLocation(index), index.getText()))
-              .collect(toList());
-    }
-
-    if (timeColumn != null && (timeBound == null && fillGroupingElements == null)) {
-      throw new SemanticException(
-          "Don't need to specify TIME_COLUMN while either TIME_BOUND or FILL_GROUP parameter is not specified");
-    }
-    return new Fill(getLocation(ctx), timeBound, timeColumn, fillGroupingElements);
-  }
-
-  @Override
-  public Node visitLinearFill(RelationalSqlParser.LinearFillContext ctx) {
-    LongLiteral timeColumn = null;
-    List<LongLiteral> fillGroupingElements = null;
-    if (ctx.timeColumnClause() != null) {
-      timeColumn =
-          new LongLiteral(
-              getLocation(ctx.timeColumnClause().INTEGER_VALUE()),
-              ctx.timeColumnClause().INTEGER_VALUE().getText());
-    }
-    if (ctx.fillGroupClause() != null) {
-      fillGroupingElements =
-          ctx.fillGroupClause().INTEGER_VALUE().stream()
-              .map(index -> new LongLiteral(getLocation(index), index.getText()))
-              .collect(toList());
-    }
-
-    return new Fill(getLocation(ctx), timeColumn, fillGroupingElements);
-  }
-
-  @Override
-  public Node visitValueFill(RelationalSqlParser.ValueFillContext ctx) {
-    return new Fill(getLocation(ctx), (Literal) visit(ctx.literalExpression()));
-  }
-
-  @Override
-  public Node visitLimitRowCount(final RelationalSqlParser.LimitRowCountContext ctx) {
-    final Expression rowCount;
-    if (ctx.ALL() != null) {
-      rowCount = new AllRows(getLocation(ctx.ALL()));
-    } else if (ctx.rowCount().INTEGER_VALUE() != null) {
-      rowCount = new LongLiteral(getLocation(ctx.rowCount().INTEGER_VALUE()), ctx.getText());
-    } else {
-      rowCount = new Parameter(getLocation(ctx.rowCount().QUESTION_MARK()), parameterPosition);
-      parameterPosition++;
-    }
-
-    return new Limit(getLocation(ctx), rowCount);
-  }
-
-  @Override
-  public Node visitRowCount(final RelationalSqlParser.RowCountContext ctx) {
-    final Expression rowCount;
-    if (ctx.INTEGER_VALUE() != null) {
-      rowCount = new LongLiteral(getLocation(ctx.INTEGER_VALUE()), ctx.getText());
-    } else {
-      rowCount = new Parameter(getLocation(ctx.QUESTION_MARK()), parameterPosition);
-      parameterPosition++;
-    }
-    return new Offset(getLocation(ctx), rowCount);
-  }
-
-  @Override
-  public Node visitQuerySpecification(RelationalSqlParser.QuerySpecificationContext ctx) {
-    return buildQuerySpecification(
-        ctx,
-        ctx.selectItem(),
-        ctx.relation(),
-        ctx.SELECT(),
-        ctx.setQuantifier(),
-        ctx.where,
-        ctx.groupBy(),
-        ctx.having,
-        ctx.windowDefinition());
-  }
-
-  @Override
-  public Node visitFromFirstQuerySpecification(
-      RelationalSqlParser.FromFirstQuerySpecificationContext ctx) {
-    return buildQuerySpecification(
-        ctx,
-        ctx.selectItem(),
-        ctx.relation(),
-        ctx.SELECT(),
-        ctx.setQuantifier(),
-        ctx.where,
-        ctx.groupBy(),
-        ctx.having,
-        ctx.windowDefinition());
-  }
-
-  private Node buildQuerySpecification(
-      ParserRuleContext parserRuleContext,
-      List<RelationalSqlParser.SelectItemContext> selectItemContexts,
-      List<RelationalSqlParser.RelationContext> relationContexts,
-      TerminalNode selectNode,
-      RelationalSqlParser.SetQuantifierContext setQuantifier,
-      RelationalSqlParser.BooleanExpressionContext where,
-      RelationalSqlParser.GroupByContext groupBy,
-      RelationalSqlParser.BooleanExpressionContext having,
-      List<RelationalSqlParser.WindowDefinitionContext> windowDefinitions) {
-
-    Optional<Relation> from = Optional.empty();
-    List<SelectItem> selectItems = visit(selectItemContexts, SelectItem.class);
-
-    List<Relation> relations = visit(relationContexts, Relation.class);
-    if (!relations.isEmpty()) {
-      // synthesize implicit join nodes
-      Iterator<Relation> iterator = relations.iterator();
-      Relation relation = iterator.next();
-
-      while (iterator.hasNext()) {
-        relation =
-            new Join(getLocation(parserRuleContext), Join.Type.IMPLICIT, relation, iterator.next());
-      }
-
-      from = Optional.of(relation);
-    }
-
-    // If no SELECT items provided (FROM-first without SELECT clause), default to SELECT *
-    if (selectItems.isEmpty()) {
-      selectItems =
-          ImmutableList.of(new AllColumns(getLocation(parserRuleContext), ImmutableList.of()));
-    }
-
-    NodeLocation selectLocation =
-        selectNode != null ? getLocation(selectNode) : getLocation(parserRuleContext);
-
-    return new QuerySpecification(
-        getLocation(parserRuleContext),
-        new Select(selectLocation, isDistinct(setQuantifier), selectItems),
-        from,
-        visitIfPresent(where, Expression.class),
-        visitIfPresent(groupBy, GroupBy.class),
-        visitIfPresent(having, Expression.class),
-        Optional.empty(),
-        visit(windowDefinitions, WindowDefinition.class),
-        Optional.empty(),
-        Optional.empty(),
-        Optional.empty());
-  }
-
-  @Override
-  public Node visitSelectSingle(RelationalSqlParser.SelectSingleContext ctx) {
-    if (ctx.identifier() != null) {
-      return new SingleColumn(
-          getLocation(ctx),
-          (Expression) visit(ctx.expression()),
-          (Identifier) visit(ctx.identifier()));
-    } else {
-      return new SingleColumn(getLocation(ctx), (Expression) visit(ctx.expression()));
-    }
-  }
-
-  @Override
-  public Node visitSelectAll(RelationalSqlParser.SelectAllContext ctx) {
-    List<Identifier> aliases = ImmutableList.of();
-    if (ctx.columnAliases() != null) {
-      aliases = visit(ctx.columnAliases().identifier(), Identifier.class);
-    }
-
-    if (ctx.primaryExpression() != null) {
-      return new AllColumns(getLocation(ctx), (Expression) visit(ctx.primaryExpression()), aliases);
-    } else {
-      return new AllColumns(getLocation(ctx), aliases);
-    }
-  }
-
-  @Override
-  public Node visitGroupBy(RelationalSqlParser.GroupByContext ctx) {
-    return new GroupBy(
-        getLocation(ctx),
-        isDistinct(ctx.setQuantifier()),
-        visit(ctx.groupingElement(), GroupingElement.class));
-  }
-
-  @Override
-  public Node visitSingleGroupingSet(RelationalSqlParser.SingleGroupingSetContext ctx) {
-    return new SimpleGroupBy(
-        getLocation(ctx), visit(ctx.groupingSet().expression(), Expression.class));
-  }
-
-  @Override
-  public Node visitRollup(RelationalSqlParser.RollupContext ctx) {
-    return new GroupingSets(
-        getLocation(ctx),
-        ROLLUP,
-        ctx.groupingSet().stream()
-            .map(groupingSet -> visit(groupingSet.expression(), Expression.class))
-            .collect(toList()));
-  }
-
-  @Override
-  public Node visitCube(RelationalSqlParser.CubeContext ctx) {
-    return new GroupingSets(
-        getLocation(ctx),
-        CUBE,
-        ctx.groupingSet().stream()
-            .map(groupingSet -> visit(groupingSet.expression(), Expression.class))
-            .collect(toList()));
-  }
-
-  @Override
-  public Node visitMultipleGroupingSets(RelationalSqlParser.MultipleGroupingSetsContext ctx) {
-    return new GroupingSets(
-        getLocation(ctx),
-        EXPLICIT,
-        ctx.groupingSet().stream()
-            .map(groupingSet -> visit(groupingSet.expression(), Expression.class))
-            .collect(toList()));
-  }
-
-  @Override
-  public Node visitSetOperation(RelationalSqlParser.SetOperationContext ctx) {
-    QueryBody left = (QueryBody) visit(ctx.left);
-    QueryBody right = (QueryBody) visit(ctx.right);
-
-    boolean distinct = ctx.setQuantifier() == null || ctx.setQuantifier().DISTINCT() != null;
-
-    switch (ctx.operator.getType()) {
-      case RelationalSqlLexer.UNION:
-        return new Union(getLocation(ctx.UNION()), ImmutableList.of(left, right), distinct);
-      case RelationalSqlLexer.INTERSECT:
-        return new Intersect(getLocation(ctx.INTERSECT()), ImmutableList.of(left, right), distinct);
-      case RelationalSqlLexer.EXCEPT:
-        return new Except(getLocation(ctx.EXCEPT()), left, right, distinct);
-      default:
-        throw new IllegalArgumentException(
-            DataNodeQueryMessages.UNSUPPORTED_SET_OPERATION + ctx.operator.getText());
-    }
-  }
-
-  @Override
-  public Node visitProperty(RelationalSqlParser.PropertyContext ctx) {
-    NodeLocation location = getLocation(ctx);
-    Identifier name = (Identifier) visit(ctx.identifier());
-    RelationalSqlParser.PropertyValueContext valueContext = ctx.propertyValue();
-    if (valueContext instanceof RelationalSqlParser.DefaultPropertyValueContext) {
-      return new Property(location, name);
-    }
-    Expression value =
-        (Expression)
-            visit(((RelationalSqlParser.NonDefaultPropertyValueContext) valueContext).expression());
-    return new Property(location, name, value);
-  }
-
-  @Override
-  public Node visitTable(RelationalSqlParser.TableContext ctx) {
-    return new Table(getLocation(ctx), getQualifiedName(ctx.qualifiedName()));
-  }
-
-  @Override
-  public Node visitInlineTable(RelationalSqlParser.InlineTableContext ctx) {
-    return new Values(getLocation(ctx), visit(ctx.expression(), Expression.class));
-  }
-
-  @Override
-  public Node visitSubquery(RelationalSqlParser.SubqueryContext ctx) {
-    return new TableSubquery(getLocation(ctx), (Query) visit(ctx.queryNoWith()));
-  }
-
-  @Override
-  public Node visitSortItem(RelationalSqlParser.SortItemContext ctx) {
-    return new SortItem(
-        getLocation(ctx),
-        (Expression) visit(ctx.expression()),
-        Optional.ofNullable(ctx.ordering)
-            .map(AstBuilder::getOrderingType)
-            .orElse(SortItem.Ordering.ASCENDING),
-        Optional.ofNullable(ctx.nullOrdering)
-            .map(AstBuilder::getNullOrderingType)
-            .orElse(SortItem.NullOrdering.UNDEFINED));
-  }
-
-  @Override
-  public Node visitUnquotedIdentifier(RelationalSqlParser.UnquotedIdentifierContext ctx) {
-    return new Identifier(getLocation(ctx), ctx.getText(), false);
-  }
-
-  @Override
-  public Node visitQuotedIdentifier(RelationalSqlParser.QuotedIdentifierContext ctx) {
-    String token = ctx.getText();
-    String identifier = token.substring(1, token.length() - 1).replace("\"\"", "\"");
-
-    return new Identifier(getLocation(ctx), identifier, true);
-  }
-
-  // ***************** boolean expressions ******************
-  @Override
-  public Node visitLogicalNot(RelationalSqlParser.LogicalNotContext ctx) {
-    return new NotExpression(getLocation(ctx), (Expression) visit(ctx.booleanExpression()));
-  }
-
-  @Override
-  public Node visitOr(RelationalSqlParser.OrContext ctx) {
-    List<ParserRuleContext> terms =
-        flatten(
-            ctx,
-            element -> {
-              if (element instanceof RelationalSqlParser.OrContext) {
-                RelationalSqlParser.OrContext or = (RelationalSqlParser.OrContext) element;
-                return Optional.of(or.booleanExpression());
-              }
-
-              return Optional.empty();
-            });
-
-    return new LogicalExpression(
-        getLocation(ctx), LogicalExpression.Operator.OR, visit(terms, Expression.class));
-  }
-
-  @Override
-  public Node visitAnd(RelationalSqlParser.AndContext ctx) {
-    List<ParserRuleContext> terms =
-        flatten(
-            ctx,
-            element -> {
-              if (element instanceof RelationalSqlParser.AndContext) {
-                RelationalSqlParser.AndContext and = (RelationalSqlParser.AndContext) element;
-                return Optional.of(and.booleanExpression());
-              }
-
-              return Optional.empty();
-            });
-
-    return new LogicalExpression(
-        getLocation(ctx), LogicalExpression.Operator.AND, visit(terms, Expression.class));
-  }
-
-  private static List<ParserRuleContext> flatten(
-      ParserRuleContext root,
-      Function<ParserRuleContext, Optional<List<? extends ParserRuleContext>>> extractChildren) {
-    List<ParserRuleContext> result = new ArrayList<>();
-    Deque<ParserRuleContext> pending = new ArrayDeque<>();
-    pending.push(root);
-
-    while (!pending.isEmpty()) {
-      ParserRuleContext next = pending.pop();
-
-      Optional<List<? extends ParserRuleContext>> children = extractChildren.apply(next);
-      if (!children.isPresent()) {
-        result.add(next);
-      } else {
-        for (int i = children.get().size() - 1; i >= 0; i--) {
-          pending.push(children.get().get(i));
-        }
-      }
-    }
-
-    return result;
-  }
-
-  // *************** from clause *****************
-  @Override
-  public Node visitJoinRelation(RelationalSqlParser.JoinRelationContext ctx) {
-    Relation left = (Relation) visit(ctx.left);
-    Relation right;
-
-    if (ctx.CROSS() != null) {
-      right = (Relation) visit(ctx.right);
-      return new Join(getLocation(ctx), Join.Type.CROSS, left, right);
-    }
-
-    JoinCriteria criteria;
-    TimeDuration timeDuration = null;
-    if (ctx.NATURAL() != null) {
-      right = (Relation) visit(ctx.right);
-      criteria = new NaturalJoin();
-    } else {
-      right = (Relation) visit(ctx.rightRelation);
-      if (ctx.joinCriteria().ON() != null) {
-        if (ctx.ASOF() != null) {
-          if (ctx.timeDuration() != null) {
-            timeDuration =
-                DataNodeDateTimeUtils.constructTimeDuration(ctx.timeDuration().getText());
-
-            if (timeDuration.monthDuration != 0) {
-              throw new SemanticException(
-                  "Month or year interval in tolerance is not supported now.");
-            }
-          }
-          criteria =
-              constructAsofJoinOn(
-                  (Expression) visit(ctx.joinCriteria().booleanExpression()), timeDuration);
-        } else {
-          criteria = new JoinOn((Expression) visit(ctx.joinCriteria().booleanExpression()));
-        }
-      } else if (ctx.joinCriteria().USING() != null) {
-        criteria = new JoinUsing(visit(ctx.joinCriteria().identifier(), Identifier.class));
-      } else {
-        throw new IllegalArgumentException(DataNodeQueryMessages.UNSUPPORTED_JOIN_CRITERIA);
-      }
-    }
-
-    Join.Type joinType;
-    if (ctx.joinType().LEFT() != null) {
-      joinType = Join.Type.LEFT;
-    } else if (ctx.joinType().RIGHT() != null) {
-      joinType = Join.Type.RIGHT;
-    } else if (ctx.joinType().FULL() != null) {
-      joinType = Join.Type.FULL;
-    } else {
-      joinType = Join.Type.INNER;
-    }
-
-    if (criteria instanceof AsofJoinOn) {
-      if (joinType == Join.Type.RIGHT || joinType == Join.Type.FULL) {
-        throw new SemanticException(
-            String.format("ASOF JOIN does not support %s type now", joinType));
-      }
-
-      if (joinType != Join.Type.INNER && timeDuration != null) {
-        throw new SemanticException(
-            DataNodeQueryMessages.TOLERANCE_IN_ASOF_JOIN_ONLY_SUPPORTS_INNER_TYPE);
-      }
-    }
-
-    return new Join(getLocation(ctx), joinType, left, right, criteria);
-  }
-
-  @Override
-  public Node visitPatternRecognition(RelationalSqlParser.PatternRecognitionContext context) {
-    Relation child = (Relation) visit(context.aliasedRelation());
-
-    if (context.MATCH_RECOGNIZE() == null) {
-      return child;
-    }
-
-    Optional<OrderBy> orderBy = Optional.empty();
-    if (context.ORDER() != null) {
-      orderBy =
-          Optional.of(
-              new OrderBy(getLocation(context.ORDER()), visit(context.sortItem(), SortItem.class)));
-    }
-
-    PatternRecognitionRelation relation =
-        new PatternRecognitionRelation(
-            getLocation(context),
-            child,
-            visit(context.partition, Expression.class),
-            orderBy,
-            visit(context.measureDefinition(), MeasureDefinition.class),
-            getRowsPerMatch(context.rowsPerMatch()),
-            visitIfPresent(context.skipTo(), SkipTo.class),
-            (RowPattern) visit(context.rowPattern()),
-            visit(context.subsetDefinition(), SubsetDefinition.class),
-            visit(context.variableDefinition(), VariableDefinition.class));
-
-    if (context.identifier() == null) {
-      return relation;
-    }
-
-    List<Identifier> aliases = null;
-    if (context.columnAliases() != null) {
-      aliases = visit(context.columnAliases().identifier(), Identifier.class);
-    }
-
-    return new AliasedRelation(
-        getLocation(context), relation, (Identifier) visit(context.identifier()), aliases);
-  }
-
-  @Override
-  public Node visitMeasureDefinition(RelationalSqlParser.MeasureDefinitionContext context) {
-    return new MeasureDefinition(
-        getLocation(context),
-        (Expression) visit(context.expression()),
-        (Identifier) visit(context.identifier()));
-  }
-
-  private Optional<RowsPerMatch> getRowsPerMatch(RelationalSqlParser.RowsPerMatchContext context) {
-    if (context == null) {
-      return Optional.empty();
-    }
-
-    if (context.ONE() != null) {
-      return Optional.of(ONE);
-    }
-
-    if (context.emptyMatchHandling() == null) {
-      return Optional.of(ALL_SHOW_EMPTY);
-    }
-
-    if (context.emptyMatchHandling().SHOW() != null) {
-      return Optional.of(ALL_SHOW_EMPTY);
-    }
-
-    if (context.emptyMatchHandling().OMIT() != null) {
-      return Optional.of(ALL_OMIT_EMPTY);
-    }
-
-    return Optional.of(ALL_WITH_UNMATCHED);
-  }
-
-  @Override
-  public Node visitSkipTo(RelationalSqlParser.SkipToContext context) {
-    if (context.PAST() != null) {
-      return skipPastLastRow(getLocation(context));
-    }
-
-    if (context.NEXT() != null) {
-      return skipToNextRow(getLocation(context));
-    }
-
-    if (context.FIRST() != null) {
-      return skipToFirst(getLocation(context), (Identifier) visit(context.identifier()));
-    }
-
-    return skipToLast(getLocation(context), (Identifier) visit(context.identifier()));
-  }
-
-  @Override
-  public Node visitSubsetDefinition(RelationalSqlParser.SubsetDefinitionContext context) {
-    return new SubsetDefinition(
-        getLocation(context),
-        (Identifier) visit(context.name),
-        visit(context.union, Identifier.class));
-  }
-
-  @Override
-  public Node visitVariableDefinition(RelationalSqlParser.VariableDefinitionContext context) {
-    return new VariableDefinition(
-        getLocation(context),
-        (Identifier) visit(context.identifier()),
-        (Expression) visit(context.expression()));
-  }
-
-  @Override
-  public Node visitAliasedRelation(RelationalSqlParser.AliasedRelationContext ctx) {
-    Relation child = (Relation) visit(ctx.relationPrimary());
-
-    if (ctx.identifier() == null) {
-      return child;
-    }
-
-    List<Identifier> aliases = null;
-    if (ctx.columnAliases() != null) {
-      aliases = visit(ctx.columnAliases().identifier(), Identifier.class);
-    }
-
-    return new AliasedRelation(
-        getLocation(ctx), child, (Identifier) visit(ctx.identifier()), aliases);
-  }
-
-  @Override
-  public Node visitTableName(RelationalSqlParser.TableNameContext ctx) {
-    return new Table(getLocation(ctx), getQualifiedName(ctx.qualifiedName()));
-  }
-
-  @Override
-  public Node visitSubqueryRelation(RelationalSqlParser.SubqueryRelationContext ctx) {
-    return new TableSubquery(getLocation(ctx), (Query) visit(ctx.query()));
-  }
-
-  @Override
-  public Node visitParenthesizedRelation(RelationalSqlParser.ParenthesizedRelationContext ctx) {
-    return visit(ctx.relation());
-  }
-
-  @Override
-  public Node visitTableFunctionInvocation(
-      RelationalSqlParser.TableFunctionInvocationContext context) {
-    return visit(context.tableFunctionCall());
-  }
-
-  @Override
-  public Node visitTableFunctionInvocationWithTableKeyWord(
-      RelationalSqlParser.TableFunctionInvocationWithTableKeyWordContext ctx) {
-    return visit(ctx.tableFunctionCall());
-  }
-
-  @Override
-  public Node visitTableFunctionCall(RelationalSqlParser.TableFunctionCallContext context) {
-    QualifiedName name = getQualifiedName(context.qualifiedName());
-    List<TableFunctionArgument> arguments =
-        visit(context.tableFunctionArgument(), TableFunctionArgument.class);
-
-    return new TableFunctionInvocation(getLocation(context), name, arguments);
-  }
-
-  @Override
-  public Node visitTableFunctionArgument(RelationalSqlParser.TableFunctionArgumentContext context) {
-    Optional<Identifier> name = visitIfPresent(context.identifier(), Identifier.class);
-    Node value;
-    if (context.tableArgument() != null) {
-      value = visit(context.tableArgument());
-    } else {
-      value = visit(context.scalarArgument());
-    }
-
-    return new TableFunctionArgument(getLocation(context), name, value);
-  }
-
-  @Override
-  public Node visitTableArgument(RelationalSqlParser.TableArgumentContext context) {
-    Relation table = (Relation) visit(context.tableArgumentRelation());
-
-    Optional<List<Expression>> partitionBy = Optional.empty();
-    if (context.PARTITION() != null) {
-      partitionBy = Optional.of(visit(context.expression(), Expression.class));
-    }
-
-    Optional<OrderBy> orderBy = Optional.empty();
-    if (context.ORDER() != null) {
-      orderBy =
-          Optional.of(
-              new OrderBy(getLocation(context.ORDER()), visit(context.sortItem(), SortItem.class)));
-    }
-
-    return new TableFunctionTableArgument(getLocation(context), table, partitionBy, orderBy);
-  }
-
-  private Node visitTableArgumentAlias(
-      NodeLocation nodeLocation,
-      Relation relation,
-      RelationalSqlParser.IdentifierContext identifierContext,
-      TerminalNode as,
-      RelationalSqlParser.ColumnAliasesContext columnAliasesContext) {
-    if (identifierContext != null) {
-      Identifier alias = (Identifier) visit(identifierContext);
-      if (as == null) {
-        validateArgumentAlias(alias, identifierContext);
-      }
-      List<Identifier> columnNames = null;
-      if (columnAliasesContext != null) {
-        columnNames = visit(columnAliasesContext.identifier(), Identifier.class);
-      }
-      relation = new AliasedRelation(nodeLocation, relation, alias, columnNames);
-    }
-    return relation;
-  }
-
-  @Override
-  public Node visitTableArgumentTableWithTableKeyWord(
-      RelationalSqlParser.TableArgumentTableWithTableKeyWordContext context) {
-    Relation relation =
-        new Table(getLocation(context.TABLE()), getQualifiedName(context.qualifiedName()));
-    return visitTableArgumentAlias(
-        getLocation(context.TABLE()),
-        relation,
-        context.identifier(),
-        context.AS(),
-        context.columnAliases());
-  }
-
-  @Override
-  public Node visitTableArgumentTable(RelationalSqlParser.TableArgumentTableContext context) {
-    Relation relation =
-        new Table(getLocation(context.qualifiedName()), getQualifiedName(context.qualifiedName()));
-    return visitTableArgumentAlias(
-        getLocation(context.qualifiedName()),
-        relation,
-        context.identifier(),
-        context.AS(),
-        context.columnAliases());
-  }
-
-  @Override
-  public Node visitTableArgumentQueryWithTableKeyWord(
-      RelationalSqlParser.TableArgumentQueryWithTableKeyWordContext context) {
-    Relation relation =
-        new TableSubquery(getLocation(context.TABLE()), (Query) visit(context.query()));
-    return visitTableArgumentAlias(
-        getLocation(context.TABLE()),
-        relation,
-        context.identifier(),
-        context.AS(),
-        context.columnAliases());
-  }
-
-  @Override
-  public Node visitTableArgumentQuery(RelationalSqlParser.TableArgumentQueryContext context) {
-    Relation relation =
-        new TableSubquery(getLocation(context.query()), (Query) visit(context.query()));
-    return visitTableArgumentAlias(
-        getLocation(context.query()),
-        relation,
-        context.identifier(),
-        context.AS(),
-        context.columnAliases());
-  }
-
-  @Override
-  public Node visitScalarArgument(RelationalSqlParser.ScalarArgumentContext ctx) {
-    if (ctx.expression() != null) {
-      return visit(ctx.expression());
-    } else {
-      return new TimeDurationLiteral(
-          DataNodeDateTimeUtils.constructTimeDuration(ctx.timeDuration().getText()));
-    }
-  }
-
-  // ********************* predicates *******************
-
-  @Override
-  public Node visitPredicated(RelationalSqlParser.PredicatedContext ctx) {
-    if (ctx.predicate() != null) {
-      return visit(ctx.predicate());
-    }
-
-    return visit(ctx.valueExpression);
-  }
-
-  @Override
-  public Node visitComparison(RelationalSqlParser.ComparisonContext ctx) {
-    return new ComparisonExpression(
-        getLocation(ctx.comparisonOperator()),
-        getComparisonOperator(((TerminalNode) ctx.comparisonOperator().getChild(0)).getSymbol()),
-        (Expression) visit(ctx.value),
-        (Expression) visit(ctx.right));
-  }
-
-  @Override
-  public Node visitQuantifiedComparison(RelationalSqlParser.QuantifiedComparisonContext ctx) {
-    return new QuantifiedComparisonExpression(
-        getLocation(ctx.comparisonOperator()),
-        getComparisonOperator(((TerminalNode) ctx.comparisonOperator().getChild(0)).getSymbol()),
-        getComparisonQuantifier(
-            ((TerminalNode) ctx.comparisonQuantifier().getChild(0)).getSymbol()),
-        (Expression) visit(ctx.value),
-        new SubqueryExpression(getLocation(ctx.query()), (Query) visit(ctx.query())));
-  }
-
-  @Override
-  public Node visitBetween(RelationalSqlParser.BetweenContext ctx) {
-    Expression expression =
-        new BetweenPredicate(
-            getLocation(ctx),
-            (Expression) visit(ctx.value),
-            (Expression) visit(ctx.lower),
-            (Expression) visit(ctx.upper));
-
-    if (ctx.NOT() != null) {
-      expression = new NotExpression(getLocation(ctx), expression);
-    }
-
-    return expression;
-  }
-
-  @Override
-  public Node visitInList(RelationalSqlParser.InListContext ctx) {
-    Expression result =
-        new InPredicate(
-            getLocation(ctx),
-            (Expression) visit(ctx.value),
-            new InListExpression(getLocation(ctx), visit(ctx.expression(), Expression.class)));
-
-    if (ctx.NOT() != null) {
-      result = new NotExpression(getLocation(ctx), result);
-    }
-
-    return result;
-  }
-
-  @Override
-  public Node visitInSubquery(RelationalSqlParser.InSubqueryContext ctx) {
-    Expression result =
-        new InPredicate(
-            getLocation(ctx),
-            (Expression) visit(ctx.value),
-            new SubqueryExpression(getLocation(ctx), (Query) visit(ctx.query())));
-
-    if (ctx.NOT() != null) {
-      result = new NotExpression(getLocation(ctx), result);
-    }
-
-    return result;
-  }
-
-  @Override
-  public Node visitLike(RelationalSqlParser.LikeContext ctx) {
-    Expression result;
-    if (ctx.escape != null) {
-      result =
-          new LikePredicate(
-              getLocation(ctx),
-              (Expression) visit(ctx.value),
-              (Expression) visit(ctx.pattern),
-              (Expression) visit(ctx.escape));
-    } else {
-      result =
-          new LikePredicate(
-              getLocation(ctx), (Expression) visit(ctx.value), (Expression) visit(ctx.pattern));
-    }
-
-    if (ctx.NOT() != null) {
-      result = new NotExpression(getLocation(ctx), result);
-    }
-
-    return result;
-  }
-
-  @Override
-  public Node visitNullPredicate(RelationalSqlParser.NullPredicateContext ctx) {
-    Expression child = (Expression) visit(ctx.value);
-
-    if (ctx.NOT() == null) {
-      return new IsNullPredicate(getLocation(ctx), child);
-    }
-
-    return new IsNotNullPredicate(getLocation(ctx), child);
-  }
-
-  @Override
-  public Node visitDistinctFrom(RelationalSqlParser.DistinctFromContext ctx) {
-    Expression expression =
-        new ComparisonExpression(
-            getLocation(ctx),
-            ComparisonExpression.Operator.IS_DISTINCT_FROM,
-            (Expression) visit(ctx.value),
-            (Expression) visit(ctx.right));
-
-    if (ctx.NOT() != null) {
-      expression = new NotExpression(getLocation(ctx), expression);
-    }
-
-    return expression;
-  }
-
-  @Override
-  public Node visitExists(RelationalSqlParser.ExistsContext ctx) {
-    return new ExistsPredicate(
-        getLocation(ctx), new SubqueryExpression(getLocation(ctx), (Query) visit(ctx.query())));
-  }
-
-  // ************** value expressions **************
-  @Override
-  public Node visitArithmeticUnary(RelationalSqlParser.ArithmeticUnaryContext ctx) {
-    Expression child = (Expression) visit(ctx.valueExpression());
-
-    switch (ctx.operator.getType()) {
-      case RelationalSqlLexer.MINUS:
-        return ArithmeticUnaryExpression.negative(getLocation(ctx), child);
-      case RelationalSqlLexer.PLUS:
-        return ArithmeticUnaryExpression.positive(getLocation(ctx), child);
-      default:
-        throw new UnsupportedOperationException(
-            DataNodeQueryMessages.UNSUPPORTED_SIGN + ctx.operator.getText());
-    }
-  }
-
-  @Override
-  public Node visitArithmeticBinary(RelationalSqlParser.ArithmeticBinaryContext ctx) {
-    return new ArithmeticBinaryExpression(
-        getLocation(ctx.operator),
-        getArithmeticBinaryOperator(ctx.operator),
-        (Expression) visit(ctx.left),
-        (Expression) visit(ctx.right));
-  }
-
-  @Override
-  public Node visitConcatenation(RelationalSqlParser.ConcatenationContext ctx) {
-    return new FunctionCall(
-        getLocation(ctx.CONCAT()),
-        QualifiedName.of(TableBuiltinScalarFunction.CONCAT.getFunctionName()),
-        ImmutableList.of((Expression) visit(ctx.left), (Expression) visit(ctx.right)));
-  }
-
-  // ********************* primary expressions **********************
-  @Override
-  public Node visitOver(RelationalSqlParser.OverContext ctx) {
-    if (ctx.windowName != null) {
-      return new WindowReference(getLocation(ctx), (Identifier) visit(ctx.windowName));
-    }
-
-    return visit(ctx.windowSpecification());
-  }
-
-  @Override
-  public Node visitWindowDefinition(RelationalSqlParser.WindowDefinitionContext ctx) {
-    return new WindowDefinition(
-        getLocation(ctx),
-        (Identifier) visit(ctx.name),
-        (WindowSpecification) visit(ctx.windowSpecification()));
-  }
-
-  @Override
-  public Node visitWindowSpecification(RelationalSqlParser.WindowSpecificationContext ctx) {
-    Optional<Identifier> existingWindowName = getIdentifierIfPresent(ctx.existingWindowName);
-
-    List<Expression> partitionBy = visit(ctx.partition, Expression.class);
-
-    Optional<OrderBy> orderBy = Optional.empty();
-    if (ctx.ORDER() != null) {
-      orderBy =
-          Optional.of(new OrderBy(getLocation(ctx.ORDER()), visit(ctx.sortItem(), SortItem.class)));
-    }
-
-    Optional<WindowFrame> frame = Optional.empty();
-    if (ctx.windowFrame() != null) {
-      frame = Optional.of((WindowFrame) visitFrameExtent(ctx.windowFrame().frameExtent()));
-    }
-
-    return new WindowSpecification(
-        getLocation(ctx), existingWindowName, partitionBy, orderBy, frame);
-  }
-
-  @Override
-  public Node visitFrameExtent(RelationalSqlParser.FrameExtentContext ctx) {
-    WindowFrame.Type frameType = toWindowFrameType(ctx.frameType);
-    FrameBound start = (FrameBound) visit(ctx.start);
-    Optional<FrameBound> end = visitIfPresent(ctx.end, FrameBound.class);
-    return new WindowFrame(getLocation(ctx), frameType, start, end);
-  }
-
-  private static WindowFrame.Type toWindowFrameType(Token token) {
-    switch (token.getType()) {
-      case RelationalSqlLexer.ROWS:
-        return WindowFrame.Type.ROWS;
-      case RelationalSqlLexer.RANGE:
-        return WindowFrame.Type.RANGE;
-      case RelationalSqlLexer.GROUPS:
-        return WindowFrame.Type.GROUPS;
-      default:
-        throw new IllegalArgumentException(
-            DataNodeQueryMessages.UNSUPPORTED_WINDOW_FRAME_TYPE + token.getText());
-    }
-  }
-
-  @Override
-  public Node visitUnboundedFrame(RelationalSqlParser.UnboundedFrameContext ctx) {
-    switch (ctx.boundType.getType()) {
-      case RelationalSqlLexer.PRECEDING:
-        return new FrameBound(getLocation(ctx), FrameBound.Type.UNBOUNDED_PRECEDING);
-      case RelationalSqlLexer.FOLLOWING:
-        return new FrameBound(getLocation(ctx), FrameBound.Type.UNBOUNDED_FOLLOWING);
-      default:
-        throw new IllegalArgumentException(
-            "Unsupported unbounded type: " + ctx.boundType.getText());
-    }
-  }
-
-  @Override
-  public Node visitCurrentRowBound(RelationalSqlParser.CurrentRowBoundContext ctx) {
-    return new FrameBound(getLocation(ctx), FrameBound.Type.CURRENT_ROW);
-  }
-
-  @Override
-  public Node visitBoundedFrame(RelationalSqlParser.BoundedFrameContext ctx) {
-    Expression value = (Expression) visit(ctx.expression());
-    switch (ctx.boundType.getType()) {
-      case RelationalSqlLexer.PRECEDING:
-        return new FrameBound(getLocation(ctx), FrameBound.Type.PRECEDING, value);
-      case RelationalSqlLexer.FOLLOWING:
-        return new FrameBound(getLocation(ctx), FrameBound.Type.FOLLOWING, value);
-      default:
-        throw new IllegalArgumentException(
-            DataNodeQueryMessages.UNSUPPORTED_BOUNDED_TYPE + ctx.boundType.getText());
-    }
-  }
-
-  @Override
-  public Node visitParenthesizedExpression(RelationalSqlParser.ParenthesizedExpressionContext ctx) {
-    return visit(ctx.expression());
-  }
-
-  @Override
-  public Node visitRowConstructor(RelationalSqlParser.RowConstructorContext context) {
-    return new Row(getLocation(context), visit(context.expression(), Expression.class));
-  }
-
-  @Override
-  public Node visitCast(RelationalSqlParser.CastContext ctx) {
-    boolean isTryCast = ctx.TRY_CAST() != null;
-    return new Cast(
-        getLocation(ctx),
-        (Expression) visit(ctx.expression()),
-        (DataType) visit(ctx.type()),
-        isTryCast);
-  }
-
-  @Override
-  public Node visitSpecialDateTimeFunction(RelationalSqlParser.SpecialDateTimeFunctionContext ctx) {
-    CurrentTime.Function function = getDateTimeFunctionType(ctx.name);
-    return new CurrentTime(getLocation(ctx), function);
-  }
-
-  @Override
-  public Node visitDateTimeExpression(RelationalSqlParser.DateTimeExpressionContext ctx) {
-    return new LongLiteral(
-        getLocation(ctx),
-        String.valueOf(
-            parseDateExpression(ctx.dateExpression(), CommonDateTimeUtils.currentTime())));
-  }
-
-  private Long parseDateExpression(
-      RelationalSqlParser.DateExpressionContext ctx, long currentTime) {
-    long time;
-    time = parseDateTimeFormat(ctx.getChild(0).getText(), currentTime, zoneId);
-    for (int i = 1; i < ctx.getChildCount(); i = i + 2) {
-      if ("+".equals(ctx.getChild(i).getText())) {
-        time +=
-            DataNodeDateTimeUtils.convertDurationStrToLong(
-                time, ctx.getChild(i + 1).getText(), false);
-      } else {
-        time -=
-            DataNodeDateTimeUtils.convertDurationStrToLong(
-                time, ctx.getChild(i + 1).getText(), false);
-      }
-    }
-    return time;
-  }
-
-  @Override
-  public Node visitTrim(RelationalSqlParser.TrimContext ctx) {
-    if (ctx.FROM() != null && ctx.trimsSpecification() == null && ctx.trimChar == null) {
-      throw parseError(
-          "The 'trim' function must have specification, char or both arguments when it takes FROM",
-          ctx);
-    }
-
-    Trim.Specification specification =
-        ctx.trimsSpecification() == null
-            ? Trim.Specification.BOTH
-            : toTrimSpecification((Token) ctx.trimsSpecification().getChild(0).getPayload());
-    if (ctx.trimChar != null) {
-      return new Trim(
-          getLocation(ctx),
-          specification,
-          (Expression) visit(ctx.trimSource),
-          (Expression) visit(ctx.trimChar));
-    } else {
-      return new Trim(getLocation(ctx), specification, (Expression) visit(ctx.trimSource));
-    }
-  }
-
-  private static Trim.Specification toTrimSpecification(Token token) {
-    switch (token.getType()) {
-      case RelationalSqlLexer.BOTH:
-        return Trim.Specification.BOTH;
-      case RelationalSqlLexer.LEADING:
-        return Trim.Specification.LEADING;
-      case RelationalSqlLexer.TRAILING:
-        return Trim.Specification.TRAILING;
-      default:
-        throw new IllegalArgumentException(
-            DataNodeQueryMessages.UNSUPPORTED_TRIM_SPECIFICATION + token.getText());
-    }
-  }
-
-  @Override
-  public Node visitSubstring(RelationalSqlParser.SubstringContext ctx) {
-    return new FunctionCall(
-        getLocation(ctx),
-        QualifiedName.of("substring"),
-        visit(ctx.valueExpression(), Expression.class));
-  }
-
-  @Override
-  public Node visitCurrentDatabase(RelationalSqlParser.CurrentDatabaseContext ctx) {
-    return new CurrentDatabase(getLocation(ctx));
-  }
-
-  @Override
-  public Node visitCurrentUser(RelationalSqlParser.CurrentUserContext ctx) {
-    return new CurrentUser(getLocation(ctx));
-  }
-
-  @Override
-  public Node visitExtract(RelationalSqlParser.ExtractContext context) {
-    String fieldString = context.identifier().getText();
-    Extract.Field field;
-    try {
-      field = Extract.Field.valueOf(fieldString.toUpperCase(ENGLISH));
-    } catch (IllegalArgumentException e) {
-      throw parseError("Invalid EXTRACT field: " + fieldString, context);
-    }
-    return new Extract(getLocation(context), (Expression) visit(context.valueExpression()), field);
-  }
-
-  @Override
-  public Node visitSubqueryExpression(RelationalSqlParser.SubqueryExpressionContext ctx) {
-    return new SubqueryExpression(getLocation(ctx), (Query) visit(ctx.query()));
-  }
-
-  @Override
-  public Node visitDereference(RelationalSqlParser.DereferenceContext ctx) {
-    return new DereferenceExpression(
-        getLocation(ctx), (Expression) visit(ctx.base), (Identifier) visit(ctx.fieldName));
-  }
-
-  @Override
-  public Node visitColumnReference(RelationalSqlParser.ColumnReferenceContext ctx) {
-    return visit(ctx.identifier());
-  }
-
-  @Override
-  public Node visitSimpleCase(RelationalSqlParser.SimpleCaseContext ctx) {
-    if (ctx.elseExpression != null) {
-      return new SimpleCaseExpression(
-          getLocation(ctx),
-          (Expression) visit(ctx.operand),
-          visit(ctx.whenClause(), WhenClause.class),
-          (Expression) visit(ctx.elseExpression));
-    } else {
-      return new SimpleCaseExpression(
-          getLocation(ctx),
-          (Expression) visit(ctx.operand),
-          visit(ctx.whenClause(), WhenClause.class));
-    }
-  }
-
-  @Override
-  public Node visitSearchedCase(RelationalSqlParser.SearchedCaseContext ctx) {
-    if (ctx.elseExpression != null) {
-      return new SearchedCaseExpression(
-          getLocation(ctx),
-          visit(ctx.whenClause(), WhenClause.class),
-          (Expression) visit(ctx.elseExpression));
-    } else {
-      return new SearchedCaseExpression(
-          getLocation(ctx), visit(ctx.whenClause(), WhenClause.class));
-    }
-  }
-
-  @Override
-  public Node visitWhenClause(RelationalSqlParser.WhenClauseContext ctx) {
-    return new WhenClause(
-        getLocation(ctx), (Expression) visit(ctx.condition), (Expression) visit(ctx.result));
-  }
-
-  @Override
-  public Node visitFunctionCall(RelationalSqlParser.FunctionCallContext ctx) {
-    Optional<Window> window = visitIfPresent(ctx.over(), Window.class);
-
-    QualifiedName name = getQualifiedName(ctx.qualifiedName());
-
-    boolean distinct = isDistinct(ctx.setQuantifier());
-
-    RelationalSqlParser.ProcessingModeContext processingMode = ctx.processingMode();
-    RelationalSqlParser.NullTreatmentContext nullTreatment = ctx.nullTreatment();
-
-    if (name.toString().equalsIgnoreCase("if")) {
-      check(
-          ctx.expression().size() == 2 || ctx.expression().size() == 3,
-          "Invalid number of arguments for 'if' function",
-          ctx);
-      check(!distinct, "DISTINCT not valid for 'if' function", ctx);
-      check(processingMode == null, "Running or final semantics not valid for 'if' function", ctx);
-      check(nullTreatment == null, "Null treatment clause not valid for 'if' function", ctx);
-
-      Expression elseExpression = null;
-      if (ctx.expression().size() == 3) {
-        elseExpression = (Expression) visit(ctx.expression(2));
-      }
-
-      return new IfExpression(
-          getLocation(ctx),
-          (Expression) visit(ctx.expression(0)),
-          (Expression) visit(ctx.expression(1)),
-          elseExpression);
-    }
-
-    if (name.toString().equalsIgnoreCase("nullif")) {
-      check(ctx.expression().size() == 2, "Invalid number of arguments for 'nullif' function", ctx);
-      check(!distinct, "DISTINCT not valid for 'nullif' function", ctx);
-      check(
-          processingMode == null,
-          "Running or final semantics not valid for 'nullif' function",
-          ctx);
-      check(nullTreatment == null, "Null treatment clause not valid for 'nullif' function", ctx);
-
-      return new NullIfExpression(
-          getLocation(ctx),
-          (Expression) visit(ctx.expression(0)),
-          (Expression) visit(ctx.expression(1)));
-    }
-
-    if (name.toString().equalsIgnoreCase("coalesce")) {
-      check(
-          ctx.expression().size() >= 2,
-          "The 'coalesce' function must have at least two arguments",
-          ctx);
-      check(!distinct, "DISTINCT not valid for 'coalesce' function", ctx);
-      check(
-          processingMode == null,
-          "Running or final semantics not valid for 'coalesce' function",
-          ctx);
-      check(nullTreatment == null, "Null treatment clause not valid for 'coalesce' function", ctx);
-
-      return new CoalesceExpression(getLocation(ctx), visit(ctx.expression(), Expression.class));
-    }
-
-    Optional<ProcessingMode> mode = Optional.empty();
-    if (processingMode != null) {
-      if (processingMode.RUNNING() != null) {
-        mode = Optional.of(new ProcessingMode(getLocation(processingMode), RUNNING));
-      } else if (processingMode.FINAL() != null) {
-        mode = Optional.of(new ProcessingMode(getLocation(processingMode), FINAL));
-      }
-    }
-
-    Optional<FunctionCall.NullTreatment> nulls = Optional.empty();
-    if (nullTreatment != null) {
-      if (nullTreatment.IGNORE() != null) {
-        nulls = Optional.of(FunctionCall.NullTreatment.IGNORE);
-      } else if (nullTreatment.RESPECT() != null) {
-        nulls = Optional.of(FunctionCall.NullTreatment.RESPECT);
-      }
-    }
-
-    List<Expression> arguments = visit(ctx.expression(), Expression.class);
-    if (ctx.label != null) {
-      arguments =
-          ImmutableList.of(
-              new DereferenceExpression(getLocation(ctx.label), (Identifier) visit(ctx.label)));
-    }
-
-    if (name.toString().equalsIgnoreCase(APPROX_COUNT_DISTINCT)) {
-      if (arguments.size() == 2
-          && !(arguments.get(1) instanceof DoubleLiteral
-              || arguments.get(1) instanceof LongLiteral
-              || arguments.get(1) instanceof StringLiteral)) {
-        throw new SemanticException(
-            "The second argument of 'approx_count_distinct' function must be a literal");
-      }
-    } else if (name.toString().equalsIgnoreCase(APPROX_MOST_FREQUENT)) {
-      if (arguments.size() == 3
-          && (!(arguments.get(1) instanceof LongLiteral)
-              || !(arguments.get(2) instanceof LongLiteral))) {
-        throw new SemanticException(
-            "The second and third argument of 'approx_most_frequent' function must be positive integer literal");
-      }
-    } else if (name.toString().equalsIgnoreCase(APPROX_PERCENTILE)) {
-      if (arguments.size() == 2 && !(arguments.get(1) instanceof DoubleLiteral)) {
-        throw new SemanticException(
-            "The second argument of 'approx_percentile' function percentage must be a double literal");
-      } else if (arguments.size() == 3 && !(arguments.get(2) instanceof DoubleLiteral)) {
-        throw new SemanticException(
-            "The third argument of 'approx_percentile' function percentage must be a double literal");
-      }
-    }
-
-    return new FunctionCall(getLocation(ctx), name, window, nulls, distinct, mode, arguments);
-  }
-
-  @Override
-  public Node visitDateBinGapFill(RelationalSqlParser.DateBinGapFillContext ctx) {
-    TimeDuration timeDuration =
-        DataNodeDateTimeUtils.constructTimeDuration(ctx.timeDuration().getText());
-
-    if (timeDuration.monthDuration != 0 && timeDuration.nonMonthDuration != 0) {
-      throw new SemanticException(
-          "Simultaneous setting of monthly and non-monthly intervals is not supported.");
-    }
-
-    LongLiteral monthDuration =
-        new LongLiteral(
-            getLocation(ctx.timeDuration()), String.valueOf(timeDuration.monthDuration));
-    LongLiteral nonMonthDuration =
-        new LongLiteral(
-            getLocation(ctx.timeDuration()), String.valueOf(timeDuration.nonMonthDuration));
-    LongLiteral origin =
-        ctx.timeValue() == null
-            ? new LongLiteral("0")
-            : new LongLiteral(
-                getLocation(ctx.timeValue()),
-                String.valueOf(parseTimeValue(ctx.timeValue(), CommonDateTimeUtils.currentTime())));
-
-    List<Expression> arguments =
-        Arrays.asList(
-            monthDuration,
-            nonMonthDuration,
-            (Expression) visit(ctx.valueExpression()),
-            origin,
-            new BooleanLiteral("true"));
-    return new FunctionCall(
-        getLocation(ctx), QualifiedName.of(DATE_BIN.getFunctionName()), arguments);
-  }
-
-  @Override
-  public Node visitDateBin(RelationalSqlParser.DateBinContext ctx) {
-    TimeDuration timeDuration =
-        DataNodeDateTimeUtils.constructTimeDuration(ctx.timeDuration().getText());
-
-    if (timeDuration.monthDuration != 0 && timeDuration.nonMonthDuration != 0) {
-      throw new SemanticException(
-          "Simultaneous setting of monthly and non-monthly intervals is not supported.");
-    }
-
-    LongLiteral monthDuration =
-        new LongLiteral(
-            getLocation(ctx.timeDuration()), String.valueOf(timeDuration.monthDuration));
-    LongLiteral nonMonthDuration =
-        new LongLiteral(
-            getLocation(ctx.timeDuration()), String.valueOf(timeDuration.nonMonthDuration));
-    LongLiteral origin =
-        ctx.timeValue() == null
-            ? new LongLiteral("0")
-            : new LongLiteral(
-                getLocation(ctx.timeValue()),
-                String.valueOf(parseTimeValue(ctx.timeValue(), CommonDateTimeUtils.currentTime())));
-
-    List<Expression> arguments =
-        Arrays.asList(
-            monthDuration, nonMonthDuration, (Expression) visit(ctx.valueExpression()), origin);
-    return new FunctionCall(
-        getLocation(ctx), QualifiedName.of(DATE_BIN.getFunctionName()), arguments);
-  }
-
-  private long parseTimeValue(RelationalSqlParser.TimeValueContext ctx, long currentTime) {
-    if (ctx.INTEGER_VALUE() != null) {
-      try {
-        if (ctx.MINUS() != null) {
-          return -parseLong(ctx.INTEGER_VALUE().getText());
-        }
-        return parseLong(ctx.INTEGER_VALUE().getText());
-      } catch (NumberFormatException e) {
-        throw new SemanticException(
-            String.format("Can not parse %s to long value", ctx.INTEGER_VALUE().getText()));
-      }
-    } else {
-      return parseDateExpression(ctx.dateExpression(), currentTime);
-    }
-  }
-
-  @Override
-  public Node visitColumns(RelationalSqlParser.ColumnsContext ctx) {
-    String pattern = null;
-    RelationalSqlParser.StringContext context = ctx.pattern;
-    if (context != null) {
-      pattern = unquote(context.getText());
-    }
-    return new Columns(getLocation(ctx), pattern);
-  }
-
-  @Override
-  public Node visitPatternAlternation(RelationalSqlParser.PatternAlternationContext context) {
-    List<RowPattern> parts = visit(context.rowPattern(), RowPattern.class);
-    return new PatternAlternation(getLocation(context), parts);
-  }
-
-  @Override
-  public Node visitPatternConcatenation(RelationalSqlParser.PatternConcatenationContext context) {
-    List<RowPattern> parts = visit(context.rowPattern(), RowPattern.class);
-    return new PatternConcatenation(getLocation(context), parts);
-  }
-
-  @Override
-  public Node visitQuantifiedPrimary(RelationalSqlParser.QuantifiedPrimaryContext context) {
-    RowPattern primary = (RowPattern) visit(context.patternPrimary());
-    if (context.patternQuantifier() != null) {
-      return new QuantifiedPattern(
-          getLocation(context), primary, (PatternQuantifier) visit(context.patternQuantifier()));
-    }
-    return primary;
-  }
-
-  @Override
-  public Node visitPatternVariable(RelationalSqlParser.PatternVariableContext context) {
-    return new PatternVariable(getLocation(context), (Identifier) visit(context.identifier()));
-  }
-
-  @Override
-  public Node visitEmptyPattern(RelationalSqlParser.EmptyPatternContext context) {
-    return new EmptyPattern(getLocation(context));
-  }
-
-  @Override
-  public Node visitPatternPermutation(RelationalSqlParser.PatternPermutationContext context) {
-    return new PatternPermutation(
-        getLocation(context), visit(context.rowPattern(), RowPattern.class));
-  }
-
-  @Override
-  public Node visitGroupedPattern(RelationalSqlParser.GroupedPatternContext context) {
-    // skip parentheses
-    return visit(context.rowPattern());
-  }
-
-  @Override
-  public Node visitPartitionStartAnchor(RelationalSqlParser.PartitionStartAnchorContext context) {
-    return new AnchorPattern(getLocation(context), PARTITION_START);
-  }
-
-  @Override
-  public Node visitPartitionEndAnchor(RelationalSqlParser.PartitionEndAnchorContext context) {
-    return new AnchorPattern(getLocation(context), PARTITION_END);
-  }
-
-  @Override
-  public Node visitExcludedPattern(RelationalSqlParser.ExcludedPatternContext context) {
-    return new ExcludedPattern(getLocation(context), (RowPattern) visit(context.rowPattern()));
-  }
-
-  @Override
-  public Node visitZeroOrMoreQuantifier(RelationalSqlParser.ZeroOrMoreQuantifierContext context) {
-    boolean greedy = context.reluctant == null;
-    return new ZeroOrMoreQuantifier(getLocation(context), greedy);
-  }
-
-  @Override
-  public Node visitOneOrMoreQuantifier(RelationalSqlParser.OneOrMoreQuantifierContext context) {
-    boolean greedy = context.reluctant == null;
-    return new OneOrMoreQuantifier(getLocation(context), greedy);
-  }
-
-  @Override
-  public Node visitZeroOrOneQuantifier(RelationalSqlParser.ZeroOrOneQuantifierContext context) {
-    boolean greedy = context.reluctant == null;
-    return new ZeroOrOneQuantifier(getLocation(context), greedy);
-  }
-
-  @Override
-  public Node visitRangeQuantifier(RelationalSqlParser.RangeQuantifierContext context) {
-    boolean greedy = context.reluctant == null;
-
-    Optional<LongLiteral> atLeast = Optional.empty();
-    Optional<LongLiteral> atMost = Optional.empty();
-    if (context.exactly != null) {
-      atLeast =
-          Optional.of(new LongLiteral(getLocation(context.exactly), context.exactly.getText()));
-      atMost =
-          Optional.of(new LongLiteral(getLocation(context.exactly), context.exactly.getText()));
-    }
-    if (context.atLeast != null) {
-      atLeast =
-          Optional.of(new LongLiteral(getLocation(context.atLeast), context.atLeast.getText()));
-    }
-    if (context.atMost != null) {
-      atMost = Optional.of(new LongLiteral(getLocation(context.atMost), context.atMost.getText()));
-    }
-    return new RangeQuantifier(getLocation(context), greedy, atLeast, atMost);
-  }
-
-  // ************** literals **************
-
-  @Override
-  public Node visitNullLiteral(RelationalSqlParser.NullLiteralContext ctx) {
-    return new NullLiteral(getLocation(ctx));
-  }
-
-  @Override
-  public Node visitBasicStringLiteral(RelationalSqlParser.BasicStringLiteralContext ctx) {
-    return new StringLiteral(getLocation(ctx), unquote(ctx.STRING().getText()));
-  }
-
-  @Override
-  public Node visitUnicodeStringLiteral(RelationalSqlParser.UnicodeStringLiteralContext ctx) {
-    return new StringLiteral(getLocation(ctx), decodeUnicodeLiteral(ctx));
-  }
-
-  @Override
-  public Node visitBinaryLiteral(RelationalSqlParser.BinaryLiteralContext ctx) {
-    String raw = ctx.BINARY_LITERAL().getText();
-    return new BinaryLiteral(getLocation(ctx), unquote(raw.substring(1)));
-  }
-
-  @Override
-  public Node visitDecimalLiteral(RelationalSqlParser.DecimalLiteralContext ctx) {
-    return new DoubleLiteral(getLocation(ctx), ctx.getText());
-  }
-
-  @Override
-  public Node visitDoubleLiteral(RelationalSqlParser.DoubleLiteralContext ctx) {
-    return new DoubleLiteral(getLocation(ctx), ctx.getText());
-  }
-
-  @Override
-  public Node visitIntegerLiteral(RelationalSqlParser.IntegerLiteralContext ctx) {
-    return new LongLiteral(getLocation(ctx), ctx.getText());
-  }
-
-  @Override
-  public Node visitBooleanLiteral(RelationalSqlParser.BooleanLiteralContext ctx) {
-    return new BooleanLiteral(getLocation(ctx), ctx.getText());
-  }
-
-  @Override
-  public Node visitDatetimeLiteral(RelationalSqlParser.DatetimeLiteralContext ctx) {
-    return new LongLiteral(
-        getLocation(ctx),
-        String.valueOf(
-            parseDateTimeFormat(
-                ctx.getChild(0).getText(), CommonDateTimeUtils.currentTime(), zoneId)));
-  }
-
-  @Override
-  public Node visitParameter(RelationalSqlParser.ParameterContext ctx) {
-    Parameter parameter = new Parameter(getLocation(ctx), parameterPosition);
-    parameterPosition++;
-    return parameter;
-  }
-
-  @Override
-  public Node visitIdentifierOrString(RelationalSqlParser.IdentifierOrStringContext ctx) {
-    String s = null;
-    if (ctx.identifier() != null) {
-      return visit(ctx.identifier());
-    } else if (ctx.string() != null) {
-      s = ((StringLiteral) visit(ctx.string())).getValue();
-    }
-
-    return new Identifier(getLocation(ctx), s);
-  }
-
-  @Override
-  public Node visitIntervalField(RelationalSqlParser.IntervalFieldContext ctx) {
-    return super.visitIntervalField(ctx);
-  }
-
-  // ***************** AI *****************
-  public static void validateModelId(String modelId) {
-    if (modelId.length() < 2 || modelId.length() > 64) {
-      throw new SemanticException(DataNodeQueryMessages.MODELID_SHOULD_BE_2_64_CHARACTERS);
-    } else if (modelId.startsWith("_")) {
-      throw new SemanticException(DataNodeQueryMessages.MODELID_SHOULD_NOT_START_WITH);
-    } else if (!modelId.matches("^[-\\w]*$")) {
-      throw new SemanticException(
-          DataNodeQueryMessages.MODELID_CAN_ONLY_CONTAIN_LETTERS_NUMBERS_AND_UNDERSCORES);
-    }
-  }
-
-  private static List<String> convertToDeviceIdList(String rawDeviceString) {
-    String[] deviceIdList = rawDeviceString.split(",");
-    List<String> result = new ArrayList<>();
-    for (String deviceId : deviceIdList) {
-      deviceId = deviceId.trim();
-      if (deviceId.equals("cpu")) {
-        result.add("cpu");
-        continue;
-      }
-      try {
-        Integer.valueOf(deviceId);
-      } catch (NumberFormatException e) {
-        throw new SemanticException(DataNodeQueryMessages.DEVICE_ID_SHOULD_BE_CPU_OR_INTEGER);
-      }
-      result.add(deviceId);
-    }
-    return result;
-  }
-
-  @Override
-  public Node visitCreateModelStatement(RelationalSqlParser.CreateModelStatementContext ctx) {
-    String modelId = ctx.modelId.getText();
-    validateModelId(modelId);
-    if (ctx.uriClause() == null) {
-      if (ctx.targetData == null) {
-        throw new SemanticException(DataNodeQueryMessages.TARGET_DATA_IN_SQL_SHOULD_BE_SET_IN);
-      }
-      String targetData = ((StringLiteral) visit(ctx.targetData)).getValue();
-      CreateTraining createTraining = new CreateTraining(modelId, targetData);
-      if (ctx.HYPERPARAMETERS() != null) {
-        Map<String, String> parameters = new HashMap<>();
-        for (RelationalSqlParser.HparamPairContext hparamPairContext : ctx.hparamPair()) {
-          parameters.put(
-              hparamPairContext.hparamKey.getText(), hparamPairContext.hyparamValue.getText());
-        }
-        createTraining.setParameters(parameters);
-      }
-
-      if (ctx.existingModelId != null) {
-        createTraining.setExistingModelId(ctx.existingModelId.getText());
-      }
-
-      return createTraining;
-    }
-    String uri = ((Identifier) visit(ctx.uriClause().uri)).getValue();
-    return new CreateModel(modelId, uri);
-  }
-
-  @Override
-  public Node visitLoadModelStatement(RelationalSqlParser.LoadModelStatementContext ctx) {
-    List<String> deviceIds = convertToDeviceIdList(unquote(ctx.deviceIdList.getText()));
-    String modelId = ctx.existingModelId.getText();
-    validateModelId(modelId);
-    return new LoadModel(modelId, deviceIds);
-  }
-
-  @Override
-  public Node visitUnloadModelStatement(RelationalSqlParser.UnloadModelStatementContext ctx) {
-    List<String> deviceIds = convertToDeviceIdList(unquote(ctx.deviceIdList.getText()));
-    String modelId = ctx.existingModelId.getText();
-    validateModelId(modelId);
-    return new UnloadModel(modelId, deviceIds);
-  }
-
-  @Override
-  public Node visitShowModelsStatement(RelationalSqlParser.ShowModelsStatementContext ctx) {
-    ShowModels showModels = new ShowModels();
-    if (ctx.modelId != null) {
-      String modelId = ctx.modelId.getText();
-      validateModelId(modelId);
-      showModels.setModelId(modelId);
-    }
-    return showModels;
-  }
-
-  @Override
-  public Node visitShowLoadedModelsStatement(
-      RelationalSqlParser.ShowLoadedModelsStatementContext ctx) {
-    return new ShowLoadedModels(
-        ctx.deviceIdList != null
-            ? convertToDeviceIdList(unquote(ctx.deviceIdList.getText()))
-            : null);
-  }
-
-  @Override
-  public Node visitShowAIDevicesStatement(RelationalSqlParser.ShowAIDevicesStatementContext ctx) {
-    return new ShowAIDevices();
-  }
-
-  @Override
-  public Node visitDropModelStatement(RelationalSqlParser.DropModelStatementContext ctx) {
-    String modelId = ctx.modelId.getText();
-    validateModelId(modelId);
-    return new DropModel(modelId);
-  }
-
-  @Override
-  public Node visitPrepareStatement(RelationalSqlParser.PrepareStatementContext ctx) {
-    Identifier statementName = lowerIdentifier((Identifier) visit(ctx.statementName));
-    Statement sql = (Statement) visit(ctx.sql);
-    return new Prepare(getLocation(ctx), statementName, sql);
-  }
-
-  @Override
-  public Node visitExecuteStatement(RelationalSqlParser.ExecuteStatementContext ctx) {
-    Identifier statementName = lowerIdentifier((Identifier) visit(ctx.statementName));
-    List<Literal> parameters =
-        ctx.literalExpression() != null && !ctx.literalExpression().isEmpty()
-            ? visit(ctx.literalExpression(), Literal.class)
-            : ImmutableList.of();
-    return new Execute(getLocation(ctx), statementName, parameters);
-  }
-
-  @Override
-  public Node visitExecuteImmediateStatement(
-      RelationalSqlParser.ExecuteImmediateStatementContext ctx) {
-    StringLiteral sql = (StringLiteral) visit(ctx.sql);
-    List<Literal> parameters =
-        ctx.literalExpression() != null && !ctx.literalExpression().isEmpty()
-            ? visit(ctx.literalExpression(), Literal.class)
-            : ImmutableList.of();
-    return new ExecuteImmediate(getLocation(ctx), sql, parameters);
-  }
-
-  @Override
-  public Node visitDeallocateStatement(RelationalSqlParser.DeallocateStatementContext ctx) {
-    Identifier statementName = lowerIdentifier((Identifier) visit(ctx.statementName));
-    return new Deallocate(getLocation(ctx), statementName);
-  }
-
-  // ***************** arguments *****************
-  @Override
-  public Node visitGenericType(RelationalSqlParser.GenericTypeContext ctx) {
-    List<DataTypeParameter> parameters =
-        ctx.typeParameter().stream()
-            .map(this::visit)
-            .map(DataTypeParameter.class::cast)
-            .collect(toImmutableList());
-
-    return new GenericDataType(getLocation(ctx), (Identifier) visit(ctx.identifier()), parameters);
-  }
-
-  @Override
-  public Node visitTypeParameter(RelationalSqlParser.TypeParameterContext ctx) {
-    if (ctx.INTEGER_VALUE() != null) {
-      return new NumericParameter(getLocation(ctx), ctx.getText());
-    }
-
-    return new TypeParameter((DataType) visit(ctx.type()));
-  }
-
-  // ***************** helpers *****************
-
-  private enum UnicodeDecodeState {
-    EMPTY,
-    ESCAPED,
-    UNICODE_SEQUENCE
-  }
-
-  private static String decodeUnicodeLiteral(
-      RelationalSqlParser.UnicodeStringLiteralContext context) {
-    char escape;
-    if (context.UESCAPE() != null) {
-      String escapeString = unquote(context.STRING().getText());
-      check(!escapeString.isEmpty(), "Empty Unicode escape character", context);
-      check(
-          escapeString.length() == 1, "Invalid Unicode escape character: " + escapeString, context);
-      escape = escapeString.charAt(0);
-      check(
-          isValidUnicodeEscape(escape),
-          "Invalid Unicode escape character: " + escapeString,
-          context);
-    } else {
-      escape = '\\';
-    }
-
-    String rawContent = unquote(context.UNICODE_STRING().getText().substring(2));
-    StringBuilder unicodeStringBuilder = new StringBuilder();
-    StringBuilder escapedCharacterBuilder = new StringBuilder();
-    int charactersNeeded = 0;
-    UnicodeDecodeState state = UnicodeDecodeState.EMPTY;
-    for (int i = 0; i < rawContent.length(); i++) {
-      char ch = rawContent.charAt(i);
-      switch (state) {
-        case EMPTY:
-          if (ch == escape) {
-            state = UnicodeDecodeState.ESCAPED;
-          } else {
-            unicodeStringBuilder.append(ch);
-          }
-          break;
-        case ESCAPED:
-          if (ch == escape) {
-            unicodeStringBuilder.append(escape);
-            state = UnicodeDecodeState.EMPTY;
-          } else if (ch == '+') {
-            state = UnicodeDecodeState.UNICODE_SEQUENCE;
-            charactersNeeded = 6;
-          } else if (isHexDigit(ch)) {
-            state = UnicodeDecodeState.UNICODE_SEQUENCE;
-            charactersNeeded = 4;
-            escapedCharacterBuilder.append(ch);
-          } else {
-            throw parseError("Invalid hexadecimal digit: " + ch, context);
-          }
-          break;
-        case UNICODE_SEQUENCE:
-          check(isHexDigit(ch), "Incomplete escape sequence: " + escapedCharacterBuilder, context);
-          escapedCharacterBuilder.append(ch);
-          if (charactersNeeded == escapedCharacterBuilder.length()) {
-            String currentEscapedCode = escapedCharacterBuilder.toString();
-            escapedCharacterBuilder.setLength(0);
-            int codePoint = Integer.parseInt(currentEscapedCode, 16);
-            check(
-                Character.isValidCodePoint(codePoint),
-                "Invalid escaped character: " + currentEscapedCode,
-                context);
-            if (Character.isSupplementaryCodePoint(codePoint)) {
-              unicodeStringBuilder.appendCodePoint(codePoint);
-            } else {
-              char currentCodePoint = (char) codePoint;
-              if (Character.isSurrogate(currentCodePoint)) {
-                throw parseError(
-                    String.format(
-                        "Invalid escaped character: %s. Escaped character is a surrogate. Use '\\+123456' instead.",
-                        currentEscapedCode),
-                    context);
-              }
-              unicodeStringBuilder.append(currentCodePoint);
-            }
-            state = UnicodeDecodeState.EMPTY;
-            charactersNeeded = -1;
-          } else {
-            check(
-                charactersNeeded > escapedCharacterBuilder.length(),
-                "Unexpected escape sequence length: " + escapedCharacterBuilder.length(),
-                context);
-          }
-          break;
-        default:
-          throw new UnsupportedOperationException();
-      }
-    }
-
-    check(
-        state == UnicodeDecodeState.EMPTY,
-        "Incomplete escape sequence: " + escapedCharacterBuilder.toString(),
-        context);
-    return unicodeStringBuilder.toString();
-  }
-
-  private <T> Optional<T> visitIfPresent(ParserRuleContext context, Class<T> clazz) {
-    return Optional.ofNullable(context).map(this::visit).map(clazz::cast);
-  }
-
-  private <T> List<T> visit(List<? extends ParserRuleContext> contexts, Class<T> clazz) {
-    return contexts.stream().map(this::visit).map(clazz::cast).collect(toList());
-  }
-
-  private static String unquote(String value) {
-    return value.substring(1, value.length() - 1).replace("''", "'");
-  }
-
-  private QualifiedName getQualifiedName(RelationalSqlParser.QualifiedNameContext context) {
-    final QualifiedName result = QualifiedName.of(visit(context.identifier(), Identifier.class));
-    if (!result.getPrefix().map(s -> PathUtils.isTableModelDatabase(s.toString())).orElse(true)) {
-      throw new SemanticException(
-          DataNodeQueryMessages.THE_TREE_MODEL_DATABASE_SHALL_NOT_BE_SPECIFIED);
-    }
-    return result;
-  }
-
-  private static boolean isDistinct(RelationalSqlParser.SetQuantifierContext setQuantifier) {
-    return setQuantifier != null && setQuantifier.DISTINCT() != null;
-  }
-
-  private static boolean isHexDigit(char c) {
-    return ((c >= '0') && (c <= '9')) || ((c >= 'A') && (c <= 'F')) || ((c >= 'a') && (c <= 'f'));
-  }
-
-  private static boolean isValidUnicodeEscape(char c) {
-    return c < 0x7F && c > 0x20 && !isHexDigit(c) && c != '"' && c != '+' && c != '\'';
-  }
-
-  private static Optional<String> getTextIfPresent(ParserRuleContext context) {
-    return Optional.ofNullable(context).map(ParseTree::getText);
-  }
-
-  private Optional<Identifier> getIdentifierIfPresent(ParserRuleContext context) {
-    return Optional.ofNullable(context).map(c -> (Identifier) visit(c));
-  }
-
-  private static TsTableColumnCategory getColumnCategory(final Token category) {
-    if (category == null) {
-      return FIELD;
-    }
-    switch (category.getType()) {
-      case RelationalSqlLexer.TAG:
-        return TAG;
-      case RelationalSqlLexer.ATTRIBUTE:
-        return ATTRIBUTE;
-      case RelationalSqlLexer.TIME:
-        return TIME;
-      case RelationalSqlLexer.FIELD:
-        return FIELD;
-      default:
-        throw new UnsupportedOperationException(
-            "Unsupported ColumnCategory: " + category.getText());
-    }
-  }
-
-  private static ArithmeticBinaryExpression.Operator getArithmeticBinaryOperator(Token operator) {
-    switch (operator.getType()) {
-      case RelationalSqlLexer.PLUS:
-        return ArithmeticBinaryExpression.Operator.ADD;
-      case RelationalSqlLexer.MINUS:
-        return ArithmeticBinaryExpression.Operator.SUBTRACT;
-      case RelationalSqlLexer.ASTERISK:
-        return ArithmeticBinaryExpression.Operator.MULTIPLY;
-      case RelationalSqlLexer.SLASH:
-        return ArithmeticBinaryExpression.Operator.DIVIDE;
-      case RelationalSqlLexer.PERCENT:
-        return ArithmeticBinaryExpression.Operator.MODULUS;
-      default:
-        throw new UnsupportedOperationException(
-            DataNodeQueryMessages.UNSUPPORTED_OPERATOR + operator.getText());
-    }
-  }
-
-  private static ComparisonExpression.Operator getComparisonOperator(Token symbol) {
-    switch (symbol.getType()) {
-      case RelationalSqlLexer.EQ:
-        return ComparisonExpression.Operator.EQUAL;
-      case RelationalSqlLexer.NEQ:
-        return ComparisonExpression.Operator.NOT_EQUAL;
-      case RelationalSqlLexer.LT:
-        return ComparisonExpression.Operator.LESS_THAN;
-      case RelationalSqlLexer.LTE:
-        return ComparisonExpression.Operator.LESS_THAN_OR_EQUAL;
-      case RelationalSqlLexer.GT:
-        return ComparisonExpression.Operator.GREATER_THAN;
-      case RelationalSqlLexer.GTE:
-        return ComparisonExpression.Operator.GREATER_THAN_OR_EQUAL;
-      default:
-        throw new IllegalArgumentException(
-            DataNodeQueryMessages.UNSUPPORTED_OPERATOR + symbol.getText());
-    }
-  }
-
-  private static CurrentTime.Function getDateTimeFunctionType(Token token) {
-    switch (token.getType()) {
-      case RelationalSqlLexer.CURRENT_DATE:
-        return CurrentTime.Function.DATE;
-      case RelationalSqlLexer.CURRENT_TIME:
-        return CurrentTime.Function.TIME;
-      case RelationalSqlLexer.CURRENT_TIMESTAMP:
-      case RelationalSqlLexer.NOW:
-        return CurrentTime.Function.TIMESTAMP;
-      case RelationalSqlLexer.LOCALTIME:
-        return CurrentTime.Function.LOCALTIME;
-      case RelationalSqlLexer.LOCALTIMESTAMP:
-        return CurrentTime.Function.LOCALTIMESTAMP;
-      default:
-        throw new IllegalArgumentException(
-            DataNodeQueryMessages.UNSUPPORTED_SPECIAL_FUNCTION + token.getText());
-    }
-  }
-
-  private static SortItem.NullOrdering getNullOrderingType(Token token) {
-    switch (token.getType()) {
-      case RelationalSqlLexer.FIRST:
-        return SortItem.NullOrdering.FIRST;
-      case RelationalSqlLexer.LAST:
-        return SortItem.NullOrdering.LAST;
-      default:
-        throw new IllegalArgumentException(
-            DataNodeQueryMessages.UNSUPPORTED_ORDERING + token.getText());
-    }
-  }
-
-  private static SortItem.Ordering getOrderingType(Token token) {
-    switch (token.getType()) {
-      case RelationalSqlLexer.ASC:
-        return SortItem.Ordering.ASCENDING;
-      case RelationalSqlLexer.DESC:
-        return SortItem.Ordering.DESCENDING;
-      default:
-        throw new IllegalArgumentException(
-            DataNodeQueryMessages.UNSUPPORTED_ORDERING + token.getText());
-    }
-  }
-
-  private static QuantifiedComparisonExpression.Quantifier getComparisonQuantifier(Token symbol) {
-    switch (symbol.getType()) {
-      case RelationalSqlLexer.ALL:
-        return QuantifiedComparisonExpression.Quantifier.ALL;
-      case RelationalSqlLexer.ANY:
-        return QuantifiedComparisonExpression.Quantifier.ANY;
-      case RelationalSqlLexer.SOME:
-        return QuantifiedComparisonExpression.Quantifier.SOME;
-      default:
-        throw new IllegalArgumentException(
-            DataNodeQueryMessages.UNSUPPORTED_QUANTIFIER + symbol.getText());
-    }
-  }
-
-  private List<Identifier> getIdentifiers(List<RelationalSqlParser.IdentifierContext> identifiers) {
-    return identifiers.stream().map(context -> (Identifier) visit(context)).collect(toList());
-  }
-
-  private static void check(boolean condition, String message, ParserRuleContext context) {
-    if (!condition) {
-      throw parseError(message, context);
-    }
-  }
-
-  private NodeLocation getLocation(TerminalNode terminalNode) {
-    requireNonNull(terminalNode, "terminalNode is null");
-    return getLocation(terminalNode.getSymbol());
-  }
-
-  private NodeLocation getLocation(ParserRuleContext parserRuleContext) {
-    requireNonNull(parserRuleContext, "parserRuleContext is null");
-    return getLocation(parserRuleContext.getStart());
-  }
-
-  private NodeLocation getLocation(Token token) {
-    requireNonNull(token, "token is null");
-    return baseLocation != null
-        ? new NodeLocation(
-            token.getLine() + baseLocation.getLineNumber() - 1,
-            token.getCharPositionInLine()
-                + 1
-                + (token.getLine() == 1 ? baseLocation.getColumnNumber() : 0))
-        : new NodeLocation(token.getLine(), token.getCharPositionInLine() + 1);
-  }
-
-  private static ParsingException parseError(String message, ParserRuleContext context) {
-    return new ParsingException(
-        message,
-        null,
-        context.getStart().getLine(),
-        context.getStart().getCharPositionInLine() + 1);
-  }
-
-  private static void validateArgumentAlias(Identifier alias, ParserRuleContext context) {
-    check(
-        alias.isDelimited() || !alias.getValue().equalsIgnoreCase("COPARTITION"),
-        "The word \"COPARTITION\" is ambiguous in this context. "
-            + "To alias an argument, precede the alias with \"AS\". "
-            + "To specify co-partitioning, change the argument order so that the last argument cannot be aliased.",
-        context);
-  }
-}
diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/util/AstUtil.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/util/AstUtil.java
deleted file mode 100644
index 986501a1976..00000000000
--- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/util/AstUtil.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * 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.sql.util;
-
-import org.apache.iotdb.commons.exception.SemanticException;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.Expression;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.Identifier;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.Literal;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.LongLiteral;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.Node;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.NullLiteral;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.StringLiteral;
-import org.apache.iotdb.commons.utils.CommonDateTimeUtils;
-import org.apache.iotdb.db.i18n.DataNodeQueryMessages;
-
-import com.google.common.graph.SuccessorsFunction;
-import com.google.common.graph.Traverser;
-
-import java.time.ZoneId;
-import java.util.List;
-import java.util.OptionalInt;
-import java.util.function.BiFunction;
-import java.util.function.Function;
-import java.util.stream.Stream;
-
-import static com.google.common.collect.Streams.stream;
-import static java.util.Objects.requireNonNull;
-import static org.apache.iotdb.db.queryengine.plan.parser.ASTVisitor.parseDateTimeFormat;
-
-public final class AstUtil {
-
-  public static Stream<Node> preOrder(Node node) {
-    return stream(
-        Traverser.forTree((SuccessorsFunction<Node>) Node::getChildren)
-            .depthFirstPreOrder(requireNonNull(node, "node is null")));
-  }
-
-  /**
-   * Compares two AST trees recursively by applying the provided comparator to each pair of nodes.
-   *
-   * <p>The comparator can perform a hybrid shallow/deep comparison. If it returns true or false,
-   * the nodes and any subtrees are considered equal or different, respectively. If it returns null,
-   * the nodes are considered shallowly-equal and their children will be compared recursively.
-   */
-  public static boolean treeEqual(
-      Node left, Node right, BiFunction<Node, Node, Boolean> subtreeComparator) {
-    Boolean equal = subtreeComparator.apply(left, right);
-
-    if (equal != null) {
-      return equal;
-    }
-
-    List<? extends Node> leftChildren = left.getChildren();
-    List<? extends Node> rightChildren = right.getChildren();
-
-    if (leftChildren.size() != rightChildren.size()) {
-      return false;
-    }
-
-    for (int i = 0; i < leftChildren.size(); i++) {
-      if (!treeEqual(leftChildren.get(i), rightChildren.get(i), subtreeComparator)) {
-        return false;
-      }
-    }
-
-    return true;
-  }
-
-  /**
-   * Computes a hash of the given AST by applying the provided subtree hasher at each level.
-   *
-   * <p>If the hasher returns a non-empty {@link OptionalInt}, the value is treated as the hash for
-   * the subtree at that node. Otherwise, the hashes of its children are computed and combined.
-   */
-  public static int treeHash(Node node, Function<Node, OptionalInt> subtreeHasher) {
-    OptionalInt hash = subtreeHasher.apply(node);
-
-    if (hash.isPresent()) {
-      return hash.getAsInt();
-    }
-
-    List<? extends Node> children = node.getChildren();
-
-    int result = node.getClass().hashCode();
-    for (Node element : children) {
-      result = 31 * result + treeHash(element, subtreeHasher);
-    }
-
-    return result;
-  }
-
-  public static Object expressionToTsValue(Expression expression) {
-    if (expression instanceof Literal) {
-      return ((Literal) expression).getTsValue();
-    }
-    if (expression instanceof Identifier) {
-      throw new SemanticException(
-          String.format("Cannot insert identifier %s, please use string literal", expression));
-    }
-    throw new SemanticException(DataNodeQueryMessages.UNSUPPORTED_EXPRESSION + expression);
-  }
-
-  public static long expressionToTimestamp(Expression expression, ZoneId zoneId) {
-    long timestamp;
-    if (expression instanceof LongLiteral) {
-      timestamp = ((LongLiteral) expression).getParsedValue();
-    } else if (expression instanceof NullLiteral) {
-      throw new SemanticException(DataNodeQueryMessages.TIMESTAMP_CANNOT_BE_NULL);
-    } else if (expression instanceof StringLiteral) {
-      timestamp =
-          parseDateTimeFormat(
-              ((StringLiteral) expression).getValue(), CommonDateTimeUtils.currentTime(), zoneId);
-    } else {
-      throw new SemanticException(DataNodeQueryMessages.UNSUPPORTED_EXPRESSION + expression);
-    }
-    return timestamp;
-  }
-
-  private AstUtil() {}
-}