pg 8.0.2 → 8.2.1
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 +34 -39
- package/lib/client.js +42 -34
- package/lib/connection-parameters.js +14 -7
- package/lib/connection.js +56 -538
- package/lib/defaults.js +1 -1
- package/lib/index.js +3 -3
- package/lib/native/client.js +8 -8
- package/lib/native/query.js +27 -22
- package/lib/query.js +44 -24
- package/lib/sasl.js +34 -30
- package/lib/type-overrides.js +7 -4
- package/lib/utils.js +43 -27
- package/package.json +6 -13
- package/lib/connection-fast.js +0 -215
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
|
-
|
|
15
|
-
var Reader = require('packet-reader')
|
|
14
|
+
const { parse, serialize } = require('pg-protocol')
|
|
16
15
|
|
|
17
|
-
|
|
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') {
|
|
@@ -50,13 +38,11 @@ util.inherits(Connection, EventEmitter)
|
|
|
50
38
|
Connection.prototype.connect = function (port, host) {
|
|
51
39
|
var self = this
|
|
52
40
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
this.emit('connect')
|
|
57
|
-
}
|
|
41
|
+
this._connecting = true
|
|
42
|
+
this.stream.setNoDelay(true)
|
|
43
|
+
this.stream.connect(port, host)
|
|
58
44
|
|
|
59
|
-
this.stream.
|
|
45
|
+
this.stream.once('connect', function () {
|
|
60
46
|
if (self._keepAlive) {
|
|
61
47
|
self.stream.setKeepAlive(true, self._keepAliveInitialDelayMillis)
|
|
62
48
|
}
|
|
@@ -88,608 +74,140 @@ Connection.prototype.connect = function (port, host) {
|
|
|
88
74
|
case 'N': // Server does not support SSL connections
|
|
89
75
|
self.stream.end()
|
|
90
76
|
return self.emit('error', new Error('The server does not support SSL connections'))
|
|
91
|
-
default:
|
|
77
|
+
default:
|
|
78
|
+
// Any other response byte, including 'E' (ErrorResponse) indicating a server error
|
|
92
79
|
self.stream.end()
|
|
93
80
|
return self.emit('error', new Error('There was an error establishing an SSL connection'))
|
|
94
81
|
}
|
|
95
82
|
var tls = require('tls')
|
|
96
|
-
const options = Object.assign(
|
|
97
|
-
|
|
98
|
-
|
|
83
|
+
const options = Object.assign(
|
|
84
|
+
{
|
|
85
|
+
socket: self.stream,
|
|
86
|
+
},
|
|
87
|
+
self.ssl
|
|
88
|
+
)
|
|
99
89
|
if (net.isIP(host) === 0) {
|
|
100
90
|
options.servername = host
|
|
101
91
|
}
|
|
102
92
|
self.stream = tls.connect(options)
|
|
103
|
-
self.stream.on('error', reportStreamError)
|
|
104
93
|
self.attachListeners(self.stream)
|
|
94
|
+
self.stream.on('error', reportStreamError)
|
|
95
|
+
|
|
105
96
|
self.emit('sslconnect')
|
|
106
97
|
})
|
|
107
98
|
}
|
|
108
99
|
|
|
109
100
|
Connection.prototype.attachListeners = function (stream) {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
self._reader.addChunk(buff)
|
|
113
|
-
var packet = self._reader.read()
|
|
114
|
-
while (packet) {
|
|
115
|
-
var msg = self.parseMessage(packet)
|
|
116
|
-
var eventName = msg.name === 'error' ? 'errorMessage' : msg.name
|
|
117
|
-
if (self._emitMessage) {
|
|
118
|
-
self.emit('message', msg)
|
|
119
|
-
}
|
|
120
|
-
self.emit(eventName, msg)
|
|
121
|
-
packet = self._reader.read()
|
|
122
|
-
}
|
|
101
|
+
stream.on('end', () => {
|
|
102
|
+
this.emit('end')
|
|
123
103
|
})
|
|
124
|
-
stream
|
|
125
|
-
|
|
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)
|
|
126
110
|
})
|
|
127
111
|
}
|
|
128
112
|
|
|
129
113
|
Connection.prototype.requestSsl = function () {
|
|
130
|
-
|
|
131
|
-
.addInt16(0x04D2)
|
|
132
|
-
.addInt16(0x162F).flush()
|
|
133
|
-
|
|
134
|
-
var length = bodyBuffer.length + 4
|
|
135
|
-
|
|
136
|
-
var buffer = new Writer()
|
|
137
|
-
.addInt32(length)
|
|
138
|
-
.add(bodyBuffer)
|
|
139
|
-
.join()
|
|
140
|
-
this.stream.write(buffer)
|
|
114
|
+
this.stream.write(serialize.requestSsl())
|
|
141
115
|
}
|
|
142
116
|
|
|
143
117
|
Connection.prototype.startup = function (config) {
|
|
144
|
-
|
|
145
|
-
.addInt16(3)
|
|
146
|
-
.addInt16(0)
|
|
147
|
-
|
|
148
|
-
Object.keys(config).forEach(function (key) {
|
|
149
|
-
var val = config[key]
|
|
150
|
-
writer.addCString(key).addCString(val)
|
|
151
|
-
})
|
|
152
|
-
|
|
153
|
-
writer.addCString('client_encoding').addCString("'utf-8'")
|
|
154
|
-
|
|
155
|
-
var bodyBuffer = writer.addCString('').flush()
|
|
156
|
-
// this message is sent without a code
|
|
157
|
-
|
|
158
|
-
var length = bodyBuffer.length + 4
|
|
159
|
-
|
|
160
|
-
var buffer = new Writer()
|
|
161
|
-
.addInt32(length)
|
|
162
|
-
.add(bodyBuffer)
|
|
163
|
-
.join()
|
|
164
|
-
this.stream.write(buffer)
|
|
118
|
+
this.stream.write(serialize.startup(config))
|
|
165
119
|
}
|
|
166
120
|
|
|
167
121
|
Connection.prototype.cancel = function (processID, secretKey) {
|
|
168
|
-
|
|
169
|
-
.addInt16(1234)
|
|
170
|
-
.addInt16(5678)
|
|
171
|
-
.addInt32(processID)
|
|
172
|
-
.addInt32(secretKey)
|
|
173
|
-
.flush()
|
|
174
|
-
|
|
175
|
-
var length = bodyBuffer.length + 4
|
|
176
|
-
|
|
177
|
-
var buffer = new Writer()
|
|
178
|
-
.addInt32(length)
|
|
179
|
-
.add(bodyBuffer)
|
|
180
|
-
.join()
|
|
181
|
-
this.stream.write(buffer)
|
|
122
|
+
this._send(serialize.cancel(processID, secretKey))
|
|
182
123
|
}
|
|
183
124
|
|
|
184
125
|
Connection.prototype.password = function (password) {
|
|
185
|
-
|
|
186
|
-
this._send(0x70, this.writer.addCString(password))
|
|
126
|
+
this._send(serialize.password(password))
|
|
187
127
|
}
|
|
188
128
|
|
|
189
129
|
Connection.prototype.sendSASLInitialResponseMessage = function (mechanism, initialResponse) {
|
|
190
|
-
|
|
191
|
-
this.writer
|
|
192
|
-
.addCString(mechanism)
|
|
193
|
-
.addInt32(Buffer.byteLength(initialResponse))
|
|
194
|
-
.addString(initialResponse)
|
|
195
|
-
|
|
196
|
-
this._send(0x70)
|
|
130
|
+
this._send(serialize.sendSASLInitialResponseMessage(mechanism, initialResponse))
|
|
197
131
|
}
|
|
198
132
|
|
|
199
133
|
Connection.prototype.sendSCRAMClientFinalMessage = function (additionalData) {
|
|
200
|
-
|
|
201
|
-
this.writer
|
|
202
|
-
.addString(additionalData)
|
|
203
|
-
|
|
204
|
-
this._send(0x70)
|
|
134
|
+
this._send(serialize.sendSCRAMClientFinalMessage(additionalData))
|
|
205
135
|
}
|
|
206
136
|
|
|
207
|
-
Connection.prototype._send = function (
|
|
137
|
+
Connection.prototype._send = function (buffer) {
|
|
208
138
|
if (!this.stream.writable) {
|
|
209
139
|
return false
|
|
210
140
|
}
|
|
211
|
-
|
|
212
|
-
this.writer.addHeader(code)
|
|
213
|
-
} else {
|
|
214
|
-
return this.stream.write(this.writer.flush(code))
|
|
215
|
-
}
|
|
141
|
+
return this.stream.write(buffer)
|
|
216
142
|
}
|
|
217
143
|
|
|
218
144
|
Connection.prototype.query = function (text) {
|
|
219
|
-
|
|
220
|
-
this.stream.write(this.writer.addCString(text).flush(0x51))
|
|
145
|
+
this._send(serialize.query(text))
|
|
221
146
|
}
|
|
222
147
|
|
|
223
148
|
// send parse message
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
// expect something like this:
|
|
227
|
-
// { name: 'queryName',
|
|
228
|
-
// text: 'select * from blah',
|
|
229
|
-
// types: ['int8', 'bool'] }
|
|
230
|
-
|
|
231
|
-
// normalize missing query names to allow for null
|
|
232
|
-
query.name = query.name || ''
|
|
233
|
-
if (query.name.length > 63) {
|
|
234
|
-
/* eslint-disable no-console */
|
|
235
|
-
console.error('Warning! Postgres only supports 63 characters for query names.')
|
|
236
|
-
console.error('You supplied %s (%s)', query.name, query.name.length)
|
|
237
|
-
console.error('This can cause conflicts and silent errors executing queries')
|
|
238
|
-
/* eslint-enable no-console */
|
|
239
|
-
}
|
|
240
|
-
// normalize null type array
|
|
241
|
-
query.types = query.types || []
|
|
242
|
-
var len = query.types.length
|
|
243
|
-
var buffer = this.writer
|
|
244
|
-
.addCString(query.name) // name of query
|
|
245
|
-
.addCString(query.text) // actual query text
|
|
246
|
-
.addInt16(len)
|
|
247
|
-
for (var i = 0; i < len; i++) {
|
|
248
|
-
buffer.addInt32(query.types[i])
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
var code = 0x50
|
|
252
|
-
this._send(code, more)
|
|
149
|
+
Connection.prototype.parse = function (query) {
|
|
150
|
+
this._send(serialize.parse(query))
|
|
253
151
|
}
|
|
254
152
|
|
|
255
153
|
// send bind message
|
|
256
154
|
// "more" === true to buffer the message until flush() is called
|
|
257
|
-
Connection.prototype.bind = function (config
|
|
258
|
-
|
|
259
|
-
config = config || {}
|
|
260
|
-
config.portal = config.portal || ''
|
|
261
|
-
config.statement = config.statement || ''
|
|
262
|
-
config.binary = config.binary || false
|
|
263
|
-
var values = config.values || []
|
|
264
|
-
var len = values.length
|
|
265
|
-
var useBinary = false
|
|
266
|
-
for (var j = 0; j < len; j++) { useBinary |= values[j] instanceof Buffer }
|
|
267
|
-
var buffer = this.writer
|
|
268
|
-
.addCString(config.portal)
|
|
269
|
-
.addCString(config.statement)
|
|
270
|
-
if (!useBinary) { buffer.addInt16(0) } else {
|
|
271
|
-
buffer.addInt16(len)
|
|
272
|
-
for (j = 0; j < len; j++) { buffer.addInt16(values[j] instanceof Buffer) }
|
|
273
|
-
}
|
|
274
|
-
buffer.addInt16(len)
|
|
275
|
-
for (var i = 0; i < len; i++) {
|
|
276
|
-
var val = values[i]
|
|
277
|
-
if (val === null || typeof val === 'undefined') {
|
|
278
|
-
buffer.addInt32(-1)
|
|
279
|
-
} else if (val instanceof Buffer) {
|
|
280
|
-
buffer.addInt32(val.length)
|
|
281
|
-
buffer.add(val)
|
|
282
|
-
} else {
|
|
283
|
-
buffer.addInt32(Buffer.byteLength(val))
|
|
284
|
-
buffer.addString(val)
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
if (config.binary) {
|
|
289
|
-
buffer.addInt16(1) // format codes to use binary
|
|
290
|
-
buffer.addInt16(1)
|
|
291
|
-
} else {
|
|
292
|
-
buffer.addInt16(0) // format codes to use text
|
|
293
|
-
}
|
|
294
|
-
// 0x42 = 'B'
|
|
295
|
-
this._send(0x42, more)
|
|
155
|
+
Connection.prototype.bind = function (config) {
|
|
156
|
+
this._send(serialize.bind(config))
|
|
296
157
|
}
|
|
297
158
|
|
|
298
159
|
// send execute message
|
|
299
160
|
// "more" === true to buffer the message until flush() is called
|
|
300
|
-
Connection.prototype.execute = function (config
|
|
301
|
-
config
|
|
302
|
-
config.portal = config.portal || ''
|
|
303
|
-
config.rows = config.rows || ''
|
|
304
|
-
this.writer
|
|
305
|
-
.addCString(config.portal)
|
|
306
|
-
.addInt32(config.rows)
|
|
307
|
-
|
|
308
|
-
// 0x45 = 'E'
|
|
309
|
-
this._send(0x45, more)
|
|
161
|
+
Connection.prototype.execute = function (config) {
|
|
162
|
+
this._send(serialize.execute(config))
|
|
310
163
|
}
|
|
311
164
|
|
|
312
|
-
|
|
313
|
-
|
|
165
|
+
const flushBuffer = serialize.flush()
|
|
314
166
|
Connection.prototype.flush = function () {
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
167
|
+
if (this.stream.writable) {
|
|
168
|
+
this.stream.write(flushBuffer)
|
|
169
|
+
}
|
|
318
170
|
}
|
|
319
171
|
|
|
172
|
+
const syncBuffer = serialize.sync()
|
|
320
173
|
Connection.prototype.sync = function () {
|
|
321
|
-
// clear out any pending data in the writer
|
|
322
|
-
this.writer.flush(0)
|
|
323
|
-
|
|
324
|
-
this.writer.add(emptyBuffer)
|
|
325
174
|
this._ending = true
|
|
326
|
-
this._send(
|
|
175
|
+
this._send(flushBuffer)
|
|
176
|
+
this._send(syncBuffer)
|
|
327
177
|
}
|
|
328
178
|
|
|
329
|
-
const
|
|
179
|
+
const endBuffer = serialize.end()
|
|
330
180
|
|
|
331
181
|
Connection.prototype.end = function () {
|
|
332
182
|
// 0x58 = 'X'
|
|
333
|
-
this.writer.add(emptyBuffer)
|
|
334
183
|
this._ending = true
|
|
335
|
-
if (!this.stream.writable) {
|
|
184
|
+
if (!this._connecting || !this.stream.writable) {
|
|
336
185
|
this.stream.end()
|
|
337
186
|
return
|
|
338
187
|
}
|
|
339
|
-
return this.stream.write(
|
|
188
|
+
return this.stream.write(endBuffer, () => {
|
|
340
189
|
this.stream.end()
|
|
341
190
|
})
|
|
342
191
|
}
|
|
343
192
|
|
|
344
|
-
Connection.prototype.close = function (msg
|
|
345
|
-
this.
|
|
346
|
-
this._send(0x43, more)
|
|
193
|
+
Connection.prototype.close = function (msg) {
|
|
194
|
+
this._send(serialize.close(msg))
|
|
347
195
|
}
|
|
348
196
|
|
|
349
|
-
Connection.prototype.describe = function (msg
|
|
350
|
-
this.
|
|
351
|
-
this._send(0x44, more)
|
|
197
|
+
Connection.prototype.describe = function (msg) {
|
|
198
|
+
this._send(serialize.describe(msg))
|
|
352
199
|
}
|
|
353
200
|
|
|
354
201
|
Connection.prototype.sendCopyFromChunk = function (chunk) {
|
|
355
|
-
this.
|
|
202
|
+
this._send(serialize.copyData(chunk))
|
|
356
203
|
}
|
|
357
204
|
|
|
358
205
|
Connection.prototype.endCopyFrom = function () {
|
|
359
|
-
this.
|
|
206
|
+
this._send(serialize.copyDone())
|
|
360
207
|
}
|
|
361
208
|
|
|
362
209
|
Connection.prototype.sendCopyFail = function (msg) {
|
|
363
|
-
|
|
364
|
-
this.writer.addCString(msg)
|
|
365
|
-
this._send(0x66)
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
var Message = function (name, length) {
|
|
369
|
-
this.name = name
|
|
370
|
-
this.length = length
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
Connection.prototype.parseMessage = function (buffer) {
|
|
374
|
-
this.offset = 0
|
|
375
|
-
var length = buffer.length + 4
|
|
376
|
-
switch (this._reader.header) {
|
|
377
|
-
case 0x52: // R
|
|
378
|
-
return this.parseR(buffer, length)
|
|
379
|
-
|
|
380
|
-
case 0x53: // S
|
|
381
|
-
return this.parseS(buffer, length)
|
|
382
|
-
|
|
383
|
-
case 0x4b: // K
|
|
384
|
-
return this.parseK(buffer, length)
|
|
385
|
-
|
|
386
|
-
case 0x43: // C
|
|
387
|
-
return this.parseC(buffer, length)
|
|
388
|
-
|
|
389
|
-
case 0x5a: // Z
|
|
390
|
-
return this.parseZ(buffer, length)
|
|
391
|
-
|
|
392
|
-
case 0x54: // T
|
|
393
|
-
return this.parseT(buffer, length)
|
|
394
|
-
|
|
395
|
-
case 0x44: // D
|
|
396
|
-
return this.parseD(buffer, length)
|
|
397
|
-
|
|
398
|
-
case 0x45: // E
|
|
399
|
-
return this.parseE(buffer, length)
|
|
400
|
-
|
|
401
|
-
case 0x4e: // N
|
|
402
|
-
return this.parseN(buffer, length)
|
|
403
|
-
|
|
404
|
-
case 0x31: // 1
|
|
405
|
-
return new Message('parseComplete', length)
|
|
406
|
-
|
|
407
|
-
case 0x32: // 2
|
|
408
|
-
return new Message('bindComplete', length)
|
|
409
|
-
|
|
410
|
-
case 0x33: // 3
|
|
411
|
-
return new Message('closeComplete', length)
|
|
412
|
-
|
|
413
|
-
case 0x41: // A
|
|
414
|
-
return this.parseA(buffer, length)
|
|
415
|
-
|
|
416
|
-
case 0x6e: // n
|
|
417
|
-
return new Message('noData', length)
|
|
418
|
-
|
|
419
|
-
case 0x49: // I
|
|
420
|
-
return new Message('emptyQuery', length)
|
|
421
|
-
|
|
422
|
-
case 0x73: // s
|
|
423
|
-
return new Message('portalSuspended', length)
|
|
424
|
-
|
|
425
|
-
case 0x47: // G
|
|
426
|
-
return this.parseG(buffer, length)
|
|
427
|
-
|
|
428
|
-
case 0x48: // H
|
|
429
|
-
return this.parseH(buffer, length)
|
|
430
|
-
|
|
431
|
-
case 0x57: // W
|
|
432
|
-
return new Message('replicationStart', length)
|
|
433
|
-
|
|
434
|
-
case 0x63: // c
|
|
435
|
-
return new Message('copyDone', length)
|
|
436
|
-
|
|
437
|
-
case 0x64: // d
|
|
438
|
-
return this.parsed(buffer, length)
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
Connection.prototype.parseR = function (buffer, length) {
|
|
443
|
-
var code = this.parseInt32(buffer)
|
|
444
|
-
|
|
445
|
-
var msg = new Message('authenticationOk', length)
|
|
446
|
-
|
|
447
|
-
switch (code) {
|
|
448
|
-
case 0: // AuthenticationOk
|
|
449
|
-
return msg
|
|
450
|
-
case 3: // AuthenticationCleartextPassword
|
|
451
|
-
if (msg.length === 8) {
|
|
452
|
-
msg.name = 'authenticationCleartextPassword'
|
|
453
|
-
return msg
|
|
454
|
-
}
|
|
455
|
-
break
|
|
456
|
-
case 5: // AuthenticationMD5Password
|
|
457
|
-
if (msg.length === 12) {
|
|
458
|
-
msg.name = 'authenticationMD5Password'
|
|
459
|
-
msg.salt = Buffer.alloc(4)
|
|
460
|
-
buffer.copy(msg.salt, 0, this.offset, this.offset + 4)
|
|
461
|
-
this.offset += 4
|
|
462
|
-
return msg
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
break
|
|
466
|
-
case 10: // AuthenticationSASL
|
|
467
|
-
msg.name = 'authenticationSASL'
|
|
468
|
-
msg.mechanisms = []
|
|
469
|
-
do {
|
|
470
|
-
var mechanism = this.parseCString(buffer)
|
|
471
|
-
|
|
472
|
-
if (mechanism) {
|
|
473
|
-
msg.mechanisms.push(mechanism)
|
|
474
|
-
}
|
|
475
|
-
} while (mechanism)
|
|
476
|
-
|
|
477
|
-
return msg
|
|
478
|
-
case 11: // AuthenticationSASLContinue
|
|
479
|
-
msg.name = 'authenticationSASLContinue'
|
|
480
|
-
msg.data = this.readString(buffer, length - 4)
|
|
481
|
-
|
|
482
|
-
return msg
|
|
483
|
-
case 12: // AuthenticationSASLFinal
|
|
484
|
-
msg.name = 'authenticationSASLFinal'
|
|
485
|
-
msg.data = this.readString(buffer, length - 4)
|
|
486
|
-
|
|
487
|
-
return msg
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
throw new Error('Unknown authenticationOk message type' + util.inspect(msg))
|
|
491
|
-
}
|
|
492
|
-
|
|
493
|
-
Connection.prototype.parseS = function (buffer, length) {
|
|
494
|
-
var msg = new Message('parameterStatus', length)
|
|
495
|
-
msg.parameterName = this.parseCString(buffer)
|
|
496
|
-
msg.parameterValue = this.parseCString(buffer)
|
|
497
|
-
return msg
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
Connection.prototype.parseK = function (buffer, length) {
|
|
501
|
-
var msg = new Message('backendKeyData', length)
|
|
502
|
-
msg.processID = this.parseInt32(buffer)
|
|
503
|
-
msg.secretKey = this.parseInt32(buffer)
|
|
504
|
-
return msg
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
Connection.prototype.parseC = function (buffer, length) {
|
|
508
|
-
var msg = new Message('commandComplete', length)
|
|
509
|
-
msg.text = this.parseCString(buffer)
|
|
510
|
-
return msg
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
Connection.prototype.parseZ = function (buffer, length) {
|
|
514
|
-
var msg = new Message('readyForQuery', length)
|
|
515
|
-
msg.name = 'readyForQuery'
|
|
516
|
-
msg.status = this.readString(buffer, 1)
|
|
517
|
-
return msg
|
|
210
|
+
this._send(serialize.copyFail(msg))
|
|
518
211
|
}
|
|
519
212
|
|
|
520
|
-
var ROW_DESCRIPTION = 'rowDescription'
|
|
521
|
-
Connection.prototype.parseT = function (buffer, length) {
|
|
522
|
-
var msg = new Message(ROW_DESCRIPTION, length)
|
|
523
|
-
msg.fieldCount = this.parseInt16(buffer)
|
|
524
|
-
var fields = []
|
|
525
|
-
for (var i = 0; i < msg.fieldCount; i++) {
|
|
526
|
-
fields.push(this.parseField(buffer))
|
|
527
|
-
}
|
|
528
|
-
msg.fields = fields
|
|
529
|
-
return msg
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
var Field = function () {
|
|
533
|
-
this.name = null
|
|
534
|
-
this.tableID = null
|
|
535
|
-
this.columnID = null
|
|
536
|
-
this.dataTypeID = null
|
|
537
|
-
this.dataTypeSize = null
|
|
538
|
-
this.dataTypeModifier = null
|
|
539
|
-
this.format = null
|
|
540
|
-
}
|
|
541
|
-
|
|
542
|
-
var FORMAT_TEXT = 'text'
|
|
543
|
-
var FORMAT_BINARY = 'binary'
|
|
544
|
-
Connection.prototype.parseField = function (buffer) {
|
|
545
|
-
var field = new Field()
|
|
546
|
-
field.name = this.parseCString(buffer)
|
|
547
|
-
field.tableID = this.parseInt32(buffer)
|
|
548
|
-
field.columnID = this.parseInt16(buffer)
|
|
549
|
-
field.dataTypeID = this.parseInt32(buffer)
|
|
550
|
-
field.dataTypeSize = this.parseInt16(buffer)
|
|
551
|
-
field.dataTypeModifier = this.parseInt32(buffer)
|
|
552
|
-
if (this.parseInt16(buffer) === TEXT_MODE) {
|
|
553
|
-
this._mode = TEXT_MODE
|
|
554
|
-
field.format = FORMAT_TEXT
|
|
555
|
-
} else {
|
|
556
|
-
this._mode = BINARY_MODE
|
|
557
|
-
field.format = FORMAT_BINARY
|
|
558
|
-
}
|
|
559
|
-
return field
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
var DATA_ROW = 'dataRow'
|
|
563
|
-
var DataRowMessage = function (length, fieldCount) {
|
|
564
|
-
this.name = DATA_ROW
|
|
565
|
-
this.length = length
|
|
566
|
-
this.fieldCount = fieldCount
|
|
567
|
-
this.fields = []
|
|
568
|
-
}
|
|
569
|
-
|
|
570
|
-
// extremely hot-path code
|
|
571
|
-
Connection.prototype.parseD = function (buffer, length) {
|
|
572
|
-
var fieldCount = this.parseInt16(buffer)
|
|
573
|
-
var msg = new DataRowMessage(length, fieldCount)
|
|
574
|
-
for (var i = 0; i < fieldCount; i++) {
|
|
575
|
-
msg.fields.push(this._readValue(buffer))
|
|
576
|
-
}
|
|
577
|
-
return msg
|
|
578
|
-
}
|
|
579
|
-
|
|
580
|
-
// extremely hot-path code
|
|
581
|
-
Connection.prototype._readValue = function (buffer) {
|
|
582
|
-
var length = this.parseInt32(buffer)
|
|
583
|
-
if (length === -1) return null
|
|
584
|
-
if (this._mode === TEXT_MODE) {
|
|
585
|
-
return this.readString(buffer, length)
|
|
586
|
-
}
|
|
587
|
-
return this.readBytes(buffer, length)
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
// parses error
|
|
591
|
-
Connection.prototype.parseE = function (buffer, length, isNotice) {
|
|
592
|
-
var fields = {}
|
|
593
|
-
var fieldType = this.readString(buffer, 1)
|
|
594
|
-
while (fieldType !== '\0') {
|
|
595
|
-
fields[fieldType] = this.parseCString(buffer)
|
|
596
|
-
fieldType = this.readString(buffer, 1)
|
|
597
|
-
}
|
|
598
|
-
|
|
599
|
-
// the msg is an Error instance
|
|
600
|
-
var msg = isNotice ? { message: fields.M } : new Error(fields.M)
|
|
601
|
-
|
|
602
|
-
// for compatibility with Message
|
|
603
|
-
msg.name = isNotice ? 'notice' : 'error'
|
|
604
|
-
msg.length = length
|
|
605
|
-
|
|
606
|
-
msg.severity = fields.S
|
|
607
|
-
msg.code = fields.C
|
|
608
|
-
msg.detail = fields.D
|
|
609
|
-
msg.hint = fields.H
|
|
610
|
-
msg.position = fields.P
|
|
611
|
-
msg.internalPosition = fields.p
|
|
612
|
-
msg.internalQuery = fields.q
|
|
613
|
-
msg.where = fields.W
|
|
614
|
-
msg.schema = fields.s
|
|
615
|
-
msg.table = fields.t
|
|
616
|
-
msg.column = fields.c
|
|
617
|
-
msg.dataType = fields.d
|
|
618
|
-
msg.constraint = fields.n
|
|
619
|
-
msg.file = fields.F
|
|
620
|
-
msg.line = fields.L
|
|
621
|
-
msg.routine = fields.R
|
|
622
|
-
return msg
|
|
623
|
-
}
|
|
624
|
-
|
|
625
|
-
// same thing, different name
|
|
626
|
-
Connection.prototype.parseN = function (buffer, length) {
|
|
627
|
-
var msg = this.parseE(buffer, length, true)
|
|
628
|
-
msg.name = 'notice'
|
|
629
|
-
return msg
|
|
630
|
-
}
|
|
631
|
-
|
|
632
|
-
Connection.prototype.parseA = function (buffer, length) {
|
|
633
|
-
var msg = new Message('notification', length)
|
|
634
|
-
msg.processId = this.parseInt32(buffer)
|
|
635
|
-
msg.channel = this.parseCString(buffer)
|
|
636
|
-
msg.payload = this.parseCString(buffer)
|
|
637
|
-
return msg
|
|
638
|
-
}
|
|
639
|
-
|
|
640
|
-
Connection.prototype.parseG = function (buffer, length) {
|
|
641
|
-
var msg = new Message('copyInResponse', length)
|
|
642
|
-
return this.parseGH(buffer, msg)
|
|
643
|
-
}
|
|
644
|
-
|
|
645
|
-
Connection.prototype.parseH = function (buffer, length) {
|
|
646
|
-
var msg = new Message('copyOutResponse', length)
|
|
647
|
-
return this.parseGH(buffer, msg)
|
|
648
|
-
}
|
|
649
|
-
|
|
650
|
-
Connection.prototype.parseGH = function (buffer, msg) {
|
|
651
|
-
var isBinary = buffer[this.offset] !== 0
|
|
652
|
-
this.offset++
|
|
653
|
-
msg.binary = isBinary
|
|
654
|
-
var columnCount = this.parseInt16(buffer)
|
|
655
|
-
msg.columnTypes = []
|
|
656
|
-
for (var i = 0; i < columnCount; i++) {
|
|
657
|
-
msg.columnTypes.push(this.parseInt16(buffer))
|
|
658
|
-
}
|
|
659
|
-
return msg
|
|
660
|
-
}
|
|
661
|
-
|
|
662
|
-
Connection.prototype.parsed = function (buffer, length) {
|
|
663
|
-
var msg = new Message('copyData', length)
|
|
664
|
-
msg.chunk = this.readBytes(buffer, msg.length - 4)
|
|
665
|
-
return msg
|
|
666
|
-
}
|
|
667
|
-
|
|
668
|
-
Connection.prototype.parseInt32 = function (buffer) {
|
|
669
|
-
var value = buffer.readInt32BE(this.offset)
|
|
670
|
-
this.offset += 4
|
|
671
|
-
return value
|
|
672
|
-
}
|
|
673
|
-
|
|
674
|
-
Connection.prototype.parseInt16 = function (buffer) {
|
|
675
|
-
var value = buffer.readInt16BE(this.offset)
|
|
676
|
-
this.offset += 2
|
|
677
|
-
return value
|
|
678
|
-
}
|
|
679
|
-
|
|
680
|
-
Connection.prototype.readString = function (buffer, length) {
|
|
681
|
-
return buffer.toString(this.encoding, this.offset, (this.offset += length))
|
|
682
|
-
}
|
|
683
|
-
|
|
684
|
-
Connection.prototype.readBytes = function (buffer, length) {
|
|
685
|
-
return buffer.slice(this.offset, (this.offset += length))
|
|
686
|
-
}
|
|
687
|
-
|
|
688
|
-
Connection.prototype.parseCString = function (buffer) {
|
|
689
|
-
var start = this.offset
|
|
690
|
-
var end = buffer.indexOf(0, start)
|
|
691
|
-
this.offset = end + 1
|
|
692
|
-
return buffer.toString(this.encoding, start, end)
|
|
693
|
-
}
|
|
694
|
-
// end parsing methods
|
|
695
213
|
module.exports = Connection
|