Comparing version 2.2.0 to 2.3.0
@@ -12,3 +12,3 @@ 'use strict'; | ||
module.exports.version = require('./package.json').version; | ||
module.exports.SqlError = require('./lib/misc/errors').SqlError; | ||
module.exports.createConnection = function createConnection(opts) { | ||
@@ -15,0 +15,0 @@ return new ConnectionCallback(new ConnOptions(opts)); |
# Change Log | ||
## [2.3.0](https://github.com/mariadb-corporation/mariadb-connector-nodejs/tree/2.3.0) (19 Mar. 2020) | ||
[Full Changelog](https://github.com/mariadb-corporation/mariadb-connector-nodejs/compare/2.2.0...2.3.0) | ||
* CONJS-127 - Resultset with same identifier skip data. Now an error will be thrown. | ||
* CONJS-126 - permit setting session query timeout per option | ||
* CONJS-124 - Force connection.escapeId to emit backtick #101 | ||
* CONJS-123 - exporting SqlError class to permit instanceOf checks #100 | ||
* CONJS-122 - fix undefined localTz with timezone: 'Z' issue #92 | ||
* CONJS-121 - Connection.escapeId must always quote value to permit reserved words | ||
misc: | ||
* appveyor testing server version upgrade | ||
* better debug logging trace format | ||
* correct ssl test | ||
## [2.2.0](https://github.com/mariadb-corporation/mariadb-connector-nodejs/tree/2.2.0) (03 Feb. 2020) | ||
@@ -3,0 +17,0 @@ [Full Changelog](https://github.com/mariadb-corporation/mariadb-connector-nodejs/compare/2.1.5...2.2.0) |
@@ -24,38 +24,88 @@ 'use strict'; | ||
/** | ||
* Throw an an unexpected error. | ||
* server exchange will still be read to keep connection in a good state, but promise will be rejected. | ||
* | ||
* @param msg message | ||
* @param fatal is error fatal for connection | ||
* @param info current server state information | ||
* @param sqlState error sqlState | ||
* @param errno error number | ||
*/ | ||
throwUnexpectedError(msg, fatal, info, sqlState, errno) { | ||
if (this.reject) { | ||
process.nextTick( | ||
this.reject, | ||
Errors.createError(msg, fatal, info, sqlState, errno, this.stack, false) | ||
); | ||
this.resolve = null; | ||
this.reject = null; | ||
} | ||
} | ||
/** | ||
* Create and throw new Error from error information | ||
* only first called throwing an error or successfully end will be executed. | ||
* | ||
* @param msg message | ||
* @param fatal is error fatal for connection | ||
* @param info current server state information | ||
* @param sqlState error sqlState | ||
* @param errno error number | ||
*/ | ||
throwNewError(msg, fatal, info, sqlState, errno) { | ||
process.nextTick( | ||
this.reject, | ||
Errors.createError(msg, fatal, info, sqlState, errno, this.stack, false) | ||
); | ||
this.onPacketReceive = null; | ||
this.resolve = null; | ||
this.reject = null; | ||
if (this.reject) { | ||
process.nextTick( | ||
this.reject, | ||
Errors.createError(msg, fatal, info, sqlState, errno, this.stack, false) | ||
); | ||
this.resolve = null; | ||
this.reject = null; | ||
} | ||
this.emit('end'); | ||
} | ||
/** | ||
* Throw Error | ||
* only first called throwing an error or successfully end will be executed. | ||
* | ||
* @param err error to be thrown | ||
* @param info current server state information | ||
*/ | ||
throwError(err, info) { | ||
if (this.stack) { | ||
err = Errors.createError( | ||
err.message, | ||
err.fatal, | ||
info, | ||
err.sqlState, | ||
err.errno, | ||
this.stack, | ||
false | ||
); | ||
this.onPacketReceive = null; | ||
if (this.reject) { | ||
if (this.stack) { | ||
err = Errors.createError( | ||
err.message, | ||
err.fatal, | ||
info, | ||
err.sqlState, | ||
err.errno, | ||
this.stack, | ||
false | ||
); | ||
} | ||
this.resolve = null; | ||
process.nextTick(this.reject, err); | ||
this.reject = null; | ||
} | ||
this.onPacketReceive = null; | ||
this.resolve = null; | ||
process.nextTick(this.reject, err); | ||
this.reject = null; | ||
this.emit('end', err); | ||
} | ||
/** | ||
* Successfully end command. | ||
* only first called throwing an error or successfully end will be executed. | ||
* | ||
* @param val return value. | ||
*/ | ||
successEnd(val) { | ||
this.onPacketReceive = null; | ||
this.reject = null; | ||
process.nextTick(this.resolve, val); | ||
this.resolve = null; | ||
this.emit('end'); | ||
if (this.resolve) { | ||
this.onPacketReceive = null; | ||
this.reject = null; | ||
process.nextTick(this.resolve, val); | ||
this.resolve = null; | ||
this.emit('end'); | ||
} | ||
} | ||
@@ -62,0 +112,0 @@ |
@@ -0,0 +0,0 @@ 'use strict'; |
@@ -92,2 +92,4 @@ 'use strict'; | ||
this.opts = connOpts; | ||
// we only need add timeout if needed | ||
this.opts.timeout = 0; | ||
return; | ||
@@ -97,2 +99,4 @@ } | ||
timeout: cmdOpts.timeout, | ||
checkDuplicate: | ||
cmdOpts.checkDuplicate != undefined ? cmdOpts.checkDuplicate : connOpts.checkDuplicate, | ||
typeCast: cmdOpts.typeCast != undefined ? cmdOpts.typeCast : connOpts.typeCast, | ||
@@ -103,2 +107,3 @@ rowsAsArray: cmdOpts.rowsAsArray != undefined ? cmdOpts.rowsAsArray : connOpts.rowsAsArray, | ||
tz: cmdOpts.tz != undefined ? cmdOpts.tz : connOpts.tz, | ||
localTz: cmdOpts.localTz != undefined ? cmdOpts.localTz : connOpts.localTz, | ||
namedPlaceholders: | ||
@@ -251,2 +256,3 @@ cmdOpts.namedPlaceholders != undefined | ||
} | ||
this.checkDuplicates(); | ||
} else if (this.opts.nestTables === true) { | ||
@@ -257,2 +263,3 @@ this.parseRow = this.parseRowNested; | ||
} | ||
this.checkNestTablesDuplicates(); | ||
} | ||
@@ -264,2 +271,3 @@ } else { | ||
} | ||
this.checkDuplicates(); | ||
} | ||
@@ -276,2 +284,48 @@ } | ||
checkDuplicates() { | ||
if (this.opts.checkDuplicate) { | ||
for (let i = 0; i < this._columnCount; i++) { | ||
if (this.tableHeader.indexOf(this.tableHeader[i], i + 1) > 0) { | ||
const dupes = this.tableHeader.reduce( | ||
(acc, v, i, arr) => | ||
arr.indexOf(v) !== i && acc.indexOf(v) === -1 ? acc.concat(v) : acc, | ||
[] | ||
); | ||
this.throwUnexpectedError( | ||
'Error in results, duplicate field name `' + dupes[0] + '`', | ||
false, | ||
null, | ||
'42000', | ||
Errors.ER_DUPLICATE_FIELD | ||
); | ||
} | ||
} | ||
} | ||
} | ||
checkNestTablesDuplicates() { | ||
if (this.opts.checkDuplicate) { | ||
for (let i = 0; i < this._columnCount; i++) { | ||
for (let j = 0; j < i; j++) { | ||
if ( | ||
this.tableHeader[j][0] === this.tableHeader[i][0] && | ||
this.tableHeader[j][1] === this.tableHeader[i][1] | ||
) { | ||
this.throwUnexpectedError( | ||
'Error in results, duplicate field name `' + | ||
this.tableHeader[i][0] + | ||
'`.`' + | ||
this.tableHeader[i][1] + | ||
'`', | ||
false, | ||
null, | ||
'42000', | ||
Errors.ER_DUPLICATE_FIELD | ||
); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
/** | ||
@@ -278,0 +332,0 @@ * Read intermediate EOF. |
@@ -55,4 +55,6 @@ 'use strict'; | ||
this.connectTimeout = opts.connectTimeout === undefined ? 10000 : opts.connectTimeout; | ||
this.timeout = opts.timeout === undefined ? 0 : opts.timeout; | ||
this.socketTimeout = opts.socketTimeout === undefined ? 0 : opts.socketTimeout; | ||
this.database = opts.database; | ||
this.checkDuplicate = opts.checkDuplicate === undefined ? true : opts.checkDuplicate; | ||
this.dateStrings = opts.dateStrings || false; | ||
@@ -70,7 +72,7 @@ this.debug = opts.debug || false; | ||
this.namedPlaceholders = opts.namedPlaceholders || false; | ||
this.nestTables = opts.nestTables === undefined ? undefined : opts.nestTables; | ||
this.nestTables = opts.nestTables; | ||
this.password = opts.password; | ||
this.permitSetMultiParamEntries = opts.permitSetMultiParamEntries || false; | ||
this.permitConnectionWhenExpired = opts.permitConnectionWhenExpired || false; | ||
this.pipelining = opts.pipelining === undefined || opts.pipelining; | ||
this.pipelining = opts.pipelining; | ||
if (opts.pipelining === undefined) { | ||
@@ -175,4 +177,6 @@ this.permitLocalInfile = opts.permitLocalInfile || false; | ||
if (opts.debug) opts.debug = opts.debug == 'true'; | ||
if (opts.checkDuplicate) opts.checkDuplicate = opts.checkDuplicate == 'true'; | ||
if (opts.debugCompress) opts.debugCompress = opts.debugCompress == 'true'; | ||
if (opts.debugLen) opts.debugLen = parseInt(opts.debugLen); | ||
if (opts.timeout) opts.timeout = parseInt(opts.timeout); | ||
if (opts.foundRows) opts.foundRows = opts.foundRows == 'true'; | ||
@@ -179,0 +183,0 @@ if (opts.maxAllowedPacket && !isNaN(Number.parseInt(opts.maxAllowedPacket))) |
@@ -813,2 +813,44 @@ 'use strict'; | ||
const _executeSessionTimeout = () => { | ||
if (opts.timeout) { | ||
if (info.isMariaDB() && info.hasMinVersion(10, 1, 2)) { | ||
return new Promise(function(resolve, reject) { | ||
const errorHandling = initialErr => { | ||
reject( | ||
Errors.createError( | ||
'Error setting session timeout: ' + initialErr.message, | ||
true, | ||
info, | ||
'08S01', | ||
Errors.ER_INITIAL_TIMEOUT_ERROR, | ||
null | ||
) | ||
); | ||
}; | ||
const cmd = new Query( | ||
resolve, | ||
errorHandling, | ||
null, | ||
opts, | ||
'SET max_statement_time=' + opts.timeout / 1000, | ||
null | ||
); | ||
if (opts.trace) Error.captureStackTrace(cmd); | ||
_addCommand(cmd); | ||
}); | ||
} else { | ||
return Promise.reject( | ||
Errors.createError( | ||
'Can only use timeout for MariaDB server after 10.1.1. timeout value: ' + opts.timeout, | ||
false, | ||
info, | ||
'HY000', | ||
Errors.ER_TIMEOUT_NOT_SUPPORTED | ||
) | ||
); | ||
} | ||
} | ||
return Promise.resolve(); | ||
}; | ||
const _getSocket = () => { | ||
@@ -910,2 +952,5 @@ return _socket; | ||
.then(() => { | ||
return _executeSessionTimeout(); | ||
}) | ||
.then(() => { | ||
_status = Status.CONNECTED; | ||
@@ -912,0 +957,0 @@ process.nextTick(resolve, this); |
'use strict'; | ||
const ErrorCodes = require('../const/error-code'); | ||
class SQLError extends Error { | ||
class SqlError extends Error { | ||
constructor(msg, fatal, info, sqlState, errno, additionalStack, addHeader) { | ||
@@ -55,3 +55,3 @@ super( | ||
) { | ||
return new SQLError(msg, fatal, info, sqlState, errno, additionalStack, addHeader); | ||
return new SqlError(msg, fatal, info, sqlState, errno, additionalStack, addHeader); | ||
}; | ||
@@ -100,2 +100,4 @@ | ||
module.exports.ER_TIMEOUT_NOT_SUPPORTED = 45038; | ||
module.exports.ER_INITIAL_TIMEOUT_ERROR = 45039; | ||
module.exports.ER_DUPLICATE_FIELD = 45040; | ||
@@ -110,1 +112,3 @@ const keys = Object.keys(module.exports); | ||
} | ||
module.exports.SqlError = SqlError; |
@@ -32,4 +32,11 @@ 'use strict'; | ||
out.push( | ||
'+--------------------------------------------------+\n' + | ||
'| 0 1 2 3 4 5 6 7 8 9 a b c d e f |\n' + | ||
'+--------------------------------------------------+------------------+\n' | ||
); | ||
if (useHeader) { | ||
while (pos < header.length) { | ||
if (posHexa === 0) out.push('| '); | ||
byteValue = header[pos++] & 0xff; | ||
@@ -39,2 +46,3 @@ out.push(hexArray[byteValue >>> 4], hexArray[byteValue & 0x0f], ' '); | ||
byteValue > 31 && byteValue < 127 ? String.fromCharCode(byteValue) : '.'; | ||
if (posHexa === 8) out.push(' '); | ||
} | ||
@@ -45,2 +53,3 @@ } | ||
while (pos < maxLgh + offset) { | ||
if (posHexa === 0) out.push('| '); | ||
byteValue = buf[pos] & 0xff; | ||
@@ -55,3 +64,3 @@ | ||
if (posHexa === 16) { | ||
out.push(' ', asciiValue.join(''), '\n'); | ||
out.push('| ', asciiValue.join(''), ' |\n'); | ||
posHexa = 0; | ||
@@ -65,12 +74,19 @@ } | ||
if (remaining < 8) { | ||
for (; remaining < 8; remaining++) out.push(' '); | ||
for (; remaining < 8; remaining++) { | ||
out.push(' '); | ||
asciiValue[posHexa++] = ' '; | ||
} | ||
out.push(' '); | ||
} | ||
for (; remaining < 16; remaining++) out.push(' '); | ||
for (; remaining < 16; remaining++) { | ||
out.push(' '); | ||
asciiValue[posHexa++] = ' '; | ||
} | ||
out.push(' ', asciiValue.slice(0, posHexa).join('') + (isLimited ? ' ...' : ''), '\n'); | ||
out.push('| ', asciiValue.join(''), isLimited ? ' |...\n' : ' |\n'); | ||
} else if (isLimited) { | ||
out[out.length - 2] = out[out.length - 2] + ' ...'; | ||
out[out.length - 1] = ' |...\n'; | ||
} | ||
out.push('+--------------------------------------------------+------------------+\n'); | ||
return out.join(''); | ||
@@ -89,20 +105,19 @@ }; | ||
} | ||
if (value.match(/^[0-9a-zA-Z\$_\u0080-\uFFFF]+$/u)) { | ||
if (value.includes('\u0000')) { | ||
throw Errors.createError( | ||
'Cannot escape ID with null character (u0000)', | ||
false, | ||
info, | ||
'0A000', | ||
Errors.ER_NULL_CHAR_ESCAPEID | ||
); | ||
} | ||
// always return escaped value, event when there is no special characters | ||
// to permit working with reserved words | ||
if (value.match(/^`.+`$/g)) { | ||
// already escaped | ||
return value; | ||
} else { | ||
if (value.includes('\u0000')) { | ||
throw Errors.createError( | ||
'Cannot escape ID with null character (u0000)', | ||
false, | ||
info, | ||
'0A000', | ||
Errors.ER_NULL_CHAR_ESCAPEID | ||
); | ||
} | ||
if (value.match(/^`.+`$/g)) { | ||
value = value.substring(1, value.length - 1); | ||
} | ||
return '`' + value.replace(/`/g, '``') + '`'; | ||
} | ||
return '`' + value.replace(/`/g, '``') + '`'; | ||
}; | ||
@@ -109,0 +124,0 @@ |
{ | ||
"name": "mariadb", | ||
"version": "2.2.0", | ||
"version": "2.3.0", | ||
"description": "fast mariadb/mysql connector.", | ||
@@ -5,0 +5,0 @@ "main": "promise.js", |
@@ -12,2 +12,3 @@ 'use strict'; | ||
module.exports.version = require('./package.json').version; | ||
module.exports.SqlError = require('./lib/misc/errors').SqlError; | ||
@@ -14,0 +15,0 @@ module.exports.createConnection = function createConnection(opts) { |
@@ -251,2 +251,14 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ | ||
/** | ||
* Force server version check by explicitly using SELECT VERSION(), not relying on server initial packet. | ||
* (Default: false) | ||
*/ | ||
forceVersionCheck?: boolean; | ||
/** | ||
* indicate to throw an exception if result-set will not contain some data due to having duplicate identifier | ||
* (Default: true) | ||
*/ | ||
checkDuplicate?: boolean; | ||
/** | ||
* When enabled, the update number corresponds to update rows. | ||
@@ -519,3 +531,3 @@ * When disabled, it indicates the real rows changed. | ||
on(ev: 'end', callback: () => void): Connection; | ||
on(ev: 'error', callback: (err: MariaDbError) => void): Connection; | ||
on(ev: 'error', callback: (err: SqlError) => void): Connection; | ||
} | ||
@@ -616,3 +628,3 @@ | ||
export interface MariaDbError extends Error { | ||
export interface SqlError extends Error { | ||
/** | ||
@@ -619,0 +631,0 @@ * Either a MySQL server error (e.g. 'ER_ACCESS_DENIED_ERROR'), |
Deprecated
MaintenanceThe maintainer of the package marked it as deprecated. This could indicate that a single version should not be used, or that the package is no longer maintained and any new vulnerabilities will not be fixed.
Found 1 instance in 1 package
503257
13253
1