Adding upstream version 26.12.0.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
aa70b5e889
commit
4118582692
70 changed files with 1134 additions and 340 deletions
|
@ -15,6 +15,7 @@ from sqlglot import (
|
|||
from sqlglot.helper import logger as helper_logger
|
||||
from sqlglot.parser import logger as parser_logger
|
||||
from tests.dialects.test_dialect import Validator
|
||||
from sqlglot.optimizer.annotate_types import annotate_types
|
||||
|
||||
|
||||
class TestBigQuery(Validator):
|
||||
|
@ -196,6 +197,9 @@ LANGUAGE js AS
|
|||
self.validate_identity("CAST(x AS TIMESTAMPTZ)", "CAST(x AS TIMESTAMP)")
|
||||
self.validate_identity("CAST(x AS RECORD)", "CAST(x AS STRUCT)")
|
||||
self.validate_identity("SELECT * FROM x WHERE x.y >= (SELECT MAX(a) FROM b-c) - 20")
|
||||
self.validate_identity(
|
||||
"SELECT FORMAT_TIMESTAMP('%Y-%m-%d %H:%M:%S', CURRENT_TIMESTAMP(), 'Europe/Berlin') AS ts"
|
||||
)
|
||||
self.validate_identity(
|
||||
"SELECT cars, apples FROM some_table PIVOT(SUM(total_counts) FOR products IN ('general.cars' AS cars, 'food.apples' AS apples))"
|
||||
)
|
||||
|
@ -317,6 +321,13 @@ LANGUAGE js AS
|
|||
"SELECT CAST(1 AS INT64)",
|
||||
)
|
||||
|
||||
self.validate_all(
|
||||
"SELECT DATE_SUB(CURRENT_DATE(), INTERVAL 2 DAY)",
|
||||
write={
|
||||
"bigquery": "SELECT DATE_SUB(CURRENT_DATE, INTERVAL '2' DAY)",
|
||||
"databricks": "SELECT DATE_ADD(CURRENT_DATE, -2)",
|
||||
},
|
||||
)
|
||||
self.validate_all(
|
||||
"SELECT DATE_SUB(DATE '2008-12-25', INTERVAL 5 DAY)",
|
||||
write={
|
||||
|
@ -1309,8 +1320,8 @@ LANGUAGE js AS
|
|||
"mysql": "DATE_ADD(CURRENT_DATE, INTERVAL '-1' DAY)",
|
||||
"postgres": "CURRENT_DATE + INTERVAL '-1 DAY'",
|
||||
"presto": "DATE_ADD('DAY', CAST('-1' AS BIGINT), CURRENT_DATE)",
|
||||
"hive": "DATE_ADD(CURRENT_DATE, '-1')",
|
||||
"spark": "DATE_ADD(CURRENT_DATE, '-1')",
|
||||
"hive": "DATE_ADD(CURRENT_DATE, -1)",
|
||||
"spark": "DATE_ADD(CURRENT_DATE, -1)",
|
||||
},
|
||||
)
|
||||
self.validate_all(
|
||||
|
@ -2356,3 +2367,18 @@ OPTIONS (
|
|||
"STRING_AGG(DISTINCT a ORDER BY b DESC, c DESC LIMIT 10)",
|
||||
"STRING_AGG(DISTINCT a, ',' ORDER BY b DESC, c DESC LIMIT 10)",
|
||||
)
|
||||
|
||||
def test_annotate_timestamps(self):
|
||||
sql = """
|
||||
SELECT
|
||||
CURRENT_TIMESTAMP() AS curr_ts,
|
||||
TIMESTAMP_SECONDS(2) AS ts_seconds,
|
||||
PARSE_TIMESTAMP('%c', 'Thu Dec 25 07:30:00 2008', 'UTC') AS parsed_ts,
|
||||
TIMESTAMP_ADD(TIMESTAMP "2008-12-25 15:30:00+00", INTERVAL 10 MINUTE) AS ts_add,
|
||||
TIMESTAMP_SUB(TIMESTAMP "2008-12-25 15:30:00+00", INTERVAL 10 MINUTE) AS ts_sub,
|
||||
"""
|
||||
|
||||
annotated = annotate_types(self.parse_one(sql), dialect="bigquery")
|
||||
|
||||
for select in annotated.selects:
|
||||
self.assertEqual(select.type.sql("bigquery"), "TIMESTAMP")
|
||||
|
|
|
@ -50,6 +50,7 @@ class TestDatabricks(Validator):
|
|||
self.validate_identity(
|
||||
"COPY INTO target FROM `s3://link` FILEFORMAT = AVRO VALIDATE = ALL FILES = ('file1', 'file2') FORMAT_OPTIONS ('opt1'='true', 'opt2'='test') COPY_OPTIONS ('mergeSchema'='true')"
|
||||
)
|
||||
self.validate_identity("SELECT PARSE_JSON('{}')")
|
||||
self.validate_identity(
|
||||
"SELECT DATE_FORMAT(CAST(FROM_UTC_TIMESTAMP(foo, 'America/Los_Angeles') AS TIMESTAMP), 'yyyy-MM-dd HH:mm:ss') AS foo FROM t",
|
||||
"SELECT DATE_FORMAT(CAST(FROM_UTC_TIMESTAMP(CAST(foo AS TIMESTAMP), 'America/Los_Angeles') AS TIMESTAMP), 'yyyy-MM-dd HH:mm:ss') AS foo FROM t",
|
||||
|
|
|
@ -1569,3 +1569,29 @@ class TestDuckDB(Validator):
|
|||
""",
|
||||
"SELECT l_returnflag, l_linestatus, SUM(l_quantity) AS sum_qty, SUM(l_extendedprice) AS sum_base_price, SUM(l_extendedprice * (1 - l_discount)) AS sum_disc_price, SUM(l_extendedprice * (1 - l_discount) * (1 + l_tax)) AS sum_charge, AVG(l_quantity) AS avg_qty, AVG(l_extendedprice) AS avg_price, AVG(l_discount) AS avg_disc, COUNT(*) AS count_order",
|
||||
)
|
||||
|
||||
def test_at_sign_to_abs(self):
|
||||
self.validate_identity(
|
||||
"SELECT @col FROM t",
|
||||
"SELECT ABS(col) FROM t",
|
||||
)
|
||||
self.validate_identity(
|
||||
"SELECT @col + 1 FROM t",
|
||||
"SELECT ABS(col + 1) FROM t",
|
||||
)
|
||||
self.validate_identity(
|
||||
"SELECT (@col) + 1 FROM t",
|
||||
"SELECT (ABS(col)) + 1 FROM t",
|
||||
)
|
||||
self.validate_identity(
|
||||
"SELECT @(-1)",
|
||||
"SELECT ABS((-1))",
|
||||
)
|
||||
self.validate_identity(
|
||||
"SELECT @(-1) + 1",
|
||||
"SELECT ABS((-1) + 1)",
|
||||
)
|
||||
self.validate_identity(
|
||||
"SELECT (@-1) + 1",
|
||||
"SELECT (ABS(-1)) + 1",
|
||||
)
|
||||
|
|
|
@ -394,7 +394,7 @@ class TestSnowflake(Validator):
|
|||
"""SELECT PARSE_JSON('{"fruit":"banana"}'):fruit""",
|
||||
write={
|
||||
"bigquery": """SELECT JSON_EXTRACT(PARSE_JSON('{"fruit":"banana"}'), '$.fruit')""",
|
||||
"databricks": """SELECT '{"fruit":"banana"}':fruit""",
|
||||
"databricks": """SELECT PARSE_JSON('{"fruit":"banana"}'):fruit""",
|
||||
"duckdb": """SELECT JSON('{"fruit":"banana"}') -> '$.fruit'""",
|
||||
"mysql": """SELECT JSON_EXTRACT('{"fruit":"banana"}', '$.fruit')""",
|
||||
"presto": """SELECT JSON_EXTRACT(JSON_PARSE('{"fruit":"banana"}'), '$.fruit')""",
|
||||
|
@ -1057,6 +1057,9 @@ class TestSnowflake(Validator):
|
|||
staged_file.sql(dialect="snowflake"),
|
||||
)
|
||||
|
||||
self.validate_identity('SELECT * FROM @"mystage"')
|
||||
self.validate_identity('SELECT * FROM @"myschema"."mystage"/file.gz')
|
||||
self.validate_identity('SELECT * FROM @"my_DB"."schEMA1".mystage/file.gz')
|
||||
self.validate_identity("SELECT metadata$filename FROM @s1/")
|
||||
self.validate_identity("SELECT * FROM @~")
|
||||
self.validate_identity("SELECT * FROM @~/some/path/to/file.csv")
|
||||
|
@ -1463,6 +1466,7 @@ class TestSnowflake(Validator):
|
|||
"CREATE TABLE t (id INT TAG (key1='value_1', key2='value_2'))",
|
||||
)
|
||||
|
||||
self.validate_identity("CREATE OR REPLACE TABLE foo COPY GRANTS USING TEMPLATE (SELECT 1)")
|
||||
self.validate_identity("USE SECONDARY ROLES ALL")
|
||||
self.validate_identity("USE SECONDARY ROLES NONE")
|
||||
self.validate_identity("USE SECONDARY ROLES a, b, c")
|
||||
|
@ -2386,11 +2390,14 @@ SINGLE = TRUE""",
|
|||
)
|
||||
|
||||
def test_put_to_stage(self):
|
||||
self.validate_identity('PUT \'file:///dir/tmp.csv\' @"my_DB"."schEMA1"."MYstage"')
|
||||
|
||||
# PUT with file path and stage ref containing spaces (wrapped in single quotes)
|
||||
ast = parse_one("PUT 'file://my file.txt' '@s1/my folder'", read="snowflake")
|
||||
self.assertIsInstance(ast, exp.Put)
|
||||
self.assertEqual(ast.this, exp.Literal(this="file://my file.txt", is_string=True))
|
||||
self.assertEqual(ast.args["target"], exp.Var(this="@s1/my folder"))
|
||||
self.assertEqual(ast.args["target"], exp.Var(this="'@s1/my folder'"))
|
||||
self.assertEqual(ast.sql("snowflake"), "PUT 'file://my file.txt' '@s1/my folder'")
|
||||
|
||||
# expression with additional properties
|
||||
ast = parse_one(
|
||||
|
|
|
@ -322,6 +322,13 @@ TBLPROPERTIES (
|
|||
},
|
||||
)
|
||||
|
||||
self.validate_all(
|
||||
"SELECT id_column, name, age FROM test_table LATERAL VIEW INLINE(struc_column) explode_view AS name, age",
|
||||
write={
|
||||
"presto": "SELECT id_column, name, age FROM test_table CROSS JOIN UNNEST(struc_column) AS explode_view(name, age)",
|
||||
"spark": "SELECT id_column, name, age FROM test_table LATERAL VIEW INLINE(struc_column) explode_view AS name, age",
|
||||
},
|
||||
)
|
||||
self.validate_all(
|
||||
"SELECT ARRAY_AGG(x) FILTER (WHERE x = 5) FROM (SELECT 1 UNION ALL SELECT NULL) AS t(x)",
|
||||
write={
|
||||
|
@ -843,7 +850,7 @@ TBLPROPERTIES (
|
|||
},
|
||||
)
|
||||
|
||||
def test_explode_to_unnest(self):
|
||||
def test_explode_projection_to_unnest(self):
|
||||
self.validate_all(
|
||||
"SELECT EXPLODE(x) FROM tbl",
|
||||
write={
|
||||
|
@ -951,3 +958,42 @@ TBLPROPERTIES (
|
|||
self.validate_identity(
|
||||
"ANALYZE TABLE ctlg.db.tbl PARTITION(foo = 'foo', bar = 'bar') COMPUTE STATISTICS NOSCAN"
|
||||
)
|
||||
|
||||
def test_transpile_annotated_exploded_column(self):
|
||||
from sqlglot.optimizer.annotate_types import annotate_types
|
||||
from sqlglot.optimizer.qualify import qualify
|
||||
|
||||
for db_prefix in ("", "explode_view."):
|
||||
with self.subTest(f"Annotated exploded column with prefix: {db_prefix}."):
|
||||
sql = f"""
|
||||
WITH test_table AS (
|
||||
SELECT
|
||||
12345 AS id_column,
|
||||
ARRAY(
|
||||
STRUCT('John' AS name, 30 AS age),
|
||||
STRUCT('Mary' AS name, 20 AS age),
|
||||
STRUCT('Mike' AS name, 80 AS age),
|
||||
STRUCT('Dan' AS name, 50 AS age)
|
||||
) AS struct_column
|
||||
)
|
||||
|
||||
SELECT
|
||||
id_column,
|
||||
{db_prefix}new_column.name,
|
||||
{db_prefix}new_column.age
|
||||
FROM test_table
|
||||
LATERAL VIEW EXPLODE(struct_column) explode_view AS new_column
|
||||
"""
|
||||
|
||||
expr = self.parse_one(sql)
|
||||
qualified = qualify(expr, dialect="spark")
|
||||
annotated = annotate_types(qualified, dialect="spark")
|
||||
|
||||
self.assertEqual(
|
||||
annotated.sql("spark"),
|
||||
"WITH `test_table` AS (SELECT 12345 AS `id_column`, ARRAY(STRUCT('John' AS `name`, 30 AS `age`), STRUCT('Mary' AS `name`, 20 AS `age`), STRUCT('Mike' AS `name`, 80 AS `age`), STRUCT('Dan' AS `name`, 50 AS `age`)) AS `struct_column`) SELECT `test_table`.`id_column` AS `id_column`, `explode_view`.`new_column`.`name` AS `name`, `explode_view`.`new_column`.`age` AS `age` FROM `test_table` AS `test_table` LATERAL VIEW EXPLODE(`test_table`.`struct_column`) explode_view AS `new_column`",
|
||||
)
|
||||
self.assertEqual(
|
||||
annotated.sql("presto"),
|
||||
"""WITH "test_table" AS (SELECT 12345 AS "id_column", ARRAY[CAST(ROW('John', 30) AS ROW("name" VARCHAR, "age" INTEGER)), CAST(ROW('Mary', 20) AS ROW("name" VARCHAR, "age" INTEGER)), CAST(ROW('Mike', 80) AS ROW("name" VARCHAR, "age" INTEGER)), CAST(ROW('Dan', 50) AS ROW("name" VARCHAR, "age" INTEGER))] AS "struct_column") SELECT "test_table"."id_column" AS "id_column", "explode_view"."name" AS "name", "explode_view"."age" AS "age" FROM "test_table" AS "test_table" CROSS JOIN UNNEST("test_table"."struct_column") AS "explode_view"("name", "age")""",
|
||||
)
|
||||
|
|
|
@ -133,12 +133,25 @@ class TestTSQL(Validator):
|
|||
},
|
||||
)
|
||||
self.validate_all(
|
||||
"WITH t(c) AS (SELECT 1) SELECT * INTO TEMP UNLOGGED foo FROM (SELECT c AS c FROM t) AS temp",
|
||||
"WITH t(c) AS (SELECT 1) SELECT * INTO UNLOGGED #foo FROM (SELECT c AS c FROM t) AS temp",
|
||||
write={
|
||||
"duckdb": "CREATE TEMPORARY TABLE foo AS WITH t(c) AS (SELECT 1) SELECT * FROM (SELECT c AS c FROM t) AS temp",
|
||||
"postgres": "WITH t(c) AS (SELECT 1) SELECT * INTO TEMPORARY foo FROM (SELECT c AS c FROM t) AS temp",
|
||||
},
|
||||
)
|
||||
self.validate_all(
|
||||
"WITH t(c) AS (SELECT 1) SELECT c INTO #foo FROM t",
|
||||
read={
|
||||
"tsql": "WITH t(c) AS (SELECT 1) SELECT c INTO #foo FROM t",
|
||||
"postgres": "WITH t(c) AS (SELECT 1) SELECT c INTO TEMPORARY foo FROM t",
|
||||
},
|
||||
write={
|
||||
"tsql": "WITH t(c) AS (SELECT 1) SELECT c INTO #foo FROM t",
|
||||
"postgres": "WITH t(c) AS (SELECT 1) SELECT c INTO TEMPORARY foo FROM t",
|
||||
"duckdb": "CREATE TEMPORARY TABLE foo AS WITH t(c) AS (SELECT 1) SELECT c FROM t",
|
||||
"snowflake": "CREATE TEMPORARY TABLE foo AS WITH t(c) AS (SELECT 1) SELECT c FROM t",
|
||||
},
|
||||
)
|
||||
self.validate_all(
|
||||
"WITH t(c) AS (SELECT 1) SELECT * INTO UNLOGGED foo FROM (SELECT c AS c FROM t) AS temp",
|
||||
write={
|
||||
|
@ -151,6 +164,13 @@ class TestTSQL(Validator):
|
|||
"duckdb": "CREATE TABLE foo AS WITH t(c) AS (SELECT 1) SELECT * FROM (SELECT c AS c FROM t) AS temp",
|
||||
},
|
||||
)
|
||||
self.validate_all(
|
||||
"WITH y AS (SELECT 2 AS c) INSERT INTO #t SELECT * FROM y",
|
||||
write={
|
||||
"duckdb": "WITH y AS (SELECT 2 AS c) INSERT INTO t SELECT * FROM y",
|
||||
"postgres": "WITH y AS (SELECT 2 AS c) INSERT INTO t SELECT * FROM y",
|
||||
},
|
||||
)
|
||||
self.validate_all(
|
||||
"WITH y AS (SELECT 2 AS c) INSERT INTO t SELECT * FROM y",
|
||||
read={
|
||||
|
@ -850,6 +870,9 @@ class TestTSQL(Validator):
|
|||
)
|
||||
|
||||
def test_ddl(self):
|
||||
for colstore in ("NONCLUSTERED COLUMNSTORE", "CLUSTERED COLUMNSTORE"):
|
||||
self.validate_identity(f"CREATE {colstore} INDEX index_name ON foo.bar")
|
||||
|
||||
for view_attr in ("ENCRYPTION", "SCHEMABINDING", "VIEW_METADATA"):
|
||||
self.validate_identity(f"CREATE VIEW a.b WITH {view_attr} AS SELECT * FROM x")
|
||||
|
||||
|
@ -871,19 +894,19 @@ class TestTSQL(Validator):
|
|||
|
||||
self.validate_identity("CREATE SCHEMA testSchema")
|
||||
self.validate_identity("CREATE VIEW t AS WITH cte AS (SELECT 1 AS c) SELECT c FROM cte")
|
||||
self.validate_identity("ALTER TABLE tbl SET SYSTEM_VERSIONING=OFF")
|
||||
self.validate_identity("ALTER TABLE tbl SET FILESTREAM_ON = 'test'")
|
||||
self.validate_identity("ALTER TABLE tbl SET DATA_DELETION=ON")
|
||||
self.validate_identity("ALTER TABLE tbl SET DATA_DELETION=OFF")
|
||||
self.validate_identity(
|
||||
"ALTER TABLE tbl SET SYSTEM_VERSIONING=ON(HISTORY_TABLE=db.tbl, DATA_CONSISTENCY_CHECK=OFF, HISTORY_RETENTION_PERIOD=5 DAYS)"
|
||||
)
|
||||
self.validate_identity(
|
||||
"ALTER TABLE tbl SET SYSTEM_VERSIONING=ON(HISTORY_TABLE=db.tbl, HISTORY_RETENTION_PERIOD=INFINITE)"
|
||||
)
|
||||
self.validate_identity("ALTER TABLE tbl SET SYSTEM_VERSIONING=OFF")
|
||||
self.validate_identity("ALTER TABLE tbl SET FILESTREAM_ON = 'test'")
|
||||
self.validate_identity(
|
||||
"ALTER TABLE tbl SET DATA_DELETION=ON(FILTER_COLUMN=col, RETENTION_PERIOD=5 MONTHS)"
|
||||
)
|
||||
self.validate_identity("ALTER TABLE tbl SET DATA_DELETION=ON")
|
||||
self.validate_identity("ALTER TABLE tbl SET DATA_DELETION=OFF")
|
||||
|
||||
self.validate_identity("ALTER VIEW v AS SELECT a, b, c, d FROM foo")
|
||||
self.validate_identity("ALTER VIEW v AS SELECT * FROM foo WHERE c > 100")
|
||||
|
@ -899,10 +922,44 @@ class TestTSQL(Validator):
|
|||
"ALTER VIEW v WITH VIEW_METADATA AS SELECT * FROM foo WHERE c > 100",
|
||||
check_command_warning=True,
|
||||
)
|
||||
self.validate_identity(
|
||||
"CREATE COLUMNSTORE INDEX index_name ON foo.bar",
|
||||
"CREATE NONCLUSTERED COLUMNSTORE INDEX index_name ON foo.bar",
|
||||
)
|
||||
self.validate_identity(
|
||||
"CREATE PROCEDURE foo AS BEGIN DELETE FROM bla WHERE foo < CURRENT_TIMESTAMP - 7 END",
|
||||
"CREATE PROCEDURE foo AS BEGIN DELETE FROM bla WHERE foo < GETDATE() - 7 END",
|
||||
)
|
||||
self.validate_identity(
|
||||
"INSERT INTO Production.UpdatedInventory SELECT ProductID, LocationID, NewQty, PreviousQty FROM (MERGE INTO Production.ProductInventory AS pi USING (SELECT ProductID, SUM(OrderQty) FROM Sales.SalesOrderDetail AS sod INNER JOIN Sales.SalesOrderHeader AS soh ON sod.SalesOrderID = soh.SalesOrderID AND soh.OrderDate BETWEEN '20030701' AND '20030731' GROUP BY ProductID) AS src(ProductID, OrderQty) ON pi.ProductID = src.ProductID WHEN MATCHED AND pi.Quantity - src.OrderQty >= 0 THEN UPDATE SET pi.Quantity = pi.Quantity - src.OrderQty WHEN MATCHED AND pi.Quantity - src.OrderQty <= 0 THEN DELETE OUTPUT $action, Inserted.ProductID, Inserted.LocationID, Inserted.Quantity AS NewQty, Deleted.Quantity AS PreviousQty) AS Changes(Action, ProductID, LocationID, NewQty, PreviousQty) WHERE Action = 'UPDATE'",
|
||||
"""INSERT INTO Production.UpdatedInventory
|
||||
SELECT
|
||||
ProductID,
|
||||
LocationID,
|
||||
NewQty,
|
||||
PreviousQty
|
||||
FROM (
|
||||
MERGE INTO Production.ProductInventory AS pi
|
||||
USING (
|
||||
SELECT
|
||||
ProductID,
|
||||
SUM(OrderQty)
|
||||
FROM Sales.SalesOrderDetail AS sod
|
||||
INNER JOIN Sales.SalesOrderHeader AS soh
|
||||
ON sod.SalesOrderID = soh.SalesOrderID
|
||||
AND soh.OrderDate BETWEEN '20030701' AND '20030731'
|
||||
GROUP BY
|
||||
ProductID
|
||||
) AS src(ProductID, OrderQty)
|
||||
ON pi.ProductID = src.ProductID
|
||||
WHEN MATCHED AND pi.Quantity - src.OrderQty >= 0 THEN UPDATE SET pi.Quantity = pi.Quantity - src.OrderQty
|
||||
WHEN MATCHED AND pi.Quantity - src.OrderQty <= 0 THEN DELETE
|
||||
OUTPUT $action, Inserted.ProductID, Inserted.LocationID, Inserted.Quantity AS NewQty, Deleted.Quantity AS PreviousQty
|
||||
) AS Changes(Action, ProductID, LocationID, NewQty, PreviousQty)
|
||||
WHERE
|
||||
Action = 'UPDATE'""",
|
||||
pretty=True,
|
||||
)
|
||||
|
||||
self.validate_all(
|
||||
"CREATE TABLE [#temptest] (name INTEGER)",
|
||||
|
@ -1003,14 +1060,6 @@ class TestTSQL(Validator):
|
|||
},
|
||||
)
|
||||
|
||||
for colstore in ("NONCLUSTERED COLUMNSTORE", "CLUSTERED COLUMNSTORE"):
|
||||
self.validate_identity(f"CREATE {colstore} INDEX index_name ON foo.bar")
|
||||
|
||||
self.validate_identity(
|
||||
"CREATE COLUMNSTORE INDEX index_name ON foo.bar",
|
||||
"CREATE NONCLUSTERED COLUMNSTORE INDEX index_name ON foo.bar",
|
||||
)
|
||||
|
||||
def test_insert_cte(self):
|
||||
self.validate_all(
|
||||
"INSERT INTO foo.bar WITH cte AS (SELECT 1 AS one) SELECT * FROM cte",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue