@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,1096 @@
|
|
|
1
|
+
import { isRelationalNode } from '../nodes/plan-node.js';
|
|
2
|
+
import { StatusCode } from '../../common/types.js';
|
|
3
|
+
import { QuereusError } from '../../common/errors.js';
|
|
4
|
+
import { sqlValuesEqual } from '../../util/comparison.js';
|
|
5
|
+
import { buildSelectStmt } from '../building/select.js';
|
|
6
|
+
import { classifyViewBody } from './propagate.js';
|
|
7
|
+
import { raiseMutationDiagnostic } from './mutation-diagnostic.js';
|
|
8
|
+
import { deriveViewColumns, resolveBaseSite } from '../analysis/update-lineage.js';
|
|
9
|
+
import { ProjectNode } from '../nodes/project-node.js';
|
|
10
|
+
import { ColumnReferenceNode } from '../nodes/reference.js';
|
|
11
|
+
import { requireValidatedNewRefIndex } from '../analysis/authored-inverse.js';
|
|
12
|
+
import { expressionToString } from '../../emit/ast-stringify.js';
|
|
13
|
+
import { transformExpr, cloneExpr, substituteNewRefs, transformScopedExpr, transformScopedQuery } from './scope-transform.js';
|
|
14
|
+
import { isMaintainedTable } from '../../schema/derivation.js';
|
|
15
|
+
import { bodyDefaults } from '../../schema/view.js';
|
|
16
|
+
/**
|
|
17
|
+
* Reserved, collision-proof correlation name synthesised onto the lowered
|
|
18
|
+
* single-source UPDATE/DELETE target. The `__` internal-name convention (same family
|
|
19
|
+
* as `__vmupd_keys` / `__shared_key`) guarantees it cannot collide with any
|
|
20
|
+
* user-introduced FROM source, so a substituted subquery-descent base term qualified
|
|
21
|
+
* with it (`__vm_self.col`) always binds the outer target row — even when the user
|
|
22
|
+
* subquery FROM names the view's own base table. Lowered-target nesting cannot occur
|
|
23
|
+
* (view-over-view / MV-over-MV / view-over-MV are all rejected by `analyzeView`, and a
|
|
24
|
+
* user subquery is a plain SELECT that never re-lowers), so a single module-level
|
|
25
|
+
* constant suffices: two `__vm_self`-aliased targets can never be in scope at once.
|
|
26
|
+
*
|
|
27
|
+
* The **multi-source** per-side lowered UPDATE (`multi-source.ts`) reuses this same
|
|
28
|
+
* constant: each per-side op is a flat single-table base UPDATE, planned independently
|
|
29
|
+
* through this same base builder and never co-scoped or nested with another lowered
|
|
30
|
+
* target, so the same "at most one `__vm_self` in scope" invariant holds. The per-side
|
|
31
|
+
* UPDATE carries `alias: SELF_ALIAS`, and its capture read-back owning-PK operands and
|
|
32
|
+
* owning-side strip-to-bare refs are qualified with it, so a correlation reference
|
|
33
|
+
* emitted inside a user value subquery binds the target row rather than re-binding to a
|
|
34
|
+
* same-named column in the subquery's own FROM (the multi-source analog of the
|
|
35
|
+
* single-source qualification below).
|
|
36
|
+
*/
|
|
37
|
+
export const SELF_ALIAS = '__vm_self';
|
|
38
|
+
function columnExpr(name) {
|
|
39
|
+
return { type: 'column', name };
|
|
40
|
+
}
|
|
41
|
+
function tableIdentifier(table) {
|
|
42
|
+
return { type: 'identifier', name: table.name, schema: table.schemaName };
|
|
43
|
+
}
|
|
44
|
+
/** Flatten a conjunction (`a AND b AND c`) into its conjuncts. */
|
|
45
|
+
export function flattenAnd(expr) {
|
|
46
|
+
if (expr.type === 'binary' && expr.operator === 'AND') {
|
|
47
|
+
return [...flattenAnd(expr.left), ...flattenAnd(expr.right)];
|
|
48
|
+
}
|
|
49
|
+
return [expr];
|
|
50
|
+
}
|
|
51
|
+
/** Conjoin two optional predicates with AND. */
|
|
52
|
+
export function combineAnd(a, b) {
|
|
53
|
+
if (a && b)
|
|
54
|
+
return { type: 'binary', operator: 'AND', left: a, right: b };
|
|
55
|
+
return a ?? b;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Rewrite base-term column references so they resolve against the single base
|
|
59
|
+
* table after the rewrite. The view body may qualify its base columns by the
|
|
60
|
+
* source's alias or the base table name (`x.col` / `pa.col`); the rewritten
|
|
61
|
+
* statement has exactly one source, so those qualifiers are dropped (an
|
|
62
|
+
* unqualified reference resolves unambiguously). This normalizes the **view
|
|
63
|
+
* body's own** projection / WHERE terms (already in base terms); it does not
|
|
64
|
+
* descend into subqueries, which is correct here — the body's own subqueries are
|
|
65
|
+
* conjoined / projected verbatim, not re-bound against view columns. The
|
|
66
|
+
* **user** predicate / assigned-value descent (where a nested reference can name
|
|
67
|
+
* a *view* column) is handled separately by {@link makeViewColumnDescend}.
|
|
68
|
+
*/
|
|
69
|
+
function normalizeBaseRefs(expr, aliases) {
|
|
70
|
+
return transformExpr(expr, (col) => col.table && aliases.has(col.table.toLowerCase()) ? { type: 'column', name: col.name } : undefined);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Build the closure that correlation-qualifies a substituted base *term* emitted
|
|
74
|
+
* INSIDE a subquery operand of a single-source rewrite. An unqualified base term
|
|
75
|
+
* there would re-bind to a same-named source the subquery's own FROM introduces
|
|
76
|
+
* (innermost SQL scoping) instead of correlating to the outer UPDATE/DELETE target
|
|
77
|
+
* row. Qualifying it with `qualifierName` makes it correlate to the outer row
|
|
78
|
+
* regardless of what the subquery FROM defines. For UPDATE/DELETE the caller passes
|
|
79
|
+
* the lowered target's synthesised collision-proof alias ({@link SELF_ALIAS}), so the
|
|
80
|
+
* qualified term binds the outer row even when the subquery FROM names the view's own
|
|
81
|
+
* base table; INSERT leaves it at the base table name (no target-row scan to collide
|
|
82
|
+
* with). Default is the bare base table name.
|
|
83
|
+
*
|
|
84
|
+
* The qualification is **scope-aware and DEEP** (it rides the shared
|
|
85
|
+
* {@link transformScopedExpr} descent over {@link makeBaseQualifyScope}): it
|
|
86
|
+
* qualifies a base-table column at the replacement's top level, and descends into a
|
|
87
|
+
* nested scalar subquery WITHIN the replacement (a computed lineage term such as
|
|
88
|
+
* `(select x from oth where fk = id)`), qualifying only the lineage's own
|
|
89
|
+
* correlation refs — a base column not shadowed by the lineage subquery's own FROM
|
|
90
|
+
* — and leaving the lineage's genuinely-local columns alone. The multi-source
|
|
91
|
+
* spine has its own analog (`makeSideQualifyScope` in multi-source.ts), which
|
|
92
|
+
* qualifies a bare lineage leaf with its owning side's alias.
|
|
93
|
+
*
|
|
94
|
+
* Returns a fresh tree (does not mutate the shared `columnMap` entry).
|
|
95
|
+
*/
|
|
96
|
+
function makeBaseQualifier(ctx, baseTable, qualifierName = baseTable.name) {
|
|
97
|
+
const scope = makeBaseQualifyScope(baseTable, qualifierName);
|
|
98
|
+
return (repl) => transformScopedExpr(ctx, scope, repl);
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* The {@link ScopeContext} for the base-term correlation-qualifier — the
|
|
102
|
+
* scope-aware DEEP qualify of a substituted base term. Its substitution qualifies
|
|
103
|
+
* an unqualified BASE-table column that is not shadowed with `qualifierName` — the
|
|
104
|
+
* lowered statement's correlation name (the synthesised {@link SELF_ALIAS} for
|
|
105
|
+
* UPDATE/DELETE, the bare base table name for INSERT / multi-source). An
|
|
106
|
+
* already-qualified ref, a non-base name (a lineage-local column such as the `x` /
|
|
107
|
+
* `fk` a nested subquery's own FROM introduces), or a shadowed name is left untouched.
|
|
108
|
+
* Restricting to base columns changes nothing for a `normalizeBaseRefs`-normalized
|
|
109
|
+
* lineage (whose top-level refs are all base columns) and is the principled gate: only
|
|
110
|
+
* the view's own base-term lineage is correlation-qualified, never a column a nested
|
|
111
|
+
* source owns.
|
|
112
|
+
*
|
|
113
|
+
* An unresolvable scope (`select *` / TVF / CTE) is **rejected** rather than
|
|
114
|
+
* tainted-and-deferred: shadowing cannot be proven, so the term could over- or
|
|
115
|
+
* under-qualify into a silent wrong write (`unresolvableScope: 'reject'`).
|
|
116
|
+
*/
|
|
117
|
+
function makeBaseQualifyScope(baseTable, qualifierName = baseTable.name) {
|
|
118
|
+
const qualifier = qualifierName;
|
|
119
|
+
const baseCols = new Set(baseTable.columns.map(c => c.name.toLowerCase()));
|
|
120
|
+
return {
|
|
121
|
+
makeSubstitute: (shadowed) => (col) => {
|
|
122
|
+
if (col.table)
|
|
123
|
+
return undefined;
|
|
124
|
+
const name = col.name.toLowerCase();
|
|
125
|
+
if (shadowed.has(name) || !baseCols.has(name))
|
|
126
|
+
return undefined;
|
|
127
|
+
return { ...col, table: qualifier };
|
|
128
|
+
},
|
|
129
|
+
unresolvableScope: 'reject',
|
|
130
|
+
rejectUnresolvableScope: () => raiseMutationDiagnostic({
|
|
131
|
+
reason: 'unsupported-subquery-correlation',
|
|
132
|
+
message: `cannot write through view: a computed column's lineage contains a correlated subquery whose source columns are not statically resolvable (a 'select *' / table-valued function / unresolved source), so its correlation cannot be proven; restructure the view body`,
|
|
133
|
+
}),
|
|
134
|
+
rejectDmlSubquery: () => raiseMutationDiagnostic({
|
|
135
|
+
reason: 'unsupported-subquery-correlation',
|
|
136
|
+
message: `cannot correlation-qualify a view lineage term: a data-modifying subquery (INSERT/UPDATE/DELETE) within it cannot be analysed`,
|
|
137
|
+
}),
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
// --- view-column descent into subquery operands ---------------------------
|
|
141
|
+
//
|
|
142
|
+
// `transformExpr` rewrites a view-column reference at the top level of a user
|
|
143
|
+
// predicate / assigned value. A reference nested inside a `subquery` / `exists` /
|
|
144
|
+
// `in`-subquery operand resolves in the *lowered* base statement's scope, where
|
|
145
|
+
// it can silently re-bind to a same-named base column instead of the view
|
|
146
|
+
// column's true lineage. The descent below (the shared scope-transform over
|
|
147
|
+
// {@link makeViewScope}) rewrites such a nested reference to its base term — but
|
|
148
|
+
// scope-aware, so it neither mis-binds a reference a subquery-local source
|
|
149
|
+
// introduces (`in (select note from src)` where `src.note` exists) nor touches a
|
|
150
|
+
// base-alias-qualified reference. A reference it cannot prove correlated (an
|
|
151
|
+
// unresolvable subquery source) is rejected loudly rather than mis-bound silently.
|
|
152
|
+
// See `docs/view-updateability.md` § Selection.
|
|
153
|
+
/**
|
|
154
|
+
* The {@link ScopeContext} for the view-column → base-term descent. A reference is
|
|
155
|
+
* rewritten to its base-term lineage only when it is genuinely correlated to the
|
|
156
|
+
* outer view row:
|
|
157
|
+
*
|
|
158
|
+
* - **qualified by the view name** → an unambiguous view-output reference;
|
|
159
|
+
* substitute (when the name is a known view column).
|
|
160
|
+
* - **unqualified**, a known view column, and NOT shadowed by a source local to
|
|
161
|
+
* this (or an enclosing) subquery scope → correlated to the outer view row;
|
|
162
|
+
* substitute.
|
|
163
|
+
* - **qualified by any other (base-alias) name**, or a name some local source
|
|
164
|
+
* introduces → left untouched.
|
|
165
|
+
*
|
|
166
|
+
* In a **tainted** scope (one whose local column names could not be resolved
|
|
167
|
+
* statically) an unqualified view-column-named reference cannot be proven
|
|
168
|
+
* correlated, so it is rejected with `unsupported-subquery-correlation` rather than
|
|
169
|
+
* silently mis-bound — hence `unresolvableScope: 'taint'` (the substitution decides
|
|
170
|
+
* per-reference once tainted, instead of rejecting the whole scope up front).
|
|
171
|
+
*
|
|
172
|
+
* When a replacement is emitted inside a subquery operand, `baseQualify`
|
|
173
|
+
* correlation-qualifies its base terms (scope-aware and deep — see
|
|
174
|
+
* {@link makeBaseQualifier}) so they bind to the outer (UPDATE/DELETE target) row
|
|
175
|
+
* rather than re-binding to a same-named local source. The single-source rewriters
|
|
176
|
+
* pass it; the multi-source spine passes its side-alias qualifier
|
|
177
|
+
* (`makeSideQualifyScope`), which qualifies a bare lineage leaf with its owning
|
|
178
|
+
* side's alias. `resolve` returns a fresh tree, never the shared `columnMap`
|
|
179
|
+
* entry.
|
|
180
|
+
*/
|
|
181
|
+
function makeViewScope(columnMap, viewName, view, baseQualify) {
|
|
182
|
+
const lcView = viewName.toLowerCase();
|
|
183
|
+
const resolve = (name) => {
|
|
184
|
+
const repl = columnMap.get(name);
|
|
185
|
+
if (!repl || !baseQualify)
|
|
186
|
+
return repl;
|
|
187
|
+
return baseQualify(repl);
|
|
188
|
+
};
|
|
189
|
+
return {
|
|
190
|
+
makeSubstitute: (shadowed, tainted, aliasShadowed) => (col) => {
|
|
191
|
+
const name = col.name.toLowerCase();
|
|
192
|
+
if (col.table) {
|
|
193
|
+
const lcQual = col.table.toLowerCase();
|
|
194
|
+
// A view-name-qualified ref (`t.id`) is normally an unambiguous outer
|
|
195
|
+
// view-output correlation, rewritten to its base-term lineage. BUT when the
|
|
196
|
+
// SAME name is a locally-shadowed FROM alias — the user-predicate self-read
|
|
197
|
+
// `select t.id from t` over the eager capture — `t.id` is the capture's own
|
|
198
|
+
// column, not an outer correlation; leave it local (innermost-scope SQL
|
|
199
|
+
// rules) so it binds to the captured snapshot rather than a de-correlated
|
|
200
|
+
// `__vm_self`-qualified base term (docs/view-updateability.md § Common Table
|
|
201
|
+
// Expressions — self-reference). Other ScopeContext implementers never reach
|
|
202
|
+
// this branch with an aliased self-read (no own-name to shadow).
|
|
203
|
+
if (aliasShadowed.has(lcQual))
|
|
204
|
+
return undefined;
|
|
205
|
+
return lcQual === lcView ? resolve(name) : undefined;
|
|
206
|
+
}
|
|
207
|
+
if (shadowed.has(name))
|
|
208
|
+
return undefined;
|
|
209
|
+
if (!columnMap.has(name))
|
|
210
|
+
return undefined;
|
|
211
|
+
if (tainted) {
|
|
212
|
+
raiseMutationDiagnostic({
|
|
213
|
+
reason: 'unsupported-subquery-correlation',
|
|
214
|
+
table: view.name,
|
|
215
|
+
column: col.name,
|
|
216
|
+
message: `cannot write through view '${view.name}': the reference '${col.name}' inside a subquery cannot be proven correlated to the view because the subquery's source columns are not statically resolvable (a 'select *' / table-valued function / unresolved source); qualify the reference with its base table or alias, or restructure the predicate`,
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
return resolve(name);
|
|
220
|
+
},
|
|
221
|
+
unresolvableScope: 'taint',
|
|
222
|
+
rejectDmlSubquery: () => raiseMutationDiagnostic({
|
|
223
|
+
reason: 'unsupported-subquery-correlation',
|
|
224
|
+
table: view.name,
|
|
225
|
+
message: `cannot write through view '${view.name}': a data-modifying subquery (INSERT/UPDATE/DELETE) in a predicate or assigned value cannot be analysed for view-column correlation`,
|
|
226
|
+
}),
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Build the `descend` transformer threaded into the top-level {@link transformExpr}
|
|
231
|
+
* calls on a user predicate / assigned value, so a view-column reference nested in
|
|
232
|
+
* a `subquery` / `exists` / `in`-subquery operand is rewritten scope-aware to its
|
|
233
|
+
* base-term lineage. `columnMap` is the view-col (lowercase) → base-term map;
|
|
234
|
+
* `viewName` is the view's own name (so a `view.col` qualifier is recognised).
|
|
235
|
+
*
|
|
236
|
+
* `baseQualify` is the single-source lowered statement's correlation qualifier
|
|
237
|
+
* (built by {@link makeBaseQualifier} from the base table); the multi-source spine
|
|
238
|
+
* passes its side-alias qualifier (`makeSideQualifyScope`), which qualifies a bare
|
|
239
|
+
* lineage leaf with its owning side's alias. See {@link makeViewScope}.
|
|
240
|
+
*/
|
|
241
|
+
export function makeViewColumnDescend(ctx, columnMap, viewName, view, baseQualify) {
|
|
242
|
+
const scope = makeViewScope(columnMap, viewName, view, baseQualify);
|
|
243
|
+
return (query) => transformScopedQuery(ctx, scope, query, new Set(), false);
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Plan the view body, gate it for phase-1 mutability, and derive the
|
|
247
|
+
* view→base column model. Throws a structured diagnostic on any unsupported
|
|
248
|
+
* shape.
|
|
249
|
+
*/
|
|
250
|
+
function analyzeView(ctx, view) {
|
|
251
|
+
// Lens read-only gate: a logical table whose primary key is not reconstructible
|
|
252
|
+
// at the lens boundary deploys read-only (the prover sets `LensSlot.readOnly`;
|
|
253
|
+
// docs/lens.md § Coverage checklist). Reads still resolve through the registered
|
|
254
|
+
// view; any mutation errors here with a precise diagnostic. The lookup only
|
|
255
|
+
// matches a logical schema's lens slot — a plain view / MV (physical schema) has
|
|
256
|
+
// none, so this never false-positives on ordinary view write-through.
|
|
257
|
+
const lensSlot = ctx.schemaManager.getSchema(view.schemaName)?.getLensSlot(view.name);
|
|
258
|
+
if (lensSlot?.readOnly) {
|
|
259
|
+
raiseMutationDiagnostic({
|
|
260
|
+
reason: 'lens-read-only',
|
|
261
|
+
table: view.name,
|
|
262
|
+
message: `cannot write through logical table '${view.schemaName}.${view.name}': its primary key is not reconstructible at the lens boundary, so it is read-only (deploy advisory lens.pk-not-reconstructible)`,
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
if (view.selectAst.type !== 'select') {
|
|
266
|
+
raiseMutationDiagnostic({
|
|
267
|
+
reason: 'no-base-lineage',
|
|
268
|
+
table: view.name,
|
|
269
|
+
message: `${view.noun ?? 'view'} '${view.name}' has a ${view.selectAst.type.toUpperCase()} body, which has no recoverable base operation`,
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
const sel = view.selectAst;
|
|
273
|
+
// Build the body plan and gate it (joins / aggregates / set-ops / recursive
|
|
274
|
+
// CTEs / VALUES bodies are rejected here).
|
|
275
|
+
const bodyPlan = buildSelectStmt(ctx, sel);
|
|
276
|
+
if (!isRelationalNode(bodyPlan)) {
|
|
277
|
+
raiseMutationDiagnostic({
|
|
278
|
+
reason: 'no-base-lineage',
|
|
279
|
+
table: view.name,
|
|
280
|
+
message: `${view.noun ?? 'view'} '${view.name}' body did not produce a relation`,
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
const classification = classifyViewBody(bodyPlan);
|
|
284
|
+
if (classification.kind === 'rejected') {
|
|
285
|
+
raiseMutationDiagnostic({
|
|
286
|
+
reason: classification.reason,
|
|
287
|
+
table: view.name,
|
|
288
|
+
// Name the target by its kind (`view.noun`) so a body-shape reject on a
|
|
289
|
+
// maintained table reads "materialized view 'm'", not the misleading
|
|
290
|
+
// plain-view framing. A maintained table reaches this and the sibling
|
|
291
|
+
// body-shape branches below — e.g. an aggregate-bodied MV here, or a
|
|
292
|
+
// subquery-in-FROM MV at the single-base-source branch — so every
|
|
293
|
+
// body-shape diagnostic in this function honours the noun.
|
|
294
|
+
message: `cannot write through ${view.noun ?? 'view'} '${view.name}': ${classification.detail}`,
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
const baseTable = classification.baseTable.tableSchema;
|
|
298
|
+
// Single-level base-table source only: a body that sources another view/CTE
|
|
299
|
+
// inlines to one table ref but its inner filters/projections live in the
|
|
300
|
+
// plan, not in this view's selectAst — driving the rewrite from selectAst
|
|
301
|
+
// would silently drop them. Reject (the inline-and-propagate generality is
|
|
302
|
+
// a later phase).
|
|
303
|
+
if (!sel.from || sel.from.length !== 1 || sel.from[0].type !== 'table') {
|
|
304
|
+
raiseMutationDiagnostic({
|
|
305
|
+
reason: 'nested-view',
|
|
306
|
+
table: view.name,
|
|
307
|
+
message: `cannot write through ${view.noun ?? 'view'} '${view.name}': only a single base-table source is supported in phase 1`,
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
const fromTable = sel.from[0];
|
|
311
|
+
if (ctx.schemaManager.getView(fromTable.table.schema ?? null, fromTable.table.name)) {
|
|
312
|
+
raiseMutationDiagnostic({
|
|
313
|
+
reason: 'nested-view',
|
|
314
|
+
table: view.name,
|
|
315
|
+
message: `cannot write through ${view.noun ?? 'view'} '${view.name}': its body references another view; nested-view mutation is not yet supported`,
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
// MV-over-MV (or a plain view over an MV): the body's single source is itself a
|
|
319
|
+
// maintained table, whose contents are derived — user DML may not write it
|
|
320
|
+
// directly. Write-through one level down (route to the inner MV's own
|
|
321
|
+
// write-through + the maintenance cascade) is deferred; reject cleanly. The
|
|
322
|
+
// source→backing maintenance cascade is unaffected — that is the read/maintain
|
|
323
|
+
// direction; this guards only the MV-name *write* direction.
|
|
324
|
+
// Checked both by name (current-schema default) and on the PLAN-resolved base
|
|
325
|
+
// table — the body's FROM resolves through the schema path, which can reach a
|
|
326
|
+
// maintained table the name lookup misses.
|
|
327
|
+
if (ctx.schemaManager.getMaintainedTable(fromTable.table.schema ?? null, fromTable.table.name)
|
|
328
|
+
|| isMaintainedTable(baseTable)) {
|
|
329
|
+
raiseMutationDiagnostic({
|
|
330
|
+
reason: 'nested-view',
|
|
331
|
+
table: view.name,
|
|
332
|
+
message: `cannot write through '${view.name}': its body reads a materialized view; `
|
|
333
|
+
+ `write-through to a materialized-view-over-materialized-view is not yet supported — write the base source instead`,
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
// LIMIT / OFFSET / DISTINCT are accepted by the plan-walk classifier as
|
|
337
|
+
// pass-through operators (so it can still reach the base table), but the
|
|
338
|
+
// predicate-conjoin rewrite cannot faithfully reproduce them: a row-count
|
|
339
|
+
// window or duplicate-collapse is not capturable as a WHERE predicate, so a
|
|
340
|
+
// mutation would affect base rows outside what the view exposes. Reject here
|
|
341
|
+
// rather than silently widening the write. (Phase 2 substrate territory.)
|
|
342
|
+
if (sel.limit || sel.offset) {
|
|
343
|
+
raiseMutationDiagnostic({
|
|
344
|
+
reason: 'unsupported-limit',
|
|
345
|
+
table: view.name,
|
|
346
|
+
message: `cannot write through ${view.noun ?? 'view'} '${view.name}': a LIMIT/OFFSET body is not decomposable in phase 1 (a mutation would escape the limited window)`,
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
if (sel.distinct) {
|
|
350
|
+
raiseMutationDiagnostic({
|
|
351
|
+
reason: 'unsupported-distinct',
|
|
352
|
+
table: view.name,
|
|
353
|
+
message: `cannot write through ${view.noun ?? 'view'} '${view.name}': a DISTINCT body has no 1:1 base-row lineage and is not updateable in phase 1`,
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
// Names that qualify the single base source inside the body — its alias (if
|
|
357
|
+
// any) and the table name as written. References so qualified are normalized
|
|
358
|
+
// to unqualified form when threaded into the rewritten single-source statement.
|
|
359
|
+
const baseAliases = new Set([fromTable.table.name.toLowerCase()]);
|
|
360
|
+
if (fromTable.alias)
|
|
361
|
+
baseAliases.add(fromTable.alias.toLowerCase());
|
|
362
|
+
// Build the view-column lineage model from the projection list (shared with
|
|
363
|
+
// the update-lineage analysis surface).
|
|
364
|
+
const viewColumns = deriveViewColumns(sel, baseTable, view.columns);
|
|
365
|
+
// Build the remap table: each view column → its base-term replacement
|
|
366
|
+
// (computed expressions are normalized so any alias-qualified base column
|
|
367
|
+
// resolves against the rewritten single-source statement).
|
|
368
|
+
const columnMap = new Map();
|
|
369
|
+
for (const vc of viewColumns) {
|
|
370
|
+
columnMap.set(vc.name.toLowerCase(), vc.lineage.kind === 'base' ? columnExpr(vc.lineage.baseColumnName) : normalizeBaseRefs(vc.lineage.expr, baseAliases));
|
|
371
|
+
}
|
|
372
|
+
const filterConstants = extractFilterConstants(sel.where, baseTable);
|
|
373
|
+
const filterPredicate = sel.where ? normalizeBaseRefs(sel.where, baseAliases) : undefined;
|
|
374
|
+
// Writable-base write sites (UPDATE SET + INSERT): read the threaded plan-node
|
|
375
|
+
// `updateLineage` off the already-planned body and, per view column, capture
|
|
376
|
+
// EVERY writable, non-null-extended base column (identity / passthrough /
|
|
377
|
+
// inverse) with its optional backward `inverse` closure. This is the
|
|
378
|
+
// single-source dual of what the multi-source spine consumes (whose
|
|
379
|
+
// `OutColumn.writable` is likewise the inverse-agnostic `base`-not-null-extended
|
|
380
|
+
// site). The identity-only AST readers (`deriveViewColumns` /
|
|
381
|
+
// `classifyProjectionExpr` / `viewColumnsFromUpdateLineage`) are deliberately NOT
|
|
382
|
+
// widened — their parity is pinned by `test/property.spec.ts` — so the richer
|
|
383
|
+
// `base` chain is read separately here via the shared `resolveBaseSite`. The UPDATE
|
|
384
|
+
// SET path routes any site (applying its `inverse` when present); INSERT
|
|
385
|
+
// (`rewriteViewInsert`) admits only the inverse-absent subset (identity + passthrough,
|
|
386
|
+
// stored verbatim). A passthrough (`collate` / no-op `cast`) or identity / rename
|
|
387
|
+
// column carries no `inverse`; an `inverse` column carries its closure (UPDATE-only —
|
|
388
|
+
// non-insertable); an `opaque` / null-extended column has no site, so a write to it
|
|
389
|
+
// still raises `no-inverse` via `requireBaseColumn`.
|
|
390
|
+
// `viewColumns[i]` ↔ `attrs[i]` holds because `deriveViewColumns` and the planned
|
|
391
|
+
// projection expand `select *` identically (the parity `viewColumnsFromUpdateLineage`
|
|
392
|
+
// relies on); a `*` column is pure identity, stored verbatim like any other.
|
|
393
|
+
const relBody = bodyPlan;
|
|
394
|
+
const attrs = relBody.getAttributes();
|
|
395
|
+
const lineage = relBody.physical.updateLineage;
|
|
396
|
+
const writableSites = new Map();
|
|
397
|
+
viewColumns.forEach((vc, i) => {
|
|
398
|
+
const site = resolveBaseSite(lineage?.get(attrs[i]?.id));
|
|
399
|
+
if (!site.writable || site.nullExtended)
|
|
400
|
+
return;
|
|
401
|
+
if (site.authored) {
|
|
402
|
+
// An authored (`with inverse`) site — writable and insertable through its
|
|
403
|
+
// put expressions. Single-source: every put target is a column of THE base
|
|
404
|
+
// table (the lineage routed each through the sole TableReferenceNode), so
|
|
405
|
+
// the table discriminator is dropped here.
|
|
406
|
+
writableSites.set(vc.name.toLowerCase(), {
|
|
407
|
+
kind: 'authored',
|
|
408
|
+
puts: site.authored.puts.map(p => ({ baseColumn: p.baseColumn, expr: p.expr })),
|
|
409
|
+
newRefIndex: site.authored.newRefIndex,
|
|
410
|
+
});
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
if (site.baseColumn) {
|
|
414
|
+
writableSites.set(vc.name.toLowerCase(), {
|
|
415
|
+
kind: 'base',
|
|
416
|
+
baseColumn: site.baseColumn,
|
|
417
|
+
...(site.inverse ? { inverse: site.inverse } : {}),
|
|
418
|
+
// No shipped invertibility profile produces a `domain` (`x ± k` is
|
|
419
|
+
// unrestricted over integers), so this is always absent today. Threaded
|
|
420
|
+
// for parity with multi-source (`multi-source.ts` decomposeUpdate), not
|
|
421
|
+
// yet conjoined into the identifying predicate — the documented deferral.
|
|
422
|
+
...(site.domain ? { domain: site.domain } : {}),
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
});
|
|
426
|
+
return { baseTable, viewColumns, filterPredicate, filterConstants, columnMap, writableSites };
|
|
427
|
+
}
|
|
428
|
+
/**
|
|
429
|
+
* Build the eager **CTE self-read capture** for a CTE-name DML target whose user
|
|
430
|
+
* clauses self-read the target name (docs/view-updateability.md § Common Table
|
|
431
|
+
* Expressions — self-reference). The capture is the FULL body relation — every view
|
|
432
|
+
* column, **unfiltered** (the self-read `from t` is the whole relation, exactly a
|
|
433
|
+
* materialized CTE) — projected over the body planned under `ctx` (the **target-
|
|
434
|
+
* excluded** body context, so the body's own `from base` reaches the REAL base table,
|
|
435
|
+
* the load-bearing shadow case). It rides {@link import('../nodes/view-mutation-node.js').ViewMutationNode}'s
|
|
436
|
+
* `identityCapture`, which the emitter materializes ONCE before any base op runs — so
|
|
437
|
+
* the lowered base op's `from t` reads the pre-mutation snapshot, Halloween-safe by
|
|
438
|
+
* construction.
|
|
439
|
+
*
|
|
440
|
+
* Mirrors `set-op.ts`'s `buildSetOpCapture`, minus the user-WHERE filter (the whole
|
|
441
|
+
* relation, not just the affected rows — a self-read names the entire CTE). Returns a
|
|
442
|
+
* {@link MultiSourceKeyCapture} so the readers reuse `makeMultiSourceKeyRef` /
|
|
443
|
+
* `withCteCapture` and the existing `identityCapture` side-input substrate verbatim.
|
|
444
|
+
*
|
|
445
|
+
* Deliberately plans the body a SECOND time (alongside `analyzeView`'s own body plan,
|
|
446
|
+
* threaded through `rewriteViewUpdate`/`Delete`): a localization tradeoff the ticket
|
|
447
|
+
* accepts — the body is a cheap single-source projection-and-filter, and the capture's
|
|
448
|
+
* projection over a freshly-planned root keeps the descriptor self-contained.
|
|
449
|
+
*/
|
|
450
|
+
export function buildCteSelfCapture(ctx, view) {
|
|
451
|
+
// Gate + derive the view-column model (names honour a `t(a,b)` rename via
|
|
452
|
+
// `deriveViewColumns`; an unsupported body shape rejects here just as the lowering's
|
|
453
|
+
// own `analyzeView` would).
|
|
454
|
+
const analysis = analyzeView(ctx, view);
|
|
455
|
+
const sel = view.selectAst; // analyzeView already proved a SELECT body
|
|
456
|
+
const bodyPlan = buildSelectStmt(ctx, sel);
|
|
457
|
+
const attrs = bodyPlan.getAttributes();
|
|
458
|
+
// One capture column per view column, positionally aligned to the body plan's
|
|
459
|
+
// attributes (the `viewColumns[i] ↔ attrs[i]` parity `analyzeView` relies on). The
|
|
460
|
+
// renamed name is the capture column name, so a self-read `from t` exposes the
|
|
461
|
+
// renamed columns; the type/id come from the planned attribute.
|
|
462
|
+
const projections = analysis.viewColumns.map((vc, i) => {
|
|
463
|
+
const attr = attrs[i];
|
|
464
|
+
const node = new ColumnReferenceNode(ctx.scope, { type: 'column', name: vc.name }, attr.type, attr.id, i);
|
|
465
|
+
return { node, alias: vc.name };
|
|
466
|
+
});
|
|
467
|
+
// preserveInputColumns=false → the materialized rows are exactly the view columns.
|
|
468
|
+
const source = new ProjectNode(ctx.scope, bodyPlan, projections, undefined, undefined, false);
|
|
469
|
+
const keyColumns = analysis.viewColumns.map((vc, i) => ({ name: vc.name, type: attrs[i].type }));
|
|
470
|
+
return { source, descriptor: {}, keyColumns };
|
|
471
|
+
}
|
|
472
|
+
/** Extract `baseColumn = literal` bindings from the view's selection predicate. */
|
|
473
|
+
function extractFilterConstants(where, baseTable) {
|
|
474
|
+
const out = [];
|
|
475
|
+
if (!where)
|
|
476
|
+
return out;
|
|
477
|
+
for (const conj of flattenAnd(where)) {
|
|
478
|
+
if (conj.type !== 'binary' || conj.operator !== '=')
|
|
479
|
+
continue;
|
|
480
|
+
const colSide = conj.left.type === 'column' ? conj.left : conj.right.type === 'column' ? conj.right : undefined;
|
|
481
|
+
const litSide = conj.left.type === 'literal' ? conj.left : conj.right.type === 'literal' ? conj.right : undefined;
|
|
482
|
+
if (!colSide || !litSide)
|
|
483
|
+
continue;
|
|
484
|
+
const baseCol = baseTable.columns.find(c => c.name.toLowerCase() === colSide.name.toLowerCase());
|
|
485
|
+
if (!baseCol)
|
|
486
|
+
continue;
|
|
487
|
+
const value = litSide.value instanceof Promise ? undefined : litSide.value;
|
|
488
|
+
out.push({ baseColumnName: baseCol.name, valueExpr: litSide, value });
|
|
489
|
+
}
|
|
490
|
+
return out;
|
|
491
|
+
}
|
|
492
|
+
function findViewColumn(analysis, name, view) {
|
|
493
|
+
const vc = analysis.viewColumns.find(c => c.name.toLowerCase() === name.toLowerCase());
|
|
494
|
+
if (!vc) {
|
|
495
|
+
// A `set` target / `insert` target column that is not a view column at all —
|
|
496
|
+
// the same encapsulation-leak guard the top-level `where` / `returning` scan
|
|
497
|
+
// applies (a base-only column must not be writable through the view). Computed
|
|
498
|
+
// view columns ARE found here and surface the `no-inverse` diagnostic instead.
|
|
499
|
+
raiseUnknownViewColumn(name, view, analysis.viewColumns.map(c => c.name));
|
|
500
|
+
}
|
|
501
|
+
return vc;
|
|
502
|
+
}
|
|
503
|
+
/**
|
|
504
|
+
* Visit every column reference at the TOP LEVEL of a scalar expression — i.e. NOT
|
|
505
|
+
* descending into a `subquery` / `exists` / `in`-subquery operand (those nested
|
|
506
|
+
* references resolve in the lowered base scope and are handled scope-aware by
|
|
507
|
+
* {@link makeViewColumnDescend}; the nested-rebind correctness ticket
|
|
508
|
+
* `view-mutation-single-source-subquery-base-term-local-rebind` owns them). The
|
|
509
|
+
* structure mirrors {@link transformExpr} exactly, minus the subquery descent.
|
|
510
|
+
*/
|
|
511
|
+
function forEachTopLevelColumn(expr, visit) {
|
|
512
|
+
switch (expr.type) {
|
|
513
|
+
case 'column':
|
|
514
|
+
visit(expr);
|
|
515
|
+
return;
|
|
516
|
+
case 'binary':
|
|
517
|
+
forEachTopLevelColumn(expr.left, visit);
|
|
518
|
+
forEachTopLevelColumn(expr.right, visit);
|
|
519
|
+
return;
|
|
520
|
+
case 'unary':
|
|
521
|
+
case 'cast':
|
|
522
|
+
case 'collate':
|
|
523
|
+
forEachTopLevelColumn(expr.expr, visit);
|
|
524
|
+
return;
|
|
525
|
+
case 'function':
|
|
526
|
+
expr.args.forEach(a => forEachTopLevelColumn(a, visit));
|
|
527
|
+
return;
|
|
528
|
+
case 'between':
|
|
529
|
+
forEachTopLevelColumn(expr.expr, visit);
|
|
530
|
+
forEachTopLevelColumn(expr.lower, visit);
|
|
531
|
+
forEachTopLevelColumn(expr.upper, visit);
|
|
532
|
+
return;
|
|
533
|
+
case 'case':
|
|
534
|
+
if (expr.baseExpr)
|
|
535
|
+
forEachTopLevelColumn(expr.baseExpr, visit);
|
|
536
|
+
expr.whenThenClauses.forEach(w => { forEachTopLevelColumn(w.when, visit); forEachTopLevelColumn(w.then, visit); });
|
|
537
|
+
if (expr.elseExpr)
|
|
538
|
+
forEachTopLevelColumn(expr.elseExpr, visit);
|
|
539
|
+
return;
|
|
540
|
+
case 'in':
|
|
541
|
+
forEachTopLevelColumn(expr.expr, visit);
|
|
542
|
+
if (expr.values)
|
|
543
|
+
expr.values.forEach(v => forEachTopLevelColumn(v, visit));
|
|
544
|
+
// expr.subquery is a nested scope — intentionally not descended.
|
|
545
|
+
return;
|
|
546
|
+
default:
|
|
547
|
+
// subquery / exists — nested scope, not validated here.
|
|
548
|
+
// literal / identifier / parameter / windowFunction / functionSource —
|
|
549
|
+
// no top-level column reference to validate.
|
|
550
|
+
return;
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
/**
|
|
554
|
+
* Raise the structured `unknown-view-column` diagnostic for a reference that names
|
|
555
|
+
* something the view does not expose. `displayColumns` is the view's exposed column
|
|
556
|
+
* list (in display spelling) for the suggestion.
|
|
557
|
+
*/
|
|
558
|
+
export function raiseUnknownViewColumn(spelling, view, displayColumns) {
|
|
559
|
+
raiseMutationDiagnostic({
|
|
560
|
+
reason: 'unknown-view-column',
|
|
561
|
+
column: spelling,
|
|
562
|
+
table: view.name,
|
|
563
|
+
message: `cannot write through view '${view.name}': '${spelling}' is not a column of the view`,
|
|
564
|
+
suggestion: `view '${view.name}' exposes: ${displayColumns.join(', ')}.`,
|
|
565
|
+
});
|
|
566
|
+
}
|
|
567
|
+
/**
|
|
568
|
+
* Enforce **view-column scope** on the TOP-LEVEL references of a user `where` /
|
|
569
|
+
* `returning` clause (the `set` targets are guarded separately at their resolution
|
|
570
|
+
* point). Without this, a name that is not a view column passes through the
|
|
571
|
+
* view→base remap unmapped and silently re-binds against the underlying base
|
|
572
|
+
* table(s) — an encapsulation leak letting a column the view projects away be
|
|
573
|
+
* filtered / returned. A reference must name a column the view exposes, optionally
|
|
574
|
+
* qualified by the view's own name; a bare base-column name (`secret`), a renamed
|
|
575
|
+
* column's base spelling (`label` for a `… as note` projection), or a view-qualified
|
|
576
|
+
* unknown (`sv.secret`) are all rejected. A computed view column passes here (it IS
|
|
577
|
+
* a view column) so a write to it still surfaces the existing `no-inverse`
|
|
578
|
+
* diagnostic. Shared by the single-source spine and the multi-source join path so
|
|
579
|
+
* the two read consistently.
|
|
580
|
+
*/
|
|
581
|
+
/** Single-source convenience: build the scope sets from a {@link ViewAnalysis}. */
|
|
582
|
+
function guardTopLevelScope(expr, analysis, view) {
|
|
583
|
+
assertTopLevelViewColumns(expr, new Set(analysis.viewColumns.map(c => c.name.toLowerCase())), analysis.viewColumns.map(c => c.name), view);
|
|
584
|
+
}
|
|
585
|
+
export function assertTopLevelViewColumns(expr, viewColumnNames, displayColumns, view) {
|
|
586
|
+
const lcView = view.name.toLowerCase();
|
|
587
|
+
forEachTopLevelColumn(expr, (col) => {
|
|
588
|
+
const qualifier = col.table?.toLowerCase();
|
|
589
|
+
const known = viewColumnNames.has(col.name.toLowerCase());
|
|
590
|
+
if ((qualifier !== undefined && qualifier !== lcView) || !known) {
|
|
591
|
+
raiseUnknownViewColumn(col.table ? `${col.table}.${col.name}` : col.name, view, displayColumns);
|
|
592
|
+
}
|
|
593
|
+
});
|
|
594
|
+
}
|
|
595
|
+
/** Resolve a view column to a writable base column, rejecting computed columns. */
|
|
596
|
+
function requireBaseColumn(vc) {
|
|
597
|
+
if (vc.lineage.kind === 'computed') {
|
|
598
|
+
raiseMutationDiagnostic({
|
|
599
|
+
reason: 'no-inverse',
|
|
600
|
+
column: vc.name,
|
|
601
|
+
message: `cannot write through view: column '${vc.name}' is a computed (non-invertible) expression and is read-only`,
|
|
602
|
+
});
|
|
603
|
+
}
|
|
604
|
+
return vc.lineage.baseColumnName;
|
|
605
|
+
}
|
|
606
|
+
/**
|
|
607
|
+
* Resolve an insert-default column name (from the body's `with defaults (col = expr, …)`
|
|
608
|
+
* clause) to its base column. The name may be a base column (the documented
|
|
609
|
+
* projected-away case) or a view column with `base` lineage. An unknown name is
|
|
610
|
+
* a structured `default-target-not-found` — a typo must fail loudly, not silently
|
|
611
|
+
* no-op. `spelling` names the offending clause entry in the diagnostic.
|
|
612
|
+
*/
|
|
613
|
+
function resolveDefaultForColumn(analysis, colName, view, spelling) {
|
|
614
|
+
const baseCol = analysis.baseTable.columns.find(c => c.name.toLowerCase() === colName);
|
|
615
|
+
if (baseCol)
|
|
616
|
+
return baseCol.name;
|
|
617
|
+
const vc = analysis.viewColumns.find(c => c.name.toLowerCase() === colName);
|
|
618
|
+
if (vc && vc.lineage.kind === 'base')
|
|
619
|
+
return vc.lineage.baseColumnName;
|
|
620
|
+
raiseMutationDiagnostic({
|
|
621
|
+
reason: 'default-target-not-found',
|
|
622
|
+
column: colName,
|
|
623
|
+
table: view.name,
|
|
624
|
+
message: `cannot write through view '${view.name}': ${spelling} names column '${colName}', which is not a column of the view or its base table '${analysis.baseTable.name}'`,
|
|
625
|
+
});
|
|
626
|
+
}
|
|
627
|
+
/** Build a substitution fn that remaps view column references to base terms. */
|
|
628
|
+
function remapper(analysis) {
|
|
629
|
+
return (col) => analysis.columnMap.get(col.name.toLowerCase());
|
|
630
|
+
}
|
|
631
|
+
// --- INSERT ---------------------------------------------------------------
|
|
632
|
+
export function rewriteViewInsert(ctx, stmt, view) {
|
|
633
|
+
const analysis = analyzeView(ctx, view);
|
|
634
|
+
// A view column is INSERTABLE iff it has a writable base site with NO inverse:
|
|
635
|
+
// `identity` / rename and `passthrough` (`b collate nocase`, no-op `cast`), whose
|
|
636
|
+
// inserted value is stored verbatim. An `inverse` column (a site WITH an inverse) and
|
|
637
|
+
// an `opaque` computed column (no site) are NOT insertable — the lowering writes the
|
|
638
|
+
// value raw, with no hook to apply an inverse. This is exactly the multi-source
|
|
639
|
+
// contract (`outColumns.filter(c => c.writable && !c.inverse)`), so the single- and
|
|
640
|
+
// multi-source INSERT spines now admit the identical set. (A bare "has a site" gate
|
|
641
|
+
// would wrongly admit an inverse column; the `inverse === undefined` check is load-bearing.)
|
|
642
|
+
// An AUTHORED (`with inverse`) column is the exception that supplies exactly that
|
|
643
|
+
// hook: it IS insertable — its puts are evaluated per VALUES row below — so the
|
|
644
|
+
// insertability gate is lifted for authored sites only (registry-`inverse` columns
|
|
645
|
+
// stay non-insertable; docs/view-updateability.md § Authored inverses).
|
|
646
|
+
const insertableBaseColumn = (name) => {
|
|
647
|
+
const site = analysis.writableSites.get(name.toLowerCase());
|
|
648
|
+
return site?.kind === 'base' && site.inverse === undefined ? site.baseColumn : undefined;
|
|
649
|
+
};
|
|
650
|
+
const authoredSiteOf = (name) => {
|
|
651
|
+
const site = analysis.writableSites.get(name.toLowerCase());
|
|
652
|
+
return site?.kind === 'authored' ? site : undefined;
|
|
653
|
+
};
|
|
654
|
+
// Target view columns: the explicit list, or every non-generated INSERTABLE view
|
|
655
|
+
// column (display order preserved) — verbatim-insertable or authored. An exposed
|
|
656
|
+
// `inverse` / `opaque` computed column is omitted from the implicit set so it falls
|
|
657
|
+
// to its base default / NOT NULL check (matching multi-source) rather than erroring.
|
|
658
|
+
const targetNames = stmt.columns && stmt.columns.length > 0
|
|
659
|
+
? stmt.columns
|
|
660
|
+
: analysis.viewColumns
|
|
661
|
+
.filter(vc => !vc.generated && (insertableBaseColumn(vc.name) !== undefined || authoredSiteOf(vc.name) !== undefined))
|
|
662
|
+
.map(vc => vc.name);
|
|
663
|
+
if (targetNames.some(name => authoredSiteOf(name) !== undefined)) {
|
|
664
|
+
return rewriteAuthoredViewInsert(ctx, stmt, view, analysis, targetNames, insertableBaseColumn, authoredSiteOf);
|
|
665
|
+
}
|
|
666
|
+
// Resolve each target to its writable base column: an insertable writable site
|
|
667
|
+
// (identity + passthrough) routes to its base column; otherwise fall back to
|
|
668
|
+
// `requireBaseColumn` (the identity base column, or `no-inverse` for an inverse /
|
|
669
|
+
// opaque column). `findViewColumn` stays the unknown-view-column guard on the fallback.
|
|
670
|
+
const baseColumns = targetNames.map(name => insertableBaseColumn(name) ?? requireBaseColumn(findViewColumn(analysis, name, view)));
|
|
671
|
+
// Merge the view's constant-FD defaults: a base column pinned by the
|
|
672
|
+
// selection predicate is supplied automatically when omitted, and a
|
|
673
|
+
// user-supplied literal that contradicts the pin is rejected at plan time.
|
|
674
|
+
const { appendColumns, appendExprs } = collectAppendedDefaults(analysis, view, baseColumns, (fc, idx) => checkContradiction(stmt.source, idx, fc, view));
|
|
675
|
+
const finalColumns = [...baseColumns, ...appendColumns];
|
|
676
|
+
let source = stmt.source;
|
|
677
|
+
if (appendExprs.length > 0) {
|
|
678
|
+
if (stmt.source.type !== 'values') {
|
|
679
|
+
raiseMutationDiagnostic({
|
|
680
|
+
reason: 'unsupported-source',
|
|
681
|
+
table: view.name,
|
|
682
|
+
message: `cannot write through view '${view.name}': supplying selection-predicate defaults requires a VALUES source in phase 1`,
|
|
683
|
+
});
|
|
684
|
+
}
|
|
685
|
+
source = {
|
|
686
|
+
type: 'values',
|
|
687
|
+
values: stmt.source.values.map(row => [...row, ...appendExprs.map(cloneExpr)]),
|
|
688
|
+
};
|
|
689
|
+
}
|
|
690
|
+
return {
|
|
691
|
+
type: 'insert',
|
|
692
|
+
table: tableIdentifier(analysis.baseTable),
|
|
693
|
+
columns: finalColumns,
|
|
694
|
+
source,
|
|
695
|
+
onConflict: stmt.onConflict,
|
|
696
|
+
upsertClauses: stmt.upsertClauses,
|
|
697
|
+
contextValues: stmt.contextValues,
|
|
698
|
+
returning: rewriteViewReturning(ctx, stmt.returning, analysis, view),
|
|
699
|
+
schemaPath: stmt.schemaPath,
|
|
700
|
+
loc: stmt.loc,
|
|
701
|
+
};
|
|
702
|
+
}
|
|
703
|
+
/**
|
|
704
|
+
* Collect the appended omitted-insert defaults shared by both INSERT lowerings:
|
|
705
|
+
* constant-FD selection pins first, then the body's `with defaults (…)` clause
|
|
706
|
+
* entries — each only for a base column the insert left unsupplied
|
|
707
|
+
* (docs/view-updateability.md § Projection step 5, § View defaults).
|
|
708
|
+
* `suppliedBaseColumns` are the base columns the insert targets directly
|
|
709
|
+
* (verbatim targets AND authored put targets — an authored target takes the
|
|
710
|
+
* inverse-computed value ahead of any default for that column: it is a supplied
|
|
711
|
+
* value, not an omission). `onPinnedSupplied` fires for a constant-FD pin whose
|
|
712
|
+
* base column IS supplied, with the index into `suppliedBaseColumns` (the plain
|
|
713
|
+
* path uses it for the literal-contradiction check; the authored path checks
|
|
714
|
+
* only its verbatim subset).
|
|
715
|
+
*/
|
|
716
|
+
function collectAppendedDefaults(analysis, view, suppliedBaseColumns, onPinnedSupplied) {
|
|
717
|
+
const appendColumns = [];
|
|
718
|
+
const appendExprs = [];
|
|
719
|
+
const isSupplied = (baseCol) => suppliedBaseColumns.some(b => b.toLowerCase() === baseCol.toLowerCase())
|
|
720
|
+
|| appendColumns.some(b => b.toLowerCase() === baseCol.toLowerCase());
|
|
721
|
+
for (const fc of analysis.filterConstants) {
|
|
722
|
+
const idx = suppliedBaseColumns.findIndex(b => b.toLowerCase() === fc.baseColumnName.toLowerCase());
|
|
723
|
+
if (idx >= 0) {
|
|
724
|
+
onPinnedSupplied(fc, idx);
|
|
725
|
+
}
|
|
726
|
+
else {
|
|
727
|
+
appendColumns.push(fc.baseColumnName);
|
|
728
|
+
appendExprs.push(fc.valueExpr);
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
// Omitted-insert defaults (the body's trailing `with defaults (…)` clause),
|
|
732
|
+
// applied ahead of the base column's declared default: the clause fills only a
|
|
733
|
+
// column the insert and the constant-FD chain left omitted — an explicit user
|
|
734
|
+
// value or a stronger predicate pin always wins. The clause value is already an
|
|
735
|
+
// AST expression — no text re-lowering. Pushing the schema-held node is safe:
|
|
736
|
+
// the VALUES rewrite clones per row.
|
|
737
|
+
for (const d of bodyDefaults(view.selectAst) ?? []) {
|
|
738
|
+
const baseCol = resolveDefaultForColumn(analysis, d.column.toLowerCase(), view, `'with defaults (${d.column} = …)'`);
|
|
739
|
+
if (isSupplied(baseCol))
|
|
740
|
+
continue;
|
|
741
|
+
appendColumns.push(baseCol);
|
|
742
|
+
appendExprs.push(d.expr);
|
|
743
|
+
}
|
|
744
|
+
return { appendColumns, appendExprs };
|
|
745
|
+
}
|
|
746
|
+
/**
|
|
747
|
+
* The INSERT lowering when ≥1 target view column carries an authored inverse
|
|
748
|
+
* (docs/view-updateability.md § Authored inverses). Per VALUES row, each authored
|
|
749
|
+
* column contributes one cell per put: the authored expression with `new.<x>`
|
|
750
|
+
* bound to the supplied (post-view-defaulting) row values — the row's cell when
|
|
751
|
+
* `x` is a target column, the appended default expression when `x`'s base column
|
|
752
|
+
* is default-filled, NULL otherwise. Verbatim targets keep their cells; the
|
|
753
|
+
* appended defaults ride last, exactly as on the plain path. A SELECT source is
|
|
754
|
+
* rejected (the per-row cell substitution needs VALUES — same v1 boundary as the
|
|
755
|
+
* appended-defaults rewrite).
|
|
756
|
+
*/
|
|
757
|
+
function rewriteAuthoredViewInsert(ctx, stmt, view, analysis, targetNames, insertableBaseColumn, authoredSiteOf) {
|
|
758
|
+
if (stmt.source.type !== 'values') {
|
|
759
|
+
raiseMutationDiagnostic({
|
|
760
|
+
reason: 'unsupported-source',
|
|
761
|
+
table: view.name,
|
|
762
|
+
message: `cannot insert through view '${view.name}': a column with an authored inverse (WITH INVERSE) requires a VALUES source in phase 1 (each put expression is evaluated per supplied row)`,
|
|
763
|
+
});
|
|
764
|
+
}
|
|
765
|
+
const values = stmt.source.values;
|
|
766
|
+
const verbatim = [];
|
|
767
|
+
const authored = [];
|
|
768
|
+
// Base column (lowercased) → the view column that supplies it — two supplied view
|
|
769
|
+
// columns landing on one base column (an authored put colliding with a verbatim
|
|
770
|
+
// target or another put) is ill-defined, mirroring the UPDATE collision guard.
|
|
771
|
+
const baseOwner = new Map();
|
|
772
|
+
const claimBase = (baseColumn, viewColumn) => {
|
|
773
|
+
const key = baseColumn.toLowerCase();
|
|
774
|
+
const prior = baseOwner.get(key);
|
|
775
|
+
if (prior !== undefined) {
|
|
776
|
+
raiseMutationDiagnostic({
|
|
777
|
+
reason: 'conflicting-assignment',
|
|
778
|
+
column: baseColumn,
|
|
779
|
+
table: view.name,
|
|
780
|
+
message: `cannot insert through view '${view.name}': columns '${prior}' and '${viewColumn}' both supply base column '${baseColumn}'`,
|
|
781
|
+
});
|
|
782
|
+
}
|
|
783
|
+
baseOwner.set(key, viewColumn);
|
|
784
|
+
};
|
|
785
|
+
targetNames.forEach((name, srcIndex) => {
|
|
786
|
+
const site = authoredSiteOf(name);
|
|
787
|
+
if (site) {
|
|
788
|
+
for (const put of site.puts)
|
|
789
|
+
claimBase(put.baseColumn, name);
|
|
790
|
+
authored.push({ viewColumn: name, site });
|
|
791
|
+
return;
|
|
792
|
+
}
|
|
793
|
+
const baseColumn = insertableBaseColumn(name) ?? requireBaseColumn(findViewColumn(analysis, name, view));
|
|
794
|
+
claimBase(baseColumn, name);
|
|
795
|
+
verbatim.push({ baseColumn, srcIndex });
|
|
796
|
+
});
|
|
797
|
+
// Appended defaults over the FULL supplied base set (verbatim + authored puts):
|
|
798
|
+
// an authored put target is a supplied value, so it shadows any `with defaults`
|
|
799
|
+
// entry / constant-FD pin for that base column. The literal-contradiction check
|
|
800
|
+
// applies only to verbatim targets (an authored cell is computed, not a literal).
|
|
801
|
+
const suppliedBase = [...verbatim.map(v => v.baseColumn), ...authored.flatMap(a => a.site.puts.map(p => p.baseColumn))];
|
|
802
|
+
const { appendColumns, appendExprs } = collectAppendedDefaults(analysis, view, suppliedBase, (fc, suppliedIndex) => {
|
|
803
|
+
const v = verbatim.find(t => t.baseColumn.toLowerCase() === suppliedBase[suppliedIndex].toLowerCase());
|
|
804
|
+
if (v)
|
|
805
|
+
checkContradiction(stmt.source, v.srcIndex, fc, view);
|
|
806
|
+
});
|
|
807
|
+
// `new.<x>` binding for one row: the supplied cell when `x` is a target view
|
|
808
|
+
// column; the appended default expression when `x` resolves to a default-filled
|
|
809
|
+
// base column (the post-view-defaulting row image); NULL otherwise. `x` is a
|
|
810
|
+
// SELECT-output name, so it bridges POSITIONALLY through the site's validated
|
|
811
|
+
// `newRefIndex` to the view column (an explicit `create view v(a, b)` column
|
|
812
|
+
// list renames outputs — a name lookup against `targetNames` would mis-bind).
|
|
813
|
+
const targetIndexByName = new Map();
|
|
814
|
+
targetNames.forEach((n, i) => {
|
|
815
|
+
if (!targetIndexByName.has(n.toLowerCase()))
|
|
816
|
+
targetIndexByName.set(n.toLowerCase(), i);
|
|
817
|
+
});
|
|
818
|
+
const appendExprFor = (name) => {
|
|
819
|
+
const baseCol = insertableBaseColumn(name);
|
|
820
|
+
if (baseCol === undefined)
|
|
821
|
+
return undefined;
|
|
822
|
+
const ai = appendColumns.findIndex(b => b.toLowerCase() === baseCol.toLowerCase());
|
|
823
|
+
return ai >= 0 ? appendExprs[ai] : undefined;
|
|
824
|
+
};
|
|
825
|
+
const finalColumns = [
|
|
826
|
+
...verbatim.map(v => v.baseColumn),
|
|
827
|
+
...authored.flatMap(a => a.site.puts.map(p => p.baseColumn)),
|
|
828
|
+
...appendColumns,
|
|
829
|
+
];
|
|
830
|
+
const newValues = values.map(row => {
|
|
831
|
+
if (row.length !== targetNames.length) {
|
|
832
|
+
raiseMutationDiagnostic({
|
|
833
|
+
reason: 'unsupported-source',
|
|
834
|
+
table: view.name,
|
|
835
|
+
message: `cannot insert through view '${view.name}': a VALUES row supplies ${row.length} value(s) but ${targetNames.length} view column(s) are targeted`,
|
|
836
|
+
});
|
|
837
|
+
}
|
|
838
|
+
const resolveNewFor = (a) => (name) => {
|
|
839
|
+
const idx = requireValidatedNewRefIndex(a.site.newRefIndex, name, a.viewColumn);
|
|
840
|
+
const viewName = analysis.viewColumns[idx]?.name;
|
|
841
|
+
const ti = viewName !== undefined ? targetIndexByName.get(viewName.toLowerCase()) : undefined;
|
|
842
|
+
if (ti !== undefined)
|
|
843
|
+
return row[ti];
|
|
844
|
+
return (viewName !== undefined ? appendExprFor(viewName) : undefined) ?? { type: 'literal', value: null };
|
|
845
|
+
};
|
|
846
|
+
return [
|
|
847
|
+
...verbatim.map(v => row[v.srcIndex]),
|
|
848
|
+
...authored.flatMap(a => a.site.puts.map(p => substituteNewRefs(p.expr, resolveNewFor(a)))),
|
|
849
|
+
...appendExprs.map(cloneExpr),
|
|
850
|
+
];
|
|
851
|
+
});
|
|
852
|
+
return {
|
|
853
|
+
type: 'insert',
|
|
854
|
+
table: tableIdentifier(analysis.baseTable),
|
|
855
|
+
columns: finalColumns,
|
|
856
|
+
source: { type: 'values', values: newValues },
|
|
857
|
+
onConflict: stmt.onConflict,
|
|
858
|
+
upsertClauses: stmt.upsertClauses,
|
|
859
|
+
contextValues: stmt.contextValues,
|
|
860
|
+
returning: rewriteViewReturning(ctx, stmt.returning, analysis, view),
|
|
861
|
+
schemaPath: stmt.schemaPath,
|
|
862
|
+
loc: stmt.loc,
|
|
863
|
+
};
|
|
864
|
+
}
|
|
865
|
+
/** Reject an insert literal that contradicts a selection-predicate constant. */
|
|
866
|
+
function checkContradiction(source, columnIndex, fc, view) {
|
|
867
|
+
if (source.type !== 'values' || fc.value === undefined)
|
|
868
|
+
return;
|
|
869
|
+
for (const row of source.values) {
|
|
870
|
+
const cell = row[columnIndex];
|
|
871
|
+
if (!cell || cell.type !== 'literal' || cell.value instanceof Promise)
|
|
872
|
+
continue;
|
|
873
|
+
if (!sqlValuesEqual(cell.value, fc.value)) {
|
|
874
|
+
raiseMutationDiagnostic({
|
|
875
|
+
reason: 'predicate-contradiction',
|
|
876
|
+
column: fc.baseColumnName,
|
|
877
|
+
table: view.name,
|
|
878
|
+
message: `insert into view '${view.name}' contradicts its selection predicate on column '${fc.baseColumnName}'`,
|
|
879
|
+
});
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
// --- UPDATE ---------------------------------------------------------------
|
|
884
|
+
export function rewriteViewUpdate(ctx, stmt, view, descendCtx) {
|
|
885
|
+
const analysis = analyzeView(ctx, view);
|
|
886
|
+
const substitute = remapper(analysis);
|
|
887
|
+
// Qualify substituted subquery-descent base terms with the lowered target's
|
|
888
|
+
// synthesised alias (SELF_ALIAS) so they correlate to the outer target row even
|
|
889
|
+
// when the user subquery FROM names the view's own base table (the same-base-table
|
|
890
|
+
// self-reference corner). The lowered statement carries `alias: SELF_ALIAS` below.
|
|
891
|
+
//
|
|
892
|
+
// `descendCtx` (a CTE-name DML target's `ctxSelfRead` — the body context with the
|
|
893
|
+
// target name re-added to `cteNodes`, resolving to the eager capture) drives ONLY
|
|
894
|
+
// the user-clause subquery descent, so a self-read `from t` resolves `t`'s columns
|
|
895
|
+
// against the capture (a clean shadowing local source). `analyzeView` keeps planning
|
|
896
|
+
// the BODY under the target-EXCLUDED `ctx` (so the body's own `from base` reaches the
|
|
897
|
+
// real table — the load-bearing shadow case). Absent it, `descendCtx ?? ctx` is the
|
|
898
|
+
// byte-identical no-self-read path.
|
|
899
|
+
const descend = makeViewColumnDescend(descendCtx ?? ctx, analysis.columnMap, view.name, view, makeBaseQualifier(ctx, analysis.baseTable, SELF_ALIAS));
|
|
900
|
+
// Scope guard: `set` targets, assigned values, and the top-level `where`
|
|
901
|
+
// references must name view columns (a base-only name must not leak through to
|
|
902
|
+
// the underlying table).
|
|
903
|
+
if (stmt.where)
|
|
904
|
+
guardTopLevelScope(stmt.where, analysis, view);
|
|
905
|
+
// View-aware collision guard: two distinct view columns may lower to one base
|
|
906
|
+
// column (e.g. `select id, b, b+1 as bp` → `set b=5, bp=100`, or a duplicate
|
|
907
|
+
// rename `b, b as b2` → `set b=1, b2=2`). The base backstop in building/update.ts
|
|
908
|
+
// would reject these but report the base column twice; detect it here so the
|
|
909
|
+
// message names both view columns the user actually wrote. Rejected
|
|
910
|
+
// unconditionally — value-agreement (`set b=5, b2=5`) is not softened.
|
|
911
|
+
const seenBaseColumns = new Map(); // base column (lower) → first view-column spelling
|
|
912
|
+
const recordBaseColumn = (baseColumn, viewColumn) => {
|
|
913
|
+
const key = baseColumn.toLowerCase();
|
|
914
|
+
const prior = seenBaseColumns.get(key);
|
|
915
|
+
if (prior !== undefined) {
|
|
916
|
+
raiseMutationDiagnostic({
|
|
917
|
+
reason: 'conflicting-assignment',
|
|
918
|
+
column: baseColumn,
|
|
919
|
+
table: view.name,
|
|
920
|
+
message: `cannot write through view '${view.name}': columns '${prior}' and '${viewColumn}' both target base column '${baseColumn}'; an UPDATE cannot assign one column twice`,
|
|
921
|
+
});
|
|
922
|
+
}
|
|
923
|
+
seenBaseColumns.set(key, viewColumn);
|
|
924
|
+
};
|
|
925
|
+
// `new.<x>` binds the WRITTEN view row: when `x` is also assigned in this
|
|
926
|
+
// statement, that assignment's value (every embedded RHS reads the pre-update
|
|
927
|
+
// row, exactly like the sibling assignment's own lowering — so cross-references
|
|
928
|
+
// are order-independent); otherwise the column's forward read image. First
|
|
929
|
+
// occurrence wins on a duplicate target — the collision guard below rejects the
|
|
930
|
+
// statement anyway. Keyed by view-column index (the `newRefIndex` domain).
|
|
931
|
+
const assignedValueByIdx = new Map();
|
|
932
|
+
stmt.assignments.forEach(a => {
|
|
933
|
+
const i = analysis.viewColumns.findIndex(c => c.name.toLowerCase() === a.column.toLowerCase());
|
|
934
|
+
if (i >= 0 && !assignedValueByIdx.has(i))
|
|
935
|
+
assignedValueByIdx.set(i, a.value);
|
|
936
|
+
});
|
|
937
|
+
const assignments = stmt.assignments.flatMap(asg => {
|
|
938
|
+
// Enforce view-column scope on the SET target (an unknown / base-only name is
|
|
939
|
+
// rejected here; a computed view column is found and surfaces `no-inverse` below).
|
|
940
|
+
const vc = findViewColumn(analysis, asg.column, view);
|
|
941
|
+
// The assigned VALUE's top-level references must also name view columns — a
|
|
942
|
+
// base-only name on the RHS would otherwise read a column the view projects
|
|
943
|
+
// away (the same encapsulation leak as the `where` / `set`-target guard).
|
|
944
|
+
guardTopLevelScope(asg.value, analysis, view);
|
|
945
|
+
const site = analysis.writableSites.get(asg.column.toLowerCase());
|
|
946
|
+
// An authored (`with inverse`) column lowers to ONE base assignment per put:
|
|
947
|
+
// inside each authored expression, `new.<x>` becomes the assigned value when
|
|
948
|
+
// `x` is assigned in this statement (including `x` = this column) and that
|
|
949
|
+
// view column's name otherwise — still in VIEW terms — then the standard
|
|
950
|
+
// view→base lowering maps everything to base terms (the forward read image
|
|
951
|
+
// for the non-assigned columns). The result is a plain base-table `set` per
|
|
952
|
+
// target riding the existing spine (docs/view-updateability.md § Authored
|
|
953
|
+
// inverses).
|
|
954
|
+
if (site?.kind === 'authored') {
|
|
955
|
+
return site.puts.map(put => {
|
|
956
|
+
const viewTermExpr = substituteNewRefs(put.expr, name => {
|
|
957
|
+
const idx = requireValidatedNewRefIndex(site.newRefIndex, name, asg.column);
|
|
958
|
+
return assignedValueByIdx.get(idx) ?? columnExpr(analysis.viewColumns[idx].name);
|
|
959
|
+
});
|
|
960
|
+
const lowered = transformExpr(viewTermExpr, substitute, descend);
|
|
961
|
+
recordBaseColumn(put.baseColumn, asg.column);
|
|
962
|
+
return { column: put.baseColumn, value: lowered };
|
|
963
|
+
});
|
|
964
|
+
}
|
|
965
|
+
const loweredValue = transformExpr(asg.value, substitute, descend);
|
|
966
|
+
// Route the SET target through the full writable-base set (identity / passthrough
|
|
967
|
+
// / inverse), mirroring the multi-source spine. An `inverse`-profile column (e.g.
|
|
968
|
+
// `b + 1 as bp`) runs the lowered value through the site's `inverse` (`set bp = 9`
|
|
969
|
+
// ⇒ `set b = 9 - 1`); an identity / passthrough column (`b collate nocase as bc`,
|
|
970
|
+
// no-op `cast`) has no inverse and stores the value verbatim. The inverse expects
|
|
971
|
+
// a value already in base terms, so it wraps the lowered value LAST (after
|
|
972
|
+
// base-term substitution). `findViewColumn` above stays the unknown-column guard;
|
|
973
|
+
// only an opaque `computed` column reaches `requireBaseColumn` (→ `no-inverse`).
|
|
974
|
+
if (site) {
|
|
975
|
+
recordBaseColumn(site.baseColumn, asg.column);
|
|
976
|
+
return [{ column: site.baseColumn, value: site.inverse ? site.inverse(loweredValue) : loweredValue }];
|
|
977
|
+
}
|
|
978
|
+
const baseColumn = requireBaseColumn(vc);
|
|
979
|
+
recordBaseColumn(baseColumn, asg.column);
|
|
980
|
+
return [{ column: baseColumn, value: loweredValue }];
|
|
981
|
+
});
|
|
982
|
+
const userWhere = stmt.where ? transformExpr(stmt.where, substitute, descend) : undefined;
|
|
983
|
+
const where = combineAnd(userWhere, analysis.filterPredicate ? cloneExpr(analysis.filterPredicate) : undefined);
|
|
984
|
+
return {
|
|
985
|
+
type: 'update',
|
|
986
|
+
table: tableIdentifier(analysis.baseTable),
|
|
987
|
+
// Synthesised collision-proof correlation name on the lowered target; the base
|
|
988
|
+
// builder registers it as the target's AliasedScope alias so an `__vm_self.col`
|
|
989
|
+
// term (emitted by the SELF_ALIAS qualifier above, incl. in RETURNING subqueries)
|
|
990
|
+
// binds the outer target row regardless of the user subquery FROM.
|
|
991
|
+
alias: SELF_ALIAS,
|
|
992
|
+
assignments,
|
|
993
|
+
where,
|
|
994
|
+
contextValues: stmt.contextValues,
|
|
995
|
+
returning: rewriteViewReturning(ctx, stmt.returning, analysis, view, SELF_ALIAS, descendCtx),
|
|
996
|
+
schemaPath: stmt.schemaPath,
|
|
997
|
+
loc: stmt.loc,
|
|
998
|
+
};
|
|
999
|
+
}
|
|
1000
|
+
// --- DELETE ---------------------------------------------------------------
|
|
1001
|
+
export function rewriteViewDelete(ctx, stmt, view, descendCtx) {
|
|
1002
|
+
const analysis = analyzeView(ctx, view);
|
|
1003
|
+
const substitute = remapper(analysis);
|
|
1004
|
+
// Qualify substituted subquery-descent base terms with the lowered target's
|
|
1005
|
+
// synthesised alias (SELF_ALIAS) so they correlate to the outer target row even
|
|
1006
|
+
// when the user subquery FROM names the view's own base table (the same-base-table
|
|
1007
|
+
// self-reference corner). The lowered statement carries `alias: SELF_ALIAS` below.
|
|
1008
|
+
// `descendCtx` (a CTE self-read `ctxSelfRead`) drives the user-WHERE subquery descent
|
|
1009
|
+
// so a self-read `from t` resolves to the eager capture; see {@link rewriteViewUpdate}.
|
|
1010
|
+
const descend = makeViewColumnDescend(descendCtx ?? ctx, analysis.columnMap, view.name, view, makeBaseQualifier(ctx, analysis.baseTable, SELF_ALIAS));
|
|
1011
|
+
// Scope guard: top-level `where` references must name view columns.
|
|
1012
|
+
if (stmt.where)
|
|
1013
|
+
guardTopLevelScope(stmt.where, analysis, view);
|
|
1014
|
+
const userWhere = stmt.where ? transformExpr(stmt.where, substitute, descend) : undefined;
|
|
1015
|
+
const where = combineAnd(userWhere, analysis.filterPredicate ? cloneExpr(analysis.filterPredicate) : undefined);
|
|
1016
|
+
return {
|
|
1017
|
+
type: 'delete',
|
|
1018
|
+
table: tableIdentifier(analysis.baseTable),
|
|
1019
|
+
// Synthesised collision-proof correlation name on the lowered target; see
|
|
1020
|
+
// rewriteViewUpdate for the rationale (binds `__vm_self.col` to the outer row).
|
|
1021
|
+
alias: SELF_ALIAS,
|
|
1022
|
+
where,
|
|
1023
|
+
contextValues: stmt.contextValues,
|
|
1024
|
+
returning: rewriteViewReturning(ctx, stmt.returning, analysis, view, SELF_ALIAS, descendCtx),
|
|
1025
|
+
schemaPath: stmt.schemaPath,
|
|
1026
|
+
loc: stmt.loc,
|
|
1027
|
+
};
|
|
1028
|
+
}
|
|
1029
|
+
/**
|
|
1030
|
+
* Rewrite a view-mediated RETURNING clause into base terms so it rides the base
|
|
1031
|
+
* op's own RETURNING machinery. The returned rows are projected through the
|
|
1032
|
+
* **view's** column list (not the base table's): each view-column reference is
|
|
1033
|
+
* substituted to its base-term lineage and the user's view-term output name is
|
|
1034
|
+
* preserved as the result-column alias. The base builder then evaluates the
|
|
1035
|
+
* clause against NEW (insert/update) or OLD (delete), i.e. the post-mutation
|
|
1036
|
+
* (or, for delete, the deleted) base row — so computed view columns re-evaluate
|
|
1037
|
+
* against the post-mutation base values. `returning *` expands to every view
|
|
1038
|
+
* column. Returns `undefined` for an absent/empty clause.
|
|
1039
|
+
*
|
|
1040
|
+
* OLD/NEW qualifiers on a view-column reference are not honored through a view
|
|
1041
|
+
* (the qualifier is dropped, so the base op's default NEW/OLD binding applies);
|
|
1042
|
+
* the documented surface is unqualified / view-qualified view columns.
|
|
1043
|
+
*
|
|
1044
|
+
* `correlationName` is the lowered target's correlation name used to qualify
|
|
1045
|
+
* substituted base terms emitted inside a RETURNING subquery (a RETURNING subquery can
|
|
1046
|
+
* correlate to the target row the same way a WHERE subquery can). UPDATE/DELETE pass
|
|
1047
|
+
* the synthesised {@link SELF_ALIAS}; INSERT leaves it at the base table name (default).
|
|
1048
|
+
*/
|
|
1049
|
+
/** Shared guard for `RETURNING <q>.*` through a view — validates the qualifier against the view name. */
|
|
1050
|
+
export function assertReturningStarQualifier(rcTable, viewName) {
|
|
1051
|
+
if (rcTable && rcTable.toLowerCase() !== viewName.toLowerCase()) {
|
|
1052
|
+
throw new QuereusError(`Table '${rcTable}' not found in FROM clause for qualified RETURNING *`, StatusCode.ERROR);
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
export function rewriteViewReturning(ctx, returning, analysis, view, correlationName = analysis.baseTable.name,
|
|
1056
|
+
/** A CTE self-read `ctxSelfRead` driving the RETURNING-subquery descent so a
|
|
1057
|
+
* self-read `from t` resolves to the eager capture (the capture is materialized
|
|
1058
|
+
* before the base op, so the RETURNING re-projection reads the frozen snapshot).
|
|
1059
|
+
* Absent it, `descendCtx ?? ctx` is the byte-identical no-self-read path. */
|
|
1060
|
+
descendCtx) {
|
|
1061
|
+
if (!returning || returning.length === 0)
|
|
1062
|
+
return undefined;
|
|
1063
|
+
const substitute = remapper(analysis);
|
|
1064
|
+
const descend = makeViewColumnDescend(descendCtx ?? ctx, analysis.columnMap, view.name, view, makeBaseQualifier(ctx, analysis.baseTable, correlationName));
|
|
1065
|
+
const out = [];
|
|
1066
|
+
for (const rc of returning) {
|
|
1067
|
+
if (rc.type === 'all') {
|
|
1068
|
+
// RETURNING * (or `view.*`) → every view column, projected through its
|
|
1069
|
+
// base-term lineage and named by the view column.
|
|
1070
|
+
assertReturningStarQualifier(rc.table, view.name);
|
|
1071
|
+
for (const vc of analysis.viewColumns) {
|
|
1072
|
+
const baseExpr = analysis.columnMap.get(vc.name.toLowerCase());
|
|
1073
|
+
if (baseExpr)
|
|
1074
|
+
out.push({ type: 'column', expr: cloneExpr(baseExpr), alias: vc.name });
|
|
1075
|
+
}
|
|
1076
|
+
continue;
|
|
1077
|
+
}
|
|
1078
|
+
// Scope guard: a top-level `returning` reference must name a view column —
|
|
1079
|
+
// the same encapsulation guard as `where` / `set` (a base-only column the
|
|
1080
|
+
// view projects away must not leak through RETURNING).
|
|
1081
|
+
guardTopLevelScope(rc.expr, analysis, view);
|
|
1082
|
+
// Preserve the user's view-term output name BEFORE rewriting to base terms,
|
|
1083
|
+
// so the result column is named as written (the view column / its alias),
|
|
1084
|
+
// not the underlying base column.
|
|
1085
|
+
const alias = rc.alias ?? deriveReturningName(rc.expr);
|
|
1086
|
+
out.push({ type: 'column', expr: transformExpr(rc.expr, substitute, descend), alias });
|
|
1087
|
+
}
|
|
1088
|
+
return out;
|
|
1089
|
+
}
|
|
1090
|
+
/** The output name for an unaliased RETURNING expression (view-term spelling). */
|
|
1091
|
+
function deriveReturningName(expr) {
|
|
1092
|
+
if (expr.type === 'column')
|
|
1093
|
+
return expr.table ? `${expr.table}.${expr.name}` : expr.name;
|
|
1094
|
+
return expressionToString(expr);
|
|
1095
|
+
}
|
|
1096
|
+
//# sourceMappingURL=single-source.js.map
|