Skip to content

Commit

Permalink
Bigints support sidorares#108
Browse files Browse the repository at this point in the history
  • Loading branch information
sidorares committed Jun 11, 2014
1 parent af8f30a commit f867557
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 27 deletions.
9 changes: 8 additions & 1 deletion Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,14 @@ Backlog:

HEAD

0.12.1 0 30/04/2014
0.12.2 - 11/07/2014

- output milliseconds in date type #107
- deserialise length coded int with > 24 bit numbers
to js int / float (and not throw "Bignts not supported") #108
- support for Bigint numbers in insertId

0.12.1 - 30/04/2014

- 'dateStrings' connection option support #99
- use anonymous function for packet routing instead
Expand Down
4 changes: 2 additions & 2 deletions lib/commands/query.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ Query.prototype.done = function() {
return null;
};

Query.prototype.resultsetHeader = function(packet) {
var rs = new Packets.ResultSetHeader(packet);
Query.prototype.resultsetHeader = function(packet, connection) {
var rs = new Packets.ResultSetHeader(packet, connection.config.bigNumberStrings);
this._fieldCount = rs.fieldCount;

if (this._fieldCount === 0) {
Expand Down
56 changes: 35 additions & 21 deletions lib/packets/packet.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
//var BigNumber = require("bignumber.js");
var ErrorCodeToName = require('../constants/errors').codeToName;

var bn = require('bn.js');

function Packet(id, buffer, start, end)
{
this.sequenceId = id;
Expand Down Expand Up @@ -102,7 +104,9 @@ Packet.prototype.eofWarningCount = function() {
return this.buffer.readInt16LE(this.offset + 1);
};

Packet.prototype.readLengthCodedNumber = function() {
Packet.prototype.readLengthCodedNumber = function(bigNumberStrings) {
var word0, word1;
var res;
var byte1 = this.readInt8();
if (byte1 < 0xfb)
return byte1;
Expand All @@ -113,8 +117,17 @@ Packet.prototype.readLengthCodedNumber = function() {
return this.readInt8() + (this.readInt8() << 8) + (this.readInt8() << 16);
}
if (byte1 == 0xfe) {
console.trace();
//throw "Implement 8bytes BigNumber";
// TODO: check version
// Up to MySQL 3.22, 0xfe was followed by a 4-byte integer.
word0 = this.readInt32();
word1 = this.readInt32();
if (word1 === 0)
return word0; // don't convert to float if possible
if (word1 < 2097152) // max exact float point int, 2^52 / 2^32
return word1*0x100000000 + word0;

res = (new bn(word1)).ishln(32).iaddn(word0);
return bigNumberStrings ? res.toString() : res;
}
if (byte1 == 0xfb)
return null;
Expand All @@ -137,7 +150,7 @@ Packet.prototype.readDouble = function() {

Packet.prototype.readBuffer = function(len) {
if (typeof len == 'undefined')
len = this.end - this.offset
len = this.end - this.offset;
this.offset += len;
return this.buffer.slice(this.offset - len, this.offset);
};
Expand Down Expand Up @@ -197,7 +210,7 @@ Packet.prototype.readDateTimeString = function() {
y = this.readInt16();
m = this.readInt8();
d = this.readInt8();
str = [leftPad(4, y), leftPad(2, m), leftPad(2, d)].join('-')
str = [leftPad(4, y), leftPad(2, m), leftPad(2, d)].join('-');
}
if (length > 6) {
H = this.readInt8();
Expand Down Expand Up @@ -316,33 +329,34 @@ Packet.prototype.parseGeometryValue = function() {
}

function parseGeometry() {
var x, y, i, j, numPoints, line;
var result = null;
var byteOrder = buffer.readUInt8(offset); offset += 1;
var wkbType = byteOrder? buffer.readUInt32LE(offset) : buffer.readUInt32BE(offset); offset += 4;
switch(wkbType) {
case 1: // WKBPoint
var x = byteOrder? buffer.readDoubleLE(offset) : buffer.readDoubleBE(offset); offset += 8;
var y = byteOrder? buffer.readDoubleLE(offset) : buffer.readDoubleBE(offset); offset += 8;
x = byteOrder? buffer.readDoubleLE(offset) : buffer.readDoubleBE(offset); offset += 8;
y = byteOrder? buffer.readDoubleLE(offset) : buffer.readDoubleBE(offset); offset += 8;
result = {x: x, y: y};
break;
case 2: // WKBLineString
var numPoints = byteOrder? buffer.readUInt32LE(offset) : buffer.readUInt32BE(offset); offset += 4;
numPoints = byteOrder? buffer.readUInt32LE(offset) : buffer.readUInt32BE(offset); offset += 4;
result = [];
for(var i=numPoints;i>0;i--) {
var x = byteOrder? buffer.readDoubleLE(offset) : buffer.readDoubleBE(offset); offset += 8;
var y = byteOrder? buffer.readDoubleLE(offset) : buffer.readDoubleBE(offset); offset += 8;
for(i=numPoints;i>0;i--) {
x = byteOrder? buffer.readDoubleLE(offset) : buffer.readDoubleBE(offset); offset += 8;
y = byteOrder? buffer.readDoubleLE(offset) : buffer.readDoubleBE(offset); offset += 8;
result.push({x: x, y: y});
}
break;
case 3: // WKBPolygon
var numRings = byteOrder? buffer.readUInt32LE(offset) : buffer.readUInt32BE(offset); offset += 4;
result = [];
for(var i=numRings;i>0;i--) {
var numPoints = byteOrder? buffer.readUInt32LE(offset) : buffer.readUInt32BE(offset); offset += 4;
var line = [];
for(var j=numPoints;j>0;j--) {
var x = byteOrder? buffer.readDoubleLE(offset) : buffer.readDoubleBE(offset); offset += 8;
var y = byteOrder? buffer.readDoubleLE(offset) : buffer.readDoubleBE(offset); offset += 8;
for(i=numRings;i>0;i--) {
numPoints = byteOrder? buffer.readUInt32LE(offset) : buffer.readUInt32BE(offset); offset += 4;
line = [];
for(j=numPoints;j>0;j--) {
x = byteOrder? buffer.readDoubleLE(offset) : buffer.readDoubleBE(offset); offset += 8;
y = byteOrder? buffer.readDoubleLE(offset) : buffer.readDoubleBE(offset); offset += 8;
line.push({x: x, y: y});
}
result.push(line);
Expand All @@ -353,8 +367,8 @@ Packet.prototype.parseGeometryValue = function() {
case 6: // WKBMultiPolygon
case 7: // WKBGeometryCollection
var num = byteOrder? buffer.readUInt32LE(offset) : buffer.readUInt32BE(offset); offset += 4;
var result = [];
for(var i=num;i>0;i--) {
result = [];
for(i=num;i>0;i--) {
result.push(parseGeometry());
}
break;
Expand All @@ -379,14 +393,14 @@ Packet.prototype.parseDate = function() {
this.offset++; // -
var d = this.parseInt(2);
return new Date(y, m-1, d);
}
};

Packet.prototype.parseDateTime = function() {
var str = this.readLengthCodedString();
if (str === null)
return null;
return new Date(str);
}
};


// TODO: handle E notation
Expand Down
6 changes: 3 additions & 3 deletions lib/packets/resultset_header.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@

var Packet = require('../packets/packet');

function ResultSetHeader(packet)
function ResultSetHeader(packet, bigNumberStrings)
{
if (packet.buffer[packet.offset] !== 0) {
this.fieldCount = packet.readLengthCodedNumber();
} else {
this.fieldCount = packet.readInt8(); // skip OK byte
this.affectedRows = packet.readLengthCodedNumber();
this.insertId = packet.readLengthCodedNumber();
this.affectedRows = packet.readLengthCodedNumber(bigNumberStrings);
this.insertId = packet.readLengthCodedNumber(bigNumberStrings);
this.serverStatus = packet.readInt16();
this.warningStatus = packet.readInt16();
}
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"author": "Andrey Sidorov <[email protected]>",
"license": "MIT",
"dependencies": {
"bn.js": "^0.11.7",
"fastqueue": "~0.1.0"
},
"devDependencies": {
Expand Down
36 changes: 36 additions & 0 deletions test/integration/connection/test-insert-bigint.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
var common = require('../../common');
var connection = common.createConnection({ bigNumberString: true });
var assert = require('assert');
var bn = require('bn.js');

var table = 'insert_test';
connection.query([
'CREATE TEMPORARY TABLE `bigs` (',
'`id` bigint NOT NULL AUTO_INCREMENT,',
'`title` varchar(255),',
'PRIMARY KEY (`id`)',
') ENGINE=InnoDB DEFAULT CHARSET=utf8'
].join('\n'));

var result, result2;
connection.query("INSERT INTO bigs SET title='test', id=123");
connection.query("INSERT INTO bigs SET title='test1'", function(err, result) {
if (err) throw err;
assert.strictEqual(result.insertId, 124);
// > 24 bits
connection.query("INSERT INTO bigs SET title='test', id=123456789");
connection.query("INSERT INTO bigs SET title='test2'", function(err, result) {
assert.strictEqual(result.insertId, 123456790);
// big int
connection.query("INSERT INTO bigs SET title='test', id=9007199254740992");
connection.query("INSERT INTO bigs SET title='test3'", function(err, result) {
assert.strictEqual((new bn("9007199254740993")).cmp(result.insertId), 0);
connection.query("INSERT INTO bigs SET title='test', id=90071992547409924");
connection.config.bigNumberStrings = true;
connection.query("INSERT INTO bigs SET title='test4'", function(err, result) {
assert.strictEqual(result.insertId, "90071992547409925");
connection.end();
});
});
});
});

0 comments on commit f867557

Please sign in to comment.