mirror of
https://github.com/brianc/node-postgres.git
synced 2025-12-08 20:16:25 +00:00
* fix(pg-protocol): specify number of result column format codes Fixes a bug when binary format. We must specify both: - the number of result column format codes - the result column format codes The text format case was working by accident. When using text format, the intention was to set the format code to 0. Instead, we set the number of result column format codes was set to 0. This is valid because it indicates that all result columns should use the default format (text). When using binary format, the intention was to set the format code to 1. Instead, we set the number of result column format codes to 1. Importantly, we never set a result column format code. This caused an error: 'insufficient data left in message'. We now always set the number of result column format codes to '1'. The value of '1' has special meaning: > or one, in which case the specified format code is applied to all result columns (if any) We then set a single column format code based on whether the connection (or query) is set to binary. Fixes #3487 * fix(pg): use a Buffer when parsing binary The call to parseArray was not working as expected because the value was being sent as a string instead of a Buffer. The binary parsers in pg-types all assume the incoming value is a Buffer.
110 lines
2.7 KiB
JavaScript
110 lines
2.7 KiB
JavaScript
'use strict'
|
|
|
|
const types = require('pg-types')
|
|
|
|
const matchRegexp = /^([A-Za-z]+)(?: (\d+))?(?: (\d+))?/
|
|
|
|
// result object returned from query
|
|
// in the 'end' event and also
|
|
// passed as second argument to provided callback
|
|
class Result {
|
|
constructor(rowMode, types) {
|
|
this.command = null
|
|
this.rowCount = null
|
|
this.oid = null
|
|
this.rows = []
|
|
this.fields = []
|
|
this._parsers = undefined
|
|
this._types = types
|
|
this.RowCtor = null
|
|
this.rowAsArray = rowMode === 'array'
|
|
if (this.rowAsArray) {
|
|
this.parseRow = this._parseRowAsArray
|
|
}
|
|
this._prebuiltEmptyResultObject = null
|
|
}
|
|
|
|
// adds a command complete message
|
|
addCommandComplete(msg) {
|
|
let match
|
|
if (msg.text) {
|
|
// pure javascript
|
|
match = matchRegexp.exec(msg.text)
|
|
} else {
|
|
// native bindings
|
|
match = matchRegexp.exec(msg.command)
|
|
}
|
|
if (match) {
|
|
this.command = match[1]
|
|
if (match[3]) {
|
|
// COMMAND OID ROWS
|
|
this.oid = parseInt(match[2], 10)
|
|
this.rowCount = parseInt(match[3], 10)
|
|
} else if (match[2]) {
|
|
// COMMAND ROWS
|
|
this.rowCount = parseInt(match[2], 10)
|
|
}
|
|
}
|
|
}
|
|
|
|
_parseRowAsArray(rowData) {
|
|
const row = new Array(rowData.length)
|
|
for (let i = 0, len = rowData.length; i < len; i++) {
|
|
const rawValue = rowData[i]
|
|
if (rawValue !== null) {
|
|
row[i] = this._parsers[i](rawValue)
|
|
} else {
|
|
row[i] = null
|
|
}
|
|
}
|
|
return row
|
|
}
|
|
|
|
parseRow(rowData) {
|
|
const row = { ...this._prebuiltEmptyResultObject }
|
|
for (let i = 0, len = rowData.length; i < len; i++) {
|
|
const rawValue = rowData[i]
|
|
const field = this.fields[i].name
|
|
if (rawValue !== null) {
|
|
const v = this.fields[i].format === 'binary' ? Buffer.from(rawValue) : rawValue
|
|
row[field] = this._parsers[i](v)
|
|
} else {
|
|
row[field] = null
|
|
}
|
|
}
|
|
return row
|
|
}
|
|
|
|
addRow(row) {
|
|
this.rows.push(row)
|
|
}
|
|
|
|
addFields(fieldDescriptions) {
|
|
// clears field definitions
|
|
// multiple query statements in 1 action can result in multiple sets
|
|
// of rowDescriptions...eg: 'select NOW(); select 1::int;'
|
|
// you need to reset the fields
|
|
this.fields = fieldDescriptions
|
|
if (this.fields.length) {
|
|
this._parsers = new Array(fieldDescriptions.length)
|
|
}
|
|
|
|
const row = {}
|
|
|
|
for (let i = 0; i < fieldDescriptions.length; i++) {
|
|
const desc = fieldDescriptions[i]
|
|
row[desc.name] = null
|
|
|
|
if (this._types) {
|
|
this._parsers[i] = this._types.getTypeParser(desc.dataTypeID, desc.format || 'text')
|
|
} else {
|
|
this._parsers[i] = types.getTypeParser(desc.dataTypeID, desc.format || 'text')
|
|
}
|
|
}
|
|
|
|
this._prebuiltEmptyResultObject = { ...row }
|
|
}
|
|
}
|
|
|
|
module.exports = Result
|