@quereus/quereus 4.4.1 → 4.6.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/core/database-events.d.ts +99 -1
- package/dist/src/core/database-events.d.ts.map +1 -1
- package/dist/src/core/database-events.js +219 -3
- package/dist/src/core/database-events.js.map +1 -1
- package/dist/src/core/database-materialized-views-analysis.d.ts.map +1 -1
- package/dist/src/core/database-materialized-views-analysis.js +1 -0
- package/dist/src/core/database-materialized-views-analysis.js.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 +29 -2
- package/dist/src/core/database-materialized-views-plan-builders.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 +7 -1
- package/dist/src/core/database.d.ts.map +1 -1
- package/dist/src/core/database.js +20 -5
- package/dist/src/core/database.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/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 +193 -37
- 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 +11 -3
- 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 +39 -1
- package/dist/src/func/registration.d.ts.map +1 -1
- package/dist/src/func/registration.js +236 -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 +14 -5
- package/dist/src/index.js.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 +160 -44
- package/dist/src/parser/parser.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/coarsened-key.d.ts +4 -3
- package/dist/src/planner/analysis/coarsened-key.d.ts.map +1 -1
- package/dist/src/planner/analysis/coarsened-key.js +37 -3
- package/dist/src/planner/analysis/coarsened-key.js.map +1 -1
- package/dist/src/planner/analysis/comparison-collation.d.ts +41 -13
- package/dist/src/planner/analysis/comparison-collation.d.ts.map +1 -1
- package/dist/src/planner/analysis/comparison-collation.js +51 -14
- 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 +13 -2
- package/dist/src/planner/analysis/coverage-prover.d.ts.map +1 -1
- package/dist/src/planner/analysis/coverage-prover.js +10 -14
- package/dist/src/planner/analysis/coverage-prover.js.map +1 -1
- package/dist/src/planner/analysis/predicate-conjuncts.d.ts +10 -4
- package/dist/src/planner/analysis/predicate-conjuncts.d.ts.map +1 -1
- package/dist/src/planner/analysis/predicate-conjuncts.js +28 -7
- package/dist/src/planner/analysis/predicate-conjuncts.js.map +1 -1
- package/dist/src/planner/analysis/query-rewrite-matcher.d.ts.map +1 -1
- package/dist/src/planner/analysis/query-rewrite-matcher.js +8 -27
- package/dist/src/planner/analysis/query-rewrite-matcher.js.map +1 -1
- package/dist/src/planner/analysis/scalar-subqueries.d.ts +22 -3
- package/dist/src/planner/analysis/scalar-subqueries.d.ts.map +1 -1
- package/dist/src/planner/analysis/scalar-subqueries.js +32 -3
- package/dist/src/planner/analysis/scalar-subqueries.js.map +1 -1
- package/dist/src/planner/analysis/set-op-type-merge.d.ts +64 -0
- package/dist/src/planner/analysis/set-op-type-merge.d.ts.map +1 -0
- package/dist/src/planner/analysis/set-op-type-merge.js +97 -0
- package/dist/src/planner/analysis/set-op-type-merge.js.map +1 -0
- package/dist/src/planner/building/alter-table.d.ts.map +1 -1
- package/dist/src/planner/building/alter-table.js +65 -27
- package/dist/src/planner/building/alter-table.js.map +1 -1
- package/dist/src/planner/building/coercion.d.ts +54 -0
- package/dist/src/planner/building/coercion.d.ts.map +1 -0
- package/dist/src/planner/building/coercion.js +88 -0
- package/dist/src/planner/building/coercion.js.map +1 -0
- package/dist/src/planner/building/constraint-builder.d.ts.map +1 -1
- package/dist/src/planner/building/constraint-builder.js +5 -18
- package/dist/src/planner/building/constraint-builder.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 +23 -115
- package/dist/src/planner/building/expression.js.map +1 -1
- package/dist/src/planner/building/function-call.d.ts.map +1 -1
- package/dist/src/planner/building/function-call.js +13 -0
- package/dist/src/planner/building/function-call.js.map +1 -1
- package/dist/src/planner/building/select-aggregates.d.ts +1 -1
- package/dist/src/planner/building/select-aggregates.d.ts.map +1 -1
- package/dist/src/planner/building/select-aggregates.js +53 -2
- package/dist/src/planner/building/select-aggregates.js.map +1 -1
- package/dist/src/planner/building/select-compound.d.ts.map +1 -1
- package/dist/src/planner/building/select-compound.js +10 -6
- package/dist/src/planner/building/select-compound.js.map +1 -1
- package/dist/src/planner/building/select-context.d.ts +7 -0
- package/dist/src/planner/building/select-context.d.ts.map +1 -1
- package/dist/src/planner/building/select-context.js +10 -40
- package/dist/src/planner/building/select-context.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 +112 -51
- package/dist/src/planner/building/select.js.map +1 -1
- package/dist/src/planner/cost/conjunct-cost.d.ts +82 -0
- package/dist/src/planner/cost/conjunct-cost.d.ts.map +1 -0
- package/dist/src/planner/cost/conjunct-cost.js +107 -0
- package/dist/src/planner/cost/conjunct-cost.js.map +1 -0
- 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/mutation/propagate.d.ts.map +1 -1
- package/dist/src/planner/mutation/propagate.js +1 -0
- package/dist/src/planner/mutation/propagate.js.map +1 -1
- package/dist/src/planner/nodes/aggregate-node.d.ts +6 -0
- package/dist/src/planner/nodes/aggregate-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/aggregate-node.js +10 -2
- 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 +24 -8
- package/dist/src/planner/nodes/alter-table-node.d.ts.map +1 -1
- 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/async-gather-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/async-gather-node.js +19 -8
- package/dist/src/planner/nodes/async-gather-node.js.map +1 -1
- package/dist/src/planner/nodes/bloom-join-node.d.ts +2 -0
- package/dist/src/planner/nodes/bloom-join-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/bloom-join-node.js +17 -7
- 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/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/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 +12 -5
- package/dist/src/planner/nodes/filter.js.map +1 -1
- package/dist/src/planner/nodes/hash-aggregate.d.ts +6 -0
- package/dist/src/planner/nodes/hash-aggregate.d.ts.map +1 -1
- package/dist/src/planner/nodes/hash-aggregate.js +10 -2
- package/dist/src/planner/nodes/hash-aggregate.js.map +1 -1
- package/dist/src/planner/nodes/join-node.d.ts +25 -1
- package/dist/src/planner/nodes/join-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/join-node.js +38 -10
- package/dist/src/planner/nodes/join-node.js.map +1 -1
- package/dist/src/planner/nodes/join-utils.d.ts +78 -0
- package/dist/src/planner/nodes/join-utils.d.ts.map +1 -1
- package/dist/src/planner/nodes/join-utils.js +73 -0
- package/dist/src/planner/nodes/join-utils.js.map +1 -1
- package/dist/src/planner/nodes/key-set-semi-join-node.d.ts +87 -0
- package/dist/src/planner/nodes/key-set-semi-join-node.d.ts.map +1 -0
- package/dist/src/planner/nodes/key-set-semi-join-node.js +141 -0
- package/dist/src/planner/nodes/key-set-semi-join-node.js.map +1 -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 +2 -0
- package/dist/src/planner/nodes/merge-join-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/merge-join-node.js +21 -8
- 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-type.d.ts +1 -0
- package/dist/src/planner/nodes/plan-node-type.d.ts.map +1 -1
- package/dist/src/planner/nodes/plan-node-type.js +1 -0
- package/dist/src/planner/nodes/plan-node-type.js.map +1 -1
- package/dist/src/planner/nodes/plan-node.d.ts +24 -0
- package/dist/src/planner/nodes/plan-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/plan-node.js.map +1 -1
- package/dist/src/planner/nodes/project-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/project-node.js +2 -1
- 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.map +1 -1
- package/dist/src/planner/nodes/retrieve-node.js +2 -1
- package/dist/src/planner/nodes/retrieve-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/set-operation-node.d.ts +68 -16
- package/dist/src/planner/nodes/set-operation-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/set-operation-node.js +147 -26
- package/dist/src/planner/nodes/set-operation-node.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 +6 -0
- package/dist/src/planner/nodes/stream-aggregate.d.ts.map +1 -1
- package/dist/src/planner/nodes/stream-aggregate.js +10 -2
- package/dist/src/planner/nodes/stream-aggregate.js.map +1 -1
- package/dist/src/planner/nodes/table-access-nodes.d.ts +19 -1
- package/dist/src/planner/nodes/table-access-nodes.d.ts.map +1 -1
- package/dist/src/planner/nodes/table-access-nodes.js +18 -2
- package/dist/src/planner/nodes/table-access-nodes.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 +9 -1
- package/dist/src/planner/optimizer.d.ts.map +1 -1
- package/dist/src/planner/optimizer.js +126 -6
- package/dist/src/planner/optimizer.js.map +1 -1
- package/dist/src/planner/rules/access/rule-key-set-seek.d.ts +68 -0
- package/dist/src/planner/rules/access/rule-key-set-seek.d.ts.map +1 -0
- package/dist/src/planner/rules/access/rule-key-set-seek.js +343 -0
- package/dist/src/planner/rules/access/rule-key-set-seek.js.map +1 -0
- 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 +46 -0
- package/dist/src/planner/rules/access/rule-select-access-path.d.ts.map +1 -1
- package/dist/src/planner/rules/access/rule-select-access-path.js +54 -13
- package/dist/src/planner/rules/access/rule-select-access-path.js.map +1 -1
- package/dist/src/planner/rules/cache/rule-cte-optimization.d.ts.map +1 -1
- package/dist/src/planner/rules/cache/rule-cte-optimization.js +9 -0
- package/dist/src/planner/rules/cache/rule-cte-optimization.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 +49 -49
- package/dist/src/planner/rules/join/equi-pair-extractor.d.ts.map +1 -1
- package/dist/src/planner/rules/join/equi-pair-extractor.js +54 -58
- 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 +285 -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-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 +97 -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.map +1 -1
- package/dist/src/planner/rules/join/rule-monotonic-merge-join.js +15 -5
- package/dist/src/planner/rules/join/rule-monotonic-merge-join.js.map +1 -1
- package/dist/src/planner/rules/predicate/rule-empty-relation-folding.d.ts +1 -1
- package/dist/src/planner/rules/predicate/rule-empty-relation-folding.js +1 -1
- package/dist/src/planner/rules/predicate/rule-filter-conjunct-ordering.d.ts +43 -0
- package/dist/src/planner/rules/predicate/rule-filter-conjunct-ordering.d.ts.map +1 -0
- package/dist/src/planner/rules/predicate/rule-filter-conjunct-ordering.js +119 -0
- package/dist/src/planner/rules/predicate/rule-filter-conjunct-ordering.js.map +1 -0
- package/dist/src/planner/rules/predicate/rule-filter-selectivity.d.ts +44 -3
- package/dist/src/planner/rules/predicate/rule-filter-selectivity.d.ts.map +1 -1
- package/dist/src/planner/rules/predicate/rule-filter-selectivity.js +142 -18
- 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 +73 -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 +205 -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 +10 -2
- package/dist/src/planner/rules/predicate/rule-predicate-pushdown.d.ts.map +1 -1
- package/dist/src/planner/rules/predicate/rule-predicate-pushdown.js +20 -2
- package/dist/src/planner/rules/predicate/rule-predicate-pushdown.js.map +1 -1
- package/dist/src/planner/rules/retrieve/rule-grow-retrieve.d.ts.map +1 -1
- package/dist/src/planner/rules/retrieve/rule-grow-retrieve.js +18 -3
- package/dist/src/planner/rules/retrieve/rule-grow-retrieve.js.map +1 -1
- package/dist/src/planner/rules/shared/access-leaf.d.ts +39 -0
- package/dist/src/planner/rules/shared/access-leaf.d.ts.map +1 -0
- package/dist/src/planner/rules/shared/access-leaf.js +79 -0
- package/dist/src/planner/rules/shared/access-leaf.js.map +1 -0
- package/dist/src/planner/rules/shared/index-style-context.d.ts +17 -0
- package/dist/src/planner/rules/shared/index-style-context.d.ts.map +1 -1
- package/dist/src/planner/rules/shared/index-style-context.js +7 -0
- package/dist/src/planner/rules/shared/index-style-context.js.map +1 -1
- package/dist/src/planner/rules/subquery/rule-anti-join-fk-empty.d.ts.map +1 -1
- package/dist/src/planner/rules/subquery/rule-anti-join-fk-empty.js +18 -8
- 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 +27 -10
- 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 +24 -6
- package/dist/src/planner/rules/subquery/rule-subquery-decorrelation.d.ts.map +1 -1
- package/dist/src/planner/rules/subquery/rule-subquery-decorrelation.js +243 -70
- 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 +87 -4
- package/dist/src/planner/stats/catalog-stats.d.ts.map +1 -1
- package/dist/src/planner/stats/catalog-stats.js +250 -28
- 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 +36 -2
- 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/selectivity-combine.d.ts +53 -0
- package/dist/src/planner/stats/selectivity-combine.d.ts.map +1 -0
- package/dist/src/planner/stats/selectivity-combine.js +75 -0
- package/dist/src/planner/stats/selectivity-combine.js.map +1 -0
- 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/util/column-origins.d.ts +79 -0
- package/dist/src/planner/util/column-origins.d.ts.map +1 -0
- package/dist/src/planner/util/column-origins.js +150 -0
- package/dist/src/planner/util/column-origins.js.map +1 -0
- 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 +56 -17
- package/dist/src/planner/util/ind-utils.d.ts.map +1 -1
- package/dist/src/planner/util/ind-utils.js +82 -21
- package/dist/src/planner/util/ind-utils.js.map +1 -1
- package/dist/src/planner/util/key-utils.d.ts +20 -2
- package/dist/src/planner/util/key-utils.d.ts.map +1 -1
- package/dist/src/planner/util/key-utils.js +37 -3
- package/dist/src/planner/util/key-utils.js.map +1 -1
- package/dist/src/planner/util/row-estimates.d.ts +28 -0
- package/dist/src/planner/util/row-estimates.d.ts.map +1 -0
- package/dist/src/planner/util/row-estimates.js +40 -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 +40 -0
- package/dist/src/runtime/deferred-constraint-queue.d.ts.map +1 -1
- package/dist/src/runtime/deferred-constraint-queue.js +90 -9
- 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 +39 -1
- 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 +42 -0
- package/dist/src/runtime/emit/alter-schema-event.d.ts.map +1 -0
- package/dist/src/runtime/emit/alter-schema-event.js +28 -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 +386 -154
- 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 +35 -3
- package/dist/src/runtime/emit/analyze.js.map +1 -1
- package/dist/src/runtime/emit/asof-scan.d.ts.map +1 -1
- package/dist/src/runtime/emit/asof-scan.js +8 -3
- package/dist/src/runtime/emit/asof-scan.js.map +1 -1
- package/dist/src/runtime/emit/between.d.ts.map +1 -1
- package/dist/src/runtime/emit/between.js +4 -38
- package/dist/src/runtime/emit/between.js.map +1 -1
- package/dist/src/runtime/emit/binary.d.ts.map +1 -1
- package/dist/src/runtime/emit/binary.js +2 -23
- package/dist/src/runtime/emit/binary.js.map +1 -1
- package/dist/src/runtime/emit/bloom-join.d.ts.map +1 -1
- package/dist/src/runtime/emit/bloom-join.js +6 -35
- package/dist/src/runtime/emit/bloom-join.js.map +1 -1
- package/dist/src/runtime/emit/case.d.ts.map +1 -1
- package/dist/src/runtime/emit/case.js +40 -6
- package/dist/src/runtime/emit/case.js.map +1 -1
- package/dist/src/runtime/emit/cast.d.ts.map +1 -1
- package/dist/src/runtime/emit/cast.js +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 +32 -8
- package/dist/src/runtime/emit/constraint-check.js.map +1 -1
- package/dist/src/runtime/emit/dml-executor.d.ts.map +1 -1
- package/dist/src/runtime/emit/dml-executor.js +90 -50
- package/dist/src/runtime/emit/dml-executor.js.map +1 -1
- 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/filter.d.ts +18 -0
- package/dist/src/runtime/emit/filter.d.ts.map +1 -1
- package/dist/src/runtime/emit/filter.js +52 -10
- package/dist/src/runtime/emit/filter.js.map +1 -1
- package/dist/src/runtime/emit/hash-aggregate.d.ts.map +1 -1
- package/dist/src/runtime/emit/hash-aggregate.js +2 -2
- package/dist/src/runtime/emit/hash-aggregate.js.map +1 -1
- package/dist/src/runtime/emit/join-key-extractor.d.ts +46 -0
- package/dist/src/runtime/emit/join-key-extractor.d.ts.map +1 -0
- package/dist/src/runtime/emit/join-key-extractor.js +60 -0
- package/dist/src/runtime/emit/join-key-extractor.js.map +1 -0
- package/dist/src/runtime/emit/join.d.ts.map +1 -1
- package/dist/src/runtime/emit/join.js +8 -46
- package/dist/src/runtime/emit/join.js.map +1 -1
- package/dist/src/runtime/emit/key-set-semi-join.d.ts +29 -0
- package/dist/src/runtime/emit/key-set-semi-join.d.ts.map +1 -0
- package/dist/src/runtime/emit/key-set-semi-join.js +149 -0
- package/dist/src/runtime/emit/key-set-semi-join.js.map +1 -0
- package/dist/src/runtime/emit/merge-join.d.ts.map +1 -1
- package/dist/src/runtime/emit/merge-join.js +15 -8
- package/dist/src/runtime/emit/merge-join.js.map +1 -1
- package/dist/src/runtime/emit/operand-comparator.d.ts +70 -0
- package/dist/src/runtime/emit/operand-comparator.d.ts.map +1 -0
- package/dist/src/runtime/emit/operand-comparator.js +93 -0
- package/dist/src/runtime/emit/operand-comparator.js.map +1 -0
- package/dist/src/runtime/emit/scan.d.ts.map +1 -1
- package/dist/src/runtime/emit/scan.js +11 -2
- package/dist/src/runtime/emit/scan.js.map +1 -1
- package/dist/src/runtime/emit/schema-declarative.d.ts.map +1 -1
- package/dist/src/runtime/emit/schema-declarative.js +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/window.js +36 -23
- package/dist/src/runtime/emit/window.js.map +1 -1
- package/dist/src/runtime/parallel-driver.d.ts +5 -2
- package/dist/src/runtime/parallel-driver.d.ts.map +1 -1
- package/dist/src/runtime/parallel-driver.js +6 -2
- package/dist/src/runtime/parallel-driver.js.map +1 -1
- package/dist/src/runtime/register.d.ts.map +1 -1
- package/dist/src/runtime/register.js +2 -0
- package/dist/src/runtime/register.js.map +1 -1
- package/dist/src/runtime/types.d.ts +7 -0
- package/dist/src/runtime/types.d.ts.map +1 -1
- package/dist/src/runtime/types.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 +76 -20
- package/dist/src/schema/catalog-persistability.js.map +1 -1
- package/dist/src/schema/catalog.d.ts +67 -2
- package/dist/src/schema/catalog.d.ts.map +1 -1
- package/dist/src/schema/catalog.js +194 -3
- package/dist/src/schema/catalog.js.map +1 -1
- 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/ddl-generator.d.ts.map +1 -1
- package/dist/src/schema/ddl-generator.js +19 -6
- package/dist/src/schema/ddl-generator.js.map +1 -1
- package/dist/src/schema/function.d.ts +40 -0
- 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/manager.d.ts +84 -7
- package/dist/src/schema/manager.d.ts.map +1 -1
- package/dist/src/schema/manager.js +153 -53
- package/dist/src/schema/manager.js.map +1 -1
- package/dist/src/schema/schema-differ.d.ts.map +1 -1
- package/dist/src/schema/schema-differ.js +104 -28
- 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/types/builtin-types.d.ts +16 -0
- package/dist/src/types/builtin-types.d.ts.map +1 -1
- package/dist/src/types/builtin-types.js +76 -12
- 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/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 +41 -3
- package/dist/src/util/comparison.d.ts.map +1 -1
- package/dist/src/util/comparison.js +52 -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/best-access-plan.d.ts +87 -0
- package/dist/src/vtab/best-access-plan.d.ts.map +1 -1
- package/dist/src/vtab/best-access-plan.js +87 -0
- package/dist/src/vtab/best-access-plan.js.map +1 -1
- package/dist/src/vtab/capabilities.d.ts +1 -1
- package/dist/src/vtab/events.d.ts +5 -1
- package/dist/src/vtab/events.d.ts.map +1 -1
- package/dist/src/vtab/events.js.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 +6 -4
- package/dist/src/vtab/memory/layer/base.d.ts.map +1 -1
- package/dist/src/vtab/memory/layer/base.js +10 -7
- 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 +232 -39
- package/dist/src/vtab/memory/layer/manager.d.ts.map +1 -1
- package/dist/src/vtab/memory/layer/manager.js +657 -519
- 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 +111 -16
- package/dist/src/vtab/memory/layer/transaction.d.ts.map +1 -1
- package/dist/src/vtab/memory/layer/transaction.js +154 -51
- package/dist/src/vtab/memory/layer/transaction.js.map +1 -1
- package/dist/src/vtab/memory/module.d.ts +14 -2
- package/dist/src/vtab/memory/module.d.ts.map +1 -1
- package/dist/src/vtab/memory/module.js +53 -40
- package/dist/src/vtab/memory/module.js.map +1 -1
- package/dist/src/vtab/memory/table.d.ts +1 -1
- package/dist/src/vtab/memory/table.d.ts.map +1 -1
- package/dist/src/vtab/memory/table.js +15 -3
- package/dist/src/vtab/memory/table.js.map +1 -1
- package/dist/src/vtab/module.d.ts +51 -21
- package/dist/src/vtab/module.d.ts.map +1 -1
- package/dist/src/vtab/table.d.ts +10 -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
|
@@ -3,12 +3,18 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Required Characteristics:
|
|
5
5
|
* - Node must be a logical JoinNode (not already a physical join)
|
|
6
|
-
* - Node must have an equi-join predicate for hash/merge
|
|
6
|
+
* - Node must have an equi-join predicate for hash/merge/index-NL consideration
|
|
7
|
+
* - Neither side may be correlated (a correlated side must keep the
|
|
8
|
+
* nested-loop driver — hash/merge drain a side outside any outer row's scope)
|
|
7
9
|
*
|
|
8
10
|
* Applied When:
|
|
9
|
-
* - Logical JoinNode with equi-join predicates where hash
|
|
11
|
+
* - Logical JoinNode with equi-join predicates where hash join, merge join, or
|
|
12
|
+
* an index-nested-loop (per-outer-row seek into the inner side, built by
|
|
13
|
+
* `index-nested-loop.ts`) is cheaper than the plain nested loop
|
|
10
14
|
*
|
|
11
|
-
* Benefits: Replaces O(n*m) nested loop with O(n+m) hash/merge join
|
|
15
|
+
* Benefits: Replaces the O(n*m) nested loop with an O(n+m) hash/merge join, or
|
|
16
|
+
* with an O(n·seek) index-nested-loop when the inner side's module can answer
|
|
17
|
+
* an equality seek on the join key
|
|
12
18
|
*/
|
|
13
19
|
import { createLogger } from '../../../common/logger.js';
|
|
14
20
|
import { JoinNode } from '../../nodes/join-node.js';
|
|
@@ -17,8 +23,11 @@ import { MergeJoinNode } from '../../nodes/merge-join-node.js';
|
|
|
17
23
|
import { SortNode } from '../../nodes/sort.js';
|
|
18
24
|
import { ColumnReferenceNode } from '../../nodes/reference.js';
|
|
19
25
|
import { nestedLoopJoinCost, hashJoinCost, mergeJoinCost } from '../../cost/index.js';
|
|
20
|
-
import { extractEquiPairs,
|
|
26
|
+
import { extractEquiPairs, isOrderedOnEquiPairs, reorderEquiPairsForMerge, } from './equi-pair-extractor.js';
|
|
21
27
|
import { PlanNodeCharacteristics } from '../../framework/characteristics.js';
|
|
28
|
+
import { isCorrelatedSubquery } from '../../cache/correlation-detector.js';
|
|
29
|
+
import { physicalSourceRows } from '../../util/row-estimates.js';
|
|
30
|
+
import { tryIndexNestedLoop } from './index-nested-loop.js';
|
|
22
31
|
const log = createLogger('optimizer:rule:join-physical-selection');
|
|
23
32
|
/**
|
|
24
33
|
* Create a SortNode that sorts a source on the equi-pair columns for this side.
|
|
@@ -40,15 +49,18 @@ function createSortForEquiPairs(source, equiPairs, side, scope) {
|
|
|
40
49
|
});
|
|
41
50
|
return new SortNode(scope, source, sortKeys);
|
|
42
51
|
}
|
|
43
|
-
export function ruleJoinPhysicalSelection(node,
|
|
52
|
+
export function ruleJoinPhysicalSelection(node, context) {
|
|
44
53
|
// Guard: only apply to logical JoinNode, not already-physical nodes
|
|
45
54
|
if (!(node instanceof JoinNode))
|
|
46
55
|
return null;
|
|
47
|
-
// A
|
|
48
|
-
//
|
|
49
|
-
//
|
|
50
|
-
//
|
|
51
|
-
|
|
56
|
+
// A correlated side must keep the nested-loop driver: hash and merge both
|
|
57
|
+
// drain a side once, outside any outer row's scope, so a subtree reading
|
|
58
|
+
// outer columns would resolve against no row (LATERAL is a parsed, supported
|
|
59
|
+
// join form, so `join lateral (…) on <equality>` reaches this rule with a
|
|
60
|
+
// correlated right side — converting it to a hash join raised "No row
|
|
61
|
+
// context found" at runtime). This is also what makes the index-nested-loop
|
|
62
|
+
// rewrite below idempotent: its own output has a correlated right side.
|
|
63
|
+
if (isCorrelatedSubquery(node.left) || isCorrelatedSubquery(node.right))
|
|
52
64
|
return null;
|
|
53
65
|
const joinType = node.joinType;
|
|
54
66
|
// Support INNER, LEFT, SEMI, and ANTI joins
|
|
@@ -59,24 +71,63 @@ export function ruleJoinPhysicalSelection(node, _context) {
|
|
|
59
71
|
const rightAttrs = node.right.getAttributes();
|
|
60
72
|
const leftAttrIds = new Set(leftAttrs.map(a => a.id));
|
|
61
73
|
const rightAttrIds = new Set(rightAttrs.map(a => a.id));
|
|
62
|
-
// Try to extract equi-join pairs from condition
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
extracted = extractEquiPairs(node.condition, leftAttrIds, rightAttrIds);
|
|
66
|
-
}
|
|
67
|
-
else if (node.usingColumns) {
|
|
68
|
-
extracted = extractEquiPairsFromUsing(node.usingColumns, leftAttrs, rightAttrs);
|
|
69
|
-
}
|
|
74
|
+
// Try to extract equi-join pairs from the condition. A USING join has one too —
|
|
75
|
+
// `buildUsingCondition` desugars it at build time — so there is no separate path.
|
|
76
|
+
const extracted = extractEquiPairs(node.condition, leftAttrIds, rightAttrIds);
|
|
70
77
|
if (!extracted || extracted.equiPairs.length === 0)
|
|
71
78
|
return null;
|
|
72
|
-
// Cost comparison: nested loop vs hash join vs merge join
|
|
73
|
-
|
|
74
|
-
|
|
79
|
+
// Cost comparison: nested loop vs hash join vs merge join vs index-nested-loop.
|
|
80
|
+
// Physical relay first: by PostOptimization both sides are physical access
|
|
81
|
+
// nodes (or wrappers over them) which declare no logical `estimatedRows`
|
|
82
|
+
// getter — the catalog-derived count lives in `physical.estimatedRows` (see
|
|
83
|
+
// planner/util/row-estimates.ts). `||` not `??`: 0 is the un-analyzed
|
|
84
|
+
// "unknown" sentinel, not "empty" (same collapse rule-select-access-path
|
|
85
|
+
// applies), so an un-analyzed table costs exactly as it did under the old
|
|
86
|
+
// logical-getter read (which yielded undefined → 100).
|
|
87
|
+
const leftRows = physicalSourceRows(node.left.physical, node.left) || 100;
|
|
88
|
+
const rightRows = physicalSourceRows(node.right.physical, node.right) || 100;
|
|
75
89
|
const nlCost = nestedLoopJoinCost(leftRows, rightRows);
|
|
90
|
+
// Index-nested-loop candidate: the logical JoinNode survives with its right
|
|
91
|
+
// leaf replaced by a per-outer-row correlated IndexSeek. Considered BEFORE
|
|
92
|
+
// the existence early-return below — index-NL keeps the nested-loop emitter
|
|
93
|
+
// (the only one that derives `exists … as` flag bits) and `withChildren`
|
|
94
|
+
// threads `existence` verbatim, so existence joins CAN take this path,
|
|
95
|
+
// unlike hash/merge which drop the appended flag column.
|
|
96
|
+
const indexNL = tryIndexNestedLoop(node, extracted.equiPairs, leftRows, context);
|
|
97
|
+
// Rebuild with the seek-bearing right side, KEEPING the ON condition on the
|
|
98
|
+
// join. It is redundant when the seek is exact, but it is the safety net
|
|
99
|
+
// when the seek over-fetches (a COARSER_SAFE collation cover, a module
|
|
100
|
+
// returning a superset) — and it costs one predicate evaluation per emitted
|
|
101
|
+
// row, not per scanned row.
|
|
102
|
+
const rebuildWithIndexNL = () => {
|
|
103
|
+
log('Selecting index-nested-loop join (cost=%.2f) for %d outer rows', indexNL.cost, leftRows);
|
|
104
|
+
return node.withChildren(node.condition
|
|
105
|
+
? [node.left, indexNL.newRight, node.condition]
|
|
106
|
+
: [node.left, indexNL.newRight]);
|
|
107
|
+
};
|
|
108
|
+
// A join exposing `exists … as` match flags stays the nested-loop JoinNode (the
|
|
109
|
+
// only emitter that derives the flag bit); the physical Bloom/Merge variants do
|
|
110
|
+
// not carry or emit the appended flag column, so converting would drop it. Read
|
|
111
|
+
// half: existence joins forgo hash/merge selection — documented limitation.
|
|
112
|
+
// Index-NL remains available (see above): only plain NL and index-NL compete.
|
|
113
|
+
if (node.hasExistenceColumns) {
|
|
114
|
+
if (indexNL && indexNL.cost < nlCost)
|
|
115
|
+
return rebuildWithIndexNL();
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
76
118
|
// Hash join cost: build side is the smaller input
|
|
77
119
|
const buildRows = Math.min(leftRows, rightRows);
|
|
78
120
|
const probeRows = Math.max(leftRows, rightRows);
|
|
79
121
|
const hashCostValue = hashJoinCost(buildRows, probeRows);
|
|
122
|
+
// Merge join is a candidate only when EVERY pair has matched declared
|
|
123
|
+
// collations: merge needs both inputs physically ordered under the key's
|
|
124
|
+
// comparison collation, and the ordering property is collation-blind — a
|
|
125
|
+
// matched declared collation is what makes each input's advertised order
|
|
126
|
+
// equal the merge comparator's order (see EquiJoinPair.collationsMatch).
|
|
127
|
+
// Any mismatched pair ⇒ merge unavailable; hash vs nested-loop compete.
|
|
128
|
+
// (Merging on just the matched subset would be sound but is deliberately
|
|
129
|
+
// not attempted — rare shape, minimal-change tradeoff.)
|
|
130
|
+
const mergeAvailable = extracted.equiPairs.every(p => p.collationsMatch);
|
|
80
131
|
// Merge join cost: depends on whether inputs are already sorted.
|
|
81
132
|
// Try reordering equi-pairs to match the source orderings first.
|
|
82
133
|
let mergeEquiPairs = extracted.equiPairs;
|
|
@@ -90,22 +141,38 @@ export function ruleJoinPhysicalSelection(node, _context) {
|
|
|
90
141
|
rightOrdered = true;
|
|
91
142
|
}
|
|
92
143
|
}
|
|
93
|
-
const mergeCostValue =
|
|
144
|
+
const mergeCostValue = mergeAvailable
|
|
145
|
+
? mergeJoinCost(leftRows, rightRows, !leftOrdered, !rightOrdered)
|
|
146
|
+
: Infinity;
|
|
147
|
+
// Hash and merge each scan the inner side once, so the inner subtree's
|
|
148
|
+
// first-row latency is charged ONCE to each — locally here, not in the
|
|
149
|
+
// shared cost functions (which other callers use latency-free). Index-NL's
|
|
150
|
+
// formula charges it per outer row (per seek). Plain nested-loop's formula
|
|
151
|
+
// is deliberately left alone: it is the no-change fallback, and if it wins
|
|
152
|
+
// nothing is rewritten.
|
|
153
|
+
const rightLatencyMs = node.right.physical.expectedLatencyMs ?? 0;
|
|
94
154
|
let bestAlgo = 'nested-loop';
|
|
95
155
|
let bestCost = nlCost;
|
|
96
|
-
if (hashCostValue < bestCost) {
|
|
156
|
+
if (hashCostValue + rightLatencyMs < bestCost) {
|
|
97
157
|
bestAlgo = 'hash';
|
|
98
|
-
bestCost = hashCostValue;
|
|
158
|
+
bestCost = hashCostValue + rightLatencyMs;
|
|
99
159
|
}
|
|
100
|
-
if (mergeCostValue < bestCost) {
|
|
160
|
+
if (mergeCostValue + rightLatencyMs < bestCost) {
|
|
101
161
|
bestAlgo = 'merge';
|
|
102
|
-
bestCost = mergeCostValue;
|
|
162
|
+
bestCost = mergeCostValue + rightLatencyMs;
|
|
163
|
+
}
|
|
164
|
+
if (indexNL && indexNL.cost < bestCost) {
|
|
165
|
+
bestAlgo = 'index-nl';
|
|
166
|
+
bestCost = indexNL.cost;
|
|
103
167
|
}
|
|
104
168
|
if (bestAlgo === 'nested-loop') {
|
|
105
|
-
log('Nested loop cheapest (nl=%.2f, hash=%.2f, merge=%.2f) for %d x %d rows', nlCost, hashCostValue, mergeCostValue, leftRows, rightRows);
|
|
169
|
+
log('Nested loop cheapest (nl=%.2f, hash=%.2f, merge=%.2f, indexNL=%.2f) for %d x %d rows', nlCost, hashCostValue, mergeCostValue, indexNL?.cost ?? Infinity, leftRows, rightRows);
|
|
106
170
|
return null;
|
|
107
171
|
}
|
|
108
|
-
|
|
172
|
+
if (bestAlgo === 'index-nl') {
|
|
173
|
+
return rebuildWithIndexNL();
|
|
174
|
+
}
|
|
175
|
+
log('Selecting %s join (nl=%.2f, hash=%.2f, merge=%.2f, indexNL=%.2f) for %d x %d rows', bestAlgo, nlCost, hashCostValue, mergeCostValue, indexNL?.cost ?? Infinity, leftRows, rightRows);
|
|
109
176
|
// Preserve attribute IDs from the logical JoinNode
|
|
110
177
|
const preserveAttrs = node.getAttributes().slice();
|
|
111
178
|
if (bestAlgo === 'merge') {
|
|
@@ -139,8 +206,9 @@ export function ruleJoinPhysicalSelection(node, _context) {
|
|
|
139
206
|
// Swap: left becomes build, right becomes probe
|
|
140
207
|
probeSource = node.right;
|
|
141
208
|
buildSource = node.left;
|
|
142
|
-
// Flip equi-pair directions
|
|
209
|
+
// Flip equi-pair directions; spread so the collation flags survive.
|
|
143
210
|
equiPairs = extracted.equiPairs.map(p => ({
|
|
211
|
+
...p,
|
|
144
212
|
leftAttrId: p.rightAttrId,
|
|
145
213
|
rightAttrId: p.leftAttrId
|
|
146
214
|
}));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rule-join-physical-selection.js","sourceRoot":"","sources":["../../../../../src/planner/rules/join/rule-join-physical-selection.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"rule-join-physical-selection.js","sourceRoot":"","sources":["../../../../../src/planner/rules/join/rule-join-physical-selection.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rule-monotonic-merge-join.d.ts","sourceRoot":"","sources":["../../../../../src/planner/rules/join/rule-monotonic-merge-join.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAA6B,MAAM,0BAA0B,CAAC;AACpF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAU7D,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,GAAG,QAAQ,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"rule-monotonic-merge-join.d.ts","sourceRoot":"","sources":["../../../../../src/planner/rules/join/rule-monotonic-merge-join.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAA6B,MAAM,0BAA0B,CAAC;AACpF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAU7D,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,GAAG,QAAQ,GAAG,IAAI,CAqG5F"}
|
|
@@ -30,7 +30,7 @@ import { JoinNode } from '../../nodes/join-node.js';
|
|
|
30
30
|
import { MergeJoinNode } from '../../nodes/merge-join-node.js';
|
|
31
31
|
import { nestedLoopJoinCost, hashJoinCost, mergeJoinCost } from '../../cost/index.js';
|
|
32
32
|
import { PlanNodeCharacteristics } from '../../framework/characteristics.js';
|
|
33
|
-
import { extractEquiPairs,
|
|
33
|
+
import { extractEquiPairs, combineResidual, isMergeReadyOnAllPairs } from './equi-pair-extractor.js';
|
|
34
34
|
const log = createLogger('optimizer:rule:monotonic-merge-join');
|
|
35
35
|
export function ruleMonotonicMergeJoin(node, _context) {
|
|
36
36
|
if (!(node instanceof JoinNode))
|
|
@@ -46,9 +46,9 @@ export function ruleMonotonicMergeJoin(node, _context) {
|
|
|
46
46
|
const rightAttrs = node.right.getAttributes();
|
|
47
47
|
const leftAttrIds = new Set(leftAttrs.map(a => a.id));
|
|
48
48
|
const rightAttrIds = new Set(rightAttrs.map(a => a.id));
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
49
|
+
// A USING join carries a desugared condition (see `buildUsingCondition`), so the
|
|
50
|
+
// one extractor covers both spellings.
|
|
51
|
+
const extracted = extractEquiPairs(node.condition, leftAttrIds, rightAttrIds);
|
|
52
52
|
if (!extracted || extracted.equiPairs.length === 0)
|
|
53
53
|
return null;
|
|
54
54
|
// Defer to `rule-join-physical-selection` whenever both sides' physical
|
|
@@ -56,7 +56,11 @@ export function ruleMonotonicMergeJoin(node, _context) {
|
|
|
56
56
|
// ordering-based path produces a multi-key merge join with full
|
|
57
57
|
// unique-key propagation; demoting pairs to residual here would lose that
|
|
58
58
|
// propagation. Our rule is meant to *extend* recognition, not regress it.
|
|
59
|
-
|
|
59
|
+
// Defer only when that rule can actually take merge: it requires EVERY
|
|
60
|
+
// pair `collationsMatch` (see EquiJoinPair.collationsMatch) — with any
|
|
61
|
+
// mismatched pair it never merges, so there is nothing to defer to.
|
|
62
|
+
if (extracted.equiPairs.every(p => p.collationsMatch)
|
|
63
|
+
&& isMergeReadyOnAllPairs(node.left, node.right, extracted.equiPairs))
|
|
60
64
|
return null;
|
|
61
65
|
const leftMon = PlanNodeCharacteristics.getMonotonicOn(node.left);
|
|
62
66
|
const rightMon = PlanNodeCharacteristics.getMonotonicOn(node.right);
|
|
@@ -65,9 +69,15 @@ export function ruleMonotonicMergeJoin(node, _context) {
|
|
|
65
69
|
// Find equi-pairs where BOTH sides are MonotonicOn on their respective
|
|
66
70
|
// attrId with matching direction. v1 requires ASC because the merge-join
|
|
67
71
|
// emitter assumes ASC; DESC-DESC streaming would need a reversed compareKeys.
|
|
72
|
+
// The driving merge key must have matched declared collations: each side's
|
|
73
|
+
// monotonicOn (like `ordering`) is implicitly under its OWN declared
|
|
74
|
+
// collation, and the merge comparator resolves the pair's collation — only
|
|
75
|
+
// a matched pair makes those the same order (see EquiJoinPair.collationsMatch).
|
|
68
76
|
const matchedIndices = [];
|
|
69
77
|
for (let i = 0; i < extracted.equiPairs.length; i++) {
|
|
70
78
|
const pair = extracted.equiPairs[i];
|
|
79
|
+
if (!pair.collationsMatch)
|
|
80
|
+
continue;
|
|
71
81
|
const l = leftMon.find(m => m.attrId === pair.leftAttrId && m.direction === 'asc');
|
|
72
82
|
if (!l)
|
|
73
83
|
continue;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rule-monotonic-merge-join.js","sourceRoot":"","sources":["../../../../../src/planner/rules/join/rule-monotonic-merge-join.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAGzD,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAE/D,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACtF,OAAO,EAAE,uBAAuB,EAAE,MAAM,oCAAoC,CAAC;AAC7E,OAAO,EAAE,gBAAgB,EAAE,
|
|
1
|
+
{"version":3,"file":"rule-monotonic-merge-join.js","sourceRoot":"","sources":["../../../../../src/planner/rules/join/rule-monotonic-merge-join.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAGzD,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAE/D,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACtF,OAAO,EAAE,uBAAuB,EAAE,MAAM,oCAAoC,CAAC;AAC7E,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAErG,MAAM,GAAG,GAAG,YAAY,CAAC,qCAAqC,CAAC,CAAC;AAEhE,MAAM,UAAU,sBAAsB,CAAC,IAAc,EAAE,QAAoB;IAC1E,IAAI,CAAC,CAAC,IAAI,YAAY,QAAQ,CAAC;QAAE,OAAO,IAAI,CAAC;IAE7C,+DAA+D;IAC/D,4EAA4E;IAC5E,IAAI,IAAI,CAAC,mBAAmB;QAAE,OAAO,IAAI,CAAC;IAE1C,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;IAC/B,IAAI,QAAQ,KAAK,OAAO,IAAI,QAAQ,KAAK,MAAM,IAAI,QAAQ,KAAK,MAAM,IAAI,QAAQ,KAAK,MAAM;QAAE,OAAO,IAAI,CAAC;IAE3G,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;IAC5C,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,aAAa,EAAE,CAAC;IAC9C,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACtD,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAExD,iFAAiF;IACjF,uCAAuC;IACvC,MAAM,SAAS,GAAG,gBAAgB,CAAC,IAAI,CAAC,SAAS,EAAE,WAAW,EAAE,YAAY,CAAC,CAAC;IAC9E,IAAI,CAAC,SAAS,IAAI,SAAS,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAEhE,wEAAwE;IACxE,mEAAmE;IACnE,gEAAgE;IAChE,0EAA0E;IAC1E,0EAA0E;IAC1E,uEAAuE;IACvE,uEAAuE;IACvE,oEAAoE;IACpE,IAAI,SAAS,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,eAAe,CAAC;WACjD,sBAAsB,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,EAAE,SAAS,CAAC,SAAS,CAAC;QAAE,OAAO,IAAI,CAAC;IAEpF,MAAM,OAAO,GAAG,uBAAuB,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAClE,MAAM,QAAQ,GAAG,uBAAuB,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACpE,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAE/D,uEAAuE;IACvE,yEAAyE;IACzE,8EAA8E;IAC9E,2EAA2E;IAC3E,qEAAqE;IACrE,2EAA2E;IAC3E,gFAAgF;IAChF,MAAM,cAAc,GAAa,EAAE,CAAC;IACpC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrD,MAAM,IAAI,GAAG,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;QACpC,IAAI,CAAC,IAAI,CAAC,eAAe;YAAE,SAAS;QACpC,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,IAAI,CAAC,UAAU,IAAI,CAAC,CAAC,SAAS,KAAK,KAAK,CAAC,CAAC;QACnF,IAAI,CAAC,CAAC;YAAE,SAAS;QACjB,MAAM,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,IAAI,CAAC,WAAW,IAAI,CAAC,CAAC,SAAS,KAAK,KAAK,CAAC,CAAC;QACrF,IAAI,CAAC,CAAC;YAAE,SAAS;QACjB,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACxB,CAAC;IACD,IAAI,cAAc,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAE7C,yEAAyE;IACzE,2EAA2E;IAC3E,yEAAyE;IACzE,2DAA2D;IAC3D,wEAAwE;IACxE,2EAA2E;IAC3E,MAAM,YAAY,GAAG,cAAc,CAAC,CAAC,CAAC,CAAC;IACvC,MAAM,OAAO,GAAmB,CAAC,SAAS,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC,CAAC;IAEpE,+EAA+E;IAC/E,yEAAyE;IACzE,kEAAkE;IAClE,wDAAwD;IACxD,MAAM,MAAM,GAAqB,EAAE,CAAC;IACpC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrD,IAAI,CAAC,KAAK,YAAY;YAAE,SAAS;QACjC,MAAM,IAAI,GAAG,SAAS,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;QACxC,IAAI,CAAC,IAAI;YAAE,OAAO,IAAI,CAAC;QACvB,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACnB,CAAC;IACD,MAAM,QAAQ,GAAG,eAAe,CAAC,SAAS,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAE7D,yEAAyE;IACzE,uCAAuC;IACvC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,IAAI,GAAG,CAAC;IAChD,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,aAAa,IAAI,GAAG,CAAC;IAClD,MAAM,MAAM,GAAG,aAAa,CAAC,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;IAChE,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,SAAS,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC,CAAC;IACzF,MAAM,GAAG,GAAG,kBAAkB,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;IACpD,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,GAAG,MAAM,EAAE,CAAC;QACnC,GAAG,CAAC,uFAAuF,EAC1F,MAAM,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC;QACrB,OAAO,IAAI,CAAC;IACb,CAAC;IAED,GAAG,CAAC,oFAAoF,EACvF,OAAO,CAAC,CAAC,CAAC,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC;IAEpE,OAAO,IAAI,aAAa,CACvB,IAAI,CAAC,KAAK,EACV,IAAI,CAAC,IAAI,EACT,IAAI,CAAC,KAAK,EACV,QAAQ,EACR,OAAO,EACP,QAAQ,EACR,IAAI,CAAC,aAAa,EAAE,CAAC,KAAK,EAAiB,CAC3C,CAAC;AACH,CAAC"}
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
* bounded: rules chain within a single node visit via the per-node fixed-
|
|
28
28
|
* point loop in `applyPassRules`, but the Structural pass itself is one
|
|
29
29
|
* top-down traversal — a parent already visited won't re-fire when an inner
|
|
30
|
-
* Filter folds. See "Cascade limits" in `docs/optimizer-
|
|
30
|
+
* Filter folds. See "Cascade limits" in `docs/optimizer-rule-families.md`.
|
|
31
31
|
*/
|
|
32
32
|
import type { PlanNode } from '../../nodes/plan-node.js';
|
|
33
33
|
import type { OptContext } from '../../framework/context.js';
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
* bounded: rules chain within a single node visit via the per-node fixed-
|
|
28
28
|
* point loop in `applyPassRules`, but the Structural pass itself is one
|
|
29
29
|
* top-down traversal — a parent already visited won't re-fire when an inner
|
|
30
|
-
* Filter folds. See "Cascade limits" in `docs/optimizer-
|
|
30
|
+
* Filter folds. See "Cascade limits" in `docs/optimizer-rule-families.md`.
|
|
31
31
|
*/
|
|
32
32
|
import { createLogger } from '../../../common/logger.js';
|
|
33
33
|
import { FilterNode } from '../../nodes/filter.js';
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rule: Filter Conjunct Ordering
|
|
3
|
+
*
|
|
4
|
+
* Reorders the top-level AND conjuncts of a FilterNode predicate so the
|
|
5
|
+
* emitter's conjunct early exit (runtime/emit/filter.ts) skips expensive
|
|
6
|
+
* conjuncts for every row an earlier conjunct already rejects. The sort key is
|
|
7
|
+
* `compareConjunctRank` (`cost/conjunct-cost.ts`): cost tier first, then —
|
|
8
|
+
* within a tier — estimated filtering bought per unit work,
|
|
9
|
+
* `(1 - selectivity) / cost` descending, with plain subtree cost breaking
|
|
10
|
+
* ratio ties.
|
|
11
|
+
*
|
|
12
|
+
* Selectivity comes from the shared per-conjunct estimator
|
|
13
|
+
* (`stats/conjunct-selectivity.ts`), gated on `statsOnlySelectivity` — real
|
|
14
|
+
* statistics only, never the NaiveStatsProvider's fabricated per-nodeType
|
|
15
|
+
* guess, whose numbers differ BY NODE KIND and would reorder conjuncts on no
|
|
16
|
+
* information at all. When no conjunct gets a real estimate the rule sorts
|
|
17
|
+
* with `compareConjunctCost` verbatim — an explicit branch, so a query with no
|
|
18
|
+
* ANALYZE'd statistics orders bit-identically to the cost-only rule.
|
|
19
|
+
*
|
|
20
|
+
* Soundness: SQL AND is commutative under three-valued logic, and a Filter
|
|
21
|
+
* rejects on both `false` and `NULL`, so any permutation of the conjuncts
|
|
22
|
+
* keeps the row set identical. Reordering changes only evaluation COUNTS,
|
|
23
|
+
* which is why the rule refuses when any conjunct's subtree carries a side
|
|
24
|
+
* effect.
|
|
25
|
+
*
|
|
26
|
+
* NOTE (tripwire): "row set identical" is a claim about VALUES, not about
|
|
27
|
+
* thrown errors. A conjunct written after a guard (`v <> 0 and 10 / v > 1`)
|
|
28
|
+
* may run on rows the guard would have rejected once it sorts ahead of the
|
|
29
|
+
* guard. Harmless today — every arithmetic edge quereus defines returns NULL
|
|
30
|
+
* rather than throwing (division by zero included, pinned in
|
|
31
|
+
* test/logic/07.7.4-where-conjunct-ordering.sqllogic), and a cheap guard
|
|
32
|
+
* already sorts first. It only becomes real if a scalar function that THROWS
|
|
33
|
+
* on bad input ships and a query guards it with a conjunct in a more expensive
|
|
34
|
+
* tier (e.g. `exists (...) and parse(x) > 0`). Selectivity adds a SECOND route
|
|
35
|
+
* past a guard: a statistics-strong conjunct can now sort ahead of a cheaper
|
|
36
|
+
* same-tier guard even where cost alone would have kept the guard first. At
|
|
37
|
+
* that point either gate the reorder on a per-function "may raise" trait or
|
|
38
|
+
* tell users to guard with CASE, as PostgreSQL does.
|
|
39
|
+
*/
|
|
40
|
+
import type { PlanNode } from '../../nodes/plan-node.js';
|
|
41
|
+
import type { OptContext } from '../../framework/context.js';
|
|
42
|
+
export declare function ruleFilterConjunctOrdering(node: PlanNode, context: OptContext): PlanNode | null;
|
|
43
|
+
//# sourceMappingURL=rule-filter-conjunct-ordering.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rule-filter-conjunct-ordering.d.ts","sourceRoot":"","sources":["../../../../../src/planner/rules/predicate/rule-filter-conjunct-ordering.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAAkB,MAAM,0BAA0B,CAAC;AACzE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAc7D,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,GAAG,QAAQ,GAAG,IAAI,CA8C/F"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rule: Filter Conjunct Ordering
|
|
3
|
+
*
|
|
4
|
+
* Reorders the top-level AND conjuncts of a FilterNode predicate so the
|
|
5
|
+
* emitter's conjunct early exit (runtime/emit/filter.ts) skips expensive
|
|
6
|
+
* conjuncts for every row an earlier conjunct already rejects. The sort key is
|
|
7
|
+
* `compareConjunctRank` (`cost/conjunct-cost.ts`): cost tier first, then —
|
|
8
|
+
* within a tier — estimated filtering bought per unit work,
|
|
9
|
+
* `(1 - selectivity) / cost` descending, with plain subtree cost breaking
|
|
10
|
+
* ratio ties.
|
|
11
|
+
*
|
|
12
|
+
* Selectivity comes from the shared per-conjunct estimator
|
|
13
|
+
* (`stats/conjunct-selectivity.ts`), gated on `statsOnlySelectivity` — real
|
|
14
|
+
* statistics only, never the NaiveStatsProvider's fabricated per-nodeType
|
|
15
|
+
* guess, whose numbers differ BY NODE KIND and would reorder conjuncts on no
|
|
16
|
+
* information at all. When no conjunct gets a real estimate the rule sorts
|
|
17
|
+
* with `compareConjunctCost` verbatim — an explicit branch, so a query with no
|
|
18
|
+
* ANALYZE'd statistics orders bit-identically to the cost-only rule.
|
|
19
|
+
*
|
|
20
|
+
* Soundness: SQL AND is commutative under three-valued logic, and a Filter
|
|
21
|
+
* rejects on both `false` and `NULL`, so any permutation of the conjuncts
|
|
22
|
+
* keeps the row set identical. Reordering changes only evaluation COUNTS,
|
|
23
|
+
* which is why the rule refuses when any conjunct's subtree carries a side
|
|
24
|
+
* effect.
|
|
25
|
+
*
|
|
26
|
+
* NOTE (tripwire): "row set identical" is a claim about VALUES, not about
|
|
27
|
+
* thrown errors. A conjunct written after a guard (`v <> 0 and 10 / v > 1`)
|
|
28
|
+
* may run on rows the guard would have rejected once it sorts ahead of the
|
|
29
|
+
* guard. Harmless today — every arithmetic edge quereus defines returns NULL
|
|
30
|
+
* rather than throwing (division by zero included, pinned in
|
|
31
|
+
* test/logic/07.7.4-where-conjunct-ordering.sqllogic), and a cheap guard
|
|
32
|
+
* already sorts first. It only becomes real if a scalar function that THROWS
|
|
33
|
+
* on bad input ships and a query guards it with a conjunct in a more expensive
|
|
34
|
+
* tier (e.g. `exists (...) and parse(x) > 0`). Selectivity adds a SECOND route
|
|
35
|
+
* past a guard: a statistics-strong conjunct can now sort ahead of a cheaper
|
|
36
|
+
* same-tier guard even where cost alone would have kept the guard first. At
|
|
37
|
+
* that point either gate the reorder on a per-function "may raise" trait or
|
|
38
|
+
* tell users to guard with CASE, as PostgreSQL does.
|
|
39
|
+
*/
|
|
40
|
+
import { createLogger } from '../../../common/logger.js';
|
|
41
|
+
import { PlanNodeType } from '../../nodes/plan-node-type.js';
|
|
42
|
+
import { FilterNode } from '../../nodes/filter.js';
|
|
43
|
+
import { PlanNodeCharacteristics } from '../../framework/characteristics.js';
|
|
44
|
+
import { splitConjuncts, combineConjuncts } from '../../analysis/predicate-conjuncts.js';
|
|
45
|
+
import { classifyConjunctCost, compareConjunctCost, compareConjunctRank, UNKNOWN_CONJUNCT_SELECTIVITY, } from '../../cost/conjunct-cost.js';
|
|
46
|
+
import { collectColumnOrigins } from '../../util/column-origins.js';
|
|
47
|
+
import { estimateConjunctSelectivity } from '../../stats/conjunct-selectivity.js';
|
|
48
|
+
const log = createLogger('optimizer:rule:filter-conjunct-ordering');
|
|
49
|
+
export function ruleFilterConjunctOrdering(node, context) {
|
|
50
|
+
if (node.nodeType !== PlanNodeType.Filter)
|
|
51
|
+
return null;
|
|
52
|
+
const filter = node;
|
|
53
|
+
const conjuncts = splitConjuncts(filter.predicate);
|
|
54
|
+
if (conjuncts.length < 2)
|
|
55
|
+
return null;
|
|
56
|
+
// Predicates are pure today, but reordering under early exit changes how
|
|
57
|
+
// often each conjunct runs — refuse outright when any conjunct carries a
|
|
58
|
+
// side effect. This guard is what makes sideEffectMode 'safe' honest.
|
|
59
|
+
if (conjuncts.some(c => PlanNodeCharacteristics.subtreeHasSideEffects(c)))
|
|
60
|
+
return null;
|
|
61
|
+
const costs = conjuncts.map(classifyConjunctCost);
|
|
62
|
+
const selectivities = estimateSelectivities(filter, conjuncts, context);
|
|
63
|
+
// Array.prototype.sort is stable, so equal-key conjuncts keep source order —
|
|
64
|
+
// the determinism requirement.
|
|
65
|
+
let sorted;
|
|
66
|
+
if (selectivities === undefined) {
|
|
67
|
+
// No conjunct got a real estimate (or the provider has none to give):
|
|
68
|
+
// sort with the cost-only comparator verbatim, so the order is
|
|
69
|
+
// bit-identical to the pre-selectivity rule.
|
|
70
|
+
const ranked = conjuncts.map((conjunct, i) => ({ conjunct, cost: costs[i] }));
|
|
71
|
+
sorted = [...ranked].sort((a, b) => compareConjunctCost(a.cost, b.cost));
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
const ranked = conjuncts.map((conjunct, i) => ({
|
|
75
|
+
conjunct,
|
|
76
|
+
cost: { ...costs[i], selectivity: selectivities[i] ?? UNKNOWN_CONJUNCT_SELECTIVITY },
|
|
77
|
+
}));
|
|
78
|
+
sorted = [...ranked].sort((a, b) => compareConjunctRank(a.cost, b.cost));
|
|
79
|
+
}
|
|
80
|
+
// Already ordered → null. This is not an optimization: it is the fixed point
|
|
81
|
+
// that stops the rewrite loop (an unconditional rebuild would flip conjunct
|
|
82
|
+
// order forever). The key depends only on the node and on `context.stats`,
|
|
83
|
+
// which is stable within one optimize(), so the sort is idempotent.
|
|
84
|
+
if (sorted.every((entry, i) => entry.conjunct === conjuncts[i]))
|
|
85
|
+
return null;
|
|
86
|
+
// length >= 2, so combineConjuncts cannot return null.
|
|
87
|
+
const reordered = combineConjuncts(sorted.map(entry => entry.conjunct));
|
|
88
|
+
log(`Reordered ${conjuncts.length} conjuncts (${selectivities === undefined ? 'cost only' : 'cost + selectivity'})`);
|
|
89
|
+
// Construct directly rather than via withPredicate (which drops selectivity
|
|
90
|
+
// on any predicate change): reordering does not change the conjunct SET, so
|
|
91
|
+
// the estimate stamped by rule-filter-selectivity remains exactly as valid.
|
|
92
|
+
return new FilterNode(filter.scope, filter.source, reordered, undefined, filter.selectivity);
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Per-conjunct selectivities aligned with `conjuncts`, or undefined when the
|
|
96
|
+
* whole filter must fall back to cost-only ordering: the provider implements no
|
|
97
|
+
* `statsOnlySelectivity`, the source exposes no base-column origins (HAVING over
|
|
98
|
+
* an aggregate, a set operation, a `values` clause, …), or no conjunct could be
|
|
99
|
+
* estimated. The provider check comes first so the origins walk — a full pass
|
|
100
|
+
* over the source subtree — is skipped outright for a provider that omits the
|
|
101
|
+
* method.
|
|
102
|
+
*
|
|
103
|
+
* NOTE (tripwire): that short-circuit does NOT help the production
|
|
104
|
+
* `CatalogStatsProvider`, which always implements `statsOnlySelectivity`. A
|
|
105
|
+
* database with nothing ANALYZEd therefore still pays one origins walk per
|
|
106
|
+
* multi-conjunct Filter here, on top of the one `rule-filter-selectivity`
|
|
107
|
+
* already pays. Unmeasured; if it ever profiles hot, memoize the map per pass on
|
|
108
|
+
* OptContext keyed by the source node — the fix noted at that rule.
|
|
109
|
+
*/
|
|
110
|
+
function estimateSelectivities(filter, conjuncts, context) {
|
|
111
|
+
if (context.stats.statsOnlySelectivity == null)
|
|
112
|
+
return undefined;
|
|
113
|
+
const origins = collectColumnOrigins(filter.source);
|
|
114
|
+
if (origins.size === 0)
|
|
115
|
+
return undefined;
|
|
116
|
+
const estimates = conjuncts.map(c => estimateConjunctSelectivity(c, origins, context));
|
|
117
|
+
return estimates.some(e => e !== undefined) ? estimates : undefined;
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=rule-filter-conjunct-ordering.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rule-filter-conjunct-ordering.js","sourceRoot":"","sources":["../../../../../src/planner/rules/predicate/rule-filter-conjunct-ordering.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,14 +4,55 @@
|
|
|
4
4
|
* Stamps a stats-derived selectivity onto a FilterNode so its `estimatedRows`
|
|
5
5
|
* reflects real column statistics instead of the flat DEFAULT_FILTER_SELECTIVITY.
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
7
|
+
* Registered TWICE, both bottom-up:
|
|
8
|
+
*
|
|
9
|
+
* - `filter-selectivity` (Physical pass), which fires AFTER the Structural pass —
|
|
10
|
+
* predicate-pushdown / grow-retrieve have already put the Filter in its final
|
|
11
|
+
* position over its final source, so the source subtree is settled (and may carry
|
|
12
|
+
* physical access nodes between the join and its table references). This stamp is
|
|
13
|
+
* what the physical and PostOptimization cost readers consult.
|
|
14
|
+
* - `filter-selectivity-restamp` (PostOptimization pass, registered first in that
|
|
15
|
+
* pass), which recovers the estimate for a Filter whose stamp was dropped by
|
|
16
|
+
* `FilterNode.withChildren` because PostOptimization rewrote something inside its
|
|
17
|
+
* predicate — `scalar-subquery-cache` wrapping an uncorrelated scalar subquery's
|
|
18
|
+
* inner re-mints every scalar ancestor up to the predicate. Without it, any query
|
|
19
|
+
* with a subquery in its `where` plans on the flat DEFAULT_FILTER_SELECTIVITY.
|
|
20
|
+
*
|
|
21
|
+
* The `selectivity !== undefined` guard below makes the second registration a no-op on
|
|
22
|
+
* every Filter whose stamp survived, so it only ever fills in, never overwrites. Both
|
|
23
|
+
* firings read a physical source subtree (`select-access-path` has already replaced
|
|
24
|
+
* Retrieve with an access node by the Physical pass's own bottom-up order);
|
|
25
|
+
* PostOptimization sources are the same shape or further lowered.
|
|
10
26
|
*
|
|
11
27
|
* Node-level accessors (`estimatedRows` / `computePhysical`) carry no OptContext,
|
|
12
28
|
* so a Filter cannot consult `context.stats` from inside itself. This rule holds
|
|
13
29
|
* the context, does the lookup, and mints a stamped Filter — the estimate then
|
|
14
30
|
* flows through `estimatedRows` automatically.
|
|
31
|
+
*
|
|
32
|
+
* Two paths:
|
|
33
|
+
* - **single-table** — `extractRowSourceTableSchema` finds one base table under
|
|
34
|
+
* the Filter *whose rows are the ones arriving at it*; hand the whole predicate
|
|
35
|
+
* to the provider, which decomposes its boolean structure itself.
|
|
36
|
+
* - **multi-relation** — the source spans several tables (a join), or the strict
|
|
37
|
+
* walk declined. Split the predicate into conjuncts, attribute each to the base
|
|
38
|
+
* table(s) its columns come from, estimate per conjunct, and combine.
|
|
39
|
+
*
|
|
40
|
+
* The strict walk matters because an aggregate's output rows are a different
|
|
41
|
+
* population from its source's, so no fraction of the base table describes them at
|
|
42
|
+
* all: over `select cat, count(*) as ct from o group by cat having ct > 2` the
|
|
43
|
+
* permissive `extractTableSchema` reaches `o` through the aggregate, but `o`'s row
|
|
44
|
+
* count and column distributions say nothing about how many GROUPS survive `ct > 2`.
|
|
45
|
+
*
|
|
46
|
+
* Both paths hand the provider a {@link ColumnStatsResolver} built from
|
|
47
|
+
* `collectColumnOrigins`, so a column in the predicate is matched to statistics by
|
|
48
|
+
* ATTRIBUTE IDENTITY rather than by the name in its AST. `ProjectNode` forwards the
|
|
49
|
+
* source attribute id for a bare column reference and mints a fresh one for a
|
|
50
|
+
* computed expression, which is exactly the distinction wanted: `select cat as qty`
|
|
51
|
+
* still reads `o.cat`'s statistics, while `select id * 7 as qty` reads none rather
|
|
52
|
+
* than borrowing `o.qty`'s because the alias happens to collide. A CTE reference
|
|
53
|
+
* republishes its body's columns under per-reference relation instances, so a `with`
|
|
54
|
+
* clause estimates like the equivalent subquery while the two arms of a CTE self-join
|
|
55
|
+
* still count as two relations — see `column-origins.ts`.
|
|
15
56
|
*/
|
|
16
57
|
import type { PlanNode } from '../../nodes/plan-node.js';
|
|
17
58
|
import type { OptContext } from '../../framework/context.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rule-filter-selectivity.d.ts","sourceRoot":"","sources":["../../../../../src/planner/rules/predicate/rule-filter-selectivity.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"rule-filter-selectivity.d.ts","sourceRoot":"","sources":["../../../../../src/planner/rules/predicate/rule-filter-selectivity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuDG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAW7D,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,GAAG,QAAQ,GAAG,IAAI,CAwC1F"}
|