Skip to content

Commit

Permalink
Add support for describing prepared statements
Browse files Browse the repository at this point in the history
  • Loading branch information
akheron committed Sep 6, 2019
1 parent 60d8df6 commit 5133ced
Show file tree
Hide file tree
Showing 6 changed files with 124 additions and 0 deletions.
5 changes: 5 additions & 0 deletions lib/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,11 @@ Client.prototype._attachListeners = function (con) {
self.activeQuery.handleDataRow(msg)
})

// delegate paramDescription to active query
con.on('paramDescription', function (msg) {
self.activeQuery.handleParamDescription(msg, con)
})

// delegate portalSuspended to active query
// eslint-disable-next-line no-unused-vars
con.on('portalSuspended', function (msg) {
Expand Down
14 changes: 14 additions & 0 deletions lib/connection.js
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,9 @@ Connection.prototype.parseMessage = function (buffer) {
case 0x73: // s
return new Message('portalSuspended', length)

case 0x74: // t
return this.parset(buffer, length)

case 0x47: // G
return this.parseG(buffer, length)

Expand Down Expand Up @@ -561,6 +564,17 @@ Connection.prototype.parseField = function (buffer) {
return field
}

Connection.prototype.parset = function (buffer, length) {
var msg = new Message('paramDescription', length)
msg.paramCount = this.parseInt16(buffer)
var params = []
for (var i = 0; i < msg.paramCount; i++) {
params.push(this.parseInt32(buffer))
}
msg.params = params
return msg
}

var DATA_ROW = 'dataRow'
var DataRowMessage = function (length, fieldCount) {
this.name = DATA_ROW
Expand Down
18 changes: 18 additions & 0 deletions lib/query.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ var Query = function (config, values, callback) {
this.types = config.types
this.name = config.name
this.binary = config.binary
this.describe = config.describe
// use unique portal name each time
this.portal = config.portal || ''
this.callback = config.callback
Expand All @@ -47,6 +48,8 @@ util.inherits(Query, EventEmitter)
Query.prototype.requiresPreparation = function () {
// named queries must always be prepared
if (this.name) { return true }
// always prepare if describing a query
if (this.describe) { return true }
// always prepare if there are max number of rows expected per
// portal execution
if (this.rows) { return true }
Expand Down Expand Up @@ -99,6 +102,11 @@ Query.prototype.handleDataRow = function (msg) {
}
}

Query.prototype.handleParamDescription = function (msg, con) {
this._result.addParams(msg.params)
con.sync()
}

Query.prototype.handleCommandComplete = function (msg, con) {
this._checkForMultirow()
this._result.addCommandComplete(msg)
Expand Down Expand Up @@ -193,6 +201,16 @@ Query.prototype.prepare = function (connection) {
}, true)
}

if (self.describe) {
// if describe is set, the query is not executed
connection.describe({
type: 'S',
name: self.name
})
connection.flush()
return
}

if (self.values) {
try {
self.values = self.values.map(utils.prepareValue)
Expand Down
11 changes: 11 additions & 0 deletions lib/result.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ var Result = function (rowMode, types) {
this.oid = null
this.rows = []
this.fields = []
this.params = []
this._parsers = []
this._types = types
this.RowCtor = null
Expand Down Expand Up @@ -100,4 +101,14 @@ Result.prototype.addFields = function (fieldDescriptions) {
}
}

Result.prototype.addParams = function (paramDescriptions) {
if (this.params.length) {
this.params = []
}
for (var i = 0; i < paramDescriptions.length; i++) {
var desc = paramDescriptions[i]
this.params.push(desc)
}
}

module.exports = Result
25 changes: 25 additions & 0 deletions test/integration/client/prepared-statement-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -151,3 +151,28 @@ var suite = new helper.Suite()

suite.test('cleanup', () => client.end())
})()

;(function () {
var client = helper.client()
client.on('drain', client.end.bind(client))

suite.test('describe', function (done) {
var query = client.query(new Query({
text: 'SELECT id, name, age FROM person WHERE age > $1',
describe: true
}, (err, res) => {
assert.deepEqual(res.params, [23])
assert.deepEqual(
res.fields.map(field => ({ name: field.name, type: field.dataTypeID })),
[
{ name: 'id', type: 23 },
{ name: 'name', type: 1043 },
{ name: 'age', type: 23 }
]
)
done()
}))
})

suite.test('cleanup', () => client.end())
})()
51 changes: 51 additions & 0 deletions test/unit/client/prepared-statement-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -153,3 +153,54 @@ test('prepared statement with explicit portal', function () {
})
})
})

var describeClient = helper.client()
var describeCon = describeClient.connection
describeCon.parse = function (arg) {
process.nextTick(function () {
describeCon.emit('parseComplete')
})
}
var describeDescribeArg = null
describeCon.describe = function (arg) {
describeDescribeArg = arg
}

var describeFlushCalled = false
describeCon.flush = function () {
describeFlushCalled = true
process.nextTick(function () {
describeCon.emit('paramDescription', { params: [] })
describeCon.emit('rowDescription', { fields: [] })
})
}

var describeSyncCalled = false
describeCon.sync = function () {
process.nextTick(function () {
describeSyncCalled = true
describeCon.emit('readyForQuery')
})
}

test('describe prepared statement', function () {
assert.ok(describeClient.connection.emit('readyForQuery'))

var query = describeClient.query(new Query({
text: 'select * from X where name = $1',
describe: true
}))

assert.emits(query, 'end', function () {
test('describe argument', function () {
assert.equal(describeDescribeArg.type, 'S')
assert.equal(describeDescribeArg.name, undefined)
})
test('flush called', function () {
assert.ok(describeFlushCalled)
})
test('sync called', function () {
assert.ok(describeSyncCalled)
})
})
})

0 comments on commit 5133ced

Please sign in to comment.