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

alexpl pushed a commit to branch sql-calcite
in repository https://gitbox.apache.org/repos/asf/ignite.git


The following commit(s) were added to refs/heads/sql-calcite by this push:
     new e8a25be  IGNITE-16018 DEFAULT operator support - Fixes #9633.
e8a25be is described below

commit e8a25bec813bd36426eb3d3fe3d040a76dc13f67
Author: Aleksey Plekhanov <[email protected]>
AuthorDate: Mon Dec 20 14:41:34 2021 +0300

    IGNITE-16018 DEFAULT operator support - Fixes #9633.
    
    Signed-off-by: Aleksey Plekhanov <[email protected]>
---
 .../query/calcite/exec/ExecutionContext.java       |  44 ++----
 .../query/calcite/exec/exp/RexImpTable.java        |   5 +-
 .../query/calcite/prepare/BaseDataContext.java     |  90 +++++++++++
 .../prepare/ddl/DdlSqlToCommandConverter.java      |  15 +-
 .../query/calcite/schema/TableDescriptorImpl.java  |  33 +++-
 .../calcite/sql/fun/IgniteStdSqlOperatorTable.java |   1 +
 .../processors/query/calcite/util/TypeUtils.java   |  82 ++++++++--
 .../integration/TableDmlIntegrationTest.java       |  88 +++++++++++
 .../query/calcite/jdbc/JdbcCrossEngineTest.java    | 169 +++++++++++++++++++++
 .../ignite/testsuites/IntegrationTestSuite.java    |   2 +
 10 files changed, 470 insertions(+), 59 deletions(-)

diff --git 
a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/ExecutionContext.java
 
b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/ExecutionContext.java
index 2a94b21..73a0472 100644
--- 
a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/ExecutionContext.java
+++ 
b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/ExecutionContext.java
@@ -18,19 +18,15 @@
 package org.apache.ignite.internal.processors.query.calcite.exec;
 
 import java.util.List;
-import java.util.Locale;
 import java.util.Map;
 import java.util.Objects;
-import java.util.TimeZone;
 import java.util.UUID;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.function.Consumer;
-
 import org.apache.calcite.DataContext;
 import org.apache.calcite.linq4j.QueryProvider;
 import org.apache.calcite.schema.SchemaPlus;
-import org.apache.calcite.tools.Frameworks;
 import org.apache.ignite.IgniteException;
 import org.apache.ignite.IgniteLogger;
 import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion;
@@ -40,11 +36,11 @@ import 
org.apache.ignite.internal.processors.query.calcite.exec.exp.ExpressionFa
 import 
org.apache.ignite.internal.processors.query.calcite.metadata.ColocationGroup;
 import 
org.apache.ignite.internal.processors.query.calcite.metadata.FragmentDescription;
 import 
org.apache.ignite.internal.processors.query.calcite.prepare.AbstractQueryContext;
+import 
org.apache.ignite.internal.processors.query.calcite.prepare.BaseDataContext;
 import 
org.apache.ignite.internal.processors.query.calcite.prepare.BaseQueryContext;
 import 
org.apache.ignite.internal.processors.query.calcite.type.IgniteTypeFactory;
 import org.apache.ignite.internal.processors.query.calcite.util.Commons;
 import org.apache.ignite.internal.processors.query.calcite.util.TypeUtils;
-import org.apache.ignite.internal.util.typedef.internal.U;
 import org.jetbrains.annotations.NotNull;
 
 import static 
org.apache.ignite.internal.processors.query.calcite.util.Commons.checkRange;
@@ -54,16 +50,6 @@ import static 
org.apache.ignite.internal.processors.query.calcite.util.Commons.c
  */
 public class ExecutionContext<Row> extends AbstractQueryContext implements 
