Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix(parser): cast coalesce arg to text in the context of a CONCAT call #1792

Merged
merged 3 commits into from
Jun 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion sqlglot/dialects/clickhouse.py
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,7 @@ def safeconcat_sql(self, expression: exp.SafeConcat) -> str:
"CONCAT",
*[
exp.func("if", e.is_(exp.null()), e, exp.cast(e, "text"))
for e in expression.expressions
for e in t.cast(t.List[exp.Condition], expression.expressions)
],
)

Expand Down
6 changes: 3 additions & 3 deletions sqlglot/expressions.py
Original file line number Diff line number Diff line change
Expand Up @@ -3221,15 +3221,15 @@ def output_name(self) -> str:
return self.name


class Parameter(Expression):
class Parameter(Condition):
arg_types = {"this": True, "wrapped": False}


class SessionParameter(Expression):
class SessionParameter(Condition):
arg_types = {"this": True, "kind": False}


class Placeholder(Expression):
class Placeholder(Condition):
arg_types = {"this": False, "kind": False}


Expand Down
6 changes: 5 additions & 1 deletion sqlglot/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -3655,7 +3655,11 @@ def _parse_cast(self, strict: bool) -> exp.Expression:
def _parse_concat(self) -> t.Optional[exp.Expression]:
args = self._parse_csv(self._parse_conjunction)
if self.CONCAT_NULL_OUTPUTS_STRING:
args = [exp.func("COALESCE", arg, exp.Literal.string("")) for arg in args]
args = [
exp.func("COALESCE", exp.cast(arg, "text"), exp.Literal.string(""))
for arg in args
if arg
]

# Some dialects (e.g. Trino) don't allow a single-argument CONCAT call, so when
# we find such a call we replace it with its argument.
Expand Down
2 changes: 1 addition & 1 deletion tests/dialects/test_clickhouse.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ def test_clickhouse(self):
)

self.validate_all(
"CONCAT(CASE WHEN COALESCE(a, '') IS NULL THEN COALESCE(a, '') ELSE CAST(COALESCE(a, '') AS TEXT) END, CASE WHEN COALESCE(b, '') IS NULL THEN COALESCE(b, '') ELSE CAST(COALESCE(b, '') AS TEXT) END)",
"CONCAT(CASE WHEN COALESCE(CAST(a AS TEXT), '') IS NULL THEN COALESCE(CAST(a AS TEXT), '') ELSE CAST(COALESCE(CAST(a AS TEXT), '') AS TEXT) END, CASE WHEN COALESCE(CAST(b AS TEXT), '') IS NULL THEN COALESCE(CAST(b AS TEXT), '') ELSE CAST(COALESCE(CAST(b AS TEXT), '') AS TEXT) END)",
read={"postgres": "CONCAT(a, b)"},
)
self.validate_all(
Expand Down
2 changes: 1 addition & 1 deletion tests/dialects/test_dialect.py
Original file line number Diff line number Diff line change
Expand Up @@ -1192,7 +1192,7 @@ def test_operators(self):
},
)
self.validate_all(
"COALESCE(a, '')",
"COALESCE(CAST(a AS TEXT), '')",
read={
"drill": "CONCAT(a)",
"duckdb": "CONCAT(a)",
Expand Down
14 changes: 10 additions & 4 deletions tests/dialects/test_postgres.py
Original file line number Diff line number Diff line change
Expand Up @@ -577,13 +577,19 @@ def test_bool_or(self):
)

def test_string_concat(self):
self.validate_all(
"SELECT CONCAT('abcde', 2, NULL, 22)",
write={
"postgres": "SELECT CONCAT(COALESCE(CAST('abcde' AS TEXT), ''), COALESCE(CAST(2 AS TEXT), ''), COALESCE(CAST(NULL AS TEXT), ''), COALESCE(CAST(22 AS TEXT), ''))",
},
)
self.validate_all(
"CONCAT(a, b)",
write={
"": "CONCAT(COALESCE(a, ''), COALESCE(b, ''))",
"duckdb": "CONCAT(COALESCE(a, ''), COALESCE(b, ''))",
"postgres": "CONCAT(COALESCE(a, ''), COALESCE(b, ''))",
"presto": "CONCAT(CAST(COALESCE(a, '') AS VARCHAR), CAST(COALESCE(b, '') AS VARCHAR))",
"": "CONCAT(COALESCE(CAST(a AS TEXT), ''), COALESCE(CAST(b AS TEXT), ''))",
"duckdb": "CONCAT(COALESCE(CAST(a AS TEXT), ''), COALESCE(CAST(b AS TEXT), ''))",
"postgres": "CONCAT(COALESCE(CAST(a AS TEXT), ''), COALESCE(CAST(b AS TEXT), ''))",
georgesittas marked this conversation as resolved.
Show resolved Hide resolved
"presto": "CONCAT(CAST(COALESCE(CAST(a AS VARCHAR), '') AS VARCHAR), CAST(COALESCE(CAST(b AS VARCHAR), '') AS VARCHAR))",
},
)
self.validate_all(
Expand Down