polyglot-sql 0.3.4__tar.gz → 0.3.5__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 (168) hide show
  1. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/Cargo.lock +5 -5
  2. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/Cargo.toml +1 -1
  3. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/PKG-INFO +1 -1
  4. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/Cargo.toml +1 -1
  5. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/mod.rs +85 -1
  6. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/sqlite.rs +201 -5
  7. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/parser.rs +29 -12
  8. polyglot_sql-0.3.5/crates/polyglot-sql/tests/postgres_sqlite_regression.rs +155 -0
  9. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/tests/snowflake_regression_test.rs +102 -0
  10. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/tests/tpch_transpile_stack.rs +5 -2
  11. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/tests/test_compat.py +2 -2
  12. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/README.md +0 -0
  13. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/README.md +0 -0
  14. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/benches/in_list.rs +0 -0
  15. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/benches/parsing.rs +0 -0
  16. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/benches/rust_parsing.rs +0 -0
  17. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/benches/transpile.rs +0 -0
  18. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/examples/basic_usage.rs +0 -0
  19. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/examples/bench_json.rs +0 -0
  20. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/ast_transforms.rs +0 -0
  21. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/builder.rs +0 -0
  22. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/athena.rs +0 -0
  23. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/bigquery.rs +0 -0
  24. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/clickhouse.rs +0 -0
  25. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/cockroachdb.rs +0 -0
  26. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/databricks.rs +0 -0
  27. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/datafusion.rs +0 -0
  28. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/doris.rs +0 -0
  29. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/dremio.rs +0 -0
  30. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/drill.rs +0 -0
  31. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/druid.rs +0 -0
  32. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/duckdb.rs +0 -0
  33. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/dune.rs +0 -0
  34. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/exasol.rs +0 -0
  35. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/fabric.rs +0 -0
  36. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/generic.rs +0 -0
  37. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/hive.rs +0 -0
  38. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/materialize.rs +0 -0
  39. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/mysql.rs +0 -0
  40. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/oracle.rs +0 -0
  41. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/postgres.rs +0 -0
  42. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/presto.rs +0 -0
  43. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/redshift.rs +0 -0
  44. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/risingwave.rs +0 -0
  45. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/singlestore.rs +0 -0
  46. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/snowflake.rs +0 -0
  47. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/solr.rs +0 -0
  48. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/spark.rs +0 -0
  49. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/starrocks.rs +0 -0
  50. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/tableau.rs +0 -0
  51. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/teradata.rs +0 -0
  52. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/tidb.rs +0 -0
  53. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/trino.rs +0 -0
  54. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/dialects/tsql.rs +0 -0
  55. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/diff.rs +0 -0
  56. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/error.rs +0 -0
  57. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/expressions.rs +0 -0
  58. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/function_catalog.rs +0 -0
  59. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/function_registry.rs +0 -0
  60. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/generator.rs +0 -0
  61. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/helper.rs +0 -0
  62. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/lib.rs +0 -0
  63. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/lineage.rs +0 -0
  64. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/optimizer/annotate_types.rs +0 -0
  65. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/optimizer/canonicalize.rs +0 -0
  66. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/optimizer/eliminate_ctes.rs +0 -0
  67. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/optimizer/eliminate_joins.rs +0 -0
  68. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/optimizer/isolate_table_selects.rs +0 -0
  69. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/optimizer/mod.rs +0 -0
  70. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/optimizer/normalize.rs +0 -0
  71. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/optimizer/normalize_identifiers.rs +0 -0
  72. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/optimizer/optimize_joins.rs +0 -0
  73. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/optimizer/optimizer.rs +0 -0
  74. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/optimizer/pushdown_predicates.rs +0 -0
  75. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/optimizer/pushdown_projections.rs +0 -0
  76. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/optimizer/qualify_columns.rs +0 -0
  77. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/optimizer/qualify_tables.rs +0 -0
  78. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/optimizer/simplify.rs +0 -0
  79. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/optimizer/subquery.rs +0 -0
  80. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/planner.rs +0 -0
  81. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/resolver.rs +0 -0
  82. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/schema.rs +0 -0
  83. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/scope.rs +0 -0
  84. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/time.rs +0 -0
  85. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/tokens.rs +0 -0
  86. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/transforms.rs +0 -0
  87. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/traversal.rs +0 -0
  88. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/trie.rs +0 -0
  89. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/validation/tests.rs +0 -0
  90. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/src/validation.rs +0 -0
  91. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/tests/analyze_failures.rs +0 -0
  92. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/tests/clickhouse_regression.rs +0 -0
  93. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/tests/common/known_failures.rs +0 -0
  94. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/tests/common/mod.rs +0 -0
  95. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/tests/common/test_data.rs +0 -0
  96. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/tests/common/test_runner.rs +0 -0
  97. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/tests/custom_clickhouse_coverage.rs +0 -0
  98. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/tests/custom_clickhouse_parser.rs +0 -0
  99. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/tests/custom_dialect.rs +0 -0
  100. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/tests/custom_dialect_tests.rs +0 -0
  101. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/tests/custom_fixtures/datafusion/ddl.json +0 -0
  102. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/tests/custom_fixtures/datafusion/dml.json +0 -0
  103. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/tests/custom_fixtures/datafusion/functions.json +0 -0
  104. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/tests/custom_fixtures/datafusion/identity.json +0 -0
  105. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/tests/custom_fixtures/datafusion/operators.json +0 -0
  106. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/tests/custom_fixtures/datafusion/select.json +0 -0
  107. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/tests/custom_fixtures/datafusion/transpilation.json +0 -0
  108. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/tests/custom_fixtures/datafusion/types.json +0 -0
  109. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/tests/deep_nesting_regression.rs +0 -0
  110. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/tests/dialect_matrix.rs +0 -0
  111. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/tests/error_handling.rs +0 -0
  112. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/tests/fabric_regression.rs +0 -0
  113. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/tests/identity_roundtrip.rs +0 -0
  114. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/tests/sqlglot_compat.rs +0 -0
  115. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/tests/sqlglot_dialect_identity.rs +0 -0
  116. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/tests/sqlglot_identity.rs +0 -0
  117. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/tests/sqlglot_identity_detailed.rs +0 -0
  118. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/tests/sqlglot_parser.rs +0 -0
  119. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/tests/sqlglot_pretty.rs +0 -0
  120. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/tests/sqlglot_transpilation.rs +0 -0
  121. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/tests/sqlglot_transpile.rs +0 -0
  122. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/tests/transform_regression.rs +0 -0
  123. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql/tests/tsql_regression.rs +0 -0
  124. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql-function-catalogs/Cargo.toml +0 -0
  125. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql-function-catalogs/README.md +0 -0
  126. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql-function-catalogs/src/clickhouse.rs +0 -0
  127. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql-function-catalogs/src/duckdb.rs +0 -0
  128. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql-function-catalogs/src/lib.rs +0 -0
  129. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql-function-catalogs/tools/clickhouse/extract_functions.py +0 -0
  130. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql-function-catalogs/tools/duckdb/extract_functions.py +0 -0
  131. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/Cargo.toml +0 -0
  132. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/README.md +0 -0
  133. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/docs/api.md +0 -0
  134. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/docs/index.md +0 -0
  135. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/mkdocs.yml +0 -0
  136. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/src/annotate_types.rs +0 -0
  137. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/src/dialects.rs +0 -0
  138. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/src/diff.rs +0 -0
  139. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/src/errors.rs +0 -0
  140. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/src/expr.rs +0 -0
  141. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/src/expr_types.rs +0 -0
  142. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/src/format.rs +0 -0
  143. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/src/generate.rs +0 -0
  144. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/src/helpers.rs +0 -0
  145. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/src/lib.rs +0 -0
  146. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/src/lineage.rs +0 -0
  147. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/src/optimize.rs +0 -0
  148. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/src/parse.rs +0 -0
  149. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/src/tokenize.rs +0 -0
  150. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/src/transpile.rs +0 -0
  151. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/src/types.rs +0 -0
  152. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/src/validate.rs +0 -0
  153. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/tests/conftest.py +0 -0
  154. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/tests/test_dialects.py +0 -0
  155. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/tests/test_diff.py +0 -0
  156. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/tests/test_expression.py +0 -0
  157. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/tests/test_format.py +0 -0
  158. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/tests/test_generate.py +0 -0
  159. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/tests/test_lineage.py +0 -0
  160. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/tests/test_optimize.py +0 -0
  161. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/tests/test_parse.py +0 -0
  162. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/tests/test_transpile.py +0 -0
  163. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/tests/test_validate.py +0 -0
  164. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/crates/polyglot-sql-python/uv.lock +0 -0
  165. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/pyproject.toml +0 -0
  166. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/python/polyglot_sql/__init__.py +0 -0
  167. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/python/polyglot_sql/__init__.pyi +0 -0
  168. {polyglot_sql-0.3.4 → polyglot_sql-0.3.5}/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.3.4"
