Skip to content

Commit b0770ef

Browse files
committed
Fix for Issue #1573 - Handle large number of outbinds
1 parent de953ce commit b0770ef

File tree

2 files changed

+164
-3
lines changed

2 files changed

+164
-3
lines changed

lib/thin/protocol/messages/withData.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -316,10 +316,11 @@ class MessageWithData extends Message {
316316
processIOVector(buf) {
317317
let numBytes;
318318
buf.skipUB1(); // flag
319-
const numBinds = buf.readUB2(); // num requests
320-
this.rowIndex = buf.readUB4(); // iter num
319+
const temp16 = buf.readUB2(); // num requests
320+
const temp32 = buf.readUB4(); // iter num
321+
const numBinds = temp32 * 256 + temp16;
321322
buf.skipUB4(); // num iters this time
322-
buf.readUB2(); // uac buffer length
323+
buf.skipUB2(); // uac buffer length
323324
numBytes = buf.readUB2(); // bit vector for fast fetch
324325
if (numBytes > 0) {
325326
buf.skipBytes(numBytes);

test/binding.js

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -956,4 +956,164 @@ describe('4. binding.js', function() {
956956
}
957957
});
958958
});
959+
960+
describe('4.14 binding large number of in and out binds', function() {
961+
962+
let connection = null;
963+
const numOutBinds = 500;
964+
const colCnt = 500;
965+
const rowCnt = 100;
966+
const tableNameBinds = 'nodb_large_bind_count_table';
967+
const bindsOutNumber = { type: oracledb.DB_TYPE_NUMBER, dir: oracledb.BIND_OUT };
968+
const bindsInNumber = { type: oracledb.NUMBER };
969+
const createSQlFn = function(colCnt) {
970+
let colNames = 'F1 NUMBER(6,0)';
971+
for (let i = 2; i <= colCnt; i++) {
972+
colNames += `, F${i} NUMBER(6,0)`;
973+
}
974+
return `create table ${tableNameBinds} ` + `(` + colNames + `)`;
975+
};
976+
const sqlCreateQuery = createSQlFn(colCnt);
977+
const sqlDrop = testsUtil.sqlDropTable(tableNameBinds);
978+
const sqlCreate = testsUtil.sqlCreateTable(tableNameBinds, sqlCreateQuery);
979+
980+
before(async function() {
981+
connection = await oracledb.getConnection(dbConfig);
982+
await connection.execute(sqlCreate);
983+
});
984+
985+
after(async function() {
986+
await connection.execute(sqlDrop);
987+
await connection.close();
988+
});
989+
990+
it('4.14.1 output binds in pl/sql', async function() {
991+
const maxValue = 10;
992+
const minValue = 2;
993+
const sql = `
994+
BEGIN
995+
${Array(numOutBinds).fill(null).map((_, i) => `:v_out_${i}_0 := :a_${i} + :b_${i} + :c_${i}; `).join('\n ')}
996+
END;
997+
`;
998+
const _genRandNum = function() {
999+
let rand = Math.random();
1000+
rand = Math.floor(rand * (maxValue - minValue));
1001+
rand = rand + minValue;
1002+
return rand;
1003+
};
1004+
const params = Array(numOutBinds).fill(null).map((_, i) => ({ [`a_${i}`]: _genRandNum(), [`b_${i}`]: _genRandNum(),
1005+
[`c_${i}`]: _genRandNum() }))
1006+
.reduce((a, x) => ({ ...a, ...x }), {});
1007+
1008+
const bindDefsIn = {};
1009+
const bindDefsOut = {};
1010+
for (let i = 0; i < numOutBinds; i++) {
1011+
bindDefsIn[`a_${i}`] = bindsInNumber;
1012+
bindDefsIn[`b_${i}`] = bindsInNumber;
1013+
bindDefsIn[`c_${i}`] = bindsInNumber;
1014+
bindDefsOut[`v_out_${i}_0`] = bindsOutNumber;
1015+
}
1016+
const binds = Object.assign(bindDefsIn, bindDefsOut);
1017+
const options = {
1018+
bindDefs: binds
1019+
};
1020+
1021+
let bulkValues = [];
1022+
for (let i = 0; i < rowCnt; i++) {
1023+
bulkValues.push(params);
1024+
}
1025+
const result = await connection.executeMany(sql, bulkValues, options);
1026+
const outParams = {};
1027+
for (let i = 0; i < numOutBinds; i++) {
1028+
outParams[`v_out_${i}_0`] = params[`a_${i}`] + params[`b_${i}`] + params[`c_${i}`];
1029+
}
1030+
for (let i = 0; i < rowCnt; i++) {
1031+
assert.deepStrictEqual(outParams, result.outBinds[i]);
1032+
}
1033+
});
1034+
1035+
it('4.14.2 output binds using bindByPosition in sql with returning clause', async function() {
1036+
const numValue = 15;
1037+
const values = Array(colCnt).fill(numValue);
1038+
let bindstring = ':1';
1039+
let retClause = 'returning F1';
1040+
let intoClause = ` INTO :${colCnt + 1}`;
1041+
let bindDefsIn = [bindsInNumber];
1042+
const bindDefsOut = [bindsOutNumber];
1043+
const lastOutBindNum = 2 * colCnt;
1044+
1045+
for (let i = 2; i <= colCnt; i++) {
1046+
bindstring += `, :${i}`;
1047+
retClause += `, F${i}`;
1048+
bindDefsIn.push(bindsInNumber);
1049+
bindDefsOut.push(bindsOutNumber);
1050+
}
1051+
for (let i = colCnt + 2; i <= lastOutBindNum; i++) {
1052+
intoClause += `, :${i}`;
1053+
}
1054+
retClause += intoClause;
1055+
1056+
const binds = bindDefsIn.concat(bindDefsOut);
1057+
const options = {
1058+
bindDefs: binds
1059+
};
1060+
let bulkValues = [];
1061+
for (let i = 0; i < rowCnt; i++) {
1062+
bulkValues.push(values);
1063+
}
1064+
let insertSql = ` insert into ${tableNameBinds} values(` + bindstring + `) ` + retClause;
1065+
const result = await connection.executeMany(insertSql, bulkValues, options);
1066+
1067+
const outBinds = result.outBinds;
1068+
assert.strictEqual(result.rowsAffected, bulkValues.length);
1069+
for (let i = 0; i < outBinds.length; i++) {
1070+
for (let j = 0; j < colCnt; j++) {
1071+
assert.strictEqual(outBinds[i][j][0], bulkValues[i][j]);
1072+
}
1073+
}
1074+
});
1075+
1076+
it('4.14.3 output binds using bindByName in sql with returning clause', async function() {
1077+
const values = {};
1078+
let bindstring = ':B1';
1079+
let retClause = 'returning F1';
1080+
let intoClause = ' INTO :OB1';
1081+
const bindDefsIn = {};
1082+
const bindDefsOut = {};
1083+
const numValue = 15;
1084+
1085+
bindDefsIn['B1'] = bindsInNumber;
1086+
bindDefsOut['OB1'] = bindsOutNumber;
1087+
values['B1'] = numValue;
1088+
for (let i = 2; i <= colCnt; i++) {
1089+
bindstring += `, :B${i}`;
1090+
retClause += `, F${i}`;
1091+
values[`B${i}`] = numValue;
1092+
bindDefsIn[`B${i}`] = bindsInNumber;
1093+
bindDefsOut[`OB${i}`] = bindsOutNumber;
1094+
intoClause += `, :OB${i}`;
1095+
}
1096+
// construct out Bind Parameters
1097+
retClause += intoClause;
1098+
1099+
const binds = Object.assign(bindDefsIn, bindDefsOut);
1100+
const options = {
1101+
bindDefs: binds
1102+
};
1103+
let bulkValues = [];
1104+
for (let i = 0; i < rowCnt; i++) {
1105+
bulkValues.push(values);
1106+
}
1107+
let insertSql = ` insert into ${tableNameBinds} values(` + bindstring + `) ` + retClause;
1108+
const result = await connection.executeMany(insertSql, bulkValues, options);
1109+
1110+
const outBinds = result.outBinds;
1111+
assert.strictEqual(result.rowsAffected, bulkValues.length);
1112+
for (let i = 0; i < outBinds.length; i++) {
1113+
for (let j = 1; j <= colCnt; j++) {
1114+
assert.strictEqual(outBinds[i][`OB${j}`][0], bulkValues[i][`B${j}`]);
1115+
}
1116+
}
1117+
});
1118+
});
9591119
});

0 commit comments

Comments
 (0)