Update tests for new functionality

This commit is contained in:
Christopher Jones 2015-08-17 16:19:36 +10:00
parent 1042166e2e
commit a8b69f0c0a
20 changed files with 3462 additions and 670 deletions

View File

@ -58,20 +58,21 @@ Note: these are listed in `devDependencies` in `package.json` so `npm
install` will install them when executed inside a node-oracledb install` will install them when executed inside a node-oracledb
package directory. package directory.
### 4. Edit database credentials ### 4. Database credentials
The database credentials for node-oracledb test suite are defined in dbConfig.js file. You can set the credentials via environment variables or dbConfig.js file.
Change the credentials to a user who has privileges to connect and create tables.
``` ```
vi <some-directory>/node_modules/oracledb/test/dbConfig.js vi <some-directory>/node_modules/oracledb/test/dbConfig.js
``` ```
Change the credentials to a user who has privileges to connect and create tables:
```javascript ```javascript
module.exports = { module.exports = {
user : "hr", user : process.env.NODE_ORACLEDB_USER || "hr",
password : "welcome", password : process.env.NODE_ORACLEDB_PASSWORD || "welcome",
connectString : "localhost/orcl", connectString : process.env.NODE_ORACLEDB_CONNECTIONSTRING || "localhost/orcl",
externalAuth : false externalAuth : process.env.NODE_ORACLEDB_EXTERNALAUTH ? true : false
}; };
``` ```
@ -113,3 +114,7 @@ assigned a number. The following number ranges have been chosen:
- 1 - 20 are reserved for basic functional tests - 1 - 20 are reserved for basic functional tests
- 21 - 50 are reserved for data type supporting tests - 21 - 50 are reserved for data type supporting tests
- 51 onwards are for other tests - 51 onwards are for other tests
## Test List
See test/list.txt file for the list of existing tests.

View File

@ -31,142 +31,168 @@
* 51 - are for other tests * 51 - are for other tests
* *
*****************************************************************************/ *****************************************************************************/
"use strict";
var oracledb = require('oracledb'); var oracledb = require('oracledb');
var should = require('should'); var should = require('should');
var async = require('async'); var async = require('async');
var dbConfig = require('./dbConfig.js'); var dbConfig = require('./dbConfig.js');
describe('7. autoCommit.js', function(){ describe('7. autoCommit.js', function() {
if(dbConfig.externalAuth){ if(dbConfig.externalAuth){
var credential = { externalAuth: true, connectString: dbConfig.connectString }; var credential = { externalAuth: true, connectString: dbConfig.connectString };
} else { } else {
var credential = dbConfig; var credential = dbConfig;
} }
var connection = false; var pool = null;
var anotherConnection = false; var connection = null;
var script =
"BEGIN \ before('create pool, get one connection, create table', function(done) {
DECLARE \ var script =
e_table_exists EXCEPTION; \ "BEGIN \
PRAGMA EXCEPTION_INIT(e_table_exists, -00942); \ DECLARE \
BEGIN \ e_table_exists EXCEPTION; \
EXECUTE IMMEDIATE ('DROP TABLE oracledb_departments'); \ PRAGMA EXCEPTION_INIT(e_table_exists, -00942); \
EXCEPTION \ BEGIN \
WHEN e_table_exists \ EXECUTE IMMEDIATE ('DROP TABLE oracledb_departments'); \
THEN NULL; \ EXCEPTION \
END; \ WHEN e_table_exists \
EXECUTE IMMEDIATE (' \ THEN NULL; \
CREATE TABLE oracledb_departments ( \ END; \
department_id NUMBER, \ EXECUTE IMMEDIATE (' \
department_name VARCHAR2(20) \ CREATE TABLE oracledb_departments ( \
) \ department_id NUMBER, \
'); \ department_name VARCHAR2(20) \
END; "; ) \
'); \
beforeEach(function(done){ END; ";
oracledb.outFormat = oracledb.OBJECT;
oracledb.autoCommit = true;
async.series([ async.series([
function(callback){ function(callback) {
oracledb.getConnection(credential, function(err, conn){ oracledb.createPool(
if(err) { console.error(err.message); return; } {
connection = conn; externalAuth : credential.externalAuth,
callback(); user : credential.user,
}); password : credential.password,
}, connectString : credential.connectString,
function(callback){ poolMin : 3,
oracledb.getConnection(credential, function(err, conn){ poolMax : 7,
if(err) { console.error(err.message); return; } poolIncrement : 1
anotherConnection = conn; },
callback(); function(err, connectionPool) {
}); should.not.exist(err);
}, pool = connectionPool;
function(callback){
connection.execute(script, function(err){
if(err) { console.error(err.message); return; }
connection.commit( function(err){
if(err) { console.error(err.message); return; }
callback();
});
});
}
], done);
})
afterEach(function(done){
oracledb.outFormat = oracledb.ARRAY;
oracledb.autoCommit = false;
async.series([
function(callback){
connection.execute(
'DROP TABLE oracledb_departments',
function(err){
if(err) { console.error(err.message); return; }
callback(); callback();
} }
); );
}, },
function(callback){ function(callback) {
connection.release( function(err){ pool.getConnection( function(err, conn) {
if(err) { console.error(err.message); return; } should.not.exist(err);
connection = conn;
callback();
});
},
function(callback) {
connection.execute(
script,
function(err) {
should.not.exist(err);
callback();
}
);
}
], done);
})
after('drop table, release connection, terminate pool', function(done) {
async.series([
function(callback) {
connection.execute(
"DROP TABLE oracledb_departments",
function(err) {
should.not.exist(err);
callback();
}
);
},
function(callback) {
connection.release( function(err) {
should.not.exist(err);
callback(); callback();
}); });
}, },
function(callback){ function(callback) {
anotherConnection.release( function(err){ pool.terminate(function(err) {
if(err) { console.error(err.message); return; } should.not.exist(err);
callback(); callback();
}); });
} }
], done); ], done);
}) })
afterEach('truncate table, reset the oracledb properties', function(done) {
oracledb.autoCommit = false; /* Restore to default value */
connection.execute(
"TRUNCATE TABLE oracledb_departments",
function(err) {
should.not.exist(err);
done();
}
);
})
it('7.1 auto commit takes effect for DML - insert', function(done){ it('7.1 autoCommit takes effect when setting oracledb.autoCommit before connecting', function(done) {
var conn1 = null;
var conn2 = null;
oracledb.autoCommit = true;
async.series([ async.series([
function(callback){ function(callback) {
connection.execute( pool.getConnection(
function(err, conn) {
should.not.exist(err);
conn1 = conn;
callback();
}
);
},
function(callback) {
conn1.execute(
"INSERT INTO oracledb_departments VALUES (82, 'Security')", "INSERT INTO oracledb_departments VALUES (82, 'Security')",
function(err){ function(err) {
should.not.exist(err); should.not.exist(err);
callback(); callback();
} }
); );
}, },
function(callback){ function(callback) { // get another connection
anotherConnection.execute( pool.getConnection(
"SELECT department_id FROM oracledb_departments WHERE department_name = 'Security'", function(err, conn) {
function(err, result){ should.not.exist(err);
conn2 = conn;
callback();
}
);
},
function(callback) {
conn2.execute(
"SELECT department_id FROM oracledb_departments WHERE department_name = 'Security'",
[],
{ outFormat: oracledb.OBJECT },
function(err, result) {
should.not.exist(err); should.not.exist(err);
should.exist(result);
// console.log(result);
result.rows[0].DEPARTMENT_ID.should.eql(82).and.be.a.Number; result.rows[0].DEPARTMENT_ID.should.eql(82).and.be.a.Number;
callback(); callback();
} }
); );
}
], done);
})
it('7.2 auto commit takes effect for DML - update', function(done){
async.series([
function(callback){
connection.execute(
"INSERT INTO oracledb_departments VALUES (82, 'Security')",
function(err){
should.not.exist(err);
callback();
}
);
}, },
function(callback){ function(callback) {
connection.execute( conn1.execute(
"UPDATE oracledb_departments SET department_id = 101 WHERE department_name = 'Security'", "UPDATE oracledb_departments SET department_id = 101 WHERE department_name = 'Security'",
function(err){ function(err){
should.not.exist(err); should.not.exist(err);
@ -174,18 +200,206 @@ describe('7. autoCommit.js', function(){
} }
); );
}, },
function(callback){ function(callback) {
anotherConnection.execute( conn2.execute(
"SELECT department_id FROM oracledb_departments WHERE department_name = 'Security'", "SELECT department_id FROM oracledb_departments WHERE department_name = 'Security'",
function(err, result){ [],
{ outFormat: oracledb.OBJECT },
function(err, result) {
should.not.exist(err); should.not.exist(err);
should.exist(result);
// console.log(result);
result.rows[0].DEPARTMENT_ID.should.eql(101).and.be.a.Number; result.rows[0].DEPARTMENT_ID.should.eql(101).and.be.a.Number;
callback(); callback();
} }
); );
},
function(callback) {
conn1.release(function(err) {
should.not.exist(err);
callback();
});
},
function(callback) {
conn2.release(function(err) {
should.not.exist(err);
callback();
});
} }
], done); ], done);
}) })
it('7.2 autoCommit takes effect when setting oracledb.autoCommit after connecting', function(done) {
var conn1 = null;
var conn2 = null;
async.series([
function(callback) {
pool.getConnection(
function(err, conn) {
should.not.exist(err);
conn1 = conn;
callback();
}
);
},
function(callback) {
oracledb.autoCommit = true; // change autoCommit after connection
conn1.execute(
"INSERT INTO oracledb_departments VALUES (82, 'Security')",
function(err) {
should.not.exist(err);
callback();
}
);
},
function(callback) {
pool.getConnection(
function(err, conn) {
should.not.exist(err);
conn2 = conn;
callback();
}
);
},
function(callback) {
conn2.execute(
"SELECT department_id FROM oracledb_departments WHERE department_name = 'Security'",
[],
{ outFormat: oracledb.OBJECT },
function(err, result) {
should.not.exist(err);
result.rows[0].DEPARTMENT_ID.should.eql(82).and.be.a.Number;
callback();
}
);
},
function(callback) {
conn1.execute(
"UPDATE oracledb_departments SET department_id = 101 WHERE department_name = 'Security'",
function(err){
should.not.exist(err);
callback();
}
);
},
function(callback) {
conn2.execute(
"SELECT department_id FROM oracledb_departments WHERE department_name = 'Security'",
[],
{ outFormat: oracledb.OBJECT },
function(err, result) {
should.not.exist(err);
result.rows[0].DEPARTMENT_ID.should.eql(101).and.be.a.Number;
callback();
}
);
},
function(callback) {
conn1.release(function(err) {
should.not.exist(err);
callback();
});
},
function(callback) {
conn2.release(function(err) {
should.not.exist(err);
callback();
});
}
], done);
})
it('7.3 autoCommit setting does not affect previous SQL result', function(done) {
var conn1 = null;
var conn2 = null;
async.series([
function(callback) {
pool.getConnection(
function(err, conn) {
should.not.exist(err);
conn1 = conn;
callback();
}
);
},
function(callback) {
conn1.execute(
"INSERT INTO oracledb_departments VALUES (82, 'Security')",
function(err) {
should.not.exist(err);
callback();
}
);
},
function(callback) {
pool.getConnection(
function(err, conn) {
should.not.exist(err);
conn2 = conn;
callback();
}
);
},
function(callback) {
oracledb.autoCommit = true; // change autoCommit after connection
conn2.execute(
"SELECT department_id FROM oracledb_departments WHERE department_name = 'Security'",
[],
{ outFormat: oracledb.OBJECT },
function(err, result) {
should.not.exist(err);
(result.rows).should.eql([]);
callback();
}
);
},
function(callback) {
conn2.execute(
"INSERT INTO oracledb_departments VALUES (99, 'Marketing')",
function(err) {
should.not.exist(err);
callback();
}
);
},
function(callback) {
conn2.execute(
"SELECT COUNT(*) as amount FROM oracledb_departments",
[],
{ outFormat: oracledb.OBJECT },
function(err, result) {
should.not.exist(err);
result.rows[0].AMOUNT.should.eql(1);
callback();
}
);
},
function(callback) {
conn1.execute(
"SELECT COUNT(*) as amount FROM oracledb_departments",
[],
{ outFormat: oracledb.OBJECT },
function(err, result) {
should.not.exist(err);
result.rows[0].AMOUNT.should.eql(2); // autoCommit for SELECT
callback();
}
);
},
function(callback) {
conn1.release(function(err) {
should.not.exist(err);
callback();
});
},
function(callback) {
conn2.release(function(err) {
should.not.exist(err);
callback();
});
}
], done);
})
}) })

View File

@ -47,318 +47,644 @@ describe('4. binding.js', function() {
var credential = dbConfig; var credential = dbConfig;
} }
var connection = false; describe('4.1 test STRING, NUMBER, ARRAY & JSON format', function() {
beforeEach(function(done) { var connection = null;
oracledb.getConnection(credential, function(err, conn) { before(function(done) {
if(err) { console.error(err.message); return; } oracledb.getConnection(credential, function(err, conn) {
connection = conn; if(err) { console.error(err.message); return; }
done(); connection = conn;
}); done();
}) });
})
afterEach(function(done) { after(function(done) {
connection.release( function(err) { connection.release( function(err) {
if(err) { console.error(err.message); return; } if(err) { console.error(err.message); return; }
done(); done();
}); });
}) })
it('4.1.1 VARCHAR2 binding, Object & Array formats', function(done) {
it('4.1 VARCHAR2 binding, Object & Array formats', function(done) { async.series([
async.series([ function(callback) {
function(callback) { var proc = "CREATE OR REPLACE PROCEDURE oracledb_testproc (p_out OUT VARCHAR2) \
var proc = "CREATE OR REPLACE PROCEDURE oracledb_testproc (p_out OUT VARCHAR2) \
AS \
BEGIN \
p_out := 'abcdef'; \
END;";
connection.should.be.ok;
connection.execute(
proc,
function(err) {
should.not.exist(err);
callback();
}
);
},
function(callback) {
connection.execute(
"BEGIN oracledb_testproc(:o); END;",
{
o: { type: oracledb.STRING, dir: oracledb.BIND_OUT }
},
function(err, result) {
should.not.exist(err);
// console.log(result);
result.outBinds.o.should.be.exactly('abcdef');
callback();
}
);
},
function(callback) {
connection.execute(
"BEGIN oracledb_testproc(:o); END;",
[
{ type: oracledb.STRING, dir: oracledb.BIND_OUT }
],
function(err, result) {
should.not.exist(err);
// console.log(result);
result.outBinds.should.be.eql(['abcdef']);
callback();
}
);
},
function(callback) {
connection.execute(
"DROP PROCEDURE oracledb_testproc",
function(err) {
should.not.exist(err);
callback();
}
);
}
], done);
})
it('4.2 NUMBER binding, Object & Array formats', function(done) {
async.series([
function(callback) {
var proc = "CREATE OR REPLACE PROCEDURE oracledb_testproc (p_out OUT NUMBER) \
AS \
BEGIN \
p_out := 10010; \
END;";
connection.should.be.ok;
connection.execute(
proc,
function(err) {
should.not.exist(err);
callback();
}
);
},
function(callback) {
connection.execute(
"BEGIN oracledb_testproc(:o); END;",
{
o: { type: oracledb.NUMBER, dir: oracledb.BIND_OUT }
},
function(err, result) {
should.not.exist(err);
// console.log(result);
result.outBinds.o.should.be.exactly(10010);
callback();
}
);
},
function(callback) {
connection.execute(
"BEGIN oracledb_testproc(:o); END;",
[
{ type: oracledb.NUMBER, dir: oracledb.BIND_OUT }
],
function(err, result) {
should.not.exist(err);
// console.log(result);
result.outBinds.should.be.eql([ 10010 ]);
callback();
}
);
},
function(callback) {
connection.execute(
"DROP PROCEDURE oracledb_testproc",
function(err) {
should.not.exist(err);
callback();
}
);
}
], done);
})
it('4.3 Multiple binding values, Object & Array formats', function(done) {
async.series([
function(callback) {
var proc = "CREATE OR REPLACE PROCEDURE oracledb_testproc (p_in IN VARCHAR2, p_inout IN OUT VARCHAR2, p_out OUT NUMBER) \
AS \ AS \
BEGIN \ BEGIN \
p_inout := p_in || ' ' || p_inout; \ p_out := 'abcdef'; \
p_out := 101; \ END;";
END; "; connection.should.be.ok;
connection.should.be.ok; connection.execute(
connection.execute( proc,
proc, function(err) {
function(err) { should.not.exist(err);
should.not.exist(err); callback();
callback(); }
} );
); },
}, function(callback) {
function(callback) { connection.execute(
connection.execute( "BEGIN oracledb_testproc(:o); END;",
"BEGIN oracledb_testproc(:i, :io, :o); END;", {
{ o: { type: oracledb.STRING, dir: oracledb.BIND_OUT }
i: 'Alan', // bind type is determined from the data type },
io: { val: 'Turing', dir : oracledb.BIND_INOUT }, function(err, result) {
o: { type: oracledb.NUMBER, dir : oracledb.BIND_OUT } should.not.exist(err);
}, // console.log(result);
function(err, result) { result.outBinds.o.should.be.exactly('abcdef');
should.not.exist(err); callback();
// console.log(result); }
result.outBinds.io.should.be.exactly('Alan Turing'); );
callback(); },
} function(callback) {
); connection.execute(
}, "BEGIN oracledb_testproc(:o); END;",
function(callback) { [
connection.execute( { type: oracledb.STRING, dir: oracledb.BIND_OUT }
"BEGIN oracledb_testproc(:i, :io, :o); END;", ],
[ function(err, result) {
'Alan', // bind type is determined from the data type should.not.exist(err);
{ val: 'Turing', dir : oracledb.BIND_INOUT }, // console.log(result);
{ type: oracledb.NUMBER, dir : oracledb.BIND_OUT } result.outBinds.should.be.eql(['abcdef']);
], callback();
function(err, result) { }
should.not.exist(err); );
// console.log(result); },
result.outBinds.should.be.eql([ 'Alan Turing', 101 ]); function(callback) {
callback(); connection.execute(
} "DROP PROCEDURE oracledb_testproc",
); function(err) {
}, should.not.exist(err);
function(callback) { callback();
connection.execute( }
"DROP PROCEDURE oracledb_testproc", );
function(err) { }
should.not.exist(err); ], done);
callback(); })
}
);
}
], done);
})
it('4.4 Multiple binding values, Change binding order', function(done) {
async.series([
function(callback) {
var proc = "CREATE OR REPLACE PROCEDURE oracledb_testproc (p_inout IN OUT VARCHAR2, p_out OUT NUMBER, p_in IN VARCHAR2) \
AS \
BEGIN \
p_inout := p_in || ' ' || p_inout; \
p_out := 101; \
END; ";
connection.should.be.ok;
connection.execute(
proc,
function(err) {
should.not.exist(err);
callback();
}
);
},
function(callback) {
connection.execute(
"BEGIN oracledb_testproc(:io, :o, :i); END;",
{
i: 'Alan', // bind type is determined from the data type
io: { val: 'Turing', dir : oracledb.BIND_INOUT },
o: { type: oracledb.NUMBER, dir : oracledb.BIND_OUT }
},
function(err, result) {
should.not.exist(err);
// console.log(result);
result.outBinds.io.should.be.exactly('Alan Turing');
callback();
}
);
},
function(callback) {
connection.execute(
"BEGIN oracledb_testproc(:io, :o, :i); END;",
[
{ val: 'Turing', dir : oracledb.BIND_INOUT },
{ type: oracledb.NUMBER, dir : oracledb.BIND_OUT },
'Alan', // bind type is determined from the data type
],
function(err, result) {
should.not.exist(err);
// console.log(result);
result.outBinds.should.be.eql([ 'Alan Turing', 101 ]);
callback();
}
);
},
function(callback) {
connection.execute(
"DROP PROCEDURE oracledb_testproc",
function(err) {
should.not.exist(err);
callback();
}
);
}
], done);
})
it('4.5 outBind & maxSize restriction', function(done) {
async.series([
function(callback) {
var proc = "CREATE OR REPLACE PROCEDURE oracledb_testproc (p_out OUT VARCHAR2) \
AS \
BEGIN \
p_out := 'ABCDEF GHIJK LMNOP QRSTU'; \
END;";
connection.should.be.ok;
connection.execute(
proc,
function(err) {
should.not.exist(err);
callback();
}
);
},
function(callback) {
connection.execute(
"BEGIN oracledb_testproc(:o); END;",
{
o: { type: oracledb.STRING, dir: oracledb.BIND_OUT, maxSize:2 }
},
function(err, result) {
should.exist(err);
// console.log(err.message);
err.message.should.startWith('ORA-06502:');
// console.log(result);
callback();
}
);
},
function(callback) {
connection.execute(
"BEGIN oracledb_testproc(:o); END;",
[
{ type: oracledb.STRING, dir: oracledb.BIND_OUT, maxSize:3 }
],
function(err, result) {
should.exist(err);
// console.log(err.message);
err.message.should.startWith('ORA-06502:');
// console.log(result);
callback();
}
);
},
function(callback) {
connection.execute(
"DROP PROCEDURE oracledb_testproc",
function(err) {
should.not.exist(err);
callback();
}
);
}
], done);
})
it('4.1.2 NUMBER binding, Object & Array formats', function(done) {
async.series([
function(callback) {
var proc = "CREATE OR REPLACE PROCEDURE oracledb_testproc (p_out OUT NUMBER) \
AS \
BEGIN \
p_out := 10010; \
END;";
connection.should.be.ok;
connection.execute(
proc,
function(err) {
should.not.exist(err);
callback();
}
);
},
function(callback) {
connection.execute(
"BEGIN oracledb_testproc(:o); END;",
{
o: { type: oracledb.NUMBER, dir: oracledb.BIND_OUT }
},
function(err, result) {
should.not.exist(err);
// console.log(result);
result.outBinds.o.should.be.exactly(10010);
callback();
}
);
},
function(callback) {
connection.execute(
"BEGIN oracledb_testproc(:o); END;",
[
{ type: oracledb.NUMBER, dir: oracledb.BIND_OUT }
],
function(err, result) {
should.not.exist(err);
// console.log(result);
result.outBinds.should.be.eql([ 10010 ]);
callback();
}
);
},
function(callback) {
connection.execute(
"DROP PROCEDURE oracledb_testproc",
function(err) {
should.not.exist(err);
callback();
}
);
}
], done);
})
it('4.1.3 Multiple binding values, Object & Array formats', function(done) {
async.series([
function(callback) {
var proc = "CREATE OR REPLACE PROCEDURE oracledb_testproc (p_in IN VARCHAR2, p_inout IN OUT VARCHAR2, p_out OUT NUMBER) \
AS \
BEGIN \
p_inout := p_in || ' ' || p_inout; \
p_out := 101; \
END; ";
connection.should.be.ok;
connection.execute(
proc,
function(err) {
should.not.exist(err);
callback();
}
);
},
function(callback) {
connection.execute(
"BEGIN oracledb_testproc(:i, :io, :o); END;",
{
i: 'Alan', // bind type is determined from the data type
io: { val: 'Turing', dir : oracledb.BIND_INOUT },
o: { type: oracledb.NUMBER, dir : oracledb.BIND_OUT }
},
function(err, result) {
should.not.exist(err);
// console.log(result);
result.outBinds.io.should.be.exactly('Alan Turing');
callback();
}
);
},
function(callback) {
connection.execute(
"BEGIN oracledb_testproc(:i, :io, :o); END;",
[
'Alan', // bind type is determined from the data type
{ val: 'Turing', dir : oracledb.BIND_INOUT },
{ type: oracledb.NUMBER, dir : oracledb.BIND_OUT }
],
function(err, result) {
should.not.exist(err);
// console.log(result);
result.outBinds.should.be.eql([ 'Alan Turing', 101 ]);
callback();
}
);
},
function(callback) {
connection.execute(
"DROP PROCEDURE oracledb_testproc",
function(err) {
should.not.exist(err);
callback();
}
);
}
], done);
})
it('4.1.4 Multiple binding values, Change binding order', function(done) {
async.series([
function(callback) {
var proc = "CREATE OR REPLACE PROCEDURE oracledb_testproc (p_inout IN OUT VARCHAR2, p_out OUT NUMBER, p_in IN VARCHAR2) \
AS \
BEGIN \
p_inout := p_in || ' ' || p_inout; \
p_out := 101; \
END; ";
connection.should.be.ok;
connection.execute(
proc,
function(err) {
should.not.exist(err);
callback();
}
);
},
function(callback) {
connection.execute(
"BEGIN oracledb_testproc(:io, :o, :i); END;",
{
i: 'Alan', // bind type is determined from the data type
io: { val: 'Turing', dir : oracledb.BIND_INOUT },
o: { type: oracledb.NUMBER, dir : oracledb.BIND_OUT }
},
function(err, result) {
should.not.exist(err);
// console.log(result);
result.outBinds.io.should.be.exactly('Alan Turing');
callback();
}
);
},
function(callback) {
connection.execute(
"BEGIN oracledb_testproc(:io, :o, :i); END;",
[
{ val: 'Turing', dir : oracledb.BIND_INOUT },
{ type: oracledb.NUMBER, dir : oracledb.BIND_OUT },
'Alan', // bind type is determined from the data type
],
function(err, result) {
should.not.exist(err);
// console.log(result);
result.outBinds.should.be.eql([ 'Alan Turing', 101 ]);
callback();
}
);
},
function(callback) {
connection.execute(
"DROP PROCEDURE oracledb_testproc",
function(err) {
should.not.exist(err);
callback();
}
);
}
], done);
})
it('4.1.5 default bind type - STRING', function(done) {
connection.should.be.ok;
var sql = "begin :n := 1001; end;";
var bindVar = { n : { dir: oracledb.BIND_OUT } };
var options = { };
connection.execute(
sql,
bindVar,
options,
function(err, result) {
should.not.exist(err);
// console.log(result);
result.outBinds.n.should.be.a.String;
result.outBinds.n.should.eql('1001');
done();
}
);
})
})
describe('4.2 mixing named with positional binding', function() {
var connection = null;
var createTable =
"BEGIN \
DECLARE \
e_table_exists EXCEPTION; \
PRAGMA EXCEPTION_INIT(e_table_exists, -00942); \
BEGIN \
EXECUTE IMMEDIATE ('DROP TABLE oracledb_binding'); \
EXCEPTION \
WHEN e_table_exists \
THEN NULL; \
END; \
EXECUTE IMMEDIATE (' \
CREATE TABLE oracledb_binding ( \
id NUMBER(4), \
name VARCHAR2(32) \
) \
'); \
END; ";
var insert = 'insert into oracledb_binding (id, name) values (:0, :1) returning id into :2';
var param1 = [ 1, 'changjie', { type: oracledb.NUMBER, dir: oracledb.BIND_OUT } ];
var param2 = [ 2, 'changjie', { ignored_name: { type: oracledb.NUMBER, dir: oracledb.BIND_OUT } } ];
var options = { autoCommit: true, outFormat: oracledb.OBJECT };
beforeEach(function(done) {
oracledb.getConnection(credential, function(err, conn) {
should.not.exist(err);
connection = conn;
conn.execute(
createTable,
function(err) {
should.not.exist(err);
done();
}
);
});
})
afterEach(function(done) {
connection.should.be.ok;
connection.execute(
"DROP TABLE oracledb_binding",
function(err) {
should.not.exist(err);
connection.release(function(err) {
should.not.exist(err);
done();
});
}
);
})
it('4.2.1 array binding is ok', function(done) {
connection.execute(
insert,
param1,
options,
function(err, result) {
should.not.exist(err);
result.rowsAffected.should.be.exactly(1);
result.outBinds[0].should.eql([1]);
// console.log(result);
connection.execute(
"SELECT * FROM oracledb_binding",
[],
options,
function(err, result) {
should.not.exist(err);
//console.log(result);
result.rows[0].ID.should.be.exactly(1);
result.rows[0].NAME.should.eql('changjie');
done();
}
);
}
);
})
it.skip('4.2.2 array binding with mixing JSON should throw an error', function(done) {
connection.execute(
insert,
param2,
options,
function(err, result) {
should.exist(err); // pending to fix
result.rowsAffected.should.be.exactly(1);
//result.outBinds[0].should.eql([1]);
//console.log(result);
connection.execute(
"SELECT * FROM oracledb_binding",
[],
options,
function(err, result) {
should.not.exist(err);
//console.log(result);
result.rows[0].ID.should.be.exactly(2);
result.rows[0].NAME.should.eql('changjie');
done();
}
);
}
);
})
})
describe('4.3 insert with DATE column and DML returning', function(done) {
var connection = null;
var createTable =
"BEGIN \
DECLARE \
e_table_exists EXCEPTION; \
PRAGMA EXCEPTION_INIT(e_table_exists, -00942); \
BEGIN \
EXECUTE IMMEDIATE ('DROP TABLE oracledb_binding'); \
EXCEPTION \
WHEN e_table_exists \
THEN NULL; \
END; \
EXECUTE IMMEDIATE (' \
CREATE TABLE oracledb_binding ( \
num NUMBER(4), \
str VARCHAR2(32), \
dt DATE \
) \
'); \
END; ";
beforeEach(function(done) {
oracledb.getConnection(credential, function(err, conn) {
should.not.exist(err);
connection = conn;
conn.execute(
createTable,
function(err) {
should.not.exist(err);
done();
}
);
});
})
afterEach(function(done) {
connection.should.be.ok;
connection.execute(
"DROP TABLE oracledb_binding",
function(err) {
should.not.exist(err);
connection.release(function(err) {
should.not.exist(err);
done();
});
}
);
})
var insert1 = 'insert into oracledb_binding (num, str, dt) values (:0, :1, :2)';
var insert2 = 'insert into oracledb_binding (num, str, dt) values (:0, :1, :2) returning num into :3';
var param1 = { 0: 123, 1: 'str', 2: new Date() };
var param2 = { 0: 123, 1: 'str', 2: new Date(), 3: { type: oracledb.NUMBER, dir: oracledb.BIND_OUT } };
var param3 = [ 123, 'str', new Date() ];
var param4 = [ 123, 'str', new Date(), { type: oracledb.NUMBER, dir: oracledb.BIND_OUT } ];
var options = { autoCommit: true };
it('4.3.1 passes in object syntax without returning into', function(done) {
connection.execute(
insert1,
param1,
options,
function(err, result) {
should.not.exist(err);
result.rowsAffected.should.be.exactly(1);
connection.execute(
"SELECT * FROM oracledb_binding",
[],
options,
function(err, result) {
should.not.exist(err);
// console.log(result);
done();
}
);
}
);
})
it('4.3.2 passes in object syntax with returning into', function(done) {
connection.execute(
insert2,
param2,
options,
function(err, result) {
should.not.exist(err);
result.rowsAffected.should.be.exactly(1);
//console.log(result);
result.outBinds.should.eql({ '3': [123] });
connection.execute(
"SELECT * FROM oracledb_binding",
[],
options,
function(err, result) {
should.not.exist(err);
// console.log(result);
done();
}
);
}
);
})
it('4.3.3 passes in array syntax without returning into', function(done) {
connection.execute(
insert1,
param3,
options,
function(err, result) {
should.not.exist(err);
result.rowsAffected.should.be.exactly(1);
// console.log(result);
connection.execute(
"SELECT * FROM oracledb_binding",
[],
options,
function(err, result) {
should.not.exist(err);
// console.log(result);
done();
}
);
}
);
})
it ('4.3.4 should pass but fail in array syntax with returning into', function(done) {
connection.execute(
insert2,
param4,
options,
function(err, result) {
should.not.exist(err);
result.rowsAffected.should.be.exactly(1);
// console.log(result);
result.outBinds[0].should.eql([123]);
connection.execute(
"SELECT * FROM oracledb_binding",
[],
options,
function(err, result) {
should.not.exist(err);
// console.log(result);
done();
}
);
}
);
})
})
describe('4.4 test maxSize option', function() {
var connection = null;
before(function(done) {
oracledb.getConnection(credential, 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('4.4.1 outBind & maxSize restriction', function(done) {
async.series([
function(callback) {
var proc = "CREATE OR REPLACE PROCEDURE oracledb_testproc (p_out OUT VARCHAR2) \
AS \
BEGIN \
p_out := 'ABCDEF GHIJK LMNOP QRSTU'; \
END;";
connection.should.be.ok;
connection.execute(
proc,
function(err) {
should.not.exist(err);
callback();
}
);
},
function(callback) {
connection.execute(
"BEGIN oracledb_testproc(:o); END;",
{
o: { type: oracledb.STRING, dir: oracledb.BIND_OUT, maxSize:2 }
},
function(err, result) {
should.exist(err);
// console.log(err.message);
err.message.should.startWith('ORA-06502:'); // ORA-06502: PL/SQL: numeric or value error: character string buffer too small
// console.log(result);
callback();
}
);
},
function(callback) {
connection.execute(
"BEGIN oracledb_testproc(:o); END;",
[
{ type: oracledb.STRING, dir: oracledb.BIND_OUT, maxSize:22 }
],
function(err, result) {
should.exist(err);
// console.log(err.message);
err.message.should.startWith('ORA-06502:');
// console.log(result);
callback();
}
);
},
function(callback) {
connection.execute(
"DROP PROCEDURE oracledb_testproc",
function(err) {
should.not.exist(err);
callback();
}
);
}
], done);
})
it.skip('4.4.2 default value is 200', function(done) {
connection.execute(
"BEGIN :o := lpad('A',201,'x'); END;",
{ o: { type: oracledb.STRING, dir : oracledb.BIND_OUT } },
function (err, result) {
should.exist(err);
err.message.should.startWith('ORA-06502:');
console.log(result.outBinds.o.length);
done();
}
);
})
it.skip('4.4.3 maximum value is 32767', function(done) {
connection.execute(
"BEGIN :o := lpad('A',32767,'x'); END;",
{ o: { type: oracledb.STRING, dir : oracledb.BIND_OUT, maxSize:50000 } },
function(err, result) {
should.exist(err);
console.log(result.outBinds.o.length);
done();
}
);
})
})
}) })

5
test/clobexample.txt Normal file
View File

@ -0,0 +1,5 @@
This is example text used for node-oracledb CLOB examples.
The Oracle Database Node.js driver powers high performance Node.js applications.
The node-oracledb home page is at http://www.oracle.com/technetwork/database/database-technologies/node_js/index.html

View File

@ -258,7 +258,7 @@ describe('9. columnMetadata.js', function(){
], done); ], done);
}) })
it('9.8 only works for SELECT statament, does not work for INSERT', function(done){ it('9.8 only works for SELECT statement, does not work for INSERT', function(done){
connection.should.be.ok; connection.should.be.ok;
connection.execute( connection.execute(
"INSERT INTO oracledb_departments VALUES (99, 'FACILITY', 456, 1700)", "INSERT INTO oracledb_departments VALUES (99, 'FACILITY', 456, 1700)",

View File

@ -141,7 +141,7 @@ describe('1. connection.js', function(){
); );
}) })
it('1.1.4 Negatve test - invalid outFormat value', function(done){ it('1.1.4 Negative test - invalid outFormat value', function(done){
connection.should.be.ok; connection.should.be.ok;
connection.execute( connection.execute(
query, {id: 20}, {outFormat:0 }, query, {id: 20}, {outFormat:0 },
@ -186,6 +186,7 @@ describe('1. connection.js', function(){
INSERT INTO oracledb_employees VALUES (x, n); \ INSERT INTO oracledb_employees VALUES (x, n); \
END LOOP; \ END LOOP; \
END; "; END; ";
var rowsAmount = 107;
before(function(done){ before(function(done){
oracledb.getConnection(credential, function(err, conn) { oracledb.getConnection(credential, function(err, conn) {
@ -274,6 +275,19 @@ describe('1. connection.js', function(){
} }
); );
}) })
it('1.2.5 sets maxRows to be very large value', function(done) {
connection.execute(
"SELECT * FROM oracledb_employees",
{},
{maxRows: 500000},
function(err, result){
should.not.exist(err);
(result.rows.length).should.eql(rowsAmount);
done();
}
);
})
}) })
describe('1.3 can call PL/SQL procedures', function(){ describe('1.3 can call PL/SQL procedures', function(){
@ -309,7 +323,7 @@ describe('1. connection.js', function(){
); );
}) })
it('bind parameters in various ways', function(done){ it('1.3.1 bind parameters in various ways', function(done){
var bindValues = { var bindValues = {
i: 'Alan', // default is type STRING and direction Infinity i: 'Alan', // default is type STRING and direction Infinity
io: { val: 'Turing', type: oracledb.STRING, dir: oracledb.BIND_INOUT }, io: { val: 'Turing', type: oracledb.STRING, dir: oracledb.BIND_INOUT },
@ -329,9 +343,7 @@ describe('1. connection.js', function(){
}) })
}) })
describe('1.4 stmtCacheSize = 0, which disable statement caching', function() { describe('1.4 statementCacheSize controls statement caching', function() {
var connection = false;
var makeTable = var makeTable =
"BEGIN \ "BEGIN \
DECLARE \ DECLARE \
@ -364,12 +376,12 @@ describe('1. connection.js', function(){
VALUES \ VALUES \
(2001, ''Karen Morton'') \ (2001, ''Karen Morton'') \
'); \ '); \
END; "; END; ";
var connection = false;
var defaultStmtCache = oracledb.stmtCacheSize; // 30 var defaultStmtCache = oracledb.stmtCacheSize; // 30
before('get connection and prepare table', function(done) { beforeEach('get connection and prepare table', function(done) {
oracledb.stmtCacheSize = 0;
oracledb.getConnection(credential, function(err, conn) { oracledb.getConnection(credential, function(err, conn) {
if(err) { console.error(err.message); return; } if(err) { console.error(err.message); return; }
connection = conn; connection = conn;
@ -383,7 +395,7 @@ describe('1. connection.js', function(){
}); });
}) })
after('drop table and release connection', function(done) { afterEach('drop table and release connection', function(done) {
oracledb.stmtCacheSize = defaultStmtCache; oracledb.stmtCacheSize = defaultStmtCache;
connection.execute( connection.execute(
"DROP TABLE oracledb_employees", "DROP TABLE oracledb_employees",
@ -396,10 +408,51 @@ describe('1. connection.js', function(){
} }
); );
}) })
it('works well when statement cache disabled', function(done) { it('1.4.1 stmtCacheSize = 0, which disable statement caching', function(done) {
connection.should.be.ok; connection.should.be.ok;
(oracledb.stmtCacheSize).should.be.exactly(0); oracledb.stmtCacheSize = 0;
async.series([
function(callback) {
connection.execute(
"INSERT INTO oracledb_employees VALUES (:num, :str)",
{ num: 1003, str: 'Robyn Sands' },
{ autoCommit: true },
function(err) {
should.not.exist(err);
callback();
}
);
},
function(callback) {
connection.execute(
"INSERT INTO oracledb_employees VALUES (:num, :str)",
{ num: 1004, str: 'Bryant Lin' },
{ autoCommit: true },
function(err) {
should.not.exist(err);
callback();
}
);
},
function(callback) {
connection.execute(
"INSERT INTO oracledb_employees VALUES (:num, :str)",
{ num: 1005, str: 'Patrick Engebresson' },
{ autoCommit: true },
function(err) {
should.not.exist(err);
callback();
}
);
}
], done);
})
it('1.4.2 works well when statement cache enabled (stmtCacheSize > 0) ', function(done) {
connection.should.be.ok;
oracledb.stmtCacheSize = 100;
async.series([ async.series([
function(callback) { function(callback) {
@ -437,11 +490,10 @@ describe('1. connection.js', function(){
} }
], done); ], done);
}) })
}) })
describe('1.5 stmtCacheSize > 0', function() { describe('1.5 Testing commit() & rollback() functions', function() {
var connection = false;
var makeTable = var makeTable =
"BEGIN \ "BEGIN \
DECLARE \ DECLARE \
@ -462,83 +514,39 @@ describe('1. connection.js', function(){
EXECUTE IMMEDIATE (' \ EXECUTE IMMEDIATE (' \
INSERT INTO oracledb_employees \ INSERT INTO oracledb_employees \
VALUES \ VALUES \
(1001,''Chris Jones'') \ (1001,''Tom Kyte'') \
'); \ '); \
EXECUTE IMMEDIATE (' \ EXECUTE IMMEDIATE (' \
INSERT INTO oracledb_employees \ INSERT INTO oracledb_employees \
VALUES \ VALUES \
(1002,''Tom Kyte'') \ (1002, ''Karen Morton'') \
'); \ '); \
EXECUTE IMMEDIATE (' \ END; ";
INSERT INTO oracledb_employees \
VALUES \
(2001, ''Karen Morton'') \
'); \
END; ";
var defaultStmtCache = oracledb.stmtCacheSize; // 30 var conn1 = false;
var conn2 = false;
before('get connection and prepare table', function(done) { beforeEach('get 2 connections and create the table', function(done) {
oracledb.stmtCacheSize = 100;
oracledb.getConnection(credential, function(err, conn) {
if(err) { console.error(err.message); return; }
connection = conn;
conn.execute(
makeTable,
function(err){
if(err) { console.error(err.message); return; }
done();
}
);
});
})
after('drop table and release connection', function(done) {
oracledb.stmtCacheSize = defaultStmtCache;
connection.execute(
"DROP TABLE oracledb_employees",
function(err){
if(err) { console.error(err.message); return; }
connection.release( function(err){
if(err) { console.error(err.message); return; }
done();
});
}
);
})
it('works well when statement cache enabled', function(done) {
connection.should.be.ok;
(oracledb.stmtCacheSize).should.be.exactly(100);
async.series([ async.series([
function(callback) { function(callback) {
connection.execute( oracledb.getConnection(credential, function(err, conn) {
"INSERT INTO oracledb_employees VALUES (:num, :str)", should.not.exist(err);
{ num: 1003, str: 'Robyn Sands' }, conn1 = conn;
{ autoCommit: true }, callback();
function(err) { });
should.not.exist(err);
callback();
}
);
}, },
function(callback) { function(callback) {
connection.execute( oracledb.getConnection(credential, function(err, conn) {
"INSERT INTO oracledb_employees VALUES (:num, :str)", should.not.exist(err);
{ num: 1004, str: 'Bryant Lin' }, conn2 = conn;
{ autoCommit: true }, callback();
function(err) { });
should.not.exist(err);
callback();
}
);
}, },
function(callback) { function(callback) {
connection.execute( conn1.should.be.ok;
"INSERT INTO oracledb_employees VALUES (:num, :str)", conn1.execute(
{ num: 1005, str: 'Patrick Engebresson' }, makeTable,
{ autoCommit: true }, [],
{ autoCommit: true },
function(err) { function(err) {
should.not.exist(err); should.not.exist(err);
callback(); callback();
@ -547,6 +555,138 @@ describe('1. connection.js', function(){
} }
], done); ], done);
}) })
afterEach('drop table and release connections', function(done) {
conn1.should.be.ok;
conn2.should.be.ok;
async.series([
function(callback) {
conn2.execute(
"DROP TABLE oracledb_employees",
function(err) {
should.not.exist(err);
callback();
}
);
},
function(callback) {
conn1.release(function(err) {
should.not.exist(err);
callback();
});
},
function(callback) {
conn2.release(function(err) {
should.not.exist(err);
callback();
});
}
], done);
})
it('1.5.1 commit() function works well', function(done) {
async.series([
function(callback) {
conn2.execute(
"INSERT INTO oracledb_employees VALUES (:num, :str)",
{ num: 1003, str: 'Patrick Engebresson' },
function(err) {
should.not.exist(err);
callback();
}
);
},
function(callback) {
conn1.execute(
"SELECT COUNT(*) FROM oracledb_employees",
function(err, result) {
should.not.exist(err);
result.rows[0][0].should.be.exactly(2);
callback();
}
);
},
function(callback) {
conn2.execute(
"SELECT COUNT(*) FROM oracledb_employees",
function(err, result) {
should.not.exist(err);
result.rows[0][0].should.be.exactly(3);
callback();
}
);
},
function(callback) {
conn2.commit(function(err) {
should.not.exist(err);
callback();
});
},
function(callback) {
conn1.execute(
"SELECT COUNT(*) FROM oracledb_employees",
function(err, result) {
should.not.exist(err);
result.rows[0][0].should.be.exactly(3);
callback();
}
);
},
], done);
})
it('1.5.2 rollback() function works well', function(done) {
async.series([
function(callback) {
conn2.execute(
"INSERT INTO oracledb_employees VALUES (:num, :str)",
{ num: 1003, str: 'Patrick Engebresson' },
function(err) {
should.not.exist(err);
callback();
}
);
},
function(callback) {
conn1.execute(
"SELECT COUNT(*) FROM oracledb_employees",
function(err, result) {
should.not.exist(err);
result.rows[0][0].should.be.exactly(2);
callback();
}
);
},
function(callback) {
conn2.execute(
"SELECT COUNT(*) FROM oracledb_employees",
function(err, result) {
should.not.exist(err);
result.rows[0][0].should.be.exactly(3);
callback();
}
);
},
function(callback) {
conn2.rollback(function(err) {
should.not.exist(err);
callback();
});
},
function(callback) {
conn2.execute(
"SELECT COUNT(*) FROM oracledb_employees",
function(err, result) {
should.not.exist(err);
result.rows[0][0].should.be.exactly(2);
callback();
}
);
},
], done);
})
}) })
}) })

242
test/dataTypeBlob.js Normal file
View File

@ -0,0 +1,242 @@
/* Copyright (c) 2015, 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
* 41. dataTypeBlob.js
*
* DESCRIPTION
* Testing Oracle data type support - BLOB.
* This test corresponds to example files:
* blobinsert1.js, blobstream1.js and blobstream2.js
* Firstly, Loads an image data and INSERTs it into a BLOB column.
* Secondly, SELECTs the BLOB and pipes it to a file, blobstreamout.jpg
* Thirdly, SELECTs the BLOB and compares it with the original image
*
* 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
*
*****************************************************************************/
var oracledb = require('oracledb');
var fs = require('fs');
var async = require('async');
var should = require('should');
var dbConfig = require('./dbConfig.js');
var assist = require('./dataTypeAssist.js');
var inFileName = './test/fuzzydinosaur.jpg'; // contains the image to be inserted
var outFileName = './test/blobstreamout.jpg';
describe('41. dataTypeBlob', function() {
if(dbConfig.externalAuth){
var credential = { externalAuth: true, connectString: dbConfig.connectString };
} else {
var credential = dbConfig;
}
var connection = null;
var tableName = "oracledb_myblobs";
var sqlCreate =
"BEGIN " +
" DECLARE " +
" e_table_exists EXCEPTION; " +
" PRAGMA EXCEPTION_INIT(e_table_exists, -00942); " +
" BEGIN " +
" EXECUTE IMMEDIATE ('DROP TABLE " + tableName + " '); " +
" EXCEPTION " +
" WHEN e_table_exists " +
" THEN NULL; " +
" END; " +
" EXECUTE IMMEDIATE (' " +
" CREATE TABLE " + tableName +" ( " +
" num NUMBER, " +
" content BLOB " +
" )" +
" '); " +
"END; ";
before(function(done) {
oracledb.getConnection(credential, function(err, conn) {
if(err) { console.error(err.message); return; }
connection = conn;
conn.execute(
sqlCreate,
function(err) {
if(err) { console.error(err.message); return; }
done();
}
);
});
})
after( function(done){
connection.execute(
"DROP table " + tableName,
function(err) {
if(err) { console.error(err.message); return; }
connection.release( function(err) {
if(err) { console.error(err.message); return; }
done();
});
}
);
})
it('41.1 processes null value correctly', function(done) {
assist.nullValueSupport(connection, tableName, done);
})
it('41.2 stores BLOB value correctly', function(done) {
connection.should.be.ok;
async.series([
function blobinsert1(callback) {
var streamEndEventFired = false;
setTimeout( function() {
streamEndEventFired.should.equal(true, "inStream does not call 'end' event!")
callback();
}, 500);
connection.execute(
"INSERT INTO oracledb_myblobs (num, content) VALUES (:n, EMPTY_BLOB()) RETURNING content INTO :lobbv",
{ n: 2, lobbv: {type: oracledb.BLOB, dir: oracledb.BIND_OUT} },
{ 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);
inStream.on('error', function(err) {
should.not.exist(err, "inStream.on 'end' event");
});
inStream.on('end', function() {
streamEndEventFired = true;
// now commit updates
connection.commit( function(err) {
should.not.exist(err);
});
});
var lob = result.outBinds.lobbv[0];
lob.on('error', function(err) {
should.not.exist(err, "lob.on 'error' event");
});
inStream.pipe(lob); // pipes the data to the BLOB
}
);
},
function blobstream1(callback) {
var streamFinishEventFired = false;
setTimeout( function() {
streamFinishEventFired.should.equal(true, "stream does not call 'finish' Event!");
callback();
}, 500);
connection.execute(
"SELECT content FROM oracledb_myblobs WHERE num = :n",
{ n: 2 },
function(err, result) {
should.not.exist(err);
var lob = result.rows[0][0];
should.exist(lob);
lob.on('error', function(err) {
should.not.exist(err, "lob.on 'end' event");
});
var outStream = fs.createWriteStream(outFileName);
outStream.on('error', function(err) {
should.not.exist(err, "outStream.on 'end' event");
});
lob.pipe(outStream);
outStream.on('finish', function() {
fs.readFile( inFileName, function(err, originalData) {
should.not.exist(err);
fs.readFile( outFileName, function(err, generatedData) {
should.not.exist(err);
originalData.should.eql(generatedData);
streamFinishEventFired = true;
});
});
}); // finish event
}
);
},
function blobstream2(callback) {
var lobEndEventFired = false;
var lobDataEventFired = false;
setTimeout( function(){
lobDataEventFired.should.equal(true, "lob does not call 'data' event!");
lobEndEventFired.should.equal(true, "lob does not call 'end' event!");
callback();
}, 500);
connection.execute(
"SELECT content FROM oracledb_myblobs WHERE num = :n",
{ n: 2 },
function(err, result) {
should.not.exist(err);
var blob = Buffer(0);
var blobLength = 0;
var lob = result.rows[0][0];
should.exist(lob);
lob.on('error', function(err) {
should.not.exist(err, "lob.on 'end' event");
});
lob.on('data', function(chunk) {
// console.log("lob.on 'data' event");
// console.log(' - got %d bytes of data', chunk.length);
lobDataEventFired = true;
blobLength = blobLength + chunk.length;
blob = Buffer.concat([blob, chunk], blobLength);
});
lob.on('end', function() {
fs.readFile( inFileName, function(err, data) {
should.not.exist(err);
lobEndEventFired = true;
data.length.should.be.exactly(blob.length);
data.should.eql(blob);
});
}); // end event
}
);
}
], done);
})
})

241
test/dataTypeClob.js Normal file
View File

@ -0,0 +1,241 @@
/* Copyright (c) 2015, 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
* 40. dataTypeClob.js
*
* DESCRIPTION
* Testing Oracle data type support - CLOB.
* This test corresponds to example files:
* clobinsert1.js, clobstream1.js and clobstream2.js
* Firstly, reads text from clobexample.txt and INSERTs it into a CLOB column.
* Secondly, SELECTs a CLOB and pipes it to a file, clobstreamout.txt
* Thirdly, SELECTs the CLOB and compares it with the content in clobexample.txt
*
* 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
*
*****************************************************************************/
var oracledb = require('oracledb');
var fs = require('fs');
var async = require('async');
var should = require('should');
var dbConfig = require('./dbConfig.js');
var assist = require('./dataTypeAssist.js');
var inFileName = './test/clobexample.txt'; // the file with text to be inserted into the database
var outFileName = './test/clobstreamout.txt';
describe('40. dataTypeClob.js', function() {
if(dbConfig.externalAuth){
var credential = { externalAuth: true, connectString: dbConfig.connectString };
} else {
var credential = dbConfig;
}
var connection = null;
var tableName = "oracledb_myclobs";
var sqlCreate =
"BEGIN " +
" DECLARE " +
" e_table_exists EXCEPTION; " +
" PRAGMA EXCEPTION_INIT(e_table_exists, -00942); " +
" BEGIN " +
" EXECUTE IMMEDIATE ('DROP TABLE " + tableName + " '); " +
" EXCEPTION " +
" WHEN e_table_exists " +
" THEN NULL; " +
" END; " +
" EXECUTE IMMEDIATE (' " +
" CREATE TABLE " + tableName +" ( " +
" num NUMBER, " +
" content CLOB " +
" )" +
" '); " +
"END; ";
before(function(done) {
oracledb.getConnection(credential, function(err, conn) {
if(err) { console.error(err.message); return; }
connection = conn;
conn.execute(
sqlCreate,
function(err) {
if(err) { console.error(err.message); return; }
done();
}
);
});
})
after( function(done){
connection.execute(
"DROP table " + tableName,
function(err) {
if(err) { console.error(err.message); return; }
connection.release( function(err) {
if(err) { console.error(err.message); return; }
done();
});
}
);
})
it('40.1 processes null value correctly', function(done) {
assist.nullValueSupport(connection, tableName, done);
})
it('40.2 stores CLOB value correctly', function(done) {
connection.should.be.ok;
async.series([
function clobinsert1(callback) {
var streamEndEventFired = false;
setTimeout( function() {
streamEndEventFired.should.equal(true, "inStream does not call 'end' event!")
callback();
}, 500);
connection.execute(
"INSERT INTO oracledb_myclobs (num, content) VALUES (:n, EMPTY_CLOB()) RETURNING content INTO :lobbv",
{ n: 1, lobbv: {type: oracledb.CLOB, dir: oracledb.BIND_OUT} },
{ 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 'end' event");
});
inStream.on('end', function() {
streamEndEventFired = true;
// now commit updates
connection.commit( function(err) {
should.not.exist(err);
});
});
inStream.pipe(lob); // copies the text to the CLOB
}
);
},
function clobstream1(callback) {
var streamFinishEventFired = false;
setTimeout( function() {
streamFinishEventFired.should.equal(true, "stream does not call 'Finish' Event!");
callback();
}, 500);
connection.execute(
"SELECT content FROM oracledb_myclobs WHERE num = :n",
{ n: 1 },
function(err, result) {
should.not.exist(err);
var lob = result.rows[0][0];
should.exist(lob);
lob.setEncoding('utf8');
lob.on('error', function(err) {
should.not.exist(err, "lob.on 'end' event");
});
var outStream = fs.createWriteStream(outFileName);
outStream.on('error', function(err) {
should.not.exist(err, "outStream.on 'end' event");
});
lob.pipe(outStream);
outStream.on('finish', function() {
fs.readFile( inFileName, { encoding: 'utf8' }, function(err, originalData) {
should.not.exist(err);
fs.readFile( outFileName, { encoding: 'utf8' }, function(err, generatedData) {
should.not.exist(err);
originalData.should.equal(generatedData);
streamFinishEventFired = true;
});
});
})
}
);
},
function clobstream2(callback) {
var lobEndEventFired = false;
var lobDataEventFired = false;
setTimeout( function(){
lobDataEventFired.should.equal(true, "lob does not call 'data' event!");
lobEndEventFired.should.equal(true, "lob does not call 'end' event!");
callback();
}, 500);
connection.execute(
"SELECT content FROM oracledb_myclobs WHERE num = :n",
{ n: 1 },
function(err, result) {
should.not.exist(err);
var clob = '';
var lob = result.rows[0][0];
should.exist(lob);
lob.setEncoding('utf8'); // set the encoding so we get a 'string' not a 'buffer'
lob.on('data', function(chunk) {
// console.log("lob.on 'data' event");
// console.log(' - got %d bytes of data', chunk.length);
lobDataEventFired = true;
clob += chunk;
});
lob.on('end', function() {
fs.readFile( inFileName, { encoding: 'utf8' }, function(err, data) {
should.not.exist(err);
lobEndEventFired = true;
data.length.should.be.exactly(clob.length);
data.should.equal(clob);
});
});
lob.on('error', function(err) {
should.not.exist(err, "lob.on 'end' event");
});
}
);
}
], done);
})
})

127
test/dataTypeRowid.js Normal file
View File

@ -0,0 +1,127 @@
/* Copyright (c) 2015, 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
* 39. dataTypeRowid.js
*
* DESCRIPTION
* Testing Oracle data type support - ROWID.
*
* NOTE
* Native ROWID support is still under enhancement request.
*
* 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 - are for other tests
*
*****************************************************************************/
var oracledb = require('oracledb');
var should = require('should');
var async = require('async');
var dbConfig = require('./dbConfig.js');
describe('39. dataTypeRowid.js', function() {
if(dbConfig.externalAuth){
var credential = { externalAuth: true, connectString: dbConfig.connectString };
} else {
var credential = dbConfig;
}
var connection = false;
before(function(done) {
oracledb.getConnection(credential, 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('39.1 supports ROWID data type', function(done) {
connection.should.be.ok;
var createTable =
"BEGIN \
DECLARE \
e_table_exists EXCEPTION; \
PRAGMA EXCEPTION_INIT(e_table_exists, -00942); \
BEGIN \
EXECUTE IMMEDIATE ('DROP TABLE oracledb_row'); \
EXCEPTION \
WHEN e_table_exists \
THEN NULL; \
END; \
EXECUTE IMMEDIATE (' \
CREATE TABLE oracledb_row ( \
ID NUMBER, \
RID ROWID \
) \
'); \
EXECUTE IMMEDIATE (' \
INSERT INTO oracledb_row(ID) VALUES(1) \
'); \
EXECUTE IMMEDIATE (' \
UPDATE oracledb_row T SET RID = T.ROWID \
'); \
END; ";
async.series([
function(callback) {
connection.execute(
createTable,
function(err) {
should.not.exist(err);
callback();
}
);
},
function(callback) {
connection.execute(
"SELECT * FROM oracledb_row",
[],
{ outFormat: oracledb.OBJECT },
function(err, result) {
should.exist(err);
err.message.should.startWith('NJS-010:'); // unsupported data type in select list
callback();
}
);
},
function(callback) {
connection.execute(
"DROP TABLE oracledb_row",
function(err) {
should.not.exist(err);
callback();
}
);
}
], done);
})
})

View File

@ -98,7 +98,7 @@ describe('35. dataTypeTimestamp3.js', function() {
); );
}) })
it.skip('supports TIMESTAMP WITH TIME ZONE data type', function(done) { it('supports TIMESTAMP WITH TIME ZONE data type', function(done) {
connection.should.be.ok; connection.should.be.ok;
var timestamps = [ var timestamps = [
@ -126,12 +126,14 @@ describe('35. dataTypeTimestamp3.js', function() {
[], [],
{ outFormat: oracledb.OBJECT }, { outFormat: oracledb.OBJECT },
function(err, result) { function(err, result) {
should.not.exist(err); should.exist(err);
// console.log(result); err.message.should.startWith('NJS-010:'); // unsupported data type in select list
/*
console.log(result);
for(var j = 0; j < timestamps.length; j++) for(var j = 0; j < timestamps.length; j++)
result.rows[j].CONTENT.toUTCString().should.eql(timestamps[result.rows[j].NUM].toUTCString()); result.rows[j].CONTENT.toUTCString().should.eql(timestamps[result.rows[j].NUM].toUTCString());
*/
done(); done();
} }
); );
}); });

View File

@ -98,7 +98,7 @@ describe('36. dataTypeTimestamp4.js', function() {
); );
}) })
it.skip('supports TIMESTAMP WITH TIME ZONE data type', function(done) { it('supports TIMESTAMP WITH TIME ZONE data type', function(done) {
connection.should.be.ok; connection.should.be.ok;
var timestamps = [ var timestamps = [
@ -126,12 +126,14 @@ describe('36. dataTypeTimestamp4.js', function() {
[], [],
{ outFormat: oracledb.OBJECT }, { outFormat: oracledb.OBJECT },
function(err, result) { function(err, result) {
should.not.exist(err); should.exist(err);
// console.log(result); err.message.should.startWith('NJS-010:'); // unsupported data type in select list
/*
console.log(result);
for(var j = 0; j < timestamps.length; j++) for(var j = 0; j < timestamps.length; j++)
result.rows[j].CONTENT.toUTCString().should.eql(timestamps[result.rows[j].NUM].toUTCString()); result.rows[j].CONTENT.toUTCString().should.eql(timestamps[result.rows[j].NUM].toUTCString());
*/
done(); done();
} }
); );
}); });

View File

@ -31,8 +31,8 @@
*****************************************************************************/ *****************************************************************************/
module.exports = { module.exports = {
user : "hr", user : process.env.NODE_ORACLEDB_USER || "hr",
password : "welcome", password : process.env.NODE_ORACLEDB_PASSWORD || "welcome",
connectString : "localhost/orcl", connectString : process.env.NODE_ORACLEDB_CONNECTIONSTRING || "localhost/orcl",
externalAuth : false externalAuth : process.env.NODE_ORACLEDB_EXTERNALAUTH ? true : false
}; };

View File

@ -157,7 +157,7 @@ describe('6. dmlReturning.js', function(){
{ autoCommit: true }, { autoCommit: true },
function(err, result) { function(err, result) {
should.exist(err); should.exist(err);
err.message.should.eql('NJS-016: buffer is too small for OUT binds'); err.message.should.startWith('NJS-016'); // NJS-016: buffer is too small for OUT binds
//console.log(result); //console.log(result);
done(); done();
} }

View File

@ -510,17 +510,7 @@ describe('3. examples.js', function(){
describe('3.7 plsql.js', function(){ describe('3.7 plsql.js', function(){
var connection = false; var connection = false;
var proc = "CREATE OR REPLACE PROCEDURE testproc (p_in IN VARCHAR2, p_inout IN OUT VARCHAR2, p_out OUT NUMBER) \
AS \
BEGIN \
p_inout := p_in || p_inout; \
p_out := 101; \
END; ";
var bindVars = {
i: 'Chris', // bind type is determined from the data type
io: { val: 'Jones', dir : oracledb.BIND_INOUT },
o: { type: oracledb.NUMBER, dir : oracledb.BIND_OUT }
}
before(function(done){ before(function(done){
oracledb.getConnection(credential, function(err, conn){ oracledb.getConnection(credential, function(err, conn){
if(err) { console.error(err.message); return; } if(err) { console.error(err.message); return; }
@ -537,6 +527,19 @@ describe('3. examples.js', function(){
}) })
it('3.7.1 can call PL/SQL procedure and binding parameters in various ways', function(done){ it('3.7.1 can call PL/SQL procedure and binding parameters in various ways', function(done){
var proc =
"CREATE OR REPLACE PROCEDURE testproc (p_in IN VARCHAR2, p_inout IN OUT VARCHAR2, p_out OUT NUMBER) \
AS \
BEGIN \
p_inout := p_in || p_inout; \
p_out := 101; \
END; ";
var bindVars = {
i: 'Chris', // bind type is determined from the data type
io: { val: 'Jones', dir : oracledb.BIND_INOUT },
o: { type: oracledb.NUMBER, dir : oracledb.BIND_OUT }
}
async.series([ async.series([
function(callback){ function(callback){
connection.execute( connection.execute(
@ -570,6 +573,53 @@ describe('3. examples.js', function(){
} }
], done); ], done);
}) })
it('3.7.2 can call PL/SQL function', function(done) {
var proc =
"CREATE OR REPLACE FUNCTION testfunc (p1_in IN VARCHAR2, p2_in IN VARCHAR2) RETURN VARCHAR2 \
AS \
BEGIN \
return p1_in || p2_in; \
END; ";
var bindVars = {
p1: 'Chris',
p2: 'Jones',
ret: { dir: oracledb.BIND_OUT, type: oracledb.STRING, maxSize: 40 }
};
async.series([
function(callback){
connection.execute(
proc,
function(err){
should.not.exist(err);
callback();
}
);
},
function(callback){
connection.execute(
"BEGIN :ret := testfunc(:p1, :p2); END;",
bindVars,
function(err, result){
should.not.exist(err);
// console.log(result);
(result.outBinds.ret).should.equal('ChrisJones');
callback();
}
);
},
function(callback){
connection.execute(
"DROP FUNCTION testfunc",
function(err, result){
should.not.exist(err);
callback();
}
);
}
], done);
})
}) })
@ -900,8 +950,155 @@ describe('3. examples.js', function(){
}); });
} }
}) })
}) })
describe('3.11 refcursor.js', function() {
var connection = false;
var script =
"BEGIN \
DECLARE \
e_table_exists EXCEPTION; \
PRAGMA EXCEPTION_INIT(e_table_exists, -00942); \
BEGIN \
EXECUTE IMMEDIATE ('DROP TABLE oracledb_employees'); \
EXCEPTION \
WHEN e_table_exists \
THEN NULL; \
END; \
EXECUTE IMMEDIATE (' \
CREATE TABLE oracledb_employees ( \
name VARCHAR2(40), \
salary NUMBER, \
hire_date DATE \
) \
'); \
EXECUTE IMMEDIATE (' \
INSERT INTO oracledb_employees \
(name, salary, hire_date) VALUES \
(''Steven'',24000, TO_DATE(''20030617'', ''yyyymmdd'')) \
'); \
EXECUTE IMMEDIATE (' \
INSERT INTO oracledb_employees \
(name, salary, hire_date) VALUES \
(''Neena'',17000, TO_DATE(''20050921'', ''yyyymmdd'')) \
'); \
EXECUTE IMMEDIATE (' \
INSERT INTO oracledb_employees \
(name, salary, hire_date) VALUES \
(''Lex'',17000, TO_DATE(''20010112'', ''yyyymmdd'')) \
'); \
EXECUTE IMMEDIATE (' \
INSERT INTO oracledb_employees \
(name, salary, hire_date) VALUES \
(''Nancy'',12008, TO_DATE(''20020817'', ''yyyymmdd'')) \
'); \
EXECUTE IMMEDIATE (' \
INSERT INTO oracledb_employees \
(name, salary, hire_date) VALUES \
(''Karen'',14000, TO_DATE(''20050104'', ''yyyymmdd'')) \
'); \
EXECUTE IMMEDIATE (' \
INSERT INTO oracledb_employees \
(name, salary, hire_date) VALUES \
(''Peter'',9000, TO_DATE(''20100525'', ''yyyymmdd'')) \
'); \
END; ";
var proc =
"CREATE OR REPLACE PROCEDURE get_emp_rs (p_sal IN NUMBER, p_recordset OUT SYS_REFCURSOR) \
AS \
BEGIN \
OPEN p_recordset FOR \
SELECT * FROM oracledb_employees \
WHERE salary > p_sal; \
END; ";
before(function(done){
async.series([
function(callback) {
oracledb.getConnection(
credential,
function(err, conn) {
should.not.exist(err);
connection = conn;
callback();
}
);
},
function(callback) {
connection.execute(
script,
function(err) {
should.not.exist(err);
callback();
}
);
},
function(callback) {
connection.execute(
proc,
function(err) {
should.not.exist(err);
callback();
}
);
}
], done);
})
after(function(done){
connection.execute(
'DROP TABLE oracledb_employees',
function(err){
if(err) { console.error(err.message); return; }
connection.release( function(err){
if(err) { console.error(err.message); return; }
done();
});
}
);
})
it('3.11.1 REF CURSOR', function(done) {
connection.should.be.ok;
var numRows = 100; // number of rows to return from each call to getRows()
connection.execute(
"BEGIN get_emp_rs(:sal, :cursor); END;",
{
sal: 12000,
cursor: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT }
},
function(err, result) {
should.not.exist(err);
result.outBinds.cursor.metaData[0].name.should.eql('NAME');
result.outBinds.cursor.metaData[1].name.should.eql('SALARY');
result.outBinds.cursor.metaData[2].name.should.eql('HIRE_DATE');
fetchRowsFromRS(result.outBinds.cursor);
}
);
function fetchRowsFromRS(resultSet) {
resultSet.getRows(
numRows,
function(err, rows) {
should.not.exist(err);
if(rows.length > 0) {
// console.log("fetchRowsFromRS(): Got " + rows.length + " rows");
// console.log(rows);
rows.length.should.be.exactly(5);
fetchRowsFromRS(resultSet);
} else {
resultSet.close( function(err) {
should.not.exist(err);
done();
});
}
}
);
}
})
})
}) })

260
test/fetchAs.js Normal file
View File

@ -0,0 +1,260 @@
/* Copyright (c) 2015, 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
* 56. fetchAs.js
*
* DESCRIPTION
* Testing driver fetchAs feature.
*
* 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
*
*****************************************************************************/
var oracledb = require ( 'oracledb' );
var should = require ( 'should' );
var async = require ( 'async' );
var dbConfig = require ( './dbConfig.js' );
describe ('56. fetchAs.js',
function ()
{
if (dbConfig.externalAuth )
{
var credential = { externalAuth : true,
connectString : dbConfig.connectString
};
}
else
{
var credential = dbConfig;
}
var connection = false;
/* preparation work before test case(s). */
before (
function ( done )
{
oracledb.getConnection ( credential,
function ( err, conn )
{
if ( err )
{
console.error ( err.message );
return;
}
connection = conn;
done ();
}
);
}
);
/* clean up after test case(s) */
after (
function ( done )
{
connection.release (
function ( err )
{
oracledb.fetchAsString = [] ;
if ( err )
{
console.error ( err.message );
return;
}
done ();
}
);
}
);
/* Fetch DATE column values as STRING - by-Column name */
it ('56.1 FetchAs - DATE type as STRING',
function ( done )
{
connection.should.be.ok;
connection.execute (
"SELECT FIRST_NAME, LAST_NAME, HIRE_DATE FROM EMPLOYEES",
[],
{
outFormat : oracledb.OBJECT,
fetchInfo : { "HIRE_DATE" : { type : oracledb.STRING } }
},
function ( err, result )
{
should.not.exist ( err ) ;
done ();
}
);
}
);
/* Fetch DATE, NUMBER column values STRING - by Column-name */
it ('56.2 FetchAs NUMBER & DATE type as STRING',
function ( done )
{
connection.should.be.ok;
connection.execute (
"SELECT employee_id as SEMPID, employee_id, " +
"hire_date as SHDATE, hire_date FROM EMPLOYEES",
[],
{
outFormat : oracledb.OBJECT,
fetchInfo :
{
"SEMPID" : { type : oracledb.STRING },
"SHDATE" : { type : oracledb.STRING }
}
},
function ( err, result )
{
should.not.exist ( err ) ;
done ();
}
);
}
);
/* Fetch DATE, NUMBER as STRING by-time configuration and by-name */
it ('56.3 FetchAs Oracledb property by-type',
function ( done )
{
connection.should.be.ok;
oracledb.fetchAsString = [ oracledb.DATE, oracledb.NUMBER ];
connection.execute (
"SELECT employee_id, first_name, last_name, hire_date " +
"FROM EMPLOYEES",
[],
{
outFormat : oracledb.OBJECT,
fetchInfo :
{
"HIRE_DATE" : { type : oracledb.STRING }
}
},
function ( err, result )
{
should.not.exist ( err ) ;
done ();
}
);
}
);
/*
* Fetch DATE, NUMBER column as STRING by-type and override
* HIRE_DATE to use default (from metadata type).
*/
it ('56.4 FetchAs override oracledb by-type (for DATE) at execute time',
function ( done )
{
connection.should.be.ok;
oracledb.fetchAsString = [ oracledb.DATE, oracledb.NUMBER ];
connection.execute (
"SELECT employee_id, first_name, last_name, hire_date " +
"FROM EMPLOYEES",
[],
{
outFormat : oracledb.OBJECT,
fetchInfo :
{
"HIRE_DATE" : { type : oracledb.DEFAULT },
"EMPLOYEE_ID" : { type : oracledb.STRING }
}
},
function ( err, result )
{
should.not.exist ( err ) ;
done ();
}
);
}
);
/* Fetch ROWID column values STRING - non-ResultSet */
it ('56.5 FetchInfo ROWID column values STRING non-ResultSet',
function ( done )
{
connection.should.be.ok;
connection.execute (
"SELECT ROWID from DUAL",
[],
{
outFormat : oracledb.OBJECT,
fetchInfo :
{
"ROWID" : { type : oracledb.STRING }
}
},
function ( err, result )
{
should.not.exist ( err ) ;
done ();
}
);
}
);
/* Fetch ROWID column values STRING - ResultSet */
it ('56.6 FetchInfo ROWID column values STRING ResultSet',
function ( done )
{
connection.should.be.ok;
connection.execute (
"SELECT ROWID from DUAL",
[],
{
outFormat : oracledb.OBJECT,
resultSet : true,
fetchInfo :
{
"ROWID" : { type : oracledb.STRING }
}
},
function ( err, result )
{
should.not.exist ( err ) ;
done ();
}
);
}
);
}
);

BIN
test/fuzzydinosaur.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

339
test/list.txt Normal file
View File

@ -0,0 +1,339 @@
1. connection.js
1.1 can run SQL query with different output formats
1.1.1 ARRAY format by default
1.1.2 ARRAY format explicitly
1.1.3 OBJECT format
1.1.4 Negative test - invalid outFormat value
1.2 limits the number of rows fetched
1.2.1 by default, the number is 100
1.2.2 can also specify for each execution
1.2.3 can set maxRows to be 0
1.2.4 cannot set maxRows to be a negative number
1.2.5 sets maxRows to be very large value
1.3 can call PL/SQL procedures
1.3.1 bind parameters in various ways
1.4 statementCacheSize controls statement caching
1.4.1 stmtCacheSize = 0, which disable statement caching
1.4.2 works well when statement cache enabled (stmtCacheSize > 0)
1.5 Testing commit() & rollback() functions
1.5.1 commit() function works well
1.5.2 rollback() function works well
2. pool.js
2.1 default values
2.1.1 set properties to default values if not explicitly specified
2.2 poolMin
2.2.1 poolMin cannot be a negative number
2.2.2 poolMin must be a Number
2.2.3 poolMin cannot equal to poolMax
2.2.4 poolMin cannot greater than poolMax
2.2.5 (poolMin + poolIncrement) cannot greater than poolMax
2.2.6 (poolMin + poolIncrement) can equal to poolMax
2.3 poolMax
2.3.1 poolMax cannot be a negative value
2.3.2 poolMax cannot be 0
2.3.3 poolMax must be a number
2.3.4 poolMax limits the pool capacity
2.4 poolIncrement
2.4.1 poolIncrement cannot be a negative value
2.4.2 poolIncrement cannot be 0
2.4.3 poolIncrement must be a Number
2.4.4 the amount of open connections equals to poolMax when (connectionsOpen + poolIncrement) > poolMax
2.5 poolTimeout
2.5.1 poolTimeout cannot be a negative number
2.5.2 poolTimeout can be 0, which disables timeout feature
2.5.3 poolTimeout must be a number
2.6 stmtCacheSize
2.6.1 stmtCacheSize cannot be a negative value
2.6.2 stmtCacheSize can be 0
2.6.3 stmtCacheSize must be a Number
3. examples.js
3.1 connect.js
3.1.1 tests a basic connection to the database
3.2 version.js
3.2.1 shows the oracledb version attribute
3.3 select1.js & select2.js
3.3.1. execute a basic query
3.3.2. execute queries to show array and object formats
3.4 selectjson.js - 12.1.0.2 feature
3.4.1 executes a query from a JSON table
3.5 date.js
3.5.1 inserts and query DATE and TIMESTAMP columns
3.6 rowlimit.js
3.6.1 by default, the number is 100
3.6.2 can also specify for each execution
3.7 plsql.js
3.7.1 can call PL/SQL procedure and binding parameters in various ways
3.7.2 can call PL/SQL function
3.8 insert1.js
3.8.1 creates a table and inserts data
3.9 insert2.js
3.9.1 tests the auto commit behavior
3.10 resultset.js
3.10.1 resultset1.js - getRow() function
3.10.2 resultset2.js - getRows() function
3.11 refcursor.js
3.11.1 REF CURSOR
4. binding.js
4.1 test STRING, NUMBER, ARRAY & JSON format
4.1.1 VARCHAR2 binding, Object & Array formats
4.1.2 NUMBER binding, Object & Array formats
4.1.3 Multiple binding values, Object & Array formats
4.1.4 Multiple binding values, Change binding order
4.1.5 default bind type - STRING
4.2 mixing named with positional binding
4.2.1 array binding is ok
- 4.2.2 array binding with mixing JSON should throw an error
4.3 insert with DATE column and DML returning
4.3.1 passes in object syntax without returning into
4.3.2 passes in object syntax with returning into
4.3.3 passes in array syntax without returning into
4.3.4 should pass but fail in array syntax with returning into
4.4 test maxSize option
4.4.1 outBind & maxSize restriction
- 4.4.2 default value is 200
- 4.4.3 maximum value is 32767
5. externalAuthentication.js
5.1 connection should succeed when setting externalAuth to be false and providing user/password
5.2 error should be thrown when setting externalAuth to be true and providing user/password
5.3 can get connection from oracledb
5.4 can create pool
6. dmlReturning.js
6.1 NUMBER & STRING driver data type
6.1.1 INSERT statement with Object binding
6.1.2 INSERT statement with Array binding
6.1.3 INSERT statement with small maxSize restriction
6.1.4 UPDATE statement with single row matched
6.1.5 UPDATE statement with single row matched & Array binding
6.1.6 UPDATE statements with multiple rows matched
6.1.7 UPDATE statements with multiple rows matched & Array binding
6.1.8 DELETE statement with Object binding
6.1.9 DELETE statement with Array binding
6.1.10 Stress test - support 4k varchars
6.1.11 Negative test - throws correct error message
7. autoCommit.js
7.1 autoCommit takes effect when setting oracledb.autoCommit before connecting
7.2 autoCommit takes effect when setting oracledb.autoCommit after connecting
7.3 autoCommit setting does not affect previous SQL result
8. autoCommitForSelect.js
8.1 should return previous value when autoCommit is false
8.2 can use explicit commit() to keep data consistent
8.3 can also use the autoCommit for SELECTs feature
9. columnMetadata.js
9.1 shows metaData correctly when retrieving 1 column from a 4-column table
9.2 shows metaData when retrieving 2 columns. MetaData is correct in content and sequence
9.3 shows metaData correctly when retrieve 3 columns
9.4 shows metaData correctly when retrieving all columns with [SELECT * FROM table] statement
9.5 works for SELECT count(*)
9.6 works when a query returns no rows
9.7 works for tables whose column names were created case sensitively
9.8 only works for SELECT statement, does not work for INSERT
9.9 only works for SELECT statement, does not work for UPDATE
9.10 works with a large number of columns
9.11 works with column names consisting of single characters
9.12 works with a SQL WITH statement
10. nullColumnValues.js
10.1 a simple query for null value
10.2 in-bind for null column value
10.3 out-bind for null column value
10.4 DML Returning for null column value
10.5 resultSet for null value
11. poolTimeout.js
pool terminates idle connections after specify time
12. resultSet1.js
12.1 Testing resultSet option
12.1.1 when resultSet option = false, content of result is correct
12.1.2 when resultSet option = true, content of result is correct
12.1.3 when resultSet option = 0, it behaves like false
12.1.4 when resultSet option = null, it behaves like false
12.1.5 when resultSet option = undefined, it behaves like false
12.1.6 when resultSet option = NaN, it behaves like false
12.1.7 when resultSet option = 1, it behaves like true
12.1.8 when resultSet option = -1, it behaves like true
12.1.9 when resultSet option is a random string, it behaves like true
12.2 Testing prefetchRows option
12.2.1 cannot set prefetchRows to be a negative value
12.2.2 cannot set prefetchRows to be a random string
12.2.3 cannot set prefetchRows to be NaN
12.2.4 cannot set prefetchRows to be null
12.2.5 prefetchRows can be set to 0
12.3 Testing function getRows()
12.3.1 retrieved set is exactly the size of result
12.3.2 retrieved set is greater than the size of result
12.3.3 retrieved set is half of the size of result
12.3.4 retrieved set is one tenth of the size of the result
12.3.5 data in resultSet is array when setting outFormat ARRAY
12.3.6 data in resultSet is object when setting outFormat OBJECT
12.3.7 the size of retrieved set can be set to 1
12.3.8 query 0 row
12.3.9 Negative - To omit the first parameter
12.3.10 Negative - set the 1st parameter of getRows() to be 0
12.3.11 Negative - set the 1st parameter of getRows() to be -5
12.3.12 Negative - set the 1st parameter of getRows() to be null
12.4 Testing function getRow()
12.4.1 works well with all correct setting
12.4.2 data in resultSet is array when setting outFormat ARRAY
12.4.3 data in resultSet is object when setting outFormat OBJECT
12.4.4 query 0 row
12.4.5 Negative - set the first parameter like getRows()
12.5 Testing function close()
12.5.1 does not call close()
12.5.2 invokes close() twice
12.5.3 uses getRows after calling close()
12.5.4 closes one resultSet and then open another resultSet
12.6 Testing metaData
12.6.1 the amount and value of metaData should be correct
12.6.2 can distinguish lower case and upper case
12.6.3 can contain quotes
12.6.4 can contain underscore
12.7 Testing maxRows
12.7.1 maxRows option is ignored when resultSet option is true
12.7.2 maxRows option is ignored with REF Cursor
21. datatypeAssist.js
22. dataTypeChar.js
22.1 supports CHAR data
22.2 resultSet stores CHAR data correctly
22.3 stores null value correctly
23. dataTypeNchar.js
23.1 supports NCHAR data type
23.2 resultSet supports NCHAR data type
23.3 stores null value correctly
24. dataTypeVarchar2.js
24.1 supports VARCHAR2 data in various lengths
24.2 resultSet stores VARCHAR2 data correctly
24.3 stores null value correctly
25. dataTypeNvarchar2.js
25.1 supports NVARCHAR2 data in various lengths
25.2 resultSet stores NVARCHAR2 data correctly
25.3 stores null value correctly
26. dataTypeNumber.js
26.1 supports NUMBER data type
26.2 resultSet stores NUMBER data correctly
26.3 stores null value correctly
27. dataTypeNumber2.js
27.1 supports NUMBER(p, s) data type
27.2 resultSet stores NUMBER(p, s) data correctly
27.3 stores null value correctly
28. dataTypeFloat.js
28.1 supports FLOAT data type
28.2 resultSet stores FLOAT data correctly
28.3 stores null value correctly
29. dataTypeFloat2.js
29.1 supports FLOAT(p) data type
29.2 resultSet stores FLOAT(p) data correctly
29.3 stores null value correctly
30. dataTypeBinaryFloat.js
- supports BINARY_FLOAT data type
31. dataTypeBinaryDouble.js
- supports BINARY_DOUBLE data type
32. dataTypeDate.js
32.1 supports DATE data type
32.2 resultSet stores DATE data correctly
32.3 stores null value correctly
33. dataTypeTimestamp1.js
33.1 supports TIMESTAMP data type
33.2 resultSet stores TIMESTAMP data correctly
33.3 stores null value correctly
34. dataTypeTimestamp2.js
34.1 supports TIMESTAMP(p) data type
34.2 resultSet stores TIMESTAMP data correctly
34.3 stores null value correctly
35. dataTypeTimestamp3.js
supports TIMESTAMP WITH TIME ZONE data type
36. dataTypeTimestamp4.js
supports TIMESTAMP WITH TIME ZONE data type
37. dataTypeTimestamp5.js
37.1 supports TIMESTAMP WITH LOCAL TIME ZONE data type
37.2 resultSet stores TIMESTAMP WITH LOCAL TIME ZONE data correctly
37.3 stores null value correctly
38. dataTypeTimestamp6.js
38.1 supports TIMESTAMP(9) WITH LOCAL TIME ZONE data type
38.2 resultSet stores TIMESTAMP(9) WITH LOCAL TIME ZONE data correctly
38.3 stores null value correctly
39. dataTypeRowid.js
39.1 supports ROWID data type
40. dataTypeClob.js
40.1 processes null value correctly
40.2 stores CLOB value correctly
41. dataTypeBlob
41.1 processes null value correctly
41.2 stores BLOB value correctly
51. accessTerminatedPoolAttributes.js
can not access attributes of terminated pool
52. getConnAfterPoolTerminate.js
can not get connections from pool after pool is terminated
53. poolValidityAfterFailingTernimate.js
pool should be available after failing terminate
54. releaseAfterFailingTerminate.js
can still release connections after failing pool termination
55. resultSet2.js
55.1 query a RDBMS function
55.1.1 LPAD function
55.2 binding variables
55.2.1 query with one binding variable
55.3 alternating getRow() & getRows() function
55.3.1 result set
55.3.2 REF Cursor
55.4 release connection before close resultSet
55.4.1 result set
55.4.2 REF Cursor
55.5 the content of resultSet should be consistent
55.5.1 (1) get RS (2) modify data in that table and commit (3) check RS
55.6 access resultSet simultaneously
55.6.1 concurrent operations on resultSet are not allowed
55.6.2 concurrent operation on REF Cursor are not allowed
55.7 getting multiple resultSets
55.7.1 can access multiple resultSet on one connection
55.7.2 can access multiple REF Cursor
55.8 Negative - resultSet is only for query statement
55.8.1 resultSet cannot be returned for non-query statements
55.9 test querying a PL/SQL function
55.9.1
55.10 calls getRows() once and then close RS before getting more rows
55.10.1
56. fetchAs.js
56.1 FetchAs - DATE type as STRING
56.2 FetchAs NUMBER & DATE type as STRING
56.3 FetchAs Oracledb property by-type
56.4 FetchAs override oracledb by-type (for DATE) at execute time
57. nestedCursor.js
57.1 testing nested cursor support - result set
57.2 testing nested cursor support - REF Cursor

303
test/nestedCursor.js Normal file
View File

@ -0,0 +1,303 @@
/* Copyright (c) 2015, 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
* 57. nestedCursor.js
*
* DESCRIPTION
* Testing nested cursor.
*
* 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('57. nestedCursor.js', function() {
if(dbConfig.externalAuth){
var credential = { externalAuth: true, connectString: dbConfig.connectString };
} else {
var credential = dbConfig;
}
var createParentTable =
"BEGIN \
DECLARE \
e_table_exists EXCEPTION; \
PRAGMA EXCEPTION_INIT(e_table_exists, -00942); \
BEGIN \
EXECUTE IMMEDIATE ('DROP TABLE test_parent_tab'); \
EXCEPTION \
WHEN e_table_exists \
THEN NULL; \
END; \
EXECUTE IMMEDIATE (' \
CREATE TABLE test_parent_tab ( \
id NUMBER, \
description VARCHAR2(32), \
CONSTRAINT parent_tab_pk PRIMARY KEY (id) \
) \
'); \
EXECUTE IMMEDIATE (' \
INSERT INTO test_parent_tab (id, description) \
VALUES \
(1,''Parent 1'') \
'); \
EXECUTE IMMEDIATE (' \
INSERT INTO test_parent_tab (id, description) \
VALUES \
(2,''Parent 2'') \
'); \
EXECUTE IMMEDIATE (' \
INSERT INTO test_parent_tab (id, description) \
VALUES \
(3,''Parent 3'') \
'); \
END; ";
var createChildTable =
"BEGIN \
DECLARE \
e_table_exists EXCEPTION; \
PRAGMA EXCEPTION_INIT(e_table_exists, -00942); \
BEGIN \
EXECUTE IMMEDIATE ('DROP TABLE test_child_tab'); \
EXCEPTION \
WHEN e_table_exists \
THEN NULL; \
END; \
EXECUTE IMMEDIATE (' \
CREATE TABLE test_child_tab ( \
id NUMBER, \
parent_id NUMBER, \
description VARCHAR2(32), \
CONSTRAINT child_tab_pk PRIMARY KEY (id), \
CONSTRAINT child_parent_fk FOREIGN KEY (parent_id) REFERENCES test_parent_tab(id) \
) \
'); \
EXECUTE IMMEDIATE (' \
INSERT INTO test_child_tab (id, parent_id, description) \
VALUES \
(1, 1, ''Child 1'') \
'); \
EXECUTE IMMEDIATE (' \
INSERT INTO test_child_tab (id, parent_id, description) \
VALUES \
(2, 1, ''Child 2'') \
'); \
EXECUTE IMMEDIATE (' \
INSERT INTO test_child_tab (id, parent_id, description) \
VALUES \
(3, 2, ''Child 3'') \
'); \
EXECUTE IMMEDIATE (' \
INSERT INTO test_child_tab (id, parent_id, description) \
VALUES \
(4, 2, ''Child 4'') \
'); \
EXECUTE IMMEDIATE (' \
INSERT INTO test_child_tab (id, parent_id, description) \
VALUES \
(5, 2, ''Child 5'') \
'); \
EXECUTE IMMEDIATE (' \
INSERT INTO test_child_tab (id, parent_id, description) \
VALUES \
(6, 3, ''Child 6'') \
'); \
END; ";
var cursorExpr =
"CREATE OR REPLACE PROCEDURE cursor_parent_child (p_out OUT SYS_REFCURSOR) \
AS \
BEGIN \
OPEN p_out FOR \
SELECT p ";
var connection = false;
before(function(done) {
async.series([
function(callback) {
oracledb.getConnection(
credential,
function(err, conn) {
connection = conn;
callback();
}
);
},
function(callback) {
connection.should.be.ok;
connection.execute(
createParentTable,
function(err) {
should.not.exist(err);
callback();
}
);
},
function(callback) {
connection.should.be.ok;
connection.execute(
createChildTable,
function(err) {
should.not.exist(err);
callback();
}
);
}
], done);
})
after(function(done) {
async.series([
function(callback) {
connection.execute(
"DROP TABLE test_child_tab",
function(err) {
should.not.exist(err);
callback();
}
);
},
function(callback) {
connection.execute(
"DROP TABLE test_parent_tab",
function(err) {
should.not.exist(err);
callback();
}
);
},
function(callback) {
connection.release( function(err) {
should.not.exist(err);
callback();
});
}
], done);
})
function fetchOneRowFromRS(rs, cb) {
rs.getRow(function(err, row) {
if(err) {
// console.error("Error at accessing RS: " + err.message);
// NJS-010: unsupported data type in select list
(err.message).should.startWith('NJS-010');
rs.close(function(err) {
should.not.exist(err);
cb();
});
} else if(row) {
console.log(row);
fetchOneRowFromRS(rs, cb);
} else {
rs.close(function(err) {
should.not.exist(err);
cb();
});
}
});
}
it('57.1 testing nested cursor support - result set', function(done) {
connection.should.be.ok;
var sql =
"SELECT p.description, \
CURSOR( \
SELECT c.description \
FROM test_child_tab c \
WHERE c.parent_id = p.id \
) children \
FROM test_parent_tab p";
connection.execute(
sql,
[],
{ resultSet: true },
function(err, result) {
should.not.exist(err);
should.exist(result.resultSet);
fetchOneRowFromRS(result.resultSet, done);
}
);
})
it('57.2 testing nested cursor support - REF Cursor', function(done) {
var testproc =
"CREATE OR REPLACE PROCEDURE get_family_tree(p_out OUT SYS_REFCURSOR) \
AS \
BEGIN \
OPEN p_out FOR \
SELECT p.description, \
CURSOR( \
SELECT c.description \
FROM test_child_tab c \
WHERE c.parent_id = p.id \
) children \
FROM test_parent_tab p; \
END; ";
async.series([
function(callback) {
connection.execute(
testproc,
function(err, result) {
should.not.exist(err);
callback();
}
);
},
function(callback){
connection.execute(
"BEGIN get_family_tree(:out); END;",
{
out: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT }
},
function(err, result) {
should.not.exist(err);
fetchOneRowFromRS(result.outBinds.out, callback);
}
);
},
function(callback) {
connection.execute(
"DROP PROCEDURE get_family_tree",
function(err, result) {
should.not.exist(err);
callback();
}
);
}
], done);
})
})

View File

@ -346,7 +346,7 @@ describe('12. resultSet1.js', function() {
}) })
describe('12.3 Testing function getRows()', function() { describe('12.3 Testing function getRows()', function() {
it('12.3.1 retrived set is exactly the size of result', function(done) { it('12.3.1 retrieved set is exactly the size of result', function(done) {
connection.should.be.ok; connection.should.be.ok;
var nRows = rowsAmount; var nRows = rowsAmount;
var accessCount = 0; var accessCount = 0;
@ -379,7 +379,7 @@ describe('12. resultSet1.js', function() {
} }
}) })
it('12.3.2 retrived set is greater than the size of result', function(done) { it('12.3.2 retrieved set is greater than the size of result', function(done) {
connection.should.be.ok; connection.should.be.ok;
var nRows = rowsAmount * 2; var nRows = rowsAmount * 2;
var accessCount = 0; var accessCount = 0;
@ -412,7 +412,7 @@ describe('12. resultSet1.js', function() {
} }
}) })
it('12.3.3 retrived set is half of the size of result', function(done) { it('12.3.3 retrieved set is half of the size of result', function(done) {
connection.should.be.ok; connection.should.be.ok;
var nRows = Math.ceil(rowsAmount/2); var nRows = Math.ceil(rowsAmount/2);
var accessCount = 0; var accessCount = 0;
@ -445,7 +445,7 @@ describe('12. resultSet1.js', function() {
} }
}) })
it('12.3.4 retrived set is one tenth of the size of the result', function(done) { it('12.3.4 retrieved set is one tenth of the size of the result', function(done) {
connection.should.be.ok; connection.should.be.ok;
var nRows = Math.ceil(rowsAmount/10); var nRows = Math.ceil(rowsAmount/10);
var accessCount = 0; var accessCount = 0;
@ -550,7 +550,7 @@ describe('12. resultSet1.js', function() {
} }
}) })
it('12.3.7 the size of retrived set can be set to 1', function(done) { it('12.3.7 the size of retrieved set can be set to 1', function(done) {
connection.should.be.ok; connection.should.be.ok;
var nRows = 1; var nRows = 1;
var accessCount = 0; var accessCount = 0;
@ -1318,6 +1318,71 @@ describe('12. resultSet1.js', function() {
}); });
} }
}) })
it('12.7.2 maxRows option is ignored with REF Cursor', function(done) {
connection.should.be.ok;
var rowCount = 0;
var queryAmount = 100;
var proc =
"CREATE OR REPLACE PROCEDURE get_emp_rs (p_in IN NUMBER, p_out OUT SYS_REFCURSOR) \
AS \
BEGIN \
OPEN p_out FOR \
SELECT * FROM oracledb_employees \
WHERE employees_id <= p_in; \
END; ";
async.series([
function(callback) {
connection.execute(
proc,
function(err) {
should.not.exist(err);
callback();
}
);
},
function(callback) {
connection.execute(
"BEGIN get_emp_rs(:in, :out); END;",
{
in: queryAmount,
out: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT }
},
{ maxRows: 10 },
function(err, result) {
should.not.exist(err);
fetchRowFromRS(result.outBinds.out, callback);
}
);
},
function(callback) {
connection.execute(
"DROP PROCEDURE get_emp_rs",
function(err) {
should.not.exist(err);
callback();
}
);
}
], done);
function fetchRowFromRS(rs, cb) {
rs.getRow(function(err, row) {
should.not.exist(err);
if(row) {
rowCount++;
return fetchRowFromRS(rs, cb);
} else {
rs.close( function(err) {
should.not.exist(err);
rowCount.should.eql(queryAmount);
cb();
});
}
});
}
})
}) })
}) })

View File

@ -31,13 +31,14 @@
* 51 onwards are for other tests * 51 onwards are for other tests
* *
*****************************************************************************/ *****************************************************************************/
"use strict";
var oracledb = require('oracledb'); var oracledb = require('oracledb');
var should = require('should'); var should = require('should');
var async = require('async'); var async = require('async');
var dbConfig = require('./dbConfig.js'); var dbConfig = require('./dbConfig.js');
describe('55 resultSet2.js', function() { describe('55. resultSet2.js', function() {
if(dbConfig.externalAuth){ if(dbConfig.externalAuth){
var credential = { externalAuth: true, connectString: dbConfig.connectString }; var credential = { externalAuth: true, connectString: dbConfig.connectString };
@ -65,6 +66,7 @@ describe('55 resultSet2.js', function() {
'); \ '); \
END; "; END; ";
var rowsAmount = 300;
var insertRows = var insertRows =
"DECLARE \ "DECLARE \
x NUMBER := 0; \ x NUMBER := 0; \
@ -76,37 +78,89 @@ describe('55 resultSet2.js', function() {
INSERT INTO oracledb_employees VALUES (x, n); \ INSERT INTO oracledb_employees VALUES (x, n); \
END LOOP; \ END LOOP; \
END; "; END; ";
var rowsAmount = 300;
var proc =
"CREATE OR REPLACE PROCEDURE get_emp_rs (p_in IN NUMBER, p_out OUT SYS_REFCURSOR) \
AS \
BEGIN \
OPEN p_out FOR \
SELECT * FROM oracledb_employees \
WHERE employees_id > p_in; \
END; ";
beforeEach(function(done) { beforeEach(function(done) {
oracledb.getConnection(credential, function(err, conn) { async.series([
if(err) { console.error(err.message); return; } function(callback) {
connection = conn; oracledb.getConnection(
connection.execute(createTable, function(err) { credential,
if(err) { console.error(err.message); return; } function(err, conn) {
connection = conn;
callback();
}
);
},
function(callback) {
connection.should.be.ok;
connection.execute( connection.execute(
insertRows, createTable,
function(err) {
should.not.exist(err);
callback();
}
);
},
function(callback) {
connection.execute(
insertRows,
[], [],
{ autoCommit: true }, { autoCommit: true },
function(err) { function(err) {
if(err) { console.error(err.message); return; } should.not.exist(err);
done(); callback();
}); }
}); );
}); },
function(callback) {
connection.execute(
proc,
[],
{ autoCommit: true },
function(err) {
should.not.exist(err);
callback();
}
);
}
], done);
}) })
afterEach(function(done) { afterEach(function(done) {
connection.execute( async.series([
'DROP TABLE oracledb_employees', function(callback) {
function(err) { connection.execute(
if(err) { console.error(err.message); return; } 'DROP TABLE oracledb_employees',
connection.release(function(err) { function(err) {
if(err) { console.error(err.message); return; } should.not.exist(err);
done(); callback();
}
);
},
function(callback) {
connection.execute(
'DROP PROCEDURE get_emp_rs',
function(err) {
should.not.exist(err);
callback();
}
);
},
function(callback) {
connection.release( function(err) {
should.not.exist(err);
callback();
}); });
} }
); ], done);
}) })
describe('55.1 query a RDBMS function', function() { describe('55.1 query a RDBMS function', function() {
@ -174,8 +228,8 @@ describe('55 resultSet2.js', function() {
}) })
describe('55.3 alternating getRow() & getRows() function', function(done) { describe('55.3 alternating getRow() & getRows() function', function() {
it('55.3.1', function(done) { it('55.3.1 result set', function(done) {
connection.should.be.ok; connection.should.be.ok;
var accessCount = 0; var accessCount = 0;
var numRows = 4; var numRows = 4;
@ -229,11 +283,85 @@ describe('55 resultSet2.js', function() {
} }
} }
}) })
it('55.3.2 REF Cursor', function(done) {
connection.should.be.ok;
var accessCount = 0;
var numRows = 4;
var flag = 1; // 1 - getRow(); 2 - getRows(); 3 - to close resultSet.
connection.execute(
"BEGIN get_emp_rs(:in, :out); END;",
{
in: 200,
out: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT }
},
function(err, result) {
should.not.exist(err);
fetchRowFromRS(result.outBinds.out, done);
}
);
function fetchRowFromRS(rs, cb) {
if(flag === 1) {
rs.getRow(function(err, row) {
should.not.exist(err);
if(row) {
flag = 2;
accessCount++;
return fetchRowFromRS(rs, cb);
} else {
flag = 3;
return fetchRowFromRS(rs, cb);
}
});
}
else if(flag === 2) {
rs.getRows(numRows, function(err, rows) {
should.not.exist(err);
if(rows.length > 0) {
flag = 1;
accessCount++;
return fetchRowFromRS(rs, cb);
} else {
flag = 3;
return fetchRowFromRS(rs, cb);
}
});
}
else if(flag === 3) {
// console.log("resultSet is empty!");
rs.close(function(err) {
should.not.exist(err);
// console.log("Total access count is " + accessCount);
accessCount.should.be.exactly((100/(numRows + 1)) * 2);
cb();
});
}
}
})
}) })
describe('55.4 release connetion before close resultSet', function() { describe('55.4 release connection before close resultSet', function() {
var conn2 = false; var conn2 = false;
before(function(done) { function fetchRowFromRS(rs, cb) {
rs.getRow(function(err, row) {
if(row) {
return fetchRowFromRS(rs, cb);
} else {
conn2.release(function(err) {
should.not.exist(err);
rs.close(function(err) {
should.exist(err);
err.message.should.startWith('NJS-003'); // invalid connection
cb();
});
});
}
});
}
beforeEach(function(done) {
oracledb.getConnection( oracledb.getConnection(
credential, credential,
function(err, conn) { function(err, conn) {
@ -244,7 +372,7 @@ describe('55 resultSet2.js', function() {
); );
}) })
it('55.4.1 ', function(done) { it('55.4.1 result set', function(done) {
conn2.should.be.ok; conn2.should.be.ok;
conn2.execute( conn2.execute(
"SELECT * FROM oracledb_employees", "SELECT * FROM oracledb_employees",
@ -252,28 +380,25 @@ describe('55 resultSet2.js', function() {
{ resultSet: true }, { resultSet: true },
function(err, result) { function(err, result) {
should.not.exist(err); should.not.exist(err);
fetchRowFromRS(result.resultSet); fetchRowFromRS(result.resultSet, done);
} }
); );
})
it('55.4.2 REF Cursor', function(done) {
conn2.should.be.ok;
function fetchRowFromRS(rs) { conn2.execute(
rs.getRow(function(err, row) { "BEGIN get_emp_rs(:in, :out); END;",
{
in: 200,
out: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT }
},
function(err, result) {
should.not.exist(err); should.not.exist(err);
if(row) { fetchRowFromRS(result.outBinds.out, done);
return fetchRowFromRS(rs); }
} else { );
conn2.release(function(err) {
should.not.exist(err);
rs.close(function(err) {
should.exist(err);
err.message.should.startWith('NJS-003');
done();
});
});
}
});
}
}) })
}) })
@ -312,13 +437,13 @@ describe('55 resultSet2.js', function() {
], done); ], done);
function fetchRowFromRS(rset, cb) { function fetchRowFromRS(rset, cb) {
rs.getRow(function(err, row) { rset.getRow(function(err, row) {
should.not.exist(err); should.not.exist(err);
if(row) { if(row) {
rowsCount++; rowsCount++;
return fetchRowFromRS(rset, cb); return fetchRowFromRS(rset, cb);
} else { } else {
rs.close(function(err) { rset.close(function(err) {
should.not.exist(err); should.not.exist(err);
rowsCount.should.eql(rowsAmount); rowsCount.should.eql(rowsAmount);
cb(); cb();
@ -328,14 +453,45 @@ describe('55 resultSet2.js', function() {
} }
}) })
}) })
describe('55.6 access resultSet simultaneously', function() { describe('55.6 access resultSet simultaneously', function() {
var numRows = 10; // number of rows to return from each call to getRows()
function fetchRowFromRS(rs, cb) {
rs.getRow(function(err, row) {
if(err) {
cb(err);
return;
} else {
if(row) {
return fetchRowFromRS(rs, cb);
} else {
cb();
}
}
});
}
function fetchRowsFromRS(rs, cb) {
rs.getRows(numRows, function(err, rows) {
if(err) {
cb(err);
return;
} else {
if(rows.length > 0) {
return fetchRowsFromRS(rs, cb);
} else {
cb();
}
}
});
}
it('55.6.1 concurrent operations on resultSet are not allowed', function(done) { it('55.6.1 concurrent operations on resultSet are not allowed', function(done) {
connection.should.be.ok; connection.should.be.ok;
var rowCount1 = 0;
var rowCount2 = 0;
var numRows = 10; // number of rows to return from each call to getRows()
connection.execute( connection.execute(
"SELECT * FROM oracledb_employees", "SELECT * FROM oracledb_employees",
[], [],
@ -364,49 +520,80 @@ describe('55 resultSet2.js', function() {
} }
}); });
} }
); );
function fetchRowFromRS(rs, cb) {
rs.getRow(function(err, row) {
if(err) {
cb(err);
return;
} else {
if(row) {
rowCount1++;
return fetchRowFromRS(rs, cb);
} else {
cb();
}
}
});
}
function fetchRowsFromRS(rs, cb) {
rs.getRows(numRows, function(err, rows) {
//should.not.exist(err);
if(err) {
cb(err);
return;
} else {
if(rows.length > 0) {
rowCount2 += 10;
return fetchRowsFromRS(rs, cb);
} else {
cb();
}
}
});
}
}) })
it('55.6.2 concurrent operation on REF Cursor are not allowed', function(done) {
connection.should.be.ok;
connection.execute(
"BEGIN get_emp_rs(:in, :out); END;",
{
in: 0,
out: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT }
},
function(err, result) {
should.not.exist(err);
async.parallel([
function(callback) {
fetchRowFromRS(result.outBinds.out, callback);
},
function(callback) {
fetchRowsFromRS(result.outBinds.out, callback);
}
], function(err) {
if(err) {
// console.log(err);
err.message.should.startWith('NJS-017');
result.outBinds.out.close(function(err) {
done();
});
} else {
result.outBinds.out.close(function(error) {
should.not.exist(error);
done();
});
}
});
}
);
})
}) })
describe('55.7 getting multiple resultSets', function() { describe('55.7 getting multiple resultSets', function() {
var numRows = 10; // number of rows to return from each call to getRows()
function fetchRowFromRS(rs, cb) {
rs.getRow(function(err, row) {
should.not.exist(err);
if(row) {
return fetchRowFromRS(rs, cb);
} else {
rs.close(function(err) {
should.not.exist(err);
cb();
});
}
});
}
function fetchRowsFromRS(rs, cb) {
rs.getRows(numRows, function(err, rows) {
should.not.exist(err);
if(rows.length > 0) {
return fetchRowsFromRS(rs, cb);
} else {
rs.close(function(err) {
should.not.exist(err);
cb();
});
}
});
}
it('55.7.1 can access multiple resultSet on one connection', function(done) { it('55.7.1 can access multiple resultSet on one connection', function(done) {
connection.should.be.ok; connection.should.be.ok;
var rowCount1 = 0;
var rowCount2 = 0;
var numRows = 10; // number of rows to return from each call to getRows()
async.parallel([ async.parallel([
function(callback) { function(callback) {
connection.execute( connection.execute(
@ -434,37 +621,42 @@ describe('55 resultSet2.js', function() {
should.not.exist(err); should.not.exist(err);
done(); done();
}); });
})
it('55.7.2 can access multiple REF Cursor', function(done) {
connection.should.be.ok;
function fetchRowFromRS(rs, cb) { async.parallel([
rs.getRow(function(err, row) { function(callback) {
should.not.exist(err); connection.execute(
if(row) { "BEGIN get_emp_rs(:in, :out); END;",
rowCount1++; {
return fetchRowFromRS(rs, cb); in: 200,
} else { out: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT }
rs.close(function(err) { },
function(err, result) {
should.not.exist(err); should.not.exist(err);
cb(); fetchRowFromRS(result.outBinds.out, callback);
}); }
} );
}); },
} function(callback) {
connection.execute(
function fetchRowsFromRS(rs, cb) { "BEGIN get_emp_rs(:in, :out); END;",
rs.getRows(numRows, function(err, rows) { {
should.not.exist(err); in: 100,
if(rows.length > 0) { out: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT }
rowCount2 += numRows; },
return fetchRowsFromRS(rs, cb); function(err, result) {
} else {
rs.close(function(err) {
should.not.exist(err); should.not.exist(err);
cb(); fetchRowsFromRS(result.outBinds.out, callback);
}); }
} );
}
}); ], function(err) {
} should.not.exist(err);
done();
});
}) })
}) })
@ -486,23 +678,155 @@ describe('55 resultSet2.js', function() {
}) })
}) })
describe('55.9 test querying a PL/SQL function', function() {
it('55.9.1 ', function(done) {
var proc =
"CREATE OR REPLACE FUNCTION testfunc RETURN VARCHAR2 \
IS \
emp_name VARCHAR2(20); \
BEGIN \
SELECT 'Clark Kent' INTO emp_name FROM dual; \
RETURN emp_name; \
END; ";
async.series([
function(callback) {
connection.execute(
proc,
function(err) {
should.not.exist(err);
callback();
}
);
},
function(callback) {
connection.execute(
"SELECT testfunc FROM dual",
[],
{ resultSet: true },
function(err, result) {
should.not.exist(err);
(result.resultSet.metaData[0].name).should.eql('TESTFUNC');
fetchRowFromRS(result.resultSet, callback);
}
);
},
function(callback) {
connection.execute(
"DROP FUNCTION testfunc",
function(err, result) {
should.not.exist(err);
callback();
}
);
}
], done);
function fetchRowFromRS(rs, cb) {
rs.getRow(function(err, row) {
should.not.exist(err);
if(row) {
row[0].should.eql('Clark Kent');
return fetchRowFromRS(rs, cb);
} else {
rs.close(function(err) {
should.not.exist(err);
cb();
});
}
});
}
})
})
describe('55.10 calls getRows() once and then close RS before getting more rows', function() {
it('55.10.1 ', function(done) {
connection.should.be.ok;
var numRows = 10;
var closeRS = true;
connection.execute(
"SELECT * FROM oracledb_employees",
[],
{ resultSet: true },
function(err, result) {
should.not.exist(err);
result.resultSet.getRows(
numRows,
function(err, rows) {
should.not.exist(err);
result.resultSet.close(function(err) {
should.not.exist(err);
fetchRowsFromRS(result.resultSet, numRows, done);
});
}
);
}
);
function fetchRowsFromRS(rs, numRows, done) {
rs.getRows(numRows, function(err, rows) {
should.exist(err);
err.message.should.startWith('NJS-018:'); // invalid result set
done();
});
}
})
})
describe('55.11 deals with unsupported database with result set', function() {
var sql1 = "select dummy, HEXTORAW('0123456789ABCDEF0123456789ABCDEF') from dual";
var sql2 = "SELECT dummy, rowid FROM dual";
function fetchOneRowFromRS(rs, cb) {
rs.getRow(function(err, row) {
/* Currently, even if the driver doesn't support certain data type
* the result set can still be created.
*/
// Error at accessing RS
if(err) {
// console.error("Error at accessing RS: " + err.message);
// NJS-010: unsupported data type in select list
(err.message).should.startWith('NJS-010');
rs.close( function(err) {
should.not.exist(err);
cb();
});
} else if(row) {
console.log(row);
fetchOneRowFromRS(rs, cb);
} else {
rs.close( function(err) {
should.not.exist(err);
cb();
});
}
});
}
it('55.11.1 RAW data type', function(done) {
connection.should.be.ok;
connection.execute(
sql1,
[],
{ resultSet: true },
function(err, result) {
should.not.exist(err);
fetchOneRowFromRS(result.resultSet, done);
}
);
})
it('55.11.2 ROWID date type', function(done) {
connection.execute(
sql2,
[],
{ resultSet: true },
function(err, result) {
should.not.exist(err);
fetchOneRowFromRS(result.resultSet, done);
}
);
})
})
}) })