polyglot-sql 0.3.7__tar.gz → 0.3.9__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 (170) hide show
  1. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/Cargo.lock +5 -5
  2. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/Cargo.toml +1 -1
  3. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/PKG-INFO +1 -1
  4. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/Cargo.toml +1 -1
  5. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/dialects/mod.rs +193 -3
  6. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/expressions.rs +15 -0
  7. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/generator.rs +54 -1
  8. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/lineage.rs +10 -0
  9. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/parser.rs +88 -66
  10. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/scope.rs +10 -0
  11. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/traversal.rs +6 -0
  12. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/tests/fabric_regression.rs +36 -0
  13. polyglot_sql-0.3.9/crates/polyglot-sql/tests/fabric_tpch_regression.rs +580 -0
  14. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/tests/transform_regression.rs +130 -2
  15. polyglot_sql-0.3.9/crates/polyglot-sql/tests/tsql_regression.rs +199 -0
  16. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql-python/src/expr_types.rs +1 -0
  17. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql-python/tests/test_parse.py +19 -0
  18. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/python/polyglot_sql/__init__.py +2 -0
  19. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/python/polyglot_sql/__init__.pyi +11 -10
  20. polyglot_sql-0.3.7/crates/polyglot-sql/tests/tsql_regression.rs +0 -85
  21. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/README.md +0 -0
  22. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/README.md +0 -0
  23. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/benches/in_list.rs +0 -0
  24. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/benches/parsing.rs +0 -0
  25. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/benches/rust_parsing.rs +0 -0
  26. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/benches/transpile.rs +0 -0
  27. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/examples/basic_usage.rs +0 -0
  28. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/examples/bench_json.rs +0 -0
  29. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/ast_transforms.rs +0 -0
  30. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/builder.rs +0 -0
  31. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/dialects/athena.rs +0 -0
  32. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/dialects/bigquery.rs +0 -0
  33. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/dialects/clickhouse.rs +0 -0
  34. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/dialects/cockroachdb.rs +0 -0
  35. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/dialects/databricks.rs +0 -0
  36. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/dialects/datafusion.rs +0 -0
  37. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/dialects/doris.rs +0 -0
  38. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/dialects/dremio.rs +0 -0
  39. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/dialects/drill.rs +0 -0
  40. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/dialects/druid.rs +0 -0
  41. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/dialects/duckdb.rs +0 -0
  42. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/dialects/dune.rs +0 -0
  43. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/dialects/exasol.rs +0 -0
  44. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/dialects/fabric.rs +0 -0
  45. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/dialects/generic.rs +0 -0
  46. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/dialects/hive.rs +0 -0
  47. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/dialects/materialize.rs +0 -0
  48. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/dialects/mysql.rs +0 -0
  49. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/dialects/oracle.rs +0 -0
  50. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/dialects/postgres.rs +0 -0
  51. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/dialects/presto.rs +0 -0
  52. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/dialects/redshift.rs +0 -0
  53. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/dialects/risingwave.rs +0 -0
  54. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/dialects/singlestore.rs +0 -0
  55. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/dialects/snowflake.rs +0 -0
  56. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/dialects/solr.rs +0 -0
  57. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/dialects/spark.rs +0 -0
  58. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/dialects/sqlite.rs +0 -0
  59. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/dialects/starrocks.rs +0 -0
  60. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/dialects/tableau.rs +0 -0
  61. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/dialects/teradata.rs +0 -0
  62. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/dialects/tidb.rs +0 -0
  63. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/dialects/trino.rs +0 -0
  64. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/dialects/tsql.rs +0 -0
  65. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/diff.rs +0 -0
  66. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/error.rs +0 -0
  67. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/function_catalog.rs +0 -0
  68. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/function_registry.rs +0 -0
  69. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/helper.rs +0 -0
  70. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/lib.rs +0 -0
  71. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/optimizer/annotate_types.rs +0 -0
  72. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/optimizer/canonicalize.rs +0 -0
  73. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/optimizer/eliminate_ctes.rs +0 -0
  74. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/optimizer/eliminate_joins.rs +0 -0
  75. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/optimizer/isolate_table_selects.rs +0 -0
  76. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/optimizer/mod.rs +0 -0
  77. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/optimizer/normalize.rs +0 -0
  78. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/optimizer/normalize_identifiers.rs +0 -0
  79. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/optimizer/optimize_joins.rs +0 -0
  80. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/optimizer/optimizer.rs +0 -0
  81. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/optimizer/pushdown_predicates.rs +0 -0
  82. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/optimizer/pushdown_projections.rs +0 -0
  83. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/optimizer/qualify_columns.rs +0 -0
  84. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/optimizer/qualify_tables.rs +0 -0
  85. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/optimizer/simplify.rs +0 -0
  86. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/optimizer/subquery.rs +0 -0
  87. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/planner.rs +0 -0
  88. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/resolver.rs +0 -0
  89. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/schema.rs +0 -0
  90. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/time.rs +0 -0
  91. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/tokens.rs +0 -0
  92. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/transforms.rs +0 -0
  93. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/trie.rs +0 -0
  94. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/validation/tests.rs +0 -0
  95. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/src/validation.rs +0 -0
  96. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/tests/analyze_failures.rs +0 -0
  97. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/tests/clickhouse_regression.rs +0 -0
  98. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/tests/common/known_failures.rs +0 -0
  99. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/tests/common/mod.rs +0 -0
  100. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/tests/common/test_data.rs +0 -0
  101. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/tests/common/test_runner.rs +0 -0
  102. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/tests/custom_clickhouse_coverage.rs +0 -0
  103. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/tests/custom_clickhouse_parser.rs +0 -0
  104. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/tests/custom_dialect.rs +0 -0
  105. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/tests/custom_dialect_tests.rs +0 -0
  106. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/tests/custom_fixtures/datafusion/ddl.json +0 -0
  107. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/tests/custom_fixtures/datafusion/dml.json +0 -0
  108. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/tests/custom_fixtures/datafusion/functions.json +0 -0
  109. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/tests/custom_fixtures/datafusion/identity.json +0 -0
  110. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/tests/custom_fixtures/datafusion/operators.json +0 -0
  111. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/tests/custom_fixtures/datafusion/select.json +0 -0
  112. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/tests/custom_fixtures/datafusion/transpilation.json +0 -0
  113. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/tests/custom_fixtures/datafusion/types.json +0 -0
  114. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/tests/deep_nesting_regression.rs +0 -0
  115. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/tests/dialect_matrix.rs +0 -0
  116. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/tests/error_handling.rs +0 -0
  117. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/tests/identity_roundtrip.rs +0 -0
  118. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/tests/postgres_sqlite_regression.rs +0 -0
  119. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/tests/snowflake_regression_test.rs +0 -0
  120. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/tests/sqlglot_compat.rs +0 -0
  121. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/tests/sqlglot_dialect_identity.rs +0 -0
  122. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/tests/sqlglot_identity.rs +0 -0
  123. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/tests/sqlglot_identity_detailed.rs +0 -0
  124. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/tests/sqlglot_parser.rs +0 -0
  125. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/tests/sqlglot_pretty.rs +0 -0
  126. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/tests/sqlglot_transpilation.rs +0 -0
  127. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/tests/sqlglot_transpile.rs +0 -0
  128. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql/tests/tpch_transpile_stack.rs +0 -0
  129. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql-function-catalogs/Cargo.toml +0 -0
  130. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql-function-catalogs/README.md +0 -0
  131. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql-function-catalogs/src/clickhouse.rs +0 -0
  132. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql-function-catalogs/src/duckdb.rs +0 -0
  133. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql-function-catalogs/src/lib.rs +0 -0
  134. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql-function-catalogs/tools/clickhouse/extract_functions.py +0 -0
  135. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql-function-catalogs/tools/duckdb/extract_functions.py +0 -0
  136. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql-python/Cargo.toml +0 -0
  137. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql-python/README.md +0 -0
  138. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql-python/docs/api.md +0 -0
  139. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql-python/docs/index.md +0 -0
  140. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql-python/mkdocs.yml +0 -0
  141. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql-python/src/annotate_types.rs +0 -0
  142. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql-python/src/dialects.rs +0 -0
  143. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql-python/src/diff.rs +0 -0
  144. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql-python/src/errors.rs +0 -0
  145. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql-python/src/expr.rs +0 -0
  146. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql-python/src/format.rs +0 -0
  147. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql-python/src/generate.rs +0 -0
  148. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql-python/src/helpers.rs +0 -0
  149. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql-python/src/lib.rs +0 -0
  150. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql-python/src/lineage.rs +0 -0
  151. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql-python/src/optimize.rs +0 -0
  152. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql-python/src/parse.rs +0 -0
  153. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql-python/src/tokenize.rs +0 -0
  154. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql-python/src/transpile.rs +0 -0
  155. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql-python/src/types.rs +0 -0
  156. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql-python/src/validate.rs +0 -0
  157. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql-python/tests/conftest.py +0 -0
  158. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql-python/tests/test_compat.py +0 -0
  159. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql-python/tests/test_dialects.py +0 -0
  160. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql-python/tests/test_diff.py +0 -0
  161. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql-python/tests/test_expression.py +0 -0
  162. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql-python/tests/test_format.py +0 -0
  163. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql-python/tests/test_generate.py +0 -0
  164. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql-python/tests/test_lineage.py +0 -0
  165. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql-python/tests/test_optimize.py +0 -0
  166. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql-python/tests/test_transpile.py +0 -0
  167. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql-python/tests/test_validate.py +0 -0
  168. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/crates/polyglot-sql-python/uv.lock +0 -0
  169. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/pyproject.toml +0 -0
  170. {polyglot_sql-0.3.7 → polyglot_sql-0.3.9}/python/polyglot_sql/py.typed +0 -0
@@ -605,7 +605,7 @@ dependencies = [
605
605
 
606
606
  [[package]]
607
607
  name = "polyglot-sql"
608
- version = "0.3.7"
608
+ version = "0.3.9"
609
609
  dependencies = [
610
610
  "criterion",
611
611
  "once_cell",
@@ -621,7 +621,7 @@ dependencies = [
621
621
 
622
622
  [[package]]
623
623
  name = "polyglot-sql-ffi"
624
- version = "0.3.7"
624
+ version = "0.3.9"
625
625
  dependencies = [
626
626
  "cbindgen",
627
627
  "polyglot-sql",
@@ -631,11 +631,11 @@ dependencies = [
631
631
 
632
632
  [[package]]
633
633
  name = "polyglot-sql-function-catalogs"
634
- version = "0.3.7"
634
+ version = "0.3.9"
635
635
 
636
636
  [[package]]
637
637
  name = "polyglot-sql-python"
638
- version = "0.3.7"
638
+ version = "0.3.9"
639
639
  dependencies = [
640
640
  "polyglot-sql",
641
641
  "pyo3",
@@ -646,7 +646,7 @@ dependencies = [
646
646
 
647
647
  [[package]]
648
648
  name = "polyglot-sql-wasm"
649
- version = "0.3.7"
649
+ version = "0.3.9"
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.3.7"
9
+ version = "0.3.9"
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.3.7
3
+ Version: 0.3.9
4
4
  Classifier: Development Status :: 4 - Beta
5
5
  Classifier: Intended Audience :: Developers
6
6
  Classifier: License :: OSI Approved :: MIT License
@@ -83,7 +83,7 @@ thiserror = { workspace = true }
83
83
  unicode-segmentation = { workspace = true }
84
84
  stacker = { version = "0.1", optional = true }
85
85
  ts-rs = { version = "12.0", features = ["serde-compat"], optional = true }
86
- polyglot-sql-function-catalogs = { path = "../polyglot-sql-function-catalogs", version = "0.3.7", optional = true, default-features = false }
86
+ polyglot-sql-function-catalogs = { path = "../polyglot-sql-function-catalogs", version = "0.3.9", optional = true, default-features = false }
87
87
 
88
88
  [dev-dependencies]
89
89
  pretty_assertions = "1.4"
@@ -158,7 +158,10 @@ pub use trino::TrinoDialect;
158
158
  pub use tsql::TSQLDialect;
159
159
 
160
160
  use crate::error::Result;
161
- use crate::expressions::{Expression, Function, FunctionBody, Identifier, Null};
161
+ use crate::expressions::{
162
+ Expression, From, Function, FunctionBody, Identifier, Join, Null, OrderBy, OutputClause,
163
+ TableRef, With,
164
+ };
162
165
  use crate::generator::{Generator, GeneratorConfig};
163
166
  use crate::parser::Parser;
164
167
  use crate::tokens::{Token, TokenType, Tokenizer, TokenizerConfig};
@@ -1661,6 +1664,122 @@ where
1661
1664
  }
1662
1665
  }
1663
1666
 
1667
+ fn transform_table_ref_recursive<F>(table: TableRef, transform_fn: &F) -> Result<TableRef>
1668
+ where
1669
+ F: Fn(Expression) -> Result<Expression>,
1670
+ {
1671
+ match transform_recursive(Expression::Table(Box::new(table)), transform_fn)? {
1672
+ Expression::Table(table) => Ok(*table),
1673
+ _ => Err(crate::error::Error::parse(
1674
+ "TableRef transformation returned non-table expression",
1675
+ 0,
1676
+ 0,
1677
+ 0,
1678
+ 0,
1679
+ )),
1680
+ }
1681
+ }
1682
+
1683
+ fn transform_from_recursive<F>(from: From, transform_fn: &F) -> Result<From>
1684
+ where
1685
+ F: Fn(Expression) -> Result<Expression>,
1686
+ {
1687
+ match transform_recursive(Expression::From(Box::new(from)), transform_fn)? {
1688
+ Expression::From(from) => Ok(*from),
1689
+ _ => Err(crate::error::Error::parse(
1690
+ "FROM transformation returned non-FROM expression",
1691
+ 0,
1692
+ 0,
1693
+ 0,
1694
+ 0,
1695
+ )),
1696
+ }
1697
+ }
1698
+
1699
+ fn transform_join_recursive<F>(mut join: Join, transform_fn: &F) -> Result<Join>
1700
+ where
1701
+ F: Fn(Expression) -> Result<Expression>,
1702
+ {
1703
+ join.this = transform_recursive(join.this, transform_fn)?;
1704
+ if let Some(on) = join.on.take() {
1705
+ join.on = Some(transform_recursive(on, transform_fn)?);
1706
+ }
1707
+ if let Some(match_condition) = join.match_condition.take() {
1708
+ join.match_condition = Some(transform_recursive(match_condition, transform_fn)?);
1709
+ }
1710
+ join.pivots = join
1711
+ .pivots
1712
+ .into_iter()
1713
+ .map(|pivot| transform_recursive(pivot, transform_fn))
1714
+ .collect::<Result<Vec<_>>>()?;
1715
+
1716
+ match transform_fn(Expression::Join(Box::new(join)))? {
1717
+ Expression::Join(join) => Ok(*join),
1718
+ _ => Err(crate::error::Error::parse(
1719
+ "Join transformation returned non-join expression",
1720
+ 0,
1721
+ 0,
1722
+ 0,
1723
+ 0,
1724
+ )),
1725
+ }
1726
+ }
1727
+
1728
+ fn transform_output_clause_recursive<F>(
1729
+ mut output: OutputClause,
1730
+ transform_fn: &F,
1731
+ ) -> Result<OutputClause>
1732
+ where
1733
+ F: Fn(Expression) -> Result<Expression>,
1734
+ {
1735
+ output.columns = output
1736
+ .columns
1737
+ .into_iter()
1738
+ .map(|column| transform_recursive(column, transform_fn))
1739
+ .collect::<Result<Vec<_>>>()?;
1740
+ if let Some(into_table) = output.into_table.take() {
1741
+ output.into_table = Some(transform_recursive(into_table, transform_fn)?);
1742
+ }
1743
+ Ok(output)
1744
+ }
1745
+
1746
+ fn transform_with_recursive<F>(mut with: With, transform_fn: &F) -> Result<With>
1747
+ where
1748
+ F: Fn(Expression) -> Result<Expression>,
1749
+ {
1750
+ with.ctes = with
1751
+ .ctes
1752
+ .into_iter()
1753
+ .map(|mut cte| {
1754
+ cte.this = transform_recursive(cte.this, transform_fn)?;
1755
+ Ok(cte)
1756
+ })
1757
+ .collect::<Result<Vec<_>>>()?;
1758
+ if let Some(search) = with.search.take() {
1759
+ with.search = Some(Box::new(transform_recursive(*search, transform_fn)?));
1760
+ }
1761
+ Ok(with)
1762
+ }
1763
+
1764
+ fn transform_order_by_recursive<F>(mut order: OrderBy, transform_fn: &F) -> Result<OrderBy>
1765
+ where
1766
+ F: Fn(Expression) -> Result<Expression>,
1767
+ {
1768
+ order.expressions = order
1769
+ .expressions
1770
+ .into_iter()
1771
+ .map(|mut ordered| {
1772
+ let original = ordered.this.clone();
1773
+ ordered.this = transform_recursive(ordered.this, transform_fn).unwrap_or(original);
1774
+ match transform_fn(Expression::Ordered(Box::new(ordered.clone()))) {
1775
+ Ok(Expression::Ordered(transformed)) => Ok(*transformed),
1776
+ Ok(_) | Err(_) => Ok(ordered),
1777
+ }
1778
+ })
1779
+ .collect::<Result<Vec<_>>>()?;
1780
+ Ok(order)
1781
+ }
1782
+
1664
1783
  fn transform_recursive_reference<F>(expr: Expression, transform_fn: &F) -> Result<Expression>
1665
1784
  where
1666
1785
  F: Fn(Expression) -> Result<Expression>,
@@ -2377,6 +2496,17 @@ where
2377
2496
  Expression::Insert(ins)
2378
2497
  }
2379
2498
  Expression::Update(mut upd) => {
2499
+ upd.table = transform_table_ref_recursive(upd.table, transform_fn)?;
2500
+ upd.extra_tables = upd
2501
+ .extra_tables
2502
+ .into_iter()
2503
+ .map(|table| transform_table_ref_recursive(table, transform_fn))
2504
+ .collect::<Result<Vec<_>>>()?;
2505
+ upd.table_joins = upd
2506
+ .table_joins
2507
+ .into_iter()
2508
+ .map(|join| transform_join_recursive(join, transform_fn))
2509
+ .collect::<Result<Vec<_>>>()?;
2380
2510
  upd.set = upd
2381
2511
  .set
2382
2512
  .into_iter()
@@ -2385,17 +2515,75 @@ where
2385
2515
  (id, new_val)
2386
2516
  })
2387
2517
  .collect();
2518
+ if let Some(from_clause) = upd.from_clause.take() {
2519
+ upd.from_clause = Some(transform_from_recursive(from_clause, transform_fn)?);
2520
+ }
2521
+ upd.from_joins = upd
2522
+ .from_joins
2523
+ .into_iter()
2524
+ .map(|join| transform_join_recursive(join, transform_fn))
2525
+ .collect::<Result<Vec<_>>>()?;
2388
2526
  if let Some(mut where_clause) = upd.where_clause.take() {
2389
2527
  where_clause.this = transform_recursive(where_clause.this, transform_fn)?;
2390
2528
  upd.where_clause = Some(where_clause);
2391
2529
  }
2530
+ upd.returning = upd
2531
+ .returning
2532
+ .into_iter()
2533
+ .map(|expr| transform_recursive(expr, transform_fn))
2534
+ .collect::<Result<Vec<_>>>()?;
2535
+ if let Some(output) = upd.output.take() {
2536
+ upd.output = Some(transform_output_clause_recursive(output, transform_fn)?);
2537
+ }
2538
+ if let Some(with) = upd.with.take() {
2539
+ upd.with = Some(transform_with_recursive(with, transform_fn)?);
2540
+ }
2541
+ if let Some(limit) = upd.limit.take() {
2542
+ upd.limit = Some(transform_recursive(limit, transform_fn)?);
2543
+ }
2544
+ if let Some(order_by) = upd.order_by.take() {
2545
+ upd.order_by = Some(transform_order_by_recursive(order_by, transform_fn)?);
2546
+ }
2392
2547
  Expression::Update(upd)
2393
2548
  }
2394
2549
  Expression::Delete(mut del) => {
2550
+ del.table = transform_table_ref_recursive(del.table, transform_fn)?;
2551
+ del.using = del
2552
+ .using
2553
+ .into_iter()
2554
+ .map(|table| transform_table_ref_recursive(table, transform_fn))
2555
+ .collect::<Result<Vec<_>>>()?;
2395
2556
  if let Some(mut where_clause) = del.where_clause.take() {
2396
2557
  where_clause.this = transform_recursive(where_clause.this, transform_fn)?;
2397
2558
  del.where_clause = Some(where_clause);
2398
2559
  }
2560
+ if let Some(output) = del.output.take() {
2561
+ del.output = Some(transform_output_clause_recursive(output, transform_fn)?);
2562
+ }
2563
+ if let Some(with) = del.with.take() {
2564
+ del.with = Some(transform_with_recursive(with, transform_fn)?);
2565
+ }
2566
+ if let Some(limit) = del.limit.take() {
2567
+ del.limit = Some(transform_recursive(limit, transform_fn)?);
2568
+ }
2569
+ if let Some(order_by) = del.order_by.take() {
2570
+ del.order_by = Some(transform_order_by_recursive(order_by, transform_fn)?);
2571
+ }
2572
+ del.returning = del
2573
+ .returning
2574
+ .into_iter()
2575
+ .map(|expr| transform_recursive(expr, transform_fn))
2576
+ .collect::<Result<Vec<_>>>()?;
2577
+ del.tables = del
2578
+ .tables
2579
+ .into_iter()
2580
+ .map(|table| transform_table_ref_recursive(table, transform_fn))
2581
+ .collect::<Result<Vec<_>>>()?;
2582
+ del.joins = del
2583
+ .joins
2584
+ .into_iter()
2585
+ .map(|join| transform_join_recursive(join, transform_fn))
2586
+ .collect::<Result<Vec<_>>>()?;
2399
2587
  Expression::Delete(del)
2400
2588
  }
2401
2589
 
@@ -32060,7 +32248,7 @@ impl Dialect {
32060
32248
  match unit.trim().to_ascii_uppercase().as_str() {
32061
32249
  "YEAR" | "YEARS" => Some(IntervalUnit::Year),
32062
32250
  "QUARTER" | "QUARTERS" => Some(IntervalUnit::Quarter),
32063
- "MONTH" | "MONTHS" => Some(IntervalUnit::Month),
32251
+ "MONTH" | "MONTHS" | "MON" | "MONS" | "MM" => Some(IntervalUnit::Month),
32064
32252
  "WEEK" | "WEEKS" | "ISOWEEK" => Some(IntervalUnit::Week),
32065
32253
  "DAY" | "DAYS" => Some(IntervalUnit::Day),
32066
32254
  "HOUR" | "HOURS" => Some(IntervalUnit::Hour),
@@ -36732,7 +36920,9 @@ impl Dialect {
36732
36920
  match s {
36733
36921
  "YEAR" | "YY" | "YYYY" => crate::expressions::IntervalUnit::Year,
36734
36922
  "QUARTER" | "QQ" | "Q" => crate::expressions::IntervalUnit::Quarter,
36735
- "MONTH" | "MM" | "M" => crate::expressions::IntervalUnit::Month,
36923
+ "MONTH" | "MONTHS" | "MON" | "MONS" | "MM" | "M" => {
36924
+ crate::expressions::IntervalUnit::Month
36925
+ }
36736
36926
  "WEEK" | "WK" | "WW" | "ISOWEEK" => crate::expressions::IntervalUnit::Week,
36737
36927
  "DAY" | "DD" | "D" | "DY" => crate::expressions::IntervalUnit::Day,
36738
36928
  "HOUR" | "HH" => crate::expressions::IntervalUnit::Hour,
@@ -114,6 +114,7 @@ pub enum Expression {
114
114
  Copy(Box<CopyStmt>),
115
115
  Put(Box<PutStmt>),
116
116
  StageReference(Box<StageReference>),
117
+ TryCatch(Box<TryCatch>),
117
118
 
118
119
  // Expressions
119
120
  Alias(Box<Alias>),
@@ -1146,6 +1147,7 @@ impl Expression {
1146
1147
  | Expression::Copy(_)
1147
1148
  | Expression::Put(_)
1148
1149
  | Expression::Merge(_)
1150
+ | Expression::TryCatch(_)
1149
1151
 
1150
1152
  // DDL
1151
1153
  | Expression::CreateTable(_)
@@ -2229,6 +2231,7 @@ impl Expression {
2229
2231
  Expression::Describe(_) => "describe",
2230
2232
  Expression::Show(_) => "show",
2231
2233
  Expression::Command(_) => "command",
2234
+ Expression::TryCatch(_) => "try_catch",
2232
2235
  Expression::Kill(_) => "kill",
2233
2236
  Expression::Execute(_) => "execute",
2234
2237
  Expression::Raw(_) => "raw",
@@ -6003,6 +6006,18 @@ pub struct Command {
6003
6006
  pub this: String,
6004
6007
  }
6005
6008
 
6009
+ /// T-SQL TRY/CATCH block.
6010
+ #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
6011
+ #[cfg_attr(feature = "bindings", derive(TS))]
6012
+ pub struct TryCatch {
6013
+ /// Statements inside BEGIN TRY ... END TRY.
6014
+ #[serde(default)]
6015
+ pub try_body: Vec<Expression>,
6016
+ /// Statements inside BEGIN CATCH ... END CATCH, when present.
6017
+ #[serde(default, skip_serializing_if = "Option::is_none")]
6018
+ pub catch_body: Option<Vec<Expression>>,
6019
+ }
6020
+
6006
6021
  /// EXEC/EXECUTE statement (TSQL stored procedure call)
6007
6022
  /// Syntax: EXEC [schema.]procedure_name [@param=value, ...]
6008
6023
  #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
@@ -3342,6 +3342,7 @@ impl Generator {
3342
3342
  Ok(())
3343
3343
  }
3344
3344
  Expression::CreateTask(task) => self.generate_create_task(task),
3345
+ Expression::TryCatch(try_catch) => self.generate_try_catch(try_catch),
3345
3346
  Expression::Command(cmd) => {
3346
3347
  self.write(&cmd.this);
3347
3348
  Ok(())
@@ -14109,6 +14110,58 @@ impl Generator {
14109
14110
  Ok(())
14110
14111
  }
14111
14112
 
14113
+ fn generate_try_catch(&mut self, try_catch: &TryCatch) -> Result<()> {
14114
+ self.write_keyword("BEGIN TRY");
14115
+ self.generate_tsql_block_statements(&try_catch.try_body)?;
14116
+ self.write_keyword("END TRY");
14117
+
14118
+ if let Some(catch_body) = &try_catch.catch_body {
14119
+ if self.config.pretty {
14120
+ self.write_newline();
14121
+ self.write_indent();
14122
+ } else {
14123
+ self.write_space();
14124
+ }
14125
+ self.write_keyword("BEGIN CATCH");
14126
+ self.generate_tsql_block_statements(catch_body)?;
14127
+ self.write_keyword("END CATCH");
14128
+ }
14129
+
14130
+ Ok(())
14131
+ }
14132
+
14133
+ fn generate_tsql_block_statements(&mut self, statements: &[Expression]) -> Result<()> {
14134
+ if statements.is_empty() {
14135
+ self.write_space();
14136
+ return Ok(());
14137
+ }
14138
+
14139
+ if self.config.pretty {
14140
+ self.indent_level += 1;
14141
+ for stmt in statements {
14142
+ self.write_newline();
14143
+ self.write_indent();
14144
+ self.generate_expression(stmt)?;
14145
+ self.write(";");
14146
+ }
14147
+ self.indent_level -= 1;
14148
+ self.write_newline();
14149
+ self.write_indent();
14150
+ } else {
14151
+ self.write_space();
14152
+ for (i, stmt) in statements.iter().enumerate() {
14153
+ if i > 0 {
14154
+ self.write_space();
14155
+ }
14156
+ self.generate_expression(stmt)?;
14157
+ self.write(";");
14158
+ }
14159
+ self.write_space();
14160
+ }
14161
+
14162
+ Ok(())
14163
+ }
14164
+
14112
14165
  fn generate_drop_type(&mut self, dt: &DropType) -> Result<()> {
14113
14166
  self.write_keyword("DROP TYPE");
14114
14167
 
@@ -18528,7 +18581,7 @@ impl Generator {
18528
18581
  };
18529
18582
  match lower {
18530
18583
  "day" | "days" | "d" => "DAY".to_string(),
18531
- "month" | "months" | "mon" | "mm" => "MONTH".to_string(),
18584
+ "month" | "months" | "mon" | "mons" | "mm" => "MONTH".to_string(),
18532
18585
  "year" | "years" | "y" | "yy" | "yyyy" => "YEAR".to_string(),
18533
18586
  "week" | "weeks" | "w" | "wk" => "WEEK".to_string(),
18534
18587
  "hour" | "hours" | "h" | "hh" => "HOUR".to_string(),
@@ -1658,6 +1658,16 @@ fn collect_column_refs(expr: &Expression, refs: &mut Vec<SimpleColumnRef>) {
1658
1658
  Expression::NamedArgument(n) => {
1659
1659
  stack.push(&n.value);
1660
1660
  }
1661
+ Expression::TryCatch(t) => {
1662
+ for stmt in &t.try_body {
1663
+ stack.push(stmt);
1664
+ }
1665
+ if let Some(catch_body) = &t.catch_body {
1666
+ for stmt in catch_body {
1667
+ stack.push(stmt);
1668
+ }
1669
+ }
1670
+ }
1661
1671
  Expression::BracedWildcard(e) | Expression::ReturnStmt(e) => {
1662
1672
  stack.push(e);
1663
1673
  }
@@ -21032,66 +21032,17 @@ impl Parser {
21032
21032
 
21033
21033
  if !is_transaction {
21034
21034
  // TSQL: BEGIN TRY ... END TRY [BEGIN CATCH ... END CATCH]
21035
- // These are block-structured constructs that may contain semicolons,
21036
- // so we can't use parse_command() which stops at the first semicolon.
21037
- let is_try = self.check_identifier("TRY");
21038
- let is_catch = self.check_identifier("CATCH");
21039
- if is_try || is_catch {
21040
- let block_kind = if is_try { "TRY" } else { "CATCH" };
21041
- self.skip(); // consume TRY or CATCH
21042
- let mut tokens: Vec<(String, TokenType)> = vec![
21043
- ("BEGIN".to_string(), TokenType::Begin),
21044
- (block_kind.to_string(), TokenType::Var),
21045
- ];
21046
- // Collect tokens until matching END TRY / END CATCH
21047
- while !self.is_at_end() {
21048
- if self.check(TokenType::End)
21049
- && self.current + 1 < self.tokens.len()
21050
- && self.tokens[self.current + 1]
21051
- .text
21052
- .eq_ignore_ascii_case(block_kind)
21053
- {
21054
- tokens.push(("END".to_string(), TokenType::End));
21055
- self.skip(); // consume END
21056
- tokens.push((block_kind.to_string(), TokenType::Var));
21057
- self.skip(); // consume TRY/CATCH
21058
- break;
21059
- }
21060
- let token = self.advance();
21061
- let text = if token.token_type == TokenType::String {
21062
- format!("'{}'", token.text)
21063
- } else if token.token_type == TokenType::QuotedIdentifier {
21064
- format!("\"{}\"", token.text)
21065
- } else {
21066
- token.text.clone()
21067
- };
21068
- tokens.push((text, token.token_type));
21069
- }
21070
- let mut result = Expression::Command(Box::new(Command {
21071
- this: self.join_command_tokens(tokens),
21072
- }));
21073
-
21074
- // If this was a TRY block, check for a following BEGIN CATCH block
21075
- if is_try
21076
- && self.check(TokenType::Begin)
21077
- && self.current + 1 < self.tokens.len()
21078
- && self.tokens[self.current + 1]
21079
- .text
21080
- .eq_ignore_ascii_case("CATCH")
21081
- {
21082
- // Recursively parse the BEGIN CATCH block
21083
- let catch_block = self.parse_transaction()?;
21084
- // Combine TRY and CATCH into a single command
21085
- if let (Expression::Command(try_cmd), Expression::Command(catch_cmd)) =
21086
- (&result, &catch_block)
21087
- {
21088
- result = Expression::Command(Box::new(Command {
21089
- this: format!("{} {}", try_cmd.this, catch_cmd.this),
21090
- }));
21091
- }
21092
- }
21093
-
21094
- return Ok(result);
21035
+ // Parse bodies into statement nodes so traversal can see table refs.
21036
+ if self.check_identifier("TRY") {
21037
+ return self.parse_tsql_try_catch();
21038
+ }
21039
+ if self.check_identifier("CATCH") {
21040
+ self.skip(); // consume CATCH
21041
+ let catch_body = self.parse_tsql_block_body("CATCH")?;
21042
+ return Ok(Expression::TryCatch(Box::new(TryCatch {
21043
+ try_body: Vec::new(),
21044
+ catch_body: Some(catch_body),
21045
+ })));
21095
21046
  }
21096
21047
 
21097
21048
  // This is a procedural BEGIN block - parse as Command
@@ -21190,6 +21141,79 @@ impl Parser {
21190
21141
  })))
21191
21142
  }
21192
21143
 
21144
+ fn parse_tsql_try_catch(&mut self) -> Result<Expression> {
21145
+ self.skip(); // consume TRY
21146
+ let try_body = self.parse_tsql_block_body("TRY")?;
21147
+ let catch_body = if self.check(TokenType::Begin)
21148
+ && self.current + 1 < self.tokens.len()
21149
+ && self.tokens[self.current + 1]
21150
+ .text
21151
+ .eq_ignore_ascii_case("CATCH")
21152
+ {
21153
+ self.skip(); // consume BEGIN
21154
+ self.skip(); // consume CATCH
21155
+ Some(self.parse_tsql_block_body("CATCH")?)
21156
+ } else {
21157
+ None
21158
+ };
21159
+
21160
+ Ok(Expression::TryCatch(Box::new(TryCatch {
21161
+ try_body,
21162
+ catch_body,
21163
+ })))
21164
+ }
21165
+
21166
+ fn parse_tsql_block_body(&mut self, block_kind: &str) -> Result<Vec<Expression>> {
21167
+ let tokens = self.collect_tsql_block_body_tokens(block_kind)?;
21168
+ if tokens.is_empty() {
21169
+ return Ok(Vec::new());
21170
+ }
21171
+
21172
+ let mut parser = Parser::with_config(tokens, self.config.clone());
21173
+ parser.parse()
21174
+ }
21175
+
21176
+ fn collect_tsql_block_body_tokens(&mut self, block_kind: &str) -> Result<Vec<Token>> {
21177
+ let mut tokens = Vec::new();
21178
+ let mut depth = 1usize;
21179
+
21180
+ while !self.is_at_end() {
21181
+ if self.check(TokenType::Begin)
21182
+ && self.current + 1 < self.tokens.len()
21183
+ && self.tokens[self.current + 1]
21184
+ .text
21185
+ .eq_ignore_ascii_case(block_kind)
21186
+ {
21187
+ depth += 1;
21188
+ tokens.push(self.advance());
21189
+ tokens.push(self.advance());
21190
+ continue;
21191
+ }
21192
+
21193
+ if self.check(TokenType::End)
21194
+ && self.current + 1 < self.tokens.len()
21195
+ && self.tokens[self.current + 1]
21196
+ .text
21197
+ .eq_ignore_ascii_case(block_kind)
21198
+ {
21199
+ depth -= 1;
21200
+ if depth == 0 {
21201
+ self.skip(); // consume END
21202
+ self.skip(); // consume TRY/CATCH
21203
+ return Ok(tokens);
21204
+ }
21205
+
21206
+ tokens.push(self.advance());
21207
+ tokens.push(self.advance());
21208
+ continue;
21209
+ }
21210
+
21211
+ tokens.push(self.advance());
21212
+ }
21213
+
21214
+ Err(self.parse_error(format!("Expected END {}", block_kind)))
21215
+ }
21216
+
21193
21217
  /// Parse START TRANSACTION statement
21194
21218
  /// START TRANSACTION [READ ONLY | READ WRITE] [, ISOLATION LEVEL ...]
21195
21219
  fn parse_start_transaction(&mut self) -> Result<Expression> {
@@ -47359,12 +47383,10 @@ impl Parser {
47359
47383
  } else {
47360
47384
  break;
47361
47385
  }
47362
- // Accept comma (TSQL/BigQuery) or semicolon (Snowflake scripting) as separator
47363
- if self.match_token(TokenType::Comma) || self.match_token(TokenType::Semicolon) {
47364
- // Stop if next token is BEGIN (end of DECLARE block)
47365
- if self.check(TokenType::Begin) {
47366
- break;
47367
- }
47386
+ // Accept comma-separated DECLARE items. Statement-level semicolons
47387
+ // are consumed by the top-level parser so batches like
47388
+ // `DECLARE @x INT; SELECT @x` keep their statement boundary.
47389
+ if self.match_token(TokenType::Comma) {
47368
47390
  continue;
47369
47391
  }
47370
47392
  break;
@@ -1001,6 +1001,16 @@ impl<'a> WalkInScopeIter<'a> {
1001
1001
  // Tables don't have child expressions to traverse within scope
1002
1002
  // (joins are handled at the Select level)
1003
1003
  }
1004
+ Expression::TryCatch(try_catch) => {
1005
+ for stmt in &try_catch.try_body {
1006
+ children.push(stmt);
1007
+ }
1008
+ if let Some(catch_body) = &try_catch.catch_body {
1009
+ for stmt in catch_body {
1010
+ children.push(stmt);
1011
+ }
1012
+ }
1013
+ }
1004
1014
  Expression::Column(_) | Expression::Literal(_) | Expression::Identifier(_) => {
1005
1015
  // Leaf nodes - no children
1006
1016
  }
@@ -746,6 +746,12 @@ fn iter_children_lists(expr: &Expression) -> Vec<(&'static str, &[Expression])>
746
746
  Expression::Tuple(t) => {
747
747
  lists.push(("expressions", t.expressions.as_slice()));
748
748
  }
749
+ Expression::TryCatch(try_catch) => {
750
+ lists.push(("try_body", try_catch.try_body.as_slice()));
751
+ if let Some(catch_body) = &try_catch.catch_body {
752
+ lists.push(("catch_body", catch_body.as_slice()));
753
+ }
754
+ }
749
755
  // Values.expressions is Vec<Tuple>, handle specially
750
756
  Expression::Coalesce(c) => {
751
757
  lists.push(("expressions", c.expressions.as_slice()));