@steadybrew/postgresjs 3.4.9 → 4.0.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 +27 -3
- package/cf/polyfills.js +27 -9
- package/cf/src/connection.js +487 -224
- package/cf/src/index.js +137 -57
- package/cf/src/types.js +26 -3
- package/cjs/src/connection.js +487 -224
- package/cjs/src/index.js +137 -57
- package/cjs/src/types.js +26 -3
- package/package.json +11 -8
- package/src/connection.js +487 -224
- package/src/index.js +137 -57
- package/src/types.js +26 -3
package/cjs/src/connection.js
CHANGED
|
@@ -4,7 +4,7 @@ const crypto = require('crypto')
|
|
|
4
4
|
const Stream = require('stream')
|
|
5
5
|
const { performance } = require('perf_hooks')
|
|
6
6
|
|
|
7
|
-
const { stringify, handleValue,
|
|
7
|
+
const { stringify, handleValue, addArrayType } = require('./types.js')
|
|
8
8
|
const { Errors } = require('./errors.js')
|
|
9
9
|
const Result = require('./result.js')
|
|
10
10
|
const Queue = require('./queue.js')
|
|
@@ -22,6 +22,8 @@ const Sync = b().S().end()
|
|
|
22
22
|
, DescribeUnnamed = b().D().str('S').str(b.N).end()
|
|
23
23
|
, noop = () => { /* noop */ }
|
|
24
24
|
|
|
25
|
+
const Phase = { Closed: 0, Backoff: 1, Opening: 2, Negotiating: 3, Authenticating: 4, Initializing: 5, Ready: 6, Draining: 7, Closing: 8 }
|
|
26
|
+
|
|
25
27
|
const retryRoutines = new Set([
|
|
26
28
|
'FetchPreparedStatement',
|
|
27
29
|
'RevalidateCachedQuery',
|
|
@@ -49,7 +51,7 @@ const errorFields = {
|
|
|
49
51
|
82 : 'routine' // R
|
|
50
52
|
}
|
|
51
53
|
|
|
52
|
-
function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose = noop } = {}) {
|
|
54
|
+
function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose = noop, ondrain = noop } = {}) {
|
|
53
55
|
const {
|
|
54
56
|
sslnegotiation,
|
|
55
57
|
ssl,
|
|
@@ -74,10 +76,16 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
|
|
|
74
76
|
, backend = { pid: null, secret: null }
|
|
75
77
|
, idleTimer = timer(end, options.idle_timeout)
|
|
76
78
|
, lifeTimer = timer(end, options.max_lifetime)
|
|
77
|
-
, connectTimer = timer(connectTimedOut, options.connect_timeout)
|
|
78
79
|
|
|
79
80
|
let socket = null
|
|
80
|
-
,
|
|
81
|
+
, phase = Phase.Closed
|
|
82
|
+
, generation = 0
|
|
83
|
+
, acquisition = null
|
|
84
|
+
, endRequested = false
|
|
85
|
+
, endWaiters = []
|
|
86
|
+
, inheritedBackoff = null
|
|
87
|
+
, backoffTimer = null
|
|
88
|
+
, connectTimer = null
|
|
81
89
|
, errorResponse = null
|
|
82
90
|
, result = new Result()
|
|
83
91
|
, incoming = Buffer.alloc(0)
|
|
@@ -86,23 +94,16 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
|
|
|
86
94
|
, statements = {}
|
|
87
95
|
, statementId = Math.random().toString(36).slice(2)
|
|
88
96
|
, statementCount = 1
|
|
89
|
-
, closedTime = 0
|
|
90
97
|
, remaining = 0
|
|
91
98
|
, hostIndex = 0
|
|
92
|
-
, retries = 0
|
|
93
99
|
, length = 0
|
|
94
|
-
, delay = 0
|
|
95
100
|
, rows = 0
|
|
96
101
|
, serverSignature = null
|
|
97
102
|
, nextWriteTimer = null
|
|
98
|
-
, terminated = false
|
|
99
103
|
, incomings = null
|
|
100
104
|
, results = null
|
|
101
|
-
, initial = null
|
|
102
|
-
, ending = null
|
|
103
105
|
, stream = null
|
|
104
106
|
, chunk = null
|
|
105
|
-
, ended = null
|
|
106
107
|
, nonce = null
|
|
107
108
|
, query = null
|
|
108
109
|
, final = null
|
|
@@ -110,13 +111,11 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
|
|
|
110
111
|
const connection = {
|
|
111
112
|
queue: queues.closed,
|
|
112
113
|
idleTimer,
|
|
113
|
-
connect
|
|
114
|
-
initial = query
|
|
115
|
-
reconnect()
|
|
116
|
-
},
|
|
114
|
+
connect: acquire,
|
|
117
115
|
terminate,
|
|
118
116
|
execute,
|
|
119
117
|
cancel,
|
|
118
|
+
release,
|
|
120
119
|
end,
|
|
121
120
|
count: 0,
|
|
122
121
|
id
|
|
@@ -126,36 +125,320 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
|
|
|
126
125
|
|
|
127
126
|
return connection
|
|
128
127
|
|
|
129
|
-
|
|
130
|
-
|
|
128
|
+
function transition(next) {
|
|
129
|
+
generation++
|
|
130
|
+
phase = next
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function starting() {
|
|
134
|
+
return phase >= Phase.Opening && phase <= Phase.Initializing
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function held() {
|
|
138
|
+
return connection.reserved || connection.queue === queues.reserved
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function drained() {
|
|
142
|
+
ondrain(connection) || closing(true)
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function idle() {
|
|
146
|
+
return !query && sent.length === 0
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function backoffMs() {
|
|
150
|
+
return (typeof backoff === 'function' ? backoff(options.shared.retries) : backoff) * 1000
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function acquire(owner) {
|
|
154
|
+
if (phase !== Phase.Closed)
|
|
155
|
+
return queryError(owner, Errors.connection('CONNECTION_CLOSED', options))
|
|
156
|
+
|
|
157
|
+
acquisition = { owner, attempts: 0, hostsTried: 0, lastError: null, deadline: null, expired: false }
|
|
158
|
+
const wait = inheritedBackoff ? inheritedBackoff.at + inheritedBackoff.delay - performance.now() : 0
|
|
159
|
+
inheritedBackoff = null
|
|
160
|
+
wait > 0 ? enterBackoff(wait) : enterOpening()
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function enterBackoff(ms) {
|
|
164
|
+
transition(Phase.Backoff)
|
|
165
|
+
const a = acquisition
|
|
166
|
+
const attempt = generation
|
|
167
|
+
const left = a.deadline === null ? Infinity : Math.max(0, a.deadline - performance.now())
|
|
168
|
+
a.expired = left <= ms
|
|
169
|
+
backoffTimer = setTimeout(() => {
|
|
170
|
+
backoffTimer = null
|
|
171
|
+
attempt === generation && (a.expired
|
|
172
|
+
? enterClosed(a.lastError || Errors.connection('CONNECT_TIMEOUT', options))
|
|
173
|
+
: enterOpening())
|
|
174
|
+
}, Math.min(ms, left))
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function enterOpening() {
|
|
178
|
+
transition(Phase.Opening)
|
|
179
|
+
const a = acquisition
|
|
180
|
+
const attempt = generation
|
|
181
|
+
const ms = options.connect_timeout * 1000
|
|
182
|
+
if (ms) {
|
|
183
|
+
const now = performance.now()
|
|
184
|
+
a.deadline === null && (a.deadline = now + ms * host.length)
|
|
185
|
+
const left = a.deadline - now
|
|
186
|
+
connectTimer = setTimeout(() => connectTimedOut(left <= ms), Math.min(ms, left))
|
|
187
|
+
}
|
|
188
|
+
a.hostsTried++
|
|
189
|
+
backendParameters = {}
|
|
190
|
+
Promise.resolve()
|
|
191
|
+
.then(() => options.socket ? options.socket(options) : new net.Socket())
|
|
192
|
+
.then(created => attempt === generation ? attach(created) : dispose(created))
|
|
193
|
+
.catch(err => attempt === generation && fail(err))
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function dispose(created) {
|
|
197
|
+
created.on('error', noop)
|
|
198
|
+
created.destroy()
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function attach(created) {
|
|
202
|
+
socket = created
|
|
203
|
+
created.on('error', error)
|
|
204
|
+
created.on('close', closed)
|
|
205
|
+
created.on('drain', drain)
|
|
206
|
+
|
|
207
|
+
if (options.socket)
|
|
208
|
+
return ssl ? negotiate() : authenticate()
|
|
209
|
+
|
|
210
|
+
created.on('connect', ssl ? negotiate : authenticate)
|
|
211
|
+
|
|
212
|
+
if (options.path)
|
|
213
|
+
return created.connect(options.path)
|
|
214
|
+
|
|
215
|
+
created.ssl = ssl
|
|
216
|
+
created.connect(port[hostIndex], host[hostIndex])
|
|
217
|
+
created.host = host[hostIndex]
|
|
218
|
+
created.port = port[hostIndex]
|
|
219
|
+
|
|
220
|
+
hostIndex = (hostIndex + 1) % port.length
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function negotiate() {
|
|
224
|
+
transition(Phase.Negotiating)
|
|
225
|
+
if (sslnegotiation === 'direct')
|
|
226
|
+
return upgrade()
|
|
227
|
+
|
|
228
|
+
const attempt = generation
|
|
229
|
+
socket.once('data', x => attempt === generation && (
|
|
230
|
+
x[0] === 83
|
|
231
|
+
? upgrade()
|
|
232
|
+
: ssl === 'prefer'
|
|
233
|
+
? authenticate()
|
|
234
|
+
: fail(Errors.generic('SSL_NOT_SUPPORTED', 'The server does not support SSL connections'))
|
|
235
|
+
))
|
|
236
|
+
write(SSLRequest)
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
function upgrade() {
|
|
240
|
+
try {
|
|
241
|
+
const raw = socket
|
|
242
|
+
const config = tlsConfig(raw)
|
|
243
|
+
raw.removeAllListeners()
|
|
244
|
+
socket = tls.connect(config)
|
|
245
|
+
socket.on('secureConnect', authenticate)
|
|
246
|
+
socket.on('error', error)
|
|
247
|
+
socket.on('close', closed)
|
|
248
|
+
socket.on('drain', drain)
|
|
249
|
+
} catch (err) {
|
|
250
|
+
fail(err)
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
function tlsConfig(raw) {
|
|
255
|
+
const config = {
|
|
256
|
+
socket: raw,
|
|
257
|
+
servername: net.isIP(raw.host) ? undefined : raw.host
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
if (sslnegotiation === 'direct')
|
|
261
|
+
config.ALPNProtocols = ['postgresql']
|
|
262
|
+
|
|
263
|
+
if (ssl === 'require' || ssl === 'allow' || ssl === 'prefer')
|
|
264
|
+
config.rejectUnauthorized = false
|
|
265
|
+
else if (typeof ssl === 'object')
|
|
266
|
+
Object.assign(config, ssl)
|
|
267
|
+
|
|
268
|
+
return config
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
function authenticate() {
|
|
272
|
+
transition(Phase.Authenticating)
|
|
131
273
|
try {
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
274
|
+
statements = {}
|
|
275
|
+
needsTypes = options.fetch_types
|
|
276
|
+
statementId = Math.random().toString(36).slice(2)
|
|
277
|
+
statementCount = 1
|
|
278
|
+
lifeTimer.start()
|
|
279
|
+
socket.on('data', data)
|
|
280
|
+
keep_alive && socket.setKeepAlive && socket.setKeepAlive(true, 1000 * keep_alive)
|
|
281
|
+
write(StartupMessage())
|
|
282
|
+
} catch (err) {
|
|
283
|
+
fail(err)
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
function connectTimedOut(expiring) {
|
|
288
|
+
connectTimer = null
|
|
289
|
+
if (!starting())
|
|
137
290
|
return
|
|
291
|
+
expiring && (acquisition.expired = true)
|
|
292
|
+
fail(Errors.connection('CONNECT_TIMEOUT', options, socket), true)
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
function fail(err, persist = host.length > 1) {
|
|
296
|
+
const a = acquisition
|
|
297
|
+
a.attempts++
|
|
298
|
+
a.lastError = err && err.code === 'CONNECT_TIMEOUT' && a.lastError ? a.lastError : err
|
|
299
|
+
clearTimeout(connectTimer)
|
|
300
|
+
connectTimer = null
|
|
301
|
+
detach()
|
|
302
|
+
resetSocketState(err)
|
|
303
|
+
|
|
304
|
+
if (endRequested)
|
|
305
|
+
return enterClosed(err)
|
|
306
|
+
|
|
307
|
+
if (a.expired || (a.deadline !== null && performance.now() >= a.deadline))
|
|
308
|
+
return enterClosed(a.lastError)
|
|
309
|
+
|
|
310
|
+
if (a.hostsTried < host.length)
|
|
311
|
+
return enterBackoff(0)
|
|
312
|
+
|
|
313
|
+
options.shared.retries++
|
|
314
|
+
if (!persist) {
|
|
315
|
+
inheritedBackoff = { at: performance.now(), delay: backoffMs() }
|
|
316
|
+
return enterClosed(err)
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
a.hostsTried = 0
|
|
320
|
+
enterBackoff(backoffMs())
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
function detach() {
|
|
324
|
+
clearTimeout(connectTimer)
|
|
325
|
+
connectTimer = null
|
|
326
|
+
idleTimer.cancel()
|
|
327
|
+
lifeTimer.cancel()
|
|
328
|
+
incoming = Buffer.alloc(0)
|
|
329
|
+
remaining = 0
|
|
330
|
+
incomings = null
|
|
331
|
+
if (socket) {
|
|
332
|
+
socket.removeAllListeners()
|
|
333
|
+
socket.on('error', noop)
|
|
334
|
+
socket.destroy()
|
|
335
|
+
socket = null
|
|
138
336
|
}
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
function enterClosed(err = Errors.connection('CONNECTION_CLOSED', options, socket)) {
|
|
340
|
+
if (phase === Phase.Closed)
|
|
341
|
+
return
|
|
342
|
+
|
|
343
|
+
const a = acquisition
|
|
344
|
+
const waiters = endWaiters
|
|
345
|
+
clearTimeout(backoffTimer)
|
|
346
|
+
backoffTimer = null
|
|
347
|
+
detach()
|
|
348
|
+
resetSocketState(err)
|
|
349
|
+
acquisition = null
|
|
350
|
+
endRequested = false
|
|
351
|
+
endWaiters = []
|
|
352
|
+
transition(Phase.Closed)
|
|
353
|
+
a && queryError(a.owner, err)
|
|
354
|
+
waiters.forEach(resolve => resolve())
|
|
355
|
+
onclose(connection, err)
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
function closing(quit) {
|
|
359
|
+
transition(Phase.Closing)
|
|
360
|
+
idleTimer.cancel()
|
|
361
|
+
lifeTimer.cancel()
|
|
362
|
+
quit && socket.readyState === 'open'
|
|
363
|
+
? socket.end(b().X().end())
|
|
364
|
+
: socket.destroy()
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
function handoff() {
|
|
368
|
+
const owner = acquisition.owner
|
|
369
|
+
transition(Phase.Ready)
|
|
370
|
+
clearTimeout(connectTimer)
|
|
371
|
+
connectTimer = null
|
|
372
|
+
acquisition = null
|
|
373
|
+
options.shared.retries = 0
|
|
374
|
+
|
|
375
|
+
if (endRequested) {
|
|
376
|
+
endRequested = false
|
|
377
|
+
if (owner.reserve)
|
|
378
|
+
return (queryError(owner, Errors.connection('CONNECTION_ENDED', options)), closing(true))
|
|
379
|
+
if (owner.cancelled)
|
|
380
|
+
return closing(true)
|
|
381
|
+
transition(Phase.Draining)
|
|
382
|
+
return execute(owner)
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
owner.reserve
|
|
386
|
+
? onopen(connection, owner)
|
|
387
|
+
: owner.cancelled
|
|
388
|
+
? onopen(connection)
|
|
389
|
+
: execute(owner)
|
|
143
390
|
}
|
|
144
391
|
|
|
145
392
|
async function cancel({ pid, secret }, resolve, reject) {
|
|
393
|
+
let timeout = null
|
|
146
394
|
try {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
395
|
+
let s = await Promise.resolve(options.socket ? options.socket(options) : new net.Socket())
|
|
396
|
+
const request = b().i32(16).i32(80877102).i32(pid).i32(secret).end(16)
|
|
397
|
+
const watch = x => {
|
|
398
|
+
x.once('error', reject)
|
|
399
|
+
x.on('error', noop)
|
|
400
|
+
x.once('close', () => (clearTimeout(timeout), resolve()))
|
|
401
|
+
}
|
|
402
|
+
const upgrade = () => {
|
|
403
|
+
const raw = s
|
|
404
|
+
const config = tlsConfig(raw)
|
|
405
|
+
raw.removeAllListeners()
|
|
406
|
+
s = tls.connect(config)
|
|
407
|
+
watch(s)
|
|
408
|
+
s.once('secureConnect', () => s.write(request))
|
|
409
|
+
}
|
|
410
|
+
const start = !ssl
|
|
411
|
+
? () => s.write(request)
|
|
412
|
+
: sslnegotiation === 'direct'
|
|
413
|
+
? upgrade
|
|
414
|
+
: () => {
|
|
415
|
+
s.once('data', x => x[0] === 83 || ssl !== 'prefer' ? upgrade() : s.write(request))
|
|
416
|
+
s.write(SSLRequest)
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
watch(s)
|
|
420
|
+
options.connect_timeout && (timeout = setTimeout(() => s.destroy(), options.connect_timeout * 1000))
|
|
421
|
+
|
|
422
|
+
if (options.socket)
|
|
423
|
+
return start()
|
|
424
|
+
|
|
425
|
+
s.once('connect', start)
|
|
426
|
+
|
|
427
|
+
if (options.path)
|
|
428
|
+
return s.connect(options.path)
|
|
429
|
+
|
|
430
|
+
s.ssl = ssl
|
|
431
|
+
s.connect(port[0], host[0])
|
|
432
|
+
s.host = host[0]
|
|
433
|
+
s.port = port[0]
|
|
151
434
|
} catch (error) {
|
|
152
435
|
reject(error)
|
|
153
436
|
}
|
|
154
437
|
}
|
|
155
438
|
|
|
156
439
|
function execute(q) {
|
|
157
|
-
if (
|
|
158
|
-
return queryError(q, Errors.connection('
|
|
440
|
+
if (phase !== Phase.Ready && phase !== Phase.Draining && !(phase === Phase.Initializing && q.initialization))
|
|
441
|
+
return queryError(q, Errors.connection('CONNECTION_CLOSED', options))
|
|
159
442
|
|
|
160
443
|
if (stream)
|
|
161
444
|
return queryError(q, Errors.generic('COPY_IN_PROGRESS', 'You cannot execute queries during copy'))
|
|
@@ -174,7 +457,6 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
|
|
|
174
457
|
&& !q.describeFirst
|
|
175
458
|
&& !q.cursorFn
|
|
176
459
|
&& sent.length < max_pipeline
|
|
177
|
-
&& (!q.options.onexecute || q.options.onexecute(connection))
|
|
178
460
|
} catch (error) {
|
|
179
461
|
sent.length === 0 && write(Sync)
|
|
180
462
|
errored(error)
|
|
@@ -252,50 +534,28 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
|
|
|
252
534
|
}
|
|
253
535
|
|
|
254
536
|
function nextWrite(fn) {
|
|
255
|
-
const x = socket.write(chunk, fn)
|
|
537
|
+
const x = socket ? socket.write(chunk, fn) : false
|
|
256
538
|
nextWriteTimer !== null && clearImmediate(nextWriteTimer)
|
|
257
539
|
chunk = nextWriteTimer = null
|
|
258
540
|
return x
|
|
259
541
|
}
|
|
260
542
|
|
|
261
|
-
function
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
return connected()
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
const options = {
|
|
276
|
-
socket,
|
|
277
|
-
servername: net.isIP(socket.host) ? undefined : socket.host
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
if (sslnegotiation === 'direct')
|
|
281
|
-
options.ALPNProtocols = ['postgresql']
|
|
282
|
-
|
|
283
|
-
if (ssl === 'require' || ssl === 'allow' || ssl === 'prefer')
|
|
284
|
-
options.rejectUnauthorized = false
|
|
285
|
-
else if (typeof ssl === 'object')
|
|
286
|
-
Object.assign(options, ssl)
|
|
287
|
-
|
|
288
|
-
socket.removeAllListeners()
|
|
289
|
-
socket = tls.connect(options)
|
|
290
|
-
socket.on('secureConnect', connected)
|
|
291
|
-
socket.on('error', error)
|
|
292
|
-
socket.on('close', closed)
|
|
293
|
-
socket.on('drain', drain)
|
|
543
|
+
function resetSocketState(err) {
|
|
544
|
+
clearImmediate(nextWriteTimer)
|
|
545
|
+
stream && (stream.destroy(err), stream = null)
|
|
546
|
+
final && (final(err), final = null)
|
|
547
|
+
query && queryError(query, err)
|
|
548
|
+
while (sent.length)
|
|
549
|
+
queryError(sent.shift(), err)
|
|
550
|
+
query = results = errorResponse = chunk = nextWriteTimer = null
|
|
551
|
+
result = new Result()
|
|
552
|
+
rows = 0
|
|
553
|
+
nonce = serverSignature = null
|
|
294
554
|
}
|
|
295
555
|
|
|
296
556
|
/* c8 ignore next 3 */
|
|
297
557
|
function drain() {
|
|
298
|
-
!query && onopen(connection)
|
|
558
|
+
phase === Phase.Ready && !query && !held() && onopen(connection)
|
|
299
559
|
}
|
|
300
560
|
|
|
301
561
|
function data(x) {
|
|
@@ -312,6 +572,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
|
|
|
312
572
|
? x
|
|
313
573
|
: Buffer.concat([incoming, x], incoming.length + x.length)
|
|
314
574
|
|
|
575
|
+
const source = socket
|
|
315
576
|
while (incoming.length > 4) {
|
|
316
577
|
length = incoming.readUInt32BE(1)
|
|
317
578
|
if (length >= incoming.length) {
|
|
@@ -324,73 +585,37 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
|
|
|
324
585
|
handle(incoming.subarray(0, length + 1))
|
|
325
586
|
} catch (e) {
|
|
326
587
|
query && (query.cursorFn || query.describeFirst) && write(Sync)
|
|
327
|
-
errored(e)
|
|
588
|
+
starting() ? fail(e) : errored(e)
|
|
328
589
|
}
|
|
590
|
+
if (socket !== source)
|
|
591
|
+
return
|
|
329
592
|
incoming = incoming.subarray(length + 1)
|
|
330
593
|
remaining = 0
|
|
331
594
|
incomings = null
|
|
332
595
|
}
|
|
333
596
|
}
|
|
334
597
|
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
socket || (socket = await createSocket())
|
|
339
|
-
|
|
340
|
-
if (!socket)
|
|
341
|
-
return
|
|
342
|
-
|
|
343
|
-
connectTimer.start()
|
|
344
|
-
|
|
345
|
-
if (options.socket)
|
|
346
|
-
return ssl ? secure() : connected()
|
|
347
|
-
|
|
348
|
-
socket.on('connect', ssl ? secure : connected)
|
|
349
|
-
|
|
350
|
-
if (options.path)
|
|
351
|
-
return socket.connect(options.path)
|
|
352
|
-
|
|
353
|
-
socket.ssl = ssl
|
|
354
|
-
socket.connect(port[hostIndex], host[hostIndex])
|
|
355
|
-
socket.host = host[hostIndex]
|
|
356
|
-
socket.port = port[hostIndex]
|
|
357
|
-
|
|
358
|
-
hostIndex = (hostIndex + 1) % port.length
|
|
359
|
-
}
|
|
598
|
+
function error(err) {
|
|
599
|
+
if (starting())
|
|
600
|
+
return fail(err)
|
|
360
601
|
|
|
361
|
-
|
|
362
|
-
|
|
602
|
+
if (phase === Phase.Ready || phase === Phase.Draining)
|
|
603
|
+
socketFailed(err)
|
|
363
604
|
}
|
|
364
605
|
|
|
365
|
-
function
|
|
366
|
-
try {
|
|
367
|
-
statements = {}
|
|
368
|
-
needsTypes = options.fetch_types
|
|
369
|
-
statementId = Math.random().toString(36).slice(2)
|
|
370
|
-
statementCount = 1
|
|
371
|
-
lifeTimer.start()
|
|
372
|
-
socket.on('data', data)
|
|
373
|
-
keep_alive && socket.setKeepAlive && socket.setKeepAlive(true, 1000 * keep_alive)
|
|
374
|
-
const s = StartupMessage()
|
|
375
|
-
write(s)
|
|
376
|
-
} catch (err) {
|
|
377
|
-
error(err)
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
function error(err) {
|
|
382
|
-
if (connection.queue === queues.connecting && options.host[retries + 1])
|
|
383
|
-
return
|
|
384
|
-
|
|
606
|
+
function socketFailed(err) {
|
|
385
607
|
errored(err)
|
|
386
608
|
while (sent.length)
|
|
387
609
|
queryError(sent.shift(), err)
|
|
610
|
+
query = null
|
|
611
|
+
options.shared.retries++
|
|
612
|
+
inheritedBackoff = { at: performance.now(), delay: backoffMs() }
|
|
613
|
+
closing(false)
|
|
388
614
|
}
|
|
389
615
|
|
|
390
616
|
function errored(err) {
|
|
391
617
|
stream && (stream.destroy(err), stream = null)
|
|
392
618
|
query && queryError(query, err)
|
|
393
|
-
initial && (queryError(initial, err), initial = null)
|
|
394
619
|
}
|
|
395
620
|
|
|
396
621
|
function queryError(query, err) {
|
|
@@ -411,52 +636,67 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
|
|
|
411
636
|
}
|
|
412
637
|
|
|
413
638
|
function end() {
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
!connection.reserved && !initial && !query && sent.length === 0
|
|
417
|
-
? (terminate(), new Promise(r => socket && socket.readyState !== 'closed' ? socket.once('close', r) : r()))
|
|
418
|
-
: ending = new Promise(r => ended = r)
|
|
419
|
-
)
|
|
420
|
-
}
|
|
639
|
+
if (phase === Phase.Closed)
|
|
640
|
+
return Promise.resolve()
|
|
421
641
|
|
|
422
|
-
|
|
423
|
-
terminated = true
|
|
424
|
-
if (stream || query || initial || sent.length)
|
|
425
|
-
error(Errors.connection('CONNECTION_DESTROYED', options))
|
|
642
|
+
const done = new Promise(resolve => endWaiters.push(resolve))
|
|
426
643
|
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
644
|
+
if (phase === Phase.Closing || phase === Phase.Draining)
|
|
645
|
+
return done
|
|
646
|
+
|
|
647
|
+
if (phase === Phase.Ready) {
|
|
648
|
+
!held() && onend(connection)
|
|
649
|
+
idle() && !held()
|
|
650
|
+
? closing(true)
|
|
651
|
+
: transition(Phase.Draining)
|
|
652
|
+
return done
|
|
432
653
|
}
|
|
433
|
-
|
|
654
|
+
|
|
655
|
+
if (acquisition.owner.reserve)
|
|
656
|
+
enterClosed(Errors.connection('CONNECTION_ENDED', options))
|
|
657
|
+
else if (phase === Phase.Backoff && acquisition.attempts > 0)
|
|
658
|
+
enterClosed(acquisition.lastError)
|
|
659
|
+
else if (!endRequested)
|
|
660
|
+
(endRequested = true, onend(connection))
|
|
661
|
+
|
|
662
|
+
return done
|
|
434
663
|
}
|
|
435
664
|
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
incomings = null
|
|
440
|
-
clearImmediate(nextWriteTimer)
|
|
441
|
-
socket.removeListener('data', data)
|
|
442
|
-
socket.removeListener('connect', connected)
|
|
443
|
-
idleTimer.cancel()
|
|
444
|
-
lifeTimer.cancel()
|
|
445
|
-
connectTimer.cancel()
|
|
665
|
+
function terminate() {
|
|
666
|
+
if (phase === Phase.Closed)
|
|
667
|
+
return
|
|
446
668
|
|
|
447
|
-
|
|
448
|
-
|
|
669
|
+
const destroyed = Errors.connection('CONNECTION_DESTROYED', options, socket)
|
|
670
|
+
if (phase === Phase.Closing)
|
|
671
|
+
return socket.destroy()
|
|
449
672
|
|
|
450
|
-
if (
|
|
451
|
-
return
|
|
673
|
+
if (phase !== Phase.Ready && phase !== Phase.Draining)
|
|
674
|
+
return enterClosed(destroyed)
|
|
452
675
|
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
delay = (typeof backoff === 'function' ? backoff(options.shared.retries) : backoff) * 1000
|
|
457
|
-
onclose(connection, Errors.connection('CONNECTION_CLOSED', options, socket))
|
|
676
|
+
const inflight = !idle()
|
|
677
|
+
resetSocketState(destroyed)
|
|
678
|
+
enterClosed(inflight ? destroyed : undefined)
|
|
458
679
|
}
|
|
459
680
|
|
|
681
|
+
function release() {
|
|
682
|
+
phase === Phase.Ready
|
|
683
|
+
? onopen(connection)
|
|
684
|
+
: phase === Phase.Draining && idle() && drained()
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
function closed(hadError) {
|
|
688
|
+
const err = Errors.connection('CONNECTION_CLOSED', options, socket)
|
|
689
|
+
if (starting())
|
|
690
|
+
return fail(errorResponse || err, true)
|
|
691
|
+
|
|
692
|
+
if (!inheritedBackoff && (phase !== Phase.Closing || hadError)) {
|
|
693
|
+
hadError && options.shared.retries++
|
|
694
|
+
inheritedBackoff = { at: performance.now(), delay: backoffMs() }
|
|
695
|
+
}
|
|
696
|
+
enterClosed(err)
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
|
|
460
700
|
/* Handlers */
|
|
461
701
|
function handle(xs, x = xs[0]) {
|
|
462
702
|
(
|
|
@@ -495,6 +735,8 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
|
|
|
495
735
|
let column
|
|
496
736
|
let value
|
|
497
737
|
|
|
738
|
+
const valueFrom = !query.initialization && transform.value.from
|
|
739
|
+
const rowFrom = !query.initialization && transform.row.from
|
|
498
740
|
const row = query.isRaw ? new Array(query.statement.columns.length) : {}
|
|
499
741
|
for (let i = 0; i < query.statement.columns.length; i++) {
|
|
500
742
|
column = query.statement.columns[i]
|
|
@@ -514,13 +756,13 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
|
|
|
514
756
|
query.isRaw
|
|
515
757
|
? (row[i] = query.isRaw === true
|
|
516
758
|
? value
|
|
517
|
-
:
|
|
518
|
-
: (row[column.name] =
|
|
759
|
+
: valueFrom ? transform.value.from(value, column) : value)
|
|
760
|
+
: (row[column.name] = valueFrom ? transform.value.from(value, column) : value)
|
|
519
761
|
}
|
|
520
762
|
|
|
521
763
|
query.forEachFn
|
|
522
|
-
? query.forEachFn(
|
|
523
|
-
: (result[rows++] =
|
|
764
|
+
? query.forEachFn(rowFrom ? transform.row.from(row) : row, result)
|
|
765
|
+
: (result[rows++] = rowFrom ? transform.row.from(row) : row)
|
|
524
766
|
}
|
|
525
767
|
|
|
526
768
|
function ParameterStatus(x) {
|
|
@@ -535,12 +777,15 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
|
|
|
535
777
|
function ReadyForQuery(x) {
|
|
536
778
|
if (query) {
|
|
537
779
|
if (errorResponse) {
|
|
780
|
+
if (query.initialization)
|
|
781
|
+
return enterClosed(errorResponse)
|
|
538
782
|
query.retried
|
|
539
783
|
? errored(query.retried)
|
|
540
784
|
: query.prepared && retryRoutines.has(errorResponse.routine)
|
|
541
785
|
? retry(query, errorResponse)
|
|
542
786
|
: errored(errorResponse)
|
|
543
787
|
} else {
|
|
788
|
+
query.initialization && query.initialization(results || result)
|
|
544
789
|
query.resolve(results || result)
|
|
545
790
|
}
|
|
546
791
|
} else if (errorResponse) {
|
|
@@ -549,44 +794,46 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
|
|
|
549
794
|
|
|
550
795
|
query = results = errorResponse = null
|
|
551
796
|
result = new Result()
|
|
552
|
-
connectTimer.cancel()
|
|
553
|
-
|
|
554
|
-
if (initial) {
|
|
555
|
-
if (target_session_attrs) {
|
|
556
|
-
if (!backendParameters.in_hot_standby || !backendParameters.default_transaction_read_only)
|
|
557
|
-
return fetchState()
|
|
558
|
-
else if (tryNext(target_session_attrs, backendParameters))
|
|
559
|
-
return terminate()
|
|
560
|
-
}
|
|
561
797
|
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
return fetchArrayTypes()
|
|
565
|
-
}
|
|
798
|
+
if (phase === Phase.Authenticating || phase === Phase.Initializing)
|
|
799
|
+
return initialized()
|
|
566
800
|
|
|
567
|
-
|
|
568
|
-
options.shared.retries = retries = 0
|
|
569
|
-
initial = null
|
|
801
|
+
if (phase === Phase.Closing)
|
|
570
802
|
return
|
|
571
|
-
}
|
|
572
803
|
|
|
573
804
|
while (sent.length && (query = sent.shift()) && (query.active = true, query.cancelled))
|
|
574
805
|
Connection(options).cancel(query.state, query.cancelled.resolve, query.cancelled.reject)
|
|
575
806
|
|
|
576
807
|
if (query)
|
|
577
|
-
return
|
|
808
|
+
return
|
|
578
809
|
|
|
579
810
|
connection.reserved
|
|
580
|
-
? !connection.reserved.release && x[5] === 73
|
|
581
|
-
?
|
|
582
|
-
?
|
|
811
|
+
? !connection.reserved.release && x[5] === 73
|
|
812
|
+
? phase === Phase.Draining
|
|
813
|
+
? drained()
|
|
583
814
|
: (connection.reserved = null, onopen(connection))
|
|
584
815
|
: connection.reserved()
|
|
585
|
-
:
|
|
586
|
-
?
|
|
816
|
+
: phase === Phase.Draining
|
|
817
|
+
? drained()
|
|
587
818
|
: onopen(connection)
|
|
588
819
|
}
|
|
589
820
|
|
|
821
|
+
function initialized() {
|
|
822
|
+
if (target_session_attrs) {
|
|
823
|
+
if (!backendParameters.in_hot_standby || !backendParameters.default_transaction_read_only)
|
|
824
|
+
return fetchState()
|
|
825
|
+
if (tryNext(target_session_attrs, backendParameters)) {
|
|
826
|
+
acquisition.mismatch = true
|
|
827
|
+
return fail(Errors.connection('CONNECTION_CLOSED', options, socket), true)
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
if (needsTypes)
|
|
832
|
+
return fetchArrayTypes()
|
|
833
|
+
|
|
834
|
+
handoff()
|
|
835
|
+
}
|
|
836
|
+
|
|
590
837
|
function CommandComplete(x) {
|
|
591
838
|
rows = 0
|
|
592
839
|
|
|
@@ -654,7 +901,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
|
|
|
654
901
|
const number = x.readUInt16BE(index + 4)
|
|
655
902
|
const type = x.readUInt32BE(index + 6)
|
|
656
903
|
query.statement.columns[i] = {
|
|
657
|
-
name: transform.column.from
|
|
904
|
+
name: !query.initialization && transform.column.from
|
|
658
905
|
? transform.column.from(x.toString('utf8', start, index - 1))
|
|
659
906
|
: x.toString('utf8', start, index - 1),
|
|
660
907
|
parser: parsers[type],
|
|
@@ -670,8 +917,9 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
|
|
|
670
917
|
return (query.resolve(query.statement), write(Sync))
|
|
671
918
|
}
|
|
672
919
|
|
|
673
|
-
|
|
674
|
-
|
|
920
|
+
function Authentication(x, type = x.readUInt32BE(5)) {
|
|
921
|
+
const attempt = generation
|
|
922
|
+
Promise.resolve((
|
|
675
923
|
type === 3 ? AuthenticationCleartextPassword :
|
|
676
924
|
type === 5 ? AuthenticationMD5Password :
|
|
677
925
|
type === 10 ? SASL :
|
|
@@ -679,18 +927,20 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
|
|
|
679
927
|
type === 12 ? SASLFinal :
|
|
680
928
|
type !== 0 ? UnknownAuth :
|
|
681
929
|
noop
|
|
682
|
-
)(x, type)
|
|
930
|
+
)(x, type, attempt)).catch(err => attempt === generation && enterClosed(err))
|
|
683
931
|
}
|
|
684
932
|
|
|
685
933
|
/* c8 ignore next 5 */
|
|
686
|
-
async function AuthenticationCleartextPassword() {
|
|
934
|
+
async function AuthenticationCleartextPassword(x, type, attempt) {
|
|
687
935
|
const payload = await Pass()
|
|
936
|
+
if (attempt !== generation)
|
|
937
|
+
return
|
|
688
938
|
write(
|
|
689
939
|
b().p().str(payload).z(1).end()
|
|
690
940
|
)
|
|
691
941
|
}
|
|
692
942
|
|
|
693
|
-
async function AuthenticationMD5Password(x) {
|
|
943
|
+
async function AuthenticationMD5Password(x, type, attempt) {
|
|
694
944
|
const payload = 'md5' + (
|
|
695
945
|
await md5(
|
|
696
946
|
Buffer.concat([
|
|
@@ -699,19 +949,25 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
|
|
|
699
949
|
])
|
|
700
950
|
)
|
|
701
951
|
)
|
|
952
|
+
if (attempt !== generation)
|
|
953
|
+
return
|
|
702
954
|
write(
|
|
703
955
|
b().p().str(payload).z(1).end()
|
|
704
956
|
)
|
|
705
957
|
}
|
|
706
958
|
|
|
707
|
-
async function SASL() {
|
|
708
|
-
|
|
959
|
+
async function SASL(x, type, attempt) {
|
|
960
|
+
const nextNonce = (await crypto.randomBytes(18)).toString('base64')
|
|
961
|
+
if (attempt !== generation)
|
|
962
|
+
return
|
|
963
|
+
nonce = nextNonce
|
|
709
964
|
b().p().str('SCRAM-SHA-256' + b.N)
|
|
710
965
|
const i = b.i
|
|
711
966
|
write(b.inc(4).str('n,,n=*,r=' + nonce).i32(b.i - i - 4, i).end())
|
|
712
967
|
}
|
|
713
968
|
|
|
714
|
-
async function SASLContinue(x) {
|
|
969
|
+
async function SASLContinue(x, type, attempt) {
|
|
970
|
+
const clientNonce = nonce
|
|
715
971
|
const res = x.toString('utf8', 9).split(',').reduce((acc, x) => (acc[x[0]] = x.slice(2), acc), {})
|
|
716
972
|
|
|
717
973
|
const saltedPassword = await crypto.pbkdf2Sync(
|
|
@@ -723,16 +979,19 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
|
|
|
723
979
|
|
|
724
980
|
const clientKey = await hmac(saltedPassword, 'Client Key')
|
|
725
981
|
|
|
726
|
-
const auth = 'n=*,r=' +
|
|
982
|
+
const auth = 'n=*,r=' + clientNonce + ','
|
|
727
983
|
+ 'r=' + res.r + ',s=' + res.s + ',i=' + res.i
|
|
728
984
|
+ ',c=biws,r=' + res.r
|
|
729
985
|
|
|
730
|
-
|
|
986
|
+
const signature = (await hmac(await hmac(saltedPassword, 'Server Key'), auth)).toString('base64')
|
|
731
987
|
|
|
732
988
|
const payload = 'c=biws,r=' + res.r + ',p=' + xor(
|
|
733
989
|
clientKey, Buffer.from(await hmac(await sha256(clientKey), auth))
|
|
734
990
|
).toString('base64')
|
|
735
991
|
|
|
992
|
+
if (attempt !== generation)
|
|
993
|
+
return
|
|
994
|
+
serverSignature = signature
|
|
736
995
|
write(
|
|
737
996
|
b().p().str(payload).end()
|
|
738
997
|
)
|
|
@@ -742,8 +1001,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
|
|
|
742
1001
|
if (x.toString('utf8', 9).split(b.N, 1)[0].slice(2) === serverSignature)
|
|
743
1002
|
return
|
|
744
1003
|
/* c8 ignore next 5 */
|
|
745
|
-
|
|
746
|
-
socket.destroy()
|
|
1004
|
+
enterClosed(Errors.generic('SASL_SIGNATURE_MISMATCH', 'The server did not return the correct signature'))
|
|
747
1005
|
}
|
|
748
1006
|
|
|
749
1007
|
function Pass() {
|
|
@@ -765,26 +1023,16 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
|
|
|
765
1023
|
backend.secret = x.readUInt32BE(9)
|
|
766
1024
|
}
|
|
767
1025
|
|
|
768
|
-
|
|
1026
|
+
function fetchArrayTypes() {
|
|
769
1027
|
needsTypes = false
|
|
770
|
-
|
|
1028
|
+
initialize(`
|
|
771
1029
|
select b.oid, b.typarray
|
|
772
1030
|
from pg_catalog.pg_type a
|
|
773
1031
|
left join pg_catalog.pg_type b on b.oid = a.typelem
|
|
774
1032
|
where a.typcategory = 'A'
|
|
775
1033
|
group by b.oid, b.typarray
|
|
776
1034
|
order by b.oid
|
|
777
|
-
|
|
778
|
-
types.forEach(({ oid, typarray }) => addArrayType(oid, typarray))
|
|
779
|
-
}
|
|
780
|
-
|
|
781
|
-
function addArrayType(oid, typarray) {
|
|
782
|
-
if (!!options.parsers[typarray] && !!options.serializers[typarray]) return
|
|
783
|
-
const parser = options.parsers[oid]
|
|
784
|
-
options.shared.typeArrayMap[oid] = typarray
|
|
785
|
-
options.parsers[typarray] = (xs) => arrayParser(xs, parser, typarray)
|
|
786
|
-
options.parsers[typarray].array = true
|
|
787
|
-
options.serializers[typarray] = (xs) => arraySerializer(xs, options.serializers[oid], options, typarray)
|
|
1035
|
+
`, types => types.forEach(({ oid, typarray }) => addArrayType(options, oid, typarray)))
|
|
788
1036
|
}
|
|
789
1037
|
|
|
790
1038
|
function tryNext(x, xs) {
|
|
@@ -793,20 +1041,28 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
|
|
|
793
1041
|
(x === 'read-only' && xs.default_transaction_read_only === 'off') ||
|
|
794
1042
|
(x === 'primary' && xs.in_hot_standby === 'on') ||
|
|
795
1043
|
(x === 'standby' && xs.in_hot_standby === 'off') ||
|
|
796
|
-
(x === 'prefer-standby' && xs.in_hot_standby === 'off' &&
|
|
1044
|
+
(x === 'prefer-standby' && xs.in_hot_standby === 'off' && host.length > 1 && !acquisition.mismatch)
|
|
797
1045
|
)
|
|
798
1046
|
}
|
|
799
1047
|
|
|
800
1048
|
function fetchState() {
|
|
801
|
-
|
|
1049
|
+
initialize(`
|
|
802
1050
|
show transaction_read_only;
|
|
803
1051
|
select pg_catalog.pg_is_in_recovery()
|
|
804
|
-
|
|
805
|
-
query.resolve = ([[a], [b]]) => {
|
|
1052
|
+
`, ([[a], [b]]) => {
|
|
806
1053
|
backendParameters.default_transaction_read_only = a.transaction_read_only
|
|
807
1054
|
backendParameters.in_hot_standby = b.pg_is_in_recovery ? 'on' : 'off'
|
|
808
|
-
}
|
|
809
|
-
|
|
1055
|
+
}, true)
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
function initialize(string, resolve, simple = false) {
|
|
1059
|
+
transition(Phase.Initializing)
|
|
1060
|
+
const attempt = generation
|
|
1061
|
+
const q = new Query([string], [], q => attempt === generation
|
|
1062
|
+
? execute(q)
|
|
1063
|
+
: queryError(q, Errors.connection('CONNECTION_CLOSED', options)), null, { simple })
|
|
1064
|
+
q.initialization = resolve
|
|
1065
|
+
q.catch(noop)
|
|
810
1066
|
}
|
|
811
1067
|
|
|
812
1068
|
function ErrorResponse(x) {
|
|
@@ -814,7 +1070,10 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
|
|
|
814
1070
|
(query.cursorFn || query.describeFirst) && write(Sync)
|
|
815
1071
|
errorResponse = Errors.postgres(parseError(x))
|
|
816
1072
|
} else {
|
|
817
|
-
|
|
1073
|
+
const err = Errors.postgres(parseError(x))
|
|
1074
|
+
phase === Phase.Ready || phase === Phase.Draining
|
|
1075
|
+
? socketFailed(err)
|
|
1076
|
+
: phase === Phase.Authenticating && fail(err)
|
|
818
1077
|
}
|
|
819
1078
|
}
|
|
820
1079
|
|
|
@@ -837,15 +1096,19 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
|
|
|
837
1096
|
}
|
|
838
1097
|
|
|
839
1098
|
async function PortalSuspended() {
|
|
1099
|
+
const current = query
|
|
1100
|
+
const source = socket
|
|
840
1101
|
try {
|
|
841
|
-
const x = await Promise.resolve(
|
|
1102
|
+
const x = await Promise.resolve(current.cursorFn(result))
|
|
1103
|
+
if (query !== current || socket !== source)
|
|
1104
|
+
return
|
|
842
1105
|
rows = 0
|
|
843
1106
|
x === CLOSE
|
|
844
|
-
? write(Close(
|
|
845
|
-
: (result = new Result(), write(Execute('',
|
|
1107
|
+
? write(Close(current.portal))
|
|
1108
|
+
: (result = new Result(), write(Execute('', current.cursorRows)))
|
|
846
1109
|
} catch (err) {
|
|
847
|
-
write(Sync)
|
|
848
|
-
|
|
1110
|
+
query === current && socket === source && write(Sync)
|
|
1111
|
+
current.reject(err)
|
|
849
1112
|
}
|
|
850
1113
|
}
|
|
851
1114
|
|
|
@@ -862,7 +1125,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
|
|
|
862
1125
|
},
|
|
863
1126
|
destroy(error, callback) {
|
|
864
1127
|
callback(error)
|
|
865
|
-
socket.write(b().f().str(error + b.N).end())
|
|
1128
|
+
socket && socket.readyState === 'open' && socket.write(b().f().str(error + b.N).end())
|
|
866
1129
|
stream = null
|
|
867
1130
|
},
|
|
868
1131
|
final(callback) {
|
|
@@ -892,7 +1155,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
|
|
|
892
1155
|
},
|
|
893
1156
|
destroy(error, callback) {
|
|
894
1157
|
callback(error)
|
|
895
|
-
socket.write(b().f().str(error + b.N).end())
|
|
1158
|
+
socket && socket.readyState === 'open' && socket.write(b().f().str(error + b.N).end())
|
|
896
1159
|
stream = null
|
|
897
1160
|
},
|
|
898
1161
|
final(callback) {
|
|
@@ -994,7 +1257,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
|
|
|
994
1257
|
}
|
|
995
1258
|
|
|
996
1259
|
function StartupMessage() {
|
|
997
|
-
return
|
|
1260
|
+
return b().inc(4).i16(3).z(2).str(
|
|
998
1261
|
Object.entries(Object.assign({
|
|
999
1262
|
user,
|
|
1000
1263
|
database,
|
|
@@ -1049,14 +1312,14 @@ function timer(fn, seconds) {
|
|
|
1049
1312
|
cancel() {
|
|
1050
1313
|
timer && (clearTimeout(timer), timer = null)
|
|
1051
1314
|
},
|
|
1052
|
-
start() {
|
|
1315
|
+
start(...args) {
|
|
1053
1316
|
timer && clearTimeout(timer)
|
|
1054
|
-
timer = setTimeout(done, seconds * 1000
|
|
1317
|
+
timer = setTimeout(() => done(args), seconds * 1000)
|
|
1055
1318
|
}
|
|
1056
1319
|
}
|
|
1057
1320
|
|
|
1058
1321
|
function done(args) {
|
|
1059
|
-
fn.apply(null, args)
|
|
1060
1322
|
timer = null
|
|
1323
|
+
fn.apply(null, args)
|
|
1061
1324
|
}
|
|
1062
1325
|
}
|