Updates for 1.9.0 Development branch
This commit is contained in:
parent
db5950f1cf
commit
8c52101005
30
CHANGELOG.md
30
CHANGELOG.md
|
@ -1,5 +1,35 @@
|
|||
# Change Log
|
||||
|
||||
## node-oracledb v1.9.0 Development (19 Apr 2016)
|
||||
|
||||
** Note this is a development release: features are subject to change.**
|
||||
|
||||
- Added Promise support. All asynchronous functions can now return
|
||||
promises. By default the standard Promise library is used for Node
|
||||
0.12, 4 and 5. This can be overridden.
|
||||
|
||||
- Added a `toQueryStream()` method for ResultSets, letting REF CURSORS
|
||||
be transformed into Readable Streams.
|
||||
|
||||
- Added an experimental query Stream `_close()` method. It allows query
|
||||
streams to be closed without needing to fetch all the data. It is
|
||||
not for production use.
|
||||
|
||||
- Added aliases `pool.close()` and `connection.close()` for
|
||||
`pool.terminate()` and `connection.release()` respectively.
|
||||
|
||||
- Some method parameter validation checks, such as the number or types
|
||||
of parameters, will now throw errors synchronously instead of
|
||||
returning errors via the callback.
|
||||
|
||||
- Removed an extra call to `getRows()` made by `queryStream()` at
|
||||
end-of-fetch.
|
||||
|
||||
- Some random crashes caused by connections being garbage collected
|
||||
while still in use should no longer occur.
|
||||
|
||||
- Regularized NJS error message capitalization.
|
||||
|
||||
## node-oracledb v1.8.0 (24 Mar 2016)
|
||||
|
||||
- Added `connection.queryStream()` for returning query results using a
|
||||
|
|
68
INSTALL.md
68
INSTALL.md
|
@ -402,47 +402,13 @@ Download the [Node.js package](http://nodejs.org) for OS X 64-bit and install it
|
|||
|
||||
### 5.3 Install the free Oracle Instant Client 'Basic' and 'SDK' ZIPs
|
||||
|
||||
Do either of the options given in [5.3.1](#instosxICroot) or [5.3.2](#instosxICuser).
|
||||
Follow the steps in either [5.3.1](#instosxICuser) or [5.3.2](#instosxICroot).
|
||||
|
||||
### <a name="instosxICroot"></a> 5.3.1 Install Instant Client in /opt
|
||||
|
||||
This first installation option puts Instant Client in the default
|
||||
location used by the node-oracledb installer. It requires root
|
||||
access. If you don't want to update system directories then follow
|
||||
the alternative steps in [5.3.2](#instosxICuser).
|
||||
|
||||
Download the free **Basic** and **SDK** ZIPs from
|
||||
[Oracle Technology Network](http://www.oracle.com/technetwork/topics/intel-macsoft-096467.html)
|
||||
and
|
||||
[install them](http://www.oracle.com/technetwork/topics/intel-macsoft-096467.html#ic_osx_inst)
|
||||
into the same directory:
|
||||
|
||||
```
|
||||
sudo su -
|
||||
unzip instantclient-basic-macos.x64-11.2.0.4.0.zip
|
||||
unzip instantclient-sdk-macos.x64-11.2.0.4.0.zip
|
||||
mkdir /opt/oracle
|
||||
mv instantclient_11_2 /opt/oracle/instantclient
|
||||
ln -s /opt/oracle/instantclient/libclntsh.dylib.11.1 /opt/oracle/instantclient/libclntsh.dylib
|
||||
```
|
||||
|
||||
Link the OCI libraries into the default library path:
|
||||
|
||||
```
|
||||
ln -s /opt/oracle/instantclient/{libclntsh.dylib.11.1,libnnz11.dylib,libociei.dylib} /usr/local/lib/
|
||||
```
|
||||
|
||||
Continue with [5.4](#instosxICaddon).
|
||||
|
||||
### <a name="instosxICuser"></a> 5.3.2 Install Instant Client in a user directory
|
||||
|
||||
This is an alternative to [5.3.1](#instosxICroot) that does not require root access.
|
||||
### <a name="instosxICuser"></a> 5.3.1 Install Instant Client in a user directory
|
||||
|
||||
Download the free **Basic** and **SDK** 64-bit ZIPs from
|
||||
[Oracle Technology Network](http://www.oracle.com/technetwork/topics/intel-macsoft-096467.html)
|
||||
and
|
||||
[install them](http://www.oracle.com/technetwork/topics/intel-macsoft-096467.html#ic_osx_inst)
|
||||
into the same directory:
|
||||
and unzip them somewhere under your home directory:
|
||||
|
||||
```
|
||||
unzip instantclient-basic-macos.x64-11.2.0.4.0.zip
|
||||
|
@ -469,6 +435,34 @@ export OCI_INC_DIR=~/instantclient_11_2/sdk/include
|
|||
|
||||
These variables are only needed during installation.
|
||||
|
||||
Continue with [5.4](#instosxICaddon).
|
||||
|
||||
### <a name="instosxICroot"></a> 5.3.2 Install Instant Client in /opt
|
||||
|
||||
This alternative to [5.3.1](#instosxICroot) requires root access. It
|
||||
puts Instant Client in the default location used by the node-oracledb
|
||||
installer. If you don't want to update system directories then follow
|
||||
the steps in [5.3.1](#instosxICuser) instead.
|
||||
|
||||
Download the free **Basic** and **SDK** ZIPs from
|
||||
[Oracle Technology Network](http://www.oracle.com/technetwork/topics/intel-macsoft-096467.html)
|
||||
and install them into the same directory:
|
||||
|
||||
```
|
||||
sudo su -
|
||||
unzip instantclient-basic-macos.x64-11.2.0.4.0.zip
|
||||
unzip instantclient-sdk-macos.x64-11.2.0.4.0.zip
|
||||
mkdir /opt/oracle
|
||||
mv instantclient_11_2 /opt/oracle/instantclient
|
||||
ln -s /opt/oracle/instantclient/libclntsh.dylib.11.1 /opt/oracle/instantclient/libclntsh.dylib
|
||||
```
|
||||
|
||||
Link the OCI libraries into the default library path:
|
||||
|
||||
```
|
||||
ln -s /opt/oracle/instantclient/{libclntsh.dylib.11.1,libnnz11.dylib,libociei.dylib} /usr/local/lib/
|
||||
```
|
||||
|
||||
### <a name="instosxICaddon"></a> 5.4 Install the add-on
|
||||
|
||||
If you are behind a firewall you may need to set your proxy, for
|
||||
|
|
23
README.md
23
README.md
|
@ -1,11 +1,11 @@
|
|||
# node-oracledb version 1.8
|
||||
# node-oracledb version 1.9
|
||||
|
||||
## <a name="about"></a> About node-oracledb
|
||||
|
||||
The node-oracledb add-on for Node.js powers high performance Oracle
|
||||
Database applications.
|
||||
|
||||
Use node-oracledb to connect Node.js 0.10, 0.12, 4 LTS and 5 to
|
||||
Use node-oracledb to connect Node.js 0.10, 0.12, 4 and 5 to
|
||||
Oracle Database.
|
||||
|
||||
The add-on is stable, well documented, and has a comprehensive test suite.
|
||||
|
@ -15,11 +15,12 @@ The node-oracledb project is open source and maintained by Oracle Corp. The hom
|
|||
|
||||
### Node-oracledb supports:
|
||||
|
||||
- [Promises](https://github.com/oracle/node-oracledb/blob/master/doc/api.md#promiseoverview), Callbacks and Streams
|
||||
- [SQL and PL/SQL execution](https://github.com/oracle/node-oracledb/blob/master/doc/api.md#sqlexecution)
|
||||
- Fetching of query results by [callbacks](https://github.com/oracle/node-oracledb/blob/master/doc/api.md#resultsethandling) or [streams](https://github.com/oracle/node-oracledb/blob/master/doc/api.md#streamingresults)
|
||||
- [REF CURSORs](https://github.com/oracle/node-oracledb/blob/master/doc/api.md#refcursors)
|
||||
- [Large Objects: CLOBs and BLOBs](https://github.com/oracle/node-oracledb/blob/master/doc/api.md#lobhandling)
|
||||
- [Query results as JavaScript objects or array ](https://github.com/oracle/node-oracledb/blob/master/doc/api.md#queryoutputformats)
|
||||
- Oracle Database 12.1 [JSON datatype](http://docs.oracle.com/database/121/ADXDB/json.htm#ADXDB6246)
|
||||
- [Query results as JavaScript objects or arrays](https://github.com/oracle/node-oracledb/blob/master/doc/api.md#queryoutputformats)
|
||||
- [Smart mapping between JavaScript and Oracle types with manual override available](https://github.com/oracle/node-oracledb/blob/master/doc/api.md#typemap)
|
||||
- [Data binding using JavaScript objects or arrays](https://github.com/oracle/node-oracledb/blob/master/doc/api.md#bind)
|
||||
- [Transaction Management](https://github.com/oracle/node-oracledb/blob/master/doc/api.md#transactionmgt)
|
||||
|
@ -30,11 +31,15 @@ The node-oracledb project is open source and maintained by Oracle Corp. The hom
|
|||
- [Statement Caching](https://github.com/oracle/node-oracledb/blob/master/doc/api.md#stmtcache)
|
||||
- [Client Result Caching](http://docs.oracle.com/database/121/ADFNS/adfns_perf_scale.htm#ADFNS464)
|
||||
- [End-to-end Tracing, Mid-tier Authentication, and Auditing](https://github.com/oracle/node-oracledb/blob/master/doc/api.md#endtoend)
|
||||
- High Availability Features
|
||||
- Oracle High Availability Features
|
||||
- [Fast Application Notification (FAN)](http://docs.oracle.com/database/121/ADFNS/adfns_avail.htm#ADFNS538)
|
||||
- [Runtime Load Balancing (RLB)](http://docs.oracle.com/database/121/ADFNS/adfns_perf_scale.htm#ADFNS515)
|
||||
- [Transparent Application Failover (TAF)](http://docs.oracle.com/database/121/ADFNS/adfns_avail.htm#ADFNS534)
|
||||
|
||||
Various Oracle Database and Oracle Client versions, can be used.
|
||||
Oracle's cross-version compatibility allows one node-oracledb
|
||||
installation to connect to different database versions.
|
||||
|
||||
We are actively working on supporting the best Oracle Database
|
||||
features, and on functionality requests from
|
||||
[users involved in the project](https://github.com/oracle/node-oracledb/issues).
|
||||
|
@ -45,7 +50,7 @@ Prerequisites:
|
|||
|
||||
- [Python 2.7](https://www.python.org/downloads/)
|
||||
- C Compiler with support for C++ 11 (Xcode, gcc, Visual Studio or similar)
|
||||
- The small, free [Oracle Instant Client](http://www.oracle.com/technetwork/database/features/instant-client/index-100365.html) "basic" and "SDK" packages if your database is remote. Or use a locally installed database such as the free [Oracle XE](http://www.oracle.com/technetwork/database/database-technologies/express-edition/overview/index.html) release
|
||||
- The small, free [Oracle Instant Client](http://www.oracle.com/technetwork/database/features/instant-client/index-100365.html) "basic" and "SDK" packages if your database is remote. Or use the libraries and headers from a locally installed database such as the free [Oracle XE](http://www.oracle.com/technetwork/database/database-technologies/express-edition/overview/index.html) release
|
||||
- Set `OCI_LIB_DIR` and `OCI_INC_DIR` during installation if the Oracle libraries and headers are in a non-default location
|
||||
|
||||
Run `npm install oracledb` to install from the [NPM registry](https://www.npmjs.com/package/oracledb).
|
||||
|
@ -56,7 +61,7 @@ See [INSTALL](https://github.com/oracle/node-oracledb/tree/master/INSTALL.md) fo
|
|||
|
||||
There are examples in the [examples](https://github.com/oracle/node-oracledb/tree/master/examples) directory.
|
||||
|
||||
### A simple query example:
|
||||
### A simple query example with callbacks:
|
||||
|
||||
```javascript
|
||||
var oracledb = require('oracledb');
|
||||
|
@ -90,6 +95,8 @@ With Oracle's sample HR schema, the output is:
|
|||
[ [ 60, 'IT' ], [ 90, 'Executive' ], [ 100, 'Finance' ] ]
|
||||
```
|
||||
|
||||
Node Promises can also be used.
|
||||
|
||||
## <a name="doc"></a> Documentation
|
||||
|
||||
See [Documentation for the Oracle Database Node.js Add-on](https://github.com/oracle/node-oracledb/tree/master/doc/api.md).
|
||||
|
@ -98,7 +105,7 @@ See [Documentation for the Oracle Database Node.js Add-on](https://github.com/or
|
|||
|
||||
See [CHANGELOG](https://github.com/oracle/node-oracledb/tree/master/CHANGELOG.md)
|
||||
|
||||
## <a name="testing"></a> Testsuite
|
||||
## <a name="testing"></a> Test Suite
|
||||
|
||||
To run the included test suite see [test/README](https://github.com/oracle/node-oracledb/tree/master/test/README.md).
|
||||
|
||||
|
|
707
doc/api.md
707
doc/api.md
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,59 @@
|
|||
/* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. */
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* You may not use the identified files except in compliance with the Apache
|
||||
* License, Version 2.0 (the "License.")
|
||||
*
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* NAME
|
||||
* promises.js
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Executes a basic query using promises instead of the callback pattern.
|
||||
*
|
||||
* Scripts to create the HR schema can be found at:
|
||||
* https://github.com/oracle/db-sample-schemas
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
var oracledb = require('oracledb');
|
||||
var dbConfig = require('./dbconfig.js');
|
||||
|
||||
oracledb.getConnection(
|
||||
{
|
||||
user : dbConfig.user,
|
||||
password : dbConfig.password,
|
||||
connectString : dbConfig.connectString
|
||||
})
|
||||
.then(function(connection) {
|
||||
return connection.execute(
|
||||
"SELECT department_id, department_name " +
|
||||
"FROM departments " +
|
||||
"WHERE department_id = :did",
|
||||
[180]
|
||||
)
|
||||
.then(function(result) {
|
||||
console.log(result.metaData);
|
||||
console.log(result.rows);
|
||||
|
||||
return connection.release();
|
||||
})
|
||||
.catch(function(err) {
|
||||
console.log(err.message);
|
||||
|
||||
return connection.release();
|
||||
});
|
||||
})
|
||||
.catch(function(err) {
|
||||
console.error(err.message);
|
||||
});
|
|
@ -19,7 +19,9 @@
|
|||
* refcursor.js
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Shows using a Result Set to fetch rows from a REF CURSOR
|
||||
* Shows using a ResultSet to fetch rows from a REF CURSOR using getRows().
|
||||
* Streaming is also possible (this is not shown).
|
||||
*
|
||||
* Uses Oracle's sample HR schema.
|
||||
* Use demo.sql to create the required procedure or do:
|
||||
*
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
/* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. */
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* You may not use the identified files except in compliance with the Apache
|
||||
* License, Version 2.0 (the "License.")
|
||||
*
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* NAME
|
||||
* refcursortoquerystream.js
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Converts a refcursor (returned from execute) to a query stream for an
|
||||
* alternative means of processing instead of using resultSet.getRows().
|
||||
*
|
||||
* Scripts to create the HR schema can be found at:
|
||||
* https://github.com/oracle/db-sample-schemas
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
var oracledb = require('oracledb');
|
||||
var dbConfig = require('./dbconfig.js');
|
||||
|
||||
oracledb.getConnection(
|
||||
{
|
||||
user : dbConfig.user,
|
||||
password : dbConfig.password,
|
||||
connectString : dbConfig.connectString
|
||||
},
|
||||
function(err, connection) {
|
||||
if (err) {
|
||||
console.error(err.message);
|
||||
return;
|
||||
}
|
||||
|
||||
connection.execute(
|
||||
"BEGIN"
|
||||
+ " OPEN :cursor FOR SELECT department_id, department_name FROM departments;"
|
||||
+ "END;",
|
||||
{
|
||||
cursor: { type: oracledb.CURSOR, dir : oracledb.BIND_OUT }
|
||||
},
|
||||
function(err, result) {
|
||||
var cursor;
|
||||
var queryStream;
|
||||
|
||||
if (err) {
|
||||
console.error(err.message);
|
||||
doRelease(connection);
|
||||
return;
|
||||
}
|
||||
|
||||
cursor = result.outBinds.cursor;
|
||||
queryStream = cursor.toQueryStream();
|
||||
|
||||
queryStream.on('data', function (row) {
|
||||
console.log(row);
|
||||
});
|
||||
|
||||
queryStream.on('error', function (err) {
|
||||
console.error(err.message);
|
||||
doRelease(connection);
|
||||
});
|
||||
|
||||
queryStream.on('end', function () {
|
||||
doRelease(connection);
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function doRelease(connection) {
|
||||
connection.release(
|
||||
function(err) {
|
||||
if (err) {
|
||||
console.error(err.message);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
|
@ -17,16 +17,44 @@
|
|||
*
|
||||
*****************************************************************************/
|
||||
|
||||
'use strict';
|
||||
|
||||
var resultset = require('./resultset.js');
|
||||
var Stream = require('./resultset-read-stream');
|
||||
var QueryStream = require('./querystream.js');
|
||||
var nodbUtil = require('./util.js');
|
||||
|
||||
// The queryStream function is similar to execute except that it immediately
|
||||
// returns a readable stream.
|
||||
// returns a QueryStream.
|
||||
function queryStream(sql, binding, options) {
|
||||
var self = this;
|
||||
var stream;
|
||||
|
||||
stream = new Stream(self, sql, binding, options);
|
||||
nodbUtil.assert(arguments.length > 0 && arguments.length < 4, 'NJS-009');
|
||||
nodbUtil.assert(typeof sql === 'string', 'NJS-006', 1);
|
||||
|
||||
if (binding) {
|
||||
nodbUtil.assert(nodbUtil.isObjectOrArray(binding), 'NJS-006', 2);
|
||||
}
|
||||
|
||||
if (options) {
|
||||
nodbUtil.assert(nodbUtil.isObject(options), 'NJS-006', 3);
|
||||
}
|
||||
|
||||
binding = binding || [];
|
||||
options = options || {};
|
||||
|
||||
options.resultSet = true;
|
||||
|
||||
stream = new QueryStream(null, self._oracledb);
|
||||
|
||||
self._execute(sql, binding, options, function(err, result) {
|
||||
if (err) {
|
||||
stream._open(err, null);
|
||||
} else {
|
||||
resultset.extend(result.resultSet, self._oracledb);
|
||||
stream._open(null, result.resultSet);
|
||||
}
|
||||
});
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
@ -39,24 +67,45 @@ function execute(a1, a2, a3, a4) {
|
|||
var executeCb;
|
||||
var custExecuteCb;
|
||||
|
||||
// Added this check so that node doesn't hang if no arguments are passed.
|
||||
if (arguments.length < 2 || arguments.length > 4) {
|
||||
if (arguments.length && typeof arguments[arguments.length - 1] === 'function') {
|
||||
arguments[arguments.length - 1](new Error('NJS-009: invalid number of parameters'));
|
||||
return;
|
||||
} else {
|
||||
throw new Error('NJS-009: invalid number of parameters');
|
||||
}
|
||||
nodbUtil.assert(arguments.length > 1 && arguments.length < 5, 'NJS-009');
|
||||
nodbUtil.assert(typeof a1 === 'string', 'NJS-006', 1);
|
||||
|
||||
switch (arguments.length) {
|
||||
case 2:
|
||||
nodbUtil.assert(typeof a2 === 'function', 'NJS-006', 2);
|
||||
break;
|
||||
case 3:
|
||||
nodbUtil.assert(nodbUtil.isObjectOrArray(a2), 'NJS-006', 2);
|
||||
nodbUtil.assert(typeof a3 === 'function', 'NJS-006', 3);
|
||||
break;
|
||||
case 4:
|
||||
nodbUtil.assert(nodbUtil.isObjectOrArray(a2), 'NJS-006', 2);
|
||||
nodbUtil.assert(nodbUtil.isObject(a3), 'NJS-006', 3);
|
||||
nodbUtil.assert(typeof a4 === 'function', 'NJS-006', 4);
|
||||
break;
|
||||
}
|
||||
|
||||
custExecuteCb = function(err, result) {
|
||||
var outBindsKeys;
|
||||
var outBindsIdx;
|
||||
|
||||
if (err) {
|
||||
executeCb(err);
|
||||
return;
|
||||
}
|
||||
|
||||
// Need to extend resultsets which may come from either the query results
|
||||
// or outBinds.
|
||||
if (result.resultSet) {
|
||||
resultset.extend(result.resultSet);
|
||||
resultset.extend(result.resultSet, self._oracledb);
|
||||
} else if (result.outBinds) {
|
||||
outBindsKeys = Object.keys(result.outBinds);
|
||||
|
||||
for (outBindsIdx = 0; outBindsIdx < outBindsKeys.length; outBindsIdx += 1) {
|
||||
if (result.outBinds[outBindsKeys[outBindsIdx]] instanceof self._oracledb.ResultSet) {
|
||||
resultset.extend(result.outBinds[outBindsKeys[outBindsIdx]], self._oracledb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
executeCb(null, result);
|
||||
|
@ -79,16 +128,22 @@ function execute(a1, a2, a3, a4) {
|
|||
}
|
||||
|
||||
// This commit function is just a place holder to allow for easier extension later.
|
||||
function commit() {
|
||||
function commit(commitCb) {
|
||||
var self = this;
|
||||
|
||||
nodbUtil.assert(arguments.length === 1, 'NJS-009');
|
||||
nodbUtil.assert(typeof commitCb === 'function', 'NJS-006', 1);
|
||||
|
||||
self._commit.apply(self, arguments);
|
||||
}
|
||||
|
||||
// This rollback function is just a place holder to allow for easier extension later.
|
||||
function rollback() {
|
||||
function rollback(rollbackCb) {
|
||||
var self = this;
|
||||
|
||||
nodbUtil.assert(arguments.length === 1, 'NJS-009');
|
||||
nodbUtil.assert(typeof rollbackCb === 'function', 'NJS-006', 1);
|
||||
|
||||
self._rollback.apply(self, arguments);
|
||||
}
|
||||
|
||||
|
@ -99,23 +154,31 @@ function rollback() {
|
|||
function release(releaseCb) {
|
||||
var self = this;
|
||||
|
||||
// _pool will only exist on connections obtained from a pool.
|
||||
if (self._pool && self._pool.queueRequests !== false) {
|
||||
nodbUtil.assert(arguments.length === 1, 'NJS-009');
|
||||
nodbUtil.assert(typeof releaseCb === 'function', 'NJS-006', 1);
|
||||
|
||||
self._release(function(err) {
|
||||
releaseCb(err);
|
||||
|
||||
// pool will only exist for connections obtained from a pool.
|
||||
if (self._pool && self._pool.queueRequests !== false) {
|
||||
self._pool._onConnectionRelease();
|
||||
});
|
||||
} else {
|
||||
self._release(releaseCb);
|
||||
}
|
||||
|
||||
// Need to maintain a reference to the connection instance to ensure that the
|
||||
// garbage collector doesn't destroy it too soon.
|
||||
self = undefined;
|
||||
});
|
||||
}
|
||||
|
||||
// This release function is just a place holder to allow for easier extension later.
|
||||
// It's attached to the module as break is a reserved word.
|
||||
module.break = function() {
|
||||
module.break = function(breakCb) {
|
||||
var self = this;
|
||||
|
||||
nodbUtil.assert(arguments.length === 1, 'NJS-009');
|
||||
nodbUtil.assert(typeof breakCb === 'function', 'NJS-006', 1);
|
||||
|
||||
self._break.apply(self, arguments);
|
||||
};
|
||||
|
||||
|
@ -143,7 +206,7 @@ function extend(conn, oracledb, pool) {
|
|||
writable: true
|
||||
},
|
||||
execute: {
|
||||
value: execute,
|
||||
value: nodbUtil.promisify(execute),
|
||||
enumerable: true,
|
||||
writable: true
|
||||
},
|
||||
|
@ -151,7 +214,7 @@ function extend(conn, oracledb, pool) {
|
|||
value: conn.commit
|
||||
},
|
||||
commit: {
|
||||
value: commit,
|
||||
value: nodbUtil.promisify(commit),
|
||||
enumerable: true,
|
||||
writable: true
|
||||
},
|
||||
|
@ -159,7 +222,7 @@ function extend(conn, oracledb, pool) {
|
|||
value: conn.rollback
|
||||
},
|
||||
rollback: {
|
||||
value: rollback,
|
||||
value: nodbUtil.promisify(rollback),
|
||||
enumerable: true,
|
||||
writable: true
|
||||
},
|
||||
|
@ -167,7 +230,12 @@ function extend(conn, oracledb, pool) {
|
|||
value: conn.release
|
||||
},
|
||||
release: {
|
||||
value: release,
|
||||
value: nodbUtil.promisify(release),
|
||||
enumerable: true,
|
||||
writable: true
|
||||
},
|
||||
close: { // alias for release
|
||||
value: nodbUtil.promisify(release),
|
||||
enumerable: true,
|
||||
writable: true
|
||||
},
|
||||
|
@ -175,7 +243,7 @@ function extend(conn, oracledb, pool) {
|
|||
value: conn.break
|
||||
},
|
||||
break: {
|
||||
value: module.break,
|
||||
value: nodbUtil.promisify(module.break),
|
||||
enumerable: true,
|
||||
writable: true
|
||||
}
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
*
|
||||
*****************************************************************************/
|
||||
|
||||
'use strict';
|
||||
|
||||
var Duplex = require('stream').Duplex;
|
||||
var util = require('util');
|
||||
|
||||
|
|
|
@ -17,11 +17,14 @@
|
|||
*
|
||||
*****************************************************************************/
|
||||
|
||||
'use strict';
|
||||
|
||||
var oracledbCLib;
|
||||
var oracledbInst;
|
||||
var Lob = require('./lob.js').Lob;
|
||||
var pool = require('./pool.js');
|
||||
var connection = require('./connection.js');
|
||||
var nodbUtil = require('./util.js');
|
||||
|
||||
try {
|
||||
oracledbCLib = require('../build/Release/oracledb');
|
||||
|
@ -43,6 +46,10 @@ oracledbCLib.Oracledb.prototype.newLob = function(iLob) {
|
|||
function createPool(poolAttrs, createPoolCb) {
|
||||
var self = this;
|
||||
|
||||
nodbUtil.assert(arguments.length === 2, 'NJS-009');
|
||||
nodbUtil.assert(nodbUtil.isObject(poolAttrs), 'NJS-006', 1);
|
||||
nodbUtil.assert(typeof createPoolCb === 'function', 'NJS-006', 2);
|
||||
|
||||
self._createPool(poolAttrs, function(err, poolInst) {
|
||||
if (err) {
|
||||
createPoolCb(err);
|
||||
|
@ -61,6 +68,10 @@ function createPool(poolAttrs, createPoolCb) {
|
|||
function getConnection(connAttrs, createConnectionCb) {
|
||||
var self = this;
|
||||
|
||||
nodbUtil.assert(arguments.length === 2, 'NJS-009');
|
||||
nodbUtil.assert(nodbUtil.isObject(connAttrs), 'NJS-006', 1);
|
||||
nodbUtil.assert(typeof createConnectionCb === 'function', 'NJS-006', 2);
|
||||
|
||||
self._getConnection(connAttrs, function(err, connInst) {
|
||||
if (err) {
|
||||
createConnectionCb(err);
|
||||
|
@ -83,6 +94,9 @@ function extend(oracledb) {
|
|||
Object.defineProperties(
|
||||
oracledb,
|
||||
{
|
||||
_oracledb: { // Known to be used in util.js' promisify function.
|
||||
value: oracledb
|
||||
},
|
||||
DEFAULT: {
|
||||
value: 0,
|
||||
enumerable: true
|
||||
|
@ -135,6 +149,11 @@ function extend(oracledb) {
|
|||
value: 4002,
|
||||
enumerable: true
|
||||
},
|
||||
Promise: {
|
||||
value: global.Promise,
|
||||
enumerable: true,
|
||||
writable: true
|
||||
},
|
||||
Oracledb: {
|
||||
value: oracledbCLib.Oracledb,
|
||||
enumerable: true
|
||||
|
@ -169,7 +188,7 @@ function extend(oracledb) {
|
|||
value: oracledb.createPool
|
||||
},
|
||||
createPool: {
|
||||
value: createPool,
|
||||
value: nodbUtil.promisify(createPool),
|
||||
enumerable: true,
|
||||
writable: true
|
||||
},
|
||||
|
@ -177,7 +196,7 @@ function extend(oracledb) {
|
|||
value: oracledb.getConnection
|
||||
},
|
||||
getConnection: {
|
||||
value: getConnection,
|
||||
value: nodbUtil.promisify(getConnection),
|
||||
enumerable: true,
|
||||
writable: true
|
||||
}
|
||||
|
@ -185,7 +204,7 @@ function extend(oracledb) {
|
|||
);
|
||||
}
|
||||
|
||||
oracledbInst = new oracledbCLib.Oracledb;
|
||||
oracledbInst = new oracledbCLib.Oracledb();
|
||||
|
||||
extend(oracledbInst);
|
||||
|
||||
|
|
50
lib/pool.js
50
lib/pool.js
|
@ -17,7 +17,10 @@
|
|||
*
|
||||
*****************************************************************************/
|
||||
|
||||
'use strict';
|
||||
|
||||
var connection = require('./connection.js');
|
||||
var nodbUtil = require('./util.js');
|
||||
|
||||
// completeConnectionRequest does the actual work of getting a connection from a
|
||||
// pool when queuing is enabled. It's abstracted out so it can be called from
|
||||
|
@ -119,7 +122,7 @@ function onRequestTimeout(timerIdx) {
|
|||
self._connRequestQueue.splice(requestIndex, 1);
|
||||
self._connRequestTimersMap[timerIdx] = null;
|
||||
|
||||
payloadToDequeue.getConnectionCb(new Error('NJS-040: connection request timeout'));
|
||||
payloadToDequeue.getConnectionCb(new Error(nodbUtil.getErrorMessage('NJS-040')));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -134,6 +137,9 @@ function getConnection(getConnectionCb) {
|
|||
var timeoutHandle;
|
||||
var timerIdx;
|
||||
|
||||
nodbUtil.assert(arguments.length === 1, 'NJS-009');
|
||||
nodbUtil.assert(typeof getConnectionCb === 'function', 'NJS-006', 1);
|
||||
|
||||
// Added this check because if the pool isn't valid and we reference self.poolMax
|
||||
// (which is a C layer getter) an error will be thrown.
|
||||
if (!self._isValid) {
|
||||
|
@ -150,21 +156,21 @@ function getConnection(getConnectionCb) {
|
|||
}
|
||||
|
||||
if (self.queueRequests === false) { // queueing is disabled for pool
|
||||
if (self._enableStats) {
|
||||
self._getConnection(function(err, connInst) {
|
||||
if (err) {
|
||||
if (self._enableStats) {
|
||||
self._totalFailedRequests += 1;
|
||||
}
|
||||
|
||||
getConnectionCb(err);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
connection.extend(connInst, self._oracledb, self);
|
||||
|
||||
getConnectionCb(null, connInst);
|
||||
});
|
||||
} else {
|
||||
self._getConnection(getConnectionCb);
|
||||
}
|
||||
} else if (self._connectionsOut < self.poolMax) { // queueing enabled, but not needed
|
||||
completeConnectionRequest.call(self, getConnectionCb);
|
||||
} else { // need to queue the request
|
||||
|
@ -204,6 +210,9 @@ function getConnection(getConnectionCb) {
|
|||
function terminate(terminateCb) {
|
||||
var self = this;
|
||||
|
||||
nodbUtil.assert(arguments.length === 1, 'NJS-009');
|
||||
nodbUtil.assert(typeof terminateCb === 'function', 'NJS-006', 1);
|
||||
|
||||
self._terminate(function(err) {
|
||||
if (!err) {
|
||||
self._isValid = false;
|
||||
|
@ -290,13 +299,23 @@ function extend(pool, poolAttrs, oracledb) {
|
|||
_oracledb: { // storing a reference to the base instance to avoid circular references with require
|
||||
value: oracledb
|
||||
},
|
||||
queueRequests: {
|
||||
value: queueRequests, // true will queue requests when conn pool is maxed out
|
||||
enumerable: true
|
||||
queueRequests: { // true will queue requests when conn pool is maxed out
|
||||
enumerable: true,
|
||||
get: function() {
|
||||
return queueRequests;
|
||||
},
|
||||
queueTimeout: {
|
||||
value: queueTimeout, // milliseconds a connection request can spend in queue before being failed
|
||||
enumerable: true
|
||||
set: function() {
|
||||
throw new Error(nodbUtil.getErrorMessage('NJS-014', 'queueRequests'));
|
||||
}
|
||||
},
|
||||
queueTimeout: { // milliseconds a connection request can spend in queue before being failed
|
||||
enumerable: true,
|
||||
get: function() {
|
||||
return queueTimeout;
|
||||
},
|
||||
set: function() {
|
||||
throw new Error(nodbUtil.getErrorMessage('NJS-014', 'queueTimeout'));
|
||||
}
|
||||
},
|
||||
_isValid: { // used to ensure operations are not done after terminate
|
||||
value: true,
|
||||
|
@ -373,7 +392,7 @@ function extend(pool, poolAttrs, oracledb) {
|
|||
value: pool.getConnection
|
||||
},
|
||||
getConnection: {
|
||||
value: getConnection,
|
||||
value: nodbUtil.promisify(getConnection),
|
||||
enumerable: true,
|
||||
writable: true
|
||||
},
|
||||
|
@ -381,7 +400,12 @@ function extend(pool, poolAttrs, oracledb) {
|
|||
value: pool.terminate
|
||||
},
|
||||
terminate: {
|
||||
value: terminate,
|
||||
value: nodbUtil.promisify(terminate),
|
||||
enumerable: true,
|
||||
writable: true
|
||||
},
|
||||
close: { // alias for terminate
|
||||
value: nodbUtil.promisify(terminate),
|
||||
enumerable: true,
|
||||
writable: true
|
||||
}
|
||||
|
|
|
@ -0,0 +1,226 @@
|
|||
/* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. */
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* You may not use the identified files except in compliance with the Apache
|
||||
* License, Version 2.0 (the "License.")
|
||||
*
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
'use strict';
|
||||
|
||||
var util = require('util');
|
||||
var Readable = require('stream').Readable;
|
||||
|
||||
// This class was originally based on https://github.com/sagiegurari/simple-oracledb/blob/master/lib/resultset-read-stream.js
|
||||
function QueryStream(resultSet, oracledb) {
|
||||
var self = this;
|
||||
|
||||
Object.defineProperties(
|
||||
self,
|
||||
{
|
||||
_oracledb: { // storing a reference to the base instance to avoid circular references with require
|
||||
value: oracledb
|
||||
},
|
||||
_resultSet: {
|
||||
value: resultSet,
|
||||
writable: true
|
||||
},
|
||||
_fetchedRows: { // a local cache of rows fetched from a call to resultSet.getRows
|
||||
value: [],
|
||||
writable: true
|
||||
},
|
||||
_fetchedAllRows: { // used to avoid an unnecessary call to resultSet.getRows
|
||||
value: false,
|
||||
writable: true
|
||||
},
|
||||
_fetching: { // used to serialize method calls on the resultset
|
||||
value: false,
|
||||
writable: true
|
||||
},
|
||||
_closed: { // used to track that the stream is closed
|
||||
value: false,
|
||||
writable: true
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
Readable.call(self, {
|
||||
objectMode: true
|
||||
});
|
||||
|
||||
if (self._resultSet) { // If true, no need to invoke _open, we are ready to go.
|
||||
self.emit('metadata', self._resultSet.metaData);
|
||||
|
||||
self.emit('open');
|
||||
}
|
||||
}
|
||||
|
||||
util.inherits(QueryStream, Readable);
|
||||
|
||||
// The _open method is only meant to be called when a QueryStream is created
|
||||
// but not passed in the resultSet during initialization. In those cases the
|
||||
// QueryStream object will have been returned immediately and the _open method
|
||||
// will be called later to pass the resultset (or error getting the resultset)
|
||||
// along.
|
||||
QueryStream.prototype._open = function(err, rs) {
|
||||
var self = this;
|
||||
|
||||
if (err) {
|
||||
self.emit('error', err);
|
||||
return;
|
||||
}
|
||||
|
||||
self._resultSet = rs;
|
||||
|
||||
self.emit('metadata', self._resultSet.metaData);
|
||||
|
||||
// Trigger the event listener that may have been added in _read now that the
|
||||
// resultset is ready.
|
||||
self.emit('open');
|
||||
};
|
||||
|
||||
// The stream _read implementation which fetches the next row from the resultset.
|
||||
QueryStream.prototype._read = function () {
|
||||
var self = this;
|
||||
var fetchCount;
|
||||
|
||||
if (!self._resultSet) {
|
||||
// Still waiting on the resultset, add an event listener to retry when ready
|
||||
return self.once('open', function() {
|
||||
self._read();
|
||||
});
|
||||
}
|
||||
|
||||
if (self._closed) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (self._fetchedRows.length) {
|
||||
// We have rows already fetched that need to be pushed
|
||||
self.push(self._fetchedRows.shift());
|
||||
} else if (self._fetchedAllRows) {
|
||||
// Calling the C layer close directly to avoid assertions on the public method
|
||||
self._resultSet._close(function(err) {
|
||||
if (err) {
|
||||
self.emit('error', err);
|
||||
return;
|
||||
}
|
||||
|
||||
// Signal the end of the stream
|
||||
self.push(null);
|
||||
});
|
||||
} else {
|
||||
// Using _fetching to indicate that the resultset is working to avoid potential
|
||||
// errors related to close w/conncurrent operations on resultsets
|
||||
self._fetching = true;
|
||||
|
||||
fetchCount = self._oracledb.maxRows || 100;
|
||||
|
||||
// Calling the C layer getRows directly to avoid assertions on the public method
|
||||
self._resultSet._getRows(fetchCount, function(err, rows) {
|
||||
if (err) {
|
||||
// We'll return the error from getRows, but first try to close the resultSet.
|
||||
self._resultSet.close(function() {});
|
||||
|
||||
self.emit('error', err);
|
||||
return;
|
||||
}
|
||||
|
||||
self._fetching = false;
|
||||
|
||||
// Close may have been called while the resultset was fetching.
|
||||
if (self._closed) {
|
||||
// Trigger the event listener that may have been added in close now that
|
||||
// the resultset has finished working.
|
||||
self.emit('_doneFetching');
|
||||
return;
|
||||
}
|
||||
|
||||
self._fetchedRows = rows;
|
||||
|
||||
if (self._fetchedRows.length < fetchCount) {
|
||||
self._fetchedAllRows = true;
|
||||
}
|
||||
|
||||
if (self._fetchedRows.length) {
|
||||
self.push(self._fetchedRows.shift());
|
||||
} else { // No more rows to fetch
|
||||
// Calling the C layer close directly to avoid assertions on the public method
|
||||
self._resultSet._close(function(err) {
|
||||
if (err) {
|
||||
self.emit('error', err);
|
||||
return;
|
||||
}
|
||||
|
||||
// Signal the end of the stream
|
||||
self.push(null);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// The close method is not a standard method on stream instances in Node.js but
|
||||
// it was added to provide developers with a means of stopping the flow of data
|
||||
// and closing the stream without having to allow the entire resultset to finish
|
||||
// streaming.
|
||||
function close(callback) {
|
||||
var self = this;
|
||||
|
||||
// Setting _closed early to prevent _read invocations from being processed and
|
||||
// to allow _doneFetching to be emitted if needed.
|
||||
self._closed = true;
|
||||
|
||||
// We can't close the resultset if it's currently fetching. Add a listener
|
||||
// to call close when the resulset is done fetching.
|
||||
if (self._fetching) {
|
||||
self.once('_doneFetching', function() {
|
||||
self._close(callback);
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (callback) {
|
||||
self.once('close', callback);
|
||||
}
|
||||
|
||||
// It's possible for close to be called very early, even before the resultset
|
||||
// has been set via _open (if needed).
|
||||
if (!self._resultSet) {
|
||||
self.emit('close');
|
||||
} else {
|
||||
// Calling the C layer close directly to avoid assertions on the public method
|
||||
self._resultSet._close(function(err) {
|
||||
if (err) {
|
||||
self.emit('error', err);
|
||||
return;
|
||||
}
|
||||
|
||||
self.emit('close');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Exposing close as a private method for now.
|
||||
Object.defineProperty(
|
||||
QueryStream.prototype,
|
||||
'_close',
|
||||
{
|
||||
value: close,
|
||||
writable: true
|
||||
}
|
||||
);
|
||||
|
||||
module.exports = QueryStream;
|
|
@ -1,121 +0,0 @@
|
|||
/* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. */
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* You may not use the identified files except in compliance with the Apache
|
||||
* License, Version 2.0 (the "License.")
|
||||
*
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
var util = require('util');
|
||||
var stream = require('stream');
|
||||
var Readable = stream.Readable;
|
||||
var resultset = require('./resultset.js');
|
||||
|
||||
// A node.js read stream for resultsets (based on https://github.com/sagiegurari/simple-oracledb/blob/master/lib/resultset-read-stream.js).
|
||||
function ResultSetReadStream(conn, sql, binding, options) {
|
||||
var self = this;
|
||||
|
||||
binding = binding || [];
|
||||
options = options || {};
|
||||
|
||||
options.resultSet = true;
|
||||
|
||||
self.streamNumRows = conn._oracledb.maxRows || 100;
|
||||
|
||||
Readable.call(self, {
|
||||
objectMode: true
|
||||
});
|
||||
|
||||
Object.defineProperty(self, 'nextRow', {
|
||||
// Sets the nextRow value.
|
||||
set: function (nextRow) {
|
||||
self.next = nextRow;
|
||||
|
||||
if (self.inRead) {
|
||||
self._read();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
conn._execute(sql, binding, options, function(err, result) {
|
||||
self._onExecuteDone(err, result);
|
||||
});
|
||||
}
|
||||
|
||||
util.inherits(ResultSetReadStream, Readable);
|
||||
|
||||
// The stream _read implementation which fetches the next row from the resultset.
|
||||
ResultSetReadStream.prototype._read = function () {
|
||||
var self = this;
|
||||
|
||||
self.inRead = false;
|
||||
|
||||
if (self.next) {
|
||||
self.next(function onNextRowRead(error, data) {
|
||||
if (error) {
|
||||
self.emit('error', error);
|
||||
} else if (data) {
|
||||
self.push(data);
|
||||
} else {
|
||||
self.push(null);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
self.inRead = true;
|
||||
}
|
||||
};
|
||||
|
||||
ResultSetReadStream.prototype._onExecuteDone = function(err, result) {
|
||||
var self = this;
|
||||
|
||||
if (err) {
|
||||
self.nextRow = function emitError(streamCallback) {
|
||||
streamCallback(err);
|
||||
};
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
resultset.extend(result.resultSet);
|
||||
|
||||
self.emit('metadata', result.resultSet.metaData);
|
||||
|
||||
var close = function (streamCallback, causeError) {
|
||||
result.resultSet.close(function onClose(closeError) {
|
||||
streamCallback(causeError || closeError);
|
||||
});
|
||||
};
|
||||
|
||||
var readRows;
|
||||
|
||||
self.nextRow = function fetchNextRow(streamCallback) {
|
||||
if (readRows && readRows.length) {
|
||||
streamCallback(null, readRows.shift());
|
||||
} else {
|
||||
result.resultSet.getRows(self.streamNumRows, function onRow(rowError, rows) {
|
||||
if (rowError) {
|
||||
close(streamCallback, rowError);
|
||||
} else if ((!rows) || (!rows.length)) {
|
||||
close(streamCallback);
|
||||
} else {
|
||||
readRows = rows;
|
||||
|
||||
streamCallback(null, readRows.shift());
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
module.exports = ResultSetReadStream;
|
|
@ -17,41 +17,117 @@
|
|||
*
|
||||
*****************************************************************************/
|
||||
|
||||
'use strict';
|
||||
|
||||
var QueryStream = require('./querystream.js');
|
||||
var nodbUtil = require('./util.js');
|
||||
|
||||
// This close function is just a place holder to allow for easier extension later.
|
||||
function close() {
|
||||
function close(closeCb) {
|
||||
var self = this;
|
||||
|
||||
self._close.apply(self, arguments);
|
||||
nodbUtil.assert(arguments.length === 1, 'NJS-009');
|
||||
nodbUtil.assert(typeof closeCb === 'function', 'NJS-006', 1);
|
||||
|
||||
if (self._convertedToStream) {
|
||||
closeCb(new Error(nodbUtil.getErrorMessage('NJS-042')));
|
||||
return;
|
||||
}
|
||||
|
||||
self._processingStarted = true;
|
||||
|
||||
self._close(function(err) {
|
||||
// Need to maintain a reference to the resultset instance to ensure that the
|
||||
// garbage collector doesn't destroy it too soon.
|
||||
self = undefined;
|
||||
|
||||
closeCb(err);
|
||||
});
|
||||
}
|
||||
|
||||
// This getRow function is just a place holder to allow for easier extension later.
|
||||
function getRow() {
|
||||
function getRow(getRowCb) {
|
||||
var self = this;
|
||||
|
||||
nodbUtil.assert(arguments.length === 1, 'NJS-009');
|
||||
nodbUtil.assert(typeof getRowCb === 'function', 'NJS-006', 1);
|
||||
|
||||
if (self._convertedToStream) {
|
||||
getRowCb(new Error(nodbUtil.getErrorMessage('NJS-042')));
|
||||
return;
|
||||
}
|
||||
|
||||
self._processingStarted = true;
|
||||
|
||||
self._getRow.apply(self, arguments);
|
||||
}
|
||||
|
||||
// This getRows function is just a place holder to allow for easier extension later.
|
||||
function getRows() {
|
||||
function getRows(numRows, getRowsCb) {
|
||||
var self = this;
|
||||
|
||||
nodbUtil.assert(arguments.length === 2, 'NJS-009');
|
||||
nodbUtil.assert(typeof numRows === 'number', 'NJS-006', 1);
|
||||
nodbUtil.assert(typeof getRowsCb === 'function', 'NJS-006', 2);
|
||||
|
||||
if (self._convertedToStream) {
|
||||
getRowsCb(new Error(nodbUtil.getErrorMessage('NJS-042')));
|
||||
return;
|
||||
}
|
||||
|
||||
self._processingStarted = true;
|
||||
|
||||
self._getRows.apply(self, arguments);
|
||||
}
|
||||
|
||||
function toQueryStream() {
|
||||
var self = this;
|
||||
var stream;
|
||||
|
||||
nodbUtil.assert(arguments.length === 0, 'NJS-009');
|
||||
|
||||
if (self._processingStarted) {
|
||||
throw new Error(nodbUtil.getErrorMessage('NJS-041'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (self._convertedToStream) {
|
||||
throw new Error(nodbUtil.getErrorMessage('NJS-043'));
|
||||
return;
|
||||
}
|
||||
|
||||
self._convertedToStream = true;
|
||||
|
||||
stream = new QueryStream(self, self._oracledb);
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
// The extend method is used to extend the ResultSet instance from the C layer with
|
||||
// custom properties and method overrides. References to the original methods are
|
||||
// maintained so they can be invoked by the overriding method at the right time.
|
||||
function extend(resultSet) {
|
||||
function extend(resultSet, oracledb) {
|
||||
// Using Object.defineProperties to add properties to the ResultSet instance with
|
||||
// special properties, such as enumerable but not writable.
|
||||
Object.defineProperties(
|
||||
resultSet,
|
||||
{
|
||||
_oracledb: { // storing a reference to the base instance to avoid circular references with require
|
||||
value: oracledb
|
||||
},
|
||||
_processingStarted: { // used to prevent conversion to stream after invoking methods
|
||||
value: false,
|
||||
writable: true
|
||||
},
|
||||
_convertedToStream: { // used to prevent invoking methods after conversion to stream
|
||||
value: false,
|
||||
writable: true
|
||||
},
|
||||
_close: {
|
||||
value: resultSet.close
|
||||
},
|
||||
close: {
|
||||
value: close,
|
||||
value: nodbUtil.promisify(close),
|
||||
enumerable: true,
|
||||
writable: true
|
||||
},
|
||||
|
@ -59,7 +135,7 @@ function extend(resultSet) {
|
|||
value: resultSet.getRow
|
||||
},
|
||||
getRow: {
|
||||
value: getRow,
|
||||
value: nodbUtil.promisify(getRow),
|
||||
enumerable: true,
|
||||
writable: true
|
||||
},
|
||||
|
@ -67,7 +143,12 @@ function extend(resultSet) {
|
|||
value: resultSet.getRows
|
||||
},
|
||||
getRows: {
|
||||
value: getRows,
|
||||
value: nodbUtil.promisify(getRows),
|
||||
enumerable: true,
|
||||
writable: true
|
||||
},
|
||||
toQueryStream: {
|
||||
value: toQueryStream,
|
||||
enumerable: true,
|
||||
writable: true
|
||||
}
|
||||
|
|
|
@ -0,0 +1,122 @@
|
|||
/* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. */
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* You may not use the identified files except in compliance with the Apache
|
||||
* License, Version 2.0 (the "License.")
|
||||
*
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
var util = require('util');
|
||||
|
||||
// errorMessages is a temporary duplication of error messages defined in the C
|
||||
// layer that will be removed once a function to fetch from the C layer is added.
|
||||
var errorMessages = {
|
||||
'NJS-005': 'NJS-005: invalid value for parameter %d',
|
||||
'NJS-006': 'NJS-006: invalid type for parameter %d',
|
||||
'NJS-009': 'NJS-009: invalid number of parameters',
|
||||
'NJS-014': 'NJS-014: %s is a read-only property',
|
||||
'NJS-037': 'NJS-037: incompatible type of value provided',
|
||||
'NJS-040': 'NJS-040: connection request timeout',
|
||||
'NJS-041': 'NJS-041: cannot convert ResultSet to QueryStream after invoking methods',
|
||||
'NJS-042': 'NJS-042: cannot invoke ResultSet methods after converting to QueryStream',
|
||||
'NJS-043': "NJS-043: ResultSet already converted to QueryStream"
|
||||
};
|
||||
|
||||
// getErrorMessage is used to get and format error messages to make throwing errors
|
||||
// a little more convenient.
|
||||
function getErrorMessage(errorCode, messageArg1) {
|
||||
if (messageArg1) {
|
||||
return util.format(errorMessages[errorCode], messageArg1);
|
||||
} else {
|
||||
return util.format(errorMessages[errorCode]);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports.getErrorMessage = getErrorMessage;
|
||||
|
||||
// assert it typically used in the beginning of public functions to assert preconditions
|
||||
// for the function to execute. Most commonly it's used to validate arguments lenght
|
||||
// and types and throw an error if they don't match what is expected.
|
||||
function assert(condition, errorCode, messageArg1) {
|
||||
if (!condition) {
|
||||
throw new Error(getErrorMessage(errorCode, messageArg1));
|
||||
}
|
||||
}
|
||||
|
||||
module.exports.assert = assert;
|
||||
|
||||
// The promisify function is used to wrap async methods to add optional promise
|
||||
// support. If the last parameter passed to a method is a function, then it is
|
||||
// assumed that the callback pattern is being used and the method is invoked as
|
||||
// usual. Otherwise a promise is returned and later resolved or rejected based on
|
||||
// the return of the method.
|
||||
function promisify(func) {
|
||||
return function() {
|
||||
var self = this;
|
||||
var args;
|
||||
|
||||
// This/self could refer to the base class instance, pool, connection, etc. All
|
||||
// class instances have a private reference to the base class for convenience.
|
||||
if (!self._oracledb.Promise || typeof arguments[arguments.length - 1] === 'function') {
|
||||
return func.apply(self, arguments);
|
||||
} else {
|
||||
// Converting to an array so we can extend it later with a custom callback
|
||||
args = Array.prototype.slice.call(arguments);
|
||||
|
||||
return new self._oracledb.Promise(function(resolve, reject) {
|
||||
var errorCode;
|
||||
|
||||
try {
|
||||
args[args.length] = function(err, result) {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(result);
|
||||
}
|
||||
};
|
||||
|
||||
func.apply(self, args);
|
||||
} catch (err) {
|
||||
errorCode = err.message.substr(0, 7);
|
||||
|
||||
// Check for invalid number or type of parameter(s) as they should be
|
||||
// eagerly thrown.
|
||||
if (errorCode === 'NJS-009' || errorCode === 'NJS-006') {
|
||||
// Throwing the error outside of the promise wrapper so that its not
|
||||
// swallowed up as a rejection.
|
||||
process.nextTick(function() {
|
||||
throw err;
|
||||
});
|
||||
} else {
|
||||
reject(err);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
module.exports.promisify = promisify;
|
||||
|
||||
function isObject(value) {
|
||||
return value !== null && typeof value === 'object';
|
||||
}
|
||||
|
||||
module.exports.isObject = isObject;
|
||||
|
||||
function isObjectOrArray(value) {
|
||||
return (value !== null && typeof value === 'object') || Array.isArray(value);
|
||||
}
|
||||
|
||||
module.exports.isObjectOrArray = isObjectOrArray;
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "oracledb",
|
||||
"version": "1.8.0",
|
||||
"version": "1.9.0",
|
||||
"description": "Oracle Database driver by Oracle Corp.",
|
||||
"license": "Apache-2.0",
|
||||
"homepage": "http://www.oracle.com/technetwork/database/database-technologies/scripting-languages/node_js/",
|
||||
|
|
|
@ -51,9 +51,9 @@ static const char *errMsg[] =
|
|||
"NJS-013: invalid bind direction",
|
||||
"NJS-014: %s is a read-only property",
|
||||
"NJS-016: buffer is too small for OUT binds",
|
||||
"NJS-017: concurrent operations on resultSet are not allowed",
|
||||
"NJS-017: concurrent operations on ResultSet are not allowed",
|
||||
"NJS-018: invalid result set",
|
||||
"NJS-019: resultSet cannot be returned for non-query statements",
|
||||
"NJS-019: ResultSet cannot be returned for non-query statements",
|
||||
"NJS-020: empty array was specified to fetch values as string",
|
||||
"NJS-021: invalid type for conversion specified",
|
||||
"NJS-022: invalid LOB",
|
||||
|
@ -63,13 +63,10 @@ static const char *errMsg[] =
|
|||
"NJS-026: maxRows must be greater than zero",
|
||||
"NJS-027: unexpected SQL parsing error",
|
||||
"NJS-028: raw database type is not supported with DML Returning statements",
|
||||
"NJS-029: Invalid object from javascript",
|
||||
"NJS-030: connection cannot be released because Lob operations are in"
|
||||
" progress",
|
||||
"NJS-031: connection cannot be released because ResultSet operations are"
|
||||
" in progress",
|
||||
"NJS-032: connection cannot be released because a database call is in"
|
||||
" progress",
|
||||
"NJS-029: invalid object from JavaScript",
|
||||
"NJS-030: connection cannot be released because Lob operations are in progress",
|
||||
"NJS-031: connection cannot be released because ResultSet operations are in progress",
|
||||
"NJS-032: connection cannot be released because a database call is in progress",
|
||||
"NJS-033: an internal error occurred. [%s][%s]",
|
||||
"NJS-034: data type is unsupported for array bind",
|
||||
"NJS-035: maxArraySize is required for IN OUT array bind",
|
||||
|
@ -78,6 +75,9 @@ static const char *errMsg[] =
|
|||
"NJS-038: maxArraySize value should be greater than 0",
|
||||
"NJS-039: empty array is not allowed for IN bind",
|
||||
"NJS-040: connection request timeout",
|
||||
"NJS-041: cannot convert ResultSet to QueryStream after invoking methods",
|
||||
"NJS-042: cannot invoke ResultSet methods after converting to QueryStream",
|
||||
"NJS-043: ResultSet already converted to QueryStream",
|
||||
};
|
||||
|
||||
string NJSMessages::getErrorMsg ( NJSErrorType err, ... )
|
||||
|
|
|
@ -74,6 +74,9 @@ typedef enum
|
|||
errInvalidValueArrayBind,
|
||||
errEmptyArray,
|
||||
errConnRequestTimeout,
|
||||
errCannotConvertRsToStream,
|
||||
errCannotInvokeRsMethods,
|
||||
errResultSetAlreadyConverted,
|
||||
|
||||
// New ones should be added here
|
||||
|
||||
|
|
|
@ -69,7 +69,7 @@ using namespace v8;
|
|||
|
||||
/* Keep the version in sync with package.json */
|
||||
#define NJS_NODE_ORACLEDB_MAJOR 1
|
||||
#define NJS_NODE_ORACLEDB_MINOR 8
|
||||
#define NJS_NODE_ORACLEDB_MINOR 9
|
||||
#define NJS_NODE_ORACLEDB_PATCH 0
|
||||
|
||||
/* Used for Oracledb.version */
|
||||
|
|
|
@ -718,7 +718,6 @@ describe('1. connection.js', function(){
|
|||
|
||||
describe('1.6 Testing parameter assertions', function() {
|
||||
var conn1;
|
||||
var sql = 'select 1 from dual';
|
||||
|
||||
beforeEach('get connection ready', function(done) {
|
||||
oracledb.getConnection(credential, function(err, conn) {
|
||||
|
@ -735,37 +734,173 @@ describe('1. connection.js', function(){
|
|||
});
|
||||
});
|
||||
|
||||
it('1.6.1 too few params without a callback should throw error', function(done) {
|
||||
try {
|
||||
conn1.execute(sql);
|
||||
} catch (err) {
|
||||
it('1.6.1 too few params should throw an error', function(done) {
|
||||
// This test returns a promise because the last parameter to execute is not
|
||||
// a function. Normally, errors thrown in a promise would be directed to
|
||||
// to a catch handler. In the case of an "accidental promise" the error
|
||||
// could go undetected. Because of this, the promisify function in util.js
|
||||
// uses process.nextTick to throw invalid number or type of params (NJS-009
|
||||
// and NJS-006). This test has been updated to account for this behavior.
|
||||
var promiseSupportEnabled = oracledb.Promise !== undefined;
|
||||
var listeners = process.listeners('uncaughtException');
|
||||
|
||||
if (promiseSupportEnabled) {
|
||||
process.removeAllListeners('uncaughtException');
|
||||
|
||||
process.once('uncaughtException', function(err) {
|
||||
listeners.forEach(function(listener) {
|
||||
process.on('uncaughtException', listener);
|
||||
});
|
||||
|
||||
should.exist(err);
|
||||
|
||||
done();
|
||||
});
|
||||
}
|
||||
|
||||
// Using try catch for instances where promises are not supported or have
|
||||
// been disabled by setting oracledb.Promise to something falsey.
|
||||
try {
|
||||
conn1.execute();
|
||||
} catch (err) {
|
||||
if (promiseSupportEnabled) {
|
||||
listeners.forEach(function(listener) {
|
||||
process.on('uncaughtException', listener);
|
||||
});
|
||||
}
|
||||
|
||||
should.exist(err);
|
||||
|
||||
done();
|
||||
}
|
||||
});
|
||||
|
||||
it('1.6.2 too few params with a callback should pass error in callback', function(done) {
|
||||
conn1.execute(function(err, result) {
|
||||
should.exist(err);
|
||||
done();
|
||||
});
|
||||
it('1.6.2 too many params should throw error', function(done) {
|
||||
// This test returns a promise because the last parameter to execute is not
|
||||
// a function. Normally, errors thrown in a promise would be directed to
|
||||
// to a catch handler. In the case of an "accidental promise" the error
|
||||
// could go undetected. Because of this, the promisify function in util.js
|
||||
// uses process.nextTick to throw invalid number or type of params (NJS-009
|
||||
// and NJS-006). This test has been updated to account for this behavior.
|
||||
var promiseSupportEnabled = oracledb.Promise !== undefined;
|
||||
var listeners = process.listeners('uncaughtException');
|
||||
|
||||
if (promiseSupportEnabled) {
|
||||
process.removeAllListeners('uncaughtException');
|
||||
|
||||
process.once('uncaughtException', function(err) {
|
||||
listeners.forEach(function(listener) {
|
||||
process.on('uncaughtException', listener);
|
||||
});
|
||||
|
||||
it('1.6.3 too many params without a callback should throw error', function(done) {
|
||||
should.exist(err);
|
||||
|
||||
done();
|
||||
});
|
||||
}
|
||||
|
||||
// Using try catch for instances where promises are not supported or have
|
||||
// been disabled by setting oracledb.Promise to something falsey.
|
||||
try {
|
||||
conn1.execute(1, 2, 3, 4, 5);
|
||||
} catch (err) {
|
||||
if (promiseSupportEnabled) {
|
||||
listeners.forEach(function(listener) {
|
||||
process.on('uncaughtException', listener);
|
||||
});
|
||||
}
|
||||
should.exist(err);
|
||||
|
||||
done();
|
||||
}
|
||||
});
|
||||
|
||||
it('1.6.3 wrong type for param 1 should throw an error', function(done) {
|
||||
// Don't need to listen for unhandledRejection because a promise will not
|
||||
// be returned as the last param is a function.
|
||||
try {
|
||||
conn1.execute(1, function() {});
|
||||
} catch (err) {
|
||||
should.exist(err);
|
||||
done();
|
||||
}
|
||||
});
|
||||
|
||||
it('1.6.4 too many params with a callback should pass error in callback', function(done) {
|
||||
conn1.execute(1, 2, 3, 4, function(err, result) {
|
||||
it('1.6.4 wrong type for param 2 should throw an error', function(done) {
|
||||
// This test returns a promise because the last parameter to execute is not
|
||||
// a function. Normally, errors thrown in a promise would be directed to
|
||||
// to a catch handler. In the case of an "accidental promise" the error
|
||||
// could go undetected. Because of this, the promisify function in util.js
|
||||
// uses process.nextTick to throw invalid number or type of params (NJS-009
|
||||
// and NJS-006). This test has been updated to account for this behavior.
|
||||
var promiseSupportEnabled = oracledb.Promise !== undefined;
|
||||
var listeners = process.listeners('uncaughtException');
|
||||
|
||||
if (promiseSupportEnabled) {
|
||||
process.removeAllListeners('uncaughtException');
|
||||
|
||||
process.once('uncaughtException', function(err) {
|
||||
listeners.forEach(function(listener) {
|
||||
process.on('uncaughtException', listener);
|
||||
});
|
||||
|
||||
should.exist(err);
|
||||
|
||||
done();
|
||||
});
|
||||
}
|
||||
|
||||
// Using try catch for instances where promises are not supported or have
|
||||
// been disabled by setting oracledb.Promise to something falsey.
|
||||
try {
|
||||
conn1.execute('select 1 from dual', 1);
|
||||
} catch (err) {
|
||||
if (promiseSupportEnabled) {
|
||||
listeners.forEach(function(listener) {
|
||||
process.on('uncaughtException', listener);
|
||||
});
|
||||
}
|
||||
|
||||
should.exist(err);
|
||||
|
||||
done();
|
||||
}
|
||||
});
|
||||
|
||||
it('1.6.5 wrong type for param 3 should throw an error', function(done) {
|
||||
// Don't need to listen for unhandledRejection because a promise will not
|
||||
// be returned as the last param is a function.
|
||||
try {
|
||||
conn1.execute('select 1 from dual', 1, function() {});
|
||||
} catch (err) {
|
||||
should.exist(err);
|
||||
done();
|
||||
}
|
||||
});
|
||||
|
||||
it('1.6.6 wrong type for param 4 should throw an error', function(done) {
|
||||
// Don't need to listen for unhandledRejection because a promise will not
|
||||
// be returned as the last param is a function.
|
||||
try {
|
||||
conn1.execute('select 1 from dual', {}, 1, function() {});
|
||||
} catch (err) {
|
||||
should.exist(err);
|
||||
done();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('1.7 Close method', function() {
|
||||
it('1.7.1 close can be used as an alternative to release', function(done) {
|
||||
oracledb.getConnection(credential, function(err, conn) {
|
||||
should.not.exist(err);
|
||||
|
||||
conn.close(function(err) {
|
||||
should.not.exist(err);
|
||||
done();
|
||||
});
|
||||
});
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
})
|
||||
});
|
||||
|
|
|
@ -18,6 +18,15 @@
|
|||
1.5 Testing commit() & rollback() functions
|
||||
1.5.1 commit() function works well
|
||||
1.5.2 rollback() function works well
|
||||
1.6 Testing parameter assertions
|
||||
1.6.1 too few params should throw an error
|
||||
1.6.2 too many params should throw error
|
||||
1.6.3 wrong type for param 1 should throw an error
|
||||
1.6.4 wrong type for param 2 should throw an error
|
||||
1.6.5 wrong type for param 3 should throw an error
|
||||
1.6.6 wrong type for param 4 should throw an error
|
||||
1.7 Close method
|
||||
1.7.1 close can be used as an alternative to release
|
||||
|
||||
2. pool.js
|
||||
2.1 default values
|
||||
|
@ -57,6 +66,8 @@
|
|||
2.8.4 does not generate NJS-040 if request is queued for less time than queueTimeout
|
||||
2.9 connection request queue (_enableStats & _logStats functionality)_logStats must be called prior to terminating pool.
|
||||
2.9.1 works after the pool as been terminated
|
||||
2.10 Close method
|
||||
2.10.1 close can be used as an alternative to release
|
||||
|
||||
|
||||
3. examples.js
|
||||
|
@ -227,7 +238,7 @@
|
|||
12.7.2 maxRows option is ignored with REF Cursor
|
||||
|
||||
13. stream.js
|
||||
13.1 Testing ResultSet stream
|
||||
13.1 Testing QueryStream
|
||||
13.1.1 stream results for oracle connection
|
||||
13.1.2 stream results for oracle connection (outFormat: oracledb.OBJECT)
|
||||
13.1.3 errors in query
|
||||
|
@ -239,6 +250,13 @@
|
|||
13.1.9 Read CLOBs after stream close
|
||||
13.1.10 meta data
|
||||
13.1.11 stream stress test
|
||||
13.2 Testing QueryStream._close
|
||||
13.2.1 should be able to stop the stream early with _close
|
||||
13.2.2 should be able to stop the stream before any data
|
||||
13.2.3 should invoke an optional callback passed to _close
|
||||
13.3 Testing QueryStream\'s maxRows control
|
||||
13.3.1 should use oracledb.maxRows for fetching
|
||||
13.3.2 should default to 100 if oracledb.maxRows is falsey
|
||||
|
||||
14. stream2.js
|
||||
14.1 Bind by position and return an array
|
||||
|
@ -249,7 +267,32 @@
|
|||
14.6 maxRows option is ignored as expect
|
||||
14.7 Negative - queryStream() has no parameters
|
||||
14.8 Negative - give invalid SQL as first parameter
|
||||
14.9 Negatvie - give non-query SQL
|
||||
14.9 Negative - give non-query SQL
|
||||
|
||||
15. resultsetToQueryStream.js
|
||||
15.1 Testing ResultSet.toQueryStream
|
||||
15.1.1 should allow resultsets to be converted to streams
|
||||
15.2 Testing ResultSet/QueryStream conversion errors
|
||||
15.2.1 should prevent conversion to stream after getRow is invoked
|
||||
15.2.2 should prevent conversion to stream after getRows is invoked
|
||||
15.2.3 should prevent conversion to stream after close is invoked
|
||||
15.2.4 should prevent invoking getRow after conversion to stream
|
||||
15.2.5 should prevent invoking getRows after conversion to stream
|
||||
15.2.6 should prevent invoking close after conversion to stream
|
||||
15.2.7 should prevent calling toQueryStream more than once
|
||||
|
||||
16. promises.js
|
||||
16.1 returns a promise from oracledb.getConnection
|
||||
16.2 returns a promise from oracledb.createPool
|
||||
16.3 returns a promise from pool.terminate
|
||||
16.4 returns a promise from pool.getConnection
|
||||
16.5 returns a promise from connection.release
|
||||
16.6 returns a promise from connection.execute
|
||||
16.7 returns a promise from connection.commit
|
||||
16.8 returns a promise form connection.rollback
|
||||
16.9 returns a promise from resultSet.close
|
||||
16.10 returns a promise from resultSet.getRow
|
||||
16.11 returns a promise from resultSet.getRows
|
||||
|
||||
21. datatypeAssist.js
|
||||
|
||||
|
|
34
test/pool.js
34
test/pool.js
|
@ -640,12 +640,14 @@ describe('2. pool.js', function(){
|
|||
);
|
||||
});
|
||||
|
||||
it('2.7.1 throws error if called after pool is terminated and a callback is not provided', function(done) {
|
||||
// Skipping this test because assertions were added to the JS layer for all
|
||||
// public methods. This now throws NJS-009: invalid number of parameters.
|
||||
it.skip('2.7.1 throws error if called after pool is terminated and a callback is not provided', function(done) {
|
||||
pool1.terminate(function(err) {
|
||||
should.not.exist(err);
|
||||
|
||||
try {
|
||||
pool1.getConnection(1);
|
||||
pool1.getConnection();
|
||||
} catch (err) {
|
||||
should.exist(err);
|
||||
(err.message).should.startWith('NJS-002: invalid pool');
|
||||
|
@ -953,4 +955,30 @@ describe('2. pool.js', function(){
|
|||
);
|
||||
});
|
||||
});
|
||||
})
|
||||
|
||||
describe('2.10 Close method', function(){
|
||||
it('2.10.1 close can be used as an alternative to release', function(done) {
|
||||
oracledb.createPool(
|
||||
{
|
||||
externalAuth : credential.externalAuth,
|
||||
user : credential.user,
|
||||
password : credential.password,
|
||||
connectString : credential.connectString,
|
||||
poolMin : 0,
|
||||
poolMax : 1,
|
||||
poolIncrement : 1,
|
||||
poolTimeout : 1
|
||||
},
|
||||
function(err, pool){
|
||||
should.not.exist(err);
|
||||
|
||||
pool.close(function(err) {
|
||||
should.not.exist(err);
|
||||
|
||||
done();
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -0,0 +1,339 @@
|
|||
/* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. */
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* You may not use the identified files except in compliance with the Apache
|
||||
* License, Version 2.0 (the "License.")
|
||||
*
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* The node-oracledb test suite uses 'mocha', 'should' and 'async'.
|
||||
* See LICENSE.md for relevant licenses.
|
||||
*
|
||||
* NAME
|
||||
* 16. promises.js
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Promise tests.
|
||||
*
|
||||
* 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');
|
||||
|
||||
// Need to skip these tests if Promises are not supported
|
||||
var it = (oracledb.Promise) ? global.it : global.it.skip;
|
||||
|
||||
describe('16. promises.js', function(){
|
||||
|
||||
it('16.1 returns a promise from oracledb.getConnection', function(done) {
|
||||
var promise = oracledb.getConnection(dbConfig);
|
||||
|
||||
promise.should.be.an.instanceof(oracledb.Promise);
|
||||
|
||||
promise
|
||||
.then(function(conn) {
|
||||
conn.should.be.ok;
|
||||
conn.release(function(err) {
|
||||
if (err)
|
||||
return done(err);
|
||||
else
|
||||
return done();
|
||||
});
|
||||
})
|
||||
.catch(function(err) {
|
||||
return done(err);
|
||||
});
|
||||
})
|
||||
|
||||
it('16.2 returns a promise from oracledb.createPool', function(done) {
|
||||
var promise = oracledb.createPool(dbConfig);
|
||||
|
||||
promise.should.be.an.instanceof(oracledb.Promise);
|
||||
|
||||
promise
|
||||
.then(function(pool) {
|
||||
pool.should.be.ok;
|
||||
pool.terminate(function(err) {
|
||||
if (err)
|
||||
return done(err);
|
||||
else
|
||||
return done();
|
||||
});
|
||||
})
|
||||
.catch(function(err) {
|
||||
return done(err);
|
||||
});
|
||||
})
|
||||
|
||||
it('16.3 returns a promise from pool.terminate', function(done) {
|
||||
oracledb.createPool(dbConfig)
|
||||
.then(function(pool) {
|
||||
pool.should.be.ok;
|
||||
var promise = pool.terminate();
|
||||
promise.should.be.an.instanceof(oracledb.Promise);
|
||||
return promise;
|
||||
})
|
||||
.then(function() {
|
||||
return done();
|
||||
})
|
||||
.catch(function(err) {
|
||||
return done(err);
|
||||
});
|
||||
})
|
||||
|
||||
it('16.4 returns a promise from pool.getConnection', function(done) {
|
||||
oracledb.createPool(dbConfig)
|
||||
.then(function(pool) {
|
||||
pool.should.be.ok;
|
||||
var getConnPromise = pool.getConnection();
|
||||
getConnPromise.should.be.an.instanceof(oracledb.Promise);
|
||||
getConnPromise
|
||||
.then(function(conn) {
|
||||
conn.release(function(err) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
|
||||
pool.terminate()
|
||||
.then(function() {
|
||||
return done();
|
||||
})
|
||||
.catch(function(err) {
|
||||
return done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
})
|
||||
.catch(function(err) {
|
||||
return done(err);
|
||||
});
|
||||
})
|
||||
|
||||
it('16.5 returns a promise from connection.release', function(done) {
|
||||
oracledb.getConnection(dbConfig)
|
||||
.then(function(conn) {
|
||||
conn.should.be.ok;
|
||||
var promise = conn.release();
|
||||
promise.should.be.an.instanceof(oracledb.Promise);
|
||||
return promise;
|
||||
})
|
||||
.then(function() {
|
||||
return done();
|
||||
})
|
||||
.catch(function(err) {
|
||||
return done(err);
|
||||
});
|
||||
})
|
||||
|
||||
it('16.6 returns a promise from connection.execute', function(done) {
|
||||
oracledb.getConnection(dbConfig)
|
||||
.then(function(conn) {
|
||||
conn.should.be.ok;
|
||||
var executePromise = conn.execute('select 1 from dual');
|
||||
executePromise.should.be.an.instanceof(oracledb.Promise);
|
||||
return executePromise
|
||||
.then(function(result) {
|
||||
result.rows[0][0].should.eql(1);
|
||||
|
||||
return conn.release()
|
||||
.then(done);
|
||||
});
|
||||
})
|
||||
.catch(function(err) {
|
||||
return done(err);
|
||||
});
|
||||
})
|
||||
|
||||
it('16.7 returns a promise from connection.commit', function(done) {
|
||||
oracledb.getConnection(dbConfig)
|
||||
.then(function(conn) {
|
||||
var commitPromise;
|
||||
conn.should.be.ok;
|
||||
commitPromise = conn.commit();
|
||||
commitPromise.should.be.an.instanceof(oracledb.Promise);
|
||||
|
||||
return commitPromise
|
||||
.then(function() {
|
||||
return conn.release()
|
||||
.then(done);
|
||||
});
|
||||
})
|
||||
.catch(function(err) {
|
||||
return done(err);
|
||||
});
|
||||
})
|
||||
|
||||
it('16.8 returns a promise form connection.rollback', function(done) {
|
||||
oracledb.getConnection(dbConfig)
|
||||
.then(function(conn) {
|
||||
var rollbackPromise;
|
||||
conn.should.be.ok;
|
||||
rollbackPromise = conn.rollback();
|
||||
rollbackPromise.should.be.an.instanceof(oracledb.Promise);
|
||||
|
||||
return rollbackPromise
|
||||
.then(function() {
|
||||
return conn.release()
|
||||
.then(done);
|
||||
});
|
||||
})
|
||||
.catch(function(err) {
|
||||
return done(err);
|
||||
});
|
||||
})
|
||||
|
||||
it('16.9 returns a promise from resultSet.close', function(done) {
|
||||
oracledb.getConnection(dbConfig)
|
||||
.then(function(conn) {
|
||||
conn.should.be.ok;
|
||||
|
||||
return conn.execute('select 1 from dual', [], {resultSet: true})
|
||||
.then(function(result) {
|
||||
var closePromise;
|
||||
closePromise = result.resultSet.close();
|
||||
closePromise.should.be.an.instanceof(oracledb.Promise);
|
||||
|
||||
return closePromise
|
||||
.then(function() {
|
||||
return conn.release()
|
||||
.then(done);
|
||||
});
|
||||
});
|
||||
})
|
||||
.catch(function(err) {
|
||||
return done(err);
|
||||
});
|
||||
})
|
||||
|
||||
it('16.10 returns a promise from resultSet.getRow', function(done) {
|
||||
|
||||
function finishProcessing(conn, resultSet) {
|
||||
return resultSet.close()
|
||||
.then(function() {
|
||||
conn.release();
|
||||
})
|
||||
}
|
||||
|
||||
function processResultSet(conn, resultSet) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
function processRow() {
|
||||
var getRowPromise;
|
||||
|
||||
getRowPromise = resultSet.getRow();
|
||||
getRowPromise.should.be.an.instanceof(oracledb.Promise);
|
||||
|
||||
getRowPromise
|
||||
.then(function(row) {
|
||||
if (!row) {
|
||||
finishProcessing(conn, resultSet)
|
||||
.then(function() {
|
||||
resolve();
|
||||
});
|
||||
} else {
|
||||
row[0].should.eql(1);
|
||||
|
||||
processRow();
|
||||
}
|
||||
})
|
||||
.catch(function(err) {
|
||||
reject(err);
|
||||
});
|
||||
}
|
||||
|
||||
processRow();
|
||||
});
|
||||
}
|
||||
|
||||
oracledb.getConnection(dbConfig)
|
||||
.then(function(conn) {
|
||||
conn.should.be.ok;
|
||||
|
||||
return conn.execute('select 1 from dual', [], {resultSet: true})
|
||||
.then(function(result) {
|
||||
return processResultSet(conn, result.resultSet)
|
||||
.then(function() {
|
||||
done();
|
||||
});
|
||||
});
|
||||
})
|
||||
.catch(function(err) {
|
||||
return done(err);
|
||||
});
|
||||
|
||||
}) // 16.10
|
||||
|
||||
it('16.11 returns a promise from resultSet.getRows', function(done) {
|
||||
function finishProcessing(conn, resultSet) {
|
||||
return resultSet.close()
|
||||
.then(function() {
|
||||
conn.release();
|
||||
});
|
||||
}
|
||||
|
||||
function processResultSet(conn, resultSet) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
function processRows() {
|
||||
var getRowsPromise;
|
||||
|
||||
getRowsPromise = resultSet.getRows(2);
|
||||
getRowsPromise.should.be.an.instanceof(oracledb.Promise);
|
||||
|
||||
getRowsPromise
|
||||
.then(function(rows) {
|
||||
if (rows.length === 0) {
|
||||
finishProcessing(conn, resultSet)
|
||||
.then(function() {
|
||||
resolve();
|
||||
});
|
||||
} else {
|
||||
rows[0][0].should.eql(1);
|
||||
rows[1][0].should.eql(2);
|
||||
|
||||
processRows();
|
||||
}
|
||||
})
|
||||
.catch(function(err) {
|
||||
reject(err);
|
||||
});
|
||||
}
|
||||
|
||||
processRows();
|
||||
});
|
||||
}
|
||||
|
||||
oracledb.getConnection(dbConfig)
|
||||
.then(function(conn) {
|
||||
conn.should.be.ok;
|
||||
|
||||
return conn.execute('select 1 from dual union select 2 from dual', [], {resultSet: true})
|
||||
.then(function(result) {
|
||||
return processResultSet(conn, result.resultSet)
|
||||
.then(function() {
|
||||
return done();
|
||||
});
|
||||
});
|
||||
})
|
||||
.catch(function(err) {
|
||||
return done(err);
|
||||
});
|
||||
}) // 16.11
|
||||
|
||||
})
|
|
@ -630,15 +630,16 @@ describe('12. resultSet1.js', function() {
|
|||
);
|
||||
|
||||
function fetchRowFromRS(rs) {
|
||||
rs.getRows(function(err, rows) {
|
||||
try {
|
||||
rs.getRows(function() {});
|
||||
} catch (err) {
|
||||
should.exist(err);
|
||||
err.message.should.eql('NJS-009: invalid number of parameters');
|
||||
should.not.exist(rows);
|
||||
rs.close(function(err) {
|
||||
should.not.exist(err);
|
||||
done();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -685,7 +686,7 @@ describe('12. resultSet1.js', function() {
|
|||
function fetchRowFromRS(rs, numRows) {
|
||||
rs.getRows(numRows, function(err, rows) {
|
||||
should.exist(err);
|
||||
err.message.should.startWith('NJS-006: invalid type for parameter 1');
|
||||
err.message.should.eql('NJS-006: invalid type for parameter 1');
|
||||
rs.close(function(err) {
|
||||
should.not.exist(err);
|
||||
done();
|
||||
|
@ -709,14 +710,16 @@ describe('12. resultSet1.js', function() {
|
|||
);
|
||||
|
||||
function fetchRowFromRS(rs, numRows) {
|
||||
rs.getRows(numRows, function(err, rows) {
|
||||
try {
|
||||
rs.getRows(numRows, function() {});
|
||||
} catch (err) {
|
||||
should.exist(err);
|
||||
err.message.should.startWith('NJS-006: invalid type for parameter 1');
|
||||
rs.close(function(err) {
|
||||
should.not.exist(err);
|
||||
done();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
@ -870,15 +873,16 @@ describe('12. resultSet1.js', function() {
|
|||
);
|
||||
|
||||
function fetchRowFromRS(rs, numRows) {
|
||||
rs.getRow(numRows, function(err, row) {
|
||||
try {
|
||||
rs.getRow(numRows, function() {});
|
||||
} catch (err) {
|
||||
should.exist(err);
|
||||
err.message.should.eql('NJS-009: invalid number of parameters');
|
||||
should.not.exist(row);
|
||||
rs.close(function(err) {
|
||||
should.not.exist(err);
|
||||
done();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
|
|
@ -0,0 +1,377 @@
|
|||
/* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. */
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* You may not use the identified files except in compliance with the Apache
|
||||
* License, Version 2.0 (the "License.")
|
||||
*
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* The node-oracledb test suite uses 'mocha', 'should' and 'async'.
|
||||
* See LICENSE.md for relevant licenses.
|
||||
*
|
||||
* NAME
|
||||
* 15. resultsetToStream.js
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Testing driver query results via stream 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
|
||||
*
|
||||
*****************************************************************************/
|
||||
'use strict';
|
||||
|
||||
var oracledb = require('oracledb');
|
||||
var should = require('should');
|
||||
var async = require('async');
|
||||
var dbConfig = require('./dbconfig.js');
|
||||
|
||||
describe('15. resultsetToStream.js', function () {
|
||||
|
||||
if (dbConfig.externalAuth) {
|
||||
var credential = {externalAuth: true, connectString: dbConfig.connectString};
|
||||
} else {
|
||||
var credential = dbConfig;
|
||||
}
|
||||
|
||||
var connection = null;
|
||||
var rowsAmount = 217;
|
||||
before(function(done) {
|
||||
async.series([
|
||||
function getConn(cb) {
|
||||
oracledb.getConnection(credential, function(err, conn) {
|
||||
should.not.exist(err);
|
||||
connection = conn;
|
||||
cb();
|
||||
});
|
||||
},
|
||||
function createTab(cb) {
|
||||
var proc = "BEGIN \n" +
|
||||
" DECLARE \n" +
|
||||
" e_table_exists EXCEPTION; \n" +
|
||||
" PRAGMA EXCEPTION_INIT(e_table_exists, -00942);\n " +
|
||||
" BEGIN \n" +
|
||||
" EXECUTE IMMEDIATE ('DROP TABLE nodb_employees'); \n" +
|
||||
" EXCEPTION \n" +
|
||||
" WHEN e_table_exists \n" +
|
||||
" THEN NULL; \n" +
|
||||
" END; \n" +
|
||||
" EXECUTE IMMEDIATE (' \n" +
|
||||
" CREATE TABLE nodb_employees ( \n" +
|
||||
" employees_id NUMBER, \n" +
|
||||
" employees_name VARCHAR2(20), \n" +
|
||||
" employees_history CLOB \n" +
|
||||
" ) \n" +
|
||||
" '); \n" +
|
||||
"END; ";
|
||||
|
||||
connection.execute(
|
||||
proc,
|
||||
function(err) {
|
||||
should.not.exist(err);
|
||||
cb();
|
||||
}
|
||||
);
|
||||
},
|
||||
function insertRows(cb) {
|
||||
var proc = "DECLARE \n" +
|
||||
" x NUMBER := 0; \n" +
|
||||
" n VARCHAR2(20); \n" +
|
||||
" clobData CLOB; \n" +
|
||||
"BEGIN \n" +
|
||||
" FOR i IN 1..217 LOOP \n" +
|
||||
" x := x + 1; \n" +
|
||||
" n := 'staff ' || x; \n" +
|
||||
" INSERT INTO nodb_employees VALUES (x, n, EMPTY_CLOB()) RETURNING employees_history INTO clobData; \n" +
|
||||
" DBMS_LOB.WRITE(clobData, 20, 1, '12345678901234567890'); \n" +
|
||||
" END LOOP; \n" +
|
||||
"end; ";
|
||||
|
||||
connection.execute(
|
||||
proc,
|
||||
function(err) {
|
||||
should.not.exist(err);
|
||||
cb();
|
||||
}
|
||||
);
|
||||
}
|
||||
], done);
|
||||
}) // before
|
||||
|
||||
after(function(done) {
|
||||
async.series([
|
||||
function(callback) {
|
||||
connection.execute(
|
||||
"DROP TABLE nodb_employees",
|
||||
function(err) {
|
||||
should.not.exist(err);
|
||||
callback();
|
||||
}
|
||||
);
|
||||
},
|
||||
function(callback) {
|
||||
connection.release(function(err) {
|
||||
should.not.exist(err);
|
||||
callback();
|
||||
});
|
||||
},
|
||||
], done);
|
||||
}) // after
|
||||
|
||||
describe('15.1 Testing ResultSet.toQueryStream', function () {
|
||||
it('15.1.1 should allow resultsets to be converted to streams', function (done) {
|
||||
connection.execute(
|
||||
'begin \n' +
|
||||
' open :cursor for select employees_name from nodb_employees; \n' +
|
||||
'end;',
|
||||
{
|
||||
cursor: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT }
|
||||
},
|
||||
function(err, result) {
|
||||
should.not.exist(err);
|
||||
|
||||
var stream = result.outBinds.cursor.toQueryStream();
|
||||
|
||||
stream.on('error', function (error) {
|
||||
console.log(error);
|
||||
should.fail(error, null, 'Error event should not be triggered');
|
||||
});
|
||||
|
||||
var counter = 0;
|
||||
stream.on('data', function (data) {
|
||||
should.exist(data);
|
||||
counter++;
|
||||
});
|
||||
|
||||
stream.on('end', function () {
|
||||
should.equal(counter, rowsAmount);
|
||||
|
||||
setTimeout(done, 500);
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('15.2 Testing ResultSet/QueryStream conversion errors', function () {
|
||||
it('15.2.1 should prevent conversion to stream after getRow is invoked', function (done) {
|
||||
connection.execute(
|
||||
'begin \n' +
|
||||
' open :cursor for select employees_name from nodb_employees; \n' +
|
||||
'end;',
|
||||
{
|
||||
cursor: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT }
|
||||
},
|
||||
function(err, result) {
|
||||
should.not.exist(err);
|
||||
|
||||
var cursor = result.outBinds.cursor;
|
||||
|
||||
cursor.getRow(function(err, row) {
|
||||
should.not.exist(err);
|
||||
|
||||
cursor.close(function(err) {
|
||||
should.not.exist(err);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
try {
|
||||
var stream = cursor.toQueryStream();
|
||||
} catch (err) {
|
||||
(err.message).should.startWith('NJS-041:');
|
||||
// NJS-041: cannot convert to stream after invoking methods
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('15.2.2 should prevent conversion to stream after getRows is invoked', function (done) {
|
||||
connection.execute(
|
||||
'begin \n' +
|
||||
' open :cursor for select employees_name from nodb_employees; \n' +
|
||||
'end;',
|
||||
{
|
||||
cursor: { type: oracledb.CURSOR, dir : oracledb.BIND_OUT }
|
||||
},
|
||||
function(err, result) {
|
||||
should.not.exist(err);
|
||||
|
||||
var cursor = result.outBinds.cursor;
|
||||
|
||||
cursor.getRows(5, function(err, rows) {
|
||||
should.not.exist(err);
|
||||
|
||||
cursor.close(function(err) {
|
||||
should.not.exist(err);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
try {
|
||||
var stream = cursor.toQueryStream();
|
||||
} catch (err) {
|
||||
(err.message).should.startWith('NJS-041:');
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('15.2.3 should prevent conversion to stream after close is invoked', function (done) {
|
||||
connection.execute(
|
||||
'begin \n' +
|
||||
' open :cursor for select employees_name from nodb_employees; \n' +
|
||||
'end;',
|
||||
{
|
||||
cursor: { type: oracledb.CURSOR, dir : oracledb.BIND_OUT }
|
||||
},
|
||||
function(err, result) {
|
||||
should.not.exist(err);
|
||||
|
||||
var cursor = result.outBinds.cursor;
|
||||
|
||||
cursor.close(function(err) {
|
||||
should.not.exist(err);
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
try {
|
||||
var stream = cursor.toQueryStream();
|
||||
} catch (err) {
|
||||
(err.message).should.startWith('NJS-041:');
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('15.2.4 should prevent invoking getRow after conversion to stream', function (done) {
|
||||
connection.execute(
|
||||
'begin \n' +
|
||||
' open :cursor for select employees_name from nodb_employees; \n' +
|
||||
'end;',
|
||||
{
|
||||
cursor: { type: oracledb.CURSOR, dir : oracledb.BIND_OUT }
|
||||
},
|
||||
function(err, result) {
|
||||
should.not.exist(err);
|
||||
|
||||
var cursor = result.outBinds.cursor;
|
||||
var stream = cursor.toQueryStream();
|
||||
|
||||
cursor.getRow(function(err, row) {
|
||||
(err.message).should.startWith('NJS-042:');
|
||||
// NJS-042: cannot invoke methods after converting to stream
|
||||
|
||||
// Closing cursor via stream._close because the cursor.close method
|
||||
// is not invokable after conversion to stream.
|
||||
stream._close(function(err) {
|
||||
should.not.exist(err);
|
||||
done();
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('15.2.5 should prevent invoking getRows after conversion to stream', function (done) {
|
||||
connection.execute(
|
||||
'begin \n' +
|
||||
' open :cursor for select employees_name from nodb_employees; \n' +
|
||||
'end;',
|
||||
{
|
||||
cursor: { type: oracledb.CURSOR, dir : oracledb.BIND_OUT }
|
||||
},
|
||||
function(err, result) {
|
||||
should.not.exist(err);
|
||||
|
||||
var cursor = result.outBinds.cursor;
|
||||
var stream = cursor.toQueryStream();
|
||||
|
||||
cursor.getRows(5, function(err, rows) {
|
||||
(err.message).should.startWith('NJS-042:');
|
||||
|
||||
// Closing cursor via stream._close because the cursor.close method
|
||||
// is not invokable after conversion to stream.
|
||||
stream._close(function(err) {
|
||||
should.not.exist(err);
|
||||
done();
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('15.2.6 should prevent invoking close after conversion to stream', function (done) {
|
||||
connection.execute(
|
||||
'begin \n' +
|
||||
' open :cursor for select employees_name from nodb_employees; \n' +
|
||||
'end;',
|
||||
{
|
||||
cursor: { type: oracledb.CURSOR, dir : oracledb.BIND_OUT }
|
||||
},
|
||||
function(err, result) {
|
||||
should.not.exist(err);
|
||||
|
||||
var cursor = result.outBinds.cursor;
|
||||
var stream = cursor.toQueryStream();
|
||||
|
||||
cursor.close(function(err) {
|
||||
(err.message).should.startWith('NJS-042:');
|
||||
|
||||
// Closing cursor via stream._close because the cursor.close method
|
||||
// is not invokable after conversion to stream.
|
||||
stream._close(function(err) {
|
||||
should.not.exist(err);
|
||||
done();
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('15.2.7 should prevent calling toQueryStream more than once', function (done) {
|
||||
connection.execute(
|
||||
'begin \n' +
|
||||
' open :cursor for select employees_name from nodb_employees; \n' +
|
||||
'end;',
|
||||
{
|
||||
cursor: { type: oracledb.CURSOR, dir : oracledb.BIND_OUT }
|
||||
},
|
||||
function(err, result) {
|
||||
should.not.exist(err);
|
||||
|
||||
var cursor = result.outBinds.cursor;
|
||||
|
||||
// First conversion to stream
|
||||
var stream = cursor.toQueryStream();
|
||||
|
||||
try {
|
||||
// Second conversion to stream
|
||||
stream = cursor.toQueryStream();
|
||||
} catch (err) {
|
||||
(err.message).should.startWith('NJS-043:');
|
||||
|
||||
stream._close(function(err) {
|
||||
should.not.exist(err);
|
||||
done();
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
}); // 15.2.7
|
||||
|
||||
}); // 15.2
|
||||
});
|
286
test/stream1.js
286
test/stream1.js
|
@ -39,7 +39,6 @@ var async = require('async');
|
|||
var dbConfig = require('./dbconfig.js');
|
||||
|
||||
describe('13. stream1.js', function () {
|
||||
var connection = false;
|
||||
|
||||
if (dbConfig.externalAuth) {
|
||||
var credential = {externalAuth: true, connectString: dbConfig.connectString};
|
||||
|
@ -47,85 +46,91 @@ describe('13. stream1.js', function () {
|
|||
var credential = dbConfig;
|
||||
}
|
||||
|
||||
var createTable =
|
||||
"BEGIN \
|
||||
DECLARE \
|
||||
e_table_exists EXCEPTION; \
|
||||
PRAGMA EXCEPTION_INIT(e_table_exists, -00942); \
|
||||
BEGIN \
|
||||
EXECUTE IMMEDIATE ('DROP TABLE nodb_employees'); \
|
||||
EXCEPTION \
|
||||
WHEN e_table_exists \
|
||||
THEN NULL; \
|
||||
END; \
|
||||
EXECUTE IMMEDIATE (' \
|
||||
CREATE TABLE nodb_employees ( \
|
||||
employees_id NUMBER, \
|
||||
employees_name VARCHAR2(20), \
|
||||
employees_history CLOB \
|
||||
) \
|
||||
'); \
|
||||
END; ";
|
||||
|
||||
var insertRows =
|
||||
"DECLARE \
|
||||
x NUMBER := 0; \
|
||||
n VARCHAR2(20); \
|
||||
clobData CLOB;\
|
||||
BEGIN \
|
||||
FOR i IN 1..217 LOOP \
|
||||
x := x + 1; \
|
||||
n := 'staff ' || x; \
|
||||
INSERT INTO nodb_employees VALUES (x, n, EMPTY_CLOB()) RETURNING employees_history INTO clobData; \
|
||||
\
|
||||
DBMS_LOB.WRITE(clobData, 20, 1, '12345678901234567890');\
|
||||
END LOOP; \
|
||||
END; ";
|
||||
var connection = null;
|
||||
var rowsAmount = 217;
|
||||
|
||||
before(function(done) {
|
||||
async.series([
|
||||
function getConn(cb) {
|
||||
oracledb.getConnection(credential, function(err, conn) {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
return;
|
||||
}
|
||||
should.not.exist(err);
|
||||
connection = conn;
|
||||
connection.execute(createTable, function (err) {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
return;
|
||||
}
|
||||
connection.execute(insertRows, function (err) {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
return;
|
||||
}
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
cb();
|
||||
});
|
||||
},
|
||||
function createTab(cb) {
|
||||
var proc = "BEGIN \n" +
|
||||
" DECLARE \n" +
|
||||
" e_table_exists EXCEPTION; \n" +
|
||||
" PRAGMA EXCEPTION_INIT(e_table_exists, -00942);\n " +
|
||||
" BEGIN \n" +
|
||||
" EXECUTE IMMEDIATE ('DROP TABLE nodb_employees'); \n" +
|
||||
" EXCEPTION \n" +
|
||||
" WHEN e_table_exists \n" +
|
||||
" THEN NULL; \n" +
|
||||
" END; \n" +
|
||||
" EXECUTE IMMEDIATE (' \n" +
|
||||
" CREATE TABLE nodb_employees ( \n" +
|
||||
" employees_id NUMBER, \n" +
|
||||
" employees_name VARCHAR2(20), \n" +
|
||||
" employees_history CLOB \n" +
|
||||
" ) \n" +
|
||||
" '); \n" +
|
||||
"END; ";
|
||||
|
||||
after(function (done) {
|
||||
connection.execute(
|
||||
'DROP TABLE nodb_employees',
|
||||
proc,
|
||||
function(err) {
|
||||
if (err) {
|
||||
console.error(err.message);
|
||||
return;
|
||||
}
|
||||
connection.release(function (err) {
|
||||
if (err) {
|
||||
console.error(err.message);
|
||||
return;
|
||||
}
|
||||
done();
|
||||
});
|
||||
should.not.exist(err);
|
||||
cb();
|
||||
}
|
||||
);
|
||||
});
|
||||
},
|
||||
function insertRows(cb) {
|
||||
var proc = "DECLARE \n" +
|
||||
" x NUMBER := 0; \n" +
|
||||
" n VARCHAR2(20); \n" +
|
||||
" clobData CLOB; \n" +
|
||||
"BEGIN \n" +
|
||||
" FOR i IN 1..217 LOOP \n" +
|
||||
" x := x + 1; \n" +
|
||||
" n := 'staff ' || x; \n" +
|
||||
" INSERT INTO nodb_employees VALUES (x, n, EMPTY_CLOB()) RETURNING employees_history INTO clobData; \n" +
|
||||
" DBMS_LOB.WRITE(clobData, 20, 1, '12345678901234567890'); \n" +
|
||||
" END LOOP; \n" +
|
||||
"end; ";
|
||||
|
||||
describe('13.1 Testing ResultSet stream', function () {
|
||||
connection.execute(
|
||||
proc,
|
||||
function(err) {
|
||||
should.not.exist(err);
|
||||
cb();
|
||||
}
|
||||
);
|
||||
}
|
||||
], done);
|
||||
}) // before
|
||||
|
||||
after(function(done) {
|
||||
async.series([
|
||||
function(callback) {
|
||||
connection.execute(
|
||||
"DROP TABLE nodb_employees",
|
||||
function(err) {
|
||||
should.not.exist(err);
|
||||
callback();
|
||||
}
|
||||
);
|
||||
},
|
||||
function(callback) {
|
||||
connection.release(function(err) {
|
||||
should.not.exist(err);
|
||||
callback();
|
||||
});
|
||||
},
|
||||
], done);
|
||||
}) // after
|
||||
|
||||
describe('13.1 Testing QueryStream', function () {
|
||||
it('13.1.1 stream results for oracle connection', function (done) {
|
||||
connection.should.be.ok;
|
||||
|
||||
|
@ -357,6 +362,7 @@ describe('13. stream1.js', function () {
|
|||
var counter = 0;
|
||||
var clobs = [];
|
||||
var clobsRead = 0;
|
||||
|
||||
stream.on('data', function (data) {
|
||||
var rowIndex = counter;
|
||||
|
||||
|
@ -487,4 +493,146 @@ describe('13. stream1.js', function () {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('13.2 Testing QueryStream._close', function () {
|
||||
it('13.2.1 should be able to stop the stream early with _close', function (done) {
|
||||
connection.should.be.ok;
|
||||
|
||||
var stream = connection.queryStream('SELECT employees_name FROM nodb_employees');
|
||||
|
||||
stream.on('data', function () {
|
||||
stream.pause();
|
||||
stream._close();
|
||||
});
|
||||
|
||||
stream.on('close', function() {
|
||||
done();
|
||||
});
|
||||
|
||||
stream.on('end', function () {
|
||||
done(new Error('Reached the end of the stream'));
|
||||
});
|
||||
|
||||
stream.on('error', function (err) {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
|
||||
it('13.2.2 should be able to stop the stream before any data', function (done) {
|
||||
connection.should.be.ok;
|
||||
|
||||
var stream = connection.queryStream('SELECT employees_name FROM nodb_employees');
|
||||
|
||||
stream.on('close', function() {
|
||||
done();
|
||||
});
|
||||
|
||||
// Close is synchronous so it needs to be called after the close listener is added.
|
||||
stream._close();
|
||||
|
||||
stream.on('data', function () {
|
||||
done(new Error('Received data'));
|
||||
});
|
||||
|
||||
stream.on('end', function () {
|
||||
done(new Error('Reached the end of the stream'));
|
||||
});
|
||||
|
||||
stream.on('error', function (err) {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
|
||||
it('13.2.3 should invoke an optional callback passed to _close', function (done) {
|
||||
connection.should.be.ok;
|
||||
|
||||
var stream = connection.queryStream('SELECT employees_name FROM nodb_employees');
|
||||
|
||||
stream._close(function() {
|
||||
done();
|
||||
});
|
||||
|
||||
stream.on('data', function () {
|
||||
done(new Error('Received data'));
|
||||
});
|
||||
|
||||
stream.on('end', function () {
|
||||
done(new Error('Reached the end of the stream'));
|
||||
});
|
||||
|
||||
stream.on('error', function (err) {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('13.3 Testing QueryStream\'s maxRows control', function () {
|
||||
it('13.3.1 should use oracledb.maxRows for fetching', function (done) {
|
||||
var defaultMaxRows;
|
||||
var testMaxRows = 9;
|
||||
|
||||
connection.should.be.ok;
|
||||
|
||||
defaultMaxRows = oracledb.maxRows;
|
||||
|
||||
oracledb.maxRows = testMaxRows;
|
||||
|
||||
var stream = connection.queryStream('SELECT employees_name FROM nodb_employees');
|
||||
|
||||
stream.on('data', function () {
|
||||
stream.pause();
|
||||
|
||||
// Using the internal/private caches to validate
|
||||
should.equal(stream._fetchedRows.length, testMaxRows - (1 + stream._readableState.buffer.length));
|
||||
stream._close();
|
||||
});
|
||||
|
||||
stream.on('close', function() {
|
||||
oracledb.maxRows = defaultMaxRows;
|
||||
done();
|
||||
});
|
||||
|
||||
stream.on('end', function () {
|
||||
done(new Error('Reached the end of the stream'));
|
||||
});
|
||||
|
||||
stream.on('error', function (err) {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
|
||||
it('13.3.2 should default to 100 if oracledb.maxRows is falsey', function (done) {
|
||||
var defaultMaxRows;
|
||||
var testMaxRows = 0;
|
||||
|
||||
connection.should.be.ok;
|
||||
|
||||
defaultMaxRows = oracledb.maxRows;
|
||||
|
||||
oracledb.maxRows = testMaxRows;
|
||||
|
||||
var stream = connection.queryStream('SELECT employees_name FROM nodb_employees');
|
||||
|
||||
stream.on('data', function () {
|
||||
stream.pause();
|
||||
|
||||
// Using the internal/private caches to validate
|
||||
should.equal(stream._fetchedRows.length, (99 - stream._readableState.buffer.length));
|
||||
stream._close();
|
||||
});
|
||||
|
||||
stream.on('close', function() {
|
||||
oracledb.maxRows = defaultMaxRows;
|
||||
done();
|
||||
});
|
||||
|
||||
stream.on('end', function () {
|
||||
done(new Error('Reached the end of the stream'));
|
||||
});
|
||||
|
||||
stream.on('error', function (err) {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -242,20 +242,15 @@ describe('14. stream2.js', function() {
|
|||
}) // 14.6
|
||||
|
||||
it('14.7 Negative - queryStream() has no parameters', function(done) {
|
||||
var stream;
|
||||
|
||||
var stream = connection.queryStream();
|
||||
|
||||
stream.on('error', function(error) {
|
||||
should.exist(error);
|
||||
// console.log(error);
|
||||
// NJS-006: invalid type for parameter 1
|
||||
setTimeout(done, 500);
|
||||
});
|
||||
|
||||
stream.on('data', function(data) {
|
||||
should.not.exist(data);
|
||||
});
|
||||
|
||||
try {
|
||||
stream = connection.queryStream();
|
||||
} catch (err) {
|
||||
should.exist(err);
|
||||
err.message.should.eql('NJS-009: invalid number of parameters');
|
||||
done();
|
||||
}
|
||||
})
|
||||
|
||||
it('14.8 Negative - give invalid SQL as first parameter', function(done) {
|
||||
|
|
Loading…
Reference in New Issue