diff --git a/test/blobDMLBindAsBuffer.js b/test/blobDMLBindAsBuffer.js new file mode 100644 index 00000000..cbd59a1e --- /dev/null +++ b/test/blobDMLBindAsBuffer.js @@ -0,0 +1,755 @@ +/* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with the Apache + * License, Version 2.0 (the "License.") + * + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + * The node-oracledb test suite uses 'mocha', 'should' and 'async'. + * See LICENSE.md for relevant licenses. + * + * NAME + * 82. blobDMLBindAsBuffer.js + * + * DESCRIPTION + * Testing BLOB binding as Buffer with DML. + * + * NUMBERING RULE + * Test numbers follow this numbering rule: + * 1 - 20 are reserved for basic functional tests + * 21 - 50 are reserved for data type supporting tests + * 51 onwards are for other tests + * + *****************************************************************************/ +'use strict'; + +var oracledb = require('oracledb'); +var should = require('should'); +var async = require('async'); +var dbConfig = require('./dbconfig.js'); +var random = require('./random.js'); +var fs = require('fs'); +var assist = require('./dataTypeAssist.js'); + +describe('82.blobDMLBindAsBuffer.js', function() { + this.timeout(100000); + + var connection = null; + var node6plus = false; // assume node runtime version is lower than 6 + var insertID = 1; // assume id for insert into db starts from 1 + + var proc_blob_1 = "BEGIN \n" + + " DECLARE \n" + + " e_table_missing EXCEPTION; \n" + + " PRAGMA EXCEPTION_INIT(e_table_missing, -00942); \n" + + " BEGIN \n" + + " EXECUTE IMMEDIATE('DROP TABLE nodb_dml_blob_1 PURGE'); \n" + + " EXCEPTION \n" + + " WHEN e_table_missing \n" + + " THEN NULL; \n" + + " END; \n" + + " EXECUTE IMMEDIATE (' \n" + + " CREATE TABLE nodb_dml_blob_1 ( \n" + + " id NUMBER, \n" + + " blob BLOB \n" + + " ) \n" + + " '); \n" + + "END; "; + var sql2DropTable1 = "DROP TABLE nodb_dml_blob_1 PURGE"; + + before(function(done) { + oracledb.getConnection(dbConfig, function(err, conn) { + should.not.exist(err); + connection = conn; + // Check whether node runtime version is >= 6 or not + if ( process.versions["node"].substring (0, 1) >= "6") + node6plus = true; + + done(); + }); + }); // before + + after(function(done) { + connection.release(function(err) { + should.not.exist(err); + done(); + }); + }); // after + + var executeSQL = function(sql, callback) { + connection.execute( + sql, + function(err) { + should.not.exist(err); + return callback(); + } + ); + }; + + var insertIntoBlobTable1 = function(id, content, callback) { + if(content == "EMPTY_BLOB") { + connection.execute( + "INSERT INTO nodb_dml_blob_1 VALUES (:ID, EMPTY_BLOB())", + [ id ], + function(err, result) { + should.not.exist(err); + should.strictEqual(result.rowsAffected, 1); + callback(); + } + ); + } else { + connection.execute( + "INSERT INTO nodb_dml_blob_1 VALUES (:ID, :C)", + { + ID : { val : id }, + C : { val : content, dir : oracledb.BIND_IN, type : oracledb.BUFFER } + }, + function(err, result) { + should.not.exist(err); + should.strictEqual(result.rowsAffected, 1); + callback(); + } + ); + } + }; + + var updateBlobTable1 = function(id, content, callback) { + if(content == "EMPTY_BLOB") { + connection.execute( + "UPDATE nodb_dml_blob_1 set blob = EMPTY_BLOB() where id = :ID", + { ID: id }, + function(err, result){ + should.not.exist(err); + should.strictEqual(result.rowsAffected, 1); + callback(); + } + ); + } else { + connection.execute( + "UPDATE nodb_dml_blob_1 set blob = :C where id = :ID", + { ID: id, C: content }, + function(err, result){ + should.not.exist(err); + should.strictEqual(result.rowsAffected, 1); + callback(); + } + ); + } + }; + + // compare the inserted blob with orginal content + var verifyBlobValueWithBuffer = function(selectSql, originalBuffer, specialStr, callback) { + connection.execute( + selectSql, + function(err, result) { + should.not.exist(err); + var lob = result.rows[0][0]; + if(originalBuffer == '' || originalBuffer == undefined) { + should.not.exist(lob); + return callback(); + } else { + should.exist(lob); + var blobData = node6plus ? Buffer.alloc(0) : new Buffer(0); + var totalLength = 0; + + lob.on('data', function(chunk) { + totalLength = totalLength + chunk.length; + blobData = Buffer.concat([blobData, chunk], totalLength); + }); + + lob.on('error', function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + lob.on('end', function() { + if(originalBuffer == "EMPTY_BLOB") { + var nullBuffer = node6plus ? Buffer.from('', "utf-8") : new Buffer('', "utf-8"); + should.strictEqual(assist.compare2Buffers(blobData, nullBuffer), true); + } else { + should.strictEqual(totalLength, originalBuffer.length); + var specStrLength = specialStr.length; + should.strictEqual(blobData.toString('utf8', 0, specStrLength), specialStr); + should.strictEqual(blobData.toString('utf8', (totalLength - specStrLength), totalLength), specialStr); + should.strictEqual(assist.compare2Buffers(blobData, originalBuffer), true); + } + return callback(); + }); + } + } + ); + }; + + var checkInsertResult = function(id, content, specialStr, callback) { + var sql = "select blob from nodb_dml_blob_1 where id = " + id; + verifyBlobValueWithBuffer(sql, content, specialStr, callback); + }; + + describe('82.1 BLOB, INSERT', function() { + before(function(done) { + executeSQL(proc_blob_1, done); + }); // before + + after(function(done) { + executeSQL(sql2DropTable1, done); + }); // after + + it('82.1.1 works with EMPTY_BLOB', function(done) { + var id = insertID++; + var content = "EMPTY_BLOB"; + + async.series([ + function(cb) { + insertIntoBlobTable1(id, content, cb); + }, + function(cb) { + checkInsertResult(id, content, null, cb); + } + ], done); + }); // 82.1.1 + + it('82.1.2 works with empty buffer', function(done) { + var id = insertID++; + var bigStr = ''; + var content = node6plus ? Buffer.from(bigStr, "utf-8") : new Buffer(bigStr, "utf-8"); + + async.series([ + function(cb) { + insertIntoBlobTable1(id, content, cb); + }, + function(cb) { + checkInsertResult(id, content, null, cb); + } + ], done); + }); // 82.1.2 + + it('82.1.3 works with empty buffer and bind in maxSize set to 32767', function(done) { + var id = insertID++; + var bigStr = ''; + var content = node6plus ? Buffer.from(bigStr, "utf-8") : new Buffer(bigStr, "utf-8"); + + async.series([ + function(cb) { + connection.execute( + "INSERT INTO nodb_dml_blob_1 VALUES (:ID, :C)", + { + ID : { val : id }, + C : { val : content, dir : oracledb.BIND_IN, type : oracledb.BUFFER, maxSize: 32767 } + }, + function(err, result) { + should.not.exist(err); + should.strictEqual(result.rowsAffected, 1); + cb(); + } + ); + }, + function(cb) { + checkInsertResult(id, content, null, cb); + } + ], done); + }); // 82.1.3 + + it('82.1.4 works with empty buffer and bind in maxSize set to 50000', function(done) { + var id = insertID++; + var bigStr = ''; + var content = node6plus ? Buffer.from(bigStr, "utf-8") : new Buffer(bigStr, "utf-8"); + + async.series([ + function(cb) { + connection.execute( + "INSERT INTO nodb_dml_blob_1 VALUES (:ID, :C)", + { + ID : { val : id }, + C : { val : content, dir : oracledb.BIND_IN, type : oracledb.BUFFER, maxSize: 50000 } + }, + function(err, result) { + should.not.exist(err); + should.strictEqual(result.rowsAffected, 1); + cb(); + } + ); + }, + function(cb) { + checkInsertResult(id, content, null, cb); + } + ], done); + }); // 82.1.4 + + it('82.1.5 works with undefined', function(done) { + var id = insertID++; + var content = undefined; + + async.series([ + function(cb) { + insertIntoBlobTable1(id, content, cb); + }, + function(cb) { + checkInsertResult(id, content, null, cb); + } + ], done); + }); // 82.1.5 + + it('82.1.6 works with null', function(done) { + var id = insertID++; + var content = null; + + async.series([ + function(cb) { + insertIntoBlobTable1(id, content, cb); + }, + function(cb) { + checkInsertResult(id, content, null, cb); + } + ], done); + }); // 82.1.6 + + it('82.1.7 works with null and bind in maxSize set to 32767', function(done) { + var id = insertID++; + var content = null; + + async.series([ + function(cb) { + connection.execute( + "INSERT INTO nodb_dml_blob_1 VALUES (:ID, :C)", + { + ID : { val : id }, + C : { val : content, dir : oracledb.BIND_IN, type : oracledb.BUFFER, maxSize: 32767 } + }, + function(err, result) { + should.not.exist(err); + should.strictEqual(result.rowsAffected, 1); + cb(); + } + ); + }, + function(cb) { + checkInsertResult(id, content, null, cb); + } + ], done); + }); // 82.1.7 + + it('82.1.8 works with null and bind in maxSize set to 50000', function(done) { + var id = insertID++; + var content = null; + + async.series([ + function(cb) { + connection.execute( + "INSERT INTO nodb_dml_blob_1 VALUES (:ID, :C)", + { + ID : { val : id }, + C : { val : content, dir : oracledb.BIND_IN, type : oracledb.BUFFER, maxSize: 50000 } + }, + function(err, result) { + should.not.exist(err); + should.strictEqual(result.rowsAffected, 1); + cb(); + } + ); + }, + function(cb) { + checkInsertResult(id, content, null, cb); + } + ], done); + }); // 82.1.8 + + it('82.1.9 works with NaN', function(done) { + var id = insertID++; + var content = NaN; + + connection.execute( + "INSERT INTO nodb_dml_blob_1 VALUES (:ID, :C)", + { + ID : { val : id }, + C : { val : content, dir : oracledb.BIND_IN, type : oracledb.BUFFER } + }, + function(err) { + should.exist(err); + // NJS-011: encountered bind value and type mismatch in parameter 2 + (err.message).should.startWith('NJS-011:'); + done(); + } + ); + }); // 82.1.9 + + it('82.1.10 works with 0', function(done) { + var id = insertID++; + var content = 0; + + connection.execute( + "INSERT INTO nodb_dml_blob_1 VALUES (:ID, :C)", + { + ID : { val : id }, + C : { val : content, dir : oracledb.BIND_IN, type : oracledb.BUFFER } + }, + function(err) { + should.exist(err); + // NJS-011: encountered bind value and type mismatch in parameter 2 + (err.message).should.startWith('NJS-011:'); + done(); + } + ); + }); // 82.1.10 + + it('82.1.11 works with Buffer length 32K', function(done) { + var id = insertID++; + var contentLength = 32768; + var specialStr = "82.1.11"; + var bigStr = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(bigStr, "utf-8") : new Buffer(bigStr, "utf-8"); + + async.series([ + function(cb) { + insertIntoBlobTable1(id, content, cb); + }, + function(cb) { + checkInsertResult(id, content, specialStr, cb); + } + ], done); + }); // 82.1.11 + + it('82.1.12 works with Buffer length (64K - 1)', function(done) { + var id = insertID++; + var contentLength = 65535; + var specialStr = "82.1.12"; + var bigStr = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(bigStr, "utf-8") : new Buffer(bigStr, "utf-8"); + + async.series([ + function(cb) { + insertIntoBlobTable1(id, content, cb); + }, + function(cb) { + checkInsertResult(id, content, specialStr, cb); + } + ], done); + }); // 82.1.12 + + it('82.1.13 works with Buffer length (64K + 1)', function(done) { + var id = insertID++; + var contentLength = 65537; + var specialStr = "82.1.13"; + var bigStr = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(bigStr, "utf-8") : new Buffer(bigStr, "utf-8"); + + async.series([ + function(cb) { + insertIntoBlobTable1(id, content, cb); + }, + function(cb) { + checkInsertResult(id, content, specialStr, cb); + } + ], done); + }); // 82.1.13 + + it('82.1.14 works with Buffer length (1MB + 1)', function(done) { + var id = insertID++; + var contentLength = 1048577; // 1 * 1024 * 1024 + 1; + var specialStr = "82.1.14"; + var bigStr = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(bigStr, "utf-8") : new Buffer(bigStr, "utf-8"); + + async.series([ + function(cb) { + insertIntoBlobTable1(id, content, cb); + }, + function(cb) { + checkInsertResult(id, content, specialStr, cb); + } + ], done); + }); // 82.1.14 + + it('82.1.15 bind value and type mismatch', function(done) { + var id = insertID++; + var content = 100; + + connection.execute( + "INSERT INTO nodb_dml_blob_1 VALUES (:ID, :C)", + { + ID : { val : id }, + C : { val : content, dir : oracledb.BIND_IN, type : oracledb.BUFFER } + }, + function(err) { + should.exist(err); + // NJS-011: encountered bind value and type mismatch in parameter 2 + (err.message).should.startWith('NJS-011:'); + done(); + } + ); + }); // 82.1.15 + + it('82.1.16 mixing named with positional binding', function(done) { + var id = insertID++; + var contentLength = 40000; + var specialStr = "82.1.16"; + var bigStr = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(bigStr, "utf-8") : new Buffer(bigStr, "utf-8"); + + async.series([ + function(cb) { + connection.execute( + "INSERT INTO nodb_dml_blob_1 VALUES (:1, :2)", + [ + id, { val : content, dir : oracledb.BIND_IN, type : oracledb.BUFFER } + ], + function(err, result) { + should.not.exist(err); + should.strictEqual(result.rowsAffected, 1); + cb(); + } + ); + }, + function(cb) { + checkInsertResult(id, content, specialStr, cb); + } + ], done); + }); // 82.1.16 + + it('82.1.17 bind with invalid BLOB', function(done) { + var id = insertID++; + + connection.execute( + "INSERT INTO nodb_dml_blob_1 VALUES (:1, :2)", + [ + id, { val : {}, dir : oracledb.BIND_IN, type : oracledb.BUFFER } + ], + function(err) { + should.exist(err); + // NJS-011: encountered bind value and type mismatch in parameter 2 + (err.message).should.startWith('NJS-011:'); + done(); + } + ); + }); // 82.1.17 + + it('82.1.18 Negative: RETURNING INTO with bind type BUFFER', function(done) { + var id = insertID++; + var contentLength = 400; + var specialStr = "82.1.18"; + var bigStr = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(bigStr, "utf-8") : new Buffer(bigStr, "utf-8"); + var sql = "INSERT INTO nodb_dml_blob_1 (id, blob) VALUES (:i, :c) RETURNING blob INTO :lobbv"; + + connection.execute( + sql, + { + i: id, + c: { val: content, type: oracledb.BUFFER, dir: oracledb.BIND_IN }, + lobbv: { type: oracledb.BUFFER, dir: oracledb.BIND_OUT, maxSize: contentLength } + }, + function(err) { + should.exist(err); + // NJS-028: RAW database type is not supported with DML Returning statements + (err.message).should.startWith('NJS-028:'); + done(); + } + ); + }); // 82.1.18 + + it('82.1.19 Negative: RETURNING INTO with autocommit on', function(done) { + var id = insertID++; + var sql = "INSERT INTO nodb_dml_blob_1 (id, blob) VALUES (:i, EMPTY_BLOB()) RETURNING blob INTO :lobbv"; + var inFileName = './test/tree.jpg'; + + connection.execute( + sql, + { + i: id, + lobbv: { type: oracledb.BLOB, dir: oracledb.BIND_OUT } + }, + { autoCommit: true }, + function(err, result) { + should.not.exist(err); + var inStream = fs.createReadStream(inFileName); + var lob = result.outBinds.lobbv[0]; + + lob.on('error', function(err) { + should.exist(err); + // ORA-22990: LOB locators cannot span transactions + (err.message).should.startWith('ORA-22990:'); + }); + + inStream.on('error', function(err) { + should.not.exist(err, "inStream.on 'error' event"); + }); + + lob.on('close', function(err) { + should.not.exist(err); + done(); + }); + + inStream.pipe(lob); // copies the text to the CLOB + } + ); + }); // 82.1.19 + + it('82.1.20 works with bind in maxSize smaller than buffer size', function(done) { + var id = insertID++; + var contentLength = 32768; + var specialStr = "82.1.20"; + var bigStr = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(bigStr, "utf-8") : new Buffer(bigStr, "utf-8"); + + async.series([ + function(cb) { + connection.execute( + "INSERT INTO nodb_dml_blob_1 VALUES (:ID, :C)", + { + ID : { val : id }, + C : { val : content, dir : oracledb.BIND_IN, type : oracledb.BUFFER, maxSize: 1 } + }, + function(err, result) { + should.not.exist(err); + should.strictEqual(result.rowsAffected, 1); + cb(); + } + ); + }, + function(cb) { + checkInsertResult(id, content, specialStr, cb); + } + ], done); + }); // 82.1.20 + + }); // 82.1 + + describe('82.2 BLOB, UPDATE', function() { + insertID = 0; + + before(function(done) { + executeSQL(proc_blob_1, done); + }); // before + + after(function(done) { + executeSQL(sql2DropTable1, done); + }); // after + + it('82.2.1 update EMPTY_BLOB column', function(done) { + var id = insertID++; + var content_1 = "EMPTY_BLOB"; + var contentLength_2 = 32768; + var specialStr_2 = "82.2.1"; + var bigStr_2 = random.getRandomString(contentLength_2, specialStr_2); + var content_2 = node6plus ? Buffer.from(bigStr_2, "utf-8") : new Buffer(bigStr_2, "utf-8"); + + async.series([ + function(cb) { + insertIntoBlobTable1(id, content_1, cb); + }, + function(cb) { + checkInsertResult(id, content_1, null, cb); + }, + function(cb) { + updateBlobTable1(id, content_2, cb); + }, + function(cb) { + checkInsertResult(id, content_2, specialStr_2, cb); + } + ], done); + }); // 82.2.1 + + it('82.2.2 update a cloumn with EMPTY_BLOB', function(done) { + var id = insertID++; + var contentLength_1 = 50000; + var specialStr_1 = "82.2.2"; + var bigStr_1 = random.getRandomString(contentLength_1, specialStr_1); + var content_1 = node6plus ? Buffer.from(bigStr_1, "utf-8") : new Buffer(bigStr_1, "utf-8"); + var content_2 = "EMPTY_BLOB"; + + async.series([ + function(cb) { + insertIntoBlobTable1(id, content_1, cb); + }, + function(cb) { + checkInsertResult(id, content_1, specialStr_1, cb); + }, + function(cb) { + updateBlobTable1(id, content_2, cb); + }, + function(cb) { + checkInsertResult(id, content_2, null, cb); + } + ], done); + }); // 82.2.2 + + it('82.2.3 update EMPTY_BLOB column with empty buffer', function(done) { + var id = insertID++; + var content_1 = "EMPTY_BLOB"; + var content_2 = ""; + + async.series([ + function(cb) { + insertIntoBlobTable1(id, content_1, cb); + }, + function(cb) { + checkInsertResult(id, content_1, null, cb); + }, + function(cb) { + updateBlobTable1(id, content_2, cb); + }, + function(cb) { + checkInsertResult(id, content_2, null, cb); + } + ], done); + }); // 82.2.3 + + it('82.2.4 update empty buffer column', function(done) { + var id = insertID++; + var bigStr_1 = ""; + var content_1 = node6plus ? Buffer.from(bigStr_1, "utf-8") : new Buffer(bigStr_1, "utf-8"); + var contentLength_2 = 54321; + var specialStr_2 = "82.2.4"; + var bigStr_2 = random.getRandomString(contentLength_2, specialStr_2); + var content_2 = node6plus ? Buffer.from(bigStr_2, "utf-8") : new Buffer(bigStr_2, "utf-8"); + + async.series([ + function(cb) { + insertIntoBlobTable1(id, content_1, cb); + }, + function(cb) { + checkInsertResult(id, content_1, null, cb); + }, + function(cb) { + updateBlobTable1(id, content_2, cb); + }, + function(cb) { + checkInsertResult(id, content_2, specialStr_2, cb); + } + ], done); + }); // 82.2.4 + + it('82.2.5 update a column with empty buffer', function(done) { + var id = insertID++; + var contentLength_1 = 50000; + var specialStr_1 = "82.2.2"; + var bigStr_1 = random.getRandomString(contentLength_1, specialStr_1); + var content_1 = node6plus ? Buffer.from(bigStr_1, "utf-8") : new Buffer(bigStr_1, "utf-8"); + var content_2 = ""; + + async.series([ + function(cb) { + insertIntoBlobTable1(id, content_1, cb); + }, + function(cb) { + checkInsertResult(id, content_1, specialStr_1, cb); + }, + function(cb) { + updateBlobTable1(id, content_2, cb); + }, + function(cb) { + checkInsertResult(id, content_2, null, cb); + } + ], done); + }); // 82.2.5 + + }); // 82.2 +}); diff --git a/test/blobPlsqlBindAsBuffer_bindin.js b/test/blobPlsqlBindAsBuffer_bindin.js new file mode 100644 index 00000000..42bf65be --- /dev/null +++ b/test/blobPlsqlBindAsBuffer_bindin.js @@ -0,0 +1,1479 @@ +/* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with the Apache + * License, Version 2.0 (the "License.") + * + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + * The node-oracledb test suite uses 'mocha', 'should' and 'async'. + * See LICENSE.md for relevant licenses. + * + * NAME + * 77. blobPlsqlBindAsBuffer_bindin.js + * + * DESCRIPTION + * Testing BLOB binding in as Buffer. + * + * NUMBERING RULE + * Test numbers follow this numbering rule: + * 1 - 20 are reserved for basic functional tests + * 21 - 50 are reserved for data type supporting tests + * 51 onwards are for other tests + * + *****************************************************************************/ +'use strict'; + +var oracledb = require('oracledb'); +var should = require('should'); +var async = require('async'); +var fs = require('fs'); +var dbConfig = require('./dbconfig.js'); +var random = require('./random.js'); +var assist = require('./dataTypeAssist.js'); + +describe('77. blobPlsqlBindAsBuffer_bindin.js', function() { + this.timeout(100000); + var connection = null; + var node6plus = false; // assume node runtime version is lower than 6 + var insertID = 1; // assume id for insert into db starts from 1 + + var proc_blob_in_tab = "BEGIN \n" + + " DECLARE \n" + + " e_table_missing EXCEPTION; \n" + + " PRAGMA EXCEPTION_INIT(e_table_missing, -00942); \n" + + " BEGIN \n" + + " EXECUTE IMMEDIATE('DROP TABLE nodb_tab_blob_in PURGE'); \n" + + " EXCEPTION \n" + + " WHEN e_table_missing \n" + + " THEN NULL; \n" + + " END; \n" + + " EXECUTE IMMEDIATE (' \n" + + " CREATE TABLE nodb_tab_blob_in ( \n" + + " id NUMBER, \n" + + " blob_1 BLOB, \n" + + " blob_2 BLOB \n" + + " ) \n" + + " '); \n" + + "END; "; + + var proc_lobs_in_tab = "BEGIN \n" + + " DECLARE \n" + + " e_table_missing EXCEPTION; \n" + + " PRAGMA EXCEPTION_INIT(e_table_missing, -00942); \n" + + " BEGIN \n" + + " EXECUTE IMMEDIATE('DROP TABLE nodb_tab_lobs_in PURGE'); \n" + + " EXCEPTION \n" + + " WHEN e_table_missing \n" + + " THEN NULL; \n" + + " END; \n" + + " EXECUTE IMMEDIATE (' \n" + + " CREATE TABLE nodb_tab_lobs_in ( \n" + + " id NUMBER, \n" + + " blob BLOB \n" + + " ) \n" + + " '); \n" + + "END; "; + + before(function(done) { + async.series([ + function(cb) { + oracledb.getConnection(dbConfig, function(err, conn) { + should.not.exist(err); + connection = conn; + + // Check whether node runtime version is >= 6 or not + if ( process.versions["node"].substring (0, 1) >= "6") + node6plus = true; + cb(); + }); + }, + function(cb) { + setupAllTable(cb); + } + ], done); + + }); // before + + after(function(done) { + async.series([ + function(cb) { + dropAllTable(cb); + }, + function(cb) { + connection.release(function(err) { + should.not.exist(err); + cb(); + }); + } + ], done); + + }); // after + + var setupAllTable = function(callback) { + async.series([ + function(cb) { + connection.execute( + proc_blob_in_tab, + function(err) { + should.not.exist(err); + cb(); + }); + }, + function(cb) { + connection.execute( + proc_lobs_in_tab, + function(err) { + should.not.exist(err); + cb(); + }); + } + ], callback); + }; + + var dropAllTable = function(callback) { + async.series([ + function(cb) { + connection.execute( + "DROP TABLE nodb_tab_blob_in PURGE", + function(err) { + should.not.exist(err); + cb(); + }); + }, + function(cb) { + connection.execute( + "DROP TABLE nodb_tab_lobs_in PURGE", + function(err) { + should.not.exist(err); + cb(); + }); + } + ], callback); + }; + + var executeSQL = function(sql, callback) { + connection.execute( + sql, + function(err) { + should.not.exist(err); + return callback(); + } + ); + }; + + var jpgFileName = './test/fuzzydinosaur.jpg'; + + var prepareTableWithBlob = function(sql, id, callback) { + var bindVar = { i: id, lobbv: { type: oracledb.BLOB, dir: oracledb.BIND_OUT } }; + + connection.execute( + sql, + bindVar, + { autoCommit: false }, // a transaction needs to span the INSERT and pipe() + function(err, result) { + should.not.exist(err); + (result.rowsAffected).should.be.exactly(1); + (result.outBinds.lobbv.length).should.be.exactly(1); + + var inStream = fs.createReadStream(jpgFileName); + var lob = result.outBinds.lobbv[0]; + + lob.on('error', function(err) { + should.not.exist(err, "lob.on 'error' event"); + }); + + inStream.on('error', function(err) { + should.not.exist(err, "inStream.on 'error' event"); + }); + + lob.on('close', function() { + connection.commit( function(err) { + should.not.exist(err); + return callback(); + }); + }); + + inStream.pipe(lob); + }); + }; + + var verifyBlobValueWithFileData = function(selectSql, callback) { + connection.execute( + selectSql, + function(err, result) { + should.not.exist(err); + var lob = result.rows[0][0]; + should.exist(lob); + + var blobData = 0; + var totalLength = 0; + blobData = node6plus ? Buffer.alloc(0) : new Buffer(0); + + lob.on('data', function(chunk) { + totalLength = totalLength + chunk.length; + blobData = Buffer.concat([blobData, chunk], totalLength); + }); + + lob.on('error', function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + lob.on('end', function() { + fs.readFile( jpgFileName, function(err, originalData) { + should.not.exist(err); + should.strictEqual(totalLength, originalData.length); + originalData.should.eql(blobData); + return callback(); + }); + }); + }); + }; + + var verifyBlobValueWithBuffer = function(selectSql, originalBuffer, specialStr, callback) { + connection.execute( + selectSql, + function(err, result) { + should.not.exist(err); + var lob = result.rows[0][0]; + if (originalBuffer == null || originalBuffer == undefined) { + should.not.exist(lob); + return callback(); + } else { + should.exist(lob); + var blobData = node6plus ? Buffer.alloc(0) : new Buffer(0); + var totalLength = 0; + + lob.on('data', function(chunk) { + totalLength = totalLength + chunk.length; + blobData = Buffer.concat([blobData, chunk], totalLength); + }); + + lob.on('error', function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + lob.on('end', function() { + should.strictEqual(totalLength, originalBuffer.length); + compareResultBufAndOriginal(blobData, totalLength, originalBuffer, specialStr, callback); + }); + } + } + ); + }; + + // compare the result buffer with the original inserted buffer + var compareResultBufAndOriginal = function(resultVal, totalLength, originalBuffer, specialStr, callback) { + if(originalBuffer.length > 0 ) { + var specStrLength = specialStr.length; + should.strictEqual(resultVal.toString('utf8', 0, specStrLength), specialStr); + should.strictEqual(resultVal.toString('utf8', (totalLength - specStrLength), totalLength), specialStr); + } + should.strictEqual(assist.compare2Buffers(resultVal, originalBuffer), true); + callback(); + }; + + // execute the bind in plsql procedure + var plsqlBindIn = function(sqlRun, bindVar, option, callback) { + connection.execute( + sqlRun, + bindVar, + option, + function(err) { + should.not.exist(err); + callback(); + } + ); + }; + + describe('77.1 BLOB, PLSQL, BIND_IN', function() { + var proc = "CREATE OR REPLACE PROCEDURE nodb_blobs_in_771 (blob_id IN NUMBER, blob_in IN BLOB)\n" + + "AS \n" + + "BEGIN \n" + + " insert into nodb_tab_blob_in (id, blob_1) values (blob_id, blob_in); \n" + + "END nodb_blobs_in_771; "; + var sqlRun = "BEGIN nodb_blobs_in_771 (:i, :b); END;"; + var proc_drop = "DROP PROCEDURE nodb_blobs_in_771"; + + var proc_7711 = "CREATE OR REPLACE PROCEDURE nodb_blobs_in_7711 (blob_id IN NUMBER, blob_in IN BLOB)\n" + + "AS \n" + + "BEGIN \n" + + " insert into nodb_tab_blob_in (id, blob_1) values (blob_id, EMPTY_BLOB()); \n" + + "END nodb_blobs_in_7711; "; + var sqlRun_7711 = "BEGIN nodb_blobs_in_7711 (:i, :b); END;"; + var proc_drop_7711 = "DROP PROCEDURE nodb_blobs_in_7711"; + + before(function(done) { + executeSQL(proc, done); + }); // before + + after(function(done) { + executeSQL(proc_drop, done); + }); // after + + it('77.1.1 works with EMPTY_BLOB', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { type: oracledb.BUFFER, dir: oracledb.BIND_IN } + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + executeSQL(proc_7711, cb); + }, + function(cb) { + plsqlBindIn(sqlRun_7711, bindVar, option, cb); + }, + function(cb) { + var sql = "select blob_1 from nodb_tab_blob_in where id = " + sequence; + var emptyBuffer = node6plus ? Buffer.from("", "utf-8") : new Buffer("", "utf-8"); + verifyBlobValueWithBuffer(sql, emptyBuffer, null, cb); + }, + function(cb) { + executeSQL(proc_drop_7711, cb); + } + ], done); + }); // 77.1.1 + + it('77.1.2 works with EMPTY_BLOB and bind in maxSize set to 1', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { type: oracledb.BUFFER, dir: oracledb.BIND_IN, maxSize: 1 } + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + executeSQL(proc_7711, cb); + }, + function(cb) { + plsqlBindIn(sqlRun_7711, bindVar, option, cb); + }, + function(cb) { + var sql = "select blob_1 from nodb_tab_blob_in where id = " + sequence; + var emptyBuffer = node6plus ? Buffer.from("", "utf-8") : new Buffer("", "utf-8"); + verifyBlobValueWithBuffer(sql, emptyBuffer, null, cb); + }, + function(cb) { + executeSQL(proc_drop_7711, cb); + } + ], done); + }); // 77.1.2 + + it('77.1.3 works with EMPTY_BLOB and bind in maxSize set to (64K - 1)', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { type: oracledb.BUFFER, dir: oracledb.BIND_IN, maxSize: 65535 } + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + executeSQL(proc_7711, cb); + }, + function(cb) { + plsqlBindIn(sqlRun_7711, bindVar, option, cb); + }, + function(cb) { + var sql = "select blob_1 from nodb_tab_blob_in where id = " + sequence; + var emptyBuffer = node6plus ? Buffer.from("", "utf-8") : new Buffer("", "utf-8"); + verifyBlobValueWithBuffer(sql, emptyBuffer, null, cb); + }, + function(cb) { + executeSQL(proc_drop_7711, cb); + } + ], done); + }); // 77.1.3 + + it('77.1.4 works with null', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { val: null, type: oracledb.BUFFER, dir: oracledb.BIND_IN } + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + plsqlBindIn(sqlRun, bindVar, option, cb); + }, + function(cb) { + var sql = "select blob_1 from nodb_tab_blob_in where id = " + sequence; + verifyBlobValueWithBuffer(sql, null, null, cb); + } + ], done); + }); // 77.1.4 + + it('77.1.5 works with null and bind in maxSize set to 1', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { val: null, type: oracledb.BUFFER, dir: oracledb.BIND_IN, maxSize: 1 } + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + plsqlBindIn(sqlRun, bindVar, option, cb); + }, + function(cb) { + var sql = "select blob_1 from nodb_tab_blob_in where id = " + sequence; + verifyBlobValueWithBuffer(sql, null, null, cb); + } + ], done); + }); // 77.1.5 + + it('77.1.6 works with null and bind in maxSize set to (64K - 1)', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { val: null, type: oracledb.BUFFER, dir: oracledb.BIND_IN, maxSize: 65535 } + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + plsqlBindIn(sqlRun, bindVar, option, cb); + }, + function(cb) { + var sql = "select blob_1 from nodb_tab_blob_in where id = " + sequence; + verifyBlobValueWithBuffer(sql, null, null, cb); + } + ], done); + }); // 77.1.6 + + it('77.1.7 works with empty buffer', function(done) { + var sequence = insertID++; + var bufferStr = node6plus ? Buffer.from('', "utf-8") : new Buffer('', "utf-8"); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { val: bufferStr, type: oracledb.BUFFER, dir: oracledb.BIND_IN } + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + plsqlBindIn(sqlRun, bindVar, option, cb); + }, + function(cb) { + var sql = "select blob_1 from nodb_tab_blob_in where id = " + sequence; + verifyBlobValueWithBuffer(sql, null, null, cb); + } + ], done); + }); // 77.1.7 + + it('77.1.8 works with empty buffer and bind in maxSize set to 1', function(done) { + var sequence = insertID++; + var bufferStr = node6plus ? Buffer.from('', "utf-8") : new Buffer('', "utf-8"); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { val: bufferStr, type: oracledb.BUFFER, dir: oracledb.BIND_IN, maxSize: 1 } + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + plsqlBindIn(sqlRun, bindVar, option, cb); + }, + function(cb) { + var sql = "select blob_1 from nodb_tab_blob_in where id = " + sequence; + verifyBlobValueWithBuffer(sql, null, null, cb); + } + ], done); + }); // 77.1.8 + + it('77.1.9 works with empty buffer and bind in maxSize set to (64K - 1)', function(done) { + var sequence = insertID++; + var bufferStr = node6plus ? Buffer.from('', "utf-8") : new Buffer('', "utf-8"); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { val: bufferStr, type: oracledb.BUFFER, dir: oracledb.BIND_IN, maxSize: 65535 } + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + plsqlBindIn(sqlRun, bindVar, option, cb); + }, + function(cb) { + var sql = "select blob_1 from nodb_tab_blob_in where id = " + sequence; + verifyBlobValueWithBuffer(sql, null, null, cb); + } + ], done); + }); // 77.1.9 + + it('77.1.10 works with undefined', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { val: undefined, type: oracledb.BUFFER, dir: oracledb.BIND_IN } + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + plsqlBindIn(sqlRun, bindVar, option, cb); + }, + function(cb) { + var sql = "select blob_1 from nodb_tab_blob_in where id = " + sequence; + verifyBlobValueWithBuffer(sql, null, null, cb); + } + ], done); + }); // 77.1.10 + + it('77.1.11 works with undefined and bind in maxSize set to 1', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { val: undefined, type: oracledb.BUFFER, dir: oracledb.BIND_IN, maxSize: 1 } + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + plsqlBindIn(sqlRun, bindVar, option, cb); + }, + function(cb) { + var sql = "select blob_1 from nodb_tab_blob_in where id = " + sequence; + verifyBlobValueWithBuffer(sql, null, null, cb); + } + ], done); + }); // 77.1.11 + + it('77.1.12 works with undefined and bind in maxSize set to (64K - 1)', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { val: undefined, type: oracledb.BUFFER, dir: oracledb.BIND_IN, maxSize: 65535 } + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + plsqlBindIn(sqlRun, bindVar, option, cb); + }, + function(cb) { + var sql = "select blob_1 from nodb_tab_blob_in where id = " + sequence; + verifyBlobValueWithBuffer(sql, null, null, cb); + } + ], done); + }); // 77.1.12 + + it('77.1.13 works with NaN', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { val: NaN, type: oracledb.BUFFER, dir: oracledb.BIND_IN } + }; + + connection.execute( + sqlRun, + bindVar, + { autoCommit: true }, + function(err) { + should.exist(err); + // NJS-011: encountered bind value and type mismatch in parameter 2 + (err.message).should.startWith('NJS-011:'); + done(); + } + ); + }); // 77.1.13 + + it('77.1.14 works with 0', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { val: 0, type: oracledb.BUFFER, dir: oracledb.BIND_IN } + }; + + connection.execute( + sqlRun, + bindVar, + { autoCommit: true }, + function(err) { + should.exist(err); + // NJS-011: encountered bind value and type mismatch in parameter 2 + (err.message).should.startWith('NJS-011:'); + done(); + } + ); + }); // 77.1.14 + + it('77.1.15 works with Buffer size 32K', function(done) { + // Driver already supports CLOB AS STRING and BLOB AS BUFFER for PLSQL BIND if the data size less than or equal to 32767. + // As part of this enhancement, driver allows even if data size more than 32767 for both column types + var sequence = insertID++; + var size = 32768; + var specialStr = "77.1.15"; + var bigStr = random.getRandomString(size, specialStr); + var bufferStr = node6plus ? Buffer.from(bigStr, "utf-8") : new Buffer(bigStr, "utf-8"); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { val: bufferStr, type: oracledb.BUFFER, dir: oracledb.BIND_IN, maxSize: size } + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + plsqlBindIn(sqlRun, bindVar, option, cb); + }, + function(cb) { + var sql = "select blob_1 from nodb_tab_blob_in where id = " + sequence; + verifyBlobValueWithBuffer(sql, bufferStr, specialStr, cb); + } + ], done); + }); // 77.1.15 + + it('77.1.16 works with Buffer size (64K - 1)', function(done) { + var size = 65535; + var sequence = insertID++; + var specialStr = "77.1.16"; + var bigStr = random.getRandomString(size, specialStr); + var bufferStr = node6plus ? Buffer.from(bigStr, "utf-8") : new Buffer(bigStr, "utf-8"); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { val: bufferStr, type: oracledb.BUFFER, dir: oracledb.BIND_IN, maxSize: size } + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + plsqlBindIn(sqlRun, bindVar, option, cb); + }, + function(cb) { + var sql = "select blob_1 from nodb_tab_blob_in where id = " + sequence; + verifyBlobValueWithBuffer(sql, bufferStr, specialStr, cb); + } + ], done); + }); // 77.1.16 + + it('77.1.17 works with Buffer size (64K + 1)', function(done) { + var size = 65537; + var sequence = insertID++; + var specialStr = "77.1.17"; + var bigStr = random.getRandomString(size, specialStr); + var bufferStr = node6plus ? Buffer.from(bigStr, "utf-8") : new Buffer(bigStr, "utf-8"); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { val: bufferStr, type: oracledb.BUFFER, dir: oracledb.BIND_IN, maxSize: size } + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + plsqlBindIn(sqlRun, bindVar, option, cb); + }, + function(cb) { + var sql = "select blob_1 from nodb_tab_blob_in where id = " + sequence; + verifyBlobValueWithBuffer(sql, bufferStr, specialStr, cb); + } + ], done); + }); // 77.1.17 + + it('77.1.18 works with Buffer size (1MB + 1)', function(done) { + var size = 1048577; // 1 * 1024 * 1024 + 1 + var sequence = insertID++; + var specialStr = "77.1.18"; + var bigStr = random.getRandomString(size, specialStr); + var bufferStr = node6plus ? Buffer.from(bigStr, "utf-8") : new Buffer(bigStr, "utf-8"); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { val: bufferStr, type: oracledb.BUFFER, dir: oracledb.BIND_IN, maxSize: size } + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + plsqlBindIn(sqlRun, bindVar, option, cb); + }, + function(cb) { + var sql = "select blob_1 from nodb_tab_blob_in where id = " + sequence; + verifyBlobValueWithBuffer(sql, bufferStr, specialStr, cb); + } + ], done); + }); // 77.1.18 + + it('77.1.19 works with bind value and type mismatch', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { val: 200, type: oracledb.BUFFER, dir: oracledb.BIND_IN, maxSize: 50000 } + }; + + connection.execute( + sqlRun, + bindVar, + { autoCommit: true }, + function(err) { + should.exist(err); + // NJS-011: encountered bind value and type mismatch in parameter 2 + (err.message).should.startWith('NJS-011:'); + done(); + } + ); + }); // 77.1.19 + + it('77.1.20 mixing named with positional binding', function(done) { + var size = 50000; + var sequence = insertID++; + var specialStr = "77.1.20"; + var bigStr = random.getRandomString(size, specialStr); + var bufferStr = node6plus ? Buffer.from(bigStr, "utf-8") : new Buffer(bigStr, "utf-8"); + var bindVar = [ sequence, { val: bufferStr, type: oracledb.BUFFER, dir: oracledb.BIND_IN, maxSize: size } ]; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + var sqlRun_77122 = "BEGIN nodb_blobs_in_771 (:1, :2); END;"; + plsqlBindIn(sqlRun_77122, bindVar, option, cb); + }, + function(cb) { + var sql = "select blob_1 from nodb_tab_blob_in where id = " + sequence; + verifyBlobValueWithBuffer(sql, bufferStr, specialStr, cb); + } + ], done); + }); // 77.1.20 + + it('77.1.21 works with invalid BLOB', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { val: {}, type: oracledb.BUFFER, dir: oracledb.BIND_IN, maxSize: 50000 } + }; + + connection.execute( + sqlRun, + bindVar, + { autoCommit: true }, + function(err) { + should.exist(err); + // NJS-011: encountered bind value and type mismatch + (err.message).should.startWith('NJS-011:'); + done(); + } + ); + }); // 77.1.21 + + it('77.1.22 works without maxSize', function(done) { + var size = 65535; + var sequence = insertID++; + var specialStr = "77.1.22"; + var bigStr = random.getRandomString(size, specialStr); + var bufferStr = node6plus ? Buffer.from(bigStr, "utf-8") : new Buffer(bigStr, "utf-8"); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { val: bufferStr, type: oracledb.BUFFER, dir: oracledb.BIND_IN } + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + plsqlBindIn(sqlRun, bindVar, option, cb); + }, + function(cb) { + var sql = "select blob_1 from nodb_tab_blob_in where id = " + sequence; + verifyBlobValueWithBuffer(sql, bufferStr, specialStr, cb); + } + ], done); + }); // 77.1.22 + + it('77.1.23 works with bind in maxSize smaller than buffer size', function(done) { + var size = 65535; + var sequence = insertID++; + var specialStr = "77.1.23"; + var bigStr = random.getRandomString(size, specialStr); + var bufferStr = node6plus ? Buffer.from(bigStr, "utf-8") : new Buffer(bigStr, "utf-8"); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { val: bufferStr, type: oracledb.BUFFER, dir: oracledb.BIND_IN, maxSize: size - 1 } + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + plsqlBindIn(sqlRun, bindVar, option, cb); + }, + function(cb) { + var sql = "select blob_1 from nodb_tab_blob_in where id = " + sequence; + verifyBlobValueWithBuffer(sql, bufferStr, specialStr, cb); + } + ], done); + }); // 77.1.23 + + it('77.1.24 works with UPDATE', function(done) { + var proc_7726 = "CREATE OR REPLACE PROCEDURE nodb_blobs_in_7726 (blob_id IN NUMBER, blob_in IN BLOB, blob_update IN BLOB)\n" + + "AS \n" + + "BEGIN \n" + + " insert into nodb_tab_blob_in (id, blob_1) values (blob_id, blob_in); \n" + + " update nodb_tab_blob_in set blob_1 = blob_update where id = blob_id; \n" + + "END nodb_blobs_in_7726; "; + var sqlRun_7726 = "BEGIN nodb_blobs_in_7726 (:i, :b1, :b2); END;"; + var proc_drop_7726 = "DROP PROCEDURE nodb_blobs_in_7726"; + var sequence = insertID++; + var size_1 = 65535; + var specialStr_1 = "77.1.24_1"; + var bigStr_1 = random.getRandomString(size_1, specialStr_1); + var bufferStr_1 = node6plus ? Buffer.from(bigStr_1, "utf-8") : new Buffer(bigStr_1, "utf-8"); + var size_2 = 30000; + var specialStr_2 = "77.1.24_2"; + var bigStr_2 = random.getRandomString(size_2, specialStr_2); + var bufferStr_2 = node6plus ? Buffer.from(bigStr_2, "utf-8") : new Buffer(bigStr_2, "utf-8"); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b1: { val: bufferStr_1, type: oracledb.BUFFER, dir: oracledb.BIND_IN, maxSize: size_1 }, + b2: { val: bufferStr_2, type: oracledb.BUFFER, dir: oracledb.BIND_IN, maxSize: size_2 } + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + executeSQL(proc_7726, cb); + }, + function(cb) { + connection.execute( + sqlRun_7726, + bindVar, + option, + function(err) { + should.not.exist(err); + cb(); + }); + }, + function(cb) { + var sql = "select blob_1 from nodb_tab_blob_in where id = " + sequence; + verifyBlobValueWithBuffer(sql, bufferStr_2, specialStr_2, cb); + }, + function(cb) { + executeSQL(proc_drop_7726, cb); + } + ], done); + }); // 77.1.24 + + }); // 77.1 + + describe('77.2 BLOB, PLSQL, BIND_IN to RAW', function() { + var proc = "CREATE OR REPLACE PROCEDURE nodb_blobs_in_771 (blob_id IN NUMBER, blob_in IN RAW)\n" + + "AS \n" + + "BEGIN \n" + + " insert into nodb_tab_blob_in (id, blob_1) values (blob_id, blob_in); \n" + + "END nodb_blobs_in_771; "; + var sqlRun = "BEGIN nodb_blobs_in_771 (:i, :b); END;"; + var proc_drop = "DROP PROCEDURE nodb_blobs_in_771"; + + var proc_7721 = "CREATE OR REPLACE PROCEDURE nodb_blobs_in_7721 (blob_id IN NUMBER, blob_in IN RAW)\n" + + "AS \n" + + "BEGIN \n" + + " insert into nodb_tab_blob_in (id, blob_1) values (blob_id, EMPTY_BLOB()); \n" + + "END nodb_blobs_in_7721; "; + var sqlRun_7721 = "BEGIN nodb_blobs_in_7721 (:i, :b); END;"; + var proc_drop_7721 = "DROP PROCEDURE nodb_blobs_in_7721"; + + before(function(done) { + executeSQL(proc, done); + }); // before + + after(function(done) { + executeSQL(proc_drop, done); + }); // after + + it('77.2.1 works with EMPTY_BLOB', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { type: oracledb.BUFFER, dir: oracledb.BIND_IN } + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + executeSQL(proc_7721, cb); + }, + function(cb) { + plsqlBindIn(sqlRun_7721, bindVar, option, cb); + }, + function(cb) { + var sql = "select blob_1 from nodb_tab_blob_in where id = " + sequence; + var emptyBuffer = node6plus ? Buffer.from("", "utf-8") : new Buffer("", "utf-8"); + verifyBlobValueWithBuffer(sql, emptyBuffer, null, cb); + }, + function(cb) { + executeSQL(proc_drop_7721, cb); + } + ], done); + }); // 77.2.1 + + it('77.2.2 works with EMPTY_BLOB and bind in maxSize set to 1', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { type: oracledb.BUFFER, dir: oracledb.BIND_IN, maxSize: 1 } + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + executeSQL(proc_7721, cb); + }, + function(cb) { + plsqlBindIn(sqlRun_7721, bindVar, option, cb); + }, + function(cb) { + var sql = "select blob_1 from nodb_tab_blob_in where id = " + sequence; + var emptyBuffer = node6plus ? Buffer.from("", "utf-8") : new Buffer("", "utf-8"); + verifyBlobValueWithBuffer(sql, emptyBuffer, null, cb); + }, + function(cb) { + executeSQL(proc_drop_7721, cb); + } + ], done); + }); // 77.2.2 + + it('77.2.3 works with EMPTY_BLOB and bind in maxSize set to (64K - 1)', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { type: oracledb.BUFFER, dir: oracledb.BIND_IN, maxSize: 65535 } + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + executeSQL(proc_7721, cb); + }, + function(cb) { + plsqlBindIn(sqlRun_7721, bindVar, option, cb); + }, + function(cb) { + var sql = "select blob_1 from nodb_tab_blob_in where id = " + sequence; + var emptyBuffer = node6plus ? Buffer.from("", "utf-8") : new Buffer("", "utf-8"); + verifyBlobValueWithBuffer(sql, emptyBuffer, null, cb); + }, + function(cb) { + executeSQL(proc_drop_7721, cb); + } + ], done); + }); // 77.2.3 + + it('77.2.4 works with null', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { val: null, type: oracledb.BUFFER, dir: oracledb.BIND_IN } + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + plsqlBindIn(sqlRun, bindVar, option, cb); + }, + function(cb) { + var sql = "select blob_1 from nodb_tab_blob_in where id = " + sequence; + verifyBlobValueWithBuffer(sql, null, null, cb); + } + ], done); + }); // 77.2.4 + + it('77.2.5 works with null and bind in maxSize set to 1', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { val: null, type: oracledb.BUFFER, dir: oracledb.BIND_IN, maxSize: 1 } + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + plsqlBindIn(sqlRun, bindVar, option, cb); + }, + function(cb) { + var sql = "select blob_1 from nodb_tab_blob_in where id = " + sequence; + verifyBlobValueWithBuffer(sql, null, null, cb); + } + ], done); + }); // 77.2.5 + + it('77.2.6 works with null and bind in maxSize set to (64K - 1)', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { val: null, type: oracledb.BUFFER, dir: oracledb.BIND_IN, maxSize: 65535 } + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + plsqlBindIn(sqlRun, bindVar, option, cb); + }, + function(cb) { + var sql = "select blob_1 from nodb_tab_blob_in where id = " + sequence; + verifyBlobValueWithBuffer(sql, null, null, cb); + } + ], done); + }); // 77.2.6 + + it('77.2.7 works with empty buffer', function(done) { + var sequence = insertID++; + var bufferStr = node6plus ? Buffer.from('', "utf-8") : new Buffer('', "utf-8"); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { val: bufferStr, type: oracledb.BUFFER, dir: oracledb.BIND_IN } + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + plsqlBindIn(sqlRun, bindVar, option, cb); + }, + function(cb) { + var sql = "select blob_1 from nodb_tab_blob_in where id = " + sequence; + verifyBlobValueWithBuffer(sql, null, null, cb); + } + ], done); + }); // 77.2.7 + + it('77.2.8 works with empty buffer and bind in maxSize set to 1', function(done) { + var sequence = insertID++; + var bufferStr = node6plus ? Buffer.from('', "utf-8") : new Buffer('', "utf-8"); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { val: bufferStr, type: oracledb.BUFFER, dir: oracledb.BIND_IN, maxSize: 1 } + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + plsqlBindIn(sqlRun, bindVar, option, cb); + }, + function(cb) { + var sql = "select blob_1 from nodb_tab_blob_in where id = " + sequence; + verifyBlobValueWithBuffer(sql, null, null, cb); + } + ], done); + }); // 77.2.8 + + it('77.2.9 works with empty buffer and bind in maxSize set to (64K - 1)', function(done) { + var sequence = insertID++; + var bufferStr = node6plus ? Buffer.from('', "utf-8") : new Buffer('', "utf-8"); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { val: bufferStr, type: oracledb.BUFFER, dir: oracledb.BIND_IN, maxSize: 65535 } + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + plsqlBindIn(sqlRun, bindVar, option, cb); + }, + function(cb) { + var sql = "select blob_1 from nodb_tab_blob_in where id = " + sequence; + verifyBlobValueWithBuffer(sql, null, null, cb); + } + ], done); + }); // 77.2.9 + + it('77.2.10 works with undefined', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { val: undefined, type: oracledb.BUFFER, dir: oracledb.BIND_IN } + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + plsqlBindIn(sqlRun, bindVar, option, cb); + }, + function(cb) { + var sql = "select blob_1 from nodb_tab_blob_in where id = " + sequence; + verifyBlobValueWithBuffer(sql, null, null, cb); + } + ], done); + }); // 77.2.10 + + it('77.2.11 works with undefined and bind in maxSize set to 1', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { val: undefined, type: oracledb.BUFFER, dir: oracledb.BIND_IN, maxSize: 1 } + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + plsqlBindIn(sqlRun, bindVar, option, cb); + }, + function(cb) { + var sql = "select blob_1 from nodb_tab_blob_in where id = " + sequence; + verifyBlobValueWithBuffer(sql, null, null, cb); + } + ], done); + }); // 77.2.11 + + it('77.2.12 works with undefined and bind in maxSize set to (64K - 1)', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { val: undefined, type: oracledb.BUFFER, dir: oracledb.BIND_IN, maxSize: 65535 } + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + plsqlBindIn(sqlRun, bindVar, option, cb); + }, + function(cb) { + var sql = "select blob_1 from nodb_tab_blob_in where id = " + sequence; + verifyBlobValueWithBuffer(sql, null, null, cb); + } + ], done); + }); // 77.2.12 + + it('77.2.13 works with NaN', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { val: NaN, type: oracledb.BUFFER, dir: oracledb.BIND_IN } + }; + + connection.execute( + sqlRun, + bindVar, + { autoCommit: true }, + function(err) { + should.exist(err); + // NJS-011: encountered bind value and type mismatch in parameter 2 + (err.message).should.startWith('NJS-011:'); + done(); + } + ); + }); // 77.2.13 + + it('77.2.14 works with 0', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { val: 0, type: oracledb.BUFFER, dir: oracledb.BIND_IN } + }; + + connection.execute( + sqlRun, + bindVar, + { autoCommit: true }, + function(err) { + should.exist(err); + // NJS-011: encountered bind value and type mismatch in parameter 2 + (err.message).should.startWith('NJS-011:'); + done(); + } + ); + }); // 77.2.14 + + it('77.2.15 works with Buffer size (32K - 1)', function(done) { + var sequence = insertID++; + var size = 32767; + var specialStr = "77.2.15"; + var bigStr = random.getRandomString(size, specialStr); + var bufferStr = node6plus ? Buffer.from(bigStr, "utf-8") : new Buffer(bigStr, "utf-8"); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { val: bufferStr, type: oracledb.BUFFER, dir: oracledb.BIND_IN, maxSize: size } + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + plsqlBindIn(sqlRun, bindVar, option, cb); + }, + function(cb) { + var sql = "select blob_1 from nodb_tab_blob_in where id = " + sequence; + verifyBlobValueWithBuffer(sql, bufferStr, specialStr, cb); + } + ], done); + }); // 77.2.15 + + it('77.2.16 works with Buffer size 32K', function(done) { + var size = 32768; + var sequence = insertID++; + var specialStr = "77.2.16"; + var bigStr = random.getRandomString(size, specialStr); + var bufferStr = node6plus ? Buffer.from(bigStr, "utf-8") : new Buffer(bigStr, "utf-8"); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { val: bufferStr, type: oracledb.BUFFER, dir: oracledb.BIND_IN, maxSize: size } + }; + + connection.execute( + sqlRun, + bindVar, + function(err) { + should.exist(err); + // ORA-06502: PL/SQL: numeric or value error + (err.message).should.startWith('ORA-06502:'); + done(); + } + ); + }); // 77.2.16 + + it('77.2.17 works with invalid BLOB', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { val: {}, type: oracledb.BUFFER, dir: oracledb.BIND_IN, maxSize: 50000 } + }; + + connection.execute( + sqlRun, + bindVar, + { autoCommit: true }, + function(err) { + should.exist(err); + // NJS-011: encountered bind value and type mismatch + (err.message).should.startWith('NJS-011:'); + done(); + } + ); + }); // 77.2.17 + + it('77.2.18 works without maxSize', function(done) { + var size = 3000; + var sequence = insertID++; + var specialStr = "77.2.18"; + var bigStr = random.getRandomString(size, specialStr); + var bufferStr = node6plus ? Buffer.from(bigStr, "utf-8") : new Buffer(bigStr, "utf-8"); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { val: bufferStr, type: oracledb.BUFFER, dir: oracledb.BIND_IN } + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + plsqlBindIn(sqlRun, bindVar, option, cb); + }, + function(cb) { + var sql = "select blob_1 from nodb_tab_blob_in where id = " + sequence; + verifyBlobValueWithBuffer(sql, bufferStr, specialStr, cb); + } + ], done); + }); // 77.2.18 + + it('77.2.19 works with bind in maxSize smaller than buffer size', function(done) { + var size = 400; + var sequence = insertID++; + var specialStr = "77.2.19"; + var bigStr = random.getRandomString(size, specialStr); + var bufferStr = node6plus ? Buffer.from(bigStr, "utf-8") : new Buffer(bigStr, "utf-8"); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { val: bufferStr, type: oracledb.BUFFER, dir: oracledb.BIND_IN, maxSize: size - 1 } + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + plsqlBindIn(sqlRun, bindVar, option, cb); + }, + function(cb) { + var sql = "select blob_1 from nodb_tab_blob_in where id = " + sequence; + verifyBlobValueWithBuffer(sql, bufferStr, specialStr, cb); + } + ], done); + }); // 77.2.19 + + it('77.2.20 works with UPDATE', function(done) { + var proc_7720 = "CREATE OR REPLACE PROCEDURE nodb_blobs_in_7720 (blob_id IN NUMBER, blob_in IN RAW, blob_update IN RAW)\n" + + "AS \n" + + "BEGIN \n" + + " insert into nodb_tab_blob_in (id, blob_1) values (blob_id, blob_in); \n" + + " update nodb_tab_blob_in set blob_1 = blob_update where id = blob_id; \n" + + "END nodb_blobs_in_7720; "; + var sqlRun_7720 = "BEGIN nodb_blobs_in_7720 (:i, :b1, :b2); END;"; + var proc_drop_7720 = "DROP PROCEDURE nodb_blobs_in_7720"; + var sequence = insertID++; + var size_1 = 3000; + var specialStr_1 = "77.2.20_1"; + var bigStr_1 = random.getRandomString(size_1, specialStr_1); + var bufferStr_1 = node6plus ? Buffer.from(bigStr_1, "utf-8") : new Buffer(bigStr_1, "utf-8"); + var size_2 = 2000; + var specialStr_2 = "77.2.20_2"; + var bigStr_2 = random.getRandomString(size_2, specialStr_2); + var bufferStr_2 = node6plus ? Buffer.from(bigStr_2, "utf-8") : new Buffer(bigStr_2, "utf-8"); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b1: { val: bufferStr_1, type: oracledb.BUFFER, dir: oracledb.BIND_IN, maxSize: size_1 }, + b2: { val: bufferStr_2, type: oracledb.BUFFER, dir: oracledb.BIND_IN, maxSize: size_2 } + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + executeSQL(proc_7720, cb); + }, + function(cb) { + connection.execute( + sqlRun_7720, + bindVar, + option, + function(err) { + should.not.exist(err); + cb(); + }); + }, + function(cb) { + var sql = "select blob_1 from nodb_tab_blob_in where id = " + sequence; + verifyBlobValueWithBuffer(sql, bufferStr_2, specialStr_2, cb); + }, + function(cb) { + executeSQL(proc_drop_7720, cb); + } + ], done); + }); // 77.2.20 + + }); // 77.2 + + describe('77.3 Multiple BLOBs, BIND_IN', function() { + var proc = "CREATE OR REPLACE PROCEDURE nodb_blobs_in_774 (blob_id IN NUMBER, blob_1 IN BLOB, blob_2 IN BLOB)\n" + + "AS \n" + + "BEGIN \n" + + " insert into nodb_tab_blob_in (id, blob_1, blob_2) values (blob_id, blob_1, blob_2); \n" + + "END nodb_blobs_in_774; "; + var sqlRun = "BEGIN nodb_blobs_in_774 (:i, :b1, :b2); END;"; + var proc_drop = "DROP PROCEDURE nodb_blobs_in_774"; + + before(function(done) { + executeSQL(proc, done); + }); // before + + after(function(done) { + executeSQL(proc_drop, done); + }); // after + + it('77.3.1 bind two Buffer', function(done) { + var size_1 = 32768; + var size_2 = 50000; + var specialStr_1 = "77.3.1_1"; + var specialStr_2 = "77.3.1_2"; + var bigStr_1 = random.getRandomString(size_1, specialStr_1); + var bigStr_2 = random.getRandomString(size_2, specialStr_2); + var bufferStr_1 = node6plus ? Buffer.from(bigStr_1, "utf-8") : new Buffer(bigStr_1, "utf-8"); + var bufferStr_2 = node6plus ? Buffer.from(bigStr_2, "utf-8") : new Buffer(bigStr_2, "utf-8"); + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b1: { val: bufferStr_1, type: oracledb.BUFFER, dir: oracledb.BIND_IN, maxSize: size_1 }, + b2: { val: bufferStr_2, type: oracledb.BUFFER, dir: oracledb.BIND_IN, maxSize: size_2 } + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + plsqlBindIn(sqlRun, bindVar, option, cb); + }, + function(cb) { + var sql_1 = "select blob_1 from nodb_tab_blob_in where id = " + sequence; + verifyBlobValueWithBuffer(sql_1, bufferStr_1, specialStr_1, cb); + }, + function(cb) { + var sql_2 = "select blob_2 from nodb_tab_blob_in where id = " + sequence; + verifyBlobValueWithBuffer(sql_2, bufferStr_2, specialStr_2, cb); + } + ], done); + }); // 77.3.1 + + it('77.3.2 bind a JPG file and a Buffer', function(done) { + var specialStr = "77.3.2"; + var preparedCLOBID = 301; + var sequence = insertID++; + var size_1 = 32768; + var bigStr_1 = random.getRandomString(size_1, specialStr); + var bufferStr_1 = node6plus ? Buffer.from(bigStr_1, "utf-8") : new Buffer(bigStr_1, "utf-8"); + + async.series([ + function(cb) { + var sql = "INSERT INTO nodb_tab_lobs_in (id, blob) VALUES (:i, EMPTY_BLOB()) RETURNING blob INTO :lobbv"; + prepareTableWithBlob(sql, preparedCLOBID, cb); + }, + function(cb) { + connection.execute( + "select blob from nodb_tab_lobs_in where id = :id", + { id: preparedCLOBID }, + function(err, result) { + should.not.exist(err); + (result.rows.length).should.not.eql(0); + var blob = result.rows[0][0]; + + connection.execute( + sqlRun, + { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b1: { val: bufferStr_1, type: oracledb.BUFFER, dir: oracledb.BIND_IN, maxSize: size_1 }, + b2: { val: blob, type: oracledb.BLOB, dir: oracledb.BIND_IN } + }, + { autoCommit: true }, + function(err) { + should.not.exist(err); + cb(); + } + ); + } + ); + }, + function(cb) { + var sql_1 = "select blob_1 from nodb_tab_blob_in where id = " + sequence; + verifyBlobValueWithBuffer(sql_1, bufferStr_1, specialStr, cb); + }, + function(cb) { + var sql_2 = "select blob_2 from nodb_tab_blob_in where id = " + sequence; + verifyBlobValueWithFileData(sql_2, cb); + } + ], done); + }); // 77.3.2 + + it('77.3.3 bind two Buffer, one > (64K - 1)', function(done) { + var size_1 = 65538; + var size_2 = 50000; + var specialStr_1 = "77.3.3_1"; + var specialStr_2 = "77.3.3_2"; + var bigStr_1 = random.getRandomString(size_1, specialStr_1); + var bigStr_2 = random.getRandomString(size_2, specialStr_2); + var bufferStr_1 = node6plus ? Buffer.from(bigStr_1, "utf-8") : new Buffer(bigStr_1, "utf-8"); + var bufferStr_2 = node6plus ? Buffer.from(bigStr_2, "utf-8") : new Buffer(bigStr_2, "utf-8"); + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b1: { val: bufferStr_1, type: oracledb.BUFFER, dir: oracledb.BIND_IN, maxSize: size_1 }, + b2: { val: bufferStr_2, type: oracledb.BUFFER, dir: oracledb.BIND_IN, maxSize: size_2 } + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + plsqlBindIn(sqlRun, bindVar, option, cb); + }, + function(cb) { + var sql_1 = "select blob_1 from nodb_tab_blob_in where id = " + sequence; + verifyBlobValueWithBuffer(sql_1, bufferStr_1, specialStr_1, cb); + }, + function(cb) { + var sql_2 = "select blob_2 from nodb_tab_blob_in where id = " + sequence; + verifyBlobValueWithBuffer(sql_2, bufferStr_2, specialStr_2, cb); + } + ], done); + }); // 77.3.3 + + }); // 77.3 + +}); diff --git a/test/blobPlsqlBindAsBuffer_bindinout.js b/test/blobPlsqlBindAsBuffer_bindinout.js new file mode 100644 index 00000000..26e4dab2 --- /dev/null +++ b/test/blobPlsqlBindAsBuffer_bindinout.js @@ -0,0 +1,1318 @@ +/* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with the Apache + * License, Version 2.0 (the "License.") + * + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + * The node-oracledb test suite uses 'mocha', 'should' and 'async'. + * See LICENSE.md for relevant licenses. + * + * NAME + * 79. blobPlsqlBindAsBuffer_inout.js + * + * DESCRIPTION + * Testing BLOB binding inout as Buffer. + * + * NUMBERING RULE + * Test numbers follow this numbering rule: + * 1 - 20 are reserved for basic functional tests + * 21 - 50 are reserved for data type supporting tests + * 51 onwards are for other tests + * + *****************************************************************************/ +'use strict'; + +var oracledb = require('oracledb'); +var should = require('should'); +var async = require('async'); +var fs = require('fs'); +var dbConfig = require('./dbconfig.js'); +var random = require('./random.js'); +var assist = require('./dataTypeAssist.js'); + +describe('79. blobPlsqlBindAsBuffer_inout.js', function() { + this.timeout(100000); + var connection = null; + var node6plus = false; // assume node runtime version is lower than 6 + var insertID = 1; // assume id for insert into db starts from 1 + + var proc_blob_in_tab = "BEGIN \n" + + " DECLARE \n" + + " e_table_missing EXCEPTION; \n" + + " PRAGMA EXCEPTION_INIT(e_table_missing, -00942); \n" + + " BEGIN \n" + + " EXECUTE IMMEDIATE('DROP TABLE nodb_tab_blob_in PURGE'); \n" + + " EXCEPTION \n" + + " WHEN e_table_missing \n" + + " THEN NULL; \n" + + " END; \n" + + " EXECUTE IMMEDIATE (' \n" + + " CREATE TABLE nodb_tab_blob_in ( \n" + + " id NUMBER, \n" + + " blob_1 BLOB, \n" + + " blob_2 BLOB \n" + + " ) \n" + + " '); \n" + + "END; "; + + var proc_lobs_in_tab = "BEGIN \n" + + " DECLARE \n" + + " e_table_missing EXCEPTION; \n" + + " PRAGMA EXCEPTION_INIT(e_table_missing, -00942); \n" + + " BEGIN \n" + + " EXECUTE IMMEDIATE('DROP TABLE nodb_tab_lobs_in PURGE'); \n" + + " EXCEPTION \n" + + " WHEN e_table_missing \n" + + " THEN NULL; \n" + + " END; \n" + + " EXECUTE IMMEDIATE (' \n" + + " CREATE TABLE nodb_tab_lobs_in ( \n" + + " id NUMBER, \n" + + " blob BLOB \n" + + " ) \n" + + " '); \n" + + "END; "; + + before(function(done) { + async.series([ + function(cb) { + oracledb.getConnection(dbConfig, function(err, conn) { + should.not.exist(err); + connection = conn; + + // Check whether node runtime version is >= 6 or not + if ( process.versions["node"].substring (0, 1) >= "6") + node6plus = true; + cb(); + }); + }, + function(cb) { + setupAllTable(cb); + } + ], done); + + }); // before + + after(function(done) { + async.series([ + function(cb) { + dropAllTable(cb); + }, + function(cb) { + connection.release(function(err) { + should.not.exist(err); + cb(); + }); + } + ], done); + + }); // after + + var setupAllTable = function(callback) { + async.series([ + function(cb) { + connection.execute( + proc_blob_in_tab, + function(err) { + should.not.exist(err); + cb(); + }); + }, + function(cb) { + connection.execute( + proc_lobs_in_tab, + function(err) { + should.not.exist(err); + cb(); + }); + } + ], callback); + }; + + var dropAllTable = function(callback) { + async.series([ + function(cb) { + connection.execute( + "DROP TABLE nodb_tab_blob_in PURGE", + function(err) { + should.not.exist(err); + cb(); + }); + }, + function(cb) { + connection.execute( + "DROP TABLE nodb_tab_lobs_in PURGE", + function(err) { + should.not.exist(err); + cb(); + }); + } + ], callback); + }; + + var executeSQL = function(sql, callback) { + connection.execute( + sql, + function(err) { + should.not.exist(err); + return callback(); + } + ); + }; + + var jpgFileName = './test/fuzzydinosaur.jpg'; + + var prepareTableWithBlob = function(sql, id, callback) { + var bindVar = { i: id, lobbv: { type: oracledb.BLOB, dir: oracledb.BIND_OUT } }; + + connection.execute( + sql, + bindVar, + { autoCommit: false }, // a transaction needs to span the INSERT and pipe() + function(err, result) { + should.not.exist(err); + (result.rowsAffected).should.be.exactly(1); + (result.outBinds.lobbv.length).should.be.exactly(1); + + var inStream = fs.createReadStream(jpgFileName); + var lob = result.outBinds.lobbv[0]; + + lob.on('error', function(err) { + should.not.exist(err, "lob.on 'error' event"); + }); + + inStream.on('error', function(err) { + should.not.exist(err, "inStream.on 'error' event"); + }); + + lob.on('close', function() { + connection.commit( function(err) { + should.not.exist(err); + return callback(); + }); + }); + + inStream.pipe(lob); + }); + }; + + // compare the result buffer with the original inserted buffer + var compareResultBufAndOriginal = function(resultVal, originalBuffer, specialStr) { + if(originalBuffer.length > 0 ) { + var resultLength = resultVal.length; + var specStrLength = specialStr.length; + should.strictEqual(resultLength, originalBuffer.length); + should.strictEqual(resultVal.toString('utf8', 0, specStrLength), specialStr); + should.strictEqual(resultVal.toString('utf8', (resultLength - specStrLength), resultLength), specialStr); + } + should.strictEqual(assist.compare2Buffers(resultVal, originalBuffer), true); + }; + + // execute plsql bind in out procedure, and verify the plsql bind out buffer + var plsqlBindInOut = function(sqlRun, bindVar, originalBuf, specialStr, callback) { + connection.execute( + sqlRun, + bindVar, + function(err, result) { + should.not.exist(err); + var resultVal = result.outBinds.io; + if(originalBuf == 'EMPTY_BLOB' || originalBuf == null || originalBuf == undefined || originalBuf == "") { + should.strictEqual(resultVal, null); + } else { + compareResultBufAndOriginal(resultVal, originalBuf, specialStr); + } + callback(); + } + ); + }; + + describe('79.1 BLOB, PLSQL, BIND_INOUT', function() { + var blob_proc_inout = "CREATE OR REPLACE PROCEDURE nodb_blob_in_out_791 (lob_id IN NUMBER, lob_in_out IN OUT BLOB) \n" + + "AS \n" + + "BEGIN \n" + + " insert into nodb_tab_blob_in (id, blob_1) values (lob_id, lob_in_out); \n" + + " select blob_1 into lob_in_out from nodb_tab_blob_in where id = lob_id; \n" + + "END nodb_blob_in_out_791;"; + var sqlRun = "begin nodb_blob_in_out_791(:i, :io); end;"; + var proc_drop = "DROP PROCEDURE nodb_blob_in_out_791"; + var blob_proc_inout_7911 = "CREATE OR REPLACE PROCEDURE nodb_blob_in_out_7911 (lob_id IN NUMBER, lob_in_out IN OUT BLOB) \n" + + "AS \n" + + "BEGIN \n" + + " insert into nodb_tab_blob_in (id, blob_1) values (lob_id, EMPTY_BLOB()); \n" + + " select blob_1 into lob_in_out from nodb_tab_blob_in where id = lob_id; \n" + + "END nodb_blob_in_out_7911;"; + var sqlRun_7911 = "begin nodb_blob_in_out_7911(:i, :io); end;"; + var proc_drop_7911 = "DROP PROCEDURE nodb_blob_in_out_7911"; + + before(function(done) { + executeSQL(blob_proc_inout, done); + }); // before + + after(function(done) { + executeSQL(proc_drop, done); + }); // after + + it('79.1.1 works with EMPTY_BLOB', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + io: { type: oracledb.BUFFER, dir: oracledb.BIND_INOUT } + }; + + async.series([ + function(cb) { + executeSQL(blob_proc_inout_7911, cb); + }, + function(cb) { + plsqlBindInOut(sqlRun_7911, bindVar, "EMPTY_BLOB", null, cb); + }, + function(cb) { + executeSQL(proc_drop_7911, cb); + } + ], done); + }); // 79.1.1 + + it('79.1.2 works with EMPTY_BLOB and maxSize set to 1', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + io: { type: oracledb.BUFFER, dir: oracledb.BIND_INOUT, maxSize: 1 } + }; + + async.series([ + function(cb) { + executeSQL(blob_proc_inout_7911, cb); + }, + function(cb) { + plsqlBindInOut(sqlRun_7911, bindVar, "EMPTY_BLOB", null, cb); + }, + function(cb) { + executeSQL(proc_drop_7911, cb); + } + ], done); + }); // 79.1.2 + + it('79.1.3 works with EMPTY_BLOB and maxSize set to (64K - 1)', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + io: { type: oracledb.BUFFER, dir: oracledb.BIND_INOUT, maxSize: 65535 } + }; + + async.series([ + function(cb) { + executeSQL(blob_proc_inout_7911, cb); + }, + function(cb) { + plsqlBindInOut(sqlRun_7911, bindVar, "EMPTY_BLOB", null, cb); + }, + function(cb) { + executeSQL(proc_drop_7911, cb); + } + ], done); + }); // 79.1.3 + + it('79.1.4 works with null', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + io: { type: oracledb.BUFFER, dir: oracledb.BIND_INOUT } + }; + + plsqlBindInOut(sqlRun, bindVar, null, null, done); + }); // 79.1.4 + + it('79.1.5 works with null and maxSize set to 1', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + io: { type: oracledb.BUFFER, dir: oracledb.BIND_INOUT, maxSize: 1 } + }; + + plsqlBindInOut(sqlRun, bindVar, null, null, done); + }); // 79.1.5 + + it('79.1.6 works with null and maxSize set to (64K - 1)', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + io: { type: oracledb.BUFFER, dir: oracledb.BIND_INOUT, maxSize: 65535 } + }; + + plsqlBindInOut(sqlRun, bindVar, null, null, done); + }); // 79.1.6 + + it('79.1.7 works with empty buffer', function(done) { + var sequence = insertID++; + var bufferStr = node6plus ? Buffer.from('', "utf-8") : new Buffer('', "utf-8"); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + io: { val: bufferStr, type: oracledb.BUFFER, dir: oracledb.BIND_INOUT } + }; + + plsqlBindInOut(sqlRun, bindVar, bufferStr, null, done); + }); // 79.1.7 + + it('79.1.8 works with empty buffer and maxSize set to 1', function(done) { + var sequence = insertID++; + var bufferStr = node6plus ? Buffer.from('', "utf-8") : new Buffer('', "utf-8"); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + io: { val: bufferStr, type: oracledb.BUFFER, dir: oracledb.BIND_INOUT, maxSize: 1 } + }; + + plsqlBindInOut(sqlRun, bindVar, bufferStr, null, done); + }); // 79.1.8 + + it('79.1.9 works with empty buffer and maxSize set to (64K - 1)', function(done) { + var sequence = insertID++; + var bufferStr = node6plus ? Buffer.from('', "utf-8") : new Buffer('', "utf-8"); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + io: { val: bufferStr, type: oracledb.BUFFER, dir: oracledb.BIND_INOUT, maxSize: 65535 } + }; + + plsqlBindInOut(sqlRun, bindVar, bufferStr, null, done); + }); // 79.1.9 + + it('79.1.10 works with undefined', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + io: { val: undefined, type: oracledb.BUFFER, dir: oracledb.BIND_INOUT } + }; + + plsqlBindInOut(sqlRun, bindVar, undefined, null, done); + }); // 79.1.7 + + it('79.1.11 works with undefined and maxSize set to 1', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + io: { val: undefined, type: oracledb.BUFFER, dir: oracledb.BIND_INOUT, maxSize: 1 } + }; + + plsqlBindInOut(sqlRun, bindVar, undefined, null, done); + }); // 79.1.11 + + it('79.1.12 works with undefined and maxSize set to (64K - 1)', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + io: { val: undefined, type: oracledb.BUFFER, dir: oracledb.BIND_INOUT, maxSize: 65535 } + }; + + plsqlBindInOut(sqlRun, bindVar, undefined, null, done); + }); // 79.1.12 + + it('79.1.13 works with NaN', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + io: { val: NaN, type: oracledb.BUFFER, dir: oracledb.BIND_INOUT, maxSize: 1 } + }; + + connection.execute( + sqlRun, + bindVar, + function(err) { + should.exist(err); + // NJS-011: encountered bind value and type mismatch in parameter 2 + (err.message).should.startWith('NJS-011:'); + done(); + } + ); + }); // 79.1.13 + + it('79.1.14 works with 0', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + io: { val: 0, type: oracledb.BUFFER, dir: oracledb.BIND_INOUT, maxSize: 1 } + }; + + connection.execute( + sqlRun, + bindVar, + function(err) { + should.exist(err); + // NJS-011: encountered bind value and type mismatch in parameter 2 + (err.message).should.startWith('NJS-011:'); + done(); + } + ); + }); // 79.1.14 + + it('79.1.15 works with buffer size 32K', function(done) { + var sequence = insertID++; + var size = 32768; + var specialStr = "79.1.15"; + var bigStr = random.getRandomString(size, specialStr); + var bufferStr = node6plus ? Buffer.from(bigStr, "utf-8") : new Buffer(bigStr, "utf-8"); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + io: { val: bufferStr, type: oracledb.BUFFER, dir: oracledb.BIND_INOUT, maxSize: size } + }; + + plsqlBindInOut(sqlRun, bindVar, bufferStr, specialStr, done); + }); // 79.1.15 + + it('79.1.16 works with buffer size (64K - 1)', function(done) { + var sequence = insertID++; + var size = 65535; + var specialStr = "79.1.16"; + var bigStr = random.getRandomString(size, specialStr); + var bufferStr = node6plus ? Buffer.from(bigStr, "utf-8") : new Buffer(bigStr, "utf-8"); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + io: { val: bufferStr, type: oracledb.BUFFER, dir: oracledb.BIND_INOUT, maxSize: size } + }; + + plsqlBindInOut(sqlRun, bindVar, bufferStr, specialStr, done); + }); // 79.1.16 + + it('79.1.17 works with buffer size (64K + 1)', function(done) { + var sequence = insertID++; + var size = 65537; + var specialStr = "79.1.16"; + var bigStr = random.getRandomString(size, specialStr); + var bufferStr = node6plus ? Buffer.from(bigStr, "utf-8") : new Buffer(bigStr, "utf-8"); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + io: { val: bufferStr, type: oracledb.BUFFER, dir: oracledb.BIND_INOUT, maxSize: size } + }; + + plsqlBindInOut(sqlRun, bindVar, bufferStr, specialStr, done); + }); // 79.1.17 + + it('79.1.18 works with buffer size (1MB + 1)', function(done) { + var sequence = insertID++; + var size = 1048577; // 1 * 1024 * 1024 + 1 + var specialStr = "79.1.18"; + var bigStr = random.getRandomString(size, specialStr); + var bufferStr = node6plus ? Buffer.from(bigStr, "utf-8") : new Buffer(bigStr, "utf-8"); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + io: { val: bufferStr, type: oracledb.BUFFER, dir: oracledb.BIND_INOUT, maxSize: size } + }; + + plsqlBindInOut(sqlRun, bindVar, bufferStr, specialStr, done); + }); // 79.1.18 + + it('79.1.19 works with bind value and type mismatch', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + io: { val: 200, type: oracledb.BUFFER, dir: oracledb.BIND_INOUT, maxSize: 1 } + }; + + connection.execute( + sqlRun, + bindVar, + function(err) { + should.exist(err); + // NJS-011: encountered bind value and type mismatch in parameter 2 + (err.message).should.startWith('NJS-011:'); + done(); + } + ); + }); // 79.1.19 + + it('79.1.20 mixing named with positional binding', function(done) { + var sequence = insertID++; + var size = 50000; + var specialStr = "79.1.20"; + var bigStr = random.getRandomString(size, specialStr); + var bufferStr = node6plus ? Buffer.from(bigStr, "utf-8") : new Buffer(bigStr, "utf-8"); + var bindVar = [ sequence, { val: bufferStr, type: oracledb.BUFFER, dir: oracledb.BIND_INOUT, maxSize: size } ]; + + connection.execute( + sqlRun, + bindVar, + function(err, result) { + should.not.exist(err); + var resultVal = result.outBinds[0]; + compareResultBufAndOriginal(resultVal, bufferStr, specialStr); + done(); + } + ); + }); // 79.1.20 + + it('79.1.21 works with invalid BLOB', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + io: { val: {}, type: oracledb.BUFFER, dir: oracledb.BIND_INOUT, maxSize: 50000 } + }; + + connection.execute( + sqlRun, + bindVar, + function(err) { + should.exist(err); + // NJS-011: encountered bind value and type mismatch + (err.message).should.startWith('NJS-011:'); + done(); + } + ); + }); // 79.1.21 + + it('79.1.22 works with substr', function(done) { + var specialStr = "79.1.22"; + var proc_79125 = "CREATE OR REPLACE PROCEDURE nodb_blob_in_out_79125 (lob_id IN NUMBER, lob_in_out IN OUT BLOB) \n" + + "AS \n" + + "BEGIN \n" + + " insert into nodb_tab_blob_in (id, blob_1) values (lob_id, lob_in_out); \n" + + " select dbms_lob.substr(blob_1, " + specialStr.length + ", 1) into lob_in_out from nodb_tab_blob_in where id = lob_id; \n" + + "END nodb_blob_in_out_79125;"; + var sqlRun_79125 = "begin nodb_blob_in_out_79125(:i, :io); end;"; + var proc_drop_79125 = "DROP PROCEDURE nodb_blob_in_out_79125"; + var sequence = insertID++; + var size = 50000; + var bigStr = random.getRandomString(size, specialStr); + var bufferStr = node6plus ? Buffer.from(bigStr, "utf-8") : new Buffer(bigStr, "utf-8"); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + io: { val: bufferStr, type: oracledb.BUFFER, dir: oracledb.BIND_INOUT, maxSize: size } + }; + + async.series([ + function(cb) { + executeSQL(proc_79125, cb); + }, + function(cb) { + var comparedBuf = node6plus ? Buffer.from(specialStr, "utf-8") : new Buffer(specialStr, "utf-8"); + plsqlBindInOut(sqlRun_79125, bindVar, comparedBuf, specialStr, cb); + }, + function(cb) { + executeSQL(proc_drop_79125, cb); + } + ], done); + }); // 79.1.22 + + it('79.1.23 works with UPDATE', function(done) { + var proc_79125 = "CREATE OR REPLACE PROCEDURE nodb_blob_in_out_79125 (lob_id IN NUMBER, lob_in IN BLOB, lob_in_out IN OUT BLOB) \n" + + "AS \n" + + "BEGIN \n" + + " insert into nodb_tab_blob_in (id, blob_1) values (lob_id, lob_in_out); \n" + + " update nodb_tab_blob_in set blob_1 = lob_in where id = lob_id; \n" + + " select blob_1 into lob_in_out from nodb_tab_blob_in where id = lob_id; \n" + + "END nodb_blob_in_out_79125;"; + var sqlRun_79125 = "begin nodb_blob_in_out_79125(:i, :in, :io); end;"; + var proc_drop_79125 = "DROP PROCEDURE nodb_blob_in_out_79125"; + var sequence = insertID++; + var size_1 = 40000; + var specialStr_1 = "79.1.23_1"; + var bigStr_1 = random.getRandomString(size_1, specialStr_1); + var bufferStr_1 = node6plus ? Buffer.from(bigStr_1, "utf-8") : new Buffer(bigStr_1, "utf-8"); + var size_2 = 50000; + var specialStr_2 = "79.1.23_2"; + var bigStr_2 = random.getRandomString(size_2, specialStr_2); + var bufferStr_2 = node6plus ? Buffer.from(bigStr_2, "utf-8") : new Buffer(bigStr_2, "utf-8"); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + in: { val: bufferStr_1, type: oracledb.BUFFER, dir: oracledb.BIND_IN, maxSize: size_1 }, + io: { val: bufferStr_2, type: oracledb.BUFFER, dir: oracledb.BIND_INOUT, maxSize: 65535 } + }; + + async.series([ + function(cb) { + executeSQL(proc_79125, cb); + }, + function(cb) { + plsqlBindInOut(sqlRun_79125, bindVar, bufferStr_1, specialStr_1, cb); + }, + function(cb) { + executeSQL(proc_drop_79125, cb); + } + ], done); + }); // 79.1.23 + + it.skip('79.1.24 named binding: maxSize smaller than buffer size ( < 32K )', function(done) { + var sequence = insertID++; + var size = 5000; + var specialStr = "79.1.24"; + var bigStr = random.getRandomString(size, specialStr); + var bufferStr = node6plus ? Buffer.from(bigStr, "utf-8") : new Buffer(bigStr, "utf-8"); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + io: { val: bufferStr, type: oracledb.BUFFER, dir: oracledb.BIND_INOUT, maxSize: size - 1 } + }; + + connection.execute( + sqlRun, + bindVar, + function(err) { + should.exist(err); + // ORA-01460: unimplemented or unreasonable conversion requested + (err.message).should.startWith('ORA-01460:'); + done(); + } + ); + }); // 79.1.24 + + it('79.1.25 named binding: maxSize smaller than buffer size ( > 32K )', function(done) { + var sequence = insertID++; + var size = 50000; + var specialStr = "79.1.25"; + var bigStr = random.getRandomString(size, specialStr); + var bufferStr = node6plus ? Buffer.from(bigStr, "utf-8") : new Buffer(bigStr, "utf-8"); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + io: { val: bufferStr, type: oracledb.BUFFER, dir: oracledb.BIND_INOUT, maxSize: size - 1 } + }; + + connection.execute( + sqlRun, + bindVar, + function(err) { + should.exist(err); + // NJS-016: buffer is too small for OUT binds + (err.message).should.startWith('NJS-016:'); + done(); + } + ); + }); // 79.1.25 + + it('79.1.26 named binding: maxSize smaller than buffer size ( > 64K )', function(done) { + var sequence = insertID++; + var size = 65539; + var specialStr = "79.1.26"; + var bigStr = random.getRandomString(size, specialStr); + var bufferStr = node6plus ? Buffer.from(bigStr, "utf-8") : new Buffer(bigStr, "utf-8"); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + io: { val: bufferStr, type: oracledb.BUFFER, dir: oracledb.BIND_INOUT, maxSize: size - 1 } + }; + + connection.execute( + sqlRun, + bindVar, + function(err) { + should.exist(err); + // NJS-016: buffer is too small for OUT binds + (err.message).should.startWith('NJS-016:'); + done(); + } + ); + }); // 79.1.26 + + it.skip('79.1.27 positional binding: maxSize smaller than buffer size ( < 32K )', function(done) { + var sequence = insertID++; + var size = 500; + var specialStr = "79.1.27"; + var bigStr = random.getRandomString(size, specialStr); + var bufferStr = node6plus ? Buffer.from(bigStr, "utf-8") : new Buffer(bigStr, "utf-8"); + var bindVar = [ sequence, { val: bufferStr, type: oracledb.BUFFER, dir: oracledb.BIND_INOUT, maxSize: size - 1 } ]; + + connection.execute( + "begin nodb_blob_in_out_791(:1, :2); end;", + bindVar, + function(err) { + should.exist(err); + // ORA-01460: unimplemented or unreasonable conversion requested + (err.message).should.startWith('ORA-01460:'); + done(); + } + ); + }); // 79.1.27 + + it('79.1.28 positional binding: maxSize smaller than buffer size ( > 32K )', function(done) { + var sequence = insertID++; + var size = 50000; + var specialStr = "79.1.28"; + var bigStr = random.getRandomString(size, specialStr); + var bufferStr = node6plus ? Buffer.from(bigStr, "utf-8") : new Buffer(bigStr, "utf-8"); + var bindVar = [ sequence, { val: bufferStr, type: oracledb.BUFFER, dir: oracledb.BIND_INOUT, maxSize: size - 1 } ]; + + connection.execute( + "begin nodb_blob_in_out_791(:1, :2); end;", + bindVar, + function(err) { + should.exist(err); + // NJS-016: buffer is too small for OUT binds + (err.message).should.startWith('NJS-016:'); + done(); + } + ); + }); // 79.1.28 + + it('79.1.29 positional binding: maxSize smaller than buffer size ( > 64K )', function(done) { + var sequence = insertID++; + var size = 65539; + var specialStr = "79.1.29"; + var bigStr = random.getRandomString(size, specialStr); + var bufferStr = node6plus ? Buffer.from(bigStr, "utf-8") : new Buffer(bigStr, "utf-8"); + var bindVar = [ sequence, { val: bufferStr, type: oracledb.BUFFER, dir: oracledb.BIND_INOUT, maxSize: size - 1 } ]; + + connection.execute( + "begin nodb_blob_in_out_791(:1, :2); end;", + bindVar, + function(err) { + should.exist(err); + // NJS-016: buffer is too small for OUT binds + (err.message).should.startWith('NJS-016:'); + done(); + } + ); + }); // 79.1.29 + + it('79.1.30 bind without maxSize', function(done) { + var sequence = insertID++; + var size = 50000; + var specialStr = "79.1.30"; + var bigStr = random.getRandomString(size, specialStr); + var bufferStr = node6plus ? Buffer.from(bigStr, "utf-8") : new Buffer(bigStr, "utf-8"); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + io: { val: bufferStr, type: oracledb.BUFFER, dir: oracledb.BIND_INOUT } + }; + + connection.execute( + sqlRun, + bindVar, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // 79.1.30 + + }); // 79.1 + + describe('79.2 BLOB, PLSQL, BIND_INOUT to RAW', function() { + var blob_proc_inout = "CREATE OR REPLACE PROCEDURE nodb_blob_in_out_792 (lob_id IN NUMBER, lob_in_out IN OUT RAW) \n" + + "AS \n" + + "BEGIN \n" + + " insert into nodb_tab_blob_in (id, blob_1) values (lob_id, lob_in_out); \n" + + " select blob_1 into lob_in_out from nodb_tab_blob_in where id = lob_id; \n" + + "END nodb_blob_in_out_792;"; + var sqlRun = "begin nodb_blob_in_out_792(:i, :io); end;"; + var proc_drop = "DROP PROCEDURE nodb_blob_in_out_792"; + var blob_proc_inout_7921 = "CREATE OR REPLACE PROCEDURE nodb_blob_in_out_7921 (lob_id IN NUMBER, lob_in_out IN OUT RAW) \n" + + "AS \n" + + "BEGIN \n" + + " insert into nodb_tab_blob_in (id, blob_1) values (lob_id, EMPTY_BLOB()); \n" + + " select blob_1 into lob_in_out from nodb_tab_blob_in where id = lob_id; \n" + + "END nodb_blob_in_out_7921;"; + var sqlRun_7921 = "begin nodb_blob_in_out_7921(:i, :io); end;"; + var proc_drop_7921 = "DROP PROCEDURE nodb_blob_in_out_7921"; + + before(function(done) { + executeSQL(blob_proc_inout, done); + }); // before + + after(function(done) { + executeSQL(proc_drop, done); + }); // after + + it('79.2.1 works with EMPTY_BLOB', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + io: { type: oracledb.BUFFER, dir: oracledb.BIND_INOUT } + }; + + async.series([ + function(cb) { + executeSQL(blob_proc_inout_7921, cb); + }, + function(cb) { + plsqlBindInOut(sqlRun_7921, bindVar, "EMPTY_BLOB", null, cb); + }, + function(cb) { + executeSQL(proc_drop_7921, cb); + } + ], done); + }); // 79.2.1 + + it('79.2.2 works with EMPTY_BLOB and maxSize set to 1', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + io: { type: oracledb.BUFFER, dir: oracledb.BIND_INOUT, maxSize: 1 } + }; + + async.series([ + function(cb) { + executeSQL(blob_proc_inout_7921, cb); + }, + function(cb) { + plsqlBindInOut(sqlRun_7921, bindVar, "EMPTY_BLOB", null, cb); + }, + function(cb) { + executeSQL(proc_drop_7921, cb); + } + ], done); + }); // 79.2.2 + + it('79.2.3 works with EMPTY_BLOB and maxSize set to (64K - 1)', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + io: { type: oracledb.BUFFER, dir: oracledb.BIND_INOUT, maxSize: 65535 } + }; + + async.series([ + function(cb) { + executeSQL(blob_proc_inout_7921, cb); + }, + function(cb) { + plsqlBindInOut(sqlRun_7921, bindVar, "EMPTY_BLOB", null, cb); + }, + function(cb) { + executeSQL(proc_drop_7921, cb); + } + ], done); + }); // 79.2.3 + + it('79.2.4 works with null', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + io: { type: oracledb.BUFFER, dir: oracledb.BIND_INOUT } + }; + + plsqlBindInOut(sqlRun, bindVar, null, null, done); + }); // 79.2.4 + + it('79.2.5 works with null and maxSize set to 1', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + io: { type: oracledb.BUFFER, dir: oracledb.BIND_INOUT, maxSize: 1 } + }; + + plsqlBindInOut(sqlRun, bindVar, null, null, done); + }); // 79.2.5 + + it('79.2.6 works with null and maxSize set to (64K - 1)', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + io: { type: oracledb.BUFFER, dir: oracledb.BIND_INOUT, maxSize: 65535 } + }; + + plsqlBindInOut(sqlRun, bindVar, null, null, done); + }); // 79.2.6 + + it('79.2.7 works with empty buffer', function(done) { + var sequence = insertID++; + var bufferStr = node6plus ? Buffer.from('', "utf-8") : new Buffer('', "utf-8"); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + io: { val: bufferStr, type: oracledb.BUFFER, dir: oracledb.BIND_INOUT } + }; + + plsqlBindInOut(sqlRun, bindVar, bufferStr, null, done); + }); // 79.2.7 + + it('79.2.8 works with empty buffer and maxSize set to 1', function(done) { + var sequence = insertID++; + var bufferStr = node6plus ? Buffer.from('', "utf-8") : new Buffer('', "utf-8"); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + io: { val: bufferStr, type: oracledb.BUFFER, dir: oracledb.BIND_INOUT, maxSize: 1 } + }; + + plsqlBindInOut(sqlRun, bindVar, bufferStr, null, done); + }); // 79.2.8 + + it('79.2.9 works with empty buffer and maxSize set to (64K - 1)', function(done) { + var sequence = insertID++; + var bufferStr = node6plus ? Buffer.from('', "utf-8") : new Buffer('', "utf-8"); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + io: { val: bufferStr, type: oracledb.BUFFER, dir: oracledb.BIND_INOUT, maxSize: 65535 } + }; + + plsqlBindInOut(sqlRun, bindVar, bufferStr, null, done); + }); // 79.2.9 + + it('79.2.10 works with undefined', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + io: { val: undefined, type: oracledb.BUFFER, dir: oracledb.BIND_INOUT } + }; + + plsqlBindInOut(sqlRun, bindVar, undefined, null, done); + }); // 79.2.7 + + it('79.2.11 works with undefined and maxSize set to 1', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + io: { val: undefined, type: oracledb.BUFFER, dir: oracledb.BIND_INOUT, maxSize: 1 } + }; + + plsqlBindInOut(sqlRun, bindVar, undefined, null, done); + }); // 79.2.11 + + it('79.2.12 works with undefined and maxSize set to (64K - 1)', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + io: { val: undefined, type: oracledb.BUFFER, dir: oracledb.BIND_INOUT, maxSize: 65535 } + }; + + plsqlBindInOut(sqlRun, bindVar, undefined, null, done); + }); // 79.2.12 + + it('79.2.13 works with NaN', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + io: { val: NaN, type: oracledb.BUFFER, dir: oracledb.BIND_INOUT, maxSize: 1 } + }; + + connection.execute( + sqlRun, + bindVar, + function(err) { + should.exist(err); + // NJS-011: encountered bind value and type mismatch in parameter 2 + (err.message).should.startWith('NJS-011:'); + done(); + } + ); + }); // 79.2.13 + + it('79.2.14 works with 0', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + io: { val: 0, type: oracledb.BUFFER, dir: oracledb.BIND_INOUT, maxSize: 1 } + }; + + connection.execute( + sqlRun, + bindVar, + function(err) { + should.exist(err); + // NJS-011: encountered bind value and type mismatch in parameter 2 + (err.message).should.startWith('NJS-011:'); + done(); + } + ); + }); // 79.2.14 + + it('79.2.15 works with buffer size (32K - 1)', function(done) { + var sequence = insertID++; + var size = 32767; + var specialStr = "79.2.15"; + var bigStr = random.getRandomString(size, specialStr); + var bufferStr = node6plus ? Buffer.from(bigStr, "utf-8") : new Buffer(bigStr, "utf-8"); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + io: { val: bufferStr, type: oracledb.BUFFER, dir: oracledb.BIND_INOUT, maxSize: size } + }; + + plsqlBindInOut(sqlRun, bindVar, bufferStr, specialStr, done); + }); // 79.2.15 + + it('79.2.16 works with buffer size 32K', function(done) { + var sequence = insertID++; + var size = 32768; + var specialStr = "79.2.16"; + var bigStr = random.getRandomString(size, specialStr); + var bufferStr = node6plus ? Buffer.from(bigStr, "utf-8") : new Buffer(bigStr, "utf-8"); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + io: { val: bufferStr, type: oracledb.BUFFER, dir: oracledb.BIND_INOUT, maxSize: size } + }; + + connection.execute( + sqlRun, + bindVar, + function(err) { + should.exist(err); + // ORA-06502: PL/SQL: numeric or value error + (err.message).should.startWith('ORA-06502:'); + done(); + } + ); + }); // 79.2.16 + + it('79.2.17 works with buffer size > maxSize', function(done) { + var sequence = insertID++; + var size = 300; + var specialStr = "79.2.17"; + var bigStr = random.getRandomString(size, specialStr); + var bufferStr = node6plus ? Buffer.from(bigStr, "utf-8") : new Buffer(bigStr, "utf-8"); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + io: { val: bufferStr, type: oracledb.BUFFER, dir: oracledb.BIND_INOUT, maxSize: size - 1 } + }; + + connection.execute( + sqlRun, + bindVar, + function(err) { + should.exist(err); + // DPI-1019: buffer size is too small + (err.message).should.startWith('DPI-1019:'); + done(); + } + ); + }); // 79.2.17 + + it('79.2.18 works with invalid BLOB', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + io: { val: {}, type: oracledb.BUFFER, dir: oracledb.BIND_INOUT, maxSize: 50000 } + }; + + connection.execute( + sqlRun, + bindVar, + function(err) { + should.exist(err); + // NJS-011: encountered bind value and type mismatch + (err.message).should.startWith('NJS-011:'); + done(); + } + ); + }); // 79.2.18 + + it('79.2.19 works with substr', function(done) { + var specialStr = "79.2.19"; + var proc_79219 = "CREATE OR REPLACE PROCEDURE nodb_blob_in_out_79219 (lob_id IN NUMBER, lob_in_out IN OUT RAW) \n" + + "AS \n" + + "BEGIN \n" + + " insert into nodb_tab_blob_in (id, blob_1) values (lob_id, lob_in_out); \n" + + " select dbms_lob.substr(blob_1, " + specialStr.length + ", 1) into lob_in_out from nodb_tab_blob_in where id = lob_id; \n" + + "END nodb_blob_in_out_79219;"; + var sqlRun_79219 = "begin nodb_blob_in_out_79219(:i, :io); end;"; + var proc_drop_79219 = "DROP PROCEDURE nodb_blob_in_out_79219"; + var sequence = insertID++; + var size = 3000; + var bigStr = random.getRandomString(size, specialStr); + var bufferStr = node6plus ? Buffer.from(bigStr, "utf-8") : new Buffer(bigStr, "utf-8"); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + io: { val: bufferStr, type: oracledb.BUFFER, dir: oracledb.BIND_INOUT, maxSize: size } + }; + + async.series([ + function(cb) { + executeSQL(proc_79219, cb); + }, + function(cb) { + var comparedBuf = node6plus ? Buffer.from(specialStr, "utf-8") : new Buffer(specialStr, "utf-8"); + plsqlBindInOut(sqlRun_79219, bindVar, comparedBuf, specialStr, cb); + }, + function(cb) { + executeSQL(proc_drop_79219, cb); + } + ], done); + }); // 79.2.19 + + it('79.2.20 works with UPDATE', function(done) { + var proc_79220 = "CREATE OR REPLACE PROCEDURE nodb_blob_in_out_79220 (lob_id IN NUMBER, lob_in IN RAW, lob_in_out IN OUT RAW) \n" + + "AS \n" + + "BEGIN \n" + + " insert into nodb_tab_blob_in (id, blob_1) values (lob_id, lob_in_out); \n" + + " update nodb_tab_blob_in set blob_1 = lob_in where id = lob_id; \n" + + " select blob_1 into lob_in_out from nodb_tab_blob_in where id = lob_id; \n" + + "END nodb_blob_in_out_79220;"; + var sqlRun_79220 = "begin nodb_blob_in_out_79220(:i, :in, :io); end;"; + var proc_drop_79220 = "DROP PROCEDURE nodb_blob_in_out_79220"; + var sequence = insertID++; + var size_1 = 2000; + var specialStr_1 = "79.2.10_1"; + var bigStr_1 = random.getRandomString(size_1, specialStr_1); + var bufferStr_1 = node6plus ? Buffer.from(bigStr_1, "utf-8") : new Buffer(bigStr_1, "utf-8"); + var size_2 = 500; + var specialStr_2 = "79.2.10_2"; + var bigStr_2 = random.getRandomString(size_2, specialStr_2); + var bufferStr_2 = node6plus ? Buffer.from(bigStr_2, "utf-8") : new Buffer(bigStr_2, "utf-8"); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + in: { val: bufferStr_1, type: oracledb.BUFFER, dir: oracledb.BIND_IN, maxSize: size_1 }, + io: { val: bufferStr_2, type: oracledb.BUFFER, dir: oracledb.BIND_INOUT, maxSize: 65535 } + }; + + async.series([ + function(cb) { + executeSQL(proc_79220, cb); + }, + function(cb) { + plsqlBindInOut(sqlRun_79220, bindVar, bufferStr_1, specialStr_1, cb); + }, + function(cb) { + executeSQL(proc_drop_79220, cb); + } + ], done); + }); // 79.2.20 + + it('79.2.21 works without maxSize', function(done) { + var sequence = insertID++; + var size = 500; + var specialStr = "79.2.21"; + var bigStr = random.getRandomString(size, specialStr); + var bufferStr = node6plus ? Buffer.from(bigStr, "utf-8") : new Buffer(bigStr, "utf-8"); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + io: { val: bufferStr, type: oracledb.BUFFER, dir: oracledb.BIND_INOUT } + }; + + connection.execute( + sqlRun, + bindVar, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // 79.2.21 + + }); // 79.2 + + describe('79.3 Multiple BLOBs, BIND_INOUT', function() { + var lobs_proc_inout = "CREATE OR REPLACE PROCEDURE nodb_lobs_in_out_793 (lob_id IN NUMBER, blob_1 IN OUT BLOB, blob_2 IN OUT BLOB) \n" + + "AS \n" + + "BEGIN \n" + + " insert into nodb_tab_blob_in (id, blob_1, blob_2) values (lob_id, blob_1, blob_2); \n" + + " select blob_1, blob_2 into blob_1, blob_2 from nodb_tab_blob_in where id = lob_id; \n" + + "END nodb_lobs_in_out_793;"; + var sqlRun = "begin nodb_lobs_in_out_793(:i, :lob_1, :lob_2); end;"; + var proc_drop = "DROP PROCEDURE nodb_lobs_in_out_793"; + + before(function(done) { + executeSQL(lobs_proc_inout, done); + }); // before + + after(function(done) { + executeSQL(proc_drop, done); + }); // after + + // execute plsql bind in out procedure, and verify the plsql bind out buffer + var plsqlBindInOut = function(sqlRun, bindVar, originalBuf1, specialStr1, originalBuf2, specialStr2, callback) { + connection.execute( + sqlRun, + bindVar, + function(err, result) { + should.not.exist(err); + var resultVal = result.outBinds.lob_1; + compareResultBufAndOriginal(resultVal, originalBuf1, specialStr1); + resultVal = result.outBinds.lob_2; + compareResultBufAndOriginal(resultVal, originalBuf2, specialStr2); + callback(); + } + ); + }; + + it('79.3.1 bind a JPG and a 32K buffer', function(done) { + var preparedCLOBID = 500; + var sequence = insertID++; + var size_1 = 32768; + var specialStr = "79.3.1"; + var bigStr_1 = random.getRandomString(size_1, specialStr); + var bufferStr_1 = node6plus ? Buffer.from(bigStr_1, "utf-8") : new Buffer(bigStr_1, "utf-8"); + + async.series([ + function(cb) { + var sql = "INSERT INTO nodb_tab_lobs_in (id, blob) VALUES (:i, EMPTY_BLOB()) RETURNING blob INTO :lobbv"; + prepareTableWithBlob(sql, preparedCLOBID, cb); + }, + function(cb) { + connection.execute( + "select blob from nodb_tab_lobs_in where id = :id", + { id: preparedCLOBID }, + function(err, result) { + should.not.exist(err); + (result.rows.length).should.not.eql(0); + var blob = result.rows[0][0]; + connection.execute( + sqlRun, + { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + lob_1: { val: bufferStr_1, type: oracledb.BUFFER, dir: oracledb.BIND_INOUT, maxSize: size_1 }, + lob_2: { val: blob, type: oracledb.BLOB, dir: oracledb.BIND_INOUT } + }, + { autoCommit: true }, + function(err, result) { + should.not.exist(err); + var resultVal = result.outBinds.lob_1; + compareResultBufAndOriginal(resultVal, bufferStr_1, specialStr); + var lob = result.outBinds.lob_2; + var blobData = node6plus ? Buffer.alloc(0) : new Buffer(0); + var totalLength = 0; + + lob.on('data', function(chunk) { + totalLength = totalLength + chunk.length; + blobData = Buffer.concat([blobData, chunk], totalLength); + }); + + lob.on('error', function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + lob.on('end', function() { + fs.readFile( jpgFileName, function(err, originalData) { + should.not.exist(err); + should.strictEqual(totalLength, originalData.length); + originalData.should.eql(blobData); + cb(); + }); + }); + }); + }); + } + ], done); + }); // 79.3.1 + + it('79.3.2 bind two buffers', function(done) { + var sequence = insertID++; + var size_1 = 30000; + var specialStr_1 = "79.3.2_1"; + var bigStr_1 = random.getRandomString(size_1, specialStr_1); + var bufferStr_1 = node6plus ? Buffer.from(bigStr_1, "utf-8") : new Buffer(bigStr_1, "utf-8"); + var size_2 = 40000; + var specialStr_2 = "79.3.2_2"; + var bigStr_2 = random.getRandomString(size_2, specialStr_2); + var bufferStr_2 = node6plus ? Buffer.from(bigStr_2, "utf-8") : new Buffer(bigStr_2, "utf-8"); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + lob_1: { val: bufferStr_1, type: oracledb.BUFFER, dir: oracledb.BIND_INOUT, maxSize: size_1 }, + lob_2: { val: bufferStr_2, type: oracledb.BUFFER, dir: oracledb.BIND_INOUT, maxSize: size_2 } + }; + + plsqlBindInOut(sqlRun, bindVar, bufferStr_1, specialStr_1, bufferStr_2, specialStr_2, done); + }); // 79.3.2 + + it('79.3.3 bind two buffers, one > (64K - 1)', function(done) { + var sequence = insertID++; + var size_1 = 30000; + var specialStr_1 = "79.3.2_1"; + var bigStr_1 = random.getRandomString(size_1, specialStr_1); + var bufferStr_1 = node6plus ? Buffer.from(bigStr_1, "utf-8") : new Buffer(bigStr_1, "utf-8"); + var size_2 = 65537; + var specialStr_2 = "79.3.2_2"; + var bigStr_2 = random.getRandomString(size_2, specialStr_2); + var bufferStr_2 = node6plus ? Buffer.from(bigStr_2, "utf-8") : new Buffer(bigStr_2, "utf-8"); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + lob_1: { val: bufferStr_1, type: oracledb.BUFFER, dir: oracledb.BIND_INOUT, maxSize: size_1 }, + lob_2: { val: bufferStr_2, type: oracledb.BUFFER, dir: oracledb.BIND_INOUT, maxSize: size_2 } + }; + + plsqlBindInOut(sqlRun, bindVar, bufferStr_1, specialStr_1, bufferStr_2, specialStr_2, done); + }); // 79.3.3 + + }); // 79.3 + +}); diff --git a/test/blobPlsqlBindAsBuffer_bindout.js b/test/blobPlsqlBindAsBuffer_bindout.js new file mode 100644 index 00000000..946ab0aa --- /dev/null +++ b/test/blobPlsqlBindAsBuffer_bindout.js @@ -0,0 +1,1610 @@ +/* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with the Apache + * License, Version 2.0 (the "License.") + * + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + * The node-oracledb test suite uses 'mocha', 'should' and 'async'. + * See LICENSE.md for relevant licenses. + * + * NAME + * 78. blobPlsqlBindAsBuffer_bindout.js + * + * DESCRIPTION + * Testing BLOB binding out as Buffer. + * + * NUMBERING RULE + * Test numbers follow this numbering rule: + * 1 - 20 are reserved for basic functional tests + * 21 - 50 are reserved for data type supporting tests + * 51 onwards are for other tests + * + *****************************************************************************/ +'use strict'; + +var oracledb = require('oracledb'); +var should = require('should'); +var async = require('async'); +var fs = require('fs'); +var file = require('./file.js'); +var dbConfig = require('./dbconfig.js'); +var random = require('./random.js'); +var assist = require('./dataTypeAssist.js'); + +describe('78. blobPlsqlBindAsBuffer_bindout.js', function() { + this.timeout(100000); + var connection = null; + var node6plus = false; // assume node runtime version is lower than 6 + var insertID = 1; // assume id for insert into db starts from 1 + + var proc_blob_in_tab = "BEGIN \n" + + " DECLARE \n" + + " e_table_missing EXCEPTION; \n" + + " PRAGMA EXCEPTION_INIT(e_table_missing, -00942); \n" + + " BEGIN \n" + + " EXECUTE IMMEDIATE('DROP TABLE nodb_tab_blob_in PURGE'); \n" + + " EXCEPTION \n" + + " WHEN e_table_missing \n" + + " THEN NULL; \n" + + " END; \n" + + " EXECUTE IMMEDIATE (' \n" + + " CREATE TABLE nodb_tab_blob_in ( \n" + + " id NUMBER, \n" + + " blob_1 BLOB, \n" + + " blob_2 BLOB \n" + + " ) \n" + + " '); \n" + + "END; "; + + var proc_lobs_in_tab = "BEGIN \n" + + " DECLARE \n" + + " e_table_missing EXCEPTION; \n" + + " PRAGMA EXCEPTION_INIT(e_table_missing, -00942); \n" + + " BEGIN \n" + + " EXECUTE IMMEDIATE('DROP TABLE nodb_tab_lobs_in PURGE'); \n" + + " EXCEPTION \n" + + " WHEN e_table_missing \n" + + " THEN NULL; \n" + + " END; \n" + + " EXECUTE IMMEDIATE (' \n" + + " CREATE TABLE nodb_tab_lobs_in ( \n" + + " id NUMBER, \n" + + " blob BLOB \n" + + " ) \n" + + " '); \n" + + "END; "; + + before(function(done) { + async.series([ + function(cb) { + oracledb.getConnection(dbConfig, function(err, conn) { + should.not.exist(err); + connection = conn; + + // Check whether node runtime version is >= 6 or not + if ( process.versions["node"].substring (0, 1) >= "6") + node6plus = true; + cb(); + }); + }, + function(cb) { + setupAllTable(cb); + } + ], done); + + }); // before + + after(function(done) { + async.series([ + function(cb) { + dropAllTable(cb); + }, + function(cb) { + connection.release(function(err) { + should.not.exist(err); + cb(); + }); + } + ], done); + + }); // after + + var setupAllTable = function(callback) { + async.series([ + function(cb) { + connection.execute( + proc_blob_in_tab, + function(err) { + should.not.exist(err); + cb(); + }); + }, + function(cb) { + connection.execute( + proc_lobs_in_tab, + function(err) { + should.not.exist(err); + cb(); + }); + } + ], callback); + }; + + var dropAllTable = function(callback) { + async.series([ + function(cb) { + connection.execute( + "DROP TABLE nodb_tab_blob_in PURGE", + function(err) { + should.not.exist(err); + cb(); + }); + }, + function(cb) { + connection.execute( + "DROP TABLE nodb_tab_lobs_in PURGE", + function(err) { + should.not.exist(err); + cb(); + }); + } + ], callback); + }; + + var executeSQL = function(sql, callback) { + connection.execute( + sql, + function(err) { + should.not.exist(err); + return callback(); + } + ); + }; + + var insertBlobWithbuffer = function(id, insertBuffer, callback) { + var sql = "INSERT INTO nodb_tab_blob_in (id, blob_1) VALUES (:i, :b)"; + var bindVar = { + i: { val: id, dir: oracledb.BIND_IN, type: oracledb.NUMBER }, + b: { val: insertBuffer, dir: oracledb.BIND_IN, type: oracledb.BUFFER } + }; + + if (insertBuffer == 'EMPTY_LOB') { + sql = "INSERT INTO nodb_tab_blob_in (id, blob_1) VALUES (:i, EMPTY_BLOB())"; + bindVar = { + i: { val: id, dir: oracledb.BIND_IN, type: oracledb.NUMBER } + }; + } + connection.execute( + sql, + bindVar, + function(err, result) { + should.not.exist(err); + should.strictEqual(result.rowsAffected, 1); + callback(); + }); + }; + + var inFileStreamed = './test/blobTmpFile.txt'; + + var jpgFileName = './test/fuzzydinosaur.jpg'; + + var prepareTableWithBlob = function(sql, id, callback) { + var bindVar = { i: id, lobbv: { type: oracledb.BLOB, dir: oracledb.BIND_OUT } }; + + connection.execute( + sql, + bindVar, + { autoCommit: false }, // a transaction needs to span the INSERT and pipe() + function(err, result) { + should.not.exist(err); + (result.rowsAffected).should.be.exactly(1); + (result.outBinds.lobbv.length).should.be.exactly(1); + + var inStream = fs.createReadStream(jpgFileName); + var lob = result.outBinds.lobbv[0]; + + lob.on('error', function(err) { + should.not.exist(err, "lob.on 'error' event"); + }); + + inStream.on('error', function(err) { + should.not.exist(err, "inStream.on 'error' event"); + }); + + lob.on('close', function() { + connection.commit( function(err) { + should.not.exist(err); + return callback(); + }); + }); + + inStream.pipe(lob); + }); + }; + + var verifyBlobValueWithFileData = function(selectSql, callback) { + connection.execute( + selectSql, + function(err, result) { + should.not.exist(err); + var lob = result.rows[0][0]; + should.exist(lob); + + var blobData = 0; + var totalLength = 0; + blobData = node6plus ? Buffer.alloc(0) : new Buffer(0); + + lob.on('data', function(chunk) { + totalLength = totalLength + chunk.length; + blobData = Buffer.concat([blobData, chunk], totalLength); + }); + + lob.on('error', function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + lob.on('end', function() { + fs.readFile( jpgFileName, function(err, originalData) { + should.not.exist(err); + should.strictEqual(totalLength, originalData.length); + originalData.should.eql(blobData); + return callback(); + }); + }); + }); + }; + + var verifyBlobValueWithBuffer = function(selectSql, oraginalBuffer, specialStr, callback) { + connection.execute( + selectSql, + function(err, result) { + should.not.exist(err); + var lob = result.rows[0][0]; + if (oraginalBuffer == null | oraginalBuffer == '' || oraginalBuffer == undefined) { + should.not.exist(lob); + return callback(); + } else { + should.exist(lob); + var blobData = node6plus ? Buffer.alloc(0) : new Buffer(0); + var totalLength = 0; + + lob.on('data', function(chunk) { + totalLength = totalLength + chunk.length; + blobData = Buffer.concat([blobData, chunk], totalLength); + }); + + lob.on('error', function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + lob.on('end', function() { + should.strictEqual(totalLength, oraginalBuffer.length); + var specStrLength = specialStr.length; + should.strictEqual(blobData.toString('utf8', 0, specStrLength), specialStr); + should.strictEqual(blobData.toString('utf8', (totalLength - specStrLength), totalLength), specialStr); + return callback(); + }); + } + } + ); + }; + + // compare the result buffer with the original inserted buffer + var compareResultBufAndOriginal = function(resultVal, originalBuffer, specialStr) { + if(originalBuffer.length > 0 ) { + var resultLength = resultVal.length; + var specStrLength = specialStr.length; + should.strictEqual(resultLength, originalBuffer.length); + should.strictEqual(resultVal.toString('utf8', 0, specStrLength), specialStr); + should.strictEqual(resultVal.toString('utf8', (resultLength - specStrLength), resultLength), specialStr); + } + should.strictEqual(assist.compare2Buffers(resultVal, originalBuffer), true); + }; + + var verifyBindOutResult = function(sqlRun, bindVar, originalBuf, specialStr, callback) { + connection.execute( + sqlRun, + bindVar, + function(err, result) { + if(originalBuf == "EMPTY_LOB" || originalBuf == undefined || originalBuf == null || originalBuf == "") { + should.not.exist(err); + should.strictEqual(result.outBinds.b, null); + callback(); + } else { + should.not.exist(err); + var resultVal = result.outBinds.b; + compareResultBufAndOriginal(resultVal, originalBuf, specialStr); + callback(); + } + } + ); + }; + + describe('78.1 BLOB, PLSQL, BIND_OUT', function() { + var proc = "CREATE OR REPLACE PROCEDURE nodb_blobs_out_782 (blob_id IN NUMBER, blob_out OUT BLOB) \n" + + "AS \n" + + "BEGIN \n" + + " select blob_1 into blob_out from nodb_tab_blob_in where id = blob_id; \n" + + "END nodb_blobs_out_782; "; + var sqlRun = "BEGIN nodb_blobs_out_782 (:i, :b); END;"; + var proc_drop = "DROP PROCEDURE nodb_blobs_out_782"; + + before(function(done) { + executeSQL(proc, done); + }); // before + + after(function(done) { + executeSQL(proc_drop, done); + }); // after + + it('78.1.1 works with EMPTY_BLOB', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { type: oracledb.BUFFER, dir: oracledb.BIND_OUT } + }; + + async.series([ + function(cb) { + insertBlobWithbuffer(sequence, "EMPTY_LOB", cb); + }, + function(cb) { + verifyBindOutResult(sqlRun, bindVar, "EMPTY_LOB", null, cb); + } + ], done); + }); // 78.1.1 + + it('78.1.2 works with EMPTY_BLOB and bind out maxSize set to 1', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { type: oracledb.BUFFER, dir: oracledb.BIND_OUT, maxSize: 1 } + }; + + async.series([ + function(cb) { + insertBlobWithbuffer(sequence, "EMPTY_LOB", cb); + }, + function(cb) { + verifyBindOutResult(sqlRun, bindVar, "EMPTY_LOB", null, cb); + } + ], done); + }); // 78.1.2 + + it('78.1.3 works with EMPTY_BLOB and bind out maxSize set to (64K - 1)', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { type: oracledb.BUFFER, dir: oracledb.BIND_OUT, maxSize: 65535 } + }; + + async.series([ + function(cb) { + insertBlobWithbuffer(sequence, "EMPTY_LOB", cb); + }, + function(cb) { + verifyBindOutResult(sqlRun, bindVar, "EMPTY_LOB", null, cb); + } + ], done); + }); // 78.1.3 + + it('78.1.4 works with null', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { type: oracledb.BUFFER, dir: oracledb.BIND_OUT } + }; + + async.series([ + function(cb) { + insertBlobWithbuffer(sequence, null, cb); + }, + function(cb) { + verifyBindOutResult(sqlRun, bindVar, null, null, cb); + } + ], done); + }); // 78.1.4 + + it('78.1.5 works with null and bind out maxSize set to 1', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { type: oracledb.BUFFER, dir: oracledb.BIND_OUT, maxSize: 1 } + }; + + async.series([ + function(cb) { + insertBlobWithbuffer(sequence, null, cb); + }, + function(cb) { + verifyBindOutResult(sqlRun, bindVar, null, null, cb); + } + ], done); + }); // 78.1.5 + + it('78.1.6 works with null and bind out maxSize set to (64K - 1)', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { type: oracledb.BUFFER, dir: oracledb.BIND_OUT, maxSize: 65535 } + }; + + async.series([ + function(cb) { + insertBlobWithbuffer(sequence, null, cb); + }, + function(cb) { + verifyBindOutResult(sqlRun, bindVar, null, null, cb); + } + ], done); + }); // 78.1.6 + + it('78.1.7 works with empty buffer', function(done) { + var sequence = insertID++; + var bufferStr = node6plus ? Buffer.from('', "utf-8") : new Buffer('', "utf-8"); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { type: oracledb.BUFFER, dir: oracledb.BIND_OUT } + }; + + async.series([ + function(cb) { + insertBlobWithbuffer(sequence, bufferStr, cb); + }, + function(cb) { + verifyBindOutResult(sqlRun, bindVar, bufferStr, null, cb); + } + ], done); + }); // 78.1.7 + + it('78.1.8 works with empty buffer and bind out maxSize set to 1', function(done) { + var sequence = insertID++; + var bufferStr = node6plus ? Buffer.from('', "utf-8") : new Buffer('', "utf-8"); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { type: oracledb.BUFFER, dir: oracledb.BIND_OUT, maxSize: 1 } + }; + + async.series([ + function(cb) { + insertBlobWithbuffer(sequence, bufferStr, cb); + }, + function(cb) { + verifyBindOutResult(sqlRun, bindVar, bufferStr, null, cb); + } + ], done); + }); // 78.1.8 + + it('78.1.9 works with empty buffer and bind out maxSize set to (64K - 1)', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { type: oracledb.BUFFER, dir: oracledb.BIND_OUT, maxSize: 65535 } + }; + var bufferStr = node6plus ? Buffer.from('', "utf-8") : new Buffer('', "utf-8"); + + async.series([ + function(cb) { + insertBlobWithbuffer(sequence, bufferStr, cb); + }, + function(cb) { + verifyBindOutResult(sqlRun, bindVar, bufferStr, null, cb); + } + ], done); + }); // 78.1.9 + + it('78.1.10 works with undefined', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { type: oracledb.BUFFER, dir: oracledb.BIND_OUT } + }; + + async.series([ + function(cb) { + insertBlobWithbuffer(sequence, undefined, cb); + }, + function(cb) { + verifyBindOutResult(sqlRun, bindVar, undefined, null, cb); + } + ], done); + }); // 78.1.10 + + it('78.1.11 works with undefined and bind out maxSize set to 1', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { type: oracledb.BUFFER, dir: oracledb.BIND_OUT, maxSize: 1 } + }; + + async.series([ + function(cb) { + insertBlobWithbuffer(sequence, undefined, cb); + }, + function(cb) { + verifyBindOutResult(sqlRun, bindVar, undefined, null, cb); + } + ], done); + }); // 78.1.11 + + it('78.1.12 works with undefined and bind out maxSize set to (64K - 1)', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { type: oracledb.BUFFER, dir: oracledb.BIND_OUT, maxSize: 65535 } + }; + + async.series([ + function(cb) { + insertBlobWithbuffer(sequence, undefined, cb); + }, + function(cb) { + verifyBindOutResult(sqlRun, bindVar, undefined, null, cb); + } + ], done); + }); // 78.1.12 + + it('78.1.13 works with Buffer size 32K', function(done) { + // Driver already supports CLOB AS STRING and BLOB AS BUFFER for PLSQL BIND if the data size less than or equal to 32767. + // As part of this enhancement, driver allows even if data size more than 32767 for both column types + var size = 32768; + var sequence = insertID++; + var specialStr = "78.1.13"; + var bigStr = random.getRandomString(size, specialStr); + var bufferStr = node6plus ? Buffer.from(bigStr, "utf-8") : new Buffer(bigStr, "utf-8"); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { type: oracledb.BUFFER, dir: oracledb.BIND_OUT, maxSize: size } + }; + + async.series([ + function(cb) { + insertBlobWithbuffer(sequence, bufferStr, cb); + }, + function(cb) { + var sql = "select blob_1 from nodb_tab_blob_in where id = " + sequence; + verifyBlobValueWithBuffer(sql, bufferStr, specialStr, cb); + }, + function(cb) { + verifyBindOutResult(sqlRun, bindVar, bufferStr, specialStr, cb); + } + ], done); + }); // 78.1.13 + + it('78.1.14 works with Buffer size (64K - 1)', function(done) { + var size = 65535; + var sequence = insertID++; + var specialStr = "78.1.14"; + var bigStr = random.getRandomString(size, specialStr); + var bufferStr = node6plus ? Buffer.from(bigStr, "utf-8") : new Buffer(bigStr, "utf-8"); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { type: oracledb.BUFFER, dir: oracledb.BIND_OUT, maxSize: size } + }; + + async.series([ + function(cb) { + insertBlobWithbuffer(sequence, bufferStr, cb); + }, + function(cb) { + var sql = "select blob_1 from nodb_tab_blob_in where id = " + sequence; + verifyBlobValueWithBuffer(sql, bufferStr, specialStr, cb); + }, + function(cb) { + verifyBindOutResult(sqlRun, bindVar, bufferStr, specialStr, cb); + } + ], done); + }); // 78.1.14 + + it('78.1.15 works with Buffer size (64K + 1)', function(done) { + var size = 65537; + var sequence = insertID++; + var specialStr = "78.1.15"; + var bigStr = random.getRandomString(size, specialStr); + var bufferStr = node6plus ? Buffer.from(bigStr, "utf-8") : new Buffer(bigStr, "utf-8"); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { type: oracledb.BUFFER, dir: oracledb.BIND_OUT, maxSize: size } + }; + + async.series([ + function(cb) { + insertBlobWithbuffer(sequence, bufferStr, cb); + }, + function(cb) { + verifyBindOutResult(sqlRun, bindVar, bufferStr, specialStr, cb); + }, + function(cb) { + file.delete(inFileStreamed); + cb(); + } + ], done); + }); // 78.1.15 + + it('78.1.16 works with Buffer size (1MB + 1)', function(done) { + var size = 1048577; // 1 * 1024 * 1024 + 1 + var sequence = insertID++; + var specialStr = "78.1.16"; + var bigStr = random.getRandomString(size, specialStr); + var bufferStr = node6plus ? Buffer.from(bigStr, "utf-8") : new Buffer(bigStr, "utf-8"); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { type: oracledb.BUFFER, dir: oracledb.BIND_OUT, maxSize: size } + }; + + async.series([ + function(cb) { + insertBlobWithbuffer(sequence, bufferStr, cb); + }, + function(cb) { + verifyBindOutResult(sqlRun, bindVar, bufferStr, specialStr, cb); + }, + function(cb) { + file.delete(inFileStreamed); + cb(); + } + ], done); + }); // 78.1.16 + + it('78.1.17 mixing named with positional binding', function(done) { + var size = 50000; + var sequence = insertID++; + var specialStr = "78.1.17"; + var bigStr = random.getRandomString(size, specialStr); + var bufferStr = node6plus ? Buffer.from(bigStr, "utf-8") : new Buffer(bigStr, "utf-8"); + var bindVar = [ sequence, { type: oracledb.BUFFER, dir: oracledb.BIND_OUT, maxSize: size } ]; + + async.series([ + function(cb) { + insertBlobWithbuffer(sequence, bufferStr, cb); + }, + function(cb) { + connection.execute( + sqlRun, + bindVar, + function(err, result) { + should.not.exist(err); + var resultVal = result.outBinds[0]; + compareResultBufAndOriginal(resultVal, bufferStr, specialStr); + cb(); + } + ); + } + ], done); + }); // 78.1.17 + + it('78.1.18 works with UPDATE', function(done) { + var proc_7821 = "CREATE OR REPLACE PROCEDURE nodb_blobs_out_7821 (blob_id IN NUMBER, blob_in IN BLOB, blob_out OUT BLOB) \n" + + "AS \n" + + "BEGIN \n" + + " update nodb_tab_blob_in set blob_1 = blob_in where id = blob_id; \n" + + " select blob_1 into blob_out from nodb_tab_blob_in where id = blob_id; \n" + + "END nodb_blobs_out_7821; "; + var sqlRun_7821 = "BEGIN nodb_blobs_out_7821 (:i, :bi, :bo); END;"; + var proc_drop_7821 = "DROP PROCEDURE nodb_blobs_out_7821"; + var size_1 = 50000; + var sequence = insertID++; + var specialStr_1 = "78.1.18_1"; + var bigStr_1 = random.getRandomString(size_1, specialStr_1); + var bufferStr_1 = node6plus ? Buffer.from(bigStr_1, "utf-8") : new Buffer(bigStr_1, "utf-8"); + var size_2 = 40000; + var specialStr_2 = "78.1.18_2"; + var bigStr_2 = random.getRandomString(size_2, specialStr_2); + var bufferStr_2 = node6plus ? Buffer.from(bigStr_2, "utf-8") : new Buffer(bigStr_2, "utf-8"); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + bi: { val:bufferStr_2, type: oracledb.BUFFER, dir: oracledb.BIND_IN, maxSize: size_2 }, + bo: { type: oracledb.BUFFER, dir: oracledb.BIND_OUT, maxSize: size_2 } + }; + + async.series([ + function(cb) { + insertBlobWithbuffer(sequence, bufferStr_1, cb); + }, + function(cb) { + executeSQL(proc_7821, cb); + }, + function(cb) { + connection.execute( + sqlRun_7821, + bindVar, + function(err, result) { + should.not.exist(err); + var resultVal = result.outBinds.bo; + compareResultBufAndOriginal(resultVal, bufferStr_2, specialStr_2); + cb(); + } + ); + }, + function(cb) { + executeSQL(proc_drop_7821, cb); + } + ], done); + }); // 78.1.18 + + it('78.1.19 works with dbms_lob.substr()', function(done) { + var size = 50000; + var sequence = insertID++; + var specialStr = "78.1.19"; + var bigStr = random.getRandomString(size, specialStr); + var bufferStr = node6plus ? Buffer.from(bigStr, "utf-8") : new Buffer(bigStr, "utf-8"); + var proc_78123 = "CREATE OR REPLACE PROCEDURE nodb_blobs_out_78123 (blob_id IN NUMBER, blob_out OUT BLOB) \n" + + "AS \n" + + "BEGIN \n" + + " select dbms_lob.substr(blob_1, " + specialStr.length + ", 1) into blob_out from nodb_tab_blob_in where id = blob_id; \n" + + "END nodb_blobs_out_78123; "; + var sqlRun_78123 = "BEGIN nodb_blobs_out_78123 (:i, :b); END;"; + var proc_drop_78123 = "DROP PROCEDURE nodb_blobs_out_78123"; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { type: oracledb.BUFFER, dir: oracledb.BIND_OUT, maxSize: size } + }; + + async.series([ + function(cb) { + insertBlobWithbuffer(sequence, bufferStr, cb); + }, + function(cb) { + executeSQL(proc_78123, cb); + }, + function(cb) { + connection.execute( + sqlRun_78123, + bindVar, + function(err, result) { + should.not.exist(err); + var resultVal = result.outBinds.b; + var comparedBuf = node6plus ? Buffer.from(specialStr, "utf-8") : new Buffer(specialStr, "utf-8"); + compareResultBufAndOriginal(resultVal, comparedBuf, specialStr); + cb(); + } + ); + }, + function(cb) { + executeSQL(proc_drop_78123, cb); + } + ], done); + }); // 78.1.19 + + it('78.1.20 named binding: bind out maxSize smaller than buffer size( < 32K )', function(done) { + var size = 3000; + var sequence = insertID++; + var specialStr = "78.1.20"; + var bigStr = random.getRandomString(size, specialStr); + var bufferStr = node6plus ? Buffer.from(bigStr, "utf-8") : new Buffer(bigStr, "utf-8"); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { type: oracledb.BUFFER, dir: oracledb.BIND_OUT, maxSize: size - 1 } + }; + + async.series([ + function(cb) { + insertBlobWithbuffer(sequence, bufferStr, cb); + }, + function(cb) { + connection.execute( + sqlRun, + bindVar, + function(err) { + should.exist(err); + // ORA-06502: PL/SQL: numeric or value error: raw variable length too long + (err.message).should.startWith('ORA-06502:'); + cb(); + } + ); + } + ], done); + }); // 78.1.20 + + it('78.1.21 named binding: bind out maxSize smaller than buffer size( > 32K )', function(done) { + var size = 50000; + var sequence = insertID++; + var specialStr = "78.1.21"; + var bigStr = random.getRandomString(size, specialStr); + var bufferStr = node6plus ? Buffer.from(bigStr, "utf-8") : new Buffer(bigStr, "utf-8"); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { type: oracledb.BUFFER, dir: oracledb.BIND_OUT, maxSize: size - 1 } + }; + + async.series([ + function(cb) { + insertBlobWithbuffer(sequence, bufferStr, cb); + }, + function(cb) { + connection.execute( + sqlRun, + bindVar, + function(err) { + should.exist(err); + // NJS-016: buffer is too small for OUT binds + (err.message).should.startWith('NJS-016:'); + cb(); + } + ); + } + ], done); + }); // 78.1.21 + + it('78.1.22 named binding: bind out maxSize smaller than buffer size( > 64K )', function(done) { + var size = 65540; + var sequence = insertID++; + var specialStr = "78.1.22"; + var bigStr = random.getRandomString(size, specialStr); + var bufferStr = node6plus ? Buffer.from(bigStr, "utf-8") : new Buffer(bigStr, "utf-8"); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { type: oracledb.BUFFER, dir: oracledb.BIND_OUT, maxSize: size - 1 } + }; + + async.series([ + function(cb) { + insertBlobWithbuffer(sequence, bufferStr, cb); + }, + function(cb) { + connection.execute( + sqlRun, + bindVar, + function(err) { + should.exist(err); + // NJS-016: buffer is too small for OUT binds + (err.message).should.startWith('NJS-016:'); + cb(); + } + ); + } + ], done); + }); // 78.1.22 + + it('78.1.23 positional binding: bind out maxSize smaller than buffer size( < 32K )', function(done) { + var size = 3000; + var sequence = insertID++; + var specialStr = "78.1.23"; + var bigStr = random.getRandomString(size, specialStr); + var bufferStr = node6plus ? Buffer.from(bigStr, "utf-8") : new Buffer(bigStr, "utf-8"); + sqlRun = "BEGIN nodb_blobs_out_782 (:1, :2); END;"; + var bindVar = [ sequence, { type: oracledb.BUFFER, dir: oracledb.BIND_OUT, maxSize: size - 1 } ]; + + async.series([ + function(cb) { + insertBlobWithbuffer(sequence, bufferStr, cb); + }, + function(cb) { + connection.execute( + sqlRun, + bindVar, + function(err) { + should.exist(err); + // ORA-06502: PL/SQL: numeric or value error: raw variable length too long + (err.message).should.startWith('ORA-06502:'); + cb(); + } + ); + } + ], done); + }); // 78.1.23 + + it('78.1.24 positional binding: bind out maxSize smaller than buffer size( > 32K )', function(done) { + var size = 32769; + var sequence = insertID++; + var specialStr = "78.1.24"; + var bigStr = random.getRandomString(size, specialStr); + var bufferStr = node6plus ? Buffer.from(bigStr, "utf-8") : new Buffer(bigStr, "utf-8"); + sqlRun = "BEGIN nodb_blobs_out_782 (:1, :2); END;"; + var bindVar = [ sequence, { type: oracledb.BUFFER, dir: oracledb.BIND_OUT, maxSize: size - 1 } ]; + + async.series([ + function(cb) { + insertBlobWithbuffer(sequence, bufferStr, cb); + }, + function(cb) { + connection.execute( + sqlRun, + bindVar, + function(err) { + should.exist(err); + // NJS-016: buffer is too small for OUT binds + (err.message).should.startWith('NJS-016:'); + cb(); + } + ); + } + ], done); + }); // 78.1.24 + + it('78.1.25 positional binding: bind out maxSize smaller than buffer size( > 64K )', function(done) { + var size = 65538; + var sequence = insertID++; + var specialStr = "78.1.25"; + var bigStr = random.getRandomString(size, specialStr); + var bufferStr = node6plus ? Buffer.from(bigStr, "utf-8") : new Buffer(bigStr, "utf-8"); + sqlRun = "BEGIN nodb_blobs_out_782 (:1, :2); END;"; + var bindVar = [ sequence, { type: oracledb.BUFFER, dir: oracledb.BIND_OUT, maxSize: size - 1 } ]; + + async.series([ + function(cb) { + insertBlobWithbuffer(sequence, bufferStr, cb); + }, + function(cb) { + connection.execute( + sqlRun, + bindVar, + function(err) { + should.exist(err); + // NJS-016: buffer is too small for OUT binds + (err.message).should.startWith('NJS-016:'); + cb(); + } + ); + } + ], done); + }); // 78.1.25 + + it('78.1.26 bind out without maxSize', function(done) { + var size = 50000; + var sequence = insertID++; + var specialStr = "78.1.26"; + var bigStr = random.getRandomString(size, specialStr); + var bufferStr = node6plus ? Buffer.from(bigStr, "utf-8") : new Buffer(bigStr, "utf-8"); + var bindVar = [ sequence, { type: oracledb.BUFFER, dir: oracledb.BIND_OUT } ]; + + async.series([ + function(cb) { + insertBlobWithbuffer(sequence, bufferStr, cb); + }, + function(cb) { + connection.execute( + sqlRun, + bindVar, + function(err) { + should.exist(err); + // ORA-06502: PL/SQL: numeric or value error + (err.message).should.startWith('ORA-06502:'); + cb(); + } + ); + } + ], done); + }); // 78.1.26 + + }); // 78.1 + + describe('78.2 BLOB, PLSQL, BIND_OUT to RAW', function() { + var proc = "CREATE OR REPLACE PROCEDURE nodb_blobs_out_772 (blob_id IN NUMBER, blob_out OUT RAW) \n" + + "AS \n" + + "BEGIN \n" + + " select blob_1 into blob_out from nodb_tab_blob_in where id = blob_id; \n" + + "END nodb_blobs_out_772; "; + var sqlRun = "BEGIN nodb_blobs_out_772 (:i, :b); END;"; + var proc_drop = "DROP PROCEDURE nodb_blobs_out_772"; + + before(function(done) { + executeSQL(proc, done); + }); // before + + after(function(done) { + executeSQL(proc_drop, done); + }); // after + + it('78.2.1 works with EMPTY_BLOB', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { type: oracledb.BUFFER, dir: oracledb.BIND_OUT } + }; + + async.series([ + function(cb) { + insertBlobWithbuffer(sequence, "EMPTY_LOB", cb); + }, + function(cb) { + verifyBindOutResult(sqlRun, bindVar, "EMPTY_LOB", null, cb); + } + ], done); + }); // 78.2.1 + + it('78.2.2 works with EMPTY_BLOB and bind out maxSize set to 1', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { type: oracledb.BUFFER, dir: oracledb.BIND_OUT, maxSize: 1 } + }; + + async.series([ + function(cb) { + insertBlobWithbuffer(sequence, "EMPTY_LOB", cb); + }, + function(cb) { + verifyBindOutResult(sqlRun, bindVar, "EMPTY_LOB", null, cb); + } + ], done); + }); // 78.2.2 + + it('78.2.3 works with EMPTY_BLOB and bind out maxSize set to (64K - 1)', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { type: oracledb.BUFFER, dir: oracledb.BIND_OUT, maxSize: 65535 } + }; + + async.series([ + function(cb) { + insertBlobWithbuffer(sequence, "EMPTY_LOB", cb); + }, + function(cb) { + verifyBindOutResult(sqlRun, bindVar, "EMPTY_LOB", null, cb); + } + ], done); + }); // 78.2.3 + + it('78.2.4 works with null', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { type: oracledb.BUFFER, dir: oracledb.BIND_OUT } + }; + + async.series([ + function(cb) { + insertBlobWithbuffer(sequence, null, cb); + }, + function(cb) { + verifyBindOutResult(sqlRun, bindVar, null, null, cb); + } + ], done); + }); // 78.2.4 + + it('78.2.5 works with null and bind out maxSize set to 1', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { type: oracledb.BUFFER, dir: oracledb.BIND_OUT, maxSize: 1 } + }; + + async.series([ + function(cb) { + insertBlobWithbuffer(sequence, null, cb); + }, + function(cb) { + verifyBindOutResult(sqlRun, bindVar, null, null, cb); + } + ], done); + }); // 78.2.5 + + it('78.2.6 works with null and bind out maxSize set to (64K - 1)', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { type: oracledb.BUFFER, dir: oracledb.BIND_OUT, maxSize: 65535 } + }; + + async.series([ + function(cb) { + insertBlobWithbuffer(sequence, null, cb); + }, + function(cb) { + verifyBindOutResult(sqlRun, bindVar, null, null, cb); + } + ], done); + }); // 78.2.6 + + it('78.2.7 works with empty buffer', function(done) { + var sequence = insertID++; + var bufferStr = node6plus ? Buffer.from('', "utf-8") : new Buffer('', "utf-8"); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { type: oracledb.BUFFER, dir: oracledb.BIND_OUT } + }; + + async.series([ + function(cb) { + insertBlobWithbuffer(sequence, bufferStr, cb); + }, + function(cb) { + verifyBindOutResult(sqlRun, bindVar, bufferStr, null, cb); + } + ], done); + }); // 78.2.7 + + it('78.2.8 works with empty buffer and bind out maxSize set to 1', function(done) { + var sequence = insertID++; + var bufferStr = node6plus ? Buffer.from('', "utf-8") : new Buffer('', "utf-8"); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { type: oracledb.BUFFER, dir: oracledb.BIND_OUT, maxSize: 1 } + }; + + async.series([ + function(cb) { + insertBlobWithbuffer(sequence, bufferStr, cb); + }, + function(cb) { + verifyBindOutResult(sqlRun, bindVar, bufferStr, null, cb); + } + ], done); + }); // 78.2.8 + + it('78.2.9 works with empty buffer and bind out maxSize set to (64K - 1)', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { type: oracledb.BUFFER, dir: oracledb.BIND_OUT, maxSize: 65535 } + }; + var bufferStr = node6plus ? Buffer.from('', "utf-8") : new Buffer('', "utf-8"); + + async.series([ + function(cb) { + insertBlobWithbuffer(sequence, bufferStr, cb); + }, + function(cb) { + verifyBindOutResult(sqlRun, bindVar, bufferStr, null, cb); + } + ], done); + }); // 78.2.9 + + it('78.2.10 works with undefined', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { type: oracledb.BUFFER, dir: oracledb.BIND_OUT } + }; + + async.series([ + function(cb) { + insertBlobWithbuffer(sequence, undefined, cb); + }, + function(cb) { + verifyBindOutResult(sqlRun, bindVar, undefined, null, cb); + } + ], done); + }); // 78.2.10 + + it('78.2.11 works with undefined and bind out maxSize set to 1', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { type: oracledb.BUFFER, dir: oracledb.BIND_OUT, maxSize: 1 } + }; + + async.series([ + function(cb) { + insertBlobWithbuffer(sequence, undefined, cb); + }, + function(cb) { + verifyBindOutResult(sqlRun, bindVar, undefined, null, cb); + } + ], done); + }); // 78.2.11 + + it('78.2.12 works with undefined and bind out maxSize set to (64K - 1)', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { type: oracledb.BUFFER, dir: oracledb.BIND_OUT, maxSize: 65535 } + }; + + async.series([ + function(cb) { + insertBlobWithbuffer(sequence, undefined, cb); + }, + function(cb) { + verifyBindOutResult(sqlRun, bindVar, undefined, null, cb); + } + ], done); + }); // 78.2.12 + + it('78.2.13 works with Buffer size (32K - 1)', function(done) { + var size = 32767; + var sequence = insertID++; + var specialStr = "78.2.13"; + var bigStr = random.getRandomString(size, specialStr); + var bufferStr = node6plus ? Buffer.from(bigStr, "utf-8") : new Buffer(bigStr, "utf-8"); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { type: oracledb.BUFFER, dir: oracledb.BIND_OUT, maxSize: size } + }; + + async.series([ + function(cb) { + insertBlobWithbuffer(sequence, bufferStr, cb); + }, + function(cb) { + var sql = "select blob_1 from nodb_tab_blob_in where id = " + sequence; + verifyBlobValueWithBuffer(sql, bufferStr, specialStr, cb); + }, + function(cb) { + verifyBindOutResult(sqlRun, bindVar, bufferStr, specialStr, cb); + } + ], done); + }); // 78.2.13 + + it('78.2.14 works with Buffer size 32K', function(done) { + var size = 32768; + var sequence = insertID++; + var specialStr = "78.2.14"; + var bigStr = random.getRandomString(size, specialStr); + var bufferStr = node6plus ? Buffer.from(bigStr, "utf-8") : new Buffer(bigStr, "utf-8"); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { type: oracledb.BUFFER, dir: oracledb.BIND_OUT, maxSize: size } + }; + + async.series([ + function(cb) { + insertBlobWithbuffer(sequence, bufferStr, cb); + }, + function(cb) { + connection.execute( + sqlRun, + bindVar, + function(err) { + should.exist(err); + // ORA-06502: PL/SQL: numeric or value error + (err.message).should.startWith('ORA-06502:'); + cb(); + } + ); + } + ], done); + }); // 78.2.14 + + it('78.2.15 works with bind out maxSize smaller than buffer size', function(done) { + var size = 200; + var sequence = insertID++; + var specialStr = "78.2.15"; + var bigStr = random.getRandomString(size, specialStr); + var bufferStr = node6plus ? Buffer.from(bigStr, "utf-8") : new Buffer(bigStr, "utf-8"); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { type: oracledb.BUFFER, dir: oracledb.BIND_OUT, maxSize: size - 1 } + }; + + async.series([ + function(cb) { + insertBlobWithbuffer(sequence, bufferStr, cb); + }, + function(cb) { + connection.execute( + sqlRun, + bindVar, + function(err) { + should.exist(err); + // ORA-06502: PL/SQL: numeric or value error + (err.message).should.startWith('ORA-06502:'); + cb(); + } + ); + } + ], done); + }); // 78.2.15 + + it('78.2.16 bind out without maxSize', function(done) { + var size = 500; + var sequence = insertID++; + var specialStr = "78.2.16"; + var bigStr = random.getRandomString(size, specialStr); + var bufferStr = node6plus ? Buffer.from(bigStr, "utf-8") : new Buffer(bigStr, "utf-8"); + var bindVar = [ sequence, { type: oracledb.BUFFER, dir: oracledb.BIND_OUT } ]; + + async.series([ + function(cb) { + insertBlobWithbuffer(sequence, bufferStr, cb); + }, + function(cb) { + connection.execute( + sqlRun, + bindVar, + function(err) { + should.exist(err); + // ORA-06502: PL/SQL: numeric or value error + (err.message).should.startWith('ORA-06502:'); + cb(); + } + ); + } + ], done); + }); // 78.2.16 + + it('78.2.17 works with UPDATE', function(done) { + var proc_7821 = "CREATE OR REPLACE PROCEDURE nodb_blobs_out_7821 (blob_id IN NUMBER, blob_in IN RAW, blob_out OUT RAW) \n" + + "AS \n" + + "BEGIN \n" + + " update nodb_tab_blob_in set blob_1 = blob_in where id = blob_id; \n" + + " select blob_1 into blob_out from nodb_tab_blob_in where id = blob_id; \n" + + "END nodb_blobs_out_7821; "; + var sqlRun_7821 = "BEGIN nodb_blobs_out_7821 (:i, :bi, :bo); END;"; + var proc_drop_7821 = "DROP PROCEDURE nodb_blobs_out_7821"; + var size_1 = 200; + var sequence = insertID++; + var specialStr_1 = "78.2.17_1"; + var bigStr_1 = random.getRandomString(size_1, specialStr_1); + var bufferStr_1 = node6plus ? Buffer.from(bigStr_1, "utf-8") : new Buffer(bigStr_1, "utf-8"); + var size_2 = 300; + var specialStr_2 = "78.2.17_2"; + var bigStr_2 = random.getRandomString(size_2, specialStr_2); + var bufferStr_2 = node6plus ? Buffer.from(bigStr_2, "utf-8") : new Buffer(bigStr_2, "utf-8"); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + bi: { val:bufferStr_2, type: oracledb.BUFFER, dir: oracledb.BIND_IN, maxSize: size_2 }, + bo: { type: oracledb.BUFFER, dir: oracledb.BIND_OUT, maxSize: size_2 } + }; + + async.series([ + function(cb) { + insertBlobWithbuffer(sequence, bufferStr_1, cb); + }, + function(cb) { + executeSQL(proc_7821, cb); + }, + function(cb) { + connection.execute( + sqlRun_7821, + bindVar, + function(err, result) { + should.not.exist(err); + var resultVal = result.outBinds.bo; + compareResultBufAndOriginal(resultVal, bufferStr_2, specialStr_2); + cb(); + } + ); + }, + function(cb) { + executeSQL(proc_drop_7821, cb); + } + ], done); + }); // 78.2.17 + + it('78.2.18 works with dbms_lob.substr()', function(done) { + var size = 3000; + var sequence = insertID++; + var specialStr = "78.2.18"; + var bigStr = random.getRandomString(size, specialStr); + var bufferStr = node6plus ? Buffer.from(bigStr, "utf-8") : new Buffer(bigStr, "utf-8"); + var proc_78223 = "CREATE OR REPLACE PROCEDURE nodb_blobs_out_78223 (blob_id IN NUMBER, blob_out OUT RAW) \n" + + "AS \n" + + "BEGIN \n" + + " select dbms_lob.substr(blob_1, " + specialStr.length + ", 1) into blob_out from nodb_tab_blob_in where id = blob_id; \n" + + "END nodb_blobs_out_78223; "; + var sqlRun_78223 = "BEGIN nodb_blobs_out_78223 (:i, :b); END;"; + var proc_drop_78223 = "DROP PROCEDURE nodb_blobs_out_78223"; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { type: oracledb.BUFFER, dir: oracledb.BIND_OUT, maxSize: size } + }; + + async.series([ + function(cb) { + insertBlobWithbuffer(sequence, bufferStr, cb); + }, + function(cb) { + executeSQL(proc_78223, cb); + }, + function(cb) { + connection.execute( + sqlRun_78223, + bindVar, + function(err, result) { + should.not.exist(err); + var resultVal = result.outBinds.b; + var comparedBuf = node6plus ? Buffer.from(specialStr, "utf-8") : new Buffer(specialStr, "utf-8"); + compareResultBufAndOriginal(resultVal, comparedBuf, specialStr); + cb(); + } + ); + }, + function(cb) { + executeSQL(proc_drop_78223, cb); + } + ], done); + }); // 78.2.18 + + }); // 78.2 + + describe('78.3 Multiple BLOBs, BIND_OUT', function() { + var proc = "CREATE OR REPLACE PROCEDURE nodb_lobs_out_775 (blob_id IN NUMBER, blob_1 OUT BLOB, blob_2 OUT BLOB) \n" + + "AS \n" + + "BEGIN \n" + + " select blob_1, blob_2 into blob_1, blob_2 from nodb_tab_blob_in where id = blob_id; \n" + + "END nodb_lobs_out_775; "; + var sqlRun = "BEGIN nodb_lobs_out_775 (:i, :b1, :b2); END;"; + var proc_drop = "DROP PROCEDURE nodb_lobs_out_775"; + + before(function(done) { + executeSQL(proc, done); + }); // before + + after(function(done) { + executeSQL(proc_drop, done); + }); // after + + var insertTwoBlobWithbuffer = function(id, insertBuffer1, insertBuffer2, callback) { + var sql = "INSERT INTO nodb_tab_blob_in (id, blob_1, blob_2) VALUES (:i, :b1, :b2)"; + var bindVar = { + i: { val: id, dir: oracledb.BIND_IN, type: oracledb.NUMBER }, + b1: { val: insertBuffer1, dir: oracledb.BIND_IN, type: oracledb.BUFFER }, + b2: { val: insertBuffer2, dir: oracledb.BIND_IN, type: oracledb.BUFFER } + }; + + connection.execute( + sql, + bindVar, + function(err, result) { + should.not.exist(err); + should.strictEqual(result.rowsAffected, 1); + callback(); + } + ); + }; + + it('78.3.1 bind two buffer', function(done) { + var specialStr_1 = "78.3.1_1"; + var specialStr_2 = "78.3.1_2"; + var size_1 = 32768; + var size_2 = 50000; + var sequence = insertID++; + var bigStr_1 = random.getRandomString(size_1, specialStr_1); + var bigStr_2 = random.getRandomString(size_2, specialStr_2); + var bufferStr_1 = node6plus ? Buffer.from(bigStr_1, "utf-8") : new Buffer(bigStr_1, "utf-8"); + var bufferStr_2 = node6plus ? Buffer.from(bigStr_2, "utf-8") : new Buffer(bigStr_2, "utf-8"); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b1: { type: oracledb.BUFFER, dir: oracledb.BIND_OUT, maxSize: size_1 }, + b2: { type: oracledb.BUFFER, dir: oracledb.BIND_OUT, maxSize: size_2 } + }; + + async.series([ + function(cb) { + insertTwoBlobWithbuffer(sequence, bufferStr_1, bufferStr_2, cb); + }, + function(cb) { + var sql = "select blob_1 from nodb_tab_blob_in where id = " + sequence; + verifyBlobValueWithBuffer(sql, bufferStr_1, specialStr_1, cb); + }, + function(cb) { + var sql = "select blob_2 from nodb_tab_blob_in where id = " + sequence; + verifyBlobValueWithBuffer(sql, bufferStr_2, specialStr_2, cb); + }, + function(cb) { + connection.execute( + sqlRun, + bindVar, + function(err, result) { + should.not.exist(err); + var resultVal = result.outBinds.b1; + compareResultBufAndOriginal(resultVal, bufferStr_1, specialStr_1); + resultVal = result.outBinds.b2; + compareResultBufAndOriginal(resultVal, bufferStr_2, specialStr_2); + cb(); + } + ); + } + ], done); + }); // 78.3.1 + + it('78.3.2 PLSQL, BIND_OUT, bind a JPG file and a Buffer', function(done) { + var specialStr = "78.3.2"; + var size_1 = 32768; + var bigStr_1 = random.getRandomString(size_1, specialStr); + var bufferStr_1 = node6plus ? Buffer.from(bigStr_1, "utf-8") : new Buffer(bigStr_1, "utf-8"); + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b1: { type: oracledb.BUFFER, dir: oracledb.BIND_OUT, maxSize: size_1 }, + b2: { type: oracledb.BLOB, dir: oracledb.BIND_OUT } + }; + + async.series([ + function(cb) { + var sql = "INSERT INTO nodb_tab_blob_in (id, blob_2) VALUES (:i, EMPTY_BLOB()) RETURNING blob_2 INTO :lobbv"; + prepareTableWithBlob(sql, sequence, cb); + }, + function(cb) { + var sql = "select blob_2 from nodb_tab_blob_in where id = " + sequence; + verifyBlobValueWithFileData(sql, cb); + }, + function(cb) { + var sql = "UPDATE nodb_tab_blob_in set blob_1 = :b1 where id = :i"; + var bindVar_1 = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b1: { val: bufferStr_1, type: oracledb.BUFFER, dir: oracledb.BIND_IN, maxSize: size_1 } + }; + connection.execute( + sql, + bindVar_1, + function(err, result) { + should.not.exist(err); + should.strictEqual(result.rowsAffected, 1); + cb(); + }); + }, + function(cb) { + var sql = "select blob_1 from nodb_tab_blob_in where id = " + sequence; + verifyBlobValueWithBuffer(sql, bufferStr_1, specialStr, cb); + }, + function(cb) { + connection.execute( + sqlRun, + bindVar, + function(err, result) { + should.not.exist(err); + var resultVal = result.outBinds.b1; + compareResultBufAndOriginal(resultVal, bufferStr_1, specialStr); + + var lob = result.outBinds.b2; + var blobData = node6plus ? Buffer.alloc(0) : new Buffer(0); + var totalLength = 0; + + lob.on('data', function(chunk) { + totalLength = totalLength + chunk.length; + blobData = Buffer.concat([blobData, chunk], totalLength); + }); + + lob.on('error', function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + lob.on('end', function() { + fs.readFile( jpgFileName, function(err, originalData) { + should.not.exist(err); + should.strictEqual(totalLength, originalData.length); + originalData.should.eql(blobData); + cb(); + }); + }); + } + ); + } + ], done); + }); // 78.3.2 + + it('78.3.3 bind two buffer, one > (64K - 1)', function(done) { + var specialStr_1 = "78.3.3_1"; + var specialStr_2 = "78.3.3_2"; + var size_1 = 65538; + var size_2 = 50000; + var sequence = insertID++; + var bigStr_1 = random.getRandomString(size_1, specialStr_1); + var bigStr_2 = random.getRandomString(size_2, specialStr_2); + var bufferStr_1 = node6plus ? Buffer.from(bigStr_1, "utf-8") : new Buffer(bigStr_1, "utf-8"); + var bufferStr_2 = node6plus ? Buffer.from(bigStr_2, "utf-8") : new Buffer(bigStr_2, "utf-8"); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b1: { type: oracledb.BUFFER, dir: oracledb.BIND_OUT, maxSize: size_1 }, + b2: { type: oracledb.BUFFER, dir: oracledb.BIND_OUT, maxSize: size_2 } + }; + + async.series([ + function(cb) { + insertTwoBlobWithbuffer(sequence, bufferStr_1, bufferStr_2, cb); + }, + function(cb) { + connection.execute( + sqlRun, + bindVar, + function(err, result) { + should.not.exist(err); + var resultVal = result.outBinds.b1; + compareResultBufAndOriginal(resultVal, bufferStr_1, specialStr_1); + resultVal = result.outBinds.b2; + compareResultBufAndOriginal(resultVal, bufferStr_2, specialStr_2); + cb(); + } + ); + } + ], done); + }); // 78.3.3 + + }); // 78.3 + +}); diff --git a/test/clobDMLBindAsString.js b/test/clobDMLBindAsString.js new file mode 100644 index 00000000..cfc7c5dd --- /dev/null +++ b/test/clobDMLBindAsString.js @@ -0,0 +1,742 @@ +/* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with the Apache + * License, Version 2.0 (the "License.") + * + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + * The node-oracledb test suite uses 'mocha', 'should' and 'async'. + * See LICENSE.md for relevant licenses. + * + * NAME + * 81. clobDMLBindAsString.js + * + * DESCRIPTION + * Testing CLOB binding as String with DML. + * + * NUMBERING RULE + * Test numbers follow this numbering rule: + * 1 - 20 are reserved for basic functional tests + * 21 - 50 are reserved for data type supporting tests + * 51 onwards are for other tests + * + *****************************************************************************/ +'use strict'; + +var oracledb = require('oracledb'); +var should = require('should'); +var async = require('async'); +var fs = require('fs'); +var dbConfig = require('./dbconfig.js'); +var random = require('./random.js'); + +describe('81. clobDMLBindAsString.js', function() { + this.timeout(100000); + + var connection = null; + var insertID = 1; // assume id for insert into db starts from 1 + + var proc_clob_1 = "BEGIN \n" + + " DECLARE \n" + + " e_table_missing EXCEPTION; \n" + + " PRAGMA EXCEPTION_INIT(e_table_missing, -00942); \n" + + " BEGIN \n" + + " EXECUTE IMMEDIATE('DROP TABLE nodb_dml_clob_1 PURGE'); \n" + + " EXCEPTION \n" + + " WHEN e_table_missing \n" + + " THEN NULL; \n" + + " END; \n" + + " EXECUTE IMMEDIATE (' \n" + + " CREATE TABLE nodb_dml_clob_1 ( \n" + + " id NUMBER, \n" + + " clob CLOB \n" + + " ) \n" + + " '); \n" + + "END; "; + var sql2DropTable1 = "DROP TABLE nodb_dml_clob_1 PURGE"; + + before(function(done) { + oracledb.getConnection(dbConfig, function(err, conn) { + should.not.exist(err); + connection = conn; + done(); + }); + }); // before + + after(function(done) { + connection.release(function(err) { + should.not.exist(err); + done(); + }); + }); // after + + var executeSQL = function(sql, callback) { + connection.execute( + sql, + function(err) { + should.not.exist(err); + return callback(); + } + ); + }; + + var insertIntoClobTable1 = function(id, content, callback) { + if(content == "EMPTY_CLOB") { + connection.execute( + "INSERT INTO nodb_dml_clob_1 VALUES (:ID, EMPTY_CLOB())", + [ id ], + function(err, result) { + should.not.exist(err); + should.strictEqual(result.rowsAffected, 1); + callback(); + } + ); + } else { + connection.execute( + "INSERT INTO nodb_dml_clob_1 VALUES (:ID, :C)", + { + ID : { val : id }, + C : { val : content, dir : oracledb.BIND_IN, type : oracledb.STRING } + }, + function(err, result) { + should.not.exist(err); + should.strictEqual(result.rowsAffected, 1); + callback(); + } + ); + } + }; + + var updateClobTable1 = function(id, content, callback) { + if(content == "EMPTY_CLOB") { + connection.execute( + "UPDATE nodb_dml_clob_1 set clob = EMPTY_CLOB() where id = :ID", + { ID: id }, + function(err, result){ + should.not.exist(err); + should.strictEqual(result.rowsAffected, 1); + callback(); + } + ); + } else { + connection.execute( + "UPDATE nodb_dml_clob_1 set clob = :C where id = :ID", + { ID: id, C: content }, + function(err, result){ + should.not.exist(err); + should.strictEqual(result.rowsAffected, 1); + callback(); + } + ); + } + }; + + // compare the inserted clob with orginal content + var verifyClobValueWithString = function(selectSql, originalString, specialStr, callback) { + connection.execute( + selectSql, + function(err, result) { + should.not.exist(err); + var lob = result.rows[0][0]; + if(originalString == '' || originalString == undefined || originalString == null) { + should.not.exist(lob); + return callback(); + } else { + should.exist(lob); + // set the encoding so we get a 'string' not a 'buffer' + lob.setEncoding('utf8'); + var clobData = ''; + + lob.on('data', function(chunk) { + clobData += chunk; + }); + + lob.on('error', function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + lob.on('end', function(err) { + should.not.exist(err); + if (originalString == "EMPTY_CLOB") { + should.strictEqual(clobData, ""); + } else { + var resultLength = clobData.length; + var specStrLength = specialStr.length; + should.strictEqual(resultLength, originalString.length); + should.strictEqual(clobData.substring(0, specStrLength), specialStr); + should.strictEqual(clobData.substring(resultLength - specStrLength, resultLength), specialStr); + } + return callback(); + }); + } + } + ); + }; + + var checkInsertResult = function(id, content, specialStr, callback) { + var sql = "select clob from nodb_dml_clob_1 where id = " + id; + verifyClobValueWithString(sql, content, specialStr, callback); + }; + + describe('81.1 CLOB, INSERT', function() { + before(function(done) { + executeSQL(proc_clob_1, done); + }); // before + + after(function(done) { + executeSQL(sql2DropTable1, done); + }); // after + + it('81.1.1 works with EMPTY_CLOB', function(done) { + var id = insertID++; + var content = "EMPTY_CLOB"; + + async.series([ + function(cb) { + insertIntoClobTable1(id, content, cb); + }, + function(cb) { + checkInsertResult(id, content, null, cb); + } + ], done); + }); // 81.1.1 + + it('81.1.2 works with empty string', function(done) { + var id = insertID++; + var content = ''; + + async.series([ + function(cb) { + insertIntoClobTable1(id, content, cb); + }, + function(cb) { + checkInsertResult(id, content, null, cb); + } + ], done); + }); // 81.1.2 + + it('81.1.3 works with empty string and bind in maxSize set to 32767', function(done) { + var id = insertID++; + var content = ""; + + async.series([ + function(cb) { + connection.execute( + "INSERT INTO nodb_dml_clob_1 VALUES (:ID, :C)", + { + ID : { val : id }, + C : { val : content, dir : oracledb.BIND_IN, type : oracledb.STRING, maxSize: 32767 } + }, + function(err, result) { + should.not.exist(err); + should.strictEqual(result.rowsAffected, 1); + cb(); + } + ); + }, + function(cb) { + checkInsertResult(id, content, null, cb); + } + ], done); + }); // 81.1.3 + + it('81.1.4 works with empty string and bind in maxSize set to 50000', function(done) { + var id = insertID++; + var content = ""; + + async.series([ + function(cb) { + connection.execute( + "INSERT INTO nodb_dml_clob_1 VALUES (:ID, :C)", + { + ID : { val : id }, + C : { val : content, dir : oracledb.BIND_IN, type : oracledb.STRING, maxSize: 50000 } + }, + function(err, result) { + should.not.exist(err); + should.strictEqual(result.rowsAffected, 1); + cb(); + } + ); + }, + function(cb) { + checkInsertResult(id, content, null, cb); + } + ], done); + }); // 81.1.4 + + it('81.1.5 works with undefined', function(done) { + var id = insertID++; + var content = undefined; + + async.series([ + function(cb) { + insertIntoClobTable1(id, content, cb); + }, + function(cb) { + checkInsertResult(id, content, null, cb); + } + ], done); + }); // 81.1.5 + + it('81.1.6 works with null', function(done) { + var id = insertID++; + var content = null; + + async.series([ + function(cb) { + insertIntoClobTable1(id, content, cb); + }, + function(cb) { + checkInsertResult(id, content, null, cb); + } + ], done); + }); // 81.1.6 + + it('81.1.7 works with null and bind in maxSize set to 32767', function(done) { + var id = insertID++; + var content = null; + + async.series([ + function(cb) { + connection.execute( + "INSERT INTO nodb_dml_clob_1 VALUES (:ID, :C)", + { + ID : { val : id }, + C : { val : content, dir : oracledb.BIND_IN, type : oracledb.STRING, maxSize: 32767 } + }, + function(err, result) { + should.not.exist(err); + should.strictEqual(result.rowsAffected, 1); + cb(); + } + ); + }, + function(cb) { + checkInsertResult(id, content, null, cb); + } + ], done); + }); // 81.1.7 + + it('81.1.8 works with null and bind in maxSize set to 50000', function(done) { + var id = insertID++; + var content = null; + + async.series([ + function(cb) { + connection.execute( + "INSERT INTO nodb_dml_clob_1 VALUES (:ID, :C)", + { + ID : { val : id }, + C : { val : content, dir : oracledb.BIND_IN, type : oracledb.STRING, maxSize: 50000 } + }, + function(err, result) { + should.not.exist(err); + should.strictEqual(result.rowsAffected, 1); + cb(); + } + ); + }, + function(cb) { + checkInsertResult(id, content, null, cb); + } + ], done); + }); // 81.1.8 + + it('81.1.9 works with NaN', function(done) { + var id = insertID++; + var content = NaN; + + connection.execute( + "INSERT INTO nodb_dml_clob_1 VALUES (:ID, :C)", + { + ID : { val : id }, + C : { val : content, dir : oracledb.BIND_IN, type : oracledb.STRING } + }, + function(err) { + should.exist(err); + // NJS-011: encountered bind value and type mismatch in parameter 2 + (err.message).should.startWith('NJS-011:'); + done(); + } + ); + }); // 81.1.9 + + it('81.1.10 works with 0', function(done) { + var id = insertID++; + var content = 0; + + connection.execute( + "INSERT INTO nodb_dml_clob_1 VALUES (:ID, :C)", + { + ID : { val : id }, + C : { val : content, dir : oracledb.BIND_IN, type : oracledb.STRING } + }, + function(err) { + should.exist(err); + // NJS-011: encountered bind value and type mismatch in parameter 2 + (err.message).should.startWith('NJS-011:'); + done(); + } + ); + }); // 81.1.10 + + it('81.1.11 works with String length 32K', function(done) { + var id = insertID++; + var contentLength = 32768; + var specialStr = "81.1.11"; + var content = random.getRandomString(contentLength, specialStr); + + async.series([ + function(cb) { + insertIntoClobTable1(id, content, cb); + }, + function(cb) { + checkInsertResult(id, content, specialStr, cb); + } + ], done); + }); // 81.1.11 + + it('81.1.12 works with String length (64K - 1)', function(done) { + var id = insertID++; + var contentLength = 65535; + var specialStr = "81.1.12"; + var content = random.getRandomString(contentLength, specialStr); + + async.series([ + function(cb) { + insertIntoClobTable1(id, content, cb); + }, + function(cb) { + checkInsertResult(id, content, specialStr, cb); + } + ], done); + }); // 81.1.12 + + it('81.1.13 works with String length (64K + 1)', function(done) { + var id = insertID++; + var contentLength = 65537; + var specialStr = "81.1.13"; + var content = random.getRandomString(contentLength, specialStr); + + async.series([ + function(cb) { + insertIntoClobTable1(id, content, cb); + }, + function(cb) { + checkInsertResult(id, content, specialStr, cb); + } + ], done); + }); // 81.1.13 + + it('81.1.14 works with String length (1MB + 1)', function(done) { + var id = insertID++; + var contentLength = 1048577; // 1 * 1024 * 1024 + 1; + var specialStr = "81.1.14"; + var content = random.getRandomString(contentLength, specialStr); + + async.series([ + function(cb) { + insertIntoClobTable1(id, content, cb); + }, + function(cb) { + checkInsertResult(id, content, specialStr, cb); + } + ], done); + }); // 81.1.14 + + it('81.1.15 bind value and type mismatch', function(done) { + var id = insertID++; + var content = 100; + + connection.execute( + "INSERT INTO nodb_dml_clob_1 VALUES (:ID, :C)", + { + ID : { val : id }, + C : { val : content, dir : oracledb.BIND_IN, type : oracledb.STRING } + }, + function(err) { + should.exist(err); + // NJS-011: encountered bind value and type mismatch in parameter 2 + (err.message).should.startWith('NJS-011:'); + done(); + } + ); + }); // 81.1.15 + + it('81.1.16 mixing named with positional binding', function(done) { + var id = insertID++; + var contentLength = 40000; + var specialStr = "81.1.16"; + var content = random.getRandomString(contentLength, specialStr); + + async.series([ + function(cb) { + connection.execute( + "INSERT INTO nodb_dml_clob_1 VALUES (:1, :2)", + [ + id, { val : content, dir : oracledb.BIND_IN, type : oracledb.STRING } + ], + function(err, result) { + should.not.exist(err); + should.strictEqual(result.rowsAffected, 1); + cb(); + } + ); + }, + function(cb) { + checkInsertResult(id, content, specialStr, cb); + } + ], done); + }); // 81.1.16 + + it('81.1.17 bind with invalid CLOB', function(done) { + var id = insertID++; + + connection.execute( + "INSERT INTO nodb_dml_clob_1 VALUES (:1, :2)", + [ + id, { val : {}, dir : oracledb.BIND_IN, type : oracledb.STRING } + ], + function(err) { + should.exist(err); + // NJS-011: encountered bind value and type mismatch + (err.message).should.startWith('NJS-011:'); + done(); + } + ); + }); // 81.1.17 + + it('81.1.18 RETURNING INTO with bind type STRING', function(done) { + var id = insertID++; + var contentLength = 400; + var specialStr = "81.1.18"; + var content = random.getRandomString(contentLength, specialStr); + var sql = "INSERT INTO nodb_dml_clob_1 (id, clob) VALUES (:i, :c) RETURNING clob INTO :lobbv"; + + async.series([ + function(cb) { + connection.execute( + sql, + { + i: id, + c: { val: content, type: oracledb.STRING, dir: oracledb.BIND_IN }, + lobbv: { type: oracledb.STRING, dir: oracledb.BIND_OUT, maxSize: contentLength } + }, + { autoCommit: false }, + function(err, result) { + should.not.exist(err); + (result.rowsAffected).should.be.exactly(1); + (result.outBinds.lobbv.length).should.be.exactly(1); + cb(); + } + ); + }, + function(cb) { + checkInsertResult(id, content, specialStr, cb); + } + ], done); + }); // 81.1.18 + + it('81.1.19 Negative: RETURNING INTO with autocommit on', function(done) { + var id = insertID++; + var sql = "INSERT INTO nodb_dml_clob_1 (id, clob) VALUES (:i, EMPTY_CLOB()) RETURNING clob INTO :lobbv"; + var inFileName = './test/clobexample.txt'; + + connection.execute( + sql, + { + i: id, + lobbv: { type: oracledb.CLOB, dir: oracledb.BIND_OUT } + }, + { autoCommit: true }, + function(err, result) { + should.not.exist(err); + var inStream = fs.createReadStream(inFileName); + var lob = result.outBinds.lobbv[0]; + + lob.on('error', function(err) { + should.exist(err); + // ORA-22990: LOB locators cannot span transactions + (err.message).should.startWith('ORA-22990:'); + }); + + inStream.on('error', function(err) { + should.not.exist(err, "inStream.on 'error' event"); + }); + + lob.on('close', function(err) { + should.not.exist(err); + done(); + }); + + inStream.pipe(lob); // copies the text to the CLOB + } + ); + }); // 81.1.19 + + it('81.1.20 works with bind in maxSize smaller than string length', function(done) { + var id = insertID++; + var contentLength = 32768; + var specialStr = "81.1.20"; + var content = random.getRandomString(contentLength, specialStr); + + async.series([ + function(cb) { + connection.execute( + "INSERT INTO nodb_dml_clob_1 VALUES (:ID, :C)", + { + ID : { val : id }, + C : { val : content, dir : oracledb.BIND_IN, type : oracledb.STRING, maxSize: 1 } + }, + function(err, result) { + should.not.exist(err); + should.strictEqual(result.rowsAffected, 1); + cb(); + } + ); + }, + function(cb) { + checkInsertResult(id, content, specialStr, cb); + } + ], done); + }); // 81.1.20 + + }); // 81.1 + + describe('81.2 CLOB, UPDATE', function() { + insertID = 0; + + before(function(done) { + executeSQL(proc_clob_1, done); + }); // before + + after(function(done) { + executeSQL(sql2DropTable1, done); + }); // after + + it('81.2.1 update EMPTY_CLOB column', function(done) { + var id = insertID++; + var content_1 = "EMPTY_CLOB"; + var contentLength_2 = 32768; + var specialStr_2 = "81.2.1"; + var content_2 = random.getRandomString(contentLength_2, specialStr_2); + + async.series([ + function(cb) { + insertIntoClobTable1(id, content_1, cb); + }, + function(cb) { + checkInsertResult(id, content_1, null, cb); + }, + function(cb) { + updateClobTable1(id, content_2, cb); + }, + function(cb) { + checkInsertResult(id, content_2, specialStr_2, cb); + } + ], done); + }); // 81.2.1 + + it('81.2.2 update a cloumn with EMPTY_CLOB', function(done) { + var id = insertID++; + var contentLength_1 = 50000; + var specialStr_1 = "81.2.2"; + var content_1 = random.getRandomString(contentLength_1, specialStr_1); + var content_2 = "EMPTY_CLOB"; + + async.series([ + function(cb) { + insertIntoClobTable1(id, content_1, cb); + }, + function(cb) { + checkInsertResult(id, content_1, specialStr_1, cb); + }, + function(cb) { + updateClobTable1(id, content_2, cb); + }, + function(cb) { + checkInsertResult(id, content_2, null, cb); + } + ], done); + }); // 81.2.2 + + it('81.2.3 update EMPTY_CLOB column with empty string', function(done) { + var id = insertID++; + var content_1 = "EMPTY_CLOB"; + var content_2 = ""; + + async.series([ + function(cb) { + insertIntoClobTable1(id, content_1, cb); + }, + function(cb) { + checkInsertResult(id, content_1, null, cb); + }, + function(cb) { + updateClobTable1(id, content_2, cb); + }, + function(cb) { + checkInsertResult(id, content_2, null, cb); + } + ], done); + }); // 81.2.3 + + it('81.2.4 update empty string column', function(done) { + var id = insertID++; + var content_1 = ""; + var contentLength_2 = 54321; + var specialStr_2 = "81.2.4"; + var content_2 = random.getRandomString(contentLength_2, specialStr_2); + + async.series([ + function(cb) { + insertIntoClobTable1(id, content_1, cb); + }, + function(cb) { + checkInsertResult(id, content_1, null, cb); + }, + function(cb) { + updateClobTable1(id, content_2, cb); + }, + function(cb) { + checkInsertResult(id, content_2, specialStr_2, cb); + } + ], done); + }); // 81.2.4 + + it('81.2.5 update a column with empty string', function(done) { + var id = insertID++; + var contentLength_1 = 50000; + var specialStr_1 = "81.2.2"; + var content_1 = random.getRandomString(contentLength_1, specialStr_1); + var content_2 = ""; + + async.series([ + function(cb) { + insertIntoClobTable1(id, content_1, cb); + }, + function(cb) { + checkInsertResult(id, content_1, specialStr_1, cb); + }, + function(cb) { + updateClobTable1(id, content_2, cb); + }, + function(cb) { + checkInsertResult(id, content_2, null, cb); + } + ], done); + }); // 81.2.5 + + }); // 81.2 +}); diff --git a/test/clobPlsqlBindAsString_bindin.js b/test/clobPlsqlBindAsString_bindin.js new file mode 100644 index 00000000..7176c037 --- /dev/null +++ b/test/clobPlsqlBindAsString_bindin.js @@ -0,0 +1,1594 @@ +/* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with the Apache + * License, Version 2.0 (the "License.") + * + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + * The node-oracledb test suite uses 'mocha', 'should' and 'async'. + * See LICENSE.md for relevant licenses. + * + * NAME + * 74. clobPlsqlBindAsString_bindin.js + * + * DESCRIPTION + * Testing CLOB binding in as String. + * + * NUMBERING RULElist + * Test numbers follow this numbering rule: + * 1 - 20 are reserved for basic functional tests + * 21 - 50 are reserved for data type supporting tests + * 51 onwards are for other tests + * + *****************************************************************************/ +'use strict'; + +var oracledb = require('oracledb'); +var should = require('should'); +var async = require('async'); +var dbConfig = require('./dbconfig.js'); +var fs = require('fs'); +var random = require('./random.js'); + +describe('74. clobPlsqlBindAsString_bindin.js', function() { + this.timeout(100000); + + var connection = null; + var insertID = 1; // assume id for insert into db starts from 1 + var proc_clob_in_tab = "BEGIN \n" + + " DECLARE \n" + + " e_table_missing EXCEPTION; \n" + + " PRAGMA EXCEPTION_INIT(e_table_missing, -00942); \n" + + " BEGIN \n" + + " EXECUTE IMMEDIATE('DROP TABLE nodb_tab_clob_in PURGE'); \n" + + " EXCEPTION \n" + + " WHEN e_table_missing \n" + + " THEN NULL; \n" + + " END; \n" + + " EXECUTE IMMEDIATE (' \n" + + " CREATE TABLE nodb_tab_clob_in ( \n" + + " id NUMBER, \n" + + " clob_1 CLOB, \n" + + " clob_2 CLOB \n" + + " ) \n" + + " '); \n" + + "END; "; + + var proc_lobs_in_tab = "BEGIN \n" + + " DECLARE \n" + + " e_table_missing EXCEPTION; \n" + + " PRAGMA EXCEPTION_INIT(e_table_missing, -00942); \n" + + " BEGIN \n" + + " EXECUTE IMMEDIATE('DROP TABLE nodb_tab_lobs_in PURGE'); \n" + + " EXCEPTION \n" + + " WHEN e_table_missing \n" + + " THEN NULL; \n" + + " END; \n" + + " EXECUTE IMMEDIATE (' \n" + + " CREATE TABLE nodb_tab_lobs_in ( \n" + + " id NUMBER, \n" + + " clob CLOB \n" + + " ) \n" + + " '); \n" + + "END; "; + + before(function(done) { + async.series([ + function(cb) { + oracledb.getConnection(dbConfig, function(err, conn) { + should.not.exist(err); + connection = conn; + cb(); + }); + }, + function(cb) { + setupAllTable(cb); + } + ], done); + + }); // before + + after(function(done) { + async.series([ + function(cb) { + dropAllTable(cb); + }, + function(cb) { + connection.release(function(err) { + should.not.exist(err); + cb(); + }); + } + ], done); + + }); // after + + var setupAllTable = function(callback) { + async.series([ + function(cb) { + connection.execute( + proc_clob_in_tab, + function(err) { + should.not.exist(err); + cb(); + }); + }, + function(cb) { + connection.execute( + proc_lobs_in_tab, + function(err) { + should.not.exist(err); + cb(); + }); + } + ], callback); + }; + + var dropAllTable = function(callback) { + async.series([ + function(cb) { + connection.execute( + "DROP TABLE nodb_tab_clob_in PURGE", + function(err) { + should.not.exist(err); + cb(); + }); + }, + function(cb) { + connection.execute( + "DROP TABLE nodb_tab_lobs_in PURGE", + function(err) { + should.not.exist(err); + cb(); + }); + } + ], callback); + }; + + var executeSQL = function(sql, callback) { + connection.execute( + sql, + function(err) { + should.not.exist(err); + return callback(); + } + ); + }; + + var inFileName = './test/clobexample.txt'; + + var prepareTableWithClob = function(sql, id, callback) { + var bindVar = { i: id, lobbv: { type: oracledb.CLOB, dir: oracledb.BIND_OUT } }; + + connection.execute( + sql, + bindVar, + { autoCommit: false }, // a transaction needs to span the INSERT and pipe() + function(err, result) { + should.not.exist(err); + (result.rowsAffected).should.be.exactly(1); + (result.outBinds.lobbv.length).should.be.exactly(1); + + var inStream = fs.createReadStream(inFileName); + var lob = result.outBinds.lobbv[0]; + + lob.on('error', function(err) { + should.not.exist(err, "lob.on 'error' event"); + }); + + inStream.on('error', function(err) { + should.not.exist(err, "inStream.on 'error' event"); + }); + + lob.on('close', function() { + connection.commit( function(err) { + should.not.exist(err); + return callback(); + }); + }); + + inStream.pipe(lob); // copies the text to the CLOB + } + ); + }; + + var verifyClobValueWithFileData = function(selectSql, callback) { + connection.execute( + selectSql, + function(err, result) { + should.not.exist(err); + var lob = result.rows[0][0]; + should.exist(lob); + // set the encoding so we get a 'string' not a 'buffer' + lob.setEncoding('utf8'); + var clobData = ''; + + lob.on('data', function(chunk) { + clobData += chunk; + }); + + lob.on('error', function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + lob.on('end', function() { + fs.readFile( inFileName, { encoding: 'utf8' }, function(err, originalData) { + should.not.exist(err); + should.strictEqual(clobData, originalData); + return callback(); + }); + }); + } + ); + }; + + // check the plsql bind in value + var compareBindInResult = function(selectSql, originalString, specialStr, callback) { + verifyClobValueWithString(selectSql, originalString, specialStr, callback); + }; + + // compare the selected value from DB with the inserted string + var verifyClobValueWithString = function(selectSql, originalString, specialStr, callback) { + connection.execute( + selectSql, + function(err, result) { + should.not.exist(err); + var lob = result.rows[0][0]; + + if (originalString == null || originalString == undefined) { + should.not.exist(lob); + return callback(); + } else { + should.exist(lob); + // set the encoding so we get a 'string' not a 'buffer' + lob.setEncoding('utf8'); + var clobData = ''; + + lob.on('data', function(chunk) { + clobData += chunk; + }); + + lob.on('error', function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + lob.on('end', function() { + if(originalString == "") { + should.strictEqual(clobData, ""); + callback(); + } else { + compareResultStrAndOriginal(clobData, originalString, specialStr, callback); + } + }); + } + } + ); + }; + + // compare the result string with the original inserted string + var compareResultStrAndOriginal = function(resultVal, originalStr, specialStr, callback) { + var resultLength = resultVal.length; + var specStrLength = specialStr.length; + should.strictEqual(resultLength, originalStr.length); + should.strictEqual(resultVal.substring(0, specStrLength), specialStr); + should.strictEqual(resultVal.substring(resultLength - specStrLength, resultLength), specialStr); + callback(); + }; + + // execute the bind in plsql procedure + var plsqlBindIn = function(sqlRun, bindVar, option, callback) { + connection.execute( + sqlRun, + bindVar, + option, + function(err) { + should.not.exist(err); + callback(); + }); + }; + + describe('74.1 CLOB, PLSQL, BIND_IN', function() { + var proc = "CREATE OR REPLACE PROCEDURE nodb_clobs_in_741 (clob_id IN NUMBER, clob_in IN CLOB)\n" + + "AS \n" + + "BEGIN \n" + + " insert into nodb_tab_clob_in (id, clob_1) values (clob_id, clob_in); \n" + + "END nodb_clobs_in_741; "; + var sqlRun = "BEGIN nodb_clobs_in_741 (:i, :c); END;"; + var proc_drop = "DROP PROCEDURE nodb_clobs_in_741"; + var proc_7411 = "CREATE OR REPLACE PROCEDURE nodb_clobs_in_7411 (clob_id IN NUMBER, clob_in IN CLOB)\n" + + "AS \n" + + "BEGIN \n" + + " insert into nodb_tab_clob_in (id, clob_1) values (clob_id, EMPTY_CLOB()); \n" + + "END nodb_clobs_in_7411; "; + var sqlRun_7411 = "BEGIN nodb_clobs_in_7411 (:i, :c); END;"; + var proc_drop_7411 = "DROP PROCEDURE nodb_clobs_in_7411"; + + before(function(done) { + executeSQL(proc, done); + }); // before + + after(function(done) { + executeSQL(proc_drop, done); + }); // after + + it('74.1.1 works with EMPTY_CLOB', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { type: oracledb.STRING, dir: oracledb.BIND_IN } + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + executeSQL(proc_7411, cb); + }, + function(cb) { + plsqlBindIn(sqlRun_7411, bindVar, option, cb); + }, + function(cb) { + var sql = "select clob_1 from nodb_tab_clob_in where id = " + sequence; + compareBindInResult(sql, "", null, cb); + }, + function(cb) { + executeSQL(proc_drop_7411, cb); + } + ], done); + }); // 74.1.1 + + it('74.1.2 works with EMPTY_CLOB and bind in maxSize set to 1', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { type: oracledb.STRING, dir: oracledb.BIND_IN, maxSize: 1 } + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + executeSQL(proc_7411, cb); + }, + function(cb) { + plsqlBindIn(sqlRun_7411, bindVar, option, cb); + }, + function(cb) { + var sql = "select clob_1 from nodb_tab_clob_in where id = " + sequence; + compareBindInResult(sql, "", null, cb); + }, + function(cb) { + executeSQL(proc_drop_7411, cb); + } + ], done); + }); // 74.1.2 + + it('74.1.3 works with EMPTY_CLOB and bind in maxSize set to (64K - 1)', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { type: oracledb.STRING, dir: oracledb.BIND_IN, maxSize: 65535 } + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + executeSQL(proc_7411, cb); + }, + function(cb) { + plsqlBindIn(sqlRun_7411, bindVar, option, cb); + }, + function(cb) { + var sql = "select clob_1 from nodb_tab_clob_in where id = " + sequence; + compareBindInResult(sql, "", null, cb); + }, + function(cb) { + executeSQL(proc_drop_7411, cb); + } + ], done); + }); // 74.1.3 + + it('74.1.4 works with null', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { val: null, type: oracledb.STRING, dir: oracledb.BIND_IN } + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + plsqlBindIn(sqlRun, bindVar, option, cb); + }, + function(cb) { + var sql = "select clob_1 from nodb_tab_clob_in where id = " + sequence; + compareBindInResult(sql, null, null, cb); + } + ], done); + }); // 74.1.4 + + it('74.1.5 works with null and bind in maxSize set to 1', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { val: null, type: oracledb.STRING, dir: oracledb.BIND_IN, maxSize: 1 } + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + plsqlBindIn(sqlRun, bindVar, option, cb); + }, + function(cb) { + var sql = "select clob_1 from nodb_tab_clob_in where id = " + sequence; + compareBindInResult(sql, null, null, cb); + } + ], done); + }); // 74.1.5 + + it('74.1.6 works with null and bind in maxSize set to (64K - 1)', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { val: null, type: oracledb.STRING, dir: oracledb.BIND_IN, maxSize: 65535 } + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + plsqlBindIn(sqlRun, bindVar, option, cb); + }, + function(cb) { + var sql = "select clob_1 from nodb_tab_clob_in where id = " + sequence; + compareBindInResult(sql, null, null, cb); + } + ], done); + }); // 74.1.6 + + it('74.1.7 works with empty string', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { val: '', type: oracledb.STRING, dir: oracledb.BIND_IN} + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + plsqlBindIn(sqlRun, bindVar, option, cb); + }, + function(cb) { + var sql = "select clob_1 from nodb_tab_clob_in where id = " + sequence; + compareBindInResult(sql, null, null, cb); + } + ], done); + }); // 74.1.7 + + it('74.1.8 works with empty string and bind in maxSize set to 1', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { val: '', type: oracledb.STRING, dir: oracledb.BIND_IN, maxSize: 1} + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + plsqlBindIn(sqlRun, bindVar, option, cb); + }, + function(cb) { + var sql = "select clob_1 from nodb_tab_clob_in where id = " + sequence; + compareBindInResult(sql, null, null, cb); + } + ], done); + }); // 74.1.8 + + it('74.1.9 works with empty string and bind in maxSize set to (64K - 1)', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { val: '', type: oracledb.STRING, dir: oracledb.BIND_IN, maxSize: 65535} + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + plsqlBindIn(sqlRun, bindVar, option, cb); + }, + function(cb) { + var sql = "select clob_1 from nodb_tab_clob_in where id = " + sequence; + compareBindInResult(sql, null, null, cb); + } + ], done); + }); // 74.1.9 + + it('74.1.10 works with undefined', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { val: undefined, type: oracledb.STRING, dir: oracledb.BIND_IN, maxSize: 50000 } + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + plsqlBindIn(sqlRun, bindVar, option, cb); + }, + function(cb) { + var sql = "select clob_1 from nodb_tab_clob_in where id = " + sequence; + compareBindInResult(sql, null, null, cb); + } + ], done); + }); // 74.1.10 + + it('74.1.11 works with undefined and bind in maxSize set to 1', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { val: undefined, type: oracledb.STRING, dir: oracledb.BIND_IN, maxSize: 1 } + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + plsqlBindIn(sqlRun, bindVar, option, cb); + }, + function(cb) { + var sql = "select clob_1 from nodb_tab_clob_in where id = " + sequence; + compareBindInResult(sql, null, null, cb); + } + ], done); + }); // 74.1.11 + + it('74.1.12 works with undefined and bind in maxSize set to (64K - 1)', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { val: undefined, type: oracledb.STRING, dir: oracledb.BIND_IN, maxSize: 65535 } + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + plsqlBindIn(sqlRun, bindVar, option, cb); + }, + function(cb) { + var sql = "select clob_1 from nodb_tab_clob_in where id = " + sequence; + compareBindInResult(sql, null, null, cb); + } + ], done); + }); // 74.1.12 + + it('74.1.13 works with NaN', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { val: NaN, type: oracledb.STRING, dir: oracledb.BIND_IN, maxSize: 50000 } + }; + + connection.execute( + sqlRun, + bindVar, + { autoCommit: true }, + function(err) { + should.exist(err); + // NJS-011: encountered bind value and type mismatch in parameter 2 + (err.message).should.startWith('NJS-011:'); + done(); + } + ); + }); // 74.1.13 + + it('74.1.14 works with 0', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { val: 0, type: oracledb.STRING, dir: oracledb.BIND_IN, maxSize: 50000 } + }; + + connection.execute( + sqlRun, + bindVar, + { autoCommit: true }, + function(err) { + should.exist(err); + // NJS-011: encountered bind value and type mismatch in parameter 2 + (err.message).should.startWith('NJS-011:'); + done(); + } + ); + }); // 74.1.14 + + it('74.1.15 works with String length 32K', function(done) { + // Driver already supports CLOB AS STRING and BLOB AS BUFFER for PLSQL BIND if the data size less than or equal to 32767. + // As part of this enhancement, driver allows even if data size more than 32767 for both column types + var len = 32768; + var sequence = insertID++; + var specialStr = "74.1.15"; + var clobStr = random.getRandomString(len, specialStr); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { val: clobStr, type: oracledb.STRING, dir: oracledb.BIND_IN, maxSize: len } + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + plsqlBindIn(sqlRun, bindVar, option, cb); + }, + function(cb) { + var sql = "select clob_1 from nodb_tab_clob_in where id = " + sequence; + compareBindInResult(sql, clobStr, specialStr, cb); + } + ], done); + }); // 74.1.15 + + it('74.1.16 works with String length (64K - 1)', function(done) { + // The upper limit on the number of bytes of data that can be bound as + // `STRING` or `BUFFER` when node-oracledb is linked with Oracle Client + // 11.2 libraries is 64 Kb. With Oracle Client 12, the limit is 1 Gb + + var len = 65535; + var sequence = insertID++; + var specialStr = "74.1.16"; + var clobStr = random.getRandomString(len, specialStr); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { val: clobStr, type: oracledb.STRING, dir: oracledb.BIND_IN, maxSize: len } + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + plsqlBindIn(sqlRun, bindVar, option, cb); + }, + function(cb) { + var sql = "select clob_1 from nodb_tab_clob_in where id = " + sequence; + compareBindInResult(sql, clobStr, specialStr, cb); + } + ], done); + }); // 74.1.16 + + it('74.1.17 works with String length (64K + 1)', function(done) { + var len = 65537; + var sequence = insertID++; + var specialStr = "74.1.17"; + var clobStr = random.getRandomString(len, specialStr); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { val: clobStr, type: oracledb.STRING, dir: oracledb.BIND_IN, maxSize: len } + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + plsqlBindIn(sqlRun, bindVar, option, cb); + }, + function(cb) { + var sql = "select clob_1 from nodb_tab_clob_in where id = " + sequence; + compareBindInResult(sql, clobStr, specialStr, cb); + } + ], done); + }); // 74.1.17 + + it('74.1.18 works with String length (1MB + 1)', function(done) { + var len = 1048577; // 1 * 1024 * 1024 + 1 + var sequence = insertID++; + var specialStr = "74.1.18"; + var clobStr = random.getRandomString(len, specialStr); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { val: clobStr, type: oracledb.STRING, dir: oracledb.BIND_IN, maxSize: len } + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + plsqlBindIn(sqlRun, bindVar, option, cb); + }, + function(cb) { + var sql = "select clob_1 from nodb_tab_clob_in where id = " + sequence; + compareBindInResult(sql, clobStr, specialStr, cb); + } + ], done); + }); // 74.1.18 + + it('74.1.19 works with bind value and type mismatch', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { val: 20, type: oracledb.STRING, dir: oracledb.BIND_IN, maxSize: 50000 } + }; + + connection.execute( + sqlRun, + bindVar, + { autoCommit: true }, + function(err) { + should.exist(err); + // NJS-011: encountered bind value and type mismatch in parameter 2 + (err.message).should.startWith('NJS-011:'); + done(); + } + ); + }); // 74.1.19 + + it('74.1.20 mixing named with positional binding', function(done) { + var sqlRun_7419 = "BEGIN nodb_clobs_in_741 (:1, :2); END;"; + var len = 50000; + var sequence = insertID++; + var specialStr = "74.1.20"; + var clobStr = random.getRandomString(len, specialStr); + var bindVar = [ sequence, { val: clobStr, type: oracledb.STRING, dir: oracledb.BIND_IN, maxSize: 50000 } ]; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + plsqlBindIn(sqlRun_7419, bindVar, option, cb); + }, + function(cb) { + var sql = "select clob_1 from nodb_tab_clob_in where id = " + sequence; + compareBindInResult(sql, clobStr, specialStr, cb); + } + ], done); + }); // 74.1.20 + + it('74.1.21 works with invalid CLOB', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { val: {}, type: oracledb.STRING, dir: oracledb.BIND_IN, maxSize: 5000 } + }; + + connection.execute( + sqlRun, + bindVar, + { autoCommit: true }, + function(err) { + should.exist(err); + // NJS-011: encountered bind value and type mismatch in parameter 2 + (err.message).should.startWith('NJS-011:'); + done(); + } + ); + }); // 74.1.21 + + it('74.1.22 works with bind in maxSize smaller than string length', function(done) { + var len = 50000; + var sequence = insertID++; + var specialStr = "74.1.22"; + var clobStr = random.getRandomString(len, specialStr); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { val: clobStr, type: oracledb.STRING, dir: oracledb.BIND_IN, maxSize: len - 1 } + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + plsqlBindIn(sqlRun, bindVar, option, cb); + }, + function(cb) { + var sql = "select clob_1 from nodb_tab_clob_in where id = " + sequence; + compareBindInResult(sql, clobStr, specialStr, cb); + } + ], done); + }); // 74.1.22 + + it('74.1.23 RETURN with bind type STRING', function(done) { + var proc_74123 = "CREATE OR REPLACE FUNCTION nodb_clobs_in_74123 (clob_id IN NUMBER, clob_in IN CLOB) RETURN VARCHAR2\n" + + "IS \n" + + " strVal VARCHAR2(500); \n" + + "BEGIN \n" + + " insert into nodb_tab_clob_in (id, clob_1) values (clob_id, clob_in); \n" + + " select clob_1 into strVal from nodb_tab_clob_in where id = clob_id; \n" + + " return strVal; \n" + + "END nodb_clobs_in_74123; "; + var sqlRun_74123 = "BEGIN :o := nodb_clobs_in_74123(:i, :c); END;"; + var proc_drop_74123 = "DROP FUNCTION nodb_clobs_in_74123"; + var len = 500; + var sequence = insertID++; + var specialStr = "74.1.23"; + var clobStr = random.getRandomString(len, specialStr); + var bindVar = { + o: { type: oracledb.STRING, dir: oracledb.BIND_OUT, maxSize: len }, + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { val: clobStr, type: oracledb.STRING, dir: oracledb.BIND_IN, maxSize: len } + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + executeSQL(proc_74123, cb); + }, + function(cb) { + connection.execute( + sqlRun_74123, + bindVar, + option, + function(err, result) { + should.not.exist(err); + var resultVal = result.outBinds.o; + compareResultStrAndOriginal(resultVal, clobStr, specialStr, cb); + }); + }, + function(cb) { + executeSQL(proc_drop_74123, cb); + } + ], done); + }); // 74.1.23 + + it('74.1.24 works with UPDATE', function(done) { + var proc_74124 = "CREATE OR REPLACE PROCEDURE nodb_clobs_in_74124 (clob_id IN NUMBER, clob_in IN CLOB, clob_update IN CLOB)\n" + + "AS \n" + + "BEGIN \n" + + " insert into nodb_tab_clob_in (id, clob_1) values (clob_id, clob_in); \n" + + " update nodb_tab_clob_in set clob_1 = clob_update where id = clob_id; \n" + + "END nodb_clobs_in_74124; "; + var sqlRun_74124 = "BEGIN nodb_clobs_in_74124 (:i, :c1, :c2); END;"; + var proc_drop_74124 = "DROP PROCEDURE nodb_clobs_in_74124"; + var sequence = insertID++; + var len_1 = 5000; + var specialStr_1 = "74.1.24_1"; + var clobStr_1 = random.getRandomString(len_1, specialStr_1); + var len_2 = 65535; + var specialStr_2 = "74.1.24_2"; + var clobStr_2 = random.getRandomString(len_2, specialStr_2); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c1: { val: clobStr_1, type: oracledb.STRING, dir: oracledb.BIND_IN, maxSize: len_1 }, + c2: { val: clobStr_2, type: oracledb.STRING, dir: oracledb.BIND_IN, maxSize: len_2 }, + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + executeSQL(proc_74124, cb); + }, + function(cb) { + connection.execute( + sqlRun_74124, + bindVar, + option, + function(err) { + should.not.exist(err); + cb(); + }); + }, + function(cb) { + var sql = "select clob_1 from nodb_tab_clob_in where id = " + sequence; + compareBindInResult(sql, clobStr_2, specialStr_2, cb); + }, + function(cb) { + executeSQL(proc_drop_74124, cb); + } + ], done); + }); // 74.1.24 + + it('74.1.25 bind error: NJS-037, bind by name 1', function(done) { + var bindVar = { + i: { val: ["sequence"], type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { val: "sequence", type: oracledb.STRING, dir: oracledb.BIND_IN, maxSize: 50000 } + }; + connection.execute( + sqlRun, + bindVar, + { autoCommit: true }, + function(err) { + should.exist(err); + // NJS-037: invalid data type at array index 0 for bind ":i" + (err.message).should.startWith('NJS-037:'); + (err.message).should.match(/^NJS-037:.*\sindex\s0\s.*\sbind\s":i"$/); + done(); + } + ); + }); // 74.1.25 + + it('74.1.26 bind error: NJS-037, bind by name 2', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { val: [0], type: oracledb.STRING, dir: oracledb.BIND_IN, maxSize: 50000 } + }; + connection.execute( + sqlRun, + bindVar, + { autoCommit: true }, + function(err) { + should.exist(err); + // NJS-037: invalid data type at array index 0 for bind ":c" + (err.message).should.startWith('NJS-037:'); + (err.message).should.match(/^NJS-037:.*\sindex\s0\s.*\sbind\s":c"$/); + done(); + } + ); + }); // 74.1.26 + + it('74.1.27 bind error: NJS-037, bind by name 3', function(done) { + var bindVar = { + i: { val: [1, "sequence"], type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { val: "sequence", type: oracledb.STRING, dir: oracledb.BIND_IN, maxSize: 50000 } + }; + connection.execute( + sqlRun, + bindVar, + { autoCommit: true }, + function(err) { + should.exist(err); + // NJS-037: invalid data type at array index 1 for bind ":i" + (err.message).should.startWith('NJS-037:'); + (err.message).should.match(/^NJS-037:.*\sindex\s1\s.*\sbind\s":i"$/); + done(); + } + ); + }); // 74.1.27 + + it('74.1.28 bind error: NJS-037, bind by name 4', function(done) { + var bindVar = { + i: { val: [1, 2], type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { val: ["sequence", "ab", 3], type: oracledb.STRING, dir: oracledb.BIND_IN, maxSize: 50000 } + }; + connection.execute( + sqlRun, + bindVar, + { autoCommit: true }, + function(err) { + should.exist(err); + // NJS-037: invalid data type at array index 2 for bind ":c" + (err.message).should.startWith('NJS-037:'); + (err.message).should.match(/^NJS-037:.*\sindex\s2\s.*\sbind\s":c"$/); + done(); + } + ); + }); // 74.1.28 + + it('74.1.29 bind error: NJS-052, bind by pos 1', function(done) { + var sequence = insertID++; + var bindVar = [ sequence, { val: [0], type: oracledb.STRING, dir: oracledb.BIND_IN, maxSize: 50000 } ] ; + connection.execute( + sqlRun, + bindVar, + { autoCommit: true }, + function(err) { + should.exist(err); + // NJS-052: invalid data type at array index 0 for bind position 2 + (err.message).should.startWith('NJS-052:'); + (err.message).should.match(/^NJS-052:.*\sindex\s0\s.*\sposition\s2$/); + done(); + } + ); + }); // 74.1.29 + + it('74.1.30 bind error: NJS-052, bind by pos 2', function(done) { + var bindVar = [ { val: ["sequence"], type: oracledb.NUMBER, dir: oracledb.BIND_IN }, { val: "sequence", type: oracledb.STRING, dir: oracledb.BIND_IN, maxSize: 50000 } ] ; + connection.execute( + sqlRun, + bindVar, + { autoCommit: true }, + function(err) { + should.exist(err); + // NJS-052: invalid data type at array index 0 for bind position 1 + (err.message).should.startWith('NJS-052:'); + (err.message).should.match(/^NJS-052:.*\sindex\s0\s.*\sposition\s1$/); + done(); + } + ); + }); // 74.1.30 + + it('74.1.31 bind error: NJS-052, bind by pos 3', function(done) { + var bindVar = [ { val: [1, 2, "sequence"], type: oracledb.NUMBER, dir: oracledb.BIND_IN }, { val: "sequence", type: oracledb.STRING, dir: oracledb.BIND_IN, maxSize: 50000 } ] ; + connection.execute( + sqlRun, + bindVar, + { autoCommit: true }, + function(err) { + should.exist(err); + // NJS-052: invalid data type at array index 2 for bind position 1 + (err.message).should.startWith('NJS-052:'); + (err.message).should.match(/^NJS-052:.*\sindex\s2\s.*\sposition\s1$/); + done(); + } + ); + }); // 74.1.31 + + it('74.1.32 bind error: NJS-052, bind by pos 4', function(done) { + var bindVar = [ { val: [1, 2], type: oracledb.NUMBER, dir: oracledb.BIND_IN }, { val: ["sequence", 1], type: oracledb.STRING, dir: oracledb.BIND_IN, maxSize: 50000 } ] ; + connection.execute( + sqlRun, + bindVar, + { autoCommit: true }, + function(err) { + should.exist(err); + // NJS-052: invalid data type at array index 1 for bind position 2 + (err.message).should.startWith('NJS-052:'); + (err.message).should.match(/^NJS-052:.*\sindex\s1\s.*\sposition\s2$/); + done(); + } + ); + }); // 74.1.32 + + }); // 74.1 + + describe('74.2 CLOB, PLSQL, BIND_IN to VARCHAR2', function() { + var proc = "CREATE OR REPLACE PROCEDURE nodb_clobs_in_741 (clob_id IN NUMBER, clob_in IN VARCHAR2)\n" + + "AS \n" + + "BEGIN \n" + + " insert into nodb_tab_clob_in (id, clob_1) values (clob_id, clob_in); \n" + + "END nodb_clobs_in_741; "; + var sqlRun = "BEGIN nodb_clobs_in_741 (:i, :c); END;"; + var proc_drop = "DROP PROCEDURE nodb_clobs_in_741"; + var proc_7411 = "CREATE OR REPLACE PROCEDURE nodb_clobs_in_7411 (clob_id IN NUMBER, clob_in IN VARCHAR2)\n" + + "AS \n" + + "BEGIN \n" + + " insert into nodb_tab_clob_in (id, clob_1) values (clob_id, EMPTY_CLOB()); \n" + + "END nodb_clobs_in_7411; "; + var sqlRun_7411 = "BEGIN nodb_clobs_in_7411 (:i, :c); END;"; + var proc_drop_7411 = "DROP PROCEDURE nodb_clobs_in_7411"; + + before(function(done) { + executeSQL(proc, done); + }); // before + + after(function(done) { + executeSQL(proc_drop, done); + }); // after + + it('74.2.1 works with EMPTY_CLOB', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { type: oracledb.STRING, dir: oracledb.BIND_IN } + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + executeSQL(proc_7411, cb); + }, + function(cb) { + plsqlBindIn(sqlRun_7411, bindVar, option, cb); + }, + function(cb) { + var sql = "select clob_1 from nodb_tab_clob_in where id = " + sequence; + compareBindInResult(sql, "", null, cb); + }, + function(cb) { + executeSQL(proc_drop_7411, cb); + } + ], done); + }); // 74.2.1 + + it('74.2.2 works with EMPTY_CLOB and bind in maxSize set to 1', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { type: oracledb.STRING, dir: oracledb.BIND_IN, maxSize: 1 } + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + executeSQL(proc_7411, cb); + }, + function(cb) { + plsqlBindIn(sqlRun_7411, bindVar, option, cb); + }, + function(cb) { + var sql = "select clob_1 from nodb_tab_clob_in where id = " + sequence; + compareBindInResult(sql, "", null, cb); + }, + function(cb) { + executeSQL(proc_drop_7411, cb); + } + ], done); + }); // 74.2.2 + + it('74.2.3 works with EMPTY_CLOB and bind in maxSize set to (64K - 1)', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { type: oracledb.STRING, dir: oracledb.BIND_IN, maxSize: 65535 } + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + executeSQL(proc_7411, cb); + }, + function(cb) { + plsqlBindIn(sqlRun_7411, bindVar, option, cb); + }, + function(cb) { + var sql = "select clob_1 from nodb_tab_clob_in where id = " + sequence; + compareBindInResult(sql, "", null, cb); + }, + function(cb) { + executeSQL(proc_drop_7411, cb); + } + ], done); + }); // 74.2.3 + + it('74.2.4 works with null', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { val: null, type: oracledb.STRING, dir: oracledb.BIND_IN } + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + plsqlBindIn(sqlRun, bindVar, option, cb); + }, + function(cb) { + var sql = "select clob_1 from nodb_tab_clob_in where id = " + sequence; + compareBindInResult(sql, null, null, cb); + } + ], done); + }); // 74.2.4 + + it('74.2.5 works with null and bind in maxSize set to 1', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { val: null, type: oracledb.STRING, dir: oracledb.BIND_IN, maxSize: 1 } + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + plsqlBindIn(sqlRun, bindVar, option, cb); + }, + function(cb) { + var sql = "select clob_1 from nodb_tab_clob_in where id = " + sequence; + compareBindInResult(sql, null, null, cb); + } + ], done); + }); // 74.2.5 + + it('74.2.6 works with null and bind in maxSize set to (64K - 1)', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { val: null, type: oracledb.STRING, dir: oracledb.BIND_IN, maxSize: 65535 } + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + plsqlBindIn(sqlRun, bindVar, option, cb); + }, + function(cb) { + var sql = "select clob_1 from nodb_tab_clob_in where id = " + sequence; + compareBindInResult(sql, null, null, cb); + } + ], done); + }); // 74.2.6 + + it('74.2.7 works with empty string', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { val: '', type: oracledb.STRING, dir: oracledb.BIND_IN} + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + plsqlBindIn(sqlRun, bindVar, option, cb); + }, + function(cb) { + var sql = "select clob_1 from nodb_tab_clob_in where id = " + sequence; + compareBindInResult(sql, null, null, cb); + } + ], done); + }); // 74.2.7 + + it('74.2.8 works with empty string and bind in maxSize set to 1', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { val: '', type: oracledb.STRING, dir: oracledb.BIND_IN, maxSize: 1} + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + plsqlBindIn(sqlRun, bindVar, option, cb); + }, + function(cb) { + var sql = "select clob_1 from nodb_tab_clob_in where id = " + sequence; + compareBindInResult(sql, null, null, cb); + } + ], done); + }); // 74.2.8 + + it('74.2.9 works with empty string and bind in maxSize set to (64K - 1)', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { val: '', type: oracledb.STRING, dir: oracledb.BIND_IN, maxSize: 65535} + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + plsqlBindIn(sqlRun, bindVar, option, cb); + }, + function(cb) { + var sql = "select clob_1 from nodb_tab_clob_in where id = " + sequence; + compareBindInResult(sql, null, null, cb); + } + ], done); + }); // 74.2.9 + + it('74.2.10 works with undefined', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { val: undefined, type: oracledb.STRING, dir: oracledb.BIND_IN, maxSize: 50000 } + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + plsqlBindIn(sqlRun, bindVar, option, cb); + }, + function(cb) { + var sql = "select clob_1 from nodb_tab_clob_in where id = " + sequence; + compareBindInResult(sql, null, null, cb); + } + ], done); + }); // 74.2.10 + + it('74.2.11 works with undefined and bind in maxSize set to 1', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { val: undefined, type: oracledb.STRING, dir: oracledb.BIND_IN, maxSize: 1 } + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + plsqlBindIn(sqlRun, bindVar, option, cb); + }, + function(cb) { + var sql = "select clob_1 from nodb_tab_clob_in where id = " + sequence; + compareBindInResult(sql, null, null, cb); + } + ], done); + }); // 74.2.11 + + it('74.2.12 works with undefined and bind in maxSize set to (64K - 1)', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { val: undefined, type: oracledb.STRING, dir: oracledb.BIND_IN, maxSize: 65535 } + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + plsqlBindIn(sqlRun, bindVar, option, cb); + }, + function(cb) { + var sql = "select clob_1 from nodb_tab_clob_in where id = " + sequence; + compareBindInResult(sql, null, null, cb); + } + ], done); + }); // 74.2.12 + + it('74.2.13 works with NaN', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { val: NaN, type: oracledb.STRING, dir: oracledb.BIND_IN, maxSize: 50000 } + }; + + connection.execute( + sqlRun, + bindVar, + { autoCommit: true }, + function(err) { + should.exist(err); + // NJS-011: encountered bind value and type mismatch in parameter 2 + (err.message).should.startWith('NJS-011:'); + done(); + } + ); + }); // 74.2.13 + + it('74.2.14 works with 0', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { val: 0, type: oracledb.STRING, dir: oracledb.BIND_IN, maxSize: 50000 } + }; + + connection.execute( + sqlRun, + bindVar, + { autoCommit: true }, + function(err) { + should.exist(err); + // NJS-011: encountered bind value and type mismatch in parameter 2 + (err.message).should.startWith('NJS-011:'); + done(); + } + ); + }); // 74.2.14 + + it('74.2.15 works with String length (32K - 1)', function(done) { + var len = 32767; + var sequence = insertID++; + var specialStr = "74.2.15"; + var clobStr = random.getRandomString(len, specialStr); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { val: clobStr, type: oracledb.STRING, dir: oracledb.BIND_IN, maxSize: len } + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + plsqlBindIn(sqlRun, bindVar, option, cb); + }, + function(cb) { + var sql = "select clob_1 from nodb_tab_clob_in where id = " + sequence; + compareBindInResult(sql, clobStr, specialStr, cb); + } + ], done); + }); // 74.2.15 + + it('74.2.16 works with String length 32K', function(done) { + var len = 32768; + var sequence = insertID++; + var specialStr = "74.2.16"; + var clobStr = random.getRandomString(len, specialStr); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { val: clobStr, type: oracledb.STRING, dir: oracledb.BIND_IN, maxSize: len } + }; + var option = { autoCommit: true }; + + connection.execute( + sqlRun, + bindVar, + option, + function(err) { + should.exist(err); + // ORA-06502: PL/SQL: numeric or value error + (err.message).should.startWith('ORA-06502:'); + done(); + } + ); + }); // 74.2.16 + + it('74.2.17 works with invalid CLOB', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { val: {}, type: oracledb.STRING, dir: oracledb.BIND_IN, maxSize: 5000 } + }; + + connection.execute( + sqlRun, + bindVar, + { autoCommit: true }, + function(err) { + should.exist(err); + // NJS-011: encountered bind value and type mismatch + (err.message).should.startWith('NJS-011:'); + done(); + } + ); + }); // 74.2.17 + + it('74.2.18 works with bind in maxSize smaller than string length', function(done) { + var len = 500; + var sequence = insertID++; + var specialStr = "74.2.18"; + var clobStr = random.getRandomString(len, specialStr); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { val: clobStr, type: oracledb.STRING, dir: oracledb.BIND_IN, maxSize: len - 1 } + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + plsqlBindIn(sqlRun, bindVar, option, cb); + }, + function(cb) { + var sql = "select clob_1 from nodb_tab_clob_in where id = " + sequence; + compareBindInResult(sql, clobStr, specialStr, cb); + } + ], done); + }); // 74.2.18 + + it('74.2.19 works with UPDATE', function(done) { + var proc_74219 = "CREATE OR REPLACE PROCEDURE nodb_clobs_in_74219 (clob_id IN NUMBER, clob_in IN VARCHAR2, clob_update IN VARCHAR2)\n" + + "AS \n" + + "BEGIN \n" + + " insert into nodb_tab_clob_in (id, clob_1) values (clob_id, clob_in); \n" + + " update nodb_tab_clob_in set clob_1 = clob_update where id = clob_id; \n" + + "END nodb_clobs_in_74219; "; + var sqlRun_74219 = "BEGIN nodb_clobs_in_74219 (:i, :c1, :c2); END;"; + var proc_drop_74219 = "DROP PROCEDURE nodb_clobs_in_74219"; + var sequence = insertID++; + var len_1 = 3000; + var specialStr_1 = "74.2.19_1"; + var clobStr_1 = random.getRandomString(len_1, specialStr_1); + var len_2 = 2000; + var specialStr_2 = "74.2.19_2"; + var clobStr_2 = random.getRandomString(len_2, specialStr_2); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c1: { val: clobStr_1, type: oracledb.STRING, dir: oracledb.BIND_IN, maxSize: len_1 }, + c2: { val: clobStr_2, type: oracledb.STRING, dir: oracledb.BIND_IN, maxSize: len_2 }, + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + executeSQL(proc_74219, cb); + }, + function(cb) { + connection.execute( + sqlRun_74219, + bindVar, + option, + function(err) { + should.not.exist(err); + cb(); + }); + }, + function(cb) { + var sql = "select clob_1 from nodb_tab_clob_in where id = " + sequence; + compareBindInResult(sql, clobStr_2, specialStr_2, cb); + }, + function(cb) { + executeSQL(proc_drop_74219, cb); + } + ], done); + }); // 74.2.19 + + }); // 74.2 + + describe('74.3 Multiple CLOBs, BIND_IN', function() { + var proc = "CREATE OR REPLACE PROCEDURE nodb_lobs_in_742 (clob_id IN NUMBER, clob_1 IN CLOB, clob_2 IN CLOB)\n" + + "AS \n" + + "BEGIN \n" + + " insert into nodb_tab_clob_in (id, clob_1, clob_2) values (clob_id, clob_1, clob_2); \n" + + "END nodb_lobs_in_742; "; + var sqlRun = "BEGIN nodb_lobs_in_742 (:i, :c1, :c2); END;"; + var proc_drop = "DROP PROCEDURE nodb_lobs_in_742"; + + before(function(done) { + executeSQL(proc, done); + }); // before + + after(function(done) { + executeSQL(proc_drop, done); + }); // after + + it('74.3.1 bind two string', function(done) { + var sequence = insertID++; + var len_1 = 50000; + var specialStr_1 = "74.3.1_1"; + var clobStr_1 = random.getRandomString(len_1, specialStr_1); + var len_2 = 10000; + var specialStr_2 = "74.3.1_2"; + var clobStr_2 = random.getRandomString(len_2, specialStr_2); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c1: { val: clobStr_1, type: oracledb.STRING, dir: oracledb.BIND_IN, maxSize: len_1 }, + c2: { val: clobStr_2, type: oracledb.STRING, dir: oracledb.BIND_IN, maxSize: len_2 } + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + plsqlBindIn(sqlRun, bindVar, option, cb); + }, + function(cb) { + var sql_1 = "select clob_1 from nodb_tab_clob_in where id = " + sequence; + compareBindInResult(sql_1, clobStr_1, specialStr_1, cb); + }, + function(cb) { + var sql_2 = "select clob_2 from nodb_tab_clob_in where id = " + sequence; + compareBindInResult(sql_2, clobStr_2, specialStr_2, cb); + } + ], done); + }); // 74.3.1 + + it('74.3.2 bind a txt file and a string', function(done) { + var preparedCLOBID = 200; + var len_1 = 50000; + var specialStr_1 = "74.3.2"; + var clobStr_1 = random.getRandomString(len_1, specialStr_1); + var sequence = insertID++; + + async.series([ + function(cb) { + var sql = "INSERT INTO nodb_tab_lobs_in (id, clob) VALUES (:i, EMPTY_CLOB()) RETURNING clob INTO :lobbv"; + prepareTableWithClob(sql, preparedCLOBID, cb); + }, + function(cb) { + connection.execute( + "select clob from nodb_tab_lobs_in where id = :id", + { id: preparedCLOBID }, + function(err, result) { + should.not.exist(err); + (result.rows.length).should.not.eql(0); + + var clob = result.rows[0][0]; + connection.execute( + sqlRun, + { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c1: { val: clobStr_1, type: oracledb.STRING, dir: oracledb.BIND_IN, maxSize: len_1 }, + c2: { val: clob, type: oracledb.CLOB, dir: oracledb.BIND_IN } + }, + { autoCommit: true }, + function(err) { + should.not.exist(err); + cb(); + } + ); + } + ); + }, + function(cb) { + var sql_1 = "select clob_1 from nodb_tab_clob_in where id = " + sequence; + compareBindInResult(sql_1, clobStr_1, specialStr_1, cb); + }, + function(cb) { + var sql_2 = "select clob_2 from nodb_tab_clob_in where id = " + sequence; + verifyClobValueWithFileData(sql_2, cb); + } + ], done); + }); // 74.3.2 + + it('74.3.3 bind two string, one > (64K - 1)', function(done) { + var sequence = insertID++; + var len_1 = 65538; + var specialStr_1 = "74.3.3_1"; + var clobStr_1 = random.getRandomString(len_1, specialStr_1); + var len_2 = 10000; + var specialStr_2 = "74.3.3_2"; + var clobStr_2 = random.getRandomString(len_2, specialStr_2); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c1: { val: clobStr_1, type: oracledb.STRING, dir: oracledb.BIND_IN, maxSize: len_1 }, + c2: { val: clobStr_2, type: oracledb.STRING, dir: oracledb.BIND_IN, maxSize: len_2 } + }; + var option = { autoCommit: true }; + + async.series([ + function(cb) { + plsqlBindIn(sqlRun, bindVar, option, cb); + }, + function(cb) { + var sql_1 = "select clob_1 from nodb_tab_clob_in where id = " + sequence; + compareBindInResult(sql_1, clobStr_1, specialStr_1, cb); + }, + function(cb) { + var sql_2 = "select clob_2 from nodb_tab_clob_in where id = " + sequence; + compareBindInResult(sql_2, clobStr_2, specialStr_2, cb); + } + ], done); + }); // 74.3.3 + + }); // 74.3 + +}); // 74 diff --git a/test/clobPlsqlBindAsString_bindinout.js b/test/clobPlsqlBindAsString_bindinout.js new file mode 100644 index 00000000..464fe866 --- /dev/null +++ b/test/clobPlsqlBindAsString_bindinout.js @@ -0,0 +1,1337 @@ +/* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with the Apache + * License, Version 2.0 (the "License.") + * + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + * The node-oracledb test suite uses 'mocha', 'should' and 'async'. + * See LICENSE.md for relevant licenses. + * + * NAME + * 76. clobPlsqlBindAsString_bindinout.js + * + * DESCRIPTION + * Testing CLOB binding as String. + * + * NUMBERING RULElist + * Test numbers follow this numbering rule: + * 1 - 20 are reserved for basic functional tests + * 21 - 50 are reserved for data type supporting tests + * 51 onwards are for other tests + * + *****************************************************************************/ +'use strict'; + +var oracledb = require('oracledb'); +var should = require('should'); +var async = require('async'); +var dbConfig = require('./dbconfig.js'); +var fs = require('fs'); +var random = require('./random.js'); + +describe('76. clobPlsqlBindAsString_bindinout.js', function() { + this.timeout(100000); + + var connection = null; + var insertID = 1; // assume id for insert into db starts from 1 + var proc_clob_in_tab = "BEGIN \n" + + " DECLARE \n" + + " e_table_missing EXCEPTION; \n" + + " PRAGMA EXCEPTION_INIT(e_table_missing, -00942); \n" + + " BEGIN \n" + + " EXECUTE IMMEDIATE('DROP TABLE nodb_tab_clob_in PURGE'); \n" + + " EXCEPTION \n" + + " WHEN e_table_missing \n" + + " THEN NULL; \n" + + " END; \n" + + " EXECUTE IMMEDIATE (' \n" + + " CREATE TABLE nodb_tab_clob_in ( \n" + + " id NUMBER, \n" + + " clob_1 CLOB, \n" + + " clob_2 CLOB \n" + + " ) \n" + + " '); \n" + + "END; "; + + var proc_lobs_in_tab = "BEGIN \n" + + " DECLARE \n" + + " e_table_missing EXCEPTION; \n" + + " PRAGMA EXCEPTION_INIT(e_table_missing, -00942); \n" + + " BEGIN \n" + + " EXECUTE IMMEDIATE('DROP TABLE nodb_tab_lobs_in PURGE'); \n" + + " EXCEPTION \n" + + " WHEN e_table_missing \n" + + " THEN NULL; \n" + + " END; \n" + + " EXECUTE IMMEDIATE (' \n" + + " CREATE TABLE nodb_tab_lobs_in ( \n" + + " id NUMBER, \n" + + " clob CLOB \n" + + " ) \n" + + " '); \n" + + "END; "; + + before(function(done) { + async.series([ + function(cb) { + oracledb.getConnection(dbConfig, function(err, conn) { + should.not.exist(err); + connection = conn; + cb(); + }); + }, + function(cb) { + setupAllTable(cb); + } + ], done); + + }); // before + + after(function(done) { + async.series([ + function(cb) { + dropAllTable(cb); + }, + function(cb) { + connection.release(function(err) { + should.not.exist(err); + cb(); + }); + } + ], done); + + }); // after + + var setupAllTable = function(callback) { + async.series([ + function(cb) { + connection.execute( + proc_clob_in_tab, + function(err) { + should.not.exist(err); + cb(); + }); + }, + function(cb) { + connection.execute( + proc_lobs_in_tab, + function(err) { + should.not.exist(err); + cb(); + }); + } + ], callback); + }; + + var dropAllTable = function(callback) { + async.series([ + function(cb) { + connection.execute( + "DROP TABLE nodb_tab_clob_in PURGE", + function(err) { + should.not.exist(err); + cb(); + }); + }, + function(cb) { + connection.execute( + "DROP TABLE nodb_tab_lobs_in PURGE", + function(err) { + should.not.exist(err); + cb(); + }); + } + ], callback); + }; + + var executeSQL = function(sql, callback) { + connection.execute( + sql, + function(err) { + should.not.exist(err); + return callback(); + } + ); + }; + + var inFileName = './test/clobexample.txt'; + + var prepareTableWithClob = function(sql, id, callback) { + var bindVar = { i: id, lobbv: { type: oracledb.CLOB, dir: oracledb.BIND_OUT } }; + + connection.execute( + sql, + bindVar, + { autoCommit: false }, // a transaction needs to span the INSERT and pipe() + function(err, result) { + should.not.exist(err); + (result.rowsAffected).should.be.exactly(1); + (result.outBinds.lobbv.length).should.be.exactly(1); + + var inStream = fs.createReadStream(inFileName); + var lob = result.outBinds.lobbv[0]; + + lob.on('error', function(err) { + should.not.exist(err, "lob.on 'error' event"); + }); + + inStream.on('error', function(err) { + should.not.exist(err, "inStream.on 'error' event"); + }); + + lob.on('close', function() { + connection.commit( function(err) { + should.not.exist(err); + return callback(); + }); + }); + + inStream.pipe(lob); // copies the text to the CLOB + } + ); + }; + + // compare the result string with the original inserted string + var compareResultStrAndOriginal = function(resultVal, originalStr, specialStr) { + var resultLength = resultVal.length; + var specStrLength = specialStr.length; + should.strictEqual(resultLength, originalStr.length); + should.strictEqual(resultVal.substring(0, specStrLength), specialStr); + should.strictEqual(resultVal.substring(resultLength - specStrLength, resultLength), specialStr); + }; + + // execute plsql bind in out procedure, and verify the plsql bind out string + var plsqlBindInOut = function(sqlRun, bindVar, originalStr, specialStr, callback) { + connection.execute( + sqlRun, + bindVar, + function(err, result) { + should.not.exist(err); + var resultVal = result.outBinds.io; + if(originalStr == 'EMPTY_CLOB' || originalStr == null || originalStr == "" || originalStr == undefined) { + should.strictEqual(resultVal, null); + } else { + compareResultStrAndOriginal(resultVal, originalStr, specialStr); + } + callback(); + } + ); + }; + + describe('76.1 CLOB, PLSQL, BIND_INOUT', function() { + var proc = "CREATE OR REPLACE PROCEDURE nodb_clob_in_out_743 (lob_id IN NUMBER, lob_in_out IN OUT CLOB) \n" + + "AS \n" + + "BEGIN \n" + + " insert into nodb_tab_clob_in (id, clob_1) values (lob_id, lob_in_out); \n" + + " select clob_1 into lob_in_out from nodb_tab_clob_in where id = lob_id; \n" + + "END nodb_clob_in_out_743;"; + var sqlRun = "begin nodb_clob_in_out_743(:i, :io); end;"; + var proc_drop = "DROP PROCEDURE nodb_clob_in_out_743"; + var proc_7431 = "CREATE OR REPLACE PROCEDURE nodb_clob_in_out_7431 (lob_id IN NUMBER, lob_in_out IN OUT CLOB) \n" + + "AS \n" + + "BEGIN \n" + + " insert into nodb_tab_clob_in (id, clob_1) values (lob_id, EMPTY_CLOB()); \n" + + " select clob_1 into lob_in_out from nodb_tab_clob_in where id = lob_id; \n" + + "END nodb_clob_in_out_7431;"; + var sqlRun_7431 = "begin nodb_clob_in_out_7431(:i, :io); end;"; + var proc_drop_7431 = "DROP PROCEDURE nodb_clob_in_out_7431"; + + before(function(done) { + executeSQL(proc, done); + }); // before + + after(function(done) { + executeSQL(proc_drop, done); + }); // after + + it('76.1.1 works with EMPTY_CLOB', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, dir: oracledb.BIND_IN, type: oracledb.NUMBER }, + io: { dir: oracledb.BIND_INOUT, type: oracledb.STRING } + }; + + async.series([ + function(cb) { + executeSQL(proc_7431, cb); + }, + function(cb) { + plsqlBindInOut(sqlRun_7431, bindVar, 'EMPTY_CLOB', null, cb); + }, + function(cb) { + executeSQL(proc_drop_7431, cb); + } + ], done); + }); // 76.1.1 + + it('76.1.2 works with EMPTY_CLOB and maxSize set to 1', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, dir: oracledb.BIND_IN, type: oracledb.NUMBER }, + io: { dir: oracledb.BIND_INOUT, type: oracledb.STRING, maxSize: 1 } + }; + + async.series([ + function(cb) { + executeSQL(proc_7431, cb); + }, + function(cb) { + plsqlBindInOut(sqlRun_7431, bindVar, 'EMPTY_CLOB', null, cb); + }, + function(cb) { + executeSQL(proc_drop_7431, cb); + } + ], done); + }); // 76.1.2 + + it('76.1.3 works with EMPTY_CLOB and maxSize set to (64K - 1)', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, dir: oracledb.BIND_IN, type: oracledb.NUMBER }, + io: { dir: oracledb.BIND_INOUT, type: oracledb.STRING, maxSize: 65535 } + }; + + async.series([ + function(cb) { + executeSQL(proc_7431, cb); + }, + function(cb) { + plsqlBindInOut(sqlRun_7431, bindVar, 'EMPTY_CLOB', null, cb); + }, + function(cb) { + executeSQL(proc_drop_7431, cb); + } + ], done); + }); // 76.1.3 + + it('76.1.4 works with null', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, dir: oracledb.BIND_IN, type: oracledb.NUMBER }, + io: { val: null, dir: oracledb.BIND_INOUT, type: oracledb.STRING } + }; + + plsqlBindInOut(sqlRun, bindVar, null, null, done); + }); // 76.1.4 + + it('76.1.5 works with null and maxSize set to 1', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, dir: oracledb.BIND_IN, type: oracledb.NUMBER }, + io: { val: null, dir: oracledb.BIND_INOUT, type: oracledb.STRING, maxSize: 1 } + }; + + plsqlBindInOut(sqlRun, bindVar, null, null, done); + }); // 76.1.5 + + it('76.1.6 works with null and maxSize set to (64K - 1)', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, dir: oracledb.BIND_IN, type: oracledb.NUMBER }, + io: { val: null, dir: oracledb.BIND_INOUT, type: oracledb.STRING, maxSize: 65535 } + }; + + plsqlBindInOut(sqlRun, bindVar, null, null, done); + }); // 76.1.6 + + it('76.1.7 works with empty string', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, dir: oracledb.BIND_IN, type: oracledb.NUMBER }, + io: { val: "", dir: oracledb.BIND_INOUT, type: oracledb.STRING } + }; + + plsqlBindInOut(sqlRun, bindVar, "", null, done); + }); // 76.1.7 + + it('76.1.8 works with empty string and maxSize set to 1', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, dir: oracledb.BIND_IN, type: oracledb.NUMBER }, + io: { val: "", dir: oracledb.BIND_INOUT, type: oracledb.STRING, maxSize: 1 } + }; + + plsqlBindInOut(sqlRun, bindVar, "", null, done); + }); // 76.1.8 + + it('76.1.9 works with empty string and maxSize set to (64K - 1)', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, dir: oracledb.BIND_IN, type: oracledb.NUMBER }, + io: { val: "", dir: oracledb.BIND_INOUT, type: oracledb.STRING, maxSize: 65535 } + }; + + plsqlBindInOut(sqlRun, bindVar, "", null, done); + }); // 76.1.9 + + it('76.1.10 works with undefined', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, dir: oracledb.BIND_IN, type: oracledb.NUMBER }, + io: { val: undefined, dir: oracledb.BIND_INOUT, type: oracledb.STRING } + }; + + plsqlBindInOut(sqlRun, bindVar, undefined, null, done); + }); // 76.1.10 + + it('76.1.11 works with undefined and maxSize set to 1', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, dir: oracledb.BIND_IN, type: oracledb.NUMBER }, + io: { val: undefined, dir: oracledb.BIND_INOUT, type: oracledb.STRING, maxSize: 1 } + }; + + plsqlBindInOut(sqlRun, bindVar, undefined, null, done); + }); // 76.1.11 + + it('76.1.12 works with undefined and maxSize set to (64K - 1)', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, dir: oracledb.BIND_IN, type: oracledb.NUMBER }, + io: { val: undefined, dir: oracledb.BIND_INOUT, type: oracledb.STRING, maxSize: 65535 } + }; + + plsqlBindInOut(sqlRun, bindVar, undefined, null, done); + }); // 76.1.12 + + it('76.1.13 works with NaN', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, dir: oracledb.BIND_IN, type: oracledb.NUMBER }, + io: { val: NaN, dir: oracledb.BIND_INOUT, type: oracledb.STRING, maxSize: 65535 } + }; + + connection.execute( + sqlRun, + bindVar, + function(err) { + should.exist(err); + // NJS-011: encountered bind value and type mismatch in parameter 2 + (err.message).should.startWith('NJS-011:'); + done(); + } + ); + }); // 76.1.13 + + it('76.1.14 works with 0', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, dir: oracledb.BIND_IN, type: oracledb.NUMBER }, + io: { val: 0, dir: oracledb.BIND_INOUT, type: oracledb.STRING, maxSize: 65535 } + }; + + connection.execute( + sqlRun, + bindVar, + function(err) { + should.exist(err); + // NJS-011: encountered bind value and type mismatch in parameter 2 + (err.message).should.startWith('NJS-011:'); + done(); + } + ); + }); // 76.1.14 + + it('76.1.15 works with String length 32K', function(done) { + var specialStr = "76.1.15"; + var len = 32768; + var clobVal = random.getRandomString(len, specialStr); + var sequence = insertID++; + var bindVar = { + i: { val: sequence, dir: oracledb.BIND_IN, type: oracledb.NUMBER }, + io: { val: clobVal, dir: oracledb.BIND_INOUT, type: oracledb.STRING, maxSize: len } + }; + + plsqlBindInOut(sqlRun, bindVar, clobVal, specialStr, done); + }); // 76.1.15 + + it('76.1.16 works with String length (64K - 1)', function(done) { + var sequence = insertID++; + var specialStr = "76.1.16"; + var len = 65535; + var clobVal = random.getRandomString(len, specialStr); + var bindVar = { + i: { val: sequence, dir: oracledb.BIND_IN, type: oracledb.NUMBER }, + io: { val: clobVal, dir: oracledb.BIND_INOUT, type: oracledb.STRING, maxSize: len } + }; + + plsqlBindInOut(sqlRun, bindVar, clobVal, specialStr, done); + }); // 76.1.16 + + it('76.1.17 works with String length (64K + 1)', function(done) { + var sequence = insertID++; + var specialStr = "76.1.17"; + var len = 65537; + var clobVal = random.getRandomString(len, specialStr); + var bindVar = { + i: { val: sequence, dir: oracledb.BIND_IN, type: oracledb.NUMBER }, + io: { val: clobVal, dir: oracledb.BIND_INOUT, type: oracledb.STRING, maxSize: len } + }; + + plsqlBindInOut(sqlRun, bindVar, clobVal, specialStr, done); + }); // 76.1.17 + + it('76.1.18 works with String length (1MB + 1)', function(done) { + var sequence = insertID++; + var specialStr = "76.1.18"; + var len = 1048577; // 1 * 1024 * 1024 + 1 + var clobVal = random.getRandomString(len, specialStr); + var bindVar = { + i: { val: sequence, dir: oracledb.BIND_IN, type: oracledb.NUMBER }, + io: { val: clobVal, dir: oracledb.BIND_INOUT, type: oracledb.STRING, maxSize: len } + }; + + plsqlBindInOut(sqlRun, bindVar, clobVal, specialStr, done); + }); // 76.1.18 + + it('76.1.19 works with bind value and type mismatch', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, dir: oracledb.BIND_IN, type: oracledb.NUMBER }, + io: { val: 10, dir: oracledb.BIND_INOUT, type: oracledb.STRING, maxSize: 65535 } + }; + + connection.execute( + sqlRun, + bindVar, + function(err) { + should.exist(err); + // NJS-011: encountered bind value and type mismatch in parameter 2 + (err.message).should.startWith('NJS-011:'); + done(); + } + ); + }); // 76.1.19 + + it('76.1.20 mixing named with positional binding', function(done) { + var sequence = insertID++; + var specialStr = "76.1.20"; + var len = 50000; + var clobVal = random.getRandomString(len, specialStr); + var bindVar = [ sequence, { dir: oracledb.BIND_INOUT, type: oracledb.STRING, val: clobVal, maxSize: len } ]; + + connection.execute( + sqlRun, + bindVar, + function(err, result) { + should.not.exist(err); + var resultVal = result.outBinds[0]; + compareResultStrAndOriginal(resultVal, clobVal, specialStr); + done(); + } + ); + }); // 76.1.20 + + it('76.1.21 works with UPDATE', function(done) { + var sequence = insertID++; + var len_1 = 50000; + var specialStr_1 = "76.1.21_1"; + var clobVal_1 = random.getRandomString(len_1, specialStr_1); + var len_2 = 300; + var specialStr_2 = "76.1.21_2"; + var clobVal_2 = random.getRandomString(len_2, specialStr_2); + var bindVar = { + id: { val: sequence, dir: oracledb.BIND_IN, type: oracledb.NUMBER }, + i: { val: clobVal_1, dir: oracledb.BIND_IN, type: oracledb.STRING, maxSize: len_1 }, + io: { val: clobVal_2, dir: oracledb.BIND_INOUT, type: oracledb.STRING, maxSize: len_2 } + }; + + var proc_74324 = "CREATE OR REPLACE PROCEDURE nodb_clob_in_out_74324 (lob_id IN NUMBER, lob_in IN CLOB, lob_in_out IN OUT CLOB) \n" + + "AS \n" + + "BEGIN \n" + + " insert into nodb_tab_clob_in (id, clob_1) values (lob_id, lob_in); \n" + + " update nodb_tab_clob_in set clob_1 = lob_in_out where id = lob_id; \n" + + " select clob_1 into lob_in_out from nodb_tab_clob_in where id = lob_id; \n" + + "END nodb_clob_in_out_74324;"; + var sqlRun_74324 = "begin nodb_clob_in_out_74324(:id, :i, :io); end;"; + var proc_drop_74324 = "DROP PROCEDURE nodb_clob_in_out_74324"; + + async.series([ + function(cb) { + executeSQL(proc_74324, cb); + }, + function(cb) { + plsqlBindInOut(sqlRun_74324, bindVar, clobVal_2, specialStr_2, cb); + }, + function(cb) { + executeSQL(proc_drop_74324, cb); + } + ], done); + }); // 76.1.21 + + it('76.1.22 works with invalid CLOB', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, dir: oracledb.BIND_IN, type: oracledb.NUMBER }, + io: { val: {}, dir: oracledb.BIND_INOUT, type: oracledb.STRING } + }; + + connection.execute( + sqlRun, + bindVar, + function(err) { + should.exist(err); + // NJS-011: encountered bind value and type mismatch + (err.message).should.startWith('NJS-011:'); + done(); + } + ); + }); // 76.1.22 + + it('76.1.23 works with substr', function(done) { + var proc_76126 = "CREATE OR REPLACE PROCEDURE nodb_clob_in_out_74126 (lob_id IN NUMBER, lob_in_out IN OUT CLOB) \n" + + "AS \n" + + "BEGIN \n" + + " insert into nodb_tab_clob_in (id, clob_1) values (lob_id, lob_in_out); \n" + + " select substr(clob_1, 1, 3) into lob_in_out from nodb_tab_clob_in where id = lob_id; \n" + + "END nodb_clob_in_out_74126;"; + var sqlRun_76126 = "begin nodb_clob_in_out_74126(:i, :io); end;"; + var proc_drop_76126 = "DROP PROCEDURE nodb_clob_in_out_74126"; + var sequence = insertID++; + var len = 32768; + var specialStr = '76.1.23'; + var clobStr = random.getRandomString(len, specialStr); + var bindVar = { + i: { val: sequence, dir: oracledb.BIND_IN, type: oracledb.NUMBER }, + io: { val: clobStr, dir: oracledb.BIND_INOUT, type: oracledb.STRING, maxSize: len } + }; + + async.series([ + function(cb) { + executeSQL(proc_76126, cb); + }, + function(cb) { + connection.execute( + sqlRun_76126, + bindVar, + function(err, result) { + should.not.exist(err); + var resultVal = result.outBinds.io; + // PLSQL substr function: the position starts from zero(0). + // The substring method extracts the characters in a string between "start" and "end", not including "end" itself. + clobStr = clobStr.substring(0, 3); + should.strictEqual(resultVal.length, 3); + should.strictEqual(resultVal, clobStr); + cb(); + } + ); + }, + function(cb) { + executeSQL(proc_drop_76126, cb); + } + ], done); + }); // 76.1.23 + + it.skip('76.1.24 named binding: maxSize smaller than string length( < 32K )', function(done) { + var sequence = insertID++; + var specialStr = "76.1.24"; + var len = 300; + var clobVal = random.getRandomString(len, specialStr); + var bindVar = { + i: { val: sequence, dir: oracledb.BIND_IN, type: oracledb.NUMBER }, + io: { val: clobVal, dir: oracledb.BIND_INOUT, type: oracledb.STRING, maxSize: len - 1 } + }; + + connection.execute( + sqlRun, + bindVar, + function(err) { + should.exist(err); + console.log(err); + // ORA-01460: unimplemented or unreasonable conversion requested + (err.message).should.startWith('ORA-01460:'); + done(); + } + ); + }); // 76.1.24 + + it('76.1.25 named binding: maxSize smaller than string length( > 32K )', function(done) { + var sequence = insertID++; + var specialStr = "76.1.25"; + var len = 50000; + var clobVal = random.getRandomString(len, specialStr); + var bindVar = { + i: { val: sequence, dir: oracledb.BIND_IN, type: oracledb.NUMBER }, + io: { val: clobVal, dir: oracledb.BIND_INOUT, type: oracledb.STRING, maxSize: len - 1 } + }; + + connection.execute( + sqlRun, + bindVar, + function(err) { + should.exist(err); + // NJS-016: buffer is too small for OUT binds + (err.message).should.startWith('NJS-016:'); + done(); + } + ); + }); // 76.1.25 + + it('76.1.26 named binding: maxSize smaller than string length( > 64K )', function(done) { + var sequence = insertID++; + var specialStr = "76.1.26"; + var len = 65539; + var clobVal = random.getRandomString(len, specialStr); + var bindVar = { + i: { val: sequence, dir: oracledb.BIND_IN, type: oracledb.NUMBER }, + io: { val: clobVal, dir: oracledb.BIND_INOUT, type: oracledb.STRING, maxSize: len - 1 } + }; + + connection.execute( + sqlRun, + bindVar, + function(err) { + should.exist(err); + // NJS-016: buffer is too small for OUT binds + (err.message).should.startWith('NJS-016:'); + done(); + } + ); + }); // 76.1.26 + + it.skip('76.1.27 positional binding: maxSize smaller than string length( < 32K )', function(done) { + var sequence = insertID++; + var specialStr = "76.1.27"; + var len = 300; + var clobVal = random.getRandomString(len, specialStr); + sqlRun = "begin nodb_clob_in_out_743(:1, :2); end;"; + var bindVar = [ sequence, { val: clobVal, dir: oracledb.BIND_INOUT, type: oracledb.STRING, maxSize: len - 1 } ]; + + connection.execute( + sqlRun, + bindVar, + function(err) { + should.exist(err); + // ORA-01460: unimplemented or unreasonable conversion requested + (err.message).should.startWith('ORA-01460:'); + done(); + } + ); + }); // 76.1.27 + + it('76.1.28 positional binding: maxSize smaller than string length( > 32K )', function(done) { + var sequence = insertID++; + var specialStr = "76.1.28"; + var len = 50000; + var clobVal = random.getRandomString(len, specialStr); + sqlRun = "begin nodb_clob_in_out_743(:1, :2); end;"; + var bindVar = [ sequence, { val: clobVal, dir: oracledb.BIND_INOUT, type: oracledb.STRING, maxSize: len - 1 } ]; + + connection.execute( + sqlRun, + bindVar, + function(err) { + should.exist(err); + // NJS-016: buffer is too small for OUT binds + (err.message).should.startWith('NJS-016:'); + done(); + } + ); + }); // 76.1.28 + + it('76.1.29 positional binding: maxSize smaller than string length( > 64K )', function(done) { + var sequence = insertID++; + var specialStr = "76.1.29"; + var len = 65539; + var clobVal = random.getRandomString(len, specialStr); + sqlRun = "begin nodb_clob_in_out_743(:1, :2); end;"; + var bindVar = [ sequence, { val: clobVal, dir: oracledb.BIND_INOUT, type: oracledb.STRING, maxSize: len - 1 } ]; + + connection.execute( + sqlRun, + bindVar, + function(err) { + should.exist(err); + // NJS-016: buffer is too small for OUT binds + (err.message).should.startWith('NJS-016:'); + done(); + } + ); + }); // 76.1.29 + + }); // 76.1 + + describe('76.2 CLOB, PLSQL, BIND_INOUT to VARCHAR2', function() { + var proc = "CREATE OR REPLACE PROCEDURE nodb_clob_in_out_743 (lob_id IN NUMBER, lob_in_out IN OUT VARCHAR2) \n" + + "AS \n" + + "BEGIN \n" + + " insert into nodb_tab_clob_in (id, clob_1) values (lob_id, lob_in_out); \n" + + " select clob_1 into lob_in_out from nodb_tab_clob_in where id = lob_id; \n" + + "END nodb_clob_in_out_743;"; + var sqlRun = "begin nodb_clob_in_out_743(:i, :io); end;"; + var proc_drop = "DROP PROCEDURE nodb_clob_in_out_743"; + var proc_7421 = "CREATE OR REPLACE PROCEDURE nodb_clob_in_out_7421 (lob_id IN NUMBER, lob_in_out IN OUT VARCHAR2) \n" + + "AS \n" + + "BEGIN \n" + + " insert into nodb_tab_clob_in (id, clob_1) values (lob_id, EMPTY_CLOB()); \n" + + " select clob_1 into lob_in_out from nodb_tab_clob_in where id = lob_id; \n" + + "END nodb_clob_in_out_7421;"; + var sqlRun_7421 = "begin nodb_clob_in_out_7421(:i, :io); end;"; + var proc_drop_7421 = "DROP PROCEDURE nodb_clob_in_out_7421"; + + before(function(done) { + executeSQL(proc, done); + }); // before + + after(function(done) { + executeSQL(proc_drop, done); + }); // after + + it('76.2.1 works with EMPTY_CLOB', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, dir: oracledb.BIND_IN, type: oracledb.NUMBER }, + io: { dir: oracledb.BIND_INOUT, type: oracledb.STRING } + }; + + async.series([ + function(cb) { + executeSQL(proc_7421, cb); + }, + function(cb) { + plsqlBindInOut(sqlRun_7421, bindVar, 'EMPTY_CLOB', null, cb); + }, + function(cb) { + executeSQL(proc_drop_7421, cb); + } + ], done); + }); // 76.2.1 + + it('76.2.2 works with EMPTY_CLOB and maxSize set to 1', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, dir: oracledb.BIND_IN, type: oracledb.NUMBER }, + io: { dir: oracledb.BIND_INOUT, type: oracledb.STRING, maxSize: 1 } + }; + + async.series([ + function(cb) { + executeSQL(proc_7421, cb); + }, + function(cb) { + plsqlBindInOut(sqlRun_7421, bindVar, 'EMPTY_CLOB', null, cb); + }, + function(cb) { + executeSQL(proc_drop_7421, cb); + } + ], done); + }); // 76.2.2 + + it('76.2.3 works with EMPTY_CLOB and maxSize set to (64K - 1)', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, dir: oracledb.BIND_IN, type: oracledb.NUMBER }, + io: { dir: oracledb.BIND_INOUT, type: oracledb.STRING, maxSize: 65535 } + }; + + async.series([ + function(cb) { + executeSQL(proc_7421, cb); + }, + function(cb) { + plsqlBindInOut(sqlRun_7421, bindVar, 'EMPTY_CLOB', null, cb); + }, + function(cb) { + executeSQL(proc_drop_7421, cb); + } + ], done); + }); // 76.2.3 + + it('76.2.4 works with null', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, dir: oracledb.BIND_IN, type: oracledb.NUMBER }, + io: { val: null, dir: oracledb.BIND_INOUT, type: oracledb.STRING } + }; + + plsqlBindInOut(sqlRun, bindVar, null, null, done); + }); // 76.2.4 + + it('76.2.5 works with null and maxSize set to 1', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, dir: oracledb.BIND_IN, type: oracledb.NUMBER }, + io: { val: null, dir: oracledb.BIND_INOUT, type: oracledb.STRING, maxSize: 1 } + }; + + plsqlBindInOut(sqlRun, bindVar, null, null, done); + }); // 76.2.5 + + it('76.2.6 works with null and maxSize set to (64K - 1)', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, dir: oracledb.BIND_IN, type: oracledb.NUMBER }, + io: { val: null, dir: oracledb.BIND_INOUT, type: oracledb.STRING, maxSize: 65535 } + }; + + plsqlBindInOut(sqlRun, bindVar, null, null, done); + }); // 76.2.6 + + it('76.2.7 works with empty string', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, dir: oracledb.BIND_IN, type: oracledb.NUMBER }, + io: { val: "", dir: oracledb.BIND_INOUT, type: oracledb.STRING } + }; + + plsqlBindInOut(sqlRun, bindVar, "", null, done); + }); // 76.2.7 + + it('76.2.8 works with empty string and maxSize set to 1', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, dir: oracledb.BIND_IN, type: oracledb.NUMBER }, + io: { val: "", dir: oracledb.BIND_INOUT, type: oracledb.STRING, maxSize: 1 } + }; + + plsqlBindInOut(sqlRun, bindVar, "", null, done); + }); // 76.2.8 + + it('76.2.9 works with empty string and maxSize set to (64K - 1)', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, dir: oracledb.BIND_IN, type: oracledb.NUMBER }, + io: { val: "", dir: oracledb.BIND_INOUT, type: oracledb.STRING, maxSize: 65535 } + }; + + plsqlBindInOut(sqlRun, bindVar, "", null, done); + }); // 76.2.9 + + it('76.2.10 works with undefined', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, dir: oracledb.BIND_IN, type: oracledb.NUMBER }, + io: { val: undefined, dir: oracledb.BIND_INOUT, type: oracledb.STRING } + }; + + plsqlBindInOut(sqlRun, bindVar, undefined, null, done); + }); // 76.2.10 + + it('76.2.11 works with undefined and maxSize set to 1', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, dir: oracledb.BIND_IN, type: oracledb.NUMBER }, + io: { val: undefined, dir: oracledb.BIND_INOUT, type: oracledb.STRING, maxSize: 1 } + }; + + plsqlBindInOut(sqlRun, bindVar, undefined, null, done); + }); // 76.2.11 + + it('76.2.12 works with undefined and maxSize set to (64K - 1)', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, dir: oracledb.BIND_IN, type: oracledb.NUMBER }, + io: { val: undefined, dir: oracledb.BIND_INOUT, type: oracledb.STRING, maxSize: 65535 } + }; + + plsqlBindInOut(sqlRun, bindVar, undefined, null, done); + }); // 76.2.12 + + it('76.2.13 works with NaN', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, dir: oracledb.BIND_IN, type: oracledb.NUMBER }, + io: { val: NaN, dir: oracledb.BIND_INOUT, type: oracledb.STRING, maxSize: 65535 } + }; + + connection.execute( + sqlRun, + bindVar, + function(err) { + should.exist(err); + // NJS-011: encountered bind value and type mismatch in parameter 2 + (err.message).should.startWith('NJS-011:'); + done(); + } + ); + }); // 76.2.13 + + it('76.2.14 works with 0', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, dir: oracledb.BIND_IN, type: oracledb.NUMBER }, + io: { val: 0, dir: oracledb.BIND_INOUT, type: oracledb.STRING, maxSize: 65535 } + }; + + connection.execute( + sqlRun, + bindVar, + function(err) { + should.exist(err); + // NJS-011: encountered bind value and type mismatch in parameter 2 + (err.message).should.startWith('NJS-011:'); + done(); + } + ); + }); // 76.2.14 + + it('76.2.15 works with String length (32K - 1)', function(done) { + var specialStr = "76.2.15"; + var len = 32767; + var clobVal = random.getRandomString(len, specialStr); + var sequence = insertID++; + var bindVar = { + i: { val: sequence, dir: oracledb.BIND_IN, type: oracledb.NUMBER }, + io: { val: clobVal, dir: oracledb.BIND_INOUT, type: oracledb.STRING, maxSize: len } + }; + + plsqlBindInOut(sqlRun, bindVar, clobVal, specialStr, done); + }); // 76.2.15 + + it('76.2.16 works with String length 32K', function(done) { + var sequence = insertID++; + var specialStr = "76.2.16"; + var len = 32768; + var clobVal = random.getRandomString(len, specialStr); + var bindVar = { + i: { val: sequence, dir: oracledb.BIND_IN, type: oracledb.NUMBER }, + io: { val: clobVal, dir: oracledb.BIND_INOUT, type: oracledb.STRING, maxSize: len } + }; + + connection.execute( + sqlRun, + bindVar, + function(err) { + should.exist(err); + // ORA-06502: PL/SQL: numeric or value error + (err.message).should.startWith('ORA-06502:'); + done(); + } + ); + }); // 76.2.16 + + it('76.2.17 works with bind out maxSize smaller than string length', function(done) { + var sequence = insertID++; + var specialStr = "76.2.17"; + var len = 600; + var clobVal = random.getRandomString(len, specialStr); + var bindVar = { + i: { val: sequence, dir: oracledb.BIND_IN, type: oracledb.NUMBER }, + io: { val: clobVal, dir: oracledb.BIND_INOUT, type: oracledb.STRING, maxSize: len - 1 } + }; + + connection.execute( + sqlRun, + bindVar, + function(err) { + should.exist(err); + // DPI-1019: buffer size is too small + (err.message).should.startWith('DPI-1019:'); + done(); + } + ); + }); // 76.2.17 + + it('76.2.18 works with UPDATE', function(done) { + var sequence = insertID++; + var len_1 = 500; + var specialStr_1 = "76.2.18_1"; + var clobVal_1 = random.getRandomString(len_1, specialStr_1); + var len_2 = 300; + var specialStr_2 = "76.2.18_2"; + var clobVal_2 = random.getRandomString(len_2, specialStr_2); + var bindVar = { + id: { val: sequence, dir: oracledb.BIND_IN, type: oracledb.NUMBER }, + i: { val: clobVal_1, dir: oracledb.BIND_IN, type: oracledb.STRING, maxSize: len_1 }, + io: { val: clobVal_2, dir: oracledb.BIND_INOUT, type: oracledb.STRING, maxSize: len_2 } + }; + + var proc_74218 = "CREATE OR REPLACE PROCEDURE nodb_clob_in_out_74218 (lob_id IN NUMBER, lob_in IN VARCHAR2, lob_in_out IN OUT VARCHAR2) \n" + + "AS \n" + + "BEGIN \n" + + " insert into nodb_tab_clob_in (id, clob_1) values (lob_id, lob_in); \n" + + " update nodb_tab_clob_in set clob_1 = lob_in_out where id = lob_id; \n" + + " select clob_1 into lob_in_out from nodb_tab_clob_in where id = lob_id; \n" + + "END nodb_clob_in_out_74218;"; + var sqlRun_74218 = "begin nodb_clob_in_out_74218(:id, :i, :io); end;"; + var proc_drop_74218 = "DROP PROCEDURE nodb_clob_in_out_74218"; + + async.series([ + function(cb) { + executeSQL(proc_74218, cb); + }, + function(cb) { + plsqlBindInOut(sqlRun_74218, bindVar, clobVal_2, specialStr_2, cb); + }, + function(cb) { + executeSQL(proc_drop_74218, cb); + } + ], done); + }); // 76.2.18 + + it('76.2.19 works with invalid CLOB', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, dir: oracledb.BIND_IN, type: oracledb.NUMBER }, + io: { val: {}, dir: oracledb.BIND_INOUT, type: oracledb.STRING } + }; + + connection.execute( + sqlRun, + bindVar, + function(err) { + should.exist(err); + // NJS-011: encountered bind value and type mismatch + (err.message).should.startWith('NJS-011:'); + done(); + } + ); + }); // 76.2.19 + + it('76.2.20 works with substr', function(done) { + var proc_76220 = "CREATE OR REPLACE PROCEDURE nodb_clob_in_out_74220 (lob_id IN NUMBER, lob_in_out IN OUT CLOB) \n" + + "AS \n" + + "BEGIN \n" + + " insert into nodb_tab_clob_in (id, clob_1) values (lob_id, lob_in_out); \n" + + " select substr(clob_1, 1, 3) into lob_in_out from nodb_tab_clob_in where id = lob_id; \n" + + "END nodb_clob_in_out_74220;"; + var sqlRun_76220 = "begin nodb_clob_in_out_74220(:i, :io); end;"; + var proc_drop_76220 = "DROP PROCEDURE nodb_clob_in_out_74220"; + var sequence = insertID++; + var len = 3000; + var specialStr = '76.2.20'; + var clobStr = random.getRandomString(len, specialStr); + var bindVar = { + i: { val: sequence, dir: oracledb.BIND_IN, type: oracledb.NUMBER }, + io: { val: clobStr, dir: oracledb.BIND_INOUT, type: oracledb.STRING, maxSize: len } + }; + + async.series([ + function(cb) { + executeSQL(proc_76220, cb); + }, + function(cb) { + connection.execute( + sqlRun_76220, + bindVar, + function(err, result) { + should.not.exist(err); + var resultVal = result.outBinds.io; + // PLSQL substr function: the position starts from zero(0). + // The substring method extracts the characters in a string between "start" and "end", not including "end" itself. + clobStr = clobStr.substring(0, 3); + should.strictEqual(resultVal.length, 3); + should.strictEqual(resultVal, clobStr); + cb(); + } + ); + }, + function(cb) { + executeSQL(proc_drop_76220, cb); + } + ], done); + }); // 76.2.20 + + }); // 76.2 + + describe('76.3 Multiple CLOBs, BIND INOUT', function() { + var lobs_proc_inout_762 = "CREATE OR REPLACE PROCEDURE nodb_lobs_in_out_746 (lob_id IN NUMBER, clob_1 IN OUT CLOB, clob_2 IN OUT CLOB) \n" + + "AS \n" + + "BEGIN \n" + + " insert into nodb_tab_clob_in (id, clob_1, clob_2) values (lob_id, clob_1, clob_2); \n" + + " select clob_1, clob_2 into clob_1, clob_2 from nodb_tab_clob_in where id = lob_id; \n" + + "END nodb_lobs_in_out_746;"; + var sqlRun_762 = "begin nodb_lobs_in_out_746(:i, :io1, :io2); end;"; + var proc_drop_762 = "DROP PROCEDURE nodb_lobs_in_out_746"; + + before(function(done) { + executeSQL(lobs_proc_inout_762, done); + }); // before + + after(function(done) { + executeSQL(proc_drop_762, done); + }); // after + + it('76.3.1 bind a txt file and a 32K string', function(done) { + var specialStr = "76.3.1"; + var len1 = 32768; + var clobVal = random.getRandomString(len1, specialStr); + var sequence = insertID++; + var preparedCLOBID = insertID++; + + async.series([ + function(cb) { + var sql = "INSERT INTO nodb_tab_lobs_in (id, clob) VALUES (:i, EMPTY_CLOB()) RETURNING clob INTO :lobbv"; + prepareTableWithClob(sql, preparedCLOBID, cb); + }, + function(cb) { + connection.execute( + "select clob from nodb_tab_lobs_in where id = :id", + { id: preparedCLOBID }, + function(err, result) { + should.not.exist(err); + (result.rows.length).should.not.eql(0); + var clob = result.rows[0][0]; + connection.execute( + sqlRun_762, + { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + io1: { val: clobVal, type: oracledb.STRING, dir: oracledb.BIND_INOUT, maxSize: len1 }, + io2: { val: clob, type: oracledb.CLOB, dir: oracledb.BIND_INOUT } + }, + { autoCommit: true }, + function(err, result) { + should.not.exist(err); + var resultVal = result.outBinds.io1; + compareResultStrAndOriginal(resultVal, clobVal, specialStr); + + var lob = result.outBinds.io2; + should.exist(lob); + lob.setEncoding("utf8"); + var clobData = ''; + lob.on('data', function(chunk) { + clobData += chunk; + }); + + lob.on('error', function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + lob.on('end', function() { + fs.readFile( inFileName, { encoding: 'utf8' }, function(err, originalData) { + should.not.exist(err); + should.strictEqual(clobData, originalData); + }); + }); + cb(); + } + ); + } + ); + } + ], done); + }); // 76.3.1 + + it('76.3.2 bind a txt file and a (64K - 1) string', function(done) { + var specialStr = "76.3.2"; + var len1 = 65535; + var clobVal = random.getRandomString(len1, specialStr); + var preparedCLOBID = insertID++; + var sequence = insertID++; + + async.series([ + function(cb) { + var sql = "INSERT INTO nodb_tab_lobs_in (id, clob) VALUES (:i, EMPTY_CLOB()) RETURNING clob INTO :lobbv"; + prepareTableWithClob(sql, preparedCLOBID, cb); + }, + function(cb) { + connection.execute( + "select clob from nodb_tab_lobs_in where id = :id", + { id: preparedCLOBID }, + function(err, result) { + should.not.exist(err); + (result.rows.length).should.not.eql(0); + var clob = result.rows[0][0]; + connection.execute( + sqlRun_762, + { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN, maxSize: len1 }, + io1: { val: clobVal, type: oracledb.STRING, dir: oracledb.BIND_INOUT, maxSize: len1 }, + io2: { val: clob, type: oracledb.CLOB, dir: oracledb.BIND_INOUT } + }, + { autoCommit: true }, + function(err, result) { + should.not.exist(err); + var resultVal = result.outBinds.io1; + compareResultStrAndOriginal(resultVal, clobVal, specialStr); + + var lob = result.outBinds.io2; + should.exist(lob); + lob.setEncoding("utf8"); + var clobData = ''; + lob.on('data', function(chunk) { + clobData += chunk; + }); + + lob.on('error', function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + lob.on('end', function() { + fs.readFile( inFileName, { encoding: 'utf8' }, function(err, originalData) { + should.not.exist(err); + should.strictEqual(clobData, originalData); + }); + }); + cb(); + } + ); + } + ); + } + ], done); + }); // 76.3.2 + + it('76.3.3 bind a txt file and a (64K + 1) string', function(done) { + var specialStr = "76.3.3"; + var len1 = 65537; + var clobVal = random.getRandomString(len1, specialStr); + var preparedCLOBID = insertID++; + var sequence = insertID++; + + async.series([ + function(cb) { + var sql = "INSERT INTO nodb_tab_lobs_in (id, clob) VALUES (:i, EMPTY_CLOB()) RETURNING clob INTO :lobbv"; + prepareTableWithClob(sql, preparedCLOBID, cb); + }, + function(cb) { + connection.execute( + "select clob from nodb_tab_lobs_in where id = :id", + { id: preparedCLOBID }, + function(err, result) { + should.not.exist(err); + (result.rows.length).should.not.eql(0); + var clob = result.rows[0][0]; + connection.execute( + sqlRun_762, + { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN, maxSize: len1 }, + io1: { val: clobVal, type: oracledb.STRING, dir: oracledb.BIND_INOUT, maxSize: len1 }, + io2: { val: clob, type: oracledb.CLOB, dir: oracledb.BIND_INOUT } + }, + { autoCommit: true }, + function(err, result) { + var resultVal = result.outBinds.io1; + compareResultStrAndOriginal(resultVal, clobVal, specialStr); + + var lob = result.outBinds.io2; + should.exist(lob); + lob.setEncoding("utf8"); + var clobData = ''; + lob.on('data', function(chunk) { + clobData += chunk; + }); + + lob.on('error', function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + lob.on('end', function() { + fs.readFile( inFileName, { encoding: 'utf8' }, function(err, originalData) { + should.not.exist(err); + should.strictEqual(clobData, originalData); + }); + }); + cb(); + } + ); + } + ); + } + ], done); + }); // 76.3.3 + + }); // 76.3 + +}); diff --git a/test/clobPlsqlBindAsString_bindout.js b/test/clobPlsqlBindAsString_bindout.js new file mode 100644 index 00000000..2107c9cd --- /dev/null +++ b/test/clobPlsqlBindAsString_bindout.js @@ -0,0 +1,1570 @@ +/* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with the Apache + * License, Version 2.0 (the "License.") + * + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + * The node-oracledb test suite uses 'mocha', 'should' and 'async'. + * See LICENSE.md for relevant licenses. + * + * NAME + * 75. clobPlsqlBindAsString_bindout.js + * + * DESCRIPTION + * Testing CLOB binding out as String. + * + * NUMBERING RULElist + * Test numbers follow this numbering rule: + * 1 - 20 are reserved for basic functional tests + * 21 - 50 are reserved for data type supporting tests + * 51 onwards are for other tests + * + *****************************************************************************/ +'use strict'; + +var oracledb = require('oracledb'); +var should = require('should'); +var async = require('async'); +var fs = require('fs'); +var dbConfig = require('./dbconfig.js'); +var file = require('./file.js'); +var random = require('./random.js'); + +describe('75. clobPlsqlBindAsString_bindout.js', function() { + this.timeout(100000); + + var connection = null; + var insertID = 1; // assume id for insert into db starts from 1 + var proc_clob_in_tab = "BEGIN \n" + + " DECLARE \n" + + " e_table_missing EXCEPTION; \n" + + " PRAGMA EXCEPTION_INIT(e_table_missing, -00942); \n" + + " BEGIN \n" + + " EXECUTE IMMEDIATE('DROP TABLE nodb_tab_clob_in PURGE'); \n" + + " EXCEPTION \n" + + " WHEN e_table_missing \n" + + " THEN NULL; \n" + + " END; \n" + + " EXECUTE IMMEDIATE (' \n" + + " CREATE TABLE nodb_tab_clob_in ( \n" + + " id NUMBER, \n" + + " clob_1 CLOB, \n" + + " clob_2 CLOB \n" + + " ) \n" + + " '); \n" + + "END; "; + + var proc_lobs_in_tab = "BEGIN \n" + + " DECLARE \n" + + " e_table_missing EXCEPTION; \n" + + " PRAGMA EXCEPTION_INIT(e_table_missing, -00942); \n" + + " BEGIN \n" + + " EXECUTE IMMEDIATE('DROP TABLE nodb_tab_lobs_in PURGE'); \n" + + " EXCEPTION \n" + + " WHEN e_table_missing \n" + + " THEN NULL; \n" + + " END; \n" + + " EXECUTE IMMEDIATE (' \n" + + " CREATE TABLE nodb_tab_lobs_in ( \n" + + " id NUMBER, \n" + + " clob CLOB \n" + + " ) \n" + + " '); \n" + + "END; "; + + before(function(done) { + async.series([ + function(cb) { + oracledb.getConnection(dbConfig, function(err, conn) { + should.not.exist(err); + connection = conn; + cb(); + }); + }, + function(cb) { + setupAllTable(cb); + } + ], done); + + }); // before + + after(function(done) { + async.series([ + function(cb) { + dropAllTable(cb); + }, + function(cb) { + connection.release(function(err) { + should.not.exist(err); + cb(); + }); + }, + function(cb) { + file.delete(inFileStreamed); + cb(); + } + ], done); + + }); // after + + var setupAllTable = function(callback) { + async.series([ + function(cb) { + connection.execute( + proc_clob_in_tab, + function(err) { + should.not.exist(err); + cb(); + }); + }, + function(cb) { + connection.execute( + proc_lobs_in_tab, + function(err) { + should.not.exist(err); + cb(); + }); + } + ], callback); + }; + + var dropAllTable = function(callback) { + async.series([ + function(cb) { + connection.execute( + "DROP TABLE nodb_tab_clob_in PURGE", + function(err) { + should.not.exist(err); + cb(); + }); + }, + function(cb) { + connection.execute( + "DROP TABLE nodb_tab_lobs_in PURGE", + function(err) { + should.not.exist(err); + cb(); + }); + } + ], callback); + }; + + var executeSQL = function(sql, callback) { + connection.execute( + sql, + function(err) { + should.not.exist(err); + return callback(); + } + ); + }; + + var insertClobWithString = function(id, insertStr, callback) { + var sql = "INSERT INTO nodb_tab_clob_in (id, clob_1) VALUES (:i, :c)"; + var bindVar = { + i: { val: id, dir: oracledb.BIND_IN, type: oracledb.NUMBER }, + c: { val: insertStr, dir: oracledb.BIND_IN, type: oracledb.STRING } + }; + + if (insertStr == 'EMPTY_LOB') { + sql = "INSERT INTO nodb_tab_clob_in (id, clob_1) VALUES (:i, EMPTY_CLOB())"; + bindVar = { + i: { val: id, dir: oracledb.BIND_IN, type: oracledb.NUMBER } + }; + } + connection.execute( + sql, + bindVar, + function(err, result) { + should.not.exist(err); + should.strictEqual(result.rowsAffected, 1); + callback(); + } + ); + }; + + var inFileStreamed = './test/clobTmpFile.txt'; + + var preparedInFileName = './test/clobexample.txt'; + + var prepareTableWithClob = function(sql, id, callback) { + + var bindVar = { i: id, lobbv: { type: oracledb.CLOB, dir: oracledb.BIND_OUT } }; + + connection.execute( + sql, + bindVar, + { autoCommit: false }, // a transaction needs to span the INSERT and pipe() + function(err, result) { + should.not.exist(err); + (result.rowsAffected).should.be.exactly(1); + (result.outBinds.lobbv.length).should.be.exactly(1); + + var inStream = fs.createReadStream(preparedInFileName); + var lob = result.outBinds.lobbv[0]; + + lob.on('error', function(err) { + should.not.exist(err, "lob.on 'error' event"); + }); + + inStream.on('error', function(err) { + should.not.exist(err, "inStream.on 'error' event"); + }); + + lob.on('close', function() { + connection.commit( function(err) { + should.not.exist(err); + return callback(); + }); + }); + + inStream.pipe(lob); // copies the text to the CLOB + } + ); + }; + + var verifyClobValueWithFileData = function(selectSql, callback) { + connection.execute( + selectSql, + function(err, result) { + should.not.exist(err); + var lob = result.rows[0][0]; + should.exist(lob); + // set the encoding so we get a 'string' not a 'buffer' + lob.setEncoding('utf8'); + var clobData = ''; + + lob.on('data', function(chunk) { + clobData += chunk; + }); + + lob.on('error', function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + lob.on('end', function() { + fs.readFile( preparedInFileName, { encoding: 'utf8' }, function(err, originalData) { + should.not.exist(err); + should.strictEqual(clobData, originalData); + return callback(); + }); + }); + } + ); + }; + + // compare the result string with the original inserted string + var compareResultStrAndOriginal = function(resultVal, originalStr, specialStr) { + var resultLength = resultVal.length; + var specStrLength = specialStr.length; + should.strictEqual(resultLength, originalStr.length); + should.strictEqual(resultVal.substring(0, specStrLength), specialStr); + should.strictEqual(resultVal.substring(resultLength - specStrLength, resultLength), specialStr); + }; + + var verifyBindOutResult = function(sqlRun, bindVar, originalStr, specialStr, callback) { + connection.execute( + sqlRun, + bindVar, + function(err, result) { + if(originalStr == "EMPTY_LOB" || originalStr == undefined || originalStr == null || originalStr == "") { + should.not.exist(err); + should.strictEqual(result.outBinds.c, null); + callback(); + } else { + should.not.exist(err); + var resultVal = result.outBinds.c; + compareResultStrAndOriginal(resultVal, originalStr, specialStr); + callback(); + } + } + ); + }; + + describe('75.1 CLOB, PLSQL, BIND_OUT', function() { + var proc = "CREATE OR REPLACE PROCEDURE nodb_clobs_out_741 (clob_id IN NUMBER, clob_out OUT CLOB) \n" + + "AS \n" + + "BEGIN \n" + + " select clob_1 into clob_out from nodb_tab_clob_in where id = clob_id; \n" + + "END nodb_clobs_out_741; "; + var sqlRun = "BEGIN nodb_clobs_out_741 (:i, :c); END;"; + var proc_drop = "DROP PROCEDURE nodb_clobs_out_741"; + + before(function(done) { + executeSQL(proc, done); + }); // before + + after(function(done) { + executeSQL(proc_drop, done); + }); // after + + it('75.1.1 works with EMPTY_LOB', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { type: oracledb.STRING, dir: oracledb.BIND_OUT } + }; + + async.series([ + function(cb) { + insertClobWithString(sequence, "EMPTY_LOB", cb); + }, + function(cb) { + verifyBindOutResult(sqlRun, bindVar, "EMPTY_LOB", null, cb); + } + ], done); + }); // 75.1.1 + + it('75.1.2 works with EMPTY_LOB and bind out maxSize set to 1', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { type: oracledb.STRING, dir: oracledb.BIND_OUT, maxSize: 1 } + }; + + async.series([ + function(cb) { + insertClobWithString(sequence, "EMPTY_LOB", cb); + }, + function(cb) { + verifyBindOutResult(sqlRun, bindVar, "EMPTY_LOB", null, cb); + } + ], done); + }); // 75.1.2 + + it('75.1.3 works with EMPTY_LOB and bind out maxSize set to (64k - 1)', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { type: oracledb.STRING, dir: oracledb.BIND_OUT, maxSize: 65535 } + }; + + async.series([ + function(cb) { + insertClobWithString(sequence, "EMPTY_LOB", cb); + }, + function(cb) { + verifyBindOutResult(sqlRun, bindVar, "EMPTY_LOB", null, cb); + } + ], done); + }); // 75.1.3 + + it('75.1.4 works with null', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { type: oracledb.STRING, dir: oracledb.BIND_OUT } + }; + + async.series([ + function(cb) { + insertClobWithString(sequence, null, cb); + }, + function(cb) { + verifyBindOutResult(sqlRun, bindVar, null, null, cb); + } + ], done); + }); // 75.1.4 + + it('75.1.5 works with null and bind out maxSize set to 1', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { type: oracledb.STRING, dir: oracledb.BIND_OUT, maxSize: 1 } + }; + + async.series([ + function(cb) { + insertClobWithString(sequence, null, cb); + }, + function(cb) { + verifyBindOutResult(sqlRun, bindVar, null, null, cb); + } + ], done); + }); // 75.1.5 + + it('75.1.6 works with null and bind out maxSize set to (64k - 1)', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { type: oracledb.STRING, dir: oracledb.BIND_OUT, maxSize: 65535 } + }; + + async.series([ + function(cb) { + insertClobWithString(sequence, null, cb); + }, + function(cb) { + verifyBindOutResult(sqlRun, bindVar, null, null, cb); + } + ], done); + }); // 75.1.6 + + it('75.1.7 works with empty string', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { type: oracledb.STRING, dir: oracledb.BIND_OUT } + }; + + async.series([ + function(cb) { + insertClobWithString(sequence, "", cb); + }, + function(cb) { + verifyBindOutResult(sqlRun, bindVar, "", null, cb); + } + ], done); + }); // 75.1.7 + + it('75.1.8 works with empty string and bind out maxSize set to 1', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { type: oracledb.STRING, dir: oracledb.BIND_OUT, maxSize: 1 } + }; + + async.series([ + function(cb) { + insertClobWithString(sequence, "", cb); + }, + function(cb) { + verifyBindOutResult(sqlRun, bindVar, "", null, cb); + } + ], done); + }); // 75.1.8 + + it('75.1.9 works with empty string and bind out maxSize set to (64K - 1)', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { type: oracledb.STRING, dir: oracledb.BIND_OUT, maxSize: 65535 } + }; + + async.series([ + function(cb) { + insertClobWithString(sequence, "", cb); + }, + function(cb) { + verifyBindOutResult(sqlRun, bindVar, "", null, cb); + } + ], done); + }); // 75.1.9 + + it('75.1.10 works with undefined', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { type: oracledb.STRING, dir: oracledb.BIND_OUT } + }; + + async.series([ + function(cb) { + insertClobWithString(sequence, undefined, cb); + }, + function(cb) { + verifyBindOutResult(sqlRun, bindVar, undefined, null, cb); + } + ], done); + }); // 75.1.10 + + it('75.1.11 works with undefined and bind out maxSize set to 1', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { type: oracledb.STRING, dir: oracledb.BIND_OUT, maxSize: 1 } + }; + + async.series([ + function(cb) { + insertClobWithString(sequence, undefined, cb); + }, + function(cb) { + verifyBindOutResult(sqlRun, bindVar, undefined, null, cb); + } + ], done); + }); // 75.1.11 + + it('75.1.12 works with undefined and bind out maxSize set to (64K - 1)', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { type: oracledb.STRING, dir: oracledb.BIND_OUT, maxSize: 65535 } + }; + + async.series([ + function(cb) { + insertClobWithString(sequence, undefined, cb); + }, + function(cb) { + verifyBindOutResult(sqlRun, bindVar, undefined, null, cb); + } + ], done); + }); // 75.1.12 + + it('75.1.13 works with NaN', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { val: NaN, type: oracledb.STRING, dir: oracledb.BIND_IN } + }; + + var sql = "INSERT INTO nodb_tab_clob_in (id, clob_1) VALUES (:i, :c)"; + connection.execute( + sql, + bindVar, + function(err) { + should.exist(err); + // NJS-011: encountered bind value and type mismatch in parameter 2 + (err.message).should.startWith('NJS-011:'); + done(); + } + ); + }); // 75.1.13 + + it('75.1.14 works with 0', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { val: 0, type: oracledb.STRING, dir: oracledb.BIND_IN } + }; + + var sql = "INSERT INTO nodb_tab_clob_in (id, clob_1) VALUES (:i, :c)"; + connection.execute( + sql, + bindVar, + function(err) { + should.exist(err); + // NJS-011: encountered bind value and type mismatch in parameter 2 + (err.message).should.startWith('NJS-011:'); + done(); + } + ); + }); // 75.1.14 + + it('75.1.15 works with String length 32K', function(done) { + // Driver already supports CLOB AS STRING and BLOB AS BUFFER for PLSQL BIND if the data size less than or equal to 32767. + // As part of this enhancement, driver allows even if data size more than 32767 for both column types + var len = 32768; + var sequence = insertID++; + var specialStr = "75.1.15"; + var clobStr = random.getRandomString(len, specialStr); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { type: oracledb.STRING, dir: oracledb.BIND_OUT, maxSize: len } + }; + + async.series([ + function(cb) { + insertClobWithString(sequence, clobStr, cb); + }, + function(cb) { + verifyBindOutResult(sqlRun, bindVar, clobStr, specialStr, cb); + } + ], done); + }); // 75.1.15 + + it('75.1.16 works with String length (64K - 1)', function(done) { + // The upper limit on the number of bytes of data that can be bound as + // `STRING` or `BUFFER` when node-oracledb is linked with Oracle Client + // 11.2 libraries is 64 Kb. With Oracle Client 12, the limit is 1 Gb + + var len = 65535; + var sequence = insertID++; + var specialStr = "75.1.16"; + var clobStr = random.getRandomString(len, specialStr); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { type: oracledb.STRING, dir: oracledb.BIND_OUT, maxSize: len } + }; + + async.series([ + function(cb) { + insertClobWithString(sequence, clobStr, cb); + }, + function(cb) { + verifyBindOutResult(sqlRun, bindVar, clobStr, specialStr, cb); + } + ], done); + }); // 75.1.16 + + it('75.1.17 works with String length (64K + 1)', function(done) { + var len = 65537; + var sequence = insertID++; + var specialStr = "75.1.17"; + var clobStr = random.getRandomString(len, specialStr); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { type: oracledb.STRING, dir: oracledb.BIND_OUT, maxSize: len } + }; + + async.series([ + function(cb) { + insertClobWithString(sequence, clobStr, cb); + }, + function(cb) { + verifyBindOutResult(sqlRun, bindVar, clobStr, specialStr, cb); + }, + function(cb) { + file.delete(inFileStreamed); + cb(); + } + ], done); + }); // 75.1.17 + + it('75.1.18 works with String length (1MB + 1)', function(done) { + var len = 1048577; // 1 * 1024 * 1024 + 1 + var sequence = insertID++; + var specialStr = "75.1.18"; + var clobStr = random.getRandomString(len, specialStr); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { type: oracledb.STRING, dir: oracledb.BIND_OUT, maxSize: len } + }; + + async.series([ + function(cb) { + insertClobWithString(sequence, clobStr, cb); + }, + function(cb) { + verifyBindOutResult(sqlRun, bindVar, clobStr, specialStr, cb); + }, + function(cb) { + file.delete(inFileStreamed); + cb(); + } + ], done); + }); // 75.1.18 + + it('75.1.19 works with bind value and type mismatch', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { val: 100, type: oracledb.STRING, dir: oracledb.BIND_IN } + }; + + var sql = "INSERT INTO nodb_tab_clob_in (id, clob_1) VALUES (:i, :c)"; + connection.execute( + sql, + bindVar, + function(err) { + should.exist(err); + // NJS-011: encountered bind value and type mismatch in parameter 2 + (err.message).should.startWith('NJS-011:'); + done(); + } + ); + }); // 75.1.19 + + it('75.1.20 mixing named with positional binding', function(done) { + var len = 50000; + var sequence = insertID++; + var specialStr = "75.1.20"; + var clobStr = random.getRandomString(len, specialStr); + var bindVar = [ sequence, { type: oracledb.STRING, dir: oracledb.BIND_OUT, maxSize: len } ]; + + async.series([ + function(cb) { + insertClobWithString(sequence, clobStr, cb); + }, + function(cb) { + connection.execute( + sqlRun, + bindVar, + function(err, result) { + should.not.exist(err); + var resultVal = result.outBinds[0]; + compareResultStrAndOriginal(resultVal, clobStr, specialStr); + cb(); + } + ); + } + ], done); + }); // 75.1.20 + + it('75.1.21 works with UPDATE', function(done) { + var proc_7412 = "CREATE OR REPLACE PROCEDURE nodb_clobs_out_7412 (clob_id IN NUMBER, clob_out OUT CLOB, clob_in CLOB) \n" + + "AS \n" + + "BEGIN \n" + + " update nodb_tab_clob_in set clob_1 = clob_in where id = clob_id; \n" + + " select clob_1 into clob_out from nodb_tab_clob_in where id = clob_id; \n" + + "END nodb_clobs_out_7412; "; + var sqlRun_7412 = "BEGIN nodb_clobs_out_7412 (:i, :co, :ci); END;"; + var proc_drop_7412 = "DROP PROCEDURE nodb_clobs_out_7412"; + var sequence = insertID++; + var len_1 = 50000; + var specialStr_1 = "75.1.21_1"; + var clobStr_1 = random.getRandomString(len_1, specialStr_1); + var len_2 = 2000; + var specialStr_2 = "75.1.21_2"; + var clobStr_2 = random.getRandomString(len_2, specialStr_2); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + co: { type: oracledb.STRING, dir: oracledb.BIND_OUT, maxSize: len_1 }, + ci: { val:clobStr_2, type: oracledb.STRING, dir: oracledb.BIND_IN, maxSize: len_2 } + }; + + async.series([ + function(cb) { + insertClobWithString(sequence, clobStr_1, cb); + }, + function(cb) { + executeSQL(proc_7412, cb); + }, + function(cb) { + connection.execute( + sqlRun_7412, + bindVar, + function(err, result) { + should.not.exist(err); + var resultVal = result.outBinds.co; + compareResultStrAndOriginal(resultVal, clobStr_2, specialStr_2); + cb(); + } + ); + }, + function(cb) { + executeSQL(proc_drop_7412, cb); + } + ], done); + }); // 75.1.21 + + it('75.1.22 works with substr', function(done) { + var proc_7415 = "CREATE OR REPLACE PROCEDURE nodb_clobs_out_7415 (clob_id IN NUMBER, clob_out OUT CLOB) \n" + + "AS \n" + + "BEGIN \n" + + " select substr(clob_1, 1, 3) into clob_out from nodb_tab_clob_in where id = clob_id; \n" + + "END nodb_clobs_out_7415; "; + var sqlRun_7415 = "BEGIN nodb_clobs_out_7415 (:i, :co); END;"; + var proc_drop_7415 = "DROP PROCEDURE nodb_clobs_out_7415"; + var sequence = insertID++; + var len = 50000; + var specialStr = "75.1.22"; + var clobStr = random.getRandomString(len, specialStr); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + co: { type: oracledb.STRING, dir: oracledb.BIND_OUT, maxSize: len } + }; + + async.series([ + function(cb) { + insertClobWithString(sequence, clobStr, cb); + }, + function(cb) { + executeSQL(proc_7415, cb); + }, + function(cb) { + connection.execute( + sqlRun_7415, + bindVar, + function(err, result) { + should.not.exist(err); + var resultVal = result.outBinds.co; + // PLSQL substr function: the position starts from zero(0). + // The substring method extracts the characters in a string between "start" and "end", not including "end" itself. + clobStr = clobStr.substring(0, 3); + should.strictEqual(resultVal.length, 3); + should.strictEqual(resultVal, clobStr); + cb(); + } + ); + }, + function(cb) { + executeSQL(proc_drop_7415, cb); + } + ], done); + }); // 75.1.22 + + it('75.1.23 named binging, bind out maxSize smaller than string length ( < 32K )', function(done) { + var len = 300; + var sequence = insertID++; + var specialStr = "75.1.23"; + var clobStr = random.getRandomString(len, specialStr); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { type: oracledb.STRING, dir: oracledb.BIND_OUT, maxSize: len - 1 } + }; + + async.series([ + function(cb) { + insertClobWithString(sequence, clobStr, cb); + }, + function(cb) { + connection.execute( + sqlRun, + bindVar, + function(err) { + should.exist(err); + // ORA-06502: PL/SQL: numeric or value error: character string buffer too small + (err.message).should.startWith('ORA-06502:'); + cb(); + } + ); + } + ], done); + }); // 75.1.23 + + it('75.1.24 named binging, bind out maxSize smaller than string length ( > 32K )', function(done) { + var len = 50000; + var sequence = insertID++; + var specialStr = "75.1.24"; + var clobStr = random.getRandomString(len, specialStr); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { type: oracledb.STRING, dir: oracledb.BIND_OUT, maxSize: len - 1 } + }; + + async.series([ + function(cb) { + insertClobWithString(sequence, clobStr, cb); + }, + function(cb) { + connection.execute( + sqlRun, + bindVar, + function(err) { + should.exist(err); + // NJS-016: buffer is too small for OUT binds + (err.message).should.startWith('NJS-016:'); + cb(); + } + ); + } + ], done); + }); // 75.1.24 + + it('75.1.25 named binging, bind out maxSize smaller than string length ( > 64K )', function(done) { + var len = 50000; + var sequence = insertID++; + var specialStr = "75.1.25"; + var clobStr = random.getRandomString(len, specialStr); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { type: oracledb.STRING, dir: oracledb.BIND_OUT, maxSize: len - 1 } + }; + + async.series([ + function(cb) { + insertClobWithString(sequence, clobStr, cb); + }, + function(cb) { + connection.execute( + sqlRun, + bindVar, + function(err) { + should.exist(err); + // NJS-016: buffer is too small for OUT binds + (err.message).should.startWith('NJS-016:'); + cb(); + } + ); + } + ], done); + }); // 75.1.25 + + it('75.1.26 positional binging, bind out maxSize smaller than string length ( < 32K )', function(done) { + var len = 500; + var sequence = insertID++; + var specialStr = "75.1.26"; + var clobStr = random.getRandomString(len, specialStr); + sqlRun = "BEGIN nodb_clobs_out_741 (:1, :2); END;"; + var bindVar = [ sequence, { type: oracledb.STRING, dir: oracledb.BIND_OUT, maxSize: len - 1 } ]; + + async.series([ + function(cb) { + insertClobWithString(sequence, clobStr, cb); + }, + function(cb) { + connection.execute( + sqlRun, + bindVar, + function(err) { + should.exist(err); + // ORA-06502: PL/SQL: numeric or value error: character string buffer too small + (err.message).should.startWith('ORA-06502:'); + cb(); + } + ); + } + ], done); + }); // 75.1.26 + + it('75.1.27 positional binging, bind out maxSize smaller than string length ( > 32K )', function(done) { + var len = 50000; + var sequence = insertID++; + var specialStr = "75.1.27"; + var clobStr = random.getRandomString(len, specialStr); + sqlRun = "BEGIN nodb_clobs_out_741 (:1, :2); END;"; + var bindVar = [ sequence, { type: oracledb.STRING, dir: oracledb.BIND_OUT, maxSize: len - 1 } ]; + + async.series([ + function(cb) { + insertClobWithString(sequence, clobStr, cb); + }, + function(cb) { + connection.execute( + sqlRun, + bindVar, + function(err) { + should.exist(err); + // NJS-016: buffer is too small for OUT binds + (err.message).should.startWith('NJS-016:'); + cb(); + } + ); + } + ], done); + }); // 75.1.27 + + it('75.1.28 positional binging, bind out maxSize smaller than string length ( > 64K )', function(done) { + var len = 65539; + var sequence = insertID++; + var specialStr = "75.1.28"; + var clobStr = random.getRandomString(len, specialStr); + sqlRun = "BEGIN nodb_clobs_out_741 (:1, :2); END;"; + var bindVar = [ sequence, { type: oracledb.STRING, dir: oracledb.BIND_OUT, maxSize: len - 1 } ]; + + async.series([ + function(cb) { + insertClobWithString(sequence, clobStr, cb); + }, + function(cb) { + connection.execute( + sqlRun, + bindVar, + function(err) { + should.exist(err); + // NJS-016: buffer is too small for OUT binds + (err.message).should.startWith('NJS-016:'); + cb(); + } + ); + } + ], done); + }); // 75.1.28 + + }); // 75.1 + + describe('75.2 CLOB, PLSQL, BIND_OUT to VARCHAR2', function() { + var proc = "CREATE OR REPLACE PROCEDURE nodb_clobs_out_742 (clob_id IN NUMBER, clob_out OUT VARCHAR2) \n" + + "AS \n" + + "BEGIN \n" + + " select clob_1 into clob_out from nodb_tab_clob_in where id = clob_id; \n" + + "END nodb_clobs_out_742; "; + var sqlRun = "BEGIN nodb_clobs_out_742 (:i, :c); END;"; + var proc_drop = "DROP PROCEDURE nodb_clobs_out_742"; + + before(function(done) { + executeSQL(proc, done); + }); // before + + after(function(done) { + executeSQL(proc_drop, done); + }); // after + + it('75.2.1 works with EMPTY_LOB', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { type: oracledb.STRING, dir: oracledb.BIND_OUT } + }; + + async.series([ + function(cb) { + insertClobWithString(sequence, "EMPTY_LOB", cb); + }, + function(cb) { + verifyBindOutResult(sqlRun, bindVar, "EMPTY_LOB", null, cb); + } + ], done); + }); // 75.2.1 + + it('75.2.2 works with EMPTY_LOB and bind out maxSize set to 1', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { type: oracledb.STRING, dir: oracledb.BIND_OUT, maxSize: 1 } + }; + + async.series([ + function(cb) { + insertClobWithString(sequence, "EMPTY_LOB", cb); + }, + function(cb) { + verifyBindOutResult(sqlRun, bindVar, "EMPTY_LOB", null, cb); + } + ], done); + }); // 75.2.2 + + it('75.2.3 works with EMPTY_LOB and bind out maxSize set to (64k - 1)', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { type: oracledb.STRING, dir: oracledb.BIND_OUT, maxSize: 65535 } + }; + + async.series([ + function(cb) { + insertClobWithString(sequence, "EMPTY_LOB", cb); + }, + function(cb) { + verifyBindOutResult(sqlRun, bindVar, "EMPTY_LOB", null, cb); + } + ], done); + }); // 75.2.3 + + it('75.2.4 works with null', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { type: oracledb.STRING, dir: oracledb.BIND_OUT } + }; + + async.series([ + function(cb) { + insertClobWithString(sequence, null, cb); + }, + function(cb) { + verifyBindOutResult(sqlRun, bindVar, null, null, cb); + } + ], done); + }); // 75.2.4 + + it('75.2.5 works with null and bind out maxSize set to 1', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { type: oracledb.STRING, dir: oracledb.BIND_OUT, maxSize: 1 } + }; + + async.series([ + function(cb) { + insertClobWithString(sequence, null, cb); + }, + function(cb) { + verifyBindOutResult(sqlRun, bindVar, null, null, cb); + } + ], done); + }); // 75.2.5 + + it('75.2.6 works with null and bind out maxSize set to (64k - 1)', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { type: oracledb.STRING, dir: oracledb.BIND_OUT, maxSize: 65535 } + }; + + async.series([ + function(cb) { + insertClobWithString(sequence, null, cb); + }, + function(cb) { + verifyBindOutResult(sqlRun, bindVar, null, null, cb); + } + ], done); + }); // 75.2.6 + + it('75.2.7 works with empty string', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { type: oracledb.STRING, dir: oracledb.BIND_OUT } + }; + + async.series([ + function(cb) { + insertClobWithString(sequence, "", cb); + }, + function(cb) { + verifyBindOutResult(sqlRun, bindVar, "", null, cb); + } + ], done); + }); // 75.2.7 + + it('75.2.8 works with empty string and bind out maxSize set to 1', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { type: oracledb.STRING, dir: oracledb.BIND_OUT, maxSize: 1 } + }; + + async.series([ + function(cb) { + insertClobWithString(sequence, "", cb); + }, + function(cb) { + verifyBindOutResult(sqlRun, bindVar, "", null, cb); + } + ], done); + }); // 75.2.8 + + it('75.2.9 works with empty string and bind out maxSize set to (64K - 1)', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { type: oracledb.STRING, dir: oracledb.BIND_OUT, maxSize: 65535 } + }; + + async.series([ + function(cb) { + insertClobWithString(sequence, "", cb); + }, + function(cb) { + verifyBindOutResult(sqlRun, bindVar, "", null, cb); + } + ], done); + }); // 75.2.9 + + it('75.2.10 works with undefined', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { type: oracledb.STRING, dir: oracledb.BIND_OUT } + }; + + async.series([ + function(cb) { + insertClobWithString(sequence, undefined, cb); + }, + function(cb) { + verifyBindOutResult(sqlRun, bindVar, undefined, null, cb); + } + ], done); + }); // 75.2.10 + + it('75.2.11 works with undefined and bind out maxSize set to 1', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { type: oracledb.STRING, dir: oracledb.BIND_OUT, maxSize: 1 } + }; + + async.series([ + function(cb) { + insertClobWithString(sequence, undefined, cb); + }, + function(cb) { + verifyBindOutResult(sqlRun, bindVar, undefined, null, cb); + } + ], done); + }); // 75.2.11 + + it('75.2.12 works with undefined and bind out maxSize set to (64K - 1)', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { type: oracledb.STRING, dir: oracledb.BIND_OUT, maxSize: 65535 } + }; + + async.series([ + function(cb) { + insertClobWithString(sequence, undefined, cb); + }, + function(cb) { + verifyBindOutResult(sqlRun, bindVar, undefined, null, cb); + } + ], done); + }); // 75.2.12 + + it('75.2.13 works with NaN', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { val: NaN, type: oracledb.STRING, dir: oracledb.BIND_IN } + }; + + var sql = "INSERT INTO nodb_tab_clob_in (id, clob_1) VALUES (:i, :c)"; + connection.execute( + sql, + bindVar, + function(err) { + should.exist(err); + // NJS-011: encountered bind value and type mismatch in parameter 2 + (err.message).should.startWith('NJS-011:'); + done(); + } + ); + }); // 75.2.13 + + it('75.2.14 works with 0', function(done) { + var sequence = insertID++; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { val: 0, type: oracledb.STRING, dir: oracledb.BIND_IN } + }; + + var sql = "INSERT INTO nodb_tab_clob_in (id, clob_1) VALUES (:i, :c)"; + connection.execute( + sql, + bindVar, + function(err) { + should.exist(err); + // NJS-011: encountered bind value and type mismatch in parameter 2 + (err.message).should.startWith('NJS-011:'); + done(); + } + ); + }); // 75.2.14 + + it('75.2.15 works with String length (32K - 1)', function(done) { + var len = 32767; + var sequence = insertID++; + var specialStr = "75.2.15"; + var clobStr = random.getRandomString(len, specialStr); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { type: oracledb.STRING, dir: oracledb.BIND_OUT, maxSize: len } + }; + + async.series([ + function(cb) { + insertClobWithString(sequence, clobStr, cb); + }, + function(cb) { + verifyBindOutResult(sqlRun, bindVar, clobStr, specialStr, cb); + } + ], done); + }); // 75.2.15 + + it('75.2.16 works with String length 32K', function(done) { + var len = 32768; + var sequence = insertID++; + var specialStr = "75.2.16"; + var clobStr = random.getRandomString(len, specialStr); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { type: oracledb.STRING, dir: oracledb.BIND_OUT, maxSize: len } + }; + + async.series([ + function(cb) { + insertClobWithString(sequence, clobStr, cb); + }, + function(cb) { + connection.execute( + sqlRun, + bindVar, + function(err) { + should.exist(err); + // ORA-06502: PL/SQL: numeric or value error + (err.message).should.startWith('ORA-06502:'); + cb(); + } + ); + } + ], done); + }); // 75.2.16 + + it('75.2.17 works with bind out maxSize smaller than string length', function(done) { + var len = 500; + var sequence = insertID++; + var specialStr = "75.2.17"; + var clobStr = random.getRandomString(len, specialStr); + var bindVar = [ sequence, { type: oracledb.STRING, dir: oracledb.BIND_OUT, maxSize: len - 1 } ]; + + async.series([ + function(cb) { + insertClobWithString(sequence, clobStr, cb); + }, + function(cb) { + connection.execute( + sqlRun, + bindVar, + function(err) { + should.exist(err); + // ORA-06502: PL/SQL: numeric or value error + (err.message).should.startWith('ORA-06502:'); + cb(); + } + ); + } + ], done); + }); // 75.2.17 + + it('75.2.18 works with UPDATE', function(done) { + var proc_7518 = "CREATE OR REPLACE PROCEDURE nodb_clobs_out_7518 (clob_id IN NUMBER, clob_out OUT CLOB, clob_in VARCHAR2) \n" + + "AS \n" + + "BEGIN \n" + + " update nodb_tab_clob_in set clob_1 = clob_in where id = clob_id; \n" + + " select clob_1 into clob_out from nodb_tab_clob_in where id = clob_id; \n" + + "END nodb_clobs_out_7518; "; + var sqlRun_7518 = "BEGIN nodb_clobs_out_7518 (:i, :co, :ci); END;"; + var proc_drop_7518 = "DROP PROCEDURE nodb_clobs_out_7518"; + var sequence = insertID++; + var len_1 = 500; + var specialStr_1 = "75.2.18_1"; + var clobStr_1 = random.getRandomString(len_1, specialStr_1); + var len_2 = 200; + var specialStr_2 = "75.2.18_2"; + var clobStr_2 = random.getRandomString(len_2, specialStr_2); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + co: { type: oracledb.STRING, dir: oracledb.BIND_OUT, maxSize: len_1 }, + ci: { val:clobStr_2, type: oracledb.STRING, dir: oracledb.BIND_IN, maxSize: len_2 } + }; + + async.series([ + function(cb) { + insertClobWithString(sequence, clobStr_1, cb); + }, + function(cb) { + executeSQL(proc_7518, cb); + }, + function(cb) { + connection.execute( + sqlRun_7518, + bindVar, + function(err, result) { + should.not.exist(err); + var resultVal = result.outBinds.co; + compareResultStrAndOriginal(resultVal, clobStr_2, specialStr_2); + cb(); + } + ); + }, + function(cb) { + executeSQL(proc_drop_7518, cb); + } + ], done); + }); // 75.2.18 + + it('75.2.19 works with substr', function(done) { + var proc_7519 = "CREATE OR REPLACE PROCEDURE nodb_clobs_out_7519 (clob_id IN NUMBER, clob_out OUT VARCHAR2) \n" + + "AS \n" + + "BEGIN \n" + + " select substr(clob_1, 1, 3) into clob_out from nodb_tab_clob_in where id = clob_id; \n" + + "END nodb_clobs_out_7519; "; + var sqlRun_7519 = "BEGIN nodb_clobs_out_7519 (:i, :co); END;"; + var proc_drop_7519 = "DROP PROCEDURE nodb_clobs_out_7519"; + var sequence = insertID++; + var len = 500; + var specialStr = "75.2.19"; + var clobStr = random.getRandomString(len, specialStr); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + co: { type: oracledb.STRING, dir: oracledb.BIND_OUT, maxSize: len } + }; + + async.series([ + function(cb) { + insertClobWithString(sequence, clobStr, cb); + }, + function(cb) { + executeSQL(proc_7519, cb); + }, + function(cb) { + connection.execute( + sqlRun_7519, + bindVar, + function(err, result) { + should.not.exist(err); + var resultVal = result.outBinds.co; + // PLSQL substr function: the position starts from zero(0). + // The substring method extracts the characters in a string between "start" and "end", not including "end" itself. + clobStr = clobStr.substring(0, 3); + should.strictEqual(resultVal.length, 3); + should.strictEqual(resultVal, clobStr); + cb(); + } + ); + }, + function(cb) { + executeSQL(proc_drop_7519, cb); + } + ], done); + }); // 75.2.19 + + }); // 75.2 + + describe('75.3 Multiple CLOBs, BIND_OUT', function() { + var proc = "CREATE OR REPLACE PROCEDURE nodb_lobs_out_745 (clob_id IN NUMBER, clob_1 OUT CLOB, clob_2 OUT CLOB) \n" + + "AS \n" + + "BEGIN \n" + + " select clob_1, clob_2 into clob_1, clob_2 from nodb_tab_clob_in where id = clob_id; \n" + + "END nodb_lobs_out_745; "; + var sqlRun = "BEGIN nodb_lobs_out_745 (:i, :c1, :c2); END;"; + var proc_drop = "DROP PROCEDURE nodb_lobs_out_745"; + + before(function(done) { + executeSQL(proc, done); + }); // before + + after(function(done) { + executeSQL(proc_drop, done); + }); // after + + var insertTwoClobWithString = function(id, insertStr1, insertStr2, callback) { + var sql = "INSERT INTO nodb_tab_clob_in (id, clob_1, clob_2) VALUES (:i, :c1, :c2)"; + var bindVar = { + i: { val: id, dir: oracledb.BIND_IN, type: oracledb.NUMBER }, + c1: { val: insertStr1, dir: oracledb.BIND_IN, type: oracledb.STRING }, + c2: { val: insertStr2, dir: oracledb.BIND_IN, type: oracledb.STRING } + }; + + connection.execute( + sql, + bindVar, + function(err, result) { + should.not.exist(err); + should.strictEqual(result.rowsAffected, 1); + callback(); + } + ); + }; + + it('75.3.1 bind two string', function(done) { + var sequence = insertID++; + var specialStr_1 = "75.3.1_1"; + var specialStr_2 = "75.3.1_2"; + var len1 = 50000; + var len2 = 10000; + var clobStr_1 = random.getRandomString(len1, specialStr_1); + var clobStr_2 = random.getRandomString(len2, specialStr_2); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c1: { type: oracledb.STRING, dir: oracledb.BIND_OUT, maxSize: len1 }, + c2: { type: oracledb.STRING, dir: oracledb.BIND_OUT, maxSize: len2 } + }; + + async.series([ + function(cb) { + insertTwoClobWithString(sequence, clobStr_1, clobStr_2, cb); + }, + function(cb) { + connection.execute( + sqlRun, + bindVar, + function(err, result) { + should.not.exist(err); + var resultVal = result.outBinds.c1; + compareResultStrAndOriginal(resultVal, clobStr_1, specialStr_1); + resultVal = result.outBinds.c2; + compareResultStrAndOriginal(resultVal, clobStr_2, specialStr_2); + cb(); + } + ); + } + ], done); + + }); // 75.3.1 + + it('75.3.2 bind a txt file and a string', function(done) { + var specialStr = "75.3.2"; + var sequence = insertID++; + var len1 = 50000; + var clobStr_1 = random.getRandomString(len1, specialStr); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c1: { type: oracledb.STRING, dir: oracledb.BIND_OUT, maxSize: len1 }, + c2: { type: oracledb.CLOB, dir: oracledb.BIND_OUT } + }; + + async.series([ + function(cb) { + var sql = "INSERT INTO nodb_tab_clob_in (id, clob_2) VALUES (:i, EMPTY_CLOB()) RETURNING clob_2 INTO :lobbv"; + prepareTableWithClob(sql, sequence, cb); + }, + function(cb) { + var sql = "select clob_2 from nodb_tab_clob_in where id = " + sequence; + verifyClobValueWithFileData(sql, cb); + }, + function(cb) { + var sql = "UPDATE nodb_tab_clob_in set clob_1 = :c where id = :i"; + var bindVar_1 = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { val: clobStr_1, type: oracledb.STRING, dir: oracledb.BIND_IN, maxSize: len1 } + }; + connection.execute( + sql, + bindVar_1, + function(err, result) { + should.not.exist(err); + should.strictEqual(result.rowsAffected, 1); + cb(); + }); + }, + function(cb) { + connection.execute( + sqlRun, + bindVar, + function(err, result) { + should.not.exist(err); + var resultVal = result.outBinds.c1; + compareResultStrAndOriginal(resultVal, clobStr_1, specialStr); + + var lob = result.outBinds.c2; + should.exist(lob); + lob.setEncoding("utf8"); + var clobData = ''; + lob.on('data', function(chunk) { + clobData += chunk; + }); + + lob.on('error', function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + lob.on('end', function() { + fs.readFile( preparedInFileName, { encoding: 'utf8' }, function(err, originalData) { + should.not.exist(err); + should.strictEqual(clobData, originalData); + }); + }); + cb(); + } + ); + } + ], done); + + }); // 75.3.2 + + it('75.3.3 bind two string, one > (64K - 1)', function(done) { + var sequence = insertID++; + var specialStr_1 = "75.3.3_1"; + var specialStr_2 = "75.3.3_2"; + var len1 = 65538; + var len2 = 10000; + var clobStr_1 = random.getRandomString(len1, specialStr_1); + var clobStr_2 = random.getRandomString(len2, specialStr_2); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c1: { type: oracledb.STRING, dir: oracledb.BIND_OUT, maxSize: len1 }, + c2: { type: oracledb.STRING, dir: oracledb.BIND_OUT, maxSize: len2 } + }; + + async.series([ + function(cb) { + insertTwoClobWithString(sequence, clobStr_1, clobStr_2, cb); + }, + function(cb) { + connection.execute( + sqlRun, + bindVar, + function(err, result) { + should.not.exist(err); + var resultVal = result.outBinds.c1; + compareResultStrAndOriginal(resultVal, clobStr_1, specialStr_1); + resultVal = result.outBinds.c2; + compareResultStrAndOriginal(resultVal, clobStr_2, specialStr_2); + cb(); + } + ); + } + ], done); + + }); // 75.3.3 + + }); // 75.3 + +}); diff --git a/test/constants.js b/test/constants.js new file mode 100644 index 00000000..49ef1747 --- /dev/null +++ b/test/constants.js @@ -0,0 +1,83 @@ +/* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with the Apache + * License, Version 2.0 (the "License.") + * + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + * The node-oracledb test suite uses 'mocha', 'should' and 'async'. + * See LICENSE.md for relevant licenses. + * + * NAME + * 18. constants.js + * + * DESCRIPTION + * Check the mapping between names and numbers of oracledb constants. + * + * NUMBERING RULE + * Test numbers follow this numbering rule: + * 1 - 20 are reserved for basic functional tests + * 21 - 50 are reserved for data type supporting tests + * 51 onwards are for other tests + * + *****************************************************************************/ +'use strict'; + +var oracledb = require('oracledb'); +var should = require('should'); + +describe('18. constants.js', function() { + + it('18.1 dbTypes maps correctly between names and numbers', function() { + + should.exist(oracledb); + (oracledb.DB_TYPE_VARCHAR).should.be.exactly(1); + (oracledb.DB_TYPE_NUMBER).should.be.exactly(2); + (oracledb.DB_TYPE_DATE).should.be.exactly(12); + (oracledb.DB_TYPE_RAW).should.be.exactly(23); + (oracledb.DB_TYPE_CHAR).should.be.exactly(96); + (oracledb.DB_TYPE_BINARY_FLOAT).should.be.exactly(100); + (oracledb.DB_TYPE_BINARY_DOUBLE).should.be.exactly(101); + (oracledb.DB_TYPE_ROWID).should.be.exactly(104); + (oracledb.DB_TYPE_CLOB).should.be.exactly(112); + (oracledb.DB_TYPE_BLOB).should.be.exactly(113); + (oracledb.DB_TYPE_TIMESTAMP).should.be.exactly(187); + (oracledb.DB_TYPE_TIMESTAMP_TZ).should.be.exactly(188); + (oracledb.DB_TYPE_TIMESTAMP_LTZ).should.be.exactly(232); + + }); + + it('18.2 jsTypes maps correctly', function() { + + (oracledb.DEFAULT).should.be.exactly(0); + (oracledb.STRING).should.be.exactly(2001); + (oracledb.NUMBER).should.be.exactly(2002); + (oracledb.DATE).should.be.exactly(2003); + (oracledb.CURSOR).should.be.exactly(2004); + (oracledb.BUFFER).should.be.exactly(2005); + (oracledb.CLOB).should.be.exactly(2006); + (oracledb.BLOB).should.be.exactly(2007); + + }); + + it('18.3 binding contants maps correctly', function() { + + (oracledb.BIND_IN).should.be.exactly(3001); + (oracledb.BIND_INOUT).should.be.exactly(3002); + (oracledb.BIND_OUT).should.be.exactly(3003); + (oracledb.ARRAY).should.be.exactly(4001); + (oracledb.OBJECT).should.be.exactly(4002); + + }); + +}); diff --git a/test/devnull.js b/test/devnull.js new file mode 100644 index 00000000..5c2dac31 --- /dev/null +++ b/test/devnull.js @@ -0,0 +1,50 @@ +/* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with the Apache + * License, Version 2.0 (the "License.") + * + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + * The node-oracledb test suite uses 'mocha', 'should' and 'async'. + * See LICENSE.md for relevant licenses. + * + * NAME + * devnull.js + * + * DESCRIPTION + * /dev/null for Node streams + * + *****************************************************************************/ +'use strict'; + +var stream = require('stream'); +var util = require('util'); + +module.exports = DevNull; + +// step 2 - to call the Writable constructor in our own constructor +function DevNull(opts) { + if ( !(this instanceof DevNull) ) return new DevNull(opts); + + opts = opts || {}; + stream.Writable.call(this, opts); + +} + +// step 1 - to extend the Writable Class +util.inherits(DevNull, stream.Writable); + +// step 3 -define a '_write()' method in the prototype of our stream object +DevNull.prototype._write = function(chunk, encoding, cb) { + setImmediate(cb); +}; diff --git a/test/driverName.js b/test/driverName.js new file mode 100644 index 00000000..f82a3b86 --- /dev/null +++ b/test/driverName.js @@ -0,0 +1,106 @@ +/* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with the Apache + * License, Version 2.0 (the "License.") + * + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + * The node-oracledb test suite uses 'mocha', 'should' and 'async'. + * See LICENSE.md for relevant licenses. + * + * NAME + * 69. driverName.js + * + * DESCRIPTION + * Testing external authentication functionality. + * + * Note that enabling the externalAuth feature requires configuration on the + * database besides setting "externalAuth" attribute to be true. Please refer + * to api doc about the configuration. + * https://github.com/oracle/node-oracledb/blob/master/doc/api.md#extauth + * + * NUMBERING RULE + * Test numbers follow this numbering rule: + * 1 - 20 are reserved for basic functional tests + * 21 - 50 are reserved for data type supporting tests + * 51 onwards are for other tests + * + *****************************************************************************/ + +'use strict'; + +var oracledb = require('oracledb'); +var should = require('should'); +var async = require('async'); +var dbConfig = require('./dbconfig.js'); + +describe('69. driverName.js', function() { + + var getAddonVer = function() { + var addonVer = oracledb.version; + var major = Math.floor (addonVer / 10000); + var minor = Math.floor(addonVer / 100) % 100; + var update = addonVer % 100; + + return (major + '.' + minor + '.' + update); + }; + + it("69.1 checks the driver name", function(done) { + + async.waterfall([ + function(cb) { + oracledb.createPool(dbConfig, cb); + }, + function(pool, cb) { + pool.should.be.ok(); + pool.getConnection( function(err, connection) { + cb(err, connection, pool); + }); + }, + function(connection, pool, cb) { + var sql = "select distinct client_driver from v$session_connect_info where sid = sys_context('USERENV', 'SID')"; + connection.should.be.ok(); + connection.execute( + sql, + function(err, result) { + + var serverVer = connection.oracleServerVersion; + + // Since 12.1.0.2, OCI_ATTR_DRIVER_NAME with 30 characters has been supported + // Database server can then return the full driver name, e.g. 'node-oracledb 1.11' + if(serverVer >= 1201000200) { + var addonVer = getAddonVer(); + (result.rows[0][0].trim()).should.equal("node-oracledb : " + addonVer); + } + // previous databases only returns the first 8 characters of the driver name + else { + (result.rows[0][0]).should.equal("node-ora"); + } + + cb(err, connection, pool); + } + ); + } + ], function(err, connection, pool) { + should.not.exist(err); + connection.close( function(err) { + should.not.exist(err); + pool.close(function(err) { + should.not.exist(err); + done(); + }); + }); + }); // async + + }); +}); diff --git a/test/externalAuth.js b/test/externalAuth.js new file mode 100644 index 00000000..ddbe95ef --- /dev/null +++ b/test/externalAuth.js @@ -0,0 +1,495 @@ +/* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with the Apache + * License, Version 2.0 (the "License.") + * + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + * The node-oracledb test suite uses 'mocha', 'should' and 'async'. + * See LICENSE.md for relevant licenses. + * + * NAME + * 5. externalAuth.js + * + * DESCRIPTION + * Testing external authentication functionality. + * + * Note that enabling the externalAuth feature requires configuration on the + * database besides setting "externalAuth" attribute to be true. Please refer + * to api doc about the configuration. + * https://github.com/oracle/node-oracledb/blob/master/doc/api.md#extauth + * + * NUMBERING RULE + * Test numbers follow this numbering rule: + * 1 - 20 are reserved for basic functional tests + * 21 - 50 are reserved for data type supporting tests + * 51 onwards are for other tests + * + *****************************************************************************/ +'use strict'; + +var oracledb = require('oracledb'); +var should = require('should'); +var async = require('async'); +var dbConfig = require('./dbconfig.js'); + +describe('5. externalAuth.js', function() { + + describe('5.1 tests that work both when DB has configured externalAuth and not configured', function() { + + it('5.1.1 can get connection from oracledb with correct user/password when externalAuth is disabled', function(done) { + + async.waterfall([ + function(callback) { + oracledb.getConnection( + { + externalAuth: false, + user: dbConfig.user, + password: dbConfig.password, + connectString: dbConfig.connectString + }, + function(err, connection) { + callback(err, connection); + } + ); + }, + function(connection, callback) { + connection.execute( + "select (7+8) from dual", + function(err, result) { + (result.rows[0][0]).should.equal(15); + callback(err, connection); + } + ); + } + ], function(err, connection) { + should.not.exist(err); + connection.release( function(err) { + should.not.exist(err); + done(); + }); + }); + + }); // 5.1.1 + + it('5.1.2 throws error when getting connection from oracledb with correct user/password when externalAuth is enabled', function(done) { + + oracledb.getConnection( + { + externalAuth: true, + user: dbConfig.user, + password: dbConfig.password, + connectString: dbConfig.connectString + }, + function(err, conn){ + should.exist(err); + (err.message).should.startWith("DPI-1032:"); + // DPI-1032: user and password should not be set when using external authentication + should.not.exist(conn); + done(); + } + ); + + }); // 5.1.2 + + it("5.1.3 throws error when gettting connection from oracledb given only 'user' when externalAuth is enabled", function(done) { + + oracledb.getConnection( + { + externalAuth: true, + user: dbConfig.user, + connectString: dbConfig.connectString + }, + function(err, conn){ + should.exist(err); + (err.message).should.startWith("DPI-1032:"); + // DPI-1032: user and password should not be set when using external authentication + should.not.exist(conn); + done(); + } + ); + + }); // 5.1.3 + + it("5.1.4 throws error when gettting connection from oracledb given only 'password' when externalAuth is enabled", function(done) { + + oracledb.getConnection( + { + externalAuth: true, + password: dbConfig.password, + connectString: dbConfig.connectString + }, + function(err, conn){ + should.exist(err); + (err.message).should.startWith("DPI-1032:"); + // DPI-1032: user and password should not be set when using external authentication + + should.not.exist(conn); + done(); + } + ); + + }); // 5.1.4 + + it("5.1.5 can get pool from oracledb with user/password when externalAuth is disabled", function(done) { + + async.waterfall([ + function(callback) { + oracledb.createPool( + { + externalAuth: false, + user: dbConfig.user, + password: dbConfig.password, + connectString: dbConfig.connectString + }, + function(err, pool) { + callback(err, pool); + } + ); + }, + function(pool, callback) { + pool.getConnection(function(err, connection) { + callback(err, connection, pool); + }); + }, + function(connection, pool, callback) { + connection.execute( + "select (3+5) from dual", + function(err, result) { + (result.rows[0][0]).should.equal(8); + callback(err, connection, pool); + } + ); + } + ], function(err, connection, pool) { + should.not.exist(err); + connection.close( function(err) { + should.not.exist(err); + pool.close( function(err) { + should.not.exist(err); + done(); + }); + }); + }); + + }); // 5.1.5 + + it("5.1.6 throws error when getting pool from oracledb given user/password when externalAuth is enabled", function(done) { + + oracledb.createPool( + { + externalAuth: true, + user: dbConfig.user, + password: dbConfig.password, + connectString: dbConfig.connectString + }, + function(err, pool) { + should.exist(err); + (err.message).should.startWith("DPI-1032:"); + // DPI-1032: user and password should not be set when using external authentication + should.not.exist(pool); + done(); + } + ); + + }); // 5.1.6 + + it("5.1.7 throws error when getting pool from oracledb only given username when externalAuth is enabled", function(done) { + + oracledb.createPool( + { + externalAuth: true, + user: dbConfig.user, + connectString: dbConfig.connectString + }, + function(err, pool) { + should.exist(err); + (err.message).should.startWith("DPI-1032:"); + should.not.exist(pool); + done(); + } + ); + + }); + + it("5.1.8 throws error when getting pool from oracledb only given password when externalAuth is enabled", function(done) { + + oracledb.createPool( + { + externalAuth: true, + password: dbConfig.password, + connectString: dbConfig.connectString + }, + function(err, pool) { + should.exist(err); + (err.message).should.startWith("DPI-1032:"); + should.not.exist(pool); + done(); + } + ); + + }); + + }); // 5.1 + + describe('5.2 tests only work when externalAuth is configured on DB', function() { + + before(function() { + if ( !(process.env.NODE_ORACLEDB_EXTERNALAUTH) ) this.skip(); + }); + + it("5.2.1 can get connection from oracledb with external authentication", function(done) { + + async.waterfall([ + function(callback) { + oracledb.getConnection( + { + externalAuth: true, + connectString: dbConfig.connectString + }, + function(err, connection) { + callback(err, connection); + } + ); + }, + function(connection, callback) { + connection.execute( + "select (7+8) from dual", + function(err, result) { + (result.rows[0][0]).should.equal(15); + callback(err, connection); + } + ); + } + ], function(err, connection) { + should.not.exist(err); + connection.release( function(err) { + should.not.exist(err); + done(); + }); + }); + + }); // 5.2.1 + + it("5.2.2 can get pool from oracledb with external authentication", function(done) { + + async.waterfall([ + function(callback) { + oracledb.createPool( + { + externalAuth: true, + connectString: dbConfig.connectString + }, + function(err, pool) { + // verify poolMin value + (pool.connectionsOpen).should.be.exactly(0); + callback(err, pool); + } + ); + }, + function(pool, callback) { + pool.getConnection( function(err, connection) { + callback(err, connection, pool); + }); + }, + function(connection, pool, callback) { + connection.execute( + "select (3+5) from dual", + function(err, result) { + (result.rows[0][0]).should.equal(8); + callback(err, connection, pool); + } + ); + } + ], function(err, connection, pool) { + should.not.exist(err); + connection.close( function(err) { + should.not.exist(err); + pool.close(function(err) { + should.not.exist(err); + done(); + }); + }); + }); + + }); // 5.2.2 + + it("5.2.3 gets multiple connections from oracledb", function(done) { + + var getConns = function(id, callback) { + oracledb.getConnection( + { + externalAuth: true, + connectString: dbConfig.connectString + }, + function(err, connection) { + callback(err, { + num: id, + inst: connection + }); + } + ); + }; + + var closeConns = function(conns, cb) { + async.map(conns, function(item, callback) { + // console.log("-- close conn " + item.num); + var connection = item.inst; + connection.execute( + "select (5+7) from dual", + function(err, result) { + should.not.exist(err); + (result.rows[0][0]).should.equal(12); + connection.close(callback); + } + ); + }, function(err) { + should.not.exist(err); + cb(); + }); + }; + + // Main function of this case + async.times(9, function(n, next) { + getConns(n, function(err, conn) { + next(err, conn); + }); + }, function(err, arr) { + should.not.exist(err); + closeConns(arr, done); + }); + + }); // 5.2.3 + + it("5.2.4 gets multiple pools from oracledb", function(done) { + + var getPools = function(id, callback) { + oracledb.createPool( + { + externalAuth: true, + connectString: dbConfig.connectString + }, + function(err, pool) { + callback(err, { + num: id, + inst: pool + }); + } + ); + }; + + var closePools = function(pools, cb) { + async.map(pools, function(item, callback) { + // console.log("-- close pool " + item.num); + var pool = item.inst; + pool.getConnection(function(err, connection) { + should.not.exist(err); + connection.execute( + "select (8+9) from dual", + function(err, result) { + should.not.exist(err); + (result.rows[0][0]).should.equal(17); + connection.close(function(err) { + should.not.exist(err); + pool.close(callback); + }); + } + ); + }); + }, function(err) { + should.not.exist(err); + cb(); + }); + }; + + // Main function of this case + async.times(9, function(n, next) { + getPools(n, function(err, poolInst) { + next(err, poolInst); + }); + }, function(err, arr) { + should.not.exist(err); + closePools(arr, done); + }); + + }); // 5.2.4 + + it("5.2.5 poolMin no longer takes effect under externalAuth", function(done) { + + oracledb.createPool( + { + externalAuth: true, + connectString: dbConfig.connectString, + poolMin: 5, + poolMax: 20, + poolIncrement: 2 + }, + function(err, pool) { + (pool.connectionsOpen).should.be.exactly(0); + + pool.close(function(err) { + should.not.exist(err); + done(); + }); + } + ); + + }); + + it("5.2.6 poolIncrement no longer takes effect", function(done) { + + async.waterfall([ + function(callback) { + oracledb.createPool( + { + externalAuth: true, + connectString: dbConfig.connectString, + poolMin: 5, + poolMax: 20, + poolIncrement: 2 + }, + function(err, pool) { + callback(err, pool); + } + ); + }, + function(pool, callback) { + pool.getConnection( function(err, conn1) { + (pool.connectionsOpen).should.be.exactly(1); + callback(err, conn1, pool); + }); + }, + function(conn1, pool, callback) { + pool.getConnection( function(err, conn2) { + (pool.connectionsOpen).should.be.exactly(2); + callback(err, conn1, conn2, pool); + }); + } + ], function(err, conn1, conn2, pool) { + should.not.exist(err); + conn1.close( function(err) { + should.not.exist(err); + conn2.close(function(err) { + should.not.exist(err); + pool.close(function(err) { + should.not.exist(err); + done(); + }); + }); + }); + }); + }); + + }); // 5.2 + +}); diff --git a/test/fetchBlobAsBuffer1.js b/test/fetchBlobAsBuffer1.js new file mode 100644 index 00000000..23c080c4 --- /dev/null +++ b/test/fetchBlobAsBuffer1.js @@ -0,0 +1,2850 @@ +/* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with the Apache + * License, Version 2.0 (the "License.") + * + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + * The node-oracledb test suite uses 'mocha', 'should' and 'async'. + * See LICENSE.md for relevant licenses. + * + * NAME + * 87. fetchBlobAsBuffer1.js + * + * DESCRIPTION + * Testing Oracle data type support - BLOB. + * To fetch BLOB columns as buffer by setting oracledb.fetchAsBuffer. + * + * NUMBERING RULE + * Test numbers follow this numbering rule: + * 1 - 20 are reserved for basic functional tests + * 21 - 50 are reserved for data type supporting tests + * 51 onwards are for other tests + * + *****************************************************************************/ +'use strict'; + +var oracledb = require('oracledb'); +var async = require('async'); +var should = require('should'); +var file = require('./file.js'); +var dbConfig = require('./dbconfig.js'); +var random = require('./random.js'); +var assist = require('./dataTypeAssist.js'); + +describe('87. fetchBlobAsBuffer1.js', function() { + this.timeout(100000); + var connection = null; + var node6plus = false; // assume node runtime version is lower than 6 + var insertID = 1; // assume id for insert into db starts from 1 + var inFileName = './test/blobTmpFile.txt'; + + var proc_create_table1 = "BEGIN \n" + + " DECLARE \n" + + " e_table_missing EXCEPTION; \n" + + " PRAGMA EXCEPTION_INIT(e_table_missing, -00942);\n" + + " BEGIN \n" + + " EXECUTE IMMEDIATE ('DROP TABLE nodb_blob1 PURGE' ); \n" + + " EXCEPTION \n" + + " WHEN e_table_missing \n" + + " THEN NULL; \n" + + " END; \n" + + " EXECUTE IMMEDIATE ( ' \n" + + " CREATE TABLE nodb_blob1 ( \n" + + " ID NUMBER, \n" + + " B BLOB \n" + + " ) \n" + + " '); \n" + + "END; "; + var drop_table1 = "DROP TABLE nodb_blob1 PURGE"; + + before('get one connection', function(done) { + async.series([ + function(cb) { + oracledb.stmtCacheSize = 0; + oracledb.getConnection(dbConfig, function(err, conn) { + should.not.exist(err); + connection = conn; + if(process.versions["node"].substring(0,1) >= "6") + node6plus = true; + cb(); + }); + }, + function(cb) { + file.create(inFileName); + cb(); + } + ], done); + + }); // before + + after('release connection', function(done) { + async.series([ + function(cb) { + connection.release(function(err) { + should.not.exist(err); + cb(); + }); + }, + function(cb) { + file.delete(inFileName); + cb(); + } + ], done); + }); // after + + // Generic function to insert a single row given ID, and data + var insertIntoBlobTable1 = function(id, content, callback) { + if(content == "EMPTY_BLOB") { + connection.execute( + "INSERT INTO nodb_blob1 VALUES (:ID, EMPTY_BLOB())", + [ id ], + function(err, result) { + should.not.exist(err); + should.strictEqual(result.rowsAffected, 1); + callback(); + } + ); + } else { + connection.execute( + "INSERT INTO nodb_blob1 VALUES (:ID, :B)", + { + ID : { val : id }, + B : { val : content, dir : oracledb.BIND_IN, type : oracledb.BUFFER } + }, + function(err, result) { + should.not.exist(err); + should.strictEqual(result.rowsAffected, 1); + callback(); + } + ); + } + }; + + var updateBlobTable1 = function(id, content, callback) { + connection.execute( + "UPDATE nodb_blob1 set B = :B where ID = :ID", + { ID: id, B: content }, + function(err, result){ + should.not.exist(err); + should.strictEqual(result.rowsAffected, 1); + callback(); + } + ); + }; + + // compare fetch result + var compareClientFetchResult = function(err, resultVal, specialStr, content, contentLength) { + should.not.exist(err); + compareBuffers(resultVal, specialStr, content, contentLength); + }; + + // compare two buffers + var compareBuffers = function(resultVal, specialStr, content, contentLength) { + should.equal(resultVal.length, contentLength); + var compareBuffer = assist.compare2Buffers(resultVal, content); + should.strictEqual(compareBuffer, true); + }; + + describe('87.1 fetch BLOB columns by setting oracledb.fetchAsBuffer', function() { + + before('Create table and populate', function(done) { + connection.execute( + proc_create_table1, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // before + + after('drop table', function(done) { + connection.execute( + drop_table1, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // after + + var insertAndFetch = function(id, specialStr, insertContent, insertContentLength, callback) { + async.series([ + function(cb) { + insertIntoBlobTable1(id, insertContent, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, B from nodb_blob1 WHERE ID = :id", + { id : id }, + function(err, result) { + var resultVal = result.rows[0][1]; + if(specialStr === null) { + should.not.exist(err); + should.equal(resultVal, null); + } else { + compareClientFetchResult(err, resultVal, specialStr, insertContent, insertContentLength); + } + cb(); + } + ); + } + ], callback); + }; + + beforeEach('set oracledb.fetchAsBuffer', function(done) { + oracledb.fetchAsBuffer = [ oracledb.BLOB ]; + done(); + }); // beforeEach + + afterEach('clear the by-type specification', function(done) { + oracledb.fetchAsBuffer = []; + done(); + }); // afterEach + + it('87.1.1 works with NULL value', function(done) { + var id = insertID++; + var content = null; + + insertAndFetch(id, null, content, null, done); + }); // 87.1.1 + + it('87.1.2 works with empty Buffer', function(done) { + var id = insertID++; + var content = node6plus ? Buffer.from("", "utf-8") : new Buffer("", "utf-8"); + + insertAndFetch(id, null, content, null, done); + }); // 87.1.2 + + it('87.1.3 works with small value', function(done) { + var id = insertID++; + var specialStr = '87.1.3'; + var contentLength = 20; + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 87.1.3 + + it('87.1.4 works with (64K - 1) value', function(done) { + var id = insertID++; + var specialStr = '87.1.4'; + var contentLength = 65535; + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 87.1.4 + + it('87.1.5 works with (64K + 1) value', function(done) { + var id = insertID++; + var specialStr = '87.1.5'; + var contentLength = 65537; + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 87.1.5 + + it('87.1.6 works with (1MB + 1) data', function(done) { + var id = insertID++; + var specialStr = '87.1.6'; + var contentLength = 1048577; // 1MB + 1 + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 87.1.6 + + it('87.1.7 works with dbms_lob.substr()', function(done) { + var id = insertID++; + var specialStr = '87.1.7'; + var contentLength = 200; + var specialStrLength = specialStr.length; + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + async.series([ + function(cb) { + insertIntoBlobTable1(id, content, cb); + }, + function(cb) { + connection.execute( + "SELECT dbms_lob.substr(B, " + specialStrLength + ", 1) from nodb_blob1 WHERE ID = :id", + { id : id }, + function(err, result) { + should.not.exist(err); + var resultVal = result.rows[0][0]; + var buffer2Compare = node6plus ? Buffer.from(specialStr, "utf-8") : new Buffer(specialStr, "utf-8"); + compareClientFetchResult(err, resultVal, specialStr, buffer2Compare, specialStrLength); + cb(); + } + ); + } + ], done); + }); // 87.1.7 + + it('87.1.8 works with EMPTY_BLOB()', function(done) { + var id = insertID++; + var content = "EMPTY_BLOB"; + + insertAndFetch(id, null, content, null, done); + }); // 87.1.8 + + it('87.1.9 fetch multiple BLOB rows as Buffer', function(done) { + var id_1 = insertID++; + var specialStr_1 = '87.1.9_1'; + var contentLength_1 = 200; + var strBuf_1 = random.getRandomString(contentLength_1, specialStr_1); + var content_1 = node6plus ? Buffer.from(strBuf_1, "utf-8") : new Buffer(strBuf_1, "utf-8"); + var id_2 = insertID++; + var specialStr_2 = '87.1.9_2'; + var contentLength_2 = 100; + var strBuf_2 = random.getRandomString(contentLength_2, specialStr_2); + var content_2 = node6plus ? Buffer.from(strBuf_2, "utf-8") : new Buffer(strBuf_2, "utf-8"); + + async.series([ + function(cb) { + insertIntoBlobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoBlobTable1(id_2, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, B from nodb_blob1 WHERE ID = " + id_1 + " or id = " + id_2, + function(err, result) { + should.not.exist(err); + var resultVal = result.rows[0][1]; + compareClientFetchResult(err, resultVal, specialStr_1, content_1, contentLength_1); + resultVal = result.rows[1][1]; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + cb(); + } + ); + } + ], done); + }); // 87.1.9 + + it('87.1.10 fetch the same BLOB column multiple times', function(done) { + var id = insertID++; + var specialStr = '87.1.10'; + var contentLength = 200; + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + async.series([ + function(cb) { + insertIntoBlobTable1(id, content, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, B AS B1, B AS B2 from nodb_blob1 WHERE ID = " + id, + function(err, result) { + should.not.exist(err); + var resultVal = result.rows[0][1]; + compareClientFetchResult(err, resultVal, specialStr, content, contentLength); + resultVal = result.rows[0][2]; + compareClientFetchResult(err, resultVal, specialStr, content, contentLength); + cb(); + } + ); + } + ], done); + }); // 87.1.10 + + it('87.1.11 works with update statement', function(done) { + var id = insertID++; + var specialStr_1 = '87.1.11_1'; + var contentLength_1 = 208; + var strBuf_1 = random.getRandomString(contentLength_1, specialStr_1); + var content_1 = node6plus ? Buffer.from(strBuf_1, "utf-8") : new Buffer(strBuf_1, "utf-8"); + var specialStr_2 = '87.1.11_2'; + var contentLength_2 = 200; + var strBuf_2 = random.getRandomString(contentLength_2, specialStr_2); + var content_2 = node6plus ? Buffer.from(strBuf_2, "utf-8") : new Buffer(strBuf_2, "utf-8"); + + async.series([ + function(cb) { + insertAndFetch(id, specialStr_1, content_1, contentLength_1, cb); + }, + function(cb) { + updateBlobTable1(id, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, B from nodb_blob1 WHERE ID = " + id, + function(err, result) { + should.not.exist(err); + var resultVal = result.rows[0][1]; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + cb(); + } + ); + } + ], done); + }); // 87.1.11 + + it('87.1.12 works with REF CURSOR', function(done) { + var id = insertID++; + var specialStr = '87.1.12'; + var contentLength = 100; + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + async.series([ + function(cb) { + insertIntoBlobTable1(id, content, cb); + }, + function(cb) { + var ref_proc = "CREATE OR REPLACE PROCEDURE nodb_ref(blob_cursor OUT SYS_REFCURSOR)\n" + + "AS \n" + + "BEGIN \n" + + " OPEN blob_cursor FOR \n" + + " SELECT B from nodb_blob1 WHERE ID = " + id + "; \n" + + "END;"; + connection.execute( + ref_proc, + function(err){ + should.not.exist(err); + cb(); + } + ); + }, + function(cb) { + var sql = "BEGIN nodb_ref(:b); END;"; + var bindVar = { + b: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT } + }; + connection.execute( + sql, + bindVar, + function(err, result) { + result.outBinds.b.getRows(3, function(err, rows) { + var resultVal = rows[0][0]; + compareClientFetchResult(err, resultVal, specialStr, content, contentLength); + cb(); + }); + } + ); + }, + function(cb) { + var ref_proc_drop = "DROP PROCEDURE nodb_ref"; + connection.execute( + ref_proc_drop, + function(err){ + should.not.exist(err); + cb(); + } + ); + } + ], done); + }); // 87.1.12 + + it('87.1.13 fetch BLOB with stream', function(done) { + var id = insertID++; + var specialStr = '87.1.13'; + var contentLength = 200; + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + async.series([ + function(cb) { + insertIntoBlobTable1(id, content, cb); + }, + function(cb) { + oracledb.fetchAsBuffer = []; + connection.execute( + "SELECT B from nodb_blob1 WHERE ID = " + id, + function(err, result) { + should.not.exist(err); + var lob = result.rows[0][0]; + should.exist(lob); + var blobData = node6plus ? Buffer.alloc(0) : new Buffer(0); + var totalLength = 0; + + lob.on('data', function(chunk) { + totalLength = totalLength + chunk.length; + blobData = Buffer.concat([blobData, chunk], totalLength); + }); + + lob.on('error', function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + lob.on('end', function() { + compareClientFetchResult(err, blobData, specialStr, content, contentLength); + cb(); + }); + } + ); + } + ], done); + }); // 87.1.13 + + it('87.1.14 works with setting oracledb.maxRows < actual number of rows in the table', function(done) { + var id_1 = insertID++; + var specialStr_1 = '87.1.14_1'; + var contentLength_1 = 200; + var strBuf_1 = random.getRandomString(contentLength_1, specialStr_1); + var content_1 = node6plus ? Buffer.from(strBuf_1, "utf-8") : new Buffer(strBuf_1, "utf-8"); + var id_2 = insertID++; + var specialStr_2 = '87.1.14_2'; + var contentLength_2 = 100; + var strBuf_2 = random.getRandomString(contentLength_2, specialStr_2); + var content_2 = node6plus ? Buffer.from(strBuf_2, "utf-8") : new Buffer(strBuf_2, "utf-8"); + var maxRowsBak = oracledb.maxRows; + oracledb.maxRows = 1; + + async.series([ + function(cb) { + insertIntoBlobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoBlobTable1(id_2, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, B from nodb_blob1 WHERE id = " + id_1 + " or id = " +id_2, + function(err, result) { + should.not.exist(err); + result.rows.length.should.eql(1); + var resultVal = result.rows[0][1]; + compareClientFetchResult(err, resultVal, specialStr_1, content_1, contentLength_1); + oracledb.maxRows = maxRowsBak; + cb(); + } + ); + } + ], done); + }); // 87.1.14 + + it('87.1.15 works with setting oracledb.maxRows > actual number of rows in the table', function(done) { + var id_1 = insertID++; + var specialStr_1 = '87.1.15_1'; + var contentLength_1 = 200; + var strBuf_1 = random.getRandomString(contentLength_1, specialStr_1); + var content_1 = node6plus ? Buffer.from(strBuf_1, "utf-8") : new Buffer(strBuf_1, "utf-8"); + var id_2 = insertID++; + var specialStr_2 = '87.1.15_2'; + var contentLength_2 = 100; + var strBuf_2 = random.getRandomString(contentLength_2, specialStr_2); + var content_2 = node6plus ? Buffer.from(strBuf_2, "utf-8") : new Buffer(strBuf_2, "utf-8"); + var maxRowsBak = oracledb.maxRows; + oracledb.maxRows = 10; + + async.series([ + function(cb) { + insertIntoBlobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoBlobTable1(id_2, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, B from nodb_blob1 WHERE id = " + id_1 + " or id = " +id_2, + function(err, result) { + should.not.exist(err); + result.rows.length.should.eql(2); + var resultVal = result.rows[0][1]; + compareClientFetchResult(err, resultVal, specialStr_1, content_1, contentLength_1); + resultVal = result.rows[1][1]; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + oracledb.maxRows = maxRowsBak; + cb(); + } + ); + } + ], done); + }); // 87.1.15 + + it('87.1.16 override oracledb.fetchAsBuffer with fetchInfo set to oracledb.DEFAULT', function(done) { + var id = insertID++; + var specialStr = '87.1.16'; + var contentLength = 20; + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + async.series([ + function(cb) { + insertIntoBlobTable1(id, content, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, B from nodb_blob1 WHERE ID = :id", + { id : id }, + { + fetchInfo : { B : { type : oracledb.DEFAULT } } + }, + function(err, result) { + should.not.exist(err); + var lob = result.rows[0][1]; + should.exist(lob); + var blobData = node6plus ? Buffer.alloc(0) : new Buffer(0); + var totalLength = 0; + + lob.on('data', function(chunk) { + totalLength = totalLength + chunk.length; + blobData = Buffer.concat([blobData, chunk], totalLength); + }); + + lob.on('error', function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + lob.on('end', function() { + compareClientFetchResult(err, blobData, specialStr, content, contentLength); + cb(); + }); + } + ); + } + ], done); + }); // 87.1.16 + + it('87.1.17 works with connection.queryStream()', function(done) { + var id = insertID++; + var specialStr = '87.1.17'; + var contentLength = 200; + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + async.series([ + function(cb) { + insertIntoBlobTable1(id, content, cb); + }, + function(cb) { + var sql = "SELECT ID, B from nodb_blob1 WHERE ID = " + id; + var stream = connection.queryStream(sql); + stream.on('error', function (error) { + should.fail(error, null, 'Error event should not be triggered'); + }); + + var counter = 0; + stream.on('data', function(data) { + should.exist(data); + var result = data[1]; + compareBuffers(result, specialStr, content, contentLength); + counter++; + }); + + stream.on('end', function () { + should.equal(counter, 1); + setTimeout(cb, 500); + }); + } + ], done); + }); // 87.1.17 + + it('87.1.18 works with connection.queryStream() and oracledb.maxRows > actual number of rows in the table', function(done) { + var id_1 = insertID++; + var specialStr_1 = '87.1.18_1'; + var contentLength_1 = 26; + var strBuf_1 = random.getRandomString(contentLength_1, specialStr_1); + var content_1 = node6plus ? Buffer.from(strBuf_1, "utf-8") : new Buffer(strBuf_1, "utf-8"); + var id_2 = insertID++; + var specialStr_2 = '87.1.18_2'; + var contentLength_2 = 30; + var strBuf_2 = random.getRandomString(contentLength_2, specialStr_2); + var content_2 = node6plus ? Buffer.from(strBuf_2, "utf-8") : new Buffer(strBuf_2, "utf-8"); + var maxRowsBak = oracledb.maxRows; + oracledb.maxRows = 20; + + async.series([ + function(cb) { + insertIntoBlobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoBlobTable1(id_2, content_2, cb); + }, + function(cb) { + var sql = "SELECT ID, B from nodb_blob1 WHERE ID = " + id_1 + " or id = " +id_2; + var stream = connection.queryStream(sql); + stream.on('error', function (error) { + should.fail(error, null, 'Error event should not be triggered'); + }); + + var counter = 0; + stream.on('data', function(data) { + should.exist(data); + var result = data[1]; + counter++; + if(counter == 1) { + compareBuffers(result, specialStr_1, content_1, contentLength_1); + } else { + compareBuffers(result, specialStr_2, content_2, contentLength_2); + } + }); + + stream.on('end', function () { + should.equal(counter, 2); + oracledb.maxRows = maxRowsBak; + setTimeout(cb, 500); + }); + } + ], done); + }); // 87.1.18 + + it('87.1.19 works with connection.queryStream() and oracledb.maxRows = actual number of rows in the table', function(done) { + var id_1 = insertID++; + var specialStr_1 = '87.1.19_1'; + var contentLength_1 = 26; + var strBuf_1 = random.getRandomString(contentLength_1, specialStr_1); + var content_1 = node6plus ? Buffer.from(strBuf_1, "utf-8") : new Buffer(strBuf_1, "utf-8"); + var id_2 = insertID++; + var specialStr_2 = '87.1.19_2'; + var contentLength_2 = 30; + var strBuf_2 = random.getRandomString(contentLength_2, specialStr_2); + var content_2 = node6plus ? Buffer.from(strBuf_2, "utf-8") : new Buffer(strBuf_2, "utf-8"); + var maxRowsBak = oracledb.maxRows; + oracledb.maxRows = 2; + + async.series([ + function(cb) { + insertIntoBlobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoBlobTable1(id_2, content_2, cb); + }, + function(cb) { + var sql = "SELECT ID, B from nodb_blob1 WHERE ID = " + id_1 + " or id = " +id_2; + var stream = connection.queryStream(sql); + stream.on('error', function (error) { + should.fail(error, null, 'Error event should not be triggered'); + }); + + var counter = 0; + stream.on('data', function(data) { + should.exist(data); + var result = data[1]; + counter++; + if(counter == 1) { + compareBuffers(result, specialStr_1, content_1, contentLength_1); + } else { + compareBuffers(result, specialStr_2, content_2, contentLength_2); + } + }); + + stream.on('end', function () { + should.equal(counter, 2); + oracledb.maxRows = maxRowsBak; + setTimeout(cb, 500); + }); + } + ], done); + }); // 87.1.19 + + it('87.1.20 works with connection.queryStream() and oracledb.maxRows < actual number of rows in the table', function(done) { + var id_1 = insertID++; + var specialStr_1 = '87.1.20_1'; + var contentLength_1 = 26; + var strBuf_1 = random.getRandomString(contentLength_1, specialStr_1); + var content_1 = node6plus ? Buffer.from(strBuf_1, "utf-8") : new Buffer(strBuf_1, "utf-8"); + var id_2 = insertID++; + var specialStr_2 = '87.1.19_2'; + var contentLength_2 = 30; + var strBuf_2 = random.getRandomString(contentLength_2, specialStr_2); + var content_2 = node6plus ? Buffer.from(strBuf_2, "utf-8") : new Buffer(strBuf_2, "utf-8"); + var maxRowsBak = oracledb.maxRows; + oracledb.maxRows = 1; + + async.series([ + function(cb) { + insertIntoBlobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoBlobTable1(id_2, content_2, cb); + }, + function(cb) { + var sql = "SELECT ID, B from nodb_blob1 WHERE ID = " + id_1 + " or id = " +id_2; + var stream = connection.queryStream(sql); + stream.on('error', function (error) { + should.fail(error, null, 'Error event should not be triggered'); + }); + + var counter = 0; + stream.on('data', function(data) { + should.exist(data); + var result = data[1]; + counter++; + if(counter == 1) { + compareBuffers(result, specialStr_1, content_1, contentLength_1); + } else { + compareBuffers(result, specialStr_2, content_2, contentLength_2); + } + }); + + stream.on('end', function () { + should.equal(counter, 2); + oracledb.maxRows = maxRowsBak; + setTimeout(cb, 500); + }); + } + ], done); + }); // 87.1.20 + + }); // 87.1 + + describe('87.2 fetch BLOB columns by setting oracledb.fetchAsBuffer and outFormat = oracledb.OBJECT', function() { + + before('Create table and populate', function(done) { + connection.execute( + proc_create_table1, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // before + + after('drop table', function(done) { + connection.execute( + drop_table1, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // after + + beforeEach('set oracledb.fetchAsBuffer', function(done) { + oracledb.fetchAsBuffer = [ oracledb.BLOB ]; + done(); + }); // beforeEach + + afterEach('clear the by-type specification', function(done) { + oracledb.fetchAsBuffer = []; + done(); + }); // afterEach + + var insertAndFetch = function(id, specialStr, insertContent, insertContentLength, callback) { + async.series([ + function(cb) { + insertIntoBlobTable1(id, insertContent, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, B from nodb_blob1 WHERE ID = :id", + { id : id }, + { outFormat : oracledb.OBJECT }, + function(err, result) { + var resultVal = result.rows[0].B; + if(specialStr === null) { + should.not.exist(err); + should.equal(resultVal, null); + } else { + compareClientFetchResult(err, resultVal, specialStr, insertContent, insertContentLength); + } + cb(); + } + ); + } + ], callback); + }; + + it('87.2.1 works with NULL value', function(done) { + var id = insertID++; + var content = null; + + insertAndFetch(id, null, content, null, done); + }); // 87.2.1 + + it('87.2.2 works with empty Buffer', function(done) { + var id = insertID++; + var content = node6plus ? Buffer.from("", "utf-8") : new Buffer("", "utf-8"); + + insertAndFetch(id, null, content, null, done); + }); // 87.2.2 + + it('87.2.3 works with small value', function(done) { + var id = insertID++; + var specialStr = '87.2.3'; + var contentLength = 20; + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 87.2.3 + + it('87.2.4 works with (64K - 1) value', function(done) { + var id = insertID++; + var specialStr = '87.2.4'; + var contentLength = 65535; + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 87.2.4 + + it('87.2.5 works with (64K + 1) value', function(done) { + var id = insertID++; + var specialStr = '87.2.5'; + var contentLength = 65537; + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 87.2.5 + + it('87.2.6 works with (1MB + 1) data', function(done) { + var id = insertID++; + var specialStr = '87.2.6'; + var contentLength = 1048577; // 1MB + 1 + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 87.2.6 + + it('87.2.7 works with dbms_lob.substr()', function(done) { + var id = insertID++; + var specialStr = '87.2.7'; + var contentLength = 200; + var specialStrLength = specialStr.length; + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + async.series([ + function(cb) { + insertIntoBlobTable1(id, content, cb); + }, + function(cb) { + connection.execute( + "SELECT dbms_lob.substr(B, " + specialStrLength + ", 1) AS B1 from nodb_blob1 WHERE ID = :id", + { id : id }, + { outFormat : oracledb.OBJECT }, + function(err, result) { + should.not.exist(err); + var resultVal = result.rows[0].B1; + var buffer2Compare = node6plus ? Buffer.from(specialStr, "utf-8") : new Buffer(specialStr, "utf-8"); + compareClientFetchResult(err, resultVal, specialStr, buffer2Compare, specialStrLength); + cb(); + } + ); + } + ], done); + }); // 87.2.7 + + it('87.2.8 works with EMPTY_BLOB()', function(done) { + var id = insertID++; + var content = "EMPTY_BLOB"; + + insertAndFetch(id, null, content, null, done); + }); // 87.2.8 + + it('87.2.9 fetch multiple BLOB rows as Buffer', function(done) { + var id_1 = insertID++; + var specialStr_1 = '87.2.9_1'; + var contentLength_1 = 200; + var strBuf_1 = random.getRandomString(contentLength_1, specialStr_1); + var content_1 = node6plus ? Buffer.from(strBuf_1, "utf-8") : new Buffer(strBuf_1, "utf-8"); + var id_2 = insertID++; + var specialStr_2 = '87.2.9_2'; + var contentLength_2 = 100; + var strBuf_2 = random.getRandomString(contentLength_2, specialStr_2); + var content_2 = node6plus ? Buffer.from(strBuf_2, "utf-8") : new Buffer(strBuf_2, "utf-8"); + + async.series([ + function(cb) { + insertIntoBlobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoBlobTable1(id_2, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, B from nodb_blob1 WHERE ID = " + id_1 + " or id = " + id_2, + { }, + { outFormat : oracledb.OBJECT }, + function(err, result) { + should.not.exist(err); + var resultVal = result.rows[0].B; + compareClientFetchResult(err, resultVal, specialStr_1, content_1, contentLength_1); + resultVal = result.rows[1].B; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + cb(); + } + ); + } + ], done); + }); // 87.2.9 + + it('87.2.10 fetch the same BLOB column multiple times', function(done) { + var id = insertID++; + var specialStr = '87.2.10'; + var contentLength = 200; + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + async.series([ + function(cb) { + insertIntoBlobTable1(id, content, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, B AS B1, B AS B2 from nodb_blob1 WHERE ID = " + id, + { }, + { outFormat : oracledb.OBJECT }, + function(err, result) { + should.not.exist(err); + var resultVal = result.rows[0].B1; + compareClientFetchResult(err, resultVal, specialStr, content, contentLength); + resultVal = result.rows[0].B2; + compareClientFetchResult(err, resultVal, specialStr, content, contentLength); + cb(); + } + ); + } + ], done); + }); // 87.2.10 + + it('87.2.11 works with update statement', function(done) { + var id = insertID++; + var specialStr_1 = '87.2.11_1'; + var contentLength_1 = 201; + var strBuf_1 = random.getRandomString(contentLength_1, specialStr_1); + var content_1 = node6plus ? Buffer.from(strBuf_1, "utf-8") : new Buffer(strBuf_1, "utf-8"); + var specialStr_2 = '87.2.11_2'; + var contentLength_2 = 208; + var strBuf_2 = random.getRandomString(contentLength_2, specialStr_2); + var content_2 = node6plus ? Buffer.from(strBuf_2, "utf-8") : new Buffer(strBuf_2, "utf-8"); + + async.series([ + function(cb) { + insertAndFetch(id, specialStr_1, content_1, contentLength_1, cb); + }, + function(cb) { + updateBlobTable1(id, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, B from nodb_blob1 WHERE ID = " + id, + { }, + { outFormat : oracledb.OBJECT }, + function(err, result) { + should.not.exist(err); + var resultVal = result.rows[0].B; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + cb(); + } + ); + } + ], done); + }); // 87.2.11 + + it('87.2.12 works with REF CURSOR', function(done) { + var id = insertID++; + var specialStr = '87.2.12'; + var contentLength = 100; + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + async.series([ + function(cb) { + insertIntoBlobTable1(id, content, cb); + }, + function(cb) { + var ref_proc = "CREATE OR REPLACE PROCEDURE nodb_ref(blob_cursor OUT SYS_REFCURSOR)\n" + + "AS \n" + + "BEGIN \n" + + " OPEN blob_cursor FOR \n" + + " SELECT B from nodb_blob1 WHERE ID = " + id + "; \n" + + "END;"; + connection.execute( + ref_proc, + function(err){ + should.not.exist(err); + cb(); + } + ); + }, + function(cb) { + var sql = "BEGIN nodb_ref(:b); END;"; + var bindVar = { + b: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT } + }; + connection.execute( + sql, + bindVar, + function(err, result) { + result.outBinds.b.getRows(3, function(err, rows) { + var resultVal = rows[0][0]; + compareClientFetchResult(err, resultVal, specialStr, content, contentLength); + cb(); + }); + } + ); + }, + function(cb) { + var ref_proc_drop = "DROP PROCEDURE nodb_ref"; + connection.execute( + ref_proc_drop, + function(err){ + should.not.exist(err); + cb(); + } + ); + } + ], done); + }); // 87.2.12 + + it('87.2.13 fetch BLOB with stream', function(done) { + var id = insertID++; + var specialStr = '87.2.13'; + var contentLength = 200; + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + async.series([ + function(cb) { + insertIntoBlobTable1(id, content, cb); + }, + function(cb) { + oracledb.fetchAsBuffer = []; + connection.execute( + "SELECT B from nodb_blob1 WHERE ID = " + id, + function(err, result) { + should.not.exist(err); + var lob = result.rows[0][0]; + should.exist(lob); + var blobData = node6plus ? Buffer.alloc(0) : new Buffer(0); + var totalLength = 0; + + lob.on('data', function(chunk) { + totalLength = totalLength + chunk.length; + blobData = Buffer.concat([blobData, chunk], totalLength); + }); + + lob.on('error', function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + lob.on('end', function() { + compareClientFetchResult(err, blobData, specialStr, content, contentLength); + cb(); + }); + } + ); + } + ], done); + }); // 87.2.13 + + it('87.2.14 works with setting oracledb.maxRows < actual number of rows in the table', function(done) { + var id_1 = insertID++; + var specialStr_1 = '87.2.14_1'; + var contentLength_1 = 200; + var strBuf_1 = random.getRandomString(contentLength_1, specialStr_1); + var content_1 = node6plus ? Buffer.from(strBuf_1, "utf-8") : new Buffer(strBuf_1, "utf-8"); + var id_2 = insertID++; + var specialStr_2 = '87.2.14_2'; + var contentLength_2 = 100; + var strBuf_2 = random.getRandomString(contentLength_2, specialStr_2); + var content_2 = node6plus ? Buffer.from(strBuf_2, "utf-8") : new Buffer(strBuf_2, "utf-8"); + var maxRowsBak = oracledb.maxRows; + oracledb.maxRows = 1; + + async.series([ + function(cb) { + insertIntoBlobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoBlobTable1(id_2, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, B from nodb_blob1 WHERE id = " + id_1 + " or id = " +id_2, + { }, + { outFormat : oracledb.OBJECT }, + function(err, result) { + should.not.exist(err); + result.rows.length.should.eql(1); + var resultVal = result.rows[0].B; + compareClientFetchResult(err, resultVal, specialStr_1, content_1, contentLength_1); + oracledb.maxRows = maxRowsBak; + cb(); + } + ); + } + ], done); + }); // 87.2.14 + + it('87.2.15 works with setting oracledb.maxRows > actual number of rows in the table', function(done) { + var id_1 = insertID++; + var specialStr_1 = '87.2.15_1'; + var contentLength_1 = 200; + var strBuf_1 = random.getRandomString(contentLength_1, specialStr_1); + var content_1 = node6plus ? Buffer.from(strBuf_1, "utf-8") : new Buffer(strBuf_1, "utf-8"); + var id_2 = insertID++; + var specialStr_2 = '87.2.15_2'; + var contentLength_2 = 100; + var strBuf_2 = random.getRandomString(contentLength_2, specialStr_2); + var content_2 = node6plus ? Buffer.from(strBuf_2, "utf-8") : new Buffer(strBuf_2, "utf-8"); + var maxRowsBak = oracledb.maxRows; + oracledb.maxRows = 10; + + async.series([ + function(cb) { + insertIntoBlobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoBlobTable1(id_2, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, B from nodb_blob1 WHERE id = " + id_1 + " or id = " +id_2, + { }, + { outFormat : oracledb.OBJECT }, + function(err, result) { + should.not.exist(err); + result.rows.length.should.eql(2); + var resultVal = result.rows[0].B; + compareClientFetchResult(err, resultVal, specialStr_1, content_1, contentLength_1); + resultVal = result.rows[1].B; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + oracledb.maxRows = maxRowsBak; + cb(); + } + ); + } + ], done); + }); // 87.2.15 + + it('87.2.16 override oracledb.fetchAsBuffer with fetchInfo set to oracledb.DEFAULT', function(done) { + var id = insertID++; + var specialStr = '87.2.16'; + var contentLength = 20; + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + async.series([ + function(cb) { + insertIntoBlobTable1(id, content, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, B from nodb_blob1 WHERE ID = :id", + { id : id }, + { + fetchInfo : { B : { type : oracledb.DEFAULT } } + }, + function(err, result) { + should.not.exist(err); + var lob = result.rows[0][1]; + should.exist(lob); + var blobData = node6plus ? Buffer.alloc(0) : new Buffer(0); + var totalLength = 0; + + lob.on('data', function(chunk) { + totalLength = totalLength + chunk.length; + blobData = Buffer.concat([blobData, chunk], totalLength); + }); + + lob.on('error', function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + lob.on('end', function() { + compareClientFetchResult(err, blobData, specialStr, content, contentLength); + cb(); + }); + } + ); + } + ], done); + }); // 87.2.16 + + }); // 87.2 + + describe('87.3 fetch BLOB columns by setting oracledb.fetchAsBuffer, outFormat = oracledb.OBJECT and resultSet = true', function() { + + before('Create table and populate', function(done) { + connection.execute( + proc_create_table1, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // before + + after('drop table', function(done) { + connection.execute( + drop_table1, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // after + + beforeEach('set oracledb.fetchAsBuffer', function(done) { + oracledb.fetchAsBuffer = [ oracledb.BLOB ]; + done(); + }); // beforeEach + + afterEach('clear the by-type specification', function(done) { + oracledb.fetchAsBuffer = []; + done(); + }); // afterEach + + var insertAndFetch = function(id, specialStr, insertContent, insertContentLength, callback) { + async.series([ + function(cb) { + insertIntoBlobTable1(id, insertContent, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, B from nodb_blob1 WHERE ID = :id", + { id : id }, + { + outFormat : oracledb.OBJECT, + resultSet : true + }, + function(err, result) { + should.not.exist(err); + result.resultSet.getRow( + function(err, row) { + var resultVal; + resultVal = row.B; + if(specialStr === null) { + should.equal(resultVal, null); + } else { + compareClientFetchResult(err, resultVal, specialStr, insertContent, insertContentLength); + } + result.resultSet.close(function(err) { + should.not.exist(err); + cb(); + }); + } + ); + } + ); + } + ], callback); + }; + + it('87.3.1 works with NULL value', function(done) { + var id = insertID++; + var content = null; + + insertAndFetch(id, null, content, null, done); + }); // 87.3.1 + + it('87.3.2 works with empty Buffer', function(done) { + var id = insertID++; + var content = node6plus ? Buffer.from("", "utf-8") : new Buffer("", "utf-8"); + + insertAndFetch(id, null, content, null, done); + }); // 87.3.2 + + it('87.3.3 works with small value', function(done) { + var id = insertID++; + var specialStr = '87.3.3'; + var contentLength = 20; + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 87.3.3 + + it('87.3.4 works with (64K - 1) value', function(done) { + var id = insertID++; + var specialStr = '87.3.4'; + var contentLength = 65535; + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 87.3.4 + + it('87.3.5 works with (64K + 1) value', function(done) { + var id = insertID++; + var specialStr = '87.3.5'; + var contentLength = 65537; + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 87.3.5 + + it('87.3.6 works with (1MB + 1) data', function(done) { + var id = insertID++; + var specialStr = '87.3.6'; + var contentLength = 1048577; // 1MB + 1 + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 87.3.6 + + it('87.3.7 works with dbms_lob.substr()', function(done) { + var id = insertID++; + var specialStr = '87.3.7'; + var contentLength = 200; + var specialStrLength = specialStr.length; + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + async.series([ + function(cb) { + insertIntoBlobTable1(id, content, cb); + }, + function(cb) { + connection.execute( + "SELECT dbms_lob.substr(B, " + specialStrLength + ", 1) AS B1 from nodb_blob1 WHERE ID = :id", + { id : id }, + { + outFormat : oracledb.OBJECT, + resultSet : true + }, + function(err, result) { + should.not.exist(err); + result.resultSet.getRow( + function(err, row) { + should.not.exist(err); + var resultVal = row.B1; + var buffer2Compare = node6plus ? Buffer.from(specialStr, "utf-8") : new Buffer(specialStr, "utf-8"); + compareClientFetchResult(err, resultVal, specialStr, buffer2Compare, specialStrLength); + result.resultSet.close(function(err) { + should.not.exist(err); + cb(); + }); + } + ); + } + ); + } + ], done); + }); // 87.3.7 + + it('87.3.8 works with EMPTY_BLOB()', function(done) { + var id = insertID++; + var content = "EMPTY_BLOB"; + + insertAndFetch(id, null, content, null, done); + }); // 87.3.8 + + it('87.3.9 fetch multiple BLOB rows as Buffer', function(done) { + var id_1 = insertID++; + var specialStr_1 = '87.3.9_1'; + var contentLength_1 = 200; + var strBuf_1 = random.getRandomString(contentLength_1, specialStr_1); + var content_1 = node6plus ? Buffer.from(strBuf_1, "utf-8") : new Buffer(strBuf_1, "utf-8"); + var id_2 = insertID++; + var specialStr_2 = '87.3.9_2'; + var contentLength_2 = 100; + var strBuf_2 = random.getRandomString(contentLength_2, specialStr_2); + var content_2 = node6plus ? Buffer.from(strBuf_2, "utf-8") : new Buffer(strBuf_2, "utf-8"); + + async.series([ + function(cb) { + insertIntoBlobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoBlobTable1(id_2, content_2, cb); + }, + function(cb) { + var rowNumFetched = 2; + connection.execute( + "SELECT ID, B from nodb_blob1 WHERE ID = " + id_1 + " or id = " + id_2, + { }, + { + outFormat : oracledb.OBJECT, + resultSet : true + }, + function(err, result) { + should.not.exist(err); + result.resultSet.getRows( + rowNumFetched, + function(err, row) { + should.not.exist(err); + var resultVal = row[0].B; + compareClientFetchResult(err, resultVal, specialStr_1, content_1, contentLength_1); + resultVal = row[1].B; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + result.resultSet.close(function(err) { + should.not.exist(err); + cb(); + }); + } + ); + } + ); + } + ], done); + }); // 87.3.9 + + it('87.3.10 fetch the same BLOB column multiple times', function(done) { + var id = insertID++; + var specialStr = '87.3.10'; + var contentLength = 200; + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + async.series([ + function(cb) { + insertIntoBlobTable1(id, content, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, B AS B1, B AS B2 from nodb_blob1 WHERE ID = " + id, + { }, + { + outFormat : oracledb.OBJECT, + resultSet : true + }, + function(err, result) { + should.not.exist(err); + result.resultSet.getRow( + function(err, row) { + should.not.exist(err); + var resultVal = row.B1; + compareClientFetchResult(err, resultVal, specialStr, content, contentLength); + resultVal = row.B2; + compareClientFetchResult(err, resultVal, specialStr, content, contentLength); + result.resultSet.close(function(err) { + should.not.exist(err); + cb(); + }); + } + ); + } + ); + } + ], done); + }); // 87.3.10 + + it('87.3.11 works with update statement', function(done) { + var id = insertID++; + var specialStr_1 = '87.3.11_1'; + var contentLength_1 = 200; + var strBuf_1 = random.getRandomString(contentLength_1, specialStr_1); + var content_1 = node6plus ? Buffer.from(strBuf_1, "utf-8") : new Buffer(strBuf_1, "utf-8"); + var specialStr_2 = '87.3.11_2'; + var contentLength_2 = 208; + var strBuf_2 = random.getRandomString(contentLength_2, specialStr_2); + var content_2 = node6plus ? Buffer.from(strBuf_2, "utf-8") : new Buffer(strBuf_2, "utf-8"); + + async.series([ + function(cb) { + insertAndFetch(id, specialStr_1, content_1, contentLength_1, cb); + }, + function(cb) { + updateBlobTable1(id, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, B from nodb_blob1 WHERE ID = " + id, + { }, + { + outFormat : oracledb.OBJECT, + resultSet : true + }, + function(err, result) { + should.not.exist(err); + result.resultSet.getRow( + function(err, row) { + should.not.exist(err); + var resultVal = row.B; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + result.resultSet.close(function(err) { + should.not.exist(err); + cb(); + }); + } + ); + } + ); + } + ], done); + }); // 87.3.11 + + it('87.3.12 works with REF CURSOR', function(done) { + var id = insertID++; + var specialStr = '87.3.12'; + var contentLength = 100; + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + async.series([ + function(cb) { + insertIntoBlobTable1(id, content, cb); + }, + function(cb) { + var ref_proc = "CREATE OR REPLACE PROCEDURE nodb_ref(blob_cursor OUT SYS_REFCURSOR)\n" + + "AS \n" + + "BEGIN \n" + + " OPEN blob_cursor FOR \n" + + " SELECT B from nodb_blob1 WHERE ID = " + id + "; \n" + + "END;"; + connection.execute( + ref_proc, + function(err){ + should.not.exist(err); + cb(); + } + ); + }, + function(cb) { + var sql = "BEGIN nodb_ref(:b); END;"; + var bindVar = { + b: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT } + }; + connection.execute( + sql, + bindVar, + function(err, result) { + result.outBinds.b.getRows(3, function(err, rows) { + var resultVal = rows[0][0]; + compareClientFetchResult(err, resultVal, specialStr, content, contentLength); + cb(); + }); + } + ); + }, + function(cb) { + var ref_proc_drop = "DROP PROCEDURE nodb_ref"; + connection.execute( + ref_proc_drop, + function(err){ + should.not.exist(err); + cb(); + } + ); + } + ], done); + }); // 87.3.12 + + it('87.3.13 fetch BLOB with stream', function(done) { + var id = insertID++; + var specialStr = '87.3.13'; + var contentLength = 200; + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + async.series([ + function(cb) { + insertIntoBlobTable1(id, content, cb); + }, + function(cb) { + oracledb.fetchAsBuffer = []; + connection.execute( + "SELECT B from nodb_blob1 WHERE ID = " + id, + function(err, result) { + should.not.exist(err); + var lob = result.rows[0][0]; + should.exist(lob); + var blobData = node6plus ? Buffer.alloc(0) : new Buffer(0); + var totalLength = 0; + + lob.on('data', function(chunk) { + totalLength = totalLength + chunk.length; + blobData = Buffer.concat([blobData, chunk], totalLength); + }); + + lob.on('error', function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + lob.on('end', function() { + compareClientFetchResult(err, blobData, specialStr, content, contentLength); + cb(); + }); + } + ); + } + ], done); + }); // 87.3.13 + + it('87.3.14 works with setting oracledb.maxRows < actual number of rows in the table', function(done) { + var id_1 = insertID++; + var specialStr_1 = '87.3.14_1'; + var contentLength_1 = 200; + var strBuf_1 = random.getRandomString(contentLength_1, specialStr_1); + var content_1 = node6plus ? Buffer.from(strBuf_1, "utf-8") : new Buffer(strBuf_1, "utf-8"); + var id_2 = insertID++; + var specialStr_2 = '87.3.14_2'; + var contentLength_2 = 100; + var strBuf_2 = random.getRandomString(contentLength_2, specialStr_2); + var content_2 = node6plus ? Buffer.from(strBuf_2, "utf-8") : new Buffer(strBuf_2, "utf-8"); + var maxRowsBak = oracledb.maxRows; + oracledb.maxRows = 1; + + async.series([ + function(cb) { + insertIntoBlobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoBlobTable1(id_2, content_2, cb); + }, + function(cb) { + var rowNumFetched = 2; + connection.execute( + "SELECT ID, B from nodb_blob1 WHERE id = " + id_1 + " or id = " +id_2, + { }, + { + outFormat : oracledb.OBJECT, + resultSet : true + }, + function(err, result) { + should.not.exist(err); + result.resultSet.getRows( + rowNumFetched, + function(err, row) { + should.not.exist(err); + should.strictEqual(row.length, 2); + var resultVal = row[0].B; + compareClientFetchResult(err, resultVal, specialStr_1, content_1, contentLength_1); + resultVal = row[1].B; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + oracledb.maxRows =maxRowsBak; + result.resultSet.close(function(err) { + should.not.exist(err); + cb(); + }); + } + ); + } + ); + } + ], done); + }); // 87.3.14 + + it('87.3.15 works with setting oracledb.maxRows > actual number of rows in the table', function(done) { + var id_1 = insertID++; + var specialStr_1 = '87.3.15_1'; + var contentLength_1 = 200; + var strBuf_1 = random.getRandomString(contentLength_1, specialStr_1); + var content_1 = node6plus ? Buffer.from(strBuf_1, "utf-8") : new Buffer(strBuf_1, "utf-8"); + var id_2 = insertID++; + var specialStr_2 = '87.3.15_2'; + var contentLength_2 = 100; + var strBuf_2 = random.getRandomString(contentLength_2, specialStr_2); + var content_2 = node6plus ? Buffer.from(strBuf_2, "utf-8") : new Buffer(strBuf_2, "utf-8"); + var maxRowsBak = oracledb.maxRows; + oracledb.maxRows = 10; + + async.series([ + function(cb) { + insertIntoBlobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoBlobTable1(id_2, content_2, cb); + }, + function(cb) { + var rowNumFetched = 2; + connection.execute( + "SELECT ID, B from nodb_blob1 WHERE id = " + id_1 + " or id = " +id_2, + { }, + { + outFormat : oracledb.OBJECT, + resultSet : true + }, + function(err, result) { + should.not.exist(err); + result.resultSet.getRows( + rowNumFetched, + function(err, row) { + should.not.exist(err); + should.strictEqual(row.length, 2); + var resultVal = row[0].B; + compareClientFetchResult(err, resultVal, specialStr_1, content_1, contentLength_1); + resultVal = row[1].B; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + oracledb.maxRows =maxRowsBak; + result.resultSet.close(function(err) { + should.not.exist(err); + cb(); + }); + } + ); + } + ); + } + ], done); + }); // 87.3.15 + + it('87.3.16 override oracledb.fetchAsBuffer with fetchInfo set to oracledb.DEFAULT', function(done) { + var id = insertID++; + var specialStr = '87.3.16'; + var contentLength = 20; + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + async.series([ + function(cb) { + insertIntoBlobTable1(id, content, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, B from nodb_blob1 WHERE ID = :id", + { id : id }, + { + fetchInfo : { B : { type : oracledb.DEFAULT } } + }, + function(err, result) { + should.not.exist(err); + var lob = result.rows[0][1]; + should.exist(lob); + var blobData = node6plus ? Buffer.alloc(0) : new Buffer(0); + var totalLength = 0; + + lob.on('data', function(chunk) { + totalLength = totalLength + chunk.length; + blobData = Buffer.concat([blobData, chunk], totalLength); + }); + + lob.on('error', function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + lob.on('end', function() { + compareClientFetchResult(err, blobData, specialStr, content, contentLength); + cb(); + }); + } + ); + } + ], done); + }); // 87.3.16 + + }); // 87.3 + + describe('87.4 fetch BLOB columns by setting oracledb.fetchAsBuffer and outFormat = oracledb.ARRAY', function() { + + before('Create table and populate', function(done) { + connection.execute( + proc_create_table1, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // before + + after('drop table', function(done) { + connection.execute( + drop_table1, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // after + + beforeEach('set oracledb.fetchAsBuffer', function(done) { + oracledb.fetchAsBuffer = [ oracledb.BLOB ]; + done(); + }); // beforeEach + + afterEach('clear the by-type specification', function(done) { + oracledb.fetchAsBuffer = []; + done(); + }); // afterEach + + var insertAndFetch = function(id, specialStr, insertContent, insertContentLength, callback) { + async.series([ + function(cb) { + insertIntoBlobTable1(id, insertContent, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, B from nodb_blob1 WHERE ID = :id", + { id : id }, + { outFormat : oracledb.ARRAY }, + function(err, result) { + var resultVal = result.rows[0][1]; + if(specialStr === null) { + should.not.exist(err); + should.equal(resultVal, null); + } else { + compareClientFetchResult(err, resultVal, specialStr, insertContent, insertContentLength); + } + cb(); + } + ); + } + ], callback); + }; + + it('87.4.1 works with NULL value', function(done) { + var id = insertID++; + var content = null; + + insertAndFetch(id, null, content, null, done); + }); // 87.4.1 + + it('87.4.2 works with empty Buffer', function(done) { + var id = insertID++; + var content = node6plus ? Buffer.from("", "utf-8") : new Buffer("", "utf-8"); + + insertAndFetch(id, null, content, null, done); + }); // 87.4.2 + + it('87.4.3 works with small value', function(done) { + var id = insertID++; + var specialStr = '87.4.3'; + var contentLength = 20; + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 87.4.3 + + it('87.4.4 works with (64K - 1) value', function(done) { + var id = insertID++; + var specialStr = '87.4.4'; + var contentLength = 65535; + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 87.4.4 + + it('87.4.5 works with (64K + 1) value', function(done) { + var id = insertID++; + var specialStr = '87.4.5'; + var contentLength = 65537; + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 87.4.5 + + it('87.4.6 works with (1MB + 1) data', function(done) { + var id = insertID++; + var specialStr = '87.4.6'; + var contentLength = 1048577; // 1MB + 1 + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 87.4.6 + + it('87.4.7 works with dbms_lob.substr()', function(done) { + var id = insertID++; + var specialStr = '87.4.7'; + var contentLength = 200; + var specialStrLength = specialStr.length; + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + async.series([ + function(cb) { + insertIntoBlobTable1(id, content, cb); + }, + function(cb) { + connection.execute( + "SELECT dbms_lob.substr(B, " + specialStrLength + ", 1) from nodb_blob1 WHERE ID = :id", + { id : id }, + { outFormat : oracledb.ARRAY }, + function(err, result) { + should.not.exist(err); + var resultVal = result.rows[0][0]; + var buffer2Compare = node6plus ? Buffer.from(specialStr, "utf-8") : new Buffer(specialStr, "utf-8"); + compareClientFetchResult(err, resultVal, specialStr, buffer2Compare, specialStrLength); + cb(); + } + ); + } + ], done); + }); // 87.4.7 + + it('87.4.8 works with EMPTY_BLOB()', function(done) { + var id = insertID++; + var content = "EMPTY_BLOB"; + + insertAndFetch(id, null, content, null, done); + }); // 87.4.8 + + it('87.4.9 fetch multiple BLOB rows as Buffer', function(done) { + var id_1 = insertID++; + var specialStr_1 = '87.4.9_1'; + var contentLength_1 = 200; + var strBuf_1 = random.getRandomString(contentLength_1, specialStr_1); + var content_1 = node6plus ? Buffer.from(strBuf_1, "utf-8") : new Buffer(strBuf_1, "utf-8"); + var id_2 = insertID++; + var specialStr_2 = '87.4.9_2'; + var contentLength_2 = 100; + var strBuf_2 = random.getRandomString(contentLength_2, specialStr_2); + var content_2 = node6plus ? Buffer.from(strBuf_2, "utf-8") : new Buffer(strBuf_2, "utf-8"); + + async.series([ + function(cb) { + insertIntoBlobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoBlobTable1(id_2, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, B from nodb_blob1 WHERE ID = " + id_1 + " or id = " + id_2, + { }, + { outFormat : oracledb.ARRAY }, + function(err, result) { + should.not.exist(err); + var resultVal = result.rows[0][1]; + compareClientFetchResult(err, resultVal, specialStr_1, content_1, contentLength_1); + resultVal = result.rows[1][1]; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + cb(); + } + ); + } + ], done); + }); // 87.4.9 + + it('87.4.10 fetch the same BLOB column multiple times', function(done) { + var id = insertID++; + var specialStr = '87.4.10'; + var contentLength = 200; + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + async.series([ + function(cb) { + insertIntoBlobTable1(id, content, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, B AS B1, B AS B2 from nodb_blob1 WHERE ID = " + id, + { }, + { outFormat : oracledb.ARRAY }, + function(err, result) { + should.not.exist(err); + var resultVal = result.rows[0][1]; + compareClientFetchResult(err, resultVal, specialStr, content, contentLength); + resultVal = result.rows[0][2]; + compareClientFetchResult(err, resultVal, specialStr, content, contentLength); + cb(); + } + ); + } + ], done); + }); // 87.4.10 + + it('87.4.11 works with update statement', function(done) { + var id = insertID++; + var specialStr_1 = '87.4.11_1'; + var contentLength_1 = 200; + var strBuf_1 = random.getRandomString(contentLength_1, specialStr_1); + var content_1 = node6plus ? Buffer.from(strBuf_1, "utf-8") : new Buffer(strBuf_1, "utf-8"); + var specialStr_2 = '87.4.11_2'; + var contentLength_2 = 208; + var strBuf_2 = random.getRandomString(contentLength_2, specialStr_2); + var content_2 = node6plus ? Buffer.from(strBuf_2, "utf-8") : new Buffer(strBuf_2, "utf-8"); + + async.series([ + function(cb) { + insertAndFetch(id, specialStr_1, content_1, contentLength_1, cb); + }, + function(cb) { + updateBlobTable1(id, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, B from nodb_blob1 WHERE ID = " + id, + { }, + { outFormat : oracledb.ARRAY }, + function(err, result) { + should.not.exist(err); + var resultVal = result.rows[0][1]; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + cb(); + } + ); + } + ], done); + }); // 87.4.11 + + it('87.4.12 works with REF CURSOR', function(done) { + var id = insertID++; + var specialStr = '87.4.12'; + var contentLength = 100; + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + async.series([ + function(cb) { + insertIntoBlobTable1(id, content, cb); + }, + function(cb) { + var ref_proc = "CREATE OR REPLACE PROCEDURE nodb_ref(blob_cursor OUT SYS_REFCURSOR)\n" + + "AS \n" + + "BEGIN \n" + + " OPEN blob_cursor FOR \n" + + " SELECT B from nodb_blob1 WHERE ID = " + id + "; \n" + + "END;"; + connection.execute( + ref_proc, + function(err){ + should.not.exist(err); + cb(); + } + ); + }, + function(cb) { + var sql = "BEGIN nodb_ref(:b); END;"; + var bindVar = { + b: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT } + }; + connection.execute( + sql, + bindVar, + function(err, result) { + result.outBinds.b.getRows(3, function(err, rows) { + var resultVal = rows[0][0]; + compareClientFetchResult(err, resultVal, specialStr, content, contentLength); + cb(); + }); + } + ); + }, + function(cb) { + var ref_proc_drop = "DROP PROCEDURE nodb_ref"; + connection.execute( + ref_proc_drop, + function(err){ + should.not.exist(err); + cb(); + } + ); + } + ], done); + }); // 87.4.12 + + it('87.4.13 fetch BLOB with stream', function(done) { + var id = insertID++; + var specialStr = '87.4.13'; + var contentLength = 200; + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + async.series([ + function(cb) { + insertIntoBlobTable1(id, content, cb); + }, + function(cb) { + oracledb.fetchAsBuffer = []; + connection.execute( + "SELECT B from nodb_blob1 WHERE ID = " + id, + function(err, result) { + should.not.exist(err); + var lob = result.rows[0][0]; + should.exist(lob); + var blobData = node6plus ? Buffer.alloc(0) : new Buffer(0); + var totalLength = 0; + + lob.on('data', function(chunk) { + totalLength = totalLength + chunk.length; + blobData = Buffer.concat([blobData, chunk], totalLength); + }); + + lob.on('error', function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + lob.on('end', function() { + compareClientFetchResult(err, blobData, specialStr, content, contentLength); + cb(); + }); + } + ); + } + ], done); + }); // 87.4.13 + + it('87.4.14 works with setting oracledb.maxRows < actual number of rows in the table', function(done) { + var id_1 = insertID++; + var specialStr_1 = '87.4.14_1'; + var contentLength_1 = 200; + var strBuf_1 = random.getRandomString(contentLength_1, specialStr_1); + var content_1 = node6plus ? Buffer.from(strBuf_1, "utf-8") : new Buffer(strBuf_1, "utf-8"); + var id_2 = insertID++; + var specialStr_2 = '87.4.14_2'; + var contentLength_2 = 100; + var strBuf_2 = random.getRandomString(contentLength_2, specialStr_2); + var content_2 = node6plus ? Buffer.from(strBuf_2, "utf-8") : new Buffer(strBuf_2, "utf-8"); + var maxRowsBak = oracledb.maxRows; + oracledb.maxRows = 1; + + async.series([ + function(cb) { + insertIntoBlobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoBlobTable1(id_2, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, B from nodb_blob1 WHERE id = " + id_1 + " or id = " +id_2, + { }, + { outFormat : oracledb.ARRAY }, + function(err, result) { + should.not.exist(err); + result.rows.length.should.eql(1); + var resultVal = result.rows[0][1]; + compareClientFetchResult(err, resultVal, specialStr_1, content_1, contentLength_1); + oracledb.maxRows = maxRowsBak; + cb(); + } + ); + } + ], done); + }); // 87.4.14 + + it('87.4.15 works with setting oracledb.maxRows < actual number of rows in the table', function(done) { + var id_1 = insertID++; + var specialStr_1 = '87.4.15_1'; + var contentLength_1 = 200; + var strBuf_1 = random.getRandomString(contentLength_1, specialStr_1); + var content_1 = node6plus ? Buffer.from(strBuf_1, "utf-8") : new Buffer(strBuf_1, "utf-8"); + var id_2 = insertID++; + var specialStr_2 = '87.4.15_2'; + var contentLength_2 = 100; + var strBuf_2 = random.getRandomString(contentLength_2, specialStr_2); + var content_2 = node6plus ? Buffer.from(strBuf_2, "utf-8") : new Buffer(strBuf_2, "utf-8"); + var maxRowsBak = oracledb.maxRows; + oracledb.maxRows = 10; + + async.series([ + function(cb) { + insertIntoBlobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoBlobTable1(id_2, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, B from nodb_blob1 WHERE id = " + id_1 + " or id = " +id_2, + { }, + { outFormat : oracledb.ARRAY }, + function(err, result) { + should.not.exist(err); + result.rows.length.should.eql(2); + var resultVal = result.rows[0][1]; + compareClientFetchResult(err, resultVal, specialStr_1, content_1, contentLength_1); + resultVal = result.rows[1][1]; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + oracledb.maxRows = maxRowsBak; + cb(); + } + ); + } + ], done); + }); // 87.4.15 + + it('87.4.16 override oracledb.fetchAsBuffer with fetchInfo set to oracledb.DEFAULT', function(done) { + var id = insertID++; + var specialStr = '87.4.16'; + var contentLength = 20; + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + async.series([ + function(cb) { + insertIntoBlobTable1(id, content, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, B from nodb_blob1 WHERE ID = :id", + { id : id }, + { + fetchInfo : { B : { type : oracledb.DEFAULT } } + }, + function(err, result) { + should.not.exist(err); + var lob = result.rows[0][1]; + should.exist(lob); + var blobData = node6plus ? Buffer.alloc(0) : new Buffer(0); + var totalLength = 0; + + lob.on('data', function(chunk) { + totalLength = totalLength + chunk.length; + blobData = Buffer.concat([blobData, chunk], totalLength); + }); + + lob.on('error', function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + lob.on('end', function() { + compareClientFetchResult(err, blobData, specialStr, content, contentLength); + cb(); + }); + } + ); + } + ], done); + }); // 87.4.16 + + }); // 87.4 + + describe('87.5 fetch BLOB columns by setting oracledb.fetchAsBuffer, outFormat = oracledb.ARRAY and resultSet = true', function() { + + before('Create table and populate', function(done) { + connection.execute( + proc_create_table1, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // before + + after('drop table', function(done) { + connection.execute( + drop_table1, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // after + + beforeEach('set oracledb.fetchAsBuffer', function(done) { + oracledb.fetchAsBuffer = [ oracledb.BLOB ]; + done(); + }); // beforeEach + + afterEach('clear the by-type specification', function(done) { + oracledb.fetchAsBuffer = []; + done(); + }); // afterEach + + var insertAndFetch = function(id, specialStr, insertContent, insertContentLength, callback) { + async.series([ + function(cb) { + insertIntoBlobTable1(id, insertContent, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, B from nodb_blob1 WHERE ID = :id", + { id : id }, + { + outFormat : oracledb.ARRAY, + resultSet : true + }, + function(err, result) { + should.not.exist(err); + result.resultSet.getRow( + function(err, row) { + var resultVal; + resultVal = row[1]; + if(specialStr === null) { + should.not.exist(err); + should.equal(resultVal, null); + } else { + compareClientFetchResult(err, resultVal, specialStr, insertContent, insertContentLength); + } + result.resultSet.close(function(err) { + should.not.exist(err); + cb(); + }); + } + ); + } + ); + } + ], callback); + }; + + it('87.5.1 works with NULL value', function(done) { + var id = insertID++; + var content = null; + + insertAndFetch(id, null, content, null, done); + }); // 87.5.1 + + it('87.5.2 works with empty Buffer', function(done) { + var id = insertID++; + var content = node6plus ? Buffer.from("", "utf-8") : new Buffer("", "utf-8"); + + insertAndFetch(id, null, content, null, done); + }); // 87.5.2 + + it('87.5.3 works with small value', function(done) { + var id = insertID++; + var specialStr = '87.5.3'; + var contentLength = 20; + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 87.5.3 + + it('87.5.4 works with (64K - 1) value', function(done) { + var id = insertID++; + var specialStr = '87.5.4'; + var contentLength = 65535; + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 87.5.4 + + it('87.5.5 works with (64K + 1) value', function(done) { + var id = insertID++; + var specialStr = '87.5.5'; + var contentLength = 65537; + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 87.5.5 + + it('87.5.6 works with (1MB + 1) data', function(done) { + var id = insertID++; + var specialStr = '87.5.6'; + var contentLength = 1048577; // 1MB + 1 + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 87.5.6 + + it('87.5.7 works with dbms_lob.substr()', function(done) { + var id = insertID++; + var specialStr = '87.5.7'; + var contentLength = 200; + var specialStrLength = specialStr.length; + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + async.series([ + function(cb) { + insertIntoBlobTable1(id, content, cb); + }, + function(cb) { + connection.execute( + "SELECT dbms_lob.substr(B, " + specialStrLength + ", 1) AS B1 from nodb_blob1 WHERE ID = :id", + { id : id }, + { + outFormat : oracledb.ARRAY, + resultSet : true + }, + function(err, result) { + should.not.exist(err); + result.resultSet.getRow( + function(err, row) { + // console.log(row[0]); + should.not.exist(err); + var resultVal = row[0]; + var buffer2Compare = node6plus ? Buffer.from(specialStr, "utf-8") : new Buffer(specialStr, "utf-8"); + compareClientFetchResult(err, resultVal, specialStr, buffer2Compare, specialStrLength); + result.resultSet.close(function(err) { + should.not.exist(err); + cb(); + }); + } + ); + } + ); + } + ], done); + }); // 87.5.7 + + it('87.5.8 works with EMPTY_BLOB()', function(done) { + var id = insertID++; + var content = "EMPTY_BLOB"; + + insertAndFetch(id, null, content, null, done); + }); // 87.5.8 + + it('87.5.9 fetch multiple BLOB rows as Buffer', function(done) { + var id_1 = insertID++; + var specialStr_1 = '87.5.9_1'; + var contentLength_1 = 200; + var strBuf_1 = random.getRandomString(contentLength_1, specialStr_1); + var content_1 = node6plus ? Buffer.from(strBuf_1, "utf-8") : new Buffer(strBuf_1, "utf-8"); + var id_2 = insertID++; + var specialStr_2 = '87.5.9_2'; + var contentLength_2 = 100; + var strBuf_2 = random.getRandomString(contentLength_2, specialStr_2); + var content_2 = node6plus ? Buffer.from(strBuf_2, "utf-8") : new Buffer(strBuf_2, "utf-8"); + + async.series([ + function(cb) { + insertIntoBlobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoBlobTable1(id_2, content_2, cb); + }, + function(cb) { + var rowNumFetched = 2; + connection.execute( + "SELECT ID, B from nodb_blob1 WHERE ID = " + id_1 + " or id = " + id_2, + { }, + { + outFormat : oracledb.ARRAY, + resultSet : true + }, + function(err, result) { + should.not.exist(err); + result.resultSet.getRows( + rowNumFetched, + function(err, row) { + should.not.exist(err); + var resultVal = row[0][1]; + compareClientFetchResult(err, resultVal, specialStr_1, content_1, contentLength_1); + resultVal = row[1][1]; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + result.resultSet.close(function(err) { + should.not.exist(err); + cb(); + }); + } + ); + } + ); + } + ], done); + }); // 87.5.9 + + it('87.5.10 fetch the same BLOB column multiple times', function(done) { + var id = insertID++; + var specialStr = '87.5.10'; + var contentLength = 200; + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + async.series([ + function(cb) { + insertIntoBlobTable1(id, content, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, B AS B1, B AS B2 from nodb_blob1 WHERE ID = " + id, + { }, + { + outFormat : oracledb.ARRAY, + resultSet : true + }, + function(err, result) { + should.not.exist(err); + result.resultSet.getRow( + function(err, row) { + should.not.exist(err); + var resultVal = row[1]; + compareClientFetchResult(err, resultVal, specialStr, content, contentLength); + resultVal = row[2]; + compareClientFetchResult(err, resultVal, specialStr, content, contentLength); + result.resultSet.close(function(err) { + should.not.exist(err); + cb(); + }); + } + ); + } + ); + } + ], done); + }); // 87.5.10 + + it('87.5.11 works with update statement', function(done) { + var id = insertID++; + var specialStr_1 = '87.5.11_1'; + var contentLength_1 = 208; + var strBuf_1 = random.getRandomString(contentLength_1, specialStr_1); + var content_1 = node6plus ? Buffer.from(strBuf_1, "utf-8") : new Buffer(strBuf_1, "utf-8"); + var specialStr_2 = '87.5.11_2'; + var contentLength_2 = 208; + var strBuf_2 = random.getRandomString(contentLength_2, specialStr_2); + var content_2 = node6plus ? Buffer.from(strBuf_2, "utf-8") : new Buffer(strBuf_2, "utf-8"); + + async.series([ + function(cb) { + insertAndFetch(id, specialStr_1, content_1, contentLength_1, cb); + }, + function(cb) { + updateBlobTable1(id, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, B from nodb_blob1 WHERE ID = " + id, + { }, + { + outFormat : oracledb.ARRAY, + resultSet : true + }, + function(err, result) { + should.not.exist(err); + result.resultSet.getRow( + function(err, row) { + should.not.exist(err); + var resultVal = row[1]; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + result.resultSet.close(function(err) { + should.not.exist(err); + cb(); + }); + } + ); + } + ); + } + ], done); + }); // 87.5.11 + + it('87.5.12 works with REF CURSOR', function(done) { + var id = insertID++; + var specialStr = '87.5.12'; + var contentLength = 100; + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + async.series([ + function(cb) { + insertIntoBlobTable1(id, content, cb); + }, + function(cb) { + var ref_proc = "CREATE OR REPLACE PROCEDURE nodb_ref(blob_cursor OUT SYS_REFCURSOR)\n" + + "AS \n" + + "BEGIN \n" + + " OPEN blob_cursor FOR \n" + + " SELECT B from nodb_blob1 WHERE ID = " + id + "; \n" + + "END;"; + connection.execute( + ref_proc, + function(err){ + should.not.exist(err); + cb(); + } + ); + }, + function(cb) { + var sql = "BEGIN nodb_ref(:b); END;"; + var bindVar = { + b: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT } + }; + connection.execute( + sql, + bindVar, + function(err, result) { + result.outBinds.b.getRows(3, function(err, rows) { + var resultVal = rows[0][0]; + compareClientFetchResult(err, resultVal, specialStr, content, contentLength); + cb(); + }); + } + ); + }, + function(cb) { + var ref_proc_drop = "DROP PROCEDURE nodb_ref"; + connection.execute( + ref_proc_drop, + function(err){ + should.not.exist(err); + cb(); + } + ); + } + ], done); + }); // 87.5.12 + + it('87.5.13 fetch BLOB with stream', function(done) { + var id = insertID++; + var specialStr = '87.5.13'; + var contentLength = 200; + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + async.series([ + function(cb) { + insertIntoBlobTable1(id, content, cb); + }, + function(cb) { + oracledb.fetchAsBuffer = []; + connection.execute( + "SELECT B from nodb_blob1 WHERE ID = " + id, + function(err, result) { + should.not.exist(err); + var lob = result.rows[0][0]; + should.exist(lob); + var blobData = node6plus ? Buffer.alloc(0) : new Buffer(0); + var totalLength = 0; + + lob.on('data', function(chunk) { + totalLength = totalLength + chunk.length; + blobData = Buffer.concat([blobData, chunk], totalLength); + }); + + lob.on('error', function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + lob.on('end', function() { + compareClientFetchResult(err, blobData, specialStr, content, contentLength); + cb(); + }); + } + ); + } + ], done); + }); // 87.5.13 + + it('87.5.14 works with setting oracledb.maxRows < actual number of rows in the table', function(done) { + var id_1 = insertID++; + var specialStr_1 = '87.5.14_1'; + var contentLength_1 = 200; + var strBuf_1 = random.getRandomString(contentLength_1, specialStr_1); + var content_1 = node6plus ? Buffer.from(strBuf_1, "utf-8") : new Buffer(strBuf_1, "utf-8"); + var id_2 = insertID++; + var specialStr_2 = '87.5.14_2'; + var contentLength_2 = 100; + var strBuf_2 = random.getRandomString(contentLength_2, specialStr_2); + var content_2 = node6plus ? Buffer.from(strBuf_2, "utf-8") : new Buffer(strBuf_2, "utf-8"); + var maxRowsBak = oracledb.maxRows; + oracledb.maxRows = 1; + + async.series([ + function(cb) { + insertIntoBlobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoBlobTable1(id_2, content_2, cb); + }, + function(cb) { + var rowNumFetched = 2; + connection.execute( + "SELECT ID, B from nodb_blob1 WHERE id = " + id_1 + " or id = " +id_2, + { }, + { + outFormat : oracledb.ARRAY, + resultSet : true + }, + function(err, result) { + should.not.exist(err); + result.resultSet.getRows( + rowNumFetched, + function(err, row) { + should.not.exist(err); + should.strictEqual(row.length, 2); + var resultVal = row[0][1]; + compareClientFetchResult(err, resultVal, specialStr_1, content_1, contentLength_1); + resultVal = row[1][1]; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + oracledb.maxRows =maxRowsBak; + result.resultSet.close(function(err) { + should.not.exist(err); + cb(); + }); + } + ); + } + ); + } + ], done); + }); // 87.5.14 + + it('87.5.15 works with setting oracledb.maxRows > actual number of rows in the table', function(done) { + var id_1 = insertID++; + var specialStr_1 = '87.5.15_1'; + var contentLength_1 = 200; + var strBuf_1 = random.getRandomString(contentLength_1, specialStr_1); + var content_1 = node6plus ? Buffer.from(strBuf_1, "utf-8") : new Buffer(strBuf_1, "utf-8"); + var id_2 = insertID++; + var specialStr_2 = '87.5.15_2'; + var contentLength_2 = 100; + var strBuf_2 = random.getRandomString(contentLength_2, specialStr_2); + var content_2 = node6plus ? Buffer.from(strBuf_2, "utf-8") : new Buffer(strBuf_2, "utf-8"); + var maxRowsBak = oracledb.maxRows; + oracledb.maxRows = 10; + + async.series([ + function(cb) { + insertIntoBlobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoBlobTable1(id_2, content_2, cb); + }, + function(cb) { + var rowNumFetched = 2; + connection.execute( + "SELECT ID, B from nodb_blob1 WHERE id = " + id_1 + " or id = " +id_2, + { }, + { + outFormat : oracledb.ARRAY, + resultSet : true + }, + function(err, result) { + should.not.exist(err); + result.resultSet.getRows( + rowNumFetched, + function(err, row) { + should.not.exist(err); + should.strictEqual(row.length, 2); + var resultVal = row[0][1]; + compareClientFetchResult(err, resultVal, specialStr_1, content_1, contentLength_1); + resultVal = row[1][1]; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + oracledb.maxRows =maxRowsBak; + result.resultSet.close(function(err) { + should.not.exist(err); + cb(); + }); + } + ); + } + ); + } + ], done); + }); // 87.5.15 + + it('87.5.16 override oracledb.fetchAsBuffer with fetchInfo set to oracledb.DEFAULT', function(done) { + var id = insertID++; + var specialStr = '87.5.16'; + var contentLength = 20; + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + async.series([ + function(cb) { + insertIntoBlobTable1(id, content, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, B from nodb_blob1 WHERE ID = :id", + { id : id }, + { + fetchInfo : { B : { type : oracledb.DEFAULT } } + }, + function(err, result) { + should.not.exist(err); + var lob = result.rows[0][1]; + should.exist(lob); + var blobData = node6plus ? Buffer.alloc(0) : new Buffer(0); + var totalLength = 0; + + lob.on('data', function(chunk) { + totalLength = totalLength + chunk.length; + blobData = Buffer.concat([blobData, chunk], totalLength); + }); + + lob.on('error', function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + lob.on('end', function() { + compareClientFetchResult(err, blobData, specialStr, content, contentLength); + cb(); + }); + } + ); + } + ], done); + }); // 87.5.16 + + }); // 87.5 + +}); diff --git a/test/fetchBlobAsBuffer2.js b/test/fetchBlobAsBuffer2.js new file mode 100644 index 00000000..6138a3a0 --- /dev/null +++ b/test/fetchBlobAsBuffer2.js @@ -0,0 +1,2194 @@ +/* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with the Apache + * License, Version 2.0 (the "License.") + * + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + * The node-oracledb test suite uses 'mocha', 'should' and 'async'. + * See LICENSE.md for relevant licenses. + * + * NAME + * 88. fetchBlobAsBuffer2.js + * + * DESCRIPTION + * Testing Oracle data type support - BLOB. + * To fetch BLOB columns as buffer by setting fetchInfo option. + * + * NUMBERING RULE + * Test numbers follow this numbering rule: + * 1 - 20 are reserved for basic functional tests + * 21 - 50 are reserved for data type supporting tests + * 51 onwards are for other tests + * + *****************************************************************************/ +'use strict'; + +var oracledb = require('oracledb'); +var async = require('async'); +var should = require('should'); +var file = require('./file.js'); +var dbConfig = require('./dbconfig.js'); +var random = require('./random.js'); +var assist = require('./dataTypeAssist.js'); + +describe('88. fetchBlobAsBuffer2.js', function() { + this.timeout(100000); + var connection = null; + var node6plus = false; // assume node runtime version is lower than 6 + var insertID = 1; // assume id for insert into db starts from 1 + var inFileName = './test/blobTmpFile.txt'; + + var proc_create_table1 = "BEGIN \n" + + " DECLARE \n" + + " e_table_missing EXCEPTION; \n" + + " PRAGMA EXCEPTION_INIT(e_table_missing, -00942);\n" + + " BEGIN \n" + + " EXECUTE IMMEDIATE ('DROP TABLE nodb_blob1 PURGE' ); \n" + + " EXCEPTION \n" + + " WHEN e_table_missing \n" + + " THEN NULL; \n" + + " END; \n" + + " EXECUTE IMMEDIATE ( ' \n" + + " CREATE TABLE nodb_blob1 ( \n" + + " ID NUMBER, \n" + + " B BLOB \n" + + " ) \n" + + " '); \n" + + "END; "; + var drop_table1 = "DROP TABLE nodb_blob1 PURGE"; + + before('get one connection', function(done) { + async.series([ + function(cb) { + oracledb.stmtCacheSize = 0; + oracledb.getConnection(dbConfig, function(err, conn) { + should.not.exist(err); + connection = conn; + if(process.versions["node"].substring(0,1) >= "6") + node6plus = true; + cb(); + }); + }, + function(cb) { + file.create(inFileName); + cb(); + } + ], done); + + }); // before + + after('release connection', function(done) { + async.series([ + function(cb) { + connection.release(function(err) { + should.not.exist(err); + cb(); + }); + }, + function(cb) { + file.delete(inFileName); + cb(); + } + ], done); + }); // after + + // Generic function to insert a single row given ID, and data + var insertIntoBlobTable1 = function(id, content, callback) { + if(content == "EMPTY_BLOB") { + connection.execute( + "INSERT INTO nodb_blob1 VALUES (:ID, EMPTY_BLOB())", + [ id ], + function(err, result) { + should.not.exist(err); + should.strictEqual(result.rowsAffected, 1); + callback(); + } + ); + } else { + connection.execute( + "INSERT INTO nodb_blob1 VALUES (:ID, :B)", + { + ID : { val : id }, + B : { val : content, dir : oracledb.BIND_IN, type : oracledb.BUFFER } + }, + function(err, result) { + should.not.exist(err); + should.strictEqual(result.rowsAffected, 1); + callback(); + } + ); + } + }; + + var updateBlobTable1 = function(id, content, callback) { + connection.execute( + "UPDATE nodb_blob1 set B = :B where ID = :ID", + { ID: id, B: content }, + function(err, result){ + should.not.exist(err); + should.strictEqual(result.rowsAffected, 1); + callback(); + } + ); + }; + + // compare fetch result + var compareClientFetchResult = function(err, resultVal, specialStr, content, contentLength) { + should.not.exist(err); + compareBuffers(resultVal, specialStr, content, contentLength); + }; + + // compare two buffers + var compareBuffers = function(resultVal, specialStr, content, contentLength) { + should.equal(resultVal.length, contentLength); + var compareBuffer = assist.compare2Buffers(resultVal, content); + should.strictEqual(compareBuffer, true); + }; + + describe('88.1 fetch BLOB columns by setting fetchInfo option', function() { + + before('Create table and populate', function(done) { + connection.execute( + proc_create_table1, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // before + + after('drop table', function(done) { + connection.execute( + drop_table1, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // after + + insertID = 0; + var insertAndFetch = function(id, specialStr, insertContent, insertContentLength, callback) { + async.series([ + function(cb) { + insertIntoBlobTable1(id, insertContent, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, B from nodb_blob1 WHERE ID = :id", + { id : id }, + { + fetchInfo : { B : { type : oracledb.BUFFER } } + }, + function(err, result) { + var resultVal = result.rows[0][1]; + if(specialStr === null) { + should.equal(resultVal, null); + } else { + compareClientFetchResult(err, resultVal, specialStr, insertContent, insertContentLength); + } + cb(); + } + ); + } + ], callback); + }; + + it('88.1.1 works with NULL value', function(done) { + var id = insertID++; + var content = null; + + insertAndFetch(id, null, content, null, done); + }); // 88.1.1 + + it('88.1.2 works with empty Buffer', function(done) { + var id = insertID++; + var content = node6plus ? Buffer.from("", "utf-8") : new Buffer("", "utf-8"); + + insertAndFetch(id, null, content, null, done); + }); // 88.1.2 + + it('88.1.3 works with small value', function(done) { + var id = insertID++; + var specialStr = '88.1.3'; + var contentLength = 20; + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 88.1.3 + + it('88.1.4 works with (64K - 1) value', function(done) { + var id = insertID++; + var specialStr = '88.1.4'; + var contentLength = 65535; + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 88.1.4 + + it('88.1.5 works with (64K + 1) value', function(done) { + var id = insertID++; + var specialStr = '88.1.5'; + var contentLength = 65537; + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 88.1.5 + + it('88.1.6 works with (1MB + 1) value', function(done) { + var id = insertID++; + var specialStr = '88.1.6'; + var contentLength = 1048577; // 1MB + 1 + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 88.1.6 + + it('88.1.7 works with dbms_lob.substr()', function(done) { + var id = insertID++; + var specialStr = '88.1.7'; + var contentLength = 200; + var specialStrLength = specialStr.length; + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + async.series([ + function(cb) { + insertIntoBlobTable1(id, content, cb); + }, + function(cb) { + connection.execute( + "SELECT dbms_lob.substr(B, " + specialStrLength + ", 1) AS B1 from nodb_blob1 WHERE ID = :id", + { id : id }, + { + fetchInfo : { B1 : { type : oracledb.BUFFER } } + }, + function(err, result) { + should.not.exist(err); + // console.log(result); + var resultVal = result.rows[0][0]; + var buffer2Compare = node6plus ? Buffer.from(specialStr, "utf-8") : new Buffer(specialStr, "utf-8"); + compareClientFetchResult(err, resultVal, specialStr, buffer2Compare, specialStrLength); + cb(); + } + ); + } + ], done); + }); // 88.1.7 + + it('88.1.8 works with EMPTY_BLOB()', function(done) { + var id = insertID++; + var content = "EMPTY_BLOB"; + + insertAndFetch(id, null, content, null, done); + }); // 88.1.8 + + it('88.1.9 fetch multiple BLOB rows as Buffer', function(done) { + var id_1 = insertID++; + var specialStr_1 = '88.1.9_1'; + var contentLength_1 = 200; + var strBuf_1 = random.getRandomString(contentLength_1, specialStr_1); + var content_1 = node6plus ? Buffer.from(strBuf_1, "utf-8") : new Buffer(strBuf_1, "utf-8"); + var id_2 = insertID++; + var specialStr_2 = '88.1.9_2'; + var contentLength_2 = 100; + var strBuf_2 = random.getRandomString(contentLength_2, specialStr_2); + var content_2 = node6plus ? Buffer.from(strBuf_2, "utf-8") : new Buffer(strBuf_2, "utf-8"); + + async.series([ + function(cb) { + insertIntoBlobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoBlobTable1(id_2, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, B from nodb_blob1 WHERE ID = " + id_1 + " or id = " + id_2, + { }, + { + fetchInfo : { B : { type : oracledb.BUFFER } } + }, + function(err, result) { + should.not.exist(err); + var resultVal = result.rows[0][1]; + compareClientFetchResult(err, resultVal, specialStr_1, content_1, contentLength_1); + resultVal = result.rows[1][1]; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + cb(); + } + ); + } + ], done); + }); // 88.1.9 + + it('88.1.10 fetch the same BLOB column multiple times', function(done) { + var id = insertID++; + var specialStr = '88.1.10'; + var contentLength = 200; + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + async.series([ + function(cb) { + insertIntoBlobTable1(id, content, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, B AS B1, B AS B2 from nodb_blob1 WHERE ID = " + id, + { }, + { + fetchInfo : { + B1 : { type : oracledb.BUFFER }, + B2 : { type : oracledb.BUFFER } } + }, + function(err, result) { + should.not.exist(err); + var resultVal = result.rows[0][1]; + compareClientFetchResult(err, resultVal, specialStr, content, contentLength); + resultVal = result.rows[0][2]; + compareClientFetchResult(err, resultVal, specialStr, content, contentLength); + cb(); + } + ); + } + ], done); + }); // 88.1.10 + + it('88.1.11 works with update statement', function(done) { + var id = insertID++; + var specialStr_1 = '88.1.11_1'; + var contentLength_1 = 200; + var strBuf_1 = random.getRandomString(contentLength_1, specialStr_1); + var content_1 = node6plus ? Buffer.from(strBuf_1, "utf-8") : new Buffer(strBuf_1, "utf-8"); + var specialStr_2 = '88.1.11_2'; + var contentLength_2 = 208; + var strBuf_2 = random.getRandomString(contentLength_2, specialStr_2); + var content_2 = node6plus ? Buffer.from(strBuf_2, "utf-8") : new Buffer(strBuf_2, "utf-8"); + + async.series([ + function(cb) { + insertAndFetch(id, specialStr_1, content_1, contentLength_1, cb); + }, + function(cb) { + updateBlobTable1(id, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, B from nodb_blob1 WHERE ID = " + id, + { }, + { + fetchInfo : { B : { type : oracledb.BUFFER } } + }, + function(err, result) { + should.not.exist(err); + var resultVal = result.rows[0][1]; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + cb(); + } + ); + } + ], done); + }); // 88.1.8 + + it('88.1.12 works with setting oracledb.maxRows < actual number of rows in the table', function(done) { + var id_1 = insertID++; + var specialStr_1 = '88.1.12_1'; + var contentLength_1 = 200; + var strBuf_1 = random.getRandomString(contentLength_1, specialStr_1); + var content_1 = node6plus ? Buffer.from(strBuf_1, "utf-8") : new Buffer(strBuf_1, "utf-8"); + var id_2 = insertID++; + var specialStr_2 = '88.1.12_2'; + var contentLength_2 = 100; + var strBuf_2 = random.getRandomString(contentLength_2, specialStr_2); + var content_2 = node6plus ? Buffer.from(strBuf_2, "utf-8") : new Buffer(strBuf_2, "utf-8"); + var maxRowsBak = oracledb.maxRows; + oracledb.maxRows = 1; + + async.series([ + function(cb) { + insertIntoBlobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoBlobTable1(id_2, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, B from nodb_blob1 WHERE id = " + id_1 + " or id = " +id_2, + { }, + { + fetchInfo : { B : { type : oracledb.BUFFER } } + }, + function(err, result) { + should.not.exist(err); + result.rows.length.should.eql(1); + var resultVal = result.rows[0][1]; + compareClientFetchResult(err, resultVal, specialStr_1, content_1, contentLength_1); + oracledb.maxRows = maxRowsBak; + cb(); + } + ); + } + ], done); + }); // 88.1.12 + + it('88.1.13 works with setting oracledb.maxRows > actual number of rows in the table', function(done) { + var id_1 = insertID++; + var specialStr_1 = '88.1.13_1'; + var contentLength_1 = 200; + var strBuf_1 = random.getRandomString(contentLength_1, specialStr_1); + var content_1 = node6plus ? Buffer.from(strBuf_1, "utf-8") : new Buffer(strBuf_1, "utf-8"); + var id_2 = insertID++; + var specialStr_2 = '88.1.13_2'; + var contentLength_2 = 100; + var strBuf_2 = random.getRandomString(contentLength_2, specialStr_2); + var content_2 = node6plus ? Buffer.from(strBuf_2, "utf-8") : new Buffer(strBuf_2, "utf-8"); + var maxRowsBak = oracledb.maxRows; + oracledb.maxRows = 10; + + async.series([ + function(cb) { + insertIntoBlobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoBlobTable1(id_2, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, B from nodb_blob1 WHERE id = " + id_1 + " or id = " +id_2, + { }, + { + fetchInfo : { B : { type : oracledb.BUFFER } } + }, + function(err, result) { + should.not.exist(err); + result.rows.length.should.eql(2); + var resultVal = result.rows[0][1]; + compareClientFetchResult(err, resultVal, specialStr_1, content_1, contentLength_1); + resultVal = result.rows[1][1]; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + oracledb.maxRows = maxRowsBak; + cb(); + } + ); + } + ], done); + }); // 88.1.13 + + it('88.1.14 works with connection.queryStream()', function(done) { + var id = insertID++; + var specialStr = '88.1.14'; + var contentLength = 200; + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + async.series([ + function(cb) { + insertIntoBlobTable1(id, content, cb); + }, + function(cb) { + var sql = "SELECT ID, B from nodb_blob1 WHERE ID = " + id; + var stream = connection.queryStream(sql, {}, { fetchInfo : { B : { type : oracledb.BUFFER } } }); + stream.on('error', function (error) { + should.fail(error, null, 'Error event should not be triggered'); + }); + + var counter = 0; + stream.on('data', function(data) { + should.exist(data); + var result = data[1]; + compareBuffers(result, specialStr, content, contentLength); + counter++; + }); + + stream.on('end', function () { + should.equal(counter, 1); + setTimeout(cb, 500); + }); + } + ], done); + }); // 88.1.14 + + it('88.1.15 works with connection.queryStream() and oracledb.maxRows > actual number of rows in the table', function(done) { + var id_1 = insertID++; + var specialStr_1 = '88.1.15_1'; + var contentLength_1 = 26; + var strBuf_1 = random.getRandomString(contentLength_1, specialStr_1); + var content_1 = node6plus ? Buffer.from(strBuf_1, "utf-8") : new Buffer(strBuf_1, "utf-8"); + var id_2 = insertID++; + var specialStr_2 = '88.1.15_2'; + var contentLength_2 = 30; + var strBuf_2 = random.getRandomString(contentLength_2, specialStr_2); + var content_2 = node6plus ? Buffer.from(strBuf_2, "utf-8") : new Buffer(strBuf_2, "utf-8"); + var maxRowsBak = oracledb.maxRows; + oracledb.maxRows = 20; + + async.series([ + function(cb) { + insertIntoBlobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoBlobTable1(id_2, content_2, cb); + }, + function(cb) { + var sql = "SELECT ID, B from nodb_blob1 WHERE ID = " + id_1 + " or id = " +id_2; + var stream = connection.queryStream(sql, {}, { fetchInfo : { B : { type : oracledb.BUFFER } } }); + stream.on('error', function (error) { + should.fail(error, null, 'Error event should not be triggered'); + }); + + var counter = 0; + stream.on('data', function(data) { + should.exist(data); + var result = data[1]; + counter++; + if(counter == 1) { + compareBuffers(result, specialStr_1, content_1, contentLength_1); + } else { + compareBuffers(result, specialStr_2, content_2, contentLength_2); + } + }); + + stream.on('end', function () { + should.equal(counter, 2); + oracledb.maxRows = maxRowsBak; + setTimeout(cb, 500); + }); + } + ], done); + }); // 88.1.15 + + it('88.1.16 works with connection.queryStream() and oracledb.maxRows = actual number of rows in the table', function(done) { + var id_1 = insertID++; + var specialStr_1 = '88.1.16_1'; + var contentLength_1 = 26; + var strBuf_1 = random.getRandomString(contentLength_1, specialStr_1); + var content_1 = node6plus ? Buffer.from(strBuf_1, "utf-8") : new Buffer(strBuf_1, "utf-8"); + var id_2 = insertID++; + var specialStr_2 = '88.1.16_2'; + var contentLength_2 = 30; + var strBuf_2 = random.getRandomString(contentLength_2, specialStr_2); + var content_2 = node6plus ? Buffer.from(strBuf_2, "utf-8") : new Buffer(strBuf_2, "utf-8"); + var maxRowsBak = oracledb.maxRows; + oracledb.maxRows = 2; + + async.series([ + function(cb) { + insertIntoBlobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoBlobTable1(id_2, content_2, cb); + }, + function(cb) { + var sql = "SELECT ID, B from nodb_blob1 WHERE ID = " + id_1 + " or id = " +id_2; + var stream = connection.queryStream(sql, {}, { fetchInfo : { B : { type : oracledb.BUFFER } } }); + stream.on('error', function (error) { + should.fail(error, null, 'Error event should not be triggered'); + }); + + var counter = 0; + stream.on('data', function(data) { + should.exist(data); + var result = data[1]; + counter++; + if(counter == 1) { + compareBuffers(result, specialStr_1, content_1, contentLength_1); + } else { + compareBuffers(result, specialStr_2, content_2, contentLength_2); + } + }); + + stream.on('end', function () { + should.equal(counter, 2); + oracledb.maxRows = maxRowsBak; + setTimeout(cb, 500); + }); + } + ], done); + }); // 88.1.16 + + it('88.1.17 works with connection.queryStream() and oracledb.maxRows < actual number of rows in the table', function(done) { + var id_1 = insertID++; + var specialStr_1 = '88.1.17_1'; + var contentLength_1 = 26; + var strBuf_1 = random.getRandomString(contentLength_1, specialStr_1); + var content_1 = node6plus ? Buffer.from(strBuf_1, "utf-8") : new Buffer(strBuf_1, "utf-8"); + var id_2 = insertID++; + var specialStr_2 = '88.1.17_2'; + var contentLength_2 = 30; + var strBuf_2 = random.getRandomString(contentLength_2, specialStr_2); + var content_2 = node6plus ? Buffer.from(strBuf_2, "utf-8") : new Buffer(strBuf_2, "utf-8"); + var maxRowsBak = oracledb.maxRows; + oracledb.maxRows = 1; + + async.series([ + function(cb) { + insertIntoBlobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoBlobTable1(id_2, content_2, cb); + }, + function(cb) { + var sql = "SELECT ID, B from nodb_blob1 WHERE ID = " + id_1 + " or id = " +id_2; + var stream = connection.queryStream(sql, {}, { fetchInfo : { B : { type : oracledb.BUFFER } } }); + stream.on('error', function (error) { + should.fail(error, null, 'Error event should not be triggered'); + }); + + var counter = 0; + stream.on('data', function(data) { + should.exist(data); + var result = data[1]; + counter++; + if(counter == 1) { + compareBuffers(result, specialStr_1, content_1, contentLength_1); + } else { + compareBuffers(result, specialStr_2, content_2, contentLength_2); + } + }); + + stream.on('end', function () { + should.equal(counter, 2); + oracledb.maxRows = maxRowsBak; + setTimeout(cb, 500); + }); + } + ], done); + }); // 88.1.17 + + }); // 88.1 + + describe('88.2 fetch BLOB columns by setting fetchInfo option and outFormat = oracledb.OBJECT', function() { + + before('Create table and populate', function(done) { + connection.execute( + proc_create_table1, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // before + + after('drop table', function(done) { + connection.execute( + drop_table1, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // after + + insertID = 0; + var insertAndFetch = function(id, specialStr, insertContent, insertContentLength, callback) { + async.series([ + function(cb) { + insertIntoBlobTable1(id, insertContent, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, B from nodb_blob1 WHERE ID = :id", + { id : id }, + { + outFormat : oracledb.OBJECT, + fetchInfo : { B : { type : oracledb.BUFFER } } + }, + function(err, result) { + var resultVal = result.rows[0].B; + if(specialStr === null) { + should.not.exist(err); + should.equal(resultVal, null); + } else { + should.not.exist(err); + compareClientFetchResult(err, resultVal, specialStr, insertContent, insertContentLength); + } + cb(); + } + ); + } + ], callback); + }; + + it('88.2.1 works with NULL value', function(done) { + var id = insertID++; + var content = null; + + insertAndFetch(id, null, content, null, done); + }); // 88.2.1 + + it('88.2.2 works with empty buffer', function(done) { + var id = insertID++; + var content = node6plus ? Buffer.from("", "utf-8") : new Buffer("", "utf-8"); + + insertAndFetch(id, null, content, null, done); + }); // 88.2.2 + + it('88.2.3 works with small value', function(done) { + var id = insertID++; + var specialStr = '88.2.3'; + var contentLength = 20; + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 88.2.3 + + it('88.2.4 works with (64K - 1) value', function(done) { + var id = insertID++; + var specialStr = '88.2.4'; + var contentLength = 65535; + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 88.2.4 + + it('88.2.5 works with (64K + 1) value', function(done) { + var id = insertID++; + var specialStr = '88.2.5'; + var contentLength = 65537; + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 88.2.5 + + it('88.2.6 works with (1MB + 1) value', function(done) { + var id = insertID++; + var specialStr = '88.2.6'; + var contentLength = 1048577; // 1MB + 1 + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 88.2.6 + + it('88.2.7 works with dbms_lob.substr()', function(done) { + var id = insertID++; + var specialStr = '88.2.7'; + var contentLength = 200; + var specialStrLength = specialStr.length; + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + async.series([ + function(cb) { + insertIntoBlobTable1(id, content, cb); + }, + function(cb) { + connection.execute( + "SELECT dbms_lob.substr(B, " + specialStrLength + ", 1) AS B1 from nodb_blob1 WHERE ID = :id", + { id : id }, + { + outFormat : oracledb.OBJECT, + fetchInfo : { B1 : { type : oracledb.BUFFER } } + }, + function(err, result) { + should.not.exist(err); + var resultVal = result.rows[0].B1; + var buffer2Compare = node6plus ? Buffer.from(specialStr, "utf-8") : new Buffer(specialStr, "utf-8"); + compareClientFetchResult(err, resultVal, specialStr, buffer2Compare, specialStrLength); + cb(); + } + ); + } + ], done); + }); // 88.2.7 + + it('88.2.8 works with EMPTY_BLOB()', function(done) { + var id = insertID++; + var content = "EMPTY_BLOB"; + + insertAndFetch(id, null, content, null, done); + }); // 88.2.8 + + it('88.2.9 fetch multiple BLOB rows as Buffer', function(done) { + var id_1 = insertID++; + var specialStr_1 = '88.2.9_1'; + var contentLength_1 = 200; + var strBuf_1 = random.getRandomString(contentLength_1, specialStr_1); + var content_1 = node6plus ? Buffer.from(strBuf_1, "utf-8") : new Buffer(strBuf_1, "utf-8"); + var id_2 = insertID++; + var specialStr_2 = '88.2.9_2'; + var contentLength_2 = 100; + var strBuf_2 = random.getRandomString(contentLength_2, specialStr_2); + var content_2 = node6plus ? Buffer.from(strBuf_2, "utf-8") : new Buffer(strBuf_2, "utf-8"); + + async.series([ + function(cb) { + insertIntoBlobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoBlobTable1(id_2, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, B from nodb_blob1 WHERE ID = " + id_1 + " or id = " + id_2, + { }, + { + outFormat : oracledb.OBJECT, + fetchInfo : { B : { type : oracledb.BUFFER } } + }, + function(err, result) { + should.not.exist(err); + var resultVal = result.rows[0].B; + compareClientFetchResult(err, resultVal, specialStr_1, content_1, contentLength_1); + resultVal = result.rows[1].B; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + cb(); + } + ); + } + ], done); + }); // 88.2.9 + + it('88.2.10 fetch the same BLOB column multiple times', function(done) { + var id = insertID++; + var specialStr = '88.2.10'; + var contentLength = 200; + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + async.series([ + function(cb) { + insertIntoBlobTable1(id, content, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, B AS B1, B AS B2 from nodb_blob1 WHERE ID = " + id, + { }, + { + outFormat : oracledb.OBJECT, + fetchInfo : { + B1 : { type : oracledb.BUFFER }, + B2 : { type : oracledb.BUFFER } } + }, + function(err, result) { + should.not.exist(err); + var resultVal = result.rows[0].B1; + compareClientFetchResult(err, resultVal, specialStr, content, contentLength); + resultVal = result.rows[0].B2; + compareClientFetchResult(err, resultVal, specialStr, content, contentLength); + cb(); + } + ); + } + ], done); + }); // 88.2.10 + + it('88.2.11 works with update statement', function(done) { + var id = insertID++; + var specialStr_1 = '88.2.11_1'; + var contentLength_1 = 200; + var strBuf_1 = random.getRandomString(contentLength_1, specialStr_1); + var content_1 = node6plus ? Buffer.from(strBuf_1, "utf-8") : new Buffer(strBuf_1, "utf-8"); + var specialStr_2 = '88.2.11_2'; + var contentLength_2 = 202; + var strBuf_2 = random.getRandomString(contentLength_2, specialStr_2); + var content_2 = node6plus ? Buffer.from(strBuf_2, "utf-8") : new Buffer(strBuf_2, "utf-8"); + + async.series([ + function(cb) { + insertAndFetch(id, specialStr_1, content_1, contentLength_1, cb); + }, + function(cb) { + updateBlobTable1(id, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, B from nodb_blob1 WHERE ID = " + id, + { }, + { + outFormat : oracledb.OBJECT, + fetchInfo : { B : { type : oracledb.BUFFER } } + }, + function(err, result) { + should.not.exist(err); + var resultVal = result.rows[0].B; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + cb(); + } + ); + } + ], done); + }); // 88.2.11 + + it('88.2.12 works with setting oracledb.maxRows < actual number of rows in the table', function(done) { + var id_1 = insertID++; + var specialStr_1 = '88.2.12_1'; + var contentLength_1 = 200; + var strBuf_1 = random.getRandomString(contentLength_1, specialStr_1); + var content_1 = node6plus ? Buffer.from(strBuf_1, "utf-8") : new Buffer(strBuf_1, "utf-8"); + var id_2 = insertID++; + var specialStr_2 = '88.2.12_2'; + var contentLength_2 = 100; + var strBuf_2 = random.getRandomString(contentLength_2, specialStr_2); + var content_2 = node6plus ? Buffer.from(strBuf_2, "utf-8") : new Buffer(strBuf_2, "utf-8"); + var maxRowsBak = oracledb.maxRows; + oracledb.maxRows = 1; + + async.series([ + function(cb) { + insertIntoBlobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoBlobTable1(id_2, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, B from nodb_blob1 WHERE id = " + id_1 + " or id = " +id_2, + { }, + { + outFormat : oracledb.OBJECT, + fetchInfo : { B : { type : oracledb.BUFFER } } + }, + function(err, result) { + should.not.exist(err); + result.rows.length.should.eql(1); + var resultVal = result.rows[0].B; + compareClientFetchResult(err, resultVal, specialStr_1, content_1, contentLength_1); + oracledb.maxRows = maxRowsBak; + cb(); + } + ); + } + ], done); + }); // 88.2.12 + + it('88.2.13 works with setting oracledb.maxRows > actual number of rows in the table', function(done) { + var id_1 = insertID++; + var specialStr_1 = '88.2.13_1'; + var contentLength_1 = 200; + var strBuf_1 = random.getRandomString(contentLength_1, specialStr_1); + var content_1 = node6plus ? Buffer.from(strBuf_1, "utf-8") : new Buffer(strBuf_1, "utf-8"); + var id_2 = insertID++; + var specialStr_2 = '88.2.13_2'; + var contentLength_2 = 100; + var strBuf_2 = random.getRandomString(contentLength_2, specialStr_2); + var content_2 = node6plus ? Buffer.from(strBuf_2, "utf-8") : new Buffer(strBuf_2, "utf-8"); + var maxRowsBak = oracledb.maxRows; + oracledb.maxRows = 10; + + async.series([ + function(cb) { + insertIntoBlobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoBlobTable1(id_2, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, B from nodb_blob1 WHERE id = " + id_1 + " or id = " +id_2, + { }, + { + outFormat : oracledb.OBJECT, + fetchInfo : { B : { type : oracledb.BUFFER } } + }, + function(err, result) { + should.not.exist(err); + var resultVal = result.rows[0].B; + compareClientFetchResult(err, resultVal, specialStr_1, content_1, contentLength_1); + resultVal = result.rows[1].B; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + result.rows.length.should.eql(2); + oracledb.maxRows = maxRowsBak; + cb(); + } + ); + } + ], done); + }); // 88.2.13 + + }); // 88.2 + + describe('88.3 fetch BLOB columns by setting fetchInfo option, outFormat = oracledb.OBJECT and resultSet = true', function() { + + before('Create table and populate', function(done) { + connection.execute( + proc_create_table1, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // before + + after('drop table', function(done) { + connection.execute( + drop_table1, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // after + + insertID = 0; + var insertAndFetch = function(id, specialStr, insertContent, insertContentLength, callback) { + async.series([ + function(cb) { + insertIntoBlobTable1(id, insertContent, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, B from nodb_blob1 WHERE ID = :id", + { id : id }, + { + outFormat : oracledb.OBJECT, + fetchInfo : { B : { type : oracledb.BUFFER } }, + resultSet : true + }, + function(err, result) { + should.not.exist(err); + result.resultSet.getRow( + function(err, row) { + var resultVal; + resultVal = row.B; + if(specialStr === null) { + should.not.exist(err); + should.equal(resultVal, null); + } else { + compareClientFetchResult(err, resultVal, specialStr, insertContent, insertContentLength); + } + result.resultSet.close(function(err) { + should.not.exist(err); + cb(); + }); + } + ); + } + ); + } + ], callback); + }; + + it('88.3.1 works with NULL value', function(done) { + var id = insertID++; + var content = null; + + insertAndFetch(id, null, content, null, done); + }); // 88.3.1 + + it('88.3.2 works with empty buffer', function(done) { + var id = insertID++; + var content = node6plus ? Buffer.from("", "utf-8") : new Buffer("", "utf-8"); + + insertAndFetch(id, null, content, null, done); + }); // 88.3.2 + + it('88.3.3 works with small value', function(done) { + var id = insertID++; + var specialStr = '88.3.3'; + var contentLength = 20; + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 88.3.3 + + it('88.3.4 works with (64K - 1) value', function(done) { + var id = insertID++; + var specialStr = '88.3.4'; + var contentLength = 65535; + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 88.3.4 + + it('88.3.5 works with (64K + 1) value', function(done) { + var id = insertID++; + var specialStr = '88.3.4'; + var contentLength = 65537; + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 88.3.5 + + it('88.3.6 works with (1MB + 1) value', function(done) { + var id = insertID++; + var specialStr = '88.3.6'; + var contentLength = 1048577; // 1MB + 1 + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 88.3.6 + + it('88.3.7 works with dbms_lob.substr()', function(done) { + var id = insertID++; + var specialStr = '88.3.7'; + var contentLength = 200; + var specialStrLength = specialStr.length; + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + async.series([ + function(cb) { + insertIntoBlobTable1(id, content, cb); + }, + function(cb) { + connection.execute( + "SELECT dbms_lob.substr(B, " + specialStrLength + ", 1) AS B1 from nodb_blob1 WHERE ID = :id", + { id : id }, + { + outFormat : oracledb.OBJECT, + fetchInfo : { B1 : { type : oracledb.BUFFER } }, + resultSet : true + }, + function(err, result) { + should.not.exist(err); + result.resultSet.getRow( + function(err, row) { + should.not.exist(err); + var resultVal = row.B1; + var buffer2Compare = node6plus ? Buffer.from(specialStr, "utf-8") : new Buffer(specialStr, "utf-8"); + compareClientFetchResult(err, resultVal, specialStr, buffer2Compare, specialStrLength); + result.resultSet.close(function(err) { + should.not.exist(err); + cb(); + }); + } + ); + } + ); + } + ], done); + }); // 88.3.7 + + it('88.3.8 works with EMPTY_BLOB()', function(done) { + var id = insertID++; + var content = "EMPTY_BLOB"; + + insertAndFetch(id, null, content, null, done); + }); // 88.3.8 + + it('88.3.9 fetch multiple BLOB rows as Buffer', function(done) { + var id_1 = insertID++; + var specialStr_1 = '88.3.9_1'; + var contentLength_1 = 200; + var strBuf_1 = random.getRandomString(contentLength_1, specialStr_1); + var content_1 = node6plus ? Buffer.from(strBuf_1, "utf-8") : new Buffer(strBuf_1, "utf-8"); + var id_2 = insertID++; + var specialStr_2 = '88.3.9_2'; + var contentLength_2 = 100; + var strBuf_2 = random.getRandomString(contentLength_2, specialStr_2); + var content_2 = node6plus ? Buffer.from(strBuf_2, "utf-8") : new Buffer(strBuf_2, "utf-8"); + + async.series([ + function(cb) { + insertIntoBlobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoBlobTable1(id_2, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, B from nodb_blob1 WHERE ID = " + id_1 + " or id = " + id_2, + { }, + { + outFormat : oracledb.OBJECT, + fetchInfo : { B : { type : oracledb.BUFFER } }, + resultSet : true + }, + function(err, result) { + should.not.exist(err); + var rowNumFetched = 2; + result.resultSet.getRows( + rowNumFetched, + function(err, row) { + should.not.exist(err); + var resultVal = row[0].B; + compareClientFetchResult(err, resultVal, specialStr_1, content_1, contentLength_1); + resultVal = row[1].B; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + result.resultSet.close(function(err) { + should.not.exist(err); + cb(); + }); + } + ); + } + ); + } + ], done); + }); // 88.3.9 + + it('88.3.10 fetch the same BLOB column multiple times', function(done) { + var id = insertID++; + var specialStr = '88.3.10'; + var contentLength = 200; + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + async.series([ + function(cb) { + insertIntoBlobTable1(id, content, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, B AS B1, B AS B2 from nodb_blob1 WHERE ID = " + id, + { }, + { + outFormat : oracledb.OBJECT, + fetchInfo : { + B1 : { type : oracledb.BUFFER }, + B2 : { type : oracledb.BUFFER } }, + resultSet : true + }, + function(err, result) { + should.not.exist(err); + result.resultSet.getRow( + function(err, row) { + should.not.exist(err); + var resultVal = row.B1; + compareClientFetchResult(err, resultVal, specialStr, content, contentLength); + resultVal = row.B2; + compareClientFetchResult(err, resultVal, specialStr, content, contentLength); + result.resultSet.close(function(err) { + should.not.exist(err); + cb(); + }); + } + ); + } + ); + } + ], done); + }); // 88.3.10 + + it('88.3.11 works with update statement', function(done) { + var id = insertID++; + var specialStr_1 = '88.3.11_1'; + var contentLength_1 = 200; + var strBuf_1 = random.getRandomString(contentLength_1, specialStr_1); + var content_1 = node6plus ? Buffer.from(strBuf_1, "utf-8") : new Buffer(strBuf_1, "utf-8"); + var specialStr_2 = '88.3.11_2'; + var contentLength_2 = 202; + var strBuf_2 = random.getRandomString(contentLength_2, specialStr_2); + var content_2 = node6plus ? Buffer.from(strBuf_2, "utf-8") : new Buffer(strBuf_2, "utf-8"); + + async.series([ + function(cb) { + insertAndFetch(id, specialStr_1, content_1, contentLength_1, cb); + }, + function(cb) { + updateBlobTable1(id, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, B from nodb_blob1 WHERE ID = " + id, + { }, + { + outFormat : oracledb.OBJECT, + fetchInfo : { B : { type : oracledb.BUFFER } }, + resultSet : true + }, + function(err, result) { + should.not.exist(err); + result.resultSet.getRow( + function(err, row) { + should.not.exist(err); + var resultVal = row.B; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + result.resultSet.close(function(err) { + should.not.exist(err); + cb(); + }); + } + ); + } + ); + } + ], done); + }); // 88.3.11 + + it('88.3.12 works with setting oracledb.maxRows < actual number of rows in the table', function(done) { + var id_1 = insertID++; + var specialStr_1 = '88.3.12_1'; + var contentLength_1 = 200; + var strBuf_1 = random.getRandomString(contentLength_1, specialStr_1); + var content_1 = node6plus ? Buffer.from(strBuf_1, "utf-8") : new Buffer(strBuf_1, "utf-8"); + var id_2 = insertID++; + var specialStr_2 = '88.3.12_2'; + var contentLength_2 = 100; + var strBuf_2 = random.getRandomString(contentLength_2, specialStr_2); + var content_2 = node6plus ? Buffer.from(strBuf_2, "utf-8") : new Buffer(strBuf_2, "utf-8"); + var maxRowsBak = oracledb.maxRows; + oracledb.maxRows = 1; + + async.series([ + function(cb) { + insertIntoBlobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoBlobTable1(id_2, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, B from nodb_blob1 WHERE id = " + id_1 + " or id = " +id_2, + { }, + { + outFormat : oracledb.OBJECT, + fetchInfo : { B : { type : oracledb.BUFFER } }, + resultSet : true + }, + function(err, result) { + should.not.exist(err); + var rowNumFetched = 2; + result.resultSet.getRows( + rowNumFetched, + function(err, row) { + should.not.exist(err); + should.equal(row.length, 2); + var resultVal = row[0].B; + compareClientFetchResult(err, resultVal, specialStr_1, content_1, contentLength_1); + resultVal = row[1].B; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + oracledb.maxRows =maxRowsBak; + result.resultSet.close(function(err) { + should.not.exist(err); + cb(); + }); + } + ); + } + ); + } + ], done); + }); // 88.3.12 + + it('88.3.13 works with setting oracledb.maxRows > actual number of rows in the table', function(done) { + var id_1 = insertID++; + var specialStr_1 = '88.3.13_1'; + var contentLength_1 = 200; + var strBuf_1 = random.getRandomString(contentLength_1, specialStr_1); + var content_1 = node6plus ? Buffer.from(strBuf_1, "utf-8") : new Buffer(strBuf_1, "utf-8"); + var id_2 = insertID++; + var specialStr_2 = '88.3.13_2'; + var contentLength_2 = 100; + var strBuf_2 = random.getRandomString(contentLength_2, specialStr_2); + var content_2 = node6plus ? Buffer.from(strBuf_2, "utf-8") : new Buffer(strBuf_2, "utf-8"); + var maxRowsBak = oracledb.maxRows; + oracledb.maxRows = 10; + + async.series([ + function(cb) { + insertIntoBlobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoBlobTable1(id_2, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, B from nodb_blob1 WHERE id = " + id_1 + " or id = " +id_2, + { }, + { + outFormat : oracledb.OBJECT, + fetchInfo : { B : { type : oracledb.BUFFER } }, + resultSet : true + }, + function(err, result) { + should.not.exist(err); + var rowNumFetched = 2; + result.resultSet.getRows( + rowNumFetched, + function(err, row) { + should.not.exist(err); + should.equal(row.length, 2); + var resultVal = row[0].B; + compareClientFetchResult(err, resultVal, specialStr_1, content_1, contentLength_1); + resultVal = row[1].B; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + oracledb.maxRows =maxRowsBak; + result.resultSet.close(function(err) { + should.not.exist(err); + cb(); + }); + } + ); + } + ); + } + ], done); + }); // 88.3.13 + + }); // 88.3 + + describe('88.4 fetch BLOB columns by setting fetchInfo option and outFormat = oracledb.ARRAY', function() { + + before('Create table and populate', function(done) { + connection.execute( + proc_create_table1, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // before + + after('drop table', function(done) { + connection.execute( + drop_table1, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // after + + insertID = 0; + var insertAndFetch = function(id, specialStr, insertContent, insertContentLength, callback) { + async.series([ + function(cb) { + insertIntoBlobTable1(id, insertContent, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, B from nodb_blob1 WHERE ID = :id", + { id : id }, + { + outFormat : oracledb.ARRAY, + fetchInfo : { B : { type : oracledb.BUFFER } } + }, + function(err, result) { + var resultVal = result.rows[0][1]; + if(specialStr === null) { + should.not.exist(err); + should.equal(resultVal, null); + } else { + should.not.exist(err); + compareClientFetchResult(err, resultVal, specialStr, insertContent, insertContentLength); + } + cb(); + } + ); + } + ], callback); + }; + + it('88.4.1 works with NULL value', function(done) { + var id = insertID++; + var content = null; + + insertAndFetch(id, null, content, null, done); + }); // 88.4.1 + + it('88.4.2 works with empty Buffer', function(done) { + var id = insertID++; + var content = node6plus ? Buffer.from("", "utf-8") : new Buffer("", "utf-8"); + + insertAndFetch(id, null, content, null, done); + }); // 88.4.2 + + it('88.4.3 works with small value', function(done) { + var id = insertID++; + var specialStr = '88.4.3'; + var contentLength = 20; + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 88.4.3 + + it('88.4.4 works with (64K - 1) value', function(done) { + var id = insertID++; + var specialStr = '88.4.4'; + var contentLength = 65535; + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 88.4.4 + + it('88.4.5 works with (64K + 1) value', function(done) { + var id = insertID++; + var specialStr = '88.4.5'; + var contentLength = 65537; + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 88.4.5 + + it('88.4.6 works with (1MB + 1) value', function(done) { + var id = insertID++; + var specialStr = '88.4.6'; + var contentLength = 1048577; // 1MB + 1 + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 88.4.6 + + it('88.4.7 works with dbms_lob.substr()', function(done) { + var id = insertID++; + var specialStr = '88.4.7'; + var contentLength = 200; + var specialStrLength = specialStr.length; + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + async.series([ + function(cb) { + insertIntoBlobTable1(id, content, cb); + }, + function(cb) { + connection.execute( + "SELECT dbms_lob.substr(B, " + specialStrLength + ", 1) AS B1 from nodb_blob1 WHERE ID = :id", + { id : id }, + { + fetchInfo : { B1 : { type : oracledb.BUFFER } } + }, + function(err, result) { + should.not.exist(err); + // console.log(result); + var resultVal = result.rows[0][0]; + var buffer2Compare = node6plus ? Buffer.from(specialStr, "utf-8") : new Buffer(specialStr, "utf-8"); + compareClientFetchResult(err, resultVal, specialStr, buffer2Compare, specialStrLength); + cb(); + } + ); + } + ], done); + }); // 88.4.7 + + it('88.4.8 works with EMPTY_BLOB()', function(done) { + var id = insertID++; + var content = "EMPTY_BLOB"; + + insertAndFetch(id, null, content, null, done); + }); // 88.4.8 + + it('88.4.9 fetch multiple BLOB rows as Buffer', function(done) { + var id_1 = insertID++; + var specialStr_1 = '88.4.9_1'; + var contentLength_1 = 200; + var strBuf_1 = random.getRandomString(contentLength_1, specialStr_1); + var content_1 = node6plus ? Buffer.from(strBuf_1, "utf-8") : new Buffer(strBuf_1, "utf-8"); + var id_2 = insertID++; + var specialStr_2 = '88.4.9_2'; + var contentLength_2 = 100; + var strBuf_2 = random.getRandomString(contentLength_2, specialStr_2); + var content_2 = node6plus ? Buffer.from(strBuf_2, "utf-8") : new Buffer(strBuf_2, "utf-8"); + + async.series([ + function(cb) { + insertIntoBlobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoBlobTable1(id_2, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, B from nodb_blob1 WHERE ID = " + id_1 + " or id = " + id_2, + { }, + { + outFormat : oracledb.ARRAY, + fetchInfo : { B : { type : oracledb.BUFFER } } + }, + function(err, result) { + should.not.exist(err); + var resultVal = result.rows[0][1]; + compareClientFetchResult(err, resultVal, specialStr_1, content_1, contentLength_1); + resultVal = result.rows[1][1]; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + cb(); + } + ); + } + ], done); + }); // 88.4.9 + + it('88.4.10 fetch the same BLOB column multiple times', function(done) { + var id = insertID++; + var specialStr = '88.4.10'; + var contentLength = 200; + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + async.series([ + function(cb) { + insertIntoBlobTable1(id, content, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, B AS B1, B AS B2 from nodb_blob1 WHERE ID = " + id, + { }, + { + fetchInfo : { + B1 : { type : oracledb.BUFFER }, + B2 : { type : oracledb.BUFFER } } + }, + function(err, result) { + should.not.exist(err); + var resultVal = result.rows[0][1]; + compareClientFetchResult(err, resultVal, specialStr, content, contentLength); + resultVal = result.rows[0][2]; + compareClientFetchResult(err, resultVal, specialStr, content, contentLength); + cb(); + } + ); + } + ], done); + }); // 88.4.10 + + it('88.4.11 works with update statement', function(done) { + var id = insertID++; + var specialStr_1 = '88.4.11_1'; + var contentLength_1 = 200; + var strBuf_1 = random.getRandomString(contentLength_1, specialStr_1); + var content_1 = node6plus ? Buffer.from(strBuf_1, "utf-8") : new Buffer(strBuf_1, "utf-8"); + var specialStr_2 = '88.4.11_2'; + var contentLength_2 = 208; + var strBuf_2 = random.getRandomString(contentLength_2, specialStr_2); + var content_2 = node6plus ? Buffer.from(strBuf_2, "utf-8") : new Buffer(strBuf_2, "utf-8"); + + async.series([ + function(cb) { + insertAndFetch(id, specialStr_1, content_1, contentLength_1, cb); + }, + function(cb) { + updateBlobTable1(id, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, B from nodb_blob1 WHERE ID = " + id, + { }, + { + outFormat : oracledb.ARRAY, + fetchInfo : { B : { type : oracledb.BUFFER } } + }, + function(err, result) { + should.not.exist(err); + var resultVal = result.rows[0][1]; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + cb(); + } + ); + } + ], done); + }); // 88.4.8 + + it('88.4.12 works with setting oracledb.maxRows < actual number of rows in the table', function(done) { + var id_1 = insertID++; + var specialStr_1 = '88.4.12_1'; + var contentLength_1 = 200; + var strBuf_1 = random.getRandomString(contentLength_1, specialStr_1); + var content_1 = node6plus ? Buffer.from(strBuf_1, "utf-8") : new Buffer(strBuf_1, "utf-8"); + var id_2 = insertID++; + var specialStr_2 = '88.4.12_2'; + var contentLength_2 = 100; + var strBuf_2 = random.getRandomString(contentLength_2, specialStr_2); + var content_2 = node6plus ? Buffer.from(strBuf_2, "utf-8") : new Buffer(strBuf_2, "utf-8"); + var maxRowsBak = oracledb.maxRows; + oracledb.maxRows = 1; + + async.series([ + function(cb) { + insertIntoBlobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoBlobTable1(id_2, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, B from nodb_blob1 WHERE id = " + id_1 + " or id = " +id_2, + { }, + { + outFormat : oracledb.ARRAY, + fetchInfo : { B : { type : oracledb.BUFFER } } + }, + function(err, result) { + should.not.exist(err); + result.rows.length.should.eql(1); + var resultVal = result.rows[0][1]; + compareClientFetchResult(err, resultVal, specialStr_1, content_1, contentLength_1); + oracledb.maxRows = maxRowsBak; + cb(); + } + ); + } + ], done); + }); // 88.4.12 + + it('88.4.13 works with setting oracledb.maxRows > actual number of rows in the table', function(done) { + var id_1 = insertID++; + var specialStr_1 = '88.4.13_1'; + var contentLength_1 = 200; + var strBuf_1 = random.getRandomString(contentLength_1, specialStr_1); + var content_1 = node6plus ? Buffer.from(strBuf_1, "utf-8") : new Buffer(strBuf_1, "utf-8"); + var id_2 = insertID++; + var specialStr_2 = '88.4.13_2'; + var contentLength_2 = 100; + var strBuf_2 = random.getRandomString(contentLength_2, specialStr_2); + var content_2 = node6plus ? Buffer.from(strBuf_2, "utf-8") : new Buffer(strBuf_2, "utf-8"); + var maxRowsBak = oracledb.maxRows; + oracledb.maxRows = 10; + + async.series([ + function(cb) { + insertIntoBlobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoBlobTable1(id_2, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, B from nodb_blob1 WHERE id = " + id_1 + " or id = " +id_2, + { }, + { + outFormat : oracledb.ARRAY, + fetchInfo : { B : { type : oracledb.BUFFER } } + }, + function(err, result) { + should.not.exist(err); + result.rows.length.should.eql(2); + var resultVal = result.rows[0][1]; + compareClientFetchResult(err, resultVal, specialStr_1, content_1, contentLength_1); + resultVal = result.rows[1][1]; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + oracledb.maxRows = maxRowsBak; + cb(); + } + ); + } + ], done); + }); // 88.4.13 + + }); // 88.4 + + describe('88.5 fetch BLOB columns by setting fetchInfo option, outFormat = oracledb.ARRAY and resultSet = true', function() { + + before('Create table and populate', function(done) { + connection.execute( + proc_create_table1, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // before + + after('drop table', function(done) { + connection.execute( + drop_table1, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // after + + insertID = 0; + var insertAndFetch = function(id, specialStr, insertContent, insertContentLength, callback) { + async.series([ + function(cb) { + insertIntoBlobTable1(id, insertContent, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, B from nodb_blob1 WHERE ID = :id", + { id : id }, + { + outFormat : oracledb.ARRAY, + fetchInfo : { B : { type : oracledb.BUFFER } }, + resultSet : true + }, + function(err, result) { + should.not.exist(err); + result.resultSet.getRow( + function(err, row) { + var resultVal; + resultVal = row[1]; + if(specialStr === null) { + should.not.exist(err); + should.equal(resultVal, null); + } else { + compareClientFetchResult(err, resultVal, specialStr, insertContent, insertContentLength, callback); + } + result.resultSet.close(function(err) { + should.not.exist(err); + cb(); + }); + } + ); + } + ); + } + ], callback); + }; + + it('88.5.1 works with NULL value', function(done) { + var id = insertID++; + var content = null; + + insertAndFetch(id, null, content, null, done); + }); // 88.5.1 + + it('88.5.2 works with empty Buffer', function(done) { + var id = insertID++; + var content = node6plus ? Buffer.from("", "utf-8") : new Buffer("", "utf-8"); + + insertAndFetch(id, null, content, null, done); + }); // 88.5.2 + + it('88.5.3 works with small value', function(done) { + var id = insertID++; + var specialStr = '88.5.3'; + var contentLength = 20; + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 88.5.3 + + it('88.5.4 works with (64K - 1) value', function(done) { + var id = insertID++; + var specialStr = '88.5.4'; + var contentLength = 65535; + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 88.5.4 + + it('88.5.5 works with (64K + 1) value', function(done) { + var id = insertID++; + var specialStr = '88.5.5'; + var contentLength = 65537; + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 88.5.5 + + it('88.5.6 works with (1MB + 1) value', function(done) { + var id = insertID++; + var specialStr = '88.5.6'; + var contentLength = 1048577; // 1MB + 1 + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 88.5.6 + + it('88.5.7 works with dbms_lob.substr()', function(done) { + var id = insertID++; + var specialStr = '88.5.7'; + var contentLength = 200; + var specialStrLength = specialStr.length; + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + async.series([ + function(cb) { + insertIntoBlobTable1(id, content, cb); + }, + function(cb) { + connection.execute( + "SELECT dbms_lob.substr(B, " + specialStrLength + ", 1) AS B1 from nodb_blob1 WHERE ID = :id", + { id : id }, + { + outFormat : oracledb.ARRAY, + fetchInfo : { B1 : { type : oracledb.BUFFER } }, + resultSet : true + }, + function(err, result) { + should.not.exist(err); + result.resultSet.getRow( + function(err, row) { + should.not.exist(err); + var resultVal = row[0]; + var buffer2Compare = node6plus ? Buffer.from(specialStr, "utf-8") : new Buffer(specialStr, "utf-8"); + compareClientFetchResult(err, resultVal, specialStr, buffer2Compare, specialStrLength); + result.resultSet.close(function(err) { + should.not.exist(err); + cb(); + }); + } + ); + } + ); + } + ], done); + }); // 88.5.7 + + it('88.5.8 works with EMPTY_BLOB()', function(done) { + var id = insertID++; + var content = "EMPTY_BLOB"; + + insertAndFetch(id, null, content, null, done); + }); // 88.5.8 + + it('88.5.9 fetch multiple BLOB rows as Buffer', function(done) { + var id_1 = insertID++; + var specialStr_1 = '88.5.9_1'; + var contentLength_1 = 200; + var strBuf_1 = random.getRandomString(contentLength_1, specialStr_1); + var content_1 = node6plus ? Buffer.from(strBuf_1, "utf-8") : new Buffer(strBuf_1, "utf-8"); + var id_2 = insertID++; + var specialStr_2 = '88.5.9_2'; + var contentLength_2 = 100; + var strBuf_2 = random.getRandomString(contentLength_2, specialStr_2); + var content_2 = node6plus ? Buffer.from(strBuf_2, "utf-8") : new Buffer(strBuf_2, "utf-8"); + + async.series([ + function(cb) { + insertIntoBlobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoBlobTable1(id_2, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, B from nodb_blob1 WHERE ID = " + id_1 + " or id = " + id_2, + { }, + { + outFormat : oracledb.ARRAY, + fetchInfo : { B : { type : oracledb.BUFFER } }, + resultSet : true + }, + function(err, result) { + should.not.exist(err); + var rowNumFetched = 2; + result.resultSet.getRows( + rowNumFetched, + function(err, row) { + should.not.exist(err); + should.strictEqual(row.length, 2); + var resultVal = row[0][1]; + compareClientFetchResult(err, resultVal, specialStr_1, content_1, contentLength_1); + resultVal = row[1][1]; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + result.resultSet.close(function(err) { + should.not.exist(err); + cb(); + }); + } + ); + } + ); + } + ], done); + }); // 88.5.9 + + it('88.5.10 fetch the same BLOB column multiple times', function(done) { + var id = insertID++; + var specialStr = '88.5.10'; + var contentLength = 200; + var strBuf = random.getRandomString(contentLength, specialStr); + var content = node6plus ? Buffer.from(strBuf, "utf-8") : new Buffer(strBuf, "utf-8"); + + async.series([ + function(cb) { + insertIntoBlobTable1(id, content, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, B AS B1, B AS B2 from nodb_blob1 WHERE ID = " + id, + { }, + { + outFormat : oracledb.ARRAY, + fetchInfo : { + B1 : { type : oracledb.BUFFER }, + B2 : { type : oracledb.BUFFER } }, + resultSet : true + }, + function(err, result) { + should.not.exist(err); + result.resultSet.getRow( + function(err, row) { + should.not.exist(err); + var resultVal = row[1]; + compareClientFetchResult(err, resultVal, specialStr, content, contentLength); + resultVal = row[2]; + compareClientFetchResult(err, resultVal, specialStr, content, contentLength); + result.resultSet.close(function(err) { + should.not.exist(err); + cb(); + }); + } + ); + } + ); + } + ], done); + }); // 88.5.10 + + it('88.5.11 works with update statement', function(done) { + var id = insertID++; + var specialStr_1 = '88.5.11_1'; + var contentLength_1 = 200; + var strBuf_1 = random.getRandomString(contentLength_1, specialStr_1); + var content_1 = node6plus ? Buffer.from(strBuf_1, "utf-8") : new Buffer(strBuf_1, "utf-8"); + var specialStr_2 = '88.5.11_2'; + var contentLength_2 = 208; + var strBuf_2 = random.getRandomString(contentLength_2, specialStr_2); + var content_2 = node6plus ? Buffer.from(strBuf_2, "utf-8") : new Buffer(strBuf_2, "utf-8"); + + async.series([ + function(cb) { + insertAndFetch(id, specialStr_1, content_1, contentLength_1, cb); + }, + function(cb) { + updateBlobTable1(id, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, B from nodb_blob1 WHERE ID = " + id, + { }, + { + outFormat : oracledb.ARRAY, + fetchInfo : { B : { type : oracledb.BUFFER } }, + resultSet : true + }, + function(err, result) { + should.not.exist(err); + result.resultSet.getRow( + function(err, row) { + should.not.exist(err); + var resultVal = row[1]; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + result.resultSet.close(function(err) { + should.not.exist(err); + cb(); + }); + } + ); + } + ); + } + ], done); + }); // 88.5.11 + + it('88.5.12 works with setting oracledb.maxRows < actual number of rows in the table', function(done) { + var id_1 = insertID++; + var specialStr_1 = '88.5.12_1'; + var contentLength_1 = 200; + var strBuf_1 = random.getRandomString(contentLength_1, specialStr_1); + var content_1 = node6plus ? Buffer.from(strBuf_1, "utf-8") : new Buffer(strBuf_1, "utf-8"); + var id_2 = insertID++; + var specialStr_2 = '88.5.12_2'; + var contentLength_2 = 100; + var strBuf_2 = random.getRandomString(contentLength_2, specialStr_2); + var content_2 = node6plus ? Buffer.from(strBuf_2, "utf-8") : new Buffer(strBuf_2, "utf-8"); + var maxRowsBak = oracledb.maxRows; + oracledb.maxRows = 1; + + async.series([ + function(cb) { + insertIntoBlobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoBlobTable1(id_2, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, B from nodb_blob1 WHERE id = " + id_1 + " or id = " +id_2, + { }, + { + outFormat : oracledb.ARRAY, + fetchInfo : { B : { type : oracledb.BUFFER } }, + resultSet : true + }, + function(err, result) { + should.not.exist(err); + var rowNumFetched = 2; + result.resultSet.getRows( + rowNumFetched, + function(err, row) { + should.not.exist(err); + should.strictEqual(row.length, 2); + var resultVal = row[0][1]; + compareClientFetchResult(err, resultVal, specialStr_1, content_1, contentLength_1); + resultVal = row[1][1]; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + oracledb.maxRows =maxRowsBak; + result.resultSet.close(function(err) { + should.not.exist(err); + cb(); + }); + } + ); + } + ); + } + ], done); + }); // 88.5.12 + + it('88.5.13 works with setting oracledb.maxRows > actual number of rows in the table', function(done) { + var id_1 = insertID++; + var specialStr_1 = '88.5.13_1'; + var contentLength_1 = 200; + var strBuf_1 = random.getRandomString(contentLength_1, specialStr_1); + var content_1 = node6plus ? Buffer.from(strBuf_1, "utf-8") : new Buffer(strBuf_1, "utf-8"); + var id_2 = insertID++; + var specialStr_2 = '88.5.13_2'; + var contentLength_2 = 100; + var strBuf_2 = random.getRandomString(contentLength_2, specialStr_2); + var content_2 = node6plus ? Buffer.from(strBuf_2, "utf-8") : new Buffer(strBuf_2, "utf-8"); + var maxRowsBak = oracledb.maxRows; + oracledb.maxRows = 10; + + async.series([ + function(cb) { + insertIntoBlobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoBlobTable1(id_2, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, B from nodb_blob1 WHERE id = " + id_1 + " or id = " +id_2, + { }, + { + outFormat : oracledb.ARRAY, + fetchInfo : { B : { type : oracledb.BUFFER } }, + resultSet : true + }, + function(err, result) { + should.not.exist(err); + var rowNumFetched = 2; + result.resultSet.getRows( + rowNumFetched, + function(err, row) { + should.not.exist(err); + should.strictEqual(row.length, 2); + var resultVal = row[0][1]; + compareClientFetchResult(err, resultVal, specialStr_1, content_1, contentLength_1); + resultVal = row[1][1]; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + oracledb.maxRows =maxRowsBak; + result.resultSet.close(function(err) { + should.not.exist(err); + cb(); + }); + } + ); + } + ); + } + ], done); + }); // 88.5.13 + + }); // 88.5 + +}); diff --git a/test/fetchBlobAsBuffer3.js b/test/fetchBlobAsBuffer3.js new file mode 100644 index 00000000..bae36d32 --- /dev/null +++ b/test/fetchBlobAsBuffer3.js @@ -0,0 +1,414 @@ +/* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with the Apache + * License, Version 2.0 (the "License.") + * + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + * The node-oracledb test suite uses 'mocha', 'should' and 'async'. + * See LICENSE.md for relevant licenses. + * + * NAME + * 89. fetchBlobAsBuffer3.js + * + * DESCRIPTION + * Testing Oracle data type support - BLOB. + * To fetch BLOB columns as buffer + * + * NUMBERING RULE + * Test numbers follow this numbering rule: + * 1 - 20 are reserved for basic functional tests + * 21 - 50 are reserved for data type supporting tests + * 51 onwards are for other tests + * + *****************************************************************************/ +'use strict'; + +var oracledb = require('oracledb'); +var async = require('async'); +var should = require('should'); +var dbConfig = require('./dbconfig.js'); +var random = require('./random.js'); +var assist = require('./dataTypeAssist.js'); + +describe('89. fetchBlobAsBuffer3.js', function() { + this.timeout(100000); + var connection = null; + var node6plus = false; // assume node runtime version is lower than 6 + var insertID = 1; // assume id for insert into db starts from 1 + + var proc_create_table2 = "BEGIN \n" + + " DECLARE \n" + + " e_table_missing EXCEPTION; \n" + + " PRAGMA EXCEPTION_INIT(e_table_missing, -00942); \n" + + " BEGIN \n" + + " EXECUTE IMMEDIATE('DROP TABLE nodb_blob2 PURGE'); \n" + + " EXCEPTION \n" + + " WHEN e_table_missing \n" + + " THEN NULL; \n" + + " END; \n" + + " EXECUTE IMMEDIATE (' \n" + + " CREATE TABLE nodb_blob2 ( \n" + + " ID NUMBER, \n" + + " B1 BLOB, \n" + + " B2 BLOB \n" + + " ) \n" + + " '); \n" + + "END; "; + var drop_table2 = "DROP TABLE nodb_blob2 PURGE"; + + before('get one connection', function(done) { + oracledb.stmtCacheSize = 0; + oracledb.getConnection(dbConfig, function(err, conn) { + should.not.exist(err); + connection = conn; + if(process.versions["node"].substring(0,1) >= "6") + node6plus = true; + + done(); + }); + + }); // before + + after('release connection', function(done) { + connection.release(function(err) { + should.not.exist(err); + done(); + }); + }); // after + + var insertIntoBlobTable2 = function(id, content1, content2, callback) { + connection.execute( + "INSERT INTO nodb_blob2 VALUES (:ID, :B1, :B2)", + [ id, content1, content2 ], + function(err, result){ + should.not.exist(err); + should.strictEqual(result.rowsAffected, 1); + callback(); + } + ); + }; + + // compare fetch result + var compareClientFetchResult = function(err, resultVal, specialStr, content, contentLength) { + should.not.exist(err); + compareBuffers(resultVal, specialStr, content, contentLength); + }; + + // compare two buffers + var compareBuffers = function(resultVal, specialStr, content, contentLength) { + should.equal(resultVal.length, contentLength); + var compareBuffer = assist.compare2Buffers(resultVal, content); + should.strictEqual(compareBuffer, true); + }; + + describe('89.1 fetch multiple BLOBs', function() { + + before('create Table and populate', function(done) { + connection.execute( + proc_create_table2, + function(err){ + should.not.exist(err); + done() ; + } + ); + }); // before + + after('drop table', function(done) { + connection.execute( + drop_table2, + function(err){ + should.not.exist(err); + done(); + } + ); + }); // after + + beforeEach('set oracledb.fetchAsBuffer', function(done) { + oracledb.fetchAsBuffer = [ oracledb.BLOB ]; + done(); + }); // beforeEach + + afterEach('clear the By type specification', function(done) { + oracledb.fetchAsBuffer = []; + done(); + }); // afterEach + + it('89.1.1 fetch multiple BLOB columns as Buffer', function(done) { + var id = insertID++; + var specialStr_1 = '89.1.1_1'; + var contentLength_1 = 26; + var strBuf_1 = random.getRandomString(contentLength_1, specialStr_1); + var content_1 = node6plus ? Buffer.from(strBuf_1, "utf-8") : new Buffer(strBuf_1, "utf-8"); + var specialStr_2 = '89.1.1_2'; + var contentLength_2 = 100; + var strBuf_2 = random.getRandomString(contentLength_2, specialStr_2); + var content_2 = node6plus ? Buffer.from(strBuf_2, "utf-8") : new Buffer(strBuf_2, "utf-8"); + + async.series([ + function(cb) { + insertIntoBlobTable2(id, content_1, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, B1, B2 from nodb_blob2", + function(err, result){ + should.not.exist(err); + var resultVal = result.rows[0][1]; + compareClientFetchResult(err, resultVal, specialStr_1, content_1, contentLength_1); + resultVal = result.rows[0][2]; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + cb(); + } + ); + } + ], done); + + }); // 89.1.1 + + it('89.1.2 fetch two BLOB columns, one as string, another streamed', function(done) { + var id = insertID++; + var specialStr_1 = '89.1.2_1'; + var contentLength_1 = 30; + var strBuf_1 = random.getRandomString(contentLength_1, specialStr_1); + var content_1 = node6plus ? Buffer.from(strBuf_1, "utf-8") : new Buffer(strBuf_1, "utf-8"); + var specialStr_2 = '89.1.2_2'; + var contentLength_2 = 50; + var strBuf_2 = random.getRandomString(contentLength_2, specialStr_2); + var content_2 = node6plus ? Buffer.from(strBuf_2, "utf-8") : new Buffer(strBuf_2, "utf-8"); + + async.series([ + function(cb) { + insertIntoBlobTable2(id, content_1, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, B1 from nodb_blob2 where ID = :id", + { id : id }, + function(err, result){ + should.not.exist(err); + var resultVal = result.rows[0][1]; + compareClientFetchResult(err, resultVal, specialStr_1, content_1, contentLength_1); + cb(); + } + ); + }, + function(cb) { + oracledb.fetchAsBuffer = []; + + connection.execute( + "SELECT B2 from nodb_blob2 where ID = :id", + { id : id }, + function(err, result){ + should.not.exist(err); + (result.rows.length).should.not.eql(0); + var lob = result.rows[0][0]; + should.exist(lob); + + // set the encoding so we get a 'string' not a 'buffer' + lob.setEncoding('utf8'); + var clobData = ''; + + lob.on('data', function(chunk) { + clobData += chunk; + }); + + lob.on('error', function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + lob.on('end', function() { + should.not.exist(err); + var specialStrLen_2 = specialStr_2.length; + var resultLen_2 = clobData.length; + should.equal(clobData.length, contentLength_2); + should.strictEqual(clobData.substring(0, specialStrLen_2), specialStr_2); + should.strictEqual(clobData.substring(resultLen_2 - specialStrLen_2, resultLen_2), specialStr_2); + + cb(); + }); + } + ); + } + ], done); + + }); // 89.1.2 + + }); // 89.1 + + describe('89.2 types support for fetchAsBuffer property', function() { + + afterEach ('clear the by-type specification', function ( done ) { + oracledb.fetchAsBuffer = []; + done (); + }); + + it('89.2.1 String not supported in fetchAsBuffer', function(done) { + should.throws( + function() { + oracledb.fetchAsBuffer = [ oracledb.STRING ]; + }, + /NJS-021: invalid type for conversion specified/ + ); + done(); + }); // 89.2.1 + + + it('89.2.2 CLOB not supported in fetchAsBuffer', function(done) { + should.throws( + function() { + oracledb.fetchAsBuffer = [ oracledb.CLOB ]; + }, + /NJS-021: invalid type for conversion specified/ + ); + done(); + }); // 89.2.2 + + + it('89.2.3 Number not supported in fetchAsBuffer', function(done) { + should.throws( + function() { + oracledb.fetchAsBuffer = [ oracledb.NUMBER ]; + }, + /NJS-021: invalid type for conversion specified/ + ); + done(); + }); // 89.2.3 + + + it('89.2.4 Date not supported in fetchAsBuffer', function(done) { + should.throws( + function() { + oracledb.fetchAsBuffer = [ oracledb.DATE ]; + }, + /NJS-021: invalid type for conversion specified/ + ); + done(); + }); // 89.2.4 + + + it('89.2.5 Cursor not supported in fetchAsBuffer', function(done) { + should.throws( + function() { + oracledb.fetchAsBuffer = [ oracledb.CURSOR ]; + }, + /NJS-021: invalid type for conversion specified/ + ); + done(); + }); // 89.2.5 + + + it('89.2.6 Buffer not supported in fetchAsBuffer', function(done) { + should.throws( + function() { + oracledb.fetchAsBuffer = [ oracledb.BUFFER ]; + }, + /NJS-021: invalid type for conversion specified/ + ); + done(); + }); // 89.2.6 + + + it('89.2.7 BLOB supported in fetchAsBuffer', function(done) { + should.doesNotThrow( + function() { + oracledb.fetchAsBuffer = [ oracledb.BLOB ]; + } + ); + should.strictEqual(oracledb.fetchAsBuffer.length, 1); + should.strictEqual(oracledb.fetchAsBuffer[0], oracledb.BLOB); + done(); + }); // 89.2.7 + + + it.skip('89.2.8 negative null value for fetchAsBuffer', function(done) { + should.throws( + function() { + oracledb.fetchAsBuffer = null; + }, + /NJS-004: invalid value for property [\w]/ + ); + done(); + }); // 89.2.8 + + + it.skip('89.2.9 negative undefined value for fetchAsBuffer', function(done) { + should.throws( + function() { + oracledb.fetchAsBuffer = undefined; + }, + /NJS-004: invalid value for property [\w]/ + ); + done(); + }); // 89.2.9 + + + it.skip('89.2.10 negative numeric value for fetchAsBuffer', function(done) { + should.throws( + function() { + oracledb.fetchAsBuffer = 89210; + }, + /NJS-004: invalid value for property [\w]/ + ); + done(); + }); // 89.2.10 + + + it.skip('89.2.11 negative emtpy string value for fetchAsBuffer', function(done) { + should.throws( + function() { + oracledb.fetchAsBuffer = ' '; + }, + /NJS-004: invalid value for property [\w]/ + ); + done(); + }); // 89.2.11 + + + it.skip('89.2.12 negative arbitary string value for fetchAsBuffer', function(done) { + should.throws( + function() { + oracledb.fetchAsBuffer = "89.2.12"; + }, + /NJS-004: invalid value for property [\w]/ + ); + done(); + }); // 89.2.12 + + + it.skip('89.2.13 negative date value for fetchAsBuffer', function(done) { + should.throws( + function() { + var dt = new Date (); + oracledb.fetchAsBuffer = dt; + }, + /NJS-004: invalid value for property [\w]/ + ); + done(); + }); // 89.2.13 + + + it.skip('89.2.14 negative arbitary buffer value for fetchAsBuffer', function(done) { + should.throws( + function() { + var buf = assist.createBuffer ( 10 ) ; + oracledb.fetchAsBuffer = buf; + }, + /NJS-004: invalid value for property [\w]/ + ); + done(); + }); // 89.2.14 + + }); // 89.2 + +}); diff --git a/test/fetchClobAsString1.js b/test/fetchClobAsString1.js new file mode 100644 index 00000000..bcf9ade8 --- /dev/null +++ b/test/fetchClobAsString1.js @@ -0,0 +1,2804 @@ +/* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with the Apache + * License, Version 2.0 (the "License.") + * + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + * The node-oracledb test suite uses 'mocha', 'should' and 'async'. + * See LICENSE.md for relevant licenses. + * + * NAME + * 84. fetchClobAsString.js + * + * DESCRIPTION + * Testing Oracle data type support - CLOB. + * To fetch CLOB columns as strings by setting oracledb.fetchAsString + * This could be very useful for smaller CLOB size as it can be fetched as string and processed in memory itself. + * + * NUMBERING RULE + * Test numbers follow this numbering rule: + * 1 - 20 are reserved for basic functional tests + * 21 - 50 are reserved for data type supporting tests + * 51 onwards are for other tests + * + *****************************************************************************/ +'use strict'; + +var oracledb = require('oracledb'); +var async = require('async'); +var should = require('should'); +var file = require('./file.js'); +var dbConfig = require('./dbconfig.js'); +var random = require('./random.js'); + +describe('84. fetchClobAsString1.js', function() { + this.timeout(100000); + var connection = null; + var insertID = 1; // assume id for insert into db starts from 1 + var inFileName = './test/clobTmpFile.txt'; + var proc_create_table1 = "BEGIN \n" + + " DECLARE \n" + + " e_table_missing EXCEPTION; \n" + + " PRAGMA EXCEPTION_INIT(e_table_missing, -00942); \n" + + " BEGIN \n" + + " EXECUTE IMMEDIATE('DROP TABLE nodb_clob1 PURGE'); \n" + + " EXCEPTION \n" + + " WHEN e_table_missing \n" + + " THEN NULL; \n" + + " END; \n" + + " EXECUTE IMMEDIATE (' \n" + + " CREATE TABLE nodb_clob1 ( \n" + + " ID NUMBER, \n" + + " C CLOB \n" + + " ) \n" + + " '); \n" + + "END; "; + var drop_table1 = "DROP TABLE nodb_clob1 PURGE"; + + before('get one connection', function(done) { + async.series([ + function(cb) { + oracledb.stmtCacheSize = 0; + oracledb.getConnection(dbConfig, function(err, conn) { + should.not.exist(err); + connection = conn; + cb(); + }); + }, + function(cb) { + file.create(inFileName); + cb(); + } + ], done); + + }); // before + + after('release connection', function(done) { + async.series([ + function(cb) { + connection.release(function(err) { + should.not.exist(err); + cb(); + }); + }, + function(cb) { + file.delete(inFileName); + cb(); + } + ], done); + }); // after + + var insertIntoClobTable1 = function(id, content, callback) { + if(content == "EMPTY_CLOB") { + connection.execute( + "INSERT INTO nodb_clob1 VALUES (:ID, EMPTY_CLOB())", + [ id ], + function(err, result) { + should.not.exist(err); + should.strictEqual(result.rowsAffected, 1); + callback(); + } + ); + } else { + connection.execute( + "INSERT INTO nodb_clob1 VALUES (:ID, :C)", + { + ID : { val : id }, + C : { val : content, dir : oracledb.BIND_IN, type : oracledb.STRING } + }, + function(err, result) { + should.not.exist(err); + should.strictEqual(result.rowsAffected, 1); + callback(); + } + ); + } + }; + + var updateClobTable1 = function(id, content, callback) { + connection.execute( + "UPDATE nodb_clob1 set C = :C where ID = :ID", + { ID: id, C: content }, + function(err, result){ + should.not.exist(err); + should.strictEqual(result.rowsAffected, 1); + callback(); + } + ); + }; + + // compare fetch result + var compareClientFetchResult = function(err, resultVal, specialStr, content, contentLength) { + should.not.exist(err); + compareStrings(resultVal, specialStr, content, contentLength); + }; + + // compare two string + var compareStrings = function(resultVal, specialStr, content, contentLength) { + var specialStrLen = specialStr.length; + var resultLen = resultVal.length; + should.equal(resultLen, contentLength); + should.strictEqual(resultVal.substring(0, specialStrLen), specialStr); + should.strictEqual(resultVal.substring(resultLen - specialStrLen, resultLen), specialStr); + }; + + describe('84.1 fetch CLOB columns by setting oracledb.fetchAsString', function() { + + before('create Table and populate', function(done) { + connection.execute( + proc_create_table1, + function(err){ + should.not.exist(err); + done() ; + } + ); + }); // before + + after('drop table', function(done) { + oracledb.fetchAsString = []; + connection.execute( + drop_table1, + function(err){ + should.not.exist(err); + done(); + } + ); + }); // after + + beforeEach('set oracledb.fetchAsString', function(done) { + oracledb.fetchAsString = [ oracledb.CLOB ]; + done(); + }); // beforeEach + + afterEach('clear the By type specification', function(done) { + oracledb.fetchAsString = []; + done(); + }); // afterEach + + var insertAndFetch = function(id, specialStr, insertContent, insertContentLength, callback) { + async.series([ + function(cb) { + insertIntoClobTable1(id, insertContent, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, C from nodb_clob1 WHERE ID = :id", + { id : id }, + function(err, result){ + if(specialStr === null) { + should.not.exist(err); + should.equal(result.rows[0][1], null); + } else { + var resultVal = result.rows[0][1]; + compareClientFetchResult(err, resultVal, specialStr, insertContent, insertContentLength); + } + cb(); + } + ); + } + ], callback); + }; + + it('84.1.1 works with NULL value', function(done) { + var id = insertID++; + var content = null; + + insertAndFetch(id, null, content, null, done); + }); // 84.1.1 + + it('84.1.2 works with empty string', function(done) { + var id = insertID++; + var content = ""; + + insertAndFetch(id, null, content, null, done); + }); // 84.1.2 + + it('84.1.3 works with small CLOB data', function(done) { + var id = insertID++; + var specialStr = '84.1.3'; + var contentLength = 26; + var content = random.getRandomString(contentLength, specialStr); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 84.1.3 + + it('84.1.4 works with (64K - 1) data', function(done) { + var id = insertID++; + var specialStr = '84.1.4'; + var contentLength = 65535; + var content = random.getRandomString(contentLength, specialStr); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 84.1.4 + + it('84.1.5 works with (64K + 1) data', function(done) { + var id = insertID++; + var specialStr = '84.1.5'; + var contentLength = 65537; + var content = random.getRandomString(contentLength, specialStr); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 84.1.5 + + it('84.1.6 works with (1MB + 1) data', function(done) { + var id = insertID++; + var specialStr = '84.1.6'; + var contentLength = 1048577; // 1MB + 1 + var content = random.getRandomString(contentLength, specialStr); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 84.1.6 + + it('84.1.7 fetch with substr()', function(done) { + var id = insertID++; + var specialStr = '84.1.7'; + var specialStrLen = specialStr.length; + var contentLength = 100; + var content = random.getRandomString(contentLength, specialStr); + + async.series([ + function(cb) { + insertIntoClobTable1(id, content, cb); + }, + function(cb) { + connection.execute( + "SELECT substr(C, 1, " + specialStrLen + ") from nodb_clob1 WHERE ID = :id", + { id : id }, + function(err, result){ + should.not.exist(err); + var resultVal = result.rows[0][0]; + compareClientFetchResult(err, resultVal, specialStr, specialStr, specialStrLen); + cb(); + } + ); + } + ], done); + }); // 84.1.7 + + it('84.1.8 works with EMPTY_CLOB()', function(done) { + var id = insertID++; + var content = "EMPTY_CLOB"; + + insertAndFetch(id, null, content, null, done); + }); // 84.1.8 + + it('84.1.9 fetch multiple CLOB columns as String', function(done) { + var id_1 = insertID++; + var specialStr_1 = '84.1.9_1'; + var contentLength_1 = 26; + var content_1 = random.getRandomString(contentLength_1, specialStr_1); + var id_2 = insertID++; + var specialStr_2 = '84.1.9_2'; + var contentLength_2 = 30; + var content_2 = random.getRandomString(contentLength_2, specialStr_2); + + async.series([ + function(cb) { + insertIntoClobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoClobTable1(id_2, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, C from nodb_clob1 where id = " + id_1 + " or id = " +id_2, + function(err, result){ + should.not.exist(err); + var resultVal = result.rows[0][1]; + compareClientFetchResult(err, resultVal, specialStr_1, content_1, contentLength_1); + resultVal = result.rows[1][1]; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + cb(); + } + ); + } + ], done); + }); // 84.1.9 + + it('84.1.10 fetch the same CLOB column multiple times', function(done) { + var id_1 = insertID++; + var specialStr_1 = '84.1.10_1'; + var contentLength_1 = 20; + var content_1 = random.getRandomString(contentLength_1, specialStr_1); + var id_2 = insertID++; + var specialStr_2 = '84.1.10_2'; + var contentLength_2 = 36; + var content_2 = random.getRandomString(contentLength_2, specialStr_2); + + async.series([ + function(cb) { + insertIntoClobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoClobTable1(id_2, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, C AS C1, C AS C2 from nodb_clob1 where id = " + id_1 + " or id = " +id_2, + function(err, result){ + should.not.exist(err); + var resultVal = result.rows[0][1]; + compareClientFetchResult(err, resultVal, specialStr_1, content_1, contentLength_1); + resultVal = result.rows[0][2]; + compareClientFetchResult(err, resultVal, specialStr_1, content_1, contentLength_1); + + resultVal = result.rows[1][1]; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + resultVal = result.rows[1][2]; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + cb(); + } + ); + } + ], done); + }); // 84.1.10 + + it('84.1.11 works with update statement', function(done) { + var id = insertID++; + var specialStr_1 = '84.1.11_1'; + var contentLength_1 = 26; + var content_1 = random.getRandomString(contentLength_1, specialStr_1); + var specialStr_2 = '84.1.11_2'; + var contentLength_2 = 30; + var content_2 = random.getRandomString(contentLength_2, specialStr_2); + + async.series([ + function(cb) { + insertAndFetch(id, specialStr_1, content_1, contentLength_1, cb); + }, + function(cb) { + updateClobTable1(id, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, C from nodb_clob1 where id = " + id, + function(err, result){ + should.not.exist(err); + var resultVal = result.rows[0][1]; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + cb(); + } + ); + } + ], done); + }); // 84.1.11 + + it('84.1.12 works with REF CURSOR', function(done) { + var id = insertID++; + var specialStr = '84.1.12'; + var contentLength = 26; + var content = random.getRandomString(contentLength, specialStr); + + async.series([ + function(cb) { + insertIntoClobTable1(id, content, cb); + }, + function(cb) { + var ref_proc = "CREATE OR REPLACE PROCEDURE nodb_ref(clob_cursor OUT SYS_REFCURSOR)\n" + + "AS \n" + + "BEGIN \n" + + " OPEN clob_cursor FOR \n" + + " SELECT C from nodb_clob1 WHERE ID = " + id + "; \n" + + "END;"; + connection.execute( + ref_proc, + function(err){ + should.not.exist(err); + cb(); + } + ); + }, + function(cb) { + var sql = "BEGIN nodb_ref(:c); END;"; + var bindVar = { + c: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT } + }; + connection.execute( + sql, + bindVar, + function(err, result) { + result.outBinds.c.getRows(3, function(err, rows) { + var resultVal = rows[0][0]; + should.strictEqual(typeof resultVal, 'string'); + compareClientFetchResult(err, resultVal, specialStr, content, contentLength); + cb(); + }); + } + ); + }, + function(cb) { + var ref_proc_drop = "DROP PROCEDURE nodb_ref"; + connection.execute( + ref_proc_drop, + function(err){ + should.not.exist(err); + cb(); + } + ); + } + ], done); + }); // 84.1.12 + + it('84.1.13 fetch CLOB with stream', function(done) { + var id = insertID++; + var specialStr = '84.1.13'; + var contentLength = 40; + var content = random.getRandomString(contentLength, specialStr); + + async.series([ + function(cb) { + insertIntoClobTable1(id, content, cb); + }, + function(cb) { + oracledb.fetchAsString = []; + + connection.execute( + "SELECT ID, C from nodb_clob1 WHERE ID = :id", + { id : id }, + function(err, result){ + should.not.exist(err); + (result.rows.length).should.not.eql(0); + var lob = result.rows[0][1]; + should.exist(lob); + + // set the encoding so we get a 'string' not a 'String' + lob.setEncoding('utf8'); + var clobData = ''; + + lob.on('data', function(chunk) { + clobData += chunk; + }); + + lob.on('error', function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + lob.on('end', function() { + should.not.exist(err); + compareClientFetchResult(err, clobData, specialStr, content, contentLength); + cb(); + }); + } + ); + } + ], done); + }); // 84.1.13 + + it('84.1.14 works with setting oracledb.maxRows < actual number of rows in the table', function(done) { + var id_1 = insertID++; + var specialStr_1 = '84.1.14_1'; + var contentLength_1 = 26; + var content_1 = random.getRandomString(contentLength_1, specialStr_1); + var id_2 = insertID++; + var specialStr_2 = '84.1.14_2'; + var contentLength_2 = 30; + var content_2 = random.getRandomString(contentLength_2, specialStr_2); + var maxRowsBak = oracledb.maxRows; + // oracledb.maxRows: The maximum number of rows that are fetched by the execute() call of the Connection object when not using a ResultSet. + // Rows beyond this limit are not fetched from the database. + oracledb.maxRows = 1; + + async.series([ + function(cb) { + insertIntoClobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoClobTable1(id_2, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, C from nodb_clob1 where id = " + id_1 + " or id = " +id_2, + function(err, result){ + should.not.exist(err); + result.rows.length.should.eql(1); + var resultVal = result.rows[0][1]; + compareClientFetchResult(err, resultVal, specialStr_1, content_1, contentLength_1); + oracledb.maxRows = maxRowsBak; + cb(); + } + ); + } + ], done); + }); // 84.1.14 + + it('84.1.15 works with setting oracledb.maxRows > actual number of rows in the table', function(done) { + var id_1 = insertID++; + var specialStr_1 = '84.1.15_1'; + var contentLength_1 = 26; + var content_1 = random.getRandomString(contentLength_1, specialStr_1); + var id_2 = insertID++; + var specialStr_2 = '84.1.15_2'; + var contentLength_2 = 30; + var content_2 = random.getRandomString(contentLength_2, specialStr_2); + var maxRowsBak = oracledb.maxRows; + oracledb.maxRows = 20; + + async.series([ + function(cb) { + insertIntoClobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoClobTable1(id_2, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, C from nodb_clob1 where id = " + id_1 + " or id = " +id_2, + function(err, result){ + should.not.exist(err); + var resultVal = result.rows[0][1]; + compareClientFetchResult(err, resultVal, specialStr_1, content_1, contentLength_1); + resultVal = result.rows[1][1]; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + oracledb.maxRows = maxRowsBak; + cb(); + } + ); + } + ], done); + }); // 84.1.15 + + it('84.1.16 override oracledb.fetchAsString with fetchInfo set to oracledb.DEFAULT', function(done) { + var id = insertID++; + var specialStr = '84.1.16'; + var contentLength = 20; + var content = random.getRandomString(contentLength, specialStr); + + async.series([ + function(cb) { + insertIntoClobTable1(id, content, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, C from nodb_clob1 WHERE ID = :id", + { id : id }, + { + fetchInfo : { C : { type : oracledb.DEFAULT } } + }, + function(err, result) { + should.not.exist(err); + (result.rows.length).should.not.eql(0); + var lob = result.rows[0][1]; + should.exist(lob); + + // set the encoding so we get a 'string' not a 'String' + lob.setEncoding('utf8'); + var clobData = ''; + + lob.on('data', function(chunk) { + clobData += chunk; + }); + + lob.on('error', function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + lob.on('end', function() { + should.not.exist(err); + compareClientFetchResult(err, clobData, specialStr, content, contentLength); + cb(); + }); + } + ); + } + ], done); + }); // 84.1.16 + + it('84.1.17 works with connection.queryStream()', function(done) { + var id = insertID++; + var specialStr = '84.1.17'; + var contentLength = 200; + var content = random.getRandomString(contentLength, specialStr); + + async.series([ + function(cb) { + insertIntoClobTable1(id, content, cb); + }, + function(cb) { + var sql = "SELECT ID, C from nodb_clob1 WHERE ID = " + id; + var stream = connection.queryStream(sql); + stream.on('error', function (error) { + should.fail(error, null, 'Error event should not be triggered'); + }); + + var counter = 0; + stream.on('data', function(data) { + should.exist(data); + var result = data[1]; + should.strictEqual(typeof result, "string"); + compareStrings(result, specialStr, content, contentLength); + counter++; + }); + + stream.on('end', function () { + should.equal(counter, 1); + setTimeout(cb, 500); + }); + } + ], done); + }); // 84.1.17 + + it('84.1.18 works with connection.queryStream() and oracledb.maxRows > actual number of rows in the table', function(done) { + var id_1 = insertID++; + var specialStr_1 = '84.1.18_1'; + var contentLength_1 = 26; + var content_1 = random.getRandomString(contentLength_1, specialStr_1); + var id_2 = insertID++; + var specialStr_2 = '84.1.18_2'; + var contentLength_2 = 30; + var content_2 = random.getRandomString(contentLength_2, specialStr_2); + var maxRowsBak = oracledb.maxRows; + oracledb.maxRows = 20; + + async.series([ + function(cb) { + insertIntoClobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoClobTable1(id_2, content_2, cb); + }, + function(cb) { + var sql = "SELECT ID, C from nodb_clob1 WHERE ID = " + id_1 + " or id = " +id_2; + var stream = connection.queryStream(sql); + stream.on('error', function (error) { + should.fail(error, null, 'Error event should not be triggered'); + }); + + var counter = 0; + stream.on('data', function(data) { + should.exist(data); + var result = data[1]; + should.strictEqual(typeof result, "string"); + counter++; + if(counter == 1) { + compareStrings(result, specialStr_1, content_1, contentLength_1); + } else { + compareStrings(result, specialStr_2, content_2, contentLength_2); + } + }); + + stream.on('end', function () { + should.equal(counter, 2); + oracledb.maxRows = maxRowsBak; + setTimeout(cb, 500); + }); + } + ], done); + }); // 84.1.18 + + it('84.1.19 works with connection.queryStream() and oracledb.maxRows = actual number of rows in the table', function(done) { + var id_1 = insertID++; + var specialStr_1 = '84.1.19_1'; + var contentLength_1 = 26; + var content_1 = random.getRandomString(contentLength_1, specialStr_1); + var id_2 = insertID++; + var specialStr_2 = '84.1.19_2'; + var contentLength_2 = 30; + var content_2 = random.getRandomString(contentLength_2, specialStr_2); + var maxRowsBak = oracledb.maxRows; + oracledb.maxRows = 2; + + async.series([ + function(cb) { + insertIntoClobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoClobTable1(id_2, content_2, cb); + }, + function(cb) { + var sql = "SELECT ID, C from nodb_clob1 WHERE ID = " + id_1 + " or id = " +id_2; + var stream = connection.queryStream(sql); + stream.on('error', function (error) { + should.fail(error, null, 'Error event should not be triggered'); + }); + + var counter = 0; + stream.on('data', function(data) { + should.exist(data); + var result = data[1]; + should.strictEqual(typeof result, "string"); + counter++; + if(counter == 1) { + compareStrings(result, specialStr_1, content_1, contentLength_1); + } else { + compareStrings(result, specialStr_2, content_2, contentLength_2); + } + }); + + stream.on('end', function () { + should.equal(counter, 2); + oracledb.maxRows = maxRowsBak; + setTimeout(cb, 500); + }); + } + ], done); + }); // 84.1.19 + + it('84.1.20 works with connection.queryStream() and oracledb.maxRows < actual number of rows in the table', function(done) { + var id_1 = insertID++; + var specialStr_1 = '84.1.20_1'; + var contentLength_1 = 26; + var content_1 = random.getRandomString(contentLength_1, specialStr_1); + var id_2 = insertID++; + var specialStr_2 = '84.1.20_2'; + var contentLength_2 = 30; + var content_2 = random.getRandomString(contentLength_2, specialStr_2); + var maxRowsBak = oracledb.maxRows; + oracledb.maxRows = 1; + + async.series([ + function(cb) { + insertIntoClobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoClobTable1(id_2, content_2, cb); + }, + function(cb) { + var sql = "SELECT ID, C from nodb_clob1 WHERE ID = " + id_1 + " or id = " +id_2; + var stream = connection.queryStream(sql); + stream.on('error', function (error) { + should.fail(error, null, 'Error event should not be triggered'); + }); + + var counter = 0; + stream.on('data', function(data) { + should.exist(data); + var result = data[1]; + should.strictEqual(typeof result, "string"); + counter++; + if(counter == 1) { + compareStrings(result, specialStr_1, content_1, contentLength_1); + } else { + compareStrings(result, specialStr_2, content_2, contentLength_2); + } + }); + + stream.on('end', function () { + should.equal(counter, 2); + oracledb.maxRows = maxRowsBak; + setTimeout(cb, 500); + }); + } + ], done); + }); // 84.1.20 + + }); // 84.1 + + describe('84.2 fetch CLOB columns by setting oracledb.fetchAsString and outFormat = oracledb.OBJECT', function() { + + before('Create table and populate', function(done) { + connection.execute( + proc_create_table1, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // before + + after('drop table', function(done) { + connection.execute( + drop_table1, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // after + + beforeEach('set oracledb.fetchAsString', function(done) { + oracledb.fetchAsString = [ oracledb.CLOB ]; + done(); + }); // beforeEach + + afterEach('clear the by-type specification', function(done) { + oracledb.fetchAsString = []; + done(); + }); // afterEach + + var insertAndFetch = function(id, specialStr, insertContent, insertContentLength, callback) { + async.series([ + function(cb) { + insertIntoClobTable1(id, insertContent, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, C from nodb_clob1 WHERE ID = :id", + { id : id }, + { outFormat : oracledb.OBJECT }, + function(err, result) { + var resultVal = result.rows[0].C; + if(specialStr === null) { + should.not.exist(err); + should.equal(resultVal, null); + } else { + compareClientFetchResult(err, resultVal, specialStr, insertContent, insertContentLength); + } + cb(); + } + ); + } + ], callback); + }; + + it('84.2.1 works with NULL value', function(done) { + var id = insertID++; + var content = null; + + insertAndFetch(id, null, content, null, done); + }); // 84.2.1 + + it('84.2.2 works with empty String', function(done) { + var id = insertID++; + var content = ""; + + insertAndFetch(id, null, content, null, done); + }); // 84.2.2 + + it('84.2.3 works with small value', function(done) { + var id = insertID++; + var specialStr = '84.2.3'; + var contentLength = 20; + var content = random.getRandomString(contentLength, specialStr); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 84.2.3 + + it('84.2.4 works with (64K - 1) value', function(done) { + var id = insertID++; + var specialStr = '84.2.4'; + var contentLength = 65535; + var content = random.getRandomString(contentLength, specialStr); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 84.2.4 + + it('84.2.5 works with (64K + 1) value', function(done) { + var id = insertID++; + var specialStr = '84.2.5'; + var contentLength = 65537; + var content = random.getRandomString(contentLength, specialStr); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 84.2.5 + + it('84.2.6 works with (1MB + 1) data', function(done) { + var id = insertID++; + var specialStr = '84.2.6'; + var contentLength = 1048577; // 1MB + 1 + var content = random.getRandomString(contentLength, specialStr); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 84.2.6 + + it('84.2.7 works with dbms_lob.substr()', function(done) { + var id = insertID++; + var specialStr = '84.2.7'; + var contentLength = 200; + var specialStrLength = specialStr.length; + var content = random.getRandomString(contentLength, specialStr); + + async.series([ + function(cb) { + insertIntoClobTable1(id, content, cb); + }, + function(cb) { + connection.execute( + "SELECT dbms_lob.substr(C, " + specialStrLength + ", 1) AS C1 from nodb_clob1 WHERE ID = :id", + { id : id }, + { outFormat : oracledb.OBJECT }, + function(err, result) { + should.not.exist(err); + var resultVal = result.rows[0].C1; + compareClientFetchResult(err, resultVal, specialStr, specialStr, specialStrLength); + cb(); + } + ); + } + ], done); + }); // 84.2.7 + + it('84.2.8 works with EMPTY_CLOB()', function(done) { + var id = insertID++; + var content = "EMPTY_CLOB"; + + insertAndFetch(id, null, content, null, done); + }); // 84.2.8 + + it('84.2.9 fetch multiple CLOB rows as String', function(done) { + var id_1 = insertID++; + var specialStr_1 = '84.2.9_1'; + var contentLength_1 = 200; + var content_1 = random.getRandomString(contentLength_1, specialStr_1); + var id_2 = insertID++; + var specialStr_2 = '84.2.9_2'; + var contentLength_2 = 100; + var content_2 = random.getRandomString(contentLength_2, specialStr_2); + + async.series([ + function(cb) { + insertIntoClobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoClobTable1(id_2, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, C from nodb_clob1 WHERE ID = " + id_1 + " or id = " + id_2, + { }, + { outFormat : oracledb.OBJECT }, + function(err, result) { + should.not.exist(err); + var resultVal = result.rows[0].C; + compareClientFetchResult(err, resultVal, specialStr_1, content_1, contentLength_1); + resultVal = result.rows[1].C; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + cb(); + } + ); + } + ], done); + }); // 84.2.9 + + it('84.2.10 fetch the same CLOB column multiple times', function(done) { + var id = insertID++; + var specialStr = '84.2.10'; + var contentLength = 200; + var content = random.getRandomString(contentLength, specialStr); + + async.series([ + function(cb) { + insertIntoClobTable1(id, content, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, C AS C1, C AS C2 from nodb_clob1 WHERE ID = " + id, + { }, + { outFormat : oracledb.OBJECT }, + function(err, result) { + should.not.exist(err); + var resultVal = result.rows[0].C1; + compareClientFetchResult(err, resultVal, specialStr, content, contentLength); + resultVal = result.rows[0].C2; + compareClientFetchResult(err, resultVal, specialStr, content, contentLength); + cb(); + } + ); + } + ], done); + }); // 84.2.10 + + it('84.2.11 works with update statement', function(done) { + var id = insertID++; + var specialStr_1 = '84.2.11_1'; + var contentLength_1 = 201; + var content_1 = random.getRandomString(contentLength_1, specialStr_1); + var specialStr_2 = '84.2.11_2'; + var contentLength_2 = 208; + var content_2 = random.getRandomString(contentLength_2, specialStr_2); + + async.series([ + function(cb) { + insertAndFetch(id, specialStr_1, content_1, contentLength_1, cb); + }, + function(cb) { + updateClobTable1(id, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, C from nodb_clob1 WHERE ID = " + id, + { }, + { outFormat : oracledb.OBJECT }, + function(err, result) { + should.not.exist(err); + var resultVal = result.rows[0].C; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + cb(); + } + ); + } + ], done); + }); // 84.2.11 + + it('84.2.12 works with REF CURSOR', function(done) { + var id = insertID++; + var specialStr = '84.2.12'; + var contentLength = 100; + var content = random.getRandomString(contentLength, specialStr); + + async.series([ + function(cb) { + insertIntoClobTable1(id, content, cb); + }, + function(cb) { + var ref_proc = "CREATE OR REPLACE PROCEDURE nodb_ref(clob_cursor OUT SYS_REFCURSOR)\n" + + "AS \n" + + "BEGIN \n" + + " OPEN clob_cursor FOR \n" + + " SELECT C from nodb_clob1 WHERE ID = " + id + "; \n" + + "END;"; + connection.execute( + ref_proc, + function(err){ + should.not.exist(err); + cb(); + } + ); + }, + function(cb) { + var sql = "BEGIN nodb_ref(:c); END;"; + var bindVar = { + c: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT } + }; + connection.execute( + sql, + bindVar, + function(err, result) { + result.outBinds.c.getRows(3, function(err, rows) { + var resultVal = rows[0][0]; + should.strictEqual(typeof resultVal, 'string'); + compareClientFetchResult(err, resultVal, specialStr, content, contentLength); + cb(); + }); + } + ); + }, + function(cb) { + var ref_proc_drop = "DROP PROCEDURE nodb_ref"; + connection.execute( + ref_proc_drop, + function(err){ + should.not.exist(err); + cb(); + } + ); + } + ], done); + }); // 84.2.12 + + it('84.2.13 fetch CLOB with stream', function(done) { + var id = insertID++; + var specialStr = '84.2.13'; + var contentLength = 200; + var content = random.getRandomString(contentLength, specialStr); + + async.series([ + function(cb) { + insertIntoClobTable1(id, content, cb); + }, + function(cb) { + oracledb.fetchAsString = []; + connection.execute( + "SELECT C from nodb_clob1 WHERE ID = " + id, + function(err, result) { + should.not.exist(err); + (result.rows.length).should.not.eql(0); + var lob = result.rows[0][0]; + should.exist(lob); + + // set the encoding so we get a 'string' not a 'buffer' + lob.setEncoding('utf8'); + var clobData = ''; + + lob.on('data', function(chunk) { + clobData += chunk; + }); + + lob.on('error', function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + lob.on('end', function() { + should.not.exist(err); + compareClientFetchResult(err, clobData, specialStr, content, contentLength); + cb(); + }); + } + ); + } + ], done); + }); // 84.2.13 + + it('84.2.14 works with setting oracledb.maxRows < actual number of rows in the table', function(done) { + var id_1 = insertID++; + var specialStr_1 = '84.2.14_1'; + var contentLength_1 = 200; + var content_1 = random.getRandomString(contentLength_1, specialStr_1); + var id_2 = insertID++; + var specialStr_2 = '84.2.14_2'; + var contentLength_2 = 100; + var content_2 = random.getRandomString(contentLength_2, specialStr_2); + var maxRowsBak = oracledb.maxRows; + // oracledb.maxRows: The maximum number of rows that are fetched by the execute() call of the Connection object when not using a ResultSet. + // Rows beyond this limit are not fetched from the database. + oracledb.maxRows = 1; + + async.series([ + function(cb) { + insertIntoClobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoClobTable1(id_2, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, C from nodb_clob1 WHERE id = " + id_1 + " or id = " +id_2, + { }, + { outFormat : oracledb.OBJECT }, + function(err, result) { + should.not.exist(err); + result.rows.length.should.eql(1); + var resultVal = result.rows[0].C; + compareClientFetchResult(err, resultVal, specialStr_1, content_1, contentLength_1); + oracledb.maxRows = maxRowsBak; + cb(); + } + ); + } + ], done); + }); // 84.2.14 + + it('84.2.15 works with setting oracledb.maxRows > actual number of rows in the table', function(done) { + var id_1 = insertID++; + var specialStr_1 = '84.2.15_1'; + var contentLength_1 = 200; + var content_1 = random.getRandomString(contentLength_1, specialStr_1); + var id_2 = insertID++; + var specialStr_2 = '84.2.15_2'; + var contentLength_2 = 100; + var content_2 = random.getRandomString(contentLength_2, specialStr_2); + var maxRowsBak = oracledb.maxRows; + oracledb.maxRows = 10; + + async.series([ + function(cb) { + insertIntoClobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoClobTable1(id_2, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, C from nodb_clob1 WHERE id = " + id_1 + " or id = " +id_2, + { }, + { outFormat : oracledb.OBJECT }, + function(err, result) { + should.not.exist(err); + result.rows.length.should.eql(2); + var resultVal = result.rows[0].C; + compareClientFetchResult(err, resultVal, specialStr_1, content_1, contentLength_1); + resultVal = result.rows[1].C; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + oracledb.maxRows = maxRowsBak; + cb(); + } + ); + } + ], done); + }); // 84.2.15 + + it('84.2.16 override oracledb.fetchAsString with fetchInfo set to oracledb.DEFAULT', function(done) { + var id = insertID++; + var specialStr = '84.2.16'; + var contentLength = 20; + var content = random.getRandomString(contentLength, specialStr); + + async.series([ + function(cb) { + insertIntoClobTable1(id, content, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, C from nodb_clob1 WHERE ID = :id", + { id : id }, + { + fetchInfo : { C : { type : oracledb.DEFAULT } } + }, + function(err, result) { + should.not.exist(err); + (result.rows.length).should.not.eql(0); + var lob = result.rows[0][1]; + should.exist(lob); + + // set the encoding so we get a 'string' not a 'buffer' + lob.setEncoding('utf8'); + var clobData = ''; + + lob.on('data', function(chunk) { + clobData += chunk; + }); + + lob.on('error', function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + lob.on('end', function() { + should.not.exist(err); + compareClientFetchResult(err, clobData, specialStr, content, contentLength); + cb(); + }); + } + ); + } + ], done); + }); // 84.2.16 + + }); // 84.2 + + describe('84.3 fetch CLOB columns by setting oracledb.fetchAsString, outFormat = oracledb.OBJECT and resultSet = true', function() { + + before('Create table and populate', function(done) { + connection.execute( + proc_create_table1, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // before + + after('drop table', function(done) { + connection.execute( + drop_table1, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // after + + beforeEach('set oracledb.fetchAsString', function(done) { + oracledb.fetchAsString = [ oracledb.CLOB ]; + done(); + }); // beforeEach + + afterEach('clear the by-type specification', function(done) { + oracledb.fetchAsString = []; + done(); + }); // afterEach + + var insertAndFetch = function(id, specialStr, insertContent, insertContentLength, callback) { + async.series([ + function(cb) { + insertIntoClobTable1(id, insertContent, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, C from nodb_clob1 WHERE ID = :id", + { id : id }, + { + outFormat : oracledb.OBJECT, + resultSet : true + }, + function(err, result) { + should.not.exist(err); + result.resultSet.getRow( + function(err, row) { + var resultVal; + resultVal = row.C; + if(specialStr === null) { + should.equal(resultVal, null); + } else { + compareClientFetchResult(err, resultVal, specialStr, insertContent, insertContentLength); + } + result.resultSet.close(function(err) { + should.not.exist(err); + cb(); + }); + } + ); + } + ); + } + ], callback); + }; + + it('84.3.1 works with NULL value', function(done) { + var id = insertID++; + var content = null; + + insertAndFetch(id, null, content, null, done); + }); // 84.3.1 + + it('84.3.2 works with empty String', function(done) { + var id = insertID++; + var content = ""; + + insertAndFetch(id, null, content, null, done); + }); // 84.3.2 + + it('84.3.3 works with small value', function(done) { + var id = insertID++; + var specialStr = '84.3.3'; + var contentLength = 20; + var content = random.getRandomString(contentLength, specialStr); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 84.3.3 + + it('84.3.4 works with (64K - 1) value', function(done) { + var id = insertID++; + var specialStr = '84.3.4'; + var contentLength = 65535; + var content = random.getRandomString(contentLength, specialStr); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 84.3.4 + + it('84.3.5 works with (64K + 1) value', function(done) { + var id = insertID++; + var specialStr = '84.3.5'; + var contentLength = 65537; + var content = random.getRandomString(contentLength, specialStr); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 84.3.5 + + it('84.3.6 works with (1MB + 1) data', function(done) { + var id = insertID++; + var specialStr = '84.3.6'; + var contentLength = 1048577; // 1MB + 1 + var content = random.getRandomString(contentLength, specialStr); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 84.3.6 + + it('84.3.7 works with dbms_lob.substr()', function(done) { + var id = insertID++; + var specialStr = '84.3.7'; + var contentLength = 200; + var specialStrLength = specialStr.length; + var content = random.getRandomString(contentLength, specialStr); + + async.series([ + function(cb) { + insertIntoClobTable1(id, content, cb); + }, + function(cb) { + connection.execute( + "SELECT dbms_lob.substr(C, " + specialStrLength + ", 1) AS C1 from nodb_clob1 WHERE ID = :id", + { id : id }, + { + outFormat : oracledb.OBJECT, + resultSet : true + }, + function(err, result) { + should.not.exist(err); + result.resultSet.getRow( + function(err, row) { + should.not.exist(err); + var resultVal = row.C1; + compareClientFetchResult(err, resultVal, specialStr, specialStr, specialStrLength); + result.resultSet.close(function(err) { + should.not.exist(err); + cb(); + }); + } + ); + } + ); + } + ], done); + }); // 84.3.7 + + it('84.3.8 works with EMPTY_CLOB()', function(done) { + var id = insertID++; + var content = "EMPTY_CLOB"; + + insertAndFetch(id, null, content, null, done); + }); // 84.3.8 + + it('84.3.9 fetch multiple CLOB rows as String', function(done) { + var id_1 = insertID++; + var specialStr_1 = '84.3.9_1'; + var contentLength_1 = 200; + var content_1 = random.getRandomString(contentLength_1, specialStr_1); + var id_2 = insertID++; + var specialStr_2 = '84.3.9_2'; + var contentLength_2 = 100; + var content_2 = random.getRandomString(contentLength_2, specialStr_2); + + async.series([ + function(cb) { + insertIntoClobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoClobTable1(id_2, content_2, cb); + }, + function(cb) { + var rowNumFetched = 2; + connection.execute( + "SELECT ID, C from nodb_clob1 WHERE ID = " + id_1 + " or id = " + id_2, + { }, + { + outFormat : oracledb.OBJECT, + resultSet : true + }, + function(err, result) { + should.not.exist(err); + result.resultSet.getRows( + rowNumFetched, + function(err, row) { + should.not.exist(err); + var resultVal = row[0].C; + compareClientFetchResult(err, resultVal, specialStr_1, content_1, contentLength_1); + resultVal = row[1].C; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + result.resultSet.close(function(err) { + should.not.exist(err); + cb(); + }); + } + ); + } + ); + } + ], done); + }); // 84.3.9 + + it('84.3.10 fetch the same CLOB column multiple times', function(done) { + var id = insertID++; + var specialStr = '84.3.10'; + var contentLength = 200; + var content = random.getRandomString(contentLength, specialStr); + + async.series([ + function(cb) { + insertIntoClobTable1(id, content, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, C AS C1, C AS C2 from nodb_clob1 WHERE ID = " + id, + { }, + { + outFormat : oracledb.OBJECT, + resultSet : true + }, + function(err, result) { + should.not.exist(err); + result.resultSet.getRow( + function(err, row) { + should.not.exist(err); + var resultVal = row.C1; + compareClientFetchResult(err, resultVal, specialStr, content, contentLength); + resultVal = row.C2; + compareClientFetchResult(err, resultVal, specialStr, content, contentLength); + result.resultSet.close(function(err) { + should.not.exist(err); + cb(); + }); + } + ); + } + ); + } + ], done); + }); // 84.3.10 + + it('84.3.11 works with update statement', function(done) { + var id = insertID++; + var specialStr_1 = '84.3.11_1'; + var contentLength_1 = 200; + var content_1 = random.getRandomString(contentLength_1, specialStr_1); + var specialStr_2 = '84.3.11_2'; + var contentLength_2 = 208; + var content_2 = random.getRandomString(contentLength_2, specialStr_2); + + async.series([ + function(cb) { + insertAndFetch(id, specialStr_1, content_1, contentLength_1, cb); + }, + function(cb) { + updateClobTable1(id, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, C from nodb_clob1 WHERE ID = " + id, + { }, + { + outFormat : oracledb.OBJECT, + resultSet : true + }, + function(err, result) { + should.not.exist(err); + result.resultSet.getRow( + function(err, row) { + should.not.exist(err); + var resultVal = row.C; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + result.resultSet.close(function(err) { + should.not.exist(err); + cb(); + }); + } + ); + } + ); + } + ], done); + }); // 84.3.11 + + it('84.3.12 works with REF CURSOR', function(done) { + var id = insertID++; + var specialStr = '84.3.12'; + var contentLength = 100; + var content = random.getRandomString(contentLength, specialStr); + + async.series([ + function(cb) { + insertIntoClobTable1(id, content, cb); + }, + function(cb) { + var ref_proc = "CREATE OR REPLACE PROCEDURE nodb_ref(clob_cursor OUT SYS_REFCURSOR)\n" + + "AS \n" + + "BEGIN \n" + + " OPEN clob_cursor FOR \n" + + " SELECT C from nodb_clob1 WHERE ID = " + id + "; \n" + + "END;"; + connection.execute( + ref_proc, + function(err){ + should.not.exist(err); + cb(); + } + ); + }, + function(cb) { + var sql = "BEGIN nodb_ref(:c); END;"; + var bindVar = { + c: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT } + }; + connection.execute( + sql, + bindVar, + function(err, result) { + result.outBinds.c.getRows(3, function(err, rows) { + var resultVal = rows[0][0]; + compareClientFetchResult(err, resultVal, specialStr, content, contentLength); + cb(); + }); + } + ); + }, + function(cb) { + var ref_proc_drop = "DROP PROCEDURE nodb_ref"; + connection.execute( + ref_proc_drop, + function(err){ + should.not.exist(err); + cb(); + } + ); + } + ], done); + }); // 84.3.12 + + it('84.3.13 fetch CLOB with stream', function(done) { + var id = insertID++; + var specialStr = '84.3.13'; + var contentLength = 200; + var content = random.getRandomString(contentLength, specialStr); + + async.series([ + function(cb) { + insertIntoClobTable1(id, content, cb); + }, + function(cb) { + oracledb.fetchAsString = []; + connection.execute( + "SELECT C from nodb_clob1 WHERE ID = " + id, + function(err, result) { + should.not.exist(err); + (result.rows.length).should.not.eql(0); + var lob = result.rows[0][0]; + should.exist(lob); + + // set the encoding so we get a 'string' not a 'buffer' + lob.setEncoding('utf8'); + var clobData = ''; + + lob.on('data', function(chunk) { + clobData += chunk; + }); + + lob.on('error', function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + lob.on('end', function() { + should.not.exist(err); + compareClientFetchResult(err, clobData, specialStr, content, contentLength); + cb(); + }); + } + ); + } + ], done); + }); // 84.3.13 + + it('84.3.14 works with setting oracledb.maxRows < actual number of rows in the table', function(done) { + var id_1 = insertID++; + var specialStr_1 = '84.3.14_1'; + var contentLength_1 = 200; + var content_1 = random.getRandomString(contentLength_1, specialStr_1); + var id_2 = insertID++; + var specialStr_2 = '84.3.14_2'; + var contentLength_2 = 100; + var content_2 = random.getRandomString(contentLength_2, specialStr_2); + var maxRowsBak = oracledb.maxRows; + oracledb.maxRows = 1; // maxRows is ignored when fetching rows with a ResultSet. + + async.series([ + function(cb) { + insertIntoClobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoClobTable1(id_2, content_2, cb); + }, + function(cb) { + var rowNumFetched = 2; + connection.execute( + "SELECT ID, C from nodb_clob1 WHERE id = " + id_1 + " or id = " +id_2, + { }, + { + outFormat : oracledb.OBJECT, + resultSet : true + }, + function(err, result) { + should.not.exist(err); + result.resultSet.getRows( + rowNumFetched, + function(err, row) { + should.not.exist(err); + should.strictEqual(row.length, 2); + var resultVal = row[0].C; + compareClientFetchResult(err, resultVal, specialStr_1, content_1, contentLength_1); + resultVal = row[1].C; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + oracledb.maxRows =maxRowsBak; + result.resultSet.close(function(err) { + should.not.exist(err); + cb(); + }); + } + ); + } + ); + } + ], done); + }); // 84.3.14 + + it('84.3.15 works with setting oracledb.maxRows > actual number of rows in the table', function(done) { + var id_1 = insertID++; + var specialStr_1 = '84.3.15_1'; + var contentLength_1 = 200; + var content_1 = random.getRandomString(contentLength_1, specialStr_1); + var id_2 = insertID++; + var specialStr_2 = '84.3.15_2'; + var contentLength_2 = 100; + var content_2 = random.getRandomString(contentLength_2, specialStr_2); + var maxRowsBak = oracledb.maxRows; + oracledb.maxRows = 10; + + async.series([ + function(cb) { + insertIntoClobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoClobTable1(id_2, content_2, cb); + }, + function(cb) { + var rowNumFetched = 2; + connection.execute( + "SELECT ID, C from nodb_clob1 WHERE id = " + id_1 + " or id = " +id_2, + { }, + { + outFormat : oracledb.OBJECT, + resultSet : true + }, + function(err, result) { + should.not.exist(err); + result.resultSet.getRows( + rowNumFetched, + function(err, row) { + should.not.exist(err); + should.strictEqual(row.length, 2); + var resultVal = row[0].C; + compareClientFetchResult(err, resultVal, specialStr_1, content_1, contentLength_1); + resultVal = row[1].C; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + oracledb.maxRows =maxRowsBak; + result.resultSet.close(function(err) { + should.not.exist(err); + cb(); + }); + } + ); + } + ); + } + ], done); + }); // 84.3.15 + + it('84.3.16 override oracledb.fetchAsString with fetchInfo set to oracledb.DEFAULT', function(done) { + var id = insertID++; + var specialStr = '84.3.16'; + var contentLength = 20; + var content = random.getRandomString(contentLength, specialStr); + + async.series([ + function(cb) { + insertIntoClobTable1(id, content, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, C from nodb_clob1 WHERE ID = :id", + { id : id }, + { + fetchInfo : { C : { type : oracledb.DEFAULT } } + }, + function(err, result) { + should.not.exist(err); + (result.rows.length).should.not.eql(0); + var lob = result.rows[0][1]; + should.exist(lob); + + // set the encoding so we get a 'string' not a 'buffer' + lob.setEncoding('utf8'); + var clobData = ''; + + lob.on('data', function(chunk) { + clobData += chunk; + }); + + lob.on('error', function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + lob.on('end', function() { + should.not.exist(err); + compareClientFetchResult(err, clobData, specialStr, content, contentLength); + cb(); + }); + } + ); + } + ], done); + }); // 84.3.16 + + }); // 84.3 + + describe('84.4 fetch CLOB columns by setting oracledb.fetchAsString and outFormat = oracledb.ARRAY', function() { + + before('Create table and populate', function(done) { + connection.execute( + proc_create_table1, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // before + + after('drop table', function(done) { + connection.execute( + drop_table1, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // after + + beforeEach('set oracledb.fetchAsString', function(done) { + oracledb.fetchAsString = [ oracledb.CLOB ]; + done(); + }); // beforeEach + + afterEach('clear the by-type specification', function(done) { + oracledb.fetchAsString = []; + done(); + }); // afterEach + + var insetAndFetch = function(id, specialStr, insertcontent, insetContentLength, callback) { + async.series([ + function(cb) { + insertIntoClobTable1(id, insertcontent, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, C from nodb_clob1 WHERE ID = :id", + { id : id }, + { outFormat : oracledb.ARRAY }, + function(err, result) { + var resultVal = result.rows[0][1]; + if(specialStr === null) { + should.not.exist(err); + should.equal(resultVal, null); + } else { + compareClientFetchResult(err, resultVal, specialStr, insertcontent, insetContentLength); + } + cb(); + } + ); + } + ], callback); + }; + + it('84.4.1 works with NULL value', function(done) { + var id = insertID++; + var content = null; + + insetAndFetch(id, null, content, null, done); + }); // 84.4.1 + + it('84.4.2 works with empty String', function(done) { + var id = insertID++; + var content = ""; + + insetAndFetch(id, null, content, null, done); + }); // 84.4.2 + + it('84.4.3 works with small value', function(done) { + var id = insertID++; + var specialStr = '84.4.3'; + var contentLength = 20; + var content = random.getRandomString(contentLength, specialStr); + + insetAndFetch(id, specialStr, content, contentLength, done); + }); // 84.4.3 + + it('84.4.4 works with (64K - 1) value', function(done) { + var id = insertID++; + var specialStr = '84.4.4'; + var contentLength = 65535; + var content = random.getRandomString(contentLength, specialStr); + + insetAndFetch(id, specialStr, content, contentLength, done); + }); // 84.4.4 + + it('84.4.5 works with (64K + 1) value', function(done) { + var id = insertID++; + var specialStr = '84.4.5'; + var contentLength = 65537; + var content = random.getRandomString(contentLength, specialStr); + + insetAndFetch(id, specialStr, content, contentLength, done); + }); // 84.4.5 + + it('84.4.6 works with (1MB + 1) data', function(done) { + var id = insertID++; + var specialStr = '84.4.6'; + var contentLength = 1048577; // 1MB + 1 + var content = random.getRandomString(contentLength, specialStr); + + insetAndFetch(id, specialStr, content, contentLength, done); + }); // 84.4.6 + + it('84.4.7 works with dbms_lob.substr()', function(done) { + var id = insertID++; + var specialStr = '84.4.7'; + var contentLength = 200; + var specialStrLength = specialStr.length; + var content = random.getRandomString(contentLength, specialStr); + + async.series([ + function(cb) { + insertIntoClobTable1(id, content, cb); + }, + function(cb) { + connection.execute( + "SELECT dbms_lob.substr(C, " + specialStrLength + ", 1) from nodb_clob1 WHERE ID = :id", + { id : id }, + { outFormat : oracledb.ARRAY }, + function(err, result) { + should.not.exist(err); + var resultVal = result.rows[0][0]; + compareClientFetchResult(err, resultVal, specialStr, specialStr, specialStrLength); + cb(); + } + ); + } + ], done); + }); // 84.4.7 + + it('84.4.8 works with EMPTY_CLOB()', function(done) { + var id = insertID++; + var content = "EMPTY_CLOB"; + + insetAndFetch(id, null, content, null, done); + }); // 84.4.8 + + it('84.4.9 fetch multiple CLOB rows as String', function(done) { + var id_1 = insertID++; + var specialStr_1 = '84.4.9_1'; + var contentLength_1 = 200; + var content_1 = random.getRandomString(contentLength_1, specialStr_1); + var id_2 = insertID++; + var specialStr_2 = '84.4.9_2'; + var contentLength_2 = 100; + var content_2 = random.getRandomString(contentLength_2, specialStr_2); + + async.series([ + function(cb) { + insertIntoClobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoClobTable1(id_2, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, C from nodb_clob1 WHERE ID = " + id_1 + " or id = " + id_2, + { }, + { outFormat : oracledb.ARRAY }, + function(err, result) { + should.not.exist(err); + var resultVal = result.rows[0][1]; + compareClientFetchResult(err, resultVal, specialStr_1, content_1, contentLength_1); + resultVal = result.rows[1][1]; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + cb(); + } + ); + } + ], done); + }); // 84.4.9 + + it('84.4.10 fetch the same CLOB column multiple times', function(done) { + var id = insertID++; + var specialStr = '84.4.10'; + var contentLength = 200; + var content = random.getRandomString(contentLength, specialStr); + + async.series([ + function(cb) { + insertIntoClobTable1(id, content, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, C AS C1, C AS C2 from nodb_clob1 WHERE ID = " + id, + { }, + { outFormat : oracledb.ARRAY }, + function(err, result) { + should.not.exist(err); + var resultVal = result.rows[0][1]; + compareClientFetchResult(err, resultVal, specialStr, content, contentLength); + resultVal = result.rows[0][2]; + compareClientFetchResult(err, resultVal, specialStr, content, contentLength); + cb(); + } + ); + } + ], done); + }); // 84.4.10 + + it('84.4.11 works with update statement', function(done) { + var id = insertID++; + var specialStr_1 = '84.4.11_1'; + var contentLength_1 = 200; + var content_1 = random.getRandomString(contentLength_1, specialStr_1); + var specialStr_2 = '84.4.11_2'; + var contentLength_2 = 208; + var content_2 = random.getRandomString(contentLength_2, specialStr_2); + + async.series([ + function(cb) { + insetAndFetch(id, specialStr_1, content_1, contentLength_1, cb); + }, + function(cb) { + updateClobTable1(id, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, C from nodb_clob1 WHERE ID = " + id, + { }, + { outFormat : oracledb.ARRAY }, + function(err, result) { + should.not.exist(err); + var resultVal = result.rows[0][1]; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + cb(); + } + ); + } + ], done); + }); // 84.4.11 + + it('84.4.12 works with REF CURSOR', function(done) { + var id = insertID++; + var specialStr = '84.4.12'; + var contentLength = 100; + var content = random.getRandomString(contentLength, specialStr); + + async.series([ + function(cb) { + insertIntoClobTable1(id, content, cb); + }, + function(cb) { + var ref_proc = "CREATE OR REPLACE PROCEDURE nodb_ref(clob_cursor OUT SYS_REFCURSOR)\n" + + "AS \n" + + "BEGIN \n" + + " OPEN clob_cursor FOR \n" + + " SELECT C from nodb_clob1 WHERE ID = " + id + "; \n" + + "END;"; + connection.execute( + ref_proc, + function(err){ + should.not.exist(err); + cb(); + } + ); + }, + function(cb) { + var sql = "BEGIN nodb_ref(:c); END;"; + var bindVar = { + c: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT } + }; + connection.execute( + sql, + bindVar, + function(err, result) { + result.outBinds.c.getRows(3, function(err, rows) { + var resultVal = rows[0][0]; + compareClientFetchResult(err, resultVal, specialStr, content, contentLength); + cb(); + }); + } + ); + }, + function(cb) { + var ref_proc_drop = "DROP PROCEDURE nodb_ref"; + connection.execute( + ref_proc_drop, + function(err){ + should.not.exist(err); + cb(); + } + ); + } + ], done); + }); // 84.4.12 + + it('84.4.13 fetch CLOB with stream', function(done) { + var id = insertID++; + var specialStr = '84.4.13'; + var contentLength = 200; + var content = random.getRandomString(contentLength, specialStr); + + async.series([ + function(cb) { + insertIntoClobTable1(id, content, cb); + }, + function(cb) { + oracledb.fetchAsString = []; + connection.execute( + "SELECT C from nodb_clob1 WHERE ID = " + id, + function(err, result) { + should.not.exist(err); + (result.rows.length).should.not.eql(0); + var lob = result.rows[0][0]; + should.exist(lob); + + // set the encoding so we get a 'string' not a 'buffer' + lob.setEncoding('utf8'); + var clobData = ''; + + lob.on('data', function(chunk) { + clobData += chunk; + }); + + lob.on('error', function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + lob.on('end', function() { + should.not.exist(err); + compareClientFetchResult(err, clobData, specialStr, content, contentLength); + cb(); + }); + } + ); + } + ], done); + }); // 84.4.13 + + it('84.4.14 works with setting oracledb.maxRows < actual number of rows in the table', function(done) { + var id_1 = insertID++; + var specialStr_1 = '84.4.14_1'; + var contentLength_1 = 200; + var content_1 = random.getRandomString(contentLength_1, specialStr_1); + var id_2 = insertID++; + var specialStr_2 = '84.4.14_2'; + var contentLength_2 = 100; + var content_2 = random.getRandomString(contentLength_2, specialStr_2); + var maxRowsBak = oracledb.maxRows; + // oracledb.maxRows: The maximum number of rows that are fetched by the execute() call of the Connection object when not using a ResultSet. + // Rows beyond this limit are not fetched from the database. + oracledb.maxRows = 1; + + async.series([ + function(cb) { + insertIntoClobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoClobTable1(id_2, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, C from nodb_clob1 WHERE id = " + id_1 + " or id = " +id_2, + { }, + { outFormat : oracledb.ARRAY }, + function(err, result) { + should.not.exist(err); + result.rows.length.should.eql(1); + var resultVal = result.rows[0][1]; + compareClientFetchResult(err, resultVal, specialStr_1, content_1, contentLength_1); + oracledb.maxRows = maxRowsBak; + cb(); + } + ); + } + ], done); + }); // 84.4.14 + + it('84.4.15 works with setting oracledb.maxRows < actual number of rows in the table', function(done) { + var id_1 = insertID++; + var specialStr_1 = '84.4.15_1'; + var contentLength_1 = 200; + var content_1 = random.getRandomString(contentLength_1, specialStr_1); + var id_2 = insertID++; + var specialStr_2 = '84.4.15_2'; + var contentLength_2 = 100; + var content_2 = random.getRandomString(contentLength_2, specialStr_2); + var maxRowsBak = oracledb.maxRows; + oracledb.maxRows = 10; + + async.series([ + function(cb) { + insertIntoClobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoClobTable1(id_2, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, C from nodb_clob1 WHERE id = " + id_1 + " or id = " +id_2, + { }, + { outFormat : oracledb.ARRAY }, + function(err, result) { + should.not.exist(err); + result.rows.length.should.eql(2); + var resultVal = result.rows[0][1]; + compareClientFetchResult(err, resultVal, specialStr_1, content_1, contentLength_1); + resultVal = result.rows[1][1]; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + oracledb.maxRows = maxRowsBak; + cb(); + } + ); + } + ], done); + }); // 84.4.15 + + it('84.4.16 override oracledb.fetchAsString with fetchInfo set to oracledb.DEFAULT', function(done) { + var id = insertID++; + var specialStr = '84.4.16'; + var contentLength = 20; + var content = random.getRandomString(contentLength, specialStr); + + async.series([ + function(cb) { + insertIntoClobTable1(id, content, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, C from nodb_clob1 WHERE ID = :id", + { id : id }, + { + fetchInfo : { C : { type : oracledb.DEFAULT } } + }, + function(err, result) { + should.not.exist(err); + (result.rows.length).should.not.eql(0); + var lob = result.rows[0][1]; + should.exist(lob); + + // set the encoding so we get a 'string' not a 'buffer' + lob.setEncoding('utf8'); + var clobData = ''; + + lob.on('data', function(chunk) { + clobData += chunk; + }); + + lob.on('error', function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + lob.on('end', function() { + should.not.exist(err); + compareClientFetchResult(err, clobData, specialStr, content, contentLength); + cb(); + }); + } + ); + } + ], done); + }); // 84.4.16 + + }); // 84.4 + + describe('84.5 fetch CLOB columns by setting oracledb.fetchAsString, outFormat = oracledb.ARRAY and resultSet = true', function() { + + before('Create table and populate', function(done) { + connection.execute( + proc_create_table1, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // before + + after('drop table', function(done) { + connection.execute( + drop_table1, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // after + + beforeEach('set oracledb.fetchAsString', function(done) { + oracledb.fetchAsString = [ oracledb.CLOB ]; + done(); + }); // beforeEach + + afterEach('clear the by-type specification', function(done) { + oracledb.fetchAsString = []; + done(); + }); // afterEach + + var insertAndFetch = function(id, specialStr, insertContent, insertContentLength, callback) { + async.series([ + function(cb) { + insertIntoClobTable1(id, insertContent, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, C from nodb_clob1 WHERE ID = :id", + { id : id }, + { + outFormat : oracledb.ARRAY, + resultSet : true + }, + function(err, result) { + should.not.exist(err); + result.resultSet.getRow( + function(err, row) { + var resultVal; + resultVal = row[1]; + if(specialStr === null) { + should.equal(resultVal, null); + } else { + compareClientFetchResult(err, resultVal, specialStr, insertContent, insertContentLength); + } + result.resultSet.close(function(err) { + should.not.exist(err); + cb(); + }); + } + ); + } + ); + } + ], callback); + }; + + it('84.5.1 works with NULL value', function(done) { + var id = insertID++; + var content = null; + + insertAndFetch(id, null, content, null, done); + }); // 84.5.1 + + it('84.5.2 works with empty String', function(done) { + var id = insertID++; + var content = ""; + + insertAndFetch(id, null, content, null, done); + }); // 84.5.2 + + it('84.5.3 works with small value', function(done) { + var id = insertID++; + var specialStr = '84.5.3'; + var contentLength = 20; + var content = random.getRandomString(contentLength, specialStr); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 84.5.3 + + it('84.5.4 works with (64K - 1) value', function(done) { + var id = insertID++; + var specialStr = '84.5.4'; + var contentLength = 65535; + var content = random.getRandomString(contentLength, specialStr); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 84.5.4 + + it('84.5.5 works with (64K + 1) value', function(done) { + var id = insertID++; + var specialStr = '84.5.5'; + var contentLength = 65537; + var content = random.getRandomString(contentLength, specialStr); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 84.5.5 + + it('84.5.6 works with (1MB + 1) data', function(done) { + var id = insertID++; + var specialStr = '84.5.6'; + var contentLength = 1048577; // 1MB + 1 + var content = random.getRandomString(contentLength, specialStr); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 84.5.6 + + it('84.5.7 works with dbms_lob.substr()', function(done) { + var id = insertID++; + var specialStr = '84.5.7'; + var contentLength = 200; + var specialStrLength = specialStr.length; + var content = random.getRandomString(contentLength, specialStr); + + async.series([ + function(cb) { + insertIntoClobTable1(id, content, cb); + }, + function(cb) { + connection.execute( + "SELECT dbms_lob.substr(C, " + specialStrLength + ", 1) AS C1 from nodb_clob1 WHERE ID = :id", + { id : id }, + { + outFormat : oracledb.ARRAY, + resultSet : true + }, + function(err, result) { + should.not.exist(err); + result.resultSet.getRow( + function(err, row) { + // console.log(row[0]); + should.not.exist(err); + var resultVal = row[0]; + compareClientFetchResult(err, resultVal, specialStr, specialStr, specialStrLength); + result.resultSet.close(function(err) { + should.not.exist(err); + cb(); + }); + } + ); + } + ); + } + ], done); + }); // 84.5.7 + + it('84.5.8 works with EMPTY_CLOB()', function(done) { + var id = insertID++; + var content = "EMPTY_CLOB"; + + insertAndFetch(id, null, content, null, done); + }); // 84.5.8 + + it('84.5.9 fetch multiple CLOB rows as String', function(done) { + var id_1 = insertID++; + var specialStr_1 = '84.5.9_1'; + var contentLength_1 = 200; + var content_1 = random.getRandomString(contentLength_1, specialStr_1); + var id_2 = insertID++; + var specialStr_2 = '84.5.9_2'; + var contentLength_2 = 100; + var content_2 = random.getRandomString(contentLength_2, specialStr_2); + + async.series([ + function(cb) { + insertIntoClobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoClobTable1(id_2, content_2, cb); + }, + function(cb) { + var rowNumFetched = 2; + connection.execute( + "SELECT ID, C from nodb_clob1 WHERE ID = " + id_1 + " or id = " + id_2, + { }, + { + outFormat : oracledb.ARRAY, + resultSet : true + }, + function(err, result) { + should.not.exist(err); + result.resultSet.getRows( + rowNumFetched, + function(err, row) { + should.not.exist(err); + var resultVal = row[0][1]; + compareClientFetchResult(err, resultVal, specialStr_1, content_1, contentLength_1); + resultVal = row[1][1]; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + result.resultSet.close(function(err) { + should.not.exist(err); + cb(); + }); + } + ); + } + ); + } + ], done); + }); // 84.5.9 + + it('84.5.10 fetch the same CLOB column multiple times', function(done) { + var id = insertID++; + var specialStr = '84.5.10'; + var contentLength = 200; + var content = random.getRandomString(contentLength, specialStr); + + async.series([ + function(cb) { + insertIntoClobTable1(id, content, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, C AS C1, C AS C2 from nodb_clob1 WHERE ID = " + id, + { }, + { + outFormat : oracledb.ARRAY, + resultSet : true + }, + function(err, result) { + should.not.exist(err); + result.resultSet.getRow( + function(err, row) { + should.not.exist(err); + var resultVal = row[1]; + compareClientFetchResult(err, resultVal, specialStr, content, contentLength); + resultVal = row[2]; + compareClientFetchResult(err, resultVal, specialStr, content, contentLength); + result.resultSet.close(function(err) { + should.not.exist(err); + cb(); + }); + } + ); + } + ); + } + ], done); + }); // 84.5.10 + + it('84.5.11 works with update statement', function(done) { + var id = insertID++; + var specialStr_1 = '84.5.11_1'; + var contentLength_1 = 208; + var content_1 = random.getRandomString(contentLength_1, specialStr_1); + var specialStr_2 = '84.5.11_2'; + var contentLength_2 = 208; + var content_2 = random.getRandomString(contentLength_2, specialStr_2); + + async.series([ + function(cb) { + insertAndFetch(id, specialStr_1, content_1, contentLength_1, cb); + }, + function(cb) { + updateClobTable1(id, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, C from nodb_clob1 WHERE ID = " + id, + { }, + { + outFormat : oracledb.ARRAY, + resultSet : true + }, + function(err, result) { + should.not.exist(err); + result.resultSet.getRow( + function(err, row) { + should.not.exist(err); + var resultVal = row[1]; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + result.resultSet.close(function(err) { + should.not.exist(err); + cb(); + }); + } + ); + } + ); + } + ], done); + }); // 84.5.11 + + it('84.5.12 works with REF CURSOR', function(done) { + var id = insertID++; + var specialStr = '84.5.12'; + var contentLength = 100; + var content = random.getRandomString(contentLength, specialStr); + + async.series([ + function(cb) { + insertIntoClobTable1(id, content, cb); + }, + function(cb) { + var ref_proc = "CREATE OR REPLACE PROCEDURE nodb_ref(clob_cursor OUT SYS_REFCURSOR)\n" + + "AS \n" + + "BEGIN \n" + + " OPEN clob_cursor FOR \n" + + " SELECT C from nodb_clob1 WHERE ID = " + id + "; \n" + + "END;"; + connection.execute( + ref_proc, + function(err){ + should.not.exist(err); + cb(); + } + ); + }, + function(cb) { + var sql = "BEGIN nodb_ref(:c); END;"; + var bindVar = { + c: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT } + }; + connection.execute( + sql, + bindVar, + function(err, result) { + result.outBinds.c.getRows(3, function(err, rows) { + var resultVal = rows[0][0]; + compareClientFetchResult(err, resultVal, specialStr, content, contentLength); + cb(); + }); + } + ); + }, + function(cb) { + var ref_proc_drop = "DROP PROCEDURE nodb_ref"; + connection.execute( + ref_proc_drop, + function(err){ + should.not.exist(err); + cb(); + } + ); + } + ], done); + }); // 84.5.12 + + it('84.5.13 fetch CLOB with stream', function(done) { + var id = insertID++; + var specialStr = '84.5.13'; + var contentLength = 200; + var content = random.getRandomString(contentLength, specialStr); + + async.series([ + function(cb) { + insertIntoClobTable1(id, content, cb); + }, + function(cb) { + oracledb.fetchAsString = []; + connection.execute( + "SELECT C from nodb_clob1 WHERE ID = " + id, + function(err, result) { + should.not.exist(err); + (result.rows.length).should.not.eql(0); + var lob = result.rows[0][0]; + should.exist(lob); + + // set the encoding so we get a 'string' not a 'String' + lob.setEncoding('utf8'); + var clobData = ''; + + lob.on('data', function(chunk) { + clobData += chunk; + }); + + lob.on('error', function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + lob.on('end', function() { + should.not.exist(err); + compareClientFetchResult(err, clobData, specialStr, content, contentLength); + cb(); + }); + } + ); + } + ], done); + }); // 84.5.13 + + it('84.5.14 works with setting oracledb.maxRows < actual number of rows in the table', function(done) { + var id_1 = insertID++; + var specialStr_1 = '84.5.14_1'; + var contentLength_1 = 200; + var content_1 = random.getRandomString(contentLength_1, specialStr_1); + var id_2 = insertID++; + var specialStr_2 = '84.5.14_2'; + var contentLength_2 = 100; + var content_2 = random.getRandomString(contentLength_2, specialStr_2); + var maxRowsBak = oracledb.maxRows; + oracledb.maxRows = 1; // maxRows is ignored when fetching rows with a ResultSet. + + async.series([ + function(cb) { + insertIntoClobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoClobTable1(id_2, content_2, cb); + }, + function(cb) { + var rowNumFetched = 2; + connection.execute( + "SELECT ID, C from nodb_clob1 WHERE id = " + id_1 + " or id = " +id_2, + { }, + { + outFormat : oracledb.ARRAY, + resultSet : true + }, + function(err, result) { + should.not.exist(err); + result.resultSet.getRows( + rowNumFetched, + function(err, row) { + should.not.exist(err); + should.strictEqual(row.length, 2); + var resultVal = row[0][1]; + compareClientFetchResult(err, resultVal, specialStr_1, content_1, contentLength_1); + resultVal = row[1][1]; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + oracledb.maxRows =maxRowsBak; + result.resultSet.close(function(err) { + should.not.exist(err); + cb(); + }); + } + ); + } + ); + } + ], done); + }); // 84.5.14 + + it('84.5.15 works with setting oracledb.maxRows > actual number of rows in the table', function(done) { + var id_1 = insertID++; + var specialStr_1 = '84.5.15_1'; + var contentLength_1 = 200; + var content_1 = random.getRandomString(contentLength_1, specialStr_1); + var id_2 = insertID++; + var specialStr_2 = '84.5.15_2'; + var contentLength_2 = 100; + var content_2 = random.getRandomString(contentLength_2, specialStr_2); + var maxRowsBak = oracledb.maxRows; + oracledb.maxRows = 10; + + async.series([ + function(cb) { + insertIntoClobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoClobTable1(id_2, content_2, cb); + }, + function(cb) { + var rowNumFetched = 2; + connection.execute( + "SELECT ID, C from nodb_clob1 WHERE id = " + id_1 + " or id = " +id_2, + { }, + { + outFormat : oracledb.ARRAY, + resultSet : true + }, + function(err, result) { + should.not.exist(err); + result.resultSet.getRows( + rowNumFetched, + function(err, row) { + should.not.exist(err); + should.strictEqual(row.length, 2); + var resultVal = row[0][1]; + compareClientFetchResult(err, resultVal, specialStr_1, content_1, contentLength_1); + resultVal = row[1][1]; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + oracledb.maxRows =maxRowsBak; + result.resultSet.close(function(err) { + should.not.exist(err); + cb(); + }); + } + ); + } + ); + } + ], done); + }); // 84.5.15 + + it('84.5.16 override oracledb.fetchAsString with fetchInfo set to oracledb.DEFAULT', function(done) { + var id = insertID++; + var specialStr = '84.5.16'; + var contentLength = 20; + var content = random.getRandomString(contentLength, specialStr); + + async.series([ + function(cb) { + insertIntoClobTable1(id, content, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, C from nodb_clob1 WHERE ID = :id", + { id : id }, + { + fetchInfo : { C : { type : oracledb.DEFAULT } } + }, + function(err, result) { + should.not.exist(err); + (result.rows.length).should.not.eql(0); + var lob = result.rows[0][1]; + should.exist(lob); + + // set the encoding so we get a 'string' not a 'String' + lob.setEncoding('utf8'); + var clobData = ''; + + lob.on('data', function(chunk) { + clobData += chunk; + }); + + lob.on('error', function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + lob.on('end', function() { + should.not.exist(err); + compareClientFetchResult(err, clobData, specialStr, content, contentLength); + cb(); + }); + } + ); + } + ], done); + }); // 84.5.16 + + }); // 84.5 +}); diff --git a/test/fetchClobAsString2.js b/test/fetchClobAsString2.js new file mode 100644 index 00000000..e5139bf9 --- /dev/null +++ b/test/fetchClobAsString2.js @@ -0,0 +1,2111 @@ +/* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with the Apache + * License, Version 2.0 (the "License.") + * + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + * The node-oracledb test suite uses 'mocha', 'should' and 'async'. + * See LICENSE.md for relevant licenses. + * + * NAME + * 85. fetchClobAsString2.js + * + * DESCRIPTION + * Testing Oracle data type support - CLOB. + * To fetch CLOB columns as strings by setting fetchInfo option + * This could be very useful for smaller CLOB size as it can be fetched as string and processed in memory itself. + * + * NUMBERING RULE + * Test numbers follow this numbering rule: + * 1 - 20 are reserved for basic functional tests + * 21 - 50 are reserved for data type supporting tests + * 51 onwards are for other tests + * + *****************************************************************************/ +'use strict'; + +var oracledb = require('oracledb'); +var async = require('async'); +var should = require('should'); +var file = require('./file.js'); +var dbConfig = require('./dbconfig.js'); +var random = require('./random.js'); + +describe('85. fetchClobAsString2.js', function() { + this.timeout(100000); + var connection = null; + var insertID = 1; // assume id for insert into db starts from 1 + var inFileName = './test/clobTmpFile.txt'; + var proc_create_table1 = "BEGIN \n" + + " DECLARE \n" + + " e_table_missing EXCEPTION; \n" + + " PRAGMA EXCEPTION_INIT(e_table_missing, -00942); \n" + + " BEGIN \n" + + " EXECUTE IMMEDIATE('DROP TABLE nodb_clob1 PURGE'); \n" + + " EXCEPTION \n" + + " WHEN e_table_missing \n" + + " THEN NULL; \n" + + " END; \n" + + " EXECUTE IMMEDIATE (' \n" + + " CREATE TABLE nodb_clob1 ( \n" + + " ID NUMBER, \n" + + " C CLOB \n" + + " ) \n" + + " '); \n" + + "END; "; + var drop_table1 = "DROP TABLE nodb_clob1 PURGE"; + + before('get one connection', function(done) { + async.series([ + function(cb) { + oracledb.stmtCacheSize = 0; + oracledb.getConnection(dbConfig, function(err, conn) { + should.not.exist(err); + connection = conn; + cb(); + }); + }, + function(cb) { + file.create(inFileName); + cb(); + } + ], done); + + }); // before + + after('release connection', function(done) { + async.series([ + function(cb) { + connection.release(function(err) { + should.not.exist(err); + cb(); + }); + }, + function(cb) { + file.delete(inFileName); + cb(); + } + ], done); + }); // after + + var insertIntoClobTable1 = function(id, content, callback) { + if(content == "EMPTY_CLOB") { + connection.execute( + "INSERT INTO nodb_clob1 VALUES (:ID, EMPTY_CLOB())", + [ id ], + function(err, result) { + should.not.exist(err); + should.strictEqual(result.rowsAffected, 1); + callback(); + } + ); + } else { + connection.execute( + "INSERT INTO nodb_clob1 VALUES (:ID, :C)", + { + ID : { val : id }, + C : { val : content, dir : oracledb.BIND_IN, type : oracledb.STRING } + }, + function(err, result) { + should.not.exist(err); + should.strictEqual(result.rowsAffected, 1); + callback(); + } + ); + } + }; + + var updateClobTable1 = function(id, content, callback) { + connection.execute( + "UPDATE nodb_clob1 set C = :C where ID = :ID", + { ID: id, C: content }, + function(err, result){ + should.not.exist(err); + should.strictEqual(result.rowsAffected, 1); + callback(); + } + ); + }; + + // compare fetch result + var compareClientFetchResult = function(err, resultVal, specialStr, content, contentLength) { + should.not.exist(err); + compareStrings(resultVal, specialStr, content, contentLength); + }; + + // compare two string + var compareStrings = function(resultVal, specialStr, content, contentLength) { + var specialStrLen = specialStr.length; + var resultLen = resultVal.length; + should.equal(resultLen, contentLength); + should.strictEqual(resultVal.substring(0, specialStrLen), specialStr); + should.strictEqual(resultVal.substring(resultLen - specialStrLen, resultLen), specialStr); + }; + + describe('85.1 fetch CLOB columns by setting fetchInfo option', function() { + + before('Create table and populate', function(done) { + connection.execute( + proc_create_table1, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // before + + after('drop table', function(done) { + connection.execute( + drop_table1, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // after + + insertID = 0; + var insertAndFetch = function(id, specialStr, insertContent, insertContentLength, callback) { + async.series([ + function(cb) { + insertIntoClobTable1(id, insertContent, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, C from nodb_clob1 WHERE ID = :id", + { id : id }, + { + fetchInfo : { C : { type : oracledb.STRING } } + }, + function(err, result) { + var resultVal = result.rows[0][1]; + if(specialStr === null) { + should.not.exist(err); + should.equal(resultVal, null); + } else { + compareClientFetchResult(err, resultVal, specialStr, insertContent, insertContentLength); + } + cb(); + } + ); + } + ], callback); + }; + + it('85.1.1 works with NULL value', function(done) { + var id = insertID++; + var content = null; + + insertAndFetch(id, null, content, null, done); + }); // 85.1.1 + + it('85.1.2 works with empty String', function(done) { + var id = insertID++; + var content = ""; + + insertAndFetch(id, null, content, null, done); + }); // 85.1.2 + + it('85.1.3 works with small value', function(done) { + var id = insertID++; + var specialStr = '85.1.3'; + var contentLength = 20; + var content = random.getRandomString(contentLength, specialStr); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 85.1.3 + + it('85.1.4 works with (64K - 1) value', function(done) { + var id = insertID++; + var specialStr = '85.1.4'; + var contentLength = 65535; + var content = random.getRandomString(contentLength, specialStr); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 85.1.4 + + it('85.1.5 works with (64K + 1) value', function(done) { + var id = insertID++; + var specialStr = '85.1.5'; + var contentLength = 65537; + var content = random.getRandomString(contentLength, specialStr); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 85.1.5 + + it('85.1.6 works with (1MB + 1) value', function(done) { + var id = insertID++; + var specialStr = '85.1.6'; + var contentLength = 1048577; // 1MB + 1 + var content = random.getRandomString(contentLength, specialStr); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 85.1.6 + + it('85.1.7 works with dbms_lob.substr()', function(done) { + var id = insertID++; + var specialStr = '85.1.7'; + var contentLength = 200; + var specialStrLength = specialStr.length; + var content = random.getRandomString(contentLength, specialStr); + + async.series([ + function(cb) { + insertIntoClobTable1(id, content, cb); + }, + function(cb) { + connection.execute( + "SELECT dbms_lob.substr(C, " + specialStrLength + ", 1) AS C1 from nodb_clob1 WHERE ID = :id", + { id : id }, + { + fetchInfo : { C1 : { type : oracledb.STRING } } + }, + function(err, result) { + should.not.exist(err); + // console.log(result); + var resultVal = result.rows[0][0]; + compareClientFetchResult(err, resultVal, specialStr, specialStr, specialStrLength); + cb(); + } + ); + } + ], done); + }); // 85.1.7 + + it('85.1.8 works with EMPTY_CLOB()', function(done) { + var id = insertID++; + var content = "EMPTY_CLOB"; + + insertAndFetch(id, null, content, null, done); + }); // 85.1.8 + + it('85.1.9 fetch multiple CLOB rows as String', function(done) { + var id_1 = insertID++; + var specialStr_1 = '85.1.9_1'; + var contentLength_1 = 200; + var content_1 = random.getRandomString(contentLength_1, specialStr_1); + var id_2 = insertID++; + var specialStr_2 = '85.1.9_2'; + var contentLength_2 = 100; + var content_2 = random.getRandomString(contentLength_2, specialStr_2); + + async.series([ + function(cb) { + insertIntoClobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoClobTable1(id_2, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, C from nodb_clob1 WHERE ID = " + id_1 + " or id = " + id_2, + { }, + { + fetchInfo : { C : { type : oracledb.STRING } } + }, + function(err, result) { + should.not.exist(err); + var resultVal = result.rows[0][1]; + compareClientFetchResult(err, resultVal, specialStr_1, content_1, contentLength_1); + resultVal = result.rows[1][1]; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + cb(); + } + ); + } + ], done); + }); // 85.1.9 + + it('85.1.10 fetch the same CLOB column multiple times', function(done) { + var id = insertID++; + var specialStr = '85.1.10'; + var contentLength = 200; + var content = random.getRandomString(contentLength, specialStr); + + async.series([ + function(cb) { + insertIntoClobTable1(id, content, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, C AS C1, C AS C2 from nodb_clob1 WHERE ID = " + id, + { }, + { + fetchInfo : { + C1 : { type : oracledb.STRING }, + C2 : { type : oracledb.STRING } } + }, + function(err, result) { + should.not.exist(err); + var resultVal = result.rows[0][1]; + compareClientFetchResult(err, resultVal, specialStr, content, contentLength); + resultVal = result.rows[0][2]; + compareClientFetchResult(err, resultVal, specialStr, content, contentLength); + cb(); + } + ); + } + ], done); + }); // 85.1.10 + + it('85.1.11 works with update statement', function(done) { + var id = insertID++; + var specialStr_1 = '85.1.11_1'; + var contentLength_1 = 200; + var content_1 = random.getRandomString(contentLength_1, specialStr_1); + var specialStr_2 = '85.1.11_2'; + var contentLength_2 = 208; + var content_2 = random.getRandomString(contentLength_2, specialStr_2); + + async.series([ + function(cb) { + insertAndFetch(id, specialStr_1, content_1, contentLength_1, cb); + }, + function(cb) { + updateClobTable1(id, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, C from nodb_clob1 WHERE ID = " + id, + { }, + { + fetchInfo : { C : { type : oracledb.STRING } } + }, + function(err, result) { + should.not.exist(err); + var resultVal = result.rows[0][1]; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + cb(); + } + ); + } + ], done); + }); // 85.1.8 + + it('85.1.12 works with setting oracledb.maxRows < actual number of rows in the table', function(done) { + var id_1 = insertID++; + var specialStr_1 = '85.1.12_1'; + var contentLength_1 = 200; + var content_1 = random.getRandomString(contentLength_1, specialStr_1); + var id_2 = insertID++; + var specialStr_2 = '85.1.12_2'; + var contentLength_2 = 100; + var content_2 = random.getRandomString(contentLength_2, specialStr_2); + var maxRowsBak = oracledb.maxRows; + oracledb.maxRows = 1; + + async.series([ + function(cb) { + insertIntoClobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoClobTable1(id_2, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, C from nodb_clob1 WHERE id = " + id_1 + " or id = " +id_2, + { }, + { + fetchInfo : { C : { type : oracledb.STRING } } + }, + function(err, result) { + should.not.exist(err); + result.rows.length.should.eql(1); + var resultVal = result.rows[0][1]; + compareClientFetchResult(err, resultVal, specialStr_1, content_1, contentLength_1); + oracledb.maxRows = maxRowsBak; + cb(); + } + ); + } + ], done); + }); // 85.1.12 + + it('85.1.13 works with setting oracledb.maxRows > actual number of rows in the table', function(done) { + var id_1 = insertID++; + var specialStr_1 = '85.1.13_1'; + var contentLength_1 = 200; + var content_1 = random.getRandomString(contentLength_1, specialStr_1); + var id_2 = insertID++; + var specialStr_2 = '85.1.13_2'; + var contentLength_2 = 100; + var content_2 = random.getRandomString(contentLength_2, specialStr_2); + var maxRowsBak = oracledb.maxRows; + oracledb.maxRows = 10; + + async.series([ + function(cb) { + insertIntoClobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoClobTable1(id_2, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, C from nodb_clob1 WHERE id = " + id_1 + " or id = " +id_2, + { }, + { + fetchInfo : { C : { type : oracledb.STRING } } + }, + function(err, result) { + should.not.exist(err); + result.rows.length.should.eql(2); + var resultVal = result.rows[0][1]; + compareClientFetchResult(err, resultVal, specialStr_1, content_1, contentLength_1); + resultVal = result.rows[1][1]; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + oracledb.maxRows = maxRowsBak; + cb(); + } + ); + } + ], done); + }); // 85.1.13 + + it('85.1.14 works with connection.queryStream()', function(done) { + var id = insertID++; + var specialStr = '85.1.14'; + var contentLength = 200; + var content = random.getRandomString(contentLength, specialStr); + + async.series([ + function(cb) { + insertIntoClobTable1(id, content, cb); + }, + function(cb) { + var sql = "SELECT ID, C from nodb_clob1 WHERE ID = " + id; + var stream = connection.queryStream(sql, {}, { fetchInfo : { C : { type : oracledb.STRING } } }); + stream.on('error', function (error) { + should.fail(error, null, 'Error event should not be triggered'); + }); + + var counter = 0; + stream.on('data', function(data) { + should.exist(data); + var result = data[1]; + should.strictEqual(typeof result, "string"); + compareStrings(result, specialStr, content, contentLength); + counter++; + }); + + stream.on('end', function () { + should.equal(counter, 1); + setTimeout(cb, 500); + }); + } + ], done); + }); // 85.1.14 + + it('85.1.15 works with connection.queryStream() and oracledb.maxRows > actual number of rows in the table', function(done) { + var id_1 = insertID++; + var specialStr_1 = '85.1.15_1'; + var contentLength_1 = 26; + var content_1 = random.getRandomString(contentLength_1, specialStr_1); + var id_2 = insertID++; + var specialStr_2 = '85.1.15_2'; + var contentLength_2 = 30; + var content_2 = random.getRandomString(contentLength_2, specialStr_2); + var maxRowsBak = oracledb.maxRows; + oracledb.maxRows = 20; + + async.series([ + function(cb) { + insertIntoClobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoClobTable1(id_2, content_2, cb); + }, + function(cb) { + var sql = "SELECT ID, C from nodb_clob1 WHERE ID = " + id_1 + " or id = " +id_2; + var stream = connection.queryStream(sql, {}, { fetchInfo : { C : { type : oracledb.STRING } } }); + stream.on('error', function (error) { + should.fail(error, null, 'Error event should not be triggered'); + }); + + var counter = 0; + stream.on('data', function(data) { + should.exist(data); + var result = data[1]; + should.strictEqual(typeof result, "string"); + counter++; + if(counter == 1) { + compareStrings(result, specialStr_1, content_1, contentLength_1); + } else { + compareStrings(result, specialStr_2, content_2, contentLength_2); + } + }); + + stream.on('end', function () { + should.equal(counter, 2); + oracledb.maxRows = maxRowsBak; + setTimeout(cb, 500); + }); + } + ], done); + }); // 85.1.15 + + it('85.1.16 works with connection.queryStream() and oracledb.maxRows = actual number of rows in the table', function(done) { + var id_1 = insertID++; + var specialStr_1 = '85.1.16_1'; + var contentLength_1 = 26; + var content_1 = random.getRandomString(contentLength_1, specialStr_1); + var id_2 = insertID++; + var specialStr_2 = '85.1.16_2'; + var contentLength_2 = 30; + var content_2 = random.getRandomString(contentLength_2, specialStr_2); + var maxRowsBak = oracledb.maxRows; + oracledb.maxRows = 2; + + async.series([ + function(cb) { + insertIntoClobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoClobTable1(id_2, content_2, cb); + }, + function(cb) { + var sql = "SELECT ID, C from nodb_clob1 WHERE ID = " + id_1 + " or id = " +id_2; + var stream = connection.queryStream(sql, {}, { fetchInfo : { C : { type : oracledb.STRING } } }); + stream.on('error', function (error) { + should.fail(error, null, 'Error event should not be triggered'); + }); + + var counter = 0; + stream.on('data', function(data) { + should.exist(data); + var result = data[1]; + should.strictEqual(typeof result, "string"); + counter++; + if(counter == 1) { + compareStrings(result, specialStr_1, content_1, contentLength_1); + } else { + compareStrings(result, specialStr_2, content_2, contentLength_2); + } + }); + + stream.on('end', function () { + should.equal(counter, 2); + oracledb.maxRows = maxRowsBak; + setTimeout(cb, 500); + }); + } + ], done); + }); // 85.1.16 + + it('85.1.17 works with connection.queryStream() and oracledb.maxRows < actual number of rows in the table', function(done) { + var id_1 = insertID++; + var specialStr_1 = '85.1.17_1'; + var contentLength_1 = 26; + var content_1 = random.getRandomString(contentLength_1, specialStr_1); + var id_2 = insertID++; + var specialStr_2 = '85.1.17_2'; + var contentLength_2 = 30; + var content_2 = random.getRandomString(contentLength_2, specialStr_2); + var maxRowsBak = oracledb.maxRows; + oracledb.maxRows = 1; + + async.series([ + function(cb) { + insertIntoClobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoClobTable1(id_2, content_2, cb); + }, + function(cb) { + var sql = "SELECT ID, C from nodb_clob1 WHERE ID = " + id_1 + " or id = " +id_2; + var stream = connection.queryStream(sql, {}, { fetchInfo : { C : { type : oracledb.STRING } } }); + stream.on('error', function (error) { + should.fail(error, null, 'Error event should not be triggered'); + }); + + var counter = 0; + stream.on('data', function(data) { + should.exist(data); + var result = data[1]; + should.strictEqual(typeof result, "string"); + counter++; + if(counter == 1) { + compareStrings(result, specialStr_1, content_1, contentLength_1); + } else { + compareStrings(result, specialStr_2, content_2, contentLength_2); + } + }); + + stream.on('end', function () { + should.equal(counter, 2); + oracledb.maxRows = maxRowsBak; + setTimeout(cb, 500); + }); + } + ], done); + }); // 85.1.17 + + }); // 85.1 + + describe('85.2 fetch CLOB columns by setting fetchInfo option and outFormat = oracledb.OBJECT', function() { + + before('Create table and populate', function(done) { + connection.execute( + proc_create_table1, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // before + + after('drop table', function(done) { + connection.execute( + drop_table1, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // after + + insertID = 0; + var insertAndFetch = function(id, specialStr, insertContent, insertContentLength, callback) { + async.series([ + function(cb) { + insertIntoClobTable1(id, insertContent, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, C from nodb_clob1 WHERE ID = :id", + { id : id }, + { + outFormat : oracledb.OBJECT, + fetchInfo : { C : { type : oracledb.STRING } } + }, + function(err, result) { + var resultVal = result.rows[0].C; + if(specialStr === null) { + should.not.exist(err); + should.equal(resultVal, null); + } else { + compareClientFetchResult(err, resultVal, specialStr, insertContent, insertContentLength); + } + cb(); + } + ); + } + ], callback); + }; + + it('85.2.1 works with NULL value', function(done) { + var id = insertID++; + var content = null; + + insertAndFetch(id, null, content, null, done); + }); // 85.2.1 + + it('85.2.2 works with empty buffer', function(done) { + var id = insertID++; + var content = ""; + + insertAndFetch(id, null, content, null, done); + }); // 85.2.2 + + it('85.2.3 works with small value', function(done) { + var id = insertID++; + var specialStr = '85.2.3'; + var contentLength = 20; + var content = random.getRandomString(contentLength, specialStr); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 85.2.3 + + it('85.2.4 works with (64K - 1) value', function(done) { + var id = insertID++; + var specialStr = '85.2.4'; + var contentLength = 65535; + var content = random.getRandomString(contentLength, specialStr); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 85.2.4 + + it('85.2.5 works with (64K + 1) value', function(done) { + var id = insertID++; + var specialStr = '85.2.5'; + var contentLength = 65537; + var content = random.getRandomString(contentLength, specialStr); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 85.2.5 + + it('85.2.6 works with (1MB + 1) value', function(done) { + var id = insertID++; + var specialStr = '85.2.6'; + var contentLength = 1048577; // 1MB + 1 + var content = random.getRandomString(contentLength, specialStr); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 85.2.6 + + it('85.2.7 works with dbms_lob.substr()', function(done) { + var id = insertID++; + var specialStr = '85.2.7'; + var contentLength = 200; + var specialStrLength = specialStr.length; + var content = random.getRandomString(contentLength, specialStr); + + async.series([ + function(cb) { + insertIntoClobTable1(id, content, cb); + }, + function(cb) { + connection.execute( + "SELECT dbms_lob.substr(C, " + specialStrLength + ", 1) AS C1 from nodb_clob1 WHERE ID = :id", + { id : id }, + { + outFormat : oracledb.OBJECT, + fetchInfo : { C1 : { type : oracledb.STRING } } + }, + function(err, result) { + should.not.exist(err); + var resultVal = result.rows[0].C1; + compareClientFetchResult(err, resultVal, specialStr, specialStr, specialStrLength); + cb(); + } + ); + } + ], done); + }); // 85.2.7 + + it('85.2.8 works with EMPTY_CLOB()', function(done) { + var id = insertID++; + var content = "EMPTY_CLOB"; + + insertAndFetch(id, null, content, null, done); + }); // 85.2.8 + + it('85.2.9 fetch multiple CLOB rows as String', function(done) { + var id_1 = insertID++; + var specialStr_1 = '85.2.9_1'; + var contentLength_1 = 200; + var content_1 = random.getRandomString(contentLength_1, specialStr_1); + var id_2 = insertID++; + var specialStr_2 = '85.2.9_2'; + var contentLength_2 = 100; + var content_2 = random.getRandomString(contentLength_2, specialStr_2); + + async.series([ + function(cb) { + insertIntoClobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoClobTable1(id_2, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, C from nodb_clob1 WHERE ID = " + id_1 + " or id = " + id_2, + { }, + { + outFormat : oracledb.OBJECT, + fetchInfo : { C : { type : oracledb.STRING } } + }, + function(err, result) { + should.not.exist(err); + var resultVal = result.rows[0].C; + compareClientFetchResult(err, resultVal, specialStr_1, content_1, contentLength_1); + resultVal = result.rows[1].C; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + cb(); + } + ); + } + ], done); + }); // 85.2.9 + + it('85.2.10 fetch the same CLOB column multiple times', function(done) { + var id = insertID++; + var specialStr = '85.2.10'; + var contentLength = 200; + var content = random.getRandomString(contentLength, specialStr); + + async.series([ + function(cb) { + insertIntoClobTable1(id, content, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, C AS C1, C AS C2 from nodb_clob1 WHERE ID = " + id, + { }, + { + outFormat : oracledb.OBJECT, + fetchInfo : { + C1 : { type : oracledb.STRING }, + C2 : { type : oracledb.STRING } } + }, + function(err, result) { + should.not.exist(err); + var resultVal = result.rows[0].C1; + compareClientFetchResult(err, resultVal, specialStr, content, contentLength); + resultVal = result.rows[0].C2; + compareClientFetchResult(err, resultVal, specialStr, content, contentLength); + cb(); + } + ); + } + ], done); + }); // 85.2.10 + + it('85.2.11 works with update statement', function(done) { + var id = insertID++; + var specialStr_1 = '85.2.11_1'; + var contentLength_1 = 200; + var content_1 = random.getRandomString(contentLength_1, specialStr_1); + var specialStr_2 = '85.2.11_2'; + var contentLength_2 = 202; + var content_2 = random.getRandomString(contentLength_2, specialStr_2); + + async.series([ + function(cb) { + insertAndFetch(id, specialStr_1, content_1, contentLength_1, cb); + }, + function(cb) { + updateClobTable1(id, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, C from nodb_clob1 WHERE ID = " + id, + { }, + { + outFormat : oracledb.OBJECT, + fetchInfo : { C : { type : oracledb.STRING } } + }, + function(err, result) { + should.not.exist(err); + var resultVal = result.rows[0].C; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + cb(); + } + ); + } + ], done); + }); // 85.2.11 + + it('85.2.12 works with setting oracledb.maxRows < actual number of rows in the table', function(done) { + var id_1 = insertID++; + var specialStr_1 = '85.2.12_1'; + var contentLength_1 = 200; + var content_1 = random.getRandomString(contentLength_1, specialStr_1); + var id_2 = insertID++; + var specialStr_2 = '85.2.12_2'; + var contentLength_2 = 100; + var content_2 = random.getRandomString(contentLength_2, specialStr_2); + var maxRowsBak = oracledb.maxRows; + oracledb.maxRows = 1; + + async.series([ + function(cb) { + insertIntoClobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoClobTable1(id_2, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, C from nodb_clob1 WHERE id = " + id_1 + " or id = " +id_2, + { }, + { + outFormat : oracledb.OBJECT, + fetchInfo : { C : { type : oracledb.STRING } } + }, + function(err, result) { + should.not.exist(err); + result.rows.length.should.eql(1); + var resultVal = result.rows[0].C; + compareClientFetchResult(err, resultVal, specialStr_1, content_1, contentLength_1); + oracledb.maxRows = maxRowsBak; + cb(); + } + ); + } + ], done); + }); // 85.2.12 + + it('85.2.13 works with setting oracledb.maxRows > actual number of rows in the table', function(done) { + var id_1 = insertID++; + var specialStr_1 = '85.2.13_1'; + var contentLength_1 = 200; + var content_1 = random.getRandomString(contentLength_1, specialStr_1); + var id_2 = insertID++; + var specialStr_2 = '85.2.13_2'; + var contentLength_2 = 100; + var content_2 = random.getRandomString(contentLength_2, specialStr_2); + var maxRowsBak = oracledb.maxRows; + oracledb.maxRows = 10; + + async.series([ + function(cb) { + insertIntoClobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoClobTable1(id_2, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, C from nodb_clob1 WHERE id = " + id_1 + " or id = " +id_2, + { }, + { + outFormat : oracledb.OBJECT, + fetchInfo : { C : { type : oracledb.STRING } } + }, + function(err, result) { + should.not.exist(err); + var resultVal = result.rows[0].C; + compareClientFetchResult(err, resultVal, specialStr_1, content_1, contentLength_1); + resultVal = result.rows[1].C; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + result.rows.length.should.eql(2); + oracledb.maxRows = maxRowsBak; + cb(); + } + ); + } + ], done); + }); // 85.2.13 + + }); // 85.2 + + describe('85.3 fetch CLOB columns by setting fetchInfo option, outFormat = oracledb.OBJECT and resultSet = true', function() { + + before('Create table and populate', function(done) { + connection.execute( + proc_create_table1, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // before + + after('drop table', function(done) { + connection.execute( + drop_table1, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // after + + insertID = 0; + var insertAndFetch = function(id, specialStr, insertContent, insertContentLength, callback) { + async.series([ + function(cb) { + insertIntoClobTable1(id, insertContent, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, C from nodb_clob1 WHERE ID = :id", + { id : id }, + { + outFormat : oracledb.OBJECT, + fetchInfo : { C : { type : oracledb.STRING } }, + resultSet : true + }, + function(err, result) { + should.not.exist(err); + result.resultSet.getRow( + function(err, row) { + var resultVal; + resultVal = row.C; + if(specialStr === null) { + should.not.exist(err); + should.equal(resultVal, null); + } else { + compareClientFetchResult(err, resultVal, specialStr, insertContent, insertContentLength, callback); + } + result.resultSet.close(function(err) { + should.not.exist(err); + cb(); + }); + } + ); + } + ); + } + ], callback); + }; + + it('85.3.1 works with NULL value', function(done) { + var id = insertID++; + var content = null; + + insertAndFetch(id, null, content, null, done); + }); // 85.3.1 + + it('85.3.2 works with empty buffer', function(done) { + var id = insertID++; + var content = ""; + + insertAndFetch(id, null, content, null, done); + }); // 85.3.2 + + it('85.3.3 works with small value', function(done) { + var id = insertID++; + var specialStr = '85.3.3'; + var contentLength = 20; + var content = random.getRandomString(contentLength, specialStr); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 85.3.3 + + it('85.3.4 works with (64K - 1) value', function(done) { + var id = insertID++; + var specialStr = '85.3.4'; + var contentLength = 65535; + var content = random.getRandomString(contentLength, specialStr); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 85.3.4 + + it('85.3.5 works with (64K + 1) value', function(done) { + var id = insertID++; + var specialStr = '85.3.4'; + var contentLength = 65537; + var content = random.getRandomString(contentLength, specialStr); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 85.3.5 + + it('85.3.6 works with (1MB + 1) value', function(done) { + var id = insertID++; + var specialStr = '85.3.6'; + var contentLength = 1048577; // 1MB + 1 + var content = random.getRandomString(contentLength, specialStr); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 85.3.6 + + it('85.3.7 works with dbms_lob.substr()', function(done) { + var id = insertID++; + var specialStr = '85.3.7'; + var contentLength = 200; + var specialStrLength = specialStr.length; + var content = random.getRandomString(contentLength, specialStr); + + async.series([ + function(cb) { + insertIntoClobTable1(id, content, cb); + }, + function(cb) { + connection.execute( + "SELECT dbms_lob.substr(C, " + specialStrLength + ", 1) AS C1 from nodb_clob1 WHERE ID = :id", + { id : id }, + { + outFormat : oracledb.OBJECT, + fetchInfo : { C1 : { type : oracledb.STRING } }, + resultSet : true + }, + function(err, result) { + should.not.exist(err); + result.resultSet.getRow( + function(err, row) { + should.not.exist(err); + var resultVal = row.C1; + compareClientFetchResult(err, resultVal, specialStr, specialStr, specialStrLength); + result.resultSet.close(function(err) { + should.not.exist(err); + cb(); + }); + } + ); + } + ); + } + ], done); + }); // 85.3.7 + + it('85.3.8 works with EMPTY_CLOB()', function(done) { + var id = insertID++; + var content = "EMPTY_CLOB"; + + insertAndFetch(id, null, content, null, done); + }); // 85.3.8 + + it('85.3.9 fetch multiple CLOB rows as String', function(done) { + var id_1 = insertID++; + var specialStr_1 = '85.3.9_1'; + var contentLength_1 = 200; + var content_1 = random.getRandomString(contentLength_1, specialStr_1); + var id_2 = insertID++; + var specialStr_2 = '85.3.9_2'; + var contentLength_2 = 100; + var content_2 = random.getRandomString(contentLength_2, specialStr_2); + + async.series([ + function(cb) { + insertIntoClobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoClobTable1(id_2, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, C from nodb_clob1 WHERE ID = " + id_1 + " or id = " + id_2, + { }, + { + outFormat : oracledb.OBJECT, + fetchInfo : { C : { type : oracledb.STRING } }, + resultSet : true + }, + function(err, result) { + should.not.exist(err); + var rowNumFetched = 2; + result.resultSet.getRows( + rowNumFetched, + function(err, row) { + should.not.exist(err); + var resultVal = row[0].C; + compareClientFetchResult(err, resultVal, specialStr_1, content_1, contentLength_1); + resultVal = row[1].C; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + result.resultSet.close(function(err) { + should.not.exist(err); + cb(); + }); + } + ); + } + ); + } + ], done); + }); // 85.3.9 + + it('85.3.10 fetch the same CLOB column multiple times', function(done) { + var id = insertID++; + var specialStr = '85.3.10'; + var contentLength = 200; + var content = random.getRandomString(contentLength, specialStr); + + async.series([ + function(cb) { + insertIntoClobTable1(id, content, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, C AS C1, C AS C2 from nodb_clob1 WHERE ID = " + id, + { }, + { + outFormat : oracledb.OBJECT, + fetchInfo : { + C1 : { type : oracledb.STRING }, + C2 : { type : oracledb.STRING } }, + resultSet : true + }, + function(err, result) { + should.not.exist(err); + result.resultSet.getRow( + function(err, row) { + should.not.exist(err); + var resultVal = row.C1; + compareClientFetchResult(err, resultVal, specialStr, content, contentLength); + resultVal = row.C2; + compareClientFetchResult(err, resultVal, specialStr, content, contentLength); + result.resultSet.close(function(err) { + should.not.exist(err); + cb(); + }); + } + ); + } + ); + } + ], done); + }); // 85.3.10 + + it('85.3.11 works with update statement', function(done) { + var id = insertID++; + var specialStr_1 = '85.3.11_1'; + var contentLength_1 = 200; + var content_1 = random.getRandomString(contentLength_1, specialStr_1); + var specialStr_2 = '85.3.11_2'; + var contentLength_2 = 202; + var content_2 = random.getRandomString(contentLength_2, specialStr_2); + + async.series([ + function(cb) { + insertAndFetch(id, specialStr_1, content_1, contentLength_1, cb); + }, + function(cb) { + updateClobTable1(id, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, C from nodb_clob1 WHERE ID = " + id, + { }, + { + outFormat : oracledb.OBJECT, + fetchInfo : { C : { type : oracledb.STRING } }, + resultSet : true + }, + function(err, result) { + should.not.exist(err); + result.resultSet.getRow( + function(err, row) { + should.not.exist(err); + var resultVal = row.C; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + result.resultSet.close(function(err) { + should.not.exist(err); + cb(); + }); + } + ); + } + ); + } + ], done); + }); // 85.3.11 + + it('85.3.12 works with setting oracledb.maxRows < actual number of rows in the table', function(done) { + var id_1 = insertID++; + var specialStr_1 = '85.3.12_1'; + var contentLength_1 = 200; + var content_1 = random.getRandomString(contentLength_1, specialStr_1); + var id_2 = insertID++; + var specialStr_2 = '85.3.12_2'; + var contentLength_2 = 100; + var content_2 = random.getRandomString(contentLength_2, specialStr_2); + var maxRowsBak = oracledb.maxRows; + oracledb.maxRows = 1; + + async.series([ + function(cb) { + insertIntoClobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoClobTable1(id_2, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, C from nodb_clob1 WHERE id = " + id_1 + " or id = " +id_2, + { }, + { + outFormat : oracledb.OBJECT, + fetchInfo : { C : { type : oracledb.STRING } }, + resultSet : true + }, + function(err, result) { + should.not.exist(err); + var rowNumFetched = 2; + result.resultSet.getRows( + rowNumFetched, + function(err, row) { + should.not.exist(err); + should.equal(row.length, 2); + var resultVal = row[0].C; + compareClientFetchResult(err, resultVal, specialStr_1, content_1, contentLength_1); + resultVal = row[1].C; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + oracledb.maxRows =maxRowsBak; + result.resultSet.close(function(err) { + should.not.exist(err); + cb(); + }); + } + ); + } + ); + } + ], done); + }); // 85.3.12 + + it('85.3.13 works with setting oracledb.maxRows > actual number of rows in the table', function(done) { + var id_1 = insertID++; + var specialStr_1 = '85.3.13_1'; + var contentLength_1 = 200; + var content_1 = random.getRandomString(contentLength_1, specialStr_1); + var id_2 = insertID++; + var specialStr_2 = '85.3.13_2'; + var contentLength_2 = 100; + var content_2 = random.getRandomString(contentLength_2, specialStr_2); + var maxRowsBak = oracledb.maxRows; + oracledb.maxRows = 10; + + async.series([ + function(cb) { + insertIntoClobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoClobTable1(id_2, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, C from nodb_clob1 WHERE id = " + id_1 + " or id = " +id_2, + { }, + { + outFormat : oracledb.OBJECT, + fetchInfo : { C : { type : oracledb.STRING } }, + resultSet : true + }, + function(err, result) { + should.not.exist(err); + var rowNumFetched = 2; + result.resultSet.getRows( + rowNumFetched, + function(err, row) { + should.not.exist(err); + should.equal(row.length, 2); + var resultVal = row[0].C; + compareClientFetchResult(err, resultVal, specialStr_1, content_1, contentLength_1); + resultVal = row[1].C; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + oracledb.maxRows =maxRowsBak; + result.resultSet.close(function(err) { + should.not.exist(err); + cb(); + }); + } + ); + } + ); + } + ], done); + }); // 85.3.13 + + }); // 85.3 + + describe('85.4 fetch CLOB columns by setting fetchInfo option and outFormat = oracledb.ARRAY', function() { + + before('Create table and populate', function(done) { + connection.execute( + proc_create_table1, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // before + + after('drop table', function(done) { + connection.execute( + drop_table1, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // after + + insertID = 0; + var insertAndFetch = function(id, specialStr, insertContent, insertContentLength, callback) { + async.series([ + function(cb) { + insertIntoClobTable1(id, insertContent, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, C from nodb_clob1 WHERE ID = :id", + { id : id }, + { + outFormat : oracledb.ARRAY, + fetchInfo : { C : { type : oracledb.STRING } } + }, + function(err, result) { + var resultVal = result.rows[0][1]; + if(specialStr === null) { + should.not.exist(err); + should.equal(resultVal, null); + } else { + compareClientFetchResult(err, resultVal, specialStr, insertContent, insertContentLength); + } + cb(); + } + ); + } + ], callback); + }; + + it('85.4.1 works with NULL value', function(done) { + var id = insertID++; + var content = null; + + insertAndFetch(id, null, content, null, done); + }); // 85.4.1 + + it('85.4.2 works with empty String', function(done) { + var id = insertID++; + var content = ""; + + insertAndFetch(id, null, content, null, done); + }); // 85.4.2 + + it('85.4.3 works with small value', function(done) { + var id = insertID++; + var specialStr = '85.4.3'; + var contentLength = 20; + var content = random.getRandomString(contentLength, specialStr); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 85.4.3 + + it('85.4.4 works with (64K - 1) value', function(done) { + var id = insertID++; + var specialStr = '85.4.4'; + var contentLength = 65535; + var content = random.getRandomString(contentLength, specialStr); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 85.4.4 + + it('85.4.5 works with (64K + 1) value', function(done) { + var id = insertID++; + var specialStr = '85.4.5'; + var contentLength = 65537; + var content = random.getRandomString(contentLength, specialStr); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 85.4.5 + + it('85.4.6 works with (1MB + 1) value', function(done) { + var id = insertID++; + var specialStr = '85.4.6'; + var contentLength = 1048577; // 1MB + 1 + var content = random.getRandomString(contentLength, specialStr); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 85.4.6 + + it('85.4.7 works with dbms_lob.substr()', function(done) { + var id = insertID++; + var specialStr = '85.4.7'; + var contentLength = 200; + var specialStrLength = specialStr.length; + var content = random.getRandomString(contentLength, specialStr); + + async.series([ + function(cb) { + insertIntoClobTable1(id, content, cb); + }, + function(cb) { + connection.execute( + "SELECT dbms_lob.substr(C, " + specialStrLength + ", 1) AS C1 from nodb_clob1 WHERE ID = :id", + { id : id }, + { + fetchInfo : { C1 : { type : oracledb.STRING } } + }, + function(err, result) { + should.not.exist(err); + // console.log(result); + var resultVal = result.rows[0][0]; + compareClientFetchResult(err, resultVal, specialStr, specialStr, specialStrLength); + cb(); + } + ); + } + ], done); + }); // 85.4.7 + + it('85.4.8 works with EMPTY_CLOB()', function(done) { + var id = insertID++; + var content = "EMPTY_CLOB"; + + insertAndFetch(id, null, content, null, done); + }); // 85.4.8 + + it('85.4.9 fetch multiple CLOB rows as String', function(done) { + var id_1 = insertID++; + var specialStr_1 = '85.4.9_1'; + var contentLength_1 = 200; + var content_1 = random.getRandomString(contentLength_1, specialStr_1); + var id_2 = insertID++; + var specialStr_2 = '85.4.9_2'; + var contentLength_2 = 100; + var content_2 = random.getRandomString(contentLength_2, specialStr_2); + + async.series([ + function(cb) { + insertIntoClobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoClobTable1(id_2, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, C from nodb_clob1 WHERE ID = " + id_1 + " or id = " + id_2, + { }, + { + outFormat : oracledb.ARRAY, + fetchInfo : { C : { type : oracledb.STRING } } + }, + function(err, result) { + should.not.exist(err); + var resultVal = result.rows[0][1]; + compareClientFetchResult(err, resultVal, specialStr_1, content_1, contentLength_1); + resultVal = result.rows[1][1]; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + cb(); + } + ); + } + ], done); + }); // 85.4.9 + + it('85.4.10 fetch the same CLOB column multiple times', function(done) { + var id = insertID++; + var specialStr = '85.4.10'; + var contentLength = 200; + var content = random.getRandomString(contentLength, specialStr); + + async.series([ + function(cb) { + insertIntoClobTable1(id, content, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, C AS C1, C AS C2 from nodb_clob1 WHERE ID = " + id, + { }, + { + fetchInfo : { + C1 : { type : oracledb.STRING }, + C2 : { type : oracledb.STRING } } + }, + function(err, result) { + should.not.exist(err); + var resultVal = result.rows[0][1]; + compareClientFetchResult(err, resultVal, specialStr, content, contentLength); + resultVal = result.rows[0][2]; + compareClientFetchResult(err, resultVal, specialStr, content, contentLength); + cb(); + } + ); + } + ], done); + }); // 85.4.10 + + it('85.4.11 works with update statement', function(done) { + var id = insertID++; + var specialStr_1 = '85.4.11_1'; + var contentLength_1 = 200; + var content_1 = random.getRandomString(contentLength_1, specialStr_1); + var specialStr_2 = '85.4.11_2'; + var contentLength_2 = 208; + var content_2 = random.getRandomString(contentLength_2, specialStr_2); + + async.series([ + function(cb) { + insertAndFetch(id, specialStr_1, content_1, contentLength_1, cb); + }, + function(cb) { + updateClobTable1(id, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, C from nodb_clob1 WHERE ID = " + id, + { }, + { + outFormat : oracledb.ARRAY, + fetchInfo : { C : { type : oracledb.STRING } } + }, + function(err, result) { + should.not.exist(err); + var resultVal = result.rows[0][1]; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + cb(); + } + ); + } + ], done); + }); // 85.4.8 + + it('85.4.12 works with setting oracledb.maxRows < actual number of rows in the table', function(done) { + var id_1 = insertID++; + var specialStr_1 = '85.4.12_1'; + var contentLength_1 = 200; + var content_1 = random.getRandomString(contentLength_1, specialStr_1); + var id_2 = insertID++; + var specialStr_2 = '85.4.12_2'; + var contentLength_2 = 100; + var content_2 = random.getRandomString(contentLength_2, specialStr_2); + var maxRowsBak = oracledb.maxRows; + oracledb.maxRows = 1; + + async.series([ + function(cb) { + insertIntoClobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoClobTable1(id_2, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, C from nodb_clob1 WHERE id = " + id_1 + " or id = " +id_2, + { }, + { + outFormat : oracledb.ARRAY, + fetchInfo : { C : { type : oracledb.STRING } } + }, + function(err, result) { + should.not.exist(err); + result.rows.length.should.eql(1); + var resultVal = result.rows[0][1]; + compareClientFetchResult(err, resultVal, specialStr_1, content_1, contentLength_1); + oracledb.maxRows = maxRowsBak; + cb(); + } + ); + } + ], done); + }); // 85.4.12 + + it('85.4.13 works with setting oracledb.maxRows > actual number of rows in the table', function(done) { + var id_1 = insertID++; + var specialStr_1 = '85.4.13_1'; + var contentLength_1 = 200; + var content_1 = random.getRandomString(contentLength_1, specialStr_1); + var id_2 = insertID++; + var specialStr_2 = '85.4.13_2'; + var contentLength_2 = 100; + var content_2 = random.getRandomString(contentLength_2, specialStr_2); + var maxRowsBak = oracledb.maxRows; + oracledb.maxRows = 10; + + async.series([ + function(cb) { + insertIntoClobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoClobTable1(id_2, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, C from nodb_clob1 WHERE id = " + id_1 + " or id = " +id_2, + { }, + { + outFormat : oracledb.ARRAY, + fetchInfo : { C : { type : oracledb.STRING } } + }, + function(err, result) { + should.not.exist(err); + result.rows.length.should.eql(2); + var resultVal = result.rows[0][1]; + compareClientFetchResult(err, resultVal, specialStr_1, content_1, contentLength_1); + resultVal = result.rows[1][1]; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + oracledb.maxRows = maxRowsBak; + cb(); + } + ); + } + ], done); + }); // 85.4.13 + + }); // 85.4 + + describe('85.5 fetch CLOB columns by setting fetchInfo option, outFormat = oracledb.ARRAY and resultSet = true', function() { + + before('Create table and populate', function(done) { + connection.execute( + proc_create_table1, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // before + + after('drop table', function(done) { + connection.execute( + drop_table1, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // after + + insertID = 0; + var insertAndFetch = function(id, specialStr, insertContent, insertContentLength, callback) { + async.series([ + function(cb) { + insertIntoClobTable1(id, insertContent, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, C from nodb_clob1 WHERE ID = :id", + { id : id }, + { + outFormat : oracledb.ARRAY, + fetchInfo : { C : { type : oracledb.STRING } }, + resultSet : true + }, + function(err, result) { + should.not.exist(err); + result.resultSet.getRow( + function(err, row) { + var resultVal; + resultVal = row[1]; + if(specialStr === null) { + should.not.exist(err); + should.equal(resultVal, null); + } else { + compareClientFetchResult(err, resultVal, specialStr, insertContent, insertContentLength); + } + result.resultSet.close(function(err) { + should.not.exist(err); + cb(); + }); + } + ); + } + ); + } + ], callback); + }; + + it('85.5.1 works with NULL value', function(done) { + var id = insertID++; + var content = null; + + insertAndFetch(id, null, content, null, done); + }); // 85.5.1 + + it('85.5.2 works with empty String', function(done) { + var id = insertID++; + var content = ""; + + insertAndFetch(id, null, content, null, done); + }); // 85.5.2 + + it('85.5.3 works with small value', function(done) { + var id = insertID++; + var specialStr = '85.5.3'; + var contentLength = 20; + var content = random.getRandomString(contentLength, specialStr); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 85.5.3 + + it('85.5.4 works with (64K - 1) value', function(done) { + var id = insertID++; + var specialStr = '85.5.4'; + var contentLength = 65535; + var content = random.getRandomString(contentLength, specialStr); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 85.5.4 + + it('85.5.5 works with (64K + 1) value', function(done) { + var id = insertID++; + var specialStr = '85.5.5'; + var contentLength = 65537; + var content = random.getRandomString(contentLength, specialStr); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 85.5.5 + + it('85.5.6 works with (1MB + 1) value', function(done) { + var id = insertID++; + var specialStr = '85.5.6'; + var contentLength = 1048577; // 1MB + 1 + var content = random.getRandomString(contentLength, specialStr); + + insertAndFetch(id, specialStr, content, contentLength, done); + }); // 85.5.6 + + it('85.5.7 works with dbms_lob.substr()', function(done) { + var id = insertID++; + var specialStr = '85.5.7'; + var contentLength = 200; + var specialStrLength = specialStr.length; + var content = random.getRandomString(contentLength, specialStr); + + async.series([ + function(cb) { + insertIntoClobTable1(id, content, cb); + }, + function(cb) { + connection.execute( + "SELECT dbms_lob.substr(C, " + specialStrLength + ", 1) AS C1 from nodb_clob1 WHERE ID = :id", + { id : id }, + { + outFormat : oracledb.ARRAY, + fetchInfo : { C1 : { type : oracledb.STRING } }, + resultSet : true + }, + function(err, result) { + should.not.exist(err); + result.resultSet.getRow( + function(err, row) { + should.not.exist(err); + var resultVal = row[0]; + compareClientFetchResult(err, resultVal, specialStr, specialStr, specialStrLength); + result.resultSet.close(function(err) { + should.not.exist(err); + cb(); + }); + } + ); + } + ); + } + ], done); + }); // 85.5.7 + + it('85.5.8 works with EMPTY_CLOB()', function(done) { + var id = insertID++; + var content = "EMPTY_CLOB"; + + insertAndFetch(id, null, content, null, done); + }); // 85.5.8 + + it('85.5.9 fetch multiple CLOB rows as String', function(done) { + var id_1 = insertID++; + var specialStr_1 = '85.5.9_1'; + var contentLength_1 = 200; + var content_1 = random.getRandomString(contentLength_1, specialStr_1); + var id_2 = insertID++; + var specialStr_2 = '85.5.9_2'; + var contentLength_2 = 100; + var content_2 = random.getRandomString(contentLength_2, specialStr_2); + + async.series([ + function(cb) { + insertIntoClobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoClobTable1(id_2, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, C from nodb_clob1 WHERE ID = " + id_1 + " or id = " + id_2, + { }, + { + outFormat : oracledb.ARRAY, + fetchInfo : { C : { type : oracledb.STRING } }, + resultSet : true + }, + function(err, result) { + should.not.exist(err); + var rowNumFetched = 2; + result.resultSet.getRows( + rowNumFetched, + function(err, row) { + should.not.exist(err); + should.strictEqual(row.length, 2); + var resultVal = row[0][1]; + compareClientFetchResult(err, resultVal, specialStr_1, content_1, contentLength_1); + resultVal = row[1][1]; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + result.resultSet.close(function(err) { + should.not.exist(err); + cb(); + }); + } + ); + } + ); + } + ], done); + }); // 85.5.9 + + it('85.5.10 fetch the same CLOB column multiple times', function(done) { + var id = insertID++; + var specialStr = '85.5.10'; + var contentLength = 200; + var content = random.getRandomString(contentLength, specialStr); + + async.series([ + function(cb) { + insertIntoClobTable1(id, content, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, C AS C1, C AS C2 from nodb_clob1 WHERE ID = " + id, + { }, + { + outFormat : oracledb.ARRAY, + fetchInfo : { + C1 : { type : oracledb.STRING }, + C2 : { type : oracledb.STRING } }, + resultSet : true + }, + function(err, result) { + should.not.exist(err); + result.resultSet.getRow( + function(err, row) { + should.not.exist(err); + var resultVal = row[1]; + compareClientFetchResult(err, resultVal, specialStr, content, contentLength); + resultVal = row[2]; + compareClientFetchResult(err, resultVal, specialStr, content, contentLength); + result.resultSet.close(function(err) { + should.not.exist(err); + cb(); + }); + } + ); + } + ); + } + ], done); + }); // 85.5.10 + + it('85.5.11 works with update statement', function(done) { + var id = insertID++; + var specialStr_1 = '85.5.11_1'; + var contentLength_1 = 200; + var content_1 = random.getRandomString(contentLength_1, specialStr_1); + var specialStr_2 = '85.5.11_2'; + var contentLength_2 = 208; + var content_2 = random.getRandomString(contentLength_2, specialStr_2); + + async.series([ + function(cb) { + insertAndFetch(id, specialStr_1, content_1, contentLength_1, cb); + }, + function(cb) { + updateClobTable1(id, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, C from nodb_clob1 WHERE ID = " + id, + { }, + { + outFormat : oracledb.ARRAY, + fetchInfo : { C : { type : oracledb.STRING } }, + resultSet : true + }, + function(err, result) { + should.not.exist(err); + result.resultSet.getRow( + function(err, row) { + should.not.exist(err); + var resultVal = row[1]; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + result.resultSet.close(function(err) { + should.not.exist(err); + cb(); + }); + } + ); + } + ); + } + ], done); + }); // 85.5.11 + + it('85.5.12 works with setting oracledb.maxRows < actual number of rows in the table', function(done) { + var id_1 = insertID++; + var specialStr_1 = '85.5.12_1'; + var contentLength_1 = 200; + var content_1 = random.getRandomString(contentLength_1, specialStr_1); + var id_2 = insertID++; + var specialStr_2 = '85.5.12_2'; + var contentLength_2 = 100; + var content_2 = random.getRandomString(contentLength_2, specialStr_2); + var maxRowsBak = oracledb.maxRows; + oracledb.maxRows = 1; + + async.series([ + function(cb) { + insertIntoClobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoClobTable1(id_2, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, C from nodb_clob1 WHERE id = " + id_1 + " or id = " +id_2, + { }, + { + outFormat : oracledb.ARRAY, + fetchInfo : { C : { type : oracledb.STRING } }, + resultSet : true + }, + function(err, result) { + should.not.exist(err); + var rowNumFetched = 2; + result.resultSet.getRows( + rowNumFetched, + function(err, row) { + should.not.exist(err); + should.strictEqual(row.length, 2); + var resultVal = row[0][1]; + compareClientFetchResult(err, resultVal, specialStr_1, content_1, contentLength_1); + resultVal = row[1][1]; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + oracledb.maxRows =maxRowsBak; + result.resultSet.close(function(err) { + should.not.exist(err); + cb(); + }); + } + ); + } + ); + } + ], done); + }); // 85.5.12 + + it('85.5.13 works with setting oracledb.maxRows > actual number of rows in the table', function(done) { + var id_1 = insertID++; + var specialStr_1 = '85.5.13_1'; + var contentLength_1 = 200; + var content_1 = random.getRandomString(contentLength_1, specialStr_1); + var id_2 = insertID++; + var specialStr_2 = '85.5.13_2'; + var contentLength_2 = 100; + var content_2 = random.getRandomString(contentLength_2, specialStr_2); + var maxRowsBak = oracledb.maxRows; + oracledb.maxRows = 10; + + async.series([ + function(cb) { + insertIntoClobTable1(id_1, content_1, cb); + }, + function(cb) { + insertIntoClobTable1(id_2, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, C from nodb_clob1 WHERE id = " + id_1 + " or id = " +id_2, + { }, + { + outFormat : oracledb.ARRAY, + fetchInfo : { C : { type : oracledb.STRING } }, + resultSet : true + }, + function(err, result) { + should.not.exist(err); + var rowNumFetched = 2; + result.resultSet.getRows( + rowNumFetched, + function(err, row) { + should.not.exist(err); + should.strictEqual(row.length, 2); + var resultVal = row[0][1]; + compareClientFetchResult(err, resultVal, specialStr_1, content_1, contentLength_1); + resultVal = row[1][1]; + compareClientFetchResult(err, resultVal, specialStr_2, content_2, contentLength_2); + oracledb.maxRows =maxRowsBak; + result.resultSet.close(function(err) { + should.not.exist(err); + cb(); + }); + } + ); + } + ); + } + ], done); + }); // 85.5.13 + + }); // 85.5 +}); diff --git a/test/fetchClobAsString3.js b/test/fetchClobAsString3.js new file mode 100644 index 00000000..ab0b0ed1 --- /dev/null +++ b/test/fetchClobAsString3.js @@ -0,0 +1,318 @@ +/* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with the Apache + * License, Version 2.0 (the "License.") + * + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + * The node-oracledb test suite uses 'mocha', 'should' and 'async'. + * See LICENSE.md for relevant licenses. + * + * NAME + * 86. fetchClobAsString.js + * + * DESCRIPTION + * Testing Oracle data type support - CLOB. + * To fetch CLOB columns as strings + * This could be very useful for smaller CLOB size as it can be fetched as string and processed in memory itself. + * + * NUMBERING RULE + * Test numbers follow this numbering rule: + * 1 - 20 are reserved for basic functional tests + * 21 - 50 are reserved for data type supporting tests + * 51 onwards are for other tests + * + *****************************************************************************/ +'use strict'; + +var oracledb = require('oracledb'); +var async = require('async'); +var should = require('should'); +var dbConfig = require('./dbconfig.js'); +var random = require('./random.js'); + +describe('86. fetchClobAsString3.js', function() { + this.timeout(100000); + var connection = null; + var insertID = 1; // assume id for insert into db starts from 1 + var proc_create_table2 = "BEGIN \n" + + " DECLARE \n" + + " e_table_missing EXCEPTION; \n" + + " PRAGMA EXCEPTION_INIT(e_table_missing, -00942); \n" + + " BEGIN \n" + + " EXECUTE IMMEDIATE('DROP TABLE nodb_clob2 PURGE'); \n" + + " EXCEPTION \n" + + " WHEN e_table_missing \n" + + " THEN NULL; \n" + + " END; \n" + + " EXECUTE IMMEDIATE (' \n" + + " CREATE TABLE nodb_clob2 ( \n" + + " ID NUMBER, \n" + + " C1 CLOB, \n" + + " C2 CLOB \n" + + " ) \n" + + " '); \n" + + "END; "; + var drop_table2 = "DROP TABLE nodb_clob2 PURGE"; + + before('get one connection', function(done) { + oracledb.stmtCacheSize = 0; + oracledb.getConnection(dbConfig, function(err, conn) { + should.not.exist(err); + connection = conn; + done(); + }); + }); // before + + after('release connection', function(done) { + connection.release(function(err) { + should.not.exist(err); + done(); + }); + }); // after + + var insertIntoClobTable2 = function(id, content1, content2, callback) { + connection.execute( + "INSERT INTO nodb_clob2 VALUES (:ID, :C1, :C2)", + [ id, content1, content2 ], + function(err, result){ + should.not.exist(err); + should.strictEqual(result.rowsAffected, 1); + callback(); + } + ); + }; + + describe('86.1 fetch multiple CLOBs', function() { + before('create Table and populate', function(done) { + connection.execute( + proc_create_table2, + function(err){ + should.not.exist(err); + done() ; + } + ); + }); // before + + after('drop table', function(done) { + oracledb.fetchAsString = []; + connection.execute( + drop_table2, + function(err){ + should.not.exist(err); + done(); + } + ); + }); // after + + beforeEach('set oracledb.fetchAsString', function(done) { + oracledb.fetchAsString = [ oracledb.CLOB ]; + done(); + }); // beforeEach + + afterEach('clear the By type specification', function(done) { + oracledb.fetchAsString = []; + done(); + }); // afterEach + + it('86.1.1 fetch multiple CLOB columns as String', function(done) { + var id = insertID++; + var specialStr_1 = '86.1.1_1'; + var contentLength_1 = 26; + var content_1 = random.getRandomString(contentLength_1, specialStr_1); + var specialStr_2 = '86.1.1_2'; + var contentLength_2 = 100; + var content_2 = random.getRandomString(contentLength_2, specialStr_2); + + async.series([ + function(cb) { + insertIntoClobTable2(id, content_1, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, C1, C2 from nodb_clob2", + function(err, result){ + should.not.exist(err); + var specialStrLen_1 = specialStr_1.length; + var resultLen_1 = result.rows[0][1].length; + should.equal(result.rows[0][1].length, contentLength_1); + should.strictEqual(result.rows[0][1].substring(0, specialStrLen_1), specialStr_1); + should.strictEqual(result.rows[0][1].substring(resultLen_1 - specialStrLen_1, resultLen_1), specialStr_1); + + var specialStrLen_2 = specialStr_2.length; + var resultLen_2 = result.rows[0][2].length; + should.equal(result.rows[0][2].length, contentLength_2); + should.strictEqual(result.rows[0][2].substring(0, specialStrLen_2), specialStr_2); + should.strictEqual(result.rows[0][2].substring(resultLen_2 - specialStrLen_2, resultLen_2), specialStr_2); + cb(); + } + ); + } + ], done); + + }); // 86.1.1 + + it('86.1.2 fetch two CLOB columns, one as string, another streamed', function(done) { + var id = insertID++; + var specialStr_1 = '86.1.2_1'; + var contentLength_1 = 30; + var content_1 = random.getRandomString(contentLength_1, specialStr_1); + var specialStr_2 = '86.1.2_2'; + var contentLength_2 = 50; + var content_2 = random.getRandomString(contentLength_2, specialStr_2); + + async.series([ + function(cb) { + insertIntoClobTable2(id, content_1, content_2, cb); + }, + function(cb) { + connection.execute( + "SELECT ID, C1 from nodb_clob2 where ID = :id", + { id: id }, + function(err, result){ + should.not.exist(err); + var specialStrLen_1 = specialStr_1.length; + var resultLen_1 = result.rows[0][1].length; + should.equal(result.rows[0][1].length, contentLength_1); + should.strictEqual(result.rows[0][1].substring(0, specialStrLen_1), specialStr_1); + should.strictEqual(result.rows[0][1].substring(resultLen_1 - specialStrLen_1, resultLen_1), specialStr_1); + cb(); + } + ); + }, + function(cb) { + oracledb.fetchAsString = []; + + connection.execute( + "SELECT C2 from nodb_clob2 where ID = :id", + { id: id }, + function(err, result){ + should.not.exist(err); + (result.rows.length).should.not.eql(0); + var lob = result.rows[0][0]; + should.exist(lob); + + // set the encoding so we get a 'string' not a 'String' + lob.setEncoding('utf8'); + var clobData = ''; + + lob.on('data', function(chunk) { + clobData += chunk; + }); + + lob.on('error', function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + lob.on('end', function() { + should.not.exist(err); + var specialStrLen_2 = specialStr_2.length; + var resultLen_2 = clobData.length; + should.equal(clobData.length, contentLength_2); + should.strictEqual(clobData.substring(0, specialStrLen_2), specialStr_2); + should.strictEqual(clobData.substring(resultLen_2 - specialStrLen_2, resultLen_2), specialStr_2); + + cb(); + }); + } + ); + } + ], done); + + }); // 86.1.2 + + }); // 86.1 + + describe('86.2 types support for fetchAsString property', function() { + + afterEach ('clear the by-type specification', function ( done ) { + oracledb.fetchAsString = []; + done (); + }); + + it('86.2.1 String not supported in fetchAsString', function(done) { + should.throws( + function() { + oracledb.fetchAsString = [ oracledb.STRING ]; + }, + /NJS-021: invalid type for conversion specified/ + ); + done(); + }); // 86.2.1 + + it('86.2.2 BLOB not supported in fetchAsString', function(done) { + should.throws( + function() { + oracledb.fetchAsString = [ oracledb.BLOB ]; + }, + /NJS-021: invalid type for conversion specified/ + ); + done(); + }); // 86.2.2 + + it('86.2.3 Cursor not supported in fetchAsString', function(done) { + should.throws( + function() { + oracledb.fetchAsString = [ oracledb.CURSOR ]; + }, + /NJS-021: invalid type for conversion specified/ + ); + done(); + }); // 86.2.3 + + it('86.2.4 Buffer not supported in fetchAsString', function(done) { + should.throws( + function() { + oracledb.fetchAsString = [ oracledb.Buffer ]; + }, + /NJS-021: invalid type for conversion specified/ + ); + done(); + }); // 86.2.4 + + it('86.2.5 Number supported in fetchAsString', function(done) { + should.doesNotThrow( + function() { + oracledb.fetchAsString = [ oracledb.NUMBER ]; + } + ); + should.strictEqual(oracledb.fetchAsString.length, 1); + should.strictEqual(oracledb.fetchAsString[0], oracledb.NUMBER); + done(); + }); // 86.2.5 + + it('86.2.6 Date supported in fetchAsString', function(done) { + should.doesNotThrow( + function() { + oracledb.fetchAsString = [ oracledb.DATE ]; + } + ); + should.strictEqual(oracledb.fetchAsString.length, 1); + should.strictEqual(oracledb.fetchAsString[0], oracledb.DATE); + done(); + }); // 86.2.6 + + it('86.2.7 CLOB supported in fetchAsString', function(done) { + should.doesNotThrow( + function() { + oracledb.fetchAsString = [ oracledb.CLOB ]; + } + ); + should.strictEqual(oracledb.fetchAsString.length, 1); + should.strictEqual(oracledb.fetchAsString[0], oracledb.CLOB); + done(); + }); // 86.2.7 + + }); // 86.2 + +}); diff --git a/test/file.js b/test/file.js new file mode 100644 index 00000000..b9dbfa33 --- /dev/null +++ b/test/file.js @@ -0,0 +1,50 @@ +/* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with the Apache + * License, Version 2.0 (the "License.") + * + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + * The node-oracledb test suite uses 'mocha', 'should' and 'async'. + * See LICENSE.md for relevant licenses. + * + * NAME + * file.js + * + * DESCRIPTION + * file manipulate + *****************************************************************************/ +'use strict'; +var should = require('should'); +var fs = require('fs'); + +var file = exports; +module.exports = file; + +file.create = function(filePath) { + fs.closeSync(fs.openSync(filePath, 'w')); +}; + +file.write = function(filePath, content) { + var stream = fs.createWriteStream(filePath, { flags: 'w', defaultEncoding: 'utf8', autoClose: true }); + stream.write(content); + stream.end(); +}; + +file.delete = function(filePath) { + if(fs.existsSync(filePath) === true) { + fs.unlink(filePath, function(err) { + should.not.exist(err); + }); + } +}; diff --git a/test/lobBind1.js b/test/lobBind1.js new file mode 100644 index 00000000..3c6454c4 --- /dev/null +++ b/test/lobBind1.js @@ -0,0 +1,1593 @@ +/* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with the Apache + * License, Version 2.0 (the "License.") + * + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + * The node-oracledb test suite uses 'mocha', 'should' and 'async'. + * See LICENSE.md for relevant licenses. + * + * NAME + * 71. lobBind1.js + * + * DESCRIPTION + * Testing binding LOB data. + * + * NUMBERING RULE + * Test numbers follow this numbering rule: + * 1 - 20 are reserved for basic functional tests + * 21 - 50 are reserved for data type supporting tests + * 51 onwards are for other tests + * + *****************************************************************************/ +'use strict'; + +var oracledb = require('oracledb'); +var fs = require('fs'); +var should = require('should'); +var async = require('async'); +var dbConfig = require('./dbconfig.js'); +var assist = require('./dataTypeAssist.js'); + +describe('71. lobBind1.js', function() { + + var connection = null; + var node6plus = false; // assume node runtime version is lower than 6 + + before(function(done) { + oracledb.getConnection(dbConfig, function(err, conn) { + should.not.exist(err); + connection = conn; + + // Check whether node runtime version is >= 6 or not + if ( process.versions["node"].substring (0, 1) >= "6") + node6plus = true; + + done(); + }); + }); // before + + after(function(done) { + connection.release(function(err) { + should.not.exist(err); + done(); + }); + }); // after + + var executeSQL = function(sql, callback) { + connection.execute( + sql, + function(err) { + should.not.exist(err); + callback(); + } + ); + }; + + describe('71.1 persistent CLOB', function() { + + before('create the tables', function(done) { + + var proc1 ="BEGIN \n" + + " DECLARE \n" + + " e_table_missing EXCEPTION; \n" + + " PRAGMA EXCEPTION_INIT(e_table_missing, -00942); \n" + + " BEGIN \n" + + " EXECUTE IMMEDIATE('DROP TABLE nodb_tab_clob1 PURGE'); \n" + + " EXCEPTION \n" + + " WHEN e_table_missing \n" + + " THEN NULL; \n" + + " END; \n" + + " EXECUTE IMMEDIATE (' \n" + + " CREATE TABLE nodb_tab_clob1 ( \n" + + " id NUMBER, \n" + + " content CLOB \n" + + " ) \n" + + " '); \n" + + "END; "; + + var proc2 ="BEGIN \n" + + " DECLARE \n" + + " e_table_missing EXCEPTION; \n" + + " PRAGMA EXCEPTION_INIT(e_table_missing, -00942); \n" + + " BEGIN \n" + + " EXECUTE IMMEDIATE('DROP TABLE nodb_tab_clob2 PURGE'); \n" + + " EXCEPTION \n" + + " WHEN e_table_missing \n" + + " THEN NULL; \n" + + " END; \n" + + " EXECUTE IMMEDIATE (' \n" + + " CREATE TABLE nodb_tab_clob2 ( \n" + + " id NUMBER, \n" + + " content CLOB \n" + + " ) \n" + + " '); \n" + + "END; "; + + async.series([ + function(cb) { + executeSQL(proc1, cb); + }, + function(cb) { + executeSQL(proc2, cb); + } + ], done); + + }); // before + + after(function(done) { + + async.series([ + function(cb) { + var sql = "DROP TABLE nodb_tab_clob1 PURGE"; + executeSQL(sql, cb); + }, + function(cb) { + var sql = "DROP TABLE nodb_tab_clob2 PURGE"; + executeSQL(sql, cb); + } + ], done); + + }); // after + + var inFileName = './test/clobexample.txt'; + + var prepareTableWithClob = function(sequence, callback) { + + var sql = "INSERT INTO nodb_tab_clob1 (id, content) " + + "VALUES (:i, EMPTY_CLOB()) RETURNING content " + + "INTO :lobbv"; + var bindVar = { i: sequence, lobbv: { type: oracledb.CLOB, dir: oracledb.BIND_OUT } }; + + connection.execute( + sql, + bindVar, + { autoCommit: false }, // a transaction needs to span the INSERT and pipe() + function(err, result) { + should.not.exist(err); + (result.rowsAffected).should.be.exactly(1); + (result.outBinds.lobbv.length).should.be.exactly(1); + + var inStream = fs.createReadStream(inFileName); + var lob = result.outBinds.lobbv[0]; + + lob.on('error', function(err) { + should.not.exist(err, "lob.on 'error' event"); + }); + + inStream.on('error', function(err) { + should.not.exist(err, "inStream.on 'error' event"); + }); + + lob.on('close', function() { + + connection.commit( function(err) { + should.not.exist(err); + + return callback(); + }); + }); + + inStream.pipe(lob); // copies the text to the CLOB + } + ); + + }; + + var verifyClobValue = function(sequence, callback) { + + var sql = "SELECT content FROM nodb_tab_clob2 WHERE id = :id"; + + connection.execute( + sql, + { id: sequence }, + function(err, result) { + should.not.exist(err); + + if (sequence == 2) { + (result.rows).should.eql([[null]]); + return callback(); + } + + var lob = result.rows[0][0]; + should.exist(lob); + + // set the encoding so we get a 'string' not a 'buffer' + lob.setEncoding('utf8'); + var clobData = ''; + + lob.on('data', function(chunk) { + clobData += chunk; + }); + + lob.on('error', function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + lob.on('end', function() { + + if (sequence == 1) { + + should.strictEqual(clobData, 'some CLOB data'); + return callback(); + + } else { + + fs.readFile( inFileName, { encoding: 'utf8' }, function(err, originalData) { + should.not.exist(err); + + should.strictEqual(clobData, originalData); + return callback(); + }); + } + + }); + + } + ); + + }; // verifyClobValue + + it('71.1.1 BIND_IN, DML, a String variable', function(done) { + + var seq = 1; + var lobData = "some CLOB data"; + + async.series([ + function(cb) { + var sql = "INSERT INTO nodb_tab_clob1 VALUES(:i, :d)"; + var bindVar = { + i: { val: seq, dir: oracledb.BIND_IN, type: oracledb.NUMBER }, + d: { val: lobData, dir: oracledb.BIND_IN, type: oracledb.STRING } + }; + + connection.execute( + sql, + bindVar, + { autoCommit: true }, + function(err, result) { + should.not.exist(err); + should.strictEqual(result.rowsAffected, 1); + cb(); + } + ); + }, + function bindCLOB(cb) { + var sql1 = "SELECT content FROM nodb_tab_clob1 WHERE id = :id"; + var sql2 = "INSERT INTO nodb_tab_clob2 (id, content) VALUES (:i, :c)"; + + connection.execute( + sql1, + { id: seq }, + function(err, result) { + should.not.exist(err); + (result.rows.length).should.not.eql(0); + + var lob = result.rows[0][0]; + + connection.execute( + sql2, + { + i: seq, + c: { val: lob, type: oracledb.CLOB, dir: oracledb.BIND_IN } + }, + { autoCommit: true }, + function(err) { + should.not.exist(err); + // console.log(result2); + cb(); + } + ); + } + ); + }, + function(cb) { + + verifyClobValue(seq, cb); + + } + ], done); + + }); // 71.1.1 + + it('71.1.2 BIND_IN, DML, null', function(done) { + + var seq = 2; + var lobData = null; + + async.series([ + function(cb) { + var sql = "INSERT INTO nodb_tab_clob1 VALUES(:i, :d)"; + var bindVar = { + i: { val: seq, dir: oracledb.BIND_IN, type: oracledb.NUMBER }, + d: { val: lobData, dir: oracledb.BIND_IN, type: oracledb.STRING } + }; + + connection.execute( + sql, + bindVar, + { autoCommit: true }, + function(err, result) { + should.not.exist(err); + should.strictEqual(result.rowsAffected, 1); + cb(); + } + ); + }, + function(cb) { + var sql1 = "SELECT content FROM nodb_tab_clob1 WHERE id = :id"; + var sql2 = "INSERT INTO nodb_tab_clob2 (id, content) VALUES (:i, :c)"; + + connection.execute( + sql1, + { id: seq }, + function(err, result) { + should.not.exist(err); + (result.rows.length).should.not.eql(0); + + var lob = result.rows[0][0]; + + connection.execute( + sql2, + { + i: seq, + c: { val: lob, type: oracledb.CLOB, dir: oracledb.BIND_IN } + }, + { autoCommit: true }, + function(err) { + should.not.exist(err); + // console.log(result2); + cb(); + } + ); + } + ); + }, + function(cb) { + + verifyClobValue(seq, cb); + + } + ], done); + + }); // 71.1.2 + + it('71.1.3 BIND_IN, DML, a txt file', function(done) { + + var seq = 3; + + async.series([ + function(cb) { + + prepareTableWithClob(seq, cb); + + }, + function bindCLOB(cb) { + var sql1 = "SELECT content FROM nodb_tab_clob1 WHERE id = :id"; + var sql2 = "INSERT INTO nodb_tab_clob2 (id, content) VALUES (:i, :c)"; + + connection.execute( + sql1, + { id: seq }, + function(err, result) { + should.not.exist(err); + (result.rows.length).should.not.eql(0); + + var lob = result.rows[0][0]; + + connection.execute( + sql2, + { + i: seq, + c: { val: lob, type: oracledb.CLOB, dir: oracledb.BIND_IN } + }, + { autoCommit: true }, + function(err) { + should.not.exist(err); + return cb(); + } + ); + } + ); + }, + function verify(cb) { + + verifyClobValue(seq, cb); + + } + ], done); + + }); // 71.1.3 + + it('71.1.4 BIND_IN, PL/SQL, a txt file', function(done) { + + var seq = 4; + var proc = "CREATE OR REPLACE PROCEDURE nodb_clobinproc1 (p_num IN NUMBER, p_lob IN CLOB) \n" + + "AS \n" + + "BEGIN \n" + + " insert into nodb_tab_clob2 (id, content) VALUES (p_num, p_lob); \n" + + "END nodb_clobinproc1;"; + + async.series([ + function(cb) { + + executeSQL(proc, cb); + + }, + function(cb) { + prepareTableWithClob(seq, cb); + }, + function bindCLOB(cb) { + var sql1 = "SELECT content FROM nodb_tab_clob1 WHERE id = :id"; + var sql2 = "begin nodb_clobinproc1(:1, :2); end;"; + + connection.execute( + sql1, + { id: seq }, + function(err, result) { + should.not.exist(err); + (result.rows.length).should.not.eql(0); + + var lob = result.rows[0][0]; + + connection.execute( + sql2, + [ + { val: seq, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + { val: lob, type: oracledb.CLOB, dir: oracledb.BIND_IN } + ], + { autoCommit: true }, + function(err) { + should.not.exist(err); + return cb(); + } + + ); + } + ); + }, + function verify(cb) { + verifyClobValue(seq, cb); + }, + function(cb) { + var sql = "DROP PROCEDURE nodb_clobinproc1"; + executeSQL(sql, cb); + } + ], done); + + }); // 71.1.4 + + it('71.1.5 BIND_OUT, PL/SQL, a string', function(done) { + + var proc = "CREATE OR REPLACE PROCEDURE nodb_cloboutproc_str(p_lob OUT CLOB) \n" + + "AS \n" + + "BEGIN \n" + + " select to_clob('I love the sunshine today.') into p_lob from dual; \n" + + "END nodb_cloboutproc_str;"; + + var sql = "begin nodb_cloboutproc_str(:c); end;"; + + async.series([ + function(cb) { + executeSQL(proc, cb); + }, + function(cb) { + connection.execute( + sql, + { c: { dir: oracledb.BIND_OUT, type: oracledb.CLOB } }, + function(err, result) { + should.not.exist(err); + // console.log(result); + var lob = result.outBinds.c; + + lob.setEncoding("utf8"); + var clobData = ''; + + lob.on('data', function(chunk) { + clobData += chunk; + }); + + lob.on('error', function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + lob.on('end', function() { + should.strictEqual(clobData, "I love the sunshine today."); + return cb(); + }); + } + ); + }, + function(cb) { + var sqlDrop = "DROP PROCEDURE nodb_cloboutproc_str"; + executeSQL(sqlDrop, cb); + } + ], done); + + }); // 71.1.5 + + it('71.1.6 BIND_OUT, PL/SQL, a txt file', function(done) { + + var seq = 6; + var proc = "CREATE OR REPLACE PROCEDURE nodb_cloboutproc1(p_num IN NUMBER, p_lob OUT CLOB) \n" + + "AS \n" + + "BEGIN \n" + + " select content into p_lob from nodb_tab_clob1 WHERE id = p_num; \n" + + "END nodb_cloboutproc1;"; + + async.series([ + function(cb) { + executeSQL(proc, cb); + }, + function(cb) { + prepareTableWithClob(seq, cb); + }, + function(cb) { + var sql = "begin nodb_cloboutproc1(:id, :c); end;"; + + connection.execute( + sql, + { + id: { val: seq, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { dir: oracledb.BIND_OUT, type: oracledb.CLOB } + }, + function(err, result) { + should.not.exist(err); + + var lob = result.outBinds.c; + should.exist(lob); + + lob.setEncoding("utf8"); + var clobData = ''; + + lob.on('data', function(chunk) { + clobData += chunk; + }); + + lob.on('error', function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + lob.on('end', function() { + fs.readFile( inFileName, { encoding: 'utf8' }, function(err, originalData) { + should.not.exist(err); + + should.strictEqual(clobData, originalData); + return cb(); + }); + }); + + } + ); + }, + function(cb) { + var sql = "DROP PROCEDURE nodb_cloboutproc1"; + executeSQL(sql, cb); + } + ], done); + + }); // 71.1.6 + + it('71.1.7 BIND_INOUT, PL/SQL, A String. IN LOB gets closed automatically.', function(done) { + + var seq = 7; + var inStr = "I love the sunshine today!", + outStr = "A new day has come."; + + var proc = "CREATE OR REPLACE PROCEDURE nodb_proc_clob_inout1 \n" + + " (p_num IN NUMBER, p_inout IN OUT CLOB) \n" + + "AS \n" + + "BEGIN \n" + + " insert into nodb_tab_clob2 (id, content) values (p_num, p_inout); \n" + + " select to_clob('" + outStr + "') into p_inout from dual; \n" + + "END nodb_proc_clob_inout1;"; + + async.series([ + function(cb) { + executeSQL(proc, cb); + }, + function(cb) { + var sql = "INSERT INTO nodb_tab_clob1 (id, content) VALUES \n" + + " (:i, '" + inStr + "')"; + + connection.execute( + sql, + { i: seq }, + function(err) { + should.not.exist(err); + cb(); + } + ); + }, + function(cb) { + var sql1 = "SELECT content FROM nodb_tab_clob1 WHERE id = :id"; + var sql2 = "begin nodb_proc_clob_inout1(:id, :io); end;"; + + connection.execute( + sql1, + { id: seq }, + function(err, result) { + should.not.exist(err); + (result.rows.length).should.not.eql(0); + + var lobin = result.rows[0][0]; + + connection.execute( + sql2, + { + id: seq, + io: { val: lobin, type: oracledb.CLOB, dir: oracledb.BIND_INOUT } + }, + { autoCommit: true }, + function(err, result2) { + should.not.exist(err); + + var lobout = result2.outBinds.io; + + async.parallel([ + function verifyOUT(callback) { + lobout.setEncoding("utf8"); + var clobData = ""; + + lobout.on("data", function(chunk) { + clobData += chunk; + }); + + lobout.on("error", function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + lobout.on("end", function() { + should.strictEqual(clobData, outStr); + + return callback(); + }); + }, + function verifyIN(callback) { + + try { + lobin.length; + } catch (err) { + should.exist(err); + (err.message).should.startWith('NJS-022:'); + // Error: NJS-022: invalid Lob + + return callback(); + } + + } + ], function(err) { + should.not.exist(err); + return cb(); + }); + + } + ); + } + ); + }, + function verifyBindInVal(cb) { + var sql = "SELECT content FROM nodb_tab_clob2 WHERE id = :1"; + + connection.execute( + sql, + [ seq ], + function(err, result) { + should.not.exist(err); + + var lobin = result.rows[0][0]; + + lobin.setEncoding('utf8'); + var clobData = ''; + + lobin.on('data', function(chunk) { + clobData += chunk; + }); + + lobin.on('error', function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + lobin.on('end', function() { + should.strictEqual(clobData, inStr); + return cb(); + }); + + } + ); + }, + function(cb) { + var sql = "DROP PROCEDURE nodb_proc_clob_inout1"; + executeSQL(sql, cb); + } + ], done); + + }); + + it('71.1.8 BIND_INOUT, PL/SQL, a txt file', function(done) { + + var seq = 8; + var outStr = "It binds IN a txt file, and binds OUT a String."; + + var proc = "CREATE OR REPLACE PROCEDURE nodb_proc_clob_inout2 \n" + + " (p_num IN NUMBER, p_inout IN OUT CLOB) \n" + + "AS \n" + + "BEGIN \n" + + " insert into nodb_tab_clob2 (id, content) values (p_num, p_inout); \n" + + " select to_clob('" + outStr + "') into p_inout from dual; \n" + + "END nodb_proc_clob_inout2;"; + + async.series([ + function(cb) { + executeSQL(proc, cb); + }, + function(cb) { + prepareTableWithClob(seq, cb); + }, + function(cb) { + var sql1 = "SELECT content FROM nodb_tab_clob1 WHERE id = :id"; + var sql2 = "begin nodb_proc_clob_inout2(:id, :io); end;"; + + connection.execute( + sql1, + { id: seq }, + function(err, result) { + should.not.exist(err); + (result.rows.length).should.not.eql(0); + + var lob = result.rows[0][0]; + + connection.execute( + sql2, + { + id: seq, + io: { val: lob, type: oracledb.CLOB, dir: oracledb.BIND_INOUT } + }, + { autoCommit: true }, + function(err, result2) { + should.not.exist(err); + + var lobout = result2.outBinds.io; + + lobout.setEncoding("utf8"); + var clobData = ''; + + lobout.on('data', function(chunk) { + clobData += chunk; + }); + + lobout.on('error', function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + lobout.on('end', function() { + should.strictEqual(clobData, outStr); + return cb(); + }); + } + + ); + } + ); + }, + function verify(cb) { + verifyClobValue(seq, cb); + }, + function(cb) { + var sql = "DROP PROCEDURE nodb_proc_clob_inout2"; + executeSQL(sql, cb); + } + ], done); + + }); // 71.1.8 + + it('71.1.9 Negative: BIND_INOUT, PL/SQL, String as bind IN Value', function(done) { + + var seq = 9; + var inStr = "I love the sunshine today!", + outStr = "A new day has come."; + + var proc = "CREATE OR REPLACE PROCEDURE nodb_proc_clob_inout3 \n" + + " (p_num IN NUMBER, p_inout IN OUT CLOB) \n" + + "AS \n" + + "BEGIN \n" + + " insert into nodb_tab_clob2 (id, content) values (p_num, p_inout); \n" + + " select to_clob('" + outStr + "') into p_inout from dual; \n" + + "END nodb_proc_clob_inout3;"; + + async.series([ + function(cb) { + executeSQL(proc, cb); + }, + function(cb) { + var sql = "begin nodb_proc_clob_inout3(:id, :io); end;"; + + connection.execute( + sql, + { + id: seq, + io: { val: inStr, type: oracledb.CLOB, dir: oracledb.BIND_INOUT } + }, + { autoCommit: true }, + function(err) { + should.exist(err); + // NJS-011: encountered bind value and type mismatch in parameter 2 + (err.message).should.startWith('NJS-011:'); + cb(); + } + ); + }, + function(cb) { + var sql = "DROP PROCEDURE nodb_proc_clob_inout3"; + executeSQL(sql, cb); + } + ], done); + + }); // 71.1.9 + + }); // 71.1 + + describe("71.2 persistent BLOB", function() { + + before('create the tables', function(done) { + + var proc1 ="BEGIN \n" + + " DECLARE \n" + + " e_table_missing EXCEPTION; \n" + + " PRAGMA EXCEPTION_INIT(e_table_missing, -00942); \n" + + " BEGIN \n" + + " EXECUTE IMMEDIATE('DROP TABLE nodb_tab_blob1 PURGE'); \n" + + " EXCEPTION \n" + + " WHEN e_table_missing \n" + + " THEN NULL; \n" + + " END; \n" + + " EXECUTE IMMEDIATE (' \n" + + " CREATE TABLE nodb_tab_blob1 ( \n" + + " id NUMBER, \n" + + " content BLOB \n" + + " ) \n" + + " '); \n" + + "END; "; + + var proc2 ="BEGIN \n" + + " DECLARE \n" + + " e_table_missing EXCEPTION; \n" + + " PRAGMA EXCEPTION_INIT(e_table_missing, -00942); \n" + + " BEGIN \n" + + " EXECUTE IMMEDIATE('DROP TABLE nodb_tab_blob2 PURGE'); \n" + + " EXCEPTION \n" + + " WHEN e_table_missing \n" + + " THEN NULL; \n" + + " END; \n" + + " EXECUTE IMMEDIATE (' \n" + + " CREATE TABLE nodb_tab_blob2 ( \n" + + " id NUMBER, \n" + + " content BLOB \n" + + " ) \n" + + " '); \n" + + "END; "; + + async.series([ + function(cb) { + executeSQL(proc1, cb); + }, + function(cb) { + executeSQL(proc2, cb); + } + ], done); + + }); // before + + after(function(done) { + async.series([ + function(cb) { + + var sql = "DROP TABLE nodb_tab_blob1 PURGE"; + executeSQL(sql, cb); + + }, + function(cb) { + + var sql = "DROP TABLE nodb_tab_blob2 PURGE"; + executeSQL(sql, cb); + + } + ], done); + }); // after + + var jpgFileName = './test/fuzzydinosaur.jpg'; + var treeAnotherJPG = './test/tree.jpg'; + + var prepareTableWithBlob = function(sequence, filepath, callback) { + + var sql = "INSERT INTO nodb_tab_blob1 (id, content) " + + "VALUES (:i, EMPTY_BLOB()) RETURNING content " + + "INTO :lobbv"; + var bindVar = { i: sequence, lobbv: { type: oracledb.BLOB, dir: oracledb.BIND_OUT } }; + + connection.execute( + sql, + bindVar, + { autoCommit: false }, // a transaction needs to span the INSERT and pipe() + function(err, result) { + should.not.exist(err); + (result.rowsAffected).should.be.exactly(1); + (result.outBinds.lobbv.length).should.be.exactly(1); + + var inStream = fs.createReadStream( filepath ); + var lob = result.outBinds.lobbv[0]; + + lob.on('error', function(err) { + should.not.exist(err, "lob.on 'error' event"); + }); + + inStream.on('error', function(err) { + should.not.exist(err, "inStream.on 'error' event"); + }); + + lob.on('close', function() { + + connection.commit( function(err) { + should.not.exist(err); + + return callback(); + }); + }); + + inStream.pipe(lob); + } + ); + }; // prepareTableWithBlob() + + var bindBlob = function(sequence, callback) { + + var sql1 = "SELECT content FROM nodb_tab_blob1 WHERE id = :id", + sql2 = "INSERT INTO nodb_tab_blob2 (id, content) VALUES (:1, :2)"; + + connection.execute( + sql1, + { id: sequence }, + function(err, result) { + should.not.exist(err); + (result.rows.length).should.not.eql(0); + + var lob = result.rows[0][0]; + + connection.execute( + sql2, + [ + sequence, + { val: lob, type: oracledb.BLOB, dir: oracledb.BIND_IN } + ], + { autoCommit: true }, + function(err) { + should.not.exist(err); + callback(); + } + ); + } + ); + }; // bindBlob() + + var verifyBlobValue = function(sequence, inlob, callback) { + + var sql = "SELECT content FROM nodb_tab_blob2 WHERE id = :id"; + + connection.execute( + sql, + { id: sequence }, + function(err, result) { + should.not.exist(err); + + var lob = result.rows[0][0]; + should.exist(lob); + + var blobData, + totalLength = 0; + + blobData = node6plus ? Buffer.alloc(0) : new Buffer(0); + + lob.on('data', function(chunk) { + totalLength = totalLength + chunk.length; + blobData = Buffer.concat([blobData, chunk], totalLength); + }); + + lob.on('error', function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + lob.on('end', function() { + + if ( (sequence == 1) || (sequence == 7) ) { + + blobData.should.eql(inlob); + + } else { + + fs.readFile( inlob, function(err, originalData) { + should.not.exist(err); + + should.strictEqual(totalLength, originalData.length); + originalData.should.eql(blobData); + }); + + } + + return callback(); + + }); + + } + ); + + }; // verifyBlobValue() + + it('71.2.1 BIND_IN, DML, a Buffer value', function(done) { + + var seq = 1, + bufSize = 10000; + var buf = assist.createBuffer(bufSize); + + async.series([ + function insertBufToTab1(cb) { + var sql = "INSERT INTO nodb_tab_blob1 VALUES (:1, :2)"; + var bindVar = [ + { val: seq, dir: oracledb.BIND_IN, type: oracledb.NUMBER }, + { val: buf, dir: oracledb.BIND_IN, type: oracledb.BUFFER } + ]; + + connection.execute( + sql, + bindVar, + { autoCommit: true }, + function(err, result) { + should.not.exist(err); + should.strictEqual(result.rowsAffected, 1); + cb(); + } + ); + }, + function(cb) { + bindBlob(seq, cb); + }, + function(cb) { + verifyBlobValue(seq, buf, cb); + } + ], done); + + }); // 71.2.1 + + it('71.2.2 BIND_IN, DML, null', function(done) { + + var seq = 2; + var lobData = node6plus ? Buffer.alloc(0) : new Buffer(0); + + async.series([ + function(cb) { + var sql = "insert into nodb_tab_blob1 values (:i, :d)"; + var bindVar = { + i: { val: seq, dir: oracledb.BIND_IN, type: oracledb.NUMBER }, + d: { val: lobData, dir: oracledb.BIND_IN, type: oracledb.BUFFER } + }; + + connection.execute( + sql, + bindVar, + { autoCommit: true }, + function(err) { + should.not.exist(err); + cb(); + } + ); + }, + function(cb) { + bindBlob(seq, cb); + }, + function(cb) { + var sql = "SELECT content FROM nodb_tab_blob2 WHERE id = :id"; + + connection.execute( + sql, + { id: seq }, + function(err, result) { + should.not.exist(err); + + (result.rows).should.eql([ [ null ] ]); + cb(); + } + ); + } + ], done); + + }); // 71.2.2 + + it('71.2.3 BIND_IN, DML, a jpg file', function(done) { + + var seq = 3; + + async.series([ + function(cb) { + prepareTableWithBlob(seq, jpgFileName, cb); + }, + function(cb) { + bindBlob(seq, cb); + }, + function(cb) { + verifyBlobValue(seq, jpgFileName, cb); + } + ], done); + + }); // 71.2.3 + + it('71.2.4 BIND_IN, PL/SQL, a jpg file', function(done) { + + var seq = 4; + var proc = "CREATE OR REPLACE PROCEDURE nodb_proc_blob_in (p_num IN NUMBER, p_lob IN BLOB) \n" + + "AS \n" + + "BEGIN \n" + + " insert into nodb_tab_blob2 (id, content) VALUES (p_num, p_lob); \n" + + "END nodb_proc_blob_in;"; + + async.series([ + function(cb) { + executeSQL(proc, cb); + }, + function(cb) { + prepareTableWithBlob(seq, jpgFileName, cb); + }, + function bindBLOB(cb) { + var sql1 = "SELECT content FROM nodb_tab_blob1 WHERE id = :id", + sql2 = "begin nodb_proc_blob_in(:1, :2); end;"; + + connection.execute( + sql1, + { id: seq }, + function(err, result) { + should.not.exist(err); + (result.rows.length).should.not.eql(0); + + var lob = result.rows[0][0]; + + connection.execute( + sql2, + [ + seq, + { val: lob, type: oracledb.BLOB, dir: oracledb.BIND_IN } + ], + { autoCommit: true }, + function(err) { + should.not.exist(err); + cb(); + } + ); + } + ); + }, + function verify(cb) { + verifyBlobValue(seq, jpgFileName, cb); + }, + function(cb) { + var sql = "DROP PROCEDURE nodb_proc_blob_in"; + executeSQL(sql, cb); + } + ], done); + + }); // 71.2.4 + + it('71.2.5 BIND_OUT, PL/SQL, a Buffer value', function(done) { + + var seq = 5, + bufSize = 1000; + var buf = assist.createBuffer(bufSize); + + var proc = "CREATE OR REPLACE PROCEDURE nodb_proc_blob_out1 (p_num IN NUMBER, p_lob OUT BLOB) \n" + + "AS \n" + + "BEGIN \n" + + " select content into p_lob from nodb_tab_blob2 where id = p_num; \n" + + "END nodb_proc_blob_out1;"; + + async.series([ + function(cb) { + executeSQL(proc, cb); + }, + function insertBuftoTab(cb) { + var sql = "insert into nodb_tab_blob2 values (:1, :2)"; + var bindvar = [ + seq, + { val: buf, dir: oracledb.BIND_IN, type: oracledb.BUFFER } + ]; + + connection.execute( + sql, + bindvar, + { autoCommit: true }, + function(err) { + should.not.exist(err); + cb(); + } + ); + }, + function(cb) { + + var sql = "begin nodb_proc_blob_out1(:i, :b); end;"; + var bindvar = { + i: seq, + b: { dir: oracledb.BIND_OUT, type: oracledb.BLOB } + }; + + connection.execute( + sql, + bindvar, + function(err, result) { + should.not.exist(err); + + var lob = result.outBinds.b; + should.exist(lob); + + var blobData, + totalLength = 0; + + blobData = node6plus ? Buffer.alloc(0) : new Buffer(0); + + lob.on('data', function(chunk) { + totalLength = totalLength + chunk.length; + blobData = Buffer.concat([blobData, chunk], totalLength); + }); + + lob.on('error', function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + lob.on('end', function() { + blobData.should.eql(buf); + + return cb(); + }); + } + ); + }, + function(cb) { + var sql = "DROP PROCEDURE nodb_proc_blob_out1"; + executeSQL(sql, cb); + } + ], done); + + }); // 71.2.5 + + it('71.2.6 BIND_OUT, PL/SQL, a jpg file', function(done) { + + var seq = 6; + var proc = "CREATE OR REPLACE PROCEDURE nodb_proc_blob_out2 (p_num IN NUMBER, p_lob OUT BLOB) \n" + + "AS \n" + + "BEGIN \n" + + " select content into p_lob from nodb_tab_blob1 where id = p_num; \n" + + "END nodb_proc_blob_out2;"; + + async.series([ + function(cb) { + executeSQL(proc, cb); + }, + function(cb) { + prepareTableWithBlob(seq, jpgFileName, cb); + }, + function(cb) { + + var sql = "begin nodb_proc_blob_out2(:1, :2); end;"; + var bindvar = [ + seq, + { dir: oracledb.BIND_OUT, type: oracledb.BLOB } + ]; + + connection.execute( + sql, + bindvar, + function(err, result) { + should.not.exist(err); + + var lob = result.outBinds[0]; + should.exist(lob); + + var blobData, + totalLength = 0; + + blobData = node6plus ? Buffer.alloc(0) : new Buffer(0); + + lob.on('data', function(chunk) { + totalLength = totalLength + chunk.length; + blobData = Buffer.concat([blobData, chunk], totalLength); + }); + + lob.on('error', function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + lob.on('end', function() { + + fs.readFile( jpgFileName, function(err, originalData) { + should.not.exist(err); + + should.strictEqual(totalLength, originalData.length); + originalData.should.eql(blobData); + + return cb(); + }); + + }); + } + ); + }, + function(cb) { + var sql = "DROP PROCEDURE nodb_proc_blob_out2"; + executeSQL(sql, cb); + } + ], done); + + }); // 71.2.6 + + it('71.2.7 BIND_INOUT, PL/SQL, a Buffer value', function(done) { + + var seq = 7, + outBufID = 70; + + var inBuf = assist.createBuffer(10), + outBuf = assist.createBuffer(100); + + var proc = "CREATE OR REPLACE PROCEDURE nodb_proc_blob_inout1 \n" + + " (p_in IN NUMBER, p_outbufid IN NUMBER, p_inout IN OUT BLOB) \n" + + "AS \n" + + "BEGIN \n" + + " insert into nodb_tab_blob2 (id, content) values (p_in, p_inout); \n" + + " select content into p_inout from nodb_tab_blob1 where id = p_outbufid; \n" + + "END nodb_proc_blob_inout1;"; + + async.series([ + function(cb) { + executeSQL(proc, cb); + }, + function prepareInBuf(cb) { + var sql = "insert into nodb_tab_blob1 values (:1, :2)"; + var bindvar = [ + seq, + { val: inBuf, dir: oracledb.BIND_IN, type: oracledb.BUFFER } + ]; + + connection.execute( + sql, + bindvar, + { autoCommit: true }, + function(err) { + should.not.exist(err); + cb(); + } + ); + }, + function prepareOutBuf(cb) { + connection.execute( + "insert into nodb_tab_blob1 values (:i, :b)", + { + i: outBufID, + b: { val: outBuf, dir:oracledb.BIND_IN, type: oracledb.BUFFER } + }, + { autoCommit: true }, + function(err) { + should.not.exist(err); + cb(); + } + ); + }, + function(cb) { + + connection.execute( + "select content from nodb_tab_blob1 where id = :1", + [ seq ], + function(err, result1) { + should.not.exist(err); + + var lobin = result1.rows[0][0]; + + connection.execute( + "begin nodb_proc_blob_inout1 (:in, :oid, :io); end;", + { + in: seq, + oid: outBufID, + io: { val: lobin, type: oracledb.BLOB, dir: oracledb.BIND_INOUT } + }, + { autoCommit: true }, + function(err, result2) { + should.not.exist(err); + + var lobout = result2.outBinds.io; + + var blobData, + totalLength = 0; + + blobData = node6plus ? Buffer.alloc(0) : new Buffer(0); + + lobout.on('data', function(chunk) { + totalLength = totalLength + chunk.length; + blobData = Buffer.concat([blobData, chunk], totalLength); + }); + + lobout.on('error', function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + lobout.on('end', function() { + blobData.should.eql(outBuf); + + return cb(); + + }); + } + ); + + } + ); + }, + + function(cb) { + verifyBlobValue(seq, inBuf, cb); + }, + function(cb) { + var sql = "DROP PROCEDURE nodb_proc_blob_inout1"; + executeSQL(sql, cb); + } + ], done); + + }); // 71.2.7 + + it('71.2.8 BIND_INOUT, PL/SQL, a jpg file', function(done) { + + var seq = 8; + var treeID = 100; + + var proc = "CREATE OR REPLACE PROCEDURE nodb_proc_blob_inout2 \n" + + " (p_in_seq IN NUMBER, p_in_tree IN NUMBER, p_inout IN OUT BLOB) \n" + + "AS \n" + + "BEGIN \n" + + " insert into nodb_tab_blob2 (id, content) values (p_in_seq, p_inout); \n" + + " select content into p_inout from nodb_tab_blob1 where id = p_in_tree; \n" + + "END nodb_proc_blob_inout2;"; + + async.series([ + function(cb) { + executeSQL(proc, cb); + }, + function(cb) { + prepareTableWithBlob(seq, jpgFileName, cb); + }, + function(cb) { + prepareTableWithBlob(treeID, treeAnotherJPG, cb); + }, + function(cb) { + + var sql1 = "select content from nodb_tab_blob1 where id = :id"; + var sql2 = "begin nodb_proc_blob_inout2(:i, :tree, :io); end;"; + + connection.execute( + sql1, + { id: seq }, + function(err, result) { + should.not.exist(err); + + // bindin lob is the tree.jpg + var inlob = result.rows[0][0]; + + connection.execute( + sql2, + { + i: seq, + tree: treeID, + io: { val: inlob, dir: oracledb.BIND_INOUT, type: oracledb.BLOB } + }, + { autoCommit: true }, + function(err, result2) { + should.not.exist(err); + (result.rows.length).should.not.eql(0); + + var lob = result2.outBinds.io; + + var blobData, + totalLength = 0; + + blobData = node6plus ? Buffer.alloc(0) : new Buffer(0); + + lob.on('data', function(chunk) { + totalLength = totalLength + chunk.length; + blobData = Buffer.concat([blobData, chunk], totalLength); + }); + + lob.on('error', function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + lob.on('end', function() { + + fs.readFile( treeAnotherJPG, function(err, treeData) { + should.not.exist(err); + + should.strictEqual(totalLength, treeData.length); + treeData.should.eql(blobData); + + return cb(); + }); + }); + } + ); + } + ); + + }, + function(cb) { + verifyBlobValue(seq, jpgFileName, cb); + }, + function(cb) { + var sql = "DROP PROCEDURE nodb_proc_blob_inout2"; + executeSQL(sql, cb); + } + ], done); + + }); // 71.2.8 + + it('71.2.9 Negative: BIND_INOUT, PL/SQL, Buffer as bind IN value', function(done) { + + var seq = 9; + var inBuf = assist.createBuffer(10); + + var proc = "CREATE OR REPLACE PROCEDURE nodb_proc_blob_inout3 \n" + + " (p_in IN NUMBER, p_inout IN OUT BLOB) \n" + + "AS \n" + + "BEGIN \n" + + " insert into nodb_tab_blob2 (id, content) values (p_in, p_inout); \n" + + " select content into p_inout from nodb_tab_blob1 where id = p_in; \n" + + "END nodb_proc_blob_inout3;"; + + async.series([ + function(cb) { + executeSQL(proc, cb); + }, + function(cb) { + prepareTableWithBlob(seq, jpgFileName, cb); + }, + function(cb) { + + var sql = "begin nodb_proc_blob_inout3 (:i, :io); end;", + bindvar = { + i: seq, + io: { val: inBuf, type: oracledb.BLOB, dir: oracledb.BIND_INOUT } + }; + + connection.execute( + sql, + bindvar, + { autoCommit: true }, + function(err) { + should.exist(err); + (err.message).should.startWith('NJS-011:'); + // NJS-011: encountered bind value and type mismatch in parameter 2 + + cb(); + } + ); + }, + function(cb) { + var sql = "DROP PROCEDURE nodb_proc_blob_inout3"; + executeSQL(sql, cb); + } + ], done); + }); // 71.2.9 + + }); // 71.2 + +}); diff --git a/test/lobBind2.js b/test/lobBind2.js new file mode 100644 index 00000000..85337fd3 --- /dev/null +++ b/test/lobBind2.js @@ -0,0 +1,1020 @@ +/* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with the Apache + * License, Version 2.0 (the "License.") + * + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + * The node-oracledb test suite uses 'mocha', 'should' and 'async'. + * See LICENSE.md for relevant licenses. + * + * NAME + * 72. lobBind2.js + * + * DESCRIPTION + * Testing connection.createLob() function. + * + * NUMBERING RULE + * Test numbers follow this numbering rule: + * 1 - 20 are reserved for basic functional tests + * 21 - 50 are reserved for data type supporting tests + * 51 onwards are for other tests + * + *****************************************************************************/ +'use strict'; + +var oracledb = require('oracledb'); +var fs = require('fs'); +var should = require('should'); +var async = require('async'); +var dbConfig = require('./dbconfig.js'); + +describe("72. lobBind2.js", function() { + + var connection = null; + var node6plus = false; // assume node runtime version is lower than 6 + + before(function(done) { + oracledb.getConnection(dbConfig, function(err, conn) { + should.not.exist(err); + connection = conn; + + // Check whether node runtime version is >= 6 or not + if ( process.versions["node"].substring (0, 1) >= "6") + node6plus = true; + + done(); + }); + }); // before + + after(function(done) { + connection.release(function(err) { + should.not.exist(err); + done(); + }); + }); // after + + var executeSQL = function(sql, callback) { + connection.execute( + sql, + function(err) { + should.not.exist(err); + callback(); + } + ); + }; + + describe("72.1 CLOB", function() { + + before(function(done) { + + var proc = "BEGIN \n" + + " DECLARE \n" + + " e_table_missing EXCEPTION; \n" + + " PRAGMA EXCEPTION_INIT(e_table_missing, -00942); \n" + + " BEGIN \n" + + " EXECUTE IMMEDIATE('DROP TABLE nodb_tab_clob72 PURGE'); \n" + + " EXCEPTION \n" + + " WHEN e_table_missing \n" + + " THEN NULL; \n" + + " END; \n" + + " EXECUTE IMMEDIATE (' \n" + + " CREATE TABLE nodb_tab_clob72 ( \n" + + " id NUMBER, \n" + + " content CLOB \n" + + " ) \n" + + " '); \n" + + "END; "; + + executeSQL(proc, done); + + }); // before + + after(function(done) { + + var sql = "DROP TABLE nodb_tab_clob72 PURGE"; + executeSQL(sql, done); + + }); // after + + var verifyClobValue = function(sequence, expectLob, callback) { + + var sql = "select content from nodb_tab_clob72 where id = :i"; + + connection.execute( + sql, + { i: sequence }, + function(err, result) { + should.not.exist(err); + + var lob = result.rows[0][0]; + should.exist(lob); + + lob.setEncoding("utf8"); + var clobData = ""; + + lob.on("data", function(chunk) { + clobData += chunk; + }); + + lob.on("error", function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + lob.on("end", function() { + + fs.readFile(expectLob, { encoding: "utf8"}, function(err, originalData) { + should.not.exist(err); + + should.strictEqual(clobData, originalData); + return callback(); + }); + + }); // end event + } + ); + + }; // verifyClobValue + + var inFileName = './test/clobexample.txt'; + + it("72.1.1 BIND_IN, DML, a txt file", function(done) { + + var seq = 1; + + async.series([ + function(cb) { + connection.createLob(oracledb.CLOB, function(err, lob) { + should.not.exist(err); + + lob.on("close", function(err) { + should.not.exist(err); + + connection.commit(function(err) { + should.not.exist(err); + + return cb(); + }); + }); // close event + + lob.on("error", function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + lob.on("finish", function() { + connection.execute( + "insert into nodb_tab_clob72 (id, content) values (:id, :bindvar)", + { id: seq, bindvar: lob}, + function(err, result) { + should.not.exist(err); + + should.strictEqual(result.rowsAffected, 1); + + lob.close(function(err) { + should.not.exist(err); + }); + } + ); + }); // finish event + + var inStream = fs.createReadStream(inFileName); + + inStream.on("error", function(err) { + should.not.exist(err, "inStream.on 'error' event."); + }); + + inStream.pipe(lob); + + }); // createLob() + }, + function(cb) { + verifyClobValue(seq, inFileName, cb); + } + ], done); + + }); // 72.1.1 + + it("72.1.2 BIND_IN, PL/SQL, a txt file", function(done) { + + var seq = 2; + var proc = "CREATE OR REPLACE PROCEDURE nodb_proc_clob_in (p_num IN NUMBER, p_lob IN CLOB) \n" + + "AS \n" + + "BEGIN \n" + + " insert into nodb_tab_clob72 (id, content) VALUES (p_num, p_lob); \n" + + "END nodb_proc_clob_in;"; + + async.series([ + function(cb) { + executeSQL(proc, cb); + }, + function dotest(cb) { + connection.createLob(oracledb.CLOB, function(err, lob) { + should.not.exist(err); + + lob.on("close", function(err) { + should.not.exist(err); + + connection.commit(function(err) { + should.not.exist(err); + + return cb(); + }); + }); // close event + + lob.on("error", function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + lob.on("finish", function() { + connection.execute( + "begin nodb_proc_clob_in(:1, :2); end;", + [seq, lob], + function(err) { + should.not.exist(err); + + lob.close(function(err) { + should.not.exist(err); + }); + } + ); + }); // finish event + + var inStream = fs.createReadStream(inFileName); + + inStream.on("error", function(err) { + should.not.exist(err, "inStream.on 'error' event."); + }); + + inStream.pipe(lob); + + }); // createLob() + }, + function(cb) { + verifyClobValue(seq, inFileName, cb); + }, + function(cb) { + var sql = "DROP PROCEDURE nodb_proc_clob_in"; + executeSQL(sql, cb); + } + ], done); + + }); // 72.1.2 + + it("72.1.3 Negative - invalid type", function(done) { + + try { + connection.createLob('CLOB', function(err, lob) { + should.exist(err); + should.not.exist(lob); + done(); + }); + } catch (err) { + should.exist(err); + (err.message).should.startWith('NJS-006:'); + // NJS-006: invalid type for parameter 1 + done(); + } + }); // 72.1.3 + + it("72.1.4 Negative - invalid value", function(done) { + + try { + connection.createLob(oracledb.STRING, function(err, lob) { + should.exist(err); + should.not.exist(lob); + done(); + }); + } catch (err) { + should.exist(err); + (err.message).should.startWith('NJS-005:'); + // NJS-005: invalid value for parameter 1 + done(); + } + + }); // 72.1.4 + + + it("72.1.5 DML - UPDATE statement", function(done) { + + var seq = 5; + + async.series([ + function(cb) { + var proc = "begin \n" + + " insert into nodb_tab_clob72 (id, content) values ( :1, to_clob('This is clob data.') ); \n" + + "end; "; + + connection.execute( + proc, + [seq], + function(err) { + should.not.exist(err); + cb(); + } + ); + }, + function(cb) { + connection.createLob(oracledb.CLOB, function(err, lob) { + should.not.exist(err); + + lob.on("close", function(err) { + should.not.exist(err); + + connection.commit(function(err) { + should.not.exist(err); + + return cb(); + }); + }); // close event + + lob.on("error", function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + lob.on("finish", function() { + connection.execute( + "update nodb_tab_clob72 set content = :bindvar where id = :id", + { id: seq, bindvar: lob}, + function(err, result) { + should.not.exist(err); + + should.strictEqual(result.rowsAffected, 1); + + lob.close(function(err) { + should.not.exist(err); + }); + } + ); + }); // finish event + + var inStream = fs.createReadStream(inFileName); + + inStream.on("error", function(err) { + should.not.exist(err, "inStream.on 'error' event."); + }); + + inStream.pipe(lob); + + }); // createLob() + }, + function(cb) { + verifyClobValue(seq, inFileName, cb); + } + ], done); + + }); // 72.1.5 + + it("72.1.6 promise test of createLob()", function(done) { + + var seq = 6; + + if (oracledb.Promise) { + connection.createLob(oracledb.CLOB) + .then(function(lob) { + should.exist(lob); + + lob.on("close", function(err) { + should.not.exist(err); + + connection.commit() + .then(function() { + verifyClobValue(seq, inFileName, done); + }); + }); + + lob.on("error", function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + lob.on("finish", function() { + connection.execute( + "insert into nodb_tab_clob72 (id, content) values (:id, :bindvar)", + { id: seq, bindvar: lob} + ).then(function(result) { + should.strictEqual(result.rowsAffected, 1); + + var lobClosePromise = lob.close(); + lobClosePromise.should.be.an.instanceOf(oracledb.Promise); + }); + }); + + var inStream = fs.createReadStream(inFileName); + + inStream.on("error", function(err) { + should.not.exist(err, "inStream.on 'error' event."); + }); + + inStream.pipe(lob); + + }) + .catch(function(err) { + should.not.exist(err); + return done(); + }); + } + else { + // This version of Node.js does not support Promise + return done(); + } + + }); // 72.1.6 + + it("72.1.7 BIND_INOUT, PL/SQL, IN LOB gets closed automatically", function(done) { + + var seq = 7; + var outStr = "This is a out bind string."; + var proc = "CREATE OR REPLACE PROCEDURE nodb_proc_clob_inout1 \n" + + " (p_num IN NUMBER, p_inout IN OUT CLOB) \n" + + "AS \n" + + "BEGIN \n" + + " insert into nodb_tab_clob72 (id, content) values (p_num, p_inout); \n" + + " select to_clob('" + outStr + "') into p_inout from dual; \n" + + "END nodb_proc_clob_inout1;"; + + async.series([ + function(cb) { + executeSQL(proc, cb); + }, + function(cb) { + connection.createLob(oracledb.CLOB, function(err, lob) { + should.not.exist(err); + + lob.on("error", function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + lob.on("finish", function() { + connection.execute( + "begin nodb_proc_clob_inout1(:id, :io); end;", + { + id: seq, + io: { type: oracledb.CLOB, dir: oracledb.BIND_INOUT, val: lob} + }, + { autoCommit: true }, + function(err, result) { + should.not.exist(err); + // The IN LOB closed automatically after execute call, need + // close the OUT LOB + + var lobout = result.outBinds.io; + + lobout.on("close", function(err) { + should.not.exist(err); + + return cb(); + }); // close event of lobout + + lobout.on("error", function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + lobout.setEncoding("utf8"); + var clobData; + lobout.on("data", function(chunk) { + clobData += chunk; + }); + + lobout.on("finish", function() { + + should.strictEqual(clobData, outStr); + + lobout.close(function(err) { + should.not.exist(err); + }); + }); + + } + ); + }); // finish event of lob + + var inStream = fs.createReadStream(inFileName); + + inStream.on("error", function(err) { + should.not.exist(err, "inStream.on 'error' event."); + }); + + inStream.pipe(lob); + }); + + }, + function(cb) { + verifyClobValue(seq, inFileName, cb); + }, + function(cb) { + var sql = "DROP PROCEDURE nodb_proc_clob_inout1"; + executeSQL(sql, cb); + } + ], done); + }); // 72.1.7 + + }); // 72.1 + + describe("72.2 BLOB", function() { + + before(function(done) { + + var proc = "BEGIN \n" + + " DECLARE \n" + + " e_table_missing EXCEPTION; \n" + + " PRAGMA EXCEPTION_INIT(e_table_missing, -00942); \n" + + " BEGIN \n" + + " EXECUTE IMMEDIATE('DROP TABLE nodb_tab_blob72 PURGE'); \n" + + " EXCEPTION \n" + + " WHEN e_table_missing \n" + + " THEN NULL; \n" + + " END; \n" + + " EXECUTE IMMEDIATE (' \n" + + " CREATE TABLE nodb_tab_blob72 ( \n" + + " id NUMBER, \n" + + " content BLOB \n" + + " ) \n" + + " '); \n" + + "END; "; + + executeSQL(proc, done); + + }); // before + + after(function(done) { + + var sql = "DROP TABLE nodb_tab_blob72 PURGE"; + executeSQL(sql, done); + + }); // after + + var jpgFileName = './test/fuzzydinosaur.jpg'; + + var verifyBlobValue = function(sequence, expectLob, callback) { + + var sql = "select content from nodb_tab_blob72 where id = :i"; + + connection.execute( + sql, + { i: sequence }, + function(err, result) { + should.not.exist(err); + + var lob = result.rows[0][0]; + should.exist(lob); + + var blobData, + totalLength = 0; + + blobData = node6plus ? Buffer.alloc(0) : new Buffer(0); + + lob.on("data", function(chunk) { + totalLength = totalLength + chunk.length; + blobData = Buffer.concat([blobData, chunk], totalLength); + }); + + lob.on("error", function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + lob.on("end", function() { + + fs.readFile(expectLob, function(err, originalData) { + should.not.exist(err); + + should.strictEqual(totalLength, originalData.length); + originalData.should.eql(blobData); + + return callback(); + }); + + }); // end event + } + ); + + }; // verifyBlobValue + + it("72.2.1 BIND_IN, DML, a jpg file", function(done) { + + var seq = 1; + + async.series([ + function(cb) { + connection.createLob(oracledb.BLOB, function(err, lob) { + should.not.exist(err); + + lob.on("close", function(err) { + should.not.exist(err); + + connection.commit(function(err) { + should.not.exist(err); + + return cb(); + }); + }); // close event + + lob.on("error", function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + lob.on("finish", function() { + connection.execute( + "insert into nodb_tab_blob72 (id, content) values (:id, :bindvar)", + { id: seq, bindvar: lob}, + function(err, result) { + should.not.exist(err); + + should.strictEqual(result.rowsAffected, 1); + + lob.close(function(err) { + should.not.exist(err); + }); + } + ); + }); // finish event + + var inStream = fs.createReadStream(jpgFileName); + + inStream.on("error", function(err) { + should.not.exist(err, "inStream.on 'error' event."); + }); + + inStream.pipe(lob); + + }); // createLob() + }, + function(cb) { + verifyBlobValue(seq, jpgFileName, cb); + } + ], done); + + }); // 72.2.1 + + it("72.2.2 BIND_IN, PL/SQL, a jpg file", function(done) { + + var seq = 2; + var proc = "CREATE OR REPLACE PROCEDURE nodb_proc_blob_in (p_num IN NUMBER, p_lob IN BLOB) \n" + + "AS \n" + + "BEGIN \n" + + " insert into nodb_tab_blob72 (id, content) VALUES (p_num, p_lob); \n" + + "END nodb_proc_blob_in;"; + + async.series([ + function(cb) { + executeSQL(proc, cb); + }, + function dotest(cb) { + connection.createLob(oracledb.BLOB, function(err, lob) { + should.not.exist(err); + + lob.on("close", function(err) { + should.not.exist(err); + + connection.commit(function(err) { + should.not.exist(err); + + return cb(); + }); + }); // close event + + lob.on("error", function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + lob.on("finish", function() { + connection.execute( + "begin nodb_proc_blob_in(:1, :2); end;", + [seq, lob], + function(err) { + should.not.exist(err); + + lob.close(function(err) { + should.not.exist(err); + }); + } + ); + }); // finish event + + var inStream = fs.createReadStream(jpgFileName); + + inStream.on("error", function(err) { + should.not.exist(err, "inStream.on 'error' event."); + }); + + inStream.pipe(lob); + + }); // createLob() + }, + function(cb) { + verifyBlobValue(seq, jpgFileName, cb); + }, + function(cb) { + var sql = "DROP PROCEDURE nodb_proc_blob_in"; + executeSQL(sql, cb); + } + ], done); + + }); // 72.2.2 + + it("72.2.3 Negative - inconsistent datatypes", function(done) { + + var seq = 3; + + async.series([ + function(cb) { + connection.createLob(oracledb.CLOB, function(err, lob) { + should.not.exist(err); + + lob.on("close", function(err) { + should.not.exist(err); + + connection.commit(function(err) { + should.not.exist(err); + + return cb(); + }); + }); // close event + + lob.on("error", function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + lob.on("finish", function() { + connection.execute( + "insert into nodb_tab_blob72 (id, content) values (:id, :bindvar)", + { id: seq, bindvar: lob}, + function(err) { + should.exist(err); + (err.message).should.startWith("ORA-00932:"); + // ORA-00932: inconsistent datatypes: expected BLOB got CLOB + + lob.close(function(err) { + should.not.exist(err); + }); + } + ); + }); // finish event + + var inStream = fs.createReadStream(jpgFileName); + + inStream.on("error", function(err) { + should.not.exist(err, "inStream.on 'error' event."); + }); + + inStream.pipe(lob); + + }); // createLob() + } + ], done); + + }); // 72.2.3 + + it("72.2.4 Negative - not providing first parameter", function(done) { + + try { + connection.createLob(function(err, lob) { + should.not.exist(err); + should.not.exist(lob); + + }); + } catch(error) { + should.exist(error); + (error.message).should.startWith("NJS-009:"); + // NJS-009: invalid number of parameters + + return done(); + } + + }); // 72.2.4 + + it("72.2.5 promise test of createLob()", function(done) { + + var seq = 5; + + if (oracledb.Promise) { + connection.createLob(oracledb.BLOB) + .then(function(lob) { + should.exist(lob); + + lob.on("close", function(err) { + should.not.exist(err); + + connection.commit() + .then(function() { + verifyBlobValue(seq, jpgFileName, done); + }); + }); + + lob.on("error", function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + lob.on("finish", function() { + connection.execute( + "insert into nodb_tab_blob72 (id, content) values (:id, :bindvar)", + { id: seq, bindvar: lob} + ).then(function(result) { + should.strictEqual(result.rowsAffected, 1); + + var lobClosePromise = lob.close(); + lobClosePromise.should.be.an.instanceOf(oracledb.Promise); + }); + }); + + var inStream = fs.createReadStream(jpgFileName); + + inStream.on("error", function(err) { + should.not.exist(err, "inStream.on 'error' event."); + }); + + inStream.pipe(lob); + + }) + .catch(function(err) { + should.not.exist(err); + return done(); + }); + } + else { + // This version of Node.js does not support Promise + return done(); + } + + }); // 72.2.5 + + it("72.2.6 call lob.close() multiple times sequentially", function(done) { + + var seq = 7000; + + async.series([ + function(cb) { + connection.createLob(oracledb.BLOB, function(err, lob) { + should.not.exist(err); + + lob.on("close", function(err) { + should.not.exist(err); + + lob.close(function(err) { + should.not.exist(err); + }); + connection.commit(function(err) { + should.not.exist(err); + + return cb(); + }); + }); // close event + + lob.on("error", function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + lob.on("finish", function() { + connection.execute( + "insert into nodb_tab_blob72 (id, content) values (:id, :bindvar)", + { id: seq, bindvar: lob}, + function(err, result) { + should.not.exist(err); + + should.strictEqual(result.rowsAffected, 1); + + lob.close(function(err) { + should.not.exist(err); + }); + + } + ); + }); // finish event + + var inStream = fs.createReadStream(jpgFileName); + + inStream.on("error", function(err) { + should.not.exist(err, "inStream.on 'error' event."); + }); + + inStream.pipe(lob); + + }); // createLob() + }, + function(cb) { + verifyBlobValue(seq, jpgFileName, cb); + } + ], done); + + }); // 72.2.6 + + it("72.2.7 BIND_INOUT, PL/SQL, needs to close out lob explicitly", function(done) { + + var seq = 7, outLobId = 77; + var outFileName = './test/tree.jpg'; + var proc = "CREATE OR REPLACE PROCEDURE nodb_proc_blob_inout1 \n" + + " (p_num IN NUMBER, p_from IN NUMBER, p_inout IN OUT BLOB) \n" + + "AS \n" + + "BEGIN \n" + + " insert into nodb_tab_blob72 (id, content) values (p_num, p_inout); \n" + + " select content into p_inout from nodb_tab_blob72 where id = p_from; \n" + + "END nodb_proc_blob_inout1;"; + + var prepareOutBlob = function(callback) { + + var buf = fs.readFileSync(outFileName); + connection.execute( + "INSERT INTO nodb_tab_blob72 (id, content) VALUES (:id, :b)", + { id: outLobId, b: buf }, + { autoCommit: true }, + function(err, result) { + should.not.exist(err); + (result.rowsAffected).should.be.exactly(1); + return callback(); + } + ); + + }; + + var dotest = function(callback) { + + connection.createLob(oracledb.BLOB, function(err, lob) { + should.not.exist(err); + + lob.on('error', function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + lob.on('finish', function() { + + connection.execute( + "begin nodb_proc_blob_inout1(:id, :oid, :io); end;", + { + id: seq, + oid: outLobId, + io: { type: oracledb.BLOB, dir: oracledb.BIND_INOUT, val: lob } + }, + { autoCommit: true }, + function(err, result) { + should.not.exist(err); + var lobout = result.outBinds.io; + + lobout.on('close', function(err) { + should.not.exist(err); + + return callback(); + }); + + lobout.on('error', function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + var blobData; + lobout.on('data', function(chunk) { + blobData += chunk; + }); + + lobout.on('finish', function() { + + var buf = fs.readFileSync(outFileName); + (blobData).should.eql(buf); + + lobout.close(function(err) { + should.not.exist(err); + }); + }); + + } + ); + + }); // finish event of lob + + var inStream = fs.createReadStream(jpgFileName); + inStream.pipe(lob); + + inStream.on('error', function(err) { + should.not.exist(err, "inStream.on 'error' event."); + }); + + }); + + }; + + async.series([ + function(cb) { + executeSQL(proc, cb); + }, + prepareOutBlob, + dotest, + function(cb) { + verifyBlobValue(seq, jpgFileName, cb); + }, + function(cb) { + var sql = "DROP PROCEDURE nodb_proc_blob_inout1"; + executeSQL(sql, cb); + } + ], done); + + }); // 72.2.7 + + }); // 72.2 + +}); diff --git a/test/lobBindAsStringBuffer.js b/test/lobBindAsStringBuffer.js new file mode 100644 index 00000000..4e33e3d6 --- /dev/null +++ b/test/lobBindAsStringBuffer.js @@ -0,0 +1,812 @@ +/* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with the Apache + * License, Version 2.0 (the "License.") + * + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + * The node-oracledb test suite uses 'mocha', 'should' and 'async'. + * See LICENSE.md for relevant licenses. + * + * NAME + * 80. lobBindAsStringBuffer.js + * + * DESCRIPTION + * Testing CLOB/BLOB binding as String/Buffer. + * + * NUMBERING RULE + * Test numbers follow this numbering rule: + * 1 - 20 are reserved for basic functional tests + * 21 - 50 are reserved for data type supporting tests + * 51 onwards are for other tests + * + *****************************************************************************/ +'use strict'; + +var oracledb = require('oracledb'); +var should = require('should'); +var async = require('async'); +var dbConfig = require('./dbconfig.js'); +var fs = require('fs'); +var random = require('./random.js'); + +describe('80. lobBindAsStringBuffer.js', function() { + var connection = null; + var node6plus = false; // assume node runtime version is lower than 6 + + var proc_lobs_in_tab = "BEGIN \n" + + " DECLARE \n" + + " e_table_missing EXCEPTION; \n" + + " PRAGMA EXCEPTION_INIT(e_table_missing, -00942); \n" + + " BEGIN \n" + + " EXECUTE IMMEDIATE('DROP TABLE nodb_tab_lobs_in PURGE'); \n" + + " EXCEPTION \n" + + " WHEN e_table_missing \n" + + " THEN NULL; \n" + + " END; \n" + + " EXECUTE IMMEDIATE (' \n" + + " CREATE TABLE nodb_tab_lobs_in ( \n" + + " id NUMBER, \n" + + " clob CLOB, \n" + + " blob BLOB \n" + + " ) \n" + + " '); \n" + + "END; "; + + before(function(done) { + async.series([ + function(cb) { + oracledb.getConnection(dbConfig, function(err, conn) { + should.not.exist(err); + connection = conn; + + // Check whether node runtime version is >= 6 or not + if ( process.versions["node"].substring (0, 1) >= "6") + node6plus = true; + + cb(); + }); + }, + function(cb) { + setupAllTable(cb); + } + ], done); + + }); // before + + after(function(done) { + async.series([ + function(cb) { + dropAllTable(cb); + }, + function(cb) { + connection.release(function(err) { + should.not.exist(err); + cb(); + }); + } + ], done); + + }); // after + + var setupAllTable = function(callback) { + connection.execute( + proc_lobs_in_tab, + function(err) { + should.not.exist(err); + callback(); + } + ); + }; + + var dropAllTable = function(callback) { + connection.execute( + "DROP TABLE nodb_tab_lobs_in PURGE", + function(err) { + should.not.exist(err); + callback(); + } + ); + }; + + var executeSQL = function(sql, callback) { + connection.execute( + sql, + function(err) { + should.not.exist(err); + return callback(); + } + ); + }; + + var inFileName = './test/clobexample.txt'; + + var prepareTableWithClob = function(sql, id, callback) { + var bindVar = { i: id, lobbv: { type: oracledb.CLOB, dir: oracledb.BIND_OUT } }; + + connection.execute( + sql, + bindVar, + { autoCommit: false }, // a transaction needs to span the INSERT and pipe() + function(err, result) { + should.not.exist(err); + (result.rowsAffected).should.be.exactly(1); + (result.outBinds.lobbv.length).should.be.exactly(1); + + var inStream = fs.createReadStream(inFileName); + var lob = result.outBinds.lobbv[0]; + + lob.on('error', function(err) { + should.not.exist(err, "lob.on 'error' event"); + }); + + inStream.on('error', function(err) { + should.not.exist(err, "inStream.on 'error' event"); + }); + + lob.on('close', function() { + connection.commit( function(err) { + should.not.exist(err); + return callback(); + }); + }); + + inStream.pipe(lob); // copies the text to the CLOB + } + ); + }; + + var jpgFileName = './test/fuzzydinosaur.jpg'; + + var prepareTableWithBlob = function(sql, id, callback) { + var bindVar = { i: id, lobbv: { type: oracledb.BLOB, dir: oracledb.BIND_OUT } }; + + connection.execute( + sql, + bindVar, + { autoCommit: false }, // a transaction needs to span the INSERT and pipe() + function(err, result) { + should.not.exist(err); + (result.rowsAffected).should.be.exactly(1); + (result.outBinds.lobbv.length).should.be.exactly(1); + + var inStream = fs.createReadStream(jpgFileName); + var lob = result.outBinds.lobbv[0]; + + lob.on('error', function(err) { + should.not.exist(err, "lob.on 'error' event"); + }); + + inStream.on('error', function(err) { + should.not.exist(err, "inStream.on 'error' event"); + }); + + lob.on('close', function() { + connection.commit( function(err) { + should.not.exist(err); + return callback(); + }); + }); + + inStream.pipe(lob); + }); + }; + + var verifyClobValueWithFileData = function(selectSql, callback) { + connection.execute( + selectSql, + function(err, result) { + should.not.exist(err); + var lob = result.rows[0][0]; + should.exist(lob); + // set the encoding so we get a 'string' not a 'buffer' + lob.setEncoding('utf8'); + var clobData = ''; + + lob.on('data', function(chunk) { + clobData += chunk; + }); + + lob.on('error', function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + lob.on('end', function() { + fs.readFile( inFileName, { encoding: 'utf8' }, function(err, originalData) { + should.not.exist(err); + should.strictEqual(clobData, originalData); + return callback(); + }); + }); + } + ); + }; + + var verifyClobValueWithString = function(selectSql, originalString, specialStr, callback) { + connection.execute( + selectSql, + function(err, result) { + should.not.exist(err); + var lob = result.rows[0][0]; + + if (originalString == null || originalString == undefined) { + should.not.exist(lob); + return callback(); + } else { + should.exist(lob); + // set the encoding so we get a 'string' not a 'buffer' + lob.setEncoding('utf8'); + var clobData = ''; + + lob.on('data', function(chunk) { + clobData += chunk; + }); + + lob.on('error', function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + lob.on('end', function() { + var resultLength = clobData.length; + var specStrLength = specialStr.length; + should.strictEqual(resultLength, originalString.length); + should.strictEqual(clobData.substring(0, specStrLength), specialStr); + should.strictEqual(clobData.substring(resultLength - specStrLength, resultLength), specialStr); + return callback(); + }); + } + } + ); + }; + + var verifyBlobValueWithFileData = function(selectSql, callback) { + connection.execute( + selectSql, + function(err, result) { + should.not.exist(err); + var lob = result.rows[0][0]; + should.exist(lob); + + var blobData = 0; + var totalLength = 0; + blobData = node6plus ? Buffer.alloc(0) : new Buffer(0); + + lob.on('data', function(chunk) { + totalLength = totalLength + chunk.length; + blobData = Buffer.concat([blobData, chunk], totalLength); + }); + + lob.on('error', function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + lob.on('end', function() { + fs.readFile( jpgFileName, function(err, originalData) { + should.not.exist(err); + should.strictEqual(totalLength, originalData.length); + originalData.should.eql(blobData); + return callback(); + }); + }); + }); + }; + + var verifyBlobValueWithBuffer = function(selectSql, oraginalBuffer, specialStr, callback) { + connection.execute( + selectSql, + function(err, result) { + should.not.exist(err); + var lob = result.rows[0][0]; + if (oraginalBuffer == null | oraginalBuffer == '' || oraginalBuffer == undefined) { + should.not.exist(lob); + return callback(); + } else { + should.exist(lob); + var blobData = node6plus ? Buffer.alloc(0) : new Buffer(0); + var totalLength = 0; + + lob.on('data', function(chunk) { + totalLength = totalLength + chunk.length; + blobData = Buffer.concat([blobData, chunk], totalLength); + }); + + lob.on('error', function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + lob.on('end', function() { + should.strictEqual(totalLength, oraginalBuffer.length); + var specStrLength = specialStr.length; + should.strictEqual(blobData.toString('utf8', 0, specStrLength), specialStr); + should.strictEqual(blobData.toString('utf8', (totalLength - specStrLength), totalLength), specialStr); + return callback(); + }); + } + } + ); + }; + + describe('80.1 Multiple LOBs, BIND_IN', function() { + var proc = "CREATE OR REPLACE PROCEDURE nodb_lobs_in_781 (id IN NUMBER, clob_in IN CLOB, blob_in IN BLOB)\n" + + "AS \n" + + "BEGIN \n" + + " insert into nodb_tab_lobs_in (id, clob, blob) values (id, clob_in, blob_in); \n" + + "END nodb_lobs_in_781; "; + var sqlRun = "BEGIN nodb_lobs_in_781 (:i, :c, :b); END;"; + var proc_drop = "DROP PROCEDURE nodb_lobs_in_781"; + + before(function(done) { + executeSQL(proc, done); + }); // before + + after(function(done) { + executeSQL(proc_drop, done); + }); // after + + it('80.1.1 PLSQL, CLOB&BLOB, bind a string and a buffer', function(done) { + var specialStr = "80.1.1"; + var length = 50000; + var bigStr = random.getRandomString(length, specialStr); + var bigBuffer = node6plus ? Buffer.from(bigStr, "utf-8") : new Buffer(bigStr, "utf-8"); + var sequence = 700; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { val: bigStr, type: oracledb.STRING, dir: oracledb.BIND_IN, maxSize: length }, + b: { val: bigBuffer, type: oracledb.BUFFER, dir: oracledb.BIND_IN, maxSize: length } + }; + + async.series([ + function(cb) { + connection.execute( + sqlRun, + bindVar, + { autoCommit: true }, + function(err) { + should.not.exist(err); + cb(); + } + ); + }, + function(cb) { + var sql_1 = "select clob from nodb_tab_lobs_in where id = " + sequence; + verifyClobValueWithString(sql_1, bigStr, specialStr, cb); + }, + function(cb) { + var sql_2 = "select blob from nodb_tab_lobs_in where id = " + sequence; + verifyBlobValueWithBuffer(sql_2, bigBuffer, specialStr, cb); + } + ], done); + }); // 80.1.1 + + it('80.1.2 PLSQL, CLOB&BLOB, bind a string and a JPG file', function(done) { + var preparedCLOBID = 701; + var sequence = 2; + var size = 40000; + var specialStr = "80.1.2"; + var bigStr = random.getRandomString(size, specialStr); + + async.series([ + function(cb) { + var sql = "INSERT INTO nodb_tab_lobs_in (id, blob) VALUES (:i, EMPTY_BLOB()) RETURNING blob INTO :lobbv"; + prepareTableWithBlob(sql, preparedCLOBID, cb); + }, + function(cb) { + connection.execute( + "select blob from nodb_tab_lobs_in where id = :id", + { id: preparedCLOBID }, + function(err, result) { + should.not.exist(err); + (result.rows.length).should.not.eql(0); + var blob = result.rows[0][0]; + + connection.execute( + sqlRun, + { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { val: bigStr, type: oracledb.STRING, dir: oracledb.BIND_IN, maxSize: size }, + b: { val: blob, type: oracledb.BLOB, dir: oracledb.BIND_IN } + }, + { autoCommit: true }, + function(err) { + should.not.exist(err); + cb(); + }); + }); + }, + function(cb) { + var sql_1 = "select clob from nodb_tab_lobs_in where id = " + sequence; + verifyClobValueWithString(sql_1, bigStr, specialStr, cb); + }, + function(cb) { + var sql_2 = "select blob from nodb_tab_lobs_in where id = " + sequence; + verifyBlobValueWithFileData(sql_2, cb); + } + ], done); + }); // 80.1.2 + + it('80.1.3 PLSQL, CLOB&BLOB, bind a txt file and a Buffer', function(done) { + var preparedCLOBID = 200; + var sequence = 303; + var size = 40000; + var specialStr = "80.1.3"; + var bigStr = random.getRandomString(size, specialStr); + var bigBuffer = node6plus ? Buffer.from(bigStr, "utf-8") : new Buffer(bigStr, "utf-8"); + + async.series([ + function(cb) { + var sql = "INSERT INTO nodb_tab_lobs_in (id, clob) VALUES (:i, EMPTY_CLOB()) RETURNING clob INTO :lobbv"; + prepareTableWithClob(sql, preparedCLOBID, cb); + }, + function(cb) { + connection.execute( + "select clob from nodb_tab_lobs_in where id = :id", + { id: preparedCLOBID }, + function(err, result) { + should.not.exist(err); + (result.rows.length).should.not.eql(0); + var clob = result.rows[0][0]; + + connection.execute( + sqlRun, + { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { val: clob, type: oracledb.CLOB, dir: oracledb.BIND_IN }, + b: { val: bigBuffer, type: oracledb.BUFFER, dir: oracledb.BIND_IN } + }, + { autoCommit: true }, + function(err) { + should.not.exist(err); + cb(); + } + ); + } + ); + }, + function(cb) { + var sql_1 = "select clob from nodb_tab_lobs_in where id = " + sequence; + verifyClobValueWithFileData(sql_1, cb); + }, + function(cb) { + var sql_2 = "select blob from nodb_tab_lobs_in where id = " + sequence; + verifyBlobValueWithBuffer(sql_2, bigBuffer, specialStr,cb); + } + ], done); + }); // 80.1.3 + + }); // 80.1 + + describe('80.2 Multiple LOBs, BIND_OUT', function() { + var proc = "CREATE OR REPLACE PROCEDURE nodb_lobs_out_782 (lob_id IN NUMBER, clob OUT CLOB, blob OUT BLOB) \n" + + "AS \n" + + "BEGIN \n" + + " select clob, blob into clob, blob from nodb_tab_lobs_in where id = lob_id; \n" + + "END nodb_lobs_out_782; "; + var sqlRun = "BEGIN nodb_lobs_out_782 (:i, :c, :b); END;"; + var proc_drop = "DROP PROCEDURE nodb_lobs_out_782"; + + before(function(done) { + executeSQL(proc, done); + }); // before + + after(function(done) { + executeSQL(proc_drop, done); + }); // after + + var insertLobs = function(id, insertStr1, insertStr2, callback) { + var sql = "INSERT INTO nodb_tab_lobs_in (id, clob, blob) VALUES (:i, :c, :b)"; + var bindVar = { + i: { val: id, dir: oracledb.BIND_IN, type: oracledb.NUMBER }, + c: { val: insertStr1, dir: oracledb.BIND_IN, type: oracledb.STRING }, + b: { val: insertStr2, dir: oracledb.BIND_IN, type: oracledb.BUFFER } + }; + + connection.execute( + sql, + bindVar, + function(err, result) { + should.not.exist(err); + should.strictEqual(result.rowsAffected, 1); + callback(); + } + ); + }; + + it('80.2.1 PLSQL, CLOB&BLOB, bind a string and a buffer', function(done) { + var length = 50000; + var specialStr = "80.2.1"; + var sequence = 311; + var bigStr = random.getRandomString(length, specialStr); + var bigBuffer = node6plus ? Buffer.from(bigStr, "utf-8") : new Buffer(bigStr, "utf-8"); + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { type: oracledb.STRING, dir: oracledb.BIND_OUT, maxSize: length }, + b: { type: oracledb.BUFFER, dir: oracledb.BIND_OUT, maxSize: length } + }; + + async.series([ + function(cb) { + insertLobs(sequence, bigStr, bigBuffer, cb); + }, + function(cb) { + var sql = "select clob from nodb_tab_lobs_in where id = " + sequence; + verifyClobValueWithString(sql, bigStr, specialStr, cb); + }, + function(cb) { + var sql = "select blob from nodb_tab_lobs_in where id = " + sequence; + verifyBlobValueWithBuffer(sql, bigBuffer, specialStr, cb); + }, + function(cb) { + connection.execute( + sqlRun, + bindVar, + function(err, result) { + should.not.exist(err); + var specStrLength = specialStr.length; + var resultLength1 = result.outBinds.c.length; + should.strictEqual(resultLength1, length); + should.strictEqual(result.outBinds.c.substring(0, specStrLength), specialStr); + should.strictEqual(result.outBinds.c.substring(resultLength1 - specStrLength, resultLength1), specialStr); + var resultLength2 = result.outBinds.b.length; + should.strictEqual(resultLength2, length); + should.strictEqual(result.outBinds.b.toString('utf8', 0, specStrLength), specialStr); + should.strictEqual(result.outBinds.b.toString('utf8', (resultLength2 - specStrLength), resultLength2), specialStr); + cb(); + }); + } + ], done); + + }); // 80.2.1 + + it('80.2.2 PLSQL, CLOB&BLOB, bind a string and a JPG file', function(done) { + var size = 40000; + var specialStr = "80.2.2"; + var bigStr = random.getRandomString(size, specialStr); + var sequence = 312; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { type: oracledb.STRING, dir: oracledb.BIND_OUT, maxSize: size }, + b: { type: oracledb.BLOB, dir: oracledb.BIND_OUT } + }; + + async.series([ + function(cb) { + var sql = "INSERT INTO nodb_tab_lobs_in (id, blob) VALUES (:i, EMPTY_BLOB()) RETURNING blob INTO :lobbv"; + prepareTableWithBlob(sql, sequence, cb); + }, + function(cb) { + var sql = "select blob from nodb_tab_lobs_in where id = " + sequence; + verifyBlobValueWithFileData(sql, cb); + }, + function(cb) { + var sql = "update nodb_tab_lobs_in set clob = :c where id = :i"; + var bindVar_1 = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { val: bigStr, type: oracledb.STRING, dir: oracledb.BIND_IN, maxSize: size } + }; + connection.execute( + sql, + bindVar_1, + function(err, result) { + should.not.exist(err); + should.strictEqual(result.rowsAffected, 1); + cb(); + }); + }, + function(cb) { + var sql = "select clob from nodb_tab_lobs_in where id = " + sequence; + verifyClobValueWithString(sql, bigStr, specialStr, cb); + }, + function(cb) { + connection.execute( + sqlRun, + bindVar, + function(err, result) { + should.not.exist(err); + var resultLength = result.outBinds.c.length; + var specStrLength = specialStr.length; + should.strictEqual(resultLength, size); + should.strictEqual(result.outBinds.c.substring(0, specStrLength), specialStr); + should.strictEqual(result.outBinds.c.substring(resultLength - specStrLength, resultLength), specialStr); + + var lob = result.outBinds.b; + var blobData = node6plus ? Buffer.alloc(0) : new Buffer(0); + var totalLength = 0; + + lob.on('data', function(chunk) { + totalLength = totalLength + chunk.length; + blobData = Buffer.concat([blobData, chunk], totalLength); + }); + + lob.on('error', function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + lob.on('end', function() { + fs.readFile( jpgFileName, function(err, originalData) { + should.not.exist(err); + should.strictEqual(totalLength, originalData.length); + originalData.should.eql(blobData); + cb(); + }); + }); + } + ); + } + ], done); + + }); // 80.2.2 + + it('80.2.3 PLSQL, CLOB&BLOB, bind a txt file and a buffer', function(done) { + var size = 40000; + var specialStr = "80.2.3"; + var bigStr = random.getRandomString(size, specialStr); + var bigBuffer = node6plus ? Buffer.from(bigStr, "utf-8") : new Buffer(bigStr, "utf-8"); + var sequence = 313; + var bindVar = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + c: { type: oracledb.CLOB, dir: oracledb.BIND_OUT }, + b: { type: oracledb.BUFFER, dir: oracledb.BIND_OUT, maxSize: size } + }; + + async.series([ + function(cb) { + var sql = "INSERT INTO nodb_tab_lobs_in (id, clob) VALUES (:i, EMPTY_CLOB()) RETURNING clob INTO :lobbv"; + prepareTableWithClob(sql, sequence, cb); + }, + function(cb) { + var sql = "select clob from nodb_tab_lobs_in where id = " + sequence; + verifyClobValueWithFileData(sql, cb); + }, + function(cb) { + var sql = "UPDATE nodb_tab_lobs_in set blob = :b where id = :i"; + var bindVar_1 = { + i: { val: sequence, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + b: { val: bigBuffer, type: oracledb.BUFFER, dir: oracledb.BIND_IN, maxSize: size } + }; + connection.execute( + sql, + bindVar_1, + function(err, result) { + should.not.exist(err); + should.strictEqual(result.rowsAffected, 1); + cb(); + }); + }, + function(cb) { + var sql = "select blob from nodb_tab_lobs_in where id = " + sequence; + verifyBlobValueWithBuffer(sql, bigBuffer, specialStr, cb); + }, + function(cb) { + connection.execute( + sqlRun, + bindVar, + function(err, result) { + should.not.exist(err); + var specStrLength = specialStr.length; + var resultLength1 = result.outBinds.b.length; + should.strictEqual(resultLength1, size); + should.strictEqual(result.outBinds.b.toString('utf8', 0, specStrLength), specialStr); + should.strictEqual(result.outBinds.b.toString('utf8', (resultLength1 - specStrLength), resultLength1), specialStr); + var lob = result.outBinds.c; + should.exist(lob); + lob.setEncoding("utf8"); + var clobData = ''; + lob.on('data', function(chunk) { + clobData += chunk; + }); + + lob.on('error', function(err) { + should.not.exist(err, "lob.on 'error' event."); + }); + + lob.on('end', function() { + fs.readFile( inFileName, { encoding: 'utf8' }, function(err, originalData) { + should.not.exist(err); + should.strictEqual(clobData, originalData); + cb(); + }); + }); + }); + } + ], done); + }); // 80.2.3 + + }); // 80.2 + + describe('80.3 Multiple LOBs, BIND_INOUT', function() { + var lobs_proc_inout = "CREATE OR REPLACE PROCEDURE nodb_lobs_in_out_783 (clob IN OUT CLOB, blob IN OUT BLOB) \n" + + "AS \n" + + "BEGIN \n" + + " clob := clob; \n" + + " blob := blob; \n" + + "END nodb_lobs_in_out_783;"; + var sqlRun = "begin nodb_lobs_in_out_783(:clob, :blob); end;"; + var proc_drop = "DROP PROCEDURE nodb_lobs_in_out_783"; + + before(function(done) { + executeSQL(lobs_proc_inout, done); + }); // before + + after(function(done) { + executeSQL(proc_drop, done); + }); // after + + it('80.3.1 PLSQL, BIND_INOUT, bind a 32K string and a 32K buffer', function(done) { + var specialStr = "80.3.1"; + var size = 32768; + var bigStr = random.getRandomString(size, specialStr); + var bufferStr = node6plus ? Buffer.from(bigStr, "utf-8") : new Buffer(bigStr, "utf-8"); + var bindVar = { + clob: { dir: oracledb.BIND_INOUT, type: oracledb.STRING, val: bigStr, maxSize: size }, + blob: { dir: oracledb.BIND_INOUT, type: oracledb.BUFFER, val: bufferStr, maxSize: size } + }; + + async.series([ + function(cb) { + connection.execute( + sqlRun, + bindVar, + function(err, result) { + should.not.exist(err); + var specStrLength = specialStr.length; + var resultLength1 = result.outBinds.clob.length; + should.strictEqual(resultLength1, size); + should.strictEqual(result.outBinds.clob.substring(0, specStrLength), specialStr); + should.strictEqual(result.outBinds.clob.substring(resultLength1 - specStrLength, resultLength1), specialStr); + var resultLength2 = result.outBinds.blob.length; + should.strictEqual(resultLength2, size); + should.strictEqual(result.outBinds.blob.toString('utf8', 0, specStrLength), specialStr); + should.strictEqual(result.outBinds.blob.toString('utf8', (resultLength2 - specStrLength), resultLength2), specialStr); + cb(); + } + ); + } + ], done); + }); // 80.3.1 + + it('80.3.2 PLSQL, BIND_INOUT, bind a (64K - 1) string and a (64K - 1) buffer', function(done) { + var specialStr = "80.3.2"; + var size = 65535; + var bigStr = random.getRandomString(size, specialStr); + var bufferStr = node6plus ? Buffer.from(bigStr, "utf-8") : new Buffer(bigStr, "utf-8"); + var bindVar = { + clob: { dir: oracledb.BIND_INOUT, type: oracledb.STRING, val: bigStr, maxSize: size }, + blob: { dir: oracledb.BIND_INOUT, type: oracledb.BUFFER, val: bufferStr, maxSize: size } + }; + + async.series([ + function(cb) { + connection.execute( + sqlRun, + bindVar, + function(err, result) { + should.not.exist(err); + var specStrLength = specialStr.length; + var resultLength1 = result.outBinds.clob.length; + should.strictEqual(resultLength1, size); + should.strictEqual(result.outBinds.clob.substring(0, specStrLength), specialStr); + should.strictEqual(result.outBinds.clob.substring(resultLength1 - specStrLength, resultLength1), specialStr); + var resultLength2 = result.outBinds.blob.length; + should.strictEqual(resultLength2, size); + should.strictEqual(result.outBinds.blob.toString('utf8', 0, specStrLength), specialStr); + should.strictEqual(result.outBinds.blob.toString('utf8', (resultLength2 - specStrLength), resultLength2), specialStr); + cb(); + } + ); + } + ], done); + }); // 80.3.2 + + }); // 80.3 + +}); diff --git a/test/lobProperties1.js b/test/lobProperties1.js new file mode 100644 index 00000000..353cbfef --- /dev/null +++ b/test/lobProperties1.js @@ -0,0 +1,478 @@ +/* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with the Apache + * License, Version 2.0 (the "License.") + * + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + * The node-oracledb test suite uses 'mocha', 'should' and 'async'. + * See LICENSE.md for relevant licenses. + * + * NAME + * 62. lobProperties1.js + * + * DESCRIPTION + * Testing getters and setters for LOB class. + * This test aims to increase the code coverage rate. + * + * NUMBERING RULE + * Test numbers follow this numbering rule: + * 1 - 20 are reserved for basic functional tests + * 21 - 50 are reserved for data type supporting tests + * 51 onwards are for other tests + * + *****************************************************************************/ +'use strict'; + +var oracledb = require('oracledb'); +var fs = require('fs'); +var should = require('should'); +var async = require('async'); +var dbConfig = require('./dbconfig.js'); + +describe('62. lobProperties1.js', function() { + + var tableName = "nodb_tab_mylobprops"; + var connection = null; + var sqlSelect = "SELECT * FROM " + tableName + " WHERE id = :i"; + var defaultChunkSize = null; + + before('prepare table and LOB data', function(done) { + + var sqlCreateTab = + " BEGIN " + + " DECLARE " + + " e_table_missing EXCEPTION; " + + " PRAGMA EXCEPTION_INIT(e_table_missing, -00942); " + + " BEGIN " + + " EXECUTE IMMEDIATE ('DROP TABLE " + tableName + " PURGE'); " + + " EXCEPTION " + + " WHEN e_table_missing " + + " THEN NULL; " + + " END; " + + " EXECUTE IMMEDIATE (' " + + " CREATE TABLE " + tableName + " ( " + + " id NUMBER, c CLOB, b BLOB " + + " ) " + + " '); " + + " END; "; + + var sqlInsert = "INSERT INTO " + tableName + " VALUES (:i, EMPTY_CLOB(), EMPTY_BLOB()) " + + " RETURNING c, b INTO :clob, :blob"; + + var bindVar = + { + i: 1, + clob: { type: oracledb.CLOB, dir: oracledb.BIND_OUT }, + blob: { type: oracledb.BLOB, dir: oracledb.BIND_OUT } + }; + var clobFileName = './test/clobexample.txt'; + var blobFileName = './test/fuzzydinosaur.jpg'; + + async.series([ + function(cb) { + oracledb.getConnection( + { + user: dbConfig.user, + password: dbConfig.password, + connectString: dbConfig.connectString + }, + function(err, conn) { + should.not.exist(err); + connection = conn; + cb(); + } + ); + }, + function(cb) { + connection.execute( + sqlCreateTab, + function(err) { + should.not.exist(err); + cb(); + } + ); + }, + function insertLobData(cb) { + connection.execute( + sqlInsert, + bindVar, + function(err, result) { + should.not.exist(err); + + var clob = result.outBinds.clob[0]; + var blob = result.outBinds.blob[0]; + var clobStream = fs.createReadStream(clobFileName); + var blobStream = fs.createReadStream(blobFileName); + + clobStream.on('error', function(err) { + should.not.exist(err); + }); + + blobStream.on('error', function(err) { + should.not.exist(err); + }); + + clob.on('error', function(err) { + should.not.exist(err); + }); + + blob.on('error', function(err) { + should.not.exist(err); + }); + + async.parallel([ + function(callback) { + clob.on('finish', function() { + callback(); + }); + }, + function(callback) { + blob.on('finish', function() { + callback(); + }); + } + ], function() { + connection.commit( function(err) { + should.not.exist(err); + cb(); + }); + }); + + clobStream.pipe(clob); + blobStream.pipe(blob); + } + ); + }, + function saveDefaultChunkSize(cb) { + connection.execute( + sqlSelect, + { i: 1 }, + function(err, result) { + should.not.exist(err); + var clob = result.rows[0][1]; + + defaultChunkSize = clob.chunkSize; + cb(); + } + ); + } + ], done); + }); // before + + after(function(done) { + + async.series([ + function(cb) { + connection.execute( + "DROP TABLE " + tableName + " PURGE", + function(err) { + should.not.exist(err); + cb(); + } + ); + }, + function(cb) { + connection.release( function(err) { + should.not.exist(err); + cb(); + }); + } + ], done); + }); // after + + it('62.1 chunkSize (read-only)', function(done) { + connection.execute( + sqlSelect, + { i: 1 }, + function(err, result) { + should.not.exist(err); + var clob = result.rows[0][1], + blob = result.rows[0][2]; + + var t1 = clob.chunkSize, + t2 = blob.chunkSize; + + t1.should.be.a.Number(); + t2.should.be.a.Number(); + t1.should.eql(t2); + defaultChunkSize = clob.chunkSize; + + try { + clob.chunkSize = t1 + 1; + } catch(err) { + should.exist(err); + // console.log(err.message); + // Cannot assign to read only property 'chunkSize' of # + } + + try { + blob.chunkSize = t2 + 1; + } catch(err) { + should.exist(err); + // console.log(err.message); + // Cannot assign to read only property 'chunkSize' of # + } + done(); + } + ); + }); // 62.1 + + it('62.2 length (read-only)', function(done) { + connection.execute( + sqlSelect, + { i: 1 }, + function(err, result) { + should.not.exist(err); + var clob = result.rows[0][1], + blob = result.rows[0][2]; + + var t1 = clob.length, + t2 = blob.length; + + t1.should.be.a.Number(); + t2.should.be.a.Number(); + t1.should.not.eql(t2); + + try { + clob.length = t1 + 1; + } catch(err) { + should.exist(err); + //console.log(err.message); + // Cannot set property length of # which has only a getter + } + + try { + blob.length = t2 + 1; + } catch(err) { + should.exist(err); + //console.log(err.message); + // Cannot set property length of # which has only a getter + } + done(); + } + ); + }); // 62.2 + + it('62.3 pieceSize -default value is chunkSize', function(done) { + connection.execute( + sqlSelect, + { i: 1 }, + function(err, result) { + should.not.exist(err); + var clob = result.rows[0][1], + blob = result.rows[0][2]; + + var t1 = clob.pieceSize, + t2 = blob.pieceSize; + t1.should.eql(defaultChunkSize); + t2.should.eql(defaultChunkSize); + done(); + } + ); + }); // 62.3 + + it('62.4 pieceSize - can be increased', function(done) { + connection.execute( + sqlSelect, + { i: 1 }, + function(err, result) { + should.not.exist(err); + var clob = result.rows[0][1], + blob = result.rows[0][2]; + + var newValue = clob.pieceSize * 5; + + clob.pieceSize = clob.pieceSize * 5; + blob.pieceSize = blob.pieceSize * 5; + + (clob.pieceSize).should.eql(newValue); + (blob.pieceSize).should.eql(newValue); + + // Remember to restore the value + clob.pieceSize = defaultChunkSize; + blob.pieceSize = defaultChunkSize; + + done(); + } + ); + }); // 62.4 + + it('62.5 pieceSize - can be decreased', function(done) { + if (defaultChunkSize <= 500) { + console.log('As default chunkSize is too small, this case is not applicable'); + done(); + } else { + connection.execute( + sqlSelect, + { i: 1 }, + function(err, result) { + should.not.exist(err); + var clob = result.rows[0][1], + blob = result.rows[0][2]; + + var newValue = clob.pieceSize - 500; + + clob.pieceSize -= 500; + blob.pieceSize -= 500; + (clob.pieceSize).should.eql(newValue); + (blob.pieceSize).should.eql(newValue); + + // Restore + clob.pieceSize = defaultChunkSize; + blob.pieceSize = defaultChunkSize; + + done(); + } + ); + } + }); // 62.5 + + it('62.6 pieceSize - can be zero', function(done) { + connection.execute( + sqlSelect, + { i: 1 }, + function(err, result) { + should.not.exist(err); + var clob = result.rows[0][1], + blob = result.rows[0][2]; + + clob.pieceSize = 0; + blob.pieceSize = 0; + + (clob.pieceSize).should.eql(0); + (blob.pieceSize).should.eql(0); + + // Remember to restore the value + clob.pieceSize = defaultChunkSize; + blob.pieceSize = defaultChunkSize; + + done(); + } + ); + }); // 62.6 + + it('62.7 pieceSize - cannot be less than zero', function(done) { + connection.execute( + sqlSelect, + { i: 1 }, + function(err, result) { + should.not.exist(err); + var clob = result.rows[0][1], + blob = result.rows[0][2]; + + try { + clob.pieceSize = -100; + } catch(err) { + should.exist(err); + (err.message).should.startWith('NJS-004:'); + // NJS-004: invalid value for property pieceSize + } + + // Remember to restore the value + clob.pieceSize = defaultChunkSize; + blob.pieceSize = defaultChunkSize; + + done(); + } + ); + }); // 62.7 + + it('62.8 pieceSize - cannot be null', function(done) { + connection.execute( + sqlSelect, + { i: 1 }, + function(err, result) { + should.not.exist(err); + var clob = result.rows[0][1], + blob = result.rows[0][2]; + + try { + clob.pieceSize = null; + } catch(err) { + should.exist(err); + (err.message).should.startWith('NJS-004:'); + // NJS-004: invalid value for property pieceSize + } + + // Remember to restore the value + clob.pieceSize = defaultChunkSize; + blob.pieceSize = defaultChunkSize; + + done(); + } + ); + }); // 62.8 + + it('62.9 pieceSize - must be a number', function(done) { + connection.execute( + sqlSelect, + { i: 1 }, + function(err, result) { + should.not.exist(err); + var clob = result.rows[0][1], + blob = result.rows[0][2]; + + try { + clob.pieceSize = NaN; + } catch(err) { + should.exist(err); + (err.message).should.startWith('NJS-004:'); + // NJS-004: invalid value for property pieceSize + } + + // Remember to restore the value + clob.pieceSize = defaultChunkSize; + blob.pieceSize = defaultChunkSize; + + done(); + } + ); + }); // 62.9 + + it('62.10 type (read-only)', function(done) { + connection.execute( + sqlSelect, + { i: 1 }, + function(err, result) { + should.not.exist(err); + var clob = result.rows[0][1], + blob = result.rows[0][2]; + + var t1 = clob.type, + t2 = blob.type; + + t1.should.eql(oracledb.CLOB); + t2.should.eql(oracledb.BLOB); + + try { + clob.type = t2; + } catch(err) { + should.exist(err); + // console.log(err); + // [TypeError: Cannot set property type of # which has only a getter] + } + + try { + blob.type = t1; + } catch(err) { + should.exist(err); + // console.log(err); + // [TypeError: Cannot set property type of # which has only a getter] + } + + done(); + } + ); + }); // 62.10 +}); diff --git a/test/lobProperties2.js b/test/lobProperties2.js new file mode 100644 index 00000000..6eef8777 --- /dev/null +++ b/test/lobProperties2.js @@ -0,0 +1,294 @@ +/* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with the Apache + * License, Version 2.0 (the "License.") + * + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + * The node-oracledb test suite uses 'mocha', 'should' and 'async'. + * See LICENSE.md for relevant licenses. + * + * NAME + * 83. lobProperties2.js + * + * DESCRIPTION + * Testing the properties of LOB that created by createLob(). + * + * NUMBERING RULE + * Test numbers follow this numbering rule: + * 1 - 20 are reserved for basic functional tests + * 21 - 50 are reserved for data type supporting tests + * 51 onwards are for other tests + * + *****************************************************************************/ +'use strict'; + +var oracledb = require('oracledb'); +var should = require('should'); +var async = require('async'); +var dbConfig = require('./dbconfig.js'); + +describe("83. lobProperties2.js", function() { + + var connection; + + before(function(done) { + oracledb.getConnection(dbConfig, function(err, conn) { + should.not.exist(err); + connection = conn; + done(); + }); + }); // before + + after(function(done) { + connection.close(function(err) { + should.not.exist(err); + done(); + }); + }); + + var checkChunkSize = function(type, callback) { + + connection.createLob(type, function(err, lob) { + should.not.exist(err); + + var t = lob.chunkSize; + t.should.be.a.Number(); + + try { + lob.chunkSize = t + 1; + } catch(err) { + should.exist(err); + // Cannot assign to read only property 'chunkSize' of object '#' + } + + lob.close(function(err) { + should.not.exist(err); + return callback(); + }); + + }); + }; // checkChunkSize + + it("83.1 CLOB: chunkSize (read-only)", function(done) { + checkChunkSize(oracledb.CLOB, done); + }); + + it("83.2 BLOB: chunkSize (read-only)", function(done) { + checkChunkSize(oracledb.BLOB, done); + }); + + var checkLength = function(type, callback) { + + connection.createLob(type, function(err, lob) { + should.not.exist(err); + + var t = lob.length; + t.should.be.a.Number(); + + try { + lob.length = t + 1; + } catch(err) { + should.exist(err); + // Cannot set property length of # which has only a getter + } + + lob.close(function(err) { + should.not.exist(err); + return callback(); + }); + }); + }; // checkLength + + it("83.3 CLOB: length (read-only)", function(done) { + checkLength(oracledb.CLOB, done); + }); + + it("83.4 BLOB: length (read-only)", function(done) { + checkLength(oracledb.BLOB, done); + }); + + var checkType = function(lobtype, callback) { + + connection.createLob(lobtype, function(err, lob) { + should.not.exist(err); + + var t = lob.type; + t.should.eql(lobtype); + + try { + lob.type = oracledb.BUFFER; + } catch(err) { + should.exist(err); + // Cannot set property type of # which has only a getter + } + + lob.close(function(err) { + should.not.exist(err); + return callback(); + }); + }); + }; // checkType + + it("83.5 CLOB: type (read-only)", function(done) { + checkType(oracledb.CLOB, done); + }); + + it("83.6 BLOB: type (read-only)", function(done) { + checkType(oracledb.CLOB, done); + }); + + describe("83.7 pieceSize", function() { + + var defaultChunkSize; + var clob, blob; + + before("get the lobs", function(done) { + async.parallel([ + function(cb) { + connection.createLob(oracledb.CLOB, function(err, lob) { + should.not.exist(err); + + clob = lob; + defaultChunkSize = clob.chunkSize; + cb(); + }); + }, + function(cb) { + connection.createLob(oracledb.BLOB, function(err, lob) { + should.not.exist(err); + + blob = lob; + cb(); + }); + } + ], done); + }); // before + + after("close the lobs", function(done) { + async.parallel([ + function(cb) { + clob.close(cb); + }, + function(cb) { + blob.close(cb); + } + ], done); + }); // after + + it("83.7.1 default value is chunkSize", function(done) { + var t1 = clob.pieceSize, + t2 = blob.pieceSize; + + t1.should.eql(defaultChunkSize); + t2.should.eql(defaultChunkSize); + done(); + }); + + it("83.7.2 can be increased", function(done) { + var newValue = clob.pieceSize * 5; + + clob.pieceSize = clob.pieceSize * 5; + blob.pieceSize = blob.pieceSize * 5; + + (clob.pieceSize).should.eql(newValue); + (blob.pieceSize).should.eql(newValue); + + clob.pieceSize = defaultChunkSize; + blob.pieceSize = defaultChunkSize; + + done(); + }); + + it("83.7.3 can be decreased", function(done) { + if (defaultChunkSize <= 500) { + console.log('As default chunkSize is too small, this case is not applicable'); + } else { + var newValue = clob.pieceSize - 500; + + clob.pieceSize -= 500; + blob.pieceSize -= 500; + (clob.pieceSize).should.eql(newValue); + (blob.pieceSize).should.eql(newValue); + + // Restore + clob.pieceSize = defaultChunkSize; + blob.pieceSize = defaultChunkSize; + } + return done(); + }); + + it("83.7.4 can be zero", function(done) { + clob.pieceSize = 0; + blob.pieceSize = 0; + + (clob.pieceSize).should.eql(0); + (blob.pieceSize).should.eql(0); + + // Remember to restore the value + clob.pieceSize = defaultChunkSize; + blob.pieceSize = defaultChunkSize; + + done(); + }); + + it("83.7.5 cannot be less than zero", function(done) { + try { + clob.pieceSize = -100; + } catch(err) { + should.exist(err); + (err.message).should.startWith('NJS-004:'); + // NJS-004: invalid value for property pieceSize + } + + // Remember to restore the value + clob.pieceSize = defaultChunkSize; + blob.pieceSize = defaultChunkSize; + + done(); + }); + + it("83.7.6 cannot be null", function(done) { + try { + clob.pieceSize = null; + } catch(err) { + should.exist(err); + (err.message).should.startWith('NJS-004:'); + // NJS-004: invalid value for property pieceSize + } + + // Remember to restore the value + clob.pieceSize = defaultChunkSize; + blob.pieceSize = defaultChunkSize; + + done(); + }); + + it("83.7.7 must be a number", function(done) { + try { + clob.pieceSize = NaN; + } catch(err) { + should.exist(err); + (err.message).should.startWith('NJS-004:'); + // NJS-004: invalid value for property pieceSize + } + + // Remember to restore the value + clob.pieceSize = defaultChunkSize; + blob.pieceSize = defaultChunkSize; + + done(); + }); + }); // 83.7 + +}); diff --git a/test/multipleLobInsertion.js b/test/multipleLobInsertion.js new file mode 100644 index 00000000..1cb267be --- /dev/null +++ b/test/multipleLobInsertion.js @@ -0,0 +1,249 @@ +/* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with the Apache + * License, Version 2.0 (the "License.") + * + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + * The node-oracledb test suite uses 'mocha', 'should' and 'async'. + * See LICENSE.md for relevant licenses. + * + * NAME + * 68. multipleLobInsertion.js + * + * DESCRIPTION + * Testing external authentication functionality. + * + * Note that enabling the externalAuth feature requires configuration on the + * database besides setting "externalAuth" attribute to be true. Please refer + * to api doc about the configuration. + * https://github.com/oracle/node-oracledb/blob/master/doc/api.md#extauth + * + * NUMBERING RULE + * Test numbers follow this numbering rule: + * 1 - 20 are reserved for basic functional tests + * 21 - 50 are reserved for data type supporting tests + * 51 onwards are for other tests + * + *****************************************************************************/ +'use strict'; + +var oracledb = require('oracledb'); +var should = require('should'); +var async = require('async'); +var fs = require('fs'); +var dbConfig = require('./dbconfig.js'); + +describe('68. multipleLobInsertion.js', function() { + + var connection = null; + before(function(done) { + + async.series([ + function getConn(cb) { + oracledb.getConnection( + dbConfig, + function(err, conn) { + should.not.exist(err); + connection = conn; + cb(); + } + ); + }, + function createTabBLOB(cb) { + var proc = "BEGIN \n" + + " DECLARE \n" + + " e_table_missing EXCEPTION; \n" + + " PRAGMA EXCEPTION_INIT(e_table_missing, -00942); \n" + + " BEGIN \n" + + " EXECUTE IMMEDIATE('DROP TABLE nodb_multi_blob PURGE'); \n" + + " EXCEPTION \n" + + " WHEN e_table_missing \n" + + " THEN NULL; \n" + + " END; \n" + + " EXECUTE IMMEDIATE (' \n" + + " CREATE TABLE nodb_multi_blob ( \n" + + " id NUMBER, \n" + + " b1 BLOB, \n" + + " b2 BLOB, \n" + + " b3 BLOB, \n" + + " b4 BLOB, \n" + + " b5 BLOB \n" + + " ) \n" + + " '); \n" + + "END; "; + + connection.execute( + proc, + function(err) { + should.not.exist(err); + cb(); + } + ); + }, + function createTabCLOB(cb) { + var proc = "BEGIN \n" + + " DECLARE \n" + + " e_table_missing EXCEPTION; \n" + + " PRAGMA EXCEPTION_INIT(e_table_missing, -00942); \n" + + " BEGIN \n" + + " EXECUTE IMMEDIATE('DROP TABLE nodb_multi_clob PURGE'); \n" + + " EXCEPTION \n" + + " WHEN e_table_missing \n" + + " THEN NULL; \n" + + " END; \n" + + " EXECUTE IMMEDIATE (' \n" + + " CREATE TABLE nodb_multi_clob ( \n" + + " id NUMBER, \n" + + " c1 CLOB, \n" + + " c2 CLOB, \n" + + " c3 CLOB, \n" + + " c4 CLOB, \n" + + " c5 CLOB \n" + + " ) \n" + + " '); \n" + + "END; "; + + connection.execute( + proc, + function(err) { + should.not.exist(err); + cb(); + } + ); + } + ], done); + + }); // before + + after(function(done) { + async.series([ + function(cb) { + connection.execute( + "DROP TABLE nodb_multi_clob PURGE", + function(err) { + should.not.exist(err); + cb(); + } + ); + }, + function(cb) { + connection.execute( + "DROP TABLE nodb_multi_blob PURGE", + function(err) { + should.not.exist(err); + cb(); + } + ); + }, + function(cb) { + connection.release(function(err) { + should.not.exist(err); + cb(); + }); + } + ], done); + }); // after + + var lobInsert = function(sql, bindv, inFileName, cb) { + + connection.execute( + sql, + bindv, + { autoCommit: false }, + function(err, result) { + should.not.exist(err); + + var lobArr = new Array(); + + // put lobbv1..5 to lobArr + for(var item in result.outBinds) { + lobArr.push(result.outBinds[item][0]); + } + + async.eachSeries( + lobArr, + function(lob, callback) { + var inStream = fs.createReadStream(inFileName); + + inStream.pipe(lob); + + // one task completes + lob.on('finish', function() { + return callback(); + }); + + lob.on('error', function(err) { + return callback(err); + }); + + inStream.on('error', function(err) { + return callback(err); + }); + }, + function(err) { + should.not.exist(err); + + connection.commit(function(err) { + should.not.exist(err); + return cb(); + }); + } + ); // async.eachSeries + + } + ); + + }; + + it('68.1 inserts multiple BLOBs', function(done) { + + var sql = "insert into nodb_multi_blob values(1, " + + " EMPTY_BLOB(), EMPTY_BLOB(), EMPTY_BLOB(), EMPTY_BLOB(), EMPTY_BLOB() ) " + + " returning b1, b2, b3, b4, b5 into :lobbv1, :lobbv2, :lobbv3, :lobbv4, :lobbv5"; + + var bindvars = { + lobbv1: { type: oracledb.BLOB, dir: oracledb.BIND_OUT }, + lobbv2: { type: oracledb.BLOB, dir: oracledb.BIND_OUT }, + lobbv3: { type: oracledb.BLOB, dir: oracledb.BIND_OUT }, + lobbv4: { type: oracledb.BLOB, dir: oracledb.BIND_OUT }, + lobbv5: { type: oracledb.BLOB, dir: oracledb.BIND_OUT } + }; + + var inFileName = './test/fuzzydinosaur.jpg'; + + lobInsert(sql, bindvars, inFileName, done); + + }); // 68.1 + + it('68.2 inserts multiple CLOBs', function(done) { + + var sql = "insert into nodb_multi_clob values(1, " + + " EMPTY_CLOB(), EMPTY_CLOB(), EMPTY_CLOB(), EMPTY_CLOB(), EMPTY_CLOB() ) " + + " returning c1, c2, c3, c4, c5 into :lobbv1, :lobbv2, :lobbv3, :lobbv4, :lobbv5"; + + var bindvars = { + lobbv1: { type: oracledb.CLOB, dir: oracledb.BIND_OUT }, + lobbv2: { type: oracledb.CLOB, dir: oracledb.BIND_OUT }, + lobbv3: { type: oracledb.CLOB, dir: oracledb.BIND_OUT }, + lobbv4: { type: oracledb.CLOB, dir: oracledb.BIND_OUT }, + lobbv5: { type: oracledb.CLOB, dir: oracledb.BIND_OUT } + }; + + var inFileName = './test/clobexample.txt'; + + lobInsert(sql, bindvars, inFileName, done); + + }); + +}); diff --git a/test/opts/mocha.opts b/test/opts/mocha.opts new file mode 100644 index 00000000..b524d0f4 --- /dev/null +++ b/test/opts/mocha.opts @@ -0,0 +1,128 @@ +--require should +--require async +--reporter spec +--ui bdd +--timeout 100000 + +test/connection.js +test/pool.js +test/examples.js +test/binding.js +test/externalAuth.js +test/dmlReturning.js +test/autoCommit.js +test/autoCommitForSelect.js +test/columnMetadata.js +test/nullColumnValues.js + +test/resultSet1.js +test/stream1.js +test/stream2.js +test/resultsetToStream.js +test/promises.js +test/extendedMetaData.js +test/constants.js +test/fetchTimestampAsString.js +test/dataTypeAssist.js +test/dataTypeChar.js + +test/dataTypeNchar.js +test/dataTypeVarchar2.js +test/dataTypeNvarchar2.js +test/dataTypeNumber.js +test/dataTypeNumber2.js +test/dataTypeFloat.js +test/dataTypeFloat2.js +test/dataTypeBinaryFloat.js +test/dataTypeBinaryDouble.js +test/dataTypeDate.js + +test/dataTypeTimestamp1.js +test/dataTypeTimestamp2.js +test/dataTypeTimestamp3.js +test/dataTypeTimestamp4.js +test/dataTypeTimestamp5.js +test/dataTypeTimestamp6.js +test/dataTypeRowid.js +test/dataTypeClob.js +test/dataTypeBlob.js +test/dataTypeRaw.js + +test/plsqlBindIndexedTable1.js +test/plsqlBindIndexedTable2.js +test/instanceof.js +test/poolClose.js +test/connClose.js +test/resultSetClose.js +test/resultSet2.js +test/fetchAs.js +test/nestedCursor.js + +test/properties.js +test/lobResultSet.js +test/clobPlsqlString.js +test/checkClassesTypes.js +test/lobProperties1.js +test/autoCommit4nestedExecutes.js +test/sqlWithWarnings.js +test/uninitializedLob.js +test/writableProperties.js +test/poolCache.js +test/multipleLobInsertion.js +test/driverName.js +test/plsqlBindScalar.js +test/lobBind1.js +test/lobBind2.js +test/poolPing.js +test/clobPlsqlBindAsString_bindin.js +test/clobPlsqlBindAsString_bindout.js +test/clobPlsqlBindAsString_bindinout.js +test/blobPlsqlBindAsBuffer_bindin.js +test/blobPlsqlBindAsBuffer_bindout.js +test/blobPlsqlBindAsBuffer_bindinout.js +test/lobBindAsStringBuffer.js +test/clobDMLBindAsString.js +test/blobDMLBindAsBuffer.js +test/lobProperties2.js +test/fetchClobAsString1.js +test/fetchClobAsString2.js +test/fetchClobAsString3.js +test/fetchBlobAsBuffer1.js +test/fetchBlobAsBuffer2.js +test/fetchBlobAsBuffer3.js +test/fetchClobAsString4.js +test/fetchBlobAsBuffer4.js +test/binding_DMLInsert.js +test/binding_procedureBindIn.js +test/binding_procedureBindInout.js +test/binding_functionBindInout.js +test/binding_procedureBindOut.js +test/binding_functionBindOut.js +test/binding_DMLReturningInto.js +test/binding_functionBindIn.js +test/binding_defaultBindIn.js +test/binding_defaultBindInout.js +test/bindTimestamp.js +test/dataTypeLong.js +test/dataTypeLongRaw.js +test/fetchRowidAsString.js +test/rowidDMLBindAsString.js +test/rowidProcedureBindAsString_bindin.js +test/rowidFunctionBindAsString_bind.js +test/rowidProcedureBindAsString_bindout.js +test/rowidProcedureBindAsString_bindinout.js +test/rowidFunctionBindAsString_bindinout.js +test/dataTypeUrowid.js +test/urowidDMLBindAsString.js +test/urowidDMLBindAsString_indexed.js +test/fetchUrowidAsString.js +test/fetchUrowidAsString_indexed.js +test/urowidProcedureBindAsString_bindin.js +test/urowidProcedureBindAsString_bindout.js +test/urowidProcedureBindAsString_bindinout.js +test/urowidFunctionBindAsString_bind.js +test/urowidFunctionBindAsString_bindinout.js +test/dataTypeNclob.js +test/nclobDMLBindAsString.js +test/longDMLBind.js +test/longrawDMLBind.js diff --git a/test/opts/versions.js b/test/opts/versions.js new file mode 100644 index 00000000..b1dbadaf --- /dev/null +++ b/test/opts/versions.js @@ -0,0 +1,68 @@ +/* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with the Apache + * License, Version 2.0 (the "License.") + * + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + * NAME + * versions.js + * + * DESCRIPTION + * Shows the oracledb version attributes + * + *****************************************************************************/ + +var oracledb = require('oracledb'); +var dbConfig = require('../dbconfig.js'); + +var addonVer, clientVer, serverVer; +var major, minor, update, port, portUpdate; + +console.log("Node.js: " + process.version); + +addonVer = oracledb.version; +major = Math.floor(addonVer / 10000); +minor = Math.floor(addonVer / 100) % 100; +update = addonVer % 100; +console.log("Node-oracledb: " + major + "." + minor + "." + update); + +clientVer = oracledb.oracleClientVersion; +major = Math.floor (clientVer / 100000000); +minor = Math.floor (clientVer / 1000000) % 100 ; +update = Math.floor (clientVer / 10000) % 100 ; +port = Math.floor (clientVer / 100) % 100 ; +portUpdate = clientVer % 100 ; +console.log("Oracle Client library: " + major + "." + minor + "." + update + "." + port + "." + portUpdate); + +oracledb.getConnection( + { + user : dbConfig.user, + password : dbConfig.password, + connectString : dbConfig.connectString + }, + function(err, connection) + { + if (err) { + console.error(err.message); + return; + } + + serverVer = connection.oracleServerVersion; + major = Math.floor (serverVer / 100000000); + minor = Math.floor (serverVer / 1000000) % 100 ; + update = Math.floor (serverVer / 10000) % 100 ; + port = Math.floor (serverVer / 100) % 100 ; + portUpdate = serverVer % 100 ; + console.log("Oracle Database: " + major + "." + minor + "." + update + "." + port + "." + portUpdate + "\n"); + }); diff --git a/test/plsqlBindIndexedTable1.js b/test/plsqlBindIndexedTable1.js new file mode 100644 index 00000000..f0aae467 --- /dev/null +++ b/test/plsqlBindIndexedTable1.js @@ -0,0 +1,1120 @@ +/* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with the Apache + * License, Version 2.0 (the "License.") + * + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + * The node-oracledb test suite uses 'mocha', 'should' and 'async'. + * See LICENSE.md for relevant licenses. + * + * NAME + * 43. plsqlBindIndexedTable1.js + * + * DESCRIPTION + * Testing PL/SQL indexed tables (associative arrays). + * + * NUMBERING RULE + * Test numbers follow this numbering rule: + * 1 - 20 are reserved for basic functional tests + * 21 - 50 are reserved for data type supporting tests + * 51 onwards are for other tests + * + *****************************************************************************/ +'use strict'; + +var oracledb = require('oracledb'); +var should = require('should'); +var async = require('async'); +var dbConfig = require('./dbconfig.js'); + +describe('43. plsqlBindIndexedTable1.js', function() { + + var credentials = { + user: dbConfig.user, + password: dbConfig.password, + connectString: dbConfig.connectString + }; + + describe('43.1 binding PL/SQL indexed table', function() { + var connection = null; + + before(function(done) { + oracledb.getConnection(credentials, function(err, conn) { + if(err) { console.error(err.message); return; } + connection = conn; + done(); + }); + }); + + after(function(done) { + connection.release( function(err) { + if(err) { console.error(err.message); return; } + done(); + }); + }); + + it('43.1.1 binding PL/SQL indexed table IN by name', function(done) { + async.series([ + function(callback) { + var proc = "CREATE OR REPLACE PACKAGE\n" + + "nodb_plsqlbindpack1\n" + + "IS\n" + + " TYPE stringsType IS TABLE OF VARCHAR2(30) INDEX BY BINARY_INTEGER;\n" + + " TYPE numbersType IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;\n" + + " FUNCTION test(strings IN stringsType, numbers IN numbersType) RETURN VARCHAR2;\n" + + "END;"; + connection.should.be.ok(); + connection.execute( + proc, + function(err) { + should.not.exist(err); + callback(); + } + ); + }, + function(callback) { + var proc = "CREATE OR REPLACE PACKAGE BODY\n" + + "nodb_plsqlbindpack1\n" + + "IS\n" + + " FUNCTION test(strings IN stringsType, numbers IN numbersType) RETURN VARCHAR2\n" + + " IS\n" + + " s VARCHAR2(2000) := '';\n" + + " BEGIN\n" + + " FOR i IN 1 .. strings.COUNT LOOP\n" + + " s := s || strings(i);\n" + + " END LOOP;\n" + + " FOR i IN 1 .. numbers.COUNT LOOP\n" + + " s := s || numbers(i);\n" + + " END LOOP;\n" + + " RETURN s;\n" + + " END;\n" + + "END;"; + connection.should.be.ok(); + connection.execute( + proc, + function(err) { + should.not.exist(err); + callback(); + } + ); + }, + function(callback) { + var bindvars = { + result: {type: oracledb.STRING, dir: oracledb.BIND_OUT, maxSize: 2000}, + strings: {type: oracledb.STRING, dir: oracledb.BIND_IN, val: ['John', 'Doe']}, + numbers: {type: oracledb.NUMBER, dir: oracledb.BIND_IN, val: [0, 8, 11]} + }; + connection.execute( + "BEGIN :result := nodb_plsqlbindpack1.test(:strings, :numbers); END;", + bindvars, + function(err, result) { + should.not.exist(err); + // console.log(result); + result.outBinds.result.should.be.exactly('JohnDoe0811'); + callback(); + } + ); + }, + function(callback) { + connection.execute( + "DROP PACKAGE nodb_plsqlbindpack1", + function(err) { + should.not.exist(err); + callback(); + } + ); + } + ], done); + }); + + it('43.1.2 binding PL/SQL indexed table IN by position', function(done) { + async.series([ + function(callback) { + var proc = "CREATE OR REPLACE PACKAGE\n" + + "nodb_plsqlbindpack2\n" + + "IS\n" + + " TYPE stringsType IS TABLE OF VARCHAR2(30) INDEX BY BINARY_INTEGER;\n" + + " TYPE numbersType IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;\n" + + " PROCEDURE test(s IN stringsType, n IN numbersType);\n" + + "END;"; + connection.should.be.ok(); + connection.execute( + proc, + function(err) { + should.not.exist(err); + callback(); + } + ); + }, + function(callback) { + var proc = "CREATE OR REPLACE PACKAGE BODY\n" + + "nodb_plsqlbindpack2\n" + + "IS\n" + + " PROCEDURE test(s IN stringsType, n IN numbersType)\n" + + " IS\n" + + " BEGIN\n" + + " IF (s(1) IS NULL OR s(1) <> 'John') THEN\n" + + " raise_application_error(-20000, 'Invalid s(1): \"' || s(1) || '\"');\n" + + " END IF;\n" + + " IF (s(2) IS NULL OR s(2) <> 'Doe') THEN\n" + + " raise_application_error(-20000, 'Invalid s(2): \"' || s(2) || '\"');\n" + + " END IF;\n" + + " END;\n" + + "END;"; + connection.should.be.ok(); + connection.execute( + proc, + function(err) { + should.not.exist(err); + callback(); + } + ); + }, + function(callback) { + var bindvars = [ + {type: oracledb.STRING, dir: oracledb.BIND_IN, val: ['John', 'Doe']}, + {type: oracledb.NUMBER, dir: oracledb.BIND_IN, val: [8, 11]} + ]; + connection.execute( + "BEGIN nodb_plsqlbindpack2.test(:1, :2); END;", + bindvars, + function(err) { + should.not.exist(err); + // console.log(result); + callback(); + } + ); + }, + function(callback) { + connection.execute( + "DROP PACKAGE nodb_plsqlbindpack2", + function(err) { + should.not.exist(err); + callback(); + } + ); + } + ], done); + }); + + it('43.1.3 binding PL/SQL indexed table IN OUT', function(done) { + async.series([ + function(callback) { + var proc = "CREATE OR REPLACE PACKAGE\n" + + "nodb_plsqlbindpack3\n" + + "IS\n" + + " TYPE stringsType IS TABLE OF VARCHAR2(30) INDEX BY BINARY_INTEGER;\n" + + " TYPE numbersType IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;\n" + + " PROCEDURE test(strings IN OUT NOCOPY stringsType, numbers IN OUT NOCOPY numbersType);\n" + + "END;"; + connection.should.be.ok(); + connection.execute( + proc, + function(err) { + should.not.exist(err); + callback(); + } + ); + }, + function(callback) { + var proc = "CREATE OR REPLACE PACKAGE BODY\n" + + "nodb_plsqlbindpack3\n" + + "IS\n" + + " PROCEDURE test(strings IN OUT NOCOPY stringsType, numbers IN OUT NOCOPY numbersType)\n" + + " IS\n" + + " BEGIN\n" + + " FOR i IN 1 .. strings.COUNT LOOP\n" + + " strings(i) := '(' || strings(i) || ')';\n" + + " END LOOP;\n" + + " FOR i IN 1 .. numbers.COUNT LOOP\n" + + " numbers(i) := numbers(i) * 10;\n" + + " END LOOP;\n" + + " numbers(numbers.COUNT + 1) := 4711;\n" + + " END;\n" + + "END;"; + connection.should.be.ok(); + connection.execute( + proc, + function(err) { + should.not.exist(err); + callback(); + } + ); + }, + function(callback) { + var bindvars = { + strings: {type: oracledb.STRING, dir: oracledb.BIND_INOUT, val: ['John', 'Doe'], maxArraySize: 2}, + numbers: {type: oracledb.NUMBER, dir: oracledb.BIND_INOUT, val: [1, 2, 3], maxArraySize: 4} + }; + connection.execute( + "BEGIN nodb_plsqlbindpack3.test(:strings, :numbers); END;", + bindvars, + function(err, result) { + should.not.exist(err); + //console.log(result); + should.deepEqual(result.outBinds.strings, ['(John)', '(Doe)']); + should.deepEqual(result.outBinds.numbers, [10, 20, 30, 4711]); + callback(); + } + ); + }, + function(callback) { + connection.execute( + "DROP PACKAGE nodb_plsqlbindpack3", + function(err) { + should.not.exist(err); + callback(); + } + ); + } + ], done); + }); + + it('43.1.4 binding PL/SQL indexed table OUT', function(done) { + async.series([ + function(callback) { + var proc = "CREATE OR REPLACE PACKAGE\n" + + "nodb_plsqlbindpack4\n" + + "IS\n" + + " TYPE stringsType IS TABLE OF VARCHAR2(30) INDEX BY BINARY_INTEGER;\n" + + " TYPE numbersType IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;\n" + + " PROCEDURE test(items IN NUMBER, strings OUT NOCOPY stringsType, numbers OUT NOCOPY numbersType);\n" + + "END;"; + connection.should.be.ok(); + connection.execute( + proc, + function(err) { + should.not.exist(err); + callback(); + } + ); + }, + function(callback) { + var proc = "CREATE OR REPLACE PACKAGE BODY\n" + + "nodb_plsqlbindpack4\n" + + "IS\n" + + " PROCEDURE test(items IN NUMBER, strings OUT NOCOPY stringsType, numbers OUT NOCOPY numbersType)\n" + + " IS\n" + + " BEGIN\n" + + " FOR i IN 1 .. items LOOP\n" + + " strings(i) := i;\n" + + " END LOOP;\n" + + " FOR i IN 1 .. items LOOP\n" + + " numbers(i) := i;\n" + + " END LOOP;\n" + + " END;\n" + + "END;"; + connection.should.be.ok(); + connection.execute( + proc, + function(err) { + should.not.exist(err); + callback(); + } + ); + }, + function(callback) { + var bindvars = { + items: {type: oracledb.NUMBER, dir: oracledb.BIND_IN, val: 3}, + strings: {type: oracledb.STRING, dir: oracledb.BIND_OUT, maxArraySize: 3}, + numbers: {type: oracledb.NUMBER, dir: oracledb.BIND_OUT, maxArraySize: 3} + }; + connection.execute( + "BEGIN nodb_plsqlbindpack4.test(:items, :strings, :numbers); END;", + bindvars, + function(err, result) { + should.not.exist(err); + //console.log(result); + should.deepEqual(result.outBinds.strings, ['1', '2', '3']); + should.deepEqual(result.outBinds.numbers, [1, 2, 3]); + callback(); + } + ); + }, + function(callback) { + connection.execute( + "DROP PACKAGE nodb_plsqlbindpack4", + function(err) { + should.not.exist(err); + callback(); + } + ); + } + ], done); + }); + + }); + + describe('43.2 test exceptions when using PL/SQL indexed table bindings', function() { + var connection = null; + + before(function(done) { + async.series([ + function(callback) { + oracledb.getConnection(credentials, function(err, conn) { + should.not.exist(err); + connection = conn; + callback(); + }); + }, + function(callback) { + var proc = "CREATE OR REPLACE PACKAGE\n" + + "nodb_plsqlbindpack21\n" + + "IS\n" + + " TYPE datesType IS TABLE OF DATE INDEX BY BINARY_INTEGER;\n" + + " TYPE numbersType IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;\n" + + " TYPE stringsType IS TABLE OF VARCHAR2(2000) INDEX BY BINARY_INTEGER;\n" + + " PROCEDURE test1(p IN numbersType);\n" + + " PROCEDURE test2(p IN OUT NOCOPY numbersType);\n" + + " PROCEDURE test3(p IN datesType);\n" + + " PROCEDURE test4(id IN numbersType, p IN datesType);\n" + + " PROCEDURE test5(p OUT stringsType);\n" + + "END;"; + connection.should.be.ok(); + connection.execute( + proc, + function(err) { + should.not.exist(err); + callback(); + } + ); + }, + function(callback) { + var proc = "CREATE OR REPLACE PACKAGE BODY\n" + + "nodb_plsqlbindpack21\n" + + "IS\n" + + " PROCEDURE test1(p IN numbersType) IS BEGIN NULL; END;\n" + + " PROCEDURE test2(p IN OUT NOCOPY numbersType) IS BEGIN NULL; END;\n" + + " PROCEDURE test3(p IN datesType) IS BEGIN NULL; END;\n" + + " PROCEDURE test4(id IN numbersType, p IN datesType) IS BEGIN NULL; END;\n" + + " PROCEDURE test5(p OUT stringsType) IS BEGIN NULL; END;\n" + + "END;"; + connection.should.be.ok(); + connection.execute( + proc, + function(err) { + should.not.exist(err); + callback(); + } + ); + } + ], done); + }); // before + + after(function(done) { + async.series([ + function(callback) { + connection.execute( + "DROP PACKAGE nodb_plsqlbindpack21", + function(err) { + should.not.exist(err); + callback(); + } + ); + }, + function(callback) { + connection.release(function(err) { + should.not.exist(err); + callback(); + }); + } + ], done); + }); // after + + it('43.2.1 maxArraySize is ignored when specifying BIND_IN', function(done) { + var bindvars = { + p: {type: oracledb.NUMBER, dir: oracledb.BIND_IN, val: [1, 2, 3], maxArraySize: 2} + }; + connection.execute( + "BEGIN nodb_plsqlbindpack21.test1(:p); END;", + bindvars, + function(err, result) { + should.not.exist(err); + should.exist(result); + done(); + } + ); + }); + + it('43.2.2 maxArraySize is mandatory for BIND_INOUT ', function(done) { + var bindvars = { + p: {type: oracledb.NUMBER, dir: oracledb.BIND_INOUT, val: [1, 2, 3]} + }; + connection.execute( + "BEGIN nodb_plsqlbindpack21.test2(:p); END;", + bindvars, + function(err, result) { + should.exist(err); + (err.message).should.startWith('NJS-035:'); + // NJS-035: maxArraySize is required for IN OUT array bind + should.not.exist(result); + done(); + } + ); + }); + + it('43.2.3 maxArraySize cannot smaller than the number of array elements', function(done) { + var bindvars = { + p: {type: oracledb.NUMBER, dir: oracledb.BIND_INOUT, val: [1, 2, 3], maxArraySize: 2} + }; + connection.execute( + "BEGIN nodb_plsqlbindpack21.test3(:p); END;", + bindvars, + function(err, result) { + should.exist(err); + (err.message).should.startWith('NJS-036:'); + // NJS-036: Given Array is of size greater than maxArraySize property. + should.not.exist(result); + done(); + } + ); + }); + + it('43.2.4 DATE type indexed table has not been supported yet', function(done) { + var bindvars = { + p: {type: oracledb.DATE, dir: oracledb.BIND_IN, val: [new Date(), new Date()]} + }; + connection.execute( + "BEGIN nodb_plsqlbindpack21.test3(:p); END;", + bindvars, + function(err, result) { + should.exist(err); + (err.message).should.startWith('NJS-034:'); + // NJS-034: data type is unsupported for array bind + should.not.exist(result); + done(); + } + ); + }); + + it('43.2.5 negative case: incorrect type of array element - bind by name 1', function(done) { + var bindvars = { + id: {type: oracledb.NUMBER, dir: oracledb.BIND_IN, val: ["1", 1]}, + p: {type: oracledb.NUMBER, dir: oracledb.BIND_IN, val: "hi"} + }; + connection.execute( + "BEGIN nodb_plsqlbindpack21.test4(:id, :p); END;", + bindvars, + function(err, result) { + should.exist(err); + (err.message).should.startWith('NJS-037:'); + (err.message).should.match(/^NJS-037:.*\sindex\s0\s.*\sbind\s":id"$/); + // NJS-037: invalid data type at array index 0 for bind ":id" + should.not.exist(result); + done(); + } + ); + }); + + it('43.2.6 negative case: incorrect type of array element - bind by name 2', function(done) { + var bindvars = { + id: {type: oracledb.NUMBER, dir: oracledb.BIND_IN, val: [1, 2, "hi"]}, + p: {type: oracledb.NUMBER, dir: oracledb.BIND_IN, val: [1, 'hello']} + }; + connection.execute( + "BEGIN nodb_plsqlbindpack21.test4(:id, :p); END;", + bindvars, + function(err, result) { + should.exist(err); + (err.message).should.startWith('NJS-037:'); + (err.message).should.match(/^NJS-037:.*\sindex\s2\s.*\sbind\s":id"$/); + // NJS-037: invalid data type at array index 2 for bind ":id" + should.not.exist(result); + done(); + } + ); + }); + + it('43.2.7 negative case: incorrect type of array element - bind by name 3', function(done) { + var bindvars = { + id: {type: oracledb.NUMBER, dir: oracledb.BIND_IN, val: [1, 2]}, + p: {type: oracledb.NUMBER, dir: oracledb.BIND_IN, val: ['hello', 1]} + }; + connection.execute( + "BEGIN nodb_plsqlbindpack21.test4(:id, :p); END;", + bindvars, + function(err, result) { + should.exist(err); + (err.message).should.startWith('NJS-037:'); + (err.message).should.match(/^NJS-037:.*\sindex\s0\s.*\sbind\s":p"$/); + // NJS-037: invalid data type at array index 0 for bind ":p" + should.not.exist(result); + done(); + } + ); + }); + + it('43.2.8 negative case: incorrect type of array element - bind by name 4', function(done) { + var bindvars = { + id: {type: oracledb.NUMBER, dir: oracledb.BIND_IN, val: [1, 2, 3]}, + p: {type: oracledb.NUMBER, dir: oracledb.BIND_IN, val: [1, 2, 'hello']} + }; + connection.execute( + "BEGIN nodb_plsqlbindpack21.test4(:id, :p); END;", + bindvars, + function(err, result) { + should.exist(err); + (err.message).should.startWith('NJS-037:'); + (err.message).should.match(/^NJS-037:.*\sindex\s2\s.*\sbind\s":p"$/); + // NJS-037: invalid data type at array index 2 for bind ":p" + should.not.exist(result); + done(); + } + ); + }); + + it('43.2.9 supports binding by position', function(done) { + var bindvars = [ + {type: oracledb.NUMBER, dir: oracledb.BIND_IN, val: [1, 2]} + ]; + connection.execute( + "BEGIN nodb_plsqlbindpack21.test1(:1); END;", + bindvars, + function(err, result) { + should.not.exist(err); + should.exist(result); + done(); + } + ); + }); + + it('43.2.10 negative case: incorrect type of array elements - bind by pos 1', + function (done ){ + var bindvars = [ + { type : oracledb.NUMBER, dir: oracledb.BIND_IN, val : ['hello', 1] }, + { type : oracledb.NUMBER, dir: oracledb.BIND_IN, val : "hi" } + ]; + connection.execute ( + "BEGIN nodb_plsqlbindpack21.test4 (:1, :2); END;", + bindvars, + function ( err, result ) { + should.exist ( err ) ; + (err.message).should.startWith ( 'NJS-052:'); + (err.message).should.match(/^NJS-052:.*\sindex\s0\s.*\sposition\s1$/); + // NJS-052: invalid data type at array index 0 for bind position 1 + should.not.exist ( result ); + done (); + } + ); + } + ); + + it('43.2.11 negative case: incorrect type of array elements - bind by pos 2', + function (done ){ + var bindvars = [ + { type : oracledb.NUMBER, dir: oracledb.BIND_IN, val : [1, 2, "hi"] }, + { type : oracledb.NUMBER, dir: oracledb.BIND_IN, val : "hi" } + ]; + connection.execute ( + "BEGIN nodb_plsqlbindpack21.test4 (:1, :2); END;", + bindvars, + function ( err, result ) { + should.exist ( err ) ; + (err.message).should.startWith ( 'NJS-052:'); + (err.message).should.match(/^NJS-052:.*\sindex\s2\s.*\sposition\s1$/); + // NJS-052: invalid data type at array index 2 for bind position 1 + should.not.exist ( result ); + done (); + } + ); + } + ); + + it('43.2.12 negative case: incorrect type of array elements - bind by pos 3', + function (done ){ + var bindvars = [ + { type : oracledb.NUMBER, dir: oracledb.BIND_IN, val : [1, 2] }, + { type : oracledb.NUMBER, dir: oracledb.BIND_IN, val : ["hi", 1] } + ]; + connection.execute ( + "BEGIN nodb_plsqlbindpack21.test4 (:1, :2); END;", + bindvars, + function ( err, result ) { + should.exist ( err ) ; + (err.message).should.startWith ( 'NJS-052:'); + (err.message).should.match(/^NJS-052:.*\sindex\s0\s.*\sposition\s2$/); + // NJS-052: invalid data type at array index 0 for bind position 2 + should.not.exist ( result ); + done (); + } + ); + } + ); + + it('43.2.13 negative case: incorrect type of array elements - bind by pos 4', + function (done ){ + var bindvars = [ + { type : oracledb.NUMBER, dir: oracledb.BIND_IN, val : [1, 2, 3] }, + { type : oracledb.NUMBER, dir: oracledb.BIND_IN, val : [1, 2, "hi"] } + ]; + connection.execute ( + "BEGIN nodb_plsqlbindpack21.test4 (:1, :2); END;", + bindvars, + function ( err, result ) { + should.exist ( err ) ; + (err.message).should.startWith ( 'NJS-052:'); + (err.message).should.match(/^NJS-052:.*\sindex\s2\s.*\sposition\s2$/); + // NJS-052: invalid data type at array index 2 for bind position 2 + should.not.exist ( result ); + done (); + } + ); + } + ); + }); // 43.2 + + describe('43.3 binding PL/SQL scalar', function() { + var connection = null; + + before(function(done) { + oracledb.getConnection(credentials, function(err, conn) { + if(err) { console.error(err.message); return; } + connection = conn; + done(); + }); + }); + + after(function(done) { + connection.release( function(err) { + if(err) { console.error(err.message); return; } + done(); + }); + }); + + it('43.3.1 binding PL/SQL scalar IN', function(done) { + async.series([ + function(callback) { + var proc = "CREATE OR REPLACE\n" + + "FUNCTION nodb_plsqlbindfunc31(stringValue IN VARCHAR2, numberValue IN NUMBER, dateValue IN DATE) RETURN VARCHAR2\n" + + "IS\n" + + "BEGIN\n" + + " RETURN stringValue || ' ' || numberValue || ' released in ' || TO_CHAR(dateValue, 'MON YYYY');\n" + + "END nodb_plsqlbindfunc31;"; + connection.should.be.ok(); + connection.execute( + proc, + function(err) { + should.not.exist(err); + callback(); + } + ); + }, + function(callback) { + var bindvars = { + result: {type: oracledb.STRING, dir: oracledb.BIND_OUT, maxSize: 2000}, + stringValue: {type: oracledb.STRING, dir: oracledb.BIND_IN, val: 'Space odyssey'}, + numberValue: {type: oracledb.NUMBER, dir: oracledb.BIND_IN, val: 2001 }, + dateValue: {type: oracledb.DATE, dir: oracledb.BIND_IN, val: new Date(1968, 3, 2) } + }; + connection.execute( + "BEGIN :result := nodb_plsqlbindfunc31(:stringValue, :numberValue, :dateValue); END;", + bindvars, + function(err, result) { + should.not.exist(err); + //console.log(result); + result.outBinds.result.should.be.exactly('Space odyssey 2001 released in APR 1968'); + callback(); + } + ); + }, + function(callback) { + connection.execute( + "DROP FUNCTION nodb_plsqlbindfunc31", + function(err) { + should.not.exist(err); + callback(); + } + ); + } + ], done); + }); + + it('43.3.2 binding PL/SQL scalar IN/OUT', function(done) { + async.series([ + function(callback) { + var proc = "CREATE OR REPLACE\n" + + "PROCEDURE nodb_plsqlbindproc32(stringValue IN OUT NOCOPY VARCHAR2, numberValue IN OUT NOCOPY NUMBER, dateValue IN OUT NOCOPY DATE)\n" + + "IS\n" + + "BEGIN\n" + + " stringValue := '(' || stringValue || ')';\n" + + " numberValue := NumberValue + 100;\n" + + //" dateValue := " + "END nodb_plsqlbindproc32;\n"; + connection.should.be.ok(); + connection.execute( + proc, + function(err) { + should.not.exist(err); + callback(); + } + ); + }, + function(callback) { + var releaseDate = new Date(1968, 3, 2); + var bindvars = { + stringValue: {type: oracledb.STRING, dir: oracledb.BIND_INOUT, val: 'Space odyssey'}, + numberValue: {type: oracledb.NUMBER, dir: oracledb.BIND_INOUT, val: 2001}, + dateValue: {type: oracledb.DATE, dir: oracledb.BIND_INOUT, val: releaseDate} + }; + connection.execute( + "BEGIN nodb_plsqlbindproc32(:stringValue, :numberValue, :dateValue); END;", + bindvars, + function(err, result) { + should.not.exist(err); + // console.log(result); + result.outBinds.stringValue.should.be.exactly('(Space odyssey)'); + result.outBinds.numberValue.should.be.exactly(2101); + //result.outBinds.dateValue.should.eql(releaseDate) + callback(); + } + ); + }, + function(callback) { + connection.execute( + "DROP PROCEDURE nodb_plsqlbindproc32", + function(err) { + should.not.exist(err); + callback(); + } + ); + } + ], done); + }); + + it('43.3.3 binding PL/SQL scalar OUT by name', function(done) { + async.series([ + function(callback) { + var proc = "CREATE OR REPLACE\n" + + "PROCEDURE nodb_plsqlbindproc33(stringValue OUT VARCHAR2, numberValue OUT NUMBER, dateValue OUT DATE)\n" + + "IS\n" + + "BEGIN\n" + + " stringValue := 'Space odyssey';\n" + + " numberValue := 2001;\n" + + " dateValue := TO_DATE('04-02-1968', 'MM-DD-YYYY');" + + "END nodb_plsqlbindproc33;\n"; + connection.should.be.ok(); + connection.execute( + proc, + function(err) { + should.not.exist(err); + callback(); + } + ); + }, + function(callback) { + var bindvars = { + stringValue: {type: oracledb.STRING, dir: oracledb.BIND_OUT}, + numberValue: {type: oracledb.NUMBER, dir: oracledb.BIND_OUT}, + dateValue: {type: oracledb.DATE, dir: oracledb.BIND_OUT} + }; + connection.execute( + "BEGIN nodb_plsqlbindproc33(:stringValue, :numberValue, :dateValue); END;", + bindvars, + function(err, result) { + should.not.exist(err); + // console.log(result); + result.outBinds.stringValue.should.be.exactly('Space odyssey'); + result.outBinds.numberValue.should.be.exactly(2001); + (Object.prototype.toString.call(result.outBinds.dateValue)).should.eql('[object Date]'); + callback(); + } + ); + }, + function(callback) { + connection.execute( + "DROP PROCEDURE nodb_plsqlbindproc33", + function(err) { + should.not.exist(err); + callback(); + } + ); + } + ], done); + }); + + it('43.3.4 binding PL/SQL scalar OUT by position', function(done) { + async.series([ + function(callback) { + var proc = "CREATE OR REPLACE\n" + + "PROCEDURE nodb_plsqlbindproc34(stringValue OUT VARCHAR2, numberValue OUT NUMBER, dateValue OUT DATE)\n" + + "IS\n" + + "BEGIN\n" + + " stringValue := 'Space odyssey';\n" + + " numberValue := 2001;\n" + + " dateValue := TO_DATE('04-02-1968', 'MM-DD-YYYY');" + + "END nodb_plsqlbindproc34;\n"; + connection.should.be.ok(); + connection.execute( + proc, + function(err) { + should.not.exist(err); + callback(); + } + ); + }, + function(callback) { + var bindvars = [ + {type: oracledb.STRING, dir: oracledb.BIND_OUT}, + {type: oracledb.NUMBER, dir: oracledb.BIND_OUT}, + {type: oracledb.DATE, dir: oracledb.BIND_OUT} + ]; + connection.execute( + "BEGIN nodb_plsqlbindproc34(:1, :2, :3); END;", + bindvars, + function(err, result) { + should.not.exist(err); + // console.log(result); + result.outBinds[0].should.be.exactly('Space odyssey'); + result.outBinds[1].should.be.exactly(2001); + (Object.prototype.toString.call(result.outBinds[2])).should.eql('[object Date]'); + callback(); + } + ); + }, + function(callback) { + connection.execute( + "DROP PROCEDURE nodb_plsqlbindproc34", + function(err) { + should.not.exist(err); + callback(); + } + ); + } + ], done); + }); + + }); // 43.3 + + describe('43.4 test attribute - maxArraySize', function() { + var connection = null; + + before(function(done) { + async.series([ + function(cb) { + oracledb.getConnection(credentials, function(err, conn) { + should.not.exist(err); + connection = conn; + cb(); + }); + }, + function(cb) { + var proc = "CREATE OR REPLACE PACKAGE\n" + + "nodb_plsqlbindpack41\n" + + "IS\n" + + " TYPE datesType IS TABLE OF DATE INDEX BY BINARY_INTEGER;\n" + + " TYPE numbersType IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;\n" + + " TYPE stringsType IS TABLE OF VARCHAR2(2000) INDEX BY BINARY_INTEGER;\n" + + " PROCEDURE test1(p IN numbersType);\n" + + " PROCEDURE test2(p IN OUT NOCOPY numbersType);\n" + + " PROCEDURE test3(p IN datesType);\n" + + " PROCEDURE test4(p IN stringsType);\n" + + " PROCEDURE test5(p IN numbersType);\n" + + "END;"; + connection.should.be.ok(); + connection.execute( + proc, + function(err) { + should.not.exist(err); + cb(); + } + ); + }, + function(cb) { + var proc = "CREATE OR REPLACE PACKAGE BODY\n" + + "nodb_plsqlbindpack41\n" + + "IS\n" + + " PROCEDURE test1(p IN numbersType) IS BEGIN NULL; END;\n" + + " PROCEDURE test2(p IN OUT NOCOPY numbersType) IS BEGIN NULL; END;\n" + + " PROCEDURE test3(p IN datesType) IS BEGIN NULL; END;\n" + + " PROCEDURE test4(p IN stringsType) IS BEGIN NULL; END;\n" + + " PROCEDURE test5(p IN numbersType) IS BEGIN NULL; END;\n" + + "END;"; + connection.execute( + proc, + function(err) { + should.not.exist(err); + cb(); + } + ); + } + ], done); + }); // before + + after(function(done) { + async.series([ + function(callback) { + connection.execute( + "DROP PACKAGE nodb_plsqlbindpack41", + function(err) { + should.not.exist(err); + callback(); + } + ); + }, + function(callback) { + connection.release(function(err) { + should.not.exist(err); + callback(); + }); + } + ], done); + }); // after + + it('43.4.1 maxArraySize property is ignored for BIND_IN', function(done) { + var bindvars = { + p: {type: oracledb.NUMBER, dir: oracledb.BIND_IN, val: [1, 2, 3], maxArraySize: 1} + }; + connection.execute( + "BEGIN nodb_plsqlbindpack41.test1(:p); END;", + bindvars, + function(err, result) { + should.not.exist(err); + should.exist(result); + done(); + } + ); + }); + + it('43.4.2 maxArraySize is mandatory for BIND_INOUT', function(done) { + var bindvars = { + p: {type: oracledb.NUMBER, dir: oracledb.BIND_INOUT, val: [1, 2, 3]} + }; + connection.execute( + "BEGIN nodb_plsqlbindpack41.test2(:p); END;", + bindvars, + function(err, result) { + should.exist(err); + (err.message).should.startWith('NJS-035:'); + // NJS-035: maxArraySize is required for IN OUT array bind + should.not.exist(result); + done(); + } + ); + }); + + it('43.4.3 maxArraySize cannot smaller than the number of array elements', function(done) { + var bindvars = { + p: {type: oracledb.NUMBER, dir: oracledb.BIND_INOUT, val: [1, 2, 3], maxArraySize: 2} + }; + connection.execute( + "BEGIN nodb_plsqlbindpack41.test2(:p); END;", + bindvars, + function(err, result) { + should.exist(err); + (err.message).should.startWith('NJS-036:'); + // NJS-036: given Array is of size greater than maxArraySize property. + should.not.exist(result); + done(); + } + ); + }); + + it('43.4.4 maxArraySize can be equal to the number of array elements', function(done) { + var bindvars = { + p: {type: oracledb.NUMBER, dir: oracledb.BIND_INOUT, val: [1, 2, 3], maxArraySize: 3} + }; + connection.execute( + "BEGIN nodb_plsqlbindpack41.test2(:p); END;", + bindvars, + function(err) { + should.not.exist(err); + done(); + } + ); + }); + + it('43.4.5 negative case: large value', function(done) { + var bindvars = { + p: {type: oracledb.NUMBER, dir: oracledb.BIND_INOUT, val: [1, 2, 3], maxArraySize: 987654321} + }; + connection.execute( + "BEGIN nodb_plsqlbindpack41.test2(:p); END;", + bindvars, + function(err) { + should.exist(err); + should.strictEqual( + err.message, + "DPI-1015: array size of 987654321 is too large" + ); + done(); + } + ); + }); + + it('43.4.6 negative case: < 0', function(done) { + var bindvars = { + p: {type: oracledb.NUMBER, dir: oracledb.BIND_INOUT, val: [1, 2, 3], maxArraySize: -9} + }; + connection.execute( + "BEGIN nodb_plsqlbindpack41.test2(:p); END;", + bindvars, + function(err) { + should.exist(err); + (err.message).should.startWith('NJS-007:'); + // NJS-007: invalid value for "maxArraySize" + done(); + } + ); + }); + + it('43.4.7 negative case: = 0', function(done) { + var bindvars = { + p: {type: oracledb.NUMBER, dir: oracledb.BIND_INOUT, val: [1, 2, 3], maxArraySize: 0} + }; + connection.execute( + "BEGIN nodb_plsqlbindpack41.test2(:p); END;", + bindvars, + function(err) { + should.exist(err); + (err.message).should.startWith('NJS-035:'); + // NJS-035: maxArraySize is required for IN OUT array bind + done(); + } + ); + }); + + it('43.4.8 negative case: assign a string to it', function(done) { + var bindvars = { + p: {type: oracledb.NUMBER, dir: oracledb.BIND_INOUT, val: [1, 2, 3], maxArraySize: 'foobar'} + }; + connection.execute( + "BEGIN nodb_plsqlbindpack41.test2(:p); END;", + bindvars, + function(err) { + should.exist(err); + (err.message).should.startWith('NJS-008:'); + // NJS-008: invalid type for "maxArraySize" + done(); + } + ); + }); + + it('43.4.9 negative case: NaN', function(done) { + var bindvars = { + p: {type: oracledb.NUMBER, dir: oracledb.BIND_INOUT, val: [1, 2, 3], maxArraySize: NaN} + }; + connection.execute( + "BEGIN nodb_plsqlbindpack41.test2(:p); END;", + bindvars, + function(err) { + should.exist(err); + (err.message).should.startWith('NJS-007:'); + // NJS-007: invalid value for "maxArraySize" + done(); + } + ); + }); + + }); // 43.4 +}); diff --git a/test/plsqlBindIndexedTable2.js b/test/plsqlBindIndexedTable2.js new file mode 100644 index 00000000..ddb98c03 --- /dev/null +++ b/test/plsqlBindIndexedTable2.js @@ -0,0 +1,721 @@ +/* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with the Apache + * License, Version 2.0 (the "License.") + * + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + * The node-oracledb test suite uses 'mocha', 'should' and 'async'. + * See LICENSE.md for relevant licenses. + * + * NAME + * 44. plsqlBindIndexedTable2.js + * + * DESCRIPTION + * Testing PL/SQL indexed tables (associative arrays). + * + * NUMBERING RULE + * Test numbers follow this numbering rule: + * 1 - 20 are reserved for basic functional tests + * 21 - 50 are reserved for data type supporting tests + * 51 onwards are for other tests + * + *****************************************************************************/ +'use strict'; + +var oracledb = require('oracledb'); +var should = require('should'); +var async = require('async'); +var dbConfig = require('./dbconfig.js'); + +describe('44. plsqlBindIndexedTable2.js', function() { + + var credentials = { + user: dbConfig.user, + password: dbConfig.password, + connectString: dbConfig.connectString + }; + + var connection = null; + + beforeEach(function(done) { + async.series([ + function(callback) { + oracledb.getConnection(credentials, function(err, conn) { + should.not.exist(err); + connection = conn; + callback(); + }); + }, + function createTab(callback) { + var proc = "BEGIN \n" + + " DECLARE \n" + + " e_table_missing EXCEPTION; \n" + + " PRAGMA EXCEPTION_INIT(e_table_missing, -00942);\n " + + " BEGIN \n" + + " EXECUTE IMMEDIATE ('DROP TABLE nodb_waveheight PURGE'); \n" + + " EXCEPTION \n" + + " WHEN e_table_missing \n" + + " THEN NULL; \n" + + " END; \n" + + " EXECUTE IMMEDIATE (' \n" + + " CREATE TABLE nodb_waveheight (beach VARCHAR2(50), depth NUMBER) \n" + + " '); \n" + + "END; "; + + connection.execute( + proc, + function(err) { + should.not.exist(err); + callback(); + } + ); + + }, + function createPkg(callback) { + var proc = "CREATE OR REPLACE PACKAGE nodb_beachpkg IS\n" + + " TYPE beachType IS TABLE OF VARCHAR2(30) INDEX BY BINARY_INTEGER;\n" + + " TYPE depthType IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;\n" + + " PROCEDURE array_in(beaches IN beachType, depths IN depthType);\n" + + " PROCEDURE array_out(beaches OUT beachType, depths OUT depthType); \n" + + " PROCEDURE array_inout(beaches IN OUT beachType, depths IN OUT depthType); \n" + + "END;"; + + connection.execute( + proc, + function(err) { + should.not.exist(err); + callback(); + } + ); + }, + function(callback) { + var proc = "CREATE OR REPLACE PACKAGE BODY nodb_beachpkg IS \n" + + " PROCEDURE array_in(beaches IN beachType, depths IN depthType) IS \n" + + " BEGIN \n" + + " IF beaches.COUNT <> depths.COUNT THEN \n" + + " RAISE_APPLICATION_ERROR(-20000, 'Array lengths must match for this example.'); \n" + + " END IF; \n" + + " FORALL i IN INDICES OF beaches \n" + + " INSERT INTO nodb_waveheight (beach, depth) VALUES (beaches(i), depths(i)); \n" + + " END; \n" + + " PROCEDURE array_out(beaches OUT beachType, depths OUT depthType) IS \n" + + " BEGIN \n" + + " SELECT beach, depth BULK COLLECT INTO beaches, depths FROM nodb_waveheight; \n" + + " END; \n" + + " PROCEDURE array_inout(beaches IN OUT beachType, depths IN OUT depthType) IS \n" + + " BEGIN \n" + + " IF beaches.COUNT <> depths.COUNT THEN \n" + + " RAISE_APPLICATION_ERROR(-20001, 'Array lenghts must match for this example.'); \n" + + " END IF; \n" + + " FORALL i IN INDICES OF beaches \n" + + " INSERT INTO nodb_waveheight (beach, depth) VALUES (beaches(i), depths(i)); \n" + + " SELECT beach, depth BULK COLLECT INTO beaches, depths FROM nodb_waveheight ORDER BY 1; \n" + + " END; \n " + + "END;"; + + connection.execute( + proc, + function(err) { + should.not.exist(err); + callback(); + } + ); + }, + function(callback) { + connection.commit(function(err) { + should.not.exist(err); + callback(); + }); + } + ], done); + }); // before + + afterEach(function(done) { + async.series([ + function(callback) { + connection.execute( + "DROP TABLE nodb_waveheight PURGE", + function(err) { + should.not.exist(err); + callback(); + } + ); + }, + function(callback) { + connection.execute( + "DROP PACKAGE nodb_beachpkg", + function(err) { + should.not.exist(err); + callback(); + } + ); + }, + function(callback) { + connection.release(function(err) { + should.not.exist(err); + callback(); + }); + }, + ], done); + }); // after + + it('44.1 example case', function(done) { + async.series([ + // Pass arrays of values to a PL/SQL procedure + function(callback) { + connection.execute( + "BEGIN nodb_beachpkg.array_in(:beach_in, :depth_in); END;", + { + beach_in: { type: oracledb.STRING, + dir: oracledb.BIND_IN, + val: ["Malibu Beach", "Bondi Beach", "Waikiki Beach"] }, + depth_in: { type: oracledb.NUMBER, + dir: oracledb.BIND_IN, + val: [45, 30, 67] + } + }, + function(err) { + should.not.exist(err); + callback(); + } + ); + }, + // Fetch arrays of values from a PL/SQL procedure + function(callback) { + connection.execute( + "BEGIN nodb_beachpkg.array_out(:beach_out, :depth_out); END;", + { + beach_out: { type: oracledb.STRING, + dir: oracledb.BIND_OUT, + maxArraySize: 3 }, + depth_out: { type: oracledb.NUMBER, + dir: oracledb.BIND_OUT, + maxArraySize: 3 } + }, + function(err, result) { + should.not.exist(err); + // console.log(result.outBinds); + (result.outBinds.beach_out).should.eql([ 'Malibu Beach', 'Bondi Beach', 'Waikiki Beach' ]); + (result.outBinds.depth_out).should.eql([45, 30, 67]); + callback(); + } + ); + }, + function(callback) { + connection.rollback(function(err) { + should.not.exist(err); + callback(); + }); + }, + // Return input arrays sorted by beach name + function(callback) { + connection.execute( + "BEGIN nodb_beachpkg.array_inout(:beach_inout, :depth_inout); END;", + { + beach_inout: { type: oracledb.STRING, + dir: oracledb.BIND_INOUT, + val: ["Port Melbourne Beach", "Eighty Mile Beach", "Chesil Beach"], + maxArraySize: 3}, + depth_inout: { type: oracledb.NUMBER, + dir: oracledb.BIND_INOUT, + val: [8, 3, 70], + maxArraySize: 3} + }, + function(err, result) { + should.not.exist(err); + //console.log(result.outBinds); + (result.outBinds.beach_inout).should.eql([ 'Chesil Beach', 'Eighty Mile Beach', 'Port Melbourne Beach' ]); + (result.outBinds.depth_inout).should.eql([ 70, 3, 8 ]); + callback(); + } + ); + } + ], done); + }); // 44.1 + + it('44.2 example case binding by position', function(done) { + async.series([ + // Pass arrays of values to a PL/SQL procedure + function(callback) { + connection.execute( + "BEGIN nodb_beachpkg.array_in(:1, :2); END;", + [ + { type: oracledb.STRING, + dir: oracledb.BIND_IN, + val: ["Malibu Beach", "Bondi Beach", "Waikiki Beach"] }, + { type: oracledb.NUMBER, + dir: oracledb.BIND_IN, + val: [45, 30, 67] + } + ], + function(err) { + should.not.exist(err); + callback(); + } + ); + }, + // Fetch arrays of values from a PL/SQL procedure + function(callback) { + connection.execute( + "BEGIN nodb_beachpkg.array_out(:1, :2); END;", + [ + { type: oracledb.STRING, + dir: oracledb.BIND_OUT, + maxArraySize: 3 }, + { type: oracledb.NUMBER, + dir: oracledb.BIND_OUT, + maxArraySize: 3 } + ], + function(err, result) { + should.not.exist(err); + // console.log(result.outBinds); + (result.outBinds[0]).should.eql([ 'Malibu Beach', 'Bondi Beach', 'Waikiki Beach' ]); + (result.outBinds[1]).should.eql([45, 30, 67]); + callback(); + } + ); + }, + function(callback) { + connection.rollback(function(err) { + should.not.exist(err); + callback(); + }); + }, + // Return input arrays sorted by beach name + function(callback) { + connection.execute( + "BEGIN nodb_beachpkg.array_inout(:1, :2); END;", + [ + { type: oracledb.STRING, + dir: oracledb.BIND_INOUT, + val: ["Port Melbourne Beach", "Eighty Mile Beach", "Chesil Beach"], + maxArraySize: 3}, + { type: oracledb.NUMBER, + dir: oracledb.BIND_INOUT, + val: [8, 3, 70], + maxArraySize: 3} + ], + function(err, result) { + should.not.exist(err); + // console.log(result.outBinds); + (result.outBinds[0]).should.eql([ 'Chesil Beach', 'Eighty Mile Beach', 'Port Melbourne Beach' ]); + (result.outBinds[1]).should.eql([ 70, 3, 8 ]); + callback(); + } + ); + } + ], done); + }); + + it('44.3 default binding type and direction with binding by name', function(done) { + async.series([ + // Pass arrays of values to a PL/SQL procedure + function(callback) { + connection.execute( + "BEGIN nodb_beachpkg.array_in(:beach_in, :depth_in); END;", + { + beach_in: { //type: oracledb.STRING, + //dir: oracledb.BIND_IN, + val: ["Malibu Beach", "Bondi Beach", "Waikiki Beach"] }, + depth_in: { type: oracledb.NUMBER, + dir: oracledb.BIND_IN, + val: [45, 30, 67] + } + }, + function(err) { + should.not.exist(err); + callback(); + } + ); + }, + // Fetch arrays of values from a PL/SQL procedure + function(callback) { + connection.execute( + "BEGIN nodb_beachpkg.array_out(:beach_out, :depth_out); END;", + { + beach_out: { type: oracledb.STRING, + dir: oracledb.BIND_OUT, + maxArraySize: 3 }, + depth_out: { type: oracledb.NUMBER, + dir: oracledb.BIND_OUT, + maxArraySize: 3 } + }, + function(err, result) { + should.not.exist(err); + // console.log(result.outBinds); + (result.outBinds.beach_out).should.eql([ 'Malibu Beach', 'Bondi Beach', 'Waikiki Beach' ]); + (result.outBinds.depth_out).should.eql([45, 30, 67]); + callback(); + } + ); + }, + function(callback) { + connection.rollback(function(err) { + should.not.exist(err); + callback(); + }); + }, + // Return input arrays sorted by beach name + function(callback) { + connection.execute( + "BEGIN nodb_beachpkg.array_inout(:beach_inout, :depth_inout); END;", + { + beach_inout: { type: oracledb.STRING, + dir: oracledb.BIND_INOUT, + val: ["Port Melbourne Beach", "Eighty Mile Beach", "Chesil Beach"], + maxArraySize: 3}, + depth_inout: { type: oracledb.NUMBER, + dir: oracledb.BIND_INOUT, + val: [8, 3, 70], + maxArraySize: 3} + }, + function(err, result) { + should.not.exist(err); + //console.log(result.outBinds); + (result.outBinds.beach_inout).should.eql([ 'Chesil Beach', 'Eighty Mile Beach', 'Port Melbourne Beach' ]); + (result.outBinds.depth_inout).should.eql([ 70, 3, 8 ]); + callback(); + } + ); + } + ], done); + }); // 44.3 + + it('44.4 default binding type and direction with binding by position', function(done) { + async.series([ + // Pass arrays of values to a PL/SQL procedure + function(callback) { + connection.execute( + "BEGIN nodb_beachpkg.array_in(:1, :2); END;", + [ + { type: oracledb.STRING, + // dir: oracledb.BIND_IN, + val: ["Malibu Beach", "Bondi Beach", "Waikiki Beach"] }, + { type: oracledb.NUMBER, + dir: oracledb.BIND_IN, + val: [45, 30, 67] + } + ], + function(err) { + should.not.exist(err); + callback(); + } + ); + }, + // Fetch arrays of values from a PL/SQL procedure + function(callback) { + connection.execute( + "BEGIN nodb_beachpkg.array_out(:1, :2); END;", + [ + { type: oracledb.STRING, + dir: oracledb.BIND_OUT, + maxArraySize: 3 }, + { type: oracledb.NUMBER, + dir: oracledb.BIND_OUT, + maxArraySize: 3 } + ], + function(err, result) { + should.not.exist(err); + // console.log(result.outBinds); + (result.outBinds[0]).should.eql([ 'Malibu Beach', 'Bondi Beach', 'Waikiki Beach' ]); + (result.outBinds[1]).should.eql([45, 30, 67]); + callback(); + } + ); + }, + function(callback) { + connection.rollback(function(err) { + should.not.exist(err); + callback(); + }); + }, + // Return input arrays sorted by beach name + function(callback) { + connection.execute( + "BEGIN nodb_beachpkg.array_inout(:1, :2); END;", + [ + { type: oracledb.STRING, + dir: oracledb.BIND_INOUT, + val: ["Port Melbourne Beach", "Eighty Mile Beach", "Chesil Beach"], + maxArraySize: 3}, + { type: oracledb.NUMBER, + dir: oracledb.BIND_INOUT, + val: [8, 3, 70], + maxArraySize: 3} + ], + function(err, result) { + should.not.exist(err); + // console.log(result.outBinds); + (result.outBinds[0]).should.eql([ 'Chesil Beach', 'Eighty Mile Beach', 'Port Melbourne Beach' ]); + (result.outBinds[1]).should.eql([ 70, 3, 8 ]); + callback(); + } + ); + } + ], done); + }); + + it('44.5 null elements in String and Number arrays', function(done) { + async.series([ + // Pass arrays of values to a PL/SQL procedure + function(callback) { + connection.execute( + "BEGIN nodb_beachpkg.array_in(:beach_in, :depth_in); END;", + { + beach_in: { type: oracledb.STRING, + dir: oracledb.BIND_IN, + val: ["Malibu Beach", "Bondi Beach", null, "Waikiki Beach", '', null] }, + depth_in: { type: oracledb.NUMBER, + dir: oracledb.BIND_IN, + val: [null, null, 45, 30, 67, null, ] + } + }, + function(err) { + should.not.exist(err); + callback(); + } + ); + }, + // Fetch arrays of values from a PL/SQL procedure + function(callback) { + connection.execute( + "BEGIN nodb_beachpkg.array_out(:beach_out, :depth_out); END;", + { + beach_out: { type: oracledb.STRING, + dir: oracledb.BIND_OUT, + maxArraySize: 10 }, + depth_out: { type: oracledb.NUMBER, + dir: oracledb.BIND_OUT, + maxArraySize: 10 } + }, + function(err, result) { + should.not.exist(err); + // console.log(result.outBinds); + (result.outBinds.beach_out).should.eql([ 'Malibu Beach', 'Bondi Beach', null, 'Waikiki Beach', null, null ]); + (result.outBinds.depth_out).should.eql([ null, null, 45, 30, 67, null ]); + callback(); + } + ); + }, + function(callback) { + connection.rollback(function(err) { + should.not.exist(err); + callback(); + }); + }, + // Return input arrays sorted by beach name + function(callback) { + connection.execute( + "BEGIN nodb_beachpkg.array_inout(:beach_inout, :depth_inout); END;", + { + beach_inout: { type: oracledb.STRING, + dir: oracledb.BIND_INOUT, + val: ["Port Melbourne Beach", "Eighty Mile Beach", '', "Chesil Beach", null, ''], + maxArraySize: 10}, + depth_inout: { type: oracledb.NUMBER, + dir: oracledb.BIND_INOUT, + val: [null, 8, null, 3, null, 70], + maxArraySize: 10} + }, + function(err, result) { + should.not.exist(err); + // console.log(result.outBinds); + (result.outBinds.beach_inout).should.eql([ 'Chesil Beach', 'Eighty Mile Beach', 'Port Melbourne Beach', null, null, null ]); + (result.outBinds.depth_inout).should.eql([ 3, 8, null, null, 70, null ]); + callback(); + } + ); + } + ], done); + }); // 44.5 + + it('44.6 empty array for BIND_IN and BIND_INOUT', function(done) { + async.series([ + // Pass arrays of values to a PL/SQL procedure + function(callback) { + connection.execute( + "BEGIN nodb_beachpkg.array_in(:beach_in, :depth_in); END;", + { + beach_in: { type: oracledb.STRING, + dir: oracledb.BIND_IN, + val: [] }, + depth_in: { type: oracledb.NUMBER, + dir: oracledb.BIND_IN, + val: [] + } + }, + function(err) { + should.not.exist(err); + callback(); + } + ); + }, + // Return input arrays sorted by beach name + function(callback) { + connection.execute( + "BEGIN nodb_beachpkg.array_inout(:beach_inout, :depth_inout); END;", + { + beach_inout: { type: oracledb.STRING, + dir: oracledb.BIND_INOUT, + val: [], + maxArraySize: 0 + }, + depth_inout: { type: oracledb.NUMBER, + dir: oracledb.BIND_INOUT, + val: [], + maxArraySize: 3} + }, + function(err) { + should.exist(err); + (err.message).should.startWith('NJS-035:'); + callback(); + } + ); + } + ], done); + }); // 44.6 + + it('44.7 empty array for BIND_OUT', function(done) { + async.series([ + function(callback) { + var proc = "CREATE OR REPLACE PACKAGE\n" + + "oracledb_testpack\n" + + "IS\n" + + " TYPE stringsType IS TABLE OF VARCHAR2(2000) INDEX BY BINARY_INTEGER;\n" + + " PROCEDURE test(p OUT stringsType);\n" + + "END;"; + connection.execute( + proc, + function(err) { + should.not.exist(err); + callback(); + } + ); + }, + function(callback) { + var proc = "CREATE OR REPLACE PACKAGE BODY\n" + + "oracledb_testpack\n" + + "IS\n" + + " PROCEDURE test(p OUT stringsType) IS BEGIN NULL; END;\n" + + "END;"; + connection.execute( + proc, + function(err) { + should.not.exist(err); + callback(); + } + ); + }, + function(callback) { + connection.execute( + "BEGIN oracledb_testpack.test(:0); END;", + [ + {type: oracledb.STRING, dir: oracledb.BIND_OUT, maxArraySize: 1} + ], + function(err, result) { + should.not.exist(err); + result.outBinds[0].should.eql([]); + callback(); + } + ); + }, + function(callback) { + connection.execute( + "DROP PACKAGE oracledb_testpack", + function(err) { + should.not.exist(err); + callback(); + } + ); + } + ], done); + }); // 44.7 + + it('44.8 maxSize option applies to each elements of an array', function(done) { + async.series([ + // Pass arrays of values to a PL/SQL procedure + function(callback) { + connection.execute( + "BEGIN nodb_beachpkg.array_in(:beach_in, :depth_in); END;", + { + beach_in: { type: oracledb.STRING, + dir: oracledb.BIND_IN, + val: ["Malibu", "Bondi", "Waikiki"] }, + depth_in: { type: oracledb.NUMBER, + dir: oracledb.BIND_IN, + val: [45, 30, 67] + } + }, + function(err) { + should.not.exist(err); + callback(); + } + ); + }, + // Fetch arrays of values from a PL/SQL procedure + function(callback) { + connection.execute( + "BEGIN nodb_beachpkg.array_out(:beach_out, :depth_out); END;", + { + beach_out: { type: oracledb.STRING, + dir: oracledb.BIND_OUT, + maxArraySize: 3, + maxSize: 6 }, + depth_out: { type: oracledb.NUMBER, + dir: oracledb.BIND_OUT, + maxArraySize: 3 } + }, + function(err) { + should.exist(err); + (err.message).should.startWith('ORA-06502:'); + // ORA-06502: PL/SQL: numeric or value error: host bind array too small + callback(); + } + ); + }, + function(callback) { + connection.rollback(function(err) { + should.not.exist(err); + callback(); + }); + }, + // Return input arrays sorted by beach name + function(callback) { + connection.execute( + "BEGIN nodb_beachpkg.array_inout(:beach_inout, :depth_inout); END;", + { + beach_inout: { type: oracledb.STRING, + dir: oracledb.BIND_INOUT, + val: ["Port Melbourne Beach", "Eighty Mile Beach", "Chesil Beach"], + maxArraySize: 3, + maxSize : 5}, + depth_inout: { type: oracledb.NUMBER, + dir: oracledb.BIND_INOUT, + val: [8, 3, 70], + maxArraySize: 3} + }, + function(err) { + should.exist(err); + should.strictEqual( + err.message, + "DPI-1019: buffer size of 5 is too small" + ); + callback(); + } + ); + } + ], done); + }); // 44.8 + +}); diff --git a/test/plsqlBindScalar.js b/test/plsqlBindScalar.js new file mode 100644 index 00000000..0b09dff3 --- /dev/null +++ b/test/plsqlBindScalar.js @@ -0,0 +1,5609 @@ +/* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with the Apache + * License, Version 2.0 (the "License.") + * + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + * The node-oracledb test suite uses 'mocha', 'should' and 'async'. + * See LICENSE.md for relevant licenses. + * + * NAME + * 70. plsqlBindScalar.js + * + * DESCRIPTION + * Testing PL/SQL bind scalars. + * + * NUMBERING RULE + * Test numbers follow this numbering rule: + * 1 - 20 are reserved for basic functional tests + * 21 - 50 are reserved for data type supporting tests + * 51 onwards are for other tests + * + *****************************************************************************/ +'use strict'; + +var oracledb = require('oracledb'); +var should = require('should'); +var async = require('async'); +var dbConfig = require('./dbconfig.js'); +var assist = require('./dataTypeAssist.js'); + +describe('70. plsqlBindScalar.js', function() { + + var connection = null; + var node6plus = false; // assume node runtime version is lower than 6 + + before(function(done) { + async.series([ + function(cb) { + oracledb.getConnection(dbConfig, function(err, conn) { + should.not.exist(err); + connection = conn; + // Note down whether node runtime version is >= 6 or not + if ( process.versions["node"].substring ( 0, 1 ) >= "6" ) + node6plus = true; + + cb(); + }); + }, + function(cb) { + connection.execute( + "alter session set time_zone='UTC'", + function(err) { + should.not.exist(err); + cb(); + }); + } + ],done); + + }); // before + + after(function(done) { + connection.release( function(err) { + should.not.exist(err); + done(); + }); + }); // after + + describe('70.1 PL/SQL bind scalar, dir: BIND_IN and BIND_OUT, type: STRING', function() { + + before(function(done) { + var proc = "CREATE OR REPLACE \n" + + "FUNCTION nodb_plsqlbindfunc71(strValue IN VARCHAR2) RETURN VARCHAR2 \n" + + "IS \n" + + "BEGIN \n" + + " RETURN strValue;\n" + + "END nodb_plsqlbindfunc71;"; + + connection.execute( + proc, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // before + + after(function(done) { + var sql = "DROP FUNCTION nodb_plsqlbindfunc71"; + connection.execute( + sql, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // after + + var sqlrun = "BEGIN :output := nodb_plsqlbindfunc71(:strValue); END;"; + var resultBind = {type: oracledb.STRING, dir: oracledb.BIND_OUT, maxSize: 2000}; + + it('70.1.1 basic case: a simple string', function(done) { + var bindVar = { + output: resultBind, + strValue: {type: oracledb.STRING, dir: oracledb.BIND_IN, val: "PL/SQL Binding Scalar"} + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.outBinds.output, "PL/SQL Binding Scalar"); + done(); + } + ); + }); // 70.1.1 + + it('70.1.2 negative: bind in value and type mismatch', function(done) { + var bindVar = { + output: resultBind, + strValue: {type: oracledb.STRING, dir: oracledb.BIND_IN, val: 42} + }; + + connection.execute( + sqlrun, + bindVar, + function(err) { + should.exist(err); + (err.message).should.startWith('NJS-011:'); + // NJS-011: encountered bind value and type mismatch in parameter 2 + done(); + } + ); + }); // 70.1.2 + + it('70.1.3 val: null', function(done) { + var bindVar = { + output: resultBind, + strValue: {type: oracledb.STRING, dir: oracledb.BIND_IN, val: null} + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.outBinds.output, null); + done(); + } + ); + }); // 70.1.3 + + it('70.1.4 val: empty string', function(done) { + var bindVar = { + output: resultBind, + strValue: {type: oracledb.STRING, dir: oracledb.BIND_IN, val: ''} + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.outBinds.output, null); + done(); + } + ); + }); // 70.1.4 + + it('70.1.5 val: undefined', function(done) { + var bindVar = { + output: resultBind, + strValue: {type: oracledb.STRING, dir: oracledb.BIND_IN, val: undefined} + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.outBinds.output, null); + done(); + } + ); + }); + + it('70.1.6 tests default dir & type', function(done) { + var bindVar = { + output: resultBind, + strValue: "PL/SQL Binding Scalar" + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.outBinds.output, "PL/SQL Binding Scalar"); + done(); + } + ); + }); // 70.1.6 + + it('70.1.7 val: NaN', function(done) { + var bindVar = { + output: resultBind, + strValue: {type: oracledb.STRING, dir: oracledb.BIND_IN, val: NaN} + }; + + connection.execute( + sqlrun, + bindVar, + function(err) { + should.exist(err); + // console.log(result); + (err.message).should.startWith('NJS-011:'); + done(); + } + ); + });// 70.1.7 + + }); // 70.1 + + describe('70.2 dir: BIND_IN and BIND_OUT, type: NUMBER', function() { + + before(function(done) { + var proc = "CREATE OR REPLACE \n" + + "FUNCTION nodb_plsqlbindfunc72(numValue IN NUMBER) RETURN NUMBER \n" + + "IS \n" + + "BEGIN \n" + + " RETURN numValue;\n" + + "END nodb_plsqlbindfunc72;"; + + connection.execute( + proc, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // before + + after(function(done) { + var sql = "DROP FUNCTION nodb_plsqlbindfunc72"; + connection.execute( + sql, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // after + + var sqlrun = "BEGIN :output := nodb_plsqlbindfunc72(:numValue); END;"; + var resultBind = {type: oracledb.NUMBER, dir: oracledb.BIND_OUT}; + + it('70.2.1 basic case', function(done) { + var bindVar = { + output: resultBind, + numValue: {type: oracledb.NUMBER, dir: oracledb.BIND_IN, val: 755} + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.outBinds.output, 755); + done(); + } + ); + }); // 70.2.1 + + it('70.2.2 auto detect number type', function(done) { + var bindVar = { + output: resultBind, + numValue: 755 + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.outBinds.output, 755); + done(); + } + ); + }); // 70.2.2 + + it('70.2.3 val: null', function(done) { + var bindVar = { + output: resultBind, + numValue: {type: oracledb.NUMBER, dir: oracledb.BIND_IN, val: null} + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.outBinds.output, null); + done(); + } + ); + }); // 70.2.3 + + it('70.2.4 Negative: bind value and type mismatch - val: empty string', function(done) { + var bindVar = { + output: resultBind, + numValue: {type: oracledb.NUMBER, dir: oracledb.BIND_IN, val: ''} + }; + + connection.execute( + sqlrun, + bindVar, + function(err) { + should.exist(err); + (err.message).should.startWith('NJS-011:'); + // console.log(result); + done(); + } + ); + }); // 70.2.4 + + it('70.2.5 val: 0', function(done) { + var bindVar = { + output: resultBind, + numValue: {type: oracledb.NUMBER, dir: oracledb.BIND_IN, val: 0} + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.outBinds.output, 0); + done(); + } + ); + }); // 70.2.5 + + it('70.2.6 val: undefined', function(done) { + var bindVar = { + output: resultBind, + numValue: {type: oracledb.NUMBER, dir: oracledb.BIND_IN, val: undefined} + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.outBinds.output, null); + done(); + } + ); + }); // 70.2.6 + + it('70.2.7 val: NaN', function(done) { + var bindVar = { + output: resultBind, + numValue: {type: oracledb.NUMBER, dir: oracledb.BIND_IN, val: NaN} + }; + + connection.execute( + sqlrun, + bindVar, + function(err) { + should.not.exist(err); + + done(); + } + ); + }); // 70.2.7 + + it('70.2.8 val: -1', function(done) { + var bindVar = { + output: resultBind, + numValue: {type: oracledb.NUMBER, dir: oracledb.BIND_IN, val: -1} + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.outBinds.output, -1); + done(); + } + ); + }); // 70.2.8 + + it.skip('70.2.9 val: maxval', function(done) { + var bindVar = { + output: resultBind, + numValue: {type: oracledb.NUMBER, dir: oracledb.BIND_IN, val: 0x0FFFFFFFFFFFFFFF} + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.outBinds.output, 0x0FFFFFFFFFFFFFFF); + done(); + } + ); + }); // 70.2.9 + + }); // 70.2 + + describe('70.3 dir: BIND_IN and BIND_OUT, type: DATE', function() { + + before(function(done) { + var proc = "CREATE OR REPLACE \n" + + "FUNCTION nodb_plsqlbindfunc73(dateValue IN DATE) RETURN DATE \n" + + "IS \n" + + "BEGIN \n" + + " RETURN dateValue;\n" + + "END nodb_plsqlbindfunc73;"; + + connection.execute( + proc, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // before + + after(function(done) { + var sql = "DROP FUNCTION nodb_plsqlbindfunc73"; + connection.execute( + sql, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // after + + var sqlrun = "BEGIN :output := nodb_plsqlbindfunc73(:dateValue); END;"; + var resultBind = {type: oracledb.DATE, dir: oracledb.BIND_OUT}; + var dt = new Date( 2016, 8, 1 ); + + it('70.3.1 basic case', function(done) { + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.DATE, dir: oracledb.BIND_IN, val: dt} + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + (result.outBinds.output).should.eql(dt); + done(); + } + ); + }); // 70.3.1 + + it('70.3.2 auto detect Date type', function(done) { + var bindVar = { + output: resultBind, + dateValue: dt + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + (result.outBinds.output).should.eql(dt); + done(); + } + ); + }); // 70.3.2 + + it('70.3.3 val: null', function(done) { + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.DATE, dir: oracledb.BIND_IN, val: null} + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.outBinds.output, null); + done(); + } + ); + }); // 70.3.3 + + it('70.3.4 val: empty string, negative - bind value and type mismatch', function(done) { + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.DATE, dir: oracledb.BIND_IN, val: ''} + }; + + connection.execute( + sqlrun, + bindVar, + function(err) { + should.exist(err); + (err.message).should.startWith('NJS-011:'); + // console.log(result); + done(); + } + ); + }); // 70.3.4 + + it('70.3.5 val: undefined', function(done) { + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.DATE, dir: oracledb.BIND_IN, val: undefined} + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.outBinds.output, null); + done(); + } + ); + }); // 70.3.5 + + it('70.3.6 val: NaN', function(done) { + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.DATE, dir: oracledb.BIND_IN, val: NaN} + }; + + connection.execute( + sqlrun, + bindVar, + function(err) { + should.exist(err); + (err.message).should.startWith('NJS-011:'); + // console.log(result); + done(); + } + ); + }); // 70.3.6 + + it('70.3.7 val: invalid Date Value: Feb 30, 2016', function(done) { + var date = new Date ( 2016, 1, 30 ); + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.DATE, dir: oracledb.BIND_IN, val: date} + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + var resultDate = new Date ( 2016, 2, 1); + (result.outBinds.output).should.eql(resultDate); + done(); + } + ); + }); // 70.3.7 + + it('70.3.8 val: 1969-12-31', function(done) { + var date = new Date ( 1969, 11, 31 ); + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.DATE, dir: oracledb.BIND_IN, val: date} + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + (result.outBinds.output).should.eql(date); + done(); + } + ); + }); // 70.3.8 + + it('70.3.9 val: epoch date 1970-1-1', function(done) { + var date = new Date ( 1970, 0, 1 ); + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.DATE, dir: oracledb.BIND_IN, val: date} + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + (result.outBinds.output).should.eql(date); + done(); + } + ); + }); // 70.3.9 + + it('70.3.10 val: create Date value using numeric value: new Date(number)', function(done) { + var date = new Date ( 1476780296673 ); + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.DATE, dir: oracledb.BIND_IN, val: date} + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + //Oracle stores only the fractions up to second in a DATE field. + var dateResult = new Date ( 1476780296000 ); + (result.outBinds.output).should.eql(dateResult); + done(); + } + ); + }); // 70.3.10 + + it('70.3.11 val: create Date value using numeric value: new Date(7 number)', function(done) { + var date = new Date ( 2011, 5, 3, 4, 6, 23, 123 ); + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.DATE, dir: oracledb.BIND_IN, val: date} + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + //Oracle stores only the fractions up to second in a DATE field. + var dateResult = new Date ( 2011, 5, 3, 4, 6, 23, 0 ); + (result.outBinds.output).should.eql(dateResult); + done(); + } + ); + }); // 70.3.11 + + it('70.3.12 val: create Date value using numeric value: 0', function(done) { + //Zero time is 01 January 1970 00:00:00 UTC + var date = new Date ( 0 ); + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.DATE, dir: oracledb.BIND_IN, val: date} + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + var dateResult = new Date ( Date.UTC( 1970, 0, 1 ) ); + (result.outBinds.output).should.eql(dateResult); + done(); + } + ); + }); // 70.3.12 + + }); // 70.3 + + describe('70.4 dir: BIND_IN and BIND_OUT, type: BUFFER', function() { + + before(function(done) { + var proc = "CREATE OR REPLACE \n" + + "FUNCTION nodb_plsqlbindfunc74(bufValue IN RAW) RETURN RAW \n" + + "IS \n" + + "BEGIN \n" + + " RETURN bufValue;\n" + + "END nodb_plsqlbindfunc74;"; + + connection.execute( + proc, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // before + + after(function(done) { + var sql = "DROP FUNCTION nodb_plsqlbindfunc74"; + connection.execute( + sql, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // after + + var sqlrun = "BEGIN :output := nodb_plsqlbindfunc74(:bufValue); END;"; + var resultBind = {type: oracledb.BUFFER, dir: oracledb.BIND_OUT}; + var bufsize = 100; + var bindValue = assist.createBuffer(bufsize); + + it('70.4.1 basic case', function(done) { + var bindVar = { + output: resultBind, + bufValue: {type: oracledb.BUFFER, dir: oracledb.BIND_IN, val: bindValue} + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + (result.outBinds.output).should.eql(bindValue); + done(); + } + ); + }); // 70.4.1 + + it('70.4.2 auto detect Buffer type', function(done) { + var bindVar = { + output: resultBind, + bufValue: bindValue + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + (result.outBinds.output).should.eql(bindValue); + done(); + } + ); + }); // 70.4.2 + + it('70.4.3 val: null', function(done) { + var bindVar = { + output: resultBind, + bufValue: {type: oracledb.BUFFER, dir: oracledb.BIND_IN, val: null} + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.outBinds.output, null); + done(); + } + ); + }); // 70.4.3 + + it('70.4.4 val: empty string', function(done) { + var bindVar = { + output: resultBind, + bufValue: {type: oracledb.BUFFER, dir: oracledb.BIND_IN, val: ''} + }; + + connection.execute( + sqlrun, + bindVar, + function(err) { + should.exist(err); + (err.message).should.startWith('NJS-011:'); + // console.log(result); + done(); + } + ); + }); // 70.4.4 + + it('70.4.5 val: undefined', function(done) { + var bindVar = { + output: resultBind, + bufValue: {type: oracledb.BUFFER, dir: oracledb.BIND_IN, val: undefined} + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + should.strictEqual(result.outBinds.output, null); + done(); + } + ); + }); // 70.4.5 + + it('70.4.6 val: NaN', function(done) { + var bindVar = { + output: resultBind, + bufValue: {type: oracledb.BUFFER, dir: oracledb.BIND_IN, val: NaN} + }; + + connection.execute( + sqlrun, + bindVar, + function(err) { + should.exist(err); + (err.message).should.startWith('NJS-011:'); + done(); + } + ); + }); // 70.4.6 + + }); // 70.4 + + describe('70.5 dir: BIND_INOUT, type: STRING', function() { + + before(function(done) { + var proc = "CREATE OR REPLACE PROCEDURE nodb_inoutproc5 (p_inout IN OUT STRING) \n" + + "AS \n" + + "BEGIN \n" + + " p_inout := p_inout; \n" + + "END nodb_inoutproc5;"; + + connection.execute( + proc, + function(err) { + should.not.exist(err); + done(); + } + ); + + }); // before + + after(function(done) { + var sql = "DROP PROCEDURE nodb_inoutproc5"; + connection.execute( + sql, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // after + + var sqlrun = "begin nodb_inoutproc5(p_inout => :p_inout); end;"; + + it('70.5.1 basic case: a simple string', function(done) { + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + type: oracledb.STRING, + val: "PL/SQL Binding INOUT Scalar" + } + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.outBinds.p_inout, "PL/SQL Binding INOUT Scalar"); + done(); + } + ); + }); // 70.5.1 + + it('70.5.2 tests default type', function(done) { + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + val: "PL/SQL Binding INOUT Scalar" + } + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.outBinds.p_inout, "PL/SQL Binding INOUT Scalar"); + done(); + } + ); + }); // 70.5.2 + + it('70.5.3 negative: bind value and type mismatch', function(done) { + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + type: oracledb.STRING, + val: 755 + } + }; + + connection.execute( + sqlrun, + bindVar, + function(err) { + should.exist(err); + (err.message).should.startWith('NJS-011'); + done(); + } + ); + }); // 70.5.3 + + it('70.5.4 val: null', function(done) { + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + type: oracledb.STRING, + val: null + } + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.outBinds.p_inout, null); + done(); + } + ); + }); // 70.5.4 + + it('70.5.5 val: empty string', function(done) { + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + type: oracledb.STRING, + val: '' + } + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.outBinds.p_inout, null); + done(); + } + ); + }); // 70.5.5 + + it('70.5.6 val: undefined', function(done) { + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + type: oracledb.STRING, + val: undefined + } + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.outBinds.p_inout, null); + done(); + } + ); + }); // 70.5.6 + + it('70.5.7 val: NaN', function(done) { + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + type: oracledb.STRING, + val: NaN + } + }; + + connection.execute( + sqlrun, + bindVar, + function(err) { + should.exist(err); + (err.message).should.startWith('NJS-011'); + done(); + } + ); + }); // 70.5.7 + + it('70.5.8 NULL IN and NON-NULL out', function(done) { + var proc508 = "CREATE OR REPLACE PROCEDURE nodb_inoutproc508 (p_inout IN OUT STRING) \n" + + "AS \n" + + "BEGIN \n" + + " p_inout := 'abc'; \n" + + "END nodb_inoutproc508;"; + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + type: oracledb.STRING, + val: null + } + }; + var sqlrun508 = "begin nodb_inoutproc508(p_inout => :p_inout); end;"; + var sqldrop = "DROP PROCEDURE nodb_inoutproc508"; + async.series([ + function(cb) { + connection.execute( + proc508, + function(err) { + should.not.exist(err); + cb(); + } + ); + }, + function(cb) { + connection.execute( + sqlrun508, + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.outBinds.p_inout, 'abc'); + cb(); + } + ); + }, + function(cb) { + connection.execute( + sqldrop, + function(err) { + should.not.exist(err); + cb(); + } + ); + } + ], done); + }); // 70.5.8 + + it('70.5.9 NON-NULL IN and NULL OUT', function(done) { + var proc509 = "CREATE OR REPLACE PROCEDURE nodb_inoutproc509 (p_inout IN OUT STRING) \n" + + "AS \n" + + "BEGIN \n" + + " p_inout := null; \n" + + "END nodb_inoutproc509;"; + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + type: oracledb.STRING, + val: "abc" + } + }; + var sqlrun509 = "begin nodb_inoutproc509(p_inout => :p_inout); end;"; + var sqldrop = "DROP PROCEDURE nodb_inoutproc509"; + + async.series([ + function(cb) { + connection.execute( + proc509, + function(err) { + should.not.exist(err); + cb(); + } + ); + }, + function(cb) { + connection.execute( + sqlrun509, + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.outBinds.p_inout, null); + cb(); + } + ); + }, + function(cb) { + connection.execute( + sqldrop, + function(err) { + should.not.exist(err); + cb(); + } + ); + } + ], done); + }); // 70.5.9 + + it('70.5.10 n Length IN and 2n OUT', function(done) { + var proc510 = "CREATE OR REPLACE PROCEDURE nodb_inoutproc510 (p_inout IN OUT STRING) \n" + + "AS \n" + + "BEGIN \n" + + " p_inout := concat (p_inout, p_inout); \n" + + "END nodb_inoutproc510;"; + var strVar = "abcdefghijklmnopqrstuvwxyz"; + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + type: oracledb.STRING, + val: strVar + } + }; + var sqlrun510 = "begin nodb_inoutproc510(p_inout => :p_inout); end;"; + var sqldrop = "DROP PROCEDURE nodb_inoutproc510"; + async.series([ + function(cb) { + connection.execute( + proc510, + function(err) { + should.not.exist(err); + cb(); + } + ); + }, + function(cb) { + connection.execute( + sqlrun510, + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + var resutVar = strVar + strVar; + should.strictEqual(result.outBinds.p_inout, resutVar); + cb(); + } + ); + }, + function(cb) { + connection.execute( + sqldrop, + function(err) { + should.not.exist(err); + cb(); + } + ); + } + ], done); + }); // 70.5.10 + + it('70.5.11 2n Length IN and n OUT', function(done) { + var proc511 = "CREATE OR REPLACE PROCEDURE nodb_inoutproc511 (p_inout IN OUT STRING) \n" + + "AS \n" + + "BEGIN \n" + + " p_inout := substr ( p_inout, 1, Length(p_inout)/2 ); \n" + + "END nodb_inoutproc511;"; + var strVar = "Pack my bag with five dozen liquor jugs"; + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + type: oracledb.STRING, + val: strVar + } + }; + var sqlrun511 = "begin nodb_inoutproc511(p_inout => :p_inout); end;"; + var sqldrop = "DROP PROCEDURE nodb_inoutproc511"; + async.series([ + function(cb) { + connection.execute( + proc511, + function(err) { + should.not.exist(err); + cb(); + } + ); + }, + function(cb) { + connection.execute( + sqlrun511, + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + var resultVar = "Pack my bag with fiv"; + //var resultVar=strVar.substr(0,(strVar.length-1)/2); + should.strictEqual(result.outBinds.p_inout, resultVar); + cb(); + } + ); + }, + function(cb) { + connection.execute( + sqldrop, + function(err) { + should.not.exist(err); + cb(); + } + ); + } + ], done); + }); // 70.5.11 + + }); // 70.5 + + describe('70.6 dir: BIND_INOUT, type: NUMBER', function() { + + before(function(done) { + var proc = "CREATE OR REPLACE PROCEDURE nodb_inoutproc6 (p_inout IN OUT NUMBER) \n" + + "AS \n" + + "BEGIN \n" + + " p_inout := p_inout; \n" + + "END nodb_inoutproc6;"; + + connection.execute( + proc, + function(err) { + should.not.exist(err); + done(); + } + ); + + }); // before + + after(function(done) { + var sql = "DROP PROCEDURE nodb_inoutproc6"; + connection.execute( + sql, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // after + + var sqlrun = "begin nodb_inoutproc6(p_inout => :p_inout); end;"; + + it('70.6.1 basic case', function(done) { + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + type: oracledb.NUMBER, + val: 8396 + } + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.outBinds.p_inout, 8396); + done(); + } + ); + }); // 70.6.1 + + it('70.6.2 auto detect number type', function(done) { + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + val: 8396 + } + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.outBinds.p_inout, 8396); + done(); + } + ); + }); // 70.6.2 + + it('70.6.3 negative: bind value and type mismatch - val: empty string', function(done) { + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + type: oracledb.NUMBER, + val: '' + } + }; + + connection.execute( + sqlrun, + bindVar, + function(err) { + should.exist(err); + (err.message).should.startWith('NJS-011:'); + done(); + } + ); + }); // 70.6.3 + + it('70.6.4 val: null', function(done) { + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + type: oracledb.NUMBER, + val: null + } + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.outBinds.p_inout, null); + done(); + } + ); + }); // 70.6.4 + + it('70.6.5 val: undefined',function(done) { + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + type: oracledb.NUMBER, + val: undefined + } + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.outBinds.p_inout, null); + done(); + } + ); + }); // 70.6.5 + + it.skip('70.6.6 val: NaN', function(done) { + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + type: oracledb.NUMBER, + val: NaN + } + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.outBinds.p_inout, null); + done(); + } + ); + }); // 70.6.6 + + it('70.6.7 val: 0', function(done) { + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + type: oracledb.NUMBER, + val: 0 + } + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.outBinds.p_inout, 0); + done(); + } + ); + }); // 70.6.7 + + it('70.6.8 val: -1', function(done) { + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + type: oracledb.NUMBER, + val: -1 + } + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.outBinds.p_inout, -1); + done(); + } + ); + }); // 70.6.8 + + it.skip('70.6.9 val: maxval', function(done) { + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + type: oracledb.NUMBER, + val: 0x0FFFFFFFFFFFFFFF + } + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + should.strictEqual(result.outBinds.p_inout, Number.MAX_VALUE); + done(); + } + ); + }); // 70.6.9 + + it('70.6.10 NULL IN and NON-NULL out', function(done) { + var proc610 = "CREATE OR REPLACE PROCEDURE nodb_inoutproc610 (p_inout IN OUT NUMBER) \n" + + "AS \n" + + "BEGIN \n" + + " p_inout := 3; \n" + + "END nodb_inoutproc610;"; + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + type: oracledb.NUMBER, + val: null + } + }; + var sqlrun610 = "begin nodb_inoutproc610(p_inout => :p_inout); end;"; + var sqldrop = "DROP PROCEDURE nodb_inoutproc610"; + + async.series([ + function(cb) { + connection.execute( + proc610, + function(err) { + should.not.exist(err); + cb(); + } + ); + }, + function(cb) { + connection.execute( + sqlrun610, + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.outBinds.p_inout, 3); + cb(); + } + ); + }, + function(cb) { + connection.execute( + sqldrop, + function(err) { + should.not.exist(err); + cb(); + } + ); + } + ], done); + }); // 70.6.10 + + it('70.6.11 NON-NULL IN and NULL OUT', function(done) { + var proc611 = "CREATE OR REPLACE PROCEDURE nodb_inoutproc611 (p_inout IN OUT NUMBER) \n" + + "AS \n" + + "BEGIN \n" + + " p_inout := null; \n" + + "END nodb_inoutproc611;"; + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + type: oracledb.NUMBER, + val: 3 + } + }; + var sqlrun611 = "begin nodb_inoutproc611(p_inout => :p_inout); end;"; + var sqldrop = "DROP PROCEDURE nodb_inoutproc611"; + + async.series([ + function(cb) { + connection.execute( + proc611, + function(err) { + should.not.exist(err); + cb(); + } + ); + }, + function(cb) { + connection.execute( + sqlrun611, + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.outBinds.p_inout, null); + cb(); + } + ); + }, + function(cb) { + connection.execute( + sqldrop, + function(err) { + should.not.exist(err); + cb(); + } + ); + } + ], done); + });// 70.6.11 + + }); // 70.6 + + describe('70.7 dir: BIND_INOUT, type: DATE', function() { + + before(function(done) { + var proc = "CREATE OR REPLACE PROCEDURE nodb_inoutproc7 (p_inout IN OUT DATE) \n" + + "AS \n" + + "BEGIN \n" + + " p_inout := p_inout; \n" + + "END nodb_inoutproc7;"; + + connection.execute( + proc, + function(err) { + should.not.exist(err); + done(); + } + ); + + }); // before + + after(function(done) { + var sql = "DROP PROCEDURE nodb_inoutproc7"; + connection.execute( + sql, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // after + + var sqlrun = "begin nodb_inoutproc7(p_inout => :p_inout); end;"; + var daterun = new Date( 2016, 7, 5 ); + + it('70.7.1 basic case', function(done) { + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + type: oracledb.DATE, + val: daterun + } + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + (result.outBinds.p_inout).should.eql(daterun); + done(); + } + ); + }); // 70.7.1 + + it('70.7.2 auto detect Date type', function(done) { + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + val: daterun + } + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + (result.outBinds.p_inout).should.eql(daterun); + done(); + } + ); + }); // 70.7.2 + + it('70.7.3 val: null', function(done) { + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + type: oracledb.DATE, + val: null + } + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.outBinds.p_inout, null); + done(); + } + ); + }); // 70.7.3 + + it('70.7.4 val: empty string, negative - bind value and type mismatch', function(done) { + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + type: oracledb.DATE, + val: '' + } + }; + + connection.execute( + sqlrun, + bindVar, + function(err) { + should.exist(err); + (err.message).should.startWith('NJS-011:'); + done(); + } + ); + }); // 70.7.4 + + it('70.7.5 val: undefined', function(done) { + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + type: oracledb.DATE, + val: undefined + } + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.outBinds.p_inout, null); + done(); + } + ); + }); // 70.7.5 + + it('70.7.6 val: NaN', function(done) { + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + type: oracledb.DATE, + val: NaN + } + }; + + connection.execute( + sqlrun, + bindVar, + function(err) { + should.exist(err); + (err.message).should.startWith('NJS-011:'); + done(); + } + ); + }); // 70.7.6 + + it('70.7.7 val: invalid Date Value: Feb 30, 2016', function(done) { + var date = new Date ( 2016, 1, 30 ); + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + type: oracledb.DATE, + val: date + } + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + //console.log(result); + var resultDate = new Date ( 2016, 2, 1 ); + (result.outBinds.p_inout).should.eql(resultDate); + done(); + } + ); + }); // 70.7.7 + + it('70.7.8 val: 1969-12-31', function(done) { + var date = new Date ( 1969, 11, 31 ); + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + type: oracledb.DATE, + val: date + } + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + (result.outBinds.p_inout).should.eql(date); + done(); + } + ); + }); // 70.7.8 + + it('70.7.9 val: epoch date 1970-1-1', function(done) { + var date = new Date ( 1970, 0, 1 ); + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + type: oracledb.DATE, + val: date + } + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + (result.outBinds.p_inout).should.eql(date); + done(); + } + ); + }); // 70.7.9 + + it('70.7.10 NULL IN and NON-NULL out', function(done) { + var proc710 = "CREATE OR REPLACE PROCEDURE nodb_inoutproc710 (p_inout IN OUT DATE) \n" + + "AS \n" + + "BEGIN \n" + + " p_inout := TO_DATE('5-AUG-2016'); \n" + + "END nodb_inoutproc710;"; + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + type: oracledb.DATE, + val: null + } + }; + var sqlrun710 = "begin nodb_inoutproc710(p_inout => :p_inout); end;"; + var sqldrop = "DROP PROCEDURE nodb_inoutproc710"; + async.series([ + function(cb) { + connection.execute( + proc710, + function(err) { + should.not.exist(err); + cb(); + } + ); + }, + function(cb) { + connection.execute( + sqlrun710, + bindVar, + function(err, result) { + should.not.exist(err); + var date = new Date( "2016-08-05T00:00:00.000Z" ); + (result.outBinds.p_inout).should.eql(date); + cb(); + } + ); + }, + function(cb) { + connection.execute( + sqldrop, + function(err) { + should.not.exist(err); + cb(); + } + ); + } + ], done); + }); // 70.7.10 + + it('70.7.11 NON-NULL IN and NULL OUT', function(done) { + var proc711 = "CREATE OR REPLACE PROCEDURE nodb_inoutproc711 (p_inout IN OUT DATE) \n" + + "AS \n" + + "BEGIN \n" + + " p_inout := null; \n" + + "END nodb_inoutproc711;"; + var date = new Date( 2011, 0, 12 ); + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + type: oracledb.DATE, + val: date + } + }; + var sqlrun711 = "begin nodb_inoutproc711(p_inout => :p_inout); end;"; + var sqldrop = "DROP PROCEDURE nodb_inoutproc711"; + async.series([ + function(cb) { + connection.execute( + proc711, + function(err) { + should.not.exist(err); + cb(); + } + ); + }, + function(cb) { + connection.execute( + sqlrun711, + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.outBinds.p_inout, null); + cb(); + } + ); + }, + function(cb) { + connection.execute( + sqldrop, + function(err) { + should.not.exist(err); + cb(); + } + ); + } + ], done); + }); // 70.7.11 + + + }); // 70.7 + + describe('70.8 dir: BIND_INOUT, type: BUFFER', function() { + before(function(done) { + var proc = "CREATE OR REPLACE PROCEDURE nodb_inoutproc8 (p_inout IN OUT RAW) \n" + + "AS \n" + + "BEGIN \n" + + " p_inout := p_inout; \n" + + "END nodb_inoutproc8;"; + + connection.execute( + proc, + function(err) { + should.not.exist(err); + done(); + } + ); + + }); // before + + after(function(done) { + var sql = "DROP PROCEDURE nodb_inoutproc8"; + connection.execute( + sql, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // after + + var sqlrun = "begin nodb_inoutproc8(p_inout => :p_inout); end;"; + + var bufsize = 201; + var bufValue = assist.createBuffer(bufsize); + + it('70.8.1 basic case', function(done) { + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + type: oracledb.BUFFER, + val: bufValue, + maxSize: 32767 // max allowed value of maxSize in PL/SQL + } + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + (result.outBinds.p_inout).should.eql(bufValue); + done(); + } + ); + }); // 70.8.1 + + it('70.8.2 auto detect BUFFER type', function(done) { + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + val: bufValue, + maxSize: 32767 + } + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + (result.outBinds.p_inout).should.eql(bufValue); + done(); + } + ); + }); // 70.8.2 + + it('70.8.3 val: null', function(done) { + var emptybuf; + if ( node6plus ) + emptybuf = Buffer.alloc ( 0 ) ; + else + emptybuf = new Buffer ( 0 ); + + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + type: oracledb.BUFFER, + val: emptybuf, + maxSize: 32767 + } + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.outBinds.p_inout, null); + done(); + } + ); + }); // 70.8.3 + + it('70.8.4 val: empty string', function(done) { + var emptybuf; + + if ( node6plus ) + emptybuf = Buffer.from ("", "utf-8" ); + else + emptybuf = new Buffer ( "", "utf-8" ) ; + + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + type: oracledb.BUFFER, + val: emptybuf, + maxSize: 32767 + } + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.outBinds.p_inout, null); + done(); + } + ); + }); // 70.8.4 + + it('70.8.5 val: undefined', function(done) { + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + type: oracledb.BUFFER, + val: undefined, + maxSize: 32767 + } + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.outBinds.p_inout, null); + done(); + } + ); + }); // 70.8.5 + + it('70.8.6 val: NaN', function(done) { + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + type: oracledb.BUFFER, + val: NaN, + maxSize: 32767 + } + }; + + connection.execute( + sqlrun, + bindVar, + function(err) { + should.exist(err); + (err.message).should.startWith('NJS-011:'); + done(); + } + ); + }); // 70.8.6 + + }); // 70.8 + + describe('70.9 Query the binded data by SQL', function() { + before(function(done) { + + var proc1 ="BEGIN \n" + + " DECLARE \n" + + " e_table_missing EXCEPTION; \n" + + " PRAGMA EXCEPTION_INIT(e_table_missing, -00942); \n" + + " BEGIN \n" + + " EXECUTE IMMEDIATE('DROP TABLE nodb_plsqlbindtab PURGE'); \n" + + " EXCEPTION \n" + + " WHEN e_table_missing \n" + + " THEN NULL; \n" + + " END; \n" + + " EXECUTE IMMEDIATE (' \n" + + " CREATE TABLE nodb_plsqlbindtab ( \n" + + " id NUMBER, \n" + + " str VARCHAR2(4000), \n" + + " num NUMBER, \n" + + " dat DATE, \n" + + " buf RAW(2000) \n" + + " ) \n" + + " '); \n" + + "END; "; + + var proc2 ="CREATE OR REPLACE PROCEDURE nodb_inoutproc9 ( \n" + + " p_in IN NUMBER, p_inout1 IN OUT VARCHAR2, \n" + + " p_inout2 IN OUT NUMBER, p_inout3 IN OUT DATE, p_inout4 IN OUT RAW) \n" + + "AS \n" + + "BEGIN \n" + + " insert into nodb_plsqlbindtab(id, str, num, dat, buf) values (p_in, p_inout1, p_inout2, p_inout3, p_inout4); \n" + + "END nodb_inoutproc9;"; + + var proc3 ="CREATE OR REPLACE PROCEDURE nodb_inoutproc10 ( \n" + + " p_in IN NUMBER, p_str IN VARCHAR2, \n" + + " p_num IN NUMBER, p_dat IN DATE, p_buf IN RAW) \n" + + "AS \n" + + "BEGIN \n" + + " insert into nodb_plsqlbindtab(id, str, num, dat, buf) values (p_in, p_str, p_num, p_dat, p_buf); \n" + + "END nodb_inoutproc10;"; + + async.series([ + function(cb) { + connection.execute( + proc1, + function(err) { + should.not.exist(err); + cb(); + } + ); + }, + function(cb) { + connection.execute( + proc2, + function(err) { + should.not.exist(err); + cb(); + } + ); + }, + function(cb) { + connection.execute( + proc3, + function(err) { + should.not.exist(err); + cb(); + } + ); + } + ], done); + + }); // before + + after(function(done) { + + async.series([ + function(cb) { + connection.execute( + "DROP PROCEDURE nodb_inoutproc9", + function(err) { + should.not.exist(err); + cb(); + } + ); + }, + function(cb) { + connection.execute( + "DROP PROCEDURE nodb_inoutproc10", + function(err) { + should.not.exist(err); + cb(); + } + ); + }, + function(cb) { + connection.execute( + "DROP TABLE nodb_plsqlbindtab PURGE", + function(err) { + should.not.exist(err); + cb(); + } + ); + } + ], done); + }); // after + + var sqlinout = "begin nodb_inoutproc9(:p_in, :p_inout1, :p_inout2, :p_inout3, :p_inout4); end;"; + var sqlin = "begin nodb_inoutproc10(:p_in, :p_str, :p_num, :p_dat, :p_buf); end;"; + + it('70.9.1 basic case', function(done) { + + var rowid = 1; + var bufsize = 201; + var bufValue = assist.createBuffer(bufsize); + var daterun = new Date( 2016, 7, 5 ); + + var bindVar = { + p_in: rowid, + p_inout1: { + dir: oracledb.BIND_INOUT, + type: oracledb.STRING, + val: "PL/SQL Binding INOUT Scalar" + }, + p_inout2: { + dir: oracledb.BIND_INOUT, + type: oracledb.NUMBER, + val: 101 + }, + p_inout3: { + dir: oracledb.BIND_INOUT, + type: oracledb.DATE, + val: daterun + }, + p_inout4: { + dir: oracledb.BIND_INOUT, + type: oracledb.BUFFER, + val: bufValue, + maxSize: 32767 + } + }; + + async.series([ + function(cb) { + connection.execute( + sqlinout, + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.outBinds.p_inout1, "PL/SQL Binding INOUT Scalar"); + should.strictEqual(result.outBinds.p_inout2, 101); + (result.outBinds.p_inout3).should.eql(daterun); + (result.outBinds.p_inout4).should.eql(bufValue); + cb(); + } + ); + }, + function(cb) { + connection.execute( + "select * from nodb_plsqlbindtab where id = :i", + [rowid], + { outFormat: oracledb.OBJECT }, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.rows[0].STR, "PL/SQL Binding INOUT Scalar"); + should.strictEqual(result.rows[0].NUM, 101); + (result.rows[0].DAT).should.eql(daterun); + (result.rows[0].BUF).should.eql(bufValue); + cb(); + } + ); + } + ], done); + + }); // 70.9.1 + + it('70.9.2 dir: BIND_INOUT, val: null', function(done) { + + var rowid = 2; + var emptybuf; + + if ( node6plus ) + emptybuf = Buffer.alloc ( 0 ) ; + else + emptybuf = new Buffer ( 0 ) ; + + var bindVar = { + p_in: rowid, + p_inout1: { + dir: oracledb.BIND_INOUT, + type: oracledb.STRING, + val: null + }, + p_inout2: { + dir: oracledb.BIND_INOUT, + type: oracledb.NUMBER, + val: null + }, + p_inout3: { + dir: oracledb.BIND_INOUT, + type: oracledb.DATE, + val: null + }, + p_inout4: { + dir: oracledb.BIND_INOUT, + type: oracledb.BUFFER, + val: emptybuf, + maxSize: 32767 + } + }; + + async.series([ + function(cb) { + connection.execute( + sqlinout, + bindVar, + function(err, result) { + should.not.exist(err); + //console.log(result); + should.strictEqual(result.outBinds.p_inout1, null); + should.strictEqual(result.outBinds.p_inout2, null); + should.strictEqual(result.outBinds.p_inout3, null); + should.strictEqual(result.outBinds.p_inout4, null); + cb(); + } + ); + }, + function(cb) { + connection.execute( + "select * from nodb_plsqlbindtab where id = :i", + [rowid], + { outFormat: oracledb.OBJECT }, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.rows[0].STR, null); + should.strictEqual(result.rows[0].NUM, null); + should.strictEqual(result.rows[0].DAT, null); + should.strictEqual(result.rows[0].BUF, null); + cb(); + } + ); + } + ], done); + + }); // 70.9.2 + + it('70.9.3 dir: BIND_IN, val: null', function(done) { + + var rowid = 3; + var emptybuf; + + if ( node6plus ) + emptybuf = Buffer.alloc ( 0 ) ; + else + emptybuf = new Buffer ( 0 ) ; + + var bindVar = { + p_in: rowid, + p_str: { + dir: oracledb.BIND_IN, + type: oracledb.STRING, + val: null + }, + p_num: { + dir: oracledb.BIND_IN, + type: oracledb.NUMBER, + val: null + }, + p_dat: { + dir: oracledb.BIND_IN, + type: oracledb.DATE, + val: null + }, + p_buf: { + dir: oracledb.BIND_IN, + type: oracledb.BUFFER, + val: emptybuf, + maxSize: 32767 + } + }; + + async.series([ + function(cb) { + connection.execute( + sqlin, + bindVar, + function(err) { + should.not.exist(err); + cb(); + } + ); + }, + function(cb) { + connection.execute( + "select * from nodb_plsqlbindtab where id = :i", + [rowid], + { outFormat: oracledb.OBJECT }, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.rows[0].STR, null); + should.strictEqual(result.rows[0].NUM, null); + should.strictEqual(result.rows[0].DAT, null); + should.strictEqual(result.rows[0].BUF, null); + cb(); + } + ); + } + ], done); + + }); // 70.9.3 + + it('70.9.4 dir: BIND_INOUT, val: undefined', function(done) { + var rowid = 4; + var emptybuf; + + if ( node6plus ) + emptybuf = Buffer.alloc ( 0 ) ; + else + emptybuf = new Buffer ( 0 ) ; + + var bindVar = { + p_in: rowid, + p_inout1: { + dir: oracledb.BIND_INOUT, + type: oracledb.STRING, + val: undefined + }, + p_inout2: { + dir: oracledb.BIND_INOUT, + type: oracledb.NUMBER, + val: undefined + }, + p_inout3: { + dir: oracledb.BIND_INOUT, + type: oracledb.DATE, + val: undefined + }, + p_inout4: { + dir: oracledb.BIND_INOUT, + type: oracledb.BUFFER, + val: emptybuf, + maxSize: 32767 + } + }; + + async.series([ + function(cb) { + connection.execute( + sqlinout, + bindVar, + function(err, result) { + should.not.exist(err); + //console.log(result); + should.strictEqual(result.outBinds.p_inout1, null); + should.strictEqual(result.outBinds.p_inout2, null); + should.strictEqual(result.outBinds.p_inout3, null); + should.strictEqual(result.outBinds.p_inout4, null); + cb(); + } + ); + }, + function(cb) { + connection.execute( + "select * from nodb_plsqlbindtab where id = :i", + [rowid], + { outFormat: oracledb.OBJECT }, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.rows[0].STR, null); + should.strictEqual(result.rows[0].NUM, null); + should.strictEqual(result.rows[0].DAT, null); + should.strictEqual(result.rows[0].BUF, null); + cb(); + } + ); + } + ], done); + }); // 70.9.4 + + it('70.9.5 dir: BIND_IN, val: undefined', function(done) { + + var rowid = 5; + var emptybuf; + + if ( node6plus ) + emptybuf = Buffer.alloc ( 0 ) ; + else + emptybuf = new Buffer ( 0 ) ; + + var bindVar = { + p_in: rowid, + p_str: { + dir: oracledb.BIND_IN, + type: oracledb.STRING, + val: undefined + }, + p_num: { + dir: oracledb.BIND_IN, + type: oracledb.NUMBER, + val: undefined + }, + p_dat: { + dir: oracledb.BIND_IN, + type: oracledb.DATE, + val: undefined + }, + p_buf: { + dir: oracledb.BIND_IN, + type: oracledb.BUFFER, + val: emptybuf, + maxSize: 32767 + } + }; + + async.series([ + function(cb) { + connection.execute( + sqlin, + bindVar, + function(err) { + should.not.exist(err); + cb(); + } + ); + }, + function(cb) { + connection.execute( + "select * from nodb_plsqlbindtab where id = :i", + [rowid], + { outFormat: oracledb.OBJECT }, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.rows[0].STR, null); + should.strictEqual(result.rows[0].NUM, null); + should.strictEqual(result.rows[0].DAT, null); + should.strictEqual(result.rows[0].BUF, null); + cb(); + } + ); + } + ], done); + + }); // 70.9.5 + + }); // 70.9 + + describe('70.10 Check the bind-in values in PL/SQL', function() { + + it('70.10.1 STRING, basic', function(done) { + + async.series([ + function(cb) { + var proc = "CREATE OR REPLACE FUNCTION nodb_checkplsqlvalue1 (p_in IN OUT VARCHAR2) RETURN VARCHAR2 \n" + + "IS \n" + + " comparison VARCHAR2(20); \n" + + "BEGIN \n" + + " IF p_in = 'Shenzhen City' THEN \n" + + " comparison := 'the same'; \n" + + " ELSE \n" + + " comparison := 'different'; \n" + + " END IF; \n" + + " RETURN comparison; \n" + + "END;"; + + connection.execute( + proc, + function(err) { + should.not.exist(err); + cb(); + } + ); + }, + function theSame(cb) { + var bindVar = { + output: { type: oracledb.STRING, dir: oracledb.BIND_OUT }, + p_in: {type: oracledb.STRING, dir: oracledb.BIND_INOUT, val: 'Shenzhen City'} + }; + connection.execute( + "begin :output := nodb_checkplsqlvalue1 (:p_in); end;", + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.outBinds.output, 'the same'); + should.strictEqual(result.outBinds.p_in, 'Shenzhen City'); + cb(); + } + ); + }, + function diff(cb) { + var bindVar = { + output: { type: oracledb.STRING, dir: oracledb.BIND_OUT }, + p_in: {type: oracledb.STRING, dir: oracledb.BIND_INOUT, val: 'Shenzhen city'} + }; + connection.execute( + "begin :output := nodb_checkplsqlvalue1 (:p_in); end;", + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.outBinds.output, 'different'); + should.strictEqual(result.outBinds.p_in, 'Shenzhen city'); + cb(); + } + ); + }, + function(cb) { + connection.execute( + "drop function nodb_checkplsqlvalue1", + function(err) { + should.not.exist(err); + cb(); + } + ); + } + ], done); + + }); // 70.10.1 + + it('70.10.2 STRING, null, empty string, undefined', function(done) { + async.series([ + function(cb) { + var proc = "CREATE OR REPLACE FUNCTION nodb_checkplsqlvalue2 (p_in IN OUT VARCHAR2) RETURN VARCHAR2 \n" + + "IS \n" + + " comparison VARCHAR2(20); \n" + + "BEGIN \n" + + " IF p_in IS NULL THEN \n" + + " comparison := 'correct'; \n" + + " ELSE \n" + + " comparison := 'wrong'; \n" + + " END IF; \n" + + " RETURN comparison; \n" + + "END;"; + + connection.execute( + proc, + function(err) { + should.not.exist(err); + cb(); + } + ); + }, + function correct(cb) { + var bindVar = { + output: { type: oracledb.STRING, dir: oracledb.BIND_OUT }, + p_in: {type: oracledb.STRING, dir: oracledb.BIND_INOUT, val: null} + }; + connection.execute( + "begin :output := nodb_checkplsqlvalue2 (:p_in); end;", + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.outBinds.output, 'correct'); + should.strictEqual(result.outBinds.p_in, null); + cb(); + } + ); + }, + function correct(cb) { + var bindVar = { + output: { type: oracledb.STRING, dir: oracledb.BIND_OUT }, + p_in: {type: oracledb.STRING, dir: oracledb.BIND_INOUT, val: ''} + }; + connection.execute( + "begin :output := nodb_checkplsqlvalue2 (:p_in); end;", + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.outBinds.output, 'correct'); + should.strictEqual(result.outBinds.p_in, null); + cb(); + } + ); + }, + function correct(cb) { + var bindVar = { + output: { type: oracledb.STRING, dir: oracledb.BIND_OUT }, + p_in: {type: oracledb.STRING, dir: oracledb.BIND_INOUT, val: undefined} + }; + connection.execute( + "begin :output := nodb_checkplsqlvalue2 (:p_in); end;", + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.outBinds.output, 'correct'); + should.strictEqual(result.outBinds.p_in, null); + cb(); + } + ); + }, + function wrong(cb) { + var bindVar = { + output: { type: oracledb.STRING, dir: oracledb.BIND_OUT }, + p_in: {type: oracledb.STRING, dir: oracledb.BIND_INOUT, val: 'foobar'} + }; + connection.execute( + "begin :output := nodb_checkplsqlvalue2 (:p_in); end;", + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.outBinds.output, 'wrong'); + should.strictEqual(result.outBinds.p_in, 'foobar'); + cb(); + } + ); + }, + function(cb) { + connection.execute( + "drop function nodb_checkplsqlvalue2", + function(err) { + should.not.exist(err); + cb(); + } + ); + } + ], done); + }); // 70.10.2 + + it('70.10.3 NUMBER, null values', function(done) { + + async.series([ + function(cb) { + var proc = "CREATE OR REPLACE FUNCTION nodb_checkplsqlvalue3 (p_in IN OUT NUMBER) RETURN VARCHAR2 \n" + + "IS \n" + + " comparison VARCHAR2(20); \n" + + "BEGIN \n" + + " IF p_in IS NULL THEN \n" + + " comparison := 'correct'; \n" + + " ELSE \n" + + " comparison := 'wrong'; \n" + + " END IF; \n" + + " RETURN comparison; \n" + + "END;"; + + connection.execute( + proc, + function(err) { + should.not.exist(err); + cb(); + } + ); + }, + function correct(cb) { + var bindVar = { + output: { type: oracledb.STRING, dir: oracledb.BIND_OUT }, + p_in: {type: oracledb.NUMBER, dir: oracledb.BIND_INOUT, val: null} + }; + connection.execute( + "begin :output := nodb_checkplsqlvalue3 (:p_in); end;", + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.outBinds.output, 'correct'); + should.strictEqual(result.outBinds.p_in, null); + cb(); + } + ); + }, + function correct(cb) { + var bindVar = { + output: { type: oracledb.STRING, dir: oracledb.BIND_OUT }, + p_in: {type: oracledb.NUMBER, dir: oracledb.BIND_INOUT, val: undefined} + }; + connection.execute( + "begin :output := nodb_checkplsqlvalue3 (:p_in); end;", + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.outBinds.output, 'correct'); + should.strictEqual(result.outBinds.p_in, null); + cb(); + } + ); + }, + function wrong(cb) { + var bindVar = { + output: { type: oracledb.STRING, dir: oracledb.BIND_OUT }, + p_in: {type: oracledb.NUMBER, dir: oracledb.BIND_INOUT, val: 0} + }; + connection.execute( + "begin :output := nodb_checkplsqlvalue3 (:p_in); end;", + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.outBinds.output, 'wrong'); + should.strictEqual(result.outBinds.p_in, 0); + cb(); + } + ); + }, + function(cb) { + connection.execute( + "drop function nodb_checkplsqlvalue3", + function(err) { + should.not.exist(err); + cb(); + } + ); + } + ], done); + + }); // 70.10.3 + + it('70.10.4 DATE, null values', function(done) { + + async.series([ + function(cb) { + var proc = "CREATE OR REPLACE FUNCTION nodb_checkplsqlvalue4 (p_in IN OUT DATE) RETURN VARCHAR2 \n" + + "IS \n" + + " comparison VARCHAR2(20); \n" + + "BEGIN \n" + + " IF p_in IS NULL THEN \n" + + " comparison := 'correct'; \n" + + " ELSE \n" + + " comparison := 'wrong'; \n" + + " END IF; \n" + + " RETURN comparison; \n" + + "END;"; + + connection.execute( + proc, + function(err) { + should.not.exist(err); + cb(); + } + ); + }, + function correct(cb) { + var bindVar = { + output: { type: oracledb.STRING, dir: oracledb.BIND_OUT }, + p_in: {type: oracledb.DATE, dir: oracledb.BIND_INOUT, val: null} + }; + connection.execute( + "begin :output := nodb_checkplsqlvalue4 (:p_in); end;", + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.outBinds.output, 'correct'); + should.strictEqual(result.outBinds.p_in, null); + cb(); + } + ); + }, + function diff(cb) { + var today = new Date(); + var bindVar = { + output: { type: oracledb.STRING, dir: oracledb.BIND_OUT }, + p_in: { type: oracledb.DATE, dir: oracledb.BIND_INOUT, val: today } + }; + connection.execute( + "begin :output := nodb_checkplsqlvalue4 (:p_in); end;", + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.outBinds.output, 'wrong'); + cb(); + } + ); + }, + function correct(cb) { + var bindVar = { + output: { type: oracledb.STRING, dir: oracledb.BIND_OUT }, + p_in: {type: oracledb.DATE, dir: oracledb.BIND_INOUT, val: undefined} + }; + connection.execute( + "begin :output := nodb_checkplsqlvalue4 (:p_in); end;", + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.outBinds.output, 'correct'); + should.strictEqual(result.outBinds.p_in, null); + cb(); + } + ); + }, + function(cb) { + connection.execute( + "drop function nodb_checkplsqlvalue4", + function(err) { + should.not.exist(err); + cb(); + } + ); + } + ], done); + + }); // 70.10.4 + + it('70.10.5 BUFFER', function(done) { + async.series([ + function(cb) { + var proc = "CREATE OR REPLACE FUNCTION nodb_checkplsqlvalue5 (p_in IN OUT RAW) RETURN VARCHAR2 \n" + + "IS \n" + + " comparison VARCHAR2(20); \n" + + "BEGIN \n" + + " IF p_in IS NULL THEN \n" + + " comparison := 'correct'; \n" + + " ELSE \n" + + " comparison := 'wrong'; \n" + + " END IF; \n" + + " RETURN comparison; \n" + + "END;"; + + connection.execute( + proc, + function(err) { + should.not.exist(err); + cb(); + } + ); + }, + function correct(cb) { + var bindVar = { + output: { type: oracledb.STRING, dir: oracledb.BIND_OUT }, + p_in: {type: oracledb.BUFFER, dir: oracledb.BIND_INOUT, val: null} + }; + connection.execute( + "begin :output := nodb_checkplsqlvalue5 (:p_in); end;", + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.outBinds.output, 'correct'); + should.strictEqual(result.outBinds.p_in, null); + cb(); + } + ); + }, + function correct(cb) { + var bindVar = { + output: { type: oracledb.STRING, dir: oracledb.BIND_OUT }, + p_in: {type: oracledb.BUFFER, dir: oracledb.BIND_INOUT, val: new Buffer('')} + }; + connection.execute( + "begin :output := nodb_checkplsqlvalue5 (:p_in); end;", + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.outBinds.output, 'correct'); + should.strictEqual(result.outBinds.p_in, null); + cb(); + } + ); + }, + function correct(cb) { + var bindVar = { + output: { type: oracledb.STRING, dir: oracledb.BIND_OUT }, + p_in: {type: oracledb.BUFFER, dir: oracledb.BIND_INOUT, val: undefined} + }; + connection.execute( + "begin :output := nodb_checkplsqlvalue5 (:p_in); end;", + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.outBinds.output, 'correct'); + should.strictEqual(result.outBinds.p_in, null); + cb(); + } + ); + }, + function wrong(cb) { + + var bufsize = 21; + var bufValue = assist.createBuffer(bufsize); + var bindVar = { + output: { type: oracledb.STRING, dir: oracledb.BIND_OUT }, + p_in: {type: oracledb.BUFFER, dir: oracledb.BIND_INOUT, val: bufValue} + }; + connection.execute( + "begin :output := nodb_checkplsqlvalue5 (:p_in); end;", + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.outBinds.output, 'wrong'); + (result.outBinds.p_in).should.eql(bufValue); + cb(); + } + ); + }, + function(cb) { + connection.execute( + "drop function nodb_checkplsqlvalue5", + function(err) { + should.not.exist(err); + cb(); + } + ); + } + ], done); + }); // 70.10.5 + + it('70.10.6 TIMESTAMP, null values', function(done) { + + async.series([ + function(cb) { + var proc = "CREATE OR REPLACE FUNCTION nodb_checkplsqlvalue6 (p_in IN OUT TIMESTAMP) RETURN VARCHAR2 \n" + + "IS \n" + + " comparison VARCHAR2(20); \n" + + "BEGIN \n" + + " IF p_in IS NULL THEN \n" + + " comparison := 'correct'; \n" + + " ELSE \n" + + " comparison := 'wrong'; \n" + + " END IF; \n" + + " RETURN comparison; \n" + + "END;"; + + connection.execute( + proc, + function(err) { + should.not.exist(err); + cb(); + } + ); + }, + function correct(cb) { + var bindVar = { + output: { type: oracledb.STRING, dir: oracledb.BIND_OUT }, + p_in: {type: oracledb.DATE, dir: oracledb.BIND_INOUT, val: null} + }; + connection.execute( + "begin :output := nodb_checkplsqlvalue6 (:p_in); end;", + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.outBinds.output, 'correct'); + should.strictEqual(result.outBinds.p_in, null); + cb(); + } + ); + }, + function diff(cb) { + var today = new Date(); + var bindVar = { + output: { type: oracledb.STRING, dir: oracledb.BIND_OUT }, + p_in: { type: oracledb.DATE, dir: oracledb.BIND_INOUT, val: today } + }; + connection.execute( + "begin :output := nodb_checkplsqlvalue6 (:p_in); end;", + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.outBinds.output, 'wrong'); + cb(); + } + ); + }, + function correct(cb) { + var bindVar = { + output: { type: oracledb.STRING, dir: oracledb.BIND_OUT }, + p_in: {type: oracledb.DATE, dir: oracledb.BIND_INOUT, val: undefined} + }; + connection.execute( + "begin :output := nodb_checkplsqlvalue6 (:p_in); end;", + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.outBinds.output, 'correct'); + should.strictEqual(result.outBinds.p_in, null); + cb(); + } + ); + }, + function(cb) { + connection.execute( + "drop function nodb_checkplsqlvalue6", + function(err) { + should.not.exist(err); + cb(); + } + ); + } + ], done); + + }); // 70.10.6 + + it('70.10.7 TIMESTAMP WITH TIME ZONE, null values', function(done) { + + async.series([ + function(cb) { + var proc = "CREATE OR REPLACE FUNCTION nodb_checkplsqlvalue7 (p_in IN OUT TIMESTAMP WITH TIME ZONE) RETURN VARCHAR2 \n" + + "IS \n" + + " comparison VARCHAR2(20); \n" + + "BEGIN \n" + + " IF p_in IS NULL THEN \n" + + " comparison := 'correct'; \n" + + " ELSE \n" + + " comparison := 'wrong'; \n" + + " END IF; \n" + + " RETURN comparison; \n" + + "END;"; + + connection.execute( + proc, + function(err) { + should.not.exist(err); + cb(); + } + ); + }, + function correct(cb) { + var bindVar = { + output: { type: oracledb.STRING, dir: oracledb.BIND_OUT }, + p_in: {type: oracledb.DATE, dir: oracledb.BIND_INOUT, val: null} + }; + connection.execute( + "begin :output := nodb_checkplsqlvalue7 (:p_in); end;", + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.outBinds.output, 'correct'); + should.strictEqual(result.outBinds.p_in, null); + cb(); + } + ); + }, + function diff(cb) { + var today = new Date(); + var bindVar = { + output: { type: oracledb.STRING, dir: oracledb.BIND_OUT }, + p_in: { type: oracledb.DATE, dir: oracledb.BIND_INOUT, val: today } + }; + connection.execute( + "begin :output := nodb_checkplsqlvalue7 (:p_in); end;", + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.outBinds.output, 'wrong'); + cb(); + } + ); + }, + function correct(cb) { + var bindVar = { + output: { type: oracledb.STRING, dir: oracledb.BIND_OUT }, + p_in: {type: oracledb.DATE, dir: oracledb.BIND_INOUT, val: undefined} + }; + connection.execute( + "begin :output := nodb_checkplsqlvalue7 (:p_in); end;", + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.outBinds.output, 'correct'); + should.strictEqual(result.outBinds.p_in, null); + cb(); + } + ); + }, + function(cb) { + connection.execute( + "drop function nodb_checkplsqlvalue7", + function(err) { + should.not.exist(err); + cb(); + } + ); + } + ], done); + + }); // 70.10.7 + + it('70.10.8 TIMESTAMP WITH LOCAL TIME ZONE, null values', function(done) { + + async.series([ + function(cb) { + var proc = "CREATE OR REPLACE FUNCTION nodb_checkplsqlvalue8 (p_in IN OUT TIMESTAMP WITH LOCAL TIME ZONE) RETURN VARCHAR2 \n" + + "IS \n" + + " comparison VARCHAR2(20); \n" + + "BEGIN \n" + + " IF p_in IS NULL THEN \n" + + " comparison := 'correct'; \n" + + " ELSE \n" + + " comparison := 'wrong'; \n" + + " END IF; \n" + + " RETURN comparison; \n" + + "END;"; + + connection.execute( + proc, + function(err) { + should.not.exist(err); + cb(); + } + ); + }, + function correct(cb) { + var bindVar = { + output: { type: oracledb.STRING, dir: oracledb.BIND_OUT }, + p_in: {type: oracledb.DATE, dir: oracledb.BIND_INOUT, val: null} + }; + connection.execute( + "begin :output := nodb_checkplsqlvalue8 (:p_in); end;", + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.outBinds.output, 'correct'); + should.strictEqual(result.outBinds.p_in, null); + cb(); + } + ); + }, + function diff(cb) { + var today = new Date(); + var bindVar = { + output: { type: oracledb.STRING, dir: oracledb.BIND_OUT }, + p_in: { type: oracledb.DATE, dir: oracledb.BIND_INOUT, val: today } + }; + connection.execute( + "begin :output := nodb_checkplsqlvalue8 (:p_in); end;", + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.outBinds.output, 'wrong'); + cb(); + } + ); + }, + function correct(cb) { + var bindVar = { + output: { type: oracledb.STRING, dir: oracledb.BIND_OUT }, + p_in: {type: oracledb.DATE, dir: oracledb.BIND_INOUT, val: undefined} + }; + connection.execute( + "begin :output := nodb_checkplsqlvalue8 (:p_in); end;", + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.outBinds.output, 'correct'); + should.strictEqual(result.outBinds.p_in, null); + cb(); + } + ); + }, + function(cb) { + connection.execute( + "drop function nodb_checkplsqlvalue8", + function(err) { + should.not.exist(err); + cb(); + } + ); + } + ], done); + + }); // 70.10.8 + + }); // 70.10 + + describe('70.11 dir: BIND_IN and BIND_OUT, type: TIMESTAMP(convert STRING to TIMESTAMP)', function() { + + before(function(done) { + var proc = "CREATE OR REPLACE \n" + + "FUNCTION nodb_plsqlbindfunc711(dateValue IN TIMESTAMP) RETURN VARCHAR2 \n" + + "IS \n" + + "BEGIN \n" + + " RETURN TO_CHAR(dateValue,'YYYY-MM-DD HH24:MI:SS.FF');\n" + + "END nodb_plsqlbindfunc711;"; + + connection.execute( + proc, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // before + + after(function(done) { + var sql = "DROP FUNCTION nodb_plsqlbindfunc711"; + connection.execute( + sql, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // after + + var sqlrun_str = "BEGIN :output := nodb_plsqlbindfunc711(TO_TIMESTAMP(:dateValue, 'YYYY-MM-DD HH24:MI:SS.FF')); END;"; + var resultBind = {type: oracledb.STRING, dir: oracledb.BIND_OUT}; + + it('70.11.1 basic case', function(done) { + var date = '1999-12-01 11:00:00.001231000'; + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.STRING, dir: oracledb.BIND_IN, val: date} + }; + + connection.execute( + sqlrun_str, + bindVar, + function(err, result) { + should.not.exist(err); + //TIMESTAMP [(fractional_seconds)]: Accepted fractional_seconds_precision values are 0 to 9. The default is 6 + should.strictEqual(result.outBinds.output, date); + done(); + } + ); + }); // 70.11.1 + + it('70.11.2 val: null', function(done) { + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.STRING, dir: oracledb.BIND_IN, val: null} + }; + + connection.execute( + sqlrun_str, + bindVar, + function(err, result) { + should.not.exist(err); + should.strictEqual(result.outBinds.output, null); + done(); + } + ); + }); // 70.11.2 + + it('70.11.3 val: empty string', function(done) { + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.STRING, dir: oracledb.BIND_IN, val: ''} + }; + + connection.execute( + sqlrun_str, + bindVar, + function(err, result) { + should.not.exist(err); + should.strictEqual(result.outBinds.output, null); + done(); + } + ); + }); // 70.11.3 + + it('70.11.4 val: undefined', function(done) { + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.STRING, dir: oracledb.BIND_IN, val: undefined} + }; + + connection.execute( + sqlrun_str, + bindVar, + function(err, result) { + should.not.exist(err); + should.strictEqual(result.outBinds.output, null); + done(); + } + ); + }); // 70.11.4 + + it('70.11.5 val: NaN', function(done) { + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.STRING, dir: oracledb.BIND_IN, val: NaN} + }; + + connection.execute( + sqlrun_str, + bindVar, + function(err) { + should.exist(err); + //NJS-011: encountered bind value and type mismatch in parameter 2 + (err.message).should.startWith('NJS-011:'); + done(); + } + ); + }); // 70.11.5 + + it('70.11.7 val: invalid Date Value: Feb 30, 2016', function(done) { + var date = '2016-02-30 00:00:00.000000000'; + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.STRING, dir: oracledb.BIND_IN, val: date} + }; + + connection.execute( + sqlrun_str, + bindVar, + function(err) { + should.exist(err); + //ORA-01839: date not valid for month specified + (err.message).should.startWith("ORA-01839:"); + done(); + } + ); + }); // 70.11.7 + + it('70.11.8 val: 1969-12-31', function(done) { + var date = '1969-12-31 00:00:00.000000000'; + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.STRING, dir: oracledb.BIND_IN, val: date} + }; + + connection.execute( + sqlrun_str, + bindVar, + function(err, result) { + should.not.exist(err); + (result.outBinds.output).should.eql(date); + done(); + } + ); + }); // 70.11.8 + + it('70.11.9 val: epoch date 1970-1-1', function(done) { + var date = '1970-01-01 00:00:00.000000000'; + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.STRING, dir: oracledb.BIND_IN, val: date} + }; + + connection.execute( + sqlrun_str, + bindVar, + function(err, result) { + should.not.exist(err); + (result.outBinds.output).should.eql(date); + done(); + } + ); + }); // 70.11.9 + + });//70.11 + + describe('70.12 dir: BIND_IN and BIND_OUT, type: TIMESTAMP(WITH VARCHAR2 RETURN)', function() { + + before(function(done) { + var proc = "CREATE OR REPLACE \n" + + "FUNCTION nodb_plsqlbindfunc712(dateValue IN TIMESTAMP) RETURN VARCHAR2 \n" + + "IS \n" + + "BEGIN \n" + + " RETURN TO_CHAR(dateValue,'YYYY-MM-DD HH24:MI:SS.FF');\n" + + "END nodb_plsqlbindfunc712;"; + + connection.execute( + proc, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // before + + after(function(done) { + var sql = "DROP FUNCTION nodb_plsqlbindfunc712"; + connection.execute( + sql, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // after + + var sqlrun_dt = "BEGIN :output := nodb_plsqlbindfunc712(:dateValue); END;"; + var resultBind = {type: oracledb.STRING, dir: oracledb.BIND_OUT}; + + it('70.12.1 basic case', function(done) { + var date = new Date( "2016-09-10T14:10:10.123Z" ); + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.DATE, dir: oracledb.BIND_IN, val: date} + }; + + connection.execute( + sqlrun_dt, + bindVar, + function(err, result) { + should.not.exist(err); + var expectDate = "2016-09-10 14:10:10.123000000"; + (result.outBinds.output).should.eql(expectDate); + done(); + } + ); + }); // 70.12.1 + + it('70.12.2 val: null', function(done) { + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.DATE, dir: oracledb.BIND_IN, val: null} + }; + + connection.execute( + sqlrun_dt, + bindVar, + function(err, result) { + should.not.exist(err); + should.strictEqual(result.outBinds.output, null); + done(); + } + ); + }); // 70.12.2 + + it('70.12.3 val: empty string', function(done) { + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.DATE, dir: oracledb.BIND_IN, val: ''} + }; + + connection.execute( + sqlrun_dt, + bindVar, + function(err) { + should.exist(err); + (err.message).should.startWith('NJS-011:'); + done(); + } + ); + }); // 70.12.3 + + it('70.12.4 val: undefined', function(done) { + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.DATE, dir: oracledb.BIND_IN, val: undefined} + }; + + connection.execute( + sqlrun_dt, + bindVar, + function(err, result) { + should.not.exist(err); + should.strictEqual(result.outBinds.output, null); + done(); + } + ); + }); // 70.12.4 + + it('70.12.5 val: NaN', function(done) { + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.DATE, dir: oracledb.BIND_IN, val: NaN} + }; + + connection.execute( + sqlrun_dt, + bindVar, + function(err) { + should.exist(err); + //NJS-011: encountered bind value and type mismatch in parameter 2 + (err.message).should.startWith('NJS-011:'); + done(); + } + ); + }); // 70.12.5 + + it('70.12.7 val: invalid Date Value: Feb 30, 2016', function(done) { + var date = new Date( Date.UTC( 2016, 1, 30, 0, 0, 0, 0 ) ); + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.DATE, dir: oracledb.BIND_IN, val: date} + }; + + connection.execute( + sqlrun_dt, + bindVar, + function(err, result) { + should.not.exist(err); + var resultDate = "2016-03-01 00:00:00.000000000"; + (result.outBinds.output).should.eql(resultDate); + done(); + } + ); + }); // 70.12.7 + + it('70.12.8 val: 1969-12-31', function(done) { + var date = new Date( Date.UTC( 1969, 11, 31, 0, 0, 0, 0 ) ); + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.DATE, dir: oracledb.BIND_IN, val: date} + }; + + connection.execute( + sqlrun_dt, + bindVar, + function(err, result) { + should.not.exist(err); + var resultDate = "1969-12-31 00:00:00.000000000"; + (result.outBinds.output).should.eql(resultDate); + done(); + } + ); + }); // 70.12.8 + + it('70.12.9 val: epoch date 1970-1-1', function(done) { + var date = new Date( Date.UTC( 1970, 0, 1, 0, 0, 0, 0 ) ); + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.DATE, dir: oracledb.BIND_IN, val: date} + }; + + connection.execute( + sqlrun_dt, + bindVar, + function(err, result) { + should.not.exist(err); + var resultDate = "1970-01-01 00:00:00.000000000"; + (result.outBinds.output).should.eql(resultDate); + done(); + } + ); + }); // 70.12.9 + + it('70.12.10 val: create Date value using numeric value: new Date(number)', function(done) { + var date = new Date ( 1476780296673 ); //Integer value representing the number of milliseconds since 1 January 1970 00:00:00 UTC + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.DATE, dir: oracledb.BIND_IN, val: date} + }; + + connection.execute( + sqlrun_dt, + bindVar, + function(err, result) { + should.not.exist(err); + var resultDate = "2016-10-18 08:44:56.673000000"; + (result.outBinds.output).should.eql(resultDate); + done(); + } + ); + }); // 70.12.10 + + it('70.12.11 val: create Date value using numeric value: 0', function(done) { + //Zero time is 01 January 1970 00:00:00 UTC + var date = new Date ( 0 ); + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.DATE, dir: oracledb.BIND_IN, val: date} + }; + + connection.execute( + sqlrun_dt, + bindVar, + function(err, result) { + should.not.exist(err); + var resultDate = "1970-01-01 00:00:00.000000000"; + (result.outBinds.output).should.eql(resultDate); + done(); + } + ); + }); // 70.12.11 + + });//70.12 + + describe('70.13 dir: BIND_IN and BIND_OUT, type: TIMESTAMP', function() { + + before(function(done) { + var proc = "CREATE OR REPLACE \n" + + "FUNCTION nodb_plsqlbindfunc713(dateValue IN TIMESTAMP) RETURN TIMESTAMP \n" + + "IS \n" + + "BEGIN \n" + + " RETURN dateValue;\n" + + "END nodb_plsqlbindfunc713;"; + + connection.execute( + proc, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // before + + after(function(done) { + var sql = "DROP FUNCTION nodb_plsqlbindfunc713"; + connection.execute( + sql, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // after + + var sqlrun = "BEGIN :output := nodb_plsqlbindfunc713(:dateValue); END;"; + var resultBind = {type: oracledb.DATE, dir: oracledb.BIND_OUT}; + + it('70.13.1 val: empty string', function(done) { + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.DATE, dir: oracledb.BIND_IN, val: ''} + }; + + connection.execute( + sqlrun, + bindVar, + function(err) { + should.exist(err); + (err.message).should.startWith('NJS-011:'); + done(); + } + ); + }); // 70.13.1 + + it('70.13.2 val: undefined', function(done) { + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.DATE, dir: oracledb.BIND_IN, val: undefined} + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + should.strictEqual(result.outBinds.output, null); + done(); + } + ); + }); // 70.13.2 + + it('70.13.3 val: NaN', function(done) { + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.DATE, dir: oracledb.BIND_IN, val: NaN} + }; + + connection.execute( + sqlrun, + bindVar, + function(err) { + should.exist(err); + //NJS-011: encountered bind value and type mismatch in parameter 2 + (err.message).should.startWith('NJS-011:'); + done(); + } + ); + }); // 70.13.3 + + });//70.13 + + describe('70.14 dir: BIND_INOUT, type:TIMESTAMP', function(){ + before(function(done){ + var proc = "CREATE OR REPLACE PROCEDURE nodb_inoutproc714 (p_inout IN OUT TIMESTAMP) \n" + + "AS \n" + + "BEGIN \n" + + " p_inout := p_inout; \n" + + "END nodb_inoutproc714;"; + + connection.execute( + proc, + function(err) { + should.not.exist(err); + done(); + } + ); + });//before + + after(function(done){ + var sql = "DROP PROCEDURE nodb_inoutproc714"; + connection.execute( + sql, + function(err) { + should.not.exist(err); + done(); + } + ); + });//after + + var sqlrun = "begin nodb_inoutproc714(p_inout => :p_inout); end;"; + + it('70.14.1 basic case', function(done){ + var date = new Date( 2016, 7, 5, 12, 13, 14, 123 ); + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + type: oracledb.DATE, + val: date + } + }; + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + (result.outBinds.p_inout).should.eql(date); + done(); + } + ); + });//70.14.1 + + it('70.14.2 auto detect data type', function(done) { + var date = new Date( 2016, 7, 5, 12, 13, 14, 123 ); + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + val: date + } + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + (result.outBinds.p_inout).should.eql(date); + done(); + } + ); + }); // 70.14.2 + + it('70.14.3 val: null', function(done) { + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + type: oracledb.DATE, + val: null + } + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + should.strictEqual(result.outBinds.p_inout, null); + done(); + } + ); + }); // 70.14.3 + + it('70.14.4 val: empty string', function(done) { + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + type: oracledb.DATE, + val: '' + } + }; + + connection.execute( + sqlrun, + bindVar, + function(err) { + should.exist(err); + (err.message).should.startWith('NJS-011:'); + done(); + } + ); + }); // 70.14.4 + + it('70.14.5 val: undefined', function(done) { + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + type: oracledb.DATE, + val: undefined + } + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.outBinds.p_inout, null); + done(); + } + ); + }); // 70.14.5 + + it('70.14.6 val: NaN', function(done) { + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + type: oracledb.DATE, + val: NaN + } + }; + + connection.execute( + sqlrun, + bindVar, + function(err) { + should.exist(err); + (err.message).should.startWith('NJS-011:'); + done(); + } + ); + }); // 70.14.6 + + it('70.14.7 val: invalid Date Value: Feb 30, 2016', function(done) { + var date = new Date ( 2016, 1, 30, 0, 0, 0, 0 ); + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + type: oracledb.DATE, + val: date + } + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + //console.log(result); + var resultDate = new Date ( 2016, 2, 1, 0, 0, 0, 0 ); + (result.outBinds.p_inout).should.eql(resultDate); + done(); + } + ); + }); // 70.14.7 + + it('70.14.8 val: 1969-12-31', function(done) { + var date = new Date ( 1969, 11, 31, 0, 0, 0, 0 ); + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + type: oracledb.DATE, + val: date + } + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + (result.outBinds.p_inout).should.eql(date); + done(); + } + ); + }); // 70.14.8 + + it('70.14.9 val: epoch date 1970-1-1', function(done) { + var date = new Date ( 1970, 0, 1, 0, 0, 0, 0 ); + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + type: oracledb.DATE, + val: date + } + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + (result.outBinds.p_inout).should.eql(date); + done(); + } + ); + }); // 70.14.9 + + it('70.14.10 NULL IN and NON-NULL out', function(done) { + var proc71410 = "CREATE OR REPLACE PROCEDURE nodb_inoutproc71410 (p_inout IN OUT TIMESTAMP) \n" + + "AS \n" + + "BEGIN \n" + + " p_inout := TO_TIMESTAMP('1999-12-01 11:00:00.001231000', 'YYYY-MM-DD HH24:MI:SS.FF'); \n" + + "END nodb_inoutproc71410;"; + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + type: oracledb.DATE, + val: null + } + }; + var sqlrun71410 = "begin nodb_inoutproc71410(p_inout => :p_inout); end;"; + var sqldrop = "DROP PROCEDURE nodb_inoutproc71410"; + async.series([ + function(cb) { + connection.execute( + proc71410, + function(err) { + should.not.exist(err); + cb(); + } + ); + }, + function(cb) { + connection.execute( + sqlrun71410, + bindVar, + function(err, result) { + should.not.exist(err); + (result.outBinds.p_inout).should.not.eql(null); + cb(); + } + ); + }, + function(cb) { + connection.execute( + sqldrop, + function(err) { + should.not.exist(err); + cb(); + } + ); + } + ], done); + }); // 70.14.10 + + it('70.14.11 NON-NULL IN and NULL OUT', function(done) { + var proc71411 = "CREATE OR REPLACE PROCEDURE nodb_inoutproc71411 (p_inout IN OUT TIMESTAMP) \n" + + "AS \n" + + "BEGIN \n" + + " p_inout := null; \n" + + "END nodb_inoutproc71411;"; + var date = new Date( 2011, 0, 12, 0, 0, 0, 0 ); + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + type: oracledb.DATE, + val: date + } + }; + var sqlrun71411 = "begin nodb_inoutproc71411(p_inout => :p_inout); end;"; + var sqldrop = "DROP PROCEDURE nodb_inoutproc71411"; + async.series([ + function(cb) { + connection.execute( + proc71411, + function(err) { + should.not.exist(err); + cb(); + } + ); + }, + function(cb) { + connection.execute( + sqlrun71411, + bindVar, + function(err, result) { + should.not.exist(err); + should.strictEqual(result.outBinds.p_inout, null); + cb(); + } + ); + }, + function(cb) { + connection.execute( + sqldrop, + function(err) { + should.not.exist(err); + cb(); + } + ); + } + ], done); + }); // 70.14.11 + + });//70.14 + + describe('70.15 dir: BIND_IN and BIND_OUT, type: TIMESTAMP WITH TIME ZONE(convert STRING to TIMESTAMP)', function() { + + before(function(done) { + var proc = "CREATE OR REPLACE \n" + + "FUNCTION nodb_plsqlbindfunc715(dateValue IN TIMESTAMP WITH TIME ZONE) RETURN VARCHAR2 \n" + + "IS \n" + + "BEGIN \n" + + " RETURN TO_CHAR(dateValue, 'YYYY-MM-DD HH24:MI:SS.FF TZH:TZM');\n" + + "END nodb_plsqlbindfunc715;"; + + connection.execute( + proc, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // before + + after(function(done) { + var sql = "DROP FUNCTION nodb_plsqlbindfunc715"; + connection.execute( + sql, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // after + + var sqlrun_str = "BEGIN :output := nodb_plsqlbindfunc715(TO_TIMESTAMP_TZ(:dateValue, 'YYYY-MM-DD HH24:MI:SS.FF TZH:TZM')); END;"; + var resultBind = {type: oracledb.STRING, dir: oracledb.BIND_OUT}; + + it('70.15.1 basic case', function(done) { + var date = '1999-12-01 11:00:00.123450000 -08:00'; + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.STRING, dir: oracledb.BIND_IN, val: date} + }; + + connection.execute( + sqlrun_str, + bindVar, + function(err, result) { + should.not.exist(err); + (result.outBinds.output).should.eql(date); + done(); + } + ); + }); // 70.15.1 + + it('70.15.2 val: null', function(done) { + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.STRING, dir: oracledb.BIND_IN, val: null} + }; + + connection.execute( + sqlrun_str, + bindVar, + function(err, result) { + should.not.exist(err); + should.strictEqual(result.outBinds.output, null); + done(); + } + ); + }); // 70.15.2 + + it('70.15.3 val: empty string', function(done) { + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.STRING, dir: oracledb.BIND_IN, val: ''} + }; + + connection.execute( + sqlrun_str, + bindVar, + function(err, result) { + should.not.exist(err); + should.strictEqual(result.outBinds.output, null); + done(); + } + ); + }); // 70.15.3 + + it('70.15.4 val: undefined', function(done) { + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.STRING, dir: oracledb.BIND_IN, val: undefined} + }; + + connection.execute( + sqlrun_str, + bindVar, + function(err, result) { + should.not.exist(err); + should.strictEqual(result.outBinds.output, null); + done(); + } + ); + }); // 70.15.4 + + it('70.15.5 val: NaN', function(done) { + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.STRING, dir: oracledb.BIND_IN, val: NaN} + }; + + connection.execute( + sqlrun_str, + bindVar, + function(err) { + should.exist(err); + //NJS-011: encountered bind value and type mismatch in parameter 2 + (err.message).should.startWith('NJS-011:'); + done(); + } + ); + }); // 70.15.5 + + it('70.15.7 val: invalid Date Value: Feb 30, 2016', function(done) { + var date = '2016-02-30 00:00:00.000000000 -08:00'; + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.STRING, dir: oracledb.BIND_IN, val: date} + }; + + connection.execute( + sqlrun_str, + bindVar, + function(err) { + should.exist(err); + //ORA-01839: date not valid for month specified + (err.message).should.startWith("ORA-01839:"); + done(); + } + ); + }); // 70.15.7 + + it('70.15.8 val: 1969-12-31', function(done) { + var date = '1969-12-31 00:00:00.000000000 -08:00'; + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.STRING, dir: oracledb.BIND_IN, val: date} + }; + + connection.execute( + sqlrun_str, + bindVar, + function(err, result) { + should.not.exist(err); + (result.outBinds.output).should.eql(date); + done(); + } + ); + }); // 70.15.8 + + it('70.15.9 val: epoch date 1970-1-1', function(done) { + var date = '1970-01-01 00:00:00.000000000 -08:00'; + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.STRING, dir: oracledb.BIND_IN, val: date} + }; + + connection.execute( + sqlrun_str, + bindVar, + function(err, result) { + should.not.exist(err); + (result.outBinds.output).should.eql(date); + done(); + } + ); + }); // 70.15.9 + + });//70.15 + + describe('70.16 dir: BIND_IN and BIND_OUT, type: TIMESTAMP WITH TIME ZONE(WITH VARCHAR2 RETURN)', function() { + + before(function(done) { + var proc = "CREATE OR REPLACE \n" + + "FUNCTION nodb_plsqlbindfunc716(dateValue IN TIMESTAMP WITH TIME ZONE) RETURN VARCHAR2 \n" + + "IS \n" + + "BEGIN \n" + + " RETURN TO_CHAR(dateValue,'YYYY-MM-DD HH24:MI:SS.FF');\n" + + "END nodb_plsqlbindfunc716;"; + + connection.execute( + proc, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // before + + after(function(done) { + var sql = "DROP FUNCTION nodb_plsqlbindfunc716"; + connection.execute( + sql, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // after + + var sqlrun_dt = "BEGIN :output := nodb_plsqlbindfunc716(:dateValue); END;"; + var resultBind = {type: oracledb.STRING, dir: oracledb.BIND_OUT}; + + it('70.16.1 basic case', function(done) { + var date = new Date( "2016-09-10T14:10:10.123Z" ); + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.DATE, dir: oracledb.BIND_IN, val: date} + }; + + connection.execute( + sqlrun_dt, + bindVar, + function(err, result) { + should.not.exist(err); + var expectDate = "2016-09-10 14:10:10.123000000"; + (result.outBinds.output).should.eql(expectDate); + done(); + } + ); + }); // 70.16.1 + + it('70.16.2 val: null', function(done) { + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.DATE, dir: oracledb.BIND_IN, val: null} + }; + + connection.execute( + sqlrun_dt, + bindVar, + function(err, result) { + should.not.exist(err); + should.strictEqual(result.outBinds.output, null); + done(); + } + ); + }); // 70.16.2 + + it('70.16.3 val: empty string', function(done) { + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.DATE, dir: oracledb.BIND_IN, val: ''} + }; + + connection.execute( + sqlrun_dt, + bindVar, + function(err) { + should.exist(err); + (err.message).should.startWith('NJS-011:'); + done(); + } + ); + }); // 70.16.3 + + it('70.16.4 val: undefined', function(done) { + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.DATE, dir: oracledb.BIND_IN, val: undefined} + }; + + connection.execute( + sqlrun_dt, + bindVar, + function(err, result) { + should.not.exist(err); + should.strictEqual(result.outBinds.output, null); + done(); + } + ); + }); // 70.16.4 + + it('70.16.5 val: NaN', function(done) { + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.DATE, dir: oracledb.BIND_IN, val: NaN} + }; + + connection.execute( + sqlrun_dt, + bindVar, + function(err) { + should.exist(err); + //NJS-011: encountered bind value and type mismatch in parameter 2 + (err.message).should.startWith('NJS-011:'); + done(); + } + ); + }); // 70.16.5 + + it('70.16.7 val: invalid Date Value: Feb 30, 2016', function(done) { + var date = new Date( Date.UTC( 2016, 1, 30, 0, 0, 0, 0 ) ); + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.DATE, dir: oracledb.BIND_IN, val: date} + }; + + connection.execute( + sqlrun_dt, + bindVar, + function(err, result) { + should.not.exist(err); + var resultDate = "2016-03-01 00:00:00.000000000"; + (result.outBinds.output).should.eql(resultDate); + done(); + } + ); + }); // 70.16.7 + + it('70.16.8 val: 1969-12-31', function(done) { + var date = new Date( Date.UTC( 1969, 11, 31, 0, 0, 0, 0 ) ); + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.DATE, dir: oracledb.BIND_IN, val: date} + }; + + connection.execute( + sqlrun_dt, + bindVar, + function(err, result) { + should.not.exist(err); + var resultDate = "1969-12-31 00:00:00.000000000"; + (result.outBinds.output).should.eql(resultDate); + done(); + } + ); + }); // 70.16.8 + + it('70.16.9 val: epoch date 1970-1-1', function(done) { + var date = new Date( Date.UTC( 1970, 0, 1, 0, 0, 0, 0 ) ); + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.DATE, dir: oracledb.BIND_IN, val: date} + }; + + connection.execute( + sqlrun_dt, + bindVar, + function(err, result) { + should.not.exist(err); + var resultDate = "1970-01-01 00:00:00.000000000"; + (result.outBinds.output).should.eql(resultDate); + done(); + } + ); + }); // 70.16.9 + + it('70.16.10 val: create Date value using numeric value: new Date(number)', function(done) { + var date = new Date ( 1476780296673 ); + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.DATE, dir: oracledb.BIND_IN, val: date} + }; + + connection.execute( + sqlrun_dt, + bindVar, + function(err, result) { + should.not.exist(err); + var resultDate = "2016-10-18 08:44:56.673000000"; + (result.outBinds.output).should.eql(resultDate); + done(); + } + ); + }); // 70.16.10 + + it('70.16.11 val: create Date value using numeric value: 0', function(done) { + //Zero time is 01 January 1970 00:00:00 UTC + var date = new Date ( 0 ); + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.DATE, dir: oracledb.BIND_IN, val: date} + }; + + connection.execute( + sqlrun_dt, + bindVar, + function(err, result) { + should.not.exist(err); + var resultDate = "1970-01-01 00:00:00.000000000"; + (result.outBinds.output).should.eql(resultDate); + done(); + } + ); + }); // 70.16.11 + + });//70.16 + + describe('70.17 dir: BIND_IN and BIND_OUT, type: TIMESTAMP WITH TIME ZONE', function() { + + before(function(done) { + var proc = "CREATE OR REPLACE \n" + + "FUNCTION nodb_plsqlbindfunc717(dateValue IN TIMESTAMP WITH TIME ZONE) RETURN TIMESTAMP WITH TIME ZONE \n" + + "IS \n" + + "BEGIN \n" + + " RETURN dateValue;\n" + + "END nodb_plsqlbindfunc717;"; + + connection.execute( + proc, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // before + + after(function(done) { + var sql = "DROP FUNCTION nodb_plsqlbindfunc717"; + connection.execute( + sql, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // after + + var sqlrun = "BEGIN :output := nodb_plsqlbindfunc717(:dateValue); END;"; + var resultBind = {type: oracledb.DATE, dir: oracledb.BIND_OUT}; + + it('70.17.1 val: empty string', function(done) { + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.DATE, dir: oracledb.BIND_IN, val: ''} + }; + + connection.execute( + sqlrun, + bindVar, + function(err) { + should.exist(err); + (err.message).should.startWith('NJS-011:'); + done(); + } + ); + }); // 70.17.1 + + it('70.17.2 val: undefined', function(done) { + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.DATE, dir: oracledb.BIND_IN, val: undefined} + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + should.strictEqual(result.outBinds.output, null); + done(); + } + ); + }); // 70.17.2 + + it('70.17.3 val: NaN', function(done) { + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.DATE, dir: oracledb.BIND_IN, val: NaN} + }; + + connection.execute( + sqlrun, + bindVar, + function(err) { + should.exist(err); + //NJS-011: encountered bind value and type mismatch in parameter 2 + (err.message).should.startWith('NJS-011:'); + done(); + } + ); + }); // 70.17.3 + });//70.17 + + describe('70.18 dir: BIND_INOUT, type:TIMESTAMP WITH TIME ZONE', function(){ + before(function(done){ + var proc = "CREATE OR REPLACE PROCEDURE nodb_inoutproc718 (p_inout IN OUT TIMESTAMP WITH TIME ZONE) \n" + + "AS \n" + + "BEGIN \n" + + " p_inout := p_inout; \n" + + "END nodb_inoutproc718;"; + + connection.execute( + proc, + function(err) { + should.not.exist(err); + done(); + } + ); + });//before + + after(function(done){ + var sql = "DROP PROCEDURE nodb_inoutproc718"; + connection.execute( + sql, + function(err) { + should.not.exist(err); + done(); + } + ); + });//after + + var sqlrun = "begin nodb_inoutproc718(p_inout => :p_inout); end;"; + + it('70.18.1 basic case', function(done){ + var date = new Date( 2016, 7, 5, 12, 13, 14, 123 ); + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + type: oracledb.DATE, + val: date + } + }; + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + (result.outBinds.p_inout).should.eql(date); + done(); + } + ); + });//70.18.1 + + it('70.18.2 auto detect data type', function(done) { + var date = new Date( 2016, 7, 5, 12, 13, 14, 123 ); + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + val: date + } + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + (result.outBinds.p_inout).should.eql(date); + done(); + } + ); + }); // 70.18.2 + + it('70.18.3 val: null', function(done) { + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + type: oracledb.DATE, + val: null + } + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + should.strictEqual(result.outBinds.p_inout, null); + done(); + } + ); + }); // 70.18.3 + + it('70.18.4 val: empty string', function(done) { + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + type: oracledb.DATE, + val: '' + } + }; + + connection.execute( + sqlrun, + bindVar, + function(err) { + should.exist(err); + (err.message).should.startWith('NJS-011:'); + done(); + } + ); + }); // 70.18.4 + + it('70.18.5 val: undefined', function(done) { + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + type: oracledb.DATE, + val: undefined + } + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.outBinds.p_inout, null); + done(); + } + ); + }); // 70.18.5 + + it('70.18.6 val: NaN', function(done) { + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + type: oracledb.DATE, + val: NaN + } + }; + + connection.execute( + sqlrun, + bindVar, + function(err) { + should.exist(err); + (err.message).should.startWith('NJS-011:'); + done(); + } + ); + }); // 70.18.6 + + it('70.18.7 val: invalid Date Value: Feb 30, 2016', function(done) { + var date = new Date ( 2016, 1, 30, 0, 0, 0, 0 ); + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + type: oracledb.DATE, + val: date + } + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + //console.log(result); + var resultDate = new Date ( 2016, 2, 1, 0, 0, 0, 0 ); + (result.outBinds.p_inout).should.eql(resultDate); + done(); + } + ); + }); // 70.18.7 + + it('70.18.8 val: 1969-12-31', function(done) { + var date = new Date ( 1969, 11, 31, 0, 0, 0, 0 ); + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + type: oracledb.DATE, + val: date + } + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + (result.outBinds.p_inout).should.eql(date); + done(); + } + ); + }); // 70.18.8 + + it('70.18.9 val: epoch date 1970-1-1', function(done) { + var date = new Date ( 1970, 0, 1, 0, 0, 0, 0 ); + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + type: oracledb.DATE, + val: date + } + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + (result.outBinds.p_inout).should.eql(date); + done(); + } + ); + }); // 70.18.9 + + it('70.18.10 NULL IN and NON-NULL out', function(done) { + var proc71810 = "CREATE OR REPLACE PROCEDURE nodb_inoutproc71810 (p_inout IN OUT TIMESTAMP WITH TIME ZONE) \n" + + "AS \n" + + "BEGIN \n" + + " p_inout := TO_TIMESTAMP_TZ('1999-12-01 11:00:00.001231000', 'YYYY-MM-DD HH24:MI:SS.FF'); \n" + + "END nodb_inoutproc71810;"; + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + type: oracledb.DATE, + val: null + } + }; + var sqlrun71810 = "begin nodb_inoutproc71810(p_inout => :p_inout); end;"; + var sqldrop = "DROP PROCEDURE nodb_inoutproc71810"; + async.series([ + function(cb) { + connection.execute( + proc71810, + function(err) { + should.not.exist(err); + cb(); + } + ); + }, + function(cb) { + connection.execute( + sqlrun71810, + bindVar, + function(err, result) { + should.not.exist(err); + (result.outBinds.p_inout).should.not.eql(null); + cb(); + } + ); + }, + function(cb) { + connection.execute( + sqldrop, + function(err) { + should.not.exist(err); + cb(); + } + ); + } + ], done); + }); // 70.18.10 + + it('70.18.11 NON-NULL IN and NULL OUT', function(done) { + var proc71811 = "CREATE OR REPLACE PROCEDURE nodb_inoutproc71811 (p_inout IN OUT TIMESTAMP WITH TIME ZONE) \n" + + "AS \n" + + "BEGIN \n" + + " p_inout := null; \n" + + "END nodb_inoutproc71811;"; + var date = new Date( 2011, 0, 12, 0, 0, 0, 0 ); + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + type: oracledb.DATE, + val: date + } + }; + var sqlrun71811 = "begin nodb_inoutproc71811(p_inout => :p_inout); end;"; + var sqldrop = "DROP PROCEDURE nodb_inoutproc71811"; + async.series([ + function(cb) { + connection.execute( + proc71811, + function(err) { + should.not.exist(err); + cb(); + } + ); + }, + function(cb) { + connection.execute( + sqlrun71811, + bindVar, + function(err, result) { + should.not.exist(err); + should.strictEqual(result.outBinds.p_inout, null); + cb(); + } + ); + }, + function(cb) { + connection.execute( + sqldrop, + function(err) { + should.not.exist(err); + cb(); + } + ); + } + ], done); + }); // 70.18.11 + + });//70.18 + + describe('70.19 dir: BIND_IN and BIND_OUT, type: TIMESTAMP WITH LOCAL TIME ZONE(convert STRING to TIMESTAMP)', function() { + + before(function(done) { + var proc = "CREATE OR REPLACE \n" + + "FUNCTION nodb_plsqlbindfunc719(dateValue IN TIMESTAMP WITH LOCAL TIME ZONE) RETURN VARCHAR2 \n" + + "IS \n" + + "BEGIN \n" + + " RETURN TO_CHAR(dateValue, 'YYYY-MM-DD HH24:MI:SS.FF');\n" + + "END nodb_plsqlbindfunc719;"; + + connection.execute( + proc, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // before + + after(function(done) { + var sql = "DROP FUNCTION nodb_plsqlbindfunc719"; + connection.execute( + sql, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // after + + var sqlrun_str = "BEGIN :output := nodb_plsqlbindfunc719(TO_TIMESTAMP_TZ(:dateValue, 'YYYY-MM-DD HH24:MI:SS.FF')); END;"; + var resultBind = {type: oracledb.STRING, dir: oracledb.BIND_OUT}; + + it('70.19.1 basic case', function(done) { + var date = '1999-12-01 11:00:00.123450000'; + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.STRING, dir: oracledb.BIND_IN, val: date} + }; + + connection.execute( + sqlrun_str, + bindVar, + function(err, result) { + should.not.exist(err); + (result.outBinds.output).should.eql(date); + done(); + } + ); + }); // 70.19.1 + + it('70.19.2 val: null', function(done) { + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.STRING, dir: oracledb.BIND_IN, val: null} + }; + + connection.execute( + sqlrun_str, + bindVar, + function(err, result) { + should.not.exist(err); + should.strictEqual(result.outBinds.output, null); + done(); + } + ); + }); // 70.19.2 + + it('70.19.3 val: empty string', function(done) { + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.STRING, dir: oracledb.BIND_IN, val: ''} + }; + + connection.execute( + sqlrun_str, + bindVar, + function(err, result) { + should.not.exist(err); + should.strictEqual(result.outBinds.output, null); + done(); + } + ); + }); // 70.19.3 + + it('70.19.4 val: undefined', function(done) { + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.STRING, dir: oracledb.BIND_IN, val: undefined} + }; + + connection.execute( + sqlrun_str, + bindVar, + function(err, result) { + should.not.exist(err); + should.strictEqual(result.outBinds.output, null); + done(); + } + ); + }); // 70.19.4 + + it('70.19.5 val: NaN', function(done) { + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.STRING, dir: oracledb.BIND_IN, val: NaN} + }; + + connection.execute( + sqlrun_str, + bindVar, + function(err) { + should.exist(err); + //NJS-011: encountered bind value and type mismatch in parameter 2 + (err.message).should.startWith('NJS-011:'); + done(); + } + ); + }); // 70.19.5 + + it('70.19.7 val: invalid Date Value: Feb 30, 2016', function(done) { + var date = '2016-02-30 00:00:00.000000000'; + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.STRING, dir: oracledb.BIND_IN, val: date} + }; + + connection.execute( + sqlrun_str, + bindVar, + function(err) { + should.exist(err); + //ORA-01839: date not valid for month specified + (err.message).should.startWith("ORA-01839:"); + done(); + } + ); + }); // 70.19.7 + + it('70.19.8 val: 1969-12-31', function(done) { + var date = '1969-12-31 00:00:00.000000000'; + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.STRING, dir: oracledb.BIND_IN, val: date} + }; + + connection.execute( + sqlrun_str, + bindVar, + function(err, result) { + should.not.exist(err); + var resultDate = result.outBinds.output.toLowerCase(); + resultDate.should.eql(date); + done(); + } + ); + }); // 70.19.8 + + it('70.19.9 val: epoch date 1970-1-1', function(done) { + var date = '1970-01-01 00:00:00.000000000'; + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.STRING, dir: oracledb.BIND_IN, val: date} + }; + + connection.execute( + sqlrun_str, + bindVar, + function(err, result) { + should.not.exist(err); + (result.outBinds.output).should.eql(date); + done(); + } + ); + }); // 70.19.9 + + });//70.19 + + describe('70.20 dir: BIND_IN and BIND_OUT, type: TIMESTAMP WITH LOCAL TIME ZONE(WITH VARCHAR2 RETURN)', function() { + + before(function(done) { + var proc = "CREATE OR REPLACE \n" + + "FUNCTION nodb_plsqlbindfunc720(dateValue IN TIMESTAMP WITH LOCAL TIME ZONE) RETURN VARCHAR2 \n" + + "IS \n" + + "BEGIN \n" + + " RETURN TO_CHAR(dateValue,'YYYY-MM-DD HH24:MI:SS.FF');\n" + + "END nodb_plsqlbindfunc720;"; + + connection.execute( + proc, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // before + + after(function(done) { + var sql = "DROP FUNCTION nodb_plsqlbindfunc720"; + connection.execute( + sql, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // after + + var sqlrun_dt = "BEGIN :output := nodb_plsqlbindfunc720(:dateValue); END;"; + var resultBind = {type: oracledb.STRING, dir: oracledb.BIND_OUT}; + + it('70.20.1 basic case', function(done) { + var date = new Date( "2016-09-10T14:10:10.123Z" ); + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.DATE, dir: oracledb.BIND_IN, val: date} + }; + + connection.execute( + sqlrun_dt, + bindVar, + function(err, result) { + should.not.exist(err); + var expectDate = "2016-09-10 14:10:10.123000000"; + (result.outBinds.output).should.eql(expectDate); + done(); + } + ); + }); // 70.20.1 + + it('70.20.2 val: null', function(done) { + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.DATE, dir: oracledb.BIND_IN, val: null} + }; + + connection.execute( + sqlrun_dt, + bindVar, + function(err, result) { + should.not.exist(err); + should.strictEqual(result.outBinds.output, null); + done(); + } + ); + }); // 70.20.2 + + it('70.20.3 val: empty string', function(done) { + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.DATE, dir: oracledb.BIND_IN, val: ''} + }; + + connection.execute( + sqlrun_dt, + bindVar, + function(err) { + should.exist(err); + (err.message).should.startWith('NJS-011:'); + done(); + } + ); + }); // 70.20.3 + + it('70.20.4 val: undefined', function(done) { + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.DATE, dir: oracledb.BIND_IN, val: undefined} + }; + + connection.execute( + sqlrun_dt, + bindVar, + function(err, result) { + should.not.exist(err); + should.strictEqual(result.outBinds.output, null); + done(); + } + ); + }); // 70.20.4 + + it('70.20.5 val: NaN', function(done) { + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.DATE, dir: oracledb.BIND_IN, val: NaN} + }; + + connection.execute( + sqlrun_dt, + bindVar, + function(err) { + should.exist(err); + //NJS-011: encountered bind value and type mismatch in parameter 2 + (err.message).should.startWith('NJS-011:'); + done(); + } + ); + }); // 70.20.5 + + it('70.20.7 val: invalid Date Value: Feb 30, 2016', function(done) { + var date = new Date( Date.UTC( 2016, 1, 30, 0, 0, 0, 0 ) ); + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.DATE, dir: oracledb.BIND_IN, val: date} + }; + + connection.execute( + sqlrun_dt, + bindVar, + function(err, result) { + should.not.exist(err); + var resultDate = "2016-03-01 00:00:00.000000000"; + (result.outBinds.output).should.eql(resultDate); + done(); + } + ); + }); // 70.20.7 + + it('70.20.8 val: 1969-12-31', function(done) { + var date = new Date( Date.UTC( 1969, 11, 31, 0, 0, 0, 0 ) ); + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.DATE, dir: oracledb.BIND_IN, val: date} + }; + + connection.execute( + sqlrun_dt, + bindVar, + function(err, result) { + should.not.exist(err); + var resultDate = "1969-12-31 00:00:00.000000000"; + (result.outBinds.output).should.eql(resultDate); + done(); + } + ); + }); // 70.20.8 + + it('70.20.9 val: epoch date 1970-1-1', function(done) { + var date = new Date( Date.UTC( 1970, 0, 1, 0, 0, 0, 0 ) ); + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.DATE, dir: oracledb.BIND_IN, val: date} + }; + + connection.execute( + sqlrun_dt, + bindVar, + function(err, result) { + should.not.exist(err); + var resultDate = "1970-01-01 00:00:00.000000000"; + (result.outBinds.output).should.eql(resultDate); + done(); + } + ); + }); // 70.20.9 + + it('70.20.10 val: create Date value using numeric value: new Date(number)', function(done) { + var date = new Date ( 1476780296673 ); + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.DATE, dir: oracledb.BIND_IN, val: date} + }; + + connection.execute( + sqlrun_dt, + bindVar, + function(err, result) { + should.not.exist(err); + var resultDate = "2016-10-18 08:44:56.673000000"; + (result.outBinds.output).should.eql(resultDate); + done(); + } + ); + }); // 70.20.10 + + it('70.20.11 val: create Date value using numeric value: 0', function(done) { + //Zero time is 01 January 1970 00:00:00 UTC + var date = new Date ( 0 ); + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.DATE, dir: oracledb.BIND_IN, val: date} + }; + + connection.execute( + sqlrun_dt, + bindVar, + function(err, result) { + should.not.exist(err); + var resultDate = "1970-01-01 00:00:00.000000000"; + (result.outBinds.output).should.eql(resultDate); + done(); + } + ); + }); // 70.20.11 + + });//70.20 + + describe('70.21 dir: BIND_IN and BIND_OUT, type: TIMESTAMP WITH LOCAL TIME ZONE', function() { + + before(function(done) { + var proc = "CREATE OR REPLACE \n" + + "FUNCTION nodb_plsqlbindfunc721(dateValue IN TIMESTAMP WITH LOCAL TIME ZONE) RETURN TIMESTAMP WITH LOCAL TIME ZONE \n" + + "IS \n" + + "BEGIN \n" + + " RETURN dateValue;\n" + + "END nodb_plsqlbindfunc721;"; + + connection.execute( + proc, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // before + + after(function(done) { + var sql = "DROP FUNCTION nodb_plsqlbindfunc721"; + connection.execute( + sql, + function(err) { + should.not.exist(err); + done(); + } + ); + }); // after + + var sqlrun = "BEGIN :output := nodb_plsqlbindfunc721(:dateValue); END;"; + var resultBind = {type: oracledb.DATE, dir: oracledb.BIND_OUT}; + + it('70.21.1 val: empty string', function(done) { + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.DATE, dir: oracledb.BIND_IN, val: ''} + }; + + connection.execute( + sqlrun, + bindVar, + function(err) { + should.exist(err); + (err.message).should.startWith('NJS-011:'); + done(); + } + ); + }); // 70.21.1 + + it('70.21.2 val: undefined', function(done) { + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.DATE, dir: oracledb.BIND_IN, val: undefined} + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + should.strictEqual(result.outBinds.output, null); + done(); + } + ); + }); // 70.21.2 + + it('70.21.3 val: NaN', function(done) { + var bindVar = { + output: resultBind, + dateValue: {type: oracledb.DATE, dir: oracledb.BIND_IN, val: NaN} + }; + + connection.execute( + sqlrun, + bindVar, + function(err) { + should.exist(err); + //NJS-011: encountered bind value and type mismatch in parameter 2 + (err.message).should.startWith('NJS-011:'); + done(); + } + ); + }); // 70.21.3 + + });//70.21 + + describe('70.22 dir: BIND_INOUT, type:TIMESTAMP WITH LOCAL TIME ZONE', function(){ + before(function(done){ + var proc = "CREATE OR REPLACE PROCEDURE nodb_inoutproc722 (p_inout IN OUT TIMESTAMP WITH LOCAL TIME ZONE) \n" + + "AS \n" + + "BEGIN \n" + + " p_inout := p_inout; \n" + + "END nodb_inoutproc722;"; + + connection.execute( + proc, + function(err) { + should.not.exist(err); + done(); + } + ); + });//before + + after(function(done){ + var sql = "DROP PROCEDURE nodb_inoutproc722"; + connection.execute( + sql, + function(err) { + should.not.exist(err); + done(); + } + ); + });//after + + var sqlrun = "begin nodb_inoutproc722(p_inout => :p_inout); end;"; + + it('70.22.1 basic case', function(done){ + var date = new Date( 2016, 7, 5, 12, 13, 14, 123 ); + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + type: oracledb.DATE, + val: date + } + }; + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + (result.outBinds.p_inout).should.eql(date); + done(); + } + ); + });//70.22.1 + + it('70.22.2 auto detect data type', function(done) { + var date = new Date( 2016, 7, 5, 12, 13, 14, 123 ); + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + val: date + } + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + (result.outBinds.p_inout).should.eql(date); + done(); + } + ); + }); // 70.22.2 + + it('70.22.3 val: null', function(done) { + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + type: oracledb.DATE, + val: null + } + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + should.strictEqual(result.outBinds.p_inout, null); + done(); + } + ); + }); // 70.22.3 + + it('70.22.4 val: empty string', function(done) { + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + type: oracledb.DATE, + val: '' + } + }; + + connection.execute( + sqlrun, + bindVar, + function(err) { + should.exist(err); + (err.message).should.startWith('NJS-011:'); + done(); + } + ); + }); // 70.22.4 + + it('70.22.5 val: undefined', function(done) { + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + type: oracledb.DATE, + val: undefined + } + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + // console.log(result); + should.strictEqual(result.outBinds.p_inout, null); + done(); + } + ); + }); // 70.22.5 + + it('70.22.6 val: NaN', function(done) { + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + type: oracledb.DATE, + val: NaN + } + }; + + connection.execute( + sqlrun, + bindVar, + function(err) { + should.exist(err); + (err.message).should.startWith('NJS-011:'); + done(); + } + ); + }); // 70.22.6 + + it('70.22.7 val: invalid Date Value: Feb 30, 2016', function(done) { + var date = new Date ( 2016, 1, 30, 0, 0, 0, 0 ); + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + type: oracledb.DATE, + val: date + } + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + //console.log(result); + var resultDate = new Date ( 2016, 2, 1, 0, 0, 0, 0 ); + (result.outBinds.p_inout).should.eql(resultDate); + done(); + } + ); + }); // 70.22.7 + + it('70.22.8 val: 1969-12-31', function(done) { + var date = new Date ( 1969, 11, 31, 0, 0, 0, 0 ); + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + type: oracledb.DATE, + val: date + } + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + (result.outBinds.p_inout).should.eql(date); + done(); + } + ); + }); // 70.22.8 + + it('70.22.9 val: epoch date 1970-1-1', function(done) { + var date = new Date ( 1970, 0, 1, 0, 0, 0, 0 ); + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + type: oracledb.DATE, + val: date + } + }; + + connection.execute( + sqlrun, + bindVar, + function(err, result) { + should.not.exist(err); + (result.outBinds.p_inout).should.eql(date); + done(); + } + ); + }); // 70.22.9 + + it('70.22.10 NULL IN and NON-NULL OUT', function(done) { + var proc72210 = "CREATE OR REPLACE PROCEDURE nodb_inoutproc72210 (p_inout IN OUT TIMESTAMP WITH LOCAL TIME ZONE) \n" + + "AS \n" + + "BEGIN \n" + + " p_inout := TO_TIMESTAMP_TZ('1999-12-01 11:00:00.001231000', 'YYYY-MM-DD HH24:MI:SS.FF'); \n" + + "END nodb_inoutproc72210;"; + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + type: oracledb.DATE, + val: null + } + }; + var sqlrun72210 = "begin nodb_inoutproc72210(p_inout => :p_inout); end;"; + var sqldrop = "DROP PROCEDURE nodb_inoutproc72210"; + async.series([ + function(cb) { + connection.execute( + proc72210, + function(err) { + should.not.exist(err); + cb(); + } + ); + }, + function(cb) { + connection.execute( + sqlrun72210, + bindVar, + function(err, result) { + should.not.exist(err); + (result.outBinds.p_inout).should.not.eql(null); + cb(); + } + ); + }, + function(cb) { + connection.execute( + sqldrop, + function(err) { + should.not.exist(err); + cb(); + } + ); + } + ], done); + }); // 70.22.10 + + it('70.22.11 NON-NULL IN and NULL OUT', function(done) { + var proc72211 = "CREATE OR REPLACE PROCEDURE nodb_inoutproc72211 (p_inout IN OUT TIMESTAMP WITH LOCAL TIME ZONE) \n" + + "AS \n" + + "BEGIN \n" + + " p_inout := null; \n" + + "END nodb_inoutproc72211;"; + var date = new Date( 2011, 0, 12, 0, 0, 0, 0 ); + var bindVar = { + p_inout : { + dir: oracledb.BIND_INOUT, + type: oracledb.DATE, + val: date + } + }; + var sqlrun72211 = "begin nodb_inoutproc72211(p_inout => :p_inout); end;"; + var sqldrop = "DROP PROCEDURE nodb_inoutproc72211"; + async.series([ + function(cb) { + connection.execute( + proc72211, + function(err) { + should.not.exist(err); + cb(); + } + ); + }, + function(cb) { + connection.execute( + sqlrun72211, + bindVar, + function(err, result) { + should.not.exist(err); + should.strictEqual(result.outBinds.p_inout, null); + cb(); + } + ); + }, + function(cb) { + connection.execute( + sqldrop, + function(err) { + should.not.exist(err); + cb(); + } + ); + } + ], done); + }); // 70.22.11 + + });//70.22 + +}); diff --git a/test/poolCache.js b/test/poolCache.js new file mode 100644 index 00000000..4a3f9d5d --- /dev/null +++ b/test/poolCache.js @@ -0,0 +1,728 @@ +/* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with the Apache + * License, Version 2.0 (the "License.") + * + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + * The node-oracledb test suite uses 'mocha', 'should' and 'async'. + * See LICENSE.md for relevant licenses. + * + * NAME + * 67. poolCache.js + * + * DESCRIPTION + * Testing properties of connection pool. + * + * NUMBERING RULE + * Test numbers follow this numbering rule: + * 1 - 20 are reserved for basic functional tests + * 21 - 50 are reserved for data type supporting tests + * 51 onwards are for other tests + * + *****************************************************************************/ +'use strict'; + +var oracledb = require('oracledb'); +var async = require('async'); +var should = require('should'); +var dbConfig = require('./dbconfig.js'); + +describe('67. poolCache.js', function() { + beforeEach(function() { + // ensure that no poolAlias has been specified + delete dbConfig.poolAlias; + }); + + after(function() { + // ensure that no poolAlias has been specified + delete dbConfig.poolAlias; + }); + + describe('67.1 basic functional tests', function() { + it('67.1.1 caches pool as default if pool is created when cache is empty', function(done) { + oracledb.createPool(dbConfig, function(err, pool) { + var defaultPool; + + should.not.exist(err); + + pool.should.be.ok(); + + // Not specifying a name, default will be used + defaultPool = oracledb.getPool(); + + should.strictEqual(pool, defaultPool); + + (defaultPool.poolAlias).should.equal('default'); + + pool.close(function(err){ + should.not.exist(err); + done(); + }); + }); + }); + + it('67.1.2 removes the pool from the cache on terminate', function(done) { + oracledb.createPool(dbConfig, function(err, pool) { + should.not.exist(err); + + pool.should.be.ok(); + + pool.close(function(err){ + var defaultPool; + + should.not.exist(err); + + (function() { + defaultPool = oracledb.getPool(); + }).should.throw(/^NJS-047:/); + + should.not.exist(defaultPool); + + done(); + }); + }); + }); + + it('67.1.3 can cache and retrieve an aliased pool', function(done) { + var poolAlias = 'random-pool-alias'; + + dbConfig.poolAlias = poolAlias; + + oracledb.createPool(dbConfig, function(err, pool) { + var aliasedPool; + + should.not.exist(err); + + pool.should.be.ok(); + + pool.poolAlias.should.equal(poolAlias); + + aliasedPool = oracledb.getPool(poolAlias); + + should.strictEqual(pool, aliasedPool); + + pool.close(function(err){ + should.not.exist(err); + done(); + }); + }); + }); + + it('67.1.4 throws an error if the poolAlias already exists in the cache', function(done) { + dbConfig.poolAlias = 'pool1'; + + oracledb.createPool(dbConfig, function(err, pool1) { + should.not.exist(err); + + pool1.should.be.ok(); + + // Creating another pool with the same poolAlias as before + oracledb.createPool(dbConfig, function(err, pool2) { + should.exist(err); + + (err.message).should.startWith('NJS-046:'); + should.not.exist(pool2); + + pool1.close(function(err){ + should.not.exist(err); + + done(); + }); + }); + }); + }); + + it('67.1.5 does not throw an error if multiple pools are created without a poolAlias', function(done) { + oracledb.createPool(dbConfig, function(err, pool1) { + should.not.exist(err); + + pool1.should.be.ok(); + + // Creating another pool with no poolAlias + oracledb.createPool(dbConfig, function(err, pool2) { + should.not.exist(err); + + pool2.should.be.ok(); + + pool1.close(function(err){ + should.not.exist(err); + + pool2.close(function(err){ + should.not.exist(err); + + done(); + }); + }); + }); + }); + }); + + it('67.1.6 throws an error if poolAttrs.poolAlias is not a string', function(done) { + // Setting poolAlias to something other than a string. Could be + // boolean, object, array, etc. + dbConfig.poolAlias = {}; + + oracledb.createPool(dbConfig, function(err, pool) { + should.exist(err); + (err.message).should.startWith('NJS-004:'); + + should.not.exist(pool); + + done(); + }); + }); + + it('67.1.7 makes poolAttrs.poolAlias a read-only attribute on the pool named poolAlias', function(done) { + dbConfig.poolAlias = 'my-pool'; + + oracledb.createPool(dbConfig, function(err, pool) { + should.not.exist(err); + + pool.should.be.ok(); + + (pool.poolAlias).should.equal(dbConfig.poolAlias); + + (function() { + pool.poolAlias = 'some-new-value'; + }).should.throw(/^NJS-014:/); + + (pool.poolAlias).should.equal(dbConfig.poolAlias); + + pool.close(function(err) { + should.not.exist(err); + + done(); + }); + }); + }); + + it('67.1.8 retrieves the default pool, even after an aliased pool is created', function(done) { + oracledb.createPool(dbConfig, function(err, pool1) { + should.not.exist(err); + + pool1.should.be.ok(); + + dbConfig.poolAlias = 'random-pool-alias'; + + oracledb.createPool(dbConfig, function(err, pool2) { + var defaultPool; + + should.not.exist(err); + + pool2.should.be.ok(); + + // Not specifying a name, default will be used + defaultPool = oracledb.getPool(); + + should.strictEqual(pool1, defaultPool); + + (defaultPool.poolAlias).should.equal('default'); + + pool1.close(function(err){ + should.not.exist(err); + + pool2.close(function(err){ + should.not.exist(err); + + done(); + }); + }); + }); + }); + }); + + it('67.1.9 retrieves the right pool, even after multiple pools are created', function(done) { + var aliasToGet = 'random-pool-alias-2'; + + dbConfig.poolAlias = 'random-pool-alias'; + + oracledb.createPool(dbConfig, function(err, pool1) { + should.not.exist(err); + + pool1.should.be.ok(); + + dbConfig.poolAlias = aliasToGet; + + oracledb.createPool(dbConfig, function(err, pool2) { + should.not.exist(err); + + pool2.should.be.ok(); + + dbConfig.poolAlias = 'random-pool-alias-3'; + + oracledb.createPool(dbConfig, function(err, pool3) { + var secondPool; + + should.not.exist(err); + + secondPool = oracledb.getPool(aliasToGet); + + should.strictEqual(pool2, secondPool); + + (secondPool.poolAlias).should.equal(aliasToGet); + + pool1.close(function(err){ + should.not.exist(err); + + pool2.close(function(err){ + should.not.exist(err); + + pool3.close(function(err){ + should.not.exist(err); + + done(); + }); + }); + }); + }); + }); + }); + }); + + it('67.1.10 throws an error if the pool specified in getPool doesn\'t exist', function(done) { + (function() { + oracledb.getPool(); + }).should.throw(/^NJS-047:/); + + (function() { + oracledb.getPool('some-random-alias'); + }).should.throw(/^NJS-047:/); + + done(); + }); + + it('67.1.11 does not throw an error if multiple pools are created without a poolAlias in the same call stack', function(done) { + var pool1; + var pool2; + + async.parallel( + [ + function(callback) { + oracledb.createPool(dbConfig, function(err, pool) { + should.not.exist(err); + + pool1 = pool; + + callback(); + }); + }, + function(callback) { + oracledb.createPool(dbConfig, function(err, pool) { + should.not.exist(err); + + pool2 = pool; + + callback(); + }); + } + ], + function(createPoolErr) { + should.not.exist(createPoolErr); + + pool1.close(function(err) { + should.not.exist(err); + + pool2.close(function(err) { + should.not.exist(err); + + done(createPoolErr); + }); + }); + } + ); + }); + + it('67.1.12 uses callback syntax function(err) instead of function(err, pool)', function(done) { + oracledb.createPool({ // this becomes the default pool + user : dbConfig.user, + password : dbConfig.password, + connectString : dbConfig.connectString, + poolMax : 4, + poolMin : 1, + poolIncrement: 1, + poolTimeout: 0 // never terminate unused connections + }, function(err) { + should.not.exist(err); + + var defaultPool = oracledb.getPool(); + should.exist(defaultPool); + (defaultPool.poolAlias).should.equal('default'); + + defaultPool.close(function(err) { + should.not.exist(err); + }); + done(); + }); + }); + + it('67.1.13 Negative: callback is called with function(err)', function(done) { + this.timeout(10000); + oracledb.createPool({ // this becomes the default pool + user : dbConfig.user, + password : 'wrongpassword', + connectString : dbConfig.connectString, + poolMax : 4, + poolMin : 1, + poolIncrement: 1, + poolTimeout: 0 // never terminate unused connections + }, function(err) { + should.exist(err); + // ORA-01017: invalid username/password; logon denied + (err.message).should.startWith('ORA-01017:'); + done(); + }); + }); + + it('67.1.14 a named pool does not also create a default pool', function(done) { + var poolAlias = "named-pool"; + dbConfig.poolAlias = poolAlias; + oracledb.createPool(dbConfig, function(err, pool) { + should.not.exist(err); + pool.should.be.ok(); + (pool.poolAlias).should.eql('named-pool'); + + (function() { + oracledb.getPool(); + }).should.throw(/^NJS-047:/); + + (function() { + oracledb.getPool('named-pool'); + }).should.be.ok(); + + done(); + }); + }); + }); + + describe('67.2 oracledb.getConnection functional tests', function() { + it('67.2.1 gets a connection from the default pool when no alias is specified', function(done) { + oracledb.createPool(dbConfig, function(err, pool) { + should.not.exist(err); + + // Not specifying a poolAlias, default will be used + oracledb.getConnection(function(err, conn) { + should.not.exist(err); + + conn.release(function(err) { + should.not.exist(err); + + pool.close(function(err){ + should.not.exist(err); + + done(); + }); + }); + }); + }); + }); + + it('67.2.2 gets a connection from the pool with the specified poolAlias', function(done) { + var poolAlias = 'random-pool-alias'; + + dbConfig.poolAlias = poolAlias; + + oracledb.createPool(dbConfig, function(err, pool) { + should.not.exist(err); + + oracledb.getConnection(poolAlias, function(err, conn) { + should.not.exist(err); + + conn.release(function(err) { + should.not.exist(err); + + pool.close(function(err){ + should.not.exist(err); + + done(); + }); + }); + }); + }); + }); + + it('67.2.3 throws an error if an attempt is made to use the default pool when it does not exist', function(done) { + dbConfig.poolAlias = 'random-pool-alias'; + + oracledb.createPool(dbConfig, function(err, pool) { + should.not.exist(err); + + // Not specifying a poolAlias, default will be used + oracledb.getConnection(function(err) { + should.exist(err); + + (err.message).should.startWith('NJS-047:'); + + pool.close(function(err){ + should.not.exist(err); + + done(); + }); + }); + }); + }); + + it('67.2.4 throws an error if an attempt is made to use a poolAlias for a pool that is not in the cache', function(done) { + dbConfig.poolAlias = 'random-pool-alias'; + + oracledb.createPool(dbConfig, function(err, pool) { + should.not.exist(err); + + oracledb.getConnection('pool-alias-that-does-not-exist', function(err) { + should.exist(err); + + (err.message).should.startWith('NJS-047:'); + + pool.close(function(err){ + should.not.exist(err); + + done(); + }); + }); + }); + }); + + it('67.2.5 gets a connection from the default pool, even after an aliased pool is created', function(done) { + oracledb.createPool(dbConfig, function(err, pool1) { + should.not.exist(err); + + pool1.should.be.ok(); + + dbConfig.poolAlias = 'random-pool-alias'; + + oracledb.createPool(dbConfig, function(err, pool2) { + should.not.exist(err); + + pool2.should.be.ok(); + + oracledb.getConnection(function(err, conn) { + should.not.exist(err); + + // Using the hidden pool property to check where the connection came from + should.strictEqual(pool1, conn._pool); + + (conn._pool.poolAlias).should.equal('default'); + + conn.close(function(err) { + should.not.exist(err); + + pool1.close(function(err){ + should.not.exist(err); + + pool2.close(function(err){ + should.not.exist(err); + + done(); + }); + }); + }); + }); + }); + }); + }); + + it('67.2.6 uses the right pool, even after multiple pools are created', function(done) { + var aliasToUse = 'random-pool-alias-2'; + + dbConfig.poolAlias = 'random-pool-alias'; + + oracledb.createPool(dbConfig, function(err, pool1) { + should.not.exist(err); + + pool1.should.be.ok(); + + dbConfig.poolAlias = aliasToUse; + + oracledb.createPool(dbConfig, function(err, pool2) { + should.not.exist(err); + + pool2.should.be.ok(); + + dbConfig.poolAlias = 'random-pool-alias-3'; + + oracledb.createPool(dbConfig, function(err, pool3) { + should.not.exist(err); + + oracledb.getConnection(aliasToUse, function(err, conn) { + // Using the hidden pool property to check where the connection came from + should.strictEqual(pool2, conn._pool); + + (conn._pool.poolAlias).should.equal(aliasToUse); + + conn.close(function(err) { + should.not.exist(err); + + pool1.close(function(err){ + should.not.exist(err); + + pool2.close(function(err){ + should.not.exist(err); + + pool3.close(function(err){ + should.not.exist(err); + + done(); + }); + }); + }); + }); + }); + }); + }); + }); + }); + + it('67.2.7 gets a connection from the default pool with callback function(err)', function(done) { + oracledb.createPool({ // this becomes the default pool + user : dbConfig.user, + password : dbConfig.password, + connectString : dbConfig.connectString, + poolMax : 4, + poolMin : 1, + poolIncrement: 1, + poolTimeout: 0 // never terminate unused connections + }, function(err) { + should.not.exist(err); + + var defaultPool = oracledb.getPool(); + should.exist(defaultPool); + + oracledb.getConnection(function(err, conn) { + should.not.exist(err); + + conn.close(function(err) { + should.not.exist(err); + + defaultPool.close(function(err){ + should.not.exist(err); + done(); + }); + }); + }); + }); + }); + }); // 67.2 + +// This suite extends 67.1.6 case with various types + describe('67.3 poolAlias attribute', function() { + + it('67.3.1 throws an error if poolAttrs.poolAlias is an object', function(done) { + + dbConfig.poolAlias = {'foo': 'bar'}; + + oracledb.createPool(dbConfig, function(err) { + should.exist(err); + + (err.message).should.startWith('NJS-004:'); + + done(); + }); + }); + + it('67.3.2 throws an error if poolAttrs.poolAlias is an array', function(done) { + + dbConfig.poolAlias = []; + + oracledb.createPool(dbConfig, function(err) { + should.exist(err); + + (err.message).should.startWith('NJS-004:'); + // NJS-004: invalid value for property poolAttrs.poolAlias + done(); + }); + }); + + it('67.3.3 throws an error if poolAttrs.poolAlias is a number', function(done) { + + dbConfig.poolAlias = 123; + + oracledb.createPool(dbConfig, function(err) { + should.exist(err); + + (err.message).should.startWith('NJS-004:'); + + done(); + }); + }); + + it('67.3.4 throws an error if poolAttrs.poolAlias is a boolean', function(done) { + + dbConfig.poolAlias = false; + + oracledb.createPool(dbConfig, function(err) { + should.exist(err); + + (err.message).should.startWith('NJS-004:'); + + done(); + }); + }); + + it('67.3.5 throws an error if poolAttrs.poolAlias is null', function(done) { + + dbConfig.poolAlias = null; + + oracledb.createPool(dbConfig, function(err) { + should.exist(err); + + (err.message).should.startWith('NJS-004:'); + + done(); + }); + }); + + it('67.3.6 throws an error if poolAttrs.poolAlias is an empty string', function(done) { + + dbConfig.poolAlias = ''; + + oracledb.createPool(dbConfig, function(err) { + should.exist(err); + + (err.message).should.startWith('NJS-004:'); + + done(); + }); + }); + + it('67.3.7 throws an error if poolAttrs.poolAlias is NaN', function(done) { + + dbConfig.poolAlias = NaN; + + oracledb.createPool(dbConfig, function(err) { + should.exist(err); + + (err.message).should.startWith('NJS-004:'); + + done(); + }); + }); + + it('67.3.8 works if poolAttrs.poolAlias is undefined', function(done) { + + dbConfig.poolAlias = undefined; + + oracledb.createPool(dbConfig, function(err, pool) { + + pool.should.be.ok(); + (pool.poolAlias).should.equal('default'); + + pool.close(function(err) { + should.not.exist(err); + done(); + }); + + }); + }); + + }); // 67.3 +}); diff --git a/test/poolPing.js b/test/poolPing.js new file mode 100644 index 00000000..a9b90ada --- /dev/null +++ b/test/poolPing.js @@ -0,0 +1,548 @@ +/* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with the Apache + * License, Version 2.0 (the "License.") + * + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + * The node-oracledb test suite uses 'mocha', 'should' and 'async'. + * See LICENSE.md for relevant licenses. + * + * NAME + * 73. poolPing.js + * + * DESCRIPTION + * Testing connection ping feature of Pool object. + * + * NUMBERING RULE + * Test numbers follow this numbering rule: + * 1 - 20 are reserved for basic functional tests + * 21 - 50 are reserved for data type supporting tests + * 51 onwards are for other tests + * + *****************************************************************************/ +'use strict'; + +var oracledb = require('oracledb'); +var async = require('async'); +var should = require('should'); +var dbConfig = require('./dbconfig.js'); + +describe("73. poolPing.js", function() { + + var defaultInterval = oracledb.poolPingInterval; + + afterEach("reset poolPingInterval to default", function() { + + oracledb.poolPingInterval = defaultInterval; + should.strictEqual(oracledb.poolPingInterval, 60); + + }); + + it("73.1 the default value of poolPingInterval is 60", function(done) { + + var defaultValue = 60; + should.strictEqual(oracledb.poolPingInterval, defaultValue); + + var pool; + async.series([ + function(cb) { + oracledb.createPool( + dbConfig, + function(err, pooling) { + should.not.exist(err); + pool = pooling; + + should.strictEqual(pool.poolPingInterval, defaultValue); + cb(); + } + ); + }, + function(cb) { + pool.close(function(err) { + should.not.exist(err); + cb(); + }); + } + ], done); + + }); // 73.1 + + it("73.2 does not change after the pool has been created", function(done) { + + var userSetInterval = 20; + oracledb.poolPingInterval = userSetInterval; + + var pool; + async.series([ + function(cb) { + oracledb.createPool( + dbConfig, + function(err, pooling) { + should.not.exist(err); + pool = pooling; + + should.strictEqual(pool.poolPingInterval, userSetInterval); + cb(); + } + ); + }, + function(cb) { + var newInterval = userSetInterval * 2; + oracledb.poolPingInterval = newInterval; + + // sleep a while + setTimeout(function() { + cb(); + }, 100); + }, + function dotest(cb) { + should.strictEqual(pool.poolPingInterval, userSetInterval); + cb(); + }, + function(cb) { + pool.close(function(err) { + should.not.exist(err); + cb(); + }); + } + ], done); + + }); // 73.2 + + it("73.3 can not be changed on pool object", function(done) { + + var userSetInterval = 30; + oracledb.poolPingInterval = userSetInterval; + + var pool; + async.series([ + function(cb) { + oracledb.createPool( + dbConfig, + function(err, pooling) { + should.not.exist(err); + pool = pooling; + + should.strictEqual(pool.poolPingInterval, userSetInterval); + cb(); + } + ); + }, + function dotest(cb) { + var newInterval = userSetInterval * 2; + + try { + pool.poolPingInterval = newInterval; + } catch(err) { + should.exist(err); + (err.message).should.startWith('NJS-014:'); + // NJS-014: poolPingInterval is a read-only property + } + cb(); + + }, + function(cb) { + pool.close(function(err) { + should.not.exist(err); + cb(); + }); + } + ], done); + + }); // 73.3 + + it("73.4 can not be accessed on connection object", function(done) { + + var pool, connection; + + async.series([ + function(cb) { + oracledb.createPool( + dbConfig, + function(err, pooling) { + should.not.exist(err); + pool = pooling; + cb(); + } + ); + }, + function dotest(cb) { + pool.getConnection(function(err, conn) { + should.not.exist(err); + connection = conn; + + should.not.exist(connection.poolPingInterval); + + cb(); + }); + }, + function(cb) { + connection.close(function(err) { + should.not.exist(err); + cb(); + }); + }, + function(cb) { + pool.close(function(err) { + should.not.exist(err); + cb(); + }); + } + ], done); + + }); // 73.4 + + // helper function for below test cases + var testDefine = function(userSetInterval, callback) { + + oracledb.poolPingInterval = userSetInterval; + + var pool; + async.series([ + function(cb) { + oracledb.createPool( + dbConfig, + function(err, pooling) { + should.not.exist(err); + pool = pooling; + + should.strictEqual(pool.poolPingInterval, userSetInterval); + cb(); + } + ); + }, + function(cb) { + pool.close(function(err) { + should.not.exist(err); + cb(); + }); + } + ], callback); + + }; // testDefine() + + it("73.5 can be set to 0, means always ping", function(done) { + + var userSetValue = 0; + testDefine(userSetValue, done); + + }); // 73.5 + + + it("73.6 can be set to negative values, means never ping", function(done) { + + var userSetValue = -80; + testDefine(userSetValue, done); + + }); // 73.6 + + it("73.7 Negative: Number.MAX_SAFE_INTEGER", function(done) { + + /* + Number.MAX_SAFE_INTEGER // 9007199254740991 + Math.pow(2, 53) - 1 // 9007199254740991 + */ + + try { + oracledb.poolPingInterval = Number.MAX_SAFE_INTEGER; + } catch(err) { + should.exist(err); + (err.message).should.startWith("NJS-004:"); + // NJS-004: invalid value for property pingPoolInterval + + done(); + } + + }); // 73.7 + + it("73.8 cannot surpass the upper limit", function(done) { + + var upperLimit = 2147483647; // 2GB + + async.series([ + function testMax(cb) { + testDefine(upperLimit, cb); + }, + function(cb) { + var upperLimitPlus = upperLimit +1; + + try{ + oracledb.poolPingInterval = upperLimitPlus; + } catch(err) { + should.exist(err); + (err.message).should.startWith("NJS-004:"); + cb(); + } + } + ], done); + + }); // 73.8 + + it("73.9 cannot surpass the lower Limit", function(done) { + + var lowerLimit = -2147483648; + + async.series([ + function texstMin(cb) { + testDefine(lowerLimit, cb); + }, + function(cb) { + var lowerLimitPlus = lowerLimit -1; + + try { + oracledb.poolPingInterval = lowerLimitPlus; + } catch(err) { + should.exist(err); + (err.message).should.startWith("NJS-004:"); + cb(); + } + } + ], done); + + }); // 73.9 + + it("73.10 Negative: null", function(done) { + + try { + oracledb.poolPingInterval = null; + } catch(err) { + should.exist(err); + (err.message).should.startWith("NJS-004:"); + + done(); + } + + + }); // 73.10 + + it("73.11 Negative: NaN", function(done) { + + try { + oracledb.poolPingInterval = NaN; + } catch(err) { + should.exist(err); + (err.message).should.startWith("NJS-004:"); + + done(); + } + + }); // 73.11 + + it("73.12 Negative: undefined", function(done) { + + try { + oracledb.poolPingInterval = undefined; + } catch(err) { + should.exist(err); + (err.message).should.startWith("NJS-004:"); + + done(); + } + + }); // 73.12 + + it("73.13 Negative: 'random-string'", function(done) { + + try { + oracledb.poolPingInterval = 'random-string'; + } catch(err) { + should.exist(err); + (err.message).should.startWith("NJS-004:"); + + done(); + } + + }); // 73.13 + + var testPoolDefine = function(userSetInterval, expectedValue, callback) { + + var pool; + async.series([ + function(cb) { + oracledb.createPool( + { + user: dbConfig.user, + password: dbConfig.password, + connectString: dbConfig.connectString, + poolPingInterval: userSetInterval + }, + function(err, pooling) { + should.not.exist(err); + pool = pooling; + + should.strictEqual(pool.poolPingInterval, expectedValue); + cb(); + } + ); + }, + function(cb) { + pool.close(function(err) { + should.not.exist(err); + cb(); + }); + } + ], callback); + + }; // testPoolDefine + + it("73.14 can be set at pool creation, e.g. positive value 1234", function(done) { + + var userSetValue = 1234; + testPoolDefine(userSetValue, userSetValue, done); + + }); + + it("73.15 can be set at pool creation, e.g. negative value -4321", function(done) { + + var userSetValue = -4321; + testPoolDefine(userSetValue, userSetValue, done); + + }); + + it("73.16 can be set at pool creation, e.g. 0 means always ping", function(done) { + + var userSetValue = 0; + testPoolDefine(userSetValue, userSetValue, done); + + }); + + it("73.17 Setting to 'null' will use current value from oracledb", function(done) { + + oracledb.poolPingInterval = 789; + var userSetValue = null; + + testPoolDefine(userSetValue, 789, done); + + }); + + it("73.18 Setting to 'undefined' will use current value from oracledb", function(done) { + + oracledb.poolPingInterval = 9876; + var userSetValue = undefined; + + testPoolDefine(userSetValue, 9876, done); + + }); + + it("73.19 can be set at pool creation. Negative: NaN", function(done) { + + /*var userSetValue = 'random-string';*/ + + var userSetValue = NaN; + + oracledb.createPool( + { + user: dbConfig.user, + password: dbConfig.password, + connectString: dbConfig.connectString, + poolPingInterval: userSetValue + }, + function(err, pool) { + should.exist(err); + (err.message).should.startWith("NJS-007:"); + // NJS-007: invalid value for "poolPingInterval" in parameter 1 + + should.not.exist(pool); + done(); + } + ); + + }); // 73.19 + + it("73.20 can be set at pool creation. Negative: 'random-string'", function(done) { + + var userSetValue = 'random-string'; + + oracledb.createPool( + { + user: dbConfig.user, + password: dbConfig.password, + connectString: dbConfig.connectString, + poolPingInterval: userSetValue + }, + function(err, pool) { + should.exist(err); + (err.message).should.startWith("NJS-008:"); + // NJS-008: invalid type for "poolPingInterval" in parameter 1 + + should.not.exist(pool); + done(); + } + ); + + }); // 73.20 + + it("73.21 cannot surpass the upper limit at pool creation", function(done) { + + var upperLimit = 2147483647; // 2GB + + async.series([ + function testMax(cb) { + testPoolDefine(upperLimit, upperLimit, cb); + }, + function(cb) { + + var userSetValue = upperLimit + 1; + oracledb.createPool( + { + user: dbConfig.user, + password: dbConfig.password, + connectString: dbConfig.connectString, + poolPingInterval: userSetValue + }, + function(err, pool) { + should.exist(err); + (err.message).should.startWith("NJS-007:"); + + should.not.exist(pool); + cb(); + } + ); + } + ], done); + + }); // 73.21 + + it("73.22 cannot surpass the lower limit at pool creation", function(done) { + + var lowerLimit = -2147483648; + + async.series([ + function testMax(cb) { + testPoolDefine(lowerLimit, lowerLimit, cb); + }, + function(cb) { + + var userSetValue = lowerLimit - 1; + oracledb.createPool( + { + user: dbConfig.user, + password: dbConfig.password, + connectString: dbConfig.connectString, + poolPingInterval: userSetValue + }, + function(err, pool) { + should.exist(err); + (err.message).should.startWith("NJS-007:"); + + should.not.exist(pool); + cb(); + } + ); + } + ], done); + + }); // 73.22 + +}); diff --git a/test/random.js b/test/random.js new file mode 100644 index 00000000..b156fc1c --- /dev/null +++ b/test/random.js @@ -0,0 +1,82 @@ +/* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with the Apache + * License, Version 2.0 (the "License.") + * + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + * The node-oracledb test suite uses 'mocha', 'should' and 'async'. + * See LICENSE.md for relevant licenses. + * + * NAME + * random.js + * + * DESCRIPTION + * generate a random string which length is 'length', with specialStr + * in it's head and tail + *****************************************************************************/ +'use strict'; + +var random = exports; +module.exports = random; + +// generate a random string which length is 'length', with specialStr in it's head and tail +random.getRandomString = function(length, specialStr) { + var str=''; + var strLength = length - specialStr.length * 2; + for( ; str.length < strLength; str += Math.random().toString(36).slice(2)); + str = str.substr(0, strLength); + str = specialStr + str + specialStr; + return str; +}; + +random.getRandomLengthString = function (length) { + var str=''; + for( ; str.length < length; str += Math.random().toString(36).slice(2)); + str = str.substr(0, length); + return str; +}; + +random.getRandomNumArray = function(size) { + var numbers = new Array(size); + for (var i = 0; i < numbers.length; i++) { + numbers[i] = getRandomInt(1,9999999); + } + return numbers; +}; + +function getRandomInt(min, max) { + min = Math.ceil(min); + max = Math.floor(max); + return Math.floor(Math.random() * (max - min)) + min; +} + +random.getIntArray = function(N) { + var arr = Array.apply(null, Array(N)); + // The map() method creates a new array with the results of calling a provided function on every element in this array. + // var new_array = arr.map(callback[, thisArg]) + // Parameters + // callback + // Function that produces an element of the new Array, taking three arguments: + // currentValue + // The current element being processed in the array. + // index + // The index of the current element being processed in the array. + // array + // The array map was called upon. + // thisArg + // Optional. Value to use as this when executing callback. + // Return value + // A new array with each element being the result of the callback function. + return arr.map(function (x, i) { return i; }); +}; diff --git a/test/tree.jpg b/test/tree.jpg new file mode 100644 index 00000000..be24a926 Binary files /dev/null and b/test/tree.jpg differ