polyglot-sql 0.3.3__tar.gz → 0.3.5__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/Cargo.lock +5 -5
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/Cargo.toml +1 -1
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/PKG-INFO +1 -1
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/Cargo.toml +1 -1
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/builder.rs +1 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/databricks.rs +106 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/fabric.rs +11 -22
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/hive.rs +6 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/mod.rs +182 -4
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/mysql.rs +23 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/snowflake.rs +31 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/spark.rs +6 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/sqlite.rs +201 -5
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/tsql.rs +86 -4
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/expressions.rs +4 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/generator.rs +69 -54
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/parser.rs +225 -28
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/tests/dialect_matrix.rs +84 -0
- polyglot_sql-0.3.5/crates/polyglot-sql/tests/fabric_regression.rs +85 -0
- polyglot_sql-0.3.5/crates/polyglot-sql/tests/postgres_sqlite_regression.rs +155 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/tests/snowflake_regression_test.rs +102 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/tests/tpch_transpile_stack.rs +5 -2
- polyglot_sql-0.3.5/crates/polyglot-sql/tests/tsql_regression.rs +85 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/tests/test_compat.py +2 -2
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/README.md +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/README.md +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/benches/in_list.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/benches/parsing.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/benches/rust_parsing.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/benches/transpile.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/examples/basic_usage.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/examples/bench_json.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/ast_transforms.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/athena.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/bigquery.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/clickhouse.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/cockroachdb.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/datafusion.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/doris.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/dremio.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/drill.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/druid.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/duckdb.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/dune.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/exasol.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/generic.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/materialize.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/oracle.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/postgres.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/presto.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/redshift.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/risingwave.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/singlestore.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/solr.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/starrocks.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/tableau.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/teradata.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/tidb.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/trino.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/diff.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/error.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/function_catalog.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/function_registry.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/helper.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/lib.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/lineage.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/optimizer/annotate_types.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/optimizer/canonicalize.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/optimizer/eliminate_ctes.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/optimizer/eliminate_joins.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/optimizer/isolate_table_selects.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/optimizer/mod.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/optimizer/normalize.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/optimizer/normalize_identifiers.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/optimizer/optimize_joins.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/optimizer/optimizer.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/optimizer/pushdown_predicates.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/optimizer/pushdown_projections.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/optimizer/qualify_columns.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/optimizer/qualify_tables.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/optimizer/simplify.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/optimizer/subquery.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/planner.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/resolver.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/schema.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/scope.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/time.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/tokens.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/transforms.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/traversal.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/trie.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/validation/tests.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/validation.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/tests/analyze_failures.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/tests/clickhouse_regression.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/tests/common/known_failures.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/tests/common/mod.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/tests/common/test_data.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/tests/common/test_runner.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/tests/custom_clickhouse_coverage.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/tests/custom_clickhouse_parser.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/tests/custom_dialect.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/tests/custom_dialect_tests.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/tests/custom_fixtures/datafusion/ddl.json +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/tests/custom_fixtures/datafusion/dml.json +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/tests/custom_fixtures/datafusion/functions.json +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/tests/custom_fixtures/datafusion/identity.json +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/tests/custom_fixtures/datafusion/operators.json +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/tests/custom_fixtures/datafusion/select.json +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/tests/custom_fixtures/datafusion/transpilation.json +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/tests/custom_fixtures/datafusion/types.json +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/tests/deep_nesting_regression.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/tests/error_handling.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/tests/identity_roundtrip.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/tests/sqlglot_compat.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/tests/sqlglot_dialect_identity.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/tests/sqlglot_identity.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/tests/sqlglot_identity_detailed.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/tests/sqlglot_parser.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/tests/sqlglot_pretty.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/tests/sqlglot_transpilation.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/tests/sqlglot_transpile.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql/tests/transform_regression.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql-function-catalogs/Cargo.toml +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql-function-catalogs/README.md +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql-function-catalogs/src/clickhouse.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql-function-catalogs/src/duckdb.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql-function-catalogs/src/lib.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql-function-catalogs/tools/clickhouse/extract_functions.py +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql-function-catalogs/tools/duckdb/extract_functions.py +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/Cargo.toml +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/README.md +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/docs/api.md +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/docs/index.md +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/mkdocs.yml +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/src/annotate_types.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/src/dialects.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/src/diff.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/src/errors.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/src/expr.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/src/expr_types.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/src/format.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/src/generate.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/src/helpers.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/src/lib.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/src/lineage.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/src/optimize.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/src/parse.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/src/tokenize.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/src/transpile.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/src/types.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/src/validate.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/tests/conftest.py +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/tests/test_dialects.py +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/tests/test_diff.py +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/tests/test_expression.py +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/tests/test_format.py +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/tests/test_generate.py +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/tests/test_lineage.py +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/tests/test_optimize.py +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/tests/test_parse.py +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/tests/test_transpile.py +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/tests/test_validate.py +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/uv.lock +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/pyproject.toml +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/python/polyglot_sql/__init__.py +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/python/polyglot_sql/__init__.pyi +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.5}/python/polyglot_sql/py.typed +0 -0
|
@@ -605,7 +605,7 @@ dependencies = [
|
|
|
605
605
|
|
|
606
606
|
[[package]]
|
|
607
607
|
name = "polyglot-sql"
|
|
608
|
-
version = "0.3.
|
|
608
|
+
version = "0.3.5"
|
|
609
609
|
dependencies = [
|
|
610
610
|
"criterion",
|
|
611
611
|
"once_cell",
|
|
@@ -621,7 +621,7 @@ dependencies = [
|
|
|
621
621
|
|
|
622
622
|
[[package]]
|
|
623
623
|
name = "polyglot-sql-ffi"
|
|
624
|
-
version = "0.3.
|
|
624
|
+
version = "0.3.5"
|
|
625
625
|
dependencies = [
|
|
626
626
|
"cbindgen",
|
|
627
627
|
"polyglot-sql",
|
|
@@ -631,11 +631,11 @@ dependencies = [
|
|
|
631
631
|
|
|
632
632
|
[[package]]
|
|
633
633
|
name = "polyglot-sql-function-catalogs"
|
|
634
|
-
version = "0.3.
|
|
634
|
+
version = "0.3.5"
|
|
635
635
|
|
|
636
636
|
[[package]]
|
|
637
637
|
name = "polyglot-sql-python"
|
|
638
|
-
version = "0.3.
|
|
638
|
+
version = "0.3.5"
|
|
639
639
|
dependencies = [
|
|
640
640
|
"polyglot-sql",
|
|
641
641
|
"pyo3",
|
|
@@ -646,7 +646,7 @@ dependencies = [
|
|
|
646
646
|
|
|
647
647
|
[[package]]
|
|
648
648
|
name = "polyglot-sql-wasm"
|
|
649
|
-
version = "0.3.
|
|
649
|
+
version = "0.3.5"
|
|
650
650
|
dependencies = [
|
|
651
651
|
"console_error_panic_hook",
|
|
652
652
|
"js-sys",
|
|
@@ -83,7 +83,7 @@ thiserror = { workspace = true }
|
|
|
83
83
|
unicode-segmentation = { workspace = true }
|
|
84
84
|
stacker = { version = "0.1", optional = true }
|
|
85
85
|
ts-rs = { version = "12.0", features = ["serde-compat"], optional = true }
|
|
86
|
-
polyglot-sql-function-catalogs = { path = "../polyglot-sql-function-catalogs", version = "0.3.
|
|
86
|
+
polyglot-sql-function-catalogs = { path = "../polyglot-sql-function-catalogs", version = "0.3.5", optional = true, default-features = false }
|
|
87
87
|
|
|
88
88
|
[dev-dependencies]
|
|
89
89
|
pretty_assertions = "1.4"
|
|
@@ -37,6 +37,12 @@ impl DialectImpl for DatabricksDialect {
|
|
|
37
37
|
config
|
|
38
38
|
.keywords
|
|
39
39
|
.insert("DIV".to_string(), crate::tokens::TokenType::Div);
|
|
40
|
+
config
|
|
41
|
+
.keywords
|
|
42
|
+
.insert("REPAIR".to_string(), crate::tokens::TokenType::Command);
|
|
43
|
+
config
|
|
44
|
+
.keywords
|
|
45
|
+
.insert("MSCK".to_string(), crate::tokens::TokenType::Command);
|
|
40
46
|
// Databricks numeric literal suffixes (same as Hive/Spark)
|
|
41
47
|
config
|
|
42
48
|
.numeric_literals
|
|
@@ -1009,4 +1015,104 @@ mod tests {
|
|
|
1009
1015
|
"FROM_UTC_TIMESTAMP with existing CAST failed"
|
|
1010
1016
|
);
|
|
1011
1017
|
}
|
|
1018
|
+
|
|
1019
|
+
#[test]
|
|
1020
|
+
fn test_deep_clone_version_as_of() {
|
|
1021
|
+
let sql = "CREATE TABLE events_clone DEEP CLONE events VERSION AS OF 5";
|
|
1022
|
+
let d = Dialect::get(DialectType::Databricks);
|
|
1023
|
+
let ast = d.parse(sql).expect("Parse failed");
|
|
1024
|
+
let output = d.generate(&ast[0]).expect("Generate failed");
|
|
1025
|
+
|
|
1026
|
+
assert_eq!(output, sql);
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
#[test]
|
|
1030
|
+
fn test_deep_clone_timestamp_as_of() {
|
|
1031
|
+
let sql = "CREATE TABLE events_clone DEEP CLONE events TIMESTAMP AS OF '2024-01-01'";
|
|
1032
|
+
let d = Dialect::get(DialectType::Databricks);
|
|
1033
|
+
let ast = d.parse(sql).expect("Parse failed");
|
|
1034
|
+
let output = d.generate(&ast[0]).expect("Generate failed");
|
|
1035
|
+
|
|
1036
|
+
assert_eq!(output, sql);
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
#[test]
|
|
1040
|
+
fn test_shallow_clone_still_roundtrips() {
|
|
1041
|
+
let sql = "CREATE TABLE events_clone SHALLOW CLONE events";
|
|
1042
|
+
let d = Dialect::get(DialectType::Databricks);
|
|
1043
|
+
let ast = d.parse(sql).expect("Parse failed");
|
|
1044
|
+
let output = d.generate(&ast[0]).expect("Generate failed");
|
|
1045
|
+
|
|
1046
|
+
assert_eq!(output, sql);
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
#[test]
|
|
1050
|
+
fn test_repair_table_commands_roundtrip() {
|
|
1051
|
+
let d = Dialect::get(DialectType::Databricks);
|
|
1052
|
+
let cases = [
|
|
1053
|
+
"REPAIR TABLE events",
|
|
1054
|
+
"MSCK REPAIR TABLE events",
|
|
1055
|
+
"REPAIR TABLE events ADD PARTITIONS",
|
|
1056
|
+
"REPAIR TABLE events DROP PARTITIONS",
|
|
1057
|
+
"REPAIR TABLE events SYNC PARTITIONS",
|
|
1058
|
+
"REPAIR TABLE events SYNC METADATA",
|
|
1059
|
+
];
|
|
1060
|
+
|
|
1061
|
+
for sql in cases {
|
|
1062
|
+
let ast = d.parse(sql).expect("Parse failed");
|
|
1063
|
+
let output = d.generate(&ast[0]).expect("Generate failed");
|
|
1064
|
+
assert_eq!(output, sql);
|
|
1065
|
+
}
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1068
|
+
#[test]
|
|
1069
|
+
fn test_apply_changes_commands_roundtrip() {
|
|
1070
|
+
let d = Dialect::get(DialectType::Databricks);
|
|
1071
|
+
let cases = [
|
|
1072
|
+
"APPLY CHANGES INTO silver.orders FROM STREAM(bronze.orders) KEYS (id) SEQUENCE BY ts",
|
|
1073
|
+
"APPLY CHANGES INTO LIVE.silver_orders FROM STREAM(LIVE.bronze_orders) KEYS (id) IGNORE NULL UPDATES SEQUENCE BY ts",
|
|
1074
|
+
"APPLY CHANGES INTO LIVE.silver_orders FROM STREAM(LIVE.bronze_orders) KEYS (id) APPLY AS DELETE WHEN operation = 'DELETE' SEQUENCE BY ts COLUMNS * EXCEPT (operation) STORED AS SCD TYPE 1",
|
|
1075
|
+
"APPLY CHANGES INTO LIVE.silver_orders FROM STREAM(LIVE.bronze_orders) KEYS (id) SEQUENCE BY ts STORED AS SCD TYPE 2 TRACK HISTORY ON * EXCEPT (updated_at)",
|
|
1076
|
+
"AUTO CDC INTO silver.orders FROM STREAM(bronze.orders) KEYS (id) SEQUENCE BY ts",
|
|
1077
|
+
"CREATE FLOW apply_cdc AS AUTO CDC INTO silver.orders FROM STREAM(bronze.orders) KEYS (id) SEQUENCE BY ts",
|
|
1078
|
+
];
|
|
1079
|
+
|
|
1080
|
+
for sql in cases {
|
|
1081
|
+
let ast = d.parse(sql).expect("Parse failed");
|
|
1082
|
+
let output = d.generate(&ast[0]).expect("Generate failed");
|
|
1083
|
+
assert_eq!(output, sql);
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1087
|
+
#[test]
|
|
1088
|
+
fn test_generate_symlink_format_manifest_roundtrip() {
|
|
1089
|
+
let d = Dialect::get(DialectType::Databricks);
|
|
1090
|
+
let cases = [
|
|
1091
|
+
"GENERATE symlink_format_manifest FOR TABLE events",
|
|
1092
|
+
"GENERATE symlink_format_manifest FOR TABLE catalog.schema.events",
|
|
1093
|
+
];
|
|
1094
|
+
|
|
1095
|
+
for sql in cases {
|
|
1096
|
+
let ast = d.parse(sql).expect("Parse failed");
|
|
1097
|
+
let output = d.generate(&ast[0]).expect("Generate failed");
|
|
1098
|
+
assert_eq!(output, sql);
|
|
1099
|
+
}
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
#[test]
|
|
1103
|
+
fn test_convert_to_delta_roundtrip() {
|
|
1104
|
+
let d = Dialect::get(DialectType::Databricks);
|
|
1105
|
+
let cases = [
|
|
1106
|
+
"CONVERT TO DELTA parquet.`/mnt/data/events`",
|
|
1107
|
+
"CONVERT TO DELTA database_name.table_name",
|
|
1108
|
+
"CONVERT TO DELTA parquet.`s3://my-bucket/path/to/table` PARTITIONED BY (date DATE)",
|
|
1109
|
+
"CONVERT TO DELTA database_name.table_name NO STATISTICS",
|
|
1110
|
+
];
|
|
1111
|
+
|
|
1112
|
+
for sql in cases {
|
|
1113
|
+
let ast = d.parse(sql).expect("Parse failed");
|
|
1114
|
+
let output = d.generate(&ast[0]).expect("Generate failed");
|
|
1115
|
+
assert_eq!(output, sql);
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1012
1118
|
}
|
|
@@ -42,6 +42,7 @@ impl DialectImpl for FabricDialect {
|
|
|
42
42
|
identifier_quote: '[',
|
|
43
43
|
identifier_quote_style: IdentifierQuoteStyle::BRACKET,
|
|
44
44
|
dialect: Some(DialectType::Fabric),
|
|
45
|
+
null_ordering_supported: false,
|
|
45
46
|
..Default::default()
|
|
46
47
|
}
|
|
47
48
|
}
|
|
@@ -63,7 +64,14 @@ impl DialectImpl for FabricDialect {
|
|
|
63
64
|
}
|
|
64
65
|
_ => {}
|
|
65
66
|
}
|
|
66
|
-
// Also transform column data types through Fabric's type mappings
|
|
67
|
+
// Also transform column data types through Fabric's type mappings.
|
|
68
|
+
// Apply TSQL normalisation first (e.g. BPCHAR → Char), then Fabric-specific.
|
|
69
|
+
let tsql = TSQLDialect;
|
|
70
|
+
if let Ok(Expression::DataType(tsql_dt)) =
|
|
71
|
+
tsql.transform_data_type(col.data_type.clone())
|
|
72
|
+
{
|
|
73
|
+
col.data_type = tsql_dt;
|
|
74
|
+
}
|
|
67
75
|
if let Expression::DataType(new_dt) =
|
|
68
76
|
self.transform_fabric_data_type(col.data_type.clone())?
|
|
69
77
|
{
|
|
@@ -361,7 +369,8 @@ impl FabricDialect {
|
|
|
361
369
|
let upper = name.to_uppercase();
|
|
362
370
|
|
|
363
371
|
// Parse out precision and scale if present: "TYPENAME(n)" or "TYPENAME(n, m)"
|
|
364
|
-
let (base_name, precision, scale) =
|
|
372
|
+
let (base_name, precision, scale) =
|
|
373
|
+
TSQLDialect::parse_type_precision_and_scale(&upper);
|
|
365
374
|
|
|
366
375
|
match base_name.as_str() {
|
|
367
376
|
// DATETIME -> DATETIME2(6)
|
|
@@ -518,24 +527,4 @@ impl FabricDialect {
|
|
|
518
527
|
None => max, // Default to max if not specified
|
|
519
528
|
}
|
|
520
529
|
}
|
|
521
|
-
|
|
522
|
-
/// Parse type name and optional precision/scale from strings like "DATETIME2(7)" or "NUMERIC(10, 2)"
|
|
523
|
-
fn parse_type_precision_and_scale(name: &str) -> (String, Option<u32>, Option<u32>) {
|
|
524
|
-
if let Some(paren_pos) = name.find('(') {
|
|
525
|
-
let base = name[..paren_pos].to_string();
|
|
526
|
-
let rest = &name[paren_pos + 1..];
|
|
527
|
-
if let Some(close_pos) = rest.find(')') {
|
|
528
|
-
let args = &rest[..close_pos];
|
|
529
|
-
let parts: Vec<&str> = args.split(',').map(|s| s.trim()).collect();
|
|
530
|
-
|
|
531
|
-
let precision = parts.first().and_then(|s| s.parse::<u32>().ok());
|
|
532
|
-
let scale = parts.get(1).and_then(|s| s.parse::<u32>().ok());
|
|
533
|
-
|
|
534
|
-
return (base, precision, scale);
|
|
535
|
-
}
|
|
536
|
-
(base, None, None)
|
|
537
|
-
} else {
|
|
538
|
-
(name.to_string(), None, None)
|
|
539
|
-
}
|
|
540
|
-
}
|
|
541
530
|
}
|
|
@@ -42,6 +42,12 @@ impl DialectImpl for HiveDialect {
|
|
|
42
42
|
config
|
|
43
43
|
.keywords
|
|
44
44
|
.insert("DIV".to_string(), crate::tokens::TokenType::Div);
|
|
45
|
+
config
|
|
46
|
+
.keywords
|
|
47
|
+
.insert("REPAIR".to_string(), crate::tokens::TokenType::Command);
|
|
48
|
+
config
|
|
49
|
+
.keywords
|
|
50
|
+
.insert("MSCK".to_string(), crate::tokens::TokenType::Command);
|
|
45
51
|
// Hive numeric literal suffixes: 1L -> BIGINT, 1S -> SMALLINT, etc.
|
|
46
52
|
config
|
|
47
53
|
.numeric_literals
|
|
@@ -158,10 +158,10 @@ pub use trino::TrinoDialect;
|
|
|
158
158
|
pub use tsql::TSQLDialect;
|
|
159
159
|
|
|
160
160
|
use crate::error::Result;
|
|
161
|
-
use crate::expressions::{Expression, FunctionBody, Null};
|
|
161
|
+
use crate::expressions::{Expression, Function, FunctionBody, Identifier, Null};
|
|
162
162
|
use crate::generator::{Generator, GeneratorConfig};
|
|
163
163
|
use crate::parser::Parser;
|
|
164
|
-
use crate::tokens::{Token, Tokenizer, TokenizerConfig};
|
|
164
|
+
use crate::tokens::{Token, TokenType, Tokenizer, TokenizerConfig};
|
|
165
165
|
use serde::{Deserialize, Serialize};
|
|
166
166
|
use std::collections::HashMap;
|
|
167
167
|
use std::sync::{Arc, LazyLock, RwLock};
|
|
@@ -3750,6 +3750,11 @@ impl Dialect {
|
|
|
3750
3750
|
pretty: bool,
|
|
3751
3751
|
) -> Result<Vec<String>> {
|
|
3752
3752
|
let target = target_dialect.dialect_type;
|
|
3753
|
+
if matches!(self.dialect_type, DialectType::PostgreSQL)
|
|
3754
|
+
&& matches!(target, DialectType::SQLite)
|
|
3755
|
+
{
|
|
3756
|
+
self.reject_pgvector_distance_operators_for_sqlite(sql)?;
|
|
3757
|
+
}
|
|
3753
3758
|
let expressions = self.parse(sql)?;
|
|
3754
3759
|
let generic_identity =
|
|
3755
3760
|
self.dialect_type == DialectType::Generic && target == DialectType::Generic;
|
|
@@ -4063,6 +4068,14 @@ impl Dialect {
|
|
|
4063
4068
|
let normalized =
|
|
4064
4069
|
Self::cross_dialect_normalize(normalized, self.dialect_type, target)?;
|
|
4065
4070
|
|
|
4071
|
+
let normalized = if matches!(self.dialect_type, DialectType::PostgreSQL)
|
|
4072
|
+
&& matches!(target, DialectType::SQLite)
|
|
4073
|
+
{
|
|
4074
|
+
Self::normalize_postgres_to_sqlite_types(normalized)?
|
|
4075
|
+
} else {
|
|
4076
|
+
normalized
|
|
4077
|
+
};
|
|
4078
|
+
|
|
4066
4079
|
// For DuckDB target from BigQuery source: wrap UNNEST of struct arrays in
|
|
4067
4080
|
// (SELECT UNNEST(..., max_depth => 2)) subquery
|
|
4068
4081
|
// Must run BEFORE unnest_alias_to_column_alias since it changes alias structure
|
|
@@ -4222,6 +4235,77 @@ impl Dialect {
|
|
|
4222
4235
|
// Transpile-only methods: cross-dialect normalization and helpers
|
|
4223
4236
|
#[cfg(feature = "transpile")]
|
|
4224
4237
|
impl Dialect {
|
|
4238
|
+
fn reject_pgvector_distance_operators_for_sqlite(&self, sql: &str) -> Result<()> {
|
|
4239
|
+
let tokens = self.tokenize(sql)?;
|
|
4240
|
+
for (i, token) in tokens.iter().enumerate() {
|
|
4241
|
+
if token.token_type == TokenType::NullsafeEq {
|
|
4242
|
+
return Err(crate::error::Error::unsupported(
|
|
4243
|
+
"PostgreSQL pgvector cosine distance operator <=>",
|
|
4244
|
+
"SQLite",
|
|
4245
|
+
));
|
|
4246
|
+
}
|
|
4247
|
+
if token.token_type == TokenType::Lt
|
|
4248
|
+
&& tokens
|
|
4249
|
+
.get(i + 1)
|
|
4250
|
+
.is_some_and(|token| token.token_type == TokenType::Tilde)
|
|
4251
|
+
&& tokens
|
|
4252
|
+
.get(i + 2)
|
|
4253
|
+
.is_some_and(|token| token.token_type == TokenType::Gt)
|
|
4254
|
+
{
|
|
4255
|
+
return Err(crate::error::Error::unsupported(
|
|
4256
|
+
"PostgreSQL pgvector Hamming distance operator <~>",
|
|
4257
|
+
"SQLite",
|
|
4258
|
+
));
|
|
4259
|
+
}
|
|
4260
|
+
}
|
|
4261
|
+
Ok(())
|
|
4262
|
+
}
|
|
4263
|
+
|
|
4264
|
+
fn normalize_postgres_to_sqlite_types(expr: Expression) -> Result<Expression> {
|
|
4265
|
+
fn sqlite_type(dt: crate::expressions::DataType) -> crate::expressions::DataType {
|
|
4266
|
+
use crate::expressions::DataType;
|
|
4267
|
+
|
|
4268
|
+
match dt {
|
|
4269
|
+
DataType::Bit { .. } => DataType::Int {
|
|
4270
|
+
length: None,
|
|
4271
|
+
integer_spelling: true,
|
|
4272
|
+
},
|
|
4273
|
+
DataType::TextWithLength { .. } => DataType::Text,
|
|
4274
|
+
DataType::VarChar { .. } => DataType::Text,
|
|
4275
|
+
DataType::Char { .. } => DataType::Text,
|
|
4276
|
+
DataType::Timestamp { timezone: true, .. } => DataType::Text,
|
|
4277
|
+
DataType::Custom { name } => {
|
|
4278
|
+
let base = name
|
|
4279
|
+
.split_once('(')
|
|
4280
|
+
.map_or(name.as_str(), |(base, _)| base)
|
|
4281
|
+
.trim();
|
|
4282
|
+
if base.eq_ignore_ascii_case("TSVECTOR")
|
|
4283
|
+
|| base.eq_ignore_ascii_case("TIMESTAMPTZ")
|
|
4284
|
+
|| base.eq_ignore_ascii_case("TIMESTAMP WITH TIME ZONE")
|
|
4285
|
+
|| base.eq_ignore_ascii_case("NVARCHAR")
|
|
4286
|
+
|| base.eq_ignore_ascii_case("NCHAR")
|
|
4287
|
+
{
|
|
4288
|
+
DataType::Text
|
|
4289
|
+
} else {
|
|
4290
|
+
DataType::Custom { name }
|
|
4291
|
+
}
|
|
4292
|
+
}
|
|
4293
|
+
_ => dt,
|
|
4294
|
+
}
|
|
4295
|
+
}
|
|
4296
|
+
|
|
4297
|
+
transform_recursive(expr, &|e| match e {
|
|
4298
|
+
Expression::DataType(dt) => Ok(Expression::DataType(sqlite_type(dt))),
|
|
4299
|
+
Expression::CreateTable(mut ct) => {
|
|
4300
|
+
for column in &mut ct.columns {
|
|
4301
|
+
column.data_type = sqlite_type(column.data_type.clone());
|
|
4302
|
+
}
|
|
4303
|
+
Ok(Expression::CreateTable(ct))
|
|
4304
|
+
}
|
|
4305
|
+
_ => Ok(e),
|
|
4306
|
+
})
|
|
4307
|
+
}
|
|
4308
|
+
|
|
4225
4309
|
/// For DuckDB target: when FROM clause contains RANGE(n), replace
|
|
4226
4310
|
/// `(ROW_NUMBER() OVER (ORDER BY 1 NULLS FIRST) - 1)` with `range` in select expressions.
|
|
4227
4311
|
/// This handles SEQ1/2/4/8 → RANGE transpilation from Snowflake.
|
|
@@ -9067,6 +9151,11 @@ impl Dialect {
|
|
|
9067
9151
|
match action {
|
|
9068
9152
|
Action::None => {
|
|
9069
9153
|
// Handle inline transforms that don't need a dedicated action
|
|
9154
|
+
if matches!(target, DialectType::TSQL | DialectType::Fabric) {
|
|
9155
|
+
if let Some(rewritten) = Self::rewrite_tsql_interval_arithmetic(&e) {
|
|
9156
|
+
return Ok(rewritten);
|
|
9157
|
+
}
|
|
9158
|
+
}
|
|
9070
9159
|
|
|
9071
9160
|
// BETWEEN SYMMETRIC/ASYMMETRIC expansion for non-PostgreSQL/Dremio targets
|
|
9072
9161
|
if let Expression::Between(ref b) = e {
|
|
@@ -31321,6 +31410,7 @@ impl Dialect {
|
|
|
31321
31410
|
clone_source: None,
|
|
31322
31411
|
clone_at_clause: None,
|
|
31323
31412
|
shallow_clone: false,
|
|
31413
|
+
deep_clone: false,
|
|
31324
31414
|
is_copy: false,
|
|
31325
31415
|
leading_comments: Vec::new(),
|
|
31326
31416
|
with_properties: Vec::new(),
|
|
@@ -31897,7 +31987,9 @@ impl Dialect {
|
|
|
31897
31987
|
// Return just the numeric part as value and parsed unit
|
|
31898
31988
|
return (
|
|
31899
31989
|
Expression::Literal(Box::new(
|
|
31900
|
-
crate::expressions::Literal::String(
|
|
31990
|
+
crate::expressions::Literal::String(
|
|
31991
|
+
parts[0].trim().to_string(),
|
|
31992
|
+
),
|
|
31901
31993
|
)),
|
|
31902
31994
|
parsed_unit,
|
|
31903
31995
|
);
|
|
@@ -31919,6 +32011,88 @@ impl Dialect {
|
|
|
31919
32011
|
}
|
|
31920
32012
|
}
|
|
31921
32013
|
|
|
32014
|
+
fn rewrite_tsql_interval_arithmetic(expr: &Expression) -> Option<Expression> {
|
|
32015
|
+
match expr {
|
|
32016
|
+
Expression::Add(op) => {
|
|
32017
|
+
let Expression::Interval(_) = &op.right else {
|
|
32018
|
+
return None;
|
|
32019
|
+
};
|
|
32020
|
+
Some(Self::build_tsql_dateadd_from_interval(
|
|
32021
|
+
op.left.clone(),
|
|
32022
|
+
&op.right,
|
|
32023
|
+
false,
|
|
32024
|
+
))
|
|
32025
|
+
}
|
|
32026
|
+
Expression::Sub(op) => {
|
|
32027
|
+
let Expression::Interval(_) = &op.right else {
|
|
32028
|
+
return None;
|
|
32029
|
+
};
|
|
32030
|
+
Some(Self::build_tsql_dateadd_from_interval(
|
|
32031
|
+
op.left.clone(),
|
|
32032
|
+
&op.right,
|
|
32033
|
+
true,
|
|
32034
|
+
))
|
|
32035
|
+
}
|
|
32036
|
+
_ => None,
|
|
32037
|
+
}
|
|
32038
|
+
}
|
|
32039
|
+
|
|
32040
|
+
fn build_tsql_dateadd_from_interval(
|
|
32041
|
+
date: Expression,
|
|
32042
|
+
interval: &Expression,
|
|
32043
|
+
subtract: bool,
|
|
32044
|
+
) -> Expression {
|
|
32045
|
+
let (value, unit) = Self::extract_interval_parts(interval);
|
|
32046
|
+
let unit = Self::interval_unit_to_string(&unit);
|
|
32047
|
+
let amount = Self::tsql_dateadd_amount(value, subtract);
|
|
32048
|
+
|
|
32049
|
+
Expression::Function(Box::new(Function::new(
|
|
32050
|
+
"DATEADD".to_string(),
|
|
32051
|
+
vec![Expression::Identifier(Identifier::new(unit)), amount, date],
|
|
32052
|
+
)))
|
|
32053
|
+
}
|
|
32054
|
+
|
|
32055
|
+
fn tsql_dateadd_amount(value: Expression, negate: bool) -> Expression {
|
|
32056
|
+
use crate::expressions::UnaryOp;
|
|
32057
|
+
|
|
32058
|
+
fn numeric_literal_value(value: &Expression) -> Option<&str> {
|
|
32059
|
+
match value {
|
|
32060
|
+
Expression::Literal(lit) => match lit.as_ref() {
|
|
32061
|
+
crate::expressions::Literal::Number(n)
|
|
32062
|
+
| crate::expressions::Literal::String(n) => Some(n.as_str()),
|
|
32063
|
+
_ => None,
|
|
32064
|
+
},
|
|
32065
|
+
_ => None,
|
|
32066
|
+
}
|
|
32067
|
+
}
|
|
32068
|
+
|
|
32069
|
+
if let Some(n) = numeric_literal_value(&value) {
|
|
32070
|
+
if let Ok(parsed) = n.parse::<f64>() {
|
|
32071
|
+
let normalized = if negate { -parsed } else { parsed };
|
|
32072
|
+
let rendered = if normalized.fract() == 0.0 {
|
|
32073
|
+
format!("{}", normalized as i64)
|
|
32074
|
+
} else {
|
|
32075
|
+
normalized.to_string()
|
|
32076
|
+
};
|
|
32077
|
+
return Expression::Literal(Box::new(crate::expressions::Literal::Number(
|
|
32078
|
+
rendered,
|
|
32079
|
+
)));
|
|
32080
|
+
}
|
|
32081
|
+
}
|
|
32082
|
+
|
|
32083
|
+
if !negate {
|
|
32084
|
+
return value;
|
|
32085
|
+
}
|
|
32086
|
+
|
|
32087
|
+
match value {
|
|
32088
|
+
Expression::Neg(op) => op.this,
|
|
32089
|
+
other => Expression::Neg(Box::new(UnaryOp {
|
|
32090
|
+
this: other,
|
|
32091
|
+
inferred_type: None,
|
|
32092
|
+
})),
|
|
32093
|
+
}
|
|
32094
|
+
}
|
|
32095
|
+
|
|
31922
32096
|
/// Normalize BigQuery-specific functions to standard forms that target dialects can handle
|
|
31923
32097
|
fn normalize_bigquery_function(
|
|
31924
32098
|
e: Expression,
|
|
@@ -37962,7 +38136,11 @@ mod tests {
|
|
|
37962
38136
|
"Expected IS NOT DISTINCT FROM: {}",
|
|
37963
38137
|
result[0]
|
|
37964
38138
|
);
|
|
37965
|
-
assert!(
|
|
38139
|
+
assert!(
|
|
38140
|
+
result[0].contains("= 0"),
|
|
38141
|
+
"Expected = 0 filter: {}",
|
|
38142
|
+
result[0]
|
|
38143
|
+
);
|
|
37966
38144
|
}
|
|
37967
38145
|
|
|
37968
38146
|
#[test]
|
|
@@ -1217,6 +1217,29 @@ mod tests {
|
|
|
1217
1217
|
assert_eq!(config.identifier_quote, '`');
|
|
1218
1218
|
}
|
|
1219
1219
|
|
|
1220
|
+
#[test]
|
|
1221
|
+
fn test_create_procedure_signal_sqlstate_regression() {
|
|
1222
|
+
let sql = "CREATE PROCEDURE CheckSalary(IN p_salary DECIMAL(10,2))
|
|
1223
|
+
BEGIN
|
|
1224
|
+
IF p_salary <= 0 THEN
|
|
1225
|
+
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Salary must be positive';
|
|
1226
|
+
END IF;
|
|
1227
|
+
INSERT INTO employees (salary) VALUES (p_salary);
|
|
1228
|
+
END;";
|
|
1229
|
+
|
|
1230
|
+
let dialect = Dialect::get(DialectType::MySQL);
|
|
1231
|
+
let ast = dialect.parse(sql).expect("Parse failed");
|
|
1232
|
+
let output = dialect.generate(&ast[0]).expect("Generate failed");
|
|
1233
|
+
|
|
1234
|
+
assert!(output.contains("CREATE PROCEDURE CheckSalary"));
|
|
1235
|
+
assert!(output.contains("IF p_salary <= 0 THEN"));
|
|
1236
|
+
assert!(
|
|
1237
|
+
output.contains("SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Salary must be positive'")
|
|
1238
|
+
);
|
|
1239
|
+
assert!(output.contains("END IF"));
|
|
1240
|
+
assert!(output.contains("INSERT INTO employees (salary) VALUES (p_salary)"));
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1220
1243
|
fn mysql_identity(sql: &str, expected: &str) {
|
|
1221
1244
|
let dialect = Dialect::get(DialectType::MySQL);
|
|
1222
1245
|
let ast = dialect.parse(sql).expect("Parse failed");
|
|
@@ -3921,6 +3921,37 @@ mod tests {
|
|
|
3921
3921
|
assert!(result.contains("FROM users"));
|
|
3922
3922
|
}
|
|
3923
3923
|
|
|
3924
|
+
#[test]
|
|
3925
|
+
fn test_snowflake_scripting_cursor_declare_block_roundtrip() {
|
|
3926
|
+
let sql = "DECLARE
|
|
3927
|
+
emp CURSOR FOR SELECT salary FROM employees;
|
|
3928
|
+
BEGIN
|
|
3929
|
+
RETURN 1;
|
|
3930
|
+
END";
|
|
3931
|
+
|
|
3932
|
+
let dialect = Dialect::get(DialectType::Snowflake);
|
|
3933
|
+
let ast = dialect.parse(sql).expect("Parse failed");
|
|
3934
|
+
let output = dialect.generate(&ast[0]).expect("Generate failed");
|
|
3935
|
+
|
|
3936
|
+
assert_eq!(output, sql);
|
|
3937
|
+
}
|
|
3938
|
+
|
|
3939
|
+
#[test]
|
|
3940
|
+
fn test_snowflake_scripting_cursor_return_table_roundtrip() {
|
|
3941
|
+
let sql = "DECLARE
|
|
3942
|
+
c1 CURSOR FOR SELECT * FROM invoices;
|
|
3943
|
+
BEGIN
|
|
3944
|
+
OPEN c1;
|
|
3945
|
+
RETURN TABLE(RESULTSET_FROM_CURSOR(c1));
|
|
3946
|
+
END";
|
|
3947
|
+
|
|
3948
|
+
let dialect = Dialect::get(DialectType::Snowflake);
|
|
3949
|
+
let ast = dialect.parse(sql).expect("Parse failed");
|
|
3950
|
+
let output = dialect.generate(&ast[0]).expect("Generate failed");
|
|
3951
|
+
|
|
3952
|
+
assert_eq!(output, sql);
|
|
3953
|
+
}
|
|
3954
|
+
|
|
3924
3955
|
#[test]
|
|
3925
3956
|
fn test_group_concat_to_listagg() {
|
|
3926
3957
|
let result = transpile_to_snowflake("SELECT GROUP_CONCAT(name)");
|
|
@@ -41,6 +41,12 @@ impl DialectImpl for SparkDialect {
|
|
|
41
41
|
config
|
|
42
42
|
.keywords
|
|
43
43
|
.insert("DIV".to_string(), crate::tokens::TokenType::Div);
|
|
44
|
+
config
|
|
45
|
+
.keywords
|
|
46
|
+
.insert("REPAIR".to_string(), crate::tokens::TokenType::Command);
|
|
47
|
+
config
|
|
48
|
+
.keywords
|
|
49
|
+
.insert("MSCK".to_string(), crate::tokens::TokenType::Command);
|
|
44
50
|
// Spark numeric literal suffixes (same as Hive): 1L -> BIGINT, 1S -> SMALLINT, etc.
|
|
45
51
|
config
|
|
46
52
|
.numeric_literals
|