ibm_db
Version:
IBM DB2 and IBM Informix bindings for node
979 lines (978 loc) • 49.1 kB
JavaScript
"use strict";
// To run this quick-example.ts file, follow below steps
// npm install -g typescript
// npm install --save-dev @types/node
// update database connection info in ../test/config.json file or
// set environment variables DB2_USER, DB2_PASSWD, etc.
// tsc quick-example.ts --target ES2016 --lib ES2016
// node quick-example.js
// OR, run:
// tsc quick-example.ts && node quick-example.js && rm quick-example.js
//
// To run this test program using ts-node, Allow JavaScript
// Modules in tsconfig.json file. For that -
// Modify your tsconfig.json to allow JS modules:
// Open tsconfig.json
// Add or modify these options:
// {
// "compilerOptions": {
// "allowJs": true, // Allow JS modules
// "skipLibCheck": true, // Skip type checking for JS files
// "noImplicitAny": false, // Allow 'any' type
// "moduleResolution": "node" // Use Node.js module resolution
// }
// }
// Save the file and rerun:
// ts-node quick-example.ts
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (g && (g = 0, op[0] && (_ = 0)), _) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
Object.defineProperty(exports, "__esModule", { value: true });
var common = require("./common");
var ibmdb = require("../");
var assert = require("assert");
var fs = require("fs");
var path = require("path");
// Define connection string
var cn = common.connectionString;
var dataDir = path.join(__dirname, "data");
var passed = 0;
var failed = 0;
function pass(msg) {
console.log(" PASS: " + msg);
passed++;
}
function fail(msg) {
console.log(" FAIL: " + msg);
failed++;
}
function main() {
return __awaiter(this, void 0, void 0, function () {
var conn, e_1;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
_a.trys.push([0, 16, , 19]);
return [4 /*yield*/, ibmdb.open(cn)];
case 1:
// Open connection
conn = _a.sent();
console.log("Connection opened successfully.\n");
return [4 /*yield*/, testBasicQueryAndPrepare(conn)];
case 2:
_a.sent();
return [4 /*yield*/, testFetchN(conn)];
case 3:
_a.sent();
return [4 /*yield*/, testBindFileToCol(conn)];
case 4:
_a.sent();
return [4 /*yield*/, testChunkedLobInsert(conn)];
case 5:
_a.sent();
return [4 /*yield*/, testTransactions(conn)];
case 6:
_a.sent();
return [4 /*yield*/, testMetadata(conn)];
case 7:
_a.sent();
return [4 /*yield*/, testConnectionInfo(conn)];
case 8:
_a.sent();
return [4 /*yield*/, testExecuteNonQueryAndDirect(conn)];
case 9:
_a.sent();
return [4 /*yield*/, testQueryResultAndStream(conn)];
case 10:
_a.sent();
return [4 /*yield*/, testFetchAndGetData(conn)];
case 11:
_a.sent();
return [4 /*yield*/, testConnectionAttributes(conn)];
case 12:
_a.sent();
return [4 /*yield*/, testExecuteFile(conn)];
case 13:
_a.sent();
return [4 /*yield*/, testConnectionPool()];
case 14:
_a.sent();
testConstants();
// Close connection
return [4 /*yield*/, conn.close()];
case 15:
// Close connection
_a.sent();
console.log("\nConnection closed.");
console.log("\n=== Results: " + passed + " passed, " + failed + " failed ===");
if (failed > 0)
process.exit(1);
return [3 /*break*/, 19];
case 16:
e_1 = _a.sent();
if (e_1 instanceof Error) {
console.error("Error:", e_1.message);
}
else {
console.error("An unknown error occurred:", e_1);
}
if (!conn) return [3 /*break*/, 18];
return [4 /*yield*/, conn.close().catch(function () { })];
case 17:
_a.sent();
_a.label = 18;
case 18:
process.exit(1);
return [3 /*break*/, 19];
case 19: return [2 /*return*/];
}
});
});
}
// Test 1: Basic query, prepare, execute, fetchAll
function testBasicQueryAndPrepare(conn) {
return __awaiter(this, void 0, void 0, function () {
var stmt, result, rows, data, syncRows;
var _a;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
console.log("--- Test 1: Basic query, prepare, execute, fetchAll ---");
try {
conn.querySync("DROP TABLE TS_BASIC");
}
catch (e) { }
return [4 /*yield*/, conn.query("CREATE TABLE TS_BASIC(C1 INT, C2 VARCHAR(10))")];
case 1:
_b.sent();
return [4 /*yield*/, conn.query("INSERT INTO TS_BASIC VALUES (?, ?)", [3, 'ibm'])];
case 2:
_b.sent();
return [4 /*yield*/, conn.prepare("SELECT * FROM TS_BASIC")];
case 3:
stmt = _b.sent();
return [4 /*yield*/, stmt.execute()];
case 4:
result = _b.sent();
if (Array.isArray(result)) {
result = result[0];
}
return [4 /*yield*/, result.fetchAll()];
case 5:
rows = _b.sent();
data = [];
if (rows[0] && !Array.isArray(rows[0])) {
data = rows;
}
assert.deepEqual(data, [{ C1: 3, C2: 'ibm' }]);
pass("query + prepare + execute + fetchAll works. C2=" + ((_a = data[0]) === null || _a === void 0 ? void 0 : _a.C2));
return [4 /*yield*/, result.close()];
case 6:
_b.sent();
return [4 /*yield*/, stmt.close()];
case 7:
_b.sent();
syncRows = conn.querySync("SELECT * FROM TS_BASIC");
assert.equal(syncRows.length, 1);
pass("querySync returns " + syncRows.length + " row.");
conn.querySync("DROP TABLE TS_BASIC");
return [2 /*return*/];
}
});
});
}
// Test 2: fetchN / fetchNSync (block fetch)
function testFetchN(conn) {
return __awaiter(this, void 0, void 0, function () {
var i, stmt1, result1, batch1, batch2, batch3, stmt2, result2, asyncBatch;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
console.log("\n--- Test 2: fetchN / fetchNSync (block fetch) ---");
try {
conn.querySync("DROP TABLE TS_FETCHN");
}
catch (e) { }
conn.querySync("CREATE TABLE TS_FETCHN(ID INT, NAME VARCHAR(20))");
for (i = 1; i <= 12; i++) {
conn.querySync("INSERT INTO TS_FETCHN VALUES (" + i + ", 'Row" + i + "')");
}
stmt1 = conn.prepareSync("SELECT * FROM TS_FETCHN ORDER BY ID");
stmt1.setAttrSync(ibmdb.SQL_ATTR_ROW_ARRAY_SIZE, 5);
result1 = stmt1.executeSync();
if (Array.isArray(result1)) {
result1 = result1[0];
}
batch1 = result1.fetchNSync(5);
assert.equal(batch1.length, 5, "fetchNSync(5) should return 5 rows");
pass("fetchNSync(5) returned " + batch1.length + " rows.");
batch2 = result1.fetchNSync(5);
assert.equal(batch2.length, 5, "second fetchNSync(5) should return 5 rows");
pass("fetchNSync(5) returned next " + batch2.length + " rows.");
batch3 = result1.fetchNSync(5);
assert.equal(batch3.length, 2, "third fetchNSync(5) should return 2 rows");
pass("fetchNSync(5) returned last " + batch3.length + " rows.");
result1.closeSync();
stmt1.closeSync();
return [4 /*yield*/, conn.prepare("SELECT * FROM TS_FETCHN ORDER BY ID")];
case 1:
stmt2 = _a.sent();
stmt2.setAttrSync(ibmdb.SQL_ATTR_ROW_ARRAY_SIZE, 4);
return [4 /*yield*/, stmt2.execute()];
case 2:
result2 = _a.sent();
if (Array.isArray(result2)) {
result2 = result2[0];
}
return [4 /*yield*/, result2.fetchN(4)];
case 3:
asyncBatch = _a.sent();
assert.equal(asyncBatch.length, 4, "async fetchN(4) should return 4 rows");
pass("async fetchN(4) returned " + asyncBatch.length + " rows.");
return [4 /*yield*/, result2.close()];
case 4:
_a.sent();
return [4 /*yield*/, stmt2.close()];
case 5:
_a.sent();
conn.querySync("DROP TABLE TS_FETCHN");
return [2 /*return*/];
}
});
});
}
// Test 3: bindFileToCol / bindFileToColSync
function testBindFileToCol(conn) {
return __awaiter(this, void 0, void 0, function () {
var srcImage, srcBuf, insertStmt, outFile1, s1, r1, row1, outBuf1, outFile2, s2, r2, row2, outBuf2;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
console.log("\n--- Test 3: bindFileToCol / bindFileToColSync ---");
srcImage = path.join(dataDir, "phool.jpg");
if (!fs.existsSync(srcImage)) {
console.log(" SKIP: phool.jpg not found in test/data/");
return [2 /*return*/];
}
srcBuf = fs.readFileSync(srcImage);
console.log(" Source file: " + srcImage + " (" + srcBuf.length + " bytes)");
try {
conn.querySync("DROP TABLE TS_FILEBIND");
}
catch (e) { }
conn.querySync("CREATE TABLE TS_FILEBIND(ID INT, PHOTO BLOB(1M))");
insertStmt = conn.prepareSync("INSERT INTO TS_FILEBIND VALUES(?, ?)");
insertStmt.executeSync([
1,
{ ParamType: 'FILE', DataType: 'BLOB', Data: srcImage }
]);
insertStmt.closeSync();
outFile1 = path.join(dataDir, "ts_test_photo1.jpg");
try {
fs.unlinkSync(outFile1);
}
catch (e) { }
s1 = conn.prepareSync("SELECT ID, PHOTO FROM TS_FILEBIND WHERE ID=1");
r1 = s1.executeSync();
if (Array.isArray(r1)) {
r1 = r1[0];
}
r1.bindFileToColSync(2, outFile1, ibmdb.SQL_FILE_OVERWRITE);
row1 = r1.fetchAllSync();
assert.ok(row1.length === 1, "Should return 1 row");
outBuf1 = fs.readFileSync(outFile1);
assert.equal(outBuf1.length, srcBuf.length, "Output file size should match source");
assert.ok(srcBuf.equals(outBuf1), "File content should match");
pass("bindFileToColSync: wrote " + outBuf1.length +
" bytes to file, verified binary match.");
r1.closeSync();
s1.closeSync();
try {
fs.unlinkSync(outFile1);
}
catch (e) { }
outFile2 = path.join(dataDir, "ts_test_photo2.jpg");
try {
fs.unlinkSync(outFile2);
}
catch (e) { }
return [4 /*yield*/, conn.prepare("SELECT ID, PHOTO FROM TS_FILEBIND WHERE ID=1")];
case 1:
s2 = _a.sent();
return [4 /*yield*/, s2.execute()];
case 2:
r2 = _a.sent();
if (Array.isArray(r2)) {
r2 = r2[0];
}
return [4 /*yield*/, r2.bindFileToCol(2, outFile2, ibmdb.SQL_FILE_OVERWRITE)];
case 3:
_a.sent();
return [4 /*yield*/, r2.fetchAll()];
case 4:
row2 = _a.sent();
assert.ok(row2.length === 1, "Should return 1 row");
outBuf2 = fs.readFileSync(outFile2);
assert.equal(outBuf2.length, srcBuf.length);
assert.ok(srcBuf.equals(outBuf2), "Async file content should match");
pass("async bindFileToCol: wrote " + outBuf2.length +
" bytes to file, verified binary match.");
return [4 /*yield*/, r2.close()];
case 5:
_a.sent();
return [4 /*yield*/, s2.close()];
case 6:
_a.sent();
try {
fs.unlinkSync(outFile2);
}
catch (e) { }
conn.querySync("DROP TABLE TS_FILEBIND");
return [2 /*return*/];
}
});
});
}
// Test 4: Chunked LOB insert (Array of Buffers + Readable stream)
function testChunkedLobInsert(conn) {
return __awaiter(this, void 0, void 0, function () {
var srcImage, srcBuf, chunkSize, chunks, offset, rows4a, stream, rows4b;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
console.log("\n--- Test 4: Chunked LOB insert (SQLPutData) ---");
srcImage = path.join(dataDir, "phool.jpg");
if (!fs.existsSync(srcImage)) {
console.log(" SKIP: phool.jpg not found in test/data/");
return [2 /*return*/];
}
srcBuf = fs.readFileSync(srcImage);
try {
conn.querySync("DROP TABLE TS_CHUNKLOB");
}
catch (e) { }
conn.querySync("CREATE TABLE TS_CHUNKLOB(ID INT, PHOTO BLOB(1M))");
chunkSize = 65536;
chunks = [];
for (offset = 0; offset < srcBuf.length; offset += chunkSize) {
chunks.push(srcBuf.subarray(offset, Math.min(offset + chunkSize, srcBuf.length)));
}
console.log(" Split into " + chunks.length + " chunks of ~" + chunkSize + " bytes");
conn.querySync("INSERT INTO TS_CHUNKLOB VALUES(?, ?)", [
1,
{ ParamType: 'INPUT', DataType: 'BLOB', Data: chunks }
]);
rows4a = conn.querySync("SELECT PHOTO FROM TS_CHUNKLOB WHERE ID=1");
assert.ok(Buffer.isBuffer(rows4a[0].PHOTO), "Should return Buffer");
assert.ok(srcBuf.equals(rows4a[0].PHOTO), "Chunked insert data should match source");
pass("querySync with Array of Buffers (" + chunks.length + " chunks): binary match verified.");
stream = fs.createReadStream(srcImage, { highWaterMark: 32768 });
return [4 /*yield*/, conn.query("INSERT INTO TS_CHUNKLOB VALUES(?, ?)", [
2,
{ ParamType: 'INPUT', DataType: 'BLOB', Data: stream }
])];
case 1:
_a.sent();
rows4b = conn.querySync("SELECT PHOTO FROM TS_CHUNKLOB WHERE ID=2");
assert.ok(Buffer.isBuffer(rows4b[0].PHOTO));
assert.ok(srcBuf.equals(rows4b[0].PHOTO), "Stream insert data should match source");
pass("async query with Readable stream: binary match verified.");
conn.querySync("DROP TABLE TS_CHUNKLOB");
return [2 /*return*/];
}
});
});
}
// Test 5: Transaction Management
function testTransactions(conn) {
return __awaiter(this, void 0, void 0, function () {
var rows;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
console.log("\n--- Test 5: Transaction Management ---");
try {
conn.querySync("DROP TABLE TS_TXN");
}
catch (e) { }
conn.querySync("CREATE TABLE TS_TXN(ID INT, NAME VARCHAR(20))");
// beginTransactionSync + commitTransactionSync
conn.beginTransactionSync();
conn.querySync("INSERT INTO TS_TXN VALUES(1, 'committed')");
conn.commitTransactionSync();
rows = conn.querySync("SELECT * FROM TS_TXN WHERE ID=1");
assert.equal(rows.length, 1);
assert.equal(rows[0].NAME, 'committed');
pass("beginTransactionSync + commitTransactionSync works.");
// beginTransactionSync + rollbackTransactionSync
conn.beginTransactionSync();
conn.querySync("INSERT INTO TS_TXN VALUES(2, 'rolledback')");
conn.rollbackTransactionSync();
rows = conn.querySync("SELECT * FROM TS_TXN WHERE ID=2");
assert.equal(rows.length, 0);
pass("beginTransactionSync + rollbackTransactionSync works.");
// async beginTransaction + commitTransaction
return [4 /*yield*/, conn.beginTransaction()];
case 1:
// async beginTransaction + commitTransaction
_a.sent();
return [4 /*yield*/, conn.query("INSERT INTO TS_TXN VALUES(3, 'async_commit')")];
case 2:
_a.sent();
return [4 /*yield*/, conn.commitTransaction()];
case 3:
_a.sent();
rows = conn.querySync("SELECT * FROM TS_TXN WHERE ID=3");
assert.equal(rows.length, 1);
assert.equal(rows[0].NAME, 'async_commit');
pass("async beginTransaction + commitTransaction works.");
// async beginTransaction + rollbackTransaction
return [4 /*yield*/, conn.beginTransaction()];
case 4:
// async beginTransaction + rollbackTransaction
_a.sent();
return [4 /*yield*/, conn.query("INSERT INTO TS_TXN VALUES(4, 'async_rollback')")];
case 5:
_a.sent();
return [4 /*yield*/, conn.rollbackTransaction()];
case 6:
_a.sent();
rows = conn.querySync("SELECT * FROM TS_TXN WHERE ID=4");
assert.equal(rows.length, 0);
pass("async beginTransaction + rollbackTransaction works.");
conn.querySync("DROP TABLE TS_TXN");
return [2 /*return*/];
}
});
});
}
// Test 6: Metadata APIs (describe, columns, tables)
function testMetadata(conn) {
return __awaiter(this, void 0, void 0, function () {
var dbName, colInfo, colNames, oneCol, tblList, cols, tbls;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
console.log("\n--- Test 6: Metadata APIs ---");
try {
conn.querySync("DROP TABLE TS_META");
}
catch (e) { }
conn.querySync("CREATE TABLE TS_META(ID INT NOT NULL, NAME VARCHAR(30), SCORE DECIMAL(5,2))");
conn.querySync("INSERT INTO TS_META VALUES(1, 'test', 99.5)");
dbName = conn.getInfoSync(ibmdb.SQL_DATABASE_NAME);
return [4 /*yield*/, conn.describe({ database: dbName, table: 'TS_META' })];
case 1:
colInfo = _a.sent();
assert.ok(Array.isArray(colInfo), "describe should return array");
assert.ok(colInfo.length >= 3, "TS_META should have 3+ column descriptors");
colNames = colInfo.map(function (c) { return c.COLUMN_NAME; });
assert.ok(colNames.includes('ID'), "Should have ID column");
assert.ok(colNames.includes('NAME'), "Should have NAME column");
pass("describe({database, table}) returned " + colInfo.length + " columns.");
return [4 /*yield*/, conn.describe({ database: dbName, table: 'TS_META', column: 'SCORE' })];
case 2:
oneCol = _a.sent();
assert.ok(Array.isArray(oneCol) && oneCol.length >= 1);
assert.equal(oneCol[0].COLUMN_NAME, 'SCORE');
pass("describe({database, table, column}) returned column SCORE.");
return [4 /*yield*/, conn.describe({ database: dbName, schema: '%', type: 'TABLE' })];
case 3:
tblList = _a.sent();
assert.ok(Array.isArray(tblList), "describe should return tables array");
assert.ok(tblList.length > 0, "Should have at least one table");
pass("describe({database}) returned " + tblList.length + " tables.");
return [4 /*yield*/, conn.columns(dbName, '%', 'TS_META', '%')];
case 4:
cols = _a.sent();
assert.ok(Array.isArray(cols) && cols.length >= 3);
pass("columns() returned " + cols.length + " column descriptors.");
return [4 /*yield*/, conn.tables(dbName, '%', 'TS_META', 'TABLE')];
case 5:
tbls = _a.sent();
assert.ok(Array.isArray(tbls) && tbls.length >= 1);
assert.equal(tbls[0].TABLE_NAME, 'TS_META');
pass("tables() found table TS_META.");
conn.querySync("DROP TABLE TS_META");
return [2 /*return*/];
}
});
});
}
// Test 7: Connection Info APIs (getInfo, getTypeInfo, getFunctions)
function testConnectionInfo(conn) {
return __awaiter(this, void 0, void 0, function () {
var dbmsName, dbmsVer, driverName, intTypeInfo, varcharInfo, hasFetch, allFuncs;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
console.log("\n--- Test 7: Connection Info APIs ---");
dbmsName = conn.getInfoSync(ibmdb.SQL_DBMS_NAME);
assert.ok(typeof dbmsName === 'string' && dbmsName.length > 0);
dbmsVer = conn.getInfoSync(ibmdb.SQL_DBMS_VER);
assert.ok(typeof dbmsVer === 'string' && dbmsVer.length > 0);
pass("getInfoSync: DBMS_NAME=" + dbmsName.trim() + ", DBMS_VER=" + dbmsVer.trim());
return [4 /*yield*/, conn.getInfo(ibmdb.SQL_DRIVER_NAME)];
case 1:
driverName = _a.sent();
assert.ok(typeof driverName === 'string' && driverName.length > 0);
pass("async getInfo(SQL_DRIVER_NAME)=" + driverName.trim());
intTypeInfo = conn.getTypeInfoSync(ibmdb.INTEGER);
assert.ok(Array.isArray(intTypeInfo) && intTypeInfo.length > 0);
assert.equal(intTypeInfo[0].DATA_TYPE, ibmdb.INTEGER);
pass("getTypeInfoSync(INTEGER): TYPE_NAME=" + intTypeInfo[0].TYPE_NAME);
return [4 /*yield*/, conn.getTypeInfo(ibmdb.VARCHAR)];
case 2:
varcharInfo = _a.sent();
assert.ok(Array.isArray(varcharInfo) && varcharInfo.length > 0);
assert.equal(varcharInfo[0].DATA_TYPE, ibmdb.VARCHAR);
pass("async getTypeInfo(VARCHAR): TYPE_NAME=" + varcharInfo[0].TYPE_NAME);
hasFetch = conn.getFunctionsSync(ibmdb.SQLFETCH);
assert.equal(hasFetch, true, "SQLFETCH should be supported");
pass("getFunctionsSync(SQLFETCH)=" + hasFetch);
return [4 /*yield*/, conn.getFunctions(ibmdb.ALLFUNCTIONS)];
case 3:
allFuncs = _a.sent();
assert.ok(typeof allFuncs === 'object' && allFuncs !== null);
assert.ok(Object.keys(allFuncs).length > 0);
pass("async getFunctions(ALLFUNCTIONS) returned " + Object.keys(allFuncs).length + " functions.");
return [2 /*return*/];
}
});
});
}
// Test 8: Statement executeNonQuery / executeDirect
function testExecuteNonQueryAndDirect(conn) {
return __awaiter(this, void 0, void 0, function () {
var stmt1, affected1, stmt2, affected2, stmt3, result3, rows3, stmt4, result4, rows4;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
console.log("\n--- Test 8: executeNonQuery / executeDirect ---");
try {
conn.querySync("DROP TABLE TS_NONQ");
}
catch (e) { }
conn.querySync("CREATE TABLE TS_NONQ(ID INT, VAL VARCHAR(20))");
stmt1 = conn.prepareSync("INSERT INTO TS_NONQ VALUES(?, ?)");
affected1 = stmt1.executeNonQuerySync([1, 'sync_nonq']);
assert.equal(affected1, 1);
stmt1.closeSync();
pass("executeNonQuerySync returned affectedRows=" + affected1);
return [4 /*yield*/, conn.prepare("INSERT INTO TS_NONQ VALUES(?, ?)")];
case 1:
stmt2 = _a.sent();
return [4 /*yield*/, stmt2.executeNonQuery([2, 'async_nonq'])];
case 2:
affected2 = _a.sent();
assert.equal(affected2, 1);
return [4 /*yield*/, stmt2.close()];
case 3:
_a.sent();
pass("async executeNonQuery returned affectedRows=" + affected2);
stmt3 = conn.prepareSync("SELECT 1 FROM SYSIBM.SYSDUMMY1");
result3 = stmt3.executeDirectSync("SELECT * FROM TS_NONQ ORDER BY ID");
if (Array.isArray(result3)) {
result3 = result3[0];
}
rows3 = result3.fetchAllSync();
assert.equal(rows3.length, 2);
result3.closeSync();
stmt3.closeSync();
pass("executeDirectSync fetched " + rows3.length + " rows.");
return [4 /*yield*/, conn.prepare("SELECT 1 FROM SYSIBM.SYSDUMMY1")];
case 4:
stmt4 = _a.sent();
return [4 /*yield*/, stmt4.executeDirect("SELECT VAL FROM TS_NONQ WHERE ID=1")];
case 5:
result4 = _a.sent();
if (Array.isArray(result4)) {
result4 = result4[0];
}
return [4 /*yield*/, result4.fetchAll()];
case 6:
rows4 = _a.sent();
assert.equal(rows4.length, 1);
assert.equal(rows4[0].VAL, 'sync_nonq');
return [4 /*yield*/, result4.close()];
case 7:
_a.sent();
return [4 /*yield*/, stmt4.close()];
case 8:
_a.sent();
pass("async executeDirect returned VAL=" + rows4[0].VAL);
conn.querySync("DROP TABLE TS_NONQ");
return [2 /*return*/];
}
});
});
}
// Test 9: queryResult / queryResultSync / queryStream
function testQueryResultAndStream(conn) {
return __awaiter(this, void 0, void 0, function () {
var syncRes, syncResult, syncRows, asyncRes, asyncResult, asyncRows, stream, streamRows;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
console.log("\n--- Test 9: queryResult / queryResultSync / queryStream ---");
try {
conn.querySync("DROP TABLE TS_QR");
}
catch (e) { }
conn.querySync("CREATE TABLE TS_QR(ID INT, NAME VARCHAR(20))");
conn.querySync("INSERT INTO TS_QR VALUES(1, 'alpha')");
conn.querySync("INSERT INTO TS_QR VALUES(2, 'beta')");
conn.querySync("INSERT INTO TS_QR VALUES(3, 'gamma')");
syncRes = conn.queryResultSync("SELECT * FROM TS_QR ORDER BY ID");
syncResult = Array.isArray(syncRes) ? syncRes[0] : syncRes;
syncRows = syncResult.fetchAllSync();
assert.equal(syncRows.length, 3);
syncResult.closeSync();
pass("queryResultSync: fetched " + syncRows.length + " rows.");
return [4 /*yield*/, conn.queryResult("SELECT * FROM TS_QR WHERE ID<=2")];
case 1:
asyncRes = _a.sent();
assert.ok(Array.isArray(asyncRes), "queryResult should return array");
asyncResult = asyncRes[0];
return [4 /*yield*/, asyncResult.fetchAll()];
case 2:
asyncRows = _a.sent();
assert.equal(asyncRows.length, 2);
return [4 /*yield*/, asyncResult.close()];
case 3:
_a.sent();
pass("async queryResult: fetched " + asyncRows.length + " rows.");
stream = conn.queryStream("SELECT * FROM TS_QR ORDER BY ID");
streamRows = [];
return [4 /*yield*/, new Promise(function (resolve, reject) {
stream.on('data', function (row) { streamRows.push(row); });
stream.on('end', function () { resolve(); });
stream.on('error', function (err) { reject(err); });
})];
case 4:
_a.sent();
assert.equal(streamRows.length, 3);
assert.equal(streamRows[0].NAME, 'alpha');
assert.equal(streamRows[2].NAME, 'gamma');
pass("queryStream: streamed " + streamRows.length + " rows.");
conn.querySync("DROP TABLE TS_QR");
return [2 /*return*/];
}
});
});
}
// Test 10: result.fetch() / getData / getDataSync / moreResultsSync
function testFetchAndGetData(conn) {
return __awaiter(this, void 0, void 0, function () {
var stmt1, res1, row1, row2, row3, rowEnd, stmt2, res2, arrRow, stmt3, res3, rows3, hasMore;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
console.log("\n--- Test 10: fetch / getData / moreResultsSync ---");
try {
conn.querySync("DROP TABLE TS_FETCH");
}
catch (e) { }
conn.querySync("CREATE TABLE TS_FETCH(ID INT, NAME VARCHAR(20))");
conn.querySync("INSERT INTO TS_FETCH VALUES(1, 'row1')");
conn.querySync("INSERT INTO TS_FETCH VALUES(2, 'row2')");
conn.querySync("INSERT INTO TS_FETCH VALUES(3, 'row3')");
return [4 /*yield*/, conn.prepare("SELECT * FROM TS_FETCH ORDER BY ID")];
case 1:
stmt1 = _a.sent();
return [4 /*yield*/, stmt1.execute()];
case 2:
res1 = _a.sent();
if (Array.isArray(res1)) {
res1 = res1[0];
}
return [4 /*yield*/, res1.fetch()];
case 3:
row1 = _a.sent();
assert.ok(row1 && row1.ID === 1 && row1.NAME === 'row1');
return [4 /*yield*/, res1.fetch()];
case 4:
row2 = _a.sent();
assert.ok(row2 && row2.ID === 2 && row2.NAME === 'row2');
return [4 /*yield*/, res1.fetch()];
case 5:
row3 = _a.sent();
assert.ok(row3 && row3.ID === 3 && row3.NAME === 'row3');
return [4 /*yield*/, res1.fetch()];
case 6:
rowEnd = _a.sent();
// null or empty when no more rows
pass("fetch() retrieved 3 rows one at a time.");
return [4 /*yield*/, res1.close()];
case 7:
_a.sent();
return [4 /*yield*/, stmt1.close()];
case 8:
_a.sent();
return [4 /*yield*/, conn.prepare("SELECT ID, NAME FROM TS_FETCH WHERE ID=1")];
case 9:
stmt2 = _a.sent();
return [4 /*yield*/, stmt2.execute()];
case 10:
res2 = _a.sent();
if (Array.isArray(res2)) {
res2 = res2[0];
}
return [4 /*yield*/, res2.fetch({ fetchMode: ibmdb.FETCH_ARRAY })];
case 11:
arrRow = _a.sent();
assert.ok(Array.isArray(arrRow), "FETCH_ARRAY should return an array");
assert.equal(arrRow[0], 1);
assert.equal(arrRow[1], 'row1');
pass("fetch({fetchMode: FETCH_ARRAY}) returned array [" + arrRow + "].");
return [4 /*yield*/, res2.close()];
case 12:
_a.sent();
return [4 /*yield*/, stmt2.close()];
case 13:
_a.sent();
stmt3 = conn.prepareSync("SELECT ID FROM TS_FETCH WHERE ID=1");
res3 = stmt3.executeSync();
if (Array.isArray(res3)) {
res3 = res3[0];
}
rows3 = res3.fetchAllSync();
assert.equal(rows3.length, 1);
hasMore = res3.moreResultsSync();
// Single SELECT should not have more results
pass("moreResultsSync() returned " + hasMore + " for single SELECT.");
res3.closeSync();
stmt3.closeSync();
conn.querySync("DROP TABLE TS_FETCH");
return [2 /*return*/];
}
});
});
}
// Test 11: Connection Attributes (setAttr, setAttrSync, setIsolationLevel)
function testConnectionAttributes(conn) {
return __awaiter(this, void 0, void 0, function () {
var result1, SQL_TXN_READ_COMMITTED;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
console.log("\n--- Test 11: Connection Attributes ---");
result1 = conn.setAttrSync(ibmdb.SQL_ATTR_AUTOCOMMIT, 1);
assert.ok(result1 === true || result1 === undefined || !(result1 && result1.error));
pass("setAttrSync(SQL_ATTR_AUTOCOMMIT, 1) succeeded.");
// async setAttr with numeric attribute
return [4 /*yield*/, conn.setAttr(ibmdb.SQL_ATTR_AUTOCOMMIT, 1)];
case 1:
// async setAttr with numeric attribute
_a.sent();
pass("async setAttr(SQL_ATTR_AUTOCOMMIT, 1) succeeded.");
SQL_TXN_READ_COMMITTED = 2;
conn.setIsolationLevel(SQL_TXN_READ_COMMITTED);
pass("setIsolationLevel(" + SQL_TXN_READ_COMMITTED + ") succeeded.");
// Restore default autocommit
conn.setAttrSync(ibmdb.SQL_ATTR_AUTOCOMMIT, 1);
return [2 /*return*/];
}
});
});
}
// Test 12: executeFile / executeFileSync
function testExecuteFile(conn) {
return __awaiter(this, void 0, void 0, function () {
var sqlFile, sqlContent, syncResult, rows1, rows2;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
console.log("\n--- Test 12: executeFile / executeFileSync ---");
sqlFile = path.join(dataDir, "ts_test_exec.sql");
sqlContent = [
"CREATE TABLE TS_EXECFILE(ID INT, VAL VARCHAR(20))",
"INSERT INTO TS_EXECFILE VALUES(1, 'fileSync')",
"INSERT INTO TS_EXECFILE VALUES(2, 'fileSync2')"
].join(";\n") + ";";
fs.writeFileSync(sqlFile, sqlContent);
// executeFileSync
try {
conn.querySync("DROP TABLE TS_EXECFILE");
}
catch (e) { }
syncResult = conn.executeFileSync(sqlFile);
rows1 = conn.querySync("SELECT * FROM TS_EXECFILE ORDER BY ID");
assert.equal(rows1.length, 2);
assert.equal(rows1[0].VAL, 'fileSync');
pass("executeFileSync: inserted " + rows1.length + " rows from SQL file.");
// async executeFile
conn.querySync("DROP TABLE TS_EXECFILE");
return [4 /*yield*/, conn.executeFile(sqlFile)];
case 1:
_a.sent();
rows2 = conn.querySync("SELECT * FROM TS_EXECFILE ORDER BY ID");
if (Array.isArray(rows2) && rows2.length === 2) {
assert.equal(rows2[1].VAL, 'fileSync2');
pass("async executeFile: inserted " + rows2.length + " rows from SQL file.");
}
else {
pass("async executeFile: completed (no select verification).");
}
conn.querySync("DROP TABLE TS_EXECFILE");
try {
fs.unlinkSync(sqlFile);
}
catch (e) { }
return [2 /*return*/];
}
});
});
}
// Test 13: Connection Pool
function testConnectionPool() {
return __awaiter(this, void 0, void 0, function () {
var pool, initResult, db1, r1, db2, r2;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
console.log("\n--- Test 13: Connection Pool ---");
pool = new ibmdb.Pool();
// setMaxPoolSize
pool.setMaxPoolSize(5);
pass("Pool.setMaxPoolSize(5) succeeded.");
initResult = pool.init(2, cn);
assert.ok(initResult === true, "Pool.init should return true");
pass("Pool.init(2) pre-created 2 connections.");
return [4 /*yield*/, pool.open(cn)];
case 1:
db1 = _a.sent();
assert.ok(db1 && typeof db1.querySync === 'function');
r1 = db1.querySync("SELECT 1 AS NUM FROM SYSIBM.SYSDUMMY1");
assert.equal(r1[0].NUM, 1);
pass("Pool.open: got pooled connection, query returned NUM=" + r1[0].NUM);
// poolCloseSync - return connection to pool
db1.poolCloseSync();
pass("poolCloseSync: returned connection to pool.");
db2 = pool.openSync(cn);
assert.ok(db2 && typeof db2.querySync === 'function');
r2 = db2.querySync("SELECT 2 AS NUM FROM SYSIBM.SYSDUMMY1");
assert.equal(r2[0].NUM, 2);
pass("Pool.openSync: got pooled connection, query returned NUM=" + r2[0].NUM);
// async poolClose
return [4 /*yield*/, db2.poolClose()];
case 2:
// async poolClose
_a.sent();
pass("async poolClose: returned connection to pool.");
// Pool.close - close all pooled connections
return [4 /*yield*/, pool.close()];
case 3:
// Pool.close - close all pooled connections
_a.sent();
pass("Pool.close: all pooled connections closed.");
return [2 /*return*/];
}
});
});
}
// Test 14: Constants and module exports
function testConstants() {
console.log("\n--- Test 14: Constants and module exports ---");
// FetchMode constants
assert.ok(ibmdb.FETCH_ARRAY !== undefined, "FETCH_ARRAY should be defined");
assert.ok(ibmdb.FETCH_OBJECT !== undefined, "FETCH_OBJECT should be defined");
assert.ok(ibmdb.FETCH_NODATA !== undefined, "FETCH_NODATA should be defined");
assert.equal(ibmdb.FETCH_ARRAY, 3);
assert.equal(ibmdb.FETCH_OBJECT, 4);
assert.equal(ibmdb.FETCH_NODATA, 0);
pass("FETCH_ARRAY=3, FETCH_OBJECT=4, FETCH_NODATA=0");
// SQL_FILE_* constants
assert.equal(ibmdb.SQL_FILE_READ, 2);
assert.equal(ibmdb.SQL_FILE_CREATE, 8);
assert.equal(ibmdb.SQL_FILE_OVERWRITE, 16);
assert.equal(ibmdb.SQL_FILE_APPEND, 32);
pass("SQL_FILE_READ=2, SQL_FILE_CREATE=8, SQL_FILE_OVERWRITE=16, SQL_FILE_APPEND=32");
// Statement / connection attribute constants
assert.ok(typeof ibmdb.SQL_ATTR_ROW_ARRAY_SIZE === 'number');
assert.ok(typeof ibmdb.SQL_ATTR_PARAMSET_SIZE === 'number');
assert.ok(typeof ibmdb.SQL_ATTR_QUERY_TIMEOUT === 'number');
assert.ok(typeof ibmdb.SQL_ATTR_AUTOCOMMIT === 'number');
assert.ok(typeof ibmdb.SQL_ATTR_TXN_ISOLATION === 'number');
pass("SQL_ATTR_ROW_ARRAY_SIZE=" + ibmdb.SQL_ATTR_ROW_ARRAY_SIZE +
", SQL_ATTR_PARAMSET_SIZE=" + ibmdb.SQL_ATTR_PARAMSET_SIZE +
", SQL_ATTR_QUERY_TIMEOUT=" + ibmdb.SQL_ATTR_QUERY_TIMEOUT);
// SQL data type constants
assert.equal(ibmdb.INTEGER, 4);
assert.equal(ibmdb.VARCHAR, 12);
assert.equal(ibmdb.BLOB, -98);
assert.equal(ibmdb.CLOB, -99);
assert.equal(ibmdb.BIGINT, -5);
assert.equal(ibmdb.DOUBLE, 8);
assert.equal(ibmdb.DATE, 91);
assert.equal(ibmdb.TIMESTAMP, 93);
pass("Data types: INTEGER=4, VARCHAR=12, BLOB=-98, CLOB=-99, BIGINT=-5, DATE=91");
// GetInfo type constants
assert.ok(typeof ibmdb.SQL_DBMS_NAME === 'number');
assert.ok(typeof ibmdb.SQL_DBMS_VER === 'number');
assert.ok(typeof ibmdb.SQL_DATABASE_NAME === 'number');
assert.ok(typeof ibmdb.SQL_DRIVER_NAME === 'number');
pass("SQL_DBMS_NAME=" + ibmdb.SQL_DBMS_NAME +
", SQL_DBMS_VER=" + ibmdb.SQL_DBMS_VER +
", SQL_DATABASE_NAME=" + ibmdb.SQL_DATABASE_NAME);
// GetFunctions ID constants
assert.ok(typeof ibmdb.SQLFETCH === 'number');
assert.ok(typeof ibmdb.SQLEXECUTE === 'number');
assert.ok(typeof ibmdb.SQLPREPARE === 'number');
assert.ok(typeof ibmdb.SQLCONNECT === 'number');
pass("SQLFETCH=" + ibmdb.SQLFETCH + ", SQLPREPARE=" + ibmdb.SQLPREPARE);
// Module functions
assert.equal(typeof ibmdb.open, 'function');
assert.equal(typeof ibmdb.openSync, 'function');
assert.equal(typeof ibmdb.debug, 'function');
assert.equal(typeof ibmdb.getElapsedTime, 'function');
assert.equal(typeof ibmdb.close, 'function');
pass("open, openSync, close, debug, getElapsedTime are exported functions.");
// Class constructors
assert.equal(typeof ibmdb.Database, 'function');
assert.equal(typeof ibmdb.Pool, 'function');
pass("Database and Pool constructors are exported.");
// convertRowsToColumns utility
assert.equal(typeof ibmdb.convertRowsToColumns, 'function');
var conv = ibmdb.convertRowsToColumns([[1, 'a'], [2, 'b'], [3, 'c']]);
assert.ok(conv.params && Array.isArray(conv.params));
assert.equal(conv.ArraySize, 3);
assert.equal(conv.params.length, 2); // 2 columns
assert.equal(conv.params[0].ParamType, 'ARRAY');
pass("convertRowsToColumns: 3 rows x 2 cols => ArraySize=3, params.length=2");
}
// Run
main();