@quereus/quereus 0.7.2 → 0.7.4
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/package.json +3 -3
- package/dist/src/common/constants.js.map +0 -1
- package/dist/src/common/datatype.js.map +0 -1
- package/dist/src/common/errors.js.map +0 -1
- package/dist/src/common/json-types.js.map +0 -1
- package/dist/src/common/logger.js.map +0 -1
- package/dist/src/common/type-inference.js.map +0 -1
- package/dist/src/common/types.js.map +0 -1
- package/dist/src/core/database-options.js.map +0 -1
- package/dist/src/core/database.js.map +0 -1
- package/dist/src/core/param.js.map +0 -1
- package/dist/src/core/statement.js.map +0 -1
- package/dist/src/func/builtins/aggregate.js.map +0 -1
- package/dist/src/func/builtins/builtin-window-functions.js.map +0 -1
- package/dist/src/func/builtins/conversion.js.map +0 -1
- package/dist/src/func/builtins/datetime.js.map +0 -1
- package/dist/src/func/builtins/explain.js.map +0 -1
- package/dist/src/func/builtins/generation.js.map +0 -1
- package/dist/src/func/builtins/index.js.map +0 -1
- package/dist/src/func/builtins/json-helpers.js.map +0 -1
- package/dist/src/func/builtins/json-tvf.js.map +0 -1
- package/dist/src/func/builtins/json.js.map +0 -1
- package/dist/src/func/builtins/scalar.js.map +0 -1
- package/dist/src/func/builtins/schema.js.map +0 -1
- package/dist/src/func/builtins/string.js.map +0 -1
- package/dist/src/func/builtins/timespan.js.map +0 -1
- package/dist/src/func/context.js.map +0 -1
- package/dist/src/func/registration.js.map +0 -1
- package/dist/src/index.js.map +0 -1
- package/dist/src/parser/ast.js.map +0 -1
- package/dist/src/parser/index.js.map +0 -1
- package/dist/src/parser/lexer.js.map +0 -1
- package/dist/src/parser/parser.js.map +0 -1
- package/dist/src/parser/utils.js.map +0 -1
- package/dist/src/parser/visitor.js.map +0 -1
- package/dist/src/planner/analysis/binding-collector.js.map +0 -1
- package/dist/src/planner/analysis/const-evaluator.js.map +0 -1
- package/dist/src/planner/analysis/const-pass.js.map +0 -1
- package/dist/src/planner/analysis/constraint-extractor.js.map +0 -1
- package/dist/src/planner/analysis/predicate-normalizer.js.map +0 -1
- package/dist/src/planner/building/alter-table.js.map +0 -1
- package/dist/src/planner/building/block.js.map +0 -1
- package/dist/src/planner/building/constraint-builder.js.map +0 -1
- package/dist/src/planner/building/create-assertion.js.map +0 -1
- package/dist/src/planner/building/create-view.js.map +0 -1
- package/dist/src/planner/building/ddl.js.map +0 -1
- package/dist/src/planner/building/declare-schema.js.map +0 -1
- package/dist/src/planner/building/delete.js.map +0 -1
- package/dist/src/planner/building/drop-assertion.js.map +0 -1
- package/dist/src/planner/building/drop-table.js.map +0 -1
- package/dist/src/planner/building/drop-view.js.map +0 -1
- package/dist/src/planner/building/expression.js.map +0 -1
- package/dist/src/planner/building/function-call.js.map +0 -1
- package/dist/src/planner/building/insert.js.map +0 -1
- package/dist/src/planner/building/pragma.js.map +0 -1
- package/dist/src/planner/building/schema-resolution.js.map +0 -1
- package/dist/src/planner/building/select-aggregates.js.map +0 -1
- package/dist/src/planner/building/select-compound.js.map +0 -1
- package/dist/src/planner/building/select-context.js.map +0 -1
- package/dist/src/planner/building/select-modifiers.js.map +0 -1
- package/dist/src/planner/building/select-projections.js.map +0 -1
- package/dist/src/planner/building/select-window.js.map +0 -1
- package/dist/src/planner/building/select.js.map +0 -1
- package/dist/src/planner/building/table-function.js.map +0 -1
- package/dist/src/planner/building/table.js.map +0 -1
- package/dist/src/planner/building/transaction.js.map +0 -1
- package/dist/src/planner/building/update.js.map +0 -1
- package/dist/src/planner/building/with.js.map +0 -1
- package/dist/src/planner/cache/correlation-detector.js.map +0 -1
- package/dist/src/planner/cache/materialization-advisory.js.map +0 -1
- package/dist/src/planner/cache/reference-graph.js.map +0 -1
- package/dist/src/planner/cost/index.js.map +0 -1
- package/dist/src/planner/debug/logger-utils.js.map +0 -1
- package/dist/src/planner/debug.js.map +0 -1
- package/dist/src/planner/framework/characteristics.js.map +0 -1
- package/dist/src/planner/framework/context.js.map +0 -1
- package/dist/src/planner/framework/pass.js.map +0 -1
- package/dist/src/planner/framework/physical-utils.js.map +0 -1
- package/dist/src/planner/framework/registry.js.map +0 -1
- package/dist/src/planner/framework/trace.js.map +0 -1
- package/dist/src/planner/nodes/add-constraint-node.js.map +0 -1
- package/dist/src/planner/nodes/aggregate-function.js.map +0 -1
- package/dist/src/planner/nodes/aggregate-node.js.map +0 -1
- package/dist/src/planner/nodes/array-index-node.js.map +0 -1
- package/dist/src/planner/nodes/block.js.map +0 -1
- package/dist/src/planner/nodes/cache-node.js.map +0 -1
- package/dist/src/planner/nodes/constraint-check-node.js.map +0 -1
- package/dist/src/planner/nodes/create-assertion-node.js.map +0 -1
- package/dist/src/planner/nodes/create-index-node.js.map +0 -1
- package/dist/src/planner/nodes/create-table-node.js.map +0 -1
- package/dist/src/planner/nodes/create-view-node.js.map +0 -1
- package/dist/src/planner/nodes/cte-node.js.map +0 -1
- package/dist/src/planner/nodes/cte-reference-node.js.map +0 -1
- package/dist/src/planner/nodes/declarative-schema.js.map +0 -1
- package/dist/src/planner/nodes/delete-node.js.map +0 -1
- package/dist/src/planner/nodes/distinct-node.js.map +0 -1
- package/dist/src/planner/nodes/dml-executor-node.js.map +0 -1
- package/dist/src/planner/nodes/drop-assertion-node.js.map +0 -1
- package/dist/src/planner/nodes/drop-table-node.js.map +0 -1
- package/dist/src/planner/nodes/drop-view-node.js.map +0 -1
- package/dist/src/planner/nodes/filter.js.map +0 -1
- package/dist/src/planner/nodes/function.js.map +0 -1
- package/dist/src/planner/nodes/insert-node.js.map +0 -1
- package/dist/src/planner/nodes/internal-recursive-cte-ref-node.js.map +0 -1
- package/dist/src/planner/nodes/join-node.js.map +0 -1
- package/dist/src/planner/nodes/limit-offset.js.map +0 -1
- package/dist/src/planner/nodes/plan-node-type.js.map +0 -1
- package/dist/src/planner/nodes/plan-node.js.map +0 -1
- package/dist/src/planner/nodes/pragma.js.map +0 -1
- package/dist/src/planner/nodes/project-node.js.map +0 -1
- package/dist/src/planner/nodes/recursive-cte-node.js.map +0 -1
- package/dist/src/planner/nodes/reference.js.map +0 -1
- package/dist/src/planner/nodes/remote-query-node.js.map +0 -1
- package/dist/src/planner/nodes/retrieve-node.js.map +0 -1
- package/dist/src/planner/nodes/returning-node.js.map +0 -1
- package/dist/src/planner/nodes/scalar.js.map +0 -1
- package/dist/src/planner/nodes/sequencing-node.js.map +0 -1
- package/dist/src/planner/nodes/set-operation-node.js.map +0 -1
- package/dist/src/planner/nodes/single-row.js.map +0 -1
- package/dist/src/planner/nodes/sink-node.js.map +0 -1
- package/dist/src/planner/nodes/sort.js.map +0 -1
- package/dist/src/planner/nodes/stream-aggregate.js.map +0 -1
- package/dist/src/planner/nodes/subquery.js.map +0 -1
- package/dist/src/planner/nodes/table-access-nodes.js.map +0 -1
- package/dist/src/planner/nodes/table-function-call.js.map +0 -1
- package/dist/src/planner/nodes/transaction-node.js.map +0 -1
- package/dist/src/planner/nodes/update-node.js.map +0 -1
- package/dist/src/planner/nodes/values-node.js.map +0 -1
- package/dist/src/planner/nodes/view-reference-node.js.map +0 -1
- package/dist/src/planner/nodes/window-function.js.map +0 -1
- package/dist/src/planner/nodes/window-node.js.map +0 -1
- package/dist/src/planner/optimizer-tuning.js.map +0 -1
- package/dist/src/planner/optimizer.js.map +0 -1
- package/dist/src/planner/planning-context.js.map +0 -1
- package/dist/src/planner/resolve.js.map +0 -1
- package/dist/src/planner/rules/access/rule-select-access-path.js.map +0 -1
- package/dist/src/planner/rules/aggregate/rule-aggregate-streaming.js.map +0 -1
- package/dist/src/planner/rules/cache/rule-cte-optimization.js.map +0 -1
- package/dist/src/planner/rules/cache/rule-materialization-advisory.js.map +0 -1
- package/dist/src/planner/rules/cache/rule-mutating-subquery-cache.js.map +0 -1
- package/dist/src/planner/rules/join/rule-join-greedy-commute.js.map +0 -1
- package/dist/src/planner/rules/join/rule-join-key-inference.js.map +0 -1
- package/dist/src/planner/rules/join/rule-quickpick-enumeration.js.map +0 -1
- package/dist/src/planner/rules/predicate/rule-predicate-pushdown.js.map +0 -1
- package/dist/src/planner/rules/retrieve/rule-grow-retrieve.js.map +0 -1
- package/dist/src/planner/scopes/aliased.js.map +0 -1
- package/dist/src/planner/scopes/base.js.map +0 -1
- package/dist/src/planner/scopes/empty.js.map +0 -1
- package/dist/src/planner/scopes/global.js.map +0 -1
- package/dist/src/planner/scopes/multi.js.map +0 -1
- package/dist/src/planner/scopes/param.js.map +0 -1
- package/dist/src/planner/scopes/registered.js.map +0 -1
- package/dist/src/planner/scopes/scope.js.map +0 -1
- package/dist/src/planner/stats/basic-estimates.js.map +0 -1
- package/dist/src/planner/stats/index.js.map +0 -1
- package/dist/src/planner/type-utils.js.map +0 -1
- package/dist/src/planner/util/key-utils.js.map +0 -1
- package/dist/src/planner/validation/determinism-validator.js.map +0 -1
- package/dist/src/planner/validation/plan-validator.js.map +0 -1
- package/dist/src/runtime/async-util.js.map +0 -1
- package/dist/src/runtime/cache/shared-cache.js.map +0 -1
- package/dist/src/runtime/context-helpers.js.map +0 -1
- package/dist/src/runtime/deferred-constraint-queue.js.map +0 -1
- package/dist/src/runtime/emission-context.js.map +0 -1
- package/dist/src/runtime/emit/add-constraint.js.map +0 -1
- package/dist/src/runtime/emit/aggregate.js.map +0 -1
- package/dist/src/runtime/emit/array-index.js.map +0 -1
- package/dist/src/runtime/emit/between.js.map +0 -1
- package/dist/src/runtime/emit/binary.js.map +0 -1
- package/dist/src/runtime/emit/block.js.map +0 -1
- package/dist/src/runtime/emit/cache.js.map +0 -1
- package/dist/src/runtime/emit/case.js.map +0 -1
- package/dist/src/runtime/emit/cast.js.map +0 -1
- package/dist/src/runtime/emit/collate.js.map +0 -1
- package/dist/src/runtime/emit/column-reference.js.map +0 -1
- package/dist/src/runtime/emit/constraint-check.js.map +0 -1
- package/dist/src/runtime/emit/create-assertion.js.map +0 -1
- package/dist/src/runtime/emit/create-index.js.map +0 -1
- package/dist/src/runtime/emit/create-table.js.map +0 -1
- package/dist/src/runtime/emit/create-view.js.map +0 -1
- package/dist/src/runtime/emit/cte-reference.js.map +0 -1
- package/dist/src/runtime/emit/cte.js.map +0 -1
- package/dist/src/runtime/emit/delete.js.map +0 -1
- package/dist/src/runtime/emit/distinct.js.map +0 -1
- package/dist/src/runtime/emit/dml-executor.js.map +0 -1
- package/dist/src/runtime/emit/drop-assertion.js.map +0 -1
- package/dist/src/runtime/emit/drop-table.js.map +0 -1
- package/dist/src/runtime/emit/drop-view.js.map +0 -1
- package/dist/src/runtime/emit/filter.js.map +0 -1
- package/dist/src/runtime/emit/insert.js.map +0 -1
- package/dist/src/runtime/emit/internal-recursive-cte-ref.js.map +0 -1
- package/dist/src/runtime/emit/join.js.map +0 -1
- package/dist/src/runtime/emit/limit-offset.js.map +0 -1
- package/dist/src/runtime/emit/literal.js.map +0 -1
- package/dist/src/runtime/emit/parameter.js.map +0 -1
- package/dist/src/runtime/emit/pragma.js.map +0 -1
- package/dist/src/runtime/emit/project.js.map +0 -1
- package/dist/src/runtime/emit/recursive-cte.js.map +0 -1
- package/dist/src/runtime/emit/remote-query.js.map +0 -1
- package/dist/src/runtime/emit/retrieve.js.map +0 -1
- package/dist/src/runtime/emit/returning.js.map +0 -1
- package/dist/src/runtime/emit/scalar-function.js.map +0 -1
- package/dist/src/runtime/emit/scan.js.map +0 -1
- package/dist/src/runtime/emit/schema-declarative.js.map +0 -1
- package/dist/src/runtime/emit/sequencing.js.map +0 -1
- package/dist/src/runtime/emit/set-operation.js.map +0 -1
- package/dist/src/runtime/emit/sink.js.map +0 -1
- package/dist/src/runtime/emit/sort.js.map +0 -1
- package/dist/src/runtime/emit/subquery.js.map +0 -1
- package/dist/src/runtime/emit/table-valued-function.js.map +0 -1
- package/dist/src/runtime/emit/temporal-arithmetic.js.map +0 -1
- package/dist/src/runtime/emit/transaction.js.map +0 -1
- package/dist/src/runtime/emit/unary.js.map +0 -1
- package/dist/src/runtime/emit/update.js.map +0 -1
- package/dist/src/runtime/emit/values.js.map +0 -1
- package/dist/src/runtime/emit/window-function.js.map +0 -1
- package/dist/src/runtime/emit/window.js.map +0 -1
- package/dist/src/runtime/emitters.js.map +0 -1
- package/dist/src/runtime/register.js.map +0 -1
- package/dist/src/runtime/scheduler.js.map +0 -1
- package/dist/src/runtime/types.js.map +0 -1
- package/dist/src/runtime/utils.js.map +0 -1
- package/dist/src/schema/assertion.js.map +0 -1
- package/dist/src/schema/catalog.js.map +0 -1
- package/dist/src/schema/change-events.js.map +0 -1
- package/dist/src/schema/column.js.map +0 -1
- package/dist/src/schema/declared-schema-manager.js.map +0 -1
- package/dist/src/schema/function.js.map +0 -1
- package/dist/src/schema/manager.js.map +0 -1
- package/dist/src/schema/schema-differ.js.map +0 -1
- package/dist/src/schema/schema-hasher.js.map +0 -1
- package/dist/src/schema/schema.js.map +0 -1
- package/dist/src/schema/table.js.map +0 -1
- package/dist/src/schema/view.js.map +0 -1
- package/dist/src/schema/window-function.js.map +0 -1
- package/dist/src/types/builtin-types.js.map +0 -1
- package/dist/src/types/index.js.map +0 -1
- package/dist/src/types/json-type.js.map +0 -1
- package/dist/src/types/logical-type.js.map +0 -1
- package/dist/src/types/plugin-interface.js.map +0 -1
- package/dist/src/types/registry.js.map +0 -1
- package/dist/src/types/temporal-types.js.map +0 -1
- package/dist/src/types/validation.js.map +0 -1
- package/dist/src/util/affinity.js.map +0 -1
- package/dist/src/util/ast-stringify.js.map +0 -1
- package/dist/src/util/cached.js.map +0 -1
- package/dist/src/util/coercion.js.map +0 -1
- package/dist/src/util/comparison.js.map +0 -1
- package/dist/src/util/environment.js.map +0 -1
- package/dist/src/util/hash.js.map +0 -1
- package/dist/src/util/latches.js.map +0 -1
- package/dist/src/util/mutation-statement.js.map +0 -1
- package/dist/src/util/patterns.js.map +0 -1
- package/dist/src/util/plan-formatter.js.map +0 -1
- package/dist/src/util/plugin-helper.js.map +0 -1
- package/dist/src/util/row-descriptor.js.map +0 -1
- package/dist/src/util/serialization.js.map +0 -1
- package/dist/src/util/sql-literal.js.map +0 -1
- package/dist/src/util/working-table-iterable.js.map +0 -1
- package/dist/src/vtab/best-access-plan.js.map +0 -1
- package/dist/src/vtab/connection.js.map +0 -1
- package/dist/src/vtab/filter-info.js.map +0 -1
- package/dist/src/vtab/index-info.js.map +0 -1
- package/dist/src/vtab/manifest.js.map +0 -1
- package/dist/src/vtab/memory/connection.js.map +0 -1
- package/dist/src/vtab/memory/index.js.map +0 -1
- package/dist/src/vtab/memory/layer/base-cursor.js.map +0 -1
- package/dist/src/vtab/memory/layer/base.js.map +0 -1
- package/dist/src/vtab/memory/layer/connection.js.map +0 -1
- package/dist/src/vtab/memory/layer/interface.js.map +0 -1
- package/dist/src/vtab/memory/layer/manager.js.map +0 -1
- package/dist/src/vtab/memory/layer/safe-iterate.js.map +0 -1
- package/dist/src/vtab/memory/layer/scan-plan.js.map +0 -1
- package/dist/src/vtab/memory/layer/transaction-cursor.js.map +0 -1
- package/dist/src/vtab/memory/layer/transaction.js.map +0 -1
- package/dist/src/vtab/memory/module.js.map +0 -1
- package/dist/src/vtab/memory/table.js.map +0 -1
- package/dist/src/vtab/memory/types.js.map +0 -1
- package/dist/src/vtab/memory/utils/logging.js.map +0 -1
- package/dist/src/vtab/memory/utils/primary-key.js.map +0 -1
- package/dist/src/vtab/module.js.map +0 -1
- package/dist/src/vtab/table.js.map +0 -1
- package/src/common/constants.ts +0 -60
- package/src/common/datatype.ts +0 -85
- package/src/common/errors.ts +0 -189
- package/src/common/json-types.ts +0 -16
- package/src/common/logger.ts +0 -97
- package/src/common/type-inference.ts +0 -39
- package/src/common/types.ts +0 -151
- package/src/core/database-options.ts +0 -258
- package/src/core/database.ts +0 -1461
- package/src/core/param.ts +0 -56
- package/src/core/statement.ts +0 -528
- package/src/func/builtins/aggregate.ts +0 -269
- package/src/func/builtins/builtin-window-functions.ts +0 -166
- package/src/func/builtins/conversion.ts +0 -226
- package/src/func/builtins/datetime.ts +0 -500
- package/src/func/builtins/explain.ts +0 -779
- package/src/func/builtins/generation.ts +0 -43
- package/src/func/builtins/index.ts +0 -167
- package/src/func/builtins/json-helpers.ts +0 -237
- package/src/func/builtins/json-tvf.ts +0 -224
- package/src/func/builtins/json.ts +0 -588
- package/src/func/builtins/scalar.ts +0 -423
- package/src/func/builtins/schema.ts +0 -213
- package/src/func/builtins/string.ts +0 -306
- package/src/func/builtins/timespan.ts +0 -179
- package/src/func/context.ts +0 -258
- package/src/func/registration.ts +0 -201
- package/src/index.ts +0 -172
- package/src/parser/ast.ts +0 -581
- package/src/parser/index.ts +0 -65
- package/src/parser/lexer.ts +0 -806
- package/src/parser/parser.ts +0 -3352
- package/src/parser/utils.ts +0 -10
- package/src/parser/visitor.ts +0 -188
- package/src/planner/analysis/README.md +0 -93
- package/src/planner/analysis/binding-collector.ts +0 -83
- package/src/planner/analysis/const-evaluator.ts +0 -63
- package/src/planner/analysis/const-pass.ts +0 -282
- package/src/planner/analysis/constraint-extractor.ts +0 -764
- package/src/planner/analysis/predicate-normalizer.ts +0 -237
- package/src/planner/building/alter-table.ts +0 -49
- package/src/planner/building/block.ts +0 -93
- package/src/planner/building/constraint-builder.ts +0 -178
- package/src/planner/building/create-assertion.ts +0 -7
- package/src/planner/building/create-view.ts +0 -29
- package/src/planner/building/ddl.ts +0 -24
- package/src/planner/building/declare-schema.ts +0 -22
- package/src/planner/building/delete.ts +0 -218
- package/src/planner/building/drop-assertion.ts +0 -11
- package/src/planner/building/drop-table.ts +0 -13
- package/src/planner/building/drop-view.ts +0 -19
- package/src/planner/building/expression.ts +0 -205
- package/src/planner/building/function-call.ts +0 -129
- package/src/planner/building/insert.ts +0 -435
- package/src/planner/building/pragma.ts +0 -34
- package/src/planner/building/schema-resolution.ts +0 -176
- package/src/planner/building/select-aggregates.ts +0 -318
- package/src/planner/building/select-compound.ts +0 -119
- package/src/planner/building/select-context.ts +0 -85
- package/src/planner/building/select-modifiers.ts +0 -236
- package/src/planner/building/select-projections.ts +0 -177
- package/src/planner/building/select-window.ts +0 -259
- package/src/planner/building/select.ts +0 -567
- package/src/planner/building/table-function.ts +0 -49
- package/src/planner/building/table.ts +0 -40
- package/src/planner/building/transaction.ts +0 -23
- package/src/planner/building/update.ts +0 -331
- package/src/planner/building/with.ts +0 -180
- package/src/planner/cache/correlation-detector.ts +0 -83
- package/src/planner/cache/materialization-advisory.ts +0 -265
- package/src/planner/cache/reference-graph.ts +0 -196
- package/src/planner/cost/index.ts +0 -169
- package/src/planner/debug/logger-utils.ts +0 -68
- package/src/planner/debug.ts +0 -480
- package/src/planner/framework/README.md +0 -132
- package/src/planner/framework/characteristics.ts +0 -503
- package/src/planner/framework/context.ts +0 -239
- package/src/planner/framework/pass.ts +0 -354
- package/src/planner/framework/physical-utils.ts +0 -210
- package/src/planner/framework/registry.ts +0 -261
- package/src/planner/framework/trace.ts +0 -259
- package/src/planner/nodes/add-constraint-node.ts +0 -62
- package/src/planner/nodes/aggregate-function.ts +0 -155
- package/src/planner/nodes/aggregate-node.ts +0 -267
- package/src/planner/nodes/array-index-node.ts +0 -50
- package/src/planner/nodes/block.ts +0 -80
- package/src/planner/nodes/cache-node.ts +0 -103
- package/src/planner/nodes/constraint-check-node.ts +0 -138
- package/src/planner/nodes/create-assertion-node.ts +0 -51
- package/src/planner/nodes/create-index-node.ts +0 -41
- package/src/planner/nodes/create-table-node.ts +0 -35
- package/src/planner/nodes/create-view-node.ts +0 -44
- package/src/planner/nodes/cte-node.ts +0 -168
- package/src/planner/nodes/cte-reference-node.ts +0 -125
- package/src/planner/nodes/declarative-schema.ts +0 -221
- package/src/planner/nodes/delete-node.ts +0 -102
- package/src/planner/nodes/distinct-node.ts +0 -107
- package/src/planner/nodes/dml-executor-node.ts +0 -104
- package/src/planner/nodes/drop-assertion-node.ts +0 -50
- package/src/planner/nodes/drop-table-node.ts +0 -36
- package/src/planner/nodes/drop-view-node.ts +0 -37
- package/src/planner/nodes/filter.ts +0 -144
- package/src/planner/nodes/function.ts +0 -98
- package/src/planner/nodes/insert-node.ts +0 -126
- package/src/planner/nodes/internal-recursive-cte-ref-node.ts +0 -61
- package/src/planner/nodes/join-node.ts +0 -336
- package/src/planner/nodes/limit-offset.ts +0 -144
- package/src/planner/nodes/plan-node-type.ts +0 -95
- package/src/planner/nodes/plan-node.ts +0 -503
- package/src/planner/nodes/pragma.ts +0 -98
- package/src/planner/nodes/project-node.ts +0 -337
- package/src/planner/nodes/recursive-cte-node.ts +0 -158
- package/src/planner/nodes/reference.ts +0 -334
- package/src/planner/nodes/remote-query-node.ts +0 -73
- package/src/planner/nodes/retrieve-node.ts +0 -86
- package/src/planner/nodes/returning-node.ts +0 -269
- package/src/planner/nodes/scalar.ts +0 -772
- package/src/planner/nodes/sequencing-node.ts +0 -113
- package/src/planner/nodes/set-operation-node.ts +0 -87
- package/src/planner/nodes/single-row.ts +0 -85
- package/src/planner/nodes/sink-node.ts +0 -61
- package/src/planner/nodes/sort.ts +0 -166
- package/src/planner/nodes/stream-aggregate.ts +0 -293
- package/src/planner/nodes/subquery.ts +0 -268
- package/src/planner/nodes/table-access-nodes.ts +0 -323
- package/src/planner/nodes/table-function-call.ts +0 -134
- package/src/planner/nodes/transaction-node.ts +0 -55
- package/src/planner/nodes/update-node.ts +0 -138
- package/src/planner/nodes/values-node.ts +0 -244
- package/src/planner/nodes/view-reference-node.ts +0 -97
- package/src/planner/nodes/window-function.ts +0 -73
- package/src/planner/nodes/window-node.ts +0 -199
- package/src/planner/optimizer-tuning.ts +0 -105
- package/src/planner/optimizer.ts +0 -332
- package/src/planner/planning-context.ts +0 -190
- package/src/planner/resolve.ts +0 -101
- package/src/planner/rules/README.md +0 -96
- package/src/planner/rules/access/rule-select-access-path.ts +0 -399
- package/src/planner/rules/aggregate/rule-aggregate-streaming.ts +0 -162
- package/src/planner/rules/cache/rule-cte-optimization.ts +0 -79
- package/src/planner/rules/cache/rule-materialization-advisory.ts +0 -77
- package/src/planner/rules/cache/rule-mutating-subquery-cache.ts +0 -104
- package/src/planner/rules/join/rule-join-greedy-commute.ts +0 -48
- package/src/planner/rules/join/rule-join-key-inference.ts +0 -35
- package/src/planner/rules/join/rule-quickpick-enumeration.ts +0 -267
- package/src/planner/rules/predicate/rule-predicate-pushdown.ts +0 -144
- package/src/planner/rules/retrieve/rule-grow-retrieve.ts +0 -337
- package/src/planner/scopes/aliased.ts +0 -50
- package/src/planner/scopes/base.ts +0 -10
- package/src/planner/scopes/empty.ts +0 -12
- package/src/planner/scopes/global.ts +0 -73
- package/src/planner/scopes/multi.ts +0 -40
- package/src/planner/scopes/param.ts +0 -95
- package/src/planner/scopes/registered.ts +0 -67
- package/src/planner/scopes/scope.ts +0 -16
- package/src/planner/stats/basic-estimates.ts +0 -107
- package/src/planner/stats/index.ts +0 -158
- package/src/planner/type-utils.ts +0 -87
- package/src/planner/util/key-utils.ts +0 -46
- package/src/planner/validation/determinism-validator.ts +0 -104
- package/src/planner/validation/plan-validator.ts +0 -335
- package/src/runtime/async-util.ts +0 -283
- package/src/runtime/cache/shared-cache.ts +0 -169
- package/src/runtime/context-helpers.ts +0 -191
- package/src/runtime/deferred-constraint-queue.ts +0 -196
- package/src/runtime/emission-context.ts +0 -319
- package/src/runtime/emit/add-constraint.ts +0 -78
- package/src/runtime/emit/aggregate.ts +0 -581
- package/src/runtime/emit/array-index.ts +0 -25
- package/src/runtime/emit/between.ts +0 -51
- package/src/runtime/emit/binary.ts +0 -357
- package/src/runtime/emit/block.ts +0 -23
- package/src/runtime/emit/cache.ts +0 -64
- package/src/runtime/emit/case.ts +0 -87
- package/src/runtime/emit/cast.ts +0 -151
- package/src/runtime/emit/collate.ts +0 -9
- package/src/runtime/emit/column-reference.ts +0 -17
- package/src/runtime/emit/constraint-check.ts +0 -290
- package/src/runtime/emit/create-assertion.ts +0 -82
- package/src/runtime/emit/create-index.ts +0 -15
- package/src/runtime/emit/create-table.ts +0 -15
- package/src/runtime/emit/create-view.ts +0 -52
- package/src/runtime/emit/cte-reference.ts +0 -38
- package/src/runtime/emit/cte.ts +0 -39
- package/src/runtime/emit/delete.ts +0 -24
- package/src/runtime/emit/distinct.ts +0 -40
- package/src/runtime/emit/dml-executor.ts +0 -198
- package/src/runtime/emit/drop-assertion.ts +0 -45
- package/src/runtime/emit/drop-table.ts +0 -27
- package/src/runtime/emit/drop-view.ts +0 -49
- package/src/runtime/emit/filter.ts +0 -30
- package/src/runtime/emit/insert.ts +0 -42
- package/src/runtime/emit/internal-recursive-cte-ref.ts +0 -37
- package/src/runtime/emit/join.ts +0 -148
- package/src/runtime/emit/limit-offset.ts +0 -73
- package/src/runtime/emit/literal.ts +0 -17
- package/src/runtime/emit/parameter.ts +0 -59
- package/src/runtime/emit/pragma.ts +0 -56
- package/src/runtime/emit/project.ts +0 -46
- package/src/runtime/emit/recursive-cte.ts +0 -111
- package/src/runtime/emit/remote-query.ts +0 -47
- package/src/runtime/emit/retrieve.ts +0 -15
- package/src/runtime/emit/returning.ts +0 -41
- package/src/runtime/emit/scalar-function.ts +0 -69
- package/src/runtime/emit/scan.ts +0 -106
- package/src/runtime/emit/schema-declarative.ts +0 -215
- package/src/runtime/emit/sequencing.ts +0 -24
- package/src/runtime/emit/set-operation.ts +0 -141
- package/src/runtime/emit/sink.ts +0 -27
- package/src/runtime/emit/sort.ts +0 -75
- package/src/runtime/emit/subquery.ts +0 -203
- package/src/runtime/emit/table-valued-function.ts +0 -106
- package/src/runtime/emit/temporal-arithmetic.ts +0 -302
- package/src/runtime/emit/transaction.ts +0 -205
- package/src/runtime/emit/unary.ts +0 -101
- package/src/runtime/emit/update.ts +0 -66
- package/src/runtime/emit/values.ts +0 -66
- package/src/runtime/emit/window-function.ts +0 -42
- package/src/runtime/emit/window.ts +0 -458
- package/src/runtime/emitters.ts +0 -183
- package/src/runtime/register.ts +0 -150
- package/src/runtime/scheduler.ts +0 -488
- package/src/runtime/types.ts +0 -242
- package/src/runtime/utils.ts +0 -177
- package/src/schema/assertion.ts +0 -21
- package/src/schema/catalog.ts +0 -269
- package/src/schema/change-events.ts +0 -80
- package/src/schema/column.ts +0 -51
- package/src/schema/declared-schema-manager.ts +0 -82
- package/src/schema/function.ts +0 -188
- package/src/schema/manager.ts +0 -1034
- package/src/schema/schema-differ.ts +0 -214
- package/src/schema/schema-hasher.ts +0 -26
- package/src/schema/schema.ts +0 -222
- package/src/schema/table.ts +0 -409
- package/src/schema/view.ts +0 -19
- package/src/schema/window-function.ts +0 -56
- package/src/types/builtin-types.ts +0 -350
- package/src/types/index.ts +0 -17
- package/src/types/json-type.ts +0 -152
- package/src/types/logical-type.ts +0 -91
- package/src/types/plugin-interface.ts +0 -10
- package/src/types/registry.ts +0 -204
- package/src/types/temporal-types.ts +0 -290
- package/src/types/validation.ts +0 -120
- package/src/util/affinity.ts +0 -151
- package/src/util/ast-stringify.ts +0 -887
- package/src/util/cached.ts +0 -25
- package/src/util/coercion.ts +0 -113
- package/src/util/comparison.ts +0 -510
- package/src/util/environment.ts +0 -52
- package/src/util/hash.ts +0 -90
- package/src/util/latches.ts +0 -47
- package/src/util/mutation-statement.ts +0 -135
- package/src/util/patterns.ts +0 -56
- package/src/util/plan-formatter.ts +0 -48
- package/src/util/plugin-helper.ts +0 -110
- package/src/util/row-descriptor.ts +0 -105
- package/src/util/serialization.ts +0 -47
- package/src/util/sql-literal.ts +0 -22
- package/src/util/working-table-iterable.ts +0 -38
- package/src/vtab/best-access-plan.ts +0 -244
- package/src/vtab/connection.ts +0 -36
- package/src/vtab/filter-info.ts +0 -23
- package/src/vtab/index-info.ts +0 -84
- package/src/vtab/manifest.ts +0 -86
- package/src/vtab/memory/connection.ts +0 -73
- package/src/vtab/memory/index.ts +0 -191
- package/src/vtab/memory/layer/base-cursor.ts +0 -124
- package/src/vtab/memory/layer/base.ts +0 -275
- package/src/vtab/memory/layer/connection.ts +0 -203
- package/src/vtab/memory/layer/interface.ts +0 -47
- package/src/vtab/memory/layer/manager.ts +0 -909
- package/src/vtab/memory/layer/safe-iterate.ts +0 -49
- package/src/vtab/memory/layer/scan-plan.ts +0 -84
- package/src/vtab/memory/layer/transaction-cursor.ts +0 -162
- package/src/vtab/memory/layer/transaction.ts +0 -229
- package/src/vtab/memory/module.ts +0 -667
- package/src/vtab/memory/table.ts +0 -251
- package/src/vtab/memory/types.ts +0 -23
- package/src/vtab/memory/utils/logging.ts +0 -36
- package/src/vtab/memory/utils/primary-key.ts +0 -163
- package/src/vtab/module.ts +0 -162
- package/src/vtab/table.ts +0 -177
package/src/core/database.ts
DELETED
|
@@ -1,1461 +0,0 @@
|
|
|
1
|
-
import { createLogger } from '../common/logger.js';
|
|
2
|
-
import { MisuseError, quereusError, QuereusError } from '../common/errors.js';
|
|
3
|
-
import { StatusCode, type SqlParameters, type SqlValue, type Row, type OutputValue } from '../common/types.js';
|
|
4
|
-
import type { ScalarType } from '../common/datatype.js';
|
|
5
|
-
import type { AnyVirtualTableModule } from '../vtab/module.js';
|
|
6
|
-
import { Statement } from './statement.js';
|
|
7
|
-
import { SchemaManager } from '../schema/manager.js';
|
|
8
|
-
import type { TableSchema } from '../schema/table.js';
|
|
9
|
-
import type { FunctionSchema } from '../schema/function.js';
|
|
10
|
-
import { BUILTIN_FUNCTIONS } from '../func/builtins/index.js';
|
|
11
|
-
import { createScalarFunction, createAggregateFunction } from '../func/registration.js';
|
|
12
|
-
import { FunctionFlags } from '../common/constants.js';
|
|
13
|
-
import { MemoryTableModule } from '../vtab/memory/module.js';
|
|
14
|
-
import type { VirtualTableConnection } from '../vtab/connection.js';
|
|
15
|
-
import { BINARY_COLLATION, getCollation, NOCASE_COLLATION, registerCollation, RTRIM_COLLATION, type CollationFunction } from '../util/comparison.js';
|
|
16
|
-
import { Parser, ParseError } from '../parser/parser.js';
|
|
17
|
-
import * as AST from '../parser/ast.js';
|
|
18
|
-
import { buildBlock } from '../planner/building/block.js';
|
|
19
|
-
import { emitPlanNode } from '../runtime/emitters.js';
|
|
20
|
-
import { Scheduler } from '../runtime/scheduler.js';
|
|
21
|
-
import type { RuntimeContext } from '../runtime/types.js';
|
|
22
|
-
import type { RowDescriptor } from '../planner/nodes/plan-node.js';
|
|
23
|
-
import { BlockNode } from '../planner/nodes/block.js';
|
|
24
|
-
import type { PlanningContext } from '../planner/planning-context.js';
|
|
25
|
-
import { BuildTimeDependencyTracker } from '../planner/planning-context.js';
|
|
26
|
-
import { ParameterScope } from '../planner/scopes/param.js';
|
|
27
|
-
import { GlobalScope } from '../planner/scopes/global.js';
|
|
28
|
-
import { PlanNode, type RelationalPlanNode, type ScalarPlanNode } from '../planner/nodes/plan-node.js';
|
|
29
|
-
import { FilterNode } from '../planner/nodes/filter.js';
|
|
30
|
-
import { BinaryOpNode } from '../planner/nodes/scalar.js';
|
|
31
|
-
import { ParameterReferenceNode, ColumnReferenceNode, TableReferenceNode } from '../planner/nodes/reference.js';
|
|
32
|
-
import { registerEmitters } from '../runtime/register.js';
|
|
33
|
-
import { serializePlanTree, formatPlanTree } from '../planner/debug.js';
|
|
34
|
-
import type { DebugOptions } from '../planner/planning-context.js';
|
|
35
|
-
import { EmissionContext } from '../runtime/emission-context.js';
|
|
36
|
-
import { Optimizer, DEFAULT_TUNING } from '../planner/optimizer.js';
|
|
37
|
-
import type { OptimizerTuning } from '../planner/optimizer-tuning.js';
|
|
38
|
-
import { registerBuiltinWindowFunctions } from '../func/builtins/builtin-window-functions.js';
|
|
39
|
-
import { DatabaseOptionsManager } from './database-options.js';
|
|
40
|
-
import type { InstructionTracer } from '../runtime/types.js';
|
|
41
|
-
import { isAsyncIterable } from '../runtime/utils.js';
|
|
42
|
-
import { DeclaredSchemaManager } from '../schema/declared-schema-manager.js';
|
|
43
|
-
import { analyzeRowSpecific } from '../planner/analysis/constraint-extractor.js';
|
|
44
|
-
import { DeferredConstraintQueue } from '../runtime/deferred-constraint-queue.js';
|
|
45
|
-
import { type LogicalType } from '../types/logical-type.js';
|
|
46
|
-
import { getParameterTypes } from './param.js';
|
|
47
|
-
|
|
48
|
-
const log = createLogger('core:database');
|
|
49
|
-
const warnLog = log.extend('warn');
|
|
50
|
-
const errorLog = log.extend('error');
|
|
51
|
-
const debugLog = log.extend('debug');
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Represents a connection to an Quereus database (in-memory in this port).
|
|
55
|
-
* Manages schema, prepared statements, virtual tables, and functions.
|
|
56
|
-
*/
|
|
57
|
-
export class Database {
|
|
58
|
-
public readonly schemaManager: SchemaManager;
|
|
59
|
-
public readonly declaredSchemaManager: DeclaredSchemaManager;
|
|
60
|
-
private isOpen = true;
|
|
61
|
-
private statements = new Set<Statement>();
|
|
62
|
-
private isAutocommit = true; // Manages transaction state
|
|
63
|
-
private inTransaction = false;
|
|
64
|
-
private activeConnections = new Map<string, VirtualTableConnection>();
|
|
65
|
-
private inImplicitTransaction = false; // Track if we're in an implicit transaction
|
|
66
|
-
public readonly optimizer: Optimizer;
|
|
67
|
-
public readonly options: DatabaseOptionsManager;
|
|
68
|
-
private instructionTracer: InstructionTracer | undefined;
|
|
69
|
-
/** Per-transaction change tracking: base table name → serialized PK tuples */
|
|
70
|
-
private changeLog: Map<string, Set<string>> = new Map();
|
|
71
|
-
/** Savepoint layers for change tracking */
|
|
72
|
-
private changeLogLayers: Array<Map<string, Set<string>>> = [];
|
|
73
|
-
/** Deferred constraint evaluation queue */
|
|
74
|
-
private readonly deferredConstraints = new DeferredConstraintQueue(this);
|
|
75
|
-
|
|
76
|
-
constructor() {
|
|
77
|
-
this.schemaManager = new SchemaManager(this);
|
|
78
|
-
this.declaredSchemaManager = new DeclaredSchemaManager();
|
|
79
|
-
this.options = new DatabaseOptionsManager();
|
|
80
|
-
log("Database instance created.");
|
|
81
|
-
|
|
82
|
-
// Register built-in functions
|
|
83
|
-
this.registerBuiltinFunctions();
|
|
84
|
-
|
|
85
|
-
// Register default virtual table modules via SchemaManager
|
|
86
|
-
// The SchemaManager.defaultVTabModuleName is already initialized (e.g. to 'memory')
|
|
87
|
-
// No need to set defaultVtabModuleName explicitly here unless it's different from SchemaManager's init value.
|
|
88
|
-
// this.schemaManager.setDefaultVTabModuleName('memory'); // Already 'memory' by default in SchemaManager
|
|
89
|
-
// this.schemaManager.setDefaultVTabArgs([]); // Already [] by default in SchemaManager
|
|
90
|
-
|
|
91
|
-
this.schemaManager.registerModule('memory', new MemoryTableModule());
|
|
92
|
-
|
|
93
|
-
// Register built-in collations
|
|
94
|
-
this.registerDefaultCollations();
|
|
95
|
-
|
|
96
|
-
// Register built-in window functions
|
|
97
|
-
registerBuiltinWindowFunctions();
|
|
98
|
-
|
|
99
|
-
registerEmitters();
|
|
100
|
-
|
|
101
|
-
// Initialize optimizer with default tuning
|
|
102
|
-
this.optimizer = new Optimizer(DEFAULT_TUNING);
|
|
103
|
-
|
|
104
|
-
// Set up option change listeners
|
|
105
|
-
this.setupOptionListeners();
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/** @internal Set up listeners for option changes */
|
|
109
|
-
private setupOptionListeners(): void {
|
|
110
|
-
// Register core database options with their change handlers
|
|
111
|
-
this.options.registerOption('runtime_stats', {
|
|
112
|
-
type: 'boolean',
|
|
113
|
-
defaultValue: false,
|
|
114
|
-
aliases: ['runtime_metrics'],
|
|
115
|
-
description: 'Enable runtime execution statistics collection'
|
|
116
|
-
// No onChange needed - consumed directly when creating RuntimeContext
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
this.options.registerOption('validate_plan', {
|
|
120
|
-
type: 'boolean',
|
|
121
|
-
defaultValue: false,
|
|
122
|
-
aliases: ['plan_validation'],
|
|
123
|
-
description: 'Enable plan validation before execution',
|
|
124
|
-
onChange: (event) => {
|
|
125
|
-
const newTuning = {
|
|
126
|
-
...this.optimizer.tuning,
|
|
127
|
-
debug: {
|
|
128
|
-
...this.optimizer.tuning.debug,
|
|
129
|
-
validatePlan: event.newValue as boolean
|
|
130
|
-
}
|
|
131
|
-
};
|
|
132
|
-
this.updateOptimizerTuning(newTuning as OptimizerTuning);
|
|
133
|
-
log('Optimizer tuning updated with validate_plan = %s', event.newValue);
|
|
134
|
-
}
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
this.options.registerOption('default_vtab_module', {
|
|
138
|
-
type: 'string',
|
|
139
|
-
defaultValue: 'memory',
|
|
140
|
-
description: 'Default virtual table module name',
|
|
141
|
-
onChange: (event) => {
|
|
142
|
-
this.schemaManager.setDefaultVTabModuleName(event.newValue as string);
|
|
143
|
-
}
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
this.options.registerOption('default_vtab_args', {
|
|
147
|
-
type: 'object',
|
|
148
|
-
defaultValue: {},
|
|
149
|
-
description: 'Default virtual table module arguments',
|
|
150
|
-
onChange: (event) => {
|
|
151
|
-
this.schemaManager.setDefaultVTabArgs(event.newValue as Record<string, SqlValue>);
|
|
152
|
-
}
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
this.options.registerOption('default_column_nullability', {
|
|
156
|
-
type: 'string',
|
|
157
|
-
defaultValue: 'not_null',
|
|
158
|
-
aliases: ['column_nullability_default', 'nullable_default'],
|
|
159
|
-
description: 'Default nullability for columns: "nullable" (SQL standard) or "not_null" (Third Manifesto)',
|
|
160
|
-
onChange: (event) => {
|
|
161
|
-
const value = event.newValue as string;
|
|
162
|
-
if (value !== 'nullable' && value !== 'not_null') {
|
|
163
|
-
throw new QuereusError(`Invalid default_column_nullability value: ${value}. Must be "nullable" or "not_null"`, StatusCode.ERROR);
|
|
164
|
-
}
|
|
165
|
-
log('Default column nullability changed to: %s', value);
|
|
166
|
-
}
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
this.options.registerOption('trace_plan_stack', {
|
|
170
|
-
type: 'boolean',
|
|
171
|
-
defaultValue: false,
|
|
172
|
-
description: 'Enable plan stack tracing',
|
|
173
|
-
});
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
/** @internal Registers default built-in SQL functions */
|
|
177
|
-
private registerBuiltinFunctions(): void {
|
|
178
|
-
const mainSchema = this.schemaManager.getMainSchema();
|
|
179
|
-
BUILTIN_FUNCTIONS.forEach(funcDef => {
|
|
180
|
-
try {
|
|
181
|
-
mainSchema.addFunction(funcDef);
|
|
182
|
-
} catch (e) {
|
|
183
|
-
errorLog(`Failed to register built-in function ${funcDef.name}/${funcDef.numArgs}: %O`, e);
|
|
184
|
-
}
|
|
185
|
-
});
|
|
186
|
-
log(`Registered ${BUILTIN_FUNCTIONS.length} built-in functions.`);
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
/** @internal Registers default collation sequences */
|
|
190
|
-
private registerDefaultCollations(): void {
|
|
191
|
-
// Register the built-in collations
|
|
192
|
-
registerCollation('BINARY', BINARY_COLLATION);
|
|
193
|
-
registerCollation('NOCASE', NOCASE_COLLATION);
|
|
194
|
-
registerCollation('RTRIM', RTRIM_COLLATION);
|
|
195
|
-
log("Default collations registered (BINARY, NOCASE, RTRIM)");
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
/**
|
|
199
|
-
* Prepares an SQL statement for execution.
|
|
200
|
-
*
|
|
201
|
-
* @param sql The SQL string to prepare.
|
|
202
|
-
* @param paramsOrTypes Optional parameter values (to infer types) or explicit type map.
|
|
203
|
-
* - If SqlParameters: Parameter types are inferred from the values
|
|
204
|
-
* - If Map<string|number, ScalarType>: Explicit type hints for parameters
|
|
205
|
-
* - If undefined: Parameters default to TEXT type
|
|
206
|
-
* @returns A Statement object.
|
|
207
|
-
* @throws QuereusError on failure (e.g., syntax error).
|
|
208
|
-
*
|
|
209
|
-
* @example
|
|
210
|
-
* // Infer types from initial values
|
|
211
|
-
* const stmt = db.prepare('INSERT INTO users (id, name) VALUES (?, ?)', [1, 'Alice']);
|
|
212
|
-
*
|
|
213
|
-
* @example
|
|
214
|
-
* // Explicit param types
|
|
215
|
-
* const types = new Map([
|
|
216
|
-
* [1, { typeClass: 'scalar', logicalType: INTEGER_TYPE, nullable: false }],
|
|
217
|
-
* [2, { typeClass: 'scalar', logicalType: TEXT_TYPE, nullable: false }]
|
|
218
|
-
* ]);
|
|
219
|
-
* const stmt = db.prepare('INSERT INTO users (id, name) VALUES (?, ?)', types);
|
|
220
|
-
*/
|
|
221
|
-
prepare(sql: string, paramsOrTypes?: SqlParameters | SqlValue[] | Map<string | number, ScalarType>): Statement {
|
|
222
|
-
this.checkOpen();
|
|
223
|
-
log('Preparing SQL (new runtime): %s', sql);
|
|
224
|
-
|
|
225
|
-
// Statement constructor defers planning/compilation until first step or explicit compile()
|
|
226
|
-
const stmt = new Statement(this, sql, 0, paramsOrTypes);
|
|
227
|
-
|
|
228
|
-
this.statements.add(stmt);
|
|
229
|
-
return stmt;
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
/**
|
|
233
|
-
* Executes a query and returns the first result row as an object.
|
|
234
|
-
* @param sql The SQL query string to execute.
|
|
235
|
-
* @param params Optional parameters to bind.
|
|
236
|
-
* @returns A Promise resolving to the first result row as an object, or undefined if no rows.
|
|
237
|
-
* @throws QuereusError on failure.
|
|
238
|
-
*/
|
|
239
|
-
get(sql: string, params?: SqlParameters | SqlValue[]): Promise<Record<string, SqlValue> | undefined> {
|
|
240
|
-
const stmt = this.prepare(sql, params);
|
|
241
|
-
return stmt.get(params);
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
/**
|
|
245
|
-
* Executes one or more SQL statements directly.
|
|
246
|
-
* @param sql The SQL string(s) to execute.
|
|
247
|
-
* @param params Optional parameters to bind.
|
|
248
|
-
* @returns A Promise resolving when execution completes.
|
|
249
|
-
* @throws QuereusError on failure.
|
|
250
|
-
*/
|
|
251
|
-
/**
|
|
252
|
-
* @internal
|
|
253
|
-
* Executes a single AST statement without transaction management.
|
|
254
|
-
* Used by both exec() and eval() to avoid code duplication.
|
|
255
|
-
*/
|
|
256
|
-
private async _executeStatement(statementAst: AST.Statement, params?: SqlParameters | SqlValue[]): Promise<void> {
|
|
257
|
-
const plan = this._buildPlan([statementAst], params);
|
|
258
|
-
|
|
259
|
-
if (plan.statements.length === 0) return; // No-op for this AST
|
|
260
|
-
|
|
261
|
-
const optimizedPlan = this.optimizer.optimize(plan, this) as BlockNode;
|
|
262
|
-
const emissionContext = new EmissionContext(this);
|
|
263
|
-
const rootInstruction = emitPlanNode(optimizedPlan, emissionContext);
|
|
264
|
-
const scheduler = new Scheduler(rootInstruction);
|
|
265
|
-
|
|
266
|
-
const runtimeCtx: RuntimeContext = {
|
|
267
|
-
db: this,
|
|
268
|
-
stmt: undefined,
|
|
269
|
-
params: params ?? {},
|
|
270
|
-
context: new Map(),
|
|
271
|
-
tableContexts: new Map(),
|
|
272
|
-
tracer: this.instructionTracer,
|
|
273
|
-
enableMetrics: this.options.getBooleanOption('runtime_stats'),
|
|
274
|
-
};
|
|
275
|
-
|
|
276
|
-
await scheduler.run(runtimeCtx);
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
async exec(
|
|
280
|
-
sql: string,
|
|
281
|
-
params?: SqlParameters,
|
|
282
|
-
): Promise<void> {
|
|
283
|
-
this.checkOpen();
|
|
284
|
-
|
|
285
|
-
log('Executing SQL block (new runtime): %s', sql);
|
|
286
|
-
|
|
287
|
-
const parser = new Parser();
|
|
288
|
-
let batch: AST.Statement[];
|
|
289
|
-
try {
|
|
290
|
-
batch = parser.parseAll(sql);
|
|
291
|
-
} catch (e) {
|
|
292
|
-
if (e instanceof ParseError) throw new QuereusError(`Parse error: ${e.message}`, StatusCode.ERROR, e);
|
|
293
|
-
throw e;
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
if (batch.length === 0) return;
|
|
297
|
-
|
|
298
|
-
const needsImplicitTransaction = batch.length >= 1
|
|
299
|
-
&& this.isAutocommit
|
|
300
|
-
// has explicit transaction
|
|
301
|
-
&& !batch.some(
|
|
302
|
-
ast => ast.type === 'begin' || ast.type === 'commit' || ast.type === 'rollback' || ast.type === 'savepoint' || ast.type === 'release'
|
|
303
|
-
);
|
|
304
|
-
|
|
305
|
-
let executionError: Error | null = null;
|
|
306
|
-
try {
|
|
307
|
-
if (needsImplicitTransaction) {
|
|
308
|
-
await this.beginImplicitTransaction();
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
for (let i = 0; i < batch.length; i++) {
|
|
312
|
-
try {
|
|
313
|
-
await this._executeStatement(batch[i], params);
|
|
314
|
-
} catch (err) {
|
|
315
|
-
const error = err instanceof Error ? err : new Error(String(err));
|
|
316
|
-
executionError = error instanceof QuereusError ? error : new QuereusError(error.message, StatusCode.ERROR, error);
|
|
317
|
-
break; // Stop processing further statements on error
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
} finally {
|
|
322
|
-
if (needsImplicitTransaction) {
|
|
323
|
-
if (executionError) {
|
|
324
|
-
await this.rollbackImplicitTransaction();
|
|
325
|
-
} else {
|
|
326
|
-
await this.commitImplicitTransaction();
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
if (executionError) {
|
|
332
|
-
throw executionError;
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
/**
|
|
337
|
-
* Registers a virtual table module.
|
|
338
|
-
* @param name The name of the module.
|
|
339
|
-
* @param module The module implementation.
|
|
340
|
-
* @param auxData Optional client data passed to create/connect.
|
|
341
|
-
*/
|
|
342
|
-
registerVtabModule(name: string, module: AnyVirtualTableModule, auxData?: unknown): void {
|
|
343
|
-
this.checkOpen();
|
|
344
|
-
this.schemaManager.registerModule(name, module, auxData);
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
/**
|
|
348
|
-
* Begins a transaction.
|
|
349
|
-
*/
|
|
350
|
-
async beginTransaction(): Promise<void> {
|
|
351
|
-
this.checkOpen();
|
|
352
|
-
|
|
353
|
-
if (this.inTransaction) {
|
|
354
|
-
throw new QuereusError("Transaction already active", StatusCode.ERROR);
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
await this.exec("BEGIN TRANSACTION");
|
|
358
|
-
this.inTransaction = true;
|
|
359
|
-
this.isAutocommit = false;
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
/**
|
|
363
|
-
* Commits the current transaction.
|
|
364
|
-
*/
|
|
365
|
-
async commit(): Promise<void> {
|
|
366
|
-
this.checkOpen();
|
|
367
|
-
|
|
368
|
-
if (!this.inTransaction) {
|
|
369
|
-
throw new QuereusError("No transaction active", StatusCode.ERROR);
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
await this.exec("COMMIT");
|
|
373
|
-
this.inTransaction = false;
|
|
374
|
-
this.isAutocommit = true;
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
/**
|
|
378
|
-
* Rolls back the current transaction.
|
|
379
|
-
*/
|
|
380
|
-
async rollback(): Promise<void> {
|
|
381
|
-
this.checkOpen();
|
|
382
|
-
|
|
383
|
-
if (!this.inTransaction) {
|
|
384
|
-
throw new QuereusError("No transaction active", StatusCode.ERROR);
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
await this.exec("ROLLBACK");
|
|
388
|
-
this.inTransaction = false;
|
|
389
|
-
this.isAutocommit = true;
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
/**
|
|
393
|
-
* Closes the database connection and releases resources.
|
|
394
|
-
* @returns A promise resolving on completion.
|
|
395
|
-
*/
|
|
396
|
-
async close(): Promise<void> {
|
|
397
|
-
if (!this.isOpen) {
|
|
398
|
-
return;
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
log("Closing database...");
|
|
402
|
-
this.isOpen = false;
|
|
403
|
-
|
|
404
|
-
// Disconnect all active connections first
|
|
405
|
-
await this.disconnectAllConnections();
|
|
406
|
-
|
|
407
|
-
// Finalize all prepared statements
|
|
408
|
-
const finalizePromises = Array.from(this.statements).map(stmt => stmt.finalize());
|
|
409
|
-
await Promise.allSettled(finalizePromises); // Wait even if some fail
|
|
410
|
-
this.statements.clear();
|
|
411
|
-
|
|
412
|
-
// Clear schemas, ensuring VTabs are potentially disconnected
|
|
413
|
-
// This will also call destroy on VTabs via SchemaManager.clearAll -> schema.clearTables -> schemaManager.dropTable
|
|
414
|
-
this.schemaManager.clearAll();
|
|
415
|
-
|
|
416
|
-
// this.registeredVTabs.clear(); // Removed, SchemaManager handles module lifecycle
|
|
417
|
-
log("Database closed.");
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
/** @internal Called by Statement when it's finalized */
|
|
421
|
-
_statementFinalized(stmt: Statement): void {
|
|
422
|
-
this.statements.delete(stmt);
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
/**
|
|
426
|
-
* Checks if the database connection is in autocommit mode.
|
|
427
|
-
*/
|
|
428
|
-
getAutocommit(): boolean {
|
|
429
|
-
this.checkOpen();
|
|
430
|
-
return this.isAutocommit;
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
/**
|
|
434
|
-
* Programmatically defines or replaces a table in the 'main' schema.
|
|
435
|
-
* This is an alternative/supplement to using `CREATE TABLE`.
|
|
436
|
-
* @param definition The schema definition for the table.
|
|
437
|
-
*/
|
|
438
|
-
defineTable(definition: TableSchema): void {
|
|
439
|
-
this.checkOpen();
|
|
440
|
-
if (definition.schemaName !== 'main') {
|
|
441
|
-
throw new MisuseError("Programmatic definition only supported for 'main' schema currently");
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
this.schemaManager.getMainSchema().addTable(definition);
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
/**
|
|
448
|
-
* Registers a user-defined scalar function.
|
|
449
|
-
*
|
|
450
|
-
* @param name The name of the SQL function.
|
|
451
|
-
* @param options Configuration: { numArgs: number, deterministic?: boolean, flags?: number }.
|
|
452
|
-
* @param func The JavaScript function implementation.
|
|
453
|
-
*/
|
|
454
|
-
createScalarFunction(
|
|
455
|
-
name: string,
|
|
456
|
-
options: {
|
|
457
|
-
numArgs: number;
|
|
458
|
-
deterministic?: boolean;
|
|
459
|
-
flags?: number;
|
|
460
|
-
},
|
|
461
|
-
func: (...args: SqlValue[]) => SqlValue
|
|
462
|
-
): void {
|
|
463
|
-
this.checkOpen();
|
|
464
|
-
|
|
465
|
-
const baseFlags = (options.deterministic ? FunctionFlags.DETERMINISTIC : 0) | FunctionFlags.UTF8;
|
|
466
|
-
const flags = options.flags ?? baseFlags;
|
|
467
|
-
|
|
468
|
-
const schema = createScalarFunction(
|
|
469
|
-
{ name, numArgs: options.numArgs, flags },
|
|
470
|
-
func
|
|
471
|
-
);
|
|
472
|
-
|
|
473
|
-
try {
|
|
474
|
-
this.schemaManager.getMainSchema().addFunction(schema);
|
|
475
|
-
} catch (e) {
|
|
476
|
-
errorLog(`Failed to register scalar function ${name}/${options.numArgs}: %O`, e);
|
|
477
|
-
if (e instanceof Error) throw e; else quereusError(String(e));
|
|
478
|
-
}
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
/**
|
|
482
|
-
* Registers a user-defined aggregate function.
|
|
483
|
-
*
|
|
484
|
-
* @param name The name of the SQL function.
|
|
485
|
-
* @param options Configuration: { numArgs: number, flags?: number, initialState?: unknown }.
|
|
486
|
-
* @param stepFunc The function called for each row (accumulator, ...args) => newAccumulator.
|
|
487
|
-
* @param finalFunc The function called at the end (accumulator) => finalResult.
|
|
488
|
-
*/
|
|
489
|
-
createAggregateFunction(
|
|
490
|
-
name: string,
|
|
491
|
-
options: {
|
|
492
|
-
numArgs: number;
|
|
493
|
-
flags?: number;
|
|
494
|
-
initialState?: unknown;
|
|
495
|
-
},
|
|
496
|
-
stepFunc: (acc: unknown, ...args: SqlValue[]) => unknown,
|
|
497
|
-
finalFunc: (acc: unknown) => SqlValue
|
|
498
|
-
): void {
|
|
499
|
-
this.checkOpen();
|
|
500
|
-
|
|
501
|
-
const flags = options.flags ?? FunctionFlags.UTF8;
|
|
502
|
-
|
|
503
|
-
const schema = createAggregateFunction(
|
|
504
|
-
{ name, numArgs: options.numArgs, flags, initialValue: options.initialState },
|
|
505
|
-
stepFunc,
|
|
506
|
-
finalFunc
|
|
507
|
-
);
|
|
508
|
-
|
|
509
|
-
try {
|
|
510
|
-
this.schemaManager.getMainSchema().addFunction(schema);
|
|
511
|
-
} catch (e) {
|
|
512
|
-
errorLog(`Failed to register aggregate function ${name}/${options.numArgs}: %O`, e);
|
|
513
|
-
if (e instanceof Error) throw e; else quereusError(String(e));
|
|
514
|
-
}
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
/**
|
|
518
|
-
* Registers a function using a pre-defined FunctionSchema.
|
|
519
|
-
* This is the lower-level registration method.
|
|
520
|
-
*
|
|
521
|
-
* @param schema The FunctionSchema object describing the function.
|
|
522
|
-
*/
|
|
523
|
-
registerFunction(schema: FunctionSchema): void {
|
|
524
|
-
this.checkOpen();
|
|
525
|
-
try {
|
|
526
|
-
this.schemaManager.getMainSchema().addFunction(schema);
|
|
527
|
-
} catch (e) {
|
|
528
|
-
errorLog(`Failed to register function ${schema.name}/${schema.numArgs}: %O`, e);
|
|
529
|
-
if (e instanceof Error) throw e; else quereusError(String(e));
|
|
530
|
-
}
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
/** Sets only the name of the default module. */
|
|
534
|
-
setDefaultVtabName(name: string): void {
|
|
535
|
-
this.checkOpen();
|
|
536
|
-
this.schemaManager.setDefaultVTabModuleName(name);
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
/** Sets the default args directly. */
|
|
540
|
-
setDefaultVtabArgs(args: Record<string, SqlValue>): void {
|
|
541
|
-
this.checkOpen();
|
|
542
|
-
this.schemaManager.setDefaultVTabArgs(args);
|
|
543
|
-
}
|
|
544
|
-
|
|
545
|
-
/** @internal Sets the default args by parsing a JSON string. Should be managed by SchemaManager now. */
|
|
546
|
-
setDefaultVtabArgsFromJson(argsJsonString: string): void {
|
|
547
|
-
this.checkOpen();
|
|
548
|
-
this.schemaManager.setDefaultVTabArgsFromJson(argsJsonString);
|
|
549
|
-
}
|
|
550
|
-
|
|
551
|
-
/**
|
|
552
|
-
* Gets the default virtual table module name and arguments.
|
|
553
|
-
* @returns An object containing the module name and arguments.
|
|
554
|
-
*/
|
|
555
|
-
getDefaultVtabModule(): { name: string; args: Record<string, SqlValue> } {
|
|
556
|
-
this.checkOpen();
|
|
557
|
-
return this.schemaManager.getDefaultVTabModule();
|
|
558
|
-
}
|
|
559
|
-
|
|
560
|
-
/**
|
|
561
|
-
* Set database configuration options
|
|
562
|
-
* @param option The option name
|
|
563
|
-
* @param value The option value
|
|
564
|
-
*/
|
|
565
|
-
setOption(option: string, value: unknown): void {
|
|
566
|
-
this.checkOpen();
|
|
567
|
-
this.options.setOption(option, value);
|
|
568
|
-
}
|
|
569
|
-
|
|
570
|
-
/**
|
|
571
|
-
* Get database configuration option value
|
|
572
|
-
* @param option The option name
|
|
573
|
-
* @returns The option value
|
|
574
|
-
*/
|
|
575
|
-
getOption(option: string): unknown {
|
|
576
|
-
this.checkOpen();
|
|
577
|
-
return this.options.getOption(option);
|
|
578
|
-
}
|
|
579
|
-
|
|
580
|
-
/** Update optimizer tuning in place */
|
|
581
|
-
private updateOptimizerTuning(tuning: OptimizerTuning): void {
|
|
582
|
-
this.optimizer.updateTuning(tuning);
|
|
583
|
-
}
|
|
584
|
-
|
|
585
|
-
/**
|
|
586
|
-
* Registers a user-defined collation sequence.
|
|
587
|
-
* @param name The name of the collation sequence (case-insensitive).
|
|
588
|
-
* @param func The comparison function (a, b) => number (-1, 0, 1).
|
|
589
|
-
* @example
|
|
590
|
-
* // Example: Create a custom collation for phone numbers
|
|
591
|
-
* db.registerCollation('PHONENUMBER', (a, b) => {
|
|
592
|
-
* // Normalize phone numbers by removing non-digit characters
|
|
593
|
-
* const normalize = (phone) => phone.replace(/\D/g, '');
|
|
594
|
-
* const numA = normalize(a);
|
|
595
|
-
* const numB = normalize(b);
|
|
596
|
-
* return numA < numB ? -1 : numA > numB ? 1 : 0;
|
|
597
|
-
* });
|
|
598
|
-
*
|
|
599
|
-
* // Then use it in SQL:
|
|
600
|
-
* // SELECT * FROM contacts ORDER BY phone COLLATE PHONENUMBER;
|
|
601
|
-
*/
|
|
602
|
-
registerCollation(name: string, func: CollationFunction): void {
|
|
603
|
-
this.checkOpen();
|
|
604
|
-
registerCollation(name, func);
|
|
605
|
-
log('Registered collation: %s', name);
|
|
606
|
-
}
|
|
607
|
-
|
|
608
|
-
/**
|
|
609
|
-
* Registers a custom logical type.
|
|
610
|
-
* @param name The name of the type (case-insensitive).
|
|
611
|
-
* @param definition The LogicalType implementation.
|
|
612
|
-
* @example
|
|
613
|
-
* // Example: Create a custom UUID type
|
|
614
|
-
* db.registerType('UUID', {
|
|
615
|
-
* name: 'UUID',
|
|
616
|
-
* physicalType: PhysicalType.TEXT,
|
|
617
|
-
* validate: (v) => typeof v === 'string' && /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(v),
|
|
618
|
-
* parse: (v) => typeof v === 'string' ? v.toLowerCase() : v,
|
|
619
|
-
* });
|
|
620
|
-
*
|
|
621
|
-
* // Then use it in SQL:
|
|
622
|
-
* // CREATE TABLE users (id UUID PRIMARY KEY, name TEXT);
|
|
623
|
-
*/
|
|
624
|
-
registerType(name: string, definition: LogicalType): void {
|
|
625
|
-
this.checkOpen();
|
|
626
|
-
const { registerType } = require('../types/registry.js');
|
|
627
|
-
registerType(name, definition);
|
|
628
|
-
log('Registered type: %s', name);
|
|
629
|
-
}
|
|
630
|
-
|
|
631
|
-
/**
|
|
632
|
-
* Sets the instruction tracer for this database.
|
|
633
|
-
* The tracer will be used for all statement executions.
|
|
634
|
-
* @param tracer The instruction tracer to use, or null to disable tracing.
|
|
635
|
-
*/
|
|
636
|
-
setInstructionTracer(tracer: InstructionTracer | undefined): void {
|
|
637
|
-
this.instructionTracer = tracer;
|
|
638
|
-
log('Instruction tracer %s', tracer ? 'enabled' : 'disabled');
|
|
639
|
-
}
|
|
640
|
-
|
|
641
|
-
/**
|
|
642
|
-
* Gets the current instruction tracer for this database.
|
|
643
|
-
* @returns The instruction tracer, or undefined if none is set.
|
|
644
|
-
*/
|
|
645
|
-
getInstructionTracer(): InstructionTracer | undefined {
|
|
646
|
-
return this.instructionTracer;
|
|
647
|
-
}
|
|
648
|
-
|
|
649
|
-
/** @internal Gets a registered collation function */
|
|
650
|
-
_getCollation(name: string): CollationFunction | undefined {
|
|
651
|
-
return getCollation(name);
|
|
652
|
-
}
|
|
653
|
-
|
|
654
|
-
/** Serialize a composite primary key tuple for set storage */
|
|
655
|
-
private serializeKeyTuple(values: SqlValue[]): string {
|
|
656
|
-
// JSON serialization is sufficient because SqlValue is JSON-safe in this engine
|
|
657
|
-
return JSON.stringify(values);
|
|
658
|
-
}
|
|
659
|
-
|
|
660
|
-
/** Add a key tuple to the current change log for a base table */
|
|
661
|
-
private addChange(baseTable: string, keyTuple: SqlValue[]): void {
|
|
662
|
-
const target = this.changeLogLayers.length > 0
|
|
663
|
-
? this.changeLogLayers[this.changeLogLayers.length - 1]
|
|
664
|
-
: this.changeLog;
|
|
665
|
-
const key = baseTable.toLowerCase();
|
|
666
|
-
if (!target.has(key)) target.set(key, new Set());
|
|
667
|
-
target.get(key)!.add(this.serializeKeyTuple(keyTuple));
|
|
668
|
-
}
|
|
669
|
-
|
|
670
|
-
public _queueDeferredConstraintRow(baseTable: string, constraintName: string, row: Row, descriptor: RowDescriptor, evaluator: (ctx: RuntimeContext) => OutputValue, connectionId?: string, contextRow?: Row, contextDescriptor?: RowDescriptor): void {
|
|
671
|
-
this.deferredConstraints.enqueue(baseTable, constraintName, row, descriptor, evaluator, connectionId, contextRow, contextDescriptor);
|
|
672
|
-
}
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
/** @internal Flag to prevent new connections from starting transactions during constraint evaluation */
|
|
676
|
-
private evaluatingDeferredConstraints = false;
|
|
677
|
-
/** @internal Flag indicating we're in a coordinated multi-connection commit */
|
|
678
|
-
private inCoordinatedCommit = false;
|
|
679
|
-
|
|
680
|
-
public async runDeferredRowConstraints(): Promise<void> {
|
|
681
|
-
this.evaluatingDeferredConstraints = true;
|
|
682
|
-
try {
|
|
683
|
-
await this.deferredConstraints.runDeferredRows();
|
|
684
|
-
} finally {
|
|
685
|
-
this.evaluatingDeferredConstraints = false;
|
|
686
|
-
}
|
|
687
|
-
}
|
|
688
|
-
|
|
689
|
-
/** @internal Check if we should skip auto-beginning transactions on newly registered connections */
|
|
690
|
-
public _isEvaluatingDeferredConstraints(): boolean {
|
|
691
|
-
return this.evaluatingDeferredConstraints;
|
|
692
|
-
}
|
|
693
|
-
|
|
694
|
-
/** @internal Mark start of coordinated multi-connection commit */
|
|
695
|
-
public _beginCoordinatedCommit(): void {
|
|
696
|
-
this.inCoordinatedCommit = true;
|
|
697
|
-
}
|
|
698
|
-
|
|
699
|
-
/** @internal Mark end of coordinated multi-connection commit */
|
|
700
|
-
public _endCoordinatedCommit(): void {
|
|
701
|
-
this.inCoordinatedCommit = false;
|
|
702
|
-
}
|
|
703
|
-
|
|
704
|
-
/** @internal Check if we're in a coordinated commit (allows sibling layer validation) */
|
|
705
|
-
public _inCoordinatedCommit(): boolean {
|
|
706
|
-
return this.inCoordinatedCommit;
|
|
707
|
-
}
|
|
708
|
-
|
|
709
|
-
/** Public API used by DML emitters to record changes */
|
|
710
|
-
public _recordInsert(baseTable: string, newKey: SqlValue[]): void {
|
|
711
|
-
this.addChange(baseTable, newKey);
|
|
712
|
-
}
|
|
713
|
-
|
|
714
|
-
public _recordDelete(baseTable: string, oldKey: SqlValue[]): void {
|
|
715
|
-
this.addChange(baseTable, oldKey);
|
|
716
|
-
}
|
|
717
|
-
|
|
718
|
-
public _recordUpdate(baseTable: string, oldKey: SqlValue[], newKey: SqlValue[]): void {
|
|
719
|
-
this.addChange(baseTable, oldKey);
|
|
720
|
-
// If the PK changed, also record the new key
|
|
721
|
-
if (this.serializeKeyTuple(oldKey) !== this.serializeKeyTuple(newKey)) {
|
|
722
|
-
this.addChange(baseTable, newKey);
|
|
723
|
-
}
|
|
724
|
-
}
|
|
725
|
-
|
|
726
|
-
/** Savepoint change tracking */
|
|
727
|
-
public _beginSavepointLayer(): void {
|
|
728
|
-
this.changeLogLayers.push(new Map());
|
|
729
|
-
this.deferredConstraints.beginLayer();
|
|
730
|
-
}
|
|
731
|
-
|
|
732
|
-
public _rollbackSavepointLayer(): void {
|
|
733
|
-
// Discard the top layer
|
|
734
|
-
this.changeLogLayers.pop();
|
|
735
|
-
this.deferredConstraints.rollbackLayer();
|
|
736
|
-
}
|
|
737
|
-
|
|
738
|
-
public _releaseSavepointLayer(): void {
|
|
739
|
-
// Merge the top layer into previous or main log
|
|
740
|
-
const top = this.changeLogLayers.pop();
|
|
741
|
-
if (!top) return;
|
|
742
|
-
const target = this.changeLogLayers.length > 0 ? this.changeLogLayers[this.changeLogLayers.length - 1] : this.changeLog;
|
|
743
|
-
for (const [table, set] of top) {
|
|
744
|
-
if (!target.has(table)) target.set(table, new Set());
|
|
745
|
-
const tgt = target.get(table)!;
|
|
746
|
-
for (const k of set) tgt.add(k);
|
|
747
|
-
}
|
|
748
|
-
this.deferredConstraints.releaseLayer();
|
|
749
|
-
}
|
|
750
|
-
|
|
751
|
-
private getChangedBaseTables(): Set<string> {
|
|
752
|
-
const result = new Set<string>();
|
|
753
|
-
const collect = (m: Map<string, Set<string>>) => {
|
|
754
|
-
for (const [t, s] of m) { if (s.size > 0) result.add(t); }
|
|
755
|
-
};
|
|
756
|
-
collect(this.changeLog);
|
|
757
|
-
for (const layer of this.changeLogLayers) collect(layer);
|
|
758
|
-
return result;
|
|
759
|
-
}
|
|
760
|
-
|
|
761
|
-
public _clearChangeLog(): void {
|
|
762
|
-
this.changeLog.clear();
|
|
763
|
-
this.changeLogLayers = [];
|
|
764
|
-
this.deferredConstraints.clear();
|
|
765
|
-
}
|
|
766
|
-
|
|
767
|
-
/**
|
|
768
|
-
* Marks that an explicit SQL BEGIN has started a transaction.
|
|
769
|
-
* Ensures subsequently registered connections also begin a transaction.
|
|
770
|
-
*/
|
|
771
|
-
public markExplicitTransactionStart(): void {
|
|
772
|
-
this.inTransaction = true;
|
|
773
|
-
this.isAutocommit = false;
|
|
774
|
-
}
|
|
775
|
-
|
|
776
|
-
/**
|
|
777
|
-
* Marks that an explicit SQL COMMIT/ROLLBACK has ended the transaction.
|
|
778
|
-
*/
|
|
779
|
-
public markExplicitTransactionEnd(): void {
|
|
780
|
-
this.inTransaction = false;
|
|
781
|
-
this.isAutocommit = true;
|
|
782
|
-
}
|
|
783
|
-
|
|
784
|
-
/**
|
|
785
|
-
* Prepares, binds parameters, executes, and yields result rows for a query.
|
|
786
|
-
* This is a high-level convenience method for iterating over query results.
|
|
787
|
-
* The underlying statement is automatically finalized when iteration completes
|
|
788
|
-
* or if an error occurs.
|
|
789
|
-
*
|
|
790
|
-
* @param sql The SQL query string to execute.
|
|
791
|
-
* @param params Optional parameters to bind (array for positional, object for named).
|
|
792
|
-
* @yields Each result row as an object (`Record<string, SqlValue>`).
|
|
793
|
-
* @returns An `AsyncIterableIterator` yielding result rows.
|
|
794
|
-
* @throws MisuseError if the database is closed.
|
|
795
|
-
* @throws QuereusError on prepare/bind/execution errors.
|
|
796
|
-
*
|
|
797
|
-
* @example
|
|
798
|
-
* ```typescript
|
|
799
|
-
* try {
|
|
800
|
-
* for await (const user of db.eval("SELECT * FROM users WHERE status = ?", ["active"])) {
|
|
801
|
-
* console.log(`Active user: ${user.name}`);
|
|
802
|
-
* }
|
|
803
|
-
* } catch (e) {
|
|
804
|
-
* console.error("Query failed:", e);
|
|
805
|
-
* }
|
|
806
|
-
* ```
|
|
807
|
-
*/
|
|
808
|
-
async *eval(sql: string, params?: SqlParameters | SqlValue[]): AsyncIterable<Record<string, SqlValue>> {
|
|
809
|
-
this.checkOpen();
|
|
810
|
-
|
|
811
|
-
let stmt: Statement | null = null;
|
|
812
|
-
try {
|
|
813
|
-
stmt = this.prepare(sql);
|
|
814
|
-
|
|
815
|
-
if (stmt.astBatch.length === 0) {
|
|
816
|
-
// No statements, yield nothing.
|
|
817
|
-
return;
|
|
818
|
-
}
|
|
819
|
-
|
|
820
|
-
if (stmt.astBatch.length > 1) {
|
|
821
|
-
// Multi-statement batch: execute all but the last statement,
|
|
822
|
-
// then yield results from the last statement
|
|
823
|
-
const parser = new Parser();
|
|
824
|
-
const batch = parser.parseAll(sql);
|
|
825
|
-
|
|
826
|
-
// Execute all statements except the last one
|
|
827
|
-
for (let i = 0; i < batch.length - 1; i++) {
|
|
828
|
-
await this._executeStatement(batch[i], params);
|
|
829
|
-
}
|
|
830
|
-
|
|
831
|
-
// Now prepare and execute the last statement to yield its results
|
|
832
|
-
const lastStmt = new Statement(this, [batch[batch.length - 1]]);
|
|
833
|
-
this.statements.add(lastStmt);
|
|
834
|
-
try {
|
|
835
|
-
yield* lastStmt.all(params);
|
|
836
|
-
} finally {
|
|
837
|
-
await lastStmt.finalize();
|
|
838
|
-
}
|
|
839
|
-
} else {
|
|
840
|
-
// Single statement: execute and yield results
|
|
841
|
-
yield* stmt.all(params);
|
|
842
|
-
}
|
|
843
|
-
} finally {
|
|
844
|
-
if (stmt) { await stmt.finalize(); }
|
|
845
|
-
}
|
|
846
|
-
}
|
|
847
|
-
|
|
848
|
-
getPlan(sqlOrAst: string | AST.AstNode): PlanNode {
|
|
849
|
-
this.checkOpen();
|
|
850
|
-
|
|
851
|
-
let ast: AST.AstNode;
|
|
852
|
-
let originalSqlString: string | undefined = undefined;
|
|
853
|
-
|
|
854
|
-
if (typeof sqlOrAst === 'string') {
|
|
855
|
-
originalSqlString = sqlOrAst;
|
|
856
|
-
const parser = new Parser();
|
|
857
|
-
try {
|
|
858
|
-
ast = parser.parse(originalSqlString);
|
|
859
|
-
} catch (err) {
|
|
860
|
-
const error = err instanceof Error ? err : new Error(String(err));
|
|
861
|
-
errorLog("Failed to parse SQL for query plan: %O", error);
|
|
862
|
-
throw error;
|
|
863
|
-
}
|
|
864
|
-
} else {
|
|
865
|
-
ast = sqlOrAst;
|
|
866
|
-
}
|
|
867
|
-
|
|
868
|
-
const plan = this._buildPlan([ast as AST.Statement]);
|
|
869
|
-
|
|
870
|
-
if (plan.statements.length === 0) return plan; // No-op for this AST
|
|
871
|
-
|
|
872
|
-
return this.optimizer.optimize(plan, this) as BlockNode;
|
|
873
|
-
}
|
|
874
|
-
|
|
875
|
-
/**
|
|
876
|
-
* Gets a detailed representation of the query plan for debugging.
|
|
877
|
-
* @param sql The SQL statement to plan.
|
|
878
|
-
* @param options Optional formatting options. If not provided, uses concise tree format.
|
|
879
|
-
* @returns String containing the formatted plan tree.
|
|
880
|
-
*/
|
|
881
|
-
getDebugPlan(sql: string, options?: { verbose?: boolean; expandNodes?: string[]; maxDepth?: number }): string {
|
|
882
|
-
this.checkOpen();
|
|
883
|
-
const plan = this.getPlan(sql);
|
|
884
|
-
|
|
885
|
-
if (options?.verbose) {
|
|
886
|
-
// Use the original detailed JSON format
|
|
887
|
-
return serializePlanTree(plan);
|
|
888
|
-
} else {
|
|
889
|
-
// Use the new concise tree format
|
|
890
|
-
return formatPlanTree(plan, {
|
|
891
|
-
concise: true,
|
|
892
|
-
expandNodes: options?.expandNodes || [],
|
|
893
|
-
maxDepth: options?.maxDepth,
|
|
894
|
-
showPhysical: true
|
|
895
|
-
});
|
|
896
|
-
}
|
|
897
|
-
}
|
|
898
|
-
|
|
899
|
-
/**
|
|
900
|
-
* Prepares a statement with debug options enabled.
|
|
901
|
-
* @param sql The SQL statement to prepare.
|
|
902
|
-
* @param debug Debug options to enable.
|
|
903
|
-
* @returns A Statement with debug capabilities.
|
|
904
|
-
*/
|
|
905
|
-
prepareDebug(sql: string, debug: DebugOptions): Statement {
|
|
906
|
-
this.checkOpen();
|
|
907
|
-
log('Preparing SQL with debug options: %s', sql);
|
|
908
|
-
|
|
909
|
-
const stmt = new Statement(this, sql);
|
|
910
|
-
// Set debug options on the statement
|
|
911
|
-
(stmt as Statement & { _debugOptions?: DebugOptions })._debugOptions = debug;
|
|
912
|
-
|
|
913
|
-
this.statements.add(stmt);
|
|
914
|
-
return stmt;
|
|
915
|
-
}
|
|
916
|
-
|
|
917
|
-
/** @internal */
|
|
918
|
-
_getVtabModule(name: string): { module: AnyVirtualTableModule, auxData?: unknown } | undefined {
|
|
919
|
-
// Delegate to SchemaManager
|
|
920
|
-
return this.schemaManager.getModule(name);
|
|
921
|
-
// return this.registeredVTabs.get(name.toLowerCase()); // Old implementation
|
|
922
|
-
}
|
|
923
|
-
|
|
924
|
-
/** @internal */
|
|
925
|
-
_findTable(tableName: string, dbName?: string): TableSchema | undefined {
|
|
926
|
-
return this.schemaManager.findTable(tableName, dbName);
|
|
927
|
-
}
|
|
928
|
-
|
|
929
|
-
/** @internal */
|
|
930
|
-
_findFunction(funcName: string, nArg: number): FunctionSchema | undefined {
|
|
931
|
-
return this.schemaManager.findFunction(funcName, nArg);
|
|
932
|
-
}
|
|
933
|
-
|
|
934
|
-
/** @internal */
|
|
935
|
-
_buildPlan(statements: AST.Statement[], paramsOrTypes?: SqlParameters | SqlValue[] | Map<string | number, ScalarType>) {
|
|
936
|
-
const globalScope = new GlobalScope(this.schemaManager);
|
|
937
|
-
|
|
938
|
-
// If we received parameter values, infer their types
|
|
939
|
-
// If we received explicit parameter types, use them as-is
|
|
940
|
-
const parameterTypes = paramsOrTypes instanceof Map
|
|
941
|
-
? paramsOrTypes
|
|
942
|
-
: getParameterTypes(paramsOrTypes);
|
|
943
|
-
|
|
944
|
-
// This ParameterScope is for the entire batch. It has globalScope as its parent.
|
|
945
|
-
const parameterScope = new ParameterScope(globalScope, parameterTypes);
|
|
946
|
-
|
|
947
|
-
const ctx: PlanningContext = {
|
|
948
|
-
db: this,
|
|
949
|
-
schemaManager: this.schemaManager,
|
|
950
|
-
parameters: paramsOrTypes instanceof Map ? {} : (paramsOrTypes ?? {}),
|
|
951
|
-
scope: parameterScope,
|
|
952
|
-
cteNodes: new Map(),
|
|
953
|
-
schemaDependencies: new BuildTimeDependencyTracker(),
|
|
954
|
-
schemaCache: new Map(),
|
|
955
|
-
cteReferenceCache: new Map(),
|
|
956
|
-
outputScopes: new Map()
|
|
957
|
-
};
|
|
958
|
-
|
|
959
|
-
return buildBlock(ctx, statements);
|
|
960
|
-
}
|
|
961
|
-
|
|
962
|
-
/**
|
|
963
|
-
* @internal Registers an active VirtualTable connection for transaction management.
|
|
964
|
-
* @param connection The connection to register
|
|
965
|
-
*/
|
|
966
|
-
async registerConnection(connection: VirtualTableConnection): Promise<void> {
|
|
967
|
-
this.activeConnections.set(connection.connectionId, connection);
|
|
968
|
-
debugLog(`Registered connection ${connection.connectionId} for table ${connection.tableName}`);
|
|
969
|
-
|
|
970
|
-
// If we're already in a transaction (implicit or explicit),
|
|
971
|
-
// start a transaction on this new connection UNLESS we're evaluating deferred constraints
|
|
972
|
-
// (during which subqueries should read committed state without creating new transaction layers)
|
|
973
|
-
if (this.inTransaction && !this.evaluatingDeferredConstraints) {
|
|
974
|
-
try {
|
|
975
|
-
await connection.begin();
|
|
976
|
-
debugLog(`Started transaction on newly registered connection ${connection.connectionId}`);
|
|
977
|
-
} catch (error) {
|
|
978
|
-
errorLog(`Error starting transaction on newly registered connection ${connection.connectionId}: %O`, error);
|
|
979
|
-
// Don't throw here - just log the error to avoid breaking connection registration
|
|
980
|
-
}
|
|
981
|
-
} else if (this.evaluatingDeferredConstraints) {
|
|
982
|
-
debugLog(`Skipped transaction begin on connection ${connection.connectionId} (evaluating deferred constraints)`);
|
|
983
|
-
}
|
|
984
|
-
}
|
|
985
|
-
|
|
986
|
-
/**
|
|
987
|
-
* @internal Unregisters an active VirtualTable connection.
|
|
988
|
-
* @param connectionId The ID of the connection to unregister
|
|
989
|
-
*/
|
|
990
|
-
unregisterConnection(connectionId: string): void {
|
|
991
|
-
const connection = this.activeConnections.get(connectionId);
|
|
992
|
-
if (connection) {
|
|
993
|
-
// Don't disconnect during implicit transactions - let the transaction coordinate
|
|
994
|
-
if (this.inImplicitTransaction) {
|
|
995
|
-
debugLog(`Deferring disconnect of connection ${connectionId} until implicit transaction completes`);
|
|
996
|
-
return;
|
|
997
|
-
}
|
|
998
|
-
|
|
999
|
-
this.activeConnections.delete(connectionId);
|
|
1000
|
-
debugLog(`Unregistered connection ${connectionId} for table ${connection.tableName}`);
|
|
1001
|
-
}
|
|
1002
|
-
}
|
|
1003
|
-
|
|
1004
|
-
/**
|
|
1005
|
-
* @internal Gets an active connection by ID.
|
|
1006
|
-
* @param connectionId The connection ID to look up
|
|
1007
|
-
* @returns The connection if found, undefined otherwise
|
|
1008
|
-
*/
|
|
1009
|
-
getConnection(connectionId: string): VirtualTableConnection | undefined {
|
|
1010
|
-
return this.activeConnections.get(connectionId);
|
|
1011
|
-
}
|
|
1012
|
-
|
|
1013
|
-
/**
|
|
1014
|
-
* @internal Gets all active connections for a specific table.
|
|
1015
|
-
* @param tableName The name of the table
|
|
1016
|
-
* @returns Array of connections for the table
|
|
1017
|
-
*/
|
|
1018
|
-
getConnectionsForTable(tableName: string): VirtualTableConnection[] {
|
|
1019
|
-
const normalized = tableName.toLowerCase();
|
|
1020
|
-
const simpleName = normalized.includes('.') ? normalized.substring(normalized.lastIndexOf('.') + 1) : normalized;
|
|
1021
|
-
return Array.from(this.activeConnections.values())
|
|
1022
|
-
.filter(conn => {
|
|
1023
|
-
const connName = conn.tableName.toLowerCase();
|
|
1024
|
-
return connName === normalized || connName === simpleName;
|
|
1025
|
-
});
|
|
1026
|
-
}
|
|
1027
|
-
|
|
1028
|
-
/**
|
|
1029
|
-
* @internal Gets all active connections.
|
|
1030
|
-
* @returns Array of all active connections
|
|
1031
|
-
*/
|
|
1032
|
-
getAllConnections(): VirtualTableConnection[] {
|
|
1033
|
-
return Array.from(this.activeConnections.values());
|
|
1034
|
-
}
|
|
1035
|
-
|
|
1036
|
-
/**
|
|
1037
|
-
* Disconnects and removes all active connections.
|
|
1038
|
-
* Called during database close.
|
|
1039
|
-
*/
|
|
1040
|
-
private async disconnectAllConnections(): Promise<void> {
|
|
1041
|
-
const connections = Array.from(this.activeConnections.values());
|
|
1042
|
-
debugLog(`Disconnecting ${connections.length} active connections`);
|
|
1043
|
-
|
|
1044
|
-
const disconnectPromises = connections.map(async (conn) => {
|
|
1045
|
-
try {
|
|
1046
|
-
await conn.disconnect();
|
|
1047
|
-
} catch (error) {
|
|
1048
|
-
errorLog(`Error disconnecting connection ${conn.connectionId}: %O`, error);
|
|
1049
|
-
}
|
|
1050
|
-
});
|
|
1051
|
-
|
|
1052
|
-
await Promise.allSettled(disconnectPromises);
|
|
1053
|
-
this.activeConnections.clear();
|
|
1054
|
-
}
|
|
1055
|
-
|
|
1056
|
-
private checkOpen(): void {
|
|
1057
|
-
if (!this.isOpen) throw new MisuseError("Database is closed");
|
|
1058
|
-
}
|
|
1059
|
-
|
|
1060
|
-
/**
|
|
1061
|
-
* Begin an implicit transaction and coordinate with virtual table connections
|
|
1062
|
-
*/
|
|
1063
|
-
private async beginImplicitTransaction(): Promise<void> {
|
|
1064
|
-
debugLog("Database: Starting implicit transaction for multi-statement block.");
|
|
1065
|
-
|
|
1066
|
-
this.inImplicitTransaction = true;
|
|
1067
|
-
|
|
1068
|
-
// Begin transaction on all active connections first
|
|
1069
|
-
const connections = this.getAllConnections();
|
|
1070
|
-
for (const connection of connections) {
|
|
1071
|
-
try {
|
|
1072
|
-
await connection.begin();
|
|
1073
|
-
} catch (error) {
|
|
1074
|
-
errorLog(`Error beginning transaction on connection ${connection.connectionId}: %O`, error);
|
|
1075
|
-
throw error;
|
|
1076
|
-
}
|
|
1077
|
-
}
|
|
1078
|
-
|
|
1079
|
-
// Then set database state
|
|
1080
|
-
this.inTransaction = true;
|
|
1081
|
-
this.isAutocommit = false;
|
|
1082
|
-
}
|
|
1083
|
-
|
|
1084
|
-
/**
|
|
1085
|
-
* Commit an implicit transaction and coordinate with virtual table connections
|
|
1086
|
-
*/
|
|
1087
|
-
private async commitImplicitTransaction(): Promise<void> {
|
|
1088
|
-
debugLog("Database: Committing implicit transaction.");
|
|
1089
|
-
|
|
1090
|
-
try {
|
|
1091
|
-
const connectionsToCommit = this.getAllConnections();
|
|
1092
|
-
|
|
1093
|
-
// Evaluate global assertions and deferred row constraints BEFORE committing connections. If violated, rollback and abort.
|
|
1094
|
-
await this.runGlobalAssertions();
|
|
1095
|
-
await this.runDeferredRowConstraints();
|
|
1096
|
-
|
|
1097
|
-
// Mark coordinated commit to relax layer validation for sibling layers
|
|
1098
|
-
this._beginCoordinatedCommit();
|
|
1099
|
-
try {
|
|
1100
|
-
// Commit only the original connections (not any opened during constraint evaluation)
|
|
1101
|
-
// Commit sequentially to avoid race conditions with layer promotion
|
|
1102
|
-
for (const connection of connectionsToCommit) {
|
|
1103
|
-
try {
|
|
1104
|
-
await connection.commit();
|
|
1105
|
-
} catch (error) {
|
|
1106
|
-
errorLog(`Error committing transaction on connection ${connection.connectionId}: %O`, error);
|
|
1107
|
-
throw error;
|
|
1108
|
-
}
|
|
1109
|
-
}
|
|
1110
|
-
} finally {
|
|
1111
|
-
this._endCoordinatedCommit();
|
|
1112
|
-
}
|
|
1113
|
-
} catch (e) {
|
|
1114
|
-
// On pre-commit assertion failure (or commit error), rollback all connections
|
|
1115
|
-
const conns = this.getAllConnections();
|
|
1116
|
-
await Promise.allSettled(conns.map(c => c.rollback()));
|
|
1117
|
-
throw e;
|
|
1118
|
-
} finally {
|
|
1119
|
-
this.inTransaction = false;
|
|
1120
|
-
this.isAutocommit = true;
|
|
1121
|
-
this.inImplicitTransaction = false;
|
|
1122
|
-
this._clearChangeLog();
|
|
1123
|
-
}
|
|
1124
|
-
}
|
|
1125
|
-
|
|
1126
|
-
public async runGlobalAssertions(): Promise<void> {
|
|
1127
|
-
const assertions = this.schemaManager.getAllAssertions();
|
|
1128
|
-
if (assertions.length === 0) return;
|
|
1129
|
-
|
|
1130
|
-
// Only evaluate assertions impacted by changed base tables
|
|
1131
|
-
const changedBases = this.getChangedBaseTables();
|
|
1132
|
-
if (changedBases.size === 0) return;
|
|
1133
|
-
|
|
1134
|
-
for (const assertion of assertions) {
|
|
1135
|
-
const planSql = assertion.violationSql;
|
|
1136
|
-
const parser = new Parser();
|
|
1137
|
-
let ast: AST.Statement;
|
|
1138
|
-
try {
|
|
1139
|
-
ast = parser.parse(planSql) as AST.Statement;
|
|
1140
|
-
} catch (err) {
|
|
1141
|
-
const error = err instanceof Error ? err : new Error(String(err));
|
|
1142
|
-
throw new QuereusError(
|
|
1143
|
-
`Failed to parse deferred assertion '${assertion.name}': ${error.message}`,
|
|
1144
|
-
StatusCode.INTERNAL,
|
|
1145
|
-
error
|
|
1146
|
-
);
|
|
1147
|
-
}
|
|
1148
|
-
const plan = this._buildPlan([ast]) as BlockNode;
|
|
1149
|
-
const analyzed = this.optimizer.optimizeForAnalysis(plan, this) as BlockNode;
|
|
1150
|
-
|
|
1151
|
-
// Collect base tables and relationKeys in this plan
|
|
1152
|
-
const relationKeyToBase = new Map<string, string>();
|
|
1153
|
-
const baseTablesInPlan = new Set<string>();
|
|
1154
|
-
this.collectTables(analyzed, relationKeyToBase, baseTablesInPlan);
|
|
1155
|
-
|
|
1156
|
-
// Determine impact: if assertion has no dependencies, treat as global and always impacted.
|
|
1157
|
-
const hasDeps = baseTablesInPlan.size > 0;
|
|
1158
|
-
let impacted = !hasDeps;
|
|
1159
|
-
if (hasDeps) {
|
|
1160
|
-
for (const b of baseTablesInPlan) { if (changedBases.has(b)) { impacted = true; break; } }
|
|
1161
|
-
}
|
|
1162
|
-
if (!impacted) continue;
|
|
1163
|
-
|
|
1164
|
-
// Classify instances as row/global
|
|
1165
|
-
const classifications: Map<string, 'row' | 'global'> = analyzeRowSpecific(analyzed as unknown as RelationalPlanNode);
|
|
1166
|
-
|
|
1167
|
-
// If any changed base appears as a global instance, run full violation query once
|
|
1168
|
-
let requiresGlobal = false;
|
|
1169
|
-
for (const [relKey, klass] of classifications) {
|
|
1170
|
-
if (klass === 'global') {
|
|
1171
|
-
const base = relationKeyToBase.get(relKey);
|
|
1172
|
-
if (base && changedBases.has(base)) { requiresGlobal = true; break; }
|
|
1173
|
-
}
|
|
1174
|
-
}
|
|
1175
|
-
|
|
1176
|
-
if (requiresGlobal) {
|
|
1177
|
-
await this.executeViolationOnce(assertion.name, assertion.violationSql);
|
|
1178
|
-
continue;
|
|
1179
|
-
}
|
|
1180
|
-
|
|
1181
|
-
// Collect row-specific references that correspond to changed bases
|
|
1182
|
-
const rowSpecificChanged: Array<{ relKey: string; base: string }> = [];
|
|
1183
|
-
for (const [relKey, klass] of classifications) {
|
|
1184
|
-
if (klass !== 'row') continue;
|
|
1185
|
-
const base = relationKeyToBase.get(relKey);
|
|
1186
|
-
if (base && changedBases.has(base)) rowSpecificChanged.push({ relKey, base });
|
|
1187
|
-
}
|
|
1188
|
-
|
|
1189
|
-
if (rowSpecificChanged.length === 0) {
|
|
1190
|
-
// No row-specific changed refs (or no refs at all) → run once globally.
|
|
1191
|
-
await this.executeViolationOnce(assertion.name, assertion.violationSql);
|
|
1192
|
-
continue;
|
|
1193
|
-
}
|
|
1194
|
-
|
|
1195
|
-
// Execute parameterized variants per changed key for each row-specific reference; early-exit on violation
|
|
1196
|
-
for (const { relKey, base } of rowSpecificChanged) {
|
|
1197
|
-
await this.executeViolationPerChangedKeys(assertion.name, assertion.violationSql, analyzed, relKey, base);
|
|
1198
|
-
}
|
|
1199
|
-
}
|
|
1200
|
-
}
|
|
1201
|
-
|
|
1202
|
-
private async executeViolationOnce(assertionName: string, sql: string): Promise<void> {
|
|
1203
|
-
const stmt = await this.prepare(sql);
|
|
1204
|
-
try {
|
|
1205
|
-
for await (const _ of stmt.all()) {
|
|
1206
|
-
throw new QuereusError(`Integrity assertion failed: ${assertionName}`, StatusCode.CONSTRAINT);
|
|
1207
|
-
}
|
|
1208
|
-
} finally {
|
|
1209
|
-
await stmt.finalize();
|
|
1210
|
-
}
|
|
1211
|
-
}
|
|
1212
|
-
|
|
1213
|
-
private async executeViolationOnceFromPlan(assertionName: string, plan: BlockNode): Promise<void> {
|
|
1214
|
-
const optimizedPlan = this.optimizer.optimize(plan, this) as BlockNode;
|
|
1215
|
-
const emissionContext = new EmissionContext(this);
|
|
1216
|
-
const rootInstruction = emitPlanNode(optimizedPlan, emissionContext);
|
|
1217
|
-
const scheduler = new Scheduler(rootInstruction);
|
|
1218
|
-
|
|
1219
|
-
const runtimeCtx: RuntimeContext = {
|
|
1220
|
-
db: this,
|
|
1221
|
-
stmt: undefined,
|
|
1222
|
-
params: {},
|
|
1223
|
-
context: new Map(),
|
|
1224
|
-
tableContexts: new Map(),
|
|
1225
|
-
tracer: this.instructionTracer,
|
|
1226
|
-
enableMetrics: this.options.getBooleanOption('runtime_stats'),
|
|
1227
|
-
};
|
|
1228
|
-
|
|
1229
|
-
const result = await scheduler.run(runtimeCtx);
|
|
1230
|
-
if (isAsyncIterable(result)) {
|
|
1231
|
-
for await (const _ of result as AsyncIterable<unknown>) {
|
|
1232
|
-
throw new QuereusError(`CHECK constraint failed: ${assertionName}`, StatusCode.CONSTRAINT);
|
|
1233
|
-
}
|
|
1234
|
-
}
|
|
1235
|
-
}
|
|
1236
|
-
|
|
1237
|
-
private async executeViolationPerChangedKeysFromPlan(
|
|
1238
|
-
assertionName: string,
|
|
1239
|
-
analyzed: BlockNode,
|
|
1240
|
-
targetRelationKey: string,
|
|
1241
|
-
base: string
|
|
1242
|
-
): Promise<void> {
|
|
1243
|
-
const changedKeyTuples = this.getChangedKeyTuples(base);
|
|
1244
|
-
if (changedKeyTuples.length === 0) return;
|
|
1245
|
-
|
|
1246
|
-
// Find PK indices for the base table
|
|
1247
|
-
const [schemaName, tableName] = base.split('.');
|
|
1248
|
-
const table = this._findTable(tableName, schemaName);
|
|
1249
|
-
if (!table) {
|
|
1250
|
-
throw new QuereusError(`Constraint references unknown table ${base}`, StatusCode.INTERNAL);
|
|
1251
|
-
}
|
|
1252
|
-
const pkIndices = table.primaryKeyDefinition.map(def => def.index);
|
|
1253
|
-
|
|
1254
|
-
// Prepare a rewritten plan with an injected Filter on the target relationKey
|
|
1255
|
-
const rewritten = this.injectPkFilter(analyzed, targetRelationKey, base, pkIndices);
|
|
1256
|
-
const optimizedPlan = this.optimizer.optimize(rewritten, this) as BlockNode;
|
|
1257
|
-
|
|
1258
|
-
// Emit and execute for each changed PK tuple; stop on first violation row.
|
|
1259
|
-
const emissionContext = new EmissionContext(this);
|
|
1260
|
-
const rootInstruction = emitPlanNode(optimizedPlan, emissionContext);
|
|
1261
|
-
const scheduler = new Scheduler(rootInstruction);
|
|
1262
|
-
|
|
1263
|
-
for (const tuple of changedKeyTuples) {
|
|
1264
|
-
const params: Record<string, SqlValue> = {};
|
|
1265
|
-
for (let i = 0; i < pkIndices.length; i++) {
|
|
1266
|
-
params[`pk${i}`] = tuple[i];
|
|
1267
|
-
}
|
|
1268
|
-
|
|
1269
|
-
const runtimeCtx: RuntimeContext = {
|
|
1270
|
-
db: this,
|
|
1271
|
-
stmt: undefined,
|
|
1272
|
-
params,
|
|
1273
|
-
context: new Map(),
|
|
1274
|
-
tableContexts: new Map(),
|
|
1275
|
-
tracer: this.instructionTracer,
|
|
1276
|
-
enableMetrics: this.options.getBooleanOption('runtime_stats'),
|
|
1277
|
-
};
|
|
1278
|
-
|
|
1279
|
-
// Run and detect first output row (violation)
|
|
1280
|
-
const result = await scheduler.run(runtimeCtx);
|
|
1281
|
-
if (isAsyncIterable(result)) {
|
|
1282
|
-
for await (const _ of result as AsyncIterable<unknown>) {
|
|
1283
|
-
throw new QuereusError(`CHECK constraint failed: ${assertionName}`, StatusCode.CONSTRAINT);
|
|
1284
|
-
}
|
|
1285
|
-
}
|
|
1286
|
-
}
|
|
1287
|
-
}
|
|
1288
|
-
|
|
1289
|
-
/** Execute a parameterized variant of the assertion once per changed key for a specific row-specific relationKey. */
|
|
1290
|
-
private async executeViolationPerChangedKeys(
|
|
1291
|
-
assertionName: string,
|
|
1292
|
-
violationSql: string,
|
|
1293
|
-
analyzed: BlockNode,
|
|
1294
|
-
targetRelationKey: string,
|
|
1295
|
-
base: string
|
|
1296
|
-
): Promise<void> {
|
|
1297
|
-
const changedKeyTuples = this.getChangedKeyTuples(base);
|
|
1298
|
-
if (changedKeyTuples.length === 0) return;
|
|
1299
|
-
|
|
1300
|
-
// Find PK indices for the base table
|
|
1301
|
-
const [schemaName, tableName] = base.split('.');
|
|
1302
|
-
const table = this._findTable(tableName, schemaName);
|
|
1303
|
-
if (!table) {
|
|
1304
|
-
throw new QuereusError(`Assertion references unknown table ${base}`, StatusCode.INTERNAL);
|
|
1305
|
-
}
|
|
1306
|
-
const pkIndices = table.primaryKeyDefinition.map(def => def.index);
|
|
1307
|
-
|
|
1308
|
-
// Prepare a rewritten plan with an injected Filter on the target relationKey
|
|
1309
|
-
const rewritten = this.injectPkFilter(analyzed, targetRelationKey, base, pkIndices);
|
|
1310
|
-
const optimizedPlan = this.optimizer.optimize(rewritten, this) as BlockNode;
|
|
1311
|
-
|
|
1312
|
-
// Emit and execute for each changed PK tuple; stop on first violation row.
|
|
1313
|
-
const emissionContext = new EmissionContext(this);
|
|
1314
|
-
const rootInstruction = emitPlanNode(optimizedPlan, emissionContext);
|
|
1315
|
-
const scheduler = new Scheduler(rootInstruction);
|
|
1316
|
-
|
|
1317
|
-
for (const tuple of changedKeyTuples) {
|
|
1318
|
-
const params: Record<string, SqlValue> = {};
|
|
1319
|
-
for (let i = 0; i < pkIndices.length; i++) {
|
|
1320
|
-
params[`pk${i}`] = tuple[i];
|
|
1321
|
-
}
|
|
1322
|
-
|
|
1323
|
-
const runtimeCtx: RuntimeContext = {
|
|
1324
|
-
db: this,
|
|
1325
|
-
stmt: undefined,
|
|
1326
|
-
params,
|
|
1327
|
-
context: new Map(),
|
|
1328
|
-
tableContexts: new Map(),
|
|
1329
|
-
tracer: this.instructionTracer,
|
|
1330
|
-
enableMetrics: this.options.getBooleanOption('runtime_stats'),
|
|
1331
|
-
};
|
|
1332
|
-
|
|
1333
|
-
// Run and detect first output row (violation)
|
|
1334
|
-
const result = await scheduler.run(runtimeCtx);
|
|
1335
|
-
if (isAsyncIterable(result)) {
|
|
1336
|
-
for await (const _ of result as AsyncIterable<unknown>) {
|
|
1337
|
-
throw new QuereusError(`Integrity assertion failed: ${assertionName}`, StatusCode.CONSTRAINT);
|
|
1338
|
-
}
|
|
1339
|
-
}
|
|
1340
|
-
}
|
|
1341
|
-
}
|
|
1342
|
-
|
|
1343
|
-
/** Gather all changed PK tuples for a base table across layers */
|
|
1344
|
-
private getChangedKeyTuples(base: string): SqlValue[][] {
|
|
1345
|
-
const lower = base.toLowerCase();
|
|
1346
|
-
const tuples: SqlValue[][] = [];
|
|
1347
|
-
const collect = (m: Map<string, Set<string>>): void => {
|
|
1348
|
-
const set = m.get(lower);
|
|
1349
|
-
if (!set) return;
|
|
1350
|
-
for (const s of set) tuples.push(JSON.parse(s) as SqlValue[]);
|
|
1351
|
-
};
|
|
1352
|
-
collect(this.changeLog);
|
|
1353
|
-
for (const layer of this.changeLogLayers) collect(layer);
|
|
1354
|
-
return tuples;
|
|
1355
|
-
}
|
|
1356
|
-
|
|
1357
|
-
/** Inject an equality Filter with named parameters :pk0, :pk1, ... at the earliest reference of targetRelationKey. */
|
|
1358
|
-
private injectPkFilter(block: BlockNode, targetRelationKey: string, base: string, pkIndices: number[]): BlockNode {
|
|
1359
|
-
const newStatements = block.getChildren().map(stmt => this.rewriteForPkFilter(stmt, targetRelationKey, base, pkIndices));
|
|
1360
|
-
if (newStatements.every((s, i) => s === block.getChildren()[i])) return block;
|
|
1361
|
-
return this.createBlockWithNewStatements(block, newStatements);
|
|
1362
|
-
}
|
|
1363
|
-
|
|
1364
|
-
private rewriteForPkFilter(node: PlanNode, targetRelationKey: string, base: string, pkIndices: number[]): PlanNode {
|
|
1365
|
-
// If this node is the target TableReference instance, wrap with a Filter
|
|
1366
|
-
const maybe = this.tryWrapTableReference(node, targetRelationKey, base, pkIndices);
|
|
1367
|
-
if (maybe) return maybe;
|
|
1368
|
-
|
|
1369
|
-
const originalChildren = node.getChildren();
|
|
1370
|
-
if (!originalChildren || originalChildren.length === 0) return node;
|
|
1371
|
-
const rewrittenChildren = originalChildren.map(child => this.rewriteForPkFilter(child, targetRelationKey, base, pkIndices));
|
|
1372
|
-
const changed = rewrittenChildren.some((c, i) => c !== originalChildren[i]);
|
|
1373
|
-
return changed ? node.withChildren(rewrittenChildren) : node;
|
|
1374
|
-
}
|
|
1375
|
-
|
|
1376
|
-
private tryWrapTableReference(node: PlanNode, targetRelationKey: string, base: string, pkIndices: number[]): PlanNode | null {
|
|
1377
|
-
if (!(node instanceof TableReferenceNode)) return null;
|
|
1378
|
-
const tableSchema = node.tableSchema;
|
|
1379
|
-
const schemaName = tableSchema.schemaName;
|
|
1380
|
-
const tableName = tableSchema.name;
|
|
1381
|
-
const relName = `${schemaName}.${tableName}`.toLowerCase();
|
|
1382
|
-
const relKey = `${relName}#${node.id ?? 'unknown'}`;
|
|
1383
|
-
if (relKey !== targetRelationKey) return null;
|
|
1384
|
-
|
|
1385
|
-
// Build predicate: AND(col_pk_i = :pk{i}) for all PK columns
|
|
1386
|
-
const relational = node as RelationalPlanNode;
|
|
1387
|
-
const scope = relational.scope;
|
|
1388
|
-
const attributes = relational.getAttributes();
|
|
1389
|
-
|
|
1390
|
-
const makeColumnRef = (colIndex: number): ScalarPlanNode => {
|
|
1391
|
-
const attr = attributes[colIndex];
|
|
1392
|
-
const expr: AST.ColumnExpr = { type: 'column', name: attr.name, table: tableName, schema: schemaName };
|
|
1393
|
-
return new ColumnReferenceNode(scope, expr, attr.type, attr.id, colIndex);
|
|
1394
|
-
};
|
|
1395
|
-
|
|
1396
|
-
const makeParamRef = (i: number, type: ScalarType): ScalarPlanNode => {
|
|
1397
|
-
const pexpr: AST.ParameterExpr = { type: 'parameter', name: `pk${i}` };
|
|
1398
|
-
return new ParameterReferenceNode(scope, pexpr, `pk${i}`, type);
|
|
1399
|
-
};
|
|
1400
|
-
|
|
1401
|
-
let predicate: ScalarPlanNode | null = null;
|
|
1402
|
-
for (let i = 0; i < pkIndices.length; i++) {
|
|
1403
|
-
const colIdx = pkIndices[i];
|
|
1404
|
-
const left = makeColumnRef(colIdx);
|
|
1405
|
-
const right = makeParamRef(i, attributes[colIdx].type);
|
|
1406
|
-
const bexpr: AST.BinaryExpr = { type: 'binary', operator: '=', left: left.expression, right: right.expression };
|
|
1407
|
-
const eqNode = new BinaryOpNode(scope, bexpr, left, right);
|
|
1408
|
-
predicate = predicate
|
|
1409
|
-
? new BinaryOpNode(scope, { type: 'binary', operator: 'AND', left: predicate.expression, right: eqNode.expression }, predicate, eqNode)
|
|
1410
|
-
: eqNode;
|
|
1411
|
-
}
|
|
1412
|
-
|
|
1413
|
-
if (!predicate) return null;
|
|
1414
|
-
|
|
1415
|
-
// Wrap the table reference with a FilterNode
|
|
1416
|
-
return new FilterNode(scope, relational, predicate);
|
|
1417
|
-
}
|
|
1418
|
-
|
|
1419
|
-
private collectTables(node: PlanNode, relToBase: Map<string, string>, bases: Set<string>): void {
|
|
1420
|
-
for (const child of node.getChildren()) {
|
|
1421
|
-
this.collectTables(child, relToBase, bases);
|
|
1422
|
-
}
|
|
1423
|
-
if (node instanceof TableReferenceNode) {
|
|
1424
|
-
const schema = node.tableSchema;
|
|
1425
|
-
const baseName = `${schema.schemaName}.${schema.name}`.toLowerCase();
|
|
1426
|
-
bases.add(baseName);
|
|
1427
|
-
const relKey = `${baseName}#${node.id ?? 'unknown'}`;
|
|
1428
|
-
relToBase.set(relKey, baseName);
|
|
1429
|
-
}
|
|
1430
|
-
}
|
|
1431
|
-
|
|
1432
|
-
/**
|
|
1433
|
-
* Rollback an implicit transaction and coordinate with virtual table connections
|
|
1434
|
-
*/
|
|
1435
|
-
private async rollbackImplicitTransaction(): Promise<void> {
|
|
1436
|
-
debugLog("Database: Rolling back implicit transaction.");
|
|
1437
|
-
|
|
1438
|
-
// Rollback all active connections
|
|
1439
|
-
const connections = this.getAllConnections();
|
|
1440
|
-
const rollbackPromises = connections.map(async (connection) => {
|
|
1441
|
-
try {
|
|
1442
|
-
await connection.rollback();
|
|
1443
|
-
} catch (error) {
|
|
1444
|
-
errorLog(`Error rolling back transaction on connection ${connection.connectionId}: %O`, error);
|
|
1445
|
-
// Continue attempting rollback for other connections.
|
|
1446
|
-
}
|
|
1447
|
-
});
|
|
1448
|
-
|
|
1449
|
-
await Promise.allSettled(rollbackPromises);
|
|
1450
|
-
|
|
1451
|
-
// Reset database state
|
|
1452
|
-
this.inTransaction = false;
|
|
1453
|
-
this.isAutocommit = true;
|
|
1454
|
-
this.inImplicitTransaction = false;
|
|
1455
|
-
}
|
|
1456
|
-
|
|
1457
|
-
private createBlockWithNewStatements(block: BlockNode, statements: PlanNode[]): BlockNode {
|
|
1458
|
-
return new BlockNode(block.scope, statements, block.parameters);
|
|
1459
|
-
}
|
|
1460
|
-
}
|
|
1461
|
-
|