From efea651daa8f0f46c3b07d4d5a6861973844c1ca Mon Sep 17 00:00:00 2001 From: niu niu Date: Fri, 20 Sep 2024 18:41:47 +0800 Subject: [PATCH 1/3] Support for federated query NOT operator --- .../common/SQLExtensionOperatorTable.java | 5 ++ .../impl/NotExpressionConverter.java | 3 +- .../function/mysql/MySQLOperatorTable.java | 34 +++++++++++ .../function/mysql/impl/MySQLNotFunction.java | 60 +++++++++++++++++++ .../util/SQLFederationPlannerUtils.java | 3 +- .../resources/cases/dql/e2e-dql-select.xml | 16 +++++ 6 files changed, 118 insertions(+), 3 deletions(-) create mode 100644 kernel/sql-federation/optimizer/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/function/mysql/MySQLOperatorTable.java create mode 100644 kernel/sql-federation/optimizer/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/function/mysql/impl/MySQLNotFunction.java diff --git a/kernel/sql-federation/optimizer/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/converter/operator/common/SQLExtensionOperatorTable.java b/kernel/sql-federation/optimizer/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/converter/operator/common/SQLExtensionOperatorTable.java index cfc8d3ced631a..110f80291c15a 100644 --- a/kernel/sql-federation/optimizer/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/converter/operator/common/SQLExtensionOperatorTable.java +++ b/kernel/sql-federation/optimizer/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/converter/operator/common/SQLExtensionOperatorTable.java @@ -22,6 +22,9 @@ import org.apache.calcite.sql.SqlBinaryOperator; import org.apache.calcite.sql.SqlKind; import org.apache.calcite.sql.SqlPrefixOperator; +import org.apache.calcite.sql.type.InferTypes; +import org.apache.calcite.sql.type.OperandTypes; +import org.apache.calcite.sql.type.ReturnTypes; import org.apache.shardingsphere.sqlfederation.optimizer.converter.operator.dialect.mysql.MySQLMatchAgainstOperator; /** @@ -60,5 +63,7 @@ public final class SQLExtensionOperatorTable { public static final SqlPrefixOperator TILDE = new SqlPrefixOperator("~", SqlKind.OTHER, 26, null, null, null); + public static final SqlPrefixOperator NOT = new SqlPrefixOperator("NOT", SqlKind.NOT, 26, ReturnTypes.BIGINT, InferTypes.BOOLEAN, OperandTypes.ANY); + public static final MySQLMatchAgainstOperator MATCH_AGAINST = new MySQLMatchAgainstOperator(); } diff --git a/kernel/sql-federation/optimizer/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/converter/segment/expression/impl/NotExpressionConverter.java b/kernel/sql-federation/optimizer/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/converter/segment/expression/impl/NotExpressionConverter.java index 6588f4473f85d..f63f93c2c7851 100644 --- a/kernel/sql-federation/optimizer/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/converter/segment/expression/impl/NotExpressionConverter.java +++ b/kernel/sql-federation/optimizer/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/converter/segment/expression/impl/NotExpressionConverter.java @@ -21,7 +21,6 @@ import lombok.NoArgsConstructor; import org.apache.calcite.sql.SqlBasicCall; import org.apache.calcite.sql.SqlNode; -import org.apache.calcite.sql.fun.SqlStdOperatorTable; import org.apache.calcite.sql.parser.SqlParserPos; import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.NotExpression; import org.apache.shardingsphere.sqlfederation.optimizer.converter.operator.common.SQLExtensionOperatorTable; @@ -50,6 +49,6 @@ public static Optional convert(final NotExpression segment) { if (segment.getNotSign().equals(true)) { return Optional.of(new SqlBasicCall(SQLExtensionOperatorTable.NOT_SIGN, sqlNodes, SqlParserPos.ZERO)); } - return Optional.of(new SqlBasicCall(SqlStdOperatorTable.NOT, sqlNodes, SqlParserPos.ZERO)); + return Optional.of(new SqlBasicCall(SQLExtensionOperatorTable.NOT, sqlNodes, SqlParserPos.ZERO)); } } diff --git a/kernel/sql-federation/optimizer/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/function/mysql/MySQLOperatorTable.java b/kernel/sql-federation/optimizer/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/function/mysql/MySQLOperatorTable.java new file mode 100644 index 0000000000000..558921e0a6d2b --- /dev/null +++ b/kernel/sql-federation/optimizer/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/function/mysql/MySQLOperatorTable.java @@ -0,0 +1,34 @@ +/* + * 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.shardingsphere.sqlfederation.optimizer.function.mysql; + +import org.apache.calcite.sql.util.ReflectiveSqlOperatorTable; +import org.apache.calcite.sql.validate.SqlUserDefinedFunction; +import org.apache.shardingsphere.sqlfederation.optimizer.function.mysql.impl.MySQLNotFunction; + +/** + * MySQL operator table. + */ +public final class MySQLOperatorTable extends ReflectiveSqlOperatorTable { + + public static final SqlUserDefinedFunction NOT = new MySQLNotFunction(); + + public MySQLOperatorTable() { + init(); + } +} diff --git a/kernel/sql-federation/optimizer/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/function/mysql/impl/MySQLNotFunction.java b/kernel/sql-federation/optimizer/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/function/mysql/impl/MySQLNotFunction.java new file mode 100644 index 0000000000000..f5e0061c65044 --- /dev/null +++ b/kernel/sql-federation/optimizer/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/function/mysql/impl/MySQLNotFunction.java @@ -0,0 +1,60 @@ +/* + * 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.shardingsphere.sqlfederation.optimizer.function.mysql.impl; + +import com.google.common.collect.ImmutableList; +import org.apache.calcite.schema.impl.ScalarFunctionImpl; +import org.apache.calcite.sql.SqlIdentifier; +import org.apache.calcite.sql.SqlKind; +import org.apache.calcite.sql.SqlSyntax; +import org.apache.calcite.sql.parser.SqlParserPos; +import org.apache.calcite.sql.type.InferTypes; +import org.apache.calcite.sql.type.OperandTypes; +import org.apache.calcite.sql.type.ReturnTypes; +import org.apache.calcite.sql.type.SqlTypeFamily; +import org.apache.calcite.sql.type.SqlTypeName; +import org.apache.calcite.sql.validate.SqlUserDefinedFunction; + +import java.util.Collections; + +/** + * MySQL not function. + */ +public final class MySQLNotFunction extends SqlUserDefinedFunction { + + public MySQLNotFunction() { + super(new SqlIdentifier("NOT", SqlParserPos.ZERO), SqlKind.NOT, ReturnTypes.BIGINT_NULLABLE, InferTypes.BOOLEAN, + OperandTypes.operandMetadata(Collections.singletonList(SqlTypeFamily.ANY), typeFactory -> ImmutableList.of(typeFactory.createSqlType(SqlTypeName.BIGINT)), null, arg -> false), + ScalarFunctionImpl.create(MySQLNotFunction.class, "not")); + } + + @Override + public SqlSyntax getSyntax() { + return SqlSyntax.PREFIX; + } + + public static Long not(final Object value) { + if (null == value) { + return null; + } + if (value instanceof Number) { + return ((Number) value).longValue() == 0 ? 1L : 0L; + } + return null; + } +} diff --git a/kernel/sql-federation/optimizer/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/planner/util/SQLFederationPlannerUtils.java b/kernel/sql-federation/optimizer/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/planner/util/SQLFederationPlannerUtils.java index 6701c4a729f0f..b6b94855efb17 100644 --- a/kernel/sql-federation/optimizer/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/planner/util/SQLFederationPlannerUtils.java +++ b/kernel/sql-federation/optimizer/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/planner/util/SQLFederationPlannerUtils.java @@ -51,6 +51,7 @@ import org.apache.shardingsphere.infra.database.core.spi.DatabaseTypedSPILoader; import org.apache.shardingsphere.infra.database.core.type.DatabaseType; import org.apache.shardingsphere.parser.rule.SQLParserRule; +import org.apache.shardingsphere.sqlfederation.optimizer.function.mysql.MySQLOperatorTable; import org.apache.shardingsphere.sqlfederation.optimizer.function.SQLFederationFunctionRegister; import org.apache.shardingsphere.sqlfederation.optimizer.metadata.view.ShardingSphereViewExpander; import org.apache.shardingsphere.sqlfederation.optimizer.planner.rule.converter.EnumerableModifyConverterRule; @@ -232,7 +233,7 @@ public static SqlValidator createSqlValidator(final CalciteCatalogReader catalog } private static SqlOperatorTable getSQLOperatorTable(final CalciteCatalogReader catalogReader, final DatabaseType databaseType) { - return SqlOperatorTables.chain(Arrays.asList(SqlLibraryOperatorTableFactory.INSTANCE.getOperatorTable( + return SqlOperatorTables.chain(Arrays.asList(new MySQLOperatorTable(), SqlLibraryOperatorTableFactory.INSTANCE.getOperatorTable( Arrays.asList(SqlLibrary.STANDARD, DATABASE_TYPE_SQL_LIBRARIES.getOrDefault(databaseType.getType(), SqlLibrary.MYSQL))), catalogReader)); } diff --git a/test/e2e/sql/src/test/resources/cases/dql/e2e-dql-select.xml b/test/e2e/sql/src/test/resources/cases/dql/e2e-dql-select.xml index 1d45a8f2189da..0f22234124d5d 100644 --- a/test/e2e/sql/src/test/resources/cases/dql/e2e-dql-select.xml +++ b/test/e2e/sql/src/test/resources/cases/dql/e2e-dql-select.xml @@ -386,4 +386,20 @@ + + + + + + + + + + + + + + + + From 33be3b92102de7a073e8ad5db10caa13ef09301c Mon Sep 17 00:00:00 2001 From: niu niu Date: Mon, 23 Sep 2024 10:00:48 +0800 Subject: [PATCH 2/3] Improve not operator sql node converter --- .../impl/LiteralExpressionConverter.java | 3 + .../function/mysql/impl/MySQLNotFunction.java | 3 + .../src/test/resources/converter/select.xml | 2 + .../src/main/resources/case/dml/select.xml | 55 +++++++++++++++++++ .../resources/sql/supported/dml/select.xml | 2 + 5 files changed, 65 insertions(+) diff --git a/kernel/sql-federation/optimizer/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/converter/segment/expression/impl/LiteralExpressionConverter.java b/kernel/sql-federation/optimizer/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/converter/segment/expression/impl/LiteralExpressionConverter.java index 63ef34b78a548..ad63003be69e6 100644 --- a/kernel/sql-federation/optimizer/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/converter/segment/expression/impl/LiteralExpressionConverter.java +++ b/kernel/sql-federation/optimizer/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/converter/segment/expression/impl/LiteralExpressionConverter.java @@ -76,6 +76,9 @@ public static Optional convert(final LiteralExpressionSegment segment) if (segment.getLiterals() instanceof String) { return Optional.of(SqlLiteral.createCharString(literalValue, SqlParserPos.ZERO)); } + if (segment.getLiterals() instanceof Boolean) { + return Optional.of(SqlLiteral.createBoolean(Boolean.parseBoolean(literalValue), SqlParserPos.ZERO)); + } return Optional.empty(); } } diff --git a/kernel/sql-federation/optimizer/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/function/mysql/impl/MySQLNotFunction.java b/kernel/sql-federation/optimizer/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/function/mysql/impl/MySQLNotFunction.java index f5e0061c65044..69a8b899021f8 100644 --- a/kernel/sql-federation/optimizer/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/function/mysql/impl/MySQLNotFunction.java +++ b/kernel/sql-federation/optimizer/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/function/mysql/impl/MySQLNotFunction.java @@ -55,6 +55,9 @@ public static Long not(final Object value) { if (value instanceof Number) { return ((Number) value).longValue() == 0 ? 1L : 0L; } + if (value instanceof Boolean) { + return ((Boolean) value) ? 0L : 1L; + } return null; } } diff --git a/test/it/optimizer/src/test/resources/converter/select.xml b/test/it/optimizer/src/test/resources/converter/select.xml index 437688b8969b6..740ec9aeb5166 100644 --- a/test/it/optimizer/src/test/resources/converter/select.xml +++ b/test/it/optimizer/src/test/resources/converter/select.xml @@ -35,4 +35,6 @@ + + diff --git a/test/it/parser/src/main/resources/case/dml/select.xml b/test/it/parser/src/main/resources/case/dml/select.xml index d001ed31d33f9..31770a3e40f87 100644 --- a/test/it/parser/src/main/resources/case/dml/select.xml +++ b/test/it/parser/src/main/resources/case/dml/select.xml @@ -9555,4 +9555,59 @@ + + + + diff --git a/test/it/parser/src/main/resources/sql/supported/dml/select.xml b/test/it/parser/src/main/resources/sql/supported/dml/select.xml index 9f199e5b391e2..c391cd8b72a07 100644 --- a/test/it/parser/src/main/resources/sql/supported/dml/select.xml +++ b/test/it/parser/src/main/resources/sql/supported/dml/select.xml @@ -283,4 +283,6 @@ + + From 3bb91d6fbc111d9a821c7e94755c18a2bab1e28f Mon Sep 17 00:00:00 2001 From: niu niu Date: Mon, 23 Sep 2024 16:59:00 +0800 Subject: [PATCH 3/3] Format code --- .../optimizer/function/mysql/impl/MySQLNotFunction.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/kernel/sql-federation/optimizer/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/function/mysql/impl/MySQLNotFunction.java b/kernel/sql-federation/optimizer/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/function/mysql/impl/MySQLNotFunction.java index 69a8b899021f8..986e78efed311 100644 --- a/kernel/sql-federation/optimizer/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/function/mysql/impl/MySQLNotFunction.java +++ b/kernel/sql-federation/optimizer/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/function/mysql/impl/MySQLNotFunction.java @@ -48,6 +48,12 @@ public SqlSyntax getSyntax() { return SqlSyntax.PREFIX; } + /** + * not. + * + * @param value value + * @return not operator result + */ public static Long not(final Object value) { if (null == value) { return null;