DataContext {
     /** */
-    private final TimeZone timeZone = TimeZone.getDefault(); // TODO 
DistributedSqlConfiguration#timeZone
-
-    /** */
-    private static final SchemaPlus DFLT_SCHEMA = 
Frameworks.createRootSchema(false);
-
-    /** */
-    // TODO https://issues.apache.org/jira/browse/IGNITE-15276 Support other 
locales.
-    private static final Locale LOCALE = Locale.ENGLISH;
-
-    /** */
     private final UUID qryId;
 
     /** */
@@ -93,11 +79,8 @@ public class ExecutionContext<Row> extends 
AbstractQueryContext implements DataC
     /** */
     private final AtomicBoolean cancelFlag = new AtomicBoolean();
 
-    /**
-     * Need to store timestamp, since SQL standard says that functions such as 
CURRENT_TIMESTAMP return the same value
-     * throughout the query.
-     */
-    private final long startTs;
+    /** */
+    private final BaseDataContext baseDataContext;
 
     /** */
     private Object[] correlations = new Object[16];
@@ -131,14 +114,13 @@ public class ExecutionContext<Row> extends 
AbstractQueryContext implements DataC
         this.handler = handler;
         this.params = params;
 
+        baseDataContext = new BaseDataContext(qctx.typeFactory());
+
         expressionFactory = new ExpressionFactoryImpl<>(
             this,
             qctx.typeFactory(),
             qctx.config().getParserConfig().conformance()
         );
-
-        long ts = U.currentTimeMillis();
-        startTs = ts + timeZone.getOffset(ts);
     }
 
     /**
@@ -228,35 +210,27 @@ public class ExecutionContext<Row> extends 
AbstractQueryContext implements DataC
 
     /** {@inheritDoc} */
     @Override public SchemaPlus getRootSchema() {
-        return DFLT_SCHEMA;
+        return baseDataContext.getRootSchema();
     }
 
     /** {@inheritDoc} */
     @Override public IgniteTypeFactory getTypeFactory() {
-        return unwrap(BaseQueryContext.class).typeFactory();
+        return baseDataContext.getTypeFactory();
     }
 
     /** {@inheritDoc} */
     @Override public QueryProvider getQueryProvider() {
-        return null; // TODO
+        return baseDataContext.getQueryProvider();
     }
 
     /** {@inheritDoc} */
     @Override public Object get(String name) {
         if (Variable.CANCEL_FLAG.camelName.equals(name))
             return cancelFlag;
-        if (Variable.TIME_ZONE.camelName.equals(name))
-            return timeZone; // TODO DistributedSqlConfiguration#timeZone
-        if (Variable.CURRENT_TIMESTAMP.camelName.equals(name))
-            return startTs;
-        if (Variable.LOCAL_TIMESTAMP.camelName.equals(name))
-            return startTs;
-        if (Variable.LOCALE.camelName.equals(name))
-            return LOCALE;
         if (name.startsWith("?"))
             return TypeUtils.toInternal(this, params.get(name));
 
-        return params.get(name);
+        return baseDataContext.get(name);
     }
 
     /**
diff --git 
a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/exp/RexImpTable.java
 
b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/exp/RexImpTable.java
index 9b8a77d..6c8ae50 100644
--- 
a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/exp/RexImpTable.java
+++ 
b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/exp/RexImpTable.java
@@ -253,6 +253,9 @@ public class RexImpTable {
     /** */
     private final Map<SqlOperator, RexCallImplementor> map = new HashMap<>();
 
