Skip to content

Commit

Permalink
copy-from-2099
Browse files Browse the repository at this point in the history
  • Loading branch information
shiyuhang0 committed Nov 17, 2023
1 parent c6a002c commit 5fa7184
Show file tree
Hide file tree
Showing 4 changed files with 151 additions and 5 deletions.
8 changes: 4 additions & 4 deletions lib/commands/query.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const Readable = require('stream').Readable;

const Command = require('./command.js');
const Packets = require('../packets/index.js');
const getTextParser = require('../parsers/text_parser.js');
const staticParser = require('../parsers/static_text_parser.js');
const ServerStatus = require('../constants/server_status.js');

const EmptyPacket = new Packets.Packet(0, Buffer.allocUnsafe(4), 0, 4);
Expand Down Expand Up @@ -212,7 +212,7 @@ class Query extends Command {
if (this._receivedFieldsCount === this._fieldCount) {
const fields = this._fields[this._resultIndex];
this.emit('fields', fields);
this._rowParser = new (getTextParser(fields, this.options, connection.config))(fields);
this._rowParser = staticParser(fields, this.options, connection.config);
return Query.prototype.fieldsEOF;
}
return Query.prototype.readField;
Expand All @@ -227,7 +227,7 @@ class Query extends Command {
}

/* eslint no-unused-vars: ["error", { "argsIgnorePattern": "^_" }] */
row(packet, _connection) {
row(packet, _connection) {
if (packet.isEOF()) {
const status = packet.eofStatusFlags();
const moreResults = status & ServerStatus.SERVER_MORE_RESULTS_EXISTS;
Expand Down Expand Up @@ -302,7 +302,7 @@ class Query extends Command {
Timers.clearTimeout(this.queryTimeout);
this.queryTimeout = null;
}

const err = new Error('Query inactivity timeout');
err.errorno = 'PROTOCOL_SEQUENCE_TIMEOUT';
err.code = 'PROTOCOL_SEQUENCE_TIMEOUT';
Expand Down
144 changes: 144 additions & 0 deletions lib/parsers/static_text_parser.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
'use strict';

const Types = require('../constants/types.js');
const Charsets = require('../constants/charsets.js');
const helpers = require('../helpers');

const typeNames = [];
for (const t in Types) {
typeNames[Types[t]] = t;
}

function readField({ packet, type, charset, encoding, config, options }) {
const supportBigNumbers =
options.supportBigNumbers || config.supportBigNumbers;
const bigNumberStrings = options.bigNumberStrings || config.bigNumberStrings;
const timezone = options.timezone || config.timezone;
const dateStrings = options.dateStrings || config.dateStrings;

switch (type) {
case Types.TINY:
case Types.SHORT:
case Types.LONG:
case Types.INT24:
case Types.YEAR:
return packet.parseLengthCodedIntNoBigCheck();
case Types.LONGLONG:
if (supportBigNumbers && bigNumberStrings) {
return packet.parseLengthCodedIntString();
}
return packet.parseLengthCodedInt(supportBigNumbers);
case Types.FLOAT:
case Types.DOUBLE:
return packet.parseLengthCodedFloat();
case Types.NULL:
// case Types.BIT:
// return 'packet.readBuffer(2)[1]';
case Types.DECIMAL:
case Types.NEWDECIMAL:
if (config.decimalNumbers) {
return packet.parseLengthCodedFloat();
}
return packet.readLengthCodedString("ascii");
case Types.DATE:
if (helpers.typeMatch(type, dateStrings, Types)) {
return packet.readLengthCodedString("ascii");
}
return packet.parseDate(timezone);
case Types.DATETIME:
case Types.TIMESTAMP:
if (helpers.typeMatch(type, dateStrings, Types)) {
return packet.readLengthCodedString('ascii');
}
return packet.parseDateTime(timezone);
case Types.TIME:
return packet.readLengthCodedString('ascii');
case Types.GEOMETRY:
return packet.parseGeometryValue();
case Types.JSON:
// Since for JSON columns mysql always returns charset 63 (BINARY),
// we have to handle it according to JSON specs and use "utf8",
// see https://github.com/sidorares/node-mysql2/issues/409
return JSON.parse(packet.readLengthCodedString('utf8'));
default:
if (charset === Charsets.BINARY) {
return packet.readLengthCodedBuffer();
}
return packet.readLengthCodedString(encoding);
}
}

function compile(fields, options, config) {
if (
typeof config.typeCast === 'function' &&
typeof options.typeCast !== 'function'
) {
options.typeCast = config.typeCast;
}
}

function createTypecastField(field, packet) {
return {
type: typeNames[field.columnType],
length: field.columnLength,
db: field.schema,
table: field.table,
name: field.name,
string: function(encoding = field.encoding) {
if (field.columnType === Types.JSON && encoding === field.encoding) {
// Since for JSON columns mysql always returns charset 63 (BINARY),
// we have to handle it according to JSON specs and use "utf8",
// see https://github.com/sidorares/node-mysql2/issues/1661
console.warn(`typeCast: JSON column "${field.name}" is interpreted as BINARY by default, recommended to manually set utf8 encoding: \`field.string("utf8")\``);
}
return packet.readLengthCodedString(encoding);
},
buffer: function() {
return packet.readLengthCodedBuffer();
},
geometry: function() {
return packet.parseGeometryValue();
}
};
}

function getTextParser(fields, options, config) {
return {
next(packet, fields, options) {
const result = options.rowsAsArray ? [] : {};
for (let i = 0; i < fields.length; i++) {
const field = fields[i];
const typeCast = options.typeCast ? options.typeCast : config.typeCast;
const next = () => {
return readField({
packet,
type: field.columnType,
encoding: field.encoding,
charset: field.characterSet,
config,
options
})
}
let value;
if (typeof typeCast === 'function') {
value = typeCast(createTypecastField(field, packet), next);
} else {
value = next();
}
if (options.rowsAsArray) {
result.push(value);
} else if (options.nestTables) {
if (!result[field.table]) {
result[field.table] = {};
}
result[field.table][field.name] = value;
} else {
result[field.name] = value;
}
}
return result;
}
}
}

module.exports = getTextParser;
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@shiyuhang0/mysql2",
"version": "0.5.2",
"version": "0.6.4",
"description": "fast mysql driver. Implements core protocol, prepared statements, ssl and compression in native JS",
"main": "index.js",
"directories": {
Expand Down
2 changes: 2 additions & 0 deletions typings/mysql/lib/Connection.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,8 @@ export interface ConnectionOptions {
authPlugins?: {
[key: string]: AuthPlugin;
};

useStaticParser?: boolean;
}

declare class Connection extends QueryableBase(ExecutableBase(EventEmitter)) {
Expand Down

0 comments on commit 5fa7184

Please sign in to comment.