polyglot-sql 0.5.9__tar.gz → 0.5.11__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.5.9 → polyglot_sql-0.5.11}/Cargo.lock +5 -5
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/Cargo.toml +1 -1
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/PKG-INFO +1 -1
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/Cargo.toml +1 -1
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/duckdb.rs +40 -1
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/mod.rs +18 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/generator.rs +44 -12
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/lineage.rs +86 -2
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/query_analysis.rs +3 -1
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/validation/tests.rs +23 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/issue227_strict_unsupported.rs +25 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/query_analysis.rs +112 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/tsql_regression.rs +47 -2
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/tests/test_lineage.py +17 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/tests/test_query_analysis.py +30 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/README.md +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/README.md +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/benches/in_list.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/benches/parsing.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/benches/rust_parsing.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/benches/transpile.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/examples/basic_usage.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/examples/bench_json.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/ast_json.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/ast_transforms.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/builder.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/athena.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/bigquery.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/clickhouse.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/cockroachdb.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/databricks.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/datafusion.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/doris.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/dremio.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/drill.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/druid.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/dune.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/exasol.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/fabric.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/generic.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/hive.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/materialize.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/mysql.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/oracle.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/postgres.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/presto.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/redshift.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/risingwave.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/singlestore.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/snowflake.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/solr.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/spark.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/sqlite.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/starrocks.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/tableau.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/teradata.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/tidb.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/trino.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/tsql.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/diff.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/error.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/expressions.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/function_catalog.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/function_registry.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/helper.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/lib.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/openlineage.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/optimizer/annotate_types.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/optimizer/canonicalize.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/optimizer/eliminate_ctes.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/optimizer/eliminate_joins.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/optimizer/isolate_table_selects.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/optimizer/mod.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/optimizer/normalize.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/optimizer/normalize_identifiers.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/optimizer/optimize_joins.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/optimizer/optimizer.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/optimizer/pushdown_predicates.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/optimizer/pushdown_projections.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/optimizer/qualify_columns.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/optimizer/qualify_tables.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/optimizer/simplify.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/optimizer/subquery.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/parser.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/planner.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/resolver.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/schema.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/scope.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/time.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/tokens.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/transforms.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/traversal.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/trie.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/validation.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/analyze_failures.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/clickhouse_regression.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/common/known_failures.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/common/mod.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/common/test_data.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/common/test_runner.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/custom_clickhouse_coverage.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/custom_clickhouse_parser.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/custom_dialect.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/custom_dialect_tests.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/custom_fixtures/datafusion/ddl.json +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/custom_fixtures/datafusion/dml.json +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/custom_fixtures/datafusion/functions.json +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/custom_fixtures/datafusion/identity.json +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/custom_fixtures/datafusion/operators.json +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/custom_fixtures/datafusion/select.json +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/custom_fixtures/datafusion/transpilation.json +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/custom_fixtures/datafusion/types.json +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/data_type_api.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/deep_nesting_regression.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/dialect_matrix.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/error_handling.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/fabric_regression.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/fabric_tpch_regression.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/identity_roundtrip.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/issue201_regression_test.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/issue210_regression_test.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/issue226_regression_test.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/postgres_sqlite_regression.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/query_analysis_regression.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/snowflake_regression_test.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/sqlglot_compat.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/sqlglot_dialect_identity.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/sqlglot_identity.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/sqlglot_identity_detailed.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/sqlglot_parser.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/sqlglot_pretty.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/sqlglot_transpilation.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/sqlglot_transpile.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/tpch_transpile_stack.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/transform_regression.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-function-catalogs/Cargo.toml +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-function-catalogs/README.md +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-function-catalogs/src/clickhouse.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-function-catalogs/src/duckdb.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-function-catalogs/src/lib.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-function-catalogs/tools/clickhouse/extract_functions.py +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-function-catalogs/tools/duckdb/extract_functions.py +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/Cargo.toml +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/README.md +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/docs/api.md +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/docs/index.md +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/mkdocs.yml +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/src/annotate_types.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/src/dialects.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/src/diff.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/src/errors.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/src/expr.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/src/expr_types.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/src/format.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/src/generate.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/src/helpers.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/src/lib.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/src/lineage.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/src/openlineage.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/src/optimize.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/src/parse.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/src/query_analysis.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/src/tokenize.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/src/transforms.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/src/transpile.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/src/types.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/src/validate.rs +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/tests/conftest.py +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/tests/test_compat.py +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/tests/test_dialects.py +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/tests/test_diff.py +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/tests/test_expression.py +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/tests/test_format.py +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/tests/test_generate.py +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/tests/test_optimize.py +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/tests/test_parse.py +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/tests/test_transforms.py +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/tests/test_transpile.py +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/tests/test_validate.py +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/uv.lock +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/pyproject.toml +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/python/polyglot_sql/__init__.py +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/python/polyglot_sql/__init__.pyi +0 -0
- {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/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.5.
|
|
608
|
+
version = "0.5.11"
|
|
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.5.
|
|
624
|
+
version = "0.5.11"
|
|
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.5.
|
|
634
|
+
version = "0.5.11"
|
|
635
635
|
|
|
636
636
|
[[package]]
|
|
637
637
|
name = "polyglot-sql-python"
|
|
638
|
-
version = "0.5.
|
|
638
|
+
version = "0.5.11"
|
|
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.5.
|
|
649
|
+
version = "0.5.11"
|
|
650
650
|
dependencies = [
|
|
651
651
|
"console_error_panic_hook",
|
|
652
652
|
"js-sys",
|
|
@@ -106,7 +106,7 @@ thiserror = { workspace = true }
|
|
|
106
106
|
unicode-segmentation = { workspace = true }
|
|
107
107
|
stacker = { version = "0.1", optional = true }
|
|
108
108
|
ts-rs = { version = "12.0", features = ["serde-compat"], optional = true }
|
|
109
|
-
polyglot-sql-function-catalogs = { path = "../polyglot-sql-function-catalogs", version = "0.5.
|
|
109
|
+
polyglot-sql-function-catalogs = { path = "../polyglot-sql-function-catalogs", version = "0.5.11", optional = true, default-features = false }
|
|
110
110
|
|
|
111
111
|
[dev-dependencies]
|
|
112
112
|
pretty_assertions = "1.4"
|
|
@@ -1068,6 +1068,11 @@ impl DialectImpl for DuckDBDialect {
|
|
|
1068
1068
|
// WithinGroup: PERCENTILE_CONT/DISC WITHIN GROUP (ORDER BY ...) -> QUANTILE_CONT/DISC(col, quantile ORDER BY ...)
|
|
1069
1069
|
Expression::WithinGroup(wg) => {
|
|
1070
1070
|
match &wg.this {
|
|
1071
|
+
Expression::ListAgg(listagg) => {
|
|
1072
|
+
let mut listagg = listagg.clone();
|
|
1073
|
+
listagg.order_by = Some(wg.order_by.clone());
|
|
1074
|
+
Ok(Expression::ListAgg(listagg))
|
|
1075
|
+
}
|
|
1071
1076
|
Expression::PercentileCont(p) => {
|
|
1072
1077
|
let column = wg
|
|
1073
1078
|
.order_by
|
|
@@ -7496,7 +7501,11 @@ mod tests {
|
|
|
7496
7501
|
use crate::dialects::Dialect;
|
|
7497
7502
|
|
|
7498
7503
|
fn transpile_to_duckdb(sql: &str) -> String {
|
|
7499
|
-
|
|
7504
|
+
transpile_to_duckdb_from(sql, DialectType::Generic)
|
|
7505
|
+
}
|
|
7506
|
+
|
|
7507
|
+
fn transpile_to_duckdb_from(sql: &str, read: DialectType) -> String {
|
|
7508
|
+
let dialect = Dialect::get(read);
|
|
7500
7509
|
let result = dialect
|
|
7501
7510
|
.transpile(sql, DialectType::DuckDB)
|
|
7502
7511
|
.expect("Transpile failed");
|
|
@@ -7550,6 +7559,36 @@ mod tests {
|
|
|
7550
7559
|
);
|
|
7551
7560
|
}
|
|
7552
7561
|
|
|
7562
|
+
#[test]
|
|
7563
|
+
fn test_ordered_string_agg_uses_duckdb_listagg_order_syntax() {
|
|
7564
|
+
let result = transpile_to_duckdb_from(
|
|
7565
|
+
"SELECT string_agg(nm, ',' ORDER BY id) AS v FROM t",
|
|
7566
|
+
DialectType::PostgreSQL,
|
|
7567
|
+
);
|
|
7568
|
+
assert_eq!(result, "SELECT LISTAGG(nm, ',' ORDER BY id) AS v FROM t");
|
|
7569
|
+
}
|
|
7570
|
+
|
|
7571
|
+
#[test]
|
|
7572
|
+
fn test_ordered_listagg_uses_duckdb_order_syntax() {
|
|
7573
|
+
let result = transpile_to_duckdb_from(
|
|
7574
|
+
"SELECT LISTAGG(col, '|SEPARATOR|') WITHIN GROUP (ORDER BY col2) FROM t",
|
|
7575
|
+
DialectType::Snowflake,
|
|
7576
|
+
);
|
|
7577
|
+
assert_eq!(
|
|
7578
|
+
result,
|
|
7579
|
+
"SELECT LISTAGG(col, '|SEPARATOR|' ORDER BY col2) FROM t"
|
|
7580
|
+
);
|
|
7581
|
+
}
|
|
7582
|
+
|
|
7583
|
+
#[test]
|
|
7584
|
+
fn test_ordered_group_concat_uses_duckdb_listagg_order_syntax() {
|
|
7585
|
+
let result = transpile_to_duckdb_from(
|
|
7586
|
+
"SELECT GROUP_CONCAT(nm ORDER BY id SEPARATOR ',') AS v FROM t",
|
|
7587
|
+
DialectType::MySQL,
|
|
7588
|
+
);
|
|
7589
|
+
assert_eq!(result, "SELECT LISTAGG(nm, ',' ORDER BY id) AS v FROM t");
|
|
7590
|
+
}
|
|
7591
|
+
|
|
7553
7592
|
#[test]
|
|
7554
7593
|
fn test_date_format_to_strftime() {
|
|
7555
7594
|
let result = transpile_to_duckdb("SELECT DATE_FORMAT(d, '%Y-%m-%d')");
|
|
@@ -4879,6 +4879,15 @@ impl Dialect {
|
|
|
4879
4879
|
Self::push_unsupported_diagnostic(&mut diagnostics, "ARRAY_AGG");
|
|
4880
4880
|
}
|
|
4881
4881
|
|
|
4882
|
+
if matches!(target, DialectType::TSQL | DialectType::Fabric)
|
|
4883
|
+
&& Self::node_is_regex_predicate(node)
|
|
4884
|
+
{
|
|
4885
|
+
Self::push_unsupported_diagnostic(
|
|
4886
|
+
&mut diagnostics,
|
|
4887
|
+
"regular expression predicates",
|
|
4888
|
+
);
|
|
4889
|
+
}
|
|
4890
|
+
|
|
4882
4891
|
if matches!(source, DialectType::PostgreSQL | DialectType::CockroachDB)
|
|
4883
4892
|
&& !matches!(target, DialectType::PostgreSQL | DialectType::CockroachDB)
|
|
4884
4893
|
{
|
|
@@ -5018,6 +5027,15 @@ impl Dialect {
|
|
|
5018
5027
|
matches!(expr, Expression::ArrayAgg(_)) || Self::node_is_function_named(expr, "ARRAY_AGG")
|
|
5019
5028
|
}
|
|
5020
5029
|
|
|
5030
|
+
fn node_is_regex_predicate(expr: &Expression) -> bool {
|
|
5031
|
+
matches!(
|
|
5032
|
+
expr,
|
|
5033
|
+
Expression::SimilarTo(_) | Expression::RegexpLike(_) | Expression::RegexpILike(_)
|
|
5034
|
+
) || Self::node_is_function_named(expr, "REGEXP_LIKE")
|
|
5035
|
+
|| Self::node_is_function_named(expr, "REGEXP_I_LIKE")
|
|
5036
|
+
|| Self::node_is_function_named(expr, "REGEXP_ILIKE")
|
|
5037
|
+
}
|
|
5038
|
+
|
|
5021
5039
|
fn node_is_function_named(expr: &Expression, name: &str) -> bool {
|
|
5022
5040
|
match expr {
|
|
5023
5041
|
Expression::Function(function) => function.name.eq_ignore_ascii_case(name),
|
|
@@ -17924,7 +17924,7 @@ impl Generator {
|
|
|
17924
17924
|
{
|
|
17925
17925
|
self.write_keyword("DATEPART");
|
|
17926
17926
|
self.write("(");
|
|
17927
|
-
self.
|
|
17927
|
+
self.write_tsql_date_part(&func.args[0])?;
|
|
17928
17928
|
self.write(", ");
|
|
17929
17929
|
self.generate_expression(&func.args[1])?;
|
|
17930
17930
|
self.write(")");
|
|
@@ -18888,6 +18888,22 @@ impl Generator {
|
|
|
18888
18888
|
}
|
|
18889
18889
|
}
|
|
18890
18890
|
|
|
18891
|
+
fn write_tsql_date_part(&mut self, expr: &Expression) -> Result<()> {
|
|
18892
|
+
if let Some(part) = self.extract_date_part_string(expr) {
|
|
18893
|
+
let upper = part.to_ascii_uppercase();
|
|
18894
|
+
let unmapped = match upper.as_str() {
|
|
18895
|
+
"DAYOFWEEK" => "WEEKDAY",
|
|
18896
|
+
"WEEKISO" => "ISO_WEEK",
|
|
18897
|
+
"TIMEZONE_MINUTE" => "TZOFFSET",
|
|
18898
|
+
_ => part.as_str(),
|
|
18899
|
+
};
|
|
18900
|
+
self.write_keyword(unmapped);
|
|
18901
|
+
} else {
|
|
18902
|
+
self.generate_expression(expr)?;
|
|
18903
|
+
}
|
|
18904
|
+
Ok(())
|
|
18905
|
+
}
|
|
18906
|
+
|
|
18891
18907
|
/// Extract date part string from expression (handles string literals and identifiers)
|
|
18892
18908
|
fn extract_date_part_string(&self, expr: &Expression) -> Option<String> {
|
|
18893
18909
|
match expr {
|
|
@@ -20369,6 +20385,7 @@ impl Generator {
|
|
|
20369
20385
|
|
|
20370
20386
|
fn generate_listagg(&mut self, f: &ListAggFunc) -> Result<()> {
|
|
20371
20387
|
use crate::dialects::DialectType;
|
|
20388
|
+
let order_inside_args = matches!(self.config.dialect, Some(DialectType::DuckDB));
|
|
20372
20389
|
self.write_keyword("LISTAGG");
|
|
20373
20390
|
self.write("(");
|
|
20374
20391
|
if f.distinct {
|
|
@@ -20408,20 +20425,35 @@ impl Generator {
|
|
|
20408
20425
|
}
|
|
20409
20426
|
}
|
|
20410
20427
|
}
|
|
20428
|
+
if order_inside_args {
|
|
20429
|
+
if let Some(ref order_by) = f.order_by {
|
|
20430
|
+
self.write_space();
|
|
20431
|
+
self.write_keyword("ORDER BY");
|
|
20432
|
+
self.write_space();
|
|
20433
|
+
for (i, ord) in order_by.iter().enumerate() {
|
|
20434
|
+
if i > 0 {
|
|
20435
|
+
self.write(", ");
|
|
20436
|
+
}
|
|
20437
|
+
self.generate_ordered(ord)?;
|
|
20438
|
+
}
|
|
20439
|
+
}
|
|
20440
|
+
}
|
|
20411
20441
|
self.write(")");
|
|
20412
|
-
if
|
|
20413
|
-
|
|
20414
|
-
|
|
20415
|
-
|
|
20416
|
-
|
|
20417
|
-
|
|
20418
|
-
|
|
20419
|
-
|
|
20420
|
-
|
|
20442
|
+
if !order_inside_args {
|
|
20443
|
+
if let Some(ref order_by) = f.order_by {
|
|
20444
|
+
self.write_space();
|
|
20445
|
+
self.write_keyword("WITHIN GROUP");
|
|
20446
|
+
self.write(" (");
|
|
20447
|
+
self.write_keyword("ORDER BY");
|
|
20448
|
+
self.write_space();
|
|
20449
|
+
for (i, ord) in order_by.iter().enumerate() {
|
|
20450
|
+
if i > 0 {
|
|
20451
|
+
self.write(", ");
|
|
20452
|
+
}
|
|
20453
|
+
self.generate_ordered(ord)?;
|
|
20421
20454
|
}
|
|
20422
|
-
self.
|
|
20455
|
+
self.write(")");
|
|
20423
20456
|
}
|
|
20424
|
-
self.write(")");
|
|
20425
20457
|
}
|
|
20426
20458
|
if let Some(ref filter) = f.filter {
|
|
20427
20459
|
self.write_space();
|
|
@@ -194,9 +194,11 @@ pub fn lineage_with_schema(
|
|
|
194
194
|
let normalized_expression = lineage_normalized_expression(sql);
|
|
195
195
|
let mut qualified_expression = if let Some(schema) = schema {
|
|
196
196
|
let options = if let Some(dialect_type) = dialect.or_else(|| schema.dialect()) {
|
|
197
|
-
QualifyColumnsOptions::new().with_dialect(dialect_type)
|
|
198
|
-
} else {
|
|
199
197
|
QualifyColumnsOptions::new()
|
|
198
|
+
.with_dialect(dialect_type)
|
|
199
|
+
.with_allow_partial(true)
|
|
200
|
+
} else {
|
|
201
|
+
QualifyColumnsOptions::new().with_allow_partial(true)
|
|
200
202
|
};
|
|
201
203
|
|
|
202
204
|
qualify_columns(normalized_expression.clone(), schema, &options).map_err(|e| {
|
|
@@ -3705,6 +3707,88 @@ mod tests {
|
|
|
3705
3707
|
assert_eq!(expr_with.inferred_type(), Some(&DataType::Text));
|
|
3706
3708
|
}
|
|
3707
3709
|
|
|
3710
|
+
#[test]
|
|
3711
|
+
fn test_lineage_with_schema_tolerates_partial_schema_for_known_column() {
|
|
3712
|
+
let expr = parse_dialect("SELECT order_id, amount FROM t", DialectType::DuckDB);
|
|
3713
|
+
let mut schema = MappingSchema::with_dialect(DialectType::DuckDB);
|
|
3714
|
+
schema
|
|
3715
|
+
.add_table(
|
|
3716
|
+
"t",
|
|
3717
|
+
&[("amount".into(), DataType::BigInt { length: None })],
|
|
3718
|
+
None,
|
|
3719
|
+
)
|
|
3720
|
+
.expect("schema setup");
|
|
3721
|
+
|
|
3722
|
+
let node = lineage_with_schema(
|
|
3723
|
+
"amount",
|
|
3724
|
+
&expr,
|
|
3725
|
+
Some(&schema),
|
|
3726
|
+
Some(DialectType::DuckDB),
|
|
3727
|
+
false,
|
|
3728
|
+
)
|
|
3729
|
+
.expect("lineage_with_schema should tolerate unrelated unknown columns");
|
|
3730
|
+
|
|
3731
|
+
assert_lineage_contains(&node, "t.amount");
|
|
3732
|
+
}
|
|
3733
|
+
|
|
3734
|
+
#[test]
|
|
3735
|
+
fn test_lineage_with_schema_tolerates_partial_schema_for_unknown_column() {
|
|
3736
|
+
let expr = parse_dialect("SELECT order_id, amount FROM t", DialectType::DuckDB);
|
|
3737
|
+
let mut schema = MappingSchema::with_dialect(DialectType::DuckDB);
|
|
3738
|
+
schema
|
|
3739
|
+
.add_table(
|
|
3740
|
+
"t",
|
|
3741
|
+
&[("amount".into(), DataType::BigInt { length: None })],
|
|
3742
|
+
None,
|
|
3743
|
+
)
|
|
3744
|
+
.expect("schema setup");
|
|
3745
|
+
|
|
3746
|
+
let node = lineage_with_schema(
|
|
3747
|
+
"order_id",
|
|
3748
|
+
&expr,
|
|
3749
|
+
Some(&schema),
|
|
3750
|
+
Some(DialectType::DuckDB),
|
|
3751
|
+
false,
|
|
3752
|
+
)
|
|
3753
|
+
.expect("lineage_with_schema should keep unknown selected columns");
|
|
3754
|
+
|
|
3755
|
+
assert_lineage_contains(&node, "t.order_id");
|
|
3756
|
+
}
|
|
3757
|
+
|
|
3758
|
+
#[test]
|
|
3759
|
+
fn test_lineage_with_schema_tolerates_partial_schema_for_join_conditions() {
|
|
3760
|
+
let expr = parse_dialect(
|
|
3761
|
+
"SELECT a.order_id, b.amount FROM t a JOIN u b ON a.id = b.id",
|
|
3762
|
+
DialectType::DuckDB,
|
|
3763
|
+
);
|
|
3764
|
+
let mut schema = MappingSchema::with_dialect(DialectType::DuckDB);
|
|
3765
|
+
schema
|
|
3766
|
+
.add_table(
|
|
3767
|
+
"t",
|
|
3768
|
+
&[("order_id".into(), DataType::BigInt { length: None })],
|
|
3769
|
+
None,
|
|
3770
|
+
)
|
|
3771
|
+
.expect("schema setup");
|
|
3772
|
+
schema
|
|
3773
|
+
.add_table(
|
|
3774
|
+
"u",
|
|
3775
|
+
&[("amount".into(), DataType::BigInt { length: None })],
|
|
3776
|
+
None,
|
|
3777
|
+
)
|
|
3778
|
+
.expect("schema setup");
|
|
3779
|
+
|
|
3780
|
+
let node = lineage_with_schema(
|
|
3781
|
+
"amount",
|
|
3782
|
+
&expr,
|
|
3783
|
+
Some(&schema),
|
|
3784
|
+
Some(DialectType::DuckDB),
|
|
3785
|
+
false,
|
|
3786
|
+
)
|
|
3787
|
+
.expect("lineage_with_schema should tolerate unknown join keys");
|
|
3788
|
+
|
|
3789
|
+
assert_lineage_contains(&node, "b.amount");
|
|
3790
|
+
}
|
|
3791
|
+
|
|
3708
3792
|
#[test]
|
|
3709
3793
|
fn test_lineage_with_schema_correlated_scalar_subquery() {
|
|
3710
3794
|
let query = "SELECT id, (SELECT AVG(val) FROM t2 WHERE t2.id = t1.id) AS avg_val FROM t1";
|
|
@@ -187,7 +187,9 @@ pub fn analyze_query(sql: &str, options: AnalyzeQueryOptions) -> Result<QueryAna
|
|
|
187
187
|
let star_projections = star_projection_facts(&original_expression, mapping_schema.as_ref());
|
|
188
188
|
|
|
189
189
|
if let Some(schema) = mapping_schema.as_ref() {
|
|
190
|
-
let qualify_options = QualifyColumnsOptions::new()
|
|
190
|
+
let qualify_options = QualifyColumnsOptions::new()
|
|
191
|
+
.with_dialect(options.dialect)
|
|
192
|
+
.with_allow_partial(true);
|
|
191
193
|
expression = qualify_columns(expression, schema, &qualify_options)
|
|
192
194
|
.map_err(|e| Error::internal(format!("query analysis qualification failed: {e}")))?;
|
|
193
195
|
}
|
|
@@ -217,6 +217,29 @@ fn test_validate_with_schema_unknown_column() {
|
|
|
217
217
|
);
|
|
218
218
|
}
|
|
219
219
|
|
|
220
|
+
#[test]
|
|
221
|
+
fn test_validate_with_schema_partial_schema_stays_strict() {
|
|
222
|
+
let mut schema = base_schema();
|
|
223
|
+
let users = schema
|
|
224
|
+
.tables
|
|
225
|
+
.iter_mut()
|
|
226
|
+
.find(|table| table.name == "users")
|
|
227
|
+
.expect("users table");
|
|
228
|
+
users.columns.retain(|column| column.name == "id");
|
|
229
|
+
|
|
230
|
+
let opts = SchemaValidationOptions::default();
|
|
231
|
+
let result = validate_with_schema(
|
|
232
|
+
"SELECT id, name FROM users",
|
|
233
|
+
DialectType::Generic,
|
|
234
|
+
&schema,
|
|
235
|
+
&opts,
|
|
236
|
+
);
|
|
237
|
+
assert!(!result.valid);
|
|
238
|
+
assert!(result.errors.iter().any(|error| {
|
|
239
|
+
error.code == validation_codes::E_UNKNOWN_COLUMN && error.message.contains("name")
|
|
240
|
+
}));
|
|
241
|
+
}
|
|
242
|
+
|
|
220
243
|
#[test]
|
|
221
244
|
fn test_validate_with_schema_function_catalog_unknown_function() {
|
|
222
245
|
let schema = base_schema();
|
{polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/issue227_strict_unsupported.rs
RENAMED
|
@@ -138,6 +138,31 @@ fn strict_transpile_rejects_array_agg_for_lossy_targets() {
|
|
|
138
138
|
assert!(err.to_string().contains("ARRAY_AGG"));
|
|
139
139
|
}
|
|
140
140
|
|
|
141
|
+
#[test]
|
|
142
|
+
fn strict_transpile_rejects_regex_predicates_for_tsql_targets() {
|
|
143
|
+
let sqls = [
|
|
144
|
+
"SELECT 1 FROM t WHERE p_brand SIMILAR TO 'Brand#[1-3][0-9]'",
|
|
145
|
+
"SELECT 1 FROM t WHERE c_phone ~ '^1[0-9]'",
|
|
146
|
+
"SELECT 1 FROM t WHERE c_phone !~ '^1[0-9]'",
|
|
147
|
+
"SELECT 1 FROM t WHERE c_phone ~* '^1[0-9]'",
|
|
148
|
+
"SELECT 1 FROM t WHERE c_phone !~* '^1[0-9]'",
|
|
149
|
+
"SELECT 1 FROM t WHERE REGEXP_LIKE(c_phone, '^1[0-9]')",
|
|
150
|
+
];
|
|
151
|
+
|
|
152
|
+
for sql in sqls {
|
|
153
|
+
for write in [DialectType::Fabric, DialectType::TSQL] {
|
|
154
|
+
let err =
|
|
155
|
+
transpile_with_level(sql, DialectType::PostgreSQL, write, UnsupportedLevel::Raise)
|
|
156
|
+
.expect_err("strict TSQL/Fabric transpile should reject regex predicates");
|
|
157
|
+
|
|
158
|
+
assert!(
|
|
159
|
+
err.to_string().contains("regular expression predicates"),
|
|
160
|
+
"unexpected error for PostgreSQL -> {write:?}: {err}"
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
141
166
|
#[test]
|
|
142
167
|
fn strict_transpile_rejects_postgres_only_functions() {
|
|
143
168
|
let err = transpile_with_level(
|
|
@@ -736,6 +736,118 @@ fn analyze_query_resolves_unnest_virtual_output_aliases_with_schema() {
|
|
|
736
736
|
}
|
|
737
737
|
}
|
|
738
738
|
|
|
739
|
+
#[test]
|
|
740
|
+
fn analyze_query_tolerates_partial_schema_for_unknown_columns() {
|
|
741
|
+
let analysis = analyze_query(
|
|
742
|
+
"SELECT order_id, amount FROM t",
|
|
743
|
+
AnalyzeQueryOptions {
|
|
744
|
+
dialect: DialectType::DuckDB,
|
|
745
|
+
schema: Some(single_column_schema(&["t"], "amount")),
|
|
746
|
+
},
|
|
747
|
+
)
|
|
748
|
+
.unwrap();
|
|
749
|
+
|
|
750
|
+
assert_eq!(analysis.projections.len(), 2);
|
|
751
|
+
assert_eq!(analysis.projections[0].name.as_deref(), Some("order_id"));
|
|
752
|
+
assert_eq!(analysis.projections[1].name.as_deref(), Some("amount"));
|
|
753
|
+
|
|
754
|
+
let order_id = &analysis.projections[0].upstream;
|
|
755
|
+
assert!(
|
|
756
|
+
order_id.iter().any(|reference| {
|
|
757
|
+
reference.column == "order_id"
|
|
758
|
+
&& reference.confidence == ReferenceConfidence::Resolved
|
|
759
|
+
&& reference.source_name.as_deref() == Some("t")
|
|
760
|
+
&& reference.table.as_deref() == Some("t")
|
|
761
|
+
}),
|
|
762
|
+
"expected best-effort order_id reference, got {order_id:?}"
|
|
763
|
+
);
|
|
764
|
+
|
|
765
|
+
let amount = &analysis.projections[1].upstream;
|
|
766
|
+
assert!(
|
|
767
|
+
amount.iter().any(|reference| {
|
|
768
|
+
reference.column == "amount"
|
|
769
|
+
&& reference.confidence == ReferenceConfidence::Resolved
|
|
770
|
+
&& reference.table.as_deref() == Some("t")
|
|
771
|
+
}),
|
|
772
|
+
"expected schema-backed amount reference, got {amount:?}"
|
|
773
|
+
);
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
#[test]
|
|
777
|
+
fn analyze_query_tolerates_partial_schema_for_qualified_unknown_columns() {
|
|
778
|
+
let analysis = analyze_query(
|
|
779
|
+
"SELECT t.order_id, t.amount FROM t",
|
|
780
|
+
AnalyzeQueryOptions {
|
|
781
|
+
dialect: DialectType::DuckDB,
|
|
782
|
+
schema: Some(single_column_schema(&["t"], "amount")),
|
|
783
|
+
},
|
|
784
|
+
)
|
|
785
|
+
.unwrap();
|
|
786
|
+
|
|
787
|
+
assert!(
|
|
788
|
+
analysis.projections[0].upstream.iter().any(|reference| {
|
|
789
|
+
reference.column == "order_id"
|
|
790
|
+
&& reference.confidence == ReferenceConfidence::Resolved
|
|
791
|
+
&& reference.table.as_deref() == Some("t")
|
|
792
|
+
}),
|
|
793
|
+
"expected qualified unknown column to stay as best-effort t.order_id, got {:?}",
|
|
794
|
+
analysis.projections[0].upstream
|
|
795
|
+
);
|
|
796
|
+
assert!(
|
|
797
|
+
analysis.projections[1].upstream.iter().any(|reference| {
|
|
798
|
+
reference.column == "amount" && reference.table.as_deref() == Some("t")
|
|
799
|
+
}),
|
|
800
|
+
"expected known t.amount to resolve, got {:?}",
|
|
801
|
+
analysis.projections[1].upstream
|
|
802
|
+
);
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
#[test]
|
|
806
|
+
fn analyze_query_tolerates_partial_schema_for_join_conditions() {
|
|
807
|
+
let schema: ValidationSchema = serde_json::from_value(json!({
|
|
808
|
+
"tables": [
|
|
809
|
+
{
|
|
810
|
+
"name": "t",
|
|
811
|
+
"columns": [{"name": "order_id", "type": "INT"}]
|
|
812
|
+
},
|
|
813
|
+
{
|
|
814
|
+
"name": "u",
|
|
815
|
+
"columns": [{"name": "amount", "type": "INT"}]
|
|
816
|
+
}
|
|
817
|
+
]
|
|
818
|
+
}))
|
|
819
|
+
.unwrap();
|
|
820
|
+
|
|
821
|
+
let analysis = analyze_query(
|
|
822
|
+
"SELECT a.order_id, b.amount FROM t a JOIN u b ON a.id = b.id",
|
|
823
|
+
AnalyzeQueryOptions {
|
|
824
|
+
dialect: DialectType::DuckDB,
|
|
825
|
+
schema: Some(schema),
|
|
826
|
+
},
|
|
827
|
+
)
|
|
828
|
+
.unwrap();
|
|
829
|
+
|
|
830
|
+
assert_eq!(analysis.projections.len(), 2);
|
|
831
|
+
assert!(
|
|
832
|
+
analysis.projections[0].upstream.iter().any(|reference| {
|
|
833
|
+
reference.column == "order_id"
|
|
834
|
+
&& reference.source_alias.as_deref() == Some("a")
|
|
835
|
+
&& reference.table.as_deref() == Some("t")
|
|
836
|
+
}),
|
|
837
|
+
"expected a.order_id to resolve, got {:?}",
|
|
838
|
+
analysis.projections[0].upstream
|
|
839
|
+
);
|
|
840
|
+
assert!(
|
|
841
|
+
analysis.projections[1].upstream.iter().any(|reference| {
|
|
842
|
+
reference.column == "amount"
|
|
843
|
+
&& reference.source_alias.as_deref() == Some("b")
|
|
844
|
+
&& reference.table.as_deref() == Some("u")
|
|
845
|
+
}),
|
|
846
|
+
"expected b.amount to resolve, got {:?}",
|
|
847
|
+
analysis.projections[1].upstream
|
|
848
|
+
);
|
|
849
|
+
}
|
|
850
|
+
|
|
739
851
|
#[test]
|
|
740
852
|
fn analyze_query_resolves_same_select_alias_reference() {
|
|
741
853
|
let analysis = analyze_query(
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
use polyglot_sql::generator::{Generator, GeneratorConfig};
|
|
4
4
|
use polyglot_sql::{
|
|
5
|
-
get_all_tables, parse, transpile, validate, Dialect, DialectType, Expression,
|
|
6
|
-
Parser, TokenType,
|
|
5
|
+
generate, get_all_tables, parse, transpile, validate, Dialect, DialectType, Expression,
|
|
6
|
+
ExpressionWalk, Parser, TokenType,
|
|
7
7
|
};
|
|
8
8
|
|
|
9
9
|
fn pg_to_tsql(sql: &str) -> String {
|
|
@@ -72,6 +72,51 @@ fn tsql_hex_literals_parse_and_roundtrip() {
|
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
+
#[test]
|
|
76
|
+
fn tsql_datepart_dayofweek_generates_valid_tsql_datepart() {
|
|
77
|
+
let cases = [
|
|
78
|
+
("WEEKDAY", "WEEKDAY"),
|
|
79
|
+
("dw", "WEEKDAY"),
|
|
80
|
+
("DAYOFWEEK", "WEEKDAY"),
|
|
81
|
+
("isowk", "ISO_WEEK"),
|
|
82
|
+
("WEEKISO", "ISO_WEEK"),
|
|
83
|
+
("tz", "TZOFFSET"),
|
|
84
|
+
("TIMEZONE_MINUTE", "TZOFFSET"),
|
|
85
|
+
];
|
|
86
|
+
|
|
87
|
+
for dialect in [DialectType::TSQL, DialectType::Fabric] {
|
|
88
|
+
for (input, expected) in cases {
|
|
89
|
+
let sql = format!("SELECT DATEPART({input}, o.order_date) AS dow FROM orders o");
|
|
90
|
+
let ast = parse(&sql, dialect)
|
|
91
|
+
.unwrap_or_else(|error| panic!("{dialect:?} DATEPART should parse: {error}"));
|
|
92
|
+
assert_eq!(ast.len(), 1);
|
|
93
|
+
|
|
94
|
+
let generated = generate(&ast[0], dialect)
|
|
95
|
+
.unwrap_or_else(|error| panic!("{dialect:?} DATEPART should generate: {error}"));
|
|
96
|
+
|
|
97
|
+
assert_eq!(
|
|
98
|
+
generated,
|
|
99
|
+
format!("SELECT DATEPART({expected}, o.order_date) AS dow FROM orders AS o"),
|
|
100
|
+
"failed for {dialect:?} DATEPART({input}, ...)"
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
#[test]
|
|
107
|
+
fn tsql_datepart_dayofweek_transpiles_to_valid_tsql_datepart() {
|
|
108
|
+
let sql = "SELECT DATEPART(WEEKDAY, o.order_date) AS dow FROM orders o";
|
|
109
|
+
|
|
110
|
+
assert_eq!(
|
|
111
|
+
transpile(sql, DialectType::TSQL, DialectType::TSQL).expect("TSQL identity transpile"),
|
|
112
|
+
vec!["SELECT DATEPART(WEEKDAY, o.order_date) AS dow FROM orders AS o"]
|
|
113
|
+
);
|
|
114
|
+
assert_eq!(
|
|
115
|
+
transpile(sql, DialectType::TSQL, DialectType::Fabric).expect("TSQL to Fabric transpile"),
|
|
116
|
+
vec!["SELECT DATEPART(WEEKDAY, o.order_date) AS dow FROM orders AS o"]
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
|
|
75
120
|
// ---------------------------------------------------------------------------
|
|
76
121
|
// T-SQL SET options
|
|
77
122
|
// ---------------------------------------------------------------------------
|
|
@@ -113,6 +113,23 @@ def test_lineage_with_schema_resolves_ambiguous_column():
|
|
|
113
113
|
assert any(name == "u.id" for name in names), f"expected u.id in lineage tree, got: {names}"
|
|
114
114
|
|
|
115
115
|
|
|
116
|
+
def test_lineage_with_schema_tolerates_partial_schema():
|
|
117
|
+
schema = {
|
|
118
|
+
"tables": [
|
|
119
|
+
{
|
|
120
|
+
"name": "t",
|
|
121
|
+
"columns": [{"name": "amount", "type": "INT"}],
|
|
122
|
+
}
|
|
123
|
+
]
|
|
124
|
+
}
|
|
125
|
+
result = polyglot_sql.lineage_with_schema(
|
|
126
|
+
"amount", "SELECT order_id, amount FROM t", schema, dialect="duckdb"
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
names = collect_names(result)
|
|
130
|
+
assert "t.amount" in names
|
|
131
|
+
|
|
132
|
+
|
|
116
133
|
def test_bigquery_unnest_lineage_marks_virtual_source():
|
|
117
134
|
sql = """
|
|
118
135
|
SELECT date_val AS week_start
|
{polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/tests/test_query_analysis.py
RENAMED
|
@@ -35,6 +35,36 @@ def test_analyze_query_accepts_schema_options():
|
|
|
35
35
|
assert result["projections"][0]["castType"] == "TEXT"
|
|
36
36
|
|
|
37
37
|
|
|
38
|
+
def test_analyze_query_tolerates_partial_schema():
|
|
39
|
+
schema = {
|
|
40
|
+
"tables": [
|
|
41
|
+
{
|
|
42
|
+
"name": "t",
|
|
43
|
+
"columns": [{"name": "amount", "type": "INT"}],
|
|
44
|
+
}
|
|
45
|
+
]
|
|
46
|
+
}
|
|
47
|
+
result = polyglot_sql.analyze_query(
|
|
48
|
+
"SELECT order_id, amount FROM t",
|
|
49
|
+
{"schema": schema, "dialect": "duckdb"},
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
assert [projection["name"] for projection in result["projections"]] == [
|
|
53
|
+
"order_id",
|
|
54
|
+
"amount",
|
|
55
|
+
]
|
|
56
|
+
assert any(
|
|
57
|
+
reference["column"] == "order_id"
|
|
58
|
+
and reference["table"] == "t"
|
|
59
|
+
and reference["confidence"] == "resolved"
|
|
60
|
+
for reference in result["projections"][0]["upstream"]
|
|
61
|
+
)
|
|
62
|
+
assert any(
|
|
63
|
+
reference["column"] == "amount" and reference["table"] == "t"
|
|
64
|
+
for reference in result["projections"][1]["upstream"]
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
|
|
38
68
|
def test_analyze_query_reports_transform_function_arguments():
|
|
39
69
|
schema = {
|
|
40
70
|
"tables": [
|
|
File without changes
|
|
File without changes
|