608
+ version = "0.3.5"
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.3.4"
624
+ version = "0.3.5"
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.3.4"
634
+ version = "0.3.5"
635
635
 
636
636
  [[package]]
637
637
  name = "polyglot-sql-python"
638
- version = "0.3.4"
638
+ version = "0.3.5"
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.3.4"
649
+ version = "0.3.5"
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.3.4"
9
+ version = "0.3.5"
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.3.4
3
+ Version: 0.3.5
4
4
  Classifier: Development Status :: 4 - Beta
5
5
  Classifier: Intended Audience :: Developers
6
6
  Classifier: License :: OSI Approved :: MIT License
@@ -83,7 +83,7 @@ thiserror = { workspace = true }
83
83
  unicode-segmentation = { workspace = true }
84
84
  stacker = { version = "0.1", optional = true }
85
85
  ts-rs = { version = "12.0", features = ["serde-compat"], optional = true }
86
- polyglot-sql-function-catalogs = { path = "../polyglot-sql-function-catalogs", version = "0.3.4", optional = true, default-features = false }
86
+ polyglot-sql-function-catalogs = { path = "../polyglot-sql-function-catalogs", version = "0.3.5", optional = true, default-features = false }
87
87
 
88
88
  [dev-dependencies]
89
89
  pretty_assertions = "1.4"
@@ -161,7 +161,7 @@ use crate::error::Result;
161
161
  use crate::expressions::{Expression, Function, FunctionBody, Identifier, Null};
