@tachybase/module-multi-app 1.6.0 → 1.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/externalVersion.js +5 -5
- package/dist/node_modules/mariadb/callback.js +43 -8
- package/dist/node_modules/mariadb/check-node.js +30 -0
- package/dist/node_modules/mariadb/lib/cluster-callback.js +84 -0
- package/dist/node_modules/mariadb/lib/cluster.js +446 -0
- package/dist/node_modules/mariadb/lib/cmd/batch-bulk.js +576 -177
- package/dist/node_modules/mariadb/lib/cmd/change-user.js +54 -44
- package/dist/node_modules/mariadb/lib/cmd/class/ok-packet.js +3 -2
- package/dist/node_modules/mariadb/lib/cmd/class/prepare-cache-wrapper.js +46 -0
- package/dist/node_modules/mariadb/lib/cmd/class/prepare-result-packet.js +141 -0
- package/dist/node_modules/mariadb/lib/cmd/class/prepare-wrapper.js +70 -0
- package/dist/node_modules/mariadb/lib/cmd/close-prepare.js +38 -0
- package/dist/node_modules/mariadb/lib/cmd/column-definition.js +145 -47
- package/dist/node_modules/mariadb/lib/cmd/command.js +41 -75
- package/dist/node_modules/mariadb/lib/cmd/decoder/binary-decoder.js +282 -0
- package/dist/node_modules/mariadb/lib/cmd/decoder/text-decoder.js +210 -0
- package/dist/node_modules/mariadb/lib/cmd/{common-binary-cmd.js → encoder/binary-encoder.js} +34 -77
- package/dist/node_modules/mariadb/lib/cmd/encoder/text-encoder.js +311 -0
- package/dist/node_modules/mariadb/lib/cmd/execute-stream.js +61 -0
- package/dist/node_modules/mariadb/lib/cmd/execute.js +338 -0
- package/dist/node_modules/mariadb/lib/cmd/handshake/auth/caching-sha2-password-auth.js +25 -62
- package/dist/node_modules/mariadb/lib/cmd/handshake/auth/clear-password-auth.js +39 -6
- package/dist/node_modules/mariadb/lib/cmd/handshake/auth/ed25519-password-auth.js +48 -16
- package/dist/node_modules/mariadb/lib/cmd/handshake/auth/handshake.js +198 -0
- package/dist/node_modules/mariadb/lib/cmd/handshake/{initial-handshake.js → auth/initial-handshake.js} +10 -8
- package/dist/node_modules/mariadb/lib/cmd/handshake/auth/native-password-auth.js +22 -9
- package/dist/node_modules/mariadb/lib/cmd/handshake/auth/pam-password-auth.js +9 -4
- package/dist/node_modules/mariadb/lib/cmd/handshake/auth/parsec-auth.js +115 -0
- package/dist/node_modules/mariadb/lib/cmd/handshake/auth/plugin-auth.js +12 -5
- package/dist/node_modules/mariadb/lib/cmd/handshake/auth/sha256-password-auth.js +44 -33
- package/dist/node_modules/mariadb/lib/cmd/handshake/authentication.js +335 -0
- package/dist/node_modules/mariadb/lib/cmd/handshake/client-capabilities.js +20 -19
- package/dist/node_modules/mariadb/lib/cmd/handshake/ssl-request.js +6 -3
- package/dist/node_modules/mariadb/lib/cmd/parser.js +861 -0
- package/dist/node_modules/mariadb/lib/cmd/ping.js +17 -18
- package/dist/node_modules/mariadb/lib/cmd/prepare.js +170 -0
- package/dist/node_modules/mariadb/lib/cmd/query.js +281 -144
- package/dist/node_modules/mariadb/lib/cmd/quit.js +9 -6
- package/dist/node_modules/mariadb/lib/cmd/reset.js +15 -19
- package/dist/node_modules/mariadb/lib/cmd/stream.js +21 -6
- package/dist/node_modules/mariadb/lib/config/cluster-options.js +23 -0
- package/dist/node_modules/mariadb/lib/config/connection-options.js +196 -132
- package/dist/node_modules/mariadb/lib/config/pool-options.js +27 -19
- package/dist/node_modules/mariadb/lib/connection-callback.js +492 -120
- package/dist/node_modules/mariadb/lib/connection-promise.js +372 -0
- package/dist/node_modules/mariadb/lib/connection.js +1739 -1016
- package/dist/node_modules/mariadb/lib/const/capabilities.js +36 -30
- package/dist/node_modules/mariadb/lib/const/collations.js +972 -36
- package/dist/node_modules/mariadb/lib/const/connection_status.js +3 -0
- package/dist/node_modules/mariadb/lib/const/error-code.js +35 -11
- package/dist/node_modules/mariadb/lib/const/field-detail.js +3 -0
- package/dist/node_modules/mariadb/lib/const/field-type.js +7 -4
- package/dist/node_modules/mariadb/lib/const/server-status.js +4 -1
- package/dist/node_modules/mariadb/lib/const/state-change.js +3 -0
- package/dist/node_modules/mariadb/lib/filtered-cluster-callback.js +136 -0
- package/dist/node_modules/mariadb/lib/filtered-cluster.js +118 -0
- package/dist/node_modules/mariadb/lib/io/compression-input-stream.js +14 -13
- package/dist/node_modules/mariadb/lib/io/compression-output-stream.js +21 -18
- package/dist/node_modules/mariadb/lib/io/packet-input-stream.js +75 -64
- package/dist/node_modules/mariadb/lib/io/packet-node-encoded.js +13 -9
- package/dist/node_modules/mariadb/lib/io/packet-node-iconv.js +12 -10
- package/dist/node_modules/mariadb/lib/io/packet-output-stream.js +402 -134
- package/dist/node_modules/mariadb/lib/io/packet.js +287 -202
- package/dist/node_modules/mariadb/lib/lru-prepare-cache.js +84 -0
- package/dist/node_modules/mariadb/lib/misc/connection-information.js +15 -32
- package/dist/node_modules/mariadb/lib/misc/errors.js +68 -25
- package/dist/node_modules/mariadb/lib/misc/parse.js +207 -711
- package/dist/node_modules/mariadb/lib/misc/utils.js +34 -62
- package/dist/node_modules/mariadb/lib/pool-callback.js +213 -174
- package/dist/node_modules/mariadb/lib/pool-promise.js +228 -94
- package/dist/node_modules/mariadb/lib/pool.js +951 -0
- package/dist/node_modules/mariadb/package.json +1 -1
- package/dist/node_modules/mariadb/promise.js +1 -34
- package/dist/node_modules/mariadb/types/callback.d.ts +207 -0
- package/dist/node_modules/mariadb/types/index.d.ts +94 -674
- package/dist/node_modules/mariadb/types/share.d.ts +804 -0
- package/dist/node_modules/qs/package.json +1 -1
- package/dist/server/actions/apps.js +2 -2
- package/dist/server/app-lifecycle.d.ts +1 -1
- package/dist/server/app-lifecycle.js +4 -4
- package/dist/server/models/application.d.ts +1 -1
- package/package.json +7 -7
- package/dist/node_modules/mariadb/lib/cmd/batch-rewrite.js +0 -372
- package/dist/node_modules/mariadb/lib/cmd/common-text-cmd.js +0 -427
- package/dist/node_modules/mariadb/lib/cmd/handshake/client-handshake-response.js +0 -126
- package/dist/node_modules/mariadb/lib/cmd/handshake/handshake.js +0 -292
- package/dist/node_modules/mariadb/lib/cmd/resultset.js +0 -607
- package/dist/node_modules/mariadb/lib/config/pool-cluster-options.js +0 -19
- package/dist/node_modules/mariadb/lib/filtered-pool-cluster.js +0 -81
- package/dist/node_modules/mariadb/lib/io/bulk-packet.js +0 -590
- package/dist/node_modules/mariadb/lib/io/rewrite-packet.js +0 -481
- package/dist/node_modules/mariadb/lib/pool-base.js +0 -611
- package/dist/node_modules/mariadb/lib/pool-cluster-callback.js +0 -66
- package/dist/node_modules/mariadb/lib/pool-cluster.js +0 -407
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
// SPDX-License-Identifier: LGPL-2.1-or-later
|
|
2
|
+
// Copyright (c) 2015-2025 MariaDB Corporation Ab
|
|
3
|
+
|
|
1
4
|
const Errors = require('../misc/errors');
|
|
2
5
|
|
|
3
6
|
const State = {
|
|
@@ -10,89 +13,107 @@ const State = {
|
|
|
10
13
|
Placeholder: 7 /* found placeholder */
|
|
11
14
|
};
|
|
12
15
|
|
|
16
|
+
const SLASH_BYTE = '/'.charCodeAt(0);
|
|
17
|
+
const STAR_BYTE = '*'.charCodeAt(0);
|
|
18
|
+
const BACKSLASH_BYTE = '\\'.charCodeAt(0);
|
|
19
|
+
const HASH_BYTE = '#'.charCodeAt(0);
|
|
20
|
+
const MINUS_BYTE = '-'.charCodeAt(0);
|
|
21
|
+
const LINE_FEED_BYTE = '\n'.charCodeAt(0);
|
|
22
|
+
const DBL_QUOTE_BYTE = '"'.charCodeAt(0);
|
|
23
|
+
const QUOTE_BYTE = "'".charCodeAt(0);
|
|
24
|
+
const RADICAL_BYTE = '`'.charCodeAt(0);
|
|
25
|
+
const QUESTION_MARK_BYTE = '?'.charCodeAt(0);
|
|
26
|
+
const COLON_BYTE = ':'.charCodeAt(0);
|
|
27
|
+
const SEMICOLON_BYTE = ';'.charCodeAt(0);
|
|
28
|
+
|
|
13
29
|
/**
|
|
14
|
-
*
|
|
15
|
-
* Question
|
|
30
|
+
* Search for question mark positions.
|
|
31
|
+
* Question marks in comment are not taken into account
|
|
16
32
|
*
|
|
17
|
-
* @returns {Array}
|
|
33
|
+
* @returns {Array} question mark position
|
|
18
34
|
*/
|
|
19
|
-
module.exports.splitQuery = function (
|
|
20
|
-
let
|
|
35
|
+
module.exports.splitQuery = function (query) {
|
|
36
|
+
let paramPositions = [];
|
|
21
37
|
let state = State.Normal;
|
|
22
|
-
let lastChar =
|
|
38
|
+
let lastChar = 0x00;
|
|
23
39
|
let singleQuotes = false;
|
|
24
|
-
let
|
|
25
|
-
let idx = 0;
|
|
26
|
-
let car = sql.charAt(idx++);
|
|
40
|
+
let currentChar;
|
|
27
41
|
|
|
28
|
-
|
|
42
|
+
const len = query.length;
|
|
43
|
+
for (let i = 0; i < len; i++) {
|
|
44
|
+
currentChar = query[i];
|
|
29
45
|
if (
|
|
30
46
|
state === State.Escape &&
|
|
31
|
-
!((
|
|
47
|
+
!((currentChar === QUOTE_BYTE && singleQuotes) || (currentChar === DBL_QUOTE_BYTE && !singleQuotes))
|
|
32
48
|
) {
|
|
33
49
|
state = State.String;
|
|
34
|
-
|
|
50
|
+
lastChar = currentChar;
|
|
35
51
|
continue;
|
|
36
52
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
53
|
+
switch (currentChar) {
|
|
54
|
+
case STAR_BYTE:
|
|
55
|
+
if (state === State.Normal && lastChar === SLASH_BYTE) {
|
|
56
|
+
state = State.SlashStarComment;
|
|
57
|
+
}
|
|
41
58
|
break;
|
|
42
59
|
|
|
43
|
-
case
|
|
44
|
-
if (state === State.SlashStarComment && lastChar
|
|
60
|
+
case SLASH_BYTE:
|
|
61
|
+
if (state === State.SlashStarComment && lastChar === STAR_BYTE) {
|
|
62
|
+
state = State.Normal;
|
|
63
|
+
}
|
|
45
64
|
break;
|
|
46
65
|
|
|
47
|
-
case
|
|
48
|
-
if (state === State.Normal)
|
|
66
|
+
case HASH_BYTE:
|
|
67
|
+
if (state === State.Normal) {
|
|
68
|
+
state = State.EOLComment;
|
|
69
|
+
}
|
|
49
70
|
break;
|
|
50
71
|
|
|
51
|
-
case
|
|
52
|
-
if (state === State.Normal && lastChar
|
|
72
|
+
case MINUS_BYTE:
|
|
73
|
+
if (state === State.Normal && lastChar === MINUS_BYTE) {
|
|
53
74
|
state = State.EOLComment;
|
|
54
75
|
}
|
|
55
76
|
break;
|
|
56
77
|
|
|
57
|
-
case
|
|
78
|
+
case LINE_FEED_BYTE:
|
|
58
79
|
if (state === State.EOLComment) {
|
|
59
80
|
state = State.Normal;
|
|
60
81
|
}
|
|
61
82
|
break;
|
|
62
83
|
|
|
63
|
-
case
|
|
84
|
+
case DBL_QUOTE_BYTE:
|
|
64
85
|
if (state === State.Normal) {
|
|
65
86
|
state = State.String;
|
|
66
87
|
singleQuotes = false;
|
|
67
88
|
} else if (state === State.String && !singleQuotes) {
|
|
68
89
|
state = State.Normal;
|
|
69
|
-
} else if (state === State.Escape
|
|
90
|
+
} else if (state === State.Escape) {
|
|
70
91
|
state = State.String;
|
|
71
92
|
}
|
|
72
93
|
break;
|
|
73
94
|
|
|
74
|
-
case
|
|
95
|
+
case QUOTE_BYTE:
|
|
75
96
|
if (state === State.Normal) {
|
|
76
97
|
state = State.String;
|
|
77
98
|
singleQuotes = true;
|
|
78
99
|
} else if (state === State.String && singleQuotes) {
|
|
79
100
|
state = State.Normal;
|
|
80
|
-
} else if (state === State.Escape
|
|
101
|
+
} else if (state === State.Escape) {
|
|
81
102
|
state = State.String;
|
|
82
103
|
}
|
|
83
104
|
break;
|
|
84
105
|
|
|
85
|
-
case
|
|
86
|
-
if (state === State.String)
|
|
106
|
+
case BACKSLASH_BYTE:
|
|
107
|
+
if (state === State.String) {
|
|
108
|
+
state = State.Escape;
|
|
109
|
+
}
|
|
87
110
|
break;
|
|
88
|
-
|
|
89
|
-
case '?':
|
|
111
|
+
case QUESTION_MARK_BYTE:
|
|
90
112
|
if (state === State.Normal) {
|
|
91
|
-
|
|
92
|
-
lastParameterPosition = idx;
|
|
113
|
+
paramPositions.push(i, ++i);
|
|
93
114
|
}
|
|
94
115
|
break;
|
|
95
|
-
case
|
|
116
|
+
case RADICAL_BYTE:
|
|
96
117
|
if (state === State.Backtick) {
|
|
97
118
|
state = State.Normal;
|
|
98
119
|
} else if (state === State.Normal) {
|
|
@@ -100,458 +121,165 @@ module.exports.splitQuery = function (sql) {
|
|
|
100
121
|
}
|
|
101
122
|
break;
|
|
102
123
|
}
|
|
103
|
-
lastChar =
|
|
104
|
-
|
|
105
|
-
car = sql.charAt(idx++);
|
|
124
|
+
lastChar = currentChar;
|
|
106
125
|
}
|
|
107
|
-
|
|
108
|
-
partList.push(sql);
|
|
109
|
-
} else {
|
|
110
|
-
partList.push(sql.substring(lastParameterPosition));
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
return partList;
|
|
126
|
+
return paramPositions;
|
|
114
127
|
};
|
|
115
128
|
|
|
116
129
|
/**
|
|
117
130
|
* Split query according to parameters using placeholder.
|
|
118
131
|
*
|
|
119
|
-
* @param
|
|
132
|
+
* @param query query bytes
|
|
120
133
|
* @param info connection information
|
|
121
134
|
* @param initialValues placeholder object
|
|
122
135
|
* @param displaySql display sql function
|
|
123
|
-
* @returns {{
|
|
136
|
+
* @returns {{paramPositions: Array, values: Array}}
|
|
124
137
|
*/
|
|
125
|
-
module.exports.splitQueryPlaceholder = function (
|
|
126
|
-
let
|
|
138
|
+
module.exports.splitQueryPlaceholder = function (query, info, initialValues, displaySql) {
|
|
139
|
+
let placeholderValues = Object.assign({}, initialValues);
|
|
140
|
+
let paramPositions = [];
|
|
127
141
|
let values = [];
|
|
128
142
|
let state = State.Normal;
|
|
129
|
-
let lastChar =
|
|
130
|
-
|
|
131
|
-
let singleQuotes = false;
|
|
132
|
-
let lastParameterPosition = 0;
|
|
133
|
-
|
|
134
|
-
let idx = 0;
|
|
135
|
-
let car = sql.charAt(idx++);
|
|
136
|
-
let placeholderName;
|
|
137
|
-
|
|
138
|
-
while (car !== '') {
|
|
139
|
-
if (
|
|
140
|
-
state === State.Escape &&
|
|
141
|
-
!((car === "'" && singleQuotes) || (car === '"' && !singleQuotes))
|
|
142
|
-
) {
|
|
143
|
-
state = State.String;
|
|
144
|
-
car = sql.charAt(idx++);
|
|
145
|
-
continue;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
switch (car) {
|
|
149
|
-
case '*':
|
|
150
|
-
if (state === State.Normal && lastChar == '/') state = State.SlashStarComment;
|
|
151
|
-
break;
|
|
152
|
-
|
|
153
|
-
case '/':
|
|
154
|
-
if (state === State.SlashStarComment && lastChar == '*') state = State.Normal;
|
|
155
|
-
break;
|
|
156
|
-
|
|
157
|
-
case '#':
|
|
158
|
-
if (state === State.Normal) state = State.EOLComment;
|
|
159
|
-
break;
|
|
160
|
-
|
|
161
|
-
case '-':
|
|
162
|
-
if (state === State.Normal && lastChar == '-') {
|
|
163
|
-
state = State.EOLComment;
|
|
164
|
-
}
|
|
165
|
-
break;
|
|
166
|
-
|
|
167
|
-
case '\n':
|
|
168
|
-
if (state === State.EOLComment) {
|
|
169
|
-
state = State.Normal;
|
|
170
|
-
}
|
|
171
|
-
break;
|
|
172
|
-
|
|
173
|
-
case '"':
|
|
174
|
-
if (state === State.Normal) {
|
|
175
|
-
state = State.String;
|
|
176
|
-
singleQuotes = false;
|
|
177
|
-
} else if (state === State.String && !singleQuotes) {
|
|
178
|
-
state = State.Normal;
|
|
179
|
-
} else if (state === State.Escape && !singleQuotes) {
|
|
180
|
-
state = State.String;
|
|
181
|
-
}
|
|
182
|
-
break;
|
|
183
|
-
|
|
184
|
-
case "'":
|
|
185
|
-
if (state === State.Normal) {
|
|
186
|
-
state = State.String;
|
|
187
|
-
singleQuotes = true;
|
|
188
|
-
} else if (state === State.String && singleQuotes) {
|
|
189
|
-
state = State.Normal;
|
|
190
|
-
singleQuotes = false;
|
|
191
|
-
} else if (state === State.Escape && singleQuotes) {
|
|
192
|
-
state = State.String;
|
|
193
|
-
}
|
|
194
|
-
break;
|
|
195
|
-
|
|
196
|
-
case '\\':
|
|
197
|
-
if (state === State.String) state = State.Escape;
|
|
198
|
-
break;
|
|
199
|
-
|
|
200
|
-
case ':':
|
|
201
|
-
if (state === State.Normal) {
|
|
202
|
-
partList.push(sql.substring(lastParameterPosition, idx - 1));
|
|
203
|
-
placeholderName = '';
|
|
204
|
-
while (
|
|
205
|
-
((car = sql.charAt(idx++)) !== '' && car >= '0' && car <= '9') ||
|
|
206
|
-
(car >= 'A' && car <= 'Z') ||
|
|
207
|
-
(car >= 'a' && car <= 'z') ||
|
|
208
|
-
car === '-' ||
|
|
209
|
-
car === '_'
|
|
210
|
-
) {
|
|
211
|
-
placeholderName += car;
|
|
212
|
-
}
|
|
213
|
-
idx--;
|
|
214
|
-
const val = initialValues[placeholderName];
|
|
215
|
-
if (val === undefined) {
|
|
216
|
-
throw Errors.createError(
|
|
217
|
-
"Placeholder '" + placeholderName + "' is not defined",
|
|
218
|
-
displaySql.call(),
|
|
219
|
-
false,
|
|
220
|
-
info,
|
|
221
|
-
'HY000',
|
|
222
|
-
Errors.ER_PLACEHOLDER_UNDEFINED
|
|
223
|
-
);
|
|
224
|
-
}
|
|
225
|
-
values.push(val);
|
|
226
|
-
lastParameterPosition = idx;
|
|
227
|
-
}
|
|
228
|
-
break;
|
|
229
|
-
case '`':
|
|
230
|
-
if (state === State.Backtick) {
|
|
231
|
-
state = State.Normal;
|
|
232
|
-
} else if (state === State.Normal) {
|
|
233
|
-
state = State.Backtick;
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
lastChar = car;
|
|
237
|
-
|
|
238
|
-
car = sql.charAt(idx++);
|
|
239
|
-
}
|
|
240
|
-
if (lastParameterPosition === 0) {
|
|
241
|
-
partList.push(sql);
|
|
242
|
-
} else {
|
|
243
|
-
partList.push(sql.substring(lastParameterPosition));
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
return { parts: partList, values: values };
|
|
247
|
-
};
|
|
248
|
-
|
|
249
|
-
/**
|
|
250
|
-
* Split query according to parameters (question mark).
|
|
251
|
-
*
|
|
252
|
-
* The only rewritten queries follow these notation: INSERT [LOW_PRIORITY | DELAYED |
|
|
253
|
-
* HIGH_PRIORITY] [IGNORE] [INTO] tbl_name [PARTITION (partition_list)] [(col,...)] {VALUES |
|
|
254
|
-
* VALUE} (...) [ ON DUPLICATE KEY UPDATE col=expr [, col=expr] ... ] With expr without
|
|
255
|
-
* parameter.
|
|
256
|
-
*
|
|
257
|
-
* Query with INSERT ... SELECT / containing LAST_INSERT_ID() will not be rewritten
|
|
258
|
-
*
|
|
259
|
-
* query parts will be split this way :
|
|
260
|
-
* - pre-value part
|
|
261
|
-
* - after value part
|
|
262
|
-
* [- after parameter part] (after each parameter)
|
|
263
|
-
* - ending part
|
|
264
|
-
*
|
|
265
|
-
* example : INSERT INTO MyTABLE VALUES (9, ?, 5, ?, 8) ON DUPLICATE KEY UPDATE col2=col2+10
|
|
266
|
-
* will result in :
|
|
267
|
-
* - pre-value : "INSERT INTO MyTABLE VALUES"
|
|
268
|
-
* - after value : " (9, "
|
|
269
|
-
* - after parameter : ", 5, "
|
|
270
|
-
* - after parameter : ", 8)"
|
|
271
|
-
* - ending : " ON DUPLICATE KEY UPDATE col2=col2+10"
|
|
272
|
-
*
|
|
273
|
-
*
|
|
274
|
-
* @returns {JSON} query separated by parameters
|
|
275
|
-
*/
|
|
276
|
-
module.exports.splitRewritableQuery = function (sql) {
|
|
277
|
-
let reWritablePrepare = true;
|
|
278
|
-
let multipleQueriesPrepare = true;
|
|
279
|
-
let partList = [];
|
|
280
|
-
let lastChar = '\0';
|
|
281
|
-
|
|
282
|
-
let lastParameterPosition = 0;
|
|
283
|
-
|
|
284
|
-
let preValuePart1 = null;
|
|
285
|
-
let preValuePart2 = null;
|
|
286
|
-
let postValuePart = null;
|
|
287
|
-
|
|
143
|
+
let lastChar = 0x00;
|
|
288
144
|
let singleQuotes = false;
|
|
145
|
+
let car;
|
|
289
146
|
|
|
290
|
-
|
|
291
|
-
let
|
|
292
|
-
|
|
293
|
-
let semicolon = false;
|
|
294
|
-
let hasParam = false;
|
|
295
|
-
let state = State.Normal;
|
|
296
|
-
|
|
297
|
-
let idx = 0;
|
|
298
|
-
let car = sql.charAt(idx++);
|
|
299
|
-
while (car !== '') {
|
|
147
|
+
const len = query.length;
|
|
148
|
+
for (let i = 0; i < len; i++) {
|
|
149
|
+
car = query[i];
|
|
300
150
|
if (
|
|
301
151
|
state === State.Escape &&
|
|
302
|
-
!((car ===
|
|
152
|
+
!((car === QUOTE_BYTE && singleQuotes) || (car === DBL_QUOTE_BYTE && !singleQuotes))
|
|
303
153
|
) {
|
|
304
154
|
state = State.String;
|
|
305
|
-
|
|
155
|
+
lastChar = car;
|
|
306
156
|
continue;
|
|
307
157
|
}
|
|
308
|
-
|
|
309
158
|
switch (car) {
|
|
310
|
-
case
|
|
311
|
-
if (state === State.Normal && lastChar
|
|
159
|
+
case STAR_BYTE:
|
|
160
|
+
if (state === State.Normal && lastChar === SLASH_BYTE) {
|
|
312
161
|
state = State.SlashStarComment;
|
|
313
162
|
}
|
|
314
163
|
break;
|
|
315
164
|
|
|
316
|
-
case
|
|
317
|
-
if (state === State.SlashStarComment && lastChar
|
|
165
|
+
case SLASH_BYTE:
|
|
166
|
+
if (state === State.SlashStarComment && lastChar === STAR_BYTE) {
|
|
318
167
|
state = State.Normal;
|
|
168
|
+
} else if (state === State.Normal && lastChar === SLASH_BYTE) {
|
|
169
|
+
state = State.EOLComment;
|
|
319
170
|
}
|
|
320
171
|
break;
|
|
321
172
|
|
|
322
|
-
case
|
|
173
|
+
case HASH_BYTE:
|
|
323
174
|
if (state === State.Normal) {
|
|
324
175
|
state = State.EOLComment;
|
|
325
176
|
}
|
|
326
177
|
break;
|
|
327
178
|
|
|
328
|
-
case
|
|
329
|
-
if (state === State.Normal && lastChar
|
|
179
|
+
case MINUS_BYTE:
|
|
180
|
+
if (state === State.Normal && lastChar === MINUS_BYTE) {
|
|
330
181
|
state = State.EOLComment;
|
|
331
182
|
}
|
|
332
183
|
break;
|
|
333
184
|
|
|
334
|
-
case
|
|
185
|
+
case LINE_FEED_BYTE:
|
|
335
186
|
if (state === State.EOLComment) {
|
|
336
187
|
state = State.Normal;
|
|
337
188
|
}
|
|
338
189
|
break;
|
|
339
190
|
|
|
340
|
-
case
|
|
191
|
+
case DBL_QUOTE_BYTE:
|
|
341
192
|
if (state === State.Normal) {
|
|
342
193
|
state = State.String;
|
|
343
194
|
singleQuotes = false;
|
|
344
195
|
} else if (state === State.String && !singleQuotes) {
|
|
345
196
|
state = State.Normal;
|
|
346
|
-
} else if (state === State.Escape
|
|
197
|
+
} else if (state === State.Escape) {
|
|
347
198
|
state = State.String;
|
|
348
199
|
}
|
|
349
200
|
break;
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
semicolon = true;
|
|
353
|
-
multipleQueriesPrepare = false;
|
|
354
|
-
}
|
|
355
|
-
break;
|
|
356
|
-
case "'":
|
|
201
|
+
|
|
202
|
+
case QUOTE_BYTE:
|
|
357
203
|
if (state === State.Normal) {
|
|
358
204
|
state = State.String;
|
|
359
205
|
singleQuotes = true;
|
|
360
206
|
} else if (state === State.String && singleQuotes) {
|
|
361
207
|
state = State.Normal;
|
|
362
|
-
} else if (state === State.Escape
|
|
208
|
+
} else if (state === State.Escape) {
|
|
363
209
|
state = State.String;
|
|
364
210
|
}
|
|
365
211
|
break;
|
|
366
212
|
|
|
367
|
-
case
|
|
213
|
+
case BACKSLASH_BYTE:
|
|
368
214
|
if (state === State.String) {
|
|
369
215
|
state = State.Escape;
|
|
370
216
|
}
|
|
371
217
|
break;
|
|
372
|
-
|
|
373
|
-
case '?':
|
|
218
|
+
case QUESTION_MARK_BYTE:
|
|
374
219
|
if (state === State.Normal) {
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
220
|
+
const key = Object.keys(placeholderValues)[0];
|
|
221
|
+
values.push(placeholderValues[key]);
|
|
222
|
+
delete placeholderValues[key];
|
|
378
223
|
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
preValuePart2 = '';
|
|
382
|
-
} else if (preValuePart2 === null) {
|
|
383
|
-
preValuePart2 = part;
|
|
384
|
-
} else {
|
|
385
|
-
if (postValuePart) {
|
|
386
|
-
//having parameters after the last ")" of value is not rewritable
|
|
387
|
-
reWritablePrepare = false;
|
|
388
|
-
partList.push(postValuePart + part);
|
|
389
|
-
postValuePart = null;
|
|
390
|
-
} else partList.push(part);
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
break;
|
|
394
|
-
case '`':
|
|
395
|
-
if (state === State.Backtick) {
|
|
396
|
-
state = State.Normal;
|
|
397
|
-
} else if (state === State.Normal) {
|
|
398
|
-
state = State.Backtick;
|
|
224
|
+
paramPositions.push(i);
|
|
225
|
+
paramPositions.push(++i);
|
|
399
226
|
}
|
|
400
227
|
break;
|
|
228
|
+
case COLON_BYTE:
|
|
229
|
+
if (state === State.Normal) {
|
|
230
|
+
let j = 1;
|
|
401
231
|
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
(sql.charAt(idx) === 'e' || sql.charAt(idx) === 'E') &&
|
|
409
|
-
(sql.charAt(idx + 1) === 'l' || sql.charAt(idx + 1) === 'L') &&
|
|
410
|
-
(sql.charAt(idx + 2) === 'e' || sql.charAt(idx + 2) === 'E') &&
|
|
411
|
-
(sql.charAt(idx + 3) === 'c' || sql.charAt(idx + 3) === 'C') &&
|
|
412
|
-
(sql.charAt(idx + 4) === 't' || sql.charAt(idx + 4) === 'T')
|
|
413
|
-
) {
|
|
414
|
-
//field/table name might contain 'select'
|
|
415
|
-
if (
|
|
416
|
-
idx > 1 &&
|
|
417
|
-
sql.charAt(idx - 2) > ' ' &&
|
|
418
|
-
'();><=-+,'.indexOf(sql.charAt(idx - 2)) === -1
|
|
232
|
+
while (
|
|
233
|
+
(i + j < len && query[i + j] >= '0'.charCodeAt(0) && query[i + j] <= '9'.charCodeAt(0)) ||
|
|
234
|
+
(query[i + j] >= 'A'.charCodeAt(0) && query[i + j] <= 'Z'.charCodeAt(0)) ||
|
|
235
|
+
(query[i + j] >= 'a'.charCodeAt(0) && query[i + j] <= 'z'.charCodeAt(0)) ||
|
|
236
|
+
query[i + j] === '-'.charCodeAt(0) ||
|
|
237
|
+
query[i + j] === '_'.charCodeAt(0)
|
|
419
238
|
) {
|
|
420
|
-
|
|
239
|
+
j++;
|
|
421
240
|
}
|
|
422
|
-
|
|
423
|
-
|
|
241
|
+
|
|
242
|
+
paramPositions.push(i, i + j);
|
|
243
|
+
|
|
244
|
+
const placeholderName = query.toString('utf8', i + 1, i + j);
|
|
245
|
+
i += j;
|
|
246
|
+
let val;
|
|
247
|
+
if (placeholderName in placeholderValues) {
|
|
248
|
+
val = placeholderValues[placeholderName];
|
|
249
|
+
delete placeholderValues[placeholderName];
|
|
250
|
+
} else {
|
|
251
|
+
// value is already used
|
|
252
|
+
val = initialValues[placeholderName];
|
|
424
253
|
}
|
|
425
254
|
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
!preValuePart1 &&
|
|
435
|
-
(lastChar == ')' || lastChar <= ' ') &&
|
|
436
|
-
sql.length > idx + 6 &&
|
|
437
|
-
(sql.charAt(idx) === 'a' || sql.charAt(idx) === 'A') &&
|
|
438
|
-
(sql.charAt(idx + 1) === 'l' || sql.charAt(idx + 1) === 'L') &&
|
|
439
|
-
(sql.charAt(idx + 2) === 'u' || sql.charAt(idx + 2) === 'U') &&
|
|
440
|
-
(sql.charAt(idx + 3) === 'e' || sql.charAt(idx + 3) === 'E') &&
|
|
441
|
-
(sql.charAt(idx + 4) === 's' || sql.charAt(idx + 4) === 'S') &&
|
|
442
|
-
(sql.charAt(idx + 5) === '(' || sql.charAt(idx + 5) <= ' ')
|
|
443
|
-
) {
|
|
444
|
-
idx += 5;
|
|
445
|
-
preValuePart1 = sql.substring(lastParameterPosition, idx);
|
|
446
|
-
lastParameterPosition = idx;
|
|
447
|
-
}
|
|
448
|
-
break;
|
|
449
|
-
case 'l':
|
|
450
|
-
case 'L':
|
|
451
|
-
if (
|
|
452
|
-
state === State.Normal &&
|
|
453
|
-
sql.length > idx + 13 &&
|
|
454
|
-
(sql.charAt(idx) === 'a' || sql.charAt(idx) === 'A') &&
|
|
455
|
-
(sql.charAt(idx + 1) === 's' || sql.charAt(idx + 1) === 'S') &&
|
|
456
|
-
(sql.charAt(idx + 2) === 't' || sql.charAt(idx + 2) === 'T') &&
|
|
457
|
-
sql.charAt(idx + 3) === '_' &&
|
|
458
|
-
(sql.charAt(idx + 4) === 'i' || sql.charAt(idx + 4) === 'I') &&
|
|
459
|
-
(sql.charAt(idx + 5) === 'n' || sql.charAt(idx + 5) === 'N') &&
|
|
460
|
-
(sql.charAt(idx + 6) === 's' || sql.charAt(idx + 6) === 'S') &&
|
|
461
|
-
(sql.charAt(idx + 7) === 'e' || sql.charAt(idx + 7) === 'E') &&
|
|
462
|
-
(sql.charAt(idx + 8) === 'r' || sql.charAt(idx + 8) === 'R') &&
|
|
463
|
-
(sql.charAt(idx + 9) === 't' || sql.charAt(idx + 9) === 'T') &&
|
|
464
|
-
sql.charAt(idx + 10) === '_' &&
|
|
465
|
-
(sql.charAt(idx + 11) === 'i' || sql.charAt(idx + 11) === 'I') &&
|
|
466
|
-
(sql.charAt(idx + 12) === 'd' || sql.charAt(idx + 12) === 'D') &&
|
|
467
|
-
sql.charAt(idx + 13) === '('
|
|
468
|
-
) {
|
|
469
|
-
reWritablePrepare = false;
|
|
470
|
-
idx += 13;
|
|
471
|
-
}
|
|
472
|
-
break;
|
|
473
|
-
case '(':
|
|
474
|
-
if (state === State.Normal) {
|
|
475
|
-
isInParenthesis++;
|
|
476
|
-
}
|
|
477
|
-
break;
|
|
478
|
-
case ')':
|
|
479
|
-
if (state === State.Normal) {
|
|
480
|
-
isInParenthesis--;
|
|
481
|
-
if (isInParenthesis === 0 && preValuePart2 !== null && postValuePart === null) {
|
|
482
|
-
postValuePart = sql.substring(lastParameterPosition, idx);
|
|
483
|
-
lastParameterPosition = idx;
|
|
255
|
+
if (val === undefined) {
|
|
256
|
+
throw Errors.createError(
|
|
257
|
+
`Placeholder '${placeholderName}' is not defined`,
|
|
258
|
+
Errors.ER_PLACEHOLDER_UNDEFINED,
|
|
259
|
+
info,
|
|
260
|
+
'HY000',
|
|
261
|
+
displaySql.call()
|
|
262
|
+
);
|
|
484
263
|
}
|
|
264
|
+
values.push(val);
|
|
485
265
|
}
|
|
486
266
|
break;
|
|
487
|
-
|
|
488
|
-
if (state === State.
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
(sql.charAt(idx) === 'n' || sql.charAt(idx) === 'N') &&
|
|
493
|
-
(sql.charAt(idx + 1) === 's' || sql.charAt(idx + 1) === 'S') &&
|
|
494
|
-
(sql.charAt(idx + 2) === 'e' || sql.charAt(idx + 2) === 'E') &&
|
|
495
|
-
(sql.charAt(idx + 3) === 'r' || sql.charAt(idx + 3) === 'R') &&
|
|
496
|
-
(sql.charAt(idx + 4) === 't' || sql.charAt(idx + 4) === 'T') &&
|
|
497
|
-
(sql.charAt(idx + 5) === '(' || sql.charAt(idx + 5) <= ' ')
|
|
498
|
-
) {
|
|
499
|
-
isInsert = true;
|
|
500
|
-
}
|
|
501
|
-
isFirstChar = false;
|
|
502
|
-
}
|
|
503
|
-
//multiple queries
|
|
504
|
-
if (state === State.Normal && semicolon && car >= ' ') {
|
|
505
|
-
reWritablePrepare = false;
|
|
506
|
-
multipleQueriesPrepare = true;
|
|
267
|
+
case RADICAL_BYTE:
|
|
268
|
+
if (state === State.Backtick) {
|
|
269
|
+
state = State.Normal;
|
|
270
|
+
} else if (state === State.Normal) {
|
|
271
|
+
state = State.Backtick;
|
|
507
272
|
}
|
|
508
273
|
break;
|
|
509
274
|
}
|
|
510
|
-
|
|
511
275
|
lastChar = car;
|
|
512
|
-
car = sql.charAt(idx++);
|
|
513
276
|
}
|
|
514
|
-
|
|
515
|
-
if (state === State.EOLComment) multipleQueriesPrepare = false;
|
|
516
|
-
|
|
517
|
-
if (!hasParam) {
|
|
518
|
-
//permit to have rewrite without parameter
|
|
519
|
-
if (preValuePart1 === null) {
|
|
520
|
-
partList.unshift('');
|
|
521
|
-
partList.unshift(sql);
|
|
522
|
-
} else {
|
|
523
|
-
partList.unshift(sql.substring(lastParameterPosition, idx));
|
|
524
|
-
partList.unshift(preValuePart1);
|
|
525
|
-
}
|
|
526
|
-
lastParameterPosition = idx;
|
|
527
|
-
} else {
|
|
528
|
-
partList.unshift(preValuePart2 !== null ? preValuePart2 : '');
|
|
529
|
-
partList.unshift(preValuePart1 !== null ? preValuePart1 : '');
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
if (!isInsert) {
|
|
533
|
-
reWritablePrepare = false;
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
//postValuePart is the value after the last parameter and parenthesis
|
|
537
|
-
//if no param, don't add to the list.
|
|
538
|
-
if (hasParam) {
|
|
539
|
-
partList.push(postValuePart !== null ? postValuePart : '');
|
|
540
|
-
}
|
|
541
|
-
partList.push(sql.substring(lastParameterPosition, idx));
|
|
542
|
-
|
|
543
|
-
return {
|
|
544
|
-
partList: partList,
|
|
545
|
-
reWritable: reWritablePrepare,
|
|
546
|
-
multipleQueries: multipleQueriesPrepare
|
|
547
|
-
};
|
|
277
|
+
return { paramPositions: paramPositions, values: values };
|
|
548
278
|
};
|
|
549
279
|
|
|
550
|
-
module.exports.searchPlaceholder = function (sql
|
|
280
|
+
module.exports.searchPlaceholder = function (sql) {
|
|
551
281
|
let sqlPlaceHolder = '';
|
|
552
|
-
|
|
553
|
-
let values = new Array(rowNumber);
|
|
554
|
-
for (let i = 0; i < rowNumber; i++) values[i] = [];
|
|
282
|
+
let placeHolderIndex = [];
|
|
555
283
|
let state = State.Normal;
|
|
556
284
|
let lastChar = '\0';
|
|
557
285
|
|
|
@@ -563,10 +291,7 @@ module.exports.searchPlaceholder = function (sql, info, initialValues, displaySq
|
|
|
563
291
|
let placeholderName;
|
|
564
292
|
|
|
565
293
|
while (car !== '') {
|
|
566
|
-
if (
|
|
567
|
-
state === State.Escape &&
|
|
568
|
-
!((car === "'" && singleQuotes) || (car === '"' && !singleQuotes))
|
|
569
|
-
) {
|
|
294
|
+
if (state === State.Escape && !((car === "'" && singleQuotes) || (car === '"' && !singleQuotes))) {
|
|
570
295
|
state = State.String;
|
|
571
296
|
lastChar = car;
|
|
572
297
|
car = sql.charAt(idx++);
|
|
@@ -575,11 +300,11 @@ module.exports.searchPlaceholder = function (sql, info, initialValues, displaySq
|
|
|
575
300
|
|
|
576
301
|
switch (car) {
|
|
577
302
|
case '*':
|
|
578
|
-
if (state === State.Normal && lastChar
|
|
303
|
+
if (state === State.Normal && lastChar === '/') state = State.SlashStarComment;
|
|
579
304
|
break;
|
|
580
305
|
|
|
581
306
|
case '/':
|
|
582
|
-
if (state === State.SlashStarComment && lastChar
|
|
307
|
+
if (state === State.SlashStarComment && lastChar === '*') state = State.Normal;
|
|
583
308
|
break;
|
|
584
309
|
|
|
585
310
|
case '#':
|
|
@@ -587,7 +312,7 @@ module.exports.searchPlaceholder = function (sql, info, initialValues, displaySq
|
|
|
587
312
|
break;
|
|
588
313
|
|
|
589
314
|
case '-':
|
|
590
|
-
if (state === State.Normal && lastChar
|
|
315
|
+
if (state === State.Normal && lastChar === '-') {
|
|
591
316
|
state = State.EOLComment;
|
|
592
317
|
}
|
|
593
318
|
break;
|
|
@@ -639,14 +364,7 @@ module.exports.searchPlaceholder = function (sql, info, initialValues, displaySq
|
|
|
639
364
|
placeholderName += car;
|
|
640
365
|
}
|
|
641
366
|
idx--;
|
|
642
|
-
|
|
643
|
-
const val = initialValues[i][placeholderName];
|
|
644
|
-
if (val !== undefined) {
|
|
645
|
-
values[i].push(val);
|
|
646
|
-
} else {
|
|
647
|
-
values[i].push(null);
|
|
648
|
-
}
|
|
649
|
-
}
|
|
367
|
+
placeHolderIndex.push(placeholderName);
|
|
650
368
|
lastParameterPosition = idx;
|
|
651
369
|
}
|
|
652
370
|
break;
|
|
@@ -667,367 +385,145 @@ module.exports.searchPlaceholder = function (sql, info, initialValues, displaySq
|
|
|
667
385
|
sqlPlaceHolder += sql.substring(lastParameterPosition);
|
|
668
386
|
}
|
|
669
387
|
|
|
670
|
-
return { sql: sqlPlaceHolder,
|
|
388
|
+
return { sql: sqlPlaceHolder, placeHolderIndex: placeHolderIndex };
|
|
671
389
|
};
|
|
672
390
|
|
|
673
391
|
/**
|
|
674
|
-
*
|
|
675
|
-
*
|
|
676
|
-
* The only rewritten queries follow these notation: INSERT [LOW_PRIORITY | DELAYED |
|
|
677
|
-
* HIGH_PRIORITY] [IGNORE] [INTO] tbl_name [PARTITION (partition_list)] [(col,...)] {VALUES |
|
|
678
|
-
* VALUE} (...) [ ON DUPLICATE KEY UPDATE col=expr [, col=expr] ... ] With expr without
|
|
679
|
-
* parameter.
|
|
680
|
-
*
|
|
681
|
-
* Query with INSERT ... SELECT / containing LAST_INSERT_ID() will not be rewritten
|
|
682
|
-
*
|
|
683
|
-
* query parts will be split this way :
|
|
684
|
-
* - pre-value part
|
|
685
|
-
* - after value part
|
|
686
|
-
* [- after parameter part] (after each parameter)
|
|
687
|
-
* - ending part
|
|
688
|
-
*
|
|
689
|
-
* example : INSERT INTO MyTABLE VALUES (9, :param1, 5, :param2, 8) ON DUPLICATE KEY UPDATE col2=col2+10
|
|
690
|
-
* will result in :
|
|
691
|
-
* - pre-value : "INSERT INTO MyTABLE VALUES"
|
|
692
|
-
* - after value : " (9, "
|
|
693
|
-
* - after parameter : ", 5, "
|
|
694
|
-
* - after parameter : ", 8)"
|
|
695
|
-
* - ending : " ON DUPLICATE KEY UPDATE col2=col2+10"
|
|
696
|
-
*
|
|
392
|
+
* Ensure that filename requested by server corresponds to query
|
|
393
|
+
* protocol : https://mariadb.com/kb/en/library/local_infile-packet/
|
|
697
394
|
*
|
|
698
|
-
* @
|
|
395
|
+
* @param sql query
|
|
396
|
+
* @param parameters parameters if any
|
|
397
|
+
* @param fileName server requested file
|
|
398
|
+
* @returns {boolean} is filename corresponding to query
|
|
699
399
|
*/
|
|
700
|
-
module.exports.
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
let postValuePart = null;
|
|
400
|
+
module.exports.validateFileName = function (sql, parameters, fileName) {
|
|
401
|
+
// in case of windows, file name in query are escaped
|
|
402
|
+
// so for example LOAD DATA LOCAL INFILE 'C:\\Temp\\myFile.txt' ...
|
|
403
|
+
// but server return 'C:\Temp\myFile.txt'
|
|
404
|
+
// so with regex escaped, must test LOAD DATA LOCAL INFILE 'C:\\\\Temp\\\\myFile.txt'
|
|
405
|
+
let queryValidator = new RegExp(
|
|
406
|
+
"^(\\s*\\/\\*([^\\*]|\\*[^\\/])*\\*\\/)*\\s*LOAD\\s+DATA\\s+((LOW_PRIORITY|CONCURRENT)\\s+)?LOCAL\\s+INFILE\\s+'" +
|
|
407
|
+
fileName.replace(/\\/g, '\\\\\\\\').replace('.', '\\.') +
|
|
408
|
+
"'",
|
|
409
|
+
'i'
|
|
410
|
+
);
|
|
411
|
+
if (queryValidator.test(sql)) return true;
|
|
713
412
|
|
|
714
|
-
|
|
413
|
+
if (parameters != null) {
|
|
414
|
+
queryValidator = new RegExp(
|
|
415
|
+
'^(\\s*\\/\\*([^\\*]|\\*[^\\/])*\\*\\/)*\\s*LOAD\\s+DATA\\s+((LOW_PRIORITY|CONCURRENT)\\s+)?LOCAL\\s+INFILE\\s+\\?',
|
|
416
|
+
'i'
|
|
417
|
+
);
|
|
418
|
+
if (queryValidator.test(sql) && parameters.length > 0) {
|
|
419
|
+
if (Array.isArray(parameters)) {
|
|
420
|
+
return parameters[0].toLowerCase() === fileName.toLowerCase();
|
|
421
|
+
}
|
|
422
|
+
return parameters.toLowerCase() === fileName.toLowerCase();
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
return false;
|
|
426
|
+
};
|
|
715
427
|
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
428
|
+
/**
|
|
429
|
+
* Parse commands from buffer, returns queries separated by ';'
|
|
430
|
+
* (last one is not parsed)
|
|
431
|
+
*
|
|
432
|
+
* @param bufState buffer
|
|
433
|
+
* @returns {*[]} array of queries contained in buffer
|
|
434
|
+
*/
|
|
435
|
+
module.exports.parseQueries = function (bufState) {
|
|
722
436
|
let state = State.Normal;
|
|
437
|
+
let lastChar = 0x00;
|
|
438
|
+
let currByte;
|
|
439
|
+
let queries = [];
|
|
440
|
+
let singleQuotes = false;
|
|
723
441
|
|
|
724
|
-
let
|
|
725
|
-
|
|
726
|
-
while (car !== '') {
|
|
442
|
+
for (let i = bufState.offset; i < bufState.end; i++) {
|
|
443
|
+
currByte = bufState.buffer[i];
|
|
727
444
|
if (
|
|
728
445
|
state === State.Escape &&
|
|
729
|
-
!((
|
|
446
|
+
!((currByte === QUOTE_BYTE && singleQuotes) || (currByte === DBL_QUOTE_BYTE && !singleQuotes))
|
|
730
447
|
) {
|
|
731
448
|
state = State.String;
|
|
732
|
-
|
|
449
|
+
lastChar = currByte;
|
|
733
450
|
continue;
|
|
734
451
|
}
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
if (state === State.Normal && lastChar == '/') {
|
|
452
|
+
switch (currByte) {
|
|
453
|
+
case STAR_BYTE:
|
|
454
|
+
if (state === State.Normal && lastChar === SLASH_BYTE) {
|
|
739
455
|
state = State.SlashStarComment;
|
|
740
456
|
}
|
|
741
457
|
break;
|
|
742
458
|
|
|
743
|
-
case
|
|
744
|
-
if (state === State.SlashStarComment && lastChar
|
|
459
|
+
case SLASH_BYTE:
|
|
460
|
+
if (state === State.SlashStarComment && lastChar === STAR_BYTE) {
|
|
745
461
|
state = State.Normal;
|
|
462
|
+
} else if (state === State.Normal && lastChar === SLASH_BYTE) {
|
|
463
|
+
state = State.EOLComment;
|
|
746
464
|
}
|
|
747
465
|
break;
|
|
748
466
|
|
|
749
|
-
case
|
|
467
|
+
case HASH_BYTE:
|
|
750
468
|
if (state === State.Normal) {
|
|
751
469
|
state = State.EOLComment;
|
|
752
470
|
}
|
|
753
471
|
break;
|
|
754
472
|
|
|
755
|
-
case
|
|
756
|
-
if (state === State.Normal && lastChar
|
|
473
|
+
case MINUS_BYTE:
|
|
474
|
+
if (state === State.Normal && lastChar === MINUS_BYTE) {
|
|
757
475
|
state = State.EOLComment;
|
|
758
476
|
}
|
|
759
477
|
break;
|
|
760
478
|
|
|
761
|
-
case
|
|
479
|
+
case LINE_FEED_BYTE:
|
|
762
480
|
if (state === State.EOLComment) {
|
|
763
481
|
state = State.Normal;
|
|
764
482
|
}
|
|
765
483
|
break;
|
|
766
484
|
|
|
767
|
-
case
|
|
485
|
+
case DBL_QUOTE_BYTE:
|
|
768
486
|
if (state === State.Normal) {
|
|
769
487
|
state = State.String;
|
|
770
488
|
singleQuotes = false;
|
|
771
489
|
} else if (state === State.String && !singleQuotes) {
|
|
772
490
|
state = State.Normal;
|
|
773
|
-
} else if (state === State.Escape
|
|
491
|
+
} else if (state === State.Escape) {
|
|
774
492
|
state = State.String;
|
|
775
493
|
}
|
|
776
494
|
break;
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
semicolon = true;
|
|
780
|
-
multipleQueriesPrepare = false;
|
|
781
|
-
}
|
|
782
|
-
break;
|
|
783
|
-
case "'":
|
|
495
|
+
|
|
496
|
+
case QUOTE_BYTE:
|
|
784
497
|
if (state === State.Normal) {
|
|
785
498
|
state = State.String;
|
|
786
499
|
singleQuotes = true;
|
|
787
500
|
} else if (state === State.String && singleQuotes) {
|
|
788
501
|
state = State.Normal;
|
|
789
|
-
} else if (state === State.Escape
|
|
502
|
+
} else if (state === State.Escape) {
|
|
790
503
|
state = State.String;
|
|
791
504
|
}
|
|
792
505
|
break;
|
|
793
506
|
|
|
794
|
-
case
|
|
507
|
+
case BACKSLASH_BYTE:
|
|
795
508
|
if (state === State.String) {
|
|
796
509
|
state = State.Escape;
|
|
797
510
|
}
|
|
798
511
|
break;
|
|
799
|
-
|
|
800
|
-
case ':':
|
|
512
|
+
case SEMICOLON_BYTE:
|
|
801
513
|
if (state === State.Normal) {
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
while (
|
|
805
|
-
((car = sql.charAt(idx++)) !== '' && car >= '0' && car <= '9') ||
|
|
806
|
-
(car >= 'A' && car <= 'Z') ||
|
|
807
|
-
(car >= 'a' && car <= 'z') ||
|
|
808
|
-
car === '-' ||
|
|
809
|
-
car === '_'
|
|
810
|
-
) {
|
|
811
|
-
placeholderName += car;
|
|
812
|
-
}
|
|
813
|
-
idx--;
|
|
814
|
-
hasParam = true;
|
|
815
|
-
initialValues.forEach((row, idx) => {
|
|
816
|
-
if (row[placeholderName] !== undefined) {
|
|
817
|
-
values[idx].push(row[placeholderName]);
|
|
818
|
-
} else {
|
|
819
|
-
values[idx].push(null);
|
|
820
|
-
}
|
|
821
|
-
});
|
|
822
|
-
|
|
823
|
-
lastParameterPosition = idx;
|
|
824
|
-
|
|
825
|
-
if (preValuePart1 === null) {
|
|
826
|
-
preValuePart1 = part;
|
|
827
|
-
preValuePart2 = '';
|
|
828
|
-
} else if (preValuePart2 === null) {
|
|
829
|
-
preValuePart2 = part;
|
|
830
|
-
} else {
|
|
831
|
-
if (postValuePart) {
|
|
832
|
-
//having parameters after the last ")" of value is not rewritable
|
|
833
|
-
reWritablePrepare = false;
|
|
834
|
-
partList.push(postValuePart + part);
|
|
835
|
-
postValuePart = null;
|
|
836
|
-
} else partList.push(part);
|
|
837
|
-
}
|
|
514
|
+
queries.push(bufState.buffer.toString('utf8', bufState.offset, i));
|
|
515
|
+
bufState.offset = i + 1;
|
|
838
516
|
}
|
|
839
517
|
break;
|
|
840
|
-
|
|
841
|
-
case '`':
|
|
518
|
+
case RADICAL_BYTE:
|
|
842
519
|
if (state === State.Backtick) {
|
|
843
520
|
state = State.Normal;
|
|
844
521
|
} else if (state === State.Normal) {
|
|
845
522
|
state = State.Backtick;
|
|
846
523
|
}
|
|
847
524
|
break;
|
|
848
|
-
|
|
849
|
-
case 's':
|
|
850
|
-
case 'S':
|
|
851
|
-
if (
|
|
852
|
-
state === State.Normal &&
|
|
853
|
-
postValuePart === null &&
|
|
854
|
-
sql.length > idx + 5 &&
|
|
855
|
-
(sql.charAt(idx) === 'e' || sql.charAt(idx) === 'E') &&
|
|
856
|
-
(sql.charAt(idx + 1) === 'l' || sql.charAt(idx + 1) === 'L') &&
|
|
857
|
-
(sql.charAt(idx + 2) === 'e' || sql.charAt(idx + 2) === 'E') &&
|
|
858
|
-
(sql.charAt(idx + 3) === 'c' || sql.charAt(idx + 3) === 'C') &&
|
|
859
|
-
(sql.charAt(idx + 4) === 't' || sql.charAt(idx + 4) === 'T')
|
|
860
|
-
) {
|
|
861
|
-
//field/table name might contain 'select'
|
|
862
|
-
if (
|
|
863
|
-
idx > 1 &&
|
|
864
|
-
sql.charAt(idx - 2) > ' ' &&
|
|
865
|
-
'();><=-+,'.indexOf(sql.charAt(idx - 2)) === -1
|
|
866
|
-
) {
|
|
867
|
-
break;
|
|
868
|
-
}
|
|
869
|
-
if (sql.charAt(idx + 5) > ' ' && '();><=-+,'.indexOf(sql.charAt(idx + 5)) === -1) {
|
|
870
|
-
break;
|
|
871
|
-
}
|
|
872
|
-
|
|
873
|
-
//SELECT queries, INSERT FROM SELECT not rewritable
|
|
874
|
-
reWritablePrepare = false;
|
|
875
|
-
}
|
|
876
|
-
break;
|
|
877
|
-
case 'v':
|
|
878
|
-
case 'V':
|
|
879
|
-
if (
|
|
880
|
-
state === State.Normal &&
|
|
881
|
-
!preValuePart1 &&
|
|
882
|
-
(lastChar == ')' || lastChar <= ' ') &&
|
|
883
|
-
sql.length > idx + 6 &&
|
|
884
|
-
(sql.charAt(idx) === 'a' || sql.charAt(idx) === 'A') &&
|
|
885
|
-
(sql.charAt(idx + 1) === 'l' || sql.charAt(idx + 1) === 'L') &&
|
|
886
|
-
(sql.charAt(idx + 2) === 'u' || sql.charAt(idx + 2) === 'U') &&
|
|
887
|
-
(sql.charAt(idx + 3) === 'e' || sql.charAt(idx + 3) === 'E') &&
|
|
888
|
-
(sql.charAt(idx + 4) === 's' || sql.charAt(idx + 4) === 'S') &&
|
|
889
|
-
(sql.charAt(idx + 5) === '(' || sql.charAt(idx + 5) <= ' ')
|
|
890
|
-
) {
|
|
891
|
-
idx += 5;
|
|
892
|
-
preValuePart1 = sql.substring(lastParameterPosition, idx);
|
|
893
|
-
lastParameterPosition = idx;
|
|
894
|
-
}
|
|
895
|
-
break;
|
|
896
|
-
case 'l':
|
|
897
|
-
case 'L':
|
|
898
|
-
if (
|
|
899
|
-
state === State.Normal &&
|
|
900
|
-
sql.length > idx + 13 &&
|
|
901
|
-
(sql.charAt(idx) === 'a' || sql.charAt(idx) === 'A') &&
|
|
902
|
-
(sql.charAt(idx + 1) === 's' || sql.charAt(idx + 1) === 'S') &&
|
|
903
|
-
(sql.charAt(idx + 2) === 't' || sql.charAt(idx + 2) === 'T') &&
|
|
904
|
-
sql.charAt(idx + 3) === '_' &&
|
|
905
|
-
(sql.charAt(idx + 4) === 'i' || sql.charAt(idx + 4) === 'I') &&
|
|
906
|
-
(sql.charAt(idx + 5) === 'n' || sql.charAt(idx + 5) === 'N') &&
|
|
907
|
-
(sql.charAt(idx + 6) === 's' || sql.charAt(idx + 6) === 'S') &&
|
|
908
|
-
(sql.charAt(idx + 7) === 'e' || sql.charAt(idx + 7) === 'E') &&
|
|
909
|
-
(sql.charAt(idx + 8) === 'r' || sql.charAt(idx + 8) === 'R') &&
|
|
910
|
-
(sql.charAt(idx + 9) === 't' || sql.charAt(idx + 9) === 'T') &&
|
|
911
|
-
sql.charAt(idx + 10) === '_' &&
|
|
912
|
-
(sql.charAt(idx + 11) === 'i' || sql.charAt(idx + 11) === 'I') &&
|
|
913
|
-
(sql.charAt(idx + 12) === 'd' || sql.charAt(idx + 12) === 'D') &&
|
|
914
|
-
sql.charAt(idx + 13) === '('
|
|
915
|
-
) {
|
|
916
|
-
reWritablePrepare = false;
|
|
917
|
-
idx += 13;
|
|
918
|
-
}
|
|
919
|
-
break;
|
|
920
|
-
case '(':
|
|
921
|
-
if (state === State.Normal) {
|
|
922
|
-
isInParenthesis++;
|
|
923
|
-
}
|
|
924
|
-
break;
|
|
925
|
-
case ')':
|
|
926
|
-
if (state === State.Normal) {
|
|
927
|
-
isInParenthesis--;
|
|
928
|
-
if (isInParenthesis === 0 && preValuePart2 !== null && postValuePart === null) {
|
|
929
|
-
postValuePart = sql.substring(lastParameterPosition, idx);
|
|
930
|
-
lastParameterPosition = idx;
|
|
931
|
-
}
|
|
932
|
-
}
|
|
933
|
-
break;
|
|
934
|
-
default:
|
|
935
|
-
if (state === State.Normal && isFirstChar && car > ' ') {
|
|
936
|
-
if (
|
|
937
|
-
(car === 'I' || car === 'i') &&
|
|
938
|
-
sql.length > idx + 6 &&
|
|
939
|
-
(sql.charAt(idx) === 'n' || sql.charAt(idx) === 'N') &&
|
|
940
|
-
(sql.charAt(idx + 1) === 's' || sql.charAt(idx + 1) === 'S') &&
|
|
941
|
-
(sql.charAt(idx + 2) === 'e' || sql.charAt(idx + 2) === 'E') &&
|
|
942
|
-
(sql.charAt(idx + 3) === 'r' || sql.charAt(idx + 3) === 'R') &&
|
|
943
|
-
(sql.charAt(idx + 4) === 't' || sql.charAt(idx + 4) === 'T') &&
|
|
944
|
-
(sql.charAt(idx + 5) === '(' || sql.charAt(idx + 5) <= ' ')
|
|
945
|
-
) {
|
|
946
|
-
isInsert = true;
|
|
947
|
-
}
|
|
948
|
-
isFirstChar = false;
|
|
949
|
-
}
|
|
950
|
-
//multiple queries
|
|
951
|
-
if (state === State.Normal && semicolon && car >= ' ') {
|
|
952
|
-
reWritablePrepare = false;
|
|
953
|
-
multipleQueriesPrepare = true;
|
|
954
|
-
}
|
|
955
|
-
break;
|
|
956
|
-
}
|
|
957
|
-
|
|
958
|
-
lastChar = car;
|
|
959
|
-
car = sql.charAt(idx++);
|
|
960
|
-
}
|
|
961
|
-
|
|
962
|
-
if (state === State.EOLComment) multipleQueriesPrepare = false;
|
|
963
|
-
|
|
964
|
-
if (!hasParam) {
|
|
965
|
-
//permit to have rewrite without parameter
|
|
966
|
-
if (preValuePart1 === null) {
|
|
967
|
-
partList.unshift('');
|
|
968
|
-
partList.unshift(sql);
|
|
969
|
-
} else {
|
|
970
|
-
partList.unshift(sql.substring(lastParameterPosition, idx));
|
|
971
|
-
partList.unshift(preValuePart1);
|
|
972
|
-
}
|
|
973
|
-
lastParameterPosition = idx;
|
|
974
|
-
} else {
|
|
975
|
-
partList.unshift(preValuePart2 !== null ? preValuePart2 : '');
|
|
976
|
-
partList.unshift(preValuePart1 !== null ? preValuePart1 : '');
|
|
977
|
-
}
|
|
978
|
-
|
|
979
|
-
if (!isInsert) {
|
|
980
|
-
reWritablePrepare = false;
|
|
981
|
-
}
|
|
982
|
-
|
|
983
|
-
//postValuePart is the value after the last parameter and parenthesis
|
|
984
|
-
//if no param, don't add to the list.
|
|
985
|
-
if (hasParam) {
|
|
986
|
-
partList.push(postValuePart !== null ? postValuePart : '');
|
|
987
|
-
}
|
|
988
|
-
partList.push(sql.substring(lastParameterPosition, idx));
|
|
989
|
-
|
|
990
|
-
return {
|
|
991
|
-
partList: partList,
|
|
992
|
-
reWritable: reWritablePrepare,
|
|
993
|
-
multipleQueries: multipleQueriesPrepare,
|
|
994
|
-
values: values
|
|
995
|
-
};
|
|
996
|
-
};
|
|
997
|
-
|
|
998
|
-
/**
|
|
999
|
-
* Ensure that filename requested by server corresponds to query
|
|
1000
|
-
* protocol : https://mariadb.com/kb/en/library/local_infile-packet/
|
|
1001
|
-
*
|
|
1002
|
-
* @param sql query
|
|
1003
|
-
* @param parameters parameters if any
|
|
1004
|
-
* @param fileName server requested file
|
|
1005
|
-
* @returns {boolean} is filename corresponding to query
|
|
1006
|
-
*/
|
|
1007
|
-
module.exports.validateFileName = function (sql, parameters, fileName) {
|
|
1008
|
-
// in case of windows, file name in query are escaped
|
|
1009
|
-
// so for example LOAD DATA LOCAL INFILE 'C:\\Temp\\myFile.txt' ...
|
|
1010
|
-
// but server return 'C:\Temp\myFile.txt'
|
|
1011
|
-
// so with regex escaped, must test LOAD DATA LOCAL INFILE 'C:\\\\Temp\\\\myFile.txt'
|
|
1012
|
-
let queryValidator = new RegExp(
|
|
1013
|
-
"^(\\s*\\/\\*([^\\*]|\\*[^\\/])*\\*\\/)*\\s*LOAD\\s+DATA\\s+((LOW_PRIORITY|CONCURRENT)\\s+)?LOCAL\\s+INFILE\\s+'" +
|
|
1014
|
-
fileName.replace(/\\/g, '\\\\\\\\').replace('.', '\\.') +
|
|
1015
|
-
"'",
|
|
1016
|
-
'i'
|
|
1017
|
-
);
|
|
1018
|
-
if (queryValidator.test(sql)) return true;
|
|
1019
|
-
|
|
1020
|
-
if (parameters != null) {
|
|
1021
|
-
queryValidator = new RegExp(
|
|
1022
|
-
'^(\\s*\\/\\*([^\\*]|\\*[^\\/])*\\*\\/)*\\s*LOAD\\s+DATA\\s+((LOW_PRIORITY|CONCURRENT)\\s+)?LOCAL\\s+INFILE\\s+\\?',
|
|
1023
|
-
'i'
|
|
1024
|
-
);
|
|
1025
|
-
if (queryValidator.test(sql) && parameters.length > 0) {
|
|
1026
|
-
if (Array.isArray(parameters)) {
|
|
1027
|
-
return parameters[0].toLowerCase() === fileName.toLowerCase();
|
|
1028
|
-
}
|
|
1029
|
-
return parameters.toLowerCase() === fileName.toLowerCase();
|
|
1030
525
|
}
|
|
526
|
+
lastChar = currByte;
|
|
1031
527
|
}
|
|
1032
|
-
return
|
|
528
|
+
return queries;
|
|
1033
529
|
};
|