Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 26 additions & 25 deletions src/tokens/colmetadata/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,19 @@ class ColumnData {
_tableNameParts: number
tableName: Array<string>

nullable: boolean
caseSensitive: boolean
updateable: ?boolean
identity: boolean

computed: ?boolean
sparseColumnSet: ?boolean
encrypted: ?boolean
fixedLenCLRType: ?boolean
hidden: ?boolean
key: ?boolean
nullableUnknown: ?boolean
flags: {
nullable: boolean,
caseSensitive: boolean,
updateable: ?string,
identity: boolean,
computed: ?boolean,
fixedLenCLRType: ?boolean,
sparseColumnSet: ?boolean,
encrypted: ?boolean,
hidden: ?boolean,
key: ?boolean,
nullableUnknown: ?boolean
}

typeInfo: ?TypeInfo

Expand All @@ -30,19 +31,19 @@ class ColumnData {
this.tableName = [];
this._tableNameParts = 0;

this.nullable = false;
this.caseSensitive = false;
this.updateable = undefined;
this.identity = false;

this.computed = undefined;
this.sparseColumnSet = undefined;
this.encrypted = undefined;
this.fixedLenCLRType = undefined;
this.hidden = undefined;
this.key = undefined;
this.nullableUnknown = undefined;

this.flags = {
nullable: false,
caseSensitive: false,
updateable: undefined,
identity: false,
computed: undefined,
fixedLenCLRType: undefined,
sparseColumnSet: undefined,
encrypted: undefined,
hidden: undefined,
key: undefined,
nullableUnknown: undefined
};
this.typeInfo = undefined;
}
}
Expand Down
49 changes: 18 additions & 31 deletions src/tokens/colmetadata/read.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,47 +72,33 @@ function parseUserType_7_2(reader: Reader) {
}

function parseFlags(reader: Reader) {
if (reader.version < 0x72090002) {
return parseFlags_7_0;
} else if (reader.version < 0x74000004) {
return parseFlags_7_2;
} else {
return parseFlags_7_4;
}
}

function parseFlags_7_0(reader: Reader) {
if (!reader.bytesAvailable(2)) {
return;
}

// TODO: Implement flag parsing
const flags = reader.readUInt16LE(0); // eslint-disable-line no-unused-vars
reader.consumeBytes(2);

return parseTypeInfo;
}
const column: ColumnData = reader.stash[reader.stash.length - 1];
const flagParser = new FlagParser(flags);
column.flags.nullable = flagParser.nullable();
column.flags.caseSensitive = flagParser.caseSensitive();
column.flags.updateable = flagParser.updateable();
column.flags.identity = flagParser.identity();

