Skip to content

Commit 7c55a07

Browse files
authored
Merge pull request #705 from gazoakley/feat-source-param-type
Use source parameter types
2 parents 4cc6250 + 410af1b commit 7c55a07

File tree

8 files changed

+206
-52
lines changed

8 files changed

+206
-52
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ matrix:
1111
env: LINT=0
1212
- node_js: "6.11"
1313
env: LINT=0
14-
- node_js: "8.0"
14+
- node_js: "8.9"
1515
env: LINT=1
1616

1717
cache:

lib/packets/execute.js

Lines changed: 100 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,85 @@ function Execute(id, parameters, charsetNumber) {
1111
this.encoding = CharsetToEncoding[charsetNumber];
1212
}
1313

14-
var pad = '000000000000';
15-
function leftPad(num, value) {
16-
var s = value.toString();
17-
// if we don't need to pad
18-
if (s.length >= num) {
19-
return s;
14+
function isJSON(value) {
15+
return Array.isArray(value) ||
16+
value.constructor === Object ||
17+
(typeof value.toJSON === 'function' && !Buffer.isBuffer(value));
18+
}
19+
20+
function toMysqlDateBuffer(value) {
21+
var bufferValue = Buffer.allocUnsafe(12);
22+
bufferValue.writeUInt8(11, 0);
23+
bufferValue.writeUInt16LE(value.getFullYear(), 1);
24+
bufferValue.writeUInt8(value.getMonth() + 1, 3);
25+
bufferValue.writeUInt8(value.getDate(), 4);
26+
bufferValue.writeUInt8(value.getHours(), 5);
27+
bufferValue.writeUInt8(value.getMinutes(), 6);
28+
bufferValue.writeUInt8(value.getSeconds(), 7);
29+
bufferValue.writeUInt32LE(value.getMilliseconds() * 1000, 8);
30+
return bufferValue;
31+
}
32+
33+
/**
34+
* Converts a value to an object describing type, String/Buffer representation and length
35+
* @param {*} value
36+
*/
37+
function toParameter(value, encoding) {
38+
var type = Types.VAR_STRING;
39+
var length;
40+
var fixed = false;
41+
if (value !== null) {
42+
switch (typeof value) {
43+
case 'undefined':
44+
throw new TypeError('Bind parameters must not contain undefined');
45+
46+
case 'number':
47+
type = Types.DOUBLE;
48+
fixed = true;
49+
var bufferValue = Buffer.allocUnsafe(8);
50+
bufferValue.writeDoubleLE(value, 0);
51+
value = bufferValue;
52+
break;
53+
54+
case 'boolean':
55+
type = Types.TINY;
56+
fixed = true;
57+
var bufferValue = Buffer.allocUnsafe(1);
58+
bufferValue.writeInt8(value | 0, 0);
59+
value = bufferValue;
60+
break;
61+
62+
case 'object':
63+
if (Object.prototype.toString.call(value) == '[object Date]') {
64+
type = Types.DATETIME;
65+
fixed = true;
66+
value = toMysqlDateBuffer(value);
67+
} else if (isJSON(value)) {
68+
type = Types.JSON;
69+
value = JSON.stringify(value);
70+
}
71+
break;
2072
}
21-
return (pad + s).slice(-num);
73+
} else {
74+
type = Types.NULL;
75+
value = '';
76+
}
77+
if (fixed) {
78+
length = value.length;
79+
} else {
80+
if (Buffer.isBuffer(value)) {
81+
length = Packet.lengthCodedNumberLength(value.length) + value.length;
82+
} else {
83+
value = value.toString();
84+
length = Packet.lengthCodedStringLength(value, encoding);
85+
}
86+
}
87+
return { type, value, length, fixed };
2288
}
2389

2490
Execute.prototype.toPacket = function() {
91+
var self = this;
92+
2593
// TODO: don't try to calculate packet length in advance, allocate some big buffer in advance (header + 256 bytes?)
2694
// and copy + reallocate if not enough
2795

@@ -32,33 +100,17 @@ Execute.prototype.toPacket = function() {
32100
// 9 + 1 - flags
33101
// 10 + 4 - iteration-count (always 1)
34102
var length = 14;
103+
var parameters;
35104
if (this.parameters && this.parameters.length > 0) {
36105
length += Math.floor((this.parameters.length + 7) / 8);
37106
length += 1; // new-params-bound-flag
38107
length += 2 * this.parameters.length; // type byte for each parameter if new-params-bound-flag is set
39-
for (i = 0; i < this.parameters.length; i++) {
40-
if (this.parameters[i] !== null) {
41-
if (
42-
Object.prototype.toString.call(this.parameters[i]) == '[object Date]'
43-
) {
44-
var d = this.parameters[i];
45-
// TODO: move to asMysqlDateTime()
46-
this.parameters[i] =
47-
[d.getFullYear(), d.getMonth() + 1, d.getDate()].join('-') +
48-
' ' +
49-
[d.getHours(), d.getMinutes(), d.getSeconds()].join(':') +
50-
'.' + leftPad(3, d.getMilliseconds())
51-
;
52-
}
53-
if (Buffer.isBuffer(this.parameters[i])) {
54-
length += Packet.lengthCodedNumberLength(this.parameters[i].length);
55-
length += this.parameters[i].length;
56-
} else {
57-
var str = this.parameters[i].toString();
58-
length += Packet.lengthCodedStringLength(str, this.encoding);
59-
}
60-
}
61-
}
108+
parameters = this.parameters.map(function (value) {
109+
return toParameter(value, self.encoding);
110+
});
111+
length += parameters.reduce(function (accumulator, parameter) {
112+
return accumulator + parameter.length;
113+
}, 0);
62114
}
63115

64116
var buffer = Buffer.allocUnsafe(length);
@@ -68,11 +120,11 @@ Execute.prototype.toPacket = function() {
68120
packet.writeInt32(this.id);
69121
packet.writeInt8(CursorType.NO_CURSOR); // flags
70122
packet.writeInt32(1); // iteration-count, always 1
71-
if (this.parameters && this.parameters.length > 0) {
123+
if (parameters) {
72124
var bitmap = 0;
73125
var bitValue = 1;
74-
for (i = 0; i < this.parameters.length; i++) {
75-
if (this.parameters[i] === null) {
126+
parameters.forEach(function (parameter) {
127+
if (parameter.type === Types.NULL) {
76128
bitmap += bitValue;
77129
}
78130
bitValue *= 2;
@@ -81,7 +133,7 @@ Execute.prototype.toPacket = function() {
81133
bitmap = 0;
82134
bitValue = 1;
83135
}
84-
}
136+
});
85137
if (bitValue != 1) {
86138
packet.writeInt8(bitmap);
87139
}
@@ -91,27 +143,24 @@ Execute.prototype.toPacket = function() {
91143
// if not, previous execution types are used (TODO prooflink)
92144
packet.writeInt8(1); // new-params-bound-flag
93145

94-
// TODO: don't typecast always to sting, use parameters type
95-
for (i = 0; i < this.parameters.length; i++) {
96-
if (this.parameters[i] !== null) {
97-
packet.writeInt16(Types.VAR_STRING);
98-
} else {
99-
packet.writeInt16(Types.NULL);
100-
}
101-
}
146+
// Write parameter types
147+
parameters.forEach(function (parameter) {
148+
packet.writeInt8(parameter.type); // field type
149+
packet.writeInt8(0); // parameter flag
150+
});
102151

103-
for (i = 0; i < this.parameters.length; i++) {
104-
if (this.parameters[i] !== null) {
105-
if (Buffer.isBuffer(this.parameters[i])) {
106-
packet.writeLengthCodedBuffer(this.parameters[i]);
152+
// Write parameter values
153+
parameters.forEach(function (parameter) {
154+
if (parameter.type !== Types.NULL) {
155+
if (parameter.fixed) {
156+
packet.writeBuffer(parameter.value);
157+
} else if (Buffer.isBuffer(parameter.value)) {
158+
packet.writeLengthCodedBuffer(parameter.value);
107159
} else {
108-
packet.writeLengthCodedString(
109-
this.parameters[i].toString(),
110-
this.encoding
111-
);
160+
packet.writeLengthCodedString(parameter.value, self.encoding);
112161
}
113162
}
114-
}
163+
});
115164
}
116165
return packet;
117166
};
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
var common = require('../../common');
2+
var connection = common.createConnection();
3+
var assert = require('assert');
4+
5+
var rows, fields;
6+
connection.execute('SELECT ? AS trueValue, ? AS falseValue', [true, false], function(err, _rows, _fields) {
7+
if (err) {
8+
throw err;
9+
}
10+
rows = _rows;
11+
fields = _fields;
12+
connection.end();
13+
});
14+
15+
process.on('exit', function() {
16+
assert.deepEqual(rows, [{ trueValue: 1, falseValue: 0 }]);
17+
});
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
var common = require('../../common');
2+
var connection = common.createConnection();
3+
var assert = require('assert');
4+
5+
var date = new Date(2018, 02, 10, 15, 12, 34, 1234)
6+
7+
var rows, fields;
8+
connection.execute('SELECT ? AS result', [date], function(err, _rows, _fields) {
9+
if (err) {
10+
throw err;
11+
}
12+
rows = _rows;
13+
fields = _fields;
14+
connection.end();
15+
});
16+
17+
process.on('exit', function() {
18+
assert.deepEqual(rows, [{ result: date }]);
19+
});
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
var common = require('../../common');
2+
var connection = common.createConnection();
3+
var assert = require('assert');
4+
5+
var rows, fields;
6+
connection.execute('SELECT ? AS result', [{ a: 1, b: true, c: ["foo"] }], function(err, _rows, _fields) {
7+
if (err) {
8+
throw err;
9+
}
10+
rows = _rows;
11+
fields = _fields;
12+
connection.end();
13+
});
14+
15+
process.on('exit', function() {
16+
assert.deepEqual(rows, [{ result: { a: 1, b: true, c: ["foo"] } }]);
17+
});
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
var common = require('../../common');
2+
var connection = common.createConnection();
3+
var assert = require('assert');
4+
5+
var rows, fields;
6+
connection.execute('SELECT ? AS firstValue, ? AS nullValue, ? AS lastValue', ['foo', null, 'bar'], function(err, _rows, _fields) {
7+
if (err) {
8+
throw err;
9+
}
10+
rows = _rows;
11+
fields = _fields;
12+
connection.end();
13+
});
14+
15+
process.on('exit', function() {
16+
assert.deepEqual(rows, [{ firstValue: 'foo', nullValue: null, lastValue: 'bar' }]);
17+
});
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
var common = require('../../common');
2+
var connection = common.createConnection();
3+
var assert = require('assert');
4+
5+
var rows, fields;
6+
connection.execute('SELECT ? AS zeroValue, ? AS positiveValue, ? AS negativeValue, ? AS decimalValue', [0, 123, -123, 1.25], function(err, _rows, _fields) {
7+
if (err) {
8+
throw err;
9+
}
10+
rows = _rows;
11+
fields = _fields;
12+
connection.end();
13+
});
14+
15+
process.on('exit', function() {
16+
assert.deepEqual(rows, [{ zeroValue: 0, positiveValue: 123, negativeValue: -123, decimalValue: 1.25 }]);
17+
});
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
var common = require('../../common');
2+
var connection = common.createConnection();
3+
var assert = require('assert');
4+
5+
var error = null;
6+
var foo = {};
7+
8+
connection.execute('SELECT ? AS result', [foo.bar], function(err, _rows) { });
9+
10+
// TODO: Needs to be a better way of catching this exception
11+
process.on('uncaughtException', (err) => {
12+
error = err;
13+
process.exit(0);
14+
});
15+
16+
process.on('exit', function() {
17+
assert.equal(error.name, 'TypeError');
18+
});

0 commit comments

Comments
 (0)