@tachybase/module-multi-app 1.6.0 → 1.6.2

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.
Files changed (105) hide show
  1. package/README.md +34 -34
  2. package/README.zh-CN.md +34 -34
  3. package/client.d.ts +1 -1
  4. package/client.js +1 -1
  5. package/dist/externalVersion.js +5 -5
  6. package/dist/locale/en-US.json +48 -48
  7. package/dist/locale/es-ES.json +9 -9
  8. package/dist/locale/ko_KR.json +11 -11
  9. package/dist/locale/pt-BR.json +9 -9
  10. package/dist/locale/zh-CN.json +58 -58
  11. package/dist/node_modules/mariadb/callback.js +43 -8
  12. package/dist/node_modules/mariadb/check-node.js +30 -0
  13. package/dist/node_modules/mariadb/lib/cluster-callback.js +84 -0
  14. package/dist/node_modules/mariadb/lib/cluster.js +446 -0
  15. package/dist/node_modules/mariadb/lib/cmd/batch-bulk.js +576 -177
  16. package/dist/node_modules/mariadb/lib/cmd/change-user.js +54 -44
  17. package/dist/node_modules/mariadb/lib/cmd/class/ok-packet.js +3 -2
  18. package/dist/node_modules/mariadb/lib/cmd/class/prepare-cache-wrapper.js +46 -0
  19. package/dist/node_modules/mariadb/lib/cmd/class/prepare-result-packet.js +141 -0
  20. package/dist/node_modules/mariadb/lib/cmd/class/prepare-wrapper.js +70 -0
  21. package/dist/node_modules/mariadb/lib/cmd/close-prepare.js +38 -0
  22. package/dist/node_modules/mariadb/lib/cmd/column-definition.js +145 -47
  23. package/dist/node_modules/mariadb/lib/cmd/command.js +41 -75
  24. package/dist/node_modules/mariadb/lib/cmd/decoder/binary-decoder.js +282 -0
  25. package/dist/node_modules/mariadb/lib/cmd/decoder/text-decoder.js +210 -0
  26. package/dist/node_modules/mariadb/lib/cmd/{common-binary-cmd.js → encoder/binary-encoder.js} +34 -77
  27. package/dist/node_modules/mariadb/lib/cmd/encoder/text-encoder.js +311 -0
  28. package/dist/node_modules/mariadb/lib/cmd/execute-stream.js +61 -0
  29. package/dist/node_modules/mariadb/lib/cmd/execute.js +338 -0
  30. package/dist/node_modules/mariadb/lib/cmd/handshake/auth/caching-sha2-password-auth.js +25 -62
  31. package/dist/node_modules/mariadb/lib/cmd/handshake/auth/clear-password-auth.js +39 -6
  32. package/dist/node_modules/mariadb/lib/cmd/handshake/auth/ed25519-password-auth.js +48 -16
  33. package/dist/node_modules/mariadb/lib/cmd/handshake/auth/handshake.js +198 -0
  34. package/dist/node_modules/mariadb/lib/cmd/handshake/{initial-handshake.js → auth/initial-handshake.js} +10 -8
  35. package/dist/node_modules/mariadb/lib/cmd/handshake/auth/native-password-auth.js +22 -9
  36. package/dist/node_modules/mariadb/lib/cmd/handshake/auth/pam-password-auth.js +9 -4
  37. package/dist/node_modules/mariadb/lib/cmd/handshake/auth/parsec-auth.js +115 -0
  38. package/dist/node_modules/mariadb/lib/cmd/handshake/auth/plugin-auth.js +12 -5
  39. package/dist/node_modules/mariadb/lib/cmd/handshake/auth/sha256-password-auth.js +44 -33
  40. package/dist/node_modules/mariadb/lib/cmd/handshake/authentication.js +335 -0
  41. package/dist/node_modules/mariadb/lib/cmd/handshake/client-capabilities.js +20 -19
  42. package/dist/node_modules/mariadb/lib/cmd/handshake/ssl-request.js +6 -3
  43. package/dist/node_modules/mariadb/lib/cmd/parser.js +861 -0
  44. package/dist/node_modules/mariadb/lib/cmd/ping.js +17 -18
  45. package/dist/node_modules/mariadb/lib/cmd/prepare.js +170 -0
  46. package/dist/node_modules/mariadb/lib/cmd/query.js +281 -144
  47. package/dist/node_modules/mariadb/lib/cmd/quit.js +9 -6
  48. package/dist/node_modules/mariadb/lib/cmd/reset.js +15 -19
  49. package/dist/node_modules/mariadb/lib/cmd/stream.js +21 -6
  50. package/dist/node_modules/mariadb/lib/config/cluster-options.js +23 -0
  51. package/dist/node_modules/mariadb/lib/config/connection-options.js +196 -132
  52. package/dist/node_modules/mariadb/lib/config/pool-options.js +27 -19
  53. package/dist/node_modules/mariadb/lib/connection-callback.js +492 -120
  54. package/dist/node_modules/mariadb/lib/connection-promise.js +372 -0
  55. package/dist/node_modules/mariadb/lib/connection.js +1739 -1016
  56. package/dist/node_modules/mariadb/lib/const/capabilities.js +36 -30
  57. package/dist/node_modules/mariadb/lib/const/collations.js +972 -36
  58. package/dist/node_modules/mariadb/lib/const/connection_status.js +3 -0
  59. package/dist/node_modules/mariadb/lib/const/error-code.js +35 -11
  60. package/dist/node_modules/mariadb/lib/const/field-detail.js +3 -0
  61. package/dist/node_modules/mariadb/lib/const/field-type.js +7 -4
  62. package/dist/node_modules/mariadb/lib/const/server-status.js +4 -1
  63. package/dist/node_modules/mariadb/lib/const/state-change.js +3 -0
  64. package/dist/node_modules/mariadb/lib/filtered-cluster-callback.js +136 -0
  65. package/dist/node_modules/mariadb/lib/filtered-cluster.js +118 -0
  66. package/dist/node_modules/mariadb/lib/io/compression-input-stream.js +14 -13
  67. package/dist/node_modules/mariadb/lib/io/compression-output-stream.js +21 -18
  68. package/dist/node_modules/mariadb/lib/io/packet-input-stream.js +75 -64
  69. package/dist/node_modules/mariadb/lib/io/packet-node-encoded.js +13 -9
  70. package/dist/node_modules/mariadb/lib/io/packet-node-iconv.js +12 -10
  71. package/dist/node_modules/mariadb/lib/io/packet-output-stream.js +402 -134
  72. package/dist/node_modules/mariadb/lib/io/packet.js +287 -202
  73. package/dist/node_modules/mariadb/lib/lru-prepare-cache.js +84 -0
  74. package/dist/node_modules/mariadb/lib/misc/connection-information.js +15 -32
  75. package/dist/node_modules/mariadb/lib/misc/errors.js +68 -25
  76. package/dist/node_modules/mariadb/lib/misc/parse.js +207 -711
  77. package/dist/node_modules/mariadb/lib/misc/utils.js +34 -62
  78. package/dist/node_modules/mariadb/lib/pool-callback.js +213 -174
  79. package/dist/node_modules/mariadb/lib/pool-promise.js +228 -94
  80. package/dist/node_modules/mariadb/lib/pool.js +951 -0
  81. package/dist/node_modules/mariadb/package.json +1 -1
  82. package/dist/node_modules/mariadb/promise.js +1 -34
  83. package/dist/node_modules/mariadb/types/callback.d.ts +207 -0
  84. package/dist/node_modules/mariadb/types/index.d.ts +94 -674
  85. package/dist/node_modules/mariadb/types/share.d.ts +804 -0
  86. package/dist/node_modules/qs/package.json +1 -1
  87. package/dist/server/actions/apps.js +2 -2
  88. package/dist/server/app-lifecycle.d.ts +1 -1
  89. package/dist/server/app-lifecycle.js +4 -4
  90. package/dist/server/models/application.d.ts +1 -1
  91. package/package.json +7 -7
  92. package/server.d.ts +2 -2
  93. package/server.js +1 -1
  94. package/dist/node_modules/mariadb/lib/cmd/batch-rewrite.js +0 -372
  95. package/dist/node_modules/mariadb/lib/cmd/common-text-cmd.js +0 -427
  96. package/dist/node_modules/mariadb/lib/cmd/handshake/client-handshake-response.js +0 -126
  97. package/dist/node_modules/mariadb/lib/cmd/handshake/handshake.js +0 -292
  98. package/dist/node_modules/mariadb/lib/cmd/resultset.js +0 -607
  99. package/dist/node_modules/mariadb/lib/config/pool-cluster-options.js +0 -19
  100. package/dist/node_modules/mariadb/lib/filtered-pool-cluster.js +0 -81
  101. package/dist/node_modules/mariadb/lib/io/bulk-packet.js +0 -590
  102. package/dist/node_modules/mariadb/lib/io/rewrite-packet.js +0 -481
  103. package/dist/node_modules/mariadb/lib/pool-base.js +0 -611
  104. package/dist/node_modules/mariadb/lib/pool-cluster-callback.js +0 -66
  105. 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
