diff --git a/sqlglot/dialects/duckdb.py b/sqlglot/dialects/duckdb.py index 7e2736ebdb..a5a14a6cf1 100644 --- a/sqlglot/dialects/duckdb.py +++ b/sqlglot/dialects/duckdb.py @@ -1047,6 +1047,7 @@ class Parser(parser.Parser): "JSON": exp.ParseJSON.from_arg_list, "JSON_EXTRACT_PATH": parser.build_extract_json_with_path(exp.JSONExtract), "JSON_EXTRACT_STRING": parser.build_extract_json_with_path(exp.JSONExtractScalar), + "JSON_KEYS": exp.JsonKeys.from_arg_list, "LIST_APPEND": exp.ArrayAppend.from_arg_list, "LIST_CONTAINS": exp.ArrayContains.from_arg_list, "LIST_COSINE_DISTANCE": exp.CosineDistance.from_arg_list, @@ -1407,6 +1408,7 @@ class Generator(generator.Generator): exp.SHA1Digest: lambda self, e: self.func("UNHEX", self.func("SHA1", e.this)), exp.SHA2Digest: lambda self, e: self.func("UNHEX", sha2_digest_sql(self, e)), exp.MonthsBetween: months_between_sql, + exp.ObjectKeys: rename_func("JSON_KEYS"), exp.PercentileCont: rename_func("QUANTILE_CONT"), exp.PercentileDisc: rename_func("QUANTILE_DISC"), # DuckDB doesn't allow qualified columns inside of PIVOT expressions. diff --git a/sqlglot/dialects/snowflake.py b/sqlglot/dialects/snowflake.py index 6ae605c983..b096d56682 100644 --- a/sqlglot/dialects/snowflake.py +++ b/sqlglot/dialects/snowflake.py @@ -811,6 +811,7 @@ class Parser(parser.Parser): "LOCALTIMESTAMP": exp.CurrentTimestamp.from_arg_list, "NULLIFZERO": _build_if_from_nullifzero, "OBJECT_CONSTRUCT": _build_object_construct, + "OBJECT_KEYS": exp.ObjectKeys.from_arg_list, "OCTET_LENGTH": exp.ByteLength.from_arg_list, "PARSE_URL": lambda args: exp.ParseUrl( this=seq_get(args, 0), permissive=seq_get(args, 1) diff --git a/sqlglot/expressions.py b/sqlglot/expressions.py index dee433d661..d7dfa18808 100644 --- a/sqlglot/expressions.py +++ b/sqlglot/expressions.py @@ -7259,6 +7259,16 @@ class ObjectInsert(Func): } +# https://docs.snowflake.com/en/sql-reference/functions/object_keys +class ObjectKeys(Func): + pass + + +# https://duckdb.org/docs/extensions/json#json-extraction-functions +class JsonKeys(Func): + _sql_names = ["JSON_KEYS"] + + class OpenJSONColumnDef(Expression): arg_types = {"this": True, "kind": True, "path": False, "as_json": False} diff --git a/tests/dialects/test_snowflake.py b/tests/dialects/test_snowflake.py index 9cedf726c1..cf397d4d81 100644 --- a/tests/dialects/test_snowflake.py +++ b/tests/dialects/test_snowflake.py @@ -2219,6 +2219,13 @@ def test_snowflake(self): self.validate_identity("SYSDATE()") self.validate_identity("SYSTIMESTAMP()", "CURRENT_TIMESTAMP()") self.validate_identity("GETDATE()", "CURRENT_TIMESTAMP()") + self.validate_all( + "SELECT OBJECT_KEYS(my_obj)", + write={ + "snowflake": "SELECT OBJECT_KEYS(my_obj)", + "duckdb": "SELECT JSON_KEYS(my_obj)", + }, + ) self.validate_identity("LOCALTIMESTAMP", "CURRENT_TIMESTAMP") self.validate_identity("LOCALTIMESTAMP()", "CURRENT_TIMESTAMP()") self.validate_identity("LOCALTIMESTAMP(3)", "CURRENT_TIMESTAMP(3)")