polyglot-sql 0.9.2__tar.gz → 0.10.0__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.9.2 → polyglot_sql-0.10.0}/Cargo.lock +6 -6
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/Cargo.toml +1 -1
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/PKG-INFO +55 -2
- {polyglot_sql-0.9.2/crates/polyglot-sql-python → polyglot_sql-0.10.0}/README.md +54 -1
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/Cargo.toml +2 -2
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/README.md +6 -1
- polyglot_sql-0.9.2/crates/polyglot-sql/src/builder/engine.rs → polyglot_sql-0.10.0/crates/polyglot-sql/src/ast_mutation.rs +8 -4
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/ast_transforms.rs +1 -1
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/builder/mod.rs +33 -1
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/builder/plan.rs +2 -1
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/dialects/duckdb.rs +148 -13
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/dialects/fabric.rs +2 -2
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/dialects/mod.rs +3 -2
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/dialects/mysql.rs +7 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/dialects/normalization/aggregates.rs +1 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/dialects/normalization/collections.rs +5 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/dialects/normalization/scalar.rs +18 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/dialects/normalization/types.rs +1 -3
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/dialects/postgres.rs +2 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/dialects/snowflake.rs +9 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/dialects/tsql.rs +1 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/error.rs +2 -2
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/expressions.rs +104 -4
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/generator.rs +31 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/lib.rs +7 -4
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/lineage.rs +114 -3
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/optimizer/annotate_types.rs +1328 -50
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/optimizer/mod.rs +24 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/optimizer/qualify_columns.rs +2 -13
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/optimizer/simplify.rs +24 -6
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/optimizer/subquery.rs +26 -1
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/parser.rs +1146 -493
- polyglot_sql-0.10.0/crates/polyglot-sql/src/query_analysis/column_uses.rs +735 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/query_analysis.rs +83 -2
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/scope.rs +87 -17
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/tokens.rs +12 -4
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/transforms.rs +2 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/validation/tests.rs +328 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/validation.rs +269 -219
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/tests/deep_nesting_regression.rs +1 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/tests/query_analysis.rs +843 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/tests/sqlglot_compat.rs +118 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/tests/tsql_regression.rs +20 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0/crates/polyglot-sql-python}/README.md +54 -1
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql-python/src/lib.rs +1 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql-python/src/types.rs +14 -0
- polyglot_sql-0.10.0/crates/polyglot-sql-python/src/validate.rs +55 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql-python/tests/test_parse.py +70 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql-python/tests/test_query_analysis.py +39 -0
- polyglot_sql-0.10.0/crates/polyglot-sql-python/tests/test_validate.py +173 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/python/polyglot_sql/__init__.py +2 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/python/polyglot_sql/__init__.pyi +42 -2
- polyglot_sql-0.9.2/crates/polyglot-sql-python/src/validate.rs +0 -23
- polyglot_sql-0.9.2/crates/polyglot-sql-python/tests/test_validate.py +0 -53
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/benches/allocation_hotspots.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/benches/ast_traversal.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/benches/in_list.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/benches/lineage.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/benches/parsing.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/benches/performance_hotspots.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/benches/rust_parsing.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/benches/transpile.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/examples/basic_usage.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/examples/bench_json.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/ast_children.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/ast_json.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/dialects/athena.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/dialects/bigquery.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/dialects/clickhouse.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/dialects/cockroachdb.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/dialects/databricks.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/dialects/datafusion.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/dialects/doris.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/dialects/dremio.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/dialects/drill.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/dialects/druid.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/dialects/dune.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/dialects/exasol.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/dialects/generic.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/dialects/hive.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/dialects/materialize.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/dialects/normalization/json.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/dialects/normalization/mod.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/dialects/normalization/operators.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/dialects/normalization/postgres_interval.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/dialects/normalization/statements.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/dialects/normalization/temporal.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/dialects/oracle.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/dialects/presto.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/dialects/redshift.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/dialects/risingwave.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/dialects/singlestore.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/dialects/solr.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/dialects/spark.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/dialects/sqlite.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/dialects/starrocks.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/dialects/tableau.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/dialects/teradata.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/dialects/tidb.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/dialects/trino.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/diff.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/format_tokens.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/function_catalog.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/function_registry.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/guard.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/helper.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/openlineage.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/optimizer/canonicalize.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/optimizer/eliminate_ctes.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/optimizer/eliminate_joins.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/optimizer/isolate_table_selects.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/optimizer/normalize.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/optimizer/normalize_identifiers.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/optimizer/optimize_joins.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/optimizer/optimizer.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/optimizer/pushdown_predicates.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/optimizer/pushdown_projections.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/optimizer/qualify_tables.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/planner.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/resolver.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/schema.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/set_operation.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/time.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/traversal.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/src/trie.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/tests/analyze_failures.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/tests/clickhouse_regression.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/tests/common/known_failures.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/tests/common/mod.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/tests/common/test_data.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/tests/common/test_runner.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/tests/create_view_security_comment_regression.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/tests/custom_clickhouse_coverage.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/tests/custom_clickhouse_parser.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/tests/custom_dialect.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/tests/custom_dialect_tests.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/tests/custom_fixtures/datafusion/ddl.json +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/tests/custom_fixtures/datafusion/dml.json +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/tests/custom_fixtures/datafusion/functions.json +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/tests/custom_fixtures/datafusion/identity.json +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/tests/custom_fixtures/datafusion/operators.json +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/tests/custom_fixtures/datafusion/select.json +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/tests/custom_fixtures/datafusion/transpilation.json +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/tests/custom_fixtures/datafusion/types.json +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/tests/data_type_api.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/tests/dialect_matrix.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/tests/error_handling.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/tests/fabric_regression.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/tests/fabric_tpch_regression.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/tests/identity_roundtrip.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/tests/oracle_data_types_regression.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/tests/postgres_explain_options.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/tests/postgres_regexp_clickhouse.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/tests/postgres_sqlite_regression.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/tests/query_analysis_regression.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/tests/snowflake_regression_test.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/tests/sqlglot_dialect_identity.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/tests/sqlglot_identity.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/tests/sqlglot_identity_detailed.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/tests/sqlglot_parser.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/tests/sqlglot_pretty.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/tests/sqlglot_transpilation.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/tests/sqlglot_transpile.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/tests/tpch_transpile_stack.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql/tests/transform_regression.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql-ast-derive/Cargo.toml +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql-ast-derive/src/lib.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql-function-catalogs/Cargo.toml +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql-function-catalogs/README.md +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql-function-catalogs/src/clickhouse.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql-function-catalogs/src/duckdb.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql-function-catalogs/src/lib.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql-function-catalogs/tools/clickhouse/extract_functions.py +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql-function-catalogs/tools/duckdb/extract_functions.py +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql-python/Cargo.toml +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql-python/docs/api.md +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql-python/docs/index.md +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql-python/mkdocs.yml +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql-python/src/annotate_types.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql-python/src/builders.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql-python/src/dialects.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql-python/src/diff.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql-python/src/errors.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql-python/src/expr.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql-python/src/expr_types.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql-python/src/format.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql-python/src/generate.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql-python/src/helpers.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql-python/src/lineage.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql-python/src/openlineage.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql-python/src/optimize.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql-python/src/parse.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql-python/src/query_analysis.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql-python/src/tokenize.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql-python/src/transforms.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql-python/src/transpile.rs +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql-python/tests/conftest.py +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql-python/tests/test_builders.py +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql-python/tests/test_compat.py +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql-python/tests/test_dialects.py +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql-python/tests/test_diff.py +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql-python/tests/test_expression.py +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql-python/tests/test_format.py +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql-python/tests/test_generate.py +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql-python/tests/test_lineage.py +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql-python/tests/test_optimize.py +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql-python/tests/test_transforms.py +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql-python/tests/test_transpile.py +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/crates/polyglot-sql-python/uv.lock +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/pyproject.toml +0 -0
- {polyglot_sql-0.9.2 → polyglot_sql-0.10.0}/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.
|
|
608
|
+
version = "0.10.0"
|
|
609
609
|
dependencies = [
|
|
610
610
|
"criterion",
|
|
611
611
|
"once_cell",
|
|
@@ -623,7 +623,7 @@ dependencies = [
|
|
|
623
623
|
|
|
624
624
|
[[package]]
|
|
625
625
|
name = "polyglot-sql-ast-derive"
|
|
626
|
-
version = "0.
|
|
626
|
+
version = "0.10.0"
|
|
627
627
|
dependencies = [
|
|
628
628
|
"proc-macro2",
|
|
629
629
|
"quote",
|
|
@@ -632,7 +632,7 @@ dependencies = [
|
|
|
632
632
|
|
|
633
633
|
[[package]]
|
|
634
634
|
name = "polyglot-sql-ffi"
|
|
635
|
-
version = "0.
|
|
635
|
+
version = "0.10.0"
|
|
636
636
|
dependencies = [
|
|
637
637
|
"cbindgen",
|
|
638
638
|
"polyglot-sql",
|
|
@@ -642,11 +642,11 @@ dependencies = [
|
|
|
642
642
|
|
|
643
643
|
[[package]]
|
|
644
644
|
name = "polyglot-sql-function-catalogs"
|
|
645
|
-
version = "0.
|
|
645
|
+
version = "0.10.0"
|
|
646
646
|
|
|
647
647
|
[[package]]
|
|
648
648
|
name = "polyglot-sql-python"
|
|
649
|
-
version = "0.
|
|
649
|
+
version = "0.10.0"
|
|
650
650
|
dependencies = [
|
|
651
651
|
"polyglot-sql",
|
|
652
652
|
"pyo3",
|
|
@@ -657,7 +657,7 @@ dependencies = [
|
|
|
657
657
|
|
|
658
658
|
[[package]]
|
|
659
659
|
name = "polyglot-sql-wasm"
|
|
660
|
-
version = "0.
|
|
660
|
+
version = "0.10.0"
|
|
661
661
|
dependencies = [
|
|
662
662
|
"console_error_panic_hook",
|
|
663
663
|
"js-sys",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: polyglot-sql
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.10.0
|
|
4
4
|
Classifier: Development Status :: 4 - Beta
|
|
5
5
|
Classifier: Intended Audience :: Developers
|
|
6
6
|
Classifier: License :: OSI Approved :: MIT License
|
|
@@ -150,6 +150,29 @@ if result:
|
|
|
150
150
|
print("valid")
|
|
151
151
|
```
|
|
152
152
|
|
|
153
|
+
Schema-aware validation uses the same Rust validator as the TypeScript SDK:
|
|
154
|
+
|
|
155
|
+
```python
|
|
156
|
+
sql = "SELECT o.order_id FROM orders o WHERE o.missing_column = TRUE"
|
|
157
|
+
schema = {"tables": [{"name": "orders", "columns": [{"name": "order_id", "type": "INT"}]}]}
|
|
158
|
+
result = polyglot_sql.validate_with_schema(
|
|
159
|
+
sql, schema, dialect="snowflake", check_types=True, check_references=True,
|
|
160
|
+
)
|
|
161
|
+
for error in result.errors:
|
|
162
|
+
print(error.code, error.message)
|
|
163
|
+
if error.start is not None and error.end is not None:
|
|
164
|
+
print(sql[error.start:error.end])
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Unknown tables, columns and aliases are checked by default. `check_references`
|
|
168
|
+
also checks ambiguous columns and foreign-key metadata; `check_types` enables
|
|
169
|
+
type checks. `strict` overrides the schema's `strict` value, which defaults to
|
|
170
|
+
`True`; `strict=False` reports reference/type findings as warnings. An empty
|
|
171
|
+
column list or a `*` column denotes an open schema, so unknown columns are not
|
|
172
|
+
rejected solely because their names are absent. Nonempty lists without `*`
|
|
173
|
+
are treated as complete. Options use snake_case keyword arguments, not an
|
|
174
|
+
`options` dictionary. Invalid schemas and unknown dialects raise `ValueError`.
|
|
175
|
+
|
|
153
176
|
```python
|
|
154
177
|
options = {
|
|
155
178
|
"producer": "https://github.com/tobilg/polyglot",
|
|
@@ -195,6 +218,26 @@ print(analysis["baseTables"][0]["name"]) # "orders"
|
|
|
195
218
|
print(analysis["baseTables"][0]["table"]) # "orders"
|
|
196
219
|
```
|
|
197
220
|
|
|
221
|
+
Non-projection uses are available through the same shared Rust analysis:
|
|
222
|
+
|
|
223
|
+
```python
|
|
224
|
+
analysis = polyglot_sql.analyze_query(
|
|
225
|
+
"SELECT o.id FROM orders o WHERE o.amount > 0", dialect="duckdb"
|
|
226
|
+
)
|
|
227
|
+
use = analysis["columnUses"][0]
|
|
228
|
+
print(use["context"]) # "filter"
|
|
229
|
+
print(use["references"][0]["column"]) # "amount"
|
|
230
|
+
print(use["scopePath"]) # "root"
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
`columnUses` groups references by clause expression without changing projection
|
|
234
|
+
lineage. It covers joins, filters, grouping, HAVING/QUALIFY, window keys/frames,
|
|
235
|
+
ordering and set-operation filter inputs. `scopePath`/`expressionPath` identify
|
|
236
|
+
the scope and expression; `expressionSql` is dialect-rendered SQL. Optional
|
|
237
|
+
`span` objects use half-open Unicode-character offsets in the original input.
|
|
238
|
+
Reference spans locate uses, not upstream definitions. Unknown or ambiguous
|
|
239
|
+
sources remain conservative; whole-expression spans are omitted when unavailable.
|
|
240
|
+
|
|
198
241
|
`analysis["relations"]` reports sources visible in the analyzed scope.
|
|
199
242
|
`analysis["baseTables"]` reports deduplicated physical table dependencies across
|
|
200
243
|
nested CTEs, derived tables, subqueries, and set-operation branches. For
|
|
@@ -259,6 +302,7 @@ All functions are exported from `polyglot_sql`.
|
|
|
259
302
|
- `format_sql(sql: str, dialect: str = "generic", *, max_input_bytes: int | None = None, max_tokens: int | None = None, max_ast_nodes: int | None = None, max_set_op_chain: int | None = None) -> str`
|
|
260
303
|
- `format(sql: str, dialect: str = "generic", *, max_input_bytes: int | None = None, max_tokens: int | None = None, max_ast_nodes: int | None = None, max_set_op_chain: int | None = None) -> str` (alias of `format_sql`)
|
|
261
304
|
- `validate(sql: str, dialect: str = "generic", *, strict_syntax: bool = False, semantic: bool = False) -> ValidationResult`
|
|
305
|
+
- `validate_with_schema(sql: str, schema: dict, dialect: str = "generic", *, check_types: bool = False, check_references: bool = False, strict: bool | None = None, semantic: bool = False, strict_syntax: bool = False) -> ValidationResult`
|
|
262
306
|
- `optimize(sql: str, dialect: str = "generic") -> str`
|
|
263
307
|
- `lineage(column: str, sql: str, dialect: str = "generic") -> dict`
|
|
264
308
|
- `lineage_at(ordinal: int, sql: str, dialect: str = "generic") -> dict`
|
|
@@ -294,7 +338,8 @@ Exception hierarchy:
|
|
|
294
338
|
|
|
295
339
|
Unknown dialect names raise built-in `ValueError`.
|
|
296
340
|
|
|
297
|
-
`validate(...)`
|
|
341
|
+
`validate(...)` and `validate_with_schema(...)` return `ValidationResult`:
|
|
342
|
+
|
|
298
343
|
- `result.valid: bool`
|
|
299
344
|
- `result.errors: list[ValidationErrorInfo]`
|
|
300
345
|
- `bool(result)` works (`True` when valid)
|
|
@@ -305,11 +350,19 @@ clause boundaries. `semantic=True` adds warning diagnostics W001-W004 for
|
|
|
305
350
|
`LIMIT` without `ORDER BY`; warnings do not make the result invalid.
|
|
306
351
|
|
|
307
352
|
Each `ValidationErrorInfo` has:
|
|
353
|
+
|
|
308
354
|
- `message: str`
|
|
309
355
|
- `line: int`
|
|
310
356
|
- `col: int`
|
|
311
357
|
- `code: str`
|
|
312
358
|
- `severity: str`
|
|
359
|
+
- `start: int | None` (zero-based Unicode character offset)
|
|
360
|
+
- `end: int | None` (exclusive Unicode character offset)
|
|
361
|
+
|
|
362
|
+
Source ranges refer to the original SQL and support Python string slicing.
|
|
363
|
+
Reference diagnostics point to the offending identifier when available;
|
|
364
|
+
synthetic or schema-only findings have no source range. Existing `line` and
|
|
365
|
+
`col` fields remain integers and use `0` when unavailable.
|
|
313
366
|
|
|
314
367
|
## Performance Note
|
|
315
368
|
|
|
@@ -123,6 +123,29 @@ if result:
|
|
|
123
123
|
print("valid")
|
|
124
124
|
```
|
|
125
125
|
|
|
126
|
+
Schema-aware validation uses the same Rust validator as the TypeScript SDK:
|
|
127
|
+
|
|
128
|
+
```python
|
|
129
|
+
sql = "SELECT o.order_id FROM orders o WHERE o.missing_column = TRUE"
|
|
130
|
+
schema = {"tables": [{"name": "orders", "columns": [{"name": "order_id", "type": "INT"}]}]}
|
|
131
|
+
result = polyglot_sql.validate_with_schema(
|
|
132
|
+
sql, schema, dialect="snowflake", check_types=True, check_references=True,
|
|
133
|
+
)
|
|
134
|
+
for error in result.errors:
|
|
135
|
+
print(error.code, error.message)
|
|
136
|
+
if error.start is not None and error.end is not None:
|
|
137
|
+
print(sql[error.start:error.end])
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Unknown tables, columns and aliases are checked by default. `check_references`
|
|
141
|
+
also checks ambiguous columns and foreign-key metadata; `check_types` enables
|
|
142
|
+
type checks. `strict` overrides the schema's `strict` value, which defaults to
|
|
143
|
+
`True`; `strict=False` reports reference/type findings as warnings. An empty
|
|
144
|
+
column list or a `*` column denotes an open schema, so unknown columns are not
|
|
145
|
+
rejected solely because their names are absent. Nonempty lists without `*`
|
|
146
|
+
are treated as complete. Options use snake_case keyword arguments, not an
|
|
147
|
+
`options` dictionary. Invalid schemas and unknown dialects raise `ValueError`.
|
|
148
|
+
|
|
126
149
|
```python
|
|
127
150
|
options = {
|
|
128
151
|
"producer": "https://github.com/tobilg/polyglot",
|
|
@@ -168,6 +191,26 @@ print(analysis["baseTables"][0]["name"]) # "orders"
|
|
|
168
191
|
print(analysis["baseTables"][0]["table"]) # "orders"
|
|
169
192
|
```
|
|
170
193
|
|
|
194
|
+
Non-projection uses are available through the same shared Rust analysis:
|
|
195
|
+
|
|
196
|
+
```python
|
|
197
|
+
analysis = polyglot_sql.analyze_query(
|
|
198
|
+
"SELECT o.id FROM orders o WHERE o.amount > 0", dialect="duckdb"
|
|
199
|
+
)
|
|
200
|
+
use = analysis["columnUses"][0]
|
|
201
|
+
print(use["context"]) # "filter"
|
|
202
|
+
print(use["references"][0]["column"]) # "amount"
|
|
203
|
+
print(use["scopePath"]) # "root"
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
`columnUses` groups references by clause expression without changing projection
|
|
207
|
+
lineage. It covers joins, filters, grouping, HAVING/QUALIFY, window keys/frames,
|
|
208
|
+
ordering and set-operation filter inputs. `scopePath`/`expressionPath` identify
|
|
209
|
+
the scope and expression; `expressionSql` is dialect-rendered SQL. Optional
|
|
210
|
+
`span` objects use half-open Unicode-character offsets in the original input.
|
|
211
|
+
Reference spans locate uses, not upstream definitions. Unknown or ambiguous
|
|
212
|
+
sources remain conservative; whole-expression spans are omitted when unavailable.
|
|
213
|
+
|
|
171
214
|
`analysis["relations"]` reports sources visible in the analyzed scope.
|
|
172
215
|
`analysis["baseTables"]` reports deduplicated physical table dependencies across
|
|
173
216
|
nested CTEs, derived tables, subqueries, and set-operation branches. For
|
|
@@ -232,6 +275,7 @@ All functions are exported from `polyglot_sql`.
|
|
|
232
275
|
- `format_sql(sql: str, dialect: str = "generic", *, max_input_bytes: int | None = None, max_tokens: int | None = None, max_ast_nodes: int | None = None, max_set_op_chain: int | None = None) -> str`
|
|
233
276
|
- `format(sql: str, dialect: str = "generic", *, max_input_bytes: int | None = None, max_tokens: int | None = None, max_ast_nodes: int | None = None, max_set_op_chain: int | None = None) -> str` (alias of `format_sql`)
|
|
234
277
|
- `validate(sql: str, dialect: str = "generic", *, strict_syntax: bool = False, semantic: bool = False) -> ValidationResult`
|
|
278
|
+
- `validate_with_schema(sql: str, schema: dict, dialect: str = "generic", *, check_types: bool = False, check_references: bool = False, strict: bool | None = None, semantic: bool = False, strict_syntax: bool = False) -> ValidationResult`
|
|
235
279
|
- `optimize(sql: str, dialect: str = "generic") -> str`
|
|
236
280
|
- `lineage(column: str, sql: str, dialect: str = "generic") -> dict`
|
|
237
281
|
- `lineage_at(ordinal: int, sql: str, dialect: str = "generic") -> dict`
|
|
@@ -267,7 +311,8 @@ Exception hierarchy:
|
|
|
267
311
|
|
|
268
312
|
Unknown dialect names raise built-in `ValueError`.
|
|
269
313
|
|
|
270
|
-
`validate(...)`
|
|
314
|
+
`validate(...)` and `validate_with_schema(...)` return `ValidationResult`:
|
|
315
|
+
|
|
271
316
|
- `result.valid: bool`
|
|
272
317
|
- `result.errors: list[ValidationErrorInfo]`
|
|
273
318
|
- `bool(result)` works (`True` when valid)
|
|
@@ -278,11 +323,19 @@ clause boundaries. `semantic=True` adds warning diagnostics W001-W004 for
|
|
|
278
323
|
`LIMIT` without `ORDER BY`; warnings do not make the result invalid.
|
|
279
324
|
|
|
280
325
|
Each `ValidationErrorInfo` has:
|
|
326
|
+
|
|
281
327
|
- `message: str`
|
|
282
328
|
- `line: int`
|
|
283
329
|
- `col: int`
|
|
284
330
|
- `code: str`
|
|
285
331
|
- `severity: str`
|
|
332
|
+
- `start: int | None` (zero-based Unicode character offset)
|
|
333
|
+
- `end: int | None` (exclusive Unicode character offset)
|
|
334
|
+
|
|
335
|
+
Source ranges refer to the original SQL and support Python string slicing.
|
|
336
|
+
Reference diagnostics point to the offending identifier when available;
|
|
337
|
+
synthetic or schema-only findings have no source range. Existing `line` and
|
|
338
|
+
`col` fields remain integers and use `0` when unavailable.
|
|
286
339
|
|
|
287
340
|
## Performance Note
|
|
288
341
|
|
|
@@ -100,14 +100,14 @@ function-catalog-all-dialects = [
|
|
|
100
100
|
]
|
|
101
101
|
|
|
102
102
|
[dependencies]
|
|
103
|
-
polyglot-sql-ast-derive = { path = "../polyglot-sql-ast-derive", version = "0.
|
|
103
|
+
polyglot-sql-ast-derive = { path = "../polyglot-sql-ast-derive", version = "0.10.0" }
|
|
104
104
|
serde = { workspace = true }
|
|
105
105
|
serde_json = { workspace = true }
|
|
106
106
|
thiserror = { workspace = true }
|
|
107
107
|
unicode-segmentation = { workspace = true }
|
|
108
108
|
stacker = { version = "0.1", optional = true }
|
|
109
109
|
ts-rs = { version = "12.0", features = ["serde-compat"], optional = true }
|
|
110
|
-
polyglot-sql-function-catalogs = { path = "../polyglot-sql-function-catalogs", version = "0.
|
|
110
|
+
polyglot-sql-function-catalogs = { path = "../polyglot-sql-function-catalogs", version = "0.10.0", optional = true, default-features = false }
|
|
111
111
|
|
|
112
112
|
[dev-dependencies]
|
|
113
113
|
pretty_assertions = "1.4"
|
|
@@ -25,7 +25,7 @@ By default, `polyglot-sql` enables the full public API. Parser-only consumers ca
|
|
|
25
25
|
disable default features and opt into only the dialect parsers they need:
|
|
26
26
|
|
|
27
27
|
```toml
|
|
28
|
-
polyglot-sql = { version = "0.
|
|
28
|
+
polyglot-sql = { version = "0.10.0", default-features = false }
|
|
29
29
|
```
|
|
30
30
|
|
|
31
31
|
```toml
|
|
@@ -479,6 +479,11 @@ Athena, BigQuery, ClickHouse, CockroachDB, DataFusion, Databricks, Doris, Dremio
|
|
|
479
479
|
| `time` | Enable time-format conversion helpers |
|
|
480
480
|
| `bindings` | Enable `ts-rs` TypeScript type generation |
|
|
481
481
|
|
|
482
|
+
With `default-features = false`, `ast-tools` and `semantic` can be used without
|
|
483
|
+
enabling `builder` or `generate`. AST transforms reuse the same internal mutation
|
|
484
|
+
primitives as the native and serializable builders, while the public builder APIs
|
|
485
|
+
remain gated by `builder`.
|
|
486
|
+
|
|
482
487
|
## License
|
|
483
488
|
|
|
484
489
|
[MIT](../../LICENSE)
|
|
@@ -1,8 +1,12 @@
|
|
|
1
|
-
//! Canonical AST construction and mutation primitives shared by
|
|
1
|
+
//! Canonical AST construction and mutation primitives shared by AST consumers.
|
|
2
2
|
//!
|
|
3
|
-
//!
|
|
4
|
-
//!
|
|
5
|
-
//!
|
|
3
|
+
//! AST transform helpers, the native fluent builder, and serializable builder
|
|
4
|
+
//! plans delegate their AST edits here so a clause has exactly one implementation.
|
|
5
|
+
//! This module depends only on AST and error types, not the optional public builder
|
|
6
|
+
//! API, SQL generation, serde, or a language binding.
|
|
7
|
+
|
|
8
|
+
// AST-only consumers use a subset of the primitives; builders use the full set.
|
|
9
|
+
#![cfg_attr(not(feature = "builder"), allow(dead_code))]
|
|
6
10
|
|
|
7
11
|
use crate::error::{Error, Result};
|
|
8
12
|
use crate::expressions::*;
|
|
@@ -55,9 +55,9 @@
|
|
|
55
55
|
//! .build();
|
|
56
56
|
//! ```
|
|
57
57
|
|
|
58
|
-
pub(crate) mod engine;
|
|
59
58
|
pub mod plan;
|
|
60
59
|
|
|
60
|
+
use crate::ast_mutation as engine;
|
|
61
61
|
use crate::expressions::*;
|
|
62
62
|
use crate::generator::{Generator, GeneratorConfig, NotInStyle};
|
|
63
63
|
use crate::parser::Parser;
|
|
@@ -552,6 +552,7 @@ pub fn trim(expr: Expr) -> Expr {
|
|
|
552
552
|
position: TrimPosition::Both,
|
|
553
553
|
sql_standard_syntax: false,
|
|
554
554
|
position_explicit: false,
|
|
555
|
+
inferred_type: None,
|
|
555
556
|
})))
|
|
556
557
|
}
|
|
557
558
|
|
|
@@ -2811,6 +2812,37 @@ mod tests {
|
|
|
2811
2812
|
assert_eq!(sql, "SELECT CAST(id AS VARCHAR) FROM users");
|
|
2812
2813
|
}
|
|
2813
2814
|
|
|
2815
|
+
#[test]
|
|
2816
|
+
fn test_cast_int128() {
|
|
2817
|
+
for name in ["HUGEINT", "INT128"] {
|
|
2818
|
+
let Expression::Cast(cast) = col("value").cast(name).0 else {
|
|
2819
|
+
panic!("expected cast");
|
|
2820
|
+
};
|
|
2821
|
+
assert_eq!(cast.to, DataType::Int128);
|
|
2822
|
+
}
|
|
2823
|
+
}
|
|
2824
|
+
|
|
2825
|
+
#[test]
|
|
2826
|
+
fn test_cast_unsigned_integer_types() {
|
|
2827
|
+
for (name, expected) in [
|
|
2828
|
+
("UTINYINT", DataType::UInt8),
|
|
2829
|
+
("UINT8", DataType::UInt8),
|
|
2830
|
+
("USMALLINT", DataType::UInt16),
|
|
2831
|
+
("UINT16", DataType::UInt16),
|
|
2832
|
+
("UINTEGER", DataType::UInt32),
|
|
2833
|
+
("UINT32", DataType::UInt32),
|
|
2834
|
+
("UBIGINT", DataType::UInt64),
|
|
2835
|
+
("UINT64", DataType::UInt64),
|
|
2836
|
+
("UHUGEINT", DataType::UInt128),
|
|
2837
|
+
("UINT128", DataType::UInt128),
|
|
2838
|
+
] {
|
|
2839
|
+
let Expression::Cast(cast) = col("value").cast(name).0 else {
|
|
2840
|
+
panic!("expected cast")
|
|
2841
|
+
};
|
|
2842
|
+
assert_eq!(cast.to, expected, "{name}");
|
|
2843
|
+
}
|
|
2844
|
+
}
|
|
2845
|
+
|
|
2814
2846
|
#[test]
|
|
2815
2847
|
fn test_from_starter() {
|
|
2816
2848
|
let sql = from("users").select_cols(["id", "name"]).to_sql();
|
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
//! provides a serializable, immutable expression plan so language bindings can
|
|
5
5
|
//! share coercion, parsing, and AST-editing semantics without duplicating them.
|
|
6
6
|
|
|
7
|
-
use crate::
|
|
7
|
+
use crate::ast_mutation as engine;
|
|
8
|
+
use crate::builder::{self, Expr};
|
|
8
9
|
use crate::dialects::Dialect;
|
|
9
10
|
use crate::error::{Error, Result};
|
|
10
11
|
use crate::expressions::*;
|
|
@@ -1520,6 +1520,9 @@ impl DuckDBDialect {
|
|
|
1520
1520
|
DataType::Custom { ref name } => {
|
|
1521
1521
|
let upper = name.to_uppercase();
|
|
1522
1522
|
match upper.as_str() {
|
|
1523
|
+
name if DataType::from_unsigned_name(name).is_some() => {
|
|
1524
|
+
DataType::from_unsigned_name(name).unwrap()
|
|
1525
|
+
}
|
|
1523
1526
|
// INT64 -> BIGINT
|
|
1524
1527
|
"INT64" | "INT8" => DataType::BigInt { length: None },
|
|
1525
1528
|
// INT32, INT4, SIGNED -> INT
|
|
@@ -1532,13 +1535,7 @@ impl DuckDBDialect {
|
|
|
1532
1535
|
// INT1 -> TINYINT
|
|
1533
1536
|
"INT1" => DataType::TinyInt { length: None },
|
|
1534
1537
|
// HUGEINT -> INT128
|
|
1535
|
-
"HUGEINT" => DataType::
|
|
1536
|
-
name: "INT128".to_string(),
|
|
1537
|
-
},
|
|
1538
|
-
// UHUGEINT -> UINT128
|
|
1539
|
-
"UHUGEINT" => DataType::Custom {
|
|
1540
|
-
name: "UINT128".to_string(),
|
|
1541
|
-
},
|
|
1538
|
+
"HUGEINT" | "INT128" => DataType::Int128,
|
|
1542
1539
|
// BPCHAR -> TEXT
|
|
1543
1540
|
"BPCHAR" => DataType::Text,
|
|
1544
1541
|
// CHARACTER VARYING, CHAR VARYING -> TEXT
|
|
@@ -2160,6 +2157,7 @@ impl DuckDBDialect {
|
|
|
2160
2157
|
// LIST_VALUE -> Array literal notation [...]
|
|
2161
2158
|
"LIST_VALUE" => Ok(Expression::Array(Box::new(crate::expressions::Array {
|
|
2162
2159
|
expressions: f.args,
|
|
2160
|
+
inferred_type: None,
|
|
2163
2161
|
}))),
|
|
2164
2162
|
|
|
2165
2163
|
// ARRAY_AGG -> LIST in DuckDB (or array_agg which is also supported)
|
|
@@ -3379,9 +3377,7 @@ impl DuckDBDialect {
|
|
|
3379
3377
|
Ok(Expression::BitwiseLeftShift(Box::new(BinaryOp {
|
|
3380
3378
|
left: Expression::Cast(Box::new(Cast {
|
|
3381
3379
|
this: a,
|
|
3382
|
-
to: DataType::
|
|
3383
|
-
name: "INT128".to_string(),
|
|
3384
|
-
},
|
|
3380
|
+
to: DataType::Int128,
|
|
3385
3381
|
trailing_comments: Vec::new(),
|
|
3386
3382
|
double_colon_syntax: false,
|
|
3387
3383
|
format: None,
|
|
@@ -3445,9 +3441,7 @@ impl DuckDBDialect {
|
|
|
3445
3441
|
Ok(Expression::BitwiseRightShift(Box::new(BinaryOp {
|
|
3446
3442
|
left: Expression::Cast(Box::new(Cast {
|
|
3447
3443
|
this: a,
|
|
3448
|
-
to: DataType::
|
|
3449
|
-
name: "INT128".to_string(),
|
|
3450
|
-
},
|
|
3444
|
+
to: DataType::Int128,
|
|
3451
3445
|
trailing_comments: Vec::new(),
|
|
3452
3446
|
double_colon_syntax: false,
|
|
3453
3447
|
format: None,
|
|
@@ -6464,6 +6458,7 @@ impl DuckDBDialect {
|
|
|
6464
6458
|
}));
|
|
6465
6459
|
let empty_result = Expression::Array(Box::new(crate::expressions::Array {
|
|
6466
6460
|
expressions: vec![null_struct],
|
|
6461
|
+
inferred_type: None,
|
|
6467
6462
|
}));
|
|
6468
6463
|
|
|
6469
6464
|
let range_upper = if n == 1 {
|
|
@@ -6513,6 +6508,7 @@ impl DuckDBDialect {
|
|
|
6513
6508
|
}));
|
|
6514
6509
|
let empty_array = Expression::Array(Box::new(crate::expressions::Array {
|
|
6515
6510
|
expressions: vec![],
|
|
6511
|
+
inferred_type: None,
|
|
6516
6512
|
}));
|
|
6517
6513
|
let zipped_struct = Expression::Struct(Box::new(Struct {
|
|
6518
6514
|
fields: args
|
|
@@ -7504,6 +7500,7 @@ impl DuckDBDialect {
|
|
|
7504
7500
|
mod tests {
|
|
7505
7501
|
use super::*;
|
|
7506
7502
|
use crate::dialects::Dialect;
|
|
7503
|
+
use crate::expressions::JoinKind;
|
|
7507
7504
|
|
|
7508
7505
|
fn transpile_to_duckdb(sql: &str) -> String {
|
|
7509
7506
|
transpile_to_duckdb_from(sql, DialectType::Generic)
|
|
@@ -7544,6 +7541,144 @@ mod tests {
|
|
|
7544
7541
|
assert!(result.contains("FROM users"));
|
|
7545
7542
|
}
|
|
7546
7543
|
|
|
7544
|
+
#[test]
|
|
7545
|
+
fn test_duckdb_keyword_relation_aliases() {
|
|
7546
|
+
let dialect = Dialect::get(DialectType::DuckDB);
|
|
7547
|
+
for alias in [
|
|
7548
|
+
"top",
|
|
7549
|
+
"TOP",
|
|
7550
|
+
"ToP",
|
|
7551
|
+
"first",
|
|
7552
|
+
"last",
|
|
7553
|
+
"begin",
|
|
7554
|
+
"type",
|
|
7555
|
+
"\"top\"",
|
|
7556
|
+
"\"where\"",
|
|
7557
|
+
] {
|
|
7558
|
+
for template in [
|
|
7559
|
+
"SELECT {alias}.item_id FROM ranked_items {as}{alias}",
|
|
7560
|
+
"WITH ranked_items AS (SELECT 1 AS item_id) SELECT {alias}.item_id FROM ranked_items {as}{alias}",
|
|
7561
|
+
"WITH ranked_items AS (SELECT 1 AS item_id), selected_items AS (SELECT 1 AS item_id) SELECT {alias}.item_id FROM selected_items JOIN ranked_items {as}{alias} ON {alias}.item_id = selected_items.item_id",
|
|
7562
|
+
"SELECT {alias}.item_id FROM (SELECT 1 AS item_id) {as}{alias}",
|
|
7563
|
+
"SELECT {alias}.item_id FROM range(1) {as}{alias}(item_id)",
|
|
7564
|
+
"SELECT {alias}.item_id FROM (VALUES (1)) {as}{alias}(item_id)",
|
|
7565
|
+
] {
|
|
7566
|
+
let template = template.replace("{alias}", alias);
|
|
7567
|
+
let explicit_sql = template.replace("{as}", "AS ");
|
|
7568
|
+
let expected = transpile_to_duckdb_from(&explicit_sql, DialectType::DuckDB);
|
|
7569
|
+
for as_keyword in ["", "AS "] {
|
|
7570
|
+
let sql = template.replace("{as}", as_keyword);
|
|
7571
|
+
let statements = dialect
|
|
7572
|
+
.parse(&sql)
|
|
7573
|
+
.unwrap_or_else(|error| panic!("Failed to parse {sql:?}: {error}"));
|
|
7574
|
+
assert_eq!(statements.len(), 1, "{sql}");
|
|
7575
|
+
let Expression::Select(select) = &statements[0] else {
|
|
7576
|
+
panic!("Expected SELECT for {sql}");
|
|
7577
|
+
};
|
|
7578
|
+
let relation = select.joins.last().map_or_else(
|
|
7579
|
+
|| &select.from.as_ref().unwrap().expressions[0],
|
|
7580
|
+
|join| &join.this,
|
|
7581
|
+
);
|
|
7582
|
+
let (identifier, columns) = match relation {
|
|
7583
|
+
Expression::Table(table) => (table.alias.as_ref().unwrap(), &table.column_aliases),
|
|
7584
|
+
Expression::Subquery(subquery) => (subquery.alias.as_ref().unwrap(), &subquery.column_aliases),
|
|
7585
|
+
Expression::Alias(alias) => (&alias.alias, &alias.column_aliases),
|
|
7586
|
+
_ => panic!("Expected aliased relation for {sql}"),
|
|
7587
|
+
};
|
|
7588
|
+
assert_eq!(identifier.name, alias.trim_matches('"'), "{sql}");
|
|
7589
|
+
assert_eq!(identifier.quoted, alias.starts_with('"'), "{sql}");
|
|
7590
|
+
if template.contains("(item_id)") {
|
|
7591
|
+
assert_eq!(columns.len(), 1, "{sql}");
|
|
7592
|
+
assert_eq!(columns[0].name, "item_id", "{sql}");
|
|
7593
|
+
}
|
|
7594
|
+
assert_eq!(
|
|
7595
|
+
transpile_to_duckdb_from(&sql, DialectType::DuckDB),
|
|
7596
|
+
expected,
|
|
7597
|
+
"{sql}"
|
|
7598
|
+
);
|
|
7599
|
+
}
|
|
7600
|
+
}
|
|
7601
|
+
}
|
|
7602
|
+
}
|
|
7603
|
+
|
|
7604
|
+
#[test]
|
|
7605
|
+
fn test_duckdb_keyword_relation_aliases_preserve_clause_boundaries() {
|
|
7606
|
+
let dialect = Dialect::get(DialectType::DuckDB);
|
|
7607
|
+
for alias in ["", " top"] {
|
|
7608
|
+
let sql = format!(
|
|
7609
|
+
"SELECT item_id, ROW_NUMBER() OVER w AS rn FROM ranked_items{alias} \
|
|
7610
|
+
WHERE item_id > 0 GROUP BY item_id HAVING COUNT(*) > 0 \
|
|
7611
|
+
WINDOW w AS (ORDER BY item_id) QUALIFY rn = 1 \
|
|
7612
|
+
ORDER BY item_id NULLS FIRST, rn NULLS LAST LIMIT 5 OFFSET 1"
|
|
7613
|
+
);
|
|
7614
|
+
let statements = dialect.parse(&sql).unwrap();
|
|
7615
|
+
let Expression::Select(select) = &statements[0] else {
|
|
7616
|
+
panic!("Expected SELECT for {sql}");
|
|
7617
|
+
};
|
|
7618
|
+
assert!(select.where_clause.is_some());
|
|
7619
|
+
assert!(select.group_by.is_some());
|
|
7620
|
+
assert!(select.having.is_some());
|
|
7621
|
+
assert!(select.windows.is_some());
|
|
7622
|
+
assert!(select.qualify.is_some());
|
|
7623
|
+
let ordering = &select.order_by.as_ref().unwrap().expressions;
|
|
7624
|
+
assert_eq!(ordering.len(), 2);
|
|
7625
|
+
assert_eq!(ordering[0].nulls_first, Some(true));
|
|
7626
|
+
assert_eq!(ordering[1].nulls_first, Some(false));
|
|
7627
|
+
assert!(select.limit.is_some());
|
|
7628
|
+
assert!(select.offset.is_some());
|
|
7629
|
+
let Expression::Table(table) = &select.from.as_ref().unwrap().expressions[0] else {
|
|
7630
|
+
panic!("Expected table source for {sql}");
|
|
7631
|
+
};
|
|
7632
|
+
assert_eq!(
|
|
7633
|
+
table.alias.as_ref().map(|a| a.name.as_str()),
|
|
7634
|
+
if alias.is_empty() { None } else { Some("top") }
|
|
7635
|
+
);
|
|
7636
|
+
|
|
7637
|
+
for (join, kind) in [
|
|
7638
|
+
("LEFT JOIN selected_items ON TRUE", JoinKind::Left),
|
|
7639
|
+
("POSITIONAL JOIN selected_items", JoinKind::Positional),
|
|
7640
|
+
] {
|
|
7641
|
+
let sql = format!("SELECT * FROM ranked_items{alias} {join}");
|
|
7642
|
+
let statements = dialect.parse(&sql).unwrap();
|
|
7643
|
+
let Expression::Select(select) = &statements[0] else {
|
|
7644
|
+
panic!("Expected SELECT for {sql}");
|
|
7645
|
+
};
|
|
7646
|
+
assert_eq!(select.joins.len(), 1, "{sql}");
|
|
7647
|
+
assert_eq!(select.joins[0].kind, kind, "{sql}");
|
|
7648
|
+
let Expression::Table(table) = &select.from.as_ref().unwrap().expressions[0] else {
|
|
7649
|
+
panic!("Expected table source for {sql}");
|
|
7650
|
+
};
|
|
7651
|
+
assert_eq!(
|
|
7652
|
+
table.alias.as_ref().map(|a| a.name.as_str()),
|
|
7653
|
+
if alias.is_empty() { None } else { Some("top") }
|
|
7654
|
+
);
|
|
7655
|
+
}
|
|
7656
|
+
}
|
|
7657
|
+
|
|
7658
|
+
// Truly reserved DuckDB words must not become implicit relation aliases.
|
|
7659
|
+
for alias in ["end", "where", "qualify", "select", "join", "limit"] {
|
|
7660
|
+
let sql = format!("SELECT * FROM ranked_items {alias}");
|
|
7661
|
+
assert!(dialect.parse(&sql).is_err(), "Unexpectedly accepted {sql}");
|
|
7662
|
+
}
|
|
7663
|
+
}
|
|
7664
|
+
|
|
7665
|
+
#[test]
|
|
7666
|
+
fn test_extract_quoted_date_parts() {
|
|
7667
|
+
for (quoted, canonical) in [("year", "YEAR"), ("month", "MONTH"), ("day", "DAY")] {
|
|
7668
|
+
let sql = format!("SELECT EXTRACT('{quoted}' FROM created_at) FROM events");
|
|
7669
|
+
assert_eq!(
|
|
7670
|
+
transpile_to_duckdb_from(&sql, DialectType::DuckDB),
|
|
7671
|
+
format!("SELECT EXTRACT({canonical} FROM created_at) FROM events")
|
|
7672
|
+
);
|
|
7673
|
+
}
|
|
7674
|
+
|
|
7675
|
+
let unquoted = "SELECT EXTRACT(YEAR FROM created_at) FROM events";
|
|
7676
|
+
assert_eq!(
|
|
7677
|
+
transpile_to_duckdb_from(unquoted, DialectType::DuckDB),
|
|
7678
|
+
unquoted
|
|
7679
|
+
);
|
|
7680
|
+
}
|
|
7681
|
+
|
|
7547
7682
|
#[test]
|
|
7548
7683
|
fn test_group_concat_to_listagg() {
|
|
7549
7684
|
let result = transpile_to_duckdb("SELECT GROUP_CONCAT(name)");
|
|
@@ -362,8 +362,8 @@ impl FabricDialect {
|
|
|
362
362
|
name: "UNIQUEIDENTIFIER".to_string(),
|
|
363
363
|
},
|
|
364
364
|
|
|
365
|
-
//
|
|
366
|
-
DataType::TinyInt { .. } => DataType::Custom {
|
|
365
|
+
// Preserve the existing signed/unsigned 8-bit mapping for typed ASTs.
|
|
366
|
+
DataType::TinyInt { .. } | DataType::UInt8 => DataType::Custom {
|
|
367
367
|
name: "SMALLINT".to_string(),
|
|
368
368
|
},
|
|
369
369
|
|
|
@@ -278,11 +278,12 @@ pub enum DialectType {
|
|
|
278
278
|
|
|
279
279
|
impl DialectType {
|
|
280
280
|
/// Whether SELECT projections may use string literals as column aliases.
|
|
281
|
-
|
|
281
|
+
/// DuckDB permits this only when the alias has an explicit AS keyword.
|
|
282
|
+
pub(crate) const fn supports_string_aliases(self, explicit_as: bool) -> bool {
|
|
282
283
|
matches!(
|
|
283
284
|
self,
|
|
284
285
|
DialectType::TSQL | DialectType::Fabric | DialectType::MySQL | DialectType::SQLite
|
|
285
|
-
)
|
|
286
|
+
) || (matches!(self, DialectType::DuckDB) && explicit_as)
|
|
286
287
|
}
|
|
287
288
|
}
|
|
288
289
|
|
|
@@ -800,6 +800,13 @@ impl MySQLDialect {
|
|
|
800
800
|
DataType::Boolean => DataType::Custom {
|
|
801
801
|
name: "SIGNED".to_string(),
|
|
802
802
|
},
|
|
803
|
+
// First-class counterparts of the legacy unsigned Custom types below.
|
|
804
|
+
// UINT128 is intentionally excluded: MySQL UNSIGNED is only 64 bits.
|
|
805
|
+
DataType::UInt8 | DataType::UInt16 | DataType::UInt32 | DataType::UInt64 => {
|
|
806
|
+
DataType::Custom {
|
|
807
|
+
name: "UNSIGNED".to_string(),
|
|
808
|
+
}
|
|
809
|
+
}
|
|
803
810
|
|
|
804
811
|
// Custom types that need mapping
|
|
805
812
|
DataType::Custom { name } => {
|