function parseFlags_7_2(reader: Reader) {
if (!reader.bytesAvailable(2)) {
return;
if (reader.version >= 0x74000004) {
column.flags.encrypted = flagParser.encrypted();
}

// TODO: Implement flag parsing
const flags = reader.readUInt16LE(0); // eslint-disable-line no-unused-vars
reader.consumeBytes(2);

return parseTypeInfo;
}

function parseFlags_7_4(reader: Reader) {
if (!reader.bytesAvailable(2)) {
return;
if (reader.version >= 0x730B0003) {
column.flags.sparseColumnSet = flagParser.sparseColumnSet();
}
if (reader.version >= 0x72090002) {
column.flags.computed = flagParser.computed();
column.flags.fixedLenCLRType = flagParser.fixedLenCLRType();
column.flags.hidden = flagParser.hidden();
column.flags.key = flagParser.key();
column.flags.nullableUnknown = flagParser.nullableUnknown();
}

// TODO: Implement flag parsing
const flags = reader.readUInt16LE(0); // eslint-disable-line no-unused-vars
reader.consumeBytes(2);

return parseTypeInfo;
}
Expand Down Expand Up @@ -214,3 +200,4 @@ module.exports = readColmetadataToken;
const ColmetadataToken = require('.');
const ColumnData = ColmetadataToken.ColumnData;
const { readTypeInfo } = require('../../types');
const { FlagParser } = require('../parserUtil');
64 changes: 64 additions & 0 deletions src/tokens/parserUtil.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/* @flow */

// FlagParser can be used for TVP_COLMETADATA, ALTMETADATA, COLMETADATA, RETURNVALUE parsing
class FlagParser {
flags: number

constructor(flags: number) {
this.flags = flags;
}

nullable() {
return 0x0001 == (this.flags & 0x0001);
}

caseSensitive() {
return 0x0002 == (this.flags & 0x0002);
}

updateable() {
const value = (this.flags >> 2) & 0x0003;
switch (value) {
case 0:
return 'READ-ONLY';
case 1:
return 'READ-WRITE';
case 2:
return 'UNKNOWN';
}
}

identity() {
return 0x0010 == (this.flags & 0x0010);
}

computed() {
return 0x0020 == (this.flags & 0x0020);
}

fixedLenCLRType() {
return 0x0100 == (this.flags & 0x0100);
}

sparseColumnSet() {
return 0x0400 == (this.flags & 0x0400);
}

encrypted() {
return 0x0800 == (this.flags & 0x0800);
}

hidden() {
return 0x2000 == (this.flags & 0x2000);
}

key() {
return 0x4000 == (this.flags & 0x4000);
}

nullableUnknown() {
return 0x8000 == (this.flags & 0x8000);
}
}

module.exports.FlagParser = FlagParser;
114 changes: 112 additions & 2 deletions test/colmetadata-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

const assert = require('chai').assert;
const Reader = require('../src').Reader;
const ColmetadataToken = require('../src/tokens/colmetadata');

describe('Parsing a COLMETADATA token', function() {
describe('in TDS 7.0 mode', function() {
Expand All @@ -20,7 +21,7 @@ describe('Parsing a COLMETADATA token', function() {
data.writeUInt16LE(2, 3);

// Flags
data.writeUInt16LE(3, 5);
data.writeUInt16LE(7, 5);

// Type
data.writeUInt8(0x30, 7);
Expand Down Expand Up @@ -57,6 +58,29 @@ describe('Parsing a COLMETADATA token', function() {

reader.end(data);
});


it('should parse flags correctly', function(done) {
let token = {};

reader.on('data', function(colToken) {
assert.instanceOf(colToken, ColmetadataToken);
token = colToken;
});

reader.on('end', function() {
const column = token.columns[0];
const flags = column.flags;
assert.isTrue(flags.nullable);
assert.isTrue(flags.caseSensitive);
assert.strictEqual('READ-WRITE', flags.updateable);
assert.isNotTrue(flags.identity);

done();
});

reader.end(data);
});
});

describe('in TDS 7.1 mode', function() {
Expand Down Expand Up @@ -130,7 +154,7 @@ describe('Parsing a COLMETADATA token', function() {
data.writeUInt32LE(2, 3);

// Flags
data.writeUInt16LE(3, 7);
data.writeUInt16LE(0xC139, 7);

// Type
data.writeUInt8(0x30, 9);
Expand Down Expand Up @@ -167,5 +191,91 @@ describe('Parsing a COLMETADATA token', function() {

reader.end(data);
});

it('should parse flags correctly', function(done) {
let token = {};

reader.on('data', function(colToken) {
assert.instanceOf(colToken, ColmetadataToken);
token = colToken;
});

reader.on('end', function() {
const column = token.columns[0];
const flags = column.flags;
assert.isTrue(flags.nullable);
assert.isNotTrue(flags.caseSensitive);
assert.strictEqual('UNKNOWN', flags.updateable);
assert.isTrue(flags.identity);
assert.isTrue(flags.computed);
assert.isTrue(flags.fixedLenCLRType);
assert.isNotTrue(flags.hidden);
assert.isTrue(flags.key);
assert.isTrue(flags.nullableUnknown);

done();
});

reader.end(data);
});

});

describe('in TDS 7.4 mode', function() {
let reader, data;

beforeEach(function() {
reader = new Reader(0x74000004);

data = Buffer.alloc(19);
data.writeUInt8(0x81, 0);

// Number of columns
data.writeUInt16LE(1, 1);

// UserType
data.writeUInt32LE(2, 3);

// Flags
data.writeUInt16LE(0xAC02, 7);

// Type
data.writeUInt8(0x30, 9);

// ColName
data.writeUInt8(4, 10);
data.write('test', 11, 8, 'ucs2');
});

it('should parse flags correctly', function(done) {
let token = {};

reader.on('data', function(colToken) {
assert.instanceOf(colToken, ColmetadataToken);
token = colToken;
});

reader.on('end', function() {
const column = token.columns[0];
const flags = column.flags;
assert.isNotTrue(flags.nullable);
assert.isTrue(flags.caseSensitive);
assert.strictEqual('READ-ONLY', flags.updateable);
assert.isNotTrue(flags.identity);
assert.isNotTrue(flags.computed);
assert.isNotTrue(flags.fixedLenCLRType);
assert.isTrue(flags.sparseColumnSet);
assert.isTrue(flags.encrypted);
assert.isTrue(flags.hidden);
assert.isNotTrue(flags.key);
assert.isTrue(flags.nullableUnknown);

done();
});

reader.end(data);
});

});

});