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