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