Permalink
Browse files

Added support for TDS 7.1 login and SQLBatch

This can be enabled on the connection with config.options.tdsVersion = "7_1"

Note that connection.execSQL is not working so there may be a problem
with RPC requests.  I added a note about this to the minimal.js example.

Fixes #38
  • Loading branch information...
1 parent 7f33ffe commit d58aa2630b2723b3aa74dd9e37222949d2f9b9f6 @pdodde pdodde committed with pekim Jun 11, 2012
View
@@ -56,5 +56,6 @@ function executeStatement() {
console.log(rowCount + ' rows returned');
});
+ // In SQL Server 2000 you may need: connection.execSqlBatch(request);
connection.execSql(request);
}
View
@@ -21,6 +21,7 @@ DEFAULT_CANCEL_TIMEOUT = 5 * 1000
DEFAULT_PACKET_SIZE = 4 * 1024
DEFAULT_TEXTSIZE = '2147483647'
DEFAULT_PORT = 1433
+DEFAULT_TDS_VERSION = '7_2'
class Connection extends EventEmitter
STATE:
@@ -133,6 +134,7 @@ class Connection extends EventEmitter
@config.options.requestTimeout ||= DEFAULT_CLIENT_REQUEST_TIMEOUT
@config.options.cancelTimeout ||= DEFAULT_CANCEL_TIMEOUT
@config.options.packetSize ||= DEFAULT_PACKET_SIZE
+ @config.options.tdsVersion ||= DEFAULT_TDS_VERSION
if !@config.options.port && !@config.options.instanceName
@config.options.port = DEFAULT_PORT
@@ -147,7 +149,7 @@ class Connection extends EventEmitter
)
createTokenStreamParser: ->
- @tokenStreamParser = new TokenStreamParser(@debug)
+ @tokenStreamParser = new TokenStreamParser(@debug, undefined, @config.options.tdsVersion)
@tokenStreamParser.on('infoMessage', (token) =>
@emit('infoMessage', token)
)
@@ -314,6 +316,7 @@ class Connection extends EventEmitter
password: @config.password
database: @config.options.database
packetSize: @config.options.packetSize
+ tdsVersion: @config.options.tdsVersion
payload = new Login7Payload(loginData)
@messageIo.sendMessage(TYPE.LOGIN7, payload.data)
View
@@ -66,8 +66,6 @@ FLAGS_3 =
UNKNOWN_COLLATION_HANDLING: 0x08 # Introduced in TDS 7.3
-DEFAULT_TDS_VERSION = versions['7_2']
-
###
s2.2.6.3
###
@@ -87,7 +85,7 @@ class Login7Payload
@data = data.data
createFixedData: ->
- @tdsVersion = DEFAULT_TDS_VERSION
+ @tdsVersion = versions[@loginData.tdsVersion]
@packetSize = @loginData.packetSize
@clientProgVer = 0
@clientPid = process.pid
@@ -134,10 +132,14 @@ class Login7Payload
buffer.data
createVariableData: (offset) ->
+ @variableLengthsLength = ((9 * 4) + 6 + (3 * 4) + 4)
+ if @loginData.tdsVersion == '7_1'
+ @variableLengthsLength = ((9 * 4) + 6 + (2 * 4))
+
variableData =
offsetsAndLengths: new WritableTrackingBuffer(200)
data: new WritableTrackingBuffer(200, 'ucs2')
- offset: offset + ((9 * 4) + 6 + (3 * 4) + 4)
+ offset: offset + @variableLengthsLength
@hostname = os.hostname()
@@ -165,8 +167,9 @@ class Login7Payload
variableData.offsetsAndLengths.writeBuffer(@clientId)
@addVariableDataString(variableData, @sspi)
@addVariableDataString(variableData, @attachDbFile)
- @addVariableDataString(variableData, @changePassword) # Introduced in TDS 7.2
- variableData.offsetsAndLengths.writeUInt32LE(@sspiLong) # Introduced in TDS 7.2
+ if @loginData.tdsVersion > '7_1'
+ @addVariableDataString(variableData, @changePassword) # Introduced in TDS 7.2
+ variableData.offsetsAndLengths.writeUInt32LE(@sspiLong) # Introduced in TDS 7.2
variableData.offsetsAndLengths.data.concat(variableData.data.data)
@@ -3,8 +3,11 @@ codepageByLcid = require('./collation').codepageByLcid
TYPE = require('./data-type').TYPE
sprintf = require('sprintf').sprintf
-parse = (buffer) ->
- userType = buffer.readUInt32LE()
+parse = (buffer, tdsVersion) ->
+ if tdsVersion < "7_2"
+ userType = buffer.readUInt16LE()
+ else
+ userType = buffer.readUInt32LE()
flags = buffer.readUInt16LE()
typeNumber = buffer.readUInt8()
type = TYPE[typeNumber]
@@ -162,10 +162,12 @@ class PreloginPayload
@version.patch,
@version.trivial,
@version.subbuild,
- @encryption, @encryptionString,
- @instance,
+ if @encryption then @encryption else 0,
+ if @encryptionString then @encryptionString else 0,
+ if @instance then @instance else 0,
if @threadId then @threadId else 0,
- @mars, @marsString
+ if @mars then @mars else 0,
+ if @marsString then @marsString else 0
)
module.exports = PreloginPayload
View
@@ -1,5 +1,6 @@
exports.versions =
+ '7_1': 0x71000001
'7_2': 0x72090002
'7_3_A': 0x730A0003
'7_3_B': 0x730B0003
@@ -2,12 +2,12 @@
metadataParse = require('../metadata-parser')
-parser = (buffer) ->
+parser = (buffer, colMetadata, tdsVersion) ->
columnCount = buffer.readUInt16LE()
columns = []
for c in [1..columnCount]
- metadata = metadataParse(buffer)
+ metadata = metadataParse(buffer, tdsVersion)
if metadata.type.hasTableName
numberOfTableNameParts = buffer.readUInt8()
@@ -10,7 +10,7 @@ STATUS =
ATTN: 0x0020
SRVERROR: 0x0100
-parser = (buffer) ->
+parser = (buffer, tdsVersion) ->
status = buffer.readUInt16LE()
more = !!(status & STATUS.MORE)
@@ -23,7 +23,10 @@ parser = (buffer) ->
curCmd = buffer.readUInt16LE()
# If rowCount > 53 bits then rowCount will be incorrect (because Javascript uses IEEE_754 for number representation).
- rowCount = buffer.readUInt64LE()
+ if tdsVersion < "7_2"
+ rowCount = buffer.readUInt32LE()
+ else
+ rowCount = buffer.readUInt64LE()
if !rowCountValid
rowCount = undefined
@@ -37,22 +40,22 @@ parser = (buffer) ->
rowCount: rowCount
curCmd: curCmd
-doneParser = (buffer) ->
- token = parser(buffer)
+doneParser = (buffer, colMetadata, tdsVersion) ->
+ token = parser(buffer, tdsVersion)
token.name = 'DONE'
token.event = 'done'
token
-doneInProcParser = (buffer) ->
- token = parser(buffer)
+doneInProcParser = (buffer, colMetadata, tdsVersion) ->
+ token = parser(buffer, tdsVersion)
token.name = 'DONEINPROC'
token.event = 'doneInProc'
token
-doneProcParser = (buffer) ->
- token = parser(buffer)
+doneProcParser = (buffer, colMetadata, tdsVersion) ->
+ token = parser(buffer, tdsVersion)
token.name = 'DONEPROC'
token.event = 'doneProc'
@@ -1,14 +1,17 @@
# s2.2.7.9, s2.2.7.10
-parser = (buffer) ->
+parser = (buffer, tdsVersion) ->
length = buffer.readUInt16LE()
number = buffer.readUInt32LE()
state = buffer.readUInt8()
class_ = buffer.readUInt8()
message = buffer.readUsVarchar()
serverName = buffer.readBVarchar()
procName = buffer.readBVarchar()
- lineNumber = buffer.readUInt32LE()
+ if tdsVersion < '7_2'
+ lineNumber = buffer.readUInt16LE()
+ else
+ lineNumber = buffer.readUInt32LE()
token =
number: number
@@ -19,15 +22,15 @@ parser = (buffer) ->
procName: procName
lineNumber: lineNumber
-infoParser = (buffer) ->
- token = parser(buffer)
+infoParser = (buffer, colMetadata, tdsVersion) ->
+ token = parser(buffer, tdsVersion)
token.name = 'INFO'
token.event = 'infoMessage'
token
-errorParser = (buffer) ->
- token = parser(buffer)
+errorParser = (buffer, colMetadata, tdsVersion) ->
+ token = parser(buffer, tdsVersion)
token.name = 'ERROR'
token.event = 'errorMessage'
@@ -3,11 +3,11 @@
metadataParse = require('../metadata-parser')
valueParse = require('../value-parser')
-parser = (buffer) ->
+parser = (buffer, colMetadata, tdsVersion) ->
paramOrdinal = buffer.readUInt16LE()
paramName = buffer.readBVarchar()
status = buffer.readUInt8()
- metadata = metadataParse(buffer)
+ metadata = metadataParse(buffer, tdsVersion)
value = valueParse(buffer, metadata)
if paramName.charAt(0) == '@'
@@ -27,7 +27,7 @@ tokenParsers[TYPE.ROW] = require('./row-token-parser')
parsing resumes.
###
class Parser extends EventEmitter
- constructor: (@debug) ->
+ constructor: (@debug, @colMetadata, @tdsVersion) ->
@buffer = new ReadableTrackingBuffer(new Buffer(0), 'ucs2')
@position = 0
@@ -49,7 +49,7 @@ class Parser extends EventEmitter
type = @buffer.readUInt8()
if tokenParsers[type]
- token = tokenParsers[type](@buffer, @colMetadata)
+ token = tokenParsers[type](@buffer, @colMetadata, @tdsVersion)
if token
@debug.token(token)

0 comments on commit d58aa26

Please sign in to comment.