+    /** Placeholder for DEFAULT operator value. */
+    public static final Object DEFAULT_VALUE_PLACEHOLDER = new Object();
+
     /** */
     RexImpTable() {
         defineMethod(ROW, BuiltInMethod.ARRAY.method, NullPolicy.NONE);
@@ -2500,7 +2503,7 @@ public class RexImpTable {
         /** {@inheritDoc} */
         @Override Expression implementSafe(final RexToLixTranslator translator,
             final RexCall call, final List<Expression> argValueList) {
-            return Expressions.constant(null);
+            return Expressions.field(null, RexImpTable.class, 
"DEFAULT_VALUE_PLACEHOLDER");
         }
     }
 
diff --git 
a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/prepare/BaseDataContext.java
 
b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/prepare/BaseDataContext.java
new file mode 100644
index 0000000..720372d
--- /dev/null
+++ 
b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/prepare/BaseDataContext.java
@@ -0,0 +1,90 @@
+/*
+ * 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.processors.query.calcite.prepare;
+
+import java.util.Locale;
+import java.util.TimeZone;
+import org.apache.calcite.DataContext;
+import org.apache.calcite.linq4j.QueryProvider;
+import org.apache.calcite.schema.SchemaPlus;
+import org.apache.calcite.tools.Frameworks;
+import 
org.apache.ignite.internal.processors.query.calcite.type.IgniteTypeFactory;
+import org.apache.ignite.internal.util.typedef.internal.U;
+
+/**
+ * Base data context.
+ */
+public final class BaseDataContext implements DataContext {
+    /** */
+    // TODO https://issues.apache.org/jira/browse/IGNITE-15276 Should be 
configurable.
+    private final TimeZone timeZone = TimeZone.getDefault();
+
+    /** */
+    private static final SchemaPlus DFLT_SCHEMA = 
Frameworks.createRootSchema(false);
+
+    /** */
+    // TODO https://issues.apache.org/jira/browse/IGNITE-15276 Support other 
locales.
+    private static final Locale LOCALE = Locale.ENGLISH;
+
+    /**
+     * Need to store timestamp, since SQL standard says that functions such as 
CURRENT_TIMESTAMP return the same value
+     * throughout the query.
+     */
+    // TODO https://issues.apache.org/jira/browse/IGNITE-15276 Should be 
propagated from the initiator node.
+    private final long startTs;
+
+    /** */
+    private final IgniteTypeFactory typeFactory;
+
+    /** */
+    public BaseDataContext(IgniteTypeFactory typeFactory) {
+        this.typeFactory = typeFactory;
+
+        long ts = U.currentTimeMillis();
+        startTs = ts + timeZone.getOffset(ts);
+    }
+
+    /** {@inheritDoc} */
+    @Override public SchemaPlus getRootSchema() {
+        return DFLT_SCHEMA;
+    }
+
+    /** {@inheritDoc} */
+    @Override public IgniteTypeFactory getTypeFactory() {
+        return typeFactory;
+    }
+
+    /** {@inheritDoc} */
+    @Override public QueryProvider getQueryProvider() {
+        return null;
+    }
+
+    /** {@inheritDoc} */
+    @Override public Object get(String name) {
+        if (Variable.TIME_ZONE.camelName.equals(name))
+            return timeZone;
+        if (Variable.CURRENT_TIMESTAMP.camelName.equals(name))
+            return startTs;
+        if (Variable.LOCAL_TIMESTAMP.camelName.equals(name))
+            return startTs;
+        if (Variable.LOCALE.camelName.equals(name))
+            return LOCALE;
+
+        return null;
+    }
+}
diff --git 
a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/prepare/ddl/DdlSqlToCommandConverter.java
 
b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/prepare/ddl/DdlSqlToCommandConverter.java
index f728750..f0b029f 100644
--- 
a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/prepare/ddl/DdlSqlToCommandConverter.java
+++ 
b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/prepare/ddl/DdlSqlToCommandConverter.java
@@ -17,6 +17,7 @@
 
 package org.apache.ignite.internal.processors.query.calcite.prepare.ddl;
 
+import java.lang.reflect.Type;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashSet;
@@ -28,6 +29,7 @@ import java.util.function.BiFunction;
 import java.util.function.Function;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
+import org.apache.calcite.DataContext;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeField;
 import org.apache.calcite.sql.SqlDdl;
@@ -45,6 +47,7 @@ import org.apache.ignite.cache.CacheWriteSynchronizationMode;
 import org.apache.ignite.internal.processors.cache.query.IgniteQueryErrorCode;
 import org.apache.ignite.internal.processors.query.IgniteSQLException;
 import org.apache.ignite.internal.processors.query.QueryUtils;
+import 
org.apache.ignite.internal.processors.query.calcite.prepare.BaseDataContext;
 import 
org.apache.ignite.internal.processors.query.calcite.prepare.IgnitePlanner;
 import 
org.apache.ignite.internal.processors.query.calcite.prepare.PlanningContext;
 import 
org.apache.ignite.internal.processors.query.calcite.prepare.ValidationResult;
@@ -53,6 +56,7 @@ import 
org.apache.ignite.internal.processors.query.calcite.sql.IgniteSqlAlterTab
 import 
org.apache.ignite.internal.processors.query.calcite.sql.IgniteSqlCreateTable;
 import 
org.apache.ignite.internal.processors.query.calcite.sql.IgniteSqlCreateTableOption;
 import 
org.apache.ignite.internal.processors.query.calcite.sql.IgniteSqlCreateTableOptionEnum;
+import org.apache.ignite.internal.processors.query.calcite.util.TypeUtils;
 import org.apache.ignite.internal.util.typedef.F;
 
 import static org.apache.calcite.sql.type.SqlTypeName.BOOLEAN;
@@ -189,8 +193,15 @@ public class DdlSqlToCommandConverter {
                 RelDataType type = planner.convert(col.dataType);
 
                 Object dflt = null;
-                if (col.expression != null)
-                    dflt = ((SqlLiteral)col.expression).getValue();
+                if (col.expression != null) {
+                    assert col.expression instanceof SqlLiteral;
+
+                    Type storageType = ctx.typeFactory().getResultClass(type);
+
+                    DataContext dataCtx = new 
BaseDataContext(ctx.typeFactory());
+
+                    dflt = TypeUtils.fromLiteral(dataCtx, storageType, 
(SqlLiteral)col.expression);
+                }
 
                 cols.add(new ColumnDefinition(name, type, dflt));
             }
diff --git 
a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/schema/TableDescriptorImpl.java
 
b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/schema/TableDescriptorImpl.java
index 633cf8d..d0d5129 100644
--- 
a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/schema/TableDescriptorImpl.java
+++ 
b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/schema/TableDescriptorImpl.java
@@ -27,6 +27,8 @@ import java.util.Objects;
 import java.util.Set;
 import java.util.UUID;
 import java.util.stream.Collectors;
+
+import org.apache.calcite.DataContext;
 import org.apache.calcite.plan.RelOptTable;
 import org.apache.calcite.rel.core.TableModify;
 import org.apache.calcite.rel.type.RelDataType;
@@ -55,7 +57,9 @@ import 
org.apache.ignite.internal.processors.query.GridQueryTypeDescriptor;
 import org.apache.ignite.internal.processors.query.QueryUtils;
 import 
org.apache.ignite.internal.processors.query.calcite.exec.ExecutionContext;
 import org.apache.ignite.internal.processors.query.calcite.exec.RowHandler;
+import 
org.apache.ignite.internal.processors.query.calcite.exec.exp.RexImpTable;
 import 
org.apache.ignite.internal.processors.query.calcite.metadata.ColocationGroup;
+import 
org.apache.ignite.internal.processors.query.calcite.prepare.BaseDataContext;
 import 
org.apache.ignite.internal.processors.query.calcite.prepare.MappingQueryContext;
 import 
org.apache.ignite.internal.processors.query.calcite.trait.IgniteDistribution;
 import 
org.apache.ignite.internal.processors.query.calcite.trait.IgniteDistributions;
@@ -301,7 +305,11 @@ public class TableDescriptorImpl extends 
NullInitializerExpressionFactory
         final RexBuilder rexBuilder = ctx.getRexBuilder();
         final IgniteTypeFactory typeFactory = 
(IgniteTypeFactory)rexBuilder.getTypeFactory();
 
-        return rexBuilder.makeLiteral(desc.defaultValue(), 
desc.logicalType(typeFactory), false);
+        DataContext dataCtx = new BaseDataContext(typeFactory);
+
+        Object dfltVal = TypeUtils.toInternal(dataCtx, desc.defaultValue());
+
+        return rexBuilder.makeLiteral(dfltVal, desc.logicalType(typeFactory), 
false);
     }
 
     /** {@inheritDoc} */
