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

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


The following commit(s) were added to refs/heads/master by this push:
     new 6dfcfb4  [CALCITE-3726] Allow declaring type objects (ritesh-kapoor)
6dfcfb4 is described below

commit 6dfcfb421aec315b50c9b5ca923f3d0d0f3568b8
Author: Ritesh Kapoor <[email protected]>
AuthorDate: Mon Jan 13 08:51:22 2020 +0530

    [CALCITE-3726] Allow declaring type objects (ritesh-kapoor)
    
    close apache/calcite#1750
---
 .../calcite/adapter/enumerable/RexImpTable.java    |  3 +
 .../java/org/apache/calcite/sql/SqlFunction.java   | 15 +++--
 .../calcite/sql/SqlTypeConstructorFunction.java    | 52 +++++++++++++++
 .../sql/type/ExplicitOperandTypeChecker.java       | 75 ++++++++++++++++++++++
 .../org/apache/calcite/test/SqlValidatorTest.java  |  2 +-
 .../java/org/apache/calcite/test/ServerTest.java   | 25 ++++++++
 server/src/test/resources/sql/type.iq              | 34 ++++++++++
 7 files changed, 201 insertions(+), 5 deletions(-)

diff --git 
a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java 
b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java
index 629e2bd..dc2a6d2 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java
@@ -50,6 +50,7 @@ import org.apache.calcite.sql.SqlBinaryOperator;
 import org.apache.calcite.sql.SqlJsonConstructorNullClause;
 import org.apache.calcite.sql.SqlMatchFunction;
 import org.apache.calcite.sql.SqlOperator;
+import org.apache.calcite.sql.SqlTypeConstructorFunction;
 import org.apache.calcite.sql.SqlWindowTableFunction;
 import org.apache.calcite.sql.fun.SqlJsonArrayAggAggFunction;
 import org.apache.calcite.sql.fun.SqlJsonObjectAggAggFunction;
@@ -910,6 +911,8 @@ public class RexImpTable {
             + " must implement ImplementableFunction");
       }
       return ((ImplementableFunction) udf).getImplementor();
+    } else if (operator instanceof SqlTypeConstructorFunction) {
+      return map.get(SqlStdOperatorTable.ROW);
     }
     return map.get(operator);
   }
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlFunction.java 
b/core/src/main/java/org/apache/calcite/sql/SqlFunction.java
index 6b8899a..8c2be4a 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlFunction.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlFunction.java
@@ -291,13 +291,20 @@ public class SqlFunction extends SqlOperator {
             }
           }
         }
