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,