@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,1158 @@
|
|
|
1
|
+
import { PlanNode } from '../nodes/plan-node.js';
|
|
2
|
+
import { RowOpFlag } from '../../schema/table.js';
|
|
3
|
+
import { ViewMutationNode } from '../nodes/view-mutation-node.js';
|
|
4
|
+
import { propagate, decompositionStorage } from '../mutation/propagate.js';
|
|
5
|
+
import { analyzeMultiSourceInsert, analyzeJoinView, decomposeUpdate, decomposeDelete, buildMultiSourceKeyCapture, buildMultiSourceUpdateReturning, buildMultiSourceDeleteReturning, makeMultiSourceKeyRef, withKeyCapture, capturedSideIndices, isJoinBody } from '../mutation/multi-source.js';
|
|
6
|
+
import { analyzeDecompositionInsert, analyzeDecomposition, decomposeUpdate as decomposeDecompositionUpdate, buildDecompositionKeyCapture } from '../mutation/decomposition.js';
|
|
7
|
+
import { isSetOpMembershipBody, isSetOpFlaglessWritableBody, buildSetOpWrite, buildFlaglessSetOpWrite } from '../mutation/set-op.js';
|
|
8
|
+
import { buildCteSelfCapture } from '../mutation/single-source.js';
|
|
9
|
+
import { needsSelfCapture } from './dml-target.js';
|
|
10
|
+
import { FilterNode } from '../nodes/filter.js';
|
|
11
|
+
import { RegisteredScope } from '../scopes/registered.js';
|
|
12
|
+
import { validateMutationTags } from '../mutation/mutation-tags.js';
|
|
13
|
+
import { collectLensRowLocalConstraints, collectLensForeignKeyConstraints, collectLensParentSideForeignKeyConstraints, collectLensSetLevelConstraints, hasCommitTimeSetLevelObligation } from '../mutation/lens-enforcement.js';
|
|
14
|
+
import { ConflictResolution } from '../../common/constants.js';
|
|
15
|
+
import { buildInsertStmt } from './insert.js';
|
|
16
|
+
import { buildUpdateStmt } from './update.js';
|
|
17
|
+
import { buildDeleteStmt } from './delete.js';
|
|
18
|
+
import { buildSelectStmt, buildValuesStmt } from './select.js';
|
|
19
|
+
import { buildExpression } from './expression.js';
|
|
20
|
+
import { EnvelopeScanNode } from '../nodes/envelope-scan-node.js';
|
|
21
|
+
import { SinkNode } from '../nodes/sink-node.js';
|
|
22
|
+
import { EmptyRelationNode } from '../nodes/empty-relation-node.js';
|
|
23
|
+
import { ProjectNode } from '../nodes/project-node.js';
|
|
24
|
+
import { ColumnReferenceNode } from '../nodes/reference.js';
|
|
25
|
+
import { isRelationalNode } from '../nodes/plan-node.js';
|
|
26
|
+
import { parseExpressionString } from '../../parser/index.js';
|
|
27
|
+
import { INTEGER_TYPE } from '../../types/builtin-types.js';
|
|
28
|
+
import { raiseMutationDiagnostic } from '../mutation/mutation-diagnostic.js';
|
|
29
|
+
import { validateDeterministicDefault } from '../validation/determinism-validator.js';
|
|
30
|
+
import { buildRowDefaultScope } from './default-scope.js';
|
|
31
|
+
import { createLogger } from '../../common/logger.js';
|
|
32
|
+
const log = createLogger('planner:view-mutation');
|
|
33
|
+
/**
|
|
34
|
+
* Build the view-mutation substrate for a view-/materialized-view-mediated DML.
|
|
35
|
+
*
|
|
36
|
+
* `propagate` decomposes the view mutation into an ordered list of base-table
|
|
37
|
+
* operations (one for the single-source spine); each is re-planned through the
|
|
38
|
+
* ordinary base-table builder — so every constraint / conflict / FK /
|
|
39
|
+
* mutation-context / RETURNING-rejection rule is reused verbatim — and the
|
|
40
|
+
* results are sequenced in a `ViewMutationNode`. For the single-source case the
|
|
41
|
+
* wrapped subtree is byte-identical to what the retired AST rewrite re-planned.
|
|
42
|
+
*/
|
|
43
|
+
export function buildViewMutation(ctx, view, req) {
|
|
44
|
+
// Site-validate the view-level reserved tags (a sited error for a typo'd /
|
|
45
|
+
// mis-sited `quereus.*` key on the view/MV is raised here, before any base op
|
|
46
|
+
// is built — atomic). The statement's own tags were already validated at the
|
|
47
|
+
// dml-stmt site by the builder entry that dispatched here. No reserved tag
|
|
48
|
+
// carries mutation behavior anymore. An EPHEMERAL target (a CTE body / inline
|
|
49
|
+
// subquery) carries no schema object and no `tags`, so neither schema-coupled
|
|
50
|
+
// step below applies to it: the validator would short-circuit on the empty tags
|
|
51
|
+
// anyway, and (more importantly) recording a `view` dependency on a non-existent
|
|
52
|
+
// `<schema>.<cteName>` would spuriously invalidate this cached plan if a real
|
|
53
|
+
// view of that name were later created — and there would be nothing to invalidate
|
|
54
|
+
// *on* (the CTE body is part of the statement, re-planned every run). Skip both.
|
|
55
|
+
if (!view.ephemeral) {
|
|
56
|
+
validateMutationTags(view, req.stmt);
|
|
57
|
+
// Record a `view` schema dependency for the mutated view/MV. This is the single
|
|
58
|
+
// funnel for ALL view-/MV-mediated writes (single-source, multi-source,
|
|
59
|
+
// decomposition, set-op, lens), so recording here — rather than at each builder's
|
|
60
|
+
// getView site — covers every write-through path DRY. It exists so that an
|
|
61
|
+
// `ALTER VIEW/MATERIALIZED VIEW … SET TAGS` (which fires `view_modified` /
|
|
62
|
+
// `materialized_view_modified`) invalidates this cached write-through plan: the
|
|
63
|
+
// validation above must re-run against the view's *current* tags (a newly-added
|
|
64
|
+
// invalid tag must surface on the next run of an already-cached statement).
|
|
65
|
+
// Read-only `select … from v` records no view dependency — view tags do not affect
|
|
66
|
+
// read results, so its plan need not invalidate on a tag change. Both halves
|
|
67
|
+
// (recording and invalidation) are pinned in test/plan/view-dependency-invalidation.spec.ts.
|
|
68
|
+
ctx.schemaDependencies.recordDependency({ type: 'view', schemaName: view.schemaName, objectName: view.name }, view);
|
|
69
|
+
}
|
|
70
|
+
// A decomposition INSERT fans out one insert per member off the same shared-
|
|
71
|
+
// surrogate envelope, materialized once and read back per member through an
|
|
72
|
+
// `EnvelopeScanNode` — the plan-level form the AST `BaseOp[]` model cannot
|
|
73
|
+
// express. Build it directly (the dual of the multi-source insert below).
|
|
74
|
+
if (req.op === 'insert' && decompositionStorage(ctx, view)) {
|
|
75
|
+
return buildDecompositionInsert(ctx, view, req.stmt);
|
|
76
|
+
}
|
|
77
|
+
// Multi-source inner-join INSERT needs the plan-level shared-surrogate envelope
|
|
78
|
+
// (a materialized augmented source the sibling base inserts fan out from), which
|
|
79
|
+
// the AST-level `BaseOp[]` model cannot express — build it directly.
|
|
80
|
+
if (req.op === 'insert' && isJoinBody(view.selectAst)) {
|
|
81
|
+
return buildMultiSourceInsert(ctx, view, req.stmt);
|
|
82
|
+
}
|
|
83
|
+
// Set-operation membership write (binary, non-nested): the per-branch fan-out keyed
|
|
84
|
+
// on the runtime membership probe needs a plan-level capture (the affected rows +
|
|
85
|
+
// their probe flags, materialized once before any branch op fires — Halloween-safe),
|
|
86
|
+
// which the AST `BaseOp[]` model cannot express. Build it directly (the dual of the
|
|
87
|
+
// multi-source insert), for insert / update / delete alike.
|
|
88
|
+
if (isSetOpMembershipBody(view.selectAst)) {
|
|
89
|
+
return buildSetOpMutation(ctx, view, req, buildSetOpWrite);
|
|
90
|
+
}
|
|
91
|
+
// Flag-less predicate-honest set-op write (`set-op-flagless-predicate-honest-writes`): the
|
|
92
|
+
// *preferred* surface over the `exists`-membership path above — a flag-less body of
|
|
93
|
+
// literal-discriminator legs (`'red' as kind`) routed by a plan-time σ + discriminator
|
|
94
|
+
// oracle. It rides the SAME capture + per-branch `propagate` + fan substrate (shared via
|
|
95
|
+
// `buildSetOpMutation`), differing only in the per-leg write builder. A non-writable
|
|
96
|
+
// flag-less shape is NOT this case — it keeps rejecting `unsupported-set-op` downstream.
|
|
97
|
+
// Gated to a real view/MV (`!view.ephemeral`): an ephemeral CTE-body / inline-subquery
|
|
98
|
+
// target with a flag-less set-op body keeps its established phase-1 reject this pass
|
|
99
|
+
// (a CTE-target flag-less write — self-reference / Halloween interplay — is out of scope).
|
|
100
|
+
if (!view.ephemeral && isSetOpFlaglessWritableBody(view.selectAst)) {
|
|
101
|
+
return buildSetOpMutation(ctx, view, req, buildFlaglessSetOpWrite);
|
|
102
|
+
}
|
|
103
|
+
// Lens set-level conflict-resolution gate: a commit-time set-level key (no basis
|
|
104
|
+
// covering structure) enforces via an O(n) deferred count scan, which cannot
|
|
105
|
+
// perform `or replace` / `or ignore`. Reject those up front so a write that would
|
|
106
|
+
// silently ABORT-at-commit instead of skipping/replacing is caught with a clear
|
|
107
|
+
// diagnostic. A row-time key (backed by a basis UNIQUE + covering MV) is NOT
|
|
108
|
+
// gated — its basis UC's covering-MV enforcement resolves the conflict action for
|
|
109
|
+
// free (`lens-set-level-rowtime-enforcement`, delivered).
|
|
110
|
+
rejectLensSetLevelConflictResolution(ctx, view, req);
|
|
111
|
+
// Multi-source inner-join UPDATE / DELETE: plan the join body ONCE here and thread
|
|
112
|
+
// the single analysis through decomposition, the identity capture, and the
|
|
113
|
+
// RETURNING re-query — so no consumer re-plans the body via AST (the retired
|
|
114
|
+
// double-plan; docs/view-updateability.md § Round-Trip Laws and the Derived
|
|
115
|
+
// Backward Walk). A decomposition-backed logical table (a `primary-storage`
|
|
116
|
+
// advertisement) is NOT this case — it routes to `propagate`'s advertisement
|
|
117
|
+
// fan-out (`decomposition.ts`); a single-source body routes to the spine.
|
|
118
|
+
const msAnalysis = (req.op === 'update' || req.op === 'delete') && isJoinBody(view.selectAst) && !decompositionStorage(ctx, view)
|
|
119
|
+
? analyzeJoinView(ctx, view)
|
|
120
|
+
: undefined;
|
|
121
|
+
// A decomposition-backed logical table UPDATE: plan the synthesized body ONCE here (so no
|
|
122
|
+
// consumer re-plans it via AST — the same single-plan discipline the multi-source path
|
|
123
|
+
// follows) and route directly to the decomposition decomposer with a captured-value carrier.
|
|
124
|
+
// An arbitrary optional-columnar value rides the single-identity `__vmupd_keys` capture
|
|
125
|
+
// (folded into the keyCapture machinery below); constant/anchor/self updates build no capture
|
|
126
|
+
// and produce byte-identical base ops to the legacy `propagate` path. DELETE / INSERT through a
|
|
127
|
+
// decomposition stay on `propagate` / the insert envelope (unchanged).
|
|
128
|
+
const decompStorageShape = req.op === 'update' ? decompositionStorage(ctx, view) : undefined;
|
|
129
|
+
const decompShape = decompStorageShape ? analyzeDecomposition(ctx, view, decompStorageShape) : undefined;
|
|
130
|
+
// Cross-source SET values (`update v set a.x = b.y`) the multi-source UPDATE lowers
|
|
131
|
+
// to a correlated read of the captured partner column accumulate here, then thread
|
|
132
|
+
// into the identity capture so the same `__vmupd_keys` set carries them (§ Inner
|
|
133
|
+
// Join). Empty for delete / single-source / decomposition.
|
|
134
|
+
const sourceValues = [];
|
|
135
|
+
// Arbitrary optional-columnar values a decomposition UPDATE lowers to a captured read-back
|
|
136
|
+
// accumulate here, then thread into the decomposition key capture (the dual of `sourceValues`).
|
|
137
|
+
const capturedValues = [];
|
|
138
|
+
// CTE-name DML target self-read (docs/view-updateability.md § Common Table Expressions
|
|
139
|
+
// — self-reference). When the user `where` / `set` / `returning` self-reads the target
|
|
140
|
+
// CTE name (`with t as (…) update t … where id in (select id from t)`), build a SPLIT
|
|
141
|
+
// planning context: the body is planned target-EXCLUDED under `ctx` (so a same-named
|
|
142
|
+
// base FROM reaches the real table — the load-bearing shadow case), while the
|
|
143
|
+
// user-clause descend AND the lowered base op's re-plan resolve `t` against an EAGER
|
|
144
|
+
// capture of the full body relation (`ctxSelfRead`). The capture rides `identityCapture`,
|
|
145
|
+
// materialized once before any base op runs — so the base op's `select id from t` reads
|
|
146
|
+
// the pre-mutation snapshot, Halloween-safe by construction. Gated to an ephemeral
|
|
147
|
+
// CTE-name target (an inline subquery already round-trips via the real base table) + a
|
|
148
|
+
// single-source UPDATE/DELETE; a join-bodied (multi-source) or INSERT-source self-read
|
|
149
|
+
// is out of scope and keeps current behavior (it does not take this path). `ctx` here is
|
|
150
|
+
// already target-excluded by the CTE-name dispatch's `contextForCteTarget`.
|
|
151
|
+
const selfCapture = !!view.ephemeral && !!view.cteTarget
|
|
152
|
+
&& (req.op === 'update' || req.op === 'delete')
|
|
153
|
+
&& !isJoinBody(view.selectAst)
|
|
154
|
+
&& needsSelfCapture(req.stmt, view.name)
|
|
155
|
+
? buildCteSelfCapture(ctx, view)
|
|
156
|
+
: undefined;
|
|
157
|
+
const ctxSelfRead = selfCapture ? withCteCapture(ctx, view.name, selfCapture) : undefined;
|
|
158
|
+
let baseOps;
|
|
159
|
+
if (msAnalysis && req.op === 'update') {
|
|
160
|
+
baseOps = decomposeUpdate(ctx, view, msAnalysis, req.stmt, sourceValues);
|
|
161
|
+
}
|
|
162
|
+
else if (msAnalysis && req.op === 'delete') {
|
|
163
|
+
baseOps = decomposeDelete(ctx, view, msAnalysis, req.stmt);
|
|
164
|
+
}
|
|
165
|
+
else if (decompShape && req.op === 'update') {
|
|
166
|
+
baseOps = decomposeDecompositionUpdate(ctx, view, decompShape, req.stmt, capturedValues);
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
// `ctxSelfRead` (when a self-read is present) threads into the single-source
|
|
170
|
+
// UPDATE/DELETE rewrite so the user-clause descend resolves `from t` to the capture;
|
|
171
|
+
// undefined elsewhere is the byte-identical no-self-read path.
|
|
172
|
+
baseOps = propagate(ctx, view, req, ctxSelfRead);
|
|
173
|
+
}
|
|
174
|
+
// Lens row-local enforcement: when the target is a lens-backed logical table,
|
|
175
|
+
// its prover-classified `enforced-row-local` CHECK obligations (rewritten to
|
|
176
|
+
// basis terms) ride the basis write's per-row check pipeline, so they fire on
|
|
177
|
+
// the write through the lens even when the basis carries no such check. A
|
|
178
|
+
// plain view / MV has no lens slot ⇒ no extras (unchanged behavior). DELETE
|
|
179
|
+
// writes no NEW row, so a CHECK is moot there.
|
|
180
|
+
// Lens FK enforcement (the `enforced-fk` obligation): each logical FK rides the
|
|
181
|
+
// same `extraConstraints` seam as a deferred basis-term `EXISTS` existence check
|
|
182
|
+
// against the schema-qualified logical parent — gated by the `foreign_keys`
|
|
183
|
+
// pragma exactly like the physical child-side FK, so a lens write enforces the
|
|
184
|
+
// logical FK with matching gating + commit-time timing even when the basis
|
|
185
|
+
// carries no such FK.
|
|
186
|
+
// Lens set-level enforcement (the `enforced-set-level` `commit-time` obligation):
|
|
187
|
+
// each logical unique / primary key with no basis covering structure rides the
|
|
188
|
+
// same seam as a deferred `(select count(*) … ) <= 1` count-subquery CHECK over
|
|
189
|
+
// the logical key columns — auto-deferred to commit, where a duplicate logical
|
|
190
|
+
// key sees count ≥ 2 ⇒ ABORT. DELETE writes no NEW row and can introduce no
|
|
191
|
+
// duplicate, so the three child/write classes do not apply there.
|
|
192
|
+
// Lens parent-side FK enforcement (the cross-slot dual of the child-side FK): a
|
|
193
|
+
// delete/update of a logical *parent* through the lens runs the RESTRICT existence
|
|
194
|
+
// check against the logical *child*, synthesized as a deferred `NOT EXISTS` and
|
|
195
|
+
// routed through the same seam — gated on `foreign_keys`. It fires on DELETE and
|
|
196
|
+
// UPDATE (the only ops that can orphan a child), so it is the *sole* extra for a
|
|
197
|
+
// delete and joins the row-local/child-FK/set-level list (UPDATE-masked) otherwise.
|
|
198
|
+
const extraConstraints = req.op === 'delete'
|
|
199
|
+
? lensParentSideForeignKeyConstraints(ctx, view, RowOpFlag.DELETE)
|
|
200
|
+
: [
|
|
201
|
+
...lensRowLocalConstraints(ctx, view),
|
|
202
|
+
...lensForeignKeyConstraints(ctx, view),
|
|
203
|
+
...lensSetLevelConstraints(ctx, view),
|
|
204
|
+
...lensParentSideForeignKeyConstraints(ctx, view, RowOpFlag.UPDATE),
|
|
205
|
+
];
|
|
206
|
+
// Multi-source identity capture (docs/view-updateability.md § Inner Join): an
|
|
207
|
+
// UPDATE that assigns BOTH base sides (⇒ more than one base op) — or carries
|
|
208
|
+
// RETURNING — and a lenient DELETE fanned out to BOTH candidate sides (⇒ more than
|
|
209
|
+
// one base op) capture each affected view row's base-PK identities ONCE up-front,
|
|
210
|
+
// *before* any base op mutates. The multi-side base ops read their identifying
|
|
211
|
+
// values back from that captured set (so the first op can't empty the join — or
|
|
212
|
+
// rewrite a predicate column — out from under the second op's identifying
|
|
213
|
+
// subquery), and the UPDATE RETURNING re-query re-projects by captured identity.
|
|
214
|
+
// Built once and shared. A decomposition UPDATE that lowered ≥1 arbitrary value builds the
|
|
215
|
+
// single-identity (anchor-key) capture instead — the same `__vmupd_keys` substrate + downstream
|
|
216
|
+
// wiring (`injectKeyRef` / `withKeyCapture` / `identityCapture`), with `k0_0` the anchor key and
|
|
217
|
+
// one `srcN` per captured value. An empty carrier (constant/anchor/self) builds no capture.
|
|
218
|
+
const keyCapture = decompShape && req.op === 'update'
|
|
219
|
+
? (capturedValues.length > 0 ? buildDecompositionKeyCapture(ctx, view, decompShape, req.stmt.where, capturedValues) : undefined)
|
|
220
|
+
: buildIdentityCapture(ctx, view, req, baseOps, msAnalysis, sourceValues);
|
|
221
|
+
// EVERY multi-source update/delete base op now resolves `select k<side> from
|
|
222
|
+
// __vmupd_keys` against the context-backed key relation (single-side and both-sides
|
|
223
|
+
// alike — the live join-body subquery is retired), so inject a fresh key ref per op
|
|
224
|
+
// (sharing the one capture descriptor) into each op's planning `cteNodes`. Non
|
|
225
|
+
// multi-source paths build no capture, so this is a no-op there.
|
|
226
|
+
const injectKeyRef = !!keyCapture;
|
|
227
|
+
// A write through a *lens* view (a lens slot exists for it) is the only view-mutation
|
|
228
|
+
// the runtime parent-side **logical** FK machinery applies to — the same predicate the
|
|
229
|
+
// lens*Constraints collectors above use. Plain updatable view / MV write-through lowers
|
|
230
|
+
// to a basis write too, but has no lens slot ⇒ `lensRouted = false` ⇒ basis-only FK
|
|
231
|
+
// semantics. Threaded onto each single-source-spine base op's DmlExecutorNode so the
|
|
232
|
+
// runtime can distinguish a lens-routed basis write from a basis-direct one.
|
|
233
|
+
const isLensWrite = !!ctx.schemaManager.getSchema(view.schemaName)?.getLensSlot(view.name);
|
|
234
|
+
// A lens-synthesized constraint (set-level uniqueness / row-local CHECK / child-FK
|
|
235
|
+
// EXISTS / parent-FK NOT EXISTS) references write-row columns in *basis* terms. On a
|
|
236
|
+
// multi-op fan-out (a decomposition UPDATE) those columns may live on only some
|
|
237
|
+
// members, so threading the SAME `extraConstraints` onto every base op would make a
|
|
238
|
+
// member op that lacks a referenced column fail to build (`NEW.<col> isn't a column`).
|
|
239
|
+
// Gate per op: a constraint rides a base op iff every write-row column it references
|
|
240
|
+
// resolves on that op's target table — so a uniqueness CHECK rides only the op that
|
|
241
|
+
// owns (and can change) the key, and a cross-member CHECK/FK rides the single member
|
|
242
|
+
// that resolves it (or none — deferred, as on decomposition INSERT). Single-source has
|
|
243
|
+
// exactly one base op carrying all basis columns, so this is a no-op there.
|
|
244
|
+
const riddenConstraints = new Set();
|
|
245
|
+
const children = baseOps.map(op => {
|
|
246
|
+
// A CTE self-read base op re-plans under `ctxSelfRead`, so its `from t` predicate /
|
|
247
|
+
// RETURNING subquery binds to the eager capture (keyed under the CTE name). Mutually
|
|
248
|
+
// exclusive with the `__vmupd_keys` key-ref injection (single-source vs multi-source /
|
|
249
|
+
// decomposition / set-op); prefer it when present.
|
|
250
|
+
const opCtx = ctxSelfRead ?? (injectKeyRef ? withKeyCapture(ctx, keyCapture) : ctx);
|
|
251
|
+
const opConstraints = constraintsForOp(op, extraConstraints, riddenConstraints);
|
|
252
|
+
return buildBaseOp(opCtx, op, opConstraints, isLensWrite);
|
|
253
|
+
});
|
|
254
|
+
// A lens-synthesized constraint that resolves on NO base op of the fan-out is silently
|
|
255
|
+
// non-enforced (a key-unchanged UPDATE drops its uniqueness scan — correct; a CHECK/FK
|
|
256
|
+
// spanning more than one member is deferred — as on decomposition INSERT). Trace it so
|
|
257
|
+
// the non-enforcement is at least visible in debug logs.
|
|
258
|
+
for (const c of extraConstraints) {
|
|
259
|
+
if (!riddenConstraints.has(c)) {
|
|
260
|
+
log('lens constraint %s references write-row columns no base op of the %s fan-out carries; not enforced on this write', c.name ?? '<anon>', req.op);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
// RETURNING-through-view. Single-source already embedded the (rewritten)
|
|
264
|
+
// RETURNING onto its base op (it now plans to a relational ReturningNode the
|
|
265
|
+
// substrate surfaces), so nothing more is needed there. A **multi-source**
|
|
266
|
+
// update/delete cannot recover the view row from its per-side base ops: a delete
|
|
267
|
+
// re-queries the view *before* the base ops fire (its rows are about to vanish);
|
|
268
|
+
// an update re-queries the join body *after* restricted to the captured identities
|
|
269
|
+
// (robust against an update that rewrites its own predicate column).
|
|
270
|
+
const { returning, returningTiming } = buildMultiSourceReturning(ctx, view, req, keyCapture, msAnalysis);
|
|
271
|
+
// The side input the emitter materializes ONCE before any base op runs: the CTE
|
|
272
|
+
// self-read capture (single-source) or the multi-source / decomposition / set-op key
|
|
273
|
+
// capture (mutually exclusive). For a self-read, single-source RETURNING is embedded on
|
|
274
|
+
// the base op (re-planned under `ctxSelfRead`) and reads the same frozen snapshot.
|
|
275
|
+
const identityCapture = selfCapture
|
|
276
|
+
? { source: selfCapture.source, descriptor: selfCapture.descriptor }
|
|
277
|
+
: keyCapture ? { source: keyCapture.source, descriptor: keyCapture.descriptor } : undefined;
|
|
278
|
+
return new ViewMutationNode(ctx.scope, children, returning, undefined, returningTiming, identityCapture);
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Build the shared up-front identity capture for a multi-source inner-join UPDATE /
|
|
282
|
+
* DELETE. Now built for **every** such mutation (the single-side live join-body
|
|
283
|
+
* subquery is retired — single-side and both-sides alike read the captured set), with
|
|
284
|
+
* `analysis` the SINGLE plan of the join body threaded from {@link buildViewMutation}
|
|
285
|
+
* so the body is planned once. `undefined` for everything else (inserts, single-source
|
|
286
|
+
* spines, decomposition-backed tables — none thread an `analysis`).
|
|
287
|
+
*
|
|
288
|
+
* The captured sides are the sides whose base ops read the set, EXCEPT an UPDATE with
|
|
289
|
+
* RETURNING captures EVERY side's PK — its post-mutation re-query identifies the full
|
|
290
|
+
* joined row by all sides' keys, so it needs a key on each side even when only one side
|
|
291
|
+
* is assigned (matching the retired path, whose RETURNING capture also projected both
|
|
292
|
+
* sides' PKs). Composite-PK sides contribute one capture column per PK column.
|
|
293
|
+
*
|
|
294
|
+
* `sourceValues` carries any cross-source SET reads `decomposeUpdate` lowered (the
|
|
295
|
+
* partner base columns a `set a.x = b.y` reads); they ride the SAME capture as extra
|
|
296
|
+
* `srcN` projections (so a single-side cross-source update — which previously needed no
|
|
297
|
+
* capture distinct from the unified one — still materializes it once with the read
|
|
298
|
+
* column). Empty for delete.
|
|
299
|
+
*/
|
|
300
|
+
function buildIdentityCapture(ctx, view, req, baseOps, analysis, sourceValues) {
|
|
301
|
+
if (!analysis)
|
|
302
|
+
return undefined; // only multi-source update/delete thread an analysis
|
|
303
|
+
switch (req.op) {
|
|
304
|
+
case 'update': {
|
|
305
|
+
const hasReturning = !!req.stmt.returning && req.stmt.returning.length > 0;
|
|
306
|
+
const sides = hasReturning ? analysis.sides.map((_, i) => i) : capturedSideIndices(baseOps, analysis);
|
|
307
|
+
return buildMultiSourceKeyCapture(ctx, view, req.stmt.where, analysis, sides, sourceValues);
|
|
308
|
+
}
|
|
309
|
+
case 'delete':
|
|
310
|
+
return buildMultiSourceKeyCapture(ctx, view, req.stmt.where, analysis, capturedSideIndices(baseOps, analysis));
|
|
311
|
+
default:
|
|
312
|
+
return undefined;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* The `ctxSelfRead` for a CTE-name DML target whose user clauses self-read the target
|
|
317
|
+
* name (docs/view-updateability.md § Common Table Expressions — self-reference): the
|
|
318
|
+
* target-EXCLUDED body context (`ctx`) with the target name **re-added** to `cteNodes`,
|
|
319
|
+
* resolving to a context-backed key relation over the eager self-read capture. The
|
|
320
|
+
* {@link withKeyCapture} analog, keyed under the CTE name (`cteName`) rather than
|
|
321
|
+
* {@link MS_UPDATE_KEYS_CTE} — so a user-clause `from t` (and the lowered base op's
|
|
322
|
+
* re-plan of it) binds to the materialized snapshot instead of the real base table. A
|
|
323
|
+
* fresh ref per call keeps the descend's and the base op's subtrees from sharing a node
|
|
324
|
+
* instance.
|
|
325
|
+
*/
|
|
326
|
+
function withCteCapture(ctx, cteName, capture) {
|
|
327
|
+
const cteNodes = new Map(ctx.cteNodes ?? []);
|
|
328
|
+
cteNodes.set(cteName.toLowerCase(), makeMultiSourceKeyRef(ctx.scope, capture));
|
|
329
|
+
return { ...ctx, cteNodes };
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* Build the separate RETURNING substrate for a **multi-source** update/delete (the
|
|
333
|
+
* only path where the view row is not recoverable from the base ops). Returns `{}`
|
|
334
|
+
* (no returning) for the absent-clause case, for single-source (handled by the
|
|
335
|
+
* embedded base-op RETURNING), for insert (single-source embeds; multi-source insert
|
|
336
|
+
* is rejected upstream), and for decomposition-backed logical tables (whose
|
|
337
|
+
* RETURNING stays rejected by `propagate`).
|
|
338
|
+
*
|
|
339
|
+
* Two shapes, by op:
|
|
340
|
+
* - **UPDATE** re-queries the join body *after* the base ops, restricted to the
|
|
341
|
+
* `keyCapture` identities captured *before* them (`returningTiming: 'post'`;
|
|
342
|
+
* `buildMultiSourceUpdateReturning`). This is robust against an update that
|
|
343
|
+
* rewrites a column its own WHERE filters on — the captured identity still matches
|
|
344
|
+
* even though the changed row no longer satisfies the predicate. The capture is
|
|
345
|
+
* built (and materialized) by {@link buildViewMutation} and shared with the
|
|
346
|
+
* both-sides base ops, so it is passed in rather than rebuilt here.
|
|
347
|
+
* - **DELETE** re-queries the join body restricted to the identifying predicate,
|
|
348
|
+
* captured `pre` (before the base op fires — the rows still match the predicate and
|
|
349
|
+
* are about to vanish; `returningTiming: 'pre'`; `buildMultiSourceDeleteReturning`).
|
|
350
|
+
* The RETURNING columns are recomputed in **base terms** over the planned `joinNode`
|
|
351
|
+
* (shared with the UPDATE path via `buildMultiSourceReturningProjection`), not by
|
|
352
|
+
* reference to the body `root`'s output attribute ids — so a body-computed column
|
|
353
|
+
* whose intermediate id project-merge eliminates still surfaces.
|
|
354
|
+
*/
|
|
355
|
+
function buildMultiSourceReturning(ctx, view, req, keyCapture, analysis) {
|
|
356
|
+
const returningCols = req.stmt.returning;
|
|
357
|
+
if (!returningCols || returningCols.length === 0)
|
|
358
|
+
return {};
|
|
359
|
+
if (req.op === 'insert')
|
|
360
|
+
return {}; // single-source insert embeds; multi-source insert is rejected upstream
|
|
361
|
+
if (!analysis)
|
|
362
|
+
return {}; // only multi-source update/delete thread an analysis
|
|
363
|
+
if (req.op === 'update') {
|
|
364
|
+
// keyCapture is guaranteed present here: buildIdentityCapture builds it
|
|
365
|
+
// whenever a multi-source update carries RETURNING (same gating conditions).
|
|
366
|
+
const returning = buildMultiSourceUpdateReturning(ctx, view, req.stmt, keyCapture, analysis);
|
|
367
|
+
return { returning, returningTiming: 'post' };
|
|
368
|
+
}
|
|
369
|
+
// DELETE: the OLD view image of the rows about to vanish, captured `pre`. Built in
|
|
370
|
+
// base terms over the planned `joinNode` (recomputing each view-spelled column from
|
|
371
|
+
// base columns) — robust against a body-computed column whose intermediate output
|
|
372
|
+
// attribute id the optimizer eliminates (project-merge), which a by-id reference to
|
|
373
|
+
// the body `root` would dangle on. Mirrors the UPDATE RETURNING path.
|
|
374
|
+
const node = buildMultiSourceDeleteReturning(ctx, view, req.stmt, analysis);
|
|
375
|
+
return { returning: node, returningTiming: 'pre' };
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* The lens row-local CHECK constraints for a view-mediated write, or `[]` when the
|
|
379
|
+
* target is not a lens-backed logical table (a plain view / MV) or the lens has no
|
|
380
|
+
* row-local obligations. The lens slot is resolved the same way the single-source
|
|
381
|
+
* rewrite resolves the read-only gate — only a logical schema carries one.
|
|
382
|
+
*/
|
|
383
|
+
function lensRowLocalConstraints(ctx, view) {
|
|
384
|
+
const slot = ctx.schemaManager.getSchema(view.schemaName)?.getLensSlot(view.name);
|
|
385
|
+
return slot ? collectLensRowLocalConstraints(ctx, slot) : [];
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
* The lens child-side FK existence constraints for a view-mediated write, or `[]`
|
|
389
|
+
* when the target is not a lens-backed logical table or the `foreign_keys` pragma
|
|
390
|
+
* is off. Gating on the pragma mirrors the physical child-side FK builder
|
|
391
|
+
* (`buildChildSideFKChecks` is only called when `foreign_keys` is true), so the
|
|
392
|
+
* lens enforces FKs under exactly the same switch — never adding enforcement the
|
|
393
|
+
* physical path would not.
|
|
394
|
+
*/
|
|
395
|
+
function lensForeignKeyConstraints(ctx, view) {
|
|
396
|
+
if (!ctx.db.options.getBooleanOption('foreign_keys'))
|
|
397
|
+
return [];
|
|
398
|
+
const slot = ctx.schemaManager.getSchema(view.schemaName)?.getLensSlot(view.name);
|
|
399
|
+
return slot ? collectLensForeignKeyConstraints(slot, ctx.schemaManager) : [];
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* The lens **parent-side** FK non-existence constraints for a view-mediated
|
|
403
|
+
* delete/update, or `[]` when the target is not a lens-backed logical table or the
|
|
404
|
+
* `foreign_keys` pragma is off. The target view's slot is the FK *parent*; the
|
|
405
|
+
* collector discovers logical FKs on *other* slots that reference it and synthesizes
|
|
406
|
+
* a deferred `NOT EXISTS` over the logical child per RESTRICT (`operation` selects the
|
|
407
|
+
* DELETE vs UPDATE form). Pragma-gated symmetrically with {@link lensForeignKeyConstraints}
|
|
408
|
+
* — the lens enforces parent-side FKs under the same switch as the physical
|
|
409
|
+
* `buildParentSideFKChecks`.
|
|
410
|
+
*/
|
|
411
|
+
function lensParentSideForeignKeyConstraints(ctx, view, operation) {
|
|
412
|
+
if (!ctx.db.options.getBooleanOption('foreign_keys'))
|
|
413
|
+
return [];
|
|
414
|
+
const slot = ctx.schemaManager.getSchema(view.schemaName)?.getLensSlot(view.name);
|
|
415
|
+
return slot ? collectLensParentSideForeignKeyConstraints(slot, ctx.schemaManager, operation) : [];
|
|
416
|
+
}
|
|
417
|
+
/**
|
|
418
|
+
* The lens set-level (`unique` / primary key) count-subquery constraints for a
|
|
419
|
+
* view-mediated write, or `[]` when the target is not a lens-backed logical table
|
|
420
|
+
* or the lens has no commit-time set-level obligation (a proved / row-time key, a
|
|
421
|
+
* plain view / MV). No pragma gate — set-level uniqueness is not a `foreign_keys`
|
|
422
|
+
* concern.
|
|
423
|
+
*/
|
|
424
|
+
function lensSetLevelConstraints(ctx, view) {
|
|
425
|
+
const slot = ctx.schemaManager.getSchema(view.schemaName)?.getLensSlot(view.name);
|
|
426
|
+
return slot ? collectLensSetLevelConstraints(slot) : [];
|
|
427
|
+
}
|
|
428
|
+
/**
|
|
429
|
+
* Reject a conflict-resolution write the commit-time set-level scan cannot honor.
|
|
430
|
+
* The detection-only count scan (no basis covering structure) can only ABORT on a
|
|
431
|
+
* duplicate; it cannot replace or skip the offending row — that requires a row-time
|
|
432
|
+
* covering structure. A **row-time** key (backed by a basis `UNIQUE` + covering MV)
|
|
433
|
+
* is *not* gated here: it carries no commit-time obligation, so the basis UC's
|
|
434
|
+
* covering-MV enforcement resolves `or replace` / `or ignore` for free
|
|
435
|
+
* (`lens-set-level-rowtime-enforcement`, delivered). Only the commit-time class is
|
|
436
|
+
* rejected. So an `insert or replace` / `or ignore` (or any upsert) against a logical table
|
|
437
|
+
* with a commit-time set-level key is rejected up front rather than silently
|
|
438
|
+
* ABORTing at commit instead of replacing/skipping. `or abort` / `or fail` /
|
|
439
|
+
* `or rollback` (and a plain insert) are fine — they ABORT, consistent with
|
|
440
|
+
* detection-only. UPDATE carries no statement-level OR clause, so only INSERT is
|
|
441
|
+
* gated. Upsert matching the key is awkward to disambiguate, so v1 conservatively
|
|
442
|
+
* rejects **any** upsert when a commit-time set-level obligation is present.
|
|
443
|
+
*/
|
|
444
|
+
function rejectLensSetLevelConflictResolution(ctx, view, req) {
|
|
445
|
+
if (req.op !== 'insert')
|
|
446
|
+
return;
|
|
447
|
+
const slot = ctx.schemaManager.getSchema(view.schemaName)?.getLensSlot(view.name);
|
|
448
|
+
if (!slot || !hasCommitTimeSetLevelObligation(slot))
|
|
449
|
+
return;
|
|
450
|
+
const reject = (clause) => raiseMutationDiagnostic({
|
|
451
|
+
reason: 'lens-set-level-conflict-resolution',
|
|
452
|
+
table: view.name,
|
|
453
|
+
message: `cannot ${clause} through lens-backed table '${view.name}': its logical unique/primary key has no basis covering structure, so it enforces via an O(n) commit-time scan that cannot perform row-time conflict resolution`,
|
|
454
|
+
suggestion: 'Add a basis covering materialized view (order by the key columns) to upgrade the key to row-time enforcement, or use a plain insert (which ABORTs on a duplicate).',
|
|
455
|
+
});
|
|
456
|
+
if (req.stmt.onConflict === ConflictResolution.REPLACE)
|
|
457
|
+
reject('insert or replace');
|
|
458
|
+
if (req.stmt.onConflict === ConflictResolution.IGNORE)
|
|
459
|
+
reject('insert or ignore');
|
|
460
|
+
if (req.stmt.upsertClauses && req.stmt.upsertClauses.length > 0)
|
|
461
|
+
reject('upsert (on conflict do …)');
|
|
462
|
+
}
|
|
463
|
+
/**
|
|
464
|
+
* Build the set-operation write substrate (docs/view-updateability.md § Set Operations) —
|
|
465
|
+
* the shared core for BOTH set-op view writabilities, parameterized by `writeFn`: the
|
|
466
|
+
* `exists`-membership decomposition ({@link buildSetOpWrite}) or the flag-less
|
|
467
|
+
* predicate-honest one ({@link buildFlaglessSetOpWrite}).
|
|
468
|
+
*
|
|
469
|
+
* `writeFn` decomposes the write into the ordered per-branch base ops (each lowered through
|
|
470
|
+
* `propagate` against a synthetic branch view-like, so the branch's own spine handles its
|
|
471
|
+
* base routing) plus the up-front affected-row capture they read. We wire the capture
|
|
472
|
+
* through the SAME `identityCapture` side input + context-backed `__vmupd_keys` relation the
|
|
473
|
+
* multi-source path uses (so the branch ops' `exists (… from __vmupd_keys …)` resolves), and
|
|
474
|
+
* sequence the base ops in a void `ViewMutationNode` (no RETURNING through a set-op write in
|
|
475
|
+
* v1). Insert-through carries no capture (its values are self-contained), so no key ref is
|
|
476
|
+
* injected there.
|
|
477
|
+
*/
|
|
478
|
+
function buildSetOpMutation(ctx, view, req, writeFn) {
|
|
479
|
+
const { baseOps, capture, nestedCaptures, joinLegInserts } = writeFn(ctx, view, req);
|
|
480
|
+
// Zero-leg DELETE / data-UPDATE → clean no-op. When the write's predicate is provably
|
|
481
|
+
// `unsat` for EVERY leg (an off-grid or same-axis-contradiction filter over the projected-
|
|
482
|
+
// constant discriminators, or any predicate inconsistent with each leg's σ), the fan narrows
|
|
483
|
+
// to zero legs (`fanLegsForFanOut` → []), so `writeFn` returns an empty decomposition (no base
|
|
484
|
+
// ops, no join-leg inserts). A delete/update that matches no rows is a clean no-op (0 rows
|
|
485
|
+
// affected) — standard SQL — so return a void sink rather than constructing `ViewMutationNode([])`
|
|
486
|
+
// (whose constructor throws `requires at least one base operation`). The discarded `capture` /
|
|
487
|
+
// `nestedCaptures` are plan-time descriptors with no runtime side effect — nothing reads them once
|
|
488
|
+
// there are no base ops. INSERT is deliberately excluded: a flag-less insert routing to no leg is a
|
|
489
|
+
// genuine "this row belongs to no branch" rejection, already raised in `buildFlaglessInsert`
|
|
490
|
+
// (`consistent with no writable leg`), so it never reaches here with an empty decomposition for a
|
|
491
|
+
// real reject — and must NOT be softened to a no-op. Placing the guard at this shared boundary also
|
|
492
|
+
// defends the `exists`-membership path (`buildSetOpWrite`) and any future fan rule that legitimately
|
|
493
|
+
// narrows to zero branches.
|
|
494
|
+
if (req.op !== 'insert' && baseOps.length === 0 && (joinLegInserts?.length ?? 0) === 0) {
|
|
495
|
+
return buildNoOpMutationSink(ctx, req.op);
|
|
496
|
+
}
|
|
497
|
+
// Each probe-driven branch op reads the capture back through `__vmupd_keys`; inject a
|
|
498
|
+
// fresh context-backed key ref (sharing the one capture descriptor) per op, exactly as
|
|
499
|
+
// the multi-source update/delete path does. Insert-through has no capture ⇒ no injection.
|
|
500
|
+
// A **multi-source (join) branch** additionally builds its own inner per-branch capture
|
|
501
|
+
// under a fresh `__vmupd_keys$N` name (chained off the outer set-op capture): inject the
|
|
502
|
+
// outer AND every inner so a base op of branch N — referencing `__vmupd_keys$N` — resolves
|
|
503
|
+
// (distinct names, so injecting all is harmless; a base op names only its own branch's).
|
|
504
|
+
let opCtx = capture ? withKeyCapture(ctx, capture) : ctx;
|
|
505
|
+
for (const inner of nestedCaptures ?? [])
|
|
506
|
+
opCtx = withKeyCapture(opCtx, inner);
|
|
507
|
+
const children = baseOps.map(op => buildBaseOp(opCtx, op, [], false));
|
|
508
|
+
// Splice each active multi-source (INNER join) leg/branch INSERT as a nested envelope-backed
|
|
509
|
+
// `ViewMutationNode` child (`set-op-write-multisource-leg-insert`): the set-op insert builders
|
|
510
|
+
// cannot call `buildMultiSourceInsert` (a building-layer function producing a whole `PlanNode`,
|
|
511
|
+
// not an AST `BaseOp`), so they recorded per-leg descriptors and we build them here. Each nested
|
|
512
|
+
// node carries its OWN envelope under a fresh identity descriptor — two join legs never collide
|
|
513
|
+
// — and runs its own self-contained sub-program (the emitter drains each base op via
|
|
514
|
+
// `emitCallFromPlan`). Pass the capture-injected `opCtx` so a membership-flip leg's
|
|
515
|
+
// `from __vmupd_keys` source resolves against the outer set-op capture (which the outer node
|
|
516
|
+
// materializes first). `buildMultiSourceInsert` records no view dependency (that happens once in
|
|
517
|
+
// `buildViewMutation` above), so building it on a synthetic branch view is safe.
|
|
518
|
+
for (const jli of joinLegInserts ?? [])
|
|
519
|
+
children.push(buildMultiSourceInsert(opCtx, jli.view, jli.stmt));
|
|
520
|
+
const identityCapture = capture ? { source: capture.source, descriptor: capture.descriptor } : undefined;
|
|
521
|
+
// The inner per-branch captures ride the ORDERED `nestedCaptures` side input: materialized
|
|
522
|
+
// AFTER the primary outer capture, in fan order, so each inner's `memberExists` filter scans
|
|
523
|
+
// the already-materialized outer `__vmupd_keys` (and torn down in reverse). Empty ⇒ undefined,
|
|
524
|
+
// so a join-leg-free set-op write lowers byte-identically to the pre-list substrate.
|
|
525
|
+
const nested = (nestedCaptures ?? []).map(c => ({ source: c.source, descriptor: c.descriptor }));
|
|
526
|
+
return new ViewMutationNode(ctx.scope, children, undefined, undefined, undefined, identityCapture, nested.length > 0 ? nested : undefined);
|
|
527
|
+
}
|
|
528
|
+
/**
|
|
529
|
+
* The void no-op sink for a set-op DELETE / data-UPDATE that decomposed to zero base ops (its
|
|
530
|
+
* predicate is provably `unsat` for every leg). Mirrors a base-table delete/update matching no
|
|
531
|
+
* rows: a {@link SinkNode} over a zero-row {@link EmptyRelationNode} source — the emitter drains
|
|
532
|
+
* it (yielding nothing) and reports 0 rows affected. Used in place of `ViewMutationNode([])`,
|
|
533
|
+
* which rejects an empty base-op list (see {@link buildSetOpMutation}).
|
|
534
|
+
*/
|
|
535
|
+
function buildNoOpMutationSink(ctx, op) {
|
|
536
|
+
const voidRelation = {
|
|
537
|
+
typeClass: 'relation',
|
|
538
|
+
isReadOnly: true,
|
|
539
|
+
isSet: false,
|
|
540
|
+
columns: [],
|
|
541
|
+
keys: [],
|
|
542
|
+
rowConstraints: [],
|
|
543
|
+
};
|
|
544
|
+
return new SinkNode(ctx.scope, new EmptyRelationNode(ctx.scope, [], voidRelation), op);
|
|
545
|
+
}
|
|
546
|
+
/**
|
|
547
|
+
* Build the shared-surrogate envelope substrate for a multi-source inner-join
|
|
548
|
+
* INSERT (docs/view-updateability.md § Inner Join — Inserts, § Mutation Context).
|
|
549
|
+
*
|
|
550
|
+
* The decomposition (`analyzeMultiSourceInsert`) yields the per-side base inserts
|
|
551
|
+
* plus the envelope shape. We build:
|
|
552
|
+
* - the **envelope source** — the user's VALUES/SELECT, whose columns are the
|
|
553
|
+
* supplied view columns. The `ViewMutation` emitter materializes it once,
|
|
554
|
+
* appends the default-sourced shared key (if any) per row, and stashes the rows
|
|
555
|
+
* in context;
|
|
556
|
+
* - one **base insert per side**, each sourcing from a projection over an
|
|
557
|
+
* `EnvelopeScanNode` that reads those shared rows back (key first, then the
|
|
558
|
+
* view columns that side owns). Re-planned through the ordinary base-table
|
|
559
|
+
* builder, so every constraint / conflict / FK / default rule is reused; and
|
|
560
|
+
* - the **key default** (the anchor key column's declared `default`), evaluated
|
|
561
|
+
* once per produced row at the envelope.
|
|
562
|
+
*
|
|
563
|
+
* The sides are already FK-parent-before-FK-child ordered; the emitter drives them
|
|
564
|
+
* in that order. Every side reads the same materialized envelope, so the shared key
|
|
565
|
+
* is evaluated exactly once per produced row and threaded identically.
|
|
566
|
+
*/
|
|
567
|
+
function buildMultiSourceInsert(ctx, view, stmt) {
|
|
568
|
+
const plan = analyzeMultiSourceInsert(ctx, view, stmt);
|
|
569
|
+
const { envelopeAttrs, envelopeType, descriptor } = buildEnvelopeShape(plan.suppliedColumns, !!plan.keyDefault);
|
|
570
|
+
// Produced-row NEW context shared by every side's default scope (the dual of the
|
|
571
|
+
// decomposition fan-out's): a side's column default can correlate on a sibling
|
|
572
|
+
// supplied column its own base table does not carry, via `new.<col>`.
|
|
573
|
+
const sideNewRowScope = buildMemberDefaultRowScope(ctx, plan.suppliedColumns, envelopeAttrs);
|
|
574
|
+
const baseOps = plan.orderedSides.map(side => {
|
|
575
|
+
const scan = new EnvelopeScanNode(ctx.scope, descriptor, envelopeAttrs, envelopeType);
|
|
576
|
+
// A non-preserved (outer-join optional) side inserts only for rows that supply ≥1
|
|
577
|
+
// of its columns — gate the envelope through the same presence FilterNode the
|
|
578
|
+
// decomposition fan-out uses (`buildDecompositionMemberInsert`). Empty ⇒
|
|
579
|
+
// unconditional (a preserved / inner side).
|
|
580
|
+
const gated = side.presenceGateIndices.length > 0
|
|
581
|
+
? new FilterNode(ctx.scope, scan, buildPresenceGate(ctx, envelopeAttrs, side.presenceGateIndices))
|
|
582
|
+
: scan;
|
|
583
|
+
const projections = side.targetColumns.map((baseColumn, k) => {
|
|
584
|
+
const envIdx = side.envelopeIndices[k];
|
|
585
|
+
// The shared-key column of an FK-child side is threaded conditionally: it
|
|
586
|
+
// projects null for a row whose presence-gated partner is absent, so the FK
|
|
587
|
+
// does not dangle (§ Outer Joins — Inserts). Every other column — and the key
|
|
588
|
+
// of an unconditional (parent/anchor) side — is a plain envelope reference.
|
|
589
|
+
if (side.keyGate && k === side.keyGate.keyTargetIndex) {
|
|
590
|
+
const node = buildGatedKeyProjection(ctx, envelopeAttrs, envIdx, side.keyGate.groups);
|
|
591
|
+
return { node, alias: baseColumn };
|
|
592
|
+
}
|
|
593
|
+
const attr = envelopeAttrs[envIdx];
|
|
594
|
+
const ref = new ColumnReferenceNode(ctx.scope, { type: 'column', name: attr.name }, attr.type, attr.id, envIdx);
|
|
595
|
+
return { node: ref, alias: baseColumn };
|
|
596
|
+
});
|
|
597
|
+
// σ-default projections (the constant-FD insert defaulting lifted from the join
|
|
598
|
+
// body's `where` — § Inner Join — Inserts, the multi-source analog of single-source
|
|
599
|
+
// § Selection). Each is a per-row **constant** — not an envelope column — so it rides
|
|
600
|
+
// the side's `ProjectNode` as a compiled literal (`buildExpression`); the base-table
|
|
601
|
+
// builder then coerces it to the column type and runs every constraint exactly as for
|
|
602
|
+
// a single-source appended-VALUES cell. Because the constant rides the projection (not
|
|
603
|
+
// the VALUES rows), this also covers a SELECT-source insert.
|
|
604
|
+
for (const sd of side.sigmaDefaults ?? []) {
|
|
605
|
+
projections.push({ node: buildExpression(ctx, sd.valueExpr), alias: sd.baseColumn });
|
|
606
|
+
}
|
|
607
|
+
// preserveInputColumns=false → output is exactly the picked columns, fresh
|
|
608
|
+
// attribute ids, positionally aligned to the base op's target columns.
|
|
609
|
+
const source = new ProjectNode(ctx.scope, gated, projections, undefined, undefined, false);
|
|
610
|
+
const sideInsert = {
|
|
611
|
+
type: 'insert',
|
|
612
|
+
table: { type: 'identifier', name: side.schema.name, schema: side.schema.schemaName },
|
|
613
|
+
columns: [...side.targetColumns, ...(side.sigmaDefaults ?? []).map(sd => sd.baseColumn)],
|
|
614
|
+
source: { type: 'values', values: [] }, // placeholder — ignored when preBuiltSource is set
|
|
615
|
+
onConflict: stmt.onConflict,
|
|
616
|
+
contextValues: stmt.contextValues,
|
|
617
|
+
schemaPath: stmt.schemaPath,
|
|
618
|
+
loc: stmt.loc,
|
|
619
|
+
};
|
|
620
|
+
// Leaves `lensRouted = false` (default): a multi-source parent resolves to no
|
|
621
|
+
// single basis spine, so the runtime parent-side cascade reverse-map never matches
|
|
622
|
+
// it — the marker would have no effect. The single-source spine (`buildBaseOp`) is
|
|
623
|
+
// the only place it is load-bearing. Do not "fix" this omission.
|
|
624
|
+
return buildInsertStmt(ctx, sideInsert, [], source, false, sideNewRowScope);
|
|
625
|
+
});
|
|
626
|
+
const envelopeSource = buildEnvelopeSource(ctx, view, stmt, plan.suppliedColumns.length);
|
|
627
|
+
const keyDefault = buildKeyDefault(ctx, view, plan.keyDefault, plan.suppliedColumns);
|
|
628
|
+
return new ViewMutationNode(ctx.scope, baseOps, undefined, {
|
|
629
|
+
source: envelopeSource,
|
|
630
|
+
descriptor,
|
|
631
|
+
keyDefault: keyDefault?.node,
|
|
632
|
+
keyDefaultRowDescriptor: keyDefault?.rowDescriptor,
|
|
633
|
+
});
|
|
634
|
+
}
|
|
635
|
+
/**
|
|
636
|
+
* Build the shared-surrogate envelope substrate for an INSERT through a
|
|
637
|
+
* decomposition-backed logical table (docs/lens.md § The Default Mapper,
|
|
638
|
+
* docs/view-updateability.md § Mutation Context). The dual of
|
|
639
|
+
* `buildMultiSourceInsert`, generalized from two FK-ordered sides to an n-way,
|
|
640
|
+
* anchor-first member fan-out with optional / EAV members.
|
|
641
|
+
*
|
|
642
|
+
* `analyzeDecompositionInsert` yields the per-member base inserts plus the envelope
|
|
643
|
+
* shape. We build the **envelope source** (the user's VALUES/SELECT, columns = the
|
|
644
|
+
* supplied logical columns), one **base insert per op** (each sourcing from a
|
|
645
|
+
* projection — over a presence `FilterNode` for an optional/EAV op — of the shared
|
|
646
|
+
* `EnvelopeScanNode`), and the **key default** (the anchor key column's declared
|
|
647
|
+
* `default`) when the shared key is a surrogate. Every member reads the same
|
|
648
|
+
* materialized envelope, so the default is evaluated once per produced row and the
|
|
649
|
+
* value threads identically across the fan-out.
|
|
650
|
+
*
|
|
651
|
+
* Lens constraint obligations (row-local CHECK / child-side FK / set-level uniqueness)
|
|
652
|
+
* ride the member inserts under the SAME per-op resolvability gate the decomposition
|
|
653
|
+
* UPDATE path uses (`constraintsForOp`): a single-member-resolvable obligation fires on
|
|
654
|
+
* the member that owns its write-row columns; a cross-member one resolves on no single
|
|
655
|
+
* member op and stays deferred. A plain (non-lens) decomposition collects none.
|
|
656
|
+
*/
|
|
657
|
+
function buildDecompositionInsert(ctx, view, stmt) {
|
|
658
|
+
const storage = decompositionStorage(ctx, view); // guaranteed by the caller's gate
|
|
659
|
+
// This path early-returns from `buildViewMutation` before its `rejectLensSetLevelConflictResolution`
|
|
660
|
+
// gate (the decomposition routing sits above it), so run the gate here too. Now that the fan-out
|
|
661
|
+
// threads the commit-time set-level count CHECK (below), an `insert or replace` / `or ignore` /
|
|
662
|
+
// upsert through a decomposition with a commit-time set-level key would otherwise silently
|
|
663
|
+
// ABORT-at-commit instead of getting the documented up-front diagnostic (docs/lens.md
|
|
664
|
+
// § Enforcement by constraint class). A plain insert / `or abort` is unaffected.
|
|
665
|
+
rejectLensSetLevelConflictResolution(ctx, view, { op: 'insert', stmt });
|
|
666
|
+
const plan = analyzeDecompositionInsert(ctx, view, storage, stmt);
|
|
667
|
+
const { envelopeAttrs, envelopeType, descriptor } = buildEnvelopeShape(plan.suppliedColumns, !!plan.keyDefault);
|
|
668
|
+
// The produced logical row's NEW context, shared by every member insert's default
|
|
669
|
+
// scope: each supplied logical column registered as `new.<col>` over the shared
|
|
670
|
+
// envelope attributes (the same surface the single-source insert path exposes). A
|
|
671
|
+
// member's key-column / NOT NULL default can thereby correlate on a sibling logical
|
|
672
|
+
// column its own base table does not carry (e.g. an anchor surrogate default
|
|
673
|
+
// `default (select … where parent.key = new.<fk>)`). The envelope attributes stay
|
|
674
|
+
// resolvable through the member insert's pipeline — the narrowing envelope
|
|
675
|
+
// projection keeps them bound while downstream rows are produced.
|
|
676
|
+
const memberNewRowScope = buildMemberDefaultRowScope(ctx, plan.suppliedColumns, envelopeAttrs);
|
|
677
|
+
// Lens enforcement on the decomposition INSERT fan-out — the dual of the per-op gate the
|
|
678
|
+
// decomposition UPDATE path runs in `buildViewMutation` (the `extraConstraints` /
|
|
679
|
+
// `constraintsForOp` seam). Collect the three INSERT-applicable lens constraint classes —
|
|
680
|
+
// row-local CHECK, child-side FK existence, and commit-time set-level uniqueness —
|
|
681
|
+
// synthesized in *basis* terms. Parent-side FK is DELETE/UPDATE-only (an INSERT cannot
|
|
682
|
+
// orphan a logical child), so it is deliberately NOT collected here. Each constraint is
|
|
683
|
+
// gated per member op by `constraintsForOp`: a single-member-resolvable obligation (every
|
|
684
|
+
// write-row column it references lives on one member's table) rides that member insert and
|
|
685
|
+
// fires; a cross-member obligation resolves on no single member op ⇒ rides none ⇒ stays
|
|
686
|
+
// deferred (the documented, deliberately-weaker contract — the same boundary the UPDATE
|
|
687
|
+
// fan-out draws). For a plain (non-lens) decomposition all three collectors return `[]`,
|
|
688
|
+
// so this path pays nothing.
|
|
689
|
+
const extraConstraints = [
|
|
690
|
+
...lensRowLocalConstraints(ctx, view),
|
|
691
|
+
...lensForeignKeyConstraints(ctx, view),
|
|
692
|
+
...lensSetLevelConstraints(ctx, view),
|
|
693
|
+
];
|
|
694
|
+
const riddenConstraints = new Set();
|
|
695
|
+
const baseOps = plan.ops.map(op => buildDecompositionMemberInsert(ctx, stmt, descriptor, envelopeAttrs, envelopeType, op, memberNewRowScope, constraintsForOp(op, extraConstraints, riddenConstraints)));
|
|
696
|
+
// A lens constraint that resolves on NO member op of the fan-out (a cross-member CHECK /
|
|
697
|
+
// FK / set-level key) is silently deferred — trace it so the non-enforcement is visible in
|
|
698
|
+
// debug logs, mirroring the UPDATE fan-out's trace loop in `buildViewMutation`.
|
|
699
|
+
for (const c of extraConstraints) {
|
|
700
|
+
if (!riddenConstraints.has(c)) {
|
|
701
|
+
log('lens constraint %s references write-row columns no member op of the decomposition insert fan-out carries; not enforced on this write', c.name ?? '<anon>');
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
const envelopeSource = buildEnvelopeSource(ctx, view, stmt, plan.suppliedColumns.length);
|
|
705
|
+
const keyDefault = buildKeyDefault(ctx, view, plan.keyDefault, plan.suppliedColumns);
|
|
706
|
+
return new ViewMutationNode(ctx.scope, baseOps, undefined, {
|
|
707
|
+
source: envelopeSource,
|
|
708
|
+
descriptor,
|
|
709
|
+
keyDefault: keyDefault?.node,
|
|
710
|
+
keyDefaultRowDescriptor: keyDefault?.rowDescriptor,
|
|
711
|
+
});
|
|
712
|
+
}
|
|
713
|
+
/**
|
|
714
|
+
* Build the shared envelope shape both insert fan-outs ride: the leading columns
|
|
715
|
+
* are the supplied logical/view columns (positional with the user source), plus a
|
|
716
|
+
* trailing `__shared_key` column when a surrogate is minted. The descriptor is the
|
|
717
|
+
* stitch every base op's `EnvelopeScanNode` shares with the rows the `ViewMutation`
|
|
718
|
+
* emitter materializes once.
|
|
719
|
+
*/
|
|
720
|
+
function buildEnvelopeShape(suppliedColumns, hasMint) {
|
|
721
|
+
const envelopeAttrs = suppliedColumns.map(col => ({
|
|
722
|
+
id: PlanNode.nextAttrId(),
|
|
723
|
+
name: col.name,
|
|
724
|
+
type: col.type,
|
|
725
|
+
sourceRelation: 'envelope',
|
|
726
|
+
}));
|
|
727
|
+
if (hasMint) {
|
|
728
|
+
envelopeAttrs.push({
|
|
729
|
+
id: PlanNode.nextAttrId(),
|
|
730
|
+
name: '__shared_key',
|
|
731
|
+
type: { typeClass: 'scalar', logicalType: INTEGER_TYPE, nullable: false, isReadOnly: false },
|
|
732
|
+
sourceRelation: 'envelope',
|
|
733
|
+
});
|
|
734
|
+
}
|
|
735
|
+
const envelopeType = {
|
|
736
|
+
typeClass: 'relation',
|
|
737
|
+
isReadOnly: true,
|
|
738
|
+
isSet: false,
|
|
739
|
+
columns: envelopeAttrs.map(a => ({ name: a.name, type: a.type })),
|
|
740
|
+
keys: [],
|
|
741
|
+
rowConstraints: [],
|
|
742
|
+
};
|
|
743
|
+
return { envelopeAttrs, envelopeType, descriptor: {} };
|
|
744
|
+
}
|
|
745
|
+
/**
|
|
746
|
+
* Compile the `MutationEnvelope.keyDefault` from the anchor key column's declared
|
|
747
|
+
* `default` AST (or `undefined` when the shared key is directly supplied). The
|
|
748
|
+
* emitter evaluates it once per produced row — with `mutation_ordinal()` resolving
|
|
749
|
+
* to the row's ordinal and any `max()` subquery observing the pre-mutation state
|
|
750
|
+
* (no base write has fired yet). Determinism is validated exactly as a base-column
|
|
751
|
+
* default is on the single-source insert path (skipped under
|
|
752
|
+
* `nondeterministic_schema`), so a `uuid7()`-style default rides the same
|
|
753
|
+
* capture-once-and-thread guarantee.
|
|
754
|
+
*
|
|
755
|
+
* The key default may read a value the INSERT supplies for a sibling view column via
|
|
756
|
+
* `new.<col>` (the same surface as the single-source insert path — e.g.
|
|
757
|
+
* `default (coalesce((select max(rid) from anchor), 0) + new.seq)`). We mint fresh
|
|
758
|
+
* attributes for the supplied envelope columns and build the default against a row
|
|
759
|
+
* scope registering them as `new.<col>` (and bare `<col>`); the returned
|
|
760
|
+
* `rowDescriptor` maps those fresh attribute ids to source-row positions, and the
|
|
761
|
+
* emitter installs it over each source row while evaluating the default. Minting fresh
|
|
762
|
+
* (rather than reusing the `EnvelopeScanNode` attributes) keeps the reference
|
|
763
|
+
* self-contained so the optimizer cannot dangle it.
|
|
764
|
+
*/
|
|
765
|
+
function buildKeyDefault(ctx, view, keyDefault, suppliedColumns) {
|
|
766
|
+
if (!keyDefault)
|
|
767
|
+
return undefined;
|
|
768
|
+
// Fresh attributes for the supplied envelope columns, referenced only by this key
|
|
769
|
+
// default's `new.<col>` column refs and resolved at runtime via the row slot the
|
|
770
|
+
// emitter installs over each source row (key minted before `__shared_key` append).
|
|
771
|
+
const rowAttrs = suppliedColumns.map(col => ({
|
|
772
|
+
id: PlanNode.nextAttrId(),
|
|
773
|
+
name: col.name,
|
|
774
|
+
type: col.type,
|
|
775
|
+
sourceRelation: 'envelope-key-default',
|
|
776
|
+
}));
|
|
777
|
+
const rowScope = buildRowDefaultScope(ctx.scope, suppliedColumns, rowAttrs);
|
|
778
|
+
const node = buildExpression({ ...ctx, scope: rowScope }, keyDefault);
|
|
779
|
+
if (!ctx.db.options.getBooleanOption('nondeterministic_schema')) {
|
|
780
|
+
validateDeterministicDefault(node, '<shared key>', view.name);
|
|
781
|
+
}
|
|
782
|
+
const rowDescriptor = [];
|
|
783
|
+
rowAttrs.forEach((attr, index) => { rowDescriptor[attr.id] = index; });
|
|
784
|
+
return { node, rowDescriptor };
|
|
785
|
+
}
|
|
786
|
+
/**
|
|
787
|
+
* Build one member base insert of a decomposition fan-out: a projection over the
|
|
788
|
+
* shared `EnvelopeScanNode` (key + supplied values, or an EAV triple), re-planned
|
|
789
|
+
* through the ordinary base-table builder so every constraint / conflict / FK /
|
|
790
|
+
* default rule is reused. An optional / EAV op first passes the envelope through a
|
|
791
|
+
* presence `FilterNode` so only rows that supply the component materialize a row.
|
|
792
|
+
*/
|
|
793
|
+
function buildDecompositionMemberInsert(ctx, stmt, descriptor, envelopeAttrs, envelopeType, op,
|
|
794
|
+
/** The produced-row NEW context (`new.<col>` over the supplied envelope columns)
|
|
795
|
+
* threaded into this member's default-build scope (see {@link buildDecompositionInsert}). */
|
|
796
|
+
memberNewRowScope,
|
|
797
|
+
/** The lens constraints (row-local CHECK / child-FK / set-level) gated onto THIS member op
|
|
798
|
+
* by `constraintsForOp` — the single-member-resolvable subset whose every write-row column
|
|
799
|
+
* resolves on this member's table. `[]` for a non-lens decomposition or a member that
|
|
800
|
+
* resolves no obligation (see {@link buildDecompositionInsert}). */
|
|
801
|
+
extraConstraints) {
|
|
802
|
+
let source = new EnvelopeScanNode(ctx.scope, descriptor, envelopeAttrs, envelopeType);
|
|
803
|
+
if (op.presenceGateIndices.length > 0) {
|
|
804
|
+
source = new FilterNode(ctx.scope, source, buildPresenceGate(ctx, envelopeAttrs, op.presenceGateIndices));
|
|
805
|
+
}
|
|
806
|
+
const projections = op.columns.map((col) => {
|
|
807
|
+
if (col.literal !== undefined) {
|
|
808
|
+
// EAV attribute literal — a constant per row, no envelope column.
|
|
809
|
+
const node = buildExpression(ctx, { type: 'literal', value: col.literal });
|
|
810
|
+
return { node, alias: col.baseColumn };
|
|
811
|
+
}
|
|
812
|
+
const envIdx = col.envelopeIndex;
|
|
813
|
+
const attr = envelopeAttrs[envIdx];
|
|
814
|
+
const ref = new ColumnReferenceNode(ctx.scope, { type: 'column', name: attr.name }, attr.type, attr.id, envIdx);
|
|
815
|
+
return { node: ref, alias: col.baseColumn };
|
|
816
|
+
});
|
|
817
|
+
// preserveInputColumns=false → output is exactly the picked columns, positionally
|
|
818
|
+
// aligned to the member insert's target columns.
|
|
819
|
+
const projectedSource = new ProjectNode(ctx.scope, source, projections, undefined, undefined, false);
|
|
820
|
+
const memberInsert = {
|
|
821
|
+
type: 'insert',
|
|
822
|
+
table: { type: 'identifier', name: op.schema.name, schema: op.schema.schemaName },
|
|
823
|
+
columns: op.columns.map(c => c.baseColumn),
|
|
824
|
+
source: { type: 'values', values: [] }, // placeholder — ignored when preBuiltSource is set
|
|
825
|
+
onConflict: stmt.onConflict,
|
|
826
|
+
contextValues: stmt.contextValues,
|
|
827
|
+
schemaPath: stmt.schemaPath,
|
|
828
|
+
loc: stmt.loc,
|
|
829
|
+
};
|
|
830
|
+
// Lens enforcement rides via `extraConstraints`, the per-op-gated subset
|
|
831
|
+
// `buildDecompositionInsert` computed for this member (`constraintsForOp`): a
|
|
832
|
+
// single-member-resolvable obligation (row-local CHECK / child-FK / set-level whose
|
|
833
|
+
// write-row columns all resolve on this member's table) fires on this member insert; a
|
|
834
|
+
// cross-member one resolves on no member op and stays deferred. The same threading seam
|
|
835
|
+
// the single-source insert spine uses (`buildInsertStmt`'s `extraConstraints`), composed
|
|
836
|
+
// here with the `projectedSource` (the envelope projection) — the two params are
|
|
837
|
+
// independent. Leaves `lensRouted = false` (default): a decomposition parent has no single
|
|
838
|
+
// basis spine for the runtime parent-side cascade reverse-map to match, so the marker is
|
|
839
|
+
// moot here (do not "fix" this) — and parent-side FK is not collected for an INSERT anyway.
|
|
840
|
+
// `memberNewRowScope` threads the produced row's `new.<col>` context so this member's
|
|
841
|
+
// defaults resolve against the supplied logical row (not only this member's own columns).
|
|
842
|
+
return buildInsertStmt(ctx, memberInsert, extraConstraints, projectedSource, false, memberNewRowScope);
|
|
843
|
+
}
|
|
844
|
+
/**
|
|
845
|
+
* Build the produced-row NEW context every member insert of a fan-out shares: each
|
|
846
|
+
* supplied logical column registered as `new.<col>` (and the bare form, unless a
|
|
847
|
+
* member shadows it) over the shared envelope attributes — the same `new.<col>`
|
|
848
|
+
* surface the single-source insert path exposes, lifted to the produced *logical*
|
|
849
|
+
* row. A member insert's default-build scope parents on this, so a default can
|
|
850
|
+
* correlate on a sibling supplied column the member's own base table does not carry.
|
|
851
|
+
* The envelope attributes it references stay resolvable through each member insert's
|
|
852
|
+
* pipeline because the narrowing envelope projection keeps its source row bound.
|
|
853
|
+
*/
|
|
854
|
+
function buildMemberDefaultRowScope(ctx, suppliedColumns, envelopeAttrs) {
|
|
855
|
+
return buildRowDefaultScope(ctx.scope, suppliedColumns, envelopeAttrs);
|
|
856
|
+
}
|
|
857
|
+
/**
|
|
858
|
+
* A scope resolving each envelope column by name to a `ColumnReferenceNode` over the
|
|
859
|
+
* materialized envelope rows (by the attribute's stable id + position). Shared by
|
|
860
|
+
* {@link buildPresenceGate} and {@link buildGatedKeyProjection}, so a parsed predicate /
|
|
861
|
+
* CASE over the envelope columns binds identically to the inlined plan nodes.
|
|
862
|
+
*/
|
|
863
|
+
function envelopeColumnScope(ctx, envelopeAttrs) {
|
|
864
|
+
const scope = new RegisteredScope(ctx.scope);
|
|
865
|
+
envelopeAttrs.forEach((attr, i) => {
|
|
866
|
+
scope.registerSymbol(attr.name.toLowerCase(), (exp, s) => new ColumnReferenceNode(s, exp, attr.type, attr.id, i));
|
|
867
|
+
});
|
|
868
|
+
return scope;
|
|
869
|
+
}
|
|
870
|
+
/** The `<col> is not null` OR-disjunction over the envelope columns named by `indices`. */
|
|
871
|
+
function presencePredicateSql(envelopeAttrs, indices) {
|
|
872
|
+
return indices.map(i => `${quoteIdent(envelopeAttrs[i].name)} is not null`).join(' or ');
|
|
873
|
+
}
|
|
874
|
+
/**
|
|
875
|
+
* Build the per-row presence predicate gating an optional / EAV member insert:
|
|
876
|
+
* `<col> is not null [or <col> is not null …]` over the envelope columns named by
|
|
877
|
+
* `gateIndices`. Resolved against a scope registering the envelope attributes (by
|
|
878
|
+
* their stable ids), so the predicate reads the materialized envelope rows.
|
|
879
|
+
*/
|
|
880
|
+
function buildPresenceGate(ctx, envelopeAttrs, gateIndices) {
|
|
881
|
+
const gateScope = envelopeColumnScope(ctx, envelopeAttrs);
|
|
882
|
+
const ast = parseExpressionString(presencePredicateSql(envelopeAttrs, gateIndices));
|
|
883
|
+
return buildExpression({ ...ctx, scope: gateScope }, ast);
|
|
884
|
+
}
|
|
885
|
+
/**
|
|
886
|
+
* Build the conditional shared-key projection for an FK-child side whose key column
|
|
887
|
+
* must not dangle: `case when <pred> then "<keyCol>" else null end`, where `<pred>` is
|
|
888
|
+
* the AND, over each presence-gated FK-parent partner, of that partner's presence
|
|
889
|
+
* predicate (the OR of its supplied columns being non-null). When every referenced
|
|
890
|
+
* partner is absent for a row, the key projects null — the correct "no partner" marker —
|
|
891
|
+
* so the preserved FK-child row does not reference a shared key with no partner row
|
|
892
|
+
* (§ Outer Joins — Inserts). `keyEnvIdx` names the key column (the appended
|
|
893
|
+
* `__shared_key` or a supplied key view column); resolved against the same envelope
|
|
894
|
+
* column scope {@link buildPresenceGate} uses.
|
|
895
|
+
*/
|
|
896
|
+
function buildGatedKeyProjection(ctx, envelopeAttrs, keyEnvIdx, groups) {
|
|
897
|
+
const scope = envelopeColumnScope(ctx, envelopeAttrs);
|
|
898
|
+
const pred = groups.map(g => `(${presencePredicateSql(envelopeAttrs, g)})`).join(' and ');
|
|
899
|
+
const keyCol = quoteIdent(envelopeAttrs[keyEnvIdx].name);
|
|
900
|
+
const ast = parseExpressionString(`case when ${pred} then ${keyCol} else null end`);
|
|
901
|
+
return buildExpression({ ...ctx, scope }, ast);
|
|
902
|
+
}
|
|
903
|
+
/**
|
|
904
|
+
* Build the envelope source — the user's INSERT source (VALUES / SELECT), whose
|
|
905
|
+
* output columns are the supplied view columns in order. The emitter materializes
|
|
906
|
+
* it once; downstream the `EnvelopeScanNode` reads those rows back (plus the
|
|
907
|
+
* appended minted key) for every base side.
|
|
908
|
+
*/
|
|
909
|
+
function buildEnvelopeSource(ctx, view, stmt, suppliedCount) {
|
|
910
|
+
switch (stmt.source.type) {
|
|
911
|
+
case 'values': {
|
|
912
|
+
const node = buildValuesStmt(ctx, stmt.source);
|
|
913
|
+
assertSourceArity(view, node.getType().columns.length, suppliedCount);
|
|
914
|
+
return node;
|
|
915
|
+
}
|
|
916
|
+
case 'select': {
|
|
917
|
+
const node = buildSelectStmt(ctx, stmt.source);
|
|
918
|
+
if (!isRelationalNode(node)) {
|
|
919
|
+
raiseMutationDiagnostic({ reason: 'no-base-lineage', table: view.name, message: `cannot insert through view '${view.name}': the SELECT source did not produce a relation` });
|
|
920
|
+
}
|
|
921
|
+
assertSourceArity(view, node.getType().columns.length, suppliedCount);
|
|
922
|
+
return node;
|
|
923
|
+
}
|
|
924
|
+
default:
|
|
925
|
+
raiseMutationDiagnostic({
|
|
926
|
+
reason: 'unsupported-source',
|
|
927
|
+
table: view.name,
|
|
928
|
+
message: `cannot insert through view '${view.name}': a multi-source (join) insert supports a VALUES or SELECT source (DML-as-source is a later phase)`,
|
|
929
|
+
});
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
function assertSourceArity(view, got, expected) {
|
|
933
|
+
if (got !== expected) {
|
|
934
|
+
raiseMutationDiagnostic({
|
|
935
|
+
reason: 'no-base-lineage',
|
|
936
|
+
table: view.name,
|
|
937
|
+
message: `cannot insert through view '${view.name}': the source supplies ${got} value(s) but ${expected} view column(s) are targeted`,
|
|
938
|
+
});
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
function quoteIdent(name) {
|
|
942
|
+
return `"${name.replace(/"/g, '""')}"`;
|
|
943
|
+
}
|
|
944
|
+
/**
|
|
945
|
+
* Filter the lens-synthesized `extraConstraints` to those a base op can build: a
|
|
946
|
+
* constraint rides `op` iff every write-row column it references resolves on the op's
|
|
947
|
+
* target-table columns (case-insensitive). Each constraint that rides ≥1 op is recorded
|
|
948
|
+
* in `ridden` so the caller can trace any that rode none (a silently-deferred cross-member
|
|
949
|
+
* CHECK/FK, or a dropped uniqueness scan on a key-unchanged UPDATE).
|
|
950
|
+
*
|
|
951
|
+
* The write-row column set comes from one of two sources. A lens-synthesized **row-local
|
|
952
|
+
* CHECK** carries `referencedWriteRowColumns` — prover-supplied lowercased basis names
|
|
953
|
+
* (`collectLensRowLocalConstraints`) — which is preferred because the AST walk
|
|
954
|
+
* ({@link writeRowColumns}) under-collects a correlated bare write-row ref that appears
|
|
955
|
+
* only inside a subquery (a subquery-bearing row-local CHECK, which the prover still
|
|
956
|
+
* classifies `enforced-row-local`). The FK / set-level classes leave it undefined and fall
|
|
957
|
+
* back to the walk, which collects their `NEW.*` / `OLD.*` refs unambiguously anywhere.
|
|
958
|
+
*
|
|
959
|
+
* `extraConstraints` is exclusively lens-synthesized (the basis table's own checks are
|
|
960
|
+
* added inside `buildConstraintChecks` from `tableSchema.checkConstraints`, never via
|
|
961
|
+
* this seam), so gating every entry is safe.
|
|
962
|
+
*
|
|
963
|
+
* `op` is typed structurally on just its `table` so BOTH fan-out op shapes satisfy it: a
|
|
964
|
+
* `BaseOp` (the single-source spine and the multi-source / decomposition UPDATE + DELETE
|
|
965
|
+
* fan-out) and a `DecompInsertOp` (the decomposition INSERT fan-out, which routes per
|
|
966
|
+
* member through {@link buildDecompositionInsert} — not via `buildBaseOp`). Both carry the
|
|
967
|
+
* member's `TableReferenceNode`, so `op.table.tableSchema.columns` resolves the member's
|
|
968
|
+
* columns directly for either.
|
|
969
|
+
*/
|
|
970
|
+
function constraintsForOp(op, extraConstraints, ridden) {
|
|
971
|
+
if (extraConstraints.length === 0)
|
|
972
|
+
return [];
|
|
973
|
+
const opCols = new Set(op.table.tableSchema.columns.map(c => c.name.toLowerCase()));
|
|
974
|
+
const kept = [];
|
|
975
|
+
for (const c of extraConstraints) {
|
|
976
|
+
// Prefer the prover-supplied row-local metadata (already lowercased basis names);
|
|
977
|
+
// fall back to the AST walk for FK / set-level constraints (which leave it undefined).
|
|
978
|
+
const refs = c.referencedWriteRowColumns ?? writeRowColumns(c.expr);
|
|
979
|
+
let resolvable = true;
|
|
980
|
+
for (const col of refs) {
|
|
981
|
+
if (!opCols.has(col)) {
|
|
982
|
+
resolvable = false;
|
|
983
|
+
break;
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
if (resolvable) {
|
|
987
|
+
ridden.add(c);
|
|
988
|
+
kept.push(c);
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
return kept;
|
|
992
|
+
}
|
|
993
|
+
/**
|
|
994
|
+
* The lowercased set of **write-row** column names a lens-synthesized constraint
|
|
995
|
+
* references — the columns that must resolve on a base op's target table for the
|
|
996
|
+
* constraint to build there. Two reference classes count:
|
|
997
|
+
* - any `NEW.*` / `OLD.*`-qualified column **anywhere** (including nested in a
|
|
998
|
+
* subquery): the correlated write-row side of a set-level count subquery, a child-FK
|
|
999
|
+
* `EXISTS`, or a parent-FK `NOT EXISTS` (+ its UPDATE short-circuit guard);
|
|
1000
|
+
* - any **bare** (unqualified) column **not** inside a subquery: a row-local CHECK
|
|
1001
|
+
* rewritten to bare basis terms (`rewriteToBasisTerms`), whose bare top-level ref is a
|
|
1002
|
+
* write-row ref.
|
|
1003
|
+
* Subquery-internal bare / alias-qualified refs (the count subquery's `_u.docKey`, an FK
|
|
1004
|
+
* child/parent alias) are assumed to resolve against the subquery's own FROM, not the
|
|
1005
|
+
* write row, so they are ignored.
|
|
1006
|
+
*
|
|
1007
|
+
* That subquery-free assumption is now only ever applied to the FK / set-level classes,
|
|
1008
|
+
* whose bare-in-subquery refs are genuinely FROM-resolved aliases. The **row-local CHECK**
|
|
1009
|
+
* class no longer reaches this walk: a subquery-bearing row-local CHECK could carry a
|
|
1010
|
+
* *correlated* bare write-row ref inside its subquery (the prover does not forbid a
|
|
1011
|
+
* subquery in a row-local CHECK), which this walk would under-collect, so the gate prefers
|
|
1012
|
+
* the prover-supplied `referencedWriteRowColumns` metadata for that class (see
|
|
1013
|
+
* {@link constraintsForOp} and `collectLensRowLocalConstraints`).
|
|
1014
|
+
*/
|
|
1015
|
+
function writeRowColumns(expr) {
|
|
1016
|
+
const cols = new Set();
|
|
1017
|
+
collectWriteRowColumns(expr, false, cols);
|
|
1018
|
+
return cols;
|
|
1019
|
+
}
|
|
1020
|
+
/** Walk an expression collecting write-row column names (see {@link writeRowColumns}). */
|
|
1021
|
+
function collectWriteRowColumns(expr, insideSubquery, cols) {
|
|
1022
|
+
switch (expr.type) {
|
|
1023
|
+
case 'column': {
|
|
1024
|
+
const qualifier = expr.table?.toLowerCase();
|
|
1025
|
+
if (qualifier === 'new' || qualifier === 'old') {
|
|
1026
|
+
cols.add(expr.name.toLowerCase());
|
|
1027
|
+
}
|
|
1028
|
+
else if (!insideSubquery && !expr.table && !expr.schema) {
|
|
1029
|
+
cols.add(expr.name.toLowerCase());
|
|
1030
|
+
}
|
|
1031
|
+
return;
|
|
1032
|
+
}
|
|
1033
|
+
case 'binary':
|
|
1034
|
+
collectWriteRowColumns(expr.left, insideSubquery, cols);
|
|
1035
|
+
collectWriteRowColumns(expr.right, insideSubquery, cols);
|
|
1036
|
+
return;
|
|
1037
|
+
case 'unary':
|
|
1038
|
+
case 'cast':
|
|
1039
|
+
case 'collate':
|
|
1040
|
+
collectWriteRowColumns(expr.expr, insideSubquery, cols);
|
|
1041
|
+
return;
|
|
1042
|
+
case 'function':
|
|
1043
|
+
expr.args.forEach(a => collectWriteRowColumns(a, insideSubquery, cols));
|
|
1044
|
+
return;
|
|
1045
|
+
case 'between':
|
|
1046
|
+
collectWriteRowColumns(expr.expr, insideSubquery, cols);
|
|
1047
|
+
collectWriteRowColumns(expr.lower, insideSubquery, cols);
|
|
1048
|
+
collectWriteRowColumns(expr.upper, insideSubquery, cols);
|
|
1049
|
+
return;
|
|
1050
|
+
case 'case':
|
|
1051
|
+
if (expr.baseExpr)
|
|
1052
|
+
collectWriteRowColumns(expr.baseExpr, insideSubquery, cols);
|
|
1053
|
+
expr.whenThenClauses.forEach(w => {
|
|
1054
|
+
collectWriteRowColumns(w.when, insideSubquery, cols);
|
|
1055
|
+
collectWriteRowColumns(w.then, insideSubquery, cols);
|
|
1056
|
+
});
|
|
1057
|
+
if (expr.elseExpr)
|
|
1058
|
+
collectWriteRowColumns(expr.elseExpr, insideSubquery, cols);
|
|
1059
|
+
return;
|
|
1060
|
+
case 'in':
|
|
1061
|
+
collectWriteRowColumns(expr.expr, insideSubquery, cols);
|
|
1062
|
+
if (expr.values)
|
|
1063
|
+
expr.values.forEach(v => collectWriteRowColumns(v, insideSubquery, cols));
|
|
1064
|
+
if (expr.subquery)
|
|
1065
|
+
collectQueryWriteRowColumns(expr.subquery, cols);
|
|
1066
|
+
return;
|
|
1067
|
+
case 'subquery':
|
|
1068
|
+
collectQueryWriteRowColumns(expr.query, cols);
|
|
1069
|
+
return;
|
|
1070
|
+
case 'exists':
|
|
1071
|
+
collectQueryWriteRowColumns(expr.subquery, cols);
|
|
1072
|
+
return;
|
|
1073
|
+
default:
|
|
1074
|
+
// literal / identifier / parameter / windowFunction / functionSource — no
|
|
1075
|
+
// write-row column ref to collect.
|
|
1076
|
+
return;
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
/**
|
|
1080
|
+
* Descend into a subquery operand collecting only its `NEW.*` / `OLD.*`-qualified
|
|
1081
|
+
* (correlated write-row) refs — bare / alias-qualified refs resolve against the
|
|
1082
|
+
* subquery's own FROM and are skipped (`insideSubquery = true`).
|
|
1083
|
+
*/
|
|
1084
|
+
function collectQueryWriteRowColumns(query, cols) {
|
|
1085
|
+
if (query.type === 'select') {
|
|
1086
|
+
for (const rc of query.columns) {
|
|
1087
|
+
if (rc.type !== 'all')
|
|
1088
|
+
collectWriteRowColumns(rc.expr, true, cols);
|
|
1089
|
+
}
|
|
1090
|
+
if (query.from)
|
|
1091
|
+
query.from.forEach(fc => collectFromWriteRowColumns(fc, cols));
|
|
1092
|
+
if (query.where)
|
|
1093
|
+
collectWriteRowColumns(query.where, true, cols);
|
|
1094
|
+
if (query.groupBy)
|
|
1095
|
+
query.groupBy.forEach(e => collectWriteRowColumns(e, true, cols));
|
|
1096
|
+
if (query.having)
|
|
1097
|
+
collectWriteRowColumns(query.having, true, cols);
|
|
1098
|
+
if (query.orderBy)
|
|
1099
|
+
query.orderBy.forEach(ob => collectWriteRowColumns(ob.expr, true, cols));
|
|
1100
|
+
if (query.limit)
|
|
1101
|
+
collectWriteRowColumns(query.limit, true, cols);
|
|
1102
|
+
if (query.offset)
|
|
1103
|
+
collectWriteRowColumns(query.offset, true, cols);
|
|
1104
|
+
if (query.compound)
|
|
1105
|
+
collectQueryWriteRowColumns(query.compound.select, cols);
|
|
1106
|
+
if (query.union)
|
|
1107
|
+
collectQueryWriteRowColumns(query.union, cols);
|
|
1108
|
+
return;
|
|
1109
|
+
}
|
|
1110
|
+
if (query.type === 'values') {
|
|
1111
|
+
query.values.forEach(row => row.forEach(e => collectWriteRowColumns(e, true, cols)));
|
|
1112
|
+
}
|
|
1113
|
+
// An INSERT/UPDATE/DELETE … RETURNING subquery: lens collectors never synthesize one,
|
|
1114
|
+
// so there is nothing to collect.
|
|
1115
|
+
}
|
|
1116
|
+
/** Collect write-row refs in a subquery's FROM (join conditions, TVF args, nested subqueries). */
|
|
1117
|
+
function collectFromWriteRowColumns(fc, cols) {
|
|
1118
|
+
switch (fc.type) {
|
|
1119
|
+
case 'table':
|
|
1120
|
+
return;
|
|
1121
|
+
case 'join':
|
|
1122
|
+
collectFromWriteRowColumns(fc.left, cols);
|
|
1123
|
+
collectFromWriteRowColumns(fc.right, cols);
|
|
1124
|
+
if (fc.condition)
|
|
1125
|
+
collectWriteRowColumns(fc.condition, true, cols);
|
|
1126
|
+
return;
|
|
1127
|
+
case 'functionSource':
|
|
1128
|
+
fc.args.forEach(a => collectWriteRowColumns(a, true, cols));
|
|
1129
|
+
return;
|
|
1130
|
+
case 'subquerySource':
|
|
1131
|
+
collectQueryWriteRowColumns(fc.subquery, cols);
|
|
1132
|
+
return;
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
/**
|
|
1136
|
+
* Re-plan one base op through the matching base-table builder. `extraConstraints`
|
|
1137
|
+
* carries the lens-routed CHECKs (basis terms) to merge into the per-row check
|
|
1138
|
+
* pipeline: row-local / child-FK / set-level for insert+update, and the parent-side
|
|
1139
|
+
* FK `NOT EXISTS` for update **and delete** (a delete can orphan a logical child, so
|
|
1140
|
+
* the delete base op now threads them too). The caller (`buildViewMutation`) has already
|
|
1141
|
+
* gated `extraConstraints` per op via {@link constraintsForOp}, so the single-source spine
|
|
1142
|
+
* (one base op carrying all basis columns) receives the full set and a multi-op UPDATE /
|
|
1143
|
+
* DELETE fan-out receives only the obligations that resolve on this op's table. The
|
|
1144
|
+
* decomposition INSERT fan-out also routes per member, but through
|
|
1145
|
+
* {@link buildDecompositionMemberInsert} (which calls `buildInsertStmt` against the shared
|
|
1146
|
+
* envelope) rather than this path — so it runs the same gate independently there.
|
|
1147
|
+
*/
|
|
1148
|
+
function buildBaseOp(ctx, op, extraConstraints, lensRouted) {
|
|
1149
|
+
switch (op.op) {
|
|
1150
|
+
case 'insert':
|
|
1151
|
+
return buildInsertStmt(ctx, op.statement, extraConstraints, undefined, lensRouted);
|
|
1152
|
+
case 'update':
|
|
1153
|
+
return buildUpdateStmt(ctx, op.statement, extraConstraints, lensRouted);
|
|
1154
|
+
case 'delete':
|
|
1155
|
+
return buildDeleteStmt(ctx, op.statement, extraConstraints, lensRouted);
|
|
1156
|
+
}
|
|
1157
|
+
}
|
|
1158
|
+
//# sourceMappingURL=view-mutation-builder.js.map
|