mssql 12.3.0 → 12.4.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.
@@ -200,9 +200,13 @@ const parameterCorrection = function (value) {
200
200
  }
201
201
 
202
202
  for (const col of value.columns) {
203
+ const tediousType = getTediousType(col.type)
204
+ if (tediousType === tds.TYPES.Variant) {
205
+ throw new RequestError(`Column '${col.name}' in TVP '${value.schema ? value.schema + '.' : ''}${value.name}' uses sql_variant which is not supported by the tedious driver for TVP column types. Consider using a more specific data type.`, 'EARGS')
206
+ }
203
207
  tvp.columns.push({
204
208
  name: col.name,
205
- type: getTediousType(col.type),
209
+ type: tediousType,
206
210
  length: col.length,
207
211
  scale: col.scale,
208
212
  precision: col.precision
@@ -664,9 +668,18 @@ class Request extends BaseRequest {
664
668
  } catch (e) {
665
669
  e.message = `Validation failed for parameter '${name}'. ${e.message}`
666
670
  const err = new RequestError(e, 'EPARAM')
671
+ delete this._cancel
672
+
673
+ if (!hasReturned) {
674
+ for (const event in errorHandlers) {
675
+ connection.removeListener(event, errorHandlers[event])
676
+ }
667
677
 
668
- this.parent.release(connection)
669
- return callback(err)
678
+ this.parent.release(connection)
679
+ hasReturned = true
680
+ return callback(err)
681
+ }
682
+ return
670
683
  }
671
684
  }
672
685
 
@@ -703,21 +716,23 @@ class Request extends BaseRequest {
703
716
 
704
717
  req.sqlTextOrProcedure = `declare ${declarations.join(', ')};select ${assigns.join(', ')};${req.sqlTextOrProcedure};${batchHasOutput ? (`select 1 as [___return___], ${selects.join(', ')}`) : ''}`
705
718
  }
706
- } else {
707
- for (const name in this.parameters) {
708
- if (!objectHasProperty(this.parameters, name)) {
709
- continue
710
- }
711
- const param = this.parameters[name]
712
- if (param.io === 1) {
713
- req.addParameter(param.name, getTediousType(param.type), parameterCorrection(param.value), { length: param.length, scale: param.scale, precision: param.precision })
714
- } else {
715
- req.addOutputParameter(param.name, getTediousType(param.type), parameterCorrection(param.value), { length: param.length, scale: param.scale, precision: param.precision })
716
- }
717
- }
718
719
  }
719
720
 
720
721
  try {
722
+ if (!this._isBatch) {
723
+ for (const name in this.parameters) {
724
+ if (!objectHasProperty(this.parameters, name)) {
725
+ continue
726
+ }
727
+ const param = this.parameters[name]
728
+ if (param.io === 1) {
729
+ req.addParameter(param.name, getTediousType(param.type), parameterCorrection(param.value), { length: param.length, scale: param.scale, precision: param.precision })
730
+ } else {
731
+ req.addOutputParameter(param.name, getTediousType(param.type), parameterCorrection(param.value), { length: param.length, scale: param.scale, precision: param.precision })
732
+ }
733
+ }
734
+ }
735
+
721
736
  connection[this._isBatch ? 'execSqlBatch' : 'execSql'](req)
722
737
  } catch (error) {
723
738
  handleError(true, connection, error)
@@ -983,19 +998,34 @@ class Request extends BaseRequest {
983
998
  output[parameterName] = value
984
999
  })
985
1000
 
986
- for (const name in this.parameters) {
987
- if (!objectHasProperty(this.parameters, name)) {
988
- continue
1001
+ try {
1002
+ for (const name in this.parameters) {
1003
+ if (!objectHasProperty(this.parameters, name)) {
1004
+ continue
1005
+ }
1006
+ const param = this.parameters[name]
1007
+ if (param.io === 1) {
1008
+ req.addParameter(param.name, getTediousType(param.type), parameterCorrection(param.value), { length: param.length, scale: param.scale, precision: param.precision })
1009
+ } else {
1010
+ req.addOutputParameter(param.name, getTediousType(param.type), parameterCorrection(param.value), { length: param.length, scale: param.scale, precision: param.precision })
1011
+ }
989
1012
  }
990
- const param = this.parameters[name]
991
- if (param.io === 1) {
992
- req.addParameter(param.name, getTediousType(param.type), parameterCorrection(param.value), { length: param.length, scale: param.scale, precision: param.precision })
993
- } else {
994
- req.addOutputParameter(param.name, getTediousType(param.type), parameterCorrection(param.value), { length: param.length, scale: param.scale, precision: param.precision })
1013
+
1014
+ connection.callProcedure(req)
1015
+ } catch (error) {
1016
+ const err = error instanceof RequestError ? error : new RequestError(error, 'EREQUEST')
1017
+ delete this._cancel
1018
+
1019
+ if (!hasReturned) {
1020
+ for (const event in errorHandlers) {
1021
+ connection.removeListener(event, errorHandlers[event])
1022
+ }
1023
+
1024
+ this.parent.release(connection)
1025
+ hasReturned = true
1026
+ callback(err)
995
1027
  }
996
1028
  }
997
-
998
- connection.callProcedure(req)
999
1029
  })
1000
1030
  })
