polyglot-sql 0.3.3__tar.gz → 0.3.4__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.4}/Cargo.lock +5 -5
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/Cargo.toml +1 -1
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/PKG-INFO +1 -1
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/Cargo.toml +1 -1
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/builder.rs +1 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/dialects/databricks.rs +106 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/dialects/fabric.rs +11 -22
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/dialects/hive.rs +6 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/dialects/mod.rs +97 -3
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/dialects/mysql.rs +23 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/dialects/snowflake.rs +31 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/dialects/spark.rs +6 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/dialects/tsql.rs +86 -4
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/expressions.rs +4 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/generator.rs +69 -54
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/parser.rs +196 -16
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/tests/dialect_matrix.rs +84 -0
- polyglot_sql-0.3.4/crates/polyglot-sql/tests/fabric_regression.rs +85 -0
- polyglot_sql-0.3.4/crates/polyglot-sql/tests/tsql_regression.rs +85 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/README.md +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/README.md +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/benches/in_list.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/benches/parsing.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/benches/rust_parsing.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/benches/transpile.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/examples/basic_usage.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/examples/bench_json.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/ast_transforms.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/dialects/athena.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/dialects/bigquery.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/dialects/clickhouse.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/dialects/cockroachdb.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/dialects/datafusion.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/dialects/doris.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/dialects/dremio.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/dialects/drill.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/dialects/druid.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/dialects/duckdb.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/dialects/dune.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/dialects/exasol.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/dialects/generic.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/dialects/materialize.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/dialects/oracle.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/dialects/postgres.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/dialects/presto.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/dialects/redshift.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/dialects/risingwave.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/dialects/singlestore.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/dialects/solr.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/dialects/sqlite.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/dialects/starrocks.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/dialects/tableau.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/dialects/teradata.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/dialects/tidb.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/dialects/trino.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/diff.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/error.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/function_catalog.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/function_registry.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/helper.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/lib.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/lineage.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/optimizer/annotate_types.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/optimizer/canonicalize.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/optimizer/eliminate_ctes.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/optimizer/eliminate_joins.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/optimizer/isolate_table_selects.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/optimizer/mod.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/optimizer/normalize.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/optimizer/normalize_identifiers.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/optimizer/optimize_joins.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/optimizer/optimizer.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/optimizer/pushdown_predicates.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/optimizer/pushdown_projections.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/optimizer/qualify_columns.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/optimizer/qualify_tables.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/optimizer/simplify.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/optimizer/subquery.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/planner.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/resolver.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/schema.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/scope.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/time.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/tokens.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/transforms.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/traversal.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/trie.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/validation/tests.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/src/validation.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/tests/analyze_failures.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/tests/clickhouse_regression.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/tests/common/known_failures.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/tests/common/mod.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/tests/common/test_data.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/tests/common/test_runner.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/tests/custom_clickhouse_coverage.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/tests/custom_clickhouse_parser.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/tests/custom_dialect.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/tests/custom_dialect_tests.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/tests/custom_fixtures/datafusion/ddl.json +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/tests/custom_fixtures/datafusion/dml.json +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/tests/custom_fixtures/datafusion/functions.json +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/tests/custom_fixtures/datafusion/identity.json +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/tests/custom_fixtures/datafusion/operators.json +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/tests/custom_fixtures/datafusion/select.json +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/tests/custom_fixtures/datafusion/transpilation.json +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/tests/custom_fixtures/datafusion/types.json +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/tests/deep_nesting_regression.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/tests/error_handling.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/tests/identity_roundtrip.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/tests/snowflake_regression_test.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/tests/sqlglot_compat.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/tests/sqlglot_dialect_identity.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/tests/sqlglot_identity.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/tests/sqlglot_identity_detailed.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/tests/sqlglot_parser.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/tests/sqlglot_pretty.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/tests/sqlglot_transpilation.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/tests/sqlglot_transpile.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/tests/tpch_transpile_stack.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql/tests/transform_regression.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql-function-catalogs/Cargo.toml +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql-function-catalogs/README.md +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql-function-catalogs/src/clickhouse.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql-function-catalogs/src/duckdb.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql-function-catalogs/src/lib.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql-function-catalogs/tools/clickhouse/extract_functions.py +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql-function-catalogs/tools/duckdb/extract_functions.py +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql-python/Cargo.toml +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql-python/README.md +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql-python/docs/api.md +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql-python/docs/index.md +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql-python/mkdocs.yml +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql-python/src/annotate_types.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql-python/src/dialects.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql-python/src/diff.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql-python/src/errors.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql-python/src/expr.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql-python/src/expr_types.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql-python/src/format.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql-python/src/generate.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql-python/src/helpers.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql-python/src/lib.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql-python/src/lineage.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql-python/src/optimize.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql-python/src/parse.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql-python/src/tokenize.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql-python/src/transpile.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql-python/src/types.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql-python/src/validate.rs +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql-python/tests/conftest.py +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql-python/tests/test_compat.py +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql-python/tests/test_dialects.py +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql-python/tests/test_diff.py +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql-python/tests/test_expression.py +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql-python/tests/test_format.py +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql-python/tests/test_generate.py +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql-python/tests/test_lineage.py +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql-python/tests/test_optimize.py +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql-python/tests/test_parse.py +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql-python/tests/test_transpile.py +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql-python/tests/test_validate.py +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/crates/polyglot-sql-python/uv.lock +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/pyproject.toml +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/python/polyglot_sql/__init__.py +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/python/polyglot_sql/__init__.pyi +0 -0
- {polyglot_sql-0.3.3 → polyglot_sql-0.3.4}/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.4"
|
|
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.4"
|
|
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.4"
|
|
635
635
|
|
|
636
636
|
[[package]]
|
|
637
637
|
name = "polyglot-sql-python"
|
|
638
|
-
version = "0.3.
|
|
638
|
+
version = "0.3.4"
|
|
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.4"
|
|
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.4", 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,7 +158,7 @@ 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
164
|
use crate::tokens::{Token, Tokenizer, TokenizerConfig};
|
|
@@ -9067,6 +9067,11 @@ impl Dialect {
|
|
|
9067
9067
|
match action {
|
|
9068
9068
|
Action::None => {
|
|
9069
9069
|
// Handle inline transforms that don't need a dedicated action
|
|
9070
|
+
if matches!(target, DialectType::TSQL | DialectType::Fabric) {
|
|
9071
|
+
if let Some(rewritten) = Self::rewrite_tsql_interval_arithmetic(&e) {
|
|
9072
|
+
return Ok(rewritten);
|
|
9073
|
+
}
|
|
9074
|
+
}
|
|
9070
9075
|
|
|
9071
9076
|
// BETWEEN SYMMETRIC/ASYMMETRIC expansion for non-PostgreSQL/Dremio targets
|
|
9072
9077
|
if let Expression::Between(ref b) = e {
|
|
@@ -31321,6 +31326,7 @@ impl Dialect {
|
|
|
31321
31326
|
clone_source: None,
|
|
31322
31327
|
clone_at_clause: None,
|
|
31323
31328
|
shallow_clone: false,
|
|
31329
|
+
deep_clone: false,
|
|
31324
31330
|
is_copy: false,
|
|
31325
31331
|
leading_comments: Vec::new(),
|
|
31326
31332
|
with_properties: Vec::new(),
|
|
@@ -31897,7 +31903,9 @@ impl Dialect {
|
|
|
31897
31903
|
// Return just the numeric part as value and parsed unit
|
|
31898
31904
|
return (
|
|
31899
31905
|
Expression::Literal(Box::new(
|
|
31900
|
-
crate::expressions::Literal::String(
|
|
31906
|
+
crate::expressions::Literal::String(
|
|
31907
|
+
parts[0].trim().to_string(),
|
|
31908
|
+
),
|
|
31901
31909
|
)),
|
|
31902
31910
|
parsed_unit,
|
|
31903
31911
|
);
|
|
@@ -31919,6 +31927,88 @@ impl Dialect {
|
|
|
31919
31927
|
}
|
|
31920
31928
|
}
|
|
31921
31929
|
|
|
31930
|
+
fn rewrite_tsql_interval_arithmetic(expr: &Expression) -> Option<Expression> {
|
|
31931
|
+
match expr {
|
|
31932
|
+
Expression::Add(op) => {
|
|
31933
|
+
let Expression::Interval(_) = &op.right else {
|
|
31934
|
+
return None;
|
|
31935
|
+
};
|
|
31936
|
+
Some(Self::build_tsql_dateadd_from_interval(
|
|
31937
|
+
op.left.clone(),
|
|
31938
|
+
&op.right,
|
|
31939
|
+
false,
|
|
31940
|
+
))
|
|
31941
|
+
}
|
|
31942
|
+
Expression::Sub(op) => {
|
|
31943
|
+
let Expression::Interval(_) = &op.right else {
|
|
31944
|
+
return None;
|
|
31945
|
+
};
|
|
31946
|
+
Some(Self::build_tsql_dateadd_from_interval(
|
|
31947
|
+
op.left.clone(),
|
|
31948
|
+
&op.right,
|
|
31949
|
+
true,
|
|
31950
|
+
))
|
|
31951
|
+
}
|
|
31952
|
+
_ => None,
|
|
31953
|
+
}
|
|
31954
|
+
}
|
|
31955
|
+
|
|
31956
|
+
fn build_tsql_dateadd_from_interval(
|
|
31957
|
+
date: Expression,
|
|
31958
|
+
interval: &Expression,
|
|
31959
|
+
subtract: bool,
|
|
31960
|
+
) -> Expression {
|
|
31961
|
+
let (value, unit) = Self::extract_interval_parts(interval);
|
|
31962
|
+
let unit = Self::interval_unit_to_string(&unit);
|
|
31963
|
+
let amount = Self::tsql_dateadd_amount(value, subtract);
|
|
31964
|
+
|
|
31965
|
+
Expression::Function(Box::new(Function::new(
|
|
31966
|
+
"DATEADD".to_string(),
|
|
31967
|
+
vec![Expression::Identifier(Identifier::new(unit)), amount, date],
|
|
31968
|
+
)))
|
|
31969
|
+
}
|
|
31970
|
+
|
|
31971
|
+
fn tsql_dateadd_amount(value: Expression, negate: bool) -> Expression {
|
|
31972
|
+
use crate::expressions::UnaryOp;
|
|
31973
|
+
|
|
31974
|
+
fn numeric_literal_value(value: &Expression) -> Option<&str> {
|
|
31975
|
+
match value {
|
|
31976
|
+
Expression::Literal(lit) => match lit.as_ref() {
|
|
31977
|
+
crate::expressions::Literal::Number(n)
|
|
31978
|
+
| crate::expressions::Literal::String(n) => Some(n.as_str()),
|
|
31979
|
+
_ => None,
|
|
31980
|
+
},
|
|
31981
|
+
_ => None,
|
|
31982
|
+
}
|
|
31983
|
+
}
|
|
31984
|
+
|
|
31985
|
+
if let Some(n) = numeric_literal_value(&value) {
|
|
31986
|
+
if let Ok(parsed) = n.parse::<f64>() {
|
|
31987
|
+
let normalized = if negate { -parsed } else { parsed };
|
|
31988
|
+
let rendered = if normalized.fract() == 0.0 {
|
|
31989
|
+
format!("{}", normalized as i64)
|
|
31990
|
+
} else {
|
|
31991
|
+
normalized.to_string()
|
|
31992
|
+
};
|
|
31993
|
+
return Expression::Literal(Box::new(crate::expressions::Literal::Number(
|
|
31994
|
+
rendered,
|
|
31995
|
+
)));
|
|
31996
|
+
}
|
|
31997
|
+
}
|
|
31998
|
+
|
|
31999
|
+
if !negate {
|
|
32000
|
+
return value;
|
|
32001
|
+
}
|
|
32002
|
+
|
|
32003
|
+
match value {
|
|
32004
|
+
Expression::Neg(op) => op.this,
|
|
32005
|
+
other => Expression::Neg(Box::new(UnaryOp {
|
|
32006
|
+
this: other,
|
|
32007
|
+
inferred_type: None,
|
|
32008
|
+
})),
|
|
32009
|
+
}
|
|
32010
|
+
}
|
|
32011
|
+
|
|
31922
32012
|
/// Normalize BigQuery-specific functions to standard forms that target dialects can handle
|
|
31923
32013
|
fn normalize_bigquery_function(
|
|
31924
32014
|
e: Expression,
|
|
@@ -37962,7 +38052,11 @@ mod tests {
|
|
|
37962
38052
|
"Expected IS NOT DISTINCT FROM: {}",
|
|
37963
38053
|
result[0]
|
|
37964
38054
|
);
|
|
37965
|
-
assert!(
|
|
38055
|
+
assert!(
|
|
38056
|
+
result[0].contains("= 0"),
|
|
38057
|
+
"Expected = 0 filter: {}",
|
|
38058
|
+
result[0]
|
|
38059
|
+
);
|
|
37966
38060
|
}
|
|
37967
38061
|
|
|
37968
38062
|
#[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
|
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
use super::{DialectImpl, DialectType};
|
|
14
14
|
use crate::error::Result;
|
|
15
15
|
use crate::expressions::{
|
|
16
|
-
Alias, Cast, Cte, DataType, Expression, Function, Identifier, Join, JoinKind, LikeOp,
|
|
17
|
-
Null, StringAggFunc, Subquery, UnaryFunc,
|
|
16
|
+
Alias, Cast, Cte, DataType, Expression, Function, Identifier, In, Join, JoinKind, LikeOp,
|
|
17
|
+
Literal, Null, QuantifiedOp, StringAggFunc, Subquery, UnaryFunc,
|
|
18
18
|
};
|
|
19
19
|
use crate::generator::GeneratorConfig;
|
|
20
20
|
use crate::tokens::TokenizerConfig;
|
|
@@ -91,6 +91,18 @@ impl DialectImpl for TSQLDialect {
|
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
fn transform_expr(&self, expr: Expression) -> Result<Expression> {
|
|
94
|
+
// Transform column data types in DDL (transform_recursive skips them by design).
|
|
95
|
+
if let Expression::CreateTable(mut ct) = expr {
|
|
96
|
+
for col in &mut ct.columns {
|
|
97
|
+
if let Ok(Expression::DataType(new_dt)) =
|
|
98
|
+
self.transform_data_type(col.data_type.clone())
|
|
99
|
+
{
|
|
100
|
+
col.data_type = new_dt;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return Ok(Expression::CreateTable(ct));
|
|
104
|
+
}
|
|
105
|
+
|
|
94
106
|
match expr {
|
|
95
107
|
// ===== SELECT a = 1 → SELECT 1 AS a =====
|
|
96
108
|
// In T-SQL, `SELECT a = expr` is equivalent to `SELECT expr AS a`
|
|
@@ -629,6 +641,36 @@ impl DialectImpl for TSQLDialect {
|
|
|
629
641
|
vec![f.this, f.path],
|
|
630
642
|
)))),
|
|
631
643
|
|
|
644
|
+
// PostgreSQL pg_get_querydef can emit scalar array comparisons for
|
|
645
|
+
// literal arrays/tuples. T-SQL/Fabric require IN for this shape.
|
|
646
|
+
Expression::Any(ref q) if matches!(&q.op, Some(QuantifiedOp::Eq)) => {
|
|
647
|
+
let values: Option<Vec<Expression>> = match &q.subquery {
|
|
648
|
+
Expression::ArrayFunc(a) => Some(a.expressions.clone()),
|
|
649
|
+
Expression::Array(a) => Some(a.expressions.clone()),
|
|
650
|
+
Expression::Tuple(t) => Some(t.expressions.clone()),
|
|
651
|
+
_ => None,
|
|
652
|
+
};
|
|
653
|
+
|
|
654
|
+
match values {
|
|
655
|
+
Some(expressions) if expressions.is_empty() => {
|
|
656
|
+
Ok(Expression::Eq(Box::new(crate::expressions::BinaryOp::new(
|
|
657
|
+
Expression::Literal(Box::new(Literal::Number("1".to_string()))),
|
|
658
|
+
Expression::Literal(Box::new(Literal::Number("0".to_string()))),
|
|
659
|
+
))))
|
|
660
|
+
}
|
|
661
|
+
Some(expressions) => Ok(Expression::In(Box::new(In {
|
|
662
|
+
this: q.this.clone(),
|
|
663
|
+
expressions,
|
|
664
|
+
query: None,
|
|
665
|
+
not: false,
|
|
666
|
+
global: false,
|
|
667
|
+
unnest: None,
|
|
668
|
+
is_field: false,
|
|
669
|
+
}))),
|
|
670
|
+
None => Ok(expr.clone()),
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
|
|
632
674
|
// Pass through everything else
|
|
633
675
|
_ => Ok(expr),
|
|
634
676
|
}
|
|
@@ -637,7 +679,10 @@ impl DialectImpl for TSQLDialect {
|
|
|
637
679
|
|
|
638
680
|
impl TSQLDialect {
|
|
639
681
|
/// Transform data types according to T-SQL TYPE_MAPPING
|
|
640
|
-
fn transform_data_type(
|
|
682
|
+
pub(super) fn transform_data_type(
|
|
683
|
+
&self,
|
|
684
|
+
dt: crate::expressions::DataType,
|
|
685
|
+
) -> Result<Expression> {
|
|
641
686
|
use crate::expressions::DataType;
|
|
642
687
|
let transformed = match dt {
|
|
643
688
|
// BOOLEAN -> BIT
|
|
@@ -669,12 +714,46 @@ impl TSQLDialect {
|
|
|
669
714
|
DataType::Uuid => DataType::Custom {
|
|
670
715
|
name: "UNIQUEIDENTIFIER".to_string(),
|
|
671
716
|
},
|
|
717
|
+
// Normalise custom type names that have PostgreSQL aliases
|
|
718
|
+
DataType::Custom { ref name } => {
|
|
719
|
+
let upper = name.trim().to_uppercase();
|
|
720
|
+
let (base_name, precision, _scale) = Self::parse_type_precision_and_scale(&upper);
|
|
721
|
+
match base_name.as_str() {
|
|
722
|
+
// BPCHAR is PostgreSQL's blank-padded CHAR alias — map to CHAR
|
|
723
|
+
"BPCHAR" => {
|
|
724
|
+
if let Some(len) = precision {
|
|
725
|
+
DataType::Char { length: Some(len) }
|
|
726
|
+
} else {
|
|
727
|
+
DataType::Char { length: None }
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
_ => dt,
|
|
731
|
+
}
|
|
732
|
+
}
|
|
672
733
|
// Keep all other types as-is
|
|
673
734
|
other => other,
|
|
674
735
|
};
|
|
675
736
|
Ok(Expression::DataType(transformed))
|
|
676
737
|
}
|
|
677
738
|
|
|
739
|
+
/// Parse a type name that may embed precision/scale: `"TYPENAME(n, m)"` → `("TYPENAME", Some(n), Some(m))`.
|
|
740
|
+
pub(super) fn parse_type_precision_and_scale(name: &str) -> (String, Option<u32>, Option<u32>) {
|
|
741
|
+
if let Some(paren_pos) = name.find('(') {
|
|
742
|
+
let base = name[..paren_pos].to_string();
|
|
743
|
+
let rest = &name[paren_pos + 1..];
|
|
744
|
+
if let Some(close_pos) = rest.find(')') {
|
|
745
|
+
let args = &rest[..close_pos];
|
|
746
|
+
let parts: Vec<&str> = args.split(',').map(|s| s.trim()).collect();
|
|
747
|
+
let precision = parts.first().and_then(|s| s.parse::<u32>().ok());
|
|
748
|
+
let scale = parts.get(1).and_then(|s| s.parse::<u32>().ok());
|
|
749
|
+
return (base, precision, scale);
|
|
750
|
+
}
|
|
751
|
+
(base, None, None)
|
|
752
|
+
} else {
|
|
753
|
+
(name.to_string(), None, None)
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
|
|
678
757
|
fn transform_function(&self, f: Function) -> Result<Expression> {
|
|
679
758
|
let name_upper = f.name.to_uppercase();
|
|
680
759
|
match name_upper.as_str() {
|
|
@@ -1346,6 +1425,9 @@ mod tests {
|
|
|
1346
1425
|
)
|
|
1347
1426
|
.expect("transpile failed");
|
|
1348
1427
|
let expected = r#"ISNULL(JSON_QUERY(REPLACE(REPLACE(x, '''', '"'), '""', '"'), '$'), JSON_VALUE(REPLACE(REPLACE(x, '''', '"'), '""', '"'), '$'))"#;
|
|
1349
|
-
assert_eq!(
|
|
1428
|
+
assert_eq!(
|
|
1429
|
+
result[0], expected,
|
|
1430
|
+
"JSON_QUERY should be wrapped with ISNULL"
|
|
1431
|
+
);
|
|
1350
1432
|
}
|
|
1351
1433
|
}
|
|
@@ -7297,6 +7297,9 @@ pub struct CreateTable {
|
|
|
7297
7297
|
/// Whether this is a SHALLOW CLONE (Databricks/Delta Lake)
|
|
7298
7298
|
#[serde(default)]
|
|
7299
7299
|
pub shallow_clone: bool,
|
|
7300
|
+
/// Whether this is an explicit DEEP CLONE (Databricks/Delta Lake)
|
|
7301
|
+
#[serde(default)]
|
|
7302
|
+
pub deep_clone: bool,
|
|
7300
7303
|
/// Leading comments before the statement
|
|
7301
7304
|
#[serde(default)]
|
|
7302
7305
|
pub leading_comments: Vec<String>,
|
|
@@ -7406,6 +7409,7 @@ impl CreateTable {
|
|
|
7406
7409
|
clone_source: None,
|
|
7407
7410
|
clone_at_clause: None,
|
|
7408
7411
|
shallow_clone: false,
|
|
7412
|
+
deep_clone: false,
|
|
7409
7413
|
is_copy: false,
|
|
7410
7414
|
leading_comments: Vec::new(),
|
|
7411
7415
|
with_properties: Vec::new(),
|