postgrejs 3.1.3 → 3.4.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 +79 -1
- package/README.md +79 -13
- package/connection/connection.d.ts +97 -0
- package/connection/connection.js +141 -2
- package/connection/cursor.d.ts +2 -1
- package/connection/cursor.js +6 -6
- package/connection/intl-connection.d.ts +113 -3
- package/connection/intl-connection.js +530 -45
- package/connection/prepared-statement.d.ts +64 -1
- package/connection/prepared-statement.js +97 -6
- package/data-types/bool-type.js +0 -1
- package/data-types/box-type.js +0 -1
- package/data-types/bytea-type.js +5 -3
- package/data-types/char-type.js +2 -2
- package/data-types/circle-type.js +0 -1
- package/data-types/date-type.js +1 -2
- package/data-types/float4-type.js +4 -5
- package/data-types/float8-type.js +4 -6
- package/data-types/int2-type.js +2 -2
- package/data-types/int2-vector-type.js +3 -2
- package/data-types/int4-type.js +2 -2
- package/data-types/int8-type.js +2 -2
- package/data-types/json-type.js +2 -2
- package/data-types/jsonb-type.js +6 -5
- package/data-types/lseg-type.js +0 -1
- package/data-types/numeric-type.js +9 -4
- package/data-types/oid-type.js +2 -2
- package/data-types/oid-vector-type.js +3 -2
- package/data-types/point-type.js +0 -1
- package/data-types/time-type.js +1 -2
- package/data-types/timestamp-type.js +13 -3
- package/data-types/timestamptz-type.js +27 -10
- package/data-types/uuid-type.js +1 -2
- package/data-types/varchar-type.js +2 -2
- package/index.d.ts +4 -0
- package/index.js +4 -0
- package/interfaces/batch-result.d.ts +42 -0
- package/interfaces/batch-result.js +1 -0
- package/interfaces/command-result.d.ts +3 -2
- package/interfaces/copy-from-rows-options.d.ts +58 -0
- package/interfaces/copy-from-rows-options.js +1 -0
- package/interfaces/data-type.d.ts +0 -1
- 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 +18 -0
- package/interfaces/script-execute-options.d.ts +12 -0
- package/package.json +18 -3
- package/protocol/backend.js +6 -6
- package/protocol/buffer-reader.d.ts +7 -12
- package/protocol/buffer-reader.js +11 -58
- package/protocol/database-error.d.ts +16 -0
- package/protocol/database-error.js +15 -0
- package/protocol/frontend.js +86 -96
- package/protocol/pg-socket.d.ts +82 -33
- package/protocol/pg-socket.js +143 -86
- package/protocol/pgoutput.js +2 -2
- package/protocol/smart-buffer.d.ts +11 -29
- package/protocol/smart-buffer.js +19 -162
- package/types.d.ts +13 -1
- package/util/assert-integer.d.ts +43 -0
- package/util/assert-integer.js +58 -0
- package/util/bigint-methods.d.ts +0 -1
- package/util/bigint-methods.js +0 -22
- package/util/copy-from-rows.d.ts +56 -0
- package/util/copy-from-rows.js +95 -0
- package/util/decode-binaryarray.d.ts +1 -1
- package/util/decode-binaryarray.js +7 -7
- package/util/encode-binaryarray.js +6 -6
- package/util/encode-copy-binary.d.ts +48 -0
- package/util/encode-copy-binary.js +112 -0
- package/util/fast-parsefloat.d.ts +15 -0
- package/util/fast-parsefloat.js +141 -0
- package/util/get-parsers.js +4 -8
- package/util/parse-datetime.js +7 -0
- package/util/parse-pg-timestamp.d.ts +31 -0
- package/util/parse-pg-timestamp.js +199 -0
- package/util/parse-row.js +120 -0
- package/util/row-decoder.d.ts +49 -0
- package/util/row-decoder.js +63 -0
package/protocol/frontend.js
CHANGED
|
@@ -39,31 +39,31 @@ export class Frontend {
|
|
|
39
39
|
this._io = new SmartBuffer(options?.buffer);
|
|
40
40
|
}
|
|
41
41
|
getSSLRequestMessage() {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
.flush();
|
|
42
|
+
const io = this._io.start();
|
|
43
|
+
io.writeUInt32BE(8); // Length of message contents in bytes, including self.
|
|
44
|
+
io.writeUInt16BE(1234);
|
|
45
|
+
io.writeUInt16BE(5679);
|
|
46
|
+
return io.flush();
|
|
48
47
|
}
|
|
49
48
|
getStartupMessage(args, minorVersion = Protocol.VERSION_MINOR) {
|
|
50
|
-
const io = this._io
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
.writeInt16BE(minorVersion);
|
|
49
|
+
const io = this._io.start();
|
|
50
|
+
io.writeInt32BE(0); // Preserve length
|
|
51
|
+
io.writeInt16BE(Protocol.VERSION_MAJOR);
|
|
52
|
+
io.writeInt16BE(minorVersion);
|
|
55
53
|
const entries = Object.entries(args);
|
|
56
54
|
const l = entries.length;
|
|
57
55
|
let k;
|
|
58
56
|
let v;
|
|
59
57
|
for (let i = 0; i < l; i++) {
|
|
60
58
|
[k, v] = entries[i];
|
|
61
|
-
if (k !== 'client_encoding')
|
|
62
|
-
io.writeCString(k, 'utf8')
|
|
59
|
+
if (k !== 'client_encoding') {
|
|
60
|
+
io.writeCString(k, 'utf8');
|
|
61
|
+
io.writeCString(v, 'utf8');
|
|
62
|
+
}
|
|
63
63
|
}
|
|
64
|
-
io.writeCString('client_encoding', 'utf8')
|
|
65
|
-
|
|
66
|
-
|
|
64
|
+
io.writeCString('client_encoding', 'utf8');
|
|
65
|
+
io.writeCString('UTF8', 'utf8');
|
|
66
|
+
io.writeUInt8(0);
|
|
67
67
|
return setLengthAndFlush(io, 0);
|
|
68
68
|
}
|
|
69
69
|
/**
|
|
@@ -73,51 +73,46 @@ export class Frontend {
|
|
|
73
73
|
* down the normal one.
|
|
74
74
|
*/
|
|
75
75
|
getCancelRequestMessage(processID, secretKey) {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
.flush();
|
|
76
|
+
const io = this._io.start();
|
|
77
|
+
io.writeUInt32BE(12 + secretKey.length); // Length of message contents in bytes, including self.
|
|
78
|
+
io.writeUInt16BE(1234);
|
|
79
|
+
io.writeUInt16BE(5678);
|
|
80
|
+
io.writeUInt32BE(processID);
|
|
81
|
+
io.writeBytes(secretKey);
|
|
82
|
+
return io.flush();
|
|
84
83
|
}
|
|
85
84
|
getPasswordMessage(password) {
|
|
86
|
-
const io = this._io
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
.writeCString(password, 'utf8');
|
|
85
|
+
const io = this._io.start();
|
|
86
|
+
io.writeInt8(Protocol.FrontendMessageCode.PasswordMessage);
|
|
87
|
+
io.writeInt32BE(0); // Preserve header
|
|
88
|
+
io.writeCString(password, 'utf8');
|
|
91
89
|
return setLengthAndFlush(io, 1);
|
|
92
90
|
}
|
|
93
91
|
getSASLMessage(sasl) {
|
|
94
|
-
const io = this._io
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
.writeLString(sasl.clientFirstMessage);
|
|
92
|
+
const io = this._io.start();
|
|
93
|
+
io.writeInt8(Protocol.FrontendMessageCode.PasswordMessage);
|
|
94
|
+
io.writeInt32BE(0); // Preserve header
|
|
95
|
+
io.writeCString(sasl.mechanism, 'utf8');
|
|
96
|
+
io.writeLString(sasl.clientFirstMessage);
|
|
100
97
|
return setLengthAndFlush(io, 1);
|
|
101
98
|
}
|
|
102
99
|
getSASLFinalMessage(session) {
|
|
103
|
-
const io = this._io
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
.writeString(session.clientFinalMessage);
|
|
100
|
+
const io = this._io.start();
|
|
101
|
+
io.writeInt8(Protocol.FrontendMessageCode.PasswordMessage);
|
|
102
|
+
io.writeInt32BE(0); // Preserve header
|
|
103
|
+
io.writeString(session.clientFinalMessage);
|
|
108
104
|
return setLengthAndFlush(io, 1);
|
|
109
105
|
}
|
|
110
106
|
getParseMessage(args) {
|
|
111
107
|
if (args.statement && args.statement.length > 63)
|
|
112
108
|
throw new Error('Query name length must be lower than 63');
|
|
113
109
|
const { paramTypes } = args;
|
|
114
|
-
const io = this._io
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
.writeUInt16BE(paramTypes?.length || 0);
|
|
110
|
+
const io = this._io.start();
|
|
111
|
+
io.writeInt8(Protocol.FrontendMessageCode.Parse);
|
|
112
|
+
io.writeInt32BE(0); // Preserve header
|
|
113
|
+
io.writeCString(args.statement || '', 'utf8');
|
|
114
|
+
io.writeCString(args.sql, 'utf8');
|
|
115
|
+
io.writeUInt16BE(paramTypes?.length || 0);
|
|
121
116
|
if (paramTypes) {
|
|
122
117
|
let i;
|
|
123
118
|
const l = paramTypes.length;
|
|
@@ -132,19 +127,18 @@ export class Frontend {
|
|
|
132
127
|
throw new Error('Portal name length must be lower than 63');
|
|
133
128
|
if (args.statement && args.statement.length > 63)
|
|
134
129
|
throw new Error('Query name length must be lower than 63');
|
|
135
|
-
const io = this._io
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
.writeCString(args.statement || '', 'utf8');
|
|
130
|
+
const io = this._io.start();
|
|
131
|
+
io.writeInt8(Protocol.FrontendMessageCode.Bind);
|
|
132
|
+
io.writeInt32BE(0); // Preserve header
|
|
133
|
+
io.writeCString(args.portal || '', 'utf8');
|
|
134
|
+
io.writeCString(args.statement || '', 'utf8');
|
|
141
135
|
const { params, paramTypes, queryOptions } = args;
|
|
142
136
|
const columnFormat = queryOptions.columnFormat != null
|
|
143
137
|
? queryOptions.columnFormat
|
|
144
138
|
: DEFAULT_COLUMN_FORMAT;
|
|
145
139
|
if (params && params.length) {
|
|
146
140
|
io.writeInt16BE(params.length);
|
|
147
|
-
const formatOffset = io.
|
|
141
|
+
const formatOffset = io.position;
|
|
148
142
|
const l = params.length;
|
|
149
143
|
let i;
|
|
150
144
|
for (i = 0; i < l; i++) {
|
|
@@ -172,7 +166,7 @@ export class Frontend {
|
|
|
172
166
|
io.buffer.writeInt16BE(Protocol.DataFormat.binary, formatOffset + i * 2);
|
|
173
167
|
// Preserve data length
|
|
174
168
|
io.writeInt32BE(0);
|
|
175
|
-
const dataOffset = io.
|
|
169
|
+
const dataOffset = io.position;
|
|
176
170
|
if (dt.elementsOID) {
|
|
177
171
|
// If data type is array
|
|
178
172
|
v = Array.isArray(v) ? v : [v];
|
|
@@ -181,7 +175,7 @@ export class Frontend {
|
|
|
181
175
|
else {
|
|
182
176
|
dt.encodeBinary(io, v, queryOptions);
|
|
183
177
|
}
|
|
184
|
-
io.buffer.writeInt32BE(io.
|
|
178
|
+
io.buffer.writeInt32BE(io.size - dataOffset, dataOffset - 4); // Update length
|
|
185
179
|
}
|
|
186
180
|
else if (typeof dt.encodeText === 'function') {
|
|
187
181
|
v = dt.elementsOID
|
|
@@ -195,9 +189,9 @@ export class Frontend {
|
|
|
195
189
|
io.buffer.writeInt16BE(Protocol.DataFormat.binary, formatOffset + i * 2);
|
|
196
190
|
// Preserve data length
|
|
197
191
|
io.writeInt32BE(0);
|
|
198
|
-
const dataOffset = io.
|
|
199
|
-
io.
|
|
200
|
-
io.buffer.writeInt32BE(io.
|
|
192
|
+
const dataOffset = io.position;
|
|
193
|
+
io.writeBytes(v);
|
|
194
|
+
io.buffer.writeInt32BE(io.size - dataOffset, dataOffset - 4); // Update length
|
|
201
195
|
}
|
|
202
196
|
else {
|
|
203
197
|
io.writeLString('' + v, 'utf8');
|
|
@@ -230,12 +224,11 @@ export class Frontend {
|
|
|
230
224
|
? 'Portal'
|
|
231
225
|
: 'Statement name length must be lower than 63');
|
|
232
226
|
}
|
|
233
|
-
const io = this._io
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
.writeCString(args.name || '', 'utf8');
|
|
227
|
+
const io = this._io.start();
|
|
228
|
+
io.writeInt8(Protocol.FrontendMessageCode.Describe);
|
|
229
|
+
io.writeInt32BE(0); // Preserve header
|
|
230
|
+
io.writeUInt8(args.type.charCodeAt(0));
|
|
231
|
+
io.writeCString(args.name || '', 'utf8');
|
|
239
232
|
return setLengthAndFlush(io, 1);
|
|
240
233
|
}
|
|
241
234
|
getExecuteMessage(args) {
|
|
@@ -243,12 +236,11 @@ export class Frontend {
|
|
|
243
236
|
(args.fetchCount < 0 || args.fetchCount > 4294967295)) {
|
|
244
237
|
throw new Error('fetchCount can be between 0 and 4294967295');
|
|
245
238
|
}
|
|
246
|
-
const io = this._io
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
.writeUInt32BE(args.fetchCount || 0);
|
|
239
|
+
const io = this._io.start();
|
|
240
|
+
io.writeInt8(Protocol.FrontendMessageCode.Execute);
|
|
241
|
+
io.writeInt32BE(0); // Preserve header
|
|
242
|
+
io.writeCString(args.portal || '', 'utf8');
|
|
243
|
+
io.writeUInt32BE(args.fetchCount || 0);
|
|
252
244
|
return setLengthAndFlush(io, 1);
|
|
253
245
|
}
|
|
254
246
|
getCloseMessage(args) {
|
|
@@ -257,20 +249,18 @@ export class Frontend {
|
|
|
257
249
|
? 'Portal'
|
|
258
250
|
: 'Statement name length must be lower than 63');
|
|
259
251
|
}
|
|
260
|
-
const io = this._io
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
.writeCString(args.name || '', 'utf8');
|
|
252
|
+
const io = this._io.start();
|
|
253
|
+
io.writeInt8(Protocol.FrontendMessageCode.Close);
|
|
254
|
+
io.writeInt32BE(0); // Preserve header
|
|
255
|
+
io.writeUInt8(args.type.charCodeAt(0));
|
|
256
|
+
io.writeCString(args.name || '', 'utf8');
|
|
266
257
|
return setLengthAndFlush(io, 1);
|
|
267
258
|
}
|
|
268
259
|
getQueryMessage(sql) {
|
|
269
|
-
const io = this._io
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
.writeCString(sql || '', 'utf8');
|
|
260
|
+
const io = this._io.start();
|
|
261
|
+
io.writeInt8(Protocol.FrontendMessageCode.Query);
|
|
262
|
+
io.writeInt32BE(0); // Preserve header
|
|
263
|
+
io.writeCString(sql || '', 'utf8');
|
|
274
264
|
return setLengthAndFlush(io, 1);
|
|
275
265
|
}
|
|
276
266
|
getFunctionCallMessage(args) {
|
|
@@ -279,12 +269,11 @@ export class Frontend {
|
|
|
279
269
|
const fl = formats.length;
|
|
280
270
|
const l = values.length;
|
|
281
271
|
let i;
|
|
282
|
-
const io = this._io
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
.writeInt16BE(fl);
|
|
272
|
+
const io = this._io.start();
|
|
273
|
+
io.writeInt8(Protocol.FrontendMessageCode.FunctionCall);
|
|
274
|
+
io.writeInt32BE(0); // Preserve header
|
|
275
|
+
io.writeInt32BE(functionId);
|
|
276
|
+
io.writeInt16BE(fl);
|
|
288
277
|
for (i = 0; i < fl; i++)
|
|
289
278
|
io.writeInt16BE(formats[i]);
|
|
290
279
|
io.writeInt16BE(l);
|
|
@@ -293,8 +282,10 @@ export class Frontend {
|
|
|
293
282
|
v = values[i];
|
|
294
283
|
if (v == null)
|
|
295
284
|
io.writeInt32BE(-1);
|
|
296
|
-
else
|
|
297
|
-
io.writeInt32BE(v.length)
|
|
285
|
+
else {
|
|
286
|
+
io.writeInt32BE(v.length);
|
|
287
|
+
io.writeBytes(v);
|
|
288
|
+
}
|
|
298
289
|
}
|
|
299
290
|
io.writeInt16BE(resultFormat ?? DataFormat.text);
|
|
300
291
|
return setLengthAndFlush(io, 1);
|
|
@@ -315,11 +306,10 @@ export class Frontend {
|
|
|
315
306
|
return StaticCopyDoneBuffer;
|
|
316
307
|
}
|
|
317
308
|
getCopyFailMessage(message) {
|
|
318
|
-
const io = this._io
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
.writeCString(message || '', 'utf8');
|
|
309
|
+
const io = this._io.start();
|
|
310
|
+
io.writeInt8(Protocol.FrontendMessageCode.CopyFail);
|
|
311
|
+
io.writeInt32BE(0); // Preserve header
|
|
312
|
+
io.writeCString(message || '', 'utf8');
|
|
323
313
|
return setLengthAndFlush(io, 1);
|
|
324
314
|
}
|
|
325
315
|
getFlushMessage() {
|
|
@@ -333,6 +323,6 @@ export class Frontend {
|
|
|
333
323
|
}
|
|
334
324
|
}
|
|
335
325
|
function setLengthAndFlush(io, lengthOffset) {
|
|
336
|
-
io.buffer.writeUInt32BE(io.
|
|
326
|
+
io.buffer.writeUInt32BE(io.size - lengthOffset, lengthOffset);
|
|
337
327
|
return io.flush();
|
|
338
328
|
}
|
package/protocol/pg-socket.d.ts
CHANGED
|
@@ -22,8 +22,6 @@ export declare class PgSocket extends SafeEventEmitter {
|
|
|
22
22
|
private _secretKey?;
|
|
23
23
|
private _protocolNegotiation?;
|
|
24
24
|
private _captureQueue;
|
|
25
|
-
private _pendingWrites;
|
|
26
|
-
private _flushScheduled;
|
|
27
25
|
private _hosts;
|
|
28
26
|
private _hostIndex;
|
|
29
27
|
private _sessionAttrsChecked;
|
|
@@ -95,6 +93,37 @@ export declare class PgSocket extends SafeEventEmitter {
|
|
|
95
93
|
bind: Frontend.BindMessageArgs;
|
|
96
94
|
describe: Frontend.DescribeMessageArgs;
|
|
97
95
|
execute: Frontend.ExecuteMessageArgs;
|
|
96
|
+
before?: string;
|
|
97
|
+
after?: string;
|
|
98
|
+
}, cb: CaptureCallback): Promise<any>;
|
|
99
|
+
/**
|
|
100
|
+
* Parse + Bind + Describe(portal) + Execute per statement, then a SINGLE
|
|
101
|
+
* Sync for the lot - the wire shape behind Connection.pipeline().
|
|
102
|
+
*
|
|
103
|
+
* The same framing as sendBatchBindExecuteMessages(), and the same
|
|
104
|
+
* consequences, except that each statement carries its own Parse rather
|
|
105
|
+
* than reusing one prepared statement: the statements share one implicit
|
|
106
|
+
* transaction, and PostgreSQL discards everything between an error and
|
|
107
|
+
* the Sync, so a rejected statement stops the ones behind it.
|
|
108
|
+
*
|
|
109
|
+
* Describe is not optional here even though nothing caches its answer.
|
|
110
|
+
* Without it the server sends DataRows for a row-returning statement with
|
|
111
|
+
* no RowDescription in front of them, leaving the column names and types
|
|
112
|
+
* unknown - the reason the one-shot path in sendExtendedQueryMessages()
|
|
113
|
+
* includes it too. It costs about a quarter of a millisecond across
|
|
114
|
+
* twenty statements, measured.
|
|
115
|
+
*
|
|
116
|
+
* Every Execute is unlimited (fetchCount 0): a portal that suspended
|
|
117
|
+
* mid-pipeline would answer PortalSuspended instead of CommandComplete
|
|
118
|
+
* and desynchronise the positional statement-to-result mapping.
|
|
119
|
+
*/
|
|
120
|
+
sendPipelineMessages(args: {
|
|
121
|
+
statements: {
|
|
122
|
+
parse: Frontend.ParseMessageArgs;
|
|
123
|
+
bind: Frontend.BindMessageArgs;
|
|
124
|
+
describe: Frontend.DescribeMessageArgs;
|
|
125
|
+
execute: Frontend.ExecuteMessageArgs;
|
|
126
|
+
}[];
|
|
98
127
|
}, cb: CaptureCallback): Promise<any>;
|
|
99
128
|
/**
|
|
100
129
|
* Parse + Describe(statement) + Sync as a single round trip - used by
|
|
@@ -119,6 +148,33 @@ export declare class PgSocket extends SafeEventEmitter {
|
|
|
119
148
|
sendBindExecuteMessages(args: {
|
|
120
149
|
bind: Frontend.BindMessageArgs;
|
|
121
150
|
execute: Frontend.ExecuteMessageArgs;
|
|
151
|
+
before?: string;
|
|
152
|
+
after?: string;
|
|
153
|
+
}, cb: CaptureCallback): Promise<any>;
|
|
154
|
+
/**
|
|
155
|
+
* One Bind+Execute pair per parameter set against the same prepared
|
|
156
|
+
* statement, then a SINGLE Sync for the lot - the wire shape behind
|
|
157
|
+
* PreparedStatement.executeBatch().
|
|
158
|
+
*
|
|
159
|
+
* The single Sync is the whole point, and it is also what gives the
|
|
160
|
+
* batch its semantics. Sending Bind/Execute/Sync per set (what N
|
|
161
|
+
* separate execute() calls do, even pipelined) makes the server finish
|
|
162
|
+
* an implicit transaction and answer ReadyForQuery every time; one Sync
|
|
163
|
+
* at the end collapses that to one, which is where the bulk of the
|
|
164
|
+
* speedup comes from. It also means the sets share one implicit
|
|
165
|
+
* transaction, and that PostgreSQL discards everything between an error
|
|
166
|
+
* and the Sync - so a set that fails stops the ones behind it from
|
|
167
|
+
* running at all. Both of those are inherent to this framing rather
|
|
168
|
+
* than choices made above it.
|
|
169
|
+
*
|
|
170
|
+
* Every Execute here must be unlimited (fetchCount 0): a portal that
|
|
171
|
+
* suspends mid-batch would answer PortalSuspended instead of
|
|
172
|
+
* CommandComplete and desynchronise the positional set-to-result
|
|
173
|
+
* mapping the caller relies on.
|
|
174
|
+
*/
|
|
175
|
+
sendBatchBindExecuteMessages(args: {
|
|
176
|
+
binds: Frontend.BindMessageArgs[];
|
|
177
|
+
execute: Frontend.ExecuteMessageArgs;
|
|
122
178
|
}, cb: CaptureCallback): Promise<any>;
|
|
123
179
|
/**
|
|
124
180
|
* Bind + Describe(portal) + Flush as a single round trip (NOT Sync - see
|
|
@@ -195,6 +251,24 @@ export declare class PgSocket extends SafeEventEmitter {
|
|
|
195
251
|
* "start listening" step to race or misuse.
|
|
196
252
|
*/
|
|
197
253
|
private _sendAndCapture;
|
|
254
|
+
/**
|
|
255
|
+
* Parse + Bind + Execute for a parameterless utility statement, appended
|
|
256
|
+
* to a message list that is about to be closed by one Sync - how
|
|
257
|
+
* sendBindExecuteMessages() and sendExtendedQueryMessages() carry their
|
|
258
|
+
* `before`/`after` SQL (today, SAVEPOINT and RELEASE) in the same round
|
|
259
|
+
* trip as the statement itself rather than as a round trip each.
|
|
260
|
+
*
|
|
261
|
+
* Everything here goes through the unnamed statement and the unnamed
|
|
262
|
+
* portal. That is safe in this order: the caller's own Bind names a
|
|
263
|
+
* prepared statement rather than the unnamed one, and PostgreSQL
|
|
264
|
+
* processes the messages in sequence, so each Bind only ever discards an
|
|
265
|
+
* unnamed portal whose Execute has already run.
|
|
266
|
+
*
|
|
267
|
+
* No Describe: neither statement returns rows, so there is no
|
|
268
|
+
* RowDescription worth asking for. Result formats come from the caller's
|
|
269
|
+
* own Bind args, which likewise cost nothing against no columns.
|
|
270
|
+
*/
|
|
271
|
+
private _pushUtilityStatement;
|
|
198
272
|
protected _removeListeners(): void;
|
|
199
273
|
protected _reset(): void;
|
|
200
274
|
protected _handleConnect(): void;
|
|
@@ -235,39 +309,14 @@ export declare class PgSocket extends SafeEventEmitter {
|
|
|
235
309
|
protected _handleNegotiateProtocolVersion(msg: Protocol.NegotiateProtocolVersionMessage): void;
|
|
236
310
|
protected _handleBackendKeyData(msg: Protocol.BackendKeyDataMessage): void;
|
|
237
311
|
protected _handleCommandComplete(msg: any): Protocol.CommandCompleteMessage;
|
|
238
|
-
/**
|
|
239
|
-
* Queues `data` for the socket instead of writing it straight through:
|
|
240
|
-
* everything handed to _send() during the same synchronous burst (e.g.
|
|
241
|
-
* many concurrent query() calls fired via Promise.all over one
|
|
242
|
-
* connection) is flushed together on the next tick, corked, so Node
|
|
243
|
-
* turns the whole batch into a single underlying writev rather than one
|
|
244
|
-
* socket write per call. Measured against postgres.js, which coalesces
|
|
245
|
-
* the same way at the application level (its connection.js write()/
|
|
246
|
-
* nextWrite() pair, flushing on a 1KB threshold or setImmediate): 50
|
|
247
|
-
* concurrent prepared executes cost it 3 socket writes where this cost
|
|
248
|
-
* us 50, and that write path was the single largest non-idle item in a
|
|
249
|
-
* CPU profile of the scenario.
|
|
250
|
-
*
|
|
251
|
-
* nextTick rather than setImmediate, deliberately: it still batches a
|
|
252
|
-
* whole synchronous burst, but a lone query doesn't have to wait for the
|
|
253
|
-
* event loop's check phase before its bytes go out - which would trade
|
|
254
|
-
* away the sequential/single-query scenarios to win the concurrent ones.
|
|
255
|
-
*
|
|
256
|
-
* Returns whether the socket could accept the data at all; the write
|
|
257
|
-
* itself is reported through `cb` (and a socket that dies before the
|
|
258
|
-
* flush rejects every pending capture via _failPendingCaptures()).
|
|
259
|
-
*/
|
|
260
312
|
protected _send(data: Buffer | Buffer[], cb?: Callback): boolean;
|
|
261
313
|
/**
|
|
262
|
-
*
|
|
263
|
-
*
|
|
264
|
-
*
|
|
265
|
-
*
|
|
266
|
-
*
|
|
267
|
-
*
|
|
268
|
-
* deferred write cannot give it.
|
|
314
|
+
* Same write as _send(), but reporting backpressure instead of
|
|
315
|
+
* writability: a COPY IN producer needs write()'s own return value to
|
|
316
|
+
* know when to stop pushing, whereas _send()'s callers only need to know
|
|
317
|
+
* whether the socket could take the bytes at all. Kept separate rather
|
|
318
|
+
* than folded into _send() precisely so those two meanings of `false`
|
|
319
|
+
* cannot be confused at a call site.
|
|
269
320
|
*/
|
|
270
321
|
protected _sendCopy(data: Buffer | Buffer[], cb?: Callback): boolean;
|
|
271
|
-
/** Arrow property, not a method: used as a bare process.nextTick callback. */
|
|
272
|
-
private _flushPendingWrites;
|
|
273
322
|
}
|