1001
1031
  }
@@ -4,6 +4,7 @@ const debug = require('debug')('mssql:tedi')
4
4
  const BaseTransaction = require('../base/transaction')
5
5
  const { IDS } = require('../utils')
6
6
  const TransactionError = require('../error/transaction-error')
7
+ const { CHANNELS, publish } = require('../diagnostics')
7
8
 
8
9
  class Transaction extends BaseTransaction {
9
10
  constructor (parent) {
@@ -23,6 +24,10 @@ class Transaction extends BaseTransaction {
23
24
  this._acquiredConfig = null
24
25
  this._aborted = true
25
26
 
27
+ publish(CHANNELS.TRANSACTION_ROLLBACK, () => ({
28
+ transactionId: IDS.get(this),
29
+ aborted: true
30
+ }))
26
31
  this.emit('rollback', true)
27
32
  }
28
33
  }
package/lib/udt.js CHANGED
@@ -44,6 +44,12 @@ const SEGMENT = {
44
44
  FIRST_ARC: 0x03
45
45
  }; */
46
46
 
47
+ const ensureBytes = (buffer, needed) => {
48
+ if (buffer.position + needed > buffer.length) {
49
+ throw new Error(`Corrupt or truncated spatial data: expected ${needed} bytes at position ${buffer.position}, but only ${buffer.length - buffer.position} bytes remain`)
50
+ }
51
+ }
52
+
47
53
  class Point {
48
54
  constructor () {
49
55
  this.x = 0
@@ -64,6 +70,8 @@ const parsePoints = (buffer, count, isGeometryPoint) => {
64
70
  return points
65
71
  }
66
72
 
73
+ ensureBytes(buffer, count * 16)
74
+
67
75
  if (isGeometryPoint) {
68
76
  // GEOMETRY POINT (s2.1.6): x then y.
69
77
  for (let i = 1; i <= count; i++) {
@@ -101,6 +109,8 @@ const parseZ = (buffer, points) => {
101
109
  return
102
110
  }
103
111
 
112
+ ensureBytes(buffer, points.length * 8)
113
+
104
114
  points.forEach(point => {
105
115
  point.z = buffer.readDoubleLE(buffer.position)
106
116
  buffer.position += 8
@@ -114,6 +124,8 @@ const parseM = (buffer, points) => {
114
124
  return
115
125
  }
116
126
 
127
+ ensureBytes(buffer, points.length * 8)
128
+
117
129
  points.forEach(point => {
118
130
  point.m = buffer.readDoubleLE(buffer.position)
119
131
  buffer.position += 8
@@ -139,6 +151,8 @@ const parseFigures = (buffer, count, properties) => {
139
151
  pointOffset: 0
140
152
  })
141
153
  } else {
154
+ ensureBytes(buffer, count * 5)
155
+
142
156
  for (let i = 1; i <= count; i++) {
143
157
  figures.push({
144
158
  attribute: buffer.readUInt8(buffer.position),
@@ -173,6 +187,8 @@ const parseShapes = (buffer, count, properties) => {
173
187
  type: 0x02
174
188
  })
175
189
  } else {
190
+ ensureBytes(buffer, count * 9)
191
+
176
192
  for (let i = 1; i <= count; i++) {
177
193
  shapes.push({
178
194
  parentOffset: buffer.readInt32LE(buffer.position),
@@ -195,6 +211,8 @@ const parseSegments = (buffer, count) => {
195
211
  return segments
196
212
  }
197
213
 
214
+ ensureBytes(buffer, count)
215
+
198
216
  for (let i = 1; i <= count; i++) {
199
217
  segments.push({ type: buffer.readUInt8(buffer.position) })
200
218
 
@@ -207,6 +225,8 @@ const parseSegments = (buffer, count) => {
207
225
  const parseGeography = (buffer, isUsingGeometryPoints) => {
208
226
  // s2.1.1 + s.2.1.2
209
227
 
228
+ ensureBytes(buffer, 6)
229
+
210
230
  const srid = buffer.readInt32LE(0)
211
231
  if (srid === -1) {
212
232
  return null
@@ -220,9 +240,6 @@ const parseGeography = (buffer, isUsingGeometryPoints) => {
220
240
  const flags = buffer.readUInt8(5)
221
241
  buffer.position = 6
222
242
 
223
- // console.log("srid", srid)
224
- // console.log("version", version)
225
-
226
243
  const properties = {
227
244
  Z: (flags & (1 << 0)) > 0,
228
245
  M: (flags & (1 << 1)) > 0,
@@ -232,23 +249,20 @@ const parseGeography = (buffer, isUsingGeometryPoints) => {
232
249
  }
233
250
 
234
251
  if (value.version === 2) {
235
- properties.H = (flags & (1 << 3)) > 0
252
+ properties.H = (flags & (1 << 5)) > 0
236
253
  }
237
254
 
238
- // console.log("properties", properties);
239
-
240
255
  let numberOfPoints
241
256
  if (properties.P) {
242
257
  numberOfPoints = 1
243
258
  } else if (properties.L) {
244
259
  numberOfPoints = 2
245
260
  } else {
261
+ ensureBytes(buffer, 4)
246
262
  numberOfPoints = buffer.readUInt32LE(buffer.position)
247
263
  buffer.position += 4
248
264
  }
249
265
 
250
- // console.log("numberOfPoints", numberOfPoints)
251
-
252
266
  value.points = parsePoints(buffer, numberOfPoints, isUsingGeometryPoints)
253
267
 
254
268
  if (properties.Z) {
@@ -259,49 +273,37 @@ const parseGeography = (buffer, isUsingGeometryPoints) => {
259
273
  parseM(buffer, value.points)
260
274
  }
261
275
 
262
- // console.log("points", points)
263
-
264
276
  let numberOfFigures
265
277
  if (properties.P) {
266
278
  numberOfFigures = 1
267
279
  } else if (properties.L) {
268
280
  numberOfFigures = 1
269
281
  } else {
282
+ ensureBytes(buffer, 4)
270
283
  numberOfFigures = buffer.readUInt32LE(buffer.position)
271
284
  buffer.position += 4
272
285
  }
273
286
 
274
- // console.log("numberOfFigures", numberOfFigures)
275
-
276
287
  value.figures = parseFigures(buffer, numberOfFigures, properties)
277
288
 
278
- // console.log("figures", figures)
279
-
280
289
  let numberOfShapes
281
290
  if (properties.P) {
282
291
  numberOfShapes = 1
283
292
  } else if (properties.L) {
284
293
  numberOfShapes = 1
285
294
  } else {
295
+ ensureBytes(buffer, 4)
286
296
  numberOfShapes = buffer.readUInt32LE(buffer.position)
287
297
  buffer.position += 4
288
298
  }
289
299
 
290
- // console.log("numberOfShapes", numberOfShapes)
291
-
292
300
  value.shapes = parseShapes(buffer, numberOfShapes, properties)
293
301
 
294
- // console.log( "shapes", shapes)
295
-
296
- if (value.version === 2 && buffer.position < buffer.length) {
302
+ if (value.version === 2 && buffer.position + 4 <= buffer.length) {
297
303
  const numberOfSegments = buffer.readUInt32LE(buffer.position)
298
304
  buffer.position += 4
299
305
 
300
- // console.log("numberOfSegments", numberOfSegments)
301
-
302
306
  value.segments = parseSegments(buffer, numberOfSegments)
303
-
304
- // console.log("segments", segments)
305
307
  } else {
306
308
  value.segments = []
307
309
  }
package/lib/utils.js CHANGED
@@ -9,6 +9,14 @@ const INCREMENT = {
9
9
  PreparedStatement: 1
10
10
  }
11
11
 
12
+ const getPoolId = (obj) => {
13
+ let parent = obj && obj.parent
14
+ while (parent && !parent.pool) {
15
+ parent = parent.parent
16
+ }
17
+ return parent ? IDS.get(parent) : undefined
18
+ }
19
+
12
20
  module.exports = {
13
21
  objectHasProperty: (object, property) => Object.prototype.hasOwnProperty.call(object, property),
14
22
  INCREMENT,
@@ -18,5 +26,6 @@ module.exports = {
18
26
  if (id) return IDS.set(object, id)
19
27
  IDS.set(object, INCREMENT[type]++)
20
28
  }
21
- }
29
+ },
30
+ getPoolId
22
31
  }
package/package.json CHANGED
@@ -21,7 +21,7 @@
21
21
  "azure",
22
22
  "node-mssql"
23
23
  ],
24
- "version": "12.3.0",
24
+ "version": "12.4.0",
25
25
  "main": "index.js",
26
26
  "type": "commonjs",
27
27
  "repository": {
@@ -52,7 +52,7 @@
52
52
  "standard": "^17.0.0"
53
53
  },
54
54
  "engines": {
55
- "node": ">=18"
55
+ "node": ">=18.19.0"
56
56
  },
57
57
  "files": [
58
58
  "lib/",