sqlty 0.2.0__tar.gz → 0.2.1__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.
- {sqlty-0.2.0 → sqlty-0.2.1}/PKG-INFO +1 -1
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/Cargo.lock +7 -4
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/Cargo.toml +2 -1
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-ext/Cargo.toml +2 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-ext/src/lib.rs +39 -20
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/Cargo.toml +1 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/api.rs +4 -1
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/dml.rs +66 -14
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/expr.rs +35 -19
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/functions.rs +16 -3
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/grouping.rs +79 -23
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/json.rs +1 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/narrowing.rs +2 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/nullability.rs +12 -5
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/operators.rs +23 -9
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/preprocess.rs +33 -2
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/query.rs +59 -3
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/resolve.rs +9 -1
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/respell.rs +13 -1
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/catalog/alter.rs +13 -5
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/catalog/columns.rs +21 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/catalog/mod.rs +6 -1
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/catalog/read.rs +5 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/catalog/resolve.rs +27 -2
- {sqlty-0.2.0 → sqlty-0.2.1}/skills/sqlty-ci/SKILL.md +1 -1
- {sqlty-0.2.0 → sqlty-0.2.1}/src/sqlty/_check.py +2 -3
- {sqlty-0.2.0 → sqlty-0.2.1}/src/sqlty/_drivers.py +63 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/src/sqlty/_source.py +12 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/src/sqlty/core.py +2 -1
- {sqlty-0.2.0 → sqlty-0.2.1}/src/sqlty/rules/param-type-mismatch.md +4 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/src/sqlty/rules/ungrouped-column.md +3 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/src/sqlty/rules/unparsed-query.md +3 -1
- {sqlty-0.2.0 → sqlty-0.2.1}/LICENSE +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/README.md +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/pyproject.toml +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-ext/build.rs +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-python/Cargo.toml +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-python/src/checker.rs +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-python/src/edit.rs +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-python/src/fixer.rs +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-python/src/lib.rs +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-python/src/options.rs +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-python/src/rewriter.rs +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-python/src/rules.rs +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-python/src/scan.rs +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-python/src/template.rs +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-python/src/tokens.rs +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/build.rs +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/README.md +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/common/aggregates.inference.toml +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/common/arithmetic.inference.toml +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/common/comparison.inference.toml +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/common/concat.inference.toml +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/common/conditional.inference.toml +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/common/datetime.inference.toml +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/common/json.inference.toml +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/common/math.inference.toml +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/common/strings.inference.toml +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/common/window.inference.toml +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/compile.rs +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/dialects.toml +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/mysql/aggregates.inference.toml +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/mysql/arithmetic.inference.toml +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/mysql/bits.inference.toml +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/mysql/comparison.inference.toml +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/mysql/concat.inference.toml +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/mysql/conditional.inference.toml +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/mysql/datetime.inference.toml +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/mysql/encryption.inference.toml +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/mysql/json.inference.toml +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/mysql/math.inference.toml +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/mysql/misc.inference.toml +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/mysql/spatial.inference.toml +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/mysql/strings.inference.toml +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/mysql/system.inference.toml +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/postgres/admin.inference.toml +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/postgres/aggregates.inference.toml +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/postgres/arithmetic.inference.toml +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/postgres/arrays.inference.toml +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/postgres/binary.inference.toml +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/postgres/comparison.inference.toml +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/postgres/concat.inference.toml +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/postgres/conditional.inference.toml +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/postgres/datetime.inference.toml +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/postgres/enums.inference.toml +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/postgres/events.inference.toml +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/postgres/extensions.inference.toml +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/postgres/formatting.inference.toml +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/postgres/geometry.inference.toml +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/postgres/json.inference.toml +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/postgres/math.inference.toml +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/postgres/merge.inference.toml +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/postgres/network.inference.toml +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/postgres/ranges.inference.toml +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/postgres/rows.inference.toml +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/postgres/sequences.inference.toml +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/postgres/series.inference.toml +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/postgres/strings.inference.toml +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/postgres/system.inference.toml +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/postgres/textsearch.inference.toml +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/postgres/uuid.inference.toml +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/postgres/xml.inference.toml +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/sqlite/aggregates.inference.toml +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/sqlite/arithmetic.inference.toml +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/sqlite/bitwise.inference.toml +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/sqlite/datetime.inference.toml +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/sqlite/fts.inference.toml +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/sqlite/json.inference.toml +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/sqlite/math.inference.toml +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/sqlite/scalar.inference.toml +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/sqlite/strings.inference.toml +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/dialect.rs +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/explain.rs +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/hashing.rs +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/inference.rs +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/literals.rs +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/memo.rs +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/merged_star.rs +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/mod.rs +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/names.rs +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/params.rs +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/pg_record_functions.rs +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/references.rs +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/registry.rs +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/scope.rs +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__dml__tests__returning_columns_in_queries.snap +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__expr__tests__arrays_and_subscripts.snap +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__expr__tests__case_expressions.snap +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__expr__tests__casts.snap +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__expr__tests__casts_without_a_schema_do_not_complain.snap +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__expr__tests__composite_fields_and_json_access.snap +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__expr__tests__literals_and_unary_operators.snap +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__expr__tests__misc_expressions.snap +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__expr__tests__mysql_and_sqlite_expressions.snap +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__functions__tests__aggregates_in_postgres.snap +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__functions__tests__function_availability_differs_by_dialect.snap +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__functions__tests__return_types_follow_the_argument.snap +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__functions__tests__unknown_functions_are_untyped_and_explained.snap +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__literals__tests__value_sets_flow_through_expressions.snap +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__names__tests__column_names_follow_postgres_figure_colname.snap +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__operators__tests__arithmetic_promotes_numbers_and_types_date_math.snap +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__operators__tests__binary_operators_in_queries.snap +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__operators__tests__common_type_follows_postgres_union_rules.snap +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__operators__tests__division_differs_between_postgres_and_mysql.snap +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__query__tests__column_names_come_from_the_first_branch.snap +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__query__tests__ctes.snap +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__query__tests__dialects_name_and_type_the_same_query_differently.snap +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__query__tests__projection_forms.snap +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__query__tests__recursive_ctes_settle_nullability.snap +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__query__tests__set_operations_combine_nullability.snap +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__query__tests__set_operations_unify_types.snap +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__query__tests__statements_that_are_not_queries_have_no_columns.snap +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__query__tests__unsupported_query_forms_are_explained.snap +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__query__tests__values_lists.snap +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__resolve__tests__ambiguous_names_are_reported_once_per_query.snap +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__resolve__tests__cte_columns_are_resolved_like_tables.snap +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__resolve__tests__names_are_not_judged_without_a_schema.snap +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__resolve__tests__nullability_comes_from_the_declaration.snap +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__resolve__tests__quoted_names_keep_their_case_in_postgres_only.snap +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__resolve__tests__star_over_unreadable_sources_names_the_reason.snap +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__resolve__tests__system_columns_exist_without_being_declared.snap +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__resolve__tests__unknown_names_say_what_is_missing.snap +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__resolve__tests__unqualified_names_resolve_to_the_first_source_that_has_them.snap +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__scope__tests__correlated_subqueries_see_the_outer_scope.snap +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__scope__tests__derived_tables_ctes_and_views.snap +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__scope__tests__nullability_follows_the_join_kind.snap +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__scope__tests__opaque_sources_explain_themselves.snap +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__scope__tests__star_expansion_over_joins.snap +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__scope__tests__table_names_fold_by_dialect.snap +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/sql_type.rs +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/star_expand.rs +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/table_functions.rs +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/test_support.rs +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/tests.rs +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/text_names.rs +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/typed.rs +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/catalog/builtin_catalog.sql +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/catalog/loader.rs +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/catalog/names.rs +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/ddl.rs +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/diagnostics.rs +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/json.rs +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/lib.rs +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/placeholders.rs +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/values.rs +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/tests/inference_compiler.rs +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/tests/timing.rs +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/skills/sqlty/SKILL.md +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/skills/sqlty-adopt/SKILL.md +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/skills/sqlty-breaking/SKILL.md +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/skills/sqlty-check/SKILL.md +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/skills/sqlty-rewrite/SKILL.md +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/src/sqlty/__init__.py +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/src/sqlty/__main__.py +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/src/sqlty/_breaking.py +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/src/sqlty/_cli.py +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/src/sqlty/_config.py +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/src/sqlty/_core.pyi +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/src/sqlty/_decode.py +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/src/sqlty/_gitignore.py +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/src/sqlty/_helpers.py +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/src/sqlty/_json_shape.py +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/src/sqlty/_json_types.py +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/src/sqlty/_lint.py +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/src/sqlty/_params.py +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/src/sqlty/_psycopg.py +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/src/sqlty/_snapshot.py +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/src/sqlty/_type_extractor/__init__.py +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/src/sqlty/_type_extractor/ast_fields.py +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/src/sqlty/_type_extractor/compat.py +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/src/sqlty/_type_extractor/extract.py +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/src/sqlty/_type_extractor/generic.py +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/src/sqlty/_type_extractor/info.py +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/src/sqlty/_type_extractor/sandbox.py +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/src/sqlty/_type_extractor/subtype.py +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/src/sqlty/drivers/psycopg.py +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/src/sqlty/magic.py +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/src/sqlty/py.typed +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/src/sqlty/rules/ambiguous-column.md +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/src/sqlty/rules/column-count-mismatch.md +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/src/sqlty/rules/column-name-mismatch.md +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/src/sqlty/rules/column-type-mismatch.md +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/src/sqlty/rules/fstring-skipped.md +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/src/sqlty/rules/inline-sql-comment.md +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/src/sqlty/rules/insert-missing-column.md +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/src/sqlty/rules/insert-value-count.md +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/src/sqlty/rules/json-shape-mismatch.md +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/src/sqlty/rules/literal-mismatch.md +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/src/sqlty/rules/mysql-sql-marker.md +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/src/sqlty/rules/narrow-type.md +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/src/sqlty/rules/nullable-mismatch.md +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/src/sqlty/rules/param-count-mismatch.md +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/src/sqlty/rules/redundant-literal.md +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/src/sqlty/rules/redundant-optional.md +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/src/sqlty/rules/select-star-no-schema.md +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/src/sqlty/rules/select-star.md +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/src/sqlty/rules/stale-rewrite.md +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/src/sqlty/rules/stale-type.md +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/src/sqlty/rules/tstring-skipped.md +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/src/sqlty/rules/typeddict-inheritance.md +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/src/sqlty/rules/typeddict-key-mismatch.md +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/src/sqlty/rules/unchecked-query.md +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/src/sqlty/rules/unknown-column.md +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/src/sqlty/rules/unknown-function.md +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/src/sqlty/rules/unknown-table.md +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/src/sqlty/rules/unknown-type.md +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/src/sqlty/rules/unsupported-syntax.md +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/src/sqlty/rules/untyped-query.md +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/src/sqlty/rules/unused-ignore.md +0 -0
- {sqlty-0.2.0 → sqlty-0.2.1}/src/sqlty_magic.pth +0 -0
|
@@ -614,7 +614,7 @@ dependencies = [
|
|
|
614
614
|
|
|
615
615
|
[[package]]
|
|
616
616
|
name = "sqlty-bench"
|
|
617
|
-
version = "0.2.
|
|
617
|
+
version = "0.2.1"
|
|
618
618
|
dependencies = [
|
|
619
619
|
"criterion",
|
|
620
620
|
"sqlty-python",
|
|
@@ -623,17 +623,19 @@ dependencies = [
|
|
|
623
623
|
|
|
624
624
|
[[package]]
|
|
625
625
|
name = "sqlty-core"
|
|
626
|
-
version = "0.2.
|
|
626
|
+
version = "0.2.1"
|
|
627
627
|
dependencies = [
|
|
628
628
|
"pyo3",
|
|
629
|
+
"recursive",
|
|
629
630
|
"sqlty-python",
|
|
630
631
|
"sqlty-sql",
|
|
632
|
+
"stacker",
|
|
631
633
|
"thiserror",
|
|
632
634
|
]
|
|
633
635
|
|
|
634
636
|
[[package]]
|
|
635
637
|
name = "sqlty-python"
|
|
636
|
-
version = "0.2.
|
|
638
|
+
version = "0.2.1"
|
|
637
639
|
dependencies = [
|
|
638
640
|
"regex",
|
|
639
641
|
"sqlty-sql",
|
|
@@ -642,9 +644,10 @@ dependencies = [
|
|
|
642
644
|
|
|
643
645
|
[[package]]
|
|
644
646
|
name = "sqlty-sql"
|
|
645
|
-
version = "0.2.
|
|
647
|
+
version = "0.2.1"
|
|
646
648
|
dependencies = [
|
|
647
649
|
"insta",
|
|
650
|
+
"recursive",
|
|
648
651
|
"regex",
|
|
649
652
|
"rustc-hash",
|
|
650
653
|
"serde",
|
|
@@ -3,7 +3,7 @@ resolver = "2"
|
|
|
3
3
|
members = ["crates/*"]
|
|
4
4
|
|
|
5
5
|
[workspace.package]
|
|
6
|
-
version = "0.2.
|
|
6
|
+
version = "0.2.1"
|
|
7
7
|
edition = "2021"
|
|
8
8
|
description = "Rust engine of sqlty: SQL type inference and Python source rewriting"
|
|
9
9
|
license = "MIT"
|
|
@@ -15,6 +15,7 @@ rust-version = "1.88"
|
|
|
15
15
|
pyo3 = { version = "0.29", features = ["extension-module"] }
|
|
16
16
|
sqlparser = { version = "0.63", features = ["visitor"] }
|
|
17
17
|
regex = "1"
|
|
18
|
+
recursive = "0.1"
|
|
18
19
|
rustc-hash = "2"
|
|
19
20
|
thiserror = "2"
|
|
20
21
|
insta = "1.49"
|
|
@@ -187,7 +187,7 @@ fn load_schema(
|
|
|
187
187
|
let dialect = dialect.0;
|
|
188
188
|
let overrides = analyzer::TypeOverrides::new(&types.unwrap_or_default(), dialect)
|
|
189
189
|
.map_err(PyValueError::new_err)?;
|
|
190
|
-
let loaded =
|
|
190
|
+
let loaded = detach(py, || {
|
|
191
191
|
let (schema, skipped) = if overrides.is_empty() {
|
|
192
192
|
analyzer::load_schema_with_skipped(schema_sql, dialect)
|
|
193
193
|
} else {
|
|
@@ -294,7 +294,20 @@ fn infer_type(
|
|
|
294
294
|
schema_sql: Option<SchemaArg>,
|
|
295
295
|
) -> Result<Option<String>, Error> {
|
|
296
296
|
let dialect = dialect.0;
|
|
297
|
-
Ok(
|
|
297
|
+
Ok(detach(py, || {
|
|
298
|
+
analyzer::infer_type(sql, dialect, schema(schema_sql, dialect).as_deref())
|
|
299
|
+
})?)
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/// The stack the analyzer's recursion keeps free: it moves to a new stack of
|
|
303
|
+
/// [`STACK_SEGMENT`] when less is left, so an expression nested `MAX_DEPTH` (1000) levels
|
|
304
|
+
/// deep fits whatever thread calls it.
|
|
305
|
+
const STACK_RED_ZONE: usize = 2 << 20;
|
|
306
|
+
const STACK_SEGMENT: usize = 16 << 20;
|
|
307
|
+
|
|
308
|
+
/// Runs `f` without the GIL, with at least [`STACK_RED_ZONE`] of stack.
|
|
309
|
+
fn detach<T: Send, F: Send + FnOnce() -> T>(py: Python<'_>, f: F) -> T {
|
|
310
|
+
py.detach(|| stacker::maybe_grow(STACK_RED_ZONE, STACK_SEGMENT, f))
|
|
298
311
|
}
|
|
299
312
|
|
|
300
313
|
include!(concat!(env!("OUT_DIR"), "/skills.rs"));
|
|
@@ -320,7 +333,7 @@ fn analyze_select(
|
|
|
320
333
|
schema_sql: Option<SchemaArg>,
|
|
321
334
|
) -> Result<Option<Vec<ColumnTuple>>, Error> {
|
|
322
335
|
let dialect = dialect.0;
|
|
323
|
-
let columns =
|
|
336
|
+
let columns = detach(py, || {
|
|
324
337
|
analyzer::analyze_select(sql, dialect, schema(schema_sql, dialect).as_deref())
|
|
325
338
|
})?;
|
|
326
339
|
Ok(columns.map(|columns| {
|
|
@@ -349,7 +362,7 @@ fn explain_select(
|
|
|
349
362
|
schema_sql: Option<SchemaArg>,
|
|
350
363
|
) -> Option<Vec<ColumnRulesTuple>> {
|
|
351
364
|
let dialect = dialect.0;
|
|
352
|
-
let columns =
|
|
365
|
+
let columns = detach(py, || {
|
|
353
366
|
analyzer::explain_select(sql, dialect, schema(schema_sql, dialect).as_deref())
|
|
354
367
|
})?;
|
|
355
368
|
let tuple = |rule: analyzer::RuleRef| (rule.id, rule.reference, rule.reasoning);
|
|
@@ -385,7 +398,7 @@ fn analyze_columns(
|
|
|
385
398
|
schema_sql: Option<SchemaArg>,
|
|
386
399
|
) -> Result<Option<Vec<NullableColumnTuple>>, Error> {
|
|
387
400
|
let dialect = dialect.0;
|
|
388
|
-
let columns =
|
|
401
|
+
let columns = detach(py, || {
|
|
389
402
|
analyzer::analyze_select(sql, dialect, schema(schema_sql, dialect).as_deref())
|
|
390
403
|
})?;
|
|
391
404
|
Ok(columns.map(|columns| {
|
|
@@ -448,7 +461,7 @@ fn analyze_params(
|
|
|
448
461
|
schema_sql: Option<SchemaArg>,
|
|
449
462
|
) -> Option<Vec<ParamTuple>> {
|
|
450
463
|
let dialect = dialect.0;
|
|
451
|
-
let params =
|
|
464
|
+
let params = detach(py, || {
|
|
452
465
|
analyzer::analyze_params(sql, dialect, schema(schema_sql, dialect).as_deref())
|
|
453
466
|
})?;
|
|
454
467
|
Some(
|
|
@@ -509,7 +522,7 @@ fn query_diagnostics(
|
|
|
509
522
|
schema_sql: Option<SchemaArg>,
|
|
510
523
|
) -> Vec<(String, String)> {
|
|
511
524
|
let dialect = dialect.0;
|
|
512
|
-
|
|
525
|
+
detach(py, || {
|
|
513
526
|
analyzer::analyze_with_diagnostics(sql, dialect, schema(schema_sql, dialect).as_deref())
|
|
514
527
|
.1
|
|
515
528
|
.into_iter()
|
|
@@ -528,7 +541,7 @@ fn schema_skipped_tables(
|
|
|
528
541
|
dialect: DialectArg,
|
|
529
542
|
) -> Vec<String> {
|
|
530
543
|
let dialect = dialect.0;
|
|
531
|
-
|
|
544
|
+
detach(py, || skipped_objects(schema_sql, dialect, Some("table")))
|
|
532
545
|
.into_iter()
|
|
533
546
|
.map(|(_, name)| name)
|
|
534
547
|
.collect()
|
|
@@ -544,7 +557,7 @@ fn schema_skipped_objects(
|
|
|
544
557
|
dialect: DialectArg,
|
|
545
558
|
) -> Vec<(String, String)> {
|
|
546
559
|
let dialect = dialect.0;
|
|
547
|
-
|
|
560
|
+
detach(py, || skipped_objects(schema_sql, dialect, None))
|
|
548
561
|
}
|
|
549
562
|
|
|
550
563
|
fn skipped_objects<S: AsRef<str>>(
|
|
@@ -569,7 +582,7 @@ fn skipped_objects<S: AsRef<str>>(
|
|
|
569
582
|
#[pyo3(signature = (sql, *, dialect = DialectArg::POSTGRES))]
|
|
570
583
|
fn parse_error(py: Python<'_>, sql: &str, dialect: DialectArg) -> Option<String> {
|
|
571
584
|
let dialect = dialect.0;
|
|
572
|
-
|
|
585
|
+
detach(py, || analyzer::parse_error(sql, dialect))
|
|
573
586
|
}
|
|
574
587
|
|
|
575
588
|
/// Whether a query yields rows: a query, DML with RETURNING, or unparseable SQL.
|
|
@@ -579,7 +592,7 @@ fn parse_error(py: Python<'_>, sql: &str, dialect: DialectArg) -> Option<String>
|
|
|
579
592
|
#[pyo3(signature = (sql, *, dialect = DialectArg::POSTGRES))]
|
|
580
593
|
fn returns_rows(py: Python<'_>, sql: &str, dialect: DialectArg) -> bool {
|
|
581
594
|
let dialect = dialect.0;
|
|
582
|
-
|
|
595
|
+
detach(py, || analyzer::returns_rows(sql, dialect))
|
|
583
596
|
}
|
|
584
597
|
|
|
585
598
|
/// Rewrite Python source: "--sql\n..." -> SQL[T]("--sql\n...").
|
|
@@ -603,7 +616,7 @@ fn rewrite_source(
|
|
|
603
616
|
keep_lines: bool,
|
|
604
617
|
) -> Result<String, Error> {
|
|
605
618
|
let dialect = dialect.0;
|
|
606
|
-
|
|
619
|
+
detach(py, || {
|
|
607
620
|
let schema = schema_for(source, schema_sql, dialect);
|
|
608
621
|
let options = Options::new(dialect, schema.as_deref(), import_style, untyped)?;
|
|
609
622
|
Ok(rewriter::rewrite_source_with(source, &options, keep_lines))
|
|
@@ -619,7 +632,7 @@ fn rewrite_source(
|
|
|
619
632
|
#[pyfunction]
|
|
620
633
|
#[pyo3(signature = (source, *, import_style = None))]
|
|
621
634
|
fn strip_source(py: Python<'_>, source: &str, import_style: Option<&str>) -> Result<String, Error> {
|
|
622
|
-
|
|
635
|
+
detach(py, || {
|
|
623
636
|
let style = ImportStyle::parse(import_style)?;
|
|
624
637
|
Ok(rewriter::strip_source(source, &style))
|
|
625
638
|
})
|
|
@@ -649,7 +662,7 @@ fn fix_source(
|
|
|
649
662
|
suppressed: Option<rewriter::Suppressed>,
|
|
650
663
|
) -> Result<String, Error> {
|
|
651
664
|
let dialect = dialect.0;
|
|
652
|
-
|
|
665
|
+
detach(py, || {
|
|
653
666
|
let schema = schema_for(source, schema_sql, dialect);
|
|
654
667
|
let options = Options::new(dialect, schema.as_deref(), import_style, untyped)?;
|
|
655
668
|
let rules = RuleConfig::from_overrides(rules).map_err(ConfigError::from)?;
|
|
@@ -675,7 +688,9 @@ fn expand_star(
|
|
|
675
688
|
schema_sql: Option<SchemaArg>,
|
|
676
689
|
) -> Option<String> {
|
|
677
690
|
let dialect = dialect.0;
|
|
678
|
-
|
|
691
|
+
detach(py, || {
|
|
692
|
+
analyzer::expand_star(sql, dialect, schema(schema_sql, dialect).as_deref())
|
|
693
|
+
})
|
|
679
694
|
}
|
|
680
695
|
|
|
681
696
|
/// `(rule, message)` of `select-star` or `select-star-no-schema` for a query whose
|
|
@@ -693,8 +708,10 @@ fn select_star_finding(
|
|
|
693
708
|
has_schema: bool,
|
|
694
709
|
) -> Option<(&'static str, String)> {
|
|
695
710
|
let dialect = dialect.0;
|
|
696
|
-
|
|
697
|
-
|
|
711
|
+
detach(py, || {
|
|
712
|
+
checker::select_star_finding(sql, dialect, has_schema)
|
|
713
|
+
})
|
|
714
|
+
.map(|(rule, message)| (rule.name(), message))
|
|
698
715
|
}
|
|
699
716
|
|
|
700
717
|
/// A finding of `check_source`, which Python reads as a dict.
|
|
@@ -737,7 +754,7 @@ fn check_source(
|
|
|
737
754
|
any_calls: Vec<usize>,
|
|
738
755
|
) -> Result<Vec<DiagnosticOut>, Error> {
|
|
739
756
|
let dialect = dialect.0;
|
|
740
|
-
|
|
757
|
+
detach(py, || {
|
|
741
758
|
let schema = schema_for(source, schema_sql, dialect);
|
|
742
759
|
let options = Options::new(dialect, schema.as_deref(), import_style, untyped)?;
|
|
743
760
|
let rules = RuleConfig::from_overrides(rules).map_err(ConfigError::from)?;
|
|
@@ -767,7 +784,7 @@ fn wrapped_queries(
|
|
|
767
784
|
source: &str,
|
|
768
785
|
import_style: Option<&str>,
|
|
769
786
|
) -> Result<Vec<(usize, String, Option<String>)>, Error> {
|
|
770
|
-
|
|
787
|
+
detach(py, || {
|
|
771
788
|
let style = ImportStyle::parse(import_style)?;
|
|
772
789
|
Ok(checker::wrapped_queries(source, &style))
|
|
773
790
|
})
|
|
@@ -795,7 +812,7 @@ fn query_sites(
|
|
|
795
812
|
import_style: Option<&str>,
|
|
796
813
|
any_calls: Vec<usize>,
|
|
797
814
|
) -> Result<Vec<(usize, String, String)>, Error> {
|
|
798
|
-
|
|
815
|
+
detach(py, || {
|
|
799
816
|
let style = ImportStyle::parse(import_style)?;
|
|
800
817
|
Ok(checker::query_sites(source, &style, &any_calls)
|
|
801
818
|
.into_iter()
|
|
@@ -808,6 +825,8 @@ fn query_sites(
|
|
|
808
825
|
/// module runs without the GIL on free-threaded builds.
|
|
809
826
|
#[pymodule(gil_used = false)]
|
|
810
827
|
fn _core(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
|
828
|
+
recursive::set_minimum_stack_size(STACK_RED_ZONE);
|
|
829
|
+
recursive::set_stack_allocation_size(STACK_SEGMENT);
|
|
811
830
|
m.add_function(wrap_pyfunction!(infer_type, m)?)?;
|
|
812
831
|
m.add_function(wrap_pyfunction!(load_schema, m)?)?;
|
|
813
832
|
m.add_class::<SchemaHandle>()?;
|
|
@@ -10,7 +10,7 @@ use super::dialect::SqlDialect;
|
|
|
10
10
|
use super::dml::statement_returns_rows;
|
|
11
11
|
use super::expr::from_sql_type;
|
|
12
12
|
use super::names::alias_name;
|
|
13
|
-
use super::preprocess::{parse_first, parse_query, parser_input};
|
|
13
|
+
use super::preprocess::{parse_first, parse_query, parser_input, too_deep, MAX_DEPTH};
|
|
14
14
|
use super::query::{Analyzer, Column};
|
|
15
15
|
use super::{Inferred, Schema, SchemaData, SkippedObject, ANY};
|
|
16
16
|
|
|
@@ -166,6 +166,9 @@ pub fn parse_error(sql: &str, dialect: &str) -> Option<String> {
|
|
|
166
166
|
let input = parser_input(sql, dialect);
|
|
167
167
|
Some(
|
|
168
168
|
match Parser::parse_sql(dialect.parser_dialect().as_ref(), &input) {
|
|
169
|
+
Ok(stmts) if too_deep(&stmts) => {
|
|
170
|
+
format!("expressions nest more than {MAX_DEPTH} levels deep")
|
|
171
|
+
}
|
|
169
172
|
Ok(_) => "unsupported in this dialect".to_string(),
|
|
170
173
|
Err(err) => {
|
|
171
174
|
let text = err.to_string();
|
|
@@ -24,12 +24,24 @@ pub(super) fn statement_returns_rows(stmt: &Statement) -> bool {
|
|
|
24
24
|
| SetExpr::Update(inner)
|
|
25
25
|
| SetExpr::Delete(inner)
|
|
26
26
|
| SetExpr::Merge(inner) => statement_returns_rows(inner),
|
|
27
|
-
|
|
27
|
+
body => !selects_into(body),
|
|
28
28
|
},
|
|
29
29
|
_ => returning(stmt).is_some(),
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
+
/// Whether a query stores its rows instead of returning them: PostgreSQL's
|
|
34
|
+
/// `SELECT ... INTO table`, MySQL's `SELECT ... INTO @variable`. Only the first `SELECT` of
|
|
35
|
+
/// a set operation may have `INTO`.
|
|
36
|
+
pub(super) fn selects_into(body: &SetExpr) -> bool {
|
|
37
|
+
match body {
|
|
38
|
+
SetExpr::Select(select) => select.into.is_some(),
|
|
39
|
+
SetExpr::SetOperation { left, .. } => selects_into(left),
|
|
40
|
+
SetExpr::Query(query) => selects_into(&query.body),
|
|
41
|
+
_ => false,
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
33
45
|
/// The non-empty top-level RETURNING list of INSERT/UPDATE/DELETE/MERGE.
|
|
34
46
|
pub(super) fn returning(stmt: &Statement) -> Option<&[SelectItem]> {
|
|
35
47
|
let items = match stmt {
|
|
@@ -218,17 +230,16 @@ impl Analyzer<'_> {
|
|
|
218
230
|
let TableObject::TableName(name) = &insert.table else {
|
|
219
231
|
return self.facts.clone();
|
|
220
232
|
};
|
|
233
|
+
let table = self
|
|
234
|
+
.schema
|
|
235
|
+
.table(&table_key(name, self.dialect))
|
|
236
|
+
.unwrap_or_default();
|
|
221
237
|
let columns: Vec<String> = if insert.columns.is_empty() {
|
|
222
|
-
|
|
223
|
-
.
|
|
224
|
-
.
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
.filter(|c| !c.invisible)
|
|
228
|
-
.map(|c| c.ident.clone())
|
|
229
|
-
.collect()
|
|
230
|
-
})
|
|
231
|
-
.unwrap_or_default()
|
|
238
|
+
table
|
|
239
|
+
.iter()
|
|
240
|
+
.filter(|c| !c.invisible)
|
|
241
|
+
.map(|c| c.ident.clone())
|
|
242
|
+
.collect()
|
|
232
243
|
} else {
|
|
233
244
|
insert
|
|
234
245
|
.columns
|
|
@@ -237,16 +248,57 @@ impl Analyzer<'_> {
|
|
|
237
248
|
.map(|ident| ident.value.clone())
|
|
238
249
|
.collect()
|
|
239
250
|
};
|
|
251
|
+
// `None` for `DEFAULT VALUES`, which writes no column.
|
|
240
252
|
let values = insert
|
|
241
253
|
.source
|
|
242
254
|
.as_deref()
|
|
243
|
-
.
|
|
244
|
-
|
|
255
|
+
.map(|source| quiet.query_columns(source).ok().flatten());
|
|
256
|
+
let written = match &values {
|
|
257
|
+
None => Some(0),
|
|
258
|
+
Some(values) => values.as_ref().map(Vec::len),
|
|
259
|
+
};
|
|
260
|
+
// A column the INSERT leaves out gets its DEFAULT; `VALUES` shorter than the
|
|
261
|
+
// table leaves out the last columns.
|
|
262
|
+
let listed: Option<Vec<String>> = if insert.columns.is_empty() {
|
|
263
|
+
written.map(|count| {
|
|
264
|
+
table
|
|
265
|
+
.iter()
|
|
266
|
+
.filter(|c| !c.invisible)
|
|
267
|
+
.take(count)
|
|
268
|
+
.map(|c| c.name.clone())
|
|
269
|
+
.collect()
|
|
270
|
+
})
|
|
271
|
+
} else {
|
|
272
|
+
Some(
|
|
273
|
+
insert
|
|
274
|
+
.columns
|
|
275
|
+
.iter()
|
|
276
|
+
.filter_map(|column| column.0.last().and_then(|part| part.as_ident()))
|
|
277
|
+
.map(|ident| fold(ident, self.dialect))
|
|
278
|
+
.collect(),
|
|
279
|
+
)
|
|
280
|
+
};
|
|
281
|
+
let defaulted = listed.into_iter().flat_map(|listed| {
|
|
282
|
+
table
|
|
283
|
+
.iter()
|
|
284
|
+
.filter(move |c| !listed.contains(&c.name))
|
|
285
|
+
.filter(|c| {
|
|
286
|
+
c.default.as_ref().is_some_and(|default| {
|
|
287
|
+
non_null(quiet.nullability(
|
|
288
|
+
default,
|
|
289
|
+
&Scope::new(),
|
|
290
|
+
&Facts::default(),
|
|
291
|
+
))
|
|
292
|
+
})
|
|
293
|
+
})
|
|
294
|
+
.map(|c| c.name.clone())
|
|
295
|
+
});
|
|
245
296
|
let inserted: Vec<String> = columns
|
|
246
297
|
.into_iter()
|
|
247
|
-
.zip(
|
|
298
|
+
.zip(values.flatten().unwrap_or_default())
|
|
248
299
|
.filter(|(_, value)| non_null(value.nullability))
|
|
249
300
|
.map(|(column, _)| column)
|
|
301
|
+
.chain(defaulted)
|
|
250
302
|
.collect();
|
|
251
303
|
match &insert.on {
|
|
252
304
|
None
|
|
@@ -5,7 +5,7 @@ use sqlparser::ast::{
|
|
|
5
5
|
FunctionArguments, Ident, ObjectName, Subscript, UnaryOperator, Value,
|
|
6
6
|
};
|
|
7
7
|
|
|
8
|
-
use crate::catalog::{fold, FunctionReturn};
|
|
8
|
+
use crate::catalog::{fold, FunctionReturn, SchemaColumn};
|
|
9
9
|
use crate::diagnostics::NameRule;
|
|
10
10
|
|
|
11
11
|
use super::dialect::SqlDialect;
|
|
@@ -102,16 +102,12 @@ impl<'a> Analyzer<'a> {
|
|
|
102
102
|
/// the composite's name when it declares no such field. In PostgreSQL each table is
|
|
103
103
|
/// also the composite type of its rows.
|
|
104
104
|
fn field_typed(&self, composite: Option<&str>, field: &Ident) -> Result<Typed, String> {
|
|
105
|
-
let
|
|
106
|
-
let Some((name, fields)) = composite.map(str::to_lowercase).and_then(|name| {
|
|
107
|
-
let fields = self
|
|
108
|
-
.schema
|
|
109
|
-
.composite(&name)
|
|
110
|
-
.or_else(|| postgres.then(|| self.schema.table(&name)).flatten())?;
|
|
111
|
-
Some((name, fields))
|
|
112
|
-
}) else {
|
|
105
|
+
let Some((name, fields)) = composite.and_then(|name| self.composite_fields(name)) else {
|
|
113
106
|
return Ok(Typed::UNKNOWN);
|
|
114
107
|
};
|
|
108
|
+
if is_field_star(field) {
|
|
109
|
+
return Ok(Typed::UNKNOWN);
|
|
110
|
+
}
|
|
115
111
|
let field = fold(field, self.dialect);
|
|
116
112
|
match fields.iter().find(|col| col.name == field) {
|
|
117
113
|
Some(col) => Ok(col.typed(self.dialect)),
|
|
@@ -119,6 +115,18 @@ impl<'a> Analyzer<'a> {
|
|
|
119
115
|
}
|
|
120
116
|
}
|
|
121
117
|
|
|
118
|
+
/// The lower-case name and the fields of the composite type `composite`, when the schema
|
|
119
|
+
/// declares it. In PostgreSQL each table is also the composite type of its rows.
|
|
120
|
+
pub(super) fn composite_fields(&self, composite: &str) -> Option<(String, &[SchemaColumn])> {
|
|
121
|
+
let name = composite.to_lowercase();
|
|
122
|
+
let fields = self.schema.composite(&name).or_else(|| {
|
|
123
|
+
(self.dialect == SqlDialect::Postgres)
|
|
124
|
+
.then(|| self.schema.table(&name))
|
|
125
|
+
.flatten()
|
|
126
|
+
})?;
|
|
127
|
+
Some((name, fields))
|
|
128
|
+
}
|
|
129
|
+
|
|
122
130
|
/// Whether `data_type` is, or is an array of, a domain, enum or composite type the
|
|
123
131
|
/// schema defines.
|
|
124
132
|
fn defines_type(&self, data_type: &DataType) -> bool {
|
|
@@ -196,6 +204,7 @@ impl<'a> Analyzer<'a> {
|
|
|
196
204
|
}
|
|
197
205
|
}
|
|
198
206
|
|
|
207
|
+
#[recursive::recursive]
|
|
199
208
|
pub(super) fn expr(&self, expr: &Expr, scope: &Scope) -> Inferred<Typed> {
|
|
200
209
|
match expr {
|
|
201
210
|
Expr::Cast { data_type, .. } => Ok(self.cast_typed(data_type)),
|
|
@@ -235,10 +244,13 @@ impl<'a> Analyzer<'a> {
|
|
|
235
244
|
expr: inner,
|
|
236
245
|
} => match crate::values::constant(expr) {
|
|
237
246
|
Some(negative) => Ok(constant(negative)),
|
|
238
|
-
None
|
|
239
|
-
self.
|
|
247
|
+
None => {
|
|
248
|
+
let typed = self.expr(inner, scope)?;
|
|
249
|
+
Ok(match self.prefix_rule_of(op, &typed) {
|
|
250
|
+
Some(rule) => self.prefixed(rule, typed),
|
|
251
|
+
None => strip(typed, self.dialect),
|
|
252
|
+
})
|
|
240
253
|
}
|
|
241
|
-
None => Ok(strip(self.expr(inner, scope)?, self.dialect)),
|
|
242
254
|
},
|
|
243
255
|
Expr::AtTimeZone { timestamp, .. } if self.dialect == SqlDialect::Postgres => {
|
|
244
256
|
// `timestamp AT TIME ZONE zone` is a `timestamptz` and vice versa; a time
|
|
@@ -252,17 +264,14 @@ impl<'a> Analyzer<'a> {
|
|
|
252
264
|
})
|
|
253
265
|
}
|
|
254
266
|
Expr::Ceil { expr: inner, .. } | Expr::Floor { expr: inner, .. } => {
|
|
267
|
+
let typed = self.expr(inner, scope)?;
|
|
255
268
|
let returns = match self.dialect {
|
|
256
269
|
SqlDialect::MySql => Returns::Integral,
|
|
257
270
|
// SQLite returns an integer argument as it is.
|
|
258
|
-
SqlDialect::Sqlite
|
|
259
|
-
if self.expr(inner, scope)?.python.as_deref() == Some("int") =>
|
|
260
|
-
{
|
|
261
|
-
Returns::Arg(0)
|
|
262
|
-
}
|
|
271
|
+
SqlDialect::Sqlite if typed.python.as_deref() == Some("int") => Returns::Arg(0),
|
|
263
272
|
_ => Returns::Real,
|
|
264
273
|
};
|
|
265
|
-
self.
|
|
274
|
+
self.function_type_of(returns, &[inner], &[Some(typed), None], scope)
|
|
266
275
|
}
|
|
267
276
|
Expr::Extract { .. } if self.dialect == SqlDialect::Postgres => {
|
|
268
277
|
Ok(from_sql_type("DECIMAL", self.dialect))
|
|
@@ -593,7 +602,9 @@ impl<'a> Analyzer<'a> {
|
|
|
593
602
|
)
|
|
594
603
|
}
|
|
595
604
|
FunctionType::Code => self.sum(argument()?, arg, scope)?,
|
|
596
|
-
FunctionType::Returns(returns) =>
|
|
605
|
+
FunctionType::Returns(returns) => {
|
|
606
|
+
self.function_type_of(returns, &args, &typed, scope)?
|
|
607
|
+
}
|
|
597
608
|
});
|
|
598
609
|
}
|
|
599
610
|
match name.as_str() {
|
|
@@ -648,6 +659,11 @@ pub(super) fn is_binary_charset(charset: &ObjectName) -> bool {
|
|
|
648
659
|
charset.to_string().eq_ignore_ascii_case("binary")
|
|
649
660
|
}
|
|
650
661
|
|
|
662
|
+
/// Whether `field` is the `"*"` that respell writes for PostgreSQL's `(composite).*`.
|
|
663
|
+
pub(super) fn is_field_star(field: &Ident) -> bool {
|
|
664
|
+
field.value == "*" && field.quote_style == Some('"')
|
|
665
|
+
}
|
|
666
|
+
|
|
651
667
|
#[cfg(test)]
|
|
652
668
|
mod tests {
|
|
653
669
|
use super::super::test_support::reports;
|
|
@@ -125,9 +125,22 @@ impl<'a> Analyzer<'a> {
|
|
|
125
125
|
args: &[&Expr],
|
|
126
126
|
scope: &Scope,
|
|
127
127
|
) -> Inferred<Typed> {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
128
|
+
self.function_type_of(returns, args, &[None, None], scope)
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/// [`Self::function_type`] given the types of the first two arguments already inferred,
|
|
132
|
+
/// which are not inferred again.
|
|
133
|
+
pub(super) fn function_type_of(
|
|
134
|
+
&self,
|
|
135
|
+
returns: Returns,
|
|
136
|
+
args: &[&Expr],
|
|
137
|
+
known: &RuleArguments,
|
|
138
|
+
scope: &Scope,
|
|
139
|
+
) -> Inferred<Typed> {
|
|
140
|
+
let arg = |i: usize| match (known.get(i), args.get(i)) {
|
|
141
|
+
(Some(Some(typed)), _) => Ok(typed.clone()),
|
|
142
|
+
(_, Some(arg)) => self.expr(arg, scope),
|
|
143
|
+
(_, None) => Ok(Typed::UNKNOWN),
|
|
131
144
|
};
|
|
132
145
|
let sql = |name: &str| Ok(from_sql_type(name, self.dialect));
|
|
133
146
|
match returns {
|