@depup/postgres 3.4.8-depup.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.
@@ -0,0 +1,1064 @@
1
+ import { Buffer } from 'node:buffer'
2
+ import { setImmediate, clearImmediate } from '../polyfills.js'
3
+ import { net } from '../polyfills.js'
4
+ import { tls } from '../polyfills.js'
5
+ import { crypto } from '../polyfills.js'
6
+ import Stream from 'node:stream'
7
+ import { performance } from '../polyfills.js'
8
+
9
+ import { stringify, handleValue, arrayParser, arraySerializer } from './types.js'
10
+ import { Errors } from './errors.js'
11
+ import Result from './result.js'
12
+ import Queue from './queue.js'
13
+ import { Query, CLOSE } from './query.js'
14
+ import b from './bytes.js'
15
+
16
+ export default Connection
17
+
18
+ let uid = 1
19
+
20
+ const Sync = b().S().end()
21
+ , Flush = b().H().end()
22
+ , SSLRequest = b().i32(8).i32(80877103).end(8)
23
+ , ExecuteUnnamed = Buffer.concat([b().E().str(b.N).i32(0).end(), Sync])
24
+ , DescribeUnnamed = b().D().str('S').str(b.N).end()
25
+ , noop = () => { /* noop */ }
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 } = {}) {
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
+ , connectTimer = timer(connectTimedOut, options.connect_timeout)
80
+
81
+ let socket = null
82
+ , cancelMessage
83
+ , errorResponse = null
84
+ , result = new Result()
85
+ , incoming = Buffer.alloc(0)
86
+ , needsTypes = options.fetch_types
87
+ , backendParameters = {}
88
+ , statements = {}
89
+ , statementId = Math.random().toString(36).slice(2)
90
+ , statementCount = 1
91
+ , closedTime = 0
92
+ , remaining = 0
93
+ , hostIndex = 0
94
+ , retries = 0
95
+ , length = 0
96
+ , delay = 0
97
+ , rows = 0
98
+ , serverSignature = null
99
+ , nextWriteTimer = null
100
+ , terminated = false
101
+ , incomings = null
102
+ , results = null
103
+ , initial = null
104
+ , ending = null
105
+ , stream = null
106
+ , chunk = null
107
+ , ended = null
108
+ , nonce = null
109
+ , query = null
110
+ , final = null
111
+
112
+ const connection = {
113
+ queue: queues.closed,
114
+ idleTimer,
115
+ connect(query) {
116
+ initial = query
117
+ reconnect()
118
+ },
119
+ terminate,
120
+ execute,
121
+ cancel,
122
+ end,
123
+ count: 0,
124
+ id
125
+ }
126
+
127
+ queues.closed && queues.closed.push(connection)
128
+
129
+ return connection
130
+
131
+ async function createSocket() {
132
+ let x
133
+ try {
134
+ x = options.socket
135
+ ? (await Promise.resolve(options.socket(options)))
136
+ : new net.Socket()
137
+ } catch (e) {
138
+ error(e)
139
+ return
140
+ }
141
+ x.on('error', error)
142
+ x.on('close', closed)
143
+ x.on('drain', drain)
144
+ return x
145
+ }
146
+
147
+ async function cancel({ pid, secret }, resolve, reject) {
148
+ try {
149
+ cancelMessage = b().i32(16).i32(80877102).i32(pid).i32(secret).end(16)
150
+ await connect()
151
+ socket.once('error', reject)
152
+ socket.once('close', resolve)
153
+ } catch (error) {
154
+ reject(error)
155
+ }
156
+ }
157
+
158
+ function execute(q) {
159
+ if (terminated)
160
+ return queryError(q, Errors.connection('CONNECTION_DESTROYED', options))
161
+
162
+ if (stream)
163
+ return queryError(q, Errors.generic('COPY_IN_PROGRESS', 'You cannot execute queries during copy'))
164
+
165
+ if (q.cancelled)
166
+ return
167
+
168
+ try {
169
+ q.state = backend
170
+ query
171
+ ? sent.push(q)
172
+ : (query = q, query.active = true)
173
+
174
+ build(q)
175
+ return write(toBuffer(q))
176
+ && !q.describeFirst
177
+ && !q.cursorFn
178
+ && sent.length < max_pipeline
179
+ && (!q.options.onexecute || q.options.onexecute(connection))
180
+ } catch (error) {
181
+ sent.length === 0 && write(Sync)
182
+ errored(error)
183
+ return true
184
+ }
185
+ }
186
+
187
+ function toBuffer(q) {
188
+ if (q.parameters.length >= 65534)
189
+ throw Errors.generic('MAX_PARAMETERS_EXCEEDED', 'Max number of parameters (65534) exceeded')
190
+
191
+ return q.options.simple
192
+ ? b().Q().str(q.statement.string + b.N).end()
193
+ : q.describeFirst
194
+ ? Buffer.concat([describe(q), Flush])
195
+ : q.prepare
196
+ ? q.prepared
197
+ ? prepared(q)
198
+ : Buffer.concat([describe(q), prepared(q)])
199
+ : unnamed(q)
200
+ }
201
+
202
+ function describe(q) {
203
+ return Buffer.concat([
204
+ Parse(q.statement.string, q.parameters, q.statement.types, q.statement.name),
205
+ Describe('S', q.statement.name)
206
+ ])
207
+ }
208
+
209
+ function prepared(q) {
210
+ return Buffer.concat([
211
+ Bind(q.parameters, q.statement.types, q.statement.name, q.cursorName),
212
+ q.cursorFn
213
+ ? Execute('', q.cursorRows)
214
+ : ExecuteUnnamed
215
+ ])
216
+ }
217
+
218
+ function unnamed(q) {
219
+ return Buffer.concat([
220
+ Parse(q.statement.string, q.parameters, q.statement.types),
221
+ DescribeUnnamed,
222
+ prepared(q)
223
+ ])
224
+ }
225
+
226
+ function build(q) {
227
+ const parameters = []
228
+ , types = []
229
+
230
+ const string = stringify(q, q.strings[0], q.args[0], parameters, types, options)
231
+
232
+ !q.tagged && q.args.forEach(x => handleValue(x, parameters, types, options))
233
+
234
+ q.prepare = options.prepare && ('prepare' in q.options ? q.options.prepare : true)
235
+ q.string = string
236
+ q.signature = q.prepare && types + string
237
+ q.onlyDescribe && (delete statements[q.signature])
238
+ q.parameters = q.parameters || parameters
239
+ q.prepared = q.prepare && q.signature in statements
240
+ q.describeFirst = q.onlyDescribe || (parameters.length && !q.prepared)
241
+ q.statement = q.prepared
242
+ ? statements[q.signature]
243
+ : { string, types, name: q.prepare ? statementId + statementCount++ : '' }
244
+
245
+ typeof options.debug === 'function' && options.debug(id, string, parameters, types)
246
+ }
247
+
248
+ function write(x, fn) {
249
+ chunk = chunk ? Buffer.concat([chunk, x]) : Buffer.from(x)
250
+ if (fn || chunk.length >= 1024)
251
+ return nextWrite(fn)
252
+ nextWriteTimer === null && (nextWriteTimer = setImmediate(nextWrite))
253
+ return true
254
+ }
255
+
256
+ function nextWrite(fn) {
257
+ const x = socket.write(chunk, fn)
258
+ nextWriteTimer !== null && clearImmediate(nextWriteTimer)
259
+ chunk = nextWriteTimer = null
260
+ return x
261
+ }
262
+
263
+ function connectTimedOut() {
264
+ errored(Errors.connection('CONNECT_TIMEOUT', options, socket))
265
+ socket.destroy()
266
+ }
267
+
268
+ async function secure() {
269
+ if (sslnegotiation !== 'direct') {
270
+ write(SSLRequest)
271
+ const canSSL = await new Promise(r => socket.once('data', x => r(x[0] === 83))) // S
272
+
273
+ if (!canSSL && ssl === 'prefer')
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)
296
+ }
297
+
298
+ /* c8 ignore next 3 */
299
+ function drain() {
300
+ !query && onopen(connection)
301
+ }
302
+
303
+ function data(x) {
304
+ if (incomings) {
305
+ incomings.push(x)
306
+ remaining -= x.length
307
+ if (remaining > 0)
308
+ return
309
+ }
310
+
311
+ incoming = incomings
312
+ ? Buffer.concat(incomings, length - remaining)
313
+ : incoming.length === 0
314
+ ? x
315
+ : Buffer.concat([incoming, x], incoming.length + x.length)
316
+
317
+ while (incoming.length > 4) {
318
+ length = incoming.readUInt32BE(1)
319
+ if (length >= incoming.length) {
320
+ remaining = length - incoming.length
321
+ incomings = [incoming]
322
+ break
323
+ }
324
+
325
+ try {
326
+ handle(incoming.subarray(0, length + 1))
327
+ } catch (e) {
328
+ query && (query.cursorFn || query.describeFirst) && write(Sync)
329
+ errored(e)
330
+ }
331
+ incoming = incoming.subarray(length + 1)
332
+ remaining = 0
333
+ incomings = null
334
+ }
335
+ }
336
+
337
+ async function connect() {
338
+ terminated = false
339
+ backendParameters = {}
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
+ }
362
+
363
+ function reconnect() {
364
+ setTimeout(connect, closedTime ? Math.max(0, closedTime + delay - performance.now()) : 0)
365
+ }
366
+
367
+ function connected() {
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
+
387
+ errored(err)
388
+ while (sent.length)
389
+ queryError(sent.shift(), err)
390
+ }
391
+
392
+ function errored(err) {
393
+ stream && (stream.destroy(err), stream = null)
394
+ query && queryError(query, err)
395
+ initial && (queryError(initial, err), initial = null)
396
+ }
397
+
398
+ function queryError(query, err) {
399
+ if (query.reserve)
400
+ return query.reject(err)
401
+
402
+ if (!err || typeof err !== 'object')
403
+ err = new Error(err)
404
+
405
+ 'query' in err || 'parameters' in err || Object.defineProperties(err, {
406
+ stack: { value: err.stack + query.origin.replace(/.*\n/, '\n'), enumerable: options.debug },
407
+ query: { value: query.string, enumerable: options.debug },
408
+ parameters: { value: query.parameters, enumerable: options.debug },
409
+ args: { value: query.args, enumerable: options.debug },
410
+ types: { value: query.statement && query.statement.types, enumerable: options.debug }
411
+ })
412
+ query.reject(err)
413
+ }
414
+
415
+ function end() {
416
+ return ending || (
417
+ !connection.reserved && onend(connection),
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
+ }
423
+
424
+ function terminate() {
425
+ terminated = true
426
+ if (stream || query || initial || sent.length)
427
+ error(Errors.connection('CONNECTION_DESTROYED', options))
428
+
429
+ clearImmediate(nextWriteTimer)
430
+ if (socket) {
431
+ socket.removeListener('data', data)
432
+ socket.removeListener('connect', connected)
433
+ socket.readyState === 'open' && socket.end(b().X().end())
434
+ }
435
+ ended && (ended(), ending = ended = null)
436
+ }
437
+
438
+ async function closed(hadError) {
439
+ incoming = Buffer.alloc(0)
440
+ remaining = 0
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()
448
+
449
+ socket.removeAllListeners()
450
+ socket = null
451
+
452
+ if (initial)
453
+ return reconnect()
454
+
455
+ !hadError && (query || sent.length) && error(Errors.connection('CONNECTION_CLOSED', options, socket))
456
+ closedTime = performance.now()
457
+ hadError && options.shared.retries++
458
+ delay = (typeof backoff === 'function' ? backoff(options.shared.retries) : backoff) * 1000
459
+ onclose(connection, Errors.connection('CONNECTION_CLOSED', options, socket))
460
+ }
461
+
462
+ /* Handlers */
463
+ function handle(xs, x = xs[0]) {
464
+ (
465
+ x === 68 ? DataRow : // D
466
+ x === 100 ? CopyData : // d
467
+ x === 65 ? NotificationResponse : // A
468
+ x === 83 ? ParameterStatus : // S
469
+ x === 90 ? ReadyForQuery : // Z
470
+ x === 67 ? CommandComplete : // C
471
+ x === 50 ? BindComplete : // 2
472
+ x === 49 ? ParseComplete : // 1
473
+ x === 116 ? ParameterDescription : // t
474
+ x === 84 ? RowDescription : // T
475
+ x === 82 ? Authentication : // R
476
+ x === 110 ? NoData : // n
477
+ x === 75 ? BackendKeyData : // K
478
+ x === 69 ? ErrorResponse : // E
479
+ x === 115 ? PortalSuspended : // s
480
+ x === 51 ? CloseComplete : // 3
481
+ x === 71 ? CopyInResponse : // G
482
+ x === 78 ? NoticeResponse : // N
483
+ x === 72 ? CopyOutResponse : // H
484
+ x === 99 ? CopyDone : // c
485
+ x === 73 ? EmptyQueryResponse : // I
486
+ x === 86 ? FunctionCallResponse : // V
487
+ x === 118 ? NegotiateProtocolVersion : // v
488
+ x === 87 ? CopyBothResponse : // W
489
+ /* c8 ignore next */
490
+ UnknownMessage
491
+ )(xs)
492
+ }
493
+
494
+ function DataRow(x) {
495
+ let index = 7
496
+ let length
497
+ let column
498
+ let value
499
+
500
+ const row = query.isRaw ? new Array(query.statement.columns.length) : {}
501
+ for (let i = 0; i < query.statement.columns.length; i++) {
502
+ column = query.statement.columns[i]
503
+ length = x.readInt32BE(index)
504
+ index += 4
505
+
506
+ value = length === -1
507
+ ? null
508
+ : query.isRaw === true
509
+ ? x.subarray(index, index += length)
510
+ : column.parser === undefined
511
+ ? x.toString('utf8', index, index += length)
512
+ : column.parser.array === true
513
+ ? column.parser(x.toString('utf8', index + 1, index += length))
514
+ : column.parser(x.toString('utf8', index, index += length))
515
+
516
+ query.isRaw
517
+ ? (row[i] = query.isRaw === true
518
+ ? value
519
+ : transform.value.from ? transform.value.from(value, column) : value)
520
+ : (row[column.name] = transform.value.from ? transform.value.from(value, column) : value)
521
+ }
522
+
523
+ query.forEachFn
524
+ ? query.forEachFn(transform.row.from ? transform.row.from(row) : row, result)
525
+ : (result[rows++] = transform.row.from ? transform.row.from(row) : row)
526
+ }
527
+
528
+ function ParameterStatus(x) {
529
+ const [k, v] = x.toString('utf8', 5, x.length - 1).split(b.N)
530
+ backendParameters[k] = v
531
+ if (options.parameters[k] !== v) {
532
+ options.parameters[k] = v
533
+ onparameter && onparameter(k, v)
534
+ }
535
+ }
536
+
537
+ function ReadyForQuery(x) {
538
+ if (query) {
539
+ if (errorResponse) {
540
+ query.retried
541
+ ? errored(query.retried)
542
+ : query.prepared && retryRoutines.has(errorResponse.routine)
543
+ ? retry(query, errorResponse)
544
+ : errored(errorResponse)
545
+ } else {
546
+ query.resolve(results || result)
547
+ }
548
+ } else if (errorResponse) {
549
+ errored(errorResponse)
550
+ }
551
+
552
+ query = results = errorResponse = null
553
+ 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
+
564
+ if (needsTypes) {
565
+ initial.reserve && (initial = null)
566
+ return fetchArrayTypes()
567
+ }
568
+
569
+ initial && !initial.reserve && execute(initial)
570
+ options.shared.retries = retries = 0
571
+ initial = null
572
+ return
573
+ }
574
+
575
+ while (sent.length && (query = sent.shift()) && (query.active = true, query.cancelled))
576
+ Connection(options).cancel(query.state, query.cancelled.resolve, query.cancelled.reject)
577
+
578
+ if (query)
579
+ return // Consider opening if able and sent.length < 50
580
+
581
+ connection.reserved
582
+ ? !connection.reserved.release && x[5] === 73 // I
583
+ ? ending
584
+ ? terminate()
585
+ : (connection.reserved = null, onopen(connection))
586
+ : connection.reserved()
587
+ : ending
588
+ ? terminate()
589
+ : onopen(connection)
590
+ }
591
+
592
+ function CommandComplete(x) {
593
+ rows = 0
594
+
595
+ for (let i = x.length - 1; i > 0; i--) {
596
+ if (x[i] === 32 && x[i + 1] < 58 && result.count === null)
597
+ result.count = +x.toString('utf8', i + 1, x.length - 1)
598
+ if (x[i - 1] >= 65) {
599
+ result.command = x.toString('utf8', 5, i)
600
+ result.state = backend
601
+ break
602
+ }
603
+ }
604
+
605
+ final && (final(), final = null)
606
+
607
+ if (result.command === 'BEGIN' && max !== 1 && !connection.reserved)
608
+ return errored(Errors.generic('UNSAFE_TRANSACTION', 'Only use sql.begin, sql.reserved or max: 1'))
609
+
610
+ if (query.options.simple)
611
+ return BindComplete()
612
+
613
+ if (query.cursorFn) {
614
+ result.count && query.cursorFn(result)
615
+ write(Sync)
616
+ }
617
+ }
618
+
619
+ function ParseComplete() {
620
+ query.parsing = false
621
+ }
622
+
623
+ function BindComplete() {
624
+ !result.statement && (result.statement = query.statement)
625
+ result.columns = query.statement.columns
626
+ }
627
+
628
+ function ParameterDescription(x) {
629
+ const length = x.readUInt16BE(5)
630
+
631
+ for (let i = 0; i < length; ++i)
632
+ !query.statement.types[i] && (query.statement.types[i] = x.readUInt32BE(7 + i * 4))
633
+
634
+ query.prepare && (statements[query.signature] = query.statement)
635
+ query.describeFirst && !query.onlyDescribe && (write(prepared(query)), query.describeFirst = false)
636
+ }
637
+
638
+ function RowDescription(x) {
639
+ if (result.command) {
640
+ results = results || [result]
641
+ results.push(result = new Result())
642
+ result.count = null
643
+ query.statement.columns = null
644
+ }
645
+
646
+ const length = x.readUInt16BE(5)
647
+ let index = 7
648
+ let start
649
+
650
+ query.statement.columns = Array(length)
651
+
652
+ for (let i = 0; i < length; ++i) {
653
+ start = index
654
+ while (x[index++] !== 0);
655
+ const table = x.readUInt32BE(index)
656
+ const number = x.readUInt16BE(index + 4)
657
+ const type = x.readUInt32BE(index + 6)
658
+ query.statement.columns[i] = {
659
+ name: transform.column.from
660
+ ? transform.column.from(x.toString('utf8', start, index - 1))
661
+ : x.toString('utf8', start, index - 1),
662
+ parser: parsers[type],
663
+ table,
664
+ number,
665
+ type
666
+ }
667
+ index += 18
668
+ }
669
+
670
+ result.statement = query.statement
671
+ if (query.onlyDescribe)
672
+ return (query.resolve(query.statement), write(Sync))
673
+ }
674
+
675
+ async function Authentication(x, type = x.readUInt32BE(5)) {
676
+ (
677
+ type === 3 ? AuthenticationCleartextPassword :
678
+ type === 5 ? AuthenticationMD5Password :
679
+ type === 10 ? SASL :
680
+ type === 11 ? SASLContinue :
681
+ type === 12 ? SASLFinal :
682
+ type !== 0 ? UnknownAuth :
683
+ noop
684
+ )(x, type)
685
+ }
686
+
687
+ /* c8 ignore next 5 */
688
+ async function AuthenticationCleartextPassword() {
689
+ const payload = await Pass()
690
+ write(
691
+ b().p().str(payload).z(1).end()
692
+ )
693
+ }
694
+
695
+ async function AuthenticationMD5Password(x) {
696
+ const payload = 'md5' + (
697
+ await md5(
698
+ Buffer.concat([
699
+ Buffer.from(await md5((await Pass()) + user)),
700
+ x.subarray(9)
701
+ ])
702
+ )
703
+ )
704
+ write(
705
+ b().p().str(payload).z(1).end()
706
+ )
707
+ }
708
+
709
+ async function SASL() {
710
+ nonce = (await crypto.randomBytes(18)).toString('base64')
711
+ b().p().str('SCRAM-SHA-256' + b.N)
712
+ const i = b.i
713
+ write(b.inc(4).str('n,,n=*,r=' + nonce).i32(b.i - i - 4, i).end())
714
+ }
715
+
716
+ async function SASLContinue(x) {
717
+ const res = x.toString('utf8', 9).split(',').reduce((acc, x) => (acc[x[0]] = x.slice(2), acc), {})
718
+
719
+ const saltedPassword = await crypto.pbkdf2Sync(
720
+ await Pass(),
721
+ Buffer.from(res.s, 'base64'),
722
+ parseInt(res.i), 32,
723
+ 'sha256'
724
+ )
725
+
726
+ const clientKey = await hmac(saltedPassword, 'Client Key')
727
+
728
+ const auth = 'n=*,r=' + nonce + ','
729
+ + 'r=' + res.r + ',s=' + res.s + ',i=' + res.i
730
+ + ',c=biws,r=' + res.r
731
+
732
+ serverSignature = (await hmac(await hmac(saltedPassword, 'Server Key'), auth)).toString('base64')
733
+
734
+ const payload = 'c=biws,r=' + res.r + ',p=' + xor(
735
+ clientKey, Buffer.from(await hmac(await sha256(clientKey), auth))
736
+ ).toString('base64')
737
+
738
+ write(
739
+ b().p().str(payload).end()
740
+ )
741
+ }
742
+
743
+ function SASLFinal(x) {
744
+ if (x.toString('utf8', 9).split(b.N, 1)[0].slice(2) === serverSignature)
745
+ return
746
+ /* c8 ignore next 5 */
747
+ errored(Errors.generic('SASL_SIGNATURE_MISMATCH', 'The server did not return the correct signature'))
748
+ socket.destroy()
749
+ }
750
+
751
+ function Pass() {
752
+ return Promise.resolve(typeof options.pass === 'function'
753
+ ? options.pass()
754
+ : options.pass
755
+ )
756
+ }
757
+
758
+ function NoData() {
759
+ result.statement = query.statement
760
+ result.statement.columns = []
761
+ if (query.onlyDescribe)
762
+ return (query.resolve(query.statement), write(Sync))
763
+ }
764
+
765
+ function BackendKeyData(x) {
766
+ backend.pid = x.readUInt32BE(5)
767
+ backend.secret = x.readUInt32BE(9)
768
+ }
769
+
770
+ async function fetchArrayTypes() {
771
+ needsTypes = false
772
+ const types = await new Query([`
773
+ select b.oid, b.typarray
774
+ from pg_catalog.pg_type a
775
+ left join pg_catalog.pg_type b on b.oid = a.typelem
776
+ where a.typcategory = 'A'
777
+ group by b.oid, b.typarray
778
+ order by b.oid
779
+ `], [], execute)
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)
790
+ }
791
+
792
+ function tryNext(x, xs) {
793
+ return (
794
+ (x === 'read-write' && xs.default_transaction_read_only === 'on') ||
795
+ (x === 'read-only' && xs.default_transaction_read_only === 'off') ||
796
+ (x === 'primary' && xs.in_hot_standby === 'on') ||
797
+ (x === 'standby' && xs.in_hot_standby === 'off') ||
798
+ (x === 'prefer-standby' && xs.in_hot_standby === 'off' && options.host[retries])
799
+ )
800
+ }
801
+
802
+ function fetchState() {
803
+ const query = new Query([`
804
+ show transaction_read_only;
805
+ select pg_catalog.pg_is_in_recovery()
806
+ `], [], execute, null, { simple: true })
807
+ query.resolve = ([[a], [b]]) => {
808
+ backendParameters.default_transaction_read_only = a.transaction_read_only
809
+ backendParameters.in_hot_standby = b.pg_is_in_recovery ? 'on' : 'off'
810
+ }
811
+ query.execute()
812
+ }
813
+
814
+ function ErrorResponse(x) {
815
+ if (query) {
816
+ (query.cursorFn || query.describeFirst) && write(Sync)
817
+ errorResponse = Errors.postgres(parseError(x))
818
+ } else {
819
+ errored(Errors.postgres(parseError(x)))
820
+ }
821
+ }
822
+
823
+ function retry(q, error) {
824
+ delete statements[q.signature]
825
+ q.retried = error
826
+ execute(q)
827
+ }
828
+
829
+ function NotificationResponse(x) {
830
+ if (!onnotify)
831
+ return
832
+
833
+ let index = 9
834
+ while (x[index++] !== 0);
835
+ onnotify(
836
+ x.toString('utf8', 9, index - 1),
837
+ x.toString('utf8', index, x.length - 1)
838
+ )
839
+ }
840
+
841
+ async function PortalSuspended() {
842
+ try {
843
+ const x = await Promise.resolve(query.cursorFn(result))
844
+ rows = 0
845
+ x === CLOSE
846
+ ? write(Close(query.portal))
847
+ : (result = new Result(), write(Execute('', query.cursorRows)))
848
+ } catch (err) {
849
+ write(Sync)
850
+ query.reject(err)
851
+ }
852
+ }
853
+
854
+ function CloseComplete() {
855
+ result.count && query.cursorFn(result)
856
+ query.resolve(result)
857
+ }
858
+
859
+ function CopyInResponse() {
860
+ stream = new Stream.Writable({
861
+ autoDestroy: true,
862
+ write(chunk, encoding, callback) {
863
+ socket.write(b().d().raw(chunk).end(), callback)
864
+ },
865
+ destroy(error, callback) {
866
+ callback(error)
867
+ socket.write(b().f().str(error + b.N).end())
868
+ stream = null
869
+ },
870
+ final(callback) {
871
+ socket.write(b().c().end())
872
+ final = callback
873
+ stream = null
874
+ }
875
+ })
876
+ query.resolve(stream)
877
+ }
878
+
879
+ function CopyOutResponse() {
880
+ stream = new Stream.Readable({
881
+ read() { socket.resume() }
882
+ })
883
+ query.resolve(stream)
884
+ }
885
+
886
+ /* c8 ignore next 3 */
887
+ function CopyBothResponse() {
888
+ stream = new Stream.Duplex({
889
+ autoDestroy: true,
890
+ read() { socket.resume() },
891
+ /* c8 ignore next 11 */
892
+ write(chunk, encoding, callback) {
893
+ socket.write(b().d().raw(chunk).end(), callback)
894
+ },
895
+ destroy(error, callback) {
896
+ callback(error)
897
+ socket.write(b().f().str(error + b.N).end())
898
+ stream = null
899
+ },
900
+ final(callback) {
901
+ socket.write(b().c().end())
902
+ final = callback
903
+ }
904
+ })
905
+ query.resolve(stream)
906
+ }
907
+
908
+ function CopyData(x) {
909
+ stream && (stream.push(x.subarray(5)) || socket.pause())
910
+ }
911
+
912
+ function CopyDone() {
913
+ stream && stream.push(null)
914
+ stream = null
915
+ }
916
+
917
+ function NoticeResponse(x) {
918
+ onnotice
919
+ ? onnotice(parseError(x))
920
+ : console.log(parseError(x)) // eslint-disable-line
921
+
922
+ }
923
+
924
+ /* c8 ignore next 3 */
925
+ function EmptyQueryResponse() {
926
+ /* noop */
927
+ }
928
+
929
+ /* c8 ignore next 3 */
930
+ function FunctionCallResponse() {
931
+ errored(Errors.notSupported('FunctionCallResponse'))
932
+ }
933
+
934
+ /* c8 ignore next 3 */
935
+ function NegotiateProtocolVersion() {
936
+ errored(Errors.notSupported('NegotiateProtocolVersion'))
937
+ }
938
+
939
+ /* c8 ignore next 3 */
940
+ function UnknownMessage(x) {
941
+ console.error('Postgres.js : Unknown Message:', x[0]) // eslint-disable-line
942
+ }
943
+
944
+ /* c8 ignore next 3 */
945
+ function UnknownAuth(x, type) {
946
+ console.error('Postgres.js : Unknown Auth:', type) // eslint-disable-line
947
+ }
948
+
949
+ /* Messages */
950
+ function Bind(parameters, types, statement = '', portal = '') {
951
+ let prev
952
+ , type
953
+
954
+ b().B().str(portal + b.N).str(statement + b.N).i16(0).i16(parameters.length)
955
+
956
+ parameters.forEach((x, i) => {
957
+ if (x === null)
958
+ return b.i32(0xFFFFFFFF)
959
+
960
+ type = types[i]
961
+ parameters[i] = x = type in options.serializers
962
+ ? options.serializers[type](x)
963
+ : '' + x
964
+
965
+ prev = b.i
966
+ b.inc(4).str(x).i32(b.i - prev - 4, prev)
967
+ })
968
+
969
+ b.i16(0)
970
+
971
+ return b.end()
972
+ }
973
+
974
+ function Parse(str, parameters, types, name = '') {
975
+ b().P().str(name + b.N).str(str + b.N).i16(parameters.length)
976
+ parameters.forEach((x, i) => b.i32(types[i] || 0))
977
+ return b.end()
978
+ }
979
+
980
+ function Describe(x, name = '') {
981
+ return b().D().str(x).str(name + b.N).end()
982
+ }
983
+
984
+ function Execute(portal = '', rows = 0) {
985
+ return Buffer.concat([
986
+ b().E().str(portal + b.N).i32(rows).end(),
987
+ Flush
988
+ ])
989
+ }
990
+
991
+ function Close(portal = '') {
992
+ return Buffer.concat([
993
+ b().C().str('P').str(portal + b.N).end(),
994
+ b().S().end()
995
+ ])
996
+ }
997
+
998
+ function StartupMessage() {
999
+ return cancelMessage || b().inc(4).i16(3).z(2).str(
1000
+ Object.entries(Object.assign({
1001
+ user,
1002
+ database,
1003
+ client_encoding: 'UTF8'
1004
+ },
1005
+ options.connection
1006
+ )).filter(([, v]) => v).map(([k, v]) => k + b.N + v).join(b.N)
1007
+ ).z(2).end(0)
1008
+ }
1009
+
1010
+ }
1011
+
1012
+ function parseError(x) {
1013
+ const error = {}
1014
+ let start = 5
1015
+ for (let i = 5; i < x.length - 1; i++) {
1016
+ if (x[i] === 0) {
1017
+ error[errorFields[x[start]]] = x.toString('utf8', start + 1, i)
1018
+ start = i + 1
1019
+ }
1020
+ }
1021
+ return error
1022
+ }
1023
+
1024
+ function md5(x) {
1025
+ return crypto.createHash('md5').update(x).digest('hex')
1026
+ }
1027
+
1028
+ function hmac(key, x) {
1029
+ return crypto.createHmac('sha256', key).update(x).digest()
1030
+ }
1031
+
1032
+ function sha256(x) {
1033
+ return crypto.createHash('sha256').update(x).digest()
1034
+ }
1035
+
1036
+ function xor(a, b) {
1037
+ const length = Math.max(a.length, b.length)
1038
+ const buffer = Buffer.allocUnsafe(length)
1039
+ for (let i = 0; i < length; i++)
1040
+ buffer[i] = a[i] ^ b[i]
1041
+ return buffer
1042
+ }
1043
+
1044
+ function timer(fn, seconds) {
1045
+ seconds = typeof seconds === 'function' ? seconds() : seconds
1046
+ if (!seconds)
1047
+ return { cancel: noop, start: noop }
1048
+
1049
+ let timer
1050
+ return {
1051
+ cancel() {
1052
+ timer && (clearTimeout(timer), timer = null)
1053
+ },
1054
+ start() {
1055
+ timer && clearTimeout(timer)
1056
+ timer = setTimeout(done, seconds * 1000, arguments)
1057
+ }
1058
+ }
1059
+
1060
+ function done(args) {
1061
+ fn.apply(null, args)
1062
+ timer = null
1063
+ }
1064
+ }