Skip to content

Commit bc58a22

Browse files
committed
Throw Error for DMLS having Duplicate bind by names in the input and RETURNING INTO SQL clause (Issue #1652)
1 parent 3d1a737 commit bc58a22

File tree

5 files changed

+58
-0
lines changed

5 files changed

+58
-0
lines changed

doc/src/release_notes.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,14 @@ node-oracledb `v6.5.0 <https://github.com/oracle/node-oracledb/compare/v6.4.0...
1313
Thin Mode Changes
1414
++++++++++++++++++
1515

16+
#) Error ``NJS-149: the bind variable placeholder "%s" cannot be used
17+
both before and after the RETURNING clause in a DML RETURNING statement``
18+
is now raised when the same bind variable placeholder name is used both
19+
before and after the RETURNING clause in a
20+
:ref:`DML RETURNING statement <dml-returning-bind>`. Previously, various
21+
internal errors were raised.
22+
See `Issue #1652 <https://github.com/oracle/node-oracledb/issues/1652>`__.
23+
1624
#) Added support for Oracle Database 23c
1725
:ref:`Implicit Connection Pooling <implicitpool>` in DRCP and PRCP.
1826

lib/errors.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,8 @@ const ERR_VECTOR_FORMAT_NOT_SUPPORTED = 144;
144144
const ERR_VECTOR_VERSION_NOT_SUPPORTED = 145;
145145
const ERR_OBJECT_IS_NOT_A_COLLECTION = 146;
146146
const ERR_CURSOR_HAS_BEEN_CLOSED = 147;
147+
const ERR_INVALID_POOL_BOUNDARY = 148;
148+
const ERR_DML_RETURNING_DUP_BINDS = 149;
147149

148150
// Oracle Net layer errors start from 500
149151
const ERR_CONNECTION_CLOSED = 500;
@@ -420,6 +422,10 @@ messages.set(ERR_OBJECT_IS_NOT_A_COLLECTION, // NJS-146
420422
'object %s is not a collection');
421423
messages.set(ERR_CURSOR_HAS_BEEN_CLOSED, // NJS-147
422424
'cursor has been closed by the database');
425+
messages.set(ERR_INVALID_POOL_BOUNDARY, // NJS-148
426+
'invalid value of POOL_BOUNDARY in connect string');
427+
messages.set(ERR_DML_RETURNING_DUP_BINDS, // NJS-149
428+
'the bind variable placeholder "%s" cannot be used both before and after the RETURNING clause in a DML RETURNING statement');
423429

424430
// Oracle Net layer errors
425431

@@ -812,6 +818,8 @@ module.exports = {
812818
ERR_VECTOR_VERSION_NOT_SUPPORTED,
813819
ERR_OBJECT_IS_NOT_A_COLLECTION,
814820
ERR_CURSOR_HAS_BEEN_CLOSED,
821+
ERR_INVALID_POOL_BOUNDARY,
822+
ERR_DML_RETURNING_DUP_BINDS,
815823
ERR_CONNECTION_CLOSED_CODE: `${ERR_PREFIX}-${ERR_CONNECTION_CLOSED}`,
816824
WRN_COMPILATION_CREATE,
817825
assert,

lib/thin/statement.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828

2929
const { Buffer } = require('buffer');
3030
const constants = require('../constants');
31+
const errors = require('../errors');
3132

3233
/**
3334
* It is used to cache the metadata about bind information
@@ -496,6 +497,12 @@ class Statement {
496497
const info = new BindInfo(name, this.isReturning);
497498
this.bindInfoList.push(info);
498499
if (this.bindInfoDict.has(info.bindName)) {
500+
if (this.isReturning) {
501+
const origInfo = this.bindInfoDict.get(info.bindName)[0];
502+
if (!origInfo.isReturnBind) {
503+
errors.throwErr(errors.ERR_DML_RETURNING_DUP_BINDS, name);
504+
}
505+
}
499506
this.bindInfoDict.get(info.bindName).push(info);
500507
} else {
501508
this.bindInfoDict.set(info.bindName, [info]);

test/dmlReturning.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,40 @@ describe('6. dmlReturning.js', function() {
327327
assert.deepStrictEqual(info.bindNames, ["I", "RID", "MÉIL"]);
328328
});
329329

330+
it('6.1.16 Execute DML with Duplicated bind names for input and returning into clause', async function() {
331+
if (!oracledb.thin) {
332+
this.skip();
333+
}
334+
335+
// Insert DML with returning into clause
336+
let sql = "INSERT INTO nodb_dmlreturn (id, name) VALUES (:int_val, :str_val) RETURNING id, name into :rid, :str_val";
337+
let inpstr = "A different test string";
338+
let binds = {
339+
int_val: 6,
340+
rid: { type: oracledb.NUMBER, dir: oracledb.BIND_OUT },
341+
str_val: { type: oracledb.STRING, val: inpstr, dir: oracledb.BIND_INOUT, maxSize: inpstr.length }
342+
};
343+
const options = {
344+
autoCommit: true
345+
};
346+
await assert.rejects(
347+
async () => await connection.execute(sql, binds, options),
348+
/NJS-149:/
349+
);
350+
351+
// update DML with returning into clause
352+
sql = "update nodb_dmlreturn set name = name || :name_val where id = :id_val returning name into :name_val";
353+
inpstr = "A different test string";
354+
binds = {
355+
id_val: 6,
356+
name_val: { type: oracledb.STRING, val: inpstr, dir: oracledb.BIND_INOUT, maxSize: 500 }
357+
};
358+
await assert.rejects(
359+
async () => await connection.execute(sql, binds, options),
360+
/NJS-149:/
361+
);
362+
});
363+
330364
}); // 6.1
331365

332366
describe('6.2 DATE and TIMESTAMP data', function() {

test/list.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ Overview of node-oracledb functional tests
210210
6.1.13 INSERT statement with NaN
211211
6.1.14 INSERT statement with an invalid bind name (reserved namespace keyword)
212212
6.1.15 INSERT statement parse non ascii returning bind
213+
6.1.16 Execute DML with Duplicated bind names for input and returning into clause
213214
6.2 DATE and TIMESTAMP data
214215
6.2.1 INSERT statement, single row matched, Object binding, no bind in data
215216
6.2.2 INSERT statement with JavaScript date bind in

0 commit comments

Comments
 (0)