polyglot-sql 0.5.5__tar.gz → 0.5.7__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 (184) hide show
  1. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/Cargo.lock +5 -5
  2. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/Cargo.toml +1 -1
  3. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/PKG-INFO +1 -1
  4. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/Cargo.toml +1 -1
  5. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/dialects/bigquery.rs +20 -0
  6. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/dialects/clickhouse.rs +22 -0
  7. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/dialects/databricks.rs +99 -45
  8. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/dialects/exasol.rs +96 -1
  9. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/dialects/mod.rs +11 -14
  10. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/dialects/mysql.rs +159 -2
  11. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/dialects/singlestore.rs +43 -0
  12. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/generator.rs +131 -16
  13. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/lineage.rs +1003 -21
  14. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/parser.rs +595 -40
  15. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/scope.rs +96 -16
  16. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/tests/clickhouse_regression.rs +80 -0
  17. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/tests/custom_clickhouse_coverage.rs +22 -0
  18. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/tests/custom_clickhouse_parser.rs +3 -0
  19. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql-python/tests/test_lineage.py +36 -6
  20. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/README.md +0 -0
  21. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/README.md +0 -0
  22. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/benches/in_list.rs +0 -0
  23. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/benches/parsing.rs +0 -0
  24. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/benches/rust_parsing.rs +0 -0
  25. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/benches/transpile.rs +0 -0
  26. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/examples/basic_usage.rs +0 -0
  27. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/examples/bench_json.rs +0 -0
  28. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/ast_json.rs +0 -0
  29. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/ast_transforms.rs +0 -0
  30. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/builder.rs +0 -0
  31. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/dialects/athena.rs +0 -0
  32. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/dialects/cockroachdb.rs +0 -0
  33. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/dialects/datafusion.rs +0 -0
  34. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/dialects/doris.rs +0 -0
  35. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/dialects/dremio.rs +0 -0
  36. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/dialects/drill.rs +0 -0
  37. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/dialects/druid.rs +0 -0
  38. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/dialects/duckdb.rs +0 -0
  39. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/dialects/dune.rs +0 -0
  40. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/dialects/fabric.rs +0 -0
  41. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/dialects/generic.rs +0 -0
  42. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/dialects/hive.rs +0 -0
  43. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/dialects/materialize.rs +0 -0
  44. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/dialects/oracle.rs +0 -0
  45. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/dialects/postgres.rs +0 -0
  46. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/dialects/presto.rs +0 -0
  47. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/dialects/redshift.rs +0 -0
  48. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/dialects/risingwave.rs +0 -0
  49. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/dialects/snowflake.rs +0 -0
  50. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/dialects/solr.rs +0 -0
  51. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/dialects/spark.rs +0 -0
  52. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/dialects/sqlite.rs +0 -0
  53. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/dialects/starrocks.rs +0 -0
  54. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/dialects/tableau.rs +0 -0
  55. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/dialects/teradata.rs +0 -0
  56. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/dialects/tidb.rs +0 -0
  57. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/dialects/trino.rs +0 -0
  58. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/dialects/tsql.rs +0 -0
  59. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/diff.rs +0 -0
  60. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/error.rs +0 -0
  61. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/expressions.rs +0 -0
  62. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/function_catalog.rs +0 -0
  63. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/function_registry.rs +0 -0
  64. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/helper.rs +0 -0
  65. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/lib.rs +0 -0
  66. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/openlineage.rs +0 -0
  67. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/optimizer/annotate_types.rs +0 -0
  68. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/optimizer/canonicalize.rs +0 -0
  69. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/optimizer/eliminate_ctes.rs +0 -0
  70. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/optimizer/eliminate_joins.rs +0 -0
  71. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/optimizer/isolate_table_selects.rs +0 -0
  72. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/optimizer/mod.rs +0 -0
  73. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/optimizer/normalize.rs +0 -0
  74. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/optimizer/normalize_identifiers.rs +0 -0
  75. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/optimizer/optimize_joins.rs +0 -0
  76. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/optimizer/optimizer.rs +0 -0
  77. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/optimizer/pushdown_predicates.rs +0 -0
  78. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/optimizer/pushdown_projections.rs +0 -0
  79. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/optimizer/qualify_columns.rs +0 -0
  80. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/optimizer/qualify_tables.rs +0 -0
  81. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/optimizer/simplify.rs +0 -0
  82. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/optimizer/subquery.rs +0 -0
  83. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/planner.rs +0 -0
  84. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/query_analysis.rs +0 -0
  85. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/resolver.rs +0 -0
  86. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/schema.rs +0 -0
  87. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/time.rs +0 -0
  88. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/tokens.rs +0 -0
  89. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/transforms.rs +0 -0
  90. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/traversal.rs +0 -0
  91. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/trie.rs +0 -0
  92. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/validation/tests.rs +0 -0
  93. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/src/validation.rs +0 -0
  94. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/tests/analyze_failures.rs +0 -0
  95. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/tests/common/known_failures.rs +0 -0
  96. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/tests/common/mod.rs +0 -0
  97. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/tests/common/test_data.rs +0 -0
  98. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/tests/common/test_runner.rs +0 -0
  99. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/tests/custom_dialect.rs +0 -0
  100. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/tests/custom_dialect_tests.rs +0 -0
  101. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/tests/custom_fixtures/datafusion/ddl.json +0 -0
  102. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/tests/custom_fixtures/datafusion/dml.json +0 -0
  103. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/tests/custom_fixtures/datafusion/functions.json +0 -0
  104. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/tests/custom_fixtures/datafusion/identity.json +0 -0
  105. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/tests/custom_fixtures/datafusion/operators.json +0 -0
  106. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/tests/custom_fixtures/datafusion/select.json +0 -0
  107. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/tests/custom_fixtures/datafusion/transpilation.json +0 -0
  108. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/tests/custom_fixtures/datafusion/types.json +0 -0
  109. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/tests/data_type_api.rs +0 -0
  110. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/tests/deep_nesting_regression.rs +0 -0
  111. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/tests/dialect_matrix.rs +0 -0
  112. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/tests/error_handling.rs +0 -0
  113. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/tests/fabric_regression.rs +0 -0
  114. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/tests/fabric_tpch_regression.rs +0 -0
  115. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/tests/identity_roundtrip.rs +0 -0
  116. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/tests/issue201_regression_test.rs +0 -0
  117. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/tests/issue210_regression_test.rs +0 -0
  118. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/tests/issue226_regression_test.rs +0 -0
  119. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/tests/issue227_strict_unsupported.rs +0 -0
  120. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/tests/postgres_sqlite_regression.rs +0 -0
  121. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/tests/query_analysis.rs +0 -0
  122. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/tests/query_analysis_regression.rs +0 -0
  123. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/tests/snowflake_regression_test.rs +0 -0
  124. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/tests/sqlglot_compat.rs +0 -0
  125. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/tests/sqlglot_dialect_identity.rs +0 -0
  126. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/tests/sqlglot_identity.rs +0 -0
  127. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/tests/sqlglot_identity_detailed.rs +0 -0
  128. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/tests/sqlglot_parser.rs +0 -0
  129. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/tests/sqlglot_pretty.rs +0 -0
  130. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/tests/sqlglot_transpilation.rs +0 -0
  131. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/tests/sqlglot_transpile.rs +0 -0
  132. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/tests/tpch_transpile_stack.rs +0 -0
  133. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/tests/transform_regression.rs +0 -0
  134. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql/tests/tsql_regression.rs +0 -0
  135. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql-function-catalogs/Cargo.toml +0 -0
  136. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql-function-catalogs/README.md +0 -0
  137. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql-function-catalogs/src/clickhouse.rs +0 -0
  138. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql-function-catalogs/src/duckdb.rs +0 -0
  139. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql-function-catalogs/src/lib.rs +0 -0
  140. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql-function-catalogs/tools/clickhouse/extract_functions.py +0 -0
  141. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql-function-catalogs/tools/duckdb/extract_functions.py +0 -0
  142. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql-python/Cargo.toml +0 -0
  143. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql-python/README.md +0 -0
  144. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql-python/docs/api.md +0 -0
  145. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql-python/docs/index.md +0 -0
  146. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql-python/mkdocs.yml +0 -0
  147. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql-python/src/annotate_types.rs +0 -0
  148. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql-python/src/dialects.rs +0 -0
  149. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql-python/src/diff.rs +0 -0
  150. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql-python/src/errors.rs +0 -0
  151. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql-python/src/expr.rs +0 -0
  152. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql-python/src/expr_types.rs +0 -0
  153. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql-python/src/format.rs +0 -0
  154. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql-python/src/generate.rs +0 -0
  155. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql-python/src/helpers.rs +0 -0
  156. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql-python/src/lib.rs +0 -0
  157. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql-python/src/lineage.rs +0 -0
  158. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql-python/src/openlineage.rs +0 -0
  159. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql-python/src/optimize.rs +0 -0
  160. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql-python/src/parse.rs +0 -0
  161. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql-python/src/query_analysis.rs +0 -0
  162. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql-python/src/tokenize.rs +0 -0
  163. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql-python/src/transforms.rs +0 -0
  164. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql-python/src/transpile.rs +0 -0
  165. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql-python/src/types.rs +0 -0
  166. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql-python/src/validate.rs +0 -0
  167. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql-python/tests/conftest.py +0 -0
  168. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql-python/tests/test_compat.py +0 -0
  169. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql-python/tests/test_dialects.py +0 -0
  170. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql-python/tests/test_diff.py +0 -0
  171. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql-python/tests/test_expression.py +0 -0
  172. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql-python/tests/test_format.py +0 -0
  173. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql-python/tests/test_generate.py +0 -0
  174. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql-python/tests/test_optimize.py +0 -0
  175. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql-python/tests/test_parse.py +0 -0
  176. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql-python/tests/test_query_analysis.py +0 -0
  177. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql-python/tests/test_transforms.py +0 -0
  178. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql-python/tests/test_transpile.py +0 -0
  179. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql-python/tests/test_validate.py +0 -0
  180. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/crates/polyglot-sql-python/uv.lock +0 -0
  181. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/pyproject.toml +0 -0
  182. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/python/polyglot_sql/__init__.py +0 -0
  183. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/python/polyglot_sql/__init__.pyi +0 -0
  184. {polyglot_sql-0.5.5 → polyglot_sql-0.5.7}/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.5.5"
