polyglot-sql 0.4.1__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.
Files changed (175) hide show
  1. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/Cargo.lock +5 -5
  2. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/Cargo.toml +1 -1
  3. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/PKG-INFO +1 -1
  4. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/Cargo.toml +1 -1
  5. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/bigquery.rs +32 -0
  6. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/mod.rs +25 -0
  7. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/expressions.rs +24 -0
  8. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/generator.rs +36 -0
  9. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/lineage.rs +161 -6
  10. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/openlineage.rs +87 -0
  11. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/parser.rs +117 -20
  12. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/scope.rs +18 -0
  13. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/tokens.rs +3 -0
  14. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/traversal.rs +12 -0
  15. polyglot_sql-0.4.3/crates/polyglot-sql/tests/issue210_regression_test.rs +80 -0
  16. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/src/expr_types.rs +1 -0
  17. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/tests/test_lineage.py +6 -0
  18. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/tests/test_parse.py +20 -0
  19. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/python/polyglot_sql/__init__.py +3 -0
  20. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/python/polyglot_sql/__init__.pyi +1 -0
  21. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/README.md +0 -0
  22. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/README.md +0 -0
  23. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/benches/in_list.rs +0 -0
  24. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/benches/parsing.rs +0 -0
  25. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/benches/rust_parsing.rs +0 -0
  26. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/benches/transpile.rs +0 -0
  27. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/examples/basic_usage.rs +0 -0
  28. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/examples/bench_json.rs +0 -0
  29. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/ast_transforms.rs +0 -0
  30. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/builder.rs +0 -0
  31. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/athena.rs +0 -0
  32. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/clickhouse.rs +0 -0
  33. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/cockroachdb.rs +0 -0
  34. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/databricks.rs +0 -0
  35. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/datafusion.rs +0 -0
  36. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/doris.rs +0 -0
  37. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/dremio.rs +0 -0
  38. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/drill.rs +0 -0
  39. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/druid.rs +0 -0
  40. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/duckdb.rs +0 -0
  41. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/dune.rs +0 -0
  42. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/exasol.rs +0 -0
  43. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/fabric.rs +0 -0
  44. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/generic.rs +0 -0
  45. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/hive.rs +0 -0
  46. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/materialize.rs +0 -0
  47. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/mysql.rs +0 -0
  48. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/oracle.rs +0 -0
  49. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/postgres.rs +0 -0
  50. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/presto.rs +0 -0
  51. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/redshift.rs +0 -0
  52. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/risingwave.rs +0 -0
  53. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/singlestore.rs +0 -0
  54. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/snowflake.rs +0 -0
  55. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/solr.rs +0 -0
  56. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/spark.rs +0 -0
  57. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/sqlite.rs +0 -0
  58. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/starrocks.rs +0 -0
  59. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/tableau.rs +0 -0
  60. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/teradata.rs +0 -0
  61. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/tidb.rs +0 -0
  62. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/trino.rs +0 -0
  63. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/dialects/tsql.rs +0 -0
  64. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/diff.rs +0 -0
  65. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/error.rs +0 -0
  66. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/function_catalog.rs +0 -0
  67. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/function_registry.rs +0 -0
  68. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/helper.rs +0 -0
  69. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/lib.rs +0 -0
  70. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/optimizer/annotate_types.rs +0 -0
  71. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/optimizer/canonicalize.rs +0 -0
  72. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/optimizer/eliminate_ctes.rs +0 -0
  73. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/optimizer/eliminate_joins.rs +0 -0
  74. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/optimizer/isolate_table_selects.rs +0 -0
  75. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/optimizer/mod.rs +0 -0
  76. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/optimizer/normalize.rs +0 -0
  77. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/optimizer/normalize_identifiers.rs +0 -0
  78. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/optimizer/optimize_joins.rs +0 -0
  79. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/optimizer/optimizer.rs +0 -0
  80. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/optimizer/pushdown_predicates.rs +0 -0
  81. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/optimizer/pushdown_projections.rs +0 -0
  82. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/optimizer/qualify_columns.rs +0 -0
  83. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/optimizer/qualify_tables.rs +0 -0
  84. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/optimizer/simplify.rs +0 -0
  85. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/optimizer/subquery.rs +0 -0
  86. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/planner.rs +0 -0
  87. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/resolver.rs +0 -0
  88. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/schema.rs +0 -0
  89. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/time.rs +0 -0
  90. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/transforms.rs +0 -0
  91. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/trie.rs +0 -0
  92. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/validation/tests.rs +0 -0
  93. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/src/validation.rs +0 -0
  94. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/analyze_failures.rs +0 -0
  95. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/clickhouse_regression.rs +0 -0
  96. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/common/known_failures.rs +0 -0
  97. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/common/mod.rs +0 -0
  98. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/common/test_data.rs +0 -0
  99. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/common/test_runner.rs +0 -0
  100. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/custom_clickhouse_coverage.rs +0 -0
  101. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/custom_clickhouse_parser.rs +0 -0
  102. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/custom_dialect.rs +0 -0
  103. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/custom_dialect_tests.rs +0 -0
  104. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/custom_fixtures/datafusion/ddl.json +0 -0
  105. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/custom_fixtures/datafusion/dml.json +0 -0
  106. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/custom_fixtures/datafusion/functions.json +0 -0
  107. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/custom_fixtures/datafusion/identity.json +0 -0
  108. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/custom_fixtures/datafusion/operators.json +0 -0
  109. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/custom_fixtures/datafusion/select.json +0 -0
  110. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/custom_fixtures/datafusion/transpilation.json +0 -0
  111. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/custom_fixtures/datafusion/types.json +0 -0
  112. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/deep_nesting_regression.rs +0 -0
  113. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/dialect_matrix.rs +0 -0
  114. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/error_handling.rs +0 -0
  115. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/fabric_regression.rs +0 -0
  116. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/fabric_tpch_regression.rs +0 -0
  117. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/identity_roundtrip.rs +0 -0
  118. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/issue201_regression_test.rs +0 -0
  119. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/postgres_sqlite_regression.rs +0 -0
  120. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/snowflake_regression_test.rs +0 -0
  121. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/sqlglot_compat.rs +0 -0
  122. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/sqlglot_dialect_identity.rs +0 -0
  123. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/sqlglot_identity.rs +0 -0
  124. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/sqlglot_identity_detailed.rs +0 -0
  125. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/sqlglot_parser.rs +0 -0
  126. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/sqlglot_pretty.rs +0 -0
  127. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/sqlglot_transpilation.rs +0 -0
  128. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/sqlglot_transpile.rs +0 -0
  129. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/tpch_transpile_stack.rs +0 -0
  130. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/transform_regression.rs +0 -0
  131. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql/tests/tsql_regression.rs +0 -0
  132. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql-function-catalogs/Cargo.toml +0 -0
  133. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql-function-catalogs/README.md +0 -0
  134. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql-function-catalogs/src/clickhouse.rs +0 -0
  135. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql-function-catalogs/src/duckdb.rs +0 -0
  136. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql-function-catalogs/src/lib.rs +0 -0
  137. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql-function-catalogs/tools/clickhouse/extract_functions.py +0 -0
  138. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql-function-catalogs/tools/duckdb/extract_functions.py +0 -0
  139. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/Cargo.toml +0 -0
  140. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/README.md +0 -0
  141. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/docs/api.md +0 -0
  142. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/docs/index.md +0 -0
  143. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/mkdocs.yml +0 -0
  144. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/src/annotate_types.rs +0 -0
  145. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/src/dialects.rs +0 -0
  146. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/src/diff.rs +0 -0
  147. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/src/errors.rs +0 -0
  148. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/src/expr.rs +0 -0
  149. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/src/format.rs +0 -0
  150. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/src/generate.rs +0 -0
  151. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/src/helpers.rs +0 -0
  152. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/src/lib.rs +0 -0
  153. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/src/lineage.rs +0 -0
  154. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/src/openlineage.rs +0 -0
  155. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/src/optimize.rs +0 -0
  156. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/src/parse.rs +0 -0
  157. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/src/tokenize.rs +0 -0
  158. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/src/transforms.rs +0 -0
  159. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/src/transpile.rs +0 -0
  160. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/src/types.rs +0 -0
  161. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/src/validate.rs +0 -0
  162. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/tests/conftest.py +0 -0
  163. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/tests/test_compat.py +0 -0
  164. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/tests/test_dialects.py +0 -0
  165. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/tests/test_diff.py +0 -0
  166. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/tests/test_expression.py +0 -0
  167. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/tests/test_format.py +0 -0
  168. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/tests/test_generate.py +0 -0
  169. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/tests/test_optimize.py +0 -0
  170. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/tests/test_transforms.py +0 -0
  171. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/tests/test_transpile.py +0 -0
  172. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/tests/test_validate.py +0 -0
  173. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/crates/polyglot-sql-python/uv.lock +0 -0
  174. {polyglot_sql-0.4.1 → polyglot_sql-0.4.3}/pyproject.toml +0 -0
  175. {polyglot_sql-0.4.1 → 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.1"
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.1"
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.1"
634
+ version = "0.4.3"
635
635
 
636
636
  [[package]]
637
637
  name = "polyglot-sql-python"
638
- version = "0.4.1"
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.1"
649
+ version = "0.4.3"
650
650
  dependencies = [
651
651
  "console_error_panic_hook",
652
652
  "js-sys",
@@ -6,7 +6,7 @@ exclude = [
6
6
  ]
7
7
 
8
8
  [workspace.package]
9
- version = "0.4.1"
9
+ version = "0.4.3"
10
10
  edition = "2021"
11
11
  license = "MIT"
12
12
  authors = ["polyglot contributors"]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: polyglot-sql
3
- Version: 0.4.1
3
+ Version: 0.4.3
4
4
  Classifier: Development Status :: 4 - Beta
5
5
  Classifier: Intended Audience :: Developers
6
6
  Classifier: License :: OSI Approved :: MIT License
@@ -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.1", optional = true, default-features = false }
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"
@@ -1587,6 +1587,38 @@ mod tests {
1587
1587
  assert_eq!(result, expected, "SQL: {}", sql);
1588
1588
  }
1589
1589
 
1590
+ #[test]
1591
+ fn test_safe_namespace_parses_as_function() {
1592
+ let expr = parse_one(
1593
+ "SELECT SAFE.PARSE_JSON(data) AS json_data FROM t",
1594
+ DialectType::BigQuery,
1595
+ )
1596
+ .expect("parse");
1597
+
1598
+ let Expression::Select(select) = expr else {
1599
+ panic!("expected SELECT");
1600
+ };
1601
+ let Expression::Alias(alias) = &select.expressions[0] else {
1602
+ panic!("expected alias");
1603
+ };
1604
+ let Expression::Function(function) = &alias.this else {
1605
+ panic!("expected SAFE namespace call to parse as Function");
1606
+ };
1607
+
1608
+ assert_eq!(function.name, "SAFE.PARSE_JSON");
1609
+ assert_eq!(function.args.len(), 1);
1610
+ }
1611
+
1612
+ #[test]
1613
+ fn test_safe_namespace_identity() {
1614
+ bigquery_identity("SAFE.PARSE_JSON(data)", "SAFE.PARSE_JSON(data)");
1615
+ bigquery_identity(
1616
+ "SAFE.PARSE_DATE('%Y-%m-%d', date_col)",
1617
+ "SAFE.PARSE_DATE('%F', date_col)",
1618
+ );
1619
+ bigquery_identity("SAFE.DIVIDE(a, b)", "SAFE.DIVIDE(a, b)");
1620
+ }
1621
+
1590
1622
  #[test]
1591
1623
  fn test_cast_char_to_string() {
1592
1624
  bigquery_identity("CAST(x AS CHAR)", "CAST(x AS STRING)");
@@ -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 has_with = matches!(sql, Expression::Select(s) if s.with.is_some());
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
  }
@@ -714,7 +740,7 @@ fn to_node_inner(
714
740
  }
715
741
 
716
742
  // 7. Column references — trace each column to its source
717
- let col_refs = find_column_refs_in_expr(&select_expr);
743
+ let col_refs = find_column_refs_in_expr(&select_expr, dialect);
718
744
  for col_ref in col_refs {
719
745
  let col_name = &col_ref.column;
720
746
  if let Some(ref table_id) = col_ref.table {
@@ -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
  }
@@ -1265,13 +1295,30 @@ struct SimpleColumnRef {
1265
1295
  }
1266
1296
 
1267
1297
  /// Find all column references in an expression (does not recurse into subqueries).
1268
- fn find_column_refs_in_expr(expr: &Expression) -> Vec<SimpleColumnRef> {
1298
+ fn find_column_refs_in_expr(
1299
+ expr: &Expression,
1300
+ dialect: Option<DialectType>,
1301
+ ) -> Vec<SimpleColumnRef> {
1269
1302
  let mut refs = Vec::new();
1270
- collect_column_refs(expr, &mut refs);
1303
+ collect_column_refs(expr, dialect, &mut refs);
1271
1304
  refs
1272
1305
  }
1273
1306
 
1274
- fn collect_column_refs(expr: &Expression, refs: &mut Vec<SimpleColumnRef>) {
1307
+ fn is_bigquery_safe_namespace_receiver(expr: &Expression) -> bool {
1308
+ match expr {
1309
+ Expression::Column(col) => {
1310
+ col.table.is_none() && !col.name.quoted && col.name.name.eq_ignore_ascii_case("SAFE")
1311
+ }
1312
+ Expression::Identifier(id) => !id.quoted && id.name.eq_ignore_ascii_case("SAFE"),
1313
+ _ => false,
1314
+ }
1315
+ }
1316
+
1317
+ fn collect_column_refs(
1318
+ expr: &Expression,
1319
+ dialect: Option<DialectType>,
1320
+ refs: &mut Vec<SimpleColumnRef>,
1321
+ ) {
1275
1322
  let mut stack: Vec<&Expression> = vec![expr];
1276
1323
 
1277
1324
  while let Some(current) = stack.pop() {
@@ -1638,7 +1685,11 @@ fn collect_column_refs(expr: &Expression, refs: &mut Vec<SimpleColumnRef>) {
1638
1685
  stack.push(&d.this);
1639
1686
  }
1640
1687
  Expression::MethodCall(m) => {
1641
- stack.push(&m.this);
1688
+ if !matches!(dialect, Some(DialectType::BigQuery))
1689
+ || !is_bigquery_safe_namespace_receiver(&m.this)
1690
+ {
1691
+ stack.push(&m.this);
1692
+ }
1642
1693
  for arg in &m.args {
1643
1694
  stack.push(arg);
1644
1695
  }
@@ -2465,6 +2516,45 @@ mod tests {
2465
2516
  assert_eq!(node.name, "name");
2466
2517
  }
2467
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
+
2468
2558
  #[test]
2469
2559
  fn test_lineage_with_schema_snowflake_datediff_date_part_issue_61() {
2470
2560
  let expr = parse_one(
@@ -2989,6 +3079,71 @@ mod tests {
2989
3079
  );
2990
3080
  }
2991
3081
 
3082
+ #[test]
3083
+ fn test_lineage_bigquery_safe_namespace_issue207() {
3084
+ let query = r#"
3085
+ WITH import_cte AS (
3086
+ SELECT timestamp, data, operation
3087
+ FROM `project`.`dataset`.`source_table`
3088
+ ),
3089
+ transform_cte AS (
3090
+ SELECT
3091
+ timestamp,
3092
+ SAFE.PARSE_JSON(data) AS json_data
3093
+ FROM import_cte
3094
+ )
3095
+ SELECT json_data FROM transform_cte
3096
+ "#;
3097
+ let expr = parse_one(query, DialectType::BigQuery).expect("parse");
3098
+ let node = lineage("json_data", &expr, Some(DialectType::BigQuery), false)
3099
+ .expect("lineage should resolve SAFE.PARSE_JSON arguments");
3100
+ let names: Vec<_> = node.walk().map(|n| n.name.clone()).collect();
3101
+
3102
+ assert!(
3103
+ names.iter().any(|name| name == "source_table.data"),
3104
+ "expected source_table.data in lineage, got {names:?}"
3105
+ );
3106
+ assert!(
3107
+ !names
3108
+ .iter()
3109
+ .any(|name| name.eq_ignore_ascii_case("import_cte.safe")),
3110
+ "did not expect SAFE namespace receiver in lineage, got {names:?}"
3111
+ );
3112
+ }
3113
+
3114
+ #[test]
3115
+ fn test_lineage_bigquery_safe_namespace_method_call_guard() {
3116
+ let expr = parse("SELECT SAFE.PARSE_JSON(data) AS json_data FROM t");
3117
+ let node = lineage("json_data", &expr, Some(DialectType::BigQuery), false)
3118
+ .expect("lineage should resolve SAFE.PARSE_JSON arguments");
3119
+ let names: Vec<_> = node.walk().map(|n| n.name.clone()).collect();
3120
+
3121
+ assert!(
3122
+ names.iter().any(|name| name == "t.data"),
3123
+ "expected t.data in lineage, got {names:?}"
3124
+ );
3125
+ assert!(
3126
+ !names.iter().any(|name| name.eq_ignore_ascii_case("t.safe")),
3127
+ "did not expect SAFE namespace receiver in lineage, got {names:?}"
3128
+ );
3129
+ }
3130
+
3131
+ #[test]
3132
+ fn test_lineage_method_call_receiver_control() {
3133
+ let expr = parse("SELECT obj.METHOD(arg) AS out FROM t");
3134
+ let node = lineage("out", &expr, None, false).expect("lineage");
3135
+ let names: Vec<_> = node.walk().map(|n| n.name.clone()).collect();
3136
+
3137
+ assert!(
3138
+ names.iter().any(|name| name == "t.obj"),
3139
+ "expected ordinary method receiver to remain in lineage, got {names:?}"
3140
+ );
3141
+ assert!(
3142
+ names.iter().any(|name| name == "t.arg"),
3143
+ "expected method argument in lineage, got {names:?}"
3144
+ );
3145
+ }
3146
+
2992
3147
  #[test]
2993
3148
  fn test_lineage_upper_function() {
2994
3149
  let expr = parse("SELECT UPPER(name) AS upper_name FROM users");
@@ -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())
@@ -1126,6 +1141,78 @@ mod tests {
1126
1141
  .all(|f| f.transformations[0].subtype == "TRANSFORMATION"));
1127
1142
  }
1128
1143
 
1144
+ #[test]
1145
+ fn omits_bigquery_safe_namespace_from_column_lineage_issue207() {
1146
+ let mut opts = options();
1147
+ opts.dialect = DialectType::BigQuery;
1148
+
1149
+ let result = openlineage_column_lineage(
1150
+ r#"
1151
+ WITH import_cte AS (
1152
+ SELECT timestamp, data, operation
1153
+ FROM `project`.`dataset`.`source_table`
1154
+ ),
1155
+ transform_cte AS (
1156
+ SELECT
1157
+ timestamp,
1158
+ SAFE.PARSE_JSON(data) AS json_data
1159
+ FROM import_cte
1160
+ )
1161
+ SELECT json_data FROM transform_cte
1162
+ "#,
1163
+ &opts,
1164
+ )
1165
+ .expect("lineage");
1166
+ let field = result.facet.fields.get("json_data").expect("json_data");
1167
+
1168
+ assert!(
1169
+ field.input_fields.iter().any(|input| input.field == "data"),
1170
+ "expected data input field, got {:?}",
1171
+ field.input_fields
1172
+ );
1173
+ assert!(
1174
+ !field
1175
+ .input_fields
1176
+ .iter()
1177
+ .any(|input| input.field.eq_ignore_ascii_case("safe")),
1178
+ "did not expect SAFE namespace as input field, got {:?}",
1179
+ field.input_fields
1180
+ );
1181
+ }
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
+
1129
1216
  #[test]
1130
1217
  fn emits_aggregation_column_lineage() {
1131
1218
  let result =