This library is not maintained. Oracle has made there own driver.
A driver to connect to an Oracle database from node.js, leveraging the "Oracle C++ Call Interface" (OCCI) for connectivity. This is most commonly obtained as part of the Oracle Instant Client.
It is known to work with Oracle 10, 11, and 12, and has been mostly tested on Linux, but should also work on OS X and Windows 7+
(See INSTALL.md for complete instructions for your platform.)
Prerequisites:
- Python 2.7 (not v3.x), used by node-gyp
- C++ Compiler toolchain (GCC, Visual Studio or similar)
Download the latest Oracle Instant Client Basic and SDK, and extract to the same directory.
Set environment variables:
OCI_LIB_DIR=/path/to/instant_client OCI_INCLUDE_DIR=/path/to/instant_client/sdk/include OCI_VERSION=<10, 11, or 12> # Integer. Optional, defaults to '11' NLS_LANG=.UTF8 # Optional, but required to support international characters ```
- Create symlinks for libclntsh and libocci in the Instant Client directory (see INSTALL.md)
- (Linux) Install libaio
- Configure the dynamic library path on your platform to include $OCI_LIB_DIR (see INSTALL.md)
npm install oracleto get the latest from npmjs.org
varoracle=require('oracle');varconnectData={hostname: "localhost",port: 1521,database: "xe",// System ID (SID)user: "oracle",password: "oracle"}oracle.connect(connectData,function(err,connection){if(err){console.log("Error connecting to db:",err);return;}connection.execute("SELECT systimestamp FROM dual",[],function(err,results){if(err){console.log("Error executing query:",err);return;}console.log(results);connection.close();// call only when query is finished executing});});Replace the connectData object above with one of the following.
Without tnsnames.ora file:
varconnString="(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=localhost)(PORT=1521))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=xe)))";varconnectData={"tns": connString,"user": "test","password": "test"};With tnsnames.ora file:
DEV =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = localhost)(PORT = 1521))
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = orcl)
)
)
varconnectData={"tns": "DEV","user": "test","password": "test"};The following options can be set on the connection:
connection.setAutoCommit(true/false);connection.setPrefetchRowCount(count);Should improve performance with large result sets
Following the basic example above, a query using a return parameter looks like this:
...
connection.execute("INSERT INTO person (name) VALUES (:1) RETURNING id INTO :2",['joe ferner',neworacle.OutParam()],function(err,results){if(err){ ... }// results.updateCount = 1// results.returnParam = the id of the person just insertedconnection.close();});
...The following OUT Params are supported in Stored Procedures:
OCCIINTOCCISTRINGOCCIDOUBLEOCCIFLOATOCCICURSOROCCICLOBOCCIDATEOCCITIMESTAMPOCCINUMBEROCCIBLOB
Specify the return type in the OutParam() constructor:
connection.execute("call myProc(:1,:2)",["nodejs",neworacle.OutParam(oracle.OCCISTRING)], ...When using OCCISTRING, the size can optionally be specified (default is 200 chars):
connection.execute("call myProc(:1,:2)",["nodejs",neworacle.OutParam(oracle.OCCISTRING,{size: 1000})], ...See tests for more examples.
The following INOUT param types are supported:
OCCIINTOCCISTRINGOCCIDOUBLEOCCIFLOATOCCINUMBER
INOUT params are used like normal OUT params, with the optional 'in' paramater value being passed in the options object:
connection.execute("call myProc(:1)",[neworacle.OutParam(oracle.OCCIINT,{in: 42})], ...To validate whether the connection is still established after some time:
if(!connection.isConnected()){// Do something like retire this connection from a pool}For DATE and TIMESTAMP types, the driver uses the UTC methods from the Javascript Date object. This means the DATE
value stored will match the value of new Date().toISOString() on your client machine. Consider this example
for a client machine in "GMT-0700":
Table schema:
CREATETABLEdate_test (mydate DATE)Javascript code:
...
vardate=newDate(2013,11,24,18,0,1);// Client timezone dependentconsole.log(date.toString());// Tue Dec 24 2013 18:00:01 GMT-0700 (MST)console.log(date.toISOString());// 2013-12-25T01:00:01.000Zconnection.execute("INSERT INTO date_test (mydate) VALUES (:1) "+"RETURNING mydate, to_char(mydate, 'YYYY-MM-DD HH24:MI:SS') INTO :2, :3",[date,neworacle.OutParam(oracle.OCCIDATE),neworacle.OutParam(oracle.OCCISTRING)],function(err,results){console.log(results.returnParam.toString());// Tue Dec 24 2013 18:00:01 GMT-0700 (MST)console.log(results.returnParam1);// 2013-12-25 01:00:01});
...To query large tables you should use a reader:
reader = connection.reader(sql, args): creates a readerreader.nextRow(callback): returns the next row through the callbackreader.nextRows(count, callback)returns the nextcountrows through the callback.countis optional andnextRowsuses the prefetch row count whencountis omitted. Also, you much check forrow.lengthsince the reader will continue returning empty arrays once it exceeds the end of the data set provided by the query.connection.setPrefetchRowCount(count): configures the prefetch row count for the connection. Prefetching can have a dramatic impact on performance but uses more memory.
Example:
connection.setPrefetchRowCount(50);varreader=connection.reader("SELECT * FROM auditlogs",[]);functiondoRead(cb){reader.nextRow(function(err,row){if(err)returncb(err);if(row){// do something with rowconsole.log("got "+JSON.stringify(row));// recurse to read next recordreturndoRead(cb)}else{// we are donereturncb();}})}doRead(function(err){if(err)throwerr;// or log itconsole.log("all records processed");});To insert or update a large number of records you should use prepared statements rather than individual execute calls on the connection object:
statement = connection.prepare(sql): creates a prepared statement.statement.execute(args, callback): executes the prepared statement with the values inargs. You can call this repeatedly on the samestatement.
Example:
functiondoInsert(stmt,records,cb){if(records.length>0){stmt.execute([records.shift()],function(err,count){if(err)returncb(err);if(count!==1)returncb(newError("bad count: "+count));// recurse with remaining recordsdoInsert(stmt,records,cb);});}else{// we are donereturncb();}}varstatement=connection.prepare("INSERT INTO users (id, firstName, lastName) VALUES (:1, :2, :3)");doInsert(statement,users,function(err){if(err)throwerr;// or log itconsole.log("all records inserted");});- Ensure you always close your connection at the end of use to avoid random false oracle errors.
- Currently no native support for connection pooling (forthcoming; use generic-pool for now.)
- Currently no support for column type "Timestamp With Timezone" (Issue #67)
- While the Oracle TIMESTAMP type provides fractional seconds up to 9 digits (nanoseconds), this will be rounded to the nearest millisecond when converted to a Javascript date (a data loss).
- Clone the source repo
- Follow the installation instructions to prepare your environment (using Oracle Instant Client)
- Run
npm installornpm testin the root of the source directory - Point to an Oracle instance of your choice. The free Oracle Express edition works well:
- Debugging:
- Compile node with debug symbols
- Use gdb/ddd or another C++ debugger to step through