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

mbudiu pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/calcite.git


The following commit(s) were added to refs/heads/main by this push:
     new fabf648bb7 [CALCITE-7339] Most classes in SqlDdlNodes use an incorrect 
SqlCallFactory
fabf648bb7 is described below

commit fabf648bb7cdc6bd17bc862068022ea363c5ab11
Author: Mihai Budiu <[email protected]>
AuthorDate: Thu Dec 18 17:12:08 2025 -0800

    [CALCITE-7339] Most classes in SqlDdlNodes use an incorrect SqlCallFactory
    
    Signed-off-by: Mihai Budiu <[email protected]>
---
 .../java/org/apache/calcite/sql/SqlCollation.java  |  23 +++++
 .../java/org/apache/calcite/sql/SqlLambda.java     |   7 ++
 .../calcite/sql/ddl/SqlAttributeDefinition.java    |  24 ++++-
 .../apache/calcite/sql/ddl/SqlCheckConstraint.java |  14 ++-
 .../calcite/sql/ddl/SqlColumnDeclaration.java      |  32 +++++--
 .../calcite/sql/ddl/SqlCreateForeignSchema.java    |  21 ++++-
 .../apache/calcite/sql/ddl/SqlCreateFunction.java  |  25 ++++-
 .../calcite/sql/ddl/SqlCreateMaterializedView.java |  20 +++-
 .../apache/calcite/sql/ddl/SqlCreateSchema.java    |  19 +++-
 .../org/apache/calcite/sql/ddl/SqlCreateTable.java |  19 +++-
 .../apache/calcite/sql/ddl/SqlCreateTableLike.java |  23 ++++-
 .../org/apache/calcite/sql/ddl/SqlCreateType.java  |  17 +++-
 .../org/apache/calcite/sql/ddl/SqlCreateView.java  |  17 +++-
 .../apache/calcite/sql/ddl/SqlDropFunction.java    |  16 +++-
 .../calcite/sql/ddl/SqlDropMaterializedView.java   |  17 +++-
 .../org/apache/calcite/sql/ddl/SqlDropObject.java  |   5 +-
 .../org/apache/calcite/sql/ddl/SqlDropSchema.java  |  19 +++-
 .../org/apache/calcite/sql/ddl/SqlDropTable.java   |  16 +++-
 .../org/apache/calcite/sql/ddl/SqlDropType.java    |  16 +++-
 .../org/apache/calcite/sql/ddl/SqlDropView.java    |  16 +++-
 .../apache/calcite/sql/ddl/SqlKeyConstraint.java   |  25 ++++-
 .../apache/calcite/sql/ddl/SqlTruncateTable.java   |  27 ++++--
 .../java/org/apache/calcite/util/UtilTest.java     |  12 +++
 .../apache/calcite/server/ServerDdlExecutor.java   |   9 +-
 .../org/apache/calcite/test/ServerParserTest.java  | 101 +++++++++++++++++++++
 25 files changed, 483 insertions(+), 57 deletions(-)

diff --git a/core/src/main/java/org/apache/calcite/sql/SqlCollation.java 
b/core/src/main/java/org/apache/calcite/sql/SqlCollation.java
index b02035f791..5f6e4805f7 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlCollation.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlCollation.java
@@ -17,8 +17,10 @@
 package org.apache.calcite.sql;
 
 import org.apache.calcite.config.CalciteSystemProperty;
+import org.apache.calcite.sql.parser.SqlParserPos;
 import org.apache.calcite.sql.parser.SqlParserUtil;
 import org.apache.calcite.util.Glossary;
+import org.apache.calcite.util.ImmutableNullableList;
 import org.apache.calcite.util.SerializableCharset;
 import org.apache.calcite.util.Util;
 
@@ -37,6 +39,8 @@
 
 import static org.apache.calcite.util.Static.RESOURCE;
 
+import static java.util.Objects.requireNonNull;
+
 /**
  * A <code>SqlCollation</code> is an object representing a <code>Collate</code>
  * statement. It is immutable.
@@ -113,6 +117,25 @@ public SqlCollation(
     this.collationName = generateCollationName(charset);
   }
 
+  /** Encode all the information require to reconstruct a SqlCollection in a 
SqlList object. */
+  public SqlNodeList asList() {
+    return new SqlNodeList(
+        ImmutableNullableList.of(
+            SqlLiteral.createCharString(this.getCollationName(), 
SqlParserPos.ZERO),
+            SqlLiteral.createSymbol(coercibility, SqlParserPos.ZERO)),
+        SqlParserPos.ZERO);
+  }
+
+  /** The inverse of the {@link #asList} function. */
+  public static SqlCollation fromSqlList(SqlNodeList list) {
+    assert list.size() == 2;
+    String name = ((SqlLiteral) list.get(0)).getValueAs(String.class);
+    Coercibility coercibility = ((SqlLiteral) 
list.get(1)).symbolValue(Coercibility.class);
+    return new SqlCollation(
+        name,
+        requireNonNull(coercibility, "coercibility"));
+  }
+
   /**
    * Creates a Collation by its coercibility, locale, charset and strength.
    */
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlLambda.java 
b/core/src/main/java/org/apache/calcite/sql/SqlLambda.java
index c0f8b2b145..696753b4f4 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlLambda.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlLambda.java
@@ -107,6 +107,13 @@ private static class SqlLambdaOperator extends 
SqlSpecialOperator {
       super("->", SqlKind.LAMBDA);
     }
 
