postgrejs 3.3.0 → 3.5.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/CHANGELOG.md +55 -1
- package/README.md +68 -7
- package/connection/connection.d.ts +134 -0
- package/connection/connection.js +213 -2
- package/connection/cursor.d.ts +8 -0
- package/connection/cursor.js +17 -0
- package/connection/intl-connection.d.ts +118 -3
- package/connection/intl-connection.js +615 -31
- package/connection/pool.d.ts +16 -0
- package/connection/pool.js +24 -0
- package/connection/prepared-statement.d.ts +64 -1
- package/connection/prepared-statement.js +95 -5
- package/data-types/float4-type.js +2 -1
- package/data-types/float8-type.js +2 -1
- package/data-types/int2-type.js +2 -1
- package/data-types/int4-type.js +2 -1
- package/data-types/int8-type.js +2 -1
- package/data-types/numeric-type.js +7 -0
- package/data-types/oid-type.js +2 -1
- package/index.d.ts +3 -0
- package/index.js +3 -0
- package/interfaces/batch-result.d.ts +42 -0
- package/interfaces/batch-result.js +1 -0
- package/interfaces/copy-from-rows-options.d.ts +58 -0
- package/interfaces/copy-from-rows-options.js +1 -0
- package/interfaces/database-connection-params.d.ts +25 -0
- package/interfaces/pipeline-request.d.ts +16 -0
- package/interfaces/pipeline-request.js +1 -0
- package/interfaces/query-options.d.ts +6 -0
- package/package.json +5 -2
- package/protocol/database-error.d.ts +16 -0
- package/protocol/database-error.js +15 -0
- package/protocol/pg-socket.d.ts +76 -0
- package/protocol/pg-socket.js +130 -12
- package/util/assert-integer.d.ts +43 -0
- package/util/assert-integer.js +58 -0
- package/util/copy-from-rows.d.ts +56 -0
- package/util/copy-from-rows.js +95 -0
- package/util/encode-copy-binary.d.ts +48 -0
- package/util/encode-copy-binary.js +112 -0
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { encodeBinaryArray } from './encode-binaryarray.js';
|
|
2
|
+
/**
|
|
3
|
+
* `PGCOPY\n\377\r\n\0` followed by two int32 words: a flags field and the
|
|
4
|
+
* length of a header extension area. Bit 16 of the flags marks a stream
|
|
5
|
+
* that carries an OID per row - an obsolete variant PostgreSQL still reads
|
|
6
|
+
* but nothing should write - so both words are zero here.
|
|
7
|
+
*/
|
|
8
|
+
export const COPY_BINARY_HEADER = Buffer.from([
|
|
9
|
+
0x50, 0x47, 0x43, 0x4f, 0x50, 0x59, 0x0a, 0xff, 0x0d, 0x0a, 0x00, 0, 0, 0, 0,
|
|
10
|
+
0, 0, 0, 0,
|
|
11
|
+
]);
|
|
12
|
+
/** A field count of -1 where a row would start, ending the stream. */
|
|
13
|
+
export const COPY_BINARY_TRAILER = Buffer.from([0xff, 0xff]);
|
|
14
|
+
/**
|
|
15
|
+
* Appends one row to `io` in PostgreSQL's binary COPY format: an int16
|
|
16
|
+
* field count, then per field an int32 byte length followed by that many
|
|
17
|
+
* bytes, with -1 standing in for NULL.
|
|
18
|
+
*
|
|
19
|
+
* Each value is written by its own type's `encodeBinary`, which is the same
|
|
20
|
+
* function a binary query parameter goes through (see Frontend's Bind) -
|
|
21
|
+
* both are the type's `send` representation, so there is one encoder per
|
|
22
|
+
* type rather than a COPY-specific set.
|
|
23
|
+
*
|
|
24
|
+
* Binary COPY performs no conversion on the server: the bytes have to be
|
|
25
|
+
* exactly what the destination column's type expects. `dataTypeIds` must
|
|
26
|
+
* therefore be the column's own OIDs, which is why the caller obtains them
|
|
27
|
+
* from the server rather than inferring them from the JavaScript values.
|
|
28
|
+
*
|
|
29
|
+
* @param rowIndex Only used to say which row failed, since a value that
|
|
30
|
+
* cannot be encoded otherwise surfaces from the server as an opaque
|
|
31
|
+
* "incorrect binary data format" naming neither row nor column.
|
|
32
|
+
* @returns Whether the row was written - false only under `'skip'`, where
|
|
33
|
+
* the partial row has already been unwound.
|
|
34
|
+
*/
|
|
35
|
+
export function encodeCopyBinaryRow(io, values, dataTypeIds, columnNames, typeMap, options, rowIndex, onInvalidValue = 'throw',
|
|
36
|
+
/** Incremented per value replaced under `'null'`; counted here rather
|
|
37
|
+
* than inferred by the caller, which cannot see inside a written row. */
|
|
38
|
+
stats) {
|
|
39
|
+
const rowStart = io.size;
|
|
40
|
+
const l = dataTypeIds.length;
|
|
41
|
+
io.writeInt16BE(l);
|
|
42
|
+
let i;
|
|
43
|
+
let v;
|
|
44
|
+
for (i = 0; i < l; i++) {
|
|
45
|
+
v = values[i];
|
|
46
|
+
if (v === null || v === undefined) {
|
|
47
|
+
io.writeInt32BE(-1);
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
const dt = typeMap.get(dataTypeIds[i]);
|
|
51
|
+
/* c8 ignore next 5 - unreachable: assertCopyBinaryEncodable() rejects
|
|
52
|
+
every column whose type has no encodeBinary before any row is
|
|
53
|
+
encoded, so this is a guard against a type map mutated mid-copy. */
|
|
54
|
+
if (!dt?.encodeBinary) {
|
|
55
|
+
throw new Error(`Column "${columnNames[i]}" has no binary encoder (type OID ${dataTypeIds[i]})`);
|
|
56
|
+
}
|
|
57
|
+
if (dt.encodeAsNull?.(v, options)) {
|
|
58
|
+
io.writeInt32BE(-1);
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
io.writeInt32BE(0); // placeholder, backfilled below
|
|
62
|
+
const dataOffset = io.position;
|
|
63
|
+
try {
|
|
64
|
+
if (dt.elementsOID) {
|
|
65
|
+
encodeBinaryArray(io, Array.isArray(v) ? v : [v], dt.elementsOID, options, dt.encodeBinary, dt.encodeCalculateDim);
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
dt.encodeBinary(io, v, options);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
catch (e) {
|
|
72
|
+
if (onInvalidValue === 'skip') {
|
|
73
|
+
// Unwind the partial row so the stream never carries half of it.
|
|
74
|
+
io.setSize(rowStart);
|
|
75
|
+
io.position = rowStart;
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
if (onInvalidValue === 'null') {
|
|
79
|
+
io.setSize(dataOffset);
|
|
80
|
+
io.position = dataOffset - 4;
|
|
81
|
+
io.writeInt32BE(-1);
|
|
82
|
+
if (stats)
|
|
83
|
+
stats.nulled++;
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
throw new Error(`Cannot encode row ${rowIndex}, column "${columnNames[i]}" (${dt.name}): ${e.message}`, { cause: e });
|
|
87
|
+
}
|
|
88
|
+
io.buffer.writeInt32BE(io.size - dataOffset, dataOffset - 4);
|
|
89
|
+
}
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Fails before a single byte goes out when any column's type cannot be
|
|
94
|
+
* written in binary. Worth doing up front: once the server has answered
|
|
95
|
+
* CopyInResponse it is waiting for a complete stream, so discovering an
|
|
96
|
+
* unencodable column at row 900,000 means aborting a copy that was already
|
|
97
|
+
* most of the way done.
|
|
98
|
+
*/
|
|
99
|
+
export function assertCopyBinaryEncodable(dataTypeIds, columnNames, typeMap) {
|
|
100
|
+
const missing = [];
|
|
101
|
+
const l = dataTypeIds.length;
|
|
102
|
+
let i;
|
|
103
|
+
for (i = 0; i < l; i++) {
|
|
104
|
+
const dt = typeMap.get(dataTypeIds[i]);
|
|
105
|
+
if (!dt?.encodeBinary)
|
|
106
|
+
missing.push(`"${columnNames[i]}" (OID ${dataTypeIds[i]})`);
|
|
107
|
+
}
|
|
108
|
+
if (missing.length) {
|
|
109
|
+
throw new Error(`Binary COPY cannot encode ${missing.join(', ')} - no binary encoder is ` +
|
|
110
|
+
`registered for that type. Use copyFrom() with a text format instead.`);
|
|
111
|
+
}
|
|
112
|
+
}
|