UNPKG

tedious

Version:

A TDS driver, for connecting to MS SQLServer databases.

174 lines (152 loc) 4.96 kB
"use strict"; const codepageBySortId = require('./collation').codepageBySortId; const codepageByLcid = require('./collation').codepageByLcid; const TYPE = require('./data-type').TYPE; const sprintf = require('sprintf-js').sprintf; module.exports = metadataParse; module.exports.readPrecision = readPrecision; module.exports.readScale = readScale; module.exports.readCollation = readCollation; function readDataLength(parser, type, callback) { if ((type.id & 0x30) === 0x20) { // xx10xxxx - s2.2.4.2.1.3 // Variable length if (type.dataLengthFromScale) { return callback(0); // dataLength is resolved from scale } else if (type.fixedDataLength) { return callback(type.fixedDataLength); } switch (type.dataLengthLength) { case 0: return callback(undefined); case 1: return parser.readUInt8(callback); case 2: return parser.readUInt16LE(callback); case 4: return parser.readUInt32LE(callback); default: return parser.emit(new Error('Unsupported dataLengthLength ' + type.dataLengthLength + ' for data type ' + type.name)); } } else { callback(undefined); } } function readPrecision(parser, type, callback) { if (type.hasPrecision) { parser.readUInt8(callback); } else { callback(undefined); } } function readScale(parser, type, callback) { if (type.hasScale) { parser.readUInt8(callback); } else { callback(undefined); } } function readCollation(parser, type, callback) { if (type.hasCollation) { // s2.2.5.1.2 parser.readBuffer(5, collationData => { const collation = {}; collation.lcid = (collationData[2] & 0x0F) << 16; collation.lcid |= collationData[1] << 8; collation.lcid |= collationData[0]; // This may not be extracting the correct nibbles in the correct order. collation.flags = collationData[3] >> 4; collation.flags |= collationData[2] & 0xF0; // This may not be extracting the correct nibble. collation.version = collationData[3] & 0x0F; collation.sortId = collationData[4]; collation.codepage = codepageBySortId[collation.sortId] || codepageByLcid[collation.lcid] || 'CP1252'; callback(collation); }); } else { callback(undefined); } } function readSchema(parser, type, callback) { if (type.hasSchemaPresent) { // s2.2.5.5.3 parser.readUInt8(schemaPresent => { if (schemaPresent === 0x01) { parser.readBVarChar(dbname => { parser.readBVarChar(owningSchema => { parser.readUsVarChar(xmlSchemaCollection => { callback({ dbname: dbname, owningSchema: owningSchema, xmlSchemaCollection: xmlSchemaCollection }); }); }); }); } else { callback(undefined); } }); } else { callback(undefined); } } function readUDTInfo(parser, type, callback) { if (type.hasUDTInfo) { parser.readUInt16LE(maxByteSize => { parser.readBVarChar(dbname => { parser.readBVarChar(owningSchema => { parser.readBVarChar(typeName => { parser.readUsVarChar(assemblyName => { callback({ maxByteSize: maxByteSize, dbname: dbname, owningSchema: owningSchema, typeName: typeName, assemblyName: assemblyName }); }); }); }); }); }); } else { return callback(); } } function metadataParse(parser, options, callback) { (options.tdsVersion < '7_2' ? parser.readUInt16LE : parser.readUInt32LE).call(parser, userType => { parser.readUInt16LE(flags => { parser.readUInt8(typeNumber => { const type = TYPE[typeNumber]; if (!type) { return parser.emit(new Error(sprintf('Unrecognised data type 0x%02X', typeNumber))); } readDataLength(parser, type, dataLength => { readPrecision(parser, type, precision => { readScale(parser, type, scale => { if (scale && type.dataLengthFromScale) { dataLength = type.dataLengthFromScale(scale); } readCollation(parser, type, collation => { readSchema(parser, type, schema => { readUDTInfo(parser, type, udtInfo => { callback({ userType: userType, flags: flags, type: type, collation: collation, precision: precision, scale: scale, dataLength: dataLength, schema: schema, udtInfo: udtInfo }); }); }); }); }); }); }); }); }); }); }