@@ -345,8 +353,11 @@ public class TableDescriptorImpl extends 
NullInitializerExpressionFactory
 
         Object key = handler.get(keyField, row);
 
-        if (key != null)
+        if (key != null) {
+            key = replaceDefault(key, descriptors[QueryUtils.KEY_COL]);
+
             return TypeUtils.fromInternal(ectx, key, 
descriptors[QueryUtils.KEY_COL].storageType());
+        }
 
         // skip _key and _val
         for (int i = 2; i < descriptors.length; i++) {
@@ -355,7 +366,7 @@ public class TableDescriptorImpl extends 
NullInitializerExpressionFactory
             if (!desc.field() || !desc.key())
                 continue;
 
-            Object fieldVal = handler.get(i, row);
+            Object fieldVal = replaceDefault(handler.get(i, row), desc);
 
             if (fieldVal != null) {
                 if (key == null)
@@ -384,19 +395,27 @@ public class TableDescriptorImpl extends 
NullInitializerExpressionFactory
             for (int i = 2; i < descriptors.length; i++) {
                 final ColumnDescriptor desc = descriptors[i];
 
-                Object fieldVal = handler.get(i, row);
+                Object fieldVal = replaceDefault(handler.get(i, row), desc);
 
                 if (desc.field() && !desc.key() && fieldVal != null)
                     desc.set(val, TypeUtils.fromInternal(ectx, fieldVal, 
desc.storageType()));
             }
         }
-        else
+        else {
+            val = replaceDefault(val, descriptors[QueryUtils.VAL_COL]);
+
             val = TypeUtils.fromInternal(ectx, val, 
descriptors[QueryUtils.VAL_COL].storageType());
+        }
 
         return val;
     }
 
     /** */
+    private Object replaceDefault(Object val, ColumnDescriptor desc) {
+        return val == RexImpTable.DEFAULT_VALUE_PLACEHOLDER ? 
desc.defaultValue() : val;
+    }
+
+    /** */
     private Object newVal(String typeName, Class<?> typeCls) throws 
