pg 8.1.0 → 8.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
  <span class="badge-npmversion"><a href="https://npmjs.org/package/pg" title="View this project on NPM"><img src="https://img.shields.io/npm/v/pg.svg" alt="NPM version" /></a></span>
6
6
  <span class="badge-npmdownloads"><a href="https://npmjs.org/package/pg" title="View this project on NPM"><img src="https://img.shields.io/npm/dm/pg.svg" alt="NPM downloads" /></a></span>
7
7
 
8
- Non-blocking PostgreSQL client for Node.js. Pure JavaScript and optional native libpq bindings.
8
+ Non-blocking PostgreSQL client for Node.js. Pure JavaScript and optional native libpq bindings.
9
9
 
10
10
  ## Install
11
11
 
@@ -14,30 +14,31 @@ $ npm install pg
14
14
  ```
15
15
 
16
16
  ---
17
- ## :star: [Documentation](https://node-postgres.com) :star:
18
17
 
18
+ ## :star: [Documentation](https://node-postgres.com) :star:
19
19
 
20
20
  ### Features
21
21
 
22
- * Pure JavaScript client and native libpq bindings share _the same API_
23
- * Connection pooling
24
- * Extensible JS ↔ PostgreSQL data-type coercion
25
- * Supported PostgreSQL features
26
- * Parameterized queries
27
- * Named statements with query plan caching
28
- * Async notifications with `LISTEN/NOTIFY`
29
- * Bulk import & export with `COPY TO/COPY FROM`
22
+ - Pure JavaScript client and native libpq bindings share _the same API_
23
+ - Connection pooling
24
+ - Extensible JS ↔ PostgreSQL data-type coercion
25
+ - Supported PostgreSQL features
26
+ - Parameterized queries
27
+ - Named statements with query plan caching
28
+ - Async notifications with `LISTEN/NOTIFY`
29
+ - Bulk import & export with `COPY TO/COPY FROM`
30
30
 
31
31
  ### Extras
32
32
 
33
- node-postgres is by design pretty light on abstractions. These are some handy modules we've been using over the years to complete the picture.
33
+ node-postgres is by design pretty light on abstractions. These are some handy modules we've been using over the years to complete the picture.
34
34
  The entire list can be found on our [wiki](https://github.com/brianc/node-postgres/wiki/Extras).
35
35
 
36
36
  ## Support
37
37
 
38
- node-postgres is free software. If you encounter a bug with the library please open an issue on the [GitHub repo](https://github.com/brianc/node-postgres). If you have questions unanswered by the documentation please open an issue pointing out how the documentation was unclear & I will do my best to make it better!
38
+ node-postgres is free software. If you encounter a bug with the library please open an issue on the [GitHub repo](https://github.com/brianc/node-postgres). If you have questions unanswered by the documentation please open an issue pointing out how the documentation was unclear & I will do my best to make it better!
39
39
 
40
40
  When you open an issue please provide:
41
+
41
42
  - version of Node
42
43
  - version of Postgres
43
44
  - smallest possible snippet of code to reproduce the problem
@@ -49,10 +50,6 @@ You can also follow me [@briancarlson](https://twitter.com/briancarlson) if that
49
50
  node-postgres's continued development has been made possible in part by generous finanical support from [the community](https://github.com/brianc/node-postgres/blob/master/SPONSORS.md) and these featured sponsors:
50
51
 
51
52
  <div align="center">
52
- <a href="https://www.timescale.com" target="_blank">
53
- <img height="80" src="https://node-postgres.com/timescale.svg" />
54
- </a>
55
- <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAABCAQAAAB0m0auAAAADElEQVR42mNkIBIAAABSAAI2VLqiAAAAAElFTkSuQmCC" />
56
53
  <a href="https://crate.io" target="_blank">
57
54
  <img height="80" src="https://node-postgres.com/crate-io.png" />
58
55
  </a>
@@ -60,19 +57,18 @@ node-postgres's continued development has been made possible in part by generous
60
57
 
61
58
  If you or your company are benefiting from node-postgres and would like to help keep the project financially sustainable [please consider supporting](https://github.com/sponsors/brianc) its development.
62
59
 
63
-
64
60
  ## Contributing
65
61
 
66
- __:heart: contributions!__
62
+ **:heart: contributions!**
67
63
 
68
- I will __happily__ accept your pull request if it:
69
- - __has tests__
64
+ I will **happily** accept your pull request if it:
65
+
66
+ - **has tests**
70
67
  - looks reasonable
71
68
  - does not break backwards compatibility
72
69
 
73
70
  If your change involves breaking backwards compatibility please please point that out in the pull request & we can discuss & plan when and how to release it and what type of documentation or communicate it will require.
74
71
 
75
-
76
72
  ## Troubleshooting and FAQ
77
73
 
78
74
  The causes and solutions to common errors can be found among the [Frequently Asked Questions (FAQ)](https://github.com/brianc/node-postgres/wiki/FAQ)
@@ -81,21 +77,20 @@ The causes and solutions to common errors can be found among the [Frequently Ask
81
77
 
82
78
  Copyright (c) 2010-2020 Brian Carlson (brian.m.carlson@gmail.com)
83
79
 
84
- Permission is hereby granted, free of charge, to any person obtaining a copy
85
- of this software and associated documentation files (the "Software"), to deal
86
- in the Software without restriction, including without limitation the rights
87
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
88
- copies of the Software, and to permit persons to whom the Software is
89
- furnished to do so, subject to the following conditions:
90
-
91
- The above copyright notice and this permission notice shall be included in
92
- all copies or substantial portions of the Software.
93
-
94
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
95
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
96
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
97
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
98
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
99
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
100
- THE SOFTWARE.
101
-
80
+ Permission is hereby granted, free of charge, to any person obtaining a copy
81
+ of this software and associated documentation files (the "Software"), to deal
82
+ in the Software without restriction, including without limitation the rights
83
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
84
+ copies of the Software, and to permit persons to whom the Software is
85
+ furnished to do so, subject to the following conditions:
86
+
87
+ The above copyright notice and this permission notice shall be included in
88
+ all copies or substantial portions of the Software.
89
+
90
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
91
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
92
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
93
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
94
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
95
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
96
+ THE SOFTWARE.
package/lib/client.js CHANGED
@@ -18,9 +18,6 @@ var ConnectionParameters = require('./connection-parameters')
18
18
  var Query = require('./query')
19
19
  var defaults = require('./defaults')
20
20
  var Connection = require('./connection')
21
- if (process.env.PG_FAST_CONNECTION) {
22
- Connection = require('./connection-fast')
23
- }
24
21
 
25
22
  var Client = function (config) {
26
23
  EventEmitter.call(this)
@@ -394,6 +391,9 @@ Client.prototype.getStartupConf = function () {
394
391
  if (params.idle_in_transaction_session_timeout) {
395
392
  data.idle_in_transaction_session_timeout = String(parseInt(params.idle_in_transaction_session_timeout, 10))
396
393
  }
394
+ if (params.options) {
395
+ data.options = params.options
396
+ }
397
397
 
398
398
  return data
399
399
  }
@@ -70,6 +70,7 @@ var ConnectionParameters = function (config) {
70
70
  })
71
71
 
72
72
  this.binary = val('binary', config)
73
+ this.options = val('options', config)
73
74
 
74
75
  this.ssl = typeof config.ssl === 'undefined' ? readSSLConfigFromEnvironment() : config.ssl
75
76
 
@@ -126,6 +127,7 @@ ConnectionParameters.prototype.getLibpqConnectionString = function (cb) {
126
127
  add(params, this, 'application_name')
127
128
  add(params, this, 'fallback_application_name')
128
129
  add(params, this, 'connect_timeout')
130
+ add(params, this, 'options')
129
131
 
130
132
  var ssl = typeof this.ssl === 'object' ? this.ssl : this.ssl ? { sslmode: this.ssl } : {}
131
133
  add(params, ssl, 'sslmode')
package/lib/connection.js CHANGED
@@ -11,11 +11,9 @@ var net = require('net')
11
11
  var EventEmitter = require('events').EventEmitter
12
12
  var util = require('util')
13
13
 
14
- var Writer = require('buffer-writer')
15
- var Reader = require('packet-reader')
14
+ const { parse, serialize } = require('pg-protocol')
16
15
 
17
- var TEXT_MODE = 0
18
- var BINARY_MODE = 1
16
+ // TODO(bmc) support binary mode at some point
19
17
  var Connection = function (config) {
20
18
  EventEmitter.call(this)
21
19
  config = config || {}
@@ -23,20 +21,10 @@ var Connection = function (config) {
23
21
  this._keepAlive = config.keepAlive
24
22
  this._keepAliveInitialDelayMillis = config.keepAliveInitialDelayMillis
25
23
  this.lastBuffer = false
26
- this.lastOffset = 0
27
- this.buffer = null
28
- this.offset = null
29
- this.encoding = config.encoding || 'utf8'
30
24
  this.parsedStatements = {}
31
- this.writer = new Writer()
32
25
  this.ssl = config.ssl || false
33
26
  this._ending = false
34
- this._mode = TEXT_MODE
35
27
  this._emitMessage = false
36
- this._reader = new Reader({
37
- headerSize: 1,
38
- lengthPadding: -4,
39
- })
40
28
  var self = this
41
29
  this.on('newListener', function (eventName) {
42
30
  if (eventName === 'message') {
@@ -51,6 +39,7 @@ Connection.prototype.connect = function (port, host) {
51
39
  var self = this
52
40
 
53
41
  this._connecting = true
42
+ this.stream.setNoDelay(true)
54
43
  this.stream.connect(port, host)
55
44
 
56
45
  this.stream.once('connect', function () {
@@ -101,576 +90,124 @@ Connection.prototype.connect = function (port, host) {
101
90
  options.servername = host
102
91
  }
103
92
  self.stream = tls.connect(options)
104
- self.stream.on('error', reportStreamError)
105
93
  self.attachListeners(self.stream)
94
+ self.stream.on('error', reportStreamError)
95
+
106
96
  self.emit('sslconnect')
107
97
  })
108
98
  }
109
99
 
110
100
  Connection.prototype.attachListeners = function (stream) {
111
- var self = this
112
- stream.on('data', function (buff) {
113
- self._reader.addChunk(buff)
114
- var packet = self._reader.read()
115
- while (packet) {
116
- var msg = self.parseMessage(packet)
117
- var eventName = msg.name === 'error' ? 'errorMessage' : msg.name
118
- if (self._emitMessage) {
119
- self.emit('message', msg)
120
- }
121
- self.emit(eventName, msg)
122
- packet = self._reader.read()
123
- }
101
+ stream.on('end', () => {
102
+ this.emit('end')
124
103
  })
125
- stream.on('end', function () {
126
- self.emit('end')
104
+ parse(stream, (msg) => {
105
+ var eventName = msg.name === 'error' ? 'errorMessage' : msg.name
106
+ if (this._emitMessage) {
107
+ this.emit('message', msg)
108
+ }
109
+ this.emit(eventName, msg)
127
110
  })
128
111
  }
129
112
 
130
113
  Connection.prototype.requestSsl = function () {
131
- var bodyBuffer = this.writer.addInt16(0x04d2).addInt16(0x162f).flush()
132
-
133
- var length = bodyBuffer.length + 4
134
-
135
- var buffer = new Writer().addInt32(length).add(bodyBuffer).join()
136
- this.stream.write(buffer)
114
+ this.stream.write(serialize.requestSsl())
137
115
  }
138
116
 
139
117
  Connection.prototype.startup = function (config) {
140
- var writer = this.writer.addInt16(3).addInt16(0)
141
-
142
- Object.keys(config).forEach(function (key) {
143
- var val = config[key]
144
- writer.addCString(key).addCString(val)
145
- })
146
-
147
- writer.addCString('client_encoding').addCString("'utf-8'")
148
-
149
- var bodyBuffer = writer.addCString('').flush()
150
- // this message is sent without a code
151
-
152
- var length = bodyBuffer.length + 4
153
-
154
- var buffer = new Writer().addInt32(length).add(bodyBuffer).join()
155
- this.stream.write(buffer)
118
+ this.stream.write(serialize.startup(config))
156
119
  }
157
120
 
158
121
  Connection.prototype.cancel = function (processID, secretKey) {
159
- var bodyBuffer = this.writer.addInt16(1234).addInt16(5678).addInt32(processID).addInt32(secretKey).flush()
160
-
161
- var length = bodyBuffer.length + 4
162
-
163
- var buffer = new Writer().addInt32(length).add(bodyBuffer).join()
164
- this.stream.write(buffer)
122
+ this._send(serialize.cancel(processID, secretKey))
165
123
  }
166
124
 
167
125
  Connection.prototype.password = function (password) {
168
- // 0x70 = 'p'
169
- this._send(0x70, this.writer.addCString(password))
126
+ this._send(serialize.password(password))
170
127
  }
171
128
 
172
129
  Connection.prototype.sendSASLInitialResponseMessage = function (mechanism, initialResponse) {
173
- // 0x70 = 'p'
174
- this.writer.addCString(mechanism).addInt32(Buffer.byteLength(initialResponse)).addString(initialResponse)
175
-
176
- this._send(0x70)
130
+ this._send(serialize.sendSASLInitialResponseMessage(mechanism, initialResponse))
177
131
  }
178
132
 
179
133
  Connection.prototype.sendSCRAMClientFinalMessage = function (additionalData) {
180
- // 0x70 = 'p'
181
- this.writer.addString(additionalData)
182
-
183
- this._send(0x70)
134
+ this._send(serialize.sendSCRAMClientFinalMessage(additionalData))
184
135
  }
185
136
 
186
- Connection.prototype._send = function (code, more) {
137
+ Connection.prototype._send = function (buffer) {
187
138
  if (!this.stream.writable) {
188
139
  return false
189
140
  }
190
- if (more === true) {
191
- this.writer.addHeader(code)
192
- } else {
193
- return this.stream.write(this.writer.flush(code))
194
- }
141
+ return this.stream.write(buffer)
195
142
  }
196
143
 
197
144
  Connection.prototype.query = function (text) {
198
- // 0x51 = Q
199
- this.stream.write(this.writer.addCString(text).flush(0x51))
145
+ this._send(serialize.query(text))
200
146
  }
201
147
 
202
148
  // send parse message
203
- // "more" === true to buffer the message until flush() is called
204
- Connection.prototype.parse = function (query, more) {
205
- // expect something like this:
206
- // { name: 'queryName',
207
- // text: 'select * from blah',
208
- // types: ['int8', 'bool'] }
209
-
210
- // normalize missing query names to allow for null
211
- query.name = query.name || ''
212
- if (query.name.length > 63) {
213
- /* eslint-disable no-console */
214
- console.error('Warning! Postgres only supports 63 characters for query names.')
215
- console.error('You supplied %s (%s)', query.name, query.name.length)
216
- console.error('This can cause conflicts and silent errors executing queries')
217
- /* eslint-enable no-console */
218
- }
219
- // normalize null type array
220
- query.types = query.types || []
221
- var len = query.types.length
222
- var buffer = this.writer
223
- .addCString(query.name) // name of query
224
- .addCString(query.text) // actual query text
225
- .addInt16(len)
226
- for (var i = 0; i < len; i++) {
227
- buffer.addInt32(query.types[i])
228
- }
229
-
230
- var code = 0x50
231
- this._send(code, more)
149
+ Connection.prototype.parse = function (query) {
150
+ this._send(serialize.parse(query))
232
151
  }
233
152
 
234
153
  // send bind message
235
154
  // "more" === true to buffer the message until flush() is called
236
- Connection.prototype.bind = function (config, more) {
237
- // normalize config
238
- config = config || {}
239
- config.portal = config.portal || ''
240
- config.statement = config.statement || ''
241
- config.binary = config.binary || false
242
- var values = config.values || []
243
- var len = values.length
244
- var useBinary = false
245
- for (var j = 0; j < len; j++) {
246
- useBinary |= values[j] instanceof Buffer
247
- }
248
- var buffer = this.writer.addCString(config.portal).addCString(config.statement)
249
- if (!useBinary) {
250
- buffer.addInt16(0)
251
- } else {
252
- buffer.addInt16(len)
253
- for (j = 0; j < len; j++) {
254
- buffer.addInt16(values[j] instanceof Buffer)
255
- }
256
- }
257
- buffer.addInt16(len)
258
- for (var i = 0; i < len; i++) {
259
- var val = values[i]
260
- if (val === null || typeof val === 'undefined') {
261
- buffer.addInt32(-1)
262
- } else if (val instanceof Buffer) {
263
- buffer.addInt32(val.length)
264
- buffer.add(val)
265
- } else {
266
- buffer.addInt32(Buffer.byteLength(val))
267
- buffer.addString(val)
268
- }
269
- }
270
-
271
- if (config.binary) {
272
- buffer.addInt16(1) // format codes to use binary
273
- buffer.addInt16(1)
274
- } else {
275
- buffer.addInt16(0) // format codes to use text
276
- }
277
- // 0x42 = 'B'
278
- this._send(0x42, more)
155
+ Connection.prototype.bind = function (config) {
156
+ this._send(serialize.bind(config))
279
157
  }
280
158
 
281
159
  // send execute message
282
160
  // "more" === true to buffer the message until flush() is called
283
- Connection.prototype.execute = function (config, more) {
284
- config = config || {}
285
- config.portal = config.portal || ''
286
- config.rows = config.rows || ''
287
- this.writer.addCString(config.portal).addInt32(config.rows)
288
-
289
- // 0x45 = 'E'
290
- this._send(0x45, more)
161
+ Connection.prototype.execute = function (config) {
162
+ this._send(serialize.execute(config))
291
163
  }
292
164
 
293
- var emptyBuffer = Buffer.alloc(0)
294
-
165
+ const flushBuffer = serialize.flush()
295
166
  Connection.prototype.flush = function () {
296
- // 0x48 = 'H'
297
- this.writer.add(emptyBuffer)
298
- this._send(0x48)
167
+ if (this.stream.writable) {
168
+ this.stream.write(flushBuffer)
169
+ }
299
170
  }
300
171
 
172
+ const syncBuffer = serialize.sync()
301
173
  Connection.prototype.sync = function () {
302
- // clear out any pending data in the writer
303
- this.writer.flush(0)
304
-
305
- this.writer.add(emptyBuffer)
306
174
  this._ending = true
307
- this._send(0x53)
175
+ this._send(flushBuffer)
176
+ this._send(syncBuffer)
308
177
  }
309
178
 
310
- const END_BUFFER = Buffer.from([0x58, 0x00, 0x00, 0x00, 0x04])
179
+ const endBuffer = serialize.end()
311
180
 
312
181
  Connection.prototype.end = function () {
313
182
  // 0x58 = 'X'
314
- this.writer.add(emptyBuffer)
315
183
  this._ending = true
316
184
  if (!this._connecting || !this.stream.writable) {
317
185
  this.stream.end()
318
186
  return
319
187
  }
320
- return this.stream.write(END_BUFFER, () => {
188
+ return this.stream.write(endBuffer, () => {
321
189
  this.stream.end()
322
190
  })
323
191
  }
324
192
 
325
- Connection.prototype.close = function (msg, more) {
326
- this.writer.addCString(msg.type + (msg.name || ''))
327
- this._send(0x43, more)
193
+ Connection.prototype.close = function (msg) {
194
+ this._send(serialize.close(msg))
328
195
  }
329
196
 
330
- Connection.prototype.describe = function (msg, more) {
331
- this.writer.addCString(msg.type + (msg.name || ''))
332
- this._send(0x44, more)
197
+ Connection.prototype.describe = function (msg) {
198
+ this._send(serialize.describe(msg))
333
199
  }
334
200
 
335
201
  Connection.prototype.sendCopyFromChunk = function (chunk) {
336
- this.stream.write(this.writer.add(chunk).flush(0x64))
202
+ this._send(serialize.copyData(chunk))
337
203
  }
338
204
 
339
205
  Connection.prototype.endCopyFrom = function () {
340
- this.stream.write(this.writer.add(emptyBuffer).flush(0x63))
206
+ this._send(serialize.copyDone())
341
207
  }
342
208
 
343
209
  Connection.prototype.sendCopyFail = function (msg) {
344
- // this.stream.write(this.writer.add(emptyBuffer).flush(0x66));
345
- this.writer.addCString(msg)
346
- this._send(0x66)
210
+ this._send(serialize.copyFail(msg))
347
211
  }
348
212
 
349
- var Message = function (name, length) {
350
- this.name = name
351
- this.length = length
352
- }
353
-
354
- Connection.prototype.parseMessage = function (buffer) {
355
- this.offset = 0
356
- var length = buffer.length + 4
357
- switch (this._reader.header) {
358
- case 0x52: // R
359
- return this.parseR(buffer, length)
360
-
361
- case 0x53: // S
362
- return this.parseS(buffer, length)
363
-
364
- case 0x4b: // K
365
- return this.parseK(buffer, length)
366
-
367
- case 0x43: // C
368
- return this.parseC(buffer, length)
369
-
370
- case 0x5a: // Z
371
- return this.parseZ(buffer, length)
372
-
373
- case 0x54: // T
374
- return this.parseT(buffer, length)
375
-
376
- case 0x44: // D
377
- return this.parseD(buffer, length)
378
-
379
- case 0x45: // E
380
- return this.parseE(buffer, length)
381
-
382
- case 0x4e: // N
383
- return this.parseN(buffer, length)
384
-
385
- case 0x31: // 1
386
- return new Message('parseComplete', length)
387
-
388
- case 0x32: // 2
389
- return new Message('bindComplete', length)
390
-
391
- case 0x33: // 3
392
- return new Message('closeComplete', length)
393
-
394
- case 0x41: // A
395
- return this.parseA(buffer, length)
396
-
397
- case 0x6e: // n
398
- return new Message('noData', length)
399
-
400
- case 0x49: // I
401
- return new Message('emptyQuery', length)
402
-
403
- case 0x73: // s
404
- return new Message('portalSuspended', length)
405
-
406
- case 0x47: // G
407
- return this.parseG(buffer, length)
408
-
409
- case 0x48: // H
410
- return this.parseH(buffer, length)
411
-
412
- case 0x57: // W
413
- return new Message('replicationStart', length)
414
-
415
- case 0x63: // c
416
- return new Message('copyDone', length)
417
-
418
- case 0x64: // d
419
- return this.parsed(buffer, length)
420
- }
421
- }
422
-
423
- Connection.prototype.parseR = function (buffer, length) {
424
- var code = this.parseInt32(buffer)
425
-
426
- var msg = new Message('authenticationOk', length)
427
-
428
- switch (code) {
429
- case 0: // AuthenticationOk
430
- return msg
431
- case 3: // AuthenticationCleartextPassword
432
- if (msg.length === 8) {
433
- msg.name = 'authenticationCleartextPassword'
434
- return msg
435
- }
436
- break
437
- case 5: // AuthenticationMD5Password
438
- if (msg.length === 12) {
439
- msg.name = 'authenticationMD5Password'
440
- msg.salt = Buffer.alloc(4)
441
- buffer.copy(msg.salt, 0, this.offset, this.offset + 4)
442
- this.offset += 4
443
- return msg
444
- }
445
-
446
- break
447
- case 10: // AuthenticationSASL
448
- msg.name = 'authenticationSASL'
449
- msg.mechanisms = []
450
- do {
451
- var mechanism = this.parseCString(buffer)
452
-
453
- if (mechanism) {
454
- msg.mechanisms.push(mechanism)
455
- }
456
- } while (mechanism)
457
-
458
- return msg
459
- case 11: // AuthenticationSASLContinue
460
- msg.name = 'authenticationSASLContinue'
461
- msg.data = this.readString(buffer, length - 4)
462
-
463
- return msg
464
- case 12: // AuthenticationSASLFinal
465
- msg.name = 'authenticationSASLFinal'
466
- msg.data = this.readString(buffer, length - 4)
467
-
468
- return msg
469
- }
470
-
471
- throw new Error('Unknown authenticationOk message type' + util.inspect(msg))
472
- }
473
-
474
- Connection.prototype.parseS = function (buffer, length) {
475
- var msg = new Message('parameterStatus', length)
476
- msg.parameterName = this.parseCString(buffer)
477
- msg.parameterValue = this.parseCString(buffer)
478
- return msg
479
- }
480
-
481
- Connection.prototype.parseK = function (buffer, length) {
482
- var msg = new Message('backendKeyData', length)
483
- msg.processID = this.parseInt32(buffer)
484
- msg.secretKey = this.parseInt32(buffer)
485
- return msg
486
- }
487
-
488
- Connection.prototype.parseC = function (buffer, length) {
489
- var msg = new Message('commandComplete', length)
490
- msg.text = this.parseCString(buffer)
491
- return msg
492
- }
493
-
494
- Connection.prototype.parseZ = function (buffer, length) {
495
- var msg = new Message('readyForQuery', length)
496
- msg.name = 'readyForQuery'
497
- msg.status = this.readString(buffer, 1)
498
- return msg
499
- }
500
-
501
- var ROW_DESCRIPTION = 'rowDescription'
502
- Connection.prototype.parseT = function (buffer, length) {
503
- var msg = new Message(ROW_DESCRIPTION, length)
504
- msg.fieldCount = this.parseInt16(buffer)
505
- var fields = []
506
- for (var i = 0; i < msg.fieldCount; i++) {
507
- fields.push(this.parseField(buffer))
508
- }
509
- msg.fields = fields
510
- return msg
511
- }
512
-
513
- var Field = function () {
514
- this.name = null
515
- this.tableID = null
516
- this.columnID = null
517
- this.dataTypeID = null
518
- this.dataTypeSize = null
519
- this.dataTypeModifier = null
520
- this.format = null
521
- }
522
-
523
- var FORMAT_TEXT = 'text'
524
- var FORMAT_BINARY = 'binary'
525
- Connection.prototype.parseField = function (buffer) {
526
- var field = new Field()
527
- field.name = this.parseCString(buffer)
528
- field.tableID = this.parseInt32(buffer)
529
- field.columnID = this.parseInt16(buffer)
530
- field.dataTypeID = this.parseInt32(buffer)
531
- field.dataTypeSize = this.parseInt16(buffer)
532
- field.dataTypeModifier = this.parseInt32(buffer)
533
- if (this.parseInt16(buffer) === TEXT_MODE) {
534
- this._mode = TEXT_MODE
535
- field.format = FORMAT_TEXT
536
- } else {
537
- this._mode = BINARY_MODE
538
- field.format = FORMAT_BINARY
539
- }
540
- return field
541
- }
542
-
543
- var DATA_ROW = 'dataRow'
544
- var DataRowMessage = function (length, fieldCount) {
545
- this.name = DATA_ROW
546
- this.length = length
547
- this.fieldCount = fieldCount
548
- this.fields = []
549
- }
550
-
551
- // extremely hot-path code
552
- Connection.prototype.parseD = function (buffer, length) {
553
- var fieldCount = this.parseInt16(buffer)
554
- var msg = new DataRowMessage(length, fieldCount)
555
- for (var i = 0; i < fieldCount; i++) {
556
- msg.fields.push(this._readValue(buffer))
557
- }
558
- return msg
559
- }
560
-
561
- // extremely hot-path code
562
- Connection.prototype._readValue = function (buffer) {
563
- var length = this.parseInt32(buffer)
564
- if (length === -1) return null
565
- if (this._mode === TEXT_MODE) {
566
- return this.readString(buffer, length)
567
- }
568
- return this.readBytes(buffer, length)
569
- }
570
-
571
- // parses error
572
- Connection.prototype.parseE = function (buffer, length, isNotice) {
573
- var fields = {}
574
- var fieldType = this.readString(buffer, 1)
575
- while (fieldType !== '\0') {
576
- fields[fieldType] = this.parseCString(buffer)
577
- fieldType = this.readString(buffer, 1)
578
- }
579
-
580
- // the msg is an Error instance
581
- var msg = isNotice ? { message: fields.M } : new Error(fields.M)
582
-
583
- // for compatibility with Message
584
- msg.name = isNotice ? 'notice' : 'error'
585
- msg.length = length
586
-
587
- msg.severity = fields.S
588
- msg.code = fields.C
589
- msg.detail = fields.D
590
- msg.hint = fields.H
591
- msg.position = fields.P
592
- msg.internalPosition = fields.p
593
- msg.internalQuery = fields.q
594
- msg.where = fields.W
595
- msg.schema = fields.s
596
- msg.table = fields.t
597
- msg.column = fields.c
598
- msg.dataType = fields.d
599
- msg.constraint = fields.n
600
- msg.file = fields.F
601
- msg.line = fields.L
602
- msg.routine = fields.R
603
- return msg
604
- }
605
-
606
- // same thing, different name
607
- Connection.prototype.parseN = function (buffer, length) {
608
- var msg = this.parseE(buffer, length, true)
609
- msg.name = 'notice'
610
- return msg
611
- }
612
-
613
- Connection.prototype.parseA = function (buffer, length) {
614
- var msg = new Message('notification', length)
615
- msg.processId = this.parseInt32(buffer)
616
- msg.channel = this.parseCString(buffer)
617
- msg.payload = this.parseCString(buffer)
618
- return msg
619
- }
620
-
621
- Connection.prototype.parseG = function (buffer, length) {
622
- var msg = new Message('copyInResponse', length)
623
- return this.parseGH(buffer, msg)
624
- }
625
-
626
- Connection.prototype.parseH = function (buffer, length) {
627
- var msg = new Message('copyOutResponse', length)
628
- return this.parseGH(buffer, msg)
629
- }
630
-
631
- Connection.prototype.parseGH = function (buffer, msg) {
632
- var isBinary = buffer[this.offset] !== 0
633
- this.offset++
634
- msg.binary = isBinary
635
- var columnCount = this.parseInt16(buffer)
636
- msg.columnTypes = []
637
- for (var i = 0; i < columnCount; i++) {
638
- msg.columnTypes.push(this.parseInt16(buffer))
639
- }
640
- return msg
641
- }
642
-
643
- Connection.prototype.parsed = function (buffer, length) {
644
- var msg = new Message('copyData', length)
645
- msg.chunk = this.readBytes(buffer, msg.length - 4)
646
- return msg
647
- }
648
-
649
- Connection.prototype.parseInt32 = function (buffer) {
650
- var value = buffer.readInt32BE(this.offset)
651
- this.offset += 4
652
- return value
653
- }
654
-
655
- Connection.prototype.parseInt16 = function (buffer) {
656
- var value = buffer.readInt16BE(this.offset)
657
- this.offset += 2
658
- return value
659
- }
660
-
661
- Connection.prototype.readString = function (buffer, length) {
662
- return buffer.toString(this.encoding, this.offset, (this.offset += length))
663
- }
664
-
665
- Connection.prototype.readBytes = function (buffer, length) {
666
- return buffer.slice(this.offset, (this.offset += length))
667
- }
668
-
669
- Connection.prototype.parseCString = function (buffer) {
670
- var start = this.offset
671
- var end = buffer.indexOf(0, start)
672
- this.offset = end + 1
673
- return buffer.toString(this.encoding, start, end)
674
- }
675
- // end parsing methods
676
213
  module.exports = Connection
package/lib/defaults.js CHANGED
@@ -53,6 +53,8 @@ module.exports = {
53
53
 
54
54
  fallback_application_name: undefined,
55
55
 
56
+ options: undefined,
57
+
56
58
  parseInputDatesAsUTC: false,
57
59
 
58
60
  // max milliseconds any query using this connection will execute for before timing out in error.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pg",
3
- "version": "8.1.0",
3
+ "version": "8.3.0",
4
4
  "description": "PostgreSQL client - pure javascript & libpq with the same API",
5
5
  "keywords": [
6
6
  "database",
@@ -21,9 +21,9 @@
21
21
  "dependencies": {
22
22
  "buffer-writer": "2.0.0",
23
23
  "packet-reader": "1.0.0",
24
- "pg-connection-string": "^2.2.2",
25
- "pg-pool": "^3.2.0",
26
- "pg-protocol": "^1.2.2",
24
+ "pg-connection-string": "^2.3.0",
25
+ "pg-pool": "^3.2.1",
26
+ "pg-protocol": "^1.2.5",
27
27
  "pg-types": "^2.1.0",
28
28
  "pgpass": "1.x",
29
29
  "semver": "4.3.2"
@@ -45,6 +45,5 @@
45
45
  "license": "MIT",
46
46
  "engines": {
47
47
  "node": ">= 8.0.0"
48
- },
49
- "gitHead": "3f5bc58a86cda3b4812addc1e42a06d61d31e614"
48
+ }
50
49
  }
package/LICENSE DELETED
@@ -1,21 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2010 - 2020 Brian Carlson
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
@@ -1,214 +0,0 @@
1
- 'use strict'
2
- /**
3
- * Copyright (c) 2010-2017 Brian Carlson (brian.m.carlson@gmail.com)
4
- * All rights reserved.
5
- *
6
- * This source code is licensed under the MIT license found in the
7
- * README.md file in the root directory of this source tree.
8
- */
9
-
10
- var net = require('net')
11
- var EventEmitter = require('events').EventEmitter
12
- var util = require('util')
13
-
14
- const { parse, serialize } = require('pg-protocol')
15
-
16
- // TODO(bmc) support binary mode at some point
17
- console.log('***using faster connection***')
18
- var Connection = function (config) {
19
- EventEmitter.call(this)
20
- config = config || {}
21
- this.stream = config.stream || new net.Socket()
22
- this.stream.setNoDelay(true)
23
- this._keepAlive = config.keepAlive
24
- this._keepAliveInitialDelayMillis = config.keepAliveInitialDelayMillis
25
- this.lastBuffer = false
26
- this.parsedStatements = {}
27
- this.ssl = config.ssl || false
28
- this._ending = false
29
- this._emitMessage = false
30
- var self = this
31
- this.on('newListener', function (eventName) {
32
- if (eventName === 'message') {
33
- self._emitMessage = true
34
- }
35
- })
36
- }
37
-
38
- util.inherits(Connection, EventEmitter)
39
-
40
- Connection.prototype.connect = function (port, host) {
41
- var self = this
42
-
43
- this._connecting = true
44
- this.stream.connect(port, host)
45
-
46
- this.stream.once('connect', function () {
47
- if (self._keepAlive) {
48
- self.stream.setKeepAlive(true, self._keepAliveInitialDelayMillis)
49
- }
50
- self.emit('connect')
51
- })
52
-
53
- const reportStreamError = function (error) {
54
- // errors about disconnections should be ignored during disconnect
55
- if (self._ending && (error.code === 'ECONNRESET' || error.code === 'EPIPE')) {
56
- return
57
- }
58
- self.emit('error', error)
59
- }
60
- this.stream.on('error', reportStreamError)
61
-
62
- this.stream.on('close', function () {
63
- self.emit('end')
64
- })
65
-
66
- if (!this.ssl) {
67
- return this.attachListeners(this.stream)
68
- }
69
-
70
- this.stream.once('data', function (buffer) {
71
- var responseCode = buffer.toString('utf8')
72
- switch (responseCode) {
73
- case 'S': // Server supports SSL connections, continue with a secure connection
74
- break
75
- case 'N': // Server does not support SSL connections
76
- self.stream.end()
77
- return self.emit('error', new Error('The server does not support SSL connections'))
78
- default:
79
- // Any other response byte, including 'E' (ErrorResponse) indicating a server error
80
- self.stream.end()
81
- return self.emit('error', new Error('There was an error establishing an SSL connection'))
82
- }
83
- var tls = require('tls')
84
- const options = Object.assign(
85
- {
86
- socket: self.stream,
87
- },
88
- self.ssl
89
- )
90
- if (net.isIP(host) === 0) {
91
- options.servername = host
92
- }
93
- self.stream = tls.connect(options)
94
- self.attachListeners(self.stream)
95
- self.stream.on('error', reportStreamError)
96
-
97
- self.emit('sslconnect')
98
- })
99
- }
100
-
101
- Connection.prototype.attachListeners = function (stream) {
102
- stream.on('end', () => {
103
- this.emit('end')
104
- })
105
- parse(stream, (msg) => {
106
- var eventName = msg.name === 'error' ? 'errorMessage' : msg.name
107
- if (this._emitMessage) {
108
- this.emit('message', msg)
109
- }
110
- this.emit(eventName, msg)
111
- })
112
- }
113
-
114
- Connection.prototype.requestSsl = function () {
115
- this.stream.write(serialize.requestSsl())
116
- }
117
-
118
- Connection.prototype.startup = function (config) {
119
- this.stream.write(serialize.startup(config))
120
- }
121
-
122
- Connection.prototype.cancel = function (processID, secretKey) {
123
- this._send(serialize.cancel(processID, secretKey))
124
- }
125
-
126
- Connection.prototype.password = function (password) {
127
- this._send(serialize.password(password))
128
- }
129
-
130
- Connection.prototype.sendSASLInitialResponseMessage = function (mechanism, initialResponse) {
131
- this._send(serialize.sendSASLInitialResponseMessage(mechanism, initialResponse))
132
- }
133
-
134
- Connection.prototype.sendSCRAMClientFinalMessage = function (additionalData) {
135
- this._send(serialize.sendSCRAMClientFinalMessage(additionalData))
136
- }
137
-
138
- Connection.prototype._send = function (buffer) {
139
- if (!this.stream.writable) {
140
- return false
141
- }
142
- return this.stream.write(buffer)
143
- }
144
-
145
- Connection.prototype.query = function (text) {
146
- this._send(serialize.query(text))
147
- }
148
-
149
- // send parse message
150
- Connection.prototype.parse = function (query) {
151
- this._send(serialize.parse(query))
152
- }
153
-
154
- // send bind message
155
- // "more" === true to buffer the message until flush() is called
156
- Connection.prototype.bind = function (config) {
157
- this._send(serialize.bind(config))
158
- }
159
-
160
- // send execute message
161
- // "more" === true to buffer the message until flush() is called
162
- Connection.prototype.execute = function (config) {
163
- this._send(serialize.execute(config))
164
- }
165
-
166
- const flushBuffer = serialize.flush()
167
- Connection.prototype.flush = function () {
168
- if (this.stream.writable) {
169
- this.stream.write(flushBuffer)
170
- }
171
- }
172
-
173
- const syncBuffer = serialize.sync()
174
- Connection.prototype.sync = function () {
175
- this._ending = true
176
- this._send(syncBuffer)
177
- this._send(flushBuffer)
178
- }
179
-
180
- const endBuffer = serialize.end()
181
-
182
- Connection.prototype.end = function () {
183
- // 0x58 = 'X'
184
- this._ending = true
185
- if (!this._connecting || !this.stream.writable) {
186
- this.stream.end()
187
- return
188
- }
189
- return this.stream.write(endBuffer, () => {
190
- this.stream.end()
191
- })
192
- }
193
-
194
- Connection.prototype.close = function (msg) {
195
- this._send(serialize.close(msg))
196
- }
197
-
198
- Connection.prototype.describe = function (msg) {
199
- this._send(serialize.describe(msg))
200
- }
201
-
202
- Connection.prototype.sendCopyFromChunk = function (chunk) {
203
- this._send(serialize.copyData(chunk))
204
- }
205
-
206
- Connection.prototype.endCopyFrom = function () {
207
- this._send(serialize.copyDone())
208
- }
209
-
210
- Connection.prototype.sendCopyFail = function (msg) {
211
- this._send(serialize.copyFail(msg))
212
- }
213
-
214
- module.exports = Connection