Skip to content

Commit a05c4dd

Browse files
committed
Fixed bug with statement cache which threw an error when select SQL is run on CLOB columns fetched as string (Issue #1684)
1 parent 0c190f9 commit a05c4dd

File tree

3 files changed

+89
-27
lines changed

3 files changed

+89
-27
lines changed

doc/src/release_notes.rst

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,21 @@ node-oracledb Release Notes
88
For deprecated and desupported features, see :ref:`Deprecations and desupported features <deprecations>`.
99

1010
node-oracledb `v6.7.0 <https://github.com/oracle/node-oracledb/compare/v6.6.0...v6.7.0>`__ (TBD)
11-
------------------------------------------------------------------------------------------------
11+
---------------------------------------------------------------------------------------------------------
12+
13+
Common Changes
14+
++++++++++++++
15+
16+
Thin Mode Changes
17+
+++++++++++++++++
18+
19+
#) Fixed bug with statement cache which threw an `NJS-111` error when select
20+
SQL is run on CLOB columns fetched as string.
21+
See `Issue #1684 <https://github.com/oracle/node-oracledb/issues/
22+
1684>`__.
23+
24+
Thick Mode Changes
25+
+++++++++++++++++++
1226

1327
node-oracledb `v6.6.0 <https://github.com/oracle/node-oracledb/compare/v6.5.1...v6.6.0>`__ (25 Jul 2024)
1428
---------------------------------------------------------------------------------------------------------

lib/thin/protocol/messages/withData.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,6 @@ class MessageWithData extends Message {
6767
if (messageType === constants.TNS_MSG_TYPE_DESCRIBE_INFO) {
6868
buf.skipBytesChunked();
6969
const prevQueryVars = this.statement.queryVars;
70-
this.statement.queryVars = [];
7170
this.statement.numQueryVars = 0;
7271
this.statement.bufferRowCount = 0;
7372
this.statement.bufferRowIndex = 0;

test/columnMetadata.js

Lines changed: 74 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@
3434
const oracledb = require('oracledb');
3535
const assert = require('assert');
3636
const dbConfig = require('./dbconfig.js');
37+
const testsUtil = require('./testsUtil.js');
38+
const random = require('./random.js');
3739

3840
describe('9. columnMetadata.js', function() {
3941

@@ -217,6 +219,11 @@ describe('9. columnMetadata.js', function() {
217219
}); // 9.2
218220

219221
describe('9.3 Large number of columns', function() {
222+
let columns_string;
223+
const tableName = "nodb_large_columns";
224+
const sqlSelect = "SELECT * FROM " + tableName;
225+
const sqlDrop = testsUtil.sqlDropTable(tableName);
226+
220227
function genColumns(size, dbType) {
221228
const buffer = [];
222229
for (var i = 0; i < size; i++) {
@@ -225,35 +232,23 @@ describe('9. columnMetadata.js', function() {
225232
return buffer.join();
226233
}
227234

235+
function generateCreateSql(cols) {
236+
return `create table ${tableName}(${cols})`;
237+
}
238+
239+
after(async function() {
240+
oracledb.fetchAsString = [];
241+
await connection.execute(sqlDrop);
242+
});
243+
228244
it('9.10 works with a large number of columns', async function() {
229245
const column_size = 300;
230-
let columns_string = genColumns(column_size, " NUMBER");
231-
const table_name = "nodb_large_columns";
232-
const sqlSelect = "SELECT * FROM " + table_name;
233-
const sqlDrop = "DROP TABLE " + table_name + " PURGE";
246+
columns_string = genColumns(column_size, " NUMBER");
234247

235-
function generateProcedure() {
236-
return "BEGIN \n" +
237-
" DECLARE \n" +
238-
" e_table_missing EXCEPTION; \n" +
239-
" PRAGMA EXCEPTION_INIT(e_table_missing, -00942);\n " +
240-
" BEGIN \n" +
241-
" EXECUTE IMMEDIATE ('DROP TABLE nodb_large_columns PURGE'); \n" +
242-
" EXCEPTION \n" +
243-
" WHEN e_table_missing \n" +
244-
" THEN NULL; \n" +
245-
" END; \n" +
246-
" EXECUTE IMMEDIATE (' \n" +
247-
" CREATE TABLE nodb_large_columns ( \n" +
248-
columns_string +
249-
" ) \n" +
250-
" '); \n" +
251-
"END; ";
252-
}
248+
let plsql = testsUtil.sqlCreateTable(tableName, generateCreateSql(columns_string));
249+
await connection.execute(plsql);
253250

254251
// check NUMBER type column
255-
await connection.execute(generateProcedure());
256-
257252
// Dont cache statment as we re-run with different
258253
// column type with same table.
259254
let result = await connection.execute(sqlSelect, [],
@@ -265,11 +260,65 @@ describe('9. columnMetadata.js', function() {
265260

266261
// check CLOB type (GH Issue 1642)
267262
columns_string = genColumns(column_size, " CLOB");
268-
await connection.execute(generateProcedure());
263+
plsql = testsUtil.sqlCreateTable(tableName, generateCreateSql(columns_string));
264+
await connection.execute(plsql);
265+
result = await connection.execute(sqlSelect, [], { keepInStmtCache: false });
266+
for (let i = 0; i < column_size; i++) {
267+
assert.strictEqual(result.metaData[i].name, 'COLUMN_' + i);
268+
}
269+
await connection.execute(sqlDrop);
270+
});
271+
272+
it('9.11 works with re-executes with multiple packet response', async function() {
273+
const column_size = 50;
274+
const numRows = 5;
275+
oracledb.fetchAsString = [oracledb.CLOB];
276+
277+
// read table meta data (GH Issue 1684) without inserting any row.
278+
columns_string = genColumns(column_size, " CLOB");
279+
const plsql = testsUtil.sqlCreateTable(tableName, generateCreateSql(columns_string));
280+
await connection.execute(plsql);
281+
let result = await connection.execute(sqlSelect);
282+
for (let i = 0; i < column_size; i++) {
283+
assert.strictEqual(result.metaData[i].name, 'COLUMN_' + i);
284+
}
285+
286+
// Insert rows.
287+
const len = 5 * 1024;
288+
const specialStr = "9.11";
289+
const clobStr = random.getRandomString(len, specialStr);
290+
let bindNames = ':clob,';
291+
bindNames = bindNames.repeat(column_size - 1);
292+
bindNames = bindNames + ':clob';
293+
const binds = new Array(numRows);
294+
const values = new Array(column_size);
295+
values.fill(clobStr, 0, column_size);
296+
binds.fill(values, 0, numRows);
297+
const sql = `INSERT INTO nodb_large_columns VALUES (${bindNames})`;
298+
result = await connection.executeMany(sql, binds);
299+
300+
// Issue second select with rows in table.
301+
result = await connection.execute(sqlSelect);
302+
for (let i = 0; i < column_size; i++) {
303+
assert.strictEqual(result.metaData[i].name, 'COLUMN_' + i);
304+
}
305+
for (let i = 0; i < result.rows.length; i++) {
306+
for (let j = 0; j < column_size; j++) {
307+
assert.strictEqual(result.rows[i][j], clobStr);
308+
}
309+
}
310+
311+
// subsequent selects should also work fine.
269312
result = await connection.execute(sqlSelect);
270313
for (let i = 0; i < column_size; i++) {
271314
assert.strictEqual(result.metaData[i].name, 'COLUMN_' + i);
272315
}
316+
for (let i = 0; i < result.rows.length; i++) {
317+
for (let j = 0; j < column_size; j++) {
318+
assert.strictEqual(result.rows[i][j], clobStr);
319+
}
320+
}
321+
273322
await connection.execute(sqlDrop);
274323
});
275324
}); // 9.3

0 commit comments

Comments
 (0)