Permalink
13a4e77 Jun 27, 2018
8781 lines (6738 sloc) 303 KB

node-oracledb 3.0-dev Documentation for the Oracle Database Node.js Add-on

Copyright (c) 2015, 2018, 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.

Contents

===> *** Note: Go to https://oracle.github.io/node-oracledb/doc/api.html for production documentation ***

  1. Introduction
  2. Errors
  3. Oracledb Class
  4. Connection Class
  5. Lob Class
  6. Pool Class
  7. ResultSet Class
  8. Connection Handling
  9. SQL Execution
  10. PL/SQL Execution
  11. Working with CLOB and BLOB Data
  12. Oracle Database 12c JSON Data type
  13. Working with XMLType
  14. Bind Parameters for Prepared Statements
  15. Batch Statement Execution
  16. Continuous Query Notification (CQN)
  17. Transaction Management
  18. Statement Caching
  19. External Configuration
  20. Globalization and National Language Support (NLS)
  21. End-to-end Tracing, Mid-tier Authentication, and Auditing
  22. Promises and node-oracledb
  23. Async/Await and node-oracledb
  24. Tracing SQL and PL/SQL Statements
  25. Migrating from Previous node-oracledb Releases

NODE-ORACLEDB API MANUAL

1. Introduction

The node-oracledb add-on for Node.js powers high performance Oracle Database applications.

This document shows how to use node-oracledb version 2. The API reference is in sections 2 - 7 and the user guide in subsequent sections.

Documentation about node-oracledb version 1 is here.

The node-oracledb API is a generic Oracle Database access layer. Almost all the functionality described here is common across all current Oracle Databases. However the documentation may describe some database features that are in specific Oracle Database versions, editions, or require additional database options or packs.

1.1 Getting Started with Node-oracledb

Install Node.js from nodejs.org.

Install node-oracledb using the Quick Start Node-oracledb Installation steps.

Download node-oracledb examples or create a script like the one below. As well as callbacks, node-oracledb can also use Promises and Async/Await functions.

Locate your Oracle Database user name and password, and the database connection string. The connection string is commonly of the format hostname/servicename, using the host name where the database is running and the Oracle Database service name of the database instance.

Substitute your user name, password and connection string in the code. For downloaded examples, put these in dbconfig.js.

Run the script, for example:

node myscript.js

Example: Simple SELECT statement in Node.js with Callbacks

// myscript.js

var oracledb = require('oracledb');

oracledb.getConnection(
  {
    user          : "hr",
    password      : "welcome",
    connectString : "localhost/XE"
  },
  function(err, connection) {
    if (err) {
      console.error(err.message);
      return;
    }
    connection.execute(
      `SELECT manager_id, department_id, department_name
       FROM departments
       WHERE manager_id = :id`,
      [103],  // bind value for :id
      function(err, result) {
        if (err) {
          console.error(err.message);
          doRelease(connection);
          return;
        }
        console.log(result.rows);
        doRelease(connection);
      });
  });

function doRelease(connection) {
  connection.close(
    function(err) {
      if (err)
        console.error(err.message);
    });
}

With Oracle's sample HR schema, the output is:

[ [ 103, 60, 'IT' ] ]

Scripts to create Oracle's sample schemas can be found at github.com/oracle/db-sample-schemas.

2. Errors

The last parameter of each method is a callback, unless Promises are being used. The first parameter of the callback is an Error object that contains error information if the call fails. If the call succeeds, then the object is null.

When using Promises, the catch() callback's error object will contain error information when the Promise chain fails.

If an invalid value is set for a property, then an error occurs. The same is true for invalid operations on read-only or write-only properties. If an unrecognized property name is used, it will be ignored.

2.1 Error Properties

The Error object contains errorNum, message and offset properties.

2.1.1 errorNum

Number errorNum

The Oracle error number. This value is undefined for non-Oracle errors and for messages prefixed with NJS or DPI.

2.1.2 message

String message

The text of the error message.

The error may be a standard Oracle message with a prefix like ORA or PLS. Alternatively it may be a node-oracledb specific error prefixed with NJS or DPI.

A single line error message may look like this:

ORA-01017: invalid username/password; logon denied

A multi-line error message may look like this:

ORA-06550: line 1, column 7:
PLS-00201: identifier 'TESTPRC' must be declared
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored

2.1.3 offset

Number offset

The character offset into the SQL text that resulted in the Oracle error. The value may be 0 in non-SQL contexts. This value is undefined for non-Oracle errors and for messages prefixed with NJS or DPI.

3. Oracledb Class

The Oracledb object is the factory class for Pool and Connection objects.

The Oracledb object is instantiated by loading node-oracledb:

var oracledb = require("oracledb");

Internally, the add-on creates the Oracledb object as a singleton. Reloading it in the same Node.js process creates a new pointer to the same object.

3.1 Oracledb Constants

These constants are defined in the oracledb module. Usage is described later in this document.

The numeric values for the constants are shown to aid debugging. They may change in future, so use the constant names in applications.

3.1.1 Query outFormat Constants

Constants for the query result outFormat option:

Constant Name Value Description
oracledb.ARRAY 4001 Fetch each row as array of column values
oracledb.OBJECT 4002 Fetch each row as an object

3.1.2 Node-oracledb Type Constants

Constants for execute() bind parameter type property, for the createLob() type parameter, for the Lob type property, for fetchAsBuffer, for fetchAsString and fetchInfo, and for extended metadata.

Not all constants can be used in all places.

Constant Name Value Description
oracledb.BLOB 2007 Bind a BLOB to a Node.js Stream or create a temporary BLOB, or for fetchAsBuffer and fetchInfo
oracledb.BUFFER 2005 Bind a RAW, LONG RAW or BLOB to a Node.js Buffer
oracledb.CLOB 2006 Bind a CLOB to a Node.js Stream, create a temporary CLOB, or for fetchAsString and fetchInfo
oracledb.CURSOR 2004 Bind a REF CURSOR to a node-oracledb ResultSet class
oracledb.DATE 2003 Bind as JavaScript date type. Can also be used for fetchAsString and fetchInfo
oracledb.DEFAULT 0 Used with fetchInfo to reset the fetch type to the database type
oracledb.NUMBER 2002 Bind as JavaScript number type. Can also be used for fetchAsString and fetchInfo
oracledb.STRING 2001 Bind as JavaScript String type. Can be used for most database types.

3.1.3 Oracle Database Type Constants

The values of these types are shown in extended metadata for queries and REF CURSORS. They indicate the Oracle Database type.

Constant Name Value Description
oracledb.DB_TYPE_BINARY_DOUBLE 101 BINARY_DOUBLE
oracledb.DB_TYPE_BINARY_FLOAT 100 BINARY_FLOAT
oracledb.DB_TYPE_BLOB 113 BLOB
oracledb.DB_TYPE_CHAR 96 CHAR
oracledb.DB_TYPE_CLOB 112 CLOB
oracledb.DB_TYPE_DATE 12 DATE
oracledb.DB_TYPE_LONG 8 LONG
oracledb.DB_TYPE_LONG_RAW 24 LONG RAW
oracledb.DB_TYPE_NCHAR 1096 NCHAR
oracledb.DB_TYPE_NCLOB 1112 NCLOB
oracledb.DB_TYPE_NUMBER 2 NUMBER or FLOAT
oracledb.DB_TYPE_NVARCHAR 1001 NVARCHAR
oracledb.DB_TYPE_RAW 23 RAW
oracledb.DB_TYPE_ROWID 104 ROWID
oracledb.DB_TYPE_TIMESTAMP 187 TIMESTAMP
oracledb.DB_TYPE_TIMESTAMP_LTZ 232 TIMESTAMP WITH LOCAL TIME ZONE
oracledb.DB_TYPE_TIMESTAMP_TZ 188 TIMESTAMP WITH TIME ZONE
oracledb.DB_TYPE_VARCHAR 1 VARCHAR2

3.1.4 Execute Bind Direction Constants

Constants for the dir property of execute() bindParams, queryStream() and executeMany() bindDefs.

These specify whether data values bound to SQL or PL/SQL bind parameters are passed into, or out from, the database:

Constant Name Value Description
oracledb.BIND_IN 3001 Direction for IN binds
oracledb.BIND_INOUT 3002 Direction for IN OUT binds
oracledb.BIND_OUT 3003 Direction for OUT binds

3.1.5 Privileged Connection Constants

Constants for getConnection() privilege properties.

These specify what privilege should be used by the connection that is being established.

Constant Name Value Description
oracledb.SYSDBA 2 SYSDBA privileges
oracledb.SYSOPER 4 SYSOPER privileges
oracledb.SYSASM 32768 SYSASM privileges
oracledb.SYSBACKUP 131072 SYSBACKUP privileges
oracledb.SYSDG 262144 SYSDG privileges
oracledb.SYSKM 524288 SYSKM privileges
oracledb.SYSRAC 1048576 SYSRAC privileges

3.1.6 SQL Statement Type Constants

Constants for connection.getStatementInfo() properties.

Constant Name Value Description
oracledb.STMT_TYPE_UNKNOWN 0 Unknown statement type
oracledb.STMT_TYPE_SELECT 1 SELECT
oracledb.STMT_TYPE_UPDATE 2 UPDATE
oracledb.STMT_TYPE_DELETE 3 DELETE
oracledb.STMT_TYPE_INSERT 4 INSERT
oracledb.STMT_TYPE_CREATE 5 CREATE
oracledb.STMT_TYPE_DROP 6 DROP
oracledb.STMT_TYPE_ALTER 7 ALTER
oracledb.STMT_TYPE_BEGIN 8 BEGIN
oracledb.STMT_TYPE_DECLARE 9 DECLARE
oracledb.STMT_TYPE_CALL 10 CALL
oracledb.STMT_TYPE_EXPLAIN_PLAN 15 EXPLAIN PLAN
oracledb.STMT_TYPE_MERGE 16 MERGE
oracledb.STMT_TYPE_ROLLBACK 17 ROLLBACK
oracledb.STMT_TYPE_COMMIT 21 COMMIT

3.1.7 Subscription Constants

Constants for the Continuous Query Notification message.type.

Constant Name Value Description
oracledb.SUBSCR_EVENT_TYPE_AQ 100 Advanced Queuing notifications are being used
oracledb.SUBSCR_EVENT_TYPE_DEREG 5 A subscription has been closed or the timeout value has been reached
oracledb.SUBSCR_EVENT_TYPE_OBJ_CHANGE 6 Object-level notications are being used (Database Change Notification)
oracledb.SUBSCR_EVENT_TYPE_QUERY_CHANGE 7 Query-level notifications are being used (Continuous Query Notification)

Constant for the Continuous Query Notification groupingClass.

Constant Name Value Description
oracledb.SUBSCR_GROUPING_CLASS_TIME 1 Group notifications by time into a single notification

Constants for the Continuous Query Notification groupingType.

Constant Name Value Description
oracledb.SUBSCR_GROUPING_TYPE_SUMMARY 1 A summary of the grouped notifications is sent
oracledb.SUBSCR_GROUPING_TYPE_LAST 2 The last notification in the group is sent

Constants for the Continuous Query Notification qos Quality of Service.

Constant Name Value Description
oracledb.SUBSCR_QOS_BEST_EFFORT 16 When best effort filtering for query result set changes is acceptable. False positive notifications may be received. This behavior may be suitable for caching applications.
oracledb.SUBSCR_QOS_DEREG_NFY 2 The subscription will be automatically unregistered as soon as the first notification is received.
oracledb.SUBSCR_QOS_QUERY 8 Continuous Query Notification will be used instead of Database Change Notification. This means that notifications are only sent if the result set of the registered query changes. By default no false positive notifications are generated. Use oracledb.SUBSCR_QOS_BEST_EFFORT if this is not needed.
oracledb.SUBSCR_QOS_RELIABLE 1 Notifications are not lost in the event of database failure.
oracledb.SUBSCR_QOS_ROWIDS 4 Notifications include the ROWIDs of the rows that were affected

Constants for the Continuous Query Notification namespace.

Constant Name Value Description
oracledb.SUBSCR_NAMESPACE_AQ 1 For Advanced Queuing notifications. Note AQ enqueue and dequeue methods are not supported in node-oracledb.
oracledb.SUBSCR_NAMESPACE_DBCHANGE 2 For Continuous Query Notifications.

3.1.8 Continuous Query Notification Constants

Constants for the Continuous Query Notification connection.subscribe() option operations, and for the notification message operation properties.

Constant Name Value Description
oracledb.CQN_OPCODE_ALL_OPS 0 Default. Used to request notification of all operations.
oracledb.CQN_OPCODE_ALL_ROWS 1 Indicates that row information is not available. This occurs if the qos quality of service flags do not specify the desire for ROWIDs, or if grouping has taken place and summary notifications are being sent.
oracledb.CQN_OPCODE_ALTER 16 Set if the table was altered in the notifying transaction
oracledb.CQN_OPCODE_DELETE 8 Set if the notifying transaction included deletes on the table
oracledb.CQN_OPCODE_DROP 32 Set if the table was dropped in the notifying transaction
oracledb.CQN_OPCODE_INSERT 2 Set if the notifying transaction included inserts on the table
oracledb.CQN_OPCODE_UPDATE 4 Set if the notifying transaction included updates on the table

3.2 Oracledb Properties

The properties of the Oracledb object are used for setting up configuration parameters for deployment.

If required, these properties can be overridden for the Pool or Connection objects.

These properties may be read or modified. If a property is modified, only subsequent invocations of the createPool() or getConnection() methods will be affected. Objects that exist before a property is modified are not altered.

Invalid values, or combinations of values, for pool configuration properties can result in the error ORA-24413: Invalid number of sessions specified.

Each of the configuration properties is described below.

3.2.1 oracledb.autoCommit

Boolean autoCommit

If this property is true, then the transaction in the current connection is automatically committed at the end of statement execution.

The default value is false.

This property may be overridden in an execute() call.

Note prior to node-oracledb 0.5 this property was called isAutoCommit.

Example
var oracledb = require('oracledb');
oracledb.autoCommit = false;

3.2.2 oracledb.connectionClass

String connectionClass

The user-chosen Connection class value defines a logical name for connections. Most single purpose applications should set connectionClass when using a connection pool or DRCP.

When a pooled session has a connection class, Oracle ensures that the session is not shared outside of that connection class.

The connection class value is similarly used by Database Resident Connection Pooling (DRCP) to allow or disallow sharing of sessions.

For example, where two different kinds of users share one pool, you might set connectionClass to 'HRPOOL' for connections that access a Human Resources system, and it might be set to 'OEPOOL' for users of an Order Entry system. Users will only be given sessions of the appropriate class, allowing maximal reuse of resources in each case, and preventing any session information leaking between the two systems.

If connectionClass is set for a non-pooled connection, the driver name is not recorded in V$ views. See End-to-end Tracing, Mid-tier Authentication, and Auditing.

Example
var oracledb = require('oracledb');
oracledb.connectionClass = 'HRPOOL';

3.2.3 oracledb.edition

String edition

Sets the name used for Edition-Based Redefinition by connections.

See Edition-Based Redefinition for more information.

This property was added in node-oracledb 2.2.

Example
var oracledb = require('oracledb');
oracledb.edition = 'ed_2';

3.2.4 oracledb.events

Boolean events

Determines whether Oracle Client events mode should be enabled.

The default value for events is false.

This property can be overridden in the oracledb.createPool() call and when getting a standalone connection from oracledb.getConnection().

Events mode is required for Continuous Query Notification, Fast Application Notification (FAN) and Runtime Load Balancing (RLB).

This property was added in node-oracledb 2.2.

Example
var oracledb = require('oracledb');
oracledb.events = true;

3.2.5 oracledb.extendedMetaData

Boolean extendedMetaData

Determines whether additional metadata is available for queries and for REF CURSORs returned from PL/SQL blocks.

The default value for extendedMetaData is false. With this value, the result.metaData result.resultSet.metaData objects only include column names.

If extendedMetaData is true then metaData will contain additional attributes. These are listed in Result Object Properties.

This property may be overridden in an execute() call.

This property was added in node-oracledb 1.10.

3.2.6 oracledb.externalAuth

Boolean externalAuth

If this property is true then connections are established using external authentication. See External Authentication for more information.

The default value is false.

The user and password properties for connecting or creating a pool should not be set when externalAuth is true.

This property can be overridden in the oracledb.createPool() call and when getting a standalone connection from oracledb.getConnection().

Note prior to node-oracledb 0.5 this property was called isExternalAuth.

Example
var oracledb = require('oracledb');
oracledb.externalAuth = false;

3.2.7 oracledb.fetchArraySize

Number fetchArraySize

This property sets the size of an internal buffer used for fetching query rows from Oracle Database. Changing it may affect query performance but does not affect how many rows are returned to the application.

The default value is 100.

The property is used during the default direct fetches, during ResultSet getRow() calls, and for queryStream(). It is not used for getRows().

Increasing this value reduces the number of round-trips to the database but increases memory usage for each data fetch. For queries that return a large number of rows, higher values of fetchArraySize may give better performance. For queries that only return a few rows, reduce the value of fetchArraySize to minimize the amount of memory management during data fetches. JavaScript memory fragmentation may occur in some cases, see Fetching Rows with Direct Fetches.

For direct fetches (those using execute() option resultSet: false), the internal buffer size will be based on the lesser of maxRows and fetchArraySize.

The property was introduced in node-oracledb version 2.0. It replaces prefetchRows.

Example
var oracledb = require('oracledb');
oracledb.fetchArraySize = 100;

3.2.8 oracledb.fetchAsBuffer

Array fetchAsBuffer

An array of node-oracledb types. Currently the only valid type is oracledb.BLOB. When a BLOB column is queried with execute() or queryStream(), the column data is returned as a Buffer instead of the default representation.

By default in node-oracledb, all columns are returned as native types or as Lob instances, in the case of CLOB and BLOB types.

Individual query columns in execute() or queryStream() calls can override the fetchAsBuffer global setting by using fetchInfo.

This property was added in node-oracledb 1.13.

Example
var oracledb = require('oracledb');
oracledb.fetchAsBuffer = [ oracledb.BLOB ];

3.2.9 oracledb.fetchAsString

Array fetchAsString

An array of node-oracledb types. The valid types are oracledb.DATE, oracledb.NUMBER, oracledb.BUFFER, and oracledb.CLOB. When any column having one of the specified types is queried with execute() or queryStream(), the column data is returned as a string instead of the default representation.

By default in node-oracledb, all columns are returned as native types or as Lob instances, in the case of CLOB and BLOB types.

This property helps avoid situations where using JavaScript types can lead to numeric precision loss, or where date conversion is unwanted. See Query Result Type Mapping for more discussion.

For raw data returned as a string, Oracle returns the data as a hex-encoded string. For dates and numbers returned as a string, the maximum length of a string created by this mapping is 200 bytes. Strings created for CLOB columns will generally be limited by Node.js and V8 memory restrictions.

Individual query columns in execute() or queryStream() calls can override the fetchAsString global setting by using fetchInfo.

For non-CLOB types, the conversion to string is handled by Oracle client libraries and is often referred to as defining the fetch type.

Example
var oracledb = require('oracledb');
oracledb.fetchAsString = [ oracledb.DATE, oracledb.NUMBER ];

3.2.10 oracledb.lobPrefetchSize

Number lobPrefetchSize

This attribute is temporarily disabled. Setting it has no effect.

Node-oracledb internally uses Oracle LOB Locators to manipulate long object (LOB) data. LOB Prefetching allows LOB data to be returned early to node-oracledb when these locators are first returned. This is similar to the way row prefetching allows for efficient use of resources and round-trips between node-oracledb and the database.

Prefetching of LOBs is mostly useful for small LOBs.

The default size is 16384.

Example
var oracledb = require('oracledb');
oracledb.lobPrefetchSize = 16384;

3.2.11 oracledb.maxRows

Number maxRows

The maximum number of rows that are fetched by a query with connection.execute() when not using a ResultSet. Rows beyond this limit are not fetched from the database. A value of 0 means there is no limit.

The default value is 0, meaning unlimited.

This property may be overridden in an execute() call.

To improve database efficiency, SQL queries should use a row limiting clause like OFFSET / FETCH or equivalent. The maxRows property can be used to stop badly coded queries from returning unexpectedly large numbers of rows.

When the number of query rows is relatively big, or can't be predicted, it is recommended to use a ResultSet or queryStream(). This allows applications to process rows in smaller chunks or individually, preventing the Node.js memory limit being exceeded or query results being unexpectedly truncated by a maxRows limit.

In version 1, the default value was 100.

Example
var oracledb = require('oracledb');
oracledb.maxRows = 0;

3.2.12 oracledb.oracleClientVersion

readonly Number oracleClientVersion

This readonly property gives a numeric representation of the Oracle client library version which is useful in comparisons. For version a.b.c.d.e, this property gives the number: (100000000 * a) + (1000000 * b) + (10000 * c) + (100 * d) + e

This property was added in node-oracledb 1.3.

Example
var oracledb = require('oracledb');
console.log("Oracle client library version number is " + oracledb.oracleClientVersion);

3.2.13 oracledb.oracleClientVersionString

readonly String oracleClientVersionString

This readonly property gives a string representation of the Oracle client library version which is useful for display.

This property was added in node-oracledb 2.2.

Example
var oracledb = require('oracledb');
console.log("Oracle client library version is " + oracledb.oracleClientVersionString);

3.2.14 oracledb.outFormat

Number outFormat

The format of query rows fetched when using connection.execute() or connection.queryStream(). It affects both ResultSet and non-ResultSet queries. It can be used for top level queries and REF CURSOR output.

This can be either of the Oracledb constants oracledb.ARRAY or oracledb.OBJECT. The default value is oracledb.ARRAY which is more efficient.

If specified as oracledb.ARRAY, each row is fetched as an array of column values.

If specified as oracledb.OBJECT, each row is fetched as a JavaScript object. The object has a property for each column name, with the property value set to the respective column value. The property name follows Oracle's standard name-casing rules. It will commonly be uppercase, since most applications create tables using unquoted, case-insensitive names.

This property may be overridden in an execute() or queryStream() call.

See Query Output Formats for more information.

Example
var oracledb = require('oracledb');
oracledb.outFormat = oracledb.ARRAY;

3.2.15 oracledb.poolIncrement

Number poolIncrement

The number of connections that are opened whenever a connection request exceeds the number of currently open connections.

The default value is 1.

This property may be overridden when creating a connection pool.

Example
var oracledb = require('oracledb');
oracledb.poolIncrement = 1;

3.2.16 oracledb.poolMax

Number poolMax

The maximum number of connections to which a connection pool can grow.

The default value is 4.

This property may be overridden when creating a connection pool.

See Connections and Number of Threads for why you should not increase this value beyond 128. Importantly, if you increase poolMax you should also increase the number of threads available to node-oracledb.

See Connection Pooling for other pool sizing guidelines.

Example
var oracledb = require('oracledb');
oracledb.poolMax = 4;

3.2.17 oracledb.poolMin

Number poolMin

The minimum number of connections a connection pool maintains, even when there is no activity to the target database.

The default value is 0.

This property may be overridden when creating a connection pool.

For pools created with External Authentication or with homogeneous set to false, the number of connections initially created is zero even if a larger value is specified for poolMin. The pool increment is always 1, regardless of the value of poolIncrement. Once the number of open connections exceeds poolMin and connections are idle for more than the poolTimeout seconds, then the number of open connections does not fall below poolMin.

Example
var oracledb = require('oracledb');
oracledb.poolMin = 0;

3.2.18 oracledb.poolPingInterval

Number poolPingInterval

When a pool getConnection() is called and the connection has been idle in the pool for at least poolPingInterval seconds, an internal "ping" will be performed first to check the aliveness of the connection. At the cost of some overhead for infrequently accessed connection pools, connection pinging improves the chance a pooled connection is valid when it is used because identified un-unusable connections will not be returned to the application by getConnection().

Note when node-oracledb is using version 12.2 of the Oracle client library, the value of poolPingInterval is ignored. Oracle client 12.2 has a lightweight, always-enabled connection check that replaces explicit pinging.

With Oracle client 12.1 or earlier, unless poolPingInterval is 0, it is possible for un-usable connections to be returned by a pool getConnection() call. Since it is also possible for network outages to occur after getConnection() is called, applications should implement appropriate statement execution error checking.

The default value is 60 seconds. Possible values for poolPingInterval are:

poolPingInterval Value Behavior of a Pool getConnection() Call
n < 0 Never checks for connection aliveness
n = 0 Always checks for connection aliveness. There is some overhead in performing a ping so non-zero values are recommended for most applications
n > 0 Checks aliveness if the connection has been idle in the pool (not "checked out" to the application by getConnection()) for at least n seconds

This property may be overridden when creating a connection pool.

See Connection Pool Pinging for more discussion.

This property was added in node-oracledb 1.12.

Example
var oracledb = require('oracledb');
oracledb.poolPingInterval = 60;     // seconds

3.2.19 oracledb.poolTimeout

Number poolTimeout

The number of seconds after which idle connections (unused in the pool) are terminated. Idle connections are terminated only when the pool is accessed. If the poolTimeout is set to 0, then idle connections are never terminated.

The default value is 60.

This property may be overridden when creating a connection pool.

Example
var oracledb = require('oracledb');
oracledb.poolTimeout = 60;

3.2.20 oracledb.prefetchRows

Number prefetchRows

This attribute is no longer used in node-oracledb version 2 and has no effect on applications. Use oracledb.fetchArraySize instead.

Example
var oracledb = require('oracledb');
oracledb.prefetchRows = 100;

3.2.21 oracledb.Promise

Promise Promise

Node-oracledb supports Promises on all methods. The standard Promise library is used.

See Promises and node-oracledb for a discussion of using Promises.

This property can be set to override or disable the Promise implementation.

Example
var mylib = require('myfavpromiseimplementation');
oracledb.Promise = mylib;

Promises can be completely disabled by setting

oracledb.Promise = null;

3.2.22 oracledb.queueRequests

This property was removed in node-oracledb 3.0. Queuing is now always enabled. See Connection Pool Queue for more information.

3.2.23 oracledb.queueTimeout

Number queueTimeout

The number of milliseconds after which connection requests waiting in the connection request queue are terminated. If queueTimeout is 0, then queued connection requests are never terminated.

The default value is 60000.

This property may be overridden when creating a connection pool.

See Connection Pool Queue for more information.

This property was added in node-oracledb 1.7.

Example
var oracledb = require('oracledb');
oracledb.queueTimeout = 3000; // 3 seconds

