polyglot-sql 0.9.0__tar.gz → 0.9.2__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 (208) hide show
  1. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/Cargo.lock +6 -6
  2. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/Cargo.toml +1 -1
  3. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/PKG-INFO +1 -1
  4. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/Cargo.toml +2 -2
  5. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/README.md +1 -1
  6. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/ast_transforms.rs +82 -23
  7. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/builder/mod.rs +22 -0
  8. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/dialects/duckdb.rs +25 -8
  9. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/dialects/mod.rs +23 -58
  10. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/dialects/normalization/aggregates.rs +89 -9
  11. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/dialects/normalization/mod.rs +5 -0
  12. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/dialects/normalization/operators.rs +13 -16
  13. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/expressions.rs +23 -4
  14. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/function_registry.rs +187 -5
  15. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/generator.rs +376 -56
  16. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/lib.rs +13 -0
  17. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/lineage.rs +462 -16
  18. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/openlineage.rs +2 -57
  19. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/optimizer/annotate_types.rs +155 -6
  20. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/optimizer/mod.rs +26 -0
  21. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/optimizer/qualify_columns.rs +535 -48
  22. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/optimizer/qualify_tables.rs +29 -1
  23. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/parser.rs +182 -43
  24. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/planner.rs +12 -85
  25. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/query_analysis.rs +167 -30
  26. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/resolver.rs +68 -0
  27. polyglot_sql-0.9.2/crates/polyglot-sql/src/set_operation.rs +475 -0
  28. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/traversal.rs +70 -0
  29. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/validation/tests.rs +39 -0
  30. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/validation.rs +4 -1
  31. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/tests/dialect_matrix.rs +30 -0
  32. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/tests/fabric_regression.rs +56 -0
  33. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/tests/query_analysis.rs +243 -0
  34. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/tests/tsql_regression.rs +56 -0
  35. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql-ast-derive/src/lib.rs +51 -0
  36. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql-python/tests/test_lineage.py +19 -0
  37. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/README.md +0 -0
  38. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/benches/allocation_hotspots.rs +0 -0
  39. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/benches/ast_traversal.rs +0 -0
  40. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/benches/in_list.rs +0 -0
  41. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/benches/lineage.rs +0 -0
  42. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/benches/parsing.rs +0 -0
  43. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/benches/performance_hotspots.rs +0 -0
  44. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/benches/rust_parsing.rs +0 -0
  45. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/benches/transpile.rs +0 -0
  46. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/examples/basic_usage.rs +0 -0
  47. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/examples/bench_json.rs +0 -0
  48. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/ast_children.rs +0 -0
  49. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/ast_json.rs +0 -0
  50. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/builder/engine.rs +0 -0
  51. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/builder/plan.rs +0 -0
  52. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/dialects/athena.rs +0 -0
  53. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/dialects/bigquery.rs +0 -0
  54. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/dialects/clickhouse.rs +0 -0
  55. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/dialects/cockroachdb.rs +0 -0
  56. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/dialects/databricks.rs +0 -0
  57. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/dialects/datafusion.rs +0 -0
  58. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/dialects/doris.rs +0 -0
  59. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/dialects/dremio.rs +0 -0
  60. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/dialects/drill.rs +0 -0
  61. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/dialects/druid.rs +0 -0
  62. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/dialects/dune.rs +0 -0
  63. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/dialects/exasol.rs +0 -0
  64. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/dialects/fabric.rs +0 -0
  65. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/dialects/generic.rs +0 -0
  66. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/dialects/hive.rs +0 -0
  67. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/dialects/materialize.rs +0 -0
  68. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/dialects/mysql.rs +0 -0
  69. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/dialects/normalization/collections.rs +0 -0
  70. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/dialects/normalization/json.rs +0 -0
  71. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/dialects/normalization/postgres_interval.rs +0 -0
  72. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/dialects/normalization/scalar.rs +0 -0
  73. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/dialects/normalization/statements.rs +0 -0
  74. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/dialects/normalization/temporal.rs +0 -0
  75. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/dialects/normalization/types.rs +0 -0
  76. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/dialects/oracle.rs +0 -0
  77. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/dialects/postgres.rs +0 -0
  78. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/dialects/presto.rs +0 -0
  79. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/dialects/redshift.rs +0 -0
  80. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/dialects/risingwave.rs +0 -0
  81. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/dialects/singlestore.rs +0 -0
  82. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/dialects/snowflake.rs +0 -0
  83. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/dialects/solr.rs +0 -0
  84. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/dialects/spark.rs +0 -0
  85. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/dialects/sqlite.rs +0 -0
  86. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/dialects/starrocks.rs +0 -0
  87. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/dialects/tableau.rs +0 -0
  88. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/dialects/teradata.rs +0 -0
  89. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/dialects/tidb.rs +0 -0
  90. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/dialects/trino.rs +0 -0
  91. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/dialects/tsql.rs +0 -0
  92. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/diff.rs +0 -0
  93. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/error.rs +0 -0
  94. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/format_tokens.rs +0 -0
  95. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/function_catalog.rs +0 -0
  96. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/guard.rs +0 -0
  97. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/helper.rs +0 -0
  98. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/optimizer/canonicalize.rs +0 -0
  99. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/optimizer/eliminate_ctes.rs +0 -0
  100. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/optimizer/eliminate_joins.rs +0 -0
  101. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/optimizer/isolate_table_selects.rs +0 -0
  102. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/optimizer/normalize.rs +0 -0
  103. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/optimizer/normalize_identifiers.rs +0 -0
  104. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/optimizer/optimize_joins.rs +0 -0
  105. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/optimizer/optimizer.rs +0 -0
  106. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/optimizer/pushdown_predicates.rs +0 -0
  107. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/optimizer/pushdown_projections.rs +0 -0
  108. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/optimizer/simplify.rs +0 -0
  109. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/optimizer/subquery.rs +0 -0
  110. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/schema.rs +0 -0
  111. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/scope.rs +0 -0
  112. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/time.rs +0 -0
  113. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/tokens.rs +0 -0
  114. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/transforms.rs +0 -0
  115. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/src/trie.rs +0 -0
  116. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/tests/analyze_failures.rs +0 -0
  117. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/tests/clickhouse_regression.rs +0 -0
  118. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/tests/common/known_failures.rs +0 -0
  119. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/tests/common/mod.rs +0 -0
  120. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/tests/common/test_data.rs +0 -0
  121. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/tests/common/test_runner.rs +0 -0
  122. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/tests/create_view_security_comment_regression.rs +0 -0
  123. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/tests/custom_clickhouse_coverage.rs +0 -0
  124. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/tests/custom_clickhouse_parser.rs +0 -0
  125. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/tests/custom_dialect.rs +0 -0
  126. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/tests/custom_dialect_tests.rs +0 -0
  127. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/tests/custom_fixtures/datafusion/ddl.json +0 -0
  128. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/tests/custom_fixtures/datafusion/dml.json +0 -0
  129. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/tests/custom_fixtures/datafusion/functions.json +0 -0
  130. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/tests/custom_fixtures/datafusion/identity.json +0 -0
  131. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/tests/custom_fixtures/datafusion/operators.json +0 -0
  132. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/tests/custom_fixtures/datafusion/select.json +0 -0
  133. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/tests/custom_fixtures/datafusion/transpilation.json +0 -0
  134. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/tests/custom_fixtures/datafusion/types.json +0 -0
  135. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/tests/data_type_api.rs +0 -0
  136. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/tests/deep_nesting_regression.rs +0 -0
  137. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/tests/error_handling.rs +0 -0
  138. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/tests/fabric_tpch_regression.rs +0 -0
  139. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/tests/identity_roundtrip.rs +0 -0
  140. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/tests/oracle_data_types_regression.rs +0 -0
  141. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/tests/postgres_explain_options.rs +0 -0
  142. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/tests/postgres_regexp_clickhouse.rs +0 -0
  143. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/tests/postgres_sqlite_regression.rs +0 -0
  144. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/tests/query_analysis_regression.rs +0 -0
  145. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/tests/snowflake_regression_test.rs +0 -0
  146. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/tests/sqlglot_compat.rs +0 -0
  147. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/tests/sqlglot_dialect_identity.rs +0 -0
  148. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/tests/sqlglot_identity.rs +0 -0
  149. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/tests/sqlglot_identity_detailed.rs +0 -0
  150. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/tests/sqlglot_parser.rs +0 -0
  151. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/tests/sqlglot_pretty.rs +0 -0
  152. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/tests/sqlglot_transpilation.rs +0 -0
  153. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/tests/sqlglot_transpile.rs +0 -0
  154. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/tests/tpch_transpile_stack.rs +0 -0
  155. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql/tests/transform_regression.rs +0 -0
  156. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql-ast-derive/Cargo.toml +0 -0
  157. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql-function-catalogs/Cargo.toml +0 -0
  158. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql-function-catalogs/README.md +0 -0
  159. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql-function-catalogs/src/clickhouse.rs +0 -0
  160. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql-function-catalogs/src/duckdb.rs +0 -0
  161. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql-function-catalogs/src/lib.rs +0 -0
  162. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql-function-catalogs/tools/clickhouse/extract_functions.py +0 -0
  163. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql-function-catalogs/tools/duckdb/extract_functions.py +0 -0
  164. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql-python/Cargo.toml +0 -0
  165. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql-python/README.md +0 -0
  166. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql-python/docs/api.md +0 -0
  167. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql-python/docs/index.md +0 -0
  168. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql-python/mkdocs.yml +0 -0
  169. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql-python/src/annotate_types.rs +0 -0
  170. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql-python/src/builders.rs +0 -0
  171. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql-python/src/dialects.rs +0 -0
  172. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql-python/src/diff.rs +0 -0
  173. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql-python/src/errors.rs +0 -0
  174. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql-python/src/expr.rs +0 -0
  175. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql-python/src/expr_types.rs +0 -0
  176. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql-python/src/format.rs +0 -0
  177. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql-python/src/generate.rs +0 -0
  178. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql-python/src/helpers.rs +0 -0
  179. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql-python/src/lib.rs +0 -0
  180. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql-python/src/lineage.rs +0 -0
  181. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql-python/src/openlineage.rs +0 -0
  182. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql-python/src/optimize.rs +0 -0
  183. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql-python/src/parse.rs +0 -0
  184. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql-python/src/query_analysis.rs +0 -0
  185. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql-python/src/tokenize.rs +0 -0
  186. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql-python/src/transforms.rs +0 -0
  187. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql-python/src/transpile.rs +0 -0
  188. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql-python/src/types.rs +0 -0
  189. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql-python/src/validate.rs +0 -0
  190. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql-python/tests/conftest.py +0 -0
  191. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql-python/tests/test_builders.py +0 -0
  192. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql-python/tests/test_compat.py +0 -0
  193. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql-python/tests/test_dialects.py +0 -0
  194. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql-python/tests/test_diff.py +0 -0
  195. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql-python/tests/test_expression.py +0 -0
  196. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql-python/tests/test_format.py +0 -0
  197. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql-python/tests/test_generate.py +0 -0
  198. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql-python/tests/test_optimize.py +0 -0
  199. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql-python/tests/test_parse.py +0 -0
  200. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql-python/tests/test_query_analysis.py +0 -0
  201. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql-python/tests/test_transforms.py +0 -0
  202. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql-python/tests/test_transpile.py +0 -0
  203. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql-python/tests/test_validate.py +0 -0
  204. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/crates/polyglot-sql-python/uv.lock +0 -0
  205. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/pyproject.toml +0 -0
  206. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/python/polyglot_sql/__init__.py +0 -0
  207. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/python/polyglot_sql/__init__.pyi +0 -0
  208. {polyglot_sql-0.9.0 → polyglot_sql-0.9.2}/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.0"
