UNPKG

node-firebird-driver

Version:
460 lines (452 loc) 20.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.charSets = exports.cancelType = exports.commonInfo = exports.statementInfo = exports.blobInfo = exports.epb = exports.bpb = exports.tpb = exports.dpb = exports.sqlTypes = void 0; exports.createDpb = createDpb; exports.createTpb = createTpb; exports.createBpb = createBpb; exports.getPortableInteger = getPortableInteger; exports.createDataReader = createDataReader; exports.createDataWriter = createDataWriter; const os = require("os"); const littleEndian = os.endianness() === 'LE'; const stringDecoder = require("string_decoder"); const date_time_1 = require("./date-time"); const time_zones_1 = require("./time-zones"); const __1 = require(".."); /** SQL_* type constants */ var sqlTypes; (function (sqlTypes) { sqlTypes.SQL_TEXT = 452; sqlTypes.SQL_VARYING = 448; sqlTypes.SQL_SHORT = 500; sqlTypes.SQL_LONG = 496; sqlTypes.SQL_FLOAT = 482; sqlTypes.SQL_DOUBLE = 480; //export const SQL_D_FLOAT = 530; sqlTypes.SQL_TIMESTAMP = 510; sqlTypes.SQL_BLOB = 520; //export const SQL_ARRAY = 540; //export const SQL_QUAD = 550; sqlTypes.SQL_TYPE_TIME = 560; sqlTypes.SQL_TYPE_DATE = 570; sqlTypes.SQL_INT64 = 580; sqlTypes.SQL_TIMESTAMP_TZ_EX = 32748; sqlTypes.SQL_TIME_TZ_EX = 32750; sqlTypes.SQL_TIMESTAMP_TZ = 32754; sqlTypes.SQL_TIME_TZ = 32756; sqlTypes.SQL_INT128 = 32752; sqlTypes.SQL_DEC16 = 32760; sqlTypes.SQL_DEC34 = 32762; sqlTypes.SQL_BOOLEAN = 32764; sqlTypes.SQL_NULL = 32766; })(sqlTypes || (exports.sqlTypes = sqlTypes = {})); /** DPB constants. */ var dpb; (function (dpb) { /* tslint:disable */ dpb.version1 = 1; dpb.lc_ctype = 48; dpb.force_write = 24; dpb.user_name = 28; dpb.password = 29; dpb.sql_role_name = 60; /* tslint:enable */ })(dpb || (exports.dpb = dpb = {})); /** TPB constants. */ var tpb; (function (tpb) { /* tslint:disable */ tpb.version1 = 1; tpb.consistency = 1; tpb.concurrency = 2; tpb.wait = 6; tpb.nowait = 7; tpb.read = 8; tpb.write = 9; tpb.ignore_limbo = 14; tpb.read_committed = 15; tpb.autocommit = 16; tpb.rec_version = 17; tpb.no_rec_version = 18; tpb.restart_requests = 19; tpb.no_auto_undo = 20; /* tslint:enable */ })(tpb || (exports.tpb = tpb = {})); /** BPB constants. */ var bpb; (function (bpb) { /* tslint:disable */ bpb.version1 = 1; bpb.source_type = 1; bpb.target_type = 2; bpb.type = 3; bpb.source_interp = 4; bpb.target_interp = 5; bpb.filter_parameter = 6; bpb.storage = 7; bpb.type_segmented = 0x0; bpb.type_stream = 0x1; bpb.storage_main = 0x0; bpb.storage_temp = 0x2; /* tslint:enable */ })(bpb || (exports.bpb = bpb = {})); /** EPB constants. */ var epb; (function (epb) { /* tslint:disable */ epb.version1 = 1; /* tslint:enable */ })(epb || (exports.epb = epb = {})); /** Blob info. */ var blobInfo; (function (blobInfo) { blobInfo.totalLength = 6; })(blobInfo || (exports.blobInfo = blobInfo = {})); /** Statement info. */ var statementInfo; (function (statementInfo) { statementInfo.sqlExecPathBlrText = 32; })(statementInfo || (exports.statementInfo = statementInfo = {})); /** Common info. */ var commonInfo; (function (commonInfo) { commonInfo.end = 1; commonInfo.truncated = 2; commonInfo.error = 3; commonInfo.dataNotReady = 4; commonInfo.length = 126; commonInfo.flagEnd = 127; })(commonInfo || (exports.commonInfo = commonInfo = {})); var cancelType; (function (cancelType) { cancelType.disable = 1; cancelType.enable = 2; cancelType.raise = 3; cancelType.abort = 4; })(cancelType || (exports.cancelType = cancelType = {})); var charSets; (function (charSets) { charSets.ascii = 2; })(charSets || (exports.charSets = charSets = {})); function createDpb(options) { const code = (c) => String.fromCharCode(c); const charSet = 'utf8'; let ret = `${code(dpb.version1)}${code(dpb.lc_ctype)}${code(charSet.length)}${charSet}`; if (!options) options = {}; if (!options.username) options.username = process.env.ISC_USER; if (!options.password) options.password = process.env.ISC_PASSWORD; if (options.username) ret += `${code(dpb.user_name)}${code(options.username.length)}${options.username}`; if (options.password) ret += `${code(dpb.password)}${code(options.password.length)}${options.password}`; if (options.role) ret += `${code(dpb.sql_role_name)}${code(options.role.length)}${options.role}`; const createOptions = options; if (createOptions.forcedWrite != undefined) ret += `${code(dpb.force_write)}${code(1)}${code(createOptions.forcedWrite ? 1 : 0)}`; return Buffer.from(ret); } function createTpb(options) { const code = (c) => String.fromCharCode(c); let ret = code(tpb.version1); if (!options) options = {}; switch (options.accessMode) { case 'READ_ONLY': ret += code(tpb.read); break; case 'READ_WRITE': ret += code(tpb.write); break; } switch (options.waitMode) { case 'NO_WAIT': ret += code(tpb.nowait); break; case 'WAIT': ret += code(tpb.wait); break; } switch (options.isolation) { case __1.TransactionIsolation.CONSISTENCY: ret += code(tpb.consistency); break; case __1.TransactionIsolation.SNAPSHOT: ret += code(tpb.concurrency); break; case __1.TransactionIsolation.READ_COMMITTED: ret += code(tpb.read_committed) + code(options.readCommittedMode == 'RECORD_VERSION' ? tpb.rec_version : tpb.no_rec_version); break; } if (options.noAutoUndo) ret += code(tpb.no_auto_undo); if (options.ignoreLimbo) ret += code(tpb.ignore_limbo); if (options.restartRequests) ret += code(tpb.restart_requests); if (options.autoCommit) ret += code(tpb.autocommit); return Buffer.from(ret); } function createBpb(options) { const code = (c) => String.fromCharCode(c); let ret = code(bpb.version1); if (!options) options = {}; switch (options.type) { case 'SEGMENTED': ret += `${code(bpb.type)}${code(1)}${code(bpb.type_segmented)}`; break; case 'STREAM': ret += `${code(bpb.type)}${code(1)}${code(bpb.type_stream)}`; break; } return Buffer.from(ret); } /** Changes a number from a scale to another. */ /*** export function changeScale(value: number, inputScale: number, outputScale: number): number { outputScale -= inputScale; Math.pow(10, outputScale); if (outputScale === 0) return value; else if (outputScale > 0) return value / Math.pow(10, outputScale); else // outputScale < 0 return value * Math.pow(10, -outputScale); } ***/ /** Emulate Firebird isc_portable_integer. */ function getPortableInteger(buffer, length) { if (!buffer || length <= 0 || length > 8) return 0; let value = 0; let pos = 0; for (let shift = 0; --length >= 0; shift += 8) value += buffer[pos++] << shift; return value; } /** Creates a data reader. */ function createDataReader(descriptors) { const mappers = new Array(descriptors.length); for (let i = 0; i < descriptors.length; ++i) { const descriptor = descriptors[i]; mappers[i] = async (attachment, transaction, buffer) => { const dataView = new DataView(buffer.buffer); if (dataView.getInt16(descriptor.nullOffset, littleEndian) == -1) return null; switch (descriptor.type) { // SQL_TEXT is handled changing its descriptor to SQL_VARYING with IMetadataBuilder. case sqlTypes.SQL_VARYING: { //// TODO: none, octets const varLength = dataView.getUint16(descriptor.offset, littleEndian); const decoder = new stringDecoder.StringDecoder('utf8'); const buf = Buffer.from(buffer.buffer, descriptor.offset + 2, varLength); return decoder.end(buf); } /*** case sqlTypes.SQL_SHORT: return changeScale(dataView.getInt16(descriptor.offset, littleEndian), descriptor.scale, 0); case sqlTypes.SQL_LONG: return changeScale(dataView.getInt32(descriptor.offset, littleEndian), descriptor.scale, 0); //// TODO: sqlTypes.SQL_INT64 case sqlTypes.SQL_FLOAT: return dataView.getFloat32(descriptor.offset, littleEndian); ***/ case sqlTypes.SQL_DOUBLE: return dataView.getFloat64(descriptor.offset, littleEndian); case sqlTypes.SQL_TYPE_TIME: { const now = new Date(); const decodedTime = (0, date_time_1.decodeTime)(dataView.getUint32(descriptor.offset, littleEndian)); return new Date(now.getFullYear(), now.getMonth(), now.getDate(), decodedTime.hours, decodedTime.minutes, decodedTime.seconds, decodedTime.fractions / 10); } case sqlTypes.SQL_TIME_TZ_EX: { const now = new Date(); const decodedTime = (0, date_time_1.decodeTime)(dataView.getUint32(descriptor.offset, littleEndian)); const date = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate(), decodedTime.hours, decodedTime.minutes, decodedTime.seconds, decodedTime.fractions / 10)); const timeZone = (0, time_zones_1.tzIdToString)(dataView.getUint16(descriptor.offset + 4, littleEndian)); const offset = dataView.getInt16(descriptor.offset + 6, littleEndian); return { date, timeZone, offset }; } case sqlTypes.SQL_TYPE_DATE: { const decodedDate = (0, date_time_1.decodeDate)(dataView.getInt32(descriptor.offset, littleEndian)); if (decodedDate.year >= 100) return new Date(decodedDate.year, decodedDate.month - 1, decodedDate.day); else { const date = new Date(2000, decodedDate.month - 1, decodedDate.day); date.setFullYear(decodedDate.year); return date; } } case sqlTypes.SQL_TIMESTAMP: { const decodedDate = (0, date_time_1.decodeDate)(dataView.getInt32(descriptor.offset, littleEndian)); const decodedTime = (0, date_time_1.decodeTime)(dataView.getUint32(descriptor.offset + 4, littleEndian)); if (decodedDate.year >= 100) { return new Date(decodedDate.year, decodedDate.month - 1, decodedDate.day, decodedTime.hours, decodedTime.minutes, decodedTime.seconds, decodedTime.fractions / 10); } else { const date = new Date(2000, decodedDate.month - 1, decodedDate.day, decodedTime.hours, decodedTime.minutes, decodedTime.seconds, decodedTime.fractions / 10); date.setFullYear(decodedDate.year); return date; } } case sqlTypes.SQL_TIMESTAMP_TZ_EX: { const decodedDate = (0, date_time_1.decodeDate)(dataView.getInt32(descriptor.offset, littleEndian)); const decodedTime = (0, date_time_1.decodeTime)(dataView.getUint32(descriptor.offset + 4, littleEndian)); const timeZone = (0, time_zones_1.tzIdToString)(dataView.getUint16(descriptor.offset + 8, littleEndian)); const offset = dataView.getInt16(descriptor.offset + 10, littleEndian); let date; if (decodedDate.year >= 100) { date = new Date(Date.UTC(decodedDate.year, decodedDate.month - 1, decodedDate.day, decodedTime.hours, decodedTime.minutes, decodedTime.seconds, decodedTime.fractions / 10)); } else { date = new Date(Date.UTC(2000, decodedDate.month - 1, decodedDate.day, decodedTime.hours, decodedTime.minutes, decodedTime.seconds, decodedTime.fractions / 10)); date.setUTCFullYear(decodedDate.year); } return { date, timeZone, offset }; } case sqlTypes.SQL_BOOLEAN: return dataView.getInt8(descriptor.offset) != 0; case sqlTypes.SQL_BLOB: return new __1.Blob(attachment, buffer.slice(descriptor.offset, descriptor.offset + 8)); case sqlTypes.SQL_NULL: return null; default: throw new Error(`Unrecognized Firebird type number ${descriptor.type}`); } }; } return async (attachment, transaction, buffer) => { return await Promise.all(mappers.map(mapper => mapper(attachment, transaction, buffer))); }; } /** Creates a data writer. */ function createDataWriter(descriptors) { const mappers = new Array(descriptors.length); for (let i = 0; i < descriptors.length; ++i) { const descriptor = descriptors[i]; mappers[i] = async (attachment, transaction, buffer, value) => { const dataView = new DataView(buffer.buffer); if (value == null) { dataView.setInt16(descriptor.nullOffset, -1, littleEndian); return; } dataView.setInt16(descriptor.nullOffset, 0, littleEndian); switch (descriptor.type) { // SQL_TEXT is handled changing its descriptor to SQL_VARYING with IMetadataBuilder. case sqlTypes.SQL_VARYING: { //// TODO: none, octets const str = value; const strBuffer = Buffer.from(str); const bytesArray = Uint8Array.from(strBuffer); if (bytesArray.length > descriptor.length) { throw new Error(`Length in bytes of string '${str}' (${bytesArray.length}) is ` + `greater than maximum expect length ${descriptor.length}.`); } dataView.setUint16(descriptor.offset, bytesArray.length, littleEndian); for (let j = 0; j < bytesArray.length; ++j) buffer[descriptor.offset + 2 + j] = bytesArray[j]; break; } /*** case sqlTypes.SQL_SHORT: dataView.setInt16(descriptor.offset, changeScale(value, 0, descriptor.scale), littleEndian); break; case sqlTypes.SQL_LONG: dataView.setInt32(descriptor.offset, changeScale(value, 0, descriptor.scale), littleEndian); break; //// TODO: sqlTypes.SQL_INT64 case sqlTypes.SQL_FLOAT: dataView.setFloat32(descriptor.offset, value, littleEndian); break; ***/ case sqlTypes.SQL_DOUBLE: dataView.setFloat64(descriptor.offset, value, littleEndian); break; case sqlTypes.SQL_TYPE_TIME: { const date = value; dataView.setUint32(descriptor.offset, (0, date_time_1.encodeTime)(date.getHours(), date.getMinutes(), date.getSeconds(), date.getMilliseconds() * 10), littleEndian); break; } case sqlTypes.SQL_TIME_TZ: case sqlTypes.SQL_TIME_TZ_EX: { const zonedDate = value; dataView.setUint32(descriptor.offset, (0, date_time_1.encodeTime)(zonedDate.date.getUTCHours(), zonedDate.date.getUTCMinutes(), zonedDate.date.getUTCSeconds(), zonedDate.date.getUTCMilliseconds() * 10), littleEndian); dataView.setUint16(descriptor.offset + 4, (0, time_zones_1.tzStringToId)(zonedDate.timeZone), littleEndian); break; } case sqlTypes.SQL_TYPE_DATE: { const date = value; dataView.setInt32(descriptor.offset, (0, date_time_1.encodeDate)(date.getFullYear(), date.getMonth() + 1, date.getDate()), littleEndian); break; } case sqlTypes.SQL_TIMESTAMP: { const date = value; dataView.setInt32(descriptor.offset, (0, date_time_1.encodeDate)(date.getFullYear(), date.getMonth() + 1, date.getDate()), littleEndian); dataView.setUint32(descriptor.offset + 4, (0, date_time_1.encodeTime)(date.getHours(), date.getMinutes(), date.getSeconds(), date.getMilliseconds() * 10), littleEndian); break; } case sqlTypes.SQL_TIMESTAMP_TZ: case sqlTypes.SQL_TIMESTAMP_TZ_EX: { const zonedDate = value; dataView.setInt32(descriptor.offset, (0, date_time_1.encodeDate)(zonedDate.date.getUTCFullYear(), zonedDate.date.getUTCMonth() + 1, zonedDate.date.getUTCDate()), littleEndian); dataView.setUint32(descriptor.offset + 4, (0, date_time_1.encodeTime)(zonedDate.date.getUTCHours(), zonedDate.date.getUTCMinutes(), zonedDate.date.getUTCSeconds(), zonedDate.date.getUTCMilliseconds() * 10), littleEndian); dataView.setUint16(descriptor.offset + 8, (0, time_zones_1.tzStringToId)(zonedDate.timeZone), littleEndian); break; } case sqlTypes.SQL_BOOLEAN: dataView.setInt8(descriptor.offset, value ? 1 : 0); break; case sqlTypes.SQL_BLOB: { const targetBlobId = buffer.subarray(descriptor.offset, descriptor.offset + 8); if (value instanceof __1.BlobStream) value = value.blob; if (value instanceof Buffer) { const blobStream = await attachment.createBlob(transaction); try { await blobStream.write(value); } catch (e) { await blobStream.cancel(); throw e; } await blobStream.close(); targetBlobId.set(blobStream.blob.id); } else if (value instanceof __1.Blob) { if (value.attachment == attachment) targetBlobId.set(value.id); else throw new Error('Cannot pass a BLOB from another attachment as parameter.'); //// TODO: add support for it } else throw new Error('Unrecognized type used as BLOB. Must be: Buffer or Blob.'); break; } case sqlTypes.SQL_NULL: break; default: throw new Error(`Unrecognized Firebird type number ${descriptor.type}`); } }; } return async (attachment, transaction, buffer, values) => { if ((values || []).length !== descriptors.length) throw new Error(`Incorrect number of parameters: expected ${descriptors.length}, received ${(values || []).length}.`); await Promise.all(mappers.map((mapper, index) => mapper(attachment, transaction, buffer, values[index]))); }; } //# sourceMappingURL=fb-util.js.map