@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,166 +1,444 @@
1
+ // SPDX-License-Identifier: LGPL-2.1-or-later
2
+ // Copyright (c) 2015-2025 MariaDB Corporation Ab
3
+
1
4
  'use strict';
2
5
 
3
- const CommonBinary = require('./common-binary-cmd');
6
+ const Parser = require('./parser');
4
7
  const Errors = require('../misc/errors');
5
- const Parse = require('../misc/parse');
6
- const BulkPacket = require('../io/bulk-packet');
8
+ const BinaryEncoder = require('./encoder/binary-encoder');
9
+ const FieldType = require('../const/field-type');
10
+ const OkPacket = require('./class/ok-packet');
11
+ const Capabilities = require('../const/capabilities');
12
+ const ServerStatus = require('../const/server-status');
13
+
14
+ // GeoJSON types supported by MariaDB
15
+ const GEOJSON_TYPES = [
16
+ 'Point',
17
+ 'LineString',
18
+ 'Polygon',
19
+ 'MultiPoint',
20
+ 'MultiLineString',
21
+ 'MultiPolygon',
22
+ 'GeometryCollection'
23
+ ];
7
24
 
8
25
  /**
9
- * Protocol COM_STMT_BULK_EXECUTE
10
- * see : https://mariadb.com/kb/en/library/com_stmt_bulk_execute/
26
+ * Protocol COM_STMT_BULK_EXECUTE implementation
27
+ * Provides efficient batch operations for MariaDB servers >= 10.2.7
28
+ *
29
+ * @see https://mariadb.com/kb/en/library/com_stmt_bulk_execute/
11
30
  */
