teradata-nodejs-driver-temp-fork1
Version:
Teradata Database Node.js Driver
642 lines • 28.2 kB
JavaScript
"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