@quereus/quereus 4.3.2 → 4.4.1
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.
- package/README.md +5 -0
- package/dist/src/common/types.d.ts +9 -0
- package/dist/src/common/types.d.ts.map +1 -1
- package/dist/src/common/types.js.map +1 -1
- package/dist/src/core/database-events.d.ts +49 -0
- package/dist/src/core/database-events.d.ts.map +1 -1
- package/dist/src/core/database-events.js +148 -0
- package/dist/src/core/database-events.js.map +1 -1
- package/dist/src/core/database-external-changes.d.ts +2 -2
- package/dist/src/core/database-external-changes.d.ts.map +1 -1
- package/dist/src/core/database-external-changes.js +12 -9
- package/dist/src/core/database-external-changes.js.map +1 -1
- package/dist/src/core/database-materialized-views-apply.d.ts +156 -14
- package/dist/src/core/database-materialized-views-apply.d.ts.map +1 -1
- package/dist/src/core/database-materialized-views-apply.js +370 -65
- package/dist/src/core/database-materialized-views-apply.js.map +1 -1
- package/dist/src/core/database-materialized-views-plan-builders.d.ts +66 -1
- package/dist/src/core/database-materialized-views-plan-builders.d.ts.map +1 -1
- package/dist/src/core/database-materialized-views-plan-builders.js +368 -8
- package/dist/src/core/database-materialized-views-plan-builders.js.map +1 -1
- package/dist/src/core/database-materialized-views-plans.d.ts +257 -30
- package/dist/src/core/database-materialized-views-plans.d.ts.map +1 -1
- package/dist/src/core/database-materialized-views.d.ts +99 -42
- package/dist/src/core/database-materialized-views.d.ts.map +1 -1
- package/dist/src/core/database-materialized-views.js +198 -121
- package/dist/src/core/database-materialized-views.js.map +1 -1
- package/dist/src/core/database.d.ts +5 -0
- package/dist/src/core/database.d.ts.map +1 -1
- package/dist/src/core/database.js +41 -18
- package/dist/src/core/database.js.map +1 -1
- package/dist/src/core/internal-statement-cache.d.ts +18 -0
- package/dist/src/core/internal-statement-cache.d.ts.map +1 -0
- package/dist/src/core/internal-statement-cache.js +211 -0
- package/dist/src/core/internal-statement-cache.js.map +1 -0
- package/dist/src/func/builtins/aggregate.d.ts +13 -12
- package/dist/src/func/builtins/aggregate.d.ts.map +1 -1
- package/dist/src/func/builtins/aggregate.js +146 -62
- package/dist/src/func/builtins/aggregate.js.map +1 -1
- package/dist/src/func/builtins/builtin-window-functions.d.ts.map +1 -1
- package/dist/src/func/builtins/builtin-window-functions.js +63 -48
- package/dist/src/func/builtins/builtin-window-functions.js.map +1 -1
- package/dist/src/func/registration.d.ts +19 -1
- package/dist/src/func/registration.d.ts.map +1 -1
- package/dist/src/func/registration.js +41 -0
- package/dist/src/func/registration.js.map +1 -1
- package/dist/src/index.d.ts +8 -8
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +12 -11
- package/dist/src/index.js.map +1 -1
- package/dist/src/parser/parser.d.ts +6 -0
- package/dist/src/parser/parser.d.ts.map +1 -1
- package/dist/src/parser/parser.js +45 -34
- package/dist/src/parser/parser.js.map +1 -1
- package/dist/src/planner/analysis/comparison-collation.d.ts +2 -0
- package/dist/src/planner/analysis/comparison-collation.d.ts.map +1 -1
- package/dist/src/planner/analysis/comparison-collation.js +1 -1
- package/dist/src/planner/analysis/comparison-collation.js.map +1 -1
- package/dist/src/planner/analysis/equi-correlation.d.ts +26 -0
- package/dist/src/planner/analysis/equi-correlation.d.ts.map +1 -0
- package/dist/src/planner/analysis/equi-correlation.js +62 -0
- package/dist/src/planner/analysis/equi-correlation.js.map +1 -0
- package/dist/src/planner/analysis/expression-fingerprint.d.ts.map +1 -1
- package/dist/src/planner/analysis/expression-fingerprint.js +29 -0
- package/dist/src/planner/analysis/expression-fingerprint.js.map +1 -1
- package/dist/src/planner/analysis/query-rewrite-matcher.d.ts +60 -18
- package/dist/src/planner/analysis/query-rewrite-matcher.d.ts.map +1 -1
- package/dist/src/planner/analysis/query-rewrite-matcher.js +95 -42
- package/dist/src/planner/analysis/query-rewrite-matcher.js.map +1 -1
- package/dist/src/planner/analysis/sat-checker.d.ts.map +1 -1
- package/dist/src/planner/analysis/sat-checker.js +43 -4
- package/dist/src/planner/analysis/sat-checker.js.map +1 -1
- package/dist/src/planner/analysis/scalar-subqueries.d.ts +28 -0
- package/dist/src/planner/analysis/scalar-subqueries.d.ts.map +1 -0
- package/dist/src/planner/analysis/scalar-subqueries.js +60 -0
- package/dist/src/planner/analysis/scalar-subqueries.js.map +1 -0
- package/dist/src/planner/building/delete.d.ts.map +1 -1
- package/dist/src/planner/building/delete.js +10 -3
- package/dist/src/planner/building/delete.js.map +1 -1
- package/dist/src/planner/building/expression.d.ts.map +1 -1
- package/dist/src/planner/building/expression.js +87 -6
- package/dist/src/planner/building/expression.js.map +1 -1
- package/dist/src/planner/building/foreign-key-builder.d.ts +44 -1
- package/dist/src/planner/building/foreign-key-builder.d.ts.map +1 -1
- package/dist/src/planner/building/foreign-key-builder.js +54 -0
- package/dist/src/planner/building/foreign-key-builder.js.map +1 -1
- package/dist/src/planner/building/insert.d.ts.map +1 -1
- package/dist/src/planner/building/insert.js +9 -12
- package/dist/src/planner/building/insert.js.map +1 -1
- package/dist/src/planner/building/select.d.ts.map +1 -1
- package/dist/src/planner/building/select.js +15 -1
- package/dist/src/planner/building/select.js.map +1 -1
- package/dist/src/planner/building/update.d.ts.map +1 -1
- package/dist/src/planner/building/update.js +13 -4
- package/dist/src/planner/building/update.js.map +1 -1
- package/dist/src/planner/building/with.d.ts.map +1 -1
- package/dist/src/planner/building/with.js +5 -8
- package/dist/src/planner/building/with.js.map +1 -1
- package/dist/src/planner/cache/materialization-advisory.d.ts +33 -0
- package/dist/src/planner/cache/materialization-advisory.d.ts.map +1 -1
- package/dist/src/planner/cache/materialization-advisory.js +164 -28
- package/dist/src/planner/cache/materialization-advisory.js.map +1 -1
- package/dist/src/planner/cache/reference-graph.d.ts +0 -4
- package/dist/src/planner/cache/reference-graph.d.ts.map +1 -1
- package/dist/src/planner/cache/reference-graph.js +5 -13
- package/dist/src/planner/cache/reference-graph.js.map +1 -1
- package/dist/src/planner/cost/index.d.ts +28 -7
- package/dist/src/planner/cost/index.d.ts.map +1 -1
- package/dist/src/planner/cost/index.js +26 -0
- package/dist/src/planner/cost/index.js.map +1 -1
- package/dist/src/planner/framework/pass.js +3 -3
- package/dist/src/planner/nodes/cache-node.d.ts +18 -2
- package/dist/src/planner/nodes/cache-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/cache-node.js +42 -3
- package/dist/src/planner/nodes/cache-node.js.map +1 -1
- package/dist/src/planner/nodes/cte-node.d.ts +15 -1
- package/dist/src/planner/nodes/cte-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/cte-node.js +12 -2
- package/dist/src/planner/nodes/cte-node.js.map +1 -1
- package/dist/src/planner/nodes/dml-executor-node.d.ts +0 -9
- package/dist/src/planner/nodes/dml-executor-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/dml-executor-node.js.map +1 -1
- package/dist/src/planner/nodes/recursive-cte-node.d.ts +30 -1
- package/dist/src/planner/nodes/recursive-cte-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/recursive-cte-node.js +30 -3
- package/dist/src/planner/nodes/recursive-cte-node.js.map +1 -1
- package/dist/src/planner/nodes/scalar.d.ts.map +1 -1
- package/dist/src/planner/nodes/scalar.js +26 -3
- package/dist/src/planner/nodes/scalar.js.map +1 -1
- package/dist/src/planner/optimizer.d.ts.map +1 -1
- package/dist/src/planner/optimizer.js +129 -8
- package/dist/src/planner/optimizer.js.map +1 -1
- package/dist/src/planner/rules/access/rule-select-access-path.d.ts.map +1 -1
- package/dist/src/planner/rules/access/rule-select-access-path.js +43 -18
- package/dist/src/planner/rules/access/rule-select-access-path.js.map +1 -1
- package/dist/src/planner/rules/cache/rule-cte-optimization.d.ts.map +1 -1
- package/dist/src/planner/rules/cache/rule-cte-optimization.js +8 -1
- package/dist/src/planner/rules/cache/rule-cte-optimization.js.map +1 -1
- package/dist/src/planner/rules/cache/rule-materialized-view-rewrite.d.ts.map +1 -1
- package/dist/src/planner/rules/cache/rule-materialized-view-rewrite.js +72 -54
- package/dist/src/planner/rules/cache/rule-materialized-view-rewrite.js.map +1 -1
- package/dist/src/planner/rules/cache/rule-mutating-subquery-cache.d.ts.map +1 -1
- package/dist/src/planner/rules/cache/rule-mutating-subquery-cache.js +6 -0
- package/dist/src/planner/rules/cache/rule-mutating-subquery-cache.js.map +1 -1
- package/dist/src/planner/rules/cache/rule-nested-loop-right-cache.d.ts +25 -0
- package/dist/src/planner/rules/cache/rule-nested-loop-right-cache.d.ts.map +1 -0
- package/dist/src/planner/rules/cache/rule-nested-loop-right-cache.js +176 -0
- package/dist/src/planner/rules/cache/rule-nested-loop-right-cache.js.map +1 -0
- package/dist/src/planner/rules/cache/rule-scalar-subquery-cache.d.ts +31 -0
- package/dist/src/planner/rules/cache/rule-scalar-subquery-cache.d.ts.map +1 -0
- package/dist/src/planner/rules/cache/rule-scalar-subquery-cache.js +68 -0
- package/dist/src/planner/rules/cache/rule-scalar-subquery-cache.js.map +1 -0
- package/dist/src/planner/rules/join/rule-fanout-lookup-join.d.ts.map +1 -1
- package/dist/src/planner/rules/join/rule-fanout-lookup-join.js +1 -54
- package/dist/src/planner/rules/join/rule-fanout-lookup-join.js.map +1 -1
- package/dist/src/planner/rules/predicate/rule-predicate-inference-equivalence.js +8 -1
- package/dist/src/planner/rules/predicate/rule-predicate-inference-equivalence.js.map +1 -1
- package/dist/src/planner/rules/subquery/rule-scalar-agg-decorrelation.d.ts +191 -0
- package/dist/src/planner/rules/subquery/rule-scalar-agg-decorrelation.d.ts.map +1 -0
- package/dist/src/planner/rules/subquery/rule-scalar-agg-decorrelation.js +627 -0
- package/dist/src/planner/rules/subquery/rule-scalar-agg-decorrelation.js.map +1 -0
- package/dist/src/planner/rules/subquery/rule-subquery-decorrelation.d.ts +10 -1
- package/dist/src/planner/rules/subquery/rule-subquery-decorrelation.d.ts.map +1 -1
- package/dist/src/planner/rules/subquery/rule-subquery-decorrelation.js +242 -51
- package/dist/src/planner/rules/subquery/rule-subquery-decorrelation.js.map +1 -1
- package/dist/src/runtime/cache/shared-cache.d.ts +7 -0
- package/dist/src/runtime/cache/shared-cache.d.ts.map +1 -1
- package/dist/src/runtime/cache/shared-cache.js +34 -1
- package/dist/src/runtime/cache/shared-cache.js.map +1 -1
- package/dist/src/runtime/deferred-constraint-queue.d.ts.map +1 -1
- package/dist/src/runtime/deferred-constraint-queue.js +10 -0
- package/dist/src/runtime/deferred-constraint-queue.js.map +1 -1
- package/dist/src/runtime/emit/aggregate-setup.d.ts +49 -0
- package/dist/src/runtime/emit/aggregate-setup.d.ts.map +1 -0
- package/dist/src/runtime/emit/aggregate-setup.js +99 -0
- package/dist/src/runtime/emit/aggregate-setup.js.map +1 -0
- package/dist/src/runtime/emit/aggregate.d.ts +2 -3
- package/dist/src/runtime/emit/aggregate.d.ts.map +1 -1
- package/dist/src/runtime/emit/aggregate.js +10 -84
- package/dist/src/runtime/emit/aggregate.js.map +1 -1
- package/dist/src/runtime/emit/alter-table.d.ts.map +1 -1
- package/dist/src/runtime/emit/alter-table.js +348 -165
- package/dist/src/runtime/emit/alter-table.js.map +1 -1
- package/dist/src/runtime/emit/asof-scan.d.ts.map +1 -1
- package/dist/src/runtime/emit/asof-scan.js +6 -0
- package/dist/src/runtime/emit/asof-scan.js.map +1 -1
- package/dist/src/runtime/emit/between.d.ts.map +1 -1
- package/dist/src/runtime/emit/between.js +32 -3
- package/dist/src/runtime/emit/between.js.map +1 -1
- package/dist/src/runtime/emit/binary.d.ts.map +1 -1
- package/dist/src/runtime/emit/binary.js +22 -2
- package/dist/src/runtime/emit/binary.js.map +1 -1
- package/dist/src/runtime/emit/bloom-join.d.ts.map +1 -1
- package/dist/src/runtime/emit/bloom-join.js +24 -3
- package/dist/src/runtime/emit/bloom-join.js.map +1 -1
- package/dist/src/runtime/emit/cache.d.ts +7 -3
- package/dist/src/runtime/emit/cache.d.ts.map +1 -1
- package/dist/src/runtime/emit/cache.js +23 -6
- package/dist/src/runtime/emit/cache.js.map +1 -1
- package/dist/src/runtime/emit/cast.d.ts.map +1 -1
- package/dist/src/runtime/emit/cast.js +10 -23
- package/dist/src/runtime/emit/cast.js.map +1 -1
- package/dist/src/runtime/emit/constraint-check.d.ts.map +1 -1
- package/dist/src/runtime/emit/constraint-check.js +41 -44
- package/dist/src/runtime/emit/constraint-check.js.map +1 -1
- package/dist/src/runtime/emit/create-view.d.ts.map +1 -1
- package/dist/src/runtime/emit/create-view.js +6 -0
- package/dist/src/runtime/emit/create-view.js.map +1 -1
- package/dist/src/runtime/emit/cte.d.ts.map +1 -1
- package/dist/src/runtime/emit/cte.js +43 -20
- package/dist/src/runtime/emit/cte.js.map +1 -1
- package/dist/src/runtime/emit/distinct.d.ts.map +1 -1
- package/dist/src/runtime/emit/distinct.js +6 -3
- package/dist/src/runtime/emit/distinct.js.map +1 -1
- package/dist/src/runtime/emit/dml-executor.d.ts.map +1 -1
- package/dist/src/runtime/emit/dml-executor.js +241 -115
- package/dist/src/runtime/emit/dml-executor.js.map +1 -1
- package/dist/src/runtime/emit/hash-aggregate.d.ts.map +1 -1
- package/dist/src/runtime/emit/hash-aggregate.js +16 -65
- package/dist/src/runtime/emit/hash-aggregate.js.map +1 -1
- package/dist/src/runtime/emit/insert.d.ts.map +1 -1
- package/dist/src/runtime/emit/insert.js +18 -7
- package/dist/src/runtime/emit/insert.js.map +1 -1
- package/dist/src/runtime/emit/join.js +5 -0
- package/dist/src/runtime/emit/join.js.map +1 -1
- package/dist/src/runtime/emit/materialized-view-helpers.d.ts +14 -1
- package/dist/src/runtime/emit/materialized-view-helpers.d.ts.map +1 -1
- package/dist/src/runtime/emit/materialized-view-helpers.js +38 -7
- package/dist/src/runtime/emit/materialized-view-helpers.js.map +1 -1
- package/dist/src/runtime/emit/materialized-view.d.ts.map +1 -1
- package/dist/src/runtime/emit/materialized-view.js +47 -6
- package/dist/src/runtime/emit/materialized-view.js.map +1 -1
- package/dist/src/runtime/emit/merge-join.d.ts.map +1 -1
- package/dist/src/runtime/emit/merge-join.js +18 -8
- package/dist/src/runtime/emit/merge-join.js.map +1 -1
- package/dist/src/runtime/emit/recursive-cte.d.ts.map +1 -1
- package/dist/src/runtime/emit/recursive-cte.js +59 -1
- package/dist/src/runtime/emit/recursive-cte.js.map +1 -1
- package/dist/src/runtime/emit/set-object-tags.d.ts +8 -0
- package/dist/src/runtime/emit/set-object-tags.d.ts.map +1 -1
- package/dist/src/runtime/emit/set-object-tags.js +8 -0
- package/dist/src/runtime/emit/set-object-tags.js.map +1 -1
- package/dist/src/runtime/emit/set-operation.d.ts.map +1 -1
- package/dist/src/runtime/emit/set-operation.js +7 -4
- package/dist/src/runtime/emit/set-operation.js.map +1 -1
- package/dist/src/runtime/emit/sort.d.ts.map +1 -1
- package/dist/src/runtime/emit/sort.js +5 -2
- package/dist/src/runtime/emit/sort.js.map +1 -1
- package/dist/src/runtime/emit/subquery.d.ts.map +1 -1
- package/dist/src/runtime/emit/subquery.js +113 -13
- package/dist/src/runtime/emit/subquery.js.map +1 -1
- package/dist/src/runtime/emit/temporal-arithmetic.d.ts +7 -0
- package/dist/src/runtime/emit/temporal-arithmetic.d.ts.map +1 -1
- package/dist/src/runtime/emit/temporal-arithmetic.js +15 -7
- package/dist/src/runtime/emit/temporal-arithmetic.js.map +1 -1
- package/dist/src/runtime/emit/update.d.ts.map +1 -1
- package/dist/src/runtime/emit/update.js +44 -3
- package/dist/src/runtime/emit/update.js.map +1 -1
- package/dist/src/runtime/emit/window.d.ts.map +1 -1
- package/dist/src/runtime/emit/window.js +72 -55
- package/dist/src/runtime/emit/window.js.map +1 -1
- package/dist/src/runtime/foreign-key-actions.d.ts +36 -1
- package/dist/src/runtime/foreign-key-actions.d.ts.map +1 -1
- package/dist/src/runtime/foreign-key-actions.js +238 -116
- package/dist/src/runtime/foreign-key-actions.js.map +1 -1
- package/dist/src/runtime/parallel-driver.d.ts +20 -1
- package/dist/src/runtime/parallel-driver.d.ts.map +1 -1
- package/dist/src/runtime/parallel-driver.js +23 -1
- package/dist/src/runtime/parallel-driver.js.map +1 -1
- package/dist/src/runtime/types.d.ts +54 -0
- package/dist/src/runtime/types.d.ts.map +1 -1
- package/dist/src/runtime/types.js.map +1 -1
- package/dist/src/schema/catalog-persistability.d.ts +58 -0
- package/dist/src/schema/catalog-persistability.d.ts.map +1 -0
- package/dist/src/schema/catalog-persistability.js +87 -0
- package/dist/src/schema/catalog-persistability.js.map +1 -0
- package/dist/src/schema/catalog.d.ts +17 -1
- package/dist/src/schema/catalog.d.ts.map +1 -1
- package/dist/src/schema/catalog.js +25 -3
- package/dist/src/schema/catalog.js.map +1 -1
- package/dist/src/schema/constraint-builder.d.ts +20 -22
- package/dist/src/schema/constraint-builder.d.ts.map +1 -1
- package/dist/src/schema/constraint-builder.js +43 -36
- package/dist/src/schema/constraint-builder.js.map +1 -1
- package/dist/src/schema/ddl-generator.d.ts +23 -0
- package/dist/src/schema/ddl-generator.d.ts.map +1 -1
- package/dist/src/schema/ddl-generator.js +27 -0
- package/dist/src/schema/ddl-generator.js.map +1 -1
- package/dist/src/schema/function.d.ts +109 -1
- package/dist/src/schema/function.d.ts.map +1 -1
- package/dist/src/schema/function.js.map +1 -1
- package/dist/src/schema/manager.d.ts +28 -0
- package/dist/src/schema/manager.d.ts.map +1 -1
- package/dist/src/schema/manager.js +82 -14
- package/dist/src/schema/manager.js.map +1 -1
- package/dist/src/schema/schema-differ.d.ts.map +1 -1
- package/dist/src/schema/schema-differ.js +51 -12
- package/dist/src/schema/schema-differ.js.map +1 -1
- package/dist/src/schema/unique-enforcement.d.ts +31 -0
- package/dist/src/schema/unique-enforcement.d.ts.map +1 -1
- package/dist/src/schema/unique-enforcement.js +37 -1
- package/dist/src/schema/unique-enforcement.js.map +1 -1
- package/dist/src/schema/window-function.d.ts +30 -10
- package/dist/src/schema/window-function.d.ts.map +1 -1
- package/dist/src/schema/window-function.js +20 -16
- package/dist/src/schema/window-function.js.map +1 -1
- package/dist/src/types/cast-semantics.d.ts +43 -0
- package/dist/src/types/cast-semantics.d.ts.map +1 -0
- package/dist/src/types/cast-semantics.js +59 -0
- package/dist/src/types/cast-semantics.js.map +1 -0
- package/dist/src/types/index.d.ts +1 -1
- package/dist/src/types/index.d.ts.map +1 -1
- package/dist/src/types/index.js +1 -1
- package/dist/src/types/index.js.map +1 -1
- package/dist/src/types/json-type.d.ts.map +1 -1
- package/dist/src/types/json-type.js +31 -10
- package/dist/src/types/json-type.js.map +1 -1
- package/dist/src/types/logical-type.d.ts +22 -0
- package/dist/src/types/logical-type.d.ts.map +1 -1
- package/dist/src/types/logical-type.js.map +1 -1
- package/dist/src/types/temporal-types.d.ts.map +1 -1
- package/dist/src/types/temporal-types.js +33 -11
- package/dist/src/types/temporal-types.js.map +1 -1
- package/dist/src/types/validation.d.ts +39 -1
- package/dist/src/types/validation.d.ts.map +1 -1
- package/dist/src/types/validation.js +60 -0
- package/dist/src/types/validation.js.map +1 -1
- package/dist/src/util/ast-spine-clone.d.ts +23 -0
- package/dist/src/util/ast-spine-clone.d.ts.map +1 -0
- package/dist/src/util/ast-spine-clone.js +41 -0
- package/dist/src/util/ast-spine-clone.js.map +1 -0
- package/dist/src/util/coercion.d.ts +13 -0
- package/dist/src/util/coercion.d.ts.map +1 -1
- package/dist/src/util/coercion.js +10 -1
- package/dist/src/util/coercion.js.map +1 -1
- package/dist/src/util/comparison.d.ts +89 -0
- package/dist/src/util/comparison.d.ts.map +1 -1
- package/dist/src/util/comparison.js +156 -27
- package/dist/src/util/comparison.js.map +1 -1
- package/dist/src/vtab/manifest.d.ts +7 -0
- package/dist/src/vtab/manifest.d.ts.map +1 -1
- package/dist/src/vtab/memory/connection.d.ts +14 -1
- package/dist/src/vtab/memory/connection.d.ts.map +1 -1
- package/dist/src/vtab/memory/connection.js +20 -2
- package/dist/src/vtab/memory/connection.js.map +1 -1
- package/dist/src/vtab/memory/layer/base.d.ts +6 -1
- package/dist/src/vtab/memory/layer/base.d.ts.map +1 -1
- package/dist/src/vtab/memory/layer/base.js +14 -5
- package/dist/src/vtab/memory/layer/base.js.map +1 -1
- package/dist/src/vtab/memory/layer/connection.d.ts +17 -0
- package/dist/src/vtab/memory/layer/connection.d.ts.map +1 -1
- package/dist/src/vtab/memory/layer/connection.js +26 -0
- package/dist/src/vtab/memory/layer/connection.js.map +1 -1
- package/dist/src/vtab/memory/layer/manager.d.ts +96 -13
- package/dist/src/vtab/memory/layer/manager.d.ts.map +1 -1
- package/dist/src/vtab/memory/layer/manager.js +595 -119
- package/dist/src/vtab/memory/layer/manager.js.map +1 -1
- package/dist/src/vtab/memory/layer/plan-filter.d.ts +41 -20
- package/dist/src/vtab/memory/layer/plan-filter.d.ts.map +1 -1
- package/dist/src/vtab/memory/layer/plan-filter.js +57 -27
- package/dist/src/vtab/memory/layer/plan-filter.js.map +1 -1
- package/dist/src/vtab/memory/layer/row-convert.d.ts +21 -0
- package/dist/src/vtab/memory/layer/row-convert.d.ts.map +1 -0
- package/dist/src/vtab/memory/layer/row-convert.js +30 -0
- package/dist/src/vtab/memory/layer/row-convert.js.map +1 -0
- package/dist/src/vtab/memory/layer/scan-layer.d.ts +6 -3
- package/dist/src/vtab/memory/layer/scan-layer.d.ts.map +1 -1
- package/dist/src/vtab/memory/layer/scan-layer.js +69 -36
- package/dist/src/vtab/memory/layer/scan-layer.js.map +1 -1
- package/dist/src/vtab/memory/layer/transaction.d.ts +127 -13
- package/dist/src/vtab/memory/layer/transaction.d.ts.map +1 -1
- package/dist/src/vtab/memory/layer/transaction.js +214 -65
- package/dist/src/vtab/memory/layer/transaction.js.map +1 -1
- package/dist/src/vtab/memory/module.d.ts.map +1 -1
- package/dist/src/vtab/memory/module.js +9 -2
- package/dist/src/vtab/memory/module.js.map +1 -1
- package/dist/src/vtab/memory/table.d.ts.map +1 -1
- package/dist/src/vtab/memory/table.js +3 -2
- package/dist/src/vtab/memory/table.js.map +1 -1
- package/dist/src/vtab/memory/types.d.ts +27 -1
- package/dist/src/vtab/memory/types.d.ts.map +1 -1
- package/dist/src/vtab/memory/types.js +16 -1
- package/dist/src/vtab/memory/types.js.map +1 -1
- package/dist/src/vtab/memory/utils/primary-key.d.ts +9 -0
- package/dist/src/vtab/memory/utils/primary-key.d.ts.map +1 -1
- package/dist/src/vtab/memory/utils/primary-key.js +11 -0
- package/dist/src/vtab/memory/utils/primary-key.js.map +1 -1
- package/dist/src/vtab/module.d.ts +63 -0
- package/dist/src/vtab/module.d.ts.map +1 -1
- package/dist/src/vtab/table.d.ts +24 -6
- package/dist/src/vtab/table.d.ts.map +1 -1
- package/dist/src/vtab/table.js.map +1 -1
- package/package.json +3 -3
- package/dist/src/planner/rules/cache/rule-in-subquery-cache.d.ts +0 -19
- package/dist/src/planner/rules/cache/rule-in-subquery-cache.d.ts.map +0 -1
- package/dist/src/planner/rules/cache/rule-in-subquery-cache.js +0 -53
- package/dist/src/planner/rules/cache/rule-in-subquery-cache.js.map +0 -1
|
@@ -5,15 +5,18 @@ import { QuereusError } from '../../common/errors.js';
|
|
|
5
5
|
import { StatusCode } from '../../common/types.js';
|
|
6
6
|
import { createLogger } from '../../common/logger.js';
|
|
7
7
|
import { buildColumnIndexMap, withGeneratedColumnGraph, requireVtabModule, resolveNamedConstraintClass, validateCollationForType } from '../../schema/table.js';
|
|
8
|
-
import {
|
|
8
|
+
import { validateForeignKeyCollations, buildForeignKeyConstraintSchema, extractColumnLevelCheckConstraints, extractColumnLevelForeignKeys, extractColumnLevelUniqueConstraints } from '../../schema/constraint-builder.js';
|
|
9
9
|
import { MemoryTableModule } from '../../vtab/memory/module.js';
|
|
10
10
|
import { quoteIdentifier, expressionToString, astToString } from '../../emit/ast-stringify.js';
|
|
11
11
|
import { renameTableInAst, renameColumnInAst, renameColumnInCheckExpression } from '../../schema/rename-rewriter.js';
|
|
12
|
+
import { assertCatalogObjectPersistable, assertRenameDependentsPersistable } from '../../schema/catalog-persistability.js';
|
|
12
13
|
import { tryFoldLiteral } from '../../parser/utils.js';
|
|
13
14
|
import { isTruthy } from '../../util/comparison.js';
|
|
14
15
|
import { assertDdlTransactionPolicy } from './ddl-transaction-policy.js';
|
|
16
|
+
import { validateAndParse } from '../../types/validation.js';
|
|
15
17
|
import { snapshotStaleMaterializedViews, propagateTableRenameToMaterializedViews, propagateColumnRenameToMaterializedViews, restoreUnaffectedMaterializedViews, attachMaintainedDerivation, detachMaintainedDerivation, } from './materialized-view-helpers.js';
|
|
16
18
|
import { isMaintainedTable } from '../../schema/derivation.js';
|
|
19
|
+
import { inferType } from '../../types/registry.js';
|
|
17
20
|
const log = createLogger('runtime:emit:alter-table');
|
|
18
21
|
/** A scheduled sub-program resolved to a callback the emitter invokes per row. */
|
|
19
22
|
function qualifyTableName(schemaName, tableName) {
|
|
@@ -156,6 +159,20 @@ async function runRenameTable(rctx, tableSchema, schema, newName) {
|
|
|
156
159
|
if (schema.getTable(newName)) {
|
|
157
160
|
throw new QuereusError(`Table '${newName}' already exists`, StatusCode.ERROR);
|
|
158
161
|
}
|
|
162
|
+
// Pre-flight, BEFORE the first side effect (`module.renameTable`): every catalog
|
|
163
|
+
// entry this rename would rewrite must still be persistable. Both the rename
|
|
164
|
+
// propagation and the store's catalog write are unfailable (notifier try/catch,
|
|
165
|
+
// then an async persist queue), so without this the statement reports success and
|
|
166
|
+
// the dependent silently diverges from — or vanishes from — the durable catalog.
|
|
167
|
+
if (isMaintainedTable(tableSchema)) {
|
|
168
|
+
// The renamed table is itself a materialized view: its own catalog entry moves
|
|
169
|
+
// (`materialized_view_removed` old → `materialized_view_added` new), so vet the
|
|
170
|
+
// prospective record's new KEY and DDL text. The self-reference rewrite
|
|
171
|
+
// `rewriteTableForTableRename` performs is not applied to the probe — it only
|
|
172
|
+
// substitutes `newName`, which is already under test as the record's own name.
|
|
173
|
+
assertCatalogObjectPersistable(rctx.db, 'materializedView', { ...tableSchema, name: newName });
|
|
174
|
+
}
|
|
175
|
+
assertRenameDependentsPersistable(rctx.db, schema, ast => renameTableInAst(ast, oldName, newName, tableSchema.schemaName));
|
|
159
176
|
// Clone schema with new name
|
|
160
177
|
const updatedTableSchema = {
|
|
161
178
|
...tableSchema,
|
|
@@ -169,6 +186,18 @@ async function runRenameTable(rctx, tableSchema, schema, newName) {
|
|
|
169
186
|
if (module.renameTable) {
|
|
170
187
|
await module.renameTable(rctx.db, tableSchema.schemaName, oldName, newName);
|
|
171
188
|
}
|
|
189
|
+
// Events this transaction already recorded still carry the OLD name; relabel them so
|
|
190
|
+
// the commit delivers every event under the name the table has at delivery. AFTER the
|
|
191
|
+
// module call (a module failure must leave the batch as untouched as the catalog, and
|
|
192
|
+
// the store's `ddlCommitPendingOps` flushes its queued events into our batch DURING
|
|
193
|
+
// that call — those must be in the batch before we walk it), BEFORE the catalog swap,
|
|
194
|
+
// matching where the other ALTER arms call `remapBatchedDataEvents`.
|
|
195
|
+
//
|
|
196
|
+
// NOTE: batched SCHEMA events are deliberately out of scope here. A schema event
|
|
197
|
+
// records a DDL operation, not current state — relabelling `objectName` without
|
|
198
|
+
// rewriting its `ddl` text would produce an incoherent instruction. How a rename
|
|
199
|
+
// crosses the wire to a peer is `fix/sync-schema-migrations-replicate-empty-ddl`.
|
|
200
|
+
rctx.db._getEventEmitter().renameBatchedEvents(tableSchema.schemaName, oldName, newName);
|
|
172
201
|
// The renamed table's own definition can name itself: a self-referencing FK's
|
|
173
202
|
// `referencedTable`, a table-qualified CHECK expression, a table-qualified
|
|
174
203
|
// partial-index predicate. Rewrite those BEFORE the catalog swap and the notify
|
|
@@ -238,6 +267,16 @@ async function runRenameColumn(rctx, tableSchema, schema, oldName, newName) {
|
|
|
238
267
|
if (oldName.toLowerCase() !== newNameLower && tableSchema.columnIndexMap.has(newNameLower)) {
|
|
239
268
|
throw new QuereusError(`Column '${newName}' already exists in table '${tableSchema.name}'`, StatusCode.ERROR);
|
|
240
269
|
}
|
|
270
|
+
// Pre-flight, BEFORE the first side effect (`module.alterTable`): the rewritten
|
|
271
|
+
// body of every dependent view / materialized view must still be persistable —
|
|
272
|
+
// same unfailable-propagation reasoning as the table-rename arm above. Shares one
|
|
273
|
+
// resolver with `propagateColumnRename` so the two passes cannot drift apart in
|
|
274
|
+
// code; what makes them agree at RUNTIME (the resolver reads the LIVE catalog, and
|
|
275
|
+
// this probe runs pre-mutation while the propagation runs post-) is that
|
|
276
|
+
// `isTableInUnaliasedScope` skips the renamed table itself and probes only OTHER
|
|
277
|
+
// sources, whose column sets this rename does not touch.
|
|
278
|
+
const resolveColumnInSource = buildColumnSourceResolver(rctx.db);
|
|
279
|
+
assertRenameDependentsPersistable(rctx.db, schema, ast => renameColumnInAst(ast, tableSchema.name, oldName, newName, tableSchema.schemaName, resolveColumnInSource));
|
|
241
280
|
const existingCol = tableSchema.columns[colIndex];
|
|
242
281
|
// Build a ColumnDef AST for the renamed column (preserving type info)
|
|
243
282
|
const newColumnDef = {
|
|
@@ -265,6 +304,12 @@ async function runRenameColumn(rctx, tableSchema, schema, oldName, newName) {
|
|
|
265
304
|
columnIndexMap: buildColumnIndexMap(updatedCols),
|
|
266
305
|
};
|
|
267
306
|
}
|
|
307
|
+
// A rename moves no value and changes no arity, so the batched events' row images are
|
|
308
|
+
// already right — but their `changedColumns` still names the OLD column. Re-derive it
|
|
309
|
+
// against the new names with an identity row map, so no delivered event names a column
|
|
310
|
+
// the table no longer has. (Modules that emit at commit from their own queue read the
|
|
311
|
+
// current schema then, so they need nothing here.)
|
|
312
|
+
await rctx.db._getEventEmitter().remapBatchedDataEvents(tableSchema.schemaName, tableSchema.name, (row) => row, updatedTableSchema.columns.map(c => c.name));
|
|
268
313
|
// Update the schema catalog
|
|
269
314
|
schema.addTable(updatedTableSchema);
|
|
270
315
|
// Snapshot pre-statement MV staleness BEFORE the notify below: the notify's
|
|
@@ -281,7 +326,7 @@ async function runRenameColumn(rctx, tableSchema, schema, oldName, newName) {
|
|
|
281
326
|
});
|
|
282
327
|
// Propagate the rename into dependent objects (CHECK / FK / partial-index
|
|
283
328
|
// predicates in this and other tables, view and materialized-view bodies).
|
|
284
|
-
await propagateColumnRename(rctx, tableSchema.schemaName, tableSchema.name, oldName, newName, preStaleMvs);
|
|
329
|
+
await propagateColumnRename(rctx, tableSchema.schemaName, tableSchema.name, oldName, newName, preStaleMvs, resolveColumnInSource);
|
|
285
330
|
log('Renamed column %s.%s.%s to %s', tableSchema.schemaName, tableSchema.name, oldName, newName);
|
|
286
331
|
return null;
|
|
287
332
|
}
|
|
@@ -299,6 +344,10 @@ async function runAddColumn(rctx, tableSchema, schema, columnDef, backfill, back
|
|
|
299
344
|
// and, when it does not fold to a literal, compiled into `backfill` — the default
|
|
300
345
|
// evaluated against the existing row, so `new.<column>` reads that row's sibling.
|
|
301
346
|
const defaultConstraint = columnDef.constraints?.find(c => c.type === 'default');
|
|
347
|
+
// Folded literal default; undefined when there is no default or it does not fold
|
|
348
|
+
// (the latter carries `backfill` instead). Used by the NOT NULL gate below and by
|
|
349
|
+
// the batched-event remap's backfill value.
|
|
350
|
+
const foldedDefault = defaultConstraint?.expr ? tryFoldLiteral(defaultConstraint.expr) : undefined;
|
|
302
351
|
// Call module.alterTable for data + schema update
|
|
303
352
|
const module = requireVtabModule(tableSchema);
|
|
304
353
|
if (!module.alterTable) {
|
|
@@ -318,19 +367,28 @@ async function runAddColumn(rctx, tableSchema, schema, columnDef, backfill, back
|
|
|
318
367
|
const delegatesBackfill = module.getCapabilities?.().delegatesNotNullBackfill === true;
|
|
319
368
|
const hasNotNull = columnDef.constraints?.some(c => c.type === 'notNull') ?? false;
|
|
320
369
|
if (hasNotNull && !delegatesBackfill && !backfill) {
|
|
321
|
-
const
|
|
322
|
-
const defaultIsNullish = !defaultConstraint?.expr || folded === null;
|
|
370
|
+
const defaultIsNullish = !defaultConstraint?.expr || foldedDefault === null;
|
|
323
371
|
if (defaultIsNullish) {
|
|
324
372
|
await validateNotNullBackfill(rctx, tableSchema, columnDef.name);
|
|
325
373
|
}
|
|
326
374
|
}
|
|
327
|
-
//
|
|
328
|
-
//
|
|
329
|
-
//
|
|
330
|
-
//
|
|
331
|
-
//
|
|
332
|
-
|
|
333
|
-
|
|
375
|
+
// Synthesize the table-level equivalent of every constraint declared inline on the new
|
|
376
|
+
// column. All three kinds go to the module via `addConstraint` below — the same path
|
|
377
|
+
// `ALTER TABLE ADD CONSTRAINT` uses — so the module owns them exactly as it owns a
|
|
378
|
+
// constraint declared in CREATE TABLE, and they survive every later structural ALTER
|
|
379
|
+
// (which installs the module's returned schema in the catalog verbatim).
|
|
380
|
+
//
|
|
381
|
+
// Extracted BEFORE the column is materialized so a malformed declaration (e.g. a
|
|
382
|
+
// multi-parent-column FK on a single ADD COLUMN) throws while the table is still
|
|
383
|
+
// untouched. Install order within the loop is UNIQUE → CHECK → FK, so a column
|
|
384
|
+
// declaring several kinds reports the cheapest-to-explain violation first; the
|
|
385
|
+
// literal-default CHECK scan runs ahead of the whole loop (see below).
|
|
386
|
+
const inlineChecks = extractColumnLevelCheckConstraints(columnDef);
|
|
387
|
+
const inlineConstraints = [
|
|
388
|
+
...extractColumnLevelUniqueConstraints(columnDef),
|
|
389
|
+
...inlineChecks,
|
|
390
|
+
...extractColumnLevelForeignKeys(columnDef),
|
|
391
|
+
];
|
|
334
392
|
// A non-foldable default backfills each existing row from its own value. Install a row
|
|
335
393
|
// slot over the default's row descriptor; the evaluator the module calls per existing
|
|
336
394
|
// row sets the slot to that row, so the default's `new.<col>` refs resolve to it.
|
|
@@ -369,185 +427,226 @@ async function runAddColumn(rctx, tableSchema, schema, columnDef, backfill, back
|
|
|
369
427
|
// scan below re-reads the table — so the backfill's context does not shadow the
|
|
370
428
|
// scan's own row context.
|
|
371
429
|
let updatedTableSchema;
|
|
430
|
+
// Slot the module actually placed the new column at (the module API permits
|
|
431
|
+
// `insertAtIndex`; SQL always appends). Recorded so the revert paths below can apply
|
|
432
|
+
// the inverse event remap.
|
|
433
|
+
let addedColIndex;
|
|
372
434
|
try {
|
|
373
435
|
updatedTableSchema = await module.alterTable(rctx.db, tableSchema.schemaName, tableSchema.name, {
|
|
374
436
|
type: 'addColumn',
|
|
375
437
|
columnDef,
|
|
376
438
|
backfillEvaluator,
|
|
377
439
|
});
|
|
440
|
+
// Events this transaction already batched for the table still describe the
|
|
441
|
+
// pre-ADD column set; insert the backfilled value at the new slot so a listener
|
|
442
|
+
// at commit pairs value i with column i of the schema current at delivery.
|
|
443
|
+
// Covers the engine auto-event path and the store module (which flushed its
|
|
444
|
+
// queued events into the batch during the ALTER); the memory module's own
|
|
445
|
+
// pending-change log is reshaped inside its alterTable. Must run INSIDE this
|
|
446
|
+
// try: the backfill evaluator closes over rowSlot/checkSlot, which the finally
|
|
447
|
+
// below closes the moment the module returns.
|
|
448
|
+
addedColIndex = updatedTableSchema.columnIndexMap.get(columnDef.name.toLowerCase());
|
|
449
|
+
if (addedColIndex !== undefined) {
|
|
450
|
+
const insertAt = addedColIndex;
|
|
451
|
+
await rctx.db._getEventEmitter().remapBatchedDataEvents(tableSchema.schemaName, tableSchema.name, async (row) => {
|
|
452
|
+
// oldRow gets the SAME map as newRow: the literal default, or the backfill
|
|
453
|
+
// evaluator applied to the pre-image itself (the evaluator is a function of
|
|
454
|
+
// a row, and the pre-image is a row), falling back to NULL — the honest
|
|
455
|
+
// "column did not exist yet" placeholder, which errs toward REPORTING a
|
|
456
|
+
// change on the new column rather than suppressing one. Rejected: reusing
|
|
457
|
+
// the newRow result for oldRow (makes oldRow[new] === newRow[new] always,
|
|
458
|
+
// so a diffing consumer never syncs the added column); suppressing the
|
|
459
|
+
// pre-ALTER oldRow (silently turns updates into upserts).
|
|
460
|
+
let value = foldedDefault ?? null;
|
|
461
|
+
if (backfillEvaluator) {
|
|
462
|
+
try {
|
|
463
|
+
value = await backfillEvaluator(row);
|
|
464
|
+
}
|
|
465
|
+
catch {
|
|
466
|
+
// Best-effort: a historical image may fail the evaluator (or its
|
|
467
|
+
// CHECKs) where every live row backfilled cleanly. Never abort
|
|
468
|
+
// the ALTER for an event image.
|
|
469
|
+
value = null;
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
return [...row.slice(0, insertAt), value, ...row.slice(insertAt)];
|
|
473
|
+
}, updatedTableSchema.columns.map(c => c.name));
|
|
474
|
+
}
|
|
378
475
|
}
|
|
379
476
|
finally {
|
|
380
477
|
rowSlot?.close();
|
|
381
478
|
checkSlot?.close();
|
|
382
479
|
}
|
|
383
|
-
//
|
|
384
|
-
//
|
|
385
|
-
//
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
}
|
|
421
|
-
// Resolve the new child column index in the freshly returned schema for any FK constraints.
|
|
422
|
-
const newColIdx = updatedTableSchema.columnIndexMap.get(columnDef.name.toLowerCase());
|
|
423
|
-
const resolvedForeignKeys = newColIdx !== undefined
|
|
424
|
-
? newForeignKeys.map(fk => ({ ...fk, columns: Object.freeze([newColIdx]) }))
|
|
425
|
-
: newForeignKeys;
|
|
426
|
-
// Merge new column-level CHECK / FK into the table-level constraint sets so the
|
|
427
|
-
// existing constraint-builder picks them up for INSERT/UPDATE enforcement.
|
|
428
|
-
const mergedChecks = newCheckConstraints.length > 0
|
|
429
|
-
? Object.freeze([...updatedTableSchema.checkConstraints, ...newCheckConstraints])
|
|
430
|
-
: updatedTableSchema.checkConstraints;
|
|
431
|
-
const mergedForeignKeys = resolvedForeignKeys.length > 0
|
|
432
|
-
? Object.freeze([...(updatedTableSchema.foreignKeys ?? []), ...resolvedForeignKeys])
|
|
433
|
-
: updatedTableSchema.foreignKeys;
|
|
434
|
-
const enhancedBase = {
|
|
435
|
-
...updatedTableSchema,
|
|
436
|
-
checkConstraints: mergedChecks,
|
|
437
|
-
foreignKeys: mergedForeignKeys,
|
|
438
|
-
};
|
|
439
|
-
// Recompute the generated-column dependency graph. If the added column is
|
|
440
|
-
// generated and its expression references an unknown column, or any new
|
|
441
|
-
// generated-column edges form a cycle, this throws before we register the
|
|
442
|
-
// new schema in the catalog.
|
|
443
|
-
const enhancedTableSchema = withGeneratedColumnGraph(enhancedBase);
|
|
444
|
-
// The optimizer trusts a DECLARED constraint as a proven invariant, which makes
|
|
445
|
-
// the existing-row validators below fold away their own work if the new constraint
|
|
446
|
-
// is already live:
|
|
447
|
-
// - A new FK seeds an inclusion dependency `child.fk ⊆ parent.pk`; the FK
|
|
448
|
-
// validator's `not exists` anti-join folds to EmptyRelation under
|
|
449
|
-
// `ruleAntiJoinFkEmpty` (+ the INDs seeded at TableReferenceNode).
|
|
450
|
-
// - A new CHECK `<p>` seeds a domain constraint on the scan; the CHECK post-scan's
|
|
451
|
-
// own `where not (<p>)` folds to EmptyRelation under `ruleFilterContradiction`
|
|
452
|
-
// (the domain `<p>` and the predicate `not <p>` are jointly unsatisfiable).
|
|
453
|
-
// Either fold makes validation trust the very invariant it is checking and silently
|
|
454
|
-
// admit a violating row. So register the new COLUMN with only the PRE-EXISTING
|
|
455
|
-
// (already-proven) constraints for the validation pass, then register the full schema
|
|
456
|
-
// — with the new FK(s) and CHECK(s) — only once validation passes. This mirrors the
|
|
457
|
-
// ADD CONSTRAINT path, which validates before swapping the constraint into the live
|
|
458
|
-
// schema. Pre-existing constraints are kept: they held before this ALTER, so folding
|
|
459
|
-
// against them is sound and preserves the optimizer's reach.
|
|
460
|
-
const hasNewForeignKeys = resolvedForeignKeys.length > 0;
|
|
461
|
-
const hasNewChecks = newCheckConstraints.length > 0;
|
|
462
|
-
const usesIntermediateSchema = hasNewForeignKeys || hasNewChecks;
|
|
463
|
-
const validationSchema = usesIntermediateSchema
|
|
464
|
-
? withGeneratedColumnGraph({
|
|
465
|
-
...enhancedBase,
|
|
466
|
-
checkConstraints: updatedTableSchema.checkConstraints,
|
|
467
|
-
foreignKeys: updatedTableSchema.foreignKeys,
|
|
468
|
-
})
|
|
469
|
-
: enhancedTableSchema;
|
|
470
|
-
schema.addTable(validationSchema);
|
|
471
|
-
// Validate new CHECK constraints against the (already-backfilled) rows AND validate
|
|
472
|
-
// existing rows against any new column-level FK, reverting (drop the column + restore
|
|
473
|
-
// the original catalog entry) on a violation. Both run inside a single try/revert
|
|
474
|
-
// region so that when both a new CHECK and a new FK exist and either fails, the same
|
|
475
|
-
// revert path fires.
|
|
476
|
-
//
|
|
477
|
-
// CHECK is gated on `!backfill`: NOT NULL of a per-row default is enforced by the module
|
|
478
|
-
// during backfill (it has the values in-hand and throws before the column is committed),
|
|
479
|
-
// and the per-row (evaluator) default path already enforced each CHECK inside the backfill
|
|
480
|
-
// hook above (against the freshly-computed value, not a stale snapshot). The CHECK post-scan
|
|
481
|
-
// is therefore only correct for the literal-default path, whose values were bulk-written by
|
|
482
|
-
// the module without a per-row hook.
|
|
483
|
-
//
|
|
484
|
-
// FK runs for ALL default kinds. It is a cross-table existence check, not a per-row
|
|
485
|
-
// predicate, so it must be a post-`alterTable` scan: the scan sees both the bulk-written
|
|
486
|
-
// (literal) and per-row-evaluated backfilled values, and for a self-referential FK it reads
|
|
487
|
-
// a consistent post-alter table (a per-row hook would have to query the very table being
|
|
488
|
-
// rebuilt). It reuses `validateForeignKeyOverExistingRows` — the same MATCH-SIMPLE,
|
|
489
|
-
// pragma-gated validator the ADD CONSTRAINT path calls — so the two paths can never drift.
|
|
490
|
-
const runCheckScan = !backfill && newCheckConstraints.length > 0;
|
|
491
|
-
if (runCheckScan || hasNewForeignKeys) {
|
|
492
|
-
try {
|
|
493
|
-
// Reject any new FK whose child/parent column collations declare a same-rank
|
|
494
|
-
// conflict (the conflict enforcement would raise at first DML). Pure schema
|
|
495
|
-
// check — no row scan, pragma-independent — but kept inside this try/revert
|
|
496
|
-
// region so a conflict drops the just-materialized column and restores the
|
|
497
|
-
// original catalog, leaving the table untouched. `enhancedTableSchema` carries
|
|
498
|
-
// the new column so the child FK column resolves.
|
|
499
|
-
for (const fk of resolvedForeignKeys) {
|
|
500
|
-
validateForeignKeyCollations(rctx.db, enhancedTableSchema, fk);
|
|
501
|
-
}
|
|
502
|
-
if (runCheckScan) {
|
|
503
|
-
await validateBackfillAgainstChecks(rctx, validationSchema, newCheckConstraints);
|
|
504
|
-
}
|
|
505
|
-
for (const fk of resolvedForeignKeys) {
|
|
506
|
-
// `enhancedTableSchema` supplies only column-name resolution here; the LIVE
|
|
507
|
-
// schema the planner reads is `validationSchema`, which omits the new FK(s)
|
|
508
|
-
// and CHECK(s), so the anti-join is not folded.
|
|
509
|
-
await validateForeignKeyOverExistingRows(rctx.db, enhancedTableSchema, fk);
|
|
510
|
-
}
|
|
480
|
+
// The column is materialized; now install the inline constraints. Names of the CHECK /
|
|
481
|
+
// FK ones the module has accepted so far, so a later failure can hand each back to
|
|
482
|
+
// `dropConstraint` before the column itself goes (see {@link revertAddColumn}).
|
|
483
|
+
const installedConstraintNames = [];
|
|
484
|
+
let finalTableSchema;
|
|
485
|
+
try {
|
|
486
|
+
// Recompute the generated-column dependency graph. If the added column is generated
|
|
487
|
+
// and its expression references an unknown column, or any new generated-column edges
|
|
488
|
+
// form a cycle, this throws — and the revert below undoes the materialization.
|
|
489
|
+
const columnOnlySchema = withGeneratedColumnGraph(updatedTableSchema);
|
|
490
|
+
// Register the COLUMN-ONLY schema before installing any inline constraint. Two
|
|
491
|
+
// properties depend on this ordering, and both are easy to break:
|
|
492
|
+
//
|
|
493
|
+
// - The module's FK arm validates existing rows with SQL planned against the LIVE
|
|
494
|
+
// catalog, so the new column has to resolve there. Likewise the CHECK backfill
|
|
495
|
+
// scan below.
|
|
496
|
+
// - The new constraint must NOT be live while its own validation runs. The optimizer
|
|
497
|
+
// trusts a DECLARED constraint as a proven invariant: a declared FK seeds the
|
|
498
|
+
// inclusion dependency `child.fk ⊆ parent.pk` and folds the validator's own
|
|
499
|
+
// `not exists` anti-join to EmptyRelation (`ruleAntiJoinFkEmpty`); a declared CHECK
|
|
500
|
+
// `<p>` seeds a domain constraint that folds the CHECK scan's `where not (<p>)`
|
|
501
|
+
// away (`ruleFilterContradiction`). Either fold makes validation trust the very
|
|
502
|
+
// thing it is checking and silently admit a violating row. The module holds each
|
|
503
|
+
// new constraint in its own cached schema until that constraint's validation
|
|
504
|
+
// passes, and the catalog only learns of them from `finalTableSchema` below.
|
|
505
|
+
//
|
|
506
|
+
// Pre-existing constraints stay live throughout: they held before this ALTER, so
|
|
507
|
+
// folding against them is sound and preserves the optimizer's reach.
|
|
508
|
+
schema.addTable(columnOnlySchema);
|
|
509
|
+
// Validate the backfilled values against each inline CHECK, for the literal-default
|
|
510
|
+
// path only. A per-row (evaluator) default already enforced its CHECKs inside the
|
|
511
|
+
// backfill hook above — against the freshly-computed value rather than this scan's
|
|
512
|
+
// stale pre-backfill snapshot — and the module enforces NOT NULL there too. Runs
|
|
513
|
+
// before the whole install loop below, so on a column declaring several kinds a
|
|
514
|
+
// CHECK violation is reported ahead of a UNIQUE or FK one.
|
|
515
|
+
if (!backfill && inlineChecks.length > 0) {
|
|
516
|
+
await validateBackfillAgainstChecks(rctx, columnOnlySchema, inlineChecks);
|
|
511
517
|
}
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
518
|
+
// Starts as the column-only schema so a column with no inline constraint needs no
|
|
519
|
+
// further work; each accepted constraint replaces it with the module's answer.
|
|
520
|
+
//
|
|
521
|
+
// NOTE: one module round-trip per inline constraint — each takes the module's
|
|
522
|
+
// schema-change latch and, store-backed, writes the table's DDL again. Fine at the
|
|
523
|
+
// counts SQL produces (a column declares 0 or 1 of each kind); if a batched
|
|
524
|
+
// `addConstraint` arm ever appears, or ADD COLUMN becomes hot, hand the whole set
|
|
525
|
+
// over in one call instead.
|
|
526
|
+
let current = columnOnlySchema;
|
|
527
|
+
for (const constraint of inlineConstraints) {
|
|
528
|
+
// A CHECK / FK is dropped by NAME on the revert path, so resolve the name the
|
|
529
|
+
// module will store BEFORE handing the constraint over. UNIQUE needs no entry:
|
|
530
|
+
// an unnamed one has no name to drop by, and the module's own DROP COLUMN
|
|
531
|
+
// prunes a UNIQUE over the dropped column (which CHECK / FK are not).
|
|
532
|
+
let installedName;
|
|
533
|
+
if (constraint.type === 'foreignKey') {
|
|
534
|
+
// Reject a same-rank child/parent collation conflict (which enforcement would
|
|
535
|
+
// raise at the first DML) BEFORE `module.alterTable`, so a rejected ALTER never
|
|
536
|
+
// reaches the module's persistence side effects — mirroring
|
|
537
|
+
// `runAddConstraintViaModule`. Built with the same builder and columnIndexMap
|
|
538
|
+
// the module uses, so the name and column indices are identical to its own.
|
|
539
|
+
const fk = buildForeignKeyConstraintSchema(constraint, columnOnlySchema.columnIndexMap, tableSchema.name, tableSchema.schemaName);
|
|
540
|
+
validateForeignKeyCollations(rctx.db, columnOnlySchema, fk);
|
|
541
|
+
installedName = fk.name;
|
|
519
542
|
}
|
|
520
|
-
|
|
521
|
-
|
|
543
|
+
else if (constraint.type === 'check') {
|
|
544
|
+
installedName = constraint.name; // always set by the extractor
|
|
522
545
|
}
|
|
523
|
-
|
|
524
|
-
|
|
546
|
+
// The module materializes (UNIQUE's covering structure), validates the existing
|
|
547
|
+
// rows as the kind requires (UNIQUE duplicates, pragma-gated MATCH SIMPLE FK
|
|
548
|
+
// orphans) and — store-backed — persists. Thread the returned schema forward so
|
|
549
|
+
// each constraint layers on the last. The module's answer carries no
|
|
550
|
+
// generated-column bookkeeping of its own, so re-derive it each round.
|
|
551
|
+
const withConstraint = await module.alterTable(rctx.db, tableSchema.schemaName, tableSchema.name, {
|
|
552
|
+
type: 'addConstraint',
|
|
553
|
+
constraint,
|
|
554
|
+
});
|
|
555
|
+
current = withGeneratedColumnGraph(withConstraint);
|
|
556
|
+
if (installedName !== undefined)
|
|
557
|
+
installedConstraintNames.push(installedName);
|
|
525
558
|
}
|
|
559
|
+
finalTableSchema = current;
|
|
526
560
|
}
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
if (usesIntermediateSchema) {
|
|
531
|
-
schema.addTable(enhancedTableSchema);
|
|
561
|
+
catch (err) {
|
|
562
|
+
await revertAddColumn(rctx, tableSchema, schema, columnDef.name, addedColIndex, installedConstraintNames);
|
|
563
|
+
throw err;
|
|
532
564
|
}
|
|
565
|
+
// Every constraint validated and installed — publish the module's final schema.
|
|
566
|
+
schema.addTable(finalTableSchema);
|
|
533
567
|
rctx.db.schemaManager.getChangeNotifier().notifyChange({
|
|
534
568
|
type: 'table_modified',
|
|
535
569
|
schemaName: tableSchema.schemaName,
|
|
536
570
|
objectName: tableSchema.name,
|
|
537
571
|
oldObject: tableSchema,
|
|
538
|
-
newObject:
|
|
572
|
+
newObject: finalTableSchema,
|
|
539
573
|
});
|
|
540
574
|
log('Added column %s to table %s.%s', columnDef.name, tableSchema.schemaName, tableSchema.name);
|
|
541
575
|
return null;
|
|
542
576
|
}
|
|
543
577
|
/**
|
|
544
|
-
*
|
|
545
|
-
*
|
|
578
|
+
* Undoes a partially-applied ADD COLUMN, leaving the table exactly as it was: hands each
|
|
579
|
+
* inline CHECK / FK the module already accepted back to `dropConstraint` (newest first),
|
|
580
|
+
* drops the column, un-remaps the batched events, and restores the original catalog entry.
|
|
581
|
+
*
|
|
582
|
+
* The constraints must go before the column: neither built-in module prunes a CHECK / FK
|
|
583
|
+
* over a dropped column, so a stranded one would keep naming a column the table no longer
|
|
584
|
+
* has. (An inline UNIQUE needs no explicit drop — both modules prune a UNIQUE over the
|
|
585
|
+
* dropped column, and an unnamed one has no name to drop by.)
|
|
586
|
+
*
|
|
587
|
+
* Best-effort on the module half: a revert failure is logged, never thrown, so it cannot
|
|
588
|
+
* mask the original violation. Restoring the catalog entry is a no-op when the ALTER failed
|
|
589
|
+
* before registering anything (the original schema is still the live one).
|
|
590
|
+
*
|
|
591
|
+
* NOTE: the hand-back is by NAME, so it assumes a name resolves to the constraint this
|
|
592
|
+
* ALTER installed. A pre-existing constraint can legitimately share an auto-name (nothing
|
|
593
|
+
* rejects `constraint _check_w check (…)` on a table that later gets `add column w …
|
|
594
|
+
* check (…)`; `create table` collides the same way), and today both modules' DROP
|
|
595
|
+
* CONSTRAINT removes every match, which lands on the right end state. If constraint-name
|
|
596
|
+
* resolution ever narrows to a single match, revert must instead identify the installed
|
|
597
|
+
* constraint by identity — otherwise it can drop the pre-existing one and leave ours.
|
|
598
|
+
*/
|
|
599
|
+
async function revertAddColumn(rctx, tableSchema, schema, columnName, addedColIndex, installedConstraintNames) {
|
|
600
|
+
try {
|
|
601
|
+
const module = requireVtabModule(tableSchema);
|
|
602
|
+
// Unreachable: runAddColumn requires `alterTable` before materializing anything.
|
|
603
|
+
if (!module.alterTable)
|
|
604
|
+
return;
|
|
605
|
+
for (let i = installedConstraintNames.length - 1; i >= 0; i--) {
|
|
606
|
+
await module.alterTable(rctx.db, tableSchema.schemaName, tableSchema.name, {
|
|
607
|
+
type: 'dropConstraint',
|
|
608
|
+
constraintName: installedConstraintNames[i],
|
|
609
|
+
});
|
|
610
|
+
}
|
|
611
|
+
await module.alterTable(rctx.db, tableSchema.schemaName, tableSchema.name, {
|
|
612
|
+
type: 'dropColumn',
|
|
613
|
+
columnName,
|
|
614
|
+
});
|
|
615
|
+
await remapEventsForRevertedAddColumn(rctx, tableSchema, addedColIndex);
|
|
616
|
+
}
|
|
617
|
+
catch (revertErr) {
|
|
618
|
+
log('Failed to revert ADD COLUMN %s.%s.%s: %s', tableSchema.schemaName, tableSchema.name, columnName, revertErr.message);
|
|
619
|
+
}
|
|
620
|
+
schema.addTable(tableSchema);
|
|
621
|
+
}
|
|
622
|
+
/**
|
|
623
|
+
* Inverse of {@link runAddColumn}'s batched-event remap, for its revert paths: the
|
|
624
|
+
* just-added column has been dropped from the module again, so the batched events must
|
|
625
|
+
* drop the slot too or they keep describing a column the table no longer has. No-op when
|
|
626
|
+
* the forward remap never ran (`addedColIndex` undefined). Best-effort like the forward
|
|
627
|
+
* remap — never masks the original constraint error.
|
|
628
|
+
*/
|
|
629
|
+
async function remapEventsForRevertedAddColumn(rctx, tableSchema, addedColIndex) {
|
|
630
|
+
if (addedColIndex === undefined)
|
|
631
|
+
return;
|
|
632
|
+
await rctx.db._getEventEmitter().remapBatchedDataEvents(tableSchema.schemaName, tableSchema.name, (row) => row.filter((_, i) => i !== addedColIndex), tableSchema.columns.map(c => c.name));
|
|
633
|
+
}
|
|
634
|
+
/**
|
|
635
|
+
* Runs each new CHECK against the (already-backfilled) existing rows. Relies on the
|
|
636
|
+
* just-registered column-only schema so SQL can resolve the new column while the CHECK
|
|
637
|
+
* itself is not yet declared — declaring it first would let `ruleFilterContradiction`
|
|
638
|
+
* fold this scan's own `not (<check_expr>)` to EmptyRelation. Any row matching
|
|
546
639
|
* `not (<check_expr>)` is a violation and aborts the ALTER.
|
|
547
640
|
*/
|
|
548
|
-
async function validateBackfillAgainstChecks(rctx,
|
|
549
|
-
const qualifiedTable = qualifyTableName(
|
|
641
|
+
async function validateBackfillAgainstChecks(rctx, columnOnlySchema, newCheckConstraints) {
|
|
642
|
+
const qualifiedTable = qualifyTableName(columnOnlySchema.schemaName, columnOnlySchema.name);
|
|
550
643
|
for (const cc of newCheckConstraints) {
|
|
644
|
+
// `extractColumnLevelCheckConstraints` skips an expression-less CHECK, so this
|
|
645
|
+
// cannot fire — but silently skipping a constraint we were asked to validate
|
|
646
|
+
// would admit a violating row, so say so loudly rather than `continue`.
|
|
647
|
+
if (!cc.expr) {
|
|
648
|
+
throw new QuereusError(`CHECK constraint ${cc.name ? `'${cc.name}' ` : ''}on ALTER TABLE ADD COLUMN has no expression`, StatusCode.INTERNAL);
|
|
649
|
+
}
|
|
551
650
|
const checkSql = expressionToString(cc.expr);
|
|
552
651
|
const sql = `select 1 from ${qualifiedTable} where not (${checkSql}) limit 1`;
|
|
553
652
|
const stmt = rctx.db.prepare(sql);
|
|
@@ -558,7 +657,7 @@ async function validateBackfillAgainstChecks(rctx, enhancedTableSchema, newCheck
|
|
|
558
657
|
break;
|
|
559
658
|
}
|
|
560
659
|
if (violated) {
|
|
561
|
-
throw new QuereusError(`CHECK constraint ${cc.name ? `'${cc.name}' ` : ''}violated by backfilled rows in ALTER TABLE ADD COLUMN on '${
|
|
660
|
+
throw new QuereusError(`CHECK constraint ${cc.name ? `'${cc.name}' ` : ''}violated by backfilled rows in ALTER TABLE ADD COLUMN on '${columnOnlySchema.name}'`, StatusCode.CONSTRAINT);
|
|
562
661
|
}
|
|
563
662
|
}
|
|
564
663
|
finally {
|
|
@@ -668,6 +767,13 @@ async function runDropColumn(rctx, tableSchema, schema, columnName) {
|
|
|
668
767
|
type: 'dropColumn',
|
|
669
768
|
columnName,
|
|
670
769
|
});
|
|
770
|
+
// Events this transaction already batched for the table still carry the pre-drop
|
|
771
|
+
// arity; drop the slot so a listener at commit pairs value i with column i of the
|
|
772
|
+
// schema current at delivery (and `changedColumns` never names the dropped column).
|
|
773
|
+
// Pure slot filter — no failure mode. Covers the engine auto-event path and the
|
|
774
|
+
// store module (which flushed its queued events into the batch during the ALTER);
|
|
775
|
+
// the memory module's own pending-change log is reshaped inside its alterTable.
|
|
776
|
+
await rctx.db._getEventEmitter().remapBatchedDataEvents(tableSchema.schemaName, tableSchema.name, (row) => row.filter((_, i) => i !== colIndex), updatedTableSchema.columns.map(c => c.name));
|
|
671
777
|
// Recompute the generated-column dependency graph against the post-drop
|
|
672
778
|
// column array — old indices in the previous map are invalid.
|
|
673
779
|
const finalSchema = withGeneratedColumnGraph(updatedTableSchema);
|
|
@@ -803,6 +909,16 @@ async function runAlterColumn(rctx, tableSchema, schema, action) {
|
|
|
803
909
|
if (action.setCollation !== undefined) {
|
|
804
910
|
validateCollationForType(action.setCollation, tableSchema.columns[colIndex].logicalType, action.columnName, (n) => rctx.db.isCollationRegistered(n));
|
|
805
911
|
}
|
|
912
|
+
// SET DATA TYPE: the column keeps its current collation, so the NEW type has to accept it —
|
|
913
|
+
// otherwise the ALTER mints a column shape CREATE TABLE would refuse and generateTableDDL
|
|
914
|
+
// cannot round-trip (a store-backed table with such a column is silently dropped on rehydrate).
|
|
915
|
+
// Same validator, same error text as CREATE TABLE / SET COLLATE. Rejects uniformly whether the
|
|
916
|
+
// collation was user-declared or inherited from `pragma default_collation`: `collationExplicit`
|
|
917
|
+
// is not persisted, so keying on it would coerce before a reopen and reject after one.
|
|
918
|
+
// Remedy: `SET COLLATE binary` first, then retype.
|
|
919
|
+
if (action.setDataType !== undefined) {
|
|
920
|
+
validateCollationForType(tableSchema.columns[colIndex].collation, inferType(action.setDataType), action.columnName, (n) => rctx.db.isCollationRegistered(n));
|
|
921
|
+
}
|
|
806
922
|
// Route a SET DEFAULT through the same DDL validator CREATE TABLE uses, so the
|
|
807
923
|
// stored default is consistent with what INSERT will accept: bind params / bare
|
|
808
924
|
// columns / non-determinism rejected, `new.<column>` accepted (deferred to INSERT
|
|
@@ -823,6 +939,18 @@ async function runAlterColumn(rctx, tableSchema, schema, action) {
|
|
|
823
939
|
setDefault: action.setDefault,
|
|
824
940
|
setCollation: action.setCollation,
|
|
825
941
|
});
|
|
942
|
+
// Events this transaction already batched still carry the PRE-conversion value at
|
|
943
|
+
// the altered column (`SET DATA TYPE`'s normalization, `SET NOT NULL`'s null →
|
|
944
|
+
// DEFAULT backfill); rewrite it so a listener at commit sees the value the
|
|
945
|
+
// committed row holds. The conversion is engine-derivable (the same
|
|
946
|
+
// `validateAndParse` the memory module's converter wraps), so no module-contract
|
|
947
|
+
// change. `SET COLLATE` / `SET DEFAULT` / `DROP NOT NULL` move no stored value and
|
|
948
|
+
// need no remap — in particular the primary-key `SET COLLATE` re-key leaves every
|
|
949
|
+
// event's key and row images valid as-is.
|
|
950
|
+
const eventValueRemap = alterColumnEventValueRemap(tableSchema, colIndex, action);
|
|
951
|
+
if (eventValueRemap) {
|
|
952
|
+
await rctx.db._getEventEmitter().remapBatchedDataEvents(tableSchema.schemaName, tableSchema.name, (row) => row.map((v, i) => i === colIndex ? eventValueRemap(v) : v), updatedTableSchema.columns.map(c => c.name));
|
|
953
|
+
}
|
|
826
954
|
schema.addTable(updatedTableSchema);
|
|
827
955
|
rctx.db.schemaManager.getChangeNotifier().notifyChange({
|
|
828
956
|
type: 'table_modified',
|
|
@@ -834,6 +962,51 @@ async function runAlterColumn(rctx, tableSchema, schema, action) {
|
|
|
834
962
|
log('Altered column %s.%s.%s', tableSchema.schemaName, tableSchema.name, action.columnName);
|
|
835
963
|
return null;
|
|
836
964
|
}
|
|
965
|
+
/**
|
|
966
|
+
* The per-value map {@link runAlterColumn}'s batched-event remap applies at the altered
|
|
967
|
+
* column, or undefined when the ALTER moves no stored value (SET COLLATE, SET DEFAULT,
|
|
968
|
+
* DROP NOT NULL, an alias retype). The returned function is TOTAL — an unconvertible
|
|
969
|
+
* historical event image keeps its raw value rather than aborting the ALTER; the module
|
|
970
|
+
* already validated every value the transaction can actually SEE, so a failure here is
|
|
971
|
+
* confined to a superseded intermediate image.
|
|
972
|
+
*/
|
|
973
|
+
function alterColumnEventValueRemap(tableSchema, colIndex, action) {
|
|
974
|
+
if (action.setDataType !== undefined) {
|
|
975
|
+
const newLogicalType = inferType(action.setDataType);
|
|
976
|
+
// Alias retype (`varchar(50)` IS TEXT): schema-only, values untouched.
|
|
977
|
+
if (newLogicalType === tableSchema.columns[colIndex].logicalType)
|
|
978
|
+
return undefined;
|
|
979
|
+
const columnName = tableSchema.columns[colIndex].name;
|
|
980
|
+
return (v) => {
|
|
981
|
+
if (v === null)
|
|
982
|
+
return v; // retype leaves NULLs untouched, matching the module's conversion
|
|
983
|
+
try {
|
|
984
|
+
return validateAndParse(v, newLogicalType, columnName);
|
|
985
|
+
}
|
|
986
|
+
catch {
|
|
987
|
+
// NOTE: the surviving raw value is honest about what the row held, but its
|
|
988
|
+
// JS type no longer matches the column's logical type — the delivered
|
|
989
|
+
// contract is positional (value i belongs to column i), not typed. Only
|
|
990
|
+
// reachable for a superseded intermediate image (e.g. insert 'zzz' →
|
|
991
|
+
// update to '42' → retype to integer delivers oldRow ['zzz']). If a
|
|
992
|
+
// consumer ever type-validates delivered images, revisit: the options are
|
|
993
|
+
// NULL (loses the value) or dropping the image (loses the event).
|
|
994
|
+
return v;
|
|
995
|
+
}
|
|
996
|
+
};
|
|
997
|
+
}
|
|
998
|
+
if (action.setNotNull === true) {
|
|
999
|
+
// SET NOT NULL backfill: null → the folded literal DEFAULT, the same map the
|
|
1000
|
+
// module applies. No usable literal default means the module either found no
|
|
1001
|
+
// NULLs (nothing to remap) or rejected the ALTER before reaching here.
|
|
1002
|
+
const defaultExpr = tableSchema.columns[colIndex].defaultValue;
|
|
1003
|
+
const folded = defaultExpr ? tryFoldLiteral(defaultExpr) : undefined;
|
|
1004
|
+
if (folded === undefined || folded === null)
|
|
1005
|
+
return undefined;
|
|
1006
|
+
return (v) => (v === null ? folded : v);
|
|
1007
|
+
}
|
|
1008
|
+
return undefined;
|
|
1009
|
+
}
|
|
837
1010
|
/**
|
|
838
1011
|
* Catalog-only metadata-tag mutations. Tags touch no stored row and no physical
|
|
839
1012
|
* layout, so these never call `module.alterTable` — they delegate to the
|
|
@@ -1295,13 +1468,23 @@ function rewriteTableForTableRename(table, renamedSchemaLower, oldName, newName)
|
|
|
1295
1468
|
indexes: table.indexes ? Object.freeze(newIndexes) : table.indexes,
|
|
1296
1469
|
});
|
|
1297
1470
|
}
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1471
|
+
/**
|
|
1472
|
+
* The catalog-backed {@link ResolveColumnInSource} the column-rename rewriters consult
|
|
1473
|
+
* to keep their unqualified-reference walk scope-aware. Built once per statement and
|
|
1474
|
+
* shared by the pre-flight probe in {@link runRenameColumn} and the real propagation
|
|
1475
|
+
* below, so the two cannot drift apart. Note it resolves against the LIVE catalog on
|
|
1476
|
+
* every call, so sharing it does not by itself freeze the answer between the two passes
|
|
1477
|
+
* — see the pre-flight's comment for why they agree anyway.
|
|
1478
|
+
*/
|
|
1479
|
+
function buildColumnSourceResolver(db) {
|
|
1480
|
+
return (s, t, col) => {
|
|
1481
|
+
const targetSchema = db.schemaManager.getSchema(s);
|
|
1302
1482
|
const targetTable = targetSchema?.getTable(t);
|
|
1303
1483
|
return targetTable?.columnIndexMap.has(col.toLowerCase()) ?? false;
|
|
1304
1484
|
};
|
|
1485
|
+
}
|
|
1486
|
+
async function propagateColumnRename(rctx, renamedSchemaName, tableName, oldCol, newCol, preStaleMvs, resolveColumnInSource) {
|
|
1487
|
+
const schemaManager = rctx.db.schemaManager;
|
|
1305
1488
|
for (const schema of schemaManager._getAllSchemas()) {
|
|
1306
1489
|
await propagateColumnRenameInSchema(rctx.db, schema, renamedSchemaName, tableName, oldCol, newCol, resolveColumnInSource, preStaleMvs);
|
|
1307
1490
|
}
|