Skip to content

Commit a717867

Browse files
committed
Fix Bad logic to decode the column name #1413
Introduce character_set_results tracking to ensure that we can read the column name properly
1 parent 7ee4323 commit a717867

File tree

7 files changed

+84
-7
lines changed

7 files changed

+84
-7
lines changed

lib/commands/query.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ class Query extends Command {
196196
if (this._fields[this._resultIndex].length !== this._fieldCount) {
197197
const field = new Packets.ColumnDefinition(
198198
packet,
199-
connection.clientEncoding
199+
connection.resultEncoding
200200
);
201201
this._fields[this._resultIndex].push(field);
202202
if (connection.config.debug) {

lib/connection.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ class Connection extends EventEmitter {
7979
this._protocolError = null;
8080
this._outOfOrderPackets = [];
8181
this.clientEncoding = CharsetToEncoding[this.config.charsetNumber];
82+
this.resultEncoding = CharsetToEncoding[this.config.charsetNumber];
8283
this.stream.on('error', this._handleNetworkError.bind(this));
8384
// see https://gist.github.com/khoomeister/4985691#use-that-instead-of-bind
8485
this.packetParser = new PacketParser(p => {

lib/connection_config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ class ConnectionConfig {
143143
this.charsetNumber = options.charset
144144
? ConnectionConfig.getCharsetNumber(options.charset)
145145
: options.charsetNumber || Charsets.UTF8MB4_UNICODE_CI;
146+
this.resultSetCharsetNumber = this.charsetNumber;
146147
this.compress = options.compress || false;
147148
this.authPlugins = options.authPlugins;
148149
this.authSwitchHandler = options.authSwitchHandler;

lib/constants/encoding_charset.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ module.exports = {
3636
macroman: 39,
3737
cp852: 40,
3838
utf8: 45,
39+
utf8mb3: 45,
3940
utf8mb4: 45,
4041
utf16: 54,
4142
utf16le: 56,

lib/packets/column_definition.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ const fields = ['catalog', 'schema', 'table', 'orgTable', 'name', 'orgName'];
1919
// see https://github.com/sidorares/node-mysql2/pull/137
2020
//
2121
class ColumnDefinition {
22-
constructor(packet, clientEncoding) {
22+
constructor(packet, resultEncoding) {
2323
this._buf = packet.buffer;
24-
this._clientEncoding = clientEncoding;
24+
this._resultEncoding = resultEncoding;
2525
this._catalogLength = packet.readLengthCodedNumber();
2626
this._catalogStart = packet.offset;
2727
packet.offset += this._catalogLength;
@@ -46,7 +46,7 @@ class ColumnDefinition {
4646
this.encoding = CharsetToEncoding[this.characterSet];
4747
this.name = StringParser.decode(
4848
this._buf,
49-
this.encoding === 'binary' ? this._clientEncoding : this.encoding,
49+
this._resultEncoding !== undefined ? this._resultEncoding : "utf8",
5050
_nameStart,
5151
_nameStart + _nameLength
5252
);
@@ -116,7 +116,7 @@ const addString = function(name) {
116116
const end = start + this[`_${name}Length`];
117117
const val = StringParser.decode(
118118
this._buf,
119-
this.encoding === 'binary' ? this._clientEncoding : this.encoding,
119+
this._resultEncoding !== undefined ? this._resultEncoding : "utf8",
120120
start,
121121
end
122122
);

lib/packets/resultset_header.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ const ClientConstants = require('../constants/client.js');
88
const ServerSatusFlags = require('../constants/server_status.js');
99

1010
const EncodingToCharset = require('../constants/encoding_charset.js');
11+
const CharsetToEncoding = require('../constants/charset_encodings.js');
1112
const sessionInfoTypes = require('../constants/session_track.js');
1213

1314
class ResultSetHeader {
@@ -62,8 +63,10 @@ class ResultSetHeader {
6263
const val = packet.readLengthCodedString(encoding);
6364
stateChanges.systemVariables[key] = val;
6465
if (key === 'character_set_client') {
65-
const charsetNumber = EncodingToCharset[val];
66-
connection.config.charsetNumber = charsetNumber;
66+
connection.clientEncoding = CharsetToEncoding[EncodingToCharset[val]];
67+
}
68+
if (key === 'character_set_results') {
69+
connection.resultEncoding = val === '' ? undefined : CharsetToEncoding[EncodingToCharset[val]];
6770
}
6871
} else if (type === sessionInfoTypes.SCHEMA) {
6972
key = packet.readLengthCodedString(encoding);
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
'use strict';
2+
3+
const common = require('../../common');
4+
const connection = common.createConnection().promise();
5+
const assert = require('assert');
6+
const { throws } = require('assert');
7+
8+
// test data stores
9+
const testData = [
10+
{
11+
column_charset: 'tis620',
12+
column_name: '平仮名',
13+
data: 'กขค',
14+
result_charset: 'utf8',
15+
},
16+
{
17+
column_charset: 'tis620',
18+
column_name: '平仮名',
19+
data: 'กขค',
20+
result_charset: null,
21+
},
22+
{
23+
column_charset: 'tis620',
24+
column_name: '平仮名',
25+
data: 'กขค',
26+
result_charset: 'utf8',
27+
},
28+
{
29+
column_charset: 'tis620',
30+
column_name: '平仮名',
31+
data: 'กขค',
32+
result_charset: 'utf8mb3',
33+
},
34+
{
35+
column_charset: 'utf16',
36+
column_name: 'กขค',
37+
data: 'กขค',
38+
result_charset: 'tis620',
39+
},
40+
];
41+
42+
let resultData = [];
43+
44+
(async () => {
45+
for (let i = 0; i < testData.length; ++i) {
46+
const entry = testData[i];
47+
48+
await connection.query('DROP TABLE IF EXISTS `test-charset-encoding2`');
49+
await connection.query('SET NAMES "utf8mb4"');
50+
await connection.query(
51+
'CREATE TABLE IF NOT EXISTS `test-charset-encoding2` ' +
52+
`( \`${entry.column_name}\` VARCHAR(1000) CHARACTER SET "${entry.column_charset}")`
53+
);
54+
await connection.query('INSERT INTO `test-charset-encoding2` values(?)', [
55+
entry.data,
56+
]);
57+
await connection.query('SET character_set_results = ?', [
58+
entry.result_charset,
59+
]);
60+
const result = await connection.query(
61+
'SELECT * from `test-charset-encoding2`'
62+
);
63+
resultData.push(result[0][0]);
64+
}
65+
connection.end();
66+
for (let i = 0; i < testData.length; ++i) {
67+
const data = {};
68+
data[testData[i].column_name] = testData[i].data;
69+
assert.deepEqual(resultData[i], data);
70+
}
71+
})();

0 commit comments

Comments
 (0)