Permalink
Browse files

Add support for Numeric/Decimal input parameters

  • Loading branch information...
1 parent b862e7e commit b6907847b40c16322b652bc3c93e45fb2a2dfdfa @patriksimek patriksimek committed Apr 1, 2014
View
@@ -20,7 +20,7 @@ Current version: 0.1.5
- Added support for TDS 7.4
- Added request cancelation
-- Added support for UDT, TVP, Time, Date, DateTime2 and DateTimeOffset data types
+- Added support for UDT, TVP, Time, Date, DateTime2 and DateTimeOffset, Numeric, Decimal data types
- Added option to choose whether to pass/receive times in UTC or local time (`useUTC`)
- Binary, VarBinary and Image are now supported as input parameters
- Binary, VarBinary and Image types are now returned as Buffer (was Array)
View
@@ -168,6 +168,128 @@ TYPE =
buffer.writeDoubleLE(parseFloat(parameter.value))
else
buffer.writeUInt8(0)
+ 0x37:
+ type: 'DECIMAL'
+ name: 'Decimal'
+ hasPrecision: true
+ hasScale: true
+ declaration: (parameter) ->
+ "decimal(#{@resolvePrecision(parameter)}, #{@resolveScale(parameter)})"
+ resolvePrecision: (parameter) ->
+ if parameter.precision?
+ parameter.precision
+ else if parameter.value is null
+ 1
+ else
+ 18
+ resolveScale: (parameter) ->
+ if parameter.scale?
+ parameter.scale
+ else
+ 0
+ writeTypeInfo: (buffer, parameter) ->
+ # ParamMetaData (TYPE_INFO)
+ buffer.writeUInt8 typeByName.DecimalN.id
+
+ if parameter.precision <= 9
+ buffer.writeUInt8 5
+ else if parameter.precision <= 19
+ buffer.writeUInt8 9
+ else if parameter.precision <= 28
+ buffer.writeUInt8 13
+ else
+ buffer.writeUInt8 17
+
+ buffer.writeUInt8 parameter.precision
+ buffer.writeUInt8 parameter.scale
+ writeParameterData: (buffer, parameter) ->
+ # ParamLenData (TYPE_VARBYTE)
+ if parameter.value?
+ sign = if parameter.value < 0 then 0 else 1
+ value = parameter.value * Math.pow 10, parameter.scale
+
+ if parameter.precision <= 9
+ buffer.writeUInt8 5
+ buffer.writeUInt8 sign
+ buffer.writeUInt32LE value
+ else if parameter.precision <= 19
+ buffer.writeUInt8 9
+ buffer.writeUInt8 sign
+ buffer.writeUInt64LE value
+ else if parameter.precision <= 28
+ buffer.writeUInt8 13
+ buffer.writeUInt8 sign
+ buffer.writeUInt64LE value
+ buffer.writeUInt32LE 0x00000000
+ else
+ buffer.writeUInt8 17
+ buffer.writeUInt8 sign
+ buffer.writeUInt64LE value
+ buffer.writeUInt32LE 0x00000000
+ buffer.writeUInt32LE 0x00000000
+ else
+ buffer.writeUInt8 0
+ 0x3F:
+ type: 'NUMERIC'
+ name: 'Numeric'
+ hasPrecision: true
+ hasScale: true
+ declaration: (parameter) ->
+ "numeric(#{@resolvePrecision(parameter)}, #{@resolveScale(parameter)})"
+ resolvePrecision: (parameter) ->
+ if parameter.precision?
+ parameter.precision
+ else if parameter.value is null
+ 1
+ else
+ 18
+ resolveScale: (parameter) ->
+ if parameter.scale?
+ parameter.scale
+ else
+ 0
+ writeTypeInfo: (buffer, parameter) ->
+ # ParamMetaData (TYPE_INFO)
+ buffer.writeUInt8 typeByName.NumericN.id
+
+ if parameter.precision <= 9
+ buffer.writeUInt8 5
+ else if parameter.precision <= 19
+ buffer.writeUInt8 9
+ else if parameter.precision <= 28
+ buffer.writeUInt8 13
+ else
+ buffer.writeUInt8 17
+
+ buffer.writeUInt8 parameter.precision
+ buffer.writeUInt8 parameter.scale
+ writeParameterData: (buffer, parameter) ->
+ # ParamLenData (TYPE_VARBYTE)
+ if parameter.value?
+ sign = if parameter.value < 0 then 0 else 1
+ value = parameter.value * Math.pow 10, parameter.scale
+
+ if parameter.precision <= 9
+ buffer.writeUInt8 5
+ buffer.writeUInt8 sign
+ buffer.writeUInt32LE value
+ else if parameter.precision <= 19
+ buffer.writeUInt8 9
+ buffer.writeUInt8 sign
+ buffer.writeUInt64LE value
+ else if parameter.precision <= 28
+ buffer.writeUInt8 13
+ buffer.writeUInt8 sign
+ buffer.writeUInt64LE value
+ buffer.writeUInt32LE 0x00000000
+ else
+ buffer.writeUInt8 17
+ buffer.writeUInt8 sign
+ buffer.writeUInt64LE value
+ buffer.writeUInt32LE 0x00000000
+ buffer.writeUInt32LE 0x00000000
+ else
+ buffer.writeUInt8 0
0x7A:
type: 'MONEY4'
name: 'SmallMoney'
@@ -324,7 +446,9 @@ TYPE =
else
"varbinary(max)"
resolveLength: (parameter) ->
- if parameter.value?
+ if parameter.length?
+ parameter.length
+ else if parameter.value?
parameter.value.length
else
@maximumLength
@@ -373,7 +497,9 @@ TYPE =
else
"varchar(max)"
resolveLength: (parameter) ->
- if parameter.value?
+ if parameter.length?
+ parameter.length
+ else if parameter.value?
if Buffer.isBuffer parameter.value
parameter.value.length || 1
else
@@ -453,7 +579,9 @@ TYPE =
else
"nvarchar(max)"
resolveLength: (parameter) ->
- if parameter.value?
+ if parameter.length?
+ parameter.length
+ else if parameter.value?
if Buffer.isBuffer parameter.value
(parameter.value.length / 2) || 1
else
@@ -53,11 +53,11 @@ class RpcRequestPayload
if (parameter.type.id & 0x30) == 0x20 # Variable length
param.length = parameter.length ? parameter.type.resolveLength? parameter
- if parameter.type.hasScale
- param.scale = parameter.scale ? parameter.type.resolveScale? parameter
-
if parameter.type.hasPrecision
param.precision = parameter.precision ? parameter.type.resolvePrecision? parameter
+
+ if parameter.type.hasScale
+ param.scale = parameter.scale ? parameter.type.resolveScale? parameter
parameter.type.writeTypeInfo(buffer, param, options)
parameter.type.writeParameterData(buffer, param, options)
@@ -1,5 +1,8 @@
buffertools = require('../buffertools')
+SHIFT_LEFT_32 = (1 << 16) * (1 << 16)
+SHIFT_RIGHT_32 = 1 / SHIFT_LEFT_32
+
###
A Buffer-like class that tracks position.
@@ -85,12 +88,13 @@ class WritableTrackingBuffer
writeUInt40LE: (value) ->
# inspred by https://github.com/dpw/node-buffer-more-ints
- SHIFT_LEFT_32 = (1 << 16) * (1 << 16)
- SHIFT_RIGHT_32 = 1 / SHIFT_LEFT_32
-
@writeInt32LE value & -1
@writeUInt8 Math.floor(value * SHIFT_RIGHT_32)
-
+
+ writeUInt64LE: (value) ->
+ @writeInt32LE value & -1
+ @writeUInt32LE Math.floor(value * SHIFT_RIGHT_32)
+
writeInt8: (value) ->
length = 1
@makeRoomFor(length)
@@ -16,6 +16,9 @@ getConfig = ->
config
+process.on 'uncaughtException', (err) ->
+ console.error err.stack
+
getInstanceName = ->
JSON.parse(fs.readFileSync(process.env.HOME + '/.tedious/test-connection.json', 'utf8')).instanceName
@@ -67,6 +67,18 @@ exports.real = (test) ->
exports.float = (test) ->
execSql(test, TYPES.Float, 9654.2546456567565767644)
+exports.numeric = (test) ->
+ execSql(test, TYPES.Numeric, 5555)
+
+exports.numericLargeValue = (test) ->
+ execSql(test, TYPES.Numeric, 5.555555555555553333, null, {precision: 19, scale: 18})
+
+exports.decimal = (test) ->
+ execSql(test, TYPES.Decimal, 5555)
+
+exports.decimalLargeValue = (test) ->
+ execSql(test, TYPES.Decimal, 5.555555555555553333, null, {precision: 19, scale: 18})
+
exports.uniqueIdentifierN = (test) ->
execSql(test, TYPES.UniqueIdentifierN, '01234567-89AB-CDEF-0123-456789ABCDEF')

0 comments on commit b690784

Please sign in to comment.