12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025 |
- const Errors = require('../misc/errors');
- const State = {
- Normal: 1 /* inside query */,
- String: 2 /* inside string */,
- SlashStarComment: 3 /* inside slash-star comment */,
- Escape: 4 /* found backslash */,
- EOLComment: 5 /* # comment, or // comment, or -- comment */,
- Backtick: 6 /* found backtick */,
- Placeholder: 7 /* found placeholder */
- };
- /**
- * Split query according to parameters (question mark).
- * Question mark in comment are not taken in account
- *
- * @returns {Array} query separated by parameters
- */
- module.exports.splitQuery = function (sql) {
- let partList = [];
- let state = State.Normal;
- let lastChar = '\0';
- let singleQuotes = false;
- let lastParameterPosition = 0;
- let idx = 0;
- let car = sql.charAt(idx++);
- while (car !== '') {
- if (
- state === State.Escape &&
- !((car === "'" && singleQuotes) || (car === '"' && !singleQuotes))
- ) {
- state = State.String;
- car = sql.charAt(idx++);
- continue;
- }
- switch (car) {
- case '*':
- if (state === State.Normal && lastChar == '/') state = State.SlashStarComment;
- break;
- case '/':
- if (state === State.SlashStarComment && lastChar == '*') state = State.Normal;
- break;
- case '#':
- if (state === State.Normal) state = State.EOLComment;
- break;
- case '-':
- if (state === State.Normal && lastChar == '-') {
- state = State.EOLComment;
- }
- break;
- case '\n':
- if (state === State.EOLComment) {
- state = State.Normal;
- }
- break;
- case '"':
- if (state === State.Normal) {
- state = State.String;
- singleQuotes = false;
- } else if (state === State.String && !singleQuotes) {
- state = State.Normal;
- } else if (state === State.Escape && !singleQuotes) {
- state = State.String;
- }
- break;
- case "'":
- if (state === State.Normal) {
- state = State.String;
- singleQuotes = true;
- } else if (state === State.String && singleQuotes) {
- state = State.Normal;
- } else if (state === State.Escape && singleQuotes) {
- state = State.String;
- }
- break;
- case '\\':
- if (state === State.String) state = State.Escape;
- break;
- case '?':
- if (state === State.Normal) {
- partList.push(sql.substring(lastParameterPosition, idx - 1));
- lastParameterPosition = idx;
- }
- break;
- case '`':
- if (state === State.Backtick) {
- state = State.Normal;
- } else if (state === State.Normal) {
- state = State.Backtick;
- }
- break;
- }
- lastChar = car;
- car = sql.charAt(idx++);
- }
- if (lastParameterPosition === 0) {
- partList.push(sql);
- } else {
- partList.push(sql.substring(lastParameterPosition));
- }
- return partList;
- };
- /**
- * Split query according to parameters using placeholder.
- *
- * @param sql sql with placeholders
- * @param info connection information
- * @param initialValues placeholder object
- * @param displaySql display sql function
- * @returns {{parts: Array, values: Array}}
- */
- module.exports.splitQueryPlaceholder = function (sql, info, initialValues, displaySql) {
- let partList = [];
- let values = [];
- let state = State.Normal;
- let lastChar = '\0';
- let singleQuotes = false;
- let lastParameterPosition = 0;
- let idx = 0;
- let car = sql.charAt(idx++);
- let placeholderName;
- while (car !== '') {
- if (
- state === State.Escape &&
- !((car === "'" && singleQuotes) || (car === '"' && !singleQuotes))
- ) {
- state = State.String;
- car = sql.charAt(idx++);
- continue;
- }
- switch (car) {
- case '*':
- if (state === State.Normal && lastChar == '/') state = State.SlashStarComment;
- break;
- case '/':
- if (state === State.SlashStarComment && lastChar == '*') state = State.Normal;
- break;
- case '#':
- if (state === State.Normal) state = State.EOLComment;
- break;
- case '-':
- if (state === State.Normal && lastChar == '-') {
- state = State.EOLComment;
- }
- break;
- case '\n':
- if (state === State.EOLComment) {
- state = State.Normal;
- }
- break;
- case '"':
- if (state === State.Normal) {
- state = State.String;
- singleQuotes = false;
- } else if (state === State.String && !singleQuotes) {
- state = State.Normal;
- } else if (state === State.Escape && !singleQuotes) {
- state = State.String;
- }
- break;
- case "'":
- if (state === State.Normal) {
- state = State.String;
- singleQuotes = true;
- } else if (state === State.String && singleQuotes) {
- state = State.Normal;
- singleQuotes = false;
- } else if (state === State.Escape && singleQuotes) {
- state = State.String;
- }
- break;
- case '\\':
- if (state === State.String) state = State.Escape;
- break;
- case ':':
- if (state === State.Normal) {
- partList.push(sql.substring(lastParameterPosition, idx - 1));
- placeholderName = '';
- while (
- ((car = sql.charAt(idx++)) !== '' && car >= '0' && car <= '9') ||
- (car >= 'A' && car <= 'Z') ||
- (car >= 'a' && car <= 'z') ||
- car === '-' ||
- car === '_'
- ) {
- placeholderName += car;
- }
- idx--;
- const val = initialValues[placeholderName];
- if (val === undefined) {
- throw Errors.createError(
- "Placeholder '" + placeholderName + "' is not defined\n" + displaySql.call(),
- false,
- info,
- 'HY000',
- Errors.ER_PLACEHOLDER_UNDEFINED
- );
- }
- values.push(val);
- lastParameterPosition = idx;
- }
- break;
- case '`':
- if (state === State.Backtick) {
- state = State.Normal;
- } else if (state === State.Normal) {
- state = State.Backtick;
- }
- }
- lastChar = car;
- car = sql.charAt(idx++);
- }
- if (lastParameterPosition === 0) {
- partList.push(sql);
- } else {
- partList.push(sql.substring(lastParameterPosition));
- }
- return { parts: partList, values: values };
- };
- /**
- * Split query according to parameters (question mark).
- *
- * The only rewritten queries follow these notation: INSERT [LOW_PRIORITY | DELAYED |
- * HIGH_PRIORITY] [IGNORE] [INTO] tbl_name [PARTITION (partition_list)] [(col,...)] {VALUES |
- * VALUE} (...) [ ON DUPLICATE KEY UPDATE col=expr [, col=expr] ... ] With expr without
- * parameter.
- *
- * Query with INSERT ... SELECT / containing LAST_INSERT_ID() will not be rewritten
- *
- * query parts will be split this way :
- * - pre-value part
- * - after value part
- * [- after parameter part] (after each parameter)
- * - ending part
- *
- * example : INSERT INTO MyTABLE VALUES (9, ?, 5, ?, 8) ON DUPLICATE KEY UPDATE col2=col2+10
- * will result in :
- * - pre-value : "INSERT INTO MyTABLE VALUES"
- * - after value : " (9, "
- * - after parameter : ", 5, "
- * - after parameter : ", 8)"
- * - ending : " ON DUPLICATE KEY UPDATE col2=col2+10"
- *
- *
- * @returns {JSON} query separated by parameters
- */
- module.exports.splitRewritableQuery = function (sql) {
- let reWritablePrepare = true;
- let multipleQueriesPrepare = true;
- let partList = [];
- let lastChar = '\0';
- let lastParameterPosition = 0;
- let preValuePart1 = null;
- let preValuePart2 = null;
- let postValuePart = null;
- let singleQuotes = false;
- let isInParenthesis = 0;
- let isFirstChar = true;
- let isInsert = false;
- let semicolon = false;
- let hasParam = false;
- let state = State.Normal;
- let idx = 0;
- let car = sql.charAt(idx++);
- while (car !== '') {
- if (
- state === State.Escape &&
- !((car === "'" && singleQuotes) || (car === '"' && !singleQuotes))
- ) {
- state = State.String;
- car = sql.charAt(idx++);
- continue;
- }
- switch (car) {
- case '*':
- if (state === State.Normal && lastChar == '/') {
- state = State.SlashStarComment;
- }
- break;
- case '/':
- if (state === State.SlashStarComment && lastChar == '*') {
- state = State.Normal;
- }
- break;
- case '#':
- if (state === State.Normal) {
- state = State.EOLComment;
- }
- break;
- case '-':
- if (state === State.Normal && lastChar == '-') {
- state = State.EOLComment;
- }
- break;
- case '\n':
- if (state === State.EOLComment) {
- state = State.Normal;
- }
- break;
- case '"':
- if (state === State.Normal) {
- state = State.String;
- singleQuotes = false;
- } else if (state === State.String && !singleQuotes) {
- state = State.Normal;
- } else if (state === State.Escape && !singleQuotes) {
- state = State.String;
- }
- break;
- case ';':
- if (state === State.Normal) {
- semicolon = true;
- multipleQueriesPrepare = false;
- }
- break;
- case "'":
- if (state === State.Normal) {
- state = State.String;
- singleQuotes = true;
- } else if (state === State.String && singleQuotes) {
- state = State.Normal;
- } else if (state === State.Escape && singleQuotes) {
- state = State.String;
- }
- break;
- case '\\':
- if (state === State.String) {
- state = State.Escape;
- }
- break;
- case '?':
- if (state === State.Normal) {
- hasParam = true;
- let part = sql.substring(lastParameterPosition, idx - 1);
- lastParameterPosition = idx;
- if (preValuePart1 === null) {
- preValuePart1 = part;
- preValuePart2 = '';
- } else if (preValuePart2 === null) {
- preValuePart2 = part;
- } else {
- if (postValuePart) {
- //having parameters after the last ")" of value is not rewritable
- reWritablePrepare = false;
- partList.push(postValuePart + part);
- postValuePart = null;
- } else partList.push(part);
- }
- }
- break;
- case '`':
- if (state === State.Backtick) {
- state = State.Normal;
- } else if (state === State.Normal) {
- state = State.Backtick;
- }
- break;
- case 's':
- case 'S':
- if (
- state === State.Normal &&
- postValuePart === null &&
- sql.length > idx + 5 &&
- (sql.charAt(idx) === 'e' || sql.charAt(idx) === 'E') &&
- (sql.charAt(idx + 1) === 'l' || sql.charAt(idx + 1) === 'L') &&
- (sql.charAt(idx + 2) === 'e' || sql.charAt(idx + 2) === 'E') &&
- (sql.charAt(idx + 3) === 'c' || sql.charAt(idx + 3) === 'C') &&
- (sql.charAt(idx + 4) === 't' || sql.charAt(idx + 4) === 'T')
- ) {
- //field/table name might contain 'select'
- if (
- idx > 1 &&
- sql.charAt(idx - 2) > ' ' &&
- '();><=-+,'.indexOf(sql.charAt(idx - 2)) === -1
- ) {
- break;
- }
- if (sql.charAt(idx + 5) > ' ' && '();><=-+,'.indexOf(sql.charAt(idx + 5)) === -1) {
- break;
- }
- //SELECT queries, INSERT FROM SELECT not rewritable
- reWritablePrepare = false;
- }
- break;
- case 'v':
- case 'V':
- if (
- state === State.Normal &&
- !preValuePart1 &&
- (lastChar == ')' || lastChar <= ' ') &&
- sql.length > idx + 6 &&
- (sql.charAt(idx) === 'a' || sql.charAt(idx) === 'A') &&
- (sql.charAt(idx + 1) === 'l' || sql.charAt(idx + 1) === 'L') &&
- (sql.charAt(idx + 2) === 'u' || sql.charAt(idx + 2) === 'U') &&
- (sql.charAt(idx + 3) === 'e' || sql.charAt(idx + 3) === 'E') &&
- (sql.charAt(idx + 4) === 's' || sql.charAt(idx + 4) === 'S') &&
- (sql.charAt(idx + 5) === '(' || sql.charAt(idx + 5) <= ' ')
- ) {
- idx += 5;
- preValuePart1 = sql.substring(lastParameterPosition, idx);
- lastParameterPosition = idx;
- }
- break;
- case 'l':
- case 'L':
- if (
- state === State.Normal &&
- sql.length > idx + 13 &&
- (sql.charAt(idx) === 'a' || sql.charAt(idx) === 'A') &&
- (sql.charAt(idx + 1) === 's' || sql.charAt(idx + 1) === 'S') &&
- (sql.charAt(idx + 2) === 't' || sql.charAt(idx + 2) === 'T') &&
- sql.charAt(idx + 3) === '_' &&
- (sql.charAt(idx + 4) === 'i' || sql.charAt(idx + 4) === 'I') &&
- (sql.charAt(idx + 5) === 'n' || sql.charAt(idx + 5) === 'N') &&
- (sql.charAt(idx + 6) === 's' || sql.charAt(idx + 6) === 'S') &&
- (sql.charAt(idx + 7) === 'e' || sql.charAt(idx + 7) === 'E') &&
- (sql.charAt(idx + 8) === 'r' || sql.charAt(idx + 8) === 'R') &&
- (sql.charAt(idx + 9) === 't' || sql.charAt(idx + 9) === 'T') &&
- sql.charAt(idx + 10) === '_' &&
- (sql.charAt(idx + 11) === 'i' || sql.charAt(idx + 11) === 'I') &&
- (sql.charAt(idx + 12) === 'd' || sql.charAt(idx + 12) === 'D') &&
- sql.charAt(idx + 13) === '('
- ) {
- reWritablePrepare = false;
- idx += 13;
- }
- break;
- case '(':
- if (state === State.Normal) {
- isInParenthesis++;
- }
- break;
- case ')':
- if (state === State.Normal) {
- isInParenthesis--;
- if (isInParenthesis === 0 && preValuePart2 !== null && postValuePart === null) {
- postValuePart = sql.substring(lastParameterPosition, idx);
- lastParameterPosition = idx;
- }
- }
- break;
- default:
- if (state === State.Normal && isFirstChar && car > ' ') {
- if (
- (car === 'I' || car === 'i') &&
- sql.length > idx + 6 &&
- (sql.charAt(idx) === 'n' || sql.charAt(idx) === 'N') &&
- (sql.charAt(idx + 1) === 's' || sql.charAt(idx + 1) === 'S') &&
- (sql.charAt(idx + 2) === 'e' || sql.charAt(idx + 2) === 'E') &&
- (sql.charAt(idx + 3) === 'r' || sql.charAt(idx + 3) === 'R') &&
- (sql.charAt(idx + 4) === 't' || sql.charAt(idx + 4) === 'T') &&
- (sql.charAt(idx + 5) === '(' || sql.charAt(idx + 5) <= ' ')
- ) {
- isInsert = true;
- }
- isFirstChar = false;
- }
- //multiple queries
- if (state === State.Normal && semicolon && car >= ' ') {
- reWritablePrepare = false;
- multipleQueriesPrepare = true;
- }
- break;
- }
- lastChar = car;
- car = sql.charAt(idx++);
- }
- if (state === State.EOLComment) multipleQueriesPrepare = false;
- if (!hasParam) {
- //permit to have rewrite without parameter
- if (preValuePart1 === null) {
- partList.unshift('');
- partList.unshift(sql);
- } else {
- partList.unshift(sql.substring(lastParameterPosition, idx));
- partList.unshift(preValuePart1);
- }
- lastParameterPosition = idx;
- } else {
- partList.unshift(preValuePart2 !== null ? preValuePart2 : '');
- partList.unshift(preValuePart1 !== null ? preValuePart1 : '');
- }
- if (!isInsert) {
- reWritablePrepare = false;
- }
- //postValuePart is the value after the last parameter and parenthesis
- //if no param, don't add to the list.
- if (hasParam) {
- partList.push(postValuePart !== null ? postValuePart : '');
- }
- partList.push(sql.substring(lastParameterPosition, idx));
- return {
- partList: partList,
- reWritable: reWritablePrepare,
- multipleQueries: multipleQueriesPrepare
- };
- };
- module.exports.searchPlaceholder = function (sql, info, initialValues, displaySql) {
- let sqlPlaceHolder = '';
- const rowNumber = initialValues.length;
- let values = new Array(rowNumber);
- for (let i = 0; i < rowNumber; i++) values[i] = [];
- let state = State.Normal;
- let lastChar = '\0';
- let singleQuotes = false;
- let lastParameterPosition = 0;
- let idx = 0;
- let car = sql.charAt(idx++);
- let placeholderName;
- while (car !== '') {
- if (
- state === State.Escape &&
- !((car === "'" && singleQuotes) || (car === '"' && !singleQuotes))
- ) {
- state = State.String;
- lastChar = car;
- car = sql.charAt(idx++);
- continue;
- }
- switch (car) {
- case '*':
- if (state === State.Normal && lastChar == '/') state = State.SlashStarComment;
- break;
- case '/':
- if (state === State.SlashStarComment && lastChar == '*') state = State.Normal;
- break;
- case '#':
- if (state === State.Normal) state = State.EOLComment;
- break;
- case '-':
- if (state === State.Normal && lastChar == '-') {
- state = State.EOLComment;
- }
- break;
- case '\n':
- if (state === State.EOLComment) {
- state = State.Normal;
- }
- break;
- case '"':
- if (state === State.Normal) {
- state = State.String;
- singleQuotes = false;
- } else if (state === State.String && !singleQuotes) {
- state = State.Normal;
- } else if (state === State.Escape && !singleQuotes) {
- state = State.String;
- }
- break;
- case "'":
- if (state === State.Normal) {
- state = State.String;
- singleQuotes = true;
- } else if (state === State.String && singleQuotes) {
- state = State.Normal;
- singleQuotes = false;
- } else if (state === State.Escape && singleQuotes) {
- state = State.String;
- }
- break;
- case '\\':
- if (state === State.String) state = State.Escape;
- break;
- case ':':
- if (state === State.Normal) {
- sqlPlaceHolder += sql.substring(lastParameterPosition, idx - 1) + '?';
- placeholderName = '';
- while (
- ((car = sql.charAt(idx++)) !== '' && car >= '0' && car <= '9') ||
- (car >= 'A' && car <= 'Z') ||
- (car >= 'a' && car <= 'z') ||
- car === '-' ||
- car === '_'
- ) {
- placeholderName += car;
- }
- idx--;
- for (let i = 0; i < rowNumber; i++) {
- const val = initialValues[i][placeholderName];
- if (val !== undefined) {
- values[i].push(val);
- } else {
- values[i].push(null);
- }
- }
- lastParameterPosition = idx;
- }
- break;
- case '`':
- if (state === State.Backtick) {
- state = State.Normal;
- } else if (state === State.Normal) {
- state = State.Backtick;
- }
- }
- lastChar = car;
- car = sql.charAt(idx++);
- }
- if (lastParameterPosition === 0) {
- sqlPlaceHolder = sql;
- } else {
- sqlPlaceHolder += sql.substring(lastParameterPosition);
- }
- return { sql: sqlPlaceHolder, values: values };
- };
- /**
- * Split query according to named parameters.
- *
- * The only rewritten queries follow these notation: INSERT [LOW_PRIORITY | DELAYED |
- * HIGH_PRIORITY] [IGNORE] [INTO] tbl_name [PARTITION (partition_list)] [(col,...)] {VALUES |
- * VALUE} (...) [ ON DUPLICATE KEY UPDATE col=expr [, col=expr] ... ] With expr without
- * parameter.
- *
- * Query with INSERT ... SELECT / containing LAST_INSERT_ID() will not be rewritten
- *
- * query parts will be split this way :
- * - pre-value part
- * - after value part
- * [- after parameter part] (after each parameter)
- * - ending part
- *
- * example : INSERT INTO MyTABLE VALUES (9, :param1, 5, :param2, 8) ON DUPLICATE KEY UPDATE col2=col2+10
- * will result in :
- * - pre-value : "INSERT INTO MyTABLE VALUES"
- * - after value : " (9, "
- * - after parameter : ", 5, "
- * - after parameter : ", 8)"
- * - ending : " ON DUPLICATE KEY UPDATE col2=col2+10"
- *
- *
- * @returns {JSON} query separated by parameters
- */
- module.exports.splitRewritableNamedParameterQuery = function (sql, initialValues) {
- let reWritablePrepare = true;
- let multipleQueriesPrepare = true;
- let partList = [];
- let values = new Array(initialValues.length);
- for (let i = 0; i < values.length; i++) values[i] = [];
- let lastChar = '\0';
- let lastParameterPosition = 0;
- let preValuePart1 = null;
- let preValuePart2 = null;
- let postValuePart = null;
- let singleQuotes = false;
- let isInParenthesis = 0;
- let isFirstChar = true;
- let isInsert = false;
- let semicolon = false;
- let hasParam = false;
- let placeholderName;
- let state = State.Normal;
- let idx = 0;
- let car = sql.charAt(idx++);
- while (car !== '') {
- if (
- state === State.Escape &&
- !((car === "'" && singleQuotes) || (car === '"' && !singleQuotes))
- ) {
- state = State.String;
- car = sql.charAt(idx++);
- continue;
- }
- switch (car) {
- case '*':
- if (state === State.Normal && lastChar == '/') {
- state = State.SlashStarComment;
- }
- break;
- case '/':
- if (state === State.SlashStarComment && lastChar == '*') {
- state = State.Normal;
- }
- break;
- case '#':
- if (state === State.Normal) {
- state = State.EOLComment;
- }
- break;
- case '-':
- if (state === State.Normal && lastChar == '-') {
- state = State.EOLComment;
- }
- break;
- case '\n':
- if (state === State.EOLComment) {
- state = State.Normal;
- }
- break;
- case '"':
- if (state === State.Normal) {
- state = State.String;
- singleQuotes = false;
- } else if (state === State.String && !singleQuotes) {
- state = State.Normal;
- } else if (state === State.Escape && !singleQuotes) {
- state = State.String;
- }
- break;
- case ';':
- if (state === State.Normal) {
- semicolon = true;
- multipleQueriesPrepare = false;
- }
- break;
- case "'":
- if (state === State.Normal) {
- state = State.String;
- singleQuotes = true;
- } else if (state === State.String && singleQuotes) {
- state = State.Normal;
- } else if (state === State.Escape && singleQuotes) {
- state = State.String;
- }
- break;
- case '\\':
- if (state === State.String) {
- state = State.Escape;
- }
- break;
- case ':':
- if (state === State.Normal) {
- let part = sql.substring(lastParameterPosition, idx - 1);
- placeholderName = '';
- while (
- ((car = sql.charAt(idx++)) !== '' && car >= '0' && car <= '9') ||
- (car >= 'A' && car <= 'Z') ||
- (car >= 'a' && car <= 'z') ||
- car === '-' ||
- car === '_'
- ) {
- placeholderName += car;
- }
- idx--;
- hasParam = true;
- initialValues.forEach((row, idx) => {
- if (row[placeholderName] !== undefined) {
- values[idx].push(row[placeholderName]);
- } else {
- values[idx].push(null);
- }
- });
- lastParameterPosition = idx;
- if (preValuePart1 === null) {
- preValuePart1 = part;
- preValuePart2 = '';
- } else if (preValuePart2 === null) {
- preValuePart2 = part;
- } else {
- if (postValuePart) {
- //having parameters after the last ")" of value is not rewritable
- reWritablePrepare = false;
- partList.push(postValuePart + part);
- postValuePart = null;
- } else partList.push(part);
- }
- }
- break;
- case '`':
- if (state === State.Backtick) {
- state = State.Normal;
- } else if (state === State.Normal) {
- state = State.Backtick;
- }
- break;
- case 's':
- case 'S':
- if (
- state === State.Normal &&
- postValuePart === null &&
- sql.length > idx + 5 &&
- (sql.charAt(idx) === 'e' || sql.charAt(idx) === 'E') &&
- (sql.charAt(idx + 1) === 'l' || sql.charAt(idx + 1) === 'L') &&
- (sql.charAt(idx + 2) === 'e' || sql.charAt(idx + 2) === 'E') &&
- (sql.charAt(idx + 3) === 'c' || sql.charAt(idx + 3) === 'C') &&
- (sql.charAt(idx + 4) === 't' || sql.charAt(idx + 4) === 'T')
- ) {
- //field/table name might contain 'select'
- if (
- idx > 1 &&
- sql.charAt(idx - 2) > ' ' &&
- '();><=-+,'.indexOf(sql.charAt(idx - 2)) === -1
- ) {
- break;
- }
- if (sql.charAt(idx + 5) > ' ' && '();><=-+,'.indexOf(sql.charAt(idx + 5)) === -1) {
- break;
- }
- //SELECT queries, INSERT FROM SELECT not rewritable
- reWritablePrepare = false;
- }
- break;
- case 'v':
- case 'V':
- if (
- state === State.Normal &&
- !preValuePart1 &&
- (lastChar == ')' || lastChar <= ' ') &&
- sql.length > idx + 6 &&
- (sql.charAt(idx) === 'a' || sql.charAt(idx) === 'A') &&
- (sql.charAt(idx + 1) === 'l' || sql.charAt(idx + 1) === 'L') &&
- (sql.charAt(idx + 2) === 'u' || sql.charAt(idx + 2) === 'U') &&
- (sql.charAt(idx + 3) === 'e' || sql.charAt(idx + 3) === 'E') &&
- (sql.charAt(idx + 4) === 's' || sql.charAt(idx + 4) === 'S') &&
- (sql.charAt(idx + 5) === '(' || sql.charAt(idx + 5) <= ' ')
- ) {
- idx += 5;
- preValuePart1 = sql.substring(lastParameterPosition, idx);
- lastParameterPosition = idx;
- }
- break;
- case 'l':
- case 'L':
- if (
- state === State.Normal &&
- sql.length > idx + 13 &&
- (sql.charAt(idx) === 'a' || sql.charAt(idx) === 'A') &&
- (sql.charAt(idx + 1) === 's' || sql.charAt(idx + 1) === 'S') &&
- (sql.charAt(idx + 2) === 't' || sql.charAt(idx + 2) === 'T') &&
- sql.charAt(idx + 3) === '_' &&
- (sql.charAt(idx + 4) === 'i' || sql.charAt(idx + 4) === 'I') &&
- (sql.charAt(idx + 5) === 'n' || sql.charAt(idx + 5) === 'N') &&
- (sql.charAt(idx + 6) === 's' || sql.charAt(idx + 6) === 'S') &&
- (sql.charAt(idx + 7) === 'e' || sql.charAt(idx + 7) === 'E') &&
- (sql.charAt(idx + 8) === 'r' || sql.charAt(idx + 8) === 'R') &&
- (sql.charAt(idx + 9) === 't' || sql.charAt(idx + 9) === 'T') &&
- sql.charAt(idx + 10) === '_' &&
- (sql.charAt(idx + 11) === 'i' || sql.charAt(idx + 11) === 'I') &&
- (sql.charAt(idx + 12) === 'd' || sql.charAt(idx + 12) === 'D') &&
- sql.charAt(idx + 13) === '('
- ) {
- reWritablePrepare = false;
- idx += 13;
- }
- break;
- case '(':
- if (state === State.Normal) {
- isInParenthesis++;
- }
- break;
- case ')':
- if (state === State.Normal) {
- isInParenthesis--;
- if (isInParenthesis === 0 && preValuePart2 !== null && postValuePart === null) {
- postValuePart = sql.substring(lastParameterPosition, idx);
- lastParameterPosition = idx;
- }
- }
- break;
- default:
- if (state === State.Normal && isFirstChar && car > ' ') {
- if (
- (car === 'I' || car === 'i') &&
- sql.length > idx + 6 &&
- (sql.charAt(idx) === 'n' || sql.charAt(idx) === 'N') &&
- (sql.charAt(idx + 1) === 's' || sql.charAt(idx + 1) === 'S') &&
- (sql.charAt(idx + 2) === 'e' || sql.charAt(idx + 2) === 'E') &&
- (sql.charAt(idx + 3) === 'r' || sql.charAt(idx + 3) === 'R') &&
- (sql.charAt(idx + 4) === 't' || sql.charAt(idx + 4) === 'T') &&
- (sql.charAt(idx + 5) === '(' || sql.charAt(idx + 5) <= ' ')
- ) {
- isInsert = true;
- }
- isFirstChar = false;
- }
- //multiple queries
- if (state === State.Normal && semicolon && car >= ' ') {
- reWritablePrepare = false;
- multipleQueriesPrepare = true;
- }
- break;
- }
- lastChar = car;
- car = sql.charAt(idx++);
- }
- if (state === State.EOLComment) multipleQueriesPrepare = false;
- if (!hasParam) {
- //permit to have rewrite without parameter
- if (preValuePart1 === null) {
- partList.unshift('');
- partList.unshift(sql);
- } else {
- partList.unshift(sql.substring(lastParameterPosition, idx));
- partList.unshift(preValuePart1);
- }
- lastParameterPosition = idx;
- } else {
- partList.unshift(preValuePart2 !== null ? preValuePart2 : '');
- partList.unshift(preValuePart1 !== null ? preValuePart1 : '');
- }
- if (!isInsert) {
- reWritablePrepare = false;
- }
- //postValuePart is the value after the last parameter and parenthesis
- //if no param, don't add to the list.
- if (hasParam) {
- partList.push(postValuePart !== null ? postValuePart : '');
- }
- partList.push(sql.substring(lastParameterPosition, idx));
- return {
- partList: partList,
- reWritable: reWritablePrepare,
- multipleQueries: multipleQueriesPrepare,
- values: values
- };
- };
- /**
- * Ensure that filename requested by server corresponds to query
- * protocol : https://mariadb.com/kb/en/library/local_infile-packet/
- *
- * @param sql query
- * @param parameters parameters if any
- * @param fileName server requested file
- * @returns {boolean} is filename corresponding to query
- */
- module.exports.validateFileName = function (sql, parameters, fileName) {
- let queryValidator = new RegExp(
- "^(\\s*\\/\\*([^\\*]|\\*[^\\/])*\\*\\/)*\\s*LOAD\\s+DATA\\s+((LOW_PRIORITY|CONCURRENT)\\s+)?LOCAL\\s+INFILE\\s+'" +
- fileName +
- "'",
- 'i'
- );
- if (queryValidator.test(sql)) return true;
- if (parameters != null) {
- queryValidator = new RegExp(
- '^(\\s*\\/\\*([^\\*]|\\*[^\\/])*\\*\\/)*\\s*LOAD\\s+DATA\\s+((LOW_PRIORITY|CONCURRENT)\\s+)?LOCAL\\s+INFILE\\s+\\?',
- 'i'
- );
- if (queryValidator.test(sql) && parameters.length > 0) {
- return parameters[0].toLowerCase() === fileName.toLowerCase();
- }
- }
- return false;
- };
|