@quereus/quereus 4.4.1 → 4.6.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 +5 -4
- package/dist/src/core/database-events.d.ts +99 -1
- package/dist/src/core/database-events.d.ts.map +1 -1
- package/dist/src/core/database-events.js +219 -3
- 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.map +1 -1
- package/dist/src/core/database-materialized-views-plan-builders.js +29 -2
- package/dist/src/core/database-materialized-views-plan-builders.js.map +1 -1
- package/dist/src/core/database-transaction.d.ts +9 -0
- package/dist/src/core/database-transaction.d.ts.map +1 -1
- package/dist/src/core/database-transaction.js +9 -0
- package/dist/src/core/database-transaction.js.map +1 -1
- package/dist/src/core/database.d.ts +7 -1
- package/dist/src/core/database.d.ts.map +1 -1
- package/dist/src/core/database.js +20 -5
- package/dist/src/core/database.js.map +1 -1
- package/dist/src/func/builtins/aggregate.js +11 -11
- 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 +15 -85
- package/dist/src/func/builtins/builtin-window-functions.js.map +1 -1
- package/dist/src/func/builtins/conversion.d.ts.map +1 -1
- package/dist/src/func/builtins/conversion.js +10 -9
- package/dist/src/func/builtins/conversion.js.map +1 -1
- package/dist/src/func/builtins/datetime.d.ts.map +1 -1
- package/dist/src/func/builtins/datetime.js +28 -10
- package/dist/src/func/builtins/datetime.js.map +1 -1
- package/dist/src/func/builtins/json.d.ts.map +1 -1
- package/dist/src/func/builtins/json.js +23 -17
- package/dist/src/func/builtins/json.js.map +1 -1
- package/dist/src/func/builtins/mutation.js +2 -2
- package/dist/src/func/builtins/mutation.js.map +1 -1
- package/dist/src/func/builtins/return-types.d.ts +327 -0
- package/dist/src/func/builtins/return-types.d.ts.map +1 -0
- package/dist/src/func/builtins/return-types.js +43 -0
- package/dist/src/func/builtins/return-types.js.map +1 -0
- package/dist/src/func/builtins/scalar.d.ts.map +1 -1
- package/dist/src/func/builtins/scalar.js +193 -37
- package/dist/src/func/builtins/scalar.js.map +1 -1
- package/dist/src/func/builtins/schema.d.ts.map +1 -1
- package/dist/src/func/builtins/schema.js +11 -3
- package/dist/src/func/builtins/schema.js.map +1 -1
- package/dist/src/func/builtins/string.d.ts.map +1 -1
- package/dist/src/func/builtins/string.js +4 -2
- package/dist/src/func/builtins/string.js.map +1 -1
- package/dist/src/func/builtins/timespan.d.ts +3 -0
- package/dist/src/func/builtins/timespan.d.ts.map +1 -1
- package/dist/src/func/builtins/timespan.js +15 -11
- package/dist/src/func/builtins/timespan.js.map +1 -1
- package/dist/src/func/registration.d.ts +39 -1
- package/dist/src/func/registration.d.ts.map +1 -1
- package/dist/src/func/registration.js +236 -41
- package/dist/src/func/registration.js.map +1 -1
- package/dist/src/index.d.ts +14 -7
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +14 -5
- package/dist/src/index.js.map +1 -1
- package/dist/src/parser/parser.d.ts +46 -0
- package/dist/src/parser/parser.d.ts.map +1 -1
- package/dist/src/parser/parser.js +160 -44
- package/dist/src/parser/parser.js.map +1 -1
- package/dist/src/planner/analysis/check-extraction.d.ts.map +1 -1
- package/dist/src/planner/analysis/check-extraction.js +37 -4
- package/dist/src/planner/analysis/check-extraction.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 +41 -13
- package/dist/src/planner/analysis/comparison-collation.d.ts.map +1 -1
- package/dist/src/planner/analysis/comparison-collation.js +51 -14
- package/dist/src/planner/analysis/comparison-collation.js.map +1 -1
- package/dist/src/planner/analysis/constraint-extractor.d.ts +0 -7
- package/dist/src/planner/analysis/constraint-extractor.d.ts.map +1 -1
- package/dist/src/planner/analysis/constraint-extractor.js +59 -59
- package/dist/src/planner/analysis/constraint-extractor.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/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.map +1 -1
- package/dist/src/planner/analysis/query-rewrite-matcher.js +8 -27
- package/dist/src/planner/analysis/query-rewrite-matcher.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/alter-table.d.ts.map +1 -1
- package/dist/src/planner/building/alter-table.js +65 -27
- package/dist/src/planner/building/alter-table.js.map +1 -1
- package/dist/src/planner/building/coercion.d.ts +54 -0
- package/dist/src/planner/building/coercion.d.ts.map +1 -0
- package/dist/src/planner/building/coercion.js +88 -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/expression.d.ts +17 -0
- package/dist/src/planner/building/expression.d.ts.map +1 -1
- package/dist/src/planner/building/expression.js +23 -115
- package/dist/src/planner/building/expression.js.map +1 -1
- package/dist/src/planner/building/function-call.d.ts.map +1 -1
- package/dist/src/planner/building/function-call.js +13 -0
- package/dist/src/planner/building/function-call.js.map +1 -1
- package/dist/src/planner/building/select-aggregates.d.ts +1 -1
- package/dist/src/planner/building/select-aggregates.d.ts.map +1 -1
- package/dist/src/planner/building/select-aggregates.js +53 -2
- package/dist/src/planner/building/select-aggregates.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/select-context.d.ts +7 -0
- package/dist/src/planner/building/select-context.d.ts.map +1 -1
- package/dist/src/planner/building/select-context.js +10 -40
- package/dist/src/planner/building/select-context.js.map +1 -1
- package/dist/src/planner/building/select.d.ts +37 -1
- package/dist/src/planner/building/select.d.ts.map +1 -1
- package/dist/src/planner/building/select.js +112 -51
- package/dist/src/planner/building/select.js.map +1 -1
- package/dist/src/planner/cost/conjunct-cost.d.ts +82 -0
- package/dist/src/planner/cost/conjunct-cost.d.ts.map +1 -0
- package/dist/src/planner/cost/conjunct-cost.js +107 -0
- package/dist/src/planner/cost/conjunct-cost.js.map +1 -0
- package/dist/src/planner/cost/index.d.ts +10 -0
- package/dist/src/planner/cost/index.d.ts.map +1 -1
- package/dist/src/planner/cost/index.js +15 -0
- package/dist/src/planner/cost/index.js.map +1 -1
- 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/aggregate-node.d.ts +6 -0
- package/dist/src/planner/nodes/aggregate-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/aggregate-node.js +10 -2
- package/dist/src/planner/nodes/aggregate-node.js.map +1 -1
- package/dist/src/planner/nodes/alias-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/alias-node.js +2 -1
- package/dist/src/planner/nodes/alias-node.js.map +1 -1
- package/dist/src/planner/nodes/alter-table-node.d.ts +24 -8
- package/dist/src/planner/nodes/alter-table-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/alter-table-node.js.map +1 -1
- package/dist/src/planner/nodes/asof-scan-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/asof-scan-node.js +4 -1
- package/dist/src/planner/nodes/asof-scan-node.js.map +1 -1
- package/dist/src/planner/nodes/asserted-keys-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/asserted-keys-node.js +2 -1
- package/dist/src/planner/nodes/asserted-keys-node.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 +17 -7
- package/dist/src/planner/nodes/bloom-join-node.js.map +1 -1
- package/dist/src/planner/nodes/cache-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/cache-node.js +2 -1
- package/dist/src/planner/nodes/cache-node.js.map +1 -1
- package/dist/src/planner/nodes/distinct-node.d.ts +6 -0
- package/dist/src/planner/nodes/distinct-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/distinct-node.js +10 -2
- package/dist/src/planner/nodes/distinct-node.js.map +1 -1
- package/dist/src/planner/nodes/eager-prefetch-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/eager-prefetch-node.js +2 -1
- package/dist/src/planner/nodes/eager-prefetch-node.js.map +1 -1
- package/dist/src/planner/nodes/fanout-lookup-join-node.d.ts +5 -0
- package/dist/src/planner/nodes/fanout-lookup-join-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/fanout-lookup-join-node.js +13 -6
- package/dist/src/planner/nodes/fanout-lookup-join-node.js.map +1 -1
- package/dist/src/planner/nodes/filter.d.ts.map +1 -1
- package/dist/src/planner/nodes/filter.js +12 -5
- package/dist/src/planner/nodes/filter.js.map +1 -1
- package/dist/src/planner/nodes/hash-aggregate.d.ts +6 -0
- package/dist/src/planner/nodes/hash-aggregate.d.ts.map +1 -1
- package/dist/src/planner/nodes/hash-aggregate.js +10 -2
- package/dist/src/planner/nodes/hash-aggregate.js.map +1 -1
- package/dist/src/planner/nodes/join-node.d.ts +25 -1
- package/dist/src/planner/nodes/join-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/join-node.js +38 -10
- package/dist/src/planner/nodes/join-node.js.map +1 -1
- package/dist/src/planner/nodes/join-utils.d.ts +78 -0
- package/dist/src/planner/nodes/join-utils.d.ts.map +1 -1
- package/dist/src/planner/nodes/join-utils.js +73 -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 +141 -0
- package/dist/src/planner/nodes/key-set-semi-join-node.js.map +1 -0
- package/dist/src/planner/nodes/lens-auxiliary-access-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/lens-auxiliary-access-node.js +2 -1
- package/dist/src/planner/nodes/lens-auxiliary-access-node.js.map +1 -1
- package/dist/src/planner/nodes/limit-offset.d.ts +6 -0
- package/dist/src/planner/nodes/limit-offset.d.ts.map +1 -1
- package/dist/src/planner/nodes/limit-offset.js +10 -2
- package/dist/src/planner/nodes/limit-offset.js.map +1 -1
- 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 +21 -8
- package/dist/src/planner/nodes/merge-join-node.js.map +1 -1
- package/dist/src/planner/nodes/ordinal-slice-node.d.ts +5 -0
- package/dist/src/planner/nodes/ordinal-slice-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/ordinal-slice-node.js +9 -2
- package/dist/src/planner/nodes/ordinal-slice-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/plan-node.d.ts +24 -0
- package/dist/src/planner/nodes/plan-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/plan-node.js.map +1 -1
- package/dist/src/planner/nodes/project-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/project-node.js +2 -1
- package/dist/src/planner/nodes/project-node.js.map +1 -1
- package/dist/src/planner/nodes/reference.d.ts.map +1 -1
- package/dist/src/planner/nodes/reference.js +3 -2
- package/dist/src/planner/nodes/reference.js.map +1 -1
- package/dist/src/planner/nodes/retrieve-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/retrieve-node.js +2 -1
- package/dist/src/planner/nodes/retrieve-node.js.map +1 -1
- package/dist/src/planner/nodes/scalar.d.ts.map +1 -1
- package/dist/src/planner/nodes/scalar.js +5 -18
- 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/sort.d.ts.map +1 -1
- package/dist/src/planner/nodes/sort.js +3 -1
- package/dist/src/planner/nodes/sort.js.map +1 -1
- package/dist/src/planner/nodes/stream-aggregate.d.ts +6 -0
- package/dist/src/planner/nodes/stream-aggregate.d.ts.map +1 -1
- package/dist/src/planner/nodes/stream-aggregate.js +10 -2
- package/dist/src/planner/nodes/stream-aggregate.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 +18 -2
- package/dist/src/planner/nodes/table-access-nodes.js.map +1 -1
- package/dist/src/planner/nodes/window-function.d.ts.map +1 -1
- package/dist/src/planner/nodes/window-function.js +8 -0
- package/dist/src/planner/nodes/window-function.js.map +1 -1
- package/dist/src/planner/nodes/window-node.d.ts +1 -1
- package/dist/src/planner/nodes/window-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/window-node.js +3 -1
- package/dist/src/planner/nodes/window-node.js.map +1 -1
- package/dist/src/planner/optimizer.d.ts +9 -1
- package/dist/src/planner/optimizer.d.ts.map +1 -1
- package/dist/src/planner/optimizer.js +126 -6
- 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 +343 -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 +46 -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 +54 -13
- 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 +9 -0
- package/dist/src/planner/rules/cache/rule-cte-optimization.js.map +1 -1
- package/dist/src/planner/rules/cache/rule-nested-loop-right-cache.d.ts.map +1 -1
- package/dist/src/planner/rules/cache/rule-nested-loop-right-cache.js +6 -4
- package/dist/src/planner/rules/cache/rule-nested-loop-right-cache.js.map +1 -1
- package/dist/src/planner/rules/join/equi-pair-extractor.d.ts +49 -49
- package/dist/src/planner/rules/join/equi-pair-extractor.d.ts.map +1 -1
- package/dist/src/planner/rules/join/equi-pair-extractor.js +54 -58
- package/dist/src/planner/rules/join/equi-pair-extractor.js.map +1 -1
- package/dist/src/planner/rules/join/index-nested-loop.d.ts +49 -0
- package/dist/src/planner/rules/join/index-nested-loop.d.ts.map +1 -0
- package/dist/src/planner/rules/join/index-nested-loop.js +285 -0
- package/dist/src/planner/rules/join/index-nested-loop.js.map +1 -0
- package/dist/src/planner/rules/join/rule-fanout-batched-outer.js +8 -8
- package/dist/src/planner/rules/join/rule-join-physical-selection.d.ts +10 -4
- 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 +97 -29
- 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 +15 -5
- 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 +43 -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 +119 -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 +44 -3
- package/dist/src/planner/rules/predicate/rule-filter-selectivity.d.ts.map +1 -1
- package/dist/src/planner/rules/predicate/rule-filter-selectivity.js +142 -18
- package/dist/src/planner/rules/predicate/rule-filter-selectivity.js.map +1 -1
- package/dist/src/planner/rules/predicate/rule-join-predicate-pushdown.d.ts +73 -0
- package/dist/src/planner/rules/predicate/rule-join-predicate-pushdown.d.ts.map +1 -0
- package/dist/src/planner/rules/predicate/rule-join-predicate-pushdown.js +205 -0
- package/dist/src/planner/rules/predicate/rule-join-predicate-pushdown.js.map +1 -0
- package/dist/src/planner/rules/predicate/rule-predicate-inference-equivalence.d.ts +14 -11
- package/dist/src/planner/rules/predicate/rule-predicate-inference-equivalence.d.ts.map +1 -1
- package/dist/src/planner/rules/predicate/rule-predicate-inference-equivalence.js +21 -85
- 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 +10 -2
- package/dist/src/planner/rules/predicate/rule-predicate-pushdown.d.ts.map +1 -1
- package/dist/src/planner/rules/predicate/rule-predicate-pushdown.js +20 -2
- 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/access-leaf.d.ts +39 -0
- package/dist/src/planner/rules/shared/access-leaf.d.ts.map +1 -0
- package/dist/src/planner/rules/shared/access-leaf.js +79 -0
- package/dist/src/planner/rules/shared/access-leaf.js.map +1 -0
- 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-anti-join-fk-empty.d.ts.map +1 -1
- package/dist/src/planner/rules/subquery/rule-anti-join-fk-empty.js +18 -8
- package/dist/src/planner/rules/subquery/rule-anti-join-fk-empty.js.map +1 -1
- package/dist/src/planner/rules/subquery/rule-semi-join-fk-trivial.d.ts +3 -1
- package/dist/src/planner/rules/subquery/rule-semi-join-fk-trivial.d.ts.map +1 -1
- package/dist/src/planner/rules/subquery/rule-semi-join-fk-trivial.js +27 -10
- package/dist/src/planner/rules/subquery/rule-semi-join-fk-trivial.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 +243 -70
- package/dist/src/planner/rules/subquery/rule-subquery-decorrelation.js.map +1 -1
- package/dist/src/planner/rules/window/rule-monotonic-window.d.ts +17 -7
- package/dist/src/planner/rules/window/rule-monotonic-window.d.ts.map +1 -1
- package/dist/src/planner/rules/window/rule-monotonic-window.js +124 -87
- package/dist/src/planner/rules/window/rule-monotonic-window.js.map +1 -1
- package/dist/src/planner/scopes/aliased.d.ts.map +1 -1
- package/dist/src/planner/scopes/aliased.js +6 -0
- package/dist/src/planner/scopes/aliased.js.map +1 -1
- package/dist/src/planner/stats/catalog-stats.d.ts +87 -4
- package/dist/src/planner/stats/catalog-stats.d.ts.map +1 -1
- package/dist/src/planner/stats/catalog-stats.js +250 -28
- package/dist/src/planner/stats/catalog-stats.js.map +1 -1
- package/dist/src/planner/stats/conjunct-selectivity.d.ts +48 -0
- package/dist/src/planner/stats/conjunct-selectivity.d.ts.map +1 -0
- package/dist/src/planner/stats/conjunct-selectivity.js +168 -0
- package/dist/src/planner/stats/conjunct-selectivity.js.map +1 -0
- package/dist/src/planner/stats/index.d.ts +36 -2
- 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/stats/table-cardinality.d.ts +28 -0
- package/dist/src/planner/stats/table-cardinality.d.ts.map +1 -0
- package/dist/src/planner/stats/table-cardinality.js +29 -0
- package/dist/src/planner/stats/table-cardinality.js.map +1 -0
- package/dist/src/planner/util/column-origins.d.ts +79 -0
- package/dist/src/planner/util/column-origins.d.ts.map +1 -0
- package/dist/src/planner/util/column-origins.js +150 -0
- package/dist/src/planner/util/column-origins.js.map +1 -0
- package/dist/src/planner/util/fd-utils.d.ts +32 -8
- package/dist/src/planner/util/fd-utils.d.ts.map +1 -1
- package/dist/src/planner/util/fd-utils.js +46 -9
- package/dist/src/planner/util/fd-utils.js.map +1 -1
- package/dist/src/planner/util/ind-utils.d.ts +56 -17
- package/dist/src/planner/util/ind-utils.d.ts.map +1 -1
- package/dist/src/planner/util/ind-utils.js +82 -21
- package/dist/src/planner/util/ind-utils.js.map +1 -1
- package/dist/src/planner/util/key-utils.d.ts +20 -2
- package/dist/src/planner/util/key-utils.d.ts.map +1 -1
- package/dist/src/planner/util/key-utils.js +37 -3
- package/dist/src/planner/util/key-utils.js.map +1 -1
- package/dist/src/planner/util/row-estimates.d.ts +28 -0
- package/dist/src/planner/util/row-estimates.d.ts.map +1 -0
- package/dist/src/planner/util/row-estimates.js +40 -0
- package/dist/src/planner/util/row-estimates.js.map +1 -0
- package/dist/src/planner/util/row-population.d.ts +42 -0
- package/dist/src/planner/util/row-population.d.ts.map +1 -0
- package/dist/src/planner/util/row-population.js +71 -0
- package/dist/src/planner/util/row-population.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 +90 -9
- package/dist/src/runtime/deferred-constraint-queue.js.map +1 -1
- package/dist/src/runtime/emit/add-constraint.d.ts.map +1 -1
- package/dist/src/runtime/emit/add-constraint.js +39 -1
- package/dist/src/runtime/emit/add-constraint.js.map +1 -1
- package/dist/src/runtime/emit/aggregate.d.ts.map +1 -1
- package/dist/src/runtime/emit/aggregate.js +4 -4
- package/dist/src/runtime/emit/aggregate.js.map +1 -1
- package/dist/src/runtime/emit/alter-schema-event.d.ts +42 -0
- package/dist/src/runtime/emit/alter-schema-event.d.ts.map +1 -0
- package/dist/src/runtime/emit/alter-schema-event.js +28 -0
- package/dist/src/runtime/emit/alter-schema-event.js.map +1 -0
- package/dist/src/runtime/emit/alter-table.d.ts.map +1 -1
- package/dist/src/runtime/emit/alter-table.js +386 -154
- package/dist/src/runtime/emit/alter-table.js.map +1 -1
- package/dist/src/runtime/emit/analyze.d.ts.map +1 -1
- package/dist/src/runtime/emit/analyze.js +35 -3
- package/dist/src/runtime/emit/analyze.js.map +1 -1
- package/dist/src/runtime/emit/asof-scan.d.ts.map +1 -1
- package/dist/src/runtime/emit/asof-scan.js +8 -3
- 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 +4 -38
- 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 +2 -23
- 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 +6 -35
- 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 +4 -19
- 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 +32 -8
- package/dist/src/runtime/emit/constraint-check.js.map +1 -1
- package/dist/src/runtime/emit/dml-executor.d.ts.map +1 -1
- package/dist/src/runtime/emit/dml-executor.js +90 -50
- package/dist/src/runtime/emit/dml-executor.js.map +1 -1
- package/dist/src/runtime/emit/drop-index.d.ts.map +1 -1
- package/dist/src/runtime/emit/drop-index.js +4 -3
- package/dist/src/runtime/emit/drop-index.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 +2 -2
- package/dist/src/runtime/emit/hash-aggregate.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 +8 -46
- 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 +149 -0
- package/dist/src/runtime/emit/key-set-semi-join.js.map +1 -0
- package/dist/src/runtime/emit/merge-join.d.ts.map +1 -1
- package/dist/src/runtime/emit/merge-join.js +15 -8
- package/dist/src/runtime/emit/merge-join.js.map +1 -1
- package/dist/src/runtime/emit/operand-comparator.d.ts +70 -0
- package/dist/src/runtime/emit/operand-comparator.d.ts.map +1 -0
- package/dist/src/runtime/emit/operand-comparator.js +93 -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/schema-declarative.d.ts.map +1 -1
- package/dist/src/runtime/emit/schema-declarative.js +30 -0
- package/dist/src/runtime/emit/schema-declarative.js.map +1 -1
- package/dist/src/runtime/emit/subquery.d.ts.map +1 -1
- package/dist/src/runtime/emit/subquery.js +153 -52
- package/dist/src/runtime/emit/subquery.js.map +1 -1
- package/dist/src/runtime/emit/window.js +36 -23
- package/dist/src/runtime/emit/window.js.map +1 -1
- package/dist/src/runtime/parallel-driver.d.ts +5 -2
- package/dist/src/runtime/parallel-driver.d.ts.map +1 -1
- package/dist/src/runtime/parallel-driver.js +6 -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 +7 -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 +19 -16
- package/dist/src/schema/catalog-persistability.d.ts.map +1 -1
- package/dist/src/schema/catalog-persistability.js +76 -20
- package/dist/src/schema/catalog-persistability.js.map +1 -1
- package/dist/src/schema/catalog.d.ts +67 -2
- package/dist/src/schema/catalog.d.ts.map +1 -1
- package/dist/src/schema/catalog.js +194 -3
- package/dist/src/schema/catalog.js.map +1 -1
- package/dist/src/schema/column.d.ts +26 -3
- package/dist/src/schema/column.d.ts.map +1 -1
- package/dist/src/schema/column.js.map +1 -1
- package/dist/src/schema/ddl-generator.d.ts.map +1 -1
- package/dist/src/schema/ddl-generator.js +19 -6
- package/dist/src/schema/ddl-generator.js.map +1 -1
- package/dist/src/schema/function.d.ts +40 -0
- package/dist/src/schema/function.d.ts.map +1 -1
- package/dist/src/schema/function.js +10 -2
- package/dist/src/schema/function.js.map +1 -1
- package/dist/src/schema/manager.d.ts +84 -7
- package/dist/src/schema/manager.d.ts.map +1 -1
- package/dist/src/schema/manager.js +153 -53
- 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 +104 -28
- package/dist/src/schema/schema-differ.js.map +1 -1
- package/dist/src/schema/table.d.ts +149 -1
- package/dist/src/schema/table.d.ts.map +1 -1
- package/dist/src/schema/table.js +248 -1
- package/dist/src/schema/table.js.map +1 -1
- package/dist/src/schema/unique-enforcement.d.ts +5 -3
- package/dist/src/schema/unique-enforcement.d.ts.map +1 -1
- package/dist/src/schema/unique-enforcement.js +5 -3
- package/dist/src/schema/unique-enforcement.js.map +1 -1
- package/dist/src/types/builtin-types.d.ts +16 -0
- package/dist/src/types/builtin-types.d.ts.map +1 -1
- package/dist/src/types/builtin-types.js +76 -12
- package/dist/src/types/builtin-types.js.map +1 -1
- package/dist/src/types/cast-semantics.d.ts +42 -0
- package/dist/src/types/cast-semantics.d.ts.map +1 -1
- package/dist/src/types/cast-semantics.js +64 -0
- package/dist/src/types/cast-semantics.js.map +1 -1
- package/dist/src/types/comparison-coercion.d.ts +101 -0
- package/dist/src/types/comparison-coercion.d.ts.map +1 -0
- package/dist/src/types/comparison-coercion.js +162 -0
- package/dist/src/types/comparison-coercion.js.map +1 -0
- package/dist/src/types/index.d.ts +2 -2
- package/dist/src/types/index.d.ts.map +1 -1
- package/dist/src/types/index.js +2 -2
- package/dist/src/types/index.js.map +1 -1
- package/dist/src/types/logical-type.d.ts +7 -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/validation.d.ts +56 -0
- package/dist/src/types/validation.d.ts.map +1 -1
- package/dist/src/types/validation.js +68 -0
- package/dist/src/types/validation.js.map +1 -1
- package/dist/src/util/coercion.d.ts +8 -0
- package/dist/src/util/coercion.d.ts.map +1 -1
- package/dist/src/util/coercion.js +8 -0
- package/dist/src/util/coercion.js.map +1 -1
- package/dist/src/util/comparison.d.ts +41 -3
- package/dist/src/util/comparison.d.ts.map +1 -1
- package/dist/src/util/comparison.js +52 -5
- package/dist/src/util/comparison.js.map +1 -1
- package/dist/src/util/key-serializer.d.ts +46 -0
- package/dist/src/util/key-serializer.d.ts.map +1 -1
- package/dist/src/util/key-serializer.js +47 -0
- package/dist/src/util/key-serializer.js.map +1 -1
- package/dist/src/util/value-set.d.ts +21 -0
- package/dist/src/util/value-set.d.ts.map +1 -0
- package/dist/src/util/value-set.js +22 -0
- package/dist/src/util/value-set.js.map +1 -0
- 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/capabilities.d.ts +1 -1
- package/dist/src/vtab/events.d.ts +5 -1
- package/dist/src/vtab/events.d.ts.map +1 -1
- package/dist/src/vtab/events.js.map +1 -1
- package/dist/src/vtab/memory/layer/alter-column.d.ts +147 -0
- package/dist/src/vtab/memory/layer/alter-column.d.ts.map +1 -0
- package/dist/src/vtab/memory/layer/alter-column.js +214 -0
- package/dist/src/vtab/memory/layer/alter-column.js.map +1 -0
- package/dist/src/vtab/memory/layer/base.d.ts +6 -4
- package/dist/src/vtab/memory/layer/base.d.ts.map +1 -1
- package/dist/src/vtab/memory/layer/base.js +10 -7
- package/dist/src/vtab/memory/layer/base.js.map +1 -1
- package/dist/src/vtab/memory/layer/interface.d.ts +2 -2
- package/dist/src/vtab/memory/layer/interface.d.ts.map +1 -1
- package/dist/src/vtab/memory/layer/manager.d.ts +232 -39
- package/dist/src/vtab/memory/layer/manager.d.ts.map +1 -1
- package/dist/src/vtab/memory/layer/manager.js +657 -519
- package/dist/src/vtab/memory/layer/manager.js.map +1 -1
- package/dist/src/vtab/memory/layer/scan-layer.d.ts.map +1 -1
- package/dist/src/vtab/memory/layer/scan-layer.js +32 -5
- package/dist/src/vtab/memory/layer/scan-layer.js.map +1 -1
- package/dist/src/vtab/memory/layer/transaction.d.ts +111 -16
- package/dist/src/vtab/memory/layer/transaction.d.ts.map +1 -1
- package/dist/src/vtab/memory/layer/transaction.js +154 -51
- 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 +53 -40
- 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 +15 -3
- package/dist/src/vtab/memory/table.js.map +1 -1
- package/dist/src/vtab/module.d.ts +51 -21
- package/dist/src/vtab/module.d.ts.map +1 -1
- package/dist/src/vtab/table.d.ts +10 -2
- package/dist/src/vtab/table.d.ts.map +1 -1
- package/dist/src/vtab/table.js +1 -1
- package/dist/src/vtab/table.js.map +1 -1
- package/package.json +3 -3
|
@@ -4,20 +4,21 @@ import { createRowSlot } from '../context-helpers.js';
|
|
|
4
4
|
import { QuereusError } from '../../common/errors.js';
|
|
5
5
|
import { StatusCode } from '../../common/types.js';
|
|
6
6
|
import { createLogger } from '../../common/logger.js';
|
|
7
|
-
import { buildColumnIndexMap, withGeneratedColumnGraph, requireVtabModule, resolveNamedConstraintClass, validateCollationForType } from '../../schema/table.js';
|
|
7
|
+
import { buildColumnIndexMap, withGeneratedColumnGraph, requireVtabModule, resolveNamedConstraintClass, namedConstraintExists, assertConstraintNameFree, validateCollationForType, columnDefToSchema } from '../../schema/table.js';
|
|
8
8
|
import { validateForeignKeyCollations, buildForeignKeyConstraintSchema, extractColumnLevelCheckConstraints, extractColumnLevelForeignKeys, extractColumnLevelUniqueConstraints } from '../../schema/constraint-builder.js';
|
|
9
|
-
import { MemoryTableModule } from '../../vtab/memory/module.js';
|
|
10
9
|
import { quoteIdentifier, expressionToString, astToString } from '../../emit/ast-stringify.js';
|
|
11
10
|
import { renameTableInAst, renameColumnInAst, renameColumnInCheckExpression } from '../../schema/rename-rewriter.js';
|
|
12
11
|
import { assertCatalogObjectPersistable, assertRenameDependentsPersistable } from '../../schema/catalog-persistability.js';
|
|
13
|
-
import {
|
|
12
|
+
import { assertUniqueConstraintIndexNameFree, assertUniqueConstraintNotDuplicated, uniqueConstraintColumnSetKey } from '../../schema/catalog.js';
|
|
14
13
|
import { isTruthy } from '../../util/comparison.js';
|
|
15
|
-
import { assertDdlTransactionPolicy } from './ddl-transaction-policy.js';
|
|
16
|
-
import {
|
|
14
|
+
import { assertDdlTransactionPolicy, isExplicitTransactionOpen } from './ddl-transaction-policy.js';
|
|
15
|
+
import { emitAlterSchemaEvent } from './alter-schema-event.js';
|
|
16
|
+
import { foldDefaultToType, validateAndParse } from '../../types/validation.js';
|
|
17
17
|
import { snapshotStaleMaterializedViews, propagateTableRenameToMaterializedViews, propagateColumnRenameToMaterializedViews, restoreUnaffectedMaterializedViews, attachMaintainedDerivation, detachMaintainedDerivation, } from './materialized-view-helpers.js';
|
|
18
18
|
import { isMaintainedTable } from '../../schema/derivation.js';
|
|
19
19
|
import { inferType } from '../../types/registry.js';
|
|
20
20
|
const log = createLogger('runtime:emit:alter-table');
|
|
21
|
+
const warnLog = log.extend('warn');
|
|
21
22
|
/** A scheduled sub-program resolved to a callback the emitter invokes per row. */
|
|
22
23
|
function qualifyTableName(schemaName, tableName) {
|
|
23
24
|
const prefix = (schemaName && schemaName.toLowerCase() !== 'main')
|
|
@@ -28,12 +29,13 @@ function qualifyTableName(schemaName, tableName) {
|
|
|
28
29
|
export function emitAlterTable(plan, ctx) {
|
|
29
30
|
const tableSchema = plan.table.tableSchema;
|
|
30
31
|
const action = plan.action;
|
|
31
|
-
// An ADD COLUMN with a
|
|
32
|
-
//
|
|
33
|
-
//
|
|
34
|
-
//
|
|
35
|
-
//
|
|
36
|
-
//
|
|
32
|
+
// An ADD COLUMN with a per-row value source — a non-foldable DEFAULT, or a GENERATED
|
|
33
|
+
// ALWAYS AS expression — carries a backfill scalar; emit it as a scheduled sub-program
|
|
34
|
+
// so the scheduler resolves it into a callback the run() body evaluates per existing row
|
|
35
|
+
// (via a row slot over the backfill's row descriptor). When the new column also carries a
|
|
36
|
+
// CHECK, its predicates ride alongside as further callbacks, evaluated per backfilled row
|
|
37
|
+
// against `[...existingRow, backfilledValue]`. Slot order is fixed: backfill first
|
|
38
|
+
// (present whenever checks are), then the checks in order.
|
|
37
39
|
const backfill = action.type === 'addColumn' ? action.backfill : undefined;
|
|
38
40
|
const checks = action.type === 'addColumn' ? action.checks : undefined;
|
|
39
41
|
const params = [
|
|
@@ -172,7 +174,7 @@ async function runRenameTable(rctx, tableSchema, schema, newName) {
|
|
|
172
174
|
// substitutes `newName`, which is already under test as the record's own name.
|
|
173
175
|
assertCatalogObjectPersistable(rctx.db, 'materializedView', { ...tableSchema, name: newName });
|
|
174
176
|
}
|
|
175
|
-
assertRenameDependentsPersistable(rctx.db, schema, ast => renameTableInAst(ast, oldName, newName, tableSchema.schemaName));
|
|
177
|
+
assertRenameDependentsPersistable(rctx.db, schema, ast => renameTableInAst(ast, oldName, newName, tableSchema.schemaName), t => rewriteTableForTableRename(t, tableSchema.schemaName.toLowerCase(), oldName, newName));
|
|
176
178
|
// Clone schema with new name
|
|
177
179
|
const updatedTableSchema = {
|
|
178
180
|
...tableSchema,
|
|
@@ -198,6 +200,12 @@ async function runRenameTable(rctx, tableSchema, schema, newName) {
|
|
|
198
200
|
// rewriting its `ddl` text would produce an incoherent instruction. How a rename
|
|
199
201
|
// crosses the wire to a peer is `fix/sync-schema-migrations-replicate-empty-ddl`.
|
|
200
202
|
rctx.db._getEventEmitter().renameBatchedEvents(tableSchema.schemaName, oldName, newName);
|
|
203
|
+
// Deferred constraint checks this transaction already parked carry evaluators compiled
|
|
204
|
+
// against the OLD name — their scan leaves would connect to a table that no longer
|
|
205
|
+
// exists (or, on a store backend, to an empty one, yielding a FALSE violation). Tell
|
|
206
|
+
// the queue so it re-points those entries and moves the bucket keyed by the table name.
|
|
207
|
+
// Same placement rationale as the event relabel above.
|
|
208
|
+
rctx.db.getDeferredConstraints().notifyTableRename(tableSchema.schemaName, oldName, newName);
|
|
201
209
|
// The renamed table's own definition can name itself: a self-referencing FK's
|
|
202
210
|
// `referencedTable`, a table-qualified CHECK expression, a table-qualified
|
|
203
211
|
// partial-index predicate. Rewrite those BEFORE the catalog swap and the notify
|
|
@@ -255,6 +263,11 @@ async function runRenameTable(rctx, tableSchema, schema, newName) {
|
|
|
255
263
|
// names a vanished table. A module whose `renameTable` already did all its work (or
|
|
256
264
|
// that keeps no per-name catalog) simply omits the hook.
|
|
257
265
|
await module.finalizeRename?.(rctx.db, tableSchema.schemaName, oldName, newName);
|
|
266
|
+
// The public schema-change event, for a module with no emitter of its own — see
|
|
267
|
+
// {@link emitAlterSchemaEvent} for why every arm emits at its tail rather than
|
|
268
|
+
// alongside the module call. Names only the NEW table: `DatabaseSchemaChangeEvent`
|
|
269
|
+
// has no old-object-name field, and the emitting backends have the identical gap.
|
|
270
|
+
emitAlterSchemaEvent(rctx, tableSchema, { type: 'alter', objectType: 'table', objectName: newName });
|
|
258
271
|
log('Renamed table %s.%s to %s', tableSchema.schemaName, oldName, newName);
|
|
259
272
|
return null;
|
|
260
273
|
}
|
|
@@ -268,7 +281,9 @@ async function runRenameColumn(rctx, tableSchema, schema, oldName, newName) {
|
|
|
268
281
|
throw new QuereusError(`Column '${newName}' already exists in table '${tableSchema.name}'`, StatusCode.ERROR);
|
|
269
282
|
}
|
|
270
283
|
// Pre-flight, BEFORE the first side effect (`module.alterTable`): the rewritten
|
|
271
|
-
// body of every dependent view / materialized view
|
|
284
|
+
// body of every dependent view / materialized view — and the rewritten record of
|
|
285
|
+
// every dependent table (its CHECK expressions, the referenced-column list of an FK
|
|
286
|
+
// pointing here, its partial-index predicates) — must still be persistable, on the
|
|
272
287
|
// same unfailable-propagation reasoning as the table-rename arm above. Shares one
|
|
273
288
|
// resolver with `propagateColumnRename` so the two passes cannot drift apart in
|
|
274
289
|
// code; what makes them agree at RUNTIME (the resolver reads the LIVE catalog, and
|
|
@@ -276,7 +291,8 @@ async function runRenameColumn(rctx, tableSchema, schema, oldName, newName) {
|
|
|
276
291
|
// `isTableInUnaliasedScope` skips the renamed table itself and probes only OTHER
|
|
277
292
|
// sources, whose column sets this rename does not touch.
|
|
278
293
|
const resolveColumnInSource = buildColumnSourceResolver(rctx.db);
|
|
279
|
-
assertRenameDependentsPersistable(rctx.db, schema, ast => renameColumnInAst(ast, tableSchema.name, oldName, newName, tableSchema.schemaName, resolveColumnInSource));
|
|
294
|
+
assertRenameDependentsPersistable(rctx.db, schema, ast => renameColumnInAst(ast, tableSchema.name, oldName, newName, tableSchema.schemaName, resolveColumnInSource), t => rewriteTableForColumnRename(t, tableSchema.schemaName.toLowerCase(), tableSchema.name, oldName, newName, resolveColumnInSource));
|
|
295
|
+
assertRenamedColumnBackingNamesFree(tableSchema, colIndex, oldName, newName);
|
|
280
296
|
const existingCol = tableSchema.columns[colIndex];
|
|
281
297
|
// Build a ColumnDef AST for the renamed column (preserving type info)
|
|
282
298
|
const newColumnDef = {
|
|
@@ -327,9 +343,86 @@ async function runRenameColumn(rctx, tableSchema, schema, oldName, newName) {
|
|
|
327
343
|
// Propagate the rename into dependent objects (CHECK / FK / partial-index
|
|
328
344
|
// predicates in this and other tables, view and materialized-view bodies).
|
|
329
345
|
await propagateColumnRename(rctx, tableSchema.schemaName, tableSchema.name, oldName, newName, preStaleMvs, resolveColumnInSource);
|
|
346
|
+
emitAlterSchemaEvent(rctx, tableSchema, {
|
|
347
|
+
type: 'alter', objectType: 'column',
|
|
348
|
+
objectName: tableSchema.name,
|
|
349
|
+
columnName: newName,
|
|
350
|
+
oldColumnName: oldName,
|
|
351
|
+
});
|
|
330
352
|
log('Renamed column %s.%s.%s to %s', tableSchema.schemaName, tableSchema.name, oldName, newName);
|
|
331
353
|
return null;
|
|
332
354
|
}
|
|
355
|
+
/**
|
|
356
|
+
* Refuses a RENAME COLUMN that would move an unnamed UNIQUE constraint's backing
|
|
357
|
+
* structure onto a name an index on the same table already holds.
|
|
358
|
+
*
|
|
359
|
+
* An unnamed UNIQUE is enforced by a structure named `_uc_<covered column names>`,
|
|
360
|
+
* derived from the LIVE column names and never recorded — so renaming a covered
|
|
361
|
+
* column moves that name. This is the same collision the four declaration paths
|
|
362
|
+
* already refuse (ADD CONSTRAINT, ADD COLUMN … unique, RENAME CONSTRAINT, and
|
|
363
|
+
* `SchemaManager.createIndex` from the index side), reached through a rename instead
|
|
364
|
+
* of a declaration. Left unguarded the user's index is silently reclassified as a
|
|
365
|
+
* hidden backing structure: it vanishes from `schema()` / `index_info()`, `DROP INDEX`
|
|
366
|
+
* answers `no such index`, and store-backed its `CREATE INDEX` line is dropped from
|
|
367
|
+
* the persisted catalog entry — after which the constraint's entries are built into
|
|
368
|
+
* that index's store and, on reopen, it stops rejecting duplicates.
|
|
369
|
+
*
|
|
370
|
+
* Placed before `module.alterTable` for the same reason those paths are: the store's
|
|
371
|
+
* `alterTable` persists, so a later throw would leave the damage on disk.
|
|
372
|
+
*
|
|
373
|
+
* Skips a case-only rename entirely: the derived name folds to the constraint's OWN
|
|
374
|
+
* pre-rename structure, which the memory backend materializes as a real index entry
|
|
375
|
+
* and the name-only guard would otherwise read as a collision (the same reason
|
|
376
|
+
* `runRenameConstraint` gates its check on `oldLower !== newLower`).
|
|
377
|
+
*
|
|
378
|
+
* Named and `derivedFromIndex` constraints are unaffected — neither takes a derived
|
|
379
|
+
* name. Two DIFFERENT unnamed constraints deriving one post-rename name is only
|
|
380
|
+
* reachable through duplicate unnamed UNIQUEs and is not this guard's problem.
|
|
381
|
+
*
|
|
382
|
+
* NOTE: name-only, like the declaration guards, so it also refuses the rename when the
|
|
383
|
+
* constraint is realized by a REUSED same-column-set index and therefore has no
|
|
384
|
+
* `_uc_*` structure to move — a legal rename turned away over a name nothing would
|
|
385
|
+
* have claimed. Deliberate: both backends decide reuse internally and at different
|
|
386
|
+
* times, so a reuse-aware check would make them disagree on which renames are legal.
|
|
387
|
+
* The refusal names both objects and is escapable by renaming the index first. If the
|
|
388
|
+
* false refusal ever bites, gate the check on the constraint actually holding a
|
|
389
|
+
* `_uc_*` structure — which means asking the module, not just `tableSchema.indexes`.
|
|
390
|
+
*/
|
|
391
|
+
function assertRenamedColumnBackingNamesFree(tableSchema, colIndex, oldName, newName) {
|
|
392
|
+
if (oldName.toLowerCase() === newName.toLowerCase())
|
|
393
|
+
return;
|
|
394
|
+
for (const uc of tableSchema.uniqueConstraints ?? []) {
|
|
395
|
+
if (uc.name !== undefined || uc.derivedFromIndex !== undefined)
|
|
396
|
+
continue;
|
|
397
|
+
if (!uc.columns.includes(colIndex))
|
|
398
|
+
continue;
|
|
399
|
+
const postRenameColumns = uc.columns.map(i => i === colIndex ? newName : (tableSchema.columns[i]?.name ?? String(i)));
|
|
400
|
+
assertUniqueConstraintIndexNameFree(tableSchema, undefined, postRenameColumns, `rename column '${oldName}' to '${newName}' on table '${tableSchema.name}'`);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
/**
|
|
404
|
+
* Refuses an inline constraint on a new column whose *user-written* name is already taken —
|
|
405
|
+
* by a constraint on the table, or by an earlier inline constraint in the same ADD COLUMN
|
|
406
|
+
* (neither is on `tableSchema` yet). Same within-table rule ADD CONSTRAINT and RENAME
|
|
407
|
+
* CONSTRAINT enforce; see {@link assertConstraintNameFree} for the ordering constraints.
|
|
408
|
+
*
|
|
409
|
+
* Reads the RAW declaration rather than the extracted table constraints: the extractors
|
|
410
|
+
* auto-name an unnamed CHECK `_check_<column>`, and that synthesized name is not user
|
|
411
|
+
* identity — comparing it would refuse two unnamed CHECKs on one new column, which is
|
|
412
|
+
* legal. Only the three classes that occupy a named-constraint array are compared (a name
|
|
413
|
+
* on an inline NOT NULL / DEFAULT / PRIMARY KEY is not stored, so it cannot collide).
|
|
414
|
+
*/
|
|
415
|
+
function assertInlineConstraintNamesFree(tableSchema, columnDef) {
|
|
416
|
+
const seen = new Set();
|
|
417
|
+
for (const declared of columnDef.constraints) {
|
|
418
|
+
if (!declared.name)
|
|
419
|
+
continue;
|
|
420
|
+
if (declared.type !== 'check' && declared.type !== 'unique' && declared.type !== 'foreignKey')
|
|
421
|
+
continue;
|
|
422
|
+
assertConstraintNameFree(tableSchema, declared.name, seen);
|
|
423
|
+
seen.add(declared.name.toLowerCase());
|
|
424
|
+
}
|
|
425
|
+
}
|
|
333
426
|
async function runAddColumn(rctx, tableSchema, schema, columnDef, backfill, backfillCb, checks, checkCbs) {
|
|
334
427
|
// Validate column doesn't already exist
|
|
335
428
|
if (tableSchema.columnIndexMap.has(columnDef.name.toLowerCase())) {
|
|
@@ -343,21 +436,37 @@ async function runAddColumn(rctx, tableSchema, schema, columnDef, backfill, back
|
|
|
343
436
|
// (bind params / bare columns / non-determinism rejected; `new.<column>` accepted)
|
|
344
437
|
// and, when it does not fold to a literal, compiled into `backfill` — the default
|
|
345
438
|
// evaluated against the existing row, so `new.<column>` reads that row's sibling.
|
|
439
|
+
// A GENERATED ALWAYS AS expression takes the same `backfill` route (always, since a
|
|
440
|
+
// generated column has no `defaultValue` any module could bulk-write), validated at
|
|
441
|
+
// plan-build with the generated-flavoured determinism check.
|
|
346
442
|
const defaultConstraint = columnDef.constraints?.find(c => c.type === 'default');
|
|
347
|
-
// Folded literal default
|
|
348
|
-
//
|
|
349
|
-
//
|
|
350
|
-
|
|
443
|
+
// Folded literal default, converted to the new column's declared type — the value a
|
|
444
|
+
// fresh INSERT under the same DEFAULT would store, and the same value each module
|
|
445
|
+
// folds for its own rows. Undefined when there is no default (a generated column
|
|
446
|
+
// included) or it does not fold — those carry `backfill` instead. Used by the NOT NULL
|
|
447
|
+
// gate below and by the batched-event remap's backfill value. An unconvertible literal
|
|
448
|
+
// (`integer default 'abc'`) throws MISMATCH here, before anything is mutated.
|
|
449
|
+
const foldedDefault = foldDefaultToType(defaultConstraint?.expr, inferType(columnDef.dataType), columnDef.name);
|
|
351
450
|
// Call module.alterTable for data + schema update
|
|
352
451
|
const module = requireVtabModule(tableSchema);
|
|
353
452
|
if (!module.alterTable) {
|
|
354
453
|
throw new QuereusError(`Module for table '${tableSchema.name}' does not support ALTER TABLE ADD COLUMN`, StatusCode.UNSUPPORTED);
|
|
355
454
|
}
|
|
356
|
-
// NOT NULL without a usable
|
|
357
|
-
// folded value is NULL is equivalent to "no DEFAULT" for this purpose. A
|
|
358
|
-
//
|
|
359
|
-
//
|
|
360
|
-
//
|
|
455
|
+
// NOT NULL without a usable value source cannot backfill existing rows. A DEFAULT whose
|
|
456
|
+
// folded value is NULL is equivalent to "no DEFAULT" for this purpose. A per-row source
|
|
457
|
+
// (carried in `backfill` — a non-foldable expression default or a GENERATED ALWAYS AS
|
|
458
|
+
// expression) IS usable: its NOT NULL enforcement is deferred to the module's per-row
|
|
459
|
+
// backfill, which rejects the ALTER if any row evaluates to NULL. If the table is
|
|
460
|
+
// non-empty and there is no usable source, reject before mutating any schema or data.
|
|
461
|
+
//
|
|
462
|
+
// Mandatoriness is RESOLVED, not read off the statement text: a column is NOT NULL
|
|
463
|
+
// either by an explicit `not null` or by the session `default_column_nullability`
|
|
464
|
+
// (which ships as `not_null`), so `add column x text default null` is a mandatory
|
|
465
|
+
// column with no value for the existing rows and must be refused. `columnDefToSchema`
|
|
466
|
+
// is the same resolver the memory module, the store module and the isolation layer's
|
|
467
|
+
// `deriveAddColumnBackfill` use, so a fourth spelling of the rule cannot drift. It
|
|
468
|
+
// also validates an explicit COLLATE and rejects DEFAULT + GENERATED ALWAYS AS on one
|
|
469
|
+
// column — both previously raised by the module mid-work, now pre-mutation.
|
|
361
470
|
//
|
|
362
471
|
// A module may opt out of this engine-generic rejection via the
|
|
363
472
|
// `delegatesNotNullBackfill` capability (structurally-total modules that
|
|
@@ -365,8 +474,9 @@ async function runAddColumn(rctx, tableSchema, schema, columnDef, backfill, back
|
|
|
365
474
|
// it declares the capability, the decision is left entirely to its
|
|
366
475
|
// `alterTable`. Native modules leave it off, so this still fires for them.
|
|
367
476
|
const delegatesBackfill = module.getCapabilities?.().delegatesNotNullBackfill === true;
|
|
368
|
-
const
|
|
369
|
-
|
|
477
|
+
const defaultNotNull = rctx.db.options.getStringOption('default_column_nullability') === 'not_null';
|
|
478
|
+
const resolvedNotNull = columnDefToSchema(columnDef, defaultNotNull, rctx.db.options.getStringOption('default_collation'), (n) => rctx.db.isCollationRegistered(n)).notNull;
|
|
479
|
+
if (resolvedNotNull && !delegatesBackfill && !backfill) {
|
|
370
480
|
const defaultIsNullish = !defaultConstraint?.expr || foldedDefault === null;
|
|
371
481
|
if (defaultIsNullish) {
|
|
372
482
|
await validateNotNullBackfill(rctx, tableSchema, columnDef.name);
|
|
@@ -389,9 +499,37 @@ async function runAddColumn(rctx, tableSchema, schema, columnDef, backfill, back
|
|
|
389
499
|
...inlineChecks,
|
|
390
500
|
...extractColumnLevelForeignKeys(columnDef),
|
|
391
501
|
];
|
|
392
|
-
//
|
|
393
|
-
//
|
|
394
|
-
|
|
502
|
+
// Refused before the column is materialized, so a duplicate name leaves the table
|
|
503
|
+
// completely untouched rather than relying on the revert path.
|
|
504
|
+
assertInlineConstraintNamesFree(tableSchema, columnDef);
|
|
505
|
+
// An inline `unique` builds an implicit backing structure named after the constraint
|
|
506
|
+
// — or `_uc_<column>` when unnamed — so reject before the column is materialized when
|
|
507
|
+
// that name is already an index on this table, or when the declaration merely repeats
|
|
508
|
+
// a UNIQUE the table already carries. The column does not exist yet, so both tests run
|
|
509
|
+
// off the column definition's own name (which is exactly what
|
|
510
|
+
// `extractColumnLevelUniqueConstraints` put in `columns`). Placed here, ahead of
|
|
511
|
+
// `module.alterTable`, so a refused statement leaves the table completely untouched
|
|
512
|
+
// rather than relying on the revert path.
|
|
513
|
+
//
|
|
514
|
+
// Duplicate-first, index-name-second — see the ordering rationale in
|
|
515
|
+
// `runAddConstraintViaModule`. `declaredColumnSets` carries the unnamed sets claimed by
|
|
516
|
+
// earlier inline constraints in THIS statement (`add column c … unique unique`); none
|
|
517
|
+
// of them is on `tableSchema` yet, so the guard cannot see them any other way.
|
|
518
|
+
const declaredColumnSets = new Set();
|
|
519
|
+
for (const constraint of inlineConstraints) {
|
|
520
|
+
if (constraint.type !== 'unique')
|
|
521
|
+
continue;
|
|
522
|
+
const columnNames = (constraint.columns ?? []).map(c => c.name);
|
|
523
|
+
const operation = `add ${constraint.name ? `constraint '${constraint.name}'` : 'UNIQUE'} column '${columnDef.name}' to table '${tableSchema.name}'`;
|
|
524
|
+
assertUniqueConstraintNotDuplicated(tableSchema, constraint.name, columnNames, operation, declaredColumnSets);
|
|
525
|
+
assertUniqueConstraintIndexNameFree(tableSchema, constraint.name, columnNames, operation);
|
|
526
|
+
if (constraint.name === undefined)
|
|
527
|
+
declaredColumnSets.add(uniqueConstraintColumnSetKey(columnNames));
|
|
528
|
+
}
|
|
529
|
+
// A per-row backfill derives each existing row's value from that row. Install a row slot
|
|
530
|
+
// over the backfill's row descriptor; the evaluator the module calls per existing row
|
|
531
|
+
// sets the slot to that row, so the expression's `new.<col>` refs (and the bare `<col>`
|
|
532
|
+
// refs a GENERATED ALWAYS AS expression uses) resolve to it.
|
|
395
533
|
const rowSlot = backfill ? createRowSlot(rctx, backfill.rowDescriptor) : undefined;
|
|
396
534
|
// When the new column carries a CHECK, install a second slot over the existing columns
|
|
397
535
|
// plus the new column; we evaluate each predicate against `[...existingRow, value]` after
|
|
@@ -405,7 +543,15 @@ async function runAddColumn(rctx, tableSchema, schema, columnDef, backfill, back
|
|
|
405
543
|
? async (row) => {
|
|
406
544
|
rowSlot.set(row);
|
|
407
545
|
const valueRaw = backfillCb(rctx);
|
|
408
|
-
const
|
|
546
|
+
const evaluated = (valueRaw instanceof Promise ? await valueRaw : valueRaw);
|
|
547
|
+
// Convert to the new column's declared type BEFORE the CHECK predicates see it,
|
|
548
|
+
// matching the write path (`emitInsert` coerces at the top of the DML pipeline, so
|
|
549
|
+
// constraint checking and storage both see the declared form). `coerceTo` is unset
|
|
550
|
+
// when the expression's static type already IS the column's type — see
|
|
551
|
+
// `AddColumnBackfill.coerceTo` for why re-converting there would be destructive.
|
|
552
|
+
const value = backfill.coerceTo
|
|
553
|
+
? validateAndParse(evaluated, backfill.coerceTo, columnDef.name)
|
|
554
|
+
: evaluated;
|
|
409
555
|
if (checkSlot && checkPredicates.length > 0 && checkCbs) {
|
|
410
556
|
checkSlot.set([...row, value]);
|
|
411
557
|
for (let i = 0; i < checkPredicates.length; i++) {
|
|
@@ -507,9 +653,10 @@ async function runAddColumn(rctx, tableSchema, schema, columnDef, backfill, back
|
|
|
507
653
|
// folding against them is sound and preserves the optimizer's reach.
|
|
508
654
|
schema.addTable(columnOnlySchema);
|
|
509
655
|
// Validate the backfilled values against each inline CHECK, for the literal-default
|
|
510
|
-
// path only. A per-row (evaluator)
|
|
511
|
-
//
|
|
512
|
-
// stale pre-backfill snapshot
|
|
656
|
+
// path only. A per-row (evaluator) backfill — non-foldable DEFAULT or GENERATED
|
|
657
|
+
// ALWAYS AS — already enforced its CHECKs inside the backfill hook above, against the
|
|
658
|
+
// freshly-computed value rather than this scan's stale pre-backfill snapshot, and the
|
|
659
|
+
// module enforces NOT NULL there too. Runs
|
|
513
660
|
// before the whole install loop below, so on a column declaring several kinds a
|
|
514
661
|
// CHECK violation is reported ahead of a UNIQUE or FK one.
|
|
515
662
|
if (!backfill && inlineChecks.length > 0) {
|
|
@@ -571,6 +718,17 @@ async function runAddColumn(rctx, tableSchema, schema, columnDef, backfill, back
|
|
|
571
718
|
oldObject: tableSchema,
|
|
572
719
|
newObject: finalTableSchema,
|
|
573
720
|
});
|
|
721
|
+
// ONE event for the whole statement, even when the column declared inline constraints.
|
|
722
|
+
// The install loop above makes a second `module.alterTable(addConstraint)` round-trip per
|
|
723
|
+
// inline constraint, and an emitter-backed module therefore announces `alter`/`column`
|
|
724
|
+
// followed by an `alter`/`table` per constraint — an artifact of its internal call
|
|
725
|
+
// pattern, not a second thing the application did. The deliberate divergence from that
|
|
726
|
+
// shape: do not "fix" this into two events.
|
|
727
|
+
emitAlterSchemaEvent(rctx, tableSchema, {
|
|
728
|
+
type: 'alter', objectType: 'column',
|
|
729
|
+
objectName: tableSchema.name,
|
|
730
|
+
columnName: columnDef.name,
|
|
731
|
+
});
|
|
574
732
|
log('Added column %s to table %s.%s', columnDef.name, tableSchema.schemaName, tableSchema.name);
|
|
575
733
|
return null;
|
|
576
734
|
}
|
|
@@ -666,9 +824,10 @@ async function validateBackfillAgainstChecks(rctx, columnOnlySchema, newCheckCon
|
|
|
666
824
|
}
|
|
667
825
|
}
|
|
668
826
|
/**
|
|
669
|
-
* Rejects ADD COLUMN ... NOT NULL when no usable
|
|
670
|
-
*
|
|
671
|
-
* the schema and module state are
|
|
827
|
+
* Rejects ADD COLUMN ... NOT NULL when no usable value source is supplied (no DEFAULT,
|
|
828
|
+
* a DEFAULT folding to NULL, and no per-row backfill) and the table already has rows.
|
|
829
|
+
* The pre-mutation form means no rollback is needed — the schema and module state are
|
|
830
|
+
* still untouched at this point.
|
|
672
831
|
*/
|
|
673
832
|
async function validateNotNullBackfill(rctx, tableSchema, newColumnName) {
|
|
674
833
|
const qualifiedTable = qualifyTableName(tableSchema.schemaName, tableSchema.name);
|
|
@@ -786,6 +945,13 @@ async function runDropColumn(rctx, tableSchema, schema, columnName) {
|
|
|
786
945
|
oldObject: tableSchema,
|
|
787
946
|
newObject: finalSchema,
|
|
788
947
|
});
|
|
948
|
+
// `drop`, not `alter` — the arm removes an object. Matches what an emitter-backed module
|
|
949
|
+
// reports for the same statement.
|
|
950
|
+
emitAlterSchemaEvent(rctx, tableSchema, {
|
|
951
|
+
type: 'drop', objectType: 'column',
|
|
952
|
+
objectName: tableSchema.name,
|
|
953
|
+
columnName,
|
|
954
|
+
});
|
|
789
955
|
log('Dropped column %s from table %s.%s', columnName, tableSchema.schemaName, tableSchema.name);
|
|
790
956
|
return null;
|
|
791
957
|
}
|
|
@@ -820,6 +986,10 @@ async function runDropConstraint(rctx, tableSchema, schema, constraintName) {
|
|
|
820
986
|
oldObject: tableSchema,
|
|
821
987
|
newObject: updatedTableSchema,
|
|
822
988
|
});
|
|
989
|
+
emitAlterSchemaEvent(rctx, tableSchema, {
|
|
990
|
+
type: 'alter', objectType: 'table',
|
|
991
|
+
objectName: tableSchema.name,
|
|
992
|
+
});
|
|
823
993
|
log('Dropped constraint %s from table %s.%s', constraintName, tableSchema.schemaName, tableSchema.name);
|
|
824
994
|
return null;
|
|
825
995
|
}
|
|
@@ -841,6 +1011,17 @@ async function runRenameConstraint(rctx, tableSchema, schema, oldName, newName)
|
|
|
841
1011
|
if (oldLower !== newLower && namedConstraintExists(tableSchema, newName)) {
|
|
842
1012
|
throw new QuereusError(`Cannot rename constraint to '${newName}': a constraint with that name already exists in table '${tableSchema.name}'`, StatusCode.CONSTRAINT);
|
|
843
1013
|
}
|
|
1014
|
+
// A UNIQUE constraint's implicit backing structure is named after the constraint, so
|
|
1015
|
+
// the rename renames that structure too — reject when the new name is already an
|
|
1016
|
+
// index on this table (the mirror of `SchemaManager.createIndex`'s refusal). Gated on
|
|
1017
|
+
// `oldLower !== newLower` for the same reason the collision check above is: on the
|
|
1018
|
+
// memory backend the constraint's OWN backing structure is a materialized index under
|
|
1019
|
+
// the old name, which a case-only rename would otherwise match.
|
|
1020
|
+
if (constraintClass === 'unique' && oldLower !== newLower) {
|
|
1021
|
+
// No columns to pass: the renamed-to name is always a name, so the `_uc_<cols>`
|
|
1022
|
+
// auto-name branch is unreachable from here.
|
|
1023
|
+
assertUniqueConstraintIndexNameFree(tableSchema, newName, [], `rename constraint '${oldName}' to '${newName}' on table '${tableSchema.name}'`);
|
|
1024
|
+
}
|
|
844
1025
|
const module = requireVtabModule(tableSchema);
|
|
845
1026
|
if (!module.alterTable) {
|
|
846
1027
|
throw new QuereusError(`Module for table '${tableSchema.name}' does not support ALTER TABLE RENAME CONSTRAINT`, StatusCode.UNSUPPORTED);
|
|
@@ -858,16 +1039,15 @@ async function runRenameConstraint(rctx, tableSchema, schema, oldName, newName)
|
|
|
858
1039
|
oldObject: tableSchema,
|
|
859
1040
|
newObject: updatedTableSchema,
|
|
860
1041
|
});
|
|
1042
|
+
// A named constraint is not an `objectType` of its own, so the arm reports the TABLE it
|
|
1043
|
+
// reshaped — same as an emitter-backed module does.
|
|
1044
|
+
emitAlterSchemaEvent(rctx, tableSchema, {
|
|
1045
|
+
type: 'alter', objectType: 'table',
|
|
1046
|
+
objectName: tableSchema.name,
|
|
1047
|
+
});
|
|
861
1048
|
log('Renamed constraint %s.%s.%s to %s', tableSchema.schemaName, tableSchema.name, oldName, newName);
|
|
862
1049
|
return null;
|
|
863
1050
|
}
|
|
864
|
-
/** True when `name` addresses any named CHECK / UNIQUE / FOREIGN KEY constraint. */
|
|
865
|
-
function namedConstraintExists(tableSchema, name) {
|
|
866
|
-
const lower = name.toLowerCase();
|
|
867
|
-
return (tableSchema.checkConstraints ?? []).some(c => c.name?.toLowerCase() === lower)
|
|
868
|
-
|| (tableSchema.uniqueConstraints ?? []).some(c => c.name?.toLowerCase() === lower)
|
|
869
|
-
|| (tableSchema.foreignKeys ?? []).some(c => c.name?.toLowerCase() === lower);
|
|
870
|
-
}
|
|
871
1051
|
/**
|
|
872
1052
|
* Rejects DROP/RENAME of a UNIQUE constraint that was synthesized from an explicit
|
|
873
1053
|
* `CREATE UNIQUE INDEX` (`derivedFromIndex` set). That constraint is the index's
|
|
@@ -959,6 +1139,14 @@ async function runAlterColumn(rctx, tableSchema, schema, action) {
|
|
|
959
1139
|
oldObject: tableSchema,
|
|
960
1140
|
newObject: updatedTableSchema,
|
|
961
1141
|
});
|
|
1142
|
+
// All four attribute forms (SET/DROP NOT NULL, SET DATA TYPE, SET/DROP DEFAULT,
|
|
1143
|
+
// SET COLLATE) report the same `alter`/`column` shape — the event says which column
|
|
1144
|
+
// changed, not which attribute.
|
|
1145
|
+
emitAlterSchemaEvent(rctx, tableSchema, {
|
|
1146
|
+
type: 'alter', objectType: 'column',
|
|
1147
|
+
objectName: tableSchema.name,
|
|
1148
|
+
columnName: action.columnName,
|
|
1149
|
+
});
|
|
962
1150
|
log('Altered column %s.%s.%s', tableSchema.schemaName, tableSchema.name, action.columnName);
|
|
963
1151
|
return null;
|
|
964
1152
|
}
|
|
@@ -996,11 +1184,17 @@ function alterColumnEventValueRemap(tableSchema, colIndex, action) {
|
|
|
996
1184
|
};
|
|
997
1185
|
}
|
|
998
1186
|
if (action.setNotNull === true) {
|
|
999
|
-
// SET NOT NULL backfill: null → the folded literal DEFAULT, the same
|
|
1000
|
-
// module applies. No usable literal default means the module
|
|
1001
|
-
// NULLs (nothing to remap) or rejected the ALTER before reaching here.
|
|
1002
|
-
|
|
1003
|
-
|
|
1187
|
+
// SET NOT NULL backfill: null → the folded-and-CONVERTED literal DEFAULT, the same
|
|
1188
|
+
// map the module applies to its rows. No usable literal default means the module
|
|
1189
|
+
// either found no NULLs (nothing to remap) or rejected the ALTER before reaching here.
|
|
1190
|
+
//
|
|
1191
|
+
// NOTE: `foldDefaultToType` throws MISMATCH on an unconvertible literal, and this
|
|
1192
|
+
// runs AFTER the module mutated. Unreachable today — every module folds the same
|
|
1193
|
+
// DEFAULT through the same helper up front and rejects the ALTER there, so a literal
|
|
1194
|
+
// that fails here would already have failed. If a module ever stops folding eagerly,
|
|
1195
|
+
// catch here and return undefined rather than aborting a completed ALTER.
|
|
1196
|
+
const col = tableSchema.columns[colIndex];
|
|
1197
|
+
const folded = foldDefaultToType(col.defaultValue, col.logicalType, col.name);
|
|
1004
1198
|
if (folded === undefined || folded === null)
|
|
1005
1199
|
return undefined;
|
|
1006
1200
|
return (v) => (v === null ? folded : v);
|
|
@@ -1094,12 +1288,33 @@ async function runAlterPrimaryKey(rctx, tableSchema, schema, columns) {
|
|
|
1094
1288
|
}
|
|
1095
1289
|
seen.add(pk.index);
|
|
1096
1290
|
}
|
|
1291
|
+
// Column indices of the key being retired and the one replacing it. Both index the
|
|
1292
|
+
// CURRENT column layout — ALTER PRIMARY KEY adds and drops no column — so they are
|
|
1293
|
+
// also indices into the batched events' row images, which any earlier ALTER in this
|
|
1294
|
+
// transaction has already remapped to that layout.
|
|
1295
|
+
const oldPkIndices = tableSchema.primaryKeyDefinition.map(pk => pk.index);
|
|
1296
|
+
const newPkIndices = newPkDef.map(pk => pk.index);
|
|
1097
1297
|
// Try native module re-key first
|
|
1098
1298
|
const module = requireVtabModule(tableSchema);
|
|
1099
1299
|
if (module.alterTable) {
|
|
1100
1300
|
try {
|
|
1101
1301
|
const schemaChangePk = newPkDef.map(pk => ({ index: pk.index, desc: pk.desc ?? false }));
|
|
1102
1302
|
const updatedTableSchema = await module.alterTable(rctx.db, tableSchema.schemaName, tableSchema.name, { type: 'alterPrimaryKey', newPkColumns: schemaChangePk });
|
|
1303
|
+
// Events this transaction already recorded identify their rows by the RETIRED
|
|
1304
|
+
// key; re-derive each from its own row image so the commit delivers every event
|
|
1305
|
+
// under the key the table has at delivery. AFTER the module call (a module
|
|
1306
|
+
// failure must leave the batch as untouched as the catalog, and the store's
|
|
1307
|
+
// `ddlCommitPendingOps` flushes its queued events into our batch DURING that
|
|
1308
|
+
// call — those must be in the batch before we walk it), BEFORE the catalog swap,
|
|
1309
|
+
// matching where the other ALTER arms call `remapBatchedDataEvents`.
|
|
1310
|
+
//
|
|
1311
|
+
// NOTE: this sits inside the try whose catch falls through to the rebuild, so an
|
|
1312
|
+
// UNSUPPORTED raised BELOW it (only reachable via a `table_modified` listener, as
|
|
1313
|
+
// `schema.addTable` raises no UNSUPPORTED) would re-key twice. The second pass is
|
|
1314
|
+
// idempotent for every event except a PK-moving update, whose image tie-break no
|
|
1315
|
+
// longer recognizes the already-rewritten key. If anything below this line gains
|
|
1316
|
+
// a real UNSUPPORTED path, narrow the try to the `module.alterTable` call.
|
|
1317
|
+
rctx.db._getEventEmitter().rekeyBatchedDataEvents(tableSchema.schemaName, tableSchema.name, oldPkIndices, newPkIndices);
|
|
1103
1318
|
schema.addTable(updatedTableSchema);
|
|
1104
1319
|
rctx.db.schemaManager.getChangeNotifier().notifyChange({
|
|
1105
1320
|
type: 'table_modified',
|
|
@@ -1108,39 +1323,96 @@ async function runAlterPrimaryKey(rctx, tableSchema, schema, columns) {
|
|
|
1108
1323
|
oldObject: tableSchema,
|
|
1109
1324
|
newObject: updatedTableSchema,
|
|
1110
1325
|
});
|
|
1326
|
+
// NOTE: inside the try whose catch falls through to the rebuild — same caveat as
|
|
1327
|
+
// the re-key above. The emit raises no UNSUPPORTED (the gate either emits or
|
|
1328
|
+
// does not), so it cannot itself trigger the fallback.
|
|
1329
|
+
emitAlterSchemaEvent(rctx, tableSchema, {
|
|
1330
|
+
type: 'alter', objectType: 'table',
|
|
1331
|
+
objectName: tableSchema.name,
|
|
1332
|
+
});
|
|
1111
1333
|
log('Altered primary key of %s.%s (native)', tableSchema.schemaName, tableSchema.name);
|
|
1112
1334
|
return null;
|
|
1113
1335
|
}
|
|
1114
1336
|
catch (e) {
|
|
1115
1337
|
if (e instanceof QuereusError && e.code === StatusCode.UNSUPPORTED) {
|
|
1116
|
-
// Fall through to rebuild
|
|
1338
|
+
// Fall through to rebuild. The swallow is the documented protocol
|
|
1339
|
+
// (docs/module-authoring.md § `alterPrimaryKey`), but a swallowed error must
|
|
1340
|
+
// still leave a trace — this is the only record that the native re-key was
|
|
1341
|
+
// attempted and declined.
|
|
1342
|
+
warnLog('Module %s declined an in-place re-key of %s.%s (UNSUPPORTED: %s); falling back to a shadow-table rebuild', tableSchema.vtabModuleName ?? '<unknown>', tableSchema.schemaName, tableSchema.name, e.message);
|
|
1117
1343
|
}
|
|
1118
1344
|
else {
|
|
1119
1345
|
throw e;
|
|
1120
1346
|
}
|
|
1121
1347
|
}
|
|
1122
1348
|
}
|
|
1123
|
-
// Rebuild fallback
|
|
1349
|
+
// Rebuild fallback. Two preconditions, both refusals rather than repairs — see
|
|
1350
|
+
// `rebuildViaShadowTable` for why neither has a correct outcome. Checked here, after the
|
|
1351
|
+
// native attempt, so both entry paths into the rebuild (no `alterTable` hook at all; the
|
|
1352
|
+
// hook raised UNSUPPORTED) are covered by one check each; a module that raised
|
|
1353
|
+
// UNSUPPORTED has by contract mutated nothing, so a refusal here leaves the catalog, the
|
|
1354
|
+
// table and the enclosing transaction untouched. Capability first: it is unconditional,
|
|
1355
|
+
// so it is the more informative answer when both apply.
|
|
1356
|
+
if (!module.renameTable) {
|
|
1357
|
+
throw new QuereusError(`Module '${tableSchema.vtabModuleName ?? '<unknown>'}' does not support ALTER PRIMARY KEY on table `
|
|
1358
|
+
+ `'${tableSchema.name}': it cannot re-key in place (it implements no 'alterTable' hook, or the `
|
|
1359
|
+
+ `hook declined), and the engine's fallback rebuild finishes by renaming a shadow table over `
|
|
1360
|
+
+ `this one — without 'renameTable' the module would keep the rows under the shadow name and `
|
|
1361
|
+
+ `the rebuilt table could not be opened.`, StatusCode.UNSUPPORTED);
|
|
1362
|
+
}
|
|
1363
|
+
// NOTE: refused on every `DdlTransactionality` tier, including a module declaring
|
|
1364
|
+
// 'transactional'. None does today; if one appears its DROP + RENAME would roll back
|
|
1365
|
+
// together with the row copy, making this refusal over-broad — exempt that tier then, the
|
|
1366
|
+
// way `assertDdlTransactionPolicy` already does.
|
|
1367
|
+
if (isExplicitTransactionOpen(rctx.db)) {
|
|
1368
|
+
throw new QuereusError(`ALTER PRIMARY KEY on table '${tableSchema.name}' is not allowed inside an explicit transaction: `
|
|
1369
|
+
+ `module '${tableSchema.vtabModuleName ?? '<unknown>'}' cannot re-key in place, so the statement `
|
|
1370
|
+
+ `would fall back to a shadow-table rebuild whose DROP + RENAME survives ROLLBACK while its row `
|
|
1371
|
+
+ `copy does not — a rollback would leave an empty table and destroy rows committed before this `
|
|
1372
|
+
+ `transaction began. COMMIT or ROLLBACK first, then re-issue in autocommit mode.`, StatusCode.ERROR);
|
|
1373
|
+
}
|
|
1124
1374
|
await rebuildTableWithNewShape(rctx, tableSchema, schema, tableSchema.columns.map(c => c.name), newPkDef);
|
|
1375
|
+
// A DEFENSIVE NO-OP on this path today, not the working re-key the native arm above does.
|
|
1376
|
+
// Nothing can be in the batch for this table by now: the rebuild's own events are
|
|
1377
|
+
// suppressed (see `rebuildViaShadowTable`), the ALTER statement writes no rows of its own,
|
|
1378
|
+
// and the explicit-transaction refusal above rules out earlier same-transaction writes.
|
|
1379
|
+
// Kept anyway — it costs one walk of an empty batch, and it is the correct call the moment
|
|
1380
|
+
// that transaction guard is loosened; deleting it would quietly make this arm's
|
|
1381
|
+
// as-of-delivery `key` guarantee depend on the guard staying exactly as it is. Every column
|
|
1382
|
+
// survives the rebuild in order (`survivingColumns` above is the full list), so the indices
|
|
1383
|
+
// would still line up with the event images.
|
|
1384
|
+
rctx.db._getEventEmitter().rekeyBatchedDataEvents(tableSchema.schemaName, tableSchema.name, oldPkIndices, newPkIndices);
|
|
1385
|
+
// The rebuild's own four statements are silent (`rebuildViaShadowTable` runs them inside
|
|
1386
|
+
// `withPublicEventsSuppressed`, which also swallows the inner RENAME TO arm's event). This
|
|
1387
|
+
// emit is OUTSIDE that scope, so the re-key itself reports exactly one `alter`/`table` —
|
|
1388
|
+
// the same shape the native branch above reports.
|
|
1389
|
+
//
|
|
1390
|
+
// NOTE: this arm is the one place where a module WITH its own emitter can end up reporting
|
|
1391
|
+
// nothing — it raised UNSUPPORTED instead of emitting, and the gate below then suppresses
|
|
1392
|
+
// the engine's fallback because the module registration advertises native support. No such
|
|
1393
|
+
// module exists today (memory re-keys in place, the store handles `alterPrimaryKey`
|
|
1394
|
+
// natively), so the path is unreachable. If an emitter-backed module ever declines the
|
|
1395
|
+
// re-key, teach the gate that a rebuild fallback owns the event regardless of the module's
|
|
1396
|
+
// emitter.
|
|
1397
|
+
emitAlterSchemaEvent(rctx, tableSchema, {
|
|
1398
|
+
type: 'alter', objectType: 'table',
|
|
1399
|
+
objectName: tableSchema.name,
|
|
1400
|
+
});
|
|
1125
1401
|
log('Altered primary key of %s.%s (rebuild)', tableSchema.schemaName, tableSchema.name);
|
|
1126
1402
|
return null;
|
|
1127
1403
|
}
|
|
1128
1404
|
/**
|
|
1129
|
-
* Rebuilds a table with a new column projection and/or primary key
|
|
1130
|
-
*
|
|
1131
|
-
*
|
|
1132
|
-
*
|
|
1405
|
+
* Rebuilds a table with a new column projection and/or primary key, via the
|
|
1406
|
+
* shadow-table SQL approach with DROP+RENAME. This is the fallback for a module
|
|
1407
|
+
* whose `alterTable` throws `UNSUPPORTED` for `alterPrimaryKey` (or omits the
|
|
1408
|
+
* hook); the built-in memory and store modules both re-key in place and never
|
|
1409
|
+
* reach it. See `rebuildViaShadowTable` for the two preconditions
|
|
1410
|
+
* `runAlterPrimaryKey` checks before calling this.
|
|
1133
1411
|
*/
|
|
1134
1412
|
async function rebuildTableWithNewShape(rctx, tableSchema, schema, survivingColumns, newPkDef) {
|
|
1135
1413
|
const tableName = tableSchema.name;
|
|
1136
1414
|
const schemaName = tableSchema.schemaName;
|
|
1137
|
-
|
|
1138
|
-
if (module instanceof MemoryTableModule) {
|
|
1139
|
-
await rebuildMemoryTable(rctx, tableSchema, schema, module, survivingColumns, newPkDef);
|
|
1140
|
-
}
|
|
1141
|
-
else {
|
|
1142
|
-
await rebuildViaShadowTable(rctx, tableSchema, schema, survivingColumns, newPkDef);
|
|
1143
|
-
}
|
|
1415
|
+
await rebuildViaShadowTable(rctx, tableSchema, schema, survivingColumns, newPkDef);
|
|
1144
1416
|
const finalSchema = schema.getTable(tableName);
|
|
1145
1417
|
if (finalSchema) {
|
|
1146
1418
|
rctx.db.schemaManager.getChangeNotifier().notifyChange({
|
|
@@ -1152,87 +1424,6 @@ async function rebuildTableWithNewShape(rctx, tableSchema, schema, survivingColu
|
|
|
1152
1424
|
});
|
|
1153
1425
|
}
|
|
1154
1426
|
}
|
|
1155
|
-
/**
|
|
1156
|
-
* MemoryTable rebuild: builds a new table via module.create() and copies rows
|
|
1157
|
-
* directly from the old manager, then swaps in the module and catalog.
|
|
1158
|
-
*/
|
|
1159
|
-
async function rebuildMemoryTable(rctx, tableSchema, schema, module, survivingColumns, newPkDef) {
|
|
1160
|
-
const tableName = tableSchema.name;
|
|
1161
|
-
const schemaName = tableSchema.schemaName;
|
|
1162
|
-
const oldKey = `${schemaName}.${tableName}`.toLowerCase();
|
|
1163
|
-
const oldMgr = module.tables.get(oldKey);
|
|
1164
|
-
if (!oldMgr) {
|
|
1165
|
-
throw new QuereusError(`Table '${tableName}' not found in module`, StatusCode.INTERNAL);
|
|
1166
|
-
}
|
|
1167
|
-
// Build column index mapping: old column index → new column index
|
|
1168
|
-
const survivingIndices = [];
|
|
1169
|
-
const newColumns = [];
|
|
1170
|
-
for (const colName of survivingColumns) {
|
|
1171
|
-
const oldIdx = tableSchema.columnIndexMap.get(colName.toLowerCase());
|
|
1172
|
-
if (oldIdx === undefined)
|
|
1173
|
-
continue;
|
|
1174
|
-
survivingIndices.push(oldIdx);
|
|
1175
|
-
newColumns.push(tableSchema.columns[oldIdx]);
|
|
1176
|
-
}
|
|
1177
|
-
// Remap PK indices from old schema to new column order
|
|
1178
|
-
const remappedPk = newPkDef.map(pk => {
|
|
1179
|
-
const newIdx = survivingIndices.indexOf(pk.index);
|
|
1180
|
-
if (newIdx === -1) {
|
|
1181
|
-
throw new QuereusError(`PK column index ${pk.index} not in surviving columns`, StatusCode.INTERNAL);
|
|
1182
|
-
}
|
|
1183
|
-
return { ...pk, index: newIdx };
|
|
1184
|
-
});
|
|
1185
|
-
// Build new schema
|
|
1186
|
-
const newSchema = Object.freeze({
|
|
1187
|
-
...tableSchema,
|
|
1188
|
-
columns: Object.freeze(newColumns),
|
|
1189
|
-
columnIndexMap: buildColumnIndexMap(newColumns),
|
|
1190
|
-
primaryKeyDefinition: Object.freeze(remappedPk),
|
|
1191
|
-
indexes: Object.freeze([]),
|
|
1192
|
-
});
|
|
1193
|
-
// Create the new table via the module API (goes directly to base layer)
|
|
1194
|
-
const shadowName = `${tableName}__rekey_${Date.now()}`;
|
|
1195
|
-
const shadowSchema = Object.freeze({ ...newSchema, name: shadowName });
|
|
1196
|
-
await module.create(rctx.db, shadowSchema);
|
|
1197
|
-
const shadowMgr = module.tables.get(`${schemaName}.${shadowName}`.toLowerCase());
|
|
1198
|
-
if (!shadowMgr) {
|
|
1199
|
-
throw new QuereusError(`Shadow table manager not found after create`, StatusCode.INTERNAL);
|
|
1200
|
-
}
|
|
1201
|
-
try {
|
|
1202
|
-
// Copy rows from old table to new, projecting surviving columns
|
|
1203
|
-
const rows = oldMgr.scanAllRows();
|
|
1204
|
-
for (const oldRow of rows) {
|
|
1205
|
-
const newRow = survivingIndices.map(i => oldRow[i]);
|
|
1206
|
-
shadowMgr.insertRow(newRow);
|
|
1207
|
-
}
|
|
1208
|
-
// Swap: remove old, remove shadow, re-register shadow under old name
|
|
1209
|
-
module.tables.delete(oldKey);
|
|
1210
|
-
module.tables.delete(`${schemaName}.${shadowName}`.toLowerCase());
|
|
1211
|
-
shadowMgr.renameTable(tableName);
|
|
1212
|
-
module.tables.set(oldKey, shadowMgr);
|
|
1213
|
-
// Update catalog
|
|
1214
|
-
schema.removeTable(tableName);
|
|
1215
|
-
schema.addTable(shadowMgr.tableSchema);
|
|
1216
|
-
// The old manager is now orphaned. Any active VirtualTableConnection bound
|
|
1217
|
-
// to it (e.g. from a prior insert in this session) is stale and must not be
|
|
1218
|
-
// reused against the rebuilt table — a reused-stale + fresh connection pair
|
|
1219
|
-
// leaves two candidates registered for the same table name, which trips
|
|
1220
|
-
// DeferredConstraintQueue.findConnection at the next commit. Mirror the
|
|
1221
|
-
// drop-table path's cleanup (schema/manager.ts dropTable). The orphaned
|
|
1222
|
-
// manager and its pending layer are discarded with the old manager, so no
|
|
1223
|
-
// rollback is needed; this intentionally bypasses implicit-transaction
|
|
1224
|
-
// deferral, exactly as drop table relies on.
|
|
1225
|
-
rctx.db.removeConnectionsForTable(schemaName, tableName);
|
|
1226
|
-
}
|
|
1227
|
-
catch (e) {
|
|
1228
|
-
// Clean up shadow on failure
|
|
1229
|
-
try {
|
|
1230
|
-
module.tables.delete(`${schemaName}.${shadowName}`.toLowerCase());
|
|
1231
|
-
}
|
|
1232
|
-
catch { /* ignore */ }
|
|
1233
|
-
throw e;
|
|
1234
|
-
}
|
|
1235
|
-
}
|
|
1236
1427
|
/**
|
|
1237
1428
|
* Build the shadow-table CREATE TABLE DDL used by the non-memory rebuild path.
|
|
1238
1429
|
*
|
|
@@ -1339,9 +1530,29 @@ async function runDropMaintained(rctx, tableSchema, schema) {
|
|
|
1339
1530
|
return null;
|
|
1340
1531
|
}
|
|
1341
1532
|
/**
|
|
1342
|
-
* Generic rebuild via shadow table SQL for
|
|
1533
|
+
* Generic rebuild via shadow table SQL, for a module without a native
|
|
1534
|
+
* `alterPrimaryKey`.
|
|
1535
|
+
*
|
|
1536
|
+
* Two preconditions the caller (`runAlterPrimaryKey`) enforces, because this rebuild has no
|
|
1537
|
+
* correct outcome without them:
|
|
1538
|
+
*
|
|
1539
|
+
* - **The module must implement `renameTable`.** The last step renames the shadow table over
|
|
1540
|
+
* the original; a module that files its rows under the table's name and never hears about
|
|
1541
|
+
* the rename keeps them under the shadow name while the catalog says otherwise, and the
|
|
1542
|
+
* rebuilt table cannot be connected at all.
|
|
1543
|
+
* - **No explicit transaction may be open.** The two halves have different transactional
|
|
1544
|
+
* lifetimes: the schema half (DROP + RENAME) escapes ROLLBACK on every
|
|
1545
|
+
* `DdlTransactionality` tier a built-in module reaches, while the row copy is staged in the
|
|
1546
|
+
* transaction and IS undone. A ROLLBACK would therefore keep the new empty table and
|
|
1547
|
+
* discard the copy of the rows it replaced — destroying data committed before the
|
|
1548
|
+
* transaction began. Making the schema half roll back needs transactional DDL no module
|
|
1549
|
+
* offers; making the data half survive would commit part of the user's transaction behind
|
|
1550
|
+
* their back.
|
|
1551
|
+
*
|
|
1552
|
+
* The four statements are engine scaffolding, not statements the application issued, so the
|
|
1553
|
+
* whole rebuild runs with the PUBLIC event channels suppressed — see the scope inside.
|
|
1343
1554
|
*/
|
|
1344
|
-
async function rebuildViaShadowTable(rctx, tableSchema,
|
|
1555
|
+
async function rebuildViaShadowTable(rctx, tableSchema, _schema, survivingColumns, newPkDef) {
|
|
1345
1556
|
const tableName = tableSchema.name;
|
|
1346
1557
|
const schemaName = tableSchema.schemaName;
|
|
1347
1558
|
const shadowName = `${tableName}__rekey_${Date.now()}`;
|
|
@@ -1349,19 +1560,40 @@ async function rebuildViaShadowTable(rctx, tableSchema, schema, survivingColumns
|
|
|
1349
1560
|
const qualifiedTable = qualifyTableName(schemaName, tableName);
|
|
1350
1561
|
const createDdl = buildShadowTableDdl(tableSchema, shadowName, survivingColumns, newPkDef);
|
|
1351
1562
|
const projection = survivingColumns.map(c => quoteIdentifier(c)).join(', ');
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1563
|
+
// The rebuild's statements are ordinary SQL, so without this scope they would raise
|
|
1564
|
+
// ordinary notifications describing the scaffolding rather than what the user asked for:
|
|
1565
|
+
// the copy announces every existing row as a fresh `insert` (relabelled onto the real
|
|
1566
|
+
// table by the trailing rename), and the create/drop pair announces a timestamped table
|
|
1567
|
+
// created and the real one dropped. A re-key changes no row and replaces no table, so all
|
|
1568
|
+
// of that is wrong. Covers the failure cleanup below too — a shadow table nobody was told
|
|
1569
|
+
// about must not announce its own drop.
|
|
1570
|
+
//
|
|
1571
|
+
// Only the PUBLIC channels are suppressed. The internal catalog change notifier keeps
|
|
1572
|
+
// firing throughout (it is what invalidates the optimizer's and the write path's cached
|
|
1573
|
+
// schemas), which is why the rebuilt table is immediately plannable under its new key.
|
|
1574
|
+
//
|
|
1575
|
+
// NOTE: a module whose own emitter defers delivery to its own commit — rather than
|
|
1576
|
+
// emitting during the write — can still leak the copy's inserts, because its events
|
|
1577
|
+
// arrive after this scope has closed. Conditional, not a live defect: no module that
|
|
1578
|
+
// reaches this rebuild behaves that way (memory and the store both re-key in place and
|
|
1579
|
+
// never enter it). If one ever does, suppression has to become name-keyed (covering the
|
|
1580
|
+
// shadow name as well as the real one) or the events have to be dropped out of the batch
|
|
1581
|
+
// after the fact.
|
|
1582
|
+
await rctx.db._getEventEmitter().withPublicEventsSuppressed(async () => {
|
|
1359
1583
|
try {
|
|
1360
|
-
await rctx.db._execWithinTransaction(
|
|
1584
|
+
await rctx.db._execWithinTransaction(createDdl);
|
|
1585
|
+
await rctx.db._execWithinTransaction(`insert into ${qualifiedShadow} (${projection}) select ${projection} from ${qualifiedTable}`);
|
|
1586
|
+
await rctx.db._execWithinTransaction(`drop table ${qualifiedTable}`);
|
|
1587
|
+
await rctx.db._execWithinTransaction(`alter table ${qualifiedShadow} rename to ${quoteIdentifier(tableName)}`);
|
|
1361
1588
|
}
|
|
1362
|
-
catch {
|
|
1363
|
-
|
|
1364
|
-
|
|
1589
|
+
catch (e) {
|
|
1590
|
+
try {
|
|
1591
|
+
await rctx.db._execWithinTransaction(`drop table if exists ${qualifiedShadow}`);
|
|
1592
|
+
}
|
|
1593
|
+
catch { /* ignore */ }
|
|
1594
|
+
throw e;
|
|
1595
|
+
}
|
|
1596
|
+
});
|
|
1365
1597
|
}
|
|
1366
1598
|
/**
|
|
1367
1599
|
* Propagates a table rename into every dependent schema object the catalog
|