This is an automated email from the ASF dual-hosted git repository.
guohongyu pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/calcite.git
The following commit(s) were added to refs/heads/main by this push:
new 4369e88b15 [CALCITE-6258] Map value constructor is unparsed
incorrectly for PrestoSqlDialect
4369e88b15 is described below
commit 4369e88b15a59333c05abeda38cf8799d61a8842
Author: YiwenWu <[email protected]>
AuthorDate: Sun Feb 11 12:59:33 2024 +0800
[CALCITE-6258] Map value constructor is unparsed incorrectly for
PrestoSqlDialect
---
.../calcite/sql/dialect/PrestoSqlDialect.java | 60 +++++++++++++++++++++-
.../calcite/rel/rel2sql/RelToSqlConverterTest.java | 17 ++++++
2 files changed, 75 insertions(+), 2 deletions(-)
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 de80351c3d..ddf2a10f6f 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
@@ -20,19 +20,28 @@ import org.apache.calcite.avatica.util.Casing;
import org.apache.calcite.config.NullCollation;
import org.apache.calcite.rel.type.RelDataType;
import org.apache.calcite.rel.type.RelDataTypeSystem;
+import org.apache.calcite.sql.SqlBasicCall;
import org.apache.calcite.sql.SqlCall;
import org.apache.calcite.sql.SqlDialect;
import org.apache.calcite.sql.SqlIntervalQualifier;
import org.apache.calcite.sql.SqlKind;
+import org.apache.calcite.sql.SqlLiteral;
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.SqlMapValueConstructor;
import org.apache.calcite.sql.fun.SqlStdOperatorTable;
+import org.apache.calcite.sql.parser.SqlParserPos;
import org.apache.calcite.util.RelToSqlConverterUtil;
import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
import org.checkerframework.checker.nullness.qual.Nullable;
+import java.util.ArrayList;
+import java.util.List;
+
/**
* A <code>SqlDialect</code> implementation for the Presto database.
*/
@@ -131,8 +140,14 @@ public class PrestoSqlDialect extends SqlDialect {
RelToSqlConverterUtil.specialOperatorByName("APPROX_DISTINCT")
.unparse(writer, call, 0, 0);
} else {
- // Current impl is same with Postgresql.
- PostgresqlSqlDialect.DEFAULT.unparseCall(writer, call, leftPrec,
rightPrec);
+ switch (call.getKind()) {
+ case MAP_VALUE_CONSTRUCTOR:
+ unparseMapValue(writer, call, leftPrec, rightPrec);
+ break;
+ default:
+ // Current impl is same with Postgresql.
+ PostgresqlSqlDialect.DEFAULT.unparseCall(writer, call, leftPrec,
rightPrec);
+ }
}
}
@@ -141,4 +156,45 @@ public class PrestoSqlDialect extends SqlDialect {
// Current impl is same with MySQL.
MysqlSqlDialect.DEFAULT.unparseSqlIntervalQualifier(writer, qualifier,
typeSystem);
}
+
+ /**
+ * change map open/close symbol from default [] to ().
+ */
+ private void unparseMapValue(SqlWriter writer, SqlCall call,
+ int leftPrec, int rightPrec) {
+ call = convertMapValueCall(call);
+ writer.keyword(call.getOperator().getName());
+ final SqlWriter.Frame frame = writer.startList("(", ")");
+ for (SqlNode operand : call.getOperandList()) {
+ writer.sep(",");
+ operand.unparse(writer, leftPrec, rightPrec);
+ }
+ writer.endList(frame);
+ }
+
+ /**
+ * Convert Presto MapValue call
+ * From MAP['k1','v1','k2','v2'] to MAP[ARRAY['k1', 'k2'],ARRAY['v1', 'v2']].
+ */
+ private SqlCall convertMapValueCall(SqlCall call) {
+ boolean unnestMap = call.operandCount() > 0
+ && call.getOperandList().stream().allMatch(operand -> operand
instanceof SqlLiteral);
+ if (!unnestMap) {
+ return call;
+ }
+ List<SqlNode> keys = new ArrayList<>();
+ List<SqlNode> values = new ArrayList<>();
+ for (int i = 0; i < call.operandCount(); i++) {
+ if (i % 2 == 0) {
+ keys.add(call.operand(i));
+ } else {
+ values.add(call.operand(i));
+ }
+ }
+ SqlParserPos pos = call.getParserPosition();
+ return new SqlBasicCall(
+ new SqlMapValueConstructor(), ImmutableList.of(
+ new SqlBasicCall(new SqlArrayValueConstructor(), keys, pos),
+ new SqlBasicCall(new SqlArrayValueConstructor(), values, pos)), pos);
+ }
}
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 739153345b..394aac0780 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
@@ -7876,6 +7876,23 @@ class RelToSqlConverterTest {
.withSpark().ok(sparkExpected);
}
+ /** Test case for
+ * <a
href="https://issues.apache.org/jira/browse/CALCITE-6258">[CALCITE-6258]
+ * Map value constructor is unparsed incorrectly for PrestoSqlDialect</a>.*/
+ @Test void testMapValueConstructor() {
+ final String query = "SELECT MAP['k1', 'v1', 'k2', 'v2']";
+ final String expectedPresto = "SELECT MAP (ARRAY['k1', 'k2'], ARRAY['v1',
'v2'])\n"
+ + "FROM (VALUES (0)) AS \"t\" (\"ZERO\")";
+ sql(query).withPresto().ok(expectedPresto);
+ }
+
+ @Test void testMapValueConstructorWithArray() {
+ final String query = "SELECT MAP[ARRAY['k1', 'k2'], ARRAY['v1', 'v2']]";
+ final String expectedPresto = "SELECT MAP (ARRAY['k1', 'k2'], ARRAY['v1',
'v2'])\n"
+ + "FROM (VALUES (0)) AS \"t\" (\"ZERO\")";
+ sql(query).withPresto().ok(expectedPresto);
+ }
+
/** Fluid interface to run tests. */
static class Sql {
private final CalciteAssert.SchemaSpec schemaSpec;