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.
- package/CHANGELOG.txt +24 -2
- package/README.md +187 -228
- package/lib/base/connection-pool.js +5 -5
- package/lib/base/index.js +7 -0
- package/lib/msnodesqlv8/connection-pool.js +4 -2
- package/lib/msnodesqlv8/index.js +7 -0
- package/lib/msnodesqlv8/request.js +26 -4
- package/lib/shared.js +7 -0
- package/lib/table.js +7 -0
- package/lib/tedious/connection-pool.js +10 -10
- package/lib/tedious/index.js +7 -0
- package/lib/tedious/request.js +26 -16
- package/lib/udt.js +33 -11
- package/package.json +6 -6
- package/test.js +17 -24
- package/lib/connectionstring.js +0 -289
- package/test2.js +0 -211
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
package/lib/table.js
CHANGED
|
@@ -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')
|
package/lib/tedious/index.js
CHANGED
|
@@ -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
|
package/lib/tedious/request.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
328
|
+
callbackWithRelease(null, rowCount)
|
|
315
329
|
} else {
|
|
316
|
-
|
|
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
|
|
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
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
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": "
|
|
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.
|
|
33
|
-
"tedious": "^
|
|
32
|
+
"tarn": "^3.0.2",
|
|
33
|
+
"tedious": "^14.0.0"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
|
-
"mocha": "^
|
|
37
|
-
"standard": "^16.0.
|
|
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
|
-
(
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
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'))
|