polyglot-sql 0.6.3__tar.gz → 0.7.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 (204) hide show
  1. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/Cargo.lock +6 -6
  2. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/Cargo.toml +1 -1
  3. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/PKG-INFO +7 -1
  4. {polyglot_sql-0.6.3/crates/polyglot-sql-python → polyglot_sql-0.7.0}/README.md +6 -0
  5. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/Cargo.toml +2 -2
  6. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/README.md +1 -1
  7. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/dialects/duckdb.rs +9 -9
  8. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/dialects/mod.rs +15 -0
  9. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/dialects/normalization/aggregates.rs +67 -15
  10. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/dialects/normalization/collections.rs +5 -1
  11. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/dialects/normalization/mod.rs +234 -4
  12. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/dialects/normalization/scalar.rs +351 -57
  13. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/dialects/normalization/statements.rs +140 -0
  14. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/dialects/normalization/temporal.rs +18 -6
  15. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/dialects/oracle.rs +2 -0
  16. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/dialects/presto.rs +8 -8
  17. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/error.rs +69 -0
  18. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/expressions.rs +6 -0
  19. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/generator.rs +187 -44
  20. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/lib.rs +10 -1
  21. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/lineage.rs +639 -114
  22. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/parser.rs +355 -56
  23. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/schema.rs +32 -6
  24. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/tokens.rs +24 -12
  25. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0/crates/polyglot-sql-python}/README.md +6 -0
  26. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql-python/src/errors.rs +31 -1
  27. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql-python/src/lib.rs +4 -0
  28. polyglot_sql-0.7.0/crates/polyglot-sql-python/src/lineage.rs +222 -0
  29. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql-python/tests/test_lineage.py +36 -0
  30. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/python/polyglot_sql/__init__.py +10 -0
  31. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/python/polyglot_sql/__init__.pyi +39 -0
  32. polyglot_sql-0.6.3/crates/polyglot-sql-python/src/lineage.rs +0 -100
  33. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/benches/allocation_hotspots.rs +0 -0
  34. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/benches/ast_traversal.rs +0 -0
  35. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/benches/in_list.rs +0 -0
  36. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/benches/lineage.rs +0 -0
  37. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/benches/parsing.rs +0 -0
  38. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/benches/performance_hotspots.rs +0 -0
  39. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/benches/rust_parsing.rs +0 -0
  40. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/benches/transpile.rs +0 -0
  41. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/examples/basic_usage.rs +0 -0
  42. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/examples/bench_json.rs +0 -0
  43. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/ast_children.rs +0 -0
  44. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/ast_json.rs +0 -0
  45. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/ast_transforms.rs +0 -0
  46. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/builder.rs +0 -0
  47. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/dialects/athena.rs +0 -0
  48. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/dialects/bigquery.rs +0 -0
  49. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/dialects/clickhouse.rs +0 -0
  50. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/dialects/cockroachdb.rs +0 -0
  51. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/dialects/databricks.rs +0 -0
  52. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/dialects/datafusion.rs +0 -0
  53. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/dialects/doris.rs +0 -0
  54. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/dialects/dremio.rs +0 -0
  55. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/dialects/drill.rs +0 -0
  56. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/dialects/druid.rs +0 -0
  57. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/dialects/dune.rs +0 -0
  58. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/dialects/exasol.rs +0 -0
  59. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/dialects/fabric.rs +0 -0
  60. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/dialects/generic.rs +0 -0
  61. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/dialects/hive.rs +0 -0
  62. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/dialects/materialize.rs +0 -0
  63. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/dialects/mysql.rs +0 -0
  64. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/dialects/normalization/json.rs +0 -0
  65. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/dialects/normalization/operators.rs +0 -0
  66. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/dialects/normalization/postgres_interval.rs +0 -0
  67. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/dialects/normalization/types.rs +0 -0
  68. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/dialects/postgres.rs +0 -0
  69. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/dialects/redshift.rs +0 -0
  70. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/dialects/risingwave.rs +0 -0
  71. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/dialects/singlestore.rs +0 -0
  72. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/dialects/snowflake.rs +0 -0
  73. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/dialects/solr.rs +0 -0
  74. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/dialects/spark.rs +0 -0
  75. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/dialects/sqlite.rs +0 -0
  76. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/dialects/starrocks.rs +0 -0
  77. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/dialects/tableau.rs +0 -0
  78. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/dialects/teradata.rs +0 -0
  79. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/dialects/tidb.rs +0 -0
  80. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/dialects/trino.rs +0 -0
  81. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/dialects/tsql.rs +0 -0
  82. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/diff.rs +0 -0
  83. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/format_tokens.rs +0 -0
  84. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/function_catalog.rs +0 -0
  85. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/function_registry.rs +0 -0
  86. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/guard.rs +0 -0
  87. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/helper.rs +0 -0
  88. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/openlineage.rs +0 -0
  89. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/optimizer/annotate_types.rs +0 -0
  90. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/optimizer/canonicalize.rs +0 -0
  91. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/optimizer/eliminate_ctes.rs +0 -0
  92. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/optimizer/eliminate_joins.rs +0 -0
  93. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/optimizer/isolate_table_selects.rs +0 -0
  94. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/optimizer/mod.rs +0 -0
  95. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/optimizer/normalize.rs +0 -0
  96. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/optimizer/normalize_identifiers.rs +0 -0
  97. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/optimizer/optimize_joins.rs +0 -0
  98. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/optimizer/optimizer.rs +0 -0
  99. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/optimizer/pushdown_predicates.rs +0 -0
  100. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/optimizer/pushdown_projections.rs +0 -0
  101. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/optimizer/qualify_columns.rs +0 -0
  102. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/optimizer/qualify_tables.rs +0 -0
  103. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/optimizer/simplify.rs +0 -0
  104. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/optimizer/subquery.rs +0 -0
  105. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/planner.rs +0 -0
  106. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/query_analysis.rs +0 -0
  107. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/resolver.rs +0 -0
  108. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/scope.rs +0 -0
  109. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/time.rs +0 -0
  110. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/transforms.rs +0 -0
  111. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/traversal.rs +0 -0
  112. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/trie.rs +0 -0
  113. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/validation/tests.rs +0 -0
  114. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/src/validation.rs +0 -0
  115. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/tests/analyze_failures.rs +0 -0
  116. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/tests/clickhouse_regression.rs +0 -0
  117. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/tests/common/known_failures.rs +0 -0
  118. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/tests/common/mod.rs +0 -0
  119. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/tests/common/test_data.rs +0 -0
  120. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/tests/common/test_runner.rs +0 -0
  121. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/tests/create_view_security_comment_regression.rs +0 -0
  122. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/tests/custom_clickhouse_coverage.rs +0 -0
  123. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/tests/custom_clickhouse_parser.rs +0 -0
  124. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/tests/custom_dialect.rs +0 -0
  125. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/tests/custom_dialect_tests.rs +0 -0
  126. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/tests/custom_fixtures/datafusion/ddl.json +0 -0
  127. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/tests/custom_fixtures/datafusion/dml.json +0 -0
  128. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/tests/custom_fixtures/datafusion/functions.json +0 -0
  129. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/tests/custom_fixtures/datafusion/identity.json +0 -0
  130. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/tests/custom_fixtures/datafusion/operators.json +0 -0
  131. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/tests/custom_fixtures/datafusion/select.json +0 -0
  132. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/tests/custom_fixtures/datafusion/transpilation.json +0 -0
  133. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/tests/custom_fixtures/datafusion/types.json +0 -0
  134. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/tests/data_type_api.rs +0 -0
  135. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/tests/deep_nesting_regression.rs +0 -0
  136. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/tests/dialect_matrix.rs +0 -0
  137. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/tests/error_handling.rs +0 -0
  138. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/tests/fabric_regression.rs +0 -0
  139. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/tests/fabric_tpch_regression.rs +0 -0
  140. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/tests/identity_roundtrip.rs +0 -0
  141. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/tests/oracle_data_types_regression.rs +0 -0
  142. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/tests/postgres_explain_options.rs +0 -0
  143. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/tests/postgres_regexp_clickhouse.rs +0 -0
  144. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/tests/postgres_sqlite_regression.rs +0 -0
  145. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/tests/query_analysis.rs +0 -0
  146. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/tests/query_analysis_regression.rs +0 -0
  147. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/tests/snowflake_regression_test.rs +0 -0
  148. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/tests/sqlglot_compat.rs +0 -0
  149. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/tests/sqlglot_dialect_identity.rs +0 -0
  150. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/tests/sqlglot_identity.rs +0 -0
  151. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/tests/sqlglot_identity_detailed.rs +0 -0
  152. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/tests/sqlglot_parser.rs +0 -0
  153. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/tests/sqlglot_pretty.rs +0 -0
  154. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/tests/sqlglot_transpilation.rs +0 -0
  155. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/tests/sqlglot_transpile.rs +0 -0
  156. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/tests/tpch_transpile_stack.rs +0 -0
  157. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/tests/transform_regression.rs +0 -0
  158. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql/tests/tsql_regression.rs +0 -0
  159. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql-ast-derive/Cargo.toml +0 -0
  160. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql-ast-derive/src/lib.rs +0 -0
  161. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql-function-catalogs/Cargo.toml +0 -0
  162. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql-function-catalogs/README.md +0 -0
  163. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql-function-catalogs/src/clickhouse.rs +0 -0
  164. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql-function-catalogs/src/duckdb.rs +0 -0
  165. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql-function-catalogs/src/lib.rs +0 -0
  166. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql-function-catalogs/tools/clickhouse/extract_functions.py +0 -0
  167. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql-function-catalogs/tools/duckdb/extract_functions.py +0 -0
  168. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql-python/Cargo.toml +0 -0
  169. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql-python/docs/api.md +0 -0
  170. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql-python/docs/index.md +0 -0
  171. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql-python/mkdocs.yml +0 -0
  172. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql-python/src/annotate_types.rs +0 -0
  173. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql-python/src/dialects.rs +0 -0
  174. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql-python/src/diff.rs +0 -0
  175. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql-python/src/expr.rs +0 -0
  176. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql-python/src/expr_types.rs +0 -0
  177. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql-python/src/format.rs +0 -0
  178. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql-python/src/generate.rs +0 -0
  179. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql-python/src/helpers.rs +0 -0
  180. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql-python/src/openlineage.rs +0 -0
  181. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql-python/src/optimize.rs +0 -0
  182. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql-python/src/parse.rs +0 -0
  183. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql-python/src/query_analysis.rs +0 -0
  184. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql-python/src/tokenize.rs +0 -0
  185. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql-python/src/transforms.rs +0 -0
  186. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql-python/src/transpile.rs +0 -0
  187. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql-python/src/types.rs +0 -0
  188. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql-python/src/validate.rs +0 -0
  189. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql-python/tests/conftest.py +0 -0
  190. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql-python/tests/test_compat.py +0 -0
  191. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql-python/tests/test_dialects.py +0 -0
  192. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql-python/tests/test_diff.py +0 -0
  193. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql-python/tests/test_expression.py +0 -0
  194. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql-python/tests/test_format.py +0 -0
  195. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql-python/tests/test_generate.py +0 -0
  196. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql-python/tests/test_optimize.py +0 -0
  197. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql-python/tests/test_parse.py +0 -0
  198. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql-python/tests/test_query_analysis.py +0 -0
  199. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql-python/tests/test_transforms.py +0 -0
  200. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql-python/tests/test_transpile.py +0 -0
  201. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql-python/tests/test_validate.py +0 -0
  202. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/crates/polyglot-sql-python/uv.lock +0 -0
  203. {polyglot_sql-0.6.3 → polyglot_sql-0.7.0}/pyproject.toml +0 -0
  204. {polyglot_sql-0.6.3 → polyglot_sql-0.7.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.6.3"
608
+ version = "0.7.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.6.3"
626
+ version = "0.7.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.6.3"
635
+ version = "0.7.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.6.3"
645
+ version = "0.7.0"
646
646
 
647
647
  [[package]]
648
648
  name = "polyglot-sql-python"
649
- version = "0.6.3"
649
+ version = "0.7.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.6.3"
660
+ version = "0.7.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.6.3"
9
+ version = "0.7.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.6.3
3
+ Version: 0.7.0
4
4
  Classifier: Development Status :: 4 - Beta
5
5
  Classifier: Intended Audience :: Developers
6
6
  Classifier: License :: OSI Approved :: MIT License
@@ -222,6 +222,11 @@ All functions are exported from `polyglot_sql`.
222
222
  - `validate(sql: str, dialect: str = "generic", *, strict_syntax: bool = False, semantic: bool = False) -> ValidationResult`
223
223
  - `optimize(sql: str, dialect: str = "generic") -> str`
224
224
  - `lineage(column: str, sql: str, dialect: str = "generic") -> dict`
225
+ - `lineage_at(ordinal: int, sql: str, dialect: str = "generic") -> dict`
226
+ - `lineage_at_with_schema(ordinal: int, sql: str, schema: dict, dialect: str = "generic") -> dict`
227
+ - `lineage_with_schema(column: str, sql: str, schema: dict, dialect: str = "generic") -> dict`
228
+ - `output_columns(sql: str, dialect: str = "generic") -> dict`
229
+ - `output_columns_with_schema(sql: str, schema: dict, dialect: str = "generic") -> dict`
225
230
  - `source_tables(column: str, sql: str, dialect: str = "generic") -> list[str]`
226
231
  - `analyze_query(sql: str, options: dict | None = None, dialect: str = "generic") -> dict`
227
232
  - `openlineage_column_lineage(sql: str, options: dict) -> dict`
@@ -246,6 +251,7 @@ Exception hierarchy:
246
251
  - `GenerateError`
247
252
  - `TranspileError`
248
253
  - `ValidationError`
254
+ - `ColumnResolutionError` (`reason`, `column`, and `ordinal` attributes)
249
255
 
250
256
  Unknown dialect names raise built-in `ValueError`.
251
257
 
@@ -195,6 +195,11 @@ All functions are exported from `polyglot_sql`.
195
195
  - `validate(sql: str, dialect: str = "generic", *, strict_syntax: bool = False, semantic: bool = False) -> ValidationResult`
196
196
  - `optimize(sql: str, dialect: str = "generic") -> str`
197
197
  - `lineage(column: str, sql: str, dialect: str = "generic") -> dict`
198
+ - `lineage_at(ordinal: int, sql: str, dialect: str = "generic") -> dict`
199
+ - `lineage_at_with_schema(ordinal: int, sql: str, schema: dict, dialect: str = "generic") -> dict`
200
+ - `lineage_with_schema(column: str, sql: str, schema: dict, dialect: str = "generic") -> dict`
201
+ - `output_columns(sql: str, dialect: str = "generic") -> dict`
202
+ - `output_columns_with_schema(sql: str, schema: dict, dialect: str = "generic") -> dict`
198
203
  - `source_tables(column: str, sql: str, dialect: str = "generic") -> list[str]`
199
204
  - `analyze_query(sql: str, options: dict | None = None, dialect: str = "generic") -> dict`
200
205
  - `openlineage_column_lineage(sql: str, options: dict) -> dict`
@@ -219,6 +224,7 @@ Exception hierarchy:
219
224
  - `GenerateError`
220
225
  - `TranspileError`
221
226
  - `ValidationError`
227
+ - `ColumnResolutionError` (`reason`, `column`, and `ordinal` attributes)
222
228
 
223
229
  Unknown dialect names raise built-in `ValueError`.
224
230
 
@@ -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.6.3" }
103
+ polyglot-sql-ast-derive = { path = "../polyglot-sql-ast-derive", version = "0.7.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.6.3", optional = true, default-features = false }
110
+ polyglot-sql-function-catalogs = { path = "../polyglot-sql-function-catalogs", version = "0.7.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.6.3", default-features = false }
28
+ polyglot-sql = { version = "0.7.0", default-features = false }
29
29
  ```
30
30
 
31
31
  ```toml
@@ -15,7 +15,7 @@ use crate::expressions::{
15
15
  AggFunc, Alias, BinaryOp, Case, Cast, CeilFunc, Column, DataType, Expression, Function,
16
16
  Identifier, Interval, IntervalUnit, IntervalUnitSpec, IsNull, JSONPath, JSONPathKey,
17
17
  JSONPathRoot, JSONPathSubscript, JsonExtractFunc, Literal, Null, Paren, Struct, Subquery,
18
- SubstringFunc, UnaryFunc, UnaryOp, VarArgFunc, WindowFunction,
18
+ SubstringFunc, UnaryFunc, UnaryOp, Unhex, VarArgFunc, WindowFunction,
19
19
  };
20
20
  #[cfg(feature = "generate")]
21
21
  use crate::generator::GeneratorConfig;
@@ -1687,6 +1687,14 @@ impl DuckDBDialect {
1687
1687
  fn transform_function(&self, f: Function) -> Result<Expression> {
1688
1688
  let name_upper = f.name.to_uppercase();
1689
1689
  match name_upper.as_str() {
1690
+ "FROM_HEX" if f.args.len() == 1 => {
1691
+ let mut args = f.args;
1692
+ Ok(Expression::Unhex(Box::new(Unhex {
1693
+ this: Box::new(args.remove(0)),
1694
+ expression: None,
1695
+ })))
1696
+ }
1697
+
1690
1698
  // IFNULL -> COALESCE
1691
1699
  "IFNULL" if f.args.len() == 2 => Ok(Expression::Coalesce(Box::new(VarArgFunc {
1692
1700
  original_name: None,
@@ -1968,14 +1976,6 @@ impl DuckDBDialect {
1968
1976
  f.args,
1969
1977
  )))),
1970
1978
 
1971
- // NOW -> CURRENT_TIMESTAMP
1972
- "NOW" => Ok(Expression::CurrentTimestamp(
1973
- crate::expressions::CurrentTimestamp {
1974
- precision: None,
1975
- sysdate: false,
1976
- },
1977
- )),
1978
-
1979
1979
  // GETDATE -> CURRENT_TIMESTAMP
1980
1980
  "GETDATE" => Ok(Expression::CurrentTimestamp(
1981
1981
  crate::expressions::CurrentTimestamp {
@@ -580,6 +580,21 @@ fn presto_to_java_format(fmt: &str) -> String {
580
580
  .replace("%M", "MMMM")
581
581
  }
582
582
 
583
+ #[cfg(feature = "transpile")]
584
+ fn presto_to_java_parse_format(fmt: &str) -> String {
585
+ fmt.replace("%Y", "yyyy")
586
+ .replace("%m", "M")
587
+ .replace("%d", "d")
588
+ .replace("%H", "H")
589
+ .replace("%i", "m")
590
+ .replace("%S", "s")
591
+ .replace("%s", "s")
592
+ .replace("%y", "yy")
593
+ .replace("%T", "H:m:s")
594
+ .replace("%F", "yyyy-M-d")
595
+ .replace("%M", "MMMM")
596
+ }
597
+
583
598
  #[cfg(feature = "transpile")]
584
599
  fn normalize_presto_format(fmt: &str) -> String {
585
600
  fmt.replace("%H:%i:%S", "%T").replace("%H:%i:%s", "%T")
@@ -632,12 +632,9 @@ pub(super) fn rewrite(
632
632
 
633
633
  Action::ArrayAggToCollectList => {
634
634
  // ARRAY_AGG(x ORDER BY ...) -> COLLECT_LIST(x) for Hive/Spark
635
- // Python sqlglot Hive.arrayagg_sql strips ORDER BY for simple cases
636
- // but preserves it when DISTINCT/IGNORE NULLS/LIMIT are present
637
635
  match e {
638
636
  Expression::AggregateFunction(mut af) => {
639
- let is_simple =
640
- !af.distinct && af.ignore_nulls.is_none() && af.limit.is_none();
637
+ let preserves_order = af.limit.is_some();
641
638
  let args = if af.args.is_empty() {
642
639
  vec![]
643
640
  } else {
@@ -645,24 +642,23 @@ pub(super) fn rewrite(
645
642
  };
646
643
  af.name = "COLLECT_LIST".to_string();
647
644
  af.args = args;
648
- if is_simple {
645
+ if !preserves_order {
649
646
  af.order_by = Vec::new();
650
647
  }
651
648
  Ok(Expression::AggregateFunction(af))
652
649
  }
653
650
  Expression::ArrayAgg(agg) => {
654
- let is_simple =
655
- !agg.distinct && agg.ignore_nulls.is_none() && agg.limit.is_none();
651
+ let preserves_order = agg.limit.is_some();
656
652
  Ok(Expression::AggregateFunction(Box::new(
657
653
  crate::expressions::AggregateFunction {
658
654
  name: "COLLECT_LIST".to_string(),
659
655
  args: vec![agg.this.clone()],
660
656
  distinct: agg.distinct,
661
657
  filter: agg.filter.clone(),
662
- order_by: if is_simple {
663
- Vec::new()
664
- } else {
658
+ order_by: if preserves_order {
665
659
  agg.order_by.clone()
660
+ } else {
661
+ Vec::new()
666
662
  },
667
663
  limit: agg.limit.clone(),
668
664
  ignore_nulls: agg.ignore_nulls,
@@ -716,14 +712,19 @@ pub(super) fn rewrite(
716
712
  }
717
713
 
718
714
  Action::ArrayAggIgnoreNullsDuckDB => {
719
- // ARRAY_AGG(x IGNORE NULLS ORDER BY a, b DESC) -> ARRAY_AGG(x ORDER BY a NULLS FIRST, b DESC)
720
- // Strip IGNORE NULLS, add NULLS FIRST to first ORDER BY column
715
+ // ARRAY_AGG(x IGNORE NULLS ...) -> ARRAY_AGG(x ...) FILTER(WHERE x IS NOT NULL)
716
+ // DuckDB also needs NULLS FIRST on the first inline ordering expression.
721
717
  let mut agg = if let Expression::ArrayAgg(a) = e {
722
718
  *a
723
719
  } else {
724
720
  unreachable!("action only triggered for ArrayAgg expressions")
725
721
  };
726
- agg.ignore_nulls = None; // Strip IGNORE NULLS
722
+ agg.ignore_nulls = None;
723
+ agg.filter = Some(Expression::IsNull(Box::new(IsNull {
724
+ this: agg.this.clone(),
725
+ not: true,
726
+ postfix_form: false,
727
+ })));
727
728
  if !agg.order_by.is_empty() {
728
729
  agg.order_by[0].nulls_first = Some(true);
729
730
  }
@@ -858,11 +859,19 @@ pub(super) fn rewrite(
858
859
 
859
860
  Action::AggFilterToIff => {
860
861
  // AggFunc.filter -> IFF wrapping: AVG(x) FILTER(WHERE cond) -> AVG(IFF(cond, x, NULL))
862
+ let prefix_not_null = |condition: Expression| match condition {
863
+ Expression::IsNull(mut is_null) if is_null.not => {
864
+ is_null.postfix_form = true;
865
+ Expression::IsNull(is_null)
866
+ }
867
+ other => other,
868
+ };
861
869
  // Helper macro to handle the common AggFunc case
862
870
  macro_rules! handle_agg_filter_to_iff {
863
871
  ($variant:ident, $agg:expr) => {{
864
872
  let mut agg = $agg;
865
873
  if let Some(filter_cond) = agg.filter.take() {
874
+ let filter_cond = prefix_not_null(filter_cond);
866
875
  let iff_call = Expression::Function(Box::new(Function::new(
867
876
  "IFF".to_string(),
868
877
  vec![filter_cond, agg.this.clone(), Expression::Null(Null)],
@@ -878,7 +887,24 @@ pub(super) fn rewrite(
878
887
  Expression::Sum(agg) => handle_agg_filter_to_iff!(Sum, agg),
879
888
  Expression::Min(agg) => handle_agg_filter_to_iff!(Min, agg),
880
889
  Expression::Max(agg) => handle_agg_filter_to_iff!(Max, agg),
881
- Expression::ArrayAgg(agg) => handle_agg_filter_to_iff!(ArrayAgg, agg),
890
+ Expression::ArrayAgg(mut agg) => {
891
+ if let Some(filter_cond) = agg.filter.take() {
892
+ let filter_cond = prefix_not_null(filter_cond);
893
+ agg.this = Expression::Function(Box::new(Function::new(
894
+ "IFF".to_string(),
895
+ vec![filter_cond, agg.this, Expression::Null(Null)],
896
+ )));
897
+ }
898
+ if agg.order_by.is_empty() {
899
+ Ok(Expression::ArrayAgg(agg))
900
+ } else {
901
+ let order_by = std::mem::take(&mut agg.order_by);
902
+ Ok(Expression::WithinGroup(Box::new(WithinGroup {
903
+ this: Expression::ArrayAgg(agg),
904
+ order_by,
905
+ })))
906
+ }
907
+ }
882
908
  Expression::CountIf(agg) => handle_agg_filter_to_iff!(CountIf, agg),
883
909
  Expression::Stddev(agg) => handle_agg_filter_to_iff!(Stddev, agg),
884
910
  Expression::StddevPop(agg) => handle_agg_filter_to_iff!(StddevPop, agg),
@@ -896,7 +922,21 @@ pub(super) fn rewrite(
896
922
  }
897
923
  Expression::Count(mut c) => {
898
924
  if let Some(filter_cond) = c.filter.take() {
899
- if let Some(ref this_expr) = c.this {
925
+ let filter_cond = prefix_not_null(filter_cond);
926
+ let is_star = c.star || matches!(c.this, Some(Expression::Star(_)));
927
+ if is_star {
928
+ return Ok(Expression::CountIf(Box::new(AggFunc {
929
+ this: filter_cond,
930
+ distinct: false,
931
+ filter: None,
932
+ order_by: Vec::new(),
933
+ name: None,
934
+ ignore_nulls: None,
935
+ having_max: None,
936
+ limit: None,
937
+ inferred_type: None,
938
+ })));
939
+ } else if let Some(ref this_expr) = c.this {
900
940
  let iff_call = Expression::Function(Box::new(Function::new(
901
941
  "IFF".to_string(),
902
942
  vec![filter_cond, this_expr.clone(), Expression::Null(Null)],
@@ -906,6 +946,18 @@ pub(super) fn rewrite(
906
946
  }
907
947
  Ok(Expression::Count(c))
908
948
  }
949
+ Expression::AggregateFunction(mut af) => {
950
+ if let Some(filter_cond) = af.filter.take() {
951
+ let filter_cond = prefix_not_null(filter_cond);
952
+ if let Some(first_arg) = af.args.first_mut() {
953
+ *first_arg = Expression::Function(Box::new(Function::new(
954
+ "IFF".to_string(),
955
+ vec![filter_cond, first_arg.clone(), Expression::Null(Null)],
956
+ )));
957
+ }
958
+ }
959
+ Ok(Expression::AggregateFunction(af))
960
+ }
909
961
  other => Ok(other),
910
962
  }
911
963
  }
@@ -862,7 +862,11 @@ pub(super) fn rewrite(
862
862
  }
863
863
 
864
864
  let seq = Expression::Function(Box::new(Function::new(
865
- "SEQUENCE".to_string(),
865
+ if matches!(target, DialectType::BigQuery) {
866
+ "GENERATE_ARRAY".to_string()
867
+ } else {
868
+ "SEQUENCE".to_string()
869
+ },
866
870
  seq_args,
867
871
  )));
868
872
 
@@ -86,6 +86,118 @@ pub(super) fn normalize(
86
86
  let expr = statements::normalize_root(expr, &context);
87
87
 
88
88
  transform_recursive(expr, &|e| {
89
+ if matches!(source, DialectType::DataFusion) && matches!(target, DialectType::DuckDB) {
90
+ if let Expression::Function(ref function) = e {
91
+ if function.name.eq_ignore_ascii_case("NOW") && function.args.is_empty() {
92
+ return Ok(Expression::CurrentTimestamp(
93
+ crate::expressions::CurrentTimestamp {
94
+ precision: None,
95
+ sysdate: false,
96
+ },
97
+ ));
98
+ }
99
+ }
100
+ }
101
+
102
+ if matches!(source, DialectType::Teradata)
103
+ && matches!(target, DialectType::Spark | DialectType::Databricks)
104
+ {
105
+ if let Expression::StrToDate(ref str_to_date) = e {
106
+ let mut normalized = str_to_date.as_ref().clone();
107
+ normalized.format = normalized.format.map(|format| format.replace("%d", "%-d"));
108
+ return Ok(Expression::StrToDate(Box::new(normalized)));
109
+ }
110
+ }
111
+
112
+ if matches!(source, DialectType::DuckDB) && matches!(target, DialectType::DuckDB) {
113
+ if let Expression::ArrayAgg(ref array_agg) = e {
114
+ if let Some(Expression::IsNull(is_null)) = &array_agg.filter {
115
+ if is_null.not && !is_null.postfix_form {
116
+ let mut normalized = array_agg.as_ref().clone();
117
+ let mut condition = is_null.as_ref().clone();
118
+ condition.postfix_form = true;
119
+ normalized.filter = Some(Expression::IsNull(Box::new(condition)));
120
+ return Ok(Expression::ArrayAgg(Box::new(normalized)));
121
+ }
122
+ }
123
+ }
124
+ }
125
+
126
+ if matches!(source, DialectType::Generic) && matches!(target, DialectType::BigQuery) {
127
+ if let Expression::TimeToStr(ref time_to_str) = e {
128
+ let mut normalized = time_to_str.as_ref().clone();
129
+ normalized.format = normalized
130
+ .format
131
+ .replace("%Y-%m-%d", "%F")
132
+ .replace("%H:%M:%S", "%T");
133
+ return Ok(Expression::TimeToStr(Box::new(normalized)));
134
+ }
135
+ }
136
+
137
+ if matches!(source, DialectType::Hive) && matches!(target, DialectType::Hive) {
138
+ if let Expression::Function(ref function) = e {
139
+ if function.name.eq_ignore_ascii_case("STR_TO_DATE") && function.args.len() == 1 {
140
+ return Ok(Expression::Cast(Box::new(Cast {
141
+ this: function.args[0].clone(),
142
+ to: DataType::Date,
143
+ trailing_comments: Vec::new(),
144
+ double_colon_syntax: false,
145
+ format: None,
146
+ default: None,
147
+ inferred_type: None,
148
+ })));
149
+ }
150
+ }
151
+ }
152
+
153
+ if matches!(source, DialectType::Generic) && matches!(target, DialectType::Drill) {
154
+ if let Expression::ILike(ref like) = e {
155
+ return Ok(Expression::Function(Box::new(Function::new(
156
+ "ILIKE".to_string(),
157
+ vec![like.left.clone(), like.right.clone()],
158
+ ))));
159
+ }
160
+ }
161
+
162
+ // DuckDB canonicalizes `x IS NOT NULL` as prefix `NOT x IS NULL`.
163
+ if matches!(source, DialectType::DuckDB) {
164
+ if let Expression::IsNull(ref is_null) = e {
165
+ if is_null.not && !is_null.postfix_form {
166
+ let mut normalized = is_null.as_ref().clone();
167
+ normalized.postfix_form = true;
168
+ return Ok(Expression::IsNull(Box::new(normalized)));
169
+ }
170
+ }
171
+ }
172
+
173
+ // Snowflake COUNT_IF requires an explicitly boolean predicate in DuckDB.
174
+ if matches!(source, DialectType::Snowflake) && matches!(target, DialectType::DuckDB) {
175
+ if let Expression::CountIf(ref count_if) = e {
176
+ let mut count_if = count_if.as_ref().clone();
177
+ count_if.this = Expression::Is(Box::new(crate::expressions::BinaryOp::new(
178
+ Expression::Paren(Box::new(crate::expressions::Paren {
179
+ this: count_if.this,
180
+ trailing_comments: Vec::new(),
181
+ })),
182
+ Expression::Boolean(crate::expressions::BooleanLiteral { value: true }),
183
+ )));
184
+ return Ok(Expression::CountIf(Box::new(count_if)));
185
+ }
186
+ }
187
+
188
+ if matches!(source, DialectType::Presto | DialectType::Trino)
189
+ && matches!(target, DialectType::DuckDB)
190
+ {
191
+ if let Expression::Function(ref function) = e {
192
+ if function.name.eq_ignore_ascii_case("SHA256") && function.args.len() == 1 {
193
+ return Ok(Expression::Unhex(Box::new(crate::expressions::Unhex {
194
+ this: Box::new(Expression::Function(function.clone())),
195
+ expression: None,
196
+ })));
197
+ }
198
+ }
199
+ }
200
+
89
201
  if matches!(source, DialectType::PostgreSQL | DialectType::Redshift)
90
202
  && matches!(target, DialectType::TSQL | DialectType::Fabric)
91
203
  {
@@ -616,7 +728,100 @@ pub(super) fn normalize(
616
728
  }
617
729
  }
618
730
 
619
- // BigQuery IN UNNEST(expr) -> IN (SELECT UNNEST/EXPLODE(expr)) for non-BigQuery targets
731
+ // BigQuery renders NOT IN UNNEST as prefix NOT around the membership predicate.
732
+ if matches!(source, DialectType::BigQuery) && matches!(target, DialectType::BigQuery) {
733
+ if let Expression::In(ref in_expr) = e {
734
+ if in_expr.not && in_expr.unnest.is_some() {
735
+ let mut positive = in_expr.as_ref().clone();
736
+ positive.not = false;
737
+ return Ok(Expression::Not(Box::new(crate::expressions::UnaryOp::new(
738
+ Expression::In(Box::new(positive)),
739
+ ))));
740
+ }
741
+ }
742
+ }
743
+
744
+ // BigQuery IN UNNEST(expr) -> a NULL-aware DuckDB CASE expression.
745
+ if matches!(source, DialectType::BigQuery) && matches!(target, DialectType::DuckDB) {
746
+ if let Expression::In(ref in_expr) = e {
747
+ if let Some(ref unnest_inner) = in_expr.unnest {
748
+ let array = unnest_inner.as_ref().clone();
749
+ let value = in_expr.this.clone();
750
+ let array_length = || {
751
+ Expression::Function(Box::new(Function::new(
752
+ "ARRAY_LENGTH".to_string(),
753
+ vec![array.clone()],
754
+ )))
755
+ };
756
+ let empty_or_null =
757
+ Expression::Or(Box::new(crate::expressions::BinaryOp::new(
758
+ Expression::IsNull(Box::new(crate::expressions::IsNull {
759
+ this: array.clone(),
760
+ not: false,
761
+ postfix_form: false,
762
+ })),
763
+ Expression::Eq(Box::new(crate::expressions::BinaryOp::new(
764
+ array_length(),
765
+ Expression::number(0),
766
+ ))),
767
+ )));
768
+ let contains = Expression::Function(Box::new(Function::new(
769
+ "ARRAY_CONTAINS".to_string(),
770
+ vec![array.clone(), value.clone()],
771
+ )));
772
+ let value_null_or_array_has_null =
773
+ Expression::Or(Box::new(crate::expressions::BinaryOp::new(
774
+ Expression::IsNull(Box::new(crate::expressions::IsNull {
775
+ this: value,
776
+ not: false,
777
+ postfix_form: false,
778
+ })),
779
+ Expression::Neq(Box::new(crate::expressions::BinaryOp::new(
780
+ array_length(),
781
+ Expression::Function(Box::new(Function::new(
782
+ "LIST_COUNT".to_string(),
783
+ vec![array],
784
+ ))),
785
+ ))),
786
+ )));
787
+ let case = Expression::Case(Box::new(Case {
788
+ operand: None,
789
+ whens: vec![
790
+ (
791
+ empty_or_null,
792
+ Expression::Boolean(crate::expressions::BooleanLiteral {
793
+ value: false,
794
+ }),
795
+ ),
796
+ (
797
+ contains,
798
+ Expression::Boolean(crate::expressions::BooleanLiteral {
799
+ value: true,
800
+ }),
801
+ ),
802
+ (
803
+ value_null_or_array_has_null,
804
+ Expression::Null(crate::expressions::Null),
805
+ ),
806
+ ],
807
+ else_: Some(Expression::Boolean(crate::expressions::BooleanLiteral {
808
+ value: false,
809
+ })),
810
+ comments: Vec::new(),
811
+ inferred_type: None,
812
+ }));
813
+ return if in_expr.not {
814
+ Ok(Expression::Not(Box::new(crate::expressions::UnaryOp::new(
815
+ case,
816
+ ))))
817
+ } else {
818
+ Ok(case)
819
+ };
820
+ }
821
+ }
822
+ }
823
+
824
+ // BigQuery IN UNNEST(expr) -> IN (SELECT UNNEST/EXPLODE(expr)) for other targets
620
825
  if matches!(source, DialectType::BigQuery) && !matches!(target, DialectType::BigQuery) {
621
826
  if let Expression::In(ref in_expr) = e {
622
827
  if let Some(ref unnest_inner) = in_expr.unnest {
@@ -1403,6 +1608,25 @@ pub(super) fn normalize(
1403
1608
  }
1404
1609
  }
1405
1610
 
1611
+ // ARRAY_CONCAT_AGG -> DuckDB: flatten an ARRAY_AGG while excluding NULL arrays.
1612
+ if matches!(target, DialectType::DuckDB) {
1613
+ if let Expression::ArrayConcatAgg(ref agg) = e {
1614
+ let mut agg = agg.as_ref().clone();
1615
+ agg.name = None;
1616
+ agg.filter = Some(Expression::IsNull(Box::new(crate::expressions::IsNull {
1617
+ this: agg.this.clone(),
1618
+ not: true,
1619
+ postfix_form: true,
1620
+ })));
1621
+ if let Some(first) = agg.order_by.first_mut() {
1622
+ first.nulls_first = Some(true);
1623
+ }
1624
+ return Ok(Expression::ArrayFlatten(Box::new(
1625
+ crate::expressions::UnaryFunc::new(Expression::ArrayAgg(Box::new(agg))),
1626
+ )));
1627
+ }
1628
+ }
1629
+
1406
1630
  // ARRAY_CONCAT_AGG -> others: keep as function for cross-dialect
1407
1631
  if !matches!(target, DialectType::BigQuery | DialectType::Snowflake) {
1408
1632
  if let Expression::ArrayConcatAgg(agg) = e {
@@ -1779,7 +2003,7 @@ pub(super) fn normalize(
1779
2003
  | "STRFTIME" | "STRPTIME"
1780
2004
  | "DATE_FORMAT" | "FORMAT_DATE"
1781
2005
  | "PARSE_TIMESTAMP" | "PARSE_DATETIME" | "PARSE_DATE"
1782
- | "FROM_ISO8601_TIMESTAMP" | "FROM_ISO8601_DATE"
2006
+ | "FROM_ISO8601_TIMESTAMP" | "FROM_ISO8601_TIMESTAMP_NANOS" | "FROM_ISO8601_DATE"
1783
2007
  | "FROM_BASE64" | "TO_BASE64"
1784
2008
  | "GETDATE"
1785
2009
  | "TO_HEX" | "FROM_HEX" | "UNHEX" | "HEX"
@@ -1957,6 +2181,11 @@ pub(super) fn normalize(
1957
2181
  }
1958
2182
  }
1959
2183
  }
2184
+ Expression::AggregateFunction(af)
2185
+ if matches!(target, DialectType::Snowflake) && af.filter.is_some() =>
2186
+ {
2187
+ Action::Aggregates(aggregates::Action::AggFilterToIff)
2188
+ }
1960
2189
  Expression::AggregateFunction(af) => {
1961
2190
  let name = af.name.to_ascii_uppercase();
1962
2191
  match name.as_str() {
@@ -2124,7 +2353,9 @@ pub(super) fn normalize(
2124
2353
  _ => Action::None,
2125
2354
  },
2126
2355
  Expression::ArrayAgg(ref agg) => {
2127
- if matches!(target, DialectType::MySQL | DialectType::SingleStore) {
2356
+ if matches!(target, DialectType::Snowflake) && agg.filter.is_some() {
2357
+ Action::Aggregates(aggregates::Action::AggFilterToIff)
2358
+ } else if matches!(target, DialectType::MySQL | DialectType::SingleStore) {
2128
2359
  Action::Aggregates(aggregates::Action::ArrayAggToGroupConcat)
2129
2360
  } else if matches!(
2130
2361
  target,
@@ -2143,7 +2374,6 @@ pub(super) fn normalize(
2143
2374
  Action::Aggregates(aggregates::Action::ArrayAggNullFilter)
2144
2375
  } else if matches!(target, DialectType::DuckDB)
2145
2376
  && agg.ignore_nulls == Some(true)
2146
- && !agg.order_by.is_empty()
2147
2377
  {
2148
2378
  // BigQuery ARRAY_AGG(x IGNORE NULLS ORDER BY ...) -> DuckDB ARRAY_AGG(x ORDER BY a NULLS FIRST, ...)
2149
2379
  Action::Aggregates(aggregates::Action::ArrayAggIgnoreNullsDuckDB)