@slexisvn/query-engine 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/binder/binder.d.ts +130 -0
- package/dist/binder/expression-binder.d.ts +168 -0
- package/dist/binder/scope.d.ts +40 -0
- package/dist/browser.d.ts +8 -0
- package/dist/catalog/catalog.d.ts +53 -0
- package/dist/catalog/function-registry.d.ts +26 -0
- package/dist/catalog/statistics-cache.d.ts +39 -0
- package/dist/catalog/statistics.d.ts +72 -0
- package/dist/catalog/tpch-schema.d.ts +15 -0
- package/dist/cli/cli-common.d.ts +11 -0
- package/dist/cli/coordinator.d.ts +1 -0
- package/dist/cli/format.d.ts +8 -0
- package/dist/cli/index.d.ts +1 -0
- package/dist/cli/loaders/csv-loader.d.ts +17 -0
- package/dist/cli/loaders/data-loader.d.ts +7 -0
- package/dist/cli/loaders/json-loader.d.ts +13 -0
- package/dist/cli/loaders/loader-factory.d.ts +4 -0
- package/dist/cli/repl.d.ts +6 -0
- package/dist/cli/worker.d.ts +1 -0
- package/dist/config.d.ts +42 -0
- package/dist/core.wasm +0 -0
- package/dist/dataframe/column-expr.d.ts +67 -0
- package/dist/dataframe/dataframe.d.ts +96 -0
- package/dist/dataframe/expr-types.d.ts +6 -0
- package/dist/dataframe/in-memory-relation.d.ts +31 -0
- package/dist/dataframe/index.d.ts +4 -0
- package/dist/dataframe/schema.d.ts +35 -0
- package/dist/dataframe/sql-expr-binder.d.ts +17 -0
- package/dist/dataframe/type-inference.d.ts +8 -0
- package/dist/distributed/cluster/cluster-manager.d.ts +54 -0
- package/dist/distributed/cluster/heartbeat-monitor.d.ts +27 -0
- package/dist/distributed/cluster/node-descriptor.d.ts +41 -0
- package/dist/distributed/distributed-types.d.ts +336 -0
- package/dist/distributed/execution/coordinator.d.ts +53 -0
- package/dist/distributed/execution/exchange-operator.d.ts +44 -0
- package/dist/distributed/execution/fragment-executor.d.ts +48 -0
- package/dist/distributed/execution/merge-exchange.d.ts +55 -0
- package/dist/distributed/optimizer/distributed-sort.d.ts +6 -0
- package/dist/distributed/optimizer/distribution-aware-join.d.ts +28 -0
- package/dist/distributed/optimizer/partial-aggregate.d.ts +9 -0
- package/dist/distributed/partition/partition-map.d.ts +27 -0
- package/dist/distributed/partition/partition-pruner.d.ts +33 -0
- package/dist/distributed/partition/partition-strategy.d.ts +43 -0
- package/dist/distributed/planner/distributed-planner.d.ts +71 -0
- package/dist/distributed/planner/exchange-placement.d.ts +19 -0
- package/dist/distributed/planner/expr-utils.d.ts +2 -0
- package/dist/distributed/planner/fragment.d.ts +47 -0
- package/dist/distributed/transport/chunk-codec.d.ts +18 -0
- package/dist/distributed/transport/http-transport.d.ts +49 -0
- package/dist/distributed/transport/transport.d.ts +13 -0
- package/dist/engine/query-engine.d.ts +142 -0
- package/dist/engine-entry.d.ts +12 -0
- package/dist/execution/builders/aggregate-builder.d.ts +46 -0
- package/dist/execution/builders/builder-utils.d.ts +5 -0
- package/dist/execution/builders/cte-builders.d.ts +20 -0
- package/dist/execution/builders/exchange-builders.d.ts +33 -0
- package/dist/execution/builders/join-builder.d.ts +67 -0
- package/dist/execution/builders/pipeline-builders.d.ts +30 -0
- package/dist/execution/builders/source-builders.d.ts +23 -0
- package/dist/execution/column-resolve.d.ts +7 -0
- package/dist/execution/execution-types.d.ts +33 -0
- package/dist/execution/expression-eval.d.ts +13 -0
- package/dist/execution/fragment-spec.d.ts +125 -0
- package/dist/execution/join-utils.d.ts +14 -0
- package/dist/execution/operator-registry.d.ts +9 -0
- package/dist/execution/operators/agg-wasm.d.ts +16 -0
- package/dist/execution/operators/dedup-core.d.ts +10 -0
- package/dist/execution/operators/dependent-join.d.ts +14 -0
- package/dist/execution/operators/distinct.d.ts +12 -0
- package/dist/execution/operators/filter.d.ts +87 -0
- package/dist/execution/operators/hash-aggregate.d.ts +121 -0
- package/dist/execution/operators/hash-join.d.ts +74 -0
- package/dist/execution/operators/index-scan.d.ts +34 -0
- package/dist/execution/operators/join-core.d.ts +47 -0
- package/dist/execution/operators/merge-join.d.ts +38 -0
- package/dist/execution/operators/nested-loop-join.d.ts +28 -0
- package/dist/execution/operators/projection.d.ts +20 -0
- package/dist/execution/operators/scan.d.ts +17 -0
- package/dist/execution/operators/sort.d.ts +48 -0
- package/dist/execution/operators/stream-aggregate.d.ts +30 -0
- package/dist/execution/operators/union.d.ts +13 -0
- package/dist/execution/operators/vector-aggregate.d.ts +73 -0
- package/dist/execution/operators/window.d.ts +22 -0
- package/dist/execution/physical-plan.d.ts +14 -0
- package/dist/execution/pipeline.d.ts +28 -0
- package/dist/execution/query-executor.d.ts +70 -0
- package/dist/execution/query-result.d.ts +15 -0
- package/dist/execution/result-sink.d.ts +26 -0
- package/dist/execution/scheduler.d.ts +8 -0
- package/dist/execution/vector-ops.d.ts +32 -0
- package/dist/execution/wasm-expr-eval.d.ts +7 -0
- package/dist/index.browser.js +17999 -0
- package/dist/index.cli.js +1002 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.node.js +21432 -0
- package/dist/optimizer/dphyp/cardinality.d.ts +69 -0
- package/dist/optimizer/dphyp/cost-model.d.ts +47 -0
- package/dist/optimizer/dphyp/dphyp.d.ts +32 -0
- package/dist/optimizer/dphyp/hypergraph.d.ts +38 -0
- package/dist/optimizer/optimizer.d.ts +12 -0
- package/dist/optimizer/pass.d.ts +5 -0
- package/dist/optimizer/passes/aggregate-pushdown.d.ts +6 -0
- package/dist/optimizer/passes/cte-optimization.d.ts +6 -0
- package/dist/optimizer/passes/empty-propagation.d.ts +6 -0
- package/dist/optimizer/passes/expr-walk.d.ts +20 -0
- package/dist/optimizer/passes/expression-simplifier.d.ts +8 -0
- package/dist/optimizer/passes/filter-ordering.d.ts +13 -0
- package/dist/optimizer/passes/having-pushdown.d.ts +6 -0
- package/dist/optimizer/passes/index-selection.d.ts +24 -0
- package/dist/optimizer/passes/join-elimination.d.ts +6 -0
- package/dist/optimizer/passes/join-reorder.d.ts +12 -0
- package/dist/optimizer/passes/join-residual-split.d.ts +6 -0
- package/dist/optimizer/passes/limit-pushdown.d.ts +6 -0
- package/dist/optimizer/passes/node-merge.d.ts +6 -0
- package/dist/optimizer/passes/outer-to-inner.d.ts +6 -0
- package/dist/optimizer/passes/physical-design.d.ts +12 -0
- package/dist/optimizer/passes/plan-refs.d.ts +22 -0
- package/dist/optimizer/passes/predicate-dedup.d.ts +6 -0
- package/dist/optimizer/passes/predicate-inference.d.ts +6 -0
- package/dist/optimizer/passes/predicate-pushdown.d.ts +9 -0
- package/dist/optimizer/passes/projection-pushdown.d.ts +6 -0
- package/dist/optimizer/passes/sort-elimination.d.ts +6 -0
- package/dist/optimizer/passes/subquery-unnesting.d.ts +6 -0
- package/dist/optimizer/passes/topn-fusion.d.ts +6 -0
- package/dist/parallel/chunk-transport.d.ts +24 -0
- package/dist/parallel/fragment-pool.d.ts +49 -0
- package/dist/parallel/fragment-worker.d.ts +1 -0
- package/dist/parallel/morsel-scheduler.d.ts +11 -0
- package/dist/parallel/parallel-dispatch.d.ts +69 -0
- package/dist/parallel/partial-spill.d.ts +3 -0
- package/dist/parallel/worker-messages.d.ts +243 -0
- package/dist/parallel/worker-pool.d.ts +62 -0
- package/dist/parallel/worker-thread.d.ts +1 -0
- package/dist/parser/ast.d.ts +298 -0
- package/dist/parser/lexer.d.ts +135 -0
- package/dist/parser/parser.d.ts +64 -0
- package/dist/planner/logical-plan.d.ts +250 -0
- package/dist/planner/logical-planner.d.ts +23 -0
- package/dist/planner/plan-formatter.d.ts +4 -0
- package/dist/planner/plan-visitor.d.ts +58 -0
- package/dist/runtime/platform.d.ts +4 -0
- package/dist/storage/backend/memory-storage-backend.d.ts +14 -0
- package/dist/storage/backend/node-storage-backend.d.ts +11 -0
- package/dist/storage/btree.d.ts +34 -0
- package/dist/storage/buffer-pool.d.ts +17 -0
- package/dist/storage/chunk.d.ts +26 -0
- package/dist/storage/column.d.ts +38 -0
- package/dist/storage/data-type.d.ts +54 -0
- package/dist/storage/dictionary-column.d.ts +33 -0
- package/dist/storage/page-store/file-page-store.d.ts +13 -0
- package/dist/storage/page-store/memory-page-store.d.ts +9 -0
- package/dist/storage/sab-arena.d.ts +26 -0
- package/dist/storage/serializer.d.ts +6 -0
- package/dist/storage/spill-manager/fs-storage.d.ts +11 -0
- package/dist/storage/spill-manager/memory-storage.d.ts +10 -0
- package/dist/storage/spill-manager/spill-manager.d.ts +17 -0
- package/dist/storage/storage-constants.d.ts +3 -0
- package/dist/storage/table.d.ts +31 -0
- package/dist/storage/temp-space/memory-temp-space.d.ts +11 -0
- package/dist/storage/temp-space/temp-directory-manager.d.ts +14 -0
- package/dist/utils/bitmap.d.ts +11 -0
- package/dist/utils/hash.d.ts +1 -0
- package/dist/utils/lru-cache.d.ts +24 -0
- package/dist/utils/priority-queue.d.ts +18 -0
- package/dist/wasm/dispatch.d.ts +13 -0
- package/dist/wasm/fetch-byte-source.d.ts +2 -0
- package/dist/wasm/kernels/core-instance.d.ts +6 -0
- package/dist/wasm/kernels/kernel-factory.d.ts +8 -0
- package/dist/wasm/kernels/wasm-aggregate.d.ts +6 -0
- package/dist/wasm/kernels/wasm-arithmetic.d.ts +13 -0
- package/dist/wasm/kernels/wasm-filter-f64.d.ts +8 -0
- package/dist/wasm/kernels/wasm-filter.d.ts +5 -0
- package/dist/wasm/loader.d.ts +17 -0
- package/dist/wasm/node-byte-source.d.ts +1 -0
- package/dist/wasm/region-allocator.d.ts +23 -0
- package/dist/wasm/register-kernels.d.ts +1 -0
- package/dist/wasm/wasm-loader-base.d.ts +33 -0
- package/dist/wasm/wasm-types.d.ts +103 -0
- package/package.json +60 -0
|
@@ -0,0 +1,1002 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __esm = (fn, res) => function __init() {
|
|
5
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
6
|
+
};
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
// src/planner/logical-plan.ts
|
|
13
|
+
var logical_plan_exports = {};
|
|
14
|
+
__export(logical_plan_exports, {
|
|
15
|
+
JoinType: () => JoinType,
|
|
16
|
+
LogicalAggregate: () => LogicalAggregate,
|
|
17
|
+
LogicalCTEAnchor: () => LogicalCTEAnchor,
|
|
18
|
+
LogicalCTEScan: () => LogicalCTEScan,
|
|
19
|
+
LogicalDependentJoin: () => LogicalDependentJoin,
|
|
20
|
+
LogicalDistinct: () => LogicalDistinct,
|
|
21
|
+
LogicalExchange: () => LogicalExchange,
|
|
22
|
+
LogicalExchangeReceive: () => LogicalExchangeReceive,
|
|
23
|
+
LogicalFilter: () => LogicalFilter,
|
|
24
|
+
LogicalFinalAggregate: () => LogicalFinalAggregate,
|
|
25
|
+
LogicalIndexScan: () => LogicalIndexScan,
|
|
26
|
+
LogicalJoin: () => LogicalJoin,
|
|
27
|
+
LogicalLimit: () => LogicalLimit,
|
|
28
|
+
LogicalMaterialize: () => LogicalMaterialize,
|
|
29
|
+
LogicalMergeExchange: () => LogicalMergeExchange,
|
|
30
|
+
LogicalPartialAggregate: () => LogicalPartialAggregate,
|
|
31
|
+
LogicalProject: () => LogicalProject,
|
|
32
|
+
LogicalScan: () => LogicalScan,
|
|
33
|
+
LogicalSingleRow: () => LogicalSingleRow,
|
|
34
|
+
LogicalSort: () => LogicalSort,
|
|
35
|
+
LogicalTopN: () => LogicalTopN,
|
|
36
|
+
LogicalUnion: () => LogicalUnion,
|
|
37
|
+
LogicalWindow: () => LogicalWindow,
|
|
38
|
+
NullOrder: () => NullOrder,
|
|
39
|
+
PhysicalStrategy: () => PhysicalStrategy,
|
|
40
|
+
PlanNodeType: () => PlanNodeType,
|
|
41
|
+
SortDirection: () => SortDirection,
|
|
42
|
+
getChildren: () => getChildren,
|
|
43
|
+
planToString: () => planToString,
|
|
44
|
+
setChildren: () => setChildren
|
|
45
|
+
});
|
|
46
|
+
function LogicalScan(table, columns, alias) {
|
|
47
|
+
return { type: "Scan" /* SCAN */, table, columns, alias: alias || table };
|
|
48
|
+
}
|
|
49
|
+
function LogicalFilter(condition, child) {
|
|
50
|
+
return { type: "Filter" /* FILTER */, condition, children: [child] };
|
|
51
|
+
}
|
|
52
|
+
function LogicalProject(expressions, child) {
|
|
53
|
+
return { type: "Project" /* PROJECT */, expressions, children: [child] };
|
|
54
|
+
}
|
|
55
|
+
function LogicalJoin(joinType, condition, left, right, physicalStrategy = "HASH" /* HASH */) {
|
|
56
|
+
return {
|
|
57
|
+
type: "Join" /* JOIN */,
|
|
58
|
+
joinType,
|
|
59
|
+
condition,
|
|
60
|
+
children: [left, right],
|
|
61
|
+
physicalStrategy
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
function LogicalAggregate(groupBy, aggregates, child, physicalStrategy = "HASH" /* HASH */) {
|
|
65
|
+
return {
|
|
66
|
+
type: "Aggregate" /* AGGREGATE */,
|
|
67
|
+
groupBy,
|
|
68
|
+
aggregates,
|
|
69
|
+
children: [child],
|
|
70
|
+
physicalStrategy
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
function LogicalSort(orderKeys, child) {
|
|
74
|
+
return { type: "Sort" /* SORT */, orderKeys, children: [child] };
|
|
75
|
+
}
|
|
76
|
+
function LogicalLimit(count, offset, child) {
|
|
77
|
+
return { type: "Limit" /* LIMIT */, count, offset: offset || 0, children: [child] };
|
|
78
|
+
}
|
|
79
|
+
function LogicalDistinct(child) {
|
|
80
|
+
return { type: "Distinct" /* DISTINCT */, children: [child] };
|
|
81
|
+
}
|
|
82
|
+
function LogicalUnion(left, right, all) {
|
|
83
|
+
return { type: "Union" /* UNION */, all: !!all, children: [left, right] };
|
|
84
|
+
}
|
|
85
|
+
function LogicalCTEScan(cteName, cteId) {
|
|
86
|
+
return { type: "CTEScan" /* CTE_SCAN */, cteName, cteId, children: [] };
|
|
87
|
+
}
|
|
88
|
+
function LogicalCTEAnchor(cteName, cteId, producer, consumer) {
|
|
89
|
+
return { type: "CTEAnchor" /* CTE_ANCHOR */, cteName, cteId, children: [producer, consumer] };
|
|
90
|
+
}
|
|
91
|
+
function LogicalDependentJoin(child, subquery, correlatedColumns, subqueryType, condition) {
|
|
92
|
+
return {
|
|
93
|
+
type: "DependentJoin" /* DEPENDENT_JOIN */,
|
|
94
|
+
correlatedColumns,
|
|
95
|
+
subqueryType,
|
|
96
|
+
condition,
|
|
97
|
+
children: [child, subquery]
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
function LogicalTopN(orderKeys, count, offset, child) {
|
|
101
|
+
return { type: "TopN" /* TOP_N */, orderKeys, count, offset: offset || 0, children: [child] };
|
|
102
|
+
}
|
|
103
|
+
function LogicalIndexScan(table, alias, indexName, columnName, scanType, scanKey, scanLow, scanHigh, lowInc, highInc, columns) {
|
|
104
|
+
return {
|
|
105
|
+
type: "IndexScan" /* INDEX_SCAN */,
|
|
106
|
+
table,
|
|
107
|
+
alias: alias || table,
|
|
108
|
+
indexName,
|
|
109
|
+
columnName,
|
|
110
|
+
scanType,
|
|
111
|
+
scanKey,
|
|
112
|
+
scanLow,
|
|
113
|
+
scanHigh,
|
|
114
|
+
lowInc,
|
|
115
|
+
highInc,
|
|
116
|
+
columns
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
function LogicalWindow(windowExprs, child) {
|
|
120
|
+
return { type: "Window" /* WINDOW */, windowExprs, children: [child] };
|
|
121
|
+
}
|
|
122
|
+
function LogicalMaterialize(child) {
|
|
123
|
+
return { type: "Materialize" /* MATERIALIZE */, children: [child] };
|
|
124
|
+
}
|
|
125
|
+
function LogicalExchange(exchangeType, partitionKeys, partitionCount, child) {
|
|
126
|
+
return {
|
|
127
|
+
type: "Exchange" /* EXCHANGE */,
|
|
128
|
+
exchangeType,
|
|
129
|
+
partitionKeys: partitionKeys || [],
|
|
130
|
+
partitionCount: partitionCount || 0,
|
|
131
|
+
children: [child]
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
function LogicalPartialAggregate(groupBy, aggregates, child) {
|
|
135
|
+
return {
|
|
136
|
+
type: "PartialAggregate" /* PARTIAL_AGGREGATE */,
|
|
137
|
+
groupBy,
|
|
138
|
+
aggregates,
|
|
139
|
+
children: [child],
|
|
140
|
+
physicalStrategy: "HASH" /* HASH */
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
function LogicalFinalAggregate(groupBy, aggregates, partialAggregates, child) {
|
|
144
|
+
return {
|
|
145
|
+
type: "FinalAggregate" /* FINAL_AGGREGATE */,
|
|
146
|
+
groupBy,
|
|
147
|
+
aggregates,
|
|
148
|
+
partialAggregates,
|
|
149
|
+
children: [child],
|
|
150
|
+
physicalStrategy: "HASH" /* HASH */
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
function LogicalMergeExchange(orderKeys, limit, child) {
|
|
154
|
+
return {
|
|
155
|
+
type: "MergeExchange" /* MERGE_EXCHANGE */,
|
|
156
|
+
orderKeys,
|
|
157
|
+
limit: limit || null,
|
|
158
|
+
children: [child]
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
function LogicalExchangeReceive(sourceFragmentIds, schema) {
|
|
162
|
+
return {
|
|
163
|
+
type: "ExchangeReceive" /* EXCHANGE_RECEIVE */,
|
|
164
|
+
sourceFragmentIds,
|
|
165
|
+
schema: schema || [],
|
|
166
|
+
children: []
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
function LogicalSingleRow() {
|
|
170
|
+
return { type: "SingleRow" /* SINGLE_ROW */, children: [] };
|
|
171
|
+
}
|
|
172
|
+
function getChildren(node) {
|
|
173
|
+
return node.children || [];
|
|
174
|
+
}
|
|
175
|
+
function setChildren(node, children) {
|
|
176
|
+
return { ...node, children };
|
|
177
|
+
}
|
|
178
|
+
function planToString(node, indent = 0) {
|
|
179
|
+
const prefix = " ".repeat(indent);
|
|
180
|
+
let str = `${prefix}${node.type}`;
|
|
181
|
+
switch (node.type) {
|
|
182
|
+
case "Scan" /* SCAN */:
|
|
183
|
+
str += `(${node.table}${node.alias !== node.table ? ` AS ${node.alias}` : ""})`;
|
|
184
|
+
break;
|
|
185
|
+
case "Join" /* JOIN */:
|
|
186
|
+
str += `(${node.joinType})`;
|
|
187
|
+
break;
|
|
188
|
+
case "Limit" /* LIMIT */:
|
|
189
|
+
str += `(${node.count}${node.offset ? `, offset=${node.offset}` : ""})`;
|
|
190
|
+
break;
|
|
191
|
+
case "CTEScan" /* CTE_SCAN */:
|
|
192
|
+
str += `(${node.cteName})`;
|
|
193
|
+
break;
|
|
194
|
+
case "CTEAnchor" /* CTE_ANCHOR */:
|
|
195
|
+
str += `(${node.cteName})`;
|
|
196
|
+
break;
|
|
197
|
+
case "DependentJoin" /* DEPENDENT_JOIN */:
|
|
198
|
+
str += `(${node.subqueryType})`;
|
|
199
|
+
break;
|
|
200
|
+
case "Window" /* WINDOW */:
|
|
201
|
+
str += `(${node.windowExprs.map((w) => w.name).join(", ")})`;
|
|
202
|
+
break;
|
|
203
|
+
case "TopN" /* TOP_N */:
|
|
204
|
+
str += `(${node.count}${node.offset ? `, offset=${node.offset}` : ""})`;
|
|
205
|
+
break;
|
|
206
|
+
case "IndexScan" /* INDEX_SCAN */:
|
|
207
|
+
str += `(${node.table} using ${node.indexName})`;
|
|
208
|
+
break;
|
|
209
|
+
case "Exchange" /* EXCHANGE */:
|
|
210
|
+
str += `(${node.exchangeType})`;
|
|
211
|
+
break;
|
|
212
|
+
case "PartialAggregate" /* PARTIAL_AGGREGATE */:
|
|
213
|
+
str += `(partial)`;
|
|
214
|
+
break;
|
|
215
|
+
case "FinalAggregate" /* FINAL_AGGREGATE */:
|
|
216
|
+
str += `(final)`;
|
|
217
|
+
break;
|
|
218
|
+
case "MergeExchange" /* MERGE_EXCHANGE */:
|
|
219
|
+
str += `(${node.limit ? `limit=${node.limit}` : "all"})`;
|
|
220
|
+
break;
|
|
221
|
+
case "ExchangeReceive" /* EXCHANGE_RECEIVE */:
|
|
222
|
+
str += `(fragments=[${node.sourceFragmentIds.join(",")}])`;
|
|
223
|
+
break;
|
|
224
|
+
}
|
|
225
|
+
str += "\n";
|
|
226
|
+
for (const child of getChildren(node)) {
|
|
227
|
+
str += planToString(child, indent + 1);
|
|
228
|
+
}
|
|
229
|
+
return str;
|
|
230
|
+
}
|
|
231
|
+
var PlanNodeType, JoinType, PhysicalStrategy, SortDirection, NullOrder;
|
|
232
|
+
var init_logical_plan = __esm({
|
|
233
|
+
"src/planner/logical-plan.ts"() {
|
|
234
|
+
"use strict";
|
|
235
|
+
PlanNodeType = /* @__PURE__ */ ((PlanNodeType2) => {
|
|
236
|
+
PlanNodeType2["SCAN"] = "Scan";
|
|
237
|
+
PlanNodeType2["FILTER"] = "Filter";
|
|
238
|
+
PlanNodeType2["PROJECT"] = "Project";
|
|
239
|
+
PlanNodeType2["JOIN"] = "Join";
|
|
240
|
+
PlanNodeType2["AGGREGATE"] = "Aggregate";
|
|
241
|
+
PlanNodeType2["SORT"] = "Sort";
|
|
242
|
+
PlanNodeType2["LIMIT"] = "Limit";
|
|
243
|
+
PlanNodeType2["DISTINCT"] = "Distinct";
|
|
244
|
+
PlanNodeType2["UNION"] = "Union";
|
|
245
|
+
PlanNodeType2["CTE_SCAN"] = "CTEScan";
|
|
246
|
+
PlanNodeType2["CTE_ANCHOR"] = "CTEAnchor";
|
|
247
|
+
PlanNodeType2["DEPENDENT_JOIN"] = "DependentJoin";
|
|
248
|
+
PlanNodeType2["MATERIALIZE"] = "Materialize";
|
|
249
|
+
PlanNodeType2["EMPTY"] = "Empty";
|
|
250
|
+
PlanNodeType2["TOP_N"] = "TopN";
|
|
251
|
+
PlanNodeType2["INDEX_SCAN"] = "IndexScan";
|
|
252
|
+
PlanNodeType2["WINDOW"] = "Window";
|
|
253
|
+
PlanNodeType2["EXCHANGE"] = "Exchange";
|
|
254
|
+
PlanNodeType2["PARTIAL_AGGREGATE"] = "PartialAggregate";
|
|
255
|
+
PlanNodeType2["FINAL_AGGREGATE"] = "FinalAggregate";
|
|
256
|
+
PlanNodeType2["MERGE_EXCHANGE"] = "MergeExchange";
|
|
257
|
+
PlanNodeType2["EXCHANGE_RECEIVE"] = "ExchangeReceive";
|
|
258
|
+
PlanNodeType2["SINGLE_ROW"] = "SingleRow";
|
|
259
|
+
return PlanNodeType2;
|
|
260
|
+
})(PlanNodeType || {});
|
|
261
|
+
JoinType = /* @__PURE__ */ ((JoinType2) => {
|
|
262
|
+
JoinType2["INNER"] = "INNER";
|
|
263
|
+
JoinType2["LEFT"] = "LEFT";
|
|
264
|
+
JoinType2["RIGHT"] = "RIGHT";
|
|
265
|
+
JoinType2["FULL"] = "FULL";
|
|
266
|
+
JoinType2["SEMI"] = "SEMI";
|
|
267
|
+
JoinType2["ANTI"] = "ANTI";
|
|
268
|
+
JoinType2["MARK"] = "MARK";
|
|
269
|
+
JoinType2["SINGLE"] = "SINGLE";
|
|
270
|
+
JoinType2["CROSS"] = "CROSS";
|
|
271
|
+
return JoinType2;
|
|
272
|
+
})(JoinType || {});
|
|
273
|
+
PhysicalStrategy = /* @__PURE__ */ ((PhysicalStrategy2) => {
|
|
274
|
+
PhysicalStrategy2["HASH"] = "HASH";
|
|
275
|
+
PhysicalStrategy2["MERGE"] = "MERGE";
|
|
276
|
+
PhysicalStrategy2["NESTED_LOOP"] = "NESTED_LOOP";
|
|
277
|
+
PhysicalStrategy2["STREAM"] = "STREAM";
|
|
278
|
+
PhysicalStrategy2["UNGROUPED"] = "UNGROUPED";
|
|
279
|
+
PhysicalStrategy2["PERFECT_HASH"] = "PERFECT_HASH";
|
|
280
|
+
return PhysicalStrategy2;
|
|
281
|
+
})(PhysicalStrategy || {});
|
|
282
|
+
SortDirection = /* @__PURE__ */ ((SortDirection2) => {
|
|
283
|
+
SortDirection2["ASC"] = "ASC";
|
|
284
|
+
SortDirection2["DESC"] = "DESC";
|
|
285
|
+
return SortDirection2;
|
|
286
|
+
})(SortDirection || {});
|
|
287
|
+
NullOrder = /* @__PURE__ */ ((NullOrder2) => {
|
|
288
|
+
NullOrder2["FIRST"] = "FIRST";
|
|
289
|
+
NullOrder2["LAST"] = "LAST";
|
|
290
|
+
return NullOrder2;
|
|
291
|
+
})(NullOrder || {});
|
|
292
|
+
}
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
// src/cli/index.ts
|
|
296
|
+
import path5 from "path";
|
|
297
|
+
import { fork } from "child_process";
|
|
298
|
+
import { availableParallelism } from "os";
|
|
299
|
+
import { fileURLToPath } from "url";
|
|
300
|
+
import { Catalog, QueryEngine } from "./index.node.js";
|
|
301
|
+
|
|
302
|
+
// src/cli/cli-common.ts
|
|
303
|
+
import fs2 from "fs";
|
|
304
|
+
import path4 from "path";
|
|
305
|
+
|
|
306
|
+
// src/cli/loaders/loader-factory.ts
|
|
307
|
+
import path3 from "path";
|
|
308
|
+
|
|
309
|
+
// src/cli/loaders/csv-loader.ts
|
|
310
|
+
import fs from "fs";
|
|
311
|
+
import csv from "csv-parser";
|
|
312
|
+
import path from "path";
|
|
313
|
+
import { DataType, DEFAULT_CHUNK_SIZE, Table } from "./index.node.js";
|
|
314
|
+
|
|
315
|
+
// src/cli/loaders/data-loader.ts
|
|
316
|
+
var DataLoader = class {
|
|
317
|
+
async load(engine, filePath) {
|
|
318
|
+
throw new Error("Method not implemented.");
|
|
319
|
+
}
|
|
320
|
+
registerToCatalog(engine, tableName, schema, table) {
|
|
321
|
+
engine.catalog.registerTable(tableName, schema);
|
|
322
|
+
engine.catalog.registerTableStorage(tableName, table);
|
|
323
|
+
}
|
|
324
|
+
buildSchema(firstRow, classify) {
|
|
325
|
+
const schema = [];
|
|
326
|
+
for (const [key, value] of Object.entries(firstRow)) {
|
|
327
|
+
schema.push({ name: key, dataType: classify(value) });
|
|
328
|
+
}
|
|
329
|
+
return schema;
|
|
330
|
+
}
|
|
331
|
+
};
|
|
332
|
+
|
|
333
|
+
// src/cli/loaders/csv-loader.ts
|
|
334
|
+
var CSVLoader = class extends DataLoader {
|
|
335
|
+
allowedDir;
|
|
336
|
+
constructor(allowedDir = null) {
|
|
337
|
+
super();
|
|
338
|
+
this.allowedDir = allowedDir;
|
|
339
|
+
}
|
|
340
|
+
validatePath(filePath) {
|
|
341
|
+
const resolved = path.resolve(filePath);
|
|
342
|
+
if (this.allowedDir) {
|
|
343
|
+
const allowedResolved = path.resolve(this.allowedDir);
|
|
344
|
+
if (!resolved.startsWith(allowedResolved + path.sep) && resolved !== allowedResolved) {
|
|
345
|
+
throw new Error(`Path traversal denied: ${filePath} is outside allowed directory`);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
if (/\.\.[/\\]/.test(filePath)) {
|
|
349
|
+
const cwd = process.cwd();
|
|
350
|
+
if (!resolved.startsWith(cwd + path.sep) && resolved !== cwd) {
|
|
351
|
+
throw new Error(`Path traversal denied: ${filePath} resolves outside working directory`);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
return resolved;
|
|
355
|
+
}
|
|
356
|
+
async load(engine, filePath, options = {}) {
|
|
357
|
+
const resolvedPath = this.validatePath(filePath);
|
|
358
|
+
const partitionIndex = options.partitionIndex ?? null;
|
|
359
|
+
const partitionCount = options.partitionCount ?? null;
|
|
360
|
+
const usePartitionFilter = partitionIndex !== null && partitionCount !== null;
|
|
361
|
+
const maxRows = options.maxRows ?? null;
|
|
362
|
+
return new Promise((resolve, reject) => {
|
|
363
|
+
const tableName = path.basename(resolvedPath, path.extname(resolvedPath)).toUpperCase();
|
|
364
|
+
let schema = null;
|
|
365
|
+
let table = null;
|
|
366
|
+
let batch = [];
|
|
367
|
+
let rowIndex = 0;
|
|
368
|
+
let done = false;
|
|
369
|
+
const flushBatch = async () => {
|
|
370
|
+
if (batch.length === 0) return;
|
|
371
|
+
await table.insertRows(batch);
|
|
372
|
+
batch = [];
|
|
373
|
+
};
|
|
374
|
+
const fileStream = fs.createReadStream(resolvedPath);
|
|
375
|
+
const stream = fileStream.pipe(csv());
|
|
376
|
+
const finish = () => {
|
|
377
|
+
if (done) return;
|
|
378
|
+
done = true;
|
|
379
|
+
fileStream.destroy();
|
|
380
|
+
flushBatch().then(() => resolve(tableName)).catch(reject);
|
|
381
|
+
};
|
|
382
|
+
stream.on("data", (data) => {
|
|
383
|
+
if (done) return;
|
|
384
|
+
if (!schema) {
|
|
385
|
+
schema = this.inferSchema(data);
|
|
386
|
+
const pageStore = engine.storageBackend.createPageStore(engine.tempManager.allocate("buffer", tableName));
|
|
387
|
+
table = new Table(tableName, schema, pageStore);
|
|
388
|
+
this.registerToCatalog(engine, tableName, schema, table);
|
|
389
|
+
}
|
|
390
|
+
const currentRow = rowIndex++;
|
|
391
|
+
if (maxRows !== null && currentRow >= maxRows) {
|
|
392
|
+
finish();
|
|
393
|
+
return;
|
|
394
|
+
}
|
|
395
|
+
if (usePartitionFilter && currentRow % partitionCount !== partitionIndex) {
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
batch.push(this.convertRow(data, schema));
|
|
399
|
+
if (batch.length >= DEFAULT_CHUNK_SIZE) {
|
|
400
|
+
stream.pause();
|
|
401
|
+
flushBatch().then(() => stream.resume()).catch(reject);
|
|
402
|
+
}
|
|
403
|
+
});
|
|
404
|
+
stream.on("end", async () => {
|
|
405
|
+
if (done) return;
|
|
406
|
+
done = true;
|
|
407
|
+
try {
|
|
408
|
+
await flushBatch();
|
|
409
|
+
resolve(tableName);
|
|
410
|
+
} catch (err) {
|
|
411
|
+
reject(err);
|
|
412
|
+
}
|
|
413
|
+
});
|
|
414
|
+
stream.on("error", (err) => {
|
|
415
|
+
if (!done) reject(err);
|
|
416
|
+
});
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
inferSchema(firstRow) {
|
|
420
|
+
return this.buildSchema(firstRow, (value) => {
|
|
421
|
+
let type = DataType.VARCHAR;
|
|
422
|
+
if (value && value.trim() !== "") {
|
|
423
|
+
const trimmed = value.trim();
|
|
424
|
+
if (/^(true|false)$/i.test(trimmed)) {
|
|
425
|
+
type = DataType.BOOLEAN;
|
|
426
|
+
} else if (!isNaN(Number(trimmed))) {
|
|
427
|
+
type = Number.isInteger(Number(trimmed)) ? DataType.INT32 : DataType.FLOAT64;
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
return type;
|
|
431
|
+
});
|
|
432
|
+
}
|
|
433
|
+
convertRow(rowObj, schema) {
|
|
434
|
+
const row = new Array(schema.length);
|
|
435
|
+
for (let i = 0; i < schema.length; i++) {
|
|
436
|
+
const val = rowObj[schema[i].name];
|
|
437
|
+
if (val === void 0 || val === null || val === "") {
|
|
438
|
+
row[i] = null;
|
|
439
|
+
continue;
|
|
440
|
+
}
|
|
441
|
+
const trimmed = typeof val === "string" ? val.trim() : val;
|
|
442
|
+
if (trimmed === "") {
|
|
443
|
+
row[i] = null;
|
|
444
|
+
continue;
|
|
445
|
+
}
|
|
446
|
+
switch (schema[i].dataType) {
|
|
447
|
+
case DataType.BOOLEAN:
|
|
448
|
+
row[i] = trimmed.toLowerCase() === "true";
|
|
449
|
+
break;
|
|
450
|
+
case DataType.INT32:
|
|
451
|
+
row[i] = parseInt(trimmed, 10);
|
|
452
|
+
break;
|
|
453
|
+
case DataType.FLOAT64:
|
|
454
|
+
row[i] = parseFloat(trimmed);
|
|
455
|
+
break;
|
|
456
|
+
default:
|
|
457
|
+
row[i] = val;
|
|
458
|
+
break;
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
return row;
|
|
462
|
+
}
|
|
463
|
+
};
|
|
464
|
+
|
|
465
|
+
// src/cli/loaders/json-loader.ts
|
|
466
|
+
import { createReadStream } from "fs";
|
|
467
|
+
import path2 from "path";
|
|
468
|
+
import { DataType as DataType2, DEFAULT_CHUNK_SIZE as DEFAULT_CHUNK_SIZE2, Table as Table2 } from "./index.node.js";
|
|
469
|
+
var JSONLoader = class extends DataLoader {
|
|
470
|
+
async load(engine, filePath) {
|
|
471
|
+
const tableName = path2.basename(filePath, path2.extname(filePath)).toUpperCase();
|
|
472
|
+
let schema = null;
|
|
473
|
+
let table = null;
|
|
474
|
+
let batch = [];
|
|
475
|
+
for await (const obj of streamJsonArray(filePath)) {
|
|
476
|
+
if (!schema) {
|
|
477
|
+
schema = this.inferSchema(obj);
|
|
478
|
+
const pageStore = engine.storageBackend.createPageStore(engine.tempManager.allocate("buffer", tableName));
|
|
479
|
+
table = new Table2(tableName, schema, pageStore);
|
|
480
|
+
this.registerToCatalog(engine, tableName, schema, table);
|
|
481
|
+
}
|
|
482
|
+
const row = new Array(schema.length);
|
|
483
|
+
for (let c = 0; c < schema.length; c++) {
|
|
484
|
+
const val = obj[schema[c].name];
|
|
485
|
+
row[c] = val === void 0 ? null : val;
|
|
486
|
+
}
|
|
487
|
+
batch.push(row);
|
|
488
|
+
if (batch.length >= DEFAULT_CHUNK_SIZE2) {
|
|
489
|
+
await table.insertRows(batch);
|
|
490
|
+
batch = [];
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
if (!table) {
|
|
494
|
+
throw new Error("JSON array is empty.");
|
|
495
|
+
}
|
|
496
|
+
if (batch.length > 0) {
|
|
497
|
+
await table.insertRows(batch);
|
|
498
|
+
}
|
|
499
|
+
return tableName;
|
|
500
|
+
}
|
|
501
|
+
inferSchema(firstRow) {
|
|
502
|
+
return this.buildSchema(firstRow, (value) => {
|
|
503
|
+
let type = DataType2.VARCHAR;
|
|
504
|
+
if (typeof value === "boolean") {
|
|
505
|
+
type = DataType2.BOOLEAN;
|
|
506
|
+
} else if (typeof value === "number") {
|
|
507
|
+
type = Number.isInteger(value) ? DataType2.INT32 : DataType2.FLOAT64;
|
|
508
|
+
}
|
|
509
|
+
return type;
|
|
510
|
+
});
|
|
511
|
+
}
|
|
512
|
+
};
|
|
513
|
+
async function* streamJsonArray(filePath) {
|
|
514
|
+
const stream = createReadStream(filePath, { encoding: "utf8", highWaterMark: 64 * 1024 });
|
|
515
|
+
let depth = 0;
|
|
516
|
+
let inString = false;
|
|
517
|
+
let escape = false;
|
|
518
|
+
let objectStart = -1;
|
|
519
|
+
let buffer = "";
|
|
520
|
+
let scanFrom = 0;
|
|
521
|
+
let seenArrayOpen = false;
|
|
522
|
+
for await (const chunk of stream) {
|
|
523
|
+
scanFrom = buffer.length;
|
|
524
|
+
buffer += chunk;
|
|
525
|
+
let i = scanFrom;
|
|
526
|
+
while (i < buffer.length) {
|
|
527
|
+
const ch = buffer[i];
|
|
528
|
+
if (escape) {
|
|
529
|
+
escape = false;
|
|
530
|
+
i++;
|
|
531
|
+
continue;
|
|
532
|
+
}
|
|
533
|
+
if (ch === "\\" && inString) {
|
|
534
|
+
escape = true;
|
|
535
|
+
i++;
|
|
536
|
+
continue;
|
|
537
|
+
}
|
|
538
|
+
if (ch === '"') {
|
|
539
|
+
inString = !inString;
|
|
540
|
+
i++;
|
|
541
|
+
continue;
|
|
542
|
+
}
|
|
543
|
+
if (inString) {
|
|
544
|
+
i++;
|
|
545
|
+
continue;
|
|
546
|
+
}
|
|
547
|
+
if (!seenArrayOpen) {
|
|
548
|
+
if (ch === "[") seenArrayOpen = true;
|
|
549
|
+
i++;
|
|
550
|
+
continue;
|
|
551
|
+
}
|
|
552
|
+
if (ch === "{") {
|
|
553
|
+
if (depth === 0) objectStart = i;
|
|
554
|
+
depth++;
|
|
555
|
+
} else if (ch === "}") {
|
|
556
|
+
depth--;
|
|
557
|
+
if (depth === 0 && objectStart !== -1) {
|
|
558
|
+
yield JSON.parse(buffer.substring(objectStart, i + 1));
|
|
559
|
+
objectStart = -1;
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
i++;
|
|
563
|
+
}
|
|
564
|
+
if (objectStart !== -1) {
|
|
565
|
+
buffer = buffer.substring(objectStart);
|
|
566
|
+
objectStart = 0;
|
|
567
|
+
} else {
|
|
568
|
+
buffer = "";
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
// src/cli/loaders/loader-factory.ts
|
|
574
|
+
var LoaderFactory = class {
|
|
575
|
+
static getLoader(filePath) {
|
|
576
|
+
const ext = path3.extname(filePath).toLowerCase();
|
|
577
|
+
switch (ext) {
|
|
578
|
+
case ".csv":
|
|
579
|
+
return new CSVLoader();
|
|
580
|
+
case ".json":
|
|
581
|
+
return new JSONLoader();
|
|
582
|
+
default:
|
|
583
|
+
throw new Error(`Unsupported file extension: ${ext}`);
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
};
|
|
587
|
+
|
|
588
|
+
// src/cli/cli-common.ts
|
|
589
|
+
async function loadDataFiles(engine, catalog, dataPaths, options = {}) {
|
|
590
|
+
const loadOptions = options.loadOptions ?? {};
|
|
591
|
+
const formatLoadLine = options.formatLoadLine ?? (({ tableName, rowCount, dataPath }) => `[load] ${tableName} (${rowCount} rows) from ${dataPath}`);
|
|
592
|
+
for (const dp of dataPaths) {
|
|
593
|
+
const resolvedPath = path4.resolve(process.cwd(), dp);
|
|
594
|
+
if (!fs2.existsSync(resolvedPath)) {
|
|
595
|
+
console.error(`File not found: ${resolvedPath}`);
|
|
596
|
+
process.exit(1);
|
|
597
|
+
}
|
|
598
|
+
const loader = LoaderFactory.getLoader(resolvedPath);
|
|
599
|
+
const tableName = await loader.load(engine, resolvedPath, loadOptions);
|
|
600
|
+
const storage = catalog.getTableStorage(tableName);
|
|
601
|
+
const rowCount = storage ? storage.rowCount() : 0;
|
|
602
|
+
console.log(formatLoadLine({ tableName, rowCount, dataPath: dp }));
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
// src/cli/repl.ts
|
|
607
|
+
import readline from "readline";
|
|
608
|
+
import { highlight } from "cli-highlight";
|
|
609
|
+
|
|
610
|
+
// src/cli/format.ts
|
|
611
|
+
function formatResult(result) {
|
|
612
|
+
if (!result || !result.rows || result.rows.length === 0) {
|
|
613
|
+
console.log("Empty result set.");
|
|
614
|
+
return;
|
|
615
|
+
}
|
|
616
|
+
const columnNames = result.columns || Object.keys(result.rows[0]);
|
|
617
|
+
if (columnNames.length === 1 && (columnNames[0] === "EXPLAIN_PLAN" || columnNames[0] === "EXPLAIN_ANALYZE")) {
|
|
618
|
+
console.log(`
|
|
619
|
+
${result.rows[0][columnNames[0]]}
|
|
620
|
+
`);
|
|
621
|
+
return;
|
|
622
|
+
}
|
|
623
|
+
const colWidths = columnNames.map((name) => name.length);
|
|
624
|
+
for (const row of result.rows) {
|
|
625
|
+
for (let i = 0; i < columnNames.length; i++) {
|
|
626
|
+
const val = row[columnNames[i]];
|
|
627
|
+
const str = String(val ?? "NULL");
|
|
628
|
+
if (str.length > colWidths[i]) {
|
|
629
|
+
colWidths[i] = str.length;
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
const separator = "+" + colWidths.map((w) => "-".repeat(w + 2)).join("+") + "+";
|
|
634
|
+
console.log(separator);
|
|
635
|
+
console.log("|" + columnNames.map((name, i) => " " + name.padEnd(colWidths[i]) + " ").join("|") + "|");
|
|
636
|
+
console.log(separator);
|
|
637
|
+
for (const row of result.rows) {
|
|
638
|
+
console.log("|" + columnNames.map((name, i) => {
|
|
639
|
+
const val = row[name];
|
|
640
|
+
const str = String(val ?? "NULL");
|
|
641
|
+
return " " + str.padEnd(colWidths[i]) + " ";
|
|
642
|
+
}).join("|") + "|");
|
|
643
|
+
}
|
|
644
|
+
console.log(separator);
|
|
645
|
+
console.log(`${result.rows.length} row(s) returned.
|
|
646
|
+
`);
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
// src/cli/repl.ts
|
|
650
|
+
function startREPL(engine, options = {}) {
|
|
651
|
+
const coordinator = options.coordinator || null;
|
|
652
|
+
const rl = readline.createInterface({
|
|
653
|
+
input: process.stdin,
|
|
654
|
+
output: process.stdout,
|
|
655
|
+
prompt: coordinator ? "dist> " : "sql> "
|
|
656
|
+
});
|
|
657
|
+
const originalWriteToOutput = rl._writeToOutput.bind(rl);
|
|
658
|
+
rl._writeToOutput = function(stringToWrite) {
|
|
659
|
+
const promptPatterns = ["sql> ", "...> ", "dist> "];
|
|
660
|
+
let promptIdx = -1;
|
|
661
|
+
let promptLen = 0;
|
|
662
|
+
for (const p of promptPatterns) {
|
|
663
|
+
const idx = stringToWrite.indexOf(p);
|
|
664
|
+
if (idx > -1) {
|
|
665
|
+
promptIdx = idx + p.length;
|
|
666
|
+
promptLen = p.length;
|
|
667
|
+
break;
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
if (promptIdx > -1) {
|
|
671
|
+
const prefix = stringToWrite.substring(0, promptIdx);
|
|
672
|
+
const code = stringToWrite.substring(promptIdx);
|
|
673
|
+
const highlightedCode = highlight(code, { language: "sql", ignoreIllegals: true });
|
|
674
|
+
originalWriteToOutput(prefix + highlightedCode);
|
|
675
|
+
} else {
|
|
676
|
+
originalWriteToOutput(stringToWrite);
|
|
677
|
+
}
|
|
678
|
+
};
|
|
679
|
+
rl._insertString = function(c) {
|
|
680
|
+
if (this.cursor < this.line.length) {
|
|
681
|
+
const beg = this.line.slice(0, this.cursor);
|
|
682
|
+
const end = this.line.slice(this.cursor, this.line.length);
|
|
683
|
+
this.line = beg + c + end;
|
|
684
|
+
this.cursor += c.length;
|
|
685
|
+
this._refreshLine();
|
|
686
|
+
} else {
|
|
687
|
+
this.line += c;
|
|
688
|
+
this.cursor += c.length;
|
|
689
|
+
this._refreshLine();
|
|
690
|
+
}
|
|
691
|
+
};
|
|
692
|
+
const defaultPrompt = coordinator ? "dist> " : "sql> ";
|
|
693
|
+
rl.prompt();
|
|
694
|
+
let queryBuffer = "";
|
|
695
|
+
rl.on("line", async (line) => {
|
|
696
|
+
const trimmed = line.trim();
|
|
697
|
+
if (trimmed.toLowerCase() === "exit" || trimmed.toLowerCase() === "quit") {
|
|
698
|
+
await engine.shutdown();
|
|
699
|
+
rl.close();
|
|
700
|
+
return;
|
|
701
|
+
}
|
|
702
|
+
if (trimmed === "") {
|
|
703
|
+
rl.prompt();
|
|
704
|
+
return;
|
|
705
|
+
}
|
|
706
|
+
if (trimmed.startsWith(".")) {
|
|
707
|
+
await handleMetaCommand(trimmed, engine, coordinator);
|
|
708
|
+
rl.prompt();
|
|
709
|
+
return;
|
|
710
|
+
}
|
|
711
|
+
queryBuffer += (queryBuffer ? " " : "") + trimmed;
|
|
712
|
+
if (queryBuffer.endsWith(";")) {
|
|
713
|
+
try {
|
|
714
|
+
console.log();
|
|
715
|
+
const sql = queryBuffer;
|
|
716
|
+
const startTime = performance.now();
|
|
717
|
+
let result;
|
|
718
|
+
if (coordinator) {
|
|
719
|
+
result = await coordinator.execute(sql);
|
|
720
|
+
} else {
|
|
721
|
+
result = await engine.run(sql);
|
|
722
|
+
}
|
|
723
|
+
const endTime = performance.now();
|
|
724
|
+
formatResult(result);
|
|
725
|
+
const mode = coordinator ? " [distributed]" : "";
|
|
726
|
+
console.log(`Executed in ${(endTime - startTime).toFixed(2)} ms${mode}
|
|
727
|
+
`);
|
|
728
|
+
} catch (err) {
|
|
729
|
+
console.error(err.message);
|
|
730
|
+
}
|
|
731
|
+
queryBuffer = "";
|
|
732
|
+
rl.setPrompt(defaultPrompt);
|
|
733
|
+
} else {
|
|
734
|
+
rl.setPrompt("...> ");
|
|
735
|
+
}
|
|
736
|
+
rl.prompt();
|
|
737
|
+
}).on("close", () => {
|
|
738
|
+
process.exit(0);
|
|
739
|
+
});
|
|
740
|
+
}
|
|
741
|
+
async function handleMetaCommand(cmd, engine, coordinator) {
|
|
742
|
+
const parts = cmd.split(/\s+/);
|
|
743
|
+
const command = parts[0].toLowerCase();
|
|
744
|
+
switch (command) {
|
|
745
|
+
case ".status": {
|
|
746
|
+
console.log("");
|
|
747
|
+
console.log(` wasm: ${engine.wasmEnabled ? "enabled" : "disabled"}`);
|
|
748
|
+
console.log(` parallel: ${engine.parallelEnabled ? `enabled (${engine.workerPool?.maxWorkers} workers)` : "disabled"}`);
|
|
749
|
+
const distInfo = engine.distributed ? (() => {
|
|
750
|
+
const workers = engine.distributed.clusterManager.getWorkerNodes?.() || [];
|
|
751
|
+
return `enabled (node: ${engine.distributed.localNode.nodeId}, ${workers.length} worker(s))`;
|
|
752
|
+
})() : "disabled";
|
|
753
|
+
console.log(` distributed: ${distInfo}`);
|
|
754
|
+
console.log(` mode: ${coordinator ? "distributed (queries go through coordinator)" : "local"}`);
|
|
755
|
+
console.log("");
|
|
756
|
+
break;
|
|
757
|
+
}
|
|
758
|
+
case ".tables": {
|
|
759
|
+
const tables = engine.catalog.listTables();
|
|
760
|
+
if (tables.length === 0) {
|
|
761
|
+
console.log("\n No tables loaded.\n");
|
|
762
|
+
} else {
|
|
763
|
+
console.log("");
|
|
764
|
+
for (const name of tables) {
|
|
765
|
+
const storage = engine.catalog.getTableStorage(name);
|
|
766
|
+
const rows = storage ? storage.rowCount() : "?";
|
|
767
|
+
const tableDef = engine.catalog.getTable(name);
|
|
768
|
+
const cols = tableDef ? tableDef.columns.map((c) => c.name).join(", ") : "";
|
|
769
|
+
console.log(` ${name} (${rows} rows) - [${cols}]`);
|
|
770
|
+
}
|
|
771
|
+
console.log("");
|
|
772
|
+
}
|
|
773
|
+
break;
|
|
774
|
+
}
|
|
775
|
+
case ".explain": {
|
|
776
|
+
const sql = parts.slice(1).join(" ");
|
|
777
|
+
if (!sql) {
|
|
778
|
+
console.log("\n Usage: .explain <sql query>\n");
|
|
779
|
+
break;
|
|
780
|
+
}
|
|
781
|
+
try {
|
|
782
|
+
const compiled = await engine.compile(sql.endsWith(";") ? sql : sql + ";");
|
|
783
|
+
if (compiled.ddl) {
|
|
784
|
+
console.log("\n DDL statement, no plan.\n");
|
|
785
|
+
break;
|
|
786
|
+
}
|
|
787
|
+
let plan = compiled.plan;
|
|
788
|
+
if (coordinator) {
|
|
789
|
+
plan._distributed = true;
|
|
790
|
+
plan = engine.optimize(plan);
|
|
791
|
+
}
|
|
792
|
+
const { planToString: planToString2 } = await Promise.resolve().then(() => (init_logical_plan(), logical_plan_exports));
|
|
793
|
+
console.log("");
|
|
794
|
+
console.log(planToString2(plan));
|
|
795
|
+
} catch (err) {
|
|
796
|
+
console.error(err.message);
|
|
797
|
+
}
|
|
798
|
+
break;
|
|
799
|
+
}
|
|
800
|
+
case ".help": {
|
|
801
|
+
console.log("");
|
|
802
|
+
console.log(" .status Show engine status");
|
|
803
|
+
console.log(" .tables List loaded tables");
|
|
804
|
+
console.log(" .explain <sql> Show query plan");
|
|
805
|
+
console.log(" exit / quit Exit");
|
|
806
|
+
console.log("");
|
|
807
|
+
break;
|
|
808
|
+
}
|
|
809
|
+
default:
|
|
810
|
+
console.log(`
|
|
811
|
+
Unknown command: ${command}. Type .help for available commands.
|
|
812
|
+
`);
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
// src/cli/index.ts
|
|
817
|
+
import { Config } from "./index.node.js";
|
|
818
|
+
var __dirname = path5.dirname(fileURLToPath(import.meta.url));
|
|
819
|
+
async function start() {
|
|
820
|
+
const args = process.argv.slice(2);
|
|
821
|
+
const dataPaths = [];
|
|
822
|
+
let useWasm = true;
|
|
823
|
+
let useParallel = false;
|
|
824
|
+
let useDistributed = false;
|
|
825
|
+
let workerCount = Config.distributedWorkers;
|
|
826
|
+
for (let i = 0; i < args.length; i++) {
|
|
827
|
+
const arg = args[i];
|
|
828
|
+
if (arg === "--no-wasm") {
|
|
829
|
+
useWasm = false;
|
|
830
|
+
} else if (arg === "--parallel") {
|
|
831
|
+
useParallel = true;
|
|
832
|
+
} else if (arg === "--distributed") {
|
|
833
|
+
useDistributed = true;
|
|
834
|
+
} else if (arg === "--workers" && args[i + 1]) {
|
|
835
|
+
workerCount = parseInt(args[++i], 10);
|
|
836
|
+
} else if (arg === "--help" || arg === "-h") {
|
|
837
|
+
console.log("Usage: npm start -- [options] <file1> [file2...]");
|
|
838
|
+
console.log("");
|
|
839
|
+
console.log("Options:");
|
|
840
|
+
console.log(" --no-wasm Disable WebAssembly acceleration");
|
|
841
|
+
console.log(" --parallel Enable parallel execution (requires WASM)");
|
|
842
|
+
console.log(" --distributed Enable distributed query layer (auto-spawns workers)");
|
|
843
|
+
console.log(" --workers N Number of worker processes (default: CPU cores - 2)");
|
|
844
|
+
console.log("");
|
|
845
|
+
console.log("REPL commands:");
|
|
846
|
+
console.log(" .status Show engine status (wasm/parallel/distributed)");
|
|
847
|
+
console.log(" .tables List loaded tables");
|
|
848
|
+
console.log(" .explain <sql> Show query plan");
|
|
849
|
+
console.log(" exit / quit Exit the REPL");
|
|
850
|
+
process.exit(0);
|
|
851
|
+
} else if (!arg.startsWith("-")) {
|
|
852
|
+
dataPaths.push(arg);
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
if (dataPaths.length === 0) {
|
|
856
|
+
console.error("Usage: npm start -- [--no-wasm] [--parallel] [--distributed] [--workers N] <file1> [file2...]");
|
|
857
|
+
process.exit(1);
|
|
858
|
+
}
|
|
859
|
+
if (workerCount <= 0) {
|
|
860
|
+
workerCount = Math.max(1, availableParallelism() - 2);
|
|
861
|
+
}
|
|
862
|
+
try {
|
|
863
|
+
const catalog = new Catalog();
|
|
864
|
+
const engine = new QueryEngine(catalog);
|
|
865
|
+
if (useWasm) {
|
|
866
|
+
await engine.enableWasm();
|
|
867
|
+
}
|
|
868
|
+
if (engine.wasmEnabled) {
|
|
869
|
+
console.log("[wasm] WebAssembly acceleration enabled");
|
|
870
|
+
}
|
|
871
|
+
if (useParallel) {
|
|
872
|
+
const ok = await engine.enableParallel();
|
|
873
|
+
if (ok) {
|
|
874
|
+
console.log(`[parallel] Parallel execution enabled (${engine.workerPool.maxWorkers} workers)`);
|
|
875
|
+
} else {
|
|
876
|
+
console.log("[parallel] Could not enable parallel execution (WASM required)");
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
const coordLoadOptions = useDistributed ? { partitionIndex: -1, partitionCount: 1 } : {};
|
|
880
|
+
await loadDataFiles(engine, catalog, dataPaths, { loadOptions: coordLoadOptions });
|
|
881
|
+
let coordinator = null;
|
|
882
|
+
const childProcesses = [];
|
|
883
|
+
if (useDistributed) {
|
|
884
|
+
const coordPort = Config.clusterPort;
|
|
885
|
+
coordinator = await engine.enableDistributed({
|
|
886
|
+
nodeId: `coordinator-${process.pid}`,
|
|
887
|
+
host: "127.0.0.1",
|
|
888
|
+
port: coordPort
|
|
889
|
+
});
|
|
890
|
+
await engine.distributed.transport.start();
|
|
891
|
+
console.log(`[distributed] Coordinator listening on port ${coordPort}`);
|
|
892
|
+
console.log(`[distributed] Spawning ${workerCount} worker(s)...`);
|
|
893
|
+
const workers = await spawnWorkers(engine, coordPort, workerCount, dataPaths);
|
|
894
|
+
childProcesses.push(...workers);
|
|
895
|
+
console.log(`[distributed] ${workers.length} worker(s) ready`);
|
|
896
|
+
}
|
|
897
|
+
const cleanup = () => {
|
|
898
|
+
for (const w of childProcesses) {
|
|
899
|
+
try {
|
|
900
|
+
w.kill();
|
|
901
|
+
} catch (_) {
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
};
|
|
905
|
+
process.on("exit", cleanup);
|
|
906
|
+
process.on("SIGINT", () => {
|
|
907
|
+
cleanup();
|
|
908
|
+
process.exit(0);
|
|
909
|
+
});
|
|
910
|
+
process.on("SIGTERM", () => {
|
|
911
|
+
cleanup();
|
|
912
|
+
process.exit(0);
|
|
913
|
+
});
|
|
914
|
+
startREPL(engine, { coordinator });
|
|
915
|
+
} catch (err) {
|
|
916
|
+
console.error(err.message);
|
|
917
|
+
process.exit(1);
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
async function spawnWorkers(engine, coordPort, count, dataPaths) {
|
|
921
|
+
const { NodeDescriptor, NodeRole, RoundRobinPartitionStrategy } = await import("./index.node.js");
|
|
922
|
+
const workerScript = path5.join(__dirname, "worker.js");
|
|
923
|
+
const children = [];
|
|
924
|
+
const basePort = coordPort + 1;
|
|
925
|
+
const transport = engine.distributed.transport;
|
|
926
|
+
const partitionMap = engine.distributed.partitionMap;
|
|
927
|
+
return new Promise((resolve, reject) => {
|
|
928
|
+
let registered = 0;
|
|
929
|
+
const workerNodeIds = [];
|
|
930
|
+
const timeout = setTimeout(() => {
|
|
931
|
+
for (const c of children) {
|
|
932
|
+
try {
|
|
933
|
+
c.kill();
|
|
934
|
+
} catch (_) {
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
reject(new Error(`Timed out waiting for ${count} workers (${registered} registered)`));
|
|
938
|
+
}, 3e4);
|
|
939
|
+
transport.onRegister((reg) => {
|
|
940
|
+
const workerDesc = new NodeDescriptor({
|
|
941
|
+
nodeId: reg.nodeId,
|
|
942
|
+
host: reg.host,
|
|
943
|
+
port: reg.port,
|
|
944
|
+
role: NodeRole.WORKER
|
|
945
|
+
});
|
|
946
|
+
engine.distributed.clusterManager.addNode(workerDesc);
|
|
947
|
+
transport.registerNode(reg.nodeId, reg.host, reg.port);
|
|
948
|
+
workerNodeIds.push(reg.nodeId);
|
|
949
|
+
registered++;
|
|
950
|
+
console.log(`[distributed] worker-${reg.port} joined (${registered}/${count})`);
|
|
951
|
+
if (registered >= count) {
|
|
952
|
+
clearTimeout(timeout);
|
|
953
|
+
const strategy = new RoundRobinPartitionStrategy();
|
|
954
|
+
const tables = engine.catalog.listTables();
|
|
955
|
+
for (const tableName of tables) {
|
|
956
|
+
const placements = /* @__PURE__ */ new Map();
|
|
957
|
+
for (let pid = 0; pid < count; pid++) {
|
|
958
|
+
placements.set(pid, [workerNodeIds[pid]]);
|
|
959
|
+
}
|
|
960
|
+
partitionMap.registerTable(tableName, strategy, count, placements);
|
|
961
|
+
}
|
|
962
|
+
resolve(children);
|
|
963
|
+
}
|
|
964
|
+
});
|
|
965
|
+
for (let i = 0; i < count; i++) {
|
|
966
|
+
const port = basePort + i;
|
|
967
|
+
const workerArgs = [
|
|
968
|
+
"--coordinator",
|
|
969
|
+
`127.0.0.1:${coordPort}`,
|
|
970
|
+
"--port",
|
|
971
|
+
String(port),
|
|
972
|
+
"--partition-index",
|
|
973
|
+
String(i),
|
|
974
|
+
"--partition-count",
|
|
975
|
+
String(count),
|
|
976
|
+
...dataPaths.map((dp) => path5.resolve(process.cwd(), dp))
|
|
977
|
+
];
|
|
978
|
+
const child = fork(workerScript, workerArgs, {
|
|
979
|
+
stdio: ["pipe", "pipe", "pipe", "ipc"]
|
|
980
|
+
});
|
|
981
|
+
child.stdout.on("data", (data) => {
|
|
982
|
+
for (const line of data.toString().trim().split("\n")) {
|
|
983
|
+
if (line) console.log(` [worker-${port}] ${line}`);
|
|
984
|
+
}
|
|
985
|
+
});
|
|
986
|
+
child.stderr.on("data", (data) => {
|
|
987
|
+
for (const line of data.toString().trim().split("\n")) {
|
|
988
|
+
if (line) console.error(` [worker-${port}] ${line}`);
|
|
989
|
+
}
|
|
990
|
+
});
|
|
991
|
+
child.on("exit", (code) => {
|
|
992
|
+
if (code !== 0 && code !== null) {
|
|
993
|
+
console.error(` [worker-${port}] exited with code ${code}`);
|
|
994
|
+
}
|
|
995
|
+
});
|
|
996
|
+
children.push(child);
|
|
997
|
+
}
|
|
998
|
+
});
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
// dist/cli-entry.js
|
|
1002
|
+
start();
|