From 2439029bef3bdf8866e95507ab972b70a6180aff Mon Sep 17 00:00:00 2001 From: Christopher Jones Date: Fri, 1 Feb 2019 16:01:43 +1100 Subject: [PATCH] Update node-oracledb examples for the latest 3.1 release --- javascript/node-oracledb/README.md | 22 +- javascript/node-oracledb/calltimeout.js | 6 +- javascript/node-oracledb/connect.js | 2 + javascript/node-oracledb/connectionpool.js | 118 +++++++++ javascript/node-oracledb/cqn1.js | 4 +- javascript/node-oracledb/cqn2.js | 4 +- javascript/node-oracledb/date.js | 38 +-- javascript/node-oracledb/dbconfig.js | 6 +- javascript/node-oracledb/em_batcherrors.js | 4 +- javascript/node-oracledb/em_batcherrors_aa.js | 4 +- javascript/node-oracledb/em_dmlreturn1.js | 4 +- javascript/node-oracledb/em_dmlreturn1_aa.js | 4 +- javascript/node-oracledb/em_dmlreturn2.js | 4 +- javascript/node-oracledb/em_dmlreturn2_aa.js | 4 +- javascript/node-oracledb/em_insert1.js | 4 +- javascript/node-oracledb/em_insert1_aa.js | 4 +- javascript/node-oracledb/em_insert2.js | 4 +- javascript/node-oracledb/em_insert2_aa.js | 4 +- javascript/node-oracledb/em_plsql.js | 4 +- javascript/node-oracledb/em_plsql_aa.js | 4 +- javascript/node-oracledb/em_rowcounts.js | 4 +- javascript/node-oracledb/em_rowcounts_aa.js | 4 +- javascript/node-oracledb/example.js | 16 +- javascript/node-oracledb/insert2.js | 3 +- javascript/node-oracledb/lobbinds.js | 6 +- javascript/node-oracledb/lobinsert1.js | 4 +- javascript/node-oracledb/lobinsert2.js | 4 +- javascript/node-oracledb/lobinserttemp.js | 4 +- javascript/node-oracledb/lobplsqltemp.js | 4 +- javascript/node-oracledb/lobselect.js | 4 +- javascript/node-oracledb/lobstream1.js | 2 + javascript/node-oracledb/lobstream2.js | 4 +- javascript/node-oracledb/metadata.js | 4 +- javascript/node-oracledb/plsqlarray.js | 4 +- javascript/node-oracledb/raw1.js | 4 +- .../node-oracledb/refcursortoquerystream.js | 4 +- javascript/node-oracledb/resultset1.js | 4 +- .../node-oracledb/resultsettoquerystream.js | 2 +- javascript/node-oracledb/select1.js | 2 +- javascript/node-oracledb/selectjsonblob.js | 4 +- javascript/node-oracledb/selectstream.js | 4 +- javascript/node-oracledb/sessionfixup.js | 130 ++++++++++ javascript/node-oracledb/sessiontagging1.js | 170 +++++++++++++ javascript/node-oracledb/sessiontagging2.js | 227 ++++++++++++++++++ javascript/node-oracledb/soda1.js | 4 +- javascript/node-oracledb/version.js | 4 +- javascript/node-oracledb/webapp.js | 32 ++- javascript/node-oracledb/webappawait.js | 30 ++- javascript/node-oracledb/webapppromises.js | 32 ++- 49 files changed, 853 insertions(+), 115 deletions(-) create mode 100644 javascript/node-oracledb/connectionpool.js create mode 100644 javascript/node-oracledb/sessionfixup.js create mode 100644 javascript/node-oracledb/sessiontagging1.js create mode 100644 javascript/node-oracledb/sessiontagging2.js diff --git a/javascript/node-oracledb/README.md b/javascript/node-oracledb/README.md index b106667f..ac865dd2 100644 --- a/javascript/node-oracledb/README.md +++ b/javascript/node-oracledb/README.md @@ -1,6 +1,6 @@ # Node-oracledb Examples -This directory contains [node-oracledb 3.0](https://www.npmjs.com/package/oracledb) examples. +This directory contains [node-oracledb 3.1](https://www.npmjs.com/package/oracledb) examples. The node-oracledb add-on for Node.js powers high performance Oracle Database applications. @@ -11,7 +11,7 @@ The node-oracledb add-on for Node.js powers high performance Oracle Database app Issues and questions about node-oracledb can be posted on [GitHub](https://github.com/oracle/node-oracledb/issues) or [Slack](https://node-oracledb.slack.com/) ([link to join -Slack](https://join.slack.com/t/node-oracledb/shared_invite/enQtNDI4NTUyNjMzMDA5LWRiZWRkZjQ3NjBhNDUwOGJlNDFiZWJhZTIzYTJkMWQ5N2UwNTg5NzNmNmY1YmZjZGYxNmRhOTkyOTlhMmViNjY)). +Slack](https://node-oracledb.slack.com/join/shared_invite/enQtNDU4Mjc2NzM5OTA2LTdkMzczODY3OGY3MGI0Yjk3NmQ4NDU4MTI2OGVjNTYzMjE5OGY5YzVkNDY4MWNkNjFiMDM2ZDMwOWRjNWVhNTg). To run the examples: @@ -22,19 +22,31 @@ To run the examples: example, to load them in the HR schema run: ``` - sqlplus hr/welcome@localhost/orclpdb @demo.sql + sqlplus hr + SQL> @demo.sql ``` -- Edit `dbconfig.js` and set your username, password and the database +- Edit `dbconfig.js` and set your username and the database connection string: ``` module.exports = { user: "hr", - password: "welcome", + password: process.env.NODE_ORACLEDB_PASSWORD, connectString:"localhost/orclpdb" }; + ``` + +- Set the environment variable `NODE_ORACLEDB_PASSWORD` to your database schema password. + + On Windows: + ``` + set NODE_ORACLEDB_PASSWORD=... + ``` + On Linux: + ``` + export NODE_ORACLEDB_PASSWORD=... ``` - Then run the samples like: diff --git a/javascript/node-oracledb/calltimeout.js b/javascript/node-oracledb/calltimeout.js index 0e359312..33a14089 100755 --- a/javascript/node-oracledb/calltimeout.js +++ b/javascript/node-oracledb/calltimeout.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -21,10 +21,12 @@ * DESCRIPTION * Shows how to time out long running database calls. * See https://oracle.github.io/node-oracledb/doc/api.html#dbcalltimeouts - * Node-oracledb must be using Oracle Client 18c libraries, or greater. * * This example uses Async/Await of Node 8. * + * This example requires node-oracledb 3 or later. + * Node-oracledb must be using Oracle Client 18c libraries, or greater. + * *****************************************************************************/ let oracledb = require("oracledb"); diff --git a/javascript/node-oracledb/connect.js b/javascript/node-oracledb/connect.js index a1afd51b..1a4e391c 100644 --- a/javascript/node-oracledb/connect.js +++ b/javascript/node-oracledb/connect.js @@ -22,6 +22,8 @@ * Tests a basic connection to the database. * See dbconfig.js for information on connectString formats. * + * For a connection pool example see connectionpool.js + * *****************************************************************************/ var oracledb = require('oracledb'); diff --git a/javascript/node-oracledb/connectionpool.js b/javascript/node-oracledb/connectionpool.js new file mode 100644 index 00000000..83c5b4a0 --- /dev/null +++ b/javascript/node-oracledb/connectionpool.js @@ -0,0 +1,118 @@ +/* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with the Apache + * License, Version 2.0 (the "License.") + * + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + * NAME + * connectionpool.js + * + * DESCRIPTION + * Shows connection pool usage. Connection pools are recommended + * for applications that use a lot of connections for short periods. + * + * This example uses Node 8's async/await syntax. + * + * Other connection pool examples are in sessionfixup.js, webapp.js, + * webapppromises.js and webappawait.js + * + * For a standalone connection example, see connect.js + * + * In some networks forced pool termination may hang unless you have + * 'disable_oob=on' in sqlnet.ora, see + * https://oracle.github.io/node-oracledb/doc/api.html#tnsadmin + * + *****************************************************************************/ + +const oracledb = require('oracledb'); +const dbConfig = require('./dbconfig.js'); + +async function init() { + try { + // Create a connection pool which will later be accessed via the + // pool cache as the 'default' pool. + await oracledb.createPool({ + user: dbConfig.user, + password: dbConfig.password, + connectString: dbConfig.connectString + // edition: 'ORA$BASE', // used for Edition Based Redefintion + // events: false, // whether to handle Oracle Database FAN and RLB events or support CQN + // externalAuth: false, // whether connections should be established using External Authentication + // homogeneous: true, // all connections in the pool have the same credentials + // poolAlias: 'default', // set an alias to allow access to the pool via a name. + // poolIncrement: 1, // only grow the pool by one connection at a time + // poolMax: 4, // maximum size of the pool. Increase UV_THREADPOOL_SIZE if you increase poolMax + // poolMin: 0, // start with no connections; let the pool shrink completely + // poolPingInterval: 60, // check aliveness of connection if idle in the pool for 60 seconds + // poolTimeout: 60, // terminate connections that are idle in the pool for 60 seconds + // queueTimeout: 60000, // terminate getConnection() calls in the queue longer than 60000 milliseconds + // sessionCallback: myFunction, // function invoked for brand new connections or by a connection tag mismatch + // stmtCacheSize: 30 // number of statements that are cached in the statement cache of each connection + }); + console.log('Connection pool started'); + + // Now the pool is running, it can be used + await dostuff(); + + } catch (err) { + console.error('init() error: ' + err.message); + } finally { + await closePoolAndExit(); + } +} + +async function dostuff() { + let connection; + try { + // Get a connection from the default pool + connection = await oracledb.getConnection(); + let sql = `SELECT sysdate FROM dual WHERE :b = 1`; + let binds = [1]; + let options = { outFormat: oracledb.OBJECT }; + let result = await connection.execute(sql, binds, options); + console.log(result); + } catch (err) { + console.error(err); + } finally { + if (connection) { + try { + // Put the connection back in the pool + await connection.close(); + } catch (err) { + console.error(err); + } + } + } +} + +async function closePoolAndExit() { + console.log('\nTerminating'); + try { + // Get the pool from the pool cache and close it when no + // connections are in use, or force it closed after 10 seconds + // If this hangs, you may need DISABLE_OOB=ON in a sqlnet.ora file + await oracledb.getPool().close(10); + console.log('Pool closed'); + process.exit(0); + } catch(err) { + console.error(err.message); + process.exit(1); + } +} + +process + .once('SIGTERM', closePoolAndExit) + .once('SIGINT', closePoolAndExit); + +init(); diff --git a/javascript/node-oracledb/cqn1.js b/javascript/node-oracledb/cqn1.js index 6beffd5a..e1b05c3d 100644 --- a/javascript/node-oracledb/cqn1.js +++ b/javascript/node-oracledb/cqn1.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -27,6 +27,8 @@ * * This example uses Node 8 syntax, but could be written to use callbacks. * + * This example requires node-oracledb 2.3 or later. + * *****************************************************************************/ const oracledb = require("oracledb"); diff --git a/javascript/node-oracledb/cqn2.js b/javascript/node-oracledb/cqn2.js index cd49b2bb..8a3a56c6 100644 --- a/javascript/node-oracledb/cqn2.js +++ b/javascript/node-oracledb/cqn2.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -28,6 +28,8 @@ * * This example uses Node 8 syntax, but could be written to use callbacks. * + * This example requires node-oracledb 2.3 or later. + * *****************************************************************************/ const oracledb = require("oracledb"); diff --git a/javascript/node-oracledb/date.js b/javascript/node-oracledb/date.js index 3dac1e51..7e10bed1 100644 --- a/javascript/node-oracledb/date.js +++ b/javascript/node-oracledb/date.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -27,10 +27,15 @@ * *****************************************************************************/// +// Using a fixed Oracle time zone helps avoid machine and deployment differences +process.env.ORA_SDTZ = 'UTC'; + var async = require('async'); var oracledb = require('oracledb'); var dbConfig = require('./dbconfig.js'); +oracledb.outFormat = oracledb.OBJECT; + var doconnect = function(cb) { oracledb.getConnection( { @@ -68,18 +73,20 @@ var docleanup = function (conn, cb) { var docreate = function(conn, cb) { conn.execute( - "CREATE TABLE datetest(timestampcol TIMESTAMP, datecol DATE)", + `CREATE TABLE datetest( + timestampcol TIMESTAMP, + timestamptz TIMESTAMP WITH TIME ZONE, + timestampltz TIMESTAMP WITH LOCAL TIME ZONE, + datecol DATE)`, function(err) { return cb(err, conn); }); }; -// Setting a local timezone in applications is recommended. -// Note setting the environment variable ORA_SDTZ is an efficient alternative. var doalter = function(conn, cb) { console.log('Altering session time zone'); conn.execute( - "ALTER SESSION SET TIME_ZONE='UTC'", + "ALTER SESSION SET TIME_ZONE='+5:00'", // resets ORA_SDTZ value function(err) { return cb(err, conn); }); @@ -92,9 +99,9 @@ var doinsert = function(conn, cb) { console.log("Inserting JavaScript date: " + date); conn.execute( - "INSERT INTO datetest (timestampcol, datecol) VALUES (:ts, :td)", - { ts: date, - td: date }, + `INSERT INTO datetest (timestampcol, timestamptz, timestampltz, datecol) + VALUES (:ts, :tstz, :tsltz, :td)`, + { ts: date, tstz: date, tsltz: date, td: date }, function(err, result) { if (err) return cb(err, conn); @@ -108,24 +115,21 @@ var doinsert = function(conn, cb) { // Fetch the dates var doselect = function(conn, cb) { conn.execute( - "SELECT timestampcol, datecol FROM datetest", + `SELECT timestampcol, timestamptz, timestampltz, datecol, + TO_CHAR(CURRENT_DATE, 'DD-Mon-YYYY HH24:MI') AS CD + FROM datetest`, function(err, result) { if (err) { return cb(err, conn); } console.log("Query Results:"); - console.log(result.rows); + console.log(result.rows[0]); // Show the queried dates are of type Date - console.log("Result Manipulation in JavaScript:"); - var ts = result.rows[0][0]; + var ts = result.rows[0]['TIMESTAMPCOL']; ts.setDate(ts.getDate() + 5); - console.log(ts); - - var d = result.rows[0][1]; - d.setDate(d.getDate() - 5); - console.log(d); + console.log("TIMESTAMP manipulation in JavaScript:", ts); return cb(null, conn); }); diff --git a/javascript/node-oracledb/dbconfig.js b/javascript/node-oracledb/dbconfig.js index b3f155c9..7397f496 100644 --- a/javascript/node-oracledb/dbconfig.js +++ b/javascript/node-oracledb/dbconfig.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -36,7 +36,7 @@ * [//]host_name[:port][/service_name][:server_type][/instance_name] * * Commonly just the host_name and service_name are needed - * e.g. "localhost/orclpdb" or "localhost/XE" + * e.g. "localhost/orclpdb" or "localhost/XEPDB1" * * If using a tnsnames.ora file, the file can be in a default * location such as $ORACLE_HOME/network/admin/tnsnames.ora or @@ -74,7 +74,7 @@ module.exports = { // Instead of hard coding the password, consider prompting for it, // passing it in an environment variable via process.env, or using // External Authentication. - password : process.env.NODE_ORACLEDB_PASSWORD || "welcome", + password : process.env.NODE_ORACLEDB_PASSWORD, // For information on connection strings see: // https://oracle.github.io/node-oracledb/doc/api.html#connectionstrings diff --git a/javascript/node-oracledb/em_batcherrors.js b/javascript/node-oracledb/em_batcherrors.js index 1a1ec150..c77fa11d 100644 --- a/javascript/node-oracledb/em_batcherrors.js +++ b/javascript/node-oracledb/em_batcherrors.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -25,6 +25,8 @@ * desired. * Use demo.sql to create the required schema. * + * This example requires node-oracledb 2.2 or later. + * *****************************************************************************/ var async = require('async'); diff --git a/javascript/node-oracledb/em_batcherrors_aa.js b/javascript/node-oracledb/em_batcherrors_aa.js index 168915e8..0e459c58 100644 --- a/javascript/node-oracledb/em_batcherrors_aa.js +++ b/javascript/node-oracledb/em_batcherrors_aa.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -26,6 +26,8 @@ * This example also uses Async/Await of Node 8. * Use demo.sql to create the required schema. * + * This example requires node-oracledb 2.2 or later. + * *****************************************************************************/ var oracledb = require('oracledb'); diff --git a/javascript/node-oracledb/em_dmlreturn1.js b/javascript/node-oracledb/em_dmlreturn1.js index e58f8fb2..71afa59a 100644 --- a/javascript/node-oracledb/em_dmlreturn1.js +++ b/javascript/node-oracledb/em_dmlreturn1.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -22,6 +22,8 @@ * executeMany() example of DML RETURNING that returns single values * Use demo.sql to create the required schema. * + * This example requires node-oracledb 2.2 or later. + * *****************************************************************************/ var async = require('async'); diff --git a/javascript/node-oracledb/em_dmlreturn1_aa.js b/javascript/node-oracledb/em_dmlreturn1_aa.js index c320e9cf..ab4115d4 100644 --- a/javascript/node-oracledb/em_dmlreturn1_aa.js +++ b/javascript/node-oracledb/em_dmlreturn1_aa.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -23,6 +23,8 @@ * This example also uses Async/Await of Node 8. * Use demo.sql to create the required schema. * + * This example requires node-oracledb 2.2 or later. + * *****************************************************************************/ var oracledb = require('oracledb'); diff --git a/javascript/node-oracledb/em_dmlreturn2.js b/javascript/node-oracledb/em_dmlreturn2.js index 764b1ff1..ed1c4762 100644 --- a/javascript/node-oracledb/em_dmlreturn2.js +++ b/javascript/node-oracledb/em_dmlreturn2.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -22,6 +22,8 @@ * executeMany() example of DML RETURNING that returns multiple values * Use demo.sql to create the required schema. * + * This example requires node-oracledb 2.2 or later. + * *****************************************************************************/ var async = require('async'); diff --git a/javascript/node-oracledb/em_dmlreturn2_aa.js b/javascript/node-oracledb/em_dmlreturn2_aa.js index 6d992bf0..8e47a489 100644 --- a/javascript/node-oracledb/em_dmlreturn2_aa.js +++ b/javascript/node-oracledb/em_dmlreturn2_aa.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -23,6 +23,8 @@ * This example also uses Async/Await of Node 8. * Use demo.sql to create the required schema. * + * This example requires node-oracledb 2.2 or later. + * *****************************************************************************/ var oracledb = require('oracledb'); diff --git a/javascript/node-oracledb/em_insert1.js b/javascript/node-oracledb/em_insert1.js index b4d20c89..3439534d 100644 --- a/javascript/node-oracledb/em_insert1.js +++ b/javascript/node-oracledb/em_insert1.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -22,6 +22,8 @@ * Array DML example using executeMany() with bind-by-name syntax. * Use demo.sql to create the required schema. * + * This example requires node-oracledb 2.2 or later. + * *****************************************************************************/ var async = require('async'); diff --git a/javascript/node-oracledb/em_insert1_aa.js b/javascript/node-oracledb/em_insert1_aa.js index c869c5a8..82283656 100644 --- a/javascript/node-oracledb/em_insert1_aa.js +++ b/javascript/node-oracledb/em_insert1_aa.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -23,6 +23,8 @@ * This example also uses Async/Await of Node 8. * Use demo.sql to create the required schema. * + * This example requires node-oracledb 2.2 or later. + * *****************************************************************************/ var oracledb = require('oracledb'); diff --git a/javascript/node-oracledb/em_insert2.js b/javascript/node-oracledb/em_insert2.js index 06aab3c6..a8aaeb3b 100644 --- a/javascript/node-oracledb/em_insert2.js +++ b/javascript/node-oracledb/em_insert2.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -22,6 +22,8 @@ * Array DML example using executeMany() with bind-by-position syntax. * Use demo.sql to create the required schema. * + * This example requires node-oracledb 2.2 or later. + * *****************************************************************************/ var async = require('async'); diff --git a/javascript/node-oracledb/em_insert2_aa.js b/javascript/node-oracledb/em_insert2_aa.js index 253b4fd9..3d97dfe4 100644 --- a/javascript/node-oracledb/em_insert2_aa.js +++ b/javascript/node-oracledb/em_insert2_aa.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -23,6 +23,8 @@ * This example also uses Async/Await of Node 8. * Use demo.sql to create the required schema. * + * This example requires node-oracledb 2.2 or later. + * *****************************************************************************/ var oracledb = require('oracledb'); diff --git a/javascript/node-oracledb/em_plsql.js b/javascript/node-oracledb/em_plsql.js index c665ac40..7b67244e 100644 --- a/javascript/node-oracledb/em_plsql.js +++ b/javascript/node-oracledb/em_plsql.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -22,6 +22,8 @@ * executeMany() example calling PL/SQL. * Use demo.sql to create the required schema. * + * This example requires node-oracledb 2.2 or later. + * *****************************************************************************/ var async = require('async'); diff --git a/javascript/node-oracledb/em_plsql_aa.js b/javascript/node-oracledb/em_plsql_aa.js index f4181cb0..454eb1c6 100644 --- a/javascript/node-oracledb/em_plsql_aa.js +++ b/javascript/node-oracledb/em_plsql_aa.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -23,6 +23,8 @@ * This example also uses Async/Await of Node 8. * Use demo.sql to create the required schema. * + * This example requires node-oracledb 2.2 or later. + * *****************************************************************************/ var oracledb = require('oracledb'); diff --git a/javascript/node-oracledb/em_rowcounts.js b/javascript/node-oracledb/em_rowcounts.js index da65c9ad..7087c940 100644 --- a/javascript/node-oracledb/em_rowcounts.js +++ b/javascript/node-oracledb/em_rowcounts.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -24,6 +24,8 @@ * This example also uses Async/Await of Node 8. * Use demo.sql to create the required schema. * + * This example requires node-oracledb 2.2 or later. + * *****************************************************************************/ var async = require('async'); diff --git a/javascript/node-oracledb/em_rowcounts_aa.js b/javascript/node-oracledb/em_rowcounts_aa.js index 1e5c7c38..b4ed3bc8 100644 --- a/javascript/node-oracledb/em_rowcounts_aa.js +++ b/javascript/node-oracledb/em_rowcounts_aa.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -24,6 +24,8 @@ * This example also uses Async/Await of Node 8. * Use demo.sql to create the required schema. * + * This example requires node-oracledb 2.2 or later. + * *****************************************************************************/ var oracledb = require('oracledb'); diff --git a/javascript/node-oracledb/example.js b/javascript/node-oracledb/example.js index fc441255..8beff71e 100644 --- a/javascript/node-oracledb/example.js +++ b/javascript/node-oracledb/example.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -21,14 +21,19 @@ * DESCRIPTION * A basic node-oracledb example using Node.js 8's async/await syntax. * - * For a connection pool example see webapp.js + * For a connection pool example see connectionpool.js * For a ResultSet example see resultset2.js * For a query stream example see selectstream.js * For a Promise example see promises.js * For a callback example see select1.js * + * This example requires node-oracledb 2.2 or later. + * *****************************************************************************/ +// Using a fixed Oracle time zone helps avoid machine and deployment differences +process.env.ORA_SDTZ = 'UTC'; + var oracledb = require('oracledb'); var dbConfig = require('./dbconfig.js'); @@ -99,6 +104,13 @@ async function run() { console.log("Query results: "); console.log(result.rows); + // Show the date. The value of ORA_SDTZ affects the output + + sql = `SELECT TO_CHAR(CURRENT_DATE, 'DD-Mon-YYYY HH24:MI') AS CD FROM DUAL`; + result = await connection.execute(sql, binds, options); + console.log("Current date query results: "); + console.log(result.rows[0]['CD']); + } catch (err) { console.error(err); } finally { diff --git a/javascript/node-oracledb/insert2.js b/javascript/node-oracledb/insert2.js index 5d61572c..4b91eb5d 100644 --- a/javascript/node-oracledb/insert2.js +++ b/javascript/node-oracledb/insert2.js @@ -24,7 +24,8 @@ * By default, node-oracledb does not commit on execute. * The driver also has commit() and rollback() methods to explicitly control transactions. * - * Note: when a connection is closed, any open transaction will be rolled back. + * Note: regardless of the auto commit mode, any open transaction + * will be rolled back when a connection is closed. * *****************************************************************************/ diff --git a/javascript/node-oracledb/lobbinds.js b/javascript/node-oracledb/lobbinds.js index 4690073d..54fae07b 100644 --- a/javascript/node-oracledb/lobbinds.js +++ b/javascript/node-oracledb/lobbinds.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -29,7 +29,9 @@ * Use demo.sql to create the required tables and procedures * Run lobinsert1.js to load text before running this example * - * *****************************************************************************/ + * This example requires node-oracledb 1.13 or later. + * + ******************************************************************************/ var fs = require('fs'); var async = require('async'); diff --git a/javascript/node-oracledb/lobinsert1.js b/javascript/node-oracledb/lobinsert1.js index 788bb549..e74360de 100644 --- a/javascript/node-oracledb/lobinsert1.js +++ b/javascript/node-oracledb/lobinsert1.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -33,6 +33,8 @@ * DROP TABLE mylobs; * CREATE TABLE mylobs (id NUMBER, c CLOB, b BLOB); * + * This example requires node-oracledb 1.12 or later. + * *****************************************************************************/ var fs = require('fs'); diff --git a/javascript/node-oracledb/lobinsert2.js b/javascript/node-oracledb/lobinsert2.js index d08c4b54..2c21e116 100644 --- a/javascript/node-oracledb/lobinsert2.js +++ b/javascript/node-oracledb/lobinsert2.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -28,6 +28,8 @@ * DROP TABLE mylobs; * CREATE TABLE mylobs (id NUMBER, c CLOB, b BLOB); * + * This example requires node-oracledb 1.12 or later. + * *****************************************************************************/ var fs = require('fs'); diff --git a/javascript/node-oracledb/lobinserttemp.js b/javascript/node-oracledb/lobinserttemp.js index 8e2fcaca..c7736592 100644 --- a/javascript/node-oracledb/lobinserttemp.js +++ b/javascript/node-oracledb/lobinserttemp.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -28,6 +28,8 @@ * Create clobexample.txt before running this example. * Use demo.sql to create the required schema. * + * This example requires node-oracledb 1.12 or later. + * *****************************************************************************/ var fs = require('fs'); diff --git a/javascript/node-oracledb/lobplsqltemp.js b/javascript/node-oracledb/lobplsqltemp.js index ca449ebb..1df8ad9a 100644 --- a/javascript/node-oracledb/lobplsqltemp.js +++ b/javascript/node-oracledb/lobplsqltemp.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -28,6 +28,8 @@ * Create clobexample.txt before running this example. * Use demo.sql to create the required schema. * + * This example requires node-oracledb 1.12.1 or later. + * *****************************************************************************/ var fs = require('fs'); diff --git a/javascript/node-oracledb/lobselect.js b/javascript/node-oracledb/lobselect.js index 6b647bc8..c455e83f 100644 --- a/javascript/node-oracledb/lobselect.js +++ b/javascript/node-oracledb/lobselect.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, 2018 Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -30,6 +30,8 @@ * * Run lobinsert1.js to load data before running this example. * + * This example requires node-oracledb 1.13 or later. + * *****************************************************************************/ var fs = require('fs'); diff --git a/javascript/node-oracledb/lobstream1.js b/javascript/node-oracledb/lobstream1.js index 2bb02cd7..f87545ce 100644 --- a/javascript/node-oracledb/lobstream1.js +++ b/javascript/node-oracledb/lobstream1.js @@ -27,6 +27,8 @@ * * Run lobinsert1.js to load data before running this example. * + * This example requires node-oracledb 1.12 or later. + * *****************************************************************************/ var fs = require('fs'); diff --git a/javascript/node-oracledb/lobstream2.js b/javascript/node-oracledb/lobstream2.js index 10d2da46..490f9517 100644 --- a/javascript/node-oracledb/lobstream2.js +++ b/javascript/node-oracledb/lobstream2.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -27,6 +27,8 @@ * * Run lobinsert1.js to load data before running this example. * + * This example requires node-oracledb 1.12 or later. + * *****************************************************************************/ var async = require('async'); diff --git a/javascript/node-oracledb/metadata.js b/javascript/node-oracledb/metadata.js index 8e1be22d..c3c9de07 100644 --- a/javascript/node-oracledb/metadata.js +++ b/javascript/node-oracledb/metadata.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -25,6 +25,8 @@ * Scripts to create the HR schema can be found at: * https://github.com/oracle/db-sample-schemas * + * This example requires node-oracledb 1.10 or later. + * * *****************************************************************************/ var async = require('async'); diff --git a/javascript/node-oracledb/plsqlarray.js b/javascript/node-oracledb/plsqlarray.js index ac1ad642..2604e828 100644 --- a/javascript/node-oracledb/plsqlarray.js +++ b/javascript/node-oracledb/plsqlarray.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -27,6 +27,8 @@ * * Use demo.sql to create the required tables and package. * + * This example requires node-oracledb 1.6 or later. + * *****************************************************************************/ var async = require('async'); diff --git a/javascript/node-oracledb/raw1.js b/javascript/node-oracledb/raw1.js index 6d6817fb..9927f6e2 100644 --- a/javascript/node-oracledb/raw1.js +++ b/javascript/node-oracledb/raw1.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -25,6 +25,8 @@ * DROP TABLE myraw; * CREATE TABLE myraw (r RAW(64)); * + * This example requires node-oracledb 1.2 or later. + * *****************************************************************************/ var async = require('async'); diff --git a/javascript/node-oracledb/refcursortoquerystream.js b/javascript/node-oracledb/refcursortoquerystream.js index 474f9436..4ff1b7e7 100644 --- a/javascript/node-oracledb/refcursortoquerystream.js +++ b/javascript/node-oracledb/refcursortoquerystream.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -25,6 +25,8 @@ * Scripts to create the HR schema can be found at: * https://github.com/oracle/db-sample-schemas * + * This example requires node-oracledb 1.9 or later. + * *****************************************************************************/ var oracledb = require('oracledb'); diff --git a/javascript/node-oracledb/resultset1.js b/javascript/node-oracledb/resultset1.js index f030a134..ce20fc48 100644 --- a/javascript/node-oracledb/resultset1.js +++ b/javascript/node-oracledb/resultset1.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -25,6 +25,8 @@ * Note using queryStream() or getRows() is recommended instead of * getRow(). * + * This example requires node-oracledb 2.0.15 or later. + * *****************************************************************************/ var oracledb = require('oracledb'); diff --git a/javascript/node-oracledb/resultsettoquerystream.js b/javascript/node-oracledb/resultsettoquerystream.js index 63c123a7..d7b4b172 100644 --- a/javascript/node-oracledb/resultsettoquerystream.js +++ b/javascript/node-oracledb/resultsettoquerystream.js @@ -21,7 +21,7 @@ * DESCRIPTION * Converts a ResultSet returned from execute() into a Readable Stream. * This is an alternative instead of using resultset.getRows(). - * Note: using connnection.queryStream() is recommended for top level + * Note: using connection.queryStream() is recommended for top level * queries because it avoids having to duplicate error handling in the * callback and event. * diff --git a/javascript/node-oracledb/select1.js b/javascript/node-oracledb/select1.js index a2a13d37..bbead6f2 100644 --- a/javascript/node-oracledb/select1.js +++ b/javascript/node-oracledb/select1.js @@ -26,7 +26,7 @@ * https://github.com/oracle/db-sample-schemas * * For an async/await example see selectawait.js - * For a connection pool example see webapp.js + * For a connection pool example see connectionpool.js * For a ResultSet example see resultset2.js * For a query stream example see selectstream.js * For a Promise example see promises.js diff --git a/javascript/node-oracledb/selectjsonblob.js b/javascript/node-oracledb/selectjsonblob.js index 632f9a17..efbcbf2a 100644 --- a/javascript/node-oracledb/selectjsonblob.js +++ b/javascript/node-oracledb/selectjsonblob.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -25,6 +25,8 @@ * * Use demo.sql to create the required table. * + * This example requires node-oracledb 1.13 or later. + * *****************************************************************************/ var async = require('async'); diff --git a/javascript/node-oracledb/selectstream.js b/javascript/node-oracledb/selectstream.js index b8d79605..00feb23c 100644 --- a/javascript/node-oracledb/selectstream.js +++ b/javascript/node-oracledb/selectstream.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -25,6 +25,8 @@ * Scripts to create the HR schema can be found at: * https://github.com/oracle/db-sample-schemas * + * This example requires node-oracledb 1.8 or later. + * *****************************************************************************/ var oracledb = require('oracledb'); diff --git a/javascript/node-oracledb/sessionfixup.js b/javascript/node-oracledb/sessionfixup.js new file mode 100644 index 00000000..a9a553a7 --- /dev/null +++ b/javascript/node-oracledb/sessionfixup.js @@ -0,0 +1,130 @@ +/* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with the Apache + * License, Version 2.0 (the "License.") + * + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + * NAME + * sessionfixup.js + * + * DESCRIPTION + * Shows using a pooled connection callback function to efficiently + * set the "session state" of pooled connections to the same values + * when each connection is first used. + * + * Each connection in a connection pool can retain state (such as + * ALTER SESSION values) from when the connection was previously + * used. Using a sessionCallback function for a connection pool + * removes the overhead of unnecessarily re-executing ALTER SESSION + * commands after each pool.getConnection() call. + * + * Run this script and experiment sending web requests. For example + * send 20 requests with a concurrency of 4: + * ab -n 20 -c 4 http://127.0.0.1:7000/ + * The function initSession() will be called just once per connection + * in the pool. + * + * This file uses Node 8's async/await syntax but could be rewritten + * to use callbacks. + * + * This example requires node-oracledb 3.1 or later. + * + * Also see sessiontagging1.js and sessiontagging2.js + * + *****************************************************************************/ + +const http = require('http'); +const oracledb = require('oracledb'); +const dbConfig = require('./dbconfig.js'); +const httpPort = 7000; + +// initSession() will be invoked internally when each brand new pooled +// connection is first used. Its callback function 'cb' should be +// invoked only when all desired session state has been set. +// In this example, the requestedTag and actualTag parameters are +// ignored. They would be valid if connection tagging was being used. +// If you have multiple SQL statements to execute, put them in a +// single, anonymous PL/SQL block for efficiency. +function initSession(connection, requestedTag, cb) { + console.log('In initSession'); + connection.execute(`ALTER SESSION SET TIME_ZONE = 'UTC'`, cb); +} + +async function init() { + try { + await oracledb.createPool({ + user: dbConfig.user, + password: dbConfig.password, + connectString: dbConfig.connectString, + sessionCallback: initSession, + poolMin: 1, + poolMax: 4, + poolIncrement: 1 + }); + + // Create HTTP server and listen on port httpPort + const server = http.createServer(); + server.listen(httpPort) + .on('request', handleRequest) + .on('error', (err) => { + console.error('HTTP server problem: ' + err); + }) + .on('listening', () => { + console.log('Server running at http://localhost:' + httpPort); + }); + } catch (err) { + console.error("init() error: " + err.message); + } +} + +async function handleRequest(request, response) { + let connection; + try { + // Get a connection from the default connection pool + connection = await oracledb.getConnection(); + let result = await connection.execute(`SELECT TO_CHAR(CURRENT_DATE, 'DD-Mon-YYYY HH24:MI') FROM DUAL`); + console.log(result.rows[0][0]); + } catch (err) { + console.error(err.message); + } finally { + if (connection) { + try { + await connection.close(); // Put the connection back in the pool + } catch (err) { + console.error(err); + } + } + response.end(); + } +} + +async function closePoolAndExit() { + console.log("\nTerminating"); + try { + // Get the 'default' pool from the pool cache and close it (force + // closed after 3 seconds). + // If this hangs, you may need DISABLE_OOB=ON in a sqlnet.ora file + await oracledb.getPool().close(3); + process.exit(0); + } catch(err) { + console.error(err.message); + process.exit(1); + } +} + +process + .once('SIGTERM', closePoolAndExit) + .once('SIGINT', closePoolAndExit); + +init(); diff --git a/javascript/node-oracledb/sessiontagging1.js b/javascript/node-oracledb/sessiontagging1.js new file mode 100644 index 00000000..bf304308 --- /dev/null +++ b/javascript/node-oracledb/sessiontagging1.js @@ -0,0 +1,170 @@ +/* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with the Apache + * License, Version 2.0 (the "License.") + * + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + * NAME + * sessiontagging1.js + * + * DESCRIPTION + * Shows a simple connection callback function to set the "session + * state" of pooled connections when the requested connection tag + * does not match the connection's current tag. + * + * Each connection in a connection pool can retain state (such as + * ALTER SESSION values) from when the connection was previously + * used. Connection tagging allows the connection state to be + * recorded and later checked. This removes the overhead of + * unnecessarily re-executing ALTER SESSION commands on re-used + * connections. + * + * When using Oracle Client libraries 12.2 or later, then + * sessionCallback can alternatively be a string containing the name + * of a PL/SQL procedure - see documentation. + * + * Run this script and experiment sending web requests. For example + * send 20 requests with a concurrency of 4: + * ab -n 20 -c 4 http://127.0.0.1:7000/ + * + * This file uses Node 8's async/await syntax but could be rewritten + * to use callbacks. + * + * This example requires node-oracledb 3.1 or later. + * + * Also see sessionfixup.js and sessiontagging2.js + * + *****************************************************************************/ + +const http = require('http'); +const oracledb = require('oracledb'); +const dbConfig = require('./dbconfig.js'); +const httpPort = 7000; + +// initSession() will be invoked internally when each brand new pooled +// connection is first used, or when a getConnection() call requests a +// connection tag and a connection without an identical tag is +// returned. Its callback function 'cb' should be invoked only when +// all desired session state has been set. +// This implementation assumes that every pool.getConnection() will +// request a tag having the format USER_TZ=X, where X is a valid +// Oracle timezone. See sessiontagging2.js for a more complete +// implementation. +function initSession(connection, requestedTag, cb) { + console.log(`In initSession. requested tag: ${requestedTag}, actual tag: ${connection.tag}`); + + const tagParts = requestedTag.split('='); + if (tagParts[0] != 'USER_TZ') { + cb(new Error('Error: Only property USER_TZ is supported')); + return; + } + + // Execute the session state change. Note: if you have multiple SQL + // statements to execute, put them in a single anonymous PL/SQL + // block for efficiency. + connection.execute( + `ALTER SESSION SET TIME_ZONE = '${tagParts[1]}'`, + (err) => { + connection.tag = requestedTag; // Record the connection's new state + cb(err); + } + ); +} + +async function init() { + try { + await oracledb.createPool({ + user: dbConfig.user, + password: dbConfig.password, + connectString: dbConfig.connectString, + sessionCallback: initSession, + poolMin: 1, + poolMax: 4, + poolIncrement: 1 + }); + + // Create HTTP server and listen on port httpPort + const server = http.createServer(); + server.listen(httpPort) + .on('request', handleRequest) + .on('error', (err) => { + console.error('HTTP server problem: ' + err); + }) + .on('listening', () => { + console.log('Server running at http://localhost:' + httpPort); + }); + } catch (err) { + console.error('init() error: ' + err.message); + } +} + +async function handleRequest(request, response) { + let connection; + + // This would normally be determined by some other means, such as user + // preference, geo location, etc. + const sessionTagNeeded = Math.random() > 0.5 ? + "USER_TZ=UTC" : "USER_TZ=Australia/Melbourne"; + + try { + // Get a connection from the default connection pool, requesting + // one with a given tag. + // Depending on the parallelism that the app is invoked with (and + // the random setting of sessionTag), getConnection() will either: + // (i) find a connection with the requested tag already in the + // connection pool. initSession() will not be invoked. + // (ii) If a connection with the requested tag is not available + // in the pool, then a connection with a new session (i.e. no + // tag) is used. Alternatively a connection with a different + // tag is used if matchAnyTag is true. In both these cases the + // requested tag and actual tag do not match, so initSession() + // will be invoked before getConnection() returns. This lets + // the desired session state be set. + connection = await oracledb.getConnection({poolAlias: 'default', tag: sessionTagNeeded /*, matchAnyTag: true */}); + let result = await connection.execute(`SELECT TO_CHAR(CURRENT_DATE, 'DD-Mon-YYYY HH24:MI') FROM DUAL`); + console.log( `getConnection() tag needed was ${sessionTagNeeded}\n ${result.rows[0][0]}`); + } catch (err) { + console.error(err.message); + } finally { + if (connection) { + try { + console.log(` Closing connection tag is ${connection.tag}`); + await connection.close(); + } catch (err) { + console.error(err.message); + } + } + response.end(); + } +} + +async function closePoolAndExit() { + console.log("\nTerminating"); + try { + // Get the 'default' pool from the pool cache and close it (force + // closed after 3 seconds). + // If this hangs, you may need DISABLE_OOB=ON in a sqlnet.ora file + await oracledb.getPool().close(3); + process.exit(0); + } catch(err) { + console.error(err.message); + process.exit(1); + } +} + +process + .once('SIGTERM', closePoolAndExit) + .once('SIGINT', closePoolAndExit); + +init(); diff --git a/javascript/node-oracledb/sessiontagging2.js b/javascript/node-oracledb/sessiontagging2.js new file mode 100644 index 00000000..c3116e11 --- /dev/null +++ b/javascript/node-oracledb/sessiontagging2.js @@ -0,0 +1,227 @@ +/* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with the Apache + * License, Version 2.0 (the "License.") + * + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + * NAME + * sessiontagging2.js + * + * DESCRIPTION + * Shows a connection callback function to set the "session state" + * of pooled connections when the requested connection tag does not + * match the current tag. + * + * Each connection in a connection pool can retain state (such as + * ALTER SESSION values) from when the connection was previously + * used. Connection tagging allows the connection state to be + * recorded and later checked. This removes the overhead of + * unnecessarily re-executing ALTER SESSION commands on re-used + * connections. + * + * When using Oracle Client libraries 12.2 or later, then + * sessionCallback can alternatively be a string containing the name + * of a PL/SQL procedure - see documentation. + * + * Run this script and experiment sending web requests. For example + * send 20 requests with a concurrency of 4: + * ab -n 20 -c 4 http://127.0.0.1:7000/ + * + * This file uses Node 8's async/await syntax but could be rewritten + * to use callbacks. + * + * This example requires node-oracledb 3.1 or later. + * + * Also see sessionfixup.js and sessiontagging1.js + * + *****************************************************************************/ + +const http = require('http'); +const oracledb = require('oracledb'); +const dbConfig = require('./dbconfig.js'); +const httpPort = 7000; + +// initSession() will be invoked internally when each brand new pooled +// connection is first used, or when a getConnection() call requests a +// connection tag and a connection without an identical tag is +// returned. Its callback function 'cb' should be invoked only when +// all desired session state has been set. +// +// This implementation assumes the tag has name-value pairs like +// "k1=v1;k2=v2" where the pairs can be used in an ALTER SESSION +// statement. Specifically it white lists TIME_ZONE=UTC and +// TIME_ZONE=Australia/Melbourne. The white list could be enhanced to +// support more settings. Another potential improvement would be to +// identify properties in connection.tag that were not specifically +// asked for in requestedTag. These can be reset, as needed. +// +// See sessiontagging1.js for a simpler implementation. +function initSession(connection, requestedTag, cb) { + console.log(`In initSession. requested tag: ${requestedTag}, actual tag: ${connection.tag}`); + + // Split the requested and actual tags into property components + let requestedProperties = []; + let actualProperties = []; + if (requestedTag) { + requestedTag.split(";").map(y => y.split("=")).forEach(e => {if (e[0]) requestedProperties[e[0]] = e[1];}); + } + if (connection.tag) { + connection.tag.split(";").map(y => y.split("=")).forEach(e => {if (e[0]) actualProperties[e[0]] = e[1];}); + } + + // Find properties we want that are not already set, or not set + // correctly; these are retained in requestedProperties. Also + // record the final, complete set of properties the connection will + // have; these are retained in actualProperties. + for (let k in requestedProperties) { + if (actualProperties[k] && actualProperties[k] === requestedProperties[k]) { + delete requestedProperties[k]; // already set correctly + } else { + actualProperties[k] = requestedProperties[k]; // not set or not correctly set. Record new setting + } + } + + // Check allowed values against a white list to avoid any SQL + // injection issues. Construct a string of valid options usable by + // ALTER SESSION. + let s = ""; + for (let k in requestedProperties) { + if (k === 'TIME_ZONE') { + switch (requestedProperties[k]) { + case 'Australia/Melbourne': + case 'UTC': + break; + default: + cb(new Error(`Error: Invalid time zone value ${requestedProperties[k]}`)); + return; + } + // add white listing code to check other properties and values here + } else { + cb(new Error(`Error: Invalid connection tag property ${k}`)); + return; + } + s += `${k}='${requestedProperties[k]}' `; + } + if (s) { + // Execute the session state change. Note: if you have multiple + // SQL statements to execute, put them in a single anonymous + // PL/SQL block for efficiency. + connection.execute( + `ALTER SESSION SET ${s}`, + (err) => { + // Store the tag representing the connection's full set of + // properties + connection.tag = ""; + for (let k in actualProperties) { + connection.tag += `${k}=${actualProperties[k]};`; + } + cb(err); + } + ); + } else { + // The requested and actual tags may not be identical (which is + // why initSession was called), but the properties that this + // function validates are already set, so there is no need to call + // ALTER SESSION + cb(); + } +} + +async function init() { + try { + await oracledb.createPool({ + user: dbConfig.user, + password: dbConfig.password, + connectString: dbConfig.connectString, + sessionCallback: initSession, + poolMin: 1, + poolMax: 4, + poolIncrement: 1 + }); + + // Create HTTP server and listen on port httpPort + const server = http.createServer(); + server.listen(httpPort) + .on('request', handleRequest) + .on('error', (err) => { + console.error('HTTP server problem: ' + err); + }) + .on('listening', () => { + console.log('Server running at http://localhost:' + httpPort); + }); + } catch (err) { + console.error('init() error: ' + err.message); + } +} + +async function handleRequest(request, response) { + let connection; + + // A tag can have the form 'a=b;c=d;e=f' etc. + // The tag would normally be determined by some other means, such as user + // preference, geolocation, etc. + const sessionTagNeeded = Math.random() > 0.5 ? + "TIME_ZONE=UTC" : "TIME_ZONE=Australia/Melbourne"; + + try { + // Get a connection from the default connection pool, requesting + // one with a given tag. + // Depending on the parallelism that the app is invoked with (and + // the random setting of sessionTag), getConnection() will either: + // (i) find a connection with the requested tag already in the + // connection pool. initSession() will not be invoked. + // (ii) If a connection with the requested tag is not available + // in the pool, then a connection with a new session (i.e. no + // tag) is used. Alternatively a connection with a different + // tag is used if matchAnyTag is true. In both these cases the + // requested tag and actual tag do not match, so initSession() + // will be invoked before getConnection() returns. This lets + // the desired session state be set. + connection = await oracledb.getConnection({poolAlias: 'default', tag: sessionTagNeeded /*, matchAnyTag: true */}); + let result = await connection.execute(`SELECT TO_CHAR(CURRENT_DATE, 'DD-Mon-YYYY HH24:MI') FROM DUAL`); + console.log( `getConnection() tag needed was ${sessionTagNeeded}\n ${result.rows[0][0]}`); + } catch (err) { + console.error(err.message); + } finally { + if (connection) { + try { + console.log(` Closing connection tag is ${connection.tag}`); + await connection.close(); + } catch (err) { + console.error(err.message); + } + } + response.end(); + } +} + +async function closePoolAndExit() { + console.log("\nTerminating"); + try { + // Get the 'default' pool from the pool cache and close it (force + // closed after 3 seconds). + // If this hangs, you may need DISABLE_OOB=ON in a sqlnet.ora file + await oracledb.getPool().close(3); + process.exit(0); + } catch(err) { + console.error(err.message); + process.exit(1); + } +} + +process + .once('SIGTERM', closePoolAndExit) + .once('SIGINT', closePoolAndExit); + +init(); diff --git a/javascript/node-oracledb/soda1.js b/javascript/node-oracledb/soda1.js index 340c7599..89c46753 100644 --- a/javascript/node-oracledb/soda1.js +++ b/javascript/node-oracledb/soda1.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -29,6 +29,8 @@ * This uses Node 8's async/await syntax but could be rewritten to * use callbacks. * + * This example requires node-oracledb 3.0 or later. + * *****************************************************************************/ var oracledb = require('oracledb'); diff --git a/javascript/node-oracledb/version.js b/javascript/node-oracledb/version.js index 1f63308f..1e0f8373 100644 --- a/javascript/node-oracledb/version.js +++ b/javascript/node-oracledb/version.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -21,6 +21,8 @@ * DESCRIPTION * Shows the node-oracledb version attributes * + * This example requires node-oracledb 2.2 or later. + * *****************************************************************************/ var oracledb = require('oracledb'); diff --git a/javascript/node-oracledb/webapp.js b/javascript/node-oracledb/webapp.js index f06fc188..e4d34118 100644 --- a/javascript/node-oracledb/webapp.js +++ b/javascript/node-oracledb/webapp.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -27,13 +27,15 @@ * accepts a URL parameter for the department ID, for example: * http://localhost:7000/90 * - * In some networks, pool termination may hang unless you have + * In some networks forced pool termination may hang unless you have * 'disable_oob=on' in sqlnet.ora, see * https://oracle.github.io/node-oracledb/doc/api.html#tnsadmin * * Uses Oracle's sample HR schema. Scripts to create the HR schema * can be found at: https://github.com/oracle/db-sample-schemas * + * This example requires node-oracledb 3 or later. + * *****************************************************************************/ var http = require('http'); @@ -50,16 +52,18 @@ function init() { user: dbConfig.user, password: dbConfig.password, connectString: dbConfig.connectString - // Default values shown below + // edition: 'ORA$BASE', // used for Edition Based Redefintion // events: false, // whether to handle Oracle Database FAN and RLB events or support CQN // externalAuth: false, // whether connections should be established using External Authentication - // poolAlias: 'myalias' // set an alias to allow access to the pool via a name + // homogeneous: true, // all connections in the pool have the same credentials + // poolAlias: 'default', // set an alias to allow access to the pool via a name // poolIncrement: 1, // only grow the pool by one connection at a time // poolMax: 4, // maximum size of the pool. Increase UV_THREADPOOL_SIZE if you increase poolMax // poolMin: 0, // start with no connections; let the pool shrink completely // poolPingInterval: 60, // check aliveness of connection if idle in the pool for 60 seconds // poolTimeout: 60, // terminate connections that are idle in the pool for 60 seconds // queueTimeout: 60000, // terminate getConnection() calls in the queue longer than 60000 milliseconds + // sessionCallback: myFunction, // function invoked for brand new connections or by a connection tag mismatch // stmtCacheSize: 30 // number of statements that are cached in the statement cache of each connection }, function(err, pool) { @@ -208,29 +212,23 @@ function htmlFooter(response) { function closePoolAndExit() { console.log("\nTerminating"); try { - // get the pool from the pool cache and close it when no + // Get the pool from the pool cache and close it when no // connections are in use, or force it closed after 10 seconds - var pool = oracledb.getPool(); - pool.close(10, function(err) { + oracledb.getPool().close(10, function(err) { if (err) - console.error(err); + console.error(err.message); else console.log("Pool closed"); process.exit(0); }); } catch(err) { - // Ignore getPool() error, which may occur if multiple signals - // sent and the pool has already been removed from the cache. - process.exit(0); + console.error(err.message); + process.exit(1); } } process - .on('SIGTERM', function() { - closePoolAndExit(); - }) - .on('SIGINT', function() { - closePoolAndExit(); - }); + .once('SIGTERM', closePoolAndExit) + .once('SIGINT', closePoolAndExit); init(); diff --git a/javascript/node-oracledb/webappawait.js b/javascript/node-oracledb/webappawait.js index dd76a414..92d57429 100644 --- a/javascript/node-oracledb/webappawait.js +++ b/javascript/node-oracledb/webappawait.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -28,13 +28,15 @@ * accepts a URL parameter for the department ID, for example: * http://localhost:7000/90 * - * In some networks, pool termination may hang unless you have + * In some networks forced pool termination may hang unless you have * 'disable_oob=on' in sqlnet.ora, see * https://oracle.github.io/node-oracledb/doc/api.html#tnsadmin * * Uses Oracle's sample HR schema. Scripts to create the HR schema * can be found at: https://github.com/oracle/db-sample-schemas * + * This example requires node-oracledb 3 or later. + * *****************************************************************************/ const http = require('http'); @@ -51,16 +53,18 @@ async function init() { user: dbConfig.user, password: dbConfig.password, connectString: dbConfig.connectString - // Default values shown below + // edition: 'ORA$BASE', // used for Edition Based Redefintion // events: false, // whether to handle Oracle Database FAN and RLB events or support CQN // externalAuth: false, // whether connections should be established using External Authentication - // poolAlias: 'myalias' // set an alias to allow access to the pool via a name. + // homogeneous: true, // all connections in the pool have the same credentials + // poolAlias: 'default', // set an alias to allow access to the pool via a name. // poolIncrement: 1, // only grow the pool by one connection at a time // poolMax: 4, // maximum size of the pool. Increase UV_THREADPOOL_SIZE if you increase poolMax // poolMin: 0, // start with no connections; let the pool shrink completely // poolPingInterval: 60, // check aliveness of connection if idle in the pool for 60 seconds // poolTimeout: 60, // terminate connections that are idle in the pool for 60 seconds // queueTimeout: 60000, // terminate getConnection() calls in the queue longer than 60000 milliseconds + // sessionCallback: myFunction, // function invoked for brand new connections or by a connection tag mismatch // stmtCacheSize: 30 // number of statements that are cached in the statement cache of each connection }); @@ -185,25 +189,19 @@ function htmlFooter(response) { async function closePoolAndExit() { console.log("\nTerminating"); try { - // get the pool from the pool cache and close it when no + // Get the pool from the pool cache and close it when no // connections are in use, or force it closed after 10 seconds - let pool = oracledb.getPool(); - await pool.close(10); + await oracledb.getPool().close(10); console.log("Pool closed"); process.exit(0); } catch(err) { - // Ignore getPool() error, which may occur if multiple signals - // sent and the pool has already been removed from the cache. - process.exit(0); + console.error(err.message); + process.exit(1); } } process - .on('SIGTERM', function() { - closePoolAndExit(); - }) - .on('SIGINT', function() { - closePoolAndExit(); - }); + .once('SIGTERM', closePoolAndExit) + .once('SIGINT', closePoolAndExit); init(); diff --git a/javascript/node-oracledb/webapppromises.js b/javascript/node-oracledb/webapppromises.js index 158e8bfd..cac6815b 100644 --- a/javascript/node-oracledb/webapppromises.js +++ b/javascript/node-oracledb/webapppromises.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -28,13 +28,15 @@ * accepts a URL parameter for the department ID, for example: * http://localhost:7000/90 * - * In some networks, pool termination may hang unless you have + * In some networks forced pool termination may hang unless you have * 'disable_oob=on' in sqlnet.ora, see * https://oracle.github.io/node-oracledb/doc/api.html#tnsadmin * * Uses Oracle's sample HR schema. Scripts to create the HR schema * can be found at: https://github.com/oracle/db-sample-schemas * + * This example requires node-oracledb 3 or later. + * *****************************************************************************/ var http = require('http'); @@ -50,16 +52,18 @@ function init() { user: dbConfig.user, password: dbConfig.password, connectString: dbConfig.connectString - // Default values shown below + // edition: 'ORA$BASE', // used for Edition Based Redefintion // events: false, // whether to handle Oracle Database FAN and RLB events or support CQN // externalAuth: false, // whether connections should be established using External Authentication - // poolAlias: 'myalias' // set an alias to allow access to the pool via a name. + // homogeneous: true, // all connections in the pool have the same credentials + // poolAlias: 'default', // set an alias to allow access to the pool via a name. // poolIncrement: 1, // only grow the pool by one connection at a time // poolMax: 4, // maximum size of the pool. Increase UV_THREADPOOL_SIZE if you increase poolMax // poolMin: 0, // start with no connections; let the pool shrink completely // poolPingInterval: 60, // check aliveness of connection if idle in the pool for 60 seconds // poolTimeout: 60, // terminate connections that are idle in the pool for 60 seconds // queueTimeout: 60000, // terminate getConnection() calls in the queue longer than 60000 milliseconds + // sessionCallback: myFunction, // function invoked for brand new connections or by a connection tag mismatch // stmtCacheSize: 30 // number of statements that are cached in the statement cache of each connection }) .then(function(pool) { @@ -201,29 +205,23 @@ function htmlFooter(response) { function closePoolAndExit() { console.log("\nTerminating"); try { - // get the pool from the pool cache and close it when no + // Get the pool from the pool cache and close it when no // connections are in use, or force it closed after 10 seconds - var pool = oracledb.getPool(); - pool.close(10, function(err) { + oracledb.getPool().close(10, function(err) { if (err) - console.error(err); + console.error(err.message); else console.log("Pool closed"); process.exit(0); }); } catch(err) { - // Ignore getPool() error, which may occur if multiple signals - // sent and the pool has already been removed from the cache. - process.exit(0); + console.error(err.message); + process.exit(1); } } process - .on('SIGTERM', function() { - closePoolAndExit(); - }) - .on('SIGINT', function() { - closePoolAndExit(); - }); + .once('SIGTERM', closePoolAndExit) + .once('SIGINT', closePoolAndExit); init();