Skip to content

Commit bae7dd1

Browse files
committed
Fixed bug that throws the NJS-111 internal error, on the second SELECT call issued after the first SELECT call on an empty table with LOBs
1 parent 8abee4c commit bae7dd1

File tree

6 files changed

+86
-5
lines changed

6 files changed

+86
-5
lines changed

doc/src/release_notes.rst

+4
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ node-oracledb `v6.0.3 <https://github.com/oracle/node-oracledb/compare/v6.0.2...
1111
Thin Mode Changes
1212
+++++++++++++++++
1313

14+
#) Fixed bug that throws the NJS-111 internal error, on the second
15+
select SQL issued after first select SQL is done on an empty
16+
table involving LOB types.
17+
1418
#) Avoid throwing errors when calls to ``os.userInfo()`` fail.
1519
`Issue #1564 <https://github.com/oracle/node-oracledb/issues/1564>`__.
1620

lib/thin/protocol/messages/execute.js

+5-5
Original file line numberDiff line numberDiff line change
@@ -77,21 +77,21 @@ class ExecuteMessage extends MessageWithData {
7777
dmlOptions = constants.TNS_EXEC_OPTION_IMPLICIT_RESULTSET;
7878
options |= constants.TNS_EXEC_OPTION_EXECUTE;
7979
}
80-
if (stmt.cursorId == 0 || stmt.isDdl) {
80+
if (stmt.cursorId === 0 || stmt.isDdl) {
8181
options |= constants.TNS_EXEC_OPTION_PARSE;
8282
}
8383
if (stmt.isQuery) {
8484
if (this.parseOnly) {
8585
options |= constants.TNS_EXEC_OPTION_DESCRIBE;
8686
} else {
87-
if (this.options.prefetchRows > 0) {
88-
options |= constants.TNS_EXEC_OPTION_FETCH;
89-
}
9087
if (stmt.cursorId === 0 || stmt.requiresDefine) {
9188
numIters = this.options.prefetchRows;
9289
} else {
9390
numIters = this.options.fetchArraySize;
9491
}
92+
if (numIters > 0 && !stmt.noPrefetch) {
93+
options |= constants.TNS_EXEC_OPTION_FETCH;
94+
}
9595
}
9696
}
9797
if (!stmt.isPlSql && !this.parseOnly) {
@@ -276,7 +276,7 @@ class ExecuteMessage extends MessageWithData {
276276
if (this.currentRow === 0) {
277277
let stmt = this.statement;
278278
if (stmt.cursorId !== 0 && !stmt.requiresFullExecute && !this.parseOnly && !stmt.requiresDefine && !stmt.isDdl && !this.batchErrors) {
279-
if (stmt.isQuery && !stmt.requiresDefine && this.options.prefetchRows > 0) {
279+
if (stmt.isQuery && !stmt.requiresDefine && !stmt.noPrefetch && this.options.prefetchRows > 0) {
280280
this.functionCode = constants.TNS_FUNC_REEXECUTE_AND_FETCH;
281281
} else {
282282
this.functionCode = constants.TNS_FUNC_REEXECUTE;

lib/thin/protocol/messages/withData.js

+1
Original file line numberDiff line numberDiff line change
@@ -547,6 +547,7 @@ class MessageWithData extends Message {
547547
variable.maxSize = constants.TNS_MAX_LONG_LENGTH;
548548
}
549549
resultSet.statement.requiresDefine = true;
550+
resultSet.statement.noPrefetch = true;
550551
}
551552
}
552553
}

lib/thin/statement.js

+1
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ class Statement {
9393
this.queryVars = [];
9494
this.bindInfoDict = new Map();
9595
this.requiresFullExecute = false;
96+
this.noPrefetch = false;
9697
this.returnToCache = false;
9798
this.numColumns = 0;
9899
this.lastRowIndex;

test/dataTypeClob.js

+40
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ const fs = require('fs');
4242
const assert = require('assert');
4343
const dbConfig = require('./dbconfig.js');
4444
const assist = require('./dataTypeAssist.js');
45+
const testsUtil = require('./testsUtil.js');
4546

4647
let inFileName = 'test/clobexample.txt'; // the file with text to be inserted into the database
4748
let outFileName = 'test/clobstreamout.txt'; // output file with the stream out data
@@ -170,4 +171,43 @@ describe('40. dataTypeClob.js', function() {
170171
await assist.verifyNullValues(connection, tableName);
171172
});
172173
});
174+
175+
describe('40.3 Read CLOB data on meta data change', function() {
176+
let connection = null;
177+
const tableNameCLOB = 'nodb_myclobs_re_create';
178+
const sqlCreateQuery = `
179+
CREATE TABLE ${tableNameCLOB} (
180+
num NUMBER,
181+
content CLOB
182+
)`;
183+
const sqlDrop = testsUtil.sqlDropTable(tableNameCLOB);
184+
const sqlCreate = testsUtil.sqlCreateTable(tableNameCLOB, sqlCreateQuery);
185+
const insertSql = `INSERT INTO ${tableNameCLOB} (num, content) ` +
186+
`VALUES (:n, 'CLOB')`;
187+
const selectSql = `SELECT content FROM ${tableNameCLOB} WHERE num = 1`;
188+
189+
before(async function() {
190+
oracledb.fetchAsString = [oracledb.CLOB];
191+
connection = await oracledb.getConnection(dbConfig);
192+
await connection.execute(sqlCreate);
193+
await connection.execute(insertSql, { n: 1 }, { autoCommit: false });
194+
});
195+
196+
after(async function() {
197+
oracledb.fetchAsString = [];
198+
await connection.execute(sqlDrop);
199+
await connection.close();
200+
});
201+
202+
it('40.3.1 Recreate table after CLOB column is read and statement is in statement cache',
203+
async function() {
204+
await connection.execute(selectSql, {}, { keepInStmtCache: true });
205+
await connection.execute(sqlDrop);
206+
await connection.execute(sqlCreate);
207+
await connection.execute(insertSql, { n: 1 }, { autoCommit: false });
208+
await connection.execute(selectSql);
209+
});
210+
211+
});
212+
173213
});

test/lobBind2.js

+35
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ const fs = require('fs');
3636
const fsPromises = require('fs/promises');
3737
const assert = require('assert');
3838
const dbConfig = require('./dbconfig.js');
39+
const testsUtil = require('./testsUtil.js');
3940

4041
describe("72. lobBind2.js", function() {
4142

@@ -539,4 +540,38 @@ describe("72. lobBind2.js", function() {
539540

540541
}); // 72.3
541542

543+
describe('72.4 Create Table with CLOB and Number columns and do select with empty rows and select after rows insertion', function() {
544+
let connection = null;
545+
const tableNameCLOB = 'nodb_myclobs_num_table';
546+
const sqlCreateQuery = `
547+
CREATE TABLE ${tableNameCLOB} (
548+
F1 NUMBER,
549+
F2 CLOB,
550+
F3 CLOB
551+
)`;
552+
const sqlDrop = testsUtil.sqlDropTable(tableNameCLOB);
553+
const sqlCreate = testsUtil.sqlCreateTable(tableNameCLOB, sqlCreateQuery);
554+
const insertSql = `INSERT INTO ${tableNameCLOB} (F1, F2, F3) ` +
555+
`VALUES (:1, :2, :3)`;
556+
const selectSql = `SELECT * FROM ${tableNameCLOB} `;
557+
558+
before(async function() {
559+
oracledb.fetchAsString = [oracledb.CLOB];
560+
connection = await oracledb.getConnection(dbConfig);
561+
await connection.execute(sqlCreate);
562+
await connection.execute(selectSql, {}, {keepInStmtCache: true});
563+
await connection.execute(insertSql, [1, 'CLOB1', 'CLOB2']);
564+
});
565+
566+
after(async function() {
567+
oracledb.fetchAsString = [];
568+
await connection.execute(sqlDrop);
569+
await connection.close();
570+
});
571+
572+
it('72.4.1 Read both CLOB and Number with statement being in statement cache', async function() {
573+
await connection.execute(selectSql, {}, {keepInStmtCache: true});
574+
});
575+
576+
});
542577
});

0 commit comments

Comments
 (0)