@quereus/quereus 4.5.0 → 4.7.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 +5 -4
- package/dist/src/common/errors.d.ts +17 -0
- package/dist/src/common/errors.d.ts.map +1 -1
- package/dist/src/common/errors.js +21 -0
- package/dist/src/common/errors.js.map +1 -1
- package/dist/src/core/database-assertions.d.ts +4 -3
- package/dist/src/core/database-assertions.d.ts.map +1 -1
- package/dist/src/core/database-assertions.js +44 -14
- package/dist/src/core/database-assertions.js.map +1 -1
- package/dist/src/core/database-events.d.ts +161 -1
- package/dist/src/core/database-events.d.ts.map +1 -1
- package/dist/src/core/database-events.js +307 -5
- package/dist/src/core/database-events.js.map +1 -1
- package/dist/src/core/database-internal.d.ts +5 -2
- package/dist/src/core/database-internal.d.ts.map +1 -1
- package/dist/src/core/database-materialized-views-plan-builders.d.ts.map +1 -1
- package/dist/src/core/database-materialized-views-plan-builders.js +33 -4
- package/dist/src/core/database-materialized-views-plan-builders.js.map +1 -1
- package/dist/src/core/database-materialized-views-plans.d.ts +12 -2
- package/dist/src/core/database-materialized-views-plans.d.ts.map +1 -1
- package/dist/src/core/database-materialized-views.d.ts +46 -0
- package/dist/src/core/database-materialized-views.d.ts.map +1 -1
- package/dist/src/core/database-materialized-views.js +75 -4
- package/dist/src/core/database-materialized-views.js.map +1 -1
- package/dist/src/core/database-transaction.d.ts +9 -0
- package/dist/src/core/database-transaction.d.ts.map +1 -1
- package/dist/src/core/database-transaction.js +9 -0
- package/dist/src/core/database-transaction.js.map +1 -1
- package/dist/src/core/database.d.ts +16 -2
- package/dist/src/core/database.d.ts.map +1 -1
- package/dist/src/core/database.js +56 -15
- package/dist/src/core/database.js.map +1 -1
- package/dist/src/core/derived-row-validator.d.ts.map +1 -1
- package/dist/src/core/derived-row-validator.js +7 -1
- package/dist/src/core/derived-row-validator.js.map +1 -1
- package/dist/src/core/statement.d.ts.map +1 -1
- package/dist/src/core/statement.js +15 -5
- package/dist/src/core/statement.js.map +1 -1
- package/dist/src/emit/ast-stringify.d.ts +18 -2
- package/dist/src/emit/ast-stringify.d.ts.map +1 -1
- package/dist/src/emit/ast-stringify.js +22 -4
- package/dist/src/emit/ast-stringify.js.map +1 -1
- package/dist/src/func/builtins/aggregate.js +11 -11
- 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 +15 -85
- package/dist/src/func/builtins/builtin-window-functions.js.map +1 -1
- package/dist/src/func/builtins/conversion.d.ts.map +1 -1
- package/dist/src/func/builtins/conversion.js +10 -9
- package/dist/src/func/builtins/conversion.js.map +1 -1
- package/dist/src/func/builtins/datetime.d.ts.map +1 -1
- package/dist/src/func/builtins/datetime.js +28 -10
- package/dist/src/func/builtins/datetime.js.map +1 -1
- package/dist/src/func/builtins/explain.d.ts.map +1 -1
- package/dist/src/func/builtins/explain.js +19 -5
- package/dist/src/func/builtins/explain.js.map +1 -1
- package/dist/src/func/builtins/json.d.ts.map +1 -1
- package/dist/src/func/builtins/json.js +23 -17
- package/dist/src/func/builtins/json.js.map +1 -1
- package/dist/src/func/builtins/mutation.js +2 -2
- package/dist/src/func/builtins/mutation.js.map +1 -1
- package/dist/src/func/builtins/return-types.d.ts +327 -0
- package/dist/src/func/builtins/return-types.d.ts.map +1 -0
- package/dist/src/func/builtins/return-types.js +43 -0
- package/dist/src/func/builtins/return-types.js.map +1 -0
- package/dist/src/func/builtins/scalar.d.ts.map +1 -1
- package/dist/src/func/builtins/scalar.js +150 -79
- package/dist/src/func/builtins/scalar.js.map +1 -1
- package/dist/src/func/builtins/schema.d.ts.map +1 -1
- package/dist/src/func/builtins/schema.js +43 -8
- package/dist/src/func/builtins/schema.js.map +1 -1
- package/dist/src/func/builtins/string.d.ts.map +1 -1
- package/dist/src/func/builtins/string.js +4 -2
- package/dist/src/func/builtins/string.js.map +1 -1
- package/dist/src/func/builtins/timespan.d.ts +3 -0
- package/dist/src/func/builtins/timespan.d.ts.map +1 -1
- package/dist/src/func/builtins/timespan.js +15 -11
- package/dist/src/func/builtins/timespan.js.map +1 -1
- package/dist/src/func/registration.d.ts +35 -1
- package/dist/src/func/registration.d.ts.map +1 -1
- package/dist/src/func/registration.js +235 -41
- package/dist/src/func/registration.js.map +1 -1
- package/dist/src/index.d.ts +14 -7
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +15 -6
- package/dist/src/index.js.map +1 -1
- package/dist/src/parser/ast.d.ts +58 -1
- package/dist/src/parser/ast.d.ts.map +1 -1
- package/dist/src/parser/parser.d.ts +46 -0
- package/dist/src/parser/parser.d.ts.map +1 -1
- package/dist/src/parser/parser.js +161 -45
- package/dist/src/parser/parser.js.map +1 -1
- package/dist/src/parser/utils.d.ts +13 -1
- package/dist/src/parser/utils.d.ts.map +1 -1
- package/dist/src/parser/utils.js +14 -0
- package/dist/src/parser/utils.js.map +1 -1
- package/dist/src/planner/analysis/assertion-classifier.d.ts.map +1 -1
- package/dist/src/planner/analysis/assertion-classifier.js +7 -2
- 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 +5 -0
- package/dist/src/planner/analysis/assertion-hoist-cache.js.map +1 -1
- package/dist/src/planner/analysis/change-scope.d.ts +11 -3
- package/dist/src/planner/analysis/change-scope.d.ts.map +1 -1
- package/dist/src/planner/analysis/change-scope.js +5 -4
- package/dist/src/planner/analysis/change-scope.js.map +1 -1
- package/dist/src/planner/analysis/check-extraction.d.ts.map +1 -1
- package/dist/src/planner/analysis/check-extraction.js +37 -4
- package/dist/src/planner/analysis/check-extraction.js.map +1 -1
- package/dist/src/planner/analysis/comparison-collation.d.ts +20 -22
- package/dist/src/planner/analysis/comparison-collation.d.ts.map +1 -1
- package/dist/src/planner/analysis/comparison-collation.js +29 -26
- package/dist/src/planner/analysis/comparison-collation.js.map +1 -1
- package/dist/src/planner/analysis/constraint-extractor.d.ts +0 -7
- package/dist/src/planner/analysis/constraint-extractor.d.ts.map +1 -1
- package/dist/src/planner/analysis/constraint-extractor.js +59 -59
- package/dist/src/planner/analysis/constraint-extractor.js.map +1 -1
- package/dist/src/planner/analysis/coverage-prover.d.ts.map +1 -1
- package/dist/src/planner/analysis/coverage-prover.js +13 -5
- package/dist/src/planner/analysis/coverage-prover.js.map +1 -1
- package/dist/src/planner/analysis/equi-correlation.d.ts +6 -1
- package/dist/src/planner/analysis/equi-correlation.d.ts.map +1 -1
- package/dist/src/planner/analysis/equi-correlation.js +8 -1
- package/dist/src/planner/analysis/equi-correlation.js.map +1 -1
- package/dist/src/planner/analysis/predicate-dependencies.d.ts +34 -0
- package/dist/src/planner/analysis/predicate-dependencies.d.ts.map +1 -0
- package/dist/src/planner/analysis/predicate-dependencies.js +60 -0
- package/dist/src/planner/analysis/predicate-dependencies.js.map +1 -0
- package/dist/src/planner/analysis/query-rewrite-matcher.d.ts +1 -1
- package/dist/src/planner/analysis/query-rewrite-matcher.d.ts.map +1 -1
- package/dist/src/planner/analysis/query-rewrite-matcher.js +0 -26
- package/dist/src/planner/analysis/query-rewrite-matcher.js.map +1 -1
- package/dist/src/planner/building/alter-table.d.ts.map +1 -1
- package/dist/src/planner/building/alter-table.js +117 -43
- package/dist/src/planner/building/alter-table.js.map +1 -1
- package/dist/src/planner/building/coercion.d.ts +21 -45
- package/dist/src/planner/building/coercion.d.ts.map +1 -1
- package/dist/src/planner/building/coercion.js +42 -91
- package/dist/src/planner/building/coercion.js.map +1 -1
- package/dist/src/planner/building/constraint-builder.d.ts.map +1 -1
- package/dist/src/planner/building/constraint-builder.js +9 -5
- package/dist/src/planner/building/constraint-builder.js.map +1 -1
- package/dist/src/planner/building/create-assertion.d.ts.map +1 -1
- package/dist/src/planner/building/create-assertion.js +72 -1
- package/dist/src/planner/building/create-assertion.js.map +1 -1
- package/dist/src/planner/building/create-view.d.ts +6 -1
- package/dist/src/planner/building/create-view.d.ts.map +1 -1
- package/dist/src/planner/building/create-view.js +12 -3
- 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 +6 -2
- package/dist/src/planner/building/ddl.js.map +1 -1
- package/dist/src/planner/building/delete.d.ts.map +1 -1
- package/dist/src/planner/building/delete.js +23 -10
- package/dist/src/planner/building/delete.js.map +1 -1
- package/dist/src/planner/building/dml-target.d.ts.map +1 -1
- package/dist/src/planner/building/dml-target.js +4 -0
- package/dist/src/planner/building/dml-target.js.map +1 -1
- package/dist/src/planner/building/drop-assertion.d.ts.map +1 -1
- package/dist/src/planner/building/drop-assertion.js +3 -1
- package/dist/src/planner/building/drop-assertion.js.map +1 -1
- package/dist/src/planner/building/expression.d.ts +17 -0
- package/dist/src/planner/building/expression.d.ts.map +1 -1
- package/dist/src/planner/building/expression.js +28 -17
- package/dist/src/planner/building/expression.js.map +1 -1
- package/dist/src/planner/building/foreign-key-builder.d.ts.map +1 -1
- package/dist/src/planner/building/foreign-key-builder.js +7 -5
- package/dist/src/planner/building/foreign-key-builder.js.map +1 -1
- package/dist/src/planner/building/function-call.d.ts +35 -0
- package/dist/src/planner/building/function-call.d.ts.map +1 -1
- package/dist/src/planner/building/function-call.js +60 -42
- package/dist/src/planner/building/function-call.js.map +1 -1
- package/dist/src/planner/building/insert.d.ts.map +1 -1
- package/dist/src/planner/building/insert.js +185 -48
- package/dist/src/planner/building/insert.js.map +1 -1
- package/dist/src/planner/building/materialized-view.d.ts.map +1 -1
- package/dist/src/planner/building/materialized-view.js +3 -1
- package/dist/src/planner/building/materialized-view.js.map +1 -1
- package/dist/src/planner/building/schema-authored-context.d.ts +69 -0
- package/dist/src/planner/building/schema-authored-context.d.ts.map +1 -0
- package/dist/src/planner/building/schema-authored-context.js +75 -0
- package/dist/src/planner/building/schema-authored-context.js.map +1 -0
- package/dist/src/planner/building/schema-resolution.d.ts.map +1 -1
- package/dist/src/planner/building/schema-resolution.js +7 -4
- package/dist/src/planner/building/schema-resolution.js.map +1 -1
- package/dist/src/planner/building/select-aggregates.d.ts +188 -3
- package/dist/src/planner/building/select-aggregates.d.ts.map +1 -1
- package/dist/src/planner/building/select-aggregates.js +449 -65
- package/dist/src/planner/building/select-aggregates.js.map +1 -1
- package/dist/src/planner/building/select-compound.js +2 -2
- package/dist/src/planner/building/select-compound.js.map +1 -1
- package/dist/src/planner/building/select-context.d.ts +98 -0
- package/dist/src/planner/building/select-context.d.ts.map +1 -1
- package/dist/src/planner/building/select-context.js +120 -37
- package/dist/src/planner/building/select-context.js.map +1 -1
- package/dist/src/planner/building/select-modifiers.d.ts +10 -3
- package/dist/src/planner/building/select-modifiers.d.ts.map +1 -1
- package/dist/src/planner/building/select-modifiers.js +29 -8
- package/dist/src/planner/building/select-modifiers.js.map +1 -1
- package/dist/src/planner/building/select-ordinal.d.ts +64 -19
- package/dist/src/planner/building/select-ordinal.d.ts.map +1 -1
- package/dist/src/planner/building/select-ordinal.js +79 -30
- package/dist/src/planner/building/select-ordinal.js.map +1 -1
- package/dist/src/planner/building/select-projections.d.ts +1 -1
- package/dist/src/planner/building/select-projections.d.ts.map +1 -1
- package/dist/src/planner/building/select-projections.js +18 -11
- package/dist/src/planner/building/select-projections.js.map +1 -1
- package/dist/src/planner/building/select-window.d.ts +13 -3
- package/dist/src/planner/building/select-window.d.ts.map +1 -1
- package/dist/src/planner/building/select-window.js +142 -37
- package/dist/src/planner/building/select-window.js.map +1 -1
- package/dist/src/planner/building/select.d.ts +37 -1
- package/dist/src/planner/building/select.d.ts.map +1 -1
- package/dist/src/planner/building/select.js +240 -109
- package/dist/src/planner/building/select.js.map +1 -1
- package/dist/src/planner/building/update.d.ts.map +1 -1
- package/dist/src/planner/building/update.js +27 -13
- package/dist/src/planner/building/update.js.map +1 -1
- package/dist/src/planner/building/view-mutation-builder.d.ts +1 -1
- package/dist/src/planner/building/view-mutation-builder.d.ts.map +1 -1
- package/dist/src/planner/building/view-mutation-builder.js +102 -8
- package/dist/src/planner/building/view-mutation-builder.js.map +1 -1
- package/dist/src/planner/building/with.d.ts.map +1 -1
- package/dist/src/planner/building/with.js +34 -4
- package/dist/src/planner/building/with.js.map +1 -1
- package/dist/src/planner/cache/correlation-detector.d.ts +15 -0
- package/dist/src/planner/cache/correlation-detector.d.ts.map +1 -1
- package/dist/src/planner/cache/correlation-detector.js +26 -0
- package/dist/src/planner/cache/correlation-detector.js.map +1 -1
- package/dist/src/planner/cache/materialization-advisory.d.ts +7 -0
- package/dist/src/planner/cache/materialization-advisory.d.ts.map +1 -1
- package/dist/src/planner/cache/materialization-advisory.js +12 -3
- package/dist/src/planner/cache/materialization-advisory.js.map +1 -1
- package/dist/src/planner/cost/conjunct-cost.d.ts +40 -0
- package/dist/src/planner/cost/conjunct-cost.d.ts.map +1 -1
- package/dist/src/planner/cost/conjunct-cost.js +45 -0
- package/dist/src/planner/cost/conjunct-cost.js.map +1 -1
- package/dist/src/planner/cost/index.d.ts +10 -0
- package/dist/src/planner/cost/index.d.ts.map +1 -1
- package/dist/src/planner/cost/index.js +15 -0
- package/dist/src/planner/cost/index.js.map +1 -1
- package/dist/src/planner/framework/characteristics.d.ts +9 -0
- package/dist/src/planner/framework/characteristics.d.ts.map +1 -1
- package/dist/src/planner/framework/characteristics.js.map +1 -1
- package/dist/src/planner/framework/pass.d.ts +2 -0
- package/dist/src/planner/framework/pass.d.ts.map +1 -1
- package/dist/src/planner/framework/pass.js +15 -0
- package/dist/src/planner/framework/pass.js.map +1 -1
- package/dist/src/planner/mutation/backward-body.d.ts.map +1 -1
- package/dist/src/planner/mutation/backward-body.js +4 -1
- package/dist/src/planner/mutation/backward-body.js.map +1 -1
- package/dist/src/planner/mutation/body-context.d.ts +23 -0
- package/dist/src/planner/mutation/body-context.d.ts.map +1 -0
- package/dist/src/planner/mutation/body-context.js +26 -0
- package/dist/src/planner/mutation/body-context.js.map +1 -0
- package/dist/src/planner/mutation/cte-flatten.js +15 -2
- package/dist/src/planner/mutation/cte-flatten.js.map +1 -1
- package/dist/src/planner/mutation/decomposition.d.ts +8 -0
- package/dist/src/planner/mutation/decomposition.d.ts.map +1 -1
- package/dist/src/planner/mutation/decomposition.js +8 -3
- package/dist/src/planner/mutation/decomposition.js.map +1 -1
- package/dist/src/planner/mutation/lens-enforcement.js +1 -1
- package/dist/src/planner/mutation/multi-source.d.ts +7 -0
- package/dist/src/planner/mutation/multi-source.d.ts.map +1 -1
- package/dist/src/planner/mutation/multi-source.js +5 -0
- package/dist/src/planner/mutation/multi-source.js.map +1 -1
- package/dist/src/planner/mutation/mutation-diagnostic.d.ts +1 -1
- package/dist/src/planner/mutation/mutation-diagnostic.d.ts.map +1 -1
- package/dist/src/planner/mutation/mutation-diagnostic.js.map +1 -1
- package/dist/src/planner/mutation/scope-transform.d.ts +32 -0
- package/dist/src/planner/mutation/scope-transform.d.ts.map +1 -1
- package/dist/src/planner/mutation/scope-transform.js +181 -33
- package/dist/src/planner/mutation/scope-transform.js.map +1 -1
- package/dist/src/planner/mutation/set-op.d.ts.map +1 -1
- package/dist/src/planner/mutation/set-op.js +66 -16
- package/dist/src/planner/mutation/set-op.js.map +1 -1
- package/dist/src/planner/mutation/single-source.d.ts.map +1 -1
- package/dist/src/planner/mutation/single-source.js +100 -24
- package/dist/src/planner/mutation/single-source.js.map +1 -1
- package/dist/src/planner/nodes/add-constraint-node.d.ts +15 -1
- package/dist/src/planner/nodes/add-constraint-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/add-constraint-node.js +10 -1
- package/dist/src/planner/nodes/add-constraint-node.js.map +1 -1
- package/dist/src/planner/nodes/aggregate-node.d.ts +15 -0
- package/dist/src/planner/nodes/aggregate-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/aggregate-node.js +32 -17
- 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 +2 -1
- package/dist/src/planner/nodes/alias-node.js.map +1 -1
- package/dist/src/planner/nodes/alter-table-node.d.ts +51 -10
- package/dist/src/planner/nodes/alter-table-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/alter-table-node.js +49 -2
- package/dist/src/planner/nodes/alter-table-node.js.map +1 -1
- package/dist/src/planner/nodes/asof-scan-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/asof-scan-node.js +4 -1
- package/dist/src/planner/nodes/asof-scan-node.js.map +1 -1
- package/dist/src/planner/nodes/asserted-keys-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/asserted-keys-node.js +2 -1
- package/dist/src/planner/nodes/asserted-keys-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 +8 -3
- package/dist/src/planner/nodes/bloom-join-node.js.map +1 -1
- package/dist/src/planner/nodes/cache-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/cache-node.js +2 -1
- package/dist/src/planner/nodes/cache-node.js.map +1 -1
- package/dist/src/planner/nodes/constraint-check-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/constraint-check-node.js +17 -19
- package/dist/src/planner/nodes/constraint-check-node.js.map +1 -1
- package/dist/src/planner/nodes/create-assertion-node.d.ts +2 -1
- package/dist/src/planner/nodes/create-assertion-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/create-assertion-node.js +5 -2
- package/dist/src/planner/nodes/create-assertion-node.js.map +1 -1
- package/dist/src/planner/nodes/cte-node.d.ts +19 -9
- package/dist/src/planner/nodes/cte-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/cte-node.js +25 -9
- package/dist/src/planner/nodes/cte-node.js.map +1 -1
- package/dist/src/planner/nodes/delete-node.d.ts +20 -2
- package/dist/src/planner/nodes/delete-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/delete-node.js +11 -2
- package/dist/src/planner/nodes/delete-node.js.map +1 -1
- package/dist/src/planner/nodes/distinct-node.d.ts +6 -0
- package/dist/src/planner/nodes/distinct-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/distinct-node.js +10 -2
- package/dist/src/planner/nodes/distinct-node.js.map +1 -1
- package/dist/src/planner/nodes/dml-executor-node.d.ts +58 -1
- package/dist/src/planner/nodes/dml-executor-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/dml-executor-node.js +107 -15
- package/dist/src/planner/nodes/dml-executor-node.js.map +1 -1
- package/dist/src/planner/nodes/drop-assertion-node.d.ts +2 -1
- package/dist/src/planner/nodes/drop-assertion-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/drop-assertion-node.js +5 -2
- package/dist/src/planner/nodes/drop-assertion-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 -1
- package/dist/src/planner/nodes/eager-prefetch-node.js.map +1 -1
- package/dist/src/planner/nodes/fanout-lookup-join-node.d.ts +5 -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 +13 -6
- 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 +18 -5
- package/dist/src/planner/nodes/filter.js.map +1 -1
- package/dist/src/planner/nodes/hash-aggregate.d.ts +1 -0
- package/dist/src/planner/nodes/hash-aggregate.d.ts.map +1 -1
- package/dist/src/planner/nodes/hash-aggregate.js +21 -16
- package/dist/src/planner/nodes/hash-aggregate.js.map +1 -1
- package/dist/src/planner/nodes/insert-node.d.ts +19 -2
- package/dist/src/planner/nodes/insert-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/insert-node.js +10 -2
- package/dist/src/planner/nodes/insert-node.js.map +1 -1
- package/dist/src/planner/nodes/join-node.d.ts +20 -1
- package/dist/src/planner/nodes/join-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/join-node.js +30 -9
- package/dist/src/planner/nodes/join-node.js.map +1 -1
- package/dist/src/planner/nodes/join-utils.d.ts +21 -0
- package/dist/src/planner/nodes/join-utils.d.ts.map +1 -1
- package/dist/src/planner/nodes/join-utils.js +26 -0
- package/dist/src/planner/nodes/join-utils.js.map +1 -1
- package/dist/src/planner/nodes/key-set-semi-join-node.d.ts +42 -10
- package/dist/src/planner/nodes/key-set-semi-join-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/key-set-semi-join-node.js +90 -17
- package/dist/src/planner/nodes/key-set-semi-join-node.js.map +1 -1
- package/dist/src/planner/nodes/lens-auxiliary-access-node.d.ts +5 -0
- package/dist/src/planner/nodes/lens-auxiliary-access-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/lens-auxiliary-access-node.js +2 -1
- package/dist/src/planner/nodes/lens-auxiliary-access-node.js.map +1 -1
- package/dist/src/planner/nodes/limit-offset.d.ts +6 -0
- package/dist/src/planner/nodes/limit-offset.d.ts.map +1 -1
- package/dist/src/planner/nodes/limit-offset.js +10 -2
- package/dist/src/planner/nodes/limit-offset.js.map +1 -1
- package/dist/src/planner/nodes/merge-join-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/merge-join-node.js +8 -3
- package/dist/src/planner/nodes/merge-join-node.js.map +1 -1
- package/dist/src/planner/nodes/ordinal-slice-node.d.ts +5 -0
- package/dist/src/planner/nodes/ordinal-slice-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/ordinal-slice-node.js +9 -2
- package/dist/src/planner/nodes/ordinal-slice-node.js.map +1 -1
- package/dist/src/planner/nodes/plan-node.d.ts +29 -0
- package/dist/src/planner/nodes/plan-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/plan-node.js +12 -0
- package/dist/src/planner/nodes/plan-node.js.map +1 -1
- package/dist/src/planner/nodes/project-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/project-node.js +18 -36
- 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 +3 -2
- package/dist/src/planner/nodes/reference.js.map +1 -1
- package/dist/src/planner/nodes/retrieve-node.d.ts +16 -2
- package/dist/src/planner/nodes/retrieve-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/retrieve-node.js +10 -2
- 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 +13 -32
- package/dist/src/planner/nodes/returning-node.js.map +1 -1
- package/dist/src/planner/nodes/scalar.d.ts.map +1 -1
- package/dist/src/planner/nodes/scalar.js +5 -18
- package/dist/src/planner/nodes/scalar.js.map +1 -1
- package/dist/src/planner/nodes/sort.d.ts.map +1 -1
- package/dist/src/planner/nodes/sort.js +3 -1
- package/dist/src/planner/nodes/sort.js.map +1 -1
- package/dist/src/planner/nodes/stream-aggregate.d.ts +1 -0
- package/dist/src/planner/nodes/stream-aggregate.d.ts.map +1 -1
- package/dist/src/planner/nodes/stream-aggregate.js +22 -20
- package/dist/src/planner/nodes/stream-aggregate.js.map +1 -1
- package/dist/src/planner/nodes/table-access-nodes.d.ts +89 -1
- package/dist/src/planner/nodes/table-access-nodes.d.ts.map +1 -1
- package/dist/src/planner/nodes/table-access-nodes.js +69 -2
- package/dist/src/planner/nodes/table-access-nodes.js.map +1 -1
- package/dist/src/planner/nodes/update-node.d.ts +19 -2
- package/dist/src/planner/nodes/update-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/update-node.js +10 -2
- package/dist/src/planner/nodes/update-node.js.map +1 -1
- package/dist/src/planner/nodes/window-function.d.ts.map +1 -1
- package/dist/src/planner/nodes/window-function.js +8 -0
- package/dist/src/planner/nodes/window-function.js.map +1 -1
- package/dist/src/planner/nodes/window-node.d.ts +1 -1
- package/dist/src/planner/nodes/window-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/window-node.js +3 -1
- package/dist/src/planner/nodes/window-node.js.map +1 -1
- package/dist/src/planner/optimizer.d.ts +27 -1
- package/dist/src/planner/optimizer.d.ts.map +1 -1
- package/dist/src/planner/optimizer.js +130 -10
- package/dist/src/planner/optimizer.js.map +1 -1
- package/dist/src/planner/planning-context.d.ts +24 -0
- package/dist/src/planner/planning-context.d.ts.map +1 -1
- package/dist/src/planner/planning-context.js.map +1 -1
- package/dist/src/planner/rules/access/rule-key-set-seek.d.ts +78 -20
- package/dist/src/planner/rules/access/rule-key-set-seek.d.ts.map +1 -1
- package/dist/src/planner/rules/access/rule-key-set-seek.js +296 -135
- package/dist/src/planner/rules/access/rule-key-set-seek.js.map +1 -1
- package/dist/src/planner/rules/access/rule-monotonic-range-access.d.ts.map +1 -1
- package/dist/src/planner/rules/access/rule-monotonic-range-access.js +2 -2
- package/dist/src/planner/rules/access/rule-monotonic-range-access.js.map +1 -1
- package/dist/src/planner/rules/access/rule-select-access-path.d.ts +30 -1
- package/dist/src/planner/rules/access/rule-select-access-path.d.ts.map +1 -1
- package/dist/src/planner/rules/access/rule-select-access-path.js +70 -5
- 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 +7 -4
- 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 +39 -5
- package/dist/src/planner/rules/aggregate/rule-groupby-fd-simplification.js.map +1 -1
- package/dist/src/planner/rules/cache/rule-cte-optimization.d.ts.map +1 -1
- package/dist/src/planner/rules/cache/rule-cte-optimization.js +15 -2
- package/dist/src/planner/rules/cache/rule-cte-optimization.js.map +1 -1
- package/dist/src/planner/rules/cache/rule-materialized-view-rewrite.js +10 -3
- package/dist/src/planner/rules/cache/rule-materialized-view-rewrite.js.map +1 -1
- package/dist/src/planner/rules/cache/rule-nested-loop-right-cache.d.ts.map +1 -1
- package/dist/src/planner/rules/cache/rule-nested-loop-right-cache.js +6 -4
- package/dist/src/planner/rules/cache/rule-nested-loop-right-cache.js.map +1 -1
- package/dist/src/planner/rules/join/equi-pair-extractor.d.ts +5 -31
- package/dist/src/planner/rules/join/equi-pair-extractor.d.ts.map +1 -1
- package/dist/src/planner/rules/join/equi-pair-extractor.js +4 -44
- package/dist/src/planner/rules/join/equi-pair-extractor.js.map +1 -1
- package/dist/src/planner/rules/join/index-nested-loop.d.ts +49 -0
- package/dist/src/planner/rules/join/index-nested-loop.d.ts.map +1 -0
- package/dist/src/planner/rules/join/index-nested-loop.js +291 -0
- package/dist/src/planner/rules/join/index-nested-loop.js.map +1 -0
- package/dist/src/planner/rules/join/rule-fanout-batched-outer.js +8 -8
- package/dist/src/planner/rules/join/rule-fanout-lookup-join.d.ts +4 -0
- 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 +50 -15
- package/dist/src/planner/rules/join/rule-fanout-lookup-join.js.map +1 -1
- package/dist/src/planner/rules/join/rule-join-elimination.d.ts +6 -0
- package/dist/src/planner/rules/join/rule-join-elimination.d.ts.map +1 -1
- package/dist/src/planner/rules/join/rule-join-elimination.js +25 -9
- package/dist/src/planner/rules/join/rule-join-elimination.js.map +1 -1
- package/dist/src/planner/rules/join/rule-join-key-inference.d.ts +7 -0
- package/dist/src/planner/rules/join/rule-join-key-inference.d.ts.map +1 -1
- package/dist/src/planner/rules/join/rule-join-key-inference.js +23 -11
- package/dist/src/planner/rules/join/rule-join-key-inference.js.map +1 -1
- package/dist/src/planner/rules/join/rule-join-physical-selection.d.ts +10 -4
- 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 +115 -29
- package/dist/src/planner/rules/join/rule-join-physical-selection.js.map +1 -1
- package/dist/src/planner/rules/join/rule-monotonic-merge-join.d.ts +2 -0
- 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 +18 -4
- package/dist/src/planner/rules/join/rule-monotonic-merge-join.js.map +1 -1
- package/dist/src/planner/rules/predicate/rule-aggregate-predicate-pushdown.d.ts +2 -2
- 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 +19 -22
- package/dist/src/planner/rules/predicate/rule-aggregate-predicate-pushdown.js.map +1 -1
- package/dist/src/planner/rules/predicate/rule-filter-conjunct-ordering.d.ts +21 -8
- package/dist/src/planner/rules/predicate/rule-filter-conjunct-ordering.d.ts.map +1 -1
- package/dist/src/planner/rules/predicate/rule-filter-conjunct-ordering.js +70 -14
- package/dist/src/planner/rules/predicate/rule-filter-conjunct-ordering.js.map +1 -1
- package/dist/src/planner/rules/predicate/rule-filter-selectivity.d.ts +56 -17
- package/dist/src/planner/rules/predicate/rule-filter-selectivity.d.ts.map +1 -1
- package/dist/src/planner/rules/predicate/rule-filter-selectivity.js +103 -154
- package/dist/src/planner/rules/predicate/rule-filter-selectivity.js.map +1 -1
- package/dist/src/planner/rules/predicate/rule-join-predicate-pushdown.d.ts +76 -0
- package/dist/src/planner/rules/predicate/rule-join-predicate-pushdown.d.ts.map +1 -0
- package/dist/src/planner/rules/predicate/rule-join-predicate-pushdown.js +208 -0
- package/dist/src/planner/rules/predicate/rule-join-predicate-pushdown.js.map +1 -0
- package/dist/src/planner/rules/predicate/rule-predicate-inference-equivalence.d.ts +14 -11
- 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 +21 -85
- package/dist/src/planner/rules/predicate/rule-predicate-inference-equivalence.js.map +1 -1
- package/dist/src/planner/rules/predicate/rule-predicate-pushdown.d.ts +7 -1
- package/dist/src/planner/rules/predicate/rule-predicate-pushdown.d.ts.map +1 -1
- package/dist/src/planner/rules/predicate/rule-predicate-pushdown.js +18 -22
- package/dist/src/planner/rules/predicate/rule-predicate-pushdown.js.map +1 -1
- package/dist/src/planner/rules/shared/access-leaf.d.ts +52 -0
- package/dist/src/planner/rules/shared/access-leaf.d.ts.map +1 -0
- package/dist/src/planner/rules/shared/access-leaf.js +95 -0
- package/dist/src/planner/rules/shared/access-leaf.js.map +1 -0
- 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 +17 -7
- 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 +3 -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 +26 -9
- 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 +69 -11
- package/dist/src/planner/rules/subquery/rule-subquery-decorrelation.js.map +1 -1
- package/dist/src/planner/rules/window/rule-monotonic-window.d.ts +17 -7
- package/dist/src/planner/rules/window/rule-monotonic-window.d.ts.map +1 -1
- package/dist/src/planner/rules/window/rule-monotonic-window.js +124 -87
- package/dist/src/planner/rules/window/rule-monotonic-window.js.map +1 -1
- package/dist/src/planner/scopes/aliased.d.ts.map +1 -1
- package/dist/src/planner/scopes/aliased.js +6 -0
- package/dist/src/planner/scopes/aliased.js.map +1 -1
- package/dist/src/planner/stats/catalog-stats.d.ts +44 -13
- package/dist/src/planner/stats/catalog-stats.d.ts.map +1 -1
- package/dist/src/planner/stats/catalog-stats.js +137 -61
- package/dist/src/planner/stats/catalog-stats.js.map +1 -1
- package/dist/src/planner/stats/conjunct-selectivity.d.ts +48 -0
- package/dist/src/planner/stats/conjunct-selectivity.d.ts.map +1 -0
- package/dist/src/planner/stats/conjunct-selectivity.js +168 -0
- package/dist/src/planner/stats/conjunct-selectivity.js.map +1 -0
- package/dist/src/planner/stats/index.d.ts +22 -3
- package/dist/src/planner/stats/index.d.ts.map +1 -1
- package/dist/src/planner/stats/index.js.map +1 -1
- package/dist/src/planner/stats/table-cardinality.d.ts +28 -0
- package/dist/src/planner/stats/table-cardinality.d.ts.map +1 -0
- package/dist/src/planner/stats/table-cardinality.js +29 -0
- package/dist/src/planner/stats/table-cardinality.js.map +1 -0
- package/dist/src/planner/stored-body-context.d.ts +57 -0
- package/dist/src/planner/stored-body-context.d.ts.map +1 -0
- package/dist/src/planner/stored-body-context.js +64 -0
- package/dist/src/planner/stored-body-context.js.map +1 -0
- package/dist/src/planner/util/column-origins.d.ts +29 -8
- package/dist/src/planner/util/column-origins.d.ts.map +1 -1
- package/dist/src/planner/util/column-origins.js +74 -14
- package/dist/src/planner/util/column-origins.js.map +1 -1
- package/dist/src/planner/util/fd-utils.d.ts +32 -8
- package/dist/src/planner/util/fd-utils.d.ts.map +1 -1
- package/dist/src/planner/util/fd-utils.js +46 -9
- package/dist/src/planner/util/fd-utils.js.map +1 -1
- package/dist/src/planner/util/ind-utils.d.ts +66 -19
- package/dist/src/planner/util/ind-utils.d.ts.map +1 -1
- package/dist/src/planner/util/ind-utils.js +91 -21
- package/dist/src/planner/util/ind-utils.js.map +1 -1
- package/dist/src/planner/util/key-utils.d.ts +36 -3
- package/dist/src/planner/util/key-utils.d.ts.map +1 -1
- package/dist/src/planner/util/key-utils.js +57 -7
- package/dist/src/planner/util/key-utils.js.map +1 -1
- package/dist/src/planner/util/output-names.d.ts +12 -0
- package/dist/src/planner/util/output-names.d.ts.map +1 -0
- package/dist/src/planner/util/output-names.js +20 -0
- package/dist/src/planner/util/output-names.js.map +1 -0
- package/dist/src/planner/util/row-estimates.d.ts +39 -0
- package/dist/src/planner/util/row-estimates.d.ts.map +1 -0
- package/dist/src/planner/util/row-estimates.js +68 -0
- package/dist/src/planner/util/row-estimates.js.map +1 -0
- package/dist/src/planner/util/row-population.d.ts +42 -0
- package/dist/src/planner/util/row-population.d.ts.map +1 -0
- package/dist/src/planner/util/row-population.js +71 -0
- package/dist/src/planner/util/row-population.js.map +1 -0
- package/dist/src/runtime/deferred-constraint-queue.d.ts.map +1 -1
- package/dist/src/runtime/deferred-constraint-queue.js +3 -2
- package/dist/src/runtime/deferred-constraint-queue.js.map +1 -1
- package/dist/src/runtime/emit/add-constraint.d.ts.map +1 -1
- package/dist/src/runtime/emit/add-constraint.js +60 -6
- 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 +4 -4
- package/dist/src/runtime/emit/aggregate.js.map +1 -1
- package/dist/src/runtime/emit/alter-schema-event.d.ts +97 -0
- package/dist/src/runtime/emit/alter-schema-event.d.ts.map +1 -0
- package/dist/src/runtime/emit/alter-schema-event.js +87 -0
- package/dist/src/runtime/emit/alter-schema-event.js.map +1 -0
- package/dist/src/runtime/emit/alter-table.d.ts.map +1 -1
- package/dist/src/runtime/emit/alter-table.js +582 -236
- 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 +50 -7
- package/dist/src/runtime/emit/analyze.js.map +1 -1
- package/dist/src/runtime/emit/assertion-drop-guard.d.ts +37 -0
- package/dist/src/runtime/emit/assertion-drop-guard.d.ts.map +1 -0
- package/dist/src/runtime/emit/assertion-drop-guard.js +59 -0
- package/dist/src/runtime/emit/assertion-drop-guard.js.map +1 -0
- package/dist/src/runtime/emit/assertion-rename-helpers.d.ts +33 -0
- package/dist/src/runtime/emit/assertion-rename-helpers.d.ts.map +1 -0
- package/dist/src/runtime/emit/assertion-rename-helpers.js +124 -0
- package/dist/src/runtime/emit/assertion-rename-helpers.js.map +1 -0
- package/dist/src/runtime/emit/cast.d.ts.map +1 -1
- package/dist/src/runtime/emit/cast.js +4 -19
- package/dist/src/runtime/emit/cast.js.map +1 -1
- package/dist/src/runtime/emit/constraint-check.d.ts.map +1 -1
- package/dist/src/runtime/emit/constraint-check.js +10 -227
- package/dist/src/runtime/emit/constraint-check.js.map +1 -1
- package/dist/src/runtime/emit/create-assertion.d.ts.map +1 -1
- package/dist/src/runtime/emit/create-assertion.js +31 -14
- package/dist/src/runtime/emit/create-assertion.js.map +1 -1
- package/dist/src/runtime/emit/cte.d.ts.map +1 -1
- package/dist/src/runtime/emit/cte.js +11 -6
- package/dist/src/runtime/emit/cte.js.map +1 -1
- package/dist/src/runtime/emit/dml-executor.d.ts.map +1 -1
- package/dist/src/runtime/emit/dml-executor.js +233 -28
- package/dist/src/runtime/emit/dml-executor.js.map +1 -1
- package/dist/src/runtime/emit/drop-assertion.js +8 -8
- package/dist/src/runtime/emit/drop-assertion.js.map +1 -1
- package/dist/src/runtime/emit/drop-column-guards.d.ts +151 -0
- package/dist/src/runtime/emit/drop-column-guards.d.ts.map +1 -0
- package/dist/src/runtime/emit/drop-column-guards.js +230 -0
- package/dist/src/runtime/emit/drop-column-guards.js.map +1 -0
- package/dist/src/runtime/emit/drop-index.d.ts.map +1 -1
- package/dist/src/runtime/emit/drop-index.js +4 -3
- package/dist/src/runtime/emit/drop-index.js.map +1 -1
- package/dist/src/runtime/emit/drop-table.d.ts.map +1 -1
- package/dist/src/runtime/emit/drop-table.js +6 -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 +4 -0
- package/dist/src/runtime/emit/drop-view.js.map +1 -1
- package/dist/src/runtime/emit/hash-aggregate.d.ts.map +1 -1
- package/dist/src/runtime/emit/hash-aggregate.js +2 -2
- package/dist/src/runtime/emit/hash-aggregate.js.map +1 -1
- package/dist/src/runtime/emit/join.d.ts.map +1 -1
- package/dist/src/runtime/emit/join.js +8 -67
- package/dist/src/runtime/emit/join.js.map +1 -1
- package/dist/src/runtime/emit/key-set-semi-join.d.ts.map +1 -1
- package/dist/src/runtime/emit/key-set-semi-join.js +11 -3
- package/dist/src/runtime/emit/key-set-semi-join.js.map +1 -1
- package/dist/src/runtime/emit/materialized-view-helpers.d.ts +4 -4
- package/dist/src/runtime/emit/materialized-view-helpers.d.ts.map +1 -1
- package/dist/src/runtime/emit/materialized-view-helpers.js +34 -22
- package/dist/src/runtime/emit/materialized-view-helpers.js.map +1 -1
- package/dist/src/runtime/emit/materialized-view.d.ts.map +1 -1
- package/dist/src/runtime/emit/materialized-view.js +7 -2
- package/dist/src/runtime/emit/materialized-view.js.map +1 -1
- package/dist/src/runtime/emit/operand-comparator.d.ts +30 -0
- package/dist/src/runtime/emit/operand-comparator.d.ts.map +1 -1
- package/dist/src/runtime/emit/operand-comparator.js +34 -0
- package/dist/src/runtime/emit/operand-comparator.js.map +1 -1
- package/dist/src/runtime/emit/recursive-cte.d.ts.map +1 -1
- package/dist/src/runtime/emit/recursive-cte.js +4 -5
- package/dist/src/runtime/emit/recursive-cte.js.map +1 -1
- package/dist/src/runtime/emit/schema-declarative.d.ts.map +1 -1
- package/dist/src/runtime/emit/schema-declarative.js +30 -0
- package/dist/src/runtime/emit/schema-declarative.js.map +1 -1
- package/dist/src/runtime/emit/subquery.d.ts.map +1 -1
- package/dist/src/runtime/emit/subquery.js +153 -52
- package/dist/src/runtime/emit/subquery.js.map +1 -1
- package/dist/src/runtime/emit/update.d.ts.map +1 -1
- package/dist/src/runtime/emit/update.js +18 -6
- package/dist/src/runtime/emit/update.js.map +1 -1
- package/dist/src/runtime/emit/window.js +36 -23
- package/dist/src/runtime/emit/window.js.map +1 -1
- package/dist/src/runtime/row-constraints.d.ts +85 -0
- package/dist/src/runtime/row-constraints.d.ts.map +1 -0
- package/dist/src/runtime/row-constraints.js +239 -0
- package/dist/src/runtime/row-constraints.js.map +1 -0
- package/dist/src/runtime/types.d.ts +8 -11
- package/dist/src/runtime/types.d.ts.map +1 -1
- package/dist/src/runtime/types.js.map +1 -1
- package/dist/src/schema/assertion.d.ts +14 -1
- package/dist/src/schema/assertion.d.ts.map +1 -1
- package/dist/src/schema/assertion.js +14 -1
- package/dist/src/schema/assertion.js.map +1 -1
- package/dist/src/schema/catalog-persistability.d.ts +19 -16
- package/dist/src/schema/catalog-persistability.d.ts.map +1 -1
- package/dist/src/schema/catalog-persistability.js +92 -20
- package/dist/src/schema/catalog-persistability.js.map +1 -1
- package/dist/src/schema/catalog.d.ts +73 -2
- package/dist/src/schema/catalog.d.ts.map +1 -1
- package/dist/src/schema/catalog.js +220 -39
- package/dist/src/schema/catalog.js.map +1 -1
- package/dist/src/schema/column-source-resolver.d.ts +18 -0
- package/dist/src/schema/column-source-resolver.d.ts.map +1 -0
- package/dist/src/schema/column-source-resolver.js +22 -0
- package/dist/src/schema/column-source-resolver.js.map +1 -0
- package/dist/src/schema/column.d.ts +26 -3
- 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.map +1 -1
- package/dist/src/schema/constraint-builder.js +7 -1
- package/dist/src/schema/constraint-builder.js.map +1 -1
- package/dist/src/schema/ddl-generator.d.ts.map +1 -1
- package/dist/src/schema/ddl-generator.js +27 -6
- package/dist/src/schema/ddl-generator.js.map +1 -1
- package/dist/src/schema/function.d.ts +32 -1
- package/dist/src/schema/function.d.ts.map +1 -1
- package/dist/src/schema/function.js +10 -2
- package/dist/src/schema/function.js.map +1 -1
- package/dist/src/schema/lens-compiler.d.ts.map +1 -1
- package/dist/src/schema/lens-compiler.js +203 -51
- package/dist/src/schema/lens-compiler.js.map +1 -1
- package/dist/src/schema/lens-prover.d.ts +2 -3
- package/dist/src/schema/lens-prover.d.ts.map +1 -1
- package/dist/src/schema/lens-prover.js +19 -11
- package/dist/src/schema/lens-prover.js.map +1 -1
- package/dist/src/schema/manager.d.ts +115 -20
- package/dist/src/schema/manager.d.ts.map +1 -1
- package/dist/src/schema/manager.js +202 -70
- package/dist/src/schema/manager.js.map +1 -1
- package/dist/src/schema/rename-rewriter.d.ts +142 -0
- package/dist/src/schema/rename-rewriter.d.ts.map +1 -1
- package/dist/src/schema/rename-rewriter.js +254 -9
- package/dist/src/schema/rename-rewriter.js.map +1 -1
- package/dist/src/schema/reserved-tags.d.ts +1 -1
- package/dist/src/schema/reserved-tags.d.ts.map +1 -1
- package/dist/src/schema/reserved-tags.js +4 -3
- package/dist/src/schema/reserved-tags.js.map +1 -1
- package/dist/src/schema/schema-differ.d.ts +16 -0
- package/dist/src/schema/schema-differ.d.ts.map +1 -1
- package/dist/src/schema/schema-differ.js +225 -38
- package/dist/src/schema/schema-differ.js.map +1 -1
- package/dist/src/schema/table.d.ts +149 -1
- package/dist/src/schema/table.d.ts.map +1 -1
- package/dist/src/schema/table.js +248 -1
- package/dist/src/schema/table.js.map +1 -1
- package/dist/src/schema/unique-enforcement.d.ts +5 -3
- package/dist/src/schema/unique-enforcement.d.ts.map +1 -1
- package/dist/src/schema/unique-enforcement.js +5 -3
- package/dist/src/schema/unique-enforcement.js.map +1 -1
- package/dist/src/schema/view.d.ts +11 -0
- package/dist/src/schema/view.d.ts.map +1 -1
- package/dist/src/schema/view.js +12 -0
- package/dist/src/schema/view.js.map +1 -1
- package/dist/src/types/builtin-types.d.ts +54 -0
- package/dist/src/types/builtin-types.d.ts.map +1 -1
- package/dist/src/types/builtin-types.js +123 -34
- package/dist/src/types/builtin-types.js.map +1 -1
- package/dist/src/types/cast-semantics.d.ts +42 -0
- package/dist/src/types/cast-semantics.d.ts.map +1 -1
- package/dist/src/types/cast-semantics.js +64 -0
- package/dist/src/types/cast-semantics.js.map +1 -1
- package/dist/src/types/comparison-coercion.d.ts +101 -0
- package/dist/src/types/comparison-coercion.d.ts.map +1 -0
- package/dist/src/types/comparison-coercion.js +162 -0
- package/dist/src/types/comparison-coercion.js.map +1 -0
- package/dist/src/types/index.d.ts +2 -2
- package/dist/src/types/index.d.ts.map +1 -1
- package/dist/src/types/index.js +2 -2
- package/dist/src/types/index.js.map +1 -1
- package/dist/src/types/logical-type.d.ts +7 -0
- package/dist/src/types/logical-type.d.ts.map +1 -1
- package/dist/src/types/logical-type.js.map +1 -1
- package/dist/src/types/validation.d.ts +56 -0
- package/dist/src/types/validation.d.ts.map +1 -1
- package/dist/src/types/validation.js +68 -0
- package/dist/src/types/validation.js.map +1 -1
- package/dist/src/util/{working-table-iterable.d.ts → array-row-iterable.d.ts} +6 -6
- package/dist/src/util/array-row-iterable.d.ts.map +1 -0
- package/dist/src/util/{working-table-iterable.js → array-row-iterable.js} +6 -6
- package/dist/src/util/array-row-iterable.js.map +1 -0
- package/dist/src/util/coercion.d.ts +8 -0
- package/dist/src/util/coercion.d.ts.map +1 -1
- package/dist/src/util/coercion.js +8 -0
- package/dist/src/util/coercion.js.map +1 -1
- package/dist/src/util/comparison.d.ts +16 -3
- package/dist/src/util/comparison.d.ts.map +1 -1
- package/dist/src/util/comparison.js +21 -5
- package/dist/src/util/comparison.js.map +1 -1
- package/dist/src/util/key-serializer.d.ts +46 -0
- package/dist/src/util/key-serializer.d.ts.map +1 -1
- package/dist/src/util/key-serializer.js +47 -0
- package/dist/src/util/key-serializer.js.map +1 -1
- package/dist/src/util/value-set.d.ts +21 -0
- package/dist/src/util/value-set.d.ts.map +1 -0
- package/dist/src/util/value-set.js +22 -0
- package/dist/src/util/value-set.js.map +1 -0
- package/dist/src/vtab/capabilities.d.ts +1 -1
- package/dist/src/vtab/events.d.ts +8 -1
- package/dist/src/vtab/events.d.ts.map +1 -1
- package/dist/src/vtab/events.js.map +1 -1
- package/dist/src/vtab/manifest.d.ts +15 -0
- package/dist/src/vtab/manifest.d.ts.map +1 -1
- package/dist/src/vtab/memory/layer/alter-column.d.ts +147 -0
- package/dist/src/vtab/memory/layer/alter-column.d.ts.map +1 -0
- package/dist/src/vtab/memory/layer/alter-column.js +214 -0
- package/dist/src/vtab/memory/layer/alter-column.js.map +1 -0
- package/dist/src/vtab/memory/layer/base.d.ts.map +1 -1
- package/dist/src/vtab/memory/layer/base.js +4 -3
- package/dist/src/vtab/memory/layer/base.js.map +1 -1
- package/dist/src/vtab/memory/layer/interface.d.ts +2 -2
- package/dist/src/vtab/memory/layer/interface.d.ts.map +1 -1
- package/dist/src/vtab/memory/layer/manager.d.ts +176 -25
- package/dist/src/vtab/memory/layer/manager.d.ts.map +1 -1
- package/dist/src/vtab/memory/layer/manager.js +569 -558
- package/dist/src/vtab/memory/layer/manager.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 +32 -5
- package/dist/src/vtab/memory/layer/scan-layer.js.map +1 -1
- package/dist/src/vtab/memory/layer/transaction.d.ts +101 -15
- package/dist/src/vtab/memory/layer/transaction.d.ts.map +1 -1
- package/dist/src/vtab/memory/layer/transaction.js +133 -45
- package/dist/src/vtab/memory/layer/transaction.js.map +1 -1
- package/dist/src/vtab/memory/module.d.ts +16 -1
- package/dist/src/vtab/memory/module.d.ts.map +1 -1
- package/dist/src/vtab/memory/module.js +64 -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 +11 -6
- package/dist/src/vtab/memory/table.js.map +1 -1
- package/dist/src/vtab/module.d.ts +77 -23
- package/dist/src/vtab/module.d.ts.map +1 -1
- package/dist/src/vtab/table.d.ts +9 -2
- package/dist/src/vtab/table.d.ts.map +1 -1
- package/dist/src/vtab/table.js +1 -1
- package/dist/src/vtab/table.js.map +1 -1
- package/package.json +3 -3
- package/dist/src/util/working-table-iterable.d.ts.map +0 -1
- package/dist/src/util/working-table-iterable.js.map +0 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { buildColumnIndexMap, columnDefToSchema, resolvePkDefaultConflict, resolveNamedConstraintClass,
|
|
1
|
+
import { buildColumnIndexMap, columnDefToSchema, resolvePkDefaultConflict, resolveNamedConstraintClass, shiftSchemaIndicesForDrop, rekeySchemaPrimaryKey } from '../../../schema/table.js';
|
|
2
2
|
import { keyParts } from '../types.js';
|
|
3
3
|
import { BTree } from 'inheritree';
|
|
4
|
+
import { createValueSet } from '../../../util/value-set.js';
|
|
4
5
|
import { StatusCode } from '../../../common/types.js';
|
|
5
6
|
import { BaseLayer, iteratePrimaryRows, populateIndexFromRows, populateIndexFromRowsAsync } from './base.js';
|
|
6
7
|
import { TransactionLayer } from './transaction.js';
|
|
@@ -11,19 +12,32 @@ import { ConflictResolution } from '../../../common/constants.js';
|
|
|
11
12
|
import { buildUniqueConstraintSchema, buildForeignKeyConstraintSchema, buildCheckConstraintSchema, validateForeignKeyOverExistingRows, maintainedTableUniqueViolationError, formatKeyValue } from '../../../schema/constraint-builder.js';
|
|
12
13
|
import { indexEnforcesUnique, uniqueEnforcementCollations, uniqueEnforcementComparators } from '../../../schema/unique-enforcement.js';
|
|
13
14
|
import { generateIndexDDL, generateDropIndexDDL } from '../../../schema/ddl-generator.js';
|
|
14
|
-
import { compareSqlValues, rowsValueIdentical, normalizeCollationName
|
|
15
|
+
import { compareSqlValues, rowsValueIdentical, normalizeCollationName } from '../../../util/comparison.js';
|
|
15
16
|
import { scanLayer as scanLayerImpl } from './scan-layer.js';
|
|
16
17
|
import { createPrimaryKeyFunctions, buildPrimaryKeyFromValues, primaryKeyArity } from '../utils/primary-key.js';
|
|
17
18
|
import { createMemoryTableLoggers } from '../utils/logging.js';
|
|
18
|
-
import {
|
|
19
|
-
import { validateAndParse, coerceRowToSchema } from '../../../types/validation.js';
|
|
20
|
-
import { inferType } from '../../../types/registry.js';
|
|
19
|
+
import { coerceRowToSchema, foldDefaultToType } from '../../../types/validation.js';
|
|
21
20
|
import { compilePredicate } from '../utils/predicate.js';
|
|
22
21
|
import { renameColumnInIndexPredicates } from '../../../schema/rename-rewriter.js';
|
|
23
22
|
import { MemoryIndex } from '../index.js';
|
|
24
23
|
import { convertRowAtIndex, mapRows, mapRowsAsync } from './row-convert.js';
|
|
24
|
+
import { buildAlterColumnPlan, planColumnAttributeChange } from './alter-column.js';
|
|
25
25
|
let tableManagerCounter = 0;
|
|
26
26
|
const logger = createMemoryTableLoggers('layer:manager');
|
|
27
|
+
/**
|
|
28
|
+
* The `_uc_<cols>` auto-name of the implicit covering structure realizing an UNNAMED
|
|
29
|
+
* UNIQUE constraint, resolved over an EXPLICIT column list rather than the manager's
|
|
30
|
+
* live one — `renameColumn` needs the name under the POST-rename columns, which
|
|
31
|
+
* `this.tableSchema` does not carry yet.
|
|
32
|
+
*
|
|
33
|
+
* The name is derived, never recorded, so it MOVES when a covered column is renamed.
|
|
34
|
+
* Every consumer re-derives it (see the catalog's `implicitIndexNameForColumns`, which
|
|
35
|
+
* this mirrors and must stay equal to, and `quereus-store`'s `implicitUniqueIndexName`);
|
|
36
|
+
* keep this the only spelling of the rule inside this file.
|
|
37
|
+
*/
|
|
38
|
+
function implicitIndexNameOver(uc, columns) {
|
|
39
|
+
return `_uc_${uc.columns.map(i => columns[i]?.name ?? String(i)).join('_')}`;
|
|
40
|
+
}
|
|
27
41
|
/** A copy of `items` with `value` inserted at `at` (`at === items.length` ⇒ append). */
|
|
28
42
|
function insertValueAt(items, at, value) {
|
|
29
43
|
const out = items.slice();
|
|
@@ -178,16 +192,36 @@ export class MemoryTableManager {
|
|
|
178
192
|
// it would enforce this non-derived UC under the index's collation rather
|
|
179
193
|
// than the declared one. A collation-mismatched index falls through to a
|
|
180
194
|
// distinct `_uc_*` covering index and coexists as its own constraint.
|
|
181
|
-
|
|
195
|
+
// A filtered (partial) index only covers rows matching its own predicate, so
|
|
196
|
+
// it's never valid backing for an unfiltered UNIQUE — and a filtered UNIQUE
|
|
197
|
+
// already owns its index, so it isn't part of this search either (mirrors
|
|
198
|
+
// `findReusableIndexForUnique` in quereus-store's implicit-unique-index.ts).
|
|
199
|
+
const matchingIndex = uc.predicate ? undefined : existingIndexes.find(idx => !idx.predicate &&
|
|
200
|
+
idx.columns.length === uc.columns.length &&
|
|
182
201
|
idx.columns.every((col, i) => col.index === uc.columns[i]) &&
|
|
183
202
|
this.indexCollationsMatchDeclared(idx, uc));
|
|
203
|
+
// The name this constraint's own structure would take, and whoever already holds
|
|
204
|
+
// it in `newIndexes` — a pre-existing index, or the structure an EARLIER
|
|
205
|
+
// constraint in this same loop just pushed. A held name is ADOPTED, never pushed
|
|
206
|
+
// a second time: two entries under one name is the state `importDDL` warns about
|
|
207
|
+
// (see `SchemaManager.importCatalog`) — `index_info()` then reports neither,
|
|
208
|
+
// `DROP INDEX` answers `no such index`, and a predicate over the covered column
|
|
209
|
+
// stops filtering. No write path can produce a duplicate unnamed UNIQUE any more
|
|
210
|
+
// (`assertNoDuplicateUniqueConstraints` / `assertUniqueConstraintNotDuplicated`
|
|
211
|
+
// refuse it at every declaration site), so this arm is defence in depth for a
|
|
212
|
+
// catalog written before those guards: it degrades to one shared structure and
|
|
213
|
+
// double enforcement rather than to a corrupt index list.
|
|
214
|
+
const wantedName = uc.name ?? this.implicitIndexNameFor(uc);
|
|
215
|
+
const claimedIndex = newIndexes.find(idx => idx.name.toLowerCase() === wantedName.toLowerCase());
|
|
184
216
|
let indexName;
|
|
185
217
|
if (matchingIndex) {
|
|
186
218
|
indexName = matchingIndex.name;
|
|
187
219
|
}
|
|
220
|
+
else if (claimedIndex) {
|
|
221
|
+
indexName = claimedIndex.name;
|
|
222
|
+
}
|
|
188
223
|
else {
|
|
189
|
-
|
|
190
|
-
indexName = uc.name ?? `_uc_${colNames.join('_')}`;
|
|
224
|
+
indexName = wantedName;
|
|
191
225
|
newIndexes.push({
|
|
192
226
|
name: indexName,
|
|
193
227
|
// Carry each column's declared collation so the auto-index — and the
|
|
@@ -220,10 +254,70 @@ export class MemoryTableManager {
|
|
|
220
254
|
const indexName = uc.name ?? this.implicitIndexNameFor(uc);
|
|
221
255
|
return this.implicitCoveringStructures.get(indexName);
|
|
222
256
|
}
|
|
223
|
-
/** Conventional auto-index name for an unnamed UNIQUE constraint
|
|
257
|
+
/** Conventional auto-index name for an unnamed UNIQUE constraint, over the LIVE columns. */
|
|
224
258
|
implicitIndexNameFor(uc) {
|
|
225
|
-
|
|
226
|
-
|
|
259
|
+
return implicitIndexNameOver(uc, this.tableSchema.columns);
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* The materialized covering-index renames a column rename forces: one per UNNAMED
|
|
263
|
+
* UNIQUE constraint covering the renamed column, from its `_uc_<old cols>` name to
|
|
264
|
+
* its `_uc_<new cols>` one.
|
|
265
|
+
*
|
|
266
|
+
* The auto-name is derived from the live column names and recomputed by every
|
|
267
|
+
* consumer ({@link implicitIndexNameFor} here, the catalog's exposure map behind
|
|
268
|
+
* `schema()` / `index_info()`), so leaving the entry under its pre-rename name
|
|
269
|
+
* severs the constraint↔structure link: the structure stops being recognized as
|
|
270
|
+
* hidden (it surfaces as a user index and becomes droppable, taking the
|
|
271
|
+
* constraint's enforcement structure with it) and
|
|
272
|
+
* {@link getImplicitCoveringStructure} falls through to its column-set fallback.
|
|
273
|
+
*
|
|
274
|
+
* Skipped for constraints that do not move: a NAMED one's structure takes the
|
|
275
|
+
* constraint's name, a `derivedFromIndex` one IS the user's index, and one realized
|
|
276
|
+
* by a REUSED user index has no `_uc_*` entry to rename (that index keeps its own
|
|
277
|
+
* name).
|
|
278
|
+
*
|
|
279
|
+
* A case-only column rename DOES produce a rename here, even though every name
|
|
280
|
+
* comparison folds case: the covering-structure map is keyed by the exact derived
|
|
281
|
+
* string, so leaving `_uc_a` in place while consumers derive `_uc_A` would break
|
|
282
|
+
* {@link getImplicitCoveringStructure} the same way. It cannot collide — an index
|
|
283
|
+
* named `_uc_A` could never have been created alongside `_uc_a` in the first place.
|
|
284
|
+
*
|
|
285
|
+
* Pure — the caller applies the result to the new index list and, once the schema
|
|
286
|
+
* swap has succeeded, to {@link implicitCoveringStructures}.
|
|
287
|
+
*/
|
|
288
|
+
planImplicitCoveringIndexRenames(updatedCols, renamedColIndex) {
|
|
289
|
+
const renames = [];
|
|
290
|
+
const indexes = this.tableSchema.indexes ?? [];
|
|
291
|
+
for (const uc of this.tableSchema.uniqueConstraints ?? []) {
|
|
292
|
+
if (uc.name !== undefined || uc.derivedFromIndex !== undefined)
|
|
293
|
+
continue;
|
|
294
|
+
if (!uc.columns.includes(renamedColIndex))
|
|
295
|
+
continue;
|
|
296
|
+
const oldName = implicitIndexNameOver(uc, this.tableSchema.columns);
|
|
297
|
+
const newName = implicitIndexNameOver(uc, updatedCols);
|
|
298
|
+
if (oldName === newName)
|
|
299
|
+
continue;
|
|
300
|
+
if (!indexes.some(idx => idx.name.toLowerCase() === oldName.toLowerCase()))
|
|
301
|
+
continue;
|
|
302
|
+
renames.push({ oldName, newName });
|
|
303
|
+
}
|
|
304
|
+
return renames;
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Re-keys {@link implicitCoveringStructures} for the renames
|
|
308
|
+
* {@link planImplicitCoveringIndexRenames} produced — the map is keyed by
|
|
309
|
+
* constraint identity, which for an unnamed constraint IS the derived index name.
|
|
310
|
+
* Runs only after the schema swap succeeded, so a failed rename leaves the map
|
|
311
|
+
* agreeing with the restored schema.
|
|
312
|
+
*/
|
|
313
|
+
applyImplicitCoveringStructureRenames(renames) {
|
|
314
|
+
for (const { oldName, newName } of renames) {
|
|
315
|
+
const rec = this.implicitCoveringStructures.get(oldName);
|
|
316
|
+
if (!rec)
|
|
317
|
+
continue;
|
|
318
|
+
this.implicitCoveringStructures.delete(oldName);
|
|
319
|
+
this.implicitCoveringStructures.set(newName, { ...rec, indexName: newName });
|
|
320
|
+
}
|
|
227
321
|
}
|
|
228
322
|
/**
|
|
229
323
|
* True when a same-column-set index's per-column collations are
|
|
@@ -504,21 +598,23 @@ export class MemoryTableManager {
|
|
|
504
598
|
connection.clearSavepoints();
|
|
505
599
|
// Emit data change events after successful commit
|
|
506
600
|
if (changes.length > 0 && this.eventEmitter?.emitDataChange) {
|
|
507
|
-
// The
|
|
508
|
-
//
|
|
509
|
-
//
|
|
510
|
-
//
|
|
511
|
-
//
|
|
512
|
-
// (
|
|
513
|
-
//
|
|
514
|
-
//
|
|
515
|
-
|
|
601
|
+
// The contract's `key` is the primary key projected out of the event's OWN row
|
|
602
|
+
// image — `newRow` for an insert or an update, `oldRow` for a delete — under the
|
|
603
|
+
// schema current at DELIVERY (docs/usage.md § Subscribing to Data Changes).
|
|
604
|
+
// Projecting here rather than replaying the key each write recorded is what
|
|
605
|
+
// makes an in-place rewrite that changes the key's VALUE but not the row's
|
|
606
|
+
// identity (a NOCASE 'apple' → 'APPLE', which `recordUpsert` files under the
|
|
607
|
+
// pre-image key) hand listeners the post-image the table actually holds. It also
|
|
608
|
+
// re-derives the key across a mid-transaction ALTER PRIMARY KEY for free: the
|
|
609
|
+
// pending-change images are already reshaped to the delivered schema, so
|
|
610
|
+
// projecting them through THAT schema's key is the re-key.
|
|
611
|
+
const pkIndices = this.tableSchema.primaryKeyDefinition.map(def => def.index);
|
|
516
612
|
for (const change of changes) {
|
|
517
613
|
const event = {
|
|
518
614
|
type: change.type,
|
|
519
615
|
schemaName: this.schemaName,
|
|
520
616
|
tableName: this._tableName,
|
|
521
|
-
key:
|
|
617
|
+
key: this.eventKeyFromImage(change, pkIndices),
|
|
522
618
|
oldRow: change.oldRow,
|
|
523
619
|
newRow: change.newRow,
|
|
524
620
|
};
|
|
@@ -535,6 +631,25 @@ export class MemoryTableManager {
|
|
|
535
631
|
logger.debugLog(`[Commit ${connection.connectionId}] Released lock for ${this._tableName}`);
|
|
536
632
|
}
|
|
537
633
|
}
|
|
634
|
+
/**
|
|
635
|
+
* The delivered `key` of one pending change: the primary key projected out of the change's
|
|
636
|
+
* own row image (`newRow` for an insert or an update, `oldRow` for a delete) through
|
|
637
|
+
* `pkIndices`, the key columns of the schema current at delivery.
|
|
638
|
+
*
|
|
639
|
+
* Best-effort, exactly like the pending-change image reshape it consumes: an image the
|
|
640
|
+
* reshape had to leave at the retired arity cannot be projected, so the event ships with no
|
|
641
|
+
* key and logs rather than emitting an `undefined` key slot a listener would file a row
|
|
642
|
+
* under. (A `PendingChange` always carries at least one image — `recordUpsert` sets
|
|
643
|
+
* `newRow`, `recordDelete` sets `oldRow` — so a missing image means only that.)
|
|
644
|
+
*/
|
|
645
|
+
eventKeyFromImage(change, pkIndices) {
|
|
646
|
+
const image = change.newRow ?? change.oldRow;
|
|
647
|
+
if (image && pkIndices.every(i => i >= 0 && i < image.length)) {
|
|
648
|
+
return pkIndices.map(i => image[i]);
|
|
649
|
+
}
|
|
650
|
+
logger.warn('Commit Transaction', this._tableName, `${change.type} event has no image the delivered primary key can be projected from; delivering it with no key`);
|
|
651
|
+
return undefined;
|
|
652
|
+
}
|
|
538
653
|
/** All layers in `layer`'s parent chain, including `layer` itself. */
|
|
539
654
|
layerChainSet(layer) {
|
|
540
655
|
const chain = new Set();
|
|
@@ -1057,8 +1172,8 @@ export class MemoryTableManager {
|
|
|
1057
1172
|
// finer index (e.g. BINARY over a NOCASE column) no longer collapses onto
|
|
1058
1173
|
// the constraint; resolving by name is robust to `schema.indexes` order
|
|
1059
1174
|
// (the finer index may be listed earlier, having been created first).
|
|
1060
|
-
// Both fall through to the column-set scan
|
|
1061
|
-
// resolve
|
|
1175
|
+
// Both fall through to the column-set scan below when the name does not
|
|
1176
|
+
// resolve — see there for when that actually happens.
|
|
1062
1177
|
if (uc.derivedFromIndex) {
|
|
1063
1178
|
const index = targetLayer.getSecondaryIndex?.(uc.derivedFromIndex);
|
|
1064
1179
|
if (index)
|
|
@@ -1072,14 +1187,40 @@ export class MemoryTableManager {
|
|
|
1072
1187
|
return { kind: 'memory-index', index };
|
|
1073
1188
|
}
|
|
1074
1189
|
}
|
|
1075
|
-
//
|
|
1076
|
-
//
|
|
1190
|
+
// Fallback: match the covering index by column-set when the by-name
|
|
1191
|
+
// resolution above did not land. Reached more often than "defensive"
|
|
1192
|
+
// suggests — the reuse arms of `ensureUniqueConstraintIndexes` /
|
|
1193
|
+
// `addUniqueConstraint` register an UNNAMED constraint's structure under the
|
|
1194
|
+
// REUSED index's name, which `getImplicitCoveringStructure` (keyed
|
|
1195
|
+
// `_uc_<cols>`) then cannot find; and a reused index that is later dropped
|
|
1196
|
+
// leaves the recorded name unresolvable.
|
|
1197
|
+
//
|
|
1198
|
+
// So this scan must apply the SAME admissibility rule as those two reuse
|
|
1199
|
+
// searches, or it re-opens the hole they close: a FILTERED index holds only
|
|
1200
|
+
// the rows its predicate admits, and `checkSingleUniqueConstraint` skips the
|
|
1201
|
+
// check outright for a row outside the covering index's predicate — adopting
|
|
1202
|
+
// one for an unfiltered UNIQUE silently narrows enforcement to the
|
|
1203
|
+
// predicate's scope. A collation-mismatched index enforces under ITS
|
|
1204
|
+
// collation rather than the declared one, the same way.
|
|
1205
|
+
//
|
|
1206
|
+
// Returning undefined is always SAFE: the caller falls back to the
|
|
1207
|
+
// predicate- and collation-aware full scan, which is slower but exact. So a
|
|
1208
|
+
// filtered constraint does not guess here at all — its own structure is
|
|
1209
|
+
// resolved by name above.
|
|
1210
|
+
if (uc.predicate)
|
|
1211
|
+
return undefined;
|
|
1077
1212
|
for (const idx of schema.indexes) {
|
|
1078
|
-
if (idx.
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1213
|
+
if (idx.predicate)
|
|
1214
|
+
continue;
|
|
1215
|
+
if (idx.columns.length !== uc.columns.length)
|
|
1216
|
+
continue;
|
|
1217
|
+
if (!idx.columns.every((col, i) => col.index === uc.columns[i]))
|
|
1218
|
+
continue;
|
|
1219
|
+
if (!this.indexCollationsMatchDeclared(idx, uc))
|
|
1220
|
+
continue;
|
|
1221
|
+
const index = targetLayer.getSecondaryIndex?.(idx.name);
|
|
1222
|
+
if (index)
|
|
1223
|
+
return { kind: 'memory-index', index };
|
|
1083
1224
|
}
|
|
1084
1225
|
return undefined;
|
|
1085
1226
|
}
|
|
@@ -1307,34 +1448,9 @@ export class MemoryTableManager {
|
|
|
1307
1448
|
// (`readLayer.getSchema() === this.tableSchema`) and drops the transaction's staged
|
|
1308
1449
|
// rows at COMMIT.
|
|
1309
1450
|
this.adoptSchemaOnOpenLayers(renamed);
|
|
1310
|
-
//
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
objectType: 'table',
|
|
1314
|
-
schemaName: this.schemaName,
|
|
1315
|
-
objectName: newName,
|
|
1316
|
-
});
|
|
1317
|
-
}
|
|
1318
|
-
/** Iterates all committed rows from the current committed layer (for rebuild). */
|
|
1319
|
-
scanAllRows() {
|
|
1320
|
-
const tree = this._currentCommittedLayer.getModificationTree('primary');
|
|
1321
|
-
if (!tree)
|
|
1322
|
-
return [];
|
|
1323
|
-
const rows = [];
|
|
1324
|
-
for (const path of tree.ascending(tree.first())) {
|
|
1325
|
-
rows.push(tree.at(path));
|
|
1326
|
-
}
|
|
1327
|
-
return rows;
|
|
1328
|
-
}
|
|
1329
|
-
/** Inserts a row directly into the base layer (for rebuild, bypasses transaction).
|
|
1330
|
-
* Throws on duplicate primary key. */
|
|
1331
|
-
insertRow(row) {
|
|
1332
|
-
const key = this.primaryKeyFunctions.extractFromRow(row);
|
|
1333
|
-
const path = this.baseLayer.primaryTree.find(key);
|
|
1334
|
-
if (path.on) {
|
|
1335
|
-
throw new QuereusError(`UNIQUE constraint failed: ${this._tableName} PK.`, StatusCode.CONSTRAINT);
|
|
1336
|
-
}
|
|
1337
|
-
this.baseLayer.primaryTree.insert(row);
|
|
1451
|
+
// No emit here (or in any other ALTER-arm manager method): the module-level
|
|
1452
|
+
// `alterTable`/`renameTable` raises the statement's ONE schema event, gated on the
|
|
1453
|
+
// engine-set `change.ddl` — so a wrapper-driven manager call announces nothing.
|
|
1338
1454
|
}
|
|
1339
1455
|
/**
|
|
1340
1456
|
* Atomically replaces the entire committed contents with `rows` by building a
|
|
@@ -1504,7 +1620,9 @@ export class MemoryTableManager {
|
|
|
1504
1620
|
oldByKey.insert({ key: this.primaryKeyFunctions.extractFromRow(row), row });
|
|
1505
1621
|
}
|
|
1506
1622
|
// New-row keys (same PK comparator) for the delete pass's membership test.
|
|
1507
|
-
|
|
1623
|
+
// Entry is the bare PK value, so it must be a non-freezing set: a
|
|
1624
|
+
// single-column BLOB PK is a `Uint8Array`, which `Object.freeze` rejects.
|
|
1625
|
+
const newKeys = createValueSet(this.comparePrimaryKeys);
|
|
1508
1626
|
// Insert/update/skip-identical pass, in new-row order.
|
|
1509
1627
|
for (const newRow of op.rows) {
|
|
1510
1628
|
const key = this.primaryKeyFunctions.extractFromRow(newRow);
|
|
@@ -1594,7 +1712,7 @@ export class MemoryTableManager {
|
|
|
1594
1712
|
const result = await this.checkSingleUniqueConstraint(layer, schema, uc, change.newRow, newPrimaryKey, ConflictResolution.ABORT, noEvict, /*allowMvCovering*/ false);
|
|
1595
1713
|
if (result) {
|
|
1596
1714
|
const colNames = uc.columns.map(i => schema.columns[i]?.name ?? String(i));
|
|
1597
|
-
throw maintainedTableUniqueViolationError(this.schemaName, this._tableName, uc.name ??
|
|
1715
|
+
throw maintainedTableUniqueViolationError(this.schemaName, this._tableName, uc.name ?? implicitIndexNameOver(uc, schema.columns), colNames, uc.columns.map(i => change.newRow[i]));
|
|
1598
1716
|
}
|
|
1599
1717
|
}
|
|
1600
1718
|
}
|
|
@@ -1628,13 +1746,14 @@ export class MemoryTableManager {
|
|
|
1628
1746
|
throw new QuereusError(`Duplicate column name: ${newColumnSchema.name}`, StatusCode.ERROR);
|
|
1629
1747
|
}
|
|
1630
1748
|
let defaultValue = null;
|
|
1631
|
-
let defaultIsLiteral = false;
|
|
1632
1749
|
const defaultConstraint = columnDefAst.constraints.find(c => c.type === 'default');
|
|
1633
1750
|
if (defaultConstraint && defaultConstraint.expr) {
|
|
1634
|
-
|
|
1751
|
+
// Fold AND convert to the new column's declared type, so the backfilled cell
|
|
1752
|
+
// is the value a fresh INSERT under the same DEFAULT would store. An
|
|
1753
|
+
// unconvertible literal (`integer default 'abc'`) throws MISMATCH here.
|
|
1754
|
+
const folded = foldDefaultToType(defaultConstraint.expr, newColumnSchema.logicalType, newColumnSchema.name);
|
|
1635
1755
|
if (folded !== undefined) {
|
|
1636
1756
|
defaultValue = folded;
|
|
1637
|
-
defaultIsLiteral = true;
|
|
1638
1757
|
}
|
|
1639
1758
|
else {
|
|
1640
1759
|
// A non-literal expression default (e.g. `new.<col>`) is written as NULL
|
|
@@ -1643,13 +1762,27 @@ export class MemoryTableManager {
|
|
|
1643
1762
|
}
|
|
1644
1763
|
}
|
|
1645
1764
|
// Check for NOT NULL constraint (could be explicit or from default behavior).
|
|
1646
|
-
// Allow NOT NULL without
|
|
1647
|
-
//
|
|
1648
|
-
//
|
|
1649
|
-
//
|
|
1765
|
+
// Allow NOT NULL without a value source if the table is empty (SQLite-compatible).
|
|
1766
|
+
//
|
|
1767
|
+
// `!backfillEvaluator` is the load-bearing clause, and mirrors
|
|
1768
|
+
// `StoreModuleBase.alterAddColumn`: an engine-supplied evaluator — a non-foldable
|
|
1769
|
+
// expression default (`new.<col>`) OR a `generated always as` expression — fills
|
|
1770
|
+
// each existing row right after this returns, and NOT NULL is then enforced on the
|
|
1771
|
+
// computed values (`BaseLayer.recreatePrimaryTreeWithNewColumn`, plus the
|
|
1772
|
+
// pending-row pass below). Asking only which KIND of DEFAULT was written used to
|
|
1773
|
+
// reject a NOT NULL generated column on a non-empty table the evaluator could fill,
|
|
1774
|
+
// and (in the other direction) to admit `default null` on a column that is NOT NULL
|
|
1775
|
+
// only by the session `default_column_nullability`. The gate is value-based now, so
|
|
1776
|
+
// it matches `StoreModuleBase.alterAddColumn` word for word.
|
|
1777
|
+
//
|
|
1778
|
+
// NOTE: that agreement — here, in the store module, and in the engine's own
|
|
1779
|
+
// pre-check in `runAddColumn` — is held together only by section 8 of
|
|
1780
|
+
// `test/logic/41.4-alter-add-column-constraints.sqllogic` running under both
|
|
1781
|
+
// `yarn test` and `yarn test:store`. Nothing enforces it mechanically. If a
|
|
1782
|
+
// fourth site ever needs the same rule, hoist it to one shared predicate
|
|
1783
|
+
// rather than adding another copy.
|
|
1650
1784
|
const tableHasRows = this.baseLayer.primaryTree.at(this.baseLayer.primaryTree.first()) !== undefined;
|
|
1651
|
-
|
|
1652
|
-
if (newColumnSchema.notNull && defaultValue === null && !defaultIsLiteral && !hasDefaultExpr && tableHasRows) {
|
|
1785
|
+
if (newColumnSchema.notNull && defaultValue === null && !backfillEvaluator && tableHasRows) {
|
|
1653
1786
|
throw new QuereusError(`Cannot add NOT NULL column '${newColumnSchema.name}' to non-empty table `
|
|
1654
1787
|
+ `'${this.schemaName}.${this._tableName}' without a DEFAULT value`, StatusCode.CONSTRAINT);
|
|
1655
1788
|
}
|
|
@@ -1709,27 +1842,14 @@ export class MemoryTableManager {
|
|
|
1709
1842
|
return insertValueAt(row, targetIndex, value);
|
|
1710
1843
|
});
|
|
1711
1844
|
this.baseLayer.updateSchema(finalNewTableSchema);
|
|
1712
|
-
// A non-foldable DEFAULT (e.g. `new.<col>`)
|
|
1713
|
-
//
|
|
1714
|
-
//
|
|
1845
|
+
// A per-row value source — a non-foldable DEFAULT (e.g. `new.<col>`) or a
|
|
1846
|
+
// `generated always as` expression — backfills each existing row from its own
|
|
1847
|
+
// value via the engine-supplied evaluator; a literal/NULL default uses the
|
|
1848
|
+
// single folded `defaultValue` for every row.
|
|
1715
1849
|
await this.baseLayer.addColumnToBase(newColumnSchema, defaultValue, backfillEvaluator, targetIndex);
|
|
1716
1850
|
this.tableSchema = finalNewTableSchema;
|
|
1717
1851
|
this.initializePrimaryKeyFunctions();
|
|
1718
1852
|
this.installReshapeOnOpenLayers(finalNewTableSchema, reshapePlans);
|
|
1719
|
-
// Emit schema change event.
|
|
1720
|
-
// NOTE: the event names the added column but not its position, which is fine while
|
|
1721
|
-
// the only non-append caller is an in-process wrapper that rebuilds its view from the
|
|
1722
|
-
// post-change schema. An append never invalidates an existing column index; an insert
|
|
1723
|
-
// does. If a position ever becomes SQL-reachable, anything that caches a column index
|
|
1724
|
-
// across this swap (planner caches, prepared statements, a wrapper's own schema
|
|
1725
|
-
// snapshot) needs to learn the insert point — so the event would have to carry it.
|
|
1726
|
-
this.eventEmitter?.emitSchemaChange?.({
|
|
1727
|
-
type: 'alter',
|
|
1728
|
-
objectType: 'column',
|
|
1729
|
-
schemaName: this.schemaName,
|
|
1730
|
-
objectName: this._tableName,
|
|
1731
|
-
columnName: newColumnSchema.name,
|
|
1732
|
-
});
|
|
1733
1853
|
logger.operation('Add Column', this._tableName, { columnName: newColumnSchema.name });
|
|
1734
1854
|
}
|
|
1735
1855
|
catch (e) {
|
|
@@ -1758,57 +1878,23 @@ export class MemoryTableManager {
|
|
|
1758
1878
|
if (this.tableSchema.primaryKeyDefinition.some(def => def.index === colIndex)) {
|
|
1759
1879
|
throw new QuereusError(`Cannot drop PK column "${columnName}".`, StatusCode.CONSTRAINT);
|
|
1760
1880
|
}
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
const updatedPrimaryKeyNames = updatedPkDefinition.map(def => updatedColumnsSchema[def.index]?.name).filter(Boolean);
|
|
1766
|
-
// Prune any UNIQUE constraint over the dropped column. A UNIQUE that includes the
|
|
1767
|
-
// dropped column is removed outright (a UNIQUE missing one of its columns is a
|
|
1768
|
-
// different, stronger constraint, not a silently-narrowed one); the auto-built
|
|
1769
|
-
// covering index it backed is torn down with it (see the index exclusion below).
|
|
1770
|
-
// Remaining constraints have their column indices shifted to track the removed slot.
|
|
1771
|
-
// Without this, dropping a uniquely-constrained column (including the ADD COLUMN +
|
|
1772
|
-
// inline-UNIQUE revert path) would strand a constraint whose column index dangles
|
|
1773
|
-
// past the end of the column array.
|
|
1774
|
-
const oldUniqueConstraints = this.tableSchema.uniqueConstraints ?? [];
|
|
1775
|
-
const droppedUcKeys = oldUniqueConstraints
|
|
1776
|
-
.filter(uc => uc.columns.includes(colIndex))
|
|
1777
|
-
.map(uc => uc.name ?? this.implicitIndexNameFor(uc));
|
|
1778
|
-
const remainingUniqueConstraints = oldUniqueConstraints
|
|
1779
|
-
.filter(uc => !uc.columns.includes(colIndex))
|
|
1780
|
-
.map(uc => ({ ...uc, columns: Object.freeze(uc.columns.map(i => i > colIndex ? i - 1 : i)) }));
|
|
1881
|
+
// Renumber every position-bearing field over the removed slot — shared with the
|
|
1882
|
+
// store module's `alterDropColumn`, the mirror of `shiftSchemaIndicesForInsert`.
|
|
1883
|
+
const shifted = shiftSchemaIndicesForDrop(this.tableSchema, colIndex);
|
|
1884
|
+
const updatedPrimaryKeyNames = shifted.primaryKeyDefinition.map(def => shifted.columns[def.index]?.name).filter(Boolean);
|
|
1781
1885
|
// Drop the implicit covering index of each removed constraint outright (matched by
|
|
1782
1886
|
// the same `uc.name ?? '_uc_<cols>'` convention DROP CONSTRAINT uses, so a user
|
|
1783
|
-
// index that merely shares columns is left untouched)
|
|
1784
|
-
//
|
|
1785
|
-
//
|
|
1786
|
-
//
|
|
1787
|
-
//
|
|
1887
|
+
// index that merely shares columns is left untouched). Only this backend needs the
|
|
1888
|
+
// pass: the covering index deliberately carries no `unique: true` flag (enforcement
|
|
1889
|
+
// routes through `uniqueConstraints`), so `shiftSchemaIndicesForDrop`'s own
|
|
1890
|
+
// drop-unique-indexes-outright rule does not see it. A *single*-column covering index
|
|
1891
|
+
// collapses to empty and is dropped by the helper's `length > 0` filter regardless;
|
|
1892
|
+
// this exclusion is what tears down a *multi*-column one, which would otherwise
|
|
1893
|
+
// survive orphaned — narrowed to its surviving columns — in `index_info` and on every
|
|
1894
|
+
// write.
|
|
1895
|
+
const droppedUcKeys = shifted.removedUniqueConstraints.map(uc => uc.name ?? this.implicitIndexNameFor(uc));
|
|
1788
1896
|
const droppedCoveringIndexNames = new Set(droppedUcKeys.map(k => k.toLowerCase()));
|
|
1789
|
-
const updatedIndexes =
|
|
1790
|
-
.filter(idx => !droppedCoveringIndexNames.has(idx.name.toLowerCase()))
|
|
1791
|
-
.map(idx => ({
|
|
1792
|
-
...idx,
|
|
1793
|
-
columns: idx.columns
|
|
1794
|
-
.filter(ic => ic.index !== colIndex)
|
|
1795
|
-
.map(ic => ({ ...ic, index: ic.index > colIndex ? ic.index - 1 : ic.index }))
|
|
1796
|
-
})).filter(idx => idx.columns.length > 0);
|
|
1797
|
-
// Shift or prune the table's own foreign keys. `foreignKeys[].columns` are indices
|
|
1798
|
-
// into THIS table, so they renumber over the removed slot exactly as the PK and the
|
|
1799
|
-
// UNIQUE constraints above do. A foreign key that loses ANY of its child columns is
|
|
1800
|
-
// removed outright, the same call the UNIQUE pruning makes: a key missing one of its
|
|
1801
|
-
// child columns is a different constraint against the parent's key, not a narrowed
|
|
1802
|
-
// one. Both halves matter — left unshifted, a surviving key's index either dangles
|
|
1803
|
-
// past the end of the column array or, worse, silently slides onto an unrelated
|
|
1804
|
-
// column and starts enforcing against the parent there.
|
|
1805
|
-
//
|
|
1806
|
-
// `referencedColumns` is not touched: enforcement resolves the parent indices on
|
|
1807
|
-
// demand from `referencedColumnNames` against the parent's current schema. See
|
|
1808
|
-
// `shiftSchemaIndicesForInsert`, the ADD-COLUMN-at-a-position mirror of this block.
|
|
1809
|
-
const remainingForeignKeys = (this.tableSchema.foreignKeys ?? [])
|
|
1810
|
-
.filter(fk => !fk.columns.includes(colIndex))
|
|
1811
|
-
.map(fk => ({ ...fk, columns: Object.freeze(fk.columns.map(i => i > colIndex ? i - 1 : i)) }));
|
|
1897
|
+
const updatedIndexes = shifted.indexes.filter(idx => !droppedCoveringIndexNames.has(idx.name.toLowerCase()));
|
|
1812
1898
|
// NOTE: the generated-column bookkeeping (`generatedColumnDependencies` /
|
|
1813
1899
|
// `generatedColumnTopoOrder`, also index-keyed) is likewise unshifted, but the
|
|
1814
1900
|
// engine recomputes it from column names right after this returns
|
|
@@ -1818,17 +1904,13 @@ export class MemoryTableManager {
|
|
|
1818
1904
|
// `primaryKey` below is not a TableSchema field at all — nothing reads it.
|
|
1819
1905
|
const finalNewTableSchema = Object.freeze({
|
|
1820
1906
|
...this.tableSchema,
|
|
1821
|
-
columns:
|
|
1822
|
-
columnIndexMap: buildColumnIndexMap(
|
|
1823
|
-
primaryKeyDefinition:
|
|
1907
|
+
columns: shifted.columns,
|
|
1908
|
+
columnIndexMap: buildColumnIndexMap(shifted.columns),
|
|
1909
|
+
primaryKeyDefinition: shifted.primaryKeyDefinition,
|
|
1824
1910
|
primaryKey: Object.freeze(updatedPrimaryKeyNames),
|
|
1825
1911
|
indexes: Object.freeze(updatedIndexes),
|
|
1826
|
-
uniqueConstraints:
|
|
1827
|
-
|
|
1828
|
-
: undefined,
|
|
1829
|
-
foreignKeys: remainingForeignKeys.length > 0
|
|
1830
|
-
? Object.freeze(remainingForeignKeys)
|
|
1831
|
-
: undefined,
|
|
1912
|
+
uniqueConstraints: shifted.uniqueConstraints,
|
|
1913
|
+
foreignKeys: shifted.foreignKeys,
|
|
1832
1914
|
});
|
|
1833
1915
|
// Phase 1 of reaching the open transaction's own pending rows. The rewrite here is
|
|
1834
1916
|
// a pure filter and cannot throw — the split exists for ADD COLUMN's fallible
|
|
@@ -1845,14 +1927,6 @@ export class MemoryTableManager {
|
|
|
1845
1927
|
this.implicitCoveringStructures.delete(key);
|
|
1846
1928
|
this.initializePrimaryKeyFunctions();
|
|
1847
1929
|
this.installReshapeOnOpenLayers(finalNewTableSchema, reshapePlans);
|
|
1848
|
-
// Emit schema change event
|
|
1849
|
-
this.eventEmitter?.emitSchemaChange?.({
|
|
1850
|
-
type: 'drop',
|
|
1851
|
-
objectType: 'column',
|
|
1852
|
-
schemaName: this.schemaName,
|
|
1853
|
-
objectName: this._tableName,
|
|
1854
|
-
columnName,
|
|
1855
|
-
});
|
|
1856
1930
|
logger.operation('Drop Column', this._tableName, { columnName });
|
|
1857
1931
|
}
|
|
1858
1932
|
catch (e) {
|
|
@@ -1891,8 +1965,17 @@ export class MemoryTableManager {
|
|
|
1891
1965
|
const defaultNotNull = defaultNullability === 'not_null';
|
|
1892
1966
|
const newColumnSchemaAtIndex = columnDefToSchema(newColumnDefAst, defaultNotNull, 'BINARY', (n) => this.db.isCollationRegistered(n));
|
|
1893
1967
|
const updatedCols = this.tableSchema.columns.map((c, i) => i === colIndex ? newColumnSchemaAtIndex : c);
|
|
1968
|
+
// An unnamed UNIQUE's covering index is named `_uc_<column names>`, so renaming a
|
|
1969
|
+
// covered column moves that name — rewrite the materialized ENTRY, not just its
|
|
1970
|
+
// column references, or the structure is orphaned under the old name (see
|
|
1971
|
+
// {@link planImplicitCoveringIndexRenames}). The engine refuses the statement up
|
|
1972
|
+
// front when the post-rename name is already an index here, so no rename below can
|
|
1973
|
+
// collide with a sibling entry.
|
|
1974
|
+
const coveringRenames = this.planImplicitCoveringIndexRenames(updatedCols, colIndex);
|
|
1975
|
+
const renamedTo = new Map(coveringRenames.map(r => [r.oldName.toLowerCase(), r.newName]));
|
|
1894
1976
|
const updatedIndexes = (this.tableSchema.indexes || []).map(idx => ({
|
|
1895
1977
|
...idx,
|
|
1978
|
+
name: renamedTo.get(idx.name.toLowerCase()) ?? idx.name,
|
|
1896
1979
|
columns: idx.columns.map(ic => ic.index === colIndex ? { ...ic, name: newColumnName } : ic)
|
|
1897
1980
|
}));
|
|
1898
1981
|
const finalNewTableSchema = Object.freeze({
|
|
@@ -1925,8 +2008,13 @@ export class MemoryTableManager {
|
|
|
1925
2008
|
predicatesRewritten = true;
|
|
1926
2009
|
renameColumnInIndexPredicates(finalNewTableSchema.indexes, this._tableName, oldName, newColumnName, this.schemaName, resolveColumnInSource);
|
|
1927
2010
|
this.baseLayer.updateSchema(finalNewTableSchema);
|
|
2011
|
+
// Rebuilds every secondary index from the new schema, so a renamed covering index
|
|
2012
|
+
// lands under its new key in the base's index map with no extra rebuild here.
|
|
1928
2013
|
await this.baseLayer.handleColumnRename();
|
|
1929
2014
|
this.tableSchema = finalNewTableSchema;
|
|
2015
|
+
// Only now that the swap has succeeded — the catch below restores the old schema
|
|
2016
|
+
// and the map must keep agreeing with it.
|
|
2017
|
+
this.applyImplicitCoveringStructureRenames(coveringRenames);
|
|
1930
2018
|
this.initializePrimaryKeyFunctions();
|
|
1931
2019
|
// The DDL transaction's own layers froze their schema at creation; hand them the
|
|
1932
2020
|
// renamed one, mirroring `handleColumnRename`'s base-side secondary rebuild —
|
|
@@ -1942,15 +2030,6 @@ export class MemoryTableManager {
|
|
|
1942
2030
|
// silently dropped at COMMIT. Covered by
|
|
1943
2031
|
// `test/logic/41.8-alter-savepoint-staged-rows.sqllogic`.
|
|
1944
2032
|
this.adoptSchemaOnOpenLayers(finalNewTableSchema);
|
|
1945
|
-
// Emit schema change event
|
|
1946
|
-
this.eventEmitter?.emitSchemaChange?.({
|
|
1947
|
-
type: 'alter',
|
|
1948
|
-
objectType: 'column',
|
|
1949
|
-
schemaName: this.schemaName,
|
|
1950
|
-
objectName: this._tableName,
|
|
1951
|
-
columnName: newColumnName,
|
|
1952
|
-
oldColumnName: oldName,
|
|
1953
|
-
});
|
|
1954
2033
|
logger.operation('Rename Column', this._tableName, { oldName, newName: newColumnName });
|
|
1955
2034
|
}
|
|
1956
2035
|
catch (e) {
|
|
@@ -1971,10 +2050,17 @@ export class MemoryTableManager {
|
|
|
1971
2050
|
}
|
|
1972
2051
|
}
|
|
1973
2052
|
/**
|
|
1974
|
-
* Apply a single-attribute ALTER COLUMN change (NOT NULL, DEFAULT, DATA TYPE).
|
|
2053
|
+
* Apply a single-attribute ALTER COLUMN change (NOT NULL, DEFAULT, DATA TYPE, COLLATE).
|
|
1975
2054
|
* The caller supplies exactly one populated change; multi-attribute combinations
|
|
1976
2055
|
* are rejected by the runtime before reaching this method.
|
|
1977
2056
|
*
|
|
2057
|
+
* The body is the ordering contract, and only that: resolve the column → decide the change
|
|
2058
|
+
* and pre-validate it (`alter-column.ts`, which mutates nothing) → probe the re-keyed
|
|
2059
|
+
* structures ({@link validateAlterColumnPlan}) → rebuild the base
|
|
2060
|
+
* ({@link applyAlterColumnToBase}, the first write) → swap this manager's schema →
|
|
2061
|
+
* propagate to open layers ({@link propagateAlterColumnToOpenLayers}) → emit. Each step's
|
|
2062
|
+
* own reasoning lives on the step.
|
|
2063
|
+
*
|
|
1978
2064
|
* `validateOnly` runs everything up to (and including) the pre-mutation validation
|
|
1979
2065
|
* passes — the effective-row NULL / conversion scans, the re-keyed UNIQUE probe, and
|
|
1980
2066
|
* the primary-key re-key legality/representability passes — and returns before the
|
|
@@ -1988,8 +2074,7 @@ export class MemoryTableManager {
|
|
|
1988
2074
|
const lockKey = `MemoryTable.SchemaChange:${this.schemaName}.${this._tableName}`;
|
|
1989
2075
|
const release = await this.db.latches.acquire(lockKey);
|
|
1990
2076
|
const originalManagerSchema = this.tableSchema;
|
|
1991
|
-
|
|
1992
|
-
let basePrimaryTreeBeforeRekey = null;
|
|
2077
|
+
const undo = { basePrimaryTree: null };
|
|
1993
2078
|
try {
|
|
1994
2079
|
await this.ensureSchemaChangeSafety();
|
|
1995
2080
|
const colNameLower = change.columnName.toLowerCase();
|
|
@@ -1997,382 +2082,50 @@ export class MemoryTableManager {
|
|
|
1997
2082
|
if (colIndex === -1) {
|
|
1998
2083
|
throw new QuereusError(`Column '${change.columnName}' not found.`, StatusCode.ERROR);
|
|
1999
2084
|
}
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
//
|
|
2003
|
-
//
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
// backfill (map null → DEFAULT). Both REPLACE the base primary tree with a
|
|
2018
|
-
// freshly-built one (never an in-place mutation, which inheritree forbids while the
|
|
2019
|
-
// open transaction's layers derive from it) and convert the transaction's
|
|
2020
|
-
// own-written rows in every open layer, after `updateSchema` (see the rebuild
|
|
2021
|
-
// section and convertColumnOnOpenLayers).
|
|
2022
|
-
let valueConvert = null;
|
|
2023
|
-
// SET NOT NULL backfill also routes NULL values through `valueConvert`; SET DATA TYPE
|
|
2024
|
-
// leaves nulls untouched. Selects the null-including path in convertBaseRows/convertColumn.
|
|
2025
|
-
let convertNulls = false;
|
|
2026
|
-
if (change.setCollation !== undefined) {
|
|
2027
|
-
const normalized = validateCollationForType(change.setCollation, oldCol.logicalType, change.columnName, (n) => this.db.isCollationRegistered(n));
|
|
2028
|
-
const nameMatches = normalized === (oldCol.collation || 'BINARY');
|
|
2029
|
-
if (nameMatches && oldCol.collationExplicit) {
|
|
2030
|
-
return; // already explicit in the desired collation — nothing to do
|
|
2031
|
-
}
|
|
2032
|
-
// SET COLLATE is a user declaration with the same standing as a
|
|
2033
|
-
// CREATE-time COLLATE clause, so mark the collation explicit (rank 2 in
|
|
2034
|
-
// the comparison lattice) regardless of the column's creation history —
|
|
2035
|
-
// including SET COLLATE binary. When only the name matches but the column
|
|
2036
|
-
// was not yet explicit (a defaulted collation, or one inherited from
|
|
2037
|
-
// session default_collation), flip the flag as a METADATA-ONLY change:
|
|
2038
|
-
// the collation bytes are unchanged, so keep collationChanged false and
|
|
2039
|
-
// skip the physical re-sort / re-key / UNIQUE re-validation below. A
|
|
2040
|
-
// different name takes the full path AND sets the flag.
|
|
2041
|
-
newCol = { ...oldCol, collation: normalized, collationExplicit: true };
|
|
2042
|
-
collationChanged = !nameMatches;
|
|
2043
|
-
}
|
|
2044
|
-
else if (change.setNotNull !== undefined) {
|
|
2045
|
-
if (change.setNotNull === true && !oldCol.notNull) {
|
|
2046
|
-
// Tightening: scan the DDL transaction's EFFECTIVE rows for NULLs — committed rows
|
|
2047
|
-
// overlaid with this transaction's own pending writes — exactly as the setDataType
|
|
2048
|
-
// arm does. A pending NULL the transaction can SEE rejects the ALTER; one only in a
|
|
2049
|
-
// row it has DELETED does not block it. `rows` is the wrapper-supplied effective set
|
|
2050
|
-
// (the isolation overlay); when absent, effectiveDdlRows() is the layered view.
|
|
2051
|
-
const defaultExpr = oldCol.defaultValue;
|
|
2052
|
-
const defaultLiteral = defaultExpr ? tryFoldLiteral(defaultExpr) : undefined;
|
|
2053
|
-
let anyNull = false;
|
|
2054
|
-
if (rows) {
|
|
2055
|
-
for await (const row of rows()) {
|
|
2056
|
-
if (row[colIndex] === null) {
|
|
2057
|
-
anyNull = true;
|
|
2058
|
-
break;
|
|
2059
|
-
}
|
|
2060
|
-
}
|
|
2061
|
-
}
|
|
2062
|
-
else {
|
|
2063
|
-
for (const row of this.effectiveDdlRows()) {
|
|
2064
|
-
if (row[colIndex] === null) {
|
|
2065
|
-
anyNull = true;
|
|
2066
|
-
break;
|
|
2067
|
-
}
|
|
2068
|
-
}
|
|
2069
|
-
}
|
|
2070
|
-
if (anyNull) {
|
|
2071
|
-
if (defaultLiteral === undefined || defaultLiteral === null) {
|
|
2072
|
-
throw new QuereusError(`column ${change.columnName} contains NULL values`, StatusCode.CONSTRAINT);
|
|
2073
|
-
}
|
|
2074
|
-
// Backfill: map null → the folded DEFAULT literal, routed through the SAME
|
|
2075
|
-
// base-replacement + open-layer conversion machinery setDataType uses — no
|
|
2076
|
-
// logical-type change, no PK re-key, no in-place base mutation. The old in-place
|
|
2077
|
-
// `tree.upsert` backfill could not fill the transaction's pending rows (they live
|
|
2078
|
-
// in the pending layer, not the base) and mutated a base the open layers derive
|
|
2079
|
-
// from — both fixed by the unified path.
|
|
2080
|
-
const literal = defaultLiteral;
|
|
2081
|
-
valueConvert = (v) => (v === null ? literal : v);
|
|
2082
|
-
convertNulls = true;
|
|
2083
|
-
}
|
|
2084
|
-
newCol = { ...oldCol, notNull: true };
|
|
2085
|
-
}
|
|
2086
|
-
else if (change.setNotNull === false && oldCol.notNull) {
|
|
2087
|
-
if (this.tableSchema.primaryKeyDefinition.some(def => def.index === colIndex)) {
|
|
2088
|
-
throw new QuereusError(`Cannot DROP NOT NULL on PRIMARY KEY column '${change.columnName}'`, StatusCode.CONSTRAINT);
|
|
2089
|
-
}
|
|
2090
|
-
newCol = { ...oldCol, notNull: false };
|
|
2091
|
-
}
|
|
2092
|
-
else {
|
|
2093
|
-
// No-op (already in desired state).
|
|
2094
|
-
return;
|
|
2095
|
-
}
|
|
2096
|
-
}
|
|
2097
|
-
else if (change.setDataType !== undefined) {
|
|
2098
|
-
const newLogicalType = inferType(change.setDataType);
|
|
2099
|
-
// Gate on logical-type IDENTITY, not the physical storage class: `inferType`
|
|
2100
|
-
// flattens aliases to the shared type object (`varchar(50)` IS `TEXT_TYPE`,
|
|
2101
|
-
// `bigint` IS `INTEGER_TYPE`), so an alias retype is schema-only — no scan, no
|
|
2102
|
-
// rewrite, no re-key. Every OTHER retype validates AND normalizes every value,
|
|
2103
|
-
// whether or not the storage class changes: a same-class move (text → date)
|
|
2104
|
-
// must reject values the new type refuses ('hello') and rewrite the rest to
|
|
2105
|
-
// the new type's canonical spelling ('2024-06-05T00:00:00Z' → '2024-06-05'),
|
|
2106
|
-
// or the column holds values no INSERT could have produced — unfindable by
|
|
2107
|
-
// equality (DATE compares BINARY over the stored text) and invisible to UNIQUE.
|
|
2108
|
-
// NOTE: the rewrite is unconditional once the types differ, even when every
|
|
2109
|
-
// converted value comes back byte-identical (already-canonical ISO durations on a
|
|
2110
|
-
// text → timespan). That costs a full base-tree + secondary-index rebuild here, and
|
|
2111
|
-
// a physical rewrite of every row on the store leg. If ALTER on large tables ever
|
|
2112
|
-
// shows up as slow, have the convert pre-pass record whether any value actually
|
|
2113
|
-
// moved and, when none did, fall through to the comparator-only re-key.
|
|
2114
|
-
if (newLogicalType !== oldCol.logicalType) {
|
|
2115
|
-
// Retyping a PRIMARY KEY column moves the key bytes (a class change), the
|
|
2116
|
-
// tree's ordering (a comparator move), or at minimum the key values'
|
|
2117
|
-
// canonical spelling — and neither the base rewrite below nor the
|
|
2118
|
-
// transaction-layer conversion re-keys the primary tree. The engine already
|
|
2119
|
-
// refuses SET DATA TYPE on any PK column (runtime/emit/alter-table.ts);
|
|
2120
|
-
// this guards direct module calls. Reject rather than corrupt — the
|
|
2121
|
-
// type-change analogue of the SET COLLATE primary-key carve-out
|
|
2122
|
-
// (`alter-collate-pk-in-transaction`).
|
|
2123
|
-
if (this.tableSchema.primaryKeyDefinition.some(def => def.index === colIndex)) {
|
|
2124
|
-
throw new QuereusError(`Cannot change the data type of primary key column '${change.columnName}' of table '${this._tableName}'.`, StatusCode.CONSTRAINT);
|
|
2125
|
-
}
|
|
2126
|
-
// Every MemoryIndex builds its comparator from the column's LOGICAL type
|
|
2127
|
-
// (`createTypedComparator(columnSchema.logicalType, …)` in vtab/memory/index.ts),
|
|
2128
|
-
// so a move to a differently-ordering type (text ↔ timespan: 'PT1H' ≡ 'PT60M';
|
|
2129
|
-
// text ↔ date/time/datetime: binary, ignoring the column's collation) re-sorts
|
|
2130
|
-
// every structure keyed by the column. Tracked separately from the value rewrite
|
|
2131
|
-
// because SET COLLATE shares the re-key machinery without rewriting values.
|
|
2132
|
-
comparatorChanged = comparisonSemanticsDiffer(oldCol.logicalType, newLogicalType);
|
|
2133
|
-
const convert = (v) => {
|
|
2134
|
-
try {
|
|
2135
|
-
return validateAndParse(v, newLogicalType, change.columnName);
|
|
2136
|
-
}
|
|
2137
|
-
catch {
|
|
2138
|
-
throw new QuereusError(`Cannot convert value in '${change.columnName}' to ${change.setDataType}`, StatusCode.MISMATCH);
|
|
2139
|
-
}
|
|
2140
|
-
};
|
|
2141
|
-
// Validate BEFORE any mutation, over the DDL transaction's EFFECTIVE rows
|
|
2142
|
-
// (committed rows overlaid with this transaction's own pending writes): an
|
|
2143
|
-
// unconvertible value the transaction can SEE rejects the ALTER, and one only in
|
|
2144
|
-
// a row it has DELETED does not block it. A throw here leaves the schema, the base
|
|
2145
|
-
// and the transaction untouched. `rows` is the wrapper-supplied effective set (the
|
|
2146
|
-
// isolation overlay); when absent, `effectiveDdlRows()` is the layered view.
|
|
2147
|
-
if (rows) {
|
|
2148
|
-
for await (const row of rows()) {
|
|
2149
|
-
const val = row[colIndex];
|
|
2150
|
-
if (val !== null)
|
|
2151
|
-
convert(val);
|
|
2152
|
-
}
|
|
2153
|
-
}
|
|
2154
|
-
else {
|
|
2155
|
-
for (const row of this.effectiveDdlRows()) {
|
|
2156
|
-
const val = row[colIndex];
|
|
2157
|
-
if (val !== null)
|
|
2158
|
-
convert(val);
|
|
2159
|
-
}
|
|
2160
|
-
}
|
|
2161
|
-
// The base rows are converted below, AFTER `updateSchema`, by REPLACING the base
|
|
2162
|
-
// primary tree with a fresh one (see the `valueConvert` branch) — never by an
|
|
2163
|
-
// in-place mutation, which inheritree forbids while the open transaction's layers
|
|
2164
|
-
// derive from that tree (`MutatedBaseError`). `valueConvert` drives both the base
|
|
2165
|
-
// replacement and the transaction-layer conversion.
|
|
2166
|
-
valueConvert = convert;
|
|
2167
|
-
}
|
|
2168
|
-
newCol = { ...oldCol, logicalType: newLogicalType };
|
|
2169
|
-
}
|
|
2170
|
-
else if (change.setDefault !== undefined) {
|
|
2171
|
-
newCol = { ...oldCol, defaultValue: change.setDefault };
|
|
2172
|
-
}
|
|
2173
|
-
else {
|
|
2174
|
-
throw new QuereusError('ALTER COLUMN requires an attribute to change', StatusCode.INTERNAL);
|
|
2175
|
-
}
|
|
2176
|
-
const updatedCols = this.tableSchema.columns.map((c, i) => i === colIndex ? newCol : c);
|
|
2177
|
-
// The changes that move the COMPARATOR the structures are keyed by: SET COLLATE
|
|
2178
|
-
// (values untouched) and a retype into a differently-ordering type (which, unless it
|
|
2179
|
-
// is an alias retype, ALSO rewrites values — `valueConvert` — and its full-rebuild
|
|
2180
|
-
// path below subsumes the comparator-only re-sort). Both need fresh IndexSchema
|
|
2181
|
-
// objects and, when no rewrite runs, the re-validate / re-sort / adopt sequence.
|
|
2182
|
-
const structuresRekeyed = collationChanged || comparatorChanged;
|
|
2183
|
-
// Propagate a collation change into every PK-definition entry and index
|
|
2184
|
-
// column that orders by this column, so their comparators re-key under it.
|
|
2185
|
-
const updatedPkDef = collationChanged
|
|
2186
|
-
? this.tableSchema.primaryKeyDefinition.map(def => def.index === colIndex ? { ...def, collation: newCol.collation } : def)
|
|
2187
|
-
: this.tableSchema.primaryKeyDefinition;
|
|
2188
|
-
// Every re-keying change also REBUILDS the IndexSchema objects, because their identity is
|
|
2189
|
-
// the discriminator `TransactionLayer.adoptSchema` uses to decide an open layer's
|
|
2190
|
-
// MemoryIndex must be replaced rather than kept (an index it holds under an object the new
|
|
2191
|
-
// schema still carries is left alone). SET COLLATE has a field to write — the index
|
|
2192
|
-
// column's own collation. A comparator-only retype has none: an index column carries no
|
|
2193
|
-
// logical type, it reads the column's from `newSchema.columns`, so the fresh object IS the
|
|
2194
|
-
// whole signal. Without it the base rebuilt its trees under the new comparator while the
|
|
2195
|
-
// DDL transaction's own layers went on comparing the old way — and shadowed the base's
|
|
2196
|
-
// rebuilt trees once the pending layer became the committed head.
|
|
2197
|
-
const updatedIndexes = (structuresRekeyed && this.tableSchema.indexes)
|
|
2198
|
-
? this.tableSchema.indexes.map(idx => ({
|
|
2199
|
-
...idx,
|
|
2200
|
-
columns: idx.columns.map(ic => (ic.index === colIndex && collationChanged) ? { ...ic, collation: newCol.collation } : ic),
|
|
2201
|
-
}))
|
|
2202
|
-
: this.tableSchema.indexes;
|
|
2203
|
-
const finalNewTableSchema = Object.freeze({
|
|
2204
|
-
...this.tableSchema,
|
|
2205
|
-
columns: Object.freeze(updatedCols),
|
|
2206
|
-
columnIndexMap: buildColumnIndexMap(updatedCols),
|
|
2207
|
-
primaryKeyDefinition: Object.freeze(updatedPkDef),
|
|
2208
|
-
indexes: updatedIndexes ? Object.freeze(updatedIndexes) : updatedIndexes,
|
|
2209
|
-
});
|
|
2210
|
-
const pkColumnRekeyed = collationChanged && updatedPkDef.some(def => def.index === colIndex);
|
|
2211
|
-
// Validate BEFORE any mutation, over the DDL transaction's EFFECTIVE rows: a pair
|
|
2212
|
-
// the transaction inserted that collides under the NEW schema must reject the
|
|
2213
|
-
// change, and one it has deleted must not block it. A throw here leaves the schema,
|
|
2214
|
-
// the base layer and the index map exactly as they were.
|
|
2215
|
-
//
|
|
2216
|
-
// A value-REWRITING change (`valueConvert`: SET DATA TYPE, or a SET NOT NULL null →
|
|
2217
|
-
// DEFAULT backfill) probes the CONVERTED rows — the same per-row conversion the base
|
|
2218
|
-
// rewrite below applies — under the NEW schema's comparators, so one call covers both
|
|
2219
|
-
// ways an ALTER can collapse two previously-distinct rows: the VALUES converge
|
|
2220
|
-
// (`'1'`/`'01'` → 1; two NULLs → one DEFAULT; '2024-06-05T00:00:00Z' → '2024-06-05')
|
|
2221
|
-
// and/or the COMPARATOR moves (text → timespan makes 'PT1H'/'PT60M' one value). A
|
|
2222
|
-
// same-storage-class retype sets `valueConvert` AND `structuresRekeyed`, so the
|
|
2223
|
-
// rewrite arm is tested FIRST — its converted-row probe subsumes the comparator-only
|
|
2224
|
-
// one. The rebuild that follows is deliberately non-enforcing, so this is the only
|
|
2225
|
-
// guard.
|
|
2226
|
-
//
|
|
2227
|
-
// The comparator-MOVING arm without a rewrite has one trigger left: SET COLLATE. The
|
|
2228
|
-
// values are untouched — hence no `mapRow` — and only the comparator the structures
|
|
2229
|
-
// are keyed by moves. `newSchema` carries the new collations, so the probe indexes
|
|
2230
|
-
// compare as the rebuilt ones will.
|
|
2231
|
-
//
|
|
2232
|
-
// The primary key: SET COLLATE on a PK member gets a stricter pre-pass
|
|
2233
|
-
// (`validateRekeyedPrimaryKey`): no layer in the chain, base included, may hold a
|
|
2234
|
-
// collision. That is what lets every step below succeed unconditionally, and what
|
|
2235
|
-
// `TransactionLayer.rekeyPrimaryKey` relies on. The rewrite arm needs no PK pre-pass
|
|
2236
|
-
// and cannot shadow one: a retype of a PK column is rejected upstream, the backfill
|
|
2237
|
-
// only fires on a column holding NULLs (which a PK member cannot — the engine
|
|
2238
|
-
// enforces NOT NULL on every PK member regardless of the declared nullability), and
|
|
2239
|
-
// `pkColumnRekeyed` is set only by SET COLLATE, which never sets `valueConvert` — so
|
|
2240
|
-
// whenever `pkColumnRekeyed` is true, the `structuresRekeyed` arm still runs.
|
|
2241
|
-
// NOTE: if PK members ever become genuinely nullable, the backfill arm gains a PK
|
|
2242
|
-
// collision path (two NULL keys → one DEFAULT) and needs `validateRekeyedPrimaryKey`
|
|
2243
|
-
// plus a primary-tree re-key of its own.
|
|
2244
|
-
if (valueConvert) {
|
|
2245
|
-
const convert = valueConvert;
|
|
2246
|
-
const nulls = convertNulls;
|
|
2247
|
-
await this.validateRekeyedUniqueStructures(finalNewTableSchema, colIndex, rows,
|
|
2248
|
-
// Unlike `convertBaseRows`, a conversion failure here is NOT swallowed. Every row
|
|
2249
|
-
// the probe sees is visible to the transaction, and the setDataType pre-pass above
|
|
2250
|
-
// already proved each one convertible, so a throw is unreachable; surfacing it as
|
|
2251
|
-
// MISMATCH still beats probing a stale value that could mask a collision.
|
|
2252
|
-
row => convertRowAtIndex(row, colIndex, convert, nulls));
|
|
2253
|
-
}
|
|
2254
|
-
else if (structuresRekeyed) {
|
|
2255
|
-
await this.validateRekeyedUniqueStructures(finalNewTableSchema, colIndex, rows);
|
|
2256
|
-
// Unlike the secondary-structure pass above — which only ever judges the effective
|
|
2257
|
-
// rows — the PK pass judges TWO row sets: the effective rows (`rows` when a wrapper
|
|
2258
|
-
// supplies them) decide whether the change is LEGAL, and this manager's own layer
|
|
2259
|
-
// chain decides whether the re-keyed trees can PHYSICALLY carry it. See
|
|
2260
|
-
// `validateRekeyedPrimaryKey` for why the sets differ and which status each raises.
|
|
2261
|
-
if (pkColumnRekeyed)
|
|
2262
|
-
await this.validateRekeyedPrimaryKey(finalNewTableSchema, rows);
|
|
2263
|
-
}
|
|
2085
|
+
// Decide + validate, in that order and both before any mutation: `planColumnAttributeChange`
|
|
2086
|
+
// runs the attribute's own pre-validation (the NULL scan, the convertibility scan, the
|
|
2087
|
+
// primary-key carve-outs) over the effective rows, and `validateAlterColumnPlan` runs the
|
|
2088
|
+
// re-keyed UNIQUE / primary-key probes over the schema it produced. Nothing above
|
|
2089
|
+
// `applyAlterColumnToBase` writes, so a throw from either leaves the table as it was.
|
|
2090
|
+
const attributeChange = await planColumnAttributeChange({
|
|
2091
|
+
schema: this.tableSchema,
|
|
2092
|
+
tableName: this._tableName,
|
|
2093
|
+
columnName: change.columnName,
|
|
2094
|
+
colIndex,
|
|
2095
|
+
effectiveRows: this.effectiveRowSource(rows),
|
|
2096
|
+
isCollationRegistered: (n) => this.db.isCollationRegistered(n),
|
|
2097
|
+
}, change);
|
|
2098
|
+
if (attributeChange === null)
|
|
2099
|
+
return; // already in the requested state — nothing to do
|
|
2100
|
+
const plan = buildAlterColumnPlan(this.tableSchema, colIndex, attributeChange);
|
|
2101
|
+
await this.validateAlterColumnPlan(plan, rows);
|
|
2264
2102
|
// Dry run ends here: everything above validates without mutating (the one earlier
|
|
2265
2103
|
// side effect, ensureSchemaChangeSafety's committed-layer drain, is semantically
|
|
2266
2104
|
// neutral bookkeeping), and everything below mutates. See the method doc.
|
|
2267
2105
|
if (validateOnly)
|
|
2268
2106
|
return;
|
|
2269
|
-
this.
|
|
2270
|
-
|
|
2271
|
-
// swapped in — each MemoryIndex rebuilds its comparator from the CURRENT schema's
|
|
2272
|
-
// collation and logical type. The secondary rebuilds are NON-enforcing (the pre-pass
|
|
2273
|
-
// above owns uniqueness, and the base's rows are not a subset of the effective rows);
|
|
2274
|
-
// the SET COLLATE PK rebuild is strict, since a PK collision cannot be represented at
|
|
2275
|
-
// all — the pre-pass has already proved the base collision-free, so the strict
|
|
2276
|
-
// rebuild is a live invariant check, not the enforcement path. It runs LAST so its
|
|
2277
|
-
// throw leaves the live tree intact for the catch's rollback.
|
|
2278
|
-
if (valueConvert) {
|
|
2279
|
-
// SET DATA TYPE / SET NOT NULL backfill: convert the committed base rows and REPLACE
|
|
2280
|
-
// the primary tree with a fresh one holding them (not an in-place upsert — inheritree
|
|
2281
|
-
// forbids mutating a base while the open transaction's layers derive from it).
|
|
2282
|
-
// `rebuildPrimaryTreeFromRows` also rebuilds every secondary index from the converted
|
|
2283
|
-
// rows under the new comparators, so index-backed lookups see the new values — which
|
|
2284
|
-
// is why this arm runs first and subsumes `rebuildAllSecondaryIndexes` when a
|
|
2285
|
-
// same-storage-class retype sets `structuresRekeyed` too. The old tree is saved for
|
|
2286
|
-
// the catch's rollback, exactly as the PK-rekey path does.
|
|
2287
|
-
// NOTE: rebuilds EVERY secondary index, not only those covering the altered column;
|
|
2288
|
-
// if a wide-index table ever shows this as slow, filter to indexes whose columns
|
|
2289
|
-
// include colIndex. Mirrors the collationChanged path's unconditional rebuild.
|
|
2290
|
-
//
|
|
2291
|
-
// SET DATA TYPE: a base value that fails to convert is kept as-is — validation over
|
|
2292
|
-
// the effective view already rejected any unconvertible value the transaction can SEE,
|
|
2293
|
-
// so a surviving one is shadowed by a pending delete/overwrite and is never read back
|
|
2294
|
-
// (a ROLLBACK re-exposes it under the new type — DDL is not undone by rollback, the
|
|
2295
|
-
// known behavior of `feat-ddl-transaction-capability`).
|
|
2296
|
-
// SET NOT NULL (`convertNulls`): null base values are mapped to the DEFAULT literal.
|
|
2297
|
-
const convertedBaseRows = this.convertBaseRows(colIndex, valueConvert, convertNulls);
|
|
2298
|
-
basePrimaryTreeBeforeRekey = this.baseLayer.primaryTree;
|
|
2299
|
-
this.baseLayer.rebuildPrimaryTreeFromRows(convertedBaseRows);
|
|
2300
|
-
}
|
|
2301
|
-
else if (structuresRekeyed) {
|
|
2302
|
-
this.baseLayer.rebuildAllSecondaryIndexes();
|
|
2303
|
-
if (pkColumnRekeyed) {
|
|
2304
|
-
basePrimaryTreeBeforeRekey = this.baseLayer.primaryTree;
|
|
2305
|
-
this.baseLayer.rebuildPrimaryTreeStrict();
|
|
2306
|
-
}
|
|
2307
|
-
}
|
|
2308
|
-
this.tableSchema = finalNewTableSchema;
|
|
2107
|
+
this.applyAlterColumnToBase(plan, undo);
|
|
2108
|
+
this.tableSchema = plan.newSchema;
|
|
2309
2109
|
this.initializePrimaryKeyFunctions();
|
|
2310
|
-
|
|
2311
|
-
// comparator; the DDL transaction's own layers still inherit the old ones and froze
|
|
2312
|
-
// the old schema at construction. Re-key them, or the rest of the transaction — and
|
|
2313
|
-
// everything after the pending layer becomes the committed head at commit — keeps
|
|
2314
|
-
// comparing under the old collation / old logical type.
|
|
2315
|
-
//
|
|
2316
|
-
// When the altered column is part of the primary key, `rebuildPrimaryTreeStrict` also
|
|
2317
|
-
// swapped the base primary tree object out from under those layers' copy-on-write
|
|
2318
|
-
// bases and invalidated their `pkFunctions`; `rekeyPrimaryKey` rebuilds both, plus
|
|
2319
|
-
// every secondary index (each derives its PK comparator/encoder from the PK
|
|
2320
|
-
// definition). Outside a transaction there are no open layers and both are no-ops.
|
|
2321
|
-
if (valueConvert) {
|
|
2322
|
-
// SET DATA TYPE / SET NOT NULL backfill converted the base above; the DDL
|
|
2323
|
-
// transaction's own open layers still froze the old schema and hold their own-written
|
|
2324
|
-
// rows unconverted. Swap the schema and convert those values so the rest of the
|
|
2325
|
-
// transaction — and the committed head at commit — read the new value. For SET NOT
|
|
2326
|
-
// NULL this fills the transaction's OWN pending NULL rows (which live in the pending
|
|
2327
|
-
// layer, never reached by the old in-place base upsert). `convertColumn` installs the
|
|
2328
|
-
// new schema and rebuilds every one of the layer's secondary indexes from it, so it
|
|
2329
|
-
// subsumes `adoptSchema` when a same-storage-class retype moved the comparators too.
|
|
2330
|
-
// No-op in autocommit.
|
|
2331
|
-
this.convertColumnOnOpenLayers(finalNewTableSchema, colIndex, valueConvert, convertNulls);
|
|
2332
|
-
}
|
|
2333
|
-
else if (structuresRekeyed) {
|
|
2334
|
-
this.adoptSchemaOnOpenLayers(finalNewTableSchema, pkColumnRekeyed);
|
|
2335
|
-
}
|
|
2336
|
-
else {
|
|
2337
|
-
// The remaining changes (SET DEFAULT, DROP NOT NULL, a SET NOT NULL that needed no
|
|
2338
|
-
// backfill, a retype between aliases of one logical type) touch nothing a layer
|
|
2339
|
-
// DERIVES — its index set, its `uniqueConstraints` enforcement and its MemoryIndex
|
|
2340
|
-
// comparators all stay put, and DEFAULT application / NOT NULL enforcement happen
|
|
2341
|
-
// above the module, off the catalog schema. But the frozen schema OBJECT is itself
|
|
2342
|
-
// observable: `commitTransaction` only wraps a swapped-in savepoint snapshot back
|
|
2343
|
-
// into the committed chain when `readLayer.getSchema() === this.tableSchema`. Left
|
|
2344
|
-
// stale, a `rollback to savepoint` taken across one of these ALTERs restores a
|
|
2345
|
-
// snapshot the wrap then skips, and the transaction's staged rows are silently
|
|
2346
|
-
// dropped at COMMIT. Adoption is cheap here — every IndexSchema object is carried
|
|
2347
|
-
// over unchanged, so `adoptSchema` keeps each layer's MemoryIndex and only swaps
|
|
2348
|
-
// the schema reference.
|
|
2349
|
-
this.adoptSchemaOnOpenLayers(finalNewTableSchema);
|
|
2350
|
-
}
|
|
2351
|
-
this.eventEmitter?.emitSchemaChange?.({
|
|
2352
|
-
type: 'alter',
|
|
2353
|
-
objectType: 'column',
|
|
2354
|
-
schemaName: this.schemaName,
|
|
2355
|
-
objectName: this._tableName,
|
|
2356
|
-
columnName: change.columnName,
|
|
2357
|
-
});
|
|
2110
|
+
this.propagateAlterColumnToOpenLayers(plan);
|
|
2358
2111
|
logger.operation('Alter Column', this._tableName, { columnName: change.columnName });
|
|
2359
2112
|
}
|
|
2360
2113
|
catch (e) {
|
|
2361
2114
|
// Restore the prior schema and primary tree, then re-key the secondary indexes back
|
|
2362
|
-
// to it. Both pre-passes
|
|
2363
|
-
// is expected to throw; the restores are the safety net for
|
|
2364
|
-
// for `rebuildPrimaryTreeStrict`'s invariant check, whose
|
|
2365
|
-
// `validateRekeyedPrimaryKey` has already established).
|
|
2115
|
+
// to it. Both pre-passes run before any mutation, so nothing inside
|
|
2116
|
+
// `applyAlterColumnToBase` is expected to throw; the restores are the safety net for
|
|
2117
|
+
// an unexpected one (and for `rebuildPrimaryTreeStrict`'s invariant check, whose
|
|
2118
|
+
// precondition `validateRekeyedPrimaryKey` has already established).
|
|
2366
2119
|
//
|
|
2367
|
-
// NOTE: a throw from a pre-pass (or from `
|
|
2120
|
+
// NOTE: a throw from a pre-pass (or from `set not null`'s NULL scan) mutated nothing,
|
|
2368
2121
|
// so this rebuild only swaps the base's index trees for fresh, content-identical
|
|
2369
2122
|
// ones — an O(rows) cost on a pure rejection. Harmless (a pending layer keeps
|
|
2370
2123
|
// reading its orphaned but content-correct copy-on-write base), but if a rejected
|
|
2371
2124
|
// ALTER on a large table ever shows up as slow, gate the rebuild on a "mutation
|
|
2372
|
-
// started" flag set just before `
|
|
2125
|
+
// started" flag set just before `applyAlterColumnToBase`.
|
|
2373
2126
|
this.baseLayer.updateSchema(originalManagerSchema);
|
|
2374
|
-
if (
|
|
2375
|
-
this.baseLayer.primaryTree =
|
|
2127
|
+
if (undo.basePrimaryTree)
|
|
2128
|
+
this.baseLayer.primaryTree = undo.basePrimaryTree;
|
|
2376
2129
|
this.baseLayer.rebuildAllSecondaryIndexes();
|
|
2377
2130
|
this.tableSchema = originalManagerSchema;
|
|
2378
2131
|
this.initializePrimaryKeyFunctions();
|
|
@@ -2383,6 +2136,272 @@ export class MemoryTableManager {
|
|
|
2383
2136
|
release();
|
|
2384
2137
|
}
|
|
2385
2138
|
}
|
|
2139
|
+
/**
|
|
2140
|
+
* Apply `alter table … alter primary key` in place — the table's rows, the open
|
|
2141
|
+
* transaction's pending writes, and its pending change events all survive under the new
|
|
2142
|
+
* key. Follows {@link alterColumn}'s ordering contract: resolve and pre-validate the new
|
|
2143
|
+
* definition (mutating nothing) → probe the re-keyed primary structures
|
|
2144
|
+
* ({@link validateRekeyedPrimaryKey}, the same pass the `set collate` re-key runs) →
|
|
2145
|
+
* rebuild the base → swap this manager's schema → propagate to the open transaction's
|
|
2146
|
+
* layers → emit. What differs from the `set collate` re-key is WHAT moves: the key's
|
|
2147
|
+
* columns rather than its comparator, so each open layer's net deletions and its pending
|
|
2148
|
+
* event log must be re-derived from row images — a two-phase prepare/install pair
|
|
2149
|
+
* ({@link TransactionLayer.prepareRekeyedPrimaryKeyColumns}), with every prepare running
|
|
2150
|
+
* BEFORE the first mutation because a deletion's image resolves only through the intact
|
|
2151
|
+
* old layer chain.
|
|
2152
|
+
*
|
|
2153
|
+
* `validateOnly` runs everything up to (and including) the pre-mutation validation and
|
|
2154
|
+
* returns before the first mutation, throwing exactly what the real application would
|
|
2155
|
+
* throw — the same dry-run contract as {@link alterColumn}'s, for a wrapper (the
|
|
2156
|
+
* isolation layer) that must pre-flight before a shared underlying mutates irreversibly.
|
|
2157
|
+
*/
|
|
2158
|
+
async alterPrimaryKey(newPkColumns, rows, validateOnly = false) {
|
|
2159
|
+
if (this.isReadOnly)
|
|
2160
|
+
throw new QuereusError(`Table '${this._tableName}' is read-only`, StatusCode.READONLY);
|
|
2161
|
+
const lockKey = `MemoryTable.SchemaChange:${this.schemaName}.${this._tableName}`;
|
|
2162
|
+
const release = await this.db.latches.acquire(lockKey);
|
|
2163
|
+
const originalManagerSchema = this.tableSchema;
|
|
2164
|
+
const undo = { basePrimaryTree: null };
|
|
2165
|
+
try {
|
|
2166
|
+
await this.ensureSchemaChangeSafety();
|
|
2167
|
+
// NOTE: no early return for a definition equal to the current one (unlike
|
|
2168
|
+
// `alterColumn`'s already-in-the-requested-state exit) — the statement is rare and
|
|
2169
|
+
// its only producer, the declarative differ, emits it solely on a genuine change.
|
|
2170
|
+
// If a caller ever re-issues an unchanged key, add the comparison here: the work
|
|
2171
|
+
// below is a full O(rows × layers) rebuild.
|
|
2172
|
+
const newSchema = this.buildRekeyedPrimaryKeySchema(newPkColumns);
|
|
2173
|
+
// Pre-validate before any mutation: the effective rows decide whether the change
|
|
2174
|
+
// is LEGAL (CONSTRAINT on a visible collision), the manager's own layer chain
|
|
2175
|
+
// whether the re-keyed trees can PHYSICALLY carry it (BUSY when only rows a
|
|
2176
|
+
// rollback must restore collide). A throw leaves everything as it was.
|
|
2177
|
+
await this.validateRekeyedPrimaryKey(newSchema, rows);
|
|
2178
|
+
// Dry run ends here: everything above validates without mutating, everything
|
|
2179
|
+
// below mutates. See the method doc.
|
|
2180
|
+
if (validateOnly)
|
|
2181
|
+
return;
|
|
2182
|
+
// Compute every open layer's re-derived net writes and event log BEFORE the
|
|
2183
|
+
// first mutation: a net deletion's new key comes from the parent's row image at
|
|
2184
|
+
// the old key, which only the intact old chain can still resolve.
|
|
2185
|
+
const newPkFunctions = createPrimaryKeyFunctions(newSchema, this.collationResolver);
|
|
2186
|
+
const plans = this.openTransactionLayersOldestFirst().map(layer => ({
|
|
2187
|
+
layer,
|
|
2188
|
+
prepared: layer.prepareRekeyedPrimaryKeyColumns(newPkFunctions),
|
|
2189
|
+
}));
|
|
2190
|
+
// Base rebuild, mirroring alterColumn's `set collate` arm: secondary indexes
|
|
2191
|
+
// first (each entry's key encoding embeds the primary key), then the strict
|
|
2192
|
+
// primary rebuild LAST so its throw — a live invariant check; the pre-pass has
|
|
2193
|
+
// already proven the base collision-free — leaves the live tree intact for the
|
|
2194
|
+
// rollback below.
|
|
2195
|
+
this.baseLayer.updateSchema(newSchema);
|
|
2196
|
+
this.baseLayer.rebuildAllSecondaryIndexes();
|
|
2197
|
+
undo.basePrimaryTree = this.baseLayer.primaryTree;
|
|
2198
|
+
this.baseLayer.rebuildPrimaryTreeStrict();
|
|
2199
|
+
this.tableSchema = newSchema;
|
|
2200
|
+
this.initializePrimaryKeyFunctions();
|
|
2201
|
+
// Oldest-first (the plans were gathered in that order): each layer's rebuilt tree
|
|
2202
|
+
// inherits copy-on-write from its parent's NEW one. Synchronous and mutation-only.
|
|
2203
|
+
for (const { layer, prepared } of plans) {
|
|
2204
|
+
layer.installRekeyedPrimaryKeyColumns(newSchema, prepared);
|
|
2205
|
+
}
|
|
2206
|
+
logger.operation('Alter Primary Key', this._tableName, {
|
|
2207
|
+
columns: newSchema.primaryKeyDefinition.map(def => def.index),
|
|
2208
|
+
});
|
|
2209
|
+
}
|
|
2210
|
+
catch (e) {
|
|
2211
|
+
// Restore the prior schema and primary tree, then re-key the secondary indexes
|
|
2212
|
+
// back to it — the same safety net as alterColumn's catch: both pre-passes run
|
|
2213
|
+
// before any mutation, so nothing in the apply steps is expected to throw.
|
|
2214
|
+
this.baseLayer.updateSchema(originalManagerSchema);
|
|
2215
|
+
if (undo.basePrimaryTree)
|
|
2216
|
+
this.baseLayer.primaryTree = undo.basePrimaryTree;
|
|
2217
|
+
this.baseLayer.rebuildAllSecondaryIndexes();
|
|
2218
|
+
this.tableSchema = originalManagerSchema;
|
|
2219
|
+
this.initializePrimaryKeyFunctions();
|
|
2220
|
+
logger.error('Alter Primary Key', this._tableName, e);
|
|
2221
|
+
throw e;
|
|
2222
|
+
}
|
|
2223
|
+
finally {
|
|
2224
|
+
release();
|
|
2225
|
+
}
|
|
2226
|
+
}
|
|
2227
|
+
/**
|
|
2228
|
+
* Resolve `alter primary key`'s column list against the current schema — bounds, no
|
|
2229
|
+
* duplicates, every member NOT NULL — and return the re-keyed schema. The engine's
|
|
2230
|
+
* emitter validates the same three by column NAME before dispatch; re-checking by index
|
|
2231
|
+
* here keeps a wrapper driving the module API directly (the isolation layer) from
|
|
2232
|
+
* installing an unkeyable definition. The schema construction itself (definition +
|
|
2233
|
+
* per-column flag rebuild, member collations carried) is delegated to the shared
|
|
2234
|
+
* {@link rekeySchemaPrimaryKey}, which the store's native arm uses too.
|
|
2235
|
+
*/
|
|
2236
|
+
buildRekeyedPrimaryKeySchema(newPkColumns) {
|
|
2237
|
+
const columns = this.tableSchema.columns;
|
|
2238
|
+
const seen = new Set();
|
|
2239
|
+
for (const pk of newPkColumns) {
|
|
2240
|
+
if (pk.index < 0 || pk.index >= columns.length) {
|
|
2241
|
+
throw new QuereusError(`Primary key column index ${pk.index} is out of bounds for table '${this._tableName}'.`, StatusCode.ERROR);
|
|
2242
|
+
}
|
|
2243
|
+
if (seen.has(pk.index)) {
|
|
2244
|
+
throw new QuereusError(`Duplicate column '${columns[pk.index].name}' in PRIMARY KEY definition`, StatusCode.ERROR);
|
|
2245
|
+
}
|
|
2246
|
+
seen.add(pk.index);
|
|
2247
|
+
if (!columns[pk.index].notNull) {
|
|
2248
|
+
throw new QuereusError(`Column '${columns[pk.index].name}' must be NOT NULL to participate in PRIMARY KEY`, StatusCode.CONSTRAINT);
|
|
2249
|
+
}
|
|
2250
|
+
}
|
|
2251
|
+
return rekeySchemaPrimaryKey(this.tableSchema, newPkColumns);
|
|
2252
|
+
}
|
|
2253
|
+
/**
|
|
2254
|
+
* The re-keyed-structure pre-pass for {@link alterColumn}, over the DDL transaction's EFFECTIVE
|
|
2255
|
+
* rows: a pair the transaction inserted that collides under the NEW schema must reject the
|
|
2256
|
+
* change, and one it has deleted must not block it. Runs before any mutation, so a throw leaves
|
|
2257
|
+
* the schema, the base layer and the index map exactly as they were.
|
|
2258
|
+
*
|
|
2259
|
+
* A value-REWRITING change (`set data type`, or a `set not null` null → DEFAULT backfill) probes
|
|
2260
|
+
* the CONVERTED rows — the same per-row conversion the base rewrite applies — under the NEW
|
|
2261
|
+
* schema's comparators, so one call covers both ways an ALTER can collapse two previously-distinct
|
|
2262
|
+
* rows: the VALUES converge (`'1'`/`'01'` → 1; two NULLs → one DEFAULT;
|
|
2263
|
+
* '2024-06-05T00:00:00Z' → '2024-06-05') and/or the COMPARATOR moves (text → timespan makes
|
|
2264
|
+
* 'PT1H'/'PT60M' one value). A same-storage-class retype sets both `rewrite` and
|
|
2265
|
+
* `structuresRekeyed`, so the rewrite arm is tested FIRST — its converted-row probe subsumes the
|
|
2266
|
+
* comparator-only one. The rebuild that follows is deliberately non-enforcing, so this is the
|
|
2267
|
+
* only guard.
|
|
2268
|
+
*
|
|
2269
|
+
* The comparator-MOVING arm without a rewrite has one trigger left: `set collate`. The values are
|
|
2270
|
+
* untouched — hence no `mapRow` — and only the comparator the structures are keyed by moves.
|
|
2271
|
+
* `newSchema` carries the new collations, so the probe indexes compare as the rebuilt ones will.
|
|
2272
|
+
*
|
|
2273
|
+
* The primary key: `set collate` on a PK member gets a stricter pre-pass
|
|
2274
|
+
* ({@link validateRekeyedPrimaryKey}): no layer in the chain, base included, may hold a collision.
|
|
2275
|
+
* That is what lets every apply step succeed unconditionally, and what
|
|
2276
|
+
* `TransactionLayer.rekeyPrimaryKey` relies on. The rewrite arm needs no PK pre-pass and cannot
|
|
2277
|
+
* shadow one: a retype of a PK column is rejected upstream, the backfill only fires on a column
|
|
2278
|
+
* holding NULLs (which a PK member cannot — the engine enforces NOT NULL on every PK member
|
|
2279
|
+
* regardless of the declared nullability), and `pkColumnRekeyed` is set only by `set collate`,
|
|
2280
|
+
* which never sets `rewrite` — so whenever `pkColumnRekeyed` is true, the `structuresRekeyed` arm
|
|
2281
|
+
* still runs.
|
|
2282
|
+
* NOTE: if PK members ever become genuinely nullable, the backfill arm gains a PK collision path
|
|
2283
|
+
* (two NULL keys → one DEFAULT) and needs `validateRekeyedPrimaryKey` plus a primary-tree re-key
|
|
2284
|
+
* of its own.
|
|
2285
|
+
*/
|
|
2286
|
+
async validateAlterColumnPlan(plan, rows) {
|
|
2287
|
+
if (plan.rewrite) {
|
|
2288
|
+
const { convert, convertNulls } = plan.rewrite;
|
|
2289
|
+
await this.validateRekeyedUniqueStructures(plan.newSchema, plan.colIndex, rows,
|
|
2290
|
+
// Unlike `convertBaseRows`, a conversion failure here is NOT swallowed. Every row
|
|
2291
|
+
// the probe sees is visible to the transaction, and the `set data type` pre-pass
|
|
2292
|
+
// already proved each one convertible, so a throw is unreachable; surfacing it as
|
|
2293
|
+
// MISMATCH still beats probing a stale value that could mask a collision.
|
|
2294
|
+
row => convertRowAtIndex(row, plan.colIndex, convert, convertNulls));
|
|
2295
|
+
}
|
|
2296
|
+
else if (plan.structuresRekeyed) {
|
|
2297
|
+
await this.validateRekeyedUniqueStructures(plan.newSchema, plan.colIndex, rows);
|
|
2298
|
+
// Unlike the secondary-structure pass above — which only ever judges the effective
|
|
2299
|
+
// rows — the PK pass judges TWO row sets: the effective rows (`rows` when a wrapper
|
|
2300
|
+
// supplies them) decide whether the change is LEGAL, and this manager's own layer
|
|
2301
|
+
// chain decides whether the re-keyed trees can PHYSICALLY carry it. See
|
|
2302
|
+
// `validateRekeyedPrimaryKey` for why the sets differ and which status each raises.
|
|
2303
|
+
if (plan.pkColumnRekeyed)
|
|
2304
|
+
await this.validateRekeyedPrimaryKey(plan.newSchema, rows);
|
|
2305
|
+
}
|
|
2306
|
+
}
|
|
2307
|
+
/**
|
|
2308
|
+
* First mutation of {@link alterColumn}: install the new schema on the base layer and rebuild its
|
|
2309
|
+
* structures under it — each MemoryIndex rebuilds its comparator from the CURRENT schema's
|
|
2310
|
+
* collation and logical type. The secondary rebuilds are NON-enforcing ({@link validateAlterColumnPlan}
|
|
2311
|
+
* owns uniqueness, and the base's rows are not a subset of the effective rows); the `set collate`
|
|
2312
|
+
* PK rebuild is strict, since a PK collision cannot be represented at all — the pre-pass has
|
|
2313
|
+
* already proved the base collision-free, so the strict rebuild is a live invariant check, not
|
|
2314
|
+
* the enforcement path. It runs LAST so its throw leaves the live tree intact for the rollback.
|
|
2315
|
+
*
|
|
2316
|
+
* Records the primary tree it is about to REPLACE in `undo` *before* replacing it, so a throw
|
|
2317
|
+
* from either rebuild still leaves the caller's `catch` a tree to restore.
|
|
2318
|
+
*/
|
|
2319
|
+
applyAlterColumnToBase(plan, undo) {
|
|
2320
|
+
this.baseLayer.updateSchema(plan.newSchema);
|
|
2321
|
+
if (plan.rewrite) {
|
|
2322
|
+
// `set data type` / `set not null` backfill: convert the committed base rows and REPLACE
|
|
2323
|
+
// the primary tree with a fresh one holding them (not an in-place upsert — inheritree
|
|
2324
|
+
// forbids mutating a base while the open transaction's layers derive from it).
|
|
2325
|
+
// `rebuildPrimaryTreeFromRows` also rebuilds every secondary index from the converted
|
|
2326
|
+
// rows under the new comparators, so index-backed lookups see the new values — which
|
|
2327
|
+
// is why this arm runs first and subsumes `rebuildAllSecondaryIndexes` when a
|
|
2328
|
+
// same-storage-class retype sets `structuresRekeyed` too.
|
|
2329
|
+
// NOTE: rebuilds EVERY secondary index, not only those covering the altered column;
|
|
2330
|
+
// if a wide-index table ever shows this as slow, filter to indexes whose columns
|
|
2331
|
+
// include colIndex. Mirrors the `set collate` path's unconditional rebuild.
|
|
2332
|
+
//
|
|
2333
|
+
// `set data type`: a base value that fails to convert is kept as-is — validation over
|
|
2334
|
+
// the effective view already rejected any unconvertible value the transaction can SEE,
|
|
2335
|
+
// so a surviving one is shadowed by a pending delete/overwrite and is never read back
|
|
2336
|
+
// (a ROLLBACK re-exposes it under the new type — DDL is not undone by rollback, the
|
|
2337
|
+
// known behavior of `feat-ddl-transaction-capability`).
|
|
2338
|
+
// `set not null` (`convertNulls`): null base values are mapped to the DEFAULT literal.
|
|
2339
|
+
const convertedBaseRows = this.convertBaseRows(plan.colIndex, plan.rewrite.convert, plan.rewrite.convertNulls);
|
|
2340
|
+
undo.basePrimaryTree = this.baseLayer.primaryTree;
|
|
2341
|
+
this.baseLayer.rebuildPrimaryTreeFromRows(convertedBaseRows);
|
|
2342
|
+
}
|
|
2343
|
+
else if (plan.structuresRekeyed) {
|
|
2344
|
+
this.baseLayer.rebuildAllSecondaryIndexes();
|
|
2345
|
+
if (plan.pkColumnRekeyed) {
|
|
2346
|
+
undo.basePrimaryTree = this.baseLayer.primaryTree;
|
|
2347
|
+
this.baseLayer.rebuildPrimaryTreeStrict();
|
|
2348
|
+
}
|
|
2349
|
+
}
|
|
2350
|
+
}
|
|
2351
|
+
/**
|
|
2352
|
+
* Hand the post-{@link alterColumn} schema to the DDL transaction's own open layers.
|
|
2353
|
+
*
|
|
2354
|
+
* The base rebuild handed every secondary index a fresh tree under the new comparator; those
|
|
2355
|
+
* layers still inherit the old ones and froze the old schema at construction. Re-key them, or
|
|
2356
|
+
* the rest of the transaction — and everything after the pending layer becomes the committed
|
|
2357
|
+
* head at commit — keeps comparing under the old collation / old logical type.
|
|
2358
|
+
*
|
|
2359
|
+
* When the altered column is part of the primary key, `rebuildPrimaryTreeStrict` also swapped the
|
|
2360
|
+
* base primary tree object out from under those layers' copy-on-write bases and invalidated their
|
|
2361
|
+
* `pkFunctions`; `rekeyPrimaryKey` rebuilds both, plus every secondary index (each derives its PK
|
|
2362
|
+
* comparator/encoder from the PK definition). Outside a transaction there are no open layers and
|
|
2363
|
+
* every arm is a no-op.
|
|
2364
|
+
*/
|
|
2365
|
+
propagateAlterColumnToOpenLayers(plan) {
|
|
2366
|
+
if (plan.rewrite) {
|
|
2367
|
+
// `set data type` / `set not null` backfill converted the base; the open layers still hold
|
|
2368
|
+
// their own-written rows unconverted. Swap the schema and convert those values so the rest
|
|
2369
|
+
// of the transaction — and the committed head at commit — read the new value. For
|
|
2370
|
+
// `set not null` this fills the transaction's OWN pending NULL rows (which live in the
|
|
2371
|
+
// pending layer, never reached by an in-place base upsert). `convertColumn` installs the
|
|
2372
|
+
// new schema and rebuilds every one of the layer's secondary indexes from it, so it
|
|
2373
|
+
// subsumes `adoptSchema` when a same-storage-class retype moved the comparators too.
|
|
2374
|
+
this.convertColumnOnOpenLayers(plan.newSchema, plan.colIndex, plan.rewrite.convert, plan.rewrite.convertNulls);
|
|
2375
|
+
}
|
|
2376
|
+
else if (plan.structuresRekeyed) {
|
|
2377
|
+
this.adoptSchemaOnOpenLayers(plan.newSchema, plan.pkColumnRekeyed);
|
|
2378
|
+
}
|
|
2379
|
+
else {
|
|
2380
|
+
// The remaining changes (`set default`, `drop not null`, a `set not null` that needed no
|
|
2381
|
+
// backfill, a retype between aliases of one logical type) touch nothing a layer
|
|
2382
|
+
// DERIVES — its index set, its `uniqueConstraints` enforcement and its MemoryIndex
|
|
2383
|
+
// comparators all stay put, and DEFAULT application / NOT NULL enforcement happen
|
|
2384
|
+
// above the module, off the catalog schema. But the frozen schema OBJECT is itself
|
|
2385
|
+
// observable: `commitTransaction` only wraps a swapped-in savepoint snapshot back
|
|
2386
|
+
// into the committed chain when `readLayer.getSchema() === this.tableSchema`. Left
|
|
2387
|
+
// stale, a `rollback to savepoint` taken across one of these ALTERs restores a
|
|
2388
|
+
// snapshot the wrap then skips, and the transaction's staged rows are silently
|
|
2389
|
+
// dropped at COMMIT. Adoption is cheap here — every IndexSchema object is carried
|
|
2390
|
+
// over unchanged, so `adoptSchema` keeps each layer's MemoryIndex and only swaps
|
|
2391
|
+
// the schema reference.
|
|
2392
|
+
this.adoptSchemaOnOpenLayers(plan.newSchema);
|
|
2393
|
+
}
|
|
2394
|
+
}
|
|
2395
|
+
/**
|
|
2396
|
+
* The rows the `alter column` pre-validation scans judge: `rows` when a wrapper module supplies
|
|
2397
|
+
* them (the isolation overlay holds the transaction's pending rows outside this manager, so only
|
|
2398
|
+
* it can name the rows the issuing connection actually sees), else this manager's own layered
|
|
2399
|
+
* view ({@link effectiveDdlRows}) — which stays a SYNC iterable on purpose, so a scan over it
|
|
2400
|
+
* cannot be interleaved with another connection's write. See `scanEffectiveRows`.
|
|
2401
|
+
*/
|
|
2402
|
+
effectiveRowSource(rows) {
|
|
2403
|
+
return rows ?? (() => this.effectiveDdlRows());
|
|
2404
|
+
}
|
|
2386
2405
|
async createIndex(newIndexSchemaEntry, ifNotExistsFromAst, rows) {
|
|
2387
2406
|
if (this.isReadOnly)
|
|
2388
2407
|
throw new QuereusError(`Table '${this._tableName}' is read-only`, StatusCode.READONLY);
|
|
@@ -2580,12 +2599,6 @@ export class MemoryTableManager {
|
|
|
2580
2599
|
// stops enforcing for the rest of it; harmless for CHECK/FK (they re-freeze an
|
|
2581
2600
|
// equivalent schema, holding no per-layer structure).
|
|
2582
2601
|
this.adoptSchemaOnOpenLayers(newSchema);
|
|
2583
|
-
this.eventEmitter?.emitSchemaChange?.({
|
|
2584
|
-
type: 'alter',
|
|
2585
|
-
objectType: 'table',
|
|
2586
|
-
schemaName: this.schemaName,
|
|
2587
|
-
objectName: this._tableName,
|
|
2588
|
-
});
|
|
2589
2602
|
logger.operation('Drop Constraint', this._tableName, { constraintName });
|
|
2590
2603
|
}
|
|
2591
2604
|
catch (e) {
|
|
@@ -2666,12 +2679,6 @@ export class MemoryTableManager {
|
|
|
2666
2679
|
// check (`readLayer.getSchema() === this.tableSchema`) skips a savepoint snapshot
|
|
2667
2680
|
// restored across this ALTER and drops the transaction's staged rows at COMMIT.
|
|
2668
2681
|
this.adoptSchemaOnOpenLayers(newSchema);
|
|
2669
|
-
this.eventEmitter?.emitSchemaChange?.({
|
|
2670
|
-
type: 'alter',
|
|
2671
|
-
objectType: 'table',
|
|
2672
|
-
schemaName: this.schemaName,
|
|
2673
|
-
objectName: this._tableName,
|
|
2674
|
-
});
|
|
2675
2682
|
logger.operation('Rename Constraint', this._tableName, { oldName, newName });
|
|
2676
2683
|
}
|
|
2677
2684
|
catch (e) {
|
|
@@ -2724,12 +2731,6 @@ export class MemoryTableManager {
|
|
|
2724
2731
|
else {
|
|
2725
2732
|
throw new QuereusError(`MemoryTable ADD CONSTRAINT does not support constraint type '${constraint.type}'`, StatusCode.UNSUPPORTED);
|
|
2726
2733
|
}
|
|
2727
|
-
this.eventEmitter?.emitSchemaChange?.({
|
|
2728
|
-
type: 'alter',
|
|
2729
|
-
objectType: 'table',
|
|
2730
|
-
schemaName: this.schemaName,
|
|
2731
|
-
objectName: this._tableName,
|
|
2732
|
-
});
|
|
2733
2734
|
logger.operation('Add Constraint', this._tableName, { type: constraint.type, name: constraint.name });
|
|
2734
2735
|
}
|
|
2735
2736
|
catch (e) {
|
|
@@ -2783,7 +2784,11 @@ export class MemoryTableManager {
|
|
|
2783
2784
|
// would under-enforce this non-derived UNIQUE. A collation mismatch falls
|
|
2784
2785
|
// through to build the distinct `_uc_*` covering index; the user index keeps
|
|
2785
2786
|
// enforcing its own (stricter) uniqueness independently (matches SQLite).
|
|
2786
|
-
|
|
2787
|
+
// A FILTERED (partial) unique index only guarantees uniqueness among the rows
|
|
2788
|
+
// its own predicate admits, so it can't back a full (unfiltered) UNIQUE either —
|
|
2789
|
+
// same reasoning as `ensureUniqueConstraintIndexes` above.
|
|
2790
|
+
const matchingUniqueIndex = uc.predicate ? undefined : existingIndexes.find(idx => idx.unique &&
|
|
2791
|
+
!idx.predicate &&
|
|
2787
2792
|
idx.columns.length === uc.columns.length &&
|
|
2788
2793
|
idx.columns.every((col, i) => col.index === uc.columns[i]) &&
|
|
2789
2794
|
this.indexCollationsMatchDeclared(idx, uc));
|
|
@@ -2803,8 +2808,7 @@ export class MemoryTableManager {
|
|
|
2803
2808
|
this.adoptSchemaOnOpenLayers(newSchema);
|
|
2804
2809
|
return;
|
|
2805
2810
|
}
|
|
2806
|
-
const
|
|
2807
|
-
const indexName = uc.name ?? `_uc_${colNames.join('_')}`;
|
|
2811
|
+
const indexName = uc.name ?? implicitIndexNameOver(uc, columns);
|
|
2808
2812
|
const indexSchema = {
|
|
2809
2813
|
name: indexName,
|
|
2810
2814
|
// Carry per-column collation so enforcement honors e.g. NOCASE (mirrors
|
|
@@ -3122,8 +3126,11 @@ export class MemoryTableManager {
|
|
|
3122
3126
|
}
|
|
3123
3127
|
}
|
|
3124
3128
|
/**
|
|
3125
|
-
*
|
|
3126
|
-
*
|
|
3129
|
+
* The primary-key re-key pre-pass, shared by both statements that move the key:
|
|
3130
|
+
* `alter column … set collate` on a PK member (the comparator moves) and
|
|
3131
|
+
* `alter table … alter primary key` (the key columns move — {@link alterPrimaryKey}).
|
|
3132
|
+
* Runs before anything is mutated, so a rejection leaves the table, the schema and the
|
|
3133
|
+
* transaction untouched.
|
|
3127
3134
|
*
|
|
3128
3135
|
* Asks two questions, in order, over two DIFFERENT row sets:
|
|
3129
3136
|
*
|
|
@@ -3141,11 +3148,11 @@ export class MemoryTableManager {
|
|
|
3141
3148
|
* necessity, not because the data is invalid: the base must keep both rows for a
|
|
3142
3149
|
* rollback, and a base re-keyed under the new collation could not represent the pair
|
|
3143
3150
|
* at all → `BUSY` with the same "commit/rollback and retry" posture as
|
|
3144
|
-
* {@link ensureSchemaChangeSafety}. The persistent store backend
|
|
3145
|
-
*
|
|
3146
|
-
*
|
|
3147
|
-
* take transaction-scoped DDL
|
|
3148
|
-
* which Quereus does not have.
|
|
3151
|
+
* {@link ensureSchemaChangeSafety}. The persistent store backend asks the same two
|
|
3152
|
+
* questions with the same statuses (`StoreTable.validateRekeyedPrimaryKey` in
|
|
3153
|
+
* quereus-store — its committed rows equally survive a rollback); accepting the
|
|
3154
|
+
* deleted-collider shape instead would take transaction-scoped DDL
|
|
3155
|
+
* (`backlog/feat-transactional-ddl-native-backends`), which Quereus does not have.
|
|
3149
3156
|
*
|
|
3150
3157
|
* The passes judge different sets because a wrapper's effective stream and this manager's
|
|
3151
3158
|
* layers genuinely diverge: staged inserts exist only in the stream, deleted committed
|
|
@@ -3161,9 +3168,10 @@ export class MemoryTableManager {
|
|
|
3161
3168
|
* rebase that savepoint snapshots exist to avoid. The tradeoff is a rare false BUSY on a
|
|
3162
3169
|
* statement sequence the user can retry after committing, versus losing a row on rollback.
|
|
3163
3170
|
*
|
|
3164
|
-
* This precondition is also what makes
|
|
3165
|
-
*
|
|
3166
|
-
* in
|
|
3171
|
+
* This precondition is also what makes the open-layer replays sound — both
|
|
3172
|
+
* `TransactionLayer.rekeyPrimaryKey`'s and `installRekeyedPrimaryKeyColumns`'s: with no
|
|
3173
|
+
* collisions anywhere in the chain, every primary key resolves to at most one row in
|
|
3174
|
+
* each layer under the new definition.
|
|
3167
3175
|
*/
|
|
3168
3176
|
async validateRekeyedPrimaryKey(newSchema, rows) {
|
|
3169
3177
|
const newPkFunctions = createPrimaryKeyFunctions(newSchema, this.collationResolver);
|
|
@@ -3211,8 +3219,11 @@ export class MemoryTableManager {
|
|
|
3211
3219
|
const key = seen(row);
|
|
3212
3220
|
if (key === undefined)
|
|
3213
3221
|
continue;
|
|
3214
|
-
|
|
3215
|
-
|
|
3222
|
+
// An empty new key (`alter primary key ()`, the singleton table) has no components
|
|
3223
|
+
// to name: every row IS the one key, so say that rather than render "(key: )".
|
|
3224
|
+
const parts = keyParts(key, keyIsTuple).map(formatKeyValue);
|
|
3225
|
+
const keyDesc = parts.length > 0 ? `(key: ${parts.join(', ')})` : '(the empty key admits one row)';
|
|
3226
|
+
throw new QuereusError(`UNIQUE constraint failed: ${this._tableName} primary key collides under the new key definition ${keyDesc}`, StatusCode.CONSTRAINT);
|
|
3216
3227
|
}
|
|
3217
3228
|
}
|
|
3218
3229
|
/**
|
|
@@ -3233,8 +3244,8 @@ export class MemoryTableManager {
|
|
|
3233
3244
|
const seen = this.makePrimaryKeyProbe(pkFunctions);
|
|
3234
3245
|
for (const row of iteratePrimaryRows(tree)) {
|
|
3235
3246
|
if (seen(row) !== undefined) {
|
|
3236
|
-
throw new QuereusError(`Cannot
|
|
3237
|
-
+ `rows this transaction has removed still collide under the new
|
|
3247
|
+
throw new QuereusError(`Cannot re-key the primary key of table ${this._tableName}: `
|
|
3248
|
+
+ `rows this transaction has removed still collide under the new key definition and must survive a rollback. `
|
|
3238
3249
|
+ `Commit/rollback and retry.`, StatusCode.BUSY);
|
|
3239
3250
|
}
|
|
3240
3251
|
}
|