162
162
  use crate::generator::{Generator, GeneratorConfig};
163
163
  use crate::parser::Parser;
164
- use crate::tokens::{Token, Tokenizer, TokenizerConfig};
164
+ use crate::tokens::{Token, TokenType, Tokenizer, TokenizerConfig};
165
165
  use serde::{Deserialize, Serialize};
166
166
  use std::collections::HashMap;
167
167
  use std::sync::{Arc, LazyLock, RwLock};
@@ -3750,6 +3750,11 @@ impl Dialect {
3750
3750
  pretty: bool,
3751
3751
  ) -> Result<Vec<String>> {
3752
3752
  let target = target_dialect.dialect_type;
3753
+ if matches!(self.dialect_type, DialectType::PostgreSQL)
3754
+ && matches!(target, DialectType::SQLite)
3755
+ {
3756
+ self.reject_pgvector_distance_operators_for_sqlite(sql)?;
3757
+ }
3753
3758
  let expressions = self.parse(sql)?;
3754
3759
  let generic_identity =
3755
3760
  self.dialect_type == DialectType::Generic && target == DialectType::Generic;
@@ -4063,6 +4068,14 @@ impl Dialect {
4063
4068
  let normalized =
4064
4069
  Self::cross_dialect_normalize(normalized, self.dialect_type, target)?;
4065
4070
 
4071
+ let normalized = if matches!(self.dialect_type, DialectType::PostgreSQL)
4072
+ && matches!(target, DialectType::SQLite)
4073
+ {
4074
+ Self::normalize_postgres_to_sqlite_types(normalized)?
4075
+ } else {
4076
+ normalized
4077
+ };
4078
+
4066
4079
  // For DuckDB target from BigQuery source: wrap UNNEST of struct arrays in
4067
4080
  // (SELECT UNNEST(..., max_depth => 2)) subquery
4068
4081
  // Must run BEFORE unnest_alias_to_column_alias since it changes alias structure
@@ -4222,6 +4235,77 @@ impl Dialect {
4222
4235
  // Transpile-only methods: cross-dialect normalization and helpers
4223
4236
  #[cfg(feature = "transpile")]
4224
4237
  impl Dialect {
4238
+ fn reject_pgvector_distance_operators_for_sqlite(&self, sql: &str) -> Result<()> {
4239
+ let tokens = self.tokenize(sql)?;
4240
+ for (i, token) in tokens.iter().enumerate() {
4241
+ if token.token_type == TokenType::NullsafeEq {
4242
+ return Err(crate::error::Error::unsupported(
4243
+ "PostgreSQL pgvector cosine distance operator <=>",
4244
+ "SQLite",
4245
+ ));
4246
+ }
4247
+ if token.token_type == TokenType::Lt
4248
+ && tokens
4249
+ .get(i + 1)
4250
+ .is_some_and(|token| token.token_type == TokenType::Tilde)
4251
+ && tokens
4252
+ .get(i + 2)
4253
+ .is_some_and(|token| token.token_type == TokenType::Gt)
4254
+ {
4255
+ return Err(crate::error::Error::unsupported(
4256
+ "PostgreSQL pgvector Hamming distance operator <~>",
4257
+ "SQLite",
4258
+ ));
4259
+ }
4260
+ }
4261
+ Ok(())
4262
+ }
4263
+
4264
+ fn normalize_postgres_to_sqlite_types(expr: Expression) -> Result<Expression> {
4265
+ fn sqlite_type(dt: crate::expressions::DataType) -> crate::expressions::DataType {
4266
+ use crate::expressions::DataType;
4267
+
4268
+ match dt {
4269
+ DataType::Bit { .. } => DataType::Int {
4270
+ length: None,
4271
+ integer_spelling: true,
4272
+ },
4273
+ DataType::TextWithLength { .. } => DataType::Text,
4274
+ DataType::VarChar { .. } => DataType::Text,
4275
+ DataType::Char { .. } => DataType::Text,
4276
+ DataType::Timestamp { timezone: true, .. } => DataType::Text,
4277
+ DataType::Custom { name } => {
4278
+ let base = name
4279
+ .split_once('(')
4280
+ .map_or(name.as_str(), |(base, _)| base)
4281
+ .trim();
4282
+ if base.eq_ignore_ascii_case("TSVECTOR")
4283
+ || base.eq_ignore_ascii_case("TIMESTAMPTZ")
4284
+ || base.eq_ignore_ascii_case("TIMESTAMP WITH TIME ZONE")
4285
+ || base.eq_ignore_ascii_case("NVARCHAR")
4286
+ || base.eq_ignore_ascii_case("NCHAR")
4287
+ {
4288
+ DataType::Text
4289
+ } else {
4290
+ DataType::Custom { name }
4291
+ }
4292
+ }
4293
+ _ => dt,
4294
+ }
4295
+ }
4296
+
4297
+ transform_recursive(expr, &|e| match e {
4298
+ Expression::DataType(dt) => Ok(Expression::DataType(sqlite_type(dt))),
4299
+ Expression::CreateTable(mut ct) => {
4300
+ for column in &mut ct.columns {
4301
+ column.data_type = sqlite_type(column.data_type.clone());
4302
+ }
4303
+ Ok(Expression::CreateTable(ct))
4304
+ }
4305
+ _ => Ok(e),
4306
+ })
4307
+ }
4308
+
4225
4309
  /// For DuckDB target: when FROM clause contains RANGE(n), replace
4226
4310
  /// `(ROW_NUMBER() OVER (ORDER BY 1 NULLS FIRST) - 1)` with `range` in select expressions.
4227
4311
  /// This handles SEQ1/2/4/8 → RANGE transpilation from Snowflake.
@@ -5,7 +5,8 @@
5
5
  use super::{DialectImpl, DialectType};
6
6
  use crate::error::Result;
7
7
  use crate::expressions::{
8
- AggFunc, BinaryFunc, BinaryOp, Case, Cast, CeilFunc, Expression, Function, LikeOp, UnaryFunc,
8
+ AggFunc, BinaryFunc, BinaryOp, Case, Cast, CeilFunc, DataType, DateTimeField, DateTruncFunc,
9
+ Expression, ExtractFunc, Function, LikeOp, Literal, TrimFunc, TrimPosition, UnaryFunc,
9
10
  VarArgFunc,
10
11
  };
11
12
  use crate::generator::GeneratorConfig;
@@ -138,6 +139,46 @@ impl DialectImpl for SQLiteDialect {
138
139
  Ok(Expression::Pragma(p))
139
140
  }
140
141
 
142
+ // PostgreSQL DATE '...' literals are not SQLite syntax.
143
+ Expression::Literal(lit) if matches!(lit.as_ref(), Literal::Date(_)) => {
144
+ let Literal::Date(date) = lit.as_ref() else {
145
+ unreachable!()
146
+ };
147
+ Ok(Self::string_literal(date))
148
+ }
149
+
150
+ // SQLite scalar MIN/MAX are multi-argument equivalents of LEAST/GREATEST.
151
+ Expression::Least(f) => Ok(Self::function("MIN", f.expressions)),
152
+ Expression::Greatest(f) => Ok(Self::function("MAX", f.expressions)),
153
+
154
+ // PostgreSQL EXTRACT(...) lowers to SQLite strftime() for common units.
155
+ Expression::Extract(f) => Self::transform_extract(*f),
156
+
157
+ // PostgreSQL DATE_TRUNC(...) lowers to date/strftime() for common units.
158
+ Expression::DateTrunc(f) => Self::transform_date_trunc(*f),
159
+
160
+ // SQLite uses comma-call SUBSTRING/SUBSTR syntax, not SQL-standard FROM/FOR.
161
+ Expression::Substring(mut f) => {
162
+ f.from_for_syntax = false;
163
+ Ok(Expression::Substring(f))
164
+ }
165
+
166
+ // SQLite supports LTRIM/RTRIM/TRIM(str, chars), not TRIM(LEADING ... FROM ...).
167
+ Expression::Trim(f) => Ok(Self::transform_trim(*f)),
168
+
169
+ // Strip PostgreSQL's default public schema in SQLite DDL.
170
+ Expression::CreateTable(mut ct)
171
+ if ct
172
+ .name
173
+ .schema
174
+ .as_ref()
175
+ .is_some_and(|schema| schema.name.eq_ignore_ascii_case("public"))
176
+ && ct.name.catalog.is_none() =>
177
+ {
178
+ ct.name.schema = None;
179
+ Ok(Expression::CreateTable(ct))
180
+ }
181
+
141
182
  // Generic function transformations
142
183
  Expression::Function(f) => self.transform_function(*f),
143
184
 
@@ -177,6 +218,122 @@ impl DialectImpl for SQLiteDialect {
177
218
  }
178
219
 
179
220
  impl SQLiteDialect {
221
+ fn function(name: &str, args: Vec<Expression>) -> Expression {
222
+ Expression::Function(Box::new(Function::new(name.to_string(), args)))
223
+ }
224
+
225
+ fn string_literal(value: &str) -> Expression {
226
+ Expression::Literal(Box::new(Literal::String(value.to_string())))
227
+ }
228
+
229
+ fn strftime(format: &str, expr: Expression) -> Expression {
230
+ Expression::Function(Box::new(Function::new(
231
+ "STRFTIME".to_string(),
232
+ vec![Self::string_literal(format), expr],
233
+ )))
234
+ }
235
+
236
+ fn cast(expr: Expression, to: DataType) -> Expression {
237
+ Expression::Cast(Box::new(Cast {
238
+ this: expr,
239
+ to,
240
+ trailing_comments: Vec::new(),
241
+ double_colon_syntax: false,
242
+ format: None,
243
+ default: None,
244
+ inferred_type: None,
245
+ }))
246
+ }
247
+
248
+ fn sqlite_int_type() -> DataType {
249
+ DataType::Int {
250
+ length: None,
251
+ integer_spelling: true,
252
+ }
253
+ }
254
+
255
+ fn sqlite_real_type() -> DataType {
256
+ DataType::Float {
257
+ precision: None,
258
+ scale: None,
259
+ real_spelling: true,
260
+ }
261
+ }
262
+
263
+ fn transform_extract(f: ExtractFunc) -> Result<Expression> {
264
+ let strftime_format = match &f.field {
265
+ DateTimeField::Year => "%Y",
266
+ DateTimeField::Month => "%m",
267
+ DateTimeField::Day => "%d",
268
+ DateTimeField::Hour => "%H",
269
+ DateTimeField::Minute => "%M",
270
+ DateTimeField::Second => "%f",
271
+ DateTimeField::DayOfWeek => "%w",
272
+ DateTimeField::DayOfYear => "%j",
273
+ DateTimeField::Epoch => "%s",
274
+ _ => return Ok(Expression::Extract(Box::new(f))),
275
+ };
276
+ let target_type = if matches!(f.field, DateTimeField::Epoch | DateTimeField::Second) {
277
+ Self::sqlite_real_type()
278
+ } else {
279
+ Self::sqlite_int_type()
280
+ };
281
+ Ok(Self::cast(
282
+ Self::strftime(strftime_format, f.this),
283
+ target_type,
284
+ ))
285
+ }
286
+
287
+ fn transform_date_trunc(f: DateTruncFunc) -> Result<Expression> {
288
+ match &f.unit {
289
+ DateTimeField::Day => Ok(Self::function("DATE", vec![f.this])),
290
+ DateTimeField::Hour => Ok(Self::strftime("%Y-%m-%d %H:00:00", f.this)),
291
+ DateTimeField::Minute => Ok(Self::strftime("%Y-%m-%d %H:%M:00", f.this)),
292
+ DateTimeField::Second => Ok(Self::strftime("%Y-%m-%d %H:%M:%S", f.this)),
293
+ DateTimeField::Month => Ok(Self::strftime("%Y-%m-01", f.this)),
294
+ DateTimeField::Year => Ok(Self::strftime("%Y-01-01", f.this)),
295
+ _ => Ok(Expression::DateTrunc(Box::new(f))),
296
+ }
297
+ }
298
+
299
+ fn datetime_field_from_expr(expr: &Expression) -> Option<DateTimeField> {
300
+ let unit = match expr {
301
+ Expression::Literal(lit) => match lit.as_ref() {
302
+ Literal::String(s) => s.as_str(),
303
+ _ => return None,
304
+ },
305
+ Expression::Identifier(id) => id.name.as_str(),
306
+ Expression::Var(v) => v.this.as_str(),
307
+ Expression::Column(col) if col.table.is_none() => col.name.name.as_str(),
308
+ _ => return None,
309
+ };
310
+ match unit.to_ascii_lowercase().as_str() {
311
+ "year" | "yyyy" | "yy" => Some(DateTimeField::Year),
312
+ "month" | "mon" | "mm" => Some(DateTimeField::Month),
313
+ "day" | "dd" => Some(DateTimeField::Day),
314
+ "hour" | "hours" | "h" | "hh" | "hr" | "hrs" => Some(DateTimeField::Hour),
315
+ "minute" | "minutes" | "mi" | "min" | "mins" => Some(DateTimeField::Minute),
316
+ "second" | "seconds" | "s" | "sec" | "secs" | "ss" => Some(DateTimeField::Second),
317
+ "dow" | "dayofweek" | "dw" => Some(DateTimeField::DayOfWeek),
318
+ "doy" | "dayofyear" | "dy" => Some(DateTimeField::DayOfYear),
319
+ "epoch" => Some(DateTimeField::Epoch),
320
+ _ => None,
321
+ }
322
+ }
323
+
324
+ fn transform_trim(f: TrimFunc) -> Expression {
325
+ let function_name = match f.position {
326
+ TrimPosition::Leading => "LTRIM",
327
+ TrimPosition::Trailing => "RTRIM",
328
+ TrimPosition::Both => "TRIM",
329
+ };
330
+ let mut args = vec![f.this];
331
+ if let Some(characters) = f.characters {
332
+ args.push(characters);
333
+ }
334
+ Expression::Function(Box::new(Function::new(function_name.to_string(), args)))
335
+ }
336
+
180
337
  /// Check if an expression is already a CAST to a float type
181
338
  fn is_float_cast(expr: &Expression) -> bool {
182
339
  if let Expression::Cast(cast) = expr {
@@ -299,6 +456,18 @@ impl SQLiteDialect {
299
456
  Function::new("EDITDIST3".to_string(), f.args),
300
457
  ))),
301
458
 
459
+ // PostgreSQL-compatible scalar/JSON rewrites.
460
+ "LEAST" if !f.args.is_empty() => Ok(Self::function("MIN", f.args)),
461
+ "GREATEST" if !f.args.is_empty() => Ok(Self::function("MAX", f.args)),
462
+ "JSON_BUILD_ARRAY" => Ok(Self::function("JSON_ARRAY", f.args)),
463
+ "JSON_BUILD_OBJECT" => Ok(Self::function("JSON_OBJECT", f.args)),
464
+ "JSON_AGG" | "JSONB_AGG" if f.args.len() == 1 => {
465
+ Ok(Self::function("JSON_GROUP_ARRAY", f.args))
466
+ }
467
+ "JSON_OBJECT_AGG" if f.args.len() == 2 => {
468
+ Ok(Self::function("JSON_GROUP_OBJECT", f.args))
469
+ }
470
+
302
471
  // GETDATE -> CURRENT_TIMESTAMP
303
472
  "GETDATE" => Ok(Expression::CurrentTimestamp(
304
473
  crate::expressions::CurrentTimestamp {
@@ -328,10 +497,7 @@ impl SQLiteDialect {
328
497
  )))),
329
498
 
330
499
  // SUBSTRING is native to SQLite (keep as-is)
331
- "SUBSTRING" => Ok(Expression::Function(Box::new(Function::new(
332
- "SUBSTRING".to_string(),
333
- f.args,
334
- )))),
500
+ "SUBSTRING" => Ok(Self::function("SUBSTRING", f.args)),
335
501
 
336
502
  // STRING_AGG -> GROUP_CONCAT in SQLite
337
503
  "STRING_AGG" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
@@ -344,6 +510,28 @@ impl SQLiteDialect {
344
510
  f.args,
345
511
  )))),
346
512
 
513
+ "DATE_PART" if f.args.len() == 2 => {
514
+ let mut args = f.args;
515
+ let unit = args.remove(0);
516
+ let expr = args.remove(0);
517
+ if let Some(field) = Self::datetime_field_from_expr(&unit) {
518
+ Self::transform_extract(ExtractFunc { this: expr, field })
519
+ } else {
520
+ Ok(Self::function("DATE_PART", vec![unit, expr]))
521
+ }
522
+ }
523
+
524
+ "DATE_TRUNC" if f.args.len() == 2 => {
525
+ let mut args = f.args;
526
+ let unit = args.remove(0);
527
+ let expr = args.remove(0);
528
+ if let Some(unit) = Self::datetime_field_from_expr(&unit) {
529
+ Self::transform_date_trunc(DateTruncFunc { this: expr, unit })
530
+ } else {
531
+ Ok(Self::function("DATE_TRUNC", vec![unit, expr]))
532
+ }
533
+ }
534
+
347
535
  // DATEDIFF(a, b, unit_string) -> JULIANDAY arithmetic for SQLite
348
536
  "DATEDIFF" | "DATE_DIFF" if f.args.len() == 3 => {
349
537
  let mut args = f.args;
@@ -534,6 +722,14 @@ impl SQLiteDialect {
534
722
  f.args,
535
723
  )))),
