UNPKG

teradata-nodejs-driver-temp-fork1

Version:
642 lines 28.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.TeradataCursor = void 0; const teradata_logging_1 = require("./teradata-logging"); const teradata_exceptions_1 = require("./teradata-exceptions"); const BINARY = 'Uint8Array'; const DATE = 'Date'; const NUMBER = 'number'; const STRING = 'string'; class TeradataCursor { constructor(connection, ffiLib, ffiRef, ffiByteArray) { this.arraySize = 1; this.rowTerminator = 'Z'; this.conn = connection; this.lib = ffiLib; this.ref = ffiRef; this.byteArray = ffiByteArray; this.logger = new teradata_logging_1.TeradataLogging(this.conn.uLog); this.rowTerminatorTA = new Uint8Array(this.rowTerminator.length); this.rowTerminatorTA[0] = this.rowTerminator.charCodeAt(0); } // getter methods for all DBAPI 2.0 attributes // https://www.python.org/dev/peps/pep-0249/#cursor-attributes get description() { return this.desc; } get rowcount() { return this.rowCount; } get rownumber() { return this.rowNumber; } get connection() { return this.conn; } get uRowsHandle() { return this.uRowsHand; } // All DBAPI 2.0 methods // https://www.python.org/dev/peps/pep-0249/#cursor-methods callproc(procname, parameters) { this.logger.traceLogMessage('entering callproc()'); try { let sCall = '{CALL ' + procname; if (parameters) { sCall += ' ('; for (let i = 0; i < parameters.length; i++) { if (i > 0) { sCall += ','; } sCall += '?'; } sCall += ')'; } sCall += '}'; this.logger.traceLogMessage('sCall=' + sCall); this.execute(sCall, parameters); } finally { this.logger.traceLogMessage('leaving callproc()'); } } close() { this.logger.traceLogMessage('entering close()'); try { const jsgoCloseRows = this.lib.jsgoCloseRows; const jsgoFreePointer = this.lib.jsgoFreePointer; const cStringPtrType = this.ref.refType(this.ref.types.char); const outputPtrPtr = this.ref.alloc(cStringPtrType); jsgoCloseRows(this.conn.uLog, this.uRowsHand, outputPtrPtr); this.uRowsHand = null; // reset uRowsHandle let outputString = this.ref.allocCString(''); outputString = this.ref.deref(outputPtrPtr); if (outputString.length > 0) { let msg = this.ref.readCString(outputString); jsgoFreePointer(this.conn.uLog, outputString); throw new teradata_exceptions_1.OperationalError(msg); } } finally { this.logger.traceLogMessage('leaving close()'); } } execute(operation, parameters) { this.logger.traceLogMessage('entering execute()'); try { if ((parameters === undefined) || (parameters === null)) { this.executemany(operation, null); } else if (Array.isArray(parameters[0])) { this.executemany(operation, parameters); } else { this.executemany(operation, [parameters]); } } finally { this.logger.traceLogMessage('leaving execute()'); } } executemany(procname, seqOfParameters) { this.logger.traceLogMessage('entering executemany()'); this.logger.debugLogMessage(seqOfParameters, true); try { const jsgoCreateRows = this.lib.jsgoCreateRows; const jsgoFreePointer = this.lib.jsgoFreePointer; const procnamePtr = this.ref.allocCString(procname); let abyBindValuesBuffer = Buffer.allocUnsafe(0); if (seqOfParameters !== null) { for (const row of seqOfParameters) { this.logger.debugLogMessage(row, true); let rowBuffer = Buffer.allocUnsafe(0); for (const field of row) { this.logger.debugLogMessage(field, true); let ao = Buffer.allocUnsafe(0); if (field === undefined) { ao = this.serializeNull(); } else if (field === null) { ao = this.serializeNull(); } else if (typeof field === 'number') { ao = this.serializeNumber(field); } else if (typeof field === 'string') { ao = this.serializeString(field); } else if (field instanceof Uint8Array) { ao = this.serializeBytes(field); } else if (field instanceof Date) { ao = this.serializeDate(field); } else { throw new TypeError('Unexpected data type for IMPORT.'); } this.logger.debugLogMessage(ao, true); rowBuffer = Buffer.concat([rowBuffer, ao]); } // end of row rowBuffer = Buffer.concat([rowBuffer, this.rowTerminatorTA]); // end of row terminator this.logger.debugLogMessage(rowBuffer, true); abyBindValuesBuffer = Buffer.concat([abyBindValuesBuffer, rowBuffer]); } // end of all rows } // end if seqOfParameters abyBindValuesBuffer = Buffer.concat([abyBindValuesBuffer, this.rowTerminatorTA]); // end of all rows terminator this.logger.debugLogMessage(abyBindValuesBuffer, true); // Close the current handle *after* the insert row is built/validated. // Othereise, the handle becomes invalid without getting a new handle // if there is an error thrown above. if (this.uRowsHand) { this.close(); } // create Uint8Array from Buffer const arrayBuffer = abyBindValuesBuffer.buffer.slice(abyBindValuesBuffer.byteOffset, abyBindValuesBuffer.byteOffset + abyBindValuesBuffer.length); this.abyBindValues = new Uint8Array(arrayBuffer); for (let i = 0; i < abyBindValuesBuffer.length; ++i) { this.abyBindValues[i] = abyBindValuesBuffer[i]; } const cStringPtrType = this.ref.refType(this.ref.types.char); const outputPtrPtr = this.ref.alloc(cStringPtrType); const rowsHandlePtr = this.ref.alloc(this.ref.types.ulonglong); jsgoCreateRows(this.conn.uLog, this.conn.uPoolHandle, procnamePtr, this.abyBindValues.length, this.abyBindValues, outputPtrPtr, rowsHandlePtr); let outputString = this.ref.allocCString(''); outputString = this.ref.deref(outputPtrPtr); if (outputString.length > 0) { let msg = this.ref.readCString(outputString); jsgoFreePointer(this.conn.uLog, outputString); throw new teradata_exceptions_1.OperationalError(msg); } if (rowsHandlePtr) { this.uRowsHand = this.ref.readUInt64LE(rowsHandlePtr); } else { throw new teradata_exceptions_1.OperationalError('rowsHandlePtr is null.'); } this._obtainResultMetaData(); } finally { this.logger.traceLogMessage('leaving executemany()'); } } // end executemany fetchone() { this.logger.traceLogMessage('entering fetchone()'); try { return this.next(); } catch (error) { if ((error instanceof teradata_exceptions_1.OperationalError) && (error.message === 'StopIteration')) { return null; } else { throw error; } } finally { this.logger.traceLogMessage('leaving fetchone()'); } } fetchmany(nDesiredRowCount) { this.logger.traceLogMessage('entering fetchmany()'); try { if (!nDesiredRowCount) { nDesiredRowCount = this.arraySize; } const rows = new Array(); let nObservedRowCount = 0; let aRow = this.fetchone(); while (aRow) { // while a row is not null rows.push(aRow); nObservedRowCount += 1; if (nObservedRowCount === nDesiredRowCount) { break; } else { aRow = this.fetchone(); } } return rows; } finally { this.logger.traceLogMessage('leaving fetchmany()'); } } fetchall() { this.logger.traceLogMessage('entering fetchall()'); try { const rows = new Array(); let aRow = this.fetchone(); while (aRow) { rows.push(aRow); aRow = this.fetchone(); } return rows; } finally { this.logger.traceLogMessage('leaving fetchall()'); } } nextset() { this.logger.traceLogMessage('entering nextset()'); try { if (this.uRowsHandle) { const jsgoNextResult = this.lib.jsgoNextResult; const jsgoFreePointer = this.lib.jsgoFreePointer; const cStringPtrType = this.ref.refType(this.ref.types.char); const outputPtrPtr = this.ref.alloc(cStringPtrType); const availPtr = this.ref.allocCString('C'); jsgoNextResult(this.conn.uLog, this.uRowsHand, outputPtrPtr, availPtr); let outputString = this.ref.allocCString(''); outputString = this.ref.deref(outputPtrPtr); if (outputString.length > 0) { let msg = this.ref.readCString(outputString); jsgoFreePointer(this.conn.uLog, outputString); throw new teradata_exceptions_1.OperationalError(msg); } if (this.ref.readCString(availPtr) === 'Y') { this._obtainResultMetaData(); return true; } else { this.desc = null; this.rowCount = -1; return false; } } else { return false; } } finally { this.logger.traceLogMessage('leaving nextset()'); } } // end nextset setinputsizes(sizes) { // do something } setoutputsize(size, column) { // do something } next() { this.logger.traceLogMessage('entering next()'); try { if (this.uRowsHandle) { const jsgoFetchRow = this.lib.jsgoFetchRow; const jsgoFreePointer = this.lib.jsgoFreePointer; const cStringPtrType = this.ref.refType(this.ref.types.char); const outputPtrPtr = this.ref.alloc(cStringPtrType); const columnValuesByteCountPtr = this.ref.alloc(this.ref.types.int); const outByteArray = this.ref.refType(this.byteArray); const byteArrayPtrPtr = this.ref.alloc(outByteArray); jsgoFetchRow(this.conn.uLog, this.uRowsHand, outputPtrPtr, columnValuesByteCountPtr, byteArrayPtrPtr); let outputString = this.ref.allocCString(''); outputString = this.ref.deref(outputPtrPtr); if (outputString.length > 0) { let msg = this.ref.readCString(outputString); jsgoFreePointer(this.conn.uLog, outputString); throw new teradata_exceptions_1.OperationalError(msg); } const rowsLength = this.ref.deref(columnValuesByteCountPtr); const byteArrayPtr = this.ref.deref(byteArrayPtrPtr); if (byteArrayPtr.length !== 0) { // indicate there is a row const row = []; let i = 0; const byteBuffer = Buffer.from(this.ref.reinterpret(byteArrayPtr, rowsLength, 0)); while (byteBuffer[i] !== 'Z'.charCodeAt(0)) { // Z=row terminator let iNew = 0; if (byteBuffer[i] === 'B'.charCodeAt(0)) { // B=bytes iNew = this.deserializeBytes(byteBuffer, i, row); } else if (byteBuffer[i] === 'D'.charCodeAt(0)) { // D=double/float iNew = this.deserializeDouble(byteBuffer, i, row); } else if (byteBuffer[i] === 'I'.charCodeAt(0)) { // I=integer iNew = this.deserializeInt(byteBuffer, i, row); } else if (byteBuffer[i] === 'L'.charCodeAt(0)) { // L=long iNew = this.deserializeLong(byteBuffer, i, row); } else if (byteBuffer[i] === 'M'.charCodeAt(0)) { // M=double/float iNew = this.deserializeNumber(byteBuffer, i, row); } else if (byteBuffer[i] === 'N'.charCodeAt(0)) { // N=null iNew = this.deserializeNull(byteBuffer, i, row); } else if (byteBuffer[i] === 'S'.charCodeAt(0)) { // S=string iNew = this.deserializeString(byteBuffer, i, row); } else if (byteBuffer[i] === 'U'.charCodeAt(0)) { // U=date iNew = this.deserializeDate(byteBuffer, i, row); } else if (byteBuffer[i] === 'V'.charCodeAt(0)) { // V=time iNew = this.deserializeTime(byteBuffer, i, row); } else if (byteBuffer[i] === 'W'.charCodeAt(0)) { // W=time with time zone iNew = this.deserializeTimeWithTimeZone(byteBuffer, i, row); } else if (byteBuffer[i] === 'X'.charCodeAt(0)) { // X=timestamp iNew = this.deserializeTimestamp(byteBuffer, i, row); } else if (byteBuffer[i] === 'Y'.charCodeAt(0)) { // Y=timestamp with time zone iNew = this.deserializeTimestampWithTimeZone(byteBuffer, i, row); } else { throw new teradata_exceptions_1.OperationalError('Unknown Data Type:' + String.fromCharCode(byteBuffer[i]) + '.'); } i = iNew; } // end while this.logger.dumpLogMessage(row, true); jsgoFreePointer(this.conn.uLog, byteArrayPtr); return row; } // end if rowsLength > 0 } // end if uRowsHandle // throw StopIteration this.logger.debugLogMessage('End of rows', false); throw new teradata_exceptions_1.OperationalError('StopIteration'); } finally { this.logger.traceLogMessage('leaving next()'); } } // end next _obtainResultMetaData() { this.logger.traceLogMessage('entering _obtainResultMetaData()'); try { const jsgoResultMetaData = this.lib.jsgoResultMetaData; const jsgoFreePointer = this.lib.jsgoFreePointer; const cStringPtrType = this.ref.refType(this.ref.types.char); const outputPtrPtr = this.ref.alloc(cStringPtrType); const metaDataByteCountPtr = this.ref.alloc(this.ref.types.int); const outByteArray = this.ref.refType(this.byteArray); const byteArrayPtrPtr = this.ref.alloc(outByteArray); const uActivityCount = this.ref.alloc(this.ref.types.ulonglong); jsgoResultMetaData(this.conn.uLog, this.uRowsHand, outputPtrPtr, uActivityCount, metaDataByteCountPtr, byteArrayPtrPtr); let outputString = this.ref.allocCString(''); outputString = this.ref.deref(outputPtrPtr); if (outputString.length > 0) { let msg = this.ref.readCString(outputString); jsgoFreePointer(this.conn.uLog, outputString); throw new teradata_exceptions_1.OperationalError(msg); } this.rowCount = this.ref.readUInt64LE(uActivityCount); const byteArrayPtr = this.ref.deref(byteArrayPtrPtr); const metadataLength = this.ref.deref(metaDataByteCountPtr); if (metadataLength > 0) { this.desc = []; let i = 0; const pcColumnMetaData = Buffer.from(this.ref.reinterpret(byteArrayPtr, metadataLength, 0)); while (pcColumnMetaData[i] !== 'Z'.charCodeAt(0)) { // Z=row terminator const columnDesc = []; // (1) Column name i = this.deserializeString(pcColumnMetaData, i, columnDesc); i = this.deserializeString(pcColumnMetaData, i, null); // discard Type name // (2) Type code i = this.deserializeString(pcColumnMetaData, i, columnDesc); if (columnDesc[columnDesc.length - 1] === 'b') { // typeCode b=bytes columnDesc[columnDesc.length - 1] = BINARY; } else if (columnDesc[columnDesc.length - 1] === 'd') { // typeCode d=double columnDesc[columnDesc.length - 1] = NUMBER; } else if ((columnDesc[columnDesc.length - 1] === 'i') || (columnDesc[columnDesc.length - 1] === 'l')) { // typeCode i=integer (int32), l=long (int64) columnDesc[columnDesc.length - 1] = NUMBER; } else if (columnDesc[columnDesc.length - 1] === 'm') { // typeCode m=number columnDesc[columnDesc.length - 1] = NUMBER; } else if (columnDesc[columnDesc.length - 1] === 's') { // typeCode s=string columnDesc[columnDesc.length - 1] = STRING; } else if (columnDesc[columnDesc.length - 1] === 'u') { // typeCode u=date columnDesc[columnDesc.length - 1] = DATE; } else if (columnDesc[columnDesc.length - 1] === 'v' || columnDesc[columnDesc.length - 1] === 'w') { // typeCode v=time, w=time with time zone columnDesc[columnDesc.length - 1] = STRING; } else if (columnDesc[columnDesc.length - 1] === 'x' || columnDesc[columnDesc.length - 1] === 'y') { // typeCode x=timestamp, y=timestamp with time zone columnDesc[columnDesc.length - 1] = STRING; } // (3) Display size columnDesc.push(null); // not provided // (4) Max byte count i = this.deserializeLong(pcColumnMetaData, i, columnDesc); // (5) Precision i = this.deserializeLong(pcColumnMetaData, i, columnDesc); // (6) Scale i = this.deserializeLong(pcColumnMetaData, i, columnDesc); // (7) Nullable i = this.deserializeBool(pcColumnMetaData, i, columnDesc); this.logger.dumpLogMessage(columnDesc, false); this.desc.push(columnDesc); } // end while jsgoFreePointer(this.conn.uLog, byteArrayPtr); } // end if rowsLength > 0 } finally { this.logger.traceLogMessage('leaving _obtainResultMetaData()'); } } deserializeBool(pc, i, row) { this.logger.debugLogMessage('deserializing bool'); if ((pc[i] === 'T'.charCodeAt(0)) || (pc[i] === 'F'.charCodeAt(0))) { // T=true, F=false if (row) { row.push((pc[i] === 'T'.charCodeAt(0))); } return i + 1; } else if (pc[i] === 'N'.charCodeAt(0)) { // N=null return this.deserializeNull(pc, i, row); } else { throw new teradata_exceptions_1.OperationalError('Expected column type T/F/N.'); } } deserializeBytes(pc, i, row) { this.logger.debugLogMessage('deserializing bytes'); if (pc[i] === 'B'.charCodeAt(0)) { // B=bytes i += 1; const uFourByte = pc.readUInt32BE(i); if (uFourByte > 0) { throw new teradata_exceptions_1.DriverError('Field length > 2^32 not supported.'); } i += 4; const uByteCount = pc.readUInt32BE(i); i += 4; const abyBuffer = pc.slice(i, i + uByteCount); const abyValue = new Uint8Array(abyBuffer); i += uByteCount; if (row) { row.push(abyValue); } return i; } else if (pc[i] === 'N'.charCodeAt(0)) { // N=null return this.deserializeNull(pc, i, row); } else { throw new teradata_exceptions_1.OperationalError('Expected column type B/N.'); } } deserializeCharacterValue(abyTypeCode, pc, i, row) { if (pc[i] === abyTypeCode) { i += 1; const uFourByte = pc.readUInt32BE(i); if (uFourByte > 0) { throw new teradata_exceptions_1.DriverError('Field length > 2^32 not supported.'); } i += 4; const uByteCount = pc.readUInt32BE(i); i += 4; const sValue = pc.toString('utf8', i, i + uByteCount); i += uByteCount; if (row) { if (abyTypeCode === 'M'.charCodeAt(0)) { // M=number row.push(Number(sValue)); } else if (abyTypeCode === 'U'.charCodeAt(0)) { // U=date row.push(new Date(sValue)); } else { row.push(sValue); } } return i; } else if (pc[i] === 'N'.charCodeAt(0)) { // N=null return this.deserializeNull(pc, i, row); } else { throw new teradata_exceptions_1.OperationalError('Expected column type ' + String.fromCharCode(abyTypeCode) + '/N.'); } } deserializeDate(pc, i, row) { this.logger.debugLogMessage('deserializing date'); return this.deserializeCharacterValue('U'.charCodeAt(0), pc, i, row); } deserializeDouble(pc, i, row) { this.logger.debugLogMessage('deserializing double'); if (pc[i] === 'D'.charCodeAt(0)) { // D=double/float i += 1; const dValue = pc.readDoubleBE(i); i += 8; if (row) { row.push(dValue); } return i; } else if (pc[i] === 'N'.charCodeAt(0)) { // N=null return this.deserializeNull(pc, i, row); } else { throw new teradata_exceptions_1.OperationalError('Expected column type D/N.'); } } deserializeInt(pc, i, row) { this.logger.debugLogMessage('deserializing int'); if (pc[i] === 'I'.charCodeAt(0)) { // I=integer i += 1; const nValue = pc.readInt32BE(i); i += 4; if (row) { row.push(nValue); } return i; } else if (pc[i] === 'N'.charCodeAt(0)) { // N=null return this.deserializeNull(pc, i, row); } else { throw new teradata_exceptions_1.OperationalError('Expected column type I/N.'); } } deserializeLong(pc, i, row) { this.logger.debugLogMessage('deserializing long'); return this.deserializeCharacterValue('L'.charCodeAt(0), pc, i, row); } deserializeNull(pc, i, row) { this.logger.debugLogMessage('deserializing null'); if (pc[i] === 'N'.charCodeAt(0)) { // N=null if (row) { row.push(null); } return i + 1; } else { throw new teradata_exceptions_1.OperationalError('Expected column type N.'); } } deserializeNumber(pc, i, row) { this.logger.debugLogMessage('deserializing number'); return this.deserializeCharacterValue('M'.charCodeAt(0), pc, i, row); } deserializeString(pc, i, row) { this.logger.debugLogMessage('deserializing string'); return this.deserializeCharacterValue('S'.charCodeAt(0), pc, i, row); } deserializeTime(pc, i, row) { this.logger.debugLogMessage('deserializing time'); return this.deserializeCharacterValue('V'.charCodeAt(0), pc, i, row); } deserializeTimeWithTimeZone(pc, i, row) { this.logger.debugLogMessage('deserializing time with time zone'); return this.deserializeCharacterValue('W'.charCodeAt(0), pc, i, row); } deserializeTimestamp(pc, i, row) { this.logger.debugLogMessage('deserializing timestamp'); return this.deserializeCharacterValue('X'.charCodeAt(0), pc, i, row); } deserializeTimestampWithTimeZone(pc, i, row) { this.logger.debugLogMessage('deserializing timestamp with time zone'); return this.deserializeCharacterValue('Y'.charCodeAt(0), pc, i, row); } serializeBytes(arr) { this.logger.debugLogMessage('serializing bytes'); let ao = Buffer.alloc(9); ao.writeUInt8('B'.charCodeAt(0), 0); if (arr.length > Math.pow(2, 32)) { throw new teradata_exceptions_1.DriverError('Field length > 2^32 not supported.'); } ao.writeUInt32BE(arr.length, 5); const buf = Buffer.from(arr); ao = Buffer.concat([ao, buf]); return ao; } serializeCharacterValue(abyTypeCode, s) { const aby = Buffer.from(s, 'utf8'); let ao = Buffer.alloc(9); ao.writeUInt8(abyTypeCode, 0); if (aby.byteLength > Math.pow(2, 32)) { throw new teradata_exceptions_1.DriverError('Field length > 2^32 not supported.'); } ao.writeUInt32BE(aby.byteLength, 5); ao = Buffer.concat([ao, aby]); return ao; } serializeDate(d) { this.logger.debugLogMessage('serializing date'); const s = d.toISOString().slice(0, 10); // example output: 2011-10-05T14:48:00.000Z return this.serializeCharacterValue('U'.charCodeAt(0), s); } serializeNull() { this.logger.debugLogMessage('serializing null'); const ao = Buffer.alloc(1); ao.writeUInt8('N'.charCodeAt(0), 0); return ao; } serializeNumber(num) { this.logger.debugLogMessage('serializing number'); const ao = Buffer.alloc(9); ao.writeUInt8('D'.charCodeAt(0), 0); ao.writeDoubleBE(num, 1); return ao; } serializeString(s) { this.logger.debugLogMessage('serializing string'); return this.serializeCharacterValue('S'.charCodeAt(0), s); } } exports.TeradataCursor = TeradataCursor; //# sourceMappingURL=teradata-cursor.js.map