- * Split query according to parameters (question mark).
15
- * Question mark in comment are not taken in account
30
+ * Search for question mark positions.
31
+ * Question marks in comment are not taken into account
16
32
  *
17
- * @returns {Array} query separated by parameters
33
+ * @returns {Array} question mark position
18
34
  */
19
- module.exports.splitQuery = function (sql) {
20
- let partList = [];
35
+ module.exports.splitQuery = function (query) {
36
+ let paramPositions = [];
21
37
  let state = State.Normal;
22
- let lastChar = '\0';
38
+ let lastChar = 0x00;
23
39
  let singleQuotes = false;
24
- let lastParameterPosition = 0;
25
- let idx = 0;
26
- let car = sql.charAt(idx++);
40
+ let currentChar;
27
41
 
28
- while (car !== '') {
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
- !((car === "'" && singleQuotes) || (car === '"' && !singleQuotes))
47
+ !((currentChar === QUOTE_BYTE && singleQuotes) || (currentChar === DBL_QUOTE_BYTE && !singleQuotes))
32
48
  ) {
33
49
  state = State.String;
34
- car = sql.charAt(idx++);
50
+ lastChar = currentChar;
35
51
  continue;
36
52
  }
37
-
38
- switch (car) {
39
- case '*':
40
- if (state === State.Normal && lastChar == '/') state = State.SlashStarComment;
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 == '*') state = State.Normal;
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) state = State.EOLComment;
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 '\n':
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 && !singleQuotes) {
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 && singleQuotes) {
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) state = State.Escape;
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
- partList.push(sql.substring(lastParameterPosition, idx - 1));
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 = car;
104
-
105
- car = sql.charAt(idx++);
124
+ lastChar = currentChar;
106
125
  }
