mirror of
https://github.com/brianc/node-postgres.git
synced 2026-01-18 15:55:05 +00:00
Add option to force use of Extended Queries (#3214)
This feature can be used as follows:
```
client.query({ text: 'SELECT 1', queryMode: 'extended' })
```
This will force the query to be sent with parse/bind/execute even when it has no parameters and disallows multiple statements being executed. This can be useful in scenarios where you want to enforce more security & help prevent sql injection attacks...particularly by library authors.
---------
Co-authored-by: alxndrsn <alxndrsn>
Co-authored-by: Brian Carlson <brian.m.carlson@gmail.com>
This commit is contained in:
parent
fe88e825e5
commit
ff47a97f28
@ -75,6 +75,9 @@ type QueryConfig {
|
||||
|
||||
// custom type parsers just for this query result
|
||||
types?: Types;
|
||||
|
||||
// TODO: document
|
||||
queryMode?: string;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@ -57,7 +57,7 @@ Client.prototype.query = function (text, values, cb) {
|
||||
cb = values
|
||||
}
|
||||
|
||||
if (Array.isArray(values) && values.length > 0) {
|
||||
if (Array.isArray(values)) {
|
||||
queryFn = function () {
|
||||
return self.pq.sendQueryParams(text, values)
|
||||
}
|
||||
|
||||
@ -10,6 +10,7 @@ var NativeQuery = (module.exports = function (config, values, callback) {
|
||||
this.text = config.text
|
||||
this.values = config.values
|
||||
this.name = config.name
|
||||
this.queryMode = config.queryMode
|
||||
this.callback = config.callback
|
||||
this.state = 'new'
|
||||
this._arrayMode = config.rowMode === 'array'
|
||||
@ -159,6 +160,8 @@ NativeQuery.prototype.submit = function (client) {
|
||||
}
|
||||
var vals = this.values.map(utils.prepareValue)
|
||||
client.native.query(this.text, vals, after)
|
||||
} else if (this.queryMode === 'extended') {
|
||||
client.native.query(this.text, [], after)
|
||||
} else {
|
||||
client.native.query(this.text, after)
|
||||
}
|
||||
|
||||
@ -16,6 +16,7 @@ class Query extends EventEmitter {
|
||||
this.rows = config.rows
|
||||
this.types = config.types
|
||||
this.name = config.name
|
||||
this.queryMode = config.queryMode
|
||||
this.binary = config.binary
|
||||
// use unique portal name each time
|
||||
this.portal = config.portal || ''
|
||||
@ -32,6 +33,10 @@ class Query extends EventEmitter {
|
||||
}
|
||||
|
||||
requiresPreparation() {
|
||||
if (this.queryMode === 'extended') {
|
||||
return true
|
||||
}
|
||||
|
||||
// named queries must always be prepared
|
||||
if (this.name) {
|
||||
return true
|
||||
|
||||
@ -25,6 +25,31 @@ suite.test(
|
||||
})
|
||||
)
|
||||
|
||||
suite.test(
|
||||
'throws if queryMode set to "extended"',
|
||||
co.wrap(function* () {
|
||||
const client = new helper.Client()
|
||||
yield client.connect()
|
||||
|
||||
// TODO should be text or sql?
|
||||
try {
|
||||
const results = yield client.query({
|
||||
text: `SELECT 'foo'::text as name; SELECT 'bar'::text as baz`,
|
||||
queryMode: 'extended',
|
||||
})
|
||||
assert.fail('Should have thrown')
|
||||
} catch (err) {
|
||||
if (err instanceof assert.AssertionError) throw err
|
||||
|
||||
assert.equal(err.severity, 'ERROR')
|
||||
assert.equal(err.code, '42601')
|
||||
assert.equal(err.message, 'cannot insert multiple commands into a prepared statement')
|
||||
}
|
||||
|
||||
return client.end()
|
||||
})
|
||||
)
|
||||
|
||||
suite.test(
|
||||
'multiple selects work',
|
||||
co.wrap(function* () {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user