608
+ version = "0.5.7"
609
609
  dependencies = [
610
610
  "criterion",
611
611
  "once_cell",
@@ -621,7 +621,7 @@ dependencies = [
621
621
 
622
622
  [[package]]
623
623
  name = "polyglot-sql-ffi"
624
- version = "0.5.5"
624
+ version = "0.5.7"
625
625
  dependencies = [
626
626
  "cbindgen",
627
627
  "polyglot-sql",
@@ -631,11 +631,11 @@ dependencies = [
631
631
 
632
632
  [[package]]
633
633
  name = "polyglot-sql-function-catalogs"
634
- version = "0.5.5"
634
+ version = "0.5.7"
635
635
 
636
636
  [[package]]
637
637
  name = "polyglot-sql-python"
638
- version = "0.5.5"
638
+ version = "0.5.7"
639
639
  dependencies = [
640
640
  "polyglot-sql",
641
641
  "pyo3",
@@ -646,7 +646,7 @@ dependencies = [
646
646
 
647
647
  [[package]]
648
648
  name = "polyglot-sql-wasm"
649
- version = "0.5.5"
649
+ version = "0.5.7"
650
650
  dependencies = [
651
651
  "console_error_panic_hook",
652
652
  "js-sys",
@@ -6,7 +6,7 @@ exclude = [
6
6
  ]
7
7
 
8
8
  [workspace.package]
9
- version = "0.5.5"
9
+ version = "0.5.7"
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.5.5
3
+ Version: 0.5.7
4
4
  Classifier: Development Status :: 4 - Beta
5
5
  Classifier: Intended Audience :: Developers
6
6
  Classifier: License :: OSI Approved :: MIT License
@@ -106,7 +106,7 @@ thiserror = { workspace = true }
106
106
  unicode-segmentation = { workspace = true }
107
107
  stacker = { version = "0.1", optional = true }
108
108
  ts-rs = { version = "12.0", features = ["serde-compat"], optional = true }
109
- polyglot-sql-function-catalogs = { path = "../polyglot-sql-function-catalogs", version = "0.5.5", optional = true, default-features = false }
109
+ polyglot-sql-function-catalogs = { path = "../polyglot-sql-function-catalogs", version = "0.5.7", optional = true, default-features = false }
110
110
 
111
111
  [dev-dependencies]
112
112
  pretty_assertions = "1.4"
@@ -104,6 +104,26 @@ impl DialectImpl for BigQueryDialect {
104
104
  // ===== Data Type Mappings =====
105
105
  Expression::DataType(dt) => self.transform_data_type(dt),
106
106
 
107
+ Expression::Table(mut table)
108
+ if table.catalog.is_none()
109
+ && table.alias.is_none()
110
+ && table.schema.as_ref().map_or(false, |schema| {
111
+ schema.quoted && schema.name.contains("INFORMATION_SCHEMA")
112
+ }) =>
113
+ {
114
+ let schema = table.schema.take().expect("schema checked above");
115
+ let old_name = table.name.clone();
116
+ let alias = old_name.name.clone();
117
+ table.name = Identifier {
118
+ name: format!("{}.{}", schema.name, old_name.name),
119
+ quoted: true,
120
+ trailing_comments: old_name.trailing_comments,
121
+ span: old_name.span,
122
+ };
123
+ table.alias = Some(Identifier::new(alias));
124
+ Ok(Expression::Table(table))
125
+ }
126
+
107
127
  // ===== Null handling =====
108
128
  // IFNULL is native to BigQuery - keep as-is for identity
109
129
  Expression::IfNull(f) => Ok(Expression::IfNull(f)),
@@ -445,6 +445,17 @@ impl ClickHouseDialect {
445
445
  }
446
446
  self.transform_expr(expr)
447
447
  }
448
+ "XOR" if f.args.len() >= 2 => {
449
+ let mut iter = f.args.into_iter().map(Self::wrap_nested_xor_arg);
450
+ let mut expr = iter.next().unwrap();
451
+ for arg in iter {
452
+ expr = Expression::Function(Box::new(Function::new(
453
+ f.name.clone(),
454
+ vec![expr, arg],
455
+ )));
456
+ }
457
+ Ok(expr)
458
+ }
448
459
  // TYPEOF -> toTypeName in ClickHouse
449
460
  "TYPEOF" => Ok(Expression::Function(Box::new(Function::new(
450
461
  "toTypeName".to_string(),
@@ -668,4 +679,15 @@ impl ClickHouseDialect {
668
679
  fn transform_cast(&self, c: Cast) -> Result<Expression> {
669
680
  Ok(Expression::Cast(Box::new(c)))
670
681
  }
682
+
683
+ fn wrap_nested_xor_arg(expr: Expression) -> Expression {
684
+ if matches!(&expr, Expression::Function(f) if f.name.eq_ignore_ascii_case("XOR")) {
685
+ Expression::Paren(Box::new(Paren {
686
+ this: expr,
687
+ trailing_comments: Vec::new(),
688
+ }))
689
+ } else {
690
+ expr
691
+ }
692
+ }
671
693
  }
@@ -10,8 +10,8 @@
10
10
  use super::{DialectImpl, DialectType};
11
11
  use crate::error::Result;
12
12
  use crate::expressions::{
13
- AggregateFunction, Cast, DataType, Expression, Function, JSONExtract, Literal, UnaryFunc,
14
- VarArgFunc,
13
+ AggregateFunction, Cast, DataType, DateAddFunc, Expression, Function, IntervalUnit, Literal,
14
+ UnaryFunc, VarArgFunc,
15
15
  };
16
16
  #[cfg(feature = "generate")]
17
17
  use crate::generator::GeneratorConfig;
@@ -181,6 +181,9 @@ impl DialectImpl for DatabricksDialect {
181
181
  ))))
182
182
  }
183
183
 
184
+ // DateAdd -> native Databricks DATE_ADD forms.
185
+ Expression::DateAdd(f) => Ok(Self::transform_date_add(*f)),
186
+
184
187
  // Pass through everything else
185
188
  _ => Ok(expr),
186
189
  }
@@ -463,13 +466,29 @@ impl DatabricksDialect {
463
466
  // DATE_TRUNC is native in Databricks
464
467
  "DATE_TRUNC" => Ok(Expression::Function(Box::new(f))),
465
468
 
466
- // DATEADD is native in Databricks - uppercase the unit if present
469
+ // DATEADD normalizes to Databricks DATE_ADD with an uppercased unit.
467
470
  "DATEADD" => {
468
- let transformed_args = self.uppercase_first_arg_if_identifier(f.args);
469
- Ok(Expression::Function(Box::new(Function::new(
470
- "DATEADD".to_string(),
471
- transformed_args,
472
- ))))
471
+ if f.args.len() == 2 {
472
+ Ok(Expression::Function(Box::new(Function::new(
473
+ "DATE_ADD".to_string(),
474
+ f.args,
475
+ ))))
476
+ } else {
477
+ let transformed_args = self.uppercase_first_arg_if_identifier(f.args);
478
+ let function_name = if matches!(
479
+ transformed_args.first(),
480
+ Some(Expression::Identifier(unit))
481
+ if unit.name.eq_ignore_ascii_case("WEEK")
482
+ ) {
483
+ "DATEADD"
484
+ } else {
485
+ "DATE_ADD"
486
+ };
487
+ Ok(Expression::Function(Box::new(Function::new(
488
+ function_name.to_string(),
489
+ transformed_args,
490
+ ))))
491
+ }
473
492
  }
474
493
 
475
494
  // DATE_ADD -> DATEADD in Databricks (2-arg form only)
@@ -554,48 +573,16 @@ impl DatabricksDialect {
554
573
  // JSON_EXTRACT_SCALAR -> same handling
555
574
  "JSON_EXTRACT_SCALAR" => Ok(Expression::Function(Box::new(f))),
556
575
 
557
- // GET_JSON_OBJECT -> colon syntax in Databricks
558
- // GET_JSON_OBJECT(col, '$.path') becomes col:path
576
+ // GET_JSON_OBJECT is native in Databricks.
559
577
  "GET_JSON_OBJECT" if f.args.len() == 2 => {
560
578
  let mut args = f.args;
561
579
  let col = args.remove(0);
562
580
  let path_arg = args.remove(0);
563
581
 
564
- // Extract and strip the $. prefix from the path
565
- let path_expr = match &path_arg {
566
- Expression::Literal(lit)
567
- if matches!(lit.as_ref(), crate::expressions::Literal::String(_)) =>
568
- {
569
- let crate::expressions::Literal::String(s) = lit.as_ref() else {
570
- unreachable!()
571
- };
572
- // Strip leading '$.' if present
573
- let stripped = if s.starts_with("$.") {
574
- &s[2..]
575
- } else if s.starts_with("$") {
576
- &s[1..]
577
- } else {
578
- s.as_str()
579
- };
580
- Expression::Literal(Box::new(crate::expressions::Literal::String(
581
- stripped.to_string(),
582
- )))
583
- }
584
- _ => path_arg,
585
- };
586
-
587
- Ok(Expression::JSONExtract(Box::new(JSONExtract {
588
- this: Box::new(col),
589
- expression: Box::new(path_expr),
590
- only_json_types: None,
591
- expressions: Vec::new(),
592
- variant_extract: Some(Box::new(Expression::true_())),
593
- json_query: None,
594
- option: None,
595
- quote: None,
596
- on_condition: None,
597
- requires_json: None,
598
- })))
582
+ Ok(Expression::Function(Box::new(Function::new(
583
+ "GET_JSON_OBJECT".to_string(),
584
+ vec![col, self.normalize_get_json_object_path(path_arg)],
585
+ ))))
599
586
  }
600
587
 
601
588
  // FROM_JSON is native in Databricks
@@ -998,6 +985,73 @@ impl DatabricksDialect {
998
985
  }
999
986
  args
1000
987
  }
988
+
989
+ fn normalize_get_json_object_path(&self, path_arg: Expression) -> Expression {
990
+ let Expression::Literal(lit) = &path_arg else {
991
+ return path_arg;
992
+ };
993
+ let crate::expressions::Literal::String(path) = lit.as_ref() else {
994
+ return path_arg;
995
+ };
996
+
997
+ let Some(segment) = path.strip_prefix("$.") else {
998
+ return path_arg;
999
+ };
1000
+
1001
+ if segment.is_empty()
1002
+ || segment.contains('.')
1003
+ || segment.contains('[')
1004
+ || segment
1005
+ .chars()
1006
+ .all(|c| c.is_ascii_alphanumeric() || c == '_')
1007
+ {
1008
+ return path_arg;
1009
+ }
1010
+
1011
+ Expression::Literal(Box::new(crate::expressions::Literal::String(format!(
1012
+ "$[\"{}\"]",
1013
+ segment.replace('"', "\\\"")
1014
+ ))))
1015
+ }
1016
+
1017
+ fn transform_date_add(f: DateAddFunc) -> Expression {
1018
+ if f.unit == IntervalUnit::Day {
1019
+ Expression::Function(Box::new(Function::new(
1020
+ "DATE_ADD".to_string(),
1021
+ vec![f.this, f.interval],
1022
+ )))
1023
+ } else {
1024
+ Expression::Function(Box::new(Function::new(
1025
+ "DATE_ADD".to_string(),
1026
+ vec![
1027
+ Expression::Identifier(crate::expressions::Identifier {
1028
+ name: Self::interval_unit_name(f.unit).to_string(),
1029
+ quoted: false,
1030
+ trailing_comments: Vec::new(),
1031
+ span: None,
1032
+ }),
1033
+ f.interval,
1034
+ f.this,
1035
+ ],
1036
+ )))
1037
+ }
1038
+ }
1039
+
1040
+ fn interval_unit_name(unit: IntervalUnit) -> &'static str {
1041
+ match unit {
1042
+ IntervalUnit::Year => "YEAR",
1043
+ IntervalUnit::Quarter => "QUARTER",
1044
+ IntervalUnit::Month => "MONTH",
1045
+ IntervalUnit::Week => "WEEK",
1046
+ IntervalUnit::Day => "DAY",
1047
+ IntervalUnit::Hour => "HOUR",
1048
+ IntervalUnit::Minute => "MINUTE",
1049
+ IntervalUnit::Second => "SECOND",
1050
+ IntervalUnit::Millisecond => "MILLISECOND",
1051
+ IntervalUnit::Microsecond => "MICROSECOND",
1052
+ IntervalUnit::Nanosecond => "NANOSECOND",
1053
+ }
1054
+ }
1001
1055
  }
1002
1056
 
1003
1057
  #[cfg(test)]
@@ -20,7 +20,9 @@
20
20
 
21
21
  use super::{DialectImpl, DialectType};
22
22
  use crate::error::Result;
23
- use crate::expressions::{Expression, Function, ListAggFunc, Literal, VarArgFunc};
23
+ use crate::expressions::{
24
+ BinaryOp, Expression, Function, Identifier, LikeOp, ListAggFunc, Literal, Select, VarArgFunc,
25
+ };
24
26
  #[cfg(feature = "generate")]
25
27
  use crate::generator::GeneratorConfig;
26
28
  use crate::tokens::TokenizerConfig;
@@ -149,6 +151,10 @@ impl DialectImpl for ExasolDialect {
149
151
  // Aggregate function transformations
150
152
  Expression::AggregateFunction(f) => self.transform_aggregate_function(f),
151
153
 
154
+ Expression::Select(select) => Ok(Expression::Select(Box::new(
155
+ self.qualify_local_alias_predicates(*select),
156
+ ))),
157
+
152
158
  // Pass through everything else
153
159
  _ => Ok(expr),
154
160
  }
@@ -157,6 +163,95 @@ impl DialectImpl for ExasolDialect {
157
163
 
158
164
  #[cfg(feature = "transpile")]
159
165
  impl ExasolDialect {
166
+ fn qualify_local_alias_predicates(&self, mut select: Select) -> Select {
167
+ let aliases = Self::select_aliases(&select);
168
+ if aliases.is_empty() {
169
+ return select;
170
+ }
171
+
172
+ if let Some(where_clause) = select.where_clause.as_mut() {
173
+ where_clause.this = Self::qualify_local_alias_expr(where_clause.this.clone(), &aliases);
174
+ }
175
+ if let Some(having) = select.having.as_mut() {
176
+ having.this = Self::qualify_local_alias_expr(having.this.clone(), &aliases);
177
+ }
178
+
179
+ select
180
+ }
181
+
182
+ fn select_aliases(select: &Select) -> std::collections::HashMap<String, Identifier> {
183
+ let mut aliases = std::collections::HashMap::new();
184
+ for expression in &select.expressions {
185
+ if let Expression::Alias(alias) = expression {
186
+ aliases.insert(alias.alias.name.to_ascii_uppercase(), alias.alias.clone());
187
+ }
188
+ }
189
+ aliases
190
+ }
191
+
192
+ fn qualify_local_alias_expr(
193
+ expr: Expression,
194
+ aliases: &std::collections::HashMap<String, Identifier>,
195
+ ) -> Expression {
196
+ match expr {
197
+ Expression::Column(col) if col.table.is_none() => {
198
+ if let Some(alias) = aliases.get(&col.name.name.to_ascii_uppercase()) {
199
+ return Expression::Raw(crate::expressions::Raw {
200
+ sql: format!("LOCAL.{}", alias.name),
201
+ });
202
+ }
203
+ Expression::Column(col)
204
+ }
205
+ Expression::Identifier(id) => {
206
+ if let Some(alias) = aliases.get(&id.name.to_ascii_uppercase()) {
207
+ Expression::Raw(crate::expressions::Raw {
208
+ sql: format!("LOCAL.{}", alias.name),
209
+ })
210
+ } else {
211
+ Expression::Identifier(id)
212
+ }
213
+ }
214
+ Expression::And(op) => Self::qualify_binary(op, aliases, Expression::And),
215
+ Expression::Or(op) => Self::qualify_binary(op, aliases, Expression::Or),
216
+ Expression::Eq(op) => Self::qualify_binary(op, aliases, Expression::Eq),
217
+ Expression::Neq(op) => Self::qualify_binary(op, aliases, Expression::Neq),
218
+ Expression::Lt(op) => Self::qualify_binary(op, aliases, Expression::Lt),
219
+ Expression::Lte(op) => Self::qualify_binary(op, aliases, Expression::Lte),
220
+ Expression::Gt(op) => Self::qualify_binary(op, aliases, Expression::Gt),
221
+ Expression::Gte(op) => Self::qualify_binary(op, aliases, Expression::Gte),
222
+ Expression::Like(op) => Self::qualify_like(op, aliases, Expression::Like),
223
+ Expression::ILike(op) => Self::qualify_like(op, aliases, Expression::ILike),
224
+ Expression::Not(mut op) => {
225
+ op.this = Self::qualify_local_alias_expr(op.this, aliases);
226
+ Expression::Not(op)
227
+ }
228
+ other => other,
229
+ }
230
+ }
231
+
232
+ fn qualify_binary(
233
+ mut op: Box<BinaryOp>,
234
+ aliases: &std::collections::HashMap<String, Identifier>,
235
+ wrap: fn(Box<BinaryOp>) -> Expression,
236
+ ) -> Expression {
237
+ op.left = Self::qualify_local_alias_expr(op.left, aliases);
238
+ op.right = Self::qualify_local_alias_expr(op.right, aliases);
239
+ wrap(op)
240
+ }
241
+
242
+ fn qualify_like(
243
+ mut op: Box<LikeOp>,
244
+ aliases: &std::collections::HashMap<String, Identifier>,
245
+ wrap: fn(Box<LikeOp>) -> Expression,
246
+ ) -> Expression {
247
+ op.left = Self::qualify_local_alias_expr(op.left, aliases);
248
+ op.right = Self::qualify_local_alias_expr(op.right, aliases);
249
+ if let Some(escape) = op.escape.take() {
250
+ op.escape = Some(Self::qualify_local_alias_expr(escape, aliases));
251
+ }
252
+ wrap(op)
253
+ }
254
+
160
255
  fn transform_function(&self, f: Function) -> Result<Expression> {
161
256
  let name_upper = f.name.to_uppercase();
162
257
  match name_upper.as_str() {
@@ -5524,7 +5524,7 @@ impl Dialect {
5524
5524
  Expression::Min(agg) => rewrite_agg_filter!(Min, agg),
5525
5525
  Expression::Max(agg) => rewrite_agg_filter!(Max, agg),
5526
5526
  Expression::ArrayAgg(agg) => rewrite_agg_filter!(ArrayAgg, agg),
5527
- Expression::CountIf(agg) => rewrite_agg_filter!(CountIf, agg),
5527
+ Expression::CountIf(agg) => Ok(Expression::CountIf(agg)),
5528
5528
  Expression::Stddev(agg) => rewrite_agg_filter!(Stddev, agg),
5529
5529
  Expression::StddevPop(agg) => rewrite_agg_filter!(StddevPop, agg),
5530
5530
  Expression::StddevSamp(agg) => rewrite_agg_filter!(StddevSamp, agg),
@@ -5610,7 +5610,10 @@ impl Dialect {
5610
5610
  Expression::Min(agg) => push_agg_filter!(Min, agg),
5611
5611
  Expression::Max(agg) => push_agg_filter!(Max, agg),
5612
5612
  Expression::ArrayAgg(agg) => push_agg_filter!(ArrayAgg, agg),
5613
- Expression::CountIf(agg) => push_agg_filter!(CountIf, agg),
5613
+ Expression::CountIf(mut agg) => {
5614
+ agg.filter = Some(filter);
5615
+ Expression::CountIf(agg)
5616
+ }
5614
5617
  Expression::Stddev(agg) => push_agg_filter!(Stddev, agg),
5615
5618
  Expression::StddevPop(agg) => push_agg_filter!(StddevPop, agg),
5616
5619
  Expression::StddevSamp(agg) => push_agg_filter!(StddevSamp, agg),
@@ -18885,17 +18888,9 @@ impl Dialect {
18885
18888
  vec![date, days],
18886
18889
  ))))
18887
18890
  }
18888
- DialectType::Databricks => {
18889
- // Databricks: DATEADD(DAY, days, date)
18890
- Ok(Expression::Function(Box::new(Function::new(
18891
- "DATEADD".to_string(),
18892
- vec![
18893
- Expression::Identifier(Identifier::new("DAY")),
18894
- days,
18895
- date,
18896
- ],
18897
- ))))
18898
- }
18891
+ DialectType::Databricks => Ok(Expression::Function(Box::new(
18892
+ Function::new("DATE_ADD".to_string(), vec![date, days]),
18893
+ ))),
18899
18894
  DialectType::DuckDB => {
18900
18895
  // DuckDB: CAST(date AS DATE) + INTERVAL days DAY
18901
18896
  let cast_date = Self::ensure_cast_date(date);
@@ -18971,7 +18966,9 @@ impl Dialect {
18971
18966
  // But Databricks DATE_ADD doesn't need this wrapping for TSQL
18972
18967
  let cast_date = if matches!(
18973
18968
  source,
18974
- DialectType::Hive | DialectType::Spark
18969
+ DialectType::Hive
18970
+ | DialectType::Spark
18971
+ | DialectType::Databricks
18975
18972
  ) {
18976
18973
  if matches!(
18977
18974
  date,
@@ -10,8 +10,8 @@
10
10
  use super::{DialectImpl, DialectType};
11
11
  use crate::error::Result;
12
12
  use crate::expressions::{
13
- BinaryFunc, BinaryOp, Cast, DataType, Expression, Function, JsonExtractFunc, LikeOp, Literal,
14
- Paren, UnaryFunc,
13
+ BinaryFunc, BinaryOp, Cast, DataType, Expression, Function, Interval, IntervalUnit,
14
+ IntervalUnitSpec, JsonExtractFunc, LikeOp, Literal, MakeInterval, Paren, UnaryFunc,
15
15
  };
16
16
  #[cfg(feature = "generate")]
17
17
  use crate::generator::GeneratorConfig;
@@ -176,6 +176,10 @@ impl DialectImpl for MySQLDialect {
176
176
  // MySQL generation renders these as CONCAT(...).
177
177
  Expression::Concat(op) => Ok(Expression::Concat(op)),
178
178
 
179
+ // PostgreSQL MAKE_INTERVAL -> MySQL interval arithmetic.
180
+ Expression::Add(op) => self.transform_make_interval_binary(op, false),
181
+ Expression::Sub(op) => self.transform_make_interval_binary(op, true),
182
+
179
183
  // RANDOM -> RAND in MySQL
180
184
  Expression::Random(_) => Ok(Expression::Rand(Box::new(crate::expressions::Rand {
181
185
  seed: None,
@@ -618,6 +622,159 @@ impl MySQLDialect {
618
622
  }
619
623
  }
620
624
 
625
+ fn transform_make_interval_binary(
626
+ &self,
627
+ op: Box<BinaryOp>,
628
+ subtract: bool,
629
+ ) -> Result<Expression> {
630
+ if let Expression::MakeInterval(make_interval) = &op.right {
631
+ if let Some(expr) =
632
+ Self::expand_make_interval_binary(op.left.clone(), make_interval, subtract)
633
+ {
634
+ return Ok(expr);
635
+ }
636
+ }
637
+ if let Expression::Function(function) = &op.right {
638
+ if function.name.eq_ignore_ascii_case("MAKE_INTERVAL") {
639
+ if let Some(expr) =
640
+ Self::expand_make_interval_function_binary(op.left.clone(), function, subtract)
641
+ {
642
+ return Ok(expr);
643
+ }
644
+ }
645
+ }
646
+
647
+ if subtract {
648
+ Ok(Expression::Sub(op))
649
+ } else {
650
+ Ok(Expression::Add(op))
651
+ }
652
+ }
653
+
654
+ fn expand_make_interval_binary(
655
+ left: Expression,
656
+ make_interval: &MakeInterval,
657
+ subtract: bool,
658
+ ) -> Option<Expression> {
659
+ let parts = Self::make_interval_parts(make_interval);
660
+ if parts.is_empty() {
661
+ return None;
662
+ }
663
+
664
+ let mut expr = left;
665
+ for (value, unit) in parts {
666
+ let interval = Expression::Interval(Box::new(Interval {
667
+ this: Some(value),
668
+ unit: Some(IntervalUnitSpec::Simple {
669
+ unit,
670
+ use_plural: false,
671
+ }),
672
+ }));
673
+ expr = if subtract {
674
+ Expression::Sub(Box::new(BinaryOp::new(expr, interval)))
675
+ } else {
676
+ Expression::Add(Box::new(BinaryOp::new(expr, interval)))
677
+ };
678
+ }
679
+
680
+ Some(expr)
681
+ }
682
+
683
+ fn expand_make_interval_function_binary(
684
+ left: Expression,
685
+ function: &Function,
686
+ subtract: bool,
687
+ ) -> Option<Expression> {
688
+ let parts = Self::make_interval_function_parts(function);
689
+ if parts.is_empty() {
690
+ return None;
691
+ }
692
+
693
+ let mut expr = left;
694
+ for (value, unit) in parts {
695
+ let interval = Expression::Interval(Box::new(Interval {
696
+ this: Some(value),
697
+ unit: Some(IntervalUnitSpec::Simple {
698
+ unit,
699
+ use_plural: false,
700
+ }),
701
+ }));
702
+ expr = if subtract {
703
+ Expression::Sub(Box::new(BinaryOp::new(expr, interval)))
704
+ } else {
705
+ Expression::Add(Box::new(BinaryOp::new(expr, interval)))
706
+ };
707
+ }
708
+
709
+ Some(expr)
710
+ }
711
+
712
+ fn make_interval_parts(make_interval: &MakeInterval) -> Vec<(Expression, IntervalUnit)> {
713
+ let mut parts = Vec::new();
714
+ if let Some(year) = &make_interval.year {
715
+ parts.push(((**year).clone(), IntervalUnit::Year));
716
+ }
717
+ if let Some(month) = &make_interval.month {
718
+ parts.push(((**month).clone(), IntervalUnit::Month));
719
+ }
720
+ if let Some(week) = &make_interval.week {
721
+ parts.push(((**week).clone(), IntervalUnit::Week));
722
+ }
723
+ if let Some(day) = &make_interval.day {
724
+ parts.push(((**day).clone(), IntervalUnit::Day));
725
+ }
726
+ if let Some(hour) = &make_interval.hour {
727
+ parts.push(((**hour).clone(), IntervalUnit::Hour));
728
+ }
729
+ if let Some(minute) = &make_interval.minute {
730
+ parts.push(((**minute).clone(), IntervalUnit::Minute));
731
+ }
732
+ if let Some(second) = &make_interval.second {
733
+ parts.push(((**second).clone(), IntervalUnit::Second));
734
+ }
735
+ parts
736
+ }
737
+
738
+ fn make_interval_function_parts(function: &Function) -> Vec<(Expression, IntervalUnit)> {
739
+ let positional_units = [
740
+ IntervalUnit::Year,
741
+ IntervalUnit::Month,
742
+ IntervalUnit::Week,
743
+ IntervalUnit::Day,
744
+ IntervalUnit::Hour,
745
+ IntervalUnit::Minute,
746
+ IntervalUnit::Second,
747
+ ];
748
+ let mut positional_index = 0;
749
+ let mut parts = Vec::new();
750
+
751
+ for arg in &function.args {
752
+ if let Expression::NamedArgument(named) = arg {
753
+ if let Some(unit) = Self::make_interval_unit_from_name(&named.name.name) {
754
+ parts.push((named.value.clone(), unit));
755
+ }
756
+ } else if let Some(unit) = positional_units.get(positional_index) {
757
+ parts.push((arg.clone(), *unit));
758
+ positional_index += 1;
759
+ }
760
+ }
761
+
762
+ parts
763
+ }
764
+
765
+ fn make_interval_unit_from_name(name: &str) -> Option<IntervalUnit> {
766
+ match name.to_ascii_lowercase().as_str() {
767
+ "year" | "years" => Some(IntervalUnit::Year),
768
+ "month" | "months" => Some(IntervalUnit::Month),
769
+ "week" | "weeks" => Some(IntervalUnit::Week),
770
+ "day" | "days" => Some(IntervalUnit::Day),
771
+ "hour" | "hours" => Some(IntervalUnit::Hour),
772
+ "min" | "mins" | "minute" | "minutes" => Some(IntervalUnit::Minute),
773
+ "sec" | "secs" | "second" | "seconds" => Some(IntervalUnit::Second),
774
+ _ => None,
775
+ }
776
+ }
777
+
621
778
  /// Transform CAST type according to MySQL restrictions
622
779
  /// MySQL doesn't support many types in CAST - they get mapped to CHAR or SIGNED
623
780
  /// Based on Python sqlglot's CHAR_CAST_MAPPING and SIGNED_CAST_MAPPING