107
- if (lastParameterPosition === 0) {
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 sql sql with placeholders
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 {{parts: Array, values: Array}}
136
+ * @returns {{paramPositions: Array, values: Array}}
124
137
  */
125
- module.exports.splitQueryPlaceholder = function (sql, info, initialValues, displaySql) {
126
- let partList = [];
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 = '\0';
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
- let isInParenthesis = 0;
291
- let isFirstChar = true;
292
- let isInsert = false;
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 === "'" && singleQuotes) || (car === '"' && !singleQuotes))
152
+ !((car === QUOTE_BYTE && singleQuotes) || (car === DBL_QUOTE_BYTE && !singleQuotes))
303
153
  ) {
304
154
  state = State.String;
305
- car = sql.charAt(idx++);
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 '\n':
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 && !singleQuotes) {
197
+ } else if (state === State.Escape) {
347
198
  state = State.String;
348
199
  }
349
200
  break;
350
- case ';':
351
- if (state === State.Normal) {
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 && singleQuotes) {
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
- hasParam = true;
376
- let part = sql.substring(lastParameterPosition, idx - 1);
377
- lastParameterPosition = idx;
220
+ const key = Object.keys(placeholderValues)[0];
221
+ values.push(placeholderValues[key]);
222
+ delete placeholderValues[key];
378
223
 
379
- if (preValuePart1 === null) {
380
- preValuePart1 = part;
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
- case 's':
403
- case 'S':
404
- if (
405
- state === State.Normal &&
406
- postValuePart === null &&
407
- sql.length > idx + 5 &&
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
- break;
239
+ j++;
421
240
  }
422
- if (sql.charAt(idx + 5) > ' ' && '();><=-+,'.indexOf(sql.charAt(idx + 5)) === -1) {
423
- break;
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
- //SELECT queries, INSERT FROM SELECT not rewritable
427
- reWritablePrepare = false;
428
- }
429
- break;
430
- case 'v':
431
- case 'V':
432
- if (
433
- state === State.Normal &&
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
- default:
488
- if (state === State.Normal && isFirstChar && car > ' ') {
489
- if (
490
- (car === 'I' || car === 'i') &&
491
- sql.length > idx + 6 &&
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, info, initialValues, displaySql) {
280
+ module.exports.searchPlaceholder = function (sql) {
551
281
  let sqlPlaceHolder = '';
552
- const rowNumber = initialValues.length;
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 == '/') state = State.SlashStarComment;
303
+ if (state === State.Normal && lastChar === '/') state = State.SlashStarComment;
579
304
  break;
580
305
 
581
306
  case '/':
582
- if (state === State.SlashStarComment && lastChar == '*') state = State.Normal;
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
- for (let i = 0; i < rowNumber; i++) {
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, values: values };
388
+ return { sql: sqlPlaceHolder, placeHolderIndex: placeHolderIndex };
671
389
  };
672
390
 
673
391
  /**
674
- * Split query according to named parameters.
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
- * @returns {JSON} query separated by parameters
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.splitRewritableNamedParameterQuery = function (sql, initialValues) {
701
- let reWritablePrepare = true;
702
- let multipleQueriesPrepare = true;
703
- let partList = [];
704
- let values = new Array(initialValues.length);
705
- for (let i = 0; i < values.length; i++) values[i] = [];
706
- let lastChar = '\0';
707
-
708
- let lastParameterPosition = 0;
709
-
710
- let preValuePart1 = null;
711
- let preValuePart2 = null;
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
- let singleQuotes = false;
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
- let isInParenthesis = 0;
717
- let isFirstChar = true;
718
- let isInsert = false;
719
- let semicolon = false;
720
- let hasParam = false;
721
- let placeholderName;
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 idx = 0;
725
- let car = sql.charAt(idx++);
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
- !((car === "'" && singleQuotes) || (car === '"' && !singleQuotes))
446
+ !((currByte === QUOTE_BYTE && singleQuotes) || (currByte === DBL_QUOTE_BYTE && !singleQuotes))
730
447
  ) {
731
448
  state = State.String;
732
- car = sql.charAt(idx++);
449
+ lastChar = currByte;
733
450
  continue;
734
451
  }
735
-
736
- switch (car) {
737
- case '*':
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 '\n':
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 && !singleQuotes) {
491
+ } else if (state === State.Escape) {
774
492
  state = State.String;
775
493
  }
776
494
  break;
777
- case ';':
778
- if (state === State.Normal) {
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 && singleQuotes) {
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
- let part = sql.substring(lastParameterPosition, idx - 1);
803
- placeholderName = '';
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 false;
528
+ return queries;
1033
529
  };