3.2.24 oracledb.stmtCacheSize

Number stmtCacheSize

The number of statements that are cached in the statement cache of each connection.

The default value is 30.

This property may be overridden for specific Pool or Connection objects.

In general, set the statement cache to the size of the working set of statements being executed by the application. Statement caching can be disabled by setting the size to 0.

See Statement Caching for examples.

Example
var oracledb = require('oracledb');
oracledb.stmtCacheSize = 30;

3.2.25 oracledb.version

readonly Number version

This readonly property gives a numeric representation of the node-oracledb version. For version x.y.z, this property gives the number: (10000 * x) + (100 * y) + z

Example
var oracledb = require('oracledb');
console.log("Driver version number is " + oracledb.version);

3.2.26 oracledb.versionString

readonly String versionString

This readonly property gives a string representation of the node-oracledb version, including the version suffix if one is present.

This property was added in node-oracledb 2.1.

Example
var oracledb = require('oracledb');
console.log("Driver version is " + oracledb.versionString);

3.2.27 oracledb.versionSuffix

readonly String versionSuffix

This readonly property gives a string representing the version suffix (e.g. "-dev" or "-beta") or an empty string if no version suffix is present.

This property was added in node-oracledb 2.1.

Example
var oracledb = require('oracledb');
console.log("Driver version suffix is " + oracledb.versionSuffix);

3.3 Oracledb Methods

3.3.1 oracledb.createPool()

Prototype

Callback:

createPool(Object poolAttrs, function(Error error, Pool pool){});

Promise:

promise = createPool(Object poolAttrs);
Description

This method creates a pool of connections with the specified user name, password and connection string.

Internally, createPool() creates an Oracle Call Interface Session Pool for each Pool object.

The default properties may be overridden by specifying new properties in the poolAttrs parameter.

It is possible to add pools to the pool cache when calling createPool(). This allows pools to later be accessed by name, removing the need to pass the pool object through code. See Connection Pool Cache for more details.

A pool should be terminated with the pool.close() call, but only after all connections have been released.

See Connection Pooling for more information about pooling.

3.3.1.1 createPool(): Parameters and Attributes
Object poolAttrs

The poolAttrs parameter object provides connection credentials and pool-specific configuration properties, such as the maximum or minimum number of connections for the pool, or the statement cache size for the connections.

The properties provided in the poolAttrs parameter override the default pooling properties of the Oracledb object. If an attribute is not set, or is null, the value of the related Oracledb property will be used.

Note that the poolAttrs parameter may have configuration properties that are not used by the createPool() method. These are ignored.

The properties of poolAttrs are described below.

3.3.1.1.1 connectString, connectionString
String connectString
String connectionString

The two properties are aliases for each other. Use only one of the properties.

The Oracle database instance used by connections in the pool. The string can be an Easy Connect string, or a Net Service Name from a tnsnames.ora file, or the name of a local Oracle database instance. See Connection Strings for examples.

The alias connectionString was added in node-oracledb 2.1.

3.3.1.1.2 edition
String edition

Sets the name used for Edition-Based Redefinition by connections in the pool.

This optional property overrides the oracledb.edition property.

This property was added in node-oracledb 2.2.

3.3.1.1.3 events
Boolean events

Indicate whether Oracle Call Interface events mode should be enabled for this pool.

This optional property overrides the oracledb.events property.

This property was added in node-oracledb 2.2.

3.3.1.1.4 externalAuth
Boolean externalAuth

Indicate whether pooled connections should be established using External Authentication.

The default is false.

This optional property overrides the oracledb.externalAuth property.

The user and password properties should not be set when externalAuth is true.

Note prior to node-oracledb 0.5 this property was called isExternalAuth.

3.3.1.1.5 homogeneous
Boolean homogeneous

Indicate whether connections in the pool all have the same credentials (a 'homogeneous' pool), or whether different credentials can be used (a 'heterogeneous' pool).

The default is true.

When set to false, the user name and password can be omitted from the connection.createPool() call, but will need to be given for subsequent pool.getConnection() calls. Different pool.getConnection() calls can provide different user credentials. Alternatively, when homogeneous is false, the user name (the 'proxy' user name) and password can be given, but subsequent pool.getConnection() calls can specify a different user name to access that user's schema.

Heterogeneous pools cannot be used with the connection pool cache. Applications should ensure the pool object is explicitly passed between code modules, or use a homogeneous pool and make use of connection.clientId.

See Heterogeneous Connection Pools and Pool Proxy Authentication for details and examples.

This property was added in node-oracledb 2.3.

3.3.1.1.6 password
String password

The password of the database user used by connections in the pool. A password is also necessary if a proxy user is specified at pool creation.

If homogeneous is false, then the password may be omitted at pool creation but given in subsequent pool.getConnection() calls.

3.3.1.1.7 poolAlias
String poolAlias

The poolAlias is an optional property that is used to explicitly add pools to the connection pool cache. If a pool alias is provided, then the new pool will be added to the connection pool cache and the poolAlias value can then be used with methods that utilize the connection pool cache, such as oracledb.getPool() and oracledb.getConnection().

See Connection Pool Cache for details and examples.

This property was added in node-oracledb 1.11.

3.3.1.1.8 poolIncrement
Number poolIncrement

The number of connections that are opened whenever a connection request exceeds the number of currently open connections.

The default value is 1.

This optional property overrides the oracledb.poolIncrement property.

3.3.1.1.9 poolMax
Number poolMax

The maximum number of connections to which a connection pool can grow.

The default value is 4.

This optional property overrides the oracledb.poolMax property.

See Connections and Number of Threads for why you should not increase this value beyond 128. Importantly, if you increase poolMax you should also increase the number of threads available to node-oracledb.

See Connection Pooling for other pool sizing guidelines.

3.3.1.1.10 poolMin
Number poolMin

The minimum number of connections a connection pool maintains, even when there is no activity to the target database.

The default value is 0.

This optional property overrides the oracledb.poolMin property.

3.3.1.1.11 poolPingInterval
Number poolPingInterval

When a pool getConnection() is called and the connection has been idle in the pool for at least poolPingInterval seconds, an internal "ping" will be performed first to check the aliveness of the connection.

Note this attribute is ignored when node-oracledb is using version 12.2 of the Oracle client library, since this has its own lightweight, always-enabled connection check.

The default value is 60.

This optional property overrides the oracledb.poolPingInterval property.

See Connection Pool Pinging for more discussion.

3.3.1.1.12 poolTimeout
Number poolTimeout

The number of seconds after which idle connections (unused in the pool) may be terminated. Idle connections are terminated only when the pool is accessed.

The default value is 60.

This optional property overrides the oracledb.poolTimeout property.

3.3.1.1.13 queueRequests

This property was removed in node-oracledb 3.0. Queuing is now always enabled. See Connection Pool Queue for more information.

3.3.1.1.14 queueTimeout
Number queueTimeout

The number of milliseconds after which connection requests waiting in the connection request queue are terminated. If queueTimeout is set to 0, then queued connection requests are never terminated.

The default value is 60000.

This optional property overrides the oracledb.queueTimeout property.

3.3.1.1.15 stmtCacheSize
Number stmtCacheSize

The number of statements to be cached in the statement cache of each connection in the pool.

This optional property overrides the oracledb.stmtCacheSize property.

3.3.1.1.16 user
String user

The database user name for connections in the pool. Can be a simple user name or a proxy of the form alison[fred]. See the Client Access Through a Proxy section in the Oracle Call Interface manual for more details about proxy authentication.

If homogeneous is false, then the pool user name and password need to be specified only if the application wants that user to proxy the users supplied in subsequent pool.getConnection() calls.

3.3.1.2 createPool(): Callback Function

function(Error error, Pool pool)

The parameters of the callback function are:

Callback function parameter Description
Error error If createPool() succeeds, error is NULL. If an error occurs, then error contains the error message.
Pool pool The newly created connection pool. If createPool() fails, pool will be NULL. See Pool class for more information.

3.3.2 oracledb.getConnection()

Prototype

Callback:

getConnection([String poolAlias | Object connAttrs], function(Error error, Connection conn){});

Promise:

promise = getConnection([String poolAlias | Object connAttrs]);
Description

Obtains a connection from a pool in the connection pool cache or creates a new, standalone, non-pooled connection.

For situations where connections are used infrequently, creating a standalone connection may be more efficient than creating and managing a connection pool. However, in most cases, Oracle recommends getting connections from a connection pool.

The following table shows the various signatures that can be used when invoking getConnection and describes how the function will behave as a result.

Signature Description
oracledb.getConnection() Gets a connection from the previously created default pool. Returns a promise.
oracledb.getConnection(callback) Gets a connection from the previously created default pool. Invokes the callback.
oracledb.getConnection(poolAlias) Gets a connection from the previously created pool with the specified poolAlias. Returns a promise.
oracledb.getConnection(poolAlias, callback) Gets a connection from the previously created pool with the specified poolAlias. Invokes the callback.
oracledb.getConnection(connAttrs) Creates a standalone, non-pooled connection. Returns a promise.
oracledb.getConnection(connAttrs, callback) Creates a standalone, non-pooled connection. Invokes the callback.

See Connection Handling for more information on connections.

Note if the application opens a number of connections, you should increase the number of threads available to node-oracledb. See Connections and Number of Threads.

3.3.2.1 getConnection(): Parameters
3.3.2.1.1 Pool Alias
String poolAlias

The poolAlias parameter is used to specify which pool in the connection pool cache to use to obtain the connection.

3.3.2.1.2 Connection Attributes
Object connAttrs

The connAttrs parameter object provides connection credentials and connection-specific configuration properties.

Any connAttrs properties that are not used by the getConnection() method are ignored.

The properties of the connAttrs object are described below.

3.3.2.1.2.1 connectString, connectionString
String connectString
String connectionString

The two properties are aliases for each other. Use only one of the properties.

The Oracle database instance to connect to. The string can be an Easy Connect string, or a Net Service Name from a tnsnames.ora file, or the name of a local Oracle database instance. See Connection Strings for examples.

The alias connectionString was added in node-oracledb 2.1.

3.3.2.1.2.2 edition
String edition

Sets the name used for Edition-Based Redefinition by this connection.

This optional property overrides the oracledb.edition property.

This property was added in node-oracledb 2.2.

3.3.2.1.2.3 events
Boolean events

Determines if the standalone connection is created using Oracle Call Interface events mode.

This optional property overrides the oracledb.events property.

This property was added in node-oracledb 2.2.

3.3.2.1.2.4 externalAuth
Boolean externalAuth

If this optional property is true then the connection will be established using External Authentication.

This optional property overrides the oracledb.externalAuth property.

The user and password properties should not be set when externalAuth is true.

Note prior to node-oracledb 0.5 this property was called isExternalAuth.

3.3.2.1.2.5 newPassword
String newPassword

The new password to use for the database user. When using newPassword, the password property should be set to the current password.

This allows passwords to be changed at the time of connection, in particular it can be used to connect when the old password has expired.

See Changing Passwords and Connecting with an Expired Password.

This property was added in node-oracledb 2.2.

3.3.2.1.2.6 password
String password

The password of the database user. A password is also necessary if a proxy user is specified.

3.3.2.1.2.7 privilege
Number privilege

The privilege to use when establishing connection to the database. This optional property should be one of the privileged connection constants.

See Privileged Connections for more information.

Note only non-pooled connections can be privileged.

This property was added in node-oracledb 2.1.

3.3.2.1.2.8 stmtCacheSize
Number stmtCacheSize

The number of statements to be cached in the statement cache of each connection. This optional property may be used to override the oracledb.stmtCacheSize property.

3.3.2.1.2.9 user
String user

The database user name. Can be a simple user name or a proxy of the form alison[fred]. See the Client Access Through a Proxy section in the Oracle Call Interface manual for more details about proxy authentication.

3.3.2.2 getConnection(): Callback Function
function(Error error, Connection conn)

The parameters of the callback function are:

Callback function parameter Description
Error error If getConnection() succeeds, error is NULL. If an error occurs, then error contains the error message.
Connection connection The newly created connection. If getConnection() fails, connection will be NULL. See Connection class for more details.

3.3.3 oracledb.getPool()

Prototype
getPool([String poolAlias]);
Description

Retrieves a previously created pool from the connection pool cache. Note that this is a synchronous method.

3.3.3.1 Parameters
3.3.3.1.1 alias
String poolAlias

The pool alias of the pool to retrieve from the connection pool cache. The default value is 'default' which will retrieve the default pool from the cache.

4. Connection Class

A Connection object is obtained by a Pool class getConnection() or Oracledb class getConnection() call.

The connection is used to access an Oracle database.

4.1 Connection Properties

The properties of a Connection object are listed below.

4.1.1 connection.action

writeonly String action

The action attribute for end-to-end application tracing.

This is a write-only property. Displaying a Connection object will show a value of null for this attribute. See End-to-end Tracing, Mid-tier Authentication, and Auditing.

4.1.2 connection.clientId

writeonly String clientId

The client identifier for end-to-end application tracing, use with mid-tier authentication, and with Virtual Private Databases.

This is a write-only property. Displaying a Connection object will show a value of null for this attribute. See End-to-end Tracing, Mid-tier Authentication, and Auditing.

4.1.3 connection.module

writeonly String module

The module attribute for end-to-end application tracing.

This is a write-only property. Displaying a Connection object will show a value of null for this attribute. See End-to-end Tracing, Mid-tier Authentication, and Auditing.

4.1.4 connection.oracleServerVersion

readonly Number oracleServerVersion

This readonly property gives a numeric representation of the Oracle database version which is useful in comparisons. For version a.b.c.d.e, this property gives the number: (100000000 * a) + (1000000 * b) + (10000 * c) + (100 * d) + e

This property was added in node-oracledb 1.3.

4.1.5 connection.oracleServerVersionString

readonly String oracleServerVersionString

This readonly property gives a string representation of the Oracle database version which is useful for display.

This property was added in node-oracledb 2.2.

4.1.6 connection.stmtCacheSize

readonly Number stmtCacheSize

The number of statements to be cached in the statement cache of the connection. The default value is the stmtCacheSize property in effect in the Pool object when the connection is created in the pool.

4.2 Connection Methods

4.2.1 connection.break()

Prototype

Callback:

break(function(Error error){});

Promise:

promise = break();
Description

This call stops the currently running operation on the connection.

If there is no operation in progress or the operation has completed by the time the break is issued, the break() is effectively a no-op.

If the running asynchronous operation is interrupted, its callback will return an error.

Parameters
function(Error error)

The parameters of the callback function are:

Callback function parameter Description
Error error If break() succeeds, error is NULL. If an error occurs, then error contains the error message.

4.2.2 connection.changePassword()

Prototype

Callback:

changePassword(String user, String oldPassword, String newPassword, function(Error error){});

Promise:

promise = changePassword(String user, String oldPassword, String newPassword);
Description

Changes the password of the specified user.

Only users with the ALTER USER privilege can change passwords of other users.

See Changing Passwords and Connecting with an Expired Password.

This method was added in node-oracledb 2.2.

Parameters
String user

The name of the user whose password is to be changed.

String oldPassword

The current password of the currently connected user.

If changePassword() is being used by a DBA to change the password of another user, the value of oldPassword is ignored and can be an empty string.

String newPassword

The new password of the user whose password is to be changed.

function(Error error)

The parameters of the callback function are:

Callback function parameter Description
Error error If changePassword() succeeds, error is NULL. If an error occurs, then error contains the error message.

4.2.3 connection.close()

Prototype

Callback:

close(function(Error error){});

Promise:

promise = close();
Description

Releases a connection. If the connection was obtained from the pool, the connection is returned to the pool and is available for reuse.

Calling close() as soon as a connection is no longer required is strongly encouraged. Releasing early can improve system efficiency. Calling close() for pooled connections is required to prevent the pool running out of connections.

When a connection is released, any ongoing transaction on the connection is rolled back.

After releasing a connection to a pool, there is no guarantee a subsequent getConnection() call gets back the same database connection. The application must redo any ALTER SESSION statements on the new connection object, as required.

If an error occurs on a pooled connection and that error is known to make the connection unusable, then close() will drop that connection from the connection pool. So a future pooled getConnection() call that grows the pool will create a new, valid connection.

This method was added to node-oracledb 1.9, replacing the equivalent alias connection.release().

Parameters
function(Error error)

The parameters of the callback function are:

Callback function parameter Description
Error error If close() succeeds, error is NULL. If an error occurs, then error contains the error message.

4.2.4 connection.commit()

Prototype

Callback:

commit(function(Error error){});

Promise:

promise = commit();
Description

This call commits the current transaction in progress on the connection.

Parameters
function(Error error)

The parameters of the callback function are:

Callback function parameter Description
Error error If commit() succeeds, error is NULL. If an error occurs, then error contains the error message.

4.2.5 connection.createLob()

Prototype

Callback:

createLob(Number type, function(Error error, Lob lob){});

Promise:

promise = createLob(Number type);
Description

Creates a Lob as an Oracle temporary LOB. The LOB is initially empty. Data can be streamed to the LOB, which can then be passed into PL/SQL blocks, or inserted into the database.

When no longer required, Lobs created with createLob() should be closed with lob.close() because Oracle Database resources are held open if temporary LOBs are not closed.

Open temporary LOB usage can be monitored using the view V$TEMPORARY_LOBS.

LOBs created with createLob() can be bound for IN, IN OUT and OUT binds.

See Working with CLOB and BLOB Data and LOB Bind Parameters for more information.

Parameters
Number type

One of the constants oracledb.CLOB or oracledb.BLOB.

function(Error error)

The parameters of the callback function are:

Callback function parameter Description
Error error If createLob() succeeds, error is NULL. If an error occurs, then error contains the error message.

4.2.6 connection.execute()

Prototype

Callback:

execute(String sql, [Object bindParams, [Object options,]] function(Error error, [Object result]){});

Promise:

promise = execute(String sql, [Object bindParams, [Object options]]);
Description

This call executes a single SQL or PL/SQL statement. See SQL Execution for examples. Also see queryStream() for an alternative way of executing queries.

The statement to be executed may contain IN binds, OUT or IN OUT bind values or variables, which are bound using either an object or an array.

A callback function returns a result object, containing any fetched rows, the values of any OUT and IN OUT bind variables, and the number of rows affected by the execution of DML statements.

Parameters
Parameter Description
String sql The SQL statement that is executed. The statement may contain bind parameters.
Object bindParams This function parameter is needed if there are bind parameters in the SQL statement.
Object options This is an optional parameter to execute() that may be used to control statement execution.
function(Error error, [Object result]) Callback function with the execution results.

The parameters are discussed in the next sections.

4.2.6.1 execute(): SQL Statement
String sql

The SQL or PL/SQL statement that execute() executes. The statement may contain bind variables.

4.2.6.2 execute(): Bind Parameters
Object bindParams

The execute() function bindParams parameter is needed if there are bind variables in the statement, or if options are used. It can be either an object that associates values or JavaScript variables to the statement's bind variables by name, or an array of values or JavaScript variables that associate to the statement's bind variables by their relative positions. See Bind Parameters for Prepared Statements for more details on binding.

If a bind value is an object it may have the following properties:

Bind Property Description
dir The direction of the bind. One of the Execute Bind Direction Constants oracledb.BIND_IN, oracledb.BIND_INOUT, or oracledb.BIND_OUT. The default is oracledb.BIND_IN.
maxArraySize The number of array elements to be allocated for a PL/SQL Collection INDEX BY associative array OUT or IN OUT array bind variable. For IN binds, the value of maxArraySize is ignored. See PL/SQL Collection Associative Array (Index-by) Bind Parameters.
maxSize The maximum number of bytes that an OUT or IN OUT bind variable of type oracledb.STRING or oracledb.BUFFER can use to get data. The default value is 200. The maximum limit depends on the database type, see below. When binding IN OUT, then maxSize refers to the size of the returned value: the input value can be smaller or bigger. For IN binds, maxSize is ignored.
type The node-oracledb or JavaScript data type to be bound. One of the Node-oracledb Type Constants oracledb.BLOB, oracledb.BUFFER, oracledb.CLOB, oracledb.CURSOR, oracledb.DATE, oracledb.NUMBER, or oracledb.STRING. With IN or IN OUT binds the type can be explicitly set with type or it will default to the type of the input data value. With OUT binds, the type defaults to oracledb.STRING whenever type is not specified.
val The input value or variable to be used for an IN or IN OUT bind variable.

The limit for maxSize when binding as oracledb.BUFFER is 2000 bytes, and as oracledb.STRING is 4000 bytes unless you are using Oracle Database 12c and the database initialization parameter MAX_STRING_SIZE has a value of EXTENDED. In this case the limit is 32767 bytes.

When binding Oracle LOBs as oracledb.STRING or oracledb.BUFFER, the value of maxSize can be much larger, see the limits in LOB Bind Parameters.

When binding to get a UROWID value from the database, note that UROWIDs can take up to 5267 bytes when fetched from the database so maxSize should be set to at least this value.

Note oracledb.CURSOR bind variables can be used only for PL/SQL OUT binds.

4.2.6.3 execute(): Options
Object options

This is an optional parameter to execute() that may be used to control statement execution.

If there are no bind variables in the SQL statement, then a null bindParams, for example {}, must be specified before options otherwise you will get an error like ORA-01036: Illegal variable name/number or NJS-012: encountered invalid bind data type in parameter.

The following properties can be set or overridden for the execution of a statement.

4.2.6.3.1 autoCommit
Boolean autoCommit

Overrides oracledb.autoCommit.

4.2.6.3.2 extendedMetaData
Boolean extendedMetaData

Overrides oracledb.extendedMetaData.

4.2.6.3.3 fetchArraySize
Number fetchArraySize

Overrides oracledb.fetchArraySize.

4.2.6.3.4 fetchInfo
Object fetchInfo

Object defining how query column data should be represented in JavaScript. It can be used in conjunction with, or instead of, the global settings fetchAsString and fetchAsBuffer.

The valid values for type are oracledb.STRING, oracledb.BUFFER and oracledb.DEFAULT.

The fetchInfo property type can be set to oracledb.STRING for number, date and raw columns in a query to indicate they should be returned as Strings instead of their native format. CLOB column data can also be returned as Strings instead of Lob instances.

When fetchInfo is set to oracledb.BUFFER for a BLOB column, each BLOB item will be returned as a Buffer instead of a Lob instance.

Using oracledb.DEFAULT overrides any global mapping given by fetchAsString or fetchAsBuffer. The column data is returned in native format.

For example:

fetchInfo:
{
  "HIRE_DATE":    { type : oracledb.STRING },  // return the date as a string
  "HIRE_DETAILS": { type : oracledb.DEFAULT }  // override fetchAsString or fetchAsBuffer
}

Each column is specified by name, using Oracle's standard naming convention.

Raw columns returned as strings will be returned as hex-encoded strings. The maximum length of a string created by type mapping number and date columns is 200 bytes. If a database column that is already being fetched as type oracledb.STRING is specified in fetchInfo, then the actual database metadata will be used to determine the maximum length.

Strings and Buffers created for LOB columns will generally be limited by Node.js and V8 memory restrictions.

Columns fetched from REF CURSORS are not mapped by fetchInfo settings in the execute() call. Use the global fetchAsString or fetchAsBuffer settings instead.

See Query Result Type Mapping for more information on query type mapping.

4.2.6.3.5 maxRows
Number maxRows

Overrides oracledb.maxRows.

4.2.6.3.6 outFormat
String outFormat

Overrides oracledb.outFormat.

4.2.6.3.7 prefetchRows
Number prefetchRows

This attribute is no longer supported in node-oracledb version 2 and has no effect on applications. Use fetchArraySize instead.

4.2.6.3.8 resultSet
Boolean resultSet

Determines whether query results should be returned as a ResultSet object or directly. The default is false.

4.2.6.4 execute(): Callback Function
function(Error error, [Object result])

The parameters of the execute() callback function are:

Callback function parameter Description
Error error If execute() succeeds, error is NULL. If an error occurs, then error contains the error message.
Object result The result object, described below. The result parameter can be omitted for DDL and DML statements where the application only checks error for success or failure.
Result Object Properties

The properties of result object from the execute() callback are described below.

4.2.6.4.1 metaData
readonly Array metaData

For SELECT statements, this contains an array of objects describing details of columns for the select list. For non queries, this property is undefined.

Each column's name is always given. If the oracledb.extendedMetaData or execute() option extendedMetaData are true then additional information is included.

  • name: The column name follows Oracle's standard name-casing rules. It will commonly be uppercase, since most applications create tables using unquoted, case-insensitive names.
  • fetchType: one of the Node-oracledb Type Constant values.
  • dbType: one of the Oracle Database Type Constant values.
  • byteSize: the database byte size. This is only set for oracledb.DB_TYPE_VARCHAR, oracledb.DB_TYPE_CHAR and oracledb.DB_TYPE_RAW column types.
  • precision: set only for oracledb.DB_TYPE_NUMBER, oracledb.DB_TYPE_TIMESTAMP, oracledb.DB_TYPE_TIMESTAMP_TZ and oracledb.DB_TYPE_TIMESTAMP_LTZ columns.
  • scale: set only for oracledb.DB_TYPE_NUMBER columns.
  • nullable: indicates whether NULL values are permitted for this column.

For numeric columns: when precision is 0, then the column is simply a NUMBER. If precision is nonzero and scale is -127, then the column is a FLOAT. Otherwise, it is a NUMBER(precision, scale).

Metadata for ResultSets and REF CURSORS is available in a ResultSet property. For Lobs, a Lob type property also indicates whether the object is a BLOB or CLOB.

To get query metadata without fetching rows, use a ResultSet. Access resultset.metaData and then close the ResultSet. Do not call getRow() or getRows(). Preferably use a query clause such as WHERE 1 = 0 so the database does minimal work.

See Query Column Metadata for examples.

4.2.6.4.2 outBinds
Array/object outBinds

This contains the output values of OUT and IN OUT binds. If bindParams is passed as an array, then outBinds is returned as an array. If bindParams is passed as an object, then outBinds is returned as an object. If there are no OUT or IN OUT binds, the value is undefined.

4.2.6.4.3 resultSet
Object resultSet

For SELECT statements when the resultSet option is true, use the resultSet object to fetch rows. See ResultSet Class and Fetching Rows with Result Sets.

When using this option, resultSet.close() must be called when the ResultSet is no longer needed. This is true whether or not rows have been fetched from the ResultSet.

4.2.6.4.4 rows
Array rows

