From b6cc2f7dcdf0d0527f3bf94ffab774b2f33e4d70 Mon Sep 17 00:00:00 2001 From: xuzifu666 Date: Tue, 4 Nov 2025 16:37:45 +0800 Subject: [PATCH] [CALCITE-7267] CHAR_LENGTH function is not support in Oracle --- .../apache/calcite/sql/dialect/DerbySqlDialect.java | 7 ++----- .../apache/calcite/sql/dialect/OracleSqlDialect.java | 4 ++++ .../apache/calcite/sql/dialect/PrestoSqlDialect.java | 5 +---- .../calcite/sql/dialect/SnowflakeSqlDialect.java | 5 ++--- .../apache/calcite/sql/dialect/SqliteSqlDialect.java | 6 +----- .../apache/calcite/util/RelToSqlConverterUtil.java | 11 +++++++++++ .../calcite/rel/rel2sql/RelToSqlConverterTest.java | 1 + 7 files changed, 22 insertions(+), 17 deletions(-) diff --git a/core/src/main/java/org/apache/calcite/sql/dialect/DerbySqlDialect.java b/core/src/main/java/org/apache/calcite/sql/dialect/DerbySqlDialect.java index 8ff6b76a6b23..376d830f3968 100644 --- a/core/src/main/java/org/apache/calcite/sql/dialect/DerbySqlDialect.java +++ b/core/src/main/java/org/apache/calcite/sql/dialect/DerbySqlDialect.java @@ -19,8 +19,7 @@ import org.apache.calcite.sql.SqlCall; import org.apache.calcite.sql.SqlDialect; import org.apache.calcite.sql.SqlWriter; -import org.apache.calcite.sql.fun.SqlLibraryOperators; -import org.apache.calcite.sql.parser.SqlParserPos; +import org.apache.calcite.util.RelToSqlConverterUtil; /** * A SqlDialect implementation for the Apache Derby database. @@ -40,9 +39,7 @@ public DerbySqlDialect(Context context) { final int rightPrec) { switch (call.getKind()) { case CHAR_LENGTH: - SqlCall lengthCall = SqlLibraryOperators.LENGTH - .createCall(SqlParserPos.ZERO, call.getOperandList()); - super.unparseCall(writer, lengthCall, leftPrec, rightPrec); + RelToSqlConverterUtil.convertCharLengthToLength(writer, call, leftPrec, rightPrec); break; default: super.unparseCall(writer, call, leftPrec, rightPrec); diff --git a/core/src/main/java/org/apache/calcite/sql/dialect/OracleSqlDialect.java b/core/src/main/java/org/apache/calcite/sql/dialect/OracleSqlDialect.java index 2de588f118cb..39182a631163 100644 --- a/core/src/main/java/org/apache/calcite/sql/dialect/OracleSqlDialect.java +++ b/core/src/main/java/org/apache/calcite/sql/dialect/OracleSqlDialect.java @@ -38,6 +38,7 @@ import org.apache.calcite.sql.fun.SqlStdOperatorTable; import org.apache.calcite.sql.parser.SqlParserPos; import org.apache.calcite.sql.type.SqlTypeName; +import org.apache.calcite.util.RelToSqlConverterUtil; import com.google.common.collect.ImmutableList; @@ -196,6 +197,9 @@ public OracleSqlDialect(Context context) { } writer.endFunCall(frame); break; + case CHAR_LENGTH: + RelToSqlConverterUtil.convertCharLengthToLength(writer, call, leftPrec, rightPrec); + break; case FLOOR: if (call.operandCount() != 2) { super.unparseCall(writer, call, leftPrec, rightPrec); diff --git a/core/src/main/java/org/apache/calcite/sql/dialect/PrestoSqlDialect.java b/core/src/main/java/org/apache/calcite/sql/dialect/PrestoSqlDialect.java index cd1aa5f5ec33..25b8153f8f0e 100644 --- a/core/src/main/java/org/apache/calcite/sql/dialect/PrestoSqlDialect.java +++ b/core/src/main/java/org/apache/calcite/sql/dialect/PrestoSqlDialect.java @@ -37,7 +37,6 @@ import org.apache.calcite.sql.SqlNode; import org.apache.calcite.sql.SqlWriter; import org.apache.calcite.sql.fun.SqlArrayValueConstructor; -import org.apache.calcite.sql.fun.SqlLibraryOperators; import org.apache.calcite.sql.fun.SqlMapValueConstructor; import org.apache.calcite.sql.fun.SqlStdOperatorTable; import org.apache.calcite.sql.parser.SqlParserPos; @@ -252,9 +251,7 @@ private static void unparseUsingLimit(SqlWriter writer, @Nullable SqlNode offset } break; case CHAR_LENGTH: - SqlCall lengthCall = SqlLibraryOperators.LENGTH - .createCall(SqlParserPos.ZERO, call.getOperandList()); - super.unparseCall(writer, lengthCall, leftPrec, rightPrec); + RelToSqlConverterUtil.convertCharLengthToLength(writer, call, leftPrec, rightPrec); break; case TRIM: RelToSqlConverterUtil.unparseTrimLR(writer, call, leftPrec, rightPrec); diff --git a/core/src/main/java/org/apache/calcite/sql/dialect/SnowflakeSqlDialect.java b/core/src/main/java/org/apache/calcite/sql/dialect/SnowflakeSqlDialect.java index 9deb0836eeea..93f782e1a1fa 100644 --- a/core/src/main/java/org/apache/calcite/sql/dialect/SnowflakeSqlDialect.java +++ b/core/src/main/java/org/apache/calcite/sql/dialect/SnowflakeSqlDialect.java @@ -28,6 +28,7 @@ import org.apache.calcite.sql.fun.SqlLibraryOperators; import org.apache.calcite.sql.parser.SqlParserPos; import org.apache.calcite.sql.type.SqlTypeName; +import org.apache.calcite.util.RelToSqlConverterUtil; import org.checkerframework.checker.nullness.qual.Nullable; @@ -62,9 +63,7 @@ public SnowflakeSqlDialect(Context context) { super.unparseCall(writer, bitOrCall, leftPrec, rightPrec); break; case CHAR_LENGTH: - SqlCall lengthCall = SqlLibraryOperators.LENGTH - .createCall(SqlParserPos.ZERO, call.getOperandList()); - super.unparseCall(writer, lengthCall, leftPrec, rightPrec); + RelToSqlConverterUtil.convertCharLengthToLength(writer, call, leftPrec, rightPrec); break; case ENDS_WITH: SqlCall endsWithCall = SqlLibraryOperators.ENDSWITH diff --git a/core/src/main/java/org/apache/calcite/sql/dialect/SqliteSqlDialect.java b/core/src/main/java/org/apache/calcite/sql/dialect/SqliteSqlDialect.java index cd809efa8b11..644e65692449 100644 --- a/core/src/main/java/org/apache/calcite/sql/dialect/SqliteSqlDialect.java +++ b/core/src/main/java/org/apache/calcite/sql/dialect/SqliteSqlDialect.java @@ -21,8 +21,6 @@ import org.apache.calcite.sql.SqlDialect; import org.apache.calcite.sql.SqlNode; import org.apache.calcite.sql.SqlWriter; -import org.apache.calcite.sql.fun.SqlLibraryOperators; -import org.apache.calcite.sql.parser.SqlParserPos; import org.apache.calcite.util.RelToSqlConverterUtil; import org.checkerframework.checker.nullness.qual.Nullable; @@ -58,9 +56,7 @@ public SqliteSqlDialect(SqlDialect.Context context) { int leftPrec, int rightPrec) { switch (call.getKind()) { case CHAR_LENGTH: - SqlCall lengthCall = SqlLibraryOperators.LENGTH - .createCall(SqlParserPos.ZERO, call.getOperandList()); - super.unparseCall(writer, lengthCall, leftPrec, rightPrec); + RelToSqlConverterUtil.convertCharLengthToLength(writer, call, leftPrec, rightPrec); break; case TRIM: RelToSqlConverterUtil.unparseTrimLR(writer, call, leftPrec, rightPrec); diff --git a/core/src/main/java/org/apache/calcite/util/RelToSqlConverterUtil.java b/core/src/main/java/org/apache/calcite/util/RelToSqlConverterUtil.java index ddb37e8dac3e..412b95829b5d 100644 --- a/core/src/main/java/org/apache/calcite/util/RelToSqlConverterUtil.java +++ b/core/src/main/java/org/apache/calcite/util/RelToSqlConverterUtil.java @@ -34,6 +34,7 @@ import org.apache.calcite.sql.SqlSpecialOperator; import org.apache.calcite.sql.SqlTypeNameSpec; import org.apache.calcite.sql.SqlWriter; +import org.apache.calcite.sql.fun.SqlLibraryOperators; import org.apache.calcite.sql.fun.SqlStdOperatorTable; import org.apache.calcite.sql.fun.SqlTrimFunction; import org.apache.calcite.sql.parser.SqlParserPos; @@ -78,6 +79,16 @@ public static void unparseHiveTrim( } } + /** + * Convert CHAR_LENGTH to LENGTH for some Dialects such as Oracle which not support CHAR_LENGTH. + */ + public static void convertCharLengthToLength(SqlWriter writer, SqlCall call, int leftPrec, + int rightPrec) { + SqlCall lengthCall = SqlLibraryOperators.LENGTH + .createCall(SqlParserPos.ZERO, call.getOperandList()); + lengthCall.getOperator().unparse(writer, lengthCall, leftPrec, rightPrec); + } + /** * For usage of TRIM(LEADING 'A' FROM 'ABCA') convert to TRIM, LTRIM and RTRIM, * can refer to BigQuery and Presto documents: diff --git a/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java b/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java index fd13824c8733..a0ac53babb07 100644 --- a/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java +++ b/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java @@ -8274,6 +8274,7 @@ private void checkLiteral2(String expression, String expected) { final String expected = "SELECT LENGTH(\"brand_name\")\n" + "FROM \"foodmart\".\"product\""; sql(query) + .withOracle().ok(expected) .withPresto().ok(expected) .withTrino().ok(expected); }