@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.
- package/README.md +34 -34
- package/README.zh-CN.md +34 -34
- package/client.d.ts +1 -1
- package/client.js +1 -1
- package/dist/externalVersion.js +5 -5
- package/dist/locale/en-US.json +48 -48
- package/dist/locale/es-ES.json +9 -9
- package/dist/locale/ko_KR.json +11 -11
- package/dist/locale/pt-BR.json +9 -9
- package/dist/locale/zh-CN.json +58 -58
- package/dist/node_modules/mariadb/callback.js +43 -8
- package/dist/node_modules/mariadb/check-node.js +30 -0
- package/dist/node_modules/mariadb/lib/cluster-callback.js +84 -0
- package/dist/node_modules/mariadb/lib/cluster.js +446 -0
- package/dist/node_modules/mariadb/lib/cmd/batch-bulk.js +576 -177
- package/dist/node_modules/mariadb/lib/cmd/change-user.js +54 -44
- package/dist/node_modules/mariadb/lib/cmd/class/ok-packet.js +3 -2
- package/dist/node_modules/mariadb/lib/cmd/class/prepare-cache-wrapper.js +46 -0
- package/dist/node_modules/mariadb/lib/cmd/class/prepare-result-packet.js +141 -0
- package/dist/node_modules/mariadb/lib/cmd/class/prepare-wrapper.js +70 -0
- package/dist/node_modules/mariadb/lib/cmd/close-prepare.js +38 -0
- package/dist/node_modules/mariadb/lib/cmd/column-definition.js +145 -47
- package/dist/node_modules/mariadb/lib/cmd/command.js +41 -75
- package/dist/node_modules/mariadb/lib/cmd/decoder/binary-decoder.js +282 -0
- package/dist/node_modules/mariadb/lib/cmd/decoder/text-decoder.js +210 -0
- package/dist/node_modules/mariadb/lib/cmd/{common-binary-cmd.js → encoder/binary-encoder.js} +34 -77
- package/dist/node_modules/mariadb/lib/cmd/encoder/text-encoder.js +311 -0
- package/dist/node_modules/mariadb/lib/cmd/execute-stream.js +61 -0
- package/dist/node_modules/mariadb/lib/cmd/execute.js +338 -0
- package/dist/node_modules/mariadb/lib/cmd/handshake/auth/caching-sha2-password-auth.js +25 -62
- package/dist/node_modules/mariadb/lib/cmd/handshake/auth/clear-password-auth.js +39 -6
- package/dist/node_modules/mariadb/lib/cmd/handshake/auth/ed25519-password-auth.js +48 -16
- package/dist/node_modules/mariadb/lib/cmd/handshake/auth/handshake.js +198 -0
- package/dist/node_modules/mariadb/lib/cmd/handshake/{initial-handshake.js → auth/initial-handshake.js} +10 -8
- package/dist/node_modules/mariadb/lib/cmd/handshake/auth/native-password-auth.js +22 -9
- package/dist/node_modules/mariadb/lib/cmd/handshake/auth/pam-password-auth.js +9 -4
- package/dist/node_modules/mariadb/lib/cmd/handshake/auth/parsec-auth.js +115 -0
- package/dist/node_modules/mariadb/lib/cmd/handshake/auth/plugin-auth.js +12 -5
- package/dist/node_modules/mariadb/lib/cmd/handshake/auth/sha256-password-auth.js +44 -33
- package/dist/node_modules/mariadb/lib/cmd/handshake/authentication.js +335 -0
- package/dist/node_modules/mariadb/lib/cmd/handshake/client-capabilities.js +20 -19
- package/dist/node_modules/mariadb/lib/cmd/handshake/ssl-request.js +6 -3
- package/dist/node_modules/mariadb/lib/cmd/parser.js +861 -0
- package/dist/node_modules/mariadb/lib/cmd/ping.js +17 -18
- package/dist/node_modules/mariadb/lib/cmd/prepare.js +170 -0
- package/dist/node_modules/mariadb/lib/cmd/query.js +281 -144
- package/dist/node_modules/mariadb/lib/cmd/quit.js +9 -6
- package/dist/node_modules/mariadb/lib/cmd/reset.js +15 -19
- package/dist/node_modules/mariadb/lib/cmd/stream.js +21 -6
- package/dist/node_modules/mariadb/lib/config/cluster-options.js +23 -0
- package/dist/node_modules/mariadb/lib/config/connection-options.js +196 -132
- package/dist/node_modules/mariadb/lib/config/pool-options.js +27 -19
- package/dist/node_modules/mariadb/lib/connection-callback.js +492 -120
- package/dist/node_modules/mariadb/lib/connection-promise.js +372 -0
- package/dist/node_modules/mariadb/lib/connection.js +1739 -1016
- package/dist/node_modules/mariadb/lib/const/capabilities.js +36 -30
- package/dist/node_modules/mariadb/lib/const/collations.js +972 -36
- package/dist/node_modules/mariadb/lib/const/connection_status.js +3 -0
- package/dist/node_modules/mariadb/lib/const/error-code.js +35 -11
- package/dist/node_modules/mariadb/lib/const/field-detail.js +3 -0
- package/dist/node_modules/mariadb/lib/const/field-type.js +7 -4
- package/dist/node_modules/mariadb/lib/const/server-status.js +4 -1
- package/dist/node_modules/mariadb/lib/const/state-change.js +3 -0
- package/dist/node_modules/mariadb/lib/filtered-cluster-callback.js +136 -0
- package/dist/node_modules/mariadb/lib/filtered-cluster.js +118 -0
- package/dist/node_modules/mariadb/lib/io/compression-input-stream.js +14 -13
- package/dist/node_modules/mariadb/lib/io/compression-output-stream.js +21 -18
- package/dist/node_modules/mariadb/lib/io/packet-input-stream.js +75 -64
- package/dist/node_modules/mariadb/lib/io/packet-node-encoded.js +13 -9
- package/dist/node_modules/mariadb/lib/io/packet-node-iconv.js +12 -10
- package/dist/node_modules/mariadb/lib/io/packet-output-stream.js +402 -134
- package/dist/node_modules/mariadb/lib/io/packet.js +287 -202
- package/dist/node_modules/mariadb/lib/lru-prepare-cache.js +84 -0
- package/dist/node_modules/mariadb/lib/misc/connection-information.js +15 -32
- package/dist/node_modules/mariadb/lib/misc/errors.js +68 -25
- package/dist/node_modules/mariadb/lib/misc/parse.js +207 -711
- package/dist/node_modules/mariadb/lib/misc/utils.js +34 -62
- package/dist/node_modules/mariadb/lib/pool-callback.js +213 -174
- package/dist/node_modules/mariadb/lib/pool-promise.js +228 -94
- package/dist/node_modules/mariadb/lib/pool.js +951 -0
- package/dist/node_modules/mariadb/package.json +1 -1
- package/dist/node_modules/mariadb/promise.js +1 -34
- package/dist/node_modules/mariadb/types/callback.d.ts +207 -0
- package/dist/node_modules/mariadb/types/index.d.ts +94 -674
- package/dist/node_modules/mariadb/types/share.d.ts +804 -0
- package/dist/node_modules/qs/package.json +1 -1
- package/dist/server/actions/apps.js +2 -2
- package/dist/server/app-lifecycle.d.ts +1 -1
- package/dist/server/app-lifecycle.js +4 -4
- package/dist/server/models/application.d.ts +1 -1
- package/package.json +7 -7
- package/server.d.ts +2 -2
- package/server.js +1 -1
- package/dist/node_modules/mariadb/lib/cmd/batch-rewrite.js +0 -372
- package/dist/node_modules/mariadb/lib/cmd/common-text-cmd.js +0 -427
- package/dist/node_modules/mariadb/lib/cmd/handshake/client-handshake-response.js +0 -126
- package/dist/node_modules/mariadb/lib/cmd/handshake/handshake.js +0 -292
- package/dist/node_modules/mariadb/lib/cmd/resultset.js +0 -607
- package/dist/node_modules/mariadb/lib/config/pool-cluster-options.js +0 -19
- package/dist/node_modules/mariadb/lib/filtered-pool-cluster.js +0 -81
- package/dist/node_modules/mariadb/lib/io/bulk-packet.js +0 -590
- package/dist/node_modules/mariadb/lib/io/rewrite-packet.js +0 -481
- package/dist/node_modules/mariadb/lib/pool-base.js +0 -611
- package/dist/node_modules/mariadb/lib/pool-cluster-callback.js +0 -66
- package/dist/node_modules/mariadb/lib/pool-cluster.js +0 -407
|
@@ -1,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
|
|
6
|
+
const Parser = require('./parser');
|
|
4
7
|
const Errors = require('../misc/errors');
|
|
5
|
-
const
|
|
6
|
-
const
|
|
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
|
-
*
|
|
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
|
|
13
|
-
constructor(resolve, reject,
|
|
14
|
-
super(resolve, reject,
|
|
15
|
-
this.
|
|
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
|
-
*
|
|
44
|
+
* Initiates the batch operation
|
|
20
45
|
*
|
|
21
|
-
* @param out
|
|
22
|
-
* @param opts
|
|
23
|
-
* @param info
|
|
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
|
-
|
|
31
|
-
|
|
32
|
-
|
|
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
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
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
|
-
|
|
57
|
-
|
|
58
|
-
|
|
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
|
-
|
|
62
|
-
|
|
63
|
-
|
|
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
|
-
|
|
66
|
-
|
|
67
|
-
out.writeString(questionMarkSql);
|
|
68
|
-
out.flushBuffer(true);
|
|
117
|
+
for (let i = 0; i < parameterCount; i++) {
|
|
118
|
+
const val = value[i];
|
|
69
119
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
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
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
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
|
-
|
|
97
|
-
|
|
98
|
-
|
|
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
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
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
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
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
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
if (
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
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
|
-
|
|
375
|
+
|
|
376
|
+
out.flush();
|
|
377
|
+
this.sending = false;
|
|
378
|
+
this.emit('send_end');
|
|
134
379
|
}
|
|
135
380
|
|
|
136
|
-
|
|
137
|
-
|
|
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 (
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
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
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
this.
|
|
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
|
-
|
|
160
|
-
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
sqlMsg += ']';
|
|
427
|
+
return sqlMsg;
|
|
428
|
+
}
|
|
161
429
|
|
|
162
|
-
|
|
163
|
-
|
|
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.
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
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
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
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
|
-
|
|
185
|
-
this._rows
|
|
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 (
|
|
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.
|
|
198
|
-
|
|
199
|
-
if (
|
|
609
|
+
this.bulkPacketNo--;
|
|
610
|
+
|
|
611
|
+
if (!this.firstError) {
|
|
200
612
|
if (err.fatal) {
|
|
201
|
-
this.
|
|
613
|
+
this.bulkPacketNo = 0;
|
|
202
614
|
}
|
|
203
|
-
|
|
615
|
+
|
|
616
|
+
if (this.cmdParam.stack) {
|
|
204
617
|
err = Errors.createError(
|
|
205
618
|
err.message,
|
|
206
|
-
|
|
207
|
-
err.fatal,
|
|
619
|
+
err.errno,
|
|
208
620
|
info,
|
|
209
621
|
err.sqlState,
|
|
210
|
-
|
|
211
|
-
|
|
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.
|
|
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
|
|
645
|
+
* Validate that parameters exist and are defined
|
|
244
646
|
*
|
|
245
|
-
* @param info
|
|
246
|
-
* @returns {
|
|
647
|
+
* @param {Object} info - Connection information
|
|
648
|
+
* @returns {Boolean} Returns false if any error occurs
|
|
247
649
|
*/
|
|
248
650
|
validateParameters(info) {
|
|
249
|
-
|
|
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]))
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
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
|
|