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
|
# 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)
|
## node-oracledb v1.8.0 (24 Mar 2016)
|
||||||
|
|
||||||
- Added `connection.queryStream()` for returning query results using a
|
- 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
|
### 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
|
### <a name="instosxICuser"></a> 5.3.1 Install Instant Client in a user directory
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
Download the free **Basic** and **SDK** 64-bit ZIPs from
|
Download the free **Basic** and **SDK** 64-bit ZIPs from
|
||||||
[Oracle Technology Network](http://www.oracle.com/technetwork/topics/intel-macsoft-096467.html)
|
[Oracle Technology Network](http://www.oracle.com/technetwork/topics/intel-macsoft-096467.html)
|
||||||
and
|
and unzip them somewhere under your home directory:
|
||||||
[install them](http://www.oracle.com/technetwork/topics/intel-macsoft-096467.html#ic_osx_inst)
|
|
||||||
into the same directory:
|
|
||||||
|
|
||||||
```
|
```
|
||||||
unzip instantclient-basic-macos.x64-11.2.0.4.0.zip
|
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.
|
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
|
### <a name="instosxICaddon"></a> 5.4 Install the add-on
|
||||||
|
|
||||||
If you are behind a firewall you may need to set your proxy, for
|
If you are behind a firewall you may need to set your proxy, for
|
||||||
|
|
25
README.md
25
README.md
|
@ -1,11 +1,11 @@
|
||||||
# node-oracledb version 1.8
|
# node-oracledb version 1.9
|
||||||
|
|
||||||
## <a name="about"></a> About node-oracledb
|
## <a name="about"></a> About node-oracledb
|
||||||
|
|
||||||
The node-oracledb add-on for Node.js powers high performance Oracle
|
The node-oracledb add-on for Node.js powers high performance Oracle
|
||||||
Database applications.
|
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.
|
Oracle Database.
|
||||||
|
|
||||||
The add-on is stable, well documented, and has a comprehensive test suite.
|
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:
|
### 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)
|
- [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)
|
- [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)
|
- [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)
|
- [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)
|
- [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)
|
- [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)
|
- [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)
|
- [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)
|
- [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)
|
- [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)
|
- [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)
|
- [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
|
We are actively working on supporting the best Oracle Database
|
||||||
features, and on functionality requests from
|
features, and on functionality requests from
|
||||||
[users involved in the project](https://github.com/oracle/node-oracledb/issues).
|
[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/)
|
- [Python 2.7](https://www.python.org/downloads/)
|
||||||
- C Compiler with support for C++ 11 (Xcode, gcc, Visual Studio or similar)
|
- 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
|
- 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).
|
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.
|
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
|
```javascript
|
||||||
var oracledb = require('oracledb');
|
var oracledb = require('oracledb');
|
||||||
|
@ -90,6 +95,8 @@ With Oracle's sample HR schema, the output is:
|
||||||
[ [ 60, 'IT' ], [ 90, 'Executive' ], [ 100, 'Finance' ] ]
|
[ [ 60, 'IT' ], [ 90, 'Executive' ], [ 100, 'Finance' ] ]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Node Promises can also be used.
|
||||||
|
|
||||||
## <a name="doc"></a> Documentation
|
## <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).
|
See [Documentation for the Oracle Database Node.js Add-on](https://github.com/oracle/node-oracledb/tree/master/doc/api.md).
|
||||||
|
@ -98,9 +105,9 @@ 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)
|
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 testsuite see [test/README](https://github.com/oracle/node-oracledb/tree/master/test/README.md).
|
To run the included test suite see [test/README](https://github.com/oracle/node-oracledb/tree/master/test/README.md).
|
||||||
|
|
||||||
## <a name="contrib"></a> Contributing
|
## <a name="contrib"></a> Contributing
|
||||||
|
|
||||||
|
|
713
doc/api.md
713
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
|
* refcursor.js
|
||||||
*
|
*
|
||||||
* DESCRIPTION
|
* 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.
|
* Uses Oracle's sample HR schema.
|
||||||
* Use demo.sql to create the required procedure or do:
|
* 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 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
|
// The queryStream function is similar to execute except that it immediately
|
||||||
// returns a readable stream.
|
// returns a QueryStream.
|
||||||
function queryStream(sql, binding, options) {
|
function queryStream(sql, binding, options) {
|
||||||
var self = this;
|
var self = this;
|
||||||
var stream;
|
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;
|
return stream;
|
||||||
}
|
}
|
||||||
|
@ -39,24 +67,45 @@ function execute(a1, a2, a3, a4) {
|
||||||
var executeCb;
|
var executeCb;
|
||||||
var custExecuteCb;
|
var custExecuteCb;
|
||||||
|
|
||||||
// Added this check so that node doesn't hang if no arguments are passed.
|
nodbUtil.assert(arguments.length > 1 && arguments.length < 5, 'NJS-009');
|
||||||
if (arguments.length < 2 || arguments.length > 4) {
|
nodbUtil.assert(typeof a1 === 'string', 'NJS-006', 1);
|
||||||
if (arguments.length && typeof arguments[arguments.length - 1] === 'function') {
|
|
||||||
arguments[arguments.length - 1](new Error('NJS-009: invalid number of parameters'));
|
switch (arguments.length) {
|
||||||
return;
|
case 2:
|
||||||
} else {
|
nodbUtil.assert(typeof a2 === 'function', 'NJS-006', 2);
|
||||||
throw new Error('NJS-009: invalid number of parameters');
|
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) {
|
custExecuteCb = function(err, result) {
|
||||||
|
var outBindsKeys;
|
||||||
|
var outBindsIdx;
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
executeCb(err);
|
executeCb(err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Need to extend resultsets which may come from either the query results
|
||||||
|
// or outBinds.
|
||||||
if (result.resultSet) {
|
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);
|
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.
|
// This commit function is just a place holder to allow for easier extension later.
|
||||||
function commit() {
|
function commit(commitCb) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
|
nodbUtil.assert(arguments.length === 1, 'NJS-009');
|
||||||
|
nodbUtil.assert(typeof commitCb === 'function', 'NJS-006', 1);
|
||||||
|
|
||||||
self._commit.apply(self, arguments);
|
self._commit.apply(self, arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This rollback function is just a place holder to allow for easier extension later.
|
// This rollback function is just a place holder to allow for easier extension later.
|
||||||
function rollback() {
|
function rollback(rollbackCb) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
|
nodbUtil.assert(arguments.length === 1, 'NJS-009');
|
||||||
|
nodbUtil.assert(typeof rollbackCb === 'function', 'NJS-006', 1);
|
||||||
|
|
||||||
self._rollback.apply(self, arguments);
|
self._rollback.apply(self, arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,23 +154,31 @@ function rollback() {
|
||||||
function release(releaseCb) {
|
function release(releaseCb) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
// _pool will only exist on connections obtained from a pool.
|
nodbUtil.assert(arguments.length === 1, 'NJS-009');
|
||||||
if (self._pool && self._pool.queueRequests !== false) {
|
nodbUtil.assert(typeof releaseCb === 'function', 'NJS-006', 1);
|
||||||
self._release(function(err) {
|
|
||||||
releaseCb(err);
|
|
||||||
|
|
||||||
|
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();
|
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.
|
// 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.
|
// It's attached to the module as break is a reserved word.
|
||||||
module.break = function() {
|
module.break = function(breakCb) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
|
nodbUtil.assert(arguments.length === 1, 'NJS-009');
|
||||||
|
nodbUtil.assert(typeof breakCb === 'function', 'NJS-006', 1);
|
||||||
|
|
||||||
self._break.apply(self, arguments);
|
self._break.apply(self, arguments);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -143,7 +206,7 @@ function extend(conn, oracledb, pool) {
|
||||||
writable: true
|
writable: true
|
||||||
},
|
},
|
||||||
execute: {
|
execute: {
|
||||||
value: execute,
|
value: nodbUtil.promisify(execute),
|
||||||
enumerable: true,
|
enumerable: true,
|
||||||
writable: true
|
writable: true
|
||||||
},
|
},
|
||||||
|
@ -151,7 +214,7 @@ function extend(conn, oracledb, pool) {
|
||||||
value: conn.commit
|
value: conn.commit
|
||||||
},
|
},
|
||||||
commit: {
|
commit: {
|
||||||
value: commit,
|
value: nodbUtil.promisify(commit),
|
||||||
enumerable: true,
|
enumerable: true,
|
||||||
writable: true
|
writable: true
|
||||||
},
|
},
|
||||||
|
@ -159,7 +222,7 @@ function extend(conn, oracledb, pool) {
|
||||||
value: conn.rollback
|
value: conn.rollback
|
||||||
},
|
},
|
||||||
rollback: {
|
rollback: {
|
||||||
value: rollback,
|
value: nodbUtil.promisify(rollback),
|
||||||
enumerable: true,
|
enumerable: true,
|
||||||
writable: true
|
writable: true
|
||||||
},
|
},
|
||||||
|
@ -167,7 +230,12 @@ function extend(conn, oracledb, pool) {
|
||||||
value: conn.release
|
value: conn.release
|
||||||
},
|
},
|
||||||
release: {
|
release: {
|
||||||
value: release,
|
value: nodbUtil.promisify(release),
|
||||||
|
enumerable: true,
|
||||||
|
writable: true
|
||||||
|
},
|
||||||
|
close: { // alias for release
|
||||||
|
value: nodbUtil.promisify(release),
|
||||||
enumerable: true,
|
enumerable: true,
|
||||||
writable: true
|
writable: true
|
||||||
},
|
},
|
||||||
|
@ -175,7 +243,7 @@ function extend(conn, oracledb, pool) {
|
||||||
value: conn.break
|
value: conn.break
|
||||||
},
|
},
|
||||||
break: {
|
break: {
|
||||||
value: module.break,
|
value: nodbUtil.promisify(module.break),
|
||||||
enumerable: true,
|
enumerable: true,
|
||||||
writable: true
|
writable: true
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
*
|
*
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
var Duplex = require('stream').Duplex;
|
var Duplex = require('stream').Duplex;
|
||||||
var util = require('util');
|
var util = require('util');
|
||||||
|
|
||||||
|
|
|
@ -17,11 +17,14 @@
|
||||||
*
|
*
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
var oracledbCLib;
|
var oracledbCLib;
|
||||||
var oracledbInst;
|
var oracledbInst;
|
||||||
var Lob = require('./lob.js').Lob;
|
var Lob = require('./lob.js').Lob;
|
||||||
var pool = require('./pool.js');
|
var pool = require('./pool.js');
|
||||||
var connection = require('./connection.js');
|
var connection = require('./connection.js');
|
||||||
|
var nodbUtil = require('./util.js');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
oracledbCLib = require('../build/Release/oracledb');
|
oracledbCLib = require('../build/Release/oracledb');
|
||||||
|
@ -43,6 +46,10 @@ oracledbCLib.Oracledb.prototype.newLob = function(iLob) {
|
||||||
function createPool(poolAttrs, createPoolCb) {
|
function createPool(poolAttrs, createPoolCb) {
|
||||||
var self = this;
|
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) {
|
self._createPool(poolAttrs, function(err, poolInst) {
|
||||||
if (err) {
|
if (err) {
|
||||||
createPoolCb(err);
|
createPoolCb(err);
|
||||||
|
@ -61,6 +68,10 @@ function createPool(poolAttrs, createPoolCb) {
|
||||||
function getConnection(connAttrs, createConnectionCb) {
|
function getConnection(connAttrs, createConnectionCb) {
|
||||||
var self = this;
|
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) {
|
self._getConnection(connAttrs, function(err, connInst) {
|
||||||
if (err) {
|
if (err) {
|
||||||
createConnectionCb(err);
|
createConnectionCb(err);
|
||||||
|
@ -83,6 +94,9 @@ function extend(oracledb) {
|
||||||
Object.defineProperties(
|
Object.defineProperties(
|
||||||
oracledb,
|
oracledb,
|
||||||
{
|
{
|
||||||
|
_oracledb: { // Known to be used in util.js' promisify function.
|
||||||
|
value: oracledb
|
||||||
|
},
|
||||||
DEFAULT: {
|
DEFAULT: {
|
||||||
value: 0,
|
value: 0,
|
||||||
enumerable: true
|
enumerable: true
|
||||||
|
@ -135,6 +149,11 @@ function extend(oracledb) {
|
||||||
value: 4002,
|
value: 4002,
|
||||||
enumerable: true
|
enumerable: true
|
||||||
},
|
},
|
||||||
|
Promise: {
|
||||||
|
value: global.Promise,
|
||||||
|
enumerable: true,
|
||||||
|
writable: true
|
||||||
|
},
|
||||||
Oracledb: {
|
Oracledb: {
|
||||||
value: oracledbCLib.Oracledb,
|
value: oracledbCLib.Oracledb,
|
||||||
enumerable: true
|
enumerable: true
|
||||||
|
@ -169,7 +188,7 @@ function extend(oracledb) {
|
||||||
value: oracledb.createPool
|
value: oracledb.createPool
|
||||||
},
|
},
|
||||||
createPool: {
|
createPool: {
|
||||||
value: createPool,
|
value: nodbUtil.promisify(createPool),
|
||||||
enumerable: true,
|
enumerable: true,
|
||||||
writable: true
|
writable: true
|
||||||
},
|
},
|
||||||
|
@ -177,7 +196,7 @@ function extend(oracledb) {
|
||||||
value: oracledb.getConnection
|
value: oracledb.getConnection
|
||||||
},
|
},
|
||||||
getConnection: {
|
getConnection: {
|
||||||
value: getConnection,
|
value: nodbUtil.promisify(getConnection),
|
||||||
enumerable: true,
|
enumerable: true,
|
||||||
writable: true
|
writable: true
|
||||||
}
|
}
|
||||||
|
@ -185,7 +204,7 @@ function extend(oracledb) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
oracledbInst = new oracledbCLib.Oracledb;
|
oracledbInst = new oracledbCLib.Oracledb();
|
||||||
|
|
||||||
extend(oracledbInst);
|
extend(oracledbInst);
|
||||||
|
|
||||||
|
|
66
lib/pool.js
66
lib/pool.js
|
@ -17,7 +17,10 @@
|
||||||
*
|
*
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
var connection = require('./connection.js');
|
var connection = require('./connection.js');
|
||||||
|
var nodbUtil = require('./util.js');
|
||||||
|
|
||||||
// completeConnectionRequest does the actual work of getting a connection from a
|
// 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
|
// 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._connRequestQueue.splice(requestIndex, 1);
|
||||||
self._connRequestTimersMap[timerIdx] = null;
|
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 timeoutHandle;
|
||||||
var timerIdx;
|
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
|
// 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.
|
// (which is a C layer getter) an error will be thrown.
|
||||||
if (!self._isValid) {
|
if (!self._isValid) {
|
||||||
|
@ -150,21 +156,21 @@ function getConnection(getConnectionCb) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self.queueRequests === false) { // queueing is disabled for pool
|
if (self.queueRequests === false) { // queueing is disabled for pool
|
||||||
if (self._enableStats) {
|
self._getConnection(function(err, connInst) {
|
||||||
self._getConnection(function(err, connInst) {
|
if (err) {
|
||||||
if (err) {
|
if (self._enableStats) {
|
||||||
self._totalFailedRequests += 1;
|
self._totalFailedRequests += 1;
|
||||||
|
|
||||||
getConnectionCb(err);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getConnectionCb(null, connInst);
|
getConnectionCb(err);
|
||||||
});
|
|
||||||
} else {
|
return;
|
||||||
self._getConnection(getConnectionCb);
|
}
|
||||||
}
|
|
||||||
|
connection.extend(connInst, self._oracledb, self);
|
||||||
|
|
||||||
|
getConnectionCb(null, connInst);
|
||||||
|
});
|
||||||
} else if (self._connectionsOut < self.poolMax) { // queueing enabled, but not needed
|
} else if (self._connectionsOut < self.poolMax) { // queueing enabled, but not needed
|
||||||
completeConnectionRequest.call(self, getConnectionCb);
|
completeConnectionRequest.call(self, getConnectionCb);
|
||||||
} else { // need to queue the request
|
} else { // need to queue the request
|
||||||
|
@ -204,6 +210,9 @@ function getConnection(getConnectionCb) {
|
||||||
function terminate(terminateCb) {
|
function terminate(terminateCb) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
|
nodbUtil.assert(arguments.length === 1, 'NJS-009');
|
||||||
|
nodbUtil.assert(typeof terminateCb === 'function', 'NJS-006', 1);
|
||||||
|
|
||||||
self._terminate(function(err) {
|
self._terminate(function(err) {
|
||||||
if (!err) {
|
if (!err) {
|
||||||
self._isValid = false;
|
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
|
_oracledb: { // storing a reference to the base instance to avoid circular references with require
|
||||||
value: oracledb
|
value: oracledb
|
||||||
},
|
},
|
||||||
queueRequests: {
|
queueRequests: { // true will queue requests when conn pool is maxed out
|
||||||
value: queueRequests, // true will queue requests when conn pool is maxed out
|
enumerable: true,
|
||||||
enumerable: true
|
get: function() {
|
||||||
|
return queueRequests;
|
||||||
|
},
|
||||||
|
set: function() {
|
||||||
|
throw new Error(nodbUtil.getErrorMessage('NJS-014', 'queueRequests'));
|
||||||
|
}
|
||||||
},
|
},
|
||||||
queueTimeout: {
|
queueTimeout: { // milliseconds a connection request can spend in queue before being failed
|
||||||
value: queueTimeout, // milliseconds a connection request can spend in queue before being failed
|
enumerable: true,
|
||||||
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
|
_isValid: { // used to ensure operations are not done after terminate
|
||||||
value: true,
|
value: true,
|
||||||
|
@ -373,7 +392,7 @@ function extend(pool, poolAttrs, oracledb) {
|
||||||
value: pool.getConnection
|
value: pool.getConnection
|
||||||
},
|
},
|
||||||
getConnection: {
|
getConnection: {
|
||||||
value: getConnection,
|
value: nodbUtil.promisify(getConnection),
|
||||||
enumerable: true,
|
enumerable: true,
|
||||||
writable: true
|
writable: true
|
||||||
},
|
},
|
||||||
|
@ -381,7 +400,12 @@ function extend(pool, poolAttrs, oracledb) {
|
||||||
value: pool.terminate
|
value: pool.terminate
|
||||||
},
|
},
|
||||||
terminate: {
|
terminate: {
|
||||||
value: terminate,
|
value: nodbUtil.promisify(terminate),
|
||||||
|
enumerable: true,
|
||||||
|
writable: true
|
||||||
|
},
|
||||||
|
close: { // alias for terminate
|
||||||
|
value: nodbUtil.promisify(terminate),
|
||||||
enumerable: true,
|
enumerable: true,
|
||||||
writable: 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.
|
// This close function is just a place holder to allow for easier extension later.
|
||||||
function close() {
|
function close(closeCb) {
|
||||||
var self = this;
|
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.
|
// This getRow function is just a place holder to allow for easier extension later.
|
||||||
function getRow() {
|
function getRow(getRowCb) {
|
||||||
var self = this;
|
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);
|
self._getRow.apply(self, arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This getRows function is just a place holder to allow for easier extension later.
|
// This getRows function is just a place holder to allow for easier extension later.
|
||||||
function getRows() {
|
function getRows(numRows, getRowsCb) {
|
||||||
var self = this;
|
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);
|
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
|
// 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
|
// 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.
|
// 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
|
// Using Object.defineProperties to add properties to the ResultSet instance with
|
||||||
// special properties, such as enumerable but not writable.
|
// special properties, such as enumerable but not writable.
|
||||||
Object.defineProperties(
|
Object.defineProperties(
|
||||||
resultSet,
|
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: {
|
_close: {
|
||||||
value: resultSet.close
|
value: resultSet.close
|
||||||
},
|
},
|
||||||
close: {
|
close: {
|
||||||
value: close,
|
value: nodbUtil.promisify(close),
|
||||||
enumerable: true,
|
enumerable: true,
|
||||||
writable: true
|
writable: true
|
||||||
},
|
},
|
||||||
|
@ -59,7 +135,7 @@ function extend(resultSet) {
|
||||||
value: resultSet.getRow
|
value: resultSet.getRow
|
||||||
},
|
},
|
||||||
getRow: {
|
getRow: {
|
||||||
value: getRow,
|
value: nodbUtil.promisify(getRow),
|
||||||
enumerable: true,
|
enumerable: true,
|
||||||
writable: true
|
writable: true
|
||||||
},
|
},
|
||||||
|
@ -67,7 +143,12 @@ function extend(resultSet) {
|
||||||
value: resultSet.getRows
|
value: resultSet.getRows
|
||||||
},
|
},
|
||||||
getRows: {
|
getRows: {
|
||||||
value: getRows,
|
value: nodbUtil.promisify(getRows),
|
||||||
|
enumerable: true,
|
||||||
|
writable: true
|
||||||
|
},
|
||||||
|
toQueryStream: {
|
||||||
|
value: toQueryStream,
|
||||||
enumerable: true,
|
enumerable: true,
|
||||||
writable: 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",
|
"name": "oracledb",
|
||||||
"version": "1.8.0",
|
"version": "1.9.0",
|
||||||
"description": "Oracle Database driver by Oracle Corp.",
|
"description": "Oracle Database driver by Oracle Corp.",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"homepage": "http://www.oracle.com/technetwork/database/database-technologies/scripting-languages/node_js/",
|
"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-013: invalid bind direction",
|
||||||
"NJS-014: %s is a read-only property",
|
"NJS-014: %s is a read-only property",
|
||||||
"NJS-016: buffer is too small for OUT binds",
|
"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-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-020: empty array was specified to fetch values as string",
|
||||||
"NJS-021: invalid type for conversion specified",
|
"NJS-021: invalid type for conversion specified",
|
||||||
"NJS-022: invalid LOB",
|
"NJS-022: invalid LOB",
|
||||||
|
@ -63,13 +63,10 @@ static const char *errMsg[] =
|
||||||
"NJS-026: maxRows must be greater than zero",
|
"NJS-026: maxRows must be greater than zero",
|
||||||
"NJS-027: unexpected SQL parsing error",
|
"NJS-027: unexpected SQL parsing error",
|
||||||
"NJS-028: raw database type is not supported with DML Returning statements",
|
"NJS-028: raw database type is not supported with DML Returning statements",
|
||||||
"NJS-029: Invalid object from javascript",
|
"NJS-029: invalid object from JavaScript",
|
||||||
"NJS-030: connection cannot be released because Lob operations are in"
|
"NJS-030: connection cannot be released because Lob operations are in progress",
|
||||||
" progress",
|
"NJS-031: connection cannot be released because ResultSet operations are in progress",
|
||||||
"NJS-031: connection cannot be released because ResultSet operations are"
|
"NJS-032: connection cannot be released because a database call is in progress",
|
||||||
" in progress",
|
|
||||||
"NJS-032: connection cannot be released because a database call is in"
|
|
||||||
" progress",
|
|
||||||
"NJS-033: an internal error occurred. [%s][%s]",
|
"NJS-033: an internal error occurred. [%s][%s]",
|
||||||
"NJS-034: data type is unsupported for array bind",
|
"NJS-034: data type is unsupported for array bind",
|
||||||
"NJS-035: maxArraySize is required for IN OUT 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-038: maxArraySize value should be greater than 0",
|
||||||
"NJS-039: empty array is not allowed for IN bind",
|
"NJS-039: empty array is not allowed for IN bind",
|
||||||
"NJS-040: connection request timeout",
|
"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, ... )
|
string NJSMessages::getErrorMsg ( NJSErrorType err, ... )
|
||||||
|
|
|
@ -74,6 +74,9 @@ typedef enum
|
||||||
errInvalidValueArrayBind,
|
errInvalidValueArrayBind,
|
||||||
errEmptyArray,
|
errEmptyArray,
|
||||||
errConnRequestTimeout,
|
errConnRequestTimeout,
|
||||||
|
errCannotConvertRsToStream,
|
||||||
|
errCannotInvokeRsMethods,
|
||||||
|
errResultSetAlreadyConverted,
|
||||||
|
|
||||||
// New ones should be added here
|
// New ones should be added here
|
||||||
|
|
||||||
|
|
|
@ -69,7 +69,7 @@ using namespace v8;
|
||||||
|
|
||||||
/* Keep the version in sync with package.json */
|
/* Keep the version in sync with package.json */
|
||||||
#define NJS_NODE_ORACLEDB_MAJOR 1
|
#define NJS_NODE_ORACLEDB_MAJOR 1
|
||||||
#define NJS_NODE_ORACLEDB_MINOR 8
|
#define NJS_NODE_ORACLEDB_MINOR 9
|
||||||
#define NJS_NODE_ORACLEDB_PATCH 0
|
#define NJS_NODE_ORACLEDB_PATCH 0
|
||||||
|
|
||||||
/* Used for Oracledb.version */
|
/* Used for Oracledb.version */
|
||||||
|
|
|
@ -718,7 +718,6 @@ describe('1. connection.js', function(){
|
||||||
|
|
||||||
describe('1.6 Testing parameter assertions', function() {
|
describe('1.6 Testing parameter assertions', function() {
|
||||||
var conn1;
|
var conn1;
|
||||||
var sql = 'select 1 from dual';
|
|
||||||
|
|
||||||
beforeEach('get connection ready', function(done) {
|
beforeEach('get connection ready', function(done) {
|
||||||
oracledb.getConnection(credential, function(err, conn) {
|
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) {
|
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 {
|
try {
|
||||||
conn1.execute(sql);
|
conn1.execute();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
if (promiseSupportEnabled) {
|
||||||
|
listeners.forEach(function(listener) {
|
||||||
|
process.on('uncaughtException', listener);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
should.exist(err);
|
should.exist(err);
|
||||||
|
|
||||||
done();
|
done();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it('1.6.2 too few params with a callback should pass error in callback', function(done) {
|
it('1.6.2 too many params should throw error', function(done) {
|
||||||
conn1.execute(function(err, result) {
|
// This test returns a promise because the last parameter to execute is not
|
||||||
should.exist(err);
|
// a function. Normally, errors thrown in a promise would be directed to
|
||||||
done();
|
// 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');
|
||||||
|
|
||||||
it('1.6.3 too many params without a callback should throw error', function(done) {
|
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 {
|
try {
|
||||||
conn1.execute(1, 2, 3, 4, 5);
|
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) {
|
} catch (err) {
|
||||||
should.exist(err);
|
should.exist(err);
|
||||||
done();
|
done();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it('1.6.4 too many params with a callback should pass error in callback', function(done) {
|
it('1.6.4 wrong type for param 2 should throw an error', function(done) {
|
||||||
conn1.execute(1, 2, 3, 4, function(err, result) {
|
// 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);
|
should.exist(err);
|
||||||
done();
|
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 Testing commit() & rollback() functions
|
||||||
1.5.1 commit() function works well
|
1.5.1 commit() function works well
|
||||||
1.5.2 rollback() 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. pool.js
|
||||||
2.1 default values
|
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.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 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.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
|
3. examples.js
|
||||||
|
@ -227,7 +238,7 @@
|
||||||
12.7.2 maxRows option is ignored with REF Cursor
|
12.7.2 maxRows option is ignored with REF Cursor
|
||||||
|
|
||||||
13. stream.js
|
13. stream.js
|
||||||
13.1 Testing ResultSet stream
|
13.1 Testing QueryStream
|
||||||
13.1.1 stream results for oracle connection
|
13.1.1 stream results for oracle connection
|
||||||
13.1.2 stream results for oracle connection (outFormat: oracledb.OBJECT)
|
13.1.2 stream results for oracle connection (outFormat: oracledb.OBJECT)
|
||||||
13.1.3 errors in query
|
13.1.3 errors in query
|
||||||
|
@ -239,6 +250,13 @@
|
||||||
13.1.9 Read CLOBs after stream close
|
13.1.9 Read CLOBs after stream close
|
||||||
13.1.10 meta data
|
13.1.10 meta data
|
||||||
13.1.11 stream stress test
|
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. stream2.js
|
||||||
14.1 Bind by position and return an array
|
14.1 Bind by position and return an array
|
||||||
|
@ -249,7 +267,32 @@
|
||||||
14.6 maxRows option is ignored as expect
|
14.6 maxRows option is ignored as expect
|
||||||
14.7 Negative - queryStream() has no parameters
|
14.7 Negative - queryStream() has no parameters
|
||||||
14.8 Negative - give invalid SQL as first parameter
|
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
|
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) {
|
pool1.terminate(function(err) {
|
||||||
should.not.exist(err);
|
should.not.exist(err);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
pool1.getConnection(1);
|
pool1.getConnection();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
should.exist(err);
|
should.exist(err);
|
||||||
(err.message).should.startWith('NJS-002: invalid pool');
|
(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) {
|
function fetchRowFromRS(rs) {
|
||||||
rs.getRows(function(err, rows) {
|
try {
|
||||||
|
rs.getRows(function() {});
|
||||||
|
} catch (err) {
|
||||||
should.exist(err);
|
should.exist(err);
|
||||||
err.message.should.eql('NJS-009: invalid number of parameters');
|
err.message.should.eql('NJS-009: invalid number of parameters');
|
||||||
should.not.exist(rows);
|
|
||||||
rs.close(function(err) {
|
rs.close(function(err) {
|
||||||
should.not.exist(err);
|
should.not.exist(err);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -685,7 +686,7 @@ describe('12. resultSet1.js', function() {
|
||||||
function fetchRowFromRS(rs, numRows) {
|
function fetchRowFromRS(rs, numRows) {
|
||||||
rs.getRows(numRows, function(err, rows) {
|
rs.getRows(numRows, function(err, rows) {
|
||||||
should.exist(err);
|
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) {
|
rs.close(function(err) {
|
||||||
should.not.exist(err);
|
should.not.exist(err);
|
||||||
done();
|
done();
|
||||||
|
@ -709,14 +710,16 @@ describe('12. resultSet1.js', function() {
|
||||||
);
|
);
|
||||||
|
|
||||||
function fetchRowFromRS(rs, numRows) {
|
function fetchRowFromRS(rs, numRows) {
|
||||||
rs.getRows(numRows, function(err, rows) {
|
try {
|
||||||
|
rs.getRows(numRows, function() {});
|
||||||
|
} catch (err) {
|
||||||
should.exist(err);
|
should.exist(err);
|
||||||
err.message.should.startWith('NJS-006: invalid type for parameter 1');
|
err.message.should.startWith('NJS-006: invalid type for parameter 1');
|
||||||
rs.close(function(err) {
|
rs.close(function(err) {
|
||||||
should.not.exist(err);
|
should.not.exist(err);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -870,15 +873,16 @@ describe('12. resultSet1.js', function() {
|
||||||
);
|
);
|
||||||
|
|
||||||
function fetchRowFromRS(rs, numRows) {
|
function fetchRowFromRS(rs, numRows) {
|
||||||
rs.getRow(numRows, function(err, row) {
|
try {
|
||||||
|
rs.getRow(numRows, function() {});
|
||||||
|
} catch (err) {
|
||||||
should.exist(err);
|
should.exist(err);
|
||||||
err.message.should.eql('NJS-009: invalid number of parameters');
|
err.message.should.eql('NJS-009: invalid number of parameters');
|
||||||
should.not.exist(row);
|
|
||||||
rs.close(function(err) {
|
rs.close(function(err) {
|
||||||
should.not.exist(err);
|
should.not.exist(err);
|
||||||
done();
|
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
|
||||||
|
});
|
298
test/stream1.js
298
test/stream1.js
|
@ -39,7 +39,6 @@ var async = require('async');
|
||||||
var dbConfig = require('./dbconfig.js');
|
var dbConfig = require('./dbconfig.js');
|
||||||
|
|
||||||
describe('13. stream1.js', function () {
|
describe('13. stream1.js', function () {
|
||||||
var connection = false;
|
|
||||||
|
|
||||||
if (dbConfig.externalAuth) {
|
if (dbConfig.externalAuth) {
|
||||||
var credential = {externalAuth: true, connectString: dbConfig.connectString};
|
var credential = {externalAuth: true, connectString: dbConfig.connectString};
|
||||||
|
@ -47,85 +46,91 @@ describe('13. stream1.js', function () {
|
||||||
var credential = dbConfig;
|
var credential = dbConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
var createTable =
|
var connection = null;
|
||||||
"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 rowsAmount = 217;
|
var rowsAmount = 217;
|
||||||
|
before(function(done) {
|
||||||
before(function (done) {
|
async.series([
|
||||||
oracledb.getConnection(credential, function (err, conn) {
|
function getConn(cb) {
|
||||||
if (err) {
|
oracledb.getConnection(credential, function(err, conn) {
|
||||||
console.error(err);
|
should.not.exist(err);
|
||||||
return;
|
connection = conn;
|
||||||
}
|
cb();
|
||||||
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();
|
|
||||||
});
|
});
|
||||||
});
|
},
|
||||||
});
|
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(
|
||||||
connection.execute(
|
proc,
|
||||||
'DROP TABLE nodb_employees',
|
function(err) {
|
||||||
function (err) {
|
should.not.exist(err);
|
||||||
if (err) {
|
cb();
|
||||||
console.error(err.message);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
connection.release(function (err) {
|
|
||||||
if (err) {
|
|
||||||
console.error(err.message);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
done();
|
);
|
||||||
});
|
},
|
||||||
}
|
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) {
|
it('13.1.1 stream results for oracle connection', function (done) {
|
||||||
connection.should.be.ok;
|
connection.should.be.ok;
|
||||||
|
|
||||||
|
@ -357,6 +362,7 @@ describe('13. stream1.js', function () {
|
||||||
var counter = 0;
|
var counter = 0;
|
||||||
var clobs = [];
|
var clobs = [];
|
||||||
var clobsRead = 0;
|
var clobsRead = 0;
|
||||||
|
|
||||||
stream.on('data', function (data) {
|
stream.on('data', function (data) {
|
||||||
var rowIndex = counter;
|
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
|
}) // 14.6
|
||||||
|
|
||||||
it('14.7 Negative - queryStream() has no parameters', function(done) {
|
it('14.7 Negative - queryStream() has no parameters', function(done) {
|
||||||
|
var stream;
|
||||||
|
|
||||||
var stream = connection.queryStream();
|
try {
|
||||||
|
stream = connection.queryStream();
|
||||||
stream.on('error', function(error) {
|
} catch (err) {
|
||||||
should.exist(error);
|
should.exist(err);
|
||||||
// console.log(error);
|
err.message.should.eql('NJS-009: invalid number of parameters');
|
||||||
// NJS-006: invalid type for parameter 1
|
done();
|
||||||
setTimeout(done, 500);
|
}
|
||||||
});
|
|
||||||
|
|
||||||
stream.on('data', function(data) {
|
|
||||||
should.not.exist(data);
|
|
||||||
});
|
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('14.8 Negative - give invalid SQL as first parameter', function(done) {
|
it('14.8 Negative - give invalid SQL as first parameter', function(done) {
|
||||||
|
|
Loading…
Reference in New Issue