@quereus/quereus 4.3.1 → 4.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +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 +3 -3
- package/dist/src/core/database-external-changes.d.ts.map +1 -1
- package/dist/src/core/database-external-changes.js +13 -10
- package/dist/src/core/database-external-changes.js.map +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 +422 -0
- package/dist/src/core/database-materialized-views-apply.d.ts.map +1 -0
- package/dist/src/core/database-materialized-views-apply.js +929 -0
- package/dist/src/core/database-materialized-views-apply.js.map +1 -0
- package/dist/src/core/database-materialized-views-plan-builders.d.ts +267 -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 +1423 -0
- package/dist/src/core/database-materialized-views-plan-builders.js.map +1 -0
- package/dist/src/core/database-materialized-views-plans.d.ts +641 -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 +108 -860
- package/dist/src/core/database-materialized-views.d.ts.map +1 -1
- package/dist/src/core/database-materialized-views.js +212 -2165
- 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 +270 -50
- 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/aggregate.d.ts.map +1 -1
- package/dist/src/func/builtins/aggregate.js +127 -21
- package/dist/src/func/builtins/aggregate.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/func/registration.d.ts +6 -1
- package/dist/src/func/registration.d.ts.map +1 -1
- package/dist/src/func/registration.js +16 -0
- package/dist/src/func/registration.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/equi-correlation.d.ts +26 -0
- package/dist/src/planner/analysis/equi-correlation.d.ts.map +1 -0
- package/dist/src/planner/analysis/equi-correlation.js +62 -0
- package/dist/src/planner/analysis/equi-correlation.js.map +1 -0
- package/dist/src/planner/analysis/query-rewrite-matcher.d.ts +54 -18
- package/dist/src/planner/analysis/query-rewrite-matcher.d.ts.map +1 -1
- package/dist/src/planner/analysis/query-rewrite-matcher.js +86 -42
- package/dist/src/planner/analysis/query-rewrite-matcher.js.map +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/scalar-subqueries.d.ts +28 -0
- package/dist/src/planner/analysis/scalar-subqueries.d.ts.map +1 -0
- package/dist/src/planner/analysis/scalar-subqueries.js +60 -0
- package/dist/src/planner/analysis/scalar-subqueries.js.map +1 -0
- package/dist/src/planner/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.d.ts.map +1 -1
- package/dist/src/planner/building/select.js +18 -4
- 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/building/with.d.ts.map +1 -1
- package/dist/src/planner/building/with.js +5 -8
- package/dist/src/planner/building/with.js.map +1 -1
- package/dist/src/planner/cache/materialization-advisory.d.ts +34 -2
- package/dist/src/planner/cache/materialization-advisory.d.ts.map +1 -1
- package/dist/src/planner/cache/materialization-advisory.js +185 -42
- package/dist/src/planner/cache/materialization-advisory.js.map +1 -1
- package/dist/src/planner/cache/reference-graph.d.ts +14 -5
- package/dist/src/planner/cache/reference-graph.d.ts.map +1 -1
- package/dist/src/planner/cache/reference-graph.js +31 -39
- package/dist/src/planner/cache/reference-graph.js.map +1 -1
- package/dist/src/planner/cost/index.d.ts +30 -5
- package/dist/src/planner/cost/index.d.ts.map +1 -1
- package/dist/src/planner/cost/index.js +26 -0
- package/dist/src/planner/cost/index.js.map +1 -1
- package/dist/src/planner/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 +19 -2
- package/dist/src/planner/nodes/cache-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/cache-node.js +43 -3
- package/dist/src/planner/nodes/cache-node.js.map +1 -1
- package/dist/src/planner/nodes/cte-node.d.ts +16 -1
- package/dist/src/planner/nodes/cte-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/cte-node.js +16 -3
- 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 +30 -1
- package/dist/src/planner/nodes/recursive-cte-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/recursive-cte-node.js +38 -5
- 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 +1014 -895
- 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-cte-optimization.d.ts.map +1 -1
- package/dist/src/planner/rules/cache/rule-cte-optimization.js +8 -1
- package/dist/src/planner/rules/cache/rule-cte-optimization.js.map +1 -1
- package/dist/src/planner/rules/cache/rule-in-subquery-cache.d.ts +7 -0
- package/dist/src/planner/rules/cache/rule-in-subquery-cache.d.ts.map +1 -1
- package/dist/src/planner/rules/cache/rule-in-subquery-cache.js +14 -1
- package/dist/src/planner/rules/cache/rule-in-subquery-cache.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.d.ts.map +1 -1
- package/dist/src/planner/rules/cache/rule-materialized-view-rewrite.js +55 -56
- package/dist/src/planner/rules/cache/rule-materialized-view-rewrite.js.map +1 -1
- package/dist/src/planner/rules/cache/rule-mutating-subquery-cache.d.ts.map +1 -1
- package/dist/src/planner/rules/cache/rule-mutating-subquery-cache.js +6 -0
- package/dist/src/planner/rules/cache/rule-mutating-subquery-cache.js.map +1 -1
- package/dist/src/planner/rules/cache/rule-nested-loop-right-cache.d.ts +25 -0
- package/dist/src/planner/rules/cache/rule-nested-loop-right-cache.d.ts.map +1 -0
- package/dist/src/planner/rules/cache/rule-nested-loop-right-cache.js +176 -0
- package/dist/src/planner/rules/cache/rule-nested-loop-right-cache.js.map +1 -0
- package/dist/src/planner/rules/cache/rule-scalar-cse.d.ts +1 -1
- package/dist/src/planner/rules/cache/rule-scalar-cse.js +1 -1
- package/dist/src/planner/rules/cache/rule-scalar-subquery-cache.d.ts +29 -0
- package/dist/src/planner/rules/cache/rule-scalar-subquery-cache.d.ts.map +1 -0
- package/dist/src/planner/rules/cache/rule-scalar-subquery-cache.js +66 -0
- package/dist/src/planner/rules/cache/rule-scalar-subquery-cache.js.map +1 -0
- 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-fanout-lookup-join.d.ts.map +1 -1
- package/dist/src/planner/rules/join/rule-fanout-lookup-join.js +1 -54
- package/dist/src/planner/rules/join/rule-fanout-lookup-join.js.map +1 -1
- package/dist/src/planner/rules/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/rules/subquery/rule-scalar-agg-decorrelation.d.ts +191 -0
- package/dist/src/planner/rules/subquery/rule-scalar-agg-decorrelation.d.ts.map +1 -0
- package/dist/src/planner/rules/subquery/rule-scalar-agg-decorrelation.js +623 -0
- package/dist/src/planner/rules/subquery/rule-scalar-agg-decorrelation.js.map +1 -0
- package/dist/src/planner/rules/subquery/rule-subquery-decorrelation.d.ts +10 -1
- package/dist/src/planner/rules/subquery/rule-subquery-decorrelation.d.ts.map +1 -1
- package/dist/src/planner/rules/subquery/rule-subquery-decorrelation.js +242 -51
- package/dist/src/planner/rules/subquery/rule-subquery-decorrelation.js.map +1 -1
- package/dist/src/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/cache/shared-cache.d.ts +7 -0
- package/dist/src/runtime/cache/shared-cache.d.ts.map +1 -1
- package/dist/src/runtime/cache/shared-cache.js +34 -1
- package/dist/src/runtime/cache/shared-cache.js.map +1 -1
- package/dist/src/runtime/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 +2 -3
- package/dist/src/runtime/emit/aggregate.d.ts.map +1 -1
- package/dist/src/runtime/emit/aggregate.js +23 -28
- 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 +7 -3
- package/dist/src/runtime/emit/cache.d.ts.map +1 -1
- package/dist/src/runtime/emit/cache.js +25 -7
- 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 +45 -21
- 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 +138 -74
- 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 +128 -16
- 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 +61 -2
- 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 +32 -4
- package/dist/src/runtime/parallel-driver.d.ts.map +1 -1
- package/dist/src/runtime/parallel-driver.js +88 -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 +102 -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/function.d.ts +79 -0
- package/dist/src/schema/function.d.ts.map +1 -1
- package/dist/src/schema/function.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 +59 -24
- 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
|
@@ -0,0 +1,929 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Materialized-view maintenance — **delta apply**. The per-row / per-flush appliers that
|
|
3
|
+
* take a compiled {@link MaintenancePlan} plus a source {@link BackingRowChange}, compute the
|
|
4
|
+
* bounded backing delta (or the full-rebuild diff), and write it through the backing table's
|
|
5
|
+
* coordinated transaction connection — plus the residual runners, backing-host / connection
|
|
6
|
+
* resolvers, derived-row and parent-side referential enforcement, and the small key-compare
|
|
7
|
+
* helpers they share. Extracted from database-materialized-views.ts as free functions over
|
|
8
|
+
* {@link MaterializedViewManagerContext}; the manager's orchestration methods
|
|
9
|
+
* (`maintainRowTime`, `flushDeferredMaintenance`, `lookupCoveringConflicts`) call in.
|
|
10
|
+
*/
|
|
11
|
+
import { QuereusError } from '../common/errors.js';
|
|
12
|
+
import { StatusCode } from '../common/types.js';
|
|
13
|
+
import { createStrictRowContextMap, wrapTableContextsStrict } from '../runtime/strict-fork.js';
|
|
14
|
+
import { isAsyncIterable } from '../runtime/utils.js';
|
|
15
|
+
import { resolveBackingHost, nullInNotNullSeededPkError } from '../runtime/emit/materialized-view-helpers.js';
|
|
16
|
+
import { assertTransitiveRestrictsForParentMutation, executeForeignKeyActionsAndLens } from '../runtime/foreign-key-actions.js';
|
|
17
|
+
import { validateDerivedRowImage } from './derived-row-validator.js';
|
|
18
|
+
import { buildPrimaryKeyFromValues } from '../vtab/memory/utils/primary-key.js';
|
|
19
|
+
import { compareSqlValuesFast, rowsValueIdentical } from '../util/comparison.js';
|
|
20
|
+
import { canonKeyValues } from './database-materialized-views-analysis.js';
|
|
21
|
+
import { cloneInitialValue } from '../func/registration.js';
|
|
22
|
+
/**
|
|
23
|
+
* Resolve a plan's backing table to its {@link BackingHost} + coordinated
|
|
24
|
+
* {@link VirtualTableConnection} — the two handles every apply path writes through.
|
|
25
|
+
* Shared by the per-row appliers, the batched residual flush, and the full-rebuild
|
|
26
|
+
* `'replace-all'` diff; throws INTERNAL when the backing table has vanished (an MV in a
|
|
27
|
+
* broken state).
|
|
28
|
+
*/
|
|
29
|
+
export async function resolveBackingApplyTarget(ctx,
|
|
30
|
+
// Structural (not the MaintenancePlan union) so the shared ForwardResidualPlan
|
|
31
|
+
// subset the join arm reuses resolves through it too.
|
|
32
|
+
plan, cache) {
|
|
33
|
+
const backing = ctx.schemaManager.getTable(plan.backingSchema, plan.backingTableName);
|
|
34
|
+
if (!backing) {
|
|
35
|
+
throw new QuereusError(`Internal error: backing table '${plan.backingTableName}' for materialized view '${plan.mv.name}' not found`, StatusCode.INTERNAL);
|
|
36
|
+
}
|
|
37
|
+
const host = backingHost(ctx, backing);
|
|
38
|
+
const connection = await getBackingConnection(ctx, host, `${plan.backingSchema}.${plan.backingTableName}`, cache);
|
|
39
|
+
return { host, connection };
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Compute an `'inverse-projection'` plan's per-row backing delta, apply it, and
|
|
43
|
+
* return the **effective** {@link BackingRowChange}(s) the backing layer realized.
|
|
44
|
+
* An out-of-scope row (or a delete of an absent backing key) yields no change. This
|
|
45
|
+
* body is the shipped covering-index maintenance, lifted verbatim from the former
|
|
46
|
+
* `applyRowTimeChange`, plus the equal-image short-circuit: an UPDATE whose old and
|
|
47
|
+
* new projected images are value-identical (both in scope) projects to NO backing
|
|
48
|
+
* delta — the dominant no-op echo (a source update touching only unprojected columns,
|
|
49
|
+
* or rewriting a projected column to its existing value) is suppressed before any
|
|
50
|
+
* backing-connection work. Accurate by the maintenance invariant (the backing row IS
|
|
51
|
+
* the old image's projection), so nothing would have changed; the host's
|
|
52
|
+
* value-identical upsert skip (vtab/backing-host.ts) remains the effective-state
|
|
53
|
+
* backstop for the paths that do emit ops.
|
|
54
|
+
*/
|
|
55
|
+
export async function applyInverseProjection(ctx, plan, change, cache) {
|
|
56
|
+
const inScope = (row) => plan.predicate === undefined || plan.predicate.evaluate(row) === true;
|
|
57
|
+
const project = (row) => plan.projectors.map(p => p.kind === 'passthrough' ? row[p.sourceCol] : p.eval(row));
|
|
58
|
+
const keyOf = (backingRow) => buildPrimaryKeyFromValues(plan.backingPkDefinition.map(d => backingRow[d.index]), plan.backingPkDefinition);
|
|
59
|
+
const ops = [];
|
|
60
|
+
if (change.op === 'insert') {
|
|
61
|
+
if (inScope(change.newRow))
|
|
62
|
+
ops.push({ kind: 'upsert', row: project(change.newRow) });
|
|
63
|
+
}
|
|
64
|
+
else if (change.op === 'delete') {
|
|
65
|
+
if (inScope(change.oldRow))
|
|
66
|
+
ops.push({ kind: 'delete-key', key: keyOf(project(change.oldRow)) });
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
// UPDATE: a both-in-scope, same-backing-key change is one upsert (the host
|
|
70
|
+
// reports a single `update`); otherwise delete the old image if it was in
|
|
71
|
+
// scope and upsert the new image if it is — predicate-scope transitions and
|
|
72
|
+
// key-changing updates are genuinely two-sided. The scope check reads the
|
|
73
|
+
// SOURCE row (the predicate may reference unprojected columns), so both
|
|
74
|
+
// images must be in scope for the equal-image short-circuit.
|
|
75
|
+
const oldIn = inScope(change.oldRow);
|
|
76
|
+
const newIn = inScope(change.newRow);
|
|
77
|
+
if (oldIn && newIn) {
|
|
78
|
+
const oldImage = project(change.oldRow);
|
|
79
|
+
const newImage = project(change.newRow);
|
|
80
|
+
// Byte-faithful identity (rowsValueIdentical): subsumes key equality, and a
|
|
81
|
+
// collation-equal / byte-different image is NOT suppressed (it must re-key
|
|
82
|
+
// the stored bytes) — the same discipline as the host-level upsert skip.
|
|
83
|
+
if (rowsValueIdentical(oldImage, newImage))
|
|
84
|
+
return [];
|
|
85
|
+
if (backingPkEqual(plan.backingPkDefinition, oldImage, newImage)) {
|
|
86
|
+
// Same backing key (collation-aware — a collation-equal / byte-different
|
|
87
|
+
// key is the SAME btree identity, and the upsert re-keys the stored
|
|
88
|
+
// bytes): one upsert replaces the row wholesale, so the host reports
|
|
89
|
+
// a single `update` — matching the residual arms' post-suppression
|
|
90
|
+
// shape (one cascade dispatch, one change-log entry, no secondary-index
|
|
91
|
+
// churn from a delete+insert at an unchanged key).
|
|
92
|
+
ops.push({ kind: 'upsert', row: newImage });
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
ops.push({ kind: 'delete-key', key: keyOf(oldImage) });
|
|
96
|
+
ops.push({ kind: 'upsert', row: newImage });
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
if (oldIn)
|
|
101
|
+
ops.push({ kind: 'delete-key', key: keyOf(project(change.oldRow)) });
|
|
102
|
+
if (newIn)
|
|
103
|
+
ops.push({ kind: 'upsert', row: project(change.newRow) });
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
if (ops.length === 0)
|
|
107
|
+
return [];
|
|
108
|
+
const { host, connection } = await resolveBackingApplyTarget(ctx, plan, cache);
|
|
109
|
+
return host.applyMaintenance(connection, ops);
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Validate the row images a maintenance apply WROTE (insert/update
|
|
113
|
+
* {@link BackingRowChange}s — a delete writes no image) against the plan's
|
|
114
|
+
* compiled {@link DerivedRowConstraintValidator}. Inline checks abort the
|
|
115
|
+
* writing statement with the maintained-table-attributed CONSTRAINT error;
|
|
116
|
+
* auto-deferred checks (subquery CHECK, every child-side FK) queue to the
|
|
117
|
+
* deferred-constraint queue and validate at commit. Deferred entries are
|
|
118
|
+
* pinned to the backing connection the maintenance write used (resolved from
|
|
119
|
+
* the per-statement cache, or re-resolved deterministically — the same
|
|
120
|
+
* connection either way) so commit-time evaluation reads the same pending
|
|
121
|
+
* state, mirroring the DML pipeline's active-connection capture.
|
|
122
|
+
*/
|
|
123
|
+
export async function validateDerivedChanges(ctx, plan, validator, changes, cache) {
|
|
124
|
+
let connectionId;
|
|
125
|
+
if (validator.checks.some(c => c.needsDeferred)) {
|
|
126
|
+
const backing = ctx.schemaManager.getTable(plan.backingSchema, plan.backingTableName);
|
|
127
|
+
if (backing) {
|
|
128
|
+
const host = backingHost(ctx, backing);
|
|
129
|
+
const conn = await getBackingConnection(ctx, host, `${plan.backingSchema}.${plan.backingTableName}`, cache);
|
|
130
|
+
connectionId = conn.connectionId;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
for (const change of changes) {
|
|
134
|
+
if (change.op === 'delete')
|
|
135
|
+
continue;
|
|
136
|
+
await validateDerivedRowImage(ctx, validator, change.newRow, connectionId);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Row-time guard: reject a maintenance write that would store a NULL into a backing column
|
|
141
|
+
* the schema declares NOT NULL *and* that is a physical-PK member whose re-derived body
|
|
142
|
+
* output turned nullable — the row-time analogue of the refresh-path
|
|
143
|
+
* `assertNoNullInNotNullSeededPk` (runtime/emit/materialized-view-helpers.ts). Row-time
|
|
144
|
+
* maintenance is the PRIMARY silent-corruption vector: it fires at the source
|
|
145
|
+
* insert/update, before any refresh, so without this guard a NULL lands in a
|
|
146
|
+
* declared-NOT-NULL PK column with no error.
|
|
147
|
+
*
|
|
148
|
+
* The offending skew (a NOT-NULL ordering-seeded PK column over a loosened source) is
|
|
149
|
+
* precomputed once at plan build into {@link MaintenancePlanCommon.nullGuardColumns}
|
|
150
|
+
* (`undefined` for nearly every MV — the zero-overhead gate), so the common path pays a
|
|
151
|
+
* single boolean check per maintained write and only the rare skewed MV scans its guarded
|
|
152
|
+
* columns per change. A `delete` writes no image and is skipped. The throw unwinds the source
|
|
153
|
+
* statement with nothing committed — the backing write rides the pending layer, discarded on
|
|
154
|
+
* a throw before commit, exactly like {@link validateDerivedChanges}. Called BEFORE the
|
|
155
|
+
* MV-over-MV cascade so a NULL row never reaches a consumer. See
|
|
156
|
+
* fix/bug-mv-rowtime-null-into-notnull-seeded-pk.
|
|
157
|
+
*/
|
|
158
|
+
export function assertNoNullInNotNullSeededPkRowTime(plan, changes) {
|
|
159
|
+
const guard = plan.nullGuardColumns;
|
|
160
|
+
if (!guard)
|
|
161
|
+
return;
|
|
162
|
+
for (const change of changes) {
|
|
163
|
+
if (change.op === 'delete')
|
|
164
|
+
continue; // a delete writes no image
|
|
165
|
+
for (const g of guard) {
|
|
166
|
+
const v = change.newRow[g.index];
|
|
167
|
+
if (v === null || v === undefined) {
|
|
168
|
+
throw nullInNotNullSeededPkError(plan.mv.schemaName, plan.mv.name, g.name);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Fire **parent-side** referential enforcement over the backing rows a maintenance
|
|
175
|
+
* apply REMOVED or re-keyed (delete / key-update {@link BackingRowChange}s — an insert
|
|
176
|
+
* has no parent-side action). When the maintained table `M` is the PARENT (FK target)
|
|
177
|
+
* of an FK declared on an ordinary table `C` (`create table C (… references M(col) …)`),
|
|
178
|
+
* a maintenance-driven delete/key-update of the referenced `M` row would silently orphan
|
|
179
|
+
* `C`'s rows, bypassing the declared RESTRICT / referential action. This is the
|
|
180
|
+
* **dual** of {@link validateDerivedChanges} (constraints declared *on* `M`); the FK here
|
|
181
|
+
* lives on `C` and references `M`, so it is invisible to `M`'s own plan/validator.
|
|
182
|
+
*
|
|
183
|
+
* It reuses the SAME shared referential-action engine the DML executor and the
|
|
184
|
+
* external-change ingestion seam use — no third copy — applying its two functions over
|
|
185
|
+
* each backing change exactly as `database-external-changes.ts` does:
|
|
186
|
+
* - {@link assertTransitiveRestrictsForParentMutation} — pre-walk the transitive cascade
|
|
187
|
+
* closure and throw a CONSTRAINT error naming `M` on any surviving RESTRICT child;
|
|
188
|
+
* - {@link executeForeignKeyActionsAndLens} — run declared CASCADE / SET NULL / SET DEFAULT,
|
|
189
|
+
* re-entering the DML executor (the already-holding-the-mutex variant) for each cascaded
|
|
190
|
+
* child write, so `C`'s own constraints, watches, nested cascades, and (if `C` is itself
|
|
191
|
+
* an MV source) its own maintenance all fire.
|
|
192
|
+
*
|
|
193
|
+
* Ordering: called AFTER the backing delta has landed in the pending layer (the RESTRICT
|
|
194
|
+
* walk runs POST-application — the child rows it keys off still exist because the cascade
|
|
195
|
+
* has not run yet) and AFTER `M`'s own image is validated, matching the DML executor's
|
|
196
|
+
* per-change order (capture → MV maintenance → FK actions) and the external-changes seam.
|
|
197
|
+
* `lensRouted = false`: a maintenance backing write is a physical basis write (maintained
|
|
198
|
+
* tables are not lens basis spines). A surviving RESTRICT throws up through
|
|
199
|
+
* {@link maintainRowTime} → the DML executor → the statement, rolling back the source write
|
|
200
|
+
* attributed to `M`.
|
|
201
|
+
*
|
|
202
|
+
* Gate: a cheap `foreign_keys`-pragma early-return keeps the pragma-off path free (the
|
|
203
|
+
* engine also early-returns, but skipping the `getTable` + loop avoids all per-change work).
|
|
204
|
+
* NOT gated on `plan.derivedRowValidator` — that gate is child-side (constraints *on* `M`);
|
|
205
|
+
* an inbound FK lives on `C` and leaves `M`'s plan untouched. Beyond the gate it fires
|
|
206
|
+
* unconditionally per delete/update change, but the engine no longer pays an `O(catalog)`
|
|
207
|
+
* scan: both calls route through `SchemaManager.getReferencingForeignKeys`, the precomputed
|
|
208
|
+
* reverse-FK index, so an `M` that nothing references resolves to the shared empty bucket and
|
|
209
|
+
* each call early-returns in O(1) — a maintained table with no inbound FK (the common case)
|
|
210
|
+
* pays only the pragma check plus one map lookup per delete/key-update change.
|
|
211
|
+
*/
|
|
212
|
+
export async function enforceParentSideReferentialActions(ctx, plan, changes) {
|
|
213
|
+
const db = ctx;
|
|
214
|
+
if (!db.options.getBooleanOption('foreign_keys'))
|
|
215
|
+
return; // cheap gate; engine early-returns too
|
|
216
|
+
// The backing `TableSchema` — same object validateDerivedChanges resolves; its `.name`
|
|
217
|
+
// equals `M`'s, so an FK on `C` (`references M`) matches the engine's referencing scan.
|
|
218
|
+
const parent = ctx.schemaManager.getTable(plan.backingSchema, plan.backingTableName);
|
|
219
|
+
if (!parent)
|
|
220
|
+
return; // backing gone ⇒ MV already broken
|
|
221
|
+
for (const change of changes) {
|
|
222
|
+
if (change.op === 'insert')
|
|
223
|
+
continue; // inserts have no parent-side actions
|
|
224
|
+
await assertTransitiveRestrictsForParentMutation(db, parent, change.op, change.oldRow, change.newRow);
|
|
225
|
+
await executeForeignKeyActionsAndLens(db, parent, change.op, change.oldRow, change.newRow);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Resolve the {@link BackingHost} capability surface for a backing table —
|
|
230
|
+
* see `vtab/backing-host.ts` for the contract. The host is resolved fresh per
|
|
231
|
+
* use (a map lookup on the owning module), so a drop+recreate of the backing
|
|
232
|
+
* always yields the new incarnation's host.
|
|
233
|
+
*/
|
|
234
|
+
export function backingHost(ctx, backing) {
|
|
235
|
+
// The ctx IS the Database (same construction as buildMaintenancePlan's cast).
|
|
236
|
+
return resolveBackingHost(ctx, backing);
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Obtain (lazily create + register) the backing table's
|
|
240
|
+
* {@link VirtualTableConnection} for the current transaction. Reuses the same
|
|
241
|
+
* connection a `select` from the MV resolves to (so reads-own-writes holds) —
|
|
242
|
+
* matched among the Database's registered connections by
|
|
243
|
+
* {@link BackingHost.ownsConnection}, which is pinned to the live backing
|
|
244
|
+
* incarnation; a freshly created connection is registered with the Database so
|
|
245
|
+
* the coordinated commit/rollback covers its pending state in lockstep with the
|
|
246
|
+
* source write.
|
|
247
|
+
*
|
|
248
|
+
* When an optional per-statement {@link BackingConnectionCache} is supplied, the
|
|
249
|
+
* scan over the Database's active connections (the dominant per-row cost on a bulk
|
|
250
|
+
* write) is paid once per (statement, backing): a hit returns the cached connection
|
|
251
|
+
* directly, and a miss caches whichever connection the scan resolves — or the one it
|
|
252
|
+
* lazily creates + registers. Caching the resolved/created connection is sound
|
|
253
|
+
* because the scan is deterministic within a statement (nothing interleaves between
|
|
254
|
+
* a statement's rows to change which connection a `select` from the MV picks), so the
|
|
255
|
+
* cache holds exactly what an uncached re-resolution would return.
|
|
256
|
+
*/
|
|
257
|
+
export async function getBackingConnection(ctx, host, qualifiedName, cache) {
|
|
258
|
+
const cacheKey = qualifiedName.toLowerCase();
|
|
259
|
+
const cached = cache?.get(cacheKey);
|
|
260
|
+
if (cached)
|
|
261
|
+
return cached;
|
|
262
|
+
for (const c of ctx.getConnectionsForTable(qualifiedName)) {
|
|
263
|
+
if (host.ownsConnection(c)) {
|
|
264
|
+
cache?.set(cacheKey, c);
|
|
265
|
+
return c;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
const conn = host.connect();
|
|
269
|
+
await ctx.registerConnection(conn);
|
|
270
|
+
cache?.set(cacheKey, conn);
|
|
271
|
+
return conn;
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Execute a cached key-filtered residual for one affected key tuple, returning its
|
|
275
|
+
* result rows (0 or 1 for the aggregate shape; 0..N for the lateral-TVF fan-out shape).
|
|
276
|
+
* Bound through a fresh {@link RuntimeContext} on the live `db` so the residual's source
|
|
277
|
+
* scan reuses `T`'s transaction connection and reads this statement's pending writes
|
|
278
|
+
* (reads-own-writes) — the synchronous analogue of
|
|
279
|
+
* `database-assertions.ts:executeResidualPerTuple`. Shared by the residual-recompute
|
|
280
|
+
* (`'gk'`) and prefix-delete (`'pk'`) arms.
|
|
281
|
+
*/
|
|
282
|
+
export async function runResidual(ctx, residualScheduler, bindParamPrefix, keyTuple) {
|
|
283
|
+
const params = {};
|
|
284
|
+
for (let i = 0; i < keyTuple.length; i++) {
|
|
285
|
+
params[`${bindParamPrefix}${i}`] = keyTuple[i];
|
|
286
|
+
}
|
|
287
|
+
return runScheduler(ctx, residualScheduler, params);
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Run a cached maintenance scheduler to completion against **live mid-transaction source
|
|
291
|
+
* state** and collect its result rows. Bound through a fresh strict {@link RuntimeContext}
|
|
292
|
+
* on the live `db` so the scan reuses the source's transaction connection and reads this
|
|
293
|
+
* statement's pending writes (reads-own-writes). The no-`stmt`, fresh-context shape is the
|
|
294
|
+
* synchronous analogue of `database-assertions.ts:executeResidualPerTuple`. Shared by the
|
|
295
|
+
* key-filtered residual arms ({@link runResidual}, parameterized) and the whole-body
|
|
296
|
+
* full-rebuild arm ({@link applyFullRebuild}, no params).
|
|
297
|
+
*/
|
|
298
|
+
export async function runScheduler(ctx, scheduler, params) {
|
|
299
|
+
const rctx = {
|
|
300
|
+
db: ctx,
|
|
301
|
+
stmt: undefined,
|
|
302
|
+
params,
|
|
303
|
+
context: createStrictRowContextMap(),
|
|
304
|
+
tableContexts: wrapTableContextsStrict(new Map()),
|
|
305
|
+
enableMetrics: false,
|
|
306
|
+
};
|
|
307
|
+
const result = await scheduler.run(rctx);
|
|
308
|
+
const rows = [];
|
|
309
|
+
if (isAsyncIterable(result)) {
|
|
310
|
+
for await (const r of result)
|
|
311
|
+
rows.push(r);
|
|
312
|
+
}
|
|
313
|
+
return rows;
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Compute a **forward** key-filtered residual plan's per-row backing delta and apply it:
|
|
317
|
+
* derive the affected binding key(s) from the changed row (OLD ∪ NEW, deduped), re-run
|
|
318
|
+
* the key-filtered residual against live source state for each, and apply the **keyed
|
|
319
|
+
* diff**: a non-empty recomputed slice is upserted (the backing key IS the affected key,
|
|
320
|
+
* so the upsert replaces the old row wholesale — no delete-first — and the host's
|
|
321
|
+
* value-identical upsert skip turns a no-op recompute into ZERO effective changes
|
|
322
|
+
* instead of delete+insert churn); an emptied slice (residual returns nothing) emits the
|
|
323
|
+
* point delete, removing the stale backing row (nothing reported if it was already
|
|
324
|
+
* absent). Returns the effective {@link BackingRowChange}(s) the backing layer realized,
|
|
325
|
+
* for the MV-over-MV cascade — a real same-key change now reports one `update`.
|
|
326
|
+
*
|
|
327
|
+
* Shared by the single-source aggregate (`'residual-recompute'`, group key, ≤1 row per
|
|
328
|
+
* key) and the 1:1-join (`'join-residual'`, the driving table `T`'s PK, exactly the one
|
|
329
|
+
* joined row per key) arms — both bind on the forward driving source via
|
|
330
|
+
* {@link ForwardResidualPlan}; the only difference is the binding (group vs PK).
|
|
331
|
+
*
|
|
332
|
+
* This is the **cold** (no statement batch in scope) inline path. A statement-batched
|
|
333
|
+
* caller instead accumulates the same deduped keys via
|
|
334
|
+
* {@link collectForwardResidualKeys} and recomputes each distinct key once at the
|
|
335
|
+
* end-of-statement flush ({@link computeForwardResidualOps}) — sound for the same
|
|
336
|
+
* last-write-wins reason: every recompute reads live (reads-own-writes) state, so
|
|
337
|
+
* running it once at flush produces exactly what the last per-row run would have.
|
|
338
|
+
*/
|
|
339
|
+
export async function applyForwardResidual(ctx, plan, change, cache) {
|
|
340
|
+
const affected = new Map();
|
|
341
|
+
collectForwardResidualKeys(plan, change, affected);
|
|
342
|
+
const ops = await computeForwardResidualOps(ctx, plan, affected.values());
|
|
343
|
+
if (ops.length === 0)
|
|
344
|
+
return [];
|
|
345
|
+
const { host, connection } = await resolveBackingApplyTarget(ctx, plan, cache);
|
|
346
|
+
return host.applyMaintenance(connection, ops);
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* Derive one changed source row's affected forward binding key(s) (OLD ∪ NEW) and add
|
|
350
|
+
* them to `into`, deduped on the canonical backing-key values: a non-key-changing update
|
|
351
|
+
* recomputes the group once; a key-changing update recomputes both the old and the new
|
|
352
|
+
* group. `into` may span a whole statement (the per-statement {@link ResidualKeyBatch})
|
|
353
|
+
* or a single change (the cold inline path) — the dedup is identical either way.
|
|
354
|
+
*/
|
|
355
|
+
export function collectForwardResidualKeys(plan, change, into) {
|
|
356
|
+
const addFrom = (row) => {
|
|
357
|
+
const keyVals = plan.backingPkSourceCols.map(sc => row[sc]);
|
|
358
|
+
const dedupKey = canonKeyValues(keyVals);
|
|
359
|
+
if (into.has(dedupKey))
|
|
360
|
+
return;
|
|
361
|
+
into.set(dedupKey, {
|
|
362
|
+
keyTuple: plan.bindColumns.map(c => row[c]),
|
|
363
|
+
keyVals,
|
|
364
|
+
deleteKey: buildPrimaryKeyFromValues(keyVals, plan.backingPkDefinition),
|
|
365
|
+
});
|
|
366
|
+
};
|
|
367
|
+
if (change.op === 'insert')
|
|
368
|
+
addFrom(change.newRow);
|
|
369
|
+
else if (change.op === 'delete')
|
|
370
|
+
addFrom(change.oldRow);
|
|
371
|
+
else {
|
|
372
|
+
addFrom(change.oldRow);
|
|
373
|
+
addFrom(change.newRow);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
/**
|
|
377
|
+
* Run the forward key-filtered residual once per affected key and build the keyed-diff
|
|
378
|
+
* ops: upsert the recomputed slice, or point-delete an emptied key. Pure op computation —
|
|
379
|
+
* the caller owns connection resolution and the single {@link BackingHost.applyMaintenance}
|
|
380
|
+
* call, so a statement flush can batch many keys' ops into one host call.
|
|
381
|
+
*/
|
|
382
|
+
export async function computeForwardResidualOps(ctx, plan, keys) {
|
|
383
|
+
const ops = [];
|
|
384
|
+
for (const { keyTuple, keyVals, deleteKey } of keys) {
|
|
385
|
+
const recomputed = await runResidual(ctx, plan.residualScheduler, plan.bindParamPrefix, keyTuple);
|
|
386
|
+
// Keep only the recomputed rows whose backing key equals the affected key.
|
|
387
|
+
// The residual for key K must only contribute K's slice; any other row is
|
|
388
|
+
// spurious and is dropped. This is the soundness net for an emptied group: when
|
|
389
|
+
// no source row matches the key, a *correct* grouped residual returns zero rows,
|
|
390
|
+
// but a constant-pinned multi-column grouped aggregate is mis-collapsed by the
|
|
391
|
+
// optimizer into a *scalar* aggregate that emits one all-NULL `count=0` row over
|
|
392
|
+
// the empty input (a pre-existing optimizer bug, filed separately as
|
|
393
|
+
// `fix/optimizer-constant-group-aggregate-empty-input-spurious-row`). That row's
|
|
394
|
+
// key ≠ K, so it is filtered here and the delete-without-upsert correctly removes
|
|
395
|
+
// the emptied group's backing row.
|
|
396
|
+
const slice = recomputed.filter(row => residualRowMatchesKey(plan, row, keyVals));
|
|
397
|
+
if (slice.length === 0) {
|
|
398
|
+
// Emptied slice: delete-without-upsert removes the stale backing row (the
|
|
399
|
+
// host reports nothing if the key was already absent).
|
|
400
|
+
ops.push({ kind: 'delete-key', key: deleteKey });
|
|
401
|
+
}
|
|
402
|
+
else {
|
|
403
|
+
// The slice shares the affected backing key, so each upsert REPLACES the old
|
|
404
|
+
// backing row — no delete-first — and the host's value-identical skip
|
|
405
|
+
// (vtab/backing-host.ts) suppresses a recompute that changed nothing.
|
|
406
|
+
for (const row of slice)
|
|
407
|
+
ops.push({ kind: 'upsert', row });
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
return ops;
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
413
|
+
* True iff `row`'s backing primary-key columns equal `keyVals` (the affected binding
|
|
414
|
+
* key, in `backingPkDefinition` order), under each column's collation. Used to keep
|
|
415
|
+
* only the residual row(s) belonging to the recomputed key — see
|
|
416
|
+
* {@link applyForwardResidual}.
|
|
417
|
+
*/
|
|
418
|
+
export function residualRowMatchesKey(plan, row, keyVals) {
|
|
419
|
+
for (let i = 0; i < plan.backingPkDefinition.length; i++) {
|
|
420
|
+
const d = plan.backingPkDefinition[i];
|
|
421
|
+
if (compareSqlValuesFast(row[d.index], keyVals[i], d.collationFn) !== 0)
|
|
422
|
+
return false;
|
|
423
|
+
}
|
|
424
|
+
return true;
|
|
425
|
+
}
|
|
426
|
+
/**
|
|
427
|
+
* Dispatch a `'join-residual'` plan on **which source changed**. A write to the driving
|
|
428
|
+
* table `T` (`changedBase === plan.sourceBase`) is the forward case — recompute the one
|
|
429
|
+
* joined row keyed on `T`'s PK, identical to a size-1 `'row'`-binding residual — so it
|
|
430
|
+
* delegates straight to {@link applyForwardResidual} (delete old backing slice → run the
|
|
431
|
+
* `T`-keyed residual → upsert). A write to the lookup table `P` is the reverse case,
|
|
432
|
+
* handled by {@link applyLookupResidual}.
|
|
433
|
+
*/
|
|
434
|
+
export async function applyJoinResidual(ctx, plan, change, changedBase, cache) {
|
|
435
|
+
if (changedBase === plan.sourceBase) {
|
|
436
|
+
return applyForwardResidual(ctx, plan, change, cache);
|
|
437
|
+
}
|
|
438
|
+
return applyLookupResidual(ctx, plan, change, cache);
|
|
439
|
+
}
|
|
440
|
+
/**
|
|
441
|
+
* Maintain a `'join-residual'` MV for a **lookup-side (`P`)** change: refresh the joined
|
|
442
|
+
* rows referencing each affected `P` key. Derive the affected `P` key(s) from the changed
|
|
443
|
+
* row (OLD ∪ NEW, deduped on `P`'s PK), and for each run the in-scope lookup-keyed residual
|
|
444
|
+
* (`… where P.pk = :pk0`, the body's WHERE retained) against live source state — returning
|
|
445
|
+
* every currently in-scope joined row, each carrying its `T.pk` backing key — and **upsert**
|
|
446
|
+
* each.
|
|
447
|
+
*
|
|
448
|
+
* **Upsert-only is sound for a no-WHERE / `T`-only-WHERE body.** For an inner/cross join with
|
|
449
|
+
* enforced RI and a predicate that cannot reference `P`, the *set* of backing rows referencing
|
|
450
|
+
* a given `P` row is `{ T : T.fk = P.pk }`, determined entirely by `T.fk` (a `T` column the
|
|
451
|
+
* `P` write cannot change), and the WHERE — over `T` only — cannot flip on a `P` write. So a
|
|
452
|
+
* `P` change can only re-derive the lookup-projected columns of those existing backing rows
|
|
453
|
+
* (an upsert at the unchanged `T.pk` key), never add or remove one: a `P` insert with no
|
|
454
|
+
* referencing `T` rows yields an empty residual (no-op); a `P` delete is only admissible (RI)
|
|
455
|
+
* when no `T` references it (empty residual); a `P` payload update upserts the affected rows
|
|
456
|
+
* with the new value.
|
|
457
|
+
*
|
|
458
|
+
* **A `P`-referencing WHERE needs the delete-capable pass.** When the body WHERE references
|
|
459
|
+
* `P`, a `P` write can flip a joined row's WHERE truth and so add or remove its backing row —
|
|
460
|
+
* which the in-scope upsert above (it returns *only* in-scope rows) could never delete. The
|
|
461
|
+
* builder then supplies `lookupMembershipResidualScheduler` (the body with the WHERE stripped,
|
|
462
|
+
* keyed on `P`). Per affected `P` key this runs both residuals against the same live state and
|
|
463
|
+
* applies the **keyed diff**: it **deletes** only the membership keys the in-scope recompute no
|
|
464
|
+
* longer produces (rows that left scope — the delete keys come from live `T` via the join, so
|
|
465
|
+
* they match existing backing keys and touch nothing belonging to another `P`; membership and
|
|
466
|
+
* in-scope rows read the same live state, so their key bytes match exactly), and **upserts**
|
|
467
|
+
* every in-scope row. A row leaving scope is deleted (removed); a row entering scope is
|
|
468
|
+
* upserted (added); an unchanged in-scope row's upsert is suppressed by the host's
|
|
469
|
+
* value-identical skip (vtab/backing-host.ts) — ZERO effective changes instead of the former
|
|
470
|
+
* delete+insert refresh churn; a changed in-scope row reports one `update`. The membership
|
|
471
|
+
* residual MUST ignore the WHERE — else a row leaving scope would never be deleted.
|
|
472
|
+
*
|
|
473
|
+
* A `T`-side membership change (insert/delete/FK-move) is the *forward* path's job and fires
|
|
474
|
+
* its own maintenance. Returns the effective {@link BackingRowChange}(s) for the MV-over-MV
|
|
475
|
+
* cascade. This is the cold inline path; a statement-batched caller accumulates via
|
|
476
|
+
* {@link collectLookupResidualKeys} and recomputes at flush ({@link computeLookupResidualOps})
|
|
477
|
+
* — sound for the same last-write-wins-against-live-state reason as
|
|
478
|
+
* {@link applyForwardResidual}.
|
|
479
|
+
*/
|
|
480
|
+
export async function applyLookupResidual(ctx, plan, change, cache) {
|
|
481
|
+
const affected = new Map();
|
|
482
|
+
collectLookupResidualKeys(plan, change, affected);
|
|
483
|
+
const ops = await computeLookupResidualOps(ctx, plan, affected.values());
|
|
484
|
+
if (ops.length === 0)
|
|
485
|
+
return [];
|
|
486
|
+
const { host, connection } = await resolveBackingApplyTarget(ctx, plan, cache);
|
|
487
|
+
return host.applyMaintenance(connection, ops);
|
|
488
|
+
}
|
|
489
|
+
/**
|
|
490
|
+
* Derive one changed lookup-side (`P`) row's affected lookup key(s) (OLD ∪ NEW) and add
|
|
491
|
+
* them to `into`, deduped on `P`'s canonical PK values. The statement-batch counterpart
|
|
492
|
+
* of the derivation inside {@link applyLookupResidual}.
|
|
493
|
+
*/
|
|
494
|
+
export function collectLookupResidualKeys(plan, change, into) {
|
|
495
|
+
const addFrom = (row) => {
|
|
496
|
+
const keyTuple = plan.lookupBindColumns.map(c => row[c]);
|
|
497
|
+
const dedupKey = canonKeyValues(keyTuple);
|
|
498
|
+
if (!into.has(dedupKey))
|
|
499
|
+
into.set(dedupKey, keyTuple);
|
|
500
|
+
};
|
|
501
|
+
if (change.op === 'insert')
|
|
502
|
+
addFrom(change.newRow);
|
|
503
|
+
else if (change.op === 'delete')
|
|
504
|
+
addFrom(change.oldRow);
|
|
505
|
+
else {
|
|
506
|
+
addFrom(change.oldRow);
|
|
507
|
+
addFrom(change.newRow);
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
/**
|
|
511
|
+
* Run the lookup-keyed residual variant once per affected `P` key and build the ops —
|
|
512
|
+
* the delete-capable membership diff when the plan carries
|
|
513
|
+
* `lookupMembershipResidualScheduler`, upsert-only otherwise (see
|
|
514
|
+
* {@link applyLookupResidual} for the soundness argument). Pure op computation; the
|
|
515
|
+
* caller owns connection resolution and the single applyMaintenance call.
|
|
516
|
+
*/
|
|
517
|
+
export async function computeLookupResidualOps(ctx, plan, keys) {
|
|
518
|
+
const ops = [];
|
|
519
|
+
for (const keyTuple of keys) {
|
|
520
|
+
const recomputed = await runResidual(ctx, plan.lookupResidualScheduler, plan.lookupBindParamPrefix, keyTuple);
|
|
521
|
+
// Delete-capable (P-referencing WHERE): keyed diff of the membership residual
|
|
522
|
+
// (WHERE stripped) against the in-scope recompute — delete ONLY the membership
|
|
523
|
+
// keys the recompute no longer produces (rows that left the WHERE scope), not
|
|
524
|
+
// every member. Both residuals read the same live state, so a surviving row's
|
|
525
|
+
// key bytes match exactly (the byte-canonical set lookup is exact). Deletes
|
|
526
|
+
// precede upserts, preserving the prior arm's ordering discipline.
|
|
527
|
+
if (plan.lookupMembershipResidualScheduler) {
|
|
528
|
+
const produced = new Set(recomputed.map(row => canonKeyValues(plan.backingPkDefinition.map(d => row[d.index]))));
|
|
529
|
+
const members = await runResidual(ctx, plan.lookupMembershipResidualScheduler, plan.lookupBindParamPrefix, keyTuple);
|
|
530
|
+
for (const row of members) {
|
|
531
|
+
const keyVals = plan.backingPkDefinition.map(d => row[d.index]);
|
|
532
|
+
if (produced.has(canonKeyValues(keyVals)))
|
|
533
|
+
continue; // still in scope — upserted below
|
|
534
|
+
ops.push({ kind: 'delete-key', key: buildPrimaryKeyFromValues(keyVals, plan.backingPkDefinition) });
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
// Upsert every in-scope row; the host's value-identical skip suppresses the
|
|
538
|
+
// unchanged ones (an in-scope refresh that changed nothing reports nothing).
|
|
539
|
+
for (const row of recomputed)
|
|
540
|
+
ops.push({ kind: 'upsert', row });
|
|
541
|
+
}
|
|
542
|
+
return ops;
|
|
543
|
+
}
|
|
544
|
+
/**
|
|
545
|
+
* Compute a `'prefix-delete'` plan's per-row backing delta and apply it: derive the
|
|
546
|
+
* affected base key(s) from the changed row (OLD ∪ NEW, deduped on the base key), and
|
|
547
|
+
* for each — re-run the base-PK-keyed residual against live source state and apply the
|
|
548
|
+
* **keyed diff against the existing effective fan-out slice** (read via the host's
|
|
549
|
+
* `scanEffective` with the base prefix, pending over committed — the same contiguous
|
|
550
|
+
* range the former wholesale `'delete-by-prefix'` removed): delete ONLY the existing
|
|
551
|
+
* keys the recompute no longer produces, upsert every recomputed row (the host's
|
|
552
|
+
* value-identical skip suppresses the unchanged ones). A base-PK-changing UPDATE
|
|
553
|
+
* recomputes both the OLD base key (slice diffs to all-deletes; the residual returns
|
|
554
|
+
* nothing for the now-absent old PK) and the NEW base key (new fan-out upserted); a
|
|
555
|
+
* DELETE diffs the old slice to all-deletes; an INSERT diffs against an empty slice
|
|
556
|
+
* (all upserts). An emptied/shrunk fan-out keeps the delete-without-upsert exactly —
|
|
557
|
+
* a disappearance is never "skipped". Returns the effective
|
|
558
|
+
* {@link BackingRowChange}(s) the backing layer realized, for the MV-over-MV cascade.
|
|
559
|
+
*
|
|
560
|
+
* Prefix-scan soundness is unchanged from the wholesale arm: the diff's slice read
|
|
561
|
+
* uses the same binary `equalityPrefix` scan `'delete-by-prefix'` used, sound under
|
|
562
|
+
* the build-time collation gate (the backing base-PK prefix inherits the source PK
|
|
563
|
+
* collation, and source-PK uniqueness collapses each collation class to one binary
|
|
564
|
+
* value). The stored slice's prefix bytes always equal the OLD image's (the slice was
|
|
565
|
+
* projected from that very source row), and OLD ∪ NEW both iterate, so a case-only
|
|
566
|
+
* base-PK rewrite still converges: the OLD-prefix pass pairs the slice with the
|
|
567
|
+
* recomputed rows (key pairing is collation-aware — the btree's identity — so a
|
|
568
|
+
* collation-equal key is REPLACED by its upsert, never also deleted) and the byte
|
|
569
|
+
* change surfaces as `update`s that re-key the stored bytes.
|
|
570
|
+
*
|
|
571
|
+
* Structurally the same as {@link applyForwardResidual}, differing only in the
|
|
572
|
+
* **prefix-slice** diff (one base row owns N backing rows sharing the prefix) and the
|
|
573
|
+
* **N-row** residual. This is the cold inline path; a statement-batched caller
|
|
574
|
+
* accumulates the same deduped base keys via {@link collectPrefixDeleteKeys} and diffs
|
|
575
|
+
* each distinct key once at flush ({@link computePrefixDeleteOps}) — sound because the
|
|
576
|
+
* residual and the effective-slice read both see live (reads-own-writes) state, so the
|
|
577
|
+
* flush-time diff is exactly what the last per-row diff would have produced.
|
|
578
|
+
*/
|
|
579
|
+
export async function applyPrefixDelete(ctx, plan, change, cache) {
|
|
580
|
+
const affected = new Map();
|
|
581
|
+
collectPrefixDeleteKeys(plan, change, affected);
|
|
582
|
+
// Resolved up front (unlike the point-op arms): the keyed diff reads the existing
|
|
583
|
+
// effective slice before any op exists. The former wholesale arm always emitted ops,
|
|
584
|
+
// so this resolves no more connections than it did.
|
|
585
|
+
const { host, connection } = await resolveBackingApplyTarget(ctx, plan, cache);
|
|
586
|
+
const ops = await computePrefixDeleteOps(ctx, plan, affected.values(), host, connection);
|
|
587
|
+
if (ops.length === 0)
|
|
588
|
+
return [];
|
|
589
|
+
return host.applyMaintenance(connection, ops);
|
|
590
|
+
}
|
|
591
|
+
/**
|
|
592
|
+
* Derive one changed base row's affected base key(s) (OLD ∪ NEW) and add them to
|
|
593
|
+
* `into`, deduped on the canonical base-PK values. `keyTuple` binds the residual
|
|
594
|
+
* (`pk{i}`); `prefix` is the slice's leading-PK equality key (the base-PK values in
|
|
595
|
+
* backing-PK order — identical here since the base PK leads the backing PK, but kept
|
|
596
|
+
* distinct for clarity). The statement-batch counterpart of the derivation inside
|
|
597
|
+
* {@link applyPrefixDelete}.
|
|
598
|
+
*/
|
|
599
|
+
export function collectPrefixDeleteKeys(plan, change, into) {
|
|
600
|
+
const addFrom = (row) => {
|
|
601
|
+
const keyTuple = plan.bindColumns.map(c => row[c]);
|
|
602
|
+
const dedupKey = canonKeyValues(keyTuple);
|
|
603
|
+
if (into.has(dedupKey))
|
|
604
|
+
return;
|
|
605
|
+
into.set(dedupKey, { keyTuple, prefix: plan.backingPrefixSourceCols.map(sc => row[sc]) });
|
|
606
|
+
};
|
|
607
|
+
if (change.op === 'insert')
|
|
608
|
+
addFrom(change.newRow);
|
|
609
|
+
else if (change.op === 'delete')
|
|
610
|
+
addFrom(change.oldRow);
|
|
611
|
+
else {
|
|
612
|
+
addFrom(change.oldRow);
|
|
613
|
+
addFrom(change.newRow);
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
/**
|
|
617
|
+
* Per affected base key: run the fan-out residual, read the existing effective slice for
|
|
618
|
+
* the base prefix, and build the keyed-diff ops (delete disappeared keys, upsert the
|
|
619
|
+
* recomputed rows). Pure op computation over the supplied host/connection; the caller
|
|
620
|
+
* owns the single applyMaintenance call, so a statement flush batches many base keys'
|
|
621
|
+
* ops into one host call.
|
|
622
|
+
*/
|
|
623
|
+
export async function computePrefixDeleteOps(ctx, plan, keys, host, connection) {
|
|
624
|
+
const ops = [];
|
|
625
|
+
for (const { keyTuple, prefix } of keys) {
|
|
626
|
+
const recomputed = await runResidual(ctx, plan.residualScheduler, plan.bindParamPrefix, keyTuple);
|
|
627
|
+
// The residual for base key K filters T to K, so every row it returns shares K's
|
|
628
|
+
// base-PK prefix; the prefix-match guard is a defensive soundness net (mirrors
|
|
629
|
+
// the aggregate arm's `residualRowMatchesKey`).
|
|
630
|
+
const slice = recomputed.filter(row => residualRowMatchesBasePrefix(plan, row, prefix));
|
|
631
|
+
// Existing effective fan-out rows for this base prefix (pending over committed).
|
|
632
|
+
const existing = [];
|
|
633
|
+
for await (const row of host.scanEffective(connection, { equalityPrefix: prefix })) {
|
|
634
|
+
existing.push(row);
|
|
635
|
+
}
|
|
636
|
+
// Keyed diff. Key pairing is collation-aware over the full backing PK (the btree's
|
|
637
|
+
// identity): a recomputed row whose key is collation-equal to an existing row
|
|
638
|
+
// REPLACES it via the upsert below, so it must not also be deleted. Deletes precede
|
|
639
|
+
// upserts (the wholesale arm's ordering discipline). The delete keys are built from
|
|
640
|
+
// the EXISTING rows' stored values, so the host's collation-aware point lookup
|
|
641
|
+
// always finds them.
|
|
642
|
+
for (const ex of existing) {
|
|
643
|
+
if (slice.some(row => backingPkEqual(plan.backingPkDefinition, row, ex)))
|
|
644
|
+
continue;
|
|
645
|
+
ops.push({
|
|
646
|
+
kind: 'delete-key',
|
|
647
|
+
key: buildPrimaryKeyFromValues(plan.backingPkDefinition.map(d => ex[d.index]), plan.backingPkDefinition),
|
|
648
|
+
});
|
|
649
|
+
}
|
|
650
|
+
for (const row of slice)
|
|
651
|
+
ops.push({ kind: 'upsert', row });
|
|
652
|
+
}
|
|
653
|
+
return ops;
|
|
654
|
+
}
|
|
655
|
+
/**
|
|
656
|
+
* True iff two backing rows agree on every backing-PK column under that column's
|
|
657
|
+
* collation — the btree's key identity. Pairs an existing slice row with the
|
|
658
|
+
* recomputed row that replaces it in {@link applyPrefixDelete}'s keyed diff.
|
|
659
|
+
*/
|
|
660
|
+
export function backingPkEqual(pkDef, a, b) {
|
|
661
|
+
for (const d of pkDef) {
|
|
662
|
+
if (compareSqlValuesFast(a[d.index], b[d.index], d.collationFn) !== 0)
|
|
663
|
+
return false;
|
|
664
|
+
}
|
|
665
|
+
return true;
|
|
666
|
+
}
|
|
667
|
+
/**
|
|
668
|
+
* True iff `row`'s **leading** (base-prefix) backing-PK columns equal `prefixVals` (the
|
|
669
|
+
* affected base key, in backing-PK order), under each column's collation. Keeps only the
|
|
670
|
+
* residual fan-out row(s) belonging to the recomputed base key — see
|
|
671
|
+
* {@link applyPrefixDelete}.
|
|
672
|
+
*/
|
|
673
|
+
export function residualRowMatchesBasePrefix(plan, row, prefixVals) {
|
|
674
|
+
for (let i = 0; i < plan.basePrefixLength; i++) {
|
|
675
|
+
const d = plan.backingPkDefinition[i];
|
|
676
|
+
if (compareSqlValuesFast(row[d.index], prefixVals[i], d.collationFn) !== 0)
|
|
677
|
+
return false;
|
|
678
|
+
}
|
|
679
|
+
return true;
|
|
680
|
+
}
|
|
681
|
+
/**
|
|
682
|
+
* Accumulate one source change's affected binding key(s) for a residual-arm plan into
|
|
683
|
+
* the per-statement {@link ResidualKeyBatch}, deduped across the whole statement —
|
|
684
|
+
* the deferred-accumulate counterpart of the cold per-row appliers above. Which
|
|
685
|
+
* variant map receives the keys follows the plan kind; a `'join-residual'` change
|
|
686
|
+
* routes on **which source changed** (forward for the driving `T`, lookup for `P`),
|
|
687
|
+
* exactly as {@link applyJoinResidual} dispatches. `planKey` is the MV key
|
|
688
|
+
* (lowercased `schema.name`) the manager indexes the plan under.
|
|
689
|
+
*/
|
|
690
|
+
export function accumulateResidualKeys(plan, change, changedBase, batch, planKey) {
|
|
691
|
+
let entry = batch.get(planKey);
|
|
692
|
+
if (!entry) {
|
|
693
|
+
entry = { forward: new Map(), lookup: new Map(), prefix: new Map() };
|
|
694
|
+
batch.set(planKey, entry);
|
|
695
|
+
}
|
|
696
|
+
switch (plan.kind) {
|
|
697
|
+
case 'residual-recompute':
|
|
698
|
+
// Residual keys FIRST, always — they are the delta path's per-group fallback
|
|
699
|
+
// (retraction-unsafe groups, poisoned accumulations), so the delta map is
|
|
700
|
+
// strictly an optimization layered on top, never the only record.
|
|
701
|
+
collectForwardResidualKeys(plan, change, entry.forward);
|
|
702
|
+
if (plan.delta && !entry.deltaPoisoned) {
|
|
703
|
+
accumulateDeltaAggregates(plan, change, entry);
|
|
704
|
+
}
|
|
705
|
+
break;
|
|
706
|
+
case 'prefix-delete':
|
|
707
|
+
collectPrefixDeleteKeys(plan, change, entry.prefix);
|
|
708
|
+
break;
|
|
709
|
+
case 'join-residual': {
|
|
710
|
+
if (changedBase === plan.sourceBase)
|
|
711
|
+
collectForwardResidualKeys(plan, change, entry.forward);
|
|
712
|
+
else
|
|
713
|
+
collectLookupResidualKeys(plan, change, entry.lookup);
|
|
714
|
+
break;
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
/**
|
|
719
|
+
* Compute the flush-time ops for one residual-arm MV's accumulated statement keys: run
|
|
720
|
+
* the appropriate residual variant once per distinct key against live post-statement
|
|
721
|
+
* state and concatenate the keyed-diff ops. Distinct keys touch disjoint backing slices
|
|
722
|
+
* — except a `'join-residual'` statement that accumulated both forward and lookup keys,
|
|
723
|
+
* where an overlapping backing row is recomputed twice from the SAME live state, so the
|
|
724
|
+
* duplicate upsert is value-identical and the host suppresses it. The caller owns the
|
|
725
|
+
* single {@link BackingHost.applyMaintenance} call over the combined array — one host
|
|
726
|
+
* round-trip per (MV, flush round) instead of one per source row.
|
|
727
|
+
*/
|
|
728
|
+
export async function computeResidualBatchOps(ctx, plan, entry, host, connection) {
|
|
729
|
+
if (plan.kind === 'prefix-delete') {
|
|
730
|
+
return computePrefixDeleteOps(ctx, plan, entry.prefix.values(), host, connection);
|
|
731
|
+
}
|
|
732
|
+
const ops = await computeForwardResidualOps(ctx, plan, entry.forward.values());
|
|
733
|
+
if (plan.kind === 'join-residual' && entry.lookup.size > 0) {
|
|
734
|
+
ops.push(...await computeLookupResidualOps(ctx, plan, entry.lookup.values()));
|
|
735
|
+
}
|
|
736
|
+
return ops;
|
|
737
|
+
}
|
|
738
|
+
/**
|
|
739
|
+
* Fold one source change's per-column aggregate contributions into the statement's
|
|
740
|
+
* delta accumulation ({@link ResidualKeyBatchEntry.delta}) — the delta-aggregate
|
|
741
|
+
* counterpart of {@link collectForwardResidualKeys}, called right after it (the
|
|
742
|
+
* residual keys remain the fallback record). Per contributing row image:
|
|
743
|
+
* `step(identity, row[arg])` (zero-arg → `step(identity)`) is the row's contribution;
|
|
744
|
+
* an insert `merge`s it in, a delete `merge`s its `negate`, an update retracts the OLD
|
|
745
|
+
* image into its group and inserts the NEW into its (possibly different) group. A row
|
|
746
|
+
* whose body-WHERE predicate is not unambiguously TRUE contributes nothing — but the
|
|
747
|
+
* raw column value (including NULL) IS fed to `step`, never pre-filtered: NULL-handling
|
|
748
|
+
* is the aggregate's own (law 2), and the row still counts toward the zero-arg
|
|
749
|
+
* multiplicity witness.
|
|
750
|
+
*/
|
|
751
|
+
export function accumulateDeltaAggregates(plan, change, entry) {
|
|
752
|
+
const d = plan.delta;
|
|
753
|
+
if (!d)
|
|
754
|
+
return;
|
|
755
|
+
const delta = entry.delta ?? (entry.delta = new Map());
|
|
756
|
+
const contribute = (row, retract) => {
|
|
757
|
+
if (d.predicate && d.predicate.evaluate(row) !== true)
|
|
758
|
+
return; // out of body scope
|
|
759
|
+
const keyVals = plan.backingPkSourceCols.map(sc => row[sc]);
|
|
760
|
+
const dedupKey = canonKeyValues(keyVals);
|
|
761
|
+
let g = delta.get(dedupKey);
|
|
762
|
+
if (!g) {
|
|
763
|
+
g = {
|
|
764
|
+
keyVals,
|
|
765
|
+
deleteKey: buildPrimaryKeyFromValues(keyVals, plan.backingPkDefinition),
|
|
766
|
+
accs: d.aggColumns.map(c => cloneInitialValue(c.schema.initialValue)),
|
|
767
|
+
retracted: false,
|
|
768
|
+
};
|
|
769
|
+
delta.set(dedupKey, g);
|
|
770
|
+
}
|
|
771
|
+
if (retract)
|
|
772
|
+
g.retracted = true;
|
|
773
|
+
for (let i = 0; i < d.aggColumns.length; i++) {
|
|
774
|
+
const c = d.aggColumns[i];
|
|
775
|
+
// A tighten-only column (min/max — merge, no negate) cannot retract arithmetically.
|
|
776
|
+
// `g.retracted` was set above, so a retracted group with a tighten column re-derives
|
|
777
|
+
// wholesale from the residual at flush (descriptor.hasTighten) and this accumulator is
|
|
778
|
+
// discarded — so skip the retraction contribution entirely (there is no negate to
|
|
779
|
+
// apply). Its INSERT contributions still fold via merge on the non-retract path below.
|
|
780
|
+
if (retract && c.deltaClass === 'tighten')
|
|
781
|
+
continue;
|
|
782
|
+
let contrib = c.argSourceCol === undefined
|
|
783
|
+
? c.schema.stepFunction(cloneInitialValue(c.schema.initialValue))
|
|
784
|
+
: c.schema.stepFunction(cloneInitialValue(c.schema.initialValue), row[c.argSourceCol]);
|
|
785
|
+
if (retract)
|
|
786
|
+
contrib = c.algebra.negate(contrib);
|
|
787
|
+
g.accs[i] = c.algebra.merge(g.accs[i], contrib);
|
|
788
|
+
}
|
|
789
|
+
};
|
|
790
|
+
if (change.op === 'insert')
|
|
791
|
+
contribute(change.newRow, false);
|
|
792
|
+
else if (change.op === 'delete')
|
|
793
|
+
contribute(change.oldRow, true);
|
|
794
|
+
else {
|
|
795
|
+
contribute(change.oldRow, true);
|
|
796
|
+
contribute(change.newRow, false);
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
/**
|
|
800
|
+
* Flush-time op computation for a delta-aggregate MV's accumulated statement deltas —
|
|
801
|
+
* the arithmetic read-modify-write that replaces the per-group residual re-execution.
|
|
802
|
+
* Per affected group:
|
|
803
|
+
* 1. read the group's current EFFECTIVE backing row by its full PK (the host's
|
|
804
|
+
* `scanEffective` equality-prefix point read — pending over committed, so a group
|
|
805
|
+
* written by an earlier statement of this transaction folds correctly);
|
|
806
|
+
* 2. per aggregate column: base = stored ? `decode(stored[col])` : a fresh identity
|
|
807
|
+
* accumulator; finalized = `finalize(merge(base, delta))`;
|
|
808
|
+
* 3. the multiplicity witness finalizing to 0 ⇔ the group emptied → `delete-key`
|
|
809
|
+
* (skipped when no row was stored); otherwise upsert the rebuilt row (group-key
|
|
810
|
+
* values + finalized aggregates) — the host's value-identical skip suppresses a
|
|
811
|
+
* net-identity delta (MV-016).
|
|
812
|
+
*
|
|
813
|
+
* **Retraction fallback.** A group that accumulated a retraction re-derives from its
|
|
814
|
+
* residual key (always accumulated alongside, same canonical map key) instead of the
|
|
815
|
+
* arithmetic, in two cases:
|
|
816
|
+
* - the descriptor has a **tighten** column (min/max — merge, no negate): a retraction
|
|
817
|
+
* cannot be undone by merge, so the whole group re-derives from live source state
|
|
818
|
+
* **whether or not a row is stored** (an intra-statement delete of the extreme poisons
|
|
819
|
+
* even a from-identity net-fold). The residual recomputes every column of the row
|
|
820
|
+
* (count/sum included), so a mixed group+tighten row is maintained by ONE path — no
|
|
821
|
+
* double-maintenance;
|
|
822
|
+
* - otherwise the descriptor is not retraction-safe (an abelian column whose decode is
|
|
823
|
+
* only an insert-observational witness — a nullable-argument sum) AND a stored row
|
|
824
|
+
* exists: the stored value cannot prove the true contribution count survives the
|
|
825
|
+
* retraction, so decoding it is unsound. A group with no stored row needs no fallback
|
|
826
|
+
* here — a pure abelian net-fold from identity is exact.
|
|
827
|
+
*
|
|
828
|
+
* Zero source reads, no residual execution on the arithmetic path — this is why the
|
|
829
|
+
* delta path also BYPASSES the per-statement degrade-to-rebuild crossover (it is
|
|
830
|
+
* already O(affected groups)).
|
|
831
|
+
*/
|
|
832
|
+
export async function computeDeltaAggregateOps(ctx, plan, entry, host, connection) {
|
|
833
|
+
const d = plan.delta;
|
|
834
|
+
if (!d || !entry.delta)
|
|
835
|
+
return [];
|
|
836
|
+
const ops = [];
|
|
837
|
+
const residualFallbackKeys = [];
|
|
838
|
+
for (const [dedupKey, g] of entry.delta) {
|
|
839
|
+
// Effective point read: the full-PK equality prefix selects at most one row
|
|
840
|
+
// (BINARY collations on every PK column are a descriptor gate, so the binary
|
|
841
|
+
// prefix compare in the host's scan is exact).
|
|
842
|
+
let stored;
|
|
843
|
+
for await (const row of host.scanEffective(connection, { equalityPrefix: [...g.keyVals] })) {
|
|
844
|
+
stored = row;
|
|
845
|
+
break;
|
|
846
|
+
}
|
|
847
|
+
// Residual fallback for a group whose arithmetic cannot be trusted under retraction:
|
|
848
|
+
// - a **tighten** column (min/max) can never retract arithmetically — a retracted
|
|
849
|
+
// group re-derives from live state whether or not a row is stored (an intra-statement
|
|
850
|
+
// delete of the extreme cannot be undone by merge, even from a fresh identity);
|
|
851
|
+
// - otherwise a not-retraction-safe abelian column (a sum whose decode forgets the true
|
|
852
|
+
// contribution count) only needs the residual when a stored row must be decoded — its
|
|
853
|
+
// no-stored net-fold stays exact, so that case keeps the pure arithmetic path.
|
|
854
|
+
// NOTE: the tighten fallback is conservative — ANY retraction rescans the group, even a
|
|
855
|
+
// delete of a provably-non-extreme value. Correct, not minimal. If min/max MVs ever show
|
|
856
|
+
// this rescan as hot, a secondary-index "is this the current extreme?" probe could keep
|
|
857
|
+
// non-extreme deletes on the arithmetic path. Not built now (see docs/mv-maintenance.md
|
|
858
|
+
// § Tighten-only columns).
|
|
859
|
+
if (g.retracted && (d.hasTighten || (stored && !d.retractionSafe))) {
|
|
860
|
+
const fk = entry.forward.get(dedupKey);
|
|
861
|
+
if (!fk) {
|
|
862
|
+
// Impossible: accumulateResidualKeys collects the forward key for every
|
|
863
|
+
// change before the delta contribution, over the same canonical key.
|
|
864
|
+
throw new QuereusError(`Internal error: delta-aggregate group of materialized view '${plan.mv.name}' has no forward residual key`, StatusCode.INTERNAL);
|
|
865
|
+
}
|
|
866
|
+
residualFallbackKeys.push(fk);
|
|
867
|
+
continue;
|
|
868
|
+
}
|
|
869
|
+
const finals = new Array(d.aggColumns.length);
|
|
870
|
+
for (let i = 0; i < d.aggColumns.length; i++) {
|
|
871
|
+
const c = d.aggColumns[i];
|
|
872
|
+
const base = stored
|
|
873
|
+
? c.algebra.decode(stored[c.backingCol])
|
|
874
|
+
: cloneInitialValue(c.schema.initialValue);
|
|
875
|
+
finals[i] = c.schema.finalizeFunction(c.algebra.merge(base, g.accs[i]));
|
|
876
|
+
}
|
|
877
|
+
const mult = finals[d.multiplicityIndex];
|
|
878
|
+
if (mult === 0 || mult === 0n) {
|
|
879
|
+
// Group emptied. The delete is emitted only when a row is stored (a group
|
|
880
|
+
// created and emptied within one statement writes nothing).
|
|
881
|
+
if (stored)
|
|
882
|
+
ops.push({ kind: 'delete-key', key: g.deleteKey });
|
|
883
|
+
continue;
|
|
884
|
+
}
|
|
885
|
+
const row = new Array(d.backingColumnCount).fill(null);
|
|
886
|
+
for (const gc of d.groupColumns)
|
|
887
|
+
row[gc.backingCol] = g.keyVals[gc.pkPos];
|
|
888
|
+
for (let i = 0; i < d.aggColumns.length; i++)
|
|
889
|
+
row[d.aggColumns[i].backingCol] = finals[i];
|
|
890
|
+
// Decomposition-maintained columns (the avg class): derived from the finalized
|
|
891
|
+
// partials, never accumulated. `combine` reproduces the aggregate's own finalize —
|
|
892
|
+
// incl. the empty-group / divide-by-zero case (avg → count 0/NULL ⇒ NULL). The group
|
|
893
|
+
// is non-empty here (multiplicity > 0), so a fully-emptied group is deleted above
|
|
894
|
+
// before combine could divide by zero; a non-empty all-NULL group finalizes count(x)
|
|
895
|
+
// = 0 and combine yields NULL, matching native avg.
|
|
896
|
+
// NOTE: byte-exactness vs a live re-fold holds while a group's integer sum stays
|
|
897
|
+
// ≤ 2^53. `avg`'s live finalize accumulates its own sum as a float, whereas this
|
|
898
|
+
// recombine reads the exact (bigint-capable) stored `sum` partial; the two round
|
|
899
|
+
// differently only once a group sum exceeds the double safe-integer range. If that
|
|
900
|
+
// regime ever becomes reachable, avg's finalize would need bigint accumulation (a
|
|
901
|
+
// change in aggregate.ts), not a change here.
|
|
902
|
+
for (const dc of d.decomposeColumns) {
|
|
903
|
+
row[dc.backingCol] = dc.combine(dc.partialIndices.map(pi => finals[pi]));
|
|
904
|
+
}
|
|
905
|
+
ops.push({ kind: 'upsert', row });
|
|
906
|
+
}
|
|
907
|
+
if (residualFallbackKeys.length > 0) {
|
|
908
|
+
ops.push(...await computeForwardResidualOps(ctx, plan, residualFallbackKeys));
|
|
909
|
+
}
|
|
910
|
+
return ops;
|
|
911
|
+
}
|
|
912
|
+
/**
|
|
913
|
+
* Invalidate every accumulated delta in the per-statement batch — called by the DML
|
|
914
|
+
* executor when an OR FAIL per-row savepoint ROLLS BACK: the savepoint undoes the
|
|
915
|
+
* failing row's source (and backing) writes, but the JS-side accumulation cannot be
|
|
916
|
+
* unwound, so the folded deltas may carry the reverted row's contribution. The residual
|
|
917
|
+
* keys are unaffected (a reverted key's recompute reads surviving live state and is
|
|
918
|
+
* value-identical → suppressed), so poisoning simply drops the fast path: the flush in
|
|
919
|
+
* the executor's catch routes those entries through the plain residual. One-way for the
|
|
920
|
+
* statement — `deltaPoisoned` also stops later (cascade-driven) delta re-accumulation
|
|
921
|
+
* into the same entry from mixing with an already-flushed-around state.
|
|
922
|
+
*/
|
|
923
|
+
export function poisonResidualDeltaAccumulations(batch) {
|
|
924
|
+
for (const entry of batch.values()) {
|
|
925
|
+
entry.delta = undefined;
|
|
926
|
+
entry.deltaPoisoned = true;
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
//# sourceMappingURL=database-materialized-views-apply.js.map
|