polyglot-sql 0.4.2__tar.gz → 0.4.3__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.4.2 → polyglot_sql-0.4.3}/Cargo.lock +5 -5
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/Cargo.toml +1 -1
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/PKG-INFO +1 -1
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/Cargo.toml +1 -1
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/mod.rs +25 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/expressions.rs +24 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/generator.rs +36 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/lineage.rs +70 -1
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/openlineage.rs +48 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/parser.rs +67 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/scope.rs +18 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/tokens.rs +3 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/traversal.rs +12 -0
- polyglot_sql-0.4.3/crates/polyglot-sql/tests/issue210_regression_test.rs +80 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/src/expr_types.rs +1 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/tests/test_lineage.py +6 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/tests/test_parse.py +20 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/python/polyglot_sql/__init__.py +3 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/python/polyglot_sql/__init__.pyi +1 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/README.md +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/README.md +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/benches/in_list.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/benches/parsing.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/benches/rust_parsing.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/benches/transpile.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/examples/basic_usage.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/examples/bench_json.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/ast_transforms.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/builder.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/athena.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/bigquery.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/clickhouse.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/cockroachdb.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/databricks.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/datafusion.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/doris.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/dremio.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/drill.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/druid.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/duckdb.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/dune.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/exasol.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/fabric.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/generic.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/hive.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/materialize.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/mysql.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/oracle.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/postgres.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/presto.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/redshift.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/risingwave.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/singlestore.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/snowflake.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/solr.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/spark.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/sqlite.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/starrocks.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/tableau.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/teradata.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/tidb.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/trino.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/tsql.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/diff.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/error.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/function_catalog.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/function_registry.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/helper.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/lib.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/optimizer/annotate_types.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/optimizer/canonicalize.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/optimizer/eliminate_ctes.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/optimizer/eliminate_joins.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/optimizer/isolate_table_selects.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/optimizer/mod.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/optimizer/normalize.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/optimizer/normalize_identifiers.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/optimizer/optimize_joins.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/optimizer/optimizer.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/optimizer/pushdown_predicates.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/optimizer/pushdown_projections.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/optimizer/qualify_columns.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/optimizer/qualify_tables.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/optimizer/simplify.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/optimizer/subquery.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/planner.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/resolver.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/schema.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/time.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/transforms.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/trie.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/validation/tests.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/validation.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/analyze_failures.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/clickhouse_regression.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/common/known_failures.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/common/mod.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/common/test_data.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/common/test_runner.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/custom_clickhouse_coverage.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/custom_clickhouse_parser.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/custom_dialect.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/custom_dialect_tests.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/custom_fixtures/datafusion/ddl.json +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/custom_fixtures/datafusion/dml.json +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/custom_fixtures/datafusion/functions.json +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/custom_fixtures/datafusion/identity.json +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/custom_fixtures/datafusion/operators.json +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/custom_fixtures/datafusion/select.json +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/custom_fixtures/datafusion/transpilation.json +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/custom_fixtures/datafusion/types.json +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/deep_nesting_regression.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/dialect_matrix.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/error_handling.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/fabric_regression.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/fabric_tpch_regression.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/identity_roundtrip.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/issue201_regression_test.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/postgres_sqlite_regression.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/snowflake_regression_test.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/sqlglot_compat.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/sqlglot_dialect_identity.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/sqlglot_identity.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/sqlglot_identity_detailed.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/sqlglot_parser.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/sqlglot_pretty.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/sqlglot_transpilation.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/sqlglot_transpile.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/tpch_transpile_stack.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/transform_regression.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/tsql_regression.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql-function-catalogs/Cargo.toml +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql-function-catalogs/README.md +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql-function-catalogs/src/clickhouse.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql-function-catalogs/src/duckdb.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql-function-catalogs/src/lib.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql-function-catalogs/tools/clickhouse/extract_functions.py +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql-function-catalogs/tools/duckdb/extract_functions.py +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/Cargo.toml +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/README.md +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/docs/api.md +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/docs/index.md +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/mkdocs.yml +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/src/annotate_types.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/src/dialects.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/src/diff.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/src/errors.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/src/expr.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/src/format.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/src/generate.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/src/helpers.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/src/lib.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/src/lineage.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/src/openlineage.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/src/optimize.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/src/parse.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/src/tokenize.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/src/transforms.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/src/transpile.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/src/types.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/src/validate.rs +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/tests/conftest.py +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/tests/test_compat.py +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/tests/test_dialects.py +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/tests/test_diff.py +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/tests/test_expression.py +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/tests/test_format.py +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/tests/test_generate.py +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/tests/test_optimize.py +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/tests/test_transforms.py +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/tests/test_transpile.py +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/tests/test_validate.py +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/uv.lock +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/pyproject.toml +0 -0
- {polyglot_sql-0.4.2 → polyglot_sql-0.4.3}/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.4.
|
|
608
|
+
version = "0.4.3"
|
|
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.4.
|
|
624
|
+
version = "0.4.3"
|
|
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.4.
|
|
634
|
+
version = "0.4.3"
|
|
635
635
|
|
|
636
636
|
[[package]]
|
|
637
637
|
name = "polyglot-sql-python"
|
|
638
|
-
version = "0.4.
|
|
638
|
+
version = "0.4.3"
|
|
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.4.
|
|
649
|
+
version = "0.4.3"
|
|
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.4.
|
|
109
|
+
polyglot-sql-function-catalogs = { path = "../polyglot-sql-function-catalogs", version = "0.4.3", optional = true, default-features = false }
|
|
110
110
|
|
|
111
111
|
[dev-dependencies]
|
|
112
112
|
pretty_assertions = "1.4"
|
|
@@ -2918,6 +2918,31 @@ where
|
|
|
2918
2918
|
Expression::CreateTask(ct)
|
|
2919
2919
|
}
|
|
2920
2920
|
|
|
2921
|
+
// Prepare: recurse into the prepared statement body
|
|
2922
|
+
Expression::Prepare(mut prepare) => {
|
|
2923
|
+
prepare.statement = transform_recursive(prepare.statement, transform_fn)?;
|
|
2924
|
+
Expression::Prepare(prepare)
|
|
2925
|
+
}
|
|
2926
|
+
|
|
2927
|
+
// Execute: recurse into procedure/prepared name and argument values
|
|
2928
|
+
Expression::Execute(mut execute) => {
|
|
2929
|
+
execute.this = transform_recursive(execute.this, transform_fn)?;
|
|
2930
|
+
execute.arguments = execute
|
|
2931
|
+
.arguments
|
|
2932
|
+
.into_iter()
|
|
2933
|
+
.map(|argument| transform_recursive(argument, transform_fn))
|
|
2934
|
+
.collect::<Result<Vec<_>>>()?;
|
|
2935
|
+
execute.parameters = execute
|
|
2936
|
+
.parameters
|
|
2937
|
+
.into_iter()
|
|
2938
|
+
.map(|mut parameter| {
|
|
2939
|
+
parameter.value = transform_recursive(parameter.value, transform_fn)?;
|
|
2940
|
+
Ok(parameter)
|
|
2941
|
+
})
|
|
2942
|
+
.collect::<Result<Vec<_>>>()?;
|
|
2943
|
+
Expression::Execute(execute)
|
|
2944
|
+
}
|
|
2945
|
+
|
|
2921
2946
|
// CreateProcedure: recurse into body expressions
|
|
2922
2947
|
Expression::CreateProcedure(mut cp) => {
|
|
2923
2948
|
if let Some(body) = cp.body.take() {
|
|
@@ -587,6 +587,8 @@ pub enum Expression {
|
|
|
587
587
|
// Transaction and other commands
|
|
588
588
|
Command(Box<Command>),
|
|
589
589
|
Kill(Box<Kill>),
|
|
590
|
+
/// PREPARE statement (PostgreSQL/generic prepared statement definition)
|
|
591
|
+
Prepare(Box<PrepareStatement>),
|
|
590
592
|
/// EXEC/EXECUTE statement (TSQL stored procedure call)
|
|
591
593
|
Execute(Box<ExecuteStatement>),
|
|
592
594
|
|
|
@@ -1197,6 +1199,7 @@ impl Expression {
|
|
|
1197
1199
|
| Expression::Describe(_)
|
|
1198
1200
|
| Expression::Show(_)
|
|
1199
1201
|
| Expression::Kill(_)
|
|
1202
|
+
| Expression::Prepare(_)
|
|
1200
1203
|
| Expression::Execute(_)
|
|
1201
1204
|
| Expression::Declare(_)
|
|
1202
1205
|
| Expression::Refresh(_)
|
|
@@ -2235,6 +2238,7 @@ impl Expression {
|
|
|
2235
2238
|
Expression::Command(_) => "command",
|
|
2236
2239
|
Expression::TryCatch(_) => "try_catch",
|
|
2237
2240
|
Expression::Kill(_) => "kill",
|
|
2241
|
+
Expression::Prepare(_) => "prepare",
|
|
2238
2242
|
Expression::Execute(_) => "execute",
|
|
2239
2243
|
Expression::Raw(_) => "raw",
|
|
2240
2244
|
Expression::CreateTask(_) => "create_task",
|
|
@@ -6008,6 +6012,20 @@ pub struct Command {
|
|
|
6008
6012
|
pub this: String,
|
|
6009
6013
|
}
|
|
6010
6014
|
|
|
6015
|
+
/// PREPARE statement (PostgreSQL/generic prepared statement definition)
|
|
6016
|
+
/// Syntax: PREPARE name [(type, ...)] AS statement
|
|
6017
|
+
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
|
6018
|
+
#[cfg_attr(feature = "bindings", derive(TS))]
|
|
6019
|
+
pub struct PrepareStatement {
|
|
6020
|
+
/// The prepared statement name.
|
|
6021
|
+
pub name: Identifier,
|
|
6022
|
+
/// Optional PostgreSQL parameter type list.
|
|
6023
|
+
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
|
6024
|
+
pub parameter_types: Vec<DataType>,
|
|
6025
|
+
/// The statement to execute when the prepared statement is invoked.
|
|
6026
|
+
pub statement: Expression,
|
|
6027
|
+
}
|
|
6028
|
+
|
|
6011
6029
|
/// T-SQL TRY/CATCH block.
|
|
6012
6030
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
|
6013
6031
|
#[cfg_attr(feature = "bindings", derive(TS))]
|
|
@@ -6030,6 +6048,12 @@ pub struct ExecuteStatement {
|
|
|
6030
6048
|
/// Named parameters: @param=value pairs
|
|
6031
6049
|
#[serde(default)]
|
|
6032
6050
|
pub parameters: Vec<ExecuteParameter>,
|
|
6051
|
+
/// Positional prepared statement arguments, used by PostgreSQL EXECUTE name(...).
|
|
6052
|
+
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
|
6053
|
+
pub arguments: Vec<Expression>,
|
|
6054
|
+
/// Whether this statement represents PostgreSQL-style prepared statement execution.
|
|
6055
|
+
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
|
|
6056
|
+
pub prepared: bool,
|
|
6033
6057
|
/// Trailing clause text (e.g. WITH RESULT SETS ((...)))
|
|
6034
6058
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
|
6035
6059
|
pub suffix: Option<String>,
|
|
@@ -3357,10 +3357,24 @@ impl Generator {
|
|
|
3357
3357
|
self.generate_expression(&kill.this)?;
|
|
3358
3358
|
Ok(())
|
|
3359
3359
|
}
|
|
3360
|
+
Expression::Prepare(prepare) => self.generate_prepare(prepare),
|
|
3360
3361
|
Expression::Execute(exec) => {
|
|
3361
3362
|
self.write_keyword("EXECUTE");
|
|
3362
3363
|
self.write_space();
|
|
3363
3364
|
self.generate_expression(&exec.this)?;
|
|
3365
|
+
if exec.prepared {
|
|
3366
|
+
if !exec.arguments.is_empty() {
|
|
3367
|
+
self.write("(");
|
|
3368
|
+
for (i, argument) in exec.arguments.iter().enumerate() {
|
|
3369
|
+
if i > 0 {
|
|
3370
|
+
self.write(", ");
|
|
3371
|
+
}
|
|
3372
|
+
self.generate_expression(argument)?;
|
|
3373
|
+
}
|
|
3374
|
+
self.write(")");
|
|
3375
|
+
}
|
|
3376
|
+
return Ok(());
|
|
3377
|
+
}
|
|
3364
3378
|
for (i, param) in exec.parameters.iter().enumerate() {
|
|
3365
3379
|
if i == 0 {
|
|
3366
3380
|
self.write_space();
|
|
@@ -15616,6 +15630,28 @@ impl Generator {
|
|
|
15616
15630
|
Ok(())
|
|
15617
15631
|
}
|
|
15618
15632
|
|
|
15633
|
+
fn generate_prepare(&mut self, prepare: &PrepareStatement) -> Result<()> {
|
|
15634
|
+
self.write_keyword("PREPARE");
|
|
15635
|
+
self.write_space();
|
|
15636
|
+
self.generate_identifier(&prepare.name)?;
|
|
15637
|
+
|
|
15638
|
+
if !prepare.parameter_types.is_empty() {
|
|
15639
|
+
self.write(" (");
|
|
15640
|
+
for (i, data_type) in prepare.parameter_types.iter().enumerate() {
|
|
15641
|
+
if i > 0 {
|
|
15642
|
+
self.write(", ");
|
|
15643
|
+
}
|
|
15644
|
+
self.generate_data_type(data_type)?;
|
|
15645
|
+
}
|
|
15646
|
+
self.write(")");
|
|
15647
|
+
}
|
|
15648
|
+
|
|
15649
|
+
self.write_space();
|
|
15650
|
+
self.write_keyword("AS");
|
|
15651
|
+
self.write_space();
|
|
15652
|
+
self.generate_expression(&prepare.statement)
|
|
15653
|
+
}
|
|
15654
|
+
|
|
15619
15655
|
/// Generate a pseudocolumn (Oracle ROWNUM, ROWID, LEVEL, etc.)
|
|
15620
15656
|
/// Pseudocolumns should NEVER be quoted, as quoting breaks them in Oracle
|
|
15621
15657
|
fn generate_pseudocolumn(&mut self, pc: &Pseudocolumn) -> Result<()> {
|
|
@@ -120,7 +120,8 @@ pub fn lineage(
|
|
|
120
120
|
trim_selects: bool,
|
|
121
121
|
) -> Result<LineageNode> {
|
|
122
122
|
// Fast path: skip clone when there are no CTEs to expand
|
|
123
|
-
let
|
|
123
|
+
let effective_sql = lineage_effective_expression(sql);
|
|
124
|
+
let has_with = matches!(effective_sql, Expression::Select(s) if s.with.is_some());
|
|
124
125
|
if !has_with {
|
|
125
126
|
return lineage_from_expression(column, sql, dialect, trim_selects);
|
|
126
127
|
}
|
|
@@ -181,6 +182,7 @@ fn lineage_from_expression(
|
|
|
181
182
|
dialect: Option<DialectType>,
|
|
182
183
|
trim_selects: bool,
|
|
183
184
|
) -> Result<LineageNode> {
|
|
185
|
+
let sql = lineage_effective_expression(sql);
|
|
184
186
|
let scope = build_scope(sql);
|
|
185
187
|
to_node(
|
|
186
188
|
ColumnRef::Name(column),
|
|
@@ -193,6 +195,13 @@ fn lineage_from_expression(
|
|
|
193
195
|
)
|
|
194
196
|
}
|
|
195
197
|
|
|
198
|
+
fn lineage_effective_expression(sql: &Expression) -> &Expression {
|
|
199
|
+
match sql {
|
|
200
|
+
Expression::Prepare(prepare) => &prepare.statement,
|
|
201
|
+
_ => sql,
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
196
205
|
// ---------------------------------------------------------------------------
|
|
197
206
|
// CTE star expansion
|
|
198
207
|
// ---------------------------------------------------------------------------
|
|
@@ -222,6 +231,11 @@ fn normalize_cte_name(ident: &Identifier) -> String {
|
|
|
222
231
|
/// case-insensitively (lowercased), while quoted names preserve their original case.
|
|
223
232
|
/// This matches sqlglot's `normalize_identifiers` behavior.
|
|
224
233
|
pub fn expand_cte_stars(expr: &mut Expression, schema: Option<&dyn Schema>) {
|
|
234
|
+
if let Expression::Prepare(prepare) = expr {
|
|
235
|
+
expand_cte_stars(&mut prepare.statement, schema);
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
|
|
225
239
|
let select = match expr {
|
|
226
240
|
Expression::Select(s) => s,
|
|
227
241
|
_ => return,
|
|
@@ -480,6 +494,14 @@ fn get_select_sources(select: &Select) -> Vec<SourceInfo> {
|
|
|
480
494
|
let mut sources = Vec::new();
|
|
481
495
|
|
|
482
496
|
fn extract_source(expr: &Expression) -> Option<SourceInfo> {
|
|
497
|
+
fn virtual_source_info(alias: &Identifier) -> SourceInfo {
|
|
498
|
+
SourceInfo {
|
|
499
|
+
alias: alias.name.clone(),
|
|
500
|
+
normalized: normalize_cte_name(alias),
|
|
501
|
+
fq_name: alias.name.clone(),
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
|
|
483
505
|
match expr {
|
|
484
506
|
Expression::Table(t) => {
|
|
485
507
|
let normalized = normalize_cte_name(&t.name);
|
|
@@ -513,6 +535,10 @@ fn get_select_sources(select: &Select) -> Vec<SourceInfo> {
|
|
|
513
535
|
fq_name,
|
|
514
536
|
})
|
|
515
537
|
}
|
|
538
|
+
Expression::Unnest(u) => u.alias.as_ref().map(virtual_source_info),
|
|
539
|
+
Expression::Alias(a) if matches!(&a.this, Expression::Unnest(_)) => {
|
|
540
|
+
Some(virtual_source_info(&a.alias))
|
|
541
|
+
}
|
|
516
542
|
Expression::Paren(p) => extract_source(&p.this),
|
|
517
543
|
_ => None,
|
|
518
544
|
}
|
|
@@ -971,6 +997,10 @@ fn source_names_from_from_join(scope: &Scope) -> Vec<String> {
|
|
|
971
997
|
Expression::Subquery(subquery) => {
|
|
972
998
|
subquery.alias.as_ref().map(|alias| alias.name.clone())
|
|
973
999
|
}
|
|
1000
|
+
Expression::Unnest(unnest) => unnest.alias.as_ref().map(|alias| alias.name.clone()),
|
|
1001
|
+
Expression::Alias(alias) if matches!(&alias.this, Expression::Unnest(_)) => {
|
|
1002
|
+
Some(alias.alias.name.clone())
|
|
1003
|
+
}
|
|
974
1004
|
Expression::Paren(paren) => source_name(&paren.this),
|
|
975
1005
|
_ => None,
|
|
976
1006
|
}
|
|
@@ -2486,6 +2516,45 @@ mod tests {
|
|
|
2486
2516
|
assert_eq!(node.name, "name");
|
|
2487
2517
|
}
|
|
2488
2518
|
|
|
2519
|
+
#[test]
|
|
2520
|
+
fn test_lineage_bigquery_unnest_alias_source_issue_209() {
|
|
2521
|
+
let expr = parse_one(
|
|
2522
|
+
r#"
|
|
2523
|
+
SELECT date_val AS week_start
|
|
2524
|
+
FROM UNNEST(GENERATE_DATE_ARRAY('2024-01-01', '2024-12-31', INTERVAL 1 WEEK)) AS date_val
|
|
2525
|
+
"#,
|
|
2526
|
+
DialectType::BigQuery,
|
|
2527
|
+
)
|
|
2528
|
+
.expect("parse");
|
|
2529
|
+
|
|
2530
|
+
let node = lineage("week_start", &expr, Some(DialectType::BigQuery), false)
|
|
2531
|
+
.expect("lineage should resolve UNNEST alias as a source");
|
|
2532
|
+
let child = node
|
|
2533
|
+
.downstream
|
|
2534
|
+
.first()
|
|
2535
|
+
.expect("week_start should have downstream lineage");
|
|
2536
|
+
|
|
2537
|
+
assert_eq!(child.name, "date_val.date_val");
|
|
2538
|
+
assert_eq!(child.source_name, "date_val");
|
|
2539
|
+
|
|
2540
|
+
let Expression::Column(column) = &child.expression else {
|
|
2541
|
+
panic!(
|
|
2542
|
+
"expected downstream column expression, got {:?}",
|
|
2543
|
+
child.expression
|
|
2544
|
+
);
|
|
2545
|
+
};
|
|
2546
|
+
assert_eq!(column.name.name, "date_val");
|
|
2547
|
+
assert_eq!(
|
|
2548
|
+
column.table.as_ref().map(|table| table.name.as_str()),
|
|
2549
|
+
Some("date_val")
|
|
2550
|
+
);
|
|
2551
|
+
assert!(
|
|
2552
|
+
matches!(&child.source, Expression::Alias(alias) if matches!(&alias.this, Expression::Unnest(_)) && alias.alias.name == "date_val"),
|
|
2553
|
+
"expected UNNEST source expression, got {:?}",
|
|
2554
|
+
child.source
|
|
2555
|
+
);
|
|
2556
|
+
}
|
|
2557
|
+
|
|
2489
2558
|
#[test]
|
|
2490
2559
|
fn test_lineage_with_schema_snowflake_datediff_date_part_issue_61() {
|
|
2491
2560
|
let expr = parse_one(
|
|
@@ -363,6 +363,7 @@ fn analyze_statement(
|
|
|
363
363
|
warnings: &mut Vec<OpenLineageWarning>,
|
|
364
364
|
) -> Result<StatementAnalysis> {
|
|
365
365
|
match expr {
|
|
366
|
+
Expression::Prepare(prepare) => analyze_statement(&prepare.statement, options, warnings),
|
|
366
367
|
Expression::Select(select) => {
|
|
367
368
|
let output = if let Some(into) = &select.into {
|
|
368
369
|
dataset_from_expression(&into.this, options)?
|
|
@@ -914,6 +915,7 @@ fn collect_source_table(expr: &Expression, result: &mut Vec<(String, String)>) {
|
|
|
914
915
|
|
|
915
916
|
fn leftmost_select(expr: &Expression) -> Option<&Select> {
|
|
916
917
|
match expr {
|
|
918
|
+
Expression::Prepare(prepare) => leftmost_select(&prepare.statement),
|
|
917
919
|
Expression::Select(select) => Some(select),
|
|
918
920
|
Expression::Union(union) => leftmost_select(&union.left),
|
|
919
921
|
Expression::Intersect(intersect) => leftmost_select(&intersect.left),
|
|
@@ -1103,6 +1105,19 @@ mod tests {
|
|
|
1103
1105
|
assert_eq!(field.input_fields[0].transformations[0].subtype, "IDENTITY");
|
|
1104
1106
|
}
|
|
1105
1107
|
|
|
1108
|
+
#[test]
|
|
1109
|
+
fn emits_column_lineage_for_prepared_statement_body() {
|
|
1110
|
+
let result = openlineage_column_lineage(
|
|
1111
|
+
"PREPARE leak AS SELECT id FROM sensitive_table WHERE id = $1",
|
|
1112
|
+
&options(),
|
|
1113
|
+
)
|
|
1114
|
+
.expect("lineage");
|
|
1115
|
+
let field = result.facet.fields.get("id").expect("field id");
|
|
1116
|
+
assert_eq!(field.input_fields.len(), 1);
|
|
1117
|
+
assert_eq!(field.input_fields[0].name, "sensitive_table");
|
|
1118
|
+
assert_eq!(field.input_fields[0].field, "id");
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1106
1121
|
#[test]
|
|
1107
1122
|
fn resolves_input_dataset_behind_table_alias() {
|
|
1108
1123
|
let result = openlineage_column_lineage("SELECT o.total FROM orders o", &options())
|
|
@@ -1165,6 +1180,39 @@ SELECT json_data FROM transform_cte
|
|
|
1165
1180
|
);
|
|
1166
1181
|
}
|
|
1167
1182
|
|
|
1183
|
+
#[test]
|
|
1184
|
+
fn emits_bigquery_unnest_alias_column_lineage_issue209() {
|
|
1185
|
+
let mut opts = options();
|
|
1186
|
+
opts.dialect = DialectType::BigQuery;
|
|
1187
|
+
opts.dataset_namespace = Some("bigquery://warehouse".to_string());
|
|
1188
|
+
opts.output_dataset = Some(OpenLineageDatasetId::new(
|
|
1189
|
+
"bigquery://warehouse",
|
|
1190
|
+
"calendar",
|
|
1191
|
+
));
|
|
1192
|
+
|
|
1193
|
+
let result = openlineage_column_lineage(
|
|
1194
|
+
r#"
|
|
1195
|
+
SELECT date_val AS week_start
|
|
1196
|
+
FROM UNNEST(GENERATE_DATE_ARRAY('2024-01-01', '2024-12-31', INTERVAL 1 WEEK)) AS date_val
|
|
1197
|
+
"#,
|
|
1198
|
+
&opts,
|
|
1199
|
+
)
|
|
1200
|
+
.expect("lineage");
|
|
1201
|
+
let field = result.facet.fields.get("week_start").expect("week_start");
|
|
1202
|
+
|
|
1203
|
+
assert_eq!(field.input_fields.len(), 1);
|
|
1204
|
+
assert_eq!(field.input_fields[0].name, "date_val");
|
|
1205
|
+
assert_eq!(field.input_fields[0].field, "date_val");
|
|
1206
|
+
assert!(
|
|
1207
|
+
result
|
|
1208
|
+
.warnings
|
|
1209
|
+
.iter()
|
|
1210
|
+
.all(|warning| warning.code != "W_EMPTY_FIELD_LINEAGE"),
|
|
1211
|
+
"did not expect empty-lineage warning, got {:?}",
|
|
1212
|
+
result.warnings
|
|
1213
|
+
);
|
|
1214
|
+
}
|
|
1215
|
+
|
|
1168
1216
|
#[test]
|
|
1169
1217
|
fn emits_aggregation_column_lineage() {
|
|
1170
1218
|
let result =
|
|
@@ -1136,6 +1136,7 @@ impl Parser {
|
|
|
1136
1136
|
self.fallback_to_command(statement_start)
|
|
1137
1137
|
}
|
|
1138
1138
|
TokenType::Kill => self.parse_kill(),
|
|
1139
|
+
TokenType::Prepare => self.parse_prepare(),
|
|
1139
1140
|
TokenType::Execute => {
|
|
1140
1141
|
// ClickHouse: EXECUTE AS username statement → parse as command
|
|
1141
1142
|
if matches!(
|
|
@@ -23658,6 +23659,48 @@ impl Parser {
|
|
|
23658
23659
|
Ok(Expression::Kill(Box::new(Kill { this, kind })))
|
|
23659
23660
|
}
|
|
23660
23661
|
|
|
23662
|
+
/// Parse PREPARE statement (PostgreSQL/generic prepared statement definition)
|
|
23663
|
+
/// PREPARE name [(type, ...)] AS statement
|
|
23664
|
+
fn parse_prepare(&mut self) -> Result<Expression> {
|
|
23665
|
+
self.expect(TokenType::Prepare)?;
|
|
23666
|
+
|
|
23667
|
+
let name = self.expect_identifier_or_keyword_with_quoted()?;
|
|
23668
|
+
|
|
23669
|
+
let mut parameter_types = Vec::new();
|
|
23670
|
+
if self.match_token(TokenType::LParen) {
|
|
23671
|
+
if !self.check(TokenType::RParen) {
|
|
23672
|
+
loop {
|
|
23673
|
+
parameter_types.push(self.parse_data_type()?);
|
|
23674
|
+
if !self.match_token(TokenType::Comma) {
|
|
23675
|
+
break;
|
|
23676
|
+
}
|
|
23677
|
+
}
|
|
23678
|
+
}
|
|
23679
|
+
self.expect(TokenType::RParen)?;
|
|
23680
|
+
}
|
|
23681
|
+
|
|
23682
|
+
self.expect(TokenType::As)?;
|
|
23683
|
+
let statement = self.parse_statement()?;
|
|
23684
|
+
|
|
23685
|
+
Ok(Expression::Prepare(Box::new(PrepareStatement {
|
|
23686
|
+
name,
|
|
23687
|
+
parameter_types,
|
|
23688
|
+
statement,
|
|
23689
|
+
})))
|
|
23690
|
+
}
|
|
23691
|
+
|
|
23692
|
+
fn is_postgres_prepared_execute_dialect(&self) -> bool {
|
|
23693
|
+
matches!(
|
|
23694
|
+
self.config.dialect,
|
|
23695
|
+
None | Some(crate::dialects::DialectType::Generic)
|
|
23696
|
+
| Some(crate::dialects::DialectType::PostgreSQL)
|
|
23697
|
+
| Some(crate::dialects::DialectType::Redshift)
|
|
23698
|
+
| Some(crate::dialects::DialectType::Materialize)
|
|
23699
|
+
| Some(crate::dialects::DialectType::RisingWave)
|
|
23700
|
+
| Some(crate::dialects::DialectType::CockroachDB)
|
|
23701
|
+
)
|
|
23702
|
+
}
|
|
23703
|
+
|
|
23661
23704
|
/// Parse EXEC/EXECUTE statement (TSQL stored procedure call)
|
|
23662
23705
|
/// EXEC [schema.]procedure_name [@param=value, ...]
|
|
23663
23706
|
fn parse_execute(&mut self) -> Result<Expression> {
|
|
@@ -23680,6 +23723,28 @@ impl Parser {
|
|
|
23680
23723
|
Expression::Table(Box::new(proc_name))
|
|
23681
23724
|
};
|
|
23682
23725
|
|
|
23726
|
+
if self.is_postgres_prepared_execute_dialect() && self.check(TokenType::LParen) {
|
|
23727
|
+
let arguments = self.parse_wrapped_csv_expressions()?;
|
|
23728
|
+
return Ok(Expression::Execute(Box::new(ExecuteStatement {
|
|
23729
|
+
this,
|
|
23730
|
+
parameters: Vec::new(),
|
|
23731
|
+
arguments,
|
|
23732
|
+
prepared: true,
|
|
23733
|
+
suffix: None,
|
|
23734
|
+
})));
|
|
23735
|
+
}
|
|
23736
|
+
if self.is_postgres_prepared_execute_dialect()
|
|
23737
|
+
&& (self.check(TokenType::Semicolon) || self.is_at_end())
|
|
23738
|
+
{
|
|
23739
|
+
return Ok(Expression::Execute(Box::new(ExecuteStatement {
|
|
23740
|
+
this,
|
|
23741
|
+
parameters: Vec::new(),
|
|
23742
|
+
arguments: Vec::new(),
|
|
23743
|
+
prepared: true,
|
|
23744
|
+
suffix: None,
|
|
23745
|
+
})));
|
|
23746
|
+
}
|
|
23747
|
+
|
|
23683
23748
|
// Parse optional parameters: @param=value [OUTPUT], ...
|
|
23684
23749
|
let mut parameters = Vec::new();
|
|
23685
23750
|
|
|
@@ -23743,6 +23808,8 @@ impl Parser {
|
|
|
23743
23808
|
Ok(Expression::Execute(Box::new(ExecuteStatement {
|
|
23744
23809
|
this,
|
|
23745
23810
|
parameters,
|
|
23811
|
+
arguments: Vec::new(),
|
|
23812
|
+
prepared: false,
|
|
23746
23813
|
suffix,
|
|
23747
23814
|
})))
|
|
23748
23815
|
}
|
|
@@ -533,6 +533,9 @@ fn collect_columns(expr: &Expression, columns: &mut Vec<ColumnRef>) {
|
|
|
533
533
|
Expression::Exists(_) | Expression::Subquery(_) => {
|
|
534
534
|
// These create their own scopes - don't collect from here
|
|
535
535
|
}
|
|
536
|
+
Expression::Prepare(prepare) => {
|
|
537
|
+
collect_columns(&prepare.statement, columns);
|
|
538
|
+
}
|
|
536
539
|
_ => {
|
|
537
540
|
// For other expressions, we might need to add more cases
|
|
538
541
|
}
|
|
@@ -551,6 +554,9 @@ pub fn build_scope(expression: &Expression) -> Scope {
|
|
|
551
554
|
|
|
552
555
|
fn build_scope_impl(expression: &Expression, current_scope: &mut Scope) {
|
|
553
556
|
match expression {
|
|
557
|
+
Expression::Prepare(prepare) => {
|
|
558
|
+
build_scope_impl(&prepare.statement, current_scope);
|
|
559
|
+
}
|
|
554
560
|
Expression::Select(select) => {
|
|
555
561
|
// Process CTEs first
|
|
556
562
|
if let Some(with) = &select.with {
|
|
@@ -674,6 +680,14 @@ fn add_table_to_scope(expr: &Expression, scope: &mut Scope) {
|
|
|
674
680
|
scope.add_source(name.clone(), expr.clone(), true);
|
|
675
681
|
scope.derived_table_scopes.push(derived_scope);
|
|
676
682
|
}
|
|
683
|
+
Expression::Unnest(unnest) => {
|
|
684
|
+
if let Some(alias) = &unnest.alias {
|
|
685
|
+
scope.add_source(alias.name.clone(), expr.clone(), false);
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
Expression::Alias(alias) if matches!(&alias.this, Expression::Unnest(_)) => {
|
|
689
|
+
scope.add_source(alias.alias.name.clone(), expr.clone(), false);
|
|
690
|
+
}
|
|
677
691
|
Expression::Paren(paren) => {
|
|
678
692
|
add_table_to_scope(&paren.this, scope);
|
|
679
693
|
}
|
|
@@ -848,6 +862,9 @@ impl<'a> WalkInScopeIter<'a> {
|
|
|
848
862
|
let mut children = Vec::new();
|
|
849
863
|
|
|
850
864
|
match expr {
|
|
865
|
+
Expression::Prepare(prepare) => {
|
|
866
|
+
children.push(&prepare.statement);
|
|
867
|
+
}
|
|
851
868
|
Expression::Select(select) => {
|
|
852
869
|
// Walk SELECT expressions
|
|
853
870
|
for e in &select.expressions {
|
|
@@ -1117,6 +1134,7 @@ pub fn traverse_scope(expression: &Expression) -> Vec<Scope> {
|
|
|
1117
1134
|
| Expression::Union(_)
|
|
1118
1135
|
| Expression::Intersect(_)
|
|
1119
1136
|
| Expression::Except(_)
|
|
1137
|
+
| Expression::Prepare(_)
|
|
1120
1138
|
| Expression::CreateTable(_) => {
|
|
1121
1139
|
let root = build_scope(expression);
|
|
1122
1140
|
root.traverse().into_iter().cloned().collect()
|
|
@@ -377,6 +377,7 @@ pub enum TokenType {
|
|
|
377
377
|
Command,
|
|
378
378
|
Comment,
|
|
379
379
|
Commit,
|
|
380
|
+
Prepare,
|
|
380
381
|
Preserve,
|
|
381
382
|
Connect,
|
|
382
383
|
ConnectBy,
|
|
@@ -898,6 +899,7 @@ impl TokenType {
|
|
|
898
899
|
| TokenType::Qualify
|
|
899
900
|
| TokenType::Returning
|
|
900
901
|
| TokenType::Language
|
|
902
|
+
| TokenType::Prepare
|
|
901
903
|
| TokenType::Preserve
|
|
902
904
|
| TokenType::Savepoint
|
|
903
905
|
| TokenType::Rollback
|
|
@@ -1171,6 +1173,7 @@ static DEFAULT_KEYWORDS: LazyLock<HashMap<String, TokenType>> = LazyLock::new(||
|
|
|
1171
1173
|
keywords.insert("COMMIT".to_string(), TokenType::Commit);
|
|
1172
1174
|
keywords.insert("BEGIN".to_string(), TokenType::Begin);
|
|
1173
1175
|
keywords.insert("DESCRIBE".to_string(), TokenType::Describe);
|
|
1176
|
+
keywords.insert("PREPARE".to_string(), TokenType::Prepare);
|
|
1174
1177
|
keywords.insert("PRESERVE".to_string(), TokenType::Preserve);
|
|
1175
1178
|
keywords.insert("TRANSACTION".to_string(), TokenType::Transaction);
|
|
1176
1179
|
keywords.insert("SAVEPOINT".to_string(), TokenType::Savepoint);
|
|
@@ -701,6 +701,18 @@ fn iter_children(expr: &Expression) -> Vec<(&'static str, &Expression)> {
|
|
|
701
701
|
Expression::CreateTask(ct) => {
|
|
702
702
|
children.push(("body", &ct.body));
|
|
703
703
|
}
|
|
704
|
+
Expression::Prepare(prepare) => {
|
|
705
|
+
children.push(("statement", &prepare.statement));
|
|
706
|
+
}
|
|
707
|
+
Expression::Execute(exec) => {
|
|
708
|
+
children.push(("this", &exec.this));
|
|
709
|
+
for argument in &exec.arguments {
|
|
710
|
+
children.push(("argument", argument));
|
|
711
|
+
}
|
|
712
|
+
for parameter in &exec.parameters {
|
|
713
|
+
children.push(("parameter", ¶meter.value));
|
|
714
|
+
}
|
|
715
|
+
}
|
|
704
716
|
Expression::Analyze(a) => {
|
|
705
717
|
if let Some(this) = &a.this {
|
|
706
718
|
children.push(("this", this));
|