12
- class BatchBulk extends CommonBinary {
13
- constructor(resolve, reject, options, connOpts, sql, values) {
14
- super(resolve, reject, options, connOpts, sql, values);
15
- this.onPacketReceive = this.readPrepareResultPacket;
31
+ class BatchBulk extends Parser {
32
+ constructor(resolve, reject, connOpts, prepare, cmdParam) {
33
+ super(resolve, reject, connOpts, cmdParam);
34
+ this.cmdOpts = cmdParam.opts;
35
+ this.binary = true;
36
+ this.prepare = prepare;
37
+ this.canSkipMeta = true;
38
+ this.bulkPacketNo = 0;
39
+ this.sending = false;
40
+ this.firstError = null;
16
41
  }
17
42
 
18
43
  /**
19
- * Send COM_STMT_BULK_EXECUTE
44
+ * Initiates the batch operation
20
45
  *
21
- * @param out output writer
22
- * @param opts connection options
23
- * @param info connection information
46
+ * @param {Object} out - Output writer
47
+ * @param {Object} opts - Connection options
48
+ * @param {Object} info - Connection information
24
49
  */
25
50
  start(out, opts, info) {
26
- this.sending = true;
27
51
  this.info = info;
28
52
  this.values = this.initialValues;
29
53
 
30
- if (this.opts.timeout) {
31
- const err = Errors.createError(
32
- 'Cannot use timeout for Batch statement',
33
- this.sql,
34
- false,
35
- info,
36
- 'HY000',
37
- Errors.ER_TIMEOUT_NOT_SUPPORTED
38
- );
39
- this.emit('send_end');
40
- this.throwError(err, info);
41
- return;
54
+ // Batch operations don't support timeouts
55
+ if (this.cmdOpts && this.cmdOpts.timeout) {
56
+ return this.handleTimeoutError(info);
42
57
  }
43
58
 
44
- let questionMarkSql = this.sql;
45
- if (this.opts.namedPlaceholders) {
46
- const res = Parse.searchPlaceholder(
47
- this.sql,
48
- info,
49
- this.initialValues,
50
- this.displaySql.bind(this)
51
- );
52
- questionMarkSql = res.sql;
53
- this.values = res.values;
59
+ this.onPacketReceive = this.readResponsePacket;
60
+
61
+ // Process named placeholders if needed
62
+ if (this.opts.namedPlaceholders && this.prepare._placeHolderIndex) {
63
+ this.processNamedPlaceholders();
54
64
  }
55
65
 
56
- if (!this.validateParameters(info)) {
57
- this.sending = false;
58
- return;
66
+ // Validate parameters before proceeding
67
+ if (!this.validateParameters(info)) return;
68
+
69
+ // Send the bulk execute command
70
+ this.sendComStmtBulkExecute(out, opts, info);
71
+ }
72
+
73
+ /**
74
+ * Handle timeout error case
75
+ * @param {Object} info - Connection information
76
+ * @private
77
+ */
78
+ handleTimeoutError(info) {
79
+ this.bulkPacketNo = 1;
80
+ this.sending = false;
81
+ return this.sendCancelled('Cannot use timeout for Batch statement', Errors.ER_TIMEOUT_NOT_SUPPORTED);
82
+ }
83
+
84
+ /**
85
+ * Process named placeholders to positional parameters
86
+ * @private
87
+ */
88
+ processNamedPlaceholders() {
89
+ this.values = [];
90
+ if (!this.initialValues) return;
91
+
92
+ const placeHolderIndex = this.prepare._placeHolderIndex;
93
+ const paramCount = this.prepare.parameterCount;
94
+
95
+ for (let r = 0; r < this.initialValues.length; r++) {
96
+ const val = this.initialValues[r];
97
+ const newRow = new Array(paramCount);
98
+
99
+ for (let i = 0; i < placeHolderIndex.length; i++) {
100
+ newRow[i] = val[placeHolderIndex[i]];
101
+ }
102
+
103
+ this.values[r] = newRow;
59
104
  }
105
+ }
60
106
 
61
- //send COM_STMT_PREPARE command
62
- this.out = out;
63
- this.packet = new BulkPacket(this.opts, out, this.values[0]);
107
+ /**
108
+ * Determine parameter header types based on value types
109
+ *
110
+ * @param {Array} value - Parameter values
111
+ * @param {Number} parameterCount - Number of parameters
112
+ * @returns {Array} Array of parameter header types
113
+ */
114
+ parameterHeaderFromValue(value, parameterCount) {
115
+ const parameterHeaderType = new Array(parameterCount);
64
116
 
65
- out.startPacket(this);
66
- out.writeInt8(0x16);
67
- out.writeString(questionMarkSql);
68
- out.flushBuffer(true);
117
+ for (let i = 0; i < parameterCount; i++) {
118
+ const val = value[i];
69
119
 
70
- if (this.opts.pipelining) {
71
- out.startPacket(this);
72
- this.valueIdx = 0;
73
- this.sendQueries();
74
- } else {
75
- this.out = out;
120
+ if (val == null) {
121
+ parameterHeaderType[i] = FieldType.VAR_STRING;
122
+ continue;
123
+ }
124
+
125
+ const type = typeof val;
126
+
127
+ switch (type) {
128
+ case 'boolean':
129
+ parameterHeaderType[i] = FieldType.TINY;
130
+ break;
131
+
132
+ case 'bigint':
133
+ parameterHeaderType[i] = val >= 2n ** 63n ? FieldType.NEWDECIMAL : FieldType.BIGINT;
134
+ break;
135
+
136
+ case 'number':
137
+ if (Number.isInteger(val) && val >= -2147483648 && val < 2147483647) {
138
+ parameterHeaderType[i] = FieldType.INT;
139
+ } else {
140
+ parameterHeaderType[i] = FieldType.DOUBLE;
141
+ }
142
+ break;
143
+
144
+ case 'string':
145
+ parameterHeaderType[i] = FieldType.VAR_STRING;
146
+ break;
147
+
148
+ case 'object':
149
+ parameterHeaderType[i] = this.getObjectFieldType(val);
150
+ break;
151
+
152
+ default:
153
+ parameterHeaderType[i] = FieldType.BLOB;
154
+ }
76
155
  }
156
+
157
+ return parameterHeaderType;
77
158
  }
78
159
 
79
- sendQueries() {
80
- let flushed = false;
81
- while (!flushed && this.sending && this.valueIdx < this.values.length) {
82
- this.valueRow = this.values[this.valueIdx++];
83
-
84
- //********************************************
85
- // send params
86
- //********************************************
87
- const len = this.valueRow.length;
88
- for (let i = 0; i < len; i++) {
89
- const value = this.valueRow[i];
90
- if (value === null) {
91
- flushed = this.packet.writeInt8(0x01) || flushed;
92
- continue;
93
- }
160
+ /**
161
+ * Determine field type for object values
162
+ *
163
+ * @param {Object} val - Object value
164
+ * @returns {Number} Field type constant
165
+ * @private
166
+ */
167
+ getObjectFieldType(val) {
168
+ if (Object.prototype.toString.call(val) === '[object Date]') {
169
+ return FieldType.DATETIME;
170
+ }
94
171
 
95
- //********************************************
96
- // param has no stream. directly write in buffer
97
- //********************************************
98
- flushed = this.writeParam(this.packet, value, this.opts, this.info) || flushed;
172
+ if (Buffer.isBuffer(val)) {
173
+ return FieldType.BLOB;
174
+ }
175
+
176
+ if (typeof val.toSqlString === 'function') {
177
+ return FieldType.VAR_STRING;
178
+ }
179
+
180
+ if (val.type != null && GEOJSON_TYPES.includes(val.type)) {
181
+ return FieldType.BLOB;
182
+ }
183
+
184
+ return FieldType.VAR_STRING;
185
+ }
186
+
187
+ /**
188
+ * Check if current value has same header as set in initial BULK header
189
+ *
190
+ * @param {Array} parameterHeaderType - Current header types
191
+ * @param {Array} value - Current values
192
+ * @param {Number} parameterCount - Number of parameters
193
+ * @returns {Boolean} True if headers are identical
194
+ */
195
+ checkSameHeader(parameterHeaderType, value, parameterCount) {
196
+ for (let i = 0; i < parameterCount; i++) {
197
+ const val = value[i];
198
+ if (val == null) continue;
199
+
200
+ const type = typeof val;
201
+
202
+ switch (type) {
203
+ case 'boolean':
204
+ if (parameterHeaderType[i] !== FieldType.TINY) return false;
205
+ break;
206
+
207
+ case 'bigint':
208
+ if (val >= 2n ** 63n) {
209
+ if (parameterHeaderType[i] !== FieldType.VAR_STRING) return false;
210
+ } else {
211
+ if (parameterHeaderType[i] !== FieldType.BIGINT) return false;
212
+ }
213
+ break;
214
+
215
+ case 'number':
216
+ if (Number.isInteger(val) && val >= -2147483648 && val < 2147483647) {
217
+ if (parameterHeaderType[i] !== FieldType.INT) return false;
218
+ } else {
219
+ if (parameterHeaderType[i] !== FieldType.DOUBLE) return false;
220
+ }
221
+ break;
222
+
223
+ case 'string':
224
+ if (parameterHeaderType[i] !== FieldType.VAR_STRING) return false;
225
+ break;
226
+
227
+ case 'object':
228
+ if (!this.checkObjectHeaderType(val, parameterHeaderType[i])) {
229
+ return false;
230
+ }
231
+ break;
232
+
233
+ default:
234
+ if (parameterHeaderType[i] !== FieldType.BLOB) return false;
99
235
  }
100
- const last = this.valueIdx === this.values.length;
101
- flushed = this.packet.mark(last, last ? null : this.values[this.valueIdx]) || flushed;
102
236
  }
103
237
 
104
- if (this.valueIdx < this.values.length && !this.packet.haveErrorResponse) {
105
- //there is still data to send
106
- setImmediate(this.sendQueries.bind(this));
107
- } else {
108
- if (this.sending && this.valueIdx === this.values.length) this.emit('send_end');
109
- this.sending = false;
238
+ return true;
239
+ }
240
+
241
+ /**
242
+ * Check if object value matches expected header type
243
+ *
244
+ * @param {Object} val - Object value
245
+ * @param {Number} headerType - Expected header type
246
+ * @returns {Boolean} True if types match
247
+ * @private
248
+ */
249
+ checkObjectHeaderType(val, headerType) {
250
+ if (Object.prototype.toString.call(val) === '[object Date]') {
251
+ return headerType === FieldType.TIMESTAMP;
252
+ }
253
+
254
+ if (Buffer.isBuffer(val)) {
255
+ return headerType === FieldType.BLOB;
110
256
  }
257
+
258
+ if (typeof val.toSqlString === 'function') {
259
+ return headerType === FieldType.VAR_STRING;
260
+ }
261
+
262
+ if (val.type != null && GEOJSON_TYPES.includes(val.type)) {
263
+ return headerType === FieldType.BLOB;
264
+ }
265
+
266
+ return headerType === FieldType.VAR_STRING;
111
267
  }
112
268
 
113
- displaySql() {
114
- if (this.opts && this.initialValues) {
115
- if (this.sql.length > this.opts.debugLen) {
116
- return this.sql.substring(0, this.opts.debugLen) + '...';
269
+ /**
270
+ * Send a COM_STMT_BULK_EXECUTE command
271
+ *
272
+ * @param {Object} out - Output packet writer
273
+ * @param {Object} opts - Connection options
274
+ * @param {Object} info - Connection information
275
+ */
276
+ sendComStmtBulkExecute(out, opts, info) {
277
+ if (opts.logger.query) {
278
+ opts.logger.query(`BULK: (${this.prepare.id}) sql: ${opts.logParam ? this.displaySql() : this.sql}`);
279
+ }
280
+
281
+ const parameterCount = this.prepare.parameterCount;
282
+ this.rowIdx = 0;
283
+ this.vals = this.values[this.rowIdx++];
284
+ let parameterHeaderType = this.parameterHeaderFromValue(this.vals, parameterCount);
285
+ let lastCmdData = null;
286
+ this.bulkPacketNo = 0;
287
+ this.sending = true;
288
+
289
+ // Main processing loop for batching parameters
290
+ main_loop: while (true) {
291
+ this.bulkPacketNo++;
292
+ out.startPacket(this);
293
+ out.writeInt8(0xfa); // COM_STMT_BULK_EXECUTE
294
+ out.writeInt32(this.prepare.id); // Statement id
295
+
296
+ // Set flags: SEND_TYPES_TO_SERVER + SEND_UNIT_RESULTS if possible
297
+ this.useUnitResult = (info.clientCapabilities & Capabilities.BULK_UNIT_RESULTS) > 0;
298
+ out.writeInt16(this.useUnitResult ? 192 : 128);
299
+
300
+ // Write parameter header types
301
+ for (let i = 0; i < parameterCount; i++) {
302
+ out.writeInt16(parameterHeaderType[i]);
117
303
  }
118
304
 
119
- let sqlMsg = this.sql + ' - parameters:';
120
- sqlMsg += '[';
121
- for (let i = 0; i < this.initialValues.length; i++) {
122
- if (i !== 0) sqlMsg += ',';
123
- let param = this.initialValues[i];
124
- sqlMsg = this.logParameters(sqlMsg, param);
125
- if (sqlMsg.length > this.opts.debugLen) {
126
- sqlMsg = sqlMsg.substr(0, this.opts.debugLen) + '...';
305
+ // Handle leftover data from previous packet
306
+ if (lastCmdData != null) {
307
+ const err = out.checkMaxAllowedLength(lastCmdData.length, info);
308
+ if (err) {
309
+ this.sending = false;
310
+ this.throwError(err, info);
311
+ return;
312
+ }
313
+
314
+ out.writeBuffer(lastCmdData, 0, lastCmdData.length);
315
+ out.mark();
316
+ lastCmdData = null;
317
+
318
+ if (this.rowIdx >= this.values.length) {
319
+ break;
320
+ }
321
+
322
+ this.vals = this.values[this.rowIdx++];
323
+ }
324
+
325
+ parameter_loop: while (true) {
326
+ // Write each parameter value
327
+ for (let i = 0; i < parameterCount; i++) {
328
+ const param = this.vals[i];
329
+
330
+ if (param != null) {
331
+ // Special handling for GeoJSON
332
+ if (param.type != null && GEOJSON_TYPES.includes(param.type)) {
333
+ this.writeGeoJSONParam(out, param, info);
334
+ } else {
335
+ out.writeInt8(0x00); // value follows
336
+ BinaryEncoder.writeParam(out, param, this.opts, info);
337
+ }
338
+ } else {
339
+ out.writeInt8(0x01); // value is null
340
+ }
341
+ }
342
+
343
+ // Buffer management for packet boundaries
344
+ if (out.isMarked() && (out.hasDataAfterMark() || out.bufIsAfterMaxPacketLength())) {
345
+ // Packet length was ok at last mark, but won't be with new data
346
+ out.flushBufferStopAtMark();
347
+ out.mark();
348
+ lastCmdData = out.resetMark();
349
+ break;
350
+ }
351
+
352
+ out.mark();
353
+
354
+ if (out.hasDataAfterMark()) {
355
+ // Flush has been done
356
+ lastCmdData = out.resetMark();
127
357
  break;
128
358
  }
359
+
360
+ if (this.rowIdx >= this.values.length) {
361
+ break main_loop;
362
+ }
363
+
364
+ this.vals = this.values[this.rowIdx++];
365
+
366
+ // Check if parameter types have changed
367
+ if (!this.checkSameHeader(parameterHeaderType, this.vals, parameterCount)) {
368
+ out.flush();
369
+ // Reset header type for new packet
370
+ parameterHeaderType = this.parameterHeaderFromValue(this.vals, parameterCount);
371
+ break parameter_loop;
372
+ }
129
373
  }
130
- sqlMsg += ']';
131
- return sqlMsg;
132
374
  }
133
- return this.sql + ' - parameters:[]';
375
+
376
+ out.flush();
377
+ this.sending = false;
378
+ this.emit('send_end');
134
379
  }
135
380
 
136
- success(val) {
137
- this.packet.waitingResponseNo--;
381
+ /**
382
+ * Write GeoJSON parameter to output buffer
383
+ *
384
+ * @param {Object} out - Output buffer
385
+ * @param {Object} param - GeoJSON parameter
386
+ * @param {Object} info - connection info data
387
+ * @private
388
+ */
389
+ writeGeoJSONParam(out, param, info) {
390
+ const geoBuff = BinaryEncoder.getBufferFromGeometryValue(param);
138
391
 
139
- if (!this.opts.pipelining && this.packet.statementId === -1) {
140
- this.packet.statementId = this.statementId;
141
- this.out.startPacket(this);
142
- this.valueIdx = 0;
143
- this.sendQueries();
144
- this._responseIndex++;
145
- this.onPacketReceive = this.readResponsePacket;
146
- return;
392
+ if (geoBuff == null) {
393
+ out.writeInt8(0x01); // value is null
394
+ } else {
395
+ out.writeInt8(0x00); // value follows
396
+ const paramBuff = Buffer.concat([
397
+ Buffer.from([0, 0, 0, 0]), // SRID
398
+ geoBuff // WKB
399
+ ]);
400
+ BinaryEncoder.writeParam(out, paramBuff, this.opts, info);
401
+ }
402
+ }
403
+
404
+ /**
405
+ * Format SQL with parameters for logging
406
+ *
407
+ * @returns {String} Formatted SQL string
408
+ */
409
+ displaySql() {
410
+ if (this.sql.length > this.opts.debugLen) {
411
+ return this.sql.substring(0, this.opts.debugLen) + '...';
147
412
  }
148
413
 
149
- if (!this.sending && this.packet.waitingResponseNo === 0) {
150
- //send COM_STMT_CLOSE packet
151
- if (!this.firstError || !this.firstError.fatal) {
152
- this.sequenceNo = -1;
153
- this.compressSequenceNo = -1;
154
- this.out.startPacket(this);
155
- this.out.writeInt8(0x19);
156
- this.out.writeInt32(this.statementId);
157
- this.out.flushBuffer(true);
414
+ let sqlMsg = this.sql + ' - parameters:[';
415
+
416
+ for (let i = 0; i < this.initialValues.length; i++) {
417
+ if (i !== 0) sqlMsg += ',';
418
+ let param = this.initialValues[i];
419
+ sqlMsg = Parser.logParameters(this.opts, sqlMsg, param);
420
+
421
+ if (sqlMsg.length > this.opts.debugLen) {
422
+ return sqlMsg.substring(0, this.opts.debugLen) + '...';
158
423
  }
159
- this.sending = false;
160
- this.emit('send_end');
424
+ }
425
+
426
+ sqlMsg += ']';
427
+ return sqlMsg;
428
+ }
161
429
 
162
- if (this.packet.haveErrorResponse) {
163
- this.packet = null;
430
+ /**
431
+ * Process successful query execution
432
+ *
433
+ * @param {Object} initVal - Query result
434
+ */
435
+ success(initVal) {
436
+ this.bulkPacketNo--;
437
+
438
+ if (!this.sending && this.bulkPacketNo === 0) {
439
+ this.packet = null;
440
+
441
+ if (this.firstError) {
164
442
  this.resolve = null;
165
443
  this.onPacketReceive = null;
166
444
  this._columns = null;
@@ -169,105 +447,226 @@ class BatchBulk extends CommonBinary {
169
447
  this.reject = null;
170
448
  this.emit('end', this.firstError);
171
449
  } else {
172
- this.packet = null;
173
- let totalAffectedRows = 0;
174
- this._rows.forEach((row) => {
175
- totalAffectedRows += row.affectedRows;
450
+ this.processResults();
451
+ }
452
+ return;
453
+ }
454
+
455
+ if (!this.firstError) {
456
+ this._responseIndex++;
457
+ this.onPacketReceive = this.readResponsePacket;
458
+ }
459
+ }
460
+
461
+ /**
462
+ * Process successful results based on result type
463
+ * @private
464
+ */
465
+ processResults() {
466
+ if (this._rows[0] && this._rows[0][0] && this._rows[0][0]['Affected_rows'] !== undefined) {
467
+ this.processUnitResults();
468
+ } else if (
469
+ this._rows[0].affectedRows !== undefined &&
470
+ !(this.opts.fullResult === undefined || this.opts.fullResult === true)
471
+ ) {
472
+ this.processAggregatedResults();
473
+ } else {
474
+ this.processRowResults();
475
+ }
476
+
477
+ this._columns = null;
478
+ this._rows = null;
479
+ }
480
+
481
+ /**
482
+ * Process unit results (for bulk operations with unit results)
483
+ * @private
484
+ */
485
+ processUnitResults() {
486
+ if (this.opts.fullResult === undefined || this.opts.fullResult === true) {
487
+ const rs = [];
488
+ this._rows.forEach((row) => {
489
+ row.forEach((unitRow) => {
490
+ rs.push(new OkPacket(Number(unitRow['Affected_rows']), BigInt(unitRow['Id']), 0));
176
491
  });
492
+ });
493
+ this.successEnd(this.opts.metaAsArray ? [rs, []] : rs);
494
+ } else {
495
+ let totalAffectedRows = 0;
496
+ this._rows.forEach((row) => {
497
+ row.forEach((unitRow) => {
498
+ totalAffectedRows += Number(unitRow['Affected_rows']);
499
+ });
500
+ });
501
+ const rs = new OkPacket(totalAffectedRows, BigInt(this._rows[0][0]['Id']), 0);
502
+ this.successEnd(this.opts.metaAsArray ? [rs, []] : rs);
503
+ }
504
+ }
177
505
 
178
- const rs = {
179
- affectedRows: totalAffectedRows,
180
- insertId: this._rows[0].insertId,
181
- warningStatus: this._rows[this._rows.length - 1].warningStatus
182
- };
506
+ /**
507
+ * Process aggregated results (for non-fullResult mode)
508
+ * @private
509
+ */
510
+ processAggregatedResults() {
511
+ let totalAffectedRows = 0;
512
+ this._rows.forEach((row) => {
513
+ totalAffectedRows += row.affectedRows;
514
+ });
515
+
516
+ const rs = new OkPacket(totalAffectedRows, this._rows[0].insertId, this._rows[this._rows.length - 1].warningStatus);
517
+ this.successEnd(this.opts.metaAsArray ? [rs, []] : rs);
518
+ }
519
+
520
+ /**
521
+ * Process row results (for SELECT queries)
522
+ * @private
523
+ */
524
+ processRowResults() {
525
+ if (this._rows.length === 1) {
526
+ this.successEnd(this.opts.metaAsArray ? [this._rows[0], this._columns] : this._rows[0]);
527
+ return;
528
+ }
529
+
530
+ if (this.opts.metaAsArray) {
531
+ if (this.useUnitResult) {
532
+ const rs = [];
533
+ this._rows.forEach((row, i) => {
534
+ if (i % 2 === 0) rs.push(...row);
535
+ });
536
+ this.successEnd([rs, this.prepare.columns]);
537
+ } else {
538
+ const rs = [];
539
+ this._rows.forEach((row) => {
540
+ rs.push(...row);
541
+ });
542
+ this.successEnd([rs, this._columns]);
543
+ }
544
+ } else {
545
+ if (this.useUnitResult) {
546
+ const rs = [];
547
+ this._rows.forEach((row, i) => {
548
+ if (i % 2 === 0) rs.push(...row);
549
+ });
550
+ Object.defineProperty(rs, 'meta', {
551
+ value: this._columns,
552
+ writable: true,
553
+ enumerable: this.opts.metaEnumerable
554
+ });
183
555
  this.successEnd(rs);
184
- this._columns = null;
185
- this._rows = null;
556
+ } else {
557
+ if (this._rows.length === 1) {
558
+ this.successEnd(this._rows[0]);
559
+ } else {
560
+ const rs = [];
561
+ if (Array.isArray(this._rows[0])) {
562
+ this._rows.forEach((row) => {
563
+ rs.push(...row);
564
+ });
565
+ } else rs.push(...this._rows);
566
+ Object.defineProperty(rs, 'meta', {
567
+ value: this._columns,
568
+ writable: true,
569
+ enumerable: this.opts.metaEnumerable
570
+ });
571
+ this.successEnd(rs);
572
+ }
186
573
  }
187
- return;
188
574
  }
575
+ }
576
+
577
+ /**
578
+ * Handle OK packet success
579
+ *
580
+ * @param {Object} okPacket - OK packet
581
+ * @param {Object} info - Connection information
582
+ */
583
+ okPacketSuccess(okPacket, info) {
584
+ this._rows.push(okPacket);
189
585
 
190
- if (!this.packet.haveErrorResponse) {
586
+ if (info.status & ServerStatus.MORE_RESULTS_EXISTS) {
191
587
  this._responseIndex++;
192
- this.onPacketReceive = this.readResponsePacket;
588
+ return (this.onPacketReceive = this.readResponsePacket);
589
+ }
590
+
591
+ if (this.opts.metaAsArray) {
592
+ if (!this._meta) {
593
+ this._meta = new Array(this._responseIndex);
594
+ }
595
+ this._meta[this._responseIndex] = null;
596
+ this.success([this._rows, this._meta]);
597
+ } else {
598
+ this.success(this._rows);
193
599
  }
194
600
  }
195
601
 
602
+ /**
603
+ * Handle errors during query execution
604
+ *
605
+ * @param {Error} err - Error object
606
+ * @param {Object} info - Connection information
607
+ */
196
608
  throwError(err, info) {
197
- this.packet.waitingResponseNo--;
198
- this.sending = false;
199
- if (this.packet && !this.packet.haveErrorResponse) {
609
+ this.bulkPacketNo--;
610
+
611
+ if (!this.firstError) {
200
612
  if (err.fatal) {
201
- this.packet.waitingResponseNo = 0;
613
+ this.bulkPacketNo = 0;
202
614
  }
203
- if (this.stack) {
615
+
616
+ if (this.cmdParam.stack) {
204
617
  err = Errors.createError(
205
618
  err.message,
206
- this.sql,
207
- err.fatal,
619
+ err.errno,
208
620
  info,
209
621
  err.sqlState,
210
- err.errno,
211
- this.stack,
622
+ this.sql,
623
+ err.fatal,
624
+ this.cmdParam.stack,
212
625
  false
213
626
  );
214
627
  }
628
+
215
629
  this.firstError = err;
216
- this.packet.endedWithError();
217
630
  }
218
631
 
219
- if (!this.sending && this.packet.waitingResponseNo === 0) {
632
+ if (!this.sending && this.bulkPacketNo === 0) {
220
633
  this.resolve = null;
221
-
222
- //send COM_STMT_CLOSE packet
223
- if (!err.fatal && this.statementId) {
224
- this.sequenceNo = -1;
225
- this.compressSequenceNo = -1;
226
- this.out.startPacket(this);
227
- this.out.writeInt8(0x19);
228
- this.out.writeInt32(this.statementId);
229
- this.out.flushBuffer(true);
230
- }
231
634
  this.emit('send_end');
232
635
  process.nextTick(this.reject, this.firstError);
233
636
  this.reject = null;
234
637
  this.onPacketReceive = null;
235
638
  this.emit('end', this.firstError);
236
639
  } else {
237
- this._responseIndex++;
238
640
  this.onPacketReceive = this.readResponsePacket;
239
641
  }
240
642
  }
241
643
 
242
644
  /**
243
- * Validate that parameters exists and are defined.
645
+ * Validate that parameters exist and are defined
244
646
  *
245
- * @param info connection info
246
- * @returns {boolean} return false if any error occur.
647
+ * @param {Object} info - Connection information
648
+ * @returns {Boolean} Returns false if any error occurs
247
649
  */
248
650
  validateParameters(info) {
249
- //validate parameter size.
651
+ const nbParameter = this.prepare.parameterCount;
652
+
250
653
  for (let r = 0; r < this.values.length; r++) {
251
- if (!Array.isArray(this.values[r])) this.values[r] = [this.values[r]];
252
-
253
- //validate parameter is defined.
254
- for (let i = 0; i < this.values[r].length; i++) {
255
- if (this.values[r][i] === undefined) {
256
- this.emit('send_end');
257
- this.throwNewError(
258
- 'Parameter at position ' +
259
- (i + 1) +
260
- ' is undefined for values ' +
261
- r +
262
- '\n' +
263
- this.displaySql(),
264
- false,
265
- info,
266
- 'HY000',
267
- Errors.ER_PARAMETER_UNDEFINED
268
- );
269
- return false;
270
- }
654
+ if (!Array.isArray(this.values[r])) {
655
+ this.values[r] = [this.values[r]];
656
+ }
657
+
658
+ if (this.values[r].length < nbParameter) {
659
+ this.emit('send_end');
660
+ this.throwNewError(
661
+ `Expect ${nbParameter} parameters, but at index ${r}, parameters only contains ${this.values[r].length}\n ${
662
+ this.opts.logParam ? this.displaySql() : this.sql
663
+ }`,
664
+ false,
665
+ info,
666
+ 'HY000',
667
+ Errors.ER_PARAMETER_UNDEFINED
668
+ );
669
+ return false;
271
670
  }
272
671
  }
273
672