For SELECT statements using direct fetches, rows contains an array of fetched rows. It will be NULL if there is an error or the SQL statement was not a SELECT statement. By default, the rows are in an array of column value arrays, but this can be changed to arrays of objects by setting outFormat to oracledb.OBJECT. If a single row is fetched, then rows is an array that contains one single row.

The number of rows returned is limited by oracledb.maxRows or the maxRows option in an execute() call. If maxRows is 0, then the number of rows is limited by Node.js memory constraints.

4.2.6.4.5 rowsAffected
Number rowsAffected

For DML statements (including SELECT FOR UPDATE) this contains the number of rows affected, for example the number of rows inserted. For non-DML statements such as queries and PL/SQL statements, rowsAffected is undefined.

4.2.7 connection.executeMany()

Prototype

Callback:

executeMany(String sql, Array binds, [Object options], function(Error error, [Object result]) {});
executeMany(String sql, Number numIterations, [Object options], function(Error error, [Object result]) {});

Promise:

promise = executeMany(String sql, Array binds, [Object options]);
promise = executeMany(String sql, Number numIterations, [Object options]);
Description

This method allows sets of data values to be bound to one DML or PL/SQL statement for execution. It is like calling connection.execute() multiple times but requires fewer round-trips. This is an efficient way to handle batch changes, for example when inserting or updating multiple rows. The method cannot be used for queries.

The executeMany() method supports IN, IN OUT and OUT binds for most data types except PL/SQL Collection Associative Arrays.

The version of this function which accepts a number of iterations should be used when no bind parameters are required or when all bind parameters are OUT binds.

See Batch Statement Execution for more information.

This method was added in node-oracledb 2.2.

4.2.6.1 executeMany(): SQL Statement
String sql

The SQL or PL/SQL statement that executeMany() executes. The statement should contain bind variable names.

4.2.7.2 executeMany(): Binds

The binds parameter contains the values or variables to be bound to the executed statement. It must be an array of arrays (for 'bind by position') or an array of objects whose keys match the bind variable names in the SQL statement (for 'bind by name'). Each sub-array or sub-object should contain values for the bind variables used in the SQL statement. At least one such record must be specified.

If a record contains fewer values than expected, NULL values will be used. For bind by position, empty values can be specified using syntax like [a,,c,d].

By default, the direction of binds is oracledb.BIND_IN. The first data record determines the number of bind variables, each bind variable's data type, and its name (when binding by name). If a variable in the first record contains a null, this value is ignored and a subsequent record is used to determine that variable's characteristics. If all values in all records for a particular bind variable are null, the type of that bind is oracledb.STRING with a maximum size of 1.

The maximum sizes of strings and buffers are determined by scanning all records in the bind data.

If a bindDefs property is used, no data scanning occurs. This property explicitly specifies the characteristics of each bind variable.

4.2.7.3 executeMany(): Options

The options parameter is optional. It can contain the following properties.

4.2.7.3.1 autoCommit
Boolean autoCommit

This optional property overrides oracledb.autoCommit.

Note batchErrors can affect autocommit mode.

4.2.7.3.2 batchErrors
Boolean batchErrors

This optional property allows invalid data records to be rejected while still letting valid data be processed. It can only be set true for INSERT, UPDATE, DELETE or MERGE statements.

When false, the executeMany() call will stop when the first error occurs. The callback error object will be set.

When batchErrors is true, processing will continue even if there are data errors. The executeMany() callback error parameter is not set. Instead, an array containing each error will be returned in the callback result parameter. All valid data records will be processed and a transaction will be started but not committed, even if autoCommit is true. The application can examine the errors, take action, and explicitly commit or rollback as desired.

Note that some classes of error will always return via the executeMany() callback error object, not as batch errors. No transaction is created in this case.

The default value is false.

4.2.7.3.3 bindDefs
Object bindDefs

The bindDefs object defines the bind variable types, sizes and directions. This object is optional in some cases but it is more efficient to set it.

It should be an array or an object, depending on the structure of the binds parameter.

Each value in the bindDefs array or object should be an object containing the keys dir, maxSize, and type for each bind variable, similar to how execute() bind parameters are identified.

BindDef Property Description
dir The direction of the bind. One of the Execute Bind Direction Constants oracledb.BIND_IN, oracledb.BIND_INOUT or oracledb.BIND_OUT. The default is oracledb.BIND_IN.
maxSize Required for Strings and Buffers. Ignored for other types. Specifies the maximum number of bytes allocated when processing each value of this bind variable. When data is being passed into the database, maxSize should be at least the size of the longest value. When data is being returned from the database, maxSize should be the size of the longest value. If maxSize is too small, executeMany() will throw an error that is not handled by batchErrors.
type The node-oracledb or JavaScript data type to be bound. One of the Node-oracledb Type Constants oracledb.BLOB, oracledb.BUFFER, oracledb.CLOB, oracledb.CURSOR, oracledb.DATE, oracledb.NUMBER, or oracledb.STRING.
4.2.7.3.4 dmlRowCounts
Boolean dmlRowCounts

When true, this optional property enables output of the number of rows affected by each input data record. It can only be set true for INSERT, UPDATE, DELETE or MERGE statements.

The default value is false.

This feature works when node-oracledb is using version 12, or later, of the Oracle client library.

4.2.7.4 executeMany(): Callback Function
4.2.7.4.1 batchErrors
Array batchErrors

This property is an array of error objects that were reported during execution. The offset property of each error object corresponds to the 0-based index of the executeMany() binds parameter array, indicating which record could not be processed.

It will be present only if batchErrors was true in the executeMany() options parameter and there are data errors to report. Some classes of execution error will always return via the executeMany() callback error object, not in batchErrors.

4.2.7.4.2 dmlRowCounts
Array dmlRowCounts

This is an array of integers identifying the number of rows affected by each record of the binds parameter. It is present only if dmlRowCounts was true in the executeMany() options parameter and a DML statement was executed.

4.2.7.4.3 outBinds
Object outBinds

This contains the value of any returned IN OUT or OUT binds. It is an array of arrays, or an array of objects, depending on the binds parameters structure. The length of the array will correspond to the length of the array passed as the binds parameter. It will be present only if there is at least one OUT bind variable identified.

4.2.7.4.4 rowsAffected
Number rowsAffected

This is an integer identifying the total number of database rows affected by the processing of all records of the binds parameter. It is only present if a DML statement was executed.

4.2.8 connection.getStatementInfo()

Prototype

Callback:

getStatementInfo(String sql, function(Error error, [Object information]){});

Promise:

promise = getStatementInfo(String sql);
Description

Parses a SQL statement and returns information about it. This is most useful for finding column names of queries, and for finding the names of bind variables used.

This method performs a round-trip to the database, so unnecessary calls should be avoided.

The information is provided by lower level APIs that have some limitations. Some uncommon statements will return the statement type as oracledb.STMT_TYPE_UNKNOWN. DDL statements are not parsed, so syntax errors in them will not be reported. The direction and types of bind variables cannot be determined.

This method was added in node-oracledb 2.2.

Parameters
String sql

The SQL statement to parse.

function(Error error, [Object information])

The parameters of the callback function are:

Callback function parameter Description
Error error If getStatementInfo() succeeds, error is NULL. If an error occurs, then error contains the error message.
Object information The information object, described below.

Depending on the statement type, the information object may contain:

  • bindNames: an array of strings corresponding to the unique names of the bind variables used in the SQL statement.

  • metaData: containing properties equivalent to those given by execute() extendedMetaData. This property exists only for queries.

  • statementType: an integer corresponding to one of the SQL Statement Type Constants.

4.2.9 connection.ping()

Prototype

Callback:

ping(function(Error error){});

Promise:

promise = ping();
Description

This method checks that a connection is currently usable and the network to the database is valid. This call can be useful for system health checks. A ping only confirms that a single connection is usable at the time of the ping.

Pinging doesn't replace error checking during statement execution, since network or database failure may occur in the interval between ping() and execute() calls.

Pinging requires a round-trip to the database so unnecessary ping calls should be avoided.

If ping() returns an error, the application should close the connection.

This method was added in node-oracledb 2.2.

Parameters
function(Error error)

The parameters of the callback function are:

Callback function parameter Description
Error error If ping() succeeds, error is NULL. If an error occurs, then error contains the error message.

4.2.10 connection.queryStream()

Prototype
queryStream(String sql, [Object bindParams, [Object options]]);
Return Value

This method will return a Readable Stream for queries.

Description

This function provides query streaming support. The parameters are the same as execute() except a callback is not used. Instead this function returns a stream used to fetch data.

Each row is returned as a data event. Query metadata is available via a metadata event. The end event indicates the end of the query results.

The connection must remain open until the stream is completely read.

For tuning, adjust the value of oracledb.fetchArraySize or the execute() option fetchArraySize.

See Query Streaming for more information.

Support for Node.js version 8 Stream destroy() method was added in node-oracledb 2.1.

This method was added in node-oracledb 1.8.

Parameters

See execute().

4.2.11 connection.release()

An alias for connection.close().

4.2.12 connection.rollback()

Prototype

Callback:

rollback(function(Error error){});

Promise:

promise = rollback();
Description

This call rolls back the current transaction in progress on the connection.

Parameters
function(Error error)

The parameters of the callback function are:

Callback function parameter Description
Error error If rollback() succeeds, error is NULL. If an error occurs, then error contains the error message.

4.2.13 connection.subscribe()

Prototype

Callback:

subscribe(String name, Object options, function(Error error){});

Promise:

promise = subscribe(String name, Object options);
Description

Register a JavaScript callback method to be invoked when data is changed in the database by any committed transaction.

For notification to work, the connection must be created with events mode true.

The database must be able to connect to the node-oracledb machine for notifications to be received. Typically this means that the machine running node-oracledb needs a fixed IP address. If there is any problem sending a notification, then the callback method will not be invoked.

The connection.subscribe() method may be called multiple times with the same name. In this case, the second and subsequent invocations ignore all options properties other than sql and binds. Instead, the new SQL statement is registered to the same subscription, and the same JavaScript notification callback is used. For performance reasons this can be preferable to creating a new subscription for each query.

See Continuous Query Notification (CQN) for more information.

This method was added in node-oracledb 2.3.

4.2.13.1 subscribe(): Name
String name

For Continuous Query Notification this is an arbitrary name given to the subscription. For Advanced Queue notifications this must be the queue name.

4.2.13.2 subscribe(): Options
Object options

The options that control the subscription. The following properties can be set.

4.2.13.2.1 binds
Object binds

An array (bind by position) or object (bind by name) containing the bind values to use in the sql property.

4.2.13.2.2 callback
function callback(message);

The notification callback that will be called whenever notifications are sent by the database. It accepts one parameter which contains details of the notification.

Callback function parameter Description
Object message Information about the notification. Described below.

The message parameter in the notification callback is an object containing the following properties:

  • dbName - the name of the database which sent a notification. This property is only defined for CQN. It is not defined when type is oracledb.SUBSCR_EVENT_TYPE_DEREG.
  • queries - an array of objects specifying the queries which were affected by the Query Change notification. This is only defined if the type key is the value oracledb.SUBSCR_EVENT_TYPE_QUERY_CHANGE. It contains the following key:
    • tables - an array of objects identical to the objects created for Database Change Notification (see the tables property below).
  • registered - a boolean indicating whether the subscription is registerd with the database. Will be false if type is oracledb.SUBSCR_EVENT_TYPE_DEREG or if the subscription was created with the qos property set to oracledb.SUBSCR_QOS_DEREG_NFY.
  • tables - an array of objects specifying the tables which were affected by the notification. This is only defined if type is oracledb.SUBSCR_EVENT_TYPE_OBJ_CHANGE. It contains the following properties:
    • name - the name of the table which was modified in some way.
    • operation - an integer mask composed of one or more values of the following constants:
    • rows - an array of objects specifying the rows which were changed. This will only be defined if the qos quality of service used when creating the subscription indicated the desire for ROWIDs and no summary grouping took place. It contains the following properties:
  • txId - a buffer containing the identifier of the transaction which spawned the notification.
  • type - the type of notification sent. This will be the value of one of the following constants:
4.2.13.2.3 groupingClass
Number groupingClass

An integer mask which currently, if set, can only contain the value oracledb.SUBSCR_GROUPING_CLASS_TIME. If this value is set then notifications are grouped by time into a single notification.

4.2.13.2.4 groupingType
Number groupingType

Either oracledb.SUBSCR_GROUPING_TYPE_SUMMARY (the default) indicating notifications should be grouped in a summary, or oracledb.SUBSCR_GROUPING_TYPE_LAST indicating the last notification in the group should be sent.

4.2.13.2.5 groupingValue
Number groupingValue

If groupingClass contains oracledb.SUBSCR_GROUPING_CLASS_TIME then groupingValue can be used to set the number of seconds over which notifications will be grouped together, invoking callback once. If groupingClass is not set, then groupingValue is ignored.

4.2.13.2.6 ipAddress
String ipAddress

A string containing an IPv4 or IPv6 address on which the subscription should listen to receive notifications. If not specified, then the Oracle Client library will select an IP address.

4.2.13.2.7 namespace
Number namespace

One of the oracledb.SUBSCR_NAMESPACE_AQ or oracledb.SUBSCR_NAMESPACE_DBCHANGE (the default) constants.

You can use oracledb.SUBSCR_NAMESPACE_AQ to get notifications that Advanced Queuing messages are available to be dequeued. Note Advanced Queuing enqueue and dequeue methods are not supported yet.

4.2.13.2.8 operations
Number operations

An integer mask containing one or more of the operation type oracledb.CQN_OPCODE_* constants to indicate what types of database change should generation notifications.

4.2.13.2.9 port
Number port

The port number on which the subscription should listen to receive notifications. If not specified, then the Oracle Client library will select a port number.

4.2.13.2.10 qos
Number qos

An integer mask containing one or more of the quality of service oracledb.CQN_QOS_* constants.

4.2.13.2.11 sql
String sql

The SQL query string to use for notifications.

4.2.13.2.12 timeout

The number of seconds the subscription should remain active. Once this length of time has been reached, the subscription is automatically unregistered and a deregistration notification is sent.

4.2.13.3 subscribe(): Callback Function
function(Error error)

The parameters of the callback function are:

Callback function parameter Description
Error error If subscribe() succeeds, error is NULL. If an error occurs, then error contains the error message.

4.2.14 connection.unsubscribe()

Prototype

Callback:

unsubscribe(String name, function(Error error){});

Promise:

promise = unsubscribe(String name);
Description

Unregister a Continuous Query Notification (CQN) subscription previously created with connection.subscribe(). No further notifications will be sent. The notification callback does not receive a notification of the deregistration event.

A subscription can be unregistered using a different connection to the initial subscription, as long as the credentials are the same.

If the subscription timeout was reached and the subscription was automatically unregistered, you will get an error if you call connection.unsubscribe().

This method was added in node-oracledb 2.3.

Parameters
String name

The name of the subscription used in connection.subscribe().

function(Error error)

The parameters of the callback function are:

Callback function parameter Description
Error error If unsubscribe() succeeds, error is NULL. If an error occurs, then error contains the error message.

5. Lob Class

Lob objects can be used to access Oracle Database CLOB and BLOB data.

A Lob object implements the Node.js Stream interface.

See Working with CLOB and BLOB Data and LOB Bind Parameters for more information.

5.1 Lob Properties

The properties of a Lob object are listed below.

5.1.1 lob.chunkSize

readonly Number chunkSize

This corresponds to the size used by the Oracle LOB layer when accessing or modifying the LOB value.

5.1.2 lob.length

readonly Number length

Length of a queried LOB in bytes (for BLOBs) or characters (for CLOBs).

5.1.3 lob.pieceSize

Number pieceSize

The number of bytes (for BLOBs) or characters (for CLOBs) to read for each Stream 'data' event of a queried LOB.

The default value is chunkSize.

For efficiency, it is recommended that pieceSize be a multiple of chunkSize.

The property should not be reset in the middle of streaming since data will be lost when internal buffers are resized.

The maximum value for pieceSize is limited to the value of UINT_MAX.

5.1.4 lob.type

readonly Number type

This read-only attribute shows the type of Lob being used. It will have the value of one of the constants oracledb.BLOB or oracledb.CLOB. The value is derived from the bind type when using LOB bind variables, or from the column type when a LOB is returned by a query.

5.2 Lob Methods

5.2.1 lob.close()

Prototype

Callback:

close(function(Error error){});

Promise:

promise = close();
Description

Explicitly closes a Lob.

Lobs created with createLob() should be explicitly closed with lob.close() when no longer needed. This frees resources in node-oracledb and in Oracle Database.

Persistent or temporary Lobs returned from the database may also be closed with lob.close() as long as streaming is not currently happening. Note these Lobs are automatically closed when streamed to completion or used as the source for an IN OUT bind. If you try to close a Lob being used for streaming you will get the error NJS-023: concurrent operations on a Lob are not allowed.

The lob.close() method emits the Node.js Stream 'close' event unless the Lob has already been explicitly or automatically closed.

The connection must be open when calling lob.close() on a temporary LOB, such as those created by createLob().

Once a Lob is closed, it cannot be bound.

See Closing Lobs for more discussion.

Parameters
function(Error error)

The parameters of the callback function are:

Callback function parameter Description
Error error If close() succeeds, error is NULL. If an error occurs, then error contains the error message.

6. Pool Class

A connection Pool object is created by calling the oracledb.createPool() method.

The Pool object obtains connections to the Oracle database using the getConnection() method to "check them out" from the pool. Internally Oracle Call Interface Session Pooling is used.

After the application finishes using a connection pool, it should release all connections and terminate the connection pool by calling the close() method on the Pool object.

See Connection Pooling for more information.

6.1 Pool Properties

The Pool object properties may be read to determine the current values.

6.1.1 pool.connectionsInUse

readonly Number connectionsInUse

The number of currently active connections in the connection pool i.e. the number of connections currently "checked out" using getConnection().

6.1.2 pool.connectionsOpen

readonly Number connectionsOpen

The number of currently open connections in the underlying connection pool.

6.1.3 pool.poolAlias

readonly Number poolAlias

The alias of this pool in the connection pool cache. An alias cannot be changed once the pool has been created.

6.1.4 pool.poolIncrement

readonly Number poolIncrement

The number of connections that are opened whenever a connection request exceeds the number of currently open connections.

See oracledb.poolIncrement.

6.1.5 pool.poolMax

readonly Number poolMax

The maximum number of connections that can be open in the connection pool.

See oracledb.poolMax.

6.1.6 pool.poolMin

readonly Number poolMin

The minimum number of connections a connection pool maintains, even when there is no activity to the target database.

See oracledb.poolMin.

6.1.7 pool.poolPingInterval

readonly Number poolPingInterval

The maximum number of seconds that a connection can remain idle in a connection pool (not "checked out" to the application by getConnection()) before node-oracledb pings the database prior to returning that connection to the application.

See oracledb.poolPingInterval.

6.1.8 pool.poolTimeout

readonly Number poolTimeout

The time (in seconds) after which the pool terminates idle connections (unused in the pool). The number of connections does not drop below poolMin.

See oracledb.poolTimeout.

6.1.9 pool.queueRequests

This property was removed in node-oracledb 3.0. Queuing is now always enabled. See Connection Pool Queue for more information.

6.1.10 pool.queueTimeout

readonly Number queueTimeout

The time (in milliseconds) that a connection request should wait in the queue before the request is terminated.

See oracledb.queueTimeout.

6.1.11 pool.stmtCacheSize

readonly Number stmtCacheSize

The number of statements to be cached in the statement cache of each connection.

See oracledb.stmtCacheSize.

6.2 Pool Methods

6.2.1 pool.close()

Prototype

Callback:

close(function(Error error){});

Promise:

promise = close();
Description

This call terminates the connection pool.

Any open connections should be released with connection.close() before pool.close() is called.

If the pool is in the connection pool cache it will be removed from the cache.

This method was added to node-oracledb 1.9, replacing the equivalent alias pool.terminate().

Parameters
function(Error error)

The parameters of the callback function are:

Callback function parameter Description
Error error If close() succeeds, error is NULL. If an error occurs, then error contains the error message.

6.2.2 pool.getConnection()

Prototype

Callback:

getConnection([Object poolAttrs,] function(Error error, Connection conn){});

Promise:

promise = getConnection([Object poolAttrs]);
Description

This method obtains a connection from the connection pool.

If a previously opened connection is available in the pool, that connection is returned. If all connections in the pool are in use, a new connection is created and returned to the caller, as long as the number of connections does not exceed the specified maximum for the pool. If the pool is at its maximum limit, the getConnection() call results in an error, such as ORA-24418: Cannot open further sessions.

By default pools are created with homogeneous set to true. The user name and password are supplied when the pool is created. Each time pool.getConnection() is called, a connection for that user is returned:

  pool.getConnection(
    function (err, conn) { ... }
  );

If a heterogeneous pool was created by setting homogeneous to false during creation and credentials were omitted, then the user name and password may be used in pool.getConnection() like:

  pool.getConnection(
    {
      user     : 'hr',
      password : 'welcome'
    },
    function (err, conn) { ... }
  );

In this case, different user names may be used each time pool.getConnection() is called. Proxy users may also be specified.

See Connection Handling for more information on connections.

See Heterogeneous Connection Pools and Pool Proxy Authentication for more information on heterogeneous pools.

Parameters
Object poolAttrs

This optional parameter is used when getting connections from heterogeneous pools. It can contain user and password properties for true heterogeneous pool usage, or it can contain a user property when a pool proxy user is desired.

function(Error error, Connection conn)

The parameters of the callback function are:

Callback function parameter Description
Error error If getConnection() succeeds, error is NULL. If an error occurs, then error contains the error message.
Connection connection The newly created connection. If getConnection() fails, connection will be NULL. See Connection class for more details.

6.2.3 pool.terminate()

An alias for pool.close().

7. ResultSet Class

ResultSets allow query results to fetched from the database one at a time, or in groups of rows. They can also be converted to Readable Streams. ResultSets enable applications to process very large data sets.

ResultSets should also be used where the number of query rows cannot be predicted and may be larger than Node.js can handle in a single array.

A ResultSet object is obtained by setting resultSet: true in the options parameter of the Connection execute() method when executing a query. A ResultSet is also returned to node-oracledb when binding as type oracledb.CURSOR to a PL/SQL REF CURSOR bind parameter.

See Fetching Rows with Result Sets for more information on ResultSets.

7.1 ResultSet Properties

The properties of a ResultSet object are listed below.

7.1.1 resultset.metaData

readonly Array metaData

Contains an array of objects with metadata about the query or REF CURSOR columns.

Each column's name is always given. If the oracledb.extendedMetaData or execute() option extendedMetaData are true then additional information is included.

See result.metaData for the available attributes.

7.2 ResultSet Methods

7.2.1 resultset.close()

Prototype

Callback:

close(function(Error error){});

Promise:

promise = close();
Description

Closes a ResultSet. Applications should always call this at the end of fetch or when no more rows are needed. It should also be called if no rows are ever going to be fetched from the ResultSet.

7.2.2 resultset.getRow()

Prototype

Callback:

getRow(function(Error error, Object row){});

Promise:

promise = getRow();
Description

This call fetches one row of the ResultSet as an object or an array of column values, depending on the value of outFormat.

At the end of fetching, the ResultSet should be freed by calling close().

Performance of getRow() can be tuned by adjusting the value of oracledb.fetchArraySize or the execute() option fetchArraySize.

7.2.3 resultset.getRows()

Prototype

Callback:

getRows(Number numRows, function(Error error, Array rows){});

Promise:

promise = getRows(Number numRows);
Description

This call fetches numRows rows of the ResultSet as an object or an array of column values, depending on the value of outFormat.

At the end of fetching, the ResultSet should be freed by calling close().

Different values of numRows may alter the time needed for fetching data from Oracle Database. The value of fetchArraySize has no effect on getRows() performance or internal buffering.

7.2.4 resultset.toQueryStream()

Prototype
toQueryStream();
Return Value

This method will return a Readable Stream.

Description

This synchronous method converts a ResultSet into a stream.

It can be used to make ResultSets from top-level queries or from REF CURSOR bind variables streamable. To make top-level queries streamable, the alternative connection.queryStream() method may be easier to use.

To change the behavior of toQueryStream(), such as setting the query output Format or the internal buffer size for performance, adjust global attributes such as oracledb.outFormat and oracledb.fetchArraySize before calling execute().

See Query Streaming for more information.

The toQueryStream() method was added in node-oracledb 1.9. Support for Node.js version 8 Stream destroy() method was added in node-oracledb 2.1.

NODE-ORACLEDB USER MANUAL

8. Connection Handling

In applications which use connections infrequently, create a connection with oracledb.getConnection(). Connections should be released with connection.close() when no longer needed:

var oracledb = require('oracledb');

oracledb.getConnection(
  {
    user          : "hr",
    password      : "welcome",
    connectString : "localhost/XE"
  },
  function(err, connection) {
    if (err) { console.error(err.message); return; }

    . . .  // use connection

    connection.close(
      function(err) {
        if (err) { console.error(err.message); }
      });
  });

Applications which are heavy users of connections should create and use a Connection Pool.

8.1 Connection Strings

The connectString parameter for oracledb.getConnection() and pool.getConnection() can be an Easy Connect string, or a Net Service Name from a local tnsnames.ora file or external naming service, or it can be the SID of a local Oracle database instance.

The connectionString property is an alias for connectString. Use only one of the properties.

If a connect string is not specified, the empty string "" is used which indicates to connect to the local, default database.

8.1.1 Easy Connect Syntax for Connection Strings

An Easy Connect string is often the simplest to use. With Oracle Database 12c the syntax is:

