@quereus/quereus 4.4.0 → 4.5.0
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 +6 -1
- 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-materialized-views-analysis.d.ts.map +1 -1
- package/dist/src/core/database-materialized-views-analysis.js +1 -0
- package/dist/src/core/database-materialized-views-analysis.js.map +1 -1
- package/dist/src/core/database-materialized-views-plan-builders.d.ts +2 -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 +26 -5
- package/dist/src/core/database-materialized-views-plan-builders.js.map +1 -1
- package/dist/src/core/database-materialized-views-plans.d.ts +6 -3
- package/dist/src/core/database-materialized-views-plans.d.ts.map +1 -1
- package/dist/src/core/database-materialized-views.d.ts +3 -2
- package/dist/src/core/database-materialized-views.d.ts.map +1 -1
- package/dist/src/core/database-materialized-views.js +26 -5
- 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 +21 -1
- 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 +45 -67
- 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/builtins/scalar.d.ts.map +1 -1
- package/dist/src/func/builtins/scalar.js +92 -3
- package/dist/src/func/builtins/scalar.js.map +1 -1
- package/dist/src/func/registration.d.ts +18 -1
- package/dist/src/func/registration.d.ts.map +1 -1
- package/dist/src/func/registration.js +26 -0
- package/dist/src/func/registration.js.map +1 -1
- package/dist/src/index.d.ts +10 -10
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +13 -12
- 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/coarsened-key.d.ts +4 -3
- package/dist/src/planner/analysis/coarsened-key.d.ts.map +1 -1
- package/dist/src/planner/analysis/coarsened-key.js +37 -3
- package/dist/src/planner/analysis/coarsened-key.js.map +1 -1
- package/dist/src/planner/analysis/comparison-collation.d.ts +35 -3
- package/dist/src/planner/analysis/comparison-collation.d.ts.map +1 -1
- package/dist/src/planner/analysis/comparison-collation.js +37 -3
- package/dist/src/planner/analysis/comparison-collation.js.map +1 -1
- package/dist/src/planner/analysis/coverage-prover.d.ts +13 -2
- package/dist/src/planner/analysis/coverage-prover.d.ts.map +1 -1
- package/dist/src/planner/analysis/coverage-prover.js +10 -14
- package/dist/src/planner/analysis/coverage-prover.js.map +1 -1
- 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/predicate-conjuncts.d.ts +10 -4
- package/dist/src/planner/analysis/predicate-conjuncts.d.ts.map +1 -1
- package/dist/src/planner/analysis/predicate-conjuncts.js +28 -7
- package/dist/src/planner/analysis/predicate-conjuncts.js.map +1 -1
- package/dist/src/planner/analysis/query-rewrite-matcher.d.ts +6 -0
- package/dist/src/planner/analysis/query-rewrite-matcher.d.ts.map +1 -1
- package/dist/src/planner/analysis/query-rewrite-matcher.js +19 -29
- 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 +22 -3
- package/dist/src/planner/analysis/scalar-subqueries.d.ts.map +1 -1
- package/dist/src/planner/analysis/scalar-subqueries.js +32 -3
- package/dist/src/planner/analysis/scalar-subqueries.js.map +1 -1
- package/dist/src/planner/analysis/set-op-type-merge.d.ts +64 -0
- package/dist/src/planner/analysis/set-op-type-merge.d.ts.map +1 -0
- package/dist/src/planner/analysis/set-op-type-merge.js +97 -0
- package/dist/src/planner/analysis/set-op-type-merge.js.map +1 -0
- package/dist/src/planner/building/coercion.d.ts +78 -0
- package/dist/src/planner/building/coercion.d.ts.map +1 -0
- package/dist/src/planner/building/coercion.js +137 -0
- package/dist/src/planner/building/coercion.js.map +1 -0
- package/dist/src/planner/building/constraint-builder.d.ts.map +1 -1
- package/dist/src/planner/building/constraint-builder.js +5 -18
- package/dist/src/planner/building/constraint-builder.js.map +1 -1
- 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 +13 -35
- 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/function-call.d.ts.map +1 -1
- package/dist/src/planner/building/function-call.js +8 -0
- package/dist/src/planner/building/function-call.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-compound.d.ts.map +1 -1
- package/dist/src/planner/building/select-compound.js +10 -6
- package/dist/src/planner/building/select-compound.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/cost/conjunct-cost.d.ts +42 -0
- package/dist/src/planner/cost/conjunct-cost.d.ts.map +1 -0
- package/dist/src/planner/cost/conjunct-cost.js +62 -0
- package/dist/src/planner/cost/conjunct-cost.js.map +1 -0
- package/dist/src/planner/framework/pass.js +3 -3
- package/dist/src/planner/mutation/propagate.d.ts.map +1 -1
- package/dist/src/planner/mutation/propagate.js +1 -0
- package/dist/src/planner/mutation/propagate.js.map +1 -1
- package/dist/src/planner/nodes/async-gather-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/async-gather-node.js +19 -8
- package/dist/src/planner/nodes/async-gather-node.js.map +1 -1
- package/dist/src/planner/nodes/bloom-join-node.d.ts +2 -0
- package/dist/src/planner/nodes/bloom-join-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/bloom-join-node.js +10 -5
- package/dist/src/planner/nodes/bloom-join-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/join-node.d.ts +5 -0
- package/dist/src/planner/nodes/join-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/join-node.js +8 -1
- package/dist/src/planner/nodes/join-node.js.map +1 -1
- package/dist/src/planner/nodes/join-utils.d.ts +57 -0
- package/dist/src/planner/nodes/join-utils.d.ts.map +1 -1
- package/dist/src/planner/nodes/join-utils.js +47 -0
- package/dist/src/planner/nodes/join-utils.js.map +1 -1
- package/dist/src/planner/nodes/key-set-semi-join-node.d.ts +87 -0
- package/dist/src/planner/nodes/key-set-semi-join-node.d.ts.map +1 -0
- package/dist/src/planner/nodes/key-set-semi-join-node.js +137 -0
- package/dist/src/planner/nodes/key-set-semi-join-node.js.map +1 -0
- package/dist/src/planner/nodes/merge-join-node.d.ts +2 -0
- package/dist/src/planner/nodes/merge-join-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/merge-join-node.js +14 -6
- package/dist/src/planner/nodes/merge-join-node.js.map +1 -1
- package/dist/src/planner/nodes/plan-node-type.d.ts +1 -0
- package/dist/src/planner/nodes/plan-node-type.d.ts.map +1 -1
- package/dist/src/planner/nodes/plan-node-type.js +1 -0
- package/dist/src/planner/nodes/plan-node-type.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/nodes/set-operation-node.d.ts +68 -16
- package/dist/src/planner/nodes/set-operation-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/set-operation-node.js +147 -26
- package/dist/src/planner/nodes/set-operation-node.js.map +1 -1
- package/dist/src/planner/nodes/table-access-nodes.d.ts +19 -1
- package/dist/src/planner/nodes/table-access-nodes.d.ts.map +1 -1
- package/dist/src/planner/nodes/table-access-nodes.js +13 -2
- package/dist/src/planner/nodes/table-access-nodes.js.map +1 -1
- package/dist/src/planner/optimizer.d.ts.map +1 -1
- package/dist/src/planner/optimizer.js +54 -12
- package/dist/src/planner/optimizer.js.map +1 -1
- package/dist/src/planner/rules/access/rule-key-set-seek.d.ts +68 -0
- package/dist/src/planner/rules/access/rule-key-set-seek.d.ts.map +1 -0
- package/dist/src/planner/rules/access/rule-key-set-seek.js +408 -0
- package/dist/src/planner/rules/access/rule-key-set-seek.js.map +1 -0
- package/dist/src/planner/rules/access/rule-monotonic-range-access.d.ts.map +1 -1
- package/dist/src/planner/rules/access/rule-monotonic-range-access.js +2 -2
- package/dist/src/planner/rules/access/rule-monotonic-range-access.js.map +1 -1
- package/dist/src/planner/rules/access/rule-select-access-path.d.ts +27 -0
- 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 +74 -29
- package/dist/src/planner/rules/access/rule-select-access-path.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 +23 -4
- package/dist/src/planner/rules/cache/rule-materialized-view-rewrite.js.map +1 -1
- package/dist/src/planner/rules/cache/rule-scalar-subquery-cache.d.ts +10 -8
- package/dist/src/planner/rules/cache/rule-scalar-subquery-cache.d.ts.map +1 -1
- package/dist/src/planner/rules/cache/rule-scalar-subquery-cache.js +10 -8
- package/dist/src/planner/rules/cache/rule-scalar-subquery-cache.js.map +1 -1
- package/dist/src/planner/rules/join/equi-pair-extractor.d.ts +67 -41
- package/dist/src/planner/rules/join/equi-pair-extractor.d.ts.map +1 -1
- package/dist/src/planner/rules/join/equi-pair-extractor.js +72 -36
- package/dist/src/planner/rules/join/equi-pair-extractor.js.map +1 -1
- package/dist/src/planner/rules/join/rule-join-physical-selection.d.ts.map +1 -1
- package/dist/src/planner/rules/join/rule-join-physical-selection.js +14 -2
- package/dist/src/planner/rules/join/rule-join-physical-selection.js.map +1 -1
- package/dist/src/planner/rules/join/rule-monotonic-merge-join.d.ts.map +1 -1
- package/dist/src/planner/rules/join/rule-monotonic-merge-join.js +11 -1
- package/dist/src/planner/rules/join/rule-monotonic-merge-join.js.map +1 -1
- package/dist/src/planner/rules/predicate/rule-empty-relation-folding.d.ts +1 -1
- package/dist/src/planner/rules/predicate/rule-empty-relation-folding.js +1 -1
- package/dist/src/planner/rules/predicate/rule-filter-conjunct-ordering.d.ts +30 -0
- package/dist/src/planner/rules/predicate/rule-filter-conjunct-ordering.d.ts.map +1 -0
- package/dist/src/planner/rules/predicate/rule-filter-conjunct-ordering.js +63 -0
- package/dist/src/planner/rules/predicate/rule-filter-conjunct-ordering.js.map +1 -0
- package/dist/src/planner/rules/predicate/rule-filter-selectivity.d.ts +17 -1
- package/dist/src/planner/rules/predicate/rule-filter-selectivity.d.ts.map +1 -1
- package/dist/src/planner/rules/predicate/rule-filter-selectivity.js +206 -12
- package/dist/src/planner/rules/predicate/rule-filter-selectivity.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/predicate/rule-predicate-pushdown.d.ts +3 -1
- package/dist/src/planner/rules/predicate/rule-predicate-pushdown.d.ts.map +1 -1
- package/dist/src/planner/rules/predicate/rule-predicate-pushdown.js +13 -1
- package/dist/src/planner/rules/predicate/rule-predicate-pushdown.js.map +1 -1
- package/dist/src/planner/rules/retrieve/rule-grow-retrieve.d.ts.map +1 -1
- package/dist/src/planner/rules/retrieve/rule-grow-retrieve.js +18 -3
- package/dist/src/planner/rules/retrieve/rule-grow-retrieve.js.map +1 -1
- package/dist/src/planner/rules/shared/index-style-context.d.ts +17 -0
- package/dist/src/planner/rules/shared/index-style-context.d.ts.map +1 -1
- package/dist/src/planner/rules/shared/index-style-context.js +7 -0
- package/dist/src/planner/rules/shared/index-style-context.js.map +1 -1
- package/dist/src/planner/rules/subquery/rule-scalar-agg-decorrelation.js +4 -0
- package/dist/src/planner/rules/subquery/rule-scalar-agg-decorrelation.js.map +1 -1
- package/dist/src/planner/rules/subquery/rule-subquery-decorrelation.d.ts +24 -6
- package/dist/src/planner/rules/subquery/rule-subquery-decorrelation.d.ts.map +1 -1
- package/dist/src/planner/rules/subquery/rule-subquery-decorrelation.js +175 -60
- package/dist/src/planner/rules/subquery/rule-subquery-decorrelation.js.map +1 -1
- package/dist/src/planner/stats/catalog-stats.d.ts +52 -0
- package/dist/src/planner/stats/catalog-stats.d.ts.map +1 -1
- package/dist/src/planner/stats/catalog-stats.js +151 -5
- package/dist/src/planner/stats/catalog-stats.js.map +1 -1
- package/dist/src/planner/stats/index.d.ts +15 -0
- package/dist/src/planner/stats/index.d.ts.map +1 -1
- package/dist/src/planner/stats/index.js.map +1 -1
- package/dist/src/planner/stats/selectivity-combine.d.ts +53 -0
- package/dist/src/planner/stats/selectivity-combine.d.ts.map +1 -0
- package/dist/src/planner/stats/selectivity-combine.js +75 -0
- package/dist/src/planner/stats/selectivity-combine.js.map +1 -0
- package/dist/src/planner/util/column-origins.d.ts +58 -0
- package/dist/src/planner/util/column-origins.d.ts.map +1 -0
- package/dist/src/planner/util/column-origins.js +90 -0
- package/dist/src/planner/util/column-origins.js.map +1 -0
- package/dist/src/runtime/deferred-constraint-queue.d.ts +40 -0
- package/dist/src/runtime/deferred-constraint-queue.d.ts.map +1 -1
- package/dist/src/runtime/deferred-constraint-queue.js +91 -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.map +1 -1
- package/dist/src/runtime/emit/aggregate.js +4 -69
- 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 +354 -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 +11 -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 +7 -12
- 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 +24 -25
- 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 +8 -16
- package/dist/src/runtime/emit/bloom-join.js.map +1 -1
- package/dist/src/runtime/emit/case.d.ts.map +1 -1
- package/dist/src/runtime/emit/case.js +40 -6
- package/dist/src/runtime/emit/case.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 +72 -51
- 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/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 +188 -84
- package/dist/src/runtime/emit/dml-executor.js.map +1 -1
- package/dist/src/runtime/emit/filter.d.ts +18 -0
- package/dist/src/runtime/emit/filter.d.ts.map +1 -1
- package/dist/src/runtime/emit/filter.js +52 -10
- package/dist/src/runtime/emit/filter.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-key-extractor.d.ts +46 -0
- package/dist/src/runtime/emit/join-key-extractor.d.ts.map +1 -0
- package/dist/src/runtime/emit/join-key-extractor.js +60 -0
- package/dist/src/runtime/emit/join-key-extractor.js.map +1 -0
- package/dist/src/runtime/emit/join.d.ts.map +1 -1
- package/dist/src/runtime/emit/join.js +37 -11
- package/dist/src/runtime/emit/join.js.map +1 -1
- package/dist/src/runtime/emit/key-set-semi-join.d.ts +29 -0
- package/dist/src/runtime/emit/key-set-semi-join.d.ts.map +1 -0
- package/dist/src/runtime/emit/key-set-semi-join.js +143 -0
- package/dist/src/runtime/emit/key-set-semi-join.js.map +1 -0
- 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 +33 -3
- 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 +32 -15
- package/dist/src/runtime/emit/merge-join.js.map +1 -1
- package/dist/src/runtime/emit/operand-comparator.d.ts +40 -0
- package/dist/src/runtime/emit/operand-comparator.d.ts.map +1 -0
- package/dist/src/runtime/emit/operand-comparator.js +59 -0
- package/dist/src/runtime/emit/operand-comparator.js.map +1 -0
- package/dist/src/runtime/emit/scan.d.ts.map +1 -1
- package/dist/src/runtime/emit/scan.js +11 -2
- package/dist/src/runtime/emit/scan.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 +10 -2
- package/dist/src/runtime/parallel-driver.d.ts.map +1 -1
- package/dist/src/runtime/parallel-driver.js +12 -2
- package/dist/src/runtime/parallel-driver.js.map +1 -1
- package/dist/src/runtime/register.d.ts.map +1 -1
- package/dist/src/runtime/register.js +2 -0
- package/dist/src/runtime/register.js.map +1 -1
- package/dist/src/runtime/types.d.ts +25 -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 +39 -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/builtin-types.d.ts.map +1 -1
- package/dist/src/types/builtin-types.js +30 -4
- package/dist/src/types/builtin-types.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 +114 -0
- package/dist/src/util/comparison.d.ts.map +1 -1
- package/dist/src/util/comparison.js +187 -27
- package/dist/src/util/comparison.js.map +1 -1
- package/dist/src/vtab/best-access-plan.d.ts +87 -0
- package/dist/src/vtab/best-access-plan.d.ts.map +1 -1
- package/dist/src/vtab/best-access-plan.js +87 -0
- package/dist/src/vtab/best-access-plan.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 +12 -5
- package/dist/src/vtab/memory/layer/base.d.ts.map +1 -1
- package/dist/src/vtab/memory/layer/base.js +20 -9
- 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 +156 -31
- package/dist/src/vtab/memory/layer/manager.d.ts.map +1 -1
- package/dist/src/vtab/memory/layer/manager.js +695 -158
- 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 +48 -34
- package/dist/src/vtab/memory/layer/scan-layer.js.map +1 -1
- package/dist/src/vtab/memory/layer/transaction.d.ts +142 -19
- package/dist/src/vtab/memory/layer/transaction.d.ts.map +1 -1
- package/dist/src/vtab/memory/layer/transaction.js +237 -73
- package/dist/src/vtab/memory/layer/transaction.js.map +1 -1
- package/dist/src/vtab/memory/module.d.ts +14 -2
- package/dist/src/vtab/memory/module.d.ts.map +1 -1
- package/dist/src/vtab/memory/module.js +60 -41
- package/dist/src/vtab/memory/module.js.map +1 -1
- package/dist/src/vtab/memory/table.d.ts +1 -1
- package/dist/src/vtab/memory/table.d.ts.map +1 -1
- package/dist/src/vtab/memory/table.js +12 -4
- 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 +33 -7
- 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 -26
- 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 -66
- 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,24 @@ 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);
|
|
201
|
+
// Deferred constraint checks this transaction already parked carry evaluators compiled
|
|
202
|
+
// against the OLD name — their scan leaves would connect to a table that no longer
|
|
203
|
+
// exists (or, on a store backend, to an empty one, yielding a FALSE violation). Tell
|
|
204
|
+
// the queue so it re-points those entries and moves the bucket keyed by the table name.
|
|
205
|
+
// Same placement rationale as the event relabel above.
|
|
206
|
+
rctx.db.getDeferredConstraints().notifyTableRename(tableSchema.schemaName, oldName, newName);
|
|
172
207
|
// The renamed table's own definition can name itself: a self-referencing FK's
|
|
173
208
|
// `referencedTable`, a table-qualified CHECK expression, a table-qualified
|
|
174
209
|
// partial-index predicate. Rewrite those BEFORE the catalog swap and the notify
|
|
@@ -238,6 +273,16 @@ async function runRenameColumn(rctx, tableSchema, schema, oldName, newName) {
|
|
|
238
273
|
if (oldName.toLowerCase() !== newNameLower && tableSchema.columnIndexMap.has(newNameLower)) {
|
|
239
274
|
throw new QuereusError(`Column '${newName}' already exists in table '${tableSchema.name}'`, StatusCode.ERROR);
|
|
240
275
|
}
|
|
276
|
+
// Pre-flight, BEFORE the first side effect (`module.alterTable`): the rewritten
|
|
277
|
+
// body of every dependent view / materialized view must still be persistable —
|
|
278
|
+
// same unfailable-propagation reasoning as the table-rename arm above. Shares one
|
|
279
|
+
// resolver with `propagateColumnRename` so the two passes cannot drift apart in
|
|
280
|
+
// code; what makes them agree at RUNTIME (the resolver reads the LIVE catalog, and
|
|
281
|
+
// this probe runs pre-mutation while the propagation runs post-) is that
|
|
282
|
+
// `isTableInUnaliasedScope` skips the renamed table itself and probes only OTHER
|
|
283
|
+
// sources, whose column sets this rename does not touch.
|
|
284
|
+
const resolveColumnInSource = buildColumnSourceResolver(rctx.db);
|
|
285
|
+
assertRenameDependentsPersistable(rctx.db, schema, ast => renameColumnInAst(ast, tableSchema.name, oldName, newName, tableSchema.schemaName, resolveColumnInSource));
|
|
241
286
|
const existingCol = tableSchema.columns[colIndex];
|
|
242
287
|
// Build a ColumnDef AST for the renamed column (preserving type info)
|
|
243
288
|
const newColumnDef = {
|
|
@@ -265,6 +310,12 @@ async function runRenameColumn(rctx, tableSchema, schema, oldName, newName) {
|
|
|
265
310
|
columnIndexMap: buildColumnIndexMap(updatedCols),
|
|
266
311
|
};
|
|
267
312
|
}
|
|
313
|
+
// A rename moves no value and changes no arity, so the batched events' row images are
|
|
314
|
+
// already right — but their `changedColumns` still names the OLD column. Re-derive it
|
|
315
|
+
// against the new names with an identity row map, so no delivered event names a column
|
|
316
|
+
// the table no longer has. (Modules that emit at commit from their own queue read the
|
|
317
|
+
// current schema then, so they need nothing here.)
|
|
318
|
+
await rctx.db._getEventEmitter().remapBatchedDataEvents(tableSchema.schemaName, tableSchema.name, (row) => row, updatedTableSchema.columns.map(c => c.name));
|
|
268
319
|
// Update the schema catalog
|
|
269
320
|
schema.addTable(updatedTableSchema);
|
|
270
321
|
// Snapshot pre-statement MV staleness BEFORE the notify below: the notify's
|
|
@@ -281,7 +332,7 @@ async function runRenameColumn(rctx, tableSchema, schema, oldName, newName) {
|
|
|
281
332
|
});
|
|
282
333
|
// Propagate the rename into dependent objects (CHECK / FK / partial-index
|
|
283
334
|
// predicates in this and other tables, view and materialized-view bodies).
|
|
284
|
-
await propagateColumnRename(rctx, tableSchema.schemaName, tableSchema.name, oldName, newName, preStaleMvs);
|
|
335
|
+
await propagateColumnRename(rctx, tableSchema.schemaName, tableSchema.name, oldName, newName, preStaleMvs, resolveColumnInSource);
|
|
285
336
|
log('Renamed column %s.%s.%s to %s', tableSchema.schemaName, tableSchema.name, oldName, newName);
|
|
286
337
|
return null;
|
|
287
338
|
}
|
|
@@ -299,6 +350,10 @@ async function runAddColumn(rctx, tableSchema, schema, columnDef, backfill, back
|
|
|
299
350
|
// and, when it does not fold to a literal, compiled into `backfill` — the default
|
|
300
351
|
// evaluated against the existing row, so `new.<column>` reads that row's sibling.
|
|
301
352
|
const defaultConstraint = columnDef.constraints?.find(c => c.type === 'default');
|
|
353
|
+
// Folded literal default; undefined when there is no default or it does not fold
|
|
354
|
+
// (the latter carries `backfill` instead). Used by the NOT NULL gate below and by
|
|
355
|
+
// the batched-event remap's backfill value.
|
|
356
|
+
const foldedDefault = defaultConstraint?.expr ? tryFoldLiteral(defaultConstraint.expr) : undefined;
|
|
302
357
|
// Call module.alterTable for data + schema update
|
|
303
358
|
const module = requireVtabModule(tableSchema);
|
|
304
359
|
if (!module.alterTable) {
|
|
@@ -318,19 +373,28 @@ async function runAddColumn(rctx, tableSchema, schema, columnDef, backfill, back
|
|
|
318
373
|
const delegatesBackfill = module.getCapabilities?.().delegatesNotNullBackfill === true;
|
|
319
374
|
const hasNotNull = columnDef.constraints?.some(c => c.type === 'notNull') ?? false;
|
|
320
375
|
if (hasNotNull && !delegatesBackfill && !backfill) {
|
|
321
|
-
const
|
|
322
|
-
const defaultIsNullish = !defaultConstraint?.expr || folded === null;
|
|
376
|
+
const defaultIsNullish = !defaultConstraint?.expr || foldedDefault === null;
|
|
323
377
|
if (defaultIsNullish) {
|
|
324
378
|
await validateNotNullBackfill(rctx, tableSchema, columnDef.name);
|
|
325
379
|
}
|
|
326
380
|
}
|
|
327
|
-
//
|
|
328
|
-
//
|
|
329
|
-
//
|
|
330
|
-
//
|
|
331
|
-
//
|
|
332
|
-
|
|
333
|
-
|
|
381
|
+
// Synthesize the table-level equivalent of every constraint declared inline on the new
|
|
382
|
+
// column. All three kinds go to the module via `addConstraint` below — the same path
|
|
383
|
+
// `ALTER TABLE ADD CONSTRAINT` uses — so the module owns them exactly as it owns a
|
|
384
|
+
// constraint declared in CREATE TABLE, and they survive every later structural ALTER
|
|
385
|
+
// (which installs the module's returned schema in the catalog verbatim).
|
|
386
|
+
//
|
|
387
|
+
// Extracted BEFORE the column is materialized so a malformed declaration (e.g. a
|
|
388
|
+
// multi-parent-column FK on a single ADD COLUMN) throws while the table is still
|
|
389
|
+
// untouched. Install order within the loop is UNIQUE → CHECK → FK, so a column
|
|
390
|
+
// declaring several kinds reports the cheapest-to-explain violation first; the
|
|
391
|
+
// literal-default CHECK scan runs ahead of the whole loop (see below).
|
|
392
|
+
const inlineChecks = extractColumnLevelCheckConstraints(columnDef);
|
|
393
|
+
const inlineConstraints = [
|
|
394
|
+
...extractColumnLevelUniqueConstraints(columnDef),
|
|
395
|
+
...inlineChecks,
|
|
396
|
+
...extractColumnLevelForeignKeys(columnDef),
|
|
397
|
+
];
|
|
334
398
|
// A non-foldable default backfills each existing row from its own value. Install a row
|
|
335
399
|
// slot over the default's row descriptor; the evaluator the module calls per existing
|
|
336
400
|
// row sets the slot to that row, so the default's `new.<col>` refs resolve to it.
|
|
@@ -369,185 +433,226 @@ async function runAddColumn(rctx, tableSchema, schema, columnDef, backfill, back
|
|
|
369
433
|
// scan below re-reads the table — so the backfill's context does not shadow the
|
|
370
434
|
// scan's own row context.
|
|
371
435
|
let updatedTableSchema;
|
|
436
|
+
// Slot the module actually placed the new column at (the module API permits
|
|
437
|
+
// `insertAtIndex`; SQL always appends). Recorded so the revert paths below can apply
|
|
438
|
+
// the inverse event remap.
|
|
439
|
+
let addedColIndex;
|
|
372
440
|
try {
|
|
373
441
|
updatedTableSchema = await module.alterTable(rctx.db, tableSchema.schemaName, tableSchema.name, {
|
|
374
442
|
type: 'addColumn',
|
|
375
443
|
columnDef,
|
|
376
444
|
backfillEvaluator,
|
|
377
445
|
});
|
|
446
|
+
// Events this transaction already batched for the table still describe the
|
|
447
|
+
// pre-ADD column set; insert the backfilled value at the new slot so a listener
|
|
448
|
+
// at commit pairs value i with column i of the schema current at delivery.
|
|
449
|
+
// Covers the engine auto-event path and the store module (which flushed its
|
|
450
|
+
// queued events into the batch during the ALTER); the memory module's own
|
|
451
|
+
// pending-change log is reshaped inside its alterTable. Must run INSIDE this
|
|
452
|
+
// try: the backfill evaluator closes over rowSlot/checkSlot, which the finally
|
|
453
|
+
// below closes the moment the module returns.
|
|
454
|
+
addedColIndex = updatedTableSchema.columnIndexMap.get(columnDef.name.toLowerCase());
|
|
455
|
+
if (addedColIndex !== undefined) {
|
|
456
|
+
const insertAt = addedColIndex;
|
|
457
|
+
await rctx.db._getEventEmitter().remapBatchedDataEvents(tableSchema.schemaName, tableSchema.name, async (row) => {
|
|
458
|
+
// oldRow gets the SAME map as newRow: the literal default, or the backfill
|
|
459
|
+
// evaluator applied to the pre-image itself (the evaluator is a function of
|
|
460
|
+
// a row, and the pre-image is a row), falling back to NULL — the honest
|
|
461
|
+
// "column did not exist yet" placeholder, which errs toward REPORTING a
|
|
462
|
+
// change on the new column rather than suppressing one. Rejected: reusing
|
|
463
|
+
// the newRow result for oldRow (makes oldRow[new] === newRow[new] always,
|
|
464
|
+
// so a diffing consumer never syncs the added column); suppressing the
|
|
465
|
+
// pre-ALTER oldRow (silently turns updates into upserts).
|
|
466
|
+
let value = foldedDefault ?? null;
|
|
467
|
+
if (backfillEvaluator) {
|
|
468
|
+
try {
|
|
469
|
+
value = await backfillEvaluator(row);
|
|
470
|
+
}
|
|
471
|
+
catch {
|
|
472
|
+
// Best-effort: a historical image may fail the evaluator (or its
|
|
473
|
+
// CHECKs) where every live row backfilled cleanly. Never abort
|
|
474
|
+
// the ALTER for an event image.
|
|
475
|
+
value = null;
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
return [...row.slice(0, insertAt), value, ...row.slice(insertAt)];
|
|
479
|
+
}, updatedTableSchema.columns.map(c => c.name));
|
|
480
|
+
}
|
|
378
481
|
}
|
|
379
482
|
finally {
|
|
380
483
|
rowSlot?.close();
|
|
381
484
|
checkSlot?.close();
|
|
382
485
|
}
|
|
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
|
-
}
|
|
486
|
+
// The column is materialized; now install the inline constraints. Names of the CHECK /
|
|
487
|
+
// FK ones the module has accepted so far, so a later failure can hand each back to
|
|
488
|
+
// `dropConstraint` before the column itself goes (see {@link revertAddColumn}).
|
|
489
|
+
const installedConstraintNames = [];
|
|
490
|
+
let finalTableSchema;
|
|
491
|
+
try {
|
|
492
|
+
// Recompute the generated-column dependency graph. If the added column is generated
|
|
493
|
+
// and its expression references an unknown column, or any new generated-column edges
|
|
494
|
+
// form a cycle, this throws — and the revert below undoes the materialization.
|
|
495
|
+
const columnOnlySchema = withGeneratedColumnGraph(updatedTableSchema);
|
|
496
|
+
// Register the COLUMN-ONLY schema before installing any inline constraint. Two
|
|
497
|
+
// properties depend on this ordering, and both are easy to break:
|
|
498
|
+
//
|
|
499
|
+
// - The module's FK arm validates existing rows with SQL planned against the LIVE
|
|
500
|
+
// catalog, so the new column has to resolve there. Likewise the CHECK backfill
|
|
501
|
+
// scan below.
|
|
502
|
+
// - The new constraint must NOT be live while its own validation runs. The optimizer
|
|
503
|
+
// trusts a DECLARED constraint as a proven invariant: a declared FK seeds the
|
|
504
|
+
// inclusion dependency `child.fk ⊆ parent.pk` and folds the validator's own
|
|
505
|
+
// `not exists` anti-join to EmptyRelation (`ruleAntiJoinFkEmpty`); a declared CHECK
|
|
506
|
+
// `<p>` seeds a domain constraint that folds the CHECK scan's `where not (<p>)`
|
|
507
|
+
// away (`ruleFilterContradiction`). Either fold makes validation trust the very
|
|
508
|
+
// thing it is checking and silently admit a violating row. The module holds each
|
|
509
|
+
// new constraint in its own cached schema until that constraint's validation
|
|
510
|
+
// passes, and the catalog only learns of them from `finalTableSchema` below.
|
|
511
|
+
//
|
|
512
|
+
// Pre-existing constraints stay live throughout: they held before this ALTER, so
|
|
513
|
+
// folding against them is sound and preserves the optimizer's reach.
|
|
514
|
+
schema.addTable(columnOnlySchema);
|
|
515
|
+
// Validate the backfilled values against each inline CHECK, for the literal-default
|
|
516
|
+
// path only. A per-row (evaluator) default already enforced its CHECKs inside the
|
|
517
|
+
// backfill hook above — against the freshly-computed value rather than this scan's
|
|
518
|
+
// stale pre-backfill snapshot — and the module enforces NOT NULL there too. Runs
|
|
519
|
+
// before the whole install loop below, so on a column declaring several kinds a
|
|
520
|
+
// CHECK violation is reported ahead of a UNIQUE or FK one.
|
|
521
|
+
if (!backfill && inlineChecks.length > 0) {
|
|
522
|
+
await validateBackfillAgainstChecks(rctx, columnOnlySchema, inlineChecks);
|
|
511
523
|
}
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
524
|
+
// Starts as the column-only schema so a column with no inline constraint needs no
|
|
525
|
+
// further work; each accepted constraint replaces it with the module's answer.
|
|
526
|
+
//
|
|
527
|
+
// NOTE: one module round-trip per inline constraint — each takes the module's
|
|
528
|
+
// schema-change latch and, store-backed, writes the table's DDL again. Fine at the
|
|
529
|
+
// counts SQL produces (a column declares 0 or 1 of each kind); if a batched
|
|
530
|
+
// `addConstraint` arm ever appears, or ADD COLUMN becomes hot, hand the whole set
|
|
531
|
+
// over in one call instead.
|
|
532
|
+
let current = columnOnlySchema;
|
|
533
|
+
for (const constraint of inlineConstraints) {
|
|
534
|
+
// A CHECK / FK is dropped by NAME on the revert path, so resolve the name the
|
|
535
|
+
// module will store BEFORE handing the constraint over. UNIQUE needs no entry:
|
|
536
|
+
// an unnamed one has no name to drop by, and the module's own DROP COLUMN
|
|
537
|
+
// prunes a UNIQUE over the dropped column (which CHECK / FK are not).
|
|
538
|
+
let installedName;
|
|
539
|
+
if (constraint.type === 'foreignKey') {
|
|
540
|
+
// Reject a same-rank child/parent collation conflict (which enforcement would
|
|
541
|
+
// raise at the first DML) BEFORE `module.alterTable`, so a rejected ALTER never
|
|
542
|
+
// reaches the module's persistence side effects — mirroring
|
|
543
|
+
// `runAddConstraintViaModule`. Built with the same builder and columnIndexMap
|
|
544
|
+
// the module uses, so the name and column indices are identical to its own.
|
|
545
|
+
const fk = buildForeignKeyConstraintSchema(constraint, columnOnlySchema.columnIndexMap, tableSchema.name, tableSchema.schemaName);
|
|
546
|
+
validateForeignKeyCollations(rctx.db, columnOnlySchema, fk);
|
|
547
|
+
installedName = fk.name;
|
|
519
548
|
}
|
|
520
|
-
|
|
521
|
-
|
|
549
|
+
else if (constraint.type === 'check') {
|
|
550
|
+
installedName = constraint.name; // always set by the extractor
|
|
522
551
|
}
|
|
523
|
-
|
|
524
|
-
|
|
552
|
+
// The module materializes (UNIQUE's covering structure), validates the existing
|
|
553
|
+
// rows as the kind requires (UNIQUE duplicates, pragma-gated MATCH SIMPLE FK
|
|
554
|
+
// orphans) and — store-backed — persists. Thread the returned schema forward so
|
|
555
|
+
// each constraint layers on the last. The module's answer carries no
|
|
556
|
+
// generated-column bookkeeping of its own, so re-derive it each round.
|
|
557
|
+
const withConstraint = await module.alterTable(rctx.db, tableSchema.schemaName, tableSchema.name, {
|
|
558
|
+
type: 'addConstraint',
|
|
559
|
+
constraint,
|
|
560
|
+
});
|
|
561
|
+
current = withGeneratedColumnGraph(withConstraint);
|
|
562
|
+
if (installedName !== undefined)
|
|
563
|
+
installedConstraintNames.push(installedName);
|
|
525
564
|
}
|
|
565
|
+
finalTableSchema = current;
|
|
526
566
|
}
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
if (usesIntermediateSchema) {
|
|
531
|
-
schema.addTable(enhancedTableSchema);
|
|
567
|
+
catch (err) {
|
|
568
|
+
await revertAddColumn(rctx, tableSchema, schema, columnDef.name, addedColIndex, installedConstraintNames);
|
|
569
|
+
throw err;
|
|
532
570
|
}
|
|
571
|
+
// Every constraint validated and installed — publish the module's final schema.
|
|
572
|
+
schema.addTable(finalTableSchema);
|
|
533
573
|
rctx.db.schemaManager.getChangeNotifier().notifyChange({
|
|
534
574
|
type: 'table_modified',
|
|
535
575
|
schemaName: tableSchema.schemaName,
|
|
536
576
|
objectName: tableSchema.name,
|
|
537
577
|
oldObject: tableSchema,
|
|
538
|
-
newObject:
|
|
578
|
+
newObject: finalTableSchema,
|
|
539
579
|
});
|
|
540
580
|
log('Added column %s to table %s.%s', columnDef.name, tableSchema.schemaName, tableSchema.name);
|
|
541
581
|
return null;
|
|
542
582
|
}
|
|
543
583
|
/**
|
|
544
|
-
*
|
|
545
|
-
*
|
|
584
|
+
* Undoes a partially-applied ADD COLUMN, leaving the table exactly as it was: hands each
|
|
585
|
+
* inline CHECK / FK the module already accepted back to `dropConstraint` (newest first),
|
|
586
|
+
* drops the column, un-remaps the batched events, and restores the original catalog entry.
|
|
587
|
+
*
|
|
588
|
+
* The constraints must go before the column: neither built-in module prunes a CHECK / FK
|
|
589
|
+
* over a dropped column, so a stranded one would keep naming a column the table no longer
|
|
590
|
+
* has. (An inline UNIQUE needs no explicit drop — both modules prune a UNIQUE over the
|
|
591
|
+
* dropped column, and an unnamed one has no name to drop by.)
|
|
592
|
+
*
|
|
593
|
+
* Best-effort on the module half: a revert failure is logged, never thrown, so it cannot
|
|
594
|
+
* mask the original violation. Restoring the catalog entry is a no-op when the ALTER failed
|
|
595
|
+
* before registering anything (the original schema is still the live one).
|
|
596
|
+
*
|
|
597
|
+
* NOTE: the hand-back is by NAME, so it assumes a name resolves to the constraint this
|
|
598
|
+
* ALTER installed. A pre-existing constraint can legitimately share an auto-name (nothing
|
|
599
|
+
* rejects `constraint _check_w check (…)` on a table that later gets `add column w …
|
|
600
|
+
* check (…)`; `create table` collides the same way), and today both modules' DROP
|
|
601
|
+
* CONSTRAINT removes every match, which lands on the right end state. If constraint-name
|
|
602
|
+
* resolution ever narrows to a single match, revert must instead identify the installed
|
|
603
|
+
* constraint by identity — otherwise it can drop the pre-existing one and leave ours.
|
|
604
|
+
*/
|
|
605
|
+
async function revertAddColumn(rctx, tableSchema, schema, columnName, addedColIndex, installedConstraintNames) {
|
|
606
|
+
try {
|
|
607
|
+
const module = requireVtabModule(tableSchema);
|
|
608
|
+
// Unreachable: runAddColumn requires `alterTable` before materializing anything.
|
|
609
|
+
if (!module.alterTable)
|
|
610
|
+
return;
|
|
611
|
+
for (let i = installedConstraintNames.length - 1; i >= 0; i--) {
|
|
612
|
+
await module.alterTable(rctx.db, tableSchema.schemaName, tableSchema.name, {
|
|
613
|
+
type: 'dropConstraint',
|
|
614
|
+
constraintName: installedConstraintNames[i],
|
|
615
|
+
});
|
|
616
|
+
}
|
|
617
|
+
await module.alterTable(rctx.db, tableSchema.schemaName, tableSchema.name, {
|
|
618
|
+
type: 'dropColumn',
|
|
619
|
+
columnName,
|
|
620
|
+
});
|
|
621
|
+
await remapEventsForRevertedAddColumn(rctx, tableSchema, addedColIndex);
|
|
622
|
+
}
|
|
623
|
+
catch (revertErr) {
|
|
624
|
+
log('Failed to revert ADD COLUMN %s.%s.%s: %s', tableSchema.schemaName, tableSchema.name, columnName, revertErr.message);
|
|
625
|
+
}
|
|
626
|
+
schema.addTable(tableSchema);
|
|
627
|
+
}
|
|
628
|
+
/**
|
|
629
|
+
* Inverse of {@link runAddColumn}'s batched-event remap, for its revert paths: the
|
|
630
|
+
* just-added column has been dropped from the module again, so the batched events must
|
|
631
|
+
* drop the slot too or they keep describing a column the table no longer has. No-op when
|
|
632
|
+
* the forward remap never ran (`addedColIndex` undefined). Best-effort like the forward
|
|
633
|
+
* remap — never masks the original constraint error.
|
|
634
|
+
*/
|
|
635
|
+
async function remapEventsForRevertedAddColumn(rctx, tableSchema, addedColIndex) {
|
|
636
|
+
if (addedColIndex === undefined)
|
|
637
|
+
return;
|
|
638
|
+
await rctx.db._getEventEmitter().remapBatchedDataEvents(tableSchema.schemaName, tableSchema.name, (row) => row.filter((_, i) => i !== addedColIndex), tableSchema.columns.map(c => c.name));
|
|
639
|
+
}
|
|
640
|
+
/**
|
|
641
|
+
* Runs each new CHECK against the (already-backfilled) existing rows. Relies on the
|
|
642
|
+
* just-registered column-only schema so SQL can resolve the new column while the CHECK
|
|
643
|
+
* itself is not yet declared — declaring it first would let `ruleFilterContradiction`
|
|
644
|
+
* fold this scan's own `not (<check_expr>)` to EmptyRelation. Any row matching
|
|
546
645
|
* `not (<check_expr>)` is a violation and aborts the ALTER.
|
|
547
646
|
*/
|
|
548
|
-
async function validateBackfillAgainstChecks(rctx,
|
|
549
|
-
const qualifiedTable = qualifyTableName(
|
|
647
|
+
async function validateBackfillAgainstChecks(rctx, columnOnlySchema, newCheckConstraints) {
|
|
648
|
+
const qualifiedTable = qualifyTableName(columnOnlySchema.schemaName, columnOnlySchema.name);
|
|
550
649
|
for (const cc of newCheckConstraints) {
|
|
650
|
+
// `extractColumnLevelCheckConstraints` skips an expression-less CHECK, so this
|
|
651
|
+
// cannot fire — but silently skipping a constraint we were asked to validate
|
|
652
|
+
// would admit a violating row, so say so loudly rather than `continue`.
|
|
653
|
+
if (!cc.expr) {
|
|
654
|
+
throw new QuereusError(`CHECK constraint ${cc.name ? `'${cc.name}' ` : ''}on ALTER TABLE ADD COLUMN has no expression`, StatusCode.INTERNAL);
|
|
655
|
+
}
|
|
551
656
|
const checkSql = expressionToString(cc.expr);
|
|
552
657
|
const sql = `select 1 from ${qualifiedTable} where not (${checkSql}) limit 1`;
|
|
553
658
|
const stmt = rctx.db.prepare(sql);
|
|
@@ -558,7 +663,7 @@ async function validateBackfillAgainstChecks(rctx, enhancedTableSchema, newCheck
|
|
|
558
663
|
break;
|
|
559
664
|
}
|
|
560
665
|
if (violated) {
|
|
561
|
-
throw new QuereusError(`CHECK constraint ${cc.name ? `'${cc.name}' ` : ''}violated by backfilled rows in ALTER TABLE ADD COLUMN on '${
|
|
666
|
+
throw new QuereusError(`CHECK constraint ${cc.name ? `'${cc.name}' ` : ''}violated by backfilled rows in ALTER TABLE ADD COLUMN on '${columnOnlySchema.name}'`, StatusCode.CONSTRAINT);
|
|
562
667
|
}
|
|
563
668
|
}
|
|
564
669
|
finally {
|
|
@@ -668,6 +773,13 @@ async function runDropColumn(rctx, tableSchema, schema, columnName) {
|
|
|
668
773
|
type: 'dropColumn',
|
|
669
774
|
columnName,
|
|
670
775
|
});
|
|
776
|
+
// Events this transaction already batched for the table still carry the pre-drop
|
|
777
|
+
// arity; drop the slot so a listener at commit pairs value i with column i of the
|
|
778
|
+
// schema current at delivery (and `changedColumns` never names the dropped column).
|
|
779
|
+
// Pure slot filter — no failure mode. Covers the engine auto-event path and the
|
|
780
|
+
// store module (which flushed its queued events into the batch during the ALTER);
|
|
781
|
+
// the memory module's own pending-change log is reshaped inside its alterTable.
|
|
782
|
+
await rctx.db._getEventEmitter().remapBatchedDataEvents(tableSchema.schemaName, tableSchema.name, (row) => row.filter((_, i) => i !== colIndex), updatedTableSchema.columns.map(c => c.name));
|
|
671
783
|
// Recompute the generated-column dependency graph against the post-drop
|
|
672
784
|
// column array — old indices in the previous map are invalid.
|
|
673
785
|
const finalSchema = withGeneratedColumnGraph(updatedTableSchema);
|
|
@@ -803,6 +915,16 @@ async function runAlterColumn(rctx, tableSchema, schema, action) {
|
|
|
803
915
|
if (action.setCollation !== undefined) {
|
|
804
916
|
validateCollationForType(action.setCollation, tableSchema.columns[colIndex].logicalType, action.columnName, (n) => rctx.db.isCollationRegistered(n));
|
|
805
917
|
}
|
|
918
|
+
// SET DATA TYPE: the column keeps its current collation, so the NEW type has to accept it —
|
|
919
|
+
// otherwise the ALTER mints a column shape CREATE TABLE would refuse and generateTableDDL
|
|
920
|
+
// cannot round-trip (a store-backed table with such a column is silently dropped on rehydrate).
|
|
921
|
+
// Same validator, same error text as CREATE TABLE / SET COLLATE. Rejects uniformly whether the
|
|
922
|
+
// collation was user-declared or inherited from `pragma default_collation`: `collationExplicit`
|
|
923
|
+
// is not persisted, so keying on it would coerce before a reopen and reject after one.
|
|
924
|
+
// Remedy: `SET COLLATE binary` first, then retype.
|
|
925
|
+
if (action.setDataType !== undefined) {
|
|
926
|
+
validateCollationForType(tableSchema.columns[colIndex].collation, inferType(action.setDataType), action.columnName, (n) => rctx.db.isCollationRegistered(n));
|
|
927
|
+
}
|
|
806
928
|
// Route a SET DEFAULT through the same DDL validator CREATE TABLE uses, so the
|
|
807
929
|
// stored default is consistent with what INSERT will accept: bind params / bare
|
|
808
930
|
// columns / non-determinism rejected, `new.<column>` accepted (deferred to INSERT
|
|
@@ -823,6 +945,18 @@ async function runAlterColumn(rctx, tableSchema, schema, action) {
|
|
|
823
945
|
setDefault: action.setDefault,
|
|
824
946
|
setCollation: action.setCollation,
|
|
825
947
|
});
|
|
948
|
+
// Events this transaction already batched still carry the PRE-conversion value at
|
|
949
|
+
// the altered column (`SET DATA TYPE`'s normalization, `SET NOT NULL`'s null →
|
|
950
|
+
// DEFAULT backfill); rewrite it so a listener at commit sees the value the
|
|
951
|
+
// committed row holds. The conversion is engine-derivable (the same
|
|
952
|
+
// `validateAndParse` the memory module's converter wraps), so no module-contract
|
|
953
|
+
// change. `SET COLLATE` / `SET DEFAULT` / `DROP NOT NULL` move no stored value and
|
|
954
|
+
// need no remap — in particular the primary-key `SET COLLATE` re-key leaves every
|
|
955
|
+
// event's key and row images valid as-is.
|
|
956
|
+
const eventValueRemap = alterColumnEventValueRemap(tableSchema, colIndex, action);
|
|
957
|
+
if (eventValueRemap) {
|
|
958
|
+
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));
|
|
959
|
+
}
|
|
826
960
|
schema.addTable(updatedTableSchema);
|
|
827
961
|
rctx.db.schemaManager.getChangeNotifier().notifyChange({
|
|
828
962
|
type: 'table_modified',
|
|
@@ -834,6 +968,51 @@ async function runAlterColumn(rctx, tableSchema, schema, action) {
|
|
|
834
968
|
log('Altered column %s.%s.%s', tableSchema.schemaName, tableSchema.name, action.columnName);
|
|
835
969
|
return null;
|
|
836
970
|
}
|
|
971
|
+
/**
|
|
972
|
+
* The per-value map {@link runAlterColumn}'s batched-event remap applies at the altered
|
|
973
|
+
* column, or undefined when the ALTER moves no stored value (SET COLLATE, SET DEFAULT,
|
|
974
|
+
* DROP NOT NULL, an alias retype). The returned function is TOTAL — an unconvertible
|
|
975
|
+
* historical event image keeps its raw value rather than aborting the ALTER; the module
|
|
976
|
+
* already validated every value the transaction can actually SEE, so a failure here is
|
|
977
|
+
* confined to a superseded intermediate image.
|
|
978
|
+
*/
|
|
979
|
+
function alterColumnEventValueRemap(tableSchema, colIndex, action) {
|
|
980
|
+
if (action.setDataType !== undefined) {
|
|
981
|
+
const newLogicalType = inferType(action.setDataType);
|
|
982
|
+
// Alias retype (`varchar(50)` IS TEXT): schema-only, values untouched.
|
|
983
|
+
if (newLogicalType === tableSchema.columns[colIndex].logicalType)
|
|
984
|
+
return undefined;
|
|
985
|
+
const columnName = tableSchema.columns[colIndex].name;
|
|
986
|
+
return (v) => {
|
|
987
|
+
if (v === null)
|
|
988
|
+
return v; // retype leaves NULLs untouched, matching the module's conversion
|
|
989
|
+
try {
|
|
990
|
+
return validateAndParse(v, newLogicalType, columnName);
|
|
991
|
+
}
|
|
992
|
+
catch {
|
|
993
|
+
// NOTE: the surviving raw value is honest about what the row held, but its
|
|
994
|
+
// JS type no longer matches the column's logical type — the delivered
|
|
995
|
+
// contract is positional (value i belongs to column i), not typed. Only
|
|
996
|
+
// reachable for a superseded intermediate image (e.g. insert 'zzz' →
|
|
997
|
+
// update to '42' → retype to integer delivers oldRow ['zzz']). If a
|
|
998
|
+
// consumer ever type-validates delivered images, revisit: the options are
|
|
999
|
+
// NULL (loses the value) or dropping the image (loses the event).
|
|
1000
|
+
return v;
|
|
1001
|
+
}
|
|
1002
|
+
};
|
|
1003
|
+
}
|
|
1004
|
+
if (action.setNotNull === true) {
|
|
1005
|
+
// SET NOT NULL backfill: null → the folded literal DEFAULT, the same map the
|
|
1006
|
+
// module applies. No usable literal default means the module either found no
|
|
1007
|
+
// NULLs (nothing to remap) or rejected the ALTER before reaching here.
|
|
1008
|
+
const defaultExpr = tableSchema.columns[colIndex].defaultValue;
|
|
1009
|
+
const folded = defaultExpr ? tryFoldLiteral(defaultExpr) : undefined;
|
|
1010
|
+
if (folded === undefined || folded === null)
|
|
1011
|
+
return undefined;
|
|
1012
|
+
return (v) => (v === null ? folded : v);
|
|
1013
|
+
}
|
|
1014
|
+
return undefined;
|
|
1015
|
+
}
|
|
837
1016
|
/**
|
|
838
1017
|
* Catalog-only metadata-tag mutations. Tags touch no stored row and no physical
|
|
839
1018
|
* layout, so these never call `module.alterTable` — they delegate to the
|
|
@@ -1295,13 +1474,23 @@ function rewriteTableForTableRename(table, renamedSchemaLower, oldName, newName)
|
|
|
1295
1474
|
indexes: table.indexes ? Object.freeze(newIndexes) : table.indexes,
|
|
1296
1475
|
});
|
|
1297
1476
|
}
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1477
|
+
/**
|
|
1478
|
+
* The catalog-backed {@link ResolveColumnInSource} the column-rename rewriters consult
|
|
1479
|
+
* to keep their unqualified-reference walk scope-aware. Built once per statement and
|
|
1480
|
+
* shared by the pre-flight probe in {@link runRenameColumn} and the real propagation
|
|
1481
|
+
* below, so the two cannot drift apart. Note it resolves against the LIVE catalog on
|
|
1482
|
+
* every call, so sharing it does not by itself freeze the answer between the two passes
|
|
1483
|
+
* — see the pre-flight's comment for why they agree anyway.
|
|
1484
|
+
*/
|
|
1485
|
+
function buildColumnSourceResolver(db) {
|
|
1486
|
+
return (s, t, col) => {
|
|
1487
|
+
const targetSchema = db.schemaManager.getSchema(s);
|
|
1302
1488
|
const targetTable = targetSchema?.getTable(t);
|
|
1303
1489
|
return targetTable?.columnIndexMap.has(col.toLowerCase()) ?? false;
|
|
1304
1490
|
};
|
|
1491
|
+
}
|
|
1492
|
+
async function propagateColumnRename(rctx, renamedSchemaName, tableName, oldCol, newCol, preStaleMvs, resolveColumnInSource) {
|
|
1493
|
+
const schemaManager = rctx.db.schemaManager;
|
|
1305
1494
|
for (const schema of schemaManager._getAllSchemas()) {
|
|
1306
1495
|
await propagateColumnRenameInSchema(rctx.db, schema, renamedSchemaName, tableName, oldCol, newCol, resolveColumnInSource, preStaleMvs);
|
|
1307
1496
|
}
|