mssql 7.1.3 → 8.0.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.
@@ -8,6 +8,7 @@ const { IDS, objectHasProperty } = require('../utils')
8
8
  const { TYPES, DECLARATIONS, declare } = require('../datatypes')
9
9
  const { PARSERS: UDT } = require('../udt')
10
10
  const Table = require('../table')
11
+ const { valueHandler } = require('../shared')
11
12
 
12
13
  const JSON_COLUMN_ID = 'JSON_F52E2B61-18A1-11d1-B105-00805F49916B'
13
14
  const XML_COLUMN_ID = 'XML_F52E2B61-18A1-11d1-B105-00805F49916B'
@@ -122,7 +123,12 @@ const createColumns = function (metadata, arrayRowMode) {
122
123
  }
123
124
 
124
125
  const valueCorrection = function (value, metadata) {
125
- if ((metadata.sqlType === 'time') && (value != null)) {
126
+ const type = metadata && objectHasProperty(metadata, 'sqlType') && objectHasProperty(DECLARATIONS, metadata.sqlType)
127
+ ? DECLARATIONS[metadata.sqlType]
128
+ : null
129
+ if (type && valueHandler.has(type)) {
130
+ return valueHandler.get(type)(value)
131
+ } else if ((metadata.sqlType === 'time') && (value != null)) {
126
132
  value.setFullYear(1970)
127
133
  return value
128
134
  } else if ((metadata.sqlType === 'udt') && (value != null)) {
@@ -146,7 +152,11 @@ class Request extends BaseRequest {
146
152
  super._bulk(table, options, err => {
147
153
  if (err) return callback(err)
148
154
 
149
- table._makeBulk()
155
+ try {
156
+ table._makeBulk()
157
+ } catch (e) {
158
+ return callback(new RequestError(e, 'EREQUEST'))
159
+ }
150
160
 
151
161
  if (!table.name) {
152
162
  setImmediate(callback, new RequestError('Table name must be specified for bulk insert.', 'ENAME'))
@@ -358,7 +368,7 @@ class Request extends BaseRequest {
358
368
  continue
359
369
  }
360
370
  const param = this.parameters[name]
361
- if (param.io === 1) {
371
+ if (param.io === 1 || (param.io === 2 && param.value)) {
362
372
  params.push(castParameter(param.value, param.type, param))
363
373
  }
364
374
  }
@@ -633,7 +643,19 @@ class Request extends BaseRequest {
633
643
  }
634
644
  }
635
645
 
636
- let cmd = `declare ${['@___return___ int'].concat(params).join(', ')};`
646
+ // set output params w/ values
647
+ const sets = []
648
+ for (const name in this.parameters) {
649
+ if (!objectHasProperty(this.parameters, name)) {
650
+ continue
651
+ }
652
+ const param = this.parameters[name]
653
+ if (param.io === 2 && param.value) {
654
+ sets.push(`set @${param.name}=?`)
655
+ }
656
+ }
657
+
658
+ let cmd = `declare ${['@___return___ int'].concat(params).join(', ')};${sets.join(';')};`
637
659
  cmd += `exec @___return___ = ${procedure} `
638
660
 
639
661
  const spp = []
package/lib/shared.js CHANGED
@@ -105,3 +105,10 @@ Object.defineProperty(module.exports, 'Promise', {
105
105
  PromiseLibrary = value
106
106
  }
107
107
  })
108
+
109
+ Object.defineProperty(module.exports, 'valueHandler', {
110
+ enumerable: true,
111
+ value: new Map(),
112
+ writable: false,
113
+ configurable: false
114
+ })
package/lib/table.js CHANGED
@@ -48,6 +48,13 @@ function Table (name) {
48
48
  }
49
49
  }
50
50
  )
51
+
52
+ Object.defineProperty(this.rows, 'clear', {
53
+ value () {
54
+ return this.splice(0, this.length)
55
+ }
56
+ }
57
+ )
51
58
  }
52
59
 
53
60
  /*
@@ -34,24 +34,23 @@ class ConnectionPool extends BaseConnectionPool {
34
34
  }, this.config.authentication)
35
35
  }
36
36
 
37
- cfg.options.database = this.config.database
38
- cfg.options.port = this.config.port
39
- cfg.options.connectTimeout = this.config.connectionTimeout || this.config.timeout || 15000
40
- cfg.options.requestTimeout = this.config.requestTimeout != null ? this.config.requestTimeout : 15000
37
+ cfg.options.database = cfg.options.database || this.config.database
38
+ cfg.options.port = cfg.options.port || this.config.port
39
+ cfg.options.connectTimeout = cfg.options.connectTimeout || this.config.connectionTimeout || this.config.timeout || 15000
40
+ cfg.options.requestTimeout = cfg.options.requestTimeout || this.config.requestTimeout != null ? this.config.requestTimeout : 15000
41
41
  cfg.options.tdsVersion = cfg.options.tdsVersion || '7_4'
42
- cfg.options.rowCollectionOnDone = false
43
- cfg.options.rowCollectionOnRequestCompletion = false
44
- cfg.options.useColumnNames = false
42
+ cfg.options.rowCollectionOnDone = cfg.options.rowCollectionOnDone || false
43
+ cfg.options.rowCollectionOnRequestCompletion = cfg.options.rowCollectionOnRequestCompletion || false
44
+ cfg.options.useColumnNames = cfg.options.useColumnNames || false
45
45
  cfg.options.appName = cfg.options.appName || 'node-mssql'
46
46
 
47
47
  // tedious always connect via tcp when port is specified
48
48
  if (cfg.options.instanceName) delete cfg.options.port
49
49
 
50
50
  if (isNaN(cfg.options.requestTimeout)) cfg.options.requestTimeout = 15000
51
- if (cfg.options.requestTimeout === Infinity) cfg.options.requestTimeout = 0
52
- if (cfg.options.requestTimeout < 0) cfg.options.requestTimeout = 0
51
+ if (cfg.options.requestTimeout === Infinity || cfg.options.requestTimeout < 0) cfg.options.requestTimeout = 0
53
52
 
54
- if (this.config.debug) {
53
+ if (!cfg.options.debug && this.config.debug) {
55
54
  cfg.options.debug = {
56
55
  packet: true,
57
56
  token: true,
@@ -73,6 +72,7 @@ class ConnectionPool extends BaseConnectionPool {
73
72
  }
74
73
 
75
74
  debug('connection(%d): established', IDS.get(tedious))
75
+ this.collation = tedious.databaseCollation
76
76
  resolveOnce(tedious)
77
77
  })
78
78
  IDS.add(tedious, 'Connection')
@@ -22,6 +22,13 @@ Object.defineProperty(module.exports, 'Promise', {
22
22
  }
23
23
  })
24
24
 
25
+ Object.defineProperty(module.exports, 'valueHandler', {
26
+ enumerable: true,
27
+ value: base.valueHandler,
28
+ writable: false,
29
+ configurable: false
30
+ })
31
+
25
32
  base.driver.name = 'tedious'
26
33
  base.driver.ConnectionPool = ConnectionPool
27
34
  base.driver.Transaction = Transaction
@@ -8,6 +8,7 @@ const { IDS, objectHasProperty } = require('../utils')
8
8
  const { TYPES, DECLARATIONS, declare, cast } = require('../datatypes')
9
9
  const Table = require('../table')
10
10
  const { PARSERS: UDT } = require('../udt')
11
+ const { valueHandler } = require('../shared')
11
12
 
12
13
  const JSON_COLUMN_ID = 'JSON_F52E2B61-18A1-11d1-B105-00805F49916B'
13
14
  const XML_COLUMN_ID = 'XML_F52E2B61-18A1-11d1-B105-00805F49916B'
@@ -159,7 +160,10 @@ const createColumns = function (metadata, arrayRowMode) {
159
160
  }
160
161
 
161
162
  const valueCorrection = function (value, metadata) {
162
- if ((metadata.type === tds.TYPES.UDT) && (value != null)) {
163
+ const type = getMssqlType(metadata.type)
164
+ if (valueHandler.has(type)) {
165
+ return valueHandler.get(type)(value)
166
+ } else if ((metadata.type === tds.TYPES.UDT) && (value != null)) {
163
167
  if (UDT[metadata.udtInfo.typeName]) {
164
168
  return UDT[metadata.udtInfo.typeName](value)
165
169
  } else {
@@ -213,7 +217,11 @@ class Request extends BaseRequest {
213
217
  super._bulk(table, options, err => {
214
218
  if (err) return callback(err)
215
219
 
216
- table._makeBulk()
220
+ try {
221
+ table._makeBulk()
222
+ } catch (e) {
223
+ return callback(new RequestError(e, 'EREQUEST'))
224
+ }
217
225
 
218
226
  if (!table.name) {
219
227
  return callback(new RequestError('Table name must be specified for bulk insert.', 'ENAME'))
@@ -266,14 +274,21 @@ class Request extends BaseRequest {
266
274
  }
267
275
 
268
276
  this.parent.acquire(this, (err, connection) => {
269
- if (err) return callback(err)
277
+ const callbackWithRelease = (err, ...args) => {
278
+ try {
279
+ this.parent.release(connection)
280
+ } catch (e) {
281
+ // noop
282
+ }
283
+ callback(err, ...args)
284
+ }
285
+ if (err) return callbackWithRelease(err)
270
286
 
271
287
  debug('connection(%d): borrowed to request #%d', IDS.get(connection), IDS.get(this))
272
288
 
273
289
  if (this.canceled) {
274
290
  debug('request(%d): canceled', IDS.get(this))
275
- this.parent.release(connection)
276
- return callback(new RequestError('Canceled.', 'ECANCEL'))
291
+ return callbackWithRelease(new RequestError('Canceled.', 'ECANCEL'))
277
292
  }
278
293
 
279
294
  this._cancel = () => {
@@ -307,13 +322,12 @@ class Request extends BaseRequest {
307
322
  connection.removeListener(event, errorHandlers[event])
308
323
  }
309
324
 
310
- this.parent.release(connection)
311
325
  hasReturned = true
312
326
 
313
327
  if (this.stream) {
314
- callback(null, rowCount)
328
+ callbackWithRelease(null, rowCount)
315
329
  } else {
316
- callback(error, rowCount)
330
+ callbackWithRelease(error, rowCount)
317
331
  }
318
332
  }
319
333
  }
@@ -324,22 +338,18 @@ class Request extends BaseRequest {
324
338
  bulk.addColumn(col.name, getTediousType(col.type), { nullable: col.nullable, length: col.length, scale: col.scale, precision: col.precision })
325
339
  }
326
340
 
327
- for (const row of table.rows) {
328
- bulk.addRow(row)
329
- }
330
-
331
341
  if (table.create) {
332
342
  const objectid = table.temporary ? `tempdb..[${table.name}]` : table.path
333
343
  const req = new tds.Request(`if object_id('${objectid.replace(/'/g, '\'\'')}') is null ${table.declare()}`, err => {
334
344
  if (err) return done(err)
335
345
 
336
- connection.execBulkLoad(bulk)
346
+ connection.execBulkLoad(bulk, table.rows)
337
347
  })
338
348
  this._setCurrentRequest(req)
339
349
 
340
350
  connection.execSqlBatch(req)
341
351
  } else {
342
- connection.execBulkLoad(bulk)
352
+ connection.execBulkLoad(bulk, table.rows)
343
353
  }
344
354
  })
345
355
  })
@@ -594,7 +604,7 @@ class Request extends BaseRequest {
594
604
  row.push(col.value)
595
605
  } else {
596
606
  const exi = row[col.metadata.colName]
597
- if (exi != null) {
607
+ if (exi !== undefined) {
598
608
  if (exi instanceof Array) {
599
609
  exi.push(col.value)
600
610
  } else {
@@ -631,7 +641,7 @@ class Request extends BaseRequest {
631
641
  const param = this.parameters[name]
632
642
 
633
643
  try {
634
- param.value = getTediousType(param.type).validate(param.value)
644
+ param.value = getTediousType(param.type).validate(param.value, this.parent.collation)
635
645
  } catch (e) {
636
646
  e.message = `Validation failed for parameter '${name}'. ${e.message}`
637
647
  const err = new RequestError(e, 'EPARAM')
package/lib/udt.js CHANGED
@@ -53,20 +53,42 @@ class Point {
53
53
  }
54
54
  }
55
55
 
56
- const parsePoints = (buffer, count) => {
56
+ const parsePoints = (buffer, count, isGeometryPoint) => {
57
57
  // s2.1.5 + s2.1.6
58
+ // The key distinction for parsing is that a GEOGRAPHY POINT is ordered Lat (y) then Long (x),
59
+ // while a GEOMETRY POINT is ordered x then y.
60
+ // Further, there are additional range constraints on GEOGRAPHY POINT that are useful for testing that the coordinate order has not been flipped, such as that Lat must be in the range [-90, +90].
58
61
 
59
62
  const points = []
60
63
  if (count < 1) {
61
64
  return points
62
65
  }
63
66
 
64
- for (let i = 1; i <= count; i++) {
65
- const point = new Point()
66
- points.push(point)
67
- point.x = buffer.readDoubleLE(buffer.position)
68
- point.y = buffer.readDoubleLE(buffer.position + 8)
69
- buffer.position += 16
67
+ if (isGeometryPoint) {
68
+ // GEOMETRY POINT (s2.1.6): x then y.
69
+ for (let i = 1; i <= count; i++) {
70
+ const point = new Point()
71
+ points.push(point)
72
+ point.x = buffer.readDoubleLE(buffer.position)
73
+ point.y = buffer.readDoubleLE(buffer.position + 8)
74
+ buffer.position += 16
75
+ }
76
+ } else {
77
+ // GEOGRAPHY POINT (s2.1.5): Lat (y) then Long (x).
78
+ for (let i = 1; i <= count; i++) {
79
+ const point = new Point()
80
+ points.push(point)
81
+ point.lat = buffer.readDoubleLE(buffer.position)
82
+ point.lng = buffer.readDoubleLE(buffer.position + 8)
83
+
84
+ // For backwards compatibility, preserve the coordinate inversion in x and y.
85
+ // A future breaking change likely eliminate x and y for geography points in favor of just the lat and lng fields, as they've proven marvelously confusing.
86
+ // See discussion at: https://github.com/tediousjs/node-mssql/pull/1282#discussion_r677769531
87
+ point.x = point.lat
88
+ point.y = point.lng
89
+
90
+ buffer.position += 16
91
+ }
70
92
  }
71
93
 
72
94
  return points
@@ -182,7 +204,7 @@ const parseSegments = (buffer, count) => {
182
204
  return segments
183
205
  }
184
206
 
185
- const parseGeography = buffer => {
207
+ const parseGeography = (buffer, isUsingGeometryPoints) => {
186
208
  // s2.1.1 + s.2.1.2
187
209
 
188
210
  const srid = buffer.readInt32LE(0)
@@ -227,7 +249,7 @@ const parseGeography = buffer => {
227
249
 
228
250
  // console.log("numberOfPoints", numberOfPoints)
229
251
 
230
- value.points = parsePoints(buffer, numberOfPoints)
252
+ value.points = parsePoints(buffer, numberOfPoints, isUsingGeometryPoints)
231
253
 
232
254
  if (properties.Z) {
233
255
  parseZ(buffer, value.points)
@@ -289,10 +311,10 @@ const parseGeography = buffer => {
289
311
 
290
312
  module.exports.PARSERS = {
291
313
  geography (buffer) {
292
- return parseGeography(buffer)
314
+ return parseGeography(buffer, /* isUsingGeometryPoints: */false)
293
315
  },
