You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by al...@apache.org on 2021/11/23 13:02:39 UTC

[ignite] branch sql-calcite updated: IGNITE-15128 Take own control of SQL operators - Fixes #9428.

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 55f2288  IGNITE-15128 Take own control of SQL operators - Fixes #9428.
55f2288 is described below

commit 55f2288e90a70dfa8995d6b4ef7012e2422171fc
Author: Aleksey Plekhanov <pl...@gmail.com>
AuthorDate: Tue Nov 23 15:50:36 2021 +0300

    IGNITE-15128 Take own control of SQL operators - Fixes #9428.
    
    Signed-off-by: Aleksey Plekhanov <pl...@gmail.com>
---
 modules/calcite/src/main/codegen/config.fmpp       |   4 +-
 .../query/calcite/CalciteQueryProcessor.java       |  14 +-
 .../query/calcite/exec/exp/RexImpTable.java        |  74 +----
 .../calcite/prepare/IgniteConvertletTable.java     |   3 +
 ...orTable.java => IgniteOwnSqlOperatorTable.java} |  13 +-
 .../calcite/sql/fun/IgniteStdSqlOperatorTable.java | 289 ++++++++++++++++++
 .../query/calcite/StdSqlOperatorsTest.java         | 335 +++++++++++++++++++++
 .../query/calcite/planner/PlannerTest.java         |   2 +-
 .../ignite/testsuites/IntegrationTestSuite.java    |   2 +
 9 files changed, 655 insertions(+), 81 deletions(-)

