polyglot-sql 0.13.2__tar.gz → 0.13.3__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 (233) hide show
  1. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/Cargo.lock +6 -6
  2. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/Cargo.toml +1 -1
  3. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/PKG-INFO +1 -1
  4. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/Cargo.toml +2 -2
  5. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/README.md +4 -4
  6. polyglot_sql-0.13.3/crates/polyglot-sql/src/dialects/normalization/duckdb.rs +272 -0
  7. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/dialects/normalization/scalar.rs +2 -1
  8. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/generator.rs +121 -22
  9. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/tests/duckdb_integer_division.rs +211 -6
  10. polyglot_sql-0.13.3/crates/polyglot-sql/tests/mod_precedence.rs +176 -0
  11. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql-function-catalogs/README.md +1 -1
  12. polyglot_sql-0.13.3/crates/polyglot-sql-python/tests/test_duckdb_datafusion_execution.py +102 -0
  13. polyglot_sql-0.13.2/crates/polyglot-sql/src/dialects/normalization/duckdb.rs +0 -107
  14. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/README.md +0 -0
  15. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/benches/allocation_hotspots.rs +0 -0
  16. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/benches/ast_traversal.rs +0 -0
  17. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/benches/common/mod.rs +0 -0
  18. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/benches/in_list.rs +0 -0
  19. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/benches/lineage.rs +0 -0
  20. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/benches/parsing.rs +0 -0
  21. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/benches/performance_hotspots.rs +0 -0
  22. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/benches/rust_parsing.rs +0 -0
  23. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/benches/transpile.rs +0 -0
  24. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/examples/basic_usage.rs +0 -0
  25. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/examples/bench_json.rs +0 -0
  26. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/ast_children.rs +0 -0
  27. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/ast_json.rs +0 -0
  28. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/ast_mutation.rs +0 -0
  29. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/ast_transforms.rs +0 -0
  30. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/binding.rs +0 -0
  31. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/builder/mod.rs +0 -0
  32. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/builder/plan.rs +0 -0
  33. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/dialects/athena.rs +0 -0
  34. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/dialects/bigquery.rs +0 -0
  35. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/dialects/clickhouse.rs +0 -0
  36. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/dialects/cockroachdb.rs +0 -0
  37. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/dialects/databricks.rs +0 -0
  38. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/dialects/datafusion.rs +0 -0
  39. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/dialects/doris.rs +0 -0
  40. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/dialects/dremio.rs +0 -0
  41. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/dialects/drill.rs +0 -0
  42. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/dialects/druid.rs +0 -0
  43. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/dialects/duckdb.rs +0 -0
  44. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/dialects/dune.rs +0 -0
  45. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/dialects/exasol.rs +0 -0
  46. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/dialects/fabric.rs +0 -0
  47. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/dialects/generic.rs +0 -0
  48. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/dialects/hana.rs +0 -0
  49. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/dialects/hive.rs +0 -0
  50. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/dialects/materialize.rs +0 -0
  51. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/dialects/mod.rs +0 -0
  52. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/dialects/mysql.rs +0 -0
  53. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/dialects/normalization/aggregates.rs +0 -0
  54. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/dialects/normalization/collections.rs +0 -0
  55. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/dialects/normalization/hana.rs +0 -0
  56. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/dialects/normalization/json.rs +0 -0
  57. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/dialects/normalization/mod.rs +0 -0
  58. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/dialects/normalization/operators.rs +0 -0
  59. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/dialects/normalization/postgres_interval.rs +0 -0
  60. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/dialects/normalization/statements.rs +0 -0
  61. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/dialects/normalization/temporal.rs +0 -0
  62. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/dialects/normalization/types.rs +0 -0
  63. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/dialects/normalization/vertica.rs +0 -0
  64. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/dialects/oracle.rs +0 -0
  65. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/dialects/postgres.rs +0 -0
  66. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/dialects/presto.rs +0 -0
  67. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/dialects/redshift.rs +0 -0
  68. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/dialects/risingwave.rs +0 -0
  69. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/dialects/singlestore.rs +0 -0
  70. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/dialects/snowflake.rs +0 -0
  71. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/dialects/solr.rs +0 -0
  72. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/dialects/spark.rs +0 -0
  73. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/dialects/sqlite.rs +0 -0
  74. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/dialects/starrocks.rs +0 -0
  75. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/dialects/tableau.rs +0 -0
  76. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/dialects/teradata.rs +0 -0
  77. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/dialects/tidb.rs +0 -0
  78. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/dialects/trino.rs +0 -0
  79. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/dialects/tsql.rs +0 -0
  80. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/dialects/vertica.rs +0 -0
  81. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/diff.rs +0 -0
  82. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/error.rs +0 -0
  83. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/expressions.rs +0 -0
  84. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/format_tokens.rs +0 -0
  85. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/function_catalog.rs +0 -0
  86. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/function_registry.rs +0 -0
  87. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/guard.rs +0 -0
  88. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/helper.rs +0 -0
  89. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/lib.rs +0 -0
  90. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/lineage.rs +0 -0
  91. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/openlineage.rs +0 -0
  92. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/optimizer/annotate_types.rs +0 -0
  93. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/optimizer/canonicalize.rs +0 -0
  94. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/optimizer/eliminate_ctes.rs +0 -0
  95. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/optimizer/eliminate_joins.rs +0 -0
  96. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/optimizer/isolate_table_selects.rs +0 -0
  97. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/optimizer/mod.rs +0 -0
  98. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/optimizer/normalize.rs +0 -0
  99. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/optimizer/normalize_identifiers.rs +0 -0
  100. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/optimizer/optimize_joins.rs +0 -0
  101. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/optimizer/optimizer.rs +0 -0
  102. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/optimizer/pushdown_predicates.rs +0 -0
  103. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/optimizer/pushdown_projections.rs +0 -0
  104. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/optimizer/qualify_columns.rs +0 -0
  105. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/optimizer/qualify_tables.rs +0 -0
  106. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/optimizer/set_operation_types.rs +0 -0
  107. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/optimizer/simplify.rs +0 -0
  108. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/optimizer/subquery.rs +0 -0
  109. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/parser.rs +0 -0
  110. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/planner.rs +0 -0
  111. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/query_analysis/column_uses.rs +0 -0
  112. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/query_analysis.rs +0 -0
  113. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/resolver.rs +0 -0
  114. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/schema.rs +0 -0
  115. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/scope.rs +0 -0
  116. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/set_operation.rs +0 -0
  117. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/time.rs +0 -0
  118. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/tokens.rs +0 -0
  119. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/transforms.rs +0 -0
  120. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/traversal.rs +0 -0
  121. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/trie.rs +0 -0
  122. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/validation/semantics.rs +0 -0
  123. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/validation/tests.rs +0 -0
  124. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/src/validation.rs +0 -0
  125. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/tests/analyze_failures.rs +0 -0
  126. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/tests/clickhouse_regression.rs +0 -0
  127. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/tests/common/known_failures.rs +0 -0
  128. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/tests/common/mod.rs +0 -0
  129. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/tests/common/test_data.rs +0 -0
  130. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/tests/common/test_runner.rs +0 -0
  131. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/tests/create_view_security_comment_regression.rs +0 -0
  132. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/tests/custom_clickhouse_coverage.rs +0 -0
  133. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/tests/custom_clickhouse_parser.rs +0 -0
  134. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/tests/custom_dialect.rs +0 -0
  135. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/tests/custom_dialect_tests.rs +0 -0
  136. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/tests/custom_fixtures/datafusion/ddl.json +0 -0
  137. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/tests/custom_fixtures/datafusion/dml.json +0 -0
  138. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/tests/custom_fixtures/datafusion/functions.json +0 -0
  139. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/tests/custom_fixtures/datafusion/identity.json +0 -0
  140. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/tests/custom_fixtures/datafusion/operators.json +0 -0
  141. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/tests/custom_fixtures/datafusion/select.json +0 -0
  142. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/tests/custom_fixtures/datafusion/transpilation.json +0 -0
  143. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/tests/custom_fixtures/datafusion/types.json +0 -0
  144. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/tests/custom_fixtures/hana/ddl.json +0 -0
  145. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/tests/custom_fixtures/hana/dml.json +0 -0
  146. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/tests/custom_fixtures/hana/functions.json +0 -0
  147. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/tests/custom_fixtures/hana/identity.json +0 -0
  148. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/tests/custom_fixtures/hana/select.json +0 -0
  149. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/tests/custom_fixtures/hana/types.json +0 -0
  150. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/tests/custom_fixtures/vertica/identity.json +0 -0
  151. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/tests/custom_fixtures/vertica/transpilation.json +0 -0
  152. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/tests/custom_fixtures/vertica/types.json +0 -0
  153. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/tests/data_type_api.rs +0 -0
  154. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/tests/deep_nesting_regression.rs +0 -0
  155. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/tests/dialect_matrix.rs +0 -0
  156. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/tests/duckdb_order_by_all.rs +0 -0
  157. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/tests/error_handling.rs +0 -0
  158. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/tests/fabric_regression.rs +0 -0
  159. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/tests/fabric_tpch_regression.rs +0 -0
  160. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/tests/identity_roundtrip.rs +0 -0
  161. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/tests/oracle_data_types_regression.rs +0 -0
  162. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/tests/postgres_explain_options.rs +0 -0
  163. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/tests/postgres_regexp_clickhouse.rs +0 -0
  164. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/tests/postgres_sqlite_regression.rs +0 -0
  165. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/tests/query_analysis.rs +0 -0
  166. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/tests/query_analysis_regression.rs +0 -0
  167. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/tests/snowflake_regression_test.rs +0 -0
  168. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/tests/sqlglot_compat.rs +0 -0
  169. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/tests/sqlglot_dialect_identity.rs +0 -0
  170. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/tests/sqlglot_identity.rs +0 -0
  171. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/tests/sqlglot_identity_detailed.rs +0 -0
  172. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/tests/sqlglot_parser.rs +0 -0
  173. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/tests/sqlglot_pretty.rs +0 -0
  174. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/tests/sqlglot_transpilation.rs +0 -0
  175. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/tests/sqlglot_transpile.rs +0 -0
  176. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/tests/tpch_transpile_stack.rs +0 -0
  177. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/tests/transform_regression.rs +0 -0
  178. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql/tests/tsql_regression.rs +0 -0
  179. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql-ast-derive/Cargo.toml +0 -0
  180. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql-ast-derive/src/lib.rs +0 -0
  181. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql-function-catalogs/Cargo.toml +0 -0
  182. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql-function-catalogs/src/clickhouse.rs +0 -0
  183. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql-function-catalogs/src/duckdb.rs +0 -0
  184. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql-function-catalogs/src/lib.rs +0 -0
  185. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql-function-catalogs/tools/clickhouse/extract_functions.py +0 -0
  186. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql-function-catalogs/tools/duckdb/extract_functions.py +0 -0
  187. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql-python/Cargo.toml +0 -0
  188. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql-python/README.md +0 -0
  189. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql-python/docs/api.md +0 -0
  190. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql-python/docs/index.md +0 -0
  191. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql-python/mkdocs.yml +0 -0
  192. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql-python/src/annotate_types.rs +0 -0
  193. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql-python/src/builders.rs +0 -0
  194. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql-python/src/dialects.rs +0 -0
  195. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql-python/src/diff.rs +0 -0
  196. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql-python/src/errors.rs +0 -0
  197. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql-python/src/expr.rs +0 -0
  198. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql-python/src/expr_types.rs +0 -0
  199. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql-python/src/format.rs +0 -0
  200. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql-python/src/generate.rs +0 -0
  201. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql-python/src/helpers.rs +0 -0
  202. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql-python/src/lib.rs +0 -0
  203. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql-python/src/lineage.rs +0 -0
  204. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql-python/src/openlineage.rs +0 -0
  205. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql-python/src/optimize.rs +0 -0
  206. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql-python/src/parse.rs +0 -0
  207. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql-python/src/query_analysis.rs +0 -0
  208. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql-python/src/tokenize.rs +0 -0
  209. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql-python/src/transforms.rs +0 -0
  210. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql-python/src/transpile.rs +0 -0
  211. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql-python/src/types.rs +0 -0
  212. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql-python/src/validate.rs +0 -0
  213. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql-python/tests/conftest.py +0 -0
  214. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql-python/tests/test_builders.py +0 -0
  215. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql-python/tests/test_compat.py +0 -0
  216. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql-python/tests/test_dialects.py +0 -0
  217. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql-python/tests/test_diff.py +0 -0
  218. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql-python/tests/test_expression.py +0 -0
  219. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql-python/tests/test_format.py +0 -0
  220. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql-python/tests/test_generate.py +0 -0
  221. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql-python/tests/test_lineage.py +0 -0
  222. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql-python/tests/test_optimize.py +0 -0
  223. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql-python/tests/test_parse.py +0 -0
  224. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql-python/tests/test_query_analysis.py +0 -0
  225. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql-python/tests/test_transforms.py +0 -0
  226. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql-python/tests/test_transpile.py +0 -0
  227. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql-python/tests/test_validate.py +0 -0
  228. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/crates/polyglot-sql-python/uv.lock +0 -0
  229. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/pyproject.toml +0 -0
  230. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/python/polyglot_sql/__init__.py +0 -0
  231. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/python/polyglot_sql/__init__.pyi +0 -0
  232. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/python/polyglot_sql/analysis_types.py +0 -0
  233. {polyglot_sql-0.13.2 → polyglot_sql-0.13.3}/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.13.2"
