polyglot-sql 0.10.0__tar.gz → 0.11.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (210) hide show
  1. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/Cargo.lock +6 -6
  2. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/Cargo.toml +1 -1
  3. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/PKG-INFO +21 -1
  4. {polyglot_sql-0.10.0/crates/polyglot-sql-python → polyglot_sql-0.11.0}/README.md +20 -0
  5. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/Cargo.toml +2 -2
  6. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/README.md +4 -4
  7. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/benches/performance_hotspots.rs +1 -0
  8. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/dialects/bigquery.rs +1 -0
  9. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/dialects/clickhouse.rs +1 -0
  10. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/dialects/duckdb.rs +2 -0
  11. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/expressions.rs +13 -0
  12. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/generator.rs +91 -48
  13. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/guard.rs +48 -0
  14. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/lineage.rs +24 -6
  15. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/optimizer/annotate_types.rs +171 -37
  16. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/optimizer/qualify_columns.rs +333 -104
  17. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/parser.rs +1780 -774
  18. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/resolver.rs +46 -4
  19. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/scope.rs +9 -0
  20. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/tokens.rs +14 -5
  21. polyglot_sql-0.11.0/crates/polyglot-sql/tests/data_type_api.rs +251 -0
  22. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/tests/deep_nesting_regression.rs +141 -0
  23. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/tests/query_analysis.rs +106 -0
  24. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql-function-catalogs/README.md +1 -1
  25. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0/crates/polyglot-sql-python}/README.md +20 -0
  26. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql-python/src/transpile.rs +33 -1
  27. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql-python/tests/test_generate.py +33 -0
  28. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql-python/tests/test_query_analysis.py +23 -0
  29. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql-python/tests/test_transpile.py +36 -0
  30. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/python/polyglot_sql/__init__.py +18 -0
  31. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/python/polyglot_sql/__init__.pyi +14 -1
  32. polyglot_sql-0.10.0/crates/polyglot-sql/tests/data_type_api.rs +0 -86
  33. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/benches/allocation_hotspots.rs +0 -0
  34. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/benches/ast_traversal.rs +0 -0
  35. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/benches/in_list.rs +0 -0
  36. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/benches/lineage.rs +0 -0
  37. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/benches/parsing.rs +0 -0
  38. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/benches/rust_parsing.rs +0 -0
  39. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/benches/transpile.rs +0 -0
  40. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/examples/basic_usage.rs +0 -0
  41. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/examples/bench_json.rs +0 -0
  42. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/ast_children.rs +0 -0
  43. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/ast_json.rs +0 -0
  44. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/ast_mutation.rs +0 -0
  45. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/ast_transforms.rs +0 -0
  46. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/builder/mod.rs +0 -0
  47. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/builder/plan.rs +0 -0
  48. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/dialects/athena.rs +0 -0
  49. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/dialects/cockroachdb.rs +0 -0
  50. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/dialects/databricks.rs +0 -0
  51. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/dialects/datafusion.rs +0 -0
  52. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/dialects/doris.rs +0 -0
  53. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/dialects/dremio.rs +0 -0
  54. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/dialects/drill.rs +0 -0
  55. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/dialects/druid.rs +0 -0
  56. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/dialects/dune.rs +0 -0
  57. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/dialects/exasol.rs +0 -0
  58. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/dialects/fabric.rs +0 -0
  59. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/dialects/generic.rs +0 -0
  60. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/dialects/hive.rs +0 -0
  61. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/dialects/materialize.rs +0 -0
  62. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/dialects/mod.rs +0 -0
  63. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/dialects/mysql.rs +0 -0
  64. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/dialects/normalization/aggregates.rs +0 -0
  65. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/dialects/normalization/collections.rs +0 -0
  66. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/dialects/normalization/json.rs +0 -0
  67. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/dialects/normalization/mod.rs +0 -0
  68. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/dialects/normalization/operators.rs +0 -0
  69. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/dialects/normalization/postgres_interval.rs +0 -0
  70. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/dialects/normalization/scalar.rs +0 -0
  71. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/dialects/normalization/statements.rs +0 -0
  72. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/dialects/normalization/temporal.rs +0 -0
  73. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/dialects/normalization/types.rs +0 -0
  74. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/dialects/oracle.rs +0 -0
  75. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/dialects/postgres.rs +0 -0
  76. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/dialects/presto.rs +0 -0
  77. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/dialects/redshift.rs +0 -0
  78. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/dialects/risingwave.rs +0 -0
  79. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/dialects/singlestore.rs +0 -0
  80. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/dialects/snowflake.rs +0 -0
  81. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/dialects/solr.rs +0 -0
  82. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/dialects/spark.rs +0 -0
  83. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/dialects/sqlite.rs +0 -0
  84. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/dialects/starrocks.rs +0 -0
  85. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/dialects/tableau.rs +0 -0
  86. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/dialects/teradata.rs +0 -0
  87. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/dialects/tidb.rs +0 -0
  88. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/dialects/trino.rs +0 -0
  89. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/dialects/tsql.rs +0 -0
  90. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/diff.rs +0 -0
  91. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/error.rs +0 -0
  92. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/format_tokens.rs +0 -0
  93. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/function_catalog.rs +0 -0
  94. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/function_registry.rs +0 -0
  95. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/helper.rs +0 -0
  96. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/lib.rs +0 -0
  97. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/openlineage.rs +0 -0
  98. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/optimizer/canonicalize.rs +0 -0
  99. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/optimizer/eliminate_ctes.rs +0 -0
  100. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/optimizer/eliminate_joins.rs +0 -0
  101. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/optimizer/isolate_table_selects.rs +0 -0
  102. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/optimizer/mod.rs +0 -0
  103. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/optimizer/normalize.rs +0 -0
  104. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/optimizer/normalize_identifiers.rs +0 -0
  105. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/optimizer/optimize_joins.rs +0 -0
  106. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/optimizer/optimizer.rs +0 -0
  107. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/optimizer/pushdown_predicates.rs +0 -0
  108. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/optimizer/pushdown_projections.rs +0 -0
  109. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/optimizer/qualify_tables.rs +0 -0
  110. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/optimizer/simplify.rs +0 -0
  111. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/optimizer/subquery.rs +0 -0
  112. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/planner.rs +0 -0
  113. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/query_analysis/column_uses.rs +0 -0
  114. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/query_analysis.rs +3 -3
  115. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/schema.rs +0 -0
  116. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/set_operation.rs +0 -0
  117. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/time.rs +0 -0
  118. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/transforms.rs +0 -0
  119. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/traversal.rs +0 -0
  120. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/trie.rs +0 -0
  121. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/validation/tests.rs +0 -0
  122. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/src/validation.rs +0 -0
  123. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/tests/analyze_failures.rs +0 -0
  124. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/tests/clickhouse_regression.rs +0 -0
  125. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/tests/common/known_failures.rs +0 -0
  126. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/tests/common/mod.rs +0 -0
  127. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/tests/common/test_data.rs +0 -0
  128. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/tests/common/test_runner.rs +0 -0
  129. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/tests/create_view_security_comment_regression.rs +0 -0
  130. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/tests/custom_clickhouse_coverage.rs +0 -0
  131. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/tests/custom_clickhouse_parser.rs +0 -0
  132. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/tests/custom_dialect.rs +0 -0
  133. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/tests/custom_dialect_tests.rs +0 -0
  134. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/tests/custom_fixtures/datafusion/ddl.json +0 -0
  135. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/tests/custom_fixtures/datafusion/dml.json +0 -0
  136. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/tests/custom_fixtures/datafusion/functions.json +0 -0
  137. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/tests/custom_fixtures/datafusion/identity.json +0 -0
  138. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/tests/custom_fixtures/datafusion/operators.json +0 -0
  139. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/tests/custom_fixtures/datafusion/select.json +0 -0
  140. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/tests/custom_fixtures/datafusion/transpilation.json +0 -0
  141. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/tests/custom_fixtures/datafusion/types.json +0 -0
  142. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/tests/dialect_matrix.rs +0 -0
  143. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/tests/error_handling.rs +0 -0
  144. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/tests/fabric_regression.rs +0 -0
  145. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/tests/fabric_tpch_regression.rs +0 -0
  146. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/tests/identity_roundtrip.rs +0 -0
  147. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/tests/oracle_data_types_regression.rs +0 -0
  148. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/tests/postgres_explain_options.rs +0 -0
  149. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/tests/postgres_regexp_clickhouse.rs +0 -0
  150. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/tests/postgres_sqlite_regression.rs +0 -0
  151. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/tests/query_analysis_regression.rs +0 -0
  152. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/tests/snowflake_regression_test.rs +0 -0
  153. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/tests/sqlglot_compat.rs +0 -0
  154. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/tests/sqlglot_dialect_identity.rs +0 -0
  155. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/tests/sqlglot_identity.rs +0 -0
  156. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/tests/sqlglot_identity_detailed.rs +0 -0
  157. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/tests/sqlglot_parser.rs +0 -0
  158. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/tests/sqlglot_pretty.rs +0 -0
  159. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/tests/sqlglot_transpilation.rs +0 -0
  160. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/tests/sqlglot_transpile.rs +0 -0
  161. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/tests/tpch_transpile_stack.rs +0 -0
  162. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/tests/transform_regression.rs +0 -0
  163. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql/tests/tsql_regression.rs +0 -0
  164. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql-ast-derive/Cargo.toml +0 -0
  165. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql-ast-derive/src/lib.rs +0 -0
  166. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql-function-catalogs/Cargo.toml +0 -0
  167. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql-function-catalogs/src/clickhouse.rs +0 -0
  168. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql-function-catalogs/src/duckdb.rs +0 -0
  169. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql-function-catalogs/src/lib.rs +0 -0
  170. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql-function-catalogs/tools/clickhouse/extract_functions.py +0 -0
  171. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql-function-catalogs/tools/duckdb/extract_functions.py +0 -0
  172. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql-python/Cargo.toml +0 -0
  173. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql-python/docs/api.md +0 -0
  174. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql-python/docs/index.md +0 -0
  175. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql-python/mkdocs.yml +0 -0
  176. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql-python/src/annotate_types.rs +0 -0
  177. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql-python/src/builders.rs +0 -0
  178. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql-python/src/dialects.rs +0 -0
  179. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql-python/src/diff.rs +0 -0
  180. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql-python/src/errors.rs +0 -0
  181. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql-python/src/expr.rs +0 -0
  182. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql-python/src/expr_types.rs +0 -0
  183. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql-python/src/format.rs +0 -0
  184. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql-python/src/generate.rs +0 -0
  185. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql-python/src/helpers.rs +0 -0
  186. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql-python/src/lib.rs +0 -0
  187. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql-python/src/lineage.rs +0 -0
  188. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql-python/src/openlineage.rs +0 -0
  189. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql-python/src/optimize.rs +0 -0
  190. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql-python/src/parse.rs +0 -0
  191. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql-python/src/query_analysis.rs +0 -0
  192. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql-python/src/tokenize.rs +0 -0
  193. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql-python/src/transforms.rs +0 -0
  194. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql-python/src/types.rs +0 -0
  195. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql-python/src/validate.rs +0 -0
  196. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql-python/tests/conftest.py +0 -0
  197. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql-python/tests/test_builders.py +0 -0
  198. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql-python/tests/test_compat.py +0 -0
  199. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql-python/tests/test_dialects.py +0 -0
  200. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql-python/tests/test_diff.py +0 -0
  201. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql-python/tests/test_expression.py +0 -0
  202. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql-python/tests/test_format.py +0 -0
  203. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql-python/tests/test_lineage.py +0 -0
  204. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql-python/tests/test_optimize.py +0 -0
  205. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql-python/tests/test_parse.py +0 -0
  206. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql-python/tests/test_transforms.py +0 -0
  207. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql-python/tests/test_validate.py +0 -0
  208. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/crates/polyglot-sql-python/uv.lock +0 -0
  209. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/pyproject.toml +0 -0
  210. {polyglot_sql-0.10.0 → polyglot_sql-0.11.0}/python/polyglot_sql/py.typed +0 -0
