@harperfast/harper 5.2.0-alpha.6 → 5.2.0-beta.2
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/bin/cliOperations.ts +76 -12
- package/bin/run.ts +10 -0
- package/bin/status.ts +1 -1
- package/components/Application.ts +146 -83
- package/components/Scope.ts +4 -0
- package/components/componentLoader.ts +7 -0
- package/components/operations.js +21 -1
- package/config/configUtils.ts +139 -5
- package/config-app.schema.json +70 -0
- package/dataLayer/harperBridge/ResourceBridge.ts +7 -0
- package/dist/bin/cliOperations.js +76 -12
- package/dist/bin/cliOperations.js.map +1 -1
- package/dist/bin/run.js +9 -0
- package/dist/bin/run.js.map +1 -1
- package/dist/bin/status.js +1 -1
- package/dist/bin/status.js.map +1 -1
- package/dist/components/Application.d.ts +12 -5
- package/dist/components/Application.js +121 -60
- package/dist/components/Application.js.map +1 -1
- package/dist/components/Scope.d.ts +1 -0
- package/dist/components/Scope.js +4 -0
- package/dist/components/Scope.js.map +1 -1
- package/dist/components/componentLoader.js +7 -0
- package/dist/components/componentLoader.js.map +1 -1
- package/dist/components/operations.js +20 -1
- package/dist/components/operations.js.map +1 -1
- package/dist/config/configUtils.d.ts +31 -0
- package/dist/config/configUtils.js +127 -5
- package/dist/config/configUtils.js.map +1 -1
- package/dist/dataLayer/harperBridge/ResourceBridge.js +8 -0
- package/dist/dataLayer/harperBridge/ResourceBridge.js.map +1 -1
- package/dist/resources/DatabaseTransaction.d.ts +12 -0
- package/dist/resources/DatabaseTransaction.js +97 -0
- package/dist/resources/DatabaseTransaction.js.map +1 -1
- package/dist/resources/RequestTarget.js +13 -3
- package/dist/resources/RequestTarget.js.map +1 -1
- package/dist/resources/Resource.js +21 -2
- package/dist/resources/Resource.js.map +1 -1
- package/dist/resources/Table.d.ts +3 -1
- package/dist/resources/Table.js +48 -5
- package/dist/resources/Table.js.map +1 -1
- package/dist/resources/analytics/metadata.d.ts +3 -0
- package/dist/resources/analytics/metadata.js +3 -0
- package/dist/resources/analytics/metadata.js.map +1 -1
- package/dist/resources/analytics/write.js +22 -0
- package/dist/resources/analytics/write.js.map +1 -1
- package/dist/resources/databases.js +21 -0
- package/dist/resources/databases.js.map +1 -1
- package/dist/resources/defineResource.js +20 -7
- package/dist/resources/defineResource.js.map +1 -1
- package/dist/resources/jsResource.d.ts +24 -0
- package/dist/resources/jsResource.js +58 -2
- package/dist/resources/jsResource.js.map +1 -1
- package/dist/resources/openApi.js +45 -20
- package/dist/resources/openApi.js.map +1 -1
- package/dist/resources/scheduler/CronExpression.d.ts +71 -0
- package/dist/resources/scheduler/CronExpression.js +367 -0
- package/dist/resources/scheduler/CronExpression.js.map +1 -0
- package/dist/resources/scheduler/engine.d.ts +91 -0
- package/dist/resources/scheduler/engine.js +767 -0
- package/dist/resources/scheduler/engine.js.map +1 -0
- package/dist/resources/scheduler/scheduler.d.ts +33 -0
- package/dist/resources/scheduler/scheduler.js +200 -0
- package/dist/resources/scheduler/scheduler.js.map +1 -0
- package/dist/security/auth.js +1 -0
- package/dist/security/auth.js.map +1 -1
- package/dist/security/jsLoader.js +8 -0
- package/dist/security/jsLoader.js.map +1 -1
- package/dist/security/keys.d.ts +32 -0
- package/dist/security/keys.js +147 -0
- package/dist/security/keys.js.map +1 -1
- package/dist/server/REST.js +67 -1
- package/dist/server/REST.js.map +1 -1
- package/dist/server/Server.d.ts +6 -0
- package/dist/server/Server.js.map +1 -1
- package/dist/server/http.d.ts +2 -0
- package/dist/server/http.js +139 -14
- package/dist/server/http.js.map +1 -1
- package/dist/server/operationsServer.js +3 -3
- package/dist/server/operationsServer.js.map +1 -1
- package/dist/server/serverHelpers/progressEmitter.js +5 -1
- package/dist/server/serverHelpers/progressEmitter.js.map +1 -1
- package/dist/server/threads/threadServer.js +9 -5
- package/dist/server/threads/threadServer.js.map +1 -1
- package/dist/sqlEngine/binder/bind.d.ts +72 -0
- package/dist/sqlEngine/binder/bind.js +289 -0
- package/dist/sqlEngine/binder/bind.js.map +1 -0
- package/dist/sqlEngine/config.d.ts +35 -0
- package/dist/sqlEngine/config.js +62 -0
- package/dist/sqlEngine/config.js.map +1 -0
- package/dist/sqlEngine/diff/differential.d.ts +23 -0
- package/dist/sqlEngine/diff/differential.js +90 -0
- package/dist/sqlEngine/diff/differential.js.map +1 -0
- package/dist/sqlEngine/errors.d.ts +22 -0
- package/dist/sqlEngine/errors.js +36 -0
- package/dist/sqlEngine/errors.js.map +1 -0
- package/dist/sqlEngine/executor/runMutation.d.ts +35 -0
- package/dist/sqlEngine/executor/runMutation.js +352 -0
- package/dist/sqlEngine/executor/runMutation.js.map +1 -0
- package/dist/sqlEngine/executor/runSelect.d.ts +7 -0
- package/dist/sqlEngine/executor/runSelect.js +14 -0
- package/dist/sqlEngine/executor/runSelect.js.map +1 -0
- package/dist/sqlEngine/expressions/compile.d.ts +24 -0
- package/dist/sqlEngine/expressions/compile.js +326 -0
- package/dist/sqlEngine/expressions/compile.js.map +1 -0
- package/dist/sqlEngine/functions/aggregates.d.ts +12 -0
- package/dist/sqlEngine/functions/aggregates.js +299 -0
- package/dist/sqlEngine/functions/aggregates.js.map +1 -0
- package/dist/sqlEngine/functions/registry.d.ts +36 -0
- package/dist/sqlEngine/functions/registry.js +33 -0
- package/dist/sqlEngine/functions/registry.js.map +1 -0
- package/dist/sqlEngine/functions/standard.d.ts +9 -0
- package/dist/sqlEngine/functions/standard.js +86 -0
- package/dist/sqlEngine/functions/standard.js.map +1 -0
- package/dist/sqlEngine/index.d.ts +29 -0
- package/dist/sqlEngine/index.js +62 -0
- package/dist/sqlEngine/index.js.map +1 -0
- package/dist/sqlEngine/logical/build.d.ts +20 -0
- package/dist/sqlEngine/logical/build.js +326 -0
- package/dist/sqlEngine/logical/build.js.map +1 -0
- package/dist/sqlEngine/logical/op.d.ts +105 -0
- package/dist/sqlEngine/logical/op.js +10 -0
- package/dist/sqlEngine/logical/op.js.map +1 -0
- package/dist/sqlEngine/optimizer/joinAnalysis.d.ts +37 -0
- package/dist/sqlEngine/optimizer/joinAnalysis.js +144 -0
- package/dist/sqlEngine/optimizer/joinAnalysis.js.map +1 -0
- package/dist/sqlEngine/optimizer/optimize.d.ts +13 -0
- package/dist/sqlEngine/optimizer/optimize.js +53 -0
- package/dist/sqlEngine/optimizer/optimize.js.map +1 -0
- package/dist/sqlEngine/optimizer/ruleEngine.d.ts +7 -0
- package/dist/sqlEngine/optimizer/ruleEngine.js +26 -0
- package/dist/sqlEngine/optimizer/ruleEngine.js.map +1 -0
- package/dist/sqlEngine/optimizer/rules/limitPushdown.d.ts +19 -0
- package/dist/sqlEngine/optimizer/rules/limitPushdown.js +55 -0
- package/dist/sqlEngine/optimizer/rules/limitPushdown.js.map +1 -0
- package/dist/sqlEngine/optimizer/rules/planJoins.d.ts +19 -0
- package/dist/sqlEngine/optimizer/rules/planJoins.js +62 -0
- package/dist/sqlEngine/optimizer/rules/planJoins.js.map +1 -0
- package/dist/sqlEngine/optimizer/rules/predicateNormalize.d.ts +18 -0
- package/dist/sqlEngine/optimizer/rules/predicateNormalize.js +80 -0
- package/dist/sqlEngine/optimizer/rules/predicateNormalize.js.map +1 -0
- package/dist/sqlEngine/optimizer/rules/predicatePushdown.d.ts +11 -0
- package/dist/sqlEngine/optimizer/rules/predicatePushdown.js +48 -0
- package/dist/sqlEngine/optimizer/rules/predicatePushdown.js.map +1 -0
- package/dist/sqlEngine/optimizer/rules/projectionPushdown.d.ts +23 -0
- package/dist/sqlEngine/optimizer/rules/projectionPushdown.js +160 -0
- package/dist/sqlEngine/optimizer/rules/projectionPushdown.js.map +1 -0
- package/dist/sqlEngine/optimizer/rules/sortFromIndex.d.ts +14 -0
- package/dist/sqlEngine/optimizer/rules/sortFromIndex.js +49 -0
- package/dist/sqlEngine/optimizer/rules/sortFromIndex.js.map +1 -0
- package/dist/sqlEngine/optimizer/rules/validateScannable.d.ts +15 -0
- package/dist/sqlEngine/optimizer/rules/validateScannable.js +60 -0
- package/dist/sqlEngine/optimizer/rules/validateScannable.js.map +1 -0
- package/dist/sqlEngine/optimizer/whereToConditions.d.ts +85 -0
- package/dist/sqlEngine/optimizer/whereToConditions.js +484 -0
- package/dist/sqlEngine/optimizer/whereToConditions.js.map +1 -0
- package/dist/sqlEngine/parser/ast.d.ts +139 -0
- package/dist/sqlEngine/parser/ast.js +10 -0
- package/dist/sqlEngine/parser/ast.js.map +1 -0
- package/dist/sqlEngine/parser/normalizer.d.ts +28 -0
- package/dist/sqlEngine/parser/normalizer.js +413 -0
- package/dist/sqlEngine/parser/normalizer.js.map +1 -0
- package/dist/sqlEngine/parser/parse.d.ts +14 -0
- package/dist/sqlEngine/parser/parse.js +20 -0
- package/dist/sqlEngine/parser/parse.js.map +1 -0
- package/dist/sqlEngine/physical/PhysicalDistinct.d.ts +9 -0
- package/dist/sqlEngine/physical/PhysicalDistinct.js +29 -0
- package/dist/sqlEngine/physical/PhysicalDistinct.js.map +1 -0
- package/dist/sqlEngine/physical/PhysicalFilter.d.ts +10 -0
- package/dist/sqlEngine/physical/PhysicalFilter.js +25 -0
- package/dist/sqlEngine/physical/PhysicalFilter.js.map +1 -0
- package/dist/sqlEngine/physical/PhysicalHashAggregate.d.ts +27 -0
- package/dist/sqlEngine/physical/PhysicalHashAggregate.js +100 -0
- package/dist/sqlEngine/physical/PhysicalHashAggregate.js.map +1 -0
- package/dist/sqlEngine/physical/PhysicalHashJoin.d.ts +29 -0
- package/dist/sqlEngine/physical/PhysicalHashJoin.js +93 -0
- package/dist/sqlEngine/physical/PhysicalHashJoin.js.map +1 -0
- package/dist/sqlEngine/physical/PhysicalIndexNestedLoopJoin.d.ts +36 -0
- package/dist/sqlEngine/physical/PhysicalIndexNestedLoopJoin.js +78 -0
- package/dist/sqlEngine/physical/PhysicalIndexNestedLoopJoin.js.map +1 -0
- package/dist/sqlEngine/physical/PhysicalIndexScan.d.ts +22 -0
- package/dist/sqlEngine/physical/PhysicalIndexScan.js +77 -0
- package/dist/sqlEngine/physical/PhysicalIndexScan.js.map +1 -0
- package/dist/sqlEngine/physical/PhysicalLimit.d.ts +5 -0
- package/dist/sqlEngine/physical/PhysicalLimit.js +28 -0
- package/dist/sqlEngine/physical/PhysicalLimit.js.map +1 -0
- package/dist/sqlEngine/physical/PhysicalNestedLoopJoin.d.ts +20 -0
- package/dist/sqlEngine/physical/PhysicalNestedLoopJoin.js +51 -0
- package/dist/sqlEngine/physical/PhysicalNestedLoopJoin.js.map +1 -0
- package/dist/sqlEngine/physical/PhysicalProject.d.ts +18 -0
- package/dist/sqlEngine/physical/PhysicalProject.js +117 -0
- package/dist/sqlEngine/physical/PhysicalProject.js.map +1 -0
- package/dist/sqlEngine/physical/PhysicalQualify.d.ts +13 -0
- package/dist/sqlEngine/physical/PhysicalQualify.js +29 -0
- package/dist/sqlEngine/physical/PhysicalQualify.js.map +1 -0
- package/dist/sqlEngine/physical/PhysicalSort.d.ts +12 -0
- package/dist/sqlEngine/physical/PhysicalSort.js +59 -0
- package/dist/sqlEngine/physical/PhysicalSort.js.map +1 -0
- package/dist/sqlEngine/physical/op.d.ts +11 -0
- package/dist/sqlEngine/physical/op.js +9 -0
- package/dist/sqlEngine/physical/op.js.map +1 -0
- package/dist/sqlEngine/physical/plan.d.ts +23 -0
- package/dist/sqlEngine/physical/plan.js +162 -0
- package/dist/sqlEngine/physical/plan.js.map +1 -0
- package/dist/sqlEngine/router.d.ts +26 -0
- package/dist/sqlEngine/router.js +48 -0
- package/dist/sqlEngine/router.js.map +1 -0
- package/dist/sqlEngine/types.d.ts +37 -0
- package/dist/sqlEngine/types.js +13 -0
- package/dist/sqlEngine/types.js.map +1 -0
- package/dist/sqlTranslator/index.js +7 -1
- package/dist/sqlTranslator/index.js.map +1 -1
- package/dist/utility/common_utils.js +25 -0
- package/dist/utility/common_utils.js.map +1 -1
- package/dist/utility/install/installer.d.ts +9 -1
- package/dist/utility/install/installer.js +21 -0
- package/dist/utility/install/installer.js.map +1 -1
- package/dist/validation/configValidator.js +3 -0
- package/dist/validation/configValidator.js.map +1 -1
- package/dist/validation/deleteValidator.js +10 -2
- package/dist/validation/deleteValidator.js.map +1 -1
- package/npm-shrinkwrap.json +272 -230
- package/package.json +3 -3
- package/resources/DESIGN.md +17 -16
- package/resources/DatabaseTransaction.ts +95 -0
- package/resources/RequestTarget.ts +12 -3
- package/resources/Resource.ts +23 -2
- package/resources/Table.ts +57 -6
- package/resources/analytics/metadata.ts +3 -0
- package/resources/analytics/write.ts +23 -0
- package/resources/databases.ts +24 -0
- package/resources/defineResource.ts +17 -4
- package/resources/jsResource.ts +61 -2
- package/resources/openApi.ts +44 -19
- package/resources/scheduler/CronExpression.ts +394 -0
- package/resources/scheduler/engine.ts +812 -0
- package/resources/scheduler/scheduler.ts +236 -0
- package/security/auth.ts +1 -0
- package/security/jsLoader.ts +8 -0
- package/security/keys.ts +152 -0
- package/server/REST.ts +70 -1
- package/server/Server.ts +6 -0
- package/server/http.ts +122 -15
- package/server/operationsServer.ts +5 -3
- package/server/serverHelpers/progressEmitter.ts +5 -1
- package/server/threads/threadServer.js +9 -5
- package/sqlTranslator/index.ts +16 -6
- package/studio/web/assets/{Chat-CTjtL8Z4.js → Chat-DHP4XpID.js} +2 -2
- package/studio/web/assets/{Chat-CTjtL8Z4.js.map → Chat-DHP4XpID.js.map} +1 -1
- package/studio/web/assets/{FloatingChat-CafHR4Ur.js → FloatingChat-CJ7PssCv.js} +4 -4
- package/studio/web/assets/{FloatingChat-CafHR4Ur.js.map → FloatingChat-CJ7PssCv.js.map} +1 -1
- package/studio/web/assets/{applications-Buh_q0Vj.js → applications-DxXiGpsR.js} +2 -2
- package/studio/web/assets/{applications-Buh_q0Vj.js.map → applications-DxXiGpsR.js.map} +1 -1
- package/studio/web/assets/{index-0hXeECkS.js → index-BdbBanDP.js} +6 -6
- package/studio/web/assets/{index-0hXeECkS.js.map → index-BdbBanDP.js.map} +1 -1
- package/studio/web/assets/{index.lazy-B00B7VBT.js → index.lazy-B2eH28zD.js} +4 -4
- package/studio/web/assets/{index.lazy-B00B7VBT.js.map → index.lazy-B2eH28zD.js.map} +1 -1
- package/studio/web/assets/{profile-Cg2wwYPn.js → profile-DK5hgucv.js} +2 -2
- package/studio/web/assets/{profile-Cg2wwYPn.js.map → profile-DK5hgucv.js.map} +1 -1
- package/studio/web/assets/{setComponentFile-DCaDIvyB.js → setComponentFile-BVDWRYxx.js} +2 -2
- package/studio/web/assets/{setComponentFile-DCaDIvyB.js.map → setComponentFile-BVDWRYxx.js.map} +1 -1
- package/studio/web/assets/{setup-CAVcAQjK.js → setup-DJ9BInoK.js} +2 -2
- package/studio/web/assets/{setup-CAVcAQjK.js.map → setup-DJ9BInoK.js.map} +1 -1
- package/studio/web/assets/{status-BRXorNdD.js → status-B_qzmgfD.js} +2 -2
- package/studio/web/assets/{status-BRXorNdD.js.map → status-B_qzmgfD.js.map} +1 -1
- package/studio/web/assets/{swagger-ui-react-Dy1D62vO.js → swagger-ui-react-DOL5jCqg.js} +2 -2
- package/studio/web/assets/{swagger-ui-react-Dy1D62vO.js.map → swagger-ui-react-DOL5jCqg.js.map} +1 -1
- package/studio/web/assets/{tsMode-A8gbL74v.js → tsMode-DpxUxfTW.js} +2 -2
- package/studio/web/assets/{tsMode-A8gbL74v.js.map → tsMode-DpxUxfTW.js.map} +1 -1
- package/studio/web/assets/{useEntityRestURL-cDodrVcQ.js → useEntityRestURL-CU_lY6XW.js} +2 -2
- package/studio/web/assets/{useEntityRestURL-cDodrVcQ.js.map → useEntityRestURL-CU_lY6XW.js.map} +1 -1
- package/studio/web/index.html +1 -1
- package/utility/common_utils.ts +26 -0
- package/utility/install/installer.ts +26 -1
- package/validation/configValidator.ts +3 -0
- package/validation/deleteValidator.ts +11 -2
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* PhysicalHashAggregate: groups all input rows in a Map keyed on JSON-serialised
|
|
4
|
+
* group-key values, then finalises accumulators and yields one output row per
|
|
5
|
+
* group.
|
|
6
|
+
*
|
|
7
|
+
* Memory is bounded by maxHashRows (total input rows consumed), after which an
|
|
8
|
+
* EngineUnsupportedError is thrown so the router falls back to legacy in 'auto'
|
|
9
|
+
* mode (runSelect fully materializes before returning, so nothing has been
|
|
10
|
+
* emitted when the cap trips).
|
|
11
|
+
*
|
|
12
|
+
* Special cases:
|
|
13
|
+
* - No GROUP BY + no rows → emit one row with default aggregate values
|
|
14
|
+
* (e.g. COUNT(*) = 0).
|
|
15
|
+
* - COUNT(*) arg is a star placeholder; we pass the sentinel value 1 to step()
|
|
16
|
+
* so the accumulator counts every row unconditionally.
|
|
17
|
+
*/
|
|
18
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
+
exports.physicalHashAggregate = physicalHashAggregate;
|
|
20
|
+
const compile_ts_1 = require("../expressions/compile.js");
|
|
21
|
+
const registry_ts_1 = require("../functions/registry.js");
|
|
22
|
+
const errors_ts_1 = require("../errors.js");
|
|
23
|
+
function physicalHashAggregate(input, groupKeys, aggs, maxHashRows, qualified = false) {
|
|
24
|
+
// In join (qualified) queries the group-key column lives under its
|
|
25
|
+
// `<alias>.<name>` key, and the aggregate output is keyed the same way so the
|
|
26
|
+
// projection above resolves it consistently.
|
|
27
|
+
const groupKeyNames = groupKeys.map((k) => {
|
|
28
|
+
if (k.kind !== 'column')
|
|
29
|
+
throw new errors_ts_1.EngineUnsupportedError('GROUP BY supports only column refs', k);
|
|
30
|
+
return qualified && k.table ? `${k.table}.${k.name}` : k.name;
|
|
31
|
+
});
|
|
32
|
+
const groupKeyEvals = groupKeyNames.map((key) => (row) => row[key]);
|
|
33
|
+
const compiledAggs = aggs.map((a) => {
|
|
34
|
+
const desc = registry_ts_1.functionRegistry.lookup(a.name);
|
|
35
|
+
if (!desc || desc.kind !== 'aggregate') {
|
|
36
|
+
throw new errors_ts_1.EngineUnsupportedError(`unknown aggregate function: ${a.name}`);
|
|
37
|
+
}
|
|
38
|
+
// DISTINCT-in-aggregate dedup is not implemented; the accumulator would
|
|
39
|
+
// otherwise step every row (silent wrong result, e.g. COUNT(DISTINCT x)
|
|
40
|
+
// counting all rows). Reject so 'auto' falls back to legacy, which dedups.
|
|
41
|
+
if (a.distinct) {
|
|
42
|
+
throw new errors_ts_1.EngineUnsupportedError(`DISTINCT aggregate not supported yet: ${a.name}`);
|
|
43
|
+
}
|
|
44
|
+
const isStarArg = a.arg.kind === 'star';
|
|
45
|
+
const argEval = isStarArg ? null : (0, compile_ts_1.compileExpr)(a.arg, qualified).eval;
|
|
46
|
+
return {
|
|
47
|
+
outputName: a.outputName,
|
|
48
|
+
factory: desc.impl.factory,
|
|
49
|
+
isStarArg,
|
|
50
|
+
argEval,
|
|
51
|
+
};
|
|
52
|
+
});
|
|
53
|
+
return {
|
|
54
|
+
schema: [],
|
|
55
|
+
execute(ctx) {
|
|
56
|
+
return runAggregate(input, ctx, groupKeyEvals, groupKeyNames, compiledAggs, maxHashRows);
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
async function* runAggregate(input, ctx, groupKeyEvals, groupKeyNames, compiledAggs, maxHashRows) {
|
|
61
|
+
const groups = new Map();
|
|
62
|
+
let rowCount = 0;
|
|
63
|
+
for await (const row of input.execute(ctx)) {
|
|
64
|
+
if (++rowCount > maxHashRows) {
|
|
65
|
+
throw new errors_ts_1.EngineUnsupportedError(`aggregate exceeded maxHashRows (${maxHashRows})`);
|
|
66
|
+
}
|
|
67
|
+
const keyVals = groupKeyEvals.map((fn) => fn(row));
|
|
68
|
+
const groupKey = JSON.stringify(keyVals);
|
|
69
|
+
let entry = groups.get(groupKey);
|
|
70
|
+
if (!entry) {
|
|
71
|
+
entry = { keys: keyVals, accs: compiledAggs.map((a) => a.factory()) };
|
|
72
|
+
groups.set(groupKey, entry);
|
|
73
|
+
}
|
|
74
|
+
for (let i = 0; i < compiledAggs.length; i++) {
|
|
75
|
+
const agg = compiledAggs[i];
|
|
76
|
+
const val = agg.isStarArg ? 1 : agg.argEval(row);
|
|
77
|
+
entry.accs[i].step(val);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
// No GROUP BY + no rows → emit one row with zero/null aggregate values.
|
|
81
|
+
if (groups.size === 0 && groupKeyNames.length === 0) {
|
|
82
|
+
const outputRow = {};
|
|
83
|
+
for (const agg of compiledAggs) {
|
|
84
|
+
outputRow[agg.outputName] = agg.factory().finalize();
|
|
85
|
+
}
|
|
86
|
+
yield outputRow;
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
for (const { keys, accs } of groups.values()) {
|
|
90
|
+
const outputRow = {};
|
|
91
|
+
for (let i = 0; i < groupKeyNames.length; i++) {
|
|
92
|
+
outputRow[groupKeyNames[i]] = keys[i];
|
|
93
|
+
}
|
|
94
|
+
for (let i = 0; i < compiledAggs.length; i++) {
|
|
95
|
+
outputRow[compiledAggs[i].outputName] = accs[i].finalize();
|
|
96
|
+
}
|
|
97
|
+
yield outputRow;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=PhysicalHashAggregate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PhysicalHashAggregate.js","sourceRoot":"","sources":["../../../sqlEngine/physical/PhysicalHashAggregate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PhysicalHashJoin: equi-join via an in-memory hash table on the right (inner)
|
|
3
|
+
* side.
|
|
4
|
+
*
|
|
5
|
+
* Build phase materializes the right input into a Map keyed on the JSON-encoded
|
|
6
|
+
* join-key tuple (bounded by maxHashRows). Probe phase streams the left
|
|
7
|
+
* (outer) input, looks up each left row's key tuple, and emits the merged row
|
|
8
|
+
* for every matching right row. An optional `residual` predicate (the
|
|
9
|
+
* non-equi remainder of the ON clause) is checked on the merged row.
|
|
10
|
+
*
|
|
11
|
+
* For a LEFT join, a left row with no surviving match emits once with the right
|
|
12
|
+
* side's declared columns null-filled (matching legacy `undefined → null`
|
|
13
|
+
* outer-join semantics in dataLayer/SQLSearch).
|
|
14
|
+
*
|
|
15
|
+
* Rows on both sides are already qualified (`<alias>.<attr>`), so the merge is
|
|
16
|
+
* a plain spread with no key collisions.
|
|
17
|
+
*/
|
|
18
|
+
import type { ExprNode } from '../parser/ast.ts';
|
|
19
|
+
import type { PhysicalOp } from './op.ts';
|
|
20
|
+
export interface HashJoinOptions {
|
|
21
|
+
leftKeys: ExprNode[];
|
|
22
|
+
rightKeys: ExprNode[];
|
|
23
|
+
residual?: ExprNode;
|
|
24
|
+
type: 'inner' | 'left';
|
|
25
|
+
/** Right-side qualified keys to null-fill on unmatched LEFT rows. */
|
|
26
|
+
rightNullKeys: string[];
|
|
27
|
+
maxHashRows: number;
|
|
28
|
+
}
|
|
29
|
+
export declare function physicalHashJoin(left: PhysicalOp, right: PhysicalOp, opts: HashJoinOptions): PhysicalOp;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* PhysicalHashJoin: equi-join via an in-memory hash table on the right (inner)
|
|
4
|
+
* side.
|
|
5
|
+
*
|
|
6
|
+
* Build phase materializes the right input into a Map keyed on the JSON-encoded
|
|
7
|
+
* join-key tuple (bounded by maxHashRows). Probe phase streams the left
|
|
8
|
+
* (outer) input, looks up each left row's key tuple, and emits the merged row
|
|
9
|
+
* for every matching right row. An optional `residual` predicate (the
|
|
10
|
+
* non-equi remainder of the ON clause) is checked on the merged row.
|
|
11
|
+
*
|
|
12
|
+
* For a LEFT join, a left row with no surviving match emits once with the right
|
|
13
|
+
* side's declared columns null-filled (matching legacy `undefined → null`
|
|
14
|
+
* outer-join semantics in dataLayer/SQLSearch).
|
|
15
|
+
*
|
|
16
|
+
* Rows on both sides are already qualified (`<alias>.<attr>`), so the merge is
|
|
17
|
+
* a plain spread with no key collisions.
|
|
18
|
+
*/
|
|
19
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
+
exports.physicalHashJoin = physicalHashJoin;
|
|
21
|
+
const compile_ts_1 = require("../expressions/compile.js");
|
|
22
|
+
const errors_ts_1 = require("../errors.js");
|
|
23
|
+
function physicalHashJoin(left, right, opts) {
|
|
24
|
+
const leftKeyEvals = opts.leftKeys.map((e) => (0, compile_ts_1.compileExpr)(e, true).eval);
|
|
25
|
+
const rightKeyEvals = opts.rightKeys.map((e) => (0, compile_ts_1.compileExpr)(e, true).eval);
|
|
26
|
+
const residual = opts.residual ? (0, compile_ts_1.compileExpr)(opts.residual, true) : undefined;
|
|
27
|
+
return {
|
|
28
|
+
schema: [],
|
|
29
|
+
async *execute(ctx) {
|
|
30
|
+
// Build side: right input → Map<keyTuple, Row[]>.
|
|
31
|
+
const buckets = new Map();
|
|
32
|
+
let built = 0;
|
|
33
|
+
for await (const rrow of right.execute(ctx)) {
|
|
34
|
+
if (++built > opts.maxHashRows) {
|
|
35
|
+
throw new errors_ts_1.EngineUnsupportedError(`hash join build side exceeded maxHashRows (${opts.maxHashRows})`);
|
|
36
|
+
}
|
|
37
|
+
const key = keyTuple(rightKeyEvals, rrow);
|
|
38
|
+
if (key === undefined)
|
|
39
|
+
continue; // NULL join key never matches
|
|
40
|
+
const bucket = buckets.get(key);
|
|
41
|
+
if (bucket)
|
|
42
|
+
bucket.push(rrow);
|
|
43
|
+
else
|
|
44
|
+
buckets.set(key, [rrow]);
|
|
45
|
+
}
|
|
46
|
+
for await (const lrow of left.execute(ctx)) {
|
|
47
|
+
const key = keyTuple(leftKeyEvals, lrow);
|
|
48
|
+
let matched = false;
|
|
49
|
+
if (key !== undefined) {
|
|
50
|
+
const bucket = buckets.get(key);
|
|
51
|
+
if (bucket) {
|
|
52
|
+
for (const rrow of bucket) {
|
|
53
|
+
const merged = { ...lrow, ...rrow };
|
|
54
|
+
if (residual) {
|
|
55
|
+
const v = residual.eval(merged);
|
|
56
|
+
if (v == null || v === false)
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
matched = true;
|
|
60
|
+
yield merged;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
if (!matched && opts.type === 'left') {
|
|
65
|
+
yield nullFill(lrow, opts.rightNullKeys);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Serializes the join key. Returns undefined if any key component is null/
|
|
73
|
+
* undefined or NaN — SQL equi-joins never match on NULL, and NaN is never equal
|
|
74
|
+
* to itself (without this guard JSON.stringify coerces NaN → "null", letting two
|
|
75
|
+
* NaN keys collide and match).
|
|
76
|
+
*/
|
|
77
|
+
function keyTuple(evals, row) {
|
|
78
|
+
const vals = [];
|
|
79
|
+
for (const e of evals) {
|
|
80
|
+
const v = e(row);
|
|
81
|
+
if (v == null || (typeof v === 'number' && Number.isNaN(v)))
|
|
82
|
+
return undefined;
|
|
83
|
+
vals.push(v);
|
|
84
|
+
}
|
|
85
|
+
return JSON.stringify(vals);
|
|
86
|
+
}
|
|
87
|
+
function nullFill(lrow, rightNullKeys) {
|
|
88
|
+
const out = { ...lrow };
|
|
89
|
+
for (const k of rightNullKeys)
|
|
90
|
+
out[k] = null;
|
|
91
|
+
return out;
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=PhysicalHashJoin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PhysicalHashJoin.js","sourceRoot":"","sources":["../../../sqlEngine/physical/PhysicalHashJoin.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;GAgBG;;AAkBH,4CA6CC;AA1DD,0DAAwD;AACxD,4CAAsD;AAYtD,SAAgB,gBAAgB,CAAC,IAAgB,EAAE,KAAiB,EAAE,IAAqB;IAC1F,MAAM,YAAY,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAA,wBAAW,EAAC,CAAC,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;IACzE,MAAM,aAAa,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAA,wBAAW,EAAC,CAAC,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;IAC3E,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAA,wBAAW,EAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAE9E,OAAO;QACN,MAAM,EAAE,EAAE;QACV,KAAK,CAAC,CAAC,OAAO,CAAC,GAAqB;YACnC,kDAAkD;YAClD,MAAM,OAAO,GAAG,IAAI,GAAG,EAAiB,CAAC;YACzC,IAAI,KAAK,GAAG,CAAC,CAAC;YACd,IAAI,KAAK,EAAE,MAAM,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC7C,IAAI,EAAE,KAAK,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;oBAChC,MAAM,IAAI,kCAAsB,CAAC,8CAA8C,IAAI,CAAC,WAAW,GAAG,CAAC,CAAC;gBACrG,CAAC;gBACD,MAAM,GAAG,GAAG,QAAQ,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC;gBAC1C,IAAI,GAAG,KAAK,SAAS;oBAAE,SAAS,CAAC,8BAA8B;gBAC/D,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;gBAChC,IAAI,MAAM;oBAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;;oBACzB,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;YAC/B,CAAC;YAED,IAAI,KAAK,EAAE,MAAM,IAAI,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC5C,MAAM,GAAG,GAAG,QAAQ,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;gBACzC,IAAI,OAAO,GAAG,KAAK,CAAC;gBACpB,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;oBACvB,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;oBAChC,IAAI,MAAM,EAAE,CAAC;wBACZ,KAAK,MAAM,IAAI,IAAI,MAAM,EAAE,CAAC;4BAC3B,MAAM,MAAM,GAAG,EAAE,GAAG,IAAI,EAAE,GAAG,IAAI,EAAE,CAAC;4BACpC,IAAI,QAAQ,EAAE,CAAC;gCACd,MAAM,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;gCAChC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,KAAK,KAAK;oCAAE,SAAS;4BACxC,CAAC;4BACD,OAAO,GAAG,IAAI,CAAC;4BACf,MAAM,MAAM,CAAC;wBACd,CAAC;oBACF,CAAC;gBACF,CAAC;gBACD,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;oBACtC,MAAM,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;gBAC1C,CAAC;YACF,CAAC;QACF,CAAC;KACD,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,SAAS,QAAQ,CAAC,KAAmC,EAAE,GAAQ;IAC9D,MAAM,IAAI,GAAc,EAAE,CAAC;IAC3B,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACvB,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;QACjB,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YAAE,OAAO,SAAS,CAAC;QAC9E,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACd,CAAC;IACD,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;AAC7B,CAAC;AAED,SAAS,QAAQ,CAAC,IAAS,EAAE,aAAuB;IACnD,MAAM,GAAG,GAAQ,EAAE,GAAG,IAAI,EAAE,CAAC;IAC7B,KAAK,MAAM,CAAC,IAAI,aAAa;QAAE,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IAC7C,OAAO,GAAG,CAAC;AACZ,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PhysicalIndexNestedLoopJoin: streams the outer (left) input and, for each
|
|
3
|
+
* outer row, probes the inner table via Table.search on its indexed join key.
|
|
4
|
+
*
|
|
5
|
+
* This is the default join strategy when the inner join key is indexed: no full
|
|
6
|
+
* inner scan, bounded memory (one inner result set at a time), and it composes
|
|
7
|
+
* with the inner table's own pushed-down WHERE conditions.
|
|
8
|
+
*
|
|
9
|
+
* The probe equality is ANDed with the inner scan's base conditions. Inner
|
|
10
|
+
* records are filtered by the inner residual (bare names), then qualified with
|
|
11
|
+
* the inner alias and merged with the outer row; an optional join residual (the
|
|
12
|
+
* non-equi remainder of ON) is checked on the merged row. LEFT joins null-fill
|
|
13
|
+
* the inner columns when no inner row matches.
|
|
14
|
+
*/
|
|
15
|
+
import type { ExprNode } from '../parser/ast.ts';
|
|
16
|
+
import type { PhysicalOp } from './op.ts';
|
|
17
|
+
import type { ConditionNode } from '../optimizer/whereToConditions.ts';
|
|
18
|
+
export interface IndexNLJoinOptions {
|
|
19
|
+
innerResource: unknown;
|
|
20
|
+
innerAlias: string;
|
|
21
|
+
/** Indexed inner attribute the probe equates against the outer key value. */
|
|
22
|
+
innerAttribute: string;
|
|
23
|
+
/** Outer-side join-key expression (compiled in qualified mode). */
|
|
24
|
+
outerKey: ExprNode;
|
|
25
|
+
/** Inner scan's own pushed-down conditions, ANDed with the probe equality. */
|
|
26
|
+
innerBaseConditions: ConditionNode[];
|
|
27
|
+
innerOperator: 'and' | 'or';
|
|
28
|
+
innerSelect?: string[];
|
|
29
|
+
/** Inner single-table residual (bare names), applied to probe records. */
|
|
30
|
+
innerResidual?: ExprNode;
|
|
31
|
+
/** Non-equi remainder of the ON clause (qualified), applied to merged rows. */
|
|
32
|
+
residualOn?: ExprNode;
|
|
33
|
+
type: 'inner' | 'left';
|
|
34
|
+
rightNullKeys: string[];
|
|
35
|
+
}
|
|
36
|
+
export declare function physicalIndexNestedLoopJoin(left: PhysicalOp, opts: IndexNLJoinOptions): PhysicalOp;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* PhysicalIndexNestedLoopJoin: streams the outer (left) input and, for each
|
|
4
|
+
* outer row, probes the inner table via Table.search on its indexed join key.
|
|
5
|
+
*
|
|
6
|
+
* This is the default join strategy when the inner join key is indexed: no full
|
|
7
|
+
* inner scan, bounded memory (one inner result set at a time), and it composes
|
|
8
|
+
* with the inner table's own pushed-down WHERE conditions.
|
|
9
|
+
*
|
|
10
|
+
* The probe equality is ANDed with the inner scan's base conditions. Inner
|
|
11
|
+
* records are filtered by the inner residual (bare names), then qualified with
|
|
12
|
+
* the inner alias and merged with the outer row; an optional join residual (the
|
|
13
|
+
* non-equi remainder of ON) is checked on the merged row. LEFT joins null-fill
|
|
14
|
+
* the inner columns when no inner row matches.
|
|
15
|
+
*/
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.physicalIndexNestedLoopJoin = physicalIndexNestedLoopJoin;
|
|
18
|
+
const compile_ts_1 = require("../expressions/compile.js");
|
|
19
|
+
function physicalIndexNestedLoopJoin(left, opts) {
|
|
20
|
+
const resource = opts.innerResource;
|
|
21
|
+
const outerKeyEval = (0, compile_ts_1.compileExpr)(opts.outerKey, true).eval;
|
|
22
|
+
const innerResidual = opts.innerResidual ? (0, compile_ts_1.compileExpr)(opts.innerResidual, false) : undefined;
|
|
23
|
+
const residualOn = opts.residualOn ? (0, compile_ts_1.compileExpr)(opts.residualOn, true) : undefined;
|
|
24
|
+
const prefix = `${opts.innerAlias}.`;
|
|
25
|
+
return {
|
|
26
|
+
schema: [],
|
|
27
|
+
async *execute(ctx) {
|
|
28
|
+
for await (const outerRow of left.execute(ctx)) {
|
|
29
|
+
const value = outerKeyEval(outerRow);
|
|
30
|
+
let matched = false;
|
|
31
|
+
if (value != null) {
|
|
32
|
+
const target = buildProbeTarget(opts, value);
|
|
33
|
+
for await (const innerRow of resource.search(target)) {
|
|
34
|
+
if (innerResidual) {
|
|
35
|
+
const v = innerResidual.eval(innerRow);
|
|
36
|
+
if (v == null || v === false)
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
const merged = { ...outerRow };
|
|
40
|
+
for (const k of Object.keys(innerRow))
|
|
41
|
+
merged[prefix + k] = innerRow[k];
|
|
42
|
+
if (residualOn) {
|
|
43
|
+
const v = residualOn.eval(merged);
|
|
44
|
+
if (v == null || v === false)
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
matched = true;
|
|
48
|
+
yield merged;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
if (!matched && opts.type === 'left') {
|
|
52
|
+
const out = { ...outerRow };
|
|
53
|
+
for (const k of opts.rightNullKeys)
|
|
54
|
+
out[k] = null;
|
|
55
|
+
yield out;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
function buildProbeTarget(opts, value) {
|
|
62
|
+
const probe = { attribute: opts.innerAttribute, value, comparator: 'equals' };
|
|
63
|
+
let conditions;
|
|
64
|
+
if (opts.innerBaseConditions.length === 0) {
|
|
65
|
+
conditions = [probe];
|
|
66
|
+
}
|
|
67
|
+
else if (opts.innerOperator === 'and') {
|
|
68
|
+
conditions = [...opts.innerBaseConditions, probe];
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
conditions = [{ conditions: opts.innerBaseConditions, operator: 'or' }, probe];
|
|
72
|
+
}
|
|
73
|
+
const target = { conditions, operator: 'and', allowFullScan: false };
|
|
74
|
+
if (opts.innerSelect)
|
|
75
|
+
target.select = opts.innerSelect;
|
|
76
|
+
return target;
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=PhysicalIndexNestedLoopJoin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PhysicalIndexNestedLoopJoin.js","sourceRoot":"","sources":["../../../sqlEngine/physical/PhysicalIndexNestedLoopJoin.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PhysicalIndexScan: wraps Table.search.
|
|
3
|
+
*
|
|
4
|
+
* Builds the RequestTarget from the LogicalScan's pushed filters/sort/limit
|
|
5
|
+
* and projection, then yields rows from the returned AsyncIterable.
|
|
6
|
+
*/
|
|
7
|
+
import type { LogicalScan } from '../logical/op.ts';
|
|
8
|
+
import type { PhysicalOp } from './op.ts';
|
|
9
|
+
import type { ConditionNode } from '../optimizer/whereToConditions.ts';
|
|
10
|
+
export interface PhysicalIndexScanOptions {
|
|
11
|
+
conditions: ConditionNode[];
|
|
12
|
+
operator: 'and' | 'or';
|
|
13
|
+
/**
|
|
14
|
+
* Set for a sort-driven scan (no index-driving predicate; the pushed sort
|
|
15
|
+
* provides index order — D-219). Table.search flags a sort-aligned scan as
|
|
16
|
+
* needFullScan and would reject it under allowFullScan:false, so it must be
|
|
17
|
+
* allowed here. Validated as scannable by validateScannable, so this is not a
|
|
18
|
+
* blanket full-scan escape hatch.
|
|
19
|
+
*/
|
|
20
|
+
allowFullScan?: boolean;
|
|
21
|
+
}
|
|
22
|
+
export declare function physicalIndexScan(scan: LogicalScan, opts: PhysicalIndexScanOptions): PhysicalOp;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* PhysicalIndexScan: wraps Table.search.
|
|
4
|
+
*
|
|
5
|
+
* Builds the RequestTarget from the LogicalScan's pushed filters/sort/limit
|
|
6
|
+
* and projection, then yields rows from the returned AsyncIterable.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.physicalIndexScan = physicalIndexScan;
|
|
10
|
+
const errors_ts_1 = require("../errors.js");
|
|
11
|
+
const hdbError_ts_1 = require("../../utility/errors/hdbError.js");
|
|
12
|
+
function physicalIndexScan(scan, opts) {
|
|
13
|
+
const schema = (scan.boundTable?.attributes ?? []).map((a) => ({
|
|
14
|
+
name: a.name,
|
|
15
|
+
type: 'unknown',
|
|
16
|
+
nullable: true,
|
|
17
|
+
}));
|
|
18
|
+
return {
|
|
19
|
+
schema,
|
|
20
|
+
execute(ctx) {
|
|
21
|
+
return executeScan(scan, opts, ctx);
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
async function* executeScan(scan, opts, ctx) {
|
|
26
|
+
const resource = scan.boundTable?.resource;
|
|
27
|
+
if (!resource)
|
|
28
|
+
throw new Error('PhysicalIndexScan: scan has no boundTable.resource');
|
|
29
|
+
const target = { allowFullScan: opts.allowFullScan === true };
|
|
30
|
+
if (ctx.includeExpiredRows)
|
|
31
|
+
target.includeExpired = true;
|
|
32
|
+
// Only attach conditions/operator when there is at least one — Table.search
|
|
33
|
+
// rejects an empty `and`/`or` group ("requires at least one condition"). A
|
|
34
|
+
// scan with no conditions is driven by its pushed sort/limit alone.
|
|
35
|
+
if (opts.conditions.length > 0) {
|
|
36
|
+
target.conditions = opts.conditions;
|
|
37
|
+
target.operator = opts.operator;
|
|
38
|
+
}
|
|
39
|
+
if (scan.projection)
|
|
40
|
+
target.select = scan.projection;
|
|
41
|
+
if (scan.pushedSort && scan.pushedSort.length > 0) {
|
|
42
|
+
const k = scan.pushedSort[0];
|
|
43
|
+
if (k.expr.kind === 'column') {
|
|
44
|
+
target.sort = { attribute: k.expr.name, descending: k.descending };
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
if (scan.pushedLimit) {
|
|
48
|
+
if (scan.pushedLimit.limit != null)
|
|
49
|
+
target.limit = scan.pushedLimit.limit;
|
|
50
|
+
if (scan.pushedLimit.offset != null)
|
|
51
|
+
target.offset = scan.pushedLimit.offset;
|
|
52
|
+
}
|
|
53
|
+
// Safety net for the fallback contract: validateScannable predicts what
|
|
54
|
+
// Table.search will accept, but if the prediction is ever wrong (F-145: a
|
|
55
|
+
// pushed `ne null` guard on an index without indexNulls), search throws a
|
|
56
|
+
// capability-shaped ClientError (400/403/404) or IndexRebuildingError at
|
|
57
|
+
// runtime, past the router's EngineUnsupportedError catch — leaking an error
|
|
58
|
+
// where 'auto' should fall back. Convert those here; results are materialized
|
|
59
|
+
// before delivery, so no partial rows have been sent when this fires.
|
|
60
|
+
try {
|
|
61
|
+
for await (const row of resource.search(target)) {
|
|
62
|
+
yield row;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
catch (err) {
|
|
66
|
+
if (err instanceof errors_ts_1.EngineUnsupportedError)
|
|
67
|
+
throw err;
|
|
68
|
+
if (err instanceof hdbError_ts_1.IndexRebuildingError) {
|
|
69
|
+
throw new errors_ts_1.EngineUnsupportedError(`index rebuilding: ${err.message}`);
|
|
70
|
+
}
|
|
71
|
+
if (err instanceof hdbError_ts_1.ClientError) {
|
|
72
|
+
throw new errors_ts_1.EngineUnsupportedError(`search rejected scan: ${err.message}`);
|
|
73
|
+
}
|
|
74
|
+
throw err;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=PhysicalIndexScan.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PhysicalIndexScan.js","sourceRoot":"","sources":["../../../sqlEngine/physical/PhysicalIndexScan.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* PhysicalLimit: drops `offset` rows then yields up to `limit` rows.
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.physicalLimit = physicalLimit;
|
|
7
|
+
function physicalLimit(child, limit, offset) {
|
|
8
|
+
return {
|
|
9
|
+
schema: child.schema,
|
|
10
|
+
async *execute(ctx) {
|
|
11
|
+
let skipped = 0;
|
|
12
|
+
let yielded = 0;
|
|
13
|
+
const skip = offset ?? 0;
|
|
14
|
+
const cap = limit ?? Number.POSITIVE_INFINITY;
|
|
15
|
+
for await (const row of child.execute(ctx)) {
|
|
16
|
+
if (skipped < skip) {
|
|
17
|
+
skipped++;
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
if (yielded >= cap)
|
|
21
|
+
return;
|
|
22
|
+
yield row;
|
|
23
|
+
yielded++;
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=PhysicalLimit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PhysicalLimit.js","sourceRoot":"","sources":["../../../sqlEngine/physical/PhysicalLimit.ts"],"names":[],"mappings":";AAAA;;GAEG;;AAKH,sCAmBC;AAnBD,SAAgB,aAAa,CAAC,KAAiB,EAAE,KAAyB,EAAE,MAA0B;IACrG,OAAO;QACN,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,KAAK,CAAC,CAAC,OAAO,CAAC,GAAqB;YACnC,IAAI,OAAO,GAAG,CAAC,CAAC;YAChB,IAAI,OAAO,GAAG,CAAC,CAAC;YAChB,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,CAAC;YACzB,MAAM,GAAG,GAAG,KAAK,IAAI,MAAM,CAAC,iBAAiB,CAAC;YAC9C,IAAI,KAAK,EAAE,MAAM,GAAG,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC5C,IAAI,OAAO,GAAG,IAAI,EAAE,CAAC;oBACpB,OAAO,EAAE,CAAC;oBACV,SAAS;gBACV,CAAC;gBACD,IAAI,OAAO,IAAI,GAAG;oBAAE,OAAO;gBAC3B,MAAM,GAAG,CAAC;gBACV,OAAO,EAAE,CAAC;YACX,CAAC;QACF,CAAC;KACD,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PhysicalNestedLoopJoin: the general join fallback for CROSS joins and
|
|
3
|
+
* non-equi ON predicates that no hash/index strategy can serve.
|
|
4
|
+
*
|
|
5
|
+
* The right (inner) input is materialized once (bounded by maxHashRows); the
|
|
6
|
+
* left (outer) input streams. For each left row every buffered right row is
|
|
7
|
+
* tested against the compiled ON predicate (absent for CROSS) on the merged
|
|
8
|
+
* row. LEFT joins null-fill the right columns when a left row matches nothing.
|
|
9
|
+
*
|
|
10
|
+
* Both inputs are already qualified (`<alias>.<attr>`); merge is a plain spread.
|
|
11
|
+
*/
|
|
12
|
+
import type { ExprNode } from '../parser/ast.ts';
|
|
13
|
+
import type { PhysicalOp } from './op.ts';
|
|
14
|
+
export interface NestedLoopJoinOptions {
|
|
15
|
+
on?: ExprNode;
|
|
16
|
+
type: 'inner' | 'left' | 'cross';
|
|
17
|
+
rightNullKeys: string[];
|
|
18
|
+
maxHashRows: number;
|
|
19
|
+
}
|
|
20
|
+
export declare function physicalNestedLoopJoin(left: PhysicalOp, right: PhysicalOp, opts: NestedLoopJoinOptions): PhysicalOp;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* PhysicalNestedLoopJoin: the general join fallback for CROSS joins and
|
|
4
|
+
* non-equi ON predicates that no hash/index strategy can serve.
|
|
5
|
+
*
|
|
6
|
+
* The right (inner) input is materialized once (bounded by maxHashRows); the
|
|
7
|
+
* left (outer) input streams. For each left row every buffered right row is
|
|
8
|
+
* tested against the compiled ON predicate (absent for CROSS) on the merged
|
|
9
|
+
* row. LEFT joins null-fill the right columns when a left row matches nothing.
|
|
10
|
+
*
|
|
11
|
+
* Both inputs are already qualified (`<alias>.<attr>`); merge is a plain spread.
|
|
12
|
+
*/
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
exports.physicalNestedLoopJoin = physicalNestedLoopJoin;
|
|
15
|
+
const compile_ts_1 = require("../expressions/compile.js");
|
|
16
|
+
const errors_ts_1 = require("../errors.js");
|
|
17
|
+
function physicalNestedLoopJoin(left, right, opts) {
|
|
18
|
+
const on = opts.on ? (0, compile_ts_1.compileExpr)(opts.on, true) : undefined;
|
|
19
|
+
return {
|
|
20
|
+
schema: [],
|
|
21
|
+
async *execute(ctx) {
|
|
22
|
+
const inner = [];
|
|
23
|
+
for await (const rrow of right.execute(ctx)) {
|
|
24
|
+
if (inner.length >= opts.maxHashRows) {
|
|
25
|
+
throw new errors_ts_1.EngineUnsupportedError(`nested-loop join inner side exceeded maxHashRows (${opts.maxHashRows})`);
|
|
26
|
+
}
|
|
27
|
+
inner.push(rrow);
|
|
28
|
+
}
|
|
29
|
+
for await (const lrow of left.execute(ctx)) {
|
|
30
|
+
let matched = false;
|
|
31
|
+
for (const rrow of inner) {
|
|
32
|
+
const merged = { ...lrow, ...rrow };
|
|
33
|
+
if (on) {
|
|
34
|
+
const v = on.eval(merged);
|
|
35
|
+
if (v == null || v === false)
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
matched = true;
|
|
39
|
+
yield merged;
|
|
40
|
+
}
|
|
41
|
+
if (!matched && opts.type === 'left') {
|
|
42
|
+
const out = { ...lrow };
|
|
43
|
+
for (const k of opts.rightNullKeys)
|
|
44
|
+
out[k] = null;
|
|
45
|
+
yield out;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=PhysicalNestedLoopJoin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PhysicalNestedLoopJoin.js","sourceRoot":"","sources":["../../../sqlEngine/physical/PhysicalNestedLoopJoin.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;GAUG;;AAeH,wDAiCC;AA3CD,0DAAwD;AACxD,4CAAsD;AAStD,SAAgB,sBAAsB,CAAC,IAAgB,EAAE,KAAiB,EAAE,IAA2B;IACtG,MAAM,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,IAAA,wBAAW,EAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAE5D,OAAO;QACN,MAAM,EAAE,EAAE;QACV,KAAK,CAAC,CAAC,OAAO,CAAC,GAAqB;YACnC,MAAM,KAAK,GAAU,EAAE,CAAC;YACxB,IAAI,KAAK,EAAE,MAAM,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC7C,IAAI,KAAK,CAAC,MAAM,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;oBACtC,MAAM,IAAI,kCAAsB,CAAC,qDAAqD,IAAI,CAAC,WAAW,GAAG,CAAC,CAAC;gBAC5G,CAAC;gBACD,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAClB,CAAC;YAED,IAAI,KAAK,EAAE,MAAM,IAAI,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC5C,IAAI,OAAO,GAAG,KAAK,CAAC;gBACpB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;oBAC1B,MAAM,MAAM,GAAG,EAAE,GAAG,IAAI,EAAE,GAAG,IAAI,EAAE,CAAC;oBACpC,IAAI,EAAE,EAAE,CAAC;wBACR,MAAM,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;wBAC1B,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,KAAK,KAAK;4BAAE,SAAS;oBACxC,CAAC;oBACD,OAAO,GAAG,IAAI,CAAC;oBACf,MAAM,MAAM,CAAC;gBACd,CAAC;gBACD,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;oBACtC,MAAM,GAAG,GAAQ,EAAE,GAAG,IAAI,EAAE,CAAC;oBAC7B,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,aAAa;wBAAE,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;oBAClD,MAAM,GAAG,CAAC;gBACX,CAAC;YACF,CAAC;QACF,CAAC;KACD,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PhysicalProject: per-row evaluation of the SELECT clause.
|
|
3
|
+
*
|
|
4
|
+
* Single-table (`qualified = false`): star expansion forwards the row's keys
|
|
5
|
+
* intact and layers projected columns on top, matching the Resource API's
|
|
6
|
+
* natural record shape.
|
|
7
|
+
*
|
|
8
|
+
* Join queries (`qualified = true`): rows arrive keyed by `<alias>.<name>`.
|
|
9
|
+
* Output columns are renamed to clean, unqualified names (or the SELECT `AS`
|
|
10
|
+
* alias). When two output columns collide on the same name the later one is
|
|
11
|
+
* suffixed `_2`, `_3`, … in SELECT order (legacy AlaSQL instead emitted
|
|
12
|
+
* `[name]`/`[name1]`; the differential harness normalizes between the two).
|
|
13
|
+
* `SELECT *` expands every column across all joined tables; `SELECT t.*`
|
|
14
|
+
* expands only table `t`'s columns.
|
|
15
|
+
*/
|
|
16
|
+
import type { ProjectionNode } from '../parser/ast.ts';
|
|
17
|
+
import type { PhysicalOp } from './op.ts';
|
|
18
|
+
export declare function physicalProject(child: PhysicalOp, projections: ProjectionNode[], qualified?: boolean): PhysicalOp;
|