| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372 |
- "use strict";
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
- exports.default = void 0;
- var _events = require("events");
- var _writableTrackingBuffer = _interopRequireDefault(require("./tracking-buffer/writable-tracking-buffer"));
- var _readableStream = require("readable-stream");
- var _token = require("./token/token");
- var _message = _interopRequireDefault(require("./message"));
- var _packet = require("./packet");
- var _errors = require("./errors");
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
- const FLAGS = {
- nullable: 1 << 0,
- caseSen: 1 << 1,
- updateableReadWrite: 1 << 2,
- updateableUnknown: 1 << 3,
- identity: 1 << 4,
- computed: 1 << 5,
- // introduced in TDS 7.2
- fixedLenCLRType: 1 << 8,
- // introduced in TDS 7.2
- sparseColumnSet: 1 << 10,
- // introduced in TDS 7.3.B
- hidden: 1 << 13,
- // introduced in TDS 7.2
- key: 1 << 14,
- // introduced in TDS 7.2
- nullableUnknown: 1 << 15 // introduced in TDS 7.2
- };
- const DONE_STATUS = {
- FINAL: 0x00,
- MORE: 0x1,
- ERROR: 0x2,
- INXACT: 0x4,
- COUNT: 0x10,
- ATTN: 0x20,
- SRVERROR: 0x100
- };
- class BulkLoad extends _events.EventEmitter {
- constructor(table, connectionOptions, {
- checkConstraints = false,
- fireTriggers = false,
- keepNulls = false,
- lockTable = false
- }, callback) {
- if (typeof checkConstraints !== 'boolean') {
- throw new TypeError('The "options.checkConstraints" property must be of type boolean.');
- }
- if (typeof fireTriggers !== 'boolean') {
- throw new TypeError('The "options.fireTriggers" property must be of type boolean.');
- }
- if (typeof keepNulls !== 'boolean') {
- throw new TypeError('The "options.keepNulls" property must be of type boolean.');
- }
- if (typeof lockTable !== 'boolean') {
- throw new TypeError('The "options.lockTable" property must be of type boolean.');
- }
- super();
- this.error = undefined;
- this.canceled = false;
- this.executionStarted = false;
- this.table = table;
- this.options = connectionOptions;
- this.callback = callback;
- this.columns = [];
- this.columnsByName = {};
- this.firstRowWritten = false;
- this.streamingMode = false;
- this.rowToPacketTransform = new RowTransform(this); // eslint-disable-line no-use-before-define
- this.bulkOptions = {
- checkConstraints,
- fireTriggers,
- keepNulls,
- lockTable
- };
- }
- addColumn(name, type, {
- output = false,
- length,
- precision,
- scale,
- objName = name,
- nullable = true
- }) {
- if (this.firstRowWritten) {
- throw new Error('Columns cannot be added to bulk insert after the first row has been written.');
- }
- if (this.executionStarted) {
- throw new Error('Columns cannot be added to bulk insert after execution has started.');
- }
- const column = {
- type: type,
- name: name,
- value: null,
- output: output,
- length: length,
- precision: precision,
- scale: scale,
- objName: objName,
- nullable: nullable
- };
- if ((type.id & 0x30) === 0x20) {
- if (column.length == null && type.resolveLength) {
- column.length = type.resolveLength(column);
- }
- }
- if (type.resolvePrecision && column.precision == null) {
- column.precision = type.resolvePrecision(column);
- }
- if (type.resolveScale && column.scale == null) {
- column.scale = type.resolveScale(column);
- }
- this.columns.push(column);
- this.columnsByName[name] = column;
- }
- addRow(...input) {
- this.firstRowWritten = true;
- let row;
- if (input.length > 1 || !input[0] || typeof input[0] !== 'object') {
- row = input;
- } else {
- row = input[0];
- } // write each column
- if (Array.isArray(row)) {
- this.rowToPacketTransform.write(row);
- } else {
- const object = row;
- this.rowToPacketTransform.write(this.columns.map(column => {
- return object[column.objName];
- }));
- }
- }
- getOptionsSql() {
- const addOptions = [];
- if (this.bulkOptions.checkConstraints) {
- addOptions.push('CHECK_CONSTRAINTS');
- }
- if (this.bulkOptions.fireTriggers) {
- addOptions.push('FIRE_TRIGGERS');
- }
- if (this.bulkOptions.keepNulls) {
- addOptions.push('KEEP_NULLS');
- }
- if (this.bulkOptions.lockTable) {
- addOptions.push('TABLOCK');
- }
- if (addOptions.length > 0) {
- return ` WITH (${addOptions.join(',')})`;
- } else {
- return '';
- }
- }
- getBulkInsertSql() {
- let sql = 'insert bulk ' + this.table + '(';
- for (let i = 0, len = this.columns.length; i < len; i++) {
- const c = this.columns[i];
- if (i !== 0) {
- sql += ', ';
- }
- sql += '[' + c.name + '] ' + c.type.declaration(c);
- }
- sql += ')';
- sql += this.getOptionsSql();
- return sql;
- }
- getTableCreationSql() {
- let sql = 'CREATE TABLE ' + this.table + '(\n';
- for (let i = 0, len = this.columns.length; i < len; i++) {
- const c = this.columns[i];
- if (i !== 0) {
- sql += ',\n';
- }
- sql += '[' + c.name + '] ' + c.type.declaration(c);
- if (c.nullable !== undefined) {
- sql += ' ' + (c.nullable ? 'NULL' : 'NOT NULL');
- }
- }
- sql += '\n)';
- return sql;
- }
- getColMetaData() {
- const tBuf = new _writableTrackingBuffer.default(100, null, true); // TokenType
- tBuf.writeUInt8(_token.TYPE.COLMETADATA); // Count
- tBuf.writeUInt16LE(this.columns.length);
- for (let j = 0, len = this.columns.length; j < len; j++) {
- const c = this.columns[j]; // UserType
- if (this.options.tdsVersion < '7_2') {
- tBuf.writeUInt16LE(0);
- } else {
- tBuf.writeUInt32LE(0);
- } // Flags
- let flags = FLAGS.updateableReadWrite;
- if (c.nullable) {
- flags |= FLAGS.nullable;
- } else if (c.nullable === undefined && this.options.tdsVersion >= '7_2') {
- flags |= FLAGS.nullableUnknown;
- }
- tBuf.writeUInt16LE(flags); // TYPE_INFO
- c.type.writeTypeInfo(tBuf, c, this.options); // ColName
- tBuf.writeBVarchar(c.name, 'ucs2');
- }
- return tBuf.data;
- }
- setTimeout(timeout) {
- this.timeout = timeout;
- }
- createDoneToken() {
- // It might be nice to make DoneToken a class if anything needs to create them, but for now, just do it here
- const tBuf = new _writableTrackingBuffer.default(this.options.tdsVersion < '7_2' ? 9 : 13);
- tBuf.writeUInt8(_token.TYPE.DONE);
- const status = DONE_STATUS.FINAL;
- tBuf.writeUInt16LE(status);
- tBuf.writeUInt16LE(0); // CurCmd (TDS ignores this)
- tBuf.writeUInt32LE(0); // row count - doesn't really matter
- if (this.options.tdsVersion >= '7_2') {
- tBuf.writeUInt32LE(0); // row count is 64 bits in >= TDS 7.2
- }
- return tBuf.data;
- } // This method switches the BulkLoad object into streaming mode and returns
- // a stream.Writable for streaming rows to the server.
- getRowStream() {
- if (this.firstRowWritten) {
- throw new Error('BulkLoad cannot be switched to streaming mode after first row has been written using addRow().');
- }
- if (this.executionStarted) {
- throw new Error('BulkLoad cannot be switched to streaming mode after execution has started.');
- }
- this.streamingMode = true;
- return this.rowToPacketTransform;
- }
- getMessageStream() {
- const message = new _message.default({
- type: _packet.TYPE.BULK_LOAD
- });
- this.rowToPacketTransform.pipe(message);
- this.rowToPacketTransform.once('finish', () => {
- this.removeListener('cancel', onCancel);
- });
- const onCancel = () => {
- this.rowToPacketTransform.emit('error', (0, _errors.RequestError)('Canceled.', 'ECANCEL'));
- this.rowToPacketTransform.destroy();
- };
- this.once('cancel', onCancel);
- return message;
- }
- cancel() {
- if (this.canceled) {
- return;
- }
- this.canceled = true;
- this.emit('cancel');
- }
- }
- var _default = BulkLoad;
- exports.default = _default;
- module.exports = BulkLoad; // A transform that converts rows to packets.
- class RowTransform extends _readableStream.Transform {
- constructor(bulkLoad) {
- super({
- writableObjectMode: true
- });
- this.bulkLoad = bulkLoad;
- this.mainOptions = bulkLoad.options;
- this.columns = bulkLoad.columns;
- this.columnMetadataWritten = false;
- }
- _transform(row, _encoding, callback) {
- if (!this.columnMetadataWritten) {
- this.push(this.bulkLoad.getColMetaData());
- this.columnMetadataWritten = true;
- }
- const buf = new _writableTrackingBuffer.default(64, 'ucs2', true);
- buf.writeUInt8(_token.TYPE.ROW);
- for (let i = 0; i < this.columns.length; i++) {
- const c = this.columns[i];
- c.type.writeParameterData(buf, {
- length: c.length,
- scale: c.scale,
- precision: c.precision,
- value: row[i]
- }, this.mainOptions, () => {});
- }
- this.push(buf.data);
- process.nextTick(callback);
- }
- _flush(callback) {
- this.push(this.bulkLoad.createDoneToken());
- process.nextTick(callback);
- }
- }
|