sqlglot 28.4.1__tar.gz → 28.6.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {sqlglot-28.4.1 → sqlglot-28.6.0}/CHANGELOG.md +48 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/PKG-INFO +44 -2
- {sqlglot-28.4.1 → sqlglot-28.6.0}/README.md +42 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/_version.py +3 -3
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/dialects/bigquery.py +5 -7
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/dialects/clickhouse.py +2 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/dialects/dialect.py +139 -5
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/dialects/doris.py +1 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/dialects/druid.py +1 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/dialects/duckdb.py +835 -147
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/dialects/exasol.py +17 -1
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/dialects/hive.py +2 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/dialects/mysql.py +7 -11
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/dialects/oracle.py +38 -1
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/dialects/postgres.py +18 -30
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/dialects/presto.py +2 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/dialects/redshift.py +4 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/dialects/singlestore.py +13 -3
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/dialects/snowflake.py +161 -18
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/dialects/spark.py +10 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/dialects/spark2.py +3 -2
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/dialects/starrocks.py +1 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/dialects/trino.py +1 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/dialects/tsql.py +3 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/diff.py +1 -1
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/expressions.py +140 -34
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/generator.py +119 -25
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/optimizer/annotate_types.py +50 -14
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/optimizer/resolver.py +19 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/parser.py +124 -44
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/schema.py +1 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/tokens.py +14 -2
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/typing/__init__.py +16 -1
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/typing/hive.py +3 -0
- sqlglot-28.6.0/sqlglot/typing/mysql.py +10 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/typing/snowflake.py +67 -5
- sqlglot-28.6.0/sqlglot/typing/spark.py +10 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/typing/spark2.py +6 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot.egg-info/PKG-INFO +44 -2
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot.egg-info/SOURCES.txt +3 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot.egg-info/requires.txt +1 -1
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglotrs/Cargo.lock +1 -1
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglotrs/Cargo.toml +1 -1
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglotrs/src/tokenizer.rs +7 -2
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/dialects/test_bigquery.py +1 -1
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/dialects/test_clickhouse.py +5 -1
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/dialects/test_databricks.py +1 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/dialects/test_dialect.py +172 -5
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/dialects/test_druid.py +1 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/dialects/test_duckdb.py +116 -19
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/dialects/test_exasol.py +18 -3
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/dialects/test_mysql.py +9 -2
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/dialects/test_oracle.py +63 -8
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/dialects/test_postgres.py +77 -14
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/dialects/test_presto.py +12 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/dialects/test_redshift.py +1 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/dialects/test_singlestore.py +4 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/dialects/test_snowflake.py +853 -57
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/dialects/test_spark.py +14 -2
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/dialects/test_teradata.py +1 -1
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/identity.sql +2 -1
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/annotate_functions.sql +344 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/annotate_types.sql +93 -0
- sqlglot-28.6.0/tests/test_dialect_entry_points.py +64 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/test_diff.py +7 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/test_generator.py +77 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/test_optimizer.py +61 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/test_parser.py +2 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/test_schema.py +30 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/.gitignore +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/.gitpod.yml +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/.pre-commit-config.yaml +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/CONTRIBUTING.md +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/LICENSE +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/MANIFEST.in +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/Makefile +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/pyproject.toml +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/setup.cfg +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/setup.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/__init__.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/__main__.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/_typing.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/dialects/__init__.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/dialects/athena.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/dialects/databricks.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/dialects/dremio.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/dialects/drill.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/dialects/dune.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/dialects/fabric.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/dialects/materialize.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/dialects/prql.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/dialects/risingwave.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/dialects/solr.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/dialects/sqlite.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/dialects/tableau.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/dialects/teradata.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/errors.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/executor/__init__.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/executor/context.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/executor/env.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/executor/python.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/executor/table.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/helper.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/jsonpath.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/lineage.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/optimizer/__init__.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/optimizer/canonicalize.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/optimizer/eliminate_ctes.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/optimizer/eliminate_joins.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/optimizer/eliminate_subqueries.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/optimizer/isolate_table_selects.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/optimizer/merge_subqueries.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/optimizer/normalize.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/optimizer/normalize_identifiers.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/optimizer/optimize_joins.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/optimizer/optimizer.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/optimizer/pushdown_predicates.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/optimizer/pushdown_projections.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/optimizer/qualify.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/optimizer/qualify_columns.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/optimizer/qualify_tables.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/optimizer/scope.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/optimizer/simplify.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/optimizer/unnest_subqueries.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/planner.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/py.typed +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/serde.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/time.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/transforms.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/trie.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/typing/bigquery.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/typing/presto.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/typing/tsql.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot.egg-info/dependency_links.txt +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot.egg-info/top_level.txt +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot.png +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglotrs/benches/dialect_settings.json +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglotrs/benches/long.rs +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglotrs/benches/token_type_settings.json +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglotrs/benches/tokenizer_dialect_settings.json +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglotrs/benches/tokenizer_settings.json +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglotrs/pyproject.toml +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglotrs/src/lib.rs +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglotrs/src/settings.rs +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglotrs/src/token.rs +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglotrs/src/trie.rs +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/__init__.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/dialects/__init__.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/dialects/test_athena.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/dialects/test_doris.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/dialects/test_dremio.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/dialects/test_drill.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/dialects/test_dune.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/dialects/test_fabric.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/dialects/test_hive.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/dialects/test_materialize.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/dialects/test_pipe_syntax.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/dialects/test_prql.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/dialects/test_risingwave.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/dialects/test_solr.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/dialects/test_sqlite.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/dialects/test_starrocks.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/dialects/test_tableau.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/dialects/test_trino.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/dialects/test_tsql.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/jsonpath/LICENSE +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/jsonpath/cts.json +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/canonicalize.sql +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/eliminate_ctes.sql +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/eliminate_joins.sql +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/eliminate_subqueries.sql +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/isolate_table_selects.sql +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/merge_subqueries.sql +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/normalize.sql +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/normalize_identifiers.sql +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/optimize_joins.sql +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/optimizer.sql +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/pushdown_cte_alias_columns.sql +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/pushdown_predicates.sql +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/pushdown_projections.sql +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/qualify_columns.sql +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/qualify_columns__invalid.sql +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/qualify_columns__with_invisible.sql +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/qualify_columns_ddl.sql +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/qualify_tables.sql +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/quote_identifiers.sql +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/simplify.sql +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/tpc-ds/call_center.csv.gz +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/tpc-ds/catalog_page.csv.gz +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/tpc-ds/catalog_returns.csv.gz +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/tpc-ds/catalog_sales.csv.gz +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/tpc-ds/customer.csv.gz +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/tpc-ds/customer_address.csv.gz +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/tpc-ds/customer_demographics.csv.gz +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/tpc-ds/date_dim.csv.gz +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/tpc-ds/household_demographics.csv.gz +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/tpc-ds/income_band.csv.gz +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/tpc-ds/inventory.csv.gz +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/tpc-ds/item.csv.gz +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/tpc-ds/promotion.csv.gz +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/tpc-ds/reason.csv.gz +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/tpc-ds/ship_mode.csv.gz +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/tpc-ds/store.csv.gz +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/tpc-ds/store_returns.csv.gz +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/tpc-ds/store_sales.csv.gz +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/tpc-ds/time_dim.csv.gz +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/tpc-ds/tpc-ds.sql +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/tpc-ds/warehouse.csv.gz +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/tpc-ds/web_page.csv.gz +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/tpc-ds/web_returns.csv.gz +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/tpc-ds/web_sales.csv.gz +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/tpc-ds/web_site.csv.gz +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/tpc-h/customer.csv.gz +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/tpc-h/lineitem.csv.gz +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/tpc-h/nation.csv.gz +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/tpc-h/orders.csv.gz +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/tpc-h/part.csv.gz +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/tpc-h/partsupp.csv.gz +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/tpc-h/region.csv.gz +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/tpc-h/supplier.csv.gz +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/tpc-h/tpc-h.sql +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/unnest_subqueries.sql +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/partial.sql +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/pretty.sql +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/gen_fixtures.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/helpers.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/test_build.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/test_dialect_imports.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/test_docs.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/test_errors.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/test_executor.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/test_expressions.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/test_helper.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/test_jsonpath.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/test_lineage.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/test_serde.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/test_time.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/test_tokens.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/test_transforms.py +0 -0
- {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/test_transpile.py +0 -0
|
@@ -1,6 +1,52 @@
|
|
|
1
1
|
Changelog
|
|
2
2
|
=========
|
|
3
3
|
|
|
4
|
+
## [v28.5.0] - 2025-12-17
|
|
5
|
+
### :boom: BREAKING CHANGES
|
|
6
|
+
- due to [`4dfc810`](https://github.com/tobymao/sqlglot/commit/4dfc810f45d5a617ada2ba4ed57002549c8d1853) - support transpilation of BOOLNOT from snowflake to duckdb *(PR [#6577](https://github.com/tobymao/sqlglot/pull/6577) by [@fivetran-felixhuang](https://github.com/fivetran-felixhuang))*:
|
|
7
|
+
|
|
8
|
+
support transpilation of BOOLNOT from snowflake to duckdb (#6577)
|
|
9
|
+
|
|
10
|
+
- due to [`b857185`](https://github.com/tobymao/sqlglot/commit/b8571850ca55802671484d118560a7b90e893c39) - remove Sysdate in favor of CurrentTimestamp with sysdate arg *(PR [#6584](https://github.com/tobymao/sqlglot/pull/6584) by [@georgesittas](https://github.com/georgesittas))*:
|
|
11
|
+
|
|
12
|
+
remove Sysdate in favor of CurrentTimestamp with sysdate arg (#6584)
|
|
13
|
+
|
|
14
|
+
- due to [`bf217d6`](https://github.com/tobymao/sqlglot/commit/bf217d69f92efcbce5b69d637976e915ca63998d) - make `JSONArrayAgg` an `AggFunc` *(PR [#6585](https://github.com/tobymao/sqlglot/pull/6585) by [@AbhishekASLK](https://github.com/AbhishekASLK))*:
|
|
15
|
+
|
|
16
|
+
make `JSONArrayAgg` an `AggFunc` (#6585)
|
|
17
|
+
|
|
18
|
+
- due to [`604efe5`](https://github.com/tobymao/sqlglot/commit/604efe5cf5812d0b1dd9d625ed278907d0d7fb8f) - Type annotation fixes for TO_TIMESTAMP* *(PR [#6557](https://github.com/tobymao/sqlglot/pull/6557) by [@fivetran-kwoodbeck](https://github.com/fivetran-kwoodbeck))*:
|
|
19
|
+
|
|
20
|
+
Type annotation fixes for TO_TIMESTAMP* (#6557)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
### :sparkles: New Features
|
|
24
|
+
- [`4dfc810`](https://github.com/tobymao/sqlglot/commit/4dfc810f45d5a617ada2ba4ed57002549c8d1853) - **snowflake**: support transpilation of BOOLNOT from snowflake to duckdb *(PR [#6577](https://github.com/tobymao/sqlglot/pull/6577) by [@fivetran-felixhuang](https://github.com/fivetran-felixhuang))*
|
|
25
|
+
- [`7077981`](https://github.com/tobymao/sqlglot/commit/707798166c1b45e633bd0e8d02d1c0146598b03a) - **snowflake**: Transpilation of Snowflake MONTHS_BETWEEN to DuckDB *(PR [#6561](https://github.com/tobymao/sqlglot/pull/6561) by [@fivetran-kwoodbeck](https://github.com/fivetran-kwoodbeck))*
|
|
26
|
+
- [`604efe5`](https://github.com/tobymao/sqlglot/commit/604efe5cf5812d0b1dd9d625ed278907d0d7fb8f) - **snowflake**: Type annotation fixes for TO_TIMESTAMP* *(PR [#6557](https://github.com/tobymao/sqlglot/pull/6557) by [@fivetran-kwoodbeck](https://github.com/fivetran-kwoodbeck))*
|
|
27
|
+
- [`3567880`](https://github.com/tobymao/sqlglot/commit/35678808dafb37c5d37c806682e6af9b6351bced) - add tokens to functions *(commit by [@tobymao](https://github.com/tobymao))*
|
|
28
|
+
|
|
29
|
+
### :bug: Bug Fixes
|
|
30
|
+
- [`b857185`](https://github.com/tobymao/sqlglot/commit/b8571850ca55802671484d118560a7b90e893c39) - **snowflake**: remove Sysdate in favor of CurrentTimestamp with sysdate arg *(PR [#6584](https://github.com/tobymao/sqlglot/pull/6584) by [@georgesittas](https://github.com/georgesittas))*
|
|
31
|
+
- [`bf217d6`](https://github.com/tobymao/sqlglot/commit/bf217d69f92efcbce5b69d637976e915ca63998d) - make `JSONArrayAgg` an `AggFunc` *(PR [#6585](https://github.com/tobymao/sqlglot/pull/6585) by [@AbhishekASLK](https://github.com/AbhishekASLK))*
|
|
32
|
+
- [`48f5e99`](https://github.com/tobymao/sqlglot/commit/48f5e999d3d3f6ad51c30e7a33a3a574d0e50d2b) - **duckdb**: preserve l/r-trim syntax *(PR [#6588](https://github.com/tobymao/sqlglot/pull/6588) by [@georgesittas](https://github.com/georgesittas))*
|
|
33
|
+
- :arrow_lower_right: *fixes issue [#6587](https://github.com/tobymao/sqlglot/issues/6587) opened by [@baruchoxman](https://github.com/baruchoxman)*
|
|
34
|
+
|
|
35
|
+
### :wrench: Chores
|
|
36
|
+
- [`ea0263a`](https://github.com/tobymao/sqlglot/commit/ea0263aa555591b03b06a4b6dee093fe42b545f9) - Skip integration tests GA for external contributors & fix `git diff` *(PR [#6582](https://github.com/tobymao/sqlglot/pull/6582) by [@VaggelisD](https://github.com/VaggelisD))*
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
## [v28.4.1] - 2025-12-16
|
|
40
|
+
### :boom: BREAKING CHANGES
|
|
41
|
+
- due to [`cfc9346`](https://github.com/tobymao/sqlglot/commit/cfc9346ba0477523d3de8f923d83fd09814b22ac) - bump sqlglotrs to 0.10.0 *(commit by [@tobymao](https://github.com/tobymao))*:
|
|
42
|
+
|
|
43
|
+
bump sqlglotrs to 0.10.0
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
### :wrench: Chores
|
|
47
|
+
- [`cfc9346`](https://github.com/tobymao/sqlglot/commit/cfc9346ba0477523d3de8f923d83fd09814b22ac) - bump sqlglotrs to 0.10.0 *(commit by [@tobymao](https://github.com/tobymao))*
|
|
48
|
+
|
|
49
|
+
|
|
4
50
|
## [v28.4.0] - 2025-12-16
|
|
5
51
|
### :boom: BREAKING CHANGES
|
|
6
52
|
- due to [`938f4b6`](https://github.com/tobymao/sqlglot/commit/938f4b6ebc1c0d26bd3c1400883978c79a435189) - annotate type for LAST_DAY *(PR [#5528](https://github.com/tobymao/sqlglot/pull/5528) by [@geooo109](https://github.com/geooo109))*:
|
|
@@ -11504,3 +11550,5 @@ Changelog
|
|
|
11504
11550
|
[v28.2.0]: https://github.com/tobymao/sqlglot/compare/v28.1.0...v28.2.0
|
|
11505
11551
|
[v28.3.0]: https://github.com/tobymao/sqlglot/compare/v28.2.0...v28.3.0
|
|
11506
11552
|
[v28.4.0]: https://github.com/tobymao/sqlglot/compare/v27.6.1...v28.4.0
|
|
11553
|
+
[v28.4.1]: https://github.com/tobymao/sqlglot/compare/v28.4.0...v28.4.1
|
|
11554
|
+
[v28.5.0]: https://github.com/tobymao/sqlglot/compare/v28.4.1...v28.5.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sqlglot
|
|
3
|
-
Version: 28.
|
|
3
|
+
Version: 28.6.0
|
|
4
4
|
Summary: An easily customizable SQL parser and transpiler
|
|
5
5
|
Author-email: Toby Mao <toby.mao@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -33,7 +33,7 @@ Requires-Dist: typing_extensions; extra == "dev"
|
|
|
33
33
|
Requires-Dist: maturin<2.0,>=1.4; extra == "dev"
|
|
34
34
|
Requires-Dist: pyperf; extra == "dev"
|
|
35
35
|
Provides-Extra: rs
|
|
36
|
-
Requires-Dist: sqlglotrs==0.
|
|
36
|
+
Requires-Dist: sqlglotrs==0.11.0; extra == "rs"
|
|
37
37
|
Dynamic: license-file
|
|
38
38
|
Dynamic: provides-extra
|
|
39
39
|
|
|
@@ -71,6 +71,7 @@ Contributions are very welcome in SQLGlot; read the [contribution guide](https:/
|
|
|
71
71
|
* [Used By](#used-by)
|
|
72
72
|
* [Documentation](#documentation)
|
|
73
73
|
* [Run Tests and Lint](#run-tests-and-lint)
|
|
74
|
+
* [Deployment](#deployment)
|
|
74
75
|
* [Benchmarks](#benchmarks)
|
|
75
76
|
* [Optional Dependencies](#optional-dependencies)
|
|
76
77
|
* [Supported Dialects](#supported-dialects)
|
|
@@ -565,6 +566,21 @@ make test # Unit and integration tests (or test-rs, to use the Rust tokenizer)
|
|
|
565
566
|
make check # Full test suite & linter checks
|
|
566
567
|
```
|
|
567
568
|
|
|
569
|
+
## Deployment
|
|
570
|
+
|
|
571
|
+
To deploy a new SQLGlot version, follow these steps:
|
|
572
|
+
|
|
573
|
+
1. Run `git pull` to make sure the local git repo is at the head of the main branch
|
|
574
|
+
2. If the Rust tokenizer code changed since the last version release:
|
|
575
|
+
1. Bump the `version` attribute under the `package` header in `sqlglotrs/Cargo.toml`
|
|
576
|
+
2. Run `make install-dev`. This will update the `Cargo.lock` file
|
|
577
|
+
3. Commit the changes made to `Cargo.toml` and `Cargo.lock`
|
|
578
|
+
3. Do a `git tag` operation to bump the SQLGlot version, e.g. `git tag v28.5.0`
|
|
579
|
+
4. Run `git push && git push --tags` to deploy the new version
|
|
580
|
+
|
|
581
|
+
> [!IMPORTANT]
|
|
582
|
+
> If there are any breaking changes since the last version release, make sure to deploy either a minor or major version for both sqlglot and sqlglotrs. Refer to SQLGlot's [versioning scheme](#versioning) for more information.
|
|
583
|
+
|
|
568
584
|
## Benchmarks
|
|
569
585
|
|
|
570
586
|
[Benchmarks](https://github.com/tobymao/sqlglot/blob/main/benchmarks/bench.py) run on Python 3.10.12 in seconds.
|
|
@@ -627,3 +643,29 @@ x + interval '1' month
|
|
|
627
643
|
**Official Dialects** are maintained by the core SQLGlot team with higher priority for bug fixes and feature additions.
|
|
628
644
|
|
|
629
645
|
**Community Dialects** are developed and maintained primarily through community contributions. These are fully functional but may receive lower priority for issue resolution compared to officially supported dialects. We welcome and encourage community contributions to improve these dialects.
|
|
646
|
+
|
|
647
|
+
### Creating a Dialect Plugin
|
|
648
|
+
|
|
649
|
+
If your database isn't supported, you can create a plugin that registers a custom dialect via entry points. Create a package with your dialect class and register it in `setup.py`:
|
|
650
|
+
|
|
651
|
+
```python
|
|
652
|
+
from setuptools import setup
|
|
653
|
+
|
|
654
|
+
setup(
|
|
655
|
+
name="mydb-sqlglot-dialect",
|
|
656
|
+
entry_points={
|
|
657
|
+
"sqlglot.dialects": [
|
|
658
|
+
"mydb = my_package.dialect:MyDB",
|
|
659
|
+
],
|
|
660
|
+
},
|
|
661
|
+
)
|
|
662
|
+
```
|
|
663
|
+
|
|
664
|
+
The dialect will be automatically discovered and can be used like any built-in dialect:
|
|
665
|
+
|
|
666
|
+
```python
|
|
667
|
+
from sqlglot import transpile
|
|
668
|
+
transpile("SELECT * FROM t", read="mydb", write="postgres")
|
|
669
|
+
```
|
|
670
|
+
|
|
671
|
+
See the [Custom Dialects](#custom-dialects) section for implementation details.
|
|
@@ -32,6 +32,7 @@ Contributions are very welcome in SQLGlot; read the [contribution guide](https:/
|
|
|
32
32
|
* [Used By](#used-by)
|
|
33
33
|
* [Documentation](#documentation)
|
|
34
34
|
* [Run Tests and Lint](#run-tests-and-lint)
|
|
35
|
+
* [Deployment](#deployment)
|
|
35
36
|
* [Benchmarks](#benchmarks)
|
|
36
37
|
* [Optional Dependencies](#optional-dependencies)
|
|
37
38
|
* [Supported Dialects](#supported-dialects)
|
|
@@ -526,6 +527,21 @@ make test # Unit and integration tests (or test-rs, to use the Rust tokenizer)
|
|
|
526
527
|
make check # Full test suite & linter checks
|
|
527
528
|
```
|
|
528
529
|
|
|
530
|
+
## Deployment
|
|
531
|
+
|
|
532
|
+
To deploy a new SQLGlot version, follow these steps:
|
|
533
|
+
|
|
534
|
+
1. Run `git pull` to make sure the local git repo is at the head of the main branch
|
|
535
|
+
2. If the Rust tokenizer code changed since the last version release:
|
|
536
|
+
1. Bump the `version` attribute under the `package` header in `sqlglotrs/Cargo.toml`
|
|
537
|
+
2. Run `make install-dev`. This will update the `Cargo.lock` file
|
|
538
|
+
3. Commit the changes made to `Cargo.toml` and `Cargo.lock`
|
|
539
|
+
3. Do a `git tag` operation to bump the SQLGlot version, e.g. `git tag v28.5.0`
|
|
540
|
+
4. Run `git push && git push --tags` to deploy the new version
|
|
541
|
+
|
|
542
|
+
> [!IMPORTANT]
|
|
543
|
+
> If there are any breaking changes since the last version release, make sure to deploy either a minor or major version for both sqlglot and sqlglotrs. Refer to SQLGlot's [versioning scheme](#versioning) for more information.
|
|
544
|
+
|
|
529
545
|
## Benchmarks
|
|
530
546
|
|
|
531
547
|
[Benchmarks](https://github.com/tobymao/sqlglot/blob/main/benchmarks/bench.py) run on Python 3.10.12 in seconds.
|
|
@@ -588,3 +604,29 @@ x + interval '1' month
|
|
|
588
604
|
**Official Dialects** are maintained by the core SQLGlot team with higher priority for bug fixes and feature additions.
|
|
589
605
|
|
|
590
606
|
**Community Dialects** are developed and maintained primarily through community contributions. These are fully functional but may receive lower priority for issue resolution compared to officially supported dialects. We welcome and encourage community contributions to improve these dialects.
|
|
607
|
+
|
|
608
|
+
### Creating a Dialect Plugin
|
|
609
|
+
|
|
610
|
+
If your database isn't supported, you can create a plugin that registers a custom dialect via entry points. Create a package with your dialect class and register it in `setup.py`:
|
|
611
|
+
|
|
612
|
+
```python
|
|
613
|
+
from setuptools import setup
|
|
614
|
+
|
|
615
|
+
setup(
|
|
616
|
+
name="mydb-sqlglot-dialect",
|
|
617
|
+
entry_points={
|
|
618
|
+
"sqlglot.dialects": [
|
|
619
|
+
"mydb = my_package.dialect:MyDB",
|
|
620
|
+
],
|
|
621
|
+
},
|
|
622
|
+
)
|
|
623
|
+
```
|
|
624
|
+
|
|
625
|
+
The dialect will be automatically discovered and can be used like any built-in dialect:
|
|
626
|
+
|
|
627
|
+
```python
|
|
628
|
+
from sqlglot import transpile
|
|
629
|
+
transpile("SELECT * FROM t", read="mydb", write="postgres")
|
|
630
|
+
```
|
|
631
|
+
|
|
632
|
+
See the [Custom Dialects](#custom-dialects) section for implementation details.
|
|
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
|
28
28
|
commit_id: COMMIT_ID
|
|
29
29
|
__commit_id__: COMMIT_ID
|
|
30
30
|
|
|
31
|
-
__version__ = version = '28.
|
|
32
|
-
__version_tuple__ = version_tuple = (28,
|
|
31
|
+
__version__ = version = '28.6.0'
|
|
32
|
+
__version_tuple__ = version_tuple = (28, 6, 0)
|
|
33
33
|
|
|
34
|
-
__commit_id__ = commit_id = '
|
|
34
|
+
__commit_id__ = commit_id = 'g33b8a5d25'
|
|
@@ -51,6 +51,8 @@ JSON_EXTRACT_TYPE = t.Union[exp.JSONExtract, exp.JSONExtractScalar, exp.JSONExtr
|
|
|
51
51
|
|
|
52
52
|
DQUOTES_ESCAPING_JSON_FUNCTIONS = ("JSON_QUERY", "JSON_VALUE", "JSON_QUERY_ARRAY")
|
|
53
53
|
|
|
54
|
+
MAKE_INTERVAL_KWARGS = ["year", "month", "day", "hour", "minute", "second"]
|
|
55
|
+
|
|
54
56
|
|
|
55
57
|
def _derived_table_values_to_unnest(self: BigQuery.Generator, expression: exp.Values) -> str:
|
|
56
58
|
if not expression.find_ancestor(exp.From, exp.Join):
|
|
@@ -389,7 +391,9 @@ class BigQuery(Dialect):
|
|
|
389
391
|
EXCLUDES_PSEUDOCOLUMNS_FROM_STAR = True
|
|
390
392
|
QUERY_RESULTS_ARE_STRUCTS = True
|
|
391
393
|
JSON_EXTRACT_SCALAR_SCALAR_ONLY = True
|
|
394
|
+
LEAST_GREATEST_IGNORES_NULLS = False
|
|
392
395
|
DEFAULT_NULL_TYPE = exp.DataType.Type.BIGINT
|
|
396
|
+
PRIORITIZE_NON_LITERAL_TYPES = True
|
|
393
397
|
|
|
394
398
|
# https://docs.cloud.google.com/bigquery/docs/reference/standard-sql/string_functions#initcap
|
|
395
399
|
INITCAP_DEFAULT_DELIMITER_CHARS = ' \t\n\r\f\v\\[\\](){}/|<>!?@"^#$&~_,.:;*%+\\-'
|
|
@@ -602,12 +606,6 @@ class BigQuery(Dialect):
|
|
|
602
606
|
"EDIT_DISTANCE": _build_levenshtein,
|
|
603
607
|
"FORMAT_DATE": _build_format_time(exp.TsOrDsToDate),
|
|
604
608
|
"GENERATE_ARRAY": exp.GenerateSeries.from_arg_list,
|
|
605
|
-
"GREATEST": lambda args: exp.Greatest(
|
|
606
|
-
this=seq_get(args, 0), expressions=args[1:], null_if_any_null=True
|
|
607
|
-
),
|
|
608
|
-
"LEAST": lambda args: exp.Least(
|
|
609
|
-
this=seq_get(args, 0), expressions=args[1:], null_if_any_null=True
|
|
610
|
-
),
|
|
611
609
|
"JSON_EXTRACT_SCALAR": _build_extract_json_with_default_path(exp.JSONExtractScalar),
|
|
612
610
|
"JSON_EXTRACT_ARRAY": _build_extract_json_with_default_path(exp.JSONExtractArray),
|
|
613
611
|
"JSON_EXTRACT_STRING_ARRAY": _build_extract_json_with_default_path(exp.JSONValueArray),
|
|
@@ -964,7 +962,7 @@ class BigQuery(Dialect):
|
|
|
964
962
|
def _parse_make_interval(self) -> exp.MakeInterval:
|
|
965
963
|
expr = exp.MakeInterval()
|
|
966
964
|
|
|
967
|
-
for arg_key in
|
|
965
|
+
for arg_key in MAKE_INTERVAL_KWARGS:
|
|
968
966
|
value = self._parse_lambda()
|
|
969
967
|
|
|
970
968
|
if not value:
|
|
@@ -565,6 +565,8 @@ class ClickHouse(Dialect):
|
|
|
565
565
|
"MEDIAN": lambda self: self._parse_quantile(),
|
|
566
566
|
"COLUMNS": lambda self: self._parse_columns(),
|
|
567
567
|
"TUPLE": lambda self: exp.Struct.from_arg_list(self._parse_function_args(alias=True)),
|
|
568
|
+
"AND": lambda self: exp.and_(*self._parse_function_args(alias=False)),
|
|
569
|
+
"OR": lambda self: exp.or_(*self._parse_function_args(alias=False)),
|
|
568
570
|
}
|
|
569
571
|
|
|
570
572
|
FUNCTION_PARSERS.pop("MATCH")
|
|
@@ -27,6 +27,8 @@ from sqlglot.tokens import Token, Tokenizer, TokenType
|
|
|
27
27
|
from sqlglot.trie import new_trie
|
|
28
28
|
from sqlglot.typing import EXPRESSION_METADATA
|
|
29
29
|
|
|
30
|
+
from importlib.metadata import entry_points
|
|
31
|
+
|
|
30
32
|
DATE_ADD_OR_DIFF = t.Union[
|
|
31
33
|
exp.DateAdd,
|
|
32
34
|
exp.DateDiff,
|
|
@@ -66,6 +68,8 @@ UNESCAPED_SEQUENCES = {
|
|
|
66
68
|
"\\\\": "\\",
|
|
67
69
|
}
|
|
68
70
|
|
|
71
|
+
PLUGIN_GROUP_NAME = "sqlglot.dialects"
|
|
72
|
+
|
|
69
73
|
|
|
70
74
|
class Dialects(str, Enum):
|
|
71
75
|
"""Dialects supported by SQLGLot."""
|
|
@@ -153,12 +157,54 @@ class _Dialect(type):
|
|
|
153
157
|
if isinstance(key, Dialects):
|
|
154
158
|
key = key.value
|
|
155
159
|
|
|
156
|
-
#
|
|
157
|
-
# We check that the key is an actual sqlglot module to avoid blindly importing
|
|
158
|
-
# files. Custom user dialects need to be imported at the top-level package, in
|
|
159
|
-
# order for them to be registered as soon as possible.
|
|
160
|
+
# 1. Try standard sqlglot modules first
|
|
160
161
|
if key in DIALECT_MODULE_NAMES:
|
|
162
|
+
module = importlib.import_module(f"sqlglot.dialects.{key}")
|
|
163
|
+
# If module was already imported, the class may not be in _classes
|
|
164
|
+
# Find and register the dialect class from the module
|
|
165
|
+
if key not in cls._classes:
|
|
166
|
+
for attr_name in dir(module):
|
|
167
|
+
attr = getattr(module, attr_name, None)
|
|
168
|
+
if (
|
|
169
|
+
isinstance(attr, type)
|
|
170
|
+
and issubclass(attr, Dialect)
|
|
171
|
+
and attr.__name__.lower() == key
|
|
172
|
+
):
|
|
173
|
+
cls._classes[key] = attr
|
|
174
|
+
break
|
|
175
|
+
return
|
|
176
|
+
|
|
177
|
+
# 2. Try entry points (for plugins)
|
|
178
|
+
try:
|
|
179
|
+
all_eps = entry_points()
|
|
180
|
+
# Python 3.10+ has select() method, older versions use dict-like access
|
|
181
|
+
if hasattr(all_eps, "select"):
|
|
182
|
+
eps = all_eps.select(group=PLUGIN_GROUP_NAME, name=key)
|
|
183
|
+
else:
|
|
184
|
+
# For older Python versions, entry_points() returns a dict-like object
|
|
185
|
+
group_eps = all_eps.get(PLUGIN_GROUP_NAME, []) # type: ignore
|
|
186
|
+
eps = [ep for ep in group_eps if ep.name == key] # type: ignore
|
|
187
|
+
|
|
188
|
+
for entry_point in eps:
|
|
189
|
+
dialect_class = entry_point.load()
|
|
190
|
+
# Verify it's a Dialect subclass
|
|
191
|
+
# issubclass() returns False if not a subclass, TypeError only if not a class at all
|
|
192
|
+
if isinstance(dialect_class, type) and issubclass(dialect_class, Dialect):
|
|
193
|
+
# Register the dialect using the entry point name (key)
|
|
194
|
+
# The metaclass may have registered it by class name, but we need it by entry point name
|
|
195
|
+
if key not in cls._classes:
|
|
196
|
+
cls._classes[key] = dialect_class
|
|
197
|
+
return
|
|
198
|
+
except ImportError:
|
|
199
|
+
# entry_point.load() failed (bad plugin - module/class doesn't exist)
|
|
200
|
+
pass
|
|
201
|
+
|
|
202
|
+
# 3. Try direct import (for backward compatibility)
|
|
203
|
+
# This allows namespace packages or explicit imports to work
|
|
204
|
+
try:
|
|
161
205
|
importlib.import_module(f"sqlglot.dialects.{key}")
|
|
206
|
+
except ImportError:
|
|
207
|
+
pass
|
|
162
208
|
|
|
163
209
|
@classmethod
|
|
164
210
|
def __getitem__(cls, key: str) -> t.Type[Dialect]:
|
|
@@ -741,6 +787,18 @@ class Dialect(metaclass=_Dialect):
|
|
|
741
787
|
For example, in BigQuery the default type of the NULL value is INT64.
|
|
742
788
|
"""
|
|
743
789
|
|
|
790
|
+
LEAST_GREATEST_IGNORES_NULLS = True
|
|
791
|
+
"""
|
|
792
|
+
Whether LEAST/GREATEST functions ignore NULL values, e.g:
|
|
793
|
+
- BigQuery, Snowflake, MySQL, Presto/Trino: LEAST(1, NULL, 2) -> NULL
|
|
794
|
+
- Spark, Postgres, DuckDB, TSQL: LEAST(1, NULL, 2) -> 1
|
|
795
|
+
"""
|
|
796
|
+
|
|
797
|
+
PRIORITIZE_NON_LITERAL_TYPES = False
|
|
798
|
+
"""
|
|
799
|
+
Whether to prioritize non-literal types over literals during type annotation.
|
|
800
|
+
"""
|
|
801
|
+
|
|
744
802
|
# --- Autofilled ---
|
|
745
803
|
|
|
746
804
|
tokenizer_class = Tokenizer
|
|
@@ -935,7 +993,9 @@ class Dialect(metaclass=_Dialect):
|
|
|
935
993
|
|
|
936
994
|
result = cls.get(dialect_name.strip())
|
|
937
995
|
if not result:
|
|
938
|
-
|
|
996
|
+
# Include both built-in dialects and any loaded dialects for better error messages
|
|
997
|
+
all_dialects = set(DIALECT_MODULE_NAMES) | set(cls._classes.keys())
|
|
998
|
+
suggest_closest_match_and_fail("dialect", dialect_name, all_dialects)
|
|
939
999
|
|
|
940
1000
|
assert result is not None
|
|
941
1001
|
return result(**kwargs)
|
|
@@ -1300,6 +1360,59 @@ def var_map_sql(
|
|
|
1300
1360
|
return self.func(map_func_name, *args)
|
|
1301
1361
|
|
|
1302
1362
|
|
|
1363
|
+
def months_between_sql(self: Generator, expression: exp.MonthsBetween) -> str:
|
|
1364
|
+
"""
|
|
1365
|
+
Transpile MONTHS_BETWEEN to dialects that don't have native support.
|
|
1366
|
+
|
|
1367
|
+
Snowflake's MONTHS_BETWEEN returns whole months + fractional part where:
|
|
1368
|
+
- Fractional part = (DAY(date1) - DAY(date2)) / 31
|
|
1369
|
+
- Special case: If both dates are last day of month, fractional part = 0
|
|
1370
|
+
|
|
1371
|
+
Formula: DATEDIFF('month', date2, date1) + (DAY(date1) - DAY(date2)) / 31.0
|
|
1372
|
+
"""
|
|
1373
|
+
date1 = expression.this
|
|
1374
|
+
date2 = expression.expression
|
|
1375
|
+
|
|
1376
|
+
# Cast to DATE to ensure consistent behavior
|
|
1377
|
+
date1_cast = exp.cast(date1, exp.DataType.Type.DATE, copy=False)
|
|
1378
|
+
date2_cast = exp.cast(date2, exp.DataType.Type.DATE, copy=False)
|
|
1379
|
+
|
|
1380
|
+
# Whole months: DATEDIFF('month', date2, date1)
|
|
1381
|
+
whole_months = exp.DateDiff(this=date1_cast, expression=date2_cast, unit=exp.var("month"))
|
|
1382
|
+
|
|
1383
|
+
# Day components
|
|
1384
|
+
day1 = exp.Day(this=date1_cast.copy())
|
|
1385
|
+
day2 = exp.Day(this=date2_cast.copy())
|
|
1386
|
+
|
|
1387
|
+
# Last day of month components
|
|
1388
|
+
last_day_of_month1 = exp.LastDay(this=date1_cast.copy())
|
|
1389
|
+
last_day_of_month2 = exp.LastDay(this=date2_cast.copy())
|
|
1390
|
+
|
|
1391
|
+
day_of_last_day1 = exp.Day(this=last_day_of_month1)
|
|
1392
|
+
day_of_last_day2 = exp.Day(this=last_day_of_month2)
|
|
1393
|
+
|
|
1394
|
+
# Check if both are last day of month
|
|
1395
|
+
last_day1 = exp.EQ(this=day1.copy(), expression=day_of_last_day1)
|
|
1396
|
+
last_day2 = exp.EQ(this=day2.copy(), expression=day_of_last_day2)
|
|
1397
|
+
both_last_day = exp.And(this=last_day1, expression=last_day2)
|
|
1398
|
+
|
|
1399
|
+
# Fractional part: (DAY(date1) - DAY(date2)) / 31.0
|
|
1400
|
+
fractional = exp.Div(
|
|
1401
|
+
this=exp.Paren(this=exp.Sub(this=day1.copy(), expression=day2.copy())),
|
|
1402
|
+
expression=exp.Literal.number("31.0"),
|
|
1403
|
+
)
|
|
1404
|
+
|
|
1405
|
+
# If both are last day of month, fractional = 0, else calculate fractional
|
|
1406
|
+
fractional_with_check = exp.If(
|
|
1407
|
+
this=both_last_day, true=exp.Literal.number("0"), false=fractional
|
|
1408
|
+
)
|
|
1409
|
+
|
|
1410
|
+
# Final result: whole_months + fractional
|
|
1411
|
+
result = exp.Add(this=whole_months, expression=fractional_with_check)
|
|
1412
|
+
|
|
1413
|
+
return self.sql(result)
|
|
1414
|
+
|
|
1415
|
+
|
|
1303
1416
|
def build_formatted_time(
|
|
1304
1417
|
exp_class: t.Type[E], dialect: str, default: t.Optional[bool | str] = None
|
|
1305
1418
|
) -> t.Callable[[t.List], E]:
|
|
@@ -2154,3 +2267,24 @@ def regexp_replace_global_modifier(expression: exp.RegexpReplace) -> exp.Express
|
|
|
2154
2267
|
modifiers = exp.Literal.string(value + "g")
|
|
2155
2268
|
|
|
2156
2269
|
return modifiers
|
|
2270
|
+
|
|
2271
|
+
|
|
2272
|
+
def getbit_sql(self: Generator, expression: exp.Getbit) -> str:
|
|
2273
|
+
"""
|
|
2274
|
+
Generates SQL for Getbit according to DuckDB and Postgres, transpiling it if either:
|
|
2275
|
+
|
|
2276
|
+
1. The zero index corresponds to the least-significant bit
|
|
2277
|
+
2. The input type is an integer value
|
|
2278
|
+
"""
|
|
2279
|
+
value = expression.this
|
|
2280
|
+
position = expression.expression
|
|
2281
|
+
|
|
2282
|
+
if not expression.args.get("zero_is_msb") and expression.is_type(
|
|
2283
|
+
*exp.DataType.SIGNED_INTEGER_TYPES, *exp.DataType.UNSIGNED_INTEGER_TYPES
|
|
2284
|
+
):
|
|
2285
|
+
# Use bitwise operations: (value >> position) & 1
|
|
2286
|
+
shifted = exp.BitwiseRightShift(this=value, expression=position)
|
|
2287
|
+
masked = exp.BitwiseAnd(this=shifted, expression=exp.Literal.number(1))
|
|
2288
|
+
return self.sql(masked)
|
|
2289
|
+
|
|
2290
|
+
return self.func("GET_BIT", value, position)
|