teradatasql
Version:
Teradata SQL Driver for Node.js
1,014 lines • 47 kB
JavaScript
"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