@query-farm/vgi 0.30.0 → 0.32.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/catalog/item-encoding.d.ts +17 -0
- package/dist/catalog/read-only.d.ts +16 -0
- package/dist/client-entry.js +19 -1
- package/dist/client-entry.js.map +3 -3
- package/dist/filter-pushdown/evaluate.d.ts +9 -0
- package/dist/filter-pushdown/history.d.ts +66 -0
- package/dist/filter-pushdown/index.d.ts +1 -0
- package/dist/functions/storage-cf-do.d.ts +2 -2
- package/dist/functions/storage.d.ts +39 -3
- package/dist/functions/table-in-out.d.ts +13 -8
- package/dist/functions/types.d.ts +14 -1
- package/dist/http/fetch.d.ts +1 -1
- package/dist/index.core.d.ts +1 -1
- package/dist/index.js +1280 -924
- package/dist/index.js.map +21 -17
- package/dist/protocol/carried-init-request.d.ts +28 -0
- package/dist/protocol/dispatch.d.ts +26 -7
- package/dist/protocol/handlers/function.d.ts +0 -1
- package/dist/protocol/handlers/shared.d.ts +0 -7
- package/dist/protocol/state-serializer.d.ts +29 -2
- package/dist/serve-entry.js +395 -188
- package/dist/serve-entry.js.map +16 -12
- package/dist/util/zstd-sync.d.ts +7 -0
- package/dist/worker-cf-entry.js +5047 -4710
- package/dist/worker-cf-entry.js.map +25 -21
- package/package.json +5 -4
- package/src/catalog/item-encoding.ts +59 -0
- package/src/catalog/read-only.ts +87 -19
- package/src/client/errors.ts +19 -0
- package/src/filter-pushdown/evaluate.ts +55 -8
- package/src/filter-pushdown/history.ts +239 -0
- package/src/filter-pushdown/index.ts +8 -0
- package/src/functions/storage-cf-do.ts +7 -12
- package/src/functions/storage.ts +54 -11
- package/src/functions/table-buffering.ts +0 -1
- package/src/functions/table-in-out.ts +99 -60
- package/src/functions/table.ts +41 -38
- package/src/functions/types.ts +14 -1
- package/src/http/fetch.ts +1 -9
- package/src/index.core.ts +1 -0
- package/src/protocol/carried-init-request.ts +139 -0
- package/src/protocol/dispatch.ts +28 -9
- package/src/protocol/handlers/catalog/admin.ts +5 -2
- package/src/protocol/handlers/function.ts +18 -15
- package/src/protocol/handlers/shared.ts +0 -22
- package/src/protocol/state-serializer.ts +109 -37
- package/src/util/zstd-sync.ts +50 -0
package/dist/index.js
CHANGED
|
@@ -2008,8 +2008,8 @@ class FunctionStorageCfDo {
|
|
|
2008
2008
|
fetch: this._fetch
|
|
2009
2009
|
});
|
|
2010
2010
|
}
|
|
2011
|
-
async workerPut(executionId,
|
|
2012
|
-
await this._statePutMany(executionId, NS_WORKER, [[
|
|
2011
|
+
async workerPut(executionId, worker, state) {
|
|
2012
|
+
await this._statePutMany(executionId, NS_WORKER, [[workerStateKey(worker), state]]);
|
|
2013
2013
|
}
|
|
2014
2014
|
async workerCollect(executionId) {
|
|
2015
2015
|
const rows = await this._statePaged("state_drain", executionId, NS_WORKER, newAttemptId());
|
|
@@ -2154,11 +2154,6 @@ function newAttemptId() {
|
|
|
2154
2154
|
s += b[i].toString(16).padStart(2, "0");
|
|
2155
2155
|
return s;
|
|
2156
2156
|
}
|
|
2157
|
-
function int64Key(v) {
|
|
2158
|
-
const b = new Uint8Array(8);
|
|
2159
|
-
new DataView(b.buffer).setBigInt64(0, BigInt(v), false);
|
|
2160
|
-
return b;
|
|
2161
|
-
}
|
|
2162
2157
|
function int64FromKey(b) {
|
|
2163
2158
|
if (b.length !== 8)
|
|
2164
2159
|
return 0;
|
|
@@ -2231,11 +2226,14 @@ function getDefaultDbPath() {
|
|
|
2231
2226
|
mkdirSync(stateDir, { recursive: true });
|
|
2232
2227
|
return join(stateDir, "vgi_storage.db");
|
|
2233
2228
|
}
|
|
2234
|
-
function
|
|
2229
|
+
function int64Key(v) {
|
|
2235
2230
|
const b = new Uint8Array(8);
|
|
2236
2231
|
new DataView(b.buffer).setBigInt64(0, BigInt(v), false);
|
|
2237
2232
|
return b;
|
|
2238
2233
|
}
|
|
2234
|
+
function workerStateKey(worker) {
|
|
2235
|
+
return typeof worker === "number" ? int64Key(worker) : worker;
|
|
2236
|
+
}
|
|
2239
2237
|
function int64FromKey2(b) {
|
|
2240
2238
|
if (b.length !== 8)
|
|
2241
2239
|
return 0;
|
|
@@ -2336,8 +2334,8 @@ class FunctionStorageSqlite {
|
|
|
2336
2334
|
total += this._db.prepare("DELETE FROM function_state_log WHERE scope_id = ?").run(eid).changes;
|
|
2337
2335
|
return total;
|
|
2338
2336
|
}
|
|
2339
|
-
async workerPut(executionId,
|
|
2340
|
-
this._db.prepare("INSERT OR REPLACE INTO function_state (scope_id, ns, key, value) VALUES (?, ?, ?, ?)").run(bufferArg(executionId), bufferArg(NS_WORKER2), bufferArg(
|
|
2337
|
+
async workerPut(executionId, worker, state) {
|
|
2338
|
+
this._db.prepare("INSERT OR REPLACE INTO function_state (scope_id, ns, key, value) VALUES (?, ?, ?, ?)").run(bufferArg(executionId), bufferArg(NS_WORKER2), bufferArg(workerStateKey(worker)), bufferArg(state));
|
|
2341
2339
|
}
|
|
2342
2340
|
async workerCollect(executionId) {
|
|
2343
2341
|
const rows = this._db.prepare("DELETE FROM function_state WHERE scope_id = ? AND ns = ? RETURNING value").all(bufferArg(executionId), bufferArg(NS_WORKER2));
|
|
@@ -2374,12 +2372,14 @@ class FunctionStorageSqlite {
|
|
|
2374
2372
|
class BoundStorage {
|
|
2375
2373
|
_base;
|
|
2376
2374
|
_executionId;
|
|
2377
|
-
|
|
2375
|
+
_substreamId;
|
|
2376
|
+
constructor(storage, executionId, substreamId = null) {
|
|
2378
2377
|
this._base = storage;
|
|
2379
2378
|
this._executionId = executionId;
|
|
2379
|
+
this._substreamId = substreamId;
|
|
2380
2380
|
}
|
|
2381
2381
|
put(state) {
|
|
2382
|
-
return this._base.workerPut(this._executionId, process.pid, state);
|
|
2382
|
+
return this._base.workerPut(this._executionId, this._substreamId ?? process.pid, state);
|
|
2383
2383
|
}
|
|
2384
2384
|
collect() {
|
|
2385
2385
|
return this._base.workerCollect(this._executionId);
|
|
@@ -3808,9 +3808,24 @@ function buildJoinKeysLookup(joinKeyBatches) {
|
|
|
3808
3808
|
}
|
|
3809
3809
|
|
|
3810
3810
|
// src/filter-pushdown/evaluate.ts
|
|
3811
|
-
|
|
3812
|
-
|
|
3813
|
-
|
|
3811
|
+
var RESOLVED_COLUMNS = new WeakMap;
|
|
3812
|
+
function resolveColumn(batch, columnName) {
|
|
3813
|
+
let byName = RESOLVED_COLUMNS.get(batch);
|
|
3814
|
+
if (!byName) {
|
|
3815
|
+
byName = new Map;
|
|
3816
|
+
RESOLVED_COLUMNS.set(batch, byName);
|
|
3817
|
+
}
|
|
3818
|
+
let resolved = byName.get(columnName);
|
|
3819
|
+
if (resolved === undefined) {
|
|
3820
|
+
const index = batch.schema.fields.findIndex((field) => field.name === columnName);
|
|
3821
|
+
if (index < 0) {
|
|
3822
|
+
throw new FilterV2Error(`filter column ${columnName} is unavailable in emitted batch`);
|
|
3823
|
+
}
|
|
3824
|
+
const column = batch.getChildAt(index);
|
|
3825
|
+
resolved = column ? { type: batch.schema.fields[index].type, column } : null;
|
|
3826
|
+
byName.set(columnName, resolved);
|
|
3827
|
+
}
|
|
3828
|
+
return resolved;
|
|
3814
3829
|
}
|
|
3815
3830
|
function deepEqual(left, right) {
|
|
3816
3831
|
if (typeof left === "number" && typeof right === "number") {
|
|
@@ -4104,11 +4119,8 @@ function evaluateCall(expression, args) {
|
|
|
4104
4119
|
function evaluateExpression(expression, batch, row, context) {
|
|
4105
4120
|
switch (expression.node) {
|
|
4106
4121
|
case "column_ref": {
|
|
4107
|
-
const
|
|
4108
|
-
|
|
4109
|
-
throw new FilterV2Error(`filter column ${expression.columnName} is unavailable in emitted batch`);
|
|
4110
|
-
}
|
|
4111
|
-
return readCell(batch, projectedIndex, row);
|
|
4122
|
+
const resolved = resolveColumn(batch, expression.columnName);
|
|
4123
|
+
return resolved ? readCanonicalValue(resolved.type, resolved.column, row) : null;
|
|
4112
4124
|
}
|
|
4113
4125
|
case "field_ref": {
|
|
4114
4126
|
const parent = evaluateExpression(expression.expression, batch, row, context);
|
|
@@ -4242,6 +4254,17 @@ class PushdownFilters {
|
|
|
4242
4254
|
applyDelta(batch) {
|
|
4243
4255
|
return applyFilterDelta(this, batch);
|
|
4244
4256
|
}
|
|
4257
|
+
withPredicateOrder(order) {
|
|
4258
|
+
const predicates = this.predicates;
|
|
4259
|
+
if (predicates.length === order.length && predicates.every((predicate, i) => predicate.id === order[i])) {
|
|
4260
|
+
return this;
|
|
4261
|
+
}
|
|
4262
|
+
const byId = new Map(predicates.map((predicate) => [predicate.id, predicate]));
|
|
4263
|
+
if (order.length !== byId.size || new Set(order).size !== order.length || !order.every((id) => byId.has(id))) {
|
|
4264
|
+
throw new FilterV2Error("recorded predicate order does not match the replayed filter state");
|
|
4265
|
+
}
|
|
4266
|
+
return new PushdownFilters(order.map((id) => byId.get(id)), this.evaluationContext, this.options, new Map(this.revisions), new Set(this.requiredIds));
|
|
4267
|
+
}
|
|
4245
4268
|
evaluate(batch) {
|
|
4246
4269
|
const mask = new Uint8Array(batch.numRows);
|
|
4247
4270
|
mask.fill(1);
|
|
@@ -4346,6 +4369,148 @@ function expressionToSql(expression) {
|
|
|
4346
4369
|
return `${filterFunctionIdentityKey(expression.algorithm)}(${expressionToSql(expression.input)})`;
|
|
4347
4370
|
}
|
|
4348
4371
|
}
|
|
4372
|
+
// src/filter-pushdown/history.ts
|
|
4373
|
+
init_arrow();
|
|
4374
|
+
var MAX_ENCODED_DELTA_BYTES = 24 << 20;
|
|
4375
|
+
var MAX_DELTA_IPC_BYTES = 17 << 20;
|
|
4376
|
+
var BASE64 = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/;
|
|
4377
|
+
var EMPTY_FILTER_HISTORY = Object.freeze({
|
|
4378
|
+
deltas: Object.freeze([]),
|
|
4379
|
+
order: Object.freeze([])
|
|
4380
|
+
});
|
|
4381
|
+
function decodeDynamicFilterMetadata(encoded) {
|
|
4382
|
+
if (new TextEncoder().encode(encoded).byteLength > MAX_ENCODED_DELTA_BYTES) {
|
|
4383
|
+
throw new Error("base64 dynamic filter metadata exceeds the encoded-size limit");
|
|
4384
|
+
}
|
|
4385
|
+
if (encoded.length % 4 !== 0 || !BASE64.test(encoded)) {
|
|
4386
|
+
throw new Error("dynamic filter metadata is not valid base64");
|
|
4387
|
+
}
|
|
4388
|
+
const binary = globalThis.atob ? globalThis.atob(encoded) : Buffer.from(encoded, "base64").toString("binary");
|
|
4389
|
+
const bytes = new Uint8Array(binary.length);
|
|
4390
|
+
for (let i = 0;i < binary.length; i++)
|
|
4391
|
+
bytes[i] = binary.charCodeAt(i);
|
|
4392
|
+
if (bytes.byteLength > MAX_DELTA_IPC_BYTES) {
|
|
4393
|
+
throw new Error("dynamic filter IPC payload exceeds the encoded-size limit");
|
|
4394
|
+
}
|
|
4395
|
+
return bytes;
|
|
4396
|
+
}
|
|
4397
|
+
function decodeFilterDelta(bytes) {
|
|
4398
|
+
if (bytes.byteLength > MAX_DELTA_IPC_BYTES) {
|
|
4399
|
+
throw new Error("dynamic filter IPC payload exceeds the encoded-size limit");
|
|
4400
|
+
}
|
|
4401
|
+
const batch = bytes.byteLength > 0 ? deserializeBatch(bytes) : null;
|
|
4402
|
+
if (!batch || batch.numRows === 0 && batch.schema.fields.length === 0) {
|
|
4403
|
+
throw new Error("dynamic filter metadata must contain one RecordBatch");
|
|
4404
|
+
}
|
|
4405
|
+
return batch;
|
|
4406
|
+
}
|
|
4407
|
+
function deltaRevisionKeys(batch) {
|
|
4408
|
+
const column = batch.getChildAt(0);
|
|
4409
|
+
if (!column)
|
|
4410
|
+
throw new FilterV2Error("delta document has no filter_spec column");
|
|
4411
|
+
const raw = readCanonicalValue(batch.schema.fields[0].type, column, 0);
|
|
4412
|
+
const document = JSON.parse(String(raw));
|
|
4413
|
+
return (document.updates ?? []).map((update) => revisionKey(update.id, update.revision));
|
|
4414
|
+
}
|
|
4415
|
+
function revisionKey(id, revision) {
|
|
4416
|
+
return `${id}\x00${revision}`;
|
|
4417
|
+
}
|
|
4418
|
+
function recordFilterDelta(current, history, deltaBytes) {
|
|
4419
|
+
const incoming = decodeFilterDelta(deltaBytes);
|
|
4420
|
+
const filters = current.applyDelta(incoming);
|
|
4421
|
+
const wanted = new Set;
|
|
4422
|
+
for (const [id, revision] of filters.revisions)
|
|
4423
|
+
wanted.add(revisionKey(id, revision));
|
|
4424
|
+
const deltas = [];
|
|
4425
|
+
const consider = (bytes, batch) => {
|
|
4426
|
+
let carries = false;
|
|
4427
|
+
for (const key of deltaRevisionKeys(batch)) {
|
|
4428
|
+
if (wanted.delete(key))
|
|
4429
|
+
carries = true;
|
|
4430
|
+
}
|
|
4431
|
+
if (carries)
|
|
4432
|
+
deltas.push(bytes);
|
|
4433
|
+
};
|
|
4434
|
+
for (const bytes of history.deltas)
|
|
4435
|
+
consider(bytes, decodeFilterDelta(bytes));
|
|
4436
|
+
consider(deltaBytes, incoming);
|
|
4437
|
+
return { filters, history: { deltas, order: filters.predicates.map((predicate) => predicate.id) } };
|
|
4438
|
+
}
|
|
4439
|
+
var HISTORY_FORMAT_VERSION = 1;
|
|
4440
|
+
var UTF8_ENCODER = new TextEncoder;
|
|
4441
|
+
var UTF8_DECODER = new TextDecoder("utf-8", { fatal: true });
|
|
4442
|
+
function encodeFilterHistory(history) {
|
|
4443
|
+
if (!history || history.deltas.length === 0)
|
|
4444
|
+
return null;
|
|
4445
|
+
const ids = history.order.map((id) => UTF8_ENCODER.encode(id));
|
|
4446
|
+
let size = 1 + 4 + 4;
|
|
4447
|
+
for (const delta of history.deltas)
|
|
4448
|
+
size += 4 + delta.byteLength;
|
|
4449
|
+
for (const id of ids)
|
|
4450
|
+
size += 4 + id.byteLength;
|
|
4451
|
+
const out = new Uint8Array(size);
|
|
4452
|
+
const view = new DataView(out.buffer);
|
|
4453
|
+
let offset = 0;
|
|
4454
|
+
out[offset++] = HISTORY_FORMAT_VERSION;
|
|
4455
|
+
const put = (chunks) => {
|
|
4456
|
+
view.setUint32(offset, chunks.length, true);
|
|
4457
|
+
offset += 4;
|
|
4458
|
+
for (const chunk of chunks) {
|
|
4459
|
+
view.setUint32(offset, chunk.byteLength, true);
|
|
4460
|
+
offset += 4;
|
|
4461
|
+
out.set(chunk, offset);
|
|
4462
|
+
offset += chunk.byteLength;
|
|
4463
|
+
}
|
|
4464
|
+
};
|
|
4465
|
+
put(history.deltas);
|
|
4466
|
+
put(ids);
|
|
4467
|
+
return out;
|
|
4468
|
+
}
|
|
4469
|
+
function decodeFilterHistory(bytes) {
|
|
4470
|
+
if (!bytes || bytes.byteLength === 0)
|
|
4471
|
+
return EMPTY_FILTER_HISTORY;
|
|
4472
|
+
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
4473
|
+
let offset = 0;
|
|
4474
|
+
const need = (n) => {
|
|
4475
|
+
if (offset + n > bytes.byteLength)
|
|
4476
|
+
throw new Error("dynamic filter history in the state token is truncated");
|
|
4477
|
+
};
|
|
4478
|
+
need(1);
|
|
4479
|
+
if (bytes[offset++] !== HISTORY_FORMAT_VERSION) {
|
|
4480
|
+
throw new Error("dynamic filter history in the state token has an unknown format");
|
|
4481
|
+
}
|
|
4482
|
+
const take = () => {
|
|
4483
|
+
need(4);
|
|
4484
|
+
const count = view.getUint32(offset, true);
|
|
4485
|
+
offset += 4;
|
|
4486
|
+
const chunks = [];
|
|
4487
|
+
for (let i = 0;i < count; i++) {
|
|
4488
|
+
need(4);
|
|
4489
|
+
const length = view.getUint32(offset, true);
|
|
4490
|
+
offset += 4;
|
|
4491
|
+
need(length);
|
|
4492
|
+
chunks.push(bytes.slice(offset, offset + length));
|
|
4493
|
+
offset += length;
|
|
4494
|
+
}
|
|
4495
|
+
return chunks;
|
|
4496
|
+
};
|
|
4497
|
+
const deltas = take();
|
|
4498
|
+
const order = take().map((id) => UTF8_DECODER.decode(id));
|
|
4499
|
+
if (offset !== bytes.byteLength)
|
|
4500
|
+
throw new Error("dynamic filter history in the state token has trailing bytes");
|
|
4501
|
+
return { deltas, order };
|
|
4502
|
+
}
|
|
4503
|
+
function replayFilterHistory(filters, history) {
|
|
4504
|
+
if (!history || history.deltas.length === 0)
|
|
4505
|
+
return filters;
|
|
4506
|
+
if (!filters)
|
|
4507
|
+
throw new Error("dynamic filter history carried without an initial snapshot");
|
|
4508
|
+
let replayed = filters;
|
|
4509
|
+
for (const bytes of history.deltas)
|
|
4510
|
+
replayed = replayed.applyDelta(decodeFilterDelta(bytes));
|
|
4511
|
+
return replayed.withPredicateOrder(history.order);
|
|
4512
|
+
}
|
|
4513
|
+
|
|
4349
4514
|
// src/filter-pushdown/collector.ts
|
|
4350
4515
|
init_arrow();
|
|
4351
4516
|
function formatPushedFilters(filters) {
|
|
@@ -4453,27 +4618,6 @@ class FilteringOutputCollector {
|
|
|
4453
4618
|
}
|
|
4454
4619
|
// src/functions/table.ts
|
|
4455
4620
|
init_storage();
|
|
4456
|
-
function base64Decode(s) {
|
|
4457
|
-
if (new TextEncoder().encode(s).byteLength > 24 << 20) {
|
|
4458
|
-
throw new Error("base64 dynamic filter metadata exceeds the encoded-size limit");
|
|
4459
|
-
}
|
|
4460
|
-
if (s.length % 4 !== 0 || !/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(s)) {
|
|
4461
|
-
throw new Error("dynamic filter metadata is not valid base64");
|
|
4462
|
-
}
|
|
4463
|
-
const bin = globalThis.atob ? globalThis.atob(s) : Buffer.from(s, "base64").toString("binary");
|
|
4464
|
-
const out = new Uint8Array(bin.length);
|
|
4465
|
-
for (let i = 0;i < bin.length; i++)
|
|
4466
|
-
out[i] = bin.charCodeAt(i);
|
|
4467
|
-
if (out.byteLength > 17 << 20)
|
|
4468
|
-
throw new Error("dynamic filter IPC payload exceeds the encoded-size limit");
|
|
4469
|
-
return out;
|
|
4470
|
-
}
|
|
4471
|
-
function deserializeFilterBatch(bytes) {
|
|
4472
|
-
if (!bytes || bytes.length === 0)
|
|
4473
|
-
return null;
|
|
4474
|
-
const batch = deserializeBatch(bytes);
|
|
4475
|
-
return batch.numRows === 0 && batch.schema.fields.length === 0 ? null : batch;
|
|
4476
|
-
}
|
|
4477
4621
|
function makeProjectingCollector(inner, targetSchema) {
|
|
4478
4622
|
function alreadyMatches(batch) {
|
|
4479
4623
|
if (batch.schema.fields.length !== targetSchema.fields.length)
|
|
@@ -4654,7 +4798,7 @@ function defineTableFunction(config) {
|
|
|
4654
4798
|
opaque_data: null
|
|
4655
4799
|
};
|
|
4656
4800
|
},
|
|
4657
|
-
createStreamHandlers(request, response) {
|
|
4801
|
+
createStreamHandlers(request, response, filterHistory) {
|
|
4658
4802
|
const args = extractArgs(request.bind_call);
|
|
4659
4803
|
const settings = batchToScalarDict(request.bind_call.settings);
|
|
4660
4804
|
const secrets = batchToSecretDict(request.bind_call.secrets);
|
|
@@ -4667,7 +4811,8 @@ function defineTableFunction(config) {
|
|
|
4667
4811
|
runtimeAlgorithms: meta.runtimeFilterAlgorithms,
|
|
4668
4812
|
evaluationContexts: meta.filterEvaluationContexts
|
|
4669
4813
|
};
|
|
4670
|
-
const
|
|
4814
|
+
const carriedFilterHistory = filterHistory ?? EMPTY_FILTER_HISTORY;
|
|
4815
|
+
const pushdownFilters = replayFilterHistory(request.pushdown_filters ? deserializeFilters(request.pushdown_filters, filterOptions) : undefined, carriedFilterHistory);
|
|
4671
4816
|
const boundStorage = new BoundStorage(storage, response.execution_id);
|
|
4672
4817
|
const processParams = {
|
|
4673
4818
|
args,
|
|
@@ -4688,7 +4833,11 @@ function defineTableFunction(config) {
|
|
|
4688
4833
|
const state = config.initialState ? config.initialState(processParams) : null;
|
|
4689
4834
|
return {
|
|
4690
4835
|
outputSchema,
|
|
4691
|
-
producerInit: () => ({
|
|
4836
|
+
producerInit: () => ({
|
|
4837
|
+
state,
|
|
4838
|
+
processParams,
|
|
4839
|
+
filterHistory: carriedFilterHistory
|
|
4840
|
+
}),
|
|
4692
4841
|
onTick: (pState, tickMetadata) => {
|
|
4693
4842
|
if (!tickMetadata)
|
|
4694
4843
|
return;
|
|
@@ -4704,11 +4853,9 @@ function defineTableFunction(config) {
|
|
|
4704
4853
|
const current = pState.processParams.pushdownFilters;
|
|
4705
4854
|
if (!current)
|
|
4706
4855
|
throw new Error("dynamic filter delta received without an initial snapshot");
|
|
4707
|
-
const
|
|
4708
|
-
|
|
4709
|
-
|
|
4710
|
-
throw new Error("dynamic filter metadata must contain one RecordBatch");
|
|
4711
|
-
pState.processParams.pushdownFilters = current.applyDelta(filterBatch);
|
|
4856
|
+
const recorded = recordFilterDelta(current, pState.filterHistory, decodeDynamicFilterMetadata(encoded));
|
|
4857
|
+
pState.processParams.pushdownFilters = recorded.filters;
|
|
4858
|
+
pState.filterHistory = recorded.history;
|
|
4712
4859
|
},
|
|
4713
4860
|
producerFn: async (pState, out) => {
|
|
4714
4861
|
const current = pState.processParams.pushdownFilters;
|
|
@@ -4960,725 +5107,133 @@ function toUint8Array(val) {
|
|
|
4960
5107
|
return new Uint8Array(0);
|
|
4961
5108
|
}
|
|
4962
5109
|
|
|
4963
|
-
// src/protocol/
|
|
4964
|
-
|
|
4965
|
-
|
|
4966
|
-
|
|
4967
|
-
|
|
4968
|
-
|
|
4969
|
-
|
|
4970
|
-
|
|
4971
|
-
|
|
4972
|
-
|
|
4973
|
-
|
|
4974
|
-
|
|
4975
|
-
var LIST_CHILD_NAME = "item";
|
|
4976
|
-
var emptyListElementType = () => utf82();
|
|
4977
|
-
function inferElementType(values) {
|
|
4978
|
-
let elementType = null;
|
|
4979
|
-
let elementSig = "";
|
|
4980
|
-
for (const v of values) {
|
|
4981
|
-
if (v === null || v === undefined)
|
|
4982
|
-
continue;
|
|
4983
|
-
const t = inferFieldType(v);
|
|
4984
|
-
const sig = typeSignature(t);
|
|
4985
|
-
if (elementType === null) {
|
|
4986
|
-
elementType = t;
|
|
4987
|
-
elementSig = sig;
|
|
4988
|
-
continue;
|
|
4989
|
-
}
|
|
4990
|
-
if (sig !== elementSig) {
|
|
4991
|
-
throw new Error(`inferFieldType: arrays in userState must be homogeneous; ` + `found both '${elementSig}' and '${sig}' in the same array ` + `(split the values into separate fields, or normalize them to one type)`);
|
|
4992
|
-
}
|
|
5110
|
+
// src/protocol/carried-init-request.ts
|
|
5111
|
+
init_arrow();
|
|
5112
|
+
|
|
5113
|
+
// src/util/zstd-sync.ts
|
|
5114
|
+
var LEVEL = 3;
|
|
5115
|
+
function resolveZstdSync() {
|
|
5116
|
+
const bun = globalThis.Bun;
|
|
5117
|
+
if (typeof bun?.zstdCompressSync === "function" && typeof bun?.zstdDecompressSync === "function") {
|
|
5118
|
+
return {
|
|
5119
|
+
compress: (data) => new Uint8Array(bun.zstdCompressSync(data, { level: LEVEL })),
|
|
5120
|
+
decompress: (data) => new Uint8Array(bun.zstdDecompressSync(data))
|
|
5121
|
+
};
|
|
4993
5122
|
}
|
|
4994
|
-
|
|
5123
|
+
let zlib = null;
|
|
5124
|
+
try {
|
|
5125
|
+
zlib = globalThis.process?.getBuiltinModule?.("node:zlib") ?? null;
|
|
5126
|
+
} catch {
|
|
5127
|
+
zlib = null;
|
|
5128
|
+
}
|
|
5129
|
+
if (typeof zlib?.zstdCompressSync === "function" && typeof zlib?.zstdDecompressSync === "function") {
|
|
5130
|
+
const params = { [zlib.constants.ZSTD_c_compressionLevel]: LEVEL };
|
|
5131
|
+
return {
|
|
5132
|
+
compress: (data) => new Uint8Array(zlib.zstdCompressSync(data, { params })),
|
|
5133
|
+
decompress: (data) => new Uint8Array(zlib.zstdDecompressSync(data))
|
|
5134
|
+
};
|
|
5135
|
+
}
|
|
5136
|
+
return null;
|
|
4995
5137
|
}
|
|
4996
|
-
|
|
4997
|
-
|
|
4998
|
-
|
|
4999
|
-
|
|
5000
|
-
|
|
5001
|
-
|
|
5002
|
-
|
|
5003
|
-
|
|
5004
|
-
|
|
5005
|
-
|
|
5006
|
-
|
|
5007
|
-
|
|
5008
|
-
|
|
5009
|
-
|
|
5010
|
-
|
|
5011
|
-
|
|
5012
|
-
|
|
5013
|
-
|
|
5014
|
-
|
|
5015
|
-
|
|
5016
|
-
|
|
5017
|
-
|
|
5018
|
-
|
|
5019
|
-
if (
|
|
5020
|
-
|
|
5021
|
-
|
|
5022
|
-
|
|
5023
|
-
|
|
5138
|
+
var resolved;
|
|
5139
|
+
function zstdSync() {
|
|
5140
|
+
if (resolved === undefined)
|
|
5141
|
+
resolved = resolveZstdSync();
|
|
5142
|
+
return resolved;
|
|
5143
|
+
}
|
|
5144
|
+
|
|
5145
|
+
// src/protocol/serializers/arguments.ts
|
|
5146
|
+
init_arrow();
|
|
5147
|
+
init_registry();
|
|
5148
|
+
|
|
5149
|
+
// src/arguments/arguments.ts
|
|
5150
|
+
class Arguments {
|
|
5151
|
+
positional;
|
|
5152
|
+
named;
|
|
5153
|
+
argumentsSchema;
|
|
5154
|
+
constructor(positional = [], named = new Map, argumentsSchema = null) {
|
|
5155
|
+
this.positional = positional;
|
|
5156
|
+
this.named = named;
|
|
5157
|
+
this.argumentsSchema = argumentsSchema;
|
|
5158
|
+
}
|
|
5159
|
+
get(position, defaultValue) {
|
|
5160
|
+
if (typeof position === "number") {
|
|
5161
|
+
if (position < this.positional.length) {
|
|
5162
|
+
const val = this.positional[position];
|
|
5163
|
+
if (val === null || val === undefined) {
|
|
5164
|
+
return defaultValue !== undefined ? defaultValue : null;
|
|
5165
|
+
}
|
|
5166
|
+
return unwrapScalar(val);
|
|
5024
5167
|
}
|
|
5025
|
-
if (
|
|
5026
|
-
|
|
5168
|
+
if (defaultValue !== undefined)
|
|
5169
|
+
return defaultValue;
|
|
5170
|
+
throw new Error(`Positional argument ${position} not found`);
|
|
5171
|
+
}
|
|
5172
|
+
if (this.named.has(position)) {
|
|
5173
|
+
const val = this.named.get(position);
|
|
5174
|
+
if (val === null || val === undefined) {
|
|
5175
|
+
return defaultValue !== undefined ? defaultValue : null;
|
|
5027
5176
|
}
|
|
5028
|
-
|
|
5029
|
-
|
|
5030
|
-
|
|
5031
|
-
|
|
5177
|
+
return unwrapScalar(val);
|
|
5178
|
+
}
|
|
5179
|
+
if (defaultValue !== undefined)
|
|
5180
|
+
return defaultValue;
|
|
5181
|
+
throw new Error(`Named argument '${position}' not found`);
|
|
5182
|
+
}
|
|
5183
|
+
get length() {
|
|
5184
|
+
return this.positional.length;
|
|
5032
5185
|
}
|
|
5033
5186
|
}
|
|
5034
|
-
function
|
|
5035
|
-
if (
|
|
5187
|
+
function unwrapScalar(val) {
|
|
5188
|
+
if (val === null || val === undefined)
|
|
5036
5189
|
return null;
|
|
5037
|
-
|
|
5038
|
-
|
|
5039
|
-
|
|
5040
|
-
|
|
5041
|
-
|
|
5042
|
-
|
|
5043
|
-
|
|
5044
|
-
|
|
5045
|
-
|
|
5190
|
+
if (typeof val !== "object")
|
|
5191
|
+
return val;
|
|
5192
|
+
if (typeof val.valueOf === "function") {
|
|
5193
|
+
let v;
|
|
5194
|
+
try {
|
|
5195
|
+
v = val.valueOf();
|
|
5196
|
+
} catch {
|
|
5197
|
+
return val;
|
|
5198
|
+
}
|
|
5199
|
+
if (typeof v === "bigint") {
|
|
5200
|
+
if (v >= Number.MIN_SAFE_INTEGER && v <= Number.MAX_SAFE_INTEGER) {
|
|
5201
|
+
return Number(v);
|
|
5202
|
+
}
|
|
5203
|
+
return v;
|
|
5204
|
+
}
|
|
5205
|
+
return v;
|
|
5046
5206
|
}
|
|
5047
|
-
return
|
|
5048
|
-
}
|
|
5049
|
-
function extractTypedValue(col, index, type) {
|
|
5050
|
-
return codecFor(type).canonicalToRich(readCanonicalValue(type, col, index));
|
|
5207
|
+
return val;
|
|
5051
5208
|
}
|
|
5052
|
-
|
|
5053
|
-
|
|
5054
|
-
|
|
5055
|
-
const
|
|
5056
|
-
|
|
5057
|
-
|
|
5209
|
+
|
|
5210
|
+
// src/protocol/serializers/arguments.ts
|
|
5211
|
+
function serializeArguments(args) {
|
|
5212
|
+
const structFields = [];
|
|
5213
|
+
const structValues = {};
|
|
5214
|
+
for (let i = 0;i < args.positional.length; i++) {
|
|
5215
|
+
const val = args.positional[i];
|
|
5216
|
+
const fieldName = `positional_${i}`;
|
|
5217
|
+
structFields.push(field2(fieldName, inferScalarType(val), true));
|
|
5218
|
+
structValues[fieldName] = val;
|
|
5058
5219
|
}
|
|
5059
|
-
|
|
5060
|
-
|
|
5061
|
-
|
|
5062
|
-
|
|
5063
|
-
|
|
5064
|
-
|
|
5065
|
-
|
|
5066
|
-
|
|
5220
|
+
for (const [name, val] of args.named) {
|
|
5221
|
+
const fieldName = `named_${name}`;
|
|
5222
|
+
structFields.push(field2(fieldName, inferScalarType(val), true));
|
|
5223
|
+
structValues[fieldName] = val;
|
|
5224
|
+
}
|
|
5225
|
+
const structType = struct2(structFields);
|
|
5226
|
+
const sch = schema2([field2("args", structType, true)]);
|
|
5227
|
+
const structRow = {};
|
|
5228
|
+
for (const f of structFields) {
|
|
5229
|
+
let val = structValues[f.name];
|
|
5230
|
+
if (isInt(f.type) && f.type.bitWidth === 64 && typeof val === "number") {
|
|
5231
|
+
val = BigInt(val);
|
|
5067
5232
|
}
|
|
5068
|
-
|
|
5233
|
+
structRow[f.name] = val;
|
|
5069
5234
|
}
|
|
5070
|
-
|
|
5071
|
-
|
|
5072
|
-
var arrowStateSerializer = {
|
|
5073
|
-
serialize(state) {
|
|
5074
|
-
const columns = {
|
|
5075
|
-
function_name: [TEXT_ENCODER.encode(state.functionName)],
|
|
5076
|
-
init_request: [state.initRequestIpc],
|
|
5077
|
-
execution_id: [state.executionId],
|
|
5078
|
-
max_workers: [state.maxWorkers],
|
|
5079
|
-
opaque_data: [state.opaqueData ?? null],
|
|
5080
|
-
is_producer: [state.isProducer],
|
|
5081
|
-
user_state: [serializeUserState(state.userState)]
|
|
5082
|
-
};
|
|
5083
|
-
const batch = batchFromColumns(columns, EXCHANGE_STATE_SCHEMA);
|
|
5084
|
-
return serializeBatch(batch);
|
|
5085
|
-
},
|
|
5086
|
-
deserialize(bytes) {
|
|
5087
|
-
const batch = deserializeBatch(bytes);
|
|
5088
|
-
const fieldByName = new Map(batch.schema.fields.map((f) => [f.name, f]));
|
|
5089
|
-
const get = (name) => {
|
|
5090
|
-
const col = batch.getChild(name);
|
|
5091
|
-
const f = fieldByName.get(name);
|
|
5092
|
-
if (!col || !f)
|
|
5093
|
-
return null;
|
|
5094
|
-
const type = f.type;
|
|
5095
|
-
return codecFor(type).canonicalToRich(readCanonicalValue(type, col, 0));
|
|
5096
|
-
};
|
|
5097
|
-
const isProducer = get("is_producer");
|
|
5098
|
-
const opaqueDataRaw = get("opaque_data");
|
|
5099
|
-
const fnNameRaw = get("function_name");
|
|
5100
|
-
return {
|
|
5101
|
-
functionName: fnNameRaw != null ? TEXT_DECODER.decode(toUint8Array(fnNameRaw)) : "",
|
|
5102
|
-
initRequestIpc: toUint8Array(get("init_request")),
|
|
5103
|
-
executionId: toUint8Array(get("execution_id")),
|
|
5104
|
-
maxWorkers: Number(get("max_workers")),
|
|
5105
|
-
opaqueData: opaqueDataRaw != null ? toUint8Array(opaqueDataRaw) : null,
|
|
5106
|
-
isProducer,
|
|
5107
|
-
__isProducer: isProducer,
|
|
5108
|
-
userState: deserializeUserState(get("user_state") != null ? toUint8Array(get("user_state")) : null)
|
|
5109
|
-
};
|
|
5110
|
-
}
|
|
5111
|
-
};
|
|
5112
|
-
|
|
5113
|
-
// src/functions/table-in-out.ts
|
|
5114
|
-
var STREAMING_FINALIZE_KEY = new Uint8Array(0);
|
|
5115
|
-
function defineTableInOutFunction(config) {
|
|
5116
|
-
assertArrowTypes(config.args, `defineTableInOutFunction("${config.name}"): args`);
|
|
5117
|
-
const specs = [];
|
|
5118
|
-
let posIdx = 0;
|
|
5119
|
-
if (config.args) {
|
|
5120
|
-
for (const [name, type] of Object.entries(config.args)) {
|
|
5121
|
-
specs.push({
|
|
5122
|
-
name,
|
|
5123
|
-
position: posIdx++,
|
|
5124
|
-
arrowType: type,
|
|
5125
|
-
doc: config.argDocs?.[name],
|
|
5126
|
-
...constraintSpecFields(config.argConstraints?.[name], config.argDefaults?.[name])
|
|
5127
|
-
});
|
|
5128
|
-
}
|
|
5129
|
-
}
|
|
5130
|
-
specs.push({
|
|
5131
|
-
name: "data",
|
|
5132
|
-
position: posIdx++,
|
|
5133
|
-
arrowType: nullType2(),
|
|
5134
|
-
isTableInput: true
|
|
5135
|
-
});
|
|
5136
|
-
if (config.namedArgs) {
|
|
5137
|
-
for (const [name, type] of Object.entries(config.namedArgs)) {
|
|
5138
|
-
specs.push({
|
|
5139
|
-
name,
|
|
5140
|
-
position: name,
|
|
5141
|
-
arrowType: type,
|
|
5142
|
-
doc: config.argDocs?.[name],
|
|
5143
|
-
...constraintSpecFields(config.argConstraints?.[name], config.argDefaults?.[name])
|
|
5144
|
-
});
|
|
5145
|
-
}
|
|
5146
|
-
}
|
|
5147
|
-
const meta = {
|
|
5148
|
-
name: config.name,
|
|
5149
|
-
description: config.description,
|
|
5150
|
-
stability: config.stability,
|
|
5151
|
-
projectionPushdown: config.projectionPushdown,
|
|
5152
|
-
filterPushdown: config.filterPushdown,
|
|
5153
|
-
autoApplyFilters: config.autoApplyFilters,
|
|
5154
|
-
examples: config.examples,
|
|
5155
|
-
categories: config.categories,
|
|
5156
|
-
tags: config.tags,
|
|
5157
|
-
parameterDefaultValues: config.parameterDefaultValues,
|
|
5158
|
-
maxWorkers: config.maxWorkers,
|
|
5159
|
-
requiredSettings: config.requiredSettings,
|
|
5160
|
-
requiredSecrets: config.requiredSecrets,
|
|
5161
|
-
hasFinalize: !!config.finalize
|
|
5162
|
-
};
|
|
5163
|
-
function extractArgs(request) {
|
|
5164
|
-
const args = {};
|
|
5165
|
-
for (const spec of specs) {
|
|
5166
|
-
if (spec.isTableInput)
|
|
5167
|
-
continue;
|
|
5168
|
-
const defaultVal = config.argDefaults?.[spec.name] !== undefined ? config.argDefaults[spec.name] : undefined;
|
|
5169
|
-
let val = request.arguments.get(spec.position, defaultVal);
|
|
5170
|
-
val = narrowArgValue(val);
|
|
5171
|
-
const constraints = config.argConstraints?.[spec.name];
|
|
5172
|
-
if (constraints)
|
|
5173
|
-
validateConstConstraints(spec.name, constraints, val);
|
|
5174
|
-
args[spec.name] = val;
|
|
5175
|
-
}
|
|
5176
|
-
return args;
|
|
5177
|
-
}
|
|
5178
|
-
return {
|
|
5179
|
-
kind: "table_in_out",
|
|
5180
|
-
meta,
|
|
5181
|
-
argumentSpecs: specs,
|
|
5182
|
-
async bind(request) {
|
|
5183
|
-
if (config.onBind) {
|
|
5184
|
-
const args = extractArgs(request);
|
|
5185
|
-
const settings = batchToScalarDict(request.settings);
|
|
5186
|
-
const secrets = batchToSecretDict(request.secrets);
|
|
5187
|
-
const result = await config.onBind({
|
|
5188
|
-
args,
|
|
5189
|
-
bindCall: request,
|
|
5190
|
-
settings,
|
|
5191
|
-
secrets,
|
|
5192
|
-
argumentNames: request.argument_names ?? null
|
|
5193
|
-
});
|
|
5194
|
-
return {
|
|
5195
|
-
output_schema: result.outputSchema,
|
|
5196
|
-
opaque_data: result.opaqueData ?? null
|
|
5197
|
-
};
|
|
5198
|
-
}
|
|
5199
|
-
return {
|
|
5200
|
-
output_schema: request.input_schema ?? schema2([]),
|
|
5201
|
-
opaque_data: null
|
|
5202
|
-
};
|
|
5203
|
-
},
|
|
5204
|
-
async globalInit(request) {
|
|
5205
|
-
const executionId = new Uint8Array(16);
|
|
5206
|
-
crypto.getRandomValues(executionId);
|
|
5207
|
-
if (request.execution_id) {
|
|
5208
|
-
return {
|
|
5209
|
-
max_workers: DEFAULT_MAX_WORKERS,
|
|
5210
|
-
execution_id: request.execution_id,
|
|
5211
|
-
opaque_data: null
|
|
5212
|
-
};
|
|
5213
|
-
}
|
|
5214
|
-
if (config.onInit) {
|
|
5215
|
-
const args = extractArgs(request.bind_call);
|
|
5216
|
-
return await config.onInit({
|
|
5217
|
-
args,
|
|
5218
|
-
initCall: request,
|
|
5219
|
-
outputSchema: request.output_schema,
|
|
5220
|
-
executionId
|
|
5221
|
-
});
|
|
5222
|
-
}
|
|
5223
|
-
return {
|
|
5224
|
-
max_workers: config.maxWorkers ?? 1,
|
|
5225
|
-
execution_id: executionId,
|
|
5226
|
-
opaque_data: null
|
|
5227
|
-
};
|
|
5228
|
-
},
|
|
5229
|
-
createStreamHandlers(request, response, accumulatedState) {
|
|
5230
|
-
const args = extractArgs(request.bind_call);
|
|
5231
|
-
const settings = batchToScalarDict(request.bind_call.settings);
|
|
5232
|
-
const secrets = batchToSecretDict(request.bind_call.secrets);
|
|
5233
|
-
const projIds = request.projection_ids && meta.projectionPushdown ? request.projection_ids : null;
|
|
5234
|
-
const outputSchema = projIds ? projectSchema(projIds, request.output_schema) : request.output_schema;
|
|
5235
|
-
const pushdownFilters = request.pushdown_filters ? deserializeFilters(request.pushdown_filters, {
|
|
5236
|
-
outputSchema: request.output_schema,
|
|
5237
|
-
joinKeyBatches: request.join_keys,
|
|
5238
|
-
extensionFunctions: meta.additionalFilterFunctions,
|
|
5239
|
-
runtimeAlgorithms: meta.runtimeFilterAlgorithms,
|
|
5240
|
-
evaluationContexts: meta.filterEvaluationContexts
|
|
5241
|
-
}) : undefined;
|
|
5242
|
-
const boundStorage = new BoundStorage(storage, response.execution_id ?? new Uint8Array(16));
|
|
5243
|
-
const processParams = {
|
|
5244
|
-
args,
|
|
5245
|
-
initCall: request,
|
|
5246
|
-
initResponse: response,
|
|
5247
|
-
outputSchema,
|
|
5248
|
-
settings,
|
|
5249
|
-
secrets,
|
|
5250
|
-
pushdownFilters,
|
|
5251
|
-
storage: boundStorage,
|
|
5252
|
-
substreamId: request.substream_id ?? null
|
|
5253
|
-
};
|
|
5254
|
-
const phase = request.phase;
|
|
5255
|
-
if (phase === "FINALIZE" /* FINALIZE */) {
|
|
5256
|
-
const finalizeLogKey = STREAMING_FINALIZE_KEY;
|
|
5257
|
-
return {
|
|
5258
|
-
outputSchema,
|
|
5259
|
-
producerInit: () => ({ state: { cursor: -1, materialized: false } }),
|
|
5260
|
-
producerFn: async (pState, out) => {
|
|
5261
|
-
if (!pState.state.materialized) {
|
|
5262
|
-
const finalizeStates = [];
|
|
5263
|
-
if (accumulatedState != null) {
|
|
5264
|
-
finalizeStates.push(accumulatedState);
|
|
5265
|
-
}
|
|
5266
|
-
const stored = await boundStorage.collect();
|
|
5267
|
-
for (const bytes of stored) {
|
|
5268
|
-
finalizeStates.push(deserializeUserState(bytes));
|
|
5269
|
-
}
|
|
5270
|
-
if (finalizeStates.length === 0) {
|
|
5271
|
-
finalizeStates.push(config.initialState ? config.initialState(processParams) : null);
|
|
5272
|
-
}
|
|
5273
|
-
const batches = config.finalize ? await config.finalize(processParams, finalizeStates) : [];
|
|
5274
|
-
for (const batch of batches) {
|
|
5275
|
-
await boundStorage.stateAppend(FrameworkNS.STREAMING_FINALIZE, finalizeLogKey, serializeBatch(batch));
|
|
5276
|
-
}
|
|
5277
|
-
pState.state.materialized = true;
|
|
5278
|
-
}
|
|
5279
|
-
const rows = await boundStorage.stateLogScan(FrameworkNS.STREAMING_FINALIZE, finalizeLogKey, pState.state.cursor, 1);
|
|
5280
|
-
if (rows.length === 0) {
|
|
5281
|
-
out.finish();
|
|
5282
|
-
return;
|
|
5283
|
-
}
|
|
5284
|
-
const [logId, bytes] = rows[0];
|
|
5285
|
-
out.emit(deserializeBatch(bytes));
|
|
5286
|
-
pState.state.cursor = logId;
|
|
5287
|
-
}
|
|
5288
|
-
};
|
|
5289
|
-
}
|
|
5290
|
-
if (request.bind_call.input_schema == null) {
|
|
5291
|
-
throw new Error(`${config.name}: is a table-in-out function (it requires an input row ` + `stream) but no input schema was supplied -- call it via ` + `table_in_out_function(input=...), not table_function().`);
|
|
5292
|
-
}
|
|
5293
|
-
const state = config.initialState ? config.initialState(processParams) : null;
|
|
5294
|
-
const processFn = config.process ?? ((_params, _state, batch, out) => {
|
|
5295
|
-
out.emit(projIds ? projectBatch(projIds, batch) : batch);
|
|
5296
|
-
});
|
|
5297
|
-
return {
|
|
5298
|
-
outputSchema,
|
|
5299
|
-
inputSchema: request.bind_call.input_schema,
|
|
5300
|
-
exchangeInit: () => ({ state, processParams }),
|
|
5301
|
-
exchangeFn: async (eState, input, out) => {
|
|
5302
|
-
applyRevalidationValidators(eState.processParams, input);
|
|
5303
|
-
applyDynamicFilterUpdate(eState.processParams, input);
|
|
5304
|
-
let wrappedOut = makeMetadataBakingCollector(out);
|
|
5305
|
-
if (projIds) {
|
|
5306
|
-
wrappedOut = makeSchemaReconcilingCollector(wrappedOut, outputSchema);
|
|
5307
|
-
}
|
|
5308
|
-
const currentFilters = eState.processParams.pushdownFilters;
|
|
5309
|
-
if (config.autoApplyFilters && currentFilters) {
|
|
5310
|
-
wrappedOut = new FilteringOutputCollector(wrappedOut, currentFilters);
|
|
5311
|
-
}
|
|
5312
|
-
await processFn(eState.processParams, eState.state, input, wrappedOut);
|
|
5313
|
-
if (eState.state != null) {
|
|
5314
|
-
const serialized = serializeUserState(eState.state);
|
|
5315
|
-
if (serialized != null) {
|
|
5316
|
-
await boundStorage.put(serialized);
|
|
5317
|
-
}
|
|
5318
|
-
}
|
|
5319
|
-
}
|
|
5320
|
-
};
|
|
5321
|
-
}
|
|
5322
|
-
};
|
|
5323
|
-
}
|
|
5324
|
-
function applyRevalidationValidators(params, input) {
|
|
5325
|
-
const md = input?.metadata;
|
|
5326
|
-
params.ifNoneMatch = md?.get(CACHE_IF_NONE_MATCH_KEY);
|
|
5327
|
-
params.ifModifiedSince = md?.get(CACHE_IF_MODIFIED_SINCE_KEY);
|
|
5328
|
-
}
|
|
5329
|
-
function applyDynamicFilterUpdate(params, input) {
|
|
5330
|
-
const encoded = input?.metadata?.get("vgi_pushdown_filters");
|
|
5331
|
-
if (!encoded)
|
|
5332
|
-
return;
|
|
5333
|
-
if (!params.pushdownFilters)
|
|
5334
|
-
throw new Error("dynamic filter delta received without an initial snapshot");
|
|
5335
|
-
if (new TextEncoder().encode(encoded).byteLength > 24 << 20) {
|
|
5336
|
-
throw new Error("base64 dynamic filter metadata exceeds the encoded-size limit");
|
|
5337
|
-
}
|
|
5338
|
-
if (encoded.length % 4 !== 0 || !/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(encoded)) {
|
|
5339
|
-
throw new Error("dynamic filter metadata is not valid base64");
|
|
5340
|
-
}
|
|
5341
|
-
const binary = globalThis.atob ? globalThis.atob(encoded) : Buffer.from(encoded, "base64").toString("binary");
|
|
5342
|
-
const bytes = Uint8Array.from(binary, (character) => character.charCodeAt(0));
|
|
5343
|
-
if (bytes.byteLength > 17 << 20)
|
|
5344
|
-
throw new Error("dynamic filter IPC payload exceeds the encoded-size limit");
|
|
5345
|
-
const current = params.pushdownFilters;
|
|
5346
|
-
params.pushdownFilters = current.applyDelta(deserializeBatch(bytes));
|
|
5347
|
-
}
|
|
5348
|
-
function makeMetadataBakingCollector(inner) {
|
|
5349
|
-
return new Proxy(inner, {
|
|
5350
|
-
get(target, prop, receiver) {
|
|
5351
|
-
if (prop === "emit") {
|
|
5352
|
-
return function(batchOrColumns, metadata) {
|
|
5353
|
-
if (batchOrColumns && typeof batchOrColumns.getChild === "function" && metadata && metadata.size > 0) {
|
|
5354
|
-
const batch = batchOrColumns;
|
|
5355
|
-
const merged = new Map(batch.metadata ?? []);
|
|
5356
|
-
for (const [k, v] of metadata)
|
|
5357
|
-
merged.set(k, v);
|
|
5358
|
-
return target.emit(withBatchMetadata(batch, merged), merged);
|
|
5359
|
-
}
|
|
5360
|
-
return target.emit(batchOrColumns, metadata);
|
|
5361
|
-
};
|
|
5362
|
-
}
|
|
5363
|
-
const v = Reflect.get(target, prop, receiver);
|
|
5364
|
-
return typeof v === "function" ? v.bind(target) : v;
|
|
5365
|
-
}
|
|
5366
|
-
});
|
|
5367
|
-
}
|
|
5368
|
-
function makeSchemaReconcilingCollector(inner, targetSchema) {
|
|
5369
|
-
function reconcile(batch) {
|
|
5370
|
-
const batchFields = batch.schema.fields;
|
|
5371
|
-
if (batchFields.length === targetSchema.fields.length && targetSchema.fields.every((f, i) => batchFields[i].name === f.name)) {
|
|
5372
|
-
return batch;
|
|
5373
|
-
}
|
|
5374
|
-
const ids = [];
|
|
5375
|
-
for (const f of targetSchema.fields) {
|
|
5376
|
-
const idx = batchFields.findIndex((bf) => bf.name === f.name);
|
|
5377
|
-
if (idx < 0) {
|
|
5378
|
-
throw new Error(`emitted batch is missing projected output column '${f.name}' ` + `(emitted: [${batchFields.map((bf) => bf.name).join(", ")}])`);
|
|
5379
|
-
}
|
|
5380
|
-
ids.push(idx);
|
|
5381
|
-
}
|
|
5382
|
-
return projectBatch(ids, batch);
|
|
5383
|
-
}
|
|
5384
|
-
return new Proxy(inner, {
|
|
5385
|
-
get(target, prop, receiver) {
|
|
5386
|
-
if (prop === "emit") {
|
|
5387
|
-
return function(batchOrColumns, metadata) {
|
|
5388
|
-
if (batchOrColumns && typeof batchOrColumns.getChild === "function") {
|
|
5389
|
-
return target.emit(reconcile(batchOrColumns), metadata);
|
|
5390
|
-
}
|
|
5391
|
-
return target.emit(batchOrColumns, metadata);
|
|
5392
|
-
};
|
|
5393
|
-
}
|
|
5394
|
-
const v = Reflect.get(target, prop, receiver);
|
|
5395
|
-
return typeof v === "function" ? v.bind(target) : v;
|
|
5396
|
-
}
|
|
5397
|
-
});
|
|
5398
|
-
}
|
|
5399
|
-
var PARENT_ROW_METADATA_KEY = "vgi_rpc.parent_row#b64";
|
|
5400
|
-
function parentRowsMetadata(parentRows, outputRows, extra) {
|
|
5401
|
-
if (parentRows.length !== outputRows) {
|
|
5402
|
-
throw new Error(`parentRowsMetadata: length ${parentRows.length} != output rows ${outputRows}; ` + `parentRows must carry exactly one input-row index per emitted output row`);
|
|
5403
|
-
}
|
|
5404
|
-
const md = new Map(extra ?? []);
|
|
5405
|
-
if (outputRows === 0) {
|
|
5406
|
-
return md;
|
|
5407
|
-
}
|
|
5408
|
-
const raw = new Uint8Array(parentRows.length * 4);
|
|
5409
|
-
const dv = new DataView(raw.buffer);
|
|
5410
|
-
for (let i = 0;i < parentRows.length; i++) {
|
|
5411
|
-
dv.setInt32(i * 4, parentRows[i], true);
|
|
5412
|
-
}
|
|
5413
|
-
md.set(PARENT_ROW_METADATA_KEY, base64Encode(raw));
|
|
5414
|
-
return md;
|
|
5415
|
-
}
|
|
5416
|
-
function base64Encode(bytes) {
|
|
5417
|
-
if (typeof globalThis.Buffer !== "undefined") {
|
|
5418
|
-
return globalThis.Buffer.from(bytes).toString("base64");
|
|
5419
|
-
}
|
|
5420
|
-
let bin = "";
|
|
5421
|
-
for (let i = 0;i < bytes.length; i++)
|
|
5422
|
-
bin += String.fromCharCode(bytes[i]);
|
|
5423
|
-
return globalThis.btoa(bin);
|
|
5424
|
-
}
|
|
5425
|
-
function defineRowTransformFunction(config) {
|
|
5426
|
-
const numPositional = Object.keys(config.args ?? {}).length + (config.varargs ? 1 : 0);
|
|
5427
|
-
if (numPositional === 0) {
|
|
5428
|
-
throw new Error(`${config.name}: a blended row-transform function needs at least one ` + `positional arg (its per-row input column); found none.`);
|
|
5429
|
-
}
|
|
5430
|
-
const specs = [];
|
|
5431
|
-
let posIdx = 0;
|
|
5432
|
-
if (config.args) {
|
|
5433
|
-
for (const [name, type] of Object.entries(config.args)) {
|
|
5434
|
-
specs.push({
|
|
5435
|
-
name,
|
|
5436
|
-
position: posIdx++,
|
|
5437
|
-
arrowType: type,
|
|
5438
|
-
doc: config.argDocs?.[name],
|
|
5439
|
-
...constraintSpecFields(config.argConstraints?.[name])
|
|
5440
|
-
});
|
|
5441
|
-
}
|
|
5442
|
-
}
|
|
5443
|
-
if (config.varargs) {
|
|
5444
|
-
specs.push({
|
|
5445
|
-
name: config.varargs.name,
|
|
5446
|
-
position: posIdx++,
|
|
5447
|
-
arrowType: config.varargs.type,
|
|
5448
|
-
isVarargs: true,
|
|
5449
|
-
doc: config.varargs.doc ?? config.argDocs?.[config.varargs.name],
|
|
5450
|
-
...constraintSpecFields(config.argConstraints?.[config.varargs.name])
|
|
5451
|
-
});
|
|
5452
|
-
}
|
|
5453
|
-
if (config.namedArgs) {
|
|
5454
|
-
for (const [name, type] of Object.entries(config.namedArgs)) {
|
|
5455
|
-
specs.push({
|
|
5456
|
-
name,
|
|
5457
|
-
position: name,
|
|
5458
|
-
arrowType: type,
|
|
5459
|
-
doc: config.argDocs?.[name],
|
|
5460
|
-
...constraintSpecFields(config.argConstraints?.[name], config.argDefaults?.[name])
|
|
5461
|
-
});
|
|
5462
|
-
}
|
|
5463
|
-
}
|
|
5464
|
-
const meta = {
|
|
5465
|
-
name: config.name,
|
|
5466
|
-
description: config.description,
|
|
5467
|
-
stability: config.stability,
|
|
5468
|
-
projectionPushdown: config.projectionPushdown,
|
|
5469
|
-
filterPushdown: config.filterPushdown,
|
|
5470
|
-
autoApplyFilters: config.autoApplyFilters,
|
|
5471
|
-
examples: config.examples,
|
|
5472
|
-
categories: config.categories,
|
|
5473
|
-
tags: config.tags,
|
|
5474
|
-
parameterDefaultValues: config.parameterDefaultValues,
|
|
5475
|
-
maxWorkers: config.maxWorkers,
|
|
5476
|
-
requiredSettings: config.requiredSettings,
|
|
5477
|
-
requiredSecrets: config.requiredSecrets,
|
|
5478
|
-
hasFinalize: false,
|
|
5479
|
-
inputFromArgs: true
|
|
5480
|
-
};
|
|
5481
|
-
function extractArgs(request) {
|
|
5482
|
-
const args = {};
|
|
5483
|
-
for (const spec of specs) {
|
|
5484
|
-
if (typeof spec.position !== "string")
|
|
5485
|
-
continue;
|
|
5486
|
-
const defaultVal = config.argDefaults?.[spec.name] !== undefined ? config.argDefaults[spec.name] : undefined;
|
|
5487
|
-
let val = request.arguments.get(spec.position, defaultVal ?? null);
|
|
5488
|
-
val = narrowArgValue(val);
|
|
5489
|
-
const constraints = config.argConstraints?.[spec.name];
|
|
5490
|
-
if (constraints)
|
|
5491
|
-
validateConstConstraints(spec.name, constraints, val);
|
|
5492
|
-
args[spec.name] = val;
|
|
5493
|
-
}
|
|
5494
|
-
return args;
|
|
5495
|
-
}
|
|
5496
|
-
return {
|
|
5497
|
-
kind: "table_in_out",
|
|
5498
|
-
meta,
|
|
5499
|
-
argumentSpecs: specs,
|
|
5500
|
-
async bind(request) {
|
|
5501
|
-
const args = extractArgs(request);
|
|
5502
|
-
const settings = batchToScalarDict(request.settings);
|
|
5503
|
-
const secrets = batchToSecretDict(request.secrets);
|
|
5504
|
-
const result = await config.onBind({
|
|
5505
|
-
args,
|
|
5506
|
-
bindCall: request,
|
|
5507
|
-
settings,
|
|
5508
|
-
secrets,
|
|
5509
|
-
argumentNames: request.argument_names ?? null
|
|
5510
|
-
});
|
|
5511
|
-
return {
|
|
5512
|
-
output_schema: result.outputSchema,
|
|
5513
|
-
opaque_data: result.opaqueData ?? null
|
|
5514
|
-
};
|
|
5515
|
-
},
|
|
5516
|
-
async globalInit(request) {
|
|
5517
|
-
if (request.execution_id) {
|
|
5518
|
-
return {
|
|
5519
|
-
max_workers: DEFAULT_MAX_WORKERS,
|
|
5520
|
-
execution_id: request.execution_id,
|
|
5521
|
-
opaque_data: null
|
|
5522
|
-
};
|
|
5523
|
-
}
|
|
5524
|
-
const executionId = new Uint8Array(16);
|
|
5525
|
-
crypto.getRandomValues(executionId);
|
|
5526
|
-
return {
|
|
5527
|
-
max_workers: config.maxWorkers ?? 1,
|
|
5528
|
-
execution_id: executionId,
|
|
5529
|
-
opaque_data: null
|
|
5530
|
-
};
|
|
5531
|
-
},
|
|
5532
|
-
createStreamHandlers(request, response, _accumulatedState) {
|
|
5533
|
-
const args = extractArgs(request.bind_call);
|
|
5534
|
-
const settings = batchToScalarDict(request.bind_call.settings);
|
|
5535
|
-
const secrets = batchToSecretDict(request.bind_call.secrets);
|
|
5536
|
-
const projIds = request.projection_ids && meta.projectionPushdown ? request.projection_ids : null;
|
|
5537
|
-
const outputSchema = projIds ? projectSchema(projIds, request.output_schema) : request.output_schema;
|
|
5538
|
-
const pushdownFilters = request.pushdown_filters ? deserializeFilters(request.pushdown_filters, {
|
|
5539
|
-
outputSchema: request.output_schema,
|
|
5540
|
-
joinKeyBatches: request.join_keys,
|
|
5541
|
-
extensionFunctions: meta.additionalFilterFunctions,
|
|
5542
|
-
runtimeAlgorithms: meta.runtimeFilterAlgorithms,
|
|
5543
|
-
evaluationContexts: meta.filterEvaluationContexts
|
|
5544
|
-
}) : undefined;
|
|
5545
|
-
const boundStorage = new BoundStorage(storage, response.execution_id ?? new Uint8Array(16));
|
|
5546
|
-
const processParams = {
|
|
5547
|
-
args,
|
|
5548
|
-
initCall: request,
|
|
5549
|
-
initResponse: response,
|
|
5550
|
-
outputSchema,
|
|
5551
|
-
settings,
|
|
5552
|
-
secrets,
|
|
5553
|
-
pushdownFilters,
|
|
5554
|
-
storage: boundStorage,
|
|
5555
|
-
substreamId: request.substream_id ?? null
|
|
5556
|
-
};
|
|
5557
|
-
if (request.phase === "FINALIZE" /* FINALIZE */) {
|
|
5558
|
-
throw new Error(`${config.name}: a blended row-transform function has no FINALIZE ` + `phase (it is a per-row map; has_finalize is advertised false).`);
|
|
5559
|
-
}
|
|
5560
|
-
if (request.bind_call.input_schema == null) {
|
|
5561
|
-
throw new Error(`${config.name}: is a table-in-out function (its positional args are ` + `per-row input columns) but no input schema was supplied -- call it ` + `via table_in_out_function(input=...), not table_function().`);
|
|
5562
|
-
}
|
|
5563
|
-
return {
|
|
5564
|
-
outputSchema,
|
|
5565
|
-
inputSchema: request.bind_call.input_schema,
|
|
5566
|
-
exchangeInit: () => ({ state: null, processParams }),
|
|
5567
|
-
exchangeFn: async (eState, input, out) => {
|
|
5568
|
-
applyRevalidationValidators(eState.processParams, input);
|
|
5569
|
-
applyDynamicFilterUpdate(eState.processParams, input);
|
|
5570
|
-
let wrappedOut = makeMetadataBakingCollector(out);
|
|
5571
|
-
if (projIds) {
|
|
5572
|
-
wrappedOut = makeSchemaReconcilingCollector(wrappedOut, outputSchema);
|
|
5573
|
-
}
|
|
5574
|
-
const currentFilters = eState.processParams.pushdownFilters;
|
|
5575
|
-
if (config.autoApplyFilters && currentFilters) {
|
|
5576
|
-
wrappedOut = new FilteringOutputCollector(wrappedOut, currentFilters);
|
|
5577
|
-
}
|
|
5578
|
-
await config.process(eState.processParams, input, wrappedOut);
|
|
5579
|
-
}
|
|
5580
|
-
};
|
|
5581
|
-
}
|
|
5582
|
-
};
|
|
5583
|
-
}
|
|
5584
|
-
// src/functions/table-buffering.ts
|
|
5585
|
-
init_arrow();
|
|
5586
|
-
init_arrow();
|
|
5587
|
-
init_registry();
|
|
5588
|
-
init_storage();
|
|
5589
|
-
|
|
5590
|
-
// src/protocol/serializers/arguments.ts
|
|
5591
|
-
init_arrow();
|
|
5592
|
-
init_registry();
|
|
5593
|
-
|
|
5594
|
-
// src/arguments/arguments.ts
|
|
5595
|
-
class Arguments {
|
|
5596
|
-
positional;
|
|
5597
|
-
named;
|
|
5598
|
-
argumentsSchema;
|
|
5599
|
-
constructor(positional = [], named = new Map, argumentsSchema = null) {
|
|
5600
|
-
this.positional = positional;
|
|
5601
|
-
this.named = named;
|
|
5602
|
-
this.argumentsSchema = argumentsSchema;
|
|
5603
|
-
}
|
|
5604
|
-
get(position, defaultValue) {
|
|
5605
|
-
if (typeof position === "number") {
|
|
5606
|
-
if (position < this.positional.length) {
|
|
5607
|
-
const val = this.positional[position];
|
|
5608
|
-
if (val === null || val === undefined) {
|
|
5609
|
-
return defaultValue !== undefined ? defaultValue : null;
|
|
5610
|
-
}
|
|
5611
|
-
return unwrapScalar(val);
|
|
5612
|
-
}
|
|
5613
|
-
if (defaultValue !== undefined)
|
|
5614
|
-
return defaultValue;
|
|
5615
|
-
throw new Error(`Positional argument ${position} not found`);
|
|
5616
|
-
}
|
|
5617
|
-
if (this.named.has(position)) {
|
|
5618
|
-
const val = this.named.get(position);
|
|
5619
|
-
if (val === null || val === undefined) {
|
|
5620
|
-
return defaultValue !== undefined ? defaultValue : null;
|
|
5621
|
-
}
|
|
5622
|
-
return unwrapScalar(val);
|
|
5623
|
-
}
|
|
5624
|
-
if (defaultValue !== undefined)
|
|
5625
|
-
return defaultValue;
|
|
5626
|
-
throw new Error(`Named argument '${position}' not found`);
|
|
5627
|
-
}
|
|
5628
|
-
get length() {
|
|
5629
|
-
return this.positional.length;
|
|
5630
|
-
}
|
|
5631
|
-
}
|
|
5632
|
-
function unwrapScalar(val) {
|
|
5633
|
-
if (val === null || val === undefined)
|
|
5634
|
-
return null;
|
|
5635
|
-
if (typeof val !== "object")
|
|
5636
|
-
return val;
|
|
5637
|
-
if (typeof val.valueOf === "function") {
|
|
5638
|
-
let v;
|
|
5639
|
-
try {
|
|
5640
|
-
v = val.valueOf();
|
|
5641
|
-
} catch {
|
|
5642
|
-
return val;
|
|
5643
|
-
}
|
|
5644
|
-
if (typeof v === "bigint") {
|
|
5645
|
-
if (v >= Number.MIN_SAFE_INTEGER && v <= Number.MAX_SAFE_INTEGER) {
|
|
5646
|
-
return Number(v);
|
|
5647
|
-
}
|
|
5648
|
-
return v;
|
|
5649
|
-
}
|
|
5650
|
-
return v;
|
|
5651
|
-
}
|
|
5652
|
-
return val;
|
|
5653
|
-
}
|
|
5654
|
-
|
|
5655
|
-
// src/protocol/serializers/arguments.ts
|
|
5656
|
-
function serializeArguments(args) {
|
|
5657
|
-
const structFields = [];
|
|
5658
|
-
const structValues = {};
|
|
5659
|
-
for (let i = 0;i < args.positional.length; i++) {
|
|
5660
|
-
const val = args.positional[i];
|
|
5661
|
-
const fieldName = `positional_${i}`;
|
|
5662
|
-
structFields.push(field2(fieldName, inferScalarType(val), true));
|
|
5663
|
-
structValues[fieldName] = val;
|
|
5664
|
-
}
|
|
5665
|
-
for (const [name, val] of args.named) {
|
|
5666
|
-
const fieldName = `named_${name}`;
|
|
5667
|
-
structFields.push(field2(fieldName, inferScalarType(val), true));
|
|
5668
|
-
structValues[fieldName] = val;
|
|
5669
|
-
}
|
|
5670
|
-
const structType = struct2(structFields);
|
|
5671
|
-
const sch = schema2([field2("args", structType, true)]);
|
|
5672
|
-
const structRow = {};
|
|
5673
|
-
for (const f of structFields) {
|
|
5674
|
-
let val = structValues[f.name];
|
|
5675
|
-
if (isInt(f.type) && f.type.bitWidth === 64 && typeof val === "number") {
|
|
5676
|
-
val = BigInt(val);
|
|
5677
|
-
}
|
|
5678
|
-
structRow[f.name] = val;
|
|
5679
|
-
}
|
|
5680
|
-
const batch = batchFromColumns({ args: [structRow] }, sch);
|
|
5681
|
-
return serializeBatch(batch);
|
|
5235
|
+
const batch = batchFromColumns({ args: [structRow] }, sch);
|
|
5236
|
+
return serializeBatch(batch);
|
|
5682
5237
|
}
|
|
5683
5238
|
function inferScalarType(val) {
|
|
5684
5239
|
if (val === null || val === undefined)
|
|
@@ -5968,162 +5523,892 @@ function serializeInitRequest(req) {
|
|
|
5968
5523
|
tablesample_percentage: req.tablesample_percentage ?? null,
|
|
5969
5524
|
tablesample_seed: req.tablesample_seed ?? null
|
|
5970
5525
|
};
|
|
5971
|
-
return buildSingleRowBatch(INIT_REQUEST_SCHEMA, row);
|
|
5526
|
+
return buildSingleRowBatch(INIT_REQUEST_SCHEMA, row);
|
|
5527
|
+
}
|
|
5528
|
+
function deserializeInitRequest(params) {
|
|
5529
|
+
const bindCallBytes = toUint8Array2(params.bind_call);
|
|
5530
|
+
const bindCallBatch = deserializeBatch(bindCallBytes);
|
|
5531
|
+
const bindParams = batchToScalarDict(bindCallBatch);
|
|
5532
|
+
const bindCall = deserializeBindRequest(bindParams);
|
|
5533
|
+
let projectionIds = null;
|
|
5534
|
+
if (params.projection_ids != null) {
|
|
5535
|
+
const raw = params.projection_ids;
|
|
5536
|
+
if (Array.isArray(raw)) {
|
|
5537
|
+
projectionIds = raw.map(Number);
|
|
5538
|
+
} else if (raw && typeof raw[Symbol.iterator] === "function") {
|
|
5539
|
+
projectionIds = [...raw].map(Number);
|
|
5540
|
+
}
|
|
5541
|
+
}
|
|
5542
|
+
let phase = null;
|
|
5543
|
+
const phaseRaw = decodeDictValue(params.phase);
|
|
5544
|
+
if (phaseRaw != null) {
|
|
5545
|
+
const phaseStr = String(phaseRaw);
|
|
5546
|
+
if (phaseStr === "INPUT") {
|
|
5547
|
+
phase = "INPUT" /* INPUT */;
|
|
5548
|
+
} else if (phaseStr === "FINALIZE") {
|
|
5549
|
+
phase = "FINALIZE" /* FINALIZE */;
|
|
5550
|
+
} else if (phaseStr === "TABLE_BUFFERING") {
|
|
5551
|
+
phase = "TABLE_BUFFERING" /* TABLE_BUFFERING */;
|
|
5552
|
+
} else if (phaseStr === "TABLE_BUFFERING_FINALIZE") {
|
|
5553
|
+
phase = "TABLE_BUFFERING_FINALIZE" /* TABLE_BUFFERING_FINALIZE */;
|
|
5554
|
+
}
|
|
5555
|
+
}
|
|
5556
|
+
const joinKeys = [];
|
|
5557
|
+
if (params.join_keys != null) {
|
|
5558
|
+
const raw = params.join_keys;
|
|
5559
|
+
const iter = Array.isArray(raw) ? raw : typeof raw[Symbol.iterator] === "function" ? raw : [];
|
|
5560
|
+
for (const entry of iter) {
|
|
5561
|
+
if (entry == null)
|
|
5562
|
+
continue;
|
|
5563
|
+
try {
|
|
5564
|
+
joinKeys.push(deserializeBatch(toUint8Array2(entry)));
|
|
5565
|
+
} catch {}
|
|
5566
|
+
}
|
|
5567
|
+
}
|
|
5568
|
+
return {
|
|
5569
|
+
bind_call: bindCall,
|
|
5570
|
+
output_schema: deserializeSchema(toUint8Array2(params.output_schema)),
|
|
5571
|
+
bind_opaque_data: params.bind_opaque_data ? toUint8Array2(params.bind_opaque_data) : null,
|
|
5572
|
+
projection_ids: projectionIds,
|
|
5573
|
+
row_limit: params.row_limit == null ? null : Number(params.row_limit),
|
|
5574
|
+
pushdown_filters: params.pushdown_filters ? deserializeBatch(toUint8Array2(params.pushdown_filters)) : null,
|
|
5575
|
+
join_keys: joinKeys,
|
|
5576
|
+
phase,
|
|
5577
|
+
finalize_state_id: params.finalize_state_id ? toUint8Array2(params.finalize_state_id) : null,
|
|
5578
|
+
split_tokens: (() => {
|
|
5579
|
+
const raw = params.split_tokens;
|
|
5580
|
+
if (raw == null)
|
|
5581
|
+
return null;
|
|
5582
|
+
const iter = Array.isArray(raw) ? raw : typeof raw[Symbol.iterator] === "function" ? raw : [];
|
|
5583
|
+
const tokens = [...iter].filter((e) => e != null).map((e) => toUint8Array2(e));
|
|
5584
|
+
return tokens.length > 0 ? tokens : null;
|
|
5585
|
+
})(),
|
|
5586
|
+
execution_id: params.execution_id ? toUint8Array2(params.execution_id) : null,
|
|
5587
|
+
init_opaque_data: params.init_opaque_data ? toUint8Array2(params.init_opaque_data) : null,
|
|
5588
|
+
substream_id: params.substream_id ? toUint8Array2(params.substream_id) : null,
|
|
5589
|
+
order_by_column_name: parseEnum(decodeDictValue(params.order_by_column_name)) ?? null,
|
|
5590
|
+
order_by_direction: parseDirection(decodeDictValue(params.order_by_direction)),
|
|
5591
|
+
order_by_null_order: parseNullOrder(decodeDictValue(params.order_by_null_order)),
|
|
5592
|
+
order_by_limit: parseBigInt(params.order_by_limit),
|
|
5593
|
+
tablesample_percentage: parseNumber(params.tablesample_percentage),
|
|
5594
|
+
tablesample_seed: parseBigInt(params.tablesample_seed)
|
|
5595
|
+
};
|
|
5596
|
+
}
|
|
5597
|
+
function parseEnum(v) {
|
|
5598
|
+
if (v === null || v === undefined)
|
|
5599
|
+
return null;
|
|
5600
|
+
return String(v);
|
|
5601
|
+
}
|
|
5602
|
+
function parseDirection(v) {
|
|
5603
|
+
if (v === null || v === undefined)
|
|
5604
|
+
return null;
|
|
5605
|
+
const s = String(v);
|
|
5606
|
+
if (s === "ASC")
|
|
5607
|
+
return "ASC" /* ASC */;
|
|
5608
|
+
if (s === "DESC")
|
|
5609
|
+
return "DESC" /* DESC */;
|
|
5610
|
+
return null;
|
|
5611
|
+
}
|
|
5612
|
+
function parseNullOrder(v) {
|
|
5613
|
+
if (v === null || v === undefined)
|
|
5614
|
+
return null;
|
|
5615
|
+
const s = String(v);
|
|
5616
|
+
if (s === "NULLS_FIRST")
|
|
5617
|
+
return "NULLS_FIRST" /* NULLS_FIRST */;
|
|
5618
|
+
if (s === "NULLS_LAST")
|
|
5619
|
+
return "NULLS_LAST" /* NULLS_LAST */;
|
|
5620
|
+
return null;
|
|
5621
|
+
}
|
|
5622
|
+
function parseBigInt(v) {
|
|
5623
|
+
if (v === null || v === undefined)
|
|
5624
|
+
return null;
|
|
5625
|
+
if (typeof v === "bigint")
|
|
5626
|
+
return v;
|
|
5627
|
+
if (typeof v === "number")
|
|
5628
|
+
return BigInt(v);
|
|
5629
|
+
try {
|
|
5630
|
+
return BigInt(String(v));
|
|
5631
|
+
} catch {
|
|
5632
|
+
return null;
|
|
5633
|
+
}
|
|
5634
|
+
}
|
|
5635
|
+
function parseNumber(v) {
|
|
5636
|
+
if (v === null || v === undefined)
|
|
5637
|
+
return null;
|
|
5638
|
+
if (typeof v === "number")
|
|
5639
|
+
return v;
|
|
5640
|
+
if (typeof v === "bigint")
|
|
5641
|
+
return Number(v);
|
|
5642
|
+
const n = Number(v);
|
|
5643
|
+
return Number.isNaN(n) ? null : n;
|
|
5644
|
+
}
|
|
5645
|
+
function serializeGlobalInitResponse(resp) {
|
|
5646
|
+
return {
|
|
5647
|
+
execution_id: resp.execution_id,
|
|
5648
|
+
opaque_data: resp.opaque_data ?? null,
|
|
5649
|
+
max_workers: resp.max_workers
|
|
5650
|
+
};
|
|
5972
5651
|
}
|
|
5973
|
-
function
|
|
5652
|
+
function deserializeGlobalInitResponse(params) {
|
|
5653
|
+
return {
|
|
5654
|
+
execution_id: toUint8Array2(params.execution_id),
|
|
5655
|
+
opaque_data: params.opaque_data ? toUint8Array2(params.opaque_data) : null,
|
|
5656
|
+
max_workers: Number(params.max_workers)
|
|
5657
|
+
};
|
|
5658
|
+
}
|
|
5659
|
+
// src/protocol/serializers/cardinality.ts
|
|
5660
|
+
init_arrow();
|
|
5661
|
+
var TABLE_FUNCTION_CARDINALITY_REQUEST_SCHEMA = schema2([
|
|
5662
|
+
field2("bind_call", binary2(), false),
|
|
5663
|
+
field2("bind_opaque_data", binary2(), true)
|
|
5664
|
+
]);
|
|
5665
|
+
function deserializeCardinalityRequest(params) {
|
|
5974
5666
|
const bindCallBytes = toUint8Array2(params.bind_call);
|
|
5975
5667
|
const bindCallBatch = deserializeBatch(bindCallBytes);
|
|
5976
5668
|
const bindParams = batchToScalarDict(bindCallBatch);
|
|
5977
5669
|
const bindCall = deserializeBindRequest(bindParams);
|
|
5978
|
-
|
|
5979
|
-
|
|
5980
|
-
|
|
5981
|
-
|
|
5982
|
-
|
|
5983
|
-
|
|
5984
|
-
|
|
5670
|
+
return {
|
|
5671
|
+
bind_call: bindCall,
|
|
5672
|
+
bind_opaque_data: params.bind_opaque_data ? toUint8Array2(params.bind_opaque_data) : null
|
|
5673
|
+
};
|
|
5674
|
+
}
|
|
5675
|
+
function serializeTableCardinality(card) {
|
|
5676
|
+
return {
|
|
5677
|
+
estimate: card.estimate,
|
|
5678
|
+
max: card.max
|
|
5679
|
+
};
|
|
5680
|
+
}
|
|
5681
|
+
// src/protocol/carried-init-request.ts
|
|
5682
|
+
var RAW = 0;
|
|
5683
|
+
var ZSTD = 1;
|
|
5684
|
+
function packInitRequest(ipc) {
|
|
5685
|
+
const codec = zstdSync();
|
|
5686
|
+
const compressed = codec ? codec.compress(ipc) : null;
|
|
5687
|
+
const useZstd = compressed !== null && compressed.byteLength < ipc.byteLength;
|
|
5688
|
+
const payload = useZstd ? compressed : ipc;
|
|
5689
|
+
const packed = new Uint8Array(payload.byteLength + 1);
|
|
5690
|
+
packed[0] = useZstd ? ZSTD : RAW;
|
|
5691
|
+
packed.set(payload, 1);
|
|
5692
|
+
return packed;
|
|
5693
|
+
}
|
|
5694
|
+
function unpackInitRequest(packed) {
|
|
5695
|
+
if (packed.byteLength === 0)
|
|
5696
|
+
throw new Error("state token carries no init request");
|
|
5697
|
+
switch (packed[0]) {
|
|
5698
|
+
case RAW:
|
|
5699
|
+
return packed.slice(1);
|
|
5700
|
+
case ZSTD: {
|
|
5701
|
+
const codec = zstdSync();
|
|
5702
|
+
if (!codec) {
|
|
5703
|
+
throw new Error("state token carries a zstd-compressed init request, and this runtime has no synchronous zstd " + "(it was minted by a worker running under Bun or Node >= 22.15 with the same signing key)");
|
|
5704
|
+
}
|
|
5705
|
+
return codec.decompress(packed.subarray(1));
|
|
5985
5706
|
}
|
|
5707
|
+
default:
|
|
5708
|
+
throw new Error(`state token carries an init request with unknown codec ${packed[0]}`);
|
|
5986
5709
|
}
|
|
5987
|
-
|
|
5988
|
-
|
|
5989
|
-
|
|
5990
|
-
|
|
5991
|
-
|
|
5992
|
-
|
|
5993
|
-
|
|
5994
|
-
|
|
5995
|
-
|
|
5996
|
-
|
|
5997
|
-
|
|
5998
|
-
|
|
5710
|
+
}
|
|
5711
|
+
var MAX_ENTRIES = 128;
|
|
5712
|
+
var parsed = new Map;
|
|
5713
|
+
var stats = { parses: 0, hits: 0 };
|
|
5714
|
+
function hashBytes(bytes) {
|
|
5715
|
+
let h = 2166136261 ^ bytes.byteLength;
|
|
5716
|
+
for (let i = 0;i < bytes.byteLength; i++) {
|
|
5717
|
+
h ^= bytes[i];
|
|
5718
|
+
h = Math.imul(h, 16777619);
|
|
5719
|
+
}
|
|
5720
|
+
return h >>> 0;
|
|
5721
|
+
}
|
|
5722
|
+
function sameBytes(a, b) {
|
|
5723
|
+
if (a.byteLength !== b.byteLength)
|
|
5724
|
+
return false;
|
|
5725
|
+
for (let i = 0;i < a.byteLength; i++)
|
|
5726
|
+
if (a[i] !== b[i])
|
|
5727
|
+
return false;
|
|
5728
|
+
return true;
|
|
5729
|
+
}
|
|
5730
|
+
function parseCarriedInitRequest(packed) {
|
|
5731
|
+
const key = hashBytes(packed);
|
|
5732
|
+
let entry = parsed.get(key);
|
|
5733
|
+
if (entry && sameBytes(entry.packed, packed)) {
|
|
5734
|
+
parsed.delete(key);
|
|
5735
|
+
parsed.set(key, entry);
|
|
5736
|
+
stats.hits++;
|
|
5737
|
+
} else {
|
|
5738
|
+
const dict = batchToScalarDict(deserializeBatch(unpackInitRequest(packed)));
|
|
5739
|
+
stats.parses++;
|
|
5740
|
+
entry = { packed: packed.slice(), request: deserializeInitRequest(dict), bindCallIpc: dict.bind_call };
|
|
5741
|
+
parsed.delete(key);
|
|
5742
|
+
if (parsed.size >= MAX_ENTRIES)
|
|
5743
|
+
parsed.delete(parsed.keys().next().value);
|
|
5744
|
+
parsed.set(key, entry);
|
|
5745
|
+
}
|
|
5746
|
+
return {
|
|
5747
|
+
request: { ...entry.request, bind_call: { ...entry.request.bind_call } },
|
|
5748
|
+
bindCallIpc: entry.bindCallIpc
|
|
5749
|
+
};
|
|
5750
|
+
}
|
|
5751
|
+
|
|
5752
|
+
// src/protocol/state-serializer.ts
|
|
5753
|
+
var EXCHANGE_STATE_SCHEMA = schema2([
|
|
5754
|
+
field2("function_name", binary2(), false),
|
|
5755
|
+
field2("init_request", binary2(), false),
|
|
5756
|
+
field2("execution_id", binary2(), false),
|
|
5757
|
+
field2("max_workers", int642(), false),
|
|
5758
|
+
field2("opaque_data", binary2(), true),
|
|
5759
|
+
field2("is_producer", bool2(), false),
|
|
5760
|
+
field2("user_state", binary2(), true),
|
|
5761
|
+
field2("filter_history", binary2(), true)
|
|
5762
|
+
]);
|
|
5763
|
+
var TEXT_ENCODER = new TextEncoder;
|
|
5764
|
+
var TEXT_DECODER = new TextDecoder;
|
|
5765
|
+
var STATE_FORMAT_VERSION = 1;
|
|
5766
|
+
var FLAG_PRODUCER = 1;
|
|
5767
|
+
var FLAG_OPAQUE_DATA = 2;
|
|
5768
|
+
var FLAG_USER_STATE = 4;
|
|
5769
|
+
var FLAG_FILTER_HISTORY = 8;
|
|
5770
|
+
var LIST_CHILD_NAME = "item";
|
|
5771
|
+
var emptyListElementType = () => utf82();
|
|
5772
|
+
function inferElementType(values) {
|
|
5773
|
+
let elementType = null;
|
|
5774
|
+
let elementSig = "";
|
|
5775
|
+
for (const v of values) {
|
|
5776
|
+
if (v === null || v === undefined)
|
|
5777
|
+
continue;
|
|
5778
|
+
const t = inferFieldType(v);
|
|
5779
|
+
const sig = typeSignature(t);
|
|
5780
|
+
if (elementType === null) {
|
|
5781
|
+
elementType = t;
|
|
5782
|
+
elementSig = sig;
|
|
5783
|
+
continue;
|
|
5784
|
+
}
|
|
5785
|
+
if (sig !== elementSig) {
|
|
5786
|
+
throw new Error(`inferFieldType: arrays in userState must be homogeneous; ` + `found both '${elementSig}' and '${sig}' in the same array ` + `(split the values into separate fields, or normalize them to one type)`);
|
|
5999
5787
|
}
|
|
6000
5788
|
}
|
|
6001
|
-
|
|
6002
|
-
|
|
6003
|
-
|
|
6004
|
-
|
|
6005
|
-
|
|
6006
|
-
|
|
5789
|
+
return elementType ?? emptyListElementType();
|
|
5790
|
+
}
|
|
5791
|
+
function inferFieldType(value) {
|
|
5792
|
+
if (value === null || value === undefined)
|
|
5793
|
+
return nullType2();
|
|
5794
|
+
switch (typeof value) {
|
|
5795
|
+
case "number":
|
|
5796
|
+
return float642();
|
|
5797
|
+
case "bigint":
|
|
5798
|
+
return int642();
|
|
5799
|
+
case "string":
|
|
5800
|
+
return utf82();
|
|
5801
|
+
case "boolean":
|
|
5802
|
+
return bool2();
|
|
5803
|
+
case "object":
|
|
5804
|
+
if (value instanceof Uint8Array || value instanceof ArrayBuffer)
|
|
5805
|
+
return binary2();
|
|
5806
|
+
if (ArrayBuffer.isView(value))
|
|
5807
|
+
return binary2();
|
|
5808
|
+
if (Array.isArray(value)) {
|
|
5809
|
+
return list2(field2(LIST_CHILD_NAME, inferElementType(value), true));
|
|
5810
|
+
}
|
|
5811
|
+
if (value instanceof Map) {
|
|
5812
|
+
throw new Error(`inferFieldType: Map is not supported in userState (use a plain object instead)`);
|
|
5813
|
+
}
|
|
5814
|
+
if (value instanceof Set) {
|
|
5815
|
+
throw new Error(`inferFieldType: Set is not supported in userState (use an array or plain object instead)`);
|
|
5816
|
+
}
|
|
5817
|
+
if (value instanceof Date) {
|
|
5818
|
+
throw new Error(`inferFieldType: Date is not supported in userState (use a number (epoch ms) or ISO string instead)`);
|
|
5819
|
+
}
|
|
5820
|
+
if (value instanceof RegExp) {
|
|
5821
|
+
throw new Error(`inferFieldType: RegExp is not supported in userState (use a string pattern instead)`);
|
|
5822
|
+
}
|
|
5823
|
+
const fields = Object.entries(value).map(([k, v]) => field2(k, inferFieldType(v), true));
|
|
5824
|
+
return struct2(fields);
|
|
5825
|
+
default:
|
|
5826
|
+
throw new Error(`inferFieldType: unsupported type '${typeof value}'`);
|
|
5827
|
+
}
|
|
5828
|
+
}
|
|
5829
|
+
function serializeUserState(userState) {
|
|
5830
|
+
if (userState == null)
|
|
5831
|
+
return null;
|
|
5832
|
+
const entries = Object.entries(userState);
|
|
5833
|
+
if (entries.length === 0) {
|
|
5834
|
+
return serializeBatch(batchFromColumns({}, schema2([])));
|
|
5835
|
+
}
|
|
5836
|
+
const fields = entries.map(([k, v]) => field2(k, inferFieldType(v), true));
|
|
5837
|
+
const sch = schema2(fields);
|
|
5838
|
+
const columns = {};
|
|
5839
|
+
for (const [key, val] of entries) {
|
|
5840
|
+
columns[key] = [val];
|
|
5841
|
+
}
|
|
5842
|
+
return serializeBatch(batchFromColumns(columns, sch));
|
|
5843
|
+
}
|
|
5844
|
+
function extractTypedValue(col, index, type) {
|
|
5845
|
+
return codecFor(type).canonicalToRich(readCanonicalValue(type, col, index));
|
|
5846
|
+
}
|
|
5847
|
+
function deserializeUserState(bytes) {
|
|
5848
|
+
if (bytes == null)
|
|
5849
|
+
return null;
|
|
5850
|
+
const batch = deserializeBatch(bytes);
|
|
5851
|
+
if (batch.numRows === 0 && batch.schema.fields.length === 0) {
|
|
5852
|
+
return {};
|
|
5853
|
+
}
|
|
5854
|
+
if (batch.numRows === 0)
|
|
5855
|
+
return null;
|
|
5856
|
+
const result = {};
|
|
5857
|
+
for (const f of batch.schema.fields) {
|
|
5858
|
+
const col = batch.getChild(f.name);
|
|
5859
|
+
if (!col) {
|
|
5860
|
+
result[f.name] = null;
|
|
5861
|
+
continue;
|
|
5862
|
+
}
|
|
5863
|
+
result[f.name] = extractTypedValue(col, 0, f.type);
|
|
5864
|
+
}
|
|
5865
|
+
return result;
|
|
5866
|
+
}
|
|
5867
|
+
var arrowStateSerializer = {
|
|
5868
|
+
serialize(state) {
|
|
5869
|
+
const functionName = TEXT_ENCODER.encode(state.functionName ?? "");
|
|
5870
|
+
const initRequest = state.initRequestPacked ?? packInitRequest(state.initRequestIpc);
|
|
5871
|
+
const executionId = toUint8Array(state.executionId);
|
|
5872
|
+
const opaqueData = state.opaqueData != null ? toUint8Array(state.opaqueData) : null;
|
|
5873
|
+
const userState = serializeUserState(state.userState);
|
|
5874
|
+
const filterHistory = encodeFilterHistory(state.filterHistory);
|
|
5875
|
+
const flags = (state.isProducer ? FLAG_PRODUCER : 0) | (opaqueData ? FLAG_OPAQUE_DATA : 0) | (userState ? FLAG_USER_STATE : 0) | (filterHistory ? FLAG_FILTER_HISTORY : 0);
|
|
5876
|
+
const chunks = [functionName, initRequest, executionId];
|
|
5877
|
+
if (opaqueData)
|
|
5878
|
+
chunks.push(opaqueData);
|
|
5879
|
+
if (userState)
|
|
5880
|
+
chunks.push(userState);
|
|
5881
|
+
if (filterHistory)
|
|
5882
|
+
chunks.push(filterHistory);
|
|
5883
|
+
let size = 2 + 8;
|
|
5884
|
+
for (const chunk of chunks)
|
|
5885
|
+
size += 4 + chunk.byteLength;
|
|
5886
|
+
const out = new Uint8Array(size);
|
|
5887
|
+
const view = new DataView(out.buffer);
|
|
5888
|
+
out[0] = STATE_FORMAT_VERSION;
|
|
5889
|
+
out[1] = flags;
|
|
5890
|
+
view.setFloat64(2, Number(state.maxWorkers ?? 1), true);
|
|
5891
|
+
let offset = 10;
|
|
5892
|
+
for (const chunk of chunks) {
|
|
5893
|
+
view.setUint32(offset, chunk.byteLength, true);
|
|
5894
|
+
out.set(chunk, offset + 4);
|
|
5895
|
+
offset += 4 + chunk.byteLength;
|
|
5896
|
+
}
|
|
5897
|
+
return out;
|
|
5898
|
+
},
|
|
5899
|
+
deserialize(bytes) {
|
|
5900
|
+
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
5901
|
+
if (bytes.byteLength < 10 || bytes[0] !== STATE_FORMAT_VERSION) {
|
|
5902
|
+
throw new Error("exchange state has an unknown format (minted by another build of this worker?)");
|
|
5903
|
+
}
|
|
5904
|
+
const flags = bytes[1];
|
|
5905
|
+
const maxWorkers = view.getFloat64(2, true);
|
|
5906
|
+
let offset = 10;
|
|
5907
|
+
const take = () => {
|
|
5908
|
+
if (offset + 4 > bytes.byteLength)
|
|
5909
|
+
throw new Error("exchange state is truncated");
|
|
5910
|
+
const length = view.getUint32(offset, true);
|
|
5911
|
+
offset += 4;
|
|
5912
|
+
if (offset + length > bytes.byteLength)
|
|
5913
|
+
throw new Error("exchange state is truncated");
|
|
5914
|
+
const chunk = bytes.slice(offset, offset + length);
|
|
5915
|
+
offset += length;
|
|
5916
|
+
return chunk;
|
|
5917
|
+
};
|
|
5918
|
+
const functionName = TEXT_DECODER.decode(take());
|
|
5919
|
+
const initRequestPacked = take();
|
|
5920
|
+
const executionId = take();
|
|
5921
|
+
const opaqueData = flags & FLAG_OPAQUE_DATA ? take() : null;
|
|
5922
|
+
const userStateBytes = flags & FLAG_USER_STATE ? take() : null;
|
|
5923
|
+
const filterHistoryBytes = flags & FLAG_FILTER_HISTORY ? take() : null;
|
|
5924
|
+
if (offset !== bytes.byteLength)
|
|
5925
|
+
throw new Error("exchange state has trailing bytes");
|
|
5926
|
+
const isProducer = (flags & FLAG_PRODUCER) !== 0;
|
|
5927
|
+
return {
|
|
5928
|
+
functionName,
|
|
5929
|
+
initRequestPacked,
|
|
5930
|
+
executionId,
|
|
5931
|
+
maxWorkers,
|
|
5932
|
+
opaqueData,
|
|
5933
|
+
isProducer,
|
|
5934
|
+
__isProducer: isProducer,
|
|
5935
|
+
userState: deserializeUserState(userStateBytes),
|
|
5936
|
+
filterHistory: decodeFilterHistory(filterHistoryBytes)
|
|
5937
|
+
};
|
|
5938
|
+
}
|
|
5939
|
+
};
|
|
5940
|
+
|
|
5941
|
+
// src/functions/table-in-out.ts
|
|
5942
|
+
var STREAMING_FINALIZE_KEY = new Uint8Array(0);
|
|
5943
|
+
function defineTableInOutFunction(config) {
|
|
5944
|
+
assertArrowTypes(config.args, `defineTableInOutFunction("${config.name}"): args`);
|
|
5945
|
+
const specs = [];
|
|
5946
|
+
let posIdx = 0;
|
|
5947
|
+
if (config.args) {
|
|
5948
|
+
for (const [name, type] of Object.entries(config.args)) {
|
|
5949
|
+
specs.push({
|
|
5950
|
+
name,
|
|
5951
|
+
position: posIdx++,
|
|
5952
|
+
arrowType: type,
|
|
5953
|
+
doc: config.argDocs?.[name],
|
|
5954
|
+
...constraintSpecFields(config.argConstraints?.[name], config.argDefaults?.[name])
|
|
5955
|
+
});
|
|
5956
|
+
}
|
|
5957
|
+
}
|
|
5958
|
+
specs.push({
|
|
5959
|
+
name: "data",
|
|
5960
|
+
position: posIdx++,
|
|
5961
|
+
arrowType: nullType2(),
|
|
5962
|
+
isTableInput: true
|
|
5963
|
+
});
|
|
5964
|
+
if (config.namedArgs) {
|
|
5965
|
+
for (const [name, type] of Object.entries(config.namedArgs)) {
|
|
5966
|
+
specs.push({
|
|
5967
|
+
name,
|
|
5968
|
+
position: name,
|
|
5969
|
+
arrowType: type,
|
|
5970
|
+
doc: config.argDocs?.[name],
|
|
5971
|
+
...constraintSpecFields(config.argConstraints?.[name], config.argDefaults?.[name])
|
|
5972
|
+
});
|
|
5973
|
+
}
|
|
5974
|
+
}
|
|
5975
|
+
const meta = {
|
|
5976
|
+
name: config.name,
|
|
5977
|
+
description: config.description,
|
|
5978
|
+
stability: config.stability,
|
|
5979
|
+
projectionPushdown: config.projectionPushdown,
|
|
5980
|
+
filterPushdown: config.filterPushdown,
|
|
5981
|
+
autoApplyFilters: config.autoApplyFilters,
|
|
5982
|
+
examples: config.examples,
|
|
5983
|
+
categories: config.categories,
|
|
5984
|
+
tags: config.tags,
|
|
5985
|
+
parameterDefaultValues: config.parameterDefaultValues,
|
|
5986
|
+
maxWorkers: config.maxWorkers,
|
|
5987
|
+
requiredSettings: config.requiredSettings,
|
|
5988
|
+
requiredSecrets: config.requiredSecrets,
|
|
5989
|
+
hasFinalize: !!config.finalize
|
|
5990
|
+
};
|
|
5991
|
+
function extractArgs(request) {
|
|
5992
|
+
const args = {};
|
|
5993
|
+
for (const spec of specs) {
|
|
5994
|
+
if (spec.isTableInput)
|
|
6007
5995
|
continue;
|
|
6008
|
-
|
|
6009
|
-
|
|
6010
|
-
|
|
5996
|
+
const defaultVal = config.argDefaults?.[spec.name] !== undefined ? config.argDefaults[spec.name] : undefined;
|
|
5997
|
+
let val = request.arguments.get(spec.position, defaultVal);
|
|
5998
|
+
val = narrowArgValue(val);
|
|
5999
|
+
const constraints = config.argConstraints?.[spec.name];
|
|
6000
|
+
if (constraints)
|
|
6001
|
+
validateConstConstraints(spec.name, constraints, val);
|
|
6002
|
+
args[spec.name] = val;
|
|
6011
6003
|
}
|
|
6004
|
+
return args;
|
|
6012
6005
|
}
|
|
6013
6006
|
return {
|
|
6014
|
-
|
|
6015
|
-
|
|
6016
|
-
|
|
6017
|
-
|
|
6018
|
-
|
|
6019
|
-
|
|
6020
|
-
|
|
6021
|
-
|
|
6022
|
-
|
|
6023
|
-
|
|
6024
|
-
|
|
6025
|
-
|
|
6026
|
-
|
|
6027
|
-
|
|
6028
|
-
|
|
6029
|
-
|
|
6030
|
-
|
|
6031
|
-
|
|
6032
|
-
|
|
6033
|
-
|
|
6034
|
-
|
|
6035
|
-
|
|
6036
|
-
|
|
6037
|
-
|
|
6038
|
-
|
|
6039
|
-
|
|
6007
|
+
kind: "table_in_out",
|
|
6008
|
+
meta,
|
|
6009
|
+
argumentSpecs: specs,
|
|
6010
|
+
async bind(request) {
|
|
6011
|
+
if (config.onBind) {
|
|
6012
|
+
const args = extractArgs(request);
|
|
6013
|
+
const settings = batchToScalarDict(request.settings);
|
|
6014
|
+
const secrets = batchToSecretDict(request.secrets);
|
|
6015
|
+
const result = await config.onBind({
|
|
6016
|
+
args,
|
|
6017
|
+
bindCall: request,
|
|
6018
|
+
settings,
|
|
6019
|
+
secrets,
|
|
6020
|
+
argumentNames: request.argument_names ?? null
|
|
6021
|
+
});
|
|
6022
|
+
return {
|
|
6023
|
+
output_schema: result.outputSchema,
|
|
6024
|
+
opaque_data: result.opaqueData ?? null
|
|
6025
|
+
};
|
|
6026
|
+
}
|
|
6027
|
+
return {
|
|
6028
|
+
output_schema: request.input_schema ?? schema2([]),
|
|
6029
|
+
opaque_data: null
|
|
6030
|
+
};
|
|
6031
|
+
},
|
|
6032
|
+
async globalInit(request) {
|
|
6033
|
+
const executionId = new Uint8Array(16);
|
|
6034
|
+
crypto.getRandomValues(executionId);
|
|
6035
|
+
if (request.execution_id) {
|
|
6036
|
+
return {
|
|
6037
|
+
max_workers: DEFAULT_MAX_WORKERS,
|
|
6038
|
+
execution_id: request.execution_id,
|
|
6039
|
+
opaque_data: null
|
|
6040
|
+
};
|
|
6041
|
+
}
|
|
6042
|
+
if (config.onInit) {
|
|
6043
|
+
const args = extractArgs(request.bind_call);
|
|
6044
|
+
return await config.onInit({
|
|
6045
|
+
args,
|
|
6046
|
+
initCall: request,
|
|
6047
|
+
outputSchema: request.output_schema,
|
|
6048
|
+
executionId
|
|
6049
|
+
});
|
|
6050
|
+
}
|
|
6051
|
+
return {
|
|
6052
|
+
max_workers: config.maxWorkers ?? 1,
|
|
6053
|
+
execution_id: executionId,
|
|
6054
|
+
opaque_data: null
|
|
6055
|
+
};
|
|
6056
|
+
},
|
|
6057
|
+
createStreamHandlers(request, response, filterHistory) {
|
|
6058
|
+
const args = extractArgs(request.bind_call);
|
|
6059
|
+
const settings = batchToScalarDict(request.bind_call.settings);
|
|
6060
|
+
const secrets = batchToSecretDict(request.bind_call.secrets);
|
|
6061
|
+
const projIds = request.projection_ids && meta.projectionPushdown ? request.projection_ids : null;
|
|
6062
|
+
const outputSchema = projIds ? projectSchema(projIds, request.output_schema) : request.output_schema;
|
|
6063
|
+
const carriedFilterHistory = filterHistory ?? EMPTY_FILTER_HISTORY;
|
|
6064
|
+
const pushdownFilters = replayFilterHistory(request.pushdown_filters ? deserializeFilters(request.pushdown_filters, {
|
|
6065
|
+
outputSchema: request.output_schema,
|
|
6066
|
+
joinKeyBatches: request.join_keys,
|
|
6067
|
+
extensionFunctions: meta.additionalFilterFunctions,
|
|
6068
|
+
runtimeAlgorithms: meta.runtimeFilterAlgorithms,
|
|
6069
|
+
evaluationContexts: meta.filterEvaluationContexts
|
|
6070
|
+
}) : undefined, carriedFilterHistory);
|
|
6071
|
+
const boundStorage = new BoundStorage(storage, response.execution_id ?? new Uint8Array(16), request.substream_id ?? null);
|
|
6072
|
+
const processParams = {
|
|
6073
|
+
args,
|
|
6074
|
+
initCall: request,
|
|
6075
|
+
initResponse: response,
|
|
6076
|
+
outputSchema,
|
|
6077
|
+
settings,
|
|
6078
|
+
secrets,
|
|
6079
|
+
pushdownFilters,
|
|
6080
|
+
storage: boundStorage,
|
|
6081
|
+
substreamId: request.substream_id ?? null
|
|
6082
|
+
};
|
|
6083
|
+
const phase = request.phase;
|
|
6084
|
+
if (phase === "FINALIZE" /* FINALIZE */) {
|
|
6085
|
+
const finalizeLogKey = STREAMING_FINALIZE_KEY;
|
|
6086
|
+
return {
|
|
6087
|
+
outputSchema,
|
|
6088
|
+
producerInit: () => ({ state: { cursor: -1, materialized: false } }),
|
|
6089
|
+
producerFn: async (pState, out) => {
|
|
6090
|
+
if (!pState.state.materialized) {
|
|
6091
|
+
const finalizeStates = [];
|
|
6092
|
+
const stored = await boundStorage.collect();
|
|
6093
|
+
for (const bytes of stored) {
|
|
6094
|
+
finalizeStates.push(deserializeUserState(bytes));
|
|
6095
|
+
}
|
|
6096
|
+
if (finalizeStates.length === 0) {
|
|
6097
|
+
finalizeStates.push(config.initialState ? config.initialState(processParams) : null);
|
|
6098
|
+
}
|
|
6099
|
+
const batches = config.finalize ? await config.finalize(processParams, finalizeStates) : [];
|
|
6100
|
+
for (const batch of batches) {
|
|
6101
|
+
await boundStorage.stateAppend(FrameworkNS.STREAMING_FINALIZE, finalizeLogKey, serializeBatch(batch));
|
|
6102
|
+
}
|
|
6103
|
+
pState.state.materialized = true;
|
|
6104
|
+
}
|
|
6105
|
+
const rows = await boundStorage.stateLogScan(FrameworkNS.STREAMING_FINALIZE, finalizeLogKey, pState.state.cursor, 1);
|
|
6106
|
+
if (rows.length === 0) {
|
|
6107
|
+
out.finish();
|
|
6108
|
+
return;
|
|
6109
|
+
}
|
|
6110
|
+
const [logId, bytes] = rows[0];
|
|
6111
|
+
out.emit(deserializeBatch(bytes));
|
|
6112
|
+
pState.state.cursor = logId;
|
|
6113
|
+
}
|
|
6114
|
+
};
|
|
6115
|
+
}
|
|
6116
|
+
if (request.bind_call.input_schema == null) {
|
|
6117
|
+
throw new Error(`${config.name}: is a table-in-out function (it requires an input row ` + `stream) but no input schema was supplied -- call it via ` + `table_in_out_function(input=...), not table_function().`);
|
|
6118
|
+
}
|
|
6119
|
+
const state = config.initialState ? config.initialState(processParams) : null;
|
|
6120
|
+
const processFn = config.process ?? ((_params, _state, batch, out) => {
|
|
6121
|
+
out.emit(projIds ? projectBatch(projIds, batch) : batch);
|
|
6122
|
+
});
|
|
6123
|
+
return {
|
|
6124
|
+
outputSchema,
|
|
6125
|
+
inputSchema: request.bind_call.input_schema,
|
|
6126
|
+
exchangeInit: () => ({ state, processParams, filterHistory: carriedFilterHistory }),
|
|
6127
|
+
exchangeFn: async (eState, input, out) => {
|
|
6128
|
+
applyRevalidationValidators(eState.processParams, input);
|
|
6129
|
+
applyDynamicFilterUpdate(eState, input);
|
|
6130
|
+
let wrappedOut = makeMetadataBakingCollector(out);
|
|
6131
|
+
if (projIds) {
|
|
6132
|
+
wrappedOut = makeSchemaReconcilingCollector(wrappedOut, outputSchema);
|
|
6133
|
+
}
|
|
6134
|
+
const currentFilters = eState.processParams.pushdownFilters;
|
|
6135
|
+
if (config.autoApplyFilters && currentFilters) {
|
|
6136
|
+
wrappedOut = new FilteringOutputCollector(wrappedOut, currentFilters);
|
|
6137
|
+
}
|
|
6138
|
+
await processFn(eState.processParams, eState.state, input, wrappedOut);
|
|
6139
|
+
if (eState.state != null) {
|
|
6140
|
+
const serialized = serializeUserState(eState.state);
|
|
6141
|
+
if (serialized != null) {
|
|
6142
|
+
await boundStorage.put(serialized);
|
|
6143
|
+
}
|
|
6144
|
+
}
|
|
6145
|
+
}
|
|
6146
|
+
};
|
|
6147
|
+
}
|
|
6040
6148
|
};
|
|
6041
6149
|
}
|
|
6042
|
-
function
|
|
6043
|
-
|
|
6044
|
-
|
|
6045
|
-
|
|
6150
|
+
function applyRevalidationValidators(params, input) {
|
|
6151
|
+
const md = input?.metadata;
|
|
6152
|
+
params.ifNoneMatch = md?.get(CACHE_IF_NONE_MATCH_KEY);
|
|
6153
|
+
params.ifModifiedSince = md?.get(CACHE_IF_MODIFIED_SINCE_KEY);
|
|
6046
6154
|
}
|
|
6047
|
-
function
|
|
6048
|
-
|
|
6049
|
-
|
|
6050
|
-
|
|
6051
|
-
|
|
6052
|
-
|
|
6053
|
-
|
|
6054
|
-
|
|
6055
|
-
|
|
6155
|
+
function applyDynamicFilterUpdate(eState, input) {
|
|
6156
|
+
const encoded = input?.metadata?.get("vgi_pushdown_filters");
|
|
6157
|
+
if (!encoded)
|
|
6158
|
+
return;
|
|
6159
|
+
const current = eState.processParams.pushdownFilters;
|
|
6160
|
+
if (!current)
|
|
6161
|
+
throw new Error("dynamic filter delta received without an initial snapshot");
|
|
6162
|
+
const recorded = recordFilterDelta(current, eState.filterHistory, decodeDynamicFilterMetadata(encoded));
|
|
6163
|
+
eState.processParams.pushdownFilters = recorded.filters;
|
|
6164
|
+
eState.filterHistory = recorded.history;
|
|
6056
6165
|
}
|
|
6057
|
-
function
|
|
6058
|
-
|
|
6059
|
-
|
|
6060
|
-
|
|
6061
|
-
|
|
6062
|
-
|
|
6063
|
-
|
|
6064
|
-
|
|
6065
|
-
|
|
6166
|
+
function makeMetadataBakingCollector(inner) {
|
|
6167
|
+
return new Proxy(inner, {
|
|
6168
|
+
get(target, prop, receiver) {
|
|
6169
|
+
if (prop === "emit") {
|
|
6170
|
+
return function(batchOrColumns, metadata) {
|
|
6171
|
+
if (batchOrColumns && typeof batchOrColumns.getChild === "function" && metadata && metadata.size > 0) {
|
|
6172
|
+
const batch = batchOrColumns;
|
|
6173
|
+
const merged = new Map(batch.metadata ?? []);
|
|
6174
|
+
for (const [k, v] of metadata)
|
|
6175
|
+
merged.set(k, v);
|
|
6176
|
+
return target.emit(withBatchMetadata(batch, merged), merged);
|
|
6177
|
+
}
|
|
6178
|
+
return target.emit(batchOrColumns, metadata);
|
|
6179
|
+
};
|
|
6180
|
+
}
|
|
6181
|
+
const v = Reflect.get(target, prop, receiver);
|
|
6182
|
+
return typeof v === "function" ? v.bind(target) : v;
|
|
6183
|
+
}
|
|
6184
|
+
});
|
|
6066
6185
|
}
|
|
6067
|
-
function
|
|
6068
|
-
|
|
6069
|
-
|
|
6070
|
-
|
|
6071
|
-
|
|
6072
|
-
|
|
6073
|
-
|
|
6074
|
-
|
|
6075
|
-
|
|
6076
|
-
|
|
6077
|
-
|
|
6186
|
+
function makeSchemaReconcilingCollector(inner, targetSchema) {
|
|
6187
|
+
function reconcile(batch) {
|
|
6188
|
+
const batchFields = batch.schema.fields;
|
|
6189
|
+
if (batchFields.length === targetSchema.fields.length && targetSchema.fields.every((f, i) => batchFields[i].name === f.name)) {
|
|
6190
|
+
return batch;
|
|
6191
|
+
}
|
|
6192
|
+
const ids = [];
|
|
6193
|
+
for (const f of targetSchema.fields) {
|
|
6194
|
+
const idx = batchFields.findIndex((bf) => bf.name === f.name);
|
|
6195
|
+
if (idx < 0) {
|
|
6196
|
+
throw new Error(`emitted batch is missing projected output column '${f.name}' ` + `(emitted: [${batchFields.map((bf) => bf.name).join(", ")}])`);
|
|
6197
|
+
}
|
|
6198
|
+
ids.push(idx);
|
|
6199
|
+
}
|
|
6200
|
+
return projectBatch(ids, batch);
|
|
6078
6201
|
}
|
|
6202
|
+
return new Proxy(inner, {
|
|
6203
|
+
get(target, prop, receiver) {
|
|
6204
|
+
if (prop === "emit") {
|
|
6205
|
+
return function(batchOrColumns, metadata) {
|
|
6206
|
+
if (batchOrColumns && typeof batchOrColumns.getChild === "function") {
|
|
6207
|
+
return target.emit(reconcile(batchOrColumns), metadata);
|
|
6208
|
+
}
|
|
6209
|
+
return target.emit(batchOrColumns, metadata);
|
|
6210
|
+
};
|
|
6211
|
+
}
|
|
6212
|
+
const v = Reflect.get(target, prop, receiver);
|
|
6213
|
+
return typeof v === "function" ? v.bind(target) : v;
|
|
6214
|
+
}
|
|
6215
|
+
});
|
|
6079
6216
|
}
|
|
6080
|
-
|
|
6081
|
-
|
|
6082
|
-
|
|
6083
|
-
|
|
6084
|
-
|
|
6085
|
-
|
|
6086
|
-
|
|
6087
|
-
|
|
6088
|
-
|
|
6089
|
-
|
|
6090
|
-
|
|
6091
|
-
|
|
6092
|
-
|
|
6093
|
-
|
|
6094
|
-
|
|
6095
|
-
|
|
6217
|
+
var PARENT_ROW_METADATA_KEY = "vgi_rpc.parent_row#b64";
|
|
6218
|
+
function parentRowsMetadata(parentRows, outputRows, extra) {
|
|
6219
|
+
if (parentRows.length !== outputRows) {
|
|
6220
|
+
throw new Error(`parentRowsMetadata: length ${parentRows.length} != output rows ${outputRows}; ` + `parentRows must carry exactly one input-row index per emitted output row`);
|
|
6221
|
+
}
|
|
6222
|
+
const md = new Map(extra ?? []);
|
|
6223
|
+
if (outputRows === 0) {
|
|
6224
|
+
return md;
|
|
6225
|
+
}
|
|
6226
|
+
const raw = new Uint8Array(parentRows.length * 4);
|
|
6227
|
+
const dv = new DataView(raw.buffer);
|
|
6228
|
+
for (let i = 0;i < parentRows.length; i++) {
|
|
6229
|
+
dv.setInt32(i * 4, parentRows[i], true);
|
|
6230
|
+
}
|
|
6231
|
+
md.set(PARENT_ROW_METADATA_KEY, base64Encode(raw));
|
|
6232
|
+
return md;
|
|
6096
6233
|
}
|
|
6097
|
-
function
|
|
6098
|
-
|
|
6099
|
-
|
|
6100
|
-
|
|
6101
|
-
|
|
6102
|
-
|
|
6234
|
+
function base64Encode(bytes) {
|
|
6235
|
+
if (typeof globalThis.Buffer !== "undefined") {
|
|
6236
|
+
return globalThis.Buffer.from(bytes).toString("base64");
|
|
6237
|
+
}
|
|
6238
|
+
let bin = "";
|
|
6239
|
+
for (let i = 0;i < bytes.length; i++)
|
|
6240
|
+
bin += String.fromCharCode(bytes[i]);
|
|
6241
|
+
return globalThis.btoa(bin);
|
|
6103
6242
|
}
|
|
6104
|
-
|
|
6105
|
-
|
|
6106
|
-
|
|
6107
|
-
|
|
6108
|
-
|
|
6109
|
-
]
|
|
6110
|
-
|
|
6111
|
-
|
|
6112
|
-
|
|
6113
|
-
|
|
6114
|
-
|
|
6115
|
-
|
|
6116
|
-
|
|
6117
|
-
|
|
6243
|
+
function defineRowTransformFunction(config) {
|
|
6244
|
+
const numPositional = Object.keys(config.args ?? {}).length + (config.varargs ? 1 : 0);
|
|
6245
|
+
if (numPositional === 0) {
|
|
6246
|
+
throw new Error(`${config.name}: a blended row-transform function needs at least one ` + `positional arg (its per-row input column); found none.`);
|
|
6247
|
+
}
|
|
6248
|
+
const specs = [];
|
|
6249
|
+
let posIdx = 0;
|
|
6250
|
+
if (config.args) {
|
|
6251
|
+
for (const [name, type] of Object.entries(config.args)) {
|
|
6252
|
+
const isAny = isNull(type);
|
|
6253
|
+
specs.push({
|
|
6254
|
+
name,
|
|
6255
|
+
position: posIdx++,
|
|
6256
|
+
arrowType: isAny ? nullType2() : type,
|
|
6257
|
+
isAnyType: isAny,
|
|
6258
|
+
doc: config.argDocs?.[name],
|
|
6259
|
+
...constraintSpecFields(config.argConstraints?.[name])
|
|
6260
|
+
});
|
|
6261
|
+
}
|
|
6262
|
+
}
|
|
6263
|
+
if (config.varargs) {
|
|
6264
|
+
const isAny = isNull(config.varargs.type);
|
|
6265
|
+
specs.push({
|
|
6266
|
+
name: config.varargs.name,
|
|
6267
|
+
position: posIdx++,
|
|
6268
|
+
arrowType: isAny ? nullType2() : config.varargs.type,
|
|
6269
|
+
isAnyType: isAny,
|
|
6270
|
+
isVarargs: true,
|
|
6271
|
+
doc: config.varargs.doc ?? config.argDocs?.[config.varargs.name],
|
|
6272
|
+
...constraintSpecFields(config.argConstraints?.[config.varargs.name])
|
|
6273
|
+
});
|
|
6274
|
+
}
|
|
6275
|
+
if (config.namedArgs) {
|
|
6276
|
+
for (const [name, type] of Object.entries(config.namedArgs)) {
|
|
6277
|
+
specs.push({
|
|
6278
|
+
name,
|
|
6279
|
+
position: name,
|
|
6280
|
+
arrowType: type,
|
|
6281
|
+
doc: config.argDocs?.[name],
|
|
6282
|
+
...constraintSpecFields(config.argConstraints?.[name], config.argDefaults?.[name])
|
|
6283
|
+
});
|
|
6284
|
+
}
|
|
6285
|
+
}
|
|
6286
|
+
const meta = {
|
|
6287
|
+
name: config.name,
|
|
6288
|
+
description: config.description,
|
|
6289
|
+
stability: config.stability,
|
|
6290
|
+
projectionPushdown: config.projectionPushdown,
|
|
6291
|
+
filterPushdown: config.filterPushdown,
|
|
6292
|
+
autoApplyFilters: config.autoApplyFilters,
|
|
6293
|
+
examples: config.examples,
|
|
6294
|
+
categories: config.categories,
|
|
6295
|
+
tags: config.tags,
|
|
6296
|
+
parameterDefaultValues: config.parameterDefaultValues,
|
|
6297
|
+
maxWorkers: config.maxWorkers,
|
|
6298
|
+
requiredSettings: config.requiredSettings,
|
|
6299
|
+
requiredSecrets: config.requiredSecrets,
|
|
6300
|
+
hasFinalize: false,
|
|
6301
|
+
inputFromArgs: true
|
|
6118
6302
|
};
|
|
6119
|
-
|
|
6120
|
-
|
|
6303
|
+
function extractArgs(request) {
|
|
6304
|
+
const args = {};
|
|
6305
|
+
for (const spec of specs) {
|
|
6306
|
+
if (typeof spec.position !== "string")
|
|
6307
|
+
continue;
|
|
6308
|
+
const defaultVal = config.argDefaults?.[spec.name] !== undefined ? config.argDefaults[spec.name] : undefined;
|
|
6309
|
+
let val = request.arguments.get(spec.position, defaultVal ?? null);
|
|
6310
|
+
val = narrowArgValue(val);
|
|
6311
|
+
const constraints = config.argConstraints?.[spec.name];
|
|
6312
|
+
if (constraints)
|
|
6313
|
+
validateConstConstraints(spec.name, constraints, val);
|
|
6314
|
+
args[spec.name] = val;
|
|
6315
|
+
}
|
|
6316
|
+
return args;
|
|
6317
|
+
}
|
|
6121
6318
|
return {
|
|
6122
|
-
|
|
6123
|
-
|
|
6319
|
+
kind: "table_in_out",
|
|
6320
|
+
meta,
|
|
6321
|
+
argumentSpecs: specs,
|
|
6322
|
+
async bind(request) {
|
|
6323
|
+
const args = extractArgs(request);
|
|
6324
|
+
const settings = batchToScalarDict(request.settings);
|
|
6325
|
+
const secrets = batchToSecretDict(request.secrets);
|
|
6326
|
+
const result = await config.onBind({
|
|
6327
|
+
args,
|
|
6328
|
+
bindCall: request,
|
|
6329
|
+
settings,
|
|
6330
|
+
secrets,
|
|
6331
|
+
argumentNames: request.argument_names ?? null
|
|
6332
|
+
});
|
|
6333
|
+
return {
|
|
6334
|
+
output_schema: result.outputSchema,
|
|
6335
|
+
opaque_data: result.opaqueData ?? null
|
|
6336
|
+
};
|
|
6337
|
+
},
|
|
6338
|
+
async globalInit(request) {
|
|
6339
|
+
if (request.execution_id) {
|
|
6340
|
+
return {
|
|
6341
|
+
max_workers: DEFAULT_MAX_WORKERS,
|
|
6342
|
+
execution_id: request.execution_id,
|
|
6343
|
+
opaque_data: null
|
|
6344
|
+
};
|
|
6345
|
+
}
|
|
6346
|
+
const executionId = new Uint8Array(16);
|
|
6347
|
+
crypto.getRandomValues(executionId);
|
|
6348
|
+
return {
|
|
6349
|
+
max_workers: config.maxWorkers ?? 1,
|
|
6350
|
+
execution_id: executionId,
|
|
6351
|
+
opaque_data: null
|
|
6352
|
+
};
|
|
6353
|
+
},
|
|
6354
|
+
createStreamHandlers(request, response, filterHistory) {
|
|
6355
|
+
const args = extractArgs(request.bind_call);
|
|
6356
|
+
const settings = batchToScalarDict(request.bind_call.settings);
|
|
6357
|
+
const secrets = batchToSecretDict(request.bind_call.secrets);
|
|
6358
|
+
const projIds = request.projection_ids && meta.projectionPushdown ? request.projection_ids : null;
|
|
6359
|
+
const outputSchema = projIds ? projectSchema(projIds, request.output_schema) : request.output_schema;
|
|
6360
|
+
const carriedFilterHistory = filterHistory ?? EMPTY_FILTER_HISTORY;
|
|
6361
|
+
const pushdownFilters = replayFilterHistory(request.pushdown_filters ? deserializeFilters(request.pushdown_filters, {
|
|
6362
|
+
outputSchema: request.output_schema,
|
|
6363
|
+
joinKeyBatches: request.join_keys,
|
|
6364
|
+
extensionFunctions: meta.additionalFilterFunctions,
|
|
6365
|
+
runtimeAlgorithms: meta.runtimeFilterAlgorithms,
|
|
6366
|
+
evaluationContexts: meta.filterEvaluationContexts
|
|
6367
|
+
}) : undefined, carriedFilterHistory);
|
|
6368
|
+
const boundStorage = new BoundStorage(storage, response.execution_id ?? new Uint8Array(16), request.substream_id ?? null);
|
|
6369
|
+
const processParams = {
|
|
6370
|
+
args,
|
|
6371
|
+
initCall: request,
|
|
6372
|
+
initResponse: response,
|
|
6373
|
+
outputSchema,
|
|
6374
|
+
settings,
|
|
6375
|
+
secrets,
|
|
6376
|
+
pushdownFilters,
|
|
6377
|
+
storage: boundStorage,
|
|
6378
|
+
substreamId: request.substream_id ?? null
|
|
6379
|
+
};
|
|
6380
|
+
if (request.phase === "FINALIZE" /* FINALIZE */) {
|
|
6381
|
+
throw new Error(`${config.name}: a blended row-transform function has no FINALIZE ` + `phase (it is a per-row map; has_finalize is advertised false).`);
|
|
6382
|
+
}
|
|
6383
|
+
if (request.bind_call.input_schema == null) {
|
|
6384
|
+
throw new Error(`${config.name}: is a table-in-out function (its positional args are ` + `per-row input columns) but no input schema was supplied -- call it ` + `via table_in_out_function(input=...), not table_function().`);
|
|
6385
|
+
}
|
|
6386
|
+
return {
|
|
6387
|
+
outputSchema,
|
|
6388
|
+
inputSchema: request.bind_call.input_schema,
|
|
6389
|
+
exchangeInit: () => ({ state: null, processParams, filterHistory: carriedFilterHistory }),
|
|
6390
|
+
exchangeFn: async (eState, input, out) => {
|
|
6391
|
+
applyRevalidationValidators(eState.processParams, input);
|
|
6392
|
+
applyDynamicFilterUpdate(eState, input);
|
|
6393
|
+
let wrappedOut = makeMetadataBakingCollector(out);
|
|
6394
|
+
if (projIds) {
|
|
6395
|
+
wrappedOut = makeSchemaReconcilingCollector(wrappedOut, outputSchema);
|
|
6396
|
+
}
|
|
6397
|
+
const currentFilters = eState.processParams.pushdownFilters;
|
|
6398
|
+
if (config.autoApplyFilters && currentFilters) {
|
|
6399
|
+
wrappedOut = new FilteringOutputCollector(wrappedOut, currentFilters);
|
|
6400
|
+
}
|
|
6401
|
+
await config.process(eState.processParams, input, wrappedOut);
|
|
6402
|
+
}
|
|
6403
|
+
};
|
|
6404
|
+
}
|
|
6124
6405
|
};
|
|
6125
6406
|
}
|
|
6126
6407
|
// src/functions/table-buffering.ts
|
|
6408
|
+
init_arrow();
|
|
6409
|
+
init_arrow();
|
|
6410
|
+
init_registry();
|
|
6411
|
+
init_storage();
|
|
6127
6412
|
function defineTableBufferingFunction(config) {
|
|
6128
6413
|
assertArrowTypes(config.args, `defineTableBufferingFunction("${config.name}"): args`);
|
|
6129
6414
|
if (config.sinkOrderDependent && config.requiresInputBatchIndex) {
|
|
@@ -6245,7 +6530,7 @@ function defineTableBufferingFunction(config) {
|
|
|
6245
6530
|
}
|
|
6246
6531
|
return response;
|
|
6247
6532
|
},
|
|
6248
|
-
createStreamHandlers(request, response
|
|
6533
|
+
createStreamHandlers(request, response) {
|
|
6249
6534
|
const args = extractArgs(request.bind_call);
|
|
6250
6535
|
const settings = batchToScalarDict(request.bind_call.settings);
|
|
6251
6536
|
const secrets = batchToSecretDict(request.bind_call.secrets);
|
|
@@ -8217,12 +8502,41 @@ function validateRequiredAttachOptions(catalogName, specs, options) {
|
|
|
8217
8502
|
}
|
|
8218
8503
|
}
|
|
8219
8504
|
|
|
8505
|
+
// src/catalog/item-encoding.ts
|
|
8506
|
+
var ENCODED = new WeakMap;
|
|
8507
|
+
function freezeCatalogItem(item) {
|
|
8508
|
+
deepFreeze(item);
|
|
8509
|
+
return item;
|
|
8510
|
+
}
|
|
8511
|
+
function deepFreeze(value) {
|
|
8512
|
+
if (value === null || typeof value !== "object" || Object.isFrozen(value) || ArrayBuffer.isView(value))
|
|
8513
|
+
return;
|
|
8514
|
+
const proto = Object.getPrototypeOf(value);
|
|
8515
|
+
if (proto !== Object.prototype && proto !== Array.prototype && proto !== null)
|
|
8516
|
+
return;
|
|
8517
|
+
for (const child of Object.values(value))
|
|
8518
|
+
deepFreeze(child);
|
|
8519
|
+
Object.freeze(value);
|
|
8520
|
+
}
|
|
8521
|
+
function encodeFunctionInfoOnce(info) {
|
|
8522
|
+
if (!Object.isFrozen(info))
|
|
8523
|
+
return encodeFunctionInfo(info);
|
|
8524
|
+
let encoded = ENCODED.get(info);
|
|
8525
|
+
if (encoded === undefined) {
|
|
8526
|
+
encoded = encodeFunctionInfo(info);
|
|
8527
|
+
ENCODED.set(info, encoded);
|
|
8528
|
+
}
|
|
8529
|
+
return encoded;
|
|
8530
|
+
}
|
|
8531
|
+
|
|
8220
8532
|
// src/catalog/read-only.ts
|
|
8221
8533
|
class ReadOnlyCatalogInterface extends CatalogInterface {
|
|
8222
8534
|
_descriptor;
|
|
8223
8535
|
_registry;
|
|
8224
8536
|
_attachments = new Map;
|
|
8225
8537
|
_version = 1;
|
|
8538
|
+
_functionListings = new Map;
|
|
8539
|
+
_functionInfos = new Map;
|
|
8226
8540
|
constructor(descriptor, registry) {
|
|
8227
8541
|
super();
|
|
8228
8542
|
this._descriptor = descriptor;
|
|
@@ -8288,7 +8602,7 @@ class ReadOnlyCatalogInterface extends CatalogInterface {
|
|
|
8288
8602
|
comment: this._descriptor.comment ?? null,
|
|
8289
8603
|
tags: this._descriptor.tags ?? {},
|
|
8290
8604
|
supports_column_statistics: true,
|
|
8291
|
-
global_functions: this._globalFunctionInfos().map(
|
|
8605
|
+
global_functions: this._globalFunctionInfos().map(encodeFunctionInfoOnce),
|
|
8292
8606
|
global_function_prefix: this._descriptor.globalFunctionPrefix ?? "",
|
|
8293
8607
|
resolved_data_version: null,
|
|
8294
8608
|
resolved_implementation_version: null
|
|
@@ -8464,16 +8778,35 @@ class ReadOnlyCatalogInterface extends CatalogInterface {
|
|
|
8464
8778
|
const schema = this._descriptor.schemas.find((s) => schemaPathsEqual(schemaDescriptorPath(s), path));
|
|
8465
8779
|
if (!schema || !schema.functions)
|
|
8466
8780
|
return [];
|
|
8467
|
-
|
|
8468
|
-
|
|
8469
|
-
|
|
8470
|
-
|
|
8471
|
-
|
|
8472
|
-
|
|
8473
|
-
|
|
8474
|
-
|
|
8475
|
-
|
|
8476
|
-
}
|
|
8781
|
+
const kind = functionListingKind(type);
|
|
8782
|
+
const canonicalPath = schemaDescriptorPath(schema);
|
|
8783
|
+
if (!sameSpelling(path, canonicalPath)) {
|
|
8784
|
+
return schema.functions.filter((f) => inListing(f, kind)).map((f) => this._functionToInfo(f, path));
|
|
8785
|
+
}
|
|
8786
|
+
let listings = this._functionListings.get(schema);
|
|
8787
|
+
if (!listings) {
|
|
8788
|
+
listings = new Map;
|
|
8789
|
+
this._functionListings.set(schema, listings);
|
|
8790
|
+
}
|
|
8791
|
+
let listing = listings.get(kind);
|
|
8792
|
+
if (!listing) {
|
|
8793
|
+
listing = Object.freeze(schema.functions.filter((f) => inListing(f, kind)).map((f) => this._sharedFunctionInfo(schema, f)));
|
|
8794
|
+
listings.set(kind, listing);
|
|
8795
|
+
}
|
|
8796
|
+
return listing.slice();
|
|
8797
|
+
}
|
|
8798
|
+
_sharedFunctionInfo(schema, f) {
|
|
8799
|
+
let infos = this._functionInfos.get(schema);
|
|
8800
|
+
if (!infos) {
|
|
8801
|
+
infos = new Map;
|
|
8802
|
+
this._functionInfos.set(schema, infos);
|
|
8803
|
+
}
|
|
8804
|
+
let info = infos.get(f);
|
|
8805
|
+
if (!info) {
|
|
8806
|
+
info = freezeCatalogItem(structuredClone(this._functionToInfo(f, schemaDescriptorPath(schema))));
|
|
8807
|
+
infos.set(f, info);
|
|
8808
|
+
}
|
|
8809
|
+
return info;
|
|
8477
8810
|
}
|
|
8478
8811
|
_functionToInfo(f, path) {
|
|
8479
8812
|
const meta = resolveMetadata(f);
|
|
@@ -8574,15 +8907,15 @@ class ReadOnlyCatalogInterface extends CatalogInterface {
|
|
|
8574
8907
|
for (const sch of this._descriptor.schemas) {
|
|
8575
8908
|
for (const fn of sch.functions ?? []) {
|
|
8576
8909
|
if (!schemaOf.has(fn))
|
|
8577
|
-
schemaOf.set(fn,
|
|
8910
|
+
schemaOf.set(fn, sch);
|
|
8578
8911
|
}
|
|
8579
8912
|
}
|
|
8580
8913
|
return globals.map((fn) => {
|
|
8581
|
-
const
|
|
8582
|
-
if (
|
|
8914
|
+
const schema = schemaOf.get(fn);
|
|
8915
|
+
if (schema === undefined) {
|
|
8583
8916
|
throw new Error(`Catalog '${this._descriptor.name}': '${fn.meta.name}' is listed in ` + `globalFunctions but is not declared in any schema.`);
|
|
8584
8917
|
}
|
|
8585
|
-
return this.
|
|
8918
|
+
return this._sharedFunctionInfo(schema, fn);
|
|
8586
8919
|
});
|
|
8587
8920
|
}
|
|
8588
8921
|
schemaContentsMacros(attachOpaqueData, path, type, transactionOpaqueData) {
|
|
@@ -8895,6 +9228,24 @@ function inlineScanFunction(func, args, schemaPath) {
|
|
|
8895
9228
|
const argBytes = serializeArgsBatch(args ?? new Arguments, argSchema);
|
|
8896
9229
|
return encodeScanFunctionResult(func.meta.name, argBytes, [], schemaPath);
|
|
8897
9230
|
}
|
|
9231
|
+
function functionListingKind(type) {
|
|
9232
|
+
const t = String(type ?? "").toUpperCase();
|
|
9233
|
+
return t === "SCALAR_FUNCTION" || t === "TABLE_FUNCTION" || t === "AGGREGATE_FUNCTION" ? t : "ALL";
|
|
9234
|
+
}
|
|
9235
|
+
function inListing(f, kind) {
|
|
9236
|
+
if (kind === "SCALAR_FUNCTION")
|
|
9237
|
+
return f.kind === "scalar";
|
|
9238
|
+
if (kind === "TABLE_FUNCTION")
|
|
9239
|
+
return f.kind === "table" || f.kind === "table_in_out" || f.kind === "table_buffering";
|
|
9240
|
+
if (kind === "AGGREGATE_FUNCTION")
|
|
9241
|
+
return f.kind === "aggregate";
|
|
9242
|
+
return true;
|
|
9243
|
+
}
|
|
9244
|
+
function sameSpelling(left, right) {
|
|
9245
|
+
const a = normalizeSchemaPath(left);
|
|
9246
|
+
const b = normalizeSchemaPath(right);
|
|
9247
|
+
return a.length === b.length && a.every((part, i) => part === b[i]);
|
|
9248
|
+
}
|
|
8898
9249
|
// src/catalog/composite.ts
|
|
8899
9250
|
var ROUTE_BYTE = 0;
|
|
8900
9251
|
|
|
@@ -9569,17 +9920,6 @@ function overloadContext(req, catalogInterface) {
|
|
|
9569
9920
|
catalogName
|
|
9570
9921
|
};
|
|
9571
9922
|
}
|
|
9572
|
-
function recoverFinalizeState(request, recoverExchangeState) {
|
|
9573
|
-
if (request.phase === "FINALIZE" /* FINALIZE */ && request.init_opaque_data && recoverExchangeState) {
|
|
9574
|
-
try {
|
|
9575
|
-
const recovered = recoverExchangeState(request.init_opaque_data);
|
|
9576
|
-
return recovered?.userState;
|
|
9577
|
-
} catch (e) {
|
|
9578
|
-
throw new Error(`Failed to recover FINALIZE state from init_opaque_data: ${e.message}`);
|
|
9579
|
-
}
|
|
9580
|
-
}
|
|
9581
|
-
return;
|
|
9582
|
-
}
|
|
9583
9923
|
|
|
9584
9924
|
// src/protocol/handlers/catalog/shared.ts
|
|
9585
9925
|
init_arrow();
|
|
@@ -10722,8 +11062,7 @@ function registerFunctionMethods(protocol, config) {
|
|
|
10722
11062
|
});
|
|
10723
11063
|
const func = registry.get(request.bind_call.function_name, overloadContext(request.bind_call, catalogInterface));
|
|
10724
11064
|
const initResponse = await func.globalInit(request);
|
|
10725
|
-
const
|
|
10726
|
-
const handlers = func.createStreamHandlers(request, initResponse, accumulatedState);
|
|
11065
|
+
const handlers = func.createStreamHandlers(request, initResponse);
|
|
10727
11066
|
let handlerState;
|
|
10728
11067
|
if (handlers.producerInit) {
|
|
10729
11068
|
handlerState = handlers.producerInit();
|
|
@@ -10757,10 +11096,9 @@ function registerFunctionMethods(protocol, config) {
|
|
|
10757
11096
|
handlers = state._handlers;
|
|
10758
11097
|
handlerState = state._handlerState;
|
|
10759
11098
|
} else {
|
|
10760
|
-
const
|
|
10761
|
-
const
|
|
10762
|
-
|
|
10763
|
-
await resolveSplitPayloads(request, { bind_call: initRequestDict.bind_call }, {
|
|
11099
|
+
const carried = parseCarriedInitRequest(state.initRequestPacked);
|
|
11100
|
+
const request = carried.request;
|
|
11101
|
+
await resolveSplitPayloads(request, { bind_call: carried.bindCallIpc }, {
|
|
10764
11102
|
auth: currentRequestAuth(),
|
|
10765
11103
|
signingKey,
|
|
10766
11104
|
catalogInterface,
|
|
@@ -10774,8 +11112,7 @@ function registerFunctionMethods(protocol, config) {
|
|
|
10774
11112
|
max_workers: Number(state.maxWorkers ?? 1),
|
|
10775
11113
|
opaque_data: opaqueData
|
|
10776
11114
|
};
|
|
10777
|
-
|
|
10778
|
-
handlers = func.createStreamHandlers(request, initResponse, recoveredState);
|
|
11115
|
+
handlers = func.createStreamHandlers(request, initResponse, state.filterHistory ?? null);
|
|
10779
11116
|
if (handlers.producerInit) {
|
|
10780
11117
|
handlerState = handlers.producerInit();
|
|
10781
11118
|
} else if (handlers.exchangeInit) {
|
|
@@ -10799,6 +11136,7 @@ function registerFunctionMethods(protocol, config) {
|
|
|
10799
11136
|
if (handlerState?.state !== undefined) {
|
|
10800
11137
|
state.userState = handlerState.state;
|
|
10801
11138
|
}
|
|
11139
|
+
state.filterHistory = handlerState?.filterHistory ?? null;
|
|
10802
11140
|
},
|
|
10803
11141
|
headerSchema: initHeaderSchema,
|
|
10804
11142
|
headerInit: (params, state, ctx) => {
|
|
@@ -11465,7 +11803,7 @@ function registerCatalogAdminMethods(protocol, getCatalog, signingKey) {
|
|
|
11465
11803
|
const cat = getCatalog();
|
|
11466
11804
|
const funcs = await cat.schemaContentsFunctions(toUint8Array(params.attach_opaque_data), params.path, decodeDictValue(params.type), params.transaction_opaque_data ? toUint8Array(params.transaction_opaque_data) : undefined);
|
|
11467
11805
|
return wrapResult({
|
|
11468
|
-
items: funcs.map((f) =>
|
|
11806
|
+
items: funcs.map((f) => encodeFunctionInfoOnce(f))
|
|
11469
11807
|
}, CatalogSchemaContentsFunctionsResultSchema);
|
|
11470
11808
|
}
|
|
11471
11809
|
});
|
|
@@ -11754,11 +12092,11 @@ function registerCatalogMethods(protocol, catalog, _catalogName, signingKey) {
|
|
|
11754
12092
|
}
|
|
11755
12093
|
|
|
11756
12094
|
// src/protocol/dispatch.ts
|
|
12095
|
+
var VGI_PROTOCOL_NAME = "vgi.v2";
|
|
11757
12096
|
function buildVgiProtocol(config) {
|
|
11758
|
-
const protocol = new Protocol(
|
|
12097
|
+
const protocol = new Protocol(VGI_PROTOCOL_NAME, { protocolVersion: "2.0.0" });
|
|
11759
12098
|
registerFunctionMethods(protocol, {
|
|
11760
12099
|
registry: config.registry,
|
|
11761
|
-
recoverExchangeState: config.recoverExchangeState,
|
|
11762
12100
|
signingKey: config.signingKey,
|
|
11763
12101
|
catalogInterface: config.catalogInterface
|
|
11764
12102
|
});
|
|
@@ -12016,6 +12354,24 @@ function wrapRpcWithErrorEnrichment(rpc) {
|
|
|
12016
12354
|
throw e;
|
|
12017
12355
|
}
|
|
12018
12356
|
},
|
|
12357
|
+
async callRaw(method, input) {
|
|
12358
|
+
try {
|
|
12359
|
+
return await rpc.callRaw(method, input);
|
|
12360
|
+
} catch (e) {
|
|
12361
|
+
if (e instanceof RpcError)
|
|
12362
|
+
throw VgiClientError.fromRpcError(e);
|
|
12363
|
+
throw e;
|
|
12364
|
+
}
|
|
12365
|
+
},
|
|
12366
|
+
async streamRaw(method, input, options) {
|
|
12367
|
+
try {
|
|
12368
|
+
return await rpc.streamRaw(method, input, options);
|
|
12369
|
+
} catch (e) {
|
|
12370
|
+
if (e instanceof RpcError)
|
|
12371
|
+
throw VgiClientError.fromRpcError(e);
|
|
12372
|
+
throw e;
|
|
12373
|
+
}
|
|
12374
|
+
},
|
|
12019
12375
|
describe: () => rpc.describe(),
|
|
12020
12376
|
close: () => rpc.close()
|
|
12021
12377
|
};
|
|
@@ -13197,4 +13553,4 @@ export {
|
|
|
13197
13553
|
utf82 as utf8
|
|
13198
13554
|
};
|
|
13199
13555
|
|
|
13200
|
-
//# debugId=
|
|
13556
|
+
//# debugId=D343450F0C99C4DF64756E2164756E21
|