korlov42 commented on code in PR #1623:
URL: https://github.com/apache/ignite-3/pull/1623#discussion_r1105664246
##########
modules/jdbc/src/main/java/org/apache/ignite/internal/jdbc/JdbcDatabaseMetadata.java:
##########
@@ -1226,6 +1227,12 @@ public ResultSet getTypeInfo() {
(short) typeNullable, false, (short) typeSearchable, false,
false, false, "LONGVARBINARY", 0, 0,
Types.LONGVARBINARY, 0, null));
+ types.add(Arrays.asList("UUID", Types.OTHER,
ColumnMetadata.UNDEFINED_PRECISION, "'", "'", null,
+ (short) typeNullable, true, (short) typeSearchable, true,
false, false, null, 0, 0,
Review Comment:
does UUID really case sensitive? (see `true` next to `typeNullable `)
##########
modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/type/IgniteCustomType.java:
##########
@@ -0,0 +1,178 @@
+/*
+ * 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.ignite.internal.sql.engine.type;
+
+import java.lang.reflect.Type;
+import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.rel.type.RelDataTypeFamily;
+import org.apache.calcite.rel.type.RelDataTypeImpl;
+import org.apache.calcite.sql.SqlIdentifier;
+import org.apache.calcite.sql.SqlLiteral;
+import org.apache.calcite.sql.SqlTypeNameSpec;
+import org.apache.calcite.sql.parser.SqlParserPos;
+import org.apache.calcite.sql.type.SqlTypeFamily;
+import org.apache.calcite.sql.type.SqlTypeName;
+import org.apache.ignite.internal.schema.NativeType;
+import org.apache.ignite.internal.sql.engine.exec.ExecutionContext;
+import org.apache.ignite.internal.sql.engine.sql.IgniteSqlTypeNameSpec;
+import org.apache.ignite.sql.ColumnType;
+
+/**
+ * A base class for custom data types.
+ * <p><b>Custom data type implementation check list.</b></p>
Review Comment:
as far as I can recall, it's mandatory to leave an empty line before new
paragraph. Beside, it's not required to close `<p>` tag in simple cases (like
the next paragraph `Add a subclass...`). I think, following these rules will
make the doc a bit easier to read without rendering
##########
modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/prepare/LeastRestrictiveTypesTest.java:
##########
@@ -208,14 +215,37 @@ private static Stream<Arguments> bigIntTests() {
return tests.stream();
}
+ @ParameterizedTest
+ @MethodSource("uuidTests")
+ public void testUuid(RelDataType t1, RelDataType t2, LeastRestrictiveType
leastRestrictiveType) {
+ expectLeastRestrictiveType(t1, t2, leastRestrictiveType);
+ expectLeastRestrictiveType(t2, t1, leastRestrictiveType);
+ }
+
+ private static Stream<Arguments> uuidTests() {
+ List<Arguments> tests = new ArrayList<>();
+
+ tests.add(Arguments.arguments(UUID, TINYINT, new
LeastRestrictiveType(ANY)));
+ tests.add(Arguments.arguments(UUID, SMALLINT, new
LeastRestrictiveType(ANY)));
+ tests.add(Arguments.arguments(UUID, INTEGER, new
LeastRestrictiveType(ANY)));
+ tests.add(Arguments.arguments(UUID, FLOAT, new
LeastRestrictiveType(ANY)));
+ tests.add(Arguments.arguments(UUID, REAL, new
LeastRestrictiveType(ANY)));
+ tests.add(Arguments.arguments(UUID, DOUBLE, new
LeastRestrictiveType(ANY)));
+ tests.add(Arguments.arguments(UUID, DECIMAL, new
LeastRestrictiveType(ANY)));
+ tests.add(Arguments.arguments(UUID, BIGINT, new
LeastRestrictiveType(ANY)));
+ tests.add(Arguments.arguments(UUID, VARCHAR, new
LeastRestrictiveType(UUID)));
Review Comment:
I think this is not correct. UUID belongs to its own family, but least
restrictive type does make sense only within the same family. So, the expected
value has to be null, I guess
##########
modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/type/IgniteCustomType.java:
##########
@@ -0,0 +1,178 @@
+/*
+ * 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.ignite.internal.sql.engine.type;
+
+import java.lang.reflect.Type;
+import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.rel.type.RelDataTypeFamily;
+import org.apache.calcite.rel.type.RelDataTypeImpl;
+import org.apache.calcite.sql.SqlIdentifier;
+import org.apache.calcite.sql.SqlLiteral;
+import org.apache.calcite.sql.SqlTypeNameSpec;
+import org.apache.calcite.sql.parser.SqlParserPos;
+import org.apache.calcite.sql.type.SqlTypeFamily;
+import org.apache.calcite.sql.type.SqlTypeName;
+import org.apache.ignite.internal.schema.NativeType;
+import org.apache.ignite.internal.sql.engine.exec.ExecutionContext;
+import org.apache.ignite.internal.sql.engine.sql.IgniteSqlTypeNameSpec;
+import org.apache.ignite.sql.ColumnType;
+
+/**
+ * A base class for custom data types.
+ * <p><b>Custom data type implementation check list.</b></p>
+ * <p>
+ * Add a subclass that extends {@link IgniteCustomType}.
+ * </p>
+ * <ul>
+ * <li>Implement {@link IgniteCustomType#storageType()} - storage type
must implement {@link Comparable}.
+ * This is a requirement imposed by calcite's row-expressions
implementation.
+ * (see {@link org.apache.ignite.internal.sql.engine.rex.IgniteRexBuilder
IgniteRexBuilder}).</li>
+ * <li>Implement {@link IgniteCustomType#nativeType()}.</li>
+ * <li>Implement {@link IgniteCustomType#columnType()}.</li>
+ * <li>Implement {@link
IgniteCustomType#createWithNullability(boolean)}.</li>
+ * </ul>
+ * <p>
+ * Code base contains comments that start with {@code IgniteCustomType:} to
provide extra information.
+ * </p>
+ * <p>
+ * Update {@link IgniteTypeFactory}'s constructor to register your type.
+ * </p>
+ * <p>
+ * Update type inference for dynamic parameters in
+ * {@link org.apache.ignite.internal.sql.engine.prepare.IgniteSqlValidator
IgniteSqlValidator}.
Review Comment:
we should use import instead of FQDN
##########
modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/type/IgniteCustomType.java:
##########
@@ -0,0 +1,178 @@
+/*
+ * 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.ignite.internal.sql.engine.type;
+
+import java.lang.reflect.Type;
+import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.rel.type.RelDataTypeFamily;
+import org.apache.calcite.rel.type.RelDataTypeImpl;
+import org.apache.calcite.sql.SqlIdentifier;
+import org.apache.calcite.sql.SqlLiteral;
+import org.apache.calcite.sql.SqlTypeNameSpec;
+import org.apache.calcite.sql.parser.SqlParserPos;
+import org.apache.calcite.sql.type.SqlTypeFamily;
+import org.apache.calcite.sql.type.SqlTypeName;
+import org.apache.ignite.internal.schema.NativeType;
+import org.apache.ignite.internal.sql.engine.exec.ExecutionContext;
+import org.apache.ignite.internal.sql.engine.sql.IgniteSqlTypeNameSpec;
+import org.apache.ignite.sql.ColumnType;
+
+/**
+ * A base class for custom data types.
+ * <p><b>Custom data type implementation check list.</b></p>
+ * <p>
+ * Add a subclass that extends {@link IgniteCustomType}.
+ * </p>
+ * <ul>
+ * <li>Implement {@link IgniteCustomType#storageType()} - storage type
must implement {@link Comparable}.
+ * This is a requirement imposed by calcite's row-expressions
implementation.
+ * (see {@link org.apache.ignite.internal.sql.engine.rex.IgniteRexBuilder
IgniteRexBuilder}).</li>
+ * <li>Implement {@link IgniteCustomType#nativeType()}.</li>
+ * <li>Implement {@link IgniteCustomType#columnType()}.</li>
+ * <li>Implement {@link
IgniteCustomType#createWithNullability(boolean)}.</li>
+ * </ul>
+ * <p>
+ * Code base contains comments that start with {@code IgniteCustomType:} to
provide extra information.
+ * </p>
+ * <p>
+ * Update {@link IgniteTypeFactory}'s constructor to register your type.
+ * </p>
+ * <p>
+ * Update type inference for dynamic parameters in
+ * {@link org.apache.ignite.internal.sql.engine.prepare.IgniteSqlValidator
IgniteSqlValidator}.
+ * </p>
+ * <p>
+ * Update {@link org.apache.ignite.internal.sql.engine.util.TypeUtils
TypeUtils}:
+ * </p>
+ * <ul>
+ * <li>Update {@link
org.apache.ignite.internal.sql.engine.util.TypeUtils#toInternal(ExecutionContext,
Object, Type)
+ * TypeUtils::toInternal} and {@link
org.apache.ignite.internal.sql.engine.util.TypeUtils#fromInternal(ExecutionContext,
Object, Type)
+ * TypeUtils::fromInternal} to add assertions that check that a value has
the same type as a {@link #storageType()}.</li>
+ * </ul>
+ * <p>
+ * Update both {@link
org.apache.ignite.internal.sql.engine.exec.exp.RexToLixTranslator
RexToLitTranslator} and
+ * {@link org.apache.ignite.internal.sql.engine.exec.exp.ConverterUtils
ConveterUtils} to implement runtime routines for conversion
+ * of your type from other data types if necessary.
+ * </p>
+ * Further steps:
+ * <ul>
+ * <li>Update an SQL parser generator code to support your type - see
DataTypeEx().</li>
+ * <li>Update JdbcDatabaseMetadata getTypeInfo.</li>
+ * <li>Update {@link
org.apache.ignite.internal.sql.engine.exec.exp.agg.Accumulators Accumulators}
+ * if your type supports some aggregation functions.
+ * By default all custom data type support {@code COUNT} and {@code
ANY_VALUE}.</li>
+ * <li>Update serialisation/deserialisation code to store extra
attributes.</li>
+ * <li>There probably some methods in {@link IgniteTypeSystem} that maybe
subject to change
+ * when a custom data type is implemented.</li>
+ * </ul>
+ * <b>Update this documentation when you are going to change this
procedure.</b>
+ *
+*/
+public abstract class IgniteCustomType extends RelDataTypeImpl {
+ /** Nullable flag. */
+ private final boolean nullable;
+
+ /** Precision. **/
+ private final int precision;
+
+ /** Constructor. */
+ protected IgniteCustomType(boolean nullable, int precision) {
+ this.nullable = nullable;
+ this.precision = precision;
+
+ computeDigest();
+ }
+
+ /** Return the name of this type. **/
+ public abstract String getCustomTypeName();
+
+ /**
+ * Returns the storage type of this data type.
+ * This method is called by {@link
IgniteTypeFactory#getJavaClass(RelDataType)}
+ * to provide types for a expression interpreter. Execution engine also
relies on the fact that this
+ * type is also used by {@link
org.apache.ignite.internal.sql.engine.util.TypeUtils} in type conversions.
+ *
+ * @see
org.apache.ignite.internal.sql.engine.exec.exp.ExpressionFactoryImpl
+ * @see
org.apache.ignite.internal.sql.engine.util.TypeUtils#toInternal(ExecutionContext,
Object, Type)
+ * @see
org.apache.ignite.internal.sql.engine.util.TypeUtils#fromInternal(ExecutionContext,
Object, Type)
+ */
+ public abstract Type storageType();
+
+ /**
+ * Returns the {@link NativeType} for this custom data type.
+ * At the moment it serves the following purpose:
+ * <ul>
+ * <li>
+ * Used by {@link
IgniteTypeFactory#relDataTypeToNative(RelDataType)} to retrieve underlying
+ * {@link NativeType} for DDL queries.
+ * </li>
+ * <li>
+ * To retrieve a java type to perform type conversions by
+ * {@link
org.apache.ignite.internal.sql.engine.exec.ExecutionServiceImpl}.
+ * </li>
+ * </ul>
+ */
+ public abstract NativeType nativeType();
+
+ /**
+ * Returns the {@link ColumnType} of this data type. Provides type
information for {@link org.apache.ignite.sql.ColumnMetadata}.
+ */
+ public abstract ColumnType columnType();
+
+ /** {@inheritDoc} */
+ @Override public final boolean isNullable() {
+ return nullable;
+ }
+
+ /** {@inheritDoc} */
+ @Override public final RelDataTypeFamily getFamily() {
+ return SqlTypeFamily.ANY;
Review Comment:
I think we need to return `this` here. Types of the same family should be
considered comparable. Thus, in general case, every custom type should be a
member of its own family
##########
modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/IgniteResource.java:
##########
@@ -40,4 +42,7 @@ public interface IgniteResource {
@Resources.BaseMessage("Unexpected number of query parameters. Provided
{0} but there is only {1} dynamic parameter(s).")
Resources.ExInst<SqlValidatorException> unexpectedParameter(int provided,
int expected);
+
+ @Resources.BaseMessage("There is no operator {0} {1} {2}")
+ Resources.ExInst<SqlValidatorException> noSqlOperator(RelDataType lhs,
SqlOperator op, RelDataType rhs);
Review Comment:
CalciteResource already has errors for similar problem:
```
@BaseMessage("Invalid types for arithmetic: {0} {1} {2}")
ExInst<CalciteException> invalidTypesForArithmetic(String clazzName0,
String op,
String clazzName1);
@BaseMessage("Invalid types for comparison: {0} {1} {2}")
ExInst<CalciteException> invalidTypesForComparison(String clazzName0,
String op,
String clazzName1);
```
Does it make sense to follow this patter?
##########
modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/type/IgniteCustomType.java:
##########
@@ -0,0 +1,178 @@
+/*
+ * 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.ignite.internal.sql.engine.type;
+
+import java.lang.reflect.Type;
+import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.rel.type.RelDataTypeFamily;
+import org.apache.calcite.rel.type.RelDataTypeImpl;
+import org.apache.calcite.sql.SqlIdentifier;
+import org.apache.calcite.sql.SqlLiteral;
+import org.apache.calcite.sql.SqlTypeNameSpec;
+import org.apache.calcite.sql.parser.SqlParserPos;
+import org.apache.calcite.sql.type.SqlTypeFamily;
+import org.apache.calcite.sql.type.SqlTypeName;
+import org.apache.ignite.internal.schema.NativeType;
+import org.apache.ignite.internal.sql.engine.exec.ExecutionContext;
+import org.apache.ignite.internal.sql.engine.sql.IgniteSqlTypeNameSpec;
+import org.apache.ignite.sql.ColumnType;
+
+/**
+ * A base class for custom data types.
+ * <p><b>Custom data type implementation check list.</b></p>
+ * <p>
+ * Add a subclass that extends {@link IgniteCustomType}.
+ * </p>
+ * <ul>
+ * <li>Implement {@link IgniteCustomType#storageType()} - storage type
must implement {@link Comparable}.
Review Comment:
> storage type must implement {@link Comparable}.
it's better to enforce this through generics:
```
abstract class IgniteCustomType<StorageT extends Comparable<StorageT>> ... {
protected IgniteCustomType(Class<StorageT> storageClass, boolean
nullable, int precision)
```
Such an approach will guarantee type safety in compile time.
##########
modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/type/IgniteCustomType.java:
##########
@@ -0,0 +1,178 @@
+/*
+ * 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.ignite.internal.sql.engine.type;
+
+import java.lang.reflect.Type;
+import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.rel.type.RelDataTypeFamily;
+import org.apache.calcite.rel.type.RelDataTypeImpl;
+import org.apache.calcite.sql.SqlIdentifier;
+import org.apache.calcite.sql.SqlLiteral;
+import org.apache.calcite.sql.SqlTypeNameSpec;
+import org.apache.calcite.sql.parser.SqlParserPos;
+import org.apache.calcite.sql.type.SqlTypeFamily;
+import org.apache.calcite.sql.type.SqlTypeName;
+import org.apache.ignite.internal.schema.NativeType;
+import org.apache.ignite.internal.sql.engine.exec.ExecutionContext;
+import org.apache.ignite.internal.sql.engine.sql.IgniteSqlTypeNameSpec;
+import org.apache.ignite.sql.ColumnType;
+
+/**
+ * A base class for custom data types.
+ * <p><b>Custom data type implementation check list.</b></p>
+ * <p>
+ * Add a subclass that extends {@link IgniteCustomType}.
+ * </p>
+ * <ul>
+ * <li>Implement {@link IgniteCustomType#storageType()} - storage type
must implement {@link Comparable}.
+ * This is a requirement imposed by calcite's row-expressions
implementation.
+ * (see {@link org.apache.ignite.internal.sql.engine.rex.IgniteRexBuilder
IgniteRexBuilder}).</li>
+ * <li>Implement {@link IgniteCustomType#nativeType()}.</li>
+ * <li>Implement {@link IgniteCustomType#columnType()}.</li>
+ * <li>Implement {@link
IgniteCustomType#createWithNullability(boolean)}.</li>
+ * </ul>
+ * <p>
+ * Code base contains comments that start with {@code IgniteCustomType:} to
provide extra information.
+ * </p>
+ * <p>
+ * Update {@link IgniteTypeFactory}'s constructor to register your type.
+ * </p>
+ * <p>
+ * Update type inference for dynamic parameters in
+ * {@link org.apache.ignite.internal.sql.engine.prepare.IgniteSqlValidator
IgniteSqlValidator}.
+ * </p>
+ * <p>
+ * Update {@link org.apache.ignite.internal.sql.engine.util.TypeUtils
TypeUtils}:
+ * </p>
+ * <ul>
+ * <li>Update {@link
org.apache.ignite.internal.sql.engine.util.TypeUtils#toInternal(ExecutionContext,
Object, Type)
+ * TypeUtils::toInternal} and {@link
org.apache.ignite.internal.sql.engine.util.TypeUtils#fromInternal(ExecutionContext,
Object, Type)
+ * TypeUtils::fromInternal} to add assertions that check that a value has
the same type as a {@link #storageType()}.</li>
+ * </ul>
+ * <p>
+ * Update both {@link
org.apache.ignite.internal.sql.engine.exec.exp.RexToLixTranslator
RexToLitTranslator} and
+ * {@link org.apache.ignite.internal.sql.engine.exec.exp.ConverterUtils
ConveterUtils} to implement runtime routines for conversion
+ * of your type from other data types if necessary.
+ * </p>
+ * Further steps:
+ * <ul>
+ * <li>Update an SQL parser generator code to support your type - see
DataTypeEx().</li>
+ * <li>Update JdbcDatabaseMetadata getTypeInfo.</li>
+ * <li>Update {@link
org.apache.ignite.internal.sql.engine.exec.exp.agg.Accumulators Accumulators}
+ * if your type supports some aggregation functions.
+ * By default all custom data type support {@code COUNT} and {@code
ANY_VALUE}.</li>
+ * <li>Update serialisation/deserialisation code to store extra
attributes.</li>
+ * <li>There probably some methods in {@link IgniteTypeSystem} that maybe
subject to change
+ * when a custom data type is implemented.</li>
+ * </ul>
+ * <b>Update this documentation when you are going to change this
procedure.</b>
+ *
+*/
+public abstract class IgniteCustomType extends RelDataTypeImpl {
+ /** Nullable flag. */
+ private final boolean nullable;
+
+ /** Precision. **/
Review Comment:
do we really need such a comment? I believe, the name of the property gives
exactly the same information
##########
modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/type/IgniteCustomType.java:
##########
@@ -0,0 +1,178 @@
+/*
+ * 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.ignite.internal.sql.engine.type;
+
+import java.lang.reflect.Type;
+import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.rel.type.RelDataTypeFamily;
+import org.apache.calcite.rel.type.RelDataTypeImpl;
+import org.apache.calcite.sql.SqlIdentifier;
+import org.apache.calcite.sql.SqlLiteral;
+import org.apache.calcite.sql.SqlTypeNameSpec;
+import org.apache.calcite.sql.parser.SqlParserPos;
+import org.apache.calcite.sql.type.SqlTypeFamily;
+import org.apache.calcite.sql.type.SqlTypeName;
+import org.apache.ignite.internal.schema.NativeType;
+import org.apache.ignite.internal.sql.engine.exec.ExecutionContext;
+import org.apache.ignite.internal.sql.engine.sql.IgniteSqlTypeNameSpec;
+import org.apache.ignite.sql.ColumnType;
+
+/**
+ * A base class for custom data types.
+ * <p><b>Custom data type implementation check list.</b></p>
+ * <p>
+ * Add a subclass that extends {@link IgniteCustomType}.
+ * </p>
+ * <ul>
+ * <li>Implement {@link IgniteCustomType#storageType()} - storage type
must implement {@link Comparable}.
+ * This is a requirement imposed by calcite's row-expressions
implementation.
+ * (see {@link org.apache.ignite.internal.sql.engine.rex.IgniteRexBuilder
IgniteRexBuilder}).</li>
+ * <li>Implement {@link IgniteCustomType#nativeType()}.</li>
+ * <li>Implement {@link IgniteCustomType#columnType()}.</li>
+ * <li>Implement {@link
IgniteCustomType#createWithNullability(boolean)}.</li>
+ * </ul>
+ * <p>
+ * Code base contains comments that start with {@code IgniteCustomType:} to
provide extra information.
+ * </p>
+ * <p>
+ * Update {@link IgniteTypeFactory}'s constructor to register your type.
+ * </p>
+ * <p>
+ * Update type inference for dynamic parameters in
+ * {@link org.apache.ignite.internal.sql.engine.prepare.IgniteSqlValidator
IgniteSqlValidator}.
+ * </p>
+ * <p>
+ * Update {@link org.apache.ignite.internal.sql.engine.util.TypeUtils
TypeUtils}:
+ * </p>
+ * <ul>
+ * <li>Update {@link
org.apache.ignite.internal.sql.engine.util.TypeUtils#toInternal(ExecutionContext,
Object, Type)
+ * TypeUtils::toInternal} and {@link
org.apache.ignite.internal.sql.engine.util.TypeUtils#fromInternal(ExecutionContext,
Object, Type)
+ * TypeUtils::fromInternal} to add assertions that check that a value has
the same type as a {@link #storageType()}.</li>
+ * </ul>
+ * <p>
+ * Update both {@link
org.apache.ignite.internal.sql.engine.exec.exp.RexToLixTranslator
RexToLitTranslator} and
+ * {@link org.apache.ignite.internal.sql.engine.exec.exp.ConverterUtils
ConveterUtils} to implement runtime routines for conversion
+ * of your type from other data types if necessary.
+ * </p>
+ * Further steps:
+ * <ul>
+ * <li>Update an SQL parser generator code to support your type - see
DataTypeEx().</li>
+ * <li>Update JdbcDatabaseMetadata getTypeInfo.</li>
+ * <li>Update {@link
org.apache.ignite.internal.sql.engine.exec.exp.agg.Accumulators Accumulators}
+ * if your type supports some aggregation functions.
+ * By default all custom data type support {@code COUNT} and {@code
ANY_VALUE}.</li>
+ * <li>Update serialisation/deserialisation code to store extra
attributes.</li>
+ * <li>There probably some methods in {@link IgniteTypeSystem} that maybe
subject to change
+ * when a custom data type is implemented.</li>
+ * </ul>
+ * <b>Update this documentation when you are going to change this
procedure.</b>
+ *
+*/
+public abstract class IgniteCustomType extends RelDataTypeImpl {
+ /** Nullable flag. */
+ private final boolean nullable;
+
+ /** Precision. **/
+ private final int precision;
+
+ /** Constructor. */
+ protected IgniteCustomType(boolean nullable, int precision) {
+ this.nullable = nullable;
+ this.precision = precision;
+
+ computeDigest();
+ }
+
+ /** Return the name of this type. **/
+ public abstract String getCustomTypeName();
+
+ /**
+ * Returns the storage type of this data type.
+ * This method is called by {@link
IgniteTypeFactory#getJavaClass(RelDataType)}
Review Comment:
```suggestion
* Returns the storage type of this data type.
*
* <p>This method is called by {@link
IgniteTypeFactory#getJavaClass(RelDataType)}
```
##########
modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/type/IgniteCustomType.java:
##########
@@ -0,0 +1,178 @@
+/*
+ * 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.ignite.internal.sql.engine.type;
+
+import java.lang.reflect.Type;
+import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.rel.type.RelDataTypeFamily;
+import org.apache.calcite.rel.type.RelDataTypeImpl;
+import org.apache.calcite.sql.SqlIdentifier;
+import org.apache.calcite.sql.SqlLiteral;
+import org.apache.calcite.sql.SqlTypeNameSpec;
+import org.apache.calcite.sql.parser.SqlParserPos;
+import org.apache.calcite.sql.type.SqlTypeFamily;
+import org.apache.calcite.sql.type.SqlTypeName;
+import org.apache.ignite.internal.schema.NativeType;
+import org.apache.ignite.internal.sql.engine.exec.ExecutionContext;
+import org.apache.ignite.internal.sql.engine.sql.IgniteSqlTypeNameSpec;
+import org.apache.ignite.sql.ColumnType;
+
+/**
+ * A base class for custom data types.
+ * <p><b>Custom data type implementation check list.</b></p>
+ * <p>
+ * Add a subclass that extends {@link IgniteCustomType}.
+ * </p>
+ * <ul>
+ * <li>Implement {@link IgniteCustomType#storageType()} - storage type
must implement {@link Comparable}.
+ * This is a requirement imposed by calcite's row-expressions
implementation.
+ * (see {@link org.apache.ignite.internal.sql.engine.rex.IgniteRexBuilder
IgniteRexBuilder}).</li>
+ * <li>Implement {@link IgniteCustomType#nativeType()}.</li>
+ * <li>Implement {@link IgniteCustomType#columnType()}.</li>
+ * <li>Implement {@link
IgniteCustomType#createWithNullability(boolean)}.</li>
+ * </ul>
+ * <p>
+ * Code base contains comments that start with {@code IgniteCustomType:} to
provide extra information.
+ * </p>
+ * <p>
+ * Update {@link IgniteTypeFactory}'s constructor to register your type.
+ * </p>
+ * <p>
+ * Update type inference for dynamic parameters in
+ * {@link org.apache.ignite.internal.sql.engine.prepare.IgniteSqlValidator
IgniteSqlValidator}.
+ * </p>
+ * <p>
+ * Update {@link org.apache.ignite.internal.sql.engine.util.TypeUtils
TypeUtils}:
+ * </p>
+ * <ul>
+ * <li>Update {@link
org.apache.ignite.internal.sql.engine.util.TypeUtils#toInternal(ExecutionContext,
Object, Type)
+ * TypeUtils::toInternal} and {@link
org.apache.ignite.internal.sql.engine.util.TypeUtils#fromInternal(ExecutionContext,
Object, Type)
+ * TypeUtils::fromInternal} to add assertions that check that a value has
the same type as a {@link #storageType()}.</li>
+ * </ul>
+ * <p>
+ * Update both {@link
org.apache.ignite.internal.sql.engine.exec.exp.RexToLixTranslator
RexToLitTranslator} and
+ * {@link org.apache.ignite.internal.sql.engine.exec.exp.ConverterUtils
ConveterUtils} to implement runtime routines for conversion
+ * of your type from other data types if necessary.
+ * </p>
+ * Further steps:
+ * <ul>
+ * <li>Update an SQL parser generator code to support your type - see
DataTypeEx().</li>
+ * <li>Update JdbcDatabaseMetadata getTypeInfo.</li>
+ * <li>Update {@link
org.apache.ignite.internal.sql.engine.exec.exp.agg.Accumulators Accumulators}
+ * if your type supports some aggregation functions.
+ * By default all custom data type support {@code COUNT} and {@code
ANY_VALUE}.</li>
+ * <li>Update serialisation/deserialisation code to store extra
attributes.</li>
+ * <li>There probably some methods in {@link IgniteTypeSystem} that maybe
subject to change
+ * when a custom data type is implemented.</li>
+ * </ul>
+ * <b>Update this documentation when you are going to change this
procedure.</b>
+ *
+*/
+public abstract class IgniteCustomType extends RelDataTypeImpl {
+ /** Nullable flag. */
+ private final boolean nullable;
+
+ /** Precision. **/
+ private final int precision;
+
+ /** Constructor. */
+ protected IgniteCustomType(boolean nullable, int precision) {
+ this.nullable = nullable;
+ this.precision = precision;
+
+ computeDigest();
+ }
+
+ /** Return the name of this type. **/
+ public abstract String getCustomTypeName();
+
+ /**
+ * Returns the storage type of this data type.
+ * This method is called by {@link
IgniteTypeFactory#getJavaClass(RelDataType)}
+ * to provide types for a expression interpreter. Execution engine also
relies on the fact that this
+ * type is also used by {@link
org.apache.ignite.internal.sql.engine.util.TypeUtils} in type conversions.
+ *
+ * @see
org.apache.ignite.internal.sql.engine.exec.exp.ExpressionFactoryImpl
+ * @see
org.apache.ignite.internal.sql.engine.util.TypeUtils#toInternal(ExecutionContext,
Object, Type)
+ * @see
org.apache.ignite.internal.sql.engine.util.TypeUtils#fromInternal(ExecutionContext,
Object, Type)
+ */
+ public abstract Type storageType();
+
+ /**
+ * Returns the {@link NativeType} for this custom data type.
+ * At the moment it serves the following purpose:
Review Comment:
```suggestion
* Returns the {@link NativeType} for this custom data type.
*
* <p>At the moment it serves the following purpose:
```
##########
modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/type/UuidFunctions.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.ignite.internal.sql.engine.type;
+
+import java.lang.reflect.Method;
+import java.util.UUID;
+import org.apache.calcite.linq4j.tree.Expression;
+import org.apache.calcite.linq4j.tree.Expressions;
+
+/**
+ * A set functions required by expression execution runtime to support of
{@code UUID} type.
+ */
+public final class UuidFunctions {
+
+ /**
+ * Implementation of a CAST operator for {@link UuidType} used by
expression execution runtime.
+ *
+ * @see #cast(Object)
+ **/
+ private static final Method CAST;
+
+ static {
+ try {
+ CAST = UuidFunctions.class.getMethod("cast", Object.class);
+ } catch (NoSuchMethodException e) {
+ throw new IllegalStateException("cast method is not defined", e);
+ }
+ }
+
+ private UuidFunctions() {
+
+ }
+
+ /**
+ * Creates a cast expression that convert the given operation into {@link
UuidType}.
+ *
+ * @param operand an operand
Review Comment:
```suggestion
* @param operand An operand.
```
please check all the javadocs
##########
modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItUuidTest.java:
##########
@@ -0,0 +1,257 @@
+/*
+ * 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.ignite.internal.sql.engine;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.containsString;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.util.Arrays;
+import java.util.UUID;
+import java.util.stream.Stream;
+import org.apache.calcite.runtime.CalciteContextException;
+import org.apache.calcite.sql.SqlKind;
+import org.apache.ignite.lang.IgniteException;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.MethodSource;
+
+/**
+ * Tests for {@link org.apache.ignite.internal.sql.engine.type.UuidType} data
type.
+ */
+public class ItUuidTest extends AbstractBasicIntegrationTest {
+
+ // UUID1 > UUID2
+ private static final UUID UUID_1 =
UUID.fromString("fd10556e-fc27-4a99-b5e4-89b8344cb3ce");
+
+ private static final UUID UUID_2 =
UUID.fromString("c67d4baf-564e-4abe-aad5-fcf078d178bf");
+
+ /**
+ * Drops all created tables.
+ */
+ @AfterAll
+ public void dropTables() {
+ dropAllTables();
+ }
+
+ @BeforeAll
+ public void createTables() {
+ sql("CREATE TABLE t(id INTEGER PRIMARY KEY, uuid_key UUID)");
+ }
+
+ @BeforeEach
+ public void cleanTables() {
+ sql("DELETE FROM t");
+ }
+
+ @Test
+ public void testUuidLiterals() {
+ UUID uuid1 = UUID.randomUUID();
+
+ assertQuery(String.format("SELECT CAST('%s' as UUID)",
uuid1)).columnTypes(UUID.class).returns(uuid1).check();
Review Comment:
nitpicking: we have `IgniteStringFormatter`. Probably. it would be better to
use it instead of `System.format`
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]