[//]host_name[:port][/service_name][:server_type][/instance_name]

Note that old-school connection SIDs are not supported: only service names can be used.

For example, use "localhost/XE" to connect to the database XE on the local machine:

var oracledb = require('oracledb');

oracledb.getConnection(
  {
    user          : "hr",
    password      : "welcome",
    connectString : "localhost/XE"
  },
  . . .

For more information on Easy Connect strings see Understanding the Easy Connect Naming Method in the Oracle documentation.

8.1.2 Net Service Names for Connection Strings

A Net Service Name, such as sales in the example below, can be used to connect:

var oracledb = require('oracledb');

oracledb.getConnection(
  {
    user          : "hr",
    password      : "welcome",
    connectString : "sales"
  },
  . . .

This could be defined in a directory server, or in a local tnsnames.ora file, for example:

sales =
  (DESCRIPTION =
    (ADDRESS = (PROTOCOL = TCP)(HOST = mymachine.example.com)(PORT = 1521))
    (CONNECT_DATA =
      (SERVER = DEDICATED)
      (SERVICE_NAME = orcl)
    )
  )

Some older databases may use a 'SID' instead of a 'Service Name'. A connection string for these databases could look like:

sales =
  (DESCRIPTION =
    (ADDRESS = (PROTOCOL = TCP)(HOST = mymachine.example.com)(PORT = 1521))
    (CONNECT_DATA =
      (SERVER = DEDICATED)
      (SID = orcl)
    )
  )

See Optional Client Configuration Files for where tnsnames.ora files can be located.

For more information on tnsnames.ora files and contents see General Syntax of tnsnames.ora in the Oracle documentation.

8.1.3 Embedded Connection Strings

Full connection strings can be embedded in applications:

var oracledb = require('oracledb');

oracledb.getConnection(
  {
    user          : "hr",
    password      : "welcome",
    connectString : "(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=mymachine.example.com)(PORT=1521))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=orcl)))"
  },
  . . .

8.1.4 JDBC and Node-oracledb Connection Strings Compared

Developers familiar with Java connection strings that reference a service name like:

jdbc:oracle:thin:@hostname:port/service_name

can use Oracle's Easy Connect syntax in node-oracledb:

var oracledb = require('oracledb');

oracledb.getConnection(
  {
    user          : "hr",
    password      : "welcome",
    connectString : "hostname:port/service_name"
  },
  . . .

Alternatively, if a JDBC connection string uses an old-style SID, and there is no service name available:

jdbc:oracle:thin:@hostname:port:sid

then consider creating a tnsnames.ora entry, for example:

finance =
 (DESCRIPTION =
   (ADDRESS = (PROTOCOL = TCP)(HOST = hostname)(PORT = 1521))
   (CONNECT_DATA =
     (SID = ORCL)
   )
 )

This can be referenced in node-oracledb:

var oracledb = require('oracledb');

oracledb.getConnection(
  {
    user          : "hr",
    password      : "welcome",
    connectString : "finance"
  },
  . . .

8.2 Connections and Number of Threads

If you open more than four connections, such as via increasing poolMax, you should increase the number of worker threads available to node-oracledb. The thread pool size should be at least equal to the maximum number of connections. If the application does database and non-database work concurrently, extra threads could also be required for optimal throughput.

Increase the thread pool size by setting the environment variable UV_THREADPOOL_SIZE before starting Node. For example, in a Linux terminal, the number of Node.js worker threads can be increased to 10 by using the following command:

$ UV_THREADPOOL_SIZE=10 node myapp.js

If the value is set inside the application with process.env.UV_THREADPOOL_SIZE ensure it is set prior to any asynchronous call that uses the thread pool otherwise the default size of 4 will still be used.

Note the 'libuv' library used by Node.js limits the number of threads to 128. This implies the maxiumum number of connections opened, i.e. poolMax, should be less than 128.

Connections can handle one database operation at a time. Node.js worker threads executing database statements on a connection will wait until round-trips between node-oracledb and the database are complete. When an application handles a sustained number of user requests, and database operations take some time to execute or the network is slow, then all available threads may be held in use. This prevents other connections from beginning work and stops Node.js from handling more user load. Increasing the number of worker threads may improve throughput and prevent deadlocks.

As well as correctly setting the thread pool size, structure your code to avoid starting parallel operations on a connection. For example, instead of using async.parallel or async.each() which call each of their items in parallel, use async.series or async.eachSeries(). When you use parallel calls on a connection, the queuing ends up being done in the C layer via a mutex. However libuv isn't aware that a connection can only do one thing at a time - it only knows when it has background threads available and so it sends off the work to be done. If your application runs operations in parallel on a connection, you could use more than one background thread (perhaps all of them) and each could be waiting on the one before it to finish its "execute". Of course other users or transactions can't use the threads at that time either. When you use methods like async.series or async.eachSeries(), the queuing is instead done in the main JavaScript thread.

8.3 Connection Pooling

When applications use a lot of connections for short periods, Oracle recommends using a connection pool for efficiency. Each pool can contain one or more connections. A pool can grow or shrink, as needed. Each node-oracledb process can use one or more local pools of connections.

Pool expansion happens when the following are all true: (i) getConnection() is called and (ii) all the currently established connections in the pool are "checked out" by previous getConnection() calls and are in-use by the application, and (iii) the number of those connections is less than the pool's poolMax setting.

A pool is created by calling the oracledb.createPool() method. Internally Oracle Call Interface Session Pooling is used.

A connection is returned with the pool.getConnection() function:

var oracledb = require('oracledb');

oracledb.createPool (
  {
    user          : "hr"
    password      : "welcome"
    connectString : "localhost/XE"
  },
  function(err, pool) {
    pool.getConnection (
      function(err, connection) {
      . . .  // use connection
      });
  });

Connections should be released with connection.close() when no longer needed:

    connection.close(
      function(err) {
        if (err) { console.error(err.message); }
      });

Make sure to release connections in all codes paths, include error handlers.

After an application finishes using a connection pool, it should release all connections and terminate the connection pool by calling the pool.close() method.

The growth characteristics of a connection pool are determined by the Pool attributes poolIncrement, poolMax, poolMin and poolTimeout. Note that when External Authentication is used, the pool behavior is different, see External Authentication.

The Oracle Real-World Performance Group's general recommendation for client connection pools is for the minimum and maximum number of connections to be the same. This avoids connection storms which can decrease throughput. They also recommend sizing connection pools so that the sum of all connections from all applications accessing a database gives 1-10 connections per database server CPU core. See About Optimizing Real-World Performance with Static Connection Pools.

The Pool attribute stmtCacheSize can be used to set the statement cache size used by connections in the pool, see Statement Caching.

8.3.1 Connection Pool Cache

Node-oracledb has an internal connection pool cache which can be used to facilitate sharing pools across modules and simplify getting connections. At creation time, a pool can be given a named alias. The alias can later be used to retrieve the related pool object for use.

Methods that can affect or use the connection pool cache include:

Pools are added to the cache if a poolAlias property is provided in the poolAttrs object when invoking oracledb.createPool(). There can be multiple pools in the cache if each pool is created with a unique alias.

If a pool is created without providing a pool alias, and a pool with an alias of 'default' is not in the cache already, this pool will be cached using the alias 'default'. This pool is used by default in methods that utilize the connection pool cache. If subsequent pools are created without explicit aliases, they will be not stored in the pool cache.

Examples using the default pool

Assuming the connection pool cache is empty, the following will create a new pool and cache it using the pool alias 'default':

var oracledb = require('oracledb');

oracledb.createPool (
  {
    user: 'hr',
    password: 'welcome',
    connectString: 'localhost/XE'
  },
  function(err, pool) {
    console.log(pool.poolAlias); // 'default'
    . . . // use pool
  }
);

Note that createPool() is not synchronous.

Once cached, the default pool can be retrieved using oracledb.getPool() without passing the poolAlias parameter:

var oracledb = require('oracledb');
var pool = oracledb.getPool();

pool.getConnection(function(err, conn) {
  . . . // Use connection from the pool and then release it
});

This specific sequence can be simplified by using the shortcut to oracledb.getConnection() that returns a connection from a pool:

var oracledb = require('oracledb');

oracledb.getConnection(function(err, conn) {
  . . . // Use connection from the previously created 'default' pool and then release it
});
Examples using multiple pools

If the application needs to use more than one pool at a time, unique pool aliases can be used when creating the pools:

var oracledb = require('oracledb');

var hrPoolPromise = oracledb.createPool({
  poolAlias: 'hrpool',
  users: 'hr',
  password: 'welcome',
  connectString: 'localhost/XE'
});

var shPoolPromise = oracledb.createPool({
  poolAlias: 'shpool',
  user: 'sh',
  password: 'welcome',
  connectString: 'localhost/XE'
});

Promise.all([hrPoolPromise, shPoolPromise])
  .then(function(pools) {
    console.log(pools[0].poolAlias); // 'hrpool'
    console.log(pools[1].poolAlias); // 'shpool'
  })
  .catch(function(err) {
    . . . // handle error
  })

To use the methods or attributes of a pool in the cache, a pool can be retrieved from the cache by passing its pool alias to oracledb.getPool():

var oracledb = require('oracledb');
var pool = oracledb.getPool('hrpool'); // or 'shpool'

pool.getConnection(function(err, conn) {
  . . . // Use connection from the pool and then release it
});

The oracledb.getConnection() shortcut can also be used with a pool alias:

var oracledb = require('oracledb');

oracledb.getConnection('hrpool', function(err, conn) { // or 'shpool'
  . . . // Use connection from the pool and then release it
});

8.3.2 Connection Pool Queue

If the application has called getConnection() so that all connections in the pool are in use, and further pool.getConnection() requests (or oracledb.getConnection() calls that use a pool) are made, then each new request will be queued until an in-use connection is released back to the pool with connection.close(). If poolMax has not been reached, then connections can be satisfied and are not queued.

The amount of time that a queued request will wait for a free connection can be configured with queueTimeout. When connections are timed out of the queue, they will return the error NJS-040: connection request timeout to the application.

Internally the queue is implemented in node-oracledb's JavaScript top level. A queued connection request is dequeued and passed down to node-oracledb's underlying C++ connection pool when an active connection is released, and the number of connections in use drops below the value of poolMax.

8.3.3 Connection Pool Monitoring and Throughput

Connection pool usage should be monitored to choose the appropriate connection pool settings for your workload.

The Pool attributes connectionsInUse and connectionsOpen provide basic information about an active pool.

Further statistics can be enabled by setting the createPool() poolAttrs parameter _enableStats to true. Statistics can be output to the console by calling the pool._logStats() method. The underscore prefixes indicate that these are private attributes and methods. This interface may be altered or enhanced in the future.

To enable recording of queue statistics:

oracledb.createPool (
  {
    _enableStats  : true,   // default is false
    user          : "hr",
    password      : "welcome",
    connectString : "localhost/XE"
  },
  function(err, pool) {
  . . .

The application can later, on some developer-chosen event, display the current statistics to the console by calling:

pool._logStats();

The current implementation of _logStats() displays pool queue statistics, pool settings, and related environment variables.

Statistics

The statistics displayed by _logStats() in this release are:

Statistic Description
total up time The number of milliseconds this pool has been running.
total connection requests Number of getConnection() requests made by the application to this pool.
total requests enqueued Number of getConnection() requests that could not be immediately satisfied because every connection in this pool was already being used, and so they had to be queued waiting for the application to return an in-use connection to the pool.
total requests dequeued Number of getConnection() requests that were dequeued when a connection in this pool became available for use.
total requests failed Number of getConnection() requests that invoked the underlying C++ getConnection() callback with an error state. Does not include queue request timeout errors.
total request timeouts Number of queued getConnection() requests that were timed out after they had spent queueTimeout or longer in this pool's queue.
max queue length Maximum number of getConnection() requests that were ever waiting at one time.
sum of time in queue The sum of the time (milliseconds) that dequeued requests spent in the queue.
min time in queue The minimum time (milliseconds) that any dequeued request spent in the queue.
max time in queue The maximum time (milliseconds) that any dequeued request spent in the queue.
avg time in queue The average time (milliseconds) that dequeued requests spent in the queue.
pool connections in use The number of connections from this pool that getConnection() returned successfully to the application and have not yet been released back to the pool.
pool connections open The number of connections in this pool that have been established to the database.

Note that for efficiency, the minimum, maximum, average, and sum of times in the queue are calculated when requests are removed from the queue. They do not take into account times for connection requests still waiting in the queue.

Attribute Values

The _logStats() method also shows attribute values in effect for the pool:

Attribute
poolAlias
queueTimeout
poolMin
poolMax
poolIncrement
poolTimeout
poolPingInterval
stmtCacheSize
Related Environment Variables

One related environment variable is is shown by _logStats():

Environment Variable Description
process.env.UV_THREADPOOL_SIZE The number of worker threads for this process. Note this shows the value of the variable, however if this variable was set after the thread pool starts, the thread pool will actually be the default size of 4.

8.3.4 Connection Pool Pinging

Node-oracledb can 'ping' connections returned from pooled getConnection() calls to check for their aliveness. The frequency of pinging can be controlled with the oracledb.poolPingInterval property or during pool creation. The default ping interval is 60 seconds.

Without pinging, when connections are idle in a connection pool, there is the possibility that a network or database instance failure makes those connections unusable. A getConnection() call will happily return a connection from the pool but an error will occur when the application later uses the connection.

Note that explicit pinging is unnecessary and is not performed when node-oracledb is using version 12.2 of the Oracle client library. This has its own lightweight, always-enabled connection check. It will return a valid connection to the node-oracledb driver, which in turn returns it via getConnection(). The value of poolPingInterval is ignored.

With Oracle client 12.1 and earlier, when a pool getConnection() is called and the connection has been idle in the pool (not "checked out" to the application by getConnection()) for the specified poolPingInterval then an internal "ping" will be performed first. At the cost of some overhead for infrequently accessed connection pools, connection pinging improves the chance a pooled connection is valid when it is first used because identified un-unusable connections will not be returned to the application by getConnection(). For active applications that are getting and releasing connections rapidly, the connections will generally not have been idle longer than poolPingInterval so no pings will be performed and there will be no overhead.

If a ping detects the connection is invalid, for example if the network had disconnected, then node-oracledb internally drops the unusable connection and obtains another from the pool. This second connection may also need a ping. This ping-and-release process may be repeated until:

  • an existing connection that doesn't qualify for pinging is obtained. The getConnection() call returns this to the application. Note it is not guaranteed to be usable
  • a new, usable connection is opened. This is returned to the application
  • a number of unsuccessful attempts to find a valid connection have been made, after which an error is returned to the application

Applications should continue to do appropriate error checking when using connections in case they have become invalid in the time since getConnection() was called. This error checking will also protect against cases where there was a network outage but a connection was idle in the pool for less than poolPingInterval seconds and so getConnection() did not ping.

In all cases, when a bad connection is released back to the pool, the connection is automatically destroyed. This allows a valid connection to be opened by some subsequent getConnection() call.

You can tune poolPingInterval to meet your quality of service requirements.

Explicit pings on any connection can be performed at any time with connection.ping().

8.3.5 Heterogeneous Connection Pools and Pool Proxy Authentication

By default, connection pools are 'homogeneous' meaning that all connections use the same database credentials. However, if the pool option homogeneous is false at pool creation, then a 'heterogeneous' pool will be created. This allows different credentials to be used each time a connection is acquired from the pool with pool.getConnection().

Heterogeneous Pools

When a heterogeneous pool is created by setting homogeneous to false and no credentials supplied during pool creation, then a user name and password may be passed to pool.getConnection():

oracledb.createPool(
  {
    connectString : "localhost/XE",  // no user name or password
    homogeneous   : false,
    . . .  // other pool options such as poolMax can be used
  },
  function(err, pool) {
    pool.getConnection(
      {
        user     : 'hr',
        password : 'welcome'
      },
      function (err, conn) {

      . . . // use connection

        conn.close(
          function(err) {
            if (err) { console.error(err.message); }
          });
      });
  });

The connectString is required during pool creation since the pool is created for one database instance.

Different user names may be used each time pool.getConnection() is called.

When applications want to use connection pools but are not able to use connection.clientId to distinguish application users from database schema owners, a 'heterogeneous' connection pool might be an option.

Note heterogeneous pools cannot be used with the connection pool cache. Applications should ensure the pool object is explicitly passed between code modules, or use a homogeneous pool and make use of connection.clientId.

For heterogeneous pools, the number of connections initially created is zero even if a larger value is specified for poolMin. The pool increment is always 1, regardless of the value of poolIncrement. Once the number of open connections exceeds poolMin and connections are idle for more than the poolTimeout seconds, then the number of open connections does not fall below poolMin.

Pool Proxy Authentication

Pool proxy authentication requires a heterogeneous pool.

The idea of a proxy is to create a schema in one database user name. Privilege is granted on that schema to other database users so they can access the schema and manipulate its data. This aids three-tier applications where one user owns the schema while multiple end-users access the data.

To grant access, typically a DBA would execute:

ALTER USER sessionuser GRANT CONNECT THROUGH proxyuser;

For example, to allow a user called MYPROXYUSER to access the schema of HR:

SQL> CONNECT system/welcome

SQL> ALTER USER hr GRANT CONNECT THROUGH myproxyuser;

SQL> CONNECT myproxyuser[hr]/myproxyuserpassword

SQL> SELECT SYS_CONTEXT('USERENV', 'SESSION_USER') AS SESSION_USER,
  2         SYS_CONTEXT('USERENV', 'PROXY_USER')   AS PROXY_USER
  3  FROM DUAL;

SESSION_USER         PROXY_USER
-------------------- --------------------
HR                   MYPROXYUSER

See the Client Access Through a Proxy section in the Oracle Call Interface manual for more details about proxy authentication.

To use the proxy user with a node-oracledb heterogeneous connection pool you could do:

oracledb.createPool(
  {
    connectString : "localhost/XE",  // no user name or password
    homogeneous   : false,
    . . .  // other pool options such as poolMax can be used
  },
  function(err, pool) {
    pool.getConnection(
      {
        user     : 'myproxyuser[hr]',
        password : 'myproxyuserpassword'
      },
      function (err, conn) {

        . . . // connection has access to the HR schema objects

        conn.close(
          function(err) {
            if (err) { console.error(err.message); }
          });
      });
  });

Other proxy cases are supported such as:

oracledb.createPool(
  {
    user          : 'myproxyuser',
    password      : 'myproxyuserpassword'
    connectString : "localhost/XE",
    homogeneous   : false,
    . . .  // other pool options such as poolMax can be used
  },
  function(err, pool) {
    pool.getConnection(
      {
        user : 'hr'  // the session user
      },
      function (err, conn) {

        . . . // connection has access to the HR schema objects

        conn.close(
          function(err) {
            if (err) { console.error(err.message); }
          });
      });
  });

8.4 Database Resident Connection Pooling (DRCP)

Database Resident Connection Pooling (DRCP) enables database resource sharing for applications that run in multiple client processes or run on multiple middle-tier application servers. DRCP reduces the overall number of connections that a database must handle.

DRCP is useful for applications which share the same database credentials, have similar session settings (for example date format settings and PL/SQL package state), and where the application gets a database connection, works on it for a relatively short duration, and then releases it.

To use DRCP in node-oracledb:

  1. The DRCP pool must be started in the database: SQL> execute dbms_connection_pool.start_pool();
  2. The connectionClass should be set by the node-oracledb application. If it is not set, the pooled server session memory will not be reused optimally, and the statistic views will record large values for NUM_MISSES.
  3. The pool.createPool() or oracledb.getConnection() property connectString (or its alias connectionString) must specify to use a pooled server, either by the Easy Connect syntax like myhost/sales:POOLED, or by using a tnsnames.ora alias for a connection that contains (SERVER=POOLED).

For efficiency, it is recommended that DRCP connections should be used with node-oracledb's local connection pool.

The DRCP 'Purity' is SELF for DRCP connections. This allows reuse of both the pooled server process and session memory, giving maximum benefit from DRCP. See the Oracle documentation on benefiting from scalability.

The Oracle DRCP documentation has more details, including when to use, and when not to use DRCP.

There are a number of Oracle Database V$ views that can be used to monitor DRCP. These are discussed in the Oracle documentation and in the Oracle white paper PHP Scalability and High Availability. This paper also gives more detail on configuring DRCP.

8.5 External Authentication

External Authentication allows applications to use an external password store (such as Oracle Wallet), the Secure Socket Layer (SSL), or the operating system to validate user access. One of the benefits is that database credentials do not need to be hard coded in the application.

To use external authentication, set the oracledb.externalAuth property to true. This property can also be set in the connAttrs or poolAttrs parameters of the oracledb.getConnection() or oracledb.createPool() calls, respectively. The user and password properties should not be set, or should be empty strings:

var oracledb = require('oracledb');

oracledb.getConnection(
  {
    externalAuth: true,
    connectString: "localhost/orclpdb"
  },
  . . .

When externalAuth is set, any subsequent connections obtained using the oracledb.getConnection() or pool.getConnection() calls will use external authentication. Setting this property does not affect the operation of existing connections or pools.

Using externalAuth in the connAttrs parameter of a pool.getConnection() call is not possible. The connections from a Pool object are always obtained in the manner in which the pool was initially created.

For pools created with external authentication, the number of connections initially created is zero even if a larger value is specified for poolMin. The pool increment is always 1, regardless of the value of poolIncrement. Once the number of open connections exceeds poolMin and connections are idle for more than the poolTimeout seconds, then the number of open connections does not fall below poolMin.

8.6 Privileged Connections

Database privileges such as SYSDBA can be obtained when using standalone connections. Use one of the Privileged Connection Constants with the connection privilege property, for example:

oracledb.getConnection(
  {
    user          : 'sys',
    password      : 'secret',
    connectString : 'localhost/orclpdb',
    privilege     : oracledb.SYSDBA
  },
  function(err, connection) {
    if (err)
      console.error(err);
    else
      console.log('I have power');
  }
);

Note that if node-oracledb is using the Oracle client libraries located in the Oracle Database installation, i.e. is on the same machine as the database and is not using Oracle Instant Client, then operating system privileges may be used for authentication. In this case the password value is ignored. For example on Linux, membership of the operating system dba group allows SYSDBA connections.

Administrative privileges can allow access to a database instance even when the database is not open. Control of these privileges is totally outside of the database itself. Care must be taken with authentication to ensure security. See the Database Administrators Guide for information.

8.7 Securely Encrypting Network Traffic to Oracle Database

Data transferred between Oracle Database and the Oracle client libraries used by node-oracledb can be encrypted so that unauthorized parties are not able to view plain text data as it passes over the network. The easiest configuration is Oracle's native network encryption. The standard SSL protocol can also be used if you have a PKI, but setup is necessarily more involved.

With native network encryption, the client and database server negotiate a key using Diffie-Hellman key exchange. There is protection against man-in-the-middle attacks.

Native network encryption can be configured by editing Oracle Net's optional sqlnet.ora configuration files, on either the database server and/or on each node-oracledb 'client'. Parameters control whether data integrity checking and encryption is required or just allowed, and which algorithms the client and server should consider for use.

As an example, to ensure all connections to the database are checked for integrity and are also encrypted, create or edit the Oracle Database $ORACLE_HOME/network/admin/sqlnet.ora file. Set the checksum negotiation to always validate a checksum and set the checksum type to your desired value. The network encryption settings can similarly be set. For example, to use the SHA512 checksum and AES256 encryption use:

SQLNET.CRYPTO_CHECKSUM_SERVER = required
SQLNET.CRYPTO_CHECKSUM_TYPES_SERVER = (SHA512)
SQLNET.ENCRYPTION_SERVER = required
SQLNET.ENCRYPTION_TYPES_SERVER = (AES256)

If you definitely know that the database server enforces integrity and encryption, then you do not need to configure Node.js separately. However you can also, or alternatively, do so depending on your business needs. Create a sqlnet.ora and locate it with other Optional Client Configuration Files:

SQLNET.CRYPTO_CHECKSUM_CLIENT = required
SQLNET.CRYPTO_CHECKSUM_TYPES_CLIENT = (SHA512)
SQLNET.ENCRYPTION_CLIENT = required
SQLNET.ENCRYPTION_TYPES_CLIENT = (AES256)

The client and server sides can negotiate the protocols used if the settings indicate more than one value is accepted.

Note these are example settings only. You must review your security requirements and read the documentation for your Oracle version. In particular review the available algorithms for security and performance.

The NETWORK_SERVICE_BANNER column of the database view V$SESSION_CONNECT_INFO can be used to verify the encryption status of a connection.

For more information about Oracle Data Network Encryption and Integrity, and for information about configuring SSL network encryption, refer to the Oracle Database Security Guide. This manual also contains information about other important security features that Oracle Database provides, such Transparent Data Encryption of data-at-rest in the database.

8.8 Changing Passwords and Connecting with an Expired Password

Changing Passwords

Database passwords can be changed with connection.changePassword(). For example, the HR user can change their password from 'welcome' to 'steamboat':

oracledb.getConnection(
  {
    user          : "hr",
    password      : "welcome",
    connectString : "localhost/orclpdb"
  },
  function(err, connection) {
    if (err) { console.error(err.message); return; }

    connection.changePassword(
        'hr', 'welcome', 'steamboat',
        function(err) {
        . . .
        });
    . . .

Only DBAs, or users with the ALTER USER privilege, can change the password of another user. In this case, the old password value is ignored and can be an empty string:

oracledb.getConnection(
  {
    user          : "system",   // a privileged user
    password      : "secret",
    connectString : "localhost/orclpdb"
  },
  function(err, connection) {
    if (err) { console.error(err.message); return; }

    connection.changePassword(
        'hr', '', 'steamboat',  // change HR's password to 'steamboat'
        function(err) {
        . . .
        });
    . . .

Connecting with an Expired Password

When creating a standalone, non-pooled connection the user's password can be changed at time of connection. This is most useful when the user's password has expired, because it allows a user to connect without requiring a DBA to reset their password.

Both the current and new passwords must be given when connecting. For example, if HR's password is 'welcome', it can be changed to 'steamboat' like:

oracledb.getConnection(
  {
    user          : "hr",
    password      : "welcome",
    newPassword   : "steamboat",
    connectString : "localhost/orclpdb"
  },
  function(err, connection) {
    if (err) { console.error(err.message); return; }
  . . .

8.9 Connections and High Availability

For applications that need to be highly available, you may want to configure your OS network settings and Oracle Net (which handles communication between node-oracledb and the database).

For Oracle Net configuration, create a sqlnet.ora file. See Optional Client Configuration Files for where to place this. In this file you can configure settings like SQLNET.OUTBOUND_CONNECT_TIMEOUT, SQLNET.RECV_TIMEOUT and SQLNET.SEND_TIMEOUT. You may also want to use a tnsnames.ora file to configure the database service setting ENABLE=BROKEN.

Other Oracle Network Services options may also be useful for high availability and performance tuning.

8.9.1 Fast Application Notification (FAN)

Users of Oracle Database FAN should set oracledb.events to true. This can also be enabled via External Configuration.

FAN support gives fast connection failover, an Oracle Database high availability feature. This allows applications to be notified when a database machine becomes unavailable. Without FAN, node-oracledb can hang until a TCP timeout occurs and an error is returned, which might be several minutes. Enabling FAN in node-oracledb can allow applications to detect errors, re-connect to an available database instance, and replay application logic without the application user being aware of an outage. It is up to the application to handle errors and take desired action.

FAN benefits users of Oracle Database's clustering technology (Oracle RAC) because connections to surviving database instances can be immediately made. Users of Oracle's Data Guard with a broker will see the FAN events generated when the standby database goes online. Standalone databases will send FAN events when the database restarts.

For active connections, when a machine or database instance becomes unavailable, a connection failure error will be returned by the node-oracledb method currently being called. On a subsequent re-connect, a connection to a surviving database instance will be established. Node-oracledb also transparently cleans up any idle connections affected by a database machine or instance failure so future connect calls will establish a fresh connection without the application being aware of any service disruption.

For a more information on FAN see the whitepaper on Fast Application Notification.

8.9.2 Runtime Load Balancing (RLB)

Oracle Database RAC users with Oracle Database (RLB) advisory events configured should use node-oracledb Connection Pooling and set oracledb.events to true. The events mode can also be enabled via External Configuration.

RLB allows optimal use of database resources by balancing database requests across RAC instances.

For a more information on RLB, see the whitepaper on Fast Application Notification.

8.10 Optional Client Configuration Files

Optional Oracle Client configuration files are read when node-oracledb is loaded. These files affect connections and applications. Common files include tnsnames.ora, sqlnet.ora, ldap.ora, and oraaccess.xml.

Default locations for these files include:

  • /opt/oracle/instantclient_12_2/network/admin if Instant Client is in /opt/oracle/instantclient_12_2.
  • /usr/lib/oracle/12.2/client64/lib/network/admin if Oracle 12.2 Instant Client RPMs are used on Linux.
  • $ORACLE_HOME/network/admin if node-oracledb is using libraries from the database installation.

Alternatively, Oracle Client configuration files can be put in another, accessible directory. Then set the environment variable TNS_ADMIN to that directory name. For example, if the file /etc/my-oracle-config/tnsnames.ora is being used, set TNS_ADMIN to /etc/my-oracle-config.

9. SQL Execution

A single SQL or PL/SQL statement may be executed using the Connection execute() method. The callback style shown below, or promises, or Async/Await may be used.

Results may be returned in a single array, or fetched in batches with a ResultSet. Queries may optionally be streamed using the connection.queryStream() method.

Node-oracledb's execute() and queryStream() methods use Statement Caching to make re-execution of statements efficient. This removes the need for a separate 'prepare' method to parse statements.

For queries that return a large number of rows, the network traffic for fetching data from Oracle Database can be optimized by increasing oracledb.fetchArraySize. For queries that are known to return a small set of rows, reduce fetchArraySize to avoid unnecessary memory allocation. The execute() option fetchArraySize can be used to override the global property for individual queries.

Connections can handle one database operation at a time. Other database operations will block. Structure your code to avoid starting parallel operations on a connection. For example, instead of using async.parallel or async.each() which calls each of its items in parallel, use async.series or async.eachSeries(). Also see Connections and Number of Threads.

After all database calls on the connection complete, the application should use the connection.close() call to release the connection.

9.1 SELECT Statements

9.1.1 Fetching Rows with Direct Fetches

By default, queries are handled as 'direct fetches', meaning all results are returned in the callback result.rows property:

    connection.execute(
      `SELECT department_id, department_name
       FROM departments
       WHERE department_id = :did`,
      [180],
      { maxRows: 10 },  // a maximum of 10 rows will be returned
      function(err, result) {
        if (err) { console.error(err.message); return; }
        console.log(result.rows);  // print all returned rows
      });

Any rows beyond the maxRows limit are not returned. If maxRows is 0, then the number of rows is only limited by Node.js memory.

To improve database efficiency, SQL queries should use a row limiting clause like OFFSET / FETCH or equivalent. The maxRows property can be used to stop badly coded queries from returning unexpectedly large numbers of rows.

Internally, rows are fetched from Oracle Database in batches. The internal batch size is based on the lesser of fetchArraySize and maxRows. Each batch is concatenated into the array returned to the application.

For queries expected to return a small number of rows, reduce maxRows or fetchArraySize to reduce internal memory overhead by node-oracledb.

For direct fetches, JavaScript memory can become a limitation in two cases:

  • the absolute amount of data returned is simply too large for JavaScript to hold in a single array.

  • the JavaScript heap can be exceeded, or become fragmented, due to concatenation of the buffers of records fetched from the database. To minimize this, use a fetchArraySize value determined by tuning.

In both cases, use a ResultSet or Query Stream instead of a direct fetch.

9.1.2 Working with Result Sets

When the number of query rows is relatively big, or can't be predicted, it is recommended to use a ResultSet with callbacks, as described in this section, or via query streaming, as described later. This prevents query results being unexpectedly truncated by the maxRows limit, or exceeding Node.js memory constraints. Otherwise, for queries that return a known small number of rows, non-ResultSet queries may have less overhead.

A ResultSet is created when the execute() option property resultSet is true. ResultSet rows can be fetched using getRow() or getRows() on the execute() callback function's result.resultSet property.

For ResultSets, the maxRows limit is ignored. All rows can be fetched.

When all rows have been fetched, or the application does not want to continue getting more rows, then the ResultSet should be freed using close(). The ResultSet should also be explicitly closed in the cases where no rows will be fetched from it.

REF CURSORS returned from a PL/SQL block via an oracledb.CURSOR OUT binds are also available as a ResultSet. See REF CURSOR Bind Parameters.

The format of each row will be an array or object, depending on the value of outFormat.

See resultset1.js, resultset2.js and refcursor.js for full examples.

To fetch one row at a time use getRow() :

connection.execute(
  "SELECT employee_id, last_name FROM employees ORDER BY employee_id",
  [], // no bind variables
  { resultSet: true }, // return a Result Set.  Default is false
  function(err, result) {
    if (err) { . . . }
    fetchOneRowFromRS(connection, result.resultSet);
  });
});

function fetchOneRowFromRS(connection, resultSet) {
  resultSet.getRow( // get one row
    function (err, row) {
      if (err) {
         . . .           // close the Result Set and release the connection
      } else if (!row) { // no rows, or no more rows
        . . .            // close the Result Set and release the connection
      } else {
        console.log(row);
        fetchOneRowFromRS(connection, resultSet);  // get next row
      }
    });
}

To fetch multiple rows at a time, use getRows():

var numRows = 10;  // number of rows to return from each call to getRows()

connection.execute(
  "SELECT employee_id, last_name FROM employees ORDER BY employee_id",
  [], // no bind variables
  { resultSet: true }, // return a ResultSet.  Default is false
  function(err, result) {
    if (err) { . . . }
    fetchRowsFromRS(connection, result.resultSet, numRows);
  });
});

function fetchRowsFromRS(connection, resultSet, numRows) {
  resultSet.getRows( // get numRows rows
    numRows,
    function (err, rows) {
      if (err) {
         . . .                        // close the ResultSet and release the connection
      } else if (rows.length > 0) {   // got some rows
        console.log(rows);            // process rows
        if (rows.length === numRows)  // might be more rows
          fetchRowsFromRS(connection, resultSet, numRows);
        else                          // got fewer rows than requested so must be at end
          . . .                       // close the ResultSet and release the connection
      } else {                        // else no rows
          . . .                       // close the ResultSet and release the connection
      }
    });
}

9.1.3 Query Streaming

Streaming of query results allows data to be piped to other streams, for example when dealing with HTTP responses.

Use connection.queryStream() to create a stream from a top level query and listen for events. You can also call connection.execute() and use toQueryStream() to return a stream from the returned ResultSet or OUT bind REF CURSOR ResultSet.

With streaming, each row is returned as a data event. Query metadata is available via a metadata event. The end event indicates the end of the query results.

Query results should be fetched to completion to avoid resource leaks, or (from Node.js 8 onwards) the Stream destroy() method can be used to terminate a stream early. For older Node.js versions use a ResultSet with callbacks if you need to stop a query before retrieving all data. Note the previous, experimental _close() method no longer emits a 'close' event.

The connection must remain open until the stream is completely read and any returned Lob objects have been processed.

The query stream implementation is a wrapper over the ResultSet Class. In particular, successive calls to getRow() are made internally. Each row will generate a data event. For tuning, adjust the value of oracledb.fetchArraySize or the execute() option fetchArraySize.

An example of streaming query results is:

var stream = connection.queryStream('SELECT employees_name FROM employees');

stream.on('error', function (error) {
  // handle any error...
});

stream.on('data', function (data) {
  // handle data row...
});

stream.on('end', function () {
  // release connection...
});

stream.on('metadata', function (metadata) {
  // access metadata of query
});

// listen to any other standard stream events...

See selectstream.js for a runnable example using connection.queryStream().

The REF CURSOR Bind Parameters section shows using toQueryStream() to return a stream for a REF CURSOR.

9.1.4 Query Output Formats

Query rows may be returned as an array of column values, or as JavaScript objects, depending on the values of outFormat.

The default format for each row is an array of column values. For example:

var oracledb = require('oracledb');
. . .

connection.execute(
  `SELECT department_id, department_name
   FROM departments
   WHERE manager_id < :id`,
  [110],  // bind value for :id
  function(err, result) {
    if (err) { console.error(err.message); return; }
    console.log(result.rows);
  });

If run with Oracle's sample HR schema, the output is:

[ [ 60, 'IT' ], [ 90, 'Executive' ], [ 100, 'Finance' ] ]

Using this format is recommended for efficiency.

Alternatively, rows may be fetched as JavaScript objects. To do so, specify the outFormat option to be oracledb.OBJECT:

oracledb.outFormat = oracledb.OBJECT;

The value can also be set as an execute() option:

connection.execute(
  `SELECT department_id, department_name
   FROM departments
   WHERE manager_id < :id`,
  [110],  // bind value for :id
  { outFormat: oracledb.OBJECT },
  function(err, result) {
    if (err) { console.error(err.message); return; }
    console.log(result.rows);
  });

The output is:

[ { DEPARTMENT_ID: 60, DEPARTMENT_NAME: 'IT' },
  { DEPARTMENT_ID: 90, DEPARTMENT_NAME: 'Executive' },
  { DEPARTMENT_ID: 100, DEPARTMENT_NAME: 'Finance' } ]

In the preceding example, each row is a JavaScript object that specifies column names and their respective values. Note the property names follow Oracle's standard name-casing rules. They will commonly be uppercase, since most applications create tables using unquoted, case-insensitive names.

9.1.5 Query Column Metadata

The column names of a query are returned in the execute() callback's result.metaData attribute:

connection.execute(
  `SELECT department_id, department_name
   FROM departments
   WHERE manager_id < :id`,
  [110],  // bind value for :id
  function(err, result) {
    if (err) { console.error(err.message); return; }
    console.log(result.metaData);  // show the metadata
  });

When using a ResultSet, metadata is also available in result.resultSet.metaData. For queries using queryStream(), metadata is available via the metadata event.

The metadata is an array of objects, one per column. By default each object has a name attribute:

[ { name: 'DEPARTMENT_ID' }, { name: 'DEPARTMENT_NAME' } ]

The names are in uppercase. This is the default casing behavior for Oracle client programs when a database table is created with unquoted, case-insensitive column names.

Extended Metadata

More metadata is included when the oracledb.extendedMetaData or connection.execute() option extendedMetaData is true. For example:

connection.execute(
  "SELECT department_id, department_name " +
    "FROM departments " +
    "WHERE manager_id < :id",
  [110],  // bind value for :id
  { extendedMetaData: true },
  function(err, result) {
    if (err) { console.error(err.message); return; }
    console.log(result.metaData);  // show the extended metadata
  });

The output is:

[ { name: 'DEPARTMENT_ID',
    fetchType: 2002,
    dbType: 2,
    precision: 4,
    scale: 0,
    nullable: false },
  { name: 'DEPARTMENT_NAME',
    fetchType: 2001,
    dbType: 1,
    byteSize: 30,
    nullable: false } ]

Description of the properties is given in the result.metaData description.

9.1.6 Query Result Type Mapping

Supported Oracle number, date, character, ROWID, UROWID, LONG and LONG RAW column types are selected as Numbers, Dates, Strings, or Buffers. BLOBs and CLOBs are selected into Lobs.

The default mapping for some types can be changed using fetchAsBuffer, or fetchAsString. The fetchInfo property can also be used to change the default mapping, or override a global mapping, for individual columns.

Data types in SELECT statements that are unsupported give an error NJS-010: unsupported data type in select list. These include INTERVAL, BFILE and XMLType types.

Details are in the following sections.

9.1.6.1 Fetching CHAR, VARCHAR2, NCHAR and NVARCHAR

Columns of database type CHAR, VARCHAR2, NCHAR and NVARCHAR are returned from queries as JavaScript strings.

Note that binding NCHAR and NVARCHAR for DML is not supported and may cause unexpected character set translation, see Bind Data Type Notes.

9.1.6.2 Fetching Numbers

By default all numeric columns are mapped to JavaScript numbers. Node.js uses double floating point numbers as its native number type.

When numbers are fetched from the database, conversion to JavaScript's less precise binary number format can result in "unexpected" representations. For example:

conn.execute(
"select 38.73 from dual",
function (err, result) {
  if (err)
    . . .
  else
    console.log(result.rows[0]); // gives 38.730000000000004
});

Similar issues can occur with binary floating-point arithmetic purely in Node.js, for example:

console.log(0.2 + 0.7); // gives 0.8999999999999999

Node.js can also only represent numbers up to 2 ^ 53 which is 9007199254740992. Numbers larger than this will be truncated.

The primary recommendation for number handling is to use Oracle SQL or PL/SQL for mathematical operations, particularly for currency calculations.

To reliably work with numbers in Node.js, use fetchAsString or fetchInfo (see below) to fetch numbers in string format, and then use one of the available third-party JavaScript number libraries that handles large values and more precision.

9.1.6.3 Fetching Dates and Timestamps

By default, date and timestamp columns are mapped to JavaScript Date objects. Internally, DATE, TIMESTAMP, TIMESTAMP WITH LOCAL TIME ZONE, and TIMESTAMP WITH TIME ZONE columns are fetched as TIMESTAMP WITH LOCAL TIME ZONE using the session time zone. Oracle INTERVAL types are not supported.

Note that JavaScript Date has millisecond precision therefore timestamps will lose any sub-millisecond fractional part when fetched.

To make applications more portable, it is recommended to always set the session time zone to a pre-determined value, such as UTC. This can be done by setting the environment variable ORA_SDTZ before starting Node.js, for example:

$ export ORA_SDTZ='UTC'
$ node myapp.js

The session time zone can also be changed at runtime for each connection by executing:

connection.execute(
  "ALTER SESSION SET TIME_ZONE='UTC'",
  function(err) { ... }
);

To do this without requiring the overhead of a round-trip to execute the ALTER statement, you could use a PL/SQL trigger:

CREATE OR REPLACE TRIGGER my_logon_trigger
  AFTER LOGON
  ON hr.SCHEMA
BEGIN
  EXECUTE IMMEDIATE 'ALTER SESSION SET TIME_ZONE=''UTC''';
END;

See Working with Dates Using the Node.js Driver for more discussion of date handling.

9.1.6.4 Fetching Numbers and Dates as String

The global fetchAsString property can be used to force all number or date columns (and CLOB columns) queried by an application to be fetched as strings instead of in native format. Allowing data to be fetched as strings helps avoid situations where using JavaScript types can lead to numeric precision loss, or where date conversion is unwanted.

For example, to force all dates and numbers used by queries in an application to be fetched as strings:

var oracledb = require('oracledb');
oracledb.fetchAsString = [ oracledb.DATE, oracledb.NUMBER ];

For dates and numbers, the maximum length of a string created can be 200 bytes.

Individual queries can use the execute() option fetchInfo to map individual number or date columns to strings without affecting other columns or other queries. Any global fetchAsString setting can be overridden to allow specific columns to have data returned in native format:

var oracledb = require('oracledb');

oracledb.fetchAsString = [ oracledb.NUMBER ];  // any number queried will be returned as a string

oracledb.getConnection(
  {
    user          : "hr",
    password      : "welcome",
    connectString : "localhost/XE"
  },
  function(err, connection) {
    if (err) { console.error(err.message); return; }
    connection.execute(
      "SELECT last_name, hire_date, salary, commission_pct FROM employees WHERE employee_id = :id",
      [178],
      {
        fetchInfo :
        {
          "HIRE_DATE":      { type : oracledb.STRING },  // return the date as a string
          "COMMISSION_PCT": { type : oracledb.DEFAULT }  // override oracledb.fetchAsString and fetch as native type
        }
      },
      function(err, result) {
        if (err) { console.error(err.message); return; }
        console.log(result.rows);
      });
  });

The output is:

[ [ 'Grant', '24-MAY-07', '7000', 0.15 ] ]

The date and salary columns are returned as strings, but the commission is a number. The date is mapped using the current session date format, which was DD-MON-YY in this example. The default date format can be set, for example, with the environment variable NLS_DATE_FORMAT. Note this variable will only be read if NLS_LANG is also set.

Without the mapping capabilities provided by fetchAsString and fetchInfo the hire date would have been a JavaScript date in the local time zone, and both numeric columns would have been represented as numbers:

[ [ 'Grant', Thu May 24 2007 00:00:00 GMT+1000 (AEST), 7000, 0.15 ] ]

To map columns returned from REF CURSORS, use fetchAsString. The fetchInfo settings do not apply.

When using fetchAsString or fetchInfo for numbers, you may need to explicitly use NLS_NUMERIC_CHARACTERS to override your NLS settings and force the decimal separator to be a period. This can be done for each connection by executing the statement:

connection.execute(
  "ALTER SESSION SET NLS_NUMERIC_CHARACTERS = '.,'",
  function(err) { ... }
);

Alternatively you can set the equivalent environment variable prior to starting Node.js:

$ export NLS_NUMERIC_CHARACTERS='.,'

Note this environment variable is not used unless the NLS_LANG environment variable is also set.

9.1.6.5 Fetching BLOB, CLOB and NCLOB

By default BLOB, CLOB and NCLOB columns are fetched into Lob instances. For small LOBs it can be more convenient to fetch them directly into Buffers or Strings by using the global fetchAsBuffer or fetchAsString settings, or the per-column fetchInfo setting. See the section Working with CLOB and BLOB Data.

Note that binding NCLOB for DML is not supported and may cause unexpected character set translation, see Bind Data Type Notes.

9.1.6.6 Fetching LONG and LONG RAW

LONG columns in queries will be fetched as Strings. LONG RAW columns will be fetched as Buffers.

Unlike for LOBs, there is no support for streaming LONG types. Oracle Database allows values 2 GB in length, but Node.js and V8 memory limitations typically only allow memory chunks in the order of tens of megabytes. This means complete data may not be able to fetched from the database. The SQL function TO_LOB can be used to migrate data to LOB columns which can be streamed to node-oracledb, however TO_LOB cannot be used directly in a SELECT.

9.1.6.7 Fetching ROWID and UROWID

Queries will return ROWID and UROWID columns as Strings.

9.1.6.8 Fetching XMLType

XMLType columns cannot be queried directly. Instead handle them as CLOBs, see Working with XMLType.

9.1.6.9 Fetching RAW

Queries will return RAW columns as Node.js Buffers.

9.1.6.10 Mapping Custom Types

Data types such as an Oracle Locator SDO_GEOMETRY, or your own custom types, cannot be fetched directly in node-oracledb. Instead, utilize techniques such as using an intermediary PL/SQL procedure to map the type components to scalar values, or use a pipelined table.

For example, consider a CUSTOMERS table having a CUST_GEO_LOCATION column of type SDO_GEOMETRY, as created in this example schema:

CREATE TABLE customers (
  customer_id NUMBER,
  last_name VARCHAR2(30),
  cust_geo_location SDO_GEOMETRY);

INSERT INTO customers VALUES
  (1001, 'Nichols', SDO_GEOMETRY(2001, 8307, SDO_POINT_TYPE (-71.48923,42.72347,NULL), NULL, NULL));

COMMIT;

Instead of attempting to get CUST_GEO_LOCATION by directly calling a PL/SQL procedure that returns an SDO_GEOMETRY parameter, you could instead get the scalar coordinates by using an intermediary PL/SQL block that decomposes the geometry:

    . . .
    var sql =
      "BEGIN " +
      "  SELECT t.x, t.y" +
      "  INTO :x, :y" +
      "  FROM customers, TABLE(sdo_util.getvertices(customers.cust_geo_location)) t" +
      "  WHERE customer_id = :id;" +
      "END; ";
    var bindvars = {
      id: 1001,
      x: { type: oracledb.NUMBER, dir : oracledb.BIND_OUT },
      y: { type: oracledb.NUMBER, dir : oracledb.BIND_OUT }
    }
    connection.execute(
      sql,
      bindvars,
      function (err, result) {
        if (err) { console.error(err.message); return; }
        console.log(result.outBinds);
      });

The output is:

{ x: -71.48922999999999, y: 42.72347 }

Note the JavaScript precision difference. In this particular example, you may want to bind using type: oracledb.STRING. Output would be:

{ x: '-71.48923', y: '42.72347' }

9.1.7 Limiting Rows and Creating Paged Datasets

Query data is commonly broken into small sets for two reasons:

  • 'Web pagination' that allows moving from one set of rows to a next, or previous, set.

  • Fetching of consectitive small sets of data for processing. This happens because the number of records is too large for Node.js to handle at the same time.

The latter can be handled by ResultSets or queryStream() with one execution of the SQL query as discsussed in those links.

How to do 'web pagination' is discussed in this section. For each 'page' of results, a SQL query is executed to get the appropriate set of rows from a table. Since the query will be executed more than once, make sure to use bind variables for row numbers and row limits.

Oracle Database 12c SQL has an OFFSET / FETCH clause, which is similar to the LIMIT keyword of MySQL.

var myoffset = 0;       // don't skip any rows (start at row 1)
var mymaxnumrows = 20;  // get 20 rows

connection.execute(
  `SELECT last_name
   FROM employees
   ORDER BY last_name
   OFFSET :offset ROWS FETCH NEXT :maxnumrows ROWS ONLY`,
  {offset: myoffset, maxnumrows: mymaxnumrows},
. . .

See rowlimit.js.

You can use a basic execute() or a ResultSet, or queryStream() with your query. For basic execute() fetches, make sure that oracledb.maxRows is greater than the value bound to :maxnumrows, or set to 0 (meaning unlimited).

In applications where the SQL query is not known in advance, this method sometimes involves appending the OFFSET clause to the 'real' user query. Be very careful to avoid SQL injection security issues.

As an anti-example, another way to limit the number of rows returned involves setting maxRows. However it is more efficient to let Oracle Database do the row selection in the SQL query and only return the exact number of rows required to node-oracledb.

For Oracle Database 11g and earlier there are several alternative ways to limit the number of rows returned. Refer to Oracle Magazine for details.

The old, canonical paging query is:

SELECT *
FROM (SELECT a.*, ROWNUM AS rnum
      FROM (YOUR_QUERY_GOES_HERE -- including the order by) a
      WHERE ROWNUM <= MAX_ROW)
WHERE rnum >= MIN_ROW

Here, MIN_ROW is the row number of first row and MAX_ROW is the row number of the last row to return. For example:

SELECT *
FROM (SELECT a.*, ROWNUM AS rnum
      FROM (SELECT last_name FROM employees ORDER BY last_name) a
      WHERE ROWNUM <= 20)
WHERE rnum >= 1

This always has an 'extra' column, here called RNUM.

An alternative and preferred query syntax for Oracle Database 11g uses the analytic ROW_NUMBER() function. For example to get the 1st to 20th names the query is:

SELECT last_name FROM
(SELECT last_name,
        ROW_NUMBER() OVER (ORDER BY last_name) AS myr
        FROM employees)
WHERE myr BETWEEN 1 and 20

9.1.8 Auto-Increment Columns

In Oracle Database 12c you can create tables with auto-incremented values. This is useful to generate unique primary keys for your data when ROWID or UROWID are not preferred.

In SQL*Plus execute:

CREATE TABLE mytable
  (myid NUMBER(11) GENERATED BY DEFAULT ON NULL AS IDENTITY (START WITH 1),
   mydata VARCHAR2(20)
  )

Refer to the CREATE TABLE identity column documentation.

If you already have a sequence myseq you can use values from it to auto-increment a column value like this:

CREATE TABLE mytable
  (myid NUMBER DEFAULT myseq.NEXTVAL,
   mydata VARCHAR2(20)
  )

This also requires Oracle Database 12c.

Prior to Oracle Database 12c, auto-increment columns in Oracle Database can be created using a sequence generator and a trigger.

Sequence generators are defined in the database and return Oracle numbers. Sequence numbers are generated independently of tables. Therefore, the same sequence generator can be used for more than one table or anywhere that you want to use a unique number. You can get a new value from a sequence generator using the NEXTVAL operator in a SQL statement. This gives the next available number and increments the generator. The similar CURRVAL operator returns the current value of a sequence without incrementing the generator.

A trigger is a PL/SQL procedure that is automatically invoked at a predetermined point. In this example a trigger is invoked whenever an insert is made to a table.

In SQL*Plus run:

CREATE SEQUENCE myseq;
CREATE TABLE mytable (myid NUMBER PRIMARY KEY, mydata VARCHAR2(20));
CREATE TRIGGER mytrigger BEFORE INSERT ON mytable FOR EACH ROW
BEGIN
  :new.myid := myseq.NEXTVAL;
END;
/

Prior to Oracle Database 11g replace the trigger assignment with a SELECT like:

SELECT myseq.NEXTVAL INTO :new.myid FROM dual;
Getting the Last Insert ID

To get the automatically inserted identifier in node-oracledb, use a DML RETURNING clause:

. . .
connection.execute(
  "INSERT INTO mytable (mydata) VALUES ('Hello') RETURN myid INTO :id",
  {id : {type: oracledb.NUMBER, dir: oracledb.BIND_OUT } },
  function (err, result) {
    if (err) { console.error(err.message); return; }
    console.log(result.outBinds.id);  // print the ID of the inserted row
  });

9.2 Cursor Management

Developers starting out with Node have to get to grips with the 'different' programming style of JavaScript that seems to cause methods to be called when least expected! While you are still in the initial hacking-around-with-node-oracledb phase you may sometimes encounter the error ORA-01000: maximum open cursors exceeded. A cursor is a "handle for the session-specific private SQL area that holds a parsed SQL statement and other processing information".

Here are things to do when you see an ORA-1000:

  • Avoid having too many incompletely processed statements open at one time:

    • Make sure your application is handling connections and statements in the order you expect.

    • Close ResultSets before releasing the connection.

    • If cursors are opened with DBMS_SQL.OPEN_CURSOR() in a PL/SQL block, close them before the block returns - except for REF CURSORs being passed back to node-oracledb.

  • Choose the appropriate Statement Cache size. Node-oracledb has a statement cache per connection. When node-oracledb internally releases a statement it will be put into the statement cache of that connection, and its cursor will remain open. This makes statement re-execution very efficient.

    The cache size is settable with the oracle.stmtCacheSize attribute. The size you choose will depend on your knowledge of the locality of the statements, and of the resources available to the application. Are statements re-executed? Will they still be in the cache when they get executed? How many statements do you want to be cached? In rare cases when statements are not re-executed, or are likely not to be in the cache, you might even want to disable the cache to eliminate its management overheads.

    Incorrectly sizing the statement cache will reduce application efficiency.

    To help set the cache size, you can turn on auto-tuning with Oracle 12.1 using an oraaccess.xml file.

    For more information, see the Statement Caching documentation.

  • Use bind variables otherwise each variant of the statement will have its own statement cache entry and cursor. With appropriate binding only one entry and cursor will be needed.

  • Set the database's open_cursors parameter appropriately. This parameter specifies the maximum number of cursors that each "session" (i.e each node-oracle connection) can use. When a connection exceeds the value, the ORA-1000 error is thrown.

    Along with a cursor per entry in the connection's statement cache, any new statements that a connection is currently executing, or ResultSets that haven't been released (in neither situation are these yet cached), will also consume a cursor. Make sure that open_cursors is large enough to accommodate the maximum open cursors any connection may have. The upper bound required is stmtCacheSize + the maximum number of executing statements in a connection.

    Remember this is all per connection. Also cache management happens when statements are internally released. The majority of your connections may use less than open_cursors cursors, but if one connection is at the limit and it then tries to execute a new statement, that connection will get ORA-1000: maximum open cursors exceeded.

10. PL/SQL Execution

PL/SQL stored procedures, functions and anonymous blocks can be called from node-oracledb using execute().

Note the error property of the callback is not set when PL/SQL "success with info" warnings such as compilation warnings occur.

10.1 PL/SQL Stored Procedures

The PL/SQL procedure:

CREATE OR REPLACE PROCEDURE myproc (id IN NUMBER, name OUT VARCHAR2) AS
BEGIN
  SELECT last_name INTO name FROM employees WHERE employee_id = id;
END;

can be called:

. . .
connection.execute(
  "BEGIN myproc(:id, :name); END;",
  {  // bind variables
    id:   159,
    name: { dir: oracledb.BIND_OUT, type: oracledb.STRING, maxSize: 40 },
  },
  function (err, result) {
    if (err) { console.error(err.message); return; }
    console.log(result.outBinds);
  });

The output is:

{ name: 'Smith' }

Binding is required for IN OUT and OUT parameters. It is strongly recommended for IN parameters. See Bind Parameters for Prepared Statements.

10.2 PL/SQL Stored Functions

The PL/SQL function:

CREATE OR REPLACE FUNCTION myfunc RETURN VARCHAR2 AS
BEGIN
  RETURN 'Hello';
END;

can be called by using an OUT bind variable for the function return value:

. . .
connection.execute(
  "BEGIN :ret := myfunc(); END;",
  { ret: { dir: oracledb.BIND_OUT, type: oracledb.STRING, maxSize: 40 } },
  function (err, result) {
    if (err) { console.error(err.message); return; }
    console.log(result.outBinds);
  });

The output is:

{ ret: 'Hello' }

See Bind Parameters for Prepared Statements for information on binding.

10.3 PL/SQL Anonymous PL/SQL Blocks

Anonymous PL/SQL blocks can be called from node-oracledb like:

. . .
connection.execute(
  "BEGIN SELECT last_name INTO :name FROM employees WHERE employee_id = :id; END;",
  {  // bind variables
    id:   134,
    name: { dir: oracledb.BIND_OUT, type: oracledb.STRING, maxSize: 40 },
  },
  function (err, result) {
    if (err) { console.error(err.message); return; }
    console.log(result.outBinds);
  });

The output is:

{ name: 'Rogers' }

See Bind Parameters for Prepared Statements for information on binding.

10.4 Using DBMS_OUTPUT

The DBMS_OUTPUT package is the standard way to "print" output from PL/SQL. The way DBMS_OUTPUT works is like a buffer. Your Node.js application code must first turn on DBMS_OUTPUT buffering for the current connection by calling the PL/SQL procedure DBMS_OUTPUT.ENABLE(NULL). Then any PL/SQL executed by the connection can put text into the buffer using DBMS_OUTPUT.PUT_LINE(). Finally DBMS_OUTPUT.GET_LINE() is used to fetch from that buffer. Note, any PL/SQL code that uses DBMS_OUTPUT runs to completion before any output is available to the user. Also, other database connections cannot access your buffer.

A basic way to fetch DBMS_OUTPUT with node-oracledb is to bind an output string when calling the PL/SQL DBMS_OUTPUT.GET_LINE() procedure, print the string, and then repeat until there is no more data. The following snippet is based on the example dbmsoutputgetline.js:

function fetchDbmsOutputLine(connection, cb) {
  connection.execute(
    "BEGIN DBMS_OUTPUT.GET_LINE(:ln, :st); END;",
    { ln: { dir: oracledb.BIND_OUT, type: oracledb.STRING, maxSize: 32767 },
      st: { dir: oracledb.BIND_OUT, type: oracledb.NUMBER } },
    function(err, result) {
      if (err) {
        return cb(err, connection);
      } else if (result.outBinds.st == 1) { // no more output
        return cb(null, connection);
      } else {
        console.log(result.outBinds.ln);
        return fetchDbmsOutputLine(connection, cb);
      }
    });
  }

Another way is to wrap the DBMS_OUTPUT.GET_LINE() call into a pipelined function and fetch the output using a SQL query. See dbmsoutputpipe.js for the full example.

The pipelined function could be created like:

CREATE OR REPLACE TYPE dorow AS TABLE OF VARCHAR2(32767);
/

CREATE OR REPLACE FUNCTION mydofetch RETURN dorow PIPELINED IS
  line VARCHAR2(32767);
  status INTEGER;
  BEGIN LOOP
    DBMS_OUTPUT.GET_LINE(line, status);
    EXIT WHEN status = 1;
    PIPE ROW (line);
  END LOOP;
END;
/

To get DBMS_OUTPUT that has been created, simply execute the query using the same connection:

connection.execute(
  "SELECT * FROM TABLE(mydofetch())",
  [],
  { resultSet: true },
  function (err, result) {
  . . .

The query rows can be handled using a ResultSet.

Remember to first enable output using DBMS_OUTPUT.ENABLE(NULL).

10.5 Edition-Based Redefinition

The Edition-Based Redefinition (EBR) feature of Oracle Database allows multiple versions of views, synonyms, PL/SQL objects and SQL Translation profiles to be used concurrently. Each items version is associated with an 'edition' which can be nominated at runtime by applications. This lets database logic be updated and tested while production users are still accessing the original version. Once every user has begun using the objects in the new edition, the old objects can be dropped.

To choose the edition, node-oracledb applications can set oracledb.edition globally, or specify a value when creating a pool or a standalone connection.

The example below shows how a PL/SQL function DISCOUNT can be created with two different implementations. The initial procedure is created as normal in the SQL*Plus command line:

CONNECT nodedemo/welcome

-- The default edition's DISCOUNT procedure

CREATE OR REPLACE FUNCTION discount(price IN NUMBER) RETURN NUMBER
AS
 newprice NUMBER;
BEGIN
  newprice := price - 4;
  IF (newprice < 1) THEN
    newprice := 1;
  END IF;
  RETURN newprice;
END;
/

This initial implementation is in the default 'edition' ora$base, which is pre-created in new and upgraded databases.

The user nodedemo can be given permission to create new 'editions':

CONNECT system/welcome

GRANT CREATE ANY EDITION TO nodedemo;
ALTER USER nodedemo ENABLE EDITIONS FORCE;

The next SQL*Plus script creates a new edition e2, and changes the current session to use it. A new version of DISCOUNT is created under that edition:

CONNECT nodedemo/welcome

CREATE EDITION e2;
ALTER SESSION SET EDITION = e2;

-- E2 edition's discount

CREATE OR REPLACE FUNCTION discount(price IN NUMBER) RETURN NUMBER
AS
 newprice NUMBER;
BEGIN
  newprice := 0.75 * price;
  RETURN newprice;
END;
/

There are now two implementations of the PL/SQL procedure DISCOUNT with the same prototype. Applications can choose at runtime which implementation to use. Here is a script that calls DISCOUNT:

var oracledb = require('oracledb');

oracledb.getConnection(
  {
    user: 'nodedemo',
    password: 'welcome',
    connectString: 'localhost/orclpdb'
  },
  function (err, connection) {
    if (err) {
      console.error(err.message);
      return;
    }
    connection.execute(
      `SELECT name, price, DISCOUNT(price) AS discountprice
       FROM parts
       ORDER BY id`,
      [],
      { outFormat: oracledb.OBJECT },
      function(err, result) {
        if (err) {
          console.error(err.message);
        } else {
          console.log(result.rows);
        }
      });
  }
);

Since the code doesn't explicitly set oracledb.edition (or equivalent), then the first implementation of DISCOUNT in the default edition is used. The output might be like:

[ { NAME: 'lamp', PRICE: 40, DISCOUNTPRICE: 36 },
  { NAME: 'wire', PRICE: 10, DISCOUNTPRICE: 6 },
  { NAME: 'switch', PRICE: 4, DISCOUNTPRICE: 1 } ]

If the connection uses edition e2, then the second implementation of DISCOUNT will be used:

oracledb.getConnection(
  {
    user: 'nodedemo',
    password: 'welcome',
    connectString: 'localhost/orclpdb',
    edition: 'e2'
  },
  . . . // same code as before

The output might be like:

[ { NAME: 'lamp', PRICE: 40, DISCOUNTPRICE: 30 },
  { NAME: 'wire', PRICE: 10, DISCOUNTPRICE: 7.5 },
  { NAME: 'switch', PRICE: 4, DISCOUNTPRICE: 3 } ]

See the Database Development Guide chapter Using Edition-Based Redefinition for more information about EBR.

11. Working with CLOB and BLOB Data

Oracle Database uses LOB data types to store long objects. The CLOB type is used for character data and the BLOB type is used for binary data. In node-oracledb, LOBs can be represented by instances of the Lob class or as Strings and Buffers.

There are runnable LOB examples in the GitHub examples directory.

11.1 Simple Insertion of LOBs

Node.js String or Buffer types can be passed into PL/SQL blocks or inserted into the database by binding to LOB columns or PL/SQL parameters.

If the data is larger than can be handled as a String or Buffer in Node.js or node-oracledb, it will need to be streamed to a Lob, as discussed in Streams and Lobs. See LOB Bind Parameters for size considerations regarding LOB binds.

Given the table:

CREATE TABLE mylobs (id NUMBER, c CLOB, b BLOB);

an INSERT example is:

var fs = require('fs');
var str = fs.readFileSync('example.txt', 'utf8');
. . .

conn.execute(
  "INSERT INTO mylobs (id, myclobcol) VALUES (:idbv, :cbv)",
  { idbv: 1,
    cbv: str },  // type and direction are optional for IN binds
  function(err, result) {
    if (err)
      console.error(err.message);
    else
      console.log('CLOB inserted from example.txt');
. . .

Updating LOBs is similar to insertion:

conn.execute(
  "UPDATE mylobs SET myclobcol = :cbv WHERE id = :idbv",
  { idbv: 1, cbv: str },
. . .

Buffers can similarly be bound for inserting into, or updating, BLOB columns.

When using PL/SQL, a procedure:

PROCEDURE lobs_in (p_id IN NUMBER, c_in IN CLOB, b_in IN BLOB) . . .

can be called like:

bigStr = 'My string to insert';
bigBuf = Buffer.from([. . .]);

conn.execute(
  "BEGIN lobs_in(:id, :c, :b); END;",
  { id: 20,
    c: bigStr,    // type and direction are optional for IN binds
    b: bigBuf } },
  function (err) {
    if (err) { return cb(err, conn); }
    console.log("Completed");
    return cb(null, conn);
  }
);

11.2 Simple LOB Queries and PL/SQL OUT Binds

Querying LOBs

Smaller LOBs queried from the database can be returned as Strings or Buffers by using oracledb.fetchAsString or oracledb.fetchAsBuffer (or fetchInfo). If the data is larger than can be handled as a String or Buffer in Node.js or node-oracledb, it will need to be streamed from a Lob, as discussed later in Streams and Lobs.

For example, to make every CLOB queried by the application be returned as a string:

oracledb.fetchAsString = [ oracledb.CLOB ];

conn.execute(
  "SELECT c FROM mylobs WHERE id = 1",
  function(err, result) {
    if (err) { console.error(err.message); return; }
    if (result.rows.length === 0)
      console.error("No results");
    else {
      var clob = result.rows[0][0];
      console.log(clob);
    }
  });

CLOB columns in individual queries can be fetched as strings using fetchInfo:

conn.execute(
  "SELECT c FROM mylobs WHERE id = 1",
  [ ], // no binds
  { fetchInfo: {"C": {type: oracledb.STRING}} },
  function(err, result) {
    if (err) { console.error(err.message); return; }
    if (result.rows.length === 0) {
      console.error("No results");
    }
    else {
      var clob = result.rows[0][0];
      console.log(clob);
    }
  });

BLOB query examples are very similar. To force every BLOB in the application to be returned as a buffer:

oracledb.fetchAsBuffer = [ oracledb.BLOB ];

conn.execute(
  "SELECT b FROM mylobs WHERE id = 2",
  function(err, result) {
    if (err) { console.error(err.message); return; }
    if (result.rows.length === 0)
      console.error("No results");
    else {
      var blob = result.rows[0][0];
      console.log(blob.toString());  // assuming printable characters
    }
  });

BLOB columns in individual queries can be fetched as buffers using fetchInfo:

conn.execute(
  "SELECT b FROM mylobs WHERE id = 2",
  [ ], // no binds
  { fetchInfo: {"B": {type: oracledb.BUFFER}} },
  function(err, result) {
    if (err) { console.error(err.message); return; }
    if (result.rows.length === 0) {
      console.error("No results");
    } else {
      var blob = result.rows[0][0];
      console.log(blob.toString());  // assuming printable characters
    }
  });

Getting LOBs as String or Buffer from PL/SQL

PL/SQL LOB OUT parameters can be bound as oracledb.STRING or oracledb.BUFFER. See LOB Bind Parameters for size considerations regarding LOB binds.

conn.execute(
  "BEGIN lobs_out(:id, :c, :b); END;",
  { id: 20,
    c: {type: oracledb.STRING, dir: oracledb.BIND_OUT, maxSize: 50000},
    b: {type: oracledb.BUFFER, dir: oracledb.BIND_OUT, maxSize: 50000} },
  function (err, result) {
    if (err) { return cb(err, conn); }

    var str = result.outBinds.c;  // a String
    var buf = result.outBinds.b;  // a Buffer
    return cb(null, str, buf); // do something with str and buf
  });

The fetched String and Buffer can be used directly in Node.js.

If data to be bound is larger than can be handled as a String or Buffer in Node.js or node-oracledb, it will need to be explicitly streamed to a Lob, as discussed in Streams and Lobs. See LOB Bind Parameters for size considerations regarding LOB binds.

11.3 Streams and Lobs

The Lob Class in node-oracledb implements the Node.js Stream interface to provide streaming access to CLOB and BLOB database columns and to PL/SQL bind parameters.

Node-oracledb Lobs can represent persistent LOBs (those permanently stored in the database) or temporary LOBs (such as those created with connection.createLob(), or returned from some SQL or PL/SQL).

If multiple LOBs are streamed concurrently, worker threads will effectively be serialized on the connection.

It is the application's responsibility to make sure the connection remains open while a Stream operation such as pipe() is in progress.

Readable Lobs

Being a Stream object, a Lob being read from the database has two modes of operation: "flowing mode" and "paused mode". In flowing mode, data is piped to another stream, or events are posted as data is read. In paused mode the application must explicitly call read() to get data.

The read(size) unit is in characters for CLOBs and in bytes for BLOBs.

When reading a LOB from the database, resources are automatically released at completion of the readable stream or if there is a LOB error. The lob.close() method can also be used to close persistent LOBs that have not been streamed to completion.

A Readable Lob object starts out in paused mode. If a 'data' event handler is added, or the Lob is piped to a Writeable stream, then the Lob switches to flowing mode.

For unpiped Readable Lobs operating in flowing mode where the Lob is read through event handlers, the Lob object can be switched to paused mode by calling pause(). Once the Lob is in paused mode, it stops emitting data events.

Similarly, a Readable Lob operating in the paused mode can be switched to flowing mode by calling resume(). It will then start emitting 'data' events again.

Writeable Lobs

Lobs are written to with pipe(). Alternatively the write() method can be called successively, with the last piece being written by the end() method. The end() method must be called because it frees resources. If the Lob is being piped into, then the write() and end() methods are automatically called.

Writeable Lobs also have events, see the Node.js Stream documentation.

At the conclusion of streaming into a Writeable Lob, the close event will occur. It is recommended to put logic such as committing and releasing connections in this event (or after it occurs). See lobinsert2.js. It is also recommended that persistent LOBs not use the finish event handler for cleanup.

11.4 Using RETURNING INTO to Insert into LOBs

If Strings or Buffers are too large to be directly inserted into the database (see Simple Insertion of LOBs), use a RETURNING INTO clause to retrieve a Lob for a table item. Data can then be streamed into the Lob and committed directly to the table:

connection.execute(
  "INSERT INTO mylobs (id, c) VALUES (:id, EMPTY_CLOB()) RETURNING c INTO :lobbv",
  { id: 4,
    lobbv: {type: oracledb.CLOB, dir: oracledb.BIND_OUT} },
  { autoCommit: false },  // a transaction needs to span the INSERT and pipe()
  function(err, result) {
    if (err) { console.error(err.message); return; }
    if (result.rowsAffected != 1 || result.outBinds.lobbv.length != 1) {
      console.error('Error getting a LOB locator');
      return;
    }

    var lob = result.outBinds.lobbv[0];
    lob.on('close', function() {
        connection.commit(  // all data is loaded so we can commit it
          function(err) {
            if (err) console.error(err.message);
            connection.close(function(err) { if (err) console.error(err); });
          });
      });
    lob.on('error', function(err) {
        console.error(err);
        connection.close(function(err) {
          if (err) console.error(err.message);
        });
      });

    var inStream = fs.createReadStream('example.txt'); // open the file to read from
    inStream.on('error', function(err) { if (err) console.error(err); });
    inStream.pipe(lob);  // copies the text to the LOB
  });

This example streams from a file into the table. When the data has been completely streamed, the Lob is automatically closed and the 'close' event triggered. At this point the data can be committed.

See lobinsert2.js for the full example.

11.5 Getting LOBs as Streams from Oracle Database

By default, when a SELECT clause contains a LOB column, or a PL/SQL OUT parameter returns a LOB, instances of Lob are created. (This can be changed, see Simple LOB Queries and PL/SQL OUT Binds.)

For each Lob instance, the lob.type property will be oracledb.BLOB or oracledb.CLOB, depending on the column or PL/SQL parameter type.

Returned Lobs can be used as Readable Streams. Data can be streamed from each Lob, for example to a file. At the conclusion of the stream, persistent LOBs are automatically closed.

Lobs returned from the database that are not streamed can be passed back to the database as IN binds for PL/SQL blocks, for INSERT, or for UPDATE statements. The Lobs should then be closed with lob.close(). If they are passed as IN OUT binds, they will be automatically closed and the execution outBinds property will contain the updated Lob.

LOB Query Example

Each CLOB or BLOB in a SELECT returns a Lob by default. The table:

CREATE TABLE mylobs (id NUMBER, c CLOB, b BLOB);

can be called to get a Lob clob like:

conn.execute(
  "SELECT c FROM mylobs WHERE id = 1",
  function(err, result) {
    if (err) {
      return cb(err);
    }
    if (result.rows.length === 0) {
      return cb(new Error("whoops"));
    }
    var clob = result.rows[0][0]; // Instance of a node-oracledb Lob
    // console.log(clob.type);    // -> 2006 aka oracledb.CLOB
    cb(null, clob);               // do something with the Lob
  });

PL/SQL LOB Parameter Fetch Example

A PL/SQL procedure such as this:

PROCEDURE lobs_out (id IN NUMBER, clob_out OUT CLOB, blob_out OUT BLOB) . . .

can be called to get the Lobs clob and blob:

conn.execute(
  "BEGIN lobs_out(:id, :c, :b); END;",
  { id: 1,
    c: {type: oracledb.CLOB, dir: oracledb.BIND_OUT},
    b: {type: oracledb.BLOB, dir: oracledb.BIND_OUT} },
  function(err, result) {
    if (err) {
      return cb(err, conn);
    }

    var clob = result.outBinds.c;
    var blob = result.outBinds.b;
    cb(null, clob, blob);         // do something with the Lobs
  });

Streaming Out a Lob

Once a Lob is obtained from a query or PL/SQL OUT bind, it can be streamed out:

if (lob === null) {
    // . . . do special handling such as create an empty file or throw an error
}

if (lob.type === oracledb.CLOB) {
  lob.setEncoding('utf8');  // set the encoding so we get a 'string' not a 'buffer'
}

lob.on('error', function(err) { cb(err); });
lob.on('close', function() { cb(null); });   // all done.  The Lob is automatically closed.

var outStream = fs.createWriteStream('myoutput.txt');
outStream.on('error', function(err) { cb(err); });

// switch into flowing mode and push the LOB to myoutput.txt
lob.pipe(outStream);

Note the Lob is automatically closed at the end of the stream.

An alternative to the lob.pipe() call is to have a data event on the Lob Stream which processes each chunk of LOB data separately. Either a String or Buffer can be built up or, if the LOB is big, each chunk can be written to another Stream or to a file:

if (lob === null) {
    // . . . do special handling such as create an empty file or throw an error
}

var str = "";

lob.setEncoding('utf8');  // set the encoding so we get a 'string' not a 'buffer'
lob.on('error', function(err) { cb(err); });
lob.on('close', function() { cb(null); });   // all done.  The Lob is automatically closed.
lob.on('data', function(chunk) {
    str += chunk; // or use Buffer.concat() for BLOBS
});
lob.on('end', function() {
    fs.writeFile(..., str, ...);
});

Node-oracledb's lob.pieceSize can be used to control the number of bytes retrieved for each readable 'data' event. This sets the number of bytes (for BLOBs) or characters (for CLOBs). The default is lob.chunkSize. The recommendation is for it to be a multiple of chunkSize.

See lobbinds.js for a full example.

11.6 Using createLob() for PL/SQL IN Binds

Node-oracledb applications can create Oracle 'temporary LOBs' by calling connection.createLob(). These are instances of the Lob class. They can be populated with data and passed to PL/SQL blocks. This is useful if the data is larger than feasible for direct binding (see Simple Insertion of LOBs). These Lobs can also be used for SQL statement IN binds, however the RETURNING INTO method shown above will be more efficient.

Lobs from createLob() will use space in the temporary tablespace until lob.close() is called. Database Administrators can track this usage by querying V$TEMPORARY_LOBS.

Passing a Lob Into PL/SQL

The following insertion example is based on lobplsqltemp.js. It creates an empty LOB, populates it, and then passes it to a PL/SQL procedure.

A temporary LOB can be created with connection.createLob():

conn.createLob(oracledb.CLOB, function(err, templob) {
  if (err) { . . . }

  // ... else use templob
});

Once created, data can be inserted into it. For example to read a text file:

templob.on('error', function(err) { somecallback(err); });

// The data was loaded into the temporary LOB, so use it
templob.on('finish', function() { somecallback(null, templob); });

// copies the text from 'example.txt' to the temporary LOB
var inStream = fs.createReadStream('example.txt');
inStream.on('error', function(err) { . . . });
inStream.pipe(templob);

Now the LOB has been populated, it can be bound in somecallback() to a PL/SQL IN parameter:

// For PROCEDURE lobs_in (p_id IN NUMBER, c_in IN CLOB, b_in IN BLOB)
conn.execute(
  "BEGIN lobs_in(:id, :c, null); END;",
  { id: 3,
    c: templob }, // type and direction are optional for IN binds
  function(err) {
    if (err) { return cb(err); }
    console.log("Call completed");
    return cb(null, conn, templob);
  });

When the LOB is no longer needed, it must be closed with lob.close():

templob.close(function (err) {
  if (err)
    . . .
  else
    // success
});

11.7 Closing Lobs

Closing a Lob frees up resources. In particular, the temporary tablespace storage used by a temporary LOB is released. Once a Lob is closed, it can no longer be bound or used for streaming.

Lobs created with createLob() should be explicitly closed with lob.close().

Persistent or temporary Lobs returned from the database should be closed with lob.close() unless they have been automatically closed. Automatic closing of returned Lobs occurs when:

  • streaming has completed
  • a stream error occurs
  • the Lob was used as the source for an IN OUT bind

If you try to close a Lob being used for streaming you will get the error NJS-023: concurrent operations on a Lob are not allowed.

The connection must be open when calling lob.close() on a temporary LOB.

The lob.close() method emits the Node.js Stream 'close' event unless the Lob has already been closed explicitly or automatically.

12. Oracle Database 12c JSON Data type

Oracle Database 12.1.0.2 introduced native support for JSON data. You can use JSON with relational database features, including transactions, indexing, declarative querying, and views. You can project JSON data relationally, making it available for relational processes and tools.

JSON data in the database is stored as BLOB, CLOB or VARCHAR2 data. This means that node-oracledb can easily insert and query it.

As an example, the following table has a PO_DOCUMENT column that is enforced to be JSON:

CREATE TABLE j_purchaseorder (po_document VARCHAR2(4000) CHECK (po_document IS JSON));

To insert data using node-oracledb:

var data = { "userId": 1, "userName": "Chris", "location": "Australia" };
var s = JSON.stringify(data);  // change JavaScript value to a JSON string

connection.execute(
  "INSERT INTO j_purchaseorder (po_document) VALUES (:bv)",
  [s]  // bind the JSON string
  function (err) {
  . . .
  });

Queries can access JSON with Oracle JSON path expressions. These expressions are matched by Oracle SQL functions and conditions to select portions of the JSON data. Path expressions can use wildcards and array ranges. An example is $.friends which is the value of JSON field friends.

Oracle provides SQL functions and conditions to create, query, and operate on JSON data stored in the database.

For example, j_purchaseorder can be queried with:

"SELECT po.po_document.location FROM j_purchaseorder po"

With the earlier JSON inserted into the table, the queried value would be Australia.

The JSON_EXISTS tests for the existence of a particular value within some JSON data. To look for JSON entries that have a quantity field:

conn.execute(
  "SELECT po_document FROM j_purchaseorder WHERE JSON_EXISTS (po_document, '$.location')",
  function(err, result) {
    if (err) {
      . . .
    } else {
      var js = JSON.parse(result.rows[0][0]);  // show only first record in this example
      console.log('Query results: ', js);
    }
  });

This query would display:

{ userId: 1, userName: 'Chris', location: 'Australia' }

In Oracle Database 12.2 the JSON_OBJECT function is a great way to convert relational table data to JSON:

conn.execute(
  `SELECT JSON_OBJECT ('deptId' IS d.department_id, 'name' IS d.department_name) department
  FROM departments d
  WHERE department_id < :did`,
  [50],
  function(err, result) {
    if (err) { console.error(err.message); return; }
    for (var i = 0; i < result.rows.length; i++)
      console.log(result.rows[i][0]);
  });

This produces:

{"deptId":10,"name":"Administration"}
{"deptId":20,"name":"Marketing"}
{"deptId":30,"name":"Purchasing"}
{"deptId":40,"name":"Human Resources"}

See selectjson.js and selectjsonblob.js for runnable examples.

For more information about using JSON in Oracle Database see the Database JSON Developer's Guide.

13. Working with XMLType

XMLType columns cannot be queried directly. Instead, change the SQL query to return a CLOB, for example

var sql = 'SELECT XMLTYPE.GETCLOBVAL(res) FROM resource_view';

The CLOB can be fetched in node-oracledb as a String or Lob.

To insert into an XMLType column, directly insert a string containing the XML, or use a temporary LOB, depending on the data length.

var myxml =
    `<Warehouse>
    <WarehouseId>1</WarehouseId>
    <WarehouseName>Melbourne, Australia</WarehouseName>
    <Building>Owned</Building>
    <Area>2020</Area>
    <Docks>1</Docks>
    <DockType>Rear load</DockType>
    <WaterAccess>false</WaterAccess>
    <RailAccess>N</RailAccess>
    <Parking>Garage</Parking>
    <VClearance>20</VClearance>
    </Warehouse>`;

    connection.execute(
      "INSERT INTO xwarehouses (warehouse_id, warehouse_spec) VALUES (:id, XMLType(:bv))",
      { id: 1, bv: myxml },
      . . .

LOB handling as discussed in the section Working with CLOB and BLOB Data.

14. Bind Parameters for Prepared Statements

SQL and PL/SQL statements may contain bind parameters, indicated by colon-prefixed identifiers or numerals. These indicate where separately specified values are substituted in a statement when it is executed, or where values are to be returned after execution.

IN binds are values passed into the database. OUT binds are used to retrieve data. IN OUT binds are passed in, and may return a different value after the statement executes.

Using bind parameters is recommended in preference to constructing SQL or PL/SQL statements by string concatenation or template literals. This is for performance and security.

Inserted data that is bound is passed to the database separately from the statement text. It can never be executed directly. This means there is no need to escape bound data inserted into the database.

If a statement is executed more than once with different values for the bind parameters, then Oracle can re-use context from the initial execution, generally improving performance. However, if similar statements contain hard coded values instead of bind parameters, Oracle sees the statement text is different and will be less efficient.

Bind parameters can be used to substitute data but not the text of the statement.

Bind variables cannot be used in DDL statements, for example CREATE TABLE or ALTER commands.

Sets of values can bound for use in connection.executeMany(), see Batch Statement Execution.

14.1 IN Bind Parameters

For IN binds, a data value is passed into the database and substituted into the statement during execution of SQL or PL/SQL.

Bind by Name

To bind data values, the bindParams argument of execute() should contain bind variable objects with dir, val, type properties. Each bind variable object name must match the statement's bind parameter name:

var oracledb = require('oracledb');
. . .
connection.execute(
  "INSERT INTO countries VALUES (:country_id, :country_name)",
  {
    country_id: { dir: oracledb.BIND_IN, val: 90, type: oracledb.NUMBER },
    country_name: { dir: oracledb.BIND_IN, val: "Tonga", type:oracledb.STRING }
  },
  function(err, result) {
    if (err)
      console.error(err.message);
    else
      console.log("Rows inserted " + result.rowsAffected);
  });

For IN binds:

  • The direction dir is oracledb.BIND_IN, which is the default when dir is not specified.

  • The val attribute may be a constant or a JavaScript variable.

  • If type is omitted, it is inferred from the bind data value. If type is set, it can be oracledb.STRING, oracledb.NUMBER, oracledb.DATE or oracledb.BUFFER matching the standard Node.js type of the data being passed into the database. Use a bind type of oracledb.BLOB or oracledb.CLOB to pass in Lob instances. The type oracledb.BUFFER can bind a Node.js Buffer to an Oracle Database RAW, LONG RAW or BLOB type.

Since dir and type have defaults, these attributes are sometimes omitted for IN binds. Binds can be like:

connection.execute(
  "INSERT INTO countries VALUES (:country_id, :country_name)",
  {country_id: 90, country_name: "Tonga"},
  function(err, result) {
    if (err)
      console.error(err.message);
    else
      console.log("Rows inserted " + result.rowsAffected);
  });

When a bind parameter name is used more than once in the SQL statement, it should only occur once in the bind object:

connection.execute(
  "SELECT first_name, last_name FROM employees WHERE first_name = :nmbv OR last_name = :nmbv",
  {nmbv: 'Christopher'},
  function(err, result)
  . . .

Bind by Position

Instead of using named bind parameters, the data can alternatively be in an array. In this example, values are bound to the SQL bind parameters :country_id and :country_name:

connection.execute(
  "INSERT INTO countries VALUES (:country_id, :country_name)",
  [90, "Tonga"],
  function(err, result)
  . . .

The position of the array values corresponds to the position of the SQL bind parameters as they occur in the statement, regardless of their names. This is still true even if the bind parameters are named like :0, :1, etc. The following snippet will fail because the country name needs to be the second entry of the array so it becomes the second value in the INSERT statement

connection.execute(
  "INSERT INTO countries (country_id, country_name) VALUES (:1, :0)",
  ["Tonga", 90],  // fail
  . . .

In the context of SQL statements, the input array position 'n' indicates the bind parameter at the n'th position in the statement. However, in the context of PL/SQL statements the position 'n' in the bind call indicates a binding for the n'th unique parameter name in the statement when scanned left to right.

If a bind parameter name is repeated in the SQL string then bind by name syntax should be used.

Bind Data Type Notes

When binding a JavaScript Date value in an INSERT statement, it is inserted as if it represented a TIMESTAMP WITH LOCAL TIME ZONE value. In the database, TIMESTAMP WITH LOCAL TIME ZONE dates are normalized to the database time zone, or to the time zone specified for TIMESTAMP WITH TIME ZONE columns. If later queried, they are returned in the session time zone. See Fetching Date and Timestamps for more information.

The type oracledb.CURSOR cannot be used with IN binds.

Binding NCHAR, NVARCHAR or NCLOB for DML may result in incorrect character mapping, depending on the database character set and the database national character set. It may work in the case where the database character set can safely convert to the database national character set.

14.2 OUT and IN OUT Bind Parameters

OUT binds are used to retrieve data from the database. IN OUT binds are passed in, and may return a different value after the statement executes. IN OUT binds can be used for PL/SQL calls, but not for SQL.

For each OUT and IN OUT bind parameter in bindParams, a bind variable object containing dir, val, type, and maxSize properties is used:

  • The dir attribute should be oracledb.BIND_OUT or oracledb.BIND_INOUT, depending on whether data is only to be returned from the database or additionally passed into the database.

  • The val parameter in needed when binding IN OUT to pass a value into the database. It is not used for OUT binds.

  • For oracledb.BIND_INOUT parameters, the type attribute is inferred from the input data type. Alternatively it can be explicitly set to oracledb.STRING, oracledb.NUMBER, oracledb.DATE, oracledb.BLOB, oracledb.CLOB or oracledb.BUFFER, matching the data type of the Node.js value or variable. The output data type will always be the same as the input data type.

    For oracledb.BIND_OUT parameters the type attribute will be the node-oracledb or Node.js data type that data will be returned as. It should be oracledb.STRING, oracledb.NUMBER, oracledb.DATE, oracledb.BUFFER, oracledb.CURSOR, oracledb.BLOB, or oracledb.CLOB. If type is not specified for OUT binds then oracledb.STRING is assumed.

    Oracle Database CLOB data can be bound with a type of oracledb.STRING to return a Node.js String, or as type of oracledb.CLOB to return a Lob instance.

    Oracle Database BLOB data can be bound with a type of oracledb.BUFFER to return a Node.js Buffer, or as type of oracledb.BLOB to return a Lob instance.

    Oracle Database RAW and LONG RAW data can be bound with a type of oracledb.BUFFER to return a Node.js Buffer.

    Oracle Database LONG, ROWID and UROWID data can be bound with a type of oracledb.STRING to return a JavaScript String.

  • A maxSize attribute should be set for oracledb.STRING or oracledb.BUFFER OUT or IN OUT binds. This is the maximum number of bytes the bind parameter will return. If the output value does not fit in maxSize bytes, then an error such ORA-06502: PL/SQL: numeric or value error: character string buffer too small or NJS-016: buffer is too small for OUT binds occurs.

    A default value of 200 bytes is used when maxSize is not provided for OUT binds of type oracledb.STRING or oracledb.BUFFER.

    A string representing a UROWID may be up to 5267 bytes long in node-oracledb.

For PL/SQL Associative Array binds a maxArraySize property is also required

Accessing OUT Bind Values

The results parameter of the execute() callback contains an outBinds property with the returned OUT and IN OUT bind values.

Given the creation of the PL/SQL procedure TESTPROC:

CREATE OR REPLACE PROCEDURE testproc (
p_in IN VARCHAR2, p_inout IN OUT VARCHAR2, p_out OUT NUMBER)
AS
BEGIN
  p_inout := p_in || p_inout;
  p_out := 101;
END;
/
show errors

The procedure TESTPROC can be called with:

var oracledb = require('oracledb');
. . .
var bindVars = {
  i:  'Chris', // default direction is BIND_IN. Data type is inferred from the data
  io: { val: 'Jones', dir: oracledb.BIND_INOUT },
  o:  { dir: oracledb.BIND_OUT, type: oracledb.NUMBER },
}
connection.execute(
  "BEGIN testproc(:i, :io, :o); END;",
  bindVars,
  function (err, result) {
    if (err) { console.error(err.message); return; }
    console.log(result.outBinds);
  });

Since bindParams is passed as an object, the outBinds property is also an object. The Node.js output is:

{ io: 'ChrisJones', o: 101 }

PL/SQL allows named parameters in procedure and function calls. This can be used in execute() like:

  "BEGIN testproc(p_in => :i, p_inout => :io, p_out => :o); END;",

An alternative to node-oracledb's 'bind by name' syntax is 'bind by array' syntax:

var bindVars = [
  'Chris',
  { val: 'Jones', dir: oracledb.BIND_INOUT },
  { type: oracledb.NUMBER, dir: oracledb.BIND_OUT }
];

When bindParams is passed as an array, then outBinds is returned as an array, with the same order as the OUT binds in the statement:

[ 'ChrisJones', 101 ]

Mixing positional and named syntax is not supported. The following will throw an error:

var bindVars = [
  'Chris',                                                  // valid
  { val: 'Jones', dir: oracledb.BIND_INOUT },               // valid
  { o: { type: oracledb.NUMBER, dir: oracledb.BIND_OUT } }  // invalid
];

14.3 DML RETURNING Bind Parameters

DML statements query or manipulate data in existing schema objects.

Bind parameters from "DML RETURNING" statements (such as INSERT ... RETURNING ... INTO ...) can use oracledb.BLOB, oracledb.CLOB, oracledb.STRING, oracledb.NUMBER or oracledb.DATE for the OUT type.

For oracledb.STRING types, an error occurs if maxSize is not large enough to hold a returned value.

Note each DML RETURNING bind OUT parameter is returned as an array containing zero or more elements. Application code that is designed to expect only one value could be made more robust if it confirms the returned array length is not greater than one. This will help identify invalid data or an incorrect WHERE clause that causes more results to be returned.

Oracle Database DATE, TIMESTAMP, TIMESTAMP WITH LOCAL TIME ZONE and TIMESTAMP WITH TIME ZONE types can be bound as oracledb.DATE for DML RETURNING. These types can also be bound as oracledb.STRING, if desired. ROWID and UROWID data to be returned can be bound as oracledb.STRING. Note that a string representing a UROWID may be up to 5267 bytes long.

No duplicate binds are allowed in a DML statement with a RETURNING clause, and no duplication is allowed between bind parameters in the DML section and the RETURNING section of the statement.

One common use case is to return an 'auto incremented' key values, see Auto-Increment Columns.

An example of DML RETURNING binds is:

var oracledb = require('oracledb');
. . .
connection.execute(
   "UPDATE mytab SET name = :name "
 + "WHERE id = :id "
 + "RETURNING id, ROWID INTO :ids, :rids",
  {
    id:    1001,
    name:  "Krishna",
    ids:   { type: oracledb.NUMBER, dir: oracledb.BIND_OUT },
    rids:  { type: oracledb.STRING, dir: oracledb.BIND_OUT }
  },
  function(err, result) {
    if (err) { console.error(err); return; }
    console.log(result.outBinds);
  });

If the WHERE clause matches one record, the output would be like:

{ ids: [ 1001 ], rids: [ 'AAAbvZAAMAAABtNAAA' ] }

When a couple of rows match, the output could be:

{ ids: [ 1001, 1002 ],
  rids: [ 'AAAbvZAAMAAABtNAAA', 'AAAbvZAAMAAABtNAAB' ] }

If the WHERE clause matches no rows, the output would be:

{ ids: [], rids: [] }

14.4 REF CURSOR Bind Parameters

Oracle REF CURSORS can be fetched in node-oracledb by binding a oracledb.CURSOR to a PL/SQL call. The resulting bind variable becomes a ResultSet, allowing rows to be fetched using getRow() or getRows(). The ResultSet can also be converted to a Readable Stream by using toQueryStream().

If using getRow() or getRows() the ResultSet must be freed using close() when all rows have been fetched, or when the application does not want to continue getting more rows. If the REF CURSOR is set to NULL or is not set in the PL/SQL procedure then the returned ResultSet is invalid and methods like getRows() will return an error when invoked.

Given a PL/SQL procedure defined as:

CREATE OR REPLACE PROCEDURE get_emp_rs (
  p_sal IN NUMBER,
  p_recordset OUT SYS_REFCURSOR) AS
BEGIN
  OPEN p_recordset FOR
    SELECT first_name, salary, hire_date
    FROM   employees
    WHERE  salary > p_sal;
END;
/

This PL/SQL procedure can be called in node-oracledb using:

var oracledb = require('oracledb');

var numRows = 10;  // number of rows to return from each call to getRows()

var plsql = "BEGIN get_emp_rs(:sal, :cursor); END;";
var bindvars = {
  sal:  6000,
  cursor:  { type: oracledb.CURSOR, dir: oracledb.BIND_OUT }
}

connection.execute(
  plsql,
  bindvars,
  function(err, result) {
    if (err) { . . . }
    fetchRowsFromRS(connection, result.outBinds.cursor, numRows);
  });

function fetchRowsFromRS(connection, resultSet, numRows) {
  resultSet.getRows( // get numRows rows
    numRows,
    function (err, rows) {
      if (err) {
         . . .                        // close the ResultSet and release the connection
      } else if (rows.length > 0) {   // got some rows
        console.log(rows);            // process rows
        if (rows.length === numRows)  // might be more rows
          fetchRowsFromRS(connection, resultSet, numRows);
        else                          // got fewer rows than requested so must be at end
          . . .                       // close the ResultSet and release the connection
      } else {                        // else no rows
          . . .                       // close the ResultSet and release the connection
      }
    });
}

See refcursor.js for a complete example.

To convert the REF CURSOR ResultSet to a stream, use toQueryStream(). With the PL/SQL and bind values from the previous examples, the code would become:

connection.execute(
  plsql,
  bindvars,
  function(err, result) {
    if (err) { . . . }
    fetchRCFromStream(connection, result.outBinds.cursor);
  });

function fetchRCFromStream(connection, cursor) {
  var stream = cursor.toQueryStream();

  stream.on('error', function (error) {
    // console.log("stream 'error' event");
    console.error(error);
    return;
  });

  stream.on('metadata', function (metadata) {
    // console.log("stream 'metadata' event");
    console.log(metadata);
  });

  stream.on('data', function (data) {
    // console.log("stream 'data' event");
    console.log(data);
  });

  stream.on('end', function () {
    // console.log("stream 'end' event");
    connection.release(
      function(err) {
        if (err) {
          console.error(err.message);
        }
      });
  });
}

The connection must remain open until the stream is completely read. Query results must be fetched to completion to avoid resource leaks. The ResultSet close() call for streaming query results will be executed internally when all data has been fetched.

14.5 LOB Bind Parameters

Database CLOBs can be bound with type set to oracledb.CLOB. Database BLOBs can be bound as oracledb.BLOB. These binds accept, or return, node-oracledb Lob instances, which implement the Node.js Stream interface.

Lobs may represent Oracle Database persistent LOBs (those stored in tables) or temporary LOBs (such as those created with createLob() or returned by some SQL and PL/SQL operations).

LOBs can be bound with direction oracledb.BIND_IN, oracledb.BIND_OUT or oracledb.BIND_INOUT, depending on context.

Note that any PL/SQL OUT LOB parameter should be initialized in the PL/SQL block - even just to NULL - before the PL/SQL code completes. Make sure to do this in all PL/SQL code paths including in error handlers. This prevents node-oracledb throwing the error DPI-007: invalid OCI handle or descriptor.

In many cases it will be easier to work with JavaScript Strings and Buffers instead of Lobs. These types can be bound directly for SQL IN binds to insert into, or update, LOB columns. They can also be bound to PL/SQL LOB parameters. Use the bind type oracledb.STRING for CLOBs and oracledb.BUFFER for BLOBs. The default size used for these binds in the OUT direction is 200, so set maxSize appropriately.

See Working with CLOB and BLOB Data for examples and more information on binding and working with LOBs.

Size Limits for Binding LOBs to Strings and Buffers

When CLOBs are bound as oracledb.STRING, or BLOBs are bound as oracledb.BUFFER, the limitation on binding is the memory available to Node.js and the V8 engine. For data larger than several megabytes, it is recommended to bind as oracledb.CLOB or oracledb.BLOB and use Lob streaming. If you try to create large Strings or Buffers in Node.js you will see errors like JavaScript heap out of memory, or other space related messages.

Internally, temporary LOBs are used when binding Strings and Buffers larger than 32 KB for PL/SQL calls. Freeing of the temporary LOB is handled automatically. For SQL calls no temporary LOBs are used.

14.6 PL/SQL Collection Associative Array (Index-by) Bind Parameters

Arrays of strings and numbers can be bound to PL/SQL IN, IN OUT, and OUT parameters of PL/SQL INDEX BY associative array type. This type was formerly called PL/SQL tables or index-by tables. This method of binding can be a very efficient way of transferring small data sets to PL/SQL. Note PL/SQL's VARRAY and nested table collection types cannot be bound.

Given this table and PL/SQL package:

DROP TABLE mytab;
CREATE TABLE mytab (id NUMBER, numcol NUMBER);

CREATE OR REPLACE PACKAGE mypkg IS
  TYPE numtype IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;
  PROCEDURE myinproc(p_id IN NUMBER, vals IN numtype);
  PROCEDURE myoutproc(p_id IN NUMBER, vals OUT numtype);
END;
/

CREATE OR REPLACE PACKAGE BODY mypkg IS

  PROCEDURE myinproc(p_id IN NUMBER, vals IN numtype) IS
  BEGIN
    FORALL i IN INDICES OF vals
      INSERT INTO mytab (id, numcol) VALUES (p_id, vals(i));
  END;

  PROCEDURE myoutproc(p_id IN NUMBER, vals OUT numtype) IS
  BEGIN
    SELECT numcol BULK COLLECT INTO vals FROM mytab WHERE id = p_id ORDER BY 1;
  END;

END;
/

To bind an array in node-oracledb using "bind by name" syntax for insertion into mytab use:

connection.execute(
  "BEGIN mypkg.myinproc(:id, :vals); END;",
  {
    id: 1234,
    vals: { type: oracledb.NUMBER,
             dir: oracledb.BIND_IN,
             val: [1, 2, 23, 4, 10]
          }
  }, . . .

Alternatively, "bind by position" syntax can be used:

connection.execute(
 "BEGIN mypkg.myinproc(:id, :vals); END;",
 [
   1234,
   { type: oracledb.NUMBER,
      dir: oracledb.BIND_IN,
      val: [1, 2, 23, 4, 10]
   }
 ],

 function (err) { . . . });

After executing either of these mytab will contain:

    ID         NUMCOL
---------- ----------
      1234          1
      1234          2
      1234         23
      1234          4
      1234         10

The type must be set for PL/SQL array binds. It can be set to oracledb.STRING or oracledb.NUMBER.

For OUT and IN OUT binds, the maxArraySize bind property must be set. Its value is the maximum number of elements that can be returned in an array. An error will occur if the PL/SQL block attempts to insert data beyond this limit. If the PL/SQL code returns fewer items, the JavaScript array will have the actual number of data elements and will not contain null entries. Setting maxArraySize larger than needed will cause unnecessary memory allocation.

For IN OUT binds, maxArraySize can be greater than the number of elements in the input array. This allows more values to be returned than are passed in.

For IN binds, maxArraySize is ignored, as also is maxSize.

For oracledb.STRING IN OUT or OUT binds, the string length maxSize property may be set. If it is not set the memory allocated per string will default to 200 bytes. If the value is not large enough to hold the longest string data item in the collection a runtime error occurs. To avoid unnecessary memory allocation, do not let the size be larger than needed.

The next example fetches an array of values from a table. First, insert these values:

INSERT INTO mytab (id, numcol) VALUES (99, 10);
INSERT INTO mytab (id, numcol) VALUES (99, 25);
INSERT INTO mytab (id, numcol) VALUES (99, 50);
COMMIT;

With these values, the following node-oracledb code will print [ 10, 25, 50 ].

connection.execute(
  "BEGIN mypkg.myoutproc(:id, :vals); END;",
  {
    id: 99,
    vals: { type: oracledb.NUMBER,
            dir:  oracledb.BIND_OUT,
            maxArraySize: 10          // allocate memory to hold 10 numbers
        }
  },
  function (err, result) {
    if (err) { console.error(err.message); return; }
    console.log(result.outBinds.vals);
  });

If maxArraySize was reduced to 2, the script would fail with:

ORA-06513: PL/SQL: index for PL/SQL table out of range for host language array

See Oracledb Constants and execute(): Bind Parameters for more information about binding.

See plsqlarray.js for a runnable example.

14.7 Binding Multiple Values to a SQL WHERE IN Clause

Binding a single JavaScript value into a SQL WHERE IN clause is easy:

sql = 'SELECT last_name FROM employees WHERE first_name IN (:bv)';
binds = ['Christopher'];
connection.execute(sql, binds, function(...));

But a common use case for a query WHERE IN clause is for multiple values, for example when a web user selects multiple check-box options and the query should match all chosen values.

Trying to associate multiple data values with a single bind parameter won't work. To use a fixed, small number of values in an WHERE IN bind clause, the SQL query should have individual bind parameters, for example:

sql = 'SELECT last_name FROM employees WHERE first_name IN (:bv1, :bv2, :bv3, :bv4)';
binds = ['Alyssa', 'Christopher', 'Hazel', 'Samuel'];
connection.execute(sql, binds, function(...));

If you sometimes execute the query with a smaller number of items, a null can be bound for the 'missing' values:

binds = ['Alyssa', 'Christopher', 'Hazel', null];

When the exact same statement text is re-executed many times regardless of the number of user supplied values, you get performance and scaling benefits from not having multiple, unique SQL statements being run.

Another solution when the number of data items is only known at runtime is to build up an exact SQL string like:

binds = ['Christopher', 'Hazel', 'Samuel'];
sql = "SELECT first_name, last_name FROM employees WHERE first_name IN (";
for (var i=0; i < binds.length; i++)
   sql += (i > 0) ? ", :" + i : ":" + i;
sql += ")";

This will construct a SQL statement:

SELECT first_name, last_name FROM employees WHERE first_name IN (:0, :1, :2)

Binds are still used for security. But, depending how often this query is executed, and how changeable the number of bind values is, you can end up with lots of 'unique' query strings being executed. You might not get the statement caching benefits that re-executing a fixed SQL statement would have.

Another solution for a larger number of values is to construct a SQL statement like:

SELECT ... WHERE col IN ( <something that returns a list of rows> )

The easiest way to do the <something that returns a list of rows> will depend on how the data is initially represented and the number of items. You might look at using CONNECT BY or nested tables. Or, for really large numbers of items, you might prefer to use a global temporary table. Some solutions are given in On Cursors, SQL, and Analytics and in this StackOverflow answer.

15. Batch Statement Execution

The connection.executeMany() method allows many sets of data values to be bound to one DML or PL/SQL statement for execution. It is like calling connection.execute() multiple times but requires fewer round-trips. This is an efficient way to handle batch changes, for example when doing bulk inserts, or for updating multiple rows. The method cannot be used for queries.

The executeMany() method supports IN, IN OUT and OUT binds for most data types except PL/SQL Collection Associative Arrays.

There are runnable examples in the GitHub examples directory.

For example, to insert three records into the database:

var sql = "INSERT INTO mytab VALUES (:a, :b)";

var binds = [
  { a: 1, b: "One" },
  { a: 2, b: "Two" },
  { a: 3, b: "Three" }
];

var options = {
  autoCommit: true,
  bindDefs: {
    a: { type: oracledb.NUMBER },
    b: { type: oracledb.STRING, maxSize: 5 }
  } };

connection.executeMany(sql, binds, options, function (err, result) {
  if (err) {
    console.error(err)
  } else {
    console.log(result);  // { rowsAffected: 3 }
  }
});

Strings and Buffers require a maxSize value in bindDefs. It must be the length (or greater) of the longest data value. For efficiency, keep the size as small as possible.

The options parameter is optional.

If bindDefs is not set, then the bind direction is assumed to be IN, and the bind data are used to determine the bind variable types, names and maximum sizes. Using bindDefs is generally recommended because it removes the overhead of scanning all records.

The bind definitions bindDefs can also use "bind by position" syntax, see the next examples.

Identifying Affected Rows

When executing a DML statement the number of database rows affected for each input record can be shown by setting dmlRowCounts. For example when deleting rows:

const sql = "DELETE FROM tab WHERE id = :1";

const binds = [
  [20],
  [30],
  [40]
];

const options = { dmlRowCounts: true };

connection.executeMany(sql, binds, options, function (err, result) {
  if (err) {
    console.error(err)
  } else {
    console.log(result.dmlRowCounts);
  }
});

If the table originally contained three rows with id of 20, five rows with id of 30 and six rows with id of 40, then the output would be:

[ 3, 5, 6 ]

Handling Data Errors

With large sets of data, it can be helpful not to abort processing on the first data error, but to continue processing and resolve the errors later.

When batchErrors is true, processing will continue even if there are data errors in some records. The executeMany() callback error parameter is not set. Instead, an array containing each error will be returned in the callback result parameter. All valid data records will be processed and a transaction will be started but not committed, even if autoCommit is true. The application can examine the errors, take action, and explicitly commit or rollback, as desired.

For example:

var sql = "INSERT INTO childtab VALUES (:1, :2, :3)";

var binds = [
  [1016, 10, "Child 2 of Parent A"],
  [1017, 10, "Child 3 of Parent A"],
  [1018, 20, "Child 4 of Parent B"],
  [1018, 20, "Child 4 of Parent B"],   // duplicate key
  [1019, 30, "Child 3 of Parent C"],
  [1020, 40, "Child 4 of Parent D"],
  [1021, 75, "Child 1 of Parent F"],   // parent does not exist
  [1022, 40, "Child 6 of Parent D"]
];

var options = {
  autoCommit: true,
  batchErrors: true,
  bindDefs: [
    { type: oracledb.NUMBER },
    { type: oracledb.NUMBER },
    { type: oracledb.STRING, maxSize: 20 }
  ]
};

connection.executeMany(sql, binds, options, function (err, result) {
  if (err) {
    console.error(err)
  } else {
    console.log(result.batchErrors);
  }
});

The output is an array of error objects that were reported during execution. The offset property corresponds to the 0-based index of the executeMany() binds parameter array, indicating which record could not be processed:

   [ { Error: ORA-00001: unique constraint (HR.CHILDTAB_PK) violated errorNum: 1, offset: 3 },
     { Error: ORA-02291: integrity constraint (HR.CHILDTAB_FK) violated - parent key not found errorNum: 2291, offset: 6 } ]

Note that some classes of error will always return via the executeMany() callback error object, not as batch errors. No transaction is created in this case. This includes errors where string or buffer data is larger than the specified maxSize value.

DML RETURNING

Values can be returned with DML RETURNING syntax:

var sql = "INSERT INTO tab VALUES (:1) RETURNING ROWID INTO :2";

var binds = [
  ["One"],
  ["Two"],
  ["Three"]
];

var options = {
  bindDefs: [
    { type: oracledb.STRING, maxSize: 5 },
    { type: oracledb.STRING, maxSize: 18, dir: oracledb.BIND_OUT  },
  ]
};

connection.executeMany(sql, binds, options, function (err, result) {
  if (err) {
    console.error(err)
  } else {
    console.log(result.outBinds);
  }
});

Output is:

[ [ [ 'AAAmI9AAMAAAAnVAAA' ] ],
  [ [ 'AAAmI9AAMAAAAnVAAB' ] ],
  [ [ 'AAAmI9AAMAAAAnVAAC' ] ] ]

Calling PL/SQL

The executeMany() method can be used to execute a PL/SQL statement multiple times with different input values. For example, the following PL/SQL procedure:

CREATE PROCEDURE testproc (
  a_num IN NUMBER,
  a_outnum OUT NUMBER,
  a_outstr OUT VARCHAR2)
AS
BEGIN
  a_outnum := a_num * 2;
  FOR i IN 1..a_num LOOP
    a_outstr := a_outstr || 'X';
  END LOOP;
END;
/

can be called like:

var sql = "BEGIN testproc(:1, :2, :3); END;";

// IN binds
var binds = [
  [1],
  [2],
  [3],
  [4]
];

var options = {
  bindDefs: [
    { type: oracledb.NUMBER },
    { type: oracledb.NUMBER, dir: oracledb.BIND_OUT },
    { type: oracledb.STRING, dir: oracledb.BIND_OUT, maxSize: 20 }
  ]
};

connection.executeMany(sql, binds, options, function (err, result) {
  if (err) {
    console.error(err)
  } else {
    console.log(result.outBinds);
  }
});

The returned bind values are:

[ [ 2, 'X' ],
  [ 4, 'XX' ],
  [ 6, 'XXX' ],
  [ 8, 'XXXX' ] ]

The variant of executeMany() that accepts a number of iterations is useful when there no bind values, or only OUT bind values. This example calls a PL/SQL block eight times:

var sql = `DECLARE
             t_id NUMBER;
           BEGIN
             SELECT NVL(COUNT(*), 0) + 1 INTO t_id FROM testtable;
             INSERT INTO testtable VALUES (t_id, 'Test String ' || t_id);
             SELECT SUM(id) INTO :1 FROM testtable;
           END;`

var options = {
  bindDefs: [
    { type : oracledb.NUMBER, dir : oracledb.BIND_OUT }
  ]
};

var numIterations = 8;

connection.executeMany(sql, numIterations, options, function (err, result) {
  if (err) {
    console.error(err)
  } else {
    console.log(result.outBinds);
  }
});

Output would be an array of eight values such as:

[ [ 6 ], [ 10 ], [ 15 ], [ 21 ], [ 28 ], [ 36 ], [ 45 ], [ 55 ] ]

16. Continuous Query Notification (CQN)

Continuous Query Notification (CQN) lets node-oracledb applications register a JavaScript method that is invoked when changed data is committed to the database, regardless of the user or the application that made the change. For example your application may be interested in knowing if a table used for lookup data has changed so the application can update a local cache of that table.

CQN is suitable for infrequently modified tables. It is recommended to avoid frequent subscription and unsubscription.

The connection must be created with events mode true.

The database must be able to connect to the node-oracledb machine for notifications to be received. Typically this means that the machine running node-oracledb needs a fixed IP address. Note connection.subscribe() does not verify that this reverse connection is possible. If there is any problem sending a notification, then the callback method will not be invoked. The configuration options can include an ipAddress and port on which to listen for notifications, otherwise the database chooses values.

To register interest in database changes, the connection.subscribe() method is passed an arbitrary name and an options object that controls notification. In particular options contains a valid SQL query and a JavaScript callback:

function myCallback(message) {
    console.log(message);
}

options = {
    sql      : "select * from mytable",  // query of interest
    callback : myCallback                // method called by notifications
};

connection.subscribe('mysub', options, function(err) { ... } );

In this example, whenever a change to mytable is committed then myCallback() is invoked. The callback message parameter contains information about the notification.

CQN notification behavior is widely configurable by the subscription options. Choices include specifying what types of SQL should trigger a notification, whether notifications should survive database loss, and control over unsubscription. You can also choose whether notification messages will include ROWIDs of affected rows.

The connection.subscribe() method may be called multiple times with the same name. In this case, the second and subsequent invocations ignore all options properties other than sql and binds. Instead, the new SQL statement is registered to the same subscription, and the same JavaScript notification callback is used. For performance reasons this can be preferable to creating a new subscription for each query.

You can view information about registrations by querying USER_CHANGE_NOTIFICATION_REGS table.

When notifications are no longer required, the subscription name can be passed to connection.unsubscribe().

By default, object-level (previously known as Database Change Notification) occurs and the JavaScript notification method is invoked whenever a database transaction is committed that changes an object the query references, regardless of whether the actual query result changed. However if the subscription option qos is oracledb.SUBSCR_QOS_QUERY then query-level notification occurs. In this mode, the database notifies the application whenever a transaction changes the result of the registered query and commits. For example:

options = {
    sql      : "select * from mytable where key > 100",  // query of interest
    callback : myCallback,                               // method called by notifications
    qos      : oracledb.SUBSCR_QOS_QUERY                 // CQN
};

In this example, if a new key of 10 was inserted then no notification would be generated. If a key wth 200 was inserted, then a notification would occur.

Before using CQN, users must have appropriate permissions, for example:

SQL> CONNECT system/welcome

SQL> GRANT CHANGE NOTIFICATION TO hr;

Below is an example of CQN that uses object-level notification and grouped notifications in batches at 10 second intervals. After 60 seconds, the notification callback is unregisted and no more notifications will occur. The quality of service flags indicate ROWIDs should be returned in the callback:

let interval = setInterval(function() {
    console.log("waiting...");
}, 5000);

function myCallback(message)
{
    console.log("Message type:", message.type);
    if (message.type == oracledb.SUBSCR_EVENT_TYPE_DEREG) {
        clearInterval(interval);
        console.log("Deregistration has taken place...");
        return;
    }
    console.log("Message database name:", message.dbName);
    console.log("Message transaction id:", message.txId);
    for (let i = 0; i < message.tables.length; i++) {
        let table = message.tables[i];
        console.log("--> Table Name:", table.name);
        console.log("--> Table Operation:", table.operation);
        if (table.rows) {
            for (j = 0; j < table.rows.length; j++) {
                let row = table.rows[j];
                console.log("--> --> Row Rowid:", row.rowid);
                console.log("--> --> Row Operation:", row.operation);
                console.log(Array(61).join("-"));
            }
        }
        console.log(Array(61).join("="));
    }
}

const options = {
    sql           : "SELECT * FROM MY mytable",
    callback      : myCallback,
    timeout       : 60,
    qos           : oracledb.SUBSCR_QOS_ROWIDS,
    groupingClass : oracledb.SUBSCR_GROUPING_CLASS_TIME,
    groupingValue : 10,
    groupingType  : oracledb.SUBSCR_GROUPING_TYPE_SUMMARY
};

try {
    // This is Node 8 syntax, but can be changed to callbacks

    let conn = await oracledb.getConnection({
      user          : "hr",
      password      : "welcome",
      connectString : "localhost/XE",
      events        :  true
    });

    await connection.subscribe('mysub', options);
    console.log("Subscription created...");

} catch (err) {
    console.error(err);
    clearInterval(interval);
}

If two new rows were inserted into the table and then committed, output might be like:

Message type: 6
Message database name: orcl
Message transaction id: <Buffer 06 00 21 00 f5 0a 00 00>
--> Table Name: CJ.MYTABLE
--> Table Operation: 2
--> --> Row Rowid: AAAVH6AAMAAAAHjAAW
--> --> Row Operation: 2
------------------------------------------------------------
--> --> Row Rowid: AAAVH6AAMAAAAHjAAX
--> --> Row Operation: 2
------------------------------------------------------------

Here, the message type 6 corresponds to oracledb.SUBSCR_EVENT_TYPE_OBJ_CHANGE and the row operations of 2 correspond to oracledb.CQN_OPCODE_INSERT.

There are runnable examples in the GitHub examples directory.

17. Transaction Management

By default, DML statements are not committed in node-oracledb.

The node-oracledb add-on implements commit() and rollback() methods that can be used to explicitly control transactions.

If the autoCommit flag is set to true, then a commit occurs at the end of each execute() call. Unlike an explicit commit(), this does not require a round-trip to the database. For maximum efficiency, set autoCommit to true for the last execute() call of a transaction in preference to using an additional, explicit commit() call.

When a connection is released, any ongoing transaction will be rolled back. Therefore if a released, pooled connection is re-used by a subsequent pool.getConnection() call (or oracledb.getConnection() call that uses a pool), then any DML statements performed on the obtained connection are always in a new transaction.

When an application ends, any uncommitted transaction on a connection will be rolled back.

Note: Oracle Database will implicitly commit when a DDL statement is executed irrespective of the value of autoCommit.

18. Statement Caching

Node-oracledb's execute() and queryStream() methods use the Oracle Call Interface statement cache to make re-execution of statements efficient. This cache removes the need for the separate 'prepare' or 'parse' method which is sometimes seen in other Oracle APIs: there is no separate method in node-oracledb.

Each non-pooled connection and each session in the connection pool has its own cache of statements with a default size of 30. Statement caching lets cursors be used without re-parsing the statement. Statement caching also reduces meta data transfer costs between the node-oracledb and the database. Performance and scalability are improved.

In general, set the statement cache to the size of the working set of statements being executed by the application.

Statement caching can be disabled by setting the size to 0. Disabling the cache may be beneficial when the quantity or order of statements causes cache entries to be flushed before they get a chance to be reused. For example if there are more distinct statements than cache slots, and the order of statement execution causes older statements to be flushed from the cache before the statements are re-executed.

The statement cache size can be set globally with stmtCacheSize:

var oracledb = require('oracledb');
oracledb.stmtCacheSize = 40;

The value can be overridden in an oracledb.getConnection() call:

var oracledb = require('oracledb');

oracledb.getConnection(
  {
    user          : "hr",
    password      : "welcome",
    connectString : "localhost/XE",
    stmtCacheSize : 40
  },
  function(err, connection) {
    . . .
  });

The value can also be overridden in the poolAttrs parameter to the createPool() method.

With Oracle Database 12c, the statement cache size can be automatically tuned with the External Configuration oraaccess.xml file.

To manually tune the statement cache size, monitor general application load and the AWR "bytes sent via SQL*Net to client" values. The latter statistic should benefit from not shipping statement metadata to node-oracledb. Adjust the statement cache size to your satisfaction.

19. External Configuration

The optional Oracle client-side configuration file oraaccess.xml can be used to configure some behaviors of node-oracledb. See Optional Client Configuration Files for information about file creation..

An oraaccess.xml file is only used when node-oracledb is linked with Oracle Database 12c client libraries.

The following oraaccess.xml file sets the Oracle client 'prefetch' value to 100 rows. This value affects every SQL query in the application:

<?xml version="1.0"?>
 <oraaccess xmlns="http://xmlns.oracle.com/oci/oraaccess"
  xmlns:oci="http://xmlns.oracle.com/oci/oraaccess"
  schemaLocation="http://xmlns.oracle.com/oci/oraaccess
  http://xmlns.oracle.com/oci/oraaccess.xsd">
  <default_parameters>
    <prefetch>
      <rows>100</rows>
    </prefetch>
  </default_parameters>
</oraaccess>

Prefetching is the number of additional rows the underlying Oracle client library fetches whenever node-oracledb requests query data from the database. Prefetching is a tuning option to maximize data transfer efficiency and minimize round-trips to the database. The prefetch size does not affect when, or how many, rows are returned by node-oracledb to the application. The cache management is transparently handled by the Oracle client libraries. Note, standard node-oracledb fetch tuning is via fetchArraySize, but changing the prefetch value can be useful in some cases such as when modifying the application is not feasible.

The oraaccess.xml file has other uses including:

Refer to the oraaccess.xml documentation.

20. Globalization and National Language Support (NLS)

Node-oracledb can use Oracle's National Language Support (NLS) to assist in globalizing applications.

Node-oracledb always uses Oracle's AL32UTF8 character set internally. Data will be converted between AL32UTF8 and the database character set when it is inserted into, or queried from, the database. The environment variable NLS_LANG can be used to configure the Oracle client language and territory only.

Oracle NLS environment variables, or statements like ALTER SESSION, can be used to configure further aspects of node-oracledb data access globalization. Examples are NLS_NUMERIC_CHARACTERS (discussed in Fetching Numbers), and NLS_DATE_FORMAT (discussed in Fetching Numbers and Dates as String). Refer to NLS Documentation for others.

21. End-to-end Tracing, Mid-tier Authentication, and Auditing

The Connection properties action, module, and clientId set metadata for end-to-end tracing. The values can be tracked in database views, shown in audit trails, and seen in tools such as Enterprise Manager.

The clientId property can also be used by applications that do their own mid-tier authentication but connect to the database using the one database schema. By setting clientId to the application's authenticated user name, the database is aware of who the actual end user is. This can, for example, be used by Oracle Virtual Private Database policies to automatically restrict data access by that user.

Applications should set the properties because they can greatly help to identify and resolve unnecessary database resource usage, or improper access.

The attributes are set on a connection object and sent to the database on the next round-trip from node-oracledb, for example, with execute():

oracledb.getConnection(
  {
    user          : "hr",
    password      : "welcome",
    connectString : "localhost/orclpdb"
  },
  function(err, connection) {
    if (err) { console.error(err.message); return;    }

    connection.clientId = "Chris";
    connection.module = "End-to-end example";
    connection.action = "Query departments";

    connection.execute("SELECT . . .",
      function(err, result) {
        . . .

While the connection is open the attribute values can be seen, for example with SQL*Plus:

SQL> SELECT username, client_identifier, action, module FROM v$session WHERE username = 'HR';

USERNAME   CLIENT_IDENTIFIER    ACTION               MODULE
---------- -------------------- -------------------- --------------------
HR         Chris                Query departments    End-to-end example

The values can also be manually set by calling DBMS_APPLICATION_INFO procedures or DBMS_SESSION.SET_IDENTIFIER, however these cause explicit round-trips, reducing scalability.

In general, applications should be consistent about how, and when, they set the end-to-end tracing attributes so that current values are recorded by the database.

Idle connections released back to a connection pool will retain the previous attribute values of that connection. This avoids the overhead of a round-trip to reset the values. The Oracle design assumption is that pools are actively used and have few idle connections. After getting a connection from a pool, an application that uses end-to-end tracing should set new values appropriately.

When a Connection object is displayed, such as with console.log(), the end-to-end tracing attributes will show as null even if values have been set and are being sent to the database. This is for architectural, efficiency and consistency reasons. When an already established connection is retrieved from a local pool, node-oracledb is not able to efficiently retrieve values previously established in the connection. The same occurs if the values are set by a call to PL/SQL code - there is no efficient way for node-oracledb to know the values have changed.

The attribute values are commonly useful to DBAs. However, if knowing the current values is useful in an application, the application should save the values as part of its application state whenever the node-oracledb attributes are set. Applications can also find the current values by querying the Oracle data dictionary or using PL/SQL procedures such as DBMS_APPLICATION_INFO.READ_MODULE() with the understanding that these require round-trips to the database.

The Add-on Name

The Oracle Database V$SESSION_CONNECT_INFO view shows the version of node-oracledb in use. This allows DBAs to verify that applications are using the desired add-on version. For example, a DBA might see:

SQL> SELECT UNIQUE sid, client_driver
     FROM v$session_connect_info
     WHERE client_driver LIKE 'node-oracledb%'
     ORDER BY sid;

       SID CLIENT_DRIVER
---------- ------------------------------
        16 node-oracledb : 2.2.0
        33 node-oracledb : 2.2.0

Note if oracledb.connectionClass is set for a non-pooled connection, the CLIENT_DRIVER value will not be set for that connection.

22. Promises and node-oracledb

Node-oracledb supports Promises with all asynchronous methods. The native Promise implementation is used.

If an asynchronous method is invoked without a callback, it returns a Promise:

var oracledb = require('oracledb');

oracledb.getConnection(
  {
    user          : "hr",
    password      : "welcome",
    connectString : "localhost/XE"
  })
  .then(function(conn) {
    return conn.execute(
      `SELECT department_id, department_name
       FROM departments
       WHERE manager_id < :id`,
      [110]  // bind value for :id
    )
      .then(function(result) {
        console.log(result.rows);
        return conn.close();
      })
      .catch(function(err) {
        console.error(err);
        return conn.close();
      });
  })
  .catch(function(err) {
    console.error(err);
  });

With Oracle's sample HR schema, the output is:

[ [ 60, 'IT' ], [ 90, 'Executive' ], [ 100, 'Finance' ] ]

Notice there are two promise "chains": one to get a connection and the other to use it. This is required because it is only possible to refer to the connection within the function to which it was passed.

When invoking asynchronous methods, it is possible to accidentally get a Promise by forgetting to pass a callback function:

oracledb.getConnection(
  {
    user          : "hr",
    password      : "welcome",
    connectString : "localhost/WRONG_SERVICE_NAME"
  });
  . . .

Since the returned promise will not have a catch block, as the developer intended to use the callback programming style, any rejections that occur will go unnoticed. Node.js 4.0 added the unhandledRejection event to prevent such rejections from going unnoticed:

process.on('unhandledRejection', (reason, p) => {
  console.error("Unhandled Rejection at: ", p, " reason: ", reason);
  // application specific logging, throwing an error, or other logic here
});

oracledb.getConnection(
  {
    user          : "hr",
    password      : "welcome",
    connectString : "localhost/WRONG_SERVICE_NAME"
  });
  . . .

Whereas the code without the unhandledRejection exception silently exited, adding the handler could, for example, show:

$ node myapp.js
Unhandled Rejection at:  Promise {
  <rejected> [Error: ORA-12514: TNS:listener does not currently know of service requested in connect descriptor
] }  reason:  [Error: ORA-12514: TNS:listener does not currently know of service requested in connect descriptor
]

For more information, see How to get, use, and close a DB connection using promises.

22.1 Custom Promise Libraries

The Promise implementation is designed to be overridden, allowing a custom Promise library to be used.

var mylib = require('myfavpromiseimplementation');
oracledb.Promise = mylib;

Promises can be completely disabled by setting

oracledb.Promise = null;

23. Async/Await and node-oracledb

Node.js 7.6 supports async functions, also known as Async/Await. These can be used with node-oracledb. For example:

const oracledb = require('oracledb');

function getEmployee(empid) {
  return new Promise(async function(resolve, reject) {
    let conn;

    try {
      conn = await oracledb.getConnection({
        user          : "hr",
        password      : "welcome",
        connectString : "localhost/XE"
      });

      let result = await conn.execute(
        'SELECT * FROM employees WHERE employee_id = :bv',
        [empid]
      );
      resolve(result.rows);

    } catch (err) { // catches errors in getConnection and the query
      reject(err);
    } finally {
      if (conn) {   // the conn assignment worked, must release
        try {
          await conn.release();
        } catch (e) {
          console.error(e);
        }
      }
    }
  });
}

async function run() {
  try {
    let res = await getEmployee(101);
    console.log(res);
  } catch (err) {
    console.error(err);
  }
}

run();

If you are using Lob instances for LOB data instead of working with the data directly as Strings or Buffers, then the Lobs must be streamed since there is no Promisified interface for them.

For more information, see How to get, use, and close a DB connection using async functions.

24. Tracing SQL and PL/SQL Statements

End-to-End Tracing

Applications that have implemented End-to-end Tracing calls such as action and module, will make it easier in database monitoring tools to identify SQL statement execution.

Tracing Executed Statements

Database statement tracing is commonly used to identify performance issues. Oracle Database trace files can be analyzed after statements are executed. Tracing can be enabled in various ways at a database system or individal session level. Refer to Oracle Database Tuning documentation. Setting a customer identifier is recommended to make searching for relevant log files easier:

ALTER SESSION SET tracefile_identifier='My-identifier' SQL_TRACE=TRUE

In node-oracledb itself, the ODPI-C tracing capability can be used to log executed statements to the standard error stream. Before executing Node.js, set the environment variable DPI_DEBUG_LEVEL to 16. At a Windows command prompt, this could be done with set DPI_DEBUG_LEVEL=16. On Linux, you might use:

export DPI_DEBUG_LEVEL=16
node myapp.js 2> log.txt

For an application that does a single query, the log file might contain a tracing line consisting of the prefix 'ODPI', a thread identifier, a timestamp, and the SQL statement executed:

ODPI [6905309] 2017-09-13 09:02:46.140: SQL select sysdate from dual where :b = 1

Tracing Bind Values

Sometimes it is useful to trace the bind data values that have been used when executing statements. Several methods are available.

In the Oracle Database, the view V$SQL_BIND_CAPTURE can capture bind information. Tracing with Oracle Database's dbms_monitor.session_trace_enable() may also be useful.

You can also write your own wrapper around execute() and log any parameters.

Other Tracing Utilities

PL/SQL users may be interested in using PL/Scope.

25. Migrating from Previous node-oracledb Releases

25.1 Migrating from node-oracledb 1.13 to node-oracledb 2.0

When upgrading from node-oracledb version 1.13 to version 2.0:

  • Review the CHANGELOG.

  • Installation has changed. Pre-built binaries are available for common platforms. To build from source code, change your package.json dependency to install from GitHub. Refer to INSTALL.

  • Users of Instant Client RPMs must now always have the Instant Client libraries in the library search path. Refer to INSTALL.

  • Users of macOS must now always have the Instant Client libraries in ~/lib or /usr/local/lib. Refer to INSTALL.

  • For queries and REF CURSORS, the internal buffer sizing and tuning of round-trips to Oracle Database is now done with fetchArraySize. This replaces prefetchRows, which is no longer used. It also replaces the overloaded use of maxRows for queryStream(). To upgrade scripts:

    • Replace the property prefetchRows with fetchArraySize and make sure all values are greater than 0.

    • Tune fetchArraySize instead of maxRows for queryStream().

    • For direct fetches, optionally tune fetchArraySize.

    • For direct fetches, optionally replace enormously over-sized maxRows values with 0, meaning an unlimited number of rows can be returned.

  • For direct fetches that relied on the version 1 default value of maxRows to limit the number of returned rows to 100, it is recommended to use an OFFSET / FETCH query clause. Alternatively explicitly set maxRows to 100.

  • Review and update code that checks for specific NJS-XXX or DPI-XXX error messages.

  • Ensure that all ResultSets and LOBs are closed prior to calling connection.close(). Otherwise you will get the error DPI-1054: connection cannot be closed when open statements or LOBs exist. (Note: this limitation was removed in node-oracledb 2.1)

  • Test applications to check if changes such as the improved property validation uncover latent problems in your code.

25.2 Migrating from node-oracledb 2.0 to node-oracledb 2.1

When upgrading from node-oracledb version 2.0 to version 2.1:

  • If using the experimental _close method with Query Streaming in Node 8 or later:

    • Change the method name from _close() to destroy().
    • Stop passing a callback.
    • Optionally pass an error.