@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
@@ -0,0 +1,861 @@
1
+ // SPDX-License-Identifier: LGPL-2.1-or-later
2
+ // Copyright (c) 2015-2025 MariaDB Corporation Ab
3
+
4
+ 'use strict';
5
+
6
+ const Command = require('./command');
7
+ const ServerStatus = require('../const/server-status');
8
+ const ColumnDefinition = require('./column-definition');
9
+ const Errors = require('../misc/errors');
10
+ const fs = require('fs');
11
+ const Parse = require('../misc/parse');
12
+ const BinaryDecoder = require('./decoder/binary-decoder');
13
+ const TextDecoder = require('./decoder/text-decoder');
14
+ const OkPacket = require('./class/ok-packet');
15
+ const StateChange = require('../const/state-change');
16
+ const Collations = require('../const/collations');
17
+
18
+ // Set of field names that are reserved for internal use
19
+ const privateFields = new Set([
20
+ '__defineGetter__',
21
+ '__defineSetter__',
22
+ '__lookupGetter__',
23
+ '__lookupSetter__',
24
+ '__proto__'
25
+ ]);
26
+
27
+ /**
28
+ * Handle COM_QUERY / COM_STMT_EXECUTE results
29
+ * @see https://mariadb.com/kb/en/library/4-server-response-packets/
30
+ */
31
+ class Parser extends Command {
32
+ /**
33
+ * Create a new Parser instance
34
+ *
35
+ * @param {Function} resolve - Promise resolve function
36
+ * @param {Function} reject - Promise reject function
37
+ * @param {Object} connOpts - Connection options
38
+ * @param {Object} cmdParam - Command parameters
39
+ */
40
+ constructor(resolve, reject, connOpts, cmdParam) {
41
+ super(cmdParam, resolve, reject);
42
+ this._responseIndex = 0;
43
+ this._rows = [];
44
+ this.opts = cmdParam.opts ? Object.assign({}, connOpts, cmdParam.opts) : connOpts;
45
+ this.sql = cmdParam.sql;
46
+ this.initialValues = cmdParam.values;
47
+ this.canSkipMeta = false;
48
+ }
49
+
50
+ /**
51
+ * Read Query response packet.
52
+ * Packet can be:
53
+ * - a result-set
54
+ * - an ERR_Packet
55
+ * - an OK_Packet
56
+ * - LOCAL_INFILE Packet
57
+ *
58
+ * @param {Object} packet - Query response packet
59
+ * @param {Object} out - Output writer
60
+ * @param {Object} opts - Connection options
61
+ * @param {Object} info - Connection info
62
+ * @returns {Function|null} Next packet handler or null
63
+ */
64
+ readResponsePacket(packet, out, opts, info) {
65
+ switch (packet.peek()) {
66
+ case 0x00: // OK response
67
+ return this.readOKPacket(packet, out, opts, info);
68
+
69
+ case 0xff: // ERROR response
70
+ return this.handleErrorPacket(packet, info);
71
+
72
+ case 0xfb: // LOCAL INFILE response
73
+ return this.readLocalInfile(packet, out, opts, info);
74
+
75
+ default: // Result set
76
+ return this.readResultSet(packet, info);
77
+ }
78
+ }
79
+
80
+ /**
81
+ * Handle error packet
82
+ *
83
+ * @param {Object} packet - Error packet
84
+ * @param {Object} info - Connection info
85
+ * @returns {null} Always returns null
86
+ * @private
87
+ */
88
+ handleErrorPacket(packet, info) {
89
+ // In case of timeout, free accumulated rows
90
+ this._columns = null;
91
+
92
+ const err = packet.readError(info, this.opts.logParam ? this.displaySql() : this.sql, this.cmdParam.stack);
93
+
94
+ // Force in transaction status, since query will have created a transaction if autocommit is off
95
+ // Goal is to avoid unnecessary COMMIT/ROLLBACK
96
+ info.status |= ServerStatus.STATUS_IN_TRANS;
97
+
98
+ return this.throwError(err, info);
99
+ }
100
+
101
+ /**
102
+ * Read result-set packets
103
+ * @see https://mariadb.com/kb/en/library/resultset/
104
+ *
105
+ * @param {Object} packet - Column count packet
106
+ * @param {Object} info - Connection information
107
+ * @returns {Function} Next packet handler
108
+ */
109
+ readResultSet(packet, info) {
110
+ this._columnCount = packet.readUnsignedLength();
111
+
112
+ this._rows.push([]);
113
+ if (this.canSkipMeta && info.serverPermitSkipMeta && packet.readUInt8() === 0) {
114
+ // Command supports skipping meta
115
+ // Server permits it
116
+ // And tells that no columns follow, using prepare results
117
+ return this.handleSkippedMeta(info);
118
+ }
119
+
120
+ this._columns = [];
121
+ return (this.onPacketReceive = this.readColumn);
122
+ }
123
+
124
+ /**
125
+ * Handle skipped metadata case
126
+ *
127
+ * @param {Object} info - Connection information
128
+ * @returns {Function} Next packet handler
129
+ * @private
130
+ */
131
+ handleSkippedMeta(info) {
132
+ this._columns = this.prepare.columns;
133
+ this._columnCount = this._columns.length;
134
+ this.emit('fields', this._columns);
135
+ this.setParser();
136
+ return (this.onPacketReceive = info.eofDeprecated ? this.readResultSetRow : this.readIntermediateEOF);
137
+ }
138
+
139
+ /**
140
+ * Read OK_Packet
141
+ * @see https://mariadb.com/kb/en/library/ok_packet/
142
+ *
143
+ * @param {Object} packet - OK_Packet
144
+ * @param {Object} out - Output writer
145
+ * @param {Object} opts - Connection options
146
+ * @param {Object} info - Connection information
147
+ * @returns {Function|null} Next packet handler or null
148
+ */
149
+ readOKPacket(packet, out, opts, info) {
150
+ packet.skip(1); // Skip header
151
+
152
+ const affectedRows = packet.readUnsignedLength();
153
+
154
+ // Handle insertId based on options
155
+ let insertId = this.processInsertId(packet.readInsertId(), info);
156
+ info.status = packet.readUInt16();
157
+
158
+ const okPacket = new OkPacket(affectedRows, insertId, packet.readUInt16());
159
+ let mustRedirect = false;
160
+
161
+ // Process session state changes if present
162
+ if (info.status & ServerStatus.SESSION_STATE_CHANGED) {
163
+ mustRedirect = this.processSessionStateChanges(packet, info, opts);
164
+ }
165
+
166
+ // Handle streaming case
167
+ if (this.inStream) {
168
+ this.handleNewRows(okPacket);
169
+ }
170
+
171
+ // Handle redirection
172
+ if (mustRedirect) {
173
+ return null; // Redirection is handled asynchronously
174
+ }
175
+
176
+ if (
177
+ info.redirectRequest &&
178
+ (info.status & ServerStatus.STATUS_IN_TRANS) === 0 &&
179
+ (info.status & ServerStatus.MORE_RESULTS_EXISTS) === 0
180
+ ) {
181
+ info.redirect(info.redirectRequest, this.okPacketSuccess.bind(this, okPacket, info));
182
+ } else {
183
+ this.okPacketSuccess(okPacket, info);
184
+ }
185
+
186
+ return null;
187
+ }
188
+
189
+ /**
190
+ * Process insertId based on connection options
191
+ *
192
+ * @param {BigInt} insertId - Raw insertId from packet
193
+ * @param {Object} info - Connection info
194
+ * @returns {BigInt|Number|String} Processed insertId
195
+ * @private
196
+ */
197
+ processInsertId(insertId, info) {
198
+ if (this.opts.supportBigNumbers || this.opts.insertIdAsNumber) {
199
+ if (this.opts.insertIdAsNumber && this.opts.checkNumberRange && !Number.isSafeInteger(Number(insertId))) {
200
+ this.onPacketReceive = info.status & ServerStatus.MORE_RESULTS_EXISTS ? this.readResponsePacket : null;
201
+ this.throwUnexpectedError(
202
+ `last insert id value ${insertId} can't safely be converted to number`,
203
+ false,
204
+ info,
205
+ '42000',
206
+ Errors.ER_PARSING_PRECISION
207
+ );
208
+ return insertId;
209
+ }
210
+
211
+ if (this.opts.supportBigNumbers && (this.opts.bigNumberStrings || !Number.isSafeInteger(Number(insertId)))) {
212
+ return insertId.toString();
213
+ } else {
214
+ return Number(insertId);
215
+ }
216
+ }
217
+
218
+ return insertId;
219
+ }
220
+
221
+ /**
222
+ * Process session state changes
223
+ *
224
+ * @param {Object} packet - Packet containing session state changes
225
+ * @param {Object} info - Connection information
226
+ * @param {Object} opts - Connection options
227
+ * @returns {Boolean} True if redirection is needed
228
+ * @private
229
+ */
230
+ processSessionStateChanges(packet, info, opts) {
231
+ let mustRedirect = false;
232
+ packet.skipLengthCodedNumber();
233
+
234
+ while (packet.remaining()) {
235
+ const len = packet.readUnsignedLength();
236
+ if (len > 0) {
237
+ const subPacket = packet.subPacketLengthEncoded(len);
238
+ while (subPacket.remaining()) {
239
+ const type = subPacket.readUInt8();
240
+ switch (type) {
241
+ case StateChange.SESSION_TRACK_SYSTEM_VARIABLES:
242
+ mustRedirect = this.processSystemVariables(subPacket, info, opts) || mustRedirect;
243
+ break;
244
+
245
+ case StateChange.SESSION_TRACK_SCHEMA:
246
+ info.database = this.readSchemaChange(subPacket);
247
+ break;
248
+ }
249
+ }
250
+ }
251
+ }
252
+
253
+ return mustRedirect;
254
+ }
255
+
256
+ /**
257
+ * Process system variables changes
258
+ *
259
+ * @param {Object} subPacket - Packet containing system variables
260
+ * @param {Object} info - Connection information
261
+ * @param {Object} opts - Connection options
262
+ * @returns {Boolean} True if redirection is needed
263
+ * @private
264
+ */
265
+ processSystemVariables(subPacket, info, opts) {
266
+ let mustRedirect = false;
267
+ let subSubPacket;
268
+
269
+ do {
270
+ subSubPacket = subPacket.subPacketLengthEncoded(subPacket.readUnsignedLength());
271
+ const variable = subSubPacket.readStringLengthEncoded();
272
+ const value = subSubPacket.readStringLengthEncoded();
273
+
274
+ switch (variable) {
275
+ case 'character_set_client':
276
+ info.collation = Collations.fromCharset(value);
277
+ if (info.collation === undefined) {
278
+ this.throwError(new Error(`unknown charset: '${value}'`), info);
279
+ return false;
280
+ }
281
+ opts.emit('collation', info.collation);
282
+ break;
283
+
284
+ case 'redirect_url':
285
+ if (value !== '') {
286
+ mustRedirect = true;
287
+ info.redirect(value, this.okPacketSuccess.bind(this, this.okPacket, info));
288
+ }
289
+ break;
290
+
291
+ case 'connection_id':
292
+ info.threadId = parseInt(value);
293
+ break;
294
+ }
295
+ } while (subSubPacket.remaining() > 0);
296
+
297
+ return mustRedirect;
298
+ }
299
+
300
+ /**
301
+ * Read schema change from packet
302
+ *
303
+ * @param {Object} subPacket - Packet containing schema change
304
+ * @returns {String} New schema name
305
+ * @private
306
+ */
307
+ readSchemaChange(subPacket) {
308
+ const subSubPacket = subPacket.subPacketLengthEncoded(subPacket.readUnsignedLength());
309
+ return subSubPacket.readStringLengthEncoded();
310
+ }
311
+
312
+ /**
313
+ * Handle OK packet success
314
+ *
315
+ * @param {Object} okPacket - OK packet
316
+ * @param {Object} info - Connection information
317
+ */
318
+ okPacketSuccess(okPacket, info) {
319
+ if (this._responseIndex === 0) {
320
+ // Fast path for standard single result
321
+ if (info.status & ServerStatus.MORE_RESULTS_EXISTS) {
322
+ this._rows.push(okPacket);
323
+ this._responseIndex++;
324
+ return (this.onPacketReceive = this.readResponsePacket);
325
+ }
326
+ return this.success(this.opts.metaAsArray ? [okPacket, []] : okPacket);
327
+ }
328
+
329
+ this._rows.push(okPacket);
330
+
331
+ if (info.status & ServerStatus.MORE_RESULTS_EXISTS) {
332
+ this._responseIndex++;
333
+ return (this.onPacketReceive = this.readResponsePacket);
334
+ }
335
+
336
+ if (this.opts.metaAsArray) {
337
+ if (!this._meta) {
338
+ this._meta = new Array(this._responseIndex);
339
+ }
340
+ this._meta[this._responseIndex] = null;
341
+ this.success([this._rows, this._meta]);
342
+ } else {
343
+ this.success(this._rows);
344
+ }
345
+ }
346
+
347
+ /**
348
+ * Complete query with success
349
+ *
350
+ * @param {*} val - Result value
351
+ */
352
+ success(val) {
353
+ this.successEnd(val);
354
+ this._columns = null;
355
+ this._rows = [];
356
+ }
357
+
358
+ /**
359
+ * Read column information metadata
360
+ * @see https://mariadb.com/kb/en/library/resultset/#column-definition-packet
361
+ *
362
+ * @param {Object} packet - Column definition packet
363
+ * @param {Object} out - Output writer
364
+ * @param {Object} opts - Connection options
365
+ * @param {Object} info - Connection information
366
+ */
367
+ readColumn(packet, out, opts, info) {
368
+ this._columns.push(new ColumnDefinition(packet, info, this.opts.rowsAsArray));
369
+
370
+ // Last column
371
+ if (this._columns.length === this._columnCount) {
372
+ this.setParser();
373
+
374
+ if (this.canSkipMeta && info.serverPermitSkipMeta && this.prepare != null) {
375
+ // Server can skip meta, but have force sending it.
376
+ // Metadata have changed, updating prepare result accordingly
377
+ if (this._responseIndex === 0) this.prepare.columns = this._columns;
378
+ }
379
+
380
+ this.emit('fields', this._columns);
381
+ this.onPacketReceive = info.eofDeprecated ? this.readResultSetRow : this.readIntermediateEOF;
382
+ }
383
+ }
384
+
385
+ /**
386
+ * Set up row parsers based on column information
387
+ */
388
+ setParser() {
389
+ this._parseFunction = new Array(this._columnCount);
390
+
391
+ if (this.opts.typeCast) {
392
+ for (let i = 0; i < this._columnCount; i++) {
393
+ this._parseFunction[i] = this.readCastValue.bind(this, this._columns[i]);
394
+ }
395
+ } else {
396
+ const dataParser = this.binary ? BinaryDecoder.parser : TextDecoder.parser;
397
+ for (let i = 0; i < this._columnCount; i++) {
398
+ this._parseFunction[i] = dataParser(this._columns[i], this.opts);
399
+ }
400
+ }
401
+
402
+ if (this.opts.rowsAsArray) {
403
+ this.parseRow = this.parseRowAsArray;
404
+ } else {
405
+ this.tableHeader = new Array(this._columnCount);
406
+ this.parseRow = this.binary ? this.parseRowStdBinary : this.parseRowStdText;
407
+
408
+ if (this.opts.nestTables) {
409
+ this.configureNestedTables();
410
+ } else {
411
+ for (let i = 0; i < this._columnCount; i++) {
412
+ this.tableHeader[i] = this._columns[i].name();
413
+ }
414
+ this.checkDuplicates();
415
+ }
416
+ }
417
+ }
418
+
419
+ /**
420
+ * Configure nested tables format
421
+ * @private
422
+ */
423
+ configureNestedTables() {
424
+ if (typeof this.opts.nestTables === 'string') {
425
+ for (let i = 0; i < this._columnCount; i++) {
426
+ this.tableHeader[i] = this._columns[i].table() + this.opts.nestTables + this._columns[i].name();
427
+ }
428
+ this.checkDuplicates();
429
+ } else if (this.opts.nestTables === true) {
430
+ this.parseRow = this.parseRowNested;
431
+ for (let i = 0; i < this._columnCount; i++) {
432
+ this.tableHeader[i] = [this._columns[i].table(), this._columns[i].name()];
433
+ }
434
+ this.checkNestTablesDuplicatesAndPrivateFields();
435
+ }
436
+ }
437
+
438
+ /**
439
+ * Check for duplicate column names
440
+ */
441
+ checkDuplicates() {
442
+ if (this.opts.checkDuplicate) {
443
+ for (let i = 0; i < this._columnCount; i++) {
444
+ if (this.tableHeader.indexOf(this.tableHeader[i], i + 1) > 0) {
445
+ const dupes = this.tableHeader.reduce(
446
+ (acc, v, i, arr) => (arr.indexOf(v) !== i && acc.indexOf(v) === -1 ? acc.concat(v) : acc),
447
+ []
448
+ );
449
+ this.throwUnexpectedError(
450
+ `Error in results, duplicate field name \`${dupes[0]}\`.\n(see option \`checkDuplicate\`)`,
451
+ false,
452
+ null,
453
+ '42000',
454
+ Errors.ER_DUPLICATE_FIELD
455
+ );
456
+ }
457
+ }
458
+ }
459
+ }
460
+
461
+ /**
462
+ * Check for duplicates and private fields in nested tables
463
+ */
464
+ checkNestTablesDuplicatesAndPrivateFields() {
465
+ if (this.opts.checkDuplicate) {
466
+ for (let i = 0; i < this._columnCount; i++) {
467
+ for (let j = 0; j < i; j++) {
468
+ if (this.tableHeader[j][0] === this.tableHeader[i][0] && this.tableHeader[j][1] === this.tableHeader[i][1]) {
469
+ this.throwUnexpectedError(
470
+ `Error in results, duplicate field name \`${this.tableHeader[i][0]}\`.\`${this.tableHeader[i][1]}\`\n(see option \`checkDuplicate\`)`,
471
+ false,
472
+ null,
473
+ '42000',
474
+ Errors.ER_DUPLICATE_FIELD
475
+ );
476
+ }
477
+ }
478
+ }
479
+ }
480
+
481
+ for (let i = 0; i < this._columnCount; i++) {
482
+ if (privateFields.has(this.tableHeader[i][0])) {
483
+ this.throwUnexpectedError(
484
+ `Use of \`${this.tableHeader[i][0]}\` is not permitted with option \`nestTables\``,
485
+ false,
486
+ null,
487
+ '42000',
488
+ Errors.ER_PRIVATE_FIELDS_USE
489
+ );
490
+
491
+ // Continue parsing results to keep connection state
492
+ // but without assigning possible dangerous value
493
+ this.parseRow = () => {
494
+ return {};
495
+ };
496
+ }
497
+ }
498
+ }
499
+
500
+ /**
501
+ * Read intermediate EOF
502
+ * Only for server before MariaDB 10.2 / MySQL 5.7 that doesn't have CLIENT_DEPRECATE_EOF capability
503
+ * @see https://mariadb.com/kb/en/library/eof_packet/
504
+ *
505
+ * @param {Object} packet - EOF Packet
506
+ * @param {Object} out - Output writer
507
+ * @param {Object} opts - Connection options
508
+ * @param {Object} info - Connection information
509
+ * @returns {Function|null} Next packet handler or null
510
+ */
511
+ readIntermediateEOF(packet, out, opts, info) {
512
+ if (packet.peek() !== 0xfe) {
513
+ return this.throwNewError('Error in protocol, expected EOF packet', true, info, '42000', Errors.ER_EOF_EXPECTED);
514
+ }
515
+
516
+ // Before MySQL 5.7.5, last EOF doesn't contain the good flag SERVER_MORE_RESULTS_EXISTS
517
+ // for OUT parameters. It must be checked here
518
+ // (5.7.5 does have the CLIENT_DEPRECATE_EOF capability, so this packet is not even sent)
519
+ packet.skip(3);
520
+ info.status = packet.readUInt16();
521
+ this.isOutParameter = info.status & ServerStatus.PS_OUT_PARAMS;
522
+ return (this.onPacketReceive = this.readResultSetRow);
523
+ }
524
+
525
+ /**
526
+ * Add new rows to the result set
527
+ *
528
+ * @param {Object} row - Row data
529
+ */
530
+ handleNewRows(row) {
531
+ this._rows[this._responseIndex].push(row);
532
+ }
533
+
534
+ /**
535
+ * Check if packet is result-set end = EOF of OK_Packet with EOF header according to CLIENT_DEPRECATE_EOF capability
536
+ * or a result-set row
537
+ *
538
+ * @param packet current packet
539
+ * @param out output writer
540
+ * @param opts connection options
541
+ * @param info connection information
542
+ * @returns {*}
543
+ */
544
+ readResultSetRow(packet, out, opts, info) {
545
+ if (packet.peek() >= 0xfe) {
546
+ if (packet.peek() === 0xff) {
547
+ //force in transaction status, since query will have created a transaction if autocommit is off
548
+ //goal is to avoid unnecessary COMMIT/ROLLBACK.
549
+ info.status |= ServerStatus.STATUS_IN_TRANS;
550
+ return this.throwError(
551
+ packet.readError(info, this.opts.logParam ? this.displaySql() : this.sql, this.cmdParam.err),
552
+ info
553
+ );
554
+ }
555
+
556
+ if ((!info.eofDeprecated && packet.length() < 13) || (info.eofDeprecated && packet.length() < 0xffffff)) {
557
+ if (!info.eofDeprecated) {
558
+ packet.skip(3);
559
+ info.status = packet.readUInt16();
560
+ } else {
561
+ packet.skip(1); //skip header
562
+ packet.skipLengthCodedNumber(); //skip update count
563
+ packet.skipLengthCodedNumber(); //skip insert id
564
+ info.status = packet.readUInt16();
565
+ }
566
+
567
+ if (
568
+ info.redirectRequest &&
569
+ (info.status & ServerStatus.STATUS_IN_TRANS) === 0 &&
570
+ (info.status & ServerStatus.MORE_RESULTS_EXISTS) === 0
571
+ ) {
572
+ info.redirect(info.redirectRequest, this.resultSetEndingPacketResult.bind(this, info));
573
+ } else {
574
+ this.resultSetEndingPacketResult(info);
575
+ }
576
+ return;
577
+ }
578
+ }
579
+
580
+ this.handleNewRows(this.parseRow(packet));
581
+ }
582
+
583
+ resultSetEndingPacketResult(info) {
584
+ if (this.opts.metaAsArray) {
585
+ //return promise object as array :
586
+ // example for SELECT 1 =>
587
+ // [
588
+ // [ {"1": 1} ], //rows
589
+ // [ColumnDefinition] //meta
590
+ // ]
591
+
592
+ if (info.status & ServerStatus.MORE_RESULTS_EXISTS || this.isOutParameter) {
593
+ if (!this._meta) this._meta = [];
594
+ this._meta[this._responseIndex] = this._columns;
595
+ this._responseIndex++;
596
+ return (this.onPacketReceive = this.readResponsePacket);
597
+ }
598
+ if (this._responseIndex === 0) {
599
+ this.success([this._rows[0], this._columns]);
600
+ } else {
601
+ if (!this._meta) this._meta = [];
602
+ this._meta[this._responseIndex] = this._columns;
603
+ this.success([this._rows, this._meta]);
604
+ }
605
+ } else {
606
+ //return promise object as rows that have meta property :
607
+ // example for SELECT 1 =>
608
+ // [
609
+ // {"1": 1},
610
+ // meta: [ColumnDefinition]
611
+ // ]
612
+ Object.defineProperty(this._rows[this._responseIndex], 'meta', {
613
+ value: this._columns,
614
+ writable: true,
615
+ enumerable: this.opts.metaEnumerable
616
+ });
617
+
618
+ if (info.status & ServerStatus.MORE_RESULTS_EXISTS || this.isOutParameter) {
619
+ this._responseIndex++;
620
+ return (this.onPacketReceive = this.readResponsePacket);
621
+ }
622
+ this.success(this._responseIndex === 0 ? this._rows[0] : this._rows);
623
+ }
624
+ }
625
+
626
+ /**
627
+ * Display current SQL with parameters (truncated if too big)
628
+ *
629
+ * @returns {string}
630
+ */
631
+ displaySql() {
632
+ if (this.opts && this.initialValues) {
633
+ if (this.sql.length > this.opts.debugLen) {
634
+ return this.sql.substring(0, this.opts.debugLen) + '...';
635
+ }
636
+
637
+ let sqlMsg = this.sql + ' - parameters:';
638
+ return Parser.logParameters(this.opts, sqlMsg, this.initialValues);
639
+ }
640
+ if (this.sql.length > this.opts.debugLen) {
641
+ return this.sql.substring(0, this.opts.debugLen) + '... - parameters:[]';
642
+ }
643
+ return this.sql + ' - parameters:[]';
644
+ }
645
+
646
+ static logParameters(opts, sqlMsg, values) {
647
+ if (opts.namedPlaceholders) {
648
+ sqlMsg += '{';
649
+ let first = true;
650
+ for (let key in values) {
651
+ if (first) {
652
+ first = false;
653
+ } else {
654
+ sqlMsg += ',';
655
+ }
656
+ sqlMsg += "'" + key + "':";
657
+ let param = values[key];
658
+ sqlMsg = Parser.logParam(sqlMsg, param);
659
+ if (sqlMsg.length > opts.debugLen) {
660
+ return sqlMsg.substring(0, opts.debugLen) + '...';
661
+ }
662
+ }
663
+ sqlMsg += '}';
664
+ } else {
665
+ sqlMsg += '[';
666
+ if (Array.isArray(values)) {
667
+ for (let i = 0; i < values.length; i++) {
668
+ if (i !== 0) sqlMsg += ',';
669
+ let param = values[i];
670
+ sqlMsg = Parser.logParam(sqlMsg, param);
671
+ if (sqlMsg.length > opts.debugLen) {
672
+ return sqlMsg.substring(0, opts.debugLen) + '...';
673
+ }
674
+ }
675
+ } else {
676
+ sqlMsg = Parser.logParam(sqlMsg, values);
677
+ if (sqlMsg.length > opts.debugLen) {
678
+ return sqlMsg.substring(0, opts.debugLen) + '...';
679
+ }
680
+ }
681
+ sqlMsg += ']';
682
+ }
683
+ return sqlMsg;
684
+ }
685
+
686
+ parseRowAsArray(packet) {
687
+ const row = new Array(this._columnCount);
688
+ const nullBitMap = this.binary ? BinaryDecoder.newRow(packet, this._columns) : null;
689
+ for (let i = 0; i < this._columnCount; i++) {
690
+ row[i] = this._parseFunction[i](packet, this.opts, this.unexpectedError, nullBitMap, i);
691
+ }
692
+ return row;
693
+ }
694
+
695
+ parseRowNested(packet) {
696
+ const row = {};
697
+ const nullBitMap = this.binary ? BinaryDecoder.newRow(packet, this._columns) : null;
698
+ for (let i = 0; i < this._columnCount; i++) {
699
+ if (!row[this.tableHeader[i][0]]) row[this.tableHeader[i][0]] = {};
700
+ row[this.tableHeader[i][0]][this.tableHeader[i][1]] = this._parseFunction[i](
701
+ packet,
702
+ this.opts,
703
+ this.unexpectedError,
704
+ nullBitMap,
705
+ i
706
+ );
707
+ }
708
+ return row;
709
+ }
710
+
711
+ parseRowStdText(packet) {
712
+ const row = {};
713
+ for (let i = 0; i < this._columnCount; i++) {
714
+ row[this.tableHeader[i]] = this._parseFunction[i](packet, this.opts, this.unexpectedError);
715
+ }
716
+ return row;
717
+ }
718
+
719
+ parseRowStdBinary(packet) {
720
+ const nullBitMap = BinaryDecoder.newRow(packet, this._columns);
721
+ const row = {};
722
+ for (let i = 0; i < this._columnCount; i++) {
723
+ row[this.tableHeader[i]] = this._parseFunction[i](packet, this.opts, this.unexpectedError, nullBitMap, i);
724
+ }
725
+ return row;
726
+ }
727
+
728
+ readCastValue(column, packet, opts, unexpectedError, nullBitmap, index) {
729
+ if (this.binary) {
730
+ BinaryDecoder.castWrapper(column, packet, opts, nullBitmap, index);
731
+ } else {
732
+ TextDecoder.castWrapper(column, packet, opts, nullBitmap, index);
733
+ }
734
+ const dataParser = this.binary ? BinaryDecoder.parser : TextDecoder.parser;
735
+ return opts.typeCast(column, dataParser(column, opts).bind(null, packet, opts, unexpectedError, nullBitmap, index));
736
+ }
737
+
738
+ readLocalInfile(packet, out, opts, info) {
739
+ packet.skip(1); //skip header
740
+ out.startPacket(this);
741
+
742
+ const fileName = packet.readStringRemaining();
743
+
744
+ if (!Parse.validateFileName(this.sql, this.initialValues, fileName)) {
745
+ out.writeEmptyPacket();
746
+ const error = Errors.createError(
747
+ "LOCAL INFILE wrong filename. '" +
748
+ fileName +
749
+ "' doesn't correspond to query " +
750
+ this.sql +
751
+ '. Query cancelled. Check for malicious server / proxy',
752
+ Errors.ER_LOCAL_INFILE_WRONG_FILENAME,
753
+ info,
754
+ 'HY000',
755
+ this.sql
756
+ );
757
+ process.nextTick(this.reject, error);
758
+ this.reject = null;
759
+ this.resolve = null;
760
+ return (this.onPacketReceive = this.readResponsePacket);
761
+ }
762
+
763
+ // this.sequenceNo = 2;
764
+ // this.compressSequenceNo = 2;
765
+ let stream;
766
+ try {
767
+ stream = this.opts.infileStreamFactory ? this.opts.infileStreamFactory(fileName) : fs.createReadStream(fileName);
768
+ } catch (e) {
769
+ out.writeEmptyPacket();
770
+ const error = Errors.createError(
771
+ `LOCAL INFILE infileStreamFactory failed`,
772
+ Errors.ER_LOCAL_INFILE_NOT_READABLE,
773
+ info,
774
+ '22000',
775
+ this.opts.logParam ? this.displaySql() : this.sql
776
+ );
777
+ error.cause = e;
778
+ process.nextTick(this.reject, error);
779
+ this.reject = null;
780
+ this.resolve = null;
781
+ return (this.onPacketReceive = this.readResponsePacket);
782
+ }
783
+
784
+ stream.on(
785
+ 'error',
786
+ function (err) {
787
+ out.writeEmptyPacket();
788
+ const error = Errors.createError(
789
+ `LOCAL INFILE command failed: ${err.message}`,
790
+ Errors.ER_LOCAL_INFILE_NOT_READABLE,
791
+ info,
792
+ '22000',
793
+ this.sql
794
+ );
795
+ process.nextTick(this.reject, error);
796
+ this.reject = null;
797
+ this.resolve = null;
798
+ }.bind(this)
799
+ );
800
+ stream.on('data', (chunk) => {
801
+ out.writeBuffer(chunk, 0, chunk.length);
802
+ });
803
+ stream.on('end', () => {
804
+ if (!out.isEmpty()) {
805
+ out.flushBuffer(false);
806
+ }
807
+ out.writeEmptyPacket();
808
+ });
809
+ this.onPacketReceive = this.readResponsePacket;
810
+ }
811
+
812
+ static logParam(sqlMsg, param) {
813
+ if (param == null) {
814
+ sqlMsg += param === undefined ? 'undefined' : 'null';
815
+ } else {
816
+ switch (param.constructor.name) {
817
+ case 'Buffer':
818
+ sqlMsg += '0x' + param.toString('hex', 0, Math.min(1024, param.length)) + '';
819
+ break;
820
+
821
+ case 'String':
822
+ sqlMsg += "'" + param + "'";
823
+ break;
824
+
825
+ case 'Date':
826
+ sqlMsg += getStringDate(param);
827
+ break;
828
+
829
+ case 'Object':
830
+ sqlMsg += JSON.stringify(param);
831
+ break;
832
+
833
+ default:
834
+ sqlMsg += param.toString();
835
+ }
836
+ }
837
+ return sqlMsg;
838
+ }
839
+ }
840
+
841
+ function getStringDate(param) {
842
+ return (
843
+ "'" +
844
+ ('00' + (param.getMonth() + 1)).slice(-2) +
845
+ '/' +
846
+ ('00' + param.getDate()).slice(-2) +
847
+ '/' +
848
+ param.getFullYear() +
849
+ ' ' +
850
+ ('00' + param.getHours()).slice(-2) +
851
+ ':' +
852
+ ('00' + param.getMinutes()).slice(-2) +
853
+ ':' +
854
+ ('00' + param.getSeconds()).slice(-2) +
855
+ '.' +
856
+ ('000' + param.getMilliseconds()).slice(-3) +
857
+ "'"
858
+ );
859
+ }
860
+
861
+ module.exports = Parser;