Skip to content

Commit 99f5c7f

Browse files
authored
Merge pull request #1387 from dhensby/pulls/bigint-msnodesql
treat bigint as string in msnodesqlv8 driver
2 parents 62f73bc + 9541bb8 commit 99f5c7f

8 files changed

Lines changed: 91 additions & 38 deletions

File tree

CHANGELOG.txt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
The changelog is not currently maintained. Please see the [releases](https://github.com/tediousjs/node-mssql/releases) for change details.
44

5+
Unreleased
6+
-------------------
7+
[fix] BigInt type in nodemsqlv8 now treated as strings in parity with the tedious driver ([#1387](https://github.com/tediousjs/node-mssql/pull/1387))
8+
59
v11.0.1 (2024-07-03)
610
--------------------
711
[fix] handle bigint types separately to int to avoid TypeError with BigInt param ([#1677](https://github.com/tediousjs/node-mssql/pull/1677))
@@ -98,7 +102,7 @@ v8.1.1 (2022-05-18)
98102

99103
v8.1.0 (2022-04-06)
100104
-------------------
101-
[new] MSSQL CLI tool now accepts some options to allow overriding config file ((#1381](https://github.com/tediousjs/node-mssql/pull/1381))
105+
[new] MSSQL CLI tool now accepts some options to allow overriding config file ([#1381](https://github.com/tediousjs/node-mssql/pull/1381))
102106
[fix] nodemsqlv8 driver tests working against Node 10 ([#1368](https://github.com/tediousjs/node-mssql/pull/1368))
103107

104108
v8.0.2 (2022-02-07)

lib/msnodesqlv8/connection-pool.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ class ConnectionPool extends BaseConnectionPool {
4747
return reject(err)
4848
}
4949

50+
tds.setUseNumericString(true)
51+
5052
IDS.add(tds, 'Connection', connedtionId)
5153
tds.setUseUTC(this.config.options.useUTC)
5254
debug('connection(%d): established', IDS.get(tds))

lib/msnodesqlv8/request.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ const castParameter = function (value, type) {
3131
case TYPES.NChar:
3232
case TYPES.Xml:
3333
case TYPES.Text:
34+
case TYPES.BigInt:
3435
case TYPES.NText:
3536
if ((typeof value !== 'string') && !(value instanceof String)) {
3637
value = value.toString()
@@ -39,7 +40,6 @@ const castParameter = function (value, type) {
3940

4041
case TYPES.Int:
4142
case TYPES.TinyInt:
42-
case TYPES.BigInt:
4343
case TYPES.SmallInt:
4444
if ((typeof value !== 'number') && !(value instanceof Number)) {
4545
value = parseInt(value)
@@ -122,6 +122,8 @@ const createColumns = function (metadata, arrayRowMode) {
122122
return out
123123
}
124124

125+
const numericStringSqlTypes = new Set(['int', 'smallint', 'tinyint', 'float', 'real', 'numeric', 'decimal', 'money', 'smallmoney'])
126+
125127
const valueCorrection = function (value, metadata) {
126128
const type = metadata && objectHasProperty(metadata, 'sqlType') && objectHasProperty(DECLARATIONS, metadata.sqlType)
127129
? DECLARATIONS[metadata.sqlType]
@@ -137,6 +139,10 @@ const valueCorrection = function (value, metadata) {
137139
} else {
138140
return value
139141
}
142+
} else if (typeof value === 'string' && numericStringSqlTypes.has(metadata.sqlType)) {
143+
return Number(value)
144+
} else if (typeof value === 'string' && metadata.sqlType === 'sql_variant' && value !== '' && !isNaN(Number(value))) {
145+
return Number(value)
140146
} else {
141147
return value
142148
}
@@ -177,13 +183,19 @@ class Request extends BaseRequest {
177183
return callback(new RequestError('Canceled.', 'ECANCEL'))
178184
}
179185

186+
// Disable useNumericString during bulk operations to avoid
187+
// msnodesqlv8 SQL generation bugs with its table manager
188+
connection.setUseNumericString(false)
189+
180190
const done = (err, rowCount) => {
181191
if (hasReturned) {
182192
return
183193
}
184194

185195
hasReturned = true
186196

197+
connection.setUseNumericString(true)
198+
187199
if (err) {
188200
if ((typeof err.sqlstate === 'string') && (err.sqlstate.toLowerCase() === '08s01')) {
189201
connection.hasError = true

test/cleanup.sql

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ if exists (select * from sys.tables where name = 'bulk_table5')
5252
if exists (select * from sys.tables where name = 'rowsaffected_test')
5353
exec('drop table [dbo].[rowsaffected_test]')
5454

55+
if exists (select * from sys.tables where name = 'bignumbers')
56+
exec('drop table [dbo].[bignumbers]')
57+
5558
if exists (select * from sys.tables where name = 'streaming')
5659
exec('drop table [dbo].[streaming]')
5760

test/common/tests.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1281,6 +1281,30 @@ module.exports = (sql, driver) => {
12811281
}).catch(done)
12821282
},
12831283

1284+
'BigInt parameters' (done) {
1285+
const req = new TestRequest()
1286+
req.input('bignumber', sql.BigInt, '9223372036854775807')
1287+
req.query('INSERT INTO [dbo].[bignumbers] (bignumber) VALUES (@bignumber)')
1288+
.then(() => {
1289+
const req2 = new TestRequest()
1290+
return req2.query('SELECT * FROM [dbo].[bignumbers]')
1291+
})
1292+
.then((result) => {
1293+
assert.strictEqual(result.recordsets.length, 1)
1294+
assert.strictEqual(result.recordset[0].bignumber, '9223372036854775807')
1295+
done()
1296+
})
1297+
.catch(done)
1298+
},
1299+
1300+
'BigInt casted types' (done) {
1301+
const req = new TestRequest()
1302+
req.query('SELECT cast(9223372036854775807 AS BigInt) as bignumber').then(result => {
1303+
assert.strictEqual(result.recordset[0].bignumber, '9223372036854775807')
1304+
done()
1305+
}).catch(done)
1306+
},
1307+
12841308
'dataLength type correction' (done) {
12851309
sql.on('error', err => console.error(err))
12861310
const req = new TestRequest()

test/msnodesqlv8/msnodesqlv8.js

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@ const sql = require('../../msnodesqlv8')
88
const TESTS = require('../common/tests.js')(sql, 'msnodesqlv8')
99
const TIMES = require('../common/times.js')(sql, 'msnodesqlv8')
1010
const versionHelper = require('../common/versionhelper')
11+
const { readFileSync } = require('node:fs')
1112

1213
const config = function () {
13-
const cfg = JSON.parse(require('node:fs').readFileSync(join(__dirname, '../.mssql.json')))
14+
const cfg = JSON.parse(readFileSync(join(__dirname, '../.mssql.json')))
1415
cfg.driver = 'msnodesqlv8'
1516
return cfg
1617
}
@@ -19,23 +20,22 @@ let connection1 = null
1920
let connection2 = null
2021

2122
describe('msnodesqlv8', function () {
22-
before(done =>
23-
sql.connect(config(), function (err) {
24-
if (err) return done(err)
25-
26-
let req = new sql.Request()
27-
req.batch(require('node:fs').readFileSync(join(__dirname, '../cleanup.sql'), 'utf8'), function (err) {
28-
if (err) return done(err)
29-
30-
req = new sql.Request()
31-
req.batch(require('node:fs').readFileSync(join(__dirname, '../prepare.sql'), 'utf8'), function (err) {
32-
if (err) return done(err)
33-
34-
sql.close(done)
23+
before(done => {
24+
try {
25+
sql.connect(config())
26+
.then(() => {
27+
return new sql.Request().query(readFileSync(join(__dirname, '../cleanup.sql'), 'utf8'))
3528
})
36-
})
37-
})
38-
)
29+
.then(() => {
30+
return new sql.Request().query(readFileSync(join(__dirname, '../prepare.sql'), 'utf8'))
31+
})
32+
.catch(done)
33+
.then(() => sql.close())
34+
.then(() => done())
35+
} catch (e) {
36+
done(e)
37+
}
38+
})
3939
afterEach(() => sql.valueHandler.clear())
4040

4141
describe('basic test suite', function () {
@@ -92,6 +92,8 @@ describe('msnodesqlv8', function () {
9292
it('connection healthy works', done => TESTS['connection healthy works'](config(), done))
9393
it('healthy connection goes bad', done => TESTS['healthy connection goes bad'](config(), done))
9494
it('request timeout', done => TESTS['request timeout'](done))
95+
it('BigInt parameters', done => TESTS['BigInt parameters'](done))
96+
it('BigInt casted types', done => TESTS['BigInt casted types'](done))
9597
it('dataLength type correction', done => TESTS['dataLength type correction'](done))
9698
it('chunked xml support', done => TESTS['chunked xml support'](done))
9799

@@ -281,7 +283,7 @@ describe('msnodesqlv8', function () {
281283
if (err) return done(err)
282284

283285
const req = new sql.Request()
284-
req.query(require('node:fs').readFileSync(join(__dirname, '../cleanup.sql'), 'utf8'), function (err) {
286+
req.query(readFileSync(join(__dirname, '../cleanup.sql'), 'utf8'), function (err) {
285287
if (err) return done(err)
286288

287289
sql.close(done)

test/prepare.sql

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,10 @@ exec('create table [dbo].[rowsaffected_test] (
145145
a int not null
146146
)')
147147

148+
exec('create table [dbo].[bignumbers] (
149+
bignumber bigint
150+
)')
151+
148152
;with nums as
149153
(
150154
select 0 AS n

test/tedious/tedious.js

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
const sql = require('../../tedious.js')
66
const assert = require('node:assert')
77
const { join } = require('node:path')
8+
const { readFileSync } = require('node:fs')
89

910
const TESTS = require('../common/tests.js')(sql, 'tedious')
1011
const TIMES = require('../common/times.js')(sql, 'tedious')
@@ -16,7 +17,7 @@ if (parseInt(process.version.match(/^v(\d+)\./)[1]) > 0) {
1617
}
1718

1819
const config = function () {
19-
const cfg = JSON.parse(require('node:fs').readFileSync(join(__dirname, '../.mssql.json')))
20+
const cfg = JSON.parse(readFileSync(join(__dirname, '../.mssql.json')))
2021
cfg.driver = 'tedious'
2122
return cfg
2223
}
@@ -25,23 +26,22 @@ let connection1 = null
2526
let connection2 = null
2627

2728
describe('tedious', () => {
28-
before(done =>
29-
sql.connect(config(), err => {
30-
if (err) return done(err)
31-
32-
let req = new sql.Request()
33-
req.query(require('node:fs').readFileSync(join(__dirname, '../cleanup.sql'), 'utf8'), err => {
34-
if (err) return done(err)
35-
36-
req = new sql.Request()
37-
req.query(require('node:fs').readFileSync(join(__dirname, '../prepare.sql'), 'utf8'), err => {
38-
if (err) return done(err)
39-
40-
sql.close(done)
29+
before(done => {
30+
try {
31+
sql.connect(config())
32+
.then(() => {
33+
return new sql.Request().query(readFileSync(join(__dirname, '../cleanup.sql'), 'utf8'))
4134
})
42-
})
43-
})
44-
)
35+
.then(() => {
36+
return new sql.Request().query(readFileSync(join(__dirname, '../prepare.sql'), 'utf8'))
37+
})
38+
.catch(done)
39+
.then(() => sql.close())
40+
.then(() => done())
41+
} catch (e) {
42+
done(e)
43+
}
44+
})
4545
afterEach(() => sql.valueHandler.clear())
4646

4747
describe('basic test suite', () => {
@@ -101,6 +101,8 @@ describe('tedious', () => {
101101
it('connection healthy works', done => TESTS['connection healthy works'](config(), done))
102102
it('healthy connection goes bad', done => TESTS['healthy connection goes bad'](config(), done))
103103
it('request timeout', done => TESTS['request timeout'](done, 'tedious', /Timeout: Request failed to complete in 1000ms/))
104+
it('BigInt parameters', done => TESTS['BigInt parameters'](done))
105+
it('BigInt casted types', done => TESTS['BigInt casted types'](done))
104106
it('dataLength type correction', done => TESTS['dataLength type correction'](done))
105107
it('type validation', done => TESTS['type validation']('query', done))
106108
it('type validation (batch)', done => TESTS['type validation']('batch', done))
@@ -346,7 +348,7 @@ describe('tedious', () => {
346348
if (err) return done(err)
347349

348350
const req = new sql.Request()
349-
req.query(require('node:fs').readFileSync(join(__dirname, '../cleanup.sql'), 'utf8'), function (err) {
351+
req.query(readFileSync(join(__dirname, '../cleanup.sql'), 'utf8'), function (err) {
350352
if (err) return done(err)
351353

352354
sql.close(done)

0 commit comments

Comments
 (0)