+    @Override public SqlCall createCall(
+        @Nullable SqlLiteral functionQualifier, SqlParserPos pos, @Nullable 
SqlNode... operands) {
+      return new SqlLambda(pos,
+          (SqlNodeList) requireNonNull(operands[0], "parameters"),
+          requireNonNull(operands[1], "expression"));
+    }
+
     @Override public RelDataType deriveType(
         SqlValidator validator, SqlValidatorScope scope, SqlCall call) {
       final SqlLambda lambdaExpr = (SqlLambda) call;
diff --git 
a/core/src/main/java/org/apache/calcite/sql/ddl/SqlAttributeDefinition.java 
b/core/src/main/java/org/apache/calcite/sql/ddl/SqlAttributeDefinition.java
index a255287846..494c262959 100644
--- a/core/src/main/java/org/apache/calcite/sql/ddl/SqlAttributeDefinition.java
+++ b/core/src/main/java/org/apache/calcite/sql/ddl/SqlAttributeDefinition.java
@@ -21,25 +21,37 @@
 import org.apache.calcite.sql.SqlDataTypeSpec;
 import org.apache.calcite.sql.SqlIdentifier;
 import org.apache.calcite.sql.SqlKind;
+import org.apache.calcite.sql.SqlLiteral;
 import org.apache.calcite.sql.SqlNode;
+import org.apache.calcite.sql.SqlNodeList;
 import org.apache.calcite.sql.SqlOperator;
 import org.apache.calcite.sql.SqlSpecialOperator;
 import org.apache.calcite.sql.SqlWriter;
 import org.apache.calcite.sql.parser.SqlParserPos;
-
-import com.google.common.collect.ImmutableList;
+import org.apache.calcite.util.ImmutableNullableList;
 
 import org.checkerframework.checker.nullness.qual.Nullable;
 
 import java.util.List;
 
+import static java.util.Objects.requireNonNull;
+
 /**
  * Parse tree for SqlAttributeDefinition,
  * which is part of a {@link SqlCreateType}.
  */
 public class SqlAttributeDefinition extends SqlCall {
-  private static final SqlSpecialOperator OPERATOR =
-      new SqlSpecialOperator("ATTRIBUTE_DEF", SqlKind.ATTRIBUTE_DEF);
+  private static final SqlOperator OPERATOR =
+      new SqlSpecialOperator("ATTRIBUTE_DEF", SqlKind.ATTRIBUTE_DEF) {
+        @Override public SqlCall createCall(@Nullable SqlLiteral 
functionQualifier,
+            SqlParserPos pos, @Nullable SqlNode... operands) {
+          return new SqlAttributeDefinition(pos,
+              (SqlIdentifier) requireNonNull(operands[0], "name"),
+              (SqlDataTypeSpec) requireNonNull(operands[1], "dataType"),
+              operands[2],
+              operands[3] != null ? SqlCollation.fromSqlList((SqlNodeList) 
operands[3]) : null);
+        }
+      };
 
   public final SqlIdentifier name;
   public final SqlDataTypeSpec dataType;
@@ -60,8 +72,10 @@ public class SqlAttributeDefinition extends SqlCall {
     return OPERATOR;
   }
 
+  @SuppressWarnings("nullness")
   @Override public List<SqlNode> getOperandList() {
-    return ImmutableList.of(name, dataType);
+    return ImmutableNullableList.of(name, dataType, expression,
+        collation != null ? collation.asList() : null);
   }
 
   @Override public void unparse(SqlWriter writer, int leftPrec, int rightPrec) 
{
diff --git 
a/core/src/main/java/org/apache/calcite/sql/ddl/SqlCheckConstraint.java 
b/core/src/main/java/org/apache/calcite/sql/ddl/SqlCheckConstraint.java
index a74ed3e90e..8106f2d1e8 100644
--- a/core/src/main/java/org/apache/calcite/sql/ddl/SqlCheckConstraint.java
+++ b/core/src/main/java/org/apache/calcite/sql/ddl/SqlCheckConstraint.java
@@ -19,6 +19,7 @@
 import org.apache.calcite.sql.SqlCall;
 import org.apache.calcite.sql.SqlIdentifier;
 import org.apache.calcite.sql.SqlKind;
+import org.apache.calcite.sql.SqlLiteral;
 import org.apache.calcite.sql.SqlNode;
 import org.apache.calcite.sql.SqlOperator;
 import org.apache.calcite.sql.SqlSpecialOperator;
@@ -30,14 +31,23 @@
 
 import java.util.List;
 
+import static java.util.Objects.requireNonNull;
+
 /**
  * Parse tree for {@code UNIQUE}, {@code PRIMARY KEY} constraints.
  *
  * <p>And {@code FOREIGN KEY}, when we support it.
  */
 public class SqlCheckConstraint extends SqlCall {
-  private static final SqlSpecialOperator OPERATOR =
-      new SqlSpecialOperator("CHECK", SqlKind.CHECK);
+  private static final SqlOperator OPERATOR =
+      new SqlSpecialOperator("CHECK", SqlKind.CHECK) {
+        @Override public SqlCall createCall(@Nullable SqlLiteral 
functionQualifier,
+            SqlParserPos pos, @Nullable SqlNode... operands) {
+          return new SqlCheckConstraint(pos,
+              (SqlIdentifier) operands[0],
+              requireNonNull(operands[1], "expression"));
+        }
+      };
 
   private final @Nullable SqlIdentifier name;
   private final SqlNode expression;
diff --git 
a/core/src/main/java/org/apache/calcite/sql/ddl/SqlColumnDeclaration.java 
b/core/src/main/java/org/apache/calcite/sql/ddl/SqlColumnDeclaration.java
index e37075f631..d57fcb502b 100644
--- a/core/src/main/java/org/apache/calcite/sql/ddl/SqlColumnDeclaration.java
+++ b/core/src/main/java/org/apache/calcite/sql/ddl/SqlColumnDeclaration.java
@@ -21,36 +21,50 @@
 import org.apache.calcite.sql.SqlDataTypeSpec;
 import org.apache.calcite.sql.SqlIdentifier;
 import org.apache.calcite.sql.SqlKind;
+import org.apache.calcite.sql.SqlLiteral;
 import org.apache.calcite.sql.SqlNode;
 import org.apache.calcite.sql.SqlOperator;
 import org.apache.calcite.sql.SqlSpecialOperator;
 import org.apache.calcite.sql.SqlWriter;
 import org.apache.calcite.sql.parser.SqlParserPos;
-
-import com.google.common.collect.ImmutableList;
+import org.apache.calcite.util.ImmutableNullableList;
 
 import org.checkerframework.checker.nullness.qual.Nullable;
 
 import java.util.List;
 
+import static java.util.Objects.requireNonNull;
+
 /**
  * Parse tree for {@code UNIQUE}, {@code PRIMARY KEY} constraints.
  *
  * <p>And {@code FOREIGN KEY}, when we support it.
  */
 public class SqlColumnDeclaration extends SqlCall {
-  private static final SqlSpecialOperator OPERATOR =
-      new SqlSpecialOperator("COLUMN_DECL", SqlKind.COLUMN_DECL);
+  private static final SqlOperator OPERATOR =
+      new SqlSpecialOperator("COLUMN_DECL", SqlKind.COLUMN_DECL) {
+        @Override public SqlCall createCall(@Nullable SqlLiteral 
functionQualifier,
+            SqlParserPos pos, @Nullable SqlNode... operands) {
+          return new SqlColumnDeclaration(pos,
+              (SqlIdentifier) requireNonNull(operands[0], "name"),
+              (SqlDataTypeSpec) requireNonNull(operands[1], "dataType"),
+              operands[2],
+              operands[3] != null
+                  ? ColumnStrategy.valueOf(((SqlIdentifier) 
operands[3]).getSimple())
+                  : null);
+        }
+      };
 
   public final SqlIdentifier name;
   public final SqlDataTypeSpec dataType;
   public final @Nullable SqlNode expression;
-  public final ColumnStrategy strategy;
+  // The Babel parser can supply null for the strategy
+  public final @Nullable ColumnStrategy strategy;
 
   /** Creates a SqlColumnDeclaration; use {@link SqlDdlNodes#column}. */
   SqlColumnDeclaration(SqlParserPos pos, SqlIdentifier name,
       SqlDataTypeSpec dataType, @Nullable SqlNode expression,
-      ColumnStrategy strategy) {
+      @Nullable ColumnStrategy strategy) {
     super(pos);
     this.name = name;
     this.dataType = dataType;
@@ -62,8 +76,10 @@ public class SqlColumnDeclaration extends SqlCall {
     return OPERATOR;
   }
 
+  @SuppressWarnings("nullness")
   @Override public List<SqlNode> getOperandList() {
-    return ImmutableList.of(name, dataType);
+    return ImmutableNullableList.of(name, dataType, expression,
+        strategy != null ? new SqlIdentifier(strategy.name(), 
SqlParserPos.ZERO) : null);
   }
 
   @Override public void unparse(SqlWriter writer, int leftPrec, int rightPrec) 
{
@@ -73,7 +89,7 @@ public class SqlColumnDeclaration extends SqlCall {
       writer.keyword("NOT NULL");
     }
     SqlNode expression = this.expression;
-    if (expression != null) {
+    if (expression != null && strategy != null) {
       switch (strategy) {
       case VIRTUAL:
       case STORED:
diff --git 
a/core/src/main/java/org/apache/calcite/sql/ddl/SqlCreateForeignSchema.java 
b/core/src/main/java/org/apache/calcite/sql/ddl/SqlCreateForeignSchema.java
index 53e106b4d8..e7a4993d8d 100644
--- a/core/src/main/java/org/apache/calcite/sql/ddl/SqlCreateForeignSchema.java
+++ b/core/src/main/java/org/apache/calcite/sql/ddl/SqlCreateForeignSchema.java
@@ -16,9 +16,11 @@
  */
 package org.apache.calcite.sql.ddl;
 
+import org.apache.calcite.sql.SqlCall;
 import org.apache.calcite.sql.SqlCreate;
 import org.apache.calcite.sql.SqlIdentifier;
 import org.apache.calcite.sql.SqlKind;
+import org.apache.calcite.sql.SqlLiteral;
 import org.apache.calcite.sql.SqlNode;
 import org.apache.calcite.sql.SqlNodeList;
 import org.apache.calcite.sql.SqlOperator;
@@ -51,8 +53,18 @@ public class SqlCreateForeignSchema extends SqlCreate {
   private final @Nullable SqlNodeList optionList;
 
   private static final SqlOperator OPERATOR =
-      new SqlSpecialOperator("CREATE FOREIGN SCHEMA",
-          SqlKind.CREATE_FOREIGN_SCHEMA);
+      new SqlSpecialOperator("CREATE FOREIGN SCHEMA", 
SqlKind.CREATE_FOREIGN_SCHEMA) {
+        @Override public SqlCall createCall(@Nullable SqlLiteral 
functionQualifier,
+            SqlParserPos pos, @Nullable SqlNode... operands) {
+          return new SqlCreateForeignSchema(pos,
+              ((SqlLiteral) requireNonNull(operands[0], 
"replace")).booleanValue(),
+              ((SqlLiteral) requireNonNull(operands[1], 
"ifNotExists")).booleanValue(),
+              (SqlIdentifier) requireNonNull(operands[2], "name"),
+              operands[3],
+              operands[4],
+              (SqlNodeList) operands[5]);
+        }
+      };
 
   /** Creates a SqlCreateForeignSchema. */
   SqlCreateForeignSchema(SqlParserPos pos, boolean replace, boolean 
ifNotExists,
@@ -69,7 +81,10 @@ public class SqlCreateForeignSchema extends SqlCreate {
 
   @SuppressWarnings("nullness")
   @Override public List<SqlNode> getOperandList() {
-    return ImmutableNullableList.of(name, type, library, optionList);
+    return ImmutableNullableList.of(
+        SqlLiteral.createBoolean(getReplace(), SqlParserPos.ZERO),
+        SqlLiteral.createBoolean(ifNotExists, SqlParserPos.ZERO),
+        name, type, library, optionList);
   }
 
   @Override public void unparse(SqlWriter writer, int leftPrec, int rightPrec) 
{
diff --git 
a/core/src/main/java/org/apache/calcite/sql/ddl/SqlCreateFunction.java 
b/core/src/main/java/org/apache/calcite/sql/ddl/SqlCreateFunction.java
index ae0abc2898..fb859b2013 100644
--- a/core/src/main/java/org/apache/calcite/sql/ddl/SqlCreateFunction.java
+++ b/core/src/main/java/org/apache/calcite/sql/ddl/SqlCreateFunction.java
@@ -16,6 +16,7 @@
  */
 package org.apache.calcite.sql.ddl;
 
+import org.apache.calcite.sql.SqlCall;
 import org.apache.calcite.sql.SqlCreate;
 import org.apache.calcite.sql.SqlIdentifier;
 import org.apache.calcite.sql.SqlKind;
@@ -29,7 +30,10 @@
 import org.apache.calcite.util.Pair;
 import org.apache.calcite.util.Util;
 
-import java.util.Arrays;
+import com.google.common.collect.ImmutableList;
+
+import org.checkerframework.checker.nullness.qual.Nullable;
+
 import java.util.List;
 
 import static com.google.common.base.Preconditions.checkArgument;
@@ -44,8 +48,18 @@ public class SqlCreateFunction extends SqlCreate {
   private final SqlNode className;
   private final SqlNodeList usingList;
 
-  private static final SqlSpecialOperator OPERATOR =
-      new SqlSpecialOperator("CREATE FUNCTION", SqlKind.CREATE_FUNCTION);
+  private static final SqlOperator OPERATOR =
+      new SqlSpecialOperator("CREATE FUNCTION", SqlKind.CREATE_FUNCTION) {
+        @Override public SqlCall createCall(@Nullable SqlLiteral 
functionQualifier,
+            SqlParserPos pos, @Nullable SqlNode... operands) {
+          return new SqlCreateFunction(pos,
+              ((SqlLiteral) requireNonNull(operands[0], 
"replace")).booleanValue(),
+              ((SqlLiteral) requireNonNull(operands[1], 
"ifNotExists")).booleanValue(),
+              (SqlIdentifier) requireNonNull(operands[2], "name"),
+              requireNonNull(operands[3], "className"),
+              (SqlNodeList) requireNonNull(operands[4], "usingList"));
+        }
+      };
 
   /** Creates a SqlCreateFunction. */
   public SqlCreateFunction(SqlParserPos pos, boolean replace,
@@ -91,6 +105,9 @@ private List<Pair<SqlLiteral, SqlLiteral>> pairs() {
   }
 
   @Override public List<SqlNode> getOperandList() {
-    return Arrays.asList(name, className, usingList);
+    return ImmutableList.of(
+        SqlLiteral.createBoolean(getReplace(), SqlParserPos.ZERO),
+        SqlLiteral.createBoolean(ifNotExists, SqlParserPos.ZERO),
+        name, className, usingList);
   }
 }
diff --git 
a/core/src/main/java/org/apache/calcite/sql/ddl/SqlCreateMaterializedView.java 
b/core/src/main/java/org/apache/calcite/sql/ddl/SqlCreateMaterializedView.java
index a5ccd904db..3894cc2769 100644
--- 
a/core/src/main/java/org/apache/calcite/sql/ddl/SqlCreateMaterializedView.java
+++ 
b/core/src/main/java/org/apache/calcite/sql/ddl/SqlCreateMaterializedView.java
@@ -16,9 +16,11 @@
  */
 package org.apache.calcite.sql.ddl;
 
+import org.apache.calcite.sql.SqlCall;
 import org.apache.calcite.sql.SqlCreate;
 import org.apache.calcite.sql.SqlIdentifier;
 import org.apache.calcite.sql.SqlKind;
+import org.apache.calcite.sql.SqlLiteral;
 import org.apache.calcite.sql.SqlNode;
 import org.apache.calcite.sql.SqlNodeList;
 import org.apache.calcite.sql.SqlOperator;
@@ -42,8 +44,17 @@ public class SqlCreateMaterializedView extends SqlCreate {
   public final SqlNode query;
 
   private static final SqlOperator OPERATOR =
-      new SqlSpecialOperator("CREATE MATERIALIZED VIEW",
-          SqlKind.CREATE_MATERIALIZED_VIEW);
+      new SqlSpecialOperator("CREATE MATERIALIZED VIEW", 
SqlKind.CREATE_MATERIALIZED_VIEW) {
+        @Override public SqlCall createCall(@Nullable SqlLiteral 
functionQualifier,
+            SqlParserPos pos, @Nullable SqlNode... operands) {
+          return new SqlCreateMaterializedView(pos,
+              ((SqlLiteral) requireNonNull(operands[0], 
"replace")).booleanValue(),
+              ((SqlLiteral) requireNonNull(operands[1], 
"ifNotExists")).booleanValue(),
+              (SqlIdentifier) requireNonNull(operands[2], "name"),
+              (SqlNodeList) operands[3],
+              requireNonNull(operands[4], "query"));
+        }
+      };
 
   /** Creates a SqlCreateView. */
   SqlCreateMaterializedView(SqlParserPos pos, boolean replace,
@@ -57,7 +68,10 @@ public class SqlCreateMaterializedView extends SqlCreate {
 
   @SuppressWarnings("nullness")
   @Override public List<SqlNode> getOperandList() {
-    return ImmutableNullableList.of(name, columnList, query);
+    return ImmutableNullableList.of(
+        SqlLiteral.createBoolean(getReplace(), SqlParserPos.ZERO),
+        SqlLiteral.createBoolean(ifNotExists, SqlParserPos.ZERO),
+        name, columnList, query);
   }
 
   @Override public void unparse(SqlWriter writer, int leftPrec, int rightPrec) 
{
diff --git a/core/src/main/java/org/apache/calcite/sql/ddl/SqlCreateSchema.java 
b/core/src/main/java/org/apache/calcite/sql/ddl/SqlCreateSchema.java
index ee405b0c2d..d661daadc2 100644
--- a/core/src/main/java/org/apache/calcite/sql/ddl/SqlCreateSchema.java
+++ b/core/src/main/java/org/apache/calcite/sql/ddl/SqlCreateSchema.java
@@ -16,9 +16,11 @@
  */
 package org.apache.calcite.sql.ddl;
 
+import org.apache.calcite.sql.SqlCall;
 import org.apache.calcite.sql.SqlCreate;
 import org.apache.calcite.sql.SqlIdentifier;
 import org.apache.calcite.sql.SqlKind;
+import org.apache.calcite.sql.SqlLiteral;
 import org.apache.calcite.sql.SqlNode;
 import org.apache.calcite.sql.SqlOperator;
 import org.apache.calcite.sql.SqlSpecialOperator;
@@ -26,6 +28,8 @@
 import org.apache.calcite.sql.parser.SqlParserPos;
 import org.apache.calcite.util.ImmutableNullableList;
 
+import org.checkerframework.checker.nullness.qual.Nullable;
+
 import java.util.List;
 
 import static java.util.Objects.requireNonNull;
@@ -37,7 +41,15 @@ public class SqlCreateSchema extends SqlCreate {
   public final SqlIdentifier name;
 
   private static final SqlOperator OPERATOR =
-      new SqlSpecialOperator("CREATE SCHEMA", SqlKind.CREATE_SCHEMA);
+      new SqlSpecialOperator("CREATE SCHEMA", SqlKind.CREATE_SCHEMA) {
+        @Override public SqlCall createCall(@Nullable SqlLiteral 
functionQualifier,
+            SqlParserPos pos, @Nullable SqlNode... operands) {
+          return new SqlCreateSchema(pos,
+              ((SqlLiteral) requireNonNull(operands[0], 
"replace")).booleanValue(),
+              ((SqlLiteral) requireNonNull(operands[1], 
"ifNotExists")).booleanValue(),
+              (SqlIdentifier) requireNonNull(operands[2], "name"));
+        }
+      };
 
   /** Creates a SqlCreateSchema. */
   SqlCreateSchema(SqlParserPos pos, boolean replace, boolean ifNotExists,
@@ -47,7 +59,10 @@ public class SqlCreateSchema extends SqlCreate {
   }
 
   @Override public List<SqlNode> getOperandList() {
-    return ImmutableNullableList.of(name);
+    return ImmutableNullableList.of(
+        SqlLiteral.createBoolean(getReplace(), SqlParserPos.ZERO),
+        SqlLiteral.createBoolean(ifNotExists, SqlParserPos.ZERO),
+        name);
   }
 
   @Override public void unparse(SqlWriter writer, int leftPrec, int rightPrec) 
{
diff --git a/core/src/main/java/org/apache/calcite/sql/ddl/SqlCreateTable.java 
b/core/src/main/java/org/apache/calcite/sql/ddl/SqlCreateTable.java
index 7e7dd144cb..1bf283bf0c 100644
--- a/core/src/main/java/org/apache/calcite/sql/ddl/SqlCreateTable.java
+++ b/core/src/main/java/org/apache/calcite/sql/ddl/SqlCreateTable.java
@@ -16,9 +16,11 @@
  */
 package org.apache.calcite.sql.ddl;
 
+import org.apache.calcite.sql.SqlCall;
 import org.apache.calcite.sql.SqlCreate;
 import org.apache.calcite.sql.SqlIdentifier;
 import org.apache.calcite.sql.SqlKind;
+import org.apache.calcite.sql.SqlLiteral;
 import org.apache.calcite.sql.SqlNode;
 import org.apache.calcite.sql.SqlNodeList;
 import org.apache.calcite.sql.SqlOperator;
@@ -42,7 +44,17 @@ public class SqlCreateTable extends SqlCreate {
   public final @Nullable SqlNode query;
 
   private static final SqlOperator OPERATOR =
-      new SqlSpecialOperator("CREATE TABLE", SqlKind.CREATE_TABLE);
+      new SqlSpecialOperator("CREATE TABLE", SqlKind.CREATE_TABLE) {
+        @Override public SqlCall createCall(@Nullable SqlLiteral 
functionQualifier,
+            SqlParserPos pos, @Nullable SqlNode... operands) {
+          return new SqlCreateTable(pos,
+              ((SqlLiteral) requireNonNull(operands[0], 
"replace")).booleanValue(),
+              ((SqlLiteral) requireNonNull(operands[1], 
"ifNotExists")).booleanValue(),
+              (SqlIdentifier) requireNonNull(operands[2], "name"),
+              (SqlNodeList) requireNonNull(operands[3], "columnList"),
+              operands[4]);
+        }
+      };
 
   /** Creates a SqlCreateTable. */
   protected SqlCreateTable(SqlParserPos pos, boolean replace, boolean 
ifNotExists,
@@ -55,7 +67,10 @@ protected SqlCreateTable(SqlParserPos pos, boolean replace, 
boolean ifNotExists,
 
   @SuppressWarnings("nullness")
   @Override public List<SqlNode> getOperandList() {
-    return ImmutableNullableList.of(name, columnList, query);
+    return ImmutableNullableList.of(
+        SqlLiteral.createBoolean(getReplace(), SqlParserPos.ZERO),
+        SqlLiteral.createBoolean(ifNotExists, SqlParserPos.ZERO),
+        name, columnList, query);
   }
 
   @Override public void unparse(SqlWriter writer, int leftPrec, int rightPrec) 
{
diff --git 
a/core/src/main/java/org/apache/calcite/sql/ddl/SqlCreateTableLike.java 
b/core/src/main/java/org/apache/calcite/sql/ddl/SqlCreateTableLike.java
index 957f87531d..225ae2d8d8 100644
--- a/core/src/main/java/org/apache/calcite/sql/ddl/SqlCreateTableLike.java
+++ b/core/src/main/java/org/apache/calcite/sql/ddl/SqlCreateTableLike.java
@@ -16,6 +16,7 @@
  */
 package org.apache.calcite.sql.ddl;
 
+import org.apache.calcite.sql.SqlCall;
 import org.apache.calcite.sql.SqlCreate;
 import org.apache.calcite.sql.SqlIdentifier;
 import org.apache.calcite.sql.SqlKind;
@@ -29,6 +30,8 @@
 import org.apache.calcite.sql.parser.SqlParserPos;
 import org.apache.calcite.util.ImmutableNullableList;
 
+import org.checkerframework.checker.nullness.qual.Nullable;
+
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
@@ -36,12 +39,25 @@
 
 import static com.google.common.base.Preconditions.checkArgument;
 
+import static java.util.Objects.requireNonNull;
+
 /**
  * Parse tree for {@code CREATE TABLE LIKE} statement.
  */
 public class SqlCreateTableLike extends SqlCreate {
   private static final SqlOperator OPERATOR =
-      new SqlSpecialOperator("CREATE TABLE LIKE", SqlKind.CREATE_TABLE_LIKE);
+      new SqlSpecialOperator("CREATE TABLE LIKE", SqlKind.CREATE_TABLE_LIKE) {
+        @Override public SqlCall createCall(@Nullable SqlLiteral 
functionQualifier,
+            SqlParserPos pos, @Nullable SqlNode... operands) {
+          return new SqlCreateTableLike(pos,
+              ((SqlLiteral) requireNonNull(operands[0], 
"replace")).booleanValue(),
+              ((SqlLiteral) requireNonNull(operands[1], 
"ifNotExists")).booleanValue(),
+              (SqlIdentifier) requireNonNull(operands[2], "name"),
+              (SqlIdentifier) requireNonNull(operands[3], "sourceTable"),
+              (SqlNodeList) requireNonNull(operands[4], "includingOptions"),
+              (SqlNodeList) requireNonNull(operands[5], "excludingOptions"));
+        }
+      };
 
   /**
    * The LikeOption specify which additional properties of the original table 
to copy.
@@ -83,7 +99,10 @@ public SqlCreateTableLike(SqlParserPos pos, boolean replace, 
boolean ifNotExists
   }
 
   @Override public List<SqlNode> getOperandList() {
-    return ImmutableNullableList.of(name, sourceTable, includingOptions,
+    return ImmutableNullableList.of(
+        SqlLiteral.createBoolean(getReplace(), SqlParserPos.ZERO),
+        SqlLiteral.createBoolean(ifNotExists, SqlParserPos.ZERO),
+        name, sourceTable, includingOptions,
         excludingOptions);
   }
 
diff --git a/core/src/main/java/org/apache/calcite/sql/ddl/SqlCreateType.java 
b/core/src/main/java/org/apache/calcite/sql/ddl/SqlCreateType.java
index 67188f736b..7e4dc1f632 100644
--- a/core/src/main/java/org/apache/calcite/sql/ddl/SqlCreateType.java
+++ b/core/src/main/java/org/apache/calcite/sql/ddl/SqlCreateType.java
@@ -16,10 +16,12 @@
  */
 package org.apache.calcite.sql.ddl;
 
+import org.apache.calcite.sql.SqlCall;
 import org.apache.calcite.sql.SqlCreate;
 import org.apache.calcite.sql.SqlDataTypeSpec;
 import org.apache.calcite.sql.SqlIdentifier;
 import org.apache.calcite.sql.SqlKind;
+import org.apache.calcite.sql.SqlLiteral;
 import org.apache.calcite.sql.SqlNode;
 import org.apache.calcite.sql.SqlNodeList;
 import org.apache.calcite.sql.SqlOperator;
@@ -43,7 +45,16 @@ public class SqlCreateType extends SqlCreate {
   public final @Nullable SqlDataTypeSpec dataType;
 
   private static final SqlOperator OPERATOR =
-      new SqlSpecialOperator("CREATE TYPE", SqlKind.CREATE_TYPE);
+      new SqlSpecialOperator("CREATE TYPE", SqlKind.CREATE_TYPE) {
+        @Override public SqlCall createCall(@Nullable SqlLiteral 
functionQualifier,
+            SqlParserPos pos, @Nullable SqlNode... operands) {
+          return new SqlCreateType(pos,
+              ((SqlLiteral) requireNonNull(operands[0], 
"replace")).booleanValue(),
+              (SqlIdentifier) requireNonNull(operands[1], "name"),
+              (SqlNodeList) operands[2],
+              (SqlDataTypeSpec) operands[3]);
+        }
+      };
 
   /** Creates a SqlCreateType. */
   SqlCreateType(SqlParserPos pos, boolean replace, SqlIdentifier name,
@@ -56,7 +67,9 @@ public class SqlCreateType extends SqlCreate {
 
   @SuppressWarnings("nullness")
   @Override public List<SqlNode> getOperandList() {
-    return ImmutableNullableList.of(name, attributeDefs);
+    return ImmutableNullableList.of(
+        SqlLiteral.createBoolean(getReplace(), SqlParserPos.ZERO),
+        name, attributeDefs, dataType);
   }
 
   @Override public void unparse(SqlWriter writer, int leftPrec, int rightPrec) 
{
diff --git a/core/src/main/java/org/apache/calcite/sql/ddl/SqlCreateView.java 
b/core/src/main/java/org/apache/calcite/sql/ddl/SqlCreateView.java
index 662e864966..38297f83e6 100644
--- a/core/src/main/java/org/apache/calcite/sql/ddl/SqlCreateView.java
+++ b/core/src/main/java/org/apache/calcite/sql/ddl/SqlCreateView.java
@@ -16,9 +16,11 @@
  */
 package org.apache.calcite.sql.ddl;
 
+import org.apache.calcite.sql.SqlCall;
 import org.apache.calcite.sql.SqlCreate;
 import org.apache.calcite.sql.SqlIdentifier;
 import org.apache.calcite.sql.SqlKind;
+import org.apache.calcite.sql.SqlLiteral;
 import org.apache.calcite.sql.SqlNode;
 import org.apache.calcite.sql.SqlNodeList;
 import org.apache.calcite.sql.SqlOperator;
@@ -42,7 +44,16 @@ public class SqlCreateView extends SqlCreate {
   public final SqlNode query;
 
   private static final SqlOperator OPERATOR =
-      new SqlSpecialOperator("CREATE VIEW", SqlKind.CREATE_VIEW);
+      new SqlSpecialOperator("CREATE VIEW", SqlKind.CREATE_VIEW) {
+        @Override public SqlCall createCall(@Nullable SqlLiteral 
functionQualifier,
+            SqlParserPos pos, @Nullable SqlNode... operands) {
+          return new SqlCreateView(pos,
+              ((SqlLiteral) requireNonNull(operands[0], 
"replace")).booleanValue(),
+              (SqlIdentifier) requireNonNull(operands[1], "name"),
+              (SqlNodeList) operands[3],
+              requireNonNull(operands[4], "query"));
+        }
+      };
 
   /** Creates a SqlCreateView. */
   SqlCreateView(SqlParserPos pos, boolean replace, SqlIdentifier name,
@@ -55,7 +66,9 @@ public class SqlCreateView extends SqlCreate {
 
   @SuppressWarnings("nullness")
   @Override public List<SqlNode> getOperandList() {
-    return ImmutableNullableList.of(name, columnList, query);
+    return ImmutableNullableList.of(
+        SqlLiteral.createBoolean(getReplace(), SqlParserPos.ZERO),
+        name, columnList, query);
   }
 
   @Override public void unparse(SqlWriter writer, int leftPrec, int rightPrec) 
{
diff --git a/core/src/main/java/org/apache/calcite/sql/ddl/SqlDropFunction.java 
b/core/src/main/java/org/apache/calcite/sql/ddl/SqlDropFunction.java
index 9b24b030b9..a8601ba9d0 100644
--- a/core/src/main/java/org/apache/calcite/sql/ddl/SqlDropFunction.java
+++ b/core/src/main/java/org/apache/calcite/sql/ddl/SqlDropFunction.java
@@ -16,18 +16,32 @@
  */
 package org.apache.calcite.sql.ddl;
 
+import org.apache.calcite.sql.SqlCall;
 import org.apache.calcite.sql.SqlIdentifier;
 import org.apache.calcite.sql.SqlKind;
+import org.apache.calcite.sql.SqlLiteral;
+import org.apache.calcite.sql.SqlNode;
 import org.apache.calcite.sql.SqlOperator;
 import org.apache.calcite.sql.SqlSpecialOperator;
 import org.apache.calcite.sql.parser.SqlParserPos;
 
+import org.checkerframework.checker.nullness.qual.Nullable;
+
+import static java.util.Objects.requireNonNull;
+
 /**
  * Parse tree for {@code DROP FUNCTION} statement.
  */
 public class SqlDropFunction extends SqlDropObject {
   private static final SqlOperator OPERATOR =
-      new SqlSpecialOperator("DROP FUNCTION", SqlKind.DROP_FUNCTION);
+      new SqlSpecialOperator("DROP FUNCTION", SqlKind.DROP_FUNCTION) {
+        @Override public SqlCall createCall(@Nullable SqlLiteral 
functionQualifier,
+            SqlParserPos pos, @Nullable SqlNode... operands) {
+          return new SqlDropFunction(pos,
+              ((SqlLiteral) requireNonNull(operands[0], 
"ifExists")).booleanValue(),
+              (SqlIdentifier) requireNonNull(operands[1], "name"));
+        }
+      };
 
   /** Creates a SqlDropFunction. */
   public SqlDropFunction(SqlParserPos pos, boolean ifExists,
diff --git 
a/core/src/main/java/org/apache/calcite/sql/ddl/SqlDropMaterializedView.java 
b/core/src/main/java/org/apache/calcite/sql/ddl/SqlDropMaterializedView.java
index 374167478a..09807cbc96 100644
--- a/core/src/main/java/org/apache/calcite/sql/ddl/SqlDropMaterializedView.java
+++ b/core/src/main/java/org/apache/calcite/sql/ddl/SqlDropMaterializedView.java
@@ -16,19 +16,32 @@
  */
 package org.apache.calcite.sql.ddl;
 
+import org.apache.calcite.sql.SqlCall;
 import org.apache.calcite.sql.SqlIdentifier;
 import org.apache.calcite.sql.SqlKind;
+import org.apache.calcite.sql.SqlLiteral;
+import org.apache.calcite.sql.SqlNode;
 import org.apache.calcite.sql.SqlOperator;
 import org.apache.calcite.sql.SqlSpecialOperator;
 import org.apache.calcite.sql.parser.SqlParserPos;
 
+import org.checkerframework.checker.nullness.qual.Nullable;
+
+import static java.util.Objects.requireNonNull;
+
 /**
  * Parse tree for {@code DROP MATERIALIZED VIEW} statement.
  */
 public class SqlDropMaterializedView extends SqlDropObject {
   private static final SqlOperator OPERATOR =
-      new SqlSpecialOperator("DROP MATERIALIZED VIEW",
-          SqlKind.DROP_MATERIALIZED_VIEW);
+      new SqlSpecialOperator("DROP MATERIALIZED VIEW", 
SqlKind.DROP_MATERIALIZED_VIEW) {
+        @Override public SqlCall createCall(@Nullable SqlLiteral 
functionQualifier,
+            SqlParserPos pos, @Nullable SqlNode... operands) {
+          return new SqlDropMaterializedView(pos,
+              ((SqlLiteral) requireNonNull(operands[0], 
"ifExists")).booleanValue(),
+              (SqlIdentifier) requireNonNull(operands[1], "name"));
+        }
+      };
 
   /** Creates a SqlDropMaterializedView. */
   SqlDropMaterializedView(SqlParserPos pos, boolean ifExists,
diff --git a/core/src/main/java/org/apache/calcite/sql/ddl/SqlDropObject.java 
b/core/src/main/java/org/apache/calcite/sql/ddl/SqlDropObject.java
index 278bde6ac8..541fe7c4aa 100644
--- a/core/src/main/java/org/apache/calcite/sql/ddl/SqlDropObject.java
+++ b/core/src/main/java/org/apache/calcite/sql/ddl/SqlDropObject.java
@@ -19,6 +19,7 @@
 import org.apache.calcite.jdbc.CalcitePrepare;
 import org.apache.calcite.sql.SqlDrop;
 import org.apache.calcite.sql.SqlIdentifier;
+import org.apache.calcite.sql.SqlLiteral;
 import org.apache.calcite.sql.SqlNode;
 import org.apache.calcite.sql.SqlOperator;
 import org.apache.calcite.sql.SqlWriter;
@@ -43,7 +44,9 @@ public abstract class SqlDropObject extends SqlDrop {
   }
 
   @Override public List<SqlNode> getOperandList() {
-    return ImmutableList.of(name);
+    return ImmutableList.of(
+        SqlLiteral.createBoolean(ifExists, SqlParserPos.ZERO),
+        name);
   }
 
   @Override public void unparse(SqlWriter writer, int leftPrec, int rightPrec) 
{
diff --git a/core/src/main/java/org/apache/calcite/sql/ddl/SqlDropSchema.java 
b/core/src/main/java/org/apache/calcite/sql/ddl/SqlDropSchema.java
index b06022977b..95689c29ef 100644
--- a/core/src/main/java/org/apache/calcite/sql/ddl/SqlDropSchema.java
+++ b/core/src/main/java/org/apache/calcite/sql/ddl/SqlDropSchema.java
@@ -16,6 +16,7 @@
  */
 package org.apache.calcite.sql.ddl;
 
+import org.apache.calcite.sql.SqlCall;
 import org.apache.calcite.sql.SqlDrop;
 import org.apache.calcite.sql.SqlIdentifier;
 import org.apache.calcite.sql.SqlKind;
@@ -28,8 +29,12 @@
 
 import com.google.common.collect.ImmutableList;
 
+import org.checkerframework.checker.nullness.qual.Nullable;
+
 import java.util.List;
 
+import static java.util.Objects.requireNonNull;
+
 /**
  * Parse tree for {@code DROP SCHEMA} statement.
  */
@@ -38,7 +43,15 @@ public class SqlDropSchema extends SqlDrop {
   public final SqlIdentifier name;
 
   private static final SqlOperator OPERATOR =
-      new SqlSpecialOperator("DROP SCHEMA", SqlKind.DROP_SCHEMA);
+      new SqlSpecialOperator("DROP SCHEMA", SqlKind.DROP_SCHEMA) {
+        @Override public SqlCall createCall(@Nullable SqlLiteral 
functionQualifier,
+            SqlParserPos pos, @Nullable SqlNode... operands) {
+          return new SqlDropSchema(pos,
+              ((SqlLiteral) requireNonNull(operands[0], 
"foreign")).booleanValue(),
+              ((SqlLiteral) requireNonNull(operands[1], 
"ifExists")).booleanValue(),
+              (SqlIdentifier) requireNonNull(operands[2], "name"));
+        }
+      };
 
   /** Creates a SqlDropSchema. */
   SqlDropSchema(SqlParserPos pos, boolean foreign, boolean ifExists,
@@ -50,7 +63,9 @@ public class SqlDropSchema extends SqlDrop {
 
   @Override public List<SqlNode> getOperandList() {
     return ImmutableList.of(
-        SqlLiteral.createBoolean(foreign, SqlParserPos.ZERO), name);
+        SqlLiteral.createBoolean(foreign, SqlParserPos.ZERO),
+        SqlLiteral.createBoolean(ifExists, SqlParserPos.ZERO),
+        name);
   }
 
   @Override public void unparse(SqlWriter writer, int leftPrec, int rightPrec) 
{
diff --git a/core/src/main/java/org/apache/calcite/sql/ddl/SqlDropTable.java 
b/core/src/main/java/org/apache/calcite/sql/ddl/SqlDropTable.java
index 4eab052ff0..314686f1e3 100644
--- a/core/src/main/java/org/apache/calcite/sql/ddl/SqlDropTable.java
+++ b/core/src/main/java/org/apache/calcite/sql/ddl/SqlDropTable.java
@@ -16,18 +16,32 @@
  */
 package org.apache.calcite.sql.ddl;
 
+import org.apache.calcite.sql.SqlCall;
 import org.apache.calcite.sql.SqlIdentifier;
 import org.apache.calcite.sql.SqlKind;
+import org.apache.calcite.sql.SqlLiteral;
+import org.apache.calcite.sql.SqlNode;
 import org.apache.calcite.sql.SqlOperator;
 import org.apache.calcite.sql.SqlSpecialOperator;
 import org.apache.calcite.sql.parser.SqlParserPos;
 
+import org.checkerframework.checker.nullness.qual.Nullable;
+
+import static java.util.Objects.requireNonNull;
+
 /**
  * Parse tree for {@code DROP TABLE} statement.
  */
 public class SqlDropTable extends SqlDropObject {
   private static final SqlOperator OPERATOR =
-      new SqlSpecialOperator("DROP TABLE", SqlKind.DROP_TABLE);
+      new SqlSpecialOperator("DROP TABLE", SqlKind.DROP_TABLE) {
+        @Override public SqlCall createCall(@Nullable SqlLiteral 
functionQualifier,
+            SqlParserPos pos, @Nullable SqlNode... operands) {
+          return new SqlDropTable(pos,
+              ((SqlLiteral) requireNonNull(operands[0], 
"ifExists")).booleanValue(),
+              (SqlIdentifier) requireNonNull(operands[1], "name"));
+        }
+      };
 
   /** Creates a SqlDropTable. */
   SqlDropTable(SqlParserPos pos, boolean ifExists, SqlIdentifier name) {
diff --git a/core/src/main/java/org/apache/calcite/sql/ddl/SqlDropType.java 
b/core/src/main/java/org/apache/calcite/sql/ddl/SqlDropType.java
index 17e29c2879..06ecf74270 100644
--- a/core/src/main/java/org/apache/calcite/sql/ddl/SqlDropType.java
+++ b/core/src/main/java/org/apache/calcite/sql/ddl/SqlDropType.java
@@ -16,18 +16,32 @@
  */
 package org.apache.calcite.sql.ddl;
 
+import org.apache.calcite.sql.SqlCall;
 import org.apache.calcite.sql.SqlIdentifier;
 import org.apache.calcite.sql.SqlKind;
+import org.apache.calcite.sql.SqlLiteral;
+import org.apache.calcite.sql.SqlNode;
 import org.apache.calcite.sql.SqlOperator;
 import org.apache.calcite.sql.SqlSpecialOperator;
 import org.apache.calcite.sql.parser.SqlParserPos;
 
+import org.checkerframework.checker.nullness.qual.Nullable;
+
+import static java.util.Objects.requireNonNull;
+
 /**
  * Parse tree for {@code DROP TYPE} statement.
  */
 public class SqlDropType extends SqlDropObject {
   private static final SqlOperator OPERATOR =
-      new SqlSpecialOperator("DROP TYPE", SqlKind.DROP_TYPE);
+      new SqlSpecialOperator("DROP TYPE", SqlKind.DROP_TYPE) {
+        @Override public SqlCall createCall(@Nullable SqlLiteral 
functionQualifier,
+            SqlParserPos pos, @Nullable SqlNode... operands) {
+          return new SqlDropType(pos,
+              ((SqlLiteral) requireNonNull(operands[0], 
"ifExists")).booleanValue(),
+              (SqlIdentifier) requireNonNull(operands[1], "name"));
+        }
+      };
 
   SqlDropType(SqlParserPos pos, boolean ifExists, SqlIdentifier name) {
     super(OPERATOR, pos, ifExists, name);
diff --git a/core/src/main/java/org/apache/calcite/sql/ddl/SqlDropView.java 
b/core/src/main/java/org/apache/calcite/sql/ddl/SqlDropView.java
index b8de41d5ad..ff2d669a68 100644
--- a/core/src/main/java/org/apache/calcite/sql/ddl/SqlDropView.java
+++ b/core/src/main/java/org/apache/calcite/sql/ddl/SqlDropView.java
@@ -16,18 +16,32 @@
  */
 package org.apache.calcite.sql.ddl;
 
+import org.apache.calcite.sql.SqlCall;
 import org.apache.calcite.sql.SqlIdentifier;
 import org.apache.calcite.sql.SqlKind;
+import org.apache.calcite.sql.SqlLiteral;
+import org.apache.calcite.sql.SqlNode;
 import org.apache.calcite.sql.SqlOperator;
 import org.apache.calcite.sql.SqlSpecialOperator;
 import org.apache.calcite.sql.parser.SqlParserPos;
 
+import org.checkerframework.checker.nullness.qual.Nullable;
+
+import static java.util.Objects.requireNonNull;
+
 /**
  * Parse tree for {@code DROP VIEW} statement.
  */
 public class SqlDropView extends SqlDropObject {
   private static final SqlOperator OPERATOR =
-      new SqlSpecialOperator("DROP VIEW", SqlKind.DROP_VIEW);
+      new SqlSpecialOperator("DROP VIEW", SqlKind.DROP_VIEW) {
+        @Override public SqlCall createCall(@Nullable SqlLiteral 
functionQualifier,
+            SqlParserPos pos, @Nullable SqlNode... operands) {
+          return new SqlDropView(pos,
+              ((SqlLiteral) requireNonNull(operands[0], 
"ifExists")).booleanValue(),
+              (SqlIdentifier) requireNonNull(operands[1], "name"));
+        }
+      };
 
   /** Creates a SqlDropView. */
   SqlDropView(SqlParserPos pos, boolean ifExists, SqlIdentifier name) {
diff --git 
a/core/src/main/java/org/apache/calcite/sql/ddl/SqlKeyConstraint.java 
b/core/src/main/java/org/apache/calcite/sql/ddl/SqlKeyConstraint.java
index bc526e1d15..37ad08be22 100644
--- a/core/src/main/java/org/apache/calcite/sql/ddl/SqlKeyConstraint.java
+++ b/core/src/main/java/org/apache/calcite/sql/ddl/SqlKeyConstraint.java
@@ -19,6 +19,7 @@
 import org.apache.calcite.sql.SqlCall;
 import org.apache.calcite.sql.SqlIdentifier;
 import org.apache.calcite.sql.SqlKind;
+import org.apache.calcite.sql.SqlLiteral;
 import org.apache.calcite.sql.SqlNode;
 import org.apache.calcite.sql.SqlNodeList;
 import org.apache.calcite.sql.SqlOperator;
@@ -31,17 +32,33 @@
 
 import java.util.List;
 
+import static java.util.Objects.requireNonNull;
+
 /**
  * Parse tree for {@code UNIQUE}, {@code PRIMARY KEY} constraints.
  *
  * <p>And {@code FOREIGN KEY}, when we support it.
  */
 public class SqlKeyConstraint extends SqlCall {
-  private static final SqlSpecialOperator UNIQUE =
-      new SqlSpecialOperator("UNIQUE", SqlKind.UNIQUE);
+  private static final SqlOperator UNIQUE =
+      new SqlSpecialOperator("UNIQUE", SqlKind.UNIQUE) {
+        @Override public SqlCall createCall(@Nullable SqlLiteral 
functionQualifier,
+            SqlParserPos pos, @Nullable SqlNode... operands) {
+          return unique(pos,
+              (SqlIdentifier) requireNonNull(operands[0], "name"),
+              (SqlNodeList) requireNonNull(operands[1], "columnList"));
+        }
+      };
 
-  protected static final SqlSpecialOperator PRIMARY =
-      new SqlSpecialOperator("PRIMARY KEY", SqlKind.PRIMARY_KEY);
+  protected static final SqlOperator PRIMARY =
+      new SqlSpecialOperator("PRIMARY KEY", SqlKind.PRIMARY_KEY) {
+        @Override public SqlCall createCall(@Nullable SqlLiteral 
functionQualifier,
+            SqlParserPos pos, @Nullable SqlNode... operands) {
+          return primary(pos,
+              (SqlIdentifier) requireNonNull(operands[0], "name"),
+              (SqlNodeList) requireNonNull(operands[1], "columnList"));
+        }
+      };
 
   private final @Nullable SqlIdentifier name;
   private final SqlNodeList columnList;
diff --git 
a/core/src/main/java/org/apache/calcite/sql/ddl/SqlTruncateTable.java 
b/core/src/main/java/org/apache/calcite/sql/ddl/SqlTruncateTable.java
index 2d82107efc..1c633c819f 100644
--- a/core/src/main/java/org/apache/calcite/sql/ddl/SqlTruncateTable.java
+++ b/core/src/main/java/org/apache/calcite/sql/ddl/SqlTruncateTable.java
@@ -16,8 +16,10 @@
  */
 package org.apache.calcite.sql.ddl;
 
+import org.apache.calcite.sql.SqlCall;
 import org.apache.calcite.sql.SqlIdentifier;
 import org.apache.calcite.sql.SqlKind;
+import org.apache.calcite.sql.SqlLiteral;
 import org.apache.calcite.sql.SqlNode;
 import org.apache.calcite.sql.SqlOperator;
 import org.apache.calcite.sql.SqlSpecialOperator;
@@ -27,40 +29,51 @@
 
 import com.google.common.collect.ImmutableList;
 
+import org.checkerframework.checker.nullness.qual.Nullable;
+
 import java.util.List;
 
+import static java.util.Objects.requireNonNull;
+
 /**
  * Parse tree for {@code TRUNCATE TABLE} statement.
  */
 public class SqlTruncateTable extends SqlTruncate {
 
   private static final SqlOperator OPERATOR =
-      new SqlSpecialOperator("TRUNCATE TABLE", SqlKind.TRUNCATE_TABLE);
+      new SqlSpecialOperator("TRUNCATE TABLE", SqlKind.TRUNCATE_TABLE) {
+        @Override public SqlCall createCall(@Nullable SqlLiteral 
functionQualifier,
+            SqlParserPos pos, @Nullable SqlNode... operands) {
+          return new SqlTruncateTable(pos,
+              (SqlIdentifier) requireNonNull(operands[0], "name"),
+              ((SqlLiteral) requireNonNull(operands[1], 
"continueIdentity")).booleanValue());
+        }
+      };
+
   public final SqlIdentifier name;
-  public final boolean continueIdentify;
+  public final boolean continueIdentity;
 
   /**
    * Creates a SqlTruncateTable.
    */
-  public SqlTruncateTable(SqlParserPos pos, SqlIdentifier name, boolean 
continueIdentify) {
+  public SqlTruncateTable(SqlParserPos pos, SqlIdentifier name, boolean 
continueIdentity) {
     super(OPERATOR, pos);
     this.name = name;
-    this.continueIdentify = continueIdentify;
+    this.continueIdentity = continueIdentity;
   }
 
   @Override public List<SqlNode> getOperandList() {
-    return ImmutableList.of(name);
+    return ImmutableList.of(name, SqlLiteral.createBoolean(continueIdentity, 
SqlParserPos.ZERO));
   }
 
   @Override public void unparse(SqlWriter writer, int leftPrec, int rightPrec) 
{
     writer.keyword("TRUNCATE");
     writer.keyword("TABLE");
     name.unparse(writer, leftPrec, rightPrec);
-    if (continueIdentify) {
+    if (continueIdentity) {
       writer.keyword("CONTINUE IDENTITY");
     } else {
       writer.keyword("RESTART IDENTITY");
-
     }
   }
 }
diff --git a/core/src/test/java/org/apache/calcite/util/UtilTest.java 
b/core/src/test/java/org/apache/calcite/util/UtilTest.java
index 45c964beed..7d8797f19c 100644
--- a/core/src/test/java/org/apache/calcite/util/UtilTest.java
+++ b/core/src/test/java/org/apache/calcite/util/UtilTest.java
@@ -30,6 +30,7 @@
 import org.apache.calcite.runtime.SqlFunctions;
 import org.apache.calcite.runtime.Utilities;
 import org.apache.calcite.sql.SqlCollation;
+import org.apache.calcite.sql.SqlNodeList;
 import org.apache.calcite.sql.dialect.CalciteSqlDialect;
 import org.apache.calcite.sql.fun.SqlLibrary;
 import org.apache.calcite.sql.util.IdPair;
@@ -56,6 +57,7 @@
 import org.hamcrest.StringDescription;
 import org.hamcrest.TypeSafeMatcher;
 import org.junit.jupiter.api.Test;
+import org.locationtech.jts.util.Assert;
 
 import java.io.PrintWriter;
 import java.io.Serializable;
@@ -2961,6 +2963,16 @@ private void checkNameMultimap(String s, 
NameMultimap<Integer> map) {
     assertThat(s2, hasToString(s.toString()));
   }
 
+  @Test void testCollationEncoding() {
+    SqlCollation collation =
+        new SqlCollation(
+            SqlCollation.Coercibility.COERCIBLE, Locale.ENGLISH,
+            Util.getDefaultCharset(), "primary");
+    SqlNodeList list = collation.asList();
+    SqlCollation decoded = SqlCollation.fromSqlList(list);
+    Assert.equals(collation, decoded);
+  }
+
   @Test void testXmlOutput() {
     final StringWriter w = new StringWriter();
     final XmlOutput o = new XmlOutput(w);
diff --git 
a/server/src/main/java/org/apache/calcite/server/ServerDdlExecutor.java 
b/server/src/main/java/org/apache/calcite/server/ServerDdlExecutor.java
index 3fb4545643..8bd55b9151 100644
--- a/server/src/main/java/org/apache/calcite/server/ServerDdlExecutor.java
+++ b/server/src/main/java/org/apache/calcite/server/ServerDdlExecutor.java
@@ -387,7 +387,7 @@ public void execute(SqlTruncateTable truncate,
           RESOURCE.tableNotFound(pair.right));
     }
 
-    if (!truncate.continueIdentify) {
+    if (!truncate.continueIdentity) {
       // Calcite not support RESTART IDENTIFY
       throw new UnsupportedOperationException("RESTART IDENTIFY is not 
supported");
     }
@@ -519,7 +519,12 @@ public void execute(SqlCreateTable create,
         if (d.strategy != ColumnStrategy.VIRTUAL) {
           storedBuilder.add(d.name.getSimple(), type);
         }
-        b.add(ColumnDef.of(d.expression, type, d.strategy));
+        final ColumnStrategy strategy = d.strategy != null
+            ? d.strategy
+            : type.isNullable()
+                ? ColumnStrategy.NULLABLE
+                : ColumnStrategy.NOT_NULLABLE;
+        b.add(ColumnDef.of(d.expression, type, strategy));
       } else if (c.e instanceof SqlIdentifier) {
         final SqlIdentifier id = (SqlIdentifier) c.e;
         if (queryRowType == null) {
diff --git a/server/src/test/java/org/apache/calcite/test/ServerParserTest.java 
b/server/src/test/java/org/apache/calcite/test/ServerParserTest.java
index aeb1c07525..99fa4f37d6 100644
--- a/server/src/test/java/org/apache/calcite/test/ServerParserTest.java
+++ b/server/src/test/java/org/apache/calcite/test/ServerParserTest.java
@@ -16,12 +16,36 @@
  */
 package org.apache.calcite.test;
 
+import org.apache.calcite.sql.SqlCall;
+import org.apache.calcite.sql.SqlNode;
+import org.apache.calcite.sql.ddl.SqlCreateFunction;
+import org.apache.calcite.sql.ddl.SqlCreateSchema;
+import org.apache.calcite.sql.ddl.SqlCreateTable;
+import org.apache.calcite.sql.ddl.SqlCreateType;
+import org.apache.calcite.sql.ddl.SqlDropFunction;
+import org.apache.calcite.sql.ddl.SqlDropMaterializedView;
+import org.apache.calcite.sql.ddl.SqlDropSchema;
+import org.apache.calcite.sql.ddl.SqlDropTable;
+import org.apache.calcite.sql.ddl.SqlDropType;
+import org.apache.calcite.sql.ddl.SqlDropView;
+import org.apache.calcite.sql.ddl.SqlTruncateTable;
+import org.apache.calcite.sql.parser.SqlParseException;
 import org.apache.calcite.sql.parser.SqlParserFixture;
+import org.apache.calcite.sql.parser.SqlParserPos;
 import org.apache.calcite.sql.parser.SqlParserTest;
 import org.apache.calcite.sql.parser.ddl.SqlDdlParserImpl;
+import org.apache.calcite.sql.util.SqlShuttle;
 
+import org.checkerframework.checker.nullness.qual.Nullable;
 import org.junit.jupiter.api.Test;
 
+import java.util.function.BiConsumer;
+import java.util.function.Function;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import static java.util.Objects.requireNonNull;
+
 /**
  * Tests SQL parser extensions for DDL.
  *
@@ -86,6 +110,83 @@ class ServerParserTest extends SqlParserTest {
     sql(sql).ok(expected);
   }
 
+  /** Test case for <a 
href="https://issues.apache.org/jira/browse/CALCITE-7339";>[CALCITE-7339]
+   * Most classes in SqlDdlNodes use an incorrect SqlCallFactory</a>. */
+  @Test void testShuttle() throws SqlParseException {
+    // A shuttle which modified a SqlCall's position
+    final SqlShuttle shuttle = new SqlShuttle() {
+      @Override public @Nullable SqlNode visit(SqlCall call) {
+        SqlNode newCall = super.visit(call);
+        return requireNonNull(newCall, "newCall").clone(SqlParserPos.ZERO);
+      }
+    };
+
+    BiConsumer<SqlParserFixture, Function<SqlNode, Boolean>> tester =
+        (fixture, function) -> {
+          SqlNode node = fixture.node();
+          assertTrue(function.apply(node));
+          SqlNode newNode = shuttle.visitNode(node);
+          assertTrue(function.apply(newNode));
+        };
+
+    String sql = "CREATE TYPE T AS (x INT)";
+    SqlParserFixture fixture = sql(sql);
+    fixture.ok("CREATE TYPE `T` AS (`X` INTEGER)");
+    tester.accept(fixture, n -> n instanceof SqlCreateType);
+
+    // The following also checks SqlCheckConstraint, SqlColumnDeclaration, 
SqlAttributeDefinition
+    sql = "CREATE TABLE X (I INTEGER NOT NULL, CONSTRAINT C1 CHECK (I < 10), J 
INTEGER)";
+    fixture = sql(sql);
+    fixture.ok("CREATE TABLE `X` (`I` INTEGER NOT NULL, "
+        + "CONSTRAINT `C1` CHECK (`I` < 10), `J` INTEGER)");
+    tester.accept(fixture, n -> n instanceof SqlCreateTable);
+
+    sql = "CREATE FUNCTION F AS 'a.b'";
+    fixture = sql(sql);
+    fixture.ok("CREATE FUNCTION `F` AS 'a.b'");
+    tester.accept(fixture, n -> n instanceof SqlCreateFunction);
+
+    sql = "CREATE SCHEMA F";
+    fixture = sql(sql);
+    fixture.ok("CREATE SCHEMA `F`");
+    tester.accept(fixture, n -> n instanceof SqlCreateSchema);
+
+    sql = "DROP FUNCTION IF EXISTS F";
+    fixture = sql(sql);
+    fixture.ok("DROP FUNCTION IF EXISTS `F`");
+    tester.accept(fixture, n -> n instanceof SqlDropFunction);
+
+    sql = "DROP VIEW IF EXISTS V";
+    fixture = sql(sql);
+    fixture.ok("DROP VIEW IF EXISTS `V`");
+    tester.accept(fixture, n -> n instanceof SqlDropView);
+
+    sql = "DROP TABLE T";
+    fixture = sql(sql);
+    fixture.ok("DROP TABLE `T`");
+    tester.accept(fixture, n -> n instanceof SqlDropTable);
+
+    sql = "DROP SCHEMA IF EXISTS S";
+    fixture = sql(sql);
+    fixture.ok("DROP SCHEMA IF EXISTS `S`");
+    tester.accept(fixture, n -> n instanceof SqlDropSchema);
+
+    sql = "DROP TYPE IF EXISTS T";
+    fixture = sql(sql);
+    fixture.ok("DROP TYPE IF EXISTS `T`");
+    tester.accept(fixture, n -> n instanceof SqlDropType);
+
+    sql = "DROP MATERIALIZED VIEW IF EXISTS V";
+    fixture = sql(sql);
+    fixture.ok("DROP MATERIALIZED VIEW IF EXISTS `V`");
+    tester.accept(fixture, n -> n instanceof SqlDropMaterializedView);
+
+    sql = "TRUNCATE TABLE T CONTINUE IDENTITY";
+    fixture = sql(sql);
+    fixture.ok("TRUNCATE TABLE `T` CONTINUE IDENTITY");
+    tester.accept(fixture, n -> n instanceof SqlTruncateTable);
+  }
+
   @Test void testCreateForeignSchema2() {
     final String sql = "create or replace foreign schema x\n"
         + "library 'com.example.ExampleSchemaFactory'\n"

Reply via email to