+
+        // check if the identifier represents type
+        final SqlFunction x = (SqlFunction) call.getOperator();
+        final SqlIdentifier identifier = Util.first(x.getSqlIdentifier(),
+            new SqlIdentifier(x.getName(), SqlParserPos.ZERO));
+        RelDataType type = 
validator.getCatalogReader().getNamedType(identifier);
+        if (type != null) {
+          function = new SqlTypeConstructorFunction(identifier, type);
+          break validCoercionType;
+        }
+
         // if function doesn't exist within operator table and known function
         // handling is turned off then create a more permissive function
         if (function == null && validator.isLenientOperatorLookup()) {
-          final SqlFunction x = (SqlFunction) call.getOperator();
-          final SqlIdentifier identifier =
-              Util.first(x.getSqlIdentifier(),
-                  new SqlIdentifier(x.getName(), SqlParserPos.ZERO));
           function = new SqlUnresolvedFunction(identifier, null,
               null, OperandTypes.VARIADIC, null, x.getFunctionType());
           break validCoercionType;
diff --git 
a/core/src/main/java/org/apache/calcite/sql/SqlTypeConstructorFunction.java 
b/core/src/main/java/org/apache/calcite/sql/SqlTypeConstructorFunction.java
new file mode 100644
index 0000000..9979855
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/sql/SqlTypeConstructorFunction.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.calcite.sql;
+
+import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.sql.type.ExplicitOperandTypeChecker;
+
+/**
+ * Type Constructor function.
+ *
+ * <p>Created by the parser, then it is rewritten to proper SqlFunction by
+ * the validator to a function defined in a Calcite schema.</p>
+ */
+public class SqlTypeConstructorFunction extends SqlFunction {
+
+  private RelDataType type;
+
+  /**
+   * Creates a constructor function for types.
+   *
+   * @param identifier possibly qualified identifier for function
+   * @param type type of data
+   */
+  public SqlTypeConstructorFunction(SqlIdentifier identifier,
+      RelDataType type) {
+    super(identifier,
+        null,
+        null,
+        new ExplicitOperandTypeChecker(type),
+        null,
+        SqlFunctionCategory.SYSTEM);
+    this.type = type;
+  }
+
+  @Override public RelDataType inferReturnType(SqlOperatorBinding opBinding) {
+    return type;
+  }
+}
diff --git 
a/core/src/main/java/org/apache/calcite/sql/type/ExplicitOperandTypeChecker.java
 
b/core/src/main/java/org/apache/calcite/sql/type/ExplicitOperandTypeChecker.java
new file mode 100644
index 0000000..d0e5988
--- /dev/null
+++ 
b/core/src/main/java/org/apache/calcite/sql/type/ExplicitOperandTypeChecker.java
@@ -0,0 +1,75 @@
+/*
+ * 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.calcite.sql.type;
+
+import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.rel.type.RelDataTypeField;
+import org.apache.calcite.sql.SqlCallBinding;
+import org.apache.calcite.sql.SqlOperandCountRange;
+import org.apache.calcite.sql.SqlOperator;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Parameter type-checking strategy for Explicit Type.
+ */
+public class ExplicitOperandTypeChecker implements SqlOperandTypeChecker {
+  //~ Methods ----------------------------------------------------------------
+
+  private RelDataType type;
+
+  public ExplicitOperandTypeChecker(RelDataType type) {
+    this.type = type;
+  }
+
+  public boolean isOptional(int i) {
+    return false;
+  }
+
+  public boolean checkOperandTypes(
+      SqlCallBinding callBinding,
+      boolean throwOnFailure) {
+    List<SqlTypeFamily> families = new ArrayList<>();
+
+    List<RelDataTypeField> fieldList = type.getFieldList();
+    for (int i = 0; i < fieldList.size(); i++) {
+      RelDataTypeField field = fieldList.get(i);
+      SqlTypeName sqlTypeName = field.getType().getSqlTypeName();
+      if (sqlTypeName == SqlTypeName.ROW) {
+        if (field.getType().equals(callBinding.getOperandType(i))) {
+          families.add(SqlTypeFamily.ANY);
+        }
+      } else {
+        families.add(field.getType().getSqlTypeName().getFamily());
+      }
+    }
+    return OperandTypes.family(families).checkOperandTypes(callBinding, 
throwOnFailure);
+  }
+
+  public SqlOperandCountRange getOperandCountRange() {
+    return SqlOperandCountRanges.of(type.getFieldCount());
+  }
+
+  public String getAllowedSignatures(SqlOperator op, String opName) {
+    return "<TYPE> " + opName + " <TYPE>";
+  }
+
+  public Consistency getConsistency() {
+    return Consistency.NONE;
+  }
+}
diff --git a/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java 
b/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
index 0be6a60..68a48b6 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
@@ -1568,7 +1568,7 @@ public class SqlValidatorTest extends 
SqlValidatorTestCase {
   @Test public void testInvalidMemberFunction() {
     expr("myCol.^func()^")
         .fails("(?s).*No match found for function signature FUNC().*");
-    expr("myCol.mySubschema.^memberFunc()^")
+    expr("customer.mySubschema.^memberFunc()^")
         .fails("(?s).*No match found for function signature MEMBERFUNC().*");
   }
 
diff --git a/server/src/test/java/org/apache/calcite/test/ServerTest.java 
b/server/src/test/java/org/apache/calcite/test/ServerTest.java
index 0c7efb7..89a842e 100644
--- a/server/src/test/java/org/apache/calcite/test/ServerTest.java
+++ b/server/src/test/java/org/apache/calcite/test/ServerTest.java
@@ -30,6 +30,7 @@ import java.sql.DriverManager;
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.sql.Statement;
+import java.sql.Struct;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -39,6 +40,10 @@ import static org.hamcrest.CoreMatchers.containsString;
 import static org.hamcrest.CoreMatchers.notNullValue;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.core.Is.is;
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.junit.jupiter.api.Assertions.fail;
 
 /**
@@ -242,6 +247,26 @@ public class ServerTest {
     }
   }
 
+  @Test public void testInsertCreateNewCompositeUdt() throws Exception {
+    try (Connection c = connect();
+        Statement s = c.createStatement()) {
+      boolean b = s.execute("create type mytype as (i int, j int)");
+      assertFalse(b);
+      b = s.execute("create table w (i int not null, j mytype)");
+      assertFalse(b);
+      int x = s.executeUpdate("insert into w "
+          + "values (1, mytype(1, 1))");
+      assertEquals(x, 1);
+
+      try (ResultSet r = s.executeQuery("select * from w")) {
+        assertTrue(r.next());
+        assertEquals(r.getInt("i"), 1);
+        assertArrayEquals(r.getObject("j", Struct.class).getAttributes(), new 
Object[] {1, 1});
+        assertFalse(r.next());
+      }
+    }
+  }
+
   @Test public void testStoredGeneratedColumn() throws Exception {
     try (Connection c = connect();
          Statement s = c.createStatement()) {
diff --git a/server/src/test/resources/sql/type.iq 
b/server/src/test/resources/sql/type.iq
index 19eb1ac..9aa2648 100644
--- a/server/src/test/resources/sql/type.iq
+++ b/server/src/test/resources/sql/type.iq
@@ -101,9 +101,43 @@ select * from w;
 
 !ok
 
+
+# Create type object
+
+create type mytype2 as (ii int, jj char);
+(0 rows modified)
+
+!update
+
+create type mytype3 as (ii int, jj mytype2);
+(0 rows modified)
+
+!update
+
+create table w2 (i int not null, j mytype2, k mytype3);
+(0 rows modified)
+
+!update
+
+insert into w2 values (1, mytype2(2, 'a'), mytype3(1, mytype2(3, 'b')) );
+(1 row modified)
+
+!update
+
+select * from w2;
++---+--------+-------------+
+| I | J      | K           |
++---+--------+-------------+
+| 1 | {2, a} | {1, {3, b}} |
++---+--------+-------------+
+(1 row)
+
+!ok
+
 drop table t;
 drop table v;
 drop table w;
+drop table w2;
 (0 rows modified)
 
 !update

Reply via email to