IgniteCheckedException {
         GridCacheContext<?, ?> cctx = cacheContext();
 
@@ -665,7 +684,7 @@ public class TableDescriptorImpl extends 
NullInitializerExpressionFactory
 
         /** {@inheritDoc} */
         @Override public RelDataType logicalType(IgniteTypeFactory f) {
-            return f.createJavaType(storageType);
+            return f.toSql(f.createJavaType(storageType));
         }
 
         /** {@inheritDoc} */
@@ -739,7 +758,7 @@ public class TableDescriptorImpl extends 
NullInitializerExpressionFactory
 
         /** {@inheritDoc} */
         @Override public RelDataType logicalType(IgniteTypeFactory f) {
-            return f.createJavaType(storageType);
+            return f.toSql(f.createJavaType(storageType));
         }
 
         /** {@inheritDoc} */
diff --git 
a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/sql/fun/IgniteStdSqlOperatorTable.java
 
b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/sql/fun/IgniteStdSqlOperatorTable.java
index 0f4e7dc..b947462 100644
--- 
a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/sql/fun/IgniteStdSqlOperatorTable.java
+++ 
b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/sql/fun/IgniteStdSqlOperatorTable.java
@@ -250,6 +250,7 @@ public class IgniteStdSqlOperatorTable extends 
ReflectiveSqlOperatorTable {
         register(SqlLibraryOperators.GREATEST);
         register(SqlLibraryOperators.COMPRESS);
         register(SqlStdOperatorTable.OCTET_LENGTH);
+        register(SqlStdOperatorTable.DEFAULT);
 
         // XML Operators.
         register(SqlLibraryOperators.EXTRACT_VALUE);
diff --git 
a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/util/TypeUtils.java
 
b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/util/TypeUtils.java
index a6e0376..bcba8bb 100644
--- 
a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/util/TypeUtils.java
+++ 
b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/util/TypeUtils.java
@@ -18,6 +18,8 @@
 package org.apache.ignite.internal.processors.query.calcite.util;
 
 import java.lang.reflect.Type;
+import java.sql.Date;
+import java.sql.Time;
 import java.sql.Timestamp;
 import java.time.Duration;
 import java.time.Period;
@@ -34,6 +36,7 @@ import com.google.common.collect.ImmutableSet;
 import org.apache.calcite.DataContext;
 import org.apache.calcite.avatica.util.ByteString;
 import org.apache.calcite.avatica.util.DateTimeUtils;
+import org.apache.calcite.linq4j.tree.Primitive;
 import org.apache.calcite.plan.RelOptSchema;
 import org.apache.calcite.plan.RelOptTable;
 import org.apache.calcite.plan.RelOptUtil;
@@ -42,9 +45,16 @@ import org.apache.calcite.rel.type.RelDataTypeFactory;
 import org.apache.calcite.rel.type.RelDataTypeFactoryImpl;
 import org.apache.calcite.rel.type.RelDataTypeField;
 import org.apache.calcite.runtime.SqlFunctions;
+import org.apache.calcite.sql.SqlIntervalLiteral;
+import org.apache.calcite.sql.SqlLiteral;
 import org.apache.calcite.sql.type.SqlTypeName;
 import org.apache.calcite.sql.type.SqlTypeUtil;
+import org.apache.calcite.util.DateString;
 import org.apache.calcite.util.Pair;
+import org.apache.calcite.util.TimeString;
+import org.apache.calcite.util.TimestampString;
+import org.apache.ignite.IgniteException;
+import org.apache.ignite.internal.processors.query.IgniteSQLException;
 import 
org.apache.ignite.internal.processors.query.calcite.exec.ExecutionContext;
 import org.apache.ignite.internal.processors.query.calcite.exec.RowHandler;
 import 
org.apache.ignite.internal.processors.query.calcite.schema.ColumnDescriptor;
@@ -54,6 +64,7 @@ import org.apache.ignite.internal.util.typedef.F;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
+import static 
org.apache.ignite.internal.processors.cache.query.IgniteQueryErrorCode.UNEXPECTED_ELEMENT_TYPE;
 import static 
org.apache.ignite.internal.processors.query.calcite.util.Commons.transform;
 
 /** */
@@ -260,22 +271,22 @@ public class TypeUtils {
     }
 
     /** */
-    public static Object toInternal(ExecutionContext<?> ectx, Object val) {
-        return val == null ? null : toInternal(ectx, val, val.getClass());
+    public static Object toInternal(DataContext ctx, Object val) {
+        return val == null ? null : toInternal(ctx, val, val.getClass());
     }
 
     /** */
-    public static Object toInternal(ExecutionContext<?> ectx, Object val, Type 
storageType) {
+    public static Object toInternal(DataContext ctx, Object val, Type 
storageType) {
         if (val == null)
             return null;
         else if (storageType == java.sql.Date.class)
-            return (int)(SqlFunctions.toLong((java.util.Date)val, 
DataContext.Variable.TIME_ZONE.get(ectx)) / DateTimeUtils.MILLIS_PER_DAY);
+            return (int)(SqlFunctions.toLong((java.util.Date)val, 
DataContext.Variable.TIME_ZONE.get(ctx)) / DateTimeUtils.MILLIS_PER_DAY);
         else if (storageType == java.sql.Time.class)
-            return (int)(SqlFunctions.toLong((java.util.Date)val, 
DataContext.Variable.TIME_ZONE.get(ectx)) % DateTimeUtils.MILLIS_PER_DAY);
+            return (int)(SqlFunctions.toLong((java.util.Date)val, 
DataContext.Variable.TIME_ZONE.get(ctx)) % DateTimeUtils.MILLIS_PER_DAY);
         else if (storageType == Timestamp.class)
-            return SqlFunctions.toLong((java.util.Date)val, 
DataContext.Variable.TIME_ZONE.get(ectx));
+            return SqlFunctions.toLong((java.util.Date)val, 
DataContext.Variable.TIME_ZONE.get(ctx));
         else if (storageType == java.util.Date.class)
-            return SqlFunctions.toLong((java.util.Date)val, 
DataContext.Variable.TIME_ZONE.get(ectx));
+            return SqlFunctions.toLong((java.util.Date)val, 
DataContext.Variable.TIME_ZONE.get(ctx));
         else if (storageType == Duration.class) {
             return TimeUnit.SECONDS.toMillis(((Duration)val).getSeconds())
                 + TimeUnit.NANOSECONDS.toMillis(((Duration)val).getNano());
@@ -289,17 +300,17 @@ public class TypeUtils {
     }
 
     /** */
-    public static Object fromInternal(ExecutionContext<?> ectx, Object val, 
Type storageType) {
+    public static Object fromInternal(DataContext ctx, Object val, Type 
storageType) {
         if (val == null)
             return null;
         else if (storageType == java.sql.Date.class && val instanceof Integer)
-            return new java.sql.Date(fromLocalTs(ectx, (Integer)val * 
DateTimeUtils.MILLIS_PER_DAY));
+            return new java.sql.Date(fromLocalTs(ctx, (Integer)val * 
DateTimeUtils.MILLIS_PER_DAY));
         else if (storageType == java.sql.Time.class && val instanceof Integer)
-            return new java.sql.Time(fromLocalTs(ectx, (Integer)val));
+            return new java.sql.Time(fromLocalTs(ctx, (Integer)val));
         else if (storageType == Timestamp.class && val instanceof Long)
-            return new Timestamp(fromLocalTs(ectx, (Long)val));
+            return new Timestamp(fromLocalTs(ctx, (Long)val));
         else if (storageType == java.util.Date.class && val instanceof Long)
-            return new java.util.Date(fromLocalTs(ectx, (Long)val));
+            return new java.util.Date(fromLocalTs(ctx, (Long)val));
         else if (storageType == Duration.class && val instanceof Long)
             return Duration.ofMillis((Long)val);
         else if (storageType == Period.class && val instanceof Integer)
@@ -310,9 +321,52 @@ public class TypeUtils {
             return val;
     }
 
+    /**
+     * Creates a value of required type from the literal.
+     */
+    public static Object fromLiteral(DataContext ctx, Type storageType, 
SqlLiteral literal) {
+        Object internalVal;
+
+        try {
+            storageType = Primitive.box(storageType); // getValueAs() 
implemented only for boxed classes.
+
+            if (Date.class.equals(storageType))
+                internalVal = 
literal.getValueAs(DateString.class).getDaysSinceEpoch();
+            else if (Time.class.equals(storageType))
+                internalVal = 
literal.getValueAs(TimeString.class).getMillisOfDay();
+            else if (Timestamp.class.equals(storageType))
+                internalVal = 
literal.getValueAs(TimestampString.class).getMillisSinceEpoch();
+            else if (Duration.class.equals(storageType)) {
+                if (literal instanceof SqlIntervalLiteral &&
+                    
!literal.getValueAs(SqlIntervalLiteral.IntervalValue.class).getIntervalQualifier().isYearMonth())
+                    internalVal = literal.getValueAs(Long.class);
+                else
+                    throw new IgniteException("Expected DAY-TIME interval 
literal");
+            }
+            else if (Period.class.equals(storageType))
+                if (literal instanceof SqlIntervalLiteral &&
+                    
literal.getValueAs(SqlIntervalLiteral.IntervalValue.class).getIntervalQualifier().isYearMonth())
+                    internalVal = literal.getValueAs(Long.class).intValue();
+                else
+                    throw new IgniteException("Expected YEAR-MONTH interval 
literal");
+            else {
+                if (storageType instanceof Class)
+                    internalVal = literal.getValueAs((Class<?>)storageType);
+                else
+                    throw new IgniteException("Unexpected storage type: " + 
storageType);
+            }
+        }
+        catch (Throwable t) { // Throwable is requred here, since Calcite 
throws Assertion error in case of type mismatch.
+            throw new IgniteSQLException("Cannot convert literal " + literal + 
" to type " + storageType,
+                UNEXPECTED_ELEMENT_TYPE, t);
+        }
+
+        return fromInternal(ctx, internalVal, storageType);
+    }
+
     /** */
-    private static long fromLocalTs(ExecutionContext<?> ectx, long ts) {
-        TimeZone tz = DataContext.Variable.TIME_ZONE.get(ectx);
+    private static long fromLocalTs(DataContext ctx, long ts) {
+        TimeZone tz = DataContext.Variable.TIME_ZONE.get(ctx);
 
         // Taking into account DST, offset can be changed after converting 
from UTC to time-zone.
         return ts - tz.getOffset(ts - tz.getOffset(ts));
diff --git 
a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/integration/TableDmlIntegrationTest.java
 
b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/integration/TableDmlIntegrationTest.java
index eca6b63..be3ee77 100644
--- 
a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/integration/TableDmlIntegrationTest.java
+++ 
b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/integration/TableDmlIntegrationTest.java
@@ -16,8 +16,15 @@
  */
 package org.apache.ignite.internal.processors.query.calcite.integration;
 
+import java.math.BigDecimal;
+import java.sql.Date;
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.time.Duration;
+import java.time.Period;
 import java.util.Arrays;
 import java.util.List;
+import java.util.Objects;
 import java.util.concurrent.ThreadLocalRandom;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.stream.Collectors;
@@ -427,4 +434,85 @@ public class TableDmlIntegrationTest extends 
AbstractBasicIntegrationTest {
             "WHEN NOT MATCHED THEN INSERT (a, b) VALUES (0, b)", 
IgniteSQLException.class,
             "Failed to MERGE some keys due to keys conflict");
     }
+
+    /** */
+    @Test
+    public void testInsertDefaultValue() {
+        checkDefaultValue("BOOLEAN", "TRUE", Boolean.TRUE);
+        checkDefaultValue("BOOLEAN NOT NULL", "TRUE", Boolean.TRUE);
+        checkDefaultValue("BIGINT", "10", 10L);
+        checkDefaultValue("INTEGER", "10", 10);
+        checkDefaultValue("SMALLINT", "10", (short)10);
+        checkDefaultValue("TINYINT", "10", (byte)10);
+        checkDefaultValue("DOUBLE", "10.01", 10.01d);
+        checkDefaultValue("FLOAT", "10.01", 10.01f);
+        checkDefaultValue("DECIMAL(4, 2)", "10.01", new BigDecimal("10.01"));
+        checkDefaultValue("CHAR(2)", "'10'", "10");
+        checkDefaultValue("VARCHAR", "'10'", "10");
+        checkDefaultValue("VARCHAR NOT NULL", "'10'", "10");
+        checkDefaultValue("VARCHAR(2)", "'10'", "10");
+        checkDefaultValue("INTERVAL DAYS TO SECONDS", "INTERVAL '10' DAYS", 
Duration.ofDays(10));
+        checkDefaultValue("INTERVAL YEARS TO MONTHS", "INTERVAL '10' MONTHS", 
Period.ofMonths(10));
+        checkDefaultValue("INTERVAL MONTHS", "INTERVAL '10' YEARS", 
Period.ofYears(10));
+        checkDefaultValue("DATE", "DATE '2021-01-01'", 
Date.valueOf("2021-01-01"));
+        checkDefaultValue("TIME", "TIME '01:01:01'", Time.valueOf("01:01:01"));
+        checkDefaultValue("TIMESTAMP", "TIMESTAMP '2021-01-01 01:01:01'", 
Timestamp.valueOf("2021-01-01 01:01:01"));
+        checkDefaultValue("BINARY(3)", "x'010203'", new byte[] {1, 2, 3});
+        checkDefaultValue("VARBINARY", "x'010203'", new byte[] {1, 2, 3});
+
+        checkWrongDefault("VARCHAR", "10");
+        checkWrongDefault("INT", "'10'");
+        checkWrongDefault("INT", "TRUE");
+        checkWrongDefault("DATE", "10");
+        checkWrongDefault("DATE", "TIME '01:01:01'");
+        checkWrongDefault("TIME", "TIMESTAMP '2021-01-01 01:01:01'");
+        checkWrongDefault("BOOLEAN", "1");
+        checkWrongDefault("INTERVAL DAYS", "INTERVAL '10' MONTHS");
+        checkWrongDefault("INTERVAL MONTHS", "INTERVAL '10' DAYS");
+        checkWrongDefault("VARBINARY", "'10'");
+        checkWrongDefault("VARBINARY", "10");
+    }
+
+    /** */
+    private void checkDefaultValue(String sqlType, String sqlVal, Object 
expectedVal) {
+        try {
+            executeSql("CREATE TABLE test (dummy INT, val " + sqlType + " 
DEFAULT " + sqlVal + ")");
+            executeSql("INSERT INTO test (dummy) VALUES (0)");
+
+            checkQueryResult("SELECT val FROM test", expectedVal);
+
+            executeSql("DELETE FROM test");
+            executeSql("INSERT INTO test (dummy, val) VALUES (0, DEFAULT)");
+
+            checkQueryResult("SELECT val FROM test", expectedVal);
+        }
+        finally {
+            executeSql("DROP TABLE IF EXISTS test");
+        }
+    }
+
+    /** */
+    private void checkQueryResult(String sql, Object expectedVal) {
+        if (expectedVal.getClass().isArray()) {
+            List<List<?>> res = executeSql(sql);
+
+            assertEquals(1, res.size());
+            assertEquals(1, res.get(0).size());
+            assertTrue("Expected: " + Arrays.deepToString(new Object[] 
{expectedVal}) + ", actual: " +
+                Arrays.deepToString(new Object[] {res.get(0).get(0)}), 
Objects.deepEquals(expectedVal, res.get(0).get(0)));
+        }
+        else
+            assertQuery(sql).returns(expectedVal).check();
+    }
+
+    /** */
+    private void checkWrongDefault(String sqlType, String sqlVal) {
+        try {
+            assertThrows("CREATE TABLE test (val " + sqlType + " DEFAULT " + 
sqlVal + ")",
+                IgniteSQLException.class, "Cannot convert literal");
+        }
+        finally {
+            executeSql("DROP TABLE IF EXISTS test");
+        }
+    }
 }
diff --git 
a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/jdbc/JdbcCrossEngineTest.java
 
b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/jdbc/JdbcCrossEngineTest.java
new file mode 100644
index 0000000..c5430fc
--- /dev/null
+++ 
b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/jdbc/JdbcCrossEngineTest.java
@@ -0,0 +1,169 @@
+/*
+ * 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.processors.query.calcite.jdbc;
+
+import java.math.BigDecimal;
+import java.sql.Connection;
+import java.sql.Date;
+import java.sql.DriverManager;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.function.Consumer;
+import org.apache.ignite.IgniteException;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.junit.Test;
+
+/**
+ * Cross check queries on experimental and non-experimental SQL engines.
+ */
+public class JdbcCrossEngineTest extends GridCommonAbstractTest {
+    /** URL. */
+    private static final String url = 
"jdbc:ignite:thin://127.0.0.1?useExperimentalQueryEngine=";
+
+    /** Nodes count. */
+    private static final int nodesCnt = 3;
+
+    /** Connections. */
+    private final Connection[] conns = new Connection[2];
+
+    /** Statements. */
+    private final Statement[] stmts = new Statement[2];
+
+    /** {@inheritDoc} */
+    @Override protected void beforeTest() throws Exception {
+        startGrids(nodesCnt);
+
+        for (int i = 0; i < conns.length; i++) {
+            conns[i] = DriverManager.getConnection(url + (i == 0 ? "false" : 
"true"));
+            conns[i].setSchema("PUBLIC");
+            stmts[i] = conns[i].createStatement();
+
+            assert stmts[i] != null;
+            assert !stmts[i].isClosed();
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void afterTest() throws Exception {
+        for (int i = 0; i < conns.length; i++) {
+            if (stmts[i] != null && !stmts[i].isClosed()) {
+                stmts[i].close();
+
+                assert stmts[i].isClosed();
+            }
+
+            conns[i].close();
+
+            assert stmts[i].isClosed();
+            assert conns[i].isClosed();
+        }
+
+        stopAllGrids();
+    }
+
+    /** */
+    @Test
+    public void testInsertDefaultValue() {
+        // Test only types supported by both SQL engines.
+        checkInsertDefaultValue("BOOLEAN", "TRUE", Boolean.TRUE);
+        checkInsertDefaultValue("BOOLEAN NOT NULL", "TRUE", Boolean.TRUE);
+        checkInsertDefaultValue("BIGINT", "10", 10L);
+        checkInsertDefaultValue("INTEGER", "10", 10);
+        checkInsertDefaultValue("SMALLINT", "10", (short)10);
+        checkInsertDefaultValue("TINYINT", "10", (byte)10);
+        checkInsertDefaultValue("DOUBLE", "10.01", 10.01d);
+        checkInsertDefaultValue("REAL", "10.01", 10.01f);
+        checkInsertDefaultValue("DECIMAL(4, 2)", "10.01", new 
BigDecimal("10.01"));
+        checkInsertDefaultValue("CHAR(2)", "'10'", "10");
+        checkInsertDefaultValue("VARCHAR", "'10'", "10");
+        checkInsertDefaultValue("VARCHAR NOT NULL", "'10'", "10");
+        checkInsertDefaultValue("VARCHAR(2)", "'10'", "10");
+        checkInsertDefaultValue("DATE", "DATE '2021-01-01'", 
Date.valueOf("2021-01-01"));
+        checkInsertDefaultValue("TIME", "TIME '01:01:01'", 
Time.valueOf("01:01:01"));
+        checkInsertDefaultValue("TIMESTAMP", "TIMESTAMP '2021-01-01 
01:01:01'", Timestamp.valueOf("2021-01-01 01:01:01"));
+        checkInsertDefaultValue("BINARY(3)", "x'010203'", new byte[] {1, 2, 
3});
+    }
+
+    /** */
+    private void checkInsertDefaultValue(String sqlType, String sqlVal, Object 
expectedVal) {
+        crossCheck(
+            stmt -> execute(stmt, "CREATE TABLE test (id INT PRIMARY KEY, val 
" + sqlType + " DEFAULT " + sqlVal + ")"),
+            stmt -> {
+                try {
+                    execute(stmt, "INSERT INTO test (id) VALUES (0)");
+
+                    List<List<Object>> res = executeQuery(stmt, "SELECT val 
FROM test");
+
+                    if (expectedVal.getClass().isArray())
+                        assertTrue(Objects.deepEquals(expectedVal, 
res.get(0).get(0)));
+                    else
+                        assertEquals(expectedVal, res.get(0).get(0));
+                }
+                finally {
+                    execute(stmt, "DROP TABLE IF EXISTS test");
+                }
+            }
+        );
+    }
+
+    /** */
+    private void execute(Statement stmt, String sql) {
+        try {
+            stmt.execute(sql);
+        }
+        catch (SQLException e) {
+            throw new IgniteException(e.getMessage(), e);
+        }
+    }
+
+    /** */
+    private List<List<Object>> executeQuery(Statement stmt, String sql) {
+        try (ResultSet rs = stmt.executeQuery(sql)) {
+            List<List<Object>> res = new ArrayList<>();
+            while (rs.next()) {
+                List<Object> row = new ArrayList<>();
+
+                for (int i = 1; i <= rs.getMetaData().getColumnCount(); i++)
+                    row.add(rs.getObject(i));
+
+                res.add(row);
+            }
+
+            return res;
+        }
+        catch (SQLException e) {
+            throw new IgniteException(e.getMessage(), e);
+        }
+    }
+
+    /** */
+    private void crossCheck(Consumer<Statement> consumer1, Consumer<Statement> 
consumer2) {
+        // Execute consumer1 on non-experimental engine, consumer2 in 
experimental engine.
+        consumer1.accept(stmts[0]);
+        consumer2.accept(stmts[1]);
+        // Execute consumer1 on non-experimental engine, consumer2 in 
experimental engine.
+        consumer1.accept(stmts[1]);
+        consumer2.accept(stmts[0]);
+    }
+}
diff --git 
a/modules/calcite/src/test/java/org/apache/ignite/testsuites/IntegrationTestSuite.java
 
b/modules/calcite/src/test/java/org/apache/ignite/testsuites/IntegrationTestSuite.java
index a859aaa..580a2e9 100644
--- 
a/modules/calcite/src/test/java/org/apache/ignite/testsuites/IntegrationTestSuite.java
+++ 
b/modules/calcite/src/test/java/org/apache/ignite/testsuites/IntegrationTestSuite.java
@@ -44,6 +44,7 @@ import 
org.apache.ignite.internal.processors.query.calcite.integration.TableDdlI
 import 
org.apache.ignite.internal.processors.query.calcite.integration.TableDmlIntegrationTest;
 import 
org.apache.ignite.internal.processors.query.calcite.integration.UserDdlIntegrationTest;
 import 
org.apache.ignite.internal.processors.query.calcite.integration.UserDefinedFunctionsIntegrationTest;
+import 
org.apache.ignite.internal.processors.query.calcite.jdbc.JdbcCrossEngineTest;
 import org.apache.ignite.internal.processors.query.calcite.jdbc.JdbcQueryTest;
 import 
org.apache.ignite.internal.processors.query.calcite.rules.JoinCommuteRulesTest;
 import 
org.apache.ignite.internal.processors.query.calcite.rules.OrToUnionRuleTest;
@@ -61,6 +62,7 @@ import org.junit.runners.Suite;
     CalciteQueryProcessorTest.class,
     CalciteErrorHandlilngIntegrationTest.class,
     JdbcQueryTest.class,
+    JdbcCrossEngineTest.class,
     CalciteBasicSecondaryIndexIntegrationTest.class,
     CancelTest.class,
     DateTimeTest.class,

Reply via email to