Comparing version 3.1.2 to 3.2.0
@@ -13,2 +13,3 @@ 'use strict'; | ||
const Connection = require('./lib/connection'); | ||
const CommandParameter = require('./lib/command-parameter'); | ||
@@ -55,1 +56,21 @@ module.exports.version = require('./package.json').version; | ||
}; | ||
module.exports.importFile = function importFile(opts, callback) { | ||
const cb = callback ? callback : () => {}; | ||
try { | ||
const options = new ConnOptions(opts); | ||
const conn = new Connection(options); | ||
conn | ||
.connect() | ||
.then(() => { | ||
return new Promise(conn.importFile.bind(conn, Object.assign({ skipDbCheck: true }, opts))); | ||
}) | ||
.then(() => cb()) | ||
.catch((err) => cb(err)) | ||
.finally(() => { | ||
new Promise(conn.end.bind(conn, new CommandParameter())).catch(console.log); | ||
}); | ||
} catch (err) { | ||
cb(err); | ||
} | ||
}; |
@@ -20,3 +20,3 @@ 'use strict'; | ||
return true; | ||
} | ||
}; | ||
@@ -23,0 +23,0 @@ module.exports.hasMinVersion = hasMinVersion; |
@@ -268,3 +268,3 @@ 'use strict'; | ||
let param = this.vals[i]; | ||
if (param !== null) { | ||
if (param != null) { | ||
// special check for GEOJSON that can be null even if object is not | ||
@@ -490,14 +490,14 @@ if ( | ||
//validate parameter is defined. | ||
for (let i = 0; i < nbParameter; i++) { | ||
if (this.values[r][i] === undefined) { | ||
this.emit('send_end'); | ||
this.throwNewError( | ||
`Parameter at position ${i} is not set for values ${r}\n ${this.displaySql()}`, | ||
false, | ||
info, | ||
'HY000', | ||
Errors.ER_PARAMETER_UNDEFINED | ||
); | ||
return false; | ||
} | ||
if (this.values[r].length < nbParameter) { | ||
this.emit('send_end'); | ||
this.throwNewError( | ||
`Expect ${nbParameter} parameters, but at index ${r}, parameters only contains ${ | ||
this.values[r].length | ||
}\n ${this.displaySql()}`, | ||
false, | ||
info, | ||
'HY000', | ||
Errors.ER_PARAMETER_UNDEFINED | ||
); | ||
return false; | ||
} | ||
@@ -504,0 +504,0 @@ } |
@@ -10,3 +10,3 @@ // noinspection JSBitwiseOperatorUsage | ||
const Collations = require('../const/collations'); | ||
const Handshake = require('./handshake/handshake'); | ||
const Authentication = require('./handshake/authentication'); | ||
@@ -17,5 +17,5 @@ /** | ||
*/ | ||
class ChangeUser extends Handshake { | ||
constructor(cmdParam, connOpts, resolve, reject, addCommand) { | ||
super(cmdParam, resolve, reject, () => {}, addCommand); | ||
class ChangeUser extends Authentication { | ||
constructor(cmdParam, connOpts, resolve, reject, getSocket) { | ||
super(cmdParam, resolve, reject, () => {}, getSocket); | ||
this.configAssign(connOpts, cmdParam.opts); | ||
@@ -109,3 +109,3 @@ } | ||
out.flush(); | ||
this.onPacketReceive = this.handshakeResult; | ||
this.plugin.onPacketReceive = this.handshakeResult.bind(this); | ||
} | ||
@@ -112,0 +112,0 @@ |
@@ -94,3 +94,3 @@ 'use strict'; | ||
const cmdParam = new CommandParameter(this.query, values, _opts, cb); | ||
const cmdParam = new CommandParameter(this.query, values, _opts, _cb); | ||
if (stack) cmdParam.stack = stack; | ||
@@ -97,0 +97,0 @@ |
@@ -24,3 +24,3 @@ 'use strict'; | ||
case 'object': | ||
if (value === null) { | ||
if (value == null) { | ||
out.writeStringAscii('NULL'); | ||
@@ -145,3 +145,7 @@ } else if (value instanceof Date) { | ||
default: | ||
out.writeStringEscapeQuote(value); | ||
if (value == null) { | ||
out.writeStringAscii('NULL'); | ||
} else { | ||
out.writeStringEscapeQuote(value); | ||
} | ||
} | ||
@@ -148,0 +152,0 @@ } |
@@ -53,3 +53,3 @@ 'use strict'; | ||
if ( | ||
value !== null && | ||
value != null && | ||
((typeof value === 'object' && typeof value.pipe === 'function' && typeof value.read === 'function') || | ||
@@ -102,12 +102,8 @@ Buffer.isBuffer(value)) | ||
for (let i = 0; i < this.prepare.parameterCount; i++) { | ||
if (this.values[i] === undefined) { | ||
if (this.opts.namedPlaceholders && this.prepare._placeHolderIndex && this.values[i] === undefined) { | ||
let errMsg = `Parameter named ${this.prepare._placeHolderIndex[i]} is not set`; | ||
if (this.prepare._placeHolderIndex.length < this.prepare.parameterCount) { | ||
errMsg = `Command expect ${this.prepare.parameterCount} parameters, but found only ${this.prepare._placeHolderIndex.length} named parameters. You probably use question mark in place of named parameters`; | ||
} | ||
this.emit('send_end'); | ||
let errMsg = `Parameter at position ${i} is undefined`; | ||
if (this.opts.namedPlaceholders && this.prepare._placeHolderIndex) { | ||
if (this.prepare._placeHolderIndex.length < this.prepare.parameterCount) { | ||
errMsg = `Command expect ${this.prepare.parameterCount} parameters, but found only ${this.prepare._placeHolderIndex.length} named parameters. You probably use question mark in place of named parameters`; | ||
} else { | ||
errMsg = `Parameter named ${this.prepare._placeHolderIndex[i]} is not set`; | ||
} | ||
} | ||
this.throwNewError(errMsg, false, info, 'HY000', Errors.ER_PARAMETER_UNDEFINED); | ||
@@ -185,3 +181,3 @@ return false; | ||
for (let i = 0; i < parameterCount; i++) { | ||
if (this.values[i] === null) { | ||
if (this.values[i] == null) { | ||
nullBitsBuffer[Math.floor(i / 8)] |= 1 << i % 8; | ||
@@ -255,3 +251,3 @@ } | ||
if ( | ||
value !== null && | ||
value != null && | ||
!(typeof value === 'object' && typeof value.pipe === 'function' && typeof value.read === 'function') && | ||
@@ -281,3 +277,3 @@ !Buffer.isBuffer(value) | ||
if ( | ||
(value !== null && | ||
(value != null && | ||
typeof value === 'object' && | ||
@@ -284,0 +280,0 @@ typeof value.pipe === 'function' && |
@@ -17,6 +17,8 @@ const PluginAuth = require('./plugin-auth'); | ||
class CachingSha2PasswordAuth extends PluginAuth { | ||
constructor(packSeq, compressPackSeq, pluginData, cmdParam, resolve, reject, multiAuthResolver) { | ||
super(cmdParam, resolve, reject, multiAuthResolver); | ||
constructor(packSeq, compressPackSeq, pluginData, cmdParam, reject, multiAuthResolver) { | ||
super(cmdParam, multiAuthResolver, reject); | ||
this.multiAuthResolver = multiAuthResolver; | ||
this.pluginData = pluginData; | ||
this.sequenceNo = packSeq; | ||
this.compressSequenceNo = compressPackSeq; | ||
this.counter = 0; | ||
@@ -117,3 +119,3 @@ this.state = State.INIT; | ||
this.emit('send_end'); | ||
return this.successSend(packet, out, opts, info); | ||
return this.multiAuthResolver(packet, out, opts, info); | ||
@@ -120,0 +122,0 @@ default: |
@@ -27,3 +27,2 @@ const PluginAuth = require('./plugin-auth'); | ||
this.emit('send_end'); | ||
this.onPacketReceive = this.successSend; | ||
} | ||
@@ -30,0 +29,0 @@ } |
@@ -10,6 +10,7 @@ 'use strict'; | ||
class Ed25519PasswordAuth extends PluginAuth { | ||
constructor(packSeq, compressPackSeq, pluginData, cmdParam, resolve, reject, multiAuthResolver) { | ||
super(cmdParam, resolve, reject, multiAuthResolver); | ||
constructor(packSeq, compressPackSeq, pluginData, cmdParam, reject, multiAuthResolver) { | ||
super(cmdParam, multiAuthResolver, reject); | ||
this.pluginData = pluginData; | ||
this.sequenceNo = packSeq; | ||
this.compressSequenceNo = compressPackSeq; | ||
} | ||
@@ -26,3 +27,2 @@ | ||
this.emit('send_end'); | ||
this.onPacketReceive = this.successSend; | ||
} | ||
@@ -29,0 +29,0 @@ |
@@ -10,4 +10,4 @@ 'use strict'; | ||
class NativePasswordAuth extends PluginAuth { | ||
constructor(packSeq, compressPackSeq, pluginData, cmdParam, resolve, reject, multiAuthResolver) { | ||
super(cmdParam, resolve, reject, multiAuthResolver); | ||
constructor(packSeq, compressPackSeq, pluginData, cmdParam, reject, multiAuthResolver) { | ||
super(cmdParam, multiAuthResolver, reject); | ||
this.pluginData = pluginData; | ||
@@ -31,3 +31,2 @@ this.sequenceNo = packSeq; | ||
this.emit('send_end'); | ||
this.onPacketReceive = this.successSend; | ||
} | ||
@@ -34,0 +33,0 @@ |
@@ -7,7 +7,9 @@ const PluginAuth = require('./plugin-auth'); | ||
class PamPasswordAuth extends PluginAuth { | ||
constructor(packSeq, compressPackSeq, pluginData, cmdParam, resolve, reject, multiAuthResolver) { | ||
super(cmdParam, resolve, reject, multiAuthResolver); | ||
constructor(packSeq, compressPackSeq, pluginData, cmdParam, reject, multiAuthResolver) { | ||
super(cmdParam, multiAuthResolver, reject); | ||
this.pluginData = pluginData; | ||
this.sequenceNo = packSeq; | ||
this.compressSequenceNo = compressPackSeq; | ||
this.counter = 0; | ||
this.multiAuthResolver = multiAuthResolver; | ||
} | ||
@@ -49,3 +51,3 @@ | ||
this.emit('send_end'); | ||
return this.successSend(packet, out, opts, info); | ||
return this.multiAuthResolver(packet, out, opts, info); | ||
@@ -52,0 +54,0 @@ default: |
@@ -9,12 +9,8 @@ 'use strict'; | ||
class PluginAuth extends Command { | ||
constructor(cmdParam, resolve, reject, multiAuthResolver) { | ||
super(cmdParam, resolve, reject); | ||
this.multiAuthResolver = multiAuthResolver; | ||
constructor(cmdParam, multiAuthResolver, reject) { | ||
super(cmdParam, multiAuthResolver, reject); | ||
this.onPacketReceive = multiAuthResolver; | ||
} | ||
successSend(packet, out, opts, info) { | ||
this.multiAuthResolver(packet, out, opts, info); | ||
} | ||
} | ||
module.exports = PluginAuth; |
@@ -11,8 +11,11 @@ const PluginAuth = require('./plugin-auth'); | ||
class Sha256PasswordAuth extends PluginAuth { | ||
constructor(packSeq, compressPackSeq, pluginData, cmdParam, resolve, reject, multiAuthResolver) { | ||
super(cmdParam, resolve, reject, multiAuthResolver); | ||
constructor(packSeq, compressPackSeq, pluginData, cmdParam, reject, multiAuthResolver) { | ||
super(cmdParam, multiAuthResolver, reject); | ||
this.pluginData = pluginData; | ||
this.sequenceNo = packSeq; | ||
this.compressSequenceNo = compressPackSeq; | ||
this.counter = 0; | ||
this.counter = 0; | ||
this.initialState = true; | ||
this.multiAuthResolver = multiAuthResolver; | ||
} | ||
@@ -138,3 +141,3 @@ | ||
this.emit('send_end'); | ||
return this.successSend(packet, out, opts, info); | ||
return this.multiAuthResolver(packet, out, opts, info); | ||
@@ -141,0 +144,0 @@ default: |
@@ -587,3 +587,3 @@ 'use strict'; | ||
static logParam(sqlMsg, param) { | ||
if (param === undefined || param === null) { | ||
if (param == null) { | ||
sqlMsg += param === undefined ? 'undefined' : 'null'; | ||
@@ -590,0 +590,0 @@ } else { |
@@ -7,3 +7,3 @@ 'use strict'; | ||
const TextEncoder = require('./encoder/text-encoder'); | ||
const { Readable } = require('stream'); | ||
const QUOTE = 0x27; | ||
@@ -83,3 +83,3 @@ | ||
if ( | ||
value !== null && | ||
value != null && | ||
typeof value === 'object' && | ||
@@ -180,18 +180,2 @@ typeof value.pipe === 'function' && | ||
} | ||
//validate parameter is defined. | ||
for (let i = 0; i < this.paramPositions.length / 2; i++) { | ||
if (this.values[i] === undefined) { | ||
this.emit('send_end'); | ||
this.throwNewError( | ||
`Parameter at position ${i + 1} is undefined\n${this.displaySql()}`, | ||
false, | ||
info, | ||
'HY000', | ||
Errors.ER_PARAMETER_UNDEFINED | ||
); | ||
return false; | ||
} | ||
} | ||
return true; | ||
@@ -217,3 +201,3 @@ } | ||
if (value === null) { | ||
if (value == null) { | ||
out.writeStringAscii('NULL'); | ||
@@ -246,4 +230,45 @@ continue; | ||
} | ||
_stream(socket, options) { | ||
this.socket = socket; | ||
options = options || {}; | ||
options.objectMode = true; | ||
options.read = () => { | ||
this.socket.resume(); | ||
}; | ||
this.inStream = new Readable(options); | ||
this.on('fields', function (meta) { | ||
this.inStream.emit('fields', meta); | ||
}); | ||
this.on('error', function (err) { | ||
this.inStream.emit('error', err); | ||
}); | ||
this.on('close', function (err) { | ||
this.inStream.emit('error', err); | ||
}); | ||
this.on('end', function (err) { | ||
if (err) this.inStream.emit('error', err); | ||
this.socket.resume(); | ||
this.inStream.push(null); | ||
}); | ||
this.inStream.close = function () { | ||
this.handleNewRows = () => {}; | ||
this.socket.resume(); | ||
}.bind(this); | ||
this.handleNewRows = function (row) { | ||
if (!this.inStream.push(row)) { | ||
this.socket.pause(); | ||
} | ||
}; | ||
return this.inStream; | ||
} | ||
} | ||
module.exports = Query; |
@@ -146,3 +146,3 @@ 'use strict'; | ||
this.restrictedAuth = opts.restrictedAuth; | ||
if (this.restrictedAuth !== undefined && this.restrictedAuth !== null) { | ||
if (this.restrictedAuth != null) { | ||
if (!Array.isArray(this.restrictedAuth)) { | ||
@@ -149,0 +149,0 @@ this.restrictedAuth = this.restrictedAuth.split(','); |
@@ -13,5 +13,2 @@ 'use strict'; | ||
this.#conn = conn; | ||
this.on = this.#conn.on.bind(this.#conn); | ||
this.once = this.#conn.once.bind(this.#conn); | ||
this.listeners = this.#conn.listeners.bind(this.#conn); | ||
} | ||
@@ -142,2 +139,3 @@ | ||
conn.addCommand(cmd); | ||
cmd.stream = (opt) => cmd._stream(conn.socket, opt); | ||
return cmd; | ||
@@ -234,2 +232,33 @@ } | ||
/** | ||
* Import sql file. | ||
* | ||
* @param opts JSON array with 2 possible fields: file and database | ||
* @param cb callback | ||
*/ | ||
importFile(opts, cb) { | ||
if (!opts || !opts.file) { | ||
if (cb) | ||
cb( | ||
Errors.createError( | ||
'SQL file parameter is mandatory', | ||
Errors.ER_MISSING_SQL_PARAMETER, | ||
this.#conn.info, | ||
'HY000', | ||
null, | ||
false, | ||
null | ||
) | ||
); | ||
return; | ||
} | ||
new Promise(this.#conn.importFile.bind(this.#conn, { file: opts.file, database: opts.database })) | ||
.then(() => { | ||
if (cb) cb(); | ||
}) | ||
.catch((err) => { | ||
if (cb) cb(err); | ||
}); | ||
} | ||
/** | ||
* Send an empty MySQL packet to ensure connection is active, and reset @@wait_timeout | ||
@@ -392,4 +421,73 @@ * @param timeout (optional) timeout value in ms. If reached, throw error and close connection | ||
} | ||
//***************************************************************** | ||
// EventEmitter proxy methods | ||
//***************************************************************** | ||
on(eventName, listener) { | ||
this.#conn.on.call(this.#conn, eventName, listener); | ||
return this; | ||
} | ||
off(eventName, listener) { | ||
this.#conn.off.call(this.#conn, eventName, listener); | ||
return this; | ||
} | ||
once(eventName, listener) { | ||
this.#conn.once.call(this.#conn, eventName, listener); | ||
return this; | ||
} | ||
listeners(eventName) { | ||
return this.#conn.listeners.call(this.#conn, eventName); | ||
} | ||
addListener(eventName, listener) { | ||
this.#conn.addListener.call(this.#conn, eventName, listener); | ||
return this; | ||
} | ||
eventNames() { | ||
return this.#conn.eventNames.call(this.#conn); | ||
} | ||
getMaxListeners() { | ||
return this.#conn.getMaxListeners.call(this.#conn); | ||
} | ||
listenerCount(eventName, listener) { | ||
return this.#conn.listenerCount.call(this.#conn, eventName, listener); | ||
} | ||
prependListener(eventName, listener) { | ||
this.#conn.prependListener.call(this.#conn, eventName, listener); | ||
return this; | ||
} | ||
prependOnceListener(eventName, listener) { | ||
this.#conn.prependOnceListener.call(this.#conn, eventName, listener); | ||
return this; | ||
} | ||
removeAllListeners(eventName, listener) { | ||
this.#conn.removeAllListeners.call(this.#conn, eventName, listener); | ||
return this; | ||
} | ||
removeListener(eventName, listener) { | ||
this.#conn.removeListener.call(this.#conn, eventName, listener); | ||
return this; | ||
} | ||
setMaxListeners(n) { | ||
this.#conn.setMaxListeners.call(this.#conn, n); | ||
return this; | ||
} | ||
rawListeners(eventName) { | ||
return this.#conn.rawListeners.call(this.#conn, eventName); | ||
} | ||
} | ||
module.exports = ConnectionCallback; |
@@ -5,2 +5,3 @@ 'use strict'; | ||
const CommandParameter = require('./command-parameter'); | ||
const Errors = require('./misc/errors'); | ||
@@ -23,5 +24,2 @@ /** | ||
this.#conn = conn; | ||
this.on = this.#conn.on.bind(this.#conn); | ||
this.once = this.#conn.once.bind(this.#conn); | ||
this.listeners = this.#conn.listeners.bind(this.#conn); | ||
} | ||
@@ -158,2 +156,24 @@ | ||
/** | ||
* Import sql file. | ||
* | ||
* @param opts JSON array with 2 possible fields: file and database | ||
*/ | ||
importFile(opts) { | ||
if (!opts || !opts.file) { | ||
return Promise.reject( | ||
Errors.createError( | ||
'SQL file parameter is mandatory', | ||
Errors.ER_MISSING_SQL_PARAMETER, | ||
this.#conn.info, | ||
'HY000', | ||
null, | ||
false, | ||
null | ||
) | ||
); | ||
} | ||
return new Promise(this.#conn.importFile.bind(this.#conn, { file: opts.file, database: opts.database })); | ||
} | ||
/** | ||
* Execute query returning a Readable Object that will emit columns/data/end/error events | ||
@@ -278,2 +298,71 @@ * to permit streaming big result-set | ||
//***************************************************************** | ||
// EventEmitter proxy methods | ||
//***************************************************************** | ||
on(eventName, listener) { | ||
this.#conn.on.call(this.#conn, eventName, listener); | ||
return this; | ||
} | ||
off(eventName, listener) { | ||
this.#conn.off.call(this.#conn, eventName, listener); | ||
return this; | ||
} | ||
once(eventName, listener) { | ||
this.#conn.once.call(this.#conn, eventName, listener); | ||
return this; | ||
} | ||
listeners(eventName) { | ||
return this.#conn.listeners.call(this.#conn, eventName); | ||
} | ||
addListener(eventName, listener) { | ||
this.#conn.addListener.call(this.#conn, eventName, listener); | ||
return this; | ||
} | ||
eventNames() { | ||
return this.#conn.eventNames.call(this.#conn); | ||
} | ||
getMaxListeners() { | ||
return this.#conn.getMaxListeners.call(this.#conn); | ||
} | ||
listenerCount(eventName, listener) { | ||
return this.#conn.listenerCount.call(this.#conn, eventName, listener); | ||
} | ||
prependListener(eventName, listener) { | ||
this.#conn.prependListener.call(this.#conn, eventName, listener); | ||
return this; | ||
} | ||
prependOnceListener(eventName, listener) { | ||
this.#conn.prependOnceListener.call(this.#conn, eventName, listener); | ||
return this; | ||
} | ||
removeAllListeners(eventName, listener) { | ||
this.#conn.removeAllListeners.call(this.#conn, eventName, listener); | ||
return this; | ||
} | ||
removeListener(eventName, listener) { | ||
this.#conn.removeListener.call(this.#conn, eventName, listener); | ||
return this; | ||
} | ||
setMaxListeners(n) { | ||
this.#conn.setMaxListeners.call(this.#conn, n); | ||
return this; | ||
} | ||
rawListeners(eventName) { | ||
return this.#conn.rawListeners.call(this.#conn, eventName); | ||
} | ||
//***************************************************************** | ||
// internal public testing methods | ||
@@ -280,0 +369,0 @@ //***************************************************************** |
@@ -18,3 +18,3 @@ 'use strict'; | ||
/*commands*/ | ||
const Handshake = require('./cmd/handshake/handshake'); | ||
const Authentication = require('./cmd/handshake/authentication'); | ||
const Quit = require('./cmd/quit'); | ||
@@ -33,5 +33,7 @@ const Ping = require('./cmd/ping'); | ||
const LruPrepareCache = require('./lru-prepare-cache'); | ||
const fsPromises = require('fs').promises; | ||
const Parse = require('./misc/parse'); | ||
const convertFixedTime = function (tz) { | ||
if (tz === 'Etc/UTC' || tz === 'Z') { | ||
const convertFixedTime = function (tz, conn) { | ||
if (tz === 'UTC' || tz === 'Etc/UTC' || tz === 'Z' || tz === 'Etc/GMT') { | ||
return '+00:00'; | ||
@@ -55,3 +57,3 @@ } else if (tz.startsWith('Etc/GMT') || tz.startsWith('GMT')) { | ||
Errors.ER_WRONG_AUTO_TIMEZONE, | ||
this.info | ||
conn.info | ||
); | ||
@@ -123,3 +125,3 @@ } | ||
this.status = Status.CONNECTING; | ||
const handshakeParam = new CommandParameter(null, null, this.opts, null); | ||
const authenticationParam = new CommandParameter(null, null, this.opts, null); | ||
return new Promise(function (resolve, reject) { | ||
@@ -129,13 +131,13 @@ conn.connectRejectFct = reject; | ||
// add a handshake to msg queue | ||
const handshake = new Handshake( | ||
handshakeParam, | ||
const authentication = new Authentication( | ||
authenticationParam, | ||
conn.authSucceedHandler.bind(conn), | ||
conn.authFailHandler.bind(conn), | ||
conn.createSecureContext.bind(conn), | ||
conn.addCommandEnable.bind(conn), | ||
conn.getSocket.bind(conn) | ||
); | ||
Error.captureStackTrace(handshake); | ||
Error.captureStackTrace(authentication); | ||
handshake.once('end', () => { | ||
authentication.once('end', () => { | ||
conn.receiveQueue.shift(); | ||
// conn.info.collation might not be initialized | ||
@@ -146,7 +148,6 @@ // in case of handshake throwing error | ||
} | ||
process.nextTick(conn.nextSendCmd.bind(conn)); | ||
}); | ||
conn.receiveQueue.push(handshake); | ||
conn.receiveQueue.push(authentication); | ||
conn.streamInitSocket.call(conn); | ||
@@ -600,3 +601,3 @@ }); | ||
if ( | ||
val !== null && | ||
val != null && | ||
typeof val === 'object' && | ||
@@ -617,3 +618,3 @@ typeof val.pipe === 'function' && | ||
if ( | ||
val !== null && | ||
val != null && | ||
typeof val === 'object' && | ||
@@ -669,2 +670,3 @@ typeof val.pipe === 'function' && | ||
handleTimezone() { | ||
const conn = this; | ||
if (this.opts.timezone === 'local') this.opts.timezone = undefined; | ||
@@ -677,3 +679,3 @@ if (this.opts.timezone === 'auto') { | ||
const localTz = Intl.DateTimeFormat().resolvedOptions().timeZone; | ||
if (serverTimezone === localTz || convertFixedTime(serverTimezone) === convertFixedTime(localTz)) { | ||
if (serverTimezone === localTz || convertFixedTime(serverTimezone, conn) === convertFixedTime(localTz, conn)) { | ||
//server timezone is identical to client tz, skipping setting | ||
@@ -683,3 +685,3 @@ this.opts.timezone = localTz; | ||
} | ||
return this._setSessionTimezone(convertFixedTime(localTz)); | ||
return this._setSessionTimezone(convertFixedTime(localTz, conn)); | ||
}); | ||
@@ -689,3 +691,3 @@ } | ||
if (this.opts.timezone) { | ||
return this._setSessionTimezone(convertFixedTime(this.opts.timezone)); | ||
return this._setSessionTimezone(convertFixedTime(this.opts.timezone, conn)); | ||
} | ||
@@ -783,2 +785,5 @@ return Promise.resolve(); | ||
streamInitSocket() { | ||
if (this.opts.connectTimeout) { | ||
this.timeout = setTimeout(this.connectTimeoutReached.bind(this), this.opts.connectTimeout, Date.now()); | ||
} | ||
if (this.opts.socketPath) { | ||
@@ -820,6 +825,2 @@ this.socket = Net.connect(this.opts.socketPath); | ||
socketInit() { | ||
if (this.opts.connectTimeout) { | ||
this.timeout = setTimeout(this.connectTimeoutReached.bind(this), this.opts.connectTimeout, Date.now()); | ||
} | ||
this.socket.on('data', this.streamIn.onData.bind(this.streamIn)); | ||
@@ -831,3 +832,2 @@ this.socket.on('error', this.socketErrorHandler.bind(this)); | ||
function () { | ||
clearTimeout(this.timeout); | ||
if (this.status === Status.CONNECTING) { | ||
@@ -884,2 +884,3 @@ this.status = Status.AUTHENTICATING; | ||
.then(() => { | ||
clearTimeout(this.timeout); | ||
conn.status = Status.CONNECTED; | ||
@@ -915,2 +916,3 @@ process.nextTick(conn.connectResolveFct, conn); | ||
authFailHandler(err) { | ||
clearTimeout(this.timeout); | ||
if (this.connectRejectFct) { | ||
@@ -1042,3 +1044,3 @@ if (this.opts.logger.error) this.opts.logger.error(err); | ||
//send immediately only if no current active receiver | ||
if (this.sendQueue.isEmpty() || !this.receiveQueue.peekFront()) { | ||
if (this.sendQueue.isEmpty() && this.receiveQueue.isEmpty()) { | ||
this.receiveQueue.push(cmd); | ||
@@ -1261,3 +1263,5 @@ cmd.start(this.streamOut, this.opts, this.info); | ||
} | ||
if (this.status < Status.CLOSING) { | ||
this.addCommand = this.addCommandEnable; | ||
} | ||
this.addCommand( | ||
@@ -1268,2 +1272,3 @@ new ChangeUser( | ||
(res) => { | ||
if (this.status < Status.CLOSING && this.opts.pipelining) this.addCommand = this.addCommandEnablePipeline; | ||
if (cmdParam.opts && cmdParam.opts.collation) this.opts.collation = cmdParam.opts.collation; | ||
@@ -1273,3 +1278,3 @@ resolve(res); | ||
this.authFailHandler.bind(this, reject), | ||
this.addCommand.bind(this) | ||
this.getSocket.bind(this) | ||
) | ||
@@ -1328,2 +1333,187 @@ ); | ||
importFile(cmdParam, resolve, reject) { | ||
const conn = this; | ||
if (!cmdParam || !cmdParam.file) { | ||
return reject( | ||
Errors.createError( | ||
'SQL file parameter is mandatory', | ||
Errors.ER_MISSING_SQL_PARAMETER, | ||
conn.info, | ||
'HY000', | ||
null, | ||
false, | ||
cmdParam.stack | ||
) | ||
); | ||
} | ||
const prevAddCommand = this.addCommand.bind(conn); | ||
this.waitingAuthenticationQueue = new Queue(); | ||
this.addCommand = this.addCommandQueue; | ||
const tmpQuery = function (sql, resolve, reject) { | ||
const cmd = new Query( | ||
resolve, | ||
(err) => { | ||
if (conn.opts.logger.error) conn.opts.logger.error(err); | ||
reject(err); | ||
}, | ||
conn.opts, | ||
new CommandParameter(sql, null, {}) | ||
); | ||
prevAddCommand(cmd); | ||
}; | ||
let prevDatabase = null; | ||
return ( | ||
cmdParam.skipDbCheck ? Promise.resolve() : new Promise(tmpQuery.bind(conn, 'SELECT DATABASE() as db')) | ||
).then((res) => { | ||
prevDatabase = res ? res[0].db : null; | ||
if ( | ||
(cmdParam.skipDbCheck && !conn.opts.database) || | ||
(!cmdParam.skipDbCheck && !cmdParam.database && !prevDatabase) | ||
) { | ||
return reject( | ||
Errors.createError( | ||
'Database parameter is not set and no database is selected', | ||
Errors.ER_MISSING_DATABASE_PARAMETER, | ||
conn.info, | ||
'HY000', | ||
null, | ||
false, | ||
cmdParam.stack | ||
) | ||
); | ||
} | ||
const searchDbPromise = cmdParam.database | ||
? new Promise(tmpQuery.bind(conn, `USE \`${cmdParam.database.replace(/`/gi, '``')}\``)) | ||
: Promise.resolve(); | ||
return searchDbPromise.then(() => { | ||
const endingFunction = () => { | ||
if (conn.status < Status.CLOSING) { | ||
conn.addCommand = conn.addCommandEnable.bind(conn); | ||
if (conn.status < Status.CLOSING && conn.opts.pipelining) { | ||
conn.addCommand = conn.addCommandEnablePipeline.bind(conn); | ||
} | ||
const commands = conn.waitingAuthenticationQueue.toArray(); | ||
commands.forEach((cmd) => { | ||
conn.addCommand(cmd); | ||
}); | ||
conn.waitingAuthenticationQueue = null; | ||
} | ||
}; | ||
return fsPromises | ||
.open(cmdParam.file, 'r') | ||
.then(async (fd) => { | ||
const buf = { | ||
buffer: Buffer.allocUnsafe(16384), | ||
offset: 0, | ||
end: 0 | ||
}; | ||
const queryPromises = []; | ||
let cmdError = null; | ||
while (!cmdError) { | ||
try { | ||
const res = await fd.read(buf.buffer, buf.end, buf.buffer.length - buf.end, null); | ||
if (res.bytesRead == 0) { | ||
// end of file reached. | ||
fd.close().catch(() => {}); | ||
if (cmdError) { | ||
endingFunction(); | ||
reject(cmdError); | ||
return; | ||
} | ||
Promise.allSettled(queryPromises) | ||
.then(() => { | ||
if (!cmdParam.skipDbCheck && cmdParam.database && cmdParam.database != prevDatabase) { | ||
return new Promise(tmpQuery.bind(conn, `USE \`${prevDatabase.replace(/`/gi, '``')}\``)); | ||
} | ||
return Promise.resolve(); | ||
}) | ||
.then(() => { | ||
endingFunction(); | ||
resolve(); | ||
}) | ||
.catch((err) => { | ||
endingFunction(); | ||
reject(err); | ||
}); | ||
return; | ||
} else { | ||
buf.end += res.bytesRead; | ||
const queries = Parse.parseQueries(buf); | ||
const queryIntermediatePromise = queries.flatMap((element) => { | ||
return new Promise(tmpQuery.bind(conn, element)).catch((err) => { | ||
cmdError = err; | ||
}); | ||
}); | ||
queryPromises.push(...queryIntermediatePromise); | ||
if (buf.offset == buf.end) { | ||
buf.offset = 0; | ||
buf.end = 0; | ||
} else { | ||
// ensure that buffer can at least read 8k bytes, | ||
// either by copying remaining data on used part or growing buffer | ||
if (buf.offset > 8192) { | ||
// reuse buffer, copying remaining data begin of buffer | ||
buf.buffer.copy(buf.buffer, 0, buf.offset, buf.end); | ||
buf.end -= buf.offset; | ||
buf.offset = 0; | ||
} else if (buf.buffer.length - buf.end < 8192) { | ||
// grow buffer | ||
const tmpBuf = Buffer.allocUnsafe(buf.buffer.length << 1); | ||
buf.buffer.copy(tmpBuf, 0, buf.offset, buf.end); | ||
buf.buffer = tmpBuf; | ||
buf.end -= buf.offset; | ||
buf.offset = 0; | ||
} | ||
} | ||
} | ||
} catch (e) { | ||
fd.close().catch(() => {}); | ||
endingFunction(); | ||
Promise.allSettled(queryPromises).catch(() => {}); | ||
return reject( | ||
Errors.createError( | ||
e.message, | ||
Errors.ER_SQL_FILE_ERROR, | ||
conn.info, | ||
'HY000', | ||
null, | ||
false, | ||
cmdParam.stack | ||
) | ||
); | ||
} | ||
} | ||
if (cmdError) { | ||
endingFunction(); | ||
reject(cmdError); | ||
} | ||
}) | ||
.catch((err) => { | ||
endingFunction(); | ||
if (err.code === 'ENOENT') { | ||
return reject( | ||
Errors.createError( | ||
`SQL file parameter '${cmdParam.file}' doesn't exists`, | ||
Errors.ER_MISSING_SQL_FILE, | ||
conn.info, | ||
'HY000', | ||
null, | ||
false, | ||
cmdParam.stack | ||
) | ||
); | ||
} | ||
return reject( | ||
Errors.createError(err.message, Errors.ER_SQL_FILE_ERROR, conn.info, 'HY000', null, false, cmdParam.stack) | ||
); | ||
}); | ||
}); | ||
}); | ||
} | ||
/** | ||
@@ -1361,2 +1551,3 @@ * Clearing connection variables when ending. | ||
} | ||
_logAndReject(reject, err) { | ||
@@ -1376,2 +1567,3 @@ if (this.opts.logger.error) this.opts.logger.error(err); | ||
} | ||
getCollation() { | ||
@@ -1378,0 +1570,0 @@ return this.#collation; |
@@ -70,3 +70,5 @@ 'use strict'; | ||
cmd.onPacketReceive(packet, this.out, this.opts, this.info); | ||
if (!cmd.onPacketReceive) this.receiveQueue.shift(); | ||
if (!cmd.onPacketReceive) { | ||
this.receiveQueue.shift(); | ||
} | ||
} | ||
@@ -73,0 +75,0 @@ |
@@ -16,3 +16,3 @@ 'use strict'; | ||
this.name = 'SqlError'; | ||
this.text = msg; | ||
this.sqlMessage = msg; | ||
this.sql = sql; | ||
@@ -33,2 +33,6 @@ this.fatal = fatal; | ||
} | ||
get text() { | ||
return this.sqlMessage; | ||
} | ||
} | ||
@@ -138,2 +142,6 @@ | ||
module.exports.ER_PREPARE_CLOSED = 45051; | ||
module.exports.ER_MISSING_SQL_PARAMETER = 45052; | ||
module.exports.ER_MISSING_SQL_FILE = 45053; | ||
module.exports.ER_SQL_FILE_ERROR = 45054; | ||
module.exports.ER_MISSING_DATABASE_PARAMETER = 45055; | ||
@@ -140,0 +148,0 @@ const keys = Object.keys(module.exports); |
@@ -24,2 +24,3 @@ const Errors = require('../misc/errors'); | ||
const COLON_BYTE = ':'.charCodeAt(0); | ||
const SEMICOLON_BYTE = ';'.charCodeAt(0); | ||
@@ -412,1 +413,103 @@ /** | ||
}; | ||
/** | ||
* Parse commands from buffer | ||
* | ||
* @param bufState buffer | ||
* @returns {*[]} array of queries contained in buffer | ||
*/ | ||
module.exports.parseQueries = function (bufState) { | ||
let state = State.Normal; | ||
let lastChar = 0x00; | ||
let currByte; | ||
let queries = []; | ||
let singleQuotes = false; | ||
for (let i = bufState.offset; i < bufState.end; i++) { | ||
currByte = bufState.buffer[i]; | ||
if ( | ||
state === State.Escape && | ||
!((currByte === QUOTE_BYTE && singleQuotes) || (currByte === DBL_QUOTE_BYTE && !singleQuotes)) | ||
) { | ||
state = State.String; | ||
lastChar = currByte; | ||
continue; | ||
} | ||
switch (currByte) { | ||
case STAR_BYTE: | ||
if (state === State.Normal && lastChar === SLASH_BYTE) { | ||
state = State.SlashStarComment; | ||
} | ||
break; | ||
case SLASH_BYTE: | ||
if (state === State.SlashStarComment && lastChar === STAR_BYTE) { | ||
state = State.Normal; | ||
} else if (state === State.Normal && lastChar === SLASH_BYTE) { | ||
state = State.EOLComment; | ||
} | ||
break; | ||
case HASH_BYTE: | ||
if (state === State.Normal) { | ||
state = State.EOLComment; | ||
} | ||
break; | ||
case MINUS_BYTE: | ||
if (state === State.Normal && lastChar === MINUS_BYTE) { | ||
state = State.EOLComment; | ||
} | ||
break; | ||
case LINE_FEED_BYTE: | ||
if (state === State.EOLComment) { | ||
state = State.Normal; | ||
} | ||
break; | ||
case DBL_QUOTE_BYTE: | ||
if (state === State.Normal) { | ||
state = State.String; | ||
singleQuotes = false; | ||
} else if (state === State.String && !singleQuotes) { | ||
state = State.Normal; | ||
} else if (state === State.Escape) { | ||
state = State.String; | ||
} | ||
break; | ||
case QUOTE_BYTE: | ||
if (state === State.Normal) { | ||
state = State.String; | ||
singleQuotes = true; | ||
} else if (state === State.String && singleQuotes) { | ||
state = State.Normal; | ||
} else if (state === State.Escape) { | ||
state = State.String; | ||
} | ||
break; | ||
case BACKSLASH_BYTE: | ||
if (state === State.String) { | ||
state = State.Escape; | ||
} | ||
break; | ||
case SEMICOLON_BYTE: | ||
if (state === State.Normal) { | ||
queries.push(bufState.buffer.toString('utf8', bufState.offset, i)); | ||
bufState.offset = i + 1; | ||
} | ||
break; | ||
case RADICAL_BYTE: | ||
if (state === State.Backtick) { | ||
state = State.Normal; | ||
} else if (state === State.Normal) { | ||
state = State.Backtick; | ||
} | ||
break; | ||
} | ||
lastChar = currByte; | ||
} | ||
return queries; | ||
}; |
@@ -183,4 +183,44 @@ 'use strict'; | ||
} | ||
/** | ||
* Import sql file. | ||
* | ||
* @param opts JSON array with 2 possible fields: file and database | ||
* @param cb callback | ||
*/ | ||
importFile(opts, cb) { | ||
if (!opts) { | ||
if (cb) | ||
cb( | ||
Errors.createError( | ||
'SQL file parameter is mandatory', | ||
Errors.ER_MISSING_SQL_PARAMETER, | ||
null, | ||
'HY000', | ||
null, | ||
false, | ||
null | ||
) | ||
); | ||
return; | ||
} | ||
this.#pool | ||
.getConnection({}) | ||
.then((baseConn) => { | ||
return new Promise(baseConn.importFile.bind(baseConn, { file: opts.file, database: opts.database })).finally( | ||
() => { | ||
this.#pool.release(baseConn); | ||
} | ||
); | ||
}) | ||
.then(() => { | ||
if (cb) cb(); | ||
}) | ||
.catch((err) => { | ||
if (cb) cb(err); | ||
}); | ||
} | ||
} | ||
module.exports = PoolCallback; |
@@ -8,2 +8,3 @@ 'use strict'; | ||
const CommandParameter = require('./command-parameter'); | ||
const Errors = require('./misc/errors'); | ||
@@ -141,4 +142,33 @@ class PoolPromise extends EventEmitter { | ||
} | ||
/** | ||
* Import sql file. | ||
* | ||
* @param opts JSON array with 2 possible fields: file and database | ||
*/ | ||
importFile(opts) { | ||
if (!opts) { | ||
return Promise.reject( | ||
Errors.createError( | ||
'SQL file parameter is mandatory', | ||
Errors.ER_MISSING_SQL_PARAMETER, | ||
conn.info, | ||
'HY000', | ||
null, | ||
false, | ||
null | ||
) | ||
); | ||
} | ||
return this.#pool.getConnection({}).then((baseConn) => { | ||
return new Promise(baseConn.importFile.bind(baseConn, { file: opts.file, database: opts.database })).finally( | ||
() => { | ||
this.#pool.release(baseConn); | ||
} | ||
); | ||
}); | ||
} | ||
} | ||
module.exports = PoolPromise; |
{ | ||
"name": "mariadb", | ||
"version": "3.1.2", | ||
"version": "3.2.0", | ||
"description": "fast mariadb or mysql connector.", | ||
@@ -15,6 +15,6 @@ "main": "promise.js", | ||
"test:base": "mocha --no-parallel --timeout 5000 \"test/**/*.js\" ", | ||
"test:lint": "eslint \"{lib,test}/**/*.js\" ", | ||
"test:lint": "eslint \"*.js\" \"{lib,test}/**/*.js\" ", | ||
"test:types": "eslint \"types/*.ts\" ", | ||
"test:types-prettier": "prettier --write \"types/*.ts\"", | ||
"test:prettier": "prettier --write \"{tools,lib,test,benchmarks}/**/*.js\"", | ||
"test:prettier": "prettier --write \"*.js\" \"{tools,lib,test,benchmarks}/**/*.js\"", | ||
"coverage": "npm run coverage:test && npm run coverage:create && npm run coverage:send", | ||
@@ -21,0 +21,0 @@ "coverage:test": "nyc mocha --no-parallel --timeout 5000 \"test/**/*.js\"", |
@@ -13,2 +13,3 @@ 'use strict'; | ||
const ClusterOptions = require('./lib/config/cluster-options'); | ||
const CommandParameter = require('./lib/command-parameter'); | ||
@@ -53,1 +54,19 @@ module.exports.version = require('./package.json').version; | ||
}; | ||
module.exports.importFile = function importFile(opts) { | ||
try { | ||
const options = new ConnOptions(opts); | ||
const conn = new Connection(options); | ||
return conn | ||
.connect() | ||
.then(() => { | ||
return new Promise(conn.importFile.bind(conn, Object.assign({ skipDbCheck: true }, opts))); | ||
}) | ||
.finally(() => { | ||
new Promise(conn.end.bind(conn, new CommandParameter())).catch(console.log); | ||
}); | ||
} catch (err) { | ||
return Promise.reject(err); | ||
} | ||
}; |
@@ -38,3 +38,4 @@ <p style="text-align: center;"> | ||
* pipelining | ||
* metadata skipping (for MariaDB server only) | ||
* metadata skipping (for MariaDB server only) | ||
* sql file import | ||
* ... | ||
@@ -41,0 +42,0 @@ |
@@ -11,2 +11,3 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ | ||
import geojson = require('geojson'); | ||
import events = require('events'); | ||
@@ -17,2 +18,3 @@ export const version: string; | ||
export function createPoolCluster(config?: PoolClusterConfig): PoolCluster; | ||
export function importFile(config: ImportFileConfig): Promise<void>; | ||
export function defaultOptions(connectionUri?: string | ConnectionConfig): any; | ||
@@ -147,2 +149,15 @@ | ||
/** | ||
* @deprecated big numbers (BIGINT and DECIMAL columns) will result as string when not in safe number range. | ||
* now replaced by decimalAsNumber, bigIntAsNumber and checkNumberRange options | ||
*/ | ||
supportBigNumbers?: boolean; | ||
/** | ||
* @deprecated when used with supportBigNumbers, big numbers (BIGINT and DECIMAL columns) will always result as string | ||
* even if in safe number range. | ||
* now replaced by decimalAsNumber, bigIntAsNumber and checkNumberRange options | ||
*/ | ||
bigNumberStrings?: boolean; | ||
/** | ||
* Throw if conversion to Number is not safe. | ||
@@ -394,2 +409,9 @@ * | ||
export interface ImportFileConfig extends ConnectionConfig { | ||
/** | ||
* sql file path to import | ||
*/ | ||
file: string; | ||
} | ||
export interface PoolConfig extends ConnectionConfig { | ||
@@ -515,3 +537,14 @@ /** | ||
} | ||
export interface SqlImportOptions { | ||
/** | ||
* file path of sql file | ||
*/ | ||
file: string; | ||
/** | ||
* Name of the database to use to import sql file. | ||
* If not set, current database is used. | ||
*/ | ||
database?: string; | ||
} | ||
export interface ConnectionInfo { | ||
@@ -570,3 +603,3 @@ /** | ||
export interface Connection { | ||
export interface Connection extends events.EventEmitter { | ||
/** | ||
@@ -647,2 +680,7 @@ * Connection information | ||
/** | ||
* import sql file | ||
*/ | ||
importFile(config: SqlImportOptions): Promise<void>; | ||
/** | ||
* Indicates the state of the connection as the driver knows it | ||
@@ -700,2 +738,3 @@ */ | ||
on(ev: 'error', callback: (err: SqlError) => void): Connection; | ||
on(eventName: string | symbol, listener: (...args: any[]) => void): this; | ||
listeners(ev: 'end'): (() => void)[]; | ||
@@ -742,2 +781,7 @@ listeners(ev: 'error'): ((err: SqlError) => void)[]; | ||
/** | ||
* import sql file | ||
*/ | ||
importFile(config: SqlImportOptions): Promise<void>; | ||
/** | ||
* Get current active connections. | ||
@@ -820,2 +864,3 @@ */ | ||
* original error message value | ||
* @deprecated since 3.2.0 prefer using sqlMessage for compatibility with other drivers. | ||
*/ | ||
@@ -825,2 +870,7 @@ text: string | null; | ||
/** | ||
* original error message value | ||
*/ | ||
sqlMessage: string | null; | ||
/** | ||
* The sql command associate | ||
@@ -827,0 +877,0 @@ */ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
546602
14737
150
5