608
+ version = "0.13.3"
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.13.2"
626
+ version = "0.13.3"
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.13.2"
635
+ version = "0.13.3"
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.13.2"
645
+ version = "0.13.3"
646
646
 
647
647
  [[package]]
648
648
  name = "polyglot-sql-python"
649
- version = "0.13.2"
649
+ version = "0.13.3"
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.13.2"
660
+ version = "0.13.3"
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.13.2"
9
+ version = "0.13.3"
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.13.2
3
+ Version: 0.13.3
4
4
  Classifier: Development Status :: 4 - Beta
5
5
  Classifier: Intended Audience :: Developers
6
6
  Classifier: License :: OSI Approved :: MIT License
@@ -103,14 +103,14 @@ function-catalog-all-dialects = [
103
103
  ]
104
104
 
105
105
  [dependencies]
106
- polyglot-sql-ast-derive = { path = "../polyglot-sql-ast-derive", version = "0.13.2" }
106
+ polyglot-sql-ast-derive = { path = "../polyglot-sql-ast-derive", version = "0.13.3" }
107
107
  serde = { workspace = true }
108
108
  serde_json = { workspace = true }
109
109
  thiserror = { workspace = true }
110
110
  unicode-segmentation = { workspace = true }
111
111
  stacker = { version = "0.1", optional = true }