294
316
 
295
317
  geometry (buffer) {
296
- return parseGeography(buffer)
318
+ return parseGeography(buffer, /* isUsingGeometryPoints: */true)
297
319
  }
298
320
  }
package/package.json CHANGED
@@ -21,20 +21,20 @@
21
21
  "azure",
22
22
  "node-mssql"
23
23
  ],
24
- "version": "7.1.3",
24
+ "version": "8.0.0",
25
25
  "main": "index.js",
26
26
  "repository": "github:tediousjs/node-mssql",
27
27
  "license": "MIT",
28
28
  "dependencies": {
29
29
  "@tediousjs/connection-string": "^0.3.0",
30
- "debug": "^4",
30
+ "debug": "^4.3.3",
31
31
  "rfdc": "^1.3.0",
32
- "tarn": "^3.0.1",
33
- "tedious": "^11.0.7"
32
+ "tarn": "^3.0.2",
33
+ "tedious": "^14.0.0"
34
34
  },
35
35
  "devDependencies": {
36
- "mocha": "^8.3.2",
37
- "standard": "^16.0.3"
36
+ "mocha": "^9.1.3",
37
+ "standard": "^16.0.4"
38
38
  },
39
39
  "engines": {
40
40
  "node": ">=10"
package/test.js CHANGED
@@ -20,28 +20,21 @@ const sqlConfig = {
20
20
  },
21
21
  port: 1433,
22
22
  user: 'sa',
23
- server: 'localhost'
24
- };
23
+ server: 'localhost',
24
+ arrayRowMode: true
25
+ }
25
26
 
26
- (async () => {
27
- const pool = new mssql.ConnectionPool(sqlConfig)
28
- try {
29
- await pool.connect();
30
-
31
- const request = pool.request();
32
- request.arrayRowMode = true;
33
- request.multiple = true;
34
-
35
- const result = await request.batch('SELECT 1;');
36
-
37
- Object.entries(result.recordset.columns).forEach(([key, value]) => {
38
- console.log(`Column: ${key}, ${JSON.stringify(value)}`);
39
- });
40
- } catch (err) {
41
- console.error(err)
42
- } finally {
43
- console.log('closing pool')
44
- await pool.close()
45
- console.log('closed')
46
- }
47
- })()
27
+ mssql.connect(sqlConfig).then((pool) => {
28
+ console.log('Connected to SQL server')
29
+ const request = pool.request()
30
+ request.stream = true
31
+ request.on('error', (err) => {
32
+ console.error('good', err)
33
+ })
34
+ return request.query('SELECT * FROM nontable')
35
+ }).catch((err) => {
36
+ console.error('bad', err)
37
+ }).then(() => {
38
+ console.log('Disconnecting from SQL server')
39
+ return mssql.close()
40
+ }).then(() => console.log('Disconnected'))