@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
|
@@ -4,18 +4,63 @@
|
|
|
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 { createLogger } from '../../../common/logger.js';
|
|
17
58
|
import { FilterNode } from '../../nodes/filter.js';
|
|
18
|
-
import {
|
|
59
|
+
import { extractRowSourceTableSchema } from '../../util/key-utils.js';
|
|
60
|
+
import { collectColumnOrigins } from '../../util/column-origins.js';
|
|
61
|
+
import { splitConjuncts } from '../../analysis/predicate-conjuncts.js';
|
|
62
|
+
import { combineConjunctive } from '../../stats/selectivity-combine.js';
|
|
63
|
+
import { estimateConjunctSelectivity, makeColumnStatsResolver } from '../../stats/conjunct-selectivity.js';
|
|
19
64
|
const log = createLogger('optimizer:rule:filter-selectivity');
|
|
20
65
|
export function ruleFilterSelectivity(node, context) {
|
|
21
66
|
const filter = node;
|
|
@@ -24,25 +69,104 @@ export function ruleFilterSelectivity(node, context) {
|
|
|
24
69
|
// makes the rule safe on any already-stamped node regardless.)
|
|
25
70
|
if (filter.selectivity !== undefined)
|
|
26
71
|
return null;
|
|
27
|
-
//
|
|
28
|
-
// TableReference) to the base table
|
|
29
|
-
//
|
|
30
|
-
//
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
//
|
|
35
|
-
//
|
|
36
|
-
//
|
|
37
|
-
//
|
|
38
|
-
//
|
|
39
|
-
|
|
72
|
+
// extractRowSourceTableSchema walks single-child wrappers (Filter/Project/Sort/
|
|
73
|
+
// Retrieve/TableReference) to the base table, but stops at any operator whose
|
|
74
|
+
// output rows are not its source's rows (aggregate, recursive CTE, set operation).
|
|
75
|
+
// It returns undefined for those and for a join / other multi-relation source,
|
|
76
|
+
// which is what the second path handles.
|
|
77
|
+
const tableSchema = extractRowSourceTableSchema(filter.source);
|
|
78
|
+
// Attribute id → base-table column, for every base column under the Filter. Both
|
|
79
|
+
// paths need it: the multi-relation path to route a conjunct to a relation, and
|
|
80
|
+
// both paths to identify a predicate's columns by identity rather than by name.
|
|
81
|
+
//
|
|
82
|
+
// NOTE: this walk covers the whole source subtree and this rule fires per
|
|
83
|
+
// FilterNode, so a stack of N filters over one large subtree costs O(N·subtree) —
|
|
84
|
+
// and unlike before, it now runs for EVERY Filter, not only filters over joins.
|
|
85
|
+
// `rule-filter-conjunct-ordering` (PostOptimization) runs the SAME walk again on
|
|
86
|
+
// each Filter it ranks, so the walk now happens twice per Filter. The walk is
|
|
87
|
+
// cheap per node and filter stacks are shallow; if it ever shows up in an
|
|
88
|
+
// optimizer profile, memoize the map per pass on OptContext keyed by the source
|
|
89
|
+
// node (or — for the single-table path only — build the resolver from the one
|
|
90
|
+
// TableReferenceNode the strict walk already found, O(columns) not O(subtree)).
|
|
91
|
+
const origins = collectColumnOrigins(filter.source);
|
|
92
|
+
const sel = tableSchema
|
|
93
|
+
? singleTableSelectivity(tableSchema, filter, origins, context)
|
|
94
|
+
: multiRelationSelectivity(filter, origins, context);
|
|
40
95
|
if (sel === undefined)
|
|
41
96
|
return null;
|
|
42
97
|
const clamped = Math.min(1, Math.max(0, sel));
|
|
43
|
-
log('Filter over %s: stamping selectivity %f', tableSchema.name, clamped);
|
|
44
98
|
// Rebuild the identical Filter (same scope, source, predicate → same output
|
|
45
99
|
// attribute ids) with only the added estimate — hence sideEffectMode 'safe'.
|
|
46
100
|
return new FilterNode(filter.scope, filter.source, filter.predicate, undefined, clamped);
|
|
47
101
|
}
|
|
102
|
+
// ── Single-table path ───────────────────────────────────────────────────
|
|
103
|
+
function singleTableSelectivity(tableSchema, filter, origins, context) {
|
|
104
|
+
// CatalogStatsProvider recurses over the predicate's boolean structure, so
|
|
105
|
+
// `a = 1 and b = 2` combines the two per-column estimates rather than falling
|
|
106
|
+
// back to a flat per-nodeType guess. It still returns undefined when it can say
|
|
107
|
+
// nothing at all, in which case the naive heuristic applies as before.
|
|
108
|
+
//
|
|
109
|
+
// NOTE: this path is deliberately NOT gated on real statistics existing — it may
|
|
110
|
+
// still stamp a NaiveStatsProvider number, as it always has. The multi-relation
|
|
111
|
+
// path below IS gated; see the comment there for why the asymmetry is on purpose.
|
|
112
|
+
//
|
|
113
|
+
// Schema equality is the right narrowing here: the strict walk established that
|
|
114
|
+
// exactly this table's rows arrive at the Filter, so any origin under it belongs
|
|
115
|
+
// to that one reference anyway.
|
|
116
|
+
const resolve = makeColumnStatsResolver(origins, origin => origin.table === tableSchema);
|
|
117
|
+
const sel = context.stats.selectivity(tableSchema, filter.predicate, resolve);
|
|
118
|
+
if (sel === undefined)
|
|
119
|
+
return undefined;
|
|
120
|
+
log('Filter over %s: stamping selectivity %f', tableSchema.name, sel);
|
|
121
|
+
return sel;
|
|
122
|
+
}
|
|
123
|
+
// ── Multi-relation path ─────────────────────────────────────────────────
|
|
124
|
+
/**
|
|
125
|
+
* Estimate a filter whose source spans several base tables by attributing each
|
|
126
|
+
* conjunct to the relation(s) its columns come from.
|
|
127
|
+
*
|
|
128
|
+
* NOTE: join type is ignored. A `left`/`right`/`full` join emits NULL-extended
|
|
129
|
+
* rows, which makes a predicate on the non-preserved side more selective than the
|
|
130
|
+
* base-table fraction suggests and one on the preserved side less so. Applying the
|
|
131
|
+
* base-table fraction either way is the conventional simplification, not an
|
|
132
|
+
* oversight.
|
|
133
|
+
*
|
|
134
|
+
* NOTE: an `aggregate` between the Filter and the join forwards group-key attribute
|
|
135
|
+
* ids unchanged, so a predicate on a group key is attributed to its base table and
|
|
136
|
+
* the base-table fraction is applied to post-aggregate cardinality. Imprecise but
|
|
137
|
+
* not unsound; deliberately not special-cased.
|
|
138
|
+
*
|
|
139
|
+
* NOTE: the stamped number does move `estimatedRows` above a join — the join family
|
|
140
|
+
* derives its physical cardinality from its children's PHYSICAL counts
|
|
141
|
+
* (`physicalSourceRows` / `joinPhysicalRows`), so a Filter over a join has a real
|
|
142
|
+
* number to multiply. It still has nothing to multiply above a `union`/`union all`,
|
|
143
|
+
* where `SetOperationNode` stamps no count at all (backlog
|
|
144
|
+
* `debt-row-estimates-die-at-set-operations`).
|
|
145
|
+
*/
|
|
146
|
+
function multiRelationSelectivity(filter, origins, context) {
|
|
147
|
+
if (origins.size === 0)
|
|
148
|
+
return undefined;
|
|
149
|
+
const conjuncts = splitConjuncts(filter.predicate);
|
|
150
|
+
const known = [];
|
|
151
|
+
for (const conjunct of conjuncts) {
|
|
152
|
+
const sel = estimateConjunctSelectivity(conjunct, origins, context);
|
|
153
|
+
if (sel !== undefined)
|
|
154
|
+
known.push(sel);
|
|
155
|
+
}
|
|
156
|
+
// Nothing estimable → leave the Filter unstamped exactly as before this path existed.
|
|
157
|
+
if (known.length === 0)
|
|
158
|
+
return undefined;
|
|
159
|
+
const combined = combineConjunctive(known);
|
|
160
|
+
// countRelations walks the whole origin map; keep it off the hot path.
|
|
161
|
+
if (log.enabled) {
|
|
162
|
+
log('Filter over %d relations: %d/%d conjuncts estimated, stamping %f', countRelations(origins), known.length, conjuncts.length, combined);
|
|
163
|
+
}
|
|
164
|
+
return combined;
|
|
165
|
+
}
|
|
166
|
+
function countRelations(origins) {
|
|
167
|
+
const relations = new Set();
|
|
168
|
+
for (const origin of origins.values())
|
|
169
|
+
relations.add(origin.relation);
|
|
170
|
+
return relations.size;
|
|
171
|
+
}
|
|
48
172
|
//# sourceMappingURL=rule-filter-selectivity.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rule-filter-selectivity.js","sourceRoot":"","sources":["../../../../../src/planner/rules/predicate/rule-filter-selectivity.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"rule-filter-selectivity.js","sourceRoot":"","sources":["../../../../../src/planner/rules/predicate/rule-filter-selectivity.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rule: Join Predicate Pushdown
|
|
3
|
+
*
|
|
4
|
+
* For a `FilterNode(predicate, JoinNode)`, each conjunct of `predicate` whose
|
|
5
|
+
* column references all land on ONE side of the join is MOVED onto that side's
|
|
6
|
+
* branch (wrapped as a `FilterNode` around `join.left` / `join.right`).
|
|
7
|
+
* Cross-side conjuncts, and anything the refusals below reject, stay in a
|
|
8
|
+
* residual Filter above the rebuilt join.
|
|
9
|
+
*
|
|
10
|
+
* Why this is sound — the null-extension argument. A side may receive a
|
|
11
|
+
* conjunct exactly when that side's columns are NEVER null-extended in the
|
|
12
|
+
* join's output (read straight off `buildJoinAttributes` in
|
|
13
|
+
* `nodes/join-utils.ts`). For such a side, every output row carries that side's
|
|
14
|
+
* genuine input values, so rejecting an input row before the join removes
|
|
15
|
+
* precisely the output rows the conjunct would have removed after it. On a
|
|
16
|
+
* null-extended side the two differ: `left join r … where r.date > 'x'` drops
|
|
17
|
+
* the NULL-padded rows after the join, but pushing `r.date > 'x'` below would
|
|
18
|
+
* KEEP them (the left row simply finds no match and is padded again).
|
|
19
|
+
*
|
|
20
|
+
* | joinType | null-extended side | conjuncts pushable to |
|
|
21
|
+
* |----------|--------------------|-----------------------|
|
|
22
|
+
* | `inner` | neither | left and right |
|
|
23
|
+
* | `cross` | neither | left and right |
|
|
24
|
+
* | `left` | right | left only |
|
|
25
|
+
* | `right` | left | right only |
|
|
26
|
+
* | `full` | both | neither — rule declines |
|
|
27
|
+
* | `semi` | n/a (output is left columns) | left only |
|
|
28
|
+
* | `anti` | n/a (output is left columns) | left only |
|
|
29
|
+
*
|
|
30
|
+
* For `semi`/`anti` the left-only restriction is moot in practice —
|
|
31
|
+
* `buildJoinAttributes` returns only the left attributes, so a Filter above such
|
|
32
|
+
* a join cannot reference a right column at all — but it is encoded anyway so
|
|
33
|
+
* the table is exhaustive and the reasoning stays local.
|
|
34
|
+
*
|
|
35
|
+
* Attribution is a plain attribute-id set test: ids are minted per node instance
|
|
36
|
+
* and are stable across this pass's rewrites, so a self-join's two branches
|
|
37
|
+
* carry distinct ids, and a join's `exists … as` flag ids are in neither side's
|
|
38
|
+
* set (a conjunct over a flag falls out as un-pushable with no special case).
|
|
39
|
+
*
|
|
40
|
+
* Refusals:
|
|
41
|
+
* - A conjunct whose subtree references a RELATIONAL child (any subquery) is
|
|
42
|
+
* left above. The id collector descends through relational children too, so
|
|
43
|
+
* `exists (select 1 from x where x.a = e.id and x.b = t.id)` contributes `x`'s
|
|
44
|
+
* own ids — which belong to neither side — and the conjunct is declined. That
|
|
45
|
+
* descent is load-bearing: a scalar-only walk would see only `e.id` and push a
|
|
46
|
+
* conjunct onto the left branch where `t.id` does not resolve.
|
|
47
|
+
* - Symmetrically, a conjunct naming a column from OUTSIDE the join — an outer
|
|
48
|
+
* reference, when this `Filter(Join)` is itself the body of a correlated
|
|
49
|
+
* subquery — sees an id in neither side's set and is declined.
|
|
50
|
+
* NOTE: sound but pessimistic — `x.a = <outer>.b` would be safe on the `x`
|
|
51
|
+
* branch. Ignoring "in neither side" ids instead of refusing on them would
|
|
52
|
+
* recover that, but only after separating a genuinely-outer id from a
|
|
53
|
+
* subquery-internal one, which this walk does not currently distinguish.
|
|
54
|
+
* Left alone until a real correlated body is measured losing a seek to it.
|
|
55
|
+
* - A conjunct with NO column references (`where 1 = 1`, `where :p > 0`) stays
|
|
56
|
+
* above; pushing it buys nothing and would make the rule fire on plans it
|
|
57
|
+
* should leave alone.
|
|
58
|
+
* - A non-functional conjunct (`random() < e.amount`) stays above — moving it
|
|
59
|
+
* below the join changes how many times it is evaluated.
|
|
60
|
+
* - A branch whose subtree carries a write keeps ITS conjuncts above while the
|
|
61
|
+
* other branch still receives its own (per-branch refusal, unlike
|
|
62
|
+
* `rule-predicate-inference-equivalence`'s outright one).
|
|
63
|
+
*
|
|
64
|
+
* A pushed conjunct is MOVED, not copied. A redundant copy above would
|
|
65
|
+
* re-evaluate per output row for no gain and, worse, make the rule
|
|
66
|
+
* non-idempotent — it would find the same pushable conjunct on every visit.
|
|
67
|
+
* With a move, a re-visit of the residual Filter finds nothing pushable and
|
|
68
|
+
* returns null, which is the termination argument.
|
|
69
|
+
*/
|
|
70
|
+
import type { PlanNode } from '../../nodes/plan-node.js';
|
|
71
|
+
import type { OptContext } from '../../framework/context.js';
|
|
72
|
+
export declare function ruleJoinPredicatePushdown(node: PlanNode, _context: OptContext): PlanNode | null;
|
|
73
|
+
//# sourceMappingURL=rule-join-predicate-pushdown.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rule-join-predicate-pushdown.d.ts","sourceRoot":"","sources":["../../../../../src/planner/rules/predicate/rule-join-predicate-pushdown.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoEG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAAsC,MAAM,0BAA0B,CAAC;AAC7F,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAyE7D,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,GAAG,QAAQ,GAAG,IAAI,CA0E/F"}
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rule: Join Predicate Pushdown
|
|
3
|
+
*
|
|
4
|
+
* For a `FilterNode(predicate, JoinNode)`, each conjunct of `predicate` whose
|
|
5
|
+
* column references all land on ONE side of the join is MOVED onto that side's
|
|
6
|
+
* branch (wrapped as a `FilterNode` around `join.left` / `join.right`).
|
|
7
|
+
* Cross-side conjuncts, and anything the refusals below reject, stay in a
|
|
8
|
+
* residual Filter above the rebuilt join.
|
|
9
|
+
*
|
|
10
|
+
* Why this is sound — the null-extension argument. A side may receive a
|
|
11
|
+
* conjunct exactly when that side's columns are NEVER null-extended in the
|
|
12
|
+
* join's output (read straight off `buildJoinAttributes` in
|
|
13
|
+
* `nodes/join-utils.ts`). For such a side, every output row carries that side's
|
|
14
|
+
* genuine input values, so rejecting an input row before the join removes
|
|
15
|
+
* precisely the output rows the conjunct would have removed after it. On a
|
|
16
|
+
* null-extended side the two differ: `left join r … where r.date > 'x'` drops
|
|
17
|
+
* the NULL-padded rows after the join, but pushing `r.date > 'x'` below would
|
|
18
|
+
* KEEP them (the left row simply finds no match and is padded again).
|
|
19
|
+
*
|
|
20
|
+
* | joinType | null-extended side | conjuncts pushable to |
|
|
21
|
+
* |----------|--------------------|-----------------------|
|
|
22
|
+
* | `inner` | neither | left and right |
|
|
23
|
+
* | `cross` | neither | left and right |
|
|
24
|
+
* | `left` | right | left only |
|
|
25
|
+
* | `right` | left | right only |
|
|
26
|
+
* | `full` | both | neither — rule declines |
|
|
27
|
+
* | `semi` | n/a (output is left columns) | left only |
|
|
28
|
+
* | `anti` | n/a (output is left columns) | left only |
|
|
29
|
+
*
|
|
30
|
+
* For `semi`/`anti` the left-only restriction is moot in practice —
|
|
31
|
+
* `buildJoinAttributes` returns only the left attributes, so a Filter above such
|
|
32
|
+
* a join cannot reference a right column at all — but it is encoded anyway so
|
|
33
|
+
* the table is exhaustive and the reasoning stays local.
|
|
34
|
+
*
|
|
35
|
+
* Attribution is a plain attribute-id set test: ids are minted per node instance
|
|
36
|
+
* and are stable across this pass's rewrites, so a self-join's two branches
|
|
37
|
+
* carry distinct ids, and a join's `exists … as` flag ids are in neither side's
|
|
38
|
+
* set (a conjunct over a flag falls out as un-pushable with no special case).
|
|
39
|
+
*
|
|
40
|
+
* Refusals:
|
|
41
|
+
* - A conjunct whose subtree references a RELATIONAL child (any subquery) is
|
|
42
|
+
* left above. The id collector descends through relational children too, so
|
|
43
|
+
* `exists (select 1 from x where x.a = e.id and x.b = t.id)` contributes `x`'s
|
|
44
|
+
* own ids — which belong to neither side — and the conjunct is declined. That
|
|
45
|
+
* descent is load-bearing: a scalar-only walk would see only `e.id` and push a
|
|
46
|
+
* conjunct onto the left branch where `t.id` does not resolve.
|
|
47
|
+
* - Symmetrically, a conjunct naming a column from OUTSIDE the join — an outer
|
|
48
|
+
* reference, when this `Filter(Join)` is itself the body of a correlated
|
|
49
|
+
* subquery — sees an id in neither side's set and is declined.
|
|
50
|
+
* NOTE: sound but pessimistic — `x.a = <outer>.b` would be safe on the `x`
|
|
51
|
+
* branch. Ignoring "in neither side" ids instead of refusing on them would
|
|
52
|
+
* recover that, but only after separating a genuinely-outer id from a
|
|
53
|
+
* subquery-internal one, which this walk does not currently distinguish.
|
|
54
|
+
* Left alone until a real correlated body is measured losing a seek to it.
|
|
55
|
+
* - A conjunct with NO column references (`where 1 = 1`, `where :p > 0`) stays
|
|
56
|
+
* above; pushing it buys nothing and would make the rule fire on plans it
|
|
57
|
+
* should leave alone.
|
|
58
|
+
* - A non-functional conjunct (`random() < e.amount`) stays above — moving it
|
|
59
|
+
* below the join changes how many times it is evaluated.
|
|
60
|
+
* - A branch whose subtree carries a write keeps ITS conjuncts above while the
|
|
61
|
+
* other branch still receives its own (per-branch refusal, unlike
|
|
62
|
+
* `rule-predicate-inference-equivalence`'s outright one).
|
|
63
|
+
*
|
|
64
|
+
* A pushed conjunct is MOVED, not copied. A redundant copy above would
|
|
65
|
+
* re-evaluate per output row for no gain and, worse, make the rule
|
|
66
|
+
* non-idempotent — it would find the same pushable conjunct on every visit.
|
|
67
|
+
* With a move, a re-visit of the residual Filter finds nothing pushable and
|
|
68
|
+
* returns null, which is the termination argument.
|
|
69
|
+
*/
|
|
70
|
+
import { createLogger } from '../../../common/logger.js';
|
|
71
|
+
import { PlanNodeType } from '../../nodes/plan-node-type.js';
|
|
72
|
+
import { FilterNode } from '../../nodes/filter.js';
|
|
73
|
+
import { JoinNode } from '../../nodes/join-node.js';
|
|
74
|
+
import { ColumnReferenceNode } from '../../nodes/reference.js';
|
|
75
|
+
import { normalizePredicate } from '../../analysis/predicate-normalizer.js';
|
|
76
|
+
import { splitConjuncts, combineConjuncts } from '../../analysis/predicate-conjuncts.js';
|
|
77
|
+
import { PlanNodeCharacteristics } from '../../framework/characteristics.js';
|
|
78
|
+
const log = createLogger('optimizer:rule:join-predicate-pushdown');
|
|
79
|
+
/** The sides of `joinType` that are never null-extended in the output — see the header table. */
|
|
80
|
+
function pushableSides(joinType) {
|
|
81
|
+
switch (joinType) {
|
|
82
|
+
case 'inner':
|
|
83
|
+
case 'cross':
|
|
84
|
+
return new Set(['left', 'right']);
|
|
85
|
+
case 'left':
|
|
86
|
+
case 'semi':
|
|
87
|
+
case 'anti':
|
|
88
|
+
return new Set(['left']);
|
|
89
|
+
case 'right':
|
|
90
|
+
return new Set(['right']);
|
|
91
|
+
case 'full':
|
|
92
|
+
return new Set();
|
|
93
|
+
default:
|
|
94
|
+
return new Set();
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Every attribute id any `ColumnReferenceNode` in `expr`'s WHOLE subtree names —
|
|
99
|
+
* descending through relational children as well as scalar ones. See the
|
|
100
|
+
* file-header refusal notes for why the relational descent is required.
|
|
101
|
+
*/
|
|
102
|
+
function collectSubtreeAttributeIds(expr) {
|
|
103
|
+
const ids = new Set();
|
|
104
|
+
// Iterative worklist so a deep predicate cannot overflow the native stack.
|
|
105
|
+
const stack = [expr];
|
|
106
|
+
while (stack.length > 0) {
|
|
107
|
+
const current = stack.pop();
|
|
108
|
+
if (current instanceof ColumnReferenceNode) {
|
|
109
|
+
ids.add(current.attributeId);
|
|
110
|
+
}
|
|
111
|
+
for (const child of current.getChildren()) {
|
|
112
|
+
stack.push(child);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return ids;
|
|
116
|
+
}
|
|
117
|
+
/** The single side `ids` lands entirely on, or null when it spans / escapes both. */
|
|
118
|
+
function attributeSide(ids, leftIds, rightIds) {
|
|
119
|
+
let allLeft = true;
|
|
120
|
+
let allRight = true;
|
|
121
|
+
for (const id of ids) {
|
|
122
|
+
if (!leftIds.has(id))
|
|
123
|
+
allLeft = false;
|
|
124
|
+
if (!rightIds.has(id))
|
|
125
|
+
allRight = false;
|
|
126
|
+
if (!allLeft && !allRight)
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
// A self-join mints distinct ids per branch, so the two sets are disjoint and
|
|
130
|
+
// a non-empty `ids` can satisfy at most one of these.
|
|
131
|
+
if (allLeft)
|
|
132
|
+
return 'left';
|
|
133
|
+
if (allRight)
|
|
134
|
+
return 'right';
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
export function ruleJoinPredicatePushdown(node, _context) {
|
|
138
|
+
if (node.nodeType !== PlanNodeType.Filter)
|
|
139
|
+
return null;
|
|
140
|
+
const filter = node;
|
|
141
|
+
const join = filter.source;
|
|
142
|
+
if (!(join instanceof JoinNode))
|
|
143
|
+
return null;
|
|
144
|
+
const sides = pushableSides(join.joinType);
|
|
145
|
+
if (sides.size === 0)
|
|
146
|
+
return null;
|
|
147
|
+
const leftIds = new Set(join.left.getAttributes().map(a => a.id));
|
|
148
|
+
const rightIds = new Set(join.right.getAttributes().map(a => a.id));
|
|
149
|
+
const conjuncts = splitConjuncts(normalizePredicate(filter.predicate));
|
|
150
|
+
let leftPush = [];
|
|
151
|
+
let rightPush = [];
|
|
152
|
+
const residual = [];
|
|
153
|
+
for (const conj of conjuncts) {
|
|
154
|
+
const ids = collectSubtreeAttributeIds(conj);
|
|
155
|
+
// No column reference at all (`1 = 1`, `:p > 0`): nothing to gain below.
|
|
156
|
+
if (ids.size === 0) {
|
|
157
|
+
residual.push(conj);
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
// Non-deterministic / write-bearing conjunct: moving it changes how many
|
|
161
|
+
// times it is evaluated.
|
|
162
|
+
if (!PlanNodeCharacteristics.isFunctional(conj)) {
|
|
163
|
+
residual.push(conj);
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
const side = attributeSide(ids, leftIds, rightIds);
|
|
167
|
+
if (side === null || !sides.has(side)) {
|
|
168
|
+
residual.push(conj);
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
(side === 'left' ? leftPush : rightPush).push(conj);
|
|
172
|
+
}
|
|
173
|
+
// Per-branch side-effect refusal: a branch carrying a write keeps its own
|
|
174
|
+
// conjuncts above while the other branch still receives its.
|
|
175
|
+
if (leftPush.length > 0 && PlanNodeCharacteristics.subtreeHasSideEffects(join.left)) {
|
|
176
|
+
log('join-predicate-pushdown: left branch has side effects; keeping its conjuncts above');
|
|
177
|
+
residual.push(...leftPush);
|
|
178
|
+
leftPush = [];
|
|
179
|
+
}
|
|
180
|
+
if (rightPush.length > 0 && PlanNodeCharacteristics.subtreeHasSideEffects(join.right)) {
|
|
181
|
+
log('join-predicate-pushdown: right branch has side effects; keeping its conjuncts above');
|
|
182
|
+
residual.push(...rightPush);
|
|
183
|
+
rightPush = [];
|
|
184
|
+
}
|
|
185
|
+
if (leftPush.length === 0 && rightPush.length === 0)
|
|
186
|
+
return null;
|
|
187
|
+
const newLeft = leftPush.length > 0
|
|
188
|
+
? new FilterNode(join.left.scope, join.left, combineConjuncts(leftPush))
|
|
189
|
+
: join.left;
|
|
190
|
+
const newRight = rightPush.length > 0
|
|
191
|
+
? new FilterNode(join.right.scope, join.right, combineConjuncts(rightPush))
|
|
192
|
+
: join.right;
|
|
193
|
+
// `withChildren` (not `new JoinNode(...)`) so `existence` and `usingColumns`
|
|
194
|
+
// thread through — a dropped existence spec strands every upstream reference
|
|
195
|
+
// to the flag's attribute id.
|
|
196
|
+
const newChildren = join.condition
|
|
197
|
+
? [newLeft, newRight, join.condition]
|
|
198
|
+
: [newLeft, newRight];
|
|
199
|
+
const newJoin = join.withChildren(newChildren);
|
|
200
|
+
log('Pushed %d left + %d right conjunct(s) below %s join (%d residual)', leftPush.length, rightPush.length, join.joinType, residual.length);
|
|
201
|
+
if (residual.length === 0)
|
|
202
|
+
return newJoin;
|
|
203
|
+
return new FilterNode(filter.scope, newJoin, combineConjuncts(residual));
|
|
204
|
+
}
|
|
205
|
+
//# sourceMappingURL=rule-join-predicate-pushdown.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rule-join-predicate-pushdown.js","sourceRoot":"","sources":["../../../../../src/planner/rules/predicate/rule-join-predicate-pushdown.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoEG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAGzD,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,EAAE,QAAQ,EAAiB,MAAM,0BAA0B,CAAC;AACnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,kBAAkB,EAAE,MAAM,wCAAwC,CAAC;AAC5E,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,uCAAuC,CAAC;AACzF,OAAO,EAAE,uBAAuB,EAAE,MAAM,oCAAoC,CAAC;AAE7E,MAAM,GAAG,GAAG,YAAY,CAAC,wCAAwC,CAAC,CAAC;AAInE,iGAAiG;AACjG,SAAS,aAAa,CAAC,QAAkB;IACxC,QAAQ,QAAQ,EAAE,CAAC;QAClB,KAAK,OAAO,CAAC;QACb,KAAK,OAAO;YACX,OAAO,IAAI,GAAG,CAAW,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;QAC7C,KAAK,MAAM,CAAC;QACZ,KAAK,MAAM,CAAC;QACZ,KAAK,MAAM;YACV,OAAO,IAAI,GAAG,CAAW,CAAC,MAAM,CAAC,CAAC,CAAC;QACpC,KAAK,OAAO;YACX,OAAO,IAAI,GAAG,CAAW,CAAC,OAAO,CAAC,CAAC,CAAC;QACrC,KAAK,MAAM;YACV,OAAO,IAAI,GAAG,EAAY,CAAC;QAC5B;YACC,OAAO,IAAI,GAAG,EAAY,CAAC;IAC7B,CAAC;AACF,CAAC;AAED;;;;GAIG;AACH,SAAS,0BAA0B,CAAC,IAAoB;IACvD,MAAM,GAAG,GAAG,IAAI,GAAG,EAAU,CAAC;IAC9B,2EAA2E;IAC3E,MAAM,KAAK,GAAe,CAAC,IAAI,CAAC,CAAC;IACjC,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACzB,MAAM,OAAO,GAAG,KAAK,CAAC,GAAG,EAAG,CAAC;QAC7B,IAAI,OAAO,YAAY,mBAAmB,EAAE,CAAC;YAC5C,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;QAC9B,CAAC;QACD,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC;YAC3C,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACnB,CAAC;IACF,CAAC;IACD,OAAO,GAAG,CAAC;AACZ,CAAC;AAED,qFAAqF;AACrF,SAAS,aAAa,CACrB,GAAwB,EACxB,OAA4B,EAC5B,QAA6B;IAE7B,IAAI,OAAO,GAAG,IAAI,CAAC;IACnB,IAAI,QAAQ,GAAG,IAAI,CAAC;IACpB,KAAK,MAAM,EAAE,IAAI,GAAG,EAAE,CAAC;QACtB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;YAAE,OAAO,GAAG,KAAK,CAAC;QACtC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YAAE,QAAQ,GAAG,KAAK,CAAC;QACxC,IAAI,CAAC,OAAO,IAAI,CAAC,QAAQ;YAAE,OAAO,IAAI,CAAC;IACxC,CAAC;IACD,8EAA8E;IAC9E,sDAAsD;IACtD,IAAI,OAAO;QAAE,OAAO,MAAM,CAAC;IAC3B,IAAI,QAAQ;QAAE,OAAO,OAAO,CAAC;IAC7B,OAAO,IAAI,CAAC;AACb,CAAC;AAED,MAAM,UAAU,yBAAyB,CAAC,IAAc,EAAE,QAAoB;IAC7E,IAAI,IAAI,CAAC,QAAQ,KAAK,YAAY,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IACvD,MAAM,MAAM,GAAG,IAAkB,CAAC;IAClC,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC;IAC3B,IAAI,CAAC,CAAC,IAAI,YAAY,QAAQ,CAAC;QAAE,OAAO,IAAI,CAAC;IAE7C,MAAM,KAAK,GAAG,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC3C,IAAI,KAAK,CAAC,IAAI,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAElC,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAClE,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,aAAa,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAEpE,MAAM,SAAS,GAAG,cAAc,CAAC,kBAAkB,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC;IAEvE,IAAI,QAAQ,GAAqB,EAAE,CAAC;IACpC,IAAI,SAAS,GAAqB,EAAE,CAAC;IACrC,MAAM,QAAQ,GAAqB,EAAE,CAAC;IAEtC,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;QAC9B,MAAM,GAAG,GAAG,0BAA0B,CAAC,IAAI,CAAC,CAAC;QAC7C,yEAAyE;QACzE,IAAI,GAAG,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YACpB,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACpB,SAAS;QACV,CAAC;QACD,yEAAyE;QACzE,yBAAyB;QACzB,IAAI,CAAC,uBAAuB,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC;YACjD,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACpB,SAAS;QACV,CAAC;QACD,MAAM,IAAI,GAAG,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;QACnD,IAAI,IAAI,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YACvC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACpB,SAAS;QACV,CAAC;QACD,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACrD,CAAC;IAED,0EAA0E;IAC1E,6DAA6D;IAC7D,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,IAAI,uBAAuB,CAAC,qBAAqB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QACrF,GAAG,CAAC,oFAAoF,CAAC,CAAC;QAC1F,QAAQ,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,CAAC;QAC3B,QAAQ,GAAG,EAAE,CAAC;IACf,CAAC;IACD,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,IAAI,uBAAuB,CAAC,qBAAqB,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QACvF,GAAG,CAAC,qFAAqF,CAAC,CAAC;QAC3F,QAAQ,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,CAAC;QAC5B,SAAS,GAAG,EAAE,CAAC;IAChB,CAAC;IAED,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAEjE,MAAM,OAAO,GAAuB,QAAQ,CAAC,MAAM,GAAG,CAAC;QACtD,CAAC,CAAC,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,IAAI,EAAE,gBAAgB,CAAC,QAAQ,CAAE,CAAC;QACzE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;IACb,MAAM,QAAQ,GAAuB,SAAS,CAAC,MAAM,GAAG,CAAC;QACxD,CAAC,CAAC,IAAI,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,gBAAgB,CAAC,SAAS,CAAE,CAAC;QAC5E,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC;IAEd,6EAA6E;IAC7E,6EAA6E;IAC7E,8BAA8B;IAC9B,MAAM,WAAW,GAAe,IAAI,CAAC,SAAS;QAC7C,CAAC,CAAC,CAAC,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC;QACrC,CAAC,CAAC,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IACvB,MAAM,OAAO,GAAG,IAAI,CAAC,YAAY,CAAC,WAAW,CAAuB,CAAC;IAErE,GAAG,CAAC,mEAAmE,EACtE,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC,MAAM,EAAE,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAEpE,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,OAAO,CAAC;IAC1C,OAAO,IAAI,UAAU,CAAC,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,gBAAgB,CAAC,QAAQ,CAAE,CAAC,CAAC;AAC3E,CAAC"}
|
|
@@ -15,14 +15,17 @@
|
|
|
15
15
|
* `col = value` conjunct.
|
|
16
16
|
* - AND the new conjuncts into the filter predicate.
|
|
17
17
|
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
18
|
+
* Getting the inferred conjunct onto the branch is NOT this rule's job.
|
|
19
|
+
* `rule-join-predicate-pushdown` (registered immediately after this one, so it
|
|
20
|
+
* fires on this rule's own output within the same node visit) moves every
|
|
21
|
+
* single-side conjunct of the augmented predicate — original and inferred alike —
|
|
22
|
+
* onto the branch it constrains, and `rule-predicate-pushdown` then carries it
|
|
23
|
+
* across that branch's Alias into its Retrieve. This rule used to inject those
|
|
24
|
+
* branch Filters itself, back when no rule could cross a join; doing both now
|
|
25
|
+
* materializes the same conjunct twice on one branch (`u.k = 5 AND u.k = 5`), so
|
|
26
|
+
* the injection was removed rather than duplicated. Disabling
|
|
27
|
+
* `join-predicate-pushdown` therefore also stops inferred conjuncts from reaching
|
|
28
|
+
* a branch — they still land in the Filter above the join.
|
|
26
29
|
*
|
|
27
30
|
* Fixpoint guard: the rule's emission set is `{otherIdx ∈ EC | otherIdx
|
|
28
31
|
* is not already in predBoundIdx}`. On a second invocation the
|
|
@@ -33,10 +36,10 @@
|
|
|
33
36
|
* Safety:
|
|
34
37
|
* - LEFT/RIGHT/FULL joins: per `propagateJoinFds`, NULL-padded sides drop
|
|
35
38
|
* their bindings/ECs, so the EC visible at the filter's source is
|
|
36
|
-
* restricted to the preserved side
|
|
37
|
-
*
|
|
39
|
+
* restricted to the preserved side — no conjunct over a null-extended
|
|
40
|
+
* side can be inferred here in the first place.
|
|
38
41
|
* - SEMI/ANTI: only the left side is in the output; no right inference
|
|
39
|
-
* can arise here.
|
|
42
|
+
* can arise here.
|
|
40
43
|
*
|
|
41
44
|
* See ticket `3-rule-predicate-inference-equivalence` for the full design.
|
|
42
45
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rule-predicate-inference-equivalence.d.ts","sourceRoot":"","sources":["../../../../../src/planner/rules/predicate/rule-predicate-inference-equivalence.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"rule-predicate-inference-equivalence.d.ts","sourceRoot":"","sources":["../../../../../src/planner/rules/predicate/rule-predicate-inference-equivalence.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AAGH,OAAO,KAAK,EAAE,UAAU,IAAI,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAW5E,wBAAgB,iCAAiC,CAAC,IAAI,EAAE,OAAO,0BAA0B,EAAE,QAAQ,EAAE,QAAQ,EAAE,WAAW,GAAG,OAAO,0BAA0B,EAAE,QAAQ,GAAG,IAAI,CAuD9K"}
|