diff --git a/modules/calcite/src/main/codegen/config.fmpp b/modules/calcite/src/main/codegen/config.fmpp
index 86ad11c..ac925dc 100644
--- a/modules/calcite/src/main/codegen/config.fmpp
+++ b/modules/calcite/src/main/codegen/config.fmpp
@@ -202,7 +202,7 @@ data: {
 #     "CURSOR"
       "CYCLE"
       "DATA"
-#     "DATE"
+      "DATE"
       "DAY"
       "DEALLOCATE"
       "DEC"
@@ -425,6 +425,7 @@ data: {
       "PRIVILEGES"
       "PROCEDURE"
       "PUBLIC"
+      "QUARTER"
 #     "RANGE"
       "RANK"
       "READ"
@@ -558,6 +559,7 @@ data: {
       "VERSIONING"
 #     "VERSIONS" # not a keyword in Calcite
       "VIEW"
+      "WEEK"
 #     "WHEN"
       "WHENEVER"
 #     "WHERE"
diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/CalciteQueryProcessor.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/CalciteQueryProcessor.java
index 98042d4..049aff6 100644
--- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/CalciteQueryProcessor.java
+++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/CalciteQueryProcessor.java
@@ -34,8 +34,6 @@ import org.apache.calcite.rel.hint.HintStrategyTable;
 import org.apache.calcite.schema.SchemaPlus;
 import org.apache.calcite.sql.SqlNode;
 import org.apache.calcite.sql.SqlNodeList;
-import org.apache.calcite.sql.fun.SqlLibrary;
-import org.apache.calcite.sql.fun.SqlLibraryOperatorTableFactory;
 import org.apache.calcite.sql.parser.SqlParser;
 import org.apache.calcite.sql.util.SqlOperatorTables;
 import org.apache.calcite.sql.validate.SqlValidator;
@@ -79,7 +77,8 @@ import org.apache.ignite.internal.processors.query.calcite.schema.SchemaHolder;
 import org.apache.ignite.internal.processors.query.calcite.schema.SchemaHolderImpl;
 import org.apache.ignite.internal.processors.query.calcite.sql.IgniteSqlConformance;
 import org.apache.ignite.internal.processors.query.calcite.sql.IgniteSqlParserImpl;
-import org.apache.ignite.internal.processors.query.calcite.sql.fun.IgniteSqlOperatorTable;
+import org.apache.ignite.internal.processors.query.calcite.sql.fun.IgniteOwnSqlOperatorTable;
+import org.apache.ignite.internal.processors.query.calcite.sql.fun.IgniteStdSqlOperatorTable;
 import org.apache.ignite.internal.processors.query.calcite.trait.CorrelationTraitDef;
 import org.apache.ignite.internal.processors.query.calcite.trait.DistributionTraitDef;
 import org.apache.ignite.internal.processors.query.calcite.trait.RewindabilityTraitDef;
@@ -121,14 +120,7 @@ public class CalciteQueryProcessor extends GridProcessorAdapter implements Query
             .withSqlConformance(IgniteSqlConformance.INSTANCE)
             .withTypeCoercionFactory(IgniteTypeCoercion::new))
         // Dialects support.
-        .operatorTable(SqlOperatorTables.chain(
-            SqlLibraryOperatorTableFactory.INSTANCE
-                .getOperatorTable(
-                    SqlLibrary.STANDARD,
-                    SqlLibrary.POSTGRESQL,
-                    SqlLibrary.ORACLE,
-                    SqlLibrary.MYSQL),
-            IgniteSqlOperatorTable.instance()))
+        .operatorTable(SqlOperatorTables.chain(IgniteStdSqlOperatorTable.INSTANCE, IgniteOwnSqlOperatorTable.instance()))
         // Context provides a way to store data within the planner session that can be accessed in planner rules.
         .context(Contexts.empty())
         // Custom cost factory to use during optimization
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 63f2d9f..ca9da6b 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
@@ -30,7 +30,6 @@ import java.util.List;
 import java.util.Map;
 import java.util.function.Supplier;
 import java.util.stream.Collectors;
-
 import com.google.common.collect.ImmutableList;
 import org.apache.calcite.adapter.enumerable.EnumUtils;
 import org.apache.calcite.adapter.enumerable.NullPolicy;
@@ -89,7 +88,6 @@ import static org.apache.calcite.linq4j.tree.ExpressionType.Subtract;
 import static org.apache.calcite.linq4j.tree.ExpressionType.UnaryPlus;
 import static org.apache.calcite.sql.fun.SqlLibraryOperators.CHR;
 import static org.apache.calcite.sql.fun.SqlLibraryOperators.COMPRESS;
-import static org.apache.calcite.sql.fun.SqlLibraryOperators.CONCAT2;
 import static org.apache.calcite.sql.fun.SqlLibraryOperators.CONCAT_FUNCTION;
 import static org.apache.calcite.sql.fun.SqlLibraryOperators.COSH;
 import static org.apache.calcite.sql.fun.SqlLibraryOperators.DATE;
@@ -142,26 +140,19 @@ import static org.apache.calcite.sql.fun.SqlStdOperatorTable.CARDINALITY;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.CAST;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.CBRT;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.CEIL;
-import static org.apache.calcite.sql.fun.SqlStdOperatorTable.CHARACTER_LENGTH;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.CHAR_LENGTH;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.COALESCE;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.CONCAT;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.COS;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.COT;
-import static org.apache.calcite.sql.fun.SqlStdOperatorTable.CURRENT_CATALOG;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.CURRENT_DATE;
-import static org.apache.calcite.sql.fun.SqlStdOperatorTable.CURRENT_PATH;
-import static org.apache.calcite.sql.fun.SqlStdOperatorTable.CURRENT_ROLE;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.CURRENT_TIME;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.CURRENT_TIMESTAMP;
-import static org.apache.calcite.sql.fun.SqlStdOperatorTable.CURRENT_USER;
-import static org.apache.calcite.sql.fun.SqlStdOperatorTable.CURRENT_VALUE;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.DATETIME_PLUS;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.DEFAULT;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.DEGREES;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.DIVIDE;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.DIVIDE_INTEGER;
-import static org.apache.calcite.sql.fun.SqlStdOperatorTable.ELEMENT;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.EQUALS;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.EXP;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.EXTRACT;
@@ -169,14 +160,12 @@ import static org.apache.calcite.sql.fun.SqlStdOperatorTable.FLOOR;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.GREATER_THAN;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.GREATER_THAN_OR_EQUAL;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.INITCAP;
-import static org.apache.calcite.sql.fun.SqlStdOperatorTable.IS_A_SET;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.IS_EMPTY;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.IS_FALSE;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.IS_JSON_ARRAY;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.IS_JSON_OBJECT;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.IS_JSON_SCALAR;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.IS_JSON_VALUE;
-import static org.apache.calcite.sql.fun.SqlStdOperatorTable.IS_NOT_A_SET;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.IS_NOT_EMPTY;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.IS_NOT_FALSE;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.IS_NOT_JSON_ARRAY;
@@ -204,23 +193,14 @@ import static org.apache.calcite.sql.fun.SqlStdOperatorTable.LOCALTIMESTAMP;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.LOG10;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.LOWER;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.MAP_VALUE_CONSTRUCTOR;
-import static org.apache.calcite.sql.fun.SqlStdOperatorTable.MEMBER_OF;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.MINUS;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.MINUS_DATE;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.MOD;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.MULTIPLY;
-import static org.apache.calcite.sql.fun.SqlStdOperatorTable.MULTISET_EXCEPT;
-import static org.apache.calcite.sql.fun.SqlStdOperatorTable.MULTISET_EXCEPT_DISTINCT;
-import static org.apache.calcite.sql.fun.SqlStdOperatorTable.MULTISET_INTERSECT;
-import static org.apache.calcite.sql.fun.SqlStdOperatorTable.MULTISET_INTERSECT_DISTINCT;
-import static org.apache.calcite.sql.fun.SqlStdOperatorTable.MULTISET_UNION;
-import static org.apache.calcite.sql.fun.SqlStdOperatorTable.MULTISET_UNION_DISTINCT;
-import static org.apache.calcite.sql.fun.SqlStdOperatorTable.NEXT_VALUE;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.NOT;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.NOT_EQUALS;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.NOT_LIKE;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.NOT_SIMILAR_TO;
-import static org.apache.calcite.sql.fun.SqlStdOperatorTable.NOT_SUBMULTISET_OF;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.OR;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.OVERLAY;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.PI;
@@ -234,25 +214,18 @@ import static org.apache.calcite.sql.fun.SqlStdOperatorTable.REINTERPRET;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.REPLACE;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.ROUND;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.ROW;
-import static org.apache.calcite.sql.fun.SqlStdOperatorTable.SESSION_USER;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.SIGN;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.SIMILAR_TO;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.SIN;
-import static org.apache.calcite.sql.fun.SqlStdOperatorTable.SLICE;
-import static org.apache.calcite.sql.fun.SqlStdOperatorTable.STRUCT_ACCESS;
-import static org.apache.calcite.sql.fun.SqlStdOperatorTable.SUBMULTISET_OF;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.SUBSTRING;
-import static org.apache.calcite.sql.fun.SqlStdOperatorTable.SYSTEM_USER;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.TAN;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.TRIM;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.TRUNCATE;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.UNARY_MINUS;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.UNARY_PLUS;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.UPPER;
-import static org.apache.calcite.sql.fun.SqlStdOperatorTable.USER;
-import static org.apache.ignite.internal.processors.query.calcite.sql.fun.IgniteSqlOperatorTable.LENGTH;
-import static org.apache.ignite.internal.processors.query.calcite.sql.fun.IgniteSqlOperatorTable.SYSTEM_RANGE;
-import static org.apache.ignite.internal.processors.query.calcite.sql.fun.IgniteSqlOperatorTable.TYPEOF;
+import static org.apache.ignite.internal.processors.query.calcite.sql.fun.IgniteOwnSqlOperatorTable.SYSTEM_RANGE;
+import static org.apache.ignite.internal.processors.query.calcite.sql.fun.IgniteOwnSqlOperatorTable.TYPEOF;
 
 /**
  * Contains implementations of Rex operators as Java code.
@@ -295,12 +268,9 @@ public class RexImpTable {
         defineMethod(REPLACE, BuiltInMethod.REPLACE.method, NullPolicy.STRICT);
         defineMethod(TRANSLATE3, BuiltInMethod.TRANSLATE3.method, NullPolicy.STRICT);
         defineMethod(CHR, "chr", NullPolicy.STRICT);
-        defineMethod(CHARACTER_LENGTH, BuiltInMethod.CHAR_LENGTH.method, NullPolicy.STRICT);
         defineMethod(CHAR_LENGTH, BuiltInMethod.CHAR_LENGTH.method, NullPolicy.STRICT);
-        defineMethod(LENGTH, BuiltInMethod.CHAR_LENGTH.method, NullPolicy.STRICT);
         defineMethod(CONCAT, BuiltInMethod.STRING_CONCAT.method, NullPolicy.STRICT);
         defineMethod(CONCAT_FUNCTION, BuiltInMethod.MULTI_STRING_CONCAT.method, NullPolicy.STRICT);
-        defineMethod(CONCAT2, BuiltInMethod.STRING_CONCAT.method, NullPolicy.STRICT);
         defineMethod(OVERLAY, BuiltInMethod.OVERLAY.method, NullPolicy.STRICT);
         defineMethod(POSITION, BuiltInMethod.POSITION.method, NullPolicy.STRICT);
         defineMethod(ASCII, BuiltInMethod.ASCII.method, NullPolicy.STRICT);
@@ -435,15 +405,18 @@ public class RexImpTable {
         // Multisets & arrays
         defineMethod(CARDINALITY, BuiltInMethod.COLLECTION_SIZE.method,
             NullPolicy.STRICT);
-        defineMethod(SLICE, BuiltInMethod.SLICE.method, NullPolicy.NONE);
-        defineMethod(ELEMENT, BuiltInMethod.ELEMENT.method, NullPolicy.STRICT);
-        defineMethod(STRUCT_ACCESS, BuiltInMethod.STRUCT_ACCESS.method, NullPolicy.ANY);
-        defineMethod(MEMBER_OF, BuiltInMethod.MEMBER_OF.method, NullPolicy.NONE);
         final MethodImplementor isEmptyImplementor =
             new MethodImplementor(BuiltInMethod.IS_EMPTY.method, NullPolicy.NONE,
                 false);
         map.put(IS_EMPTY, isEmptyImplementor);
         map.put(IS_NOT_EMPTY, NotImplementor.of(isEmptyImplementor));
+
+        // TODO https://issues.apache.org/jira/browse/IGNITE-15551
+/*
+        defineMethod(SLICE, BuiltInMethod.SLICE.method, NullPolicy.NONE);
+        defineMethod(ELEMENT, BuiltInMethod.ELEMENT.method, NullPolicy.STRICT);
+        defineMethod(STRUCT_ACCESS, BuiltInMethod.STRUCT_ACCESS.method, NullPolicy.ANY);
+        defineMethod(MEMBER_OF, BuiltInMethod.MEMBER_OF.method, NullPolicy.NONE);
         final MethodImplementor isASetImplementor =
             new MethodImplementor(BuiltInMethod.IS_A_SET.method, NullPolicy.NONE,
                 false);
@@ -463,6 +436,7 @@ public class RexImpTable {
             new MethodImplementor(BuiltInMethod.SUBMULTISET_OF.method, NullPolicy.NONE, false);
         map.put(SUBMULTISET_OF, subMultisetImplementor);
         map.put(NOT_SUBMULTISET_OF, NotImplementor.of(subMultisetImplementor));
+*/
 
         map.put(COALESCE, new CoalesceImplementor());
         map.put(CAST, new CastImplementor());
@@ -477,12 +451,6 @@ public class RexImpTable {
 
         map.put(DEFAULT, new DefaultImplementor());
 
-        // Sequences
-        defineMethod(CURRENT_VALUE, BuiltInMethod.SEQUENCE_CURRENT_VALUE.method,
-            NullPolicy.STRICT);
-        defineMethod(NEXT_VALUE, BuiltInMethod.SEQUENCE_NEXT_VALUE.method,
-            NullPolicy.STRICT);
-
         // Compression Operators
         defineMethod(COMPRESS, BuiltInMethod.COMPRESS.method, NullPolicy.ARG0);
 
@@ -539,13 +507,6 @@ public class RexImpTable {
 
         // System functions
         final SystemFunctionImplementor systemFunctionImplementor = new SystemFunctionImplementor();
-        map.put(USER, systemFunctionImplementor);
-        map.put(CURRENT_USER, systemFunctionImplementor);
-        map.put(SESSION_USER, systemFunctionImplementor);
-        map.put(SYSTEM_USER, systemFunctionImplementor);
-        map.put(CURRENT_PATH, systemFunctionImplementor);
-        map.put(CURRENT_ROLE, systemFunctionImplementor);
-        map.put(CURRENT_CATALOG, systemFunctionImplementor);
         map.put(SYSTEM_RANGE, systemFunctionImplementor);
 
         // Current time functions
@@ -1698,20 +1659,7 @@ public class RexImpTable {
             final RexCall call, final List<Expression> argValueList) {
             final SqlOperator op = call.getOperator();
             final Expression root = translator.getRoot();
-            if (op == CURRENT_USER
-                || op == SESSION_USER
-                || op == USER)
-                return Expressions.call(BuiltInMethod.USER.method, root);
-            else if (op == SYSTEM_USER)
-                return Expressions.call(BuiltInMethod.SYSTEM_USER.method, root);
-            else if (op == CURRENT_PATH
-                || op == CURRENT_ROLE
-                || op == CURRENT_CATALOG) {
-                // By default, the CURRENT_ROLE and CURRENT_CATALOG functions return the
-                // empty string because a role or a catalog has to be set explicitly.
-                return Expressions.constant("");
-            }
-            else if (op == CURRENT_TIMESTAMP)
+            if (op == CURRENT_TIMESTAMP)
                 return Expressions.call(BuiltInMethod.CURRENT_TIMESTAMP.method, root);
             else if (op == CURRENT_TIME)
                 return Expressions.call(BuiltInMethod.CURRENT_TIME.method, root);
diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/prepare/IgniteConvertletTable.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/prepare/IgniteConvertletTable.java
index 39ff956..235c6d0 100644
--- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/prepare/IgniteConvertletTable.java
+++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/prepare/IgniteConvertletTable.java
@@ -36,6 +36,7 @@ import org.apache.calcite.sql2rel.ReflectiveConvertletTable;
 import org.apache.calcite.sql2rel.SqlRexContext;
 import org.apache.calcite.sql2rel.SqlRexConvertlet;
 import org.apache.calcite.sql2rel.StandardConvertletTable;
+import org.apache.ignite.internal.processors.query.calcite.sql.fun.IgniteOwnSqlOperatorTable;
 import org.checkerframework.checker.nullness.qual.Nullable;
 
 /**
@@ -49,6 +50,8 @@ public class IgniteConvertletTable extends ReflectiveConvertletTable {
     private IgniteConvertletTable() {
         // Replace Calcite's convertlet with our own.
         registerOp(SqlStdOperatorTable.TIMESTAMP_DIFF, new TimestampDiffConvertlet());
+
+        addAlias(IgniteOwnSqlOperatorTable.LENGTH, SqlStdOperatorTable.CHAR_LENGTH);
     }
 
     /** {@inheritDoc} */
diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/sql/fun/IgniteSqlOperatorTable.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/sql/fun/IgniteOwnSqlOperatorTable.java
similarity index 83%
rename from modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/sql/fun/IgniteSqlOperatorTable.java
rename to modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/sql/fun/IgniteOwnSqlOperatorTable.java
index d4c2674..078e3a9 100644
--- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/sql/fun/IgniteSqlOperatorTable.java
+++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/sql/fun/IgniteOwnSqlOperatorTable.java
@@ -24,13 +24,16 @@ import org.apache.calcite.sql.type.ReturnTypes;
 import org.apache.calcite.sql.util.ReflectiveSqlOperatorTable;
 
 /**
- * Operator table that contains only Ignite-specific functions and operators.
+ * Operator table that contains Ignite own functions and operators.
+ *
+ * Implementors for operators should be added to
+ * {@link org.apache.ignite.internal.processors.query.calcite.exec.exp.RexImpTable}
  */
-public class IgniteSqlOperatorTable extends ReflectiveSqlOperatorTable {
+public class IgniteOwnSqlOperatorTable extends ReflectiveSqlOperatorTable {
     /**
      * The table of contains Ignite-specific operators.
      */
-    private static IgniteSqlOperatorTable instance;
+    private static IgniteOwnSqlOperatorTable instance;
 
     /**
      *
@@ -64,12 +67,12 @@ public class IgniteSqlOperatorTable extends ReflectiveSqlOperatorTable {
     /**
      * Returns the Ignite operator table, creating it if necessary.
      */
-    public static synchronized IgniteSqlOperatorTable instance() {
+    public static synchronized IgniteOwnSqlOperatorTable instance() {
         if (instance == null) {
             // Creates and initializes the standard operator table.
             // Uses two-phase construction, because we can't initialize the
             // table until the constructor of the sub-class has completed.
-            instance = new IgniteSqlOperatorTable();
+            instance = new IgniteOwnSqlOperatorTable();
             instance.init();
         }
         return instance;
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
new file mode 100644
index 0000000..3e5dcaa
--- /dev/null
+++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/sql/fun/IgniteStdSqlOperatorTable.java
@@ -0,0 +1,289 @@
+/*
+ * 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.sql.fun;
+
+import org.apache.calcite.sql.fun.SqlLibraryOperators;
+import org.apache.calcite.sql.fun.SqlStdOperatorTable;
+import org.apache.calcite.sql.util.ReflectiveSqlOperatorTable;
+import org.apache.ignite.internal.processors.query.calcite.exec.exp.RexImpTable;
+import org.apache.ignite.internal.processors.query.calcite.exec.exp.agg.Accumulators;
+import org.apache.ignite.internal.processors.query.calcite.prepare.IgniteConvertletTable;
+
+/**
+ * Operator table that contains subset of Calcite's library operators supported by Ignite.
+ *
+ * @see RexImpTable for functions and operators implementors.
+ * @see IgniteConvertletTable for functions and operators convertlets.
+ * @see Accumulators for aggregates implementors.
+ *
+ * Note: Actially we don't use reflective capabilities of ReflectiveSqlOperatorTable (init method never called), but
+ * this class have infrastructure to register operators manualy and for fast operators lookup, so it's handy to use it.
+ */
+public class IgniteStdSqlOperatorTable extends ReflectiveSqlOperatorTable {
+    /** Singleton instance. */
+    public static final IgniteStdSqlOperatorTable INSTANCE = new IgniteStdSqlOperatorTable();
+
+    /**
+     * Default constructor.
+     */
+    public IgniteStdSqlOperatorTable() {
+        // Set operators.
+        register(SqlStdOperatorTable.UNION);
+        register(SqlStdOperatorTable.UNION_ALL);
+        register(SqlStdOperatorTable.EXCEPT);
+        register(SqlStdOperatorTable.EXCEPT_ALL);
+        register(SqlStdOperatorTable.INTERSECT);
+        register(SqlStdOperatorTable.INTERSECT_ALL);
+
+        // Logical.
+        register(SqlStdOperatorTable.AND);
+        register(SqlStdOperatorTable.OR);
+        register(SqlStdOperatorTable.NOT);
+
+        // Comparisons.
+        register(SqlStdOperatorTable.LESS_THAN);
+        register(SqlStdOperatorTable.LESS_THAN_OR_EQUAL);
+        register(SqlStdOperatorTable.GREATER_THAN);
+        register(SqlStdOperatorTable.GREATER_THAN_OR_EQUAL);
+        register(SqlStdOperatorTable.EQUALS);
+        register(SqlStdOperatorTable.NOT_EQUALS);
+        register(SqlStdOperatorTable.BETWEEN);
+        register(SqlStdOperatorTable.NOT_BETWEEN);
+
+        // Arithmetic.
+        register(SqlStdOperatorTable.PLUS);
+        register(SqlStdOperatorTable.MINUS);
+        register(SqlStdOperatorTable.MULTIPLY);
+        register(SqlStdOperatorTable.DIVIDE);
+        register(SqlStdOperatorTable.DIVIDE_INTEGER); // Used internally.
+        register(SqlStdOperatorTable.PERCENT_REMAINDER);
+        register(SqlStdOperatorTable.UNARY_MINUS);
+        register(SqlStdOperatorTable.UNARY_PLUS);
+
+        // Aggregates.
+        register(SqlStdOperatorTable.COUNT);
+        register(SqlStdOperatorTable.SUM);
+        register(SqlStdOperatorTable.AVG);
+        register(SqlStdOperatorTable.MIN);
+        register(SqlStdOperatorTable.MAX);
+        register(SqlStdOperatorTable.ANY_VALUE);
+        register(SqlStdOperatorTable.SINGLE_VALUE);
+        register(SqlStdOperatorTable.FILTER);
+
+        // IS ... operator.
+        register(SqlStdOperatorTable.IS_NULL);
+        register(SqlStdOperatorTable.IS_NOT_NULL);
+        register(SqlStdOperatorTable.IS_TRUE);
+        register(SqlStdOperatorTable.IS_NOT_TRUE);
+        register(SqlStdOperatorTable.IS_FALSE);
+        register(SqlStdOperatorTable.IS_NOT_FALSE);
+        register(SqlStdOperatorTable.IS_DISTINCT_FROM);
+        register(SqlStdOperatorTable.IS_NOT_DISTINCT_FROM);
+
+        // LIKE and SIMILAR.
+        register(SqlStdOperatorTable.LIKE);
+        register(SqlStdOperatorTable.NOT_LIKE);
+        register(SqlStdOperatorTable.SIMILAR_TO);
+        register(SqlStdOperatorTable.NOT_SIMILAR_TO);
+
+        // NULLS ordering.
+        register(SqlStdOperatorTable.NULLS_FIRST);
+        register(SqlStdOperatorTable.NULLS_LAST);
+        register(SqlStdOperatorTable.DESC);
+
+        // Exists.
+        register(SqlStdOperatorTable.EXISTS);
+
+        // String functions.
+        register(SqlStdOperatorTable.UPPER);
+        register(SqlStdOperatorTable.LOWER);
+        register(SqlStdOperatorTable.INITCAP);
+        register(SqlLibraryOperators.TO_BASE64);
+        register(SqlLibraryOperators.FROM_BASE64);
+        register(SqlLibraryOperators.MD5);
+        register(SqlLibraryOperators.SHA1);
+        register(SqlStdOperatorTable.SUBSTRING);
+        register(SqlLibraryOperators.LEFT);
+        register(SqlLibraryOperators.RIGHT);
+        register(SqlStdOperatorTable.REPLACE);
+        register(SqlLibraryOperators.TRANSLATE3);
+        register(SqlLibraryOperators.CHR);
+        register(SqlStdOperatorTable.CHAR_LENGTH);
+        register(SqlStdOperatorTable.CHARACTER_LENGTH);
+        register(SqlStdOperatorTable.CONCAT);
+        register(SqlLibraryOperators.CONCAT_FUNCTION);
+        register(SqlStdOperatorTable.OVERLAY);
+        register(SqlStdOperatorTable.POSITION);
+        register(SqlStdOperatorTable.ASCII);
+        register(SqlLibraryOperators.REPEAT);
+        register(SqlLibraryOperators.SPACE);
+        register(SqlLibraryOperators.STRCMP);
+        register(SqlLibraryOperators.SOUNDEX);
+        register(SqlLibraryOperators.DIFFERENCE);
+        register(SqlLibraryOperators.REVERSE);
+        register(SqlStdOperatorTable.TRIM);
+        register(SqlLibraryOperators.LTRIM);
+        register(SqlLibraryOperators.RTRIM);
+
+        // Math functions.
+        register(SqlStdOperatorTable.MOD); // Arithmetic remainder.
+        register(SqlStdOperatorTable.EXP); // Euler's number e raised to the power of a value.
+        register(SqlStdOperatorTable.POWER);
+        register(SqlStdOperatorTable.LN); // Natural logarithm.
+        register(SqlStdOperatorTable.LOG10); // The base 10 logarithm.
+        register(SqlStdOperatorTable.ABS); // Absolute value.
+        register(SqlStdOperatorTable.RAND); // Random.
+        register(SqlStdOperatorTable.RAND_INTEGER); // Integer random.
+        register(SqlStdOperatorTable.ACOS); // Arc cosine.
+        register(SqlStdOperatorTable.ASIN); // Arc sine.
+        register(SqlStdOperatorTable.ATAN); // Arc tangent.
+        register(SqlStdOperatorTable.ATAN2); // Angle from coordinates.
+        register(SqlStdOperatorTable.SQRT); // Square root.
+        register(SqlStdOperatorTable.CBRT); // Cube root.
+        register(SqlStdOperatorTable.COS); // Cosine
+        register(SqlLibraryOperators.COSH); // Hyperbolic cosine.
+        register(SqlStdOperatorTable.COT); // Cotangent.
+        register(SqlStdOperatorTable.DEGREES); // Radians to degrees.
+        register(SqlStdOperatorTable.RADIANS); // Degrees to radians.
+        register(SqlStdOperatorTable.ROUND);
+        register(SqlStdOperatorTable.SIGN);
+        register(SqlStdOperatorTable.SIN); // Sine.
+        register(SqlLibraryOperators.SINH); // Hyperbolic sine.
+        register(SqlStdOperatorTable.TAN); // Tangent.
+        register(SqlLibraryOperators.TANH); // Hyperbolic tangent.
+        register(SqlStdOperatorTable.TRUNCATE);
+        register(SqlStdOperatorTable.PI);
+
+        // Date and time.
+        register(SqlStdOperatorTable.DATETIME_PLUS);
+        register(SqlStdOperatorTable.MINUS_DATE);
+        register(SqlStdOperatorTable.EXTRACT);
+        register(SqlStdOperatorTable.FLOOR);
+        register(SqlStdOperatorTable.CEIL);
+        register(SqlStdOperatorTable.TIMESTAMP_ADD);
+        register(SqlStdOperatorTable.TIMESTAMP_DIFF);
+        register(SqlStdOperatorTable.LAST_DAY);
+        register(SqlLibraryOperators.DAYNAME);
+        register(SqlLibraryOperators.MONTHNAME);
+        register(SqlStdOperatorTable.DAYOFMONTH);
+        register(SqlStdOperatorTable.DAYOFWEEK);
+        register(SqlStdOperatorTable.DAYOFYEAR);
+        register(SqlStdOperatorTable.YEAR);
+        register(SqlStdOperatorTable.QUARTER);
+        register(SqlStdOperatorTable.MONTH);
+        register(SqlStdOperatorTable.WEEK);
+        register(SqlStdOperatorTable.HOUR);
+        register(SqlStdOperatorTable.MINUTE);
+        register(SqlStdOperatorTable.SECOND);
+        register(SqlLibraryOperators.TIMESTAMP_SECONDS); // Seconds since 1970-01-01 to timestamp.
+        register(SqlLibraryOperators.TIMESTAMP_MILLIS); // Milliseconds since 1970-01-01 to timestamp.
+        register(SqlLibraryOperators.TIMESTAMP_MICROS); // Microseconds since 1970-01-01 to timestamp.
+        register(SqlLibraryOperators.UNIX_SECONDS); // Timestamp to seconds since 1970-01-01.
+        register(SqlLibraryOperators.UNIX_MILLIS); // Timestamp to milliseconds since 1970-01-01.
+        register(SqlLibraryOperators.UNIX_MICROS); // Timestamp to microseconds since 1970-01-01.
+        register(SqlLibraryOperators.UNIX_DATE); // Date to days since 1970-01-01.
+        register(SqlLibraryOperators.DATE_FROM_UNIX_DATE); // Days since 1970-01-01 to date.
+        register(SqlLibraryOperators.DATE); // String to date.
+
+        // POSIX REGEX.
+        register(SqlStdOperatorTable.POSIX_REGEX_CASE_INSENSITIVE);
+        register(SqlStdOperatorTable.POSIX_REGEX_CASE_SENSITIVE);
+        register(SqlStdOperatorTable.NEGATED_POSIX_REGEX_CASE_INSENSITIVE);
+        register(SqlStdOperatorTable.NEGATED_POSIX_REGEX_CASE_SENSITIVE);
+        register(SqlLibraryOperators.REGEXP_REPLACE);
+
+        // Collections.
+        register(SqlStdOperatorTable.MAP_VALUE_CONSTRUCTOR);
+        register(SqlStdOperatorTable.ARRAY_VALUE_CONSTRUCTOR);
+        register(SqlStdOperatorTable.ITEM);
+        register(SqlStdOperatorTable.CARDINALITY);
+        register(SqlStdOperatorTable.IS_EMPTY);
+        register(SqlStdOperatorTable.IS_NOT_EMPTY);
+
+        // TODO https://issues.apache.org/jira/browse/IGNITE-15550
+        //register(SqlStdOperatorTable.MAP_QUERY);
+        //register(SqlStdOperatorTable.ARRAY_QUERY);
+
+        // Multiset.
+        // TODO https://issues.apache.org/jira/browse/IGNITE-15551
+        //register(SqlStdOperatorTable.MULTISET_VALUE);
+        //register(SqlStdOperatorTable.MULTISET_QUERY);
+        //register(SqlStdOperatorTable.SLICE);
+        //register(SqlStdOperatorTable.ELEMENT);
+        //register(SqlStdOperatorTable.STRUCT_ACCESS);
+        //register(SqlStdOperatorTable.MEMBER_OF);
+        //register(SqlStdOperatorTable.IS_A_SET);
+        //register(SqlStdOperatorTable.IS_NOT_A_SET);
+        //register(SqlStdOperatorTable.MULTISET_INTERSECT_DISTINCT);
+        //register(SqlStdOperatorTable.MULTISET_INTERSECT);
+        //register(SqlStdOperatorTable.MULTISET_EXCEPT_DISTINCT);
+        //register(SqlStdOperatorTable.MULTISET_EXCEPT);
+        //register(SqlStdOperatorTable.MULTISET_UNION_DISTINCT);
+        //register(SqlStdOperatorTable.MULTISET_UNION);
+        //register(SqlStdOperatorTable.SUBMULTISET_OF);
+        //register(SqlStdOperatorTable.NOT_SUBMULTISET_OF);
+
+        // Other fuctions and operators.
+        register(SqlStdOperatorTable.ROW);
+        register(SqlStdOperatorTable.CAST);
+        register(SqlLibraryOperators.INFIX_CAST);
+        register(SqlStdOperatorTable.COALESCE);
+        register(SqlLibraryOperators.NVL);
+        register(SqlStdOperatorTable.NULLIF);
+        register(SqlStdOperatorTable.CASE);
+        register(SqlLibraryOperators.DECODE);
+        register(SqlLibraryOperators.LEAST);
+        register(SqlLibraryOperators.GREATEST);
+        register(SqlLibraryOperators.COMPRESS);
+
+        // XML Operators.
+        register(SqlLibraryOperators.EXTRACT_VALUE);
+        register(SqlLibraryOperators.XML_TRANSFORM);
+        register(SqlLibraryOperators.EXTRACT_XML);
+        register(SqlLibraryOperators.EXISTS_NODE);
+
+        // JSON Operators
+        register(SqlStdOperatorTable.JSON_VALUE_EXPRESSION);
+        register(SqlStdOperatorTable.JSON_VALUE);
+        register(SqlStdOperatorTable.JSON_QUERY);
+        register(SqlLibraryOperators.JSON_TYPE);
+        register(SqlStdOperatorTable.JSON_EXISTS);
+        register(SqlLibraryOperators.JSON_DEPTH);
+        register(SqlLibraryOperators.JSON_KEYS);
+        register(SqlLibraryOperators.JSON_PRETTY);
+        register(SqlLibraryOperators.JSON_LENGTH);
+        register(SqlLibraryOperators.JSON_REMOVE);
+        register(SqlLibraryOperators.JSON_STORAGE_SIZE);
+        register(SqlStdOperatorTable.JSON_OBJECT);
+        register(SqlStdOperatorTable.JSON_ARRAY);
+        register(SqlStdOperatorTable.IS_JSON_VALUE);
+        register(SqlStdOperatorTable.IS_JSON_OBJECT);
+        register(SqlStdOperatorTable.IS_JSON_ARRAY);
+        register(SqlStdOperatorTable.IS_JSON_SCALAR);
+        register(SqlStdOperatorTable.IS_NOT_JSON_VALUE);
+        register(SqlStdOperatorTable.IS_NOT_JSON_OBJECT);
+        register(SqlStdOperatorTable.IS_NOT_JSON_ARRAY);
+        register(SqlStdOperatorTable.IS_NOT_JSON_SCALAR);
+
+        // Current time functions.
+        register(SqlStdOperatorTable.CURRENT_TIME);
+        register(SqlStdOperatorTable.CURRENT_TIMESTAMP);
+        register(SqlStdOperatorTable.CURRENT_DATE);
+        register(SqlStdOperatorTable.LOCALTIME);
+        register(SqlStdOperatorTable.LOCALTIMESTAMP);
+    }
+}
diff --git a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/StdSqlOperatorsTest.java b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/StdSqlOperatorsTest.java
new file mode 100644
index 0000000..467a75e
--- /dev/null
+++ b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/StdSqlOperatorsTest.java
@@ -0,0 +1,335 @@
+/*
+ * 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;
+
+import java.math.BigDecimal;
+import java.sql.Date;
+import java.sql.Timestamp;
+import java.time.Period;
+import java.util.Arrays;
+import java.util.Collections;
+import org.apache.calcite.avatica.util.ByteString;
+import org.apache.ignite.internal.processors.query.calcite.integration.AbstractBasicIntegrationTest;
+import org.apache.ignite.internal.processors.query.calcite.sql.fun.IgniteStdSqlOperatorTable;
+import org.apache.ignite.internal.util.typedef.F;
+import org.junit.Ignore;
+import org.junit.Test;
+
+/**
+ * Ignite's SQL dialect test.
+ * This test contains basic checks for standard SQL operators (only syntax check and check ability to use it).
+ *
+ * @see IgniteStdSqlOperatorTable
+ */
+public class StdSqlOperatorsTest extends AbstractBasicIntegrationTest {
+    /** */
+    @Test
+    public void testSet() {
+        assertQuery("SELECT 1 UNION SELECT 2").returns(1).returns(2).check();
+        assertQuery("SELECT 1 UNION ALL SELECT 1").returns(1).returns(1).check();
+        assertQuery("SELECT 1 EXCEPT SELECT 2").returns(1).check();
+        assertQuery("SELECT 1 EXCEPT ALL SELECT 2").returns(1).check();
+        assertQuery("SELECT 1 INTERSECT SELECT 1").returns(1).check();
+        assertQuery("SELECT 1 INTERSECT ALL SELECT 1").returns(1).check();
+    }
+
+    /** */
+    @Test
+    public void testLogical() {
+        assertQuery("SELECT FALSE AND TRUE").returns(false).check();
+        assertQuery("SELECT FALSE OR TRUE").returns(true).check();
+        assertQuery("SELECT NOT FALSE").returns(true).check();
+    }
+
+    /** */
+    @Test
+    public void testComparison() {
+        assertQuery("SELECT 2 > 1").returns(true).check();
+        assertQuery("SELECT 2 >= 1").returns(true).check();
+        assertQuery("SELECT 2 < 1").returns(false).check();
+        assertQuery("SELECT 2 <= 1").returns(false).check();
+        assertQuery("SELECT 2 = 1").returns(false).check();
+        assertQuery("SELECT 2 <> 1").returns(true).check();
+        assertQuery("SELECT 2 BETWEEN 1 AND 3").returns(true).check();
+        assertQuery("SELECT 2 NOT BETWEEN 1 AND 3").returns(false).check();
+    }
+
+    /** */
+    @Test
+    public void testArithmetic() {
+        assertQuery("SELECT 1 + 2").returns(3).check();
+        assertQuery("SELECT 2 - 1").returns(1).check();
+        assertQuery("SELECT 2 * 3").returns(6).check();
+        assertQuery("SELECT 3 / 2 ").returns(1).check();
+        assertQuery("SELECT -(1)").returns(-1).check();
+        assertQuery("SELECT +(1)").returns(1).check();
+        assertQuery("SELECT 3 % 2").returns(1).check();
+    }
+
+    /** */
+    @Test
+    public void testAggregates() {
+        assertQuery("SELECT COUNT(*) FROM (SELECT 1 AS a)").returns(1L).check();
+        assertQuery("SELECT SUM(a) FROM (SELECT 1 AS a)").returns(1L).check();
+        assertQuery("SELECT AVG(a) FROM (SELECT 1 AS a)").returns(1).check();
+        assertQuery("SELECT MIN(a) FROM (SELECT 1 AS a)").returns(1).check();
+        assertQuery("SELECT MAX(a) FROM (SELECT 1 AS a)").returns(1).check();
+        assertQuery("SELECT ANY_VALUE(a) FROM (SELECT 1 AS a)").returns(1).check();
+        assertQuery("SELECT COUNT(*) FILTER(WHERE a <> 1) FROM (SELECT 1 AS a)").returns(0L).check();
+    }
+
+    /** */
+    @Test
+    public void testIs() {
+        assertQuery("SELECT 'a' IS NULL").returns(false).check();
+        assertQuery("SELECT 'a' IS NOT NULL").returns(true).check();
+        assertQuery("SELECT 1=1 IS TRUE").returns(true).check();
+        assertQuery("SELECT 1=1 IS NOT TRUE").returns(false).check();
+        assertQuery("SELECT 1=1 IS FALSE").returns(false).check();
+        assertQuery("SELECT 1=1 IS NOT FALSE").returns(true).check();
+    }
+
+    /** */
+    @Test
+    public void testLike() {
+        assertQuery("SELECT 'a' LIKE 'a%'").returns(true).check();
+        assertQuery("SELECT 'a' NOT LIKE 'a%'").returns(false).check();
+        assertQuery("SELECT 'a' SIMILAR TO '(a|A)%'").returns(true).check();
+        assertQuery("SELECT 'A' NOT SIMILAR TO '(a|A)%'").returns(false).check();
+    }
+
+    /** */
+    @Test
+    public void testNullsOrdering() {
+        assertQuery("SELECT a FROM (SELECT 1 AS a) ORDER BY a NULLS FIRST").returns(1).check();
+        assertQuery("SELECT a FROM (SELECT 1 AS a) ORDER BY a NULLS LAST").returns(1).check();
+        assertQuery("SELECT a FROM (SELECT 1 AS a) ORDER BY a DESC NULLS FIRST").returns(1).check();
+        assertQuery("SELECT a FROM (SELECT 1 AS a) ORDER BY a DESC NULLS LAST").returns(1).check();
+        assertQuery("SELECT a FROM (SELECT 1 AS a) ORDER BY a ASC NULLS FIRST").returns(1).check();
+        assertQuery("SELECT a FROM (SELECT 1 AS a) ORDER BY a ASC NULLS LAST").returns(1).check();
+    }
+
+    /** */
+    @Test
+    public void testExists() {
+        assertQuery("SELECT EXISTS (SELECT 1)").returns(true).check();
+        assertQuery("SELECT NOT EXISTS (SELECT 1)").returns(false).check();
+    }
+
+    /** */
+    @Test
+    public void testStringFunctions() {
+        assertQuery("SELECT UPPER('aA')").returns("AA").check();
+        assertQuery("SELECT LOWER('aA')").returns("aa").check();
+        assertQuery("SELECT INITCAP('aA')").returns("Aa").check();
+        assertQuery("SELECT TO_BASE64('aA')").returns("YUE=").check();
+        assertQuery("SELECT FROM_BASE64('YUE=')").returns(new ByteString(new byte[] {'a', 'A'})).check();
+        assertQuery("SELECT MD5('aa')").returns("4124bc0a9335c27f086f24ba207a4912").check();
+        assertQuery("SELECT SHA1('aa')").returns("e0c9035898dd52fc65c41454cec9c4d2611bfb37").check();
+        assertQuery("SELECT SUBSTRING('aAaA', 2, 2)").returns("Aa").check();
+        assertQuery("SELECT LEFT('aA', 1)").returns("a").check();
+        assertQuery("SELECT RIGHT('aA', 1)").returns("A").check();
+        assertQuery("SELECT REPLACE('aA', 'A', 'a')").returns("aa").check();
+        assertQuery("SELECT TRANSLATE('aA', 'A', 'a')").returns("aa").check();
+        assertQuery("SELECT CHR(97)").returns("a").check();
+        assertQuery("SELECT CHAR_LENGTH('aa')").returns(2).check();
+        assertQuery("SELECT CHARACTER_LENGTH('aa')").returns(2).check();
+        assertQuery("SELECT 'a' || 'a'").returns("aa").check();
+        assertQuery("SELECT CONCAT('a', 'a')").returns("aa").check();
+        assertQuery("SELECT OVERLAY('aAaA' PLACING 'aA' FROM 2)").returns("aaAA").check();
+        assertQuery("SELECT POSITION('A' IN 'aA')").returns(2).check();
+        assertQuery("SELECT ASCII('a')").returns(97).check();
+        assertQuery("SELECT REPEAT('a', 2)").returns("aa").check();
+        assertQuery("SELECT SPACE(2)").returns("  ").check();
+        assertQuery("SELECT STRCMP('a', 'b')").returns(1).check();
+        assertQuery("SELECT SOUNDEX('a')").returns("A000").check();
+        assertQuery("SELECT DIFFERENCE('a', 'A')").returns(4).check();
+        assertQuery("SELECT REVERSE('aA')").returns("Aa").check();
+        assertQuery("SELECT TRIM('a' FROM 'aA')").returns("A").check();
+        assertQuery("SELECT LTRIM(' a ')").returns("a ").check();
+        assertQuery("SELECT RTRIM(' a ')").returns(" a").check();
+    }
+
+    /** */
+    @Test
+    public void testMathFunctions() {
+        assertQuery("SELECT MOD(3, 2)").returns(1).check();
+        assertQuery("SELECT EXP(2)").returns(Math.exp(2)).check();
+        assertQuery("SELECT POWER(2, 2)").returns(Math.pow(2, 2)).check();
+        assertQuery("SELECT LN(2)").returns(Math.log(2)).check();
+        assertQuery("SELECT LOG10(2) ").returns(Math.log10(2)).check();
+        assertQuery("SELECT ABS(-1)").returns(Math.abs(-1)).check();
+        assertQuery("SELECT RAND()").check();
+        assertQuery("SELECT RAND_INTEGER(10)").check();
+        assertQuery("SELECT ACOS(1)").returns(Math.acos(1)).check();
+        assertQuery("SELECT ASIN(1)").returns(Math.asin(1)).check();
+        assertQuery("SELECT ATAN(1)").returns(Math.atan(1)).check();
+        assertQuery("SELECT ATAN2(1, 1)").returns(Math.atan2(1, 1)).check();
+        assertQuery("SELECT SQRT(4)").returns(Math.sqrt(4)).check();
+        assertQuery("SELECT CBRT(8)").returns(Math.cbrt(8)).check();
+        assertQuery("SELECT COS(1)").returns(Math.cos(1)).check();
+        assertQuery("SELECT COSH(1)").returns(Math.cosh(1)).check();
+        assertQuery("SELECT COT(1)").returns(1.0d / Math.tan(1)).check();
+        assertQuery("SELECT DEGREES(1)").returns(Math.toDegrees(1)).check();
+        assertQuery("SELECT RADIANS(1)").returns(Math.toRadians(1)).check();
+        assertQuery("SELECT ROUND(1.7)").returns(BigDecimal.valueOf(2)).check();
+        assertQuery("SELECT SIGN(-5)").returns(-1).check();
+        assertQuery("SELECT SIN(1)").returns(Math.sin(1)).check();
+        assertQuery("SELECT SINH(1)").returns(Math.sinh(1)).check();
+        assertQuery("SELECT TAN(1)").returns(Math.tan(1)).check();
+        assertQuery("SELECT TANH(1)").returns(Math.tanh(1)).check();
+        assertQuery("SELECT TRUNCATE(1.7)").returns(BigDecimal.valueOf(1)).check();
+        assertQuery("SELECT PI").returns(Math.PI).check();
+    }
+
+    /** */
+    @Test
+    public void testDateAndTime() {
+        assertQuery("SELECT DATE '2021-01-01' + interval (1) days").returns(Date.valueOf("2021-01-02")).check();
+        assertQuery("SELECT (DATE '2021-03-01' - DATE '2021-01-01') months").returns(Period.ofMonths(2)).check();
+        assertQuery("SELECT EXTRACT(DAY FROM DATE '2021-01-15')").returns(15L).check();
+        assertQuery("SELECT FLOOR(DATE '2021-01-15' TO MONTH)").returns(Date.valueOf("2021-01-01")).check();
+        assertQuery("SELECT CEIL(DATE '2021-01-15' TO MONTH)").returns(Date.valueOf("2021-02-01")).check();
+        assertQuery("SELECT TIMESTAMPADD(DAY, 1, TIMESTAMP '2021-01-01')").returns(Timestamp.valueOf("2021-01-02 00:00:00")).check();
+        assertQuery("SELECT TIMESTAMPDIFF(DAY, TIMESTAMP '2021-01-01', TIMESTAMP '2021-01-02')").returns(1).check();
+        assertQuery("SELECT LAST_DAY(DATE '2021-01-01')").returns(Date.valueOf("2021-01-31")).check();
+        assertQuery("SELECT DAYNAME(DATE '2021-01-01')").returns("Friday").check();
+        assertQuery("SELECT MONTHNAME(DATE '2021-01-01')").returns("January").check();
+        assertQuery("SELECT DAYOFMONTH(DATE '2021-01-01')").returns(1L).check();
+        assertQuery("SELECT DAYOFWEEK(DATE '2021-01-01')").returns(6L).check();
+        assertQuery("SELECT DAYOFYEAR(DATE '2021-01-01')").returns(1L).check();
+        assertQuery("SELECT YEAR(DATE '2021-01-01')").returns(2021L).check();
+        assertQuery("SELECT QUARTER(DATE '2021-01-01')").returns(1L).check();
+        assertQuery("SELECT MONTH(DATE '2021-01-01')").returns(1L).check();
+        assertQuery("SELECT WEEK(DATE '2021-01-04')").returns(1L).check();
+        assertQuery("SELECT HOUR(TIMESTAMP '2021-01-01 01:01:01')").returns(1L).check();
+        assertQuery("SELECT MINUTE(TIMESTAMP '2021-01-01 01:01:01')").returns(1L).check();
+        assertQuery("SELECT SECOND(TIMESTAMP '2021-01-01 01:01:01')").returns(1L).check();
+        assertQuery("SELECT TIMESTAMP_SECONDS(1609459200)").returns(Timestamp.valueOf("2021-01-01 00:00:00")).check();
+        assertQuery("SELECT TIMESTAMP_MILLIS(1609459200000)").returns(Timestamp.valueOf("2021-01-01 00:00:00")).check();
+        assertQuery("SELECT TIMESTAMP_MICROS(1609459200000000)").returns(Timestamp.valueOf("2021-01-01 00:00:00")).check();
+        assertQuery("SELECT UNIX_SECONDS(TIMESTAMP '2021-01-01 00:00:00')").returns(1609459200L).check();
+        assertQuery("SELECT UNIX_MILLIS(TIMESTAMP '2021-01-01 00:00:00')").returns(1609459200000L).check();
+        assertQuery("SELECT UNIX_MICROS(TIMESTAMP '2021-01-01 00:00:00')").returns(1609459200000000L).check();
+        assertQuery("SELECT UNIX_DATE(DATE '2021-01-01')").returns(18628).check();
+        assertQuery("SELECT DATE_FROM_UNIX_DATE(18628)").returns(Date.valueOf("2021-01-01")).check();
+        assertQuery("SELECT DATE('2021-01-01')").returns(Date.valueOf("2021-01-01")).check();
+    }
+
+    /** */
+    @Test
+    public void testPosixRegex() {
+        assertQuery("SELECT 'aA' ~ '.*aa.*'").returns(false).check();
+        assertQuery("SELECT 'aA' ~* '.*aa.*'").returns(true).check();
+        assertQuery("SELECT 'aA' !~ '.*aa.*'").returns(true).check();
+        assertQuery("SELECT 'aA' !~* '.*aa.*'").returns(false).check();
+        assertQuery("SELECT REGEXP_REPLACE('aA', '[Aa]+', 'X')").returns("X").check();
+    }
+
+    /** */
+    @Test
+    public void testCollections() {
+        assertQuery("SELECT MAP['a', 1, 'A', 2]").returns(F.asMap("a", 1, "A", 2)).check();
+        assertQuery("SELECT ARRAY[1, 2, 3]").returns(Arrays.asList(1, 2, 3)).check();
+        assertQuery("SELECT ARRAY[1, 2, 3][2]").returns(2).check();
+        assertQuery("SELECT CARDINALITY(ARRAY[1, 2, 3])").returns(3).check();
+        assertQuery("SELECT ARRAY[1, 2, 3] IS EMPTY").returns(false).check();
+        assertQuery("SELECT ARRAY[1, 2, 3] IS NOT EMPTY").returns(true).check();
+    }
+
+    /** */
+    @Test
+    @Ignore("https://issues.apache.org/jira/browse/IGNITE-15550")
+    public void testQueryAsCollections() {
+        assertQuery("SELECT MAP(SELECT 'a', 1)").returns(F.asMap("a", 1)).check();
+        assertQuery("SELECT ARRAY(SELECT 1)").returns(Collections.singletonList(1)).check();
+    }
+
+    /** */
+    @Test
+    public void testOtherFunctions() {
+        assertQuery("SELECT * FROM (VALUES ROW('a', 1))").returns("a", 1).check();
+        assertQuery("SELECT CAST('1' AS INT)").returns(1).check();
+        assertQuery("SELECT '1'::INT").returns(1).check();
+        assertQuery("SELECT COALESCE(null, 'a', 'A')").returns("a").check();
+        assertQuery("SELECT NVL(null, 'a')").returns("a").check();
+        assertQuery("SELECT NULLIF(1, 2)").returns(1).check();
+        assertQuery("SELECT CASE WHEN 1=1 THEN 1 ELSE 2 END").returns(1).check();
+        assertQuery("SELECT DECODE(1, 1, 1, 2)").returns(1).check();
+        assertQuery("SELECT LEAST('a', 'b')").returns("a").check();
+        assertQuery("SELECT GREATEST('a', 'b')").returns("b").check();
+        assertQuery("SELECT COMPRESS('')::VARCHAR").returns("").check();
+    }
+
+    /** */
+    @Test
+    public void testXml() {
+        assertQuery("SELECT EXTRACTVALUE('<a>b</a>', '//a')").returns("b").check();
+        assertQuery("SELECT XMLTRANSFORM('<a>b</a>',"
+            + "'<?xml version=\"1.0\"?>\n"
+            + "<xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">"
+            + "  <xsl:output method=\"text\"/>"
+            + "  <xsl:template match=\"/\">"
+            + "    a - <xsl:value-of select=\"/a\"/>"
+            + "  </xsl:template>"
+            + "</xsl:stylesheet>')"
+        ).returns("    a - b").check();
+        assertQuery("SELECT \"EXTRACT\"('<a><b>c</b></a>', '/a/b')").returns("<b>c</b>").check();
+        assertQuery("SELECT EXISTSNODE('<a><b>c</b></a>', '/a/b')").returns(1).check();
+    }
+
+    /** */
+    @Test
+    public void testJson() {
+        assertQuery("SELECT '{\"a\":1}' FORMAT JSON").check();
+        assertQuery("SELECT JSON_VALUE('{\"a\":1}', '$.a')").returns("1").check();
+        assertQuery("SELECT JSON_VALUE('{\"a\":1}' FORMAT JSON, '$.a')").returns("1").check();
+        assertQuery("SELECT JSON_QUERY('{\"a\":{\"b\":1}}', '$.a')").returns("{\"b\":1}").check();
+        assertQuery("SELECT JSON_TYPE('{\"a\":1}')").returns("OBJECT").check();
+        assertQuery("SELECT JSON_EXISTS('{\"a\":1}', '$.a')").returns(true).check();
+        assertQuery("SELECT JSON_DEPTH('{\"a\":1}')").returns(2).check();
+        assertQuery("SELECT JSON_KEYS('{\"a\":1}')").returns("[\"a\"]").check();
+        assertQuery("SELECT JSON_PRETTY('{\"a\":1}')").returns("{\n  \"a\" : 1\n}").check();
+        assertQuery("SELECT JSON_LENGTH('{\"a\":1}')").returns(1).check();
+        assertQuery("SELECT JSON_REMOVE('{\"a\":1, \"b\":2}', '$.a')").returns("{\"b\":2}").check();
+        assertQuery("SELECT JSON_STORAGE_SIZE('1')").returns(1).check();
+        assertQuery("SELECT JSON_OBJECT('a': 1)").returns("{\"a\":1}").check();
+        assertQuery("SELECT JSON_ARRAY('a', 'b')").returns("[\"a\",\"b\"]").check();
+        assertQuery("SELECT '{\"a\":1}' IS JSON").returns(true).check();
+        assertQuery("SELECT '{\"a\":1}' IS JSON VALUE").returns(true).check();
+        assertQuery("SELECT '{\"a\":1}' IS JSON OBJECT").returns(true).check();
+        assertQuery("SELECT '[1, 2]' IS JSON ARRAY").returns(true).check();
+        assertQuery("SELECT '1' IS JSON SCALAR").returns(true).check();
+        assertQuery("SELECT '{\"a\":1}' IS NOT JSON").returns(false).check();
+        assertQuery("SELECT '{\"a\":1}' IS NOT JSON VALUE").returns(false).check();
+        assertQuery("SELECT '{\"a\":1}' IS NOT JSON OBJECT").returns(false).check();
+        assertQuery("SELECT '[1, 2]' IS NOT JSON ARRAY").returns(false).check();
+        assertQuery("SELECT '1' IS NOT JSON SCALAR").returns(false).check();
+    }
+
+    /** */
+    @Test
+    public void testCurrentTimeFunctions() {
+        // Don't check returned value, only ability to use these functions.
+        assertQuery("SELECT CURRENT_TIME").check();
+        assertQuery("SELECT CURRENT_TIMESTAMP").check();
+        assertQuery("SELECT CURRENT_DATE").check();
+        assertQuery("SELECT LOCALTIME").check();
+        assertQuery("SELECT LOCALTIMESTAMP").check();
+    }
+}
diff --git a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/planner/PlannerTest.java b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/planner/PlannerTest.java
index 1b5779d..99c6ca9 100644
--- a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/planner/PlannerTest.java
+++ b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/planner/PlannerTest.java
@@ -1285,7 +1285,7 @@ public class PlannerTest extends AbstractPlannerTest {
 
         String queries[] = {
             "select REVERSE(val) from TEST", // MYSQL
-            "select TO_DATE(val, 'yyyymmdd') from TEST" // ORACLE
+            "select DECODE(id, 0, val, '') from TEST" // ORACLE
         };
 
         for (String sql : queries) {
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 96cccfc..ea9bbba 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
@@ -25,6 +25,7 @@ import org.apache.ignite.internal.processors.query.calcite.DateTimeTest;
 import org.apache.ignite.internal.processors.query.calcite.FunctionsTest;
 import org.apache.ignite.internal.processors.query.calcite.LimitOffsetTest;
 import org.apache.ignite.internal.processors.query.calcite.SqlFieldsQueryUsageTest;
+import org.apache.ignite.internal.processors.query.calcite.StdSqlOperatorsTest;
 import org.apache.ignite.internal.processors.query.calcite.UnstableTopologyTest;
 import org.apache.ignite.internal.processors.query.calcite.integration.AggregatesIntegrationTest;
 import org.apache.ignite.internal.processors.query.calcite.integration.CalciteErrorHandlilngIntegrationTest;
@@ -73,6 +74,7 @@ import org.junit.runners.Suite;
     UserDdlIntegrationTest.class,
     KillCommandDdlIntegrationTest.class,
     FunctionsTest.class,
+    StdSqlOperatorsTest.class,
     TableDmlIntegrationTest.class,
     DataTypesTest.class,
     IndexSpoolIntegrationTest.class,