postgrejs 2.23.0 → 3.0.1
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/CHANGELOG.md +162 -1
- package/LICENSE +26 -17
- package/README.md +195 -175
- package/connection/connection.d.ts +152 -13
- package/connection/connection.js +296 -49
- package/connection/copy-stream.d.ts +88 -0
- package/connection/copy-stream.js +244 -0
- package/connection/cursor.js +20 -13
- package/connection/intl-connection.d.ts +68 -3
- package/connection/intl-connection.js +414 -57
- package/connection/large-object.d.ts +65 -0
- package/connection/large-object.js +151 -0
- package/connection/logical-replication.d.ts +121 -0
- package/connection/logical-replication.js +279 -0
- package/connection/pool.d.ts +61 -4
- package/connection/pool.js +177 -29
- package/connection/portal.d.ts +18 -4
- package/connection/portal.js +53 -59
- package/connection/prepared-statement.d.ts +22 -1
- package/connection/prepared-statement.js +117 -97
- package/data-type-map.d.ts +2 -2
- package/data-type-map.js +4 -2
- package/data-types/bool-type.js +14 -10
- package/data-types/box-type.js +15 -8
- package/data-types/bytea-type.js +9 -5
- package/data-types/char-type.js +11 -5
- package/data-types/circle-type.js +15 -7
- package/data-types/date-type.js +25 -19
- package/data-types/float4-type.js +10 -3
- package/data-types/float8-type.js +12 -3
- package/data-types/int2-type.js +9 -4
- package/data-types/int2-vector-type.js +10 -4
- package/data-types/int4-type.js +11 -5
- package/data-types/int8-type.js +22 -7
- package/data-types/json-type.js +17 -8
- package/data-types/jsonb-type.js +20 -14
- package/data-types/lseg-type.js +16 -8
- package/data-types/numeric-type.d.ts +8 -0
- package/data-types/numeric-type.js +112 -8
- package/data-types/oid-type.d.ts +0 -1
- package/data-types/oid-type.js +9 -10
- package/data-types/oid-vector-type.d.ts +9 -0
- package/data-types/oid-vector-type.js +51 -0
- package/data-types/point-type.js +14 -6
- package/data-types/time-type.js +20 -13
- package/data-types/timestamp-type.js +32 -25
- package/data-types/timestamptz-type.d.ts +1 -1
- package/data-types/timestamptz-type.js +34 -21
- package/data-types/uuid-type.js +21 -11
- package/data-types/varchar-type.js +16 -4
- package/index.d.ts +5 -0
- package/index.js +5 -0
- package/interfaces/data-type.d.ts +5 -3
- package/interfaces/database-connection-params.d.ts +95 -0
- package/interfaces/query-options.d.ts +17 -0
- package/interfaces/script-execute-options.d.ts +17 -0
- package/package.json +3 -4
- package/protocol/backend.d.ts +6 -1
- package/protocol/backend.js +70 -45
- package/protocol/buffer-reader.d.ts +0 -2
- package/protocol/buffer-reader.js +3 -10
- package/protocol/cert-signature.d.ts +12 -0
- package/protocol/cert-signature.js +114 -0
- package/protocol/database-error.js +1 -0
- package/protocol/frontend.d.ts +16 -0
- package/protocol/frontend.js +58 -6
- package/protocol/pg-socket.d.ts +221 -10
- package/protocol/pg-socket.js +539 -102
- package/protocol/pgoutput.d.ts +76 -0
- package/protocol/pgoutput.js +155 -0
- package/protocol/protocol.d.ts +3 -4
- package/protocol/protocol.js +1 -1
- package/protocol/sasl.d.ts +11 -1
- package/protocol/sasl.js +35 -4
- package/protocol/smart-buffer.d.ts +0 -2
- package/protocol/smart-buffer.js +11 -16
- package/types.d.ts +5 -3
- package/util/abort-signal.d.ts +24 -0
- package/util/abort-signal.js +63 -0
- package/util/array-calculatedim.js +3 -1
- package/util/bigint-methods.js +1 -1
- package/util/connection-config.js +77 -3
- package/util/decode-binaryarray.d.ts +1 -1
- package/util/decode-binaryarray.js +15 -6
- package/util/encode-binaryarray.js +7 -3
- package/util/escape-identifier.d.ts +14 -0
- package/util/escape-identifier.js +32 -0
- package/util/escape-literal.js +3 -0
- package/util/fast-parseint.d.ts +1 -0
- package/util/fast-parseint.js +12 -17
- package/util/format-datetime.d.ts +10 -0
- package/util/format-datetime.js +71 -0
- package/util/get-parsers.js +31 -10
- package/util/parse-array.js +2 -2
- package/util/parse-bytea.d.ts +2 -0
- package/util/parse-bytea.js +83 -0
- package/util/parse-datetime.d.ts +3 -1
- package/util/parse-datetime.js +86 -17
- package/util/parse-row.d.ts +3 -1
- package/util/parse-row.js +60 -5
- package/util/parse-time.js +8 -1
- package/util/sql-tag.d.ts +60 -0
- package/util/sql-tag.js +202 -0
- package/util/starts-transaction.d.ts +38 -0
- package/util/starts-transaction.js +148 -0
- package/util/stringify-arrayliteral.js +13 -1
- package/util/wrap-row-description.js +13 -4
- package/util/convert-row-to-object.d.ts +0 -2
- package/util/convert-row-to-object.js +0 -9
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { DataTypeOIDs } from '../constants.js';
|
|
2
|
+
import { SmartBuffer } from '../protocol/smart-buffer.js';
|
|
2
3
|
import { decodeBinaryArray } from '../util/decode-binaryarray.js';
|
|
3
4
|
import { encodeBinaryArray } from '../util/encode-binaryarray.js';
|
|
4
5
|
import { fastParseInt } from '../util/fast-parseint.js';
|
|
@@ -6,9 +7,6 @@ export const Int2VectorType = {
|
|
|
6
7
|
name: 'int2vector',
|
|
7
8
|
oid: DataTypeOIDs.int2vector,
|
|
8
9
|
jsType: 'array',
|
|
9
|
-
parseBinary(v) {
|
|
10
|
-
return decodeBinaryArray(v, b => b.readInt16BE()) || undefined;
|
|
11
|
-
},
|
|
12
10
|
encodeBinary(buf, v) {
|
|
13
11
|
encodeBinaryArray(buf, v, DataTypeOIDs.int2, {}, (io, x) => {
|
|
14
12
|
io.writeInt16BE(x);
|
|
@@ -17,9 +15,17 @@ export const Int2VectorType = {
|
|
|
17
15
|
encodeCalculateDim(v) {
|
|
18
16
|
return [v.length];
|
|
19
17
|
},
|
|
20
|
-
|
|
18
|
+
decodeBinary(v) {
|
|
19
|
+
return decodeBinaryArray(v, 0, b => b.readInt16BE()) || undefined;
|
|
20
|
+
},
|
|
21
|
+
decodeText(str) {
|
|
21
22
|
return str.split(' ').map(fastParseInt);
|
|
22
23
|
},
|
|
24
|
+
// See box-type.ts's decodeTextBuffer comment - same rationale (this text
|
|
25
|
+
// grammar is pure ASCII digits/minus/space).
|
|
26
|
+
decodeTextBuffer(buf, offset, len, options) {
|
|
27
|
+
return Int2VectorType.decodeText(buf.toString('latin1', offset, offset + len), options);
|
|
28
|
+
},
|
|
23
29
|
encodeText(v) {
|
|
24
30
|
return v.join(' ');
|
|
25
31
|
},
|
package/data-types/int4-type.js
CHANGED
|
@@ -1,20 +1,26 @@
|
|
|
1
1
|
import { DataTypeOIDs } from '../constants.js';
|
|
2
|
-
import { fastParseInt } from '../util/fast-parseint.js';
|
|
2
|
+
import { fastParseInt, fastParseIntBuffer } from '../util/fast-parseint.js';
|
|
3
3
|
export const Int4Type = {
|
|
4
4
|
name: 'int4',
|
|
5
5
|
oid: DataTypeOIDs.int4,
|
|
6
6
|
jsType: 'number',
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
fixedBinarySize: 4,
|
|
8
|
+
encodeText(v) {
|
|
9
|
+
return '' + v;
|
|
9
10
|
},
|
|
10
11
|
encodeBinary(buf, v) {
|
|
11
12
|
buf.writeInt32BE(fastParseInt(v));
|
|
12
13
|
},
|
|
13
|
-
|
|
14
|
+
decodeBinary(v, offset = 0) {
|
|
15
|
+
return v.readInt32BE(offset);
|
|
16
|
+
},
|
|
17
|
+
decodeText: fastParseInt,
|
|
18
|
+
decodeTextBuffer: fastParseIntBuffer,
|
|
14
19
|
isType(v) {
|
|
15
20
|
return (typeof v === 'number' &&
|
|
16
21
|
Number.isInteger(v) &&
|
|
17
|
-
v
|
|
22
|
+
v >= -2147483648 &&
|
|
23
|
+
v <= 2147483647);
|
|
18
24
|
},
|
|
19
25
|
};
|
|
20
26
|
export const ArrayInt4Type = {
|
package/data-types/int8-type.js
CHANGED
|
@@ -1,28 +1,43 @@
|
|
|
1
1
|
import { DataTypeOIDs } from '../constants.js';
|
|
2
2
|
import { readBigInt64BE } from '../util/bigint-methods.js';
|
|
3
|
+
import { fastParseIntBuffer } from '../util/fast-parseint.js';
|
|
3
4
|
const maxSafeInteger = BigInt(Number.MAX_SAFE_INTEGER);
|
|
4
5
|
export const Int8Type = {
|
|
5
6
|
name: 'int8',
|
|
6
7
|
oid: DataTypeOIDs.int8,
|
|
7
8
|
jsType: 'BigInt',
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
: readBigInt64BE(buf);
|
|
12
|
-
return v >= -maxSafeInteger && v <= maxSafeInteger ? Number(v) : v;
|
|
9
|
+
fixedBinarySize: 8,
|
|
10
|
+
encodeText(v) {
|
|
11
|
+
return '' + v;
|
|
13
12
|
},
|
|
14
13
|
encodeBinary(buf, v) {
|
|
15
14
|
buf.writeBigInt64BE(v);
|
|
16
15
|
},
|
|
17
|
-
|
|
16
|
+
decodeBinary(buf, offset = 0) {
|
|
17
|
+
const v = typeof buf.readBigInt64BE === 'function'
|
|
18
|
+
? buf.readBigInt64BE(offset)
|
|
19
|
+
: readBigInt64BE(buf, offset);
|
|
20
|
+
return v >= -maxSafeInteger && v <= maxSafeInteger ? Number(v) : v;
|
|
21
|
+
},
|
|
22
|
+
decodeText(s) {
|
|
23
|
+
const digits = s.charCodeAt(0) === 45 /* '-' */ ? s.length - 1 : s.length;
|
|
24
|
+
if (digits <= 15)
|
|
25
|
+
return Number(s);
|
|
18
26
|
const v = BigInt(s);
|
|
19
27
|
return v >= -maxSafeInteger && v <= maxSafeInteger ? Number(v) : v;
|
|
20
28
|
},
|
|
29
|
+
decodeTextBuffer(buf, offset, len) {
|
|
30
|
+
const digits = buf[offset] === 45 /* '-' */ ? len - 1 : len;
|
|
31
|
+
if (digits <= 15)
|
|
32
|
+
return fastParseIntBuffer(buf, offset, len);
|
|
33
|
+
const v = BigInt(buf.toString('utf8', offset, offset + len));
|
|
34
|
+
return v >= -maxSafeInteger && v <= maxSafeInteger ? Number(v) : v;
|
|
35
|
+
},
|
|
21
36
|
isType(v) {
|
|
22
37
|
return (typeof v === 'bigint' ||
|
|
23
38
|
(typeof v === 'number' &&
|
|
24
39
|
Number.isInteger(v) &&
|
|
25
|
-
v >
|
|
40
|
+
(v > 2147483647 || v < -2147483648)));
|
|
26
41
|
},
|
|
27
42
|
};
|
|
28
43
|
export const ArrayInt8Type = {
|
package/data-types/json-type.js
CHANGED
|
@@ -3,28 +3,37 @@ export const JsonType = {
|
|
|
3
3
|
name: 'json',
|
|
4
4
|
oid: DataTypeOIDs.json,
|
|
5
5
|
jsType: 'string',
|
|
6
|
-
|
|
7
|
-
const content = v.toString('utf8');
|
|
8
|
-
const fetchAsString = options.fetchAsString
|
|
9
|
-
options.fetchAsString.includes(DataTypeOIDs.jsonb);
|
|
6
|
+
decodeBinary(v, offset = 0, options) {
|
|
7
|
+
const content = v.toString('utf8', offset);
|
|
8
|
+
const fetchAsString = options.fetchAsString?.includes(DataTypeOIDs.json);
|
|
10
9
|
if (fetchAsString)
|
|
11
10
|
return content;
|
|
12
11
|
return content ? JSON.parse(content) : undefined;
|
|
13
12
|
},
|
|
13
|
+
// json is stored as the text itself, so its binary form is those bytes.
|
|
14
|
+
encodeBinary(buf, v) {
|
|
15
|
+
buf.writeString(JsonType.encodeText(v, {}), 'utf8');
|
|
16
|
+
},
|
|
14
17
|
encodeText(v) {
|
|
15
|
-
|
|
18
|
+
// JSON.stringify() cannot serialize a BigInt itself (it throws), so a
|
|
19
|
+
// bigint is written directly as a bare numeric literal instead.
|
|
20
|
+
if (typeof v === 'bigint')
|
|
21
|
+
return v.toString();
|
|
22
|
+
if (typeof v === 'object')
|
|
16
23
|
return JSON.stringify(v);
|
|
17
24
|
if (typeof v === 'boolean')
|
|
18
25
|
return v ? 'true' : 'false';
|
|
19
26
|
return '' + v;
|
|
20
27
|
},
|
|
21
|
-
|
|
22
|
-
const fetchAsString = options.fetchAsString
|
|
23
|
-
options.fetchAsString.includes(DataTypeOIDs.jsonb);
|
|
28
|
+
decodeText(v, options) {
|
|
29
|
+
const fetchAsString = options.fetchAsString?.includes(DataTypeOIDs.json);
|
|
24
30
|
if (fetchAsString)
|
|
25
31
|
return v;
|
|
26
32
|
return v ? JSON.parse(v) : null;
|
|
27
33
|
},
|
|
34
|
+
decodeTextBuffer(buf, offset, len, options) {
|
|
35
|
+
return JsonType.decodeText(buf.toString('utf8', offset, offset + len), options);
|
|
36
|
+
},
|
|
28
37
|
isType(v) {
|
|
29
38
|
return v && typeof v === 'object';
|
|
30
39
|
},
|
package/data-types/jsonb-type.js
CHANGED
|
@@ -4,31 +4,37 @@ export const JsonbType = {
|
|
|
4
4
|
name: 'jsonb',
|
|
5
5
|
oid: DataTypeOIDs.jsonb,
|
|
6
6
|
jsType: 'string',
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
encodeText(v) {
|
|
8
|
+
if (typeof v === 'object' || typeof v === 'bigint')
|
|
9
|
+
return JSON.stringify(v);
|
|
10
|
+
if (typeof v === 'boolean')
|
|
11
|
+
return v ? 'true' : 'false';
|
|
12
|
+
return '' + v;
|
|
13
|
+
},
|
|
14
|
+
encodeBinary(buf, v) {
|
|
15
|
+
buf.writeUInt8(1);
|
|
16
|
+
buf.writeString(JsonbType.encodeText(v, {}), 'utf8');
|
|
17
|
+
},
|
|
18
|
+
decodeBinary(v, offset = 0, options) {
|
|
19
|
+
const buf = new BufferReader(offset ? v.subarray(offset) : v);
|
|
9
20
|
if (buf.readUInt8() !== 1)
|
|
10
21
|
throw new Error('Unexpected Jsonb version value in header');
|
|
11
|
-
const fetchAsString = options.fetchAsString
|
|
12
|
-
options.fetchAsString.includes(DataTypeOIDs.json);
|
|
22
|
+
const fetchAsString = options.fetchAsString?.includes(DataTypeOIDs.jsonb);
|
|
13
23
|
const content = buf.readLString(buf.length - buf.offset);
|
|
14
24
|
if (fetchAsString)
|
|
15
25
|
return content;
|
|
16
26
|
return content ? JSON.parse(content) : undefined;
|
|
17
27
|
},
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
return JSON.stringify(v);
|
|
21
|
-
if (typeof v === 'boolean')
|
|
22
|
-
return v ? 'true' : 'false';
|
|
23
|
-
return '\x0001' + v;
|
|
24
|
-
},
|
|
25
|
-
parseText(v, options) {
|
|
26
|
-
const fetchAsString = options.fetchAsString &&
|
|
27
|
-
options.fetchAsString.includes(DataTypeOIDs.json);
|
|
28
|
+
decodeText(v, options) {
|
|
29
|
+
const fetchAsString = options.fetchAsString?.includes(DataTypeOIDs.jsonb);
|
|
28
30
|
if (fetchAsString)
|
|
29
31
|
return v;
|
|
30
32
|
return v ? JSON.parse(v) : null;
|
|
31
33
|
},
|
|
34
|
+
// See json-type.ts's decodeTextBuffer comment - same rationale.
|
|
35
|
+
decodeTextBuffer(buf, offset, len, options) {
|
|
36
|
+
return JsonbType.decodeText(buf.toString('utf8', offset, offset + len), options);
|
|
37
|
+
},
|
|
32
38
|
isType(v) {
|
|
33
39
|
return v && typeof v === 'object';
|
|
34
40
|
},
|
package/data-types/lseg-type.js
CHANGED
|
@@ -7,13 +7,9 @@ export const LsegType = {
|
|
|
7
7
|
name: 'lseg',
|
|
8
8
|
oid: DataTypeOIDs.lseg,
|
|
9
9
|
jsType: 'object',
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
y1: v.readDoubleBE(8),
|
|
14
|
-
x2: v.readDoubleBE(16),
|
|
15
|
-
y2: v.readDoubleBE(24),
|
|
16
|
-
};
|
|
10
|
+
fixedBinarySize: 32,
|
|
11
|
+
encodeText(v) {
|
|
12
|
+
return `[(${v.x1},${v.y1}),(${v.x2},${v.y2})]`;
|
|
17
13
|
},
|
|
18
14
|
encodeBinary(buf, v) {
|
|
19
15
|
buf.writeDoubleBE(v.x1);
|
|
@@ -21,7 +17,15 @@ export const LsegType = {
|
|
|
21
17
|
buf.writeDoubleBE(v.x2);
|
|
22
18
|
buf.writeDoubleBE(v.y2);
|
|
23
19
|
},
|
|
24
|
-
|
|
20
|
+
decodeBinary(v, offset = 0) {
|
|
21
|
+
return {
|
|
22
|
+
x1: v.readDoubleBE(offset),
|
|
23
|
+
y1: v.readDoubleBE(offset + 8),
|
|
24
|
+
x2: v.readDoubleBE(offset + 16),
|
|
25
|
+
y2: v.readDoubleBE(offset + 24),
|
|
26
|
+
};
|
|
27
|
+
},
|
|
28
|
+
decodeText(v) {
|
|
25
29
|
const m = v.match(LSEG_PATTERN1) ||
|
|
26
30
|
v.match(LSEG_PATTERN2) ||
|
|
27
31
|
v.match(LSEG_PATTERN3) ||
|
|
@@ -35,6 +39,10 @@ export const LsegType = {
|
|
|
35
39
|
y2: parseFloat(m[4]),
|
|
36
40
|
};
|
|
37
41
|
},
|
|
42
|
+
// See box-type.ts's decodeTextBuffer comment - same rationale.
|
|
43
|
+
decodeTextBuffer(buf, offset, len, options) {
|
|
44
|
+
return LsegType.decodeText(buf.toString('latin1', offset, offset + len), options);
|
|
45
|
+
},
|
|
38
46
|
isType(v) {
|
|
39
47
|
return (typeof v === 'object' &&
|
|
40
48
|
Object.keys(v).length === 4 &&
|
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
import type { DataType } from '../interfaces/data-type.js';
|
|
2
2
|
export declare const NumericType: DataType;
|
|
3
3
|
export declare const ArrayNumericType: DataType;
|
|
4
|
+
/**
|
|
5
|
+
* Turns a JS exponential-notation number string (e.g. "1e+21", "-1.5e-7")
|
|
6
|
+
* into plain decimal notation by shifting the decimal point across the
|
|
7
|
+
* mantissa's own digits - no floating-point math involved, so it stays
|
|
8
|
+
* exact for magnitudes past what toFixed() can express (it reverts to
|
|
9
|
+
* exponential notation itself once |x| reaches 1e21).
|
|
10
|
+
*/
|
|
11
|
+
export declare function expandExponential(str: string): string;
|
|
4
12
|
/**
|
|
5
13
|
* Convert a number from binary representation to text representation.
|
|
6
14
|
* @param digits array of shorts that can be decoded as the number String
|
|
@@ -1,22 +1,100 @@
|
|
|
1
1
|
import { DataTypeOIDs } from '../constants.js';
|
|
2
2
|
const NUMERIC_NEG = 0x4000;
|
|
3
3
|
const NUMERIC_NAN = 0xc000;
|
|
4
|
+
const NUMERIC_PINF = 0xd000;
|
|
5
|
+
const NUMERIC_NINF = 0xf000;
|
|
4
6
|
const DEC_DIGITS = 4;
|
|
5
7
|
const ROUND_POWERS = [0, 1000, 100, 10];
|
|
6
8
|
export const NumericType = {
|
|
7
9
|
name: 'numeric',
|
|
8
10
|
oid: DataTypeOIDs.numeric,
|
|
9
11
|
jsType: 'number',
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
/**
|
|
13
|
+
* numeric on the wire is a base-10000 number: a digit count, the weight
|
|
14
|
+
* of the first group (in groups of four decimal digits, not digits), a
|
|
15
|
+
* sign mask, the display scale, then the groups themselves.
|
|
16
|
+
*
|
|
17
|
+
* Encoded from the decimal text rather than from the float, so a value
|
|
18
|
+
* that JavaScript cannot hold exactly - which is most of what numeric
|
|
19
|
+
* exists for - survives when it was given as a string.
|
|
20
|
+
*/
|
|
21
|
+
encodeBinary(buf, v) {
|
|
22
|
+
const writeHeader = (ndigits, weight, sign, dscale) => {
|
|
23
|
+
buf.writeInt16BE(ndigits);
|
|
24
|
+
buf.writeInt16BE(weight);
|
|
25
|
+
buf.writeUInt16BE(sign);
|
|
26
|
+
buf.writeInt16BE(dscale);
|
|
27
|
+
};
|
|
28
|
+
if (typeof v === 'number' && !Number.isFinite(v)) {
|
|
29
|
+
writeHeader(0, 0, Number.isNaN(v) ? NUMERIC_NAN : v > 0 ? NUMERIC_PINF : NUMERIC_NINF, 0);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
let str = typeof v === 'string' ? v.trim() : String(v);
|
|
33
|
+
if (str === 'NaN')
|
|
34
|
+
return writeHeader(0, 0, NUMERIC_NAN, 0);
|
|
35
|
+
if (str === 'Infinity')
|
|
36
|
+
return writeHeader(0, 0, NUMERIC_PINF, 0);
|
|
37
|
+
if (str === '-Infinity')
|
|
38
|
+
return writeHeader(0, 0, NUMERIC_NINF, 0);
|
|
39
|
+
// Exponent form has no place in the wire format; go through Number to
|
|
40
|
+
// get it back into plain notation. toFixed() cannot do this itself -
|
|
41
|
+
// per spec it falls back to exponential notation once the magnitude
|
|
42
|
+
// reaches 1e21, so this shifts the decimal point manually instead.
|
|
43
|
+
if (/e/i.test(str))
|
|
44
|
+
str = expandExponential(Number(str).toString());
|
|
45
|
+
let sign = 0;
|
|
46
|
+
if (str.startsWith('-')) {
|
|
47
|
+
sign = NUMERIC_NEG;
|
|
48
|
+
str = str.substring(1);
|
|
49
|
+
}
|
|
50
|
+
else if (str.startsWith('+'))
|
|
51
|
+
str = str.substring(1);
|
|
52
|
+
const dot = str.indexOf('.');
|
|
53
|
+
let intPart = dot < 0 ? str : str.substring(0, dot);
|
|
54
|
+
let fracPart = dot < 0 ? '' : str.substring(dot + 1);
|
|
55
|
+
const dscale = fracPart.length;
|
|
56
|
+
// Group into fours, aligned on the decimal point from both sides.
|
|
57
|
+
const intPad = (DEC_DIGITS - (intPart.length % DEC_DIGITS)) % DEC_DIGITS;
|
|
58
|
+
intPart = '0'.repeat(intPad) + intPart;
|
|
59
|
+
const fracPad = (DEC_DIGITS - (fracPart.length % DEC_DIGITS)) % DEC_DIGITS;
|
|
60
|
+
fracPart = fracPart + '0'.repeat(fracPad);
|
|
61
|
+
const digits = [];
|
|
62
|
+
for (let i = 0; i < intPart.length; i += DEC_DIGITS)
|
|
63
|
+
digits.push(+intPart.substring(i, i + DEC_DIGITS));
|
|
64
|
+
for (let i = 0; i < fracPart.length; i += DEC_DIGITS)
|
|
65
|
+
digits.push(+fracPart.substring(i, i + DEC_DIGITS));
|
|
66
|
+
// weight counts groups before the point, less one; leading zero groups
|
|
67
|
+
// are dropped and lower it, trailing ones are simply dropped.
|
|
68
|
+
let weight = intPart.length / DEC_DIGITS - 1;
|
|
69
|
+
while (digits.length && digits[0] === 0) {
|
|
70
|
+
digits.shift();
|
|
71
|
+
weight--;
|
|
72
|
+
}
|
|
73
|
+
while (digits.length && digits[digits.length - 1] === 0)
|
|
74
|
+
digits.pop();
|
|
75
|
+
if (!digits.length)
|
|
76
|
+
weight = 0;
|
|
77
|
+
writeHeader(digits.length, weight, sign, dscale);
|
|
78
|
+
for (const d of digits)
|
|
79
|
+
buf.writeInt16BE(d);
|
|
80
|
+
},
|
|
81
|
+
decodeBinary(v, offset = 0) {
|
|
82
|
+
const len = v.readInt16BE(offset);
|
|
83
|
+
const weight = v.readInt16BE(offset + 2);
|
|
84
|
+
// sign is a bitmask (0x0000/0x4000/0xC000/0xD000/0xF000), not a two's
|
|
85
|
+
// complement quantity - must be read unsigned or NaN/Infinity sign
|
|
86
|
+
// values (which set the top bit) never compare equal to the constants.
|
|
87
|
+
const sign = v.readUInt16BE(offset + 4);
|
|
88
|
+
const scale = v.readInt16BE(offset + 6);
|
|
15
89
|
if (sign === NUMERIC_NAN)
|
|
16
90
|
return NaN;
|
|
91
|
+
if (sign === NUMERIC_PINF)
|
|
92
|
+
return Infinity;
|
|
93
|
+
if (sign === NUMERIC_NINF)
|
|
94
|
+
return -Infinity;
|
|
17
95
|
const digits = [];
|
|
18
96
|
for (let i = 0; i < len; i++) {
|
|
19
|
-
digits[i] = v.readInt16BE(8 + i * 2);
|
|
97
|
+
digits[i] = v.readInt16BE(offset + 8 + i * 2);
|
|
20
98
|
}
|
|
21
99
|
const numString = numberBytesToString(digits, scale, weight, sign);
|
|
22
100
|
return parseFloat(numString);
|
|
@@ -25,7 +103,11 @@ export const NumericType = {
|
|
|
25
103
|
const n = typeof v === 'number' ? v : parseFloat(v);
|
|
26
104
|
return '' + n;
|
|
27
105
|
},
|
|
28
|
-
|
|
106
|
+
decodeText: parseFloat,
|
|
107
|
+
// See float4-type.ts's decodeTextBuffer comment - same rationale.
|
|
108
|
+
decodeTextBuffer(buf, offset, len) {
|
|
109
|
+
return parseFloat(buf.toString('latin1', offset, offset + len));
|
|
110
|
+
},
|
|
29
111
|
isType(v) {
|
|
30
112
|
return typeof v === 'number';
|
|
31
113
|
},
|
|
@@ -36,6 +118,26 @@ export const ArrayNumericType = {
|
|
|
36
118
|
oid: DataTypeOIDs._numeric,
|
|
37
119
|
elementsOID: DataTypeOIDs.numeric,
|
|
38
120
|
};
|
|
121
|
+
/**
|
|
122
|
+
* Turns a JS exponential-notation number string (e.g. "1e+21", "-1.5e-7")
|
|
123
|
+
* into plain decimal notation by shifting the decimal point across the
|
|
124
|
+
* mantissa's own digits - no floating-point math involved, so it stays
|
|
125
|
+
* exact for magnitudes past what toFixed() can express (it reverts to
|
|
126
|
+
* exponential notation itself once |x| reaches 1e21).
|
|
127
|
+
*/
|
|
128
|
+
export function expandExponential(str) {
|
|
129
|
+
const m = str.match(/^(-)?(\d+)(?:\.(\d+))?e([+-]?\d+)$/i);
|
|
130
|
+
if (!m)
|
|
131
|
+
return str;
|
|
132
|
+
const sign = m[1] || '';
|
|
133
|
+
const digits = m[2] + (m[3] || '');
|
|
134
|
+
const pointPos = m[2].length + parseInt(m[4], 10);
|
|
135
|
+
if (pointPos <= 0)
|
|
136
|
+
return sign + '0.' + '0'.repeat(-pointPos) + digits;
|
|
137
|
+
if (pointPos >= digits.length)
|
|
138
|
+
return sign + digits + '0'.repeat(pointPos - digits.length);
|
|
139
|
+
return sign + digits.slice(0, pointPos) + '.' + digits.slice(pointPos);
|
|
140
|
+
}
|
|
39
141
|
/* https://github.com/pgjdbc/pgjdbc/blob/3eca3a76aa4a04cb28cb960ed674cb67db30b5e3/pgjdbc/src/main/java/org/postgresql/util/ByteConverter.java */
|
|
40
142
|
/**
|
|
41
143
|
* Convert a number from binary representation to text representation.
|
|
@@ -103,7 +205,9 @@ function digitToString(idx, digits, alwaysPutIt) {
|
|
|
103
205
|
let dig = idx >= 0 && idx < digits.length ? digits[idx] : 0;
|
|
104
206
|
// Each dig represents 4 decimal digits (e.g. 9999)
|
|
105
207
|
// If we continue the number, then we need to print 0 as 0000 (alwaysPutIt parameter is true)
|
|
106
|
-
|
|
208
|
+
const l = ROUND_POWERS.length;
|
|
209
|
+
let p;
|
|
210
|
+
for (p = 1; p < l; p++) {
|
|
107
211
|
const pow = ROUND_POWERS[p];
|
|
108
212
|
const d1 = Math.trunc(dig / pow);
|
|
109
213
|
dig -= d1 * pow;
|
package/data-types/oid-type.d.ts
CHANGED
package/data-types/oid-type.js
CHANGED
|
@@ -1,16 +1,21 @@
|
|
|
1
1
|
import { DataTypeNames, DataTypeOIDs } from '../constants.js';
|
|
2
|
-
import { fastParseInt } from '../util/fast-parseint.js';
|
|
2
|
+
import { fastParseInt, fastParseIntBuffer } from '../util/fast-parseint.js';
|
|
3
3
|
export const OidType = {
|
|
4
4
|
name: 'oid',
|
|
5
5
|
oid: DataTypeOIDs.oid,
|
|
6
6
|
jsType: 'number',
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
fixedBinarySize: 4,
|
|
8
|
+
encodeText(v) {
|
|
9
|
+
return '' + v;
|
|
9
10
|
},
|
|
10
11
|
encodeBinary(buf, v) {
|
|
11
12
|
buf.writeUInt32BE(fastParseInt(v));
|
|
12
13
|
},
|
|
13
|
-
|
|
14
|
+
decodeBinary(v, offset = 0) {
|
|
15
|
+
return v.readUInt32BE(offset);
|
|
16
|
+
},
|
|
17
|
+
decodeText: fastParseInt,
|
|
18
|
+
decodeTextBuffer: fastParseIntBuffer,
|
|
14
19
|
isType(v) {
|
|
15
20
|
return typeof v === 'number' && Number.isInteger(v) && !!DataTypeNames[v];
|
|
16
21
|
},
|
|
@@ -21,9 +26,3 @@ export const ArrayOidType = {
|
|
|
21
26
|
oid: DataTypeOIDs._oid,
|
|
22
27
|
elementsOID: DataTypeOIDs.oid,
|
|
23
28
|
};
|
|
24
|
-
export const VectorOidType = {
|
|
25
|
-
...OidType,
|
|
26
|
-
name: '_oidvector',
|
|
27
|
-
oid: DataTypeOIDs.oidvector,
|
|
28
|
-
elementsOID: DataTypeOIDs.oid,
|
|
29
|
-
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { DataType } from '../interfaces/data-type.js';
|
|
2
|
+
/**
|
|
3
|
+
* `oidvector` (OID 30) is a list of OIDs, not the array type of `oid` -
|
|
4
|
+
* that is `_oid` (1028). It has its own array type, `_oidvector` (1013),
|
|
5
|
+
* exactly as `int2vector` has `_int2vector`, and its text form is
|
|
6
|
+
* space-separated rather than braced.
|
|
7
|
+
*/
|
|
8
|
+
export declare const OidVectorType: DataType;
|
|
9
|
+
export declare const ArrayOidVectorType: DataType;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { DataTypeOIDs } from '../constants.js';
|
|
2
|
+
import { SmartBuffer } from '../protocol/smart-buffer.js';
|
|
3
|
+
import { decodeBinaryArray } from '../util/decode-binaryarray.js';
|
|
4
|
+
import { encodeBinaryArray } from '../util/encode-binaryarray.js';
|
|
5
|
+
import { fastParseInt } from '../util/fast-parseint.js';
|
|
6
|
+
/**
|
|
7
|
+
* `oidvector` (OID 30) is a list of OIDs, not the array type of `oid` -
|
|
8
|
+
* that is `_oid` (1028). It has its own array type, `_oidvector` (1013),
|
|
9
|
+
* exactly as `int2vector` has `_int2vector`, and its text form is
|
|
10
|
+
* space-separated rather than braced.
|
|
11
|
+
*/
|
|
12
|
+
export const OidVectorType = {
|
|
13
|
+
name: 'oidvector',
|
|
14
|
+
oid: DataTypeOIDs.oidvector,
|
|
15
|
+
jsType: 'array',
|
|
16
|
+
encodeBinary(buf, v) {
|
|
17
|
+
encodeBinaryArray(buf, v, DataTypeOIDs.oid, {}, (io, x) => {
|
|
18
|
+
io.writeUInt32BE(x);
|
|
19
|
+
});
|
|
20
|
+
},
|
|
21
|
+
encodeCalculateDim(v) {
|
|
22
|
+
return [v.length];
|
|
23
|
+
},
|
|
24
|
+
decodeBinary(v) {
|
|
25
|
+
return decodeBinaryArray(v, 0, b => b.readUInt32BE()) || undefined;
|
|
26
|
+
},
|
|
27
|
+
decodeText(str) {
|
|
28
|
+
return str.split(' ').map(fastParseInt);
|
|
29
|
+
},
|
|
30
|
+
// See box-type.ts's decodeTextBuffer comment - same rationale (this text
|
|
31
|
+
// grammar is pure ASCII digits and spaces).
|
|
32
|
+
decodeTextBuffer(buf, offset, len, options) {
|
|
33
|
+
return OidVectorType.decodeText(buf.toString('latin1', offset, offset + len), options);
|
|
34
|
+
},
|
|
35
|
+
encodeText(v) {
|
|
36
|
+
return v.join(' ');
|
|
37
|
+
},
|
|
38
|
+
isType(v) {
|
|
39
|
+
return (Array.isArray(v) &&
|
|
40
|
+
!v.find(x => !(typeof x === 'number' &&
|
|
41
|
+
Number.isInteger(x) &&
|
|
42
|
+
x >= 0 &&
|
|
43
|
+
x <= 4294967295)));
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
export const ArrayOidVectorType = {
|
|
47
|
+
...OidVectorType,
|
|
48
|
+
name: '_oidvector',
|
|
49
|
+
oid: DataTypeOIDs._oidvector,
|
|
50
|
+
elementsOID: DataTypeOIDs.oidvector,
|
|
51
|
+
};
|
package/data-types/point-type.js
CHANGED
|
@@ -5,17 +5,21 @@ export const PointType = {
|
|
|
5
5
|
name: 'point',
|
|
6
6
|
oid: DataTypeOIDs.point,
|
|
7
7
|
jsType: 'object',
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
y: v.readDoubleBE(8),
|
|
12
|
-
};
|
|
8
|
+
fixedBinarySize: 16,
|
|
9
|
+
encodeText(v) {
|
|
10
|
+
return `(${v.x},${v.y})`;
|
|
13
11
|
},
|
|
14
12
|
encodeBinary(buf, v) {
|
|
15
13
|
buf.writeDoubleBE(v.x);
|
|
16
14
|
buf.writeDoubleBE(v.y);
|
|
17
15
|
},
|
|
18
|
-
|
|
16
|
+
decodeBinary(v, offset = 0) {
|
|
17
|
+
return {
|
|
18
|
+
x: v.readDoubleBE(offset),
|
|
19
|
+
y: v.readDoubleBE(offset + 8),
|
|
20
|
+
};
|
|
21
|
+
},
|
|
22
|
+
decodeText(v) {
|
|
19
23
|
const m = v.match(POINT_PATTERN1) || v.match(POINT_PATTERN2);
|
|
20
24
|
if (!m)
|
|
21
25
|
return undefined;
|
|
@@ -24,6 +28,10 @@ export const PointType = {
|
|
|
24
28
|
y: parseFloat(m[2]),
|
|
25
29
|
};
|
|
26
30
|
},
|
|
31
|
+
// See box-type.ts's decodeTextBuffer comment - same rationale.
|
|
32
|
+
decodeTextBuffer(buf, offset, len, options) {
|
|
33
|
+
return PointType.decodeText(buf.toString('latin1', offset, offset + len), options);
|
|
34
|
+
},
|
|
27
35
|
isType(v) {
|
|
28
36
|
return (typeof v === 'object' &&
|
|
29
37
|
Object.keys(v).length === 2 &&
|
package/data-types/time-type.js
CHANGED
|
@@ -1,20 +1,14 @@
|
|
|
1
1
|
import { DataTypeOIDs } from '../constants.js';
|
|
2
|
+
import { formatTime } from '../util/format-datetime.js';
|
|
2
3
|
import { parseTime, STRICT_TIME_PATTERN } from '../util/parse-time.js';
|
|
3
4
|
const timeMul = 4294967296;
|
|
4
5
|
export const TimeType = {
|
|
5
6
|
name: 'time',
|
|
6
7
|
oid: DataTypeOIDs.time,
|
|
7
8
|
jsType: 'string',
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const hi = v.readInt32BE();
|
|
12
|
-
const lo = v.readUInt32BE(4);
|
|
13
|
-
let d = new Date((lo + hi * timeMul) / 1000);
|
|
14
|
-
if (fetchAsString || !options.utcDates) {
|
|
15
|
-
d = new Date(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds());
|
|
16
|
-
}
|
|
17
|
-
return fetchAsString ? dateToTimeString(d) : d;
|
|
9
|
+
fixedBinarySize: 8,
|
|
10
|
+
encodeText(v, options) {
|
|
11
|
+
return formatTime(v, options);
|
|
18
12
|
},
|
|
19
13
|
encodeBinary(buf, v, options) {
|
|
20
14
|
if (typeof v === 'string')
|
|
@@ -31,12 +25,25 @@ export const TimeType = {
|
|
|
31
25
|
buf.writeInt32BE(hi);
|
|
32
26
|
buf.writeUInt32BE(lo);
|
|
33
27
|
},
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
28
|
+
decodeBinary(v, offset = 0, options) {
|
|
29
|
+
const fetchAsString = options.fetchAsString?.includes(DataTypeOIDs.time);
|
|
30
|
+
const hi = v.readInt32BE(offset);
|
|
31
|
+
const lo = v.readUInt32BE(offset + 4);
|
|
32
|
+
let d = new Date((lo + hi * timeMul) / 1000);
|
|
33
|
+
if (fetchAsString || !options.utcDates) {
|
|
34
|
+
d = new Date(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds());
|
|
35
|
+
}
|
|
36
|
+
return fetchAsString ? dateToTimeString(d) : d;
|
|
37
|
+
},
|
|
38
|
+
decodeText(v, options) {
|
|
39
|
+
if (options.fetchAsString?.includes(DataTypeOIDs.time))
|
|
37
40
|
return v;
|
|
38
41
|
return parseTime(v, false, options.utcDates);
|
|
39
42
|
},
|
|
43
|
+
// See date-type.ts's decodeTextBuffer comment - same rationale.
|
|
44
|
+
decodeTextBuffer(buf, offset, len, options) {
|
|
45
|
+
return TimeType.decodeText(buf.toString('latin1', offset, offset + len), options);
|
|
46
|
+
},
|
|
40
47
|
isType(v) {
|
|
41
48
|
return ((v instanceof Date &&
|
|
42
49
|
v.getFullYear() === 1970 &&
|