Skip to content
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
19 changes: 17 additions & 2 deletions sqlglot/generators/presto.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
regexp_extract_sql,
rename_func,
right_to_substring_sql,
sha256_sql,
strposition_sql,
struct_extract_sql,
timestamptrunc_sql,
Expand Down Expand Up @@ -385,7 +384,6 @@ class PrestoGenerator(generator.Generator):
exp.MD5Digest: rename_func("MD5"),
exp.SHA: rename_func("SHA1"),
exp.SHA1Digest: rename_func("SHA1"),
exp.SHA2: sha256_sql,
exp.SHA2Digest: sha2_digest_sql,
exp.Substring: rename_func("SUBSTR"),
}
Expand Down Expand Up @@ -503,6 +501,23 @@ def md5_sql(self, expression: exp.MD5) -> str:

return self.func("LOWER", self.func("TO_HEX", self.func("MD5", self.sql(this))))

def sha2_sql(self, expression: exp.SHA2) -> str:
length = expression.text("length") or "256"
if length not in ("256", "512"):
self.unsupported(f"SHA{length} is not supported in Presto")

this = expression.this

if not this.type:
from sqlglot.optimizer.annotate_types import annotate_types

this = annotate_types(this, dialect=self.dialect)

Comment on lines +511 to +515

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's remove this. For transpilation purposes, nowadays we assume that type inference has ran separately and thus we expect is_type on its own to suffice.

Just need to make sure the Presto functions roundtrip unaffected by default, i.e., when there aren't any type annotations in the AST. I think this is already the case, just double-checking.

if this.is_type(*exp.DataType.TEXT_TYPES):
this = exp.Encode(this=this, charset=exp.Literal.string("utf-8"))

return self.func("LOWER", self.func("TO_HEX", self.func(f"SHA{length}", self.sql(this))))

def strtounix_sql(self, expression: exp.StrToUnix) -> str:
# Since `TO_UNIXTIME` requires a `TIMESTAMP`, we need to parse the argument into one.
# To do this, we first try to `DATE_PARSE` it, but since this can fail when there's a
Expand Down
8 changes: 6 additions & 2 deletions sqlglot/parsers/presto.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,12 @@ class PrestoParser(parser.Parser):
this=seq_get(args, 0), charset=exp.Literal.string("utf-8")
),
"MD5": exp.MD5Digest.from_arg_list,
"SHA256": lambda args: exp.SHA2(this=seq_get(args, 0), length=exp.Literal.number(256)),
"SHA512": lambda args: exp.SHA2(this=seq_get(args, 0), length=exp.Literal.number(512)),
"SHA256": lambda args: exp.SHA2Digest(
this=seq_get(args, 0), length=exp.Literal.number(256)
),
"SHA512": lambda args: exp.SHA2Digest(
this=seq_get(args, 0), length=exp.Literal.number(512)
),
"WEEK": exp.WeekOfYear.from_arg_list,
}

Expand Down
4 changes: 2 additions & 2 deletions tests/dialects/test_bigquery.py
Original file line number Diff line number Diff line change
Expand Up @@ -1173,8 +1173,8 @@ def test_bigquery(self):
"clickhouse": "SHA512(x)",
"bigquery": "SHA512(x)",
"spark2": "SHA2(x, 512)",
"presto": "SHA512(x)",
"trino": "SHA512(x)",
"presto": "LOWER(TO_HEX(SHA512(x)))",
"trino": "LOWER(TO_HEX(SHA512(x)))",
},
Comment on lines +1176 to 1178

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should add a test where you annotate types in the ast you get after parsing with bigquery, so that the transpilation path with is_type is reached in a realistic scenario.

)
self.validate_all(
Expand Down
12 changes: 4 additions & 8 deletions tests/dialects/test_exasol.py
Original file line number Diff line number Diff line change
Expand Up @@ -754,8 +754,6 @@ def test_scalar(self):
"HASH_SHA256(x)",
read={
"clickhouse": "SHA256(x)",
"presto": "SHA256(x)",
"trino": "SHA256(x)",
"postgres": "SHA256(x)",
"duckdb": "SHA256(x)",
},
Expand All @@ -765,9 +763,9 @@ def test_scalar(self):
"spark2": "SHA2(x, 256)",
"clickhouse": "SHA256(x)",
"postgres": "SHA256(x)",
"presto": "SHA256(x)",
"presto": "LOWER(TO_HEX(SHA256(x)))",
"redshift": "SHA2(x, 256)",
"trino": "SHA256(x)",
"trino": "LOWER(TO_HEX(SHA256(x)))",
"duckdb": "SHA256(x)",
"snowflake": "SHA2(x, 256)",
},
Expand All @@ -776,16 +774,14 @@ def test_scalar(self):
"HASH_SHA512(x)",
read={
"clickhouse": "SHA512(x)",
"presto": "SHA512(x)",
"trino": "SHA512(x)",
},
write={
"exasol": "HASH_SHA512(x)",
"clickhouse": "SHA512(x)",
"bigquery": "SHA512(x)",
"spark2": "SHA2(x, 512)",
"presto": "SHA512(x)",
"trino": "SHA512(x)",
"presto": "LOWER(TO_HEX(SHA512(x)))",
"trino": "LOWER(TO_HEX(SHA512(x)))",
},
)
self.validate_all(
Expand Down
41 changes: 41 additions & 0 deletions tests/dialects/test_presto.py
Original file line number Diff line number Diff line change
Expand Up @@ -710,6 +710,47 @@ def test_presto(self):
"LOWER(TO_HEX(MD5(TO_UTF8(CONCAT(CAST(x AS VARCHAR), CAST('s' AS VARCHAR))))))",
)

self.assertEqual(
exp.func("sha2", exp.cast("x", "text"), exp.Literal.number(256)).sql(dialect="presto"),
"LOWER(TO_HEX(SHA256(TO_UTF8(CAST(x AS VARCHAR)))))",
)

# native SHA256/SHA512 take and return VARBINARY, so they parse as
# SHA2Digest and round-trip untouched, mirroring MD5 -> MD5Digest
self.validate_all(
"SELECT SHA256(x)",
write={
"presto": "SELECT SHA256(x)",
"trino": "SELECT SHA256(x)",
"duckdb": "SELECT UNHEX(SHA256(x))",
"bigquery": "SELECT SHA256(x)",
},
)
self.validate_all(
"SELECT SHA512(x)",
write={
"presto": "SELECT SHA512(x)",
"trino": "SELECT SHA512(x)",
"bigquery": "SELECT SHA512(x)",
},
)

# string-semantics SHA2 renders hex output like md5_sql does for MD5
self.validate_all(
"SELECT SHA2(x, 256)",
write={
"presto": "SELECT LOWER(TO_HEX(SHA256(x)))",
"trino": "SELECT LOWER(TO_HEX(SHA256(x)))",
},
)
self.validate_all(
"SELECT SHA2(x, 512)",
write={
"presto": "SELECT LOWER(TO_HEX(SHA512(x)))",
"trino": "SELECT LOWER(TO_HEX(SHA512(x)))",
},
)

Comment on lines +738 to +753

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These aren't valid presto inputs afaict, i.e., SHA2(x, 256) and SHA2(x, 512). We should use read={...} and use a dialect that supports these calls to demonstrate actual transpilation so that the test is well-formed.

with self.assertLogs(helper_logger):
self.validate_all(
"SELECT COALESCE(ELEMENT_AT(MAP_FROM_ENTRIES(ARRAY[(51, '1')]), id), quantity) FROM my_table",
Expand Down
Loading