@quereus/quereus 3.3.0 → 4.1.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 +7 -0
- package/dist/src/common/datatype.d.ts +12 -0
- package/dist/src/common/datatype.d.ts.map +1 -1
- package/dist/src/common/datatype.js.map +1 -1
- package/dist/src/common/types.d.ts +24 -0
- package/dist/src/common/types.d.ts.map +1 -1
- package/dist/src/common/types.js.map +1 -1
- package/dist/src/core/database-assertions.d.ts +37 -9
- package/dist/src/core/database-assertions.d.ts.map +1 -1
- package/dist/src/core/database-assertions.js +62 -110
- package/dist/src/core/database-assertions.js.map +1 -1
- package/dist/src/core/database-events.d.ts +163 -0
- package/dist/src/core/database-events.d.ts.map +1 -1
- package/dist/src/core/database-events.js +235 -21
- package/dist/src/core/database-events.js.map +1 -1
- package/dist/src/core/database-external-changes.d.ts +28 -0
- package/dist/src/core/database-external-changes.d.ts.map +1 -0
- package/dist/src/core/database-external-changes.js +242 -0
- package/dist/src/core/database-external-changes.js.map +1 -0
- package/dist/src/core/database-internal.d.ts +50 -1
- package/dist/src/core/database-internal.d.ts.map +1 -1
- package/dist/src/core/database-materialized-views.d.ts +1253 -0
- package/dist/src/core/database-materialized-views.d.ts.map +1 -0
- package/dist/src/core/database-materialized-views.js +3064 -0
- package/dist/src/core/database-materialized-views.js.map +1 -0
- package/dist/src/core/database-options.d.ts +4 -0
- package/dist/src/core/database-options.d.ts.map +1 -1
- package/dist/src/core/database-options.js +10 -0
- package/dist/src/core/database-options.js.map +1 -1
- package/dist/src/core/database-transaction.d.ts +19 -3
- package/dist/src/core/database-transaction.d.ts.map +1 -1
- package/dist/src/core/database-transaction.js +30 -3
- package/dist/src/core/database-transaction.js.map +1 -1
- package/dist/src/core/database-watchers.d.ts +19 -0
- package/dist/src/core/database-watchers.d.ts.map +1 -1
- package/dist/src/core/database-watchers.js +63 -3
- package/dist/src/core/database-watchers.js.map +1 -1
- package/dist/src/core/database.d.ts +204 -11
- package/dist/src/core/database.d.ts.map +1 -1
- package/dist/src/core/database.js +493 -29
- package/dist/src/core/database.js.map +1 -1
- package/dist/src/core/derived-row-validator.d.ts +137 -0
- package/dist/src/core/derived-row-validator.d.ts.map +1 -0
- package/dist/src/core/derived-row-validator.js +314 -0
- package/dist/src/core/derived-row-validator.js.map +1 -0
- package/dist/src/core/statement.d.ts.map +1 -1
- package/dist/src/core/statement.js +30 -9
- package/dist/src/core/statement.js.map +1 -1
- package/dist/src/emit/ast-stringify.d.ts +135 -1
- package/dist/src/emit/ast-stringify.d.ts.map +1 -1
- package/dist/src/emit/ast-stringify.js +793 -118
- 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 +11 -10
- package/dist/src/func/builtins/aggregate.js.map +1 -1
- package/dist/src/func/builtins/builtin-window-functions.d.ts.map +1 -1
- package/dist/src/func/builtins/builtin-window-functions.js +32 -0
- package/dist/src/func/builtins/builtin-window-functions.js.map +1 -1
- package/dist/src/func/builtins/explain.d.ts +3 -0
- package/dist/src/func/builtins/explain.d.ts.map +1 -1
- package/dist/src/func/builtins/explain.js +229 -0
- package/dist/src/func/builtins/explain.js.map +1 -1
- package/dist/src/func/builtins/index.d.ts.map +1 -1
- package/dist/src/func/builtins/index.js +10 -2
- package/dist/src/func/builtins/index.js.map +1 -1
- package/dist/src/func/builtins/json.d.ts.map +1 -1
- package/dist/src/func/builtins/json.js +3 -2
- package/dist/src/func/builtins/json.js.map +1 -1
- package/dist/src/func/builtins/mutation.d.ts +2 -0
- package/dist/src/func/builtins/mutation.d.ts.map +1 -0
- package/dist/src/func/builtins/mutation.js +53 -0
- package/dist/src/func/builtins/mutation.js.map +1 -0
- package/dist/src/func/builtins/schema.d.ts +2 -0
- package/dist/src/func/builtins/schema.d.ts.map +1 -1
- package/dist/src/func/builtins/schema.js +716 -27
- package/dist/src/func/builtins/schema.js.map +1 -1
- package/dist/src/func/builtins/string.js +1 -1
- package/dist/src/func/builtins/string.js.map +1 -1
- package/dist/src/func/registration.d.ts +13 -0
- package/dist/src/func/registration.d.ts.map +1 -1
- package/dist/src/func/registration.js +5 -0
- package/dist/src/func/registration.js.map +1 -1
- package/dist/src/index.d.ts +25 -6
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +27 -3
- package/dist/src/index.js.map +1 -1
- package/dist/src/parser/ast.d.ts +353 -21
- package/dist/src/parser/ast.d.ts.map +1 -1
- package/dist/src/parser/index.d.ts +14 -1
- package/dist/src/parser/index.d.ts.map +1 -1
- package/dist/src/parser/index.js +19 -0
- package/dist/src/parser/index.js.map +1 -1
- package/dist/src/parser/lexer.d.ts +9 -0
- package/dist/src/parser/lexer.d.ts.map +1 -1
- package/dist/src/parser/lexer.js +9 -0
- package/dist/src/parser/lexer.js.map +1 -1
- package/dist/src/parser/parser.d.ts +276 -7
- package/dist/src/parser/parser.d.ts.map +1 -1
- package/dist/src/parser/parser.js +1387 -469
- package/dist/src/parser/parser.js.map +1 -1
- package/dist/src/parser/visitor.d.ts.map +1 -1
- package/dist/src/parser/visitor.js +12 -8
- package/dist/src/parser/visitor.js.map +1 -1
- package/dist/src/planner/analysis/assertion-classifier.d.ts.map +1 -1
- package/dist/src/planner/analysis/assertion-classifier.js +4 -0
- package/dist/src/planner/analysis/assertion-classifier.js.map +1 -1
- package/dist/src/planner/analysis/assertion-hoist-cache.d.ts.map +1 -1
- package/dist/src/planner/analysis/assertion-hoist-cache.js +8 -4
- package/dist/src/planner/analysis/assertion-hoist-cache.js.map +1 -1
- package/dist/src/planner/analysis/authored-inverse.d.ts +22 -0
- package/dist/src/planner/analysis/authored-inverse.d.ts.map +1 -0
- package/dist/src/planner/analysis/authored-inverse.js +267 -0
- package/dist/src/planner/analysis/authored-inverse.js.map +1 -0
- package/dist/src/planner/analysis/change-scope.d.ts +34 -4
- package/dist/src/planner/analysis/change-scope.d.ts.map +1 -1
- package/dist/src/planner/analysis/change-scope.js +108 -7
- package/dist/src/planner/analysis/change-scope.js.map +1 -1
- package/dist/src/planner/analysis/check-extraction.d.ts +36 -2
- package/dist/src/planner/analysis/check-extraction.d.ts.map +1 -1
- package/dist/src/planner/analysis/check-extraction.js +174 -46
- package/dist/src/planner/analysis/check-extraction.js.map +1 -1
- package/dist/src/planner/analysis/coarsened-key.d.ts +109 -0
- package/dist/src/planner/analysis/coarsened-key.d.ts.map +1 -0
- package/dist/src/planner/analysis/coarsened-key.js +228 -0
- package/dist/src/planner/analysis/coarsened-key.js.map +1 -0
- package/dist/src/planner/analysis/comparison-collation.d.ts +216 -0
- package/dist/src/planner/analysis/comparison-collation.d.ts.map +1 -0
- package/dist/src/planner/analysis/comparison-collation.js +341 -0
- package/dist/src/planner/analysis/comparison-collation.js.map +1 -0
- package/dist/src/planner/analysis/constraint-extractor.d.ts +3 -1
- package/dist/src/planner/analysis/constraint-extractor.d.ts.map +1 -1
- package/dist/src/planner/analysis/constraint-extractor.js +192 -9
- package/dist/src/planner/analysis/constraint-extractor.js.map +1 -1
- package/dist/src/planner/analysis/coverage-prover.d.ts +321 -0
- package/dist/src/planner/analysis/coverage-prover.d.ts.map +1 -0
- package/dist/src/planner/analysis/coverage-prover.js +1038 -0
- package/dist/src/planner/analysis/coverage-prover.js.map +1 -0
- package/dist/src/planner/analysis/key-filter.d.ts +22 -0
- package/dist/src/planner/analysis/key-filter.d.ts.map +1 -0
- package/dist/src/planner/analysis/key-filter.js +105 -0
- package/dist/src/planner/analysis/key-filter.js.map +1 -0
- package/dist/src/planner/analysis/partial-unique-extraction.d.ts +36 -1
- package/dist/src/planner/analysis/partial-unique-extraction.d.ts.map +1 -1
- package/dist/src/planner/analysis/partial-unique-extraction.js +148 -22
- package/dist/src/planner/analysis/partial-unique-extraction.js.map +1 -1
- package/dist/src/planner/analysis/predicate-normalizer.d.ts.map +1 -1
- package/dist/src/planner/analysis/predicate-normalizer.js +30 -1
- package/dist/src/planner/analysis/predicate-normalizer.js.map +1 -1
- package/dist/src/planner/analysis/predicate-shape.d.ts +36 -1
- package/dist/src/planner/analysis/predicate-shape.d.ts.map +1 -1
- package/dist/src/planner/analysis/predicate-shape.js +51 -13
- package/dist/src/planner/analysis/predicate-shape.js.map +1 -1
- package/dist/src/planner/analysis/query-rewrite-matcher.d.ts +314 -0
- package/dist/src/planner/analysis/query-rewrite-matcher.d.ts.map +1 -0
- package/dist/src/planner/analysis/query-rewrite-matcher.js +1081 -0
- package/dist/src/planner/analysis/query-rewrite-matcher.js.map +1 -0
- package/dist/src/planner/analysis/scalar-invertibility.d.ts +92 -0
- package/dist/src/planner/analysis/scalar-invertibility.d.ts.map +1 -0
- package/dist/src/planner/analysis/scalar-invertibility.js +129 -0
- package/dist/src/planner/analysis/scalar-invertibility.js.map +1 -0
- package/dist/src/planner/analysis/update-lineage.d.ts +196 -0
- package/dist/src/planner/analysis/update-lineage.d.ts.map +1 -0
- package/dist/src/planner/analysis/update-lineage.js +322 -0
- package/dist/src/planner/analysis/update-lineage.js.map +1 -0
- package/dist/src/planner/analysis/view-complement.d.ts +42 -0
- package/dist/src/planner/analysis/view-complement.d.ts.map +1 -0
- package/dist/src/planner/analysis/view-complement.js +54 -0
- package/dist/src/planner/analysis/view-complement.js.map +1 -0
- package/dist/src/planner/building/alter-table.d.ts +1 -1
- package/dist/src/planner/building/alter-table.d.ts.map +1 -1
- package/dist/src/planner/building/alter-table.js +211 -2
- package/dist/src/planner/building/alter-table.js.map +1 -1
- package/dist/src/planner/building/block.d.ts.map +1 -1
- package/dist/src/planner/building/block.js +18 -1
- package/dist/src/planner/building/block.js.map +1 -1
- package/dist/src/planner/building/constraint-builder.d.ts +33 -5
- package/dist/src/planner/building/constraint-builder.d.ts.map +1 -1
- package/dist/src/planner/building/constraint-builder.js +63 -28
- package/dist/src/planner/building/constraint-builder.js.map +1 -1
- package/dist/src/planner/building/create-view.d.ts +9 -0
- package/dist/src/planner/building/create-view.d.ts.map +1 -1
- package/dist/src/planner/building/create-view.js +41 -12
- package/dist/src/planner/building/create-view.js.map +1 -1
- package/dist/src/planner/building/ddl.d.ts.map +1 -1
- package/dist/src/planner/building/ddl.js +94 -0
- package/dist/src/planner/building/ddl.js.map +1 -1
- package/dist/src/planner/building/declare-schema.d.ts +1 -0
- package/dist/src/planner/building/declare-schema.d.ts.map +1 -1
- package/dist/src/planner/building/declare-schema.js +4 -1
- package/dist/src/planner/building/declare-schema.js.map +1 -1
- package/dist/src/planner/building/default-scope.d.ts +26 -0
- package/dist/src/planner/building/default-scope.d.ts.map +1 -0
- package/dist/src/planner/building/default-scope.js +41 -0
- package/dist/src/planner/building/default-scope.js.map +1 -0
- package/dist/src/planner/building/delete.d.ts +19 -1
- package/dist/src/planner/building/delete.d.ts.map +1 -1
- package/dist/src/planner/building/delete.js +109 -30
- package/dist/src/planner/building/delete.js.map +1 -1
- package/dist/src/planner/building/dml-target.d.ts +118 -0
- package/dist/src/planner/building/dml-target.d.ts.map +1 -0
- package/dist/src/planner/building/dml-target.js +282 -0
- package/dist/src/planner/building/dml-target.js.map +1 -0
- package/dist/src/planner/building/drop-index.d.ts.map +1 -1
- package/dist/src/planner/building/drop-index.js +4 -1
- package/dist/src/planner/building/drop-index.js.map +1 -1
- package/dist/src/planner/building/drop-view.d.ts.map +1 -1
- package/dist/src/planner/building/drop-view.js +4 -2
- package/dist/src/planner/building/drop-view.js.map +1 -1
- package/dist/src/planner/building/expression.d.ts.map +1 -1
- package/dist/src/planner/building/expression.js +60 -21
- package/dist/src/planner/building/expression.js.map +1 -1
- package/dist/src/planner/building/foreign-key-builder.d.ts +30 -0
- package/dist/src/planner/building/foreign-key-builder.d.ts.map +1 -1
- package/dist/src/planner/building/foreign-key-builder.js +160 -129
- package/dist/src/planner/building/foreign-key-builder.js.map +1 -1
- package/dist/src/planner/building/insert.d.ts +45 -2
- package/dist/src/planner/building/insert.d.ts.map +1 -1
- package/dist/src/planner/building/insert.js +257 -88
- package/dist/src/planner/building/insert.js.map +1 -1
- package/dist/src/planner/building/lens-auxiliary-access.d.ts +22 -0
- package/dist/src/planner/building/lens-auxiliary-access.d.ts.map +1 -0
- package/dist/src/planner/building/lens-auxiliary-access.js +132 -0
- package/dist/src/planner/building/lens-auxiliary-access.js.map +1 -0
- package/dist/src/planner/building/materialized-view.d.ts +16 -0
- package/dist/src/planner/building/materialized-view.d.ts.map +1 -0
- package/dist/src/planner/building/materialized-view.js +57 -0
- package/dist/src/planner/building/materialized-view.js.map +1 -0
- package/dist/src/planner/building/returning-star.d.ts +32 -0
- package/dist/src/planner/building/returning-star.d.ts.map +1 -0
- package/dist/src/planner/building/returning-star.js +45 -0
- package/dist/src/planner/building/returning-star.js.map +1 -0
- package/dist/src/planner/building/select-aggregates.d.ts.map +1 -1
- package/dist/src/planner/building/select-aggregates.js +47 -0
- package/dist/src/planner/building/select-aggregates.js.map +1 -1
- package/dist/src/planner/building/select-compound.d.ts.map +1 -1
- package/dist/src/planner/building/select-compound.js +84 -11
- package/dist/src/planner/building/select-compound.js.map +1 -1
- package/dist/src/planner/building/select-context.d.ts +10 -2
- package/dist/src/planner/building/select-context.d.ts.map +1 -1
- package/dist/src/planner/building/select-context.js +7 -1
- package/dist/src/planner/building/select-context.js.map +1 -1
- package/dist/src/planner/building/select-modifiers.js +6 -0
- package/dist/src/planner/building/select-modifiers.js.map +1 -1
- package/dist/src/planner/building/select-ordinal.d.ts +18 -0
- package/dist/src/planner/building/select-ordinal.d.ts.map +1 -1
- package/dist/src/planner/building/select-ordinal.js +30 -0
- package/dist/src/planner/building/select-ordinal.js.map +1 -1
- package/dist/src/planner/building/select-projections.d.ts +8 -2
- package/dist/src/planner/building/select-projections.d.ts.map +1 -1
- package/dist/src/planner/building/select-projections.js +26 -4
- package/dist/src/planner/building/select-projections.js.map +1 -1
- package/dist/src/planner/building/select-window.d.ts.map +1 -1
- package/dist/src/planner/building/select-window.js +8 -5
- package/dist/src/planner/building/select-window.js.map +1 -1
- package/dist/src/planner/building/select.d.ts.map +1 -1
- package/dist/src/planner/building/select.js +164 -59
- package/dist/src/planner/building/select.js.map +1 -1
- package/dist/src/planner/building/set-object-tags.d.ts +7 -0
- package/dist/src/planner/building/set-object-tags.d.ts.map +1 -0
- package/dist/src/planner/building/set-object-tags.js +38 -0
- package/dist/src/planner/building/set-object-tags.js.map +1 -0
- package/dist/src/planner/building/tag-diagnostics.d.ts +27 -0
- package/dist/src/planner/building/tag-diagnostics.d.ts.map +1 -0
- package/dist/src/planner/building/tag-diagnostics.js +37 -0
- package/dist/src/planner/building/tag-diagnostics.js.map +1 -0
- package/dist/src/planner/building/update.d.ts +18 -1
- package/dist/src/planner/building/update.d.ts.map +1 -1
- package/dist/src/planner/building/update.js +134 -58
- package/dist/src/planner/building/update.js.map +1 -1
- package/dist/src/planner/building/view-mutation-builder.d.ts +15 -0
- package/dist/src/planner/building/view-mutation-builder.d.ts.map +1 -0
- package/dist/src/planner/building/view-mutation-builder.js +1158 -0
- package/dist/src/planner/building/view-mutation-builder.js.map +1 -0
- package/dist/src/planner/building/with.d.ts +11 -0
- package/dist/src/planner/building/with.d.ts.map +1 -1
- package/dist/src/planner/building/with.js +48 -10
- package/dist/src/planner/building/with.js.map +1 -1
- package/dist/src/planner/cost/index.d.ts +83 -0
- package/dist/src/planner/cost/index.d.ts.map +1 -1
- package/dist/src/planner/cost/index.js +114 -0
- package/dist/src/planner/cost/index.js.map +1 -1
- package/dist/src/planner/framework/characteristics.d.ts +38 -4
- package/dist/src/planner/framework/characteristics.d.ts.map +1 -1
- package/dist/src/planner/framework/characteristics.js +50 -6
- package/dist/src/planner/framework/characteristics.js.map +1 -1
- package/dist/src/planner/framework/pass.d.ts.map +1 -1
- package/dist/src/planner/framework/pass.js +2 -1
- package/dist/src/planner/framework/pass.js.map +1 -1
- package/dist/src/planner/framework/registry.d.ts +39 -1
- package/dist/src/planner/framework/registry.d.ts.map +1 -1
- package/dist/src/planner/framework/registry.js +18 -2
- package/dist/src/planner/framework/registry.js.map +1 -1
- package/dist/src/planner/mutation/backward-body.d.ts +131 -0
- package/dist/src/planner/mutation/backward-body.d.ts.map +1 -0
- package/dist/src/planner/mutation/backward-body.js +135 -0
- package/dist/src/planner/mutation/backward-body.js.map +1 -0
- package/dist/src/planner/mutation/cte-flatten.d.ts +17 -0
- package/dist/src/planner/mutation/cte-flatten.d.ts.map +1 -0
- package/dist/src/planner/mutation/cte-flatten.js +364 -0
- package/dist/src/planner/mutation/cte-flatten.js.map +1 -0
- package/dist/src/planner/mutation/decomposition.d.ts +273 -0
- package/dist/src/planner/mutation/decomposition.d.ts.map +1 -0
- package/dist/src/planner/mutation/decomposition.js +1719 -0
- package/dist/src/planner/mutation/decomposition.js.map +1 -0
- package/dist/src/planner/mutation/lens-enforcement.d.ts +165 -0
- package/dist/src/planner/mutation/lens-enforcement.d.ts.map +1 -0
- package/dist/src/planner/mutation/lens-enforcement.js +745 -0
- package/dist/src/planner/mutation/lens-enforcement.js.map +1 -0
- package/dist/src/planner/mutation/multi-source.d.ts +568 -0
- package/dist/src/planner/mutation/multi-source.d.ts.map +1 -0
- package/dist/src/planner/mutation/multi-source.js +2915 -0
- package/dist/src/planner/mutation/multi-source.js.map +1 -0
- package/dist/src/planner/mutation/mutation-diagnostic.d.ts +37 -0
- package/dist/src/planner/mutation/mutation-diagnostic.d.ts.map +1 -0
- package/dist/src/planner/mutation/mutation-diagnostic.js +24 -0
- package/dist/src/planner/mutation/mutation-diagnostic.js.map +1 -0
- package/dist/src/planner/mutation/mutation-tags.d.ts +33 -0
- package/dist/src/planner/mutation/mutation-tags.d.ts.map +1 -0
- package/dist/src/planner/mutation/mutation-tags.js +31 -0
- package/dist/src/planner/mutation/mutation-tags.js.map +1 -0
- package/dist/src/planner/mutation/propagate.d.ts +97 -0
- package/dist/src/planner/mutation/propagate.d.ts.map +1 -0
- package/dist/src/planner/mutation/propagate.js +220 -0
- package/dist/src/planner/mutation/propagate.js.map +1 -0
- package/dist/src/planner/mutation/scope-transform.d.ts +181 -0
- package/dist/src/planner/mutation/scope-transform.d.ts.map +1 -0
- package/dist/src/planner/mutation/scope-transform.js +574 -0
- package/dist/src/planner/mutation/scope-transform.js.map +1 -0
- package/dist/src/planner/mutation/set-op.d.ts +242 -0
- package/dist/src/planner/mutation/set-op.d.ts.map +1 -0
- package/dist/src/planner/mutation/set-op.js +1687 -0
- package/dist/src/planner/mutation/set-op.js.map +1 -0
- package/dist/src/planner/mutation/single-source.d.ts +261 -0
- package/dist/src/planner/mutation/single-source.d.ts.map +1 -0
- package/dist/src/planner/mutation/single-source.js +1096 -0
- package/dist/src/planner/mutation/single-source.js.map +1 -0
- package/dist/src/planner/nodes/aggregate-node.js +3 -3
- 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 +5 -1
- package/dist/src/planner/nodes/alias-node.js.map +1 -1
- package/dist/src/planner/nodes/alter-table-node.d.ts +124 -1
- package/dist/src/planner/nodes/alter-table-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/alter-table-node.js +27 -0
- package/dist/src/planner/nodes/alter-table-node.js.map +1 -1
- package/dist/src/planner/nodes/analyze-node.d.ts +2 -1
- package/dist/src/planner/nodes/analyze-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/analyze-node.js +18 -1
- package/dist/src/planner/nodes/analyze-node.js.map +1 -1
- package/dist/src/planner/nodes/asserted-keys-node.d.ts +43 -0
- package/dist/src/planner/nodes/asserted-keys-node.d.ts.map +1 -0
- package/dist/src/planner/nodes/asserted-keys-node.js +99 -0
- package/dist/src/planner/nodes/asserted-keys-node.js.map +1 -0
- package/dist/src/planner/nodes/async-gather-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/async-gather-node.js +33 -8
- package/dist/src/planner/nodes/async-gather-node.js.map +1 -1
- package/dist/src/planner/nodes/bloom-join-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/bloom-join-node.js +2 -1
- package/dist/src/planner/nodes/bloom-join-node.js.map +1 -1
- package/dist/src/planner/nodes/create-view-node.d.ts +7 -2
- package/dist/src/planner/nodes/create-view-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/create-view-node.js +4 -1
- package/dist/src/planner/nodes/create-view-node.js.map +1 -1
- package/dist/src/planner/nodes/declarative-schema.d.ts +13 -1
- package/dist/src/planner/nodes/declarative-schema.d.ts.map +1 -1
- package/dist/src/planner/nodes/declarative-schema.js +32 -0
- package/dist/src/planner/nodes/declarative-schema.js.map +1 -1
- package/dist/src/planner/nodes/distinct-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/distinct-node.js +2 -0
- package/dist/src/planner/nodes/distinct-node.js.map +1 -1
- package/dist/src/planner/nodes/dml-executor-node.d.ts +29 -1
- package/dist/src/planner/nodes/dml-executor-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/dml-executor-node.js +27 -3
- package/dist/src/planner/nodes/dml-executor-node.js.map +1 -1
- package/dist/src/planner/nodes/eager-prefetch-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/eager-prefetch-node.js +2 -0
- package/dist/src/planner/nodes/eager-prefetch-node.js.map +1 -1
- package/dist/src/planner/nodes/envelope-scan-node.d.ts +42 -0
- package/dist/src/planner/nodes/envelope-scan-node.d.ts.map +1 -0
- package/dist/src/planner/nodes/envelope-scan-node.js +62 -0
- package/dist/src/planner/nodes/envelope-scan-node.js.map +1 -0
- package/dist/src/planner/nodes/fanout-lookup-join-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/fanout-lookup-join-node.js +11 -1
- package/dist/src/planner/nodes/fanout-lookup-join-node.js.map +1 -1
- package/dist/src/planner/nodes/filter.d.ts.map +1 -1
- package/dist/src/planner/nodes/filter.js +63 -13
- package/dist/src/planner/nodes/filter.js.map +1 -1
- package/dist/src/planner/nodes/join-node.d.ts +41 -1
- package/dist/src/planner/nodes/join-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/join-node.js +78 -8
- package/dist/src/planner/nodes/join-node.js.map +1 -1
- package/dist/src/planner/nodes/join-utils.d.ts +33 -6
- package/dist/src/planner/nodes/join-utils.d.ts.map +1 -1
- package/dist/src/planner/nodes/join-utils.js +124 -9
- package/dist/src/planner/nodes/join-utils.js.map +1 -1
- package/dist/src/planner/nodes/lens-auxiliary-access-node.d.ts +104 -0
- package/dist/src/planner/nodes/lens-auxiliary-access-node.d.ts.map +1 -0
- package/dist/src/planner/nodes/lens-auxiliary-access-node.js +91 -0
- package/dist/src/planner/nodes/lens-auxiliary-access-node.js.map +1 -0
- package/dist/src/planner/nodes/limit-offset.d.ts.map +1 -1
- package/dist/src/planner/nodes/limit-offset.js +4 -5
- package/dist/src/planner/nodes/limit-offset.js.map +1 -1
- package/dist/src/planner/nodes/materialized-view-nodes.d.ts +69 -0
- package/dist/src/planner/nodes/materialized-view-nodes.d.ts.map +1 -0
- package/dist/src/planner/nodes/materialized-view-nodes.js +111 -0
- package/dist/src/planner/nodes/materialized-view-nodes.js.map +1 -0
- package/dist/src/planner/nodes/merge-join-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/merge-join-node.js +2 -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 +2 -0
- package/dist/src/planner/nodes/ordinal-slice-node.js.map +1 -1
- package/dist/src/planner/nodes/plan-node-type.d.ts +9 -0
- package/dist/src/planner/nodes/plan-node-type.d.ts.map +1 -1
- package/dist/src/planner/nodes/plan-node-type.js +9 -0
- package/dist/src/planner/nodes/plan-node-type.js.map +1 -1
- package/dist/src/planner/nodes/plan-node.d.ts +265 -5
- package/dist/src/planner/nodes/plan-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/plan-node.js.map +1 -1
- package/dist/src/planner/nodes/pragma.d.ts +2 -1
- package/dist/src/planner/nodes/pragma.d.ts.map +1 -1
- package/dist/src/planner/nodes/pragma.js +12 -0
- package/dist/src/planner/nodes/pragma.js.map +1 -1
- package/dist/src/planner/nodes/project-node.d.ts +14 -1
- package/dist/src/planner/nodes/project-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/project-node.js +85 -11
- package/dist/src/planner/nodes/project-node.js.map +1 -1
- package/dist/src/planner/nodes/reference.d.ts.map +1 -1
- package/dist/src/planner/nodes/reference.js +62 -27
- package/dist/src/planner/nodes/reference.js.map +1 -1
- package/dist/src/planner/nodes/retrieve-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/retrieve-node.js +7 -0
- package/dist/src/planner/nodes/retrieve-node.js.map +1 -1
- package/dist/src/planner/nodes/returning-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/returning-node.js +10 -3
- package/dist/src/planner/nodes/returning-node.js.map +1 -1
- package/dist/src/planner/nodes/scalar.d.ts +20 -0
- package/dist/src/planner/nodes/scalar.d.ts.map +1 -1
- package/dist/src/planner/nodes/scalar.js +71 -14
- package/dist/src/planner/nodes/scalar.js.map +1 -1
- package/dist/src/planner/nodes/set-object-tags-node.d.ts +39 -0
- package/dist/src/planner/nodes/set-object-tags-node.d.ts.map +1 -0
- package/dist/src/planner/nodes/set-object-tags-node.js +41 -0
- package/dist/src/planner/nodes/set-object-tags-node.js.map +1 -0
- package/dist/src/planner/nodes/set-operation-node.d.ts +123 -1
- package/dist/src/planner/nodes/set-operation-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/set-operation-node.js +291 -18
- package/dist/src/planner/nodes/set-operation-node.js.map +1 -1
- package/dist/src/planner/nodes/single-row.d.ts.map +1 -1
- package/dist/src/planner/nodes/single-row.js +3 -0
- package/dist/src/planner/nodes/single-row.js.map +1 -1
- package/dist/src/planner/nodes/sort.d.ts.map +1 -1
- package/dist/src/planner/nodes/sort.js +7 -6
- package/dist/src/planner/nodes/sort.js.map +1 -1
- package/dist/src/planner/nodes/subquery.d.ts +2 -0
- package/dist/src/planner/nodes/subquery.d.ts.map +1 -1
- package/dist/src/planner/nodes/subquery.js +18 -2
- package/dist/src/planner/nodes/subquery.js.map +1 -1
- package/dist/src/planner/nodes/table-access-nodes.d.ts.map +1 -1
- package/dist/src/planner/nodes/table-access-nodes.js +23 -3
- package/dist/src/planner/nodes/table-access-nodes.js.map +1 -1
- package/dist/src/planner/nodes/table-function-call.js +6 -0
- package/dist/src/planner/nodes/table-function-call.js.map +1 -1
- package/dist/src/planner/nodes/values-node.d.ts +1 -0
- package/dist/src/planner/nodes/values-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/values-node.js +16 -6
- package/dist/src/planner/nodes/values-node.js.map +1 -1
- package/dist/src/planner/nodes/view-mutation-node.d.ts +259 -0
- package/dist/src/planner/nodes/view-mutation-node.d.ts.map +1 -0
- package/dist/src/planner/nodes/view-mutation-node.js +273 -0
- package/dist/src/planner/nodes/view-mutation-node.js.map +1 -0
- package/dist/src/planner/nodes/window-function.d.ts +17 -1
- package/dist/src/planner/nodes/window-function.d.ts.map +1 -1
- package/dist/src/planner/nodes/window-function.js +15 -1
- package/dist/src/planner/nodes/window-function.js.map +1 -1
- package/dist/src/planner/nodes/window-node.js +2 -2
- package/dist/src/planner/nodes/window-node.js.map +1 -1
- package/dist/src/planner/optimizer.d.ts.map +1 -1
- package/dist/src/planner/optimizer.js +372 -39
- package/dist/src/planner/optimizer.js.map +1 -1
- package/dist/src/planner/planning-context.d.ts +1 -1
- package/dist/src/planner/planning-context.d.ts.map +1 -1
- package/dist/src/planner/rules/access/lens-access-form-matcher.d.ts +70 -0
- package/dist/src/planner/rules/access/lens-access-form-matcher.d.ts.map +1 -0
- package/dist/src/planner/rules/access/lens-access-form-matcher.js +156 -0
- package/dist/src/planner/rules/access/lens-access-form-matcher.js.map +1 -0
- package/dist/src/planner/rules/access/rule-lens-auxiliary-access.d.ts +31 -0
- package/dist/src/planner/rules/access/rule-lens-auxiliary-access.d.ts.map +1 -0
- package/dist/src/planner/rules/access/rule-lens-auxiliary-access.js +176 -0
- package/dist/src/planner/rules/access/rule-lens-auxiliary-access.js.map +1 -0
- package/dist/src/planner/rules/access/rule-select-access-path.d.ts.map +1 -1
- package/dist/src/planner/rules/access/rule-select-access-path.js +435 -37
- package/dist/src/planner/rules/access/rule-select-access-path.js.map +1 -1
- package/dist/src/planner/rules/aggregate/rule-groupby-fd-simplification.d.ts.map +1 -1
- package/dist/src/planner/rules/aggregate/rule-groupby-fd-simplification.js +9 -0
- package/dist/src/planner/rules/aggregate/rule-groupby-fd-simplification.js.map +1 -1
- package/dist/src/planner/rules/cache/rule-materialized-view-rewrite.d.ts +39 -0
- package/dist/src/planner/rules/cache/rule-materialized-view-rewrite.d.ts.map +1 -0
- package/dist/src/planner/rules/cache/rule-materialized-view-rewrite.js +616 -0
- package/dist/src/planner/rules/cache/rule-materialized-view-rewrite.js.map +1 -0
- package/dist/src/planner/rules/cache/rule-scalar-cse.d.ts.map +1 -1
- package/dist/src/planner/rules/cache/rule-scalar-cse.js +8 -1
- package/dist/src/planner/rules/cache/rule-scalar-cse.js.map +1 -1
- package/dist/src/planner/rules/join/equi-pair-extractor.d.ts +36 -0
- package/dist/src/planner/rules/join/equi-pair-extractor.d.ts.map +1 -1
- package/dist/src/planner/rules/join/equi-pair-extractor.js +38 -1
- package/dist/src/planner/rules/join/equi-pair-extractor.js.map +1 -1
- package/dist/src/planner/rules/join/rule-fanout-batched-outer.d.ts.map +1 -1
- package/dist/src/planner/rules/join/rule-fanout-batched-outer.js +10 -0
- package/dist/src/planner/rules/join/rule-fanout-batched-outer.js.map +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 +19 -1
- 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 +130 -0
- package/dist/src/planner/rules/join/rule-inner-join-existence-recovery.d.ts.map +1 -0
- package/dist/src/planner/rules/join/rule-inner-join-existence-recovery.js +206 -0
- package/dist/src/planner/rules/join/rule-inner-join-existence-recovery.js.map +1 -0
- package/dist/src/planner/rules/join/rule-join-elimination.d.ts +67 -14
- package/dist/src/planner/rules/join/rule-join-elimination.d.ts.map +1 -1
- package/dist/src/planner/rules/join/rule-join-elimination.js +81 -25
- package/dist/src/planner/rules/join/rule-join-elimination.js.map +1 -1
- package/dist/src/planner/rules/join/rule-join-existence-pruning.d.ts +84 -0
- package/dist/src/planner/rules/join/rule-join-existence-pruning.d.ts.map +1 -0
- package/dist/src/planner/rules/join/rule-join-existence-pruning.js +138 -0
- package/dist/src/planner/rules/join/rule-join-existence-pruning.js.map +1 -0
- package/dist/src/planner/rules/join/rule-join-greedy-commute.d.ts.map +1 -1
- package/dist/src/planner/rules/join/rule-join-greedy-commute.js +9 -1
- package/dist/src/planner/rules/join/rule-join-greedy-commute.js.map +1 -1
- package/dist/src/planner/rules/join/rule-join-physical-selection.d.ts.map +1 -1
- package/dist/src/planner/rules/join/rule-join-physical-selection.js +12 -1
- package/dist/src/planner/rules/join/rule-join-physical-selection.js.map +1 -1
- package/dist/src/planner/rules/join/rule-lateral-top1-asof.d.ts.map +1 -1
- package/dist/src/planner/rules/join/rule-lateral-top1-asof.js +4 -0
- package/dist/src/planner/rules/join/rule-lateral-top1-asof.js.map +1 -1
- package/dist/src/planner/rules/join/rule-monotonic-merge-join.d.ts.map +1 -1
- package/dist/src/planner/rules/join/rule-monotonic-merge-join.js +4 -0
- package/dist/src/planner/rules/join/rule-monotonic-merge-join.js.map +1 -1
- package/dist/src/planner/rules/join/rule-quickpick-enumeration.d.ts.map +1 -1
- package/dist/src/planner/rules/join/rule-quickpick-enumeration.js +10 -0
- package/dist/src/planner/rules/join/rule-quickpick-enumeration.js.map +1 -1
- package/dist/src/planner/rules/join/rule-semijoin-existence-recovery.d.ts +286 -0
- package/dist/src/planner/rules/join/rule-semijoin-existence-recovery.d.ts.map +1 -0
- package/dist/src/planner/rules/join/rule-semijoin-existence-recovery.js +548 -0
- package/dist/src/planner/rules/join/rule-semijoin-existence-recovery.js.map +1 -0
- package/dist/src/planner/rules/parallel/rule-async-gather-union-all.d.ts.map +1 -1
- package/dist/src/planner/rules/parallel/rule-async-gather-union-all.js +9 -1
- package/dist/src/planner/rules/parallel/rule-async-gather-union-all.js.map +1 -1
- package/dist/src/planner/rules/parallel/rule-async-gather-zip-by-key.d.ts.map +1 -1
- package/dist/src/planner/rules/parallel/rule-async-gather-zip-by-key.js +7 -0
- package/dist/src/planner/rules/parallel/rule-async-gather-zip-by-key.js.map +1 -1
- package/dist/src/planner/rules/parallel/rule-eager-prefetch-probe.d.ts.map +1 -1
- package/dist/src/planner/rules/parallel/rule-eager-prefetch-probe.js +10 -1
- package/dist/src/planner/rules/parallel/rule-eager-prefetch-probe.js.map +1 -1
- package/dist/src/planner/rules/predicate/rule-aggregate-predicate-pushdown.d.ts.map +1 -1
- package/dist/src/planner/rules/predicate/rule-aggregate-predicate-pushdown.js +9 -0
- package/dist/src/planner/rules/predicate/rule-aggregate-predicate-pushdown.js.map +1 -1
- package/dist/src/planner/rules/predicate/rule-empty-relation-folding.d.ts.map +1 -1
- package/dist/src/planner/rules/predicate/rule-empty-relation-folding.js +18 -0
- package/dist/src/planner/rules/predicate/rule-empty-relation-folding.js.map +1 -1
- package/dist/src/planner/rules/predicate/rule-filter-contradiction.d.ts.map +1 -1
- package/dist/src/planner/rules/predicate/rule-filter-contradiction.js +7 -0
- package/dist/src/planner/rules/predicate/rule-filter-contradiction.js.map +1 -1
- package/dist/src/planner/rules/predicate/rule-predicate-inference-equivalence.d.ts.map +1 -1
- package/dist/src/planner/rules/predicate/rule-predicate-inference-equivalence.js +9 -0
- package/dist/src/planner/rules/predicate/rule-predicate-inference-equivalence.js.map +1 -1
- package/dist/src/planner/rules/predicate/rule-predicate-pushdown.js +13 -3
- package/dist/src/planner/rules/predicate/rule-predicate-pushdown.js.map +1 -1
- package/dist/src/planner/rules/retrieve/rule-projection-pruning.d.ts.map +1 -1
- package/dist/src/planner/rules/retrieve/rule-projection-pruning.js +14 -0
- package/dist/src/planner/rules/retrieve/rule-projection-pruning.js.map +1 -1
- 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 +4 -4
- package/dist/src/planner/rules/sort/rule-orderby-fd-pruning.js.map +1 -1
- package/dist/src/planner/rules/subquery/rule-anti-join-fk-empty.d.ts.map +1 -1
- package/dist/src/planner/rules/subquery/rule-anti-join-fk-empty.js +8 -0
- package/dist/src/planner/rules/subquery/rule-anti-join-fk-empty.js.map +1 -1
- package/dist/src/planner/rules/subquery/rule-semi-join-fk-trivial.d.ts.map +1 -1
- package/dist/src/planner/rules/subquery/rule-semi-join-fk-trivial.js +7 -0
- package/dist/src/planner/rules/subquery/rule-semi-join-fk-trivial.js.map +1 -1
- package/dist/src/planner/rules/subquery/rule-subquery-decorrelation.d.ts.map +1 -1
- package/dist/src/planner/rules/subquery/rule-subquery-decorrelation.js +12 -0
- package/dist/src/planner/rules/subquery/rule-subquery-decorrelation.js.map +1 -1
- package/dist/src/planner/type-utils.d.ts +14 -0
- package/dist/src/planner/type-utils.d.ts.map +1 -1
- package/dist/src/planner/type-utils.js +66 -21
- package/dist/src/planner/type-utils.js.map +1 -1
- package/dist/src/planner/util/fd-utils.d.ts +177 -43
- package/dist/src/planner/util/fd-utils.d.ts.map +1 -1
- package/dist/src/planner/util/fd-utils.js +396 -101
- package/dist/src/planner/util/fd-utils.js.map +1 -1
- package/dist/src/planner/util/ind-utils.d.ts +27 -1
- package/dist/src/planner/util/ind-utils.d.ts.map +1 -1
- package/dist/src/planner/util/ind-utils.js +80 -6
- package/dist/src/planner/util/ind-utils.js.map +1 -1
- package/dist/src/planner/util/key-utils.d.ts.map +1 -1
- package/dist/src/planner/util/key-utils.js +81 -12
- package/dist/src/planner/util/key-utils.js.map +1 -1
- package/dist/src/planner/util/set-op-wrapper.d.ts +37 -0
- package/dist/src/planner/util/set-op-wrapper.d.ts.map +1 -0
- package/dist/src/planner/util/set-op-wrapper.js +82 -0
- package/dist/src/planner/util/set-op-wrapper.js.map +1 -0
- package/dist/src/planner/validation/plan-validator.d.ts.map +1 -1
- package/dist/src/planner/validation/plan-validator.js +1 -0
- package/dist/src/planner/validation/plan-validator.js.map +1 -1
- package/dist/src/runtime/context-helpers.d.ts +13 -1
- package/dist/src/runtime/context-helpers.d.ts.map +1 -1
- package/dist/src/runtime/context-helpers.js +7 -1
- package/dist/src/runtime/context-helpers.js.map +1 -1
- package/dist/src/runtime/delta-executor.d.ts +30 -1
- package/dist/src/runtime/delta-executor.d.ts.map +1 -1
- package/dist/src/runtime/delta-executor.js +29 -4
- package/dist/src/runtime/delta-executor.js.map +1 -1
- package/dist/src/runtime/emit/add-constraint.d.ts.map +1 -1
- package/dist/src/runtime/emit/add-constraint.js +38 -5
- package/dist/src/runtime/emit/add-constraint.js.map +1 -1
- package/dist/src/runtime/emit/aggregate.d.ts.map +1 -1
- package/dist/src/runtime/emit/aggregate.js +10 -8
- package/dist/src/runtime/emit/aggregate.js.map +1 -1
- package/dist/src/runtime/emit/alter-table.d.ts +1 -1
- package/dist/src/runtime/emit/alter-table.d.ts.map +1 -1
- package/dist/src/runtime/emit/alter-table.js +664 -108
- 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 +18 -5
- package/dist/src/runtime/emit/asof-scan.js.map +1 -1
- package/dist/src/runtime/emit/asserted-keys.d.ts +13 -0
- package/dist/src/runtime/emit/asserted-keys.d.ts.map +1 -0
- package/dist/src/runtime/emit/asserted-keys.js +13 -0
- package/dist/src/runtime/emit/asserted-keys.js.map +1 -0
- package/dist/src/runtime/emit/between.d.ts.map +1 -1
- package/dist/src/runtime/emit/between.js +24 -19
- 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 +5 -9
- 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 +11 -2
- 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 +8 -2
- package/dist/src/runtime/emit/bloom-join.js.map +1 -1
- package/dist/src/runtime/emit/constraint-check.js +15 -0
- package/dist/src/runtime/emit/constraint-check.js.map +1 -1
- package/dist/src/runtime/emit/create-table.d.ts.map +1 -1
- package/dist/src/runtime/emit/create-table.js +8 -0
- package/dist/src/runtime/emit/create-table.js.map +1 -1
- package/dist/src/runtime/emit/create-view.d.ts.map +1 -1
- package/dist/src/runtime/emit/create-view.js +16 -1
- package/dist/src/runtime/emit/create-view.js.map +1 -1
- package/dist/src/runtime/emit/dml-executor.d.ts +27 -0
- package/dist/src/runtime/emit/dml-executor.d.ts.map +1 -1
- package/dist/src/runtime/emit/dml-executor.js +413 -193
- package/dist/src/runtime/emit/dml-executor.js.map +1 -1
- package/dist/src/runtime/emit/drop-table.d.ts.map +1 -1
- package/dist/src/runtime/emit/drop-table.js +10 -0
- package/dist/src/runtime/emit/drop-table.js.map +1 -1
- package/dist/src/runtime/emit/drop-view.d.ts.map +1 -1
- package/dist/src/runtime/emit/drop-view.js +17 -0
- package/dist/src/runtime/emit/drop-view.js.map +1 -1
- package/dist/src/runtime/emit/envelope-scan.d.ts +13 -0
- package/dist/src/runtime/emit/envelope-scan.d.ts.map +1 -0
- package/dist/src/runtime/emit/envelope-scan.js +22 -0
- package/dist/src/runtime/emit/envelope-scan.js.map +1 -0
- package/dist/src/runtime/emit/join.d.ts +10 -2
- package/dist/src/runtime/emit/join.d.ts.map +1 -1
- package/dist/src/runtime/emit/join.js +128 -38
- package/dist/src/runtime/emit/join.js.map +1 -1
- package/dist/src/runtime/emit/lens-auxiliary-access.d.ts +16 -0
- package/dist/src/runtime/emit/lens-auxiliary-access.d.ts.map +1 -0
- package/dist/src/runtime/emit/lens-auxiliary-access.js +16 -0
- package/dist/src/runtime/emit/lens-auxiliary-access.js.map +1 -0
- package/dist/src/runtime/emit/materialized-view-helpers.d.ts +640 -0
- package/dist/src/runtime/emit/materialized-view-helpers.d.ts.map +1 -0
- package/dist/src/runtime/emit/materialized-view-helpers.js +2576 -0
- package/dist/src/runtime/emit/materialized-view-helpers.js.map +1 -0
- package/dist/src/runtime/emit/materialized-view.d.ts +31 -0
- package/dist/src/runtime/emit/materialized-view.d.ts.map +1 -0
- package/dist/src/runtime/emit/materialized-view.js +187 -0
- package/dist/src/runtime/emit/materialized-view.js.map +1 -0
- package/dist/src/runtime/emit/merge-join.d.ts.map +1 -1
- package/dist/src/runtime/emit/merge-join.js +15 -3
- package/dist/src/runtime/emit/merge-join.js.map +1 -1
- package/dist/src/runtime/emit/project.d.ts.map +1 -1
- package/dist/src/runtime/emit/project.js +10 -5
- package/dist/src/runtime/emit/project.js.map +1 -1
- package/dist/src/runtime/emit/schema-declarative.d.ts +1 -0
- package/dist/src/runtime/emit/schema-declarative.d.ts.map +1 -1
- package/dist/src/runtime/emit/schema-declarative.js +101 -5
- package/dist/src/runtime/emit/schema-declarative.js.map +1 -1
- package/dist/src/runtime/emit/set-object-tags.d.ts +16 -0
- package/dist/src/runtime/emit/set-object-tags.d.ts.map +1 -0
- package/dist/src/runtime/emit/set-object-tags.js +57 -0
- package/dist/src/runtime/emit/set-object-tags.js.map +1 -0
- package/dist/src/runtime/emit/set-operation.d.ts.map +1 -1
- package/dist/src/runtime/emit/set-operation.js +140 -24
- package/dist/src/runtime/emit/set-operation.js.map +1 -1
- package/dist/src/runtime/emit/subquery.d.ts.map +1 -1
- package/dist/src/runtime/emit/subquery.js +110 -5
- package/dist/src/runtime/emit/subquery.js.map +1 -1
- package/dist/src/runtime/emit/unary.d.ts.map +1 -1
- package/dist/src/runtime/emit/unary.js +34 -6
- package/dist/src/runtime/emit/unary.js.map +1 -1
- package/dist/src/runtime/emit/view-mutation.d.ts +70 -0
- package/dist/src/runtime/emit/view-mutation.d.ts.map +1 -0
- package/dist/src/runtime/emit/view-mutation.js +299 -0
- package/dist/src/runtime/emit/view-mutation.js.map +1 -0
- package/dist/src/runtime/emit/window.js +29 -5
- package/dist/src/runtime/emit/window.js.map +1 -1
- package/dist/src/runtime/foreign-key-actions.d.ts +66 -3
- package/dist/src/runtime/foreign-key-actions.d.ts.map +1 -1
- package/dist/src/runtime/foreign-key-actions.js +580 -172
- package/dist/src/runtime/foreign-key-actions.js.map +1 -1
- package/dist/src/runtime/parallel-driver.d.ts +4 -1
- package/dist/src/runtime/parallel-driver.d.ts.map +1 -1
- package/dist/src/runtime/parallel-driver.js +5 -1
- package/dist/src/runtime/parallel-driver.js.map +1 -1
- package/dist/src/runtime/register.d.ts.map +1 -1
- package/dist/src/runtime/register.js +17 -1
- package/dist/src/runtime/register.js.map +1 -1
- package/dist/src/runtime/types.d.ts +10 -0
- package/dist/src/runtime/types.d.ts.map +1 -1
- package/dist/src/runtime/types.js.map +1 -1
- package/dist/src/schema/basis-backfill.d.ts +63 -0
- package/dist/src/schema/basis-backfill.d.ts.map +1 -0
- package/dist/src/schema/basis-backfill.js +161 -0
- package/dist/src/schema/basis-backfill.js.map +1 -0
- package/dist/src/schema/catalog.d.ts +115 -1
- package/dist/src/schema/catalog.d.ts.map +1 -1
- package/dist/src/schema/catalog.js +249 -22
- package/dist/src/schema/catalog.js.map +1 -1
- package/dist/src/schema/change-events.d.ts +42 -1
- package/dist/src/schema/change-events.d.ts.map +1 -1
- package/dist/src/schema/change-events.js.map +1 -1
- package/dist/src/schema/column.d.ts +16 -0
- package/dist/src/schema/column.d.ts.map +1 -1
- package/dist/src/schema/column.js.map +1 -1
- package/dist/src/schema/constraint-builder.d.ts +182 -0
- package/dist/src/schema/constraint-builder.d.ts.map +1 -0
- package/dist/src/schema/constraint-builder.js +424 -0
- package/dist/src/schema/constraint-builder.js.map +1 -0
- package/dist/src/schema/ddl-generator.d.ts +86 -1
- package/dist/src/schema/ddl-generator.d.ts.map +1 -1
- package/dist/src/schema/ddl-generator.js +316 -20
- package/dist/src/schema/ddl-generator.js.map +1 -1
- package/dist/src/schema/declared-schema-manager.d.ts +51 -0
- package/dist/src/schema/declared-schema-manager.d.ts.map +1 -1
- package/dist/src/schema/declared-schema-manager.js +61 -0
- package/dist/src/schema/declared-schema-manager.js.map +1 -1
- package/dist/src/schema/derivation.d.ts +106 -0
- package/dist/src/schema/derivation.d.ts.map +1 -0
- package/dist/src/schema/derivation.js +25 -0
- package/dist/src/schema/derivation.js.map +1 -0
- package/dist/src/schema/function.d.ts +20 -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-ack.d.ts +90 -0
- package/dist/src/schema/lens-ack.d.ts.map +1 -0
- package/dist/src/schema/lens-ack.js +361 -0
- package/dist/src/schema/lens-ack.js.map +1 -0
- package/dist/src/schema/lens-compiler.d.ts +62 -0
- package/dist/src/schema/lens-compiler.d.ts.map +1 -0
- package/dist/src/schema/lens-compiler.js +1594 -0
- package/dist/src/schema/lens-compiler.js.map +1 -0
- package/dist/src/schema/lens-fk-discovery.d.ts +175 -0
- package/dist/src/schema/lens-fk-discovery.d.ts.map +1 -0
- package/dist/src/schema/lens-fk-discovery.js +336 -0
- package/dist/src/schema/lens-fk-discovery.js.map +1 -0
- package/dist/src/schema/lens-prover.d.ts +336 -0
- package/dist/src/schema/lens-prover.d.ts.map +1 -0
- package/dist/src/schema/lens-prover.js +1988 -0
- package/dist/src/schema/lens-prover.js.map +1 -0
- package/dist/src/schema/lens.d.ts +254 -0
- package/dist/src/schema/lens.d.ts.map +1 -0
- package/dist/src/schema/lens.js +21 -0
- package/dist/src/schema/lens.js.map +1 -0
- package/dist/src/schema/manager.d.ts +676 -18
- package/dist/src/schema/manager.d.ts.map +1 -1
- package/dist/src/schema/manager.js +1573 -238
- package/dist/src/schema/manager.js.map +1 -1
- package/dist/src/schema/mapping-advertisement-tags.d.ts +39 -0
- package/dist/src/schema/mapping-advertisement-tags.d.ts.map +1 -0
- package/dist/src/schema/mapping-advertisement-tags.js +216 -0
- package/dist/src/schema/mapping-advertisement-tags.js.map +1 -0
- package/dist/src/schema/rename-rewriter.d.ts +45 -4
- package/dist/src/schema/rename-rewriter.d.ts.map +1 -1
- package/dist/src/schema/rename-rewriter.js +412 -19
- package/dist/src/schema/rename-rewriter.js.map +1 -1
- package/dist/src/schema/reserved-tags-policy.d.ts +32 -0
- package/dist/src/schema/reserved-tags-policy.d.ts.map +1 -0
- package/dist/src/schema/reserved-tags-policy.js +34 -0
- package/dist/src/schema/reserved-tags-policy.js.map +1 -0
- package/dist/src/schema/reserved-tags.d.ts +170 -0
- package/dist/src/schema/reserved-tags.d.ts.map +1 -0
- package/dist/src/schema/reserved-tags.js +507 -0
- package/dist/src/schema/reserved-tags.js.map +1 -0
- package/dist/src/schema/schema-differ.d.ts +158 -2
- package/dist/src/schema/schema-differ.d.ts.map +1 -1
- package/dist/src/schema/schema-differ.js +1460 -78
- package/dist/src/schema/schema-differ.js.map +1 -1
- package/dist/src/schema/schema-hasher.d.ts +8 -3
- package/dist/src/schema/schema-hasher.d.ts.map +1 -1
- package/dist/src/schema/schema-hasher.js +22 -2
- package/dist/src/schema/schema-hasher.js.map +1 -1
- package/dist/src/schema/schema.d.ts +25 -1
- package/dist/src/schema/schema.d.ts.map +1 -1
- package/dist/src/schema/schema.js +36 -2
- package/dist/src/schema/schema.js.map +1 -1
- package/dist/src/schema/table.d.ts +259 -10
- package/dist/src/schema/table.d.ts.map +1 -1
- package/dist/src/schema/table.js +309 -26
- package/dist/src/schema/table.js.map +1 -1
- package/dist/src/schema/unique-enforcement.d.ts +78 -0
- package/dist/src/schema/unique-enforcement.d.ts.map +1 -0
- package/dist/src/schema/unique-enforcement.js +93 -0
- package/dist/src/schema/unique-enforcement.js.map +1 -0
- package/dist/src/schema/view.d.ts +83 -2
- package/dist/src/schema/view.d.ts.map +1 -1
- package/dist/src/schema/view.js +67 -1
- package/dist/src/schema/view.js.map +1 -1
- package/dist/src/schema/window-function.d.ts +9 -1
- package/dist/src/schema/window-function.d.ts.map +1 -1
- package/dist/src/schema/window-function.js.map +1 -1
- package/dist/src/util/comparison.d.ts +24 -0
- package/dist/src/util/comparison.d.ts.map +1 -1
- package/dist/src/util/comparison.js +34 -0
- package/dist/src/util/comparison.js.map +1 -1
- package/dist/src/util/mutation-statement.d.ts.map +1 -1
- package/dist/src/util/mutation-statement.js +4 -1
- package/dist/src/util/mutation-statement.js.map +1 -1
- package/dist/src/util/serialization.d.ts +9 -0
- package/dist/src/util/serialization.d.ts.map +1 -1
- package/dist/src/util/serialization.js +26 -0
- package/dist/src/util/serialization.js.map +1 -1
- package/dist/src/vtab/backing-host.d.ts +286 -0
- package/dist/src/vtab/backing-host.d.ts.map +1 -0
- package/dist/src/vtab/backing-host.js +118 -0
- package/dist/src/vtab/backing-host.js.map +1 -0
- package/dist/src/vtab/best-access-plan.d.ts +21 -0
- package/dist/src/vtab/best-access-plan.d.ts.map +1 -1
- package/dist/src/vtab/best-access-plan.js.map +1 -1
- package/dist/src/vtab/capabilities.d.ts +5 -5
- package/dist/src/vtab/capabilities.d.ts.map +1 -1
- package/dist/src/vtab/mapping-advertisement.d.ts +163 -0
- package/dist/src/vtab/mapping-advertisement.d.ts.map +1 -0
- package/dist/src/vtab/mapping-advertisement.js +2 -0
- package/dist/src/vtab/mapping-advertisement.js.map +1 -0
- package/dist/src/vtab/memory/index.d.ts +64 -4
- package/dist/src/vtab/memory/index.d.ts.map +1 -1
- package/dist/src/vtab/memory/index.js +119 -12
- package/dist/src/vtab/memory/index.js.map +1 -1
- package/dist/src/vtab/memory/layer/base.d.ts +38 -1
- package/dist/src/vtab/memory/layer/base.d.ts.map +1 -1
- package/dist/src/vtab/memory/layer/base.js +112 -24
- package/dist/src/vtab/memory/layer/base.js.map +1 -1
- package/dist/src/vtab/memory/layer/manager.d.ts +291 -4
- package/dist/src/vtab/memory/layer/manager.d.ts.map +1 -1
- package/dist/src/vtab/memory/layer/manager.js +1050 -91
- package/dist/src/vtab/memory/layer/manager.js.map +1 -1
- package/dist/src/vtab/memory/layer/plan-filter.d.ts.map +1 -1
- package/dist/src/vtab/memory/layer/plan-filter.js +35 -6
- package/dist/src/vtab/memory/layer/plan-filter.js.map +1 -1
- package/dist/src/vtab/memory/layer/scan-layer.d.ts.map +1 -1
- package/dist/src/vtab/memory/layer/scan-layer.js +66 -14
- package/dist/src/vtab/memory/layer/scan-layer.js.map +1 -1
- package/dist/src/vtab/memory/layer/scan-plan.d.ts +14 -0
- package/dist/src/vtab/memory/layer/scan-plan.d.ts.map +1 -1
- package/dist/src/vtab/memory/layer/scan-plan.js +27 -4
- package/dist/src/vtab/memory/layer/scan-plan.js.map +1 -1
- package/dist/src/vtab/memory/layer/transaction.d.ts.map +1 -1
- package/dist/src/vtab/memory/layer/transaction.js +5 -1
- package/dist/src/vtab/memory/layer/transaction.js.map +1 -1
- package/dist/src/vtab/memory/module.d.ts +17 -0
- package/dist/src/vtab/memory/module.d.ts.map +1 -1
- package/dist/src/vtab/memory/module.js +82 -3
- package/dist/src/vtab/memory/module.js.map +1 -1
- package/dist/src/vtab/memory/table.d.ts.map +1 -1
- package/dist/src/vtab/memory/table.js +15 -5
- package/dist/src/vtab/memory/table.js.map +1 -1
- package/dist/src/vtab/memory/types.d.ts +20 -2
- package/dist/src/vtab/memory/types.d.ts.map +1 -1
- package/dist/src/vtab/memory/utils/predicate.d.ts.map +1 -1
- package/dist/src/vtab/memory/utils/predicate.js +46 -24
- package/dist/src/vtab/memory/utils/predicate.js.map +1 -1
- package/dist/src/vtab/memory/utils/primary-key-encode.d.ts +31 -0
- package/dist/src/vtab/memory/utils/primary-key-encode.d.ts.map +1 -0
- package/dist/src/vtab/memory/utils/primary-key-encode.js +101 -0
- package/dist/src/vtab/memory/utils/primary-key-encode.js.map +1 -0
- package/dist/src/vtab/memory/utils/primary-key.d.ts +8 -0
- package/dist/src/vtab/memory/utils/primary-key.d.ts.map +1 -1
- package/dist/src/vtab/memory/utils/primary-key.js +12 -5
- package/dist/src/vtab/memory/utils/primary-key.js.map +1 -1
- package/dist/src/vtab/module.d.ts +203 -4
- package/dist/src/vtab/module.d.ts.map +1 -1
- package/dist/src/vtab/table.d.ts +9 -0
- package/dist/src/vtab/table.d.ts.map +1 -1
- package/dist/src/vtab/table.js.map +1 -1
- package/package.json +17 -16
|
@@ -0,0 +1,1253 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Materialized-view maintenance: schema-change staleness tracking plus row-time
|
|
3
|
+
* write-through maintenance.
|
|
4
|
+
*
|
|
5
|
+
* Two responsibilities:
|
|
6
|
+
*
|
|
7
|
+
* 1. **Staleness** — a *schema* change to a source table (drop / alter) can break
|
|
8
|
+
* an MV's body. This manager subscribes to schema-change events and marks any
|
|
9
|
+
* MV whose body reads a modified/removed source `stale`. The next reference
|
|
10
|
+
* re-validates the body (erroring with the staleness diagnostic on an
|
|
11
|
+
* incompatible change); the next successful refresh clears the flag. One
|
|
12
|
+
* carve-out: a **body-irrelevant** `table_modified` (constraint/stats/tags-only —
|
|
13
|
+
* columns and physical PK identical, see `isBodyIrrelevantTableChange`) instead
|
|
14
|
+
* RECOMPILES each live dependent's row-time plan in place
|
|
15
|
+
* (`tryRecompileMaterializedViewLive`, gated by shape re-derivation), falling
|
|
16
|
+
* back to mark-stale on any failure — so DROP/ADD/RENAME CONSTRAINT and ANALYZE
|
|
17
|
+
* no longer de-liven dependents whose backing shape is unaffected. The SAME
|
|
18
|
+
* subscription also rebuilds a maintained table's compiled **derived-row
|
|
19
|
+
* constraint validator** when a *constraint-only* dependency — an FK parent or a
|
|
20
|
+
* subquery-CHECK target, neither a derivation source — is renamed/dropped/re-created
|
|
21
|
+
* (see {@link MaterializedViewManager.rebuildConstraintValidatorsFor}); without
|
|
22
|
+
* this the validator, compiled once at registration, would keep resolving against
|
|
23
|
+
* the dead/renamed incarnation and fail maintenance writes with an internal
|
|
24
|
+
* module-connect error.
|
|
25
|
+
*
|
|
26
|
+
* 2. **Row-time write-through** (`maintainRowTime`) — the backing table is kept
|
|
27
|
+
* consistent *synchronously* with each source row-write, driven from the
|
|
28
|
+
* runtime DML boundary (not at COMMIT). Each MV's maintenance is **cost-gated with a
|
|
29
|
+
* floor**: the builder matches the body to a bounded-delta arm (the covering-index
|
|
30
|
+
* inverse projection, an aggregate / lateral-TVF / 1:1-join residual) when one fits —
|
|
31
|
+
* each source row then maps to a bounded backing delta, no full scan — and otherwise
|
|
32
|
+
* falls through to the always-correct **full-rebuild floor** (re-evaluate the whole
|
|
33
|
+
* body, replace the backing). **No body is rejected for its shape;** the only
|
|
34
|
+
* create-time rejections are non-shape (non-determinism, bag/no-key, no relational
|
|
35
|
+
* output, and a full-rebuild-only body over a source past the size threshold). The
|
|
36
|
+
* write targets the backing table's *pending* transaction layer through the same
|
|
37
|
+
* connection a `select` from the MV uses, so the change is visible mid-transaction
|
|
38
|
+
* (reads-own-writes) and is committed/rolled-back in lockstep with the source write by
|
|
39
|
+
* the coordinated commit (see {@link MaterializedViewManager.buildMaintenancePlan}).
|
|
40
|
+
*/
|
|
41
|
+
import type { SchemaManager } from '../schema/manager.js';
|
|
42
|
+
import { type SqlValue, type Row } from '../common/types.js';
|
|
43
|
+
import { Scheduler } from '../runtime/scheduler.js';
|
|
44
|
+
import type { BindingMode } from '../planner/analysis/binding-extractor.js';
|
|
45
|
+
import { type MaintenanceSourceStats, type MaintenanceStrategy } from '../planner/cost/index.js';
|
|
46
|
+
import { type DerivedRowConstraintValidator } from './derived-row-validator.js';
|
|
47
|
+
import type { BackingRowChange } from '../vtab/backing-host.js';
|
|
48
|
+
import type { VirtualTableConnection } from '../vtab/connection.js';
|
|
49
|
+
import { type CompiledPredicate } from '../vtab/memory/utils/predicate.js';
|
|
50
|
+
import type { MaintainedTableSchema } from '../schema/derivation.js';
|
|
51
|
+
import type { UniqueConstraintSchema } from '../schema/table.js';
|
|
52
|
+
import type { Database } from './database.js';
|
|
53
|
+
import type { DatabaseEventEmitter } from './database-events.js';
|
|
54
|
+
import type * as AST from '../parser/ast.js';
|
|
55
|
+
/**
|
|
56
|
+
* Database internals the materialized-view manager needs. Mirrors
|
|
57
|
+
* `AssertionEvaluatorContext` / `WatcherManagerContext` — keeps the manager
|
|
58
|
+
* decoupled from the full `Database`.
|
|
59
|
+
*/
|
|
60
|
+
export interface MaterializedViewManagerContext {
|
|
61
|
+
readonly schemaManager: SchemaManager;
|
|
62
|
+
readonly optimizer: Database['optimizer'];
|
|
63
|
+
/** Database event emitter — the row-time collision telemetry channel
|
|
64
|
+
* ({@link MaterializedViewManager.detectAndReportCoarseningCollisions}) queues
|
|
65
|
+
* {@link MaintenanceCollisionEvent}s here. Already exposed for the transaction
|
|
66
|
+
* manager; reused narrowly. */
|
|
67
|
+
getEventEmitter(): DatabaseEventEmitter;
|
|
68
|
+
_buildPlan(statements: AST.Statement[]): import('./database.js').BuildPlanResult;
|
|
69
|
+
_findTable(tableName: string, schemaName?: string): ReturnType<Database['_findTable']>;
|
|
70
|
+
/** Backing-connection resolution for row-time write-through (see {@link MaterializedViewManager.getBackingConnection}). */
|
|
71
|
+
getConnectionsForTable(tableName: string): VirtualTableConnection[];
|
|
72
|
+
registerConnection(connection: VirtualTableConnection): Promise<void>;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* A compiled per-MV maintenance plan — how {@link MaterializedViewManager.applyMaintenancePlan}
|
|
76
|
+
* keeps an MV's backing table consistent with a source row-write. A tagged union over
|
|
77
|
+
* the maintenance strategies the incremental substrate names (the spike's
|
|
78
|
+
* `incremental-maintenance-substrate-spike` design). The builder
|
|
79
|
+
* ({@link MaterializedViewManager.buildMaintenancePlan}) produces four bounded-delta arms:
|
|
80
|
+
* `'inverse-projection'` (the covering-index shape), `'residual-recompute'` (single-source
|
|
81
|
+
* aggregates), `'prefix-delete'` (single-source lateral-TVF fan-out), and `'join-residual'`
|
|
82
|
+
* (the provably-1:1 inner join) — each applied **per source row, immediately**. The
|
|
83
|
+
* `'full-rebuild'` floor (the always-correct convergence point for bodies no bounded-delta
|
|
84
|
+
* arm fits) is the fall-through the builder routes to whenever no bounded-delta arm matches;
|
|
85
|
+
* it is the one **deferred** arm — marked dirty per row and rebuilt once per statement at
|
|
86
|
+
* {@link MaterializedViewManager.flushDeferredRebuilds}.
|
|
87
|
+
*/
|
|
88
|
+
export type MaintenancePlan = InverseProjectionPlan | FullRebuildPlan | ResidualRecomputePlan | PrefixDeletePlan | JoinResidualPlan;
|
|
89
|
+
/**
|
|
90
|
+
* Structural subset of the fields the forward (driving-source) residual-recompute
|
|
91
|
+
* apply path reads — shared by the aggregate {@link ResidualRecomputePlan} and the
|
|
92
|
+
* 1:1-join {@link JoinResidualPlan} so both drive {@link MaterializedViewManager.applyForwardResidual}
|
|
93
|
+
* unchanged. For an aggregate the forward key is the group key (`'gk'`); for a join
|
|
94
|
+
* it is the driving table `T`'s PK (`'pk'`).
|
|
95
|
+
*/
|
|
96
|
+
interface ForwardResidualPlan {
|
|
97
|
+
mv: MaintainedTableSchema;
|
|
98
|
+
backingSchema: string;
|
|
99
|
+
backingTableName: string;
|
|
100
|
+
/** Cached scheduler for the key-filtered residual (the body with `injectKeyFilter`
|
|
101
|
+
* applied on the driving source). Re-run per affected key, bound through the live txn. */
|
|
102
|
+
residualScheduler: Scheduler;
|
|
103
|
+
bindParamPrefix: 'gk' | 'pk';
|
|
104
|
+
/** Source-column indices of the forward binding key (group columns / `T`'s PK columns). */
|
|
105
|
+
bindColumns: number[];
|
|
106
|
+
backingPkDefinition: ReadonlyArray<{
|
|
107
|
+
index: number;
|
|
108
|
+
desc?: boolean;
|
|
109
|
+
collation?: string;
|
|
110
|
+
}>;
|
|
111
|
+
backingPkSourceCols: number[];
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* The shipped covering-index maintenance arm (the former `RowTimeMaintenancePlan`,
|
|
115
|
+
* verbatim). Per source row-write the backing delta is a pure projection of the
|
|
116
|
+
* changed row: project the source row to a backing row (a per-column projector —
|
|
117
|
+
* passthrough columns *and* deterministic scalar expressions over the source row),
|
|
118
|
+
* key it by the backing physical PK, and (if the partial predicate admits it) delete
|
|
119
|
+
* the old image / upsert the new image. No body re-execution, no scan — see
|
|
120
|
+
* `docs/materialized-views.md` § Row-time refresh.
|
|
121
|
+
*/
|
|
122
|
+
/**
|
|
123
|
+
* How a single backing output column is derived from the changed source row — a pure
|
|
124
|
+
* per-row (per-statement) function. `'passthrough'` copies a source column (the column
|
|
125
|
+
* permutation that *every* PK / UNIQUE-covered column must use, so the backing key and
|
|
126
|
+
* the inverse-projection conflict map are recoverable); `'expr'` evaluates a
|
|
127
|
+
* deterministic scalar expression over the source row (a non-key derived column —
|
|
128
|
+
* `materialized-view-rowtime-expression-projections`). `eval` is the runtime-compiled
|
|
129
|
+
* evaluator (see {@link compileSourceRowEvaluator}), so a computed backing value is
|
|
130
|
+
* exactly what `select <body>` would produce.
|
|
131
|
+
*/
|
|
132
|
+
export type BackingProjector = {
|
|
133
|
+
readonly kind: 'passthrough';
|
|
134
|
+
readonly sourceCol: number;
|
|
135
|
+
} | {
|
|
136
|
+
readonly kind: 'expr';
|
|
137
|
+
readonly eval: (sourceRow: Row) => SqlValue;
|
|
138
|
+
};
|
|
139
|
+
/**
|
|
140
|
+
* One **weakened** column of a coarsened backing key K′, precomputed once at
|
|
141
|
+
* registration for the row-time collision telemetry
|
|
142
|
+
* ({@link MaterializedViewManager.detectAndReportCoarseningCollisions}). Carries the
|
|
143
|
+
* backing column index to read from each {@link BackingRowChange} image, the
|
|
144
|
+
* **source** (pre-coarsening, stricter) collation the divergence test compares
|
|
145
|
+
* under, the **output** (coarsened) collation the backing key enforces, and the
|
|
146
|
+
* column name for the {@link MaintenanceCollisionEvent} payload. Derived from
|
|
147
|
+
* `mv.derivation.coarsenedKey.weakened` (column names) via `mv.columnIndexMap`.
|
|
148
|
+
*/
|
|
149
|
+
interface CoarseningWatchColumn {
|
|
150
|
+
/** Backing column index (= body output column index) the weakened K′ column lands at. */
|
|
151
|
+
readonly index: number;
|
|
152
|
+
/** Source key enforcement collation (pre-coarsening); the divergence test compares under it. */
|
|
153
|
+
readonly sourceCollation: string;
|
|
154
|
+
/** Output (coarsened) collation the backing key enforces. */
|
|
155
|
+
readonly outputCollation: string;
|
|
156
|
+
/** Backing/output column name (for the event payload's `weakenedColumns`). */
|
|
157
|
+
readonly column: string;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Common identity + cost-gate fields shared by every {@link MaintenancePlan} arm.
|
|
161
|
+
* `chosenStrategy` / `sourceStats` are set once by the create-time cost gate
|
|
162
|
+
* ({@link MaterializedViewManager.buildMaintenancePlan}, via `selectMaintenanceStrategy`)
|
|
163
|
+
* and are not re-evaluated per write, except for the residual → rebuild demotion
|
|
164
|
+
* (`shouldDegradeToRebuild`; dormant until the residual arm is reachable).
|
|
165
|
+
*/
|
|
166
|
+
interface MaintenancePlanCommon {
|
|
167
|
+
/** The MV this plan maintains. */
|
|
168
|
+
mv: MaintainedTableSchema;
|
|
169
|
+
/** Lowercased `schema.table` of the single source `T`. */
|
|
170
|
+
sourceBase: string;
|
|
171
|
+
backingSchema: string;
|
|
172
|
+
backingTableName: string;
|
|
173
|
+
/** Strategy the cost gate chose: argmin `maintenanceCost` over the body's sound strategies. */
|
|
174
|
+
chosenStrategy: MaintenanceStrategy;
|
|
175
|
+
/** Create-time cost inputs (StatsProvider + forward optimizer), retained so the DML
|
|
176
|
+
* boundary can re-cost residual vs. rebuild against the actual changeCardinality. */
|
|
177
|
+
sourceStats: MaintenanceSourceStats;
|
|
178
|
+
/** Compiled declared-CHECK/FK validator over derived row images — present ONLY
|
|
179
|
+
* when the maintained table declares ≥1 applicable CHECK or ≥1 FK (the
|
|
180
|
+
* zero-overhead gate: MV-sugar backings and constraint-less maintained tables
|
|
181
|
+
* carry `undefined` and pay nothing per write). Built once at registration
|
|
182
|
+
* ({@link MaterializedViewManager.registerMaterializedView}); applied to each
|
|
183
|
+
* insert/update {@link BackingRowChange} before the cascade. */
|
|
184
|
+
derivedRowValidator?: DerivedRowConstraintValidator;
|
|
185
|
+
/** Precomputed weakened-K′-column watch list for row-time collision telemetry —
|
|
186
|
+
* present ONLY when `mv.derivation.coarsenedKey` is stamped (the zero-overhead
|
|
187
|
+
* gate: a provable-key / refining-lineage-key MV carries `undefined` and pays
|
|
188
|
+
* nothing per write — detection short-circuits on this field). Built once at
|
|
189
|
+
* registration ({@link MaterializedViewManager.registerMaterializedView} →
|
|
190
|
+
* {@link MaterializedViewManager.buildCoarseningWatch}); read by
|
|
191
|
+
* {@link MaterializedViewManager.detectAndReportCoarseningCollisions} from both
|
|
192
|
+
* the bounded-delta and full-rebuild maintenance arms. */
|
|
193
|
+
coarseningWatch?: ReadonlyArray<CoarseningWatchColumn>;
|
|
194
|
+
}
|
|
195
|
+
export interface InverseProjectionPlan extends MaintenancePlanCommon {
|
|
196
|
+
readonly kind: 'inverse-projection';
|
|
197
|
+
/** Backing-table physical primary-key definition (the column order the btree keys on). */
|
|
198
|
+
backingPkDefinition: ReadonlyArray<{
|
|
199
|
+
index: number;
|
|
200
|
+
desc?: boolean;
|
|
201
|
+
collation?: string;
|
|
202
|
+
}>;
|
|
203
|
+
/** `projectors[j]` derives backing output column `j` from the changed source row —
|
|
204
|
+
* either a passthrough copy of a source column or a deterministic scalar expression
|
|
205
|
+
* over the source row. Every PK / backing-key column is `'passthrough'` (eligibility
|
|
206
|
+
* rejects a computed column that lands in the backing key); non-key columns may be
|
|
207
|
+
* `'expr'`. {@link MaterializedViewManager.lookupCoveringConflicts} reads only the
|
|
208
|
+
* passthrough projectors for its inverse (source↔backing) map. */
|
|
209
|
+
projectors: BackingProjector[];
|
|
210
|
+
/** Partial-WHERE predicate evaluated on a single source row; absent ⇒ every row
|
|
211
|
+
* is in scope. A source row contributes a backing row only when this is
|
|
212
|
+
* unambiguously TRUE (mirrors partial-UNIQUE / partial-index semantics). */
|
|
213
|
+
predicate?: CompiledPredicate;
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* The always-correct **floor**: a body for which no bounded-delta arm is sound is
|
|
217
|
+
* maintained by re-evaluating it in full per writing statement and replacing the backing
|
|
218
|
+
* transactionally (a single `'replace-all'` {@link MaintenanceOp} — a keyed diff against
|
|
219
|
+
* the backing's pending layer, so the delta still commits/rolls-back with the source
|
|
220
|
+
* write and still drives the MV-over-MV cascade). The whole optimized body is compiled
|
|
221
|
+
* once at registration into {@link bodyScheduler}; {@link MaterializedViewManager.applyFullRebuild}
|
|
222
|
+
* runs it to completion against live source state and diffs the result into the backing.
|
|
223
|
+
*
|
|
224
|
+
* Reachability: `buildMaintenancePlan` routes a body here whenever no bounded-delta arm
|
|
225
|
+
* fits ({@link MaterializedViewManager.tryBuildBoundedDeltaArm} returns `null`). It is the
|
|
226
|
+
* one **deferred** arm — marked dirty per source row and rebuilt exactly once at the
|
|
227
|
+
* end-of-statement flush ({@link MaterializedViewManager.flushDeferredRebuilds}), so a bulk
|
|
228
|
+
* write is O(body) not O(rows × body). See `docs/materialized-views.md` § Full-rebuild floor.
|
|
229
|
+
*/
|
|
230
|
+
export interface FullRebuildPlan extends MaintenancePlanCommon {
|
|
231
|
+
readonly kind: 'full-rebuild';
|
|
232
|
+
/** The optimized body compiled once at registration — the **whole** body (no
|
|
233
|
+
* `injectKeyFilter`), with the read-side MV rewrite suppressed so it reads its sources,
|
|
234
|
+
* not the backing it populates. Re-run to completion per writing statement, bound
|
|
235
|
+
* through the live transaction (reads-own-writes), to recompute every backing row. */
|
|
236
|
+
bodyScheduler: Scheduler;
|
|
237
|
+
/** Every source base (lowercased `schema.table`) the body reads — set-op legs, every
|
|
238
|
+
* join source, etc. The plan is indexed under each in `rowTimeBySource` (via
|
|
239
|
+
* {@link planSourceBases}), so a write to **any** of them triggers a rebuild; missing
|
|
240
|
+
* one would leave the MV stale on that source's writes. `sourceBase` (the
|
|
241
|
+
* {@link MaintenancePlanCommon} field) holds the first of these for parity. */
|
|
242
|
+
sourceBases: string[];
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* The general-body residual-recompute arm: per source change, derive the affected
|
|
246
|
+
* binding key(s) from the changed row, run a key-filtered residual of the body against
|
|
247
|
+
* **live mid-transaction source state**, and apply the keyed diff — upsert the recomputed
|
|
248
|
+
* slice (replacing the old row at the same backing key; a value-identical recompute is
|
|
249
|
+
* suppressed by the host, see vtab/backing-host.ts) or, when the residual returns
|
|
250
|
+
* nothing, delete the emptied key. Wired for the **single-source aggregate** shape
|
|
251
|
+
* (`select g1,… , agg(…) from T [where P] group by g1,…` over bare group columns) by
|
|
252
|
+
* `materialized-view-rowtime-residual-recompute`; the 1:1 row-preserving join shape
|
|
253
|
+
* (`'row'` binding) reuses the same kernel in a follow-on ticket.
|
|
254
|
+
*
|
|
255
|
+
* The residual is the body with a key-equality filter injected on `T`'s
|
|
256
|
+
* `TableReferenceNode` via {@link injectKeyFilter} (parameterized `gk0…` for a group
|
|
257
|
+
* binding, `pk0…` for a row binding), compiled + cached once at registration and run
|
|
258
|
+
* synchronously through the live transaction so the source read is reads-own-writes —
|
|
259
|
+
* the synchronous analogue of `database-assertions.ts`'s residual path.
|
|
260
|
+
*
|
|
261
|
+
* It carries the {@link BindingMode} the spike names as the convergence point (built
|
|
262
|
+
* directly from the body's shape — for an aggregate, the bare GROUP BY columns; NOT
|
|
263
|
+
* via `extractBindings`, whose `'group'` classification additionally requires the group
|
|
264
|
+
* key to cover a source unique key and so reports `'global'` for the common
|
|
265
|
+
* `group by <non-key>` body). `degradeToRebuild` is the cost gate's full-rebuild escape
|
|
266
|
+
* flag — dormant in v1 (the per-row recompute is correct without batching, and the
|
|
267
|
+
* full-rebuild arm is unwired).
|
|
268
|
+
*/
|
|
269
|
+
export interface ResidualRecomputePlan extends MaintenancePlanCommon {
|
|
270
|
+
readonly kind: 'residual-recompute';
|
|
271
|
+
binding: BindingMode;
|
|
272
|
+
degradeToRebuild: boolean;
|
|
273
|
+
/** Cached scheduler for the key-filtered residual (the body with `injectKeyFilter`
|
|
274
|
+
* applied on `T`). Re-run per affected key tuple, bound through the live transaction. */
|
|
275
|
+
residualScheduler: Scheduler;
|
|
276
|
+
/** Bind-parameter prefix the residual was compiled with: `'gk'` (group) / `'pk'` (row). */
|
|
277
|
+
bindParamPrefix: 'gk' | 'pk';
|
|
278
|
+
/** Source-column indices of the binding key (group columns / row key columns). The
|
|
279
|
+
* affected key tuple is `bindColumns.map(c => changedRow[c])`, bound to `${prefix}{i}`. */
|
|
280
|
+
bindColumns: number[];
|
|
281
|
+
/** Backing-table physical primary-key definition (the column order the btree keys on). */
|
|
282
|
+
backingPkDefinition: ReadonlyArray<{
|
|
283
|
+
index: number;
|
|
284
|
+
desc?: boolean;
|
|
285
|
+
collation?: string;
|
|
286
|
+
}>;
|
|
287
|
+
/** Source column projected (passthrough) into each backing-PK column, in
|
|
288
|
+
* `backingPkDefinition` order. The old backing slice's delete key for a changed row
|
|
289
|
+
* `R` is `buildPrimaryKeyFromValues(backingPkSourceCols.map(sc => R[sc]), backingPkDefinition)`. */
|
|
290
|
+
backingPkSourceCols: number[];
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* The single-source lateral-TVF fan-out arm: a body of the shape
|
|
294
|
+
* `select T.pk…, …, f.* from T cross join lateral tvf(<args over T>) f`, where each base
|
|
295
|
+
* row of `T` fans out to **N** backing rows (one per row the TVF emits for it). The
|
|
296
|
+
* backing PK is the **composite product key** `(T.pk ∪ tvf-key)` that
|
|
297
|
+
* `optimizer-keyed-cross-product-join-keys` advertises through `keysOf` over the lateral
|
|
298
|
+
* join, with the base PK as its **leading prefix** (asserted at build).
|
|
299
|
+
*
|
|
300
|
+
* Per changed base row, maintenance is a **keyed diff of the recomputed fan-out against
|
|
301
|
+
* the existing effective slice for the base-PK prefix** (read via the host's
|
|
302
|
+
* `scanEffective`, since one base row owns many backing rows sharing the prefix): re-run
|
|
303
|
+
* the TVF fan-out **residual** for that base row, delete only the existing keys the
|
|
304
|
+
* recompute no longer produces, and **upsert** each recomputed row (value-identical
|
|
305
|
+
* upserts are suppressed by the host). An UPDATE diffs both the OLD and NEW base keys
|
|
306
|
+
* (the base PK may move); a DELETE diffs the old slice to all-deletes; an INSERT diffs
|
|
307
|
+
* against an empty slice. This reuses the residual kernel of {@link ResidualRecomputePlan}
|
|
308
|
+
* unchanged — the affected-key derivation, the `injectKeyFilter` residual (pinned to the
|
|
309
|
+
* base `TableReferenceNode` with the `'pk'` prefix), reads-own-writes execution, the cost
|
|
310
|
+
* gate — and differs only in the **prefix-slice** diff (vs point-key) and the **N-row**
|
|
311
|
+
* residual (vs ≤1). The body's WHERE, if any, is part of the residual (so an out-of-scope
|
|
312
|
+
* base row fans out to zero rows), exactly as in the aggregate arm.
|
|
313
|
+
*
|
|
314
|
+
* `chosenStrategy` is `'residual-recompute'` (the shared key-filtered re-execution cost
|
|
315
|
+
* shape — the fan-out factor is unknown at create); `kind` is `'prefix-delete'` (the
|
|
316
|
+
* apply-arm dispatcher). `degradeToRebuild` is dormant (as in the aggregate arm).
|
|
317
|
+
*/
|
|
318
|
+
export interface PrefixDeletePlan extends MaintenancePlanCommon {
|
|
319
|
+
readonly kind: 'prefix-delete';
|
|
320
|
+
/** Substrate parity (the base-PK 'row' binding); unread by the apply path, which uses
|
|
321
|
+
* `bindColumns` / `backingPrefixSourceCols`. */
|
|
322
|
+
binding: BindingMode;
|
|
323
|
+
degradeToRebuild: boolean;
|
|
324
|
+
/** Cached scheduler for the base-PK-keyed residual (the body with `injectKeyFilter`
|
|
325
|
+
* applied on `T`, `'pk'` prefix). Re-run per affected base key; fans out to N rows. */
|
|
326
|
+
residualScheduler: Scheduler;
|
|
327
|
+
bindParamPrefix: 'pk';
|
|
328
|
+
/** Source-`T` PK column indices (the base key). The affected key tuple is
|
|
329
|
+
* `bindColumns.map(c => changedRow[c])`, bound to `pk{i}`. */
|
|
330
|
+
bindColumns: number[];
|
|
331
|
+
/** Full backing-table physical primary key (base-PK prefix ++ TVF-key tail). */
|
|
332
|
+
backingPkDefinition: ReadonlyArray<{
|
|
333
|
+
index: number;
|
|
334
|
+
desc?: boolean;
|
|
335
|
+
collation?: string;
|
|
336
|
+
}>;
|
|
337
|
+
/** Number of leading backing-PK columns that form the base-PK prefix (= `bindColumns.length`). */
|
|
338
|
+
basePrefixLength: number;
|
|
339
|
+
/** Source-`T` column projected into each leading (base-prefix) backing-PK column, in
|
|
340
|
+
* backing-PK order. The by-prefix delete key for a changed row `R` is
|
|
341
|
+
* `backingPrefixSourceCols.map(sc => R[sc])`. */
|
|
342
|
+
backingPrefixSourceCols: number[];
|
|
343
|
+
}
|
|
344
|
+
/**
|
|
345
|
+
* The 1:1 row-preserving **inner/cross join** arm: a body
|
|
346
|
+
* `select … from T join P on T.fk = P.id` where `T` contributes **exactly one** MV row
|
|
347
|
+
* per governed `T` row (proven by {@link proveOneToOneJoin} — no row loss via NOT-NULL
|
|
348
|
+
* FK→PK referential integrity, no fan-out via `isUnique(T.pk)` at the join frame). The
|
|
349
|
+
* backing is keyed on `T`'s PK (the composite product key `keysOf` advertises across the
|
|
350
|
+
* 1:1 join collapses to `T`'s PK), so each changed `T` row maps to one backing row.
|
|
351
|
+
*
|
|
352
|
+
* Reuses the residual kernel of {@link ResidualRecomputePlan} on its **driving (`T`)**
|
|
353
|
+
* side via {@link ForwardResidualPlan}: a `T`-keyed (`'pk'`) residual recomputes the one
|
|
354
|
+
* joined row for a changed `T` row (run residual → upsert the recomputed row, or delete
|
|
355
|
+
* the key when it returns nothing), identical to a `'row'`-binding aggregate of size 1.
|
|
356
|
+
* `applyForwardResidual` drives it.
|
|
357
|
+
*
|
|
358
|
+
* The **lookup (`P`)** side is the join arm's distinct problem: the MV's `sourceTables`
|
|
359
|
+
* includes `P`, so a write to `P` also fires maintenance, but the forward residual is
|
|
360
|
+
* keyed on `T`'s PK and a `P` row joins *many* `T` rows. This plan therefore carries a
|
|
361
|
+
* **second residual keyed on `P`'s PK** (`lookupResidualScheduler`): for a `P` change it
|
|
362
|
+
* runs `… where P.pk = :pk0` (the body **including** its WHERE) against live state,
|
|
363
|
+
* returning every currently in-scope joined row (each carrying its `T.pk` backing key), and
|
|
364
|
+
* **upserts** each.
|
|
365
|
+
*
|
|
366
|
+
* **WHERE handling — bounded-delta over a partial-WHERE 1:1 join.** A body WHERE is
|
|
367
|
+
* classified at build by which base table(s) its columns reference
|
|
368
|
+
* ({@link MaterializedViewManager.buildJoinResidualPlan}):
|
|
369
|
+
* - **`T`-only predicate** — no extra machinery. The forward (`T`) residual already injects
|
|
370
|
+
* + applies the WHERE (an out-of-scope `T` row recomputes to zero residual rows ⇒ its
|
|
371
|
+
* delete-without-upsert removes the backing row), and a `T`-column predicate cannot move
|
|
372
|
+
* the membership set `{ T : T.fk = P.pk }`, so the lookup side stays **upsert-only**
|
|
373
|
+
* (`lookupMembershipResidualScheduler` absent) — sound for the same reason the no-WHERE
|
|
374
|
+
* arm is.
|
|
375
|
+
* - **`P`-referencing predicate** (or both sides) — a `P` write can flip a row's WHERE truth
|
|
376
|
+
* and so add/remove a backing row, which upsert-only could never delete. The lookup side
|
|
377
|
+
* becomes **delete-capable**: `lookupMembershipResidualScheduler` is the body with
|
|
378
|
+
* `injectKeyFilter` on `P` but the WHERE **stripped** (membership only). Per affected `P`
|
|
379
|
+
* key {@link MaterializedViewManager.applyLookupResidual} diffs it against the in-scope
|
|
380
|
+
* `lookupResidualScheduler` (WHERE retained): membership keys the in-scope recompute no
|
|
381
|
+
* longer produces are deleted, the in-scope rows are upserted — a keyed diff that converges
|
|
382
|
+
* the membership both ways without churning the unchanged rows.
|
|
383
|
+
*
|
|
384
|
+
* Still inner/cross only; outer joins and **fanning** (non-1:1) joins continue to fall to the
|
|
385
|
+
* full-rebuild floor. See `docs/incremental-maintenance.md` § join-residual and the soundness
|
|
386
|
+
* note in {@link MaterializedViewManager.applyLookupResidual}.
|
|
387
|
+
*/
|
|
388
|
+
export interface JoinResidualPlan extends MaintenancePlanCommon, ForwardResidualPlan {
|
|
389
|
+
readonly kind: 'join-residual';
|
|
390
|
+
/** Substrate parity: the driving `T`'s `'row'`/PK binding. */
|
|
391
|
+
binding: BindingMode;
|
|
392
|
+
degradeToRebuild: boolean;
|
|
393
|
+
bindParamPrefix: 'pk';
|
|
394
|
+
/** Lowercased `schema.table` of the lookup source `P` (distinct from `sourceBase` = `T`). */
|
|
395
|
+
lookupBase: string;
|
|
396
|
+
/** Cached scheduler for the in-scope lookup-keyed residual (the body — WHERE **retained** —
|
|
397
|
+
* with `injectKeyFilter` applied on `P`, `'pk'` prefix). Re-run per affected `P` key;
|
|
398
|
+
* returns the currently in-scope joined rows to upsert. */
|
|
399
|
+
lookupResidualScheduler: Scheduler;
|
|
400
|
+
/** Delete-capable lookup membership residual (the body with the WHERE **stripped** and
|
|
401
|
+
* `injectKeyFilter` on `P`). Present **iff** the body WHERE references `P`: the lookup side
|
|
402
|
+
* must then delete the backing key of every currently-referencing `T` row (regardless of
|
|
403
|
+
* scope) before re-upserting the in-scope survivors, so a `P` write that flips a row's WHERE
|
|
404
|
+
* membership adds/removes its backing row. Absent for a no-WHERE or `T`-only-WHERE body
|
|
405
|
+
* (the lookup side is sound upsert-only — membership cannot move on a `P` write). */
|
|
406
|
+
lookupMembershipResidualScheduler?: Scheduler;
|
|
407
|
+
/** Source-`P` PK column indices (the lookup key). The affected key tuple for a `P`
|
|
408
|
+
* change is `lookupBindColumns.map(c => changedRow[c])`, bound to `pk{i}`. */
|
|
409
|
+
lookupBindColumns: number[];
|
|
410
|
+
lookupBindParamPrefix: 'pk';
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
413
|
+
* Per-statement cache of resolved backing {@link VirtualTableConnection}s, keyed by the
|
|
414
|
+
* lowercased backing `schema.table`. Created **once per DML generator run** (one
|
|
415
|
+
* statement) and threaded through the maintenance path so the backing-connection
|
|
416
|
+
* resolution — a scan over *all* the Database's active connections in
|
|
417
|
+
* {@link MaterializedViewManager.getBackingConnection} — is paid once per
|
|
418
|
+
* (statement, backing) instead of once per source row. This amortizes the dominant
|
|
419
|
+
* per-row overhead of a bulk `insert`/`update`/`delete` over a covered table.
|
|
420
|
+
*
|
|
421
|
+
* It is purely a resolution cache: each **bounded-delta** arm's per-row ops are still
|
|
422
|
+
* applied **immediately** to the cached connection's pending transaction layer, so a later
|
|
423
|
+
* same-statement row's enforcement scan (`lookupCoveringConflicts`) still observes every
|
|
424
|
+
* earlier row's backing write. The one exception is the **full-rebuild** arm, which the DML
|
|
425
|
+
* boundary defers to a single end-of-statement {@link MaterializedViewManager.flushDeferredRebuilds}
|
|
426
|
+
* (tracked in a separate per-statement dirty set, not this cache) — sound because a
|
|
427
|
+
* full-rebuild MV is never a covering structure, so no enforcement scan depends on its
|
|
428
|
+
* per-row visibility. See `docs/materialized-views.md` § Synchronous, transactional,
|
|
429
|
+
* per-statement. Because the cache is scoped to one generator run, the connection it holds
|
|
430
|
+
* cannot be torn down mid-statement; the cold enforcement/eviction paths that omit the cache
|
|
431
|
+
* re-resolve the *same* connection deterministically, so reads-own-writes is unaffected.
|
|
432
|
+
*/
|
|
433
|
+
export type BackingConnectionCache = Map<string, VirtualTableConnection>;
|
|
434
|
+
export declare class MaterializedViewManager {
|
|
435
|
+
private readonly ctx;
|
|
436
|
+
private unsubscribeSchemaChanges;
|
|
437
|
+
/** Compiled maintenance plans keyed by MV `schema.name` (lowercase). */
|
|
438
|
+
private readonly rowTime;
|
|
439
|
+
/** Source base (lowercased `schema.table`) → set of MV keys with a row-time plan
|
|
440
|
+
* reading it. The per-row DML maintenance hook looks plans up by source base. */
|
|
441
|
+
private readonly rowTimeBySource;
|
|
442
|
+
constructor(ctx: MaterializedViewManagerContext);
|
|
443
|
+
private subscribeToSchemaChanges;
|
|
444
|
+
/**
|
|
445
|
+
* Rebuild the derived-row constraint validator of every registered plan whose
|
|
446
|
+
* validator depends on `changed` (lowercased `schema.table`): it names `changed`
|
|
447
|
+
* in {@link DerivedRowConstraintValidator.dependencyTables} (FK parent /
|
|
448
|
+
* subquery-CHECK target), or — when `matchOwnName` — `changed` IS the maintained
|
|
449
|
+
* table itself (the rename signal; see {@link subscribeToSchemaChanges}).
|
|
450
|
+
*
|
|
451
|
+
* The derivation is unaffected by a constraint-only dependency's DDL, so this
|
|
452
|
+
* rebuilds the validator ONLY — no {@link releaseRowTime}, no staleness, no
|
|
453
|
+
* maintenance interruption. The rebuild reads the CURRENT catalog record
|
|
454
|
+
* (`getMaintainedTable`) so a rename re-resolves against the new name, and
|
|
455
|
+
* replacing the validator also refreshes its `dependencyTables` (a rename re-keys
|
|
456
|
+
* `{main.parent}` → `{main.parent2}`, so a later drop of `parent2` is caught too).
|
|
457
|
+
*
|
|
458
|
+
* Rebuild-failure handling: a rebuild THROWS when the subquery-CHECK target was
|
|
459
|
+
* dropped (`buildConstraintChecks` → optimize raises a sited "table not found").
|
|
460
|
+
* The throw is caught and a {@link makePoisonedDerivedRowValidator} installed, so
|
|
461
|
+
* (a) this listener never propagates an exception — a schema-change event must not
|
|
462
|
+
* fail the unrelated DDL that triggered it — and (b) the next derivation write
|
|
463
|
+
* surfaces the clear sited planning error instead of the stale validator's internal
|
|
464
|
+
* module-connect failure. The FK-parent-dropped case does NOT throw: the
|
|
465
|
+
* absent-parent null-guards-only fallback (`buildChildSideFKChecks`) builds cleanly,
|
|
466
|
+
* so the rebuilt validator is healthy (a non-NULL ref fails with the maintained-table
|
|
467
|
+
* FK attribution; a NULL ref is admitted under MATCH SIMPLE).
|
|
468
|
+
*/
|
|
469
|
+
private rebuildConstraintValidatorsFor;
|
|
470
|
+
/**
|
|
471
|
+
* Emit a synthetic `table_modified` event for `mv`'s backing table so any cached
|
|
472
|
+
* prepared-statement plan that reads the backing table directly invalidates →
|
|
473
|
+
* recompiles → re-hits the build-time `stale` guard in `building/select.ts`.
|
|
474
|
+
*
|
|
475
|
+
* A `select … from mv` compiled while the MV was NOT stale resolves to a
|
|
476
|
+
* `TableReference` against the maintained table itself, so its only schema
|
|
477
|
+
* dependency is that table. The *source* change event that marks the MV stale never
|
|
478
|
+
* names the maintained table, so without this emit the cached plan would re-run the
|
|
479
|
+
* scan and serve stale rows against a structurally-changed source — bypassing the
|
|
480
|
+
* guard a fresh prepare would hit. (A plan compiled while the MV is *already* stale
|
|
481
|
+
* is separately safe: the while-stale build-time re-validation resolves the body's
|
|
482
|
+
* source tables and records them as direct statement dependencies, so a later source
|
|
483
|
+
* change invalidates it without this emit — verified by the regression suite, which
|
|
484
|
+
* stays green even with the emit removed for that case.) The `Statement` listener
|
|
485
|
+
* maps `table_*` → `'table'` and matches on type + objectName (+ optional schemaName)
|
|
486
|
+
* only, ignoring the payload, so the maintained `TableSchema` is passed as both old/new.
|
|
487
|
+
*
|
|
488
|
+
* **Same-object payload contract (load-bearing coupling).** Passing the SAME object
|
|
489
|
+
* as `oldObject` and `newObject` is what keeps this synthetic event body-RELEVANT to
|
|
490
|
+
* `isBodyIrrelevantTableChange` (its reference-equality guard) — so it cascades
|
|
491
|
+
* staleness down an MV-over-MV chain instead of triggering the consumers'
|
|
492
|
+
* recompile-in-place path. Every genuine `table_modified` emitter passes distinct
|
|
493
|
+
* old/new objects. If this payload ever changes, change the classifier's guard with
|
|
494
|
+
* it (see the matching comment in runtime/emit/materialized-view-helpers.ts).
|
|
495
|
+
*
|
|
496
|
+
* Safety: the event names the maintained table itself, which is never in its OWN
|
|
497
|
+
* `sourceTables` (self-reference is rejected at create), so this manager's listener
|
|
498
|
+
* treats it as a no-op for a plain MV; for an MV-over-MV chain it conservatively
|
|
499
|
+
* cascades staleness down the producer→consumer DAG (acyclic — a consumer requires
|
|
500
|
+
* its producer to pre-exist), so the nested notification terminates. If the table
|
|
501
|
+
* lookup unexpectedly fails the MV is already in a broken state — skip the emit
|
|
502
|
+
* rather than fabricate a partial event.
|
|
503
|
+
*/
|
|
504
|
+
private emitBackingInvalidation;
|
|
505
|
+
/**
|
|
506
|
+
* Compile + register an MV for row-time write-through maintenance. Always
|
|
507
|
+
* builds the maintenance plan via {@link buildMaintenancePlan}, which throws on a
|
|
508
|
+
* body that is not row-time maintainable — the create emitter rolls the MV back on
|
|
509
|
+
* throw, so an ineligible body errors cleanly at create time.
|
|
510
|
+
*/
|
|
511
|
+
registerMaterializedView(mv: MaintainedTableSchema): void;
|
|
512
|
+
/** Detach an MV's row-time plan + its source-base index entry (DROP path). */
|
|
513
|
+
unregisterMaterializedView(schemaName: string, name: string): void;
|
|
514
|
+
/**
|
|
515
|
+
* Force-mark an MV stale: set the flag, detach its row-time plan, and invalidate
|
|
516
|
+
* cached prepared-statement plans reading its backing so the next reference
|
|
517
|
+
* re-hits the build-time stale guard. Mirrors the schema-change listener's stale
|
|
518
|
+
* transition exactly; exposed for the ALTER … RENAME propagation failure path
|
|
519
|
+
* (a dependent MV whose in-place body rewrite / backing rename / re-registration
|
|
520
|
+
* failed mid-way must not keep serving its backing as if live).
|
|
521
|
+
*/
|
|
522
|
+
markMaterializedViewStale(mv: MaintainedTableSchema): void;
|
|
523
|
+
dispose(): void;
|
|
524
|
+
/** Drop a row-time plan and its source-base index entry (DROP / schema-change / re-register). */
|
|
525
|
+
private releaseRowTime;
|
|
526
|
+
/**
|
|
527
|
+
* The source bases (lowercased `schema.table`) an MV's body reads — the
|
|
528
|
+
* dependency edges {@link Database.refreshAllMaterializedViews} orders the
|
|
529
|
+
* convergence sweep on. A registered (live) MV reports its compiled plan's
|
|
530
|
+
* bases ({@link planSourceBases} — the same set `rowTimeBySource` indexes it
|
|
531
|
+
* under). A **stale** MV has no live plan (a body-relevant source change
|
|
532
|
+
* released it), so its bases come from the recorded
|
|
533
|
+
* {@link import('../schema/derivation.js').TableDerivation.sourceTables} — the
|
|
534
|
+
* body's source-table set captured at (re)registration and kept current
|
|
535
|
+
* through every reshape. That recorded set is identical to what re-planning
|
|
536
|
+
* the body would derive (the create/refresh path fills it from the same
|
|
537
|
+
* analysis), but never re-plans a stale body that may no longer plan — so the
|
|
538
|
+
* ordering pass cannot throw a planning error before the per-MV refresh
|
|
539
|
+
* surfaces the real staleness diagnostic.
|
|
540
|
+
*/
|
|
541
|
+
sourceBasesFor(mv: MaintainedTableSchema): readonly string[];
|
|
542
|
+
/**
|
|
543
|
+
* All maintained tables in **source-dependency order**: a base MV precedes
|
|
544
|
+
* every MV whose body reads it (MV-over-MV — in the unified model a base MV's
|
|
545
|
+
* backing is a table under its own name, so a dependent's
|
|
546
|
+
* {@link sourceBasesFor} contains that qualified name). A sequential refresh
|
|
547
|
+
* sweep over this order is correct because refresh is commit-first per MV: a
|
|
548
|
+
* base MV's backing commits before a dependent's body re-reads it
|
|
549
|
+
* ({@link Database.refreshAllMaterializedViews}).
|
|
550
|
+
*
|
|
551
|
+
* Edges are `sourceBasesFor(mv)` intersected with the MV-key set (a non-MV
|
|
552
|
+
* source is no ordering constraint); Kahn's algorithm produces the order.
|
|
553
|
+
* Throws {@link StatusCode.INTERNAL} on a cycle — the create-time gates
|
|
554
|
+
* (`assertNoSelfReference` / `assertNoDerivationCycle`) reject recursive MVs,
|
|
555
|
+
* so a cycle here is an impossible-state backstop, never a silently dropped MV.
|
|
556
|
+
*/
|
|
557
|
+
materializedViewRefreshOrder(): MaintainedTableSchema[];
|
|
558
|
+
/**
|
|
559
|
+
* Precompute the weakened-K′-column watch list for row-time collision telemetry —
|
|
560
|
+
* one entry per coarsening column of the MV's coarsened backing key. Returns
|
|
561
|
+
* `undefined` (the zero-overhead gate) unless `mv.derivation.coarsenedKey` is
|
|
562
|
+
* stamped with ≥1 weakened column: a provable-key or refining-lineage-key MV builds
|
|
563
|
+
* no watch, so {@link detectAndReportCoarseningCollisions} short-circuits and the
|
|
564
|
+
* maintenance path is untouched. Each weakened column name resolves to its backing
|
|
565
|
+
* column index via `mv.columnIndexMap` (the maintained table IS the backing table),
|
|
566
|
+
* carrying the source → output collations the divergence test needs.
|
|
567
|
+
*/
|
|
568
|
+
private buildCoarseningWatch;
|
|
569
|
+
/**
|
|
570
|
+
* Observe-only row-time collision telemetry: scan the **realized**
|
|
571
|
+
* {@link BackingRowChange}s a maintenance apply produced and queue a
|
|
572
|
+
* {@link MaintenanceCollisionEvent} for each one that is a key-coarsening collision —
|
|
573
|
+
* an `update` whose replaced backing row came from a **distinct source identity**
|
|
574
|
+
* than the incoming row's, merged under the coarsened backing key K′ (last-writer-win).
|
|
575
|
+
*
|
|
576
|
+
* **Zero-overhead gate.** Returns immediately unless `plan.coarseningWatch` is present
|
|
577
|
+
* (only a coarsened-key MV builds one). A non-coarsened MV never scans `backingChanges`.
|
|
578
|
+
*
|
|
579
|
+
* **Criterion.** For each `'update'` change, a weakened K′ column is *diverged* when its
|
|
580
|
+
* old/new backing values differ under the **source** (pre-coarsening, stricter) collation.
|
|
581
|
+
* An `update` here means the incoming row landed on an existing backing row sharing K′
|
|
582
|
+
* under the **output** collation (that is what made the upsert replacing, not inserting);
|
|
583
|
+
* if those rows are equal under the source collation it is the same source row's value
|
|
584
|
+
* being updated (e.g. an `email` change — not reported), and if they differ under the
|
|
585
|
+
* source collation two distinct source identities (`'Bob'`/`'bob'`) collapsed onto one
|
|
586
|
+
* backing key (reported). `insert`/`delete` changes are never collisions (new key / removal).
|
|
587
|
+
*
|
|
588
|
+
* Runs **independently** of the cascade — it neither consumes nor reorders the
|
|
589
|
+
* `backingChanges` routed onward (observe-only), so an MV-over-MV chain is unperturbed.
|
|
590
|
+
* The queued event rides the emitter's transaction batching, so a collision inside a
|
|
591
|
+
* rolled-back transaction reports nothing and does not increment the counter.
|
|
592
|
+
*/
|
|
593
|
+
private detectAndReportCoarseningCollisions;
|
|
594
|
+
/**
|
|
595
|
+
* True iff a row-time covering structure reads `sourceBase` (lowercased
|
|
596
|
+
* `schema.table`). The DML write boundary consults this synchronously so the
|
|
597
|
+
* per-row maintenance hook is a zero-allocation no-op when nothing depends on
|
|
598
|
+
* the written table.
|
|
599
|
+
*/
|
|
600
|
+
hasRowTimePlanFor(sourceBase: string): boolean;
|
|
601
|
+
/**
|
|
602
|
+
* Synchronously maintain every row-time covering structure on `sourceBase` for
|
|
603
|
+
* one source row-write. Each plan computes the per-row backing delta (a pure
|
|
604
|
+
* projection of the changed row) and applies it to the backing table's pending
|
|
605
|
+
* transaction layer through the connection a `select` from the MV would use —
|
|
606
|
+
* so the write is visible mid-transaction and rides the coordinated commit.
|
|
607
|
+
*
|
|
608
|
+
* **MV-over-MV cascade.** A backing write is itself a row-write that every MV
|
|
609
|
+
* reading *that backing table* must see. When a plan's backing base has its own
|
|
610
|
+
* dependents (`rowTimeBySource[backingBase]` non-empty), each effective
|
|
611
|
+
* {@link BackingRowChange} the write produced is routed back through this method,
|
|
612
|
+
* recursively. The dependency graph is acyclic (a consumer MV requires its
|
|
613
|
+
* producer MV to already exist at create time), so this synchronous depth-first
|
|
614
|
+
* recursion is DAG-ordered — a producer's backing is fully written before its
|
|
615
|
+
* consumers run — and the whole chain commits/rolls-back atomically on the live
|
|
616
|
+
* transaction. The leaf fast path (`!rowTimeBySource.has(backingBase)`) keeps a
|
|
617
|
+
* non-chained MV at exactly today's cost (one map lookup, no recursion). `depth`
|
|
618
|
+
* feeds the structural-cycle backstop in {@link assertCascadeDepth}.
|
|
619
|
+
*
|
|
620
|
+
* `cache` is the optional per-statement {@link BackingConnectionCache}: when the
|
|
621
|
+
* DML boundary supplies one, every backing (this plan's and each cascade level's)
|
|
622
|
+
* resolves its connection at most once for the whole statement. The cascade threads
|
|
623
|
+
* the same cache through, so a multi-level chain amortizes each level's resolution
|
|
624
|
+
* too. Omitted by the cold enforcement/eviction callers, which re-resolve the same
|
|
625
|
+
* connection deterministically.
|
|
626
|
+
*
|
|
627
|
+
* `deferred` is the optional per-statement deferred-rebuild set (MV keys). A
|
|
628
|
+
* `'full-rebuild'` plan re-evaluates the WHOLE body, so applying it per source row is
|
|
629
|
+
* O(rows × body) — pathological. When the DML boundary supplies a `deferred` set, a
|
|
630
|
+
* full-rebuild plan is instead marked dirty here (no per-row apply) and rebuilt exactly
|
|
631
|
+
* once at the end-of-statement {@link flushDeferredRebuilds} boundary. The bounded-delta
|
|
632
|
+
* arms stay per-row-immediate (cheap, and the covering-UNIQUE enforcement scan depends on
|
|
633
|
+
* their per-row backing visibility; a full-rebuild MV is never a covering structure, so
|
|
634
|
+
* deferring it cannot starve that scan). A cold caller without a `deferred` set falls
|
|
635
|
+
* through to an inline rebuild — a safe, unamortized fallback that the
|
|
636
|
+
* enforcement/eviction callers never actually reach (they never name a full-rebuild MV).
|
|
637
|
+
*/
|
|
638
|
+
maintainRowTime(sourceBase: string, change: BackingRowChange, cache?: BackingConnectionCache, deferred?: Set<string>, depth?: number): Promise<void>;
|
|
639
|
+
/**
|
|
640
|
+
* Flush the per-statement deferred full-rebuild set at the end-of-statement boundary:
|
|
641
|
+
* rebuild every dirtied full-rebuild MV exactly once (not once per source row) and
|
|
642
|
+
* cascade each rebuild's effective {@link BackingRowChange}(s) onward so MV-over-MV
|
|
643
|
+
* consumers converge.
|
|
644
|
+
*
|
|
645
|
+
* Drained as a worklist over the producer→consumer DAG. Each rebuild calls
|
|
646
|
+
* {@link applyFullRebuild} (re-run the whole body against live mid-transaction source
|
|
647
|
+
* state → a `'replace-all'` diff) and routes the realized delta back through
|
|
648
|
+
* {@link maintainRowTime} with the SAME `deferred` set: an incremental consumer applies
|
|
649
|
+
* inline; a full-rebuild consumer re-dirties into the drain (rebuilt in a later round,
|
|
650
|
+
* after its producer's delta has landed). The drain proceeds in **rounds** — each round
|
|
651
|
+
* snapshots the current dirty set, clears it, and rebuilds each member, collecting the
|
|
652
|
+
* next round's re-dirties — so a consumer is never permanently stale (a producer rebuilt
|
|
653
|
+
* in the same round re-dirties it for the next), and convergence takes at most one round
|
|
654
|
+
* per level of the full-rebuild sub-DAG.
|
|
655
|
+
*
|
|
656
|
+
* Termination: the dependency DAG is acyclic (a consumer MV requires its producer to
|
|
657
|
+
* pre-exist), so the longest full-rebuild chain — hence the round count — is bounded by
|
|
658
|
+
* the registered-row-time-MV count. Exceeding it signals a structurally-impossible cycle
|
|
659
|
+
* and fails loud ({@link assertFlushRounds}) — the worklist analogue of
|
|
660
|
+
* {@link assertCascadeDepth}. This should never fire.
|
|
661
|
+
*
|
|
662
|
+
* The DML executor calls this INSIDE the statement-atomicity savepoint (after the row
|
|
663
|
+
* loop, before the savepoint release), so a failed rebuild rolls the whole statement
|
|
664
|
+
* back. An empty set is a no-op (no overhead on statements touching no full-rebuild MV).
|
|
665
|
+
*/
|
|
666
|
+
flushDeferredRebuilds(deferred: Set<string>, cache?: BackingConnectionCache): Promise<void>;
|
|
667
|
+
/**
|
|
668
|
+
* Round backstop for {@link flushDeferredRebuilds}. The full-rebuild sub-DAG is acyclic,
|
|
669
|
+
* so the drain converges in at most one round per chain level — bounded by the row-time
|
|
670
|
+
* MV count. A round count beyond that (`+1` slack for an initial dirty set already
|
|
671
|
+
* spanning multiple levels) signals a structural impossibility (a cycle) — fail loud
|
|
672
|
+
* rather than spin. This should never fire.
|
|
673
|
+
*/
|
|
674
|
+
private assertFlushRounds;
|
|
675
|
+
/**
|
|
676
|
+
* Defense-in-depth backstop for the cascade. Cycles are structurally impossible
|
|
677
|
+
* (a consumer MV can only be created once its producer exists, and an MV's source
|
|
678
|
+
* set is fixed at create), so a valid chain descends at most once per registered
|
|
679
|
+
* row-time MV. A depth beyond that count signals a structural impossibility (a
|
|
680
|
+
* cycle) — fail loud with `INTERNAL` naming the backing base rather than overflow
|
|
681
|
+
* the stack. This should never fire.
|
|
682
|
+
*/
|
|
683
|
+
private assertCascadeDepth;
|
|
684
|
+
/**
|
|
685
|
+
* Dispatch a maintenance plan on its `kind`, compute the per-row backing delta,
|
|
686
|
+
* apply it, and return the **effective** {@link BackingRowChange}(s) the backing
|
|
687
|
+
* layer realized (so the cascade can drive this plan's own dependents). The builder
|
|
688
|
+
* yields `'inverse-projection'` (covering-index shape), `'residual-recompute'`
|
|
689
|
+
* (single-source aggregate), `'prefix-delete'` (single-source lateral-TVF fan-out), and
|
|
690
|
+
* `'full-rebuild'` (the floor — re-evaluate the whole body and replace the backing). The
|
|
691
|
+
* floor ignores the specific `change` (it rebuilds wholesale); the others derive a
|
|
692
|
+
* bounded per-row delta from it.
|
|
693
|
+
*/
|
|
694
|
+
private applyMaintenancePlan;
|
|
695
|
+
/**
|
|
696
|
+
* Compute an `'inverse-projection'` plan's per-row backing delta, apply it, and
|
|
697
|
+
* return the **effective** {@link BackingRowChange}(s) the backing layer realized.
|
|
698
|
+
* An out-of-scope row (or a delete of an absent backing key) yields no change. This
|
|
699
|
+
* body is the shipped covering-index maintenance, lifted verbatim from the former
|
|
700
|
+
* `applyRowTimeChange`, plus the equal-image short-circuit: an UPDATE whose old and
|
|
701
|
+
* new projected images are value-identical (both in scope) projects to NO backing
|
|
702
|
+
* delta — the dominant no-op echo (a source update touching only unprojected columns,
|
|
703
|
+
* or rewriting a projected column to its existing value) is suppressed before any
|
|
704
|
+
* backing-connection work. Accurate by the maintenance invariant (the backing row IS
|
|
705
|
+
* the old image's projection), so nothing would have changed; the host's
|
|
706
|
+
* value-identical upsert skip (vtab/backing-host.ts) remains the effective-state
|
|
707
|
+
* backstop for the paths that do emit ops.
|
|
708
|
+
*/
|
|
709
|
+
private applyInverseProjection;
|
|
710
|
+
/**
|
|
711
|
+
* Validate the row images a maintenance apply WROTE (insert/update
|
|
712
|
+
* {@link BackingRowChange}s — a delete writes no image) against the plan's
|
|
713
|
+
* compiled {@link DerivedRowConstraintValidator}. Inline checks abort the
|
|
714
|
+
* writing statement with the maintained-table-attributed CONSTRAINT error;
|
|
715
|
+
* auto-deferred checks (subquery CHECK, every child-side FK) queue to the
|
|
716
|
+
* deferred-constraint queue and validate at commit. Deferred entries are
|
|
717
|
+
* pinned to the backing connection the maintenance write used (resolved from
|
|
718
|
+
* the per-statement cache, or re-resolved deterministically — the same
|
|
719
|
+
* connection either way) so commit-time evaluation reads the same pending
|
|
720
|
+
* state, mirroring the DML pipeline's active-connection capture.
|
|
721
|
+
*/
|
|
722
|
+
private validateDerivedChanges;
|
|
723
|
+
/**
|
|
724
|
+
* Fire **parent-side** referential enforcement over the backing rows a maintenance
|
|
725
|
+
* apply REMOVED or re-keyed (delete / key-update {@link BackingRowChange}s — an insert
|
|
726
|
+
* has no parent-side action). When the maintained table `M` is the PARENT (FK target)
|
|
727
|
+
* of an FK declared on an ordinary table `C` (`create table C (… references M(col) …)`),
|
|
728
|
+
* a maintenance-driven delete/key-update of the referenced `M` row would silently orphan
|
|
729
|
+
* `C`'s rows, bypassing the declared RESTRICT / referential action. This is the
|
|
730
|
+
* **dual** of {@link validateDerivedChanges} (constraints declared *on* `M`); the FK here
|
|
731
|
+
* lives on `C` and references `M`, so it is invisible to `M`'s own plan/validator.
|
|
732
|
+
*
|
|
733
|
+
* It reuses the SAME shared referential-action engine the DML executor and the
|
|
734
|
+
* external-change ingestion seam use — no third copy — applying its two functions over
|
|
735
|
+
* each backing change exactly as `database-external-changes.ts` does:
|
|
736
|
+
* - {@link assertTransitiveRestrictsForParentMutation} — pre-walk the transitive cascade
|
|
737
|
+
* closure and throw a CONSTRAINT error naming `M` on any surviving RESTRICT child;
|
|
738
|
+
* - {@link executeForeignKeyActionsAndLens} — run declared CASCADE / SET NULL / SET DEFAULT,
|
|
739
|
+
* re-entering the DML executor (the already-holding-the-mutex variant) for each cascaded
|
|
740
|
+
* child write, so `C`'s own constraints, watches, nested cascades, and (if `C` is itself
|
|
741
|
+
* an MV source) its own maintenance all fire.
|
|
742
|
+
*
|
|
743
|
+
* Ordering: called AFTER the backing delta has landed in the pending layer (the RESTRICT
|
|
744
|
+
* walk runs POST-application — the child rows it keys off still exist because the cascade
|
|
745
|
+
* has not run yet) and AFTER `M`'s own image is validated, matching the DML executor's
|
|
746
|
+
* per-change order (capture → MV maintenance → FK actions) and the external-changes seam.
|
|
747
|
+
* `lensRouted = false`: a maintenance backing write is a physical basis write (maintained
|
|
748
|
+
* tables are not lens basis spines). A surviving RESTRICT throws up through
|
|
749
|
+
* {@link maintainRowTime} → the DML executor → the statement, rolling back the source write
|
|
750
|
+
* attributed to `M`.
|
|
751
|
+
*
|
|
752
|
+
* Gate: a cheap `foreign_keys`-pragma early-return keeps the pragma-off path free (the
|
|
753
|
+
* engine also early-returns, but skipping the `getTable` + loop avoids all per-change work).
|
|
754
|
+
* NOT gated on `plan.derivedRowValidator` — that gate is child-side (constraints *on* `M`);
|
|
755
|
+
* an inbound FK lives on `C` and leaves `M`'s plan untouched. Beyond the gate it fires
|
|
756
|
+
* unconditionally per delete/update change, but the engine no longer pays an `O(catalog)`
|
|
757
|
+
* scan: both calls route through `SchemaManager.getReferencingForeignKeys`, the precomputed
|
|
758
|
+
* reverse-FK index, so an `M` that nothing references resolves to the shared empty bucket and
|
|
759
|
+
* each call early-returns in O(1) — a maintained table with no inbound FK (the common case)
|
|
760
|
+
* pays only the pragma check plus one map lookup per delete/key-update change.
|
|
761
|
+
*/
|
|
762
|
+
private enforceParentSideReferentialActions;
|
|
763
|
+
/**
|
|
764
|
+
* Resolve the {@link BackingHost} capability surface for a backing table —
|
|
765
|
+
* see `vtab/backing-host.ts` for the contract. The host is resolved fresh per
|
|
766
|
+
* use (a map lookup on the owning module), so a drop+recreate of the backing
|
|
767
|
+
* always yields the new incarnation's host.
|
|
768
|
+
*/
|
|
769
|
+
private backingHost;
|
|
770
|
+
/**
|
|
771
|
+
* Obtain (lazily create + register) the backing table's
|
|
772
|
+
* {@link VirtualTableConnection} for the current transaction. Reuses the same
|
|
773
|
+
* connection a `select` from the MV resolves to (so reads-own-writes holds) —
|
|
774
|
+
* matched among the Database's registered connections by
|
|
775
|
+
* {@link BackingHost.ownsConnection}, which is pinned to the live backing
|
|
776
|
+
* incarnation; a freshly created connection is registered with the Database so
|
|
777
|
+
* the coordinated commit/rollback covers its pending state in lockstep with the
|
|
778
|
+
* source write.
|
|
779
|
+
*
|
|
780
|
+
* When an optional per-statement {@link BackingConnectionCache} is supplied, the
|
|
781
|
+
* scan over the Database's active connections (the dominant per-row cost on a bulk
|
|
782
|
+
* write) is paid once per (statement, backing): a hit returns the cached connection
|
|
783
|
+
* directly, and a miss caches whichever connection the scan resolves — or the one it
|
|
784
|
+
* lazily creates + registers. Caching the resolved/created connection is sound
|
|
785
|
+
* because the scan is deterministic within a statement (nothing interleaves between
|
|
786
|
+
* a statement's rows to change which connection a `select` from the MV picks), so the
|
|
787
|
+
* cache holds exactly what an uncached re-resolution would return.
|
|
788
|
+
*/
|
|
789
|
+
private getBackingConnection;
|
|
790
|
+
/**
|
|
791
|
+
* Build the row-time maintenance plan for an MV — **cost-gated, with a floor, never a
|
|
792
|
+
* shape allowlist**. The builder tries to match a bounded-delta arm by shape
|
|
793
|
+
* ({@link tryBuildBoundedDeltaArm}); a body that matches **none** falls through to the
|
|
794
|
+
* always-correct {@link buildFullRebuildPlan} floor (re-evaluate the whole body, replace
|
|
795
|
+
* the backing transactionally). **No body is rejected for its shape.** Only four
|
|
796
|
+
* create-time rejections remain, all non-shape:
|
|
797
|
+
* - a **non-deterministic** body without `pragma nondeterministic_schema` — a hard reject
|
|
798
|
+
* in the matched arm (so the arm-specific determinism diagnostic survives) or, for a
|
|
799
|
+
* body matching no arm, in the floor's whole-body determinism check;
|
|
800
|
+
* - a **bag** (no provable unique key) — the floor's `keysOf` reject (a duplicate-producing
|
|
801
|
+
* body usually fails the set contract earlier, at create-fill);
|
|
802
|
+
* - a body with **no relational output**;
|
|
803
|
+
* - a **full-rebuild-only body over a source past the size threshold**
|
|
804
|
+
* ({@link isFullRebuildPathological}, the `materialized_view_rebuild_row_threshold` option).
|
|
805
|
+
*
|
|
806
|
+
* The single source may itself be another MV's backing table (an MV-over-MV body):
|
|
807
|
+
* `building/select.ts` rewrites a reference to `mv1` into a `TableReference` against
|
|
808
|
+
* `mv1`'s backing table, so the source base is `mv1`'s backing base and the same checks
|
|
809
|
+
* evaluate against the (keyed `memory`) backing schema unchanged. A write to `mv1` then
|
|
810
|
+
* drives `mv2` via the cascade in {@link maintainRowTime}.
|
|
811
|
+
*
|
|
812
|
+
* Eligibility is a *cost choice* among the body's structurally-sound strategies
|
|
813
|
+
* ({@link selectMaintenanceStrategy}): the bounded-delta arms are preferred by the argmin
|
|
814
|
+
* cost gate, and full-rebuild is selected exactly when no bounded-delta arm is sound (an
|
|
815
|
+
* empty sound set resolves to the floor) — so an existing eligible shape is unaffected.
|
|
816
|
+
*/
|
|
817
|
+
private buildMaintenancePlan;
|
|
818
|
+
/**
|
|
819
|
+
* Route the analyzed body to the matching bounded-delta arm, or return `null` when its
|
|
820
|
+
* shape fits **no** bounded-delta arm (the caller then builds the full-rebuild floor).
|
|
821
|
+
* Each arm builder likewise returns `null` on a sub-shape mismatch and falls through
|
|
822
|
+
* here. The arms keep only **determinism** as a hard reject (so their arm-specific
|
|
823
|
+
* determinism diagnostic survives — see the individual builders); every other mismatch
|
|
824
|
+
* is a `null` fall-through. Bag / no-output / size rejects live in the floor.
|
|
825
|
+
*/
|
|
826
|
+
private tryBuildBoundedDeltaArm;
|
|
827
|
+
/**
|
|
828
|
+
* Build an `'inverse-projection'` plan for the covering-index shape: a single
|
|
829
|
+
* row-preserving source `T` with a primary key, a linear
|
|
830
|
+
* `TableReference → optional Filter → Project → optional Sort` body, a projection that
|
|
831
|
+
* resolves every source PK column (and every backing-key column) to a **passthrough**
|
|
832
|
+
* source column — non-key columns may instead be a **deterministic scalar expression**
|
|
833
|
+
* over the source row — and a partial WHERE evaluable on a single source row. Returns
|
|
834
|
+
* `null` on any **shape** mismatch (the caller falls through to the full-rebuild floor);
|
|
835
|
+
* a **non-deterministic** computed column is the one hard reject (its arm-specific
|
|
836
|
+
* determinism diagnostic must survive rather than fall through to the floor's generic one).
|
|
837
|
+
*/
|
|
838
|
+
private buildInverseProjectionPlan;
|
|
839
|
+
/**
|
|
840
|
+
* Build a `'residual-recompute'` plan for a single-source aggregate body
|
|
841
|
+
* (`select g1,…, agg(…) from T [where P] group by g1,…` over **bare** group columns),
|
|
842
|
+
* or return `null` on a shape mismatch (the caller falls through to the full-rebuild
|
|
843
|
+
* floor). Each changed source row belongs to exactly one group `(g1,…)`; maintaining the
|
|
844
|
+
* MV means recomputing that group's backing row from live state — delete the old slice,
|
|
845
|
+
* run the group-keyed residual, upsert the recomputed slice (zero rows when the group
|
|
846
|
+
* emptied). See {@link ResidualRecomputePlan} and `docs/incremental-maintenance.md`
|
|
847
|
+
* § residual-recompute.
|
|
848
|
+
*
|
|
849
|
+
* A **non-deterministic** group/aggregate expression is the one hard reject (the
|
|
850
|
+
* arm-specific determinism diagnostic must survive); every other mismatch — a scalar
|
|
851
|
+
* aggregate, a computed group key, a backing key that is not the group key — returns
|
|
852
|
+
* `null` → the floor.
|
|
853
|
+
*
|
|
854
|
+
* NOTE: the group binding is derived **directly** from the aggregate node's bare GROUP
|
|
855
|
+
* BY columns, not via `extractBindings`. `analyzeRowSpecific`'s `'group'` classification
|
|
856
|
+
* additionally requires the group key to cover a *source* unique key (so it reports
|
|
857
|
+
* `'global'` for the common `group by <non-key>` body), which is the wrong test here —
|
|
858
|
+
* the backing is keyed by the group key regardless of whether it is a source key.
|
|
859
|
+
*/
|
|
860
|
+
private buildAggregateResidualPlan;
|
|
861
|
+
/**
|
|
862
|
+
* Build a `'join-residual'` plan for a provably-1:1 row-preserving **inner/cross join**
|
|
863
|
+
* body (`select … from T join P on T.fk = P.id`), or return `null` on a shape mismatch
|
|
864
|
+
* (the caller falls through to the full-rebuild floor). The driving table `T` is the one
|
|
865
|
+
* whose PK the optimizer surfaced as the backing key (the 1:1 join collapses the composite
|
|
866
|
+
* product key to `T`'s PK); the other base ref is the lookup `P`. See {@link JoinResidualPlan}
|
|
867
|
+
* and `docs/incremental-maintenance.md` § join-residual.
|
|
868
|
+
*
|
|
869
|
+
* Soundness gates (a mismatch on any returns `null` → floor): exactly two base tables; no
|
|
870
|
+
* aggregate over the join; the backing PK is exactly `T`'s PK projected as passthrough
|
|
871
|
+
* columns (so each changed `T` row maps to one backing row and the reverse residual's rows
|
|
872
|
+
* carry the backing key); the join is provably 1:1 on `T` ({@link proveOneToOneJoin} — no
|
|
873
|
+
* row loss via NOT-NULL FK→PK RI, no fan-out via the join-frame `isUnique(T.pk)`); and the
|
|
874
|
+
* join is **inner/cross** (an outer join would make the lookup-side reverse residual unsound
|
|
875
|
+
* — filtering `P` drops the null-extended rows). A **non-deterministic** projection is the
|
|
876
|
+
* one hard reject (its arm-specific determinism diagnostic must survive).
|
|
877
|
+
*
|
|
878
|
+
* **A body WHERE is now accepted** (it is no longer a blanket reject): the predicate is
|
|
879
|
+
* classified by which base table(s) its columns reference (reusing the per-base-ref
|
|
880
|
+
* attribute→source-column maps below). A `T`-only predicate needs nothing extra — the
|
|
881
|
+
* forward residual already carries it and the membership set `{ T : T.fk = P.pk }` cannot
|
|
882
|
+
* move on a `P` write, so the lookup side stays upsert-only. A predicate referencing `P` (or
|
|
883
|
+
* both sides) switches the lookup side to a **delete-capable** reverse residual by building
|
|
884
|
+
* `lookupMembershipResidualScheduler` (the body with the WHERE stripped, keyed on `P`). See
|
|
885
|
+
* {@link JoinResidualPlan}'s "WHERE handling" note and {@link applyLookupResidual}.
|
|
886
|
+
*/
|
|
887
|
+
private buildJoinResidualPlan;
|
|
888
|
+
/**
|
|
889
|
+
* Compile the **lookup membership** residual for the join-residual arm's delete-capable
|
|
890
|
+
* lookup side: the MV body with its top-level WHERE **stripped** (membership only) and a
|
|
891
|
+
* key-equality filter injected on the lookup `P`, keyed `pk0…`. The WHERE is stripped at the
|
|
892
|
+
* AST level (a shallow clone dropping `where`) and the body re-built + re-analyzed, so only
|
|
893
|
+
* the WHERE is removed — the join, its `ON` condition, and any projection sub-expressions are
|
|
894
|
+
* preserved. Re-analysis assigns fresh node ids, so `P`'s reference is re-located by base name
|
|
895
|
+
* to compute the injection target. Returns `null` if the lookup ref or the key-filter
|
|
896
|
+
* injection could not be resolved (the caller then falls to the full-rebuild floor).
|
|
897
|
+
*
|
|
898
|
+
* Run per affected `P` key, this residual returns **every** `T` row currently joined to `P`
|
|
899
|
+
* via the join's `ON` condition — irrespective of the WHERE — so {@link applyLookupResidual}
|
|
900
|
+
* can delete each one's `T.pk` backing key before the in-scope residual re-upserts the
|
|
901
|
+
* survivors (the membership set the WHERE-bearing reverse residual would otherwise never
|
|
902
|
+
* shrink).
|
|
903
|
+
*/
|
|
904
|
+
private compileLookupMembershipResidual;
|
|
905
|
+
/**
|
|
906
|
+
* Build a `'full-rebuild'` plan — the always-correct floor — for an MV whose body matches
|
|
907
|
+
* no bounded-delta arm, or throw with a non-shape diagnostic. This is the fall-through
|
|
908
|
+
* builder {@link tryBuildBoundedDeltaArm} routes to on a `null` (no bounded-delta arm fits).
|
|
909
|
+
* See {@link FullRebuildPlan} and `docs/materialized-views.md` § Full-rebuild floor /
|
|
910
|
+
* § Primary key inference.
|
|
911
|
+
*
|
|
912
|
+
* Create-time rejections (none shape-based — the floor accepts general bodies):
|
|
913
|
+
* - **bag** body with no provable unique key (`keysOf` over the optimized body root is
|
|
914
|
+
* empty) — there is no row identity to materialize on. `keysOf` already gates its
|
|
915
|
+
* all-columns fallback on `isSet`, so a non-empty result is a real key (a true column
|
|
916
|
+
* key OR the all-columns key of a provable set) and an empty result is exactly a bag.
|
|
917
|
+
* (A duplicate-producing body usually fails the set contract earlier, at create-fill.)
|
|
918
|
+
* - **non-deterministic** body (any `random()`/`now()`/volatile UDF anywhere in the plan)
|
|
919
|
+
* without `pragma nondeterministic_schema` — no maintenance could keep it equal to its
|
|
920
|
+
* plain view (mirrors the per-arm determinism rejects and the DDL determinism gate);
|
|
921
|
+
* - body with **no relational output** (degenerate);
|
|
922
|
+
* - **size**: full-rebuild is the only sound strategy *and* the **largest** participating
|
|
923
|
+
* source exceeds the `materialized_view_rebuild_row_threshold` option
|
|
924
|
+
* ({@link isFullRebuildPathological}) — every DML write would re-scan that source.
|
|
925
|
+
* `0` disables the size reject (accept any size).
|
|
926
|
+
*/
|
|
927
|
+
private buildFullRebuildPlan;
|
|
928
|
+
/**
|
|
929
|
+
* Compile the key-filtered residual for a binding into a reusable {@link Scheduler}:
|
|
930
|
+
* the analyzed body with a key-equality filter injected on `T`'s `TableReferenceNode`
|
|
931
|
+
* (parameterized `${paramPrefix}0…`), then optimized + emitted. Mirrors the assertion
|
|
932
|
+
* evaluator's residual compilation (`database-assertions.ts`) so the two cannot drift.
|
|
933
|
+
* Returns `null` if `injectKeyFilter` could not target `T` (the arm builder then falls
|
|
934
|
+
* through to the full-rebuild floor).
|
|
935
|
+
*/
|
|
936
|
+
private compileResidual;
|
|
937
|
+
/**
|
|
938
|
+
* Execute a cached key-filtered residual for one affected key tuple, returning its
|
|
939
|
+
* result rows (0 or 1 for the aggregate shape; 0..N for the lateral-TVF fan-out shape).
|
|
940
|
+
* Bound through a fresh {@link RuntimeContext} on the live `db` so the residual's source
|
|
941
|
+
* scan reuses `T`'s transaction connection and reads this statement's pending writes
|
|
942
|
+
* (reads-own-writes) — the synchronous analogue of
|
|
943
|
+
* `database-assertions.ts:executeResidualPerTuple`. Shared by the residual-recompute
|
|
944
|
+
* (`'gk'`) and prefix-delete (`'pk'`) arms.
|
|
945
|
+
*/
|
|
946
|
+
private runResidual;
|
|
947
|
+
/**
|
|
948
|
+
* Run a cached maintenance scheduler to completion against **live mid-transaction source
|
|
949
|
+
* state** and collect its result rows. Bound through a fresh strict {@link RuntimeContext}
|
|
950
|
+
* on the live `db` so the scan reuses the source's transaction connection and reads this
|
|
951
|
+
* statement's pending writes (reads-own-writes). The no-`stmt`, fresh-context shape is the
|
|
952
|
+
* synchronous analogue of `database-assertions.ts:executeResidualPerTuple`. Shared by the
|
|
953
|
+
* key-filtered residual arms ({@link runResidual}, parameterized) and the whole-body
|
|
954
|
+
* full-rebuild arm ({@link applyFullRebuild}, no params).
|
|
955
|
+
*/
|
|
956
|
+
private runScheduler;
|
|
957
|
+
/**
|
|
958
|
+
* Maintain a `'full-rebuild'` MV: re-evaluate the **whole** body against live
|
|
959
|
+
* mid-transaction source state and replace the backing transactionally. Run the cached
|
|
960
|
+
* {@link FullRebuildPlan.bodyScheduler} to completion (no params — reads-own-writes via
|
|
961
|
+
* the same fresh-context path the residual arms use), collect every recomputed row, and
|
|
962
|
+
* apply a single `'replace-all'` {@link MaintenanceOp}: a keyed diff (by backing PK) of
|
|
963
|
+
* the recomputed rows against the backing's current pending-layer contents (insert/
|
|
964
|
+
* update/delete, identical rows skipped). The diff rides the backing's **pending**
|
|
965
|
+
* `TransactionLayer`, so it commits/rolls-back in lockstep with the source write, and the
|
|
966
|
+
* returned effective {@link BackingRowChange}(s) drive the MV-over-MV cascade unchanged.
|
|
967
|
+
*
|
|
968
|
+
* Unlike the bounded-delta arms this ignores the specific changed row — the floor
|
|
969
|
+
* rebuilds wholesale. It is therefore deferred to a single end-of-statement flush
|
|
970
|
+
* ({@link flushDeferredRebuilds}) rather than run per source row, so a bulk statement
|
|
971
|
+
* rebuilds exactly once; this is that one rebuild. An empty body (zero rows) yields a
|
|
972
|
+
* `'replace-all' []`, which empties the backing.
|
|
973
|
+
*/
|
|
974
|
+
private applyFullRebuild;
|
|
975
|
+
/**
|
|
976
|
+
* Compute a **forward** key-filtered residual plan's per-row backing delta and apply it:
|
|
977
|
+
* derive the affected binding key(s) from the changed row (OLD ∪ NEW, deduped), re-run
|
|
978
|
+
* the key-filtered residual against live source state for each, and apply the **keyed
|
|
979
|
+
* diff**: a non-empty recomputed slice is upserted (the backing key IS the affected key,
|
|
980
|
+
* so the upsert replaces the old row wholesale — no delete-first — and the host's
|
|
981
|
+
* value-identical upsert skip turns a no-op recompute into ZERO effective changes
|
|
982
|
+
* instead of delete+insert churn); an emptied slice (residual returns nothing) emits the
|
|
983
|
+
* point delete, removing the stale backing row (nothing reported if it was already
|
|
984
|
+
* absent). Returns the effective {@link BackingRowChange}(s) the backing layer realized,
|
|
985
|
+
* for the MV-over-MV cascade — a real same-key change now reports one `update`.
|
|
986
|
+
*
|
|
987
|
+
* Shared by the single-source aggregate (`'residual-recompute'`, group key, ≤1 row per
|
|
988
|
+
* key) and the 1:1-join (`'join-residual'`, the driving table `T`'s PK, exactly the one
|
|
989
|
+
* joined row per key) arms — both bind on the forward driving source via
|
|
990
|
+
* {@link ForwardResidualPlan}; the only difference is the binding (group vs PK).
|
|
991
|
+
*
|
|
992
|
+
* Per-row recompute is correct without per-statement batching: every change to a key
|
|
993
|
+
* triggers a full recompute of that key's slice from live (reads-own-writes) state, so
|
|
994
|
+
* the last change to touch a key writes the authoritative backing row. Batching/dedup
|
|
995
|
+
* across a whole statement is an affordability optimization deferred with the
|
|
996
|
+
* statement-flush boundary (see the ticket handoff).
|
|
997
|
+
*/
|
|
998
|
+
private applyForwardResidual;
|
|
999
|
+
/**
|
|
1000
|
+
* True iff `row`'s backing primary-key columns equal `keyVals` (the affected binding
|
|
1001
|
+
* key, in `backingPkDefinition` order), under each column's collation. Used to keep
|
|
1002
|
+
* only the residual row(s) belonging to the recomputed key — see
|
|
1003
|
+
* {@link applyForwardResidual}.
|
|
1004
|
+
*/
|
|
1005
|
+
private residualRowMatchesKey;
|
|
1006
|
+
/**
|
|
1007
|
+
* Dispatch a `'join-residual'` plan on **which source changed**. A write to the driving
|
|
1008
|
+
* table `T` (`changedBase === plan.sourceBase`) is the forward case — recompute the one
|
|
1009
|
+
* joined row keyed on `T`'s PK, identical to a size-1 `'row'`-binding residual — so it
|
|
1010
|
+
* delegates straight to {@link applyForwardResidual} (delete old backing slice → run the
|
|
1011
|
+
* `T`-keyed residual → upsert). A write to the lookup table `P` is the reverse case,
|
|
1012
|
+
* handled by {@link applyLookupResidual}.
|
|
1013
|
+
*/
|
|
1014
|
+
private applyJoinResidual;
|
|
1015
|
+
/**
|
|
1016
|
+
* Maintain a `'join-residual'` MV for a **lookup-side (`P`)** change: refresh the joined
|
|
1017
|
+
* rows referencing each affected `P` key. Derive the affected `P` key(s) from the changed
|
|
1018
|
+
* row (OLD ∪ NEW, deduped on `P`'s PK), and for each run the in-scope lookup-keyed residual
|
|
1019
|
+
* (`… where P.pk = :pk0`, the body's WHERE retained) against live source state — returning
|
|
1020
|
+
* every currently in-scope joined row, each carrying its `T.pk` backing key — and **upsert**
|
|
1021
|
+
* each.
|
|
1022
|
+
*
|
|
1023
|
+
* **Upsert-only is sound for a no-WHERE / `T`-only-WHERE body.** For an inner/cross join with
|
|
1024
|
+
* enforced RI and a predicate that cannot reference `P`, the *set* of backing rows referencing
|
|
1025
|
+
* a given `P` row is `{ T : T.fk = P.pk }`, determined entirely by `T.fk` (a `T` column the
|
|
1026
|
+
* `P` write cannot change), and the WHERE — over `T` only — cannot flip on a `P` write. So a
|
|
1027
|
+
* `P` change can only re-derive the lookup-projected columns of those existing backing rows
|
|
1028
|
+
* (an upsert at the unchanged `T.pk` key), never add or remove one: a `P` insert with no
|
|
1029
|
+
* referencing `T` rows yields an empty residual (no-op); a `P` delete is only admissible (RI)
|
|
1030
|
+
* when no `T` references it (empty residual); a `P` payload update upserts the affected rows
|
|
1031
|
+
* with the new value.
|
|
1032
|
+
*
|
|
1033
|
+
* **A `P`-referencing WHERE needs the delete-capable pass.** When the body WHERE references
|
|
1034
|
+
* `P`, a `P` write can flip a joined row's WHERE truth and so add or remove its backing row —
|
|
1035
|
+
* which the in-scope upsert above (it returns *only* in-scope rows) could never delete. The
|
|
1036
|
+
* builder then supplies `lookupMembershipResidualScheduler` (the body with the WHERE stripped,
|
|
1037
|
+
* keyed on `P`). Per affected `P` key this runs both residuals against the same live state and
|
|
1038
|
+
* applies the **keyed diff**: it **deletes** only the membership keys the in-scope recompute no
|
|
1039
|
+
* longer produces (rows that left scope — the delete keys come from live `T` via the join, so
|
|
1040
|
+
* they match existing backing keys and touch nothing belonging to another `P`; membership and
|
|
1041
|
+
* in-scope rows read the same live state, so their key bytes match exactly), and **upserts**
|
|
1042
|
+
* every in-scope row. A row leaving scope is deleted (removed); a row entering scope is
|
|
1043
|
+
* upserted (added); an unchanged in-scope row's upsert is suppressed by the host's
|
|
1044
|
+
* value-identical skip (vtab/backing-host.ts) — ZERO effective changes instead of the former
|
|
1045
|
+
* delete+insert refresh churn; a changed in-scope row reports one `update`. The membership
|
|
1046
|
+
* residual MUST ignore the WHERE — else a row leaving scope would never be deleted.
|
|
1047
|
+
*
|
|
1048
|
+
* A `T`-side membership change (insert/delete/FK-move) is the *forward* path's job and fires
|
|
1049
|
+
* its own maintenance. Returns the effective {@link BackingRowChange}(s) for the MV-over-MV
|
|
1050
|
+
* cascade. Per-row recompute is correct without batching for the same
|
|
1051
|
+
* last-write-wins-against-live-state reason as {@link applyForwardResidual}.
|
|
1052
|
+
*/
|
|
1053
|
+
private applyLookupResidual;
|
|
1054
|
+
/**
|
|
1055
|
+
* Build a `'prefix-delete'` plan for a single-source lateral-TVF fan-out body
|
|
1056
|
+
* (`select T.pk…, …, f.* from T cross join lateral tvf(<args over T>) f`), or return
|
|
1057
|
+
* `null` on a shape mismatch (the caller falls through to the full-rebuild floor). The
|
|
1058
|
+
* backing PK is the composite product key `(T.pk ∪ tvf-key)` that `keysOf` advertises
|
|
1059
|
+
* through the lateral join; the base PK is its leading prefix. See {@link PrefixDeletePlan}
|
|
1060
|
+
* and `docs/incremental-maintenance.md` § prefix-delete.
|
|
1061
|
+
*
|
|
1062
|
+
* Soundness gates (a mismatch on any returns `null` → floor): exactly one lateral TVF and
|
|
1063
|
+
* one join (no nested/multi TVF, no aggregate over the fan-out); the TVF advertises a
|
|
1064
|
+
* per-call key; the base PK projected and forming the **leading prefix** of the backing PK
|
|
1065
|
+
* with a non-empty TVF-key tail (so each base row's fan-out rows are individually
|
|
1066
|
+
* addressable and a by-prefix delete selects exactly one base row's slice). An `order by`
|
|
1067
|
+
* over the fan-out that reorders the composite key so the base PK no longer leads is a
|
|
1068
|
+
* `null` fall-through (the floor maintains it wholesale). The body's WHERE, if any, is part
|
|
1069
|
+
* of the residual (so an out-of-scope base row fans out to zero rows), exactly as in the
|
|
1070
|
+
* aggregate arm. A **non-deterministic** TVF / argument is the one hard reject (its
|
|
1071
|
+
* arm-specific determinism diagnostic must survive).
|
|
1072
|
+
*/
|
|
1073
|
+
private buildLateralTvfPrefixDeletePlan;
|
|
1074
|
+
/**
|
|
1075
|
+
* Compute a `'prefix-delete'` plan's per-row backing delta and apply it: derive the
|
|
1076
|
+
* affected base key(s) from the changed row (OLD ∪ NEW, deduped on the base key), and
|
|
1077
|
+
* for each — re-run the base-PK-keyed residual against live source state and apply the
|
|
1078
|
+
* **keyed diff against the existing effective fan-out slice** (read via the host's
|
|
1079
|
+
* `scanEffective` with the base prefix, pending over committed — the same contiguous
|
|
1080
|
+
* range the former wholesale `'delete-by-prefix'` removed): delete ONLY the existing
|
|
1081
|
+
* keys the recompute no longer produces, upsert every recomputed row (the host's
|
|
1082
|
+
* value-identical skip suppresses the unchanged ones). A base-PK-changing UPDATE
|
|
1083
|
+
* recomputes both the OLD base key (slice diffs to all-deletes; the residual returns
|
|
1084
|
+
* nothing for the now-absent old PK) and the NEW base key (new fan-out upserted); a
|
|
1085
|
+
* DELETE diffs the old slice to all-deletes; an INSERT diffs against an empty slice
|
|
1086
|
+
* (all upserts). An emptied/shrunk fan-out keeps the delete-without-upsert exactly —
|
|
1087
|
+
* a disappearance is never "skipped". Returns the effective
|
|
1088
|
+
* {@link BackingRowChange}(s) the backing layer realized, for the MV-over-MV cascade.
|
|
1089
|
+
*
|
|
1090
|
+
* Prefix-scan soundness is unchanged from the wholesale arm: the diff's slice read
|
|
1091
|
+
* uses the same binary `equalityPrefix` scan `'delete-by-prefix'` used, sound under
|
|
1092
|
+
* the build-time collation gate (the backing base-PK prefix inherits the source PK
|
|
1093
|
+
* collation, and source-PK uniqueness collapses each collation class to one binary
|
|
1094
|
+
* value). The stored slice's prefix bytes always equal the OLD image's (the slice was
|
|
1095
|
+
* projected from that very source row), and OLD ∪ NEW both iterate, so a case-only
|
|
1096
|
+
* base-PK rewrite still converges: the OLD-prefix pass pairs the slice with the
|
|
1097
|
+
* recomputed rows (key pairing is collation-aware — the btree's identity — so a
|
|
1098
|
+
* collation-equal key is REPLACED by its upsert, never also deleted) and the byte
|
|
1099
|
+
* change surfaces as `update`s that re-key the stored bytes.
|
|
1100
|
+
*
|
|
1101
|
+
* Structurally the same as {@link applyForwardResidual}, differing only in the
|
|
1102
|
+
* **prefix-slice** diff (one base row owns N backing rows sharing the prefix) and the
|
|
1103
|
+
* **N-row** residual. Per-row recompute is correct without per-statement batching: the
|
|
1104
|
+
* residual reads live (reads-own-writes) state, so the last write to a base key produces
|
|
1105
|
+
* the authoritative slice. (Statement-level dedup of distinct base keys is the same
|
|
1106
|
+
* affordability optimization deferred for the aggregate arm.)
|
|
1107
|
+
*/
|
|
1108
|
+
private applyPrefixDelete;
|
|
1109
|
+
/**
|
|
1110
|
+
* True iff two backing rows agree on every backing-PK column under that column's
|
|
1111
|
+
* collation — the btree's key identity. Pairs an existing slice row with the
|
|
1112
|
+
* recomputed row that replaces it in {@link applyPrefixDelete}'s keyed diff.
|
|
1113
|
+
*/
|
|
1114
|
+
private backingPkEqual;
|
|
1115
|
+
/**
|
|
1116
|
+
* True iff `row`'s **leading** (base-prefix) backing-PK columns equal `prefixVals` (the
|
|
1117
|
+
* affected base key, in backing-PK order), under each column's collation. Keeps only the
|
|
1118
|
+
* residual fan-out row(s) belonging to the recomputed base key — see
|
|
1119
|
+
* {@link applyPrefixDelete}.
|
|
1120
|
+
*/
|
|
1121
|
+
private residualRowMatchesBasePrefix;
|
|
1122
|
+
/**
|
|
1123
|
+
* Assemble {@link MaintenanceSourceStats} for the cost gate from the optimizer's
|
|
1124
|
+
* StatsProvider and tuning. `tableRows` / `distinctGroupsEstimate` come from the
|
|
1125
|
+
* provider (heuristic defaults when absent); `forwardBodyCost` is estimated from the
|
|
1126
|
+
* forward cost helpers (a scan + optional filter + projection of the source — the
|
|
1127
|
+
* covering-index body shape); `fallbackRatio` carries the detection kernel's
|
|
1128
|
+
* `deltaPerRowFallbackRatio` for the no-stats residual path.
|
|
1129
|
+
*/
|
|
1130
|
+
/**
|
|
1131
|
+
* The CURRENT `TableSchema` of a source `TableReferenceNode`, re-resolved through the
|
|
1132
|
+
* schema manager. A plan node captures the schema as of plan-build; a later `analyze`
|
|
1133
|
+
* replaces the catalog entry with one carrying fresh `statistics`, so the stale captured
|
|
1134
|
+
* schema would report pre-`analyze` row counts. Re-resolving keeps the floor's size gate
|
|
1135
|
+
* on the live source size. Falls back to the node's captured schema if the name no longer
|
|
1136
|
+
* resolves (it always should — the body planned).
|
|
1137
|
+
*/
|
|
1138
|
+
private liveSourceSchema;
|
|
1139
|
+
private estimateMaintenanceStats;
|
|
1140
|
+
/**
|
|
1141
|
+
* Resolve the linked, enforcement-ready covering MV for a UNIQUE constraint on
|
|
1142
|
+
* `schema.table`, or `undefined`. The constraint's `coveringStructureName`
|
|
1143
|
+
* forward pointer (set by the eager prove-and-link) is the source of truth;
|
|
1144
|
+
* this confirms a live row-time plan exists for the source, the MV is not
|
|
1145
|
+
* `stale` (structural breakage), and the plan is **per-row maintained** — only
|
|
1146
|
+
* then is its backing table row-time consistent enough to answer conflict
|
|
1147
|
+
* resolution. A `'full-rebuild'` plan is deferred to the end-of-statement flush
|
|
1148
|
+
* (its backing lags the source mid-statement), so it can never serve as a
|
|
1149
|
+
* covering structure for a synchronous per-row UNIQUE probe — it is skipped here
|
|
1150
|
+
* regardless of any (informational) `coveringStructureName` link, which keeps the
|
|
1151
|
+
* eligibility flip from opening a stale-read enforcement path. O(1) negative fast
|
|
1152
|
+
* path off {@link rowTimeBySource} so a source table with no row-time covering MV
|
|
1153
|
+
* pays a single map lookup and stays on the synchronous index/scan path.
|
|
1154
|
+
*
|
|
1155
|
+
* **Collation eligibility gate.** A covering MV generates its conflict candidates
|
|
1156
|
+
* by re-comparing each backing row under the SOURCE column's DECLARED collation
|
|
1157
|
+
* ({@link lookupCoveringConflicts} / {@link tryBuildCoveringPrefix}), while the
|
|
1158
|
+
* re-validators (store `findUniqueConflictViaCoveringMv`, memory
|
|
1159
|
+
* `checkUniqueViaMaterializedView`) filter under the index per-column collation. The
|
|
1160
|
+
* candidate set is a sound *superset* of the index-collation matches — safe to filter
|
|
1161
|
+
* down — only when the index collation is coarser-or-equal to the declared collation
|
|
1162
|
+
* per constrained column (see {@link coveringMvHonorsIndexCollation}). For a
|
|
1163
|
+
* finer/incomparable index-derived UNIQUE (e.g. a coarser NOCASE index over a BINARY
|
|
1164
|
+
* column) the candidate set may be a *subset* that silently misses conflicts, so the
|
|
1165
|
+
* MV is declined here and enforcement falls back to the per-scan / auto-index path
|
|
1166
|
+
* (already correct under the index collation). All three callers (store, memory,
|
|
1167
|
+
* lens-prover) consult this resolver, so they decline the same MV in lockstep and
|
|
1168
|
+
* candidate generation never runs for a declined MV. This gate is load-bearing, not
|
|
1169
|
+
* mere defense-in-depth: the covering-link prover's own collation gate compares the
|
|
1170
|
+
* OUTPUT column collation against the DECLARED base-column collation (not the index
|
|
1171
|
+
* collation), so it DOES link a coarser-index covering MV — confirmed by the
|
|
1172
|
+
* premise-check test in `covering-structure.spec.ts`.
|
|
1173
|
+
*/
|
|
1174
|
+
findRowTimeCoveringStructure(schemaName: string, tableName: string, uc: UniqueConstraintSchema): MaintainedTableSchema | undefined;
|
|
1175
|
+
/**
|
|
1176
|
+
* Resolve a constraint's `coveringStructureName` forward pointer. Prefers the
|
|
1177
|
+
* pointer already on the passed `uc` (the memory source shares the
|
|
1178
|
+
* schema-manager's frozen constraint, so the eager link's mutation is visible).
|
|
1179
|
+
* A store source holds a *copied* schema whose constraint never received the
|
|
1180
|
+
* mutation, so fall back to the authoritative schema-manager constraint matched
|
|
1181
|
+
* by column set — keeping the covering-structure lookup module-agnostic.
|
|
1182
|
+
*/
|
|
1183
|
+
private resolveCoveringStructureName;
|
|
1184
|
+
/**
|
|
1185
|
+
* Point-look up the covering MV's backing table for rows whose backing columns
|
|
1186
|
+
* equal `newRow`'s UNIQUE-constraint values, recover each conflicting **source**
|
|
1187
|
+
* PK from the projected PK columns, and exclude the row being written
|
|
1188
|
+
* (`newSourcePk`). Returns the conflicting source PK(s) — the caller resolves
|
|
1189
|
+
* IGNORE/ABORT/REPLACE against its own source storage (recovering the live
|
|
1190
|
+
* source row and validating the candidate against it, since the backing entry
|
|
1191
|
+
* for an internally-deleted/updated source row can lag within a statement).
|
|
1192
|
+
*
|
|
1193
|
+
* Reads-own-writes: the scan resolves to the backing table's coordinated
|
|
1194
|
+
* connection (the same one {@link maintainRowTime} writes), so the backing
|
|
1195
|
+
* reflects all prior rows of the statement. The backing is hosted by whatever
|
|
1196
|
+
* backing-host-capable module the MV declared (`memory` by default, the store
|
|
1197
|
+
* module under `using store`), independent of the source module — the host's
|
|
1198
|
+
* `scanEffective` abstracts the storage.
|
|
1199
|
+
*
|
|
1200
|
+
* The conflict check is a **backing-PK prefix scan** keyed on `newRow`'s UC
|
|
1201
|
+
* values — O(log n + matches) rather than the former O(n) full backing scan.
|
|
1202
|
+
* Soundness rests on the covering-index shape: the body's `order by` columns are
|
|
1203
|
+
* a permutation of the UC columns ({@link buildMaintenancePlan} eligibility +
|
|
1204
|
+
* the coverage prover), and they seed the leading backing-PK columns
|
|
1205
|
+
* (`computeBackingPrimaryKey`), so the leading `k = uc.columns.length` backing-PK
|
|
1206
|
+
* columns are exactly the UC columns. {@link tryBuildCoveringPrefix} builds the
|
|
1207
|
+
* equality prefix in backing-PK column order; the scan seeks to it and
|
|
1208
|
+
* early-terminates when the leading columns stop matching. It falls back to a
|
|
1209
|
+
* full scan whenever the fast-path gate fails (non-BINARY collation, or a
|
|
1210
|
+
* leading-prefix shape that does not lead with exactly the UC columns) — the
|
|
1211
|
+
* full scan re-compares with the source collation, so the fallback is
|
|
1212
|
+
* collation-correct. Either way the result is only a *candidate* set: the caller
|
|
1213
|
+
* validates each against the live source row.
|
|
1214
|
+
*/
|
|
1215
|
+
lookupCoveringConflicts(mv: MaintainedTableSchema, uc: UniqueConstraintSchema, newRow: Row, newSourcePk: readonly SqlValue[]): Promise<Array<{
|
|
1216
|
+
pk: SqlValue[];
|
|
1217
|
+
row?: Row;
|
|
1218
|
+
}>>;
|
|
1219
|
+
/**
|
|
1220
|
+
* Build the backing-PK equality prefix for a covering-conflict scan, or
|
|
1221
|
+
* `undefined` to fall back to the full backing scan.
|
|
1222
|
+
*
|
|
1223
|
+
* The covering-index shape guarantees the body's `order by` columns are a
|
|
1224
|
+
* permutation of the UC columns and that they seed the leading backing-PK columns
|
|
1225
|
+
* (`computeBackingPrimaryKey`). So the leading `k = uc.columns.length` backing-PK
|
|
1226
|
+
* columns are exactly the UC columns (as a set, possibly reordered by `order by`).
|
|
1227
|
+
* The returned prefix is keyed in **backing-PK column order** (not `uc.columns`
|
|
1228
|
+
* order), so a permuting `order by` still seeks to the right block:
|
|
1229
|
+
* `prefix[i] = newRow[ sourceCol(backingPkDefinition[i]) ]`.
|
|
1230
|
+
*
|
|
1231
|
+
* Returns `undefined` (full-scan fallback) when any holds:
|
|
1232
|
+
* - fewer than `k` backing-PK columns, or a leading column is not a passthrough
|
|
1233
|
+
* of a source column (defensive — the covering shape guarantees passthrough);
|
|
1234
|
+
* - the leading `k` backing-PK columns do not map to **exactly** the UC
|
|
1235
|
+
* source-column set (defensive guard against a non-UC-leading structure);
|
|
1236
|
+
* - any leading backing-PK column, or its source UC column, has a **non-BINARY**
|
|
1237
|
+
* collation. This is a *soundness* gate, not a perf choice: the prefix seek's
|
|
1238
|
+
* early-termination compares with plain `compareSqlValues` (binary), while the
|
|
1239
|
+
* backing btree orders the PK by its declared collation and the UNIQUE
|
|
1240
|
+
* constraint conflicts by the source collation. Under a non-binary collation
|
|
1241
|
+
* the binary early-termination could `break` before a collated-equal /
|
|
1242
|
+
* binary-different conflict, missing it. The full-scan fallback re-compares
|
|
1243
|
+
* with the source collation, so it stays collation-correct.
|
|
1244
|
+
*
|
|
1245
|
+
* DESC-leading prefixes are admitted: equality on a column makes its order
|
|
1246
|
+
* direction irrelevant to *grouping* (the binary-equal rows stay contiguous), and
|
|
1247
|
+
* `scanLayer`'s `equalityPrefix` seek + ascending walk lands at the group start
|
|
1248
|
+
* for either direction (verified by the `order by … desc` enforcement test).
|
|
1249
|
+
*/
|
|
1250
|
+
private tryBuildCoveringPrefix;
|
|
1251
|
+
}
|
|
1252
|
+
export {};
|
|
1253
|
+
//# sourceMappingURL=database-materialized-views.d.ts.map
|