@steadybrew/postgresjs 0.0.0-stage → 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.
@@ -0,0 +1,1325 @@
1
+ import net from 'net'
2
+ import tls from 'tls'
3
+ import crypto from 'crypto'
4
+ import Stream from 'stream'
5
+ import { performance } from 'perf_hooks'
6
+
7
+ import { stringify, handleValue, addArrayType } from './types.js'
8
+ import { Errors } from './errors.js'
9
+ import Result from './result.js'
10
+ import Queue from './queue.js'
11
+ import { Query, CLOSE } from './query.js'
12
+ import b from './bytes.js'
13
+
14
+ export default Connection
15
+
16
+ let uid = 1
17
+
18
+ const Sync = b().S().end()
19
+ , Flush = b().H().end()
20
+ , SSLRequest = b().i32(8).i32(80877103).end(8)
21
+ , ExecuteUnnamed = Buffer.concat([b().E().str(b.N).i32(0).end(), Sync])
22
+ , DescribeUnnamed = b().D().str('S').str(b.N).end()
23
+ , noop = () => { /* noop */ }
24
+
25
+ const Phase = { Closed: 0, Backoff: 1, Opening: 2, Negotiating: 3, Authenticating: 4, Initializing: 5, Ready: 6, Draining: 7, Closing: 8 }
26
+
27
+ const retryRoutines = new Set([
28
+ 'FetchPreparedStatement',
29
+ 'RevalidateCachedQuery',
30
+ 'transformAssignedExpr'
31
+ ])
32
+
33
+ const errorFields = {
34
+ 83 : 'severity_local', // S
35
+ 86 : 'severity', // V
36
+ 67 : 'code', // C
37
+ 77 : 'message', // M
38
+ 68 : 'detail', // D
39
+ 72 : 'hint', // H
40
+ 80 : 'position', // P
41
+ 112 : 'internal_position', // p
42
+ 113 : 'internal_query', // q
43
+ 87 : 'where', // W
44
+ 115 : 'schema_name', // s
45
+ 116 : 'table_name', // t
46
+ 99 : 'column_name', // c
47
+ 100 : 'data type_name', // d
48
+ 110 : 'constraint_name', // n
49
+ 70 : 'file', // F
50
+ 76 : 'line', // L
51
+ 82 : 'routine' // R
52
+ }
53
+
54
+ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose = noop, ondrain = noop } = {}) {
55
+ const {
56
+ sslnegotiation,
57
+ ssl,
58
+ max,
59
+ user,
60
+ host,
61
+ port,
62
+ database,
63
+ parsers,
64
+ transform,
65
+ onnotice,
66
+ onnotify,
67
+ onparameter,
68
+ max_pipeline,
69
+ keep_alive,
70
+ backoff,
71
+ target_session_attrs
72
+ } = options
73
+
74
+ const sent = Queue()
75
+ , id = uid++
76
+ , backend = { pid: null, secret: null }
77
+ , idleTimer = timer(end, options.idle_timeout)
78
+ , lifeTimer = timer(end, options.max_lifetime)
79
+
80
+ let socket = null
81
+ , phase = Phase.Closed
82
+ , generation = 0
83
+ , acquisition = null
84
+ , endRequested = false
85
+ , endWaiters = []
86
+ , inheritedBackoff = null
87
+ , backoffTimer = null
88
+ , connectTimer = null
89
+ , errorResponse = null
90
+ , result = new Result()
91
+ , incoming = Buffer.alloc(0)
92
+ , needsTypes = options.fetch_types
93
+ , backendParameters = {}
94
+ , statements = {}
95
+ , statementId = Math.random().toString(36).slice(2)
96
+ , statementCount = 1
97
+ , remaining = 0
98
+ , hostIndex = 0
99
+ , length = 0
100
+ , rows = 0
101
+ , serverSignature = null
102
+ , nextWriteTimer = null
103
+ , incomings = null
104
+ , results = null
105
+ , stream = null
106
+ , chunk = null
107
+ , nonce = null
108
+ , query = null
109
+ , final = null
110
+
111
+ const connection = {
112
+ queue: queues.closed,
113
+ idleTimer,
114
+ connect: acquire,
115
+ terminate,
116
+ execute,
117
+ cancel,
118
+ release,
119
+ end,
120
+ count: 0,
121
+ id
122
+ }
123
+
124
+ queues.closed && queues.closed.push(connection)
125
+
126
+ return connection
127
+
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)
273
+ try {
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())
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
336
+ }
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)
390
+ }
391
+
392
+ async function cancel({ pid, secret }, resolve, reject) {
393
+ let timeout = null
394
+ try {
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]
434
+ } catch (error) {
435
+ reject(error)
436
+ }
437
+ }
438
+
439
+ function execute(q) {
440
+ if (phase !== Phase.Ready && phase !== Phase.Draining && !(phase === Phase.Initializing && q.initialization))
441
+ return queryError(q, Errors.connection('CONNECTION_CLOSED', options))
442
+
443
+ if (stream)
444
+ return queryError(q, Errors.generic('COPY_IN_PROGRESS', 'You cannot execute queries during copy'))
445
+
446
+ if (q.cancelled)
447
+ return
448
+
449
+ try {
450
+ q.state = backend
451
+ query
452
+ ? sent.push(q)
453
+ : (query = q, query.active = true)
454
+
455
+ build(q)
456
+ return write(toBuffer(q))
457
+ && !q.describeFirst
458
+ && !q.cursorFn
459
+ && sent.length < max_pipeline
460
+ } catch (error) {
461
+ sent.length === 0 && write(Sync)
462
+ errored(error)
463
+ return true
464
+ }
465
+ }
466
+
467
+ function toBuffer(q) {
468
+ if (q.parameters.length >= 65534)
469
+ throw Errors.generic('MAX_PARAMETERS_EXCEEDED', 'Max number of parameters (65534) exceeded')
470
+
471
+ return q.options.simple
472
+ ? b().Q().str(q.statement.string + b.N).end()
473
+ : q.describeFirst
474
+ ? Buffer.concat([describe(q), Flush])
475
+ : q.prepare
476
+ ? q.prepared
477
+ ? prepared(q)
478
+ : Buffer.concat([describe(q), prepared(q)])
479
+ : unnamed(q)
480
+ }
481
+
482
+ function describe(q) {
483
+ return Buffer.concat([
484
+ Parse(q.statement.string, q.parameters, q.statement.types, q.statement.name),
485
+ Describe('S', q.statement.name)
486
+ ])
487
+ }
488
+
489
+ function prepared(q) {
490
+ return Buffer.concat([
491
+ Bind(q.parameters, q.statement.types, q.statement.name, q.cursorName),
492
+ q.cursorFn
493
+ ? Execute('', q.cursorRows)
494
+ : ExecuteUnnamed
495
+ ])
496
+ }
497
+
498
+ function unnamed(q) {
499
+ return Buffer.concat([
500
+ Parse(q.statement.string, q.parameters, q.statement.types),
501
+ DescribeUnnamed,
502
+ prepared(q)
503
+ ])
504
+ }
505
+
506
+ function build(q) {
507
+ const parameters = []
508
+ , types = []
509
+
510
+ const string = stringify(q, q.strings[0], q.args[0], parameters, types, options)
511
+
512
+ !q.tagged && q.args.forEach(x => handleValue(x, parameters, types, options))
513
+
514
+ q.prepare = options.prepare && ('prepare' in q.options ? q.options.prepare : true)
515
+ q.string = string
516
+ q.signature = q.prepare && types + string
517
+ q.onlyDescribe && (delete statements[q.signature])
518
+ q.parameters = q.parameters || parameters
519
+ q.prepared = q.prepare && q.signature in statements
520
+ q.describeFirst = q.onlyDescribe || (parameters.length && !q.prepared)
521
+ q.statement = q.prepared
522
+ ? statements[q.signature]
523
+ : { string, types, name: q.prepare ? statementId + statementCount++ : '' }
524
+
525
+ typeof options.debug === 'function' && options.debug(id, string, parameters, types)
526
+ }
527
+
528
+ function write(x, fn) {
529
+ chunk = chunk ? Buffer.concat([chunk, x]) : Buffer.from(x)
530
+ if (fn || chunk.length >= 1024)
531
+ return nextWrite(fn)
532
+ nextWriteTimer === null && (nextWriteTimer = setImmediate(nextWrite))
533
+ return true
534
+ }
535
+
536
+ function nextWrite(fn) {
537
+ const x = socket ? socket.write(chunk, fn) : false
538
+ nextWriteTimer !== null && clearImmediate(nextWriteTimer)
539
+ chunk = nextWriteTimer = null
540
+ return x
541
+ }
542
+
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
554
+ }
555
+
556
+ /* c8 ignore next 3 */
557
+ function drain() {
558
+ phase === Phase.Ready && !query && !held() && onopen(connection)
559
+ }
560
+
561
+ function data(x) {
562
+ if (incomings) {
563
+ incomings.push(x)
564
+ remaining -= x.length
565
+ if (remaining > 0)
566
+ return
567
+ }
568
+
569
+ incoming = incomings
570
+ ? Buffer.concat(incomings, length - remaining)
571
+ : incoming.length === 0
572
+ ? x
573
+ : Buffer.concat([incoming, x], incoming.length + x.length)
574
+
575
+ const source = socket
576
+ while (incoming.length > 4) {
577
+ length = incoming.readUInt32BE(1)
578
+ if (length >= incoming.length) {
579
+ remaining = length - incoming.length
580
+ incomings = [incoming]
581
+ break
582
+ }
583
+
584
+ try {
585
+ handle(incoming.subarray(0, length + 1))
586
+ } catch (e) {
587
+ query && (query.cursorFn || query.describeFirst) && write(Sync)
588
+ starting() ? fail(e) : errored(e)
589
+ }
590
+ if (socket !== source)
591
+ return
592
+ incoming = incoming.subarray(length + 1)
593
+ remaining = 0
594
+ incomings = null
595
+ }
596
+ }
597
+
598
+ function error(err) {
599
+ if (starting())
600
+ return fail(err)
601
+
602
+ if (phase === Phase.Ready || phase === Phase.Draining)
603
+ socketFailed(err)
604
+ }
605
+
606
+ function socketFailed(err) {
607
+ errored(err)
608
+ while (sent.length)
609
+ queryError(sent.shift(), err)
610
+ query = null
611
+ options.shared.retries++
612
+ inheritedBackoff = { at: performance.now(), delay: backoffMs() }
613
+ closing(false)
614
+ }
615
+
616
+ function errored(err) {
617
+ stream && (stream.destroy(err), stream = null)
618
+ query && queryError(query, err)
619
+ }
620
+
621
+ function queryError(query, err) {
622
+ if (query.reserve)
623
+ return query.reject(err)
624
+
625
+ if (!err || typeof err !== 'object')
626
+ err = new Error(err)
627
+
628
+ 'query' in err || 'parameters' in err || Object.defineProperties(err, {
629
+ stack: { value: err.stack + query.origin.replace(/.*\n/, '\n'), enumerable: options.debug },
630
+ query: { value: query.string, enumerable: options.debug },
631
+ parameters: { value: query.parameters, enumerable: options.debug },
632
+ args: { value: query.args, enumerable: options.debug },
633
+ types: { value: query.statement && query.statement.types, enumerable: options.debug }
634
+ })
635
+ query.reject(err)
636
+ }
637
+
638
+ function end() {
639
+ if (phase === Phase.Closed)
640
+ return Promise.resolve()
641
+
642
+ const done = new Promise(resolve => endWaiters.push(resolve))
643
+
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
653
+ }
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
663
+ }
664
+
665
+ function terminate() {
666
+ if (phase === Phase.Closed)
667
+ return
668
+
669
+ const destroyed = Errors.connection('CONNECTION_DESTROYED', options, socket)
670
+ if (phase === Phase.Closing)
671
+ return socket.destroy()
672
+
673
+ if (phase !== Phase.Ready && phase !== Phase.Draining)
674
+ return enterClosed(destroyed)
675
+
676
+ const inflight = !idle()
677
+ resetSocketState(destroyed)
678
+ enterClosed(inflight ? destroyed : undefined)
679
+ }
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
+
700
+ /* Handlers */
701
+ function handle(xs, x = xs[0]) {
702
+ (
703
+ x === 68 ? DataRow : // D
704
+ x === 100 ? CopyData : // d
705
+ x === 65 ? NotificationResponse : // A
706
+ x === 83 ? ParameterStatus : // S
707
+ x === 90 ? ReadyForQuery : // Z
708
+ x === 67 ? CommandComplete : // C
709
+ x === 50 ? BindComplete : // 2
710
+ x === 49 ? ParseComplete : // 1
711
+ x === 116 ? ParameterDescription : // t
712
+ x === 84 ? RowDescription : // T
713
+ x === 82 ? Authentication : // R
714
+ x === 110 ? NoData : // n
715
+ x === 75 ? BackendKeyData : // K
716
+ x === 69 ? ErrorResponse : // E
717
+ x === 115 ? PortalSuspended : // s
718
+ x === 51 ? CloseComplete : // 3
719
+ x === 71 ? CopyInResponse : // G
720
+ x === 78 ? NoticeResponse : // N
721
+ x === 72 ? CopyOutResponse : // H
722
+ x === 99 ? CopyDone : // c
723
+ x === 73 ? EmptyQueryResponse : // I
724
+ x === 86 ? FunctionCallResponse : // V
725
+ x === 118 ? NegotiateProtocolVersion : // v
726
+ x === 87 ? CopyBothResponse : // W
727
+ /* c8 ignore next */
728
+ UnknownMessage
729
+ )(xs)
730
+ }
731
+
732
+ function DataRow(x) {
733
+ let index = 7
734
+ let length
735
+ let column
736
+ let value
737
+
738
+ const valueFrom = !query.initialization && transform.value.from
739
+ const rowFrom = !query.initialization && transform.row.from
740
+ const row = query.isRaw ? new Array(query.statement.columns.length) : {}
741
+ for (let i = 0; i < query.statement.columns.length; i++) {
742
+ column = query.statement.columns[i]
743
+ length = x.readInt32BE(index)
744
+ index += 4
745
+
746
+ value = length === -1
747
+ ? null
748
+ : query.isRaw === true
749
+ ? x.subarray(index, index += length)
750
+ : column.parser === undefined
751
+ ? x.toString('utf8', index, index += length)
752
+ : column.parser.array === true
753
+ ? column.parser(x.toString('utf8', index + 1, index += length))
754
+ : column.parser(x.toString('utf8', index, index += length))
755
+
756
+ query.isRaw
757
+ ? (row[i] = query.isRaw === true
758
+ ? value
759
+ : valueFrom ? transform.value.from(value, column) : value)
760
+ : (row[column.name] = valueFrom ? transform.value.from(value, column) : value)
761
+ }
762
+
763
+ query.forEachFn
764
+ ? query.forEachFn(rowFrom ? transform.row.from(row) : row, result)
765
+ : (result[rows++] = rowFrom ? transform.row.from(row) : row)
766
+ }
767
+
768
+ function ParameterStatus(x) {
769
+ const [k, v] = x.toString('utf8', 5, x.length - 1).split(b.N)
770
+ backendParameters[k] = v
771
+ if (options.parameters[k] !== v) {
772
+ options.parameters[k] = v
773
+ onparameter && onparameter(k, v)
774
+ }
775
+ }
776
+
777
+ function ReadyForQuery(x) {
778
+ if (query) {
779
+ if (errorResponse) {
780
+ if (query.initialization)
781
+ return enterClosed(errorResponse)
782
+ query.retried
783
+ ? errored(query.retried)
784
+ : query.prepared && retryRoutines.has(errorResponse.routine)
785
+ ? retry(query, errorResponse)
786
+ : errored(errorResponse)
787
+ } else {
788
+ query.initialization && query.initialization(results || result)
789
+ query.resolve(results || result)
790
+ }
791
+ } else if (errorResponse) {
792
+ errored(errorResponse)
793
+ }
794
+
795
+ query = results = errorResponse = null
796
+ result = new Result()
797
+
798
+ if (phase === Phase.Authenticating || phase === Phase.Initializing)
799
+ return initialized()
800
+
801
+ if (phase === Phase.Closing)
802
+ return
803
+
804
+ while (sent.length && (query = sent.shift()) && (query.active = true, query.cancelled))
805
+ Connection(options).cancel(query.state, query.cancelled.resolve, query.cancelled.reject)
806
+
807
+ if (query)
808
+ return
809
+
810
+ connection.reserved
811
+ ? !connection.reserved.release && x[5] === 73
812
+ ? phase === Phase.Draining
813
+ ? drained()
814
+ : (connection.reserved = null, onopen(connection))
815
+ : connection.reserved()
816
+ : phase === Phase.Draining
817
+ ? drained()
818
+ : onopen(connection)
819
+ }
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
+
837
+ function CommandComplete(x) {
838
+ rows = 0
839
+
840
+ for (let i = x.length - 1; i > 0; i--) {
841
+ if (x[i] === 32 && x[i + 1] < 58 && result.count === null)
842
+ result.count = +x.toString('utf8', i + 1, x.length - 1)
843
+ if (x[i - 1] >= 65) {
844
+ result.command = x.toString('utf8', 5, i)
845
+ result.state = backend
846
+ break
847
+ }
848
+ }
849
+
850
+ final && (final(), final = null)
851
+
852
+ if (result.command === 'BEGIN' && max !== 1 && !connection.reserved)
853
+ return errored(Errors.generic('UNSAFE_TRANSACTION', 'Only use sql.begin, sql.reserved or max: 1'))
854
+
855
+ if (query.options.simple)
856
+ return BindComplete()
857
+
858
+ if (query.cursorFn) {
859
+ result.count && query.cursorFn(result)
860
+ write(Sync)
861
+ }
862
+ }
863
+
864
+ function ParseComplete() {
865
+ query.parsing = false
866
+ }
867
+
868
+ function BindComplete() {
869
+ !result.statement && (result.statement = query.statement)
870
+ result.columns = query.statement.columns
871
+ }
872
+
873
+ function ParameterDescription(x) {
874
+ const length = x.readUInt16BE(5)
875
+
876
+ for (let i = 0; i < length; ++i)
877
+ !query.statement.types[i] && (query.statement.types[i] = x.readUInt32BE(7 + i * 4))
878
+
879
+ query.prepare && (statements[query.signature] = query.statement)
880
+ query.describeFirst && !query.onlyDescribe && (write(prepared(query)), query.describeFirst = false)
881
+ }
882
+
883
+ function RowDescription(x) {
884
+ if (result.command) {
885
+ results = results || [result]
886
+ results.push(result = new Result())
887
+ result.count = null
888
+ query.statement.columns = null
889
+ }
890
+
891
+ const length = x.readUInt16BE(5)
892
+ let index = 7
893
+ let start
894
+
895
+ query.statement.columns = Array(length)
896
+
897
+ for (let i = 0; i < length; ++i) {
898
+ start = index
899
+ while (x[index++] !== 0);
900
+ const table = x.readUInt32BE(index)
901
+ const number = x.readUInt16BE(index + 4)
902
+ const type = x.readUInt32BE(index + 6)
903
+ query.statement.columns[i] = {
904
+ name: !query.initialization && transform.column.from
905
+ ? transform.column.from(x.toString('utf8', start, index - 1))
906
+ : x.toString('utf8', start, index - 1),
907
+ parser: parsers[type],
908
+ table,
909
+ number,
910
+ type
911
+ }
912
+ index += 18
913
+ }
914
+
915
+ result.statement = query.statement
916
+ if (query.onlyDescribe)
917
+ return (query.resolve(query.statement), write(Sync))
918
+ }
919
+
920
+ function Authentication(x, type = x.readUInt32BE(5)) {
921
+ const attempt = generation
922
+ Promise.resolve((
923
+ type === 3 ? AuthenticationCleartextPassword :
924
+ type === 5 ? AuthenticationMD5Password :
925
+ type === 10 ? SASL :
926
+ type === 11 ? SASLContinue :
927
+ type === 12 ? SASLFinal :
928
+ type !== 0 ? UnknownAuth :
929
+ noop
930
+ )(x, type, attempt)).catch(err => attempt === generation && enterClosed(err))
931
+ }
932
+
933
+ /* c8 ignore next 5 */
934
+ async function AuthenticationCleartextPassword(x, type, attempt) {
935
+ const payload = await Pass()
936
+ if (attempt !== generation)
937
+ return
938
+ write(
939
+ b().p().str(payload).z(1).end()
940
+ )
941
+ }
942
+
943
+ async function AuthenticationMD5Password(x, type, attempt) {
944
+ const payload = 'md5' + (
945
+ await md5(
946
+ Buffer.concat([
947
+ Buffer.from(await md5((await Pass()) + user)),
948
+ x.subarray(9)
949
+ ])
950
+ )
951
+ )
952
+ if (attempt !== generation)
953
+ return
954
+ write(
955
+ b().p().str(payload).z(1).end()
956
+ )
957
+ }
958
+
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
964
+ b().p().str('SCRAM-SHA-256' + b.N)
965
+ const i = b.i
966
+ write(b.inc(4).str('n,,n=*,r=' + nonce).i32(b.i - i - 4, i).end())
967
+ }
968
+
969
+ async function SASLContinue(x, type, attempt) {
970
+ const clientNonce = nonce
971
+ const res = x.toString('utf8', 9).split(',').reduce((acc, x) => (acc[x[0]] = x.slice(2), acc), {})
972
+
973
+ const saltedPassword = await crypto.pbkdf2Sync(
974
+ await Pass(),
975
+ Buffer.from(res.s, 'base64'),
976
+ parseInt(res.i), 32,
977
+ 'sha256'
978
+ )
979
+
980
+ const clientKey = await hmac(saltedPassword, 'Client Key')
981
+
982
+ const auth = 'n=*,r=' + clientNonce + ','
983
+ + 'r=' + res.r + ',s=' + res.s + ',i=' + res.i
984
+ + ',c=biws,r=' + res.r
985
+
986
+ const signature = (await hmac(await hmac(saltedPassword, 'Server Key'), auth)).toString('base64')
987
+
988
+ const payload = 'c=biws,r=' + res.r + ',p=' + xor(
989
+ clientKey, Buffer.from(await hmac(await sha256(clientKey), auth))
990
+ ).toString('base64')
991
+
992
+ if (attempt !== generation)
993
+ return
994
+ serverSignature = signature
995
+ write(
996
+ b().p().str(payload).end()
997
+ )
998
+ }
999
+
1000
+ function SASLFinal(x) {
1001
+ if (x.toString('utf8', 9).split(b.N, 1)[0].slice(2) === serverSignature)
1002
+ return
1003
+ /* c8 ignore next 5 */
1004
+ enterClosed(Errors.generic('SASL_SIGNATURE_MISMATCH', 'The server did not return the correct signature'))
1005
+ }
1006
+
1007
+ function Pass() {
1008
+ return Promise.resolve(typeof options.pass === 'function'
1009
+ ? options.pass()
1010
+ : options.pass
1011
+ )
1012
+ }
1013
+
1014
+ function NoData() {
1015
+ result.statement = query.statement
1016
+ result.statement.columns = []
1017
+ if (query.onlyDescribe)
1018
+ return (query.resolve(query.statement), write(Sync))
1019
+ }
1020
+
1021
+ function BackendKeyData(x) {
1022
+ backend.pid = x.readUInt32BE(5)
1023
+ backend.secret = x.readUInt32BE(9)
1024
+ }
1025
+
1026
+ function fetchArrayTypes() {
1027
+ needsTypes = false
1028
+ initialize(`
1029
+ select b.oid, b.typarray
1030
+ from pg_catalog.pg_type a
1031
+ left join pg_catalog.pg_type b on b.oid = a.typelem
1032
+ where a.typcategory = 'A'
1033
+ group by b.oid, b.typarray
1034
+ order by b.oid
1035
+ `, types => types.forEach(({ oid, typarray }) => addArrayType(options, oid, typarray)))
1036
+ }
1037
+
1038
+ function tryNext(x, xs) {
1039
+ return (
1040
+ (x === 'read-write' && xs.default_transaction_read_only === 'on') ||
1041
+ (x === 'read-only' && xs.default_transaction_read_only === 'off') ||
1042
+ (x === 'primary' && xs.in_hot_standby === 'on') ||
1043
+ (x === 'standby' && xs.in_hot_standby === 'off') ||
1044
+ (x === 'prefer-standby' && xs.in_hot_standby === 'off' && host.length > 1 && !acquisition.mismatch)
1045
+ )
1046
+ }
1047
+
1048
+ function fetchState() {
1049
+ initialize(`
1050
+ show transaction_read_only;
1051
+ select pg_catalog.pg_is_in_recovery()
1052
+ `, ([[a], [b]]) => {
1053
+ backendParameters.default_transaction_read_only = a.transaction_read_only
1054
+ backendParameters.in_hot_standby = b.pg_is_in_recovery ? 'on' : 'off'
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)
1066
+ }
1067
+
1068
+ function ErrorResponse(x) {
1069
+ if (query) {
1070
+ (query.cursorFn || query.describeFirst) && write(Sync)
1071
+ errorResponse = Errors.postgres(parseError(x))
1072
+ } else {
1073
+ const err = Errors.postgres(parseError(x))
1074
+ phase === Phase.Ready || phase === Phase.Draining
1075
+ ? socketFailed(err)
1076
+ : phase === Phase.Authenticating && fail(err)
1077
+ }
1078
+ }
1079
+
1080
+ function retry(q, error) {
1081
+ delete statements[q.signature]
1082
+ q.retried = error
1083
+ execute(q)
1084
+ }
1085
+
1086
+ function NotificationResponse(x) {
1087
+ if (!onnotify)
1088
+ return
1089
+
1090
+ let index = 9
1091
+ while (x[index++] !== 0);
1092
+ onnotify(
1093
+ x.toString('utf8', 9, index - 1),
1094
+ x.toString('utf8', index, x.length - 1)
1095
+ )
1096
+ }
1097
+
1098
+ async function PortalSuspended() {
1099
+ const current = query
1100
+ const source = socket
1101
+ try {
1102
+ const x = await Promise.resolve(current.cursorFn(result))
1103
+ if (query !== current || socket !== source)
1104
+ return
1105
+ rows = 0
1106
+ x === CLOSE
1107
+ ? write(Close(current.portal))
1108
+ : (result = new Result(), write(Execute('', current.cursorRows)))
1109
+ } catch (err) {
1110
+ query === current && socket === source && write(Sync)
1111
+ current.reject(err)
1112
+ }
1113
+ }
1114
+
1115
+ function CloseComplete() {
1116
+ result.count && query.cursorFn(result)
1117
+ query.resolve(result)
1118
+ }
1119
+
1120
+ function CopyInResponse() {
1121
+ stream = new Stream.Writable({
1122
+ autoDestroy: true,
1123
+ write(chunk, encoding, callback) {
1124
+ socket.write(b().d().raw(chunk).end(), callback)
1125
+ },
1126
+ destroy(error, callback) {
1127
+ callback(error)
1128
+ socket && socket.readyState === 'open' && socket.write(b().f().str(error + b.N).end())
1129
+ stream = null
1130
+ },
1131
+ final(callback) {
1132
+ socket.write(b().c().end())
1133
+ final = callback
1134
+ stream = null
1135
+ }
1136
+ })
1137
+ query.resolve(stream)
1138
+ }
1139
+
1140
+ function CopyOutResponse() {
1141
+ stream = new Stream.Readable({
1142
+ read() { socket.resume() }
1143
+ })
1144
+ query.resolve(stream)
1145
+ }
1146
+
1147
+ /* c8 ignore next 3 */
1148
+ function CopyBothResponse() {
1149
+ stream = new Stream.Duplex({
1150
+ autoDestroy: true,
1151
+ read() { socket.resume() },
1152
+ /* c8 ignore next 11 */
1153
+ write(chunk, encoding, callback) {
1154
+ socket.write(b().d().raw(chunk).end(), callback)
1155
+ },
1156
+ destroy(error, callback) {
1157
+ callback(error)
1158
+ socket && socket.readyState === 'open' && socket.write(b().f().str(error + b.N).end())
1159
+ stream = null
1160
+ },
1161
+ final(callback) {
1162
+ socket.write(b().c().end())
1163
+ final = callback
1164
+ }
1165
+ })
1166
+ query.resolve(stream)
1167
+ }
1168
+
1169
+ function CopyData(x) {
1170
+ stream && (stream.push(x.subarray(5)) || socket.pause())
1171
+ }
1172
+
1173
+ function CopyDone() {
1174
+ stream && stream.push(null)
1175
+ stream = null
1176
+ }
1177
+
1178
+ function NoticeResponse(x) {
1179
+ onnotice
1180
+ ? onnotice(parseError(x))
1181
+ : console.log(parseError(x)) // eslint-disable-line
1182
+
1183
+ }
1184
+
1185
+ /* c8 ignore next 3 */
1186
+ function EmptyQueryResponse() {
1187
+ /* noop */
1188
+ }
1189
+
1190
+ /* c8 ignore next 3 */
1191
+ function FunctionCallResponse() {
1192
+ errored(Errors.notSupported('FunctionCallResponse'))
1193
+ }
1194
+
1195
+ /* c8 ignore next 3 */
1196
+ function NegotiateProtocolVersion() {
1197
+ errored(Errors.notSupported('NegotiateProtocolVersion'))
1198
+ }
1199
+
1200
+ /* c8 ignore next 3 */
1201
+ function UnknownMessage(x) {
1202
+ console.error('Postgres.js : Unknown Message:', x[0]) // eslint-disable-line
1203
+ }
1204
+
1205
+ /* c8 ignore next 3 */
1206
+ function UnknownAuth(x, type) {
1207
+ console.error('Postgres.js : Unknown Auth:', type) // eslint-disable-line
1208
+ }
1209
+
1210
+ /* Messages */
1211
+ function Bind(parameters, types, statement = '', portal = '') {
1212
+ let prev
1213
+ , type
1214
+
1215
+ b().B().str(portal + b.N).str(statement + b.N).i16(0).i16(parameters.length)
1216
+
1217
+ parameters.forEach((x, i) => {
1218
+ if (x === null)
1219
+ return b.i32(0xFFFFFFFF)
1220
+
1221
+ type = types[i]
1222
+ x = type in options.serializers
1223
+ ? options.serializers[type](x)
1224
+ : '' + x
1225
+
1226
+ prev = b.i
1227
+ b.inc(4).str(x).i32(b.i - prev - 4, prev)
1228
+ })
1229
+
1230
+ b.i16(0)
1231
+
1232
+ return b.end()
1233
+ }
1234
+
1235
+ function Parse(str, parameters, types, name = '') {
1236
+ b().P().str(name + b.N).str(str + b.N).i16(parameters.length)
1237
+ parameters.forEach((x, i) => b.i32(types[i] || 0))
1238
+ return b.end()
1239
+ }
1240
+
1241
+ function Describe(x, name = '') {
1242
+ return b().D().str(x).str(name + b.N).end()
1243
+ }
1244
+
1245
+ function Execute(portal = '', rows = 0) {
1246
+ return Buffer.concat([
1247
+ b().E().str(portal + b.N).i32(rows).end(),
1248
+ Flush
1249
+ ])
1250
+ }
1251
+
1252
+ function Close(portal = '') {
1253
+ return Buffer.concat([
1254
+ b().C().str('P').str(portal + b.N).end(),
1255
+ b().S().end()
1256
+ ])
1257
+ }
1258
+
1259
+ function StartupMessage() {
1260
+ return b().inc(4).i16(3).z(2).str(
1261
+ Object.entries(Object.assign({
1262
+ user,
1263
+ database,
1264
+ client_encoding: 'UTF8'
1265
+ },
1266
+ options.connection
1267
+ )).filter(([, v]) => v).map(([k, v]) => k + b.N + v).join(b.N)
1268
+ ).z(2).end(0)
1269
+ }
1270
+
1271
+ }
1272
+
1273
+ function parseError(x) {
1274
+ const error = {}
1275
+ let start = 5
1276
+ for (let i = 5; i < x.length - 1; i++) {
1277
+ if (x[i] === 0) {
1278
+ error[errorFields[x[start]]] = x.toString('utf8', start + 1, i)
1279
+ start = i + 1
1280
+ }
1281
+ }
1282
+ return error
1283
+ }
1284
+
1285
+ function md5(x) {
1286
+ return crypto.createHash('md5').update(x).digest('hex')
1287
+ }
1288
+
1289
+ function hmac(key, x) {
1290
+ return crypto.createHmac('sha256', key).update(x).digest()
1291
+ }
1292
+
1293
+ function sha256(x) {
1294
+ return crypto.createHash('sha256').update(x).digest()
1295
+ }
1296
+
1297
+ function xor(a, b) {
1298
+ const length = Math.max(a.length, b.length)
1299
+ const buffer = Buffer.allocUnsafe(length)
1300
+ for (let i = 0; i < length; i++)
1301
+ buffer[i] = a[i] ^ b[i]
1302
+ return buffer
1303
+ }
1304
+
1305
+ function timer(fn, seconds) {
1306
+ seconds = typeof seconds === 'function' ? seconds() : seconds
1307
+ if (!seconds)
1308
+ return { cancel: noop, start: noop }
1309
+
1310
+ let timer
1311
+ return {
1312
+ cancel() {
1313
+ timer && (clearTimeout(timer), timer = null)
1314
+ },
1315
+ start(...args) {
1316
+ timer && clearTimeout(timer)
1317
+ timer = setTimeout(() => done(args), seconds * 1000)
1318
+ }
1319
+ }
1320
+
1321
+ function done(args) {
1322
+ timer = null
1323
+ fn.apply(null, args)
1324
+ }
1325
+ }