Skip to content

Commit

Permalink
fix: treat bigint as string in msnodesqlv8 driver
Browse files Browse the repository at this point in the history
BigInt types will lose precision if they are above the MAX_SAFE_INTEGER
value. A work around for this is to use strings to represent the numbers
instead.
  • Loading branch information
dhensby committed Sep 4, 2023
1 parent b5cf976 commit bd791d4
Show file tree
Hide file tree
Showing 8 changed files with 79 additions and 38 deletions.
6 changes: 5 additions & 1 deletion CHANGELOG.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
Unreleased
-------------------
[fix] BigInt type in nodemsqlv8 now treated as strings in parity with the tedious drive ([#1387](https://github.com/tediousjs/node-mssql/pull/1387))

v9.1.3 (2023-??-??)
-------------------
[fix] Escape values that are added to the msnodesqlv8 connection string that we construct ((#1479)[https://github.com/tediousjs/node-mssql/pull/1479])
Expand Down Expand Up @@ -44,7 +48,7 @@ v8.1.1 (2022-05-18)

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

v8.0.2 (2022-02-07)
Expand Down
2 changes: 2 additions & 0 deletions lib/msnodesqlv8/connection-pool.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ class ConnectionPool extends BaseConnectionPool {
return reject(err)
}

tds.setUseNumericString(true)

IDS.add(tds, 'Connection', connedtionId)
tds.setUseUTC(this.config.options.useUTC)
debug('connection(%d): established', IDS.get(tds))
Expand Down
2 changes: 1 addition & 1 deletion lib/msnodesqlv8/request.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ const castParameter = function (value, type) {
case TYPES.NChar:
case TYPES.Xml:
case TYPES.Text:
case TYPES.BigInt:
case TYPES.NText:
if ((typeof value !== 'string') && !(value instanceof String)) {
value = value.toString()
Expand All @@ -39,7 +40,6 @@ const castParameter = function (value, type) {

case TYPES.Int:
case TYPES.TinyInt:
case TYPES.BigInt:
case TYPES.SmallInt:
if ((typeof value !== 'number') && !(value instanceof Number)) {
value = parseInt(value)
Expand Down
3 changes: 3 additions & 0 deletions test/cleanup.sql
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ if exists (select * from sys.tables where name = 'bulk_table5')
if exists (select * from sys.tables where name = 'rowsaffected_test')
exec('drop table [dbo].[rowsaffected_test]')

if exists (select * from sys.tables where name = 'bignumbers')
exec('drop table [dbo].[bignumbers]')

if exists (select * from sys.tables where name = 'streaming')
exec('drop table [dbo].[streaming]')

24 changes: 24 additions & 0 deletions test/common/tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -1276,6 +1276,30 @@ module.exports = (sql, driver) => {
}).catch(done)
},

'BigInt parameters' (done) {
const req = new TestRequest()
req.input('bignumber', sql.BigInt, '9223372036854775807')
req.query('INSERT INTO [dbo].[bignumbers] (bignumber) VALUES (@bignumber)')
.then(() => {
const req2 = new TestRequest()
return req2.query('SELECT * FROM [dbo].[bignumbers]')
})
.then((result) => {
assert.strictEqual(result.recordsets.length, 1)
assert.strictEqual(result.recordset[0].bignumber, '9223372036854775807')
done()
})
.catch(done)
},

'BigInt casted types' (done) {
const req = new TestRequest()
req.query('SELECT cast(9223372036854775807 AS BigInt) as bignumber').then(result => {
assert.strictEqual(result.recordset[0].bignumber, '9223372036854775807')
done()
}).catch(done)
},

'dataLength type correction' (done) {
sql.on('error', err => console.error(err))
const req = new TestRequest()
Expand Down
38 changes: 20 additions & 18 deletions test/msnodesqlv8/msnodesqlv8.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ const sql = require('../../msnodesqlv8')
const TESTS = require('../common/tests.js')(sql, 'msnodesqlv8')
const TIMES = require('../common/times.js')(sql, 'msnodesqlv8')
const versionHelper = require('../common/versionhelper')
const { readFileSync } = require('fs')

const config = function () {
const cfg = JSON.parse(require('fs').readFileSync(join(__dirname, '../.mssql.json')))
const cfg = JSON.parse(readFileSync(join(__dirname, '../.mssql.json')))
cfg.driver = 'msnodesqlv8'
return cfg
}
Expand All @@ -19,23 +20,22 @@ let connection1 = null
let connection2 = null

describe('msnodesqlv8', function () {
before(done =>
sql.connect(config(), function (err) {
if (err) return done(err)

let req = new sql.Request()
req.batch(require('fs').readFileSync(join(__dirname, '../cleanup.sql'), 'utf8'), function (err) {
if (err) return done(err)

req = new sql.Request()
req.batch(require('fs').readFileSync(join(__dirname, '../prepare.sql'), 'utf8'), function (err) {
if (err) return done(err)

sql.close(done)
before(done => {
try {
sql.connect(config())
.then(() => {
return new sql.Request().query(readFileSync(join(__dirname, '../cleanup.sql'), 'utf8'))
})
})
})
)
.then(() => {
return new sql.Request().query(readFileSync(join(__dirname, '../prepare.sql'), 'utf8'))
})
.catch(done)
.then(() => sql.close())
.then(() => done())
} catch (e) {
done(e)
}
})
afterEach(() => sql.valueHandler.clear())

describe('basic test suite', function () {
Expand Down Expand Up @@ -91,6 +91,8 @@ describe('msnodesqlv8', function () {
it('connection healthy works', done => TESTS['connection healthy works'](config(), done))
it('healthy connection goes bad', done => TESTS['healthy connection goes bad'](config(), done))
it('request timeout', done => TESTS['request timeout'](done))
it('BigInt parameters', done => TESTS['BigInt parameters'](done))
it('BigInt casted types', done => TESTS['BigInt casted types'](done))
it('dataLength type correction', done => TESTS['dataLength type correction'](done))
it('chunked xml support', done => TESTS['chunked xml support'](done))

Expand Down Expand Up @@ -245,7 +247,7 @@ describe('msnodesqlv8', function () {
if (err) return done(err)

const req = new sql.Request()
req.query(require('fs').readFileSync(join(__dirname, '../cleanup.sql'), 'utf8'), function (err) {
req.query(readFileSync(join(__dirname, '../cleanup.sql'), 'utf8'), function (err) {
if (err) return done(err)

sql.close(done)
Expand Down
4 changes: 4 additions & 0 deletions test/prepare.sql
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,10 @@ exec('create table [dbo].[rowsaffected_test] (
a int not null
)')

exec('create table [dbo].[bignumbers] (
bignumber bigint
)')

;with nums as
(
select 0 AS n
Expand Down
38 changes: 20 additions & 18 deletions test/tedious/tedious.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
const sql = require('../../tedious.js')
const assert = require('assert')
const { join } = require('path')
const { readFileSync } = require('fs')

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

const config = function () {
const cfg = JSON.parse(require('fs').readFileSync(join(__dirname, '../.mssql.json')))
const cfg = JSON.parse(readFileSync(join(__dirname, '../.mssql.json')))
cfg.driver = 'tedious'
return cfg
}
Expand All @@ -25,23 +26,22 @@ let connection1 = null
let connection2 = null

describe('tedious', () => {
before(done =>
sql.connect(config(), err => {
if (err) return done(err)

let req = new sql.Request()
req.query(require('fs').readFileSync(join(__dirname, '../cleanup.sql'), 'utf8'), err => {
if (err) return done(err)

req = new sql.Request()
req.query(require('fs').readFileSync(join(__dirname, '../prepare.sql'), 'utf8'), err => {
if (err) return done(err)

sql.close(done)
before(done => {
try {
sql.connect(config())
.then(() => {
return new sql.Request().query(readFileSync(join(__dirname, '../cleanup.sql'), 'utf8'))
})
})
})
)
.then(() => {
return new sql.Request().query(readFileSync(join(__dirname, '../prepare.sql'), 'utf8'))
})
.catch(done)
.then(() => sql.close())
.then(() => done())
} catch (e) {
done(e)
}
})
afterEach(() => sql.valueHandler.clear())

describe('basic test suite', () => {
Expand Down Expand Up @@ -100,6 +100,8 @@ describe('tedious', () => {
it('connection healthy works', done => TESTS['connection healthy works'](config(), done))
it('healthy connection goes bad', done => TESTS['healthy connection goes bad'](config(), done))
it('request timeout', done => TESTS['request timeout'](done, 'tedious', /Timeout: Request failed to complete in 1000ms/))
it('BigInt parameters', done => TESTS['BigInt parameters'](done))
it('BigInt casted types', done => TESTS['BigInt casted types'](done))
it('dataLength type correction', done => TESTS['dataLength type correction'](done))
it('type validation', done => TESTS['type validation']('query', done))
it('type validation (batch)', done => TESTS['type validation']('batch', done))
Expand Down Expand Up @@ -345,7 +347,7 @@ describe('tedious', () => {
if (err) return done(err)

const req = new sql.Request()
req.query(require('fs').readFileSync(join(__dirname, '../cleanup.sql'), 'utf8'), function (err) {
req.query(readFileSync(join(__dirname, '../cleanup.sql'), 'utf8'), function (err) {
if (err) return done(err)

sql.close(done)
Expand Down

0 comments on commit bd791d4

Please sign in to comment.