@amritk/nish-aarch64-darwin 0.26.0 → 0.27.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/nish +0 -0
- package/docs/AI.md +8 -3
- package/package.json +1 -1
- package/runtime/nish.d.ts +5 -5
- package/runtime/nish.h +17 -3
- package/runtime/runtime-os.c +9 -4
- package/runtime/runtime-simd.c +63 -2
- package/runtime/runtime-wasm.c +18 -0
- package/scripts/build.sh +16 -1
- package/std/README.md +2 -1
- package/std/crypto/sha256.ts +335 -188
- package/std/net/http-client.ts +1645 -0
- package/std/net/postgres.ts +171 -8
package/std/net/postgres.ts
CHANGED
|
@@ -81,7 +81,11 @@
|
|
|
81
81
|
* A `text` column is the same bytes in either format, so `columnText` and the
|
|
82
82
|
* column windows read it unchanged. The program knows which of its binds
|
|
83
83
|
* asked for which, and reads each execution's rows with the matching
|
|
84
|
-
* decoders.
|
|
84
|
+
* decoders. A `PgBatcher` with `binary` set opens each batch this way and
|
|
85
|
+
* reads its routing ordinal with `binaryInt`, so its rows are binary too.
|
|
86
|
+
* `PgBinaryArray` walks a one-dimensional `int2[]`, `int4[]` or `int8[]`
|
|
87
|
+
* column in its binary layout, and refuses any other array (a `text[]` or a
|
|
88
|
+
* multi-dimensional one among them).
|
|
85
89
|
*
|
|
86
90
|
* **Authentication.** SCRAM-SHA-256 (RFC 5802, RFC 7677) or none (`trust`).
|
|
87
91
|
* The password arrives as a `Secret<u8[]>`; the connection keeps a copy in a
|
|
@@ -237,6 +241,15 @@ const PG_TAIL: i32 = 17
|
|
|
237
241
|
const PG_BINARY_TAIL: i32 = 2
|
|
238
242
|
// The result format code for binary.
|
|
239
243
|
const PG_FORMAT_BINARY: i32 = 1
|
|
244
|
+
// The element types `PgBinaryArray` reads, by OID: int8, int2 and int4.
|
|
245
|
+
const PG_OID_INT8: i32 = 20
|
|
246
|
+
const PG_OID_INT2: i32 = 21
|
|
247
|
+
const PG_OID_INT4: i32 = 23
|
|
248
|
+
// The bytes a binary array's header takes before its dimensions: ndim,
|
|
249
|
+
// hasnull and the element OID, one i32 each; one dimension adds its length
|
|
250
|
+
// and lower bound, another two i32s.
|
|
251
|
+
const PG_ARRAY_HEADER: i32 = 12
|
|
252
|
+
const PG_ARRAY_DIM: i32 = 8
|
|
240
253
|
// The largest `maxMessage` and `maxOutput`. The input buffer doubles up to one
|
|
241
254
|
// past them; the output buffer doubles only while twice its size fits in an i32.
|
|
242
255
|
const PG_MAX_CAP: i32 = 1073741823
|
|
@@ -858,6 +871,139 @@ export class PgBinary {
|
|
|
858
871
|
}
|
|
859
872
|
}
|
|
860
873
|
|
|
874
|
+
/**
|
|
875
|
+
* A walk over a one-dimensional `int2[]`, `int4[]` or `int8[]` column in
|
|
876
|
+
* PostgreSQL's binary array layout, in place: `begin` the column, then
|
|
877
|
+
* `next()` until `PG_ARRAY_END` or `PG_ARRAY_BAD`, and `int()` decodes the
|
|
878
|
+
* current element through `binary`. The header is `ndim`, `hasnull` and the
|
|
879
|
+
* element OID, then for `ndim` 1 the dimension's length and lower bound (the
|
|
880
|
+
* bound is read and not used); each element is a length word and its bytes,
|
|
881
|
+
* and a NULL is a length of -1 with no bytes. `ndim` 0 is the empty array.
|
|
882
|
+
* Every refusal sets `binary.failed`: an `ndim` above 1, another element
|
|
883
|
+
* type, an element whose length is not its type's size, a NULL when
|
|
884
|
+
* `hasnull` is 0, a column cut short, or bytes after the last element. The
|
|
885
|
+
* walk allocates nothing, and it reads nothing outside the column.
|
|
886
|
+
*/
|
|
887
|
+
export class PgBinaryArray {
|
|
888
|
+
/** The number of elements the header gives: 0 for an empty array. */
|
|
889
|
+
count: i32 = 0
|
|
890
|
+
/** The element type's OID, 20, 21 or 23, once `begin` has read a header it accepts. */
|
|
891
|
+
elementOid: i32 = 0
|
|
892
|
+
/** The current element's first byte in the buffer. */
|
|
893
|
+
start: i32 = 0
|
|
894
|
+
/** The current element's length: its type's size, or 0 for a NULL. */
|
|
895
|
+
length: i32 = 0
|
|
896
|
+
private binary: PgBinary
|
|
897
|
+
private b: u8[]
|
|
898
|
+
private pos: i32 = 0
|
|
899
|
+
private end: i32 = 0
|
|
900
|
+
private size: i32 = 0
|
|
901
|
+
private seen: i32 = 0
|
|
902
|
+
private hasNull: boolean = false
|
|
903
|
+
private bad: boolean = true
|
|
904
|
+
|
|
905
|
+
constructor(binary: PgBinary) {
|
|
906
|
+
this.binary = binary
|
|
907
|
+
this.b = []
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
/** Starts a walk over `b[start, start + length)`; a header this walker does not read is refused. */
|
|
911
|
+
begin(b: u8[], start: i32, length: i32): void {
|
|
912
|
+
this.b = b
|
|
913
|
+
this.count = 0
|
|
914
|
+
this.elementOid = 0
|
|
915
|
+
this.seen = 0
|
|
916
|
+
this.start = 0
|
|
917
|
+
this.length = 0
|
|
918
|
+
this.bad = !(start >= 0 && length >= PG_ARRAY_HEADER && start <= toI32(b.length) - length)
|
|
919
|
+
if (this.bad) {
|
|
920
|
+
this.refuse()
|
|
921
|
+
return
|
|
922
|
+
}
|
|
923
|
+
const ndim: i32 = getI32BE(b, start)
|
|
924
|
+
const hasNull: i32 = getI32BE(b, start + 4)
|
|
925
|
+
const oid: i32 = getI32BE(b, start + 8)
|
|
926
|
+
this.size = 0
|
|
927
|
+
if (oid === PG_OID_INT8) {
|
|
928
|
+
this.size = 8
|
|
929
|
+
} else if (oid === PG_OID_INT2) {
|
|
930
|
+
this.size = 2
|
|
931
|
+
} else if (oid === PG_OID_INT4) {
|
|
932
|
+
this.size = 4
|
|
933
|
+
}
|
|
934
|
+
this.bad = (ndim !== 0 && ndim !== 1) || (hasNull !== 0 && hasNull !== 1) || this.size === 0
|
|
935
|
+
if (ndim === 1 && !this.bad) {
|
|
936
|
+
this.bad = length < PG_ARRAY_HEADER + PG_ARRAY_DIM
|
|
937
|
+
}
|
|
938
|
+
if (this.bad) {
|
|
939
|
+
this.refuse()
|
|
940
|
+
return
|
|
941
|
+
}
|
|
942
|
+
this.elementOid = oid
|
|
943
|
+
this.hasNull = hasNull === 1
|
|
944
|
+
this.pos = start + PG_ARRAY_HEADER
|
|
945
|
+
this.end = start + length
|
|
946
|
+
if (ndim === 1) {
|
|
947
|
+
const dim: i32 = getI32BE(b, start + PG_ARRAY_HEADER)
|
|
948
|
+
if (dim < 0) {
|
|
949
|
+
this.refuse()
|
|
950
|
+
return
|
|
951
|
+
}
|
|
952
|
+
this.count = dim
|
|
953
|
+
this.pos += PG_ARRAY_DIM
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
private refuse(): i32 {
|
|
958
|
+
this.bad = true
|
|
959
|
+
this.binary.failed = true
|
|
960
|
+
return PG_ARRAY_BAD
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
/** The next element: `PG_ARRAY_ELEMENT`, `PG_ARRAY_NULL`, `PG_ARRAY_END` or `PG_ARRAY_BAD`. */
|
|
964
|
+
next(): i32 {
|
|
965
|
+
if (this.bad) {
|
|
966
|
+
return PG_ARRAY_BAD
|
|
967
|
+
}
|
|
968
|
+
if (this.seen === this.count) {
|
|
969
|
+
if (this.pos === this.end) {
|
|
970
|
+
return PG_ARRAY_END
|
|
971
|
+
}
|
|
972
|
+
return this.refuse()
|
|
973
|
+
}
|
|
974
|
+
if (this.end - this.pos < 4) {
|
|
975
|
+
return this.refuse()
|
|
976
|
+
}
|
|
977
|
+
const n: i32 = getI32BE(this.b, this.pos)
|
|
978
|
+
this.pos += 4
|
|
979
|
+
this.seen += 1
|
|
980
|
+
if (n === -1) {
|
|
981
|
+
if (!this.hasNull) {
|
|
982
|
+
return this.refuse()
|
|
983
|
+
}
|
|
984
|
+
this.start = this.pos
|
|
985
|
+
this.length = 0
|
|
986
|
+
return PG_ARRAY_NULL
|
|
987
|
+
}
|
|
988
|
+
if (n !== this.size || this.end - this.pos < n) {
|
|
989
|
+
return this.refuse()
|
|
990
|
+
}
|
|
991
|
+
this.start = this.pos
|
|
992
|
+
this.length = n
|
|
993
|
+
this.pos += n
|
|
994
|
+
return PG_ARRAY_ELEMENT
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
/** The current element as an integer, through `PgBinary.int`; a NULL, or a walk that was refused, sets `binary.failed`. */
|
|
998
|
+
int(): i64 {
|
|
999
|
+
if (this.bad) {
|
|
1000
|
+
this.binary.failed = true
|
|
1001
|
+
return 0
|
|
1002
|
+
}
|
|
1003
|
+
return this.binary.int(this.b, this.start, this.length)
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
|
|
861
1007
|
/**
|
|
862
1008
|
* A walk over a one-dimensional `text[]` column in place: `start` the
|
|
863
1009
|
* column, then `next()` until `PG_ARRAY_END` or `PG_ARRAY_BAD`. Each element
|
|
@@ -1935,10 +2081,13 @@ export class PgConnection {
|
|
|
1935
2081
|
* format rather than text: fixed-size integers, booleans, floats and
|
|
1936
2082
|
* times, read in place by `binaryInt`, `binaryBool`, `binaryFloat` and
|
|
1937
2083
|
* `binary.timestamp`. A `text` column's bytes are the same in either
|
|
1938
|
-
* format, so `columnText` and the column windows read it as before
|
|
1939
|
-
* `
|
|
1940
|
-
*
|
|
1941
|
-
*
|
|
2084
|
+
* format, so `columnText` and the column windows read it as before. An
|
|
2085
|
+
* `int2[]`, `int4[]` or `int8[]` column comes in PostgreSQL's binary layout,
|
|
2086
|
+
* which `PgBinaryArray` reads; a `text[]` or `numeric` column comes in that
|
|
2087
|
+
* layout too, and no decoder here reads it. `PgBatcher` opens its batches
|
|
2088
|
+
* with this when its `binary` is set, and reads their routing ordinals with
|
|
2089
|
+
* `binaryInt`. Its `bindEnd()` writes two bytes more, kept free under
|
|
2090
|
+
* `maxOutput` from here on. False as `prepare` is.
|
|
1942
2091
|
*/
|
|
1943
2092
|
bindStartBinary(name: string): boolean {
|
|
1944
2093
|
return this.openBind(name, true)
|
|
@@ -2863,6 +3012,8 @@ export class PgBatchConfig {
|
|
|
2863
3012
|
queueBytes: i32 = 65536
|
|
2864
3013
|
/** The most executions in flight at once. */
|
|
2865
3014
|
runs: i32 = 16
|
|
3015
|
+
/** Whether every row of a batch comes in binary format, read with the binary decoders and its ordinal by `binaryInt`; false for text. */
|
|
3016
|
+
binary: boolean = false
|
|
2866
3017
|
}
|
|
2867
3018
|
|
|
2868
3019
|
/** One execution's requests, grouped by key, and how far its rows have been routed. */
|
|
@@ -2913,7 +3064,10 @@ class PgBatchRun {
|
|
|
2913
3064
|
* connection to `fail(run)`; after each, `next(run)` answers events until
|
|
2914
3065
|
* `PG_BATCH_NONE`, `tag` naming the request each is about. Every row goes to
|
|
2915
3066
|
* every request for its key, and every request gets one last event:
|
|
2916
|
-
* `PG_BATCH_DONE`, `PG_BATCH_MISSING` or `PG_BATCH_FAILED`.
|
|
3067
|
+
* `PG_BATCH_DONE`, `PG_BATCH_MISSING` or `PG_BATCH_FAILED`. A batch with
|
|
3068
|
+
* `binary` set comes in binary format: its rows are read with the binary
|
|
3069
|
+
* decoders, `binaryInt` for each ordinal, and the caller's `binary.failed`
|
|
3070
|
+
* is left as it was.
|
|
2917
3071
|
*
|
|
2918
3072
|
* Nothing outlives its execution: a run is free again once the events
|
|
2919
3073
|
* `end` or `fail` owe are answered, and its handle is then spent. What the
|
|
@@ -2960,6 +3114,7 @@ export class PgBatcher {
|
|
|
2960
3114
|
private readonly keyType: i32
|
|
2961
3115
|
private readonly maxRequests: i32
|
|
2962
3116
|
private readonly maxBytes: i32
|
|
3117
|
+
private readonly binary: boolean
|
|
2963
3118
|
private storeEnd: i32 = 0
|
|
2964
3119
|
private head: i32 = 0
|
|
2965
3120
|
private count: i32 = 0
|
|
@@ -2997,6 +3152,7 @@ export class PgBatcher {
|
|
|
2997
3152
|
this.keyType = keyType
|
|
2998
3153
|
this.maxRequests = maxRequests
|
|
2999
3154
|
this.maxBytes = config.maxBytes
|
|
3155
|
+
this.binary = config.binary
|
|
3000
3156
|
this.name = config.name
|
|
3001
3157
|
const type: string = keyType === PG_BATCH_INT ? "int8" : "text"
|
|
3002
3158
|
const order: string = config.orderBy.length > 0 ? `, ${config.orderBy}` : ""
|
|
@@ -3164,7 +3320,7 @@ export class PgBatcher {
|
|
|
3164
3320
|
break
|
|
3165
3321
|
}
|
|
3166
3322
|
}
|
|
3167
|
-
if (r < 0 || !conn.bindStart(this.name)) {
|
|
3323
|
+
if (r < 0 || !(this.binary ? conn.bindStartBinary(this.name) : conn.bindStart(this.name))) {
|
|
3168
3324
|
return -1
|
|
3169
3325
|
}
|
|
3170
3326
|
if (!conn.arrayStart()) {
|
|
@@ -3296,7 +3452,14 @@ export class PgBatcher {
|
|
|
3296
3452
|
const last: i32 = conn.columns - 1
|
|
3297
3453
|
let ordinal: i64 = 0
|
|
3298
3454
|
let bad: boolean = last < 0 || conn.isNull(last)
|
|
3299
|
-
if (!bad) {
|
|
3455
|
+
if (!bad && this.binary) {
|
|
3456
|
+
// Read without touching `binary.failed`, which belongs to the program's own decoding.
|
|
3457
|
+
const failed: boolean = conn.binary.failed
|
|
3458
|
+
conn.binary.failed = false
|
|
3459
|
+
ordinal = conn.binaryInt(last)
|
|
3460
|
+
bad = conn.binary.failed
|
|
3461
|
+
conn.binary.failed = failed
|
|
3462
|
+
} else if (!bad) {
|
|
3300
3463
|
// Read without touching `text.failed`, which belongs to the program's own decoding.
|
|
3301
3464
|
const failed: boolean = conn.text.failed
|
|
3302
3465
|
conn.text.failed = false
|