@quereus/quereus 0.1.0 → 0.2.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 +47 -23
- package/dist/src/core/database.d.ts +22 -4
- package/dist/src/core/database.d.ts.map +1 -1
- package/dist/src/core/database.js +44 -6
- package/dist/src/core/database.js.map +1 -1
- package/dist/src/core/statement.d.ts +0 -7
- package/dist/src/core/statement.d.ts.map +1 -1
- package/dist/src/core/statement.js +1 -51
- package/dist/src/core/statement.js.map +1 -1
- package/dist/src/func/builtins/explain.d.ts.map +1 -1
- package/dist/src/func/builtins/explain.js +0 -11
- package/dist/src/func/builtins/explain.js.map +1 -1
- package/dist/src/index.d.ts +13 -5
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +5 -2
- package/dist/src/index.js.map +1 -1
- package/dist/src/parser/ast.d.ts +9 -2
- package/dist/src/parser/ast.d.ts.map +1 -1
- package/dist/src/parser/parser.d.ts.map +1 -1
- package/dist/src/parser/parser.js +40 -44
- package/dist/src/parser/parser.js.map +1 -1
- package/dist/src/planner/analysis/const-pass.d.ts.map +1 -1
- package/dist/src/planner/analysis/const-pass.js +12 -6
- package/dist/src/planner/analysis/const-pass.js.map +1 -1
- package/dist/src/planner/building/constraint-builder.d.ts +11 -0
- package/dist/src/planner/building/constraint-builder.d.ts.map +1 -0
- package/dist/src/planner/building/constraint-builder.js +79 -0
- package/dist/src/planner/building/constraint-builder.js.map +1 -0
- package/dist/src/planner/building/delete.d.ts.map +1 -1
- package/dist/src/planner/building/delete.js +6 -3
- package/dist/src/planner/building/delete.js.map +1 -1
- package/dist/src/planner/building/expression.d.ts +3 -0
- package/dist/src/planner/building/expression.d.ts.map +1 -1
- package/dist/src/planner/building/expression.js +33 -7
- package/dist/src/planner/building/expression.js.map +1 -1
- package/dist/src/planner/building/insert.d.ts.map +1 -1
- package/dist/src/planner/building/insert.js +4 -1
- package/dist/src/planner/building/insert.js.map +1 -1
- package/dist/src/planner/building/select-aggregates.d.ts.map +1 -1
- package/dist/src/planner/building/select-aggregates.js +46 -9
- package/dist/src/planner/building/select-aggregates.js.map +1 -1
- package/dist/src/planner/building/select-context.js +20 -11
- package/dist/src/planner/building/select-context.js.map +1 -1
- package/dist/src/planner/building/select-modifiers.d.ts +5 -3
- package/dist/src/planner/building/select-modifiers.d.ts.map +1 -1
- package/dist/src/planner/building/select-modifiers.js +29 -20
- package/dist/src/planner/building/select-modifiers.js.map +1 -1
- package/dist/src/planner/building/select-projections.d.ts +3 -1
- package/dist/src/planner/building/select-projections.d.ts.map +1 -1
- package/dist/src/planner/building/select-projections.js +15 -20
- package/dist/src/planner/building/select-projections.js.map +1 -1
- package/dist/src/planner/building/select-window.d.ts.map +1 -1
- package/dist/src/planner/building/select-window.js +6 -3
- package/dist/src/planner/building/select-window.js.map +1 -1
- package/dist/src/planner/building/select.d.ts +25 -2
- package/dist/src/planner/building/select.d.ts.map +1 -1
- package/dist/src/planner/building/select.js +147 -24
- package/dist/src/planner/building/select.js.map +1 -1
- package/dist/src/planner/building/table.d.ts +0 -10
- package/dist/src/planner/building/table.d.ts.map +1 -1
- package/dist/src/planner/building/table.js +1 -35
- package/dist/src/planner/building/table.js.map +1 -1
- package/dist/src/planner/building/update.d.ts.map +1 -1
- package/dist/src/planner/building/update.js +7 -4
- package/dist/src/planner/building/update.js.map +1 -1
- package/dist/src/planner/building/with.d.ts.map +1 -1
- package/dist/src/planner/building/with.js +7 -8
- package/dist/src/planner/building/with.js.map +1 -1
- package/dist/src/planner/cache/correlation-detector.d.ts +11 -0
- package/dist/src/planner/cache/correlation-detector.d.ts.map +1 -0
- package/dist/src/planner/cache/correlation-detector.js +73 -0
- package/dist/src/planner/cache/correlation-detector.js.map +1 -0
- package/dist/src/planner/cache/materialization-advisory.d.ts +12 -18
- package/dist/src/planner/cache/materialization-advisory.d.ts.map +1 -1
- package/dist/src/planner/cache/materialization-advisory.js +65 -46
- package/dist/src/planner/cache/materialization-advisory.js.map +1 -1
- package/dist/src/planner/cache/reference-graph.d.ts +14 -9
- package/dist/src/planner/cache/reference-graph.d.ts.map +1 -1
- package/dist/src/planner/cache/reference-graph.js +93 -84
- package/dist/src/planner/cache/reference-graph.js.map +1 -1
- package/dist/src/planner/debug.d.ts +25 -0
- package/dist/src/planner/debug.d.ts.map +1 -1
- package/dist/src/planner/debug.js +127 -0
- package/dist/src/planner/debug.js.map +1 -1
- package/dist/src/planner/framework/context.d.ts +11 -0
- package/dist/src/planner/framework/context.d.ts.map +1 -1
- package/dist/src/planner/framework/context.js +25 -2
- package/dist/src/planner/framework/context.js.map +1 -1
- package/dist/src/planner/framework/registry.d.ts +3 -7
- package/dist/src/planner/framework/registry.d.ts.map +1 -1
- package/dist/src/planner/framework/registry.js +20 -31
- package/dist/src/planner/framework/registry.js.map +1 -1
- package/dist/src/planner/nodes/add-constraint-node.d.ts +2 -1
- package/dist/src/planner/nodes/add-constraint-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/add-constraint-node.js +3 -0
- package/dist/src/planner/nodes/add-constraint-node.js.map +1 -1
- package/dist/src/planner/nodes/aggregate-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/aggregate-node.js +6 -4
- package/dist/src/planner/nodes/aggregate-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 -2
- package/dist/src/planner/nodes/cache-node.js.map +1 -1
- package/dist/src/planner/nodes/constraint-check-node.d.ts +11 -4
- package/dist/src/planner/nodes/constraint-check-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/constraint-check-node.js +38 -12
- package/dist/src/planner/nodes/constraint-check-node.js.map +1 -1
- package/dist/src/planner/nodes/create-index-node.d.ts +2 -1
- package/dist/src/planner/nodes/create-index-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/create-index-node.js +3 -0
- package/dist/src/planner/nodes/create-index-node.js.map +1 -1
- package/dist/src/planner/nodes/create-table-node.d.ts +2 -1
- package/dist/src/planner/nodes/create-table-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/create-table-node.js +3 -0
- package/dist/src/planner/nodes/create-table-node.js.map +1 -1
- package/dist/src/planner/nodes/create-view-node.d.ts +2 -1
- package/dist/src/planner/nodes/create-view-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/create-view-node.js +3 -0
- package/dist/src/planner/nodes/create-view-node.js.map +1 -1
- package/dist/src/planner/nodes/cte-node.d.ts +1 -1
- package/dist/src/planner/nodes/cte-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/cte-node.js +33 -12
- package/dist/src/planner/nodes/cte-node.js.map +1 -1
- package/dist/src/planner/nodes/cte-reference-node.d.ts +18 -4
- package/dist/src/planner/nodes/cte-reference-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/cte-reference-node.js +40 -10
- package/dist/src/planner/nodes/cte-reference-node.js.map +1 -1
- package/dist/src/planner/nodes/delete-node.d.ts +4 -3
- package/dist/src/planner/nodes/delete-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/delete-node.js +20 -6
- package/dist/src/planner/nodes/delete-node.js.map +1 -1
- package/dist/src/planner/nodes/distinct-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/distinct-node.js +2 -2
- package/dist/src/planner/nodes/distinct-node.js.map +1 -1
- package/dist/src/planner/nodes/dml-executor-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/dml-executor-node.js +2 -2
- package/dist/src/planner/nodes/dml-executor-node.js.map +1 -1
- package/dist/src/planner/nodes/drop-table-node.d.ts +2 -1
- package/dist/src/planner/nodes/drop-table-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/drop-table-node.js +3 -0
- package/dist/src/planner/nodes/drop-table-node.js.map +1 -1
- package/dist/src/planner/nodes/drop-view-node.d.ts +2 -1
- package/dist/src/planner/nodes/drop-view-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/drop-view-node.js +3 -0
- package/dist/src/planner/nodes/drop-view-node.js.map +1 -1
- package/dist/src/planner/nodes/filter.d.ts.map +1 -1
- package/dist/src/planner/nodes/filter.js +3 -3
- package/dist/src/planner/nodes/filter.js.map +1 -1
- package/dist/src/planner/nodes/insert-node.d.ts +2 -1
- package/dist/src/planner/nodes/insert-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/insert-node.js +18 -5
- package/dist/src/planner/nodes/insert-node.js.map +1 -1
- package/dist/src/planner/nodes/internal-recursive-cte-ref-node.d.ts +28 -0
- package/dist/src/planner/nodes/internal-recursive-cte-ref-node.d.ts.map +1 -0
- package/dist/src/planner/nodes/internal-recursive-cte-ref-node.js +69 -0
- package/dist/src/planner/nodes/internal-recursive-cte-ref-node.js.map +1 -0
- package/dist/src/planner/nodes/join-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/join-node.js +3 -3
- package/dist/src/planner/nodes/join-node.js.map +1 -1
- package/dist/src/planner/nodes/limit-offset.d.ts.map +1 -1
- package/dist/src/planner/nodes/limit-offset.js +2 -2
- package/dist/src/planner/nodes/limit-offset.js.map +1 -1
- package/dist/src/planner/nodes/plan-node-type.d.ts +1 -1
- package/dist/src/planner/nodes/plan-node-type.d.ts.map +1 -1
- package/dist/src/planner/nodes/plan-node-type.js +1 -1
- package/dist/src/planner/nodes/plan-node-type.js.map +1 -1
- package/dist/src/planner/nodes/plan-node.d.ts +23 -0
- package/dist/src/planner/nodes/plan-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/plan-node.js +25 -2
- package/dist/src/planner/nodes/plan-node.js.map +1 -1
- package/dist/src/planner/nodes/project-node.d.ts +5 -1
- package/dist/src/planner/nodes/project-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/project-node.js +39 -20
- package/dist/src/planner/nodes/project-node.js.map +1 -1
- package/dist/src/planner/nodes/recursive-cte-node.d.ts +2 -2
- package/dist/src/planner/nodes/recursive-cte-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/recursive-cte-node.js +20 -8
- package/dist/src/planner/nodes/recursive-cte-node.js.map +1 -1
- package/dist/src/planner/nodes/reference.d.ts.map +1 -1
- package/dist/src/planner/nodes/reference.js +4 -2
- package/dist/src/planner/nodes/reference.js.map +1 -1
- package/dist/src/planner/nodes/returning-node.d.ts +1 -1
- package/dist/src/planner/nodes/returning-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/returning-node.js +21 -13
- package/dist/src/planner/nodes/returning-node.js.map +1 -1
- package/dist/src/planner/nodes/scalar.d.ts +26 -2
- package/dist/src/planner/nodes/scalar.d.ts.map +1 -1
- package/dist/src/planner/nodes/scalar.js +82 -10
- package/dist/src/planner/nodes/scalar.js.map +1 -1
- package/dist/src/planner/nodes/sequencing-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/sequencing-node.js +2 -2
- package/dist/src/planner/nodes/sequencing-node.js.map +1 -1
- package/dist/src/planner/nodes/set-operation-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/set-operation-node.js +3 -3
- package/dist/src/planner/nodes/set-operation-node.js.map +1 -1
- package/dist/src/planner/nodes/single-row.d.ts +4 -2
- package/dist/src/planner/nodes/single-row.d.ts.map +1 -1
- package/dist/src/planner/nodes/single-row.js +3 -0
- package/dist/src/planner/nodes/single-row.js.map +1 -1
- package/dist/src/planner/nodes/sink-node.d.ts +1 -1
- package/dist/src/planner/nodes/sink-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/sink-node.js +4 -4
- package/dist/src/planner/nodes/sink-node.js.map +1 -1
- package/dist/src/planner/nodes/sort.d.ts.map +1 -1
- package/dist/src/planner/nodes/sort.js +2 -2
- package/dist/src/planner/nodes/sort.js.map +1 -1
- package/dist/src/planner/nodes/stream-aggregate.d.ts +1 -0
- package/dist/src/planner/nodes/stream-aggregate.d.ts.map +1 -1
- package/dist/src/planner/nodes/stream-aggregate.js +64 -11
- package/dist/src/planner/nodes/stream-aggregate.js.map +1 -1
- package/dist/src/planner/nodes/subquery.d.ts +4 -4
- package/dist/src/planner/nodes/subquery.d.ts.map +1 -1
- package/dist/src/planner/nodes/subquery.js +68 -23
- package/dist/src/planner/nodes/subquery.js.map +1 -1
- package/dist/src/planner/nodes/table-access-nodes.d.ts +83 -0
- package/dist/src/planner/nodes/table-access-nodes.d.ts.map +1 -0
- package/dist/src/planner/nodes/table-access-nodes.js +226 -0
- package/dist/src/planner/nodes/table-access-nodes.js.map +1 -0
- package/dist/src/planner/nodes/update-node.d.ts +4 -2
- package/dist/src/planner/nodes/update-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/update-node.js +26 -13
- package/dist/src/planner/nodes/update-node.js.map +1 -1
- package/dist/src/planner/nodes/window-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/window-node.js +25 -23
- package/dist/src/planner/nodes/window-node.js.map +1 -1
- package/dist/src/planner/optimizer.d.ts.map +1 -1
- package/dist/src/planner/optimizer.js +46 -50
- package/dist/src/planner/optimizer.js.map +1 -1
- package/dist/src/planner/planning-context.d.ts +13 -0
- package/dist/src/planner/planning-context.d.ts.map +1 -1
- package/dist/src/planner/planning-context.js.map +1 -1
- package/dist/src/planner/rules/access/rule-select-access-path.d.ts +1 -1
- package/dist/src/planner/rules/access/rule-select-access-path.d.ts.map +1 -1
- package/dist/src/planner/rules/access/rule-select-access-path.js +59 -53
- package/dist/src/planner/rules/access/rule-select-access-path.js.map +1 -1
- package/dist/src/planner/rules/aggregate/rule-aggregate-streaming.d.ts.map +1 -1
- package/dist/src/planner/rules/aggregate/rule-aggregate-streaming.js +62 -2
- package/dist/src/planner/rules/aggregate/rule-aggregate-streaming.js.map +1 -1
- package/dist/src/planner/rules/cache/rule-materialization-advisory.d.ts.map +1 -1
- package/dist/src/planner/rules/cache/rule-materialization-advisory.js +31 -24
- package/dist/src/planner/rules/cache/rule-materialization-advisory.js.map +1 -1
- package/dist/src/planner/scopes/base.d.ts +0 -10
- package/dist/src/planner/scopes/base.d.ts.map +1 -1
- package/dist/src/planner/scopes/base.js +0 -14
- package/dist/src/planner/scopes/base.js.map +1 -1
- package/dist/src/planner/scopes/empty.d.ts +0 -2
- package/dist/src/planner/scopes/empty.d.ts.map +1 -1
- package/dist/src/planner/scopes/empty.js +0 -8
- package/dist/src/planner/scopes/empty.js.map +1 -1
- package/dist/src/planner/scopes/multi.d.ts.map +1 -1
- package/dist/src/planner/scopes/multi.js +0 -1
- package/dist/src/planner/scopes/multi.js.map +1 -1
- package/dist/src/planner/scopes/param.d.ts.map +1 -1
- package/dist/src/planner/scopes/param.js +0 -1
- package/dist/src/planner/scopes/param.js.map +1 -1
- package/dist/src/planner/scopes/registered.d.ts +0 -10
- package/dist/src/planner/scopes/registered.d.ts.map +1 -1
- package/dist/src/planner/scopes/registered.js +1 -17
- package/dist/src/planner/scopes/registered.js.map +1 -1
- package/dist/src/planner/scopes/scope.d.ts +0 -8
- package/dist/src/planner/scopes/scope.d.ts.map +1 -1
- package/dist/src/planner/validation/plan-validator.d.ts.map +1 -1
- package/dist/src/planner/validation/plan-validator.js +1 -7
- package/dist/src/planner/validation/plan-validator.js.map +1 -1
- package/dist/src/runtime/context-helpers.d.ts +45 -0
- package/dist/src/runtime/context-helpers.d.ts.map +1 -0
- package/dist/src/runtime/context-helpers.js +139 -0
- package/dist/src/runtime/context-helpers.js.map +1 -0
- package/dist/src/runtime/emission-context.d.ts +1 -0
- package/dist/src/runtime/emission-context.d.ts.map +1 -1
- package/dist/src/runtime/emission-context.js +2 -1
- package/dist/src/runtime/emission-context.js.map +1 -1
- package/dist/src/runtime/emit/aggregate.d.ts.map +1 -1
- package/dist/src/runtime/emit/aggregate.js +119 -86
- package/dist/src/runtime/emit/aggregate.js.map +1 -1
- package/dist/src/runtime/emit/between.d.ts +5 -0
- package/dist/src/runtime/emit/between.d.ts.map +1 -0
- package/dist/src/runtime/emit/between.js +38 -0
- package/dist/src/runtime/emit/between.js.map +1 -0
- package/dist/src/runtime/emit/binary.d.ts +0 -1
- package/dist/src/runtime/emit/binary.d.ts.map +1 -1
- package/dist/src/runtime/emit/binary.js +0 -36
- package/dist/src/runtime/emit/binary.js.map +1 -1
- package/dist/src/runtime/emit/column-reference.d.ts.map +1 -1
- package/dist/src/runtime/emit/column-reference.js +2 -26
- package/dist/src/runtime/emit/column-reference.js.map +1 -1
- package/dist/src/runtime/emit/constraint-check.d.ts.map +1 -1
- package/dist/src/runtime/emit/constraint-check.js +14 -121
- package/dist/src/runtime/emit/constraint-check.js.map +1 -1
- package/dist/src/runtime/emit/cte-reference.d.ts.map +1 -1
- package/dist/src/runtime/emit/cte-reference.js +16 -48
- package/dist/src/runtime/emit/cte-reference.js.map +1 -1
- package/dist/src/runtime/emit/distinct.d.ts.map +1 -1
- package/dist/src/runtime/emit/distinct.js +2 -8
- package/dist/src/runtime/emit/distinct.js.map +1 -1
- package/dist/src/runtime/emit/filter.d.ts.map +1 -1
- package/dist/src/runtime/emit/filter.js +6 -13
- package/dist/src/runtime/emit/filter.js.map +1 -1
- package/dist/src/runtime/emit/internal-recursive-cte-ref.d.ts +5 -0
- package/dist/src/runtime/emit/internal-recursive-cte-ref.d.ts.map +1 -0
- package/dist/src/runtime/emit/internal-recursive-cte-ref.js +23 -0
- package/dist/src/runtime/emit/internal-recursive-cte-ref.js.map +1 -0
- package/dist/src/runtime/emit/join.d.ts.map +1 -1
- package/dist/src/runtime/emit/join.js +40 -40
- package/dist/src/runtime/emit/join.js.map +1 -1
- package/dist/src/runtime/emit/project.d.ts.map +1 -1
- package/dist/src/runtime/emit/project.js +13 -13
- package/dist/src/runtime/emit/project.js.map +1 -1
- package/dist/src/runtime/emit/recursive-cte.d.ts.map +1 -1
- package/dist/src/runtime/emit/recursive-cte.js +3 -14
- package/dist/src/runtime/emit/recursive-cte.js.map +1 -1
- package/dist/src/runtime/emit/returning.d.ts.map +1 -1
- package/dist/src/runtime/emit/returning.js +7 -14
- package/dist/src/runtime/emit/returning.js.map +1 -1
- package/dist/src/runtime/emit/scan.d.ts +5 -2
- package/dist/src/runtime/emit/scan.d.ts.map +1 -1
- package/dist/src/runtime/emit/scan.js +21 -17
- package/dist/src/runtime/emit/scan.js.map +1 -1
- package/dist/src/runtime/emit/sort.d.ts.map +1 -1
- package/dist/src/runtime/emit/sort.js +8 -11
- package/dist/src/runtime/emit/sort.js.map +1 -1
- package/dist/src/runtime/emit/subquery.d.ts.map +1 -1
- package/dist/src/runtime/emit/subquery.js +95 -40
- package/dist/src/runtime/emit/subquery.js.map +1 -1
- package/dist/src/runtime/emit/table-valued-function.d.ts.map +1 -1
- package/dist/src/runtime/emit/table-valued-function.js +7 -22
- package/dist/src/runtime/emit/table-valued-function.js.map +1 -1
- package/dist/src/runtime/emit/update.d.ts.map +1 -1
- package/dist/src/runtime/emit/update.js +20 -27
- package/dist/src/runtime/emit/update.js.map +1 -1
- package/dist/src/runtime/emit/window.d.ts.map +1 -1
- package/dist/src/runtime/emit/window.js +55 -83
- package/dist/src/runtime/emit/window.js.map +1 -1
- package/dist/src/runtime/emitters.d.ts.map +1 -1
- package/dist/src/runtime/emitters.js +49 -1
- package/dist/src/runtime/emitters.js.map +1 -1
- package/dist/src/runtime/register.d.ts.map +1 -1
- package/dist/src/runtime/register.js +5 -4
- package/dist/src/runtime/register.js.map +1 -1
- package/dist/src/runtime/scheduler.d.ts.map +1 -1
- package/dist/src/runtime/scheduler.js +47 -42
- package/dist/src/runtime/scheduler.js.map +1 -1
- package/dist/src/runtime/types.d.ts +34 -0
- package/dist/src/runtime/types.d.ts.map +1 -1
- package/dist/src/runtime/types.js +21 -0
- package/dist/src/runtime/types.js.map +1 -1
- package/dist/src/schema/manager.d.ts.map +1 -1
- package/dist/src/schema/manager.js +29 -16
- package/dist/src/schema/manager.js.map +1 -1
- package/dist/src/util/plugin-loader.d.ts +10 -1
- package/dist/src/util/plugin-loader.d.ts.map +1 -1
- package/dist/src/util/plugin-loader.js +56 -1
- package/dist/src/util/plugin-loader.js.map +1 -1
- package/dist/src/util/working-table-iterable.d.ts.map +1 -1
- package/dist/src/util/working-table-iterable.js +8 -8
- package/dist/src/util/working-table-iterable.js.map +1 -1
- package/dist/src/vtab/manifest.d.ts +36 -0
- package/dist/src/vtab/manifest.d.ts.map +1 -1
- package/package.json +8 -3
- package/src/core/database.ts +48 -6
- package/src/core/statement.ts +1 -49
- package/src/func/builtins/explain.ts +0 -11
- package/src/index.ts +39 -5
- package/src/parser/ast.ts +11 -2
- package/src/parser/parser.ts +40 -47
- package/src/planner/analysis/const-pass.ts +281 -270
- package/src/planner/building/constraint-builder.ts +114 -0
- package/src/planner/building/delete.ts +16 -3
- package/src/planner/building/expression.ts +35 -7
- package/src/planner/building/insert.ts +14 -1
- package/src/planner/building/select-aggregates.ts +57 -11
- package/src/planner/building/select-context.ts +22 -12
- package/src/planner/building/select-modifiers.ts +35 -21
- package/src/planner/building/select-projections.ts +25 -26
- package/src/planner/building/select-window.ts +14 -9
- package/src/planner/building/select.ts +163 -31
- package/src/planner/building/table.ts +1 -40
- package/src/planner/building/update.ts +19 -4
- package/src/planner/building/with.ts +12 -13
- package/src/planner/cache/correlation-detector.ts +83 -0
- package/src/planner/cache/materialization-advisory.ts +71 -50
- package/src/planner/cache/reference-graph.ts +115 -91
- package/src/planner/debug.ts +163 -0
- package/src/planner/framework/context.ts +36 -2
- package/src/planner/framework/registry.ts +261 -274
- package/src/planner/nodes/add-constraint-node.ts +5 -1
- package/src/planner/nodes/aggregate-node.ts +6 -4
- package/src/planner/nodes/cache-node.ts +2 -2
- package/src/planner/nodes/constraint-check-node.ts +47 -13
- package/src/planner/nodes/create-index-node.ts +5 -1
- package/src/planner/nodes/create-table-node.ts +5 -1
- package/src/planner/nodes/create-view-node.ts +5 -1
- package/src/planner/nodes/cte-node.ts +45 -14
- package/src/planner/nodes/cte-reference-node.ts +49 -13
- package/src/planner/nodes/delete-node.ts +31 -7
- package/src/planner/nodes/distinct-node.ts +2 -2
- package/src/planner/nodes/dml-executor-node.ts +2 -2
- package/src/planner/nodes/drop-table-node.ts +5 -1
- package/src/planner/nodes/drop-view-node.ts +5 -1
- package/src/planner/nodes/filter.ts +3 -3
- package/src/planner/nodes/function.ts +93 -93
- package/src/planner/nodes/insert-node.ts +28 -5
- package/src/planner/nodes/internal-recursive-cte-ref-node.ts +76 -0
- package/src/planner/nodes/join-node.ts +3 -3
- package/src/planner/nodes/limit-offset.ts +2 -2
- package/src/planner/nodes/plan-node-type.ts +1 -1
- package/src/planner/nodes/plan-node.ts +39 -2
- package/src/planner/nodes/project-node.ts +39 -19
- package/src/planner/nodes/recursive-cte-node.ts +37 -9
- package/src/planner/nodes/reference.ts +4 -2
- package/src/planner/nodes/returning-node.ts +25 -13
- package/src/planner/nodes/scalar.ts +95 -11
- package/src/planner/nodes/sequencing-node.ts +2 -2
- package/src/planner/nodes/set-operation-node.ts +3 -3
- package/src/planner/nodes/single-row.ts +7 -2
- package/src/planner/nodes/sink-node.ts +5 -5
- package/src/planner/nodes/sort.ts +2 -2
- package/src/planner/nodes/stream-aggregate.ts +76 -12
- package/src/planner/nodes/subquery.ts +90 -27
- package/src/planner/nodes/{physical-access-nodes.ts → table-access-nodes.ts} +6 -6
- package/src/planner/nodes/update-node.ts +31 -13
- package/src/planner/nodes/window-node.ts +28 -22
- package/src/planner/optimizer.ts +257 -263
- package/src/planner/planning-context.ts +15 -0
- package/src/planner/rules/access/rule-select-access-path.ts +68 -64
- package/src/planner/rules/aggregate/rule-aggregate-streaming.ts +74 -2
- package/src/planner/rules/cache/rule-materialization-advisory.ts +31 -27
- package/src/planner/scopes/base.ts +0 -17
- package/src/planner/scopes/empty.ts +0 -10
- package/src/planner/scopes/multi.ts +0 -1
- package/src/planner/scopes/param.ts +0 -1
- package/src/planner/scopes/registered.ts +1 -20
- package/src/planner/scopes/scope.ts +0 -12
- package/src/planner/validation/plan-validator.ts +1 -8
- package/src/runtime/context-helpers.ts +191 -0
- package/src/runtime/emission-context.ts +5 -2
- package/src/runtime/emit/aggregate.ts +131 -85
- package/src/runtime/emit/between.ts +51 -0
- package/src/runtime/emit/binary.ts +0 -46
- package/src/runtime/emit/column-reference.ts +3 -36
- package/src/runtime/emit/constraint-check.ts +17 -142
- package/src/runtime/emit/cte-reference.ts +23 -60
- package/src/runtime/emit/distinct.ts +2 -7
- package/src/runtime/emit/filter.ts +6 -13
- package/src/runtime/emit/internal-recursive-cte-ref.ts +37 -0
- package/src/runtime/emit/join.ts +45 -43
- package/src/runtime/emit/project.ts +18 -12
- package/src/runtime/emit/recursive-cte.ts +3 -12
- package/src/runtime/emit/returning.ts +7 -14
- package/src/runtime/emit/scan.ts +25 -23
- package/src/runtime/emit/sort.ts +8 -11
- package/src/runtime/emit/subquery.ts +108 -48
- package/src/runtime/emit/table-valued-function.ts +7 -20
- package/src/runtime/emit/update.ts +22 -29
- package/src/runtime/emit/window.ts +74 -88
- package/src/runtime/emitters.ts +52 -1
- package/src/runtime/register.ts +5 -4
- package/src/runtime/scheduler.ts +54 -54
- package/src/runtime/types.ts +45 -0
- package/src/schema/manager.ts +34 -19
- package/src/util/plugin-loader.ts +78 -4
- package/src/util/working-table-iterable.ts +15 -7
- package/src/vtab/manifest.ts +42 -0
- package/src/planner/nodes/scan.ts +0 -103
- package/src/planner/rules/physical/rule-mark-physical.ts +0 -37
- package/src/runtime/emit/table-reference.ts +0 -92
|
@@ -4,11 +4,12 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { createLogger } from '../../common/logger.js';
|
|
7
|
-
import type
|
|
7
|
+
import { isRelationalNode, type PlanNode, type RelationalPlanNode } from '../nodes/plan-node.js';
|
|
8
8
|
import { CacheNode, type CacheStrategy } from '../nodes/cache-node.js';
|
|
9
9
|
import { PlanNodeType } from '../nodes/plan-node-type.js';
|
|
10
10
|
import type { OptimizerTuning } from '../optimizer-tuning.js';
|
|
11
11
|
import { ReferenceGraphBuilder, type RefStats } from './reference-graph.js';
|
|
12
|
+
import { isCorrelatedSubquery } from './correlation-detector.js';
|
|
12
13
|
|
|
13
14
|
const log = createLogger('optimizer:cache:materialization');
|
|
14
15
|
|
|
@@ -37,34 +38,38 @@ export class MaterializationAdvisory {
|
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
/**
|
|
40
|
-
* Analyze a plan tree and
|
|
41
|
+
* Analyze a plan tree and inject caching where beneficial
|
|
42
|
+
* Returns the transformed tree or the original if no caching was added
|
|
41
43
|
*/
|
|
42
|
-
|
|
44
|
+
analyzeAndTransform(root: PlanNode): PlanNode {
|
|
45
|
+
// Build reference graph
|
|
43
46
|
const refGraph = this.referenceBuilder.buildReferenceGraph(root);
|
|
47
|
+
|
|
48
|
+
// Build recommendations
|
|
44
49
|
const recommendations = new Map<PlanNode, CacheRecommendation>();
|
|
45
50
|
|
|
46
51
|
for (const [node, stats] of refGraph) {
|
|
47
52
|
// Only consider relational nodes for caching
|
|
48
|
-
if (!
|
|
53
|
+
if (!isRelationalNode(node)) {
|
|
49
54
|
continue;
|
|
50
55
|
}
|
|
51
56
|
|
|
52
57
|
const recommendation = this.adviseCaching(node, stats);
|
|
53
|
-
recommendations.set(node, recommendation);
|
|
54
|
-
|
|
55
58
|
if (recommendation.shouldCache) {
|
|
59
|
+
recommendations.set(node, recommendation);
|
|
56
60
|
log('Recommending cache for %s: %s', node.nodeType, recommendation.reason);
|
|
57
61
|
}
|
|
58
62
|
}
|
|
59
63
|
|
|
60
|
-
|
|
61
|
-
|
|
64
|
+
if (recommendations.size === 0) {
|
|
65
|
+
log('No caching opportunities identified');
|
|
66
|
+
return root;
|
|
67
|
+
}
|
|
62
68
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
return this.transformNode(root, recommendations);
|
|
69
|
+
log('Found %d caching opportunities', recommendations.size);
|
|
70
|
+
|
|
71
|
+
// Transform the tree by wrapping recommended nodes with CacheNode
|
|
72
|
+
return this.transformTree(root, recommendations);
|
|
68
73
|
}
|
|
69
74
|
|
|
70
75
|
/**
|
|
@@ -91,7 +96,18 @@ export class MaterializationAdvisory {
|
|
|
91
96
|
};
|
|
92
97
|
}
|
|
93
98
|
|
|
94
|
-
// Rule 3:
|
|
99
|
+
// Rule 3: Correlated subqueries should not be cached
|
|
100
|
+
// Check if this node is part of a subquery context and if it's correlated
|
|
101
|
+
if (isRelationalNode(node) && this.isCorrelatedNode(node)) {
|
|
102
|
+
return {
|
|
103
|
+
shouldCache: false,
|
|
104
|
+
strategy: 'memory',
|
|
105
|
+
threshold: 0,
|
|
106
|
+
reason: 'Correlated subquery - must re-execute for each outer row'
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Rule 4: Single-parent nodes that don't appear in loops typically don't benefit from caching
|
|
95
111
|
if (stats.parentCount <= 1 && !stats.appearsInLoop) {
|
|
96
112
|
return {
|
|
97
113
|
shouldCache: false,
|
|
@@ -101,7 +117,7 @@ export class MaterializationAdvisory {
|
|
|
101
117
|
};
|
|
102
118
|
}
|
|
103
119
|
|
|
104
|
-
// Rule
|
|
120
|
+
// Rule 5: Multi-parent nodes benefit from caching
|
|
105
121
|
if (stats.parentCount > 1) {
|
|
106
122
|
const strategy = this.selectStrategy(stats.estimatedRows);
|
|
107
123
|
const threshold = this.calculateThreshold(stats.estimatedRows, strategy);
|
|
@@ -114,7 +130,7 @@ export class MaterializationAdvisory {
|
|
|
114
130
|
};
|
|
115
131
|
}
|
|
116
132
|
|
|
117
|
-
// Rule
|
|
133
|
+
// Rule 6: Nodes in loop contexts benefit from caching even with single parent
|
|
118
134
|
if (stats.appearsInLoop) {
|
|
119
135
|
// Check if the estimated size is reasonable for caching
|
|
120
136
|
if (stats.estimatedRows > this.tuning.join.maxRightRowsForCaching) {
|
|
@@ -146,7 +162,7 @@ export class MaterializationAdvisory {
|
|
|
146
162
|
};
|
|
147
163
|
}
|
|
148
164
|
|
|
149
|
-
|
|
165
|
+
/**
|
|
150
166
|
* Select appropriate cache strategy based on estimated size
|
|
151
167
|
*/
|
|
152
168
|
private selectStrategy(estimatedRows: number): CacheStrategy {
|
|
@@ -174,22 +190,27 @@ export class MaterializationAdvisory {
|
|
|
174
190
|
}
|
|
175
191
|
|
|
176
192
|
/**
|
|
177
|
-
* Check if a node is
|
|
193
|
+
* Check if a node is part of a correlated subquery
|
|
178
194
|
*/
|
|
179
|
-
private
|
|
180
|
-
|
|
195
|
+
private isCorrelatedNode(node: PlanNode): boolean {
|
|
196
|
+
// Check if this is a relational node that could be correlated
|
|
197
|
+
if (isRelationalNode(node)) {
|
|
198
|
+
return isCorrelatedSubquery(node as RelationalPlanNode);
|
|
199
|
+
}
|
|
200
|
+
return false;
|
|
181
201
|
}
|
|
182
202
|
|
|
183
203
|
/**
|
|
184
|
-
* Transform a
|
|
204
|
+
* Transform a tree by wrapping recommended nodes with CacheNode
|
|
205
|
+
* Uses a bottom-up approach to ensure proper transformation
|
|
185
206
|
*/
|
|
186
|
-
private
|
|
187
|
-
// First,
|
|
207
|
+
private transformTree(node: PlanNode, recommendations: Map<PlanNode, CacheRecommendation>): PlanNode {
|
|
208
|
+
// First, transform all children recursively
|
|
188
209
|
const transformedNode = this.transformChildren(node, recommendations);
|
|
189
210
|
|
|
190
|
-
//
|
|
211
|
+
// Then check if this node itself should be cached
|
|
191
212
|
const recommendation = recommendations.get(node);
|
|
192
|
-
if (recommendation?.shouldCache &&
|
|
213
|
+
if (recommendation?.shouldCache && isRelationalNode(transformedNode)) {
|
|
193
214
|
log('Injecting %s cache for %s (threshold: %d)',
|
|
194
215
|
recommendation.strategy, transformedNode.nodeType, recommendation.threshold);
|
|
195
216
|
|
|
@@ -206,39 +227,39 @@ export class MaterializationAdvisory {
|
|
|
206
227
|
|
|
207
228
|
/**
|
|
208
229
|
* Transform children of a node
|
|
230
|
+
* This handles both scalar and relational children using a simpler approach
|
|
209
231
|
*/
|
|
210
232
|
private transformChildren(node: PlanNode, recommendations: Map<PlanNode, CacheRecommendation>): PlanNode {
|
|
211
|
-
//
|
|
233
|
+
// For nodes that we know how to handle, transform their children
|
|
234
|
+
// For others, return the node as-is (the optimizer will handle it)
|
|
212
235
|
|
|
213
|
-
//
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
236
|
+
// First, try to transform scalar children using withChildren
|
|
237
|
+
const scalarChildren = node.getChildren();
|
|
238
|
+
const transformedScalarChildren = scalarChildren.map(child =>
|
|
239
|
+
this.transformTree(child, recommendations)
|
|
240
|
+
);
|
|
241
|
+
|
|
242
|
+
const scalarChanged = transformedScalarChildren.some((child, idx) =>
|
|
243
|
+
child !== scalarChildren[idx]
|
|
244
|
+
);
|
|
219
245
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
246
|
+
if (scalarChanged) {
|
|
247
|
+
// Let withChildren handle the transformation
|
|
248
|
+
// This will maintain proper attribute IDs and node structure
|
|
249
|
+
try {
|
|
250
|
+
return node.withChildren(transformedScalarChildren);
|
|
251
|
+
} catch (e) {
|
|
252
|
+
// If withChildren fails, log and return original
|
|
253
|
+
log('Warning: withChildren failed for %s: %s', node.nodeType, e);
|
|
254
|
+
return node;
|
|
224
255
|
}
|
|
225
256
|
}
|
|
226
257
|
|
|
227
|
-
// If no
|
|
228
|
-
return node
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
/**
|
|
232
|
-
* Recreate a node with new relational children
|
|
233
|
-
* This is a simplified version - in practice, would need comprehensive node cloning
|
|
234
|
-
*/
|
|
235
|
-
private recreateNodeWithNewRelations(node: PlanNode, _newRelations: RelationalPlanNode[]): PlanNode {
|
|
236
|
-
// TODO: This is a simplified implementation
|
|
237
|
-
// In practice, would need to handle all node types properly
|
|
258
|
+
// If no scalar children changed, check if this node has relational children
|
|
259
|
+
// that might need caching. For now, we'll return the node as-is and let
|
|
260
|
+
// individual optimization rules handle relational transformations.
|
|
261
|
+
// This is safer than trying to recreate complex nodes.
|
|
238
262
|
|
|
239
|
-
// For now, just return the original node
|
|
240
|
-
// This would need to be expanded to handle all node types
|
|
241
|
-
log('Node recreation not yet implemented for %s', node.nodeType);
|
|
242
263
|
return node;
|
|
243
264
|
}
|
|
244
265
|
}
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Reference graph builder for materialization advisory
|
|
3
3
|
* Analyzes plan tree to identify nodes that would benefit from caching
|
|
4
|
+
*
|
|
5
|
+
* Note: This builder works with logical plan nodes and their properties.
|
|
6
|
+
* It does not make assumptions about execution strategies (e.g., whether
|
|
7
|
+
* a join will use nested loops vs hash join). Loop detection and execution
|
|
8
|
+
* multipliers should be determined during physical optimization when
|
|
9
|
+
* concrete execution strategies are chosen.
|
|
4
10
|
*/
|
|
5
11
|
|
|
6
12
|
import { createLogger } from '../../common/logger.js';
|
|
7
|
-
import type
|
|
8
|
-
import { PlanNodeType } from '../nodes/plan-node-type.js';
|
|
9
|
-
import { JoinNode } from '../nodes/join-node.js';
|
|
13
|
+
import { isRelationalNode, type PlanNode } from '../nodes/plan-node.js';
|
|
10
14
|
import type { OptimizerTuning } from '../optimizer-tuning.js';
|
|
11
15
|
|
|
12
16
|
const log = createLogger('optimizer:cache:reference-graph');
|
|
@@ -23,6 +27,22 @@ export interface RefStats {
|
|
|
23
27
|
estimatedRows: number;
|
|
24
28
|
/** Whether this node is deterministic (same inputs produce same outputs) */
|
|
25
29
|
deterministic: boolean;
|
|
30
|
+
/** Parent nodes that reference this node (for debugging) */
|
|
31
|
+
parents: Set<PlanNode>;
|
|
32
|
+
/** Estimated execution multiplier due to loop contexts */
|
|
33
|
+
loopMultiplier: number;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Node traversal context
|
|
38
|
+
*/
|
|
39
|
+
interface TraversalContext {
|
|
40
|
+
/** Current parent node */
|
|
41
|
+
parent: PlanNode | null;
|
|
42
|
+
/** Whether we're in a loop context */
|
|
43
|
+
inLoop: boolean;
|
|
44
|
+
/** Estimated loop iteration count */
|
|
45
|
+
loopIterations: number;
|
|
26
46
|
}
|
|
27
47
|
|
|
28
48
|
/**
|
|
@@ -30,7 +50,6 @@ export interface RefStats {
|
|
|
30
50
|
*/
|
|
31
51
|
export class ReferenceGraphBuilder {
|
|
32
52
|
private refMap = new Map<PlanNode, RefStats>();
|
|
33
|
-
private visited = new Set<PlanNode>();
|
|
34
53
|
|
|
35
54
|
constructor(private tuning: OptimizerTuning) {}
|
|
36
55
|
|
|
@@ -38,90 +57,105 @@ export class ReferenceGraphBuilder {
|
|
|
38
57
|
* Build reference statistics for all nodes in the plan tree
|
|
39
58
|
*/
|
|
40
59
|
buildReferenceGraph(root: PlanNode): Map<PlanNode, RefStats> {
|
|
60
|
+
if (!root) {
|
|
61
|
+
log('Warning: buildReferenceGraph called with null root');
|
|
62
|
+
return new Map();
|
|
63
|
+
}
|
|
64
|
+
|
|
41
65
|
this.refMap.clear();
|
|
42
|
-
this.visited.clear();
|
|
43
66
|
|
|
44
|
-
//
|
|
45
|
-
|
|
67
|
+
// Build the reference graph with proper parent tracking
|
|
68
|
+
const context: TraversalContext = {
|
|
69
|
+
parent: null,
|
|
70
|
+
inLoop: false,
|
|
71
|
+
loopIterations: 1
|
|
72
|
+
};
|
|
46
73
|
|
|
47
|
-
|
|
48
|
-
this.identifyLoopContexts(root, false);
|
|
74
|
+
this.buildReferences(root, context);
|
|
49
75
|
|
|
50
76
|
log('Built reference graph with %d nodes', this.refMap.size);
|
|
51
77
|
return new Map(this.refMap);
|
|
52
78
|
}
|
|
53
79
|
|
|
54
80
|
/**
|
|
55
|
-
*
|
|
81
|
+
* Build reference statistics recursively
|
|
56
82
|
*/
|
|
57
|
-
private
|
|
58
|
-
if (
|
|
59
|
-
// Node seen again - increment parent count
|
|
60
|
-
const stats = this.refMap.get(node);
|
|
61
|
-
if (stats) {
|
|
62
|
-
stats.parentCount++;
|
|
63
|
-
}
|
|
83
|
+
private buildReferences(node: PlanNode | null | undefined, context: TraversalContext): void {
|
|
84
|
+
if (!node) {
|
|
64
85
|
return;
|
|
65
86
|
}
|
|
66
87
|
|
|
67
|
-
this
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
this.countReferences(child, inLoop);
|
|
82
|
-
});
|
|
83
|
-
}
|
|
88
|
+
// Get or create stats for this node
|
|
89
|
+
let stats = this.refMap.get(node);
|
|
90
|
+
if (!stats) {
|
|
91
|
+
// First time seeing this node
|
|
92
|
+
stats = {
|
|
93
|
+
parentCount: 0,
|
|
94
|
+
appearsInLoop: context.inLoop,
|
|
95
|
+
estimatedRows: this.getEstimatedRows(node),
|
|
96
|
+
deterministic: this.isDeterministic(node),
|
|
97
|
+
parents: new Set<PlanNode>(),
|
|
98
|
+
loopMultiplier: context.loopIterations
|
|
99
|
+
};
|
|
100
|
+
this.refMap.set(node, stats);
|
|
101
|
+
}
|
|
84
102
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
if (!stats) return;
|
|
103
|
+
// Update stats based on current traversal
|
|
104
|
+
if (context.parent && !stats.parents.has(context.parent)) {
|
|
105
|
+
stats.parents.add(context.parent);
|
|
106
|
+
stats.parentCount++;
|
|
107
|
+
}
|
|
91
108
|
|
|
92
|
-
// Update loop
|
|
93
|
-
if (inLoop
|
|
109
|
+
// Update loop context
|
|
110
|
+
if (context.inLoop) {
|
|
94
111
|
stats.appearsInLoop = true;
|
|
95
|
-
|
|
112
|
+
stats.loopMultiplier = Math.max(stats.loopMultiplier, context.loopIterations);
|
|
96
113
|
}
|
|
97
114
|
|
|
98
|
-
//
|
|
99
|
-
if
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
});
|
|
109
|
-
}
|
|
115
|
+
// Create child context - for now, we propagate the parent context
|
|
116
|
+
// In the future, if nodes expose execution strategy hints, we could use those
|
|
117
|
+
const childContext: TraversalContext = {
|
|
118
|
+
parent: node,
|
|
119
|
+
inLoop: context.inLoop,
|
|
120
|
+
loopIterations: context.loopIterations
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
// Visit all children uniformly
|
|
124
|
+
this.visitAllChildren(node, childContext);
|
|
110
125
|
}
|
|
111
126
|
|
|
112
127
|
/**
|
|
113
128
|
* Visit all children of a node
|
|
114
129
|
*/
|
|
115
|
-
private
|
|
116
|
-
//
|
|
117
|
-
|
|
118
|
-
|
|
130
|
+
private visitAllChildren(node: PlanNode, childContext: TraversalContext): void {
|
|
131
|
+
// 1. Scalar children (expressions)
|
|
132
|
+
try {
|
|
133
|
+
const children = node.getChildren();
|
|
134
|
+
for (const child of children) {
|
|
135
|
+
if (child) {
|
|
136
|
+
this.buildReferences(child, childContext);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
} catch (e) {
|
|
140
|
+
log('Warning: Failed to get children for node %s: %s', node.nodeType, e);
|
|
119
141
|
}
|
|
120
142
|
|
|
121
|
-
//
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
143
|
+
// 2. Relational children
|
|
144
|
+
// Note: getRelations() returns a subset of getChildren() for nodes that have relational children
|
|
145
|
+
// We need to be careful not to double-count, but since we're using a Set for parents,
|
|
146
|
+
// and checking if we've already added a parent, this should be fine
|
|
147
|
+
if (isRelationalNode(node)) {
|
|
148
|
+
try {
|
|
149
|
+
const relations = node.getRelations();
|
|
150
|
+
for (const relation of relations) {
|
|
151
|
+
if (relation) {
|
|
152
|
+
// For now, treat all relational children the same
|
|
153
|
+
// In the future, nodes could provide hints about execution patterns
|
|
154
|
+
this.buildReferences(relation, childContext);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
} catch (e) {
|
|
158
|
+
log('Warning: Failed to get relations for node %s: %s', node.nodeType, e);
|
|
125
159
|
}
|
|
126
160
|
}
|
|
127
161
|
}
|
|
@@ -129,44 +163,34 @@ export class ReferenceGraphBuilder {
|
|
|
129
163
|
/**
|
|
130
164
|
* Get estimated row count for a node
|
|
131
165
|
*/
|
|
132
|
-
private getEstimatedRows(node: PlanNode): number {
|
|
133
|
-
if (
|
|
134
|
-
return
|
|
166
|
+
private getEstimatedRows(node: PlanNode | null | undefined): number {
|
|
167
|
+
if (!node) {
|
|
168
|
+
return this.tuning.defaultRowEstimate;
|
|
135
169
|
}
|
|
136
|
-
|
|
170
|
+
|
|
171
|
+
// Use physical properties if available
|
|
172
|
+
if (node.physical?.estimatedRows !== undefined) {
|
|
137
173
|
return node.physical.estimatedRows;
|
|
138
174
|
}
|
|
175
|
+
|
|
176
|
+
// Fall back to node-specific estimates (for relational nodes)
|
|
177
|
+
if (isRelationalNode(node) && node.estimatedRows !== undefined) {
|
|
178
|
+
return node.estimatedRows;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Default estimate
|
|
139
182
|
return this.tuning.defaultRowEstimate;
|
|
140
183
|
}
|
|
141
184
|
|
|
142
185
|
/**
|
|
143
186
|
* Determine if a node is deterministic
|
|
144
187
|
*/
|
|
145
|
-
private isDeterministic(node: PlanNode): boolean {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
return node.physical.deterministic;
|
|
188
|
+
private isDeterministic(node: PlanNode | null | undefined): boolean {
|
|
189
|
+
if (!node) {
|
|
190
|
+
return true;
|
|
149
191
|
}
|
|
150
192
|
|
|
151
|
-
//
|
|
152
|
-
|
|
153
|
-
case PlanNodeType.TableScan:
|
|
154
|
-
case PlanNodeType.Values:
|
|
155
|
-
case PlanNodeType.Project:
|
|
156
|
-
case PlanNodeType.Filter:
|
|
157
|
-
case PlanNodeType.Sort:
|
|
158
|
-
case PlanNodeType.Aggregate:
|
|
159
|
-
case PlanNodeType.StreamAggregate:
|
|
160
|
-
return true;
|
|
161
|
-
|
|
162
|
-
case PlanNodeType.TableFunctionCall:
|
|
163
|
-
// Would need to check if the table function is deterministic
|
|
164
|
-
// For now, assume non-deterministic to be safe
|
|
165
|
-
return false;
|
|
166
|
-
|
|
167
|
-
default:
|
|
168
|
-
// Conservative default - assume deterministic unless proven otherwise
|
|
169
|
-
return true;
|
|
170
|
-
}
|
|
193
|
+
// Use physical properties to determine determinism
|
|
194
|
+
return node.physical?.deterministic ?? true;
|
|
171
195
|
}
|
|
172
196
|
}
|
package/src/planner/debug.ts
CHANGED
|
@@ -314,3 +314,166 @@ export function generateTraceReport(
|
|
|
314
314
|
lines.push('=== END TRACE ===');
|
|
315
315
|
return lines.join('\n');
|
|
316
316
|
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Options for plan formatting
|
|
320
|
+
*/
|
|
321
|
+
export interface PlanDisplayOptions {
|
|
322
|
+
/** Show concise plan by default (true) or full details (false) */
|
|
323
|
+
concise?: boolean;
|
|
324
|
+
/** Node IDs to expand with full details (only applies when concise=true) */
|
|
325
|
+
expandNodes?: string[];
|
|
326
|
+
/** Maximum depth to display (default: no limit) */
|
|
327
|
+
maxDepth?: number;
|
|
328
|
+
/** Show physical properties if available */
|
|
329
|
+
showPhysical?: boolean;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Creates a concise, tree-like representation of the plan
|
|
334
|
+
*/
|
|
335
|
+
export function formatPlanTree(rootNode: PlanNode, options: PlanDisplayOptions = {}): string {
|
|
336
|
+
const { concise = true, expandNodes = [], maxDepth, showPhysical = true } = options;
|
|
337
|
+
const lines: string[] = [];
|
|
338
|
+
const nodesSeen = new Set<PlanNode>();
|
|
339
|
+
|
|
340
|
+
function formatNode(node: PlanNode, depth: number, isLast: boolean, prefix: string): void {
|
|
341
|
+
if (maxDepth !== undefined && depth > maxDepth) {
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// Avoid infinite recursion for circular references
|
|
346
|
+
if (nodesSeen.has(node)) {
|
|
347
|
+
lines.push(`${prefix}├─ [CIRCULAR: ${node.nodeType}#${node.id}]`);
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
nodesSeen.add(node);
|
|
351
|
+
|
|
352
|
+
// Determine if this node should be expanded
|
|
353
|
+
const shouldExpand = !concise || expandNodes.includes(node.id);
|
|
354
|
+
|
|
355
|
+
// Node header with connection lines
|
|
356
|
+
const connector = isLast ? '└─ ' : '├─ ';
|
|
357
|
+
const nodeType = node.nodeType;
|
|
358
|
+
const nodeId = `#${node.id}`;
|
|
359
|
+
const description = node.toString();
|
|
360
|
+
|
|
361
|
+
// Build the header line
|
|
362
|
+
let headerLine = `${prefix}${connector}${nodeType}${nodeId}`;
|
|
363
|
+
if (description && description !== nodeType) {
|
|
364
|
+
headerLine += `: ${description}`;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
// Add cost information if available
|
|
368
|
+
const cost = node.estimatedCost;
|
|
369
|
+
const totalCost = node.getTotalCost();
|
|
370
|
+
if (cost > 0 || totalCost > 0) {
|
|
371
|
+
headerLine += ` [cost: ${cost}, total: ${totalCost}]`;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
// Add physical properties if requested and available
|
|
375
|
+
if (showPhysical && (node as any).physical) {
|
|
376
|
+
const physical = (node as any).physical;
|
|
377
|
+
const physicalInfo = [];
|
|
378
|
+
if (physical.estimatedRows !== undefined) {
|
|
379
|
+
physicalInfo.push(`rows: ${physical.estimatedRows}`);
|
|
380
|
+
}
|
|
381
|
+
if (physical.ordering && physical.ordering.length > 0) {
|
|
382
|
+
physicalInfo.push(`ordered: ${physical.ordering.map((o: any) => `${o.attributeId}:${o.direction}`).join(',')}`);
|
|
383
|
+
}
|
|
384
|
+
if (physical.readonly !== undefined) {
|
|
385
|
+
physicalInfo.push(`readonly: ${physical.readonly}`);
|
|
386
|
+
}
|
|
387
|
+
if (physicalInfo.length > 0) {
|
|
388
|
+
headerLine += ` {${physicalInfo.join(', ')}}`;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
lines.push(headerLine);
|
|
393
|
+
|
|
394
|
+
// Add expanded details if requested
|
|
395
|
+
if (shouldExpand) {
|
|
396
|
+
const logical = node.getLogicalAttributes();
|
|
397
|
+
if (logical && Object.keys(logical).length > 0) {
|
|
398
|
+
const logicalLines = JSON.stringify(logical, null, 2).split('\n');
|
|
399
|
+
const extendedPrefix = prefix + (isLast ? ' ' : '│ ');
|
|
400
|
+
lines.push(`${extendedPrefix}┌─ Logical Attributes:`);
|
|
401
|
+
for (let i = 0; i < logicalLines.length; i++) {
|
|
402
|
+
const line = logicalLines[i];
|
|
403
|
+
const isLastLogicalLine = i === logicalLines.length - 1;
|
|
404
|
+
const logicalConnector = isLastLogicalLine ? '└─ ' : '│ ';
|
|
405
|
+
lines.push(`${extendedPrefix}${logicalConnector}${line}`);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
// Process children
|
|
411
|
+
const children = node.getChildren();
|
|
412
|
+
const relations = node.getRelations();
|
|
413
|
+
const allChildren = [...children, ...relations];
|
|
414
|
+
|
|
415
|
+
// Filter out duplicates (in case a child is both a child and relation)
|
|
416
|
+
const uniqueChildren = Array.from(new Set(allChildren));
|
|
417
|
+
|
|
418
|
+
for (let i = 0; i < uniqueChildren.length; i++) {
|
|
419
|
+
const child = uniqueChildren[i];
|
|
420
|
+
const isLastChild = i === uniqueChildren.length - 1;
|
|
421
|
+
const childPrefix = prefix + (isLast ? ' ' : '│ ');
|
|
422
|
+
formatNode(child, depth + 1, isLastChild, childPrefix);
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
nodesSeen.delete(node);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
lines.push('Query Plan:');
|
|
429
|
+
formatNode(rootNode, 0, true, '');
|
|
430
|
+
|
|
431
|
+
// Add help text
|
|
432
|
+
if (concise && expandNodes.length === 0) {
|
|
433
|
+
lines.push('');
|
|
434
|
+
lines.push('Tip: Use --expand-nodes node1,node2,... to see detailed properties for specific nodes');
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
return lines.join('\n');
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
/**
|
|
441
|
+
* Generates a compact plan summary showing just the execution path
|
|
442
|
+
*/
|
|
443
|
+
export function formatPlanSummary(rootNode: PlanNode): string {
|
|
444
|
+
const path: string[] = [];
|
|
445
|
+
const visited = new Set<PlanNode>();
|
|
446
|
+
|
|
447
|
+
function collectPath(node: PlanNode): void {
|
|
448
|
+
if (visited.has(node)) return;
|
|
449
|
+
visited.add(node);
|
|
450
|
+
|
|
451
|
+
const description = node.toString();
|
|
452
|
+
const nodeInfo = description && description !== node.nodeType
|
|
453
|
+
? `${node.nodeType}(${description})`
|
|
454
|
+
: node.nodeType;
|
|
455
|
+
|
|
456
|
+
path.push(nodeInfo);
|
|
457
|
+
|
|
458
|
+
// Follow the main execution path (first child for most nodes)
|
|
459
|
+
const children = node.getChildren();
|
|
460
|
+
if (children.length > 0) {
|
|
461
|
+
collectPath(children[0]);
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
collectPath(rootNode);
|
|
466
|
+
return `Execution Path: ${path.join(' → ')}`;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
/**
|
|
470
|
+
* Enhanced plan serialization with formatting options
|
|
471
|
+
*/
|
|
472
|
+
export function serializePlanTreeWithOptions(rootNode: PlanNode, options: PlanDisplayOptions = {}): string {
|
|
473
|
+
if (options.concise !== false) {
|
|
474
|
+
return formatPlanTree(rootNode, options);
|
|
475
|
+
} else {
|
|
476
|
+
// Use the existing detailed serialization
|
|
477
|
+
return serializePlanTree(rootNode);
|
|
478
|
+
}
|
|
479
|
+
}
|