Skip to content

Commit 483a211

Browse files
committed
Improved bind error message NJS-098 with cleaner description that is thrown for all bind mismatch scenarios
1 parent 902e4db commit 483a211

File tree

5 files changed

+126
-9
lines changed

5 files changed

+126
-9
lines changed

doc/src/release_notes.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@ Thin Mode Changes
7272

7373
#) Provide additional error details when an invalid wallet is used.
7474

75+
#) Improved bind error message ``NJS-098`` with cleaner description that is
76+
thrown for all bind mismatch scenarios.
77+
7578
Thick Mode changes
7679
++++++++++++++++++
7780

lib/errors.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ const ERR_MISSING_FILE = 91;
108108
const ERR_INVALID_NUMBER_OF_CONNECTIONS = 92;
109109
const ERR_EXEC_MODE_ONLY_FOR_DML = 95;
110110
const ERR_INVALID_BIND_NAME = 97;
111-
const ERR_WRONG_NUMBER_OF_POSITIONAL_BINDS = 98;
111+
const ERR_WRONG_NUMBER_OF_BINDS = 98;
112112
const ERR_BUFFER_LENGTH_INSUFFICIENT = 99;
113113
const ERR_NCHAR_CS_NOT_SUPPORTED = 100;
114114
const ERR_MISSING_CREDENTIALS = 101;
@@ -353,8 +353,8 @@ messages.set(ERR_EXEC_MODE_ONLY_FOR_DML, // NJS-095
353353
'setting "batchErrors" or "dmlRowCounts" to true is only permitted for DML statements');
354354
messages.set(ERR_INVALID_BIND_NAME, // NJS-097
355355
'no bind placeholder named ":%s" was found in the statement text');
356-
messages.set(ERR_WRONG_NUMBER_OF_POSITIONAL_BINDS, // NJS-098
357-
'%s positional bind values are required but %s were provided');
356+
messages.set(ERR_WRONG_NUMBER_OF_BINDS, // NJS-098
357+
'%s bind placeholders were used in the SQL statement but %s bind values were provided');
358358
messages.set(ERR_BUFFER_LENGTH_INSUFFICIENT, // NJS-099
359359
'internal error: buffer of length %s insufficient to hold %s bytes');
360360
messages.set(ERR_NCHAR_CS_NOT_SUPPORTED, // NJS-100
@@ -841,7 +841,7 @@ module.exports = {
841841
ERR_CONFIG_PROVIDER_LOAD_FAILED,
842842
ERR_WALLET_TYPE_NOT_SUPPORTED,
843843
ERR_INVALID_BIND_NAME,
844-
ERR_WRONG_NUMBER_OF_POSITIONAL_BINDS,
844+
ERR_WRONG_NUMBER_OF_BINDS,
845845
ERR_BUFFER_LENGTH_INSUFFICIENT,
846846
ERR_NCHAR_CS_NOT_SUPPORTED,
847847
ERR_MISSING_CREDENTIALS,

lib/thin/connection.js

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -170,11 +170,22 @@ class ThinConnectionImpl extends ConnectionImpl {
170170
async _execute(statement, numIters, binds, options, executeManyFlag) {
171171

172172
// perform binds
173-
const numBinds = statement.bindInfoList.length;
174-
const numVars = binds.length;
175-
if (numBinds !== numVars && (numVars === 0 || !binds[0].name)) {
176-
errors.throwErr(errors.ERR_WRONG_NUMBER_OF_POSITIONAL_BINDS, numBinds, numVars);
173+
const numStmtBinds = statement.bindInfoList.length;
174+
const numUserBinds = binds.length;
175+
if (numStmtBinds !== numUserBinds) {
176+
if (!binds[0]?.name) {
177+
// positional bind mismatch or zero binds
178+
errors.throwErr(errors.ERR_WRONG_NUMBER_OF_BINDS, numStmtBinds, numUserBinds);
179+
}
180+
181+
// named bind mismatch
182+
// Find the number of distinct named bind placeholders and see
183+
// if they match the bind values
184+
const numDistinctStmtBinds = statement.bindInfoDict.size;
185+
if (numDistinctStmtBinds !== numUserBinds)
186+
errors.throwErr(errors.ERR_WRONG_NUMBER_OF_BINDS, numStmtBinds, numUserBinds);
177187
}
188+
178189
for (let i = 0; i < binds.length; i++) {
179190
await this._bind(statement, binds[i], i + 1);
180191
}

test/binding.js

Lines changed: 96 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -777,10 +777,61 @@ describe('4. binding.js', function() {
777777
await connection.execute(sql);
778778
},
779779
//ORA-01008: not all variables bound
780-
//NJS-098: 1 positional bind values are required but 0 were provided
780+
//NJS-098: 1 bind placeholders were used in the SQL statement but 0 bind values were provided
781781
/ORA-01008:|NJS-098:/
782782
);
783783
});
784+
785+
it('4.9.4 not using a bind name in execute statement - repeated bind placeholders', async function() {
786+
const sql = 'select :val, bind(:val) from dual';
787+
await assert.rejects(
788+
async () => {
789+
await connection.execute(sql);
790+
},
791+
//ORA-01008: not all variables bound
792+
//NJS-098: 2 bind placeholders were used in the SQL statement but 0 bind values were provided
793+
/ORA-01008:|NJS-098:/
794+
);
795+
});
796+
797+
it('4.9.5 mismatch of named binds - lower number of bind values', async function() {
798+
const sql = 'select :val1, :val2 from dual';
799+
const binds = {val1: 1};
800+
await assert.rejects(
801+
async () => {
802+
await connection.execute(sql, binds);
803+
},
804+
//ORA-01008: not all variables bound
805+
//NJS-098: 2 bind placeholders were used in the SQL statement but 1 bind values were provided
806+
/ORA-01008:|NJS-098:/
807+
);
808+
});
809+
810+
it('4.9.6 mismatch of named repeated binds - lower number of bind values', async function() {
811+
const sql = 'select :val1, bind(:val1), :val2 from dual';
812+
const binds = {val1: 1};
813+
await assert.rejects(
814+
async () => {
815+
await connection.execute(sql, binds);
816+
},
817+
//ORA-01008: not all variables bound
818+
//NJS-098: 3 bind placeholders were used in the SQL statement but 1 bind values were provided
819+
/ORA-01008:|NJS-098:/
820+
);
821+
});
822+
823+
it('4.9.7 mismatch of named binds - higher number of bind values', async function() {
824+
const sql = 'select :val1 from dual';
825+
const binds = {val1: 1, val2: 2};
826+
await assert.rejects(
827+
async () => {
828+
await connection.execute(sql, binds);
829+
},
830+
//ORA-01036: illegal variable name/number
831+
//NJS-098: 1 bind placeholders were used in the SQL statement but 2 bind values were provided
832+
/ORA-01036:|NJS-098:/
833+
);
834+
});
784835
}); // 4.9
785836

786837
describe('4.10 various quoted binds', function() {
@@ -1187,4 +1238,48 @@ describe('4. binding.js', function() {
11871238
assert(newOpenCount - openCount < 4);
11881239
});
11891240
});
1241+
1242+
describe('4.16 positional binding', function() {
1243+
let connection = null;
1244+
before(async function() {
1245+
connection = await oracledb.getConnection(dbConfig);
1246+
});
1247+
1248+
after(async function() {
1249+
await connection.close();
1250+
});
1251+
1252+
it('4.16.1 Matching bind values', async function() {
1253+
const sql = 'select :1, :2, :3 from dual';
1254+
const binds = [1, 2, 3];
1255+
const result = await connection.execute(sql, binds);
1256+
assert.strictEqual(result.rows[0][0], 1);
1257+
assert.strictEqual(result.rows[0][2], 3);
1258+
});
1259+
1260+
it('4.16.2 Negative - bind mismatch of zero bind values', async function() {
1261+
const sql = 'select :1, dump(:2) from dual';
1262+
await assert.rejects(
1263+
async () => {
1264+
await connection.execute(sql);
1265+
},
1266+
//ORA-01008: not all variables bound
1267+
//NJS-098: 2 bind placeholders were used in the SQL statement but 0 bind values were provided
1268+
/ORA-01008:|NJS-098:/
1269+
);
1270+
});
1271+
1272+
it('4.16.3 Negative - bind mismatch of non-zero bind values', async function() {
1273+
const sql = 'select :1, dump(:2), :3 from dual';
1274+
const binds = [1];
1275+
await assert.rejects(
1276+
async () => {
1277+
await connection.execute(sql, binds);
1278+
},
1279+
//ORA-01008: not all variables bound
1280+
//NJS-098: 3 bind placeholders were used in the SQL statement but 1 bind values were provided
1281+
/ORA-01008:|NJS-098:/
1282+
);
1283+
});
1284+
});
11901285
});

test/list.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,10 @@ Overview of node-oracledb functional tests
212212
4.9.1 test case sensitivity of quoted bind names
213213
4.9.2 using a reserved keyword as a bind name
214214
4.9.3 not using a bind name in execute statement
215+
4.9.4 not using a bind name in execute statement - repeated bind placeholders
216+
4.9.5 mismatch of named binds - lower number of bind values
217+
4.9.6 mismatch of named repeated binds - lower number of bind values
218+
4.9.7 mismatch of named binds - higher number of bind values
215219
4.10 various quoted binds
216220
4.10.1 various quoted bind names
217221
4.11 PL/SQL block with null Binds
@@ -228,6 +232,10 @@ Overview of node-oracledb functional tests
228232
4.15 binding different data types for same sql
229233
4.15.1 change bindtypes using bindByPosition for queries
230234
4.15.2 change bindtypes using bindByName for queries
235+
4.16 positional binding
236+
4.16.1 Matching bind values
237+
4.16.2 Negative - bind mismatch of zero bind values
238+
4.16.3 Negative - bind mismatch of non-zero bind values
231239

232240
5. externalAuth.js
233241
5.1 tests that work both when DB has configured externalAuth and not configured

0 commit comments

Comments
 (0)