608
+ version = "0.9.2"
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.0"
626
+ version = "0.9.2"
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.0"
635
+ version = "0.9.2"
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.0"
645
+ version = "0.9.2"
646
646
 
647
647
  [[package]]
648
648
  name = "polyglot-sql-python"
649
- version = "0.9.0"
649
+ version = "0.9.2"
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.0"
660
+ version = "0.9.2"
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.0"
9
+ version = "0.9.2"
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.0
3
+ Version: 0.9.2
4
4
  Classifier: Development Status :: 4 - Beta
5
5
  Classifier: Intended Audience :: Developers
6
6
  Classifier: License :: OSI Approved :: MIT License
@@ -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.0" }
103
+ polyglot-sql-ast-derive = { path = "../polyglot-sql-ast-derive", version = "0.9.2" }
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.0", optional = true, default-features = false }
110
+ polyglot-sql-function-catalogs = { path = "../polyglot-sql-function-catalogs", version = "0.9.2", 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.0", default-features = false }
28
+ polyglot-sql = { version = "0.9.2", default-features = false }
29
29
  ```
30
30
 
31
31
  ```toml
@@ -11,7 +11,7 @@ use std::collections::{HashMap, HashSet};
11
11
 
12
12
  use crate::builder::engine;
13
13
  use crate::expressions::*;
14
- use crate::traversal::ExpressionWalk;
14
+ use crate::traversal::{is_aggregate, ExpressionWalk};
15
15
 
16
16
  /// Apply a bottom-up transformation to every node in the tree.
17
17
  /// Wraps `crate::traversal::transform` with a simpler signature for this module.
@@ -336,6 +336,26 @@ pub fn get_output_column_names(expr: &Expression) -> Vec<String> {
336
336
  output_column_names_from_query(expr)
337
337
  }
338
338
 
339
+ /// Collect projected output column names using dialect-specific set-operation
340
+ /// alignment rules.
341
+ ///
342
+ /// This differs from [`get_output_column_names`] only for name-aligned set
343
+ /// operations. When an output shape is not statically knowable (for example an
344
+ /// unresolved wildcard), it preserves the existing leftmost-branch behavior.
345
+ pub fn get_output_column_names_for_dialect(
346
+ expr: &Expression,
347
+ dialect: Option<crate::dialects::DialectType>,
348
+ ) -> Vec<String> {
349
+ crate::set_operation::query_output_identifiers(expr, dialect)
350
+ .map(|identifiers| {
351
+ identifiers
352
+ .into_iter()
353
+ .map(|identifier| identifier.name)
354
+ .collect()
355
+ })
356
+ .unwrap_or_else(|_| output_column_names_from_query(expr))
357
+ }
358
+
339
359
  fn output_column_names_from_query(expr: &Expression) -> Vec<String> {
340
360
  match expr {
341
361
  Expression::Select(select) => select_output_column_names(select),
@@ -540,22 +560,7 @@ pub fn get_subqueries(expr: &Expression) -> Vec<&Expression> {
540
560
  /// Includes typed aggregates (`Count`, `Sum`, `Avg`, `Min`, `Max`, etc.)
541
561
  /// and generic `AggregateFunction` nodes.
542
562
  pub fn get_aggregate_functions(expr: &Expression) -> Vec<&Expression> {
543
- expr.find_all(|e| {
544
- matches!(
545
- e,
546
- Expression::AggregateFunction(_)
547
- | Expression::Count(_)
548
- | Expression::Sum(_)
549
- | Expression::Avg(_)
550
- | Expression::Min(_)
551
- | Expression::Max(_)
552
- | Expression::ApproxDistinct(_)
553
- | Expression::ArrayAgg(_)
554
- | Expression::GroupConcat(_)
555
- | Expression::StringAgg(_)
556
- | Expression::ListAgg(_)
557
- )
558
- })
563
+ expr.find_all(is_aggregate)
559
564
  }
560
565
 
561
566
  /// Collect all window function nodes in the expression tree.
@@ -695,6 +700,37 @@ mod tests {
695
700
  assert_eq!(names, vec!["c1".to_string(), "c2".to_string()]);
696
701
  }
697
702
 
703
+ #[test]
704
+ fn test_get_output_column_names_uses_dialect_by_name_layout() {
705
+ for dialect in [
706
+ crate::dialects::DialectType::DuckDB,
707
+ crate::dialects::DialectType::Snowflake,
708
+ ] {
709
+ let expr = crate::parse_one(
710
+ "SELECT 1 AS left_value UNION ALL BY NAME SELECT 2 AS right_value",
711
+ dialect,
712
+ )
713
+ .expect("parse");
714
+ assert_eq!(
715
+ get_output_column_names_for_dialect(&expr, Some(dialect)),
716
+ vec!["left_value", "right_value"]
717
+ );
718
+ }
719
+
720
+ let expr = crate::parse_one(
721
+ "SELECT 1 AS a, 2 AS b UNION ALL BY NAME SELECT 3 AS b, 4 AS a",
722
+ crate::dialects::DialectType::BigQuery,
723
+ )
724
+ .expect("parse");
725
+ assert_eq!(
726
+ get_output_column_names_for_dialect(
727
+ &expr,
728
+ Some(crate::dialects::DialectType::BigQuery),
729
+ ),
730
+ vec!["a", "b"]
731
+ );
732
+ }
733
+
698
734
  #[test]
699
735
  fn test_get_column_names_union_still_returns_all_references() {
700
736
  let expr =
@@ -851,12 +887,35 @@ mod tests {
851
887
 
852
888
  #[test]
853
889
  fn test_get_aggregate_functions() {
854
- let expr = parse_one("SELECT COUNT(*), SUM(x) FROM t");
890
+ let expr = crate::parse_one(
891
+ "SELECT COUNT_IF(numeric_value > 0), MEDIAN(numeric_value), FIRST(numeric_value) FROM source_table",
892
+ crate::dialects::DialectType::DuckDB,
893
+ )
894
+ .unwrap();
855
895
  let aggs = get_aggregate_functions(&expr);
856
- assert!(
857
- aggs.len() >= 2,
858
- "Expected at least 2 aggregates, got {}",
859
- aggs.len()
860
- );
896
+ let aggregate_types: Vec<_> = aggs.iter().map(|agg| agg.variant_name()).collect();
897
+
898
+ assert_eq!(aggregate_types, vec!["count_if", "median", "first"]);
899
+ }
900
+
901
+ #[test]
902
+ fn test_get_duckdb_null_preserving_arg_extrema() {
903
+ let expr = crate::parse_one(
904
+ "SELECT ARG_MAX_NULL(label, score), ARG_MIN_NULL(label, score) FROM source_table",
905
+ crate::dialects::DialectType::DuckDB,
906
+ )
907
+ .unwrap();
908
+ let aggregates = get_aggregate_functions(&expr);
909
+
910
+ assert_eq!(aggregates.len(), 2);
911
+ for (aggregate, expected_name) in
912
+ aggregates.into_iter().zip(["ARG_MAX_NULL", "ARG_MIN_NULL"])
913
+ {
914
+ let Expression::AggregateFunction(function) = aggregate else {
915
+ panic!("expected a generic aggregate node, got {aggregate:?}");
916
+ };
917
+ assert_eq!(function.name, expected_name);
918
+ assert_eq!(function.args.len(), 2);
919
+ }
861
920
  }
862
921
  }
@@ -186,6 +186,7 @@ pub fn col(name: &str) -> Expr {
186
186
  expr = Expression::Dot(Box::new(DotAccess {
187
187
  this: expr,
188
188
  field: builder_identifier(field),
189
+ inferred_type: None,
189
190
  }));
190
191
  }
191
192
 
@@ -2783,6 +2784,27 @@ mod tests {
2783
2784
  assert_eq!(sql, "SELECT price * quantity AS total FROM items");
2784
2785
  }
2785
2786
 
2787
+ #[test]
2788
+ fn test_nested_operator_grouping() {
2789
+ assert_eq!(
2790
+ or(col("a").eq(lit(1)), col("b").eq(lit(2)))
2791
+ .and(col("c").eq(lit(3)))
2792
+ .to_sql(),
2793
+ "(a = 1 OR b = 2) AND c = 3"
2794
+ );
2795
+ assert_eq!(
2796
+ col("a")
2797
+ .eq(lit(1))
2798
+ .and(or(col("b").eq(lit(2)), col("c").eq(lit(3))))
2799
+ .to_sql(),
2800
+ "a = 1 AND (b = 2 OR c = 3)"
2801
+ );
2802
+ assert_eq!(col("a").add(col("b")).mul(col("c")).to_sql(), "(a + b) * c");
2803
+ assert_eq!(col("a").mul(col("b").add(col("c"))).to_sql(), "a * (b + c)");
2804
+ assert_eq!(col("a").sub(col("b").sub(col("c"))).to_sql(), "a - (b - c)");
2805
+ assert_eq!(col("a").div(col("b").div(col("c"))).to_sql(), "a / (b / c)");
2806
+ }
2807
+
2786
2808
  #[test]
2787
2809
  fn test_cast() {
2788
2810
  let sql = select([col("id").cast("VARCHAR")]).from("users").to_sql();
@@ -6120,14 +6120,12 @@ impl DuckDBDialect {
6120
6120
  trailing_comments: Vec::new(),
6121
6121
  inferred_type: None,
6122
6122
  }));
6123
- let two_pi_u2 = Expression::Mul(Box::new(BinaryOp {
6124
- left: two_pi,
6125
- right: u2,
6126
- left_comments: Vec::new(),
6127
- operator_comments: Vec::new(),
6128
- trailing_comments: Vec::new(),
6129
- inferred_type: None,
6130
- }));
6123
+ let two_pi_u2 = if let Expression::Div(div) = u2 {
6124
+ let numerator = Expression::Mul(Box::new(BinaryOp::new(two_pi, div.left)));
6125
+ Expression::Div(Box::new(BinaryOp::new(numerator, div.right)))
6126
+ } else {
6127
+ Expression::Mul(Box::new(BinaryOp::new(two_pi, u2)))
6128
+ };
6131
6129
  let cos_part = Expression::Function(Box::new(Function::new(
6132
6130
  "COS".to_string(),
6133
6131
  vec![two_pi_u2],
@@ -6328,6 +6326,7 @@ impl DuckDBDialect {
6328
6326
  let x_value = Expression::Dot(Box::new(crate::expressions::DotAccess {
6329
6327
  this: x_ref,
6330
6328
  field: Identifier::new("value"),
6329
+ inferred_type: None,
6331
6330
  }));
6332
6331
  let x_value_is_null = Expression::IsNull(Box::new(crate::expressions::IsNull {
6333
6332
  this: x_value,
@@ -7212,6 +7211,24 @@ impl DuckDBDialect {
7212
7211
  ) -> Result<Expression> {
7213
7212
  let name_upper = f.name.to_uppercase();
7214
7213
  match name_upper.as_str() {
7214
+ // Keep the established canonical transpilation for a plain DuckDB
7215
+ // LIST aggregate now that the parser represents it as an aggregate
7216
+ // node. Modifier-bearing LIST calls retain their aggregate shape so
7217
+ // DISTINCT, ORDER BY, FILTER, and LIMIT are not discarded.
7218
+ "LIST"
7219
+ if f.args.len() == 1
7220
+ && !f.distinct
7221
+ && f.filter.is_none()
7222
+ && f.order_by.is_empty()
7223
+ && f.limit.is_none()
7224
+ && f.ignore_nulls.is_none() =>
7225
+ {
7226
+ Ok(Expression::Function(Box::new(Function::new(
7227
+ "ARRAY_AGG".to_string(),
7228
+ f.args,
7229
+ ))))
7230
+ }
7231
+
7215
7232
  // GROUP_CONCAT -> LISTAGG
7216
7233
  "GROUP_CONCAT" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
7217
7234
  Function::new("LISTAGG".to_string(), f.args),
@@ -188,7 +188,7 @@ use crate::parser::Parser;
188
188
  use crate::tokens::TokenType;
189
189
  use crate::tokens::{Token, Tokenizer, TokenizerConfig};
190
190
  #[cfg(feature = "transpile")]
191
- use crate::traversal::ExpressionWalk;
191
+ use crate::traversal::{is_aggregate, ExpressionWalk};
192
192
  use serde::{Deserialize, Serialize};
193
193
  use std::collections::HashMap;
194
194
  #[cfg(feature = "transpile")]
@@ -4561,6 +4561,12 @@ impl Dialect {
4561
4561
  "qualified whole-row aggregate arguments",
4562
4562
  );
4563
4563
  }
4564
+ if Self::node_has_subquery_in_aggregate_argument(node) {
4565
+ Self::push_unsupported_diagnostic(
4566
+ &mut diagnostics,
4567
+ "aggregate arguments containing subqueries",
4568
+ );
4569
+ }
4564
4570
  }
4565
4571
 
4566
4572
  if !Self::target_supports_distinct_on(target) && Self::node_has_distinct_on(node) {
@@ -5368,63 +5374,7 @@ impl Dialect {
5368
5374
  }
5369
5375
 
5370
5376
  fn node_is_aggregate_function(expr: &Expression) -> bool {
5371
- matches!(
5372
- expr,
5373
- Expression::AggregateFunction(_)
5374
- | Expression::Count(_)
5375
- | Expression::Sum(_)
5376
- | Expression::Avg(_)
5377
- | Expression::Min(_)
5378
- | Expression::Max(_)
5379
- | Expression::GroupConcat(_)
5380
- | Expression::StringAgg(_)
5381
- | Expression::ListAgg(_)
5382
- | Expression::ArrayAgg(_)
5383
- | Expression::CountIf(_)
5384
- | Expression::SumIf(_)
5385
- | Expression::Stddev(_)
5386
- | Expression::StddevPop(_)
5387
- | Expression::StddevSamp(_)
5388
- | Expression::Variance(_)
5389
- | Expression::VarPop(_)
5390
- | Expression::VarSamp(_)
5391
- | Expression::Median(_)
5392
- | Expression::Mode(_)
5393
- | Expression::First(_)
5394
- | Expression::Last(_)
5395
- | Expression::AnyValue(_)
5396
- | Expression::ApproxDistinct(_)
5397
- | Expression::ApproxCountDistinct(_)
5398
- | Expression::ApproxPercentile(_)
5399
- | Expression::Percentile(_)
5400
- | Expression::LogicalAnd(_)
5401
- | Expression::LogicalOr(_)
5402
- | Expression::Skewness(_)
5403
- | Expression::BitwiseCount(_)
5404
- | Expression::BitwiseAndAgg(_)
5405
- | Expression::BitwiseOrAgg(_)
5406
- | Expression::BitwiseXorAgg(_)
5407
- | Expression::ArrayConcatAgg(_)
5408
- | Expression::ArrayUniqueAgg(_)
5409
- | Expression::BoolXorAgg(_)
5410
- | Expression::JsonArrayAgg(_)
5411
- | Expression::JsonObjectAgg(_)
5412
- | Expression::ParameterizedAgg(_)
5413
- | Expression::ArgMax(_)
5414
- | Expression::ArgMin(_)
5415
- | Expression::ApproxTopK(_)
5416
- | Expression::ApproxTopKAccumulate(_)
5417
- | Expression::ApproxTopKCombine(_)
5418
- | Expression::ApproxTopKEstimate(_)
5419
- | Expression::ApproxTopSum(_)
5420
- | Expression::ApproxQuantiles(_)
5421
- | Expression::AnonymousAggFunc(_)
5422
- | Expression::CombinedAggFunc(_)
5423
- | Expression::CombinedParameterizedAgg(_)
5424
- | Expression::HashAgg(_)
5425
- | Expression::ObjectAgg(_)
5426
- | Expression::AIAgg(_)
5427
- )
5377
+ is_aggregate(expr)
5428
5378
  }
5429
5379
 
5430
5380
  fn node_has_qualified_whole_row_aggregate_argument(expr: &Expression) -> bool {
@@ -5446,6 +5396,21 @@ impl Dialect {
5446
5396
  && expr.children().into_iter().any(contains_qualified_star)
5447
5397
  }
5448
5398
 
5399
+ fn node_has_subquery_in_aggregate_argument(expr: &Expression) -> bool {
5400
+ fn contains_query(expr: &Expression) -> bool {
5401
+ matches!(
5402
+ expr,
5403
+ Expression::Select(_)
5404
+ | Expression::Subquery(_)
5405
+ | Expression::Union(_)
5406
+ | Expression::Intersect(_)
5407
+ | Expression::Except(_)
5408
+ ) || expr.children().into_iter().any(contains_query)
5409
+ }
5410
+
5411
+ Self::node_is_aggregate_function(expr) && expr.children().into_iter().any(contains_query)
5412
+ }
5413
+
5449
5414
  fn tsql_apply_has_invalid_outer_aggregate(expr: &Expression) -> bool {
5450
5415
  // SQL Server error 8124: if an aggregate expression contains an outer
5451
5416
  // reference, that reference must be the only column used by the expression.
@@ -32,6 +32,7 @@ pub(super) enum Action {
32
32
  CollectListToArrayAgg,
33
33
  CollectSetConvert,
34
34
  PercentileConvert,
35
+ DuckDBQuantileConvert,
35
36
  CorrIsnanWrap,
36
37
  FirstToAnyValue,
37
38
  PercentileContConvert,
@@ -191,10 +192,16 @@ pub(super) fn rewrite(
191
192
  } else {
192
193
  "ARG_MIN_NULL"
193
194
  };
194
- Ok(Expression::Function(Box::new(Function::new(
195
- func_name.to_string(),
196
- vec![agg.this, *having_expr],
197
- ))))
195
+ Ok(Expression::AggregateFunction(Box::new(AggregateFunction {
196
+ name: func_name.to_string(),
197
+ args: vec![agg.this, *having_expr],
198
+ distinct: agg.distinct,
199
+ filter: agg.filter,
200
+ order_by: agg.order_by,
201
+ limit: agg.limit,
202
+ ignore_nulls: agg.ignore_nulls,
203
+ inferred_type: agg.inferred_type,
204
+ })))
198
205
  } else {
199
206
  Ok(Expression::AnyValue(agg))
200
207
  }
@@ -247,11 +254,10 @@ pub(super) fn rewrite(
247
254
  expressions: quantiles,
248
255
  }));
249
256
 
250
- // Preserve DISTINCT modifier
251
- let mut new_func =
252
- Function::new("APPROX_QUANTILE".to_string(), vec![x_expr, array_expr]);
253
- new_func.distinct = agg.distinct;
254
- Ok(Expression::Function(Box::new(new_func)))
257
+ let mut new_agg = *agg;
258
+ new_agg.name = "APPROX_QUANTILE".to_string();
259
+ new_agg.args = vec![x_expr, array_expr];
260
+ Ok(Expression::AggregateFunction(Box::new(new_agg)))
255
261
  } else {
256
262
  Ok(Expression::AggregateFunction(agg))
257
263
  }
@@ -1146,6 +1152,80 @@ pub(super) fn rewrite(
1146
1152
  }
1147
1153
  }
1148
1154
 
1155
+ Action::DuckDBQuantileConvert => {
1156
+ let mut aggregate = if let Expression::AggregateFunction(aggregate) = e {
1157
+ *aggregate
1158
+ } else {
1159
+ unreachable!("action only triggered for AggregateFunction expressions")
1160
+ };
1161
+ let name = aggregate.name.to_ascii_uppercase();
1162
+
1163
+ match name.as_str() {
1164
+ "QUANTILE" => {
1165
+ aggregate.name = match target {
1166
+ DialectType::Spark | DialectType::Databricks | DialectType::Hive => {
1167
+ "PERCENTILE"
1168
+ }
1169
+ DialectType::Presto | DialectType::Trino => "APPROX_PERCENTILE",
1170
+ DialectType::BigQuery => "PERCENTILE_CONT",
1171
+ _ => "QUANTILE",
1172
+ }
1173
+ .to_string();
1174
+ Ok(Expression::AggregateFunction(Box::new(aggregate)))
1175
+ }
1176
+ "APPROX_QUANTILE" => {
1177
+ if matches!(target, DialectType::Snowflake) {
1178
+ aggregate.name = "APPROX_PERCENTILE".to_string();
1179
+ }
1180
+ Ok(Expression::AggregateFunction(Box::new(aggregate)))
1181
+ }
1182
+ "QUANTILE_CONT" | "QUANTILE_DISC"
1183
+ if aggregate.args.len() == 2
1184
+ && matches!(
1185
+ target,
1186
+ DialectType::PostgreSQL
1187
+ | DialectType::Redshift
1188
+ | DialectType::Snowflake
1189
+ ) =>
1190
+ {
1191
+ // DISTINCT, an inner ORDER BY, LIMIT, and explicit null
1192
+ // handling cannot be represented by these targets' ordered-set
1193
+ // aggregate syntax. Keep the original aggregate intact rather
1194
+ // than silently dropping any of those modifiers.
1195
+ if aggregate.distinct
1196
+ || !aggregate.order_by.is_empty()
1197
+ || aggregate.limit.is_some()
1198
+ || aggregate.ignore_nulls.is_some()
1199
+ {
1200
+ return Ok(Expression::AggregateFunction(Box::new(aggregate)));
1201
+ }
1202
+
1203
+ let mut args = aggregate.args;
1204
+ let column = args.remove(0);
1205
+ let percentile = args.remove(0);
1206
+ let percentile = PercentileFunc {
1207
+ this: column.clone(),
1208
+ percentile,
1209
+ order_by: Some(vec![Ordered {
1210
+ this: column,
1211
+ desc: false,
1212
+ nulls_first: None,
1213
+ explicit_asc: false,
1214
+ with_fill: None,
1215
+ }]),
1216
+ filter: aggregate.filter,
1217
+ };
1218
+
1219
+ if name == "QUANTILE_CONT" {
1220
+ Ok(Expression::PercentileCont(Box::new(percentile)))
1221
+ } else {
1222
+ Ok(Expression::PercentileDisc(Box::new(percentile)))
1223
+ }
1224
+ }
1225
+ _ => Ok(Expression::AggregateFunction(Box::new(aggregate))),
1226
+ }
1227
+ }
1228
+
1149
1229
  Action::CorrIsnanWrap => {
1150
1230
  // CORR(a, b) -> CASE WHEN ISNAN(CORR(a, b)) THEN NULL ELSE CORR(a, b) END
1151
1231
  // The CORR expression could be AggregateFunction, WindowFunction, or Filter-wrapped
@@ -2294,6 +2294,11 @@ pub(super) fn normalize(
2294
2294
  {
2295
2295
  Action::Aggregates(aggregates::Action::BigQueryPercentileContToDuckDB)
2296
2296
  }
2297
+ "QUANTILE" | "QUANTILE_CONT" | "QUANTILE_DISC" | "APPROX_QUANTILE"
2298
+ if matches!(source, DialectType::DuckDB) =>
2299
+ {
2300
+ Action::Aggregates(aggregates::Action::DuckDBQuantileConvert)
2301
+ }
2297
2302
  _ => Action::None,
2298
2303
  }
2299
2304
  }
@@ -1418,26 +1418,23 @@ pub(super) fn rewrite(
1418
1418
  ],
1419
1419
  )));
1420
1420
 
1421
- // Position offset: pos - 1 when pos > 1, else 0
1422
- let pos_offset: Expression = if !is_pos_1 {
1421
+ // ELSE base: 1 + split_sum + extract_sum
1422
+ let else_base = Expression::Add(Box::new(BinaryOp::new(
1423
+ Expression::Add(Box::new(BinaryOp::new(Expression::number(1), split_sum))),
1424
+ extract_sum,
1425
+ )));
1426
+
1427
+ // Append the position offset as a left-associated `+ pos - 1` chain.
1428
+ let else_expr = if !is_pos_1 {
1423
1429
  let pos = position.clone().unwrap_or(Expression::number(1));
1424
- Expression::Sub(Box::new(BinaryOp::new(pos, Expression::number(1))))
1430
+ Expression::Sub(Box::new(BinaryOp::new(
1431
+ Expression::Add(Box::new(BinaryOp::new(else_base, pos))),
1432
+ Expression::number(1),
1433
+ )))
1425
1434
  } else {
1426
- Expression::number(0)
1435
+ Expression::Add(Box::new(BinaryOp::new(else_base, Expression::number(0))))
1427
1436
  };
1428
1437
 
1429
- // ELSE: 1 + split_sum + extract_sum + pos_offset
1430
- let else_expr = Expression::Add(Box::new(BinaryOp::new(
1431
- Expression::Add(Box::new(BinaryOp::new(
1432
- Expression::Add(Box::new(BinaryOp::new(
1433
- Expression::number(1),
1434
- split_sum,
1435
- ))),
1436
- extract_sum,
1437
- ))),
1438
- pos_offset,
1439
- )));
1440
-
1441
1438
  Ok(Expression::Case(Box::new(Case {
1442
1439
  operand: None,
1443
1440
  whens: vec![