UNPKG

teradatasql

Version:
1,014 lines 47 kB
"use strict"; // Copyright 2025 by Teradata Corporation. All Rights Reserved. var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.TeradataCursor = exports.STRING = exports.NUMBER = exports.DATE = exports.BINARY = void 0; const teradata_connection_1 = require("./teradata-connection"); const teradata_exceptions_1 = require("./teradata-exceptions"); const koffi = __importStar(require("koffi")); exports.BINARY = "Uint8Array"; exports.DATE = "Date"; exports.NUMBER = "number"; exports.STRING = "string"; class TeradataCursor { constructor(connection, ffiLib) { this.desc = null; this.colTypeName = null; this.rowCount = 0n; this.rowNumber = null; this.uRowsHandle = null; this.arraySize = 1; this.bClosed = false; this.bInAsyncExecute = false; this.nId = ++TeradataCursor.nInstanceCount; this.conn = connection; this.lib = ffiLib; this.logger = this.conn.logger; } // getter methods for all DBAPI 2.0 attributes // https://www.python.org/dev/peps/pep-0249/#cursor-attributes get Id() { return this.nId; } get description() { return this.desc; } get columntypename() { return this.colTypeName; } get rowcount() { return this.rowCount; } get rownumber() { return this.rowNumber; } get connection() { return this.conn; } get arraysize() { return this.arraySize; } get isAsyncExec() { return this.bInAsyncExecute; } set arraysize(value) { if (Number.isInteger(value) && value > 0) { this.arraySize = value; } else { throw new TypeError(`unexpected value ${value}`); } } // All DBAPI 2.0 methods // https://www.python.org/dev/peps/pep-0249/#cursor-methods callproc(procname, parameters) { this.logger.traceLog("> enter callproc TeradataCursor, bInAsyncExecute=" + this.bInAsyncExecute); try { this._stopIfInAsyncExecute(); this._stopIfClosed(); let sCall = "{CALL " + procname; if (parameters) { sCall += " ("; for (let i = 0; i < parameters.length; i++) { if (i > 0) { sCall += ","; } sCall += "?"; } sCall += ")"; } sCall += "}"; this.logger.traceLog("sCall=" + sCall); this.execute(sCall, parameters); } finally { this.logger.traceLog("< leave callproc TeradataCursor"); } } _stopIfInAsyncExecute() { this.logger.traceLog("> enter _stopIfInAsyncExecute TeradataCursor"); try { // Check if connection has async operation in progress (broadest constraint) if (this.conn.bInAsyncConnect) { this.logger.debugLog(`_stopIfInAsyncExecute: ENFORCEMENT_CHECK cursor_id=${this.nId}, decision=BLOCKED, reason=connection_async_in_progress`); // Connection async operation blocks ANY cursor operation (sync or async) throw new teradata_exceptions_1.ProgrammingError(teradata_connection_1.TeradataConnection.ERROR_803_CONNECTION_ASYNC_IN_PROGRESS); } // Check if this cursor has async operation in progress (most specific to caller) if (this.bInAsyncExecute) { this.logger.debugLog(`_stopIfInAsyncExecute: ENFORCEMENT_CHECK cursor_id=${this.nId}, decision=BLOCKED, reason=this_cursor_async_in_progress`); throw new teradata_exceptions_1.ProgrammingError(teradata_connection_1.TeradataConnection.ERROR_801_CURSOR_SELF_ASYNC_IN_PROGRESS); } // Check if any OTHER cursor on same connection has async operation if (this.conn._hasActiveCursorAsyncOp && this.conn._hasActiveCursorAsyncOp(this)) { this.logger.debugLog(`_stopIfInAsyncExecute: ENFORCEMENT_CHECK cursor_id=${this.nId}, decision=BLOCKED, reason=other_cursor_async_in_progress`); throw new teradata_exceptions_1.ProgrammingError(teradata_connection_1.TeradataConnection.ERROR_802_OTHER_CURSOR_ASYNC_IN_PROGRESS); } // Log allowed decision this.logger.debugLog(`_stopIfInAsyncExecute: ENFORCEMENT_CHECK cursor_id=${this.nId}, decision=ALLOWED, reason=no_async_operations_in_progress`); } finally { this.logger.traceLog("< leave _stopIfInAsyncExecute TeradataCursor"); } } close() { this.logger.traceLog("> enter close TeradataCursor"); this._stopIfInAsyncExecute(); try { if (!this.bClosed) { this._closeRows(); this.bClosed = true; // Unregister cursor from connection's active cursor registry if (typeof this.conn._unregisterCursor === 'function') { this.conn._unregisterCursor(this); } else { // Fail-safe: Log warning if unregister method missing (potential memory leak) this.logger.debugLog(`[Cursor ${this.Id}] WARNING: _unregisterCursor not available on connection - cursor may not be properly cleaned up`); } } } finally { this.logger.traceLog("< leave close TeradataCursor"); } } _stopIfClosed() { this.logger.traceLog("> enter _stopIfClosed TeradataCursor"); try { if (this.bClosed) { throw new teradata_exceptions_1.ProgrammingError("Cursor is closed"); } } finally { this.logger.traceLog("< leave _stopIfClosed TeradataCursor"); } } _closeRows() { this.logger.traceLog("> enter _closeRows TeradataCursor, bInAsyncExecute=" + this.bInAsyncExecute); try { if (this.uRowsHandle) { const dStartTime = Date.now(); let outputPtrPtr = [null]; this.lib.jsgoCloseRows(this.conn.uLog, this.uRowsHandle, outputPtrPtr); this.uRowsHandle = null; // reset uRowsHandle const outputString = outputPtrPtr[0]; if (outputString) { throw new teradata_exceptions_1.OperationalError(outputString); } this.logger.timingLog("_closeRows took " + (Date.now() - dStartTime) + " ms"); } } finally { this.logger.traceLog("< leave _closeRows TeradataCursor"); } } execute(operation, parameters, ignoreErrors = null) { this.logger.traceLog("> enter execute TeradataCursor, bInAsyncExecute=" + this.bInAsyncExecute); try { if (parameters === undefined || parameters === null) { this.executemany(operation, null, ignoreErrors); } else if (Array.isArray(parameters[0])) { this.executemany(operation, parameters, ignoreErrors); } else { this.executemany(operation, [parameters], ignoreErrors); } } finally { this.logger.traceLog("< leave execute TeradataCursor"); } } executemany(procname, seqOfParameters, ignoreErrors = null) { this.logger.traceLog("> enter executemany TeradataCursor, bInAsyncExecute=" + this.bInAsyncExecute); this.logger.debugLog(seqOfParameters, true); try { const dStartTimeBegin = Date.now(); this._stopIfInAsyncExecute(); this._stopIfClosed(); this._closeRows(); if (ignoreErrors !== null) { if (typeof ignoreErrors === "number") { ignoreErrors = [ignoreErrors]; } for (let i = 0; i < ignoreErrors.length; i++) { if (!Number.isInteger(ignoreErrors[i])) { throw new TypeError(`ignoreErrors[${i}] ${ignoreErrors[i]} is not an integer`); } } } else { ignoreErrors = []; } const setIgnoreErrorCodes = [...ignoreErrors]; let dStartTime = Date.now(); const abyBindValuesBuffer = this._buildAbyBindValuesBuffer(seqOfParameters); const abyBindValues = Uint8Array.from(abyBindValuesBuffer); this.logger.debugLog(abyBindValuesBuffer, true); this.logger.timingLog("executemany serialize bind value took " + (Date.now() - dStartTime) + " ms and produced " + abyBindValues.length + " bytes"); dStartTime = Date.now(); let outputPtrPtr = [null]; let rowsHandlePtr = [0]; this.lib.jsgoCreateRows(this.conn.uLog, this.conn.uPoolHandle, procname, abyBindValues.length, abyBindValues, outputPtrPtr, rowsHandlePtr); const outputString = outputPtrPtr[0]; if (outputString) { const regex = /\[Error (\d+)\]/g; const found = outputString.matchAll(regex); const aErrorCodes = []; if (found) { for (const codes of found) { aErrorCodes.push(parseInt(codes[1], 10)); } } let bIgnore = false; for (const errorCode of aErrorCodes) { if (setIgnoreErrorCodes.includes(errorCode)) { bIgnore = true; break; } } this.logger.debugLog(`executemany bIgnore=${bIgnore} aErrorCodes=[${aErrorCodes}] setIgnoreErrorCodes=[${setIgnoreErrorCodes}]`); if (bIgnore) { return; } throw new teradata_exceptions_1.OperationalError(outputString); } this.logger.timingLog("executemany createRows took " + (Date.now() - dStartTime) + " ms"); if (rowsHandlePtr[0] !== 0) { this.uRowsHandle = rowsHandlePtr[0]; } else { throw new teradata_exceptions_1.OperationalError("rowsHandle is 0."); } this._obtainResultMetaData(); this.logger.timingLog("executemany took " + (Date.now() - dStartTimeBegin) + " ms"); } finally { this.logger.traceLog("< leave executemany TeradataCursor"); } } // end executemany async executeAsync(operation, parameters, ignoreErrors = null) { if (parameters === undefined || parameters === null) { return this.executemanyAsync(operation, null, ignoreErrors); } else if (Array.isArray(parameters[0])) { return this.executemanyAsync(operation, parameters, ignoreErrors); } else { return this.executemanyAsync(operation, [parameters], ignoreErrors); } } // end executeAsync async executemanyAsync(procname, seqOfParameters, ignoreErrors = null) { this.logger.traceLog("> enter executemanyAsync TeradataCursor, bInAsyncExecute=" + this.bInAsyncExecute); this.logger.debugLog(seqOfParameters, true); try { this._stopIfInAsyncExecute(); this._stopIfClosed(); this._closeRows(); if (ignoreErrors !== null) { if (typeof ignoreErrors === "number") { ignoreErrors = [ignoreErrors]; } for (let i = 0; i < ignoreErrors.length; i++) { if (!Number.isInteger(ignoreErrors[i])) { throw new TypeError(`ignoreErrors[${i}] ${ignoreErrors[i]} is not an integer`); } } } else { ignoreErrors = []; } const setIgnoreErrorCodes = [...ignoreErrors]; this.bInAsyncExecute = true; // async execute starts const dStartTime = Date.now(); const abyBindValues = await this._buildBindValues(procname, seqOfParameters); await this._createRows(this.conn.uLog, this.conn.uPoolHandle, procname, abyBindValues); let result; const nInterval = 100; // milliseconds while (true) { try { this.logger.traceLog("_pollRows TeradataCursor, bInAsyncExecute=" + this.bInAsyncExecute); result = await this._pollRows(this.conn.uLog, this.conn.uPoolHandle, setIgnoreErrorCodes); this.logger.debugLog(`executemanyAsync _pollRows returned ${result}`); if (typeof result === "number") { if (result !== 0) { this.uRowsHandle = result; // a non-null rowsHandlePtr was returned and the value was read into result break; } else { this.logger.debugLog(`executemanyAsync will retry _pollRows after ${nInterval} ms`); await new Promise((resolve) => setTimeout(resolve, nInterval)); } } else { throw new teradata_exceptions_1.OperationalError(`executemanyAsync expecting number typed result but ${typeof result} typed is received`); } } catch (error) { // Empty string "" is returned by _jsgoPollRows when an error is successfully ignored // This is NOT an error condition - it's a success signal for ignored errors if (error === "") { this.logger.debugLog(`executemanyAsync: Error was successfully ignored (empty string signal from _jsgoPollRows)`); return; } else { throw new teradata_exceptions_1.OperationalError(error); } } } // end infinite loop this._obtainResultMetaData(); this.logger.timingLog("executemanyAsync took " + (Date.now() - dStartTime) + " ms"); } finally { this.bInAsyncExecute = false; // async execute completes this.logger.traceLog("< leave executemanyAsync TeradataCursor, bInAsyncExecute=" + this.bInAsyncExecute); } } // end executemanyAsync fetchone() { this.logger.traceLog("> enter fetchone TeradataCursor, bInAsyncExecute=" + this.bInAsyncExecute); try { this._stopIfInAsyncExecute(); this._stopIfClosed(); const row = this.next(); return row; } catch (error) { if (error instanceof teradata_exceptions_1.OperationalError && error.message === "StopIteration") { return null; } else { throw error; } } finally { this.logger.traceLog("< leave fetchone TeradataCursor"); } } fetchall() { this.logger.traceLog("> enter fetchall TeradataCursor, bInAsyncExecute=" + this.bInAsyncExecute); this._stopIfInAsyncExecute(); this._stopIfClosed(); try { if (this.uRowsHandle) { const dStartTime = Date.now(); let aRow = []; let rows = this.fetchmany_(); while (rows) { aRow = aRow.concat(rows); // [...aRow, ...rows]; rows = this.fetchmany_(); } this.logger.timingLog("fetchall fetched " + aRow.length + " rows and took " + (Date.now() - dStartTime) + " ms"); return aRow; } } finally { this.logger.traceLog("< leave fetchall TeradataCursor"); } return []; } fetchmany(nDesiredRowCount) { this.logger.traceLog("> enter fetchmany TeradataCursor, bInAsyncExecute=" + this.bInAsyncExecute); this._stopIfInAsyncExecute(); this._stopIfClosed(); try { if (this.uRowsHandle) { const result = this.fetchmany_(nDesiredRowCount); if (result) { return result; } } } finally { this.logger.traceLog("< leave fetchmany TeradataCursor"); } return []; } nextset() { this.logger.traceLog("> enter nextset TeradataCursor, bInAsyncExecute=" + this.bInAsyncExecute); try { this._stopIfInAsyncExecute(); this._stopIfClosed(); if (this.uRowsHandle) { const dStartTime = Date.now(); let outputPtrPtr = [null]; let availPtr = ["\0"]; this.lib.jsgoNextResult(this.conn.uLog, this.uRowsHandle, outputPtrPtr, availPtr); const outputString = outputPtrPtr[0]; if (outputString) { throw new teradata_exceptions_1.OperationalError(outputString); } const sAvil = availPtr[0]; this.logger.debugLog(`nextset() sAvil=${sAvil}`); if (sAvil === "Y") { this._obtainResultMetaData(); this.logger.timingLog("nextset() took " + (Date.now() - dStartTime) + " ms"); return true; } else { this.desc = null; this.colTypeName = null; this.rowCount = 0n; this.logger.timingLog("nextset() took " + (Date.now() - dStartTime) + " ms"); return false; } } else { return false; } } finally { this.logger.traceLog("< leave nextset TeradataCursor"); } } // end nextset setinputsizes(sizes) { this._stopIfClosed(); } setoutputsize(size, column) { this._stopIfClosed(); } next() { this.logger.traceLog("> enter next TeradataCursor, bInAsyncExecute=" + this.bInAsyncExecute); try { this._stopIfInAsyncExecute(); this._stopIfClosed(); if (this.uRowsHandle) { const row = this.fetchmany_(1); if (row && row.length > 0) { return row[0]; } } // end if uRowsHandle // throw StopIteration this.logger.debugLog("End of rows"); throw new teradata_exceptions_1.OperationalError("StopIteration"); } finally { this.logger.traceLog("< leave next TeradataCursor"); } } // end next fetchmany_(nDesiredRowCount) { this.logger.traceLog("> enter fetchmany_ TeradataCursor, bInAsyncExecute=" + this.bInAsyncExecute); try { const dStartTimeBegin = Date.now(); this.logger.debugLog(`fetchmany_ nDesiredRowCount=${nDesiredRowCount}`); this.logger.debugLog(`fetchmany_ arraySize=${this.arraySize}`); if (!nDesiredRowCount) { nDesiredRowCount = this.arraySize; } let outputPtrPtr = [null]; let columnValuesByteCountPtr = [0]; let byteArrayPtrPtr = [0]; let dStartTime = Date.now(); this.lib.jsgoFetchRow(this.conn.uLog, this.uRowsHandle, outputPtrPtr, columnValuesByteCountPtr, byteArrayPtrPtr, nDesiredRowCount); this.logger.timingLog("fetchmany_ call to jsgoFetchRow took " + (Date.now() - dStartTime) + " ms"); const outputString = outputPtrPtr[0]; if (outputString) { throw new teradata_exceptions_1.OperationalError(outputString); } dStartTime = Date.now(); const rowsLength = columnValuesByteCountPtr[0]; let nObservedRowCount = 0; dStartTime = Date.now(); if (byteArrayPtrPtr[0] !== null) { this.logger.debugLog(`fetchmany_ rowsLength=${rowsLength}`); const byteArrayPtr = koffi.decode(byteArrayPtrPtr[0], "uint8_t", rowsLength); if (this.logger.bDebugLog) { this.logger.debugLog(byteArrayPtr, true); } const byteBuffer = Buffer.from(byteArrayPtr); const rows = []; let row; let i = 0; while (i < rowsLength - 1) { row = []; while (byteBuffer[i] !== "Z".charCodeAt(0)) { // Z=row terminator let iNew = 0; if (byteBuffer[i] === "S".charCodeAt(0)) { // S=string iNew = this._deserializeString(byteBuffer, i, row); } else if (byteBuffer[i] === "I".charCodeAt(0)) { // I=integer iNew = this._deserializeInt(byteBuffer, i, row); } else if (byteBuffer[i] === "N".charCodeAt(0)) { // N=null iNew = this._deserializeNull(byteBuffer, i, row); } else if (byteBuffer[i] === "D".charCodeAt(0)) { // D=double/float iNew = this._deserializeDouble(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=number iNew = this._deserializeNumber(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 if (byteBuffer[i] === "B".charCodeAt(0)) { // B=bytes iNew = this._deserializeBytes(byteBuffer, i, row); } else { throw new teradata_exceptions_1.OperationalError("Unknown Data Type:" + String.fromCharCode(byteBuffer[i]) + "."); } this.logger.debugLog(`fetchmany_() row[${row.length - 1}], typeCode=${byteBuffer[i].toString()} type=${typeof row[row.length - 1]} value=${row[row.length - 1]}`); if (this.logger.bDebugLog) { this.logger.debugLog("deserialized row:"); this.logger.debugLog(row, true); } i = iNew; } // end while rows.push(row); nObservedRowCount += 1; i += 1; // advance to next row } // end rows this.logger.timingLog("fetchmany_ deserialized " + rowsLength + " bytes and took " + (Date.now() - dStartTime) + " ms"); this.logger.debugLog(`fetchmany_ nObservedRowCount=${nObservedRowCount}`); if (rows.length === 0) { throw new teradata_exceptions_1.OperationalError(`Found no row with byteArrayPtr.length = ${byteArrayPtr.length} `); } this.logger.timingLog("fetchmany_(" + nDesiredRowCount + ") fetched " + nObservedRowCount + " rows and took " + (Date.now() - dStartTimeBegin) + " ms"); return rows; } else { return null; } // end if (byteArrayPtr.length !== 0) } finally { this.logger.traceLog("< leave fetchmany_ TeradataCursor"); } } _buildBindValues(procname, seqOfParameters) { this.logger.traceLog("> enter _buildBindValues TeradataCursor, bInAsyncExecute=" + this.bInAsyncExecute); let dStartTime = Date.now(); const abyBindValuesBuffer = this._buildAbyBindValuesBuffer(seqOfParameters); this.logger.debugLog(abyBindValuesBuffer, true); const abyBindValues = Uint8Array.from(abyBindValuesBuffer); this.logger.timingLog("_buildBindValues serialize bind value took " + (Date.now() - dStartTime) + " ms and produced " + abyBindValues.length + " bytes"); this.logger.traceLog("> leave _buildBindValues TeradataCursor"); return Promise.resolve(abyBindValues); } // end _buildBindValues async _createRows(nLog, nPoolHandle, procname, abyBindValues) { this.logger.traceLog("> enter _createRows TeradataCursor, bInAsyncExecute=" + this.bInAsyncExecute); let dStartTimeBeginning = Date.now(); let outputPtrPtr = [null]; let rowsHandlePtr = [0]; this.lib.jsgoAsyncCreateRows(nLog, nPoolHandle, procname, abyBindValues.length, abyBindValues, outputPtrPtr, rowsHandlePtr); const outputString = outputPtrPtr[0]; if (outputString) { throw new teradata_exceptions_1.OperationalError(outputString); } this.logger.timingLog("_createRows took " + (Date.now() - dStartTimeBeginning) + " ms"); this.logger.traceLog("> leave _createRows TeradataCursor"); } // end _createRows _jsgoPollRows(nLog, nConnHandle, setIgnoreErrorCodes) { this.logger.traceLog("> enter _jsgoPollRows TeradataCursor, bInAsyncExecute=" + this.bInAsyncExecute); let dStartTime = Date.now(); let outputPtrPtr = [null]; let rowsHandlePtr = [0]; this.lib.jsgoPollRows(nLog, nConnHandle, outputPtrPtr, rowsHandlePtr); const outputString = outputPtrPtr[0]; if (outputString) { // Detect error correlation ID const errorMatch = outputString.match(/^\[ERR-(\d+-\d+)\]/); if (errorMatch) { const errorId = errorMatch[0]; this.logger.debugLog(`_jsgoPollRows: received_error error_id=${errorId} from Go layer for connection_handle=${nConnHandle}`); } const regex = /\[Error (\d+)\]/g; const found = outputString.matchAll(regex); const aErrorCodes = []; if (found) { for (const codes of found) { aErrorCodes.push(parseInt(codes[1], 10)); } } let bIgnore = false; for (const errorCode of aErrorCodes) { if (setIgnoreErrorCodes.includes(errorCode)) { bIgnore = true; break; } } this.logger.timingLog("_jsgoPollRows took " + (Date.now() - dStartTime) + " ms"); this.logger.debugLog(`_jsgoPollRows bIgnore=${bIgnore} aErrorCodes=[${aErrorCodes}] setIgnoreErrorCodes=[${setIgnoreErrorCodes}]`); if (!bIgnore) { return outputString; } else { return ""; // indicating error ignored } } this.logger.timingLog("_jsgoPollRows took " + (Date.now() - dStartTime) + " ms"); const nRowsHandle = rowsHandlePtr[0]; if (nRowsHandle !== 0) { this.logger.traceLog(`> leave _jsgoPollRows TeradataCursor, nRowsHandle=${nRowsHandle}`); return nRowsHandle; } this.logger.traceLog("> leave _jsgoPollRows TeradataCursor, the request is still executing."); return 0; // SQL request is still executing } // end _jsgoPollRows _pollRows(nLog, nConnHandle, setIgnoreErrorCodes) { return new Promise((resolve, reject) => { this.logger.traceLog("_pollRows TeradataCursor, bInAsyncExecute=" + this.bInAsyncExecute); const result = this._jsgoPollRows(nLog, nConnHandle, setIgnoreErrorCodes); if (typeof result === "number") { resolve(result); // 0: results not available, non-zero: results available and nRowsHandle returned } else { reject(result); // error text } }); } _buildAbyBindValuesBuffer(seqOfParameters) { this.logger.traceLog("> enter _buildAbyBindValuesBuffer TeradataCursor, bInAsyncExecute=" + this.bInAsyncExecute); const aao = []; if (seqOfParameters !== null) { for (const row of seqOfParameters) { for (const field of row) { let ao = Buffer.allocUnsafe(0); if (typeof field === "string") { const aby = Buffer.from(field, "utf8"); ao = Buffer.allocUnsafe(9); ao.writeUInt8("S".charCodeAt(0), 0); ao.writeBigUInt64BE(BigInt(aby.byteLength), 1); ao = Buffer.concat([ao, aby]); } else if (typeof field === "number") { ao = Buffer.allocUnsafe(9); ao.writeUInt8("D".charCodeAt(0), 0); ao.writeDoubleBE(field, 1); } else if (field === null || field === undefined) { ao = Buffer.allocUnsafe(1); ao.writeUInt8("N".charCodeAt(0), 0); } else if (field instanceof Date) { // TIMESTAMP without TIME ZONE: YYYY-MM-DD HH:MM:SS[.FFFFFF] // field.toISOString(): 2011-10-05T14:48:00.000Z const sDate = field.toISOString().slice(0, 10); const sTime = field.toISOString().slice(11, 23); const s = `${sDate} ${sTime}`; const aby = Buffer.from(s, "utf8"); ao = Buffer.allocUnsafe(9); ao.writeUInt8("X".charCodeAt(0), 0); ao.writeBigUInt64BE(BigInt(aby.byteLength), 1); ao = Buffer.concat([ao, aby]); } else if (typeof field === "bigint") { ao = Buffer.allocUnsafe(9); ao.writeUInt8("L".charCodeAt(0), 0); ao.writeBigInt64BE(field, 1); } else if (field instanceof Uint8Array) { ao = Buffer.allocUnsafe(9); ao.writeUInt8("B".charCodeAt(0), 0); ao.writeBigUInt64BE(BigInt(field.length), 1); const buf = Buffer.from(field); ao = Buffer.concat([ao, buf]); } else { throw new TypeError(`unexpected type=${typeof field} value=${field}`); } aao.push(ao); } // end of row aao.push(Buffer.from("Z")); // end of row terminator } // end of all rows } // end if seqOfParameters aao.push(Buffer.from("Z")); // end of all rows terminator this.logger.traceLog("< leave _buildAbyBindValuesBuffer TeradataCursor"); return Buffer.concat(aao); } _obtainResultMetaData() { this.logger.traceLog("> enter _obtainResultMetaData TeradataCursor, bInAsyncExecute=" + this.bInAsyncExecute); try { const dStartTimeBegin = Date.now(); let outputPtrPtr = [null]; let uActivityCount = [0]; let metaDataByteCountPtr = [0]; let byteArrayPtrPtr = [0]; let dStartTime = Date.now(); this.lib.jsgoResultMetaData(this.conn.uLog, this.uRowsHandle, outputPtrPtr, uActivityCount, metaDataByteCountPtr, byteArrayPtrPtr); this.logger.timingLog("_obtainResultMetaData call to jsgoResultMetaData took " + (Date.now() - dStartTime) + " ms"); const outputString = outputPtrPtr[0]; if (outputString) { throw new teradata_exceptions_1.OperationalError(outputString); } dStartTime = Date.now(); this.rowCount = BigInt(uActivityCount[0]); const metadataLength = metaDataByteCountPtr[0]; if (metadataLength > 0) { this.desc = []; this.colTypeName = []; let i = 0; const byteArrayPtr = koffi.decode(byteArrayPtrPtr[0], "uint8_t", metadataLength); const pcColumnMetaData = Buffer.from(byteArrayPtr); 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, this.colTypeName); // (2) Type code i = this._deserializeString(pcColumnMetaData, i, columnDesc); if (columnDesc[columnDesc.length - 1] === "b") { // typeCode b=bytes columnDesc[columnDesc.length - 1] = exports.BINARY; } else if (columnDesc[columnDesc.length - 1] === "d") { // typeCode d=double columnDesc[columnDesc.length - 1] = exports.NUMBER; } else if (columnDesc[columnDesc.length - 1] === "i" || columnDesc[columnDesc.length - 1] === "l") { // typeCode i=integer (int32), l=long (int64) columnDesc[columnDesc.length - 1] = exports.NUMBER; } else if (columnDesc[columnDesc.length - 1] === "m") { // typeCode m=number columnDesc[columnDesc.length - 1] = exports.NUMBER; } else if (columnDesc[columnDesc.length - 1] === "s") { // typeCode s=string columnDesc[columnDesc.length - 1] = exports.STRING; } else if (columnDesc[columnDesc.length - 1] === "u") { // typeCode u=date columnDesc[columnDesc.length - 1] = exports.STRING; } else if (columnDesc[columnDesc.length - 1] === "v" || columnDesc[columnDesc.length - 1] === "w") { // typeCode v=time, w=time with time zone columnDesc[columnDesc.length - 1] = exports.STRING; } else if (columnDesc[columnDesc.length - 1] === "x") { // typeCode x=timestamp (without time zone) columnDesc[columnDesc.length - 1] = exports.DATE; } else if (columnDesc[columnDesc.length - 1] === "y") { // y=timestamp with time zone columnDesc[columnDesc.length - 1] = exports.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.debugLog(columnDesc, true); this.desc.push(columnDesc); } // end while this.logger.timingLog("_obtainResultMetaData deserialized " + metadataLength + " bytes and took " + (Date.now() - dStartTime) + " ms"); this.logger.timingLog("_obtainResultMetaData() took " + (Date.now() - dStartTimeBegin) + " ms"); } // end if rowsLength > 0 } finally { this.logger.traceLog("< leave _obtainResultMetaData TeradataCursor"); } } _deserializeBool(pc, i, row) { 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) { if (pc[i] === "B".charCodeAt(0)) { // B=bytes i += 1; const unByteCount = pc.readBigUInt64BE(i); let uByteCount = 0; if (unByteCount <= Number.MAX_SAFE_INTEGER) { uByteCount = Number(unByteCount); } else { throw new teradata_exceptions_1.OperationalError(`Data length > ${unByteCount} is not supported.`); } i += 8; 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; let uByteCount = 0; const unByteCount = pc.readBigUInt64BE(i); if (unByteCount <= Number.MAX_SAFE_INTEGER) { uByteCount = Number(unByteCount); } else { throw new teradata_exceptions_1.OperationalError(`Data length > ${unByteCount} is not supported.`); } i += 8; const sValue = pc.toString("utf8", i, i + uByteCount); i += uByteCount; if (row) { if (abyTypeCode === "L".charCodeAt(0)) { // L=bigint throw new teradata_exceptions_1.OperationalError("BigInt should not be a char value."); } else if (abyTypeCode === "M".charCodeAt(0)) { // M=number row.push(Number(sValue)); } else if (abyTypeCode === "X".charCodeAt(0)) { // X=timestamp without time zone (the UTC time) // Parse sValue and feed it to Date.UTC() which creates a Date object treating the input as the UTC time. const timePieces = /^([0-9]{4})-([0-9]{2})-([0-9]{2}) ([0-9]{2}):([0-9]{2}):([0-9]{2})(\.[0-9]*)?/; const u = timePieces.exec(sValue); let date; if (u) { const nMillisecondsUTC = Date.UTC(parseInt(u[1], 10), // YYYY parseInt(u[2], 10) - 1, // Months starts with zero parseInt(u[3], 10), // DD parseInt(u[4], 10), // HH parseInt(u[5], 10), // MM parseInt(u[6], 10), // SS (u[7] && parseFloat(u[7]) * 1000) || 0 // (.ssssss) ); date = new Date(nMillisecondsUTC); row.push(date); } else { throw new teradata_exceptions_1.OperationalError("Unexpected timestamp value"); } } 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) { return this._deserializeCharacterValue("U".charCodeAt(0), pc, i, row); } _deserializeDouble(pc, i, row) { 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) { 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) { if (pc[i] === "L".charCodeAt(0)) { // L=long i += 1; const nValue = pc.readBigInt64BE(i); i += 8; 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 L/N."); } } _deserializeNull(pc, i, row) { 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) { return this._deserializeCharacterValue("M".charCodeAt(0), pc, i, row); } _deserializeString(pc, i, row) { return this._deserializeCharacterValue("S".charCodeAt(0), pc, i, row); } _deserializeTime(pc, i, row) { return this._deserializeCharacterValue("V".charCodeAt(0), pc, i, row); } _deserializeTimeWithTimeZone(pc, i, row) { return this._deserializeCharacterValue("W".charCodeAt(0), pc, i, row); } _deserializeTimestamp(pc, i, row) { return this._deserializeCharacterValue("X".charCodeAt(0), pc, i, row); } _deserializeTimestampWithTimeZone(pc, i, row) { return this._deserializeCharacterValue("Y".charCodeAt(0), pc, i, row); } } exports.TeradataCursor = TeradataCursor; // Private properties TeradataCursor.nInstanceCount = 0; //# sourceMappingURL=teradata-cursor.js.map