mysql2 3.8.0 → 3.9.0

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.
@@ -80,12 +80,35 @@ function readCodeFor(field, config, options, fieldNum) {
80
80
 
81
81
  function compile(fields, options, config) {
82
82
  const parserFn = genFunc();
83
- let i = 0;
84
83
  const nullBitmapLength = Math.floor((fields.length + 7 + 2) / 8);
85
84
 
86
- /* eslint-disable no-trailing-spaces */
87
- /* eslint-disable no-spaced-func */
88
- /* eslint-disable no-unexpected-multiline */
85
+ function wrap(field, packet) {
86
+ return {
87
+ type: typeNames[field.columnType],
88
+ length: field.columnLength,
89
+ db: field.schema,
90
+ table: field.table,
91
+ name: field.name,
92
+ string: function (encoding = field.encoding) {
93
+ if (field.columnType === Types.JSON && encoding === field.encoding) {
94
+ // Since for JSON columns mysql always returns charset 63 (BINARY),
95
+ // we have to handle it according to JSON specs and use "utf8",
96
+ // see https://github.com/sidorares/node-mysql2/issues/1661
97
+ console.warn(
98
+ `typeCast: JSON column "${field.name}" is interpreted as BINARY by default, recommended to manually set utf8 encoding: \`field.string("utf8")\``,
99
+ );
100
+ }
101
+
102
+ return packet.readLengthCodedString(encoding);
103
+ },
104
+ buffer: function () {
105
+ return packet.readLengthCodedBuffer();
106
+ },
107
+ geometry: function () {
108
+ return packet.parseGeometryValue();
109
+ },
110
+ };
111
+ }
89
112
 
90
113
  parserFn('(function(){');
91
114
  parserFn('return class BinaryRow {');
@@ -96,24 +119,19 @@ function compile(fields, options, config) {
96
119
  if (options.rowsAsArray) {
97
120
  parserFn(`const result = new Array(${fields.length});`);
98
121
  } else {
99
- parserFn("const result = {};");
122
+ parserFn('const result = {};');
100
123
  }
101
124
 
102
- const resultTables = {};
103
- let resultTablesArray = [];
104
-
105
- if (options.nestTables === true) {
106
- for (i = 0; i < fields.length; i++) {
107
- resultTables[fields[i].table] = 1;
108
- }
109
- resultTablesArray = Object.keys(resultTables);
110
- for (i = 0; i < resultTablesArray.length; i++) {
111
- parserFn(`result[${helpers.srcEscape(resultTablesArray[i])}] = {};`);
112
- }
125
+ // Global typeCast
126
+ if (
127
+ typeof config.typeCast === 'function' &&
128
+ typeof options.typeCast !== 'function'
129
+ ) {
130
+ options.typeCast = config.typeCast;
113
131
  }
114
132
 
115
133
  parserFn('packet.readInt8();'); // status byte
116
- for (i = 0; i < nullBitmapLength; ++i) {
134
+ for (let i = 0; i < nullBitmapLength; ++i) {
117
135
  parserFn(`const nullBitmaskByte${i} = packet.readInt8();`);
118
136
  }
119
137
 
@@ -123,38 +141,44 @@ function compile(fields, options, config) {
123
141
  let fieldName = '';
124
142
  let tableName = '';
125
143
 
126
- for (i = 0; i < fields.length; i++) {
144
+ for (let i = 0; i < fields.length; i++) {
127
145
  fieldName = helpers.srcEscape(fields[i].name);
128
146
  parserFn(`// ${fieldName}: ${typeNames[fields[i].columnType]}`);
129
147
 
130
148
  if (typeof options.nestTables === 'string') {
131
- tableName = helpers.srcEscape(fields[i].table);
132
149
  lvalue = `result[${helpers.srcEscape(
133
- fields[i].table + options.nestTables + fields[i].name
150
+ fields[i].table + options.nestTables + fields[i].name,
134
151
  )}]`;
135
152
  } else if (options.nestTables === true) {
136
153
  tableName = helpers.srcEscape(fields[i].table);
154
+ parserFn(`if (!result[${tableName}]) result[${tableName}] = {};`);
137
155
  lvalue = `result[${tableName}][${fieldName}]`;
138
156
  } else if (options.rowsAsArray) {
139
157
  lvalue = `result[${i.toString(10)}]`;
140
158
  } else {
141
- lvalue = `result[${helpers.srcEscape(fields[i].name)}]`;
159
+ lvalue = `result[${fieldName}]`;
160
+ }
161
+
162
+ if (options.typeCast === false) {
163
+ parserFn(`${lvalue} = packet.readLengthCodedBuffer();`);
164
+ } else {
165
+ const fieldWrapperVar = `fieldWrapper${i}`;
166
+ parserFn(`const ${fieldWrapperVar} = wrap(fields[${i}], packet);`);
167
+ const readCode = readCodeFor(fields[i], config, options, i);
168
+
169
+ parserFn(`if (nullBitmaskByte${nullByteIndex} & ${currentFieldNullBit})`);
170
+ parserFn(`${lvalue} = null;`);
171
+ parserFn('else {');
172
+ if (typeof options.typeCast === 'function') {
173
+ parserFn(
174
+ `${lvalue} = options.typeCast(${fieldWrapperVar}, function() { return ${readCode} });`,
175
+ );
176
+ } else {
177
+ parserFn(`${lvalue} = ${readCode};`);
178
+ }
179
+ parserFn('}');
142
180
  }
143
181
 
144
- // TODO: this used to be an optimisation ( if column marked as NOT_NULL don't include code to check null
145
- // bitmap at all, but it seems that we can't rely on this flag, see #178
146
- // TODO: benchmark performance difference
147
- //
148
- // if (fields[i].flags & FieldFlags.NOT_NULL) { // don't need to check null bitmap if field can't be null.
149
- // result.push(lvalue + ' = ' + readCodeFor(fields[i], config));
150
- // } else if (fields[i].columnType == Types.NULL) {
151
- // result.push(lvalue + ' = null;');
152
- // } else {
153
- parserFn(`if (nullBitmaskByte${nullByteIndex} & ${currentFieldNullBit})`);
154
- parserFn(`${lvalue} = null;`);
155
- parserFn('else');
156
- parserFn(`${lvalue} = ${readCodeFor(fields[i], config, options, i)}`);
157
- // }
158
182
  currentFieldNullBit *= 2;
159
183
  if (currentFieldNullBit === 0x100) {
160
184
  currentFieldNullBit = 1;
@@ -166,17 +190,13 @@ function compile(fields, options, config) {
166
190
  parserFn('}');
167
191
  parserFn('};')('})()');
168
192
 
169
- /* eslint-enable no-trailing-spaces */
170
- /* eslint-enable no-spaced-func */
171
- /* eslint-enable no-unexpected-multiline */
172
-
173
193
  if (config.debug) {
174
194
  helpers.printDebugWithCode(
175
195
  'Compiled binary protocol row parser',
176
- parserFn.toString()
196
+ parserFn.toString(),
177
197
  );
178
198
  }
179
- return parserFn.toFunction();
199
+ return parserFn.toFunction({ wrap });
180
200
  }
181
201
 
182
202
  function getBinaryParser(fields, options, config) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mysql2",
3
- "version": "3.8.0",
3
+ "version": "3.9.0",
4
4
  "description": "fast mysql driver. Implements core protocol, prepared statements, ssl and compression in native JS",
5
5
  "main": "index.js",
6
6
  "typings": "typings/mysql/index",
@@ -76,7 +76,7 @@
76
76
  "eslint-config-prettier": "^9.0.0",
77
77
  "eslint-plugin-async-await": "0.0.0",
78
78
  "eslint-plugin-markdown": "^3.0.0",
79
- "husky": "^8.0.2",
79
+ "husky": "^9.0.2",
80
80
  "lint-staged": "^15.0.1",
81
81
  "portfinder": "^1.0.28",
82
82
  "prettier": "^3.0.0",
@@ -209,10 +209,6 @@ export interface ConnectionOptions {
209
209
  * ```
210
210
  *
211
211
  * You can find which field function you need to use by looking at `RowDataPacket.prototype._typeCast`.
212
- *
213
- * ---
214
- *
215
- * For `execute`, please see: [typeCast not supported with .execute #649](https://github.com/sidorares/node-mysql2/issues/649).
216
212
  */
217
213
  typeCast?: TypeCast;
218
214
 
@@ -70,10 +70,6 @@ export interface QueryOptions {
70
70
  * ```
71
71
  *
72
72
  * You can find which field function you need to use by looking at `RowDataPacket.prototype._typeCast`.
73
- *
74
- * ---
75
- *
76
- * For `execute`, please see: [typeCast not supported with .execute #649](https://github.com/sidorares/node-mysql2/issues/649).
77
73
  */
78
74
  typeCast?: TypeCast;
79
75