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

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