112
112
  ts-rs = { version = "12.0", features = ["serde-compat"], optional = true }
113
- polyglot-sql-function-catalogs = { path = "../polyglot-sql-function-catalogs", version = "0.13.2", optional = true, default-features = false }
113
+ polyglot-sql-function-catalogs = { path = "../polyglot-sql-function-catalogs", version = "0.13.3", optional = true, default-features = false }
114
114
 
115
115
  [dev-dependencies]
116
116
  pretty_assertions = "1.4"
@@ -25,12 +25,12 @@ By default, `polyglot-sql` enables the full public API. Parser-only consumers ca
25
25
  disable default features and opt into only the dialect parsers they need:
26
26
 
27
27
  ```toml
28
- polyglot-sql = { version = "0.13.2", default-features = false }
28
+ polyglot-sql = { version = "0.13.3", default-features = false }
29
29
  ```
30
30
 
31
31
  ```toml
32
32
  polyglot-sql = {
33
- version = "0.13.2",
33
+ version = "0.13.3",
34
34
  default-features = false,
35
35
  features = ["dialect-clickhouse"],
36
36
  }
@@ -44,14 +44,14 @@ Examples:
44
44
  ```toml
45
45
  # Parse and generate SQL for one dialect.
46
46
  polyglot-sql = {
47
- version = "0.13.2",
47
+ version = "0.13.3",
48
48
  default-features = false,
49
49
  features = ["generate", "dialect-clickhouse"],
50
50
  }
