Skip to content

Commit eaa0cfd

Browse files
committed
pg-native: read all the values of a result in one call when libpq has getvalues
1 parent 0980cef commit eaa0cfd

2 files changed

Lines changed: 64 additions & 6 deletions

File tree

‎packages/pg-native/lib/build-result.js‎

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,28 +39,34 @@ class Result {
3939
consumeRows(pq) {
4040
const tupleCount = pq.ntuples()
4141
this.rows = new Array(tupleCount)
42+
// all the values in one native call when libpq has it, instead of one or two calls per value
43+
const values = typeof pq.getvalues === 'function' ? pq.getvalues() : undefined
4244
for (let i = 0; i < tupleCount; i++) {
43-
this.rows[i] = this._arrayMode ? this.consumeRowAsArray(pq, i) : this.consumeRowAsObject(pq, i)
45+
this.rows[i] = this._arrayMode ? this.consumeRowAsArray(pq, i, values) : this.consumeRowAsObject(pq, i, values)
4446
}
4547
}
4648

47-
consumeRowAsObject(pq, rowIndex) {
49+
consumeRowAsObject(pq, rowIndex, values) {
4850
const row = { ...this._prebuiltEmptyResultObject }
4951
for (let j = 0; j < this.fields.length; j++) {
50-
row[this.fields[j].name] = this.readValue(pq, rowIndex, j)
52+
row[this.fields[j].name] = this.readValue(pq, rowIndex, j, values)
5153
}
5254
return row
5355
}
5456

55-
consumeRowAsArray(pq, rowIndex) {
57+
consumeRowAsArray(pq, rowIndex, values) {
5658
const row = new Array(this.fields.length)
5759
for (let j = 0; j < this.fields.length; j++) {
58-
row[j] = this.readValue(pq, rowIndex, j)
60+
row[j] = this.readValue(pq, rowIndex, j, values)
5961
}
6062
return row
6163
}
6264

63-
readValue(pq, rowIndex, colIndex) {
65+
readValue(pq, rowIndex, colIndex, values) {
66+
if (values !== undefined) {
67+
const value = values[rowIndex * this.fields.length + colIndex]
68+
return value === null ? null : this._parsers[colIndex](value)
69+
}
6470
const rawValue = pq.getvalue(rowIndex, colIndex)
6571
if (rawValue === '' && pq.getisnull(rowIndex, colIndex)) {
6672
return null
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
const assert = require('assert')
2+
const types = require('pg-types')
3+
const buildResult = require('../lib/build-result')
4+
5+
// the rows ('brian', 30) and ('', NULL) as libpq returns them
6+
function fakeResult() {
7+
const values = [
8+
['brian', '30'],
9+
['', null],
10+
]
11+
return {
12+
cmdStatus: () => 'SELECT 2',
13+
cmdTuples: () => '2',
14+
ntuples: () => values.length,
15+
nfields: () => 2,
16+
fname: (col) => ['name', 'age'][col],
17+
ftype: (col) => [25, 23][col],
18+
getvalue: (row, col) => values[row][col] ?? '',
19+
getisnull: (row, col) => values[row][col] === null,
20+
getvalues: () => values.flat(),
21+
}
22+
}
23+
24+
describe('build result', function () {
25+
it('reads all the values in one call when libpq has getvalues', function () {
26+
const pq = fakeResult()
27+
pq.getvalue = pq.getisnull = () => {
28+
throw new Error('one native call per value')
29+
}
30+
assert.deepStrictEqual(buildResult(pq, types, false).rows, [
31+
{ name: 'brian', age: 30 },
32+
{ name: '', age: null },
33+
])
34+
assert.deepStrictEqual(buildResult(pq, types, true).rows, [
35+
['brian', 30],
36+
['', null],
37+
])
38+
})
39+
40+
it('reads one value at a time with an older libpq', function () {
41+
const pq = fakeResult()
42+
delete pq.getvalues
43+
assert.deepStrictEqual(buildResult(pq, types, false).rows, [
44+
{ name: 'brian', age: 30 },
45+
{ name: '', age: null },
46+
])
47+
assert.deepStrictEqual(buildResult(pq, types, true).rows, [
48+
['brian', 30],
49+
['', null],
50+
])
51+
})
52+
})

0 commit comments

Comments
 (0)