536
724
 
725
+ "JSON_AGG" | "JSONB_AGG" if f.args.len() == 1 => {
726
+ Ok(Self::function("JSON_GROUP_ARRAY", f.args))
727
+ }
728
+
729
+ "JSON_OBJECT_AGG" if f.args.len() == 2 => {
730
+ Ok(Self::function("JSON_GROUP_OBJECT", f.args))
731
+ }
732
+
537
733
  // Pass through everything else
538
734
  _ => Ok(Expression::AggregateFunction(f)),
539
735
  }
@@ -4882,8 +4882,9 @@ impl Parser {
4882
4882
  } else {
4883
4883
  return Err(self.parse_error("Expected identifier after ${"));
4884
4884
  }
4885
- } else if self.check(TokenType::String) {
4885
+ } else if self.check(TokenType::String) || self.check(TokenType::DollarString) {
4886
4886
  // DuckDB allows string literals as table names: SELECT * FROM 'x.y'
4887
+ // Snowflake JDBC uses dollar-quoted strings for stage paths: SELECT $1 FROM $$@%"table"/$$
4887
4888
  // Convert to a quoted identifier
4888
4889
  let string_token = self.advance();
4889
4890
  let table_name = Identifier {
@@ -22741,9 +22742,14 @@ impl Parser {
22741
22742
  while self.check(TokenType::Slash) {
22742
22743
  self.skip(); // consume /
22743
22744
  stage_path.push('/');
22744
- if (self.check(TokenType::Var)
22745
+ // Use `while` (not `if`) because a single path segment between slashes
22746
+ // may consist of multiple tokens — e.g., a UUID like `c8b31cea-a6d1-4413`
22747
+ // tokenizes as Identifier("c8b31cea") + Dash + Identifier("a6d1") + Dash + Number(4413).
22748
+ while (self.check(TokenType::Var)
22745
22749
  || self.check_keyword()
22746
- || self.is_identifier_token())
22750
+ || self.is_identifier_token()
22751
+ || self.check(TokenType::Number)
22752
+ || self.check(TokenType::Dash))
22747
22753
  && !self.check_next(TokenType::Eq)
22748
22754
  {
22749
22755
  stage_path.push_str(&self.advance().text);
@@ -22790,10 +22796,14 @@ impl Parser {
22790
22796
  while self.check(TokenType::Slash) {
22791
22797
  self.skip(); // consume /
22792
22798
  stage_path.push('/');
22793
- // Get path segment but don't consume if followed by = (that's a parameter)
22794
- if (self.check(TokenType::Var)
22799
+ // Use `while` (not `if`) because a single path segment between slashes
22800
+ // may consist of multiple tokens — e.g., a UUID like `c8b31cea-a6d1-4413`
22801
+ // tokenizes as Identifier("c8b31cea") + Dash + Identifier("a6d1") + Dash + Number(4413).
22802
+ while (self.check(TokenType::Var)
22795
22803
  || self.check_keyword()
22796
- || self.is_identifier_token())
22804
+ || self.is_identifier_token()
22805
+ || self.check(TokenType::Number)
22806
+ || self.check(TokenType::Dash))
22797
22807
  && !self.check_next(TokenType::Eq)
22798
22808
  {
22799
22809
  stage_path.push_str(&self.advance().text);
@@ -22828,9 +22838,14 @@ impl Parser {
22828
22838
  while self.check(TokenType::Slash) {
22829
22839
  self.skip(); // consume /
22830
22840
  stage_path.push('/');
22831
- if (self.check(TokenType::Var)
22841
+ // Use `while` (not `if`) because a single path segment between slashes
22842
+ // may consist of multiple tokens — e.g., a UUID like `c8b31cea-a6d1-4413`
22843
+ // tokenizes as Identifier("c8b31cea") + Dash + Identifier("a6d1") + Dash + Number(4413).
22844
+ while (self.check(TokenType::Var)
22832
22845
  || self.check_keyword()
22833
- || self.is_identifier_token())
22846
+ || self.is_identifier_token()
22847
+ || self.check(TokenType::Number)
22848
+ || self.check(TokenType::Dash))
22834
22849
  && !self.check_next(TokenType::Eq)
22835
22850
  {
22836
22851
  stage_path.push_str(&self.advance().text);
@@ -22863,9 +22878,11 @@ impl Parser {
22863
22878
  break;
22864
22879
  }
22865
22880
  // Stop at ? (placeholder for stage destination), quoted string
22866
- // (e.g., '@SYSTEM$BIND/...'), or semicolon
22881
+ // (e.g., '@SYSTEM$BIND/...'), dollar-quoted string (e.g., $$@%"table"$$),
22882
+ // or semicolon
22867
22883
  if self.check(TokenType::Parameter)
22868
22884
  || self.check(TokenType::String)
22885
+ || self.check(TokenType::DollarString)
22869
22886
  || self.check(TokenType::Semicolon)
22870
22887
  {
22871
22888
  break;
@@ -22876,11 +22893,11 @@ impl Parser {
22876
22893
  (source_parts.join(""), false)
22877
22894
  };
22878
22895
 
22879
- // Parse target stage (@stage_name, ? placeholder, or quoted '@stage')
22896
+ // Parse target stage (@stage_name, ? placeholder, quoted '@stage', or dollar-quoted $$@%"stage"$$)
22880
22897
  let target = if self.match_token(TokenType::Parameter) {
22881
22898
  Expression::Placeholder(Placeholder { index: None })
22882
- } else if self.check(TokenType::String) {
22883
- // Quoted stage: '@SYSTEM$BIND/path'
22899
+ } else if self.check(TokenType::String) || self.check(TokenType::DollarString) {
22900
+ // Quoted stage: '@SYSTEM$BIND/path' or $$@%"table"$$
22884
22901
  let tok = self.advance();
22885
22902
  Expression::Literal(Box::new(Literal::String(tok.text.clone())))
22886
22903
  } else {
@@ -0,0 +1,155 @@
1
+ use polyglot_sql::{transpile, DialectType, Error};
2
+
3
+ fn pg_to_sqlite(sql: &str) -> String {
4
+ transpile(sql, DialectType::PostgreSQL, DialectType::SQLite)
5
+ .expect("PostgreSQL to SQLite transpilation should succeed")
6
+ .join("; ")
7
+ }
8
+
9
+ #[test]
10
+ fn postgres_to_sqlite_rewrites_scalar_json_and_dates() {
11
+ let cases = [
12
+ ("SELECT LEAST(a, b) FROM t", "SELECT MIN(a, b) FROM t"),
13
+ ("SELECT GREATEST(a, b) FROM t", "SELECT MAX(a, b) FROM t"),
14
+ (
15
+ "SELECT JSON_AGG(name) FROM t",
16
+ "SELECT JSON_GROUP_ARRAY(name) FROM t",
17
+ ),
18
+ (
19
+ "SELECT JSONB_AGG(name) FROM t",
20
+ "SELECT JSON_GROUP_ARRAY(name) FROM t",
21
+ ),
22
+ (
23
+ "SELECT JSON_OBJECT_AGG(k, v) FROM t",
24
+ "SELECT JSON_GROUP_OBJECT(k, v) FROM t",
25
+ ),
26
+ (
27
+ "SELECT JSON_BUILD_OBJECT('id', id, 'name', name) FROM t",
28
+ "SELECT JSON_OBJECT('id', id, 'name', name) FROM t",
29
+ ),
30
+ (
31
+ "SELECT JSON_BUILD_ARRAY(a, b, c) FROM t",
32
+ "SELECT JSON_ARRAY(a, b, c) FROM t",
33
+ ),
34
+ (
35
+ "SELECT DATE_PART('year', ts) FROM t",
36
+ "SELECT CAST(STRFTIME('%Y', ts) AS INTEGER) FROM t",
37
+ ),
38
+ (
39
+ "SELECT DATE_PART('hour', ts) FROM t",
40
+ "SELECT CAST(STRFTIME('%H', ts) AS INTEGER) FROM t",
41
+ ),
42
+ (
43
+ "SELECT DATE_PART('minute', ts) FROM t",
44
+ "SELECT CAST(STRFTIME('%M', ts) AS INTEGER) FROM t",
45
+ ),
46
+ (
47
+ "SELECT DATE_PART('second', ts) FROM t",
48
+ "SELECT CAST(STRFTIME('%f', ts) AS REAL) FROM t",
49
+ ),
50
+ (
51
+ "SELECT DATE_PART('dow', ts) FROM t",
52
+ "SELECT CAST(STRFTIME('%w', ts) AS INTEGER) FROM t",
53
+ ),
54
+ (
55
+ "SELECT DATE_PART('doy', ts) FROM t",
56
+ "SELECT CAST(STRFTIME('%j', ts) AS INTEGER) FROM t",
57
+ ),
58
+ (
59
+ "SELECT DATE_PART('epoch', ts) FROM t",
60
+ "SELECT CAST(STRFTIME('%s', ts) AS REAL) FROM t",
61
+ ),
62
+ (
63
+ "SELECT EXTRACT(YEAR FROM ts) FROM t",
64
+ "SELECT CAST(STRFTIME('%Y', ts) AS INTEGER) FROM t",
65
+ ),
66
+ (
67
+ "SELECT EXTRACT(HOUR FROM ts) FROM t",
68
+ "SELECT CAST(STRFTIME('%H', ts) AS INTEGER) FROM t",
69
+ ),
70
+ (
71
+ "SELECT EXTRACT(MINUTE FROM ts) FROM t",
72
+ "SELECT CAST(STRFTIME('%M', ts) AS INTEGER) FROM t",
73
+ ),
74
+ (
75
+ "SELECT EXTRACT(SECOND FROM ts) FROM t",
76
+ "SELECT CAST(STRFTIME('%f', ts) AS REAL) FROM t",
77
+ ),
78
+ (
79
+ "SELECT EXTRACT(DOW FROM ts) FROM t",
80
+ "SELECT CAST(STRFTIME('%w', ts) AS INTEGER) FROM t",
81
+ ),
82
+ (
83
+ "SELECT EXTRACT(DOY FROM ts) FROM t",
84
+ "SELECT CAST(STRFTIME('%j', ts) AS INTEGER) FROM t",
85
+ ),
86
+ (
87
+ "SELECT EXTRACT(EPOCH FROM ts) FROM t",
88
+ "SELECT CAST(STRFTIME('%s', ts) AS REAL) FROM t",
89
+ ),
90
+ (
91
+ "SELECT DATE_TRUNC('month', ts) FROM t",
92
+ "SELECT STRFTIME('%Y-%m-01', ts) FROM t",
93
+ ),
94
+ (
95
+ "SELECT DATE_TRUNC('hour', ts) FROM t",
96
+ "SELECT STRFTIME('%Y-%m-%d %H:00:00', ts) FROM t",
97
+ ),
98
+ (
99
+ "SELECT DATE_TRUNC('minute', ts) FROM t",
100
+ "SELECT STRFTIME('%Y-%m-%d %H:%M:00', ts) FROM t",
101
+ ),
102
+ (
103
+ "SELECT DATE_TRUNC('second', ts) FROM t",
104
+ "SELECT STRFTIME('%Y-%m-%d %H:%M:%S', ts) FROM t",
105
+ ),
106
+ (
107
+ "SELECT DATE_TRUNC('day', ts) FROM t",
108
+ "SELECT DATE(ts) FROM t",
109
+ ),
110
+ ];
111
+
112
+ for (sql, expected) in cases {
113
+ assert_eq!(pg_to_sqlite(sql), expected, "input: {sql}");
114
+ }
115
+ }
116
+
117
+ #[test]
118
+ fn postgres_to_sqlite_rewrites_common_syntax_and_types() {
119
+ let cases = [
120
+ (
121
+ "SELECT SUBSTRING(str FROM 2 FOR 5) FROM t",
122
+ "SELECT SUBSTRING(str, 2, 5) FROM t",
123
+ ),
124
+ (
125
+ "SELECT TRIM(LEADING 'x' FROM str) FROM t",
126
+ "SELECT LTRIM(str, 'x') FROM t",
127
+ ),
128
+ ("SELECT DATE '2023-01-01'", "SELECT '2023-01-01'"),
129
+ (
130
+ "CREATE TABLE public.t (id INT, name TEXT)",
131
+ "CREATE TABLE t (id INTEGER, name TEXT)",
132
+ ),
133
+ (
134
+ "CREATE TABLE t (flag BIT, label NVARCHAR(100), doc TSVECTOR)",
135
+ "CREATE TABLE t (flag INTEGER, label TEXT, doc TEXT)",
136
+ ),
137
+ (
138
+ "CREATE TABLE t (data JSONB, ts TIMESTAMPTZ)",
139
+ "CREATE TABLE t (data JSON, ts TEXT)",
140
+ ),
141
+ ];
142
+
143
+ for (sql, expected) in cases {
144
+ assert_eq!(pg_to_sqlite(sql), expected, "input: {sql}");
145
+ }
146
+ }
147
+
148
+ #[test]
149
+ fn postgres_to_sqlite_rejects_pgvector_distance_operators() {
150
+ for sql in ["SELECT a <=> b FROM t", "SELECT a <~> b FROM t"] {
151
+ let err = transpile(sql, DialectType::PostgreSQL, DialectType::SQLite)
152
+ .expect_err("pgvector distance operators have no SQLite equivalent");
153
+ assert!(matches!(err, Error::Unsupported { .. }), "{err}");
154
+ }
155
+ }