51
51
 
52
52
  # Cross-dialect transpilation.
53
53
  polyglot-sql = {
54
- version = "0.13.2",
54
+ version = "0.13.3",
55
55
  default-features = false,
56
56
  features = ["transpile", "dialect-clickhouse", "dialect-postgresql"],
57
57
  }
@@ -0,0 +1,272 @@
1
+ //! Preserve DuckDB's type-dependent `//` semantics before target rewrites.
2
+
3
+ use super::scalar::{expression_numeric_kind, NumericKind};
4
+ use super::*;
5
+ use crate::expressions::RoundFunc;
6
+
7
+ fn combine(left: NumericKind, right: NumericKind) -> NumericKind {
8
+ use NumericKind::*;
9
+ match (left, right) {
10
+ (Unknown, _) | (_, Unknown) => Unknown,
11
+ (Float, _) | (_, Float) => Float,
12
+ (Decimal, _) | (_, Decimal) => Decimal,
13
+ (Integer, Integer) => Integer,
14
+ }
15
+ }
16
+
17
+ fn numeric_kind(expr: &Expression) -> NumericKind {
18
+ match expr {
19
+ Expression::Paren(p) => numeric_kind(&p.this),
20
+ Expression::Neg(n) => numeric_kind(&n.this),
21
+ Expression::Alias(a) => numeric_kind(&a.this),
22
+ Expression::Add(b) | Expression::Sub(b) | Expression::Mul(b) | Expression::Mod(b) => {
23
+ combine(numeric_kind(&b.left), numeric_kind(&b.right))
24
+ }
25
+ // The complete bottom-up source pass has already lowered fractional
26
+ // children to Div. Remaining IntDiv children have integer operands.
27
+ Expression::IntDiv(_) => NumericKind::Integer,
28
+ Expression::Div(_) => NumericKind::Float,
29
+ Expression::Function(f) if f.name.eq_ignore_ascii_case("NULLIF") && f.args.len() == 2 => {
30
+ numeric_kind(&f.args[0])
31
+ }
32
+ Expression::NullIf(f) => numeric_kind(&f.this),
33
+ _ => expression_numeric_kind(expr),
34
+ }
35
+ }
36
+
37
+ /// Classify the rewritten DataFusion expression. Source `/` nodes have already
38
+ /// been made floating, and lowered `//` nodes retain their operands' types.
39
+ /// Never infer provenance from SQL syntax such as a NULLIF divisor.
40
+ fn datafusion_numeric_kind(expr: &Expression) -> NumericKind {
41
+ match expr {
42
+ Expression::Paren(p) => datafusion_numeric_kind(&p.this),
43
+ Expression::Annotated(a) => datafusion_numeric_kind(&a.this),
44
+ Expression::Neg(n) => datafusion_numeric_kind(&n.this),
45
+ Expression::Alias(a) => datafusion_numeric_kind(&a.this),
46
+ Expression::Abs(f) => datafusion_numeric_kind(&f.this),
47
+ Expression::Add(b) | Expression::Sub(b) | Expression::Mul(b) | Expression::Mod(b) => {
48
+ combine(
49
+ datafusion_numeric_kind(&b.left),
50
+ datafusion_numeric_kind(&b.right),
51
+ )
52
+ }
53
+ Expression::Div(b) => {
54
+ let left = datafusion_numeric_kind(&b.left);
55
+ // Div is already target SQL. Its generated NULLIF follows
56
+ // DataFusion's common-type coercion, including a floating divisor.
57
+ let right = match &b.right {
58
+ Expression::Function(f)
59
+ if f.name.eq_ignore_ascii_case("NULLIF") && f.args.len() == 2 =>
60
+ {
61
+ combine(
62
+ datafusion_numeric_kind(&f.args[0]),
63
+ datafusion_numeric_kind(&f.args[1]),
64
+ )
65
+ }
66
+ other => datafusion_numeric_kind(other),
67
+ };
68
+ // A source `/` supplies a floating operand even when columns or
69
+ // function return types on the other side are unresolved.
70
+ if left == NumericKind::Float || right == NumericKind::Float {
71
+ NumericKind::Float
72
+ } else {
73
+ combine(left, right)
74
+ }
75
+ }
76
+ Expression::Coalesce(f) => datafusion_branch_kind(f.expressions.iter()),
77
+ Expression::Case(c) => datafusion_branch_kind(
78
+ c.whens
79
+ .iter()
80
+ .map(|(_, result)| result)
81
+ .chain(c.else_.iter()),
82
+ ),
83
+ Expression::IfFunc(f) => {
84
+ datafusion_branch_kind(std::iter::once(&f.true_value).chain(f.false_value.iter()))
85
+ }
86
+ Expression::Function(f) if f.name.eq_ignore_ascii_case("NULLIF") && f.args.len() == 2 => {
87
+ datafusion_nullif_kind(&f.args[0], &f.args[1])
88
+ }
89
+ Expression::NullIf(f) => datafusion_nullif_kind(&f.this, &f.expression),
90
+ // Do not assume functions such as ROUND preserve numeric types across
91
+ // dialects: DuckDB ROUND(integer) is integer, DataFusion's is floating.
92
+ _ => expression_numeric_kind(expr),
93
+ }
94
+ }
95
+
96
+ fn datafusion_branch_kind<'a>(branches: impl Iterator<Item = &'a Expression>) -> NumericKind {
97
+ branches
98
+ .filter(|expr| !matches!(expr, Expression::Null(_)))
99
+ .map(datafusion_numeric_kind)
100
+ .reduce(combine)
101
+ .unwrap_or(NumericKind::Unknown)
102
+ }
103
+
104
+ fn datafusion_nullif_kind(left: &Expression, right: &Expression) -> NumericKind {
105
+ let left_kind = datafusion_numeric_kind(left);
106
+ // DuckDB preserves the first argument's type, but DataFusion coerces both
107
+ // arguments to a common type. Mixed numeric types need an explicit cast.
108
+ if left_kind == datafusion_numeric_kind(right) || matches!(right, Expression::Null(_)) {
109
+ left_kind
110
+ } else {
111
+ NumericKind::Unknown
112
+ }
113
+ }
114
+
115
+ fn as_double(expr: Expression) -> Expression {
116
+ super::operators::cast_expr(
117
+ expr,
118
+ DataType::Double {
119
+ precision: None,
120
+ scale: None,
121
+ },
122
+ )
123
+ }
124
+
125
+ fn unresolved_division(target: DialectType) -> crate::error::Error {
126
+ crate::error::Error::unsupported(
127
+ "DuckDB // with unresolved operand types; use explicit numeric casts",
128
+ target.to_string(),
129
+ )
130
+ }
131
+
132
+ fn prepare_datafusion_division(expr: Expression) -> Result<Expression> {
133
+ // Stop the outer traversal at each outermost IntDiv. Rewrite that complete
134
+ // subtree once, bottom-up, including casts, functions, CASE and subqueries.
135
+ // Replacement nodes are not revisited, so a generated Div cannot be
136
+ // mistaken for a source `/`, even across nested integer divisions.
137
+ crate::traversal::transform_with_dispatch(
138
+ expr,
139
+ &Ok,
140
+ &|expr| !matches!(expr, Expression::IntDiv(_)),
141
+ &|expr, _| {
142
+ crate::traversal::transform_all(expr, &|mut expr| {
143
+ match &mut expr {
144
+ Expression::Div(b) => {
145
+ // Integer, decimal and unresolved source operands need
146
+ // floating arithmetic. Preserve an existing FLOAT operand
147
+ // rather than widening DuckDB's FLOAT/FLOAT division.
148
+ if datafusion_numeric_kind(&b.left) != NumericKind::Float
149
+ && datafusion_numeric_kind(&b.right) != NumericKind::Float
150
+ {
151
+ b.left =
152
+ as_double(std::mem::replace(&mut b.left, Expression::number(0)));
153
+ }
154
+ }
155
+ Expression::Cast(c) | Expression::TryCast(c) | Expression::SafeCast(c)
156
+ if super::scalar::data_type_numeric_kind(&c.to) == NumericKind::Integer
157
+ && matches!(
158
+ datafusion_numeric_kind(&c.this),
159
+ NumericKind::Float | NumericKind::Decimal
160
+ ) =>
161
+ {
162
+ // DuckDB rounds numeric casts to integers; DataFusion
163
+ // truncates. This also matters after a nested source `/`.
164
+ c.this = Expression::Round(Box::new(RoundFunc {
165
+ this: std::mem::replace(&mut c.this, Expression::number(0)),
166
+ decimals: Some(Expression::number(0)),
167
+ }));
168
+ }
169
+ Expression::IntDiv(_) => {
170
+ let Expression::IntDiv(mut division) = expr else {
171
+ unreachable!()
172
+ };
173
+ let kind = combine(
174
+ datafusion_numeric_kind(&division.this),
175
+ datafusion_numeric_kind(&division.expression),
176
+ );
177
+ if kind == NumericKind::Unknown {
178
+ return Err(unresolved_division(DialectType::DataFusion));
179
+ }
180
+ if kind == NumericKind::Decimal {
181
+ division.this = as_double(division.this);
182
+ }
183
+ return Ok(Expression::Div(Box::new(BinaryOp::new(
184
+ division.this,
185
+ Expression::Function(Box::new(Function::new(
186
+ "NULLIF".to_string(),
187
+ vec![division.expression, Expression::number(0)],
188
+ ))),
189
+ ))));
190
+ }
191
+ _ => {}
192
+ }
193
+ Ok(expr)
194
+ })
195
+ },
196
+ )
197
+ }
198
+
199
+ pub(in crate::dialects) fn prepare_integer_division(
200
+ expr: Expression,
201
+ source: DialectType,
202
+ target: DialectType,
203
+ ) -> Result<Expression> {
204
+ if source != DialectType::DuckDB || target == DialectType::DuckDB {
205
+ return Ok(expr);
206
+ }
207
+
208
+ if target == DialectType::DataFusion {
209
+ return prepare_datafusion_division(expr);
210
+ }
211
+
212
+ // Visit every physical child, including typed function arguments and both
213
+ // operands of nested IntDiv nodes, before lowering the enclosing operator.
214
+ crate::traversal::transform_all(expr, &|expr| {
215
+ let Expression::IntDiv(mut division) = expr else {
216
+ return Ok(expr);
217
+ };
218
+ let left_kind = numeric_kind(&division.this);
219
+ let right_kind = numeric_kind(&division.expression);
220
+ let kind = combine(left_kind, right_kind);
221
+
222
+ if kind == NumericKind::Unknown {
223
+ return Err(unresolved_division(target));
224
+ }
225
+
226
+ // NULLIF evaluates the divisor once and preserves NULL on zero for
227
+ // literals, casts, computed expressions, and values only known at runtime.
228
+ division.expression = Expression::Function(Box::new(Function::new(
229
+ "NULLIF".to_string(),
230
+ vec![division.expression, Expression::number(0)],
231
+ )));
232
+
233
+ if kind != NumericKind::Integer {
234
+ // DuckDB decimal division produces DOUBLE, whereas some targets
235
+ // keep decimal arithmetic (and SQLite may treat DECIMAL as INTEGER).
236
+ // An explicitly floating operand already establishes float division.
237
+ if kind == NumericKind::Decimal {
238
+ division.this = super::operators::cast_expr(
239
+ division.this,
240
+ DataType::Double {
241
+ precision: None,
242
+ scale: None,
243
+ },
244
+ );
245
+ }
246
+ return Ok(Expression::Div(Box::new(BinaryOp::new(
247
+ division.this,
248
+ division.expression,
249
+ ))));
250
+ }
251
+
252
+ // Only use IntDiv where generation has a native or exact lowering.
253
+ // A generic DIV(...) call is invalid in several other targets.
254
+ if !matches!(
255
+ target,
256
+ DialectType::PostgreSQL
257
+ | DialectType::BigQuery
258
+ | DialectType::ClickHouse
259
+ | DialectType::SQLite
260
+ | DialectType::Vertica
261
+ | DialectType::Hive
262
+ | DialectType::Spark
263
+ | DialectType::Databricks
264
+ ) {
265
+ return Err(crate::error::Error::unsupported(
266
+ "DuckDB integer // conversion",
267
+ target.to_string(),
268
+ ));
269
+ }
270
+ Ok(Expression::IntDiv(division))
271
+ })
272
+ }
@@ -15738,7 +15738,8 @@ pub(super) fn normalize_bigquery_function(
15738
15738
  | DialectType::Athena
15739
15739
  | DialectType::Snowflake
15740
15740
  | DialectType::TSQL
15741
- | DialectType::Fabric => {
15741
+ | DialectType::Fabric
15742
+ | DialectType::DataFusion => {
15742
15743
  let x = args.remove(0);
15743
15744
  let y = args.remove(0);
15744
15745
  // Wrap complex expressions in parens to preserve precedence
@@ -3476,20 +3476,28 @@ impl Generator {
3476
3476
  Ok(())
3477
3477
  } else if is_native_slash_op {
3478
3478
  // DuckDB and Vertica use // operator for integer division
3479
- self.generate_expression(&f.this)?;
3479
+ self.generate_infix_operand(InfixOperator::Div, &f.this, OperandSide::Left)?;
3480
3480
  self.write(" // ");
3481
- self.generate_expression(&f.expression)?;
3481
+ self.generate_infix_operand(
3482
+ InfixOperator::Div,
3483
+ &f.expression,
3484
+ OperandSide::Right,
3485
+ )?;
3482
3486
  Ok(())
3483
3487
  } else if matches!(
3484
3488
  self.config.dialect,
3485
3489
  Some(DialectType::Hive | DialectType::Spark | DialectType::Databricks)
3486
3490
  ) {
3487
3491
  // Hive/Spark use DIV as an infix operator
3488
- self.generate_expression(&f.this)?;
3492
+ self.generate_infix_operand(InfixOperator::Div, &f.this, OperandSide::Left)?;
3489
3493
  self.write(" ");
3490
3494
  self.write_keyword("DIV");
3491
3495
  self.write(" ");
3492
- self.generate_expression(&f.expression)?;
3496
+ self.generate_infix_operand(
3497
+ InfixOperator::Div,
3498
+ &f.expression,
3499
+ OperandSide::Right,
3500
+ )?;
3493
3501
  Ok(())
3494
3502
  } else {
3495
3503
  // Other dialects use DIV function
@@ -19030,13 +19038,14 @@ impl Generator {
19030
19038
  matches!(self.config.dialect, Some(DialectType::ClickHouse))
19031
19039
  }
19032
19040
 
19033
- /// Generate MOD function - uses % operator for dialects that prefer or require it.
19034
- fn generate_mod_func(&mut self, f: &crate::expressions::BinaryFunc) -> Result<()> {
19035
- use crate::dialects::DialectType;
19041
+ /// Whether `MOD(x, y)` is rendered as the infix `x % y` for this dialect.
19042
+ fn mod_func_uses_percent_operator(&self) -> bool {
19043
+ Self::mod_func_uses_percent_for(self.config.dialect)
19044
+ }
19036
19045
 
19037
- // Several dialects prefer or require x % y instead of MOD(x, y).
19038
- let use_percent_operator = matches!(
19039
- self.config.dialect,
19046
+ fn mod_func_uses_percent_for(dialect: Option<DialectType>) -> bool {
19047
+ matches!(
19048
+ dialect,
19040
19049
  Some(DialectType::Snowflake)
19041
19050
  | Some(DialectType::MySQL)
19042
19051
  | Some(DialectType::Presto)
@@ -19049,11 +19058,20 @@ impl Generator {
19049
19058
  | Some(DialectType::Athena)
19050
19059
  | Some(DialectType::TSQL)
19051
19060
  | Some(DialectType::Fabric)
19052
- );
19061
+ | Some(DialectType::DataFusion)
19062
+ )
19063
+ }
19064
+
19065
+ /// Generate MOD function - uses % operator for dialects that prefer or require it.
19066
+ fn generate_mod_func(&mut self, f: &crate::expressions::BinaryFunc) -> Result<()> {
19067
+ // Several dialects prefer or require x % y instead of MOD(x, y).
19068
+ let use_percent_operator = self.mod_func_uses_percent_operator();
19053
19069
 
19054
19070
  if use_percent_operator {
19055
19071
  // MOD(a, b) treats both arguments as grouped expressions. When
19056
- // lowering to an infix operator, keep binary arguments grouped.
19072
+ // lowering to an infix operator, keep binary arguments grouped,
19073
+ // including operators introduced when rendering either argument.
19074
+ let dialect = self.config.dialect;
19057
19075
  let needs_paren = |e: &Expression| {
19058
19076
  matches!(
19059
19077
  e,
@@ -19063,6 +19081,11 @@ impl Generator {
19063
19081
  | Expression::Div(_)
19064
19082
  | Expression::Mod(_)
19065
19083
  | Expression::ModFunc(_)
19084
+ ) || Self::infix_operand_needs_parentheses(
19085
+ dialect,
19086
+ InfixOperator::Mod,
19087
+ e,
19088
+ OperandSide::Right,
19066
19089
  )
19067
19090
  };
19068
19091
  if needs_paren(&f.this) {
@@ -25720,7 +25743,12 @@ impl Generator {
25720
25743
  infix_operator: Option<InfixOperator>,
25721
25744
  ) -> Result<()> {
25722
25745
  let wrap_left = infix_operator.is_some_and(|parent| {
25723
- Self::infix_operand_needs_parentheses(parent, &op.left, OperandSide::Left)
25746
+ Self::infix_operand_needs_parentheses(
25747
+ self.config.dialect,
25748
+ parent,
25749
+ &op.left,
25750
+ OperandSide::Left,
25751
+ )
25724
25752
  });
25725
25753
  if wrap_left {
25726
25754
  self.write("(");
@@ -25798,7 +25826,12 @@ impl Generator {
25798
25826
  }
25799
25827
  self.write_space();
25800
25828
  let wrap_right = infix_operator.is_some_and(|parent| {
25801
- Self::infix_operand_needs_parentheses(parent, &op.right, OperandSide::Right)
25829
+ Self::infix_operand_needs_parentheses(
25830
+ self.config.dialect,
25831
+ parent,
25832
+ &op.right,
25833
+ OperandSide::Right,
25834
+ )
25802
25835
  });
25803
25836
  if wrap_right {
25804
25837
  self.write("(");
@@ -25823,8 +25856,12 @@ impl Generator {
25823
25856
 
25824
25857
  let generate_term =
25825
25858
  |generator: &mut Self, term: &Expression, side: OperandSide| -> Result<()> {
25826
- let should_wrap_for_precedence =
25827
- Self::infix_operand_needs_parentheses(connector.infix_operator(), term, side);
25859
+ let should_wrap_for_precedence = Self::infix_operand_needs_parentheses(
25860
+ generator.config.dialect,
25861
+ connector.infix_operator(),
25862
+ term,
25863
+ side,
25864
+ );
25828
25865
  let should_wrap_for_clickhouse = matches!(connector, ConnectorOperator::Or)
25829
25866
  && matches!(generator.config.dialect, Some(DialectType::ClickHouse))
25830
25867
  && matches!(
@@ -25903,8 +25940,32 @@ impl Generator {
25903
25940
  }
25904
25941
  }
25905
25942
 
25906
- fn infix_operator(expression: &Expression) -> Option<InfixOperator> {
25943
+ fn infix_operator(
25944
+ dialect: Option<DialectType>,
25945
+ expression: &Expression,
25946
+ ) -> Option<InfixOperator> {
25907
25947
  match expression {
25948
+ // `MOD(x, y)` lowered to `x % y` binds like the infix operator, so as an
25949
+ // operand it needs the same parentheses (`2 * MOD(5, 3)` -> `2 * (5 % 3)`).
25950
+ Expression::ModFunc(_) if Self::mod_func_uses_percent_for(dialect) => {
25951
+ Some(InfixOperator::Mod)
25952
+ }
25953
+ // IntDiv is atomic when rendered as a function or CAST, but // and
25954
+ // DIV have the same precedence and associativity as division.
25955
+ Expression::IntDiv(_)
25956
+ if matches!(
25957
+ dialect,
25958
+ Some(
25959
+ DialectType::DuckDB
25960
+ | DialectType::Vertica
25961
+ | DialectType::Hive
25962
+ | DialectType::Spark
25963
+ | DialectType::Databricks
25964
+ )
25965
+ ) =>
25966
+ {
25967
+ Some(InfixOperator::Div)
25968
+ }
25908
25969
  Expression::Or(_) => Some(InfixOperator::Or),
25909
25970
  Expression::Xor(_) => Some(InfixOperator::Xor),
25910
25971
  Expression::And(_) => Some(InfixOperator::And),
@@ -25940,6 +26001,7 @@ impl Generator {
25940
26001
  }
25941
26002
 
25942
26003
  fn infix_operand_needs_parentheses(
26004
+ dialect: Option<DialectType>,
25943
26005
  parent: InfixOperator,
25944
26006
  child: &Expression,
25945
26007
  side: OperandSide,
@@ -25948,7 +26010,22 @@ impl Generator {
25948
26010
  return false;
25949
26011
  }
25950
26012
 
25951
- let Some(child_operator) = Self::infix_operator(child) else {
26013
+ // Bitwise precedence differs between dialects. Group these operands
26014
+ // explicitly when emitting arithmetic, including a lowered MOD call.
26015
+ if parent.is_arithmetic()
26016
+ && matches!(
26017
+ child,
26018
+ Expression::BitwiseAnd(_)
26019
+ | Expression::BitwiseOr(_)
26020
+ | Expression::BitwiseXor(_)
26021
+ | Expression::BitwiseLeftShift(_)
26022
+ | Expression::BitwiseRightShift(_)
26023
+ )
26024
+ {
26025
+ return true;
26026
+ }
26027
+
26028
+ let Some(child_operator) = Self::infix_operator(dialect, child) else {
25952
26029
  return false;
25953
26030
  };
25954
26031
 
@@ -25974,7 +26051,8 @@ impl Generator {
25974
26051
  expression: &Expression,
25975
26052
  side: OperandSide,
25976
26053
  ) -> Result<()> {
25977
- let needs_parentheses = Self::infix_operand_needs_parentheses(parent, expression, side);
26054
+ let needs_parentheses =
26055
+ Self::infix_operand_needs_parentheses(self.config.dialect, parent, expression, side);
25978
26056
  if needs_parentheses {
25979
26057
  self.write("(");
25980
26058
  }
@@ -26155,7 +26233,12 @@ impl Generator {
26155
26233
  infix_operator: Option<InfixOperator>,
26156
26234
  ) -> Result<()> {
26157
26235
  let wrap_left = infix_operator.is_some_and(|parent| {
26158
- Self::infix_operand_needs_parentheses(parent, &op.left, OperandSide::Left)
26236
+ Self::infix_operand_needs_parentheses(
26237
+ self.config.dialect,
26238
+ parent,
26239
+ &op.left,
26240
+ OperandSide::Left,
26241
+ )
26159
26242
  });
26160
26243
  if wrap_left {
26161
26244
  self.write("(");
@@ -26212,7 +26295,12 @@ impl Generator {
26212
26295
  }
26213
26296
  self.write_space();
26214
26297
  let wrap_right = infix_operator.is_some_and(|parent| {
26215
- Self::infix_operand_needs_parentheses(parent, &op.right, OperandSide::Right)
26298
+ Self::infix_operand_needs_parentheses(
26299
+ self.config.dialect,
26300
+ parent,
26301
+ &op.right,
26302
+ OperandSide::Right,
26303
+ )
26216
26304
  });
26217
26305
  if wrap_right {
26218
26306
  self.write("(");
@@ -26253,7 +26341,18 @@ impl Generator {
26253
26341
  self.write_space();
26254
26342
  }
26255
26343
  }
26256
- self.generate_expression(&op.this)
26344
+ // Function-like AST nodes such as MOD and DIV can render as infix
26345
+ // operators. Preserve their grouping under a symbolic unary operator.
26346
+ let needs_parens = matches!(operator, "-" | "~")
26347
+ && Self::infix_operator(self.config.dialect, &op.this).is_some();
26348
+ if needs_parens {
26349
+ self.write("(");
26350
+ }
26351
+ self.generate_expression(&op.this)?;
26352
+ if needs_parens {
26353
+ self.write(")");
26354
+ }
26355
+ Ok(())
26257
26356
  }
26258
26357
 
26259
26358
  fn generate_in(&mut self, in_expr: &In) -> Result<()> {