tedious
Version:
A TDS driver, for connecting to MS SQLServer databases.
174 lines (152 loc) • 4.96 kB
JavaScript
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
});
});
});
});
});
});
});
});
});
});
}
;