@quereus/quereus 4.3.1 → 4.3.2
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 +25 -7
- package/dist/src/common/types.d.ts +9 -59
- package/dist/src/common/types.d.ts.map +1 -1
- package/dist/src/common/types.js.map +1 -1
- package/dist/src/core/database-assertions.d.ts +2 -2
- package/dist/src/core/database-assertions.d.ts.map +1 -1
- package/dist/src/core/database-assertions.js +4 -3
- package/dist/src/core/database-assertions.js.map +1 -1
- package/dist/src/core/database-external-changes.d.ts +1 -1
- package/dist/src/core/database-external-changes.js +1 -1
- package/dist/src/core/database-internal.d.ts.map +1 -1
- package/dist/src/core/database-materialized-views-analysis.d.ts +199 -0
- package/dist/src/core/database-materialized-views-analysis.d.ts.map +1 -0
- package/dist/src/core/database-materialized-views-analysis.js +502 -0
- package/dist/src/core/database-materialized-views-analysis.js.map +1 -0
- package/dist/src/core/database-materialized-views-apply.d.ts +280 -0
- package/dist/src/core/database-materialized-views-apply.d.ts.map +1 -0
- package/dist/src/core/database-materialized-views-apply.js +624 -0
- package/dist/src/core/database-materialized-views-apply.js.map +1 -0
- package/dist/src/core/database-materialized-views-plan-builders.d.ts +203 -0
- package/dist/src/core/database-materialized-views-plan-builders.d.ts.map +1 -0
- package/dist/src/core/database-materialized-views-plan-builders.js +1084 -0
- package/dist/src/core/database-materialized-views-plan-builders.js.map +1 -0
- package/dist/src/core/database-materialized-views-plans.d.ts +417 -0
- package/dist/src/core/database-materialized-views-plans.d.ts.map +1 -0
- package/dist/src/core/database-materialized-views-plans.js +13 -0
- package/dist/src/core/database-materialized-views-plans.js.map +1 -0
- package/dist/src/core/database-materialized-views.d.ts +11 -819
- package/dist/src/core/database-materialized-views.d.ts.map +1 -1
- package/dist/src/core/database-materialized-views.js +60 -2069
- package/dist/src/core/database-materialized-views.js.map +1 -1
- package/dist/src/core/database-transaction.d.ts +10 -1
- package/dist/src/core/database-transaction.d.ts.map +1 -1
- package/dist/src/core/database-transaction.js +16 -4
- package/dist/src/core/database-transaction.js.map +1 -1
- package/dist/src/core/database-watchers.d.ts.map +1 -1
- package/dist/src/core/database-watchers.js +2 -1
- package/dist/src/core/database-watchers.js.map +1 -1
- package/dist/src/core/database.d.ts +99 -13
- package/dist/src/core/database.d.ts.map +1 -1
- package/dist/src/core/database.js +250 -33
- package/dist/src/core/database.js.map +1 -1
- package/dist/src/core/derived-row-validator.d.ts +1 -1
- package/dist/src/core/derived-row-validator.d.ts.map +1 -1
- package/dist/src/core/derived-row-validator.js +5 -3
- package/dist/src/core/derived-row-validator.js.map +1 -1
- package/dist/src/core/statement.d.ts +8 -0
- package/dist/src/core/statement.d.ts.map +1 -1
- package/dist/src/core/statement.js +98 -18
- package/dist/src/core/statement.js.map +1 -1
- package/dist/src/emit/ast-stringify.d.ts.map +1 -1
- package/dist/src/emit/ast-stringify.js +24 -13
- package/dist/src/emit/ast-stringify.js.map +1 -1
- package/dist/src/func/builtins/explain.d.ts.map +1 -1
- package/dist/src/func/builtins/explain.js +2 -1
- package/dist/src/func/builtins/explain.js.map +1 -1
- package/dist/src/func/builtins/json.d.ts.map +1 -1
- package/dist/src/func/builtins/json.js +2 -1
- package/dist/src/func/builtins/json.js.map +1 -1
- package/dist/src/func/builtins/mutation.d.ts.map +1 -1
- package/dist/src/func/builtins/mutation.js +3 -2
- package/dist/src/func/builtins/mutation.js.map +1 -1
- package/dist/src/index.d.ts +16 -6
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +33 -7
- package/dist/src/index.js.map +1 -1
- package/dist/src/parser/ast.d.ts +2 -2
- package/dist/src/parser/lexer.d.ts +11 -1
- package/dist/src/parser/lexer.d.ts.map +1 -1
- package/dist/src/parser/lexer.js +40 -34
- package/dist/src/parser/lexer.js.map +1 -1
- package/dist/src/parser/parser.d.ts.map +1 -1
- package/dist/src/parser/parser.js +16 -9
- package/dist/src/parser/parser.js.map +1 -1
- package/dist/src/planner/analysis/authored-inverse.js +1 -1
- package/dist/src/planner/analysis/comparison-collation.d.ts +52 -0
- package/dist/src/planner/analysis/comparison-collation.d.ts.map +1 -1
- package/dist/src/planner/analysis/comparison-collation.js +84 -7
- package/dist/src/planner/analysis/comparison-collation.js.map +1 -1
- package/dist/src/planner/analysis/constraint-extractor.d.ts.map +1 -1
- package/dist/src/planner/analysis/constraint-extractor.js +64 -17
- package/dist/src/planner/analysis/constraint-extractor.js.map +1 -1
- package/dist/src/planner/analysis/coverage-prover.d.ts +1 -1
- package/dist/src/planner/analysis/coverage-prover.js +1 -1
- package/dist/src/planner/analysis/sat-checker.d.ts +8 -1
- package/dist/src/planner/analysis/sat-checker.d.ts.map +1 -1
- package/dist/src/planner/analysis/sat-checker.js +117 -22
- package/dist/src/planner/analysis/sat-checker.js.map +1 -1
- package/dist/src/planner/analysis/scalar-invertibility.d.ts +13 -4
- package/dist/src/planner/analysis/scalar-invertibility.d.ts.map +1 -1
- package/dist/src/planner/analysis/scalar-invertibility.js +12 -3
- package/dist/src/planner/analysis/scalar-invertibility.js.map +1 -1
- package/dist/src/planner/analysis/update-lineage.d.ts +1 -1
- package/dist/src/planner/analysis/update-lineage.js +1 -1
- package/dist/src/planner/analysis/update-lineage.js.map +1 -1
- package/dist/src/planner/analysis/view-complement.d.ts +2 -2
- package/dist/src/planner/building/delete.js +2 -2
- package/dist/src/planner/building/delete.js.map +1 -1
- package/dist/src/planner/building/dml-target.d.ts +2 -2
- package/dist/src/planner/building/dml-target.js +2 -2
- package/dist/src/planner/building/insert.d.ts.map +1 -1
- package/dist/src/planner/building/insert.js +53 -2
- package/dist/src/planner/building/insert.js.map +1 -1
- package/dist/src/planner/building/schema-resolution.d.ts +3 -0
- package/dist/src/planner/building/schema-resolution.d.ts.map +1 -1
- package/dist/src/planner/building/schema-resolution.js +4 -5
- package/dist/src/planner/building/schema-resolution.js.map +1 -1
- package/dist/src/planner/building/select.js +3 -3
- package/dist/src/planner/building/select.js.map +1 -1
- package/dist/src/planner/building/update.js +2 -2
- package/dist/src/planner/building/update.js.map +1 -1
- package/dist/src/planner/building/view-mutation-builder.js +7 -7
- package/dist/src/planner/building/view-mutation-builder.js.map +1 -1
- package/dist/src/planner/cache/materialization-advisory.d.ts +1 -2
- package/dist/src/planner/cache/materialization-advisory.d.ts.map +1 -1
- package/dist/src/planner/cache/materialization-advisory.js +21 -14
- package/dist/src/planner/cache/materialization-advisory.js.map +1 -1
- package/dist/src/planner/cache/reference-graph.d.ts +14 -1
- package/dist/src/planner/cache/reference-graph.d.ts.map +1 -1
- package/dist/src/planner/cache/reference-graph.js +26 -26
- package/dist/src/planner/cache/reference-graph.js.map +1 -1
- package/dist/src/planner/cost/index.d.ts +7 -3
- package/dist/src/planner/cost/index.d.ts.map +1 -1
- package/dist/src/planner/cost/index.js.map +1 -1
- package/dist/src/planner/debug.d.ts +3 -2
- package/dist/src/planner/debug.d.ts.map +1 -1
- package/dist/src/planner/debug.js +9 -3
- package/dist/src/planner/debug.js.map +1 -1
- package/dist/src/planner/framework/characteristics.d.ts +46 -19
- package/dist/src/planner/framework/characteristics.d.ts.map +1 -1
- package/dist/src/planner/framework/characteristics.js +50 -134
- package/dist/src/planner/framework/characteristics.js.map +1 -1
- package/dist/src/planner/framework/context.d.ts +8 -44
- package/dist/src/planner/framework/context.d.ts.map +1 -1
- package/dist/src/planner/framework/context.js +0 -91
- package/dist/src/planner/framework/context.js.map +1 -1
- package/dist/src/planner/framework/pass.d.ts +7 -0
- package/dist/src/planner/framework/pass.d.ts.map +1 -1
- package/dist/src/planner/framework/pass.js +84 -0
- package/dist/src/planner/framework/pass.js.map +1 -1
- package/dist/src/planner/framework/registry.d.ts +13 -42
- package/dist/src/planner/framework/registry.d.ts.map +1 -1
- package/dist/src/planner/framework/registry.js +14 -182
- package/dist/src/planner/framework/registry.js.map +1 -1
- package/dist/src/planner/mutation/backward-body.d.ts +2 -2
- package/dist/src/planner/mutation/cte-flatten.js +1 -1
- package/dist/src/planner/mutation/decomposition.d.ts +2 -2
- package/dist/src/planner/mutation/decomposition.js +1 -1
- package/dist/src/planner/mutation/lens-enforcement.d.ts.map +1 -1
- package/dist/src/planner/mutation/lens-enforcement.js +2 -1
- package/dist/src/planner/mutation/lens-enforcement.js.map +1 -1
- package/dist/src/planner/mutation/multi-source.d.ts +8 -8
- package/dist/src/planner/mutation/multi-source.js +11 -11
- package/dist/src/planner/mutation/multi-source.js.map +1 -1
- package/dist/src/planner/mutation/propagate.d.ts +1 -1
- package/dist/src/planner/mutation/propagate.js +1 -1
- package/dist/src/planner/mutation/scope-transform.d.ts +2 -2
- package/dist/src/planner/mutation/scope-transform.js +3 -3
- package/dist/src/planner/mutation/scope-transform.js.map +1 -1
- package/dist/src/planner/mutation/set-op.d.ts +1 -1
- package/dist/src/planner/mutation/set-op.d.ts.map +1 -1
- package/dist/src/planner/mutation/set-op.js +3 -2
- package/dist/src/planner/mutation/set-op.js.map +1 -1
- package/dist/src/planner/mutation/single-source.d.ts +3 -3
- package/dist/src/planner/mutation/single-source.js +9 -9
- package/dist/src/planner/mutation/single-source.js.map +1 -1
- package/dist/src/planner/nodes/aggregate-function.d.ts +3 -1
- package/dist/src/planner/nodes/aggregate-function.d.ts.map +1 -1
- package/dist/src/planner/nodes/aggregate-function.js +1 -0
- package/dist/src/planner/nodes/aggregate-function.js.map +1 -1
- package/dist/src/planner/nodes/aggregate-node.d.ts +1 -0
- package/dist/src/planner/nodes/aggregate-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/aggregate-node.js +8 -1
- 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 +3 -1
- package/dist/src/planner/nodes/alias-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 +3 -2
- package/dist/src/planner/nodes/asof-scan-node.js.map +1 -1
- package/dist/src/planner/nodes/asserted-keys-node.d.ts +1 -1
- package/dist/src/planner/nodes/asserted-keys-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/asserted-keys-node.js +5 -2
- 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 +3 -1
- package/dist/src/planner/nodes/async-gather-node.js.map +1 -1
- package/dist/src/planner/nodes/block.js +3 -3
- package/dist/src/planner/nodes/block.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 +5 -1
- package/dist/src/planner/nodes/bloom-join-node.js.map +1 -1
- package/dist/src/planner/nodes/cache-node.d.ts +1 -0
- package/dist/src/planner/nodes/cache-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/cache-node.js +1 -0
- package/dist/src/planner/nodes/cache-node.js.map +1 -1
- package/dist/src/planner/nodes/cte-node.d.ts +1 -0
- package/dist/src/planner/nodes/cte-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/cte-node.js +4 -1
- package/dist/src/planner/nodes/cte-node.js.map +1 -1
- package/dist/src/planner/nodes/distinct-node.js +3 -3
- package/dist/src/planner/nodes/distinct-node.js.map +1 -1
- package/dist/src/planner/nodes/dml-executor-node.d.ts +21 -0
- 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/envelope-scan-node.d.ts +1 -1
- package/dist/src/planner/nodes/envelope-scan-node.js +1 -1
- package/dist/src/planner/nodes/fanout-lookup-join-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/fanout-lookup-join-node.js +4 -2
- package/dist/src/planner/nodes/fanout-lookup-join-node.js.map +1 -1
- package/dist/src/planner/nodes/filter.d.ts +10 -2
- package/dist/src/planner/nodes/filter.d.ts.map +1 -1
- package/dist/src/planner/nodes/filter.js +81 -14
- package/dist/src/planner/nodes/filter.js.map +1 -1
- package/dist/src/planner/nodes/hash-aggregate.d.ts +12 -1
- package/dist/src/planner/nodes/hash-aggregate.d.ts.map +1 -1
- package/dist/src/planner/nodes/hash-aggregate.js +28 -1
- package/dist/src/planner/nodes/hash-aggregate.js.map +1 -1
- package/dist/src/planner/nodes/internal-recursive-cte-ref-node.d.ts +3 -1
- package/dist/src/planner/nodes/internal-recursive-cte-ref-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/internal-recursive-cte-ref-node.js +1 -0
- package/dist/src/planner/nodes/internal-recursive-cte-ref-node.js.map +1 -1
- package/dist/src/planner/nodes/join-node.d.ts +3 -1
- package/dist/src/planner/nodes/join-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/join-node.js +5 -5
- package/dist/src/planner/nodes/join-node.js.map +1 -1
- package/dist/src/planner/nodes/lens-auxiliary-access-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/lens-auxiliary-access-node.js +4 -1
- package/dist/src/planner/nodes/lens-auxiliary-access-node.js.map +1 -1
- package/dist/src/planner/nodes/limit-offset.d.ts +1 -0
- package/dist/src/planner/nodes/limit-offset.d.ts.map +1 -1
- package/dist/src/planner/nodes/limit-offset.js +4 -3
- 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 +6 -1
- package/dist/src/planner/nodes/merge-join-node.js.map +1 -1
- package/dist/src/planner/nodes/ordinal-slice-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/ordinal-slice-node.js +3 -1
- package/dist/src/planner/nodes/ordinal-slice-node.js.map +1 -1
- package/dist/src/planner/nodes/plan-node.d.ts +68 -5
- package/dist/src/planner/nodes/plan-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/plan-node.js +137 -24
- package/dist/src/planner/nodes/plan-node.js.map +1 -1
- package/dist/src/planner/nodes/project-node.d.ts +3 -2
- package/dist/src/planner/nodes/project-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/project-node.js +1 -0
- package/dist/src/planner/nodes/project-node.js.map +1 -1
- package/dist/src/planner/nodes/recursive-cte-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/recursive-cte-node.js +8 -2
- package/dist/src/planner/nodes/recursive-cte-node.js.map +1 -1
- package/dist/src/planner/nodes/reference.d.ts +5 -1
- package/dist/src/planner/nodes/reference.d.ts.map +1 -1
- package/dist/src/planner/nodes/reference.js +3 -0
- package/dist/src/planner/nodes/reference.js.map +1 -1
- package/dist/src/planner/nodes/remote-query-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/remote-query-node.js +3 -1
- package/dist/src/planner/nodes/remote-query-node.js.map +1 -1
- package/dist/src/planner/nodes/retrieve-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/retrieve-node.js +3 -1
- package/dist/src/planner/nodes/retrieve-node.js.map +1 -1
- package/dist/src/planner/nodes/set-operation-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/set-operation-node.js +3 -1
- package/dist/src/planner/nodes/set-operation-node.js.map +1 -1
- package/dist/src/planner/nodes/sink-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/sink-node.js +3 -1
- package/dist/src/planner/nodes/sink-node.js.map +1 -1
- package/dist/src/planner/nodes/sort.d.ts +2 -1
- package/dist/src/planner/nodes/sort.d.ts.map +1 -1
- package/dist/src/planner/nodes/sort.js +9 -5
- package/dist/src/planner/nodes/sort.js.map +1 -1
- package/dist/src/planner/nodes/stream-aggregate.d.ts +12 -1
- package/dist/src/planner/nodes/stream-aggregate.d.ts.map +1 -1
- package/dist/src/planner/nodes/stream-aggregate.js +32 -3
- package/dist/src/planner/nodes/stream-aggregate.js.map +1 -1
- package/dist/src/planner/nodes/table-access-nodes.d.ts +2 -1
- package/dist/src/planner/nodes/table-access-nodes.d.ts.map +1 -1
- package/dist/src/planner/nodes/table-access-nodes.js +2 -0
- package/dist/src/planner/nodes/table-access-nodes.js.map +1 -1
- package/dist/src/planner/nodes/view-mutation-node.d.ts +2 -2
- package/dist/src/planner/nodes/view-mutation-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/view-mutation-node.js +5 -1
- package/dist/src/planner/nodes/view-mutation-node.js.map +1 -1
- package/dist/src/planner/nodes/window-function.d.ts +3 -1
- package/dist/src/planner/nodes/window-function.d.ts.map +1 -1
- package/dist/src/planner/nodes/window-function.js +1 -0
- package/dist/src/planner/nodes/window-function.js.map +1 -1
- package/dist/src/planner/optimizer.d.ts +52 -8
- package/dist/src/planner/optimizer.d.ts.map +1 -1
- package/dist/src/planner/optimizer.js +885 -894
- package/dist/src/planner/optimizer.js.map +1 -1
- package/dist/src/planner/rules/access/rule-select-access-path.d.ts.map +1 -1
- package/dist/src/planner/rules/access/rule-select-access-path.js +235 -202
- 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 +2 -2
- package/dist/src/planner/rules/cache/rule-materialized-view-rewrite.js +2 -2
- package/dist/src/planner/rules/cache/rule-scalar-cse.d.ts +1 -1
- package/dist/src/planner/rules/cache/rule-scalar-cse.js +1 -1
- package/dist/src/planner/rules/join/rule-fanout-batched-outer.d.ts +1 -1
- package/dist/src/planner/rules/join/rule-fanout-batched-outer.js +1 -1
- package/dist/src/planner/rules/join/rule-inner-join-existence-recovery.d.ts +1 -1
- package/dist/src/planner/rules/join/rule-inner-join-existence-recovery.js +1 -1
- package/dist/src/planner/rules/join/rule-join-elimination.d.ts +1 -1
- package/dist/src/planner/rules/join/rule-join-elimination.js +1 -1
- package/dist/src/planner/rules/parallel/rule-async-gather-zip-by-key.js +5 -6
- package/dist/src/planner/rules/parallel/rule-async-gather-zip-by-key.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-contradiction.d.ts +2 -2
- package/dist/src/planner/rules/predicate/rule-filter-contradiction.d.ts.map +1 -1
- package/dist/src/planner/rules/predicate/rule-filter-contradiction.js +4 -3
- package/dist/src/planner/rules/predicate/rule-filter-contradiction.js.map +1 -1
- package/dist/src/planner/rules/predicate/rule-filter-selectivity.d.ts +19 -0
- package/dist/src/planner/rules/predicate/rule-filter-selectivity.d.ts.map +1 -0
- package/dist/src/planner/rules/predicate/rule-filter-selectivity.js +48 -0
- package/dist/src/planner/rules/predicate/rule-filter-selectivity.js.map +1 -0
- package/dist/src/planner/rules/predicate/rule-sargable-range-rewrite.js +12 -1
- package/dist/src/planner/rules/predicate/rule-sargable-range-rewrite.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 +22 -20
- package/dist/src/planner/rules/retrieve/rule-grow-retrieve.js.map +1 -1
- package/dist/src/planner/rules/shared/index-style-context.d.ts +39 -0
- package/dist/src/planner/rules/shared/index-style-context.d.ts.map +1 -0
- package/dist/src/planner/rules/shared/index-style-context.js +26 -0
- package/dist/src/planner/rules/shared/index-style-context.js.map +1 -0
- package/dist/src/planner/rules/sort/rule-orderby-fd-pruning.d.ts +1 -1
- package/dist/src/planner/rules/sort/rule-orderby-fd-pruning.js +1 -1
- package/dist/src/planner/rules/subquery/rule-anti-join-fk-empty.d.ts +1 -1
- package/dist/src/planner/rules/subquery/rule-anti-join-fk-empty.js +1 -1
- package/dist/src/planner/stats/analyze.d.ts.map +1 -1
- package/dist/src/planner/stats/analyze.js +2 -20
- package/dist/src/planner/stats/analyze.js.map +1 -1
- package/dist/src/planner/stats/histogram.d.ts.map +1 -1
- package/dist/src/planner/stats/histogram.js +4 -0
- package/dist/src/planner/stats/histogram.js.map +1 -1
- package/dist/src/planner/util/fd-utils.d.ts +2 -3
- package/dist/src/planner/util/fd-utils.d.ts.map +1 -1
- package/dist/src/planner/util/fd-utils.js +2 -3
- package/dist/src/planner/util/fd-utils.js.map +1 -1
- package/dist/src/planner/validation/plan-validator.d.ts +16 -0
- package/dist/src/planner/validation/plan-validator.d.ts.map +1 -1
- package/dist/src/planner/validation/plan-validator.js +36 -0
- package/dist/src/planner/validation/plan-validator.js.map +1 -1
- package/dist/src/runtime/async-util.d.ts +26 -0
- package/dist/src/runtime/async-util.d.ts.map +1 -1
- package/dist/src/runtime/async-util.js +139 -55
- package/dist/src/runtime/async-util.js.map +1 -1
- package/dist/src/runtime/context-helpers.d.ts +32 -4
- package/dist/src/runtime/context-helpers.d.ts.map +1 -1
- package/dist/src/runtime/context-helpers.js +26 -9
- package/dist/src/runtime/context-helpers.js.map +1 -1
- package/dist/src/runtime/deferred-constraint-queue.d.ts.map +1 -1
- package/dist/src/runtime/deferred-constraint-queue.js +2 -1
- package/dist/src/runtime/deferred-constraint-queue.js.map +1 -1
- package/dist/src/runtime/emission-context.d.ts +27 -3
- package/dist/src/runtime/emission-context.d.ts.map +1 -1
- package/dist/src/runtime/emission-context.js +38 -7
- package/dist/src/runtime/emission-context.js.map +1 -1
- package/dist/src/runtime/emit/add-constraint.d.ts.map +1 -1
- package/dist/src/runtime/emit/add-constraint.js +7 -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 +17 -13
- 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 +98 -9
- 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 +2 -1
- 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 +13 -10
- package/dist/src/runtime/emit/asof-scan.js.map +1 -1
- package/dist/src/runtime/emit/async-gather.d.ts.map +1 -1
- package/dist/src/runtime/emit/async-gather.js +4 -3
- package/dist/src/runtime/emit/async-gather.js.map +1 -1
- package/dist/src/runtime/emit/between.d.ts.map +1 -1
- package/dist/src/runtime/emit/between.js +2 -1
- 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 +122 -14
- package/dist/src/runtime/emit/binary.js.map +1 -1
- package/dist/src/runtime/emit/block.d.ts.map +1 -1
- package/dist/src/runtime/emit/block.js +2 -1
- package/dist/src/runtime/emit/block.js.map +1 -1
- package/dist/src/runtime/emit/bloom-join.d.ts.map +1 -1
- package/dist/src/runtime/emit/bloom-join.js +20 -8
- package/dist/src/runtime/emit/bloom-join.js.map +1 -1
- package/dist/src/runtime/emit/cache.d.ts.map +1 -1
- package/dist/src/runtime/emit/cache.js +2 -1
- package/dist/src/runtime/emit/cache.js.map +1 -1
- package/dist/src/runtime/emit/case.d.ts.map +1 -1
- package/dist/src/runtime/emit/case.js +66 -45
- 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 +2 -1
- 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 +13 -7
- package/dist/src/runtime/emit/constraint-check.js.map +1 -1
- package/dist/src/runtime/emit/create-assertion.d.ts.map +1 -1
- package/dist/src/runtime/emit/create-assertion.js +2 -1
- package/dist/src/runtime/emit/create-assertion.js.map +1 -1
- package/dist/src/runtime/emit/create-index.d.ts.map +1 -1
- package/dist/src/runtime/emit/create-index.js +12 -1
- package/dist/src/runtime/emit/create-index.js.map +1 -1
- package/dist/src/runtime/emit/create-table.d.ts.map +1 -1
- package/dist/src/runtime/emit/create-table.js +12 -1
- package/dist/src/runtime/emit/create-table.js.map +1 -1
- package/dist/src/runtime/emit/cte-reference.d.ts.map +1 -1
- package/dist/src/runtime/emit/cte-reference.js +2 -1
- package/dist/src/runtime/emit/cte-reference.js.map +1 -1
- package/dist/src/runtime/emit/cte.d.ts.map +1 -1
- package/dist/src/runtime/emit/cte.js +2 -1
- package/dist/src/runtime/emit/cte.js.map +1 -1
- package/dist/src/runtime/emit/ddl-transaction-policy.d.ts +50 -0
- package/dist/src/runtime/emit/ddl-transaction-policy.d.ts.map +1 -0
- package/dist/src/runtime/emit/ddl-transaction-policy.js +69 -0
- package/dist/src/runtime/emit/ddl-transaction-policy.js.map +1 -0
- package/dist/src/runtime/emit/delete.d.ts.map +1 -1
- package/dist/src/runtime/emit/delete.js +2 -1
- package/dist/src/runtime/emit/delete.js.map +1 -1
- package/dist/src/runtime/emit/distinct.d.ts.map +1 -1
- package/dist/src/runtime/emit/distinct.js +2 -1
- 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 +70 -31
- package/dist/src/runtime/emit/dml-executor.js.map +1 -1
- package/dist/src/runtime/emit/drop-assertion.d.ts.map +1 -1
- package/dist/src/runtime/emit/drop-assertion.js +2 -1
- package/dist/src/runtime/emit/drop-assertion.js.map +1 -1
- package/dist/src/runtime/emit/drop-index.d.ts.map +1 -1
- package/dist/src/runtime/emit/drop-index.js +17 -1
- package/dist/src/runtime/emit/drop-index.js.map +1 -1
- package/dist/src/runtime/emit/drop-table.d.ts.map +1 -1
- package/dist/src/runtime/emit/drop-table.js +11 -1
- package/dist/src/runtime/emit/drop-table.js.map +1 -1
- package/dist/src/runtime/emit/eager-prefetch.d.ts.map +1 -1
- package/dist/src/runtime/emit/eager-prefetch.js +2 -1
- package/dist/src/runtime/emit/eager-prefetch.js.map +1 -1
- package/dist/src/runtime/emit/envelope-scan.d.ts.map +1 -1
- package/dist/src/runtime/emit/envelope-scan.js +2 -1
- package/dist/src/runtime/emit/envelope-scan.js.map +1 -1
- package/dist/src/runtime/emit/fanout-lookup-join.d.ts.map +1 -1
- package/dist/src/runtime/emit/fanout-lookup-join.js +3 -2
- package/dist/src/runtime/emit/fanout-lookup-join.js.map +1 -1
- package/dist/src/runtime/emit/filter.d.ts.map +1 -1
- package/dist/src/runtime/emit/filter.js +8 -3
- 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 -11
- 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 +2 -1
- package/dist/src/runtime/emit/insert.js.map +1 -1
- package/dist/src/runtime/emit/join.d.ts.map +1 -1
- package/dist/src/runtime/emit/join.js +20 -6
- package/dist/src/runtime/emit/join.js.map +1 -1
- package/dist/src/runtime/emit/limit-offset.d.ts.map +1 -1
- package/dist/src/runtime/emit/limit-offset.js +2 -1
- package/dist/src/runtime/emit/limit-offset.js.map +1 -1
- package/dist/src/runtime/emit/literal.d.ts.map +1 -1
- package/dist/src/runtime/emit/literal.js +2 -1
- package/dist/src/runtime/emit/literal.js.map +1 -1
- package/dist/src/runtime/emit/materialized-view-helpers.d.ts +22 -0
- package/dist/src/runtime/emit/materialized-view-helpers.d.ts.map +1 -1
- package/dist/src/runtime/emit/materialized-view-helpers.js +123 -12
- 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 +6 -0
- 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 +14 -4
- package/dist/src/runtime/emit/merge-join.js.map +1 -1
- package/dist/src/runtime/emit/ordinal-slice.d.ts.map +1 -1
- package/dist/src/runtime/emit/ordinal-slice.js +2 -1
- package/dist/src/runtime/emit/ordinal-slice.js.map +1 -1
- package/dist/src/runtime/emit/pragma.d.ts.map +1 -1
- package/dist/src/runtime/emit/pragma.js +2 -1
- package/dist/src/runtime/emit/pragma.js.map +1 -1
- package/dist/src/runtime/emit/project.d.ts.map +1 -1
- package/dist/src/runtime/emit/project.js +7 -2
- package/dist/src/runtime/emit/project.js.map +1 -1
- package/dist/src/runtime/emit/recursive-cte.d.ts.map +1 -1
- package/dist/src/runtime/emit/recursive-cte.js +2 -1
- package/dist/src/runtime/emit/recursive-cte.js.map +1 -1
- package/dist/src/runtime/emit/returning.d.ts.map +1 -1
- package/dist/src/runtime/emit/returning.js +7 -2
- package/dist/src/runtime/emit/returning.js.map +1 -1
- package/dist/src/runtime/emit/scalar-function.d.ts.map +1 -1
- package/dist/src/runtime/emit/scalar-function.js +2 -1
- package/dist/src/runtime/emit/scalar-function.js.map +1 -1
- package/dist/src/runtime/emit/scan.d.ts.map +1 -1
- package/dist/src/runtime/emit/scan.js +55 -17
- 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 +6 -5
- package/dist/src/runtime/emit/schema-declarative.js.map +1 -1
- package/dist/src/runtime/emit/sequencing.d.ts.map +1 -1
- package/dist/src/runtime/emit/sequencing.js +2 -1
- package/dist/src/runtime/emit/sequencing.js.map +1 -1
- package/dist/src/runtime/emit/set-operation.d.ts.map +1 -1
- package/dist/src/runtime/emit/set-operation.js +6 -5
- package/dist/src/runtime/emit/set-operation.js.map +1 -1
- package/dist/src/runtime/emit/sink.d.ts.map +1 -1
- package/dist/src/runtime/emit/sink.js +2 -1
- package/dist/src/runtime/emit/sink.js.map +1 -1
- package/dist/src/runtime/emit/sort.d.ts.map +1 -1
- package/dist/src/runtime/emit/sort.js +2 -1
- 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 +42 -23
- package/dist/src/runtime/emit/subquery.js.map +1 -1
- package/dist/src/runtime/emit/table-valued-function.d.ts.map +1 -1
- package/dist/src/runtime/emit/table-valued-function.js +2 -1
- package/dist/src/runtime/emit/table-valued-function.js.map +1 -1
- package/dist/src/runtime/emit/temporal-arithmetic.d.ts.map +1 -1
- package/dist/src/runtime/emit/temporal-arithmetic.js +2 -1
- package/dist/src/runtime/emit/temporal-arithmetic.js.map +1 -1
- package/dist/src/runtime/emit/transaction.d.ts.map +1 -1
- package/dist/src/runtime/emit/transaction.js +2 -1
- package/dist/src/runtime/emit/transaction.js.map +1 -1
- package/dist/src/runtime/emit/unary.d.ts.map +1 -1
- package/dist/src/runtime/emit/unary.js +2 -1
- package/dist/src/runtime/emit/unary.js.map +1 -1
- package/dist/src/runtime/emit/update.d.ts.map +1 -1
- package/dist/src/runtime/emit/update.js +2 -1
- package/dist/src/runtime/emit/update.js.map +1 -1
- package/dist/src/runtime/emit/values.d.ts.map +1 -1
- package/dist/src/runtime/emit/values.js +2 -1
- package/dist/src/runtime/emit/values.js.map +1 -1
- package/dist/src/runtime/emit/view-mutation.d.ts +1 -1
- package/dist/src/runtime/emit/view-mutation.d.ts.map +1 -1
- package/dist/src/runtime/emit/view-mutation.js +6 -3
- package/dist/src/runtime/emit/view-mutation.js.map +1 -1
- package/dist/src/runtime/emit/window.d.ts.map +1 -1
- package/dist/src/runtime/emit/window.js +26 -9
- package/dist/src/runtime/emit/window.js.map +1 -1
- package/dist/src/runtime/emitters.d.ts +11 -3
- package/dist/src/runtime/emitters.d.ts.map +1 -1
- package/dist/src/runtime/emitters.js +13 -22
- package/dist/src/runtime/emitters.js.map +1 -1
- package/dist/src/runtime/foreign-key-actions.d.ts.map +1 -1
- package/dist/src/runtime/foreign-key-actions.js +39 -13
- package/dist/src/runtime/foreign-key-actions.js.map +1 -1
- package/dist/src/runtime/parallel-driver.d.ts +18 -4
- package/dist/src/runtime/parallel-driver.d.ts.map +1 -1
- package/dist/src/runtime/parallel-driver.js +72 -18
- package/dist/src/runtime/parallel-driver.js.map +1 -1
- package/dist/src/runtime/scheduler.d.ts +56 -7
- package/dist/src/runtime/scheduler.d.ts.map +1 -1
- package/dist/src/runtime/scheduler.js +223 -200
- package/dist/src/runtime/scheduler.js.map +1 -1
- package/dist/src/runtime/strict-flags.d.ts +22 -0
- package/dist/src/runtime/strict-flags.d.ts.map +1 -0
- package/dist/src/runtime/strict-flags.js +26 -0
- package/dist/src/runtime/strict-flags.js.map +1 -0
- package/dist/src/runtime/strict-fork.d.ts +4 -4
- package/dist/src/runtime/strict-fork.d.ts.map +1 -1
- package/dist/src/runtime/strict-fork.js +175 -31
- package/dist/src/runtime/strict-fork.js.map +1 -1
- package/dist/src/runtime/types.d.ts +66 -4
- package/dist/src/runtime/types.d.ts.map +1 -1
- package/dist/src/runtime/types.js +37 -0
- package/dist/src/runtime/types.js.map +1 -1
- package/dist/src/runtime/utils.d.ts.map +1 -1
- package/dist/src/runtime/utils.js +8 -17
- package/dist/src/runtime/utils.js.map +1 -1
- package/dist/src/schema/column.d.ts +8 -0
- 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.js +5 -0
- package/dist/src/schema/ddl-generator.js.map +1 -1
- package/dist/src/schema/lens-compiler.js +2 -2
- package/dist/src/schema/lens-compiler.js.map +1 -1
- package/dist/src/schema/lens-prover.d.ts.map +1 -1
- package/dist/src/schema/lens-prover.js +2 -3
- package/dist/src/schema/lens-prover.js.map +1 -1
- package/dist/src/schema/lens.d.ts +1 -1
- package/dist/src/schema/manager.d.ts.map +1 -1
- package/dist/src/schema/manager.js +7 -2
- package/dist/src/schema/manager.js.map +1 -1
- package/dist/src/schema/rename-rewriter.d.ts +61 -0
- package/dist/src/schema/rename-rewriter.d.ts.map +1 -1
- package/dist/src/schema/rename-rewriter.js +77 -0
- package/dist/src/schema/rename-rewriter.js.map +1 -1
- package/dist/src/schema/table.d.ts +36 -8
- package/dist/src/schema/table.d.ts.map +1 -1
- package/dist/src/schema/table.js +61 -11
- package/dist/src/schema/table.js.map +1 -1
- package/dist/src/schema/unique-enforcement.d.ts +28 -5
- package/dist/src/schema/unique-enforcement.d.ts.map +1 -1
- package/dist/src/schema/unique-enforcement.js +37 -5
- package/dist/src/schema/unique-enforcement.js.map +1 -1
- package/dist/src/schema/view.d.ts +1 -1
- package/dist/src/schema/view.js +1 -1
- package/dist/src/types/json-type.d.ts.map +1 -1
- package/dist/src/types/json-type.js +18 -8
- package/dist/src/types/json-type.js.map +1 -1
- package/dist/src/types/logical-type.d.ts +26 -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/util/comparison.d.ts +83 -59
- package/dist/src/util/comparison.d.ts.map +1 -1
- package/dist/src/util/comparison.js +191 -131
- package/dist/src/util/comparison.js.map +1 -1
- package/dist/src/util/json-canonical.d.ts +34 -0
- package/dist/src/util/json-canonical.d.ts.map +1 -0
- package/dist/src/util/json-canonical.js +32 -0
- package/dist/src/util/json-canonical.js.map +1 -0
- package/dist/src/util/key-serializer.d.ts +10 -3
- package/dist/src/util/key-serializer.d.ts.map +1 -1
- package/dist/src/util/key-serializer.js +43 -17
- package/dist/src/util/key-serializer.js.map +1 -1
- package/dist/src/util/key-tuple-codec.d.ts +37 -0
- package/dist/src/util/key-tuple-codec.d.ts.map +1 -0
- package/dist/src/util/key-tuple-codec.js +65 -0
- package/dist/src/util/key-tuple-codec.js.map +1 -0
- package/dist/src/util/latches.d.ts +29 -3
- package/dist/src/util/latches.d.ts.map +1 -1
- package/dist/src/util/latches.js +60 -6
- package/dist/src/util/latches.js.map +1 -1
- package/dist/src/util/patterns.d.ts +22 -8
- package/dist/src/util/patterns.d.ts.map +1 -1
- package/dist/src/util/patterns.js +87 -16
- package/dist/src/util/patterns.js.map +1 -1
- package/dist/src/util/qualified-name.d.ts +10 -0
- package/dist/src/util/qualified-name.d.ts.map +1 -0
- package/dist/src/util/qualified-name.js +15 -0
- package/dist/src/util/qualified-name.js.map +1 -0
- package/dist/src/vtab/backing-host.d.ts +8 -1
- package/dist/src/vtab/backing-host.d.ts.map +1 -1
- package/dist/src/vtab/backing-host.js +7 -0
- package/dist/src/vtab/backing-host.js.map +1 -1
- package/dist/src/vtab/best-access-plan.d.ts +18 -0
- package/dist/src/vtab/best-access-plan.d.ts.map +1 -1
- package/dist/src/vtab/best-access-plan.js +15 -0
- package/dist/src/vtab/best-access-plan.js.map +1 -1
- package/dist/src/vtab/capabilities.d.ts +44 -0
- package/dist/src/vtab/capabilities.d.ts.map +1 -1
- package/dist/src/vtab/filter-info.d.ts +42 -0
- package/dist/src/vtab/filter-info.d.ts.map +1 -1
- package/dist/src/vtab/filter-info.js +137 -1
- package/dist/src/vtab/filter-info.js.map +1 -1
- package/dist/src/vtab/idx-str.d.ts +62 -0
- package/dist/src/vtab/idx-str.d.ts.map +1 -0
- package/dist/src/vtab/idx-str.js +130 -0
- package/dist/src/vtab/idx-str.js.map +1 -0
- package/dist/src/vtab/index-descriptor.d.ts +122 -0
- package/dist/src/vtab/index-descriptor.d.ts.map +1 -0
- package/dist/src/vtab/index-descriptor.js +104 -0
- package/dist/src/vtab/index-descriptor.js.map +1 -0
- package/dist/src/vtab/mapping-advertisement.d.ts +1 -1
- package/dist/src/vtab/memory/index.d.ts +12 -4
- package/dist/src/vtab/memory/index.d.ts.map +1 -1
- package/dist/src/vtab/memory/index.js +17 -9
- package/dist/src/vtab/memory/index.js.map +1 -1
- package/dist/src/vtab/memory/layer/base.d.ts +85 -31
- package/dist/src/vtab/memory/layer/base.d.ts.map +1 -1
- package/dist/src/vtab/memory/layer/base.js +127 -86
- package/dist/src/vtab/memory/layer/base.js.map +1 -1
- package/dist/src/vtab/memory/layer/connection.d.ts +27 -0
- package/dist/src/vtab/memory/layer/connection.d.ts.map +1 -1
- package/dist/src/vtab/memory/layer/connection.js +36 -1
- package/dist/src/vtab/memory/layer/connection.js.map +1 -1
- package/dist/src/vtab/memory/layer/interface.d.ts +24 -4
- package/dist/src/vtab/memory/layer/interface.d.ts.map +1 -1
- package/dist/src/vtab/memory/layer/manager.d.ts +212 -16
- package/dist/src/vtab/memory/layer/manager.d.ts.map +1 -1
- package/dist/src/vtab/memory/layer/manager.js +754 -170
- package/dist/src/vtab/memory/layer/manager.js.map +1 -1
- package/dist/src/vtab/memory/layer/plan-filter.d.ts +26 -1
- package/dist/src/vtab/memory/layer/plan-filter.d.ts.map +1 -1
- package/dist/src/vtab/memory/layer/plan-filter.js +29 -11
- package/dist/src/vtab/memory/layer/plan-filter.js.map +1 -1
- package/dist/src/vtab/memory/layer/safe-iterate.d.ts +2 -2
- package/dist/src/vtab/memory/layer/safe-iterate.d.ts.map +1 -1
- package/dist/src/vtab/memory/layer/safe-iterate.js +2 -2
- package/dist/src/vtab/memory/layer/safe-iterate.js.map +1 -1
- package/dist/src/vtab/memory/layer/scan-layer.d.ts +5 -1
- package/dist/src/vtab/memory/layer/scan-layer.d.ts.map +1 -1
- package/dist/src/vtab/memory/layer/scan-layer.js +38 -22
- package/dist/src/vtab/memory/layer/scan-layer.js.map +1 -1
- package/dist/src/vtab/memory/layer/scan-plan.d.ts.map +1 -1
- package/dist/src/vtab/memory/layer/scan-plan.js +13 -21
- package/dist/src/vtab/memory/layer/scan-plan.js.map +1 -1
- package/dist/src/vtab/memory/layer/transaction.d.ts +169 -7
- package/dist/src/vtab/memory/layer/transaction.d.ts.map +1 -1
- package/dist/src/vtab/memory/layer/transaction.js +334 -9
- package/dist/src/vtab/memory/layer/transaction.js.map +1 -1
- package/dist/src/vtab/memory/module.d.ts +11 -4
- package/dist/src/vtab/memory/module.d.ts.map +1 -1
- package/dist/src/vtab/memory/module.js +35 -16
- package/dist/src/vtab/memory/module.js.map +1 -1
- package/dist/src/vtab/memory/table.d.ts +30 -4
- package/dist/src/vtab/memory/table.d.ts.map +1 -1
- package/dist/src/vtab/memory/table.js +63 -15
- package/dist/src/vtab/memory/table.js.map +1 -1
- package/dist/src/vtab/memory/utils/predicate.d.ts +9 -1
- package/dist/src/vtab/memory/utils/predicate.d.ts.map +1 -1
- package/dist/src/vtab/memory/utils/predicate.js +35 -14
- package/dist/src/vtab/memory/utils/predicate.js.map +1 -1
- package/dist/src/vtab/memory/utils/primary-key-encode.d.ts.map +1 -1
- package/dist/src/vtab/memory/utils/primary-key-encode.js +12 -6
- package/dist/src/vtab/memory/utils/primary-key-encode.js.map +1 -1
- package/dist/src/vtab/memory/utils/primary-key.d.ts +6 -1
- package/dist/src/vtab/memory/utils/primary-key.d.ts.map +1 -1
- package/dist/src/vtab/memory/utils/primary-key.js +12 -8
- package/dist/src/vtab/memory/utils/primary-key.js.map +1 -1
- package/dist/src/vtab/module.d.ts +38 -14
- package/dist/src/vtab/module.d.ts.map +1 -1
- package/dist/src/vtab/table.d.ts +41 -2
- package/dist/src/vtab/table.d.ts.map +1 -1
- package/dist/src/vtab/table.js +19 -0
- package/dist/src/vtab/table.js.map +1 -1
- package/package.json +5 -4
- package/dist/src/planner/rules/cache/rule-materialization-advisory.d.ts +0 -18
- package/dist/src/planner/rules/cache/rule-materialization-advisory.d.ts.map +0 -1
- package/dist/src/planner/rules/cache/rule-materialization-advisory.js +0 -65
- package/dist/src/planner/rules/cache/rule-materialization-advisory.js.map +0 -1
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
import { buildColumnIndexMap, columnDefToSchema, resolvePkDefaultConflict, resolveNamedConstraintClass, validateCollationForType } from '../../../schema/table.js';
|
|
2
2
|
import { BTree } from 'inheritree';
|
|
3
3
|
import { StatusCode } from '../../../common/types.js';
|
|
4
|
-
import { BaseLayer } from './base.js';
|
|
4
|
+
import { BaseLayer, iteratePrimaryRows, populateIndexFromRows, populateIndexFromRowsAsync } from './base.js';
|
|
5
5
|
import { TransactionLayer } from './transaction.js';
|
|
6
6
|
import { MemoryTableConnection } from './connection.js';
|
|
7
7
|
import { MemoryVirtualTableConnection } from '../connection.js';
|
|
8
|
-
import { Latches } from '../../../util/latches.js';
|
|
9
8
|
import { QuereusError } from '../../../common/errors.js';
|
|
10
9
|
import { ConflictResolution } from '../../../common/constants.js';
|
|
11
10
|
import { buildUniqueConstraintSchema, buildForeignKeyConstraintSchema, buildCheckConstraintSchema, validateForeignKeyOverExistingRows, maintainedTableUniqueViolationError } from '../../../schema/constraint-builder.js';
|
|
12
|
-
import { uniqueEnforcementCollations } from '../../../schema/unique-enforcement.js';
|
|
13
|
-
import { compareSqlValues, rowsValueIdentical, normalizeCollationName } from '../../../util/comparison.js';
|
|
11
|
+
import { indexEnforcesUnique, uniqueEnforcementCollations } from '../../../schema/unique-enforcement.js';
|
|
12
|
+
import { compareSqlValues, compareSqlValuesFast, rowsValueIdentical, normalizeCollationName } from '../../../util/comparison.js';
|
|
14
13
|
import { scanLayer as scanLayerImpl } from './scan-layer.js';
|
|
15
14
|
import { createPrimaryKeyFunctions, buildPrimaryKeyFromValues } from '../utils/primary-key.js';
|
|
16
15
|
import { createMemoryTableLoggers } from '../utils/logging.js';
|
|
@@ -18,6 +17,8 @@ import { tryFoldLiteral } from '../../../parser/utils.js';
|
|
|
18
17
|
import { validateAndParse } from '../../../types/validation.js';
|
|
19
18
|
import { inferType } from '../../../types/registry.js';
|
|
20
19
|
import { compilePredicate } from '../utils/predicate.js';
|
|
20
|
+
import { renameColumnInIndexPredicates } from '../../../schema/rename-rewriter.js';
|
|
21
|
+
import { MemoryIndex } from '../index.js';
|
|
21
22
|
let tableManagerCounter = 0;
|
|
22
23
|
const logger = createMemoryTableLoggers('layer:manager');
|
|
23
24
|
export class MemoryTableManager {
|
|
@@ -31,6 +32,13 @@ export class MemoryTableManager {
|
|
|
31
32
|
connections = new Map();
|
|
32
33
|
isReadOnly;
|
|
33
34
|
tableSchema;
|
|
35
|
+
/**
|
|
36
|
+
* `db.getCollationResolver()`, bound once. Every comparator this manager or its
|
|
37
|
+
* layers build — primary key, secondary index, UNIQUE enforcement, scan bounds —
|
|
38
|
+
* resolves names through it, so a collation registered on *this* database is
|
|
39
|
+
* honored and one registered on no database raises instead of byte-ordering.
|
|
40
|
+
*/
|
|
41
|
+
collationResolver;
|
|
34
42
|
primaryKeyFunctions;
|
|
35
43
|
/**
|
|
36
44
|
* Implicit covering structures: constraint identity → the auto-index that
|
|
@@ -46,6 +54,7 @@ export class MemoryTableManager {
|
|
|
46
54
|
constructor(db, _moduleName, schemaName, tableName, initialSchema, readOnly = false, eventEmitter) {
|
|
47
55
|
this.managerId = tableManagerCounter++;
|
|
48
56
|
this.db = db;
|
|
57
|
+
this.collationResolver = db.getCollationResolver();
|
|
49
58
|
this.schemaName = schemaName;
|
|
50
59
|
this._tableName = tableName;
|
|
51
60
|
this.tableSchema = initialSchema;
|
|
@@ -63,11 +72,11 @@ export class MemoryTableManager {
|
|
|
63
72
|
this.ensureUniqueConstraintIndexes();
|
|
64
73
|
}
|
|
65
74
|
this.initializePrimaryKeyFunctions();
|
|
66
|
-
this.baseLayer = new BaseLayer(this.tableSchema);
|
|
75
|
+
this.baseLayer = new BaseLayer(this.tableSchema, this.collationResolver);
|
|
67
76
|
this._currentCommittedLayer = this.baseLayer;
|
|
68
77
|
}
|
|
69
78
|
initializePrimaryKeyFunctions() {
|
|
70
|
-
this.primaryKeyFunctions = createPrimaryKeyFunctions(this.tableSchema);
|
|
79
|
+
this.primaryKeyFunctions = createPrimaryKeyFunctions(this.tableSchema, this.collationResolver);
|
|
71
80
|
}
|
|
72
81
|
/**
|
|
73
82
|
* One-bit guard on `Schema.kind` (docs/lens.md § Departures): true when this
|
|
@@ -324,70 +333,84 @@ export class MemoryTableManager {
|
|
|
324
333
|
connection.readLayer = this._currentCommittedLayer;
|
|
325
334
|
return;
|
|
326
335
|
}
|
|
327
|
-
// Capture changes from pendingLayer and any ancestor TransactionLayers
|
|
328
|
-
// up to (but not including) the currentCommittedLayer. Ancestor layers
|
|
329
|
-
// in the chain are typically savepoint-promoted in-transaction layers
|
|
330
|
-
// whose pendingChanges were never emitted (they were never directly
|
|
331
|
-
// committed). Walking the chain ensures events from earlier writes
|
|
332
|
-
// in the same transaction aren't dropped just because a SAVEPOINT
|
|
333
|
-
// promotion swapped the pending layer mid-transaction.
|
|
334
|
-
const eventChunks = [];
|
|
335
|
-
{
|
|
336
|
-
let layer = pendingLayer;
|
|
337
|
-
while (layer && layer !== this._currentCommittedLayer) {
|
|
338
|
-
if (layer instanceof TransactionLayer) {
|
|
339
|
-
const events = layer.getPendingChanges();
|
|
340
|
-
if (events.length > 0)
|
|
341
|
-
eventChunks.push(events);
|
|
342
|
-
}
|
|
343
|
-
layer = layer.getParent();
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
// Chunks are newest-layer-first; reverse to chronological order while
|
|
347
|
-
// preserving intra-layer event order.
|
|
348
|
-
const changes = eventChunks.reverse().flat();
|
|
349
336
|
const lockKey = `MemoryTable.Commit:${this.schemaName}.${this._tableName}`;
|
|
350
|
-
const release = await
|
|
337
|
+
const release = await this.db.latches.acquire(lockKey);
|
|
351
338
|
logger.debugLog(`[Commit ${connection.connectionId}] Acquired lock for ${this._tableName}`);
|
|
352
339
|
try {
|
|
353
|
-
//
|
|
354
|
-
//
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
//
|
|
365
|
-
//
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
340
|
+
// Relate the pending layer's chain to the current committed head.
|
|
341
|
+
//
|
|
342
|
+
// Case A — the head is an ancestor of the pending layer: pending forked
|
|
343
|
+
// off (a descendant of) the current head, so its chain already
|
|
344
|
+
// contains everything committed so far. Publish it wholesale.
|
|
345
|
+
// Case B — the head advanced past the pending layer's fork point
|
|
346
|
+
// (a sibling connection committed a disjoint change to the same table
|
|
347
|
+
// in a coordinated multi-connection commit): pending and head share a
|
|
348
|
+
// common ancestor — the fork point — that is a *proper* ancestor of
|
|
349
|
+
// the head. Rebase pending's own writes onto the head so the sibling's
|
|
350
|
+
// already-committed rows are not discarded (the bug this guards).
|
|
351
|
+
// Case C — no common ancestor reachable: a genuinely stale commit. Roll
|
|
352
|
+
// back with BUSY outside a coordinated commit (the caller can retry);
|
|
353
|
+
// inside one, preserve the prior wholesale fallback.
|
|
354
|
+
let headIsAncestorOfPending = false;
|
|
355
|
+
{
|
|
356
|
+
let cur = pendingLayer;
|
|
357
|
+
while (cur) {
|
|
358
|
+
if (cur === this._currentCommittedLayer) {
|
|
359
|
+
headIsAncestorOfPending = true;
|
|
372
360
|
break;
|
|
373
361
|
}
|
|
374
|
-
|
|
362
|
+
cur = cur.getParent();
|
|
375
363
|
}
|
|
376
364
|
}
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
365
|
+
let committedLayer;
|
|
366
|
+
let changes;
|
|
367
|
+
if (headIsAncestorOfPending) {
|
|
368
|
+
// Case A: the un-emitted in-transaction event span ends at the head.
|
|
369
|
+
changes = this.collectPendingChanges(pendingLayer, this._currentCommittedLayer);
|
|
370
|
+
pendingLayer.markCommitted();
|
|
371
|
+
committedLayer = pendingLayer;
|
|
372
|
+
}
|
|
373
|
+
else {
|
|
374
|
+
// Find the fork point: the deepest layer present in BOTH chains.
|
|
375
|
+
const headChain = this.layerChainSet(this._currentCommittedLayer);
|
|
376
|
+
let forkPoint = pendingLayer.getParent();
|
|
377
|
+
while (forkPoint && !headChain.has(forkPoint)) {
|
|
378
|
+
forkPoint = forkPoint.getParent();
|
|
379
|
+
}
|
|
380
|
+
if (forkPoint) {
|
|
381
|
+
// Schema drift: an ALTER consolidated the head to a different schema
|
|
382
|
+
// since the pending layer forked. Replaying stale-schema rows onto
|
|
383
|
+
// the new-schema head is unsafe — abort with BUSY rather than corrupt
|
|
384
|
+
// the committed head (mirrors the stale-ancestor caution above).
|
|
385
|
+
if (pendingLayer.getSchema() !== this.tableSchema) {
|
|
386
|
+
connection.pendingTransactionLayer = null;
|
|
387
|
+
connection.clearSavepoints();
|
|
388
|
+
logger.warn('Commit Transaction', this._tableName, 'Schema drift under sibling commit, rolling back', { connectionId: connection.connectionId });
|
|
389
|
+
throw new QuereusError(`Commit failed: schema changed under transaction on table ${this._tableName}. Retry.`, StatusCode.BUSY);
|
|
390
|
+
}
|
|
391
|
+
// Case B: rebase. Events come from the same fork-bounded pending-chain
|
|
392
|
+
// span; structural writes are replayed onto the advanced head.
|
|
393
|
+
changes = this.collectPendingChanges(pendingLayer, forkPoint);
|
|
394
|
+
committedLayer = this.rebaseLayerOntoHead(pendingLayer, forkPoint);
|
|
395
|
+
}
|
|
396
|
+
else if (!this.db._inCoordinatedCommit()) {
|
|
381
397
|
connection.pendingTransactionLayer = null;
|
|
382
398
|
connection.clearSavepoints();
|
|
383
399
|
logger.warn('Commit Transaction', this._tableName, 'Stale commit detected, rolling back', { connectionId: connection.connectionId });
|
|
384
400
|
throw new QuereusError(`Commit failed: concurrent update on table ${this._tableName}. Retry.`, StatusCode.BUSY);
|
|
385
401
|
}
|
|
402
|
+
else {
|
|
403
|
+
// Case C fallback inside a coordinated commit: no safe rebase target,
|
|
404
|
+
// but aborting would roll back every connection. Preserve the prior
|
|
405
|
+
// wholesale publish.
|
|
406
|
+
changes = this.collectPendingChanges(pendingLayer, this._currentCommittedLayer);
|
|
407
|
+
pendingLayer.markCommitted();
|
|
408
|
+
committedLayer = pendingLayer;
|
|
409
|
+
}
|
|
386
410
|
}
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
connection.readLayer = pendingLayer;
|
|
411
|
+
this._currentCommittedLayer = committedLayer;
|
|
412
|
+
logger.debugLog(`[Commit ${connection.connectionId}] CurrentCommittedLayer set to ${committedLayer.getLayerId()} for ${this._tableName}`);
|
|
413
|
+
connection.readLayer = committedLayer;
|
|
391
414
|
connection.pendingTransactionLayer = null;
|
|
392
415
|
connection.clearSavepoints();
|
|
393
416
|
// Emit data change events after successful commit
|
|
@@ -414,11 +437,92 @@ export class MemoryTableManager {
|
|
|
414
437
|
logger.debugLog(`[Commit ${connection.connectionId}] Released lock for ${this._tableName}`);
|
|
415
438
|
}
|
|
416
439
|
}
|
|
440
|
+
/** All layers in `layer`'s parent chain, including `layer` itself. */
|
|
441
|
+
layerChainSet(layer) {
|
|
442
|
+
const chain = new Set();
|
|
443
|
+
let cur = layer;
|
|
444
|
+
while (cur) {
|
|
445
|
+
chain.add(cur);
|
|
446
|
+
cur = cur.getParent();
|
|
447
|
+
}
|
|
448
|
+
return chain;
|
|
449
|
+
}
|
|
450
|
+
/**
|
|
451
|
+
* Collect pending change events from `fromLayer` up to (but not including)
|
|
452
|
+
* `boundary`, in chronological order (oldest layer first, intra-layer order
|
|
453
|
+
* preserved). Mirrors the in-transaction event span whose writes are being
|
|
454
|
+
* committed: savepoint-promoted ancestor layers whose events were never
|
|
455
|
+
* directly emitted are included; already-committed layers at/below the
|
|
456
|
+
* boundary are not (their events were emitted when they committed).
|
|
457
|
+
*/
|
|
458
|
+
collectPendingChanges(fromLayer, boundary) {
|
|
459
|
+
const eventChunks = [];
|
|
460
|
+
let layer = fromLayer;
|
|
461
|
+
while (layer && layer !== boundary) {
|
|
462
|
+
if (layer instanceof TransactionLayer) {
|
|
463
|
+
const events = layer.getPendingChanges();
|
|
464
|
+
if (events.length > 0)
|
|
465
|
+
eventChunks.push(events);
|
|
466
|
+
}
|
|
467
|
+
layer = layer.getParent();
|
|
468
|
+
}
|
|
469
|
+
// Chunks are newest-layer-first; reverse to chronological order while
|
|
470
|
+
// preserving intra-layer event order.
|
|
471
|
+
return eventChunks.reverse().flat();
|
|
472
|
+
}
|
|
473
|
+
/**
|
|
474
|
+
* Rebase a pending layer onto the current committed head after a sibling
|
|
475
|
+
* connection advanced the head past this layer's fork point. Replays the
|
|
476
|
+
* pending chain's own structural writes (pending + in-transaction ancestors
|
|
477
|
+
* down to, but not including, `forkPoint`) onto a fresh {@link TransactionLayer}
|
|
478
|
+
* parented on the head, so the sibling's already-committed rows survive.
|
|
479
|
+
*
|
|
480
|
+
* The head becomes the new layer's base, so every row the sibling committed is
|
|
481
|
+
* inherited automatically; only this branch's own writes are replayed on top.
|
|
482
|
+
*/
|
|
483
|
+
rebaseLayerOntoHead(pendingLayer, forkPoint) {
|
|
484
|
+
// Gather own-writes from pendingLayer up to (excluding) the fork point.
|
|
485
|
+
// Chunks are newest-layer-first; reverse so the oldest layer replays first.
|
|
486
|
+
const writeChunks = [];
|
|
487
|
+
let layer = pendingLayer;
|
|
488
|
+
while (layer && layer !== forkPoint) {
|
|
489
|
+
if (layer instanceof TransactionLayer) {
|
|
490
|
+
writeChunks.push(layer.getOwnWrites());
|
|
491
|
+
}
|
|
492
|
+
layer = layer.getParent();
|
|
493
|
+
}
|
|
494
|
+
const ownWrites = writeChunks.reverse().flat();
|
|
495
|
+
const rebased = new TransactionLayer(this._currentCommittedLayer);
|
|
496
|
+
if (this.eventEmitter?.hasDataListeners?.()) {
|
|
497
|
+
rebased.enableChangeTracking();
|
|
498
|
+
}
|
|
499
|
+
for (const write of ownWrites) {
|
|
500
|
+
// Re-derive the effective row at this PK on the NEW head (including
|
|
501
|
+
// earlier replays in this loop) and pass it as the old row, so
|
|
502
|
+
// secondary-index maintenance removes the correct pre-existing entry.
|
|
503
|
+
// NOTE: a primary key OR a secondary-UNIQUE value written by BOTH
|
|
504
|
+
// siblings resolves last-writer-wins to the rebasing writer's row —
|
|
505
|
+
// every non-contended key from both siblings survives. recordUpsert is
|
|
506
|
+
// the raw structural write and does not re-run checkUniqueConstraints, so
|
|
507
|
+
// a UNIQUE collision existing only BETWEEN the two siblings' rows is not
|
|
508
|
+
// detected here. This matches the memory manager's read-your-own-writes
|
|
509
|
+
// model (snapshot-isolation conflict detection lives in quereus-isolation).
|
|
510
|
+
const effective = this.lookupEffectiveRow(write.primaryKey, rebased);
|
|
511
|
+
if (write.type === 'upsert') {
|
|
512
|
+
rebased.recordUpsert(write.primaryKey, write.newRow, effective);
|
|
513
|
+
}
|
|
514
|
+
else if (effective) {
|
|
515
|
+
rebased.recordDelete(write.primaryKey, effective);
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
rebased.markCommitted();
|
|
519
|
+
return rebased;
|
|
520
|
+
}
|
|
417
521
|
async tryCollapseLayers() {
|
|
418
522
|
const lockKey = `MemoryTable.Collapse:${this.schemaName}.${this._tableName}`;
|
|
419
523
|
let release = null;
|
|
420
524
|
try {
|
|
421
|
-
const acquirePromise =
|
|
525
|
+
const acquirePromise = this.db.latches.acquire(lockKey);
|
|
422
526
|
const timeoutPromise = new Promise((resolve) => setTimeout(() => resolve(null), 10)); // Short timeout
|
|
423
527
|
const result = await Promise.race([
|
|
424
528
|
acquirePromise.then(releaseFn => ({ release: releaseFn })),
|
|
@@ -466,9 +570,7 @@ export class MemoryTableManager {
|
|
|
466
570
|
// by examining if this layer can be promoted above its (now detached) parent
|
|
467
571
|
logger.debugLog(`[Collapse] Layer ${layerToPromote.getLayerId()} is now independent for ${this._tableName}`);
|
|
468
572
|
}
|
|
469
|
-
// Trigger garbage collection of unreferenced layers
|
|
470
573
|
if (collapsedCount > 0) {
|
|
471
|
-
void this.cleanupUnreferencedLayers();
|
|
472
574
|
logger.operation('Collapse Layers', this._tableName, { collapsedCount, iterations });
|
|
473
575
|
}
|
|
474
576
|
else {
|
|
@@ -517,26 +619,6 @@ export class MemoryTableManager {
|
|
|
517
619
|
}
|
|
518
620
|
return false;
|
|
519
621
|
}
|
|
520
|
-
/**
|
|
521
|
-
* Performs garbage collection of layers that are no longer referenced
|
|
522
|
-
* by any connections or the current committed layer chain.
|
|
523
|
-
*/
|
|
524
|
-
cleanupUnreferencedLayers() {
|
|
525
|
-
// For now, this is a no-op since JavaScript's garbage collector
|
|
526
|
-
// will handle cleanup of unreferenced objects automatically.
|
|
527
|
-
// In the future, we could implement more aggressive cleanup
|
|
528
|
-
// or tracking of layer references for memory monitoring.
|
|
529
|
-
logger.debugLog(`[Cleanup] Triggering garbage collection hint for ${this._tableName}`);
|
|
530
|
-
// Optional: Force garbage collection if available (Node.js with --expose-gc)
|
|
531
|
-
if (typeof global !== 'undefined' && global.gc) {
|
|
532
|
-
try {
|
|
533
|
-
global.gc();
|
|
534
|
-
}
|
|
535
|
-
catch {
|
|
536
|
-
// Ignore errors - gc() might not be available
|
|
537
|
-
}
|
|
538
|
-
}
|
|
539
|
-
}
|
|
540
622
|
// With inherited BTrees, lookupEffectiveRow is much simpler
|
|
541
623
|
lookupEffectiveRow(primaryKey, startLayer) {
|
|
542
624
|
// With inherited BTrees, a simple get() will traverse the inheritance chain automatically
|
|
@@ -767,7 +849,7 @@ export class MemoryTableManager {
|
|
|
767
849
|
// which columns can transition the row across the predicate's scope.
|
|
768
850
|
const referenced = covering?.kind === 'memory-index'
|
|
769
851
|
? covering.index.predicate?.referencedColumns
|
|
770
|
-
: compilePredicate(uc.predicate, schema.columns).referencedColumns;
|
|
852
|
+
: compilePredicate(uc.predicate, schema.columns, schema.name).referencedColumns;
|
|
771
853
|
if (referenced) {
|
|
772
854
|
for (const colIdx of referenced) {
|
|
773
855
|
if (compareSqlValues(oldRow[colIdx], newRow[colIdx]) !== 0)
|
|
@@ -813,7 +895,7 @@ export class MemoryTableManager {
|
|
|
813
895
|
}
|
|
814
896
|
if (covering?.kind === 'materialized-view'
|
|
815
897
|
&& uc.predicate
|
|
816
|
-
&& compilePredicate(uc.predicate, schema.columns).evaluate(newRowData) !== true) {
|
|
898
|
+
&& compilePredicate(uc.predicate, schema.columns, schema.name).evaluate(newRowData) !== true) {
|
|
817
899
|
return null;
|
|
818
900
|
}
|
|
819
901
|
// Resolve effective action: statement OR > constraint default > ABORT.
|
|
@@ -901,6 +983,13 @@ export class MemoryTableManager {
|
|
|
901
983
|
checkUniqueViaIndex(targetLayer, schema, uc, index, newRowData, newPrimaryKey, onConflict, evicted) {
|
|
902
984
|
const indexKey = index.keyFromRow(newRowData);
|
|
903
985
|
const existingPKs = index.getPrimaryKeys(indexKey);
|
|
986
|
+
// The overwhelmingly common insert has no candidate at all; bail before paying
|
|
987
|
+
// for the collation resolves below.
|
|
988
|
+
if (existingPKs.length === 0)
|
|
989
|
+
return null;
|
|
990
|
+
// Resolve the per-column enforcement collations once, ahead of the candidate loop
|
|
991
|
+
// (which collation governs, and why, is spelled out at the compare below).
|
|
992
|
+
const enforcementCollations = uc.columns.map((col, i) => this.collationResolver(index.specColumns[i]?.collation ?? schema.columns[col].collation ?? 'BINARY'));
|
|
904
993
|
for (const existingPK of existingPKs) {
|
|
905
994
|
if (this.comparePrimaryKeys(newPrimaryKey, existingPK) === 0)
|
|
906
995
|
continue;
|
|
@@ -939,7 +1028,7 @@ export class MemoryTableManager {
|
|
|
939
1028
|
const conflictingRow = this.lookupEffectiveRow(existingPK, targetLayer);
|
|
940
1029
|
if (!conflictingRow)
|
|
941
1030
|
continue;
|
|
942
|
-
if (!uc.columns.every((col, i) =>
|
|
1031
|
+
if (!uc.columns.every((col, i) => compareSqlValuesFast(newRowData[col], conflictingRow[col], enforcementCollations[i]) === 0))
|
|
943
1032
|
continue;
|
|
944
1033
|
if (index.predicate && !index.rowMatchesPredicate(conflictingRow))
|
|
945
1034
|
continue;
|
|
@@ -995,7 +1084,7 @@ export class MemoryTableManager {
|
|
|
995
1084
|
// index-derived UNIQUE whose declared candidate set could be a subset is declined
|
|
996
1085
|
// upstream by findRowTimeCoveringStructure's collation gate, so only BINARY-floor
|
|
997
1086
|
// or equal-collation MVs ever reach here.
|
|
998
|
-
const collations = uniqueEnforcementCollations(schema, uc);
|
|
1087
|
+
const collations = uniqueEnforcementCollations(schema, uc).map(name => this.collationResolver(name ?? 'BINARY'));
|
|
999
1088
|
for (const conflict of conflicts) {
|
|
1000
1089
|
const existingPK = buildPrimaryKeyFromValues(conflict.pk, schema.primaryKeyDefinition);
|
|
1001
1090
|
if (this.comparePrimaryKeys(newPrimaryKey, existingPK) === 0)
|
|
@@ -1004,7 +1093,7 @@ export class MemoryTableManager {
|
|
|
1004
1093
|
const conflictingRow = this.lookupEffectiveRow(existingPK, targetLayer);
|
|
1005
1094
|
if (!conflictingRow)
|
|
1006
1095
|
continue;
|
|
1007
|
-
if (!uc.columns.every((col, i) =>
|
|
1096
|
+
if (!uc.columns.every((col, i) => compareSqlValuesFast(newRowData[col], conflictingRow[col], collations[i]) === 0))
|
|
1008
1097
|
continue;
|
|
1009
1098
|
if (onConflict === ConflictResolution.IGNORE) {
|
|
1010
1099
|
return { status: 'ok', row: undefined };
|
|
@@ -1032,8 +1121,10 @@ export class MemoryTableManager {
|
|
|
1032
1121
|
// Compile partial-UNIQUE predicate ad-hoc (cold path: an auto-index normally
|
|
1033
1122
|
// services this check, so this branch fires only for pathological schemas).
|
|
1034
1123
|
const predicate = uc.predicate
|
|
1035
|
-
? compilePredicate(uc.predicate, schema.columns)
|
|
1124
|
+
? compilePredicate(uc.predicate, schema.columns, schema.name)
|
|
1036
1125
|
: undefined;
|
|
1126
|
+
// One resolve per column, not per scanned row.
|
|
1127
|
+
const collations = uc.columns.map(colIdx => this.collationResolver(schema.columns[colIdx].collation ?? 'BINARY'));
|
|
1037
1128
|
for (const path of primaryTree.ascending(primaryTree.first())) {
|
|
1038
1129
|
const existingRow = primaryTree.at(path);
|
|
1039
1130
|
const existingPK = this.primaryKeyFromRow(existingRow);
|
|
@@ -1041,7 +1132,7 @@ export class MemoryTableManager {
|
|
|
1041
1132
|
continue;
|
|
1042
1133
|
if (predicate && predicate.evaluate(existingRow) !== true)
|
|
1043
1134
|
continue;
|
|
1044
|
-
const allMatch = uc.columns.every(colIdx =>
|
|
1135
|
+
const allMatch = uc.columns.every((colIdx, i) => compareSqlValuesFast(newRowData[colIdx], existingRow[colIdx], collations[i]) === 0);
|
|
1045
1136
|
if (!allMatch)
|
|
1046
1137
|
continue;
|
|
1047
1138
|
if (onConflict === ConflictResolution.IGNORE) {
|
|
@@ -1121,13 +1212,13 @@ export class MemoryTableManager {
|
|
|
1121
1212
|
throw new QuereusError(`Table '${this._tableName}' is read-only`, StatusCode.READONLY);
|
|
1122
1213
|
}
|
|
1123
1214
|
const lockKey = `MemoryTable.SchemaChange:${this.schemaName}.${this._tableName}`;
|
|
1124
|
-
const release = await
|
|
1215
|
+
const release = await this.db.latches.acquire(lockKey);
|
|
1125
1216
|
try {
|
|
1126
1217
|
// Drain any in-flight transaction layers down to the base so the swap
|
|
1127
1218
|
// below isn't shadowed by a committed transaction layer ahead of base.
|
|
1128
1219
|
await this.ensureSchemaChangeSafety();
|
|
1129
1220
|
const oldBase = this.baseLayer;
|
|
1130
|
-
const newBase = new BaseLayer(this.tableSchema);
|
|
1221
|
+
const newBase = new BaseLayer(this.tableSchema, this.collationResolver);
|
|
1131
1222
|
for (const row of rows) {
|
|
1132
1223
|
const key = this.primaryKeyFunctions.extractFromRow(row);
|
|
1133
1224
|
const path = newBase.primaryTree.find(key);
|
|
@@ -1240,7 +1331,7 @@ export class MemoryTableManager {
|
|
|
1240
1331
|
// Collect-then-delete avoids mutating the tree mid-iteration.
|
|
1241
1332
|
const scanPlan = { indexName: 'primary', descending: false, equalityPrefix: op.keyPrefix };
|
|
1242
1333
|
const matched = [];
|
|
1243
|
-
for
|
|
1334
|
+
for (const row of scanLayerImpl(layer, scanPlan)) {
|
|
1244
1335
|
matched.push({ key: this.primaryKeyFunctions.extractFromRow(row), row });
|
|
1245
1336
|
}
|
|
1246
1337
|
for (const { key, row } of matched) {
|
|
@@ -1262,7 +1353,7 @@ export class MemoryTableManager {
|
|
|
1262
1353
|
// delete that would leak secondary-index bookkeeping. VALUE fidelity of a paired
|
|
1263
1354
|
// row is byte-faithful (`rowsValueIdentical`, below) — one discipline, not two.
|
|
1264
1355
|
const oldByKey = new BTree(e => e.key, this.comparePrimaryKeys);
|
|
1265
|
-
for
|
|
1356
|
+
for (const row of scanLayerImpl(layer, { indexName: 'primary', descending: false })) {
|
|
1266
1357
|
oldByKey.insert({ key: this.primaryKeyFunctions.extractFromRow(row), row });
|
|
1267
1358
|
}
|
|
1268
1359
|
// New-row keys (same PK comparator) for the delete pass's membership test.
|
|
@@ -1313,7 +1404,7 @@ export class MemoryTableManager {
|
|
|
1313
1404
|
* Declared secondary-UNIQUE enforcement for maintenance writes — the
|
|
1314
1405
|
* collision-shaped half of the derived-row constraint contract (CHECK / FK
|
|
1315
1406
|
* are per-row properties and validate engine-side; see
|
|
1316
|
-
* docs/
|
|
1407
|
+
* docs/mv-constraints.md § Derived-row constraint validation). The
|
|
1317
1408
|
* privileged surface bypasses the DML constraint pipeline, so without this
|
|
1318
1409
|
* the batch above would store two derived rows colliding on a declared
|
|
1319
1410
|
* UNIQUE silently.
|
|
@@ -1366,7 +1457,7 @@ export class MemoryTableManager {
|
|
|
1366
1457
|
if (this.isReadOnly)
|
|
1367
1458
|
throw new QuereusError(`Table '${this._tableName}' is read-only`, StatusCode.READONLY);
|
|
1368
1459
|
const lockKey = `MemoryTable.SchemaChange:${this.schemaName}.${this._tableName}`;
|
|
1369
|
-
const release = await
|
|
1460
|
+
const release = await this.db.latches.acquire(lockKey);
|
|
1370
1461
|
const originalManagerSchema = this.tableSchema;
|
|
1371
1462
|
try {
|
|
1372
1463
|
await this.ensureSchemaChangeSafety();
|
|
@@ -1377,7 +1468,7 @@ export class MemoryTableManager {
|
|
|
1377
1468
|
// COLLATE, matching the CREATE path (and the differ's resolved-COLLATE emission) so
|
|
1378
1469
|
// an ADD-COLUMN-ed text column gets the same collation a CREATE-d one would.
|
|
1379
1470
|
// resolveDefaultCollation falls non-text types back to BINARY automatically.
|
|
1380
|
-
const newColumnSchema = columnDefToSchema(columnDefAst, defaultNotNull, this.db.options.getStringOption('default_collation'));
|
|
1471
|
+
const newColumnSchema = columnDefToSchema(columnDefAst, defaultNotNull, this.db.options.getStringOption('default_collation'), (n) => this.db.isCollationRegistered(n));
|
|
1381
1472
|
if (this.tableSchema.columns.some(c => c.name.toLowerCase() === newColumnSchema.name.toLowerCase())) {
|
|
1382
1473
|
throw new QuereusError(`Duplicate column name: ${newColumnSchema.name}`, StatusCode.ERROR);
|
|
1383
1474
|
}
|
|
@@ -1445,7 +1536,7 @@ export class MemoryTableManager {
|
|
|
1445
1536
|
if (this.isReadOnly)
|
|
1446
1537
|
throw new QuereusError(`Table '${this._tableName}' is read-only`, StatusCode.READONLY);
|
|
1447
1538
|
const lockKey = `MemoryTable.SchemaChange:${this.schemaName}.${this._tableName}`;
|
|
1448
|
-
const release = await
|
|
1539
|
+
const release = await this.db.latches.acquire(lockKey);
|
|
1449
1540
|
const originalManagerSchema = this.tableSchema;
|
|
1450
1541
|
try {
|
|
1451
1542
|
await this.ensureSchemaChangeSafety();
|
|
@@ -1536,8 +1627,11 @@ export class MemoryTableManager {
|
|
|
1536
1627
|
if (this.isReadOnly)
|
|
1537
1628
|
throw new QuereusError(`Table '${this._tableName}' is read-only`, StatusCode.READONLY);
|
|
1538
1629
|
const lockKey = `MemoryTable.SchemaChange:${this.schemaName}.${this._tableName}`;
|
|
1539
|
-
const release = await
|
|
1630
|
+
const release = await this.db.latches.acquire(lockKey);
|
|
1540
1631
|
const originalManagerSchema = this.tableSchema;
|
|
1632
|
+
const schemaManager = this.db.schemaManager;
|
|
1633
|
+
const resolveColumnInSource = (s, t, col) => schemaManager.getSchema(s)?.getTable(t)?.columnIndexMap.has(col.toLowerCase()) ?? false;
|
|
1634
|
+
let predicatesRewritten = false;
|
|
1541
1635
|
try {
|
|
1542
1636
|
await this.ensureSchemaChangeSafety();
|
|
1543
1637
|
const oldNameLower = oldName.toLowerCase();
|
|
@@ -1552,7 +1646,7 @@ export class MemoryTableManager {
|
|
|
1552
1646
|
// Get default nullability setting from database options
|
|
1553
1647
|
const defaultNullability = this.db.options.getStringOption('default_column_nullability');
|
|
1554
1648
|
const defaultNotNull = defaultNullability === 'not_null';
|
|
1555
|
-
const newColumnSchemaAtIndex = columnDefToSchema(newColumnDefAst, defaultNotNull);
|
|
1649
|
+
const newColumnSchemaAtIndex = columnDefToSchema(newColumnDefAst, defaultNotNull, 'BINARY', (n) => this.db.isCollationRegistered(n));
|
|
1556
1650
|
const updatedCols = this.tableSchema.columns.map((c, i) => i === colIndex ? newColumnSchemaAtIndex : c);
|
|
1557
1651
|
const updatedIndexes = (this.tableSchema.indexes || []).map(idx => ({
|
|
1558
1652
|
...idx,
|
|
@@ -1565,6 +1659,28 @@ export class MemoryTableManager {
|
|
|
1565
1659
|
primaryKeyDefinition: Object.freeze(this.tableSchema.primaryKeyDefinition),
|
|
1566
1660
|
indexes: Object.freeze(updatedIndexes),
|
|
1567
1661
|
});
|
|
1662
|
+
// Rewrite partial-index predicates into the new column name BEFORE the
|
|
1663
|
+
// rebuild that `handleColumnRename()` triggers: `createSecondaryIndexes`
|
|
1664
|
+
// compiles each predicate against the new column list, so a `WHERE` still
|
|
1665
|
+
// naming the old column cannot build.
|
|
1666
|
+
//
|
|
1667
|
+
// The window is narrow. `ensureSchemaChangeSafety()` above consolidates the
|
|
1668
|
+
// transaction layers into the base and rebuilds every secondary index against
|
|
1669
|
+
// the OLD column list — an already-rewritten predicate would break that. So
|
|
1670
|
+
// the rewrite belongs here and nowhere earlier (in particular, not before the
|
|
1671
|
+
// engine calls `module.alterTable`).
|
|
1672
|
+
//
|
|
1673
|
+
// In place, so the catalog's `TableSchema` and a unique partial index's derived
|
|
1674
|
+
// UNIQUE constraint — which share the `Expression` by reference — follow along.
|
|
1675
|
+
// `propagateColumnRename` re-runs the same rewrite once the engine regains
|
|
1676
|
+
// control and finds nothing left to do.
|
|
1677
|
+
// Armed BEFORE the call, not from its return value: the rewrite walks the
|
|
1678
|
+
// indexes one at a time, so a throw partway through would otherwise leave the
|
|
1679
|
+
// already-rewritten predicates renamed with the flag still false. The reverse
|
|
1680
|
+
// pass is a no-op when nothing names `newColumnName`, so arming it eagerly
|
|
1681
|
+
// costs nothing when the rewrite finds no predicate to touch.
|
|
1682
|
+
predicatesRewritten = true;
|
|
1683
|
+
renameColumnInIndexPredicates(finalNewTableSchema.indexes, this._tableName, oldName, newColumnName, this.schemaName, resolveColumnInSource);
|
|
1568
1684
|
this.baseLayer.updateSchema(finalNewTableSchema);
|
|
1569
1685
|
await this.baseLayer.handleColumnRename();
|
|
1570
1686
|
this.tableSchema = finalNewTableSchema;
|
|
@@ -1581,6 +1697,12 @@ export class MemoryTableManager {
|
|
|
1581
1697
|
logger.operation('Rename Column', this._tableName, { oldName, newName: newColumnName });
|
|
1582
1698
|
}
|
|
1583
1699
|
catch (e) {
|
|
1700
|
+
// The predicate ASTs are shared with the catalog's TableSchema, so restoring
|
|
1701
|
+
// `originalManagerSchema` does not undo the rewrite — run it in reverse. The
|
|
1702
|
+
// flag keeps a failure raised *before* the rewrite from un-renaming anything.
|
|
1703
|
+
if (predicatesRewritten) {
|
|
1704
|
+
renameColumnInIndexPredicates(originalManagerSchema.indexes, this._tableName, newColumnDefAst.name, oldName, this.schemaName, resolveColumnInSource);
|
|
1705
|
+
}
|
|
1584
1706
|
this.baseLayer.updateSchema(originalManagerSchema);
|
|
1585
1707
|
this.tableSchema = originalManagerSchema;
|
|
1586
1708
|
this.initializePrimaryKeyFunctions();
|
|
@@ -1596,12 +1718,14 @@ export class MemoryTableManager {
|
|
|
1596
1718
|
* The caller supplies exactly one populated change; multi-attribute combinations
|
|
1597
1719
|
* are rejected by the runtime before reaching this method.
|
|
1598
1720
|
*/
|
|
1599
|
-
async alterColumn(change) {
|
|
1721
|
+
async alterColumn(change, rows) {
|
|
1600
1722
|
if (this.isReadOnly)
|
|
1601
1723
|
throw new QuereusError(`Table '${this._tableName}' is read-only`, StatusCode.READONLY);
|
|
1602
1724
|
const lockKey = `MemoryTable.SchemaChange:${this.schemaName}.${this._tableName}`;
|
|
1603
|
-
const release = await
|
|
1725
|
+
const release = await this.db.latches.acquire(lockKey);
|
|
1604
1726
|
const originalManagerSchema = this.tableSchema;
|
|
1727
|
+
/** The base primary tree `rebuildPrimaryTreeStrict` replaced, for the catch's rollback. */
|
|
1728
|
+
let basePrimaryTreeBeforeRekey = null;
|
|
1605
1729
|
try {
|
|
1606
1730
|
await this.ensureSchemaChangeSafety();
|
|
1607
1731
|
const colNameLower = change.columnName.toLowerCase();
|
|
@@ -1614,8 +1738,18 @@ export class MemoryTableManager {
|
|
|
1614
1738
|
// A collation change re-keys any PK / UNIQUE / index that orders by this
|
|
1615
1739
|
// column, so it needs the structure re-sort + uniqueness re-validation below.
|
|
1616
1740
|
let collationChanged = false;
|
|
1741
|
+
// Set to the per-value conversion function when a physical value rewrite is needed:
|
|
1742
|
+
// SET DATA TYPE (retype every value) or SET NOT NULL backfill (map null → DEFAULT).
|
|
1743
|
+
// Both REPLACE the base primary tree with a freshly-built one (never an in-place
|
|
1744
|
+
// mutation, which inheritree forbids while the open transaction's layers derive from
|
|
1745
|
+
// it) and convert the transaction's own-written rows in every open layer, after
|
|
1746
|
+
// `updateSchema` (see the rebuild section and convertColumnOnOpenLayers).
|
|
1747
|
+
let valueConvert = null;
|
|
1748
|
+
// SET NOT NULL backfill also routes NULL values through `valueConvert`; SET DATA TYPE
|
|
1749
|
+
// leaves nulls untouched. Selects the null-including path in convertBaseRows/convertColumn.
|
|
1750
|
+
let convertNulls = false;
|
|
1617
1751
|
if (change.setCollation !== undefined) {
|
|
1618
|
-
const normalized = validateCollationForType(change.setCollation, oldCol.logicalType, change.columnName);
|
|
1752
|
+
const normalized = validateCollationForType(change.setCollation, oldCol.logicalType, change.columnName, (n) => this.db.isCollationRegistered(n));
|
|
1619
1753
|
const nameMatches = normalized === (oldCol.collation || 'BINARY');
|
|
1620
1754
|
if (nameMatches && oldCol.collationExplicit) {
|
|
1621
1755
|
return; // already explicit in the desired collation — nothing to do
|
|
@@ -1634,30 +1768,43 @@ export class MemoryTableManager {
|
|
|
1634
1768
|
}
|
|
1635
1769
|
else if (change.setNotNull !== undefined) {
|
|
1636
1770
|
if (change.setNotNull === true && !oldCol.notNull) {
|
|
1637
|
-
// Tightening: scan for NULLs
|
|
1771
|
+
// Tightening: scan the DDL transaction's EFFECTIVE rows for NULLs — committed rows
|
|
1772
|
+
// overlaid with this transaction's own pending writes — exactly as the setDataType
|
|
1773
|
+
// arm does. A pending NULL the transaction can SEE rejects the ALTER; one only in a
|
|
1774
|
+
// row it has DELETED does not block it. `rows` is the wrapper-supplied effective set
|
|
1775
|
+
// (the isolation overlay); when absent, effectiveDdlRows() is the layered view.
|
|
1638
1776
|
const defaultExpr = oldCol.defaultValue;
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1777
|
+
const defaultLiteral = defaultExpr ? tryFoldLiteral(defaultExpr) : undefined;
|
|
1778
|
+
let anyNull = false;
|
|
1779
|
+
if (rows) {
|
|
1780
|
+
for await (const row of rows()) {
|
|
1781
|
+
if (row[colIndex] === null) {
|
|
1782
|
+
anyNull = true;
|
|
1783
|
+
break;
|
|
1784
|
+
}
|
|
1785
|
+
}
|
|
1642
1786
|
}
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1787
|
+
else {
|
|
1788
|
+
for (const row of this.effectiveDdlRows()) {
|
|
1789
|
+
if (row[colIndex] === null) {
|
|
1790
|
+
anyNull = true;
|
|
1791
|
+
break;
|
|
1792
|
+
}
|
|
1793
|
+
}
|
|
1649
1794
|
}
|
|
1650
|
-
if (
|
|
1795
|
+
if (anyNull) {
|
|
1651
1796
|
if (defaultLiteral === undefined || defaultLiteral === null) {
|
|
1652
1797
|
throw new QuereusError(`column ${change.columnName} contains NULL values`, StatusCode.CONSTRAINT);
|
|
1653
1798
|
}
|
|
1654
|
-
// Backfill
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1799
|
+
// Backfill: map null → the folded DEFAULT literal, routed through the SAME
|
|
1800
|
+
// base-replacement + open-layer conversion machinery setDataType uses — no
|
|
1801
|
+
// logical-type change, no PK re-key, no in-place base mutation. The old in-place
|
|
1802
|
+
// `tree.upsert` backfill could not fill the transaction's pending rows (they live
|
|
1803
|
+
// in the pending layer, not the base) and mutated a base the open layers derive
|
|
1804
|
+
// from — both fixed by the unified path.
|
|
1805
|
+
const literal = defaultLiteral;
|
|
1806
|
+
valueConvert = (v) => (v === null ? literal : v);
|
|
1807
|
+
convertNulls = true;
|
|
1661
1808
|
}
|
|
1662
1809
|
newCol = { ...oldCol, notNull: true };
|
|
1663
1810
|
}
|
|
@@ -1678,27 +1825,49 @@ export class MemoryTableManager {
|
|
|
1678
1825
|
newCol = { ...oldCol, logicalType: newLogicalType };
|
|
1679
1826
|
}
|
|
1680
1827
|
else {
|
|
1681
|
-
//
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1828
|
+
// Retyping a PRIMARY KEY column changes the physical key bytes. The in-place
|
|
1829
|
+
// base rewrite below cannot re-key the primary tree (an upsert of a row whose
|
|
1830
|
+
// PK value changed physical type lands at a NEW key, orphaning the old entry),
|
|
1831
|
+
// and the transaction-layer conversion deliberately leaves every layer's primary
|
|
1832
|
+
// tree keyed as-is. Reject rather than corrupt it — the type-change analogue of
|
|
1833
|
+
// the SET COLLATE primary-key carve-out (`alter-collate-pk-in-transaction`).
|
|
1834
|
+
if (this.tableSchema.primaryKeyDefinition.some(def => def.index === colIndex)) {
|
|
1835
|
+
throw new QuereusError(`Cannot change the data type of primary key column '${change.columnName}' of table '${this._tableName}'.`, StatusCode.CONSTRAINT);
|
|
1687
1836
|
}
|
|
1688
|
-
|
|
1689
|
-
const oldVal = row[colIndex];
|
|
1690
|
-
if (oldVal === null)
|
|
1691
|
-
continue;
|
|
1692
|
-
let newVal;
|
|
1837
|
+
const convert = (v) => {
|
|
1693
1838
|
try {
|
|
1694
|
-
|
|
1839
|
+
return validateAndParse(v, newLogicalType, change.columnName);
|
|
1695
1840
|
}
|
|
1696
1841
|
catch {
|
|
1697
1842
|
throw new QuereusError(`Cannot convert value in '${change.columnName}' to ${change.setDataType}`, StatusCode.MISMATCH);
|
|
1698
1843
|
}
|
|
1699
|
-
|
|
1700
|
-
|
|
1844
|
+
};
|
|
1845
|
+
// Validate BEFORE any mutation, over the DDL transaction's EFFECTIVE rows
|
|
1846
|
+
// (committed rows overlaid with this transaction's own pending writes): an
|
|
1847
|
+
// unconvertible value the transaction can SEE rejects the ALTER, and one only in
|
|
1848
|
+
// a row it has DELETED does not block it. A throw here leaves the schema, the base
|
|
1849
|
+
// and the transaction untouched. `rows` is the wrapper-supplied effective set (the
|
|
1850
|
+
// isolation overlay); when absent, `effectiveDdlRows()` is the layered view.
|
|
1851
|
+
if (rows) {
|
|
1852
|
+
for await (const row of rows()) {
|
|
1853
|
+
const val = row[colIndex];
|
|
1854
|
+
if (val !== null)
|
|
1855
|
+
convert(val);
|
|
1856
|
+
}
|
|
1701
1857
|
}
|
|
1858
|
+
else {
|
|
1859
|
+
for (const row of this.effectiveDdlRows()) {
|
|
1860
|
+
const val = row[colIndex];
|
|
1861
|
+
if (val !== null)
|
|
1862
|
+
convert(val);
|
|
1863
|
+
}
|
|
1864
|
+
}
|
|
1865
|
+
// The base rows are converted below, AFTER `updateSchema`, by REPLACING the base
|
|
1866
|
+
// primary tree with a fresh one (see the `valueConvert` branch) — never by an
|
|
1867
|
+
// in-place mutation, which inheritree forbids while the open transaction's layers
|
|
1868
|
+
// derive from that tree (`MutatedBaseError`). `valueConvert` drives both the base
|
|
1869
|
+
// replacement and the transaction-layer conversion.
|
|
1870
|
+
valueConvert = convert;
|
|
1702
1871
|
newCol = { ...oldCol, logicalType: newLogicalType };
|
|
1703
1872
|
}
|
|
1704
1873
|
}
|
|
@@ -1727,20 +1896,89 @@ export class MemoryTableManager {
|
|
|
1727
1896
|
primaryKeyDefinition: Object.freeze(updatedPkDef),
|
|
1728
1897
|
indexes: updatedIndexes ? Object.freeze(updatedIndexes) : updatedIndexes,
|
|
1729
1898
|
});
|
|
1899
|
+
const pkColumnRekeyed = collationChanged && updatedPkDef.some(def => def.index === colIndex);
|
|
1900
|
+
// Validate BEFORE any mutation, over the DDL transaction's EFFECTIVE rows: a pair
|
|
1901
|
+
// the transaction inserted that collides under the NEW collation must reject the
|
|
1902
|
+
// change, and one it has deleted must not block it. A throw here leaves the schema,
|
|
1903
|
+
// the base layer and the index map exactly as they were.
|
|
1904
|
+
//
|
|
1905
|
+
// The primary key gets a stricter pre-pass (`validateRekeyedPrimaryKey`): no layer in
|
|
1906
|
+
// the chain, base included, may hold a collision. That is what lets every step below
|
|
1907
|
+
// succeed unconditionally, and what `TransactionLayer.rekeyPrimaryKey` relies on.
|
|
1908
|
+
if (collationChanged) {
|
|
1909
|
+
await this.validateRekeyedUniqueStructures(finalNewTableSchema, colIndex, rows);
|
|
1910
|
+
// NOTE: `validateRekeyedPrimaryKey` deliberately ignores `rows`. It asserts that no
|
|
1911
|
+
// LAYER of this manager's own chain holds a PK collision under the new comparator —
|
|
1912
|
+
// a physical property of the structures it is about to re-key, which a wrapper's
|
|
1913
|
+
// merged row stream cannot speak to. A wrapper's staged rows live in the wrapper's
|
|
1914
|
+
// own overlay, which enforces the PK itself, so the pair "one staged row + one
|
|
1915
|
+
// committed row that collide only under the new collation" is checked by neither
|
|
1916
|
+
// side. Rejecting it here would need the wrapper to expose its overlay's PK set, not
|
|
1917
|
+
// just its merged rows.
|
|
1918
|
+
if (pkColumnRekeyed)
|
|
1919
|
+
this.validateRekeyedPrimaryKey(finalNewTableSchema);
|
|
1920
|
+
}
|
|
1730
1921
|
this.baseLayer.updateSchema(finalNewTableSchema);
|
|
1731
|
-
// A collation change re-sorts structures that order by the column
|
|
1732
|
-
//
|
|
1733
|
-
//
|
|
1734
|
-
//
|
|
1735
|
-
//
|
|
1922
|
+
// A collation change re-sorts the structures that order by the column. The
|
|
1923
|
+
// secondary rebuild is NON-enforcing (the pre-pass above owns uniqueness, and the
|
|
1924
|
+
// base's rows are not a subset of the effective rows); the primary tree rebuild is
|
|
1925
|
+
// strict, since a PK collision cannot be represented at all — the pre-pass has
|
|
1926
|
+
// already proved the base collision-free, so the strict rebuild is a live invariant
|
|
1927
|
+
// check, not the enforcement path. It runs LAST so its throw leaves the live tree
|
|
1928
|
+
// intact for the catch's rollback.
|
|
1736
1929
|
if (collationChanged) {
|
|
1737
|
-
this.baseLayer.
|
|
1738
|
-
if (
|
|
1930
|
+
this.baseLayer.rebuildAllSecondaryIndexes();
|
|
1931
|
+
if (pkColumnRekeyed) {
|
|
1932
|
+
basePrimaryTreeBeforeRekey = this.baseLayer.primaryTree;
|
|
1739
1933
|
this.baseLayer.rebuildPrimaryTreeStrict();
|
|
1740
1934
|
}
|
|
1741
1935
|
}
|
|
1936
|
+
else if (valueConvert) {
|
|
1937
|
+
// SET DATA TYPE / SET NOT NULL backfill: convert the committed base rows and REPLACE
|
|
1938
|
+
// the primary tree with a fresh one holding them (not an in-place upsert — inheritree
|
|
1939
|
+
// forbids mutating a base while the open transaction's layers derive from it).
|
|
1940
|
+
// `rebuildPrimaryTreeFromRows` also rebuilds every secondary index from the converted
|
|
1941
|
+
// rows, so index-backed lookups see the new values. The old tree is saved for the
|
|
1942
|
+
// catch's rollback, exactly as the PK-rekey path does.
|
|
1943
|
+
// NOTE: rebuilds EVERY secondary index, not only those covering the altered column;
|
|
1944
|
+
// if a wide-index table ever shows this as slow, filter to indexes whose columns
|
|
1945
|
+
// include colIndex. Mirrors the collationChanged path's unconditional rebuild.
|
|
1946
|
+
//
|
|
1947
|
+
// SET DATA TYPE: a base value that fails to convert is kept as-is — validation over
|
|
1948
|
+
// the effective view already rejected any unconvertible value the transaction can SEE,
|
|
1949
|
+
// so a surviving one is shadowed by a pending delete/overwrite and is never read back
|
|
1950
|
+
// (a ROLLBACK re-exposes it under the new type — DDL is not undone by rollback, the
|
|
1951
|
+
// known behavior of `feat-ddl-transaction-capability`).
|
|
1952
|
+
// SET NOT NULL (`convertNulls`): null base values are mapped to the DEFAULT literal.
|
|
1953
|
+
const convertedBaseRows = this.convertBaseRows(colIndex, valueConvert, convertNulls);
|
|
1954
|
+
basePrimaryTreeBeforeRekey = this.baseLayer.primaryTree;
|
|
1955
|
+
this.baseLayer.rebuildPrimaryTreeFromRows(convertedBaseRows);
|
|
1956
|
+
}
|
|
1742
1957
|
this.tableSchema = finalNewTableSchema;
|
|
1743
1958
|
this.initializePrimaryKeyFunctions();
|
|
1959
|
+
// The base rebuild handed every secondary index a fresh tree under the new
|
|
1960
|
+
// collation; the DDL transaction's own layers still inherit the old ones and froze
|
|
1961
|
+
// the old schema at construction. Re-key them, or the rest of the transaction — and
|
|
1962
|
+
// everything after the pending layer becomes the committed head at commit — keeps
|
|
1963
|
+
// comparing under the old collation.
|
|
1964
|
+
//
|
|
1965
|
+
// When the altered column is part of the primary key, `rebuildPrimaryTreeStrict` also
|
|
1966
|
+
// swapped the base primary tree object out from under those layers' copy-on-write
|
|
1967
|
+
// bases and invalidated their `pkFunctions`; `rekeyPrimaryKey` rebuilds both, plus
|
|
1968
|
+
// every secondary index (each derives its PK comparator/encoder from the PK
|
|
1969
|
+
// definition). Outside a transaction there are no open layers and both are no-ops.
|
|
1970
|
+
if (collationChanged) {
|
|
1971
|
+
this.adoptSchemaOnOpenLayers(finalNewTableSchema, pkColumnRekeyed);
|
|
1972
|
+
}
|
|
1973
|
+
else if (valueConvert) {
|
|
1974
|
+
// SET DATA TYPE / SET NOT NULL backfill converted the base above; the DDL
|
|
1975
|
+
// transaction's own open layers still froze the old schema and hold their own-written
|
|
1976
|
+
// rows unconverted. Swap the schema and convert those values so the rest of the
|
|
1977
|
+
// transaction — and the committed head at commit — read the new value. For SET NOT
|
|
1978
|
+
// NULL this fills the transaction's OWN pending NULL rows (which live in the pending
|
|
1979
|
+
// layer, never reached by the old in-place base upsert). No-op in autocommit.
|
|
1980
|
+
this.convertColumnOnOpenLayers(finalNewTableSchema, colIndex, valueConvert, convertNulls);
|
|
1981
|
+
}
|
|
1744
1982
|
this.eventEmitter?.emitSchemaChange?.({
|
|
1745
1983
|
type: 'alter',
|
|
1746
1984
|
objectType: 'column',
|
|
@@ -1751,11 +1989,21 @@ export class MemoryTableManager {
|
|
|
1751
1989
|
logger.operation('Alter Column', this._tableName, { columnName: change.columnName });
|
|
1752
1990
|
}
|
|
1753
1991
|
catch (e) {
|
|
1754
|
-
// Restore the prior schema, then
|
|
1755
|
-
//
|
|
1756
|
-
//
|
|
1757
|
-
//
|
|
1992
|
+
// Restore the prior schema and primary tree, then re-key the secondary indexes back
|
|
1993
|
+
// to it. Both pre-passes now run before any mutation, so nothing below `updateSchema`
|
|
1994
|
+
// is expected to throw; the restores are the safety net for an unexpected one (and
|
|
1995
|
+
// for `rebuildPrimaryTreeStrict`'s invariant check, whose precondition
|
|
1996
|
+
// `validateRekeyedPrimaryKey` has already established).
|
|
1997
|
+
//
|
|
1998
|
+
// NOTE: a throw from a pre-pass (or from `setNotNull`'s NULL scan) mutated nothing,
|
|
1999
|
+
// so this rebuild only swaps the base's index trees for fresh, content-identical
|
|
2000
|
+
// ones — an O(rows) cost on a pure rejection. Harmless (a pending layer keeps
|
|
2001
|
+
// reading its orphaned but content-correct copy-on-write base), but if a rejected
|
|
2002
|
+
// ALTER on a large table ever shows up as slow, gate the rebuild on a "mutation
|
|
2003
|
+
// started" flag set just before `updateSchema`.
|
|
1758
2004
|
this.baseLayer.updateSchema(originalManagerSchema);
|
|
2005
|
+
if (basePrimaryTreeBeforeRekey)
|
|
2006
|
+
this.baseLayer.primaryTree = basePrimaryTreeBeforeRekey;
|
|
1759
2007
|
this.baseLayer.rebuildAllSecondaryIndexes();
|
|
1760
2008
|
this.tableSchema = originalManagerSchema;
|
|
1761
2009
|
this.initializePrimaryKeyFunctions();
|
|
@@ -1766,11 +2014,11 @@ export class MemoryTableManager {
|
|
|
1766
2014
|
release();
|
|
1767
2015
|
}
|
|
1768
2016
|
}
|
|
1769
|
-
async createIndex(newIndexSchemaEntry, ifNotExistsFromAst) {
|
|
2017
|
+
async createIndex(newIndexSchemaEntry, ifNotExistsFromAst, rows) {
|
|
1770
2018
|
if (this.isReadOnly)
|
|
1771
2019
|
throw new QuereusError(`Table '${this._tableName}' is read-only`, StatusCode.READONLY);
|
|
1772
2020
|
const lockKey = `MemoryTable.SchemaChange:${this.schemaName}.${this._tableName}`;
|
|
1773
|
-
const release = await
|
|
2021
|
+
const release = await this.db.latches.acquire(lockKey);
|
|
1774
2022
|
const originalManagerSchema = this.tableSchema;
|
|
1775
2023
|
try {
|
|
1776
2024
|
await this.ensureSchemaChangeSafety();
|
|
@@ -1787,6 +2035,13 @@ export class MemoryTableManager {
|
|
|
1787
2035
|
throw new QuereusError(`Column index ${iCol.index} for index '${indexName}' is out of bounds for table '${this._tableName}'.`, StatusCode.ERROR);
|
|
1788
2036
|
}
|
|
1789
2037
|
}
|
|
2038
|
+
// Validate BEFORE any mutation, over the DDL transaction's EFFECTIVE rows — a
|
|
2039
|
+
// duplicate the transaction inserted but has not committed must reject the build,
|
|
2040
|
+
// and one it has deleted must not. A throw here leaves schema, base layer and
|
|
2041
|
+
// index map exactly as they were.
|
|
2042
|
+
if (newIndexSchemaEntry.unique) {
|
|
2043
|
+
await this.validateUniqueOverEffectiveRows(newIndexSchemaEntry, this.tableSchema, rows);
|
|
2044
|
+
}
|
|
1790
2045
|
const updatedIndexes = Object.freeze([...(this.tableSchema.indexes || []), newIndexSchemaEntry]);
|
|
1791
2046
|
let updatedUniqueConstraints = this.tableSchema.uniqueConstraints;
|
|
1792
2047
|
if (newIndexSchemaEntry.unique) {
|
|
@@ -1809,6 +2064,9 @@ export class MemoryTableManager {
|
|
|
1809
2064
|
this.baseLayer.updateSchema(finalNewTableSchema);
|
|
1810
2065
|
await this.baseLayer.addIndexToBase(newIndexSchemaEntry);
|
|
1811
2066
|
this.tableSchema = finalNewTableSchema;
|
|
2067
|
+
// The DDL transaction's own layers froze their schema at creation; hand them the
|
|
2068
|
+
// new one so the rest of the transaction scans and enforces the new index.
|
|
2069
|
+
this.adoptSchemaOnOpenLayers(finalNewTableSchema);
|
|
1812
2070
|
// Emit schema change event
|
|
1813
2071
|
this.eventEmitter?.emitSchemaChange?.({
|
|
1814
2072
|
type: 'create',
|
|
@@ -1819,7 +2077,16 @@ export class MemoryTableManager {
|
|
|
1819
2077
|
logger.operation('Create Index', this._tableName, { indexName });
|
|
1820
2078
|
}
|
|
1821
2079
|
catch (e) {
|
|
2080
|
+
// Restore the prior schema, and drop the index if `addIndexToBase` already landed
|
|
2081
|
+
// it — otherwise the base layer's index map would advertise a structure the schema
|
|
2082
|
+
// no longer declares. Guarded on the ORIGINAL schema so the "index already exists"
|
|
2083
|
+
// arm never tears down the pre-existing index of the same name.
|
|
1822
2084
|
this.baseLayer.updateSchema(originalManagerSchema);
|
|
2085
|
+
const name = newIndexSchemaEntry.name;
|
|
2086
|
+
const preexisting = originalManagerSchema.indexes?.some(i => i.name.toLowerCase() === name.toLowerCase()) ?? false;
|
|
2087
|
+
if (!preexisting && this.baseLayer.getSecondaryIndex(name)) {
|
|
2088
|
+
await this.baseLayer.dropIndexFromBase(name);
|
|
2089
|
+
}
|
|
1823
2090
|
this.tableSchema = originalManagerSchema;
|
|
1824
2091
|
logger.error('Create Index', this._tableName, e);
|
|
1825
2092
|
throw e;
|
|
@@ -1832,7 +2099,7 @@ export class MemoryTableManager {
|
|
|
1832
2099
|
if (this.isReadOnly)
|
|
1833
2100
|
throw new QuereusError(`Table '${this._tableName}' is read-only`, StatusCode.READONLY);
|
|
1834
2101
|
const lockKey = `MemoryTable.SchemaChange:${this.schemaName}.${this._tableName}`;
|
|
1835
|
-
const release = await
|
|
2102
|
+
const release = await this.db.latches.acquire(lockKey);
|
|
1836
2103
|
const originalManagerSchema = this.tableSchema;
|
|
1837
2104
|
try {
|
|
1838
2105
|
await this.ensureSchemaChangeSafety();
|
|
@@ -1859,6 +2126,9 @@ export class MemoryTableManager {
|
|
|
1859
2126
|
this.baseLayer.updateSchema(finalNewTableSchema);
|
|
1860
2127
|
await this.baseLayer.dropIndexFromBase(indexName);
|
|
1861
2128
|
this.tableSchema = finalNewTableSchema;
|
|
2129
|
+
// The DDL transaction's own layers froze their schema at creation; hand them the new
|
|
2130
|
+
// one so the rest of the transaction stops enforcing (and scanning) the dropped index.
|
|
2131
|
+
this.adoptSchemaOnOpenLayers(finalNewTableSchema);
|
|
1862
2132
|
// Emit schema change event
|
|
1863
2133
|
this.eventEmitter?.emitSchemaChange?.({
|
|
1864
2134
|
type: 'drop',
|
|
@@ -1890,7 +2160,7 @@ export class MemoryTableManager {
|
|
|
1890
2160
|
if (this.isReadOnly)
|
|
1891
2161
|
throw new QuereusError(`Table '${this._tableName}' is read-only`, StatusCode.READONLY);
|
|
1892
2162
|
const lockKey = `MemoryTable.SchemaChange:${this.schemaName}.${this._tableName}`;
|
|
1893
|
-
const release = await
|
|
2163
|
+
const release = await this.db.latches.acquire(lockKey);
|
|
1894
2164
|
const originalManagerSchema = this.tableSchema;
|
|
1895
2165
|
try {
|
|
1896
2166
|
await this.ensureSchemaChangeSafety();
|
|
@@ -1933,6 +2203,10 @@ export class MemoryTableManager {
|
|
|
1933
2203
|
await this.baseLayer.dropIndexFromBase(droppedIndexName);
|
|
1934
2204
|
this.tableSchema = newSchema;
|
|
1935
2205
|
this.initializePrimaryKeyFunctions();
|
|
2206
|
+
// Hand the new schema to the DDL transaction's own frozen layers so a dropped UNIQUE
|
|
2207
|
+
// stops enforcing for the rest of it; harmless for CHECK/FK (they re-freeze an
|
|
2208
|
+
// equivalent schema, holding no per-layer structure).
|
|
2209
|
+
this.adoptSchemaOnOpenLayers(newSchema);
|
|
1936
2210
|
this.eventEmitter?.emitSchemaChange?.({
|
|
1937
2211
|
type: 'alter',
|
|
1938
2212
|
objectType: 'table',
|
|
@@ -1962,7 +2236,7 @@ export class MemoryTableManager {
|
|
|
1962
2236
|
if (this.isReadOnly)
|
|
1963
2237
|
throw new QuereusError(`Table '${this._tableName}' is read-only`, StatusCode.READONLY);
|
|
1964
2238
|
const lockKey = `MemoryTable.SchemaChange:${this.schemaName}.${this._tableName}`;
|
|
1965
|
-
const release = await
|
|
2239
|
+
const release = await this.db.latches.acquire(lockKey);
|
|
1966
2240
|
const originalManagerSchema = this.tableSchema;
|
|
1967
2241
|
try {
|
|
1968
2242
|
await this.ensureSchemaChangeSafety();
|
|
@@ -2049,16 +2323,16 @@ export class MemoryTableManager {
|
|
|
2049
2323
|
* keeps an engine-side fallback in `runtime/emit/add-constraint.ts` only for
|
|
2050
2324
|
* modules that omit `alterTable` — which cannot DROP/RENAME a constraint anyway.)
|
|
2051
2325
|
*/
|
|
2052
|
-
async addConstraint(constraint) {
|
|
2326
|
+
async addConstraint(constraint, rows) {
|
|
2053
2327
|
if (this.isReadOnly)
|
|
2054
2328
|
throw new QuereusError(`Table '${this._tableName}' is read-only`, StatusCode.READONLY);
|
|
2055
2329
|
const lockKey = `MemoryTable.SchemaChange:${this.schemaName}.${this._tableName}`;
|
|
2056
|
-
const release = await
|
|
2330
|
+
const release = await this.db.latches.acquire(lockKey);
|
|
2057
2331
|
const originalManagerSchema = this.tableSchema;
|
|
2058
2332
|
try {
|
|
2059
2333
|
await this.ensureSchemaChangeSafety();
|
|
2060
2334
|
if (constraint.type === 'unique') {
|
|
2061
|
-
await this.addUniqueConstraint(constraint);
|
|
2335
|
+
await this.addUniqueConstraint(constraint, rows);
|
|
2062
2336
|
}
|
|
2063
2337
|
else if (constraint.type === 'foreignKey') {
|
|
2064
2338
|
await this.addForeignKeyConstraint(constraint);
|
|
@@ -2109,12 +2383,12 @@ export class MemoryTableManager {
|
|
|
2109
2383
|
}
|
|
2110
2384
|
/**
|
|
2111
2385
|
* UNIQUE arm of {@link addConstraint}. Builds the covering secondary index the
|
|
2112
|
-
* same way {@link ensureUniqueConstraintIndexes} does (validating
|
|
2113
|
-
* via
|
|
2114
|
-
* already covers the exact columns — in which
|
|
2115
|
-
* validated and we only register the covering structure.
|
|
2386
|
+
* same way {@link ensureUniqueConstraintIndexes} does (validating the DDL
|
|
2387
|
+
* transaction's effective rows via {@link validateUniqueOverEffectiveRows} first),
|
|
2388
|
+
* unless an existing *unique* index already covers the exact columns — in which
|
|
2389
|
+
* case the data is already validated and we only register the covering structure.
|
|
2116
2390
|
*/
|
|
2117
|
-
async addUniqueConstraint(constraint) {
|
|
2391
|
+
async addUniqueConstraint(constraint, rows) {
|
|
2118
2392
|
const uc = buildUniqueConstraintSchema(constraint, this.tableSchema.columnIndexMap);
|
|
2119
2393
|
const columns = this.tableSchema.columns;
|
|
2120
2394
|
const existingIndexes = this.tableSchema.indexes ?? [];
|
|
@@ -2133,6 +2407,8 @@ export class MemoryTableManager {
|
|
|
2133
2407
|
idx.columns.every((col, i) => col.index === uc.columns[i]) &&
|
|
2134
2408
|
this.indexCollationsMatchDeclared(idx, uc));
|
|
2135
2409
|
if (matchingUniqueIndex) {
|
|
2410
|
+
// No validation pass: the reused index is UNIQUE, so its own derived constraint
|
|
2411
|
+
// has already rejected every colliding row — committed and pending alike.
|
|
2136
2412
|
const newSchema = Object.freeze({
|
|
2137
2413
|
...this.tableSchema,
|
|
2138
2414
|
uniqueConstraints: appendedUcs,
|
|
@@ -2141,6 +2417,9 @@ export class MemoryTableManager {
|
|
|
2141
2417
|
this.tableSchema = newSchema;
|
|
2142
2418
|
this.initializePrimaryKeyFunctions();
|
|
2143
2419
|
this.implicitCoveringStructures.set(uc.name ?? matchingUniqueIndex.name, { indexName: matchingUniqueIndex.name, origin: 'implicit-from-unique-constraint' });
|
|
2420
|
+
// This arm skips addIndexToBase, but the open transaction's layers still need the
|
|
2421
|
+
// new `uniqueConstraints` entry or they will not enforce it.
|
|
2422
|
+
this.adoptSchemaOnOpenLayers(newSchema);
|
|
2144
2423
|
return;
|
|
2145
2424
|
}
|
|
2146
2425
|
const colNames = uc.columns.map(i => columns[i]?.name ?? String(i));
|
|
@@ -2153,19 +2432,23 @@ export class MemoryTableManager {
|
|
|
2153
2432
|
columns: uc.columns.map(colIdx => ({ index: colIdx, collation: columns[colIdx]?.collation })),
|
|
2154
2433
|
predicate: uc.predicate,
|
|
2155
2434
|
};
|
|
2435
|
+
// Validate BEFORE any mutation, over the DDL transaction's EFFECTIVE rows (throws
|
|
2436
|
+
// CONSTRAINT on the first in-scope duplicate). The covering index carries no
|
|
2437
|
+
// `unique: true` flag, so `addIndexToBase` would not check it anyway — and must
|
|
2438
|
+
// not: it populates from committed rows, which may still hold a duplicate this
|
|
2439
|
+
// transaction has deleted.
|
|
2440
|
+
await this.validateUniqueOverEffectiveRows(indexSchema, this.tableSchema, rows);
|
|
2156
2441
|
const newSchema = Object.freeze({
|
|
2157
2442
|
...this.tableSchema,
|
|
2158
2443
|
uniqueConstraints: appendedUcs,
|
|
2159
2444
|
indexes: Object.freeze([...existingIndexes, indexSchema]),
|
|
2160
2445
|
});
|
|
2161
|
-
// Swap the schema FIRST so `addIndexToBase` → `indexEnforcesUnique` sees the
|
|
2162
|
-
// new constraint and rejects duplicates, then populate (throws CONSTRAINT on
|
|
2163
|
-
// the first in-scope duplicate). A throw rolls back via the catch in addConstraint.
|
|
2164
2446
|
this.baseLayer.updateSchema(newSchema);
|
|
2165
2447
|
await this.baseLayer.addIndexToBase(indexSchema);
|
|
2166
2448
|
this.tableSchema = newSchema;
|
|
2167
2449
|
this.initializePrimaryKeyFunctions();
|
|
2168
2450
|
this.implicitCoveringStructures.set(uc.name ?? indexName, { indexName, origin: 'implicit-from-unique-constraint' });
|
|
2451
|
+
this.adoptSchemaOnOpenLayers(newSchema);
|
|
2169
2452
|
}
|
|
2170
2453
|
/**
|
|
2171
2454
|
* FOREIGN KEY arm of {@link addConstraint}. Validates existing child rows
|
|
@@ -2189,14 +2472,14 @@ export class MemoryTableManager {
|
|
|
2189
2472
|
}
|
|
2190
2473
|
async destroy() {
|
|
2191
2474
|
const lockKey = `MemoryTable.Destroy:${this.schemaName}.${this._tableName}`;
|
|
2192
|
-
const release = await
|
|
2475
|
+
const release = await this.db.latches.acquire(lockKey);
|
|
2193
2476
|
try {
|
|
2194
2477
|
for (const connection of this.connections.values()) {
|
|
2195
2478
|
if (connection.pendingTransactionLayer)
|
|
2196
2479
|
connection.rollback();
|
|
2197
2480
|
}
|
|
2198
2481
|
this.connections.clear();
|
|
2199
|
-
this.baseLayer = new BaseLayer(this.tableSchema);
|
|
2482
|
+
this.baseLayer = new BaseLayer(this.tableSchema, this.collationResolver);
|
|
2200
2483
|
this._currentCommittedLayer = this.baseLayer;
|
|
2201
2484
|
logger.operation('Destroy', this._tableName, 'Manager destroyed and data cleared');
|
|
2202
2485
|
}
|
|
@@ -2214,10 +2497,24 @@ export class MemoryTableManager {
|
|
|
2214
2497
|
throw new QuereusError(`Cannot perform schema change on table ${this._tableName} while older transaction versions are in use by active connections. Commit/rollback active transactions and retry.`, StatusCode.BUSY);
|
|
2215
2498
|
}
|
|
2216
2499
|
}
|
|
2500
|
+
// Consolidation drains COMMITTED layers into the base; a connection's own
|
|
2501
|
+
// UNCOMMITTED writes are untouched by it. Those rows are invisible to the DDL's
|
|
2502
|
+
// transaction, so a row-validating schema change cannot be checked against them,
|
|
2503
|
+
// and the sibling's layers cannot be re-pointed at the new schema. Only the
|
|
2504
|
+
// DDL-issuing connection may hold open work — everyone else must land first.
|
|
2505
|
+
const ddlConnection = this.ddlConnection();
|
|
2506
|
+
for (const connection of this.knownConnections()) {
|
|
2507
|
+
if (connection === ddlConnection || !connection.hasOpenWork())
|
|
2508
|
+
continue;
|
|
2509
|
+
throw new QuereusError(`Cannot perform schema change on table ${this._tableName} while another connection has uncommitted changes. Commit/rollback active transactions and retry.`, StatusCode.BUSY);
|
|
2510
|
+
}
|
|
2217
2511
|
// After ensuring we're at the base layer, update all connections to read from the base layer
|
|
2218
|
-
// This is necessary because connections might still be reading from promoted/collapsed layers
|
|
2512
|
+
// This is necessary because connections might still be reading from promoted/collapsed layers.
|
|
2513
|
+
// The DDL issuer's own open transaction is exempt: its read view is a pending layer or an
|
|
2514
|
+
// eager savepoint snapshot holding its uncommitted rows, and re-pointing it at the base
|
|
2515
|
+
// would silently drop them from every later read in that transaction.
|
|
2219
2516
|
for (const connection of this.connections.values()) {
|
|
2220
|
-
if (connection.readLayer !== this.baseLayer) {
|
|
2517
|
+
if (connection.readLayer !== this.baseLayer && !connection.hasOpenWork()) {
|
|
2221
2518
|
logger.debugLog(`[Schema Safety] Updating connection ${connection.connectionId} to read from base layer`);
|
|
2222
2519
|
connection.readLayer = this.baseLayer;
|
|
2223
2520
|
}
|
|
@@ -2242,6 +2539,17 @@ export class MemoryTableManager {
|
|
|
2242
2539
|
* the Database registry but not in the manager's map.
|
|
2243
2540
|
*/
|
|
2244
2541
|
repointRegisteredConnections() {
|
|
2542
|
+
for (const mc of this.registeredConnections()) {
|
|
2543
|
+
if (mc.hasOpenWork())
|
|
2544
|
+
continue;
|
|
2545
|
+
if (mc.readLayer === this.baseLayer)
|
|
2546
|
+
continue;
|
|
2547
|
+
logger.debugLog(`[Schema Safety] Re-pointing registered connection ${mc.connectionId} to base layer`);
|
|
2548
|
+
mc.readLayer = this.baseLayer;
|
|
2549
|
+
}
|
|
2550
|
+
}
|
|
2551
|
+
/** Every Database-registered {@link MemoryTableConnection} backed by this manager. */
|
|
2552
|
+
*registeredConnections() {
|
|
2245
2553
|
const qualifiedName = `${this.schemaName}.${this._tableName}`;
|
|
2246
2554
|
for (const c of this.db.getConnectionsForTable(qualifiedName)) {
|
|
2247
2555
|
if (!(c instanceof MemoryVirtualTableConnection))
|
|
@@ -2249,18 +2557,282 @@ export class MemoryTableManager {
|
|
|
2249
2557
|
const mc = c.getMemoryConnection();
|
|
2250
2558
|
if (mc.tableManager !== this)
|
|
2251
2559
|
continue;
|
|
2252
|
-
|
|
2560
|
+
yield mc;
|
|
2561
|
+
}
|
|
2562
|
+
}
|
|
2563
|
+
/**
|
|
2564
|
+
* Every connection this manager can see: the ones still attached to {@link connections}
|
|
2565
|
+
* (including unregistered committed-snapshot readers) plus the Database-registered ones,
|
|
2566
|
+
* which may have been detached from the map by a post-autocommit disconnect.
|
|
2567
|
+
*/
|
|
2568
|
+
*knownConnections() {
|
|
2569
|
+
const seen = new Set();
|
|
2570
|
+
for (const mc of this.connections.values()) {
|
|
2571
|
+
seen.add(mc);
|
|
2572
|
+
yield mc;
|
|
2573
|
+
}
|
|
2574
|
+
for (const mc of this.registeredConnections()) {
|
|
2575
|
+
if (seen.has(mc))
|
|
2253
2576
|
continue;
|
|
2254
|
-
|
|
2577
|
+
seen.add(mc);
|
|
2578
|
+
yield mc;
|
|
2579
|
+
}
|
|
2580
|
+
}
|
|
2581
|
+
/**
|
|
2582
|
+
* The connection through which the current DDL statement's transaction runs, if any.
|
|
2583
|
+
*
|
|
2584
|
+
* A statement reaches a memory table through the single Database-registered connection
|
|
2585
|
+
* for it (`MemoryTable.ensureConnection` and `getVTableConnection` both reuse the first
|
|
2586
|
+
* one), so that connection's view IS this statement's transaction. In autocommit with
|
|
2587
|
+
* no prior scan there is no connection at all, and the committed base is the whole story.
|
|
2588
|
+
*
|
|
2589
|
+
* NOTE: takes the FIRST registered connection, matching how both reuse sites pick one.
|
|
2590
|
+
* If the registry ever holds more than one connection per (table, transaction), this
|
|
2591
|
+
* picks arbitrarily — validate against the writer instead, and treat the rest as
|
|
2592
|
+
* siblings.
|
|
2593
|
+
*/
|
|
2594
|
+
ddlConnection() {
|
|
2595
|
+
for (const mc of this.registeredConnections())
|
|
2596
|
+
return mc;
|
|
2597
|
+
return undefined;
|
|
2598
|
+
}
|
|
2599
|
+
/**
|
|
2600
|
+
* The rows a `select` issued by the DDL statement's own transaction would see: the
|
|
2601
|
+
* committed base overlaid with that connection's uncommitted writes. Degenerates to the
|
|
2602
|
+
* base primary tree when no connection holds open work.
|
|
2603
|
+
*
|
|
2604
|
+
* `pendingTransactionLayer ?? readLayer` is exactly the layer `MemoryTable.query` scans,
|
|
2605
|
+
* and each layer's primary BTree is copy-on-write over its parent's, so one ascending
|
|
2606
|
+
* walk yields the merged view (pending inserts/updates present, pending deletes absent).
|
|
2607
|
+
*/
|
|
2608
|
+
effectiveDdlRows() {
|
|
2609
|
+
const connection = this.ddlConnection();
|
|
2610
|
+
const layer = connection
|
|
2611
|
+
? (connection.pendingTransactionLayer ?? connection.readLayer)
|
|
2612
|
+
: this.baseLayer;
|
|
2613
|
+
return iteratePrimaryRows(layer.getModificationTree('primary') ?? this.baseLayer.primaryTree);
|
|
2614
|
+
}
|
|
2615
|
+
/**
|
|
2616
|
+
* The committed base rows for `alter column … set data type` / `set not null` backfill, with the
|
|
2617
|
+
* value at `colIndex` run through `convert`. NULLs pass through untouched UNLESS `convertNulls` is
|
|
2618
|
+
* set (the SET NOT NULL backfill maps null → DEFAULT). A value that fails to convert is kept as-is:
|
|
2619
|
+
* the manager validated every value in the effective VIEW before calling, so a base value that
|
|
2620
|
+
* fails here is one a pending delete/overwrite shadows and no reader can see. The result is a fresh
|
|
2621
|
+
* full row list for {@link BaseLayer.rebuildPrimaryTreeFromRows} — the base primary tree is
|
|
2622
|
+
* REPLACED, never mutated in place (inheritree forbids mutating a tree the open transaction's
|
|
2623
|
+
* layers derive from).
|
|
2624
|
+
*/
|
|
2625
|
+
convertBaseRows(colIndex, convert, convertNulls = false) {
|
|
2626
|
+
const out = [];
|
|
2627
|
+
for (const row of iteratePrimaryRows(this.baseLayer.primaryTree)) {
|
|
2628
|
+
const oldVal = row[colIndex];
|
|
2629
|
+
if (oldVal === null && !convertNulls) {
|
|
2630
|
+
out.push(row);
|
|
2255
2631
|
continue;
|
|
2256
|
-
|
|
2257
|
-
|
|
2632
|
+
}
|
|
2633
|
+
let newVal;
|
|
2634
|
+
try {
|
|
2635
|
+
newVal = convert(oldVal);
|
|
2636
|
+
}
|
|
2637
|
+
catch {
|
|
2638
|
+
out.push(row); // shadowed unconvertible value — keep as-is
|
|
2639
|
+
continue;
|
|
2640
|
+
}
|
|
2641
|
+
out.push(row.map((v, i) => i === colIndex ? newVal : v));
|
|
2642
|
+
}
|
|
2643
|
+
return out;
|
|
2644
|
+
}
|
|
2645
|
+
/**
|
|
2646
|
+
* Rejects an index/constraint whose uniqueness the DDL transaction's own effective rows
|
|
2647
|
+
* already violate, BEFORE anything is mutated. Builds a throwaway {@link MemoryIndex} —
|
|
2648
|
+
* the collation-aware, partial-predicate-aware key comparator — over those rows and lets
|
|
2649
|
+
* {@link populateIndexFromRows} raise CONSTRAINT on the first duplicate.
|
|
2650
|
+
*
|
|
2651
|
+
* `rows` overrides {@link effectiveDdlRows}. A wrapper module (the isolation layer) holds
|
|
2652
|
+
* the transaction's pending rows outside this manager, so only it can name the rows the
|
|
2653
|
+
* issuing connection actually sees; when it supplies them, they are the judged set and this
|
|
2654
|
+
* manager's own committed rows are ignored. See `vtab/module.ts` {@link EffectiveRowSource}.
|
|
2655
|
+
*/
|
|
2656
|
+
async validateUniqueOverEffectiveRows(indexSchema, schema, rows) {
|
|
2657
|
+
const probe = new MemoryIndex(indexSchema, schema.columns, this.collationResolver, this.primaryKeyFunctions.compare, this.primaryKeyFunctions.encode, schema.name);
|
|
2658
|
+
if (rows) {
|
|
2659
|
+
await populateIndexFromRowsAsync(rows(), probe, this.primaryKeyFunctions.extractFromRow, true, this._tableName, schema.columns);
|
|
2660
|
+
return;
|
|
2661
|
+
}
|
|
2662
|
+
populateIndexFromRows(this.effectiveDdlRows(), probe, this.primaryKeyFunctions.extractFromRow, true, this._tableName, schema.columns);
|
|
2663
|
+
}
|
|
2664
|
+
/**
|
|
2665
|
+
* `ALTER COLUMN … SET COLLATE` arm of {@link validateUniqueOverEffectiveRows}: rejects the
|
|
2666
|
+
* change when it makes two of the DDL transaction's effective rows collide under any
|
|
2667
|
+
* uniqueness-enforcing structure that orders by the altered column. Runs before anything is
|
|
2668
|
+
* mutated, so a rejection leaves the table and schema untouched and the transaction usable.
|
|
2669
|
+
*
|
|
2670
|
+
* `newSchema` carries the post-change per-column collations, so each probe index compares
|
|
2671
|
+
* exactly as the rebuilt structure will. Indexes that do not mention the column keep their
|
|
2672
|
+
* keys and need no re-check.
|
|
2673
|
+
*
|
|
2674
|
+
* NOTE: walks `schema.indexes`, so a UNIQUE constraint covered by a row-time materialized
|
|
2675
|
+
* view rather than its auto-index (`findIndexForConstraint` prefers the MV) is not re-checked
|
|
2676
|
+
* here. The auto-index always exists alongside, so the structure is still validated — but if
|
|
2677
|
+
* an MV-only covering shape ever becomes reachable, this walk must follow it.
|
|
2678
|
+
*/
|
|
2679
|
+
async validateRekeyedUniqueStructures(newSchema, alteredColumnIndex, rows) {
|
|
2680
|
+
// NOTE: the probe index carries the manager's PRE-change `primaryKeyFunctions` (the new
|
|
2681
|
+
// ones cannot exist before the schema swaps). Only the probe's per-entry PK bookkeeping
|
|
2682
|
+
// uses them, and every effective row already has a distinct PK under the old encoder, so
|
|
2683
|
+
// duplicate detection — which fires on the index key, before any PK is stored — is
|
|
2684
|
+
// unaffected. If a probe ever needs to compare PKs semantically, pass the new functions in.
|
|
2685
|
+
for (const indexSchema of newSchema.indexes ?? []) {
|
|
2686
|
+
if (!indexSchema.columns.some(c => c.index === alteredColumnIndex))
|
|
2687
|
+
continue;
|
|
2688
|
+
if (!indexEnforcesUnique(newSchema, indexSchema))
|
|
2689
|
+
continue;
|
|
2690
|
+
// `rows` is re-callable, so each structure gets a fresh stream.
|
|
2691
|
+
await this.validateUniqueOverEffectiveRows(indexSchema, newSchema, rows);
|
|
2692
|
+
}
|
|
2693
|
+
}
|
|
2694
|
+
/**
|
|
2695
|
+
* PRIMARY KEY arm of the `alter column … set collate` pre-pass. Runs before anything is
|
|
2696
|
+
* mutated, so a rejection leaves the table, the schema and the transaction untouched.
|
|
2697
|
+
*
|
|
2698
|
+
* The primary tree is a map, not a multi-map, so — unlike a secondary index — it cannot
|
|
2699
|
+
* physically hold two rows whose keys collapse under the new comparator. Every layer the
|
|
2700
|
+
* DDL connection still reads through therefore has to be collision-free, not just the
|
|
2701
|
+
* transaction's effective view:
|
|
2702
|
+
*
|
|
2703
|
+
* 1. **The effective view collides** → `CONSTRAINT`. The duplicate is visible to a `select`
|
|
2704
|
+
* in this transaction; the change is simply illegal.
|
|
2705
|
+
* 2. **A layer beneath it collides** → `BUSY`. Those rows are not visible now, but every
|
|
2706
|
+
* such layer is the copy-on-write base the view reads through, and one of them may be a
|
|
2707
|
+
* savepoint snapshot a `rollback to savepoint` must restore. A re-keyed tree could not
|
|
2708
|
+
* represent the pair at all. Committing (or rolling back) settles the transaction and
|
|
2709
|
+
* the ALTER can be retried — the same "commit/rollback and retry" posture as
|
|
2710
|
+
* {@link ensureSchemaChangeSafety}.
|
|
2711
|
+
*
|
|
2712
|
+
* Case 2 is deliberately conservative. The chain holds one immutable layer per statement
|
|
2713
|
+
* boundary (see `MemoryTableConnection.createSavepoint`'s eager path), so it rejects any
|
|
2714
|
+
* transaction that has held a colliding pair at ANY statement boundary — even one whose
|
|
2715
|
+
* final view is clean and whose intermediate layer no savepoint can reach. Narrowing that
|
|
2716
|
+
* would mean re-parenting the view's tree past the unreachable layers, which is exactly the
|
|
2717
|
+
* rebase that savepoint snapshots exist to avoid. The tradeoff is a rare false BUSY on a
|
|
2718
|
+
* statement sequence the user can retry after committing, versus losing a row on rollback.
|
|
2719
|
+
*
|
|
2720
|
+
* This precondition is also what makes `TransactionLayer.rekeyPrimaryKey`'s replay sound:
|
|
2721
|
+
* with no collisions anywhere in the chain, every primary key resolves to at most one row
|
|
2722
|
+
* in each layer under the new comparator.
|
|
2723
|
+
*/
|
|
2724
|
+
validateRekeyedPrimaryKey(newSchema) {
|
|
2725
|
+
const newPkFunctions = createPrimaryKeyFunctions(newSchema, this.collationResolver);
|
|
2726
|
+
const connection = this.ddlConnection();
|
|
2727
|
+
const view = connection
|
|
2728
|
+
? (connection.pendingTransactionLayer ?? connection.readLayer)
|
|
2729
|
+
: this.baseLayer;
|
|
2730
|
+
this.assertNoPrimaryKeyCollision(view, newPkFunctions, StatusCode.CONSTRAINT, `UNIQUE constraint failed: ${this._tableName} primary key collides under new collation`);
|
|
2731
|
+
// `ensureSchemaChangeSafety` has already drained every committed layer into the base and
|
|
2732
|
+
// rejected sibling connections with open work, so the chain below the view holds only
|
|
2733
|
+
// this transaction's own layers.
|
|
2734
|
+
for (let layer = view.getParent(); layer; layer = layer.getParent()) {
|
|
2735
|
+
this.assertNoPrimaryKeyCollision(layer, newPkFunctions, StatusCode.BUSY, `Cannot change the collation of a primary key column of table ${this._tableName}: `
|
|
2736
|
+
+ `rows this transaction has removed still collide under the new collation and must survive a rollback. `
|
|
2737
|
+
+ `Commit/rollback and retry.`);
|
|
2738
|
+
}
|
|
2739
|
+
}
|
|
2740
|
+
/**
|
|
2741
|
+
* Raises `code` when two of `layer`'s rows share a primary key under `pkFunctions`.
|
|
2742
|
+
*
|
|
2743
|
+
* NOTE: O(rows) per layer, so O(layers × rows) for a whole chain — one more full pass than
|
|
2744
|
+
* the base rebuild the caller is about to do anyway. Fine for a statement this rare; if a
|
|
2745
|
+
* deep savepoint stack over a large table ever makes an ALTER slow, note that a layer's rows
|
|
2746
|
+
* differ from its parent's only at the keys it wrote, so the walk can be narrowed to those.
|
|
2747
|
+
*/
|
|
2748
|
+
assertNoPrimaryKeyCollision(layer, pkFunctions, code, message) {
|
|
2749
|
+
const tree = layer.getModificationTree('primary');
|
|
2750
|
+
if (!tree)
|
|
2751
|
+
return;
|
|
2752
|
+
const probe = new BTree((row) => pkFunctions.extractFromRow(row), pkFunctions.compare);
|
|
2753
|
+
for (const row of iteratePrimaryRows(tree)) {
|
|
2754
|
+
const key = pkFunctions.extractFromRow(row);
|
|
2755
|
+
if (probe.get(key) !== undefined)
|
|
2756
|
+
throw new QuereusError(message, code);
|
|
2757
|
+
probe.insert(row);
|
|
2758
|
+
}
|
|
2759
|
+
}
|
|
2760
|
+
/**
|
|
2761
|
+
* Propagates a schema change — a new index and/or UNIQUE constraint, or a set of structures
|
|
2762
|
+
* re-keyed by `alter column … set collate` — into every {@link TransactionLayer} the DDL
|
|
2763
|
+
* connection's open transaction still reads through: its pending layer and every savepoint
|
|
2764
|
+
* snapshot below it, which are exactly the transaction layers on the view layer's parent
|
|
2765
|
+
* chain above the base.
|
|
2766
|
+
*
|
|
2767
|
+
* Without this the transaction would keep enforcing (and scanning) its creation-time schema
|
|
2768
|
+
* for the rest of its life, a `rollback to savepoint` would restore a stale-schema layer,
|
|
2769
|
+
* and at commit the pending layer would become the committed head carrying its stale schema
|
|
2770
|
+
* and structures — shadowing the base's rebuilt ones. Rebasing would achieve the same but
|
|
2771
|
+
* invalidate those snapshots. Applied oldest-first: both
|
|
2772
|
+
* {@link TransactionLayer.adoptSchema} and {@link TransactionLayer.rekeyPrimaryKey} inherit
|
|
2773
|
+
* their parent's already-rebuilt trees.
|
|
2774
|
+
*
|
|
2775
|
+
* `rekeyPrimary` selects the heavier path, for the one change that invalidates a layer's
|
|
2776
|
+
* primary key functions and every structure derived from them: a collation change on a
|
|
2777
|
+
* primary key column.
|
|
2778
|
+
*/
|
|
2779
|
+
adoptSchemaOnOpenLayers(newSchema, rekeyPrimary = false) {
|
|
2780
|
+
for (const layer of this.openTransactionLayersOldestFirst()) {
|
|
2781
|
+
if (rekeyPrimary)
|
|
2782
|
+
layer.rekeyPrimaryKey(newSchema);
|
|
2783
|
+
else
|
|
2784
|
+
layer.adoptSchema(newSchema);
|
|
2258
2785
|
}
|
|
2259
2786
|
}
|
|
2787
|
+
/**
|
|
2788
|
+
* Converts the altered column's own-written values in every open transaction layer, after
|
|
2789
|
+
* `alter column … set data type` / `set not null` backfill has converted the base. Runs
|
|
2790
|
+
* oldest-first so each layer's copy-on-write base inherits its parent's already-converted rows
|
|
2791
|
+
* and only the layer's OWN writes are rewritten (see {@link TransactionLayer.convertColumn}).
|
|
2792
|
+
* `convertNulls` routes null own-values through `convert` (the SET NOT NULL null → DEFAULT map);
|
|
2793
|
+
* SET DATA TYPE leaves them untouched. No-op in autocommit.
|
|
2794
|
+
*
|
|
2795
|
+
* PRIMARY-KEY columns never reach here — a physical retype of a key column is rejected before
|
|
2796
|
+
* any mutation, and SET NOT NULL leaves the key bytes unchanged — so the primary tree's keys are
|
|
2797
|
+
* stable and no re-key is needed.
|
|
2798
|
+
*/
|
|
2799
|
+
convertColumnOnOpenLayers(newSchema, colIndex, convert, convertNulls = false) {
|
|
2800
|
+
for (const layer of this.openTransactionLayersOldestFirst()) {
|
|
2801
|
+
layer.convertColumn(colIndex, convert, newSchema, convertNulls);
|
|
2802
|
+
}
|
|
2803
|
+
}
|
|
2804
|
+
/**
|
|
2805
|
+
* The DDL connection's open {@link TransactionLayer}s, oldest-first, base excluded — its
|
|
2806
|
+
* pending layer and every savepoint snapshot below it, the layers on the view's parent chain
|
|
2807
|
+
* above the base. Empty in autocommit (no connection, or the view IS the base).
|
|
2808
|
+
*
|
|
2809
|
+
* Both schema adoption ({@link adoptSchemaOnOpenLayers}) and value conversion
|
|
2810
|
+
* ({@link convertColumnOnOpenLayers}) MUST apply oldest-first: each layer rebuilds its
|
|
2811
|
+
* structures over its parent's, so the parent's must already be the new/converted ones.
|
|
2812
|
+
*
|
|
2813
|
+
* NOTE: the walk takes every TransactionLayer below the view, which normally means the pending
|
|
2814
|
+
* layer and its savepoint snapshots. A committed layer already drained into the base by
|
|
2815
|
+
* `ensureSchemaChangeSafety` can also sit in the chain (the pending layer forked from it before
|
|
2816
|
+
* consolidation); it still shadows the base with its OWN unadapted rows while it remains the
|
|
2817
|
+
* view's copy-on-write base, so it must be adapted too — it cannot be skipped, since a savepoint
|
|
2818
|
+
* snapshot is `markCommitted()` as well. Both callers' per-layer work is idempotent and additive.
|
|
2819
|
+
*/
|
|
2820
|
+
openTransactionLayersOldestFirst() {
|
|
2821
|
+
const connection = this.ddlConnection();
|
|
2822
|
+
if (!connection)
|
|
2823
|
+
return [];
|
|
2824
|
+
const view = connection.pendingTransactionLayer ?? connection.readLayer;
|
|
2825
|
+
const chain = [];
|
|
2826
|
+
for (let cur = view; cur && cur !== this.baseLayer; cur = cur.getParent()) {
|
|
2827
|
+
if (cur instanceof TransactionLayer)
|
|
2828
|
+
chain.push(cur);
|
|
2829
|
+
}
|
|
2830
|
+
return chain.reverse();
|
|
2831
|
+
}
|
|
2260
2832
|
/** Consolidates all transaction data into the base layer for schema changes */
|
|
2261
2833
|
async consolidateToBaseLayer() {
|
|
2262
2834
|
const lockKey = `MemoryTable.Consolidate:${this.schemaName}.${this._tableName}`;
|
|
2263
|
-
const release = await
|
|
2835
|
+
const release = await this.db.latches.acquire(lockKey);
|
|
2264
2836
|
try {
|
|
2265
2837
|
logger.debugLog(`[Consolidate] Acquired lock for ${this._tableName}`);
|
|
2266
2838
|
// If current committed layer is a transaction layer, we need to merge its data into the base
|
|
@@ -2305,9 +2877,21 @@ export class MemoryTableManager {
|
|
|
2305
2877
|
// rebuilds the base secondary indexes from the new tree.
|
|
2306
2878
|
this.baseLayer.rebuildPrimaryTreeFromRows(allRows);
|
|
2307
2879
|
}
|
|
2308
|
-
/**
|
|
2880
|
+
/**
|
|
2881
|
+
* Sync scan — the hot path (query()/internal maintenance) avoids the async hop.
|
|
2882
|
+
* The backing BTree (inheritree) and all per-row filter/early-term logic are
|
|
2883
|
+
* fully synchronous, so no async boundary belongs here.
|
|
2884
|
+
*/
|
|
2885
|
+
scanLayerSync(layer, plan) {
|
|
2886
|
+
return scanLayerImpl(layer, plan);
|
|
2887
|
+
}
|
|
2888
|
+
/**
|
|
2889
|
+
* Async adapter for external `AsyncIterable<Row>` callers (tests,
|
|
2890
|
+
* `module.scanEffective`, the backing-host). Retained deliberately — do not
|
|
2891
|
+
* delete thinking it is dead; delegates to {@link scanLayerSync}.
|
|
2892
|
+
*/
|
|
2309
2893
|
async *scanLayer(layer, plan) {
|
|
2310
|
-
yield*
|
|
2894
|
+
yield* this.scanLayerSync(layer, plan);
|
|
2311
2895
|
}
|
|
2312
2896
|
}
|
|
2313
2897
|
//# sourceMappingURL=manager.js.map
|