Skip to content

Commit 42bae0c

Browse files
committed
Merge pull request #353 from sevastos/bigint-bulletproofing
Handle bigint as string to prevent precision loss
2 parents a39c081 + c2a93aa commit 42bae0c

File tree

5 files changed

+58
-32
lines changed

5 files changed

+58
-32
lines changed

lib/types/binaryParsers.js

+4-5
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
var ref = require('ref');
2+
var endian = (ref.endianness === 'LE') ? 'BE' : 'LE';
3+
14
var parseBits = function(data, bits, offset, invert, callback) {
25
offset = offset || 0;
36
invert = invert || false;
@@ -106,11 +109,7 @@ var parseInt32 = function(value) {
106109
};
107110

108111
var parseInt64 = function(value) {
109-
if (parseBits(value, 1) == 1) {
110-
return -1 * (parseBits(value, 63, 1, true) + 1);
111-
}
112-
113-
return parseBits(value, 63, 1);
112+
return String(ref['readInt64' + endian](value, 0));
114113
};
115114

116115
var parseFloat32 = function(value) {

lib/types/textParsers.js

+13-4
Original file line numberDiff line numberDiff line change
@@ -162,11 +162,20 @@ var parseInteger = function(val) {
162162
return parseInt(val, 10);
163163
};
164164

165+
var parseBigInteger = function(val) {
166+
var valStr = String(val);
167+
if (/^\d+$/.test(valStr)) { return valStr; }
168+
return val;
169+
};
170+
165171
var init = function(register) {
166-
register(20, parseInteger);
167-
register(21, parseInteger);
168-
register(23, parseInteger);
169-
register(26, parseInteger);
172+
register(20, parseBigInteger); // int8
173+
register(21, parseInteger); // int2
174+
register(23, parseInteger); // int4
175+
register(26, parseInteger); // oid
176+
register(700, parseFloat); // float4/real
177+
register(701, parseFloat); // float8/double
178+
//register(1700, parseString); // numeric/decimal
170179
register(16, parseBool);
171180
register(1082, parseDate); // date
172181
register(1114, parseDate); // timestamp without timezone

package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@
1919
"main": "./lib",
2020
"dependencies": {
2121
"generic-pool": "2.0.3",
22-
"buffer-writer": "1.0.0"
22+
"buffer-writer": "1.0.0",
23+
"ref": "0.1.3"
2324
},
2425
"devDependencies": {
2526
"jshint": "1.1.0",

test/integration/client/type-coercion-tests.js

+25-8
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ var testForTypeCoercion = function(type){
2323
});
2424

2525
assert.emits(query, 'row', function(row) {
26-
assert.strictEqual(row.col, val, "expected " + type.name + " of " + val + " but got " + row.col);
26+
var expected = val + " (" + typeof val + ")";
27+
var returned = row.col + " (" + typeof row.col + ")";
28+
assert.strictEqual(row.col, val, "expected " + type.name + " of " + expected + " but got " + returned);
2729
}, "row should have been called for " + type.name + " of " + val);
2830

2931
client.query('delete from test_type');
@@ -40,13 +42,21 @@ var testForTypeCoercion = function(type){
4042

4143
var types = [{
4244
name: 'integer',
43-
values: [1, -1, null]
45+
values: [-2147483648, -1, 0, 1, 2147483647, null]
4446
},{
4547
name: 'smallint',
46-
values: [-1, 0, 1, null]
48+
values: [-32768, -1, 0, 1, 32767, null]
4749
},{
4850
name: 'bigint',
49-
values: [-10000, 0, 10000, null]
51+
values: [
52+
'-9223372036854775808',
53+
'-9007199254740992',
54+
'0',
55+
'9007199254740992',
56+
'72057594037928030',
57+
'9223372036854775807',
58+
null
59+
]
5060
},{
5161
name: 'varchar(5)',
5262
values: ['yo', '', 'zomg!', null]
@@ -58,13 +68,20 @@ var types = [{
5868
values: [true, false, null]
5969
},{
6070
name: 'numeric',
61-
values: ['-12.34', '0', '12.34', null]
71+
values: [
72+
'-12.34',
73+
'0',
74+
'12.34',
75+
'-3141592653589793238462643383279502.1618033988749894848204586834365638',
76+
'3141592653589793238462643383279502.1618033988749894848204586834365638',
77+
null
78+
]
6279
},{
6380
name: 'real',
64-
values: ['101.1', '0', '-101.3', null]
81+
values: [-101.3, -1.2, 0, 1.2, 101.1, null]
6582
},{
6683
name: 'double precision',
67-
values: ['-1.2', '0', '1.2', null]
84+
values: [-101.3, -1.2, 0, 1.2, 101.1, null]
6885
},{
6986
name: 'timestamptz',
7087
values: [null]
@@ -82,7 +99,7 @@ var types = [{
8299
// ignore some tests in binary mode
83100
if (helper.config.binary) {
84101
types = types.filter(function(type) {
85-
return !(type.name in {'real':1, 'timetz':1, 'time':1, 'numeric': 1, 'double precision': 1});
102+
return !(type.name in {'real': 1, 'timetz':1, 'time':1, 'numeric': 1});
86103
});
87104
}
88105

test/unit/client/typed-query-results-tests.js

+14-14
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
var helper = require(__dirname + '/test-helper');
2-
//http://www.postgresql.org/docs/8.4/static/datatype.html
2+
//http://www.postgresql.org/docs/9.2/static/datatype.html
33
test('typed results', function() {
44
var client = helper.client();
55
var con = client.connection;
@@ -18,20 +18,20 @@ test('typed results', function() {
1818
name: 'integer/int4',
1919
format: 'text',
2020
dataTypeID: 23,
21-
actual: '100',
22-
expected: 100
21+
actual: '2147483647',
22+
expected: 2147483647
2323
},{
2424
name: 'smallint/int2',
2525
format: 'text',
2626
dataTypeID: 21,
27-
actual: '101',
28-
expected: 101
27+
actual: '32767',
28+
expected: 32767
2929
},{
3030
name: 'bigint/int8',
3131
format: 'text',
3232
dataTypeID: 20,
33-
actual: '102',
34-
expected: 102
33+
actual: '9223372036854775807',
34+
expected: '9223372036854775807'
3535
},{
3636
name: 'oid',
3737
format: 'text',
@@ -42,20 +42,20 @@ test('typed results', function() {
4242
name: 'numeric',
4343
format: 'text',
4444
dataTypeID: 1700,
45-
actual: '12.34',
46-
expected: '12.34'
45+
actual: '31415926535897932384626433832795028841971693993751058.16180339887498948482045868343656381177203091798057628',
46+
expected: '31415926535897932384626433832795028841971693993751058.16180339887498948482045868343656381177203091798057628'
4747
},{
4848
name: 'real/float4',
4949
dataTypeID: 700,
5050
format: 'text',
5151
actual: '123.456',
52-
expected: '123.456'
52+
expected: 123.456
5353
},{
5454
name: 'double precision / float8',
5555
format: 'text',
5656
dataTypeID: 701,
57-
actual: '1.2',
58-
expected: '1.2'
57+
actual: '12345678.12345678',
58+
expected: 12345678.12345678
5959
},{
6060
name: 'boolean true',
6161
format: 'text',
@@ -222,13 +222,13 @@ test('typed results', function() {
222222
format: 'binary',
223223
dataTypeID: 20,
224224
actual: [0, 0, 0, 0, 0, 0, 0, 102],
225-
expected: 102
225+
expected: '102'
226226
},{
227227
name: 'binary-bigint/int8-full',
228228
format: 'binary',
229229
dataTypeID: 20,
230230
actual: [1, 0, 0, 0, 0, 0, 0, 102],
231-
expected: 72057594037928030
231+
expected: '72057594037928038'
232232
},{
233233
name: 'binary-oid',
234234
format: 'binary',

0 commit comments

Comments
 (0)