@@ -605,7 +605,7 @@ dependencies = [
605
605
 
606
606
  [[package]]
607
607
  name = "polyglot-sql"
608
- version = "0.10.0"
608
+ version = "0.11.0"
609
609
  dependencies = [
610
610
  "criterion",
611
611
  "once_cell",
@@ -623,7 +623,7 @@ dependencies = [
623
623
 
624
624
  [[package]]
625
625
  name = "polyglot-sql-ast-derive"
626
- version = "0.10.0"
626
+ version = "0.11.0"
627
627
  dependencies = [
628
628
  "proc-macro2",
629
629
  "quote",
@@ -632,7 +632,7 @@ dependencies = [
632
632
 
633
633
  [[package]]
634
634
  name = "polyglot-sql-ffi"
635
- version = "0.10.0"
635
+ version = "0.11.0"
636
636
  dependencies = [
637
637
  "cbindgen",
638
638
  "polyglot-sql",
@@ -642,11 +642,11 @@ dependencies = [
642
642
 
643
643
  [[package]]
644
644
  name = "polyglot-sql-function-catalogs"
645
- version = "0.10.0"
645
+ version = "0.11.0"
646
646
 
647
647
  [[package]]
648
648
  name = "polyglot-sql-python"
649
- version = "0.10.0"
649
+ version = "0.11.0"
650
650
  dependencies = [
651
651
  "polyglot-sql",
652
652
  "pyo3",
@@ -657,7 +657,7 @@ dependencies = [
657
657
 
658
658
  [[package]]
659
659
  name = "polyglot-sql-wasm"
660
- version = "0.10.0"
660
+ version = "0.11.0"
661
661
  dependencies = [
662
662
  "console_error_panic_hook",
663
663
  "js-sys",
@@ -6,7 +6,7 @@ exclude = [
6
6
  ]
7
7
 
8
8
  [workspace.package]
9
- version = "0.10.0"
9
+ version = "0.11.0"
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.10.0
3
+ Version: 0.11.0
4
4
  Classifier: Development Status :: 4 - Beta
5
5
  Classifier: Intended Audience :: Developers
6
6
  Classifier: License :: OSI Approved :: MIT License
@@ -110,6 +110,26 @@ polyglot_sql.generate(ast)
110
110
  # ["SELECT id FROM a UNION ALL SELECT id FROM b ORDER BY id LIMIT 100 OFFSET 10"]
111
111
  ```
112
112
 
113
+ ### Complexity Guard Options
114
+
115
+ `transpile` also accepts `complexity_guard`, a `ComplexityGuardOptions` typed dictionary
116
+ using the shared camelCase keys: `maxParserDepth`, `maxInputBytes`, `maxTokens`,
117
+ `maxAstNodes`, `maxAstDepth`, `maxParenthesisDepth`, and `maxFunctionCallDepth`.
118
+ Omit the argument, pass `None`, or omit a key to use its default. A field-level `None`
119
+ disables that check; a nonnegative integer overrides it. For example:
120
+
121
+ ```python
122
+ polyglot_sql.transpile(sql, complexity_guard={"maxParserDepth": 128})
123
+ ```
124
+
125
+ Parser depth defaults to 1024 logical levels on native targets (32 on WASM) and is
126
+ checked during parsing, before an AST exists. Zero rejects parsing descents.
127
+ Other checks remain independent.
128
+ Raising or disabling limits can permit stack exhaustion and process termination,
129
+ even for trusted generated SQL. Increasing a limit does not increase stack space;
130
+ these limits are not general time/memory budgets. Application owners should control
131
+ overrides. Parsing APIs without guard options inherit the default protection.
132
+
113
133
  ### Format Guard Behavior
114
134
 
115
135
  `format_sql` uses Rust core formatting guards with default limits:
@@ -83,6 +83,26 @@ polyglot_sql.generate(ast)
83
83
  # ["SELECT id FROM a UNION ALL SELECT id FROM b ORDER BY id LIMIT 100 OFFSET 10"]
84
84
  ```
85
85
 
86
+ ### Complexity Guard Options
87
+
88
+ `transpile` also accepts `complexity_guard`, a `ComplexityGuardOptions` typed dictionary
89
+ using the shared camelCase keys: `maxParserDepth`, `maxInputBytes`, `maxTokens`,
90
+ `maxAstNodes`, `maxAstDepth`, `maxParenthesisDepth`, and `maxFunctionCallDepth`.
91
+ Omit the argument, pass `None`, or omit a key to use its default. A field-level `None`
92
+ disables that check; a nonnegative integer overrides it. For example:
93
+
94
+ ```python
95
+ polyglot_sql.transpile(sql, complexity_guard={"maxParserDepth": 128})
96
+ ```
97
+
98
+ Parser depth defaults to 1024 logical levels on native targets (32 on WASM) and is
99
+ checked during parsing, before an AST exists. Zero rejects parsing descents.
100
+ Other checks remain independent.
101
+ Raising or disabling limits can permit stack exhaustion and process termination,
102
+ even for trusted generated SQL. Increasing a limit does not increase stack space;
103
+ these limits are not general time/memory budgets. Application owners should control
104
+ overrides. Parsing APIs without guard options inherit the default protection.
105
+
86
106
  ### Format Guard Behavior
87
107
 
88
108
  `format_sql` uses Rust core formatting guards with default limits:
@@ -100,14 +100,14 @@ function-catalog-all-dialects = [
100
100
  ]
101
101
 
102
102
  [dependencies]
103
- polyglot-sql-ast-derive = { path = "../polyglot-sql-ast-derive", version = "0.10.0" }
103
+ polyglot-sql-ast-derive = { path = "../polyglot-sql-ast-derive", version = "0.11.0" }
104
104
  serde = { workspace = true }
105
105
  serde_json = { workspace = true }
106
106
  thiserror = { workspace = true }
107
107
  unicode-segmentation = { workspace = true }
108
108
  stacker = { version = "0.1", optional = true }
109
109
  ts-rs = { version = "12.0", features = ["serde-compat"], optional = true }
110
- polyglot-sql-function-catalogs = { path = "../polyglot-sql-function-catalogs", version = "0.10.0", optional = true, default-features = false }
110
+ polyglot-sql-function-catalogs = { path = "../polyglot-sql-function-catalogs", version = "0.11.0", optional = true, default-features = false }
111
111
 
112
112
  [dev-dependencies]
113
113
  pretty_assertions = "1.4"
@@ -25,12 +25,12 @@ By default, `polyglot-sql` enables the full public API. Parser-only consumers ca
25
25
  disable default features and opt into only the dialect parsers they need:
26
26
 
27
27
  ```toml
28
- polyglot-sql = { version = "0.10.0", default-features = false }
28
+ polyglot-sql = { version = "0.11.0", default-features = false }
29
29
  ```
30
30
 
31
31
  ```toml
32
32
  polyglot-sql = {
33
- version = "0.8.0",
33
+ version = "0.11.0",
34
34
  default-features = false,
35
35
  features = ["dialect-clickhouse"],
36
36
  }
@@ -44,14 +44,14 @@ Examples:
44
44
  ```toml
45
45
  # Parse and generate SQL for one dialect.
46
46
  polyglot-sql = {
47
- version = "0.8.0",
47
+ version = "0.11.0",
48
48
  default-features = false,
49
49
  features = ["generate", "dialect-clickhouse"],
50
50
  }
51
51
 
52
52
  # Cross-dialect transpilation.
53
53
  polyglot-sql = {
54
- version = "0.8.0",
54
+ version = "0.11.0",
55
55
  default-features = false,
56
56
  features = ["transpile", "dialect-clickhouse", "dialect-postgresql"],
57
57
  }
@@ -81,6 +81,7 @@ fn many_numbers() -> String {
81
81
 
82
82
  fn disabled_guards() -> ComplexityGuardOptions {
83
83
  ComplexityGuardOptions {
84
+ max_parser_depth: None,
84
85
  max_input_bytes: None,
85
86
  max_tokens: None,
86
87
  max_ast_nodes: None,
@@ -34,6 +34,7 @@ impl DialectImpl for BigQueryDialect {
34
34
  // Remove double quote from identifiers (it's in the default config)
35
35
  config.identifiers.remove(&'"');
36
36
  config.identifiers.insert('`', '`');
37
+ config.identifier_backslash_escapes = true;
37
38
  // BigQuery supports double quotes for strings (in addition to single quotes)
38
39
  config.quotes.insert("\"".to_string(), "\"".to_string());
39
40
  // BigQuery supports triple-quoted strings
@@ -28,6 +28,7 @@ impl DialectImpl for ClickHouseDialect {
28
28
  // ClickHouse uses double quotes and backticks for identifiers
29
29
  config.identifiers.insert('"', '"');
30
30
  config.identifiers.insert('`', '`');
31
+ config.identifier_backslash_escapes = true;
31
32
  // ClickHouse supports nested comments
32
33
  config.nested_comments = true;
33
34
  // ClickHouse allows identifiers to start with digits
@@ -97,6 +97,8 @@ impl DialectImpl for DuckDBDialect {
97
97
  let mut config = TokenizerConfig::default();
98
98
  // DuckDB uses double quotes for identifiers
99
99
  config.identifiers.insert('"', '"');
100
+ // A leading escaped double quote belongs to the identifier, not a triple-quoted string.
101
+ config.quotes.remove("\"\"\"");
100
102
  // DuckDB supports nested comments
101
103
  config.nested_comments = true;
102
104
  // DuckDB allows underscores as digit separators in numeric literals
@@ -3373,6 +3373,16 @@ impl Identifier {
3373
3373
  self.name.is_empty()
3374
3374
  }
3375
3375
 
3376
+ /// Preserve quoting in the legacy string representation of named type fields.
3377
+ /// Always use SQL-standard delimiters internally, independent of the source dialect.
3378
+ pub(crate) fn to_type_field_name(&self) -> String {
3379
+ if self.quoted {
3380
+ format!("\"{}\"", self.name.replace('"', "\"\""))
3381
+ } else {
3382
+ self.name.clone()
3383
+ }
3384
+ }
3385
+
3376
3386
  /// Set the source span on this identifier
3377
3387
  pub fn with_span(mut self, span: Span) -> Self {
3378
3388
  self.span = Some(span);
@@ -5740,6 +5750,9 @@ pub enum WindowFrameBound {
5740
5750
  #[derive(polyglot_sql_ast_derive::AstNode, Debug, Clone, PartialEq, Serialize, Deserialize)]
5741
5751
  #[cfg_attr(feature = "bindings", derive(TS))]
5742
5752
  pub struct StructField {
5753
+ /// A raw field name, or a delimited identifier for compatibility with parsed ASTs.
5754
+ /// Parsed quoted names use double quotes with doubled internal quotes. An empty
5755
+ /// string denotes an anonymous field. Generation selects the target dialect's quotes.
5743
5756
  pub name: String,
5744
5757
  pub data_type: DataType,
5745
5758
  #[serde(default, skip_serializing_if = "Vec::is_empty")]
@@ -16621,22 +16621,7 @@ impl Generator {
16621
16621
  } else {
16622
16622
  quote_style
16623
16623
  };
16624
- // Escape any quote characters within the identifier
16625
- let escaped_name = if quote_style.start == quote_style.end {
16626
- output_name.replace(
16627
- quote_style.end,
16628
- &format!("{}{}", quote_style.end, quote_style.end),
16629
- )
16630
- } else {
16631
- output_name.replace(
16632
- quote_style.end,
16633
- &format!("{}{}", quote_style.end, quote_style.end),
16634
- )
16635
- };
16636
- self.write(&format!(
16637
- "{}{}{}",
16638
- quote_style.start, escaped_name, quote_style.end
16639
- ));
16624
+ self.write_quoted_identifier(&output_name, *quote_style);
16640
16625
  } else {
16641
16626
  self.write(&output_name);
16642
16627
  }
@@ -16746,24 +16731,8 @@ impl Generator {
16746
16731
  };
16747
16732
 
16748
16733
  if needs_quoting {
16749
- // Escape any quote characters within the identifier
16750
- let escaped_name = if quote_style.start == quote_style.end {
16751
- // Same start/end char (e.g., " or `) - double the quote char
16752
- output_name.replace(
16753
- quote_style.end,
16754
- &format!("{}{}", quote_style.end, quote_style.end),
16755
- )
16756
- } else {
16757
- // Different start/end (e.g., [ and ]) - escape only the end char
16758
- output_name.replace(
16759
- quote_style.end,
16760
- &format!("{}{}", quote_style.end, quote_style.end),
16761
- )
16762
- };
16763
- self.write(&format!(
16764
- "{}{}{}{}",
16765
- quote_style.start, escaped_name, quote_style.end, suffix
16766
- ));
16734
+ self.write_quoted_identifier(&output_name, *quote_style);
16735
+ self.write(&suffix);
16767
16736
  } else {
16768
16737
  self.write(&output_name);
16769
16738
  }
@@ -16776,6 +16745,78 @@ impl Generator {
16776
16745
  Ok(())
16777
16746
  }
16778
16747
 
16748
+ /// Write an identifier using the target dialect's delimiters and escape rules.
16749
+ fn write_quoted_identifier(&mut self, name: &str, quote_style: IdentifierQuoteStyle) {
16750
+ let backslash_escapes = matches!(
16751
+ self.config.dialect,
16752
+ Some(DialectType::BigQuery | DialectType::ClickHouse)
16753
+ );
16754
+ self.output.push(quote_style.start);
16755
+ for c in name.chars() {
16756
+ if backslash_escapes {
16757
+ let escape = match c {
16758
+ '\\' => Some("\\\\"),
16759
+ '\n' => Some("\\n"),
16760
+ '\r' => Some("\\r"),
16761
+ '\t' => Some("\\t"),
16762
+ '\0' => Some("\\x00"),
16763
+ _ => None,
16764
+ };
16765
+ if let Some(escape) = escape {
16766
+ self.write(escape);
16767
+ continue;
16768
+ }
16769
+ if c == quote_style.end && self.config.dialect == Some(DialectType::BigQuery) {
16770
+ self.output.push('\\');
16771
+ self.output.push(c);
16772
+ continue;
16773
+ }
16774
+ }
16775
+ self.output.push(c);
16776
+ if c == quote_style.end {
16777
+ self.output.push(c);
16778
+ }
16779
+ }
16780
+ self.output.push(quote_style.end);
16781
+ }
16782
+
16783
+ /// Named type fields are single identifiers, never SQL fragments or index columns.
16784
+ /// Keep the public string shape while accepting legacy delimited field names.
16785
+ fn generate_type_field_name(&mut self, field_name: &str) {
16786
+ let mut name = Cow::Borrowed(field_name);
16787
+ let mut quoted = false;
16788
+ for (start, end) in [('"', '"'), ('`', '`'), ('[', ']')] {
16789
+ if let Some(inner) = field_name
16790
+ .strip_prefix(start)
16791
+ .and_then(|s| s.strip_suffix(end))
16792
+ {
16793
+ name = Cow::Owned(inner.replace(&format!("{end}{end}"), &end.to_string()));
16794
+ quoted = true;
16795
+ break;
16796
+ }
16797
+ }
16798
+
16799
+ let needs_quoting = quoted
16800
+ || !Self::is_safe_unquoted_identifier(&name)
16801
+ || self.is_reserved_keyword(&name)
16802
+ || self.config.always_quote_identifiers;
16803
+ if self.config.normalize_identifiers && !quoted {
16804
+ name = Cow::Owned(name.to_ascii_lowercase());
16805
+ }
16806
+ if !needs_quoting {
16807
+ self.write(&name);
16808
+ return;
16809
+ }
16810
+
16811
+ let quote_style =
16812
+ if self.config.dialect == Some(DialectType::Athena) && self.athena_hive_context {
16813
+ IdentifierQuoteStyle::BACKTICK
16814
+ } else {
16815
+ self.config.identifier_quote_style
16816
+ };
16817
+ self.write_quoted_identifier(&name, quote_style);
16818
+ }
16819
+
16779
16820
  fn generate_column(&mut self, col: &Column) -> Result<()> {
16780
16821
  use crate::dialects::DialectType;
16781
16822
 
@@ -26846,7 +26887,7 @@ impl Generator {
26846
26887
  if i > 0 {
26847
26888
  self.write(", ");
26848
26889
  }
26849
- self.write(name);
26890
+ self.generate_type_field_name(name);
26850
26891
  self.write(" ");
26851
26892
  self.generate_data_type(dt)?;
26852
26893
  if *not_null {
@@ -26870,7 +26911,7 @@ impl Generator {
26870
26911
  self.write(", ");
26871
26912
  }
26872
26913
  if !field.name.is_empty() {
26873
- self.write(&field.name);
26914
+ self.generate_type_field_name(&field.name);
26874
26915
  self.write(" ");
26875
26916
  }
26876
26917
  self.generate_data_type(&field.data_type)?;
@@ -26885,7 +26926,7 @@ impl Generator {
26885
26926
  self.write(", ");
26886
26927
  }
26887
26928
  if !field.name.is_empty() {
26888
- self.write(&field.name);
26929
+ self.generate_type_field_name(&field.name);
26889
26930
  self.write(" ");
26890
26931
  }
26891
26932
  self.generate_data_type(&field.data_type)?;
@@ -26900,7 +26941,7 @@ impl Generator {
26900
26941
  self.write(", ");
26901
26942
  }
26902
26943
  if !field.name.is_empty() {
26903
- self.write(&field.name);
26944
+ self.generate_type_field_name(&field.name);
26904
26945
  self.write(" ");
26905
26946
  }
26906
26947
  self.generate_data_type(&field.data_type)?;
@@ -26915,7 +26956,7 @@ impl Generator {
26915
26956
  self.write(", ");
26916
26957
  }
26917
26958
  if !field.name.is_empty() {
26918
- self.write(&field.name);
26959
+ self.generate_type_field_name(&field.name);
26919
26960
  self.write(" ");
26920
26961
  }
26921
26962
  self.generate_data_type(&field.data_type)?;
@@ -26930,7 +26971,7 @@ impl Generator {
26930
26971
  self.write(", ");
26931
26972
  }
26932
26973
  if !field.name.is_empty() {
26933
- self.write(&field.name);
26974
+ self.generate_type_field_name(&field.name);
26934
26975
  self.write(" ");
26935
26976
  }
26936
26977
  self.generate_data_type(&field.data_type)?;
@@ -26938,12 +26979,14 @@ impl Generator {
26938
26979
  self.write(")");
26939
26980
  }
26940
26981
  _ => {
26941
- // Hive/Spark always use angle bracket syntax: STRUCT<name: TYPE>
26982
+ // BigQuery and Hive/Spark use angle brackets even for types
26983
+ // parsed from a parenthesized source dialect.
26942
26984
  let force_angle_brackets = matches!(
26943
26985
  self.config.dialect,
26944
26986
  Some(DialectType::Hive)
26945
26987
  | Some(DialectType::Spark)
26946
26988
  | Some(DialectType::Databricks)
26989
+ | Some(DialectType::BigQuery)
26947
26990
  );
26948
26991
  if *nested && !force_angle_brackets {
26949
26992
  self.write_keyword("STRUCT(");
@@ -26952,7 +26995,7 @@ impl Generator {
26952
26995
  self.write(", ");
26953
26996
  }
26954
26997
  if !field.name.is_empty() {
26955
- self.write(&field.name);
26998
+ self.generate_type_field_name(&field.name);
26956
26999
  self.write(" ");
26957
27000
  }
26958
27001
  self.generate_data_type(&field.data_type)?;
@@ -26966,7 +27009,7 @@ impl Generator {
26966
27009
  }
26967
27010
  if !field.name.is_empty() {
26968
27011
  // Named field: name TYPE (with configurable separator for Hive)
26969
- self.write(&field.name);
27012
+ self.generate_type_field_name(&field.name);
26970
27013
  self.write(self.config.struct_field_sep);
26971
27014
  }
26972
27015
  // For anonymous fields, just output the type
@@ -27034,7 +27077,7 @@ impl Generator {
27034
27077
  self.write(", ");
27035
27078
  }
27036
27079
  if !name.is_empty() {
27037
- self.write(name);
27080
+ self.generate_type_field_name(name);
27038
27081
  self.write(" ");
27039
27082
  }
27040
27083
  self.generate_data_type(dt)?;
@@ -33275,7 +33318,7 @@ impl Generator {
33275
33318
  if key.is_empty() {
33276
33319
  // Bracket notation at start of segment (e.g., already formatted)
33277
33320
  self.write(segment);
33278
- } else if Self::is_safe_json_path_key(key) {
33321
+ } else if Self::is_safe_unquoted_identifier(key) {
33279
33322
  self.write(key);
33280
33323
  self.write(subscript);
33281
33324
  } else {
@@ -33284,7 +33327,7 @@ impl Generator {
33284
33327
  self.write("\"]");
33285
33328
  self.write(subscript);
33286
33329
  }
33287
- } else if Self::is_safe_json_path_key(segment) {
33330
+ } else if Self::is_safe_unquoted_identifier(segment) {
33288
33331
  self.write(segment);
33289
33332
  } else {
33290
33333
  self.write("[\"");
@@ -33294,9 +33337,9 @@ impl Generator {
33294
33337
  }
33295
33338
  }
33296
33339
 
33297
- /// Check if a JSON path key is a safe identifier that doesn't need bracket quoting.
33340
+ /// Check if a name can be emitted as a conservative unquoted identifier.
33298
33341
  /// Matches Python sqlglot's SAFE_IDENTIFIER_RE: ^[_a-zA-Z]\w*$
33299
- fn is_safe_json_path_key(key: &str) -> bool {
33342
+ fn is_safe_unquoted_identifier(key: &str) -> bool {
33300
33343
  if key.is_empty() {
33301
33344
  return false;
33302
33345
  }
@@ -11,6 +11,21 @@ const DEFAULT_MAX_AST_NODES: usize = 1_000_000;
11
11
  const DEFAULT_MAX_AST_DEPTH: usize = 512;
12
12
  const DEFAULT_MAX_PARENTHESES_DEPTH: usize = 512;
13
13
  const DEFAULT_MAX_FUNCTION_CALL_DEPTH: usize = 64;
14
+ // WASM has no stacker support, and grammar frames differ substantially in size.
15
+ // Keep its default conservative; an explicit option still replaces this value.
16
+ #[cfg(target_arch = "wasm32")]
17
+ const DEFAULT_MAX_PARSER_DEPTH: usize = 32;
18
+ #[cfg(not(target_arch = "wasm32"))]
19
+ const DEFAULT_MAX_PARSER_DEPTH: usize = 1_024;
20
+
21
+ fn default_max_parser_depth() -> Option<usize> {
22
+ Some(DEFAULT_MAX_PARSER_DEPTH)
23
+ }
24
+
25
+ /// Resource exhaustion must not be treated as a speculative syntax mismatch.
26
+ pub(crate) fn is_guard_error(error: &Error) -> bool {
27
+ matches!(error, Error::Parse { message, .. } if message.starts_with("E_GUARD_"))
28
+ }
14
29
 
15
30
  fn default_max_input_bytes() -> Option<usize> {
16
31
  Some(DEFAULT_MAX_INPUT_BYTES)
@@ -43,6 +58,11 @@ fn default_max_function_call_depth() -> Option<usize> {
43
58
  #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
44
59
  #[serde(rename_all = "camelCase")]
45
60
  pub struct ComplexityGuardOptions {
61
+ /// Maximum logical nesting during parsing, before an AST exists.
62
+ /// Defaults to 32 on WASM and 1024 on native targets.
63
+ /// Raising this limit or disabling it with `None` can permit stack exhaustion.
64
+ #[serde(default = "default_max_parser_depth")]
65
+ pub max_parser_depth: Option<usize>,
46
66
  /// Maximum allowed SQL input size in bytes.
47
67
  /// `None` disables this check.
48
68
  #[serde(default = "default_max_input_bytes")]
@@ -120,6 +140,7 @@ impl TokenGuardStats {
120
140
  impl Default for ComplexityGuardOptions {
121
141
  fn default() -> Self {
122
142
  Self {
143
+ max_parser_depth: default_max_parser_depth(),
123
144
  max_input_bytes: default_max_input_bytes(),
124
145
  max_tokens: default_max_tokens(),
125
146
  max_ast_nodes: default_max_ast_nodes(),
@@ -372,6 +393,33 @@ mod token_guard_tests {
372
393
  use crate::tokens::Tokenizer;
373
394
  use std::sync::Arc;
374
395
 
396
+ #[test]
397
+ fn parser_depth_json_contract() {
398
+ let omitted: ComplexityGuardOptions = serde_json::from_str("{}").unwrap();
399
+ assert_eq!(omitted.max_parser_depth, Some(DEFAULT_MAX_PARSER_DEPTH));
400
+ assert_eq!(
401
+ omitted.max_parser_depth,
402
+ ComplexityGuardOptions::default().max_parser_depth
403
+ );
404
+ for limit in [Some(0), Some(1), Some(2048), None] {
405
+ let guard = ComplexityGuardOptions {
406
+ max_parser_depth: limit,
407
+ ..Default::default()
408
+ };
409
+ let json = serde_json::to_string(&guard).unwrap();
410
+ assert_eq!(
411
+ serde_json::from_str::<ComplexityGuardOptions>(&json).unwrap(),
412
+ guard
413
+ );
414
+ }
415
+ for value in ["-1", "1.5", "true", "\"10\""] {
416
+ assert!(serde_json::from_str::<ComplexityGuardOptions>(&format!(
417
+ "{{\"maxParserDepth\":{value}}}"
418
+ ))
419
+ .is_err());
420
+ }
421
+ }
422
+
375
423
  #[test]
376
424
  fn collected_parser_stats_match_full_token_guard_pass() {
377
425
  let sql: Arc<str> = Arc::from("SELECT outer(inner((value))), other(1, 2) FROM t");
@@ -476,8 +476,8 @@ fn normalize_cte_name(ident: &Identifier) -> String {
476
476
  }
477
477
 
478
478
  /// Expand SELECT * in CTEs by walking CTE definitions in order and propagating
479
- /// resolved column lists. This handles nested CTEs (e.g., cte2 AS (SELECT * FROM cte1))
480
- /// which qualify_columns cannot resolve because it processes each SELECT independently.
479
+ /// resolved column lists. This also handles chained CTEs in schema-free lineage
480
+ /// and analysis paths, where full column qualification is not performed.
481
481
  ///
482
482
  /// When `schema` is provided, stars from external tables (not CTEs) are also resolved
483
483
  /// by looking up column names in the schema. This enables correct expansion of patterns
@@ -1211,14 +1211,26 @@ fn to_node_inner(
1211
1211
  // 0. Unwrap CTE scope — CTE scope expressions are Expression::Cte(...)
1212
1212
  // but we need the inner query (SELECT/UNION) for column lookup.
1213
1213
  let effective_expr = effective_scope_expression(scope_expr);
1214
+ // A CTE's explicit output names replace its projection names by ordinal.
1215
+ // Resolve that boundary before unwrapping, including unnamed expressions.
1216
+ let alias_ordinal = match (scope_expr, &column) {
1217
+ (Expression::Cte(cte), ColumnRef::Name(name)) if !cte.columns.is_empty() => {
1218
+ cte.columns.iter().position(|alias| {
1219
+ normalize_column_name(&alias.name, dialect) == normalize_column_name(name, dialect)
1220
+ })
1221
+ }
1222
+ _ => None,
1223
+ };
1224
+ let lookup_column = alias_ordinal.map(ColumnRef::Index);
1225
+ let lookup_column = lookup_column.as_ref().unwrap_or(&column);
1214
1226
 
1215
1227
  // 1. Set operations (UNION / INTERSECT / EXCEPT)
1216
1228
  if matches!(
1217
1229
  effective_expr,
1218
1230
  Expression::Union(_) | Expression::Intersect(_) | Expression::Except(_)
1219
1231
  ) {
1220
- return handle_set_operation(
1221
- &column,
1232
+ let mut node = handle_set_operation(
1233
+ lookup_column,
1222
1234
  context,
1223
1235
  scope_id,
1224
1236
  effective_expr,
@@ -1230,11 +1242,17 @@ fn to_node_inner(
1230
1242
  trim_selects,
1231
1243
  &descendant_cte_scopes,
1232
1244
  depth,
1233
- );
1245
+ )?;
1246
+ if alias_ordinal.is_some() {
1247
+ if let ColumnRef::Name(name) = &column {
1248
+ node.name = (*name).to_string();
1249
+ }
1250
+ }
1251
+ return Ok(node);
1234
1252
  }
1235
1253
 
1236
1254
  // 2. Find the select expression for this column
1237
- let select_expr = find_select_expr(effective_expr, &column, dialect)?;
1255
+ let select_expr = find_select_expr(effective_expr, lookup_column, dialect)?;
1238
1256
  let column_name = resolve_column_name(&column, &select_expr);
1239
1257
 
1240
1258
  // 3. Trim source if requested