Skip to content

Commit 930ff33

Browse files
fix(snowflake): transpile DuckDB JSON_ARRAY to ARRAY_CONSTRUCT [CLAUDE] (#7497)
* fix(snowflake): transpile DuckDB JSON_ARRAY to ARRAY_CONSTRUCT [CLAUDE] DuckDB's JSON_ARRAY function has no Snowflake equivalent — Snowflake uses ARRAY_CONSTRUCT instead (JSON_ARRAY is not a recognized function). - Add JSON_ARRAY → exp.JSONArray mapping in DuckDB parser FUNCTIONS - Add exp.JSONArray → ARRAY_CONSTRUCT transform in Snowflake generator Ref: https://docs.snowflake.com/en/sql-reference/functions/array_construct * fix(snowflake): wrap JSON_ARRAY transpilation with TO_JSON for correct return type [CLAUDE] DuckDB JSON_ARRAY returns a JSON string, not a native array. ARRAY_CONSTRUCT alone returns a native array which breaks downstream JSON access operators. * fix(snowflake): use TO_VARIANT instead of TO_JSON when transpiling JSON_ARRAY [CLAUDE] DuckDB JSON_ARRAY returns type JSON, which we map to Snowflake VARIANT (see #7496). TO_JSON returns VARCHAR, breaking downstream JSON access operators like JSON_EXTRACT_PATH_TEXT. TO_VARIANT preserves the semi-structured semantics.
1 parent c1f929f commit 930ff33

3 files changed

Lines changed: 32 additions & 0 deletions

File tree

sqlglot/generators/snowflake.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -497,6 +497,9 @@ class SnowflakeGenerator(generator.Generator):
497497
exp.GetExtract: rename_func("GET"),
498498
exp.GroupConcat: lambda self, e: groupconcat_sql(self, e, sep=""),
499499
exp.If: if_sql(name="IFF", false_value="NULL"),
500+
exp.JSONArray: lambda self, e: self.func(
501+
"TO_VARIANT", self.func("ARRAY_CONSTRUCT", *e.expressions)
502+
),
500503
exp.JSONExtractArray: _json_extract_value_array_sql,
501504
exp.JSONExtractScalar: lambda self, e: self.func(
502505
"JSON_EXTRACT_PATH_TEXT", e.this, e.expression

sqlglot/parsers/duckdb.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ class DuckDBParser(parser.Parser):
130130
),
131131
"JARO_WINKLER_SIMILARITY": exp.JarowinklerSimilarity.from_arg_list,
132132
"JSON": exp.ParseJSON.from_arg_list,
133+
"JSON_ARRAY": lambda args: exp.JSONArray(expressions=args),
133134
"JSON_EXTRACT_PATH": parser.build_extract_json_with_path(exp.JSONExtract),
134135
"JSON_EXTRACT_STRING": parser.build_extract_json_with_path(exp.JSONExtractScalar),
135136
"LIST_APPEND": exp.ArrayAppend.from_arg_list,

tests/dialects/test_duckdb.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,34 @@ def test_duckdb(self):
549549
"""SELECT JSON_EXTRACT_STRING('{ "family": "anatidae", "species": [ "duck", "goose", "swan", null ] }', ['$.family', '$.species'])""",
550550
"""SELECT '{ "family": "anatidae", "species": [ "duck", "goose", "swan", null ] }' ->> ['$.family', '$.species']""",
551551
)
552+
self.validate_all(
553+
"SELECT JSON_ARRAY('a', 'b', 'c')",
554+
write={
555+
"duckdb": "SELECT JSON_ARRAY('a', 'b', 'c')",
556+
"snowflake": "SELECT TO_VARIANT(ARRAY_CONSTRUCT('a', 'b', 'c'))",
557+
},
558+
)
559+
self.validate_all(
560+
"SELECT JSON_ARRAY(NULL, 'a', 1)",
561+
write={
562+
"duckdb": "SELECT JSON_ARRAY(NULL, 'a', 1)",
563+
"snowflake": "SELECT TO_VARIANT(ARRAY_CONSTRUCT(NULL, 'a', 1))",
564+
},
565+
)
566+
self.validate_all(
567+
"SELECT JSON_ARRAY(NULL)",
568+
write={
569+
"duckdb": "SELECT JSON_ARRAY(NULL)",
570+
"snowflake": "SELECT TO_VARIANT(ARRAY_CONSTRUCT(NULL))",
571+
},
572+
)
573+
self.validate_all(
574+
"SELECT JSON_ARRAY()",
575+
write={
576+
"duckdb": "SELECT JSON_ARRAY()",
577+
"snowflake": "SELECT TO_VARIANT(ARRAY_CONSTRUCT())",
578+
},
579+
)
552580
self.validate_identity(
553581
"SELECT col FROM t WHERE JSON_EXTRACT_STRING(col, '$.id') NOT IN ('b')",
554582
"SELECT col FROM t WHERE NOT (col ->> '$.id') IN ('b')",

0 commit comments

Comments
 (0)