Update bot
Took 2 hours 17 minutes
This commit is contained in:
113
node_modules/mysql2/lib/auth_41.js
generated
vendored
Normal file
113
node_modules/mysql2/lib/auth_41.js
generated
vendored
Normal file
@ -0,0 +1,113 @@
|
||||
'use strict';
|
||||
|
||||
/*
|
||||
4.1 authentication: (http://bazaar.launchpad.net/~mysql/mysql-server/5.5/view/head:/sql/password.c)
|
||||
|
||||
SERVER: public_seed=create_random_string()
|
||||
send(public_seed)
|
||||
|
||||
CLIENT: recv(public_seed)
|
||||
hash_stage1=sha1("password")
|
||||
hash_stage2=sha1(hash_stage1)
|
||||
reply=xor(hash_stage1, sha1(public_seed,hash_stage2)
|
||||
|
||||
// this three steps are done in scramble()
|
||||
|
||||
send(reply)
|
||||
|
||||
|
||||
SERVER: recv(reply)
|
||||
hash_stage1=xor(reply, sha1(public_seed,hash_stage2))
|
||||
candidate_hash2=sha1(hash_stage1)
|
||||
check(candidate_hash2==hash_stage2)
|
||||
|
||||
server stores sha1(sha1(password)) ( hash_stag2)
|
||||
*/
|
||||
|
||||
const crypto = require('crypto');
|
||||
|
||||
function sha1(msg, msg1, msg2) {
|
||||
const hash = crypto.createHash('sha1');
|
||||
hash.update(msg);
|
||||
if (msg1) {
|
||||
hash.update(msg1);
|
||||
}
|
||||
|
||||
if (msg2) {
|
||||
hash.update(msg2);
|
||||
}
|
||||
|
||||
return hash.digest();
|
||||
}
|
||||
|
||||
function xor(a, b) {
|
||||
if (!Buffer.isBuffer(a)) {
|
||||
a = Buffer.from(a, 'binary');
|
||||
}
|
||||
|
||||
if (!Buffer.isBuffer(b)) {
|
||||
b = Buffer.from(b, 'binary');
|
||||
}
|
||||
|
||||
const result = Buffer.allocUnsafe(a.length);
|
||||
|
||||
for (let i = 0; i < a.length; i++) {
|
||||
result[i] = a[i] ^ b[i];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
exports.xor = xor;
|
||||
|
||||
function token(password, scramble1, scramble2) {
|
||||
// TODO: use buffers (not sure why strings here)
|
||||
if (!password) {
|
||||
return Buffer.alloc(0);
|
||||
}
|
||||
const stage1 = sha1(password);
|
||||
return exports.calculateTokenFromPasswordSha(stage1, scramble1, scramble2);
|
||||
}
|
||||
|
||||
exports.calculateTokenFromPasswordSha = function(
|
||||
passwordSha,
|
||||
scramble1,
|
||||
scramble2
|
||||
) {
|
||||
// we use AUTH 41 here, and we need only the bytes we just need.
|
||||
const authPluginData1 = scramble1.slice(0, 8);
|
||||
const authPluginData2 = scramble2.slice(0, 12);
|
||||
const stage2 = sha1(passwordSha);
|
||||
const stage3 = sha1(authPluginData1, authPluginData2, stage2);
|
||||
return xor(stage3, passwordSha);
|
||||
};
|
||||
|
||||
exports.calculateToken = token;
|
||||
|
||||
exports.verifyToken = function(publicSeed1, publicSeed2, token, doubleSha) {
|
||||
const hashStage1 = xor(token, sha1(publicSeed1, publicSeed2, doubleSha));
|
||||
const candidateHash2 = sha1(hashStage1);
|
||||
return candidateHash2.compare(doubleSha) === 0;
|
||||
};
|
||||
|
||||
exports.doubleSha1 = function(password) {
|
||||
return sha1(sha1(password));
|
||||
};
|
||||
|
||||
function xorRotating(a, seed) {
|
||||
if (!Buffer.isBuffer(a)) {
|
||||
a = Buffer.from(a, 'binary');
|
||||
}
|
||||
|
||||
if (!Buffer.isBuffer(seed)) {
|
||||
seed = Buffer.from(seed, 'binary');
|
||||
}
|
||||
|
||||
const result = Buffer.allocUnsafe(a.length);
|
||||
const seedLen = seed.length;
|
||||
|
||||
for (let i = 0; i < a.length; i++) {
|
||||
result[i] = a[i] ^ seed[i % seedLen];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
exports.xorRotating = xorRotating;
|
103
node_modules/mysql2/lib/auth_plugins/caching_sha2_password.js
generated
vendored
Normal file
103
node_modules/mysql2/lib/auth_plugins/caching_sha2_password.js
generated
vendored
Normal file
@ -0,0 +1,103 @@
|
||||
'use strict';
|
||||
|
||||
// https://mysqlserverteam.com/mysql-8-0-4-new-default-authentication-plugin-caching_sha2_password/
|
||||
|
||||
const PLUGIN_NAME = 'caching_sha2_password';
|
||||
const crypto = require('crypto');
|
||||
const { xor, xorRotating } = require('../auth_41');
|
||||
|
||||
const REQUEST_SERVER_KEY_PACKET = Buffer.from([2]);
|
||||
const FAST_AUTH_SUCCESS_PACKET = Buffer.from([3]);
|
||||
const PERFORM_FULL_AUTHENTICATION_PACKET = Buffer.from([4]);
|
||||
|
||||
const STATE_INITIAL = 0;
|
||||
const STATE_TOKEN_SENT = 1;
|
||||
const STATE_WAIT_SERVER_KEY = 2;
|
||||
const STATE_FINAL = -1;
|
||||
|
||||
function sha256(msg) {
|
||||
const hash = crypto.createHash('sha256');
|
||||
hash.update(msg, 'binary');
|
||||
return hash.digest('binary');
|
||||
}
|
||||
|
||||
function calculateToken(password, scramble) {
|
||||
if (!password) {
|
||||
return Buffer.alloc(0);
|
||||
}
|
||||
const stage1 = sha256(Buffer.from(password, 'utf8').toString('binary'));
|
||||
const stage2 = sha256(stage1);
|
||||
const stage3 = sha256(stage2 + scramble.toString('binary'));
|
||||
return xor(stage1, stage3);
|
||||
}
|
||||
|
||||
function encrypt(password, scramble, key) {
|
||||
const stage1 = xorRotating(
|
||||
Buffer.from(`${password}\0`, 'utf8').toString('binary'),
|
||||
scramble.toString('binary')
|
||||
);
|
||||
return crypto.publicEncrypt(key, stage1);
|
||||
}
|
||||
|
||||
module.exports = (pluginOptions = {}) => ({ connection }) => {
|
||||
let state = 0;
|
||||
let scramble = null;
|
||||
|
||||
const password = connection.config.password;
|
||||
|
||||
const authWithKey = serverKey => {
|
||||
const _password = encrypt(password, scramble, serverKey);
|
||||
state = STATE_FINAL;
|
||||
return _password;
|
||||
};
|
||||
|
||||
return data => {
|
||||
switch (state) {
|
||||
case STATE_INITIAL:
|
||||
scramble = data.slice(0, 20);
|
||||
state = STATE_TOKEN_SENT;
|
||||
return calculateToken(password, scramble);
|
||||
|
||||
case STATE_TOKEN_SENT:
|
||||
if (FAST_AUTH_SUCCESS_PACKET.equals(data)) {
|
||||
state = STATE_FINAL;
|
||||
return null;
|
||||
}
|
||||
|
||||
if (PERFORM_FULL_AUTHENTICATION_PACKET.equals(data)) {
|
||||
const isSecureConnection =
|
||||
typeof pluginOptions.overrideIsSecure === 'undefined'
|
||||
? connection.config.ssl || connection.config.socketPath
|
||||
: pluginOptions.overrideIsSecure;
|
||||
if (isSecureConnection) {
|
||||
state = STATE_FINAL;
|
||||
return Buffer.from(`${password}\0`, 'utf8');
|
||||
}
|
||||
|
||||
// if client provides key we can save one extra roundrip on first connection
|
||||
if (pluginOptions.serverPublicKey) {
|
||||
return authWithKey(pluginOptions.serverPublicKey);
|
||||
}
|
||||
|
||||
state = STATE_WAIT_SERVER_KEY;
|
||||
return REQUEST_SERVER_KEY_PACKET;
|
||||
}
|
||||
throw new Error(
|
||||
`Invalid AuthMoreData packet received by ${PLUGIN_NAME} plugin in STATE_TOKEN_SENT state.`
|
||||
);
|
||||
case STATE_WAIT_SERVER_KEY:
|
||||
if (pluginOptions.onServerPublicKey) {
|
||||
pluginOptions.onServerPublicKey(data);
|
||||
}
|
||||
return authWithKey(data);
|
||||
case STATE_FINAL:
|
||||
throw new Error(
|
||||
`Unexpected data in AuthMoreData packet received by ${PLUGIN_NAME} plugin in STATE_FINAL state.`
|
||||
);
|
||||
}
|
||||
|
||||
throw new Error(
|
||||
`Unexpected data in AuthMoreData packet received by ${PLUGIN_NAME} plugin in state ${state}`
|
||||
);
|
||||
};
|
||||
};
|
18
node_modules/mysql2/lib/auth_plugins/caching_sha2_password.md
generated
vendored
Normal file
18
node_modules/mysql2/lib/auth_plugins/caching_sha2_password.md
generated
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
##
|
||||
|
||||
https://mysqlserverteam.com/mysql-8-0-4-new-default-authentication-plugin-caching_sha2_password/
|
||||
|
||||
```js
|
||||
const mysql = require('mysql');
|
||||
mysql.createConnection({
|
||||
authPlugins: {
|
||||
caching_sha2_password: mysql.authPlugins.caching_sha2_password({
|
||||
onServerPublikKey: function(key) {
|
||||
console.log(key);
|
||||
},
|
||||
serverPublicKey: 'xxxyyy',
|
||||
overrideIsSecure: true //
|
||||
})
|
||||
}
|
||||
});
|
||||
```
|
0
node_modules/mysql2/lib/auth_plugins/index.js
generated
vendored
Normal file
0
node_modules/mysql2/lib/auth_plugins/index.js
generated
vendored
Normal file
32
node_modules/mysql2/lib/auth_plugins/mysql_native_password.js
generated
vendored
Normal file
32
node_modules/mysql2/lib/auth_plugins/mysql_native_password.js
generated
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
'use strict';
|
||||
|
||||
//const PLUGIN_NAME = 'mysql_native_password';
|
||||
const auth41 = require('../auth_41.js');
|
||||
|
||||
module.exports = pluginOptions => ({ connection, command }) => {
|
||||
const password =
|
||||
command.password || pluginOptions.password || connection.config.password;
|
||||
const passwordSha1 =
|
||||
command.passwordSha1 ||
|
||||
pluginOptions.passwordSha1 ||
|
||||
connection.config.passwordSha1;
|
||||
return data => {
|
||||
const authPluginData1 = data.slice(0, 8);
|
||||
const authPluginData2 = data.slice(8, 20);
|
||||
let authToken;
|
||||
if (passwordSha1) {
|
||||
authToken = auth41.calculateTokenFromPasswordSha(
|
||||
passwordSha1,
|
||||
authPluginData1,
|
||||
authPluginData2
|
||||
);
|
||||
} else {
|
||||
authToken = auth41.calculateToken(
|
||||
password,
|
||||
authPluginData1,
|
||||
authPluginData2
|
||||
);
|
||||
}
|
||||
return authToken;
|
||||
};
|
||||
};
|
60
node_modules/mysql2/lib/auth_plugins/sha256_password.js
generated
vendored
Normal file
60
node_modules/mysql2/lib/auth_plugins/sha256_password.js
generated
vendored
Normal file
@ -0,0 +1,60 @@
|
||||
'use strict';
|
||||
|
||||
const PLUGIN_NAME = 'sha256_password';
|
||||
const crypto = require('crypto');
|
||||
const { xor } = require('../auth_41');
|
||||
|
||||
const REQUEST_SERVER_KEY_PACKET = Buffer.from([1]);
|
||||
|
||||
const STATE_INITIAL = 0;
|
||||
const STATE_WAIT_SERVER_KEY = 1;
|
||||
const STATE_FINAL = -1;
|
||||
|
||||
function encrypt(password, scramble, key) {
|
||||
const stage1 = xor(
|
||||
Buffer.from(`${password}\0`, 'utf8').toString('binary'),
|
||||
scramble.toString('binary')
|
||||
);
|
||||
return crypto.publicEncrypt(key, stage1);
|
||||
}
|
||||
|
||||
module.exports = (pluginOptions = {}) => ({ connection }) => {
|
||||
let state = 0;
|
||||
let scramble = null;
|
||||
|
||||
const password = connection.config.password;
|
||||
|
||||
const authWithKey = serverKey => {
|
||||
const _password = encrypt(password, scramble, serverKey);
|
||||
state = STATE_FINAL;
|
||||
return _password;
|
||||
};
|
||||
|
||||
return data => {
|
||||
switch (state) {
|
||||
case STATE_INITIAL:
|
||||
scramble = data.slice(0, 20);
|
||||
// if client provides key we can save one extra roundrip on first connection
|
||||
if (pluginOptions.serverPublicKey) {
|
||||
return authWithKey(pluginOptions.serverPublicKey);
|
||||
}
|
||||
|
||||
state = STATE_WAIT_SERVER_KEY;
|
||||
return REQUEST_SERVER_KEY_PACKET;
|
||||
|
||||
case STATE_WAIT_SERVER_KEY:
|
||||
if (pluginOptions.onServerPublicKey) {
|
||||
pluginOptions.onServerPublicKey(data);
|
||||
}
|
||||
return authWithKey(data);
|
||||
case STATE_FINAL:
|
||||
throw new Error(
|
||||
`Unexpected data in AuthMoreData packet received by ${PLUGIN_NAME} plugin in STATE_FINAL state.`
|
||||
);
|
||||
}
|
||||
|
||||
throw new Error(
|
||||
`Unexpected data in AuthMoreData packet received by ${PLUGIN_NAME} plugin in state ${state}`
|
||||
);
|
||||
};
|
||||
};
|
91
node_modules/mysql2/lib/commands/auth_switch.js
generated
vendored
Normal file
91
node_modules/mysql2/lib/commands/auth_switch.js
generated
vendored
Normal file
@ -0,0 +1,91 @@
|
||||
'use strict';
|
||||
|
||||
const Packets = require('../packets/index.js');
|
||||
const sha256_password = require('../auth_plugins/sha256_password');
|
||||
const caching_sha2_password = require('../auth_plugins/caching_sha2_password.js');
|
||||
const mysql_native_password = require('../auth_plugins/mysql_native_password.js');
|
||||
|
||||
const standardAuthPlugins = {
|
||||
sha256_password: sha256_password({}),
|
||||
caching_sha2_password: caching_sha2_password({}),
|
||||
mysql_native_password: mysql_native_password({})
|
||||
};
|
||||
|
||||
function warnLegacyAuthSwitch() {
|
||||
console.warn(
|
||||
'WARNING! authSwitchHandler api is deprecated, please use new authPlugins api'
|
||||
);
|
||||
}
|
||||
|
||||
function authSwitchRequest(packet, connection, command) {
|
||||
const { pluginName, pluginData } = Packets.AuthSwitchRequest.fromPacket(
|
||||
packet
|
||||
);
|
||||
let authPlugin =
|
||||
connection.config.authPlugins && connection.config.authPlugins[pluginName];
|
||||
|
||||
// legacy plugin api don't allow to override mysql_native_password
|
||||
// if pluginName is mysql_native_password it's using standard auth4.1 auth
|
||||
if (
|
||||
connection.config.authSwitchHandler &&
|
||||
pluginName !== 'mysql_native_password'
|
||||
) {
|
||||
const legacySwitchHandler = connection.config.authSwitchHandler;
|
||||
warnLegacyAuthSwitch();
|
||||
legacySwitchHandler({ pluginName, pluginData }, (err, data) => {
|
||||
if (err) {
|
||||
connection.emit('error', err);
|
||||
return;
|
||||
}
|
||||
connection.writePacket(new Packets.AuthSwitchResponse(data).toPacket());
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (!authPlugin) {
|
||||
authPlugin = standardAuthPlugins[pluginName];
|
||||
}
|
||||
if (!authPlugin) {
|
||||
throw new Error(
|
||||
`Server requests authentication using unknown plugin ${pluginName}. See ${'TODO: add plugins doco here'} on how to configure or author authentication plugins.`
|
||||
);
|
||||
}
|
||||
connection._authPlugin = authPlugin({ connection, command });
|
||||
Promise.resolve(connection._authPlugin(pluginData)).then(data => {
|
||||
if (data) {
|
||||
connection.writePacket(new Packets.AuthSwitchResponse(data).toPacket());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function authSwitchRequestMoreData(packet, connection) {
|
||||
const { data } = Packets.AuthSwitchRequestMoreData.fromPacket(packet);
|
||||
|
||||
if (connection.config.authSwitchHandler) {
|
||||
const legacySwitchHandler = connection.config.authSwitchHandler;
|
||||
warnLegacyAuthSwitch();
|
||||
legacySwitchHandler({ pluginData: data }, (err, data) => {
|
||||
if (err) {
|
||||
connection.emit('error', err);
|
||||
return;
|
||||
}
|
||||
connection.writePacket(new Packets.AuthSwitchResponse(data).toPacket());
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!connection._authPlugin) {
|
||||
throw new Error(
|
||||
'AuthPluginMoreData received but no auth plugin instance found'
|
||||
);
|
||||
}
|
||||
Promise.resolve(connection._authPlugin(data)).then(data => {
|
||||
if (data) {
|
||||
connection.writePacket(new Packets.AuthSwitchResponse(data).toPacket());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
authSwitchRequest,
|
||||
authSwitchRequestMoreData
|
||||
};
|
109
node_modules/mysql2/lib/commands/binlog_dump.js
generated
vendored
Normal file
109
node_modules/mysql2/lib/commands/binlog_dump.js
generated
vendored
Normal file
@ -0,0 +1,109 @@
|
||||
'use strict';
|
||||
|
||||
const Command = require('./command');
|
||||
const Packets = require('../packets');
|
||||
|
||||
const eventParsers = [];
|
||||
|
||||
class BinlogEventHeader {
|
||||
constructor(packet) {
|
||||
this.timestamp = packet.readInt32();
|
||||
this.eventType = packet.readInt8();
|
||||
this.serverId = packet.readInt32();
|
||||
this.eventSize = packet.readInt32();
|
||||
this.logPos = packet.readInt32();
|
||||
this.flags = packet.readInt16();
|
||||
}
|
||||
}
|
||||
|
||||
class BinlogDump extends Command {
|
||||
constructor(opts) {
|
||||
super();
|
||||
// this.onResult = callback;
|
||||
this.opts = opts;
|
||||
}
|
||||
|
||||
start(packet, connection) {
|
||||
const newPacket = new Packets.BinlogDump(this.opts);
|
||||
connection.writePacket(newPacket.toPacket(1));
|
||||
return BinlogDump.prototype.binlogData;
|
||||
}
|
||||
|
||||
binlogData(packet) {
|
||||
// ok - continue consuming events
|
||||
// error - error
|
||||
// eof - end of binlog
|
||||
if (packet.isEOF()) {
|
||||
this.emit('eof');
|
||||
return null;
|
||||
}
|
||||
// binlog event header
|
||||
packet.readInt8();
|
||||
const header = new BinlogEventHeader(packet);
|
||||
const EventParser = eventParsers[header.eventType];
|
||||
let event;
|
||||
if (EventParser) {
|
||||
event = new EventParser(packet);
|
||||
} else {
|
||||
event = {
|
||||
name: 'UNKNOWN'
|
||||
};
|
||||
}
|
||||
event.header = header;
|
||||
this.emit('event', event);
|
||||
return BinlogDump.prototype.binlogData;
|
||||
}
|
||||
}
|
||||
|
||||
class RotateEvent {
|
||||
constructor(packet) {
|
||||
this.pposition = packet.readInt32();
|
||||
// TODO: read uint64 here
|
||||
packet.readInt32(); // positionDword2
|
||||
this.nextBinlog = packet.readString();
|
||||
this.name = 'RotateEvent';
|
||||
}
|
||||
}
|
||||
|
||||
class FormatDescriptionEvent {
|
||||
constructor(packet) {
|
||||
this.binlogVersion = packet.readInt16();
|
||||
this.serverVersion = packet.readString(50).replace(/\u0000.*/, ''); // eslint-disable-line no-control-regex
|
||||
this.createTimestamp = packet.readInt32();
|
||||
this.eventHeaderLength = packet.readInt8(); // should be 19
|
||||
this.eventsLength = packet.readBuffer();
|
||||
this.name = 'FormatDescriptionEvent';
|
||||
}
|
||||
}
|
||||
|
||||
class QueryEvent {
|
||||
constructor(packet) {
|
||||
const parseStatusVars = require('../packets/binlog_query_statusvars.js');
|
||||
this.slaveProxyId = packet.readInt32();
|
||||
this.executionTime = packet.readInt32();
|
||||
const schemaLength = packet.readInt8();
|
||||
this.errorCode = packet.readInt16();
|
||||
const statusVarsLength = packet.readInt16();
|
||||
const statusVars = packet.readBuffer(statusVarsLength);
|
||||
this.schema = packet.readString(schemaLength);
|
||||
packet.readInt8(); // should be zero
|
||||
this.statusVars = parseStatusVars(statusVars);
|
||||
this.query = packet.readString();
|
||||
this.name = 'QueryEvent';
|
||||
}
|
||||
}
|
||||
|
||||
class XidEvent {
|
||||
constructor(packet) {
|
||||
this.binlogVersion = packet.readInt16();
|
||||
this.xid = packet.readInt64();
|
||||
this.name = 'XidEvent';
|
||||
}
|
||||
}
|
||||
|
||||
eventParsers[2] = QueryEvent;
|
||||
eventParsers[4] = RotateEvent;
|
||||
eventParsers[15] = FormatDescriptionEvent;
|
||||
eventParsers[16] = XidEvent;
|
||||
|
||||
module.exports = BinlogDump;
|
47
node_modules/mysql2/lib/commands/change_user.js
generated
vendored
Normal file
47
node_modules/mysql2/lib/commands/change_user.js
generated
vendored
Normal file
@ -0,0 +1,47 @@
|
||||
'use strict';
|
||||
|
||||
const Command = require('./command.js');
|
||||
const Packets = require('../packets/index.js');
|
||||
const ClientHandshake = require('./client_handshake.js');
|
||||
const CharsetToEncoding = require('../constants/charset_encodings.js');
|
||||
|
||||
class ChangeUser extends Command {
|
||||
constructor(options, callback) {
|
||||
super();
|
||||
this.onResult = callback;
|
||||
this.user = options.user;
|
||||
this.password = options.password;
|
||||
this.database = options.database;
|
||||
this.passwordSha1 = options.passwordSha1;
|
||||
this.charsetNumber = options.charsetNumber;
|
||||
this.currentConfig = options.currentConfig;
|
||||
}
|
||||
start(packet, connection) {
|
||||
const newPacket = new Packets.ChangeUser({
|
||||
flags: connection.config.clientFlags,
|
||||
user: this.user,
|
||||
database: this.database,
|
||||
charsetNumber: this.charsetNumber,
|
||||
password: this.password,
|
||||
passwordSha1: this.passwordSha1,
|
||||
authPluginData1: connection._handshakePacket.authPluginData1,
|
||||
authPluginData2: connection._handshakePacket.authPluginData2
|
||||
});
|
||||
this.currentConfig.user = this.user;
|
||||
this.currentConfig.password = this.password;
|
||||
this.currentConfig.database = this.database;
|
||||
this.currentConfig.charsetNumber = this.charsetNumber;
|
||||
connection.clientEncoding = CharsetToEncoding[this.charsetNumber];
|
||||
// reset prepared statements cache as all statements become invalid after changeUser
|
||||
connection._statements.reset();
|
||||
connection.writePacket(newPacket.toPacket());
|
||||
return ChangeUser.prototype.handshakeResult;
|
||||
}
|
||||
}
|
||||
|
||||
ChangeUser.prototype.handshakeResult =
|
||||
ClientHandshake.prototype.handshakeResult;
|
||||
ChangeUser.prototype.calculateNativePasswordAuthToken =
|
||||
ClientHandshake.prototype.calculateNativePasswordAuthToken;
|
||||
|
||||
module.exports = ChangeUser;
|
187
node_modules/mysql2/lib/commands/client_handshake.js
generated
vendored
Normal file
187
node_modules/mysql2/lib/commands/client_handshake.js
generated
vendored
Normal file
@ -0,0 +1,187 @@
|
||||
'use strict';
|
||||
|
||||
const Command = require('./command.js');
|
||||
const Packets = require('../packets/index.js');
|
||||
const ClientConstants = require('../constants/client.js');
|
||||
const CharsetToEncoding = require('../constants/charset_encodings.js');
|
||||
const auth41 = require('../auth_41.js');
|
||||
|
||||
function flagNames(flags) {
|
||||
const res = [];
|
||||
for (const c in ClientConstants) {
|
||||
if (flags & ClientConstants[c]) {
|
||||
res.push(c.replace(/_/g, ' ').toLowerCase());
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
class ClientHandshake extends Command {
|
||||
constructor(clientFlags) {
|
||||
super();
|
||||
this.handshake = null;
|
||||
this.clientFlags = clientFlags;
|
||||
}
|
||||
|
||||
start() {
|
||||
return ClientHandshake.prototype.handshakeInit;
|
||||
}
|
||||
|
||||
sendSSLRequest(connection) {
|
||||
const sslRequest = new Packets.SSLRequest(
|
||||
this.clientFlags,
|
||||
connection.config.charsetNumber
|
||||
);
|
||||
connection.writePacket(sslRequest.toPacket());
|
||||
}
|
||||
|
||||
sendCredentials(connection) {
|
||||
if (connection.config.debug) {
|
||||
// eslint-disable-next-line
|
||||
console.log(
|
||||
'Sending handshake packet: flags:%d=(%s)',
|
||||
this.clientFlags,
|
||||
flagNames(this.clientFlags).join(', ')
|
||||
);
|
||||
}
|
||||
this.user = connection.config.user;
|
||||
this.password = connection.config.password;
|
||||
this.passwordSha1 = connection.config.passwordSha1;
|
||||
this.database = connection.config.database;
|
||||
this.autPluginName = this.handshake.autPluginName;
|
||||
const handshakeResponse = new Packets.HandshakeResponse({
|
||||
flags: this.clientFlags,
|
||||
user: this.user,
|
||||
database: this.database,
|
||||
password: this.password,
|
||||
passwordSha1: this.passwordSha1,
|
||||
charsetNumber: connection.config.charsetNumber,
|
||||
authPluginData1: this.handshake.authPluginData1,
|
||||
authPluginData2: this.handshake.authPluginData2,
|
||||
compress: connection.config.compress,
|
||||
connectAttributes: connection.config.connectAttributes
|
||||
});
|
||||
connection.writePacket(handshakeResponse.toPacket());
|
||||
}
|
||||
|
||||
calculateNativePasswordAuthToken(authPluginData) {
|
||||
// TODO: dont split into authPluginData1 and authPluginData2, instead join when 1 & 2 received
|
||||
const authPluginData1 = authPluginData.slice(0, 8);
|
||||
const authPluginData2 = authPluginData.slice(8, 20);
|
||||
let authToken;
|
||||
if (this.passwordSha1) {
|
||||
authToken = auth41.calculateTokenFromPasswordSha(
|
||||
this.passwordSha1,
|
||||
authPluginData1,
|
||||
authPluginData2
|
||||
);
|
||||
} else {
|
||||
authToken = auth41.calculateToken(
|
||||
this.password,
|
||||
authPluginData1,
|
||||
authPluginData2
|
||||
);
|
||||
}
|
||||
return authToken;
|
||||
}
|
||||
|
||||
handshakeInit(helloPacket, connection) {
|
||||
this.on('error', e => {
|
||||
connection._fatalError = e;
|
||||
connection._protocolError = e;
|
||||
});
|
||||
this.handshake = Packets.Handshake.fromPacket(helloPacket);
|
||||
if (connection.config.debug) {
|
||||
// eslint-disable-next-line
|
||||
console.log(
|
||||
'Server hello packet: capability flags:%d=(%s)',
|
||||
this.handshake.capabilityFlags,
|
||||
flagNames(this.handshake.capabilityFlags).join(', ')
|
||||
);
|
||||
}
|
||||
connection.serverCapabilityFlags = this.handshake.capabilityFlags;
|
||||
connection.serverEncoding = CharsetToEncoding[this.handshake.characterSet];
|
||||
connection.connectionId = this.handshake.connectionId;
|
||||
const serverSSLSupport =
|
||||
this.handshake.capabilityFlags & ClientConstants.SSL;
|
||||
// use compression only if requested by client and supported by server
|
||||
connection.config.compress =
|
||||
connection.config.compress &&
|
||||
this.handshake.capabilityFlags & ClientConstants.COMPRESS;
|
||||
this.clientFlags = this.clientFlags | connection.config.compress;
|
||||
if (connection.config.ssl) {
|
||||
// client requires SSL but server does not support it
|
||||
if (!serverSSLSupport) {
|
||||
const err = new Error('Server does not support secure connnection');
|
||||
err.code = 'HANDSHAKE_NO_SSL_SUPPORT';
|
||||
err.fatal = true;
|
||||
this.emit('error', err);
|
||||
return false;
|
||||
}
|
||||
// send ssl upgrade request and immediately upgrade connection to secure
|
||||
this.clientFlags |= ClientConstants.SSL;
|
||||
this.sendSSLRequest(connection);
|
||||
connection.startTLS(err => {
|
||||
// after connection is secure
|
||||
if (err) {
|
||||
// SSL negotiation error are fatal
|
||||
err.code = 'HANDSHAKE_SSL_ERROR';
|
||||
err.fatal = true;
|
||||
this.emit('error', err);
|
||||
return;
|
||||
}
|
||||
// rest of communication is encrypted
|
||||
this.sendCredentials(connection);
|
||||
});
|
||||
} else {
|
||||
this.sendCredentials(connection);
|
||||
}
|
||||
return ClientHandshake.prototype.handshakeResult;
|
||||
}
|
||||
|
||||
handshakeResult(packet, connection) {
|
||||
const marker = packet.peekByte();
|
||||
if (marker === 0xfe || marker === 1) {
|
||||
const authSwitch = require('./auth_switch');
|
||||
try {
|
||||
if (marker === 1) {
|
||||
authSwitch.authSwitchRequestMoreData(packet, connection, this);
|
||||
} else {
|
||||
authSwitch.authSwitchRequest(packet, connection, this);
|
||||
}
|
||||
return ClientHandshake.prototype.handshakeResult;
|
||||
} catch (err) {
|
||||
if (this.onResult) {
|
||||
this.onResult(err);
|
||||
} else {
|
||||
connection.emit('error', err);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if (marker !== 0) {
|
||||
const err = new Error('Unexpected packet during handshake phase');
|
||||
if (this.onResult) {
|
||||
this.onResult(err);
|
||||
} else {
|
||||
connection.emit('error', err);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
// this should be called from ClientHandshake command only
|
||||
// and skipped when called from ChangeUser command
|
||||
if (!connection.authorized) {
|
||||
connection.authorized = true;
|
||||
if (connection.config.compress) {
|
||||
const enableCompression = require('../compressed_protocol.js')
|
||||
.enableCompression;
|
||||
enableCompression(connection);
|
||||
}
|
||||
}
|
||||
if (this.onResult) {
|
||||
this.onResult(null);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
module.exports = ClientHandshake;
|
18
node_modules/mysql2/lib/commands/close_statement.js
generated
vendored
Normal file
18
node_modules/mysql2/lib/commands/close_statement.js
generated
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
'use strict';
|
||||
|
||||
const Command = require('./command');
|
||||
const Packets = require('../packets/index.js');
|
||||
|
||||
class CloseStatement extends Command {
|
||||
constructor(id) {
|
||||
super();
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
start(packet, connection) {
|
||||
connection.writePacket(new Packets.CloseStatement(this.id).toPacket(1));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = CloseStatement;
|
49
node_modules/mysql2/lib/commands/command.js
generated
vendored
Normal file
49
node_modules/mysql2/lib/commands/command.js
generated
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
'use strict';
|
||||
|
||||
const EventEmitter = require('events').EventEmitter;
|
||||
|
||||
class Command extends EventEmitter {
|
||||
constructor() {
|
||||
super();
|
||||
this.next = null;
|
||||
}
|
||||
|
||||
// slow. debug only
|
||||
stateName() {
|
||||
const state = this.next;
|
||||
for (const i in this) {
|
||||
if (this[i] === state && i !== 'next') {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return 'unknown name';
|
||||
}
|
||||
|
||||
execute(packet, connection) {
|
||||
if (!this.next) {
|
||||
this.next = this.start;
|
||||
connection._resetSequenceId();
|
||||
}
|
||||
if (packet && packet.isError()) {
|
||||
const err = packet.asError(connection.clientEncoding);
|
||||
if (this.onResult) {
|
||||
this.onResult(err);
|
||||
this.emit('end');
|
||||
} else {
|
||||
this.emit('error', err);
|
||||
this.emit('end');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// TODO: don't return anything from execute, it's ugly and error-prone. Listen for 'end' event in connection
|
||||
this.next = this.next(packet, connection);
|
||||
if (this.next) {
|
||||
return false;
|
||||
}
|
||||
this.emit('end');
|
||||
return true;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Command;
|
102
node_modules/mysql2/lib/commands/execute.js
generated
vendored
Normal file
102
node_modules/mysql2/lib/commands/execute.js
generated
vendored
Normal file
@ -0,0 +1,102 @@
|
||||
'use strict';
|
||||
|
||||
const Command = require('./command.js');
|
||||
const Query = require('./query.js');
|
||||
const Packets = require('../packets/index.js');
|
||||
|
||||
const getBinaryParser = require('../parsers/binary_parser.js');
|
||||
|
||||
class Execute extends Command {
|
||||
constructor(options, callback) {
|
||||
super();
|
||||
this.statement = options.statement;
|
||||
this.sql = options.sql;
|
||||
this.values = options.values;
|
||||
this.onResult = callback;
|
||||
this.parameters = options.values;
|
||||
this.insertId = 0;
|
||||
this._rows = [];
|
||||
this._fields = [];
|
||||
this._result = [];
|
||||
this._fieldCount = 0;
|
||||
this._rowParser = null;
|
||||
this._executeOptions = options;
|
||||
this._resultIndex = 0;
|
||||
this._localStream = null;
|
||||
this._unpipeStream = function() {};
|
||||
this._streamFactory = options.infileStreamFactory;
|
||||
this._connection = null;
|
||||
}
|
||||
|
||||
buildParserFromFields(fields, connection) {
|
||||
return getBinaryParser(fields, this.options, connection.config);
|
||||
}
|
||||
|
||||
start(packet, connection) {
|
||||
this._connection = connection;
|
||||
this.options = Object.assign({}, connection.config, this._executeOptions);
|
||||
const executePacket = new Packets.Execute(
|
||||
this.statement.id,
|
||||
this.parameters,
|
||||
connection.config.charsetNumber,
|
||||
connection.config.timezone
|
||||
);
|
||||
//For reasons why this try-catch is here, please see
|
||||
// https://github.com/sidorares/node-mysql2/pull/689
|
||||
//For additional discussion, see
|
||||
// 1. https://github.com/sidorares/node-mysql2/issues/493
|
||||
// 2. https://github.com/sidorares/node-mysql2/issues/187
|
||||
// 3. https://github.com/sidorares/node-mysql2/issues/480
|
||||
try {
|
||||
connection.writePacket(executePacket.toPacket(1));
|
||||
} catch (error) {
|
||||
this.onResult(error);
|
||||
}
|
||||
return Execute.prototype.resultsetHeader;
|
||||
}
|
||||
|
||||
readField(packet, connection) {
|
||||
let fields;
|
||||
// disabling for now, but would be great to find reliable way to parse fields only once
|
||||
// fields reported by prepare can be empty at all or just incorrect - see #169
|
||||
//
|
||||
// perfomance optimisation: if we already have this field parsed in statement header, use one from header
|
||||
// const field = this.statement.columns.length == this._fieldCount ?
|
||||
// this.statement.columns[this._receivedFieldsCount] : new Packets.ColumnDefinition(packet);
|
||||
const field = new Packets.ColumnDefinition(
|
||||
packet,
|
||||
connection.clientEncoding
|
||||
);
|
||||
this._receivedFieldsCount++;
|
||||
this._fields[this._resultIndex].push(field);
|
||||
if (this._receivedFieldsCount === this._fieldCount) {
|
||||
fields = this._fields[this._resultIndex];
|
||||
this.emit('fields', fields, this._resultIndex);
|
||||
return Execute.prototype.fieldsEOF;
|
||||
}
|
||||
return Execute.prototype.readField;
|
||||
}
|
||||
|
||||
fieldsEOF(packet, connection) {
|
||||
// check EOF
|
||||
if (!packet.isEOF()) {
|
||||
return connection.protocolError('Expected EOF packet');
|
||||
}
|
||||
this._rowParser = this.buildParserFromFields(
|
||||
this._fields[this._resultIndex],
|
||||
connection
|
||||
);
|
||||
return Execute.prototype.row;
|
||||
}
|
||||
}
|
||||
|
||||
Execute.prototype.done = Query.prototype.done;
|
||||
Execute.prototype.doneInsert = Query.prototype.doneInsert;
|
||||
Execute.prototype.resultsetHeader = Query.prototype.resultsetHeader;
|
||||
Execute.prototype._findOrCreateReadStream =
|
||||
Query.prototype._findOrCreateReadStream;
|
||||
Execute.prototype._streamLocalInfile = Query.prototype._streamLocalInfile;
|
||||
Execute.prototype.row = Query.prototype.row;
|
||||
Execute.prototype.stream = Query.prototype.stream;
|
||||
|
||||
module.exports = Execute;
|
27
node_modules/mysql2/lib/commands/index.js
generated
vendored
Normal file
27
node_modules/mysql2/lib/commands/index.js
generated
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
'use strict';
|
||||
|
||||
const ClientHandshake = require('./client_handshake.js');
|
||||
const ServerHandshake = require('./server_handshake.js');
|
||||
const Query = require('./query.js');
|
||||
const Prepare = require('./prepare.js');
|
||||
const CloseStatement = require('./close_statement.js');
|
||||
const Execute = require('./execute.js');
|
||||
const Ping = require('./ping.js');
|
||||
const RegisterSlave = require('./register_slave.js');
|
||||
const BinlogDump = require('./binlog_dump.js');
|
||||
const ChangeUser = require('./change_user.js');
|
||||
const Quit = require('./quit.js');
|
||||
|
||||
module.exports = {
|
||||
ClientHandshake,
|
||||
ServerHandshake,
|
||||
Query,
|
||||
Prepare,
|
||||
CloseStatement,
|
||||
Execute,
|
||||
Ping,
|
||||
RegisterSlave,
|
||||
BinlogDump,
|
||||
ChangeUser,
|
||||
Quit
|
||||
};
|
36
node_modules/mysql2/lib/commands/ping.js
generated
vendored
Normal file
36
node_modules/mysql2/lib/commands/ping.js
generated
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
'use strict';
|
||||
|
||||
const Command = require('./command');
|
||||
const CommandCode = require('../constants/commands');
|
||||
const Packet = require('../packets/packet');
|
||||
|
||||
// TODO: time statistics?
|
||||
// usefull for queue size and network latency monitoring
|
||||
// store created,sent,reply timestamps
|
||||
class Ping extends Command {
|
||||
constructor(callback) {
|
||||
super();
|
||||
this.onResult = callback;
|
||||
}
|
||||
|
||||
start(packet, connection) {
|
||||
const ping = new Packet(
|
||||
0,
|
||||
Buffer.from([1, 0, 0, 0, CommandCode.PING]),
|
||||
0,
|
||||
5
|
||||
);
|
||||
connection.writePacket(ping);
|
||||
return Ping.prototype.pingResponse;
|
||||
}
|
||||
|
||||
pingResponse() {
|
||||
// TODO: check it's OK packet. error check already done in caller
|
||||
if (this.onResult) {
|
||||
process.nextTick(this.onResult.bind(this));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Ping;
|
130
node_modules/mysql2/lib/commands/prepare.js
generated
vendored
Normal file
130
node_modules/mysql2/lib/commands/prepare.js
generated
vendored
Normal file
@ -0,0 +1,130 @@
|
||||
'use strict';
|
||||
|
||||
const Packets = require('../packets/index.js');
|
||||
const Command = require('./command.js');
|
||||
const CloseStatement = require('./close_statement.js');
|
||||
const Execute = require('./execute.js');
|
||||
|
||||
class PreparedStatementInfo {
|
||||
constructor(query, id, columns, parameters, connection) {
|
||||
this.query = query;
|
||||
this.id = id;
|
||||
this.columns = columns;
|
||||
this.parameters = parameters;
|
||||
this.rowParser = null;
|
||||
this._connection = connection;
|
||||
}
|
||||
|
||||
close() {
|
||||
return this._connection.addCommand(new CloseStatement(this.id));
|
||||
}
|
||||
|
||||
execute(parameters, callback) {
|
||||
if (typeof parameters === 'function') {
|
||||
callback = parameters;
|
||||
parameters = [];
|
||||
}
|
||||
return this._connection.addCommand(
|
||||
new Execute({ statement: this, values: parameters }, callback)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class Prepare extends Command {
|
||||
constructor(options, callback) {
|
||||
super();
|
||||
this.query = options.sql;
|
||||
this.onResult = callback;
|
||||
this.id = 0;
|
||||
this.fieldCount = 0;
|
||||
this.parameterCount = 0;
|
||||
this.fields = [];
|
||||
this.parameterDefinitions = [];
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
start(packet, connection) {
|
||||
const Connection = connection.constructor;
|
||||
this.key = Connection.statementKey(this.options);
|
||||
const statement = connection._statements.get(this.key);
|
||||
if (statement) {
|
||||
if (this.onResult) {
|
||||
this.onResult(null, statement);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
const cmdPacket = new Packets.PrepareStatement(
|
||||
this.query,
|
||||
connection.config.charsetNumber
|
||||
);
|
||||
connection.writePacket(cmdPacket.toPacket(1));
|
||||
return Prepare.prototype.prepareHeader;
|
||||
}
|
||||
|
||||
prepareHeader(packet, connection) {
|
||||
const header = new Packets.PreparedStatementHeader(packet);
|
||||
this.id = header.id;
|
||||
this.fieldCount = header.fieldCount;
|
||||
this.parameterCount = header.parameterCount;
|
||||
if (this.parameterCount > 0) {
|
||||
return Prepare.prototype.readParameter;
|
||||
} if (this.fieldCount > 0) {
|
||||
return Prepare.prototype.readField;
|
||||
}
|
||||
return this.prepareDone(connection);
|
||||
|
||||
}
|
||||
|
||||
readParameter(packet, connection) {
|
||||
const def = new Packets.ColumnDefinition(packet, connection.clientEncoding);
|
||||
this.parameterDefinitions.push(def);
|
||||
if (this.parameterDefinitions.length === this.parameterCount) {
|
||||
return Prepare.prototype.parametersEOF;
|
||||
}
|
||||
return this.readParameter;
|
||||
}
|
||||
|
||||
readField(packet, connection) {
|
||||
const def = new Packets.ColumnDefinition(packet, connection.clientEncoding);
|
||||
this.fields.push(def);
|
||||
if (this.fields.length === this.fieldCount) {
|
||||
return Prepare.prototype.fieldsEOF;
|
||||
}
|
||||
return Prepare.prototype.readField;
|
||||
}
|
||||
|
||||
parametersEOF(packet, connection) {
|
||||
if (!packet.isEOF()) {
|
||||
return connection.protocolError('Expected EOF packet after parameters');
|
||||
}
|
||||
if (this.fieldCount > 0) {
|
||||
return Prepare.prototype.readField;
|
||||
}
|
||||
return this.prepareDone(connection);
|
||||
|
||||
}
|
||||
|
||||
fieldsEOF(packet, connection) {
|
||||
if (!packet.isEOF()) {
|
||||
return connection.protocolError('Expected EOF packet after fields');
|
||||
}
|
||||
return this.prepareDone(connection);
|
||||
}
|
||||
|
||||
prepareDone(connection) {
|
||||
const statement = new PreparedStatementInfo(
|
||||
this.query,
|
||||
this.id,
|
||||
this.fields,
|
||||
this.parameterDefinitions,
|
||||
connection
|
||||
);
|
||||
connection._statements.set(this.key, statement);
|
||||
if (this.onResult) {
|
||||
this.onResult(null, statement);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Prepare;
|
279
node_modules/mysql2/lib/commands/query.js
generated
vendored
Normal file
279
node_modules/mysql2/lib/commands/query.js
generated
vendored
Normal file
@ -0,0 +1,279 @@
|
||||
'use strict';
|
||||
|
||||
const process = require('process');
|
||||
|
||||
const Readable = require('stream').Readable;
|
||||
|
||||
const Command = require('./command.js');
|
||||
const Packets = require('../packets/index.js');
|
||||
const getTextParser = require('../parsers/text_parser.js');
|
||||
const ServerStatus = require('../constants/server_status.js');
|
||||
const CharsetToEncoding = require('../constants/charset_encodings.js');
|
||||
|
||||
const EmptyPacket = new Packets.Packet(0, Buffer.allocUnsafe(4), 0, 4);
|
||||
|
||||
// http://dev.mysql.com/doc/internals/en/com-query.html
|
||||
class Query extends Command {
|
||||
constructor(options, callback) {
|
||||
super();
|
||||
this.sql = options.sql;
|
||||
this.values = options.values;
|
||||
this._queryOptions = options;
|
||||
this.namedPlaceholders = options.namedPlaceholders || false;
|
||||
this.onResult = callback;
|
||||
this._fieldCount = 0;
|
||||
this._rowParser = null;
|
||||
this._fields = [];
|
||||
this._rows = [];
|
||||
this._receivedFieldsCount = 0;
|
||||
this._resultIndex = 0;
|
||||
this._localStream = null;
|
||||
this._unpipeStream = function() {};
|
||||
this._streamFactory = options.infileStreamFactory;
|
||||
this._connection = null;
|
||||
}
|
||||
|
||||
then() {
|
||||
const err =
|
||||
"You have tried to call .then(), .catch(), or invoked await on the result of query that is not a promise, which is a programming error. Try calling con.promise().query(), or require('mysql2/promise') instead of 'mysql2' for a promise-compatible version of the query interface. To learn how to use async/await or Promises check out documentation at https://www.npmjs.com/package/mysql2#using-promise-wrapper, or the mysql2 documentation at https://github.com/sidorares/node-mysql2/tree/master/documentation/Promise-Wrapper.md";
|
||||
// eslint-disable-next-line
|
||||
console.log(err);
|
||||
throw new Error(err);
|
||||
}
|
||||
|
||||
start(packet, connection) {
|
||||
if (connection.config.debug) {
|
||||
// eslint-disable-next-line
|
||||
console.log(' Sending query command: %s', this.sql);
|
||||
}
|
||||
this._connection = connection;
|
||||
this.options = Object.assign({}, connection.config, this._queryOptions);
|
||||
const cmdPacket = new Packets.Query(
|
||||
this.sql,
|
||||
connection.config.charsetNumber
|
||||
);
|
||||
connection.writePacket(cmdPacket.toPacket(1));
|
||||
return Query.prototype.resultsetHeader;
|
||||
}
|
||||
|
||||
done() {
|
||||
this._unpipeStream();
|
||||
if (this.onResult) {
|
||||
let rows, fields;
|
||||
if (this._resultIndex === 0) {
|
||||
rows = this._rows[0];
|
||||
fields = this._fields[0];
|
||||
} else {
|
||||
rows = this._rows;
|
||||
fields = this._fields;
|
||||
}
|
||||
if (fields) {
|
||||
process.nextTick(() => {
|
||||
this.onResult(null, rows, fields);
|
||||
});
|
||||
} else {
|
||||
process.nextTick(() => {
|
||||
this.onResult(null, rows);
|
||||
});
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
doneInsert(rs) {
|
||||
if (this._localStreamError) {
|
||||
if (this.onResult) {
|
||||
this.onResult(this._localStreamError, rs);
|
||||
} else {
|
||||
this.emit('error', this._localStreamError);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
this._rows.push(rs);
|
||||
this._fields.push(void 0);
|
||||
this.emit('fields', void 0);
|
||||
this.emit('result', rs);
|
||||
if (rs.serverStatus & ServerStatus.SERVER_MORE_RESULTS_EXISTS) {
|
||||
this._resultIndex++;
|
||||
return this.resultsetHeader;
|
||||
}
|
||||
return this.done();
|
||||
}
|
||||
|
||||
resultsetHeader(packet, connection) {
|
||||
const rs = new Packets.ResultSetHeader(packet, connection);
|
||||
this._fieldCount = rs.fieldCount;
|
||||
if (connection.config.debug) {
|
||||
// eslint-disable-next-line
|
||||
console.log(
|
||||
` Resultset header received, expecting ${rs.fieldCount} column definition packets`
|
||||
);
|
||||
}
|
||||
if (this._fieldCount === 0) {
|
||||
return this.doneInsert(rs);
|
||||
}
|
||||
if (this._fieldCount === null) {
|
||||
return this._streamLocalInfile(connection, rs.infileName);
|
||||
}
|
||||
this._receivedFieldsCount = 0;
|
||||
this._rows.push([]);
|
||||
this._fields.push([]);
|
||||
return this.readField;
|
||||
}
|
||||
|
||||
_streamLocalInfile(connection, path) {
|
||||
if (this._streamFactory) {
|
||||
this._localStream = this._streamFactory(path);
|
||||
} else {
|
||||
this._localStreamError = new Error(
|
||||
`As a result of LOCAL INFILE command server wants to read ${path} file, but as of v2.0 you must provide streamFactory option returning ReadStream.`
|
||||
);
|
||||
connection.writePacket(EmptyPacket);
|
||||
return this.infileOk;
|
||||
}
|
||||
|
||||
const onConnectionError = () => {
|
||||
this._unpipeStream();
|
||||
};
|
||||
const onDrain = () => {
|
||||
this._localStream.resume();
|
||||
};
|
||||
const onPause = () => {
|
||||
this._localStream.pause();
|
||||
};
|
||||
const onData = function(data) {
|
||||
const dataWithHeader = Buffer.allocUnsafe(data.length + 4);
|
||||
data.copy(dataWithHeader, 4);
|
||||
connection.writePacket(
|
||||
new Packets.Packet(0, dataWithHeader, 0, dataWithHeader.length)
|
||||
);
|
||||
};
|
||||
const onEnd = () => {
|
||||
connection.removeListener('error', onConnectionError);
|
||||
connection.writePacket(EmptyPacket);
|
||||
};
|
||||
const onError = err => {
|
||||
this._localStreamError = err;
|
||||
connection.removeListener('error', onConnectionError);
|
||||
connection.writePacket(EmptyPacket);
|
||||
};
|
||||
this._unpipeStream = () => {
|
||||
connection.stream.removeListener('pause', onPause);
|
||||
connection.stream.removeListener('drain', onDrain);
|
||||
this._localStream.removeListener('data', onData);
|
||||
this._localStream.removeListener('end', onEnd);
|
||||
this._localStream.removeListener('error', onError);
|
||||
};
|
||||
connection.stream.on('pause', onPause);
|
||||
connection.stream.on('drain', onDrain);
|
||||
this._localStream.on('data', onData);
|
||||
this._localStream.on('end', onEnd);
|
||||
this._localStream.on('error', onError);
|
||||
connection.once('error', onConnectionError);
|
||||
return this.infileOk;
|
||||
}
|
||||
|
||||
readField(packet, connection) {
|
||||
this._receivedFieldsCount++;
|
||||
// Often there is much more data in the column definition than in the row itself
|
||||
// If you set manually _fields[0] to array of ColumnDefinition's (from previous call)
|
||||
// you can 'cache' result of parsing. Field packets still received, but ignored in that case
|
||||
// this is the reason _receivedFieldsCount exist (otherwise we could just use current length of fields array)
|
||||
if (this._fields[this._resultIndex].length !== this._fieldCount) {
|
||||
const field = new Packets.ColumnDefinition(
|
||||
packet,
|
||||
connection.clientEncoding
|
||||
);
|
||||
this._fields[this._resultIndex].push(field);
|
||||
if (connection.config.debug) {
|
||||
/* eslint-disable no-console */
|
||||
console.log(' Column definition:');
|
||||
console.log(` name: ${field.name}`);
|
||||
console.log(` type: ${field.columnType}`);
|
||||
console.log(` flags: ${field.flags}`);
|
||||
/* eslint-enable no-console */
|
||||
}
|
||||
}
|
||||
// last field received
|
||||
if (this._receivedFieldsCount === this._fieldCount) {
|
||||
const fields = this._fields[this._resultIndex];
|
||||
this.emit('fields', fields);
|
||||
this._rowParser = getTextParser(fields, this.options, connection.config);
|
||||
return Query.prototype.fieldsEOF;
|
||||
}
|
||||
return Query.prototype.readField;
|
||||
}
|
||||
|
||||
fieldsEOF(packet, connection) {
|
||||
// check EOF
|
||||
if (!packet.isEOF()) {
|
||||
return connection.protocolError('Expected EOF packet');
|
||||
}
|
||||
return this.row;
|
||||
}
|
||||
|
||||
row(packet) {
|
||||
if (packet.isEOF()) {
|
||||
const status = packet.eofStatusFlags();
|
||||
const moreResults = status & ServerStatus.SERVER_MORE_RESULTS_EXISTS;
|
||||
if (moreResults) {
|
||||
this._resultIndex++;
|
||||
return Query.prototype.resultsetHeader;
|
||||
}
|
||||
return this.done();
|
||||
}
|
||||
let row;
|
||||
try {
|
||||
row = new this._rowParser(
|
||||
packet,
|
||||
this._fields[this._resultIndex],
|
||||
this.options,
|
||||
CharsetToEncoding
|
||||
);
|
||||
} catch (err) {
|
||||
this._localStreamError = err;
|
||||
return this.doneInsert(null);
|
||||
}
|
||||
if (this.onResult) {
|
||||
this._rows[this._resultIndex].push(row);
|
||||
} else {
|
||||
this.emit('result', row);
|
||||
}
|
||||
return Query.prototype.row;
|
||||
}
|
||||
|
||||
infileOk(packet, connection) {
|
||||
const rs = new Packets.ResultSetHeader(packet, connection);
|
||||
return this.doneInsert(rs);
|
||||
}
|
||||
|
||||
stream(options) {
|
||||
options = options || {};
|
||||
options.objectMode = true;
|
||||
const stream = new Readable(options);
|
||||
stream._read = () => {
|
||||
this._connection && this._connection.resume();
|
||||
};
|
||||
this.on('result', row => {
|
||||
if (!stream.push(row)) {
|
||||
this._connection.pause();
|
||||
}
|
||||
stream.emit('result', row); // replicate old emitter
|
||||
});
|
||||
this.on('error', err => {
|
||||
stream.emit('error', err); // Pass on any errors
|
||||
});
|
||||
this.on('end', () => {
|
||||
stream.push(null); // pushing null, indicating EOF
|
||||
stream.emit('close'); // notify readers that query has completed
|
||||
});
|
||||
this.on('fields', fields => {
|
||||
stream.emit('fields', fields); // replicate old emitter
|
||||
});
|
||||
return stream;
|
||||
}
|
||||
}
|
||||
|
||||
Query.prototype.catch = Query.prototype.then;
|
||||
|
||||
module.exports = Query;
|
29
node_modules/mysql2/lib/commands/quit.js
generated
vendored
Normal file
29
node_modules/mysql2/lib/commands/quit.js
generated
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
'use strict';
|
||||
|
||||
const Command = require('./command.js');
|
||||
const CommandCode = require('../constants/commands.js');
|
||||
const Packet = require('../packets/packet.js');
|
||||
|
||||
class Quit extends Command {
|
||||
constructor(callback) {
|
||||
super();
|
||||
this.done = callback;
|
||||
}
|
||||
|
||||
start(packet, connection) {
|
||||
connection._closing = true;
|
||||
const quit = new Packet(
|
||||
0,
|
||||
Buffer.from([1, 0, 0, 0, CommandCode.QUIT]),
|
||||
0,
|
||||
5
|
||||
);
|
||||
if (this.done) {
|
||||
this.done();
|
||||
}
|
||||
connection.writePacket(quit);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Quit;
|
27
node_modules/mysql2/lib/commands/register_slave.js
generated
vendored
Normal file
27
node_modules/mysql2/lib/commands/register_slave.js
generated
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
'use strict';
|
||||
|
||||
const Command = require('./command');
|
||||
const Packets = require('../packets');
|
||||
|
||||
class RegisterSlave extends Command {
|
||||
constructor(opts, callback) {
|
||||
super();
|
||||
this.onResult = callback;
|
||||
this.opts = opts;
|
||||
}
|
||||
|
||||
start(packet, connection) {
|
||||
const newPacket = new Packets.RegisterSlave(this.opts);
|
||||
connection.writePacket(newPacket.toPacket(1));
|
||||
return RegisterSlave.prototype.registerResponse;
|
||||
}
|
||||
|
||||
registerResponse() {
|
||||
if (this.onResult) {
|
||||
process.nextTick(this.onResult.bind(this));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = RegisterSlave;
|
162
node_modules/mysql2/lib/commands/server_handshake.js
generated
vendored
Normal file
162
node_modules/mysql2/lib/commands/server_handshake.js
generated
vendored
Normal file
@ -0,0 +1,162 @@
|
||||
'use strict';
|
||||
|
||||
const CommandCode = require('../constants/commands.js');
|
||||
const Errors = require('../constants/errors.js');
|
||||
|
||||
const Command = require('./command.js');
|
||||
const Packets = require('../packets/index.js');
|
||||
|
||||
class ServerHandshake extends Command {
|
||||
constructor(args) {
|
||||
super();
|
||||
this.args = args;
|
||||
/*
|
||||
this.protocolVersion = args.protocolVersion || 10;
|
||||
this.serverVersion = args.serverVersion;
|
||||
this.connectionId = args.connectionId,
|
||||
this.statusFlags = args.statusFlags,
|
||||
this.characterSet = args.characterSet,
|
||||
this.capabilityFlags = args.capabilityFlags || 512;
|
||||
*/
|
||||
}
|
||||
|
||||
start(packet, connection) {
|
||||
const serverHelloPacket = new Packets.Handshake(this.args);
|
||||
this.serverHello = serverHelloPacket;
|
||||
serverHelloPacket.setScrambleData(err => {
|
||||
if (err) {
|
||||
connection.emit('error', new Error('Error generating random bytes'));
|
||||
return;
|
||||
}
|
||||
connection.writePacket(serverHelloPacket.toPacket(0));
|
||||
});
|
||||
return ServerHandshake.prototype.readClientReply;
|
||||
}
|
||||
|
||||
readClientReply(packet, connection) {
|
||||
// check auth here
|
||||
const clientHelloReply = Packets.HandshakeResponse.fromPacket(packet);
|
||||
// TODO check we don't have something similar already
|
||||
connection.clientHelloReply = clientHelloReply;
|
||||
if (this.args.authCallback) {
|
||||
this.args.authCallback(
|
||||
{
|
||||
user: clientHelloReply.user,
|
||||
database: clientHelloReply.database,
|
||||
address: connection.stream.remoteAddress,
|
||||
authPluginData1: this.serverHello.authPluginData1,
|
||||
authPluginData2: this.serverHello.authPluginData2,
|
||||
authToken: clientHelloReply.authToken
|
||||
},
|
||||
(err, mysqlError) => {
|
||||
// if (err)
|
||||
if (!mysqlError) {
|
||||
connection.writeOk();
|
||||
} else {
|
||||
// TODO create constants / errorToCode
|
||||
// 1045 = ER_ACCESS_DENIED_ERROR
|
||||
connection.writeError({
|
||||
message: mysqlError.message || '',
|
||||
code: mysqlError.code || 1045
|
||||
});
|
||||
connection.close();
|
||||
}
|
||||
}
|
||||
);
|
||||
} else {
|
||||
connection.writeOk();
|
||||
}
|
||||
return ServerHandshake.prototype.dispatchCommands;
|
||||
}
|
||||
|
||||
dispatchCommands(packet, connection) {
|
||||
// command from client to server
|
||||
let knownCommand = true;
|
||||
const encoding = connection.clientHelloReply.encoding;
|
||||
const commandCode = packet.readInt8();
|
||||
switch (commandCode) {
|
||||
case CommandCode.QUIT:
|
||||
if (connection.listeners('quit').length) {
|
||||
connection.emit('quit');
|
||||
} else {
|
||||
connection.stream.end();
|
||||
}
|
||||
break;
|
||||
case CommandCode.INIT_DB:
|
||||
if (connection.listeners('init_db').length) {
|
||||
const schemaName = packet.readString(undefined, encoding);
|
||||
connection.emit('init_db', schemaName);
|
||||
} else {
|
||||
connection.writeOk();
|
||||
}
|
||||
break;
|
||||
case CommandCode.QUERY:
|
||||
if (connection.listeners('query').length) {
|
||||
const query = packet.readString(undefined, encoding);
|
||||
connection.emit('query', query);
|
||||
} else {
|
||||
connection.writeError({
|
||||
code: Errors.HA_ERR_INTERNAL_ERROR,
|
||||
message: 'No query handler'
|
||||
});
|
||||
}
|
||||
break;
|
||||
case CommandCode.FIELD_LIST:
|
||||
if (connection.listeners('field_list').length) {
|
||||
const table = packet.readNullTerminatedString();
|
||||
const fields = packet.readString(undefined, encoding);
|
||||
connection.emit('field_list', table, fields);
|
||||
} else {
|
||||
connection.writeError({
|
||||
code: Errors.ER_WARN_DEPRECATED_SYNTAX,
|
||||
message:
|
||||
'As of MySQL 5.7.11, COM_FIELD_LIST is deprecated and will be removed in a future version of MySQL.'
|
||||
});
|
||||
}
|
||||
break;
|
||||
case CommandCode.PING:
|
||||
if (connection.listeners('ping').length) {
|
||||
connection.emit('ping');
|
||||
} else {
|
||||
connection.writeOk();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
knownCommand = false;
|
||||
}
|
||||
if (connection.listeners('packet').length) {
|
||||
connection.emit('packet', packet.clone(), knownCommand, commandCode);
|
||||
} else if (!knownCommand) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('Unknown command:', commandCode);
|
||||
}
|
||||
return ServerHandshake.prototype.dispatchCommands;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ServerHandshake;
|
||||
|
||||
// TODO: implement server-side 4.1 authentication
|
||||
/*
|
||||
4.1 authentication: (http://bazaar.launchpad.net/~mysql/mysql-server/5.5/view/head:/sql/password.c)
|
||||
|
||||
SERVER: public_seed=create_random_string()
|
||||
send(public_seed)
|
||||
|
||||
CLIENT: recv(public_seed)
|
||||
hash_stage1=sha1("password")
|
||||
hash_stage2=sha1(hash_stage1)
|
||||
reply=xor(hash_stage1, sha1(public_seed,hash_stage2)
|
||||
|
||||
// this three steps are done in scramble()
|
||||
|
||||
send(reply)
|
||||
|
||||
|
||||
SERVER: recv(reply)
|
||||
hash_stage1=xor(reply, sha1(public_seed,hash_stage2))
|
||||
candidate_hash2=sha1(hash_stage1)
|
||||
check(candidate_hash2==hash_stage2)
|
||||
|
||||
server stores sha1(sha1(password)) ( hash_stag2)
|
||||
*/
|
127
node_modules/mysql2/lib/compressed_protocol.js
generated
vendored
Normal file
127
node_modules/mysql2/lib/compressed_protocol.js
generated
vendored
Normal file
@ -0,0 +1,127 @@
|
||||
'use strict';
|
||||
|
||||
// connection mixins
|
||||
// implementation of http://dev.mysql.com/doc/internals/en/compression.html
|
||||
|
||||
const zlib = require('zlib');
|
||||
const PacketParser = require('./packet_parser.js');
|
||||
|
||||
function handleCompressedPacket(packet) {
|
||||
// eslint-disable-next-line consistent-this, no-invalid-this
|
||||
const connection = this;
|
||||
const deflatedLength = packet.readInt24();
|
||||
const body = packet.readBuffer();
|
||||
|
||||
if (deflatedLength !== 0) {
|
||||
connection.inflateQueue.push(task => {
|
||||
zlib.inflate(body, (err, data) => {
|
||||
if (err) {
|
||||
connection._handleNetworkError(err);
|
||||
return;
|
||||
}
|
||||
connection._bumpCompressedSequenceId(packet.numPackets);
|
||||
connection._inflatedPacketsParser.execute(data);
|
||||
task.done();
|
||||
});
|
||||
});
|
||||
} else {
|
||||
connection.inflateQueue.push(task => {
|
||||
connection._bumpCompressedSequenceId(packet.numPackets);
|
||||
connection._inflatedPacketsParser.execute(body);
|
||||
task.done();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function writeCompressed(buffer) {
|
||||
// http://dev.mysql.com/doc/internals/en/example-several-mysql-packets.html
|
||||
// note: sending a MySQL Packet of the size 2^24−5 to 2^24−1 via compression
|
||||
// leads to at least one extra compressed packet.
|
||||
// (this is because "length of the packet before compression" need to fit
|
||||
// into 3 byte unsigned int. "length of the packet before compression" includes
|
||||
// 4 byte packet header, hence 2^24−5)
|
||||
const MAX_COMPRESSED_LENGTH = 16777210;
|
||||
let start;
|
||||
if (buffer.length > MAX_COMPRESSED_LENGTH) {
|
||||
for (start = 0; start < buffer.length; start += MAX_COMPRESSED_LENGTH) {
|
||||
writeCompressed.call(
|
||||
// eslint-disable-next-line no-invalid-this
|
||||
this,
|
||||
buffer.slice(start, start + MAX_COMPRESSED_LENGTH)
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-invalid-this, consistent-this
|
||||
const connection = this;
|
||||
|
||||
let packetLen = buffer.length;
|
||||
const compressHeader = Buffer.allocUnsafe(7);
|
||||
|
||||
// seqqueue is used here because zlib async execution is routed via thread pool
|
||||
// internally and when we have multiple compressed packets arriving we need
|
||||
// to assemble uncompressed result sequentially
|
||||
(function(seqId) {
|
||||
connection.deflateQueue.push(task => {
|
||||
zlib.deflate(buffer, (err, compressed) => {
|
||||
if (err) {
|
||||
connection._handleFatalError(err);
|
||||
return;
|
||||
}
|
||||
let compressedLength = compressed.length;
|
||||
|
||||
if (compressedLength < packetLen) {
|
||||
compressHeader.writeUInt8(compressedLength & 0xff, 0);
|
||||
compressHeader.writeUInt16LE(compressedLength >> 8, 1);
|
||||
compressHeader.writeUInt8(seqId, 3);
|
||||
compressHeader.writeUInt8(packetLen & 0xff, 4);
|
||||
compressHeader.writeUInt16LE(packetLen >> 8, 5);
|
||||
connection.writeUncompressed(compressHeader);
|
||||
connection.writeUncompressed(compressed);
|
||||
} else {
|
||||
// http://dev.mysql.com/doc/internals/en/uncompressed-payload.html
|
||||
// To send an uncompressed payload:
|
||||
// - set length of payload before compression to 0
|
||||
// - the compressed payload contains the uncompressed payload instead.
|
||||
compressedLength = packetLen;
|
||||
packetLen = 0;
|
||||
compressHeader.writeUInt8(compressedLength & 0xff, 0);
|
||||
compressHeader.writeUInt16LE(compressedLength >> 8, 1);
|
||||
compressHeader.writeUInt8(seqId, 3);
|
||||
compressHeader.writeUInt8(packetLen & 0xff, 4);
|
||||
compressHeader.writeUInt16LE(packetLen >> 8, 5);
|
||||
connection.writeUncompressed(compressHeader);
|
||||
connection.writeUncompressed(buffer);
|
||||
}
|
||||
task.done();
|
||||
});
|
||||
});
|
||||
})(connection.compressedSequenceId);
|
||||
connection._bumpCompressedSequenceId(1);
|
||||
}
|
||||
|
||||
function enableCompression(connection) {
|
||||
connection._lastWrittenPacketId = 0;
|
||||
connection._lastReceivedPacketId = 0;
|
||||
|
||||
connection._handleCompressedPacket = handleCompressedPacket;
|
||||
connection._inflatedPacketsParser = new PacketParser(p => {
|
||||
connection.handlePacket(p);
|
||||
}, 4);
|
||||
connection._inflatedPacketsParser._lastPacket = 0;
|
||||
connection.packetParser = new PacketParser(packet => {
|
||||
connection._handleCompressedPacket(packet);
|
||||
}, 7);
|
||||
|
||||
connection.writeUncompressed = connection.write;
|
||||
connection.write = writeCompressed;
|
||||
|
||||
const seqqueue = require('seq-queue');
|
||||
connection.inflateQueue = seqqueue.createQueue();
|
||||
connection.deflateQueue = seqqueue.createQueue();
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
enableCompression: enableCompression
|
||||
};
|
900
node_modules/mysql2/lib/connection.js
generated
vendored
Normal file
900
node_modules/mysql2/lib/connection.js
generated
vendored
Normal file
@ -0,0 +1,900 @@
|
||||
'use strict';
|
||||
|
||||
const Net = require('net');
|
||||
const Tls = require('tls');
|
||||
const Timers = require('timers');
|
||||
const EventEmitter = require('events').EventEmitter;
|
||||
const Readable = require('stream').Readable;
|
||||
const Queue = require('denque');
|
||||
const SqlString = require('sqlstring');
|
||||
const LRU = require('lru-cache');
|
||||
|
||||
const PacketParser = require('./packet_parser.js');
|
||||
const Packets = require('./packets/index.js');
|
||||
const Commands = require('./commands/index.js');
|
||||
const ConnectionConfig = require('./connection_config.js');
|
||||
const CharsetToEncoding = require('./constants/charset_encodings.js');
|
||||
|
||||
let _connectionId = 0;
|
||||
|
||||
let convertNamedPlaceholders = null;
|
||||
|
||||
class Connection extends EventEmitter {
|
||||
constructor(opts) {
|
||||
super();
|
||||
this.config = opts.config;
|
||||
// TODO: fill defaults
|
||||
// if no params, connect to /var/lib/mysql/mysql.sock ( /tmp/mysql.sock on OSX )
|
||||
// if host is given, connect to host:3306
|
||||
// TODO: use `/usr/local/mysql/bin/mysql_config --socket` output? as default socketPath
|
||||
// if there is no host/port and no socketPath parameters?
|
||||
if (!opts.config.stream) {
|
||||
if (opts.config.socketPath) {
|
||||
this.stream = Net.connect(opts.config.socketPath);
|
||||
} else {
|
||||
this.stream = Net.connect(
|
||||
opts.config.port,
|
||||
opts.config.host
|
||||
);
|
||||
|
||||
// Enable keep-alive on the socket. It's disabled by default, but the
|
||||
// user can enable it and supply an initial delay.
|
||||
this.stream.setKeepAlive(true, this.config.keepAliveInitialDelay);
|
||||
}
|
||||
// if stream is a function, treat it as "stream agent / factory"
|
||||
} else if (typeof opts.config.stream === 'function') {
|
||||
this.stream = opts.config.stream(opts);
|
||||
} else {
|
||||
this.stream = opts.config.stream;
|
||||
}
|
||||
|
||||
this._internalId = _connectionId++;
|
||||
this._commands = new Queue();
|
||||
this._command = null;
|
||||
this._paused = false;
|
||||
this._paused_packets = new Queue();
|
||||
this._statements = new LRU({
|
||||
max: this.config.maxPreparedStatements,
|
||||
dispose: function(key, statement) {
|
||||
statement.close();
|
||||
}
|
||||
});
|
||||
this.serverCapabilityFlags = 0;
|
||||
this.authorized = false;
|
||||
this.sequenceId = 0;
|
||||
this.compressedSequenceId = 0;
|
||||
this.threadId = null;
|
||||
this._handshakePacket = null;
|
||||
this._fatalError = null;
|
||||
this._protocolError = null;
|
||||
this._outOfOrderPackets = [];
|
||||
this.clientEncoding = CharsetToEncoding[this.config.charsetNumber];
|
||||
this.stream.on('error', this._handleNetworkError.bind(this));
|
||||
// see https://gist.github.com/khoomeister/4985691#use-that-instead-of-bind
|
||||
this.packetParser = new PacketParser(p => {
|
||||
this.handlePacket(p);
|
||||
});
|
||||
this.stream.on('data', data => {
|
||||
if (this.connectTimeout) {
|
||||
Timers.clearTimeout(this.connectTimeout);
|
||||
this.connectTimeout = null;
|
||||
}
|
||||
this.packetParser.execute(data);
|
||||
});
|
||||
this.stream.on('close', () => {
|
||||
// we need to set this flag everywhere where we want connection to close
|
||||
if (this._closing) {
|
||||
return;
|
||||
}
|
||||
if (!this._protocolError) {
|
||||
// no particular error message before disconnect
|
||||
this._protocolError = new Error(
|
||||
'Connection lost: The server closed the connection.'
|
||||
);
|
||||
this._protocolError.fatal = true;
|
||||
this._protocolError.code = 'PROTOCOL_CONNECTION_LOST';
|
||||
}
|
||||
this._notifyError(this._protocolError);
|
||||
});
|
||||
let handshakeCommand;
|
||||
if (!this.config.isServer) {
|
||||
handshakeCommand = new Commands.ClientHandshake(this.config.clientFlags);
|
||||
handshakeCommand.on('end', () => {
|
||||
// this happens when handshake finishes early and first packet is error
|
||||
// and not server hello ( for example, 'Too many connactions' error)
|
||||
if (!handshakeCommand.handshake) {
|
||||
return;
|
||||
}
|
||||
this._handshakePacket = handshakeCommand.handshake;
|
||||
this.threadId = handshakeCommand.handshake.connectionId;
|
||||
this.emit('connect', handshakeCommand.handshake);
|
||||
});
|
||||
handshakeCommand.on('error', err => {
|
||||
this._closing = true;
|
||||
this._notifyError(err);
|
||||
});
|
||||
this.addCommand(handshakeCommand);
|
||||
}
|
||||
// in case there was no initiall handshake but we need to read sting, assume it utf-8
|
||||
// most common example: "Too many connections" error ( packet is sent immediately on connection attempt, we don't know server encoding yet)
|
||||
// will be overwrittedn with actial encoding value as soon as server handshake packet is received
|
||||
this.serverEncoding = 'utf8';
|
||||
if (this.config.connectTimeout) {
|
||||
const timeoutHandler = this._handleTimeoutError.bind(this);
|
||||
this.connectTimeout = Timers.setTimeout(
|
||||
timeoutHandler,
|
||||
this.config.connectTimeout
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
promise(promiseImpl) {
|
||||
const PromiseConnection = require('../promise').PromiseConnection;
|
||||
return new PromiseConnection(this, promiseImpl);
|
||||
}
|
||||
|
||||
_addCommandClosedState(cmd) {
|
||||
const err = new Error(
|
||||
"Can't add new command when connection is in closed state"
|
||||
);
|
||||
err.fatal = true;
|
||||
if (cmd.onResult) {
|
||||
cmd.onResult(err);
|
||||
} else {
|
||||
this.emit('error', err);
|
||||
}
|
||||
}
|
||||
|
||||
_handleFatalError(err) {
|
||||
err.fatal = true;
|
||||
// stop receiving packets
|
||||
this.stream.removeAllListeners('data');
|
||||
this.addCommand = this._addCommandClosedState;
|
||||
this.write = () => {
|
||||
this.emit('error', new Error("Can't write in closed state"));
|
||||
};
|
||||
this._notifyError(err);
|
||||
this._fatalError = err;
|
||||
}
|
||||
|
||||
_handleNetworkError(err) {
|
||||
if (this.connectTimeout) {
|
||||
Timers.clearTimeout(this.connectTimeout);
|
||||
this.connectTimeout = null;
|
||||
}
|
||||
// Do not throw an error when a connection ends with a RST,ACK packet
|
||||
if (err.errno === 'ECONNRESET' && this._closing) {
|
||||
return;
|
||||
}
|
||||
this._handleFatalError(err);
|
||||
}
|
||||
|
||||
_handleTimeoutError() {
|
||||
if (this.connectTimeout) {
|
||||
Timers.clearTimeout(this.connectTimeout);
|
||||
this.connectTimeout = null;
|
||||
}
|
||||
this.stream.destroy && this.stream.destroy();
|
||||
const err = new Error('connect ETIMEDOUT');
|
||||
err.errorno = 'ETIMEDOUT';
|
||||
err.code = 'ETIMEDOUT';
|
||||
err.syscall = 'connect';
|
||||
this._handleNetworkError(err);
|
||||
}
|
||||
|
||||
// notify all commands in the queue and bubble error as connection "error"
|
||||
// called on stream error or unexpected termination
|
||||
_notifyError(err) {
|
||||
if (this.connectTimeout) {
|
||||
Timers.clearTimeout(this.connectTimeout);
|
||||
this.connectTimeout = null;
|
||||
}
|
||||
// prevent from emitting 'PROTOCOL_CONNECTION_LOST' after EPIPE or ECONNRESET
|
||||
if (this._fatalError) {
|
||||
return;
|
||||
}
|
||||
let command;
|
||||
// if there is no active command, notify connection
|
||||
// if there are commands and all of them have callbacks, pass error via callback
|
||||
let bubbleErrorToConnection = !this._command;
|
||||
if (this._command && this._command.onResult) {
|
||||
this._command.onResult(err);
|
||||
this._command = null;
|
||||
// connection handshake is special because we allow it to be implicit
|
||||
// if error happened during handshake, but there are others commands in queue
|
||||
// then bubble error to other commands and not to connection
|
||||
} else if (
|
||||
!(
|
||||
this._command &&
|
||||
this._command.constructor === Commands.ClientHandshake &&
|
||||
this._commands.length > 0
|
||||
)
|
||||
) {
|
||||
bubbleErrorToConnection = true;
|
||||
}
|
||||
while ((command = this._commands.shift())) {
|
||||
if (command.onResult) {
|
||||
command.onResult(err);
|
||||
} else {
|
||||
bubbleErrorToConnection = true;
|
||||
}
|
||||
}
|
||||
// notify connection if some comands in the queue did not have callbacks
|
||||
// or if this is pool connection ( so it can be removed from pool )
|
||||
if (bubbleErrorToConnection || this._pool) {
|
||||
this.emit('error', err);
|
||||
}
|
||||
}
|
||||
|
||||
write(buffer) {
|
||||
const result = this.stream.write(buffer, err => {
|
||||
if (err) {
|
||||
this._handleNetworkError(err);
|
||||
}
|
||||
});
|
||||
|
||||
if (!result) {
|
||||
this.stream.emit('pause');
|
||||
}
|
||||
}
|
||||
|
||||
// http://dev.mysql.com/doc/internals/en/sequence-id.html
|
||||
//
|
||||
// The sequence-id is incremented with each packet and may wrap around.
|
||||
// It starts at 0 and is reset to 0 when a new command
|
||||
// begins in the Command Phase.
|
||||
// http://dev.mysql.com/doc/internals/en/example-several-mysql-packets.html
|
||||
_resetSequenceId() {
|
||||
this.sequenceId = 0;
|
||||
this.compressedSequenceId = 0;
|
||||
}
|
||||
|
||||
_bumpCompressedSequenceId(numPackets) {
|
||||
this.compressedSequenceId += numPackets;
|
||||
this.compressedSequenceId %= 256;
|
||||
}
|
||||
|
||||
_bumpSequenceId(numPackets) {
|
||||
this.sequenceId += numPackets;
|
||||
this.sequenceId %= 256;
|
||||
}
|
||||
|
||||
writePacket(packet) {
|
||||
const MAX_PACKET_LENGTH = 16777215;
|
||||
const length = packet.length();
|
||||
let chunk, offset, header;
|
||||
if (length < MAX_PACKET_LENGTH) {
|
||||
packet.writeHeader(this.sequenceId);
|
||||
if (this.config.debug) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(
|
||||
`${this._internalId} ${this.connectionId} <== ${this._command._commandName}#${this._command.stateName()}(${[this.sequenceId, packet._name, packet.length()].join(',')})`
|
||||
);
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(
|
||||
`${this._internalId} ${this.connectionId} <== ${packet.buffer.toString('hex')}`
|
||||
);
|
||||
}
|
||||
this._bumpSequenceId(1);
|
||||
this.write(packet.buffer);
|
||||
} else {
|
||||
if (this.config.debug) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(
|
||||
`${this._internalId} ${this.connectionId} <== Writing large packet, raw content not written:`
|
||||
);
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(
|
||||
`${this._internalId} ${this.connectionId} <== ${this._command._commandName}#${this._command.stateName()}(${[this.sequenceId, packet._name, packet.length()].join(',')})`
|
||||
);
|
||||
}
|
||||
for (offset = 4; offset < 4 + length; offset += MAX_PACKET_LENGTH) {
|
||||
chunk = packet.buffer.slice(offset, offset + MAX_PACKET_LENGTH);
|
||||
if (chunk.length === MAX_PACKET_LENGTH) {
|
||||
header = Buffer.from([0xff, 0xff, 0xff, this.sequenceId]);
|
||||
} else {
|
||||
header = Buffer.from([
|
||||
chunk.length & 0xff,
|
||||
(chunk.length >> 8) & 0xff,
|
||||
(chunk.length >> 16) & 0xff,
|
||||
this.sequenceId
|
||||
]);
|
||||
}
|
||||
this._bumpSequenceId(1);
|
||||
this.write(header);
|
||||
this.write(chunk);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 0.11+ environment
|
||||
startTLS(onSecure) {
|
||||
if (this.config.debug) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('Upgrading connection to TLS');
|
||||
}
|
||||
const secureContext = Tls.createSecureContext({
|
||||
ca: this.config.ssl.ca,
|
||||
cert: this.config.ssl.cert,
|
||||
ciphers: this.config.ssl.ciphers,
|
||||
key: this.config.ssl.key,
|
||||
passphrase: this.config.ssl.passphrase,
|
||||
minVersion: this.config.ssl.minVersion
|
||||
});
|
||||
const rejectUnauthorized = this.config.ssl.rejectUnauthorized;
|
||||
let secureEstablished = false;
|
||||
const secureSocket = new Tls.TLSSocket(this.stream, {
|
||||
rejectUnauthorized: rejectUnauthorized,
|
||||
requestCert: true,
|
||||
secureContext: secureContext,
|
||||
isServer: false
|
||||
});
|
||||
// error handler for secure socket
|
||||
secureSocket.on('_tlsError', err => {
|
||||
if (secureEstablished) {
|
||||
this._handleNetworkError(err);
|
||||
} else {
|
||||
onSecure(err);
|
||||
}
|
||||
});
|
||||
secureSocket.on('secure', () => {
|
||||
secureEstablished = true;
|
||||
onSecure(rejectUnauthorized ? secureSocket.ssl.verifyError() : null);
|
||||
});
|
||||
secureSocket.on('data', data => {
|
||||
this.packetParser.execute(data);
|
||||
});
|
||||
this.write = buffer => {
|
||||
secureSocket.write(buffer);
|
||||
};
|
||||
// start TLS communications
|
||||
secureSocket._start();
|
||||
}
|
||||
|
||||
pipe() {
|
||||
if (this.stream instanceof Net.Stream) {
|
||||
this.stream.ondata = (data, start, end) => {
|
||||
this.packetParser.execute(data, start, end);
|
||||
};
|
||||
} else {
|
||||
this.stream.on('data', data => {
|
||||
this.packetParser.execute(
|
||||
data.parent,
|
||||
data.offset,
|
||||
data.offset + data.length
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
protocolError(message, code) {
|
||||
const err = new Error(message);
|
||||
err.fatal = true;
|
||||
err.code = code || 'PROTOCOL_ERROR';
|
||||
this.emit('error', err);
|
||||
}
|
||||
|
||||
handlePacket(packet) {
|
||||
if (this._paused) {
|
||||
this._paused_packets.push(packet);
|
||||
return;
|
||||
}
|
||||
if (packet) {
|
||||
if (this.sequenceId !== packet.sequenceId) {
|
||||
const err = new Error(
|
||||
`Warning: got packets out of order. Expected ${this.sequenceId} but received ${packet.sequenceId}`
|
||||
);
|
||||
err.expected = this.sequenceId;
|
||||
err.received = packet.sequenceId;
|
||||
this.emit('warn', err); // REVIEW
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(err.message);
|
||||
}
|
||||
this._bumpSequenceId(packet.numPackets);
|
||||
}
|
||||
if (this.config.debug) {
|
||||
if (packet) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(
|
||||
` raw: ${packet.buffer
|
||||
.slice(packet.offset, packet.offset + packet.length())
|
||||
.toString('hex')}`
|
||||
);
|
||||
// eslint-disable-next-line no-console
|
||||
console.trace();
|
||||
const commandName = this._command
|
||||
? this._command._commandName
|
||||
: '(no command)';
|
||||
const stateName = this._command
|
||||
? this._command.stateName()
|
||||
: '(no command)';
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(
|
||||
`${this._internalId} ${this.connectionId} ==> ${commandName}#${stateName}(${[packet.sequenceId, packet.type(), packet.length()].join(',')})`
|
||||
);
|
||||
}
|
||||
}
|
||||
if (!this._command) {
|
||||
this.protocolError(
|
||||
'Unexpected packet while no commands in the queue',
|
||||
'PROTOCOL_UNEXPECTED_PACKET'
|
||||
);
|
||||
this.close();
|
||||
return;
|
||||
}
|
||||
const done = this._command.execute(packet, this);
|
||||
if (done) {
|
||||
this._command = this._commands.shift();
|
||||
if (this._command) {
|
||||
this.sequenceId = 0;
|
||||
this.compressedSequenceId = 0;
|
||||
this.handlePacket();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addCommand(cmd) {
|
||||
// this.compressedSequenceId = 0;
|
||||
// this.sequenceId = 0;
|
||||
if (this.config.debug) {
|
||||
const commandName = cmd.constructor.name;
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(`Add command: ${commandName}`);
|
||||
cmd._commandName = commandName;
|
||||
}
|
||||
if (!this._command) {
|
||||
this._command = cmd;
|
||||
this.handlePacket();
|
||||
} else {
|
||||
this._commands.push(cmd);
|
||||
}
|
||||
return cmd;
|
||||
}
|
||||
|
||||
format(sql, values) {
|
||||
if (typeof this.config.queryFormat === 'function') {
|
||||
return this.config.queryFormat.call(
|
||||
this,
|
||||
sql,
|
||||
values,
|
||||
this.config.timezone
|
||||
);
|
||||
}
|
||||
const opts = {
|
||||
sql: sql,
|
||||
values: values
|
||||
};
|
||||
this._resolveNamedPlaceholders(opts);
|
||||
return SqlString.format(
|
||||
opts.sql,
|
||||
opts.values,
|
||||
this.config.stringifyObjects,
|
||||
this.config.timezone
|
||||
);
|
||||
}
|
||||
|
||||
escape(value) {
|
||||
return SqlString.escape(value, false, this.config.timezone);
|
||||
}
|
||||
|
||||
escapeId(value) {
|
||||
return SqlString.escapeId(value, false);
|
||||
}
|
||||
|
||||
raw(sql) {
|
||||
return SqlString.raw(sql);
|
||||
}
|
||||
|
||||
_resolveNamedPlaceholders(options) {
|
||||
let unnamed;
|
||||
if (this.config.namedPlaceholders || options.namedPlaceholders) {
|
||||
if (convertNamedPlaceholders === null) {
|
||||
convertNamedPlaceholders = require('named-placeholders')();
|
||||
}
|
||||
unnamed = convertNamedPlaceholders(options.sql, options.values);
|
||||
options.sql = unnamed[0];
|
||||
options.values = unnamed[1];
|
||||
}
|
||||
}
|
||||
|
||||
query(sql, values, cb) {
|
||||
let cmdQuery;
|
||||
if (sql.constructor === Commands.Query) {
|
||||
cmdQuery = sql;
|
||||
} else {
|
||||
cmdQuery = Connection.createQuery(sql, values, cb, this.config);
|
||||
}
|
||||
this._resolveNamedPlaceholders(cmdQuery);
|
||||
const rawSql = this.format(cmdQuery.sql, cmdQuery.values !== undefined ? cmdQuery.values : []);
|
||||
cmdQuery.sql = rawSql;
|
||||
return this.addCommand(cmdQuery);
|
||||
}
|
||||
|
||||
pause() {
|
||||
this._paused = true;
|
||||
this.stream.pause();
|
||||
}
|
||||
|
||||
resume() {
|
||||
let packet;
|
||||
this._paused = false;
|
||||
while ((packet = this._paused_packets.shift())) {
|
||||
this.handlePacket(packet);
|
||||
// don't resume if packet hander paused connection
|
||||
if (this._paused) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.stream.resume();
|
||||
}
|
||||
|
||||
// TODO: named placeholders support
|
||||
prepare(options, cb) {
|
||||
if (typeof options === 'string') {
|
||||
options = { sql: options };
|
||||
}
|
||||
return this.addCommand(new Commands.Prepare(options, cb));
|
||||
}
|
||||
|
||||
unprepare(sql) {
|
||||
let options = {};
|
||||
if (typeof sql === 'object') {
|
||||
options = sql;
|
||||
} else {
|
||||
options.sql = sql;
|
||||
}
|
||||
const key = Connection.statementKey(options);
|
||||
const stmt = this._statements.get(key);
|
||||
if (stmt) {
|
||||
this._statements.del(key);
|
||||
stmt.close();
|
||||
}
|
||||
return stmt;
|
||||
}
|
||||
|
||||
execute(sql, values, cb) {
|
||||
let options = {};
|
||||
if (typeof sql === 'object') {
|
||||
// execute(options, cb)
|
||||
options = sql;
|
||||
if (typeof values === 'function') {
|
||||
cb = values;
|
||||
} else {
|
||||
options.values = options.values || values;
|
||||
}
|
||||
} else if (typeof values === 'function') {
|
||||
// execute(sql, cb)
|
||||
cb = values;
|
||||
options.sql = sql;
|
||||
options.values = undefined;
|
||||
} else {
|
||||
// execute(sql, values, cb)
|
||||
options.sql = sql;
|
||||
options.values = values;
|
||||
}
|
||||
this._resolveNamedPlaceholders(options);
|
||||
// check for values containing undefined
|
||||
if (options.values) {
|
||||
//If namedPlaceholder is not enabled and object is passed as bind parameters
|
||||
if (!Array.isArray(options.values)) {
|
||||
throw new TypeError(
|
||||
'Bind parameters must be array if namedPlaceholders parameter is not enabled'
|
||||
);
|
||||
}
|
||||
options.values.forEach(val => {
|
||||
//If namedPlaceholder is not enabled and object is passed as bind parameters
|
||||
if (!Array.isArray(options.values)) {
|
||||
throw new TypeError(
|
||||
'Bind parameters must be array if namedPlaceholders parameter is not enabled'
|
||||
);
|
||||
}
|
||||
if (val === undefined) {
|
||||
throw new TypeError(
|
||||
'Bind parameters must not contain undefined. To pass SQL NULL specify JS null'
|
||||
);
|
||||
}
|
||||
if (typeof val === 'function') {
|
||||
throw new TypeError(
|
||||
'Bind parameters must not contain function(s). To pass the body of a function as a string call .toString() first'
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
const executeCommand = new Commands.Execute(options, cb);
|
||||
const prepareCommand = new Commands.Prepare(options, (err, stmt) => {
|
||||
if (err) {
|
||||
// skip execute command if prepare failed, we have main
|
||||
// combined callback here
|
||||
executeCommand.start = function() {
|
||||
return null;
|
||||
};
|
||||
if (cb) {
|
||||
cb(err);
|
||||
} else {
|
||||
executeCommand.emit('error', err);
|
||||
}
|
||||
executeCommand.emit('end');
|
||||
return;
|
||||
}
|
||||
executeCommand.statement = stmt;
|
||||
});
|
||||
this.addCommand(prepareCommand);
|
||||
this.addCommand(executeCommand);
|
||||
return executeCommand;
|
||||
}
|
||||
|
||||
changeUser(options, callback) {
|
||||
if (!callback && typeof options === 'function') {
|
||||
callback = options;
|
||||
options = {};
|
||||
}
|
||||
const charsetNumber = options.charset
|
||||
? ConnectionConfig.getCharsetNumber(options.charset)
|
||||
: this.config.charsetNumber;
|
||||
return this.addCommand(
|
||||
new Commands.ChangeUser(
|
||||
{
|
||||
user: options.user || this.config.user,
|
||||
password: options.password || this.config.password,
|
||||
passwordSha1: options.passwordSha1 || this.config.passwordSha1,
|
||||
database: options.database || this.config.database,
|
||||
timeout: options.timeout,
|
||||
charsetNumber: charsetNumber,
|
||||
currentConfig: this.config
|
||||
},
|
||||
err => {
|
||||
if (err) {
|
||||
err.fatal = true;
|
||||
}
|
||||
if (callback) {
|
||||
callback(err);
|
||||
}
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// transaction helpers
|
||||
beginTransaction(cb) {
|
||||
return this.query('START TRANSACTION', cb);
|
||||
}
|
||||
|
||||
commit(cb) {
|
||||
return this.query('COMMIT', cb);
|
||||
}
|
||||
|
||||
rollback(cb) {
|
||||
return this.query('ROLLBACK', cb);
|
||||
}
|
||||
|
||||
ping(cb) {
|
||||
return this.addCommand(new Commands.Ping(cb));
|
||||
}
|
||||
|
||||
_registerSlave(opts, cb) {
|
||||
return this.addCommand(new Commands.RegisterSlave(opts, cb));
|
||||
}
|
||||
|
||||
_binlogDump(opts, cb) {
|
||||
return this.addCommand(new Commands.BinlogDump(opts, cb));
|
||||
}
|
||||
|
||||
// currently just alias to close
|
||||
destroy() {
|
||||
this.close();
|
||||
}
|
||||
|
||||
close() {
|
||||
if (this.connectTimeout) {
|
||||
Timers.clearTimeout(this.connectTimeout);
|
||||
this.connectTimeout = null;
|
||||
}
|
||||
this._closing = true;
|
||||
this.stream.end();
|
||||
this.addCommand = this._addCommandClosedState;
|
||||
}
|
||||
|
||||
createBinlogStream(opts) {
|
||||
// TODO: create proper stream class
|
||||
// TODO: use through2
|
||||
let test = 1;
|
||||
const stream = new Readable({ objectMode: true });
|
||||
stream._read = function() {
|
||||
return {
|
||||
data: test++
|
||||
};
|
||||
};
|
||||
this._registerSlave(opts, () => {
|
||||
const dumpCmd = this._binlogDump(opts);
|
||||
dumpCmd.on('event', ev => {
|
||||
stream.push(ev);
|
||||
});
|
||||
dumpCmd.on('eof', () => {
|
||||
stream.push(null);
|
||||
// if non-blocking, then close stream to prevent errors
|
||||
if (opts.flags && opts.flags & 0x01) {
|
||||
this.close();
|
||||
}
|
||||
});
|
||||
// TODO: pipe errors as well
|
||||
});
|
||||
return stream;
|
||||
}
|
||||
|
||||
connect(cb) {
|
||||
if (!cb) {
|
||||
return;
|
||||
}
|
||||
if (this._fatalError || this._protocolError) {
|
||||
return cb(this._fatalError || this._protocolError);
|
||||
}
|
||||
if (this._handshakePacket) {
|
||||
return cb(null, this);
|
||||
}
|
||||
let connectCalled = 0;
|
||||
function callbackOnce(isErrorHandler) {
|
||||
return function(param) {
|
||||
if (!connectCalled) {
|
||||
if (isErrorHandler) {
|
||||
cb(param);
|
||||
} else {
|
||||
cb(null, param);
|
||||
}
|
||||
}
|
||||
connectCalled = 1;
|
||||
};
|
||||
}
|
||||
this.once('error', callbackOnce(true));
|
||||
this.once('connect', callbackOnce(false));
|
||||
}
|
||||
|
||||
// ===================================
|
||||
// outgoing server connection methods
|
||||
// ===================================
|
||||
writeColumns(columns) {
|
||||
this.writePacket(Packets.ResultSetHeader.toPacket(columns.length));
|
||||
columns.forEach(column => {
|
||||
this.writePacket(
|
||||
Packets.ColumnDefinition.toPacket(column, this.serverConfig.encoding)
|
||||
);
|
||||
});
|
||||
this.writeEof();
|
||||
}
|
||||
|
||||
// row is array of columns, not hash
|
||||
writeTextRow(column) {
|
||||
this.writePacket(
|
||||
Packets.TextRow.toPacket(column, this.serverConfig.encoding)
|
||||
);
|
||||
}
|
||||
|
||||
writeTextResult(rows, columns) {
|
||||
this.writeColumns(columns);
|
||||
rows.forEach(row => {
|
||||
const arrayRow = new Array(columns.length);
|
||||
columns.forEach(column => {
|
||||
arrayRow.push(row[column.name]);
|
||||
});
|
||||
this.writeTextRow(arrayRow);
|
||||
});
|
||||
this.writeEof();
|
||||
}
|
||||
|
||||
writeEof(warnings, statusFlags) {
|
||||
this.writePacket(Packets.EOF.toPacket(warnings, statusFlags));
|
||||
}
|
||||
|
||||
writeOk(args) {
|
||||
if (!args) {
|
||||
args = { affectedRows: 0 };
|
||||
}
|
||||
this.writePacket(Packets.OK.toPacket(args, this.serverConfig.encoding));
|
||||
}
|
||||
|
||||
writeError(args) {
|
||||
// if we want to send error before initial hello was sent, use default encoding
|
||||
const encoding = this.serverConfig ? this.serverConfig.encoding : 'cesu8';
|
||||
this.writePacket(Packets.Error.toPacket(args, encoding));
|
||||
}
|
||||
|
||||
serverHandshake(args) {
|
||||
this.serverConfig = args;
|
||||
this.serverConfig.encoding =
|
||||
CharsetToEncoding[this.serverConfig.characterSet];
|
||||
return this.addCommand(new Commands.ServerHandshake(args));
|
||||
}
|
||||
|
||||
// ===============================================================
|
||||
end(callback) {
|
||||
if (this.config.isServer) {
|
||||
this._closing = true;
|
||||
const quitCmd = new EventEmitter();
|
||||
setImmediate(() => {
|
||||
this.stream.end();
|
||||
quitCmd.emit('end');
|
||||
});
|
||||
return quitCmd;
|
||||
}
|
||||
// trigger error if more commands enqueued after end command
|
||||
const quitCmd = this.addCommand(new Commands.Quit(callback));
|
||||
this.addCommand = this._addCommandClosedState;
|
||||
return quitCmd;
|
||||
}
|
||||
|
||||
static createQuery(sql, values, cb, config) {
|
||||
let options = {
|
||||
rowsAsArray: config.rowsAsArray
|
||||
};
|
||||
if (typeof sql === 'object') {
|
||||
// query(options, cb)
|
||||
options = sql;
|
||||
if (typeof values === 'function') {
|
||||
cb = values;
|
||||
} else if (values !== undefined) {
|
||||
options.values = values;
|
||||
}
|
||||
} else if (typeof values === 'function') {
|
||||
// query(sql, cb)
|
||||
cb = values;
|
||||
options.sql = sql;
|
||||
options.values = undefined;
|
||||
} else {
|
||||
// query(sql, values, cb)
|
||||
options.sql = sql;
|
||||
options.values = values;
|
||||
}
|
||||
return new Commands.Query(options, cb);
|
||||
}
|
||||
|
||||
static statementKey(options) {
|
||||
return (
|
||||
`${typeof options.nestTables}/${options.nestTables}/${options.rowsAsArray}${options.sql}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (Tls.TLSSocket) {
|
||||
// not supported
|
||||
} else {
|
||||
Connection.prototype.startTLS = function _startTLS(onSecure) {
|
||||
if (this.config.debug) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('Upgrading connection to TLS');
|
||||
}
|
||||
const crypto = require('crypto');
|
||||
const config = this.config;
|
||||
const stream = this.stream;
|
||||
const rejectUnauthorized = this.config.ssl.rejectUnauthorized;
|
||||
const credentials = crypto.createCredentials({
|
||||
key: config.ssl.key,
|
||||
cert: config.ssl.cert,
|
||||
passphrase: config.ssl.passphrase,
|
||||
ca: config.ssl.ca,
|
||||
ciphers: config.ssl.ciphers
|
||||
});
|
||||
const securePair = Tls.createSecurePair(
|
||||
credentials,
|
||||
false,
|
||||
true,
|
||||
rejectUnauthorized
|
||||
);
|
||||
|
||||
if (stream.ondata) {
|
||||
stream.ondata = null;
|
||||
}
|
||||
stream.removeAllListeners('data');
|
||||
stream.pipe(securePair.encrypted);
|
||||
securePair.encrypted.pipe(stream);
|
||||
securePair.cleartext.on('data', data => {
|
||||
this.packetParser.execute(data);
|
||||
});
|
||||
this.write = function(buffer) {
|
||||
securePair.cleartext.write(buffer);
|
||||
};
|
||||
securePair.on('secure', () => {
|
||||
onSecure(rejectUnauthorized ? securePair.ssl.verifyError() : null);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = Connection;
|
262
node_modules/mysql2/lib/connection_config.js
generated
vendored
Normal file
262
node_modules/mysql2/lib/connection_config.js
generated
vendored
Normal file
@ -0,0 +1,262 @@
|
||||
'use strict';
|
||||
|
||||
const urlParse = require('url').parse;
|
||||
const ClientConstants = require('./constants/client');
|
||||
const Charsets = require('./constants/charsets');
|
||||
let SSLProfiles = null;
|
||||
|
||||
const validOptions = {
|
||||
authPlugins: 1,
|
||||
authSwitchHandler: 1,
|
||||
bigNumberStrings: 1,
|
||||
charset: 1,
|
||||
charsetNumber: 1,
|
||||
compress: 1,
|
||||
connectAttributes: 1,
|
||||
connectTimeout: 1,
|
||||
database: 1,
|
||||
dateStrings: 1,
|
||||
debug: 1,
|
||||
decimalNumbers: 1,
|
||||
enableKeepAlive: 1,
|
||||
flags: 1,
|
||||
host: 1,
|
||||
insecureAuth: 1,
|
||||
isServer: 1,
|
||||
keepAliveInitialDelay: 1,
|
||||
localAddress: 1,
|
||||
maxPreparedStatements: 1,
|
||||
multipleStatements: 1,
|
||||
namedPlaceholders: 1,
|
||||
nestTables: 1,
|
||||
password: 1,
|
||||
passwordSha1: 1,
|
||||
pool: 1,
|
||||
port: 1,
|
||||
queryFormat: 1,
|
||||
rowsAsArray: 1,
|
||||
socketPath: 1,
|
||||
ssl: 1,
|
||||
stream: 1,
|
||||
stringifyObjects: 1,
|
||||
supportBigNumbers: 1,
|
||||
timezone: 1,
|
||||
trace: 1,
|
||||
typeCast: 1,
|
||||
uri: 1,
|
||||
user: 1,
|
||||
// These options are used for Pool
|
||||
connectionLimit: 1,
|
||||
Promise: 1,
|
||||
queueLimit: 1,
|
||||
waitForConnections: 1
|
||||
};
|
||||
|
||||
class ConnectionConfig {
|
||||
constructor(options) {
|
||||
if (typeof options === 'string') {
|
||||
options = ConnectionConfig.parseUrl(options);
|
||||
} else if (options && options.uri) {
|
||||
const uriOptions = ConnectionConfig.parseUrl(options.uri);
|
||||
for (const key in uriOptions) {
|
||||
if (!Object.prototype.hasOwnProperty.call(uriOptions, key)) continue;
|
||||
if (options[key]) continue;
|
||||
options[key] = uriOptions[key];
|
||||
}
|
||||
}
|
||||
for (const key in options) {
|
||||
if (!Object.prototype.hasOwnProperty.call(options, key)) continue;
|
||||
if (validOptions[key] !== 1) {
|
||||
// REVIEW: Should this be emitted somehow?
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(
|
||||
`Ignoring invalid configuration option passed to Connection: ${key}. This is currently a warning, but in future versions of MySQL2, an error will be thrown if you pass an invalid configuration option to a Connection`
|
||||
);
|
||||
}
|
||||
}
|
||||
this.isServer = options.isServer;
|
||||
this.stream = options.stream;
|
||||
this.host = options.host || 'localhost';
|
||||
this.port = options.port || 3306;
|
||||
this.localAddress = options.localAddress;
|
||||
this.socketPath = options.socketPath;
|
||||
this.user = options.user || undefined;
|
||||
this.password = options.password || undefined;
|
||||
this.passwordSha1 = options.passwordSha1 || undefined;
|
||||
this.database = options.database;
|
||||
this.connectTimeout = isNaN(options.connectTimeout)
|
||||
? 10 * 1000
|
||||
: options.connectTimeout;
|
||||
this.insecureAuth = options.insecureAuth || false;
|
||||
this.supportBigNumbers = options.supportBigNumbers || false;
|
||||
this.bigNumberStrings = options.bigNumberStrings || false;
|
||||
this.decimalNumbers = options.decimalNumbers || false;
|
||||
this.dateStrings = options.dateStrings || false;
|
||||
this.debug = options.debug;
|
||||
this.trace = options.trace !== false;
|
||||
this.stringifyObjects = options.stringifyObjects || false;
|
||||
this.enableKeepAlive = !!options.enableKeepAlive;
|
||||
this.keepAliveInitialDelay = options.keepAliveInitialDelay || 0;
|
||||
if (
|
||||
options.timezone &&
|
||||
!/^(?:local|Z|[ +-]\d\d:\d\d)$/.test(options.timezone)
|
||||
) {
|
||||
// strictly supports timezones specified by mysqljs/mysql:
|
||||
// https://github.com/mysqljs/mysql#user-content-connection-options
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(
|
||||
`Ignoring invalid timezone passed to Connection: ${options.timezone}. This is currently a warning, but in future versions of MySQL2, an error will be thrown if you pass an invalid configuration option to a Connection`
|
||||
);
|
||||
// SqlStrings falls back to UTC on invalid timezone
|
||||
this.timezone = 'Z';
|
||||
} else {
|
||||
this.timezone = options.timezone || 'local';
|
||||
}
|
||||
this.queryFormat = options.queryFormat;
|
||||
this.pool = options.pool || undefined;
|
||||
this.ssl =
|
||||
typeof options.ssl === 'string'
|
||||
? ConnectionConfig.getSSLProfile(options.ssl)
|
||||
: options.ssl || false;
|
||||
this.multipleStatements = options.multipleStatements || false;
|
||||
this.rowsAsArray = options.rowsAsArray || false;
|
||||
this.namedPlaceholders = options.namedPlaceholders || false;
|
||||
this.nestTables =
|
||||
options.nestTables === undefined ? undefined : options.nestTables;
|
||||
this.typeCast = options.typeCast === undefined ? true : options.typeCast;
|
||||
if (this.timezone[0] === ' ') {
|
||||
// "+" is a url encoded char for space so it
|
||||
// gets translated to space when giving a
|
||||
// connection string..
|
||||
this.timezone = `+${this.timezone.substr(1)}`;
|
||||
}
|
||||
if (this.ssl) {
|
||||
if (typeof this.ssl !== 'object') {
|
||||
throw new TypeError(
|
||||
`SSL profile must be an object, instead it's a ${typeof this.ssl}`
|
||||
);
|
||||
}
|
||||
// Default rejectUnauthorized to true
|
||||
this.ssl.rejectUnauthorized = this.ssl.rejectUnauthorized !== false;
|
||||
}
|
||||
this.maxPacketSize = 0;
|
||||
this.charsetNumber = options.charset
|
||||
? ConnectionConfig.getCharsetNumber(options.charset)
|
||||
: options.charsetNumber || Charsets.UTF8MB4_UNICODE_CI;
|
||||
this.compress = options.compress || false;
|
||||
this.authPlugins = options.authPlugins;
|
||||
this.authSwitchHandler = options.authSwitchHandler;
|
||||
this.clientFlags = ConnectionConfig.mergeFlags(
|
||||
ConnectionConfig.getDefaultFlags(options),
|
||||
options.flags || ''
|
||||
);
|
||||
this.connectAttributes = options.connectAttributes;
|
||||
this.maxPreparedStatements = options.maxPreparedStatements || 16000;
|
||||
}
|
||||
|
||||
static mergeFlags(default_flags, user_flags) {
|
||||
let flags = 0x0,
|
||||
i;
|
||||
if (!Array.isArray(user_flags)) {
|
||||
user_flags = String(user_flags || '')
|
||||
.toUpperCase()
|
||||
.split(/\s*,+\s*/);
|
||||
}
|
||||
// add default flags unless "blacklisted"
|
||||
for (i in default_flags) {
|
||||
if (user_flags.indexOf(`-${default_flags[i]}`) >= 0) {
|
||||
continue;
|
||||
}
|
||||
flags |= ClientConstants[default_flags[i]] || 0x0;
|
||||
}
|
||||
// add user flags unless already already added
|
||||
for (i in user_flags) {
|
||||
if (user_flags[i][0] === '-') {
|
||||
continue;
|
||||
}
|
||||
if (default_flags.indexOf(user_flags[i]) >= 0) {
|
||||
continue;
|
||||
}
|
||||
flags |= ClientConstants[user_flags[i]] || 0x0;
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
|
||||
static getDefaultFlags(options) {
|
||||
const defaultFlags = [
|
||||
'LONG_PASSWORD',
|
||||
'FOUND_ROWS',
|
||||
'LONG_FLAG',
|
||||
'CONNECT_WITH_DB',
|
||||
'ODBC',
|
||||
'LOCAL_FILES',
|
||||
'IGNORE_SPACE',
|
||||
'PROTOCOL_41',
|
||||
'IGNORE_SIGPIPE',
|
||||
'TRANSACTIONS',
|
||||
'RESERVED',
|
||||
'SECURE_CONNECTION',
|
||||
'MULTI_RESULTS',
|
||||
'TRANSACTIONS',
|
||||
'SESSION_TRACK'
|
||||
];
|
||||
if (options && options.multipleStatements) {
|
||||
defaultFlags.push('MULTI_STATEMENTS');
|
||||
}
|
||||
defaultFlags.push('PLUGIN_AUTH');
|
||||
defaultFlags.push('PLUGIN_AUTH_LENENC_CLIENT_DATA');
|
||||
|
||||
if (options && options.connectAttributes) {
|
||||
defaultFlags.push('CONNECT_ATTRS');
|
||||
}
|
||||
return defaultFlags;
|
||||
}
|
||||
|
||||
static getCharsetNumber(charset) {
|
||||
const num = Charsets[charset.toUpperCase()];
|
||||
if (num === undefined) {
|
||||
throw new TypeError(`Unknown charset '${charset}'`);
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
static getSSLProfile(name) {
|
||||
if (!SSLProfiles) {
|
||||
SSLProfiles = require('./constants/ssl_profiles.js');
|
||||
}
|
||||
const ssl = SSLProfiles[name];
|
||||
if (ssl === undefined) {
|
||||
throw new TypeError(`Unknown SSL profile '${name}'`);
|
||||
}
|
||||
return ssl;
|
||||
}
|
||||
|
||||
static parseUrl(url) {
|
||||
url = urlParse(url, true);
|
||||
const options = {
|
||||
host: url.hostname,
|
||||
port: url.port,
|
||||
database: url.pathname.substr(1)
|
||||
};
|
||||
if (url.auth) {
|
||||
const auth = url.auth.split(':');
|
||||
options.user = auth[0];
|
||||
options.password = auth[1];
|
||||
}
|
||||
if (url.query) {
|
||||
for (const key in url.query) {
|
||||
const value = url.query[key];
|
||||
try {
|
||||
// Try to parse this as a JSON expression first
|
||||
options[key] = JSON.parse(value);
|
||||
} catch (err) {
|
||||
// Otherwise assume it is a plain string
|
||||
options[key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
return options;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ConnectionConfig;
|
313
node_modules/mysql2/lib/constants/charset_encodings.js
generated
vendored
Normal file
313
node_modules/mysql2/lib/constants/charset_encodings.js
generated
vendored
Normal file
@ -0,0 +1,313 @@
|
||||
'use strict';
|
||||
|
||||
// see tools/generate-charset-mapping.js
|
||||
// basicalliy result of "SHOW COLLATION" query
|
||||
|
||||
module.exports = [
|
||||
'utf8',
|
||||
'big5',
|
||||
'latin2',
|
||||
'dec8',
|
||||
'cp850',
|
||||
'latin1',
|
||||
'hp8',
|
||||
'koi8r',
|
||||
'latin1',
|
||||
'latin2',
|
||||
'swe7',
|
||||
'ascii',
|
||||
'eucjp',
|
||||
'sjis',
|
||||
'cp1251',
|
||||
'latin1',
|
||||
'hebrew',
|
||||
'utf8',
|
||||
'tis620',
|
||||
'euckr',
|
||||
'latin7',
|
||||
'latin2',
|
||||
'koi8u',
|
||||
'cp1251',
|
||||
'gb2312',
|
||||
'greek',
|
||||
'cp1250',
|
||||
'latin2',
|
||||
'gbk',
|
||||
'cp1257',
|
||||
'latin5',
|
||||
'latin1',
|
||||
'armscii8',
|
||||
'cesu8',
|
||||
'cp1250',
|
||||
'ucs2',
|
||||
'cp866',
|
||||
'keybcs2',
|
||||
'macintosh',
|
||||
'macroman',
|
||||
'cp852',
|
||||
'latin7',
|
||||
'latin7',
|
||||
'macintosh',
|
||||
'cp1250',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'latin1',
|
||||
'latin1',
|
||||
'latin1',
|
||||
'cp1251',
|
||||
'cp1251',
|
||||
'cp1251',
|
||||
'macroman',
|
||||
'utf16',
|
||||
'utf16',
|
||||
'utf16-le',
|
||||
'cp1256',
|
||||
'cp1257',
|
||||
'cp1257',
|
||||
'utf32',
|
||||
'utf32',
|
||||
'utf16-le',
|
||||
'binary',
|
||||
'armscii8',
|
||||
'ascii',
|
||||
'cp1250',
|
||||
'cp1256',
|
||||
'cp866',
|
||||
'dec8',
|
||||
'greek',
|
||||
'hebrew',
|
||||
'hp8',
|
||||
'keybcs2',
|
||||
'koi8r',
|
||||
'koi8u',
|
||||
'cesu8',
|
||||
'latin2',
|
||||
'latin5',
|
||||
'latin7',
|
||||
'cp850',
|
||||
'cp852',
|
||||
'swe7',
|
||||
'cesu8',
|
||||
'big5',
|
||||
'euckr',
|
||||
'gb2312',
|
||||
'gbk',
|
||||
'sjis',
|
||||
'tis620',
|
||||
'ucs2',
|
||||
'eucjp',
|
||||
'geostd8',
|
||||
'geostd8',
|
||||
'latin1',
|
||||
'cp932',
|
||||
'cp932',
|
||||
'eucjpms',
|
||||
'eucjpms',
|
||||
'cp1250',
|
||||
'utf8',
|
||||
'utf16',
|
||||
'utf16',
|
||||
'utf16',
|
||||
'utf16',
|
||||
'utf16',
|
||||
'utf16',
|
||||
'utf16',
|
||||
'utf16',
|
||||
'utf16',
|
||||
'utf16',
|
||||
'utf16',
|
||||
'utf16',
|
||||
'utf16',
|
||||
'utf16',
|
||||
'utf16',
|
||||
'utf16',
|
||||
'utf16',
|
||||
'utf16',
|
||||
'utf16',
|
||||
'utf16',
|
||||
'utf16',
|
||||
'utf16',
|
||||
'utf16',
|
||||
'utf16',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'ucs2',
|
||||
'ucs2',
|
||||
'ucs2',
|
||||
'ucs2',
|
||||
'ucs2',
|
||||
'ucs2',
|
||||
'ucs2',
|
||||
'ucs2',
|
||||
'ucs2',
|
||||
'ucs2',
|
||||
'ucs2',
|
||||
'ucs2',
|
||||
'ucs2',
|
||||
'ucs2',
|
||||
'ucs2',
|
||||
'ucs2',
|
||||
'ucs2',
|
||||
'ucs2',
|
||||
'ucs2',
|
||||
'ucs2',
|
||||
'ucs2',
|
||||
'ucs2',
|
||||
'ucs2',
|
||||
'ucs2',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'ucs2',
|
||||
'utf32',
|
||||
'utf32',
|
||||
'utf32',
|
||||
'utf32',
|
||||
'utf32',
|
||||
'utf32',
|
||||
'utf32',
|
||||
'utf32',
|
||||
'utf32',
|
||||
'utf32',
|
||||
'utf32',
|
||||
'utf32',
|
||||
'utf32',
|
||||
'utf32',
|
||||
'utf32',
|
||||
'utf32',
|
||||
'utf32',
|
||||
'utf32',
|
||||
'utf32',
|
||||
'utf32',
|
||||
'utf32',
|
||||
'utf32',
|
||||
'utf32',
|
||||
'utf32',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'cesu8',
|
||||
'cesu8',
|
||||
'cesu8',
|
||||
'cesu8',
|
||||
'cesu8',
|
||||
'cesu8',
|
||||
'cesu8',
|
||||
'cesu8',
|
||||
'cesu8',
|
||||
'cesu8',
|
||||
'cesu8',
|
||||
'cesu8',
|
||||
'cesu8',
|
||||
'cesu8',
|
||||
'cesu8',
|
||||
'cesu8',
|
||||
'cesu8',
|
||||
'cesu8',
|
||||
'cesu8',
|
||||
'cesu8',
|
||||
'cesu8',
|
||||
'cesu8',
|
||||
'cesu8',
|
||||
'cesu8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'cesu8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'gb18030',
|
||||
'gb18030',
|
||||
'gb18030',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8',
|
||||
'utf8'
|
||||
];
|
289
node_modules/mysql2/lib/constants/charsets.js
generated
vendored
Normal file
289
node_modules/mysql2/lib/constants/charsets.js
generated
vendored
Normal file
@ -0,0 +1,289 @@
|
||||
'use strict';
|
||||
|
||||
exports.BIG5_CHINESE_CI = 1;
|
||||
exports.LATIN2_CZECH_CS = 2;
|
||||
exports.DEC8_SWEDISH_CI = 3;
|
||||
exports.CP850_GENERAL_CI = 4;
|
||||
exports.LATIN1_GERMAN1_CI = 5;
|
||||
exports.HP8_ENGLISH_CI = 6;
|
||||
exports.KOI8R_GENERAL_CI = 7;
|
||||
exports.LATIN1_SWEDISH_CI = 8;
|
||||
exports.LATIN2_GENERAL_CI = 9;
|
||||
exports.SWE7_SWEDISH_CI = 10;
|
||||
exports.ASCII_GENERAL_CI = 11;
|
||||
exports.UJIS_JAPANESE_CI = 12;
|
||||
exports.SJIS_JAPANESE_CI = 13;
|
||||
exports.CP1251_BULGARIAN_CI = 14;
|
||||
exports.LATIN1_DANISH_CI = 15;
|
||||
exports.HEBREW_GENERAL_CI = 16;
|
||||
exports.TIS620_THAI_CI = 18;
|
||||
exports.EUCKR_KOREAN_CI = 19;
|
||||
exports.LATIN7_ESTONIAN_CS = 20;
|
||||
exports.LATIN2_HUNGARIAN_CI = 21;
|
||||
exports.KOI8U_GENERAL_CI = 22;
|
||||
exports.CP1251_UKRAINIAN_CI = 23;
|
||||
exports.GB2312_CHINESE_CI = 24;
|
||||
exports.GREEK_GENERAL_CI = 25;
|
||||
exports.CP1250_GENERAL_CI = 26;
|
||||
exports.LATIN2_CROATIAN_CI = 27;
|
||||
exports.GBK_CHINESE_CI = 28;
|
||||
exports.CP1257_LITHUANIAN_CI = 29;
|
||||
exports.LATIN5_TURKISH_CI = 30;
|
||||
exports.LATIN1_GERMAN2_CI = 31;
|
||||
exports.ARMSCII8_GENERAL_CI = 32;
|
||||
exports.UTF8_GENERAL_CI = 33;
|
||||
exports.CP1250_CZECH_CS = 34;
|
||||
exports.UCS2_GENERAL_CI = 35;
|
||||
exports.CP866_GENERAL_CI = 36;
|
||||
exports.KEYBCS2_GENERAL_CI = 37;
|
||||
exports.MACCE_GENERAL_CI = 38;
|
||||
exports.MACROMAN_GENERAL_CI = 39;
|
||||
exports.CP852_GENERAL_CI = 40;
|
||||
exports.LATIN7_GENERAL_CI = 41;
|
||||
exports.LATIN7_GENERAL_CS = 42;
|
||||
exports.MACCE_BIN = 43;
|
||||
exports.CP1250_CROATIAN_CI = 44;
|
||||
exports.UTF8MB4_GENERAL_CI = 45;
|
||||
exports.UTF8MB4_BIN = 46;
|
||||
exports.LATIN1_BIN = 47;
|
||||
exports.LATIN1_GENERAL_CI = 48;
|
||||
exports.LATIN1_GENERAL_CS = 49;
|
||||
exports.CP1251_BIN = 50;
|
||||
exports.CP1251_GENERAL_CI = 51;
|
||||
exports.CP1251_GENERAL_CS = 52;
|
||||
exports.MACROMAN_BIN = 53;
|
||||
exports.UTF16_GENERAL_CI = 54;
|
||||
exports.UTF16_BIN = 55;
|
||||
exports.UTF16LE_GENERAL_CI = 56;
|
||||
exports.CP1256_GENERAL_CI = 57;
|
||||
exports.CP1257_BIN = 58;
|
||||
exports.CP1257_GENERAL_CI = 59;
|
||||
exports.UTF32_GENERAL_CI = 60;
|
||||
exports.UTF32_BIN = 61;
|
||||
exports.UTF16LE_BIN = 62;
|
||||
exports.BINARY = 63;
|
||||
exports.ARMSCII8_BIN = 64;
|
||||
exports.ASCII_BIN = 65;
|
||||
exports.CP1250_BIN = 66;
|
||||
exports.CP1256_BIN = 67;
|
||||
exports.CP866_BIN = 68;
|
||||
exports.DEC8_BIN = 69;
|
||||
exports.GREEK_BIN = 70;
|
||||
exports.HEBREW_BIN = 71;
|
||||
exports.HP8_BIN = 72;
|
||||
exports.KEYBCS2_BIN = 73;
|
||||
exports.KOI8R_BIN = 74;
|
||||
exports.KOI8U_BIN = 75;
|
||||
exports.UTF8_TOLOWER_CI = 76;
|
||||
exports.LATIN2_BIN = 77;
|
||||
exports.LATIN5_BIN = 78;
|
||||
exports.LATIN7_BIN = 79;
|
||||
exports.CP850_BIN = 80;
|
||||
exports.CP852_BIN = 81;
|
||||
exports.SWE7_BIN = 82;
|
||||
exports.UTF8_BIN = 83;
|
||||
exports.BIG5_BIN = 84;
|
||||
exports.EUCKR_BIN = 85;
|
||||
exports.GB2312_BIN = 86;
|
||||
exports.GBK_BIN = 87;
|
||||
exports.SJIS_BIN = 88;
|
||||
exports.TIS620_BIN = 89;
|
||||
exports.UCS2_BIN = 90;
|
||||
exports.UJIS_BIN = 91;
|
||||
exports.GEOSTD8_GENERAL_CI = 92;
|
||||
exports.GEOSTD8_BIN = 93;
|
||||
exports.LATIN1_SPANISH_CI = 94;
|
||||
exports.CP932_JAPANESE_CI = 95;
|
||||
exports.CP932_BIN = 96;
|
||||
exports.EUCJPMS_JAPANESE_CI = 97;
|
||||
exports.EUCJPMS_BIN = 98;
|
||||
exports.CP1250_POLISH_CI = 99;
|
||||
exports.UTF16_UNICODE_CI = 101;
|
||||
exports.UTF16_ICELANDIC_CI = 102;
|
||||
exports.UTF16_LATVIAN_CI = 103;
|
||||
exports.UTF16_ROMANIAN_CI = 104;
|
||||
exports.UTF16_SLOVENIAN_CI = 105;
|
||||
exports.UTF16_POLISH_CI = 106;
|
||||
exports.UTF16_ESTONIAN_CI = 107;
|
||||
exports.UTF16_SPANISH_CI = 108;
|
||||
exports.UTF16_SWEDISH_CI = 109;
|
||||
exports.UTF16_TURKISH_CI = 110;
|
||||
exports.UTF16_CZECH_CI = 111;
|
||||
exports.UTF16_DANISH_CI = 112;
|
||||
exports.UTF16_LITHUANIAN_CI = 113;
|
||||
exports.UTF16_SLOVAK_CI = 114;
|
||||
exports.UTF16_SPANISH2_CI = 115;
|
||||
exports.UTF16_ROMAN_CI = 116;
|
||||
exports.UTF16_PERSIAN_CI = 117;
|
||||
exports.UTF16_ESPERANTO_CI = 118;
|
||||
exports.UTF16_HUNGARIAN_CI = 119;
|
||||
exports.UTF16_SINHALA_CI = 120;
|
||||
exports.UTF16_GERMAN2_CI = 121;
|
||||
exports.UTF16_CROATIAN_CI = 122;
|
||||
exports.UTF16_UNICODE_520_CI = 123;
|
||||
exports.UTF16_VIETNAMESE_CI = 124;
|
||||
exports.UCS2_UNICODE_CI = 128;
|
||||
exports.UCS2_ICELANDIC_CI = 129;
|
||||
exports.UCS2_LATVIAN_CI = 130;
|
||||
exports.UCS2_ROMANIAN_CI = 131;
|
||||
exports.UCS2_SLOVENIAN_CI = 132;
|
||||
exports.UCS2_POLISH_CI = 133;
|
||||
exports.UCS2_ESTONIAN_CI = 134;
|
||||
exports.UCS2_SPANISH_CI = 135;
|
||||
exports.UCS2_SWEDISH_CI = 136;
|
||||
exports.UCS2_TURKISH_CI = 137;
|
||||
exports.UCS2_CZECH_CI = 138;
|
||||
exports.UCS2_DANISH_CI = 139;
|
||||
exports.UCS2_LITHUANIAN_CI = 140;
|
||||
exports.UCS2_SLOVAK_CI = 141;
|
||||
exports.UCS2_SPANISH2_CI = 142;
|
||||
exports.UCS2_ROMAN_CI = 143;
|
||||
exports.UCS2_PERSIAN_CI = 144;
|
||||
exports.UCS2_ESPERANTO_CI = 145;
|
||||
exports.UCS2_HUNGARIAN_CI = 146;
|
||||
exports.UCS2_SINHALA_CI = 147;
|
||||
exports.UCS2_GERMAN2_CI = 148;
|
||||
exports.UCS2_CROATIAN_CI = 149;
|
||||
exports.UCS2_UNICODE_520_CI = 150;
|
||||
exports.UCS2_VIETNAMESE_CI = 151;
|
||||
exports.UCS2_GENERAL_MYSQL500_CI = 159;
|
||||
exports.UTF32_UNICODE_CI = 160;
|
||||
exports.UTF32_ICELANDIC_CI = 161;
|
||||
exports.UTF32_LATVIAN_CI = 162;
|
||||
exports.UTF32_ROMANIAN_CI = 163;
|
||||
exports.UTF32_SLOVENIAN_CI = 164;
|
||||
exports.UTF32_POLISH_CI = 165;
|
||||
exports.UTF32_ESTONIAN_CI = 166;
|
||||
exports.UTF32_SPANISH_CI = 167;
|
||||
exports.UTF32_SWEDISH_CI = 168;
|
||||
exports.UTF32_TURKISH_CI = 169;
|
||||
exports.UTF32_CZECH_CI = 170;
|
||||
exports.UTF32_DANISH_CI = 171;
|
||||
exports.UTF32_LITHUANIAN_CI = 172;
|
||||
exports.UTF32_SLOVAK_CI = 173;
|
||||
exports.UTF32_SPANISH2_CI = 174;
|
||||
exports.UTF32_ROMAN_CI = 175;
|
||||
exports.UTF32_PERSIAN_CI = 176;
|
||||
exports.UTF32_ESPERANTO_CI = 177;
|
||||
exports.UTF32_HUNGARIAN_CI = 178;
|
||||
exports.UTF32_SINHALA_CI = 179;
|
||||
exports.UTF32_GERMAN2_CI = 180;
|
||||
exports.UTF32_CROATIAN_CI = 181;
|
||||
exports.UTF32_UNICODE_520_CI = 182;
|
||||
exports.UTF32_VIETNAMESE_CI = 183;
|
||||
exports.UTF8_UNICODE_CI = 192;
|
||||
exports.UTF8_ICELANDIC_CI = 193;
|
||||
exports.UTF8_LATVIAN_CI = 194;
|
||||
exports.UTF8_ROMANIAN_CI = 195;
|
||||
exports.UTF8_SLOVENIAN_CI = 196;
|
||||
exports.UTF8_POLISH_CI = 197;
|
||||
exports.UTF8_ESTONIAN_CI = 198;
|
||||
exports.UTF8_SPANISH_CI = 199;
|
||||
exports.UTF8_SWEDISH_CI = 200;
|
||||
exports.UTF8_TURKISH_CI = 201;
|
||||
exports.UTF8_CZECH_CI = 202;
|
||||
exports.UTF8_DANISH_CI = 203;
|
||||
exports.UTF8_LITHUANIAN_CI = 204;
|
||||
exports.UTF8_SLOVAK_CI = 205;
|
||||
exports.UTF8_SPANISH2_CI = 206;
|
||||
exports.UTF8_ROMAN_CI = 207;
|
||||
exports.UTF8_PERSIAN_CI = 208;
|
||||
exports.UTF8_ESPERANTO_CI = 209;
|
||||
exports.UTF8_HUNGARIAN_CI = 210;
|
||||
exports.UTF8_SINHALA_CI = 211;
|
||||
exports.UTF8_GERMAN2_CI = 212;
|
||||
exports.UTF8_CROATIAN_CI = 213;
|
||||
exports.UTF8_UNICODE_520_CI = 214;
|
||||
exports.UTF8_VIETNAMESE_CI = 215;
|
||||
exports.UTF8_GENERAL_MYSQL500_CI = 223;
|
||||
exports.UTF8MB4_UNICODE_CI = 224;
|
||||
exports.UTF8MB4_ICELANDIC_CI = 225;
|
||||
exports.UTF8MB4_LATVIAN_CI = 226;
|
||||
exports.UTF8MB4_ROMANIAN_CI = 227;
|
||||
exports.UTF8MB4_SLOVENIAN_CI = 228;
|
||||
exports.UTF8MB4_POLISH_CI = 229;
|
||||
exports.UTF8MB4_ESTONIAN_CI = 230;
|
||||
exports.UTF8MB4_SPANISH_CI = 231;
|
||||
exports.UTF8MB4_SWEDISH_CI = 232;
|
||||
exports.UTF8MB4_TURKISH_CI = 233;
|
||||
exports.UTF8MB4_CZECH_CI = 234;
|
||||
exports.UTF8MB4_DANISH_CI = 235;
|
||||
exports.UTF8MB4_LITHUANIAN_CI = 236;
|
||||
exports.UTF8MB4_SLOVAK_CI = 237;
|
||||
exports.UTF8MB4_SPANISH2_CI = 238;
|
||||
exports.UTF8MB4_ROMAN_CI = 239;
|
||||
exports.UTF8MB4_PERSIAN_CI = 240;
|
||||
exports.UTF8MB4_ESPERANTO_CI = 241;
|
||||
exports.UTF8MB4_HUNGARIAN_CI = 242;
|
||||
exports.UTF8MB4_SINHALA_CI = 243;
|
||||
exports.UTF8MB4_GERMAN2_CI = 244;
|
||||
exports.UTF8MB4_CROATIAN_CI = 245;
|
||||
exports.UTF8MB4_UNICODE_520_CI = 246;
|
||||
exports.UTF8MB4_VIETNAMESE_CI = 247;
|
||||
exports.GB18030_CHINESE_CI = 248;
|
||||
exports.GB18030_BIN = 249;
|
||||
exports.GB18030_UNICODE_520_CI = 250;
|
||||
exports.UTF8_GENERAL50_CI = 253;
|
||||
exports.UTF8MB4_0900_AI_CI = 255;
|
||||
exports.UTF8MB4_CS_0900_AI_CI = 266;
|
||||
exports.UTF8MB4_DA_0900_AI_CI = 267;
|
||||
exports.UTF8MB4_DE_PB_0900_AI_CI = 256;
|
||||
exports.UTF8MB4_EO_0900_AI_CI = 273;
|
||||
exports.UTF8MB4_ES_0900_AI_CI = 263;
|
||||
exports.UTF8MB4_ES_TRAD_0900_AI_CI = 270;
|
||||
exports.UTF8MB4_ET_0900_AI_CI = 262;
|
||||
exports.UTF8MB4_HR_0900_AI_CI = 275;
|
||||
exports.UTF8MB4_HU_0900_AI_CI = 274;
|
||||
exports.UTF8MB4_IS_0900_AI_CI = 257;
|
||||
exports.UTF8MB4_LA_0900_AI_CI = 271;
|
||||
exports.UTF8MB4_LT_0900_AI_CI = 268;
|
||||
exports.UTF8MB4_LV_0900_AI_CI = 258;
|
||||
exports.UTF8MB4_PL_0900_AI_CI = 261;
|
||||
exports.UTF8MB4_RO_0900_AI_CI = 259;
|
||||
exports.UTF8MB4_SK_0900_AI_CI = 269;
|
||||
exports.UTF8MB4_SL_0900_AI_CI = 260;
|
||||
exports.UTF8MB4_SV_0900_AI_CI = 264;
|
||||
exports.UTF8MB4_TR_0900_AI_CI = 265;
|
||||
exports.UTF8MB4_VI_0900_AI_CI = 277;
|
||||
|
||||
// short aliases
|
||||
exports.BIG5 = exports.BIG5_CHINESE_CI;
|
||||
exports.DEC8 = exports.DEC8_SWEDISH_CI;
|
||||
exports.CP850 = exports.CP850_GENERAL_CI;
|
||||
exports.HP8 = exports.HP8_ENGLISH_CI;
|
||||
exports.KOI8R = exports.KOI8R_GENERAL_CI;
|
||||
exports.LATIN1 = exports.LATIN1_SWEDISH_CI;
|
||||
exports.LATIN2 = exports.LATIN2_GENERAL_CI;
|
||||
exports.SWE7 = exports.SWE7_SWEDISH_CI;
|
||||
exports.ASCII = exports.ASCII_GENERAL_CI;
|
||||
exports.UJIS = exports.UJIS_JAPANESE_CI;
|
||||
exports.SJIS = exports.SJIS_JAPANESE_CI;
|
||||
exports.HEBREW = exports.HEBREW_GENERAL_CI;
|
||||
exports.TIS620 = exports.TIS620_THAI_CI;
|
||||
exports.EUCKR = exports.EUCKR_KOREAN_CI;
|
||||
exports.KOI8U = exports.KOI8U_GENERAL_CI;
|
||||
exports.GB2312 = exports.GB2312_CHINESE_CI;
|
||||
exports.GREEK = exports.GREEK_GENERAL_CI;
|
||||
exports.CP1250 = exports.CP1250_GENERAL_CI;
|
||||
exports.GBK = exports.GBK_CHINESE_CI;
|
||||
exports.LATIN5 = exports.LATIN5_TURKISH_CI;
|
||||
exports.ARMSCII8 = exports.ARMSCII8_GENERAL_CI;
|
||||
exports.UTF8 = exports.UTF8_GENERAL_CI;
|
||||
exports.UCS2 = exports.UCS2_GENERAL_CI;
|
||||
exports.CP866 = exports.CP866_GENERAL_CI;
|
||||
exports.KEYBCS2 = exports.KEYBCS2_GENERAL_CI;
|
||||
exports.MACCE = exports.MACCE_GENERAL_CI;
|
||||
exports.MACROMAN = exports.MACROMAN_GENERAL_CI;
|
||||
exports.CP852 = exports.CP852_GENERAL_CI;
|
||||
exports.LATIN7 = exports.LATIN7_GENERAL_CI;
|
||||
exports.UTF8MB4 = exports.UTF8MB4_GENERAL_CI;
|
||||
exports.CP1251 = exports.CP1251_GENERAL_CI;
|
||||
exports.UTF16 = exports.UTF16_GENERAL_CI;
|
||||
exports.UTF16LE = exports.UTF16LE_GENERAL_CI;
|
||||
exports.CP1256 = exports.CP1256_GENERAL_CI;
|
||||
exports.CP1257 = exports.CP1257_GENERAL_CI;
|
||||
exports.UTF32 = exports.UTF32_GENERAL_CI;
|
||||
exports.CP932 = exports.CP932_JAPANESE_CI;
|
||||
exports.EUCJPMS = exports.EUCJPMS_JAPANESE_CI;
|
||||
exports.GB18030 = exports.GB18030_CHINESE_CI;
|
||||
exports.GEOSTD8 = exports.GEOSTD8_GENERAL_CI;
|
31
node_modules/mysql2/lib/constants/client.js
generated
vendored
Normal file
31
node_modules/mysql2/lib/constants/client.js
generated
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
'use strict';
|
||||
|
||||
// Manually extracted from mysql-5.5.23/include/mysql_com.h
|
||||
exports.LONG_PASSWORD = 0x00000001; /* new more secure passwords */
|
||||
exports.FOUND_ROWS = 0x00000002; /* found instead of affected rows */
|
||||
exports.LONG_FLAG = 0x00000004; /* get all column flags */
|
||||
exports.CONNECT_WITH_DB = 0x00000008; /* one can specify db on connect */
|
||||
exports.NO_SCHEMA = 0x00000010; /* don't allow database.table.column */
|
||||
exports.COMPRESS = 0x00000020; /* can use compression protocol */
|
||||
exports.ODBC = 0x00000040; /* odbc client */
|
||||
exports.LOCAL_FILES = 0x00000080; /* can use LOAD DATA LOCAL */
|
||||
exports.IGNORE_SPACE = 0x00000100; /* ignore spaces before '' */
|
||||
exports.PROTOCOL_41 = 0x00000200; /* new 4.1 protocol */
|
||||
exports.INTERACTIVE = 0x00000400; /* this is an interactive client */
|
||||
exports.SSL = 0x00000800; /* switch to ssl after handshake */
|
||||
exports.IGNORE_SIGPIPE = 0x00001000; /* IGNORE sigpipes */
|
||||
exports.TRANSACTIONS = 0x00002000; /* client knows about transactions */
|
||||
exports.RESERVED = 0x00004000; /* old flag for 4.1 protocol */
|
||||
exports.SECURE_CONNECTION = 0x00008000; /* new 4.1 authentication */
|
||||
exports.MULTI_STATEMENTS = 0x00010000; /* enable/disable multi-stmt support */
|
||||
exports.MULTI_RESULTS = 0x00020000; /* enable/disable multi-results */
|
||||
exports.PS_MULTI_RESULTS = 0x00040000; /* multi-results in ps-protocol */
|
||||
exports.PLUGIN_AUTH = 0x00080000; /* client supports plugin authentication */
|
||||
exports.CONNECT_ATTRS = 0x00100000; /* permits connection attributes */
|
||||
exports.PLUGIN_AUTH_LENENC_CLIENT_DATA = 0x00200000; /* Understands length-encoded integer for auth response data in Protocol::HandshakeResponse41. */
|
||||
exports.CAN_HANDLE_EXPIRED_PASSWORDS = 0x00400000; /* Announces support for expired password extension. */
|
||||
exports.SESSION_TRACK = 0x00800000; /* Can set SERVER_SESSION_STATE_CHANGED in the Status Flags and send session-state change data after a OK packet. */
|
||||
exports.DEPRECATE_EOF = 0x01000000; /* Can send OK after a Text Resultset. */
|
||||
|
||||
exports.SSL_VERIFY_SERVER_CERT = 0x40000000;
|
||||
exports.REMEMBER_OPTIONS = 0x80000000;
|
36
node_modules/mysql2/lib/constants/commands.js
generated
vendored
Normal file
36
node_modules/mysql2/lib/constants/commands.js
generated
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
SLEEP: 0x00, // deprecated
|
||||
QUIT: 0x01,
|
||||
INIT_DB: 0x02,
|
||||
QUERY: 0x03,
|
||||
FIELD_LIST: 0x04,
|
||||
CREATE_DB: 0x05,
|
||||
DROP_DB: 0x06,
|
||||
REFRESH: 0x07,
|
||||
SHUTDOWN: 0x08,
|
||||
STATISTICS: 0x09,
|
||||
PROCESS_INFO: 0x0a, // deprecated
|
||||
CONNECT: 0x0b, // deprecated
|
||||
PROCESS_KILL: 0x0c,
|
||||
DEBUG: 0x0d,
|
||||
PING: 0x0e,
|
||||
TIME: 0x0f, // deprecated
|
||||
DELAYED_INSERT: 0x10, // deprecated
|
||||
CHANGE_USER: 0x11,
|
||||
BINLOG_DUMP: 0x12,
|
||||
TABLE_DUMP: 0x13,
|
||||
CONNECT_OUT: 0x14,
|
||||
REGISTER_SLAVE: 0x15,
|
||||
STMT_PREPARE: 0x16,
|
||||
STMT_EXECUTE: 0x17,
|
||||
STMT_SEND_LONG_DATA: 0x18,
|
||||
STMT_CLOSE: 0x19,
|
||||
STMT_RESET: 0x1a,
|
||||
SET_OPTION: 0x1b,
|
||||
STMT_FETCH: 0x1c,
|
||||
DAEMON: 0x1d, // deprecated
|
||||
BINLOG_DUMP_GTID: 0x1e,
|
||||
UNKNOWN: 0xff // bad!
|
||||
};
|
8
node_modules/mysql2/lib/constants/cursor.js
generated
vendored
Normal file
8
node_modules/mysql2/lib/constants/cursor.js
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
NO_CURSOR: 0,
|
||||
READ_ONLY: 1,
|
||||
FOR_UPDATE: 2,
|
||||
SCROLLABLE: 3
|
||||
};
|
49
node_modules/mysql2/lib/constants/encoding_charset.js
generated
vendored
Normal file
49
node_modules/mysql2/lib/constants/encoding_charset.js
generated
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
'use strict';
|
||||
|
||||
// inverse of charset_encodings
|
||||
// given encoding, get matching mysql charset number
|
||||
|
||||
module.exports = {
|
||||
big5: 1,
|
||||
latin2: 2,
|
||||
dec8: 3,
|
||||
cp850: 4,
|
||||
latin1: 5,
|
||||
hp8: 6,
|
||||
koi8r: 7,
|
||||
swe7: 10,
|
||||
ascii: 11,
|
||||
eucjp: 12,
|
||||
sjis: 13,
|
||||
cp1251: 14,
|
||||
hebrew: 16,
|
||||
tis620: 18,
|
||||
euckr: 19,
|
||||
latin7: 20,
|
||||
koi8u: 22,
|
||||
gb2312: 24,
|
||||
greek: 25,
|
||||
cp1250: 26,
|
||||
gbk: 28,
|
||||
cp1257: 29,
|
||||
latin5: 30,
|
||||
armscii8: 32,
|
||||
cesu8: 33,
|
||||
ucs2: 35,
|
||||
cp866: 36,
|
||||
keybcs2: 37,
|
||||
macintosh: 38,
|
||||
macroman: 39,
|
||||
cp852: 40,
|
||||
utf8: 45,
|
||||
utf8mb4: 45,
|
||||
utf16: 54,
|
||||
utf16le: 56,
|
||||
cp1256: 57,
|
||||
utf32: 60,
|
||||
binary: 63,
|
||||
geostd8: 92,
|
||||
cp932: 95,
|
||||
eucjpms: 97,
|
||||
gb18030: 248
|
||||
};
|
1984
node_modules/mysql2/lib/constants/errors.js
generated
vendored
Normal file
1984
node_modules/mysql2/lib/constants/errors.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
20
node_modules/mysql2/lib/constants/field_flags.js
generated
vendored
Normal file
20
node_modules/mysql2/lib/constants/field_flags.js
generated
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
'use strict';
|
||||
|
||||
// Manually extracted from mysql-5.5.23/include/mysql_com.h
|
||||
exports.NOT_NULL = 1; /* Field can't be NULL */
|
||||
exports.PRI_KEY = 2; /* Field is part of a primary key */
|
||||
exports.UNIQUE_KEY = 4; /* Field is part of a unique key */
|
||||
exports.MULTIPLE_KEY = 8; /* Field is part of a key */
|
||||
exports.BLOB = 16; /* Field is a blob */
|
||||
exports.UNSIGNED = 32; /* Field is unsigned */
|
||||
exports.ZEROFILL = 64; /* Field is zerofill */
|
||||
exports.BINARY = 128; /* Field is binary */
|
||||
|
||||
/* The following are only sent to new clients */
|
||||
exports.ENUM = 256; /* field is an enum */
|
||||
exports.AUTO_INCREMENT = 512; /* field is a autoincrement field */
|
||||
exports.TIMESTAMP = 1024; /* Field is a timestamp */
|
||||
exports.SET = 2048; /* field is a set */
|
||||
exports.NO_DEFAULT_VALUE = 4096; /* Field doesn't have default value */
|
||||
exports.ON_UPDATE_NOW = 8192; /* Field is set to NOW on UPDATE */
|
||||
exports.NUM = 32768; /* Field is num (for clients) */
|
44
node_modules/mysql2/lib/constants/server_status.js
generated
vendored
Normal file
44
node_modules/mysql2/lib/constants/server_status.js
generated
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
'use strict';
|
||||
|
||||
// Manually extracted from mysql-5.5.23/include/mysql_com.h
|
||||
|
||||
/**
|
||||
Is raised when a multi-statement transaction
|
||||
has been started, either explicitly, by means
|
||||
of BEGIN or COMMIT AND CHAIN, or
|
||||
implicitly, by the first transactional
|
||||
statement, when autocommit=off.
|
||||
*/
|
||||
exports.SERVER_STATUS_IN_TRANS = 1;
|
||||
exports.SERVER_STATUS_AUTOCOMMIT = 2; /* Server in auto_commit mode */
|
||||
exports.SERVER_MORE_RESULTS_EXISTS = 8; /* Multi query - next query exists */
|
||||
exports.SERVER_QUERY_NO_GOOD_INDEX_USED = 16;
|
||||
exports.SERVER_QUERY_NO_INDEX_USED = 32;
|
||||
/**
|
||||
The server was able to fulfill the clients request and opened a
|
||||
read-only non-scrollable cursor for a query. This flag comes
|
||||
in reply to COM_STMT_EXECUTE and COM_STMT_FETCH commands.
|
||||
*/
|
||||
exports.SERVER_STATUS_CURSOR_EXISTS = 64;
|
||||
/**
|
||||
This flag is sent when a read-only cursor is exhausted, in reply to
|
||||
COM_STMT_FETCH command.
|
||||
*/
|
||||
exports.SERVER_STATUS_LAST_ROW_SENT = 128;
|
||||
exports.SERVER_STATUS_DB_DROPPED = 256; /* A database was dropped */
|
||||
exports.SERVER_STATUS_NO_BACKSLASH_ESCAPES = 512;
|
||||
/**
|
||||
Sent to the client if after a prepared statement reprepare
|
||||
we discovered that the new statement returns a different
|
||||
number of result set columns.
|
||||
*/
|
||||
exports.SERVER_STATUS_METADATA_CHANGED = 1024;
|
||||
exports.SERVER_QUERY_WAS_SLOW = 2048;
|
||||
|
||||
/**
|
||||
To mark ResultSet containing output parameter values.
|
||||
*/
|
||||
exports.SERVER_PS_OUT_PARAMS = 4096;
|
||||
|
||||
exports.SERVER_STATUS_IN_TRANS_READONLY = 0x2000; // in a read-only transaction
|
||||
exports.SERVER_SESSION_STATE_CHANGED = 0x4000;
|
11
node_modules/mysql2/lib/constants/session_track.js
generated
vendored
Normal file
11
node_modules/mysql2/lib/constants/session_track.js
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
'use strict';
|
||||
|
||||
exports.SYSTEM_VARIABLES = 0;
|
||||
exports.SCHEMA = 1;
|
||||
exports.STATE_CHANGE = 2;
|
||||
exports.STATE_GTIDS = 3;
|
||||
exports.TRANSACTION_CHARACTERISTICS = 4;
|
||||
exports.TRANSACTION_STATE = 5;
|
||||
|
||||
exports.FIRST_KEY = exports.SYSTEM_VARIABLES;
|
||||
exports.LAST_KEY = exports.TRANSACTION_STATE;
|
1109
node_modules/mysql2/lib/constants/ssl_profiles.js
generated
vendored
Normal file
1109
node_modules/mysql2/lib/constants/ssl_profiles.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
32
node_modules/mysql2/lib/constants/types.js
generated
vendored
Normal file
32
node_modules/mysql2/lib/constants/types.js
generated
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
'use strict';
|
||||
|
||||
// Manually extracted from mysql-5.5.23/include/mysql_com.h
|
||||
// some more info here: http://dev.mysql.com/doc/refman/5.5/en/c-api-prepared-statement-type-codes.html
|
||||
exports.DECIMAL = 0x00; // aka DECIMAL (http://dev.mysql.com/doc/refman/5.0/en/precision-math-decimal-changes.html)
|
||||
exports.TINY = 0x01; // aka TINYINT, 1 byte
|
||||
exports.SHORT = 0x02; // aka SMALLINT, 2 bytes
|
||||
exports.LONG = 0x03; // aka INT, 4 bytes
|
||||
exports.FLOAT = 0x04; // aka FLOAT, 4-8 bytes
|
||||
exports.DOUBLE = 0x05; // aka DOUBLE, 8 bytes
|
||||
exports.NULL = 0x06; // NULL (used for prepared statements, I think)
|
||||
exports.TIMESTAMP = 0x07; // aka TIMESTAMP
|
||||
exports.LONGLONG = 0x08; // aka BIGINT, 8 bytes
|
||||
exports.INT24 = 0x09; // aka MEDIUMINT, 3 bytes
|
||||
exports.DATE = 0x0a; // aka DATE
|
||||
exports.TIME = 0x0b; // aka TIME
|
||||
exports.DATETIME = 0x0c; // aka DATETIME
|
||||
exports.YEAR = 0x0d; // aka YEAR, 1 byte (don't ask)
|
||||
exports.NEWDATE = 0x0e; // aka ?
|
||||
exports.VARCHAR = 0x0f; // aka VARCHAR (?)
|
||||
exports.BIT = 0x10; // aka BIT, 1-8 byte
|
||||
exports.JSON = 0xf5;
|
||||
exports.NEWDECIMAL = 0xf6; // aka DECIMAL
|
||||
exports.ENUM = 0xf7; // aka ENUM
|
||||
exports.SET = 0xf8; // aka SET
|
||||
exports.TINY_BLOB = 0xf9; // aka TINYBLOB, TINYTEXT
|
||||
exports.MEDIUM_BLOB = 0xfa; // aka MEDIUMBLOB, MEDIUMTEXT
|
||||
exports.LONG_BLOB = 0xfb; // aka LONGBLOG, LONGTEXT
|
||||
exports.BLOB = 0xfc; // aka BLOB, TEXT
|
||||
exports.VAR_STRING = 0xfd; // aka VARCHAR, VARBINARY
|
||||
exports.STRING = 0xfe; // aka CHAR, BINARY
|
||||
exports.GEOMETRY = 0xff; // aka GEOMETRY
|
63
node_modules/mysql2/lib/helpers.js
generated
vendored
Normal file
63
node_modules/mysql2/lib/helpers.js
generated
vendored
Normal file
@ -0,0 +1,63 @@
|
||||
'use strict';
|
||||
|
||||
/*
|
||||
|
||||
this seems to be not only shorter, but faster than
|
||||
string.replace(/\\/g, '\\\\').
|
||||
replace(/\u0008/g, '\\b').
|
||||
replace(/\t/g, '\\t').
|
||||
replace(/\n/g, '\\n').
|
||||
replace(/\f/g, '\\f').
|
||||
replace(/\r/g, '\\r').
|
||||
replace(/'/g, '\\\'').
|
||||
replace(/"/g, '\\"');
|
||||
or string.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&")
|
||||
see http://jsperf.com/string-escape-regexp-vs-json-stringify
|
||||
*/
|
||||
function srcEscape(str) {
|
||||
return JSON.stringify({
|
||||
[str]: 1
|
||||
}).slice(1, -3);
|
||||
}
|
||||
|
||||
exports.srcEscape = srcEscape;
|
||||
|
||||
let highlightFn;
|
||||
let cardinalRecommended = false;
|
||||
try {
|
||||
highlightFn = require('cardinal').highlight;
|
||||
} catch (err) {
|
||||
highlightFn = text => {
|
||||
if (!cardinalRecommended) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('For nicer debug output consider install cardinal@^2.0.0');
|
||||
cardinalRecommended = true;
|
||||
}
|
||||
return text;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints debug message with code frame, will try to use `cardinal` if available.
|
||||
*/
|
||||
function printDebugWithCode(msg, code) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(`\n\n${msg}:\n`);
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(`${highlightFn(code)}\n`);
|
||||
}
|
||||
|
||||
exports.printDebugWithCode = printDebugWithCode;
|
||||
|
||||
/**
|
||||
* checks whether the `type` is in the `list`
|
||||
*/
|
||||
function typeMatch(type, list, Types) {
|
||||
if (Array.isArray(list)) {
|
||||
return list.some(t => type === Types[t]);
|
||||
}
|
||||
|
||||
return !!list;
|
||||
}
|
||||
|
||||
exports.typeMatch = typeMatch;
|
195
node_modules/mysql2/lib/packet_parser.js
generated
vendored
Normal file
195
node_modules/mysql2/lib/packet_parser.js
generated
vendored
Normal file
@ -0,0 +1,195 @@
|
||||
'use strict';
|
||||
|
||||
const Packet = require('./packets/packet.js');
|
||||
|
||||
const MAX_PACKET_LENGTH = 16777215;
|
||||
|
||||
function readPacketLength(b, off) {
|
||||
const b0 = b[off];
|
||||
const b1 = b[off + 1];
|
||||
const b2 = b[off + 2];
|
||||
if (b1 + b2 === 0) {
|
||||
return b0;
|
||||
}
|
||||
return b0 + (b1 << 8) + (b2 << 16);
|
||||
}
|
||||
|
||||
class PacketParser {
|
||||
constructor(onPacket, packetHeaderLength) {
|
||||
// 4 for normal packets, 7 for comprssed protocol packets
|
||||
if (typeof packetHeaderLength === 'undefined') {
|
||||
packetHeaderLength = 4;
|
||||
}
|
||||
// array of last payload chunks
|
||||
// only used when current payload is not complete
|
||||
this.buffer = [];
|
||||
// total length of chunks on buffer
|
||||
this.bufferLength = 0;
|
||||
this.packetHeaderLength = packetHeaderLength;
|
||||
// incomplete header state: number of header bytes received
|
||||
this.headerLen = 0;
|
||||
// expected payload length
|
||||
this.length = 0;
|
||||
this.largePacketParts = [];
|
||||
this.firstPacketSequenceId = 0;
|
||||
this.onPacket = onPacket;
|
||||
this.execute = PacketParser.prototype.executeStart;
|
||||
this._flushLargePacket =
|
||||
packetHeaderLength === 7
|
||||
? this._flushLargePacket7
|
||||
: this._flushLargePacket4;
|
||||
}
|
||||
|
||||
_flushLargePacket4() {
|
||||
const numPackets = this.largePacketParts.length;
|
||||
this.largePacketParts.unshift(Buffer.from([0, 0, 0, 0])); // insert header
|
||||
const body = Buffer.concat(this.largePacketParts);
|
||||
const packet = new Packet(this.firstPacketSequenceId, body, 0, body.length);
|
||||
this.largePacketParts.length = 0;
|
||||
packet.numPackets = numPackets;
|
||||
this.onPacket(packet);
|
||||
}
|
||||
|
||||
_flushLargePacket7() {
|
||||
const numPackets = this.largePacketParts.length;
|
||||
this.largePacketParts.unshift(Buffer.from([0, 0, 0, 0, 0, 0, 0])); // insert header
|
||||
const body = Buffer.concat(this.largePacketParts);
|
||||
this.largePacketParts.length = 0;
|
||||
const packet = new Packet(this.firstPacketSequenceId, body, 0, body.length);
|
||||
packet.numPackets = numPackets;
|
||||
this.onPacket(packet);
|
||||
}
|
||||
|
||||
executeStart(chunk) {
|
||||
let start = 0;
|
||||
const end = chunk.length;
|
||||
while (end - start >= 3) {
|
||||
this.length = readPacketLength(chunk, start);
|
||||
if (end - start >= this.length + this.packetHeaderLength) {
|
||||
// at least one full packet
|
||||
const sequenceId = chunk[start + 3];
|
||||
if (
|
||||
this.length < MAX_PACKET_LENGTH &&
|
||||
this.largePacketParts.length === 0
|
||||
) {
|
||||
this.onPacket(
|
||||
new Packet(
|
||||
sequenceId,
|
||||
chunk,
|
||||
start,
|
||||
start + this.packetHeaderLength + this.length
|
||||
)
|
||||
);
|
||||
} else {
|
||||
// first large packet - remember it's id
|
||||
if (this.largePacketParts.length === 0) {
|
||||
this.firstPacketSequenceId = sequenceId;
|
||||
}
|
||||
this.largePacketParts.push(
|
||||
chunk.slice(
|
||||
start + this.packetHeaderLength,
|
||||
start + this.packetHeaderLength + this.length
|
||||
)
|
||||
);
|
||||
if (this.length < MAX_PACKET_LENGTH) {
|
||||
this._flushLargePacket();
|
||||
}
|
||||
}
|
||||
start += this.packetHeaderLength + this.length;
|
||||
} else {
|
||||
// payload is incomplete
|
||||
this.buffer = [chunk.slice(start + 3, end)];
|
||||
this.bufferLength = end - start - 3;
|
||||
this.execute = PacketParser.prototype.executePayload;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (end - start > 0) {
|
||||
// there is start of length header, but it's not full 3 bytes
|
||||
this.headerLen = end - start; // 1 or 2 bytes
|
||||
this.length = chunk[start];
|
||||
if (this.headerLen === 2) {
|
||||
this.length = chunk[start] + (chunk[start + 1] << 8);
|
||||
this.execute = PacketParser.prototype.executeHeader3;
|
||||
} else {
|
||||
this.execute = PacketParser.prototype.executeHeader2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
executePayload(chunk) {
|
||||
let start = 0;
|
||||
const end = chunk.length;
|
||||
const remainingPayload =
|
||||
this.length - this.bufferLength + this.packetHeaderLength - 3;
|
||||
if (end - start >= remainingPayload) {
|
||||
// last chunk for payload
|
||||
const payload = Buffer.allocUnsafe(this.length + this.packetHeaderLength);
|
||||
let offset = 3;
|
||||
for (let i = 0; i < this.buffer.length; ++i) {
|
||||
this.buffer[i].copy(payload, offset);
|
||||
offset += this.buffer[i].length;
|
||||
}
|
||||
chunk.copy(payload, offset, start, start + remainingPayload);
|
||||
const sequenceId = payload[3];
|
||||
if (
|
||||
this.length < MAX_PACKET_LENGTH &&
|
||||
this.largePacketParts.length === 0
|
||||
) {
|
||||
this.onPacket(
|
||||
new Packet(
|
||||
sequenceId,
|
||||
payload,
|
||||
0,
|
||||
this.length + this.packetHeaderLength
|
||||
)
|
||||
);
|
||||
} else {
|
||||
// first large packet - remember it's id
|
||||
if (this.largePacketParts.length === 0) {
|
||||
this.firstPacketSequenceId = sequenceId;
|
||||
}
|
||||
this.largePacketParts.push(
|
||||
payload.slice(
|
||||
this.packetHeaderLength,
|
||||
this.packetHeaderLength + this.length
|
||||
)
|
||||
);
|
||||
if (this.length < MAX_PACKET_LENGTH) {
|
||||
this._flushLargePacket();
|
||||
}
|
||||
}
|
||||
this.buffer = [];
|
||||
this.bufferLength = 0;
|
||||
this.execute = PacketParser.prototype.executeStart;
|
||||
start += remainingPayload;
|
||||
if (end - start > 0) {
|
||||
return this.execute(chunk.slice(start, end));
|
||||
}
|
||||
} else {
|
||||
this.buffer.push(chunk);
|
||||
this.bufferLength += chunk.length;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
executeHeader2(chunk) {
|
||||
this.length += chunk[0] << 8;
|
||||
if (chunk.length > 1) {
|
||||
this.length += chunk[1] << 16;
|
||||
this.execute = PacketParser.prototype.executePayload;
|
||||
return this.executePayload(chunk.slice(2));
|
||||
}
|
||||
this.execute = PacketParser.prototype.executeHeader3;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
executeHeader3(chunk) {
|
||||
this.length += chunk[0] << 16;
|
||||
this.execute = PacketParser.prototype.executePayload;
|
||||
return this.executePayload(chunk.slice(1));
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = PacketParser;
|
38
node_modules/mysql2/lib/packets/auth_switch_request.js
generated
vendored
Normal file
38
node_modules/mysql2/lib/packets/auth_switch_request.js
generated
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
'use strict';
|
||||
|
||||
// http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::AuthSwitchRequest
|
||||
|
||||
const Packet = require('../packets/packet');
|
||||
|
||||
class AuthSwitchRequest {
|
||||
constructor(opts) {
|
||||
this.pluginName = opts.pluginName;
|
||||
this.pluginData = opts.pluginData;
|
||||
}
|
||||
|
||||
toPacket() {
|
||||
const length = 6 + this.pluginName.length + this.pluginData.length;
|
||||
const buffer = Buffer.allocUnsafe(length);
|
||||
const packet = new Packet(0, buffer, 0, length);
|
||||
packet.offset = 4;
|
||||
packet.writeInt8(0xfe);
|
||||
// TODO: use server encoding
|
||||
packet.writeNullTerminatedString(this.pluginName, 'cesu8');
|
||||
packet.writeBuffer(this.pluginData);
|
||||
return packet;
|
||||
}
|
||||
|
||||
static fromPacket(packet) {
|
||||
packet.readInt8(); // marker
|
||||
// assert marker == 0xfe?
|
||||
// TODO: use server encoding
|
||||
const name = packet.readNullTerminatedString('cesu8');
|
||||
const data = packet.readBuffer();
|
||||
return new AuthSwitchRequest({
|
||||
pluginName: name,
|
||||
pluginData: data
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = AuthSwitchRequest;
|
33
node_modules/mysql2/lib/packets/auth_switch_request_more_data.js
generated
vendored
Normal file
33
node_modules/mysql2/lib/packets/auth_switch_request_more_data.js
generated
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
'use strict';
|
||||
|
||||
// http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::AuthSwitchRequest
|
||||
|
||||
const Packet = require('../packets/packet');
|
||||
|
||||
class AuthSwitchRequestMoreData {
|
||||
constructor(data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
toPacket() {
|
||||
const length = 5 + this.data.length;
|
||||
const buffer = Buffer.allocUnsafe(length);
|
||||
const packet = new Packet(0, buffer, 0, length);
|
||||
packet.offset = 4;
|
||||
packet.writeInt8(0x01);
|
||||
packet.writeBuffer(this.data);
|
||||
return packet;
|
||||
}
|
||||
|
||||
static fromPacket(packet) {
|
||||
packet.readInt8(); // marker
|
||||
const data = packet.readBuffer();
|
||||
return new AuthSwitchRequestMoreData(data);
|
||||
}
|
||||
|
||||
static verifyMarker(packet) {
|
||||
return packet.peekByte() === 0x01;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = AuthSwitchRequestMoreData;
|
30
node_modules/mysql2/lib/packets/auth_switch_response.js
generated
vendored
Normal file
30
node_modules/mysql2/lib/packets/auth_switch_response.js
generated
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
'use strict';
|
||||
|
||||
// http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::AuthSwitchRequest
|
||||
|
||||
const Packet = require('../packets/packet');
|
||||
|
||||
class AuthSwitchResponse {
|
||||
constructor(data) {
|
||||
if (!Buffer.isBuffer(data)) {
|
||||
data = Buffer.from(data);
|
||||
}
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
toPacket() {
|
||||
const length = 4 + this.data.length;
|
||||
const buffer = Buffer.allocUnsafe(length);
|
||||
const packet = new Packet(0, buffer, 0, length);
|
||||
packet.offset = 4;
|
||||
packet.writeBuffer(this.data);
|
||||
return packet;
|
||||
}
|
||||
|
||||
static fromPacket(packet) {
|
||||
const data = packet.readBuffer();
|
||||
return new AuthSwitchResponse(data);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = AuthSwitchResponse;
|
48
node_modules/mysql2/lib/packets/binary_row.js
generated
vendored
Normal file
48
node_modules/mysql2/lib/packets/binary_row.js
generated
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
'use strict';
|
||||
|
||||
const Types = require('../constants/types');
|
||||
const Packet = require('../packets/packet');
|
||||
|
||||
const binaryReader = new Array(256);
|
||||
|
||||
class BinaryRow {
|
||||
constructor(columns) {
|
||||
this.columns = columns || [];
|
||||
}
|
||||
|
||||
toPacket() {
|
||||
throw new Error('Not implemented');
|
||||
}
|
||||
|
||||
// TODO: complete list of types...
|
||||
static fromPacket(fields, packet) {
|
||||
const columns = new Array(fields.length);
|
||||
packet.readInt8(); // TODO check it's 0
|
||||
const nullBitmapLength = Math.floor((fields.length + 7 + 2) / 8);
|
||||
// TODO: read and interpret null bitmap
|
||||
packet.skip(nullBitmapLength);
|
||||
for (let i = 0; i < columns.length; ++i) {
|
||||
columns[i] = binaryReader[fields[i].columnType].apply(packet);
|
||||
}
|
||||
return new BinaryRow(columns);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: replace with constants.MYSQL_TYPE_*
|
||||
binaryReader[Types.DECIMAL] = Packet.prototype.readLengthCodedString;
|
||||
binaryReader[1] = Packet.prototype.readInt8; // tiny
|
||||
binaryReader[2] = Packet.prototype.readInt16; // short
|
||||
binaryReader[3] = Packet.prototype.readInt32; // long
|
||||
binaryReader[4] = Packet.prototype.readFloat; // float
|
||||
binaryReader[5] = Packet.prototype.readDouble; // double
|
||||
binaryReader[6] = Packet.prototype.assertInvalid; // null, should be skipped vie null bitmap
|
||||
binaryReader[7] = Packet.prototype.readTimestamp; // timestamp, http://dev.mysql.com/doc/internals/en/prepared-statements.html#packet-ProtocolBinary::MYSQL_TYPE_TIMESTAMP
|
||||
binaryReader[8] = Packet.prototype.readInt64; // long long
|
||||
binaryReader[9] = Packet.prototype.readInt32; // int24
|
||||
binaryReader[10] = Packet.prototype.readTimestamp; // date
|
||||
binaryReader[11] = Packet.prototype.readTime; // time, http://dev.mysql.com/doc/internals/en/prepared-statements.html#packet-ProtocolBinary::MYSQL_TYPE_TIME
|
||||
binaryReader[12] = Packet.prototype.readDateTime; // datetime, http://dev.mysql.com/doc/internals/en/prepared-statements.html#packet-ProtocolBinary::MYSQL_TYPE_DATETIME
|
||||
binaryReader[13] = Packet.prototype.readInt16; // year
|
||||
binaryReader[Types.VAR_STRING] = Packet.prototype.readLengthCodedString; // var string
|
||||
|
||||
module.exports = BinaryRow;
|
33
node_modules/mysql2/lib/packets/binlog_dump.js
generated
vendored
Normal file
33
node_modules/mysql2/lib/packets/binlog_dump.js
generated
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
'use strict';
|
||||
|
||||
// http://dev.mysql.com/doc/internals/en/com-binlog-dump.html#packet-COM_BINLOG_DUMP
|
||||
|
||||
const Packet = require('../packets/packet');
|
||||
const CommandCodes = require('../constants/commands');
|
||||
|
||||
// TODO: add flag to constants
|
||||
// 0x01 - BINLOG_DUMP_NON_BLOCK
|
||||
// send EOF instead of blocking
|
||||
class BinlogDump {
|
||||
constructor(opts) {
|
||||
this.binlogPos = opts.binlogPos || 0;
|
||||
this.serverId = opts.serverId || 0;
|
||||
this.flags = opts.flags || 0;
|
||||
this.filename = opts.filename || '';
|
||||
}
|
||||
|
||||
toPacket() {
|
||||
const length = 15 + Buffer.byteLength(this.filename, 'utf8'); // TODO: should be ascii?
|
||||
const buffer = Buffer.allocUnsafe(length);
|
||||
const packet = new Packet(0, buffer, 0, length);
|
||||
packet.offset = 4;
|
||||
packet.writeInt8(CommandCodes.BINLOG_DUMP);
|
||||
packet.writeInt32(this.binlogPos);
|
||||
packet.writeInt16(this.flags);
|
||||
packet.writeInt32(this.serverId);
|
||||
packet.writeString(this.filename);
|
||||
return packet;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = BinlogDump;
|
115
node_modules/mysql2/lib/packets/binlog_query_statusvars.js
generated
vendored
Normal file
115
node_modules/mysql2/lib/packets/binlog_query_statusvars.js
generated
vendored
Normal file
@ -0,0 +1,115 @@
|
||||
'use strict';
|
||||
|
||||
// http://dev.mysql.com/doc/internals/en/query-event.html
|
||||
|
||||
const keys = {
|
||||
FLAGS2: 0,
|
||||
SQL_MODE: 1,
|
||||
CATALOG: 2,
|
||||
AUTO_INCREMENT: 3,
|
||||
CHARSET: 4,
|
||||
TIME_ZONE: 5,
|
||||
CATALOG_NZ: 6,
|
||||
LC_TIME_NAMES: 7,
|
||||
CHARSET_DATABASE: 8,
|
||||
TABLE_MAP_FOR_UPDATE: 9,
|
||||
MASTER_DATA_WRITTEN: 10,
|
||||
INVOKERS: 11,
|
||||
UPDATED_DB_NAMES: 12,
|
||||
MICROSECONDS: 3
|
||||
};
|
||||
|
||||
module.exports = function parseStatusVars(buffer) {
|
||||
const result = {};
|
||||
let offset = 0;
|
||||
let key, length, prevOffset;
|
||||
while (offset < buffer.length) {
|
||||
key = buffer[offset++];
|
||||
switch (key) {
|
||||
case keys.FLAGS2:
|
||||
result.flags = buffer.readUInt32LE(offset);
|
||||
offset += 4;
|
||||
break;
|
||||
case keys.SQL_MODE:
|
||||
// value is 8 bytes, but all dcumented flags are in first 4 bytes
|
||||
result.sqlMode = buffer.readUInt32LE(offset);
|
||||
offset += 8;
|
||||
break;
|
||||
case keys.CATALOG:
|
||||
length = buffer[offset++];
|
||||
result.catalog = buffer.toString('utf8', offset, offset + length);
|
||||
offset += length + 1; // null byte after string
|
||||
break;
|
||||
case keys.CHARSET:
|
||||
result.clientCharset = buffer.readUInt16LE(offset);
|
||||
result.connectionCollation = buffer.readUInt16LE(offset + 2);
|
||||
result.serverCharset = buffer.readUInt16LE(offset + 4);
|
||||
offset += 6;
|
||||
break;
|
||||
case keys.TIME_ZONE:
|
||||
length = buffer[offset++];
|
||||
result.timeZone = buffer.toString('utf8', offset, offset + length);
|
||||
offset += length; // no null byte
|
||||
break;
|
||||
case keys.CATALOG_NZ:
|
||||
length = buffer[offset++];
|
||||
result.catalogNz = buffer.toString('utf8', offset, offset + length);
|
||||
offset += length; // no null byte
|
||||
break;
|
||||
case keys.LC_TIME_NAMES:
|
||||
result.lcTimeNames = buffer.readUInt16LE(offset);
|
||||
offset += 2;
|
||||
break;
|
||||
case keys.CHARSET_DATABASE:
|
||||
result.schemaCharset = buffer.readUInt16LE(offset);
|
||||
offset += 2;
|
||||
break;
|
||||
case keys.TABLE_MAP_FOR_UPDATE:
|
||||
result.mapForUpdate1 = buffer.readUInt32LE(offset);
|
||||
result.mapForUpdate2 = buffer.readUInt32LE(offset + 4);
|
||||
offset += 8;
|
||||
break;
|
||||
case keys.MASTER_DATA_WRITTEN:
|
||||
result.masterDataWritten = buffer.readUInt32LE(offset);
|
||||
offset += 4;
|
||||
break;
|
||||
case keys.INVOKERS:
|
||||
length = buffer[offset++];
|
||||
result.invokerUsername = buffer.toString(
|
||||
'utf8',
|
||||
offset,
|
||||
offset + length
|
||||
);
|
||||
offset += length;
|
||||
length = buffer[offset++];
|
||||
result.invokerHostname = buffer.toString(
|
||||
'utf8',
|
||||
offset,
|
||||
offset + length
|
||||
);
|
||||
offset += length;
|
||||
break;
|
||||
case keys.UPDATED_DB_NAMES:
|
||||
length = buffer[offset++];
|
||||
// length - number of null-terminated strings
|
||||
result.updatedDBs = []; // we'll store them as array here
|
||||
for (; length; --length) {
|
||||
prevOffset = offset;
|
||||
// fast forward to null terminating byte
|
||||
while (buffer[offset++] && offset < buffer.length) {
|
||||
// empty body, everything inside while condition
|
||||
}
|
||||
result.updatedDBs.push(
|
||||
buffer.toString('utf8', prevOffset, offset - 1)
|
||||
);
|
||||
}
|
||||
break;
|
||||
case keys.MICROSECONDS:
|
||||
result.microseconds =
|
||||
// REVIEW: INVALID UNKNOWN VARIABLE!
|
||||
buffer.readInt16LE(offset) + (buffer[offset + 2] << 16);
|
||||
offset += 3;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
97
node_modules/mysql2/lib/packets/change_user.js
generated
vendored
Normal file
97
node_modules/mysql2/lib/packets/change_user.js
generated
vendored
Normal file
@ -0,0 +1,97 @@
|
||||
'use strict';
|
||||
|
||||
const CommandCode = require('../constants/commands.js');
|
||||
const ClientConstants = require('../constants/client.js');
|
||||
const Packet = require('../packets/packet.js');
|
||||
const auth41 = require('../auth_41.js');
|
||||
const CharsetToEncoding = require('../constants/charset_encodings.js');
|
||||
|
||||
// https://dev.mysql.com/doc/internals/en/com-change-user.html#packet-COM_CHANGE_USER
|
||||
class ChangeUser {
|
||||
constructor(opts) {
|
||||
this.flags = opts.flags;
|
||||
this.user = opts.user || '';
|
||||
this.database = opts.database || '';
|
||||
this.password = opts.password || '';
|
||||
this.passwordSha1 = opts.passwordSha1;
|
||||
this.authPluginData1 = opts.authPluginData1;
|
||||
this.authPluginData2 = opts.authPluginData2;
|
||||
this.connectAttributes = opts.connectAttrinutes || {};
|
||||
let authToken;
|
||||
if (this.passwordSha1) {
|
||||
authToken = auth41.calculateTokenFromPasswordSha(
|
||||
this.passwordSha1,
|
||||
this.authPluginData1,
|
||||
this.authPluginData2
|
||||
);
|
||||
} else {
|
||||
authToken = auth41.calculateToken(
|
||||
this.password,
|
||||
this.authPluginData1,
|
||||
this.authPluginData2
|
||||
);
|
||||
}
|
||||
this.authToken = authToken;
|
||||
this.charsetNumber = opts.charsetNumber;
|
||||
}
|
||||
|
||||
// TODO
|
||||
// ChangeUser.fromPacket = function(packet)
|
||||
// };
|
||||
serializeToBuffer(buffer) {
|
||||
const isSet = flag => this.flags & ClientConstants[flag];
|
||||
const packet = new Packet(0, buffer, 0, buffer.length);
|
||||
packet.offset = 4;
|
||||
const encoding = CharsetToEncoding[this.charsetNumber];
|
||||
packet.writeInt8(CommandCode.CHANGE_USER);
|
||||
packet.writeNullTerminatedString(this.user, encoding);
|
||||
if (isSet('SECURE_CONNECTION')) {
|
||||
packet.writeInt8(this.authToken.length);
|
||||
packet.writeBuffer(this.authToken);
|
||||
} else {
|
||||
packet.writeBuffer(this.authToken);
|
||||
packet.writeInt8(0);
|
||||
}
|
||||
packet.writeNullTerminatedString(this.database, encoding);
|
||||
packet.writeInt16(this.charsetNumber);
|
||||
if (isSet('PLUGIN_AUTH')) {
|
||||
// TODO: read this from parameters
|
||||
packet.writeNullTerminatedString('mysql_native_password', 'latin1');
|
||||
}
|
||||
if (isSet('CONNECT_ATTRS')) {
|
||||
const connectAttributes = this.connectAttributes;
|
||||
const attrNames = Object.keys(connectAttributes);
|
||||
let keysLength = 0;
|
||||
for (let k = 0; k < attrNames.length; ++k) {
|
||||
keysLength += Packet.lengthCodedStringLength(attrNames[k], encoding);
|
||||
keysLength += Packet.lengthCodedStringLength(
|
||||
connectAttributes[attrNames[k]],
|
||||
encoding
|
||||
);
|
||||
}
|
||||
packet.writeLengthCodedNumber(keysLength);
|
||||
for (let k = 0; k < attrNames.length; ++k) {
|
||||
packet.writeLengthCodedString(attrNames[k], encoding);
|
||||
packet.writeLengthCodedString(
|
||||
connectAttributes[attrNames[k]],
|
||||
encoding
|
||||
);
|
||||
}
|
||||
}
|
||||
return packet;
|
||||
}
|
||||
|
||||
toPacket() {
|
||||
if (typeof this.user !== 'string') {
|
||||
throw new Error('"user" connection config property must be a string');
|
||||
}
|
||||
if (typeof this.database !== 'string') {
|
||||
throw new Error('"database" connection config property must be a string');
|
||||
}
|
||||
// dry run: calculate resulting packet length
|
||||
const p = this.serializeToBuffer(Packet.MockBuffer());
|
||||
return this.serializeToBuffer(Buffer.allocUnsafe(p.offset));
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ChangeUser;
|
21
node_modules/mysql2/lib/packets/close_statement.js
generated
vendored
Normal file
21
node_modules/mysql2/lib/packets/close_statement.js
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
'use strict';
|
||||
|
||||
const Packet = require('../packets/packet');
|
||||
const CommandCodes = require('../constants/commands');
|
||||
|
||||
class CloseStatement {
|
||||
constructor(id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
// note: no response sent back
|
||||
toPacket() {
|
||||
const packet = new Packet(0, Buffer.allocUnsafe(9), 0, 9);
|
||||
packet.offset = 4;
|
||||
packet.writeInt8(CommandCodes.STMT_CLOSE);
|
||||
packet.writeInt32(this.id);
|
||||
return packet;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = CloseStatement;
|
129
node_modules/mysql2/lib/packets/column_definition.js
generated
vendored
Normal file
129
node_modules/mysql2/lib/packets/column_definition.js
generated
vendored
Normal file
@ -0,0 +1,129 @@
|
||||
'use strict';
|
||||
|
||||
const Packet = require('../packets/packet');
|
||||
const StringParser = require('../parsers/string');
|
||||
const CharsetToEncoding = require('../constants/charset_encodings.js');
|
||||
|
||||
const fields = ['catalog', 'schema', 'table', 'orgTable', 'name', 'orgName'];
|
||||
|
||||
// creating JS string is relatively expensive (compared to
|
||||
// reading few bytes from buffer) because all string properties
|
||||
// except for name are unlikely to be used we postpone
|
||||
// string conversion until property access
|
||||
//
|
||||
// TODO: watch for integration benchmarks (one with real network buffer)
|
||||
// there could be bad side effect as keeping reference to a buffer makes it
|
||||
// sit in the memory longer (usually until final .query() callback)
|
||||
// Latest v8 perform much better in regard to bufferer -> string conversion,
|
||||
// at some point of time this optimisation might become unnecessary
|
||||
// see https://github.com/sidorares/node-mysql2/pull/137
|
||||
//
|
||||
class ColumnDefinition {
|
||||
constructor(packet, clientEncoding) {
|
||||
this._buf = packet.buffer;
|
||||
this._clientEncoding = clientEncoding;
|
||||
this._catalogLength = packet.readLengthCodedNumber();
|
||||
this._catalogStart = packet.offset;
|
||||
packet.offset += this._catalogLength;
|
||||
this._schemaLength = packet.readLengthCodedNumber();
|
||||
this._schemaStart = packet.offset;
|
||||
packet.offset += this._schemaLength;
|
||||
this._tableLength = packet.readLengthCodedNumber();
|
||||
this._tableStart = packet.offset;
|
||||
packet.offset += this._tableLength;
|
||||
this._orgTableLength = packet.readLengthCodedNumber();
|
||||
this._orgTableStart = packet.offset;
|
||||
packet.offset += this._orgTableLength;
|
||||
// name is always used, don't make it lazy
|
||||
const _nameLength = packet.readLengthCodedNumber();
|
||||
const _nameStart = packet.offset;
|
||||
packet.offset += _nameLength;
|
||||
this._orgNameLength = packet.readLengthCodedNumber();
|
||||
this._orgNameStart = packet.offset;
|
||||
packet.offset += this._orgNameLength;
|
||||
packet.skip(1); // length of the following fields (always 0x0c)
|
||||
this.characterSet = packet.readInt16();
|
||||
this.encoding = CharsetToEncoding[this.characterSet];
|
||||
this.name = StringParser.decode(
|
||||
this._buf.slice(_nameStart, _nameStart + _nameLength),
|
||||
this.encoding === 'binary' ? this._clientEncoding : this.encoding
|
||||
);
|
||||
this.columnLength = packet.readInt32();
|
||||
this.columnType = packet.readInt8();
|
||||
this.flags = packet.readInt16();
|
||||
this.decimals = packet.readInt8();
|
||||
}
|
||||
|
||||
inspect() {
|
||||
return {
|
||||
catalog: this.catalog,
|
||||
schema: this.schema,
|
||||
name: this.name,
|
||||
orgName: this.orgName,
|
||||
table: this.table,
|
||||
orgTable: this.orgTable,
|
||||
characterSet: this.characterSet,
|
||||
columnLength: this.columnLength,
|
||||
columnType: this.columnType,
|
||||
flags: this.flags,
|
||||
decimals: this.decimals
|
||||
};
|
||||
}
|
||||
|
||||
static toPacket(column, sequenceId) {
|
||||
let length = 17; // = 4 padding + 1 + 12 for the rest
|
||||
fields.forEach(field => {
|
||||
length += Packet.lengthCodedStringLength(
|
||||
column[field],
|
||||
CharsetToEncoding[column.characterSet]
|
||||
);
|
||||
});
|
||||
const buffer = Buffer.allocUnsafe(length);
|
||||
|
||||
const packet = new Packet(sequenceId, buffer, 0, length);
|
||||
function writeField(name) {
|
||||
packet.writeLengthCodedString(
|
||||
column[name],
|
||||
CharsetToEncoding[column.characterSet]
|
||||
);
|
||||
}
|
||||
packet.offset = 4;
|
||||
fields.forEach(writeField);
|
||||
packet.writeInt8(0x0c);
|
||||
packet.writeInt16(column.characterSet);
|
||||
packet.writeInt32(column.columnLength);
|
||||
packet.writeInt8(column.columnType);
|
||||
packet.writeInt16(column.flags);
|
||||
packet.writeInt8(column.decimals);
|
||||
packet.writeInt16(0); // filler
|
||||
return packet;
|
||||
}
|
||||
|
||||
// node-mysql compatibility: alias "db" to "schema"
|
||||
get db() {
|
||||
const start = this._schemaStart;
|
||||
const end = start._shemaLength;
|
||||
return this._buf.utf8Slice(start, end);
|
||||
}
|
||||
}
|
||||
|
||||
const addString = function(name) {
|
||||
Object.defineProperty(ColumnDefinition.prototype, name, {
|
||||
get: function() {
|
||||
const start = this[`_${name}Start`];
|
||||
const end = start + this[`_${name}Length`];
|
||||
return StringParser.decode(
|
||||
this._buf.slice(start, end),
|
||||
this.encoding === 'binary' ? this._clientEncoding : this.encoding
|
||||
);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
addString('catalog');
|
||||
addString('schema');
|
||||
addString('table');
|
||||
addString('orgTable');
|
||||
addString('orgName');
|
||||
|
||||
module.exports = ColumnDefinition;
|
150
node_modules/mysql2/lib/packets/execute.js
generated
vendored
Normal file
150
node_modules/mysql2/lib/packets/execute.js
generated
vendored
Normal file
@ -0,0 +1,150 @@
|
||||
'use strict';
|
||||
|
||||
const CursorType = require('../constants/cursor');
|
||||
const CommandCodes = require('../constants/commands');
|
||||
const Types = require('../constants/types');
|
||||
const Packet = require('../packets/packet');
|
||||
const CharsetToEncoding = require('../constants/charset_encodings.js');
|
||||
|
||||
function isJSON(value) {
|
||||
return (
|
||||
Array.isArray(value) ||
|
||||
value.constructor === Object ||
|
||||
(typeof value.toJSON === 'function' && !Buffer.isBuffer(value))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a value to an object describing type, String/Buffer representation and length
|
||||
* @param {*} value
|
||||
*/
|
||||
function toParameter(value, encoding, timezone) {
|
||||
let type = Types.VAR_STRING;
|
||||
let length;
|
||||
let writer = function(value) {
|
||||
// eslint-disable-next-line no-invalid-this
|
||||
return Packet.prototype.writeLengthCodedString.call(this, value, encoding);
|
||||
};
|
||||
if (value !== null) {
|
||||
switch (typeof value) {
|
||||
case 'undefined':
|
||||
throw new TypeError('Bind parameters must not contain undefined');
|
||||
|
||||
case 'number':
|
||||
type = Types.DOUBLE;
|
||||
length = 8;
|
||||
writer = Packet.prototype.writeDouble;
|
||||
break;
|
||||
|
||||
case 'boolean':
|
||||
value = value | 0;
|
||||
type = Types.TINY;
|
||||
length = 1;
|
||||
writer = Packet.prototype.writeInt8;
|
||||
break;
|
||||
|
||||
case 'object':
|
||||
if (Object.prototype.toString.call(value) === '[object Date]') {
|
||||
type = Types.DATETIME;
|
||||
length = 12;
|
||||
writer = function(value) {
|
||||
// eslint-disable-next-line no-invalid-this
|
||||
return Packet.prototype.writeDate.call(this, value, timezone);
|
||||
};
|
||||
} else if (isJSON(value)) {
|
||||
value = JSON.stringify(value);
|
||||
type = Types.JSON;
|
||||
} else if (Buffer.isBuffer(value)) {
|
||||
length = Packet.lengthCodedNumberLength(value.length) + value.length;
|
||||
writer = Packet.prototype.writeLengthCodedBuffer;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
value = value.toString();
|
||||
}
|
||||
} else {
|
||||
value = '';
|
||||
type = Types.NULL;
|
||||
}
|
||||
if (!length) {
|
||||
length = Packet.lengthCodedStringLength(value, encoding);
|
||||
}
|
||||
return { value, type, length, writer };
|
||||
}
|
||||
|
||||
class Execute {
|
||||
constructor(id, parameters, charsetNumber, timezone) {
|
||||
this.id = id;
|
||||
this.parameters = parameters;
|
||||
this.encoding = CharsetToEncoding[charsetNumber];
|
||||
this.timezone = timezone;
|
||||
}
|
||||
|
||||
toPacket() {
|
||||
// TODO: don't try to calculate packet length in advance, allocate some big buffer in advance (header + 256 bytes?)
|
||||
// and copy + reallocate if not enough
|
||||
// 0 + 4 - length, seqId
|
||||
// 4 + 1 - COM_EXECUTE
|
||||
// 5 + 4 - stmtId
|
||||
// 9 + 1 - flags
|
||||
// 10 + 4 - iteration-count (always 1)
|
||||
let length = 14;
|
||||
let parameters;
|
||||
if (this.parameters && this.parameters.length > 0) {
|
||||
length += Math.floor((this.parameters.length + 7) / 8);
|
||||
length += 1; // new-params-bound-flag
|
||||
length += 2 * this.parameters.length; // type byte for each parameter if new-params-bound-flag is set
|
||||
parameters = this.parameters.map(value =>
|
||||
toParameter(value, this.encoding, this.timezone)
|
||||
);
|
||||
length += parameters.reduce(
|
||||
(accumulator, parameter) => accumulator + parameter.length,
|
||||
0
|
||||
);
|
||||
}
|
||||
const buffer = Buffer.allocUnsafe(length);
|
||||
const packet = new Packet(0, buffer, 0, length);
|
||||
packet.offset = 4;
|
||||
packet.writeInt8(CommandCodes.STMT_EXECUTE);
|
||||
packet.writeInt32(this.id);
|
||||
packet.writeInt8(CursorType.NO_CURSOR); // flags
|
||||
packet.writeInt32(1); // iteration-count, always 1
|
||||
if (parameters) {
|
||||
let bitmap = 0;
|
||||
let bitValue = 1;
|
||||
parameters.forEach(parameter => {
|
||||
if (parameter.type === Types.NULL) {
|
||||
bitmap += bitValue;
|
||||
}
|
||||
bitValue *= 2;
|
||||
if (bitValue === 256) {
|
||||
packet.writeInt8(bitmap);
|
||||
bitmap = 0;
|
||||
bitValue = 1;
|
||||
}
|
||||
});
|
||||
if (bitValue !== 1) {
|
||||
packet.writeInt8(bitmap);
|
||||
}
|
||||
// TODO: explain meaning of the flag
|
||||
// afaik, if set n*2 bytes with type of parameter are sent before parameters
|
||||
// if not, previous execution types are used (TODO prooflink)
|
||||
packet.writeInt8(1); // new-params-bound-flag
|
||||
// Write parameter types
|
||||
parameters.forEach(parameter => {
|
||||
packet.writeInt8(parameter.type); // field type
|
||||
packet.writeInt8(0); // parameter flag
|
||||
});
|
||||
// Write parameter values
|
||||
parameters.forEach(parameter => {
|
||||
if (parameter.type !== Types.NULL) {
|
||||
parameter.writer.call(packet, parameter.value);
|
||||
}
|
||||
});
|
||||
}
|
||||
return packet;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Execute;
|
112
node_modules/mysql2/lib/packets/handshake.js
generated
vendored
Normal file
112
node_modules/mysql2/lib/packets/handshake.js
generated
vendored
Normal file
@ -0,0 +1,112 @@
|
||||
'use strict';
|
||||
|
||||
const Packet = require('../packets/packet');
|
||||
const ClientConstants = require('../constants/client.js');
|
||||
|
||||
// https://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::Handshake
|
||||
|
||||
class Handshake {
|
||||
constructor(args) {
|
||||
this.protocolVersion = args.protocolVersion;
|
||||
this.serverVersion = args.serverVersion;
|
||||
this.capabilityFlags = args.capabilityFlags;
|
||||
this.connectionId = args.connectionId;
|
||||
this.authPluginData1 = args.authPluginData1;
|
||||
this.authPluginData2 = args.authPluginData2;
|
||||
this.characterSet = args.characterSet;
|
||||
this.statusFlags = args.statusFlags;
|
||||
this.autPluginName = args.autPluginName;
|
||||
}
|
||||
|
||||
setScrambleData(cb) {
|
||||
require('crypto').randomBytes(20, (err, data) => {
|
||||
if (err) {
|
||||
cb(err);
|
||||
return;
|
||||
}
|
||||
this.authPluginData1 = data.slice(0, 8);
|
||||
this.authPluginData2 = data.slice(8, 20);
|
||||
cb();
|
||||
});
|
||||
}
|
||||
|
||||
toPacket(sequenceId) {
|
||||
const length = 68 + Buffer.byteLength(this.serverVersion, 'utf8');
|
||||
const buffer = Buffer.alloc(length + 4, 0); // zero fill, 10 bytes filler later needs to contain zeros
|
||||
const packet = new Packet(sequenceId, buffer, 0, length + 4);
|
||||
packet.offset = 4;
|
||||
packet.writeInt8(this.protocolVersion);
|
||||
packet.writeString(this.serverVersion, 'cesu8');
|
||||
packet.writeInt8(0);
|
||||
packet.writeInt32(this.connectionId);
|
||||
packet.writeBuffer(this.authPluginData1);
|
||||
packet.writeInt8(0);
|
||||
const capabilityFlagsBuffer = Buffer.allocUnsafe(4);
|
||||
capabilityFlagsBuffer.writeUInt32LE(this.capabilityFlags, 0);
|
||||
packet.writeBuffer(capabilityFlagsBuffer.slice(0, 2));
|
||||
packet.writeInt8(this.characterSet);
|
||||
packet.writeInt16(this.statusFlags);
|
||||
packet.writeBuffer(capabilityFlagsBuffer.slice(2, 4));
|
||||
packet.writeInt8(21); // authPluginDataLength
|
||||
packet.skip(10);
|
||||
packet.writeBuffer(this.authPluginData2);
|
||||
packet.writeInt8(0);
|
||||
packet.writeString('mysql_native_password', 'latin1');
|
||||
packet.writeInt8(0);
|
||||
return packet;
|
||||
}
|
||||
|
||||
static fromPacket(packet) {
|
||||
const args = {};
|
||||
args.protocolVersion = packet.readInt8();
|
||||
args.serverVersion = packet.readNullTerminatedString('cesu8');
|
||||
args.connectionId = packet.readInt32();
|
||||
args.authPluginData1 = packet.readBuffer(8);
|
||||
packet.skip(1);
|
||||
const capabilityFlagsBuffer = Buffer.allocUnsafe(4);
|
||||
capabilityFlagsBuffer[0] = packet.readInt8();
|
||||
capabilityFlagsBuffer[1] = packet.readInt8();
|
||||
if (packet.haveMoreData()) {
|
||||
args.characterSet = packet.readInt8();
|
||||
args.statusFlags = packet.readInt16();
|
||||
// upper 2 bytes
|
||||
capabilityFlagsBuffer[2] = packet.readInt8();
|
||||
capabilityFlagsBuffer[3] = packet.readInt8();
|
||||
args.capabilityFlags = capabilityFlagsBuffer.readUInt32LE(0);
|
||||
if (args.capabilityFlags & ClientConstants.PLUGIN_AUTH) {
|
||||
args.authPluginDataLength = packet.readInt8();
|
||||
} else {
|
||||
args.authPluginDataLength = 0;
|
||||
packet.skip(1);
|
||||
}
|
||||
packet.skip(10);
|
||||
} else {
|
||||
args.capabilityFlags = capabilityFlagsBuffer.readUInt16LE(0);
|
||||
}
|
||||
|
||||
const isSecureConnection =
|
||||
args.capabilityFlags & ClientConstants.SECURE_CONNECTION;
|
||||
if (isSecureConnection) {
|
||||
const authPluginDataLength = args.authPluginDataLength;
|
||||
if (authPluginDataLength === 0) {
|
||||
// for Secure Password Authentication
|
||||
args.authPluginDataLength = 20;
|
||||
args.authPluginData2 = packet.readBuffer(12);
|
||||
packet.skip(1);
|
||||
} else {
|
||||
// length > 0
|
||||
// for Custom Auth Plugin (PLUGIN_AUTH)
|
||||
const len = Math.max(13, authPluginDataLength - 8);
|
||||
args.authPluginData2 = packet.readBuffer(len);
|
||||
}
|
||||
}
|
||||
|
||||
if (args.capabilityFlags & ClientConstants.PLUGIN_AUTH) {
|
||||
args.autPluginName = packet.readNullTerminatedString('ascii');
|
||||
}
|
||||
|
||||
return new Handshake(args);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Handshake;
|
145
node_modules/mysql2/lib/packets/handshake_response.js
generated
vendored
Normal file
145
node_modules/mysql2/lib/packets/handshake_response.js
generated
vendored
Normal file
@ -0,0 +1,145 @@
|
||||
'use strict';
|
||||
|
||||
const ClientConstants = require('../constants/client.js');
|
||||
const CharsetToEncoding = require('../constants/charset_encodings.js');
|
||||
const Packet = require('../packets/packet.js');
|
||||
|
||||
const auth41 = require('../auth_41.js');
|
||||
|
||||
class HandshakeResponse {
|
||||
constructor(handshake) {
|
||||
this.user = handshake.user || '';
|
||||
this.database = handshake.database || '';
|
||||
this.password = handshake.password || '';
|
||||
this.passwordSha1 = handshake.passwordSha1;
|
||||
this.authPluginData1 = handshake.authPluginData1;
|
||||
this.authPluginData2 = handshake.authPluginData2;
|
||||
this.compress = handshake.compress;
|
||||
this.clientFlags = handshake.flags;
|
||||
// TODO: pre-4.1 auth support
|
||||
let authToken;
|
||||
if (this.passwordSha1) {
|
||||
authToken = auth41.calculateTokenFromPasswordSha(
|
||||
this.passwordSha1,
|
||||
this.authPluginData1,
|
||||
this.authPluginData2
|
||||
);
|
||||
} else {
|
||||
authToken = auth41.calculateToken(
|
||||
this.password,
|
||||
this.authPluginData1,
|
||||
this.authPluginData2
|
||||
);
|
||||
}
|
||||
this.authToken = authToken;
|
||||
this.charsetNumber = handshake.charsetNumber;
|
||||
this.encoding = CharsetToEncoding[handshake.charsetNumber];
|
||||
this.connectAttributes = handshake.connectAttributes;
|
||||
}
|
||||
|
||||
serializeResponse(buffer) {
|
||||
const isSet = flag => this.clientFlags & ClientConstants[flag];
|
||||
const packet = new Packet(0, buffer, 0, buffer.length);
|
||||
packet.offset = 4;
|
||||
packet.writeInt32(this.clientFlags);
|
||||
packet.writeInt32(0); // max packet size. todo: move to config
|
||||
packet.writeInt8(this.charsetNumber);
|
||||
packet.skip(23);
|
||||
const encoding = this.encoding;
|
||||
packet.writeNullTerminatedString(this.user, encoding);
|
||||
let k;
|
||||
if (isSet('PLUGIN_AUTH_LENENC_CLIENT_DATA')) {
|
||||
packet.writeLengthCodedNumber(this.authToken.length);
|
||||
packet.writeBuffer(this.authToken);
|
||||
} else if (isSet('SECURE_CONNECTION')) {
|
||||
packet.writeInt8(this.authToken.length);
|
||||
packet.writeBuffer(this.authToken);
|
||||
} else {
|
||||
packet.writeBuffer(this.authToken);
|
||||
packet.writeInt8(0);
|
||||
}
|
||||
if (isSet('CONNECT_WITH_DB')) {
|
||||
packet.writeNullTerminatedString(this.database, encoding);
|
||||
}
|
||||
if (isSet('PLUGIN_AUTH')) {
|
||||
// TODO: pass from config
|
||||
packet.writeNullTerminatedString('mysql_native_password', 'latin1');
|
||||
}
|
||||
if (isSet('CONNECT_ATTRS')) {
|
||||
const connectAttributes = this.connectAttributes || {};
|
||||
const attrNames = Object.keys(connectAttributes);
|
||||
let keysLength = 0;
|
||||
for (k = 0; k < attrNames.length; ++k) {
|
||||
keysLength += Packet.lengthCodedStringLength(attrNames[k], encoding);
|
||||
keysLength += Packet.lengthCodedStringLength(
|
||||
connectAttributes[attrNames[k]],
|
||||
encoding
|
||||
);
|
||||
}
|
||||
packet.writeLengthCodedNumber(keysLength);
|
||||
for (k = 0; k < attrNames.length; ++k) {
|
||||
packet.writeLengthCodedString(attrNames[k], encoding);
|
||||
packet.writeLengthCodedString(
|
||||
connectAttributes[attrNames[k]],
|
||||
encoding
|
||||
);
|
||||
}
|
||||
}
|
||||
return packet;
|
||||
}
|
||||
|
||||
toPacket() {
|
||||
if (typeof this.user !== 'string') {
|
||||
throw new Error('"user" connection config property must be a string');
|
||||
}
|
||||
if (typeof this.database !== 'string') {
|
||||
throw new Error('"database" connection config property must be a string');
|
||||
}
|
||||
// dry run: calculate resulting packet length
|
||||
const p = this.serializeResponse(Packet.MockBuffer());
|
||||
return this.serializeResponse(Buffer.alloc(p.offset));
|
||||
}
|
||||
static fromPacket(packet) {
|
||||
const args = {};
|
||||
args.clientFlags = packet.readInt32();
|
||||
function isSet(flag) {
|
||||
return args.clientFlags & ClientConstants[flag];
|
||||
}
|
||||
args.maxPacketSize = packet.readInt32();
|
||||
args.charsetNumber = packet.readInt8();
|
||||
const encoding = CharsetToEncoding[args.charsetNumber];
|
||||
args.encoding = encoding;
|
||||
packet.skip(23);
|
||||
args.user = packet.readNullTerminatedString(encoding);
|
||||
let authTokenLength;
|
||||
if (isSet('PLUGIN_AUTH_LENENC_CLIENT_DATA')) {
|
||||
authTokenLength = packet.readLengthCodedNumber(encoding);
|
||||
args.authToken = packet.readBuffer(authTokenLength);
|
||||
} else if (isSet('SECURE_CONNECTION')) {
|
||||
authTokenLength = packet.readInt8();
|
||||
args.authToken = packet.readBuffer(authTokenLength);
|
||||
} else {
|
||||
args.authToken = packet.readNullTerminatedString(encoding);
|
||||
}
|
||||
if (isSet('CONNECT_WITH_DB')) {
|
||||
args.database = packet.readNullTerminatedString(encoding);
|
||||
}
|
||||
if (isSet('PLUGIN_AUTH')) {
|
||||
args.authPluginName = packet.readNullTerminatedString(encoding);
|
||||
}
|
||||
if (isSet('CONNECT_ATTRS')) {
|
||||
const keysLength = packet.readLengthCodedNumber(encoding);
|
||||
const keysEnd = packet.offset + keysLength;
|
||||
const attrs = {};
|
||||
while (packet.offset < keysEnd) {
|
||||
attrs[
|
||||
packet.readLengthCodedString(encoding)
|
||||
] = packet.readLengthCodedString(encoding);
|
||||
}
|
||||
args.connectAttributes = attrs;
|
||||
}
|
||||
return args;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = HandshakeResponse;
|
127
node_modules/mysql2/lib/packets/index.js
generated
vendored
Normal file
127
node_modules/mysql2/lib/packets/index.js
generated
vendored
Normal file
@ -0,0 +1,127 @@
|
||||
'use strict';
|
||||
|
||||
const process = require('process');
|
||||
|
||||
const AuthSwitchRequest = require('./auth_switch_request');
|
||||
const AuthSwitchRequestMoreData = require('./auth_switch_request_more_data');
|
||||
const AuthSwitchResponse = require('./auth_switch_response');
|
||||
const BinaryRow = require('./binary_row');
|
||||
const BinlogDump = require('./binlog_dump');
|
||||
const ChangeUser = require('./change_user');
|
||||
const CloseStatement = require('./close_statement');
|
||||
const ColumnDefinition = require('./column_definition');
|
||||
const Execute = require('./execute');
|
||||
const Handshake = require('./handshake');
|
||||
const HandshakeResponse = require('./handshake_response');
|
||||
const PrepareStatement = require('./prepare_statement');
|
||||
const PreparedStatementHeader = require('./prepared_statement_header');
|
||||
const Query = require('./query');
|
||||
const RegisterSlave = require('./register_slave');
|
||||
const ResultSetHeader = require('./resultset_header');
|
||||
const SSLRequest = require('./ssl_request');
|
||||
const TextRow = require('./text_row');
|
||||
|
||||
const ctorMap = {
|
||||
AuthSwitchRequest,
|
||||
AuthSwitchRequestMoreData,
|
||||
AuthSwitchResponse,
|
||||
BinaryRow,
|
||||
BinlogDump,
|
||||
ChangeUser,
|
||||
CloseStatement,
|
||||
ColumnDefinition,
|
||||
Execute,
|
||||
Handshake,
|
||||
HandshakeResponse,
|
||||
PrepareStatement,
|
||||
PreparedStatementHeader,
|
||||
Query,
|
||||
RegisterSlave,
|
||||
ResultSetHeader,
|
||||
SSLRequest,
|
||||
TextRow
|
||||
};
|
||||
Object.entries(ctorMap).forEach(([name, ctor]) => {
|
||||
module.exports[name] = ctor;
|
||||
// monkey-patch it to include name if debug is on
|
||||
if (process.env.NODE_DEBUG) {
|
||||
if (ctor.prototype.toPacket) {
|
||||
const old = ctor.prototype.toPacket;
|
||||
ctor.prototype.toPacket = function() {
|
||||
const p = old.call(this);
|
||||
p._name = name;
|
||||
return p;
|
||||
};
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// simple packets:
|
||||
const Packet = require('./packet');
|
||||
exports.Packet = Packet;
|
||||
|
||||
class OK {
|
||||
static toPacket(args, encoding) {
|
||||
args = args || {};
|
||||
const affectedRows = args.affectedRows || 0;
|
||||
const insertId = args.insertId || 0;
|
||||
const serverStatus = args.serverStatus || 0;
|
||||
const warningCount = args.warningCount || 0;
|
||||
const message = args.message || '';
|
||||
|
||||
let length = 9 + Packet.lengthCodedNumberLength(affectedRows);
|
||||
length += Packet.lengthCodedNumberLength(insertId);
|
||||
|
||||
const buffer = Buffer.allocUnsafe(length);
|
||||
const packet = new Packet(0, buffer, 0, length);
|
||||
packet.offset = 4;
|
||||
packet.writeInt8(0);
|
||||
packet.writeLengthCodedNumber(affectedRows);
|
||||
packet.writeLengthCodedNumber(insertId);
|
||||
packet.writeInt16(serverStatus);
|
||||
packet.writeInt16(warningCount);
|
||||
packet.writeString(message, encoding);
|
||||
packet._name = 'OK';
|
||||
return packet;
|
||||
}
|
||||
}
|
||||
|
||||
exports.OK = OK;
|
||||
|
||||
// warnings, statusFlags
|
||||
class EOF {
|
||||
static toPacket(warnings, statusFlags) {
|
||||
if (typeof warnings === 'undefined') {
|
||||
warnings = 0;
|
||||
}
|
||||
if (typeof statusFlags === 'undefined') {
|
||||
statusFlags = 0;
|
||||
}
|
||||
const packet = new Packet(0, Buffer.allocUnsafe(9), 0, 9);
|
||||
packet.offset = 4;
|
||||
packet.writeInt8(0xfe);
|
||||
packet.writeInt16(warnings);
|
||||
packet.writeInt16(statusFlags);
|
||||
packet._name = 'EOF';
|
||||
return packet;
|
||||
}
|
||||
}
|
||||
|
||||
exports.EOF = EOF;
|
||||
|
||||
class Error {
|
||||
static toPacket(args, encoding) {
|
||||
const length = 13 + Buffer.byteLength(args.message, 'utf8');
|
||||
const packet = new Packet(0, Buffer.allocUnsafe(length), 0, length);
|
||||
packet.offset = 4;
|
||||
packet.writeInt8(0xff);
|
||||
packet.writeInt16(args.code);
|
||||
// TODO: sql state parameter
|
||||
packet.writeString('#_____', encoding);
|
||||
packet.writeString(args.message, encoding);
|
||||
packet._name = 'Error';
|
||||
return packet;
|
||||
}
|
||||
}
|
||||
|
||||
exports.Error = Error;
|
903
node_modules/mysql2/lib/packets/packet.js
generated
vendored
Normal file
903
node_modules/mysql2/lib/packets/packet.js
generated
vendored
Normal file
@ -0,0 +1,903 @@
|
||||
'use strict';
|
||||
|
||||
const ErrorCodeToName = require('../constants/errors.js');
|
||||
const NativeBuffer = require('buffer').Buffer;
|
||||
const Long = require('long');
|
||||
const StringParser = require('../parsers/string.js');
|
||||
|
||||
const INVALID_DATE = new Date(NaN);
|
||||
|
||||
// this is nearly duplicate of previous function so generated code is not slower
|
||||
// due to "if (dateStrings)" branching
|
||||
const pad = '000000000000';
|
||||
function leftPad(num, value) {
|
||||
const s = value.toString();
|
||||
// if we don't need to pad
|
||||
if (s.length >= num) {
|
||||
return s;
|
||||
}
|
||||
return (pad + s).slice(-num);
|
||||
}
|
||||
|
||||
// The whole reason parse* function below exist
|
||||
// is because String creation is relatively expensive (at least with V8), and if we have
|
||||
// a buffer with "12345" content ideally we would like to bypass intermediate
|
||||
// "12345" string creation and directly build 12345 number out of
|
||||
// <Buffer 31 32 33 34 35> data.
|
||||
// In my benchmarks the difference is ~25M 8-digit numbers per second vs
|
||||
// 4.5 M using Number(packet.readLengthCodedString())
|
||||
// not used when size is close to max precision as series of *10 accumulate error
|
||||
// and approximate result mihgt be diffreent from (approximate as well) Number(bigNumStringValue))
|
||||
// In the futire node version if speed difference is smaller parse* functions might be removed
|
||||
// don't consider them as Packet public API
|
||||
|
||||
const minus = '-'.charCodeAt(0);
|
||||
const plus = '+'.charCodeAt(0);
|
||||
|
||||
// TODO: handle E notation
|
||||
const dot = '.'.charCodeAt(0);
|
||||
const exponent = 'e'.charCodeAt(0);
|
||||
const exponentCapital = 'E'.charCodeAt(0);
|
||||
|
||||
class Packet {
|
||||
constructor(id, buffer, start, end) {
|
||||
// hot path, enable checks when testing only
|
||||
// if (!Buffer.isBuffer(buffer) || typeof start == 'undefined' || typeof end == 'undefined')
|
||||
// throw new Error('invalid packet');
|
||||
this.sequenceId = id;
|
||||
this.numPackets = 1;
|
||||
this.buffer = buffer;
|
||||
this.start = start;
|
||||
this.offset = start + 4;
|
||||
this.end = end;
|
||||
}
|
||||
|
||||
// ==============================
|
||||
// readers
|
||||
// ==============================
|
||||
reset() {
|
||||
this.offset = this.start + 4;
|
||||
}
|
||||
|
||||
length() {
|
||||
return this.end - this.start;
|
||||
}
|
||||
|
||||
slice() {
|
||||
return this.buffer.slice(this.start, this.end);
|
||||
}
|
||||
|
||||
dump() {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(
|
||||
[this.buffer.asciiSlice(this.start, this.end)],
|
||||
this.buffer.slice(this.start, this.end),
|
||||
this.length(),
|
||||
this.sequenceId
|
||||
);
|
||||
}
|
||||
|
||||
haveMoreData() {
|
||||
return this.end > this.offset;
|
||||
}
|
||||
|
||||
skip(num) {
|
||||
this.offset += num;
|
||||
}
|
||||
|
||||
readInt8() {
|
||||
return this.buffer[this.offset++];
|
||||
}
|
||||
|
||||
readInt16() {
|
||||
this.offset += 2;
|
||||
return this.buffer.readUInt16LE(this.offset - 2);
|
||||
}
|
||||
|
||||
readInt24() {
|
||||
return this.readInt16() + (this.readInt8() << 16);
|
||||
}
|
||||
|
||||
readInt32() {
|
||||
this.offset += 4;
|
||||
return this.buffer.readUInt32LE(this.offset - 4);
|
||||
}
|
||||
|
||||
readSInt8() {
|
||||
return this.buffer.readInt8(this.offset++);
|
||||
}
|
||||
|
||||
readSInt16() {
|
||||
this.offset += 2;
|
||||
return this.buffer.readInt16LE(this.offset - 2);
|
||||
}
|
||||
|
||||
readSInt32() {
|
||||
this.offset += 4;
|
||||
return this.buffer.readInt32LE(this.offset - 4);
|
||||
}
|
||||
|
||||
readInt64JSNumber() {
|
||||
const word0 = this.readInt32();
|
||||
const word1 = this.readInt32();
|
||||
const l = new Long(word0, word1, true);
|
||||
return l.toNumber();
|
||||
}
|
||||
|
||||
readSInt64JSNumber() {
|
||||
const word0 = this.readInt32();
|
||||
const word1 = this.readInt32();
|
||||
if (!(word1 & 0x80000000)) {
|
||||
return word0 + 0x100000000 * word1;
|
||||
}
|
||||
const l = new Long(word0, word1, false);
|
||||
return l.toNumber();
|
||||
}
|
||||
|
||||
readInt64String() {
|
||||
const word0 = this.readInt32();
|
||||
const word1 = this.readInt32();
|
||||
const res = new Long(word0, word1, true);
|
||||
return res.toString();
|
||||
}
|
||||
|
||||
readSInt64String() {
|
||||
const word0 = this.readInt32();
|
||||
const word1 = this.readInt32();
|
||||
const res = new Long(word0, word1, false);
|
||||
return res.toString();
|
||||
}
|
||||
|
||||
readInt64() {
|
||||
const word0 = this.readInt32();
|
||||
const word1 = this.readInt32();
|
||||
let res = new Long(word0, word1, true);
|
||||
const resNumber = res.toNumber();
|
||||
const resString = res.toString();
|
||||
res = resNumber.toString() === resString ? resNumber : resString;
|
||||
return res;
|
||||
}
|
||||
|
||||
readSInt64() {
|
||||
const word0 = this.readInt32();
|
||||
const word1 = this.readInt32();
|
||||
let res = new Long(word0, word1, false);
|
||||
const resNumber = res.toNumber();
|
||||
const resString = res.toString();
|
||||
res = resNumber.toString() === resString ? resNumber : resString;
|
||||
return res;
|
||||
}
|
||||
|
||||
isEOF() {
|
||||
return this.buffer[this.offset] === 0xfe && this.length() < 13;
|
||||
}
|
||||
|
||||
eofStatusFlags() {
|
||||
return this.buffer.readInt16LE(this.offset + 3);
|
||||
}
|
||||
|
||||
eofWarningCount() {
|
||||
return this.buffer.readInt16LE(this.offset + 1);
|
||||
}
|
||||
|
||||
readLengthCodedNumber(bigNumberStrings, signed) {
|
||||
const byte1 = this.buffer[this.offset++];
|
||||
if (byte1 < 251) {
|
||||
return byte1;
|
||||
}
|
||||
return this.readLengthCodedNumberExt(byte1, bigNumberStrings, signed);
|
||||
}
|
||||
|
||||
readLengthCodedNumberSigned(bigNumberStrings) {
|
||||
return this.readLengthCodedNumber(bigNumberStrings, true);
|
||||
}
|
||||
|
||||
readLengthCodedNumberExt(tag, bigNumberStrings, signed) {
|
||||
let word0, word1;
|
||||
let res;
|
||||
if (tag === 0xfb) {
|
||||
return null;
|
||||
}
|
||||
if (tag === 0xfc) {
|
||||
return this.readInt8() + (this.readInt8() << 8);
|
||||
}
|
||||
if (tag === 0xfd) {
|
||||
return this.readInt8() + (this.readInt8() << 8) + (this.readInt8() << 16);
|
||||
}
|
||||
if (tag === 0xfe) {
|
||||
// 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 Long(word0, word1, !signed); // Long need unsigned
|
||||
const resNumber = res.toNumber();
|
||||
const resString = res.toString();
|
||||
res = resNumber.toString() === resString ? resNumber : resString;
|
||||
return bigNumberStrings ? resString : res;
|
||||
}
|
||||
// eslint-disable-next-line no-console
|
||||
console.trace();
|
||||
throw new Error(`Should not reach here: ${tag}`);
|
||||
}
|
||||
|
||||
readFloat() {
|
||||
const res = this.buffer.readFloatLE(this.offset);
|
||||
this.offset += 4;
|
||||
return res;
|
||||
}
|
||||
|
||||
readDouble() {
|
||||
const res = this.buffer.readDoubleLE(this.offset);
|
||||
this.offset += 8;
|
||||
return res;
|
||||
}
|
||||
|
||||
readBuffer(len) {
|
||||
if (typeof len === 'undefined') {
|
||||
len = this.end - this.offset;
|
||||
}
|
||||
this.offset += len;
|
||||
return this.buffer.slice(this.offset - len, this.offset);
|
||||
}
|
||||
|
||||
// DATE, DATETIME and TIMESTAMP
|
||||
readDateTime(timezone) {
|
||||
if (!timezone || timezone === 'Z' || timezone === 'local') {
|
||||
const length = this.readInt8();
|
||||
if (length === 0xfb) {
|
||||
return null;
|
||||
}
|
||||
let y = 0;
|
||||
let m = 0;
|
||||
let d = 0;
|
||||
let H = 0;
|
||||
let M = 0;
|
||||
let S = 0;
|
||||
let ms = 0;
|
||||
if (length > 3) {
|
||||
y = this.readInt16();
|
||||
m = this.readInt8();
|
||||
d = this.readInt8();
|
||||
}
|
||||
if (length > 6) {
|
||||
H = this.readInt8();
|
||||
M = this.readInt8();
|
||||
S = this.readInt8();
|
||||
}
|
||||
if (length > 10) {
|
||||
ms = this.readInt32() / 1000;
|
||||
}
|
||||
if (y + m + d + H + M + S + ms === 0) {
|
||||
return INVALID_DATE;
|
||||
}
|
||||
if (timezone === 'Z') {
|
||||
return new Date(Date.UTC(y, m - 1, d, H, M, S, ms));
|
||||
}
|
||||
return new Date(y, m - 1, d, H, M, S, ms);
|
||||
}
|
||||
let str = this.readDateTimeString(6, 'T');
|
||||
if (str.length === 10) {
|
||||
str += 'T00:00:00';
|
||||
}
|
||||
return new Date(str + timezone);
|
||||
}
|
||||
|
||||
readDateTimeString(decimals, timeSep) {
|
||||
const length = this.readInt8();
|
||||
let y = 0;
|
||||
let m = 0;
|
||||
let d = 0;
|
||||
let H = 0;
|
||||
let M = 0;
|
||||
let S = 0;
|
||||
let ms = 0;
|
||||
let str;
|
||||
if (length > 3) {
|
||||
y = this.readInt16();
|
||||
m = this.readInt8();
|
||||
d = this.readInt8();
|
||||
str = [leftPad(4, y), leftPad(2, m), leftPad(2, d)].join('-');
|
||||
}
|
||||
if (length > 6) {
|
||||
H = this.readInt8();
|
||||
M = this.readInt8();
|
||||
S = this.readInt8();
|
||||
str += `${timeSep || ' '}${[
|
||||
leftPad(2, H),
|
||||
leftPad(2, M),
|
||||
leftPad(2, S)
|
||||
].join(':')}`;
|
||||
}
|
||||
if (length > 10) {
|
||||
ms = this.readInt32();
|
||||
str += '.';
|
||||
if (decimals) {
|
||||
ms = leftPad(6, ms);
|
||||
if (ms.length > decimals) {
|
||||
ms = ms.substring(0, decimals); // rounding is done at the MySQL side, only 0 are here
|
||||
}
|
||||
}
|
||||
str += ms;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
// TIME - value as a string, Can be negative
|
||||
readTimeString(convertTtoMs) {
|
||||
const length = this.readInt8();
|
||||
if (length === 0) {
|
||||
return '00:00:00';
|
||||
}
|
||||
const sign = this.readInt8() ? -1 : 1; // 'isNegative' flag byte
|
||||
let d = 0;
|
||||
let H = 0;
|
||||
let M = 0;
|
||||
let S = 0;
|
||||
let ms = 0;
|
||||
if (length > 6) {
|
||||
d = this.readInt32();
|
||||
H = this.readInt8();
|
||||
M = this.readInt8();
|
||||
S = this.readInt8();
|
||||
}
|
||||
if (length > 10) {
|
||||
ms = this.readInt32();
|
||||
}
|
||||
if (convertTtoMs) {
|
||||
H += d * 24;
|
||||
M += H * 60;
|
||||
S += M * 60;
|
||||
ms += S * 1000;
|
||||
ms *= sign;
|
||||
return ms;
|
||||
}
|
||||
return (
|
||||
(sign === -1 ? '-' : '') +
|
||||
[d ? d * 24 + H : H, leftPad(2, M), leftPad(2, S)].join(':') +
|
||||
(ms ? `.${ms}` : '')
|
||||
);
|
||||
}
|
||||
|
||||
readLengthCodedString(encoding) {
|
||||
const len = this.readLengthCodedNumber();
|
||||
// TODO: check manually first byte here to avoid polymorphic return type?
|
||||
if (len === null) {
|
||||
return null;
|
||||
}
|
||||
this.offset += len;
|
||||
// TODO: Use characterSetCode to get proper encoding
|
||||
// https://github.com/sidorares/node-mysql2/pull/374
|
||||
return StringParser.decode(
|
||||
this.buffer.slice(this.offset - len, this.offset),
|
||||
encoding
|
||||
);
|
||||
}
|
||||
|
||||
readLengthCodedBuffer() {
|
||||
const len = this.readLengthCodedNumber();
|
||||
if (len === null) {
|
||||
return null;
|
||||
}
|
||||
return this.readBuffer(len);
|
||||
}
|
||||
|
||||
readNullTerminatedString(encoding) {
|
||||
const start = this.offset;
|
||||
let end = this.offset;
|
||||
while (this.buffer[end]) {
|
||||
end = end + 1; // TODO: handle OOB check
|
||||
}
|
||||
this.offset = end + 1;
|
||||
return StringParser.decode(this.buffer.slice(start, end), encoding);
|
||||
}
|
||||
|
||||
// TODO reuse?
|
||||
readString(len, encoding) {
|
||||
if ((typeof len === 'string') && (typeof encoding === 'undefined')) {
|
||||
encoding = len
|
||||
len = undefined
|
||||
}
|
||||
if (typeof len === 'undefined') {
|
||||
len = this.end - this.offset;
|
||||
}
|
||||
this.offset += len;
|
||||
return StringParser.decode(
|
||||
this.buffer.slice(this.offset - len, this.offset),
|
||||
encoding
|
||||
);
|
||||
}
|
||||
|
||||
parseInt(len, supportBigNumbers) {
|
||||
if (len === null) {
|
||||
return null;
|
||||
}
|
||||
if (len >= 14 && !supportBigNumbers) {
|
||||
const s = this.buffer.toString('ascii', this.offset, this.offset + len);
|
||||
this.offset += len;
|
||||
return Number(s);
|
||||
}
|
||||
let result = 0;
|
||||
const start = this.offset;
|
||||
const end = this.offset + len;
|
||||
let sign = 1;
|
||||
if (len === 0) {
|
||||
return 0; // TODO: assert? exception?
|
||||
}
|
||||
if (this.buffer[this.offset] === minus) {
|
||||
this.offset++;
|
||||
sign = -1;
|
||||
}
|
||||
// max precise int is 9007199254740992
|
||||
let str;
|
||||
const numDigits = end - this.offset;
|
||||
if (supportBigNumbers) {
|
||||
if (numDigits >= 15) {
|
||||
str = this.readString(end - this.offset, 'binary');
|
||||
result = parseInt(str, 10);
|
||||
if (result.toString() === str) {
|
||||
return sign * result;
|
||||
}
|
||||
return sign === -1 ? `-${str}` : str;
|
||||
}
|
||||
if (numDigits > 16) {
|
||||
str = this.readString(end - this.offset);
|
||||
return sign === -1 ? `-${str}` : str;
|
||||
}
|
||||
}
|
||||
if (this.buffer[this.offset] === plus) {
|
||||
this.offset++; // just ignore
|
||||
}
|
||||
while (this.offset < end) {
|
||||
result *= 10;
|
||||
result += this.buffer[this.offset] - 48;
|
||||
this.offset++;
|
||||
}
|
||||
const num = result * sign;
|
||||
if (!supportBigNumbers) {
|
||||
return num;
|
||||
}
|
||||
str = this.buffer.toString('ascii', start, end);
|
||||
if (num.toString() === str) {
|
||||
return num;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
// note that if value of inputNumberAsString is bigger than MAX_SAFE_INTEGER
|
||||
// ( or smaller than MIN_SAFE_INTEGER ) the parseIntNoBigCheck result might be
|
||||
// different from what you would get from Number(inputNumberAsString)
|
||||
// String(parseIntNoBigCheck) <> String(Number(inputNumberAsString)) <> inputNumberAsString
|
||||
parseIntNoBigCheck(len) {
|
||||
if (len === null) {
|
||||
return null;
|
||||
}
|
||||
let result = 0;
|
||||
const end = this.offset + len;
|
||||
let sign = 1;
|
||||
if (len === 0) {
|
||||
return 0; // TODO: assert? exception?
|
||||
}
|
||||
if (this.buffer[this.offset] === minus) {
|
||||
this.offset++;
|
||||
sign = -1;
|
||||
}
|
||||
if (this.buffer[this.offset] === plus) {
|
||||
this.offset++; // just ignore
|
||||
}
|
||||
while (this.offset < end) {
|
||||
result *= 10;
|
||||
result += this.buffer[this.offset] - 48;
|
||||
this.offset++;
|
||||
}
|
||||
return result * sign;
|
||||
}
|
||||
|
||||
// copy-paste from https://github.com/mysqljs/mysql/blob/master/lib/protocol/Parser.js
|
||||
parseGeometryValue() {
|
||||
const buffer = this.readLengthCodedBuffer();
|
||||
let offset = 4;
|
||||
if (buffer === null || !buffer.length) {
|
||||
return null;
|
||||
}
|
||||
function parseGeometry() {
|
||||
let x, y, i, j, numPoints, line;
|
||||
let result = null;
|
||||
const byteOrder = buffer.readUInt8(offset);
|
||||
offset += 1;
|
||||
const wkbType = byteOrder
|
||||
? buffer.readUInt32LE(offset)
|
||||
: buffer.readUInt32BE(offset);
|
||||
offset += 4;
|
||||
switch (wkbType) {
|
||||
case 1: // WKBPoint
|
||||
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
|
||||
numPoints = byteOrder
|
||||
? buffer.readUInt32LE(offset)
|
||||
: buffer.readUInt32BE(offset);
|
||||
offset += 4;
|
||||
result = [];
|
||||
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
|
||||
// eslint-disable-next-line no-case-declarations
|
||||
const numRings = byteOrder
|
||||
? buffer.readUInt32LE(offset)
|
||||
: buffer.readUInt32BE(offset);
|
||||
offset += 4;
|
||||
result = [];
|
||||
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);
|
||||
}
|
||||
break;
|
||||
case 4: // WKBMultiPoint
|
||||
case 5: // WKBMultiLineString
|
||||
case 6: // WKBMultiPolygon
|
||||
case 7: // WKBGeometryCollection
|
||||
// eslint-disable-next-line no-case-declarations
|
||||
const num = byteOrder
|
||||
? buffer.readUInt32LE(offset)
|
||||
: buffer.readUInt32BE(offset);
|
||||
offset += 4;
|
||||
result = [];
|
||||
for (i = num; i > 0; i--) {
|
||||
result.push(parseGeometry());
|
||||
}
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return parseGeometry();
|
||||
}
|
||||
|
||||
parseDate(timezone) {
|
||||
const strLen = this.readLengthCodedNumber();
|
||||
if (strLen === null) {
|
||||
return null;
|
||||
}
|
||||
if (strLen !== 10) {
|
||||
// we expect only YYYY-MM-DD here.
|
||||
// if for some reason it's not the case return invalid date
|
||||
return new Date(NaN);
|
||||
}
|
||||
const y = this.parseInt(4);
|
||||
this.offset++; // -
|
||||
const m = this.parseInt(2);
|
||||
this.offset++; // -
|
||||
const d = this.parseInt(2);
|
||||
if (!timezone || timezone === 'local') {
|
||||
return new Date(y, m - 1, d);
|
||||
}
|
||||
if (timezone === 'Z') {
|
||||
return new Date(Date.UTC(y, m - 1, d));
|
||||
}
|
||||
return new Date(
|
||||
`${leftPad(4, y)}-${leftPad(2, m)}-${leftPad(2, d)}T00:00:00${timezone}`
|
||||
);
|
||||
}
|
||||
|
||||
parseDateTime(timezone) {
|
||||
const str = this.readLengthCodedString('binary');
|
||||
if (str === null) {
|
||||
return null;
|
||||
}
|
||||
if (!timezone || timezone === 'local') {
|
||||
return new Date(str);
|
||||
}
|
||||
return new Date(`${str}${timezone}`);
|
||||
}
|
||||
|
||||
parseFloat(len) {
|
||||
if (len === null) {
|
||||
return null;
|
||||
}
|
||||
let result = 0;
|
||||
const end = this.offset + len;
|
||||
let factor = 1;
|
||||
let pastDot = false;
|
||||
let charCode = 0;
|
||||
if (len === 0) {
|
||||
return 0; // TODO: assert? exception?
|
||||
}
|
||||
if (this.buffer[this.offset] === minus) {
|
||||
this.offset++;
|
||||
factor = -1;
|
||||
}
|
||||
if (this.buffer[this.offset] === plus) {
|
||||
this.offset++; // just ignore
|
||||
}
|
||||
while (this.offset < end) {
|
||||
charCode = this.buffer[this.offset];
|
||||
if (charCode === dot) {
|
||||
pastDot = true;
|
||||
this.offset++;
|
||||
} else if (charCode === exponent || charCode === exponentCapital) {
|
||||
this.offset++;
|
||||
const exponentValue = this.parseInt(end - this.offset);
|
||||
return (result / factor) * Math.pow(10, exponentValue);
|
||||
} else {
|
||||
result *= 10;
|
||||
result += this.buffer[this.offset] - 48;
|
||||
this.offset++;
|
||||
if (pastDot) {
|
||||
factor = factor * 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result / factor;
|
||||
}
|
||||
|
||||
parseLengthCodedIntNoBigCheck() {
|
||||
return this.parseIntNoBigCheck(this.readLengthCodedNumber());
|
||||
}
|
||||
|
||||
parseLengthCodedInt(supportBigNumbers) {
|
||||
return this.parseInt(this.readLengthCodedNumber(), supportBigNumbers);
|
||||
}
|
||||
|
||||
parseLengthCodedIntString() {
|
||||
return this.readLengthCodedString('binary');
|
||||
}
|
||||
|
||||
parseLengthCodedFloat() {
|
||||
return this.parseFloat(this.readLengthCodedNumber());
|
||||
}
|
||||
|
||||
peekByte() {
|
||||
return this.buffer[this.offset];
|
||||
}
|
||||
|
||||
// OxFE is often used as "Alt" flag - not ok, not error.
|
||||
// For example, it's first byte of AuthSwitchRequest
|
||||
isAlt() {
|
||||
return this.peekByte() === 0xfe;
|
||||
}
|
||||
|
||||
isError() {
|
||||
return this.peekByte() === 0xff;
|
||||
}
|
||||
|
||||
asError(encoding) {
|
||||
this.reset();
|
||||
this.readInt8(); // fieldCount
|
||||
const errorCode = this.readInt16();
|
||||
let sqlState = '';
|
||||
if (this.buffer[this.offset] === 0x23) {
|
||||
this.skip(1);
|
||||
sqlState = this.readBuffer(5).toString();
|
||||
}
|
||||
const message = this.readString(undefined, encoding);
|
||||
const err = new Error(message);
|
||||
err.code = ErrorCodeToName[errorCode];
|
||||
err.errno = errorCode;
|
||||
err.sqlState = sqlState;
|
||||
err.sqlMessage = message;
|
||||
return err;
|
||||
}
|
||||
|
||||
writeInt32(n) {
|
||||
this.buffer.writeUInt32LE(n, this.offset);
|
||||
this.offset += 4;
|
||||
}
|
||||
|
||||
writeInt24(n) {
|
||||
this.writeInt8(n & 0xff);
|
||||
this.writeInt16(n >> 8);
|
||||
}
|
||||
|
||||
writeInt16(n) {
|
||||
this.buffer.writeUInt16LE(n, this.offset);
|
||||
this.offset += 2;
|
||||
}
|
||||
|
||||
writeInt8(n) {
|
||||
this.buffer.writeUInt8(n, this.offset);
|
||||
this.offset++;
|
||||
}
|
||||
|
||||
writeDouble(n) {
|
||||
this.buffer.writeDoubleLE(n, this.offset);
|
||||
this.offset += 8;
|
||||
}
|
||||
|
||||
writeBuffer(b) {
|
||||
b.copy(this.buffer, this.offset);
|
||||
this.offset += b.length;
|
||||
}
|
||||
|
||||
writeNull() {
|
||||
this.buffer[this.offset] = 0xfb;
|
||||
this.offset++;
|
||||
}
|
||||
|
||||
// TODO: refactor following three?
|
||||
writeNullTerminatedString(s, encoding) {
|
||||
const buf = StringParser.encode(s, encoding);
|
||||
this.buffer.length && buf.copy(this.buffer, this.offset);
|
||||
this.offset += buf.length;
|
||||
this.writeInt8(0);
|
||||
}
|
||||
|
||||
writeString(s, encoding) {
|
||||
if (s === null) {
|
||||
this.writeInt8(0xfb);
|
||||
return;
|
||||
}
|
||||
if (s.length === 0) {
|
||||
return;
|
||||
}
|
||||
// const bytes = Buffer.byteLength(s, 'utf8');
|
||||
// this.buffer.write(s, this.offset, bytes, 'utf8');
|
||||
// this.offset += bytes;
|
||||
const buf = StringParser.encode(s, encoding);
|
||||
this.buffer.length && buf.copy(this.buffer, this.offset);
|
||||
this.offset += buf.length;
|
||||
}
|
||||
|
||||
writeLengthCodedString(s, encoding) {
|
||||
const buf = StringParser.encode(s, encoding);
|
||||
this.writeLengthCodedNumber(buf.length);
|
||||
this.buffer.length && buf.copy(this.buffer, this.offset);
|
||||
this.offset += buf.length;
|
||||
}
|
||||
|
||||
writeLengthCodedBuffer(b) {
|
||||
this.writeLengthCodedNumber(b.length);
|
||||
b.copy(this.buffer, this.offset);
|
||||
this.offset += b.length;
|
||||
}
|
||||
|
||||
writeLengthCodedNumber(n) {
|
||||
if (n < 0xfb) {
|
||||
return this.writeInt8(n);
|
||||
}
|
||||
if (n < 0xffff) {
|
||||
this.writeInt8(0xfc);
|
||||
return this.writeInt16(n);
|
||||
}
|
||||
if (n < 0xffffff) {
|
||||
this.writeInt8(0xfd);
|
||||
return this.writeInt24(n);
|
||||
}
|
||||
if (n === null) {
|
||||
return this.writeInt8(0xfb);
|
||||
}
|
||||
// TODO: check that n is out of int precision
|
||||
this.writeInt8(0xfe);
|
||||
this.buffer.writeUInt32LE(n, this.offset);
|
||||
this.offset += 4;
|
||||
this.buffer.writeUInt32LE(n >> 32, this.offset);
|
||||
this.offset += 4;
|
||||
return this.offset;
|
||||
}
|
||||
|
||||
writeDate(d, timezone) {
|
||||
this.buffer.writeUInt8(11, this.offset);
|
||||
if (!timezone || timezone === 'local') {
|
||||
this.buffer.writeUInt16LE(d.getFullYear(), this.offset + 1);
|
||||
this.buffer.writeUInt8(d.getMonth() + 1, this.offset + 3);
|
||||
this.buffer.writeUInt8(d.getDate(), this.offset + 4);
|
||||
this.buffer.writeUInt8(d.getHours(), this.offset + 5);
|
||||
this.buffer.writeUInt8(d.getMinutes(), this.offset + 6);
|
||||
this.buffer.writeUInt8(d.getSeconds(), this.offset + 7);
|
||||
this.buffer.writeUInt32LE(d.getMilliseconds() * 1000, this.offset + 8);
|
||||
} else {
|
||||
if (timezone !== 'Z') {
|
||||
const offset =
|
||||
(timezone[0] === '-' ? -1 : 1) *
|
||||
(parseInt(timezone.substring(1, 3), 10) * 60 +
|
||||
parseInt(timezone.substring(4), 10));
|
||||
if (offset !== 0) {
|
||||
d = new Date(d.getTime() + 60000 * offset);
|
||||
}
|
||||
}
|
||||
this.buffer.writeUInt16LE(d.getUTCFullYear(), this.offset + 1);
|
||||
this.buffer.writeUInt8(d.getUTCMonth() + 1, this.offset + 3);
|
||||
this.buffer.writeUInt8(d.getUTCDate(), this.offset + 4);
|
||||
this.buffer.writeUInt8(d.getUTCHours(), this.offset + 5);
|
||||
this.buffer.writeUInt8(d.getUTCMinutes(), this.offset + 6);
|
||||
this.buffer.writeUInt8(d.getUTCSeconds(), this.offset + 7);
|
||||
this.buffer.writeUInt32LE(d.getUTCMilliseconds() * 1000, this.offset + 8);
|
||||
}
|
||||
this.offset += 12;
|
||||
}
|
||||
|
||||
writeHeader(sequenceId) {
|
||||
const offset = this.offset;
|
||||
this.offset = 0;
|
||||
this.writeInt24(this.buffer.length - 4);
|
||||
this.writeInt8(sequenceId);
|
||||
this.offset = offset;
|
||||
}
|
||||
|
||||
clone() {
|
||||
return new Packet(this.sequenceId, this.buffer, this.start, this.end);
|
||||
}
|
||||
|
||||
type() {
|
||||
if (this.isEOF()) {
|
||||
return 'EOF';
|
||||
}
|
||||
if (this.isError()) {
|
||||
return 'Error';
|
||||
}
|
||||
if (this.buffer[this.offset] === 0) {
|
||||
return 'maybeOK'; // could be other packet types as well
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
static lengthCodedNumberLength(n) {
|
||||
if (n < 0xfb) {
|
||||
return 1;
|
||||
}
|
||||
if (n < 0xffff) {
|
||||
return 3;
|
||||
}
|
||||
if (n < 0xffffff) {
|
||||
return 5;
|
||||
}
|
||||
return 9;
|
||||
}
|
||||
|
||||
static lengthCodedStringLength(str, encoding) {
|
||||
const buf = StringParser.encode(str, encoding);
|
||||
const slen = buf.length;
|
||||
return Packet.lengthCodedNumberLength(slen) + slen;
|
||||
}
|
||||
|
||||
static MockBuffer() {
|
||||
const noop = function() {};
|
||||
const res = Buffer.alloc(0);
|
||||
for (const op in NativeBuffer.prototype) {
|
||||
if (typeof res[op] === 'function') {
|
||||
res[op] = noop;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Packet;
|
27
node_modules/mysql2/lib/packets/prepare_statement.js
generated
vendored
Normal file
27
node_modules/mysql2/lib/packets/prepare_statement.js
generated
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
'use strict';
|
||||
|
||||
const Packet = require('../packets/packet');
|
||||
const CommandCodes = require('../constants/commands');
|
||||
const StringParser = require('../parsers/string.js');
|
||||
const CharsetToEncoding = require('../constants/charset_encodings.js');
|
||||
|
||||
class PrepareStatement {
|
||||
constructor(sql, charsetNumber) {
|
||||
this.query = sql;
|
||||
this.charsetNumber = charsetNumber;
|
||||
this.encoding = CharsetToEncoding[charsetNumber];
|
||||
}
|
||||
|
||||
toPacket() {
|
||||
const buf = StringParser.encode(this.query, this.encoding);
|
||||
const length = 5 + buf.length;
|
||||
const buffer = Buffer.allocUnsafe(length);
|
||||
const packet = new Packet(0, buffer, 0, length);
|
||||
packet.offset = 4;
|
||||
packet.writeInt8(CommandCodes.STMT_PREPARE);
|
||||
packet.writeBuffer(buf);
|
||||
return packet;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = PrepareStatement;
|
16
node_modules/mysql2/lib/packets/prepared_statement_header.js
generated
vendored
Normal file
16
node_modules/mysql2/lib/packets/prepared_statement_header.js
generated
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
'use strict';
|
||||
|
||||
class PreparedStatementHeader {
|
||||
constructor(packet) {
|
||||
packet.skip(1); // should be 0
|
||||
this.id = packet.readInt32();
|
||||
this.fieldCount = packet.readInt16();
|
||||
this.parameterCount = packet.readInt16();
|
||||
packet.skip(1); // should be 0
|
||||
this.warningCount = packet.readInt16();
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: toPacket
|
||||
|
||||
module.exports = PreparedStatementHeader;
|
27
node_modules/mysql2/lib/packets/query.js
generated
vendored
Normal file
27
node_modules/mysql2/lib/packets/query.js
generated
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
'use strict';
|
||||
|
||||
const Packet = require('../packets/packet.js');
|
||||
const CommandCode = require('../constants/commands.js');
|
||||
const StringParser = require('../parsers/string.js');
|
||||
const CharsetToEncoding = require('../constants/charset_encodings.js');
|
||||
|
||||
class Query {
|
||||
constructor(sql, charsetNumber) {
|
||||
this.query = sql;
|
||||
this.charsetNumber = charsetNumber;
|
||||
this.encoding = CharsetToEncoding[charsetNumber];
|
||||
}
|
||||
|
||||
toPacket() {
|
||||
const buf = StringParser.encode(this.query, this.encoding);
|
||||
const length = 5 + buf.length;
|
||||
const buffer = Buffer.allocUnsafe(length);
|
||||
const packet = new Packet(0, buffer, 0, length);
|
||||
packet.offset = 4;
|
||||
packet.writeInt8(CommandCode.QUERY);
|
||||
packet.writeBuffer(buf);
|
||||
return packet;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Query;
|
46
node_modules/mysql2/lib/packets/register_slave.js
generated
vendored
Normal file
46
node_modules/mysql2/lib/packets/register_slave.js
generated
vendored
Normal file
@ -0,0 +1,46 @@
|
||||
'use strict';
|
||||
|
||||
// http://dev.mysql.com/doc/internals/en/com-register-slave.html
|
||||
// note that documentation is incorrect, for example command code is actually 0x15 but documented as 0x14
|
||||
|
||||
const Packet = require('../packets/packet');
|
||||
const CommandCodes = require('../constants/commands');
|
||||
|
||||
class RegisterSlave {
|
||||
constructor(opts) {
|
||||
this.serverId = opts.serverId || 0;
|
||||
this.slaveHostname = opts.slaveHostname || '';
|
||||
this.slaveUser = opts.slaveUser || '';
|
||||
this.slavePassword = opts.slavePassword || '';
|
||||
this.slavePort = opts.slavePort || 0;
|
||||
this.replicationRank = opts.replicationRank || 0;
|
||||
this.masterId = opts.masterId || 0;
|
||||
}
|
||||
|
||||
toPacket() {
|
||||
const length =
|
||||
15 + // TODO: should be ascii?
|
||||
Buffer.byteLength(this.slaveHostname, 'utf8') +
|
||||
Buffer.byteLength(this.slaveUser, 'utf8') +
|
||||
Buffer.byteLength(this.slavePassword, 'utf8') +
|
||||
3 +
|
||||
4;
|
||||
const buffer = Buffer.allocUnsafe(length);
|
||||
const packet = new Packet(0, buffer, 0, length);
|
||||
packet.offset = 4;
|
||||
packet.writeInt8(CommandCodes.REGISTER_SLAVE);
|
||||
packet.writeInt32(this.serverId);
|
||||
packet.writeInt8(Buffer.byteLength(this.slaveHostname, 'utf8'));
|
||||
packet.writeString(this.slaveHostname);
|
||||
packet.writeInt8(Buffer.byteLength(this.slaveUser, 'utf8'));
|
||||
packet.writeString(this.slaveUser);
|
||||
packet.writeInt8(Buffer.byteLength(this.slavePassword, 'utf8'));
|
||||
packet.writeString(this.slavePassword);
|
||||
packet.writeInt16(this.slavePort);
|
||||
packet.writeInt32(this.replicationRank);
|
||||
packet.writeInt32(this.masterId);
|
||||
return packet;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = RegisterSlave;
|
110
node_modules/mysql2/lib/packets/resultset_header.js
generated
vendored
Normal file
110
node_modules/mysql2/lib/packets/resultset_header.js
generated
vendored
Normal file
@ -0,0 +1,110 @@
|
||||
'use strict';
|
||||
|
||||
// TODO: rename to OK packet
|
||||
// https://dev.mysql.com/doc/internals/en/packet-OK_Packet.html
|
||||
|
||||
const Packet = require('./packet.js');
|
||||
const ClientConstants = require('../constants/client.js');
|
||||
const ServerSatusFlags = require('../constants/server_status.js');
|
||||
|
||||
const EncodingToCharset = require('../constants/encoding_charset.js');
|
||||
const sessionInfoTypes = require('../constants/session_track.js');
|
||||
|
||||
class ResultSetHeader {
|
||||
constructor(packet, connection) {
|
||||
const bigNumberStrings = connection.config.bigNumberStrings;
|
||||
const encoding = connection.serverEncoding;
|
||||
const flags = connection._handshakePacket.capabilityFlags;
|
||||
const isSet = function(flag) {
|
||||
return flags & ClientConstants[flag];
|
||||
};
|
||||
if (packet.buffer[packet.offset] !== 0) {
|
||||
this.fieldCount = packet.readLengthCodedNumber();
|
||||
if (this.fieldCount === null) {
|
||||
this.infileName = packet.readString(undefined, encoding);
|
||||
}
|
||||
return;
|
||||
}
|
||||
this.fieldCount = packet.readInt8(); // skip OK byte
|
||||
this.affectedRows = packet.readLengthCodedNumber(bigNumberStrings);
|
||||
this.insertId = packet.readLengthCodedNumberSigned(bigNumberStrings);
|
||||
this.info = '';
|
||||
if (isSet('PROTOCOL_41')) {
|
||||
this.serverStatus = packet.readInt16();
|
||||
this.warningStatus = packet.readInt16();
|
||||
} else if (isSet('TRANSACTIONS')) {
|
||||
this.serverStatus = packet.readInt16();
|
||||
}
|
||||
let stateChanges = null;
|
||||
if (isSet('SESSION_TRACK') && packet.offset < packet.end) {
|
||||
this.info = packet.readLengthCodedString(encoding);
|
||||
|
||||
if (this.serverStatus && ServerSatusFlags.SERVER_SESSION_STATE_CHANGED) {
|
||||
// session change info record - see
|
||||
// https://dev.mysql.com/doc/internals/en/packet-OK_Packet.html#cs-sect-packet-ok-sessioninfo
|
||||
let len =
|
||||
packet.offset < packet.end ? packet.readLengthCodedNumber() : 0;
|
||||
const end = packet.offset + len;
|
||||
let type, key, stateEnd;
|
||||
if (len > 0) {
|
||||
stateChanges = {
|
||||
systemVariables: {},
|
||||
schema: null,
|
||||
trackStateChange: null
|
||||
};
|
||||
}
|
||||
while (packet.offset < end) {
|
||||
type = packet.readInt8();
|
||||
len = packet.readLengthCodedNumber();
|
||||
stateEnd = packet.offset + len;
|
||||
if (type === sessionInfoTypes.SYSTEM_VARIABLES) {
|
||||
key = packet.readLengthCodedString(encoding);
|
||||
const val = packet.readLengthCodedString(encoding);
|
||||
stateChanges.systemVariables[key] = val;
|
||||
if (key === 'character_set_client') {
|
||||
const charsetNumber = EncodingToCharset[val];
|
||||
connection.config.charsetNumber = charsetNumber;
|
||||
}
|
||||
} else if (type === sessionInfoTypes.SCHEMA) {
|
||||
key = packet.readLengthCodedString(encoding);
|
||||
stateChanges.schema = key;
|
||||
} else if (type === sessionInfoTypes.STATE_CHANGE) {
|
||||
stateChanges.trackStateChange = packet.readLengthCodedString(
|
||||
encoding
|
||||
);
|
||||
} else {
|
||||
// unsupported session track type. For now just ignore
|
||||
}
|
||||
packet.offset = stateEnd;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.info = packet.readString(undefined, encoding);
|
||||
}
|
||||
if (stateChanges) {
|
||||
this.stateChanges = stateChanges;
|
||||
}
|
||||
const m = this.info.match(/\schanged:\s*(\d+)/i);
|
||||
if (m !== null) {
|
||||
this.changedRows = parseInt(m[1], 10);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: should be consistent instance member, but it's just easier here to have just function
|
||||
static toPacket(fieldCount, insertId) {
|
||||
let length = 4 + Packet.lengthCodedNumberLength(fieldCount);
|
||||
if (typeof insertId !== 'undefined') {
|
||||
length += Packet.lengthCodedNumberLength(insertId);
|
||||
}
|
||||
const buffer = Buffer.allocUnsafe(length);
|
||||
const packet = new Packet(0, buffer, 0, length);
|
||||
packet.offset = 4;
|
||||
packet.writeLengthCodedNumber(fieldCount);
|
||||
if (typeof insertId !== 'undefined') {
|
||||
packet.writeLengthCodedNumber(insertId);
|
||||
}
|
||||
return packet;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ResultSetHeader;
|
25
node_modules/mysql2/lib/packets/ssl_request.js
generated
vendored
Normal file
25
node_modules/mysql2/lib/packets/ssl_request.js
generated
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
'use strict';
|
||||
|
||||
const ClientConstants = require('../constants/client');
|
||||
const Packet = require('../packets/packet');
|
||||
|
||||
class SSLRequest {
|
||||
constructor(flags, charset) {
|
||||
this.clientFlags = flags | ClientConstants.SSL;
|
||||
this.charset = charset;
|
||||
}
|
||||
|
||||
toPacket() {
|
||||
const length = 36;
|
||||
const buffer = Buffer.allocUnsafe(length);
|
||||
const packet = new Packet(0, buffer, 0, length);
|
||||
buffer.fill(0);
|
||||
packet.offset = 4;
|
||||
packet.writeInt32(this.clientFlags);
|
||||
packet.writeInt32(0); // max packet size. todo: move to config
|
||||
packet.writeInt8(this.charset);
|
||||
return packet;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = SSLRequest;
|
47
node_modules/mysql2/lib/packets/text_row.js
generated
vendored
Normal file
47
node_modules/mysql2/lib/packets/text_row.js
generated
vendored
Normal file
@ -0,0 +1,47 @@
|
||||
'use strict';
|
||||
|
||||
const Packet = require('../packets/packet');
|
||||
|
||||
class TextRow {
|
||||
constructor(columns) {
|
||||
this.columns = columns || [];
|
||||
}
|
||||
|
||||
static fromPacket(packet) {
|
||||
// packet.reset(); // set offset to starting point?
|
||||
const columns = [];
|
||||
while (packet.haveMoreData()) {
|
||||
columns.push(packet.readLengthCodedString());
|
||||
}
|
||||
return new TextRow(columns);
|
||||
}
|
||||
|
||||
static toPacket(columns, encoding) {
|
||||
const sequenceId = 0; // TODO remove, this is calculated now in connecton
|
||||
let length = 0;
|
||||
columns.forEach(val => {
|
||||
if (val === null || typeof val === 'undefined') {
|
||||
++length;
|
||||
return;
|
||||
}
|
||||
length += Packet.lengthCodedStringLength(val.toString(10), encoding);
|
||||
});
|
||||
const buffer = Buffer.allocUnsafe(length + 4);
|
||||
const packet = new Packet(sequenceId, buffer, 0, length + 4);
|
||||
packet.offset = 4;
|
||||
columns.forEach(val => {
|
||||
if (val === null) {
|
||||
packet.writeNull();
|
||||
return;
|
||||
}
|
||||
if (typeof val === 'undefined') {
|
||||
packet.writeInt8(0);
|
||||
return;
|
||||
}
|
||||
packet.writeLengthCodedString(val.toString(10), encoding);
|
||||
});
|
||||
return packet;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = TextRow;
|
184
node_modules/mysql2/lib/parsers/binary_parser.js
generated
vendored
Normal file
184
node_modules/mysql2/lib/parsers/binary_parser.js
generated
vendored
Normal file
@ -0,0 +1,184 @@
|
||||
'use strict';
|
||||
|
||||
const FieldFlags = require('../constants/field_flags.js');
|
||||
const Charsets = require('../constants/charsets.js');
|
||||
const Types = require('../constants/types.js');
|
||||
const helpers = require('../helpers');
|
||||
const genFunc = require('generate-function');
|
||||
const parserCache = require('./parser_cache.js');
|
||||
const typeNames = [];
|
||||
for (const t in Types) {
|
||||
typeNames[Types[t]] = t;
|
||||
}
|
||||
|
||||
function readCodeFor(field, config, options, fieldNum) {
|
||||
const supportBigNumbers =
|
||||
options.supportBigNumbers || config.supportBigNumbers;
|
||||
const bigNumberStrings = options.bigNumberStrings || config.bigNumberStrings;
|
||||
const timezone = options.timezone || config.timezone;
|
||||
const dateStrings = options.dateStrings || config.dateStrings;
|
||||
const unsigned = field.flags & FieldFlags.UNSIGNED;
|
||||
switch (field.columnType) {
|
||||
case Types.TINY:
|
||||
return unsigned ? 'packet.readInt8();' : 'packet.readSInt8();';
|
||||
case Types.SHORT:
|
||||
return unsigned ? 'packet.readInt16();' : 'packet.readSInt16();';
|
||||
case Types.LONG:
|
||||
case Types.INT24: // in binary protocol int24 is encoded in 4 bytes int32
|
||||
return unsigned ? 'packet.readInt32();' : 'packet.readSInt32();';
|
||||
case Types.YEAR:
|
||||
return 'packet.readInt16()';
|
||||
case Types.FLOAT:
|
||||
return 'packet.readFloat();';
|
||||
case Types.DOUBLE:
|
||||
return 'packet.readDouble();';
|
||||
case Types.NULL:
|
||||
return 'null;';
|
||||
case Types.DATE:
|
||||
case Types.DATETIME:
|
||||
case Types.TIMESTAMP:
|
||||
case Types.NEWDATE:
|
||||
if (helpers.typeMatch(field.columnType, dateStrings, Types)) {
|
||||
return `packet.readDateTimeString(${field.decimals});`;
|
||||
}
|
||||
return `packet.readDateTime('${timezone}');`;
|
||||
case Types.TIME:
|
||||
return 'packet.readTimeString()';
|
||||
case Types.DECIMAL:
|
||||
case Types.NEWDECIMAL:
|
||||
if (config.decimalNumbers) {
|
||||
return 'packet.parseLengthCodedFloat();';
|
||||
}
|
||||
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"));';
|
||||
case Types.LONGLONG:
|
||||
if (!supportBigNumbers) {
|
||||
return unsigned
|
||||
? 'packet.readInt64JSNumber();'
|
||||
: 'packet.readSInt64JSNumber();';
|
||||
}
|
||||
if (bigNumberStrings) {
|
||||
return unsigned
|
||||
? 'packet.readInt64String();'
|
||||
: 'packet.readSInt64String();';
|
||||
}
|
||||
return unsigned ? 'packet.readInt64();' : 'packet.readSInt64();';
|
||||
|
||||
default:
|
||||
if (field.characterSet === Charsets.BINARY) {
|
||||
return 'packet.readLengthCodedBuffer();';
|
||||
}
|
||||
return `packet.readLengthCodedString(CharsetToEncoding[fields[${fieldNum}].characterSet])`;
|
||||
}
|
||||
}
|
||||
|
||||
function compile(fields, options, config) {
|
||||
const parserFn = genFunc();
|
||||
let i = 0;
|
||||
const nullBitmapLength = Math.floor((fields.length + 7 + 2) / 8);
|
||||
|
||||
/* eslint-disable no-trailing-spaces */
|
||||
/* eslint-disable no-spaced-func */
|
||||
/* eslint-disable no-unexpected-multiline */
|
||||
|
||||
parserFn('(function(){')(
|
||||
'return function BinaryRow(packet, fields, options, CharsetToEncoding) {'
|
||||
);
|
||||
|
||||
if (options.rowsAsArray) {
|
||||
parserFn(`const result = new Array(${fields.length});`);
|
||||
}
|
||||
|
||||
const resultTables = {};
|
||||
let resultTablesArray = [];
|
||||
|
||||
if (options.nestTables === true) {
|
||||
for (i = 0; i < fields.length; i++) {
|
||||
resultTables[fields[i].table] = 1;
|
||||
}
|
||||
resultTablesArray = Object.keys(resultTables);
|
||||
for (i = 0; i < resultTablesArray.length; i++) {
|
||||
parserFn(`this[${helpers.srcEscape(resultTablesArray[i])}] = {};`);
|
||||
}
|
||||
}
|
||||
|
||||
parserFn('packet.readInt8();'); // status byte
|
||||
for (i = 0; i < nullBitmapLength; ++i) {
|
||||
parserFn(`const nullBitmaskByte${i} = packet.readInt8();`);
|
||||
}
|
||||
|
||||
let lvalue = '';
|
||||
let currentFieldNullBit = 4;
|
||||
let nullByteIndex = 0;
|
||||
let fieldName = '';
|
||||
let tableName = '';
|
||||
|
||||
for (i = 0; i < fields.length; i++) {
|
||||
fieldName = helpers.srcEscape(fields[i].name);
|
||||
parserFn(`// ${fieldName}: ${typeNames[fields[i].columnType]}`);
|
||||
|
||||
if (typeof options.nestTables === 'string') {
|
||||
tableName = helpers.srcEscape(fields[i].table);
|
||||
lvalue = `this[${helpers.srcEscape(
|
||||
fields[i].table + options.nestTables + fields[i].name
|
||||
)}]`;
|
||||
} else if (options.nestTables === true) {
|
||||
tableName = helpers.srcEscape(fields[i].table);
|
||||
lvalue = `this[${tableName}][${fieldName}]`;
|
||||
} else if (options.rowsAsArray) {
|
||||
lvalue = `result[${i.toString(10)}]`;
|
||||
} else {
|
||||
lvalue = `this[${helpers.srcEscape(fields[i].name)}]`;
|
||||
}
|
||||
|
||||
// TODO: this used to be an optimisation ( if column marked as NOT_NULL don't include code to check null
|
||||
// bitmap at all, but it seems that we can't rely on this flag, see #178
|
||||
// TODO: benchmark performance difference
|
||||
//
|
||||
// if (fields[i].flags & FieldFlags.NOT_NULL) { // don't need to check null bitmap if field can't be null.
|
||||
// result.push(lvalue + ' = ' + readCodeFor(fields[i], config));
|
||||
// } else if (fields[i].columnType == Types.NULL) {
|
||||
// result.push(lvalue + ' = null;');
|
||||
// } else {
|
||||
parserFn(`if (nullBitmaskByte${nullByteIndex} & ${currentFieldNullBit})`);
|
||||
parserFn(`${lvalue} = null;`);
|
||||
parserFn('else');
|
||||
parserFn(`${lvalue} = ${readCodeFor(fields[i], config, options, i)}`);
|
||||
// }
|
||||
currentFieldNullBit *= 2;
|
||||
if (currentFieldNullBit === 0x100) {
|
||||
currentFieldNullBit = 1;
|
||||
nullByteIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
if (options.rowsAsArray) {
|
||||
parserFn('return result;');
|
||||
}
|
||||
|
||||
parserFn('};')('})()');
|
||||
|
||||
/* eslint-enable no-trailing-spaces */
|
||||
/* eslint-enable no-spaced-func */
|
||||
/* eslint-enable no-unexpected-multiline */
|
||||
|
||||
if (config.debug) {
|
||||
helpers.printDebugWithCode(
|
||||
'Compiled binary protocol row parser',
|
||||
parserFn.toString()
|
||||
);
|
||||
}
|
||||
return parserFn.toFunction();
|
||||
}
|
||||
|
||||
function getBinaryParser(fields, options, config) {
|
||||
return parserCache.getParser('binary', fields, options, config, compile);
|
||||
}
|
||||
|
||||
module.exports = getBinaryParser;
|
59
node_modules/mysql2/lib/parsers/parser_cache.js
generated
vendored
Normal file
59
node_modules/mysql2/lib/parsers/parser_cache.js
generated
vendored
Normal file
@ -0,0 +1,59 @@
|
||||
'use strict';
|
||||
|
||||
const LRU = require('lru-cache');
|
||||
|
||||
const parserCache = new LRU({
|
||||
max: 15000
|
||||
});
|
||||
|
||||
function keyFromFields(type, fields, options, config) {
|
||||
let res =
|
||||
`${type}` +
|
||||
`/${typeof options.nestTables}` +
|
||||
`/${options.nestTables}` +
|
||||
`/${options.rowsAsArray}` +
|
||||
`/${options.supportBigNumbers || config.supportBigNumbers}` +
|
||||
`/${options.bigNumberStrings || config.bigNumberStrings}` +
|
||||
`/${typeof options.typeCast}` +
|
||||
`/${options.timezone || config.timezone}` +
|
||||
`/${options.decimalNumbers}` +
|
||||
`/${options.dateStrings}`;
|
||||
for (let i = 0; i < fields.length; ++i) {
|
||||
const field = fields[i];
|
||||
res += `/${field.name}:${field.columnType}:${field.flags}:${
|
||||
field.characterSet
|
||||
}`;
|
||||
|
||||
if (options.nestTables) {
|
||||
res += `:${field.table}`
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
function getParser(type, fields, options, config, compiler) {
|
||||
const key = keyFromFields(type, fields, options, config);
|
||||
let parser = parserCache.get(key);
|
||||
|
||||
if (parser) {
|
||||
return parser;
|
||||
}
|
||||
|
||||
parser = compiler(fields, options, config);
|
||||
parserCache.set(key, parser);
|
||||
return parser;
|
||||
}
|
||||
|
||||
function setMaxCache(max) {
|
||||
parserCache.max = max;
|
||||
}
|
||||
|
||||
function clearCache() {
|
||||
parserCache.reset();
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getParser: getParser,
|
||||
setMaxCache: setMaxCache,
|
||||
clearCache: clearCache
|
||||
};
|
29
node_modules/mysql2/lib/parsers/string.js
generated
vendored
Normal file
29
node_modules/mysql2/lib/parsers/string.js
generated
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
'use strict';
|
||||
|
||||
const Iconv = require('iconv-lite');
|
||||
|
||||
exports.decode = function(buffer, encoding, options) {
|
||||
if (Buffer.isEncoding(encoding)) {
|
||||
return buffer.toString(encoding);
|
||||
}
|
||||
|
||||
const decoder = Iconv.getDecoder(encoding, options || {});
|
||||
|
||||
const res = decoder.write(buffer);
|
||||
const trail = decoder.end();
|
||||
|
||||
return trail ? res + trail : res;
|
||||
};
|
||||
|
||||
exports.encode = function(string, encoding, options) {
|
||||
if (Buffer.isEncoding(encoding)) {
|
||||
return Buffer.from(string, encoding);
|
||||
}
|
||||
|
||||
const encoder = Iconv.getEncoder(encoding, options || {});
|
||||
|
||||
const res = encoder.write(string);
|
||||
const trail = encoder.end();
|
||||
|
||||
return trail && trail.length > 0 ? Buffer.concat([res, trail]) : res;
|
||||
};
|
193
node_modules/mysql2/lib/parsers/text_parser.js
generated
vendored
Normal file
193
node_modules/mysql2/lib/parsers/text_parser.js
generated
vendored
Normal file
@ -0,0 +1,193 @@
|
||||
'use strict';
|
||||
|
||||
const Types = require('../constants/types.js');
|
||||
const Charsets = require('../constants/charsets.js');
|
||||
const helpers = require('../helpers');
|
||||
const genFunc = require('generate-function');
|
||||
const parserCache = require('./parser_cache.js');
|
||||
|
||||
const typeNames = [];
|
||||
for (const t in Types) {
|
||||
typeNames[Types[t]] = t;
|
||||
}
|
||||
|
||||
function readCodeFor(type, charset, encodingExpr, 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:
|
||||
return 'packet.readLengthCodedNumber()';
|
||||
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(${encodingExpr})`;
|
||||
}
|
||||
}
|
||||
|
||||
function compile(fields, options, config) {
|
||||
// node-mysql typeCast compatibility wrapper
|
||||
// see https://github.com/mysqljs/mysql/blob/96fdd0566b654436624e2375c7b6604b1f50f825/lib/protocol/packets/Field.js
|
||||
function wrap(field, type, packet, encoding) {
|
||||
return {
|
||||
type: type,
|
||||
length: field.columnLength,
|
||||
db: field.schema,
|
||||
table: field.table,
|
||||
name: field.name,
|
||||
string: function() {
|
||||
return packet.readLengthCodedString(encoding);
|
||||
},
|
||||
buffer: function() {
|
||||
return packet.readLengthCodedBuffer();
|
||||
},
|
||||
geometry: function() {
|
||||
return packet.parseGeometryValue();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// use global typeCast if current query doesn't specify one
|
||||
if (
|
||||
typeof config.typeCast === 'function' &&
|
||||
typeof options.typeCast !== 'function'
|
||||
) {
|
||||
options.typeCast = config.typeCast;
|
||||
}
|
||||
|
||||
const parserFn = genFunc();
|
||||
let i = 0;
|
||||
|
||||
/* eslint-disable no-trailing-spaces */
|
||||
/* eslint-disable no-spaced-func */
|
||||
/* eslint-disable no-unexpected-multiline */
|
||||
parserFn('(function () {')(
|
||||
'return function TextRow(packet, fields, options, CharsetToEncoding) {'
|
||||
);
|
||||
|
||||
if (options.rowsAsArray) {
|
||||
parserFn(`const result = new Array(${fields.length})`);
|
||||
}
|
||||
|
||||
if (typeof options.typeCast === 'function') {
|
||||
parserFn(`const wrap = ${wrap.toString()}`);
|
||||
}
|
||||
|
||||
const resultTables = {};
|
||||
let resultTablesArray = [];
|
||||
|
||||
if (options.nestTables === true) {
|
||||
for (i = 0; i < fields.length; i++) {
|
||||
resultTables[fields[i].table] = 1;
|
||||
}
|
||||
resultTablesArray = Object.keys(resultTables);
|
||||
for (i = 0; i < resultTablesArray.length; i++) {
|
||||
parserFn(`this[${helpers.srcEscape(resultTablesArray[i])}] = {};`);
|
||||
}
|
||||
}
|
||||
|
||||
let lvalue = '';
|
||||
let fieldName = '';
|
||||
for (i = 0; i < fields.length; i++) {
|
||||
fieldName = helpers.srcEscape(fields[i].name);
|
||||
parserFn(`// ${fieldName}: ${typeNames[fields[i].columnType]}`);
|
||||
if (typeof options.nestTables === 'string') {
|
||||
lvalue = `this[${helpers.srcEscape(
|
||||
fields[i].table + options.nestTables + fields[i].name
|
||||
)}]`;
|
||||
} else if (options.nestTables === true) {
|
||||
lvalue = `this[${helpers.srcEscape(fields[i].table)}][${fieldName}]`;
|
||||
} else if (options.rowsAsArray) {
|
||||
lvalue = `result[${i.toString(10)}]`;
|
||||
} else {
|
||||
lvalue = `this[${fieldName}]`;
|
||||
}
|
||||
const encodingExpr = `CharsetToEncoding[fields[${i}].characterSet]`;
|
||||
const readCode = readCodeFor(
|
||||
fields[i].columnType,
|
||||
fields[i].characterSet,
|
||||
encodingExpr,
|
||||
config,
|
||||
options
|
||||
);
|
||||
if (typeof options.typeCast === 'function') {
|
||||
parserFn(
|
||||
`${lvalue} = options.typeCast(wrap(fields[${i}], ${helpers.srcEscape(
|
||||
typeNames[fields[i].columnType]
|
||||
)}, packet, ${encodingExpr}), function() { return ${readCode};})`
|
||||
);
|
||||
} else if (options.typeCast === false) {
|
||||
parserFn(`${lvalue} = packet.readLengthCodedBuffer();`);
|
||||
} else {
|
||||
parserFn(`${lvalue} = ${readCode};`);
|
||||
}
|
||||
}
|
||||
|
||||
if (options.rowsAsArray) {
|
||||
parserFn('return result;');
|
||||
}
|
||||
|
||||
parserFn('};')('})()');
|
||||
|
||||
/* eslint-enable no-trailing-spaces */
|
||||
/* eslint-enable no-spaced-func */
|
||||
/* eslint-enable no-unexpected-multiline */
|
||||
|
||||
if (config.debug) {
|
||||
helpers.printDebugWithCode(
|
||||
'Compiled text protocol row parser',
|
||||
parserFn.toString()
|
||||
);
|
||||
}
|
||||
return parserFn.toFunction();
|
||||
}
|
||||
|
||||
function getTextParser(fields, options, config) {
|
||||
return parserCache.getParser('text', fields, options, config, compile);
|
||||
}
|
||||
|
||||
module.exports = getTextParser;
|
212
node_modules/mysql2/lib/pool.js
generated
vendored
Normal file
212
node_modules/mysql2/lib/pool.js
generated
vendored
Normal file
@ -0,0 +1,212 @@
|
||||
'use strict';
|
||||
|
||||
const process = require('process');
|
||||
const mysql = require('../index.js');
|
||||
|
||||
const EventEmitter = require('events').EventEmitter;
|
||||
const PoolConnection = require('./pool_connection.js');
|
||||
const Queue = require('denque');
|
||||
const Connection = require('./connection.js');
|
||||
|
||||
function spliceConnection(queue, connection) {
|
||||
const len = queue.length;
|
||||
for (let i = 0; i < len; i++) {
|
||||
if (queue.get(i) === connection) {
|
||||
queue.removeOne(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Pool extends EventEmitter {
|
||||
constructor(options) {
|
||||
super();
|
||||
this.config = options.config;
|
||||
this.config.connectionConfig.pool = this;
|
||||
this._allConnections = new Queue();
|
||||
this._freeConnections = new Queue();
|
||||
this._connectionQueue = new Queue();
|
||||
this._closed = false;
|
||||
}
|
||||
|
||||
promise(promiseImpl) {
|
||||
const PromisePool = require('../promise').PromisePool;
|
||||
return new PromisePool(this, promiseImpl);
|
||||
}
|
||||
|
||||
getConnection(cb) {
|
||||
if (this._closed) {
|
||||
return process.nextTick(() => cb(new Error('Pool is closed.')));
|
||||
}
|
||||
let connection;
|
||||
if (this._freeConnections.length > 0) {
|
||||
connection = this._freeConnections.shift();
|
||||
this.emit('acquire', connection);
|
||||
return process.nextTick(() => cb(null, connection));
|
||||
}
|
||||
if (
|
||||
this.config.connectionLimit === 0 ||
|
||||
this._allConnections.length < this.config.connectionLimit
|
||||
) {
|
||||
connection = new PoolConnection(this, {
|
||||
config: this.config.connectionConfig
|
||||
});
|
||||
this._allConnections.push(connection);
|
||||
return connection.connect(err => {
|
||||
if (this._closed) {
|
||||
return cb(new Error('Pool is closed.'));
|
||||
}
|
||||
if (err) {
|
||||
return cb(err);
|
||||
}
|
||||
this.emit('connection', connection);
|
||||
this.emit('acquire', connection);
|
||||
return cb(null, connection);
|
||||
});
|
||||
}
|
||||
if (!this.config.waitForConnections) {
|
||||
return process.nextTick(() => cb(new Error('No connections available.')));
|
||||
}
|
||||
if (
|
||||
this.config.queueLimit &&
|
||||
this._connectionQueue.length >= this.config.queueLimit
|
||||
) {
|
||||
return cb(new Error('Queue limit reached.'));
|
||||
}
|
||||
this.emit('enqueue');
|
||||
return this._connectionQueue.push(cb);
|
||||
}
|
||||
|
||||
releaseConnection(connection) {
|
||||
let cb;
|
||||
if (!connection._pool) {
|
||||
// The connection has been removed from the pool and is no longer good.
|
||||
if (this._connectionQueue.length) {
|
||||
cb = this._connectionQueue.shift();
|
||||
process.nextTick(this.getConnection.bind(this, cb));
|
||||
}
|
||||
} else if (this._connectionQueue.length) {
|
||||
cb = this._connectionQueue.shift();
|
||||
process.nextTick(cb.bind(null, null, connection));
|
||||
} else {
|
||||
this._freeConnections.push(connection);
|
||||
this.emit('release', connection);
|
||||
}
|
||||
}
|
||||
|
||||
end(cb) {
|
||||
this._closed = true;
|
||||
if (typeof cb !== 'function') {
|
||||
cb = function(err) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
}
|
||||
let calledBack = false;
|
||||
let closedConnections = 0;
|
||||
let connection;
|
||||
const endCB = function(err) {
|
||||
if (calledBack) {
|
||||
return;
|
||||
}
|
||||
if (err || ++closedConnections >= this._allConnections.length) {
|
||||
calledBack = true;
|
||||
cb(err);
|
||||
return;
|
||||
}
|
||||
}.bind(this);
|
||||
if (this._allConnections.length === 0) {
|
||||
endCB();
|
||||
return;
|
||||
}
|
||||
for (let i = 0; i < this._allConnections.length; i++) {
|
||||
connection = this._allConnections.get(i);
|
||||
connection._realEnd(endCB);
|
||||
}
|
||||
}
|
||||
|
||||
query(sql, values, cb) {
|
||||
const cmdQuery = Connection.createQuery(
|
||||
sql,
|
||||
values,
|
||||
cb,
|
||||
this.config.connectionConfig
|
||||
);
|
||||
if (typeof cmdQuery.namedPlaceholders === 'undefined') {
|
||||
cmdQuery.namedPlaceholders = this.config.connectionConfig.namedPlaceholders;
|
||||
}
|
||||
this.getConnection((err, conn) => {
|
||||
if (err) {
|
||||
if (typeof cmdQuery.onResult === 'function') {
|
||||
cmdQuery.onResult(err);
|
||||
} else {
|
||||
cmdQuery.emit('error', err);
|
||||
}
|
||||
return;
|
||||
}
|
||||
try {
|
||||
conn.query(cmdQuery).once('end', () => {
|
||||
conn.release();
|
||||
});
|
||||
} catch (e) {
|
||||
conn.release();
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
return cmdQuery;
|
||||
}
|
||||
|
||||
execute(sql, values, cb) {
|
||||
// TODO construct execute command first here and pass it to connection.execute
|
||||
// so that polymorphic arguments logic is there in one place
|
||||
if (typeof values === 'function') {
|
||||
cb = values;
|
||||
values = [];
|
||||
}
|
||||
this.getConnection((err, conn) => {
|
||||
if (err) {
|
||||
return cb(err);
|
||||
}
|
||||
try {
|
||||
conn.execute(sql, values, cb).once('end', () => {
|
||||
conn.release();
|
||||
});
|
||||
} catch (e) {
|
||||
conn.release();
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
_removeConnection(connection) {
|
||||
// Remove connection from all connections
|
||||
spliceConnection(this._allConnections, connection);
|
||||
// Remove connection from free connections
|
||||
spliceConnection(this._freeConnections, connection);
|
||||
this.releaseConnection(connection);
|
||||
}
|
||||
|
||||
format(sql, values) {
|
||||
return mysql.format(
|
||||
sql,
|
||||
values,
|
||||
this.config.connectionConfig.stringifyObjects,
|
||||
this.config.connectionConfig.timezone
|
||||
);
|
||||
}
|
||||
|
||||
escape(value) {
|
||||
return mysql.escape(
|
||||
value,
|
||||
this.config.connectionConfig.stringifyObjects,
|
||||
this.config.connectionConfig.timezone
|
||||
);
|
||||
}
|
||||
|
||||
escapeId(value) {
|
||||
return mysql.escapeId(value, false);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Pool;
|
226
node_modules/mysql2/lib/pool_cluster.js
generated
vendored
Normal file
226
node_modules/mysql2/lib/pool_cluster.js
generated
vendored
Normal file
@ -0,0 +1,226 @@
|
||||
'use strict';
|
||||
|
||||
const process = require('process');
|
||||
|
||||
const Pool = require('./pool.js');
|
||||
const PoolConfig = require('./pool_config.js');
|
||||
const EventEmitter = require('events').EventEmitter;
|
||||
|
||||
/**
|
||||
* Selector
|
||||
*/
|
||||
const makeSelector = {
|
||||
RR() {
|
||||
let index = 0;
|
||||
return clusterIds => clusterIds[index++ % clusterIds.length];
|
||||
},
|
||||
RANDOM() {
|
||||
return clusterIds =>
|
||||
clusterIds[Math.floor(Math.random() * clusterIds.length)];
|
||||
},
|
||||
ORDER() {
|
||||
return clusterIds => clusterIds[0];
|
||||
}
|
||||
};
|
||||
|
||||
class PoolNamespace {
|
||||
constructor(cluster, pattern, selector) {
|
||||
this._cluster = cluster;
|
||||
this._pattern = pattern;
|
||||
this._selector = makeSelector[selector]();
|
||||
}
|
||||
|
||||
getConnection(cb) {
|
||||
const clusterNode = this._getClusterNode();
|
||||
if (clusterNode === null) {
|
||||
return cb(new Error('Pool does Not exists.'));
|
||||
}
|
||||
return this._cluster._getConnection(clusterNode, (err, connection) => {
|
||||
if (err) {
|
||||
return cb(err);
|
||||
}
|
||||
if (connection === 'retry') {
|
||||
return this.getConnection(cb);
|
||||
}
|
||||
return cb(null, connection);
|
||||
});
|
||||
}
|
||||
|
||||
_getClusterNode() {
|
||||
const foundNodeIds = this._cluster._findNodeIds(this._pattern);
|
||||
if (foundNodeIds.length === 0) {
|
||||
return null;
|
||||
}
|
||||
const nodeId =
|
||||
foundNodeIds.length === 1
|
||||
? foundNodeIds[0]
|
||||
: this._selector(foundNodeIds);
|
||||
return this._cluster._getNode(nodeId);
|
||||
}
|
||||
}
|
||||
|
||||
class PoolCluster extends EventEmitter {
|
||||
constructor(config) {
|
||||
super();
|
||||
config = config || {};
|
||||
this._canRetry =
|
||||
typeof config.canRetry === 'undefined' ? true : config.canRetry;
|
||||
this._removeNodeErrorCount = config.removeNodeErrorCount || 5;
|
||||
this._defaultSelector = config.defaultSelector || 'RR';
|
||||
this._closed = false;
|
||||
this._lastId = 0;
|
||||
this._nodes = {};
|
||||
this._serviceableNodeIds = [];
|
||||
this._namespaces = {};
|
||||
this._findCaches = {};
|
||||
}
|
||||
|
||||
of(pattern, selector) {
|
||||
pattern = pattern || '*';
|
||||
selector = selector || this._defaultSelector;
|
||||
selector = selector.toUpperCase();
|
||||
if (!makeSelector[selector] === 'undefined') {
|
||||
selector = this._defaultSelector;
|
||||
}
|
||||
const key = pattern + selector;
|
||||
if (typeof this._namespaces[key] === 'undefined') {
|
||||
this._namespaces[key] = new PoolNamespace(this, pattern, selector);
|
||||
}
|
||||
return this._namespaces[key];
|
||||
}
|
||||
|
||||
add(id, config) {
|
||||
if (typeof id === 'object') {
|
||||
config = id;
|
||||
id = `CLUSTER::${++this._lastId}`;
|
||||
}
|
||||
if (typeof this._nodes[id] === 'undefined') {
|
||||
this._nodes[id] = {
|
||||
id: id,
|
||||
errorCount: 0,
|
||||
pool: new Pool({ config: new PoolConfig(config) })
|
||||
};
|
||||
this._serviceableNodeIds.push(id);
|
||||
this._clearFindCaches();
|
||||
}
|
||||
}
|
||||
|
||||
getConnection(pattern, selector, cb) {
|
||||
let namespace;
|
||||
if (typeof pattern === 'function') {
|
||||
cb = pattern;
|
||||
namespace = this.of();
|
||||
} else {
|
||||
if (typeof selector === 'function') {
|
||||
cb = selector;
|
||||
selector = this._defaultSelector;
|
||||
}
|
||||
namespace = this.of(pattern, selector);
|
||||
}
|
||||
namespace.getConnection(cb);
|
||||
}
|
||||
|
||||
end(callback) {
|
||||
const cb =
|
||||
callback !== undefined
|
||||
? callback
|
||||
: err => {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
if (this._closed) {
|
||||
process.nextTick(cb);
|
||||
return;
|
||||
}
|
||||
this._closed = true;
|
||||
|
||||
let calledBack = false;
|
||||
let waitingClose = 0;
|
||||
const onEnd = err => {
|
||||
if (!calledBack && (err || --waitingClose <= 0)) {
|
||||
calledBack = true;
|
||||
return cb(err);
|
||||
}
|
||||
};
|
||||
|
||||
for (const id in this._nodes) {
|
||||
waitingClose++;
|
||||
this._nodes[id].pool.end(onEnd);
|
||||
}
|
||||
if (waitingClose === 0) {
|
||||
process.nextTick(onEnd);
|
||||
}
|
||||
}
|
||||
|
||||
_findNodeIds(pattern) {
|
||||
if (typeof this._findCaches[pattern] !== 'undefined') {
|
||||
return this._findCaches[pattern];
|
||||
}
|
||||
let foundNodeIds;
|
||||
if (pattern === '*') {
|
||||
// all
|
||||
foundNodeIds = this._serviceableNodeIds;
|
||||
} else if (this._serviceableNodeIds.indexOf(pattern) !== -1) {
|
||||
// one
|
||||
foundNodeIds = [pattern];
|
||||
} else {
|
||||
// wild matching
|
||||
const keyword = pattern.substring(pattern.length - 1, 0);
|
||||
foundNodeIds = this._serviceableNodeIds.filter(id =>
|
||||
id.startsWith(keyword)
|
||||
);
|
||||
}
|
||||
this._findCaches[pattern] = foundNodeIds;
|
||||
return foundNodeIds;
|
||||
}
|
||||
|
||||
_getNode(id) {
|
||||
return this._nodes[id] || null;
|
||||
}
|
||||
|
||||
_increaseErrorCount(node) {
|
||||
if (++node.errorCount >= this._removeNodeErrorCount) {
|
||||
const index = this._serviceableNodeIds.indexOf(node.id);
|
||||
if (index !== -1) {
|
||||
this._serviceableNodeIds.splice(index, 1);
|
||||
delete this._nodes[node.id];
|
||||
this._clearFindCaches();
|
||||
node.pool.end();
|
||||
this.emit('remove', node.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_decreaseErrorCount(node) {
|
||||
if (node.errorCount > 0) {
|
||||
--node.errorCount;
|
||||
}
|
||||
}
|
||||
|
||||
_getConnection(node, cb) {
|
||||
node.pool.getConnection((err, connection) => {
|
||||
if (err) {
|
||||
this._increaseErrorCount(node);
|
||||
if (this._canRetry) {
|
||||
// REVIEW: this seems wrong?
|
||||
this.emit('warn', err);
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn(`[Error] PoolCluster : ${err}`);
|
||||
return cb(null, 'retry');
|
||||
}
|
||||
return cb(err);
|
||||
}
|
||||
this._decreaseErrorCount(node);
|
||||
|
||||
connection._clusterId = node.id;
|
||||
return cb(null, connection);
|
||||
});
|
||||
}
|
||||
|
||||
_clearFindCaches() {
|
||||
this._findCaches = {};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = PoolCluster;
|
24
node_modules/mysql2/lib/pool_config.js
generated
vendored
Normal file
24
node_modules/mysql2/lib/pool_config.js
generated
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
'use strict';
|
||||
|
||||
const ConnectionConfig = require('./connection_config.js');
|
||||
|
||||
class PoolConfig {
|
||||
constructor(options) {
|
||||
if (typeof options === 'string') {
|
||||
options = ConnectionConfig.parseUrl(options);
|
||||
}
|
||||
this.connectionConfig = new ConnectionConfig(options);
|
||||
this.waitForConnections =
|
||||
options.waitForConnections === undefined
|
||||
? true
|
||||
: Boolean(options.waitForConnections);
|
||||
this.connectionLimit = isNaN(options.connectionLimit)
|
||||
? 10
|
||||
: Number(options.connectionLimit);
|
||||
this.queueLimit = isNaN(options.queueLimit)
|
||||
? 0
|
||||
: Number(options.queueLimit);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = PoolConfig;
|
65
node_modules/mysql2/lib/pool_connection.js
generated
vendored
Normal file
65
node_modules/mysql2/lib/pool_connection.js
generated
vendored
Normal file
@ -0,0 +1,65 @@
|
||||
'use strict';
|
||||
|
||||
const Connection = require('../index.js').Connection;
|
||||
|
||||
class PoolConnection extends Connection {
|
||||
constructor(pool, options) {
|
||||
super(options);
|
||||
this._pool = pool;
|
||||
// When a fatal error occurs the connection's protocol ends, which will cause
|
||||
// the connection to end as well, thus we only need to watch for the end event
|
||||
// and we will be notified of disconnects.
|
||||
// REVIEW: Moved to `once`
|
||||
this.once('end', () => {
|
||||
this._removeFromPool();
|
||||
});
|
||||
this.once('error', () => {
|
||||
this._removeFromPool();
|
||||
});
|
||||
}
|
||||
|
||||
release() {
|
||||
if (!this._pool || this._pool._closed) {
|
||||
return;
|
||||
}
|
||||
this._pool.releaseConnection(this);
|
||||
}
|
||||
|
||||
promise(promiseImpl) {
|
||||
const PromisePoolConnection = require('../promise').PromisePoolConnection;
|
||||
return new PromisePoolConnection(this, promiseImpl);
|
||||
}
|
||||
|
||||
end() {
|
||||
const err = new Error(
|
||||
'Calling conn.end() to release a pooled connection is ' +
|
||||
'deprecated. In next version calling conn.end() will be ' +
|
||||
'restored to default conn.end() behavior. Use ' +
|
||||
'conn.release() instead.'
|
||||
);
|
||||
this.emit('warn', err);
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn(err.message);
|
||||
this.release();
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this._removeFromPool();
|
||||
super.destroy();
|
||||
}
|
||||
|
||||
_removeFromPool() {
|
||||
if (!this._pool || this._pool._closed) {
|
||||
return;
|
||||
}
|
||||
const pool = this._pool;
|
||||
this._pool = null;
|
||||
pool._removeConnection(this);
|
||||
}
|
||||
}
|
||||
|
||||
PoolConnection.statementKey = Connection.statementKey;
|
||||
module.exports = PoolConnection;
|
||||
|
||||
// TODO: Remove this when we are removing PoolConnection#end
|
||||
PoolConnection.prototype._realEnd = Connection.prototype.end;
|
38
node_modules/mysql2/lib/results_stream.js
generated
vendored
Normal file
38
node_modules/mysql2/lib/results_stream.js
generated
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
'use strict';
|
||||
|
||||
const Readable = require('stream').Readable;
|
||||
|
||||
// copy-paste from https://github.com/mysqljs/mysql/blob/master/lib/protocol/sequences/Query.js
|
||||
module.exports = function(command, connectionStream) {
|
||||
command.stream = function(options) {
|
||||
let stream;
|
||||
|
||||
options = options || {};
|
||||
options.objectMode = true;
|
||||
(stream = new Readable(options)),
|
||||
(stream._read = function() {
|
||||
connectionStream.resume();
|
||||
});
|
||||
|
||||
this.on('result', (row, i) => {
|
||||
if (!stream.push(row)) {
|
||||
connectionStream.pause();
|
||||
}
|
||||
stream.emit('result', row, i); // replicate old emitter
|
||||
});
|
||||
|
||||
this.on('error', err => {
|
||||
stream.emit('error', err); // Pass on any errors
|
||||
});
|
||||
|
||||
this.on('end', () => {
|
||||
stream.push(null); // pushing null, indicating EOF
|
||||
});
|
||||
|
||||
this.on('fields', (fields, i) => {
|
||||
stream.emit('fields', fields, i); // replicate old emitter
|
||||
});
|
||||
|
||||
return stream;
|
||||
};
|
||||
};
|
37
node_modules/mysql2/lib/server.js
generated
vendored
Normal file
37
node_modules/mysql2/lib/server.js
generated
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
'use strict';
|
||||
|
||||
const net = require('net');
|
||||
const EventEmitter = require('events').EventEmitter;
|
||||
|
||||
const Connection = require('./connection');
|
||||
const ConnectionConfig = require('./connection_config');
|
||||
|
||||
// TODO: inherit Server from net.Server
|
||||
class Server extends EventEmitter {
|
||||
constructor() {
|
||||
super();
|
||||
this.connections = [];
|
||||
this._server = net.createServer(this._handleConnection.bind(this));
|
||||
}
|
||||
|
||||
_handleConnection(socket) {
|
||||
const connectionConfig = new ConnectionConfig({
|
||||
stream: socket,
|
||||
isServer: true
|
||||
});
|
||||
const connection = new Connection({ config: connectionConfig });
|
||||
this.emit('connection', connection);
|
||||
}
|
||||
|
||||
listen(port) {
|
||||
this._port = port;
|
||||
this._server.listen.apply(this._server, arguments);
|
||||
return this;
|
||||
}
|
||||
|
||||
close(cb) {
|
||||
this._server.close(cb);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Server;
|
Reference in New Issue
Block a user