diff --git a/javascript/node-oracledb/README.md b/javascript/node-oracledb/README.md index f0053a1e..a15f648e 100644 --- a/javascript/node-oracledb/README.md +++ b/javascript/node-oracledb/README.md @@ -1,14 +1,15 @@ # Node-oracledb Examples -This directory contains [node-oracledb](https://www.npmjs.com/package/oracledb) examples. +This directory contains [node-oracledb](https://www.npmjs.com/package/oracledb) +examples. Documentation is [here +](https://oracle.github.io/node-oracledb/doc/api.html). To run the examples: - [Install node-oracledb](https://oracle.github.io/node-oracledb/INSTALL.html#quickstart). - -- Edit `dbconfig.js` and set your username, password and the database -connection string, for example: +- Edit `dbconfig.js` and set your username and the database connection string, +for example: ``` module.exports = { @@ -19,9 +20,8 @@ connection string, for example: ``` - This reads the password from the environment variable - `NODE_ORACLEDB_PASSWORD`, which you must set before running - examples. +- In a terminal window, set the environment variable `NODE_ORACLEDB_PASSWORD` to + the value of your database password. - Review the samples and then run them like: @@ -58,8 +58,7 @@ File Name | Description [`dbmsoutputpipe.js`](dbmsoutputpipe.js) | Show fetching DBMS_OUTPUT by using a pipelined table [`demodrop.js`](demodrop.js) | Drops the schema objects created by the examples [`demosetup.js`](demosetup.js) | Used to create common schema objects for the examples -[`dmlrupd1.js`](dmlrupd1.js) | Example of DML RETURNING with a single row match -[`dmlrupd2.js`](dmlrupd2.js) | Example of DML RETURNING where multiple rows are matched +[`dmlrupd.js`](dmlrupd.js) | Example of DML RETURNING where multiple rows are matched [`em_batcherrors.js`](em_batcherrors.js) | `executeMany()` example showing handling data errors [`em_dmlreturn1.js`](em_dmlreturn1.js) | `executeMany()` example of DML RETURNING that returns single values [`em_dmlreturn2.js`](em_dmlreturn2.js) | `executeMany()` example of DML RETURNING that returns multiple values @@ -73,6 +72,7 @@ File Name | Description [`impres.js`](impres.js) | Shows PL/SQL 'Implict Results' returning multiple query results from PL/SQL code. [`insert1.js`](insert1.js) | Basic example creating a table and inserting data. Shows DDL and DML [`insert2.js`](insert2.js) | Basic example showing auto commit behavior +[`lastinsertid.js`](lastinsertid.js) | Shows inserting a row and getting its ROWID. [`lobbinds.js`](lobbinds.js) | Demonstrates how to bind and query LOBs [`lobinsert1.js`](lobinsert1.js) | Shows inserting a file into a CLOB column [`lobinsert2.js`](lobinsert2.js) | Inserts text into a CLOB column using the RETURNING INTO method. @@ -97,7 +97,7 @@ File Name | Description [`select1.js`](select1.js) | Executes a basic query without using a connection pool or ResultSet [`select2.js`](select2.js) | Executes queries to show array and object output formats [`selectgeometry.js`](selectgeometry.js) | Insert and query Oracle Spatial geometries -[`selectjson.js`](selectjson.js) | Shows some JSON features of Oracle Database +[`selectjson.js`](selectjson.js) | Shows some JSON features of Oracle Database 21c [`selectjsonblob.js`](selectjsonblob.js) | Shows how to use a BLOB as a JSON column store [`selectobject.js`](selectobject.js) | Insert and query a named Oracle database object [`selectnestedcursor.js`](selectnestedcursor.js) | Shows selecting from a nested cursor @@ -108,4 +108,4 @@ File Name | Description [`sessiontagging2.js`](sessiontagging2.js) | More complex example of pooled connection tagging for setting session state [`soda1.js`](soda1.js) | Basic Simple Oracle Document Access (SODA) example [`version.js`](version.js) | Shows the node-oracledb version attributes -[`webappawait.js`](webappawait.js) | A simple web application using a connection pool +[`webapp.js`](webapp.js) | A simple web application using a connection pool diff --git a/javascript/node-oracledb/aqmulti.js b/javascript/node-oracledb/aqmulti.js index 9f367e73..ede8ee89 100644 --- a/javascript/node-oracledb/aqmulti.js +++ b/javascript/node-oracledb/aqmulti.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -33,6 +33,17 @@ const oracledb = require('oracledb'); const dbConfig = require('./dbconfig.js'); +// On Windows and macOS, you can specify the directory containing the Oracle +// Client Libraries at runtime, or before Node.js starts. On other platforms +// the system library search path must always be set before Node.js is started. +// See the node-oracledb installation documentation. +// If the search path is not correct, you will get a DPI-1047 error. +if (process.platform === 'win32') { // Windows + oracledb.initOracleClient({ libDir: 'C:\\oracle\\instantclient_19_11' }); +} else if (process.platform === 'darwin') { // macOS + oracledb.initOracleClient({ libDir: process.env.HOME + '/Downloads/instantclient_19_8' }); +} + const queueName = "DEMO_RAW_QUEUE"; async function enq() { diff --git a/javascript/node-oracledb/aqobject.js b/javascript/node-oracledb/aqobject.js index 4afccdad..d2b6aa3b 100644 --- a/javascript/node-oracledb/aqobject.js +++ b/javascript/node-oracledb/aqobject.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -34,6 +34,17 @@ const oracledb = require('oracledb'); const dbConfig = require('./dbconfig.js'); +// On Windows and macOS, you can specify the directory containing the Oracle +// Client Libraries at runtime, or before Node.js starts. On other platforms +// the system library search path must always be set before Node.js is started. +// See the node-oracledb installation documentation. +// If the search path is not correct, you will get a DPI-1047 error. +if (process.platform === 'win32') { // Windows + oracledb.initOracleClient({ libDir: 'C:\\oracle\\instantclient_19_11' }); +} else if (process.platform === 'darwin') { // macOS + oracledb.initOracleClient({ libDir: process.env.HOME + '/Downloads/instantclient_19_8' }); +} + const queueName = "ADDR_QUEUE"; async function enq() { diff --git a/javascript/node-oracledb/aqoptions.js b/javascript/node-oracledb/aqoptions.js index f1bf86d1..d6ce3ff1 100644 --- a/javascript/node-oracledb/aqoptions.js +++ b/javascript/node-oracledb/aqoptions.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -33,6 +33,17 @@ const oracledb = require('oracledb'); const dbConfig = require('./dbconfig.js'); +// On Windows and macOS, you can specify the directory containing the Oracle +// Client Libraries at runtime, or before Node.js starts. On other platforms +// the system library search path must always be set before Node.js is started. +// See the node-oracledb installation documentation. +// If the search path is not correct, you will get a DPI-1047 error. +if (process.platform === 'win32') { // Windows + oracledb.initOracleClient({ libDir: 'C:\\oracle\\instantclient_19_11' }); +} else if (process.platform === 'darwin') { // macOS + oracledb.initOracleClient({ libDir: process.env.HOME + '/Downloads/instantclient_19_8' }); +} + const queueName = "DEMO_RAW_QUEUE"; async function enq() { diff --git a/javascript/node-oracledb/aqraw.js b/javascript/node-oracledb/aqraw.js index ace88f35..d617c324 100644 --- a/javascript/node-oracledb/aqraw.js +++ b/javascript/node-oracledb/aqraw.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -33,6 +33,17 @@ const oracledb = require('oracledb'); const dbConfig = require('./dbconfig.js'); +// On Windows and macOS, you can specify the directory containing the Oracle +// Client Libraries at runtime, or before Node.js starts. On other platforms +// the system library search path must always be set before Node.js is started. +// See the node-oracledb installation documentation. +// If the search path is not correct, you will get a DPI-1047 error. +if (process.platform === 'win32') { // Windows + oracledb.initOracleClient({ libDir: 'C:\\oracle\\instantclient_19_11' }); +} else if (process.platform === 'darwin') { // macOS + oracledb.initOracleClient({ libDir: process.env.HOME + '/Downloads/instantclient_19_8' }); +} + const queueName = "DEMO_RAW_QUEUE"; async function enq() { diff --git a/javascript/node-oracledb/blobhttp.js b/javascript/node-oracledb/blobhttp.js index a4ea1614..13a26afe 100644 --- a/javascript/node-oracledb/blobhttp.js +++ b/javascript/node-oracledb/blobhttp.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -35,6 +35,17 @@ const oracledb = require('oracledb'); const dbConfig = require('./dbconfig.js'); const demoSetup = require('./demosetup.js'); +// On Windows and macOS, you can specify the directory containing the Oracle +// Client Libraries at runtime, or before Node.js starts. On other platforms +// the system library search path must always be set before Node.js is started. +// See the node-oracledb installation documentation. +// If the search path is not correct, you will get a DPI-1047 error. +if (process.platform === 'win32') { // Windows + oracledb.initOracleClient({ libDir: 'C:\\oracle\\instantclient_19_11' }); +} else if (process.platform === 'darwin') { // macOS + oracledb.initOracleClient({ libDir: process.env.HOME + '/Downloads/instantclient_19_8' }); +} + const httpPort = 7000; // Main entry point. Creates a connection pool which becomes the @@ -140,7 +151,7 @@ async function closePoolAndExit() { await oracledb.getPool().close(2); console.log('Pool closed'); process.exit(0); - } catch(err) { + } catch (err) { console.error(err.message); process.exit(1); } diff --git a/javascript/node-oracledb/calltimeout.js b/javascript/node-oracledb/calltimeout.js index 318eb682..d464e4dc 100755 --- a/javascript/node-oracledb/calltimeout.js +++ b/javascript/node-oracledb/calltimeout.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -32,6 +32,17 @@ const oracledb = require("oracledb"); const dbConfig = require('./dbconfig.js'); +// On Windows and macOS, you can specify the directory containing the Oracle +// Client Libraries at runtime, or before Node.js starts. On other platforms +// the system library search path must always be set before Node.js is started. +// See the node-oracledb installation documentation. +// If the search path is not correct, you will get a DPI-1047 error. +if (process.platform === 'win32') { // Windows + oracledb.initOracleClient({ libDir: 'C:\\oracle\\instantclient_19_11' }); +} else if (process.platform === 'darwin') { // macOS + oracledb.initOracleClient({ libDir: process.env.HOME + '/Downloads/instantclient_19_8' }); +} + const dboptime = 4; // seconds the simulated database operation will take const timeout = 2; // seconds the application will wait for the database operation diff --git a/javascript/node-oracledb/connect.js b/javascript/node-oracledb/connect.js index 25fdd886..92b59070 100644 --- a/javascript/node-oracledb/connect.js +++ b/javascript/node-oracledb/connect.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -33,6 +33,17 @@ const oracledb = require('oracledb'); const dbConfig = require('./dbconfig.js'); +// On Windows and macOS, you can specify the directory containing the Oracle +// Client Libraries at runtime, or before Node.js starts. On other platforms +// the system library search path must always be set before Node.js is started. +// See the node-oracledb installation documentation. +// If the search path is not correct, you will get a DPI-1047 error. +if (process.platform === 'win32') { // Windows + oracledb.initOracleClient({ libDir: 'C:\\oracle\\instantclient_19_11' }); +} else if (process.platform === 'darwin') { // macOS + oracledb.initOracleClient({ libDir: process.env.HOME + '/Downloads/instantclient_19_8' }); +} + async function run() { let connection; diff --git a/javascript/node-oracledb/connectionpool.js b/javascript/node-oracledb/connectionpool.js index 20d8b164..5482c146 100644 --- a/javascript/node-oracledb/connectionpool.js +++ b/javascript/node-oracledb/connectionpool.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -22,7 +22,7 @@ * Shows connection pool usage. Connection pools are recommended * for applications that use a lot of connections for short periods. * - * Other connection pool examples are in sessionfixup.js and webappawait.js. + * Other connection pool examples are in sessionfixup.js and webapp.js. * For a standalone connection example, see connect.js * * In some networks forced pool termination may hang unless you have @@ -38,11 +38,24 @@ // If you increase poolMax, you must increase UV_THREADPOOL_SIZE before Node.js // starts its thread pool. If you set UV_THREADPOOL_SIZE too late, the value is // ignored and the default size of 4 is used. +// Note on Windows you must set the UV_THREADPOOL_SIZE environment variable before +// running your application. // process.env.UV_THREADPOOL_SIZE = 4; const oracledb = require('oracledb'); const dbConfig = require('./dbconfig.js'); +// On Windows and macOS, you can specify the directory containing the Oracle +// Client Libraries at runtime, or before Node.js starts. On other platforms +// the system library search path must always be set before Node.js is started. +// See the node-oracledb installation documentation. +// If the search path is not correct, you will get a DPI-1047 error. +if (process.platform === 'win32') { // Windows + oracledb.initOracleClient({ libDir: 'C:\\oracle\\instantclient_19_11' }); +} else if (process.platform === 'darwin') { // macOS + oracledb.initOracleClient({ libDir: process.env.HOME + '/Downloads/instantclient_19_8' }); +} + async function init() { try { // Create a connection pool which will later be accessed via the @@ -64,8 +77,9 @@ async function init() { // queueMax: 500, // don't allow more than 500 unsatisfied getConnection() calls in the pool queue // queueTimeout: 60000, // terminate getConnection() calls queued for longer than 60000 milliseconds // sessionCallback: myFunction, // function invoked for brand new connections or by a connection tag mismatch + // sodaMetaDataCache: false, // Set true to improve SODA collection access performance // stmtCacheSize: 30, // number of statements that are cached in the statement cache of each connection - // _enableStats: false // record pool usage statistics that can be output with pool._logStats() + // enableStatistics: false // record pool usage for oracledb.getPool().getStatistics() and logStatistics() }); console.log('Connection pool started'); @@ -89,7 +103,7 @@ async function dostuff() { const options = { outFormat: oracledb.OUT_FORMAT_OBJECT }; const result = await connection.execute(sql, binds, options); console.log(result); - // oracledb.getPool()._logStats(); // show pool statistics. _enableStats must be true + // oracledb.getPool().logStatistics(); // show pool statistics. pool.enableStatistics must be true } catch (err) { console.error(err); } finally { @@ -115,7 +129,7 @@ async function closePoolAndExit() { await oracledb.getPool().close(10); console.log('Pool closed'); process.exit(0); - } catch(err) { + } catch (err) { console.error(err.message); process.exit(1); } diff --git a/javascript/node-oracledb/cqn1.js b/javascript/node-oracledb/cqn1.js index 2a85bbb3..79580f47 100644 --- a/javascript/node-oracledb/cqn1.js +++ b/javascript/node-oracledb/cqn1.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -39,14 +39,24 @@ const oracledb = require("oracledb"); const dbConfig = require('./dbconfig.js'); +// On Windows and macOS, you can specify the directory containing the Oracle +// Client Libraries at runtime, or before Node.js starts. On other platforms +// the system library search path must always be set before Node.js is started. +// See the node-oracledb installation documentation. +// If the search path is not correct, you will get a DPI-1047 error. +if (process.platform === 'win32') { // Windows + oracledb.initOracleClient({ libDir: 'C:\\oracle\\instantclient_19_11' }); +} else if (process.platform === 'darwin') { // macOS + oracledb.initOracleClient({ libDir: process.env.HOME + '/Downloads/instantclient_19_8' }); +} + dbConfig.events = true; // CQN needs events mode const interval = setInterval(function() { console.log("waiting..."); }, 5000); -function myCallback(message) -{ +function myCallback(message) { // message.type is one of the oracledb.SUBSCR_EVENT_TYPE_* values console.log("Message type:", message.type); if (message.type == oracledb.SUBSCR_EVENT_TYPE_DEREG) { @@ -100,7 +110,7 @@ async function setup(connection) { for (const s of stmts) { try { await connection.execute(s); - } catch(e) { + } catch (e) { if (e.errorNum != 942) console.error(e); } diff --git a/javascript/node-oracledb/cqn2.js b/javascript/node-oracledb/cqn2.js index 5970d244..aab21cd1 100644 --- a/javascript/node-oracledb/cqn2.js +++ b/javascript/node-oracledb/cqn2.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -40,14 +40,24 @@ const oracledb = require("oracledb"); const dbConfig = require('./dbconfig.js'); +// On Windows and macOS, you can specify the directory containing the Oracle +// Client Libraries at runtime, or before Node.js starts. On other platforms +// the system library search path must always be set before Node.js is started. +// See the node-oracledb installation documentation. +// If the search path is not correct, you will get a DPI-1047 error. +if (process.platform === 'win32') { // Windows + oracledb.initOracleClient({ libDir: 'C:\\oracle\\instantclient_19_11' }); +} else if (process.platform === 'darwin') { // macOS + oracledb.initOracleClient({ libDir: process.env.HOME + '/Downloads/instantclient_19_8' }); +} + dbConfig.events = true; // CQN needs events mode const interval = setInterval(function() { console.log("waiting..."); }, 5000); -function myCallback(message) -{ +function myCallback(message) { // message.type is one of the oracledb.SUBSCR_EVENT_TYPE_* values console.log("Message type:", message.type); if (message.type == oracledb.SUBSCR_EVENT_TYPE_DEREG) { @@ -100,7 +110,7 @@ async function setup(connection) { for (const s of stmts) { try { await connection.execute(s); - } catch(e) { + } catch (e) { if (e.errorNum != 942) console.error(e); } diff --git a/javascript/node-oracledb/date.js b/javascript/node-oracledb/date.js index a6fb3a54..dfd11bf8 100644 --- a/javascript/node-oracledb/date.js +++ b/javascript/node-oracledb/date.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -35,6 +35,17 @@ process.env.ORA_SDTZ = 'UTC'; const oracledb = require('oracledb'); const dbConfig = require('./dbconfig.js'); +// On Windows and macOS, you can specify the directory containing the Oracle +// Client Libraries at runtime, or before Node.js starts. On other platforms +// the system library search path must always be set before Node.js is started. +// See the node-oracledb installation documentation. +// If the search path is not correct, you will get a DPI-1047 error. +if (process.platform === 'win32') { // Windows + oracledb.initOracleClient({ libDir: 'C:\\oracle\\instantclient_19_11' }); +} else if (process.platform === 'darwin') { // macOS + oracledb.initOracleClient({ libDir: process.env.HOME + '/Downloads/instantclient_19_8' }); +} + oracledb.outFormat = oracledb.OUT_FORMAT_OBJECT; async function run() { @@ -62,7 +73,7 @@ async function run() { for (const s of stmts) { try { await connection.execute(s); - } catch(e) { + } catch (e) { if (e.errorNum != 942) console.error(e); } @@ -75,7 +86,7 @@ async function run() { `INSERT INTO no_datetab (id, timestampcol, timestamptz, timestampltz, datecol) VALUES (1, :ts, :tstz, :tsltz, :td)`, { ts: date, tstz: date, tsltz: date, td: date }); - console.log('Rows inserted: ' + result.rowsAffected ); + console.log('Rows inserted: ' + result.rowsAffected); console.log('Query Results:'); result = await connection.execute( @@ -94,7 +105,7 @@ async function run() { `INSERT INTO no_datetab (id, timestampcol, timestamptz, timestampltz, datecol) VALUES (2, :ts, :tstz, :tsltz, :td)`, { ts: date, tstz: date, tsltz: date, td: date }); - console.log('Rows inserted: ' + result.rowsAffected ); + console.log('Rows inserted: ' + result.rowsAffected); console.log('Query Results:'); result = await connection.execute( diff --git a/javascript/node-oracledb/dbconfig.js b/javascript/node-oracledb/dbconfig.js index 23d5c235..6efd0d8c 100644 --- a/javascript/node-oracledb/dbconfig.js +++ b/javascript/node-oracledb/dbconfig.js @@ -23,7 +23,8 @@ * to the database. Production applications should consider using * External Authentication to avoid hard coded credentials. * - * To create a database user see https://www.youtube.com/watch?v=WDJacg0NuLo + * To create a database user see + * https://blogs.oracle.com/sql/how-to-create-users-grant-them-privileges-and-remove-them-in-oracle-database * * Applications can set the connectString value to an Easy Connect * string, or a Net Service Name from a tnsnames.ora file or diff --git a/javascript/node-oracledb/dbmsoutputgetline.js b/javascript/node-oracledb/dbmsoutputgetline.js index d9dc1adb..89e4d8a7 100644 --- a/javascript/node-oracledb/dbmsoutputgetline.js +++ b/javascript/node-oracledb/dbmsoutputgetline.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -30,6 +30,17 @@ const oracledb = require('oracledb'); const dbConfig = require('./dbconfig.js'); +// On Windows and macOS, you can specify the directory containing the Oracle +// Client Libraries at runtime, or before Node.js starts. On other platforms +// the system library search path must always be set before Node.js is started. +// See the node-oracledb installation documentation. +// If the search path is not correct, you will get a DPI-1047 error. +if (process.platform === 'win32') { // Windows + oracledb.initOracleClient({ libDir: 'C:\\oracle\\instantclient_19_11' }); +} else if (process.platform === 'darwin') { // macOS + oracledb.initOracleClient({ libDir: process.env.HOME + '/Downloads/instantclient_19_8' }); +} + async function run() { let connection; diff --git a/javascript/node-oracledb/dbmsoutputpipe.js b/javascript/node-oracledb/dbmsoutputpipe.js index 1bf4154f..700b906a 100644 --- a/javascript/node-oracledb/dbmsoutputpipe.js +++ b/javascript/node-oracledb/dbmsoutputpipe.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -28,6 +28,17 @@ const oracledb = require('oracledb'); const dbConfig = require('./dbconfig.js'); +// On Windows and macOS, you can specify the directory containing the Oracle +// Client Libraries at runtime, or before Node.js starts. On other platforms +// the system library search path must always be set before Node.js is started. +// See the node-oracledb installation documentation. +// If the search path is not correct, you will get a DPI-1047 error. +if (process.platform === 'win32') { // Windows + oracledb.initOracleClient({ libDir: 'C:\\oracle\\instantclient_19_11' }); +} else if (process.platform === 'darwin') { // macOS + oracledb.initOracleClient({ libDir: process.env.HOME + '/Downloads/instantclient_19_8' }); +} + async function run() { let connection; @@ -57,7 +68,7 @@ async function run() { for (const s of stmts) { try { await connection.execute(s); - } catch(e) { + } catch (e) { if (e.errorNum != 942) console.error(e); } diff --git a/javascript/node-oracledb/demodrop.js b/javascript/node-oracledb/demodrop.js index f6ad3e3f..f649eb93 100644 --- a/javascript/node-oracledb/demodrop.js +++ b/javascript/node-oracledb/demodrop.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -26,6 +26,17 @@ const oracledb = require('oracledb'); const dbConfig = require('./dbconfig.js'); +// On Windows and macOS, you can specify the directory containing the Oracle +// Client Libraries at runtime, or before Node.js starts. On other platforms +// the system library search path must always be set before Node.js is started. +// See the node-oracledb installation documentation. +// If the search path is not correct, you will get a DPI-1047 error. +if (process.platform === 'win32') { // Windows + oracledb.initOracleClient({ libDir: 'C:\\oracle\\instantclient_19_11' }); +} else if (process.platform === 'darwin') { // macOS + oracledb.initOracleClient({ libDir: process.env.HOME + '/Downloads/instantclient_19_8' }); +} + async function run() { let connection; @@ -52,6 +63,8 @@ async function run() { `DROP TABLE no_purchaseorder_b PURGE`, + `DROP TABLE no_lastinsertid PURGE`, + `DROP TABLE no_dmlrupdtab PURGE`, `DROP TABLE no_lobs PURGE`, @@ -114,7 +127,7 @@ async function run() { try { console.log(s); await connection.execute(s); - } catch(e) { + } catch (e) { // do nothing } } diff --git a/javascript/node-oracledb/demosetup.js b/javascript/node-oracledb/demosetup.js index 4f79d8c3..ce7c5513 100644 --- a/javascript/node-oracledb/demosetup.js +++ b/javascript/node-oracledb/demosetup.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -60,9 +60,9 @@ async function setupBf(connection) { for (const s of stmts) { try { await connection.execute(s); - } catch(e) { + } catch (e) { if (e.errorNum != 942) - throw(e); + throw (e); } } await connection.commit(); @@ -113,9 +113,9 @@ async function setupLobs(connection, insertData) { for (const s of stmts) { try { await connection.execute(s); - } catch(e) { + } catch (e) { if (e.errorNum != 942) - throw(e); + throw (e); } } @@ -230,9 +230,9 @@ async function setupEm(connection) { for (const s of stmts) { try { await connection.execute(s); - } catch(e) { + } catch (e) { if (e.errorNum != 942) - throw(e); + throw (e); } } await connection.commit(); diff --git a/javascript/node-oracledb/dmlrupd2.js b/javascript/node-oracledb/dmlrupd.js similarity index 73% rename from javascript/node-oracledb/dmlrupd2.js rename to javascript/node-oracledb/dmlrupd.js index 28187a71..4097456e 100644 --- a/javascript/node-oracledb/dmlrupd2.js +++ b/javascript/node-oracledb/dmlrupd.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -16,20 +16,31 @@ * limitations under the License. * * NAME - * dmlrupd2.js + * dmlrupd.js * * DESCRIPTION * Example of 'DML Returning' with multiple rows matched. * The ROWIDs of the changed records are returned. This is how to get - * the 'last insert id'. + * the 'last insert id' of multiple rows. For a single row, use "lastRowid". * * This example uses Node 8's async/await syntax. * *****************************************************************************/ -const oracledb = require( 'oracledb' ); +const oracledb = require('oracledb'); const dbConfig = require('./dbconfig.js'); +// On Windows and macOS, you can specify the directory containing the Oracle +// Client Libraries at runtime, or before Node.js starts. On other platforms +// the system library search path must always be set before Node.js is started. +// See the node-oracledb installation documentation. +// If the search path is not correct, you will get a DPI-1047 error. +if (process.platform === 'win32') { // Windows + oracledb.initOracleClient({ libDir: 'C:\\oracle\\instantclient_19_11' }); +} else if (process.platform === 'darwin') { // macOS + oracledb.initOracleClient({ libDir: process.env.HOME + '/Downloads/instantclient_19_8' }); +} + async function run() { let connection; @@ -54,7 +65,7 @@ async function run() { for (const s of stmts) { try { await connection.execute(s); - } catch(e) { + } catch (e) { if (e.errorNum != 942) console.error(e); } diff --git a/javascript/node-oracledb/em_batcherrors.js b/javascript/node-oracledb/em_batcherrors.js index c86c8648..70328894 100644 --- a/javascript/node-oracledb/em_batcherrors.js +++ b/javascript/node-oracledb/em_batcherrors.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -35,6 +35,17 @@ const oracledb = require('oracledb'); const dbConfig = require('./dbconfig.js'); const demoSetup = require('./demosetup.js'); +// On Windows and macOS, you can specify the directory containing the Oracle +// Client Libraries at runtime, or before Node.js starts. On other platforms +// the system library search path must always be set before Node.js is started. +// See the node-oracledb installation documentation. +// If the search path is not correct, you will get a DPI-1047 error. +if (process.platform === 'win32') { // Windows + oracledb.initOracleClient({ libDir: 'C:\\oracle\\instantclient_19_11' }); +} else if (process.platform === 'darwin') { // macOS + oracledb.initOracleClient({ libDir: process.env.HOME + '/Downloads/instantclient_19_8' }); +} + const sql = "INSERT INTO no_em_childtab VALUES (:1, :2, :3)"; const binds = [ diff --git a/javascript/node-oracledb/em_dmlreturn1.js b/javascript/node-oracledb/em_dmlreturn1.js index 61fcd5ef..1cd85a16 100644 --- a/javascript/node-oracledb/em_dmlreturn1.js +++ b/javascript/node-oracledb/em_dmlreturn1.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -31,6 +31,17 @@ const oracledb = require('oracledb'); const dbConfig = require('./dbconfig.js'); const demoSetup = require('./demosetup.js'); +// On Windows and macOS, you can specify the directory containing the Oracle +// Client Libraries at runtime, or before Node.js starts. On other platforms +// the system library search path must always be set before Node.js is started. +// See the node-oracledb installation documentation. +// If the search path is not correct, you will get a DPI-1047 error. +if (process.platform === 'win32') { // Windows + oracledb.initOracleClient({ libDir: 'C:\\oracle\\instantclient_19_11' }); +} else if (process.platform === 'darwin') { // macOS + oracledb.initOracleClient({ libDir: process.env.HOME + '/Downloads/instantclient_19_8' }); +} + const sql = "INSERT INTO no_em_tab VALUES (:1, :2) RETURNING ROWID, id, val INTO :3, :4, :5"; const binds = [ diff --git a/javascript/node-oracledb/em_dmlreturn2.js b/javascript/node-oracledb/em_dmlreturn2.js index c2088699..5cdb9419 100644 --- a/javascript/node-oracledb/em_dmlreturn2.js +++ b/javascript/node-oracledb/em_dmlreturn2.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -31,6 +31,17 @@ const oracledb = require('oracledb'); const dbConfig = require('./dbconfig.js'); const demoSetup = require('./demosetup.js'); +// On Windows and macOS, you can specify the directory containing the Oracle +// Client Libraries at runtime, or before Node.js starts. On other platforms +// the system library search path must always be set before Node.js is started. +// See the node-oracledb installation documentation. +// If the search path is not correct, you will get a DPI-1047 error. +if (process.platform === 'win32') { // Windows + oracledb.initOracleClient({ libDir: 'C:\\oracle\\instantclient_19_11' }); +} else if (process.platform === 'darwin') { // macOS + oracledb.initOracleClient({ libDir: process.env.HOME + '/Downloads/instantclient_19_8' }); +} + const insertSql = "INSERT INTO no_em_tab VALUES (:1, :2)"; const insertData = [ diff --git a/javascript/node-oracledb/em_insert1.js b/javascript/node-oracledb/em_insert1.js index 0e30e4a5..b090067f 100644 --- a/javascript/node-oracledb/em_insert1.js +++ b/javascript/node-oracledb/em_insert1.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -31,6 +31,17 @@ const oracledb = require('oracledb'); const dbConfig = require('./dbconfig.js'); const demoSetup = require('./demosetup.js'); +// On Windows and macOS, you can specify the directory containing the Oracle +// Client Libraries at runtime, or before Node.js starts. On other platforms +// the system library search path must always be set before Node.js is started. +// See the node-oracledb installation documentation. +// If the search path is not correct, you will get a DPI-1047 error. +if (process.platform === 'win32') { // Windows + oracledb.initOracleClient({ libDir: 'C:\\oracle\\instantclient_19_11' }); +} else if (process.platform === 'darwin') { // macOS + oracledb.initOracleClient({ libDir: process.env.HOME + '/Downloads/instantclient_19_8' }); +} + const sql = "INSERT INTO no_em_tab values (:a, :b)"; const binds = [ diff --git a/javascript/node-oracledb/em_insert2.js b/javascript/node-oracledb/em_insert2.js index 5af60ab1..f21b8c57 100644 --- a/javascript/node-oracledb/em_insert2.js +++ b/javascript/node-oracledb/em_insert2.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -31,6 +31,17 @@ const oracledb = require('oracledb'); const dbConfig = require('./dbconfig.js'); const demoSetup = require('./demosetup.js'); +// On Windows and macOS, you can specify the directory containing the Oracle +// Client Libraries at runtime, or before Node.js starts. On other platforms +// the system library search path must always be set before Node.js is started. +// See the node-oracledb installation documentation. +// If the search path is not correct, you will get a DPI-1047 error. +if (process.platform === 'win32') { // Windows + oracledb.initOracleClient({ libDir: 'C:\\oracle\\instantclient_19_11' }); +} else if (process.platform === 'darwin') { // macOS + oracledb.initOracleClient({ libDir: process.env.HOME + '/Downloads/instantclient_19_8' }); +} + const sql = "INSERT INTO no_em_tab values (:1, :2)"; const binds = [ diff --git a/javascript/node-oracledb/em_plsql.js b/javascript/node-oracledb/em_plsql.js index e10b8fee..b5bf171d 100644 --- a/javascript/node-oracledb/em_plsql.js +++ b/javascript/node-oracledb/em_plsql.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -21,6 +21,9 @@ * DESCRIPTION * executeMany() example calling PL/SQL. * + * Note that when OUT binds are used with PL/SQL, there may be no performance + * advantages compared with repeating calls to execute(). + * * This example requires node-oracledb 2.2 or later. * * This example uses Node 8's async/await syntax. @@ -31,6 +34,17 @@ const oracledb = require('oracledb'); const dbConfig = require('./dbconfig.js'); const demoSetup = require('./demosetup.js'); +// On Windows and macOS, you can specify the directory containing the Oracle +// Client Libraries at runtime, or before Node.js starts. On other platforms +// the system library search path must always be set before Node.js is started. +// See the node-oracledb installation documentation. +// If the search path is not correct, you will get a DPI-1047 error. +if (process.platform === 'win32') { // Windows + oracledb.initOracleClient({ libDir: 'C:\\oracle\\instantclient_19_11' }); +} else if (process.platform === 'darwin') { // macOS + oracledb.initOracleClient({ libDir: process.env.HOME + '/Downloads/instantclient_19_8' }); +} + const sql = "BEGIN no_em_proc(:1, :2, :3); END;"; const binds = [ diff --git a/javascript/node-oracledb/em_rowcounts.js b/javascript/node-oracledb/em_rowcounts.js index 953b4c5a..101a3c88 100644 --- a/javascript/node-oracledb/em_rowcounts.js +++ b/javascript/node-oracledb/em_rowcounts.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -32,6 +32,17 @@ const oracledb = require('oracledb'); const dbConfig = require('./dbconfig.js'); const demoSetup = require('./demosetup.js'); +// On Windows and macOS, you can specify the directory containing the Oracle +// Client Libraries at runtime, or before Node.js starts. On other platforms +// the system library search path must always be set before Node.js is started. +// See the node-oracledb installation documentation. +// If the search path is not correct, you will get a DPI-1047 error. +if (process.platform === 'win32') { // Windows + oracledb.initOracleClient({ libDir: 'C:\\oracle\\instantclient_19_11' }); +} else if (process.platform === 'darwin') { // macOS + oracledb.initOracleClient({ libDir: process.env.HOME + '/Downloads/instantclient_19_8' }); +} + const sql = "DELETE FROM no_em_childtab WHERE parentid = :1"; const binds = [ diff --git a/javascript/node-oracledb/endtoend.js b/javascript/node-oracledb/endtoend.js index f737473f..001ec5db 100644 --- a/javascript/node-oracledb/endtoend.js +++ b/javascript/node-oracledb/endtoend.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -32,6 +32,17 @@ const oracledb = require('oracledb'); const dbConfig = require('./dbconfig.js'); +// On Windows and macOS, you can specify the directory containing the Oracle +// Client Libraries at runtime, or before Node.js starts. On other platforms +// the system library search path must always be set before Node.js is started. +// See the node-oracledb installation documentation. +// If the search path is not correct, you will get a DPI-1047 error. +if (process.platform === 'win32') { // Windows + oracledb.initOracleClient({ libDir: 'C:\\oracle\\instantclient_19_11' }); +} else if (process.platform === 'darwin') { // macOS + oracledb.initOracleClient({ libDir: process.env.HOME + '/Downloads/instantclient_19_8' }); +} + async function run() { let connection; @@ -46,7 +57,7 @@ async function run() { connection.action = "Query departments"; console.log("Use SQL*Plus as SYSTEM (or ADMIN for Oracle Cloud databases) to execute the query:"); - console.log(" SELECT username, client_identifier, action, module FROM v$session WHERE username = UPPER('" + dbConfig.user +"');"); + console.log(" SELECT username, client_identifier, action, module FROM v$session WHERE username = UPPER('" + dbConfig.user + "');"); // Sleep 10 seconds to keep the connection open. This allows // external queries on V$SESSION to show the connection diff --git a/javascript/node-oracledb/example.js b/javascript/node-oracledb/example.js index 76a14e4f..f809720e 100644 --- a/javascript/node-oracledb/example.js +++ b/javascript/node-oracledb/example.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -21,11 +21,11 @@ * DESCRIPTION * A basic node-oracledb example using Node.js 8's async/await syntax. * - * For connection pool examples see connectionpool.js and webappawait.js + * For connection pool examples see connectionpool.js and webapp.js * For a ResultSet example see resultset1.js * For a query stream example see selectstream.js * - * This example requires node-oracledb 2.2 or later. + * This example requires node-oracledb 5 or later. * *****************************************************************************/ @@ -35,11 +35,16 @@ process.env.ORA_SDTZ = 'UTC'; const oracledb = require('oracledb'); const dbConfig = require('./dbconfig.js'); -// On Windows and macOS, you can specify the directory containing your Oracle -// Client Libraries. If this is not done, then a standard search heuristic is -// used, see the node-oracledb documentation. -// oracledb.initOracleClient({ libDir: 'C:\instantclient_19_3' }); // Windows -// oracledb.initOracleClient({ libDir: '/Users/your_username/instantclient_19_3' }); // macOS +// On Windows and macOS, you can specify the directory containing the Oracle +// Client Libraries at runtime, or before Node.js starts. On other platforms +// the system library search path must always be set before Node.js is started. +// See the node-oracledb installation documentation. +// If the search path is not correct, you will get a DPI-1047 error. +if (process.platform === 'win32') { // Windows + oracledb.initOracleClient({ libDir: 'C:\\oracle\\instantclient_19_11' }); +} else if (process.platform === 'darwin') { // macOS + oracledb.initOracleClient({ libDir: process.env.HOME + '/Downloads/instantclient_19_8' }); +} async function run() { let connection; @@ -63,7 +68,7 @@ async function run() { for (const s of stmts) { try { await connection.execute(s); - } catch(e) { + } catch (e) { if (e.errorNum != 942) console.error(e); } diff --git a/javascript/node-oracledb/fetchinfo.js b/javascript/node-oracledb/fetchinfo.js index 13ad237e..452ddf27 100644 --- a/javascript/node-oracledb/fetchinfo.js +++ b/javascript/node-oracledb/fetchinfo.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -30,6 +30,17 @@ const oracledb = require('oracledb'); const dbConfig = require('./dbconfig.js'); const demoSetup = require('./demosetup.js'); +// On Windows and macOS, you can specify the directory containing the Oracle +// Client Libraries at runtime, or before Node.js starts. On other platforms +// the system library search path must always be set before Node.js is started. +// See the node-oracledb installation documentation. +// If the search path is not correct, you will get a DPI-1047 error. +if (process.platform === 'win32') { // Windows + oracledb.initOracleClient({ libDir: 'C:\\oracle\\instantclient_19_11' }); +} else if (process.platform === 'darwin') { // macOS + oracledb.initOracleClient({ libDir: process.env.HOME + '/Downloads/instantclient_19_8' }); +} + oracledb.fetchAsString = [ oracledb.NUMBER ]; // any number queried will be returned as a string async function run() { diff --git a/javascript/node-oracledb/impres.js b/javascript/node-oracledb/impres.js index 736c5c0c..c6a3a006 100644 --- a/javascript/node-oracledb/impres.js +++ b/javascript/node-oracledb/impres.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -33,6 +33,17 @@ const oracledb = require('oracledb'); const dbConfig = require('./dbconfig.js'); const demoSetup = require('./demosetup.js'); +// On Windows and macOS, you can specify the directory containing the Oracle +// Client Libraries at runtime, or before Node.js starts. On other platforms +// the system library search path must always be set before Node.js is started. +// See the node-oracledb installation documentation. +// If the search path is not correct, you will get a DPI-1047 error. +if (process.platform === 'win32') { // Windows + oracledb.initOracleClient({ libDir: 'C:\\oracle\\instantclient_19_11' }); +} else if (process.platform === 'darwin') { // macOS + oracledb.initOracleClient({ libDir: process.env.HOME + '/Downloads/instantclient_19_8' }); +} + oracledb.outFormat = oracledb.OUT_FORMAT_OBJECT; async function run() { diff --git a/javascript/node-oracledb/insert1.js b/javascript/node-oracledb/insert1.js index a93dfcb6..dd62557b 100644 --- a/javascript/node-oracledb/insert1.js +++ b/javascript/node-oracledb/insert1.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -31,6 +31,17 @@ const oracledb = require('oracledb'); const dbConfig = require('./dbconfig.js'); +// On Windows and macOS, you can specify the directory containing the Oracle +// Client Libraries at runtime, or before Node.js starts. On other platforms +// the system library search path must always be set before Node.js is started. +// See the node-oracledb installation documentation. +// If the search path is not correct, you will get a DPI-1047 error. +if (process.platform === 'win32') { // Windows + oracledb.initOracleClient({ libDir: 'C:\\oracle\\instantclient_19_11' }); +} else if (process.platform === 'darwin') { // macOS + oracledb.initOracleClient({ libDir: process.env.HOME + '/Downloads/instantclient_19_8' }); +} + async function run() { let connection; @@ -51,7 +62,7 @@ async function run() { for (const s of stmts) { try { await connection.execute(s); - } catch(e) { + } catch (e) { if (e.errorNum != 942) console.error(e); } diff --git a/javascript/node-oracledb/insert2.js b/javascript/node-oracledb/insert2.js index b1dfe282..37e3d1bd 100644 --- a/javascript/node-oracledb/insert2.js +++ b/javascript/node-oracledb/insert2.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -34,6 +34,17 @@ const oracledb = require('oracledb'); const dbConfig = require('./dbconfig.js'); +// On Windows and macOS, you can specify the directory containing the Oracle +// Client Libraries at runtime, or before Node.js starts. On other platforms +// the system library search path must always be set before Node.js is started. +// See the node-oracledb installation documentation. +// If the search path is not correct, you will get a DPI-1047 error. +if (process.platform === 'win32') { // Windows + oracledb.initOracleClient({ libDir: 'C:\\oracle\\instantclient_19_11' }); +} else if (process.platform === 'darwin') { // macOS + oracledb.initOracleClient({ libDir: process.env.HOME + '/Downloads/instantclient_19_8' }); +} + async function run() { let connection1, connection2; @@ -57,7 +68,7 @@ async function run() { for (const s of stmts) { try { await connection1.execute(s); - } catch(e) { + } catch (e) { if (e.errorNum != 942) console.error(e); } diff --git a/javascript/node-oracledb/dmlrupd1.js b/javascript/node-oracledb/lastinsertid.js similarity index 55% rename from javascript/node-oracledb/dmlrupd1.js rename to javascript/node-oracledb/lastinsertid.js index 2d80e9be..37349e5d 100644 --- a/javascript/node-oracledb/dmlrupd1.js +++ b/javascript/node-oracledb/lastinsertid.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -16,20 +16,30 @@ * limitations under the License. * * NAME - * dmlrupd1.js + * lastinsertid.js * * DESCRIPTION - * Example of 'DML Returning' with a single row match. - * The ROWID of the changed record is returned. This is how to get - * the 'last insert id'. + * Example of inserting a row and getting it's ROWID. + * To return application generated identifiers, see dmlrupd.js. * * This example uses Node 8's async/await syntax. * *****************************************************************************/ -const oracledb = require( 'oracledb' ); +const oracledb = require('oracledb'); const dbConfig = require('./dbconfig.js'); +// On Windows and macOS, you can specify the directory containing the Oracle +// Client Libraries at runtime, or before Node.js starts. On other platforms +// the system library search path must always be set before Node.js is started. +// See the node-oracledb installation documentation. +// If the search path is not correct, you will get a DPI-1047 error. +if (process.platform === 'win32') { // Windows + oracledb.initOracleClient({ libDir: 'C:\\oracle\\instantclient_19_11' }); +} else if (process.platform === 'darwin') { // macOS + oracledb.initOracleClient({ libDir: process.env.HOME + '/Downloads/instantclient_19_8' }); +} + async function run() { let connection; @@ -42,47 +52,36 @@ async function run() { // const stmts = [ - `DROP TABLE no_dmlrupdtab`, - - `CREATE TABLE no_dmlrupdtab (id NUMBER, name VARCHAR2(40))`, - - `INSERT INTO no_dmlrupdtab VALUES (1001, 'Venkat')`, + `DROP TABLE no_lastinsertid`, - `INSERT INTO no_dmlrupdtab VALUES (1002, 'Neeharika')` + `CREATE TABLE no_lastinsertid (id NUMBER, name VARCHAR2(40))`, ]; for (const s of stmts) { try { await connection.execute(s); - } catch(e) { + } catch (e) { if (e.errorNum != 942) console.error(e); } } // - // Show DML Returning + // Execute the SQL statement // - // SQL statement. - // Note bind names cannot be reused in the DML section and the RETURNING section - const sql = - `UPDATE no_dmlrupdtab - SET name = :name - WHERE id = :id - RETURNING ROWID INTO :rid`; + const sql = `INSERT INTO no_lastinsertid VALUES (:id, :name)`; const result = await connection.execute( sql, { - id: 1001, - name: "Krishna", - rid: { type: oracledb.STRING, dir: oracledb.BIND_OUT } + id: 1000, + name: "Chris" }, { autoCommit: true } ); - console.log(result.outBinds); + console.log("The ROWID is", result.lastRowid); } catch (err) { console.error(err); diff --git a/javascript/node-oracledb/lobbinds.js b/javascript/node-oracledb/lobbinds.js index 27da2137..50ce62ed 100644 --- a/javascript/node-oracledb/lobbinds.js +++ b/javascript/node-oracledb/lobbinds.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -37,6 +37,17 @@ const oracledb = require('oracledb'); const dbConfig = require('./dbconfig.js'); const demoSetup = require('./demosetup.js'); +// On Windows and macOS, you can specify the directory containing the Oracle +// Client Libraries at runtime, or before Node.js starts. On other platforms +// the system library search path must always be set before Node.js is started. +// See the node-oracledb installation documentation. +// If the search path is not correct, you will get a DPI-1047 error. +if (process.platform === 'win32') { // Windows + oracledb.initOracleClient({ libDir: 'C:\\oracle\\instantclient_19_11' }); +} else if (process.platform === 'darwin') { // macOS + oracledb.initOracleClient({ libDir: process.env.HOME + '/Downloads/instantclient_19_8' }); +} + const clobOutFileName1 = 'lobbindsout1.txt'; const clobOutFileName2 = 'lobbindsout2.txt'; diff --git a/javascript/node-oracledb/lobinsert1.js b/javascript/node-oracledb/lobinsert1.js index 2f9c2f5d..52d1b6d4 100644 --- a/javascript/node-oracledb/lobinsert1.js +++ b/javascript/node-oracledb/lobinsert1.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -40,6 +40,17 @@ const oracledb = require('oracledb'); const dbConfig = require('./dbconfig.js'); const demoSetup = require('./demosetup.js'); +// On Windows and macOS, you can specify the directory containing the Oracle +// Client Libraries at runtime, or before Node.js starts. On other platforms +// the system library search path must always be set before Node.js is started. +// See the node-oracledb installation documentation. +// If the search path is not correct, you will get a DPI-1047 error. +if (process.platform === 'win32') { // Windows + oracledb.initOracleClient({ libDir: 'C:\\oracle\\instantclient_19_11' }); +} else if (process.platform === 'darwin') { // macOS + oracledb.initOracleClient({ libDir: process.env.HOME + '/Downloads/instantclient_19_8' }); +} + oracledb.autoCommit = true; // for ease of demonstration only const clobInFileName = 'clobexample.txt'; // the file with text to be inserted into the database diff --git a/javascript/node-oracledb/lobinsert2.js b/javascript/node-oracledb/lobinsert2.js index 3725c0d7..b8fb5955 100644 --- a/javascript/node-oracledb/lobinsert2.js +++ b/javascript/node-oracledb/lobinsert2.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -32,6 +32,17 @@ const oracledb = require('oracledb'); const dbConfig = require('./dbconfig.js'); const demoSetup = require('./demosetup.js'); +// On Windows and macOS, you can specify the directory containing the Oracle +// Client Libraries at runtime, or before Node.js starts. On other platforms +// the system library search path must always be set before Node.js is started. +// See the node-oracledb installation documentation. +// If the search path is not correct, you will get a DPI-1047 error. +if (process.platform === 'win32') { // Windows + oracledb.initOracleClient({ libDir: 'C:\\oracle\\instantclient_19_11' }); +} else if (process.platform === 'darwin') { // macOS + oracledb.initOracleClient({ libDir: process.env.HOME + '/Downloads/instantclient_19_8' }); +} + const inFileName = 'clobexample.txt'; // the file with text to be inserted into the database async function run() { diff --git a/javascript/node-oracledb/lobinserttemp.js b/javascript/node-oracledb/lobinserttemp.js index 3ee350bf..561ed526 100644 --- a/javascript/node-oracledb/lobinserttemp.js +++ b/javascript/node-oracledb/lobinserttemp.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -36,6 +36,17 @@ const oracledb = require('oracledb'); const dbConfig = require('./dbconfig.js'); const demoSetup = require('./demosetup.js'); +// On Windows and macOS, you can specify the directory containing the Oracle +// Client Libraries at runtime, or before Node.js starts. On other platforms +// the system library search path must always be set before Node.js is started. +// See the node-oracledb installation documentation. +// If the search path is not correct, you will get a DPI-1047 error. +if (process.platform === 'win32') { // Windows + oracledb.initOracleClient({ libDir: 'C:\\oracle\\instantclient_19_11' }); +} else if (process.platform === 'darwin') { // macOS + oracledb.initOracleClient({ libDir: process.env.HOME + '/Downloads/instantclient_19_8' }); +} + const inFileName = 'clobexample.txt'; // the file with text to be inserted into the database async function run() { diff --git a/javascript/node-oracledb/lobplsqltemp.js b/javascript/node-oracledb/lobplsqltemp.js index bff2fbd4..3ea9a232 100644 --- a/javascript/node-oracledb/lobplsqltemp.js +++ b/javascript/node-oracledb/lobplsqltemp.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -36,6 +36,17 @@ const oracledb = require('oracledb'); const dbConfig = require('./dbconfig.js'); const demoSetup = require('./demosetup.js'); +// On Windows and macOS, you can specify the directory containing the Oracle +// Client Libraries at runtime, or before Node.js starts. On other platforms +// the system library search path must always be set before Node.js is started. +// See the node-oracledb installation documentation. +// If the search path is not correct, you will get a DPI-1047 error. +if (process.platform === 'win32') { // Windows + oracledb.initOracleClient({ libDir: 'C:\\oracle\\instantclient_19_11' }); +} else if (process.platform === 'darwin') { // macOS + oracledb.initOracleClient({ libDir: process.env.HOME + '/Downloads/instantclient_19_8' }); +} + const inFileName = 'clobexample.txt'; // the file with text to be inserted into the database async function run() { diff --git a/javascript/node-oracledb/lobselect.js b/javascript/node-oracledb/lobselect.js index 6e74d9f8..83586994 100644 --- a/javascript/node-oracledb/lobselect.js +++ b/javascript/node-oracledb/lobselect.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -35,6 +35,17 @@ const oracledb = require('oracledb'); const dbConfig = require('./dbconfig.js'); const demoSetup = require('./demosetup.js'); +// On Windows and macOS, you can specify the directory containing the Oracle +// Client Libraries at runtime, or before Node.js starts. On other platforms +// the system library search path must always be set before Node.js is started. +// See the node-oracledb installation documentation. +// If the search path is not correct, you will get a DPI-1047 error. +if (process.platform === 'win32') { // Windows + oracledb.initOracleClient({ libDir: 'C:\\oracle\\instantclient_19_11' }); +} else if (process.platform === 'darwin') { // macOS + oracledb.initOracleClient({ libDir: process.env.HOME + '/Downloads/instantclient_19_8' }); +} + const blobOutFileName = 'lobselectout.jpg'; // file to write the BLOB to // force all queried CLOBs to be returned as Strings diff --git a/javascript/node-oracledb/lobstream1.js b/javascript/node-oracledb/lobstream1.js index b7afea10..822e16ba 100644 --- a/javascript/node-oracledb/lobstream1.js +++ b/javascript/node-oracledb/lobstream1.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -32,6 +32,17 @@ const oracledb = require('oracledb'); const dbConfig = require('./dbconfig.js'); const demoSetup = require('./demosetup.js'); +// On Windows and macOS, you can specify the directory containing the Oracle +// Client Libraries at runtime, or before Node.js starts. On other platforms +// the system library search path must always be set before Node.js is started. +// See the node-oracledb installation documentation. +// If the search path is not correct, you will get a DPI-1047 error. +if (process.platform === 'win32') { // Windows + oracledb.initOracleClient({ libDir: 'C:\\oracle\\instantclient_19_11' }); +} else if (process.platform === 'darwin') { // macOS + oracledb.initOracleClient({ libDir: process.env.HOME + '/Downloads/instantclient_19_8' }); +} + // Stream a LOB to a file async function doStream(lob, outFileName) { diff --git a/javascript/node-oracledb/lobstream2.js b/javascript/node-oracledb/lobstream2.js index b5edcb1d..d8023adf 100644 --- a/javascript/node-oracledb/lobstream2.js +++ b/javascript/node-oracledb/lobstream2.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -31,6 +31,17 @@ const oracledb = require('oracledb'); const dbConfig = require('./dbconfig.js'); const demoSetup = require('./demosetup.js'); +// On Windows and macOS, you can specify the directory containing the Oracle +// Client Libraries at runtime, or before Node.js starts. On other platforms +// the system library search path must always be set before Node.js is started. +// See the node-oracledb installation documentation. +// If the search path is not correct, you will get a DPI-1047 error. +if (process.platform === 'win32') { // Windows + oracledb.initOracleClient({ libDir: 'C:\\oracle\\instantclient_19_11' }); +} else if (process.platform === 'darwin') { // macOS + oracledb.initOracleClient({ libDir: process.env.HOME + '/Downloads/instantclient_19_8' }); +} + async function run() { let connection; diff --git a/javascript/node-oracledb/metadata.js b/javascript/node-oracledb/metadata.js index b9601ace..9c6a42db 100644 --- a/javascript/node-oracledb/metadata.js +++ b/javascript/node-oracledb/metadata.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -31,6 +31,17 @@ const oracledb = require('oracledb'); const dbConfig = require('./dbconfig.js'); const demoSetup = require('./demosetup.js'); +// On Windows and macOS, you can specify the directory containing the Oracle +// Client Libraries at runtime, or before Node.js starts. On other platforms +// the system library search path must always be set before Node.js is started. +// See the node-oracledb installation documentation. +// If the search path is not correct, you will get a DPI-1047 error. +if (process.platform === 'win32') { // Windows + oracledb.initOracleClient({ libDir: 'C:\\oracle\\instantclient_19_11' }); +} else if (process.platform === 'darwin') { // macOS + oracledb.initOracleClient({ libDir: process.env.HOME + '/Downloads/instantclient_19_8' }); +} + async function run() { let connection; diff --git a/javascript/node-oracledb/plsqlarray.js b/javascript/node-oracledb/plsqlarray.js index 11f4ed17..1f0a131a 100644 --- a/javascript/node-oracledb/plsqlarray.js +++ b/javascript/node-oracledb/plsqlarray.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -34,6 +34,17 @@ const oracledb = require('oracledb'); const dbConfig = require('./dbconfig.js'); +// On Windows and macOS, you can specify the directory containing the Oracle +// Client Libraries at runtime, or before Node.js starts. On other platforms +// the system library search path must always be set before Node.js is started. +// See the node-oracledb installation documentation. +// If the search path is not correct, you will get a DPI-1047 error. +if (process.platform === 'win32') { // Windows + oracledb.initOracleClient({ libDir: 'C:\\oracle\\instantclient_19_11' }); +} else if (process.platform === 'darwin') { // macOS + oracledb.initOracleClient({ libDir: process.env.HOME + '/Downloads/instantclient_19_8' }); +} + async function run() { let connection; @@ -93,7 +104,7 @@ async function run() { for (const s of stmts) { try { await connection.execute(s); - } catch(e) { + } catch (e) { if (e.errorNum != 942) console.error(e); } diff --git a/javascript/node-oracledb/plsqlfunc.js b/javascript/node-oracledb/plsqlfunc.js index 7c6bb2f4..edd83f27 100644 --- a/javascript/node-oracledb/plsqlfunc.js +++ b/javascript/node-oracledb/plsqlfunc.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -28,6 +28,17 @@ const oracledb = require('oracledb'); const dbConfig = require('./dbconfig.js'); +// On Windows and macOS, you can specify the directory containing the Oracle +// Client Libraries at runtime, or before Node.js starts. On other platforms +// the system library search path must always be set before Node.js is started. +// See the node-oracledb installation documentation. +// If the search path is not correct, you will get a DPI-1047 error. +if (process.platform === 'win32') { // Windows + oracledb.initOracleClient({ libDir: 'C:\\oracle\\instantclient_19_11' }); +} else if (process.platform === 'darwin') { // macOS + oracledb.initOracleClient({ libDir: process.env.HOME + '/Downloads/instantclient_19_8' }); +} + async function run() { let connection; @@ -39,9 +50,10 @@ async function run() { await connection.execute( `CREATE OR REPLACE FUNCTION no_func - (p1_in IN VARCHAR2, p2_in IN VARCHAR2) RETURN VARCHAR2 + (p1_in IN VARCHAR2, p2_in IN VARCHAR2, p3_out OUT NUMBER) RETURN VARCHAR2 AS BEGIN + p3_out := 123; RETURN p1_in || ' ' || p2_in; END;` ); @@ -50,17 +62,18 @@ async function run() { // // The equivalent call with PL/SQL named parameter syntax is: // `BEGIN - // :ret := no_func(p1_in => :p1, p2_in => :p2); + // :ret := no_func(p1_in => :p1, p2_in => :p2, p3_out => :p3); // END;` const result = await connection.execute( `BEGIN - :ret := no_func(:p1, :p2); + :ret := no_func(:p1, :p2, :p3); END;`, { p1: 'Chris', // Bind type is determined from the data. Default direction is BIND_IN p2: 'Jones', - ret: { dir: oracledb.BIND_OUT, type: oracledb.STRING, maxSize: 40 } + p3: { dir: oracledb.BIND_OUT, type: oracledb.NUMBER }, + ret: { dir: oracledb.BIND_OUT, type: oracledb.STRING, maxSize: 40 } }); console.log(result.outBinds); diff --git a/javascript/node-oracledb/plsqlproc.js b/javascript/node-oracledb/plsqlproc.js index 4a0b79b9..3e541a27 100644 --- a/javascript/node-oracledb/plsqlproc.js +++ b/javascript/node-oracledb/plsqlproc.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -28,6 +28,17 @@ const oracledb = require('oracledb'); const dbConfig = require('./dbconfig.js'); +// On Windows and macOS, you can specify the directory containing the Oracle +// Client Libraries at runtime, or before Node.js starts. On other platforms +// the system library search path must always be set before Node.js is started. +// See the node-oracledb installation documentation. +// If the search path is not correct, you will get a DPI-1047 error. +if (process.platform === 'win32') { // Windows + oracledb.initOracleClient({ libDir: 'C:\\oracle\\instantclient_19_11' }); +} else if (process.platform === 'darwin') { // macOS + oracledb.initOracleClient({ libDir: process.env.HOME + '/Downloads/instantclient_19_8' }); +} + async function run() { let connection; diff --git a/javascript/node-oracledb/plsqlrecord.js b/javascript/node-oracledb/plsqlrecord.js index a9036882..457e24e1 100644 --- a/javascript/node-oracledb/plsqlrecord.js +++ b/javascript/node-oracledb/plsqlrecord.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -32,6 +32,17 @@ const oracledb = require('oracledb'); const dbConfig = require('./dbconfig.js'); +// On Windows and macOS, you can specify the directory containing the Oracle +// Client Libraries at runtime, or before Node.js starts. On other platforms +// the system library search path must always be set before Node.js is started. +// See the node-oracledb installation documentation. +// If the search path is not correct, you will get a DPI-1047 error. +if (process.platform === 'win32') { // Windows + oracledb.initOracleClient({ libDir: 'C:\\oracle\\instantclient_19_11' }); +} else if (process.platform === 'darwin') { // macOS + oracledb.initOracleClient({ libDir: process.env.HOME + '/Downloads/instantclient_19_8' }); +} + async function run() { let connection, binds, options, result, obj; @@ -64,7 +75,7 @@ async function run() { for (const s of stmts) { try { await connection.execute(s); - } catch(e) { + } catch (e) { console.error(e); } } diff --git a/javascript/node-oracledb/plsqlvarrayrecord.js b/javascript/node-oracledb/plsqlvarrayrecord.js index fbca68d0..a27014fe 100644 --- a/javascript/node-oracledb/plsqlvarrayrecord.js +++ b/javascript/node-oracledb/plsqlvarrayrecord.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -32,6 +32,17 @@ const oracledb = require('oracledb'); const dbConfig = require('./dbconfig.js'); +// On Windows and macOS, you can specify the directory containing the Oracle +// Client Libraries at runtime, or before Node.js starts. On other platforms +// the system library search path must always be set before Node.js is started. +// See the node-oracledb installation documentation. +// If the search path is not correct, you will get a DPI-1047 error. +if (process.platform === 'win32') { // Windows + oracledb.initOracleClient({ libDir: 'C:\\oracle\\instantclient_19_11' }); +} else if (process.platform === 'darwin') { // macOS + oracledb.initOracleClient({ libDir: process.env.HOME + '/Downloads/instantclient_19_8' }); +} + async function run() { let connection; @@ -70,7 +81,7 @@ async function run() { for (const s of stmts) { try { await connection.execute(s); - } catch(e) { + } catch (e) { console.error(e); } } diff --git a/javascript/node-oracledb/raw.js b/javascript/node-oracledb/raw.js index f99a9e49..150cb674 100644 --- a/javascript/node-oracledb/raw.js +++ b/javascript/node-oracledb/raw.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -30,6 +30,17 @@ const oracledb = require('oracledb'); const dbConfig = require('./dbconfig.js'); +// On Windows and macOS, you can specify the directory containing the Oracle +// Client Libraries at runtime, or before Node.js starts. On other platforms +// the system library search path must always be set before Node.js is started. +// See the node-oracledb installation documentation. +// If the search path is not correct, you will get a DPI-1047 error. +if (process.platform === 'win32') { // Windows + oracledb.initOracleClient({ libDir: 'C:\\oracle\\instantclient_19_11' }); +} else if (process.platform === 'darwin') { // macOS + oracledb.initOracleClient({ libDir: process.env.HOME + '/Downloads/instantclient_19_8' }); +} + async function run() { let connection; @@ -50,7 +61,7 @@ async function run() { for (const s of stmts) { try { await connection.execute(s); - } catch(e) { + } catch (e) { if (e.errorNum != 942) console.error(e); } diff --git a/javascript/node-oracledb/refcursor.js b/javascript/node-oracledb/refcursor.js index 5420abad..a1c52409 100644 --- a/javascript/node-oracledb/refcursor.js +++ b/javascript/node-oracledb/refcursor.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -30,7 +30,16 @@ const oracledb = require('oracledb'); const dbConfig = require('./dbconfig.js'); const demoSetup = require('./demosetup.js'); -const numRows = 10; // number of rows to return from each call to getRows() +// On Windows and macOS, you can specify the directory containing the Oracle +// Client Libraries at runtime, or before Node.js starts. On other platforms +// the system library search path must always be set before Node.js is started. +// See the node-oracledb installation documentation. +// If the search path is not correct, you will get a DPI-1047 error. +if (process.platform === 'win32') { // Windows + oracledb.initOracleClient({ libDir: 'C:\\oracle\\instantclient_19_11' }); +} else if (process.platform === 'darwin') { // macOS + oracledb.initOracleClient({ libDir: process.env.HOME + '/Downloads/instantclient_19_8' }); +} async function run() { @@ -75,14 +84,16 @@ async function run() { // // Fetch rows from the REF CURSOR. // - // + + const resultSet = result.outBinds.cursor; + const numRows = 10; // number of rows to return from each call to getRows() + let rows; + // If getRows(numRows) returns: // Zero rows => there were no rows, or are no more rows to return // Fewer than numRows rows => this was the last set of rows to get // Exactly numRows rows => there may be more rows to fetch - const resultSet = result.outBinds.cursor; - let rows; do { rows = await resultSet.getRows(numRows); // get numRows rows at a time if (rows.length > 0) { @@ -91,6 +102,13 @@ async function run() { } } while (rows.length === numRows); + // From node-oracledb 5.2, you can alternatively fetch all rows in one call. + // This is useful when the ResultSet is known to contain a small number of + // rows that will always fit in memory. + // + // rows = await resultSet.getRows(); // no parameter means get all rows + // console.log(rows); + // always close the ResultSet await resultSet.close(); diff --git a/javascript/node-oracledb/refcursortoquerystream.js b/javascript/node-oracledb/refcursortoquerystream.js index 912a71fe..e69bdb5a 100644 --- a/javascript/node-oracledb/refcursortoquerystream.js +++ b/javascript/node-oracledb/refcursortoquerystream.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -33,6 +33,17 @@ const oracledb = require('oracledb'); const dbConfig = require('./dbconfig.js'); const demoSetup = require('./demosetup.js'); +// On Windows and macOS, you can specify the directory containing the Oracle +// Client Libraries at runtime, or before Node.js starts. On other platforms +// the system library search path must always be set before Node.js is started. +// See the node-oracledb installation documentation. +// If the search path is not correct, you will get a DPI-1047 error. +if (process.platform === 'win32') { // Windows + oracledb.initOracleClient({ libDir: 'C:\\oracle\\instantclient_19_11' }); +} else if (process.platform === 'darwin') { // macOS + oracledb.initOracleClient({ libDir: process.env.HOME + '/Downloads/instantclient_19_8' }); +} + async function run() { let connection; diff --git a/javascript/node-oracledb/resultset1.js b/javascript/node-oracledb/resultset1.js index 21d0c1f6..d78b912e 100644 --- a/javascript/node-oracledb/resultset1.js +++ b/javascript/node-oracledb/resultset1.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -31,6 +31,17 @@ const oracledb = require('oracledb'); const dbConfig = require('./dbconfig.js'); const demoSetup = require('./demosetup.js'); +// On Windows and macOS, you can specify the directory containing the Oracle +// Client Libraries at runtime, or before Node.js starts. On other platforms +// the system library search path must always be set before Node.js is started. +// See the node-oracledb installation documentation. +// If the search path is not correct, you will get a DPI-1047 error. +if (process.platform === 'win32') { // Windows + oracledb.initOracleClient({ libDir: 'C:\\oracle\\instantclient_19_11' }); +} else if (process.platform === 'darwin') { // macOS + oracledb.initOracleClient({ libDir: process.env.HOME + '/Downloads/instantclient_19_8' }); +} + async function run() { let connection; diff --git a/javascript/node-oracledb/resultset2.js b/javascript/node-oracledb/resultset2.js index dcce5eb4..b591dd21 100644 --- a/javascript/node-oracledb/resultset2.js +++ b/javascript/node-oracledb/resultset2.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -30,6 +30,17 @@ const oracledb = require('oracledb'); const dbConfig = require('./dbconfig.js'); const demoSetup = require('./demosetup.js'); +// On Windows and macOS, you can specify the directory containing the Oracle +// Client Libraries at runtime, or before Node.js starts. On other platforms +// the system library search path must always be set before Node.js is started. +// See the node-oracledb installation documentation. +// If the search path is not correct, you will get a DPI-1047 error. +if (process.platform === 'win32') { // Windows + oracledb.initOracleClient({ libDir: 'C:\\oracle\\instantclient_19_11' }); +} else if (process.platform === 'darwin') { // macOS + oracledb.initOracleClient({ libDir: process.env.HOME + '/Downloads/instantclient_19_8' }); +} + // Number of rows to return from each call to getRows() const numRows = 2; diff --git a/javascript/node-oracledb/resultsettoquerystream.js b/javascript/node-oracledb/resultsettoquerystream.js index 14401202..9cbcbeb6 100644 --- a/javascript/node-oracledb/resultsettoquerystream.js +++ b/javascript/node-oracledb/resultsettoquerystream.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -30,6 +30,17 @@ const oracledb = require('oracledb'); const dbConfig = require('./dbconfig.js'); const demoSetup = require('./demosetup.js'); +// On Windows and macOS, you can specify the directory containing the Oracle +// Client Libraries at runtime, or before Node.js starts. On other platforms +// the system library search path must always be set before Node.js is started. +// See the node-oracledb installation documentation. +// If the search path is not correct, you will get a DPI-1047 error. +if (process.platform === 'win32') { // Windows + oracledb.initOracleClient({ libDir: 'C:\\oracle\\instantclient_19_11' }); +} else if (process.platform === 'darwin') { // macOS + oracledb.initOracleClient({ libDir: process.env.HOME + '/Downloads/instantclient_19_8' }); +} + async function run() { let connection; diff --git a/javascript/node-oracledb/rowlimit.js b/javascript/node-oracledb/rowlimit.js index c9bb8052..c5faaac8 100644 --- a/javascript/node-oracledb/rowlimit.js +++ b/javascript/node-oracledb/rowlimit.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -35,6 +35,17 @@ const oracledb = require('oracledb'); const dbConfig = require('./dbconfig.js'); const demoSetup = require('./demosetup.js'); +// On Windows and macOS, you can specify the directory containing the Oracle +// Client Libraries at runtime, or before Node.js starts. On other platforms +// the system library search path must always be set before Node.js is started. +// See the node-oracledb installation documentation. +// If the search path is not correct, you will get a DPI-1047 error. +if (process.platform === 'win32') { // Windows + oracledb.initOracleClient({ libDir: 'C:\\oracle\\instantclient_19_11' }); +} else if (process.platform === 'darwin') { // macOS + oracledb.initOracleClient({ libDir: process.env.HOME + '/Downloads/instantclient_19_8' }); +} + const myoffset = 1; // number of rows to skip const mymaxnumrows = 2; // number of rows to fetch diff --git a/javascript/node-oracledb/select1.js b/javascript/node-oracledb/select1.js index 1c3996dc..67a4bad9 100644 --- a/javascript/node-oracledb/select1.js +++ b/javascript/node-oracledb/select1.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -35,6 +35,17 @@ const oracledb = require('oracledb'); const dbConfig = require('./dbconfig.js'); const demoSetup = require('./demosetup.js'); +// On Windows and macOS, you can specify the directory containing the Oracle +// Client Libraries at runtime, or before Node.js starts. On other platforms +// the system library search path must always be set before Node.js is started. +// See the node-oracledb installation documentation. +// If the search path is not correct, you will get a DPI-1047 error. +if (process.platform === 'win32') { // Windows + oracledb.initOracleClient({ libDir: 'C:\\oracle\\instantclient_19_11' }); +} else if (process.platform === 'darwin') { // macOS + oracledb.initOracleClient({ libDir: process.env.HOME + '/Downloads/instantclient_19_8' }); +} + async function run() { let connection; diff --git a/javascript/node-oracledb/select2.js b/javascript/node-oracledb/select2.js index bcc68dc7..d7a1e0e9 100644 --- a/javascript/node-oracledb/select2.js +++ b/javascript/node-oracledb/select2.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -32,6 +32,17 @@ const oracledb = require('oracledb'); const dbConfig = require('./dbconfig.js'); const demoSetup = require('./demosetup.js'); +// On Windows and macOS, you can specify the directory containing the Oracle +// Client Libraries at runtime, or before Node.js starts. On other platforms +// the system library search path must always be set before Node.js is started. +// See the node-oracledb installation documentation. +// If the search path is not correct, you will get a DPI-1047 error. +if (process.platform === 'win32') { // Windows + oracledb.initOracleClient({ libDir: 'C:\\oracle\\instantclient_19_11' }); +} else if (process.platform === 'darwin') { // macOS + oracledb.initOracleClient({ libDir: process.env.HOME + '/Downloads/instantclient_19_8' }); +} + // Oracledb properties are applicable to all connections and SQL // executions. They can also be set or overridden at the individual // execute() call level diff --git a/javascript/node-oracledb/selectgeometry.js b/javascript/node-oracledb/selectgeometry.js index 23c6909f..f632344a 100644 --- a/javascript/node-oracledb/selectgeometry.js +++ b/javascript/node-oracledb/selectgeometry.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -32,6 +32,21 @@ const oracledb = require('oracledb'); const dbConfig = require('./dbconfig.js'); +// On Windows and macOS, you can specify the directory containing the Oracle +// Client Libraries at runtime, or before Node.js starts. On other platforms +// the system library search path must always be set before Node.js is started. +// See the node-oracledb installation documentation. +// If the search path is not correct, you will get a DPI-1047 error. +if (process.platform === 'win32') { // Windows + oracledb.initOracleClient({ libDir: 'C:\\oracle\\instantclient_19_11' }); +} else if (process.platform === 'darwin') { // macOS + oracledb.initOracleClient({ libDir: process.env.HOME + '/Downloads/instantclient_19_8' }); +} + +// If each object's attributes are accessed multiple times, it may be more +// efficient to fetch as simple JavaScriptobjects. +// oracledb.dbObjectAsPojo = true; + async function run() { let connection, result; @@ -52,7 +67,7 @@ async function run() { for (const s of stmts) { try { await connection.execute(s); - } catch(e) { + } catch (e) { if (e.errorNum != 942) console.error(e); } diff --git a/javascript/node-oracledb/selectjson.js b/javascript/node-oracledb/selectjson.js index 75671482..714d43c5 100644 --- a/javascript/node-oracledb/selectjson.js +++ b/javascript/node-oracledb/selectjson.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -19,11 +19,13 @@ * selectjson.js * * DESCRIPTION - * Shows some JSON features of Oracle Database 12c. - * - * Requires at least Oracle Database 12.1.0.2, which has extensive JSON datatype support. + * Shows some JSON features of Oracle Database 21c. * See https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=ADJSN * + * For JSON with older databases see selectjsonblob.js + * + * This example requires node-oracledb 5.1 or later. + * * This example uses Node 8's async/await syntax. * *****************************************************************************/ @@ -31,79 +33,108 @@ const oracledb = require('oracledb'); const dbConfig = require('./dbconfig.js'); +// On Windows and macOS, you can specify the directory containing the Oracle +// Client Libraries at runtime, or before Node.js starts. On other platforms +// the system library search path must always be set before Node.js is started. +// See the node-oracledb installation documentation. +// If the search path is not correct, you will get a DPI-1047 error. +if (process.platform === 'win32') { // Windows + oracledb.initOracleClient({ libDir: 'C:\\oracle\\instantclient_19_11' }); +} else if (process.platform === 'darwin') { // macOS + oracledb.initOracleClient({ libDir: process.env.HOME + '/Downloads/instantclient_19_8' }); +} + +oracledb.extendedMetaData = true; + async function run() { let connection; try { + connection = await oracledb.getConnection(dbConfig); - if (connection.oracleServerVersion < 1201000200) { - throw new Error('This example only works with Oracle Database 12.1.0.2 or greater'); + if (connection.oracleServerVersion < 2100000000) { + throw new Error('This example requires Oracle Database 21.1 or later. Try selectjsonblob.js.'); } - const stmts = [ - `DROP TABLE no_purchaseorder`, + console.log('1. Creating Table'); - // Note if your applications always insert valid JSON, you may delete - // the IS JSON check to remove its additional validation overhead. - `CREATE TABLE no_purchaseorder (po_document VARCHAR2(4000) CHECK (po_document IS JSON))` - ]; + try { + await connection.execute(`DROP TABLE no_purchaseorder`); + } catch (e) { + if (e.errorNum != 942) + console.error(e); + } - for (const s of stmts) { - try { - await connection.execute(s); - } catch(e) { - if (e.errorNum != 942) - console.error(e); - } + connection.execute(`CREATE TABLE no_purchaseorder (po_document JSON)`); + + console.log('2. Inserting Data'); + + const inssql = `INSERT INTO no_purchaseorder (po_document) VALUES (:bv)`; + const data = { "userId": 1, "userName": "Anna", "location": "Australia" }; + if (oracledb.oracleClientVersion >= 2100000000) { + await connection.execute(inssql, { bv: { val: data, type: oracledb.DB_TYPE_JSON } }); + } else { + // With older client versions, insert as a JSON string + const s = JSON.stringify(data); + const b = Buffer.from(s, 'utf8'); + await connection.execute(inssql, { bv: { val: b } }); } - let result; + let result, j; - console.log('Inserting Data'); - const data = { "userId": 1, "userName": "Chris", "location": "Australia" }; - const s = JSON.stringify(data); - await connection.execute( - `INSERT INTO no_purchaseorder (po_document) VALUES (:bv)`, - [s], // bind the JSON string for inserting into the JSON column. - { autoCommit: true } - ); + console.log('3. Selecting JSON stored in a column'); - console.log('1. Selecting JSON stored in a VARCHAR2 column'); result = await connection.execute( `SELECT po_document FROM no_purchaseorder - WHERE JSON_EXISTS (po_document, '$.location')` + WHERE JSON_EXISTS (po_document, '$.location') + OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY` ); - const js = JSON.parse(result.rows[0][0]); // just show first record - console.log('Query results: ', js); + if (result.metaData[0].fetchType == oracledb.DB_TYPE_JSON) { + j = result.rows[0][0]; + } else { + // Oracle Client libraries < 21 will return a BLOB + const d = await result.rows[0][0].getData(); + j = await JSON.parse(d); + } + console.log('Query results: ', j); + + console.log('4. Using JSON_VALUE to extract a value from a JSON column'); - console.log('2. Using JSON_VALUE to extract a value from a JSON column'); result = await connection.execute( `SELECT JSON_VALUE(po_document, '$.location') - FROM no_purchaseorder` + FROM no_purchaseorder + OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY` ); console.log('Query results: ', result.rows[0][0]); // just show first record - if (connection.oracleServerVersion < 1202000000) { - throw new Error('These examples only work with Oracle Database 12.2 or greater'); - } + console.log('5. Using dot-notation to extract a value from a JSON column'); - console.log('3. Using dot-notation to extract a value from a JSON column'); result = await connection.execute( `SELECT po.po_document.location - FROM no_purchaseorder po` + FROM no_purchaseorder po + OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY` ); - console.log('Query results: ', result.rows[0][0]); // just show first record + if (result.metaData[0].fetchType == oracledb.DB_TYPE_JSON) { + j = result.rows[0][0]; + } else { + // Oracle Client libraries < 21 will return a BLOB + const d = await result.rows[0][0].getData(); + j = await JSON.parse(d); + } + console.log('Query results: ', j); + + console.log('6. Using JSON_OBJECT to extract relational data as JSON'); - console.log('4. Using JSON_OBJECT to extract relational data as JSON'); result = await connection.execute( `SELECT JSON_OBJECT('key' IS d.dummy) dummy FROM dual d` ); - for (let row of result.rows) - console.log(row[0]); + for (let row of result.rows) { + console.log('Query results: ', row[0]); + } } catch (err) { console.error(err); diff --git a/javascript/node-oracledb/selectjsonblob.js b/javascript/node-oracledb/selectjsonblob.js index 8140f45d..35ce953d 100644 --- a/javascript/node-oracledb/selectjsonblob.js +++ b/javascript/node-oracledb/selectjsonblob.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -19,12 +19,13 @@ * selectjsonblob.js * * DESCRIPTION - * Executes sample insert and query statements using a JSON column with BLOB storage. + * Shows how to use a BLOB as a JSON column store. * - * Requires Oracle Database 12.1.0.2, which has extensive JSON datatype support. - * See https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=ADJSN + * Note: with Oracle Database 21c using the new JSON type is recommended + * instead, see selectjson.js * - * This example requires node-oracledb 1.13 or later. + * Requires Oracle Database 12.1.0.2 or later. + * See https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=ADJSN * * This example uses Node 8's async/await syntax. * @@ -33,6 +34,19 @@ const oracledb = require('oracledb'); const dbConfig = require('./dbconfig.js'); +// On Windows and macOS, you can specify the directory containing the Oracle +// Client Libraries at runtime, or before Node.js starts. On other platforms +// the system library search path must always be set before Node.js is started. +// See the node-oracledb installation documentation. +// If the search path is not correct, you will get a DPI-1047 error. +if (process.platform === 'win32') { // Windows + oracledb.initOracleClient({ libDir: 'C:\\oracle\\instantclient_19_11' }); +} else if (process.platform === 'darwin') { // macOS + oracledb.initOracleClient({ libDir: process.env.HOME + '/Downloads/instantclient_19_8' }); +} + +oracledb.extendedMetaData = true; + async function run() { let connection; @@ -42,58 +56,81 @@ async function run() { connection = await oracledb.getConnection(dbConfig); if (connection.oracleServerVersion < 1201000200) { - throw new Error('This example only works with Oracle Database 12.1.0.2 or greater'); + throw new Error('Using JSON requires Oracle Database 12.1.0.2 or later'); } - const stmts = [ - `DROP TABLE no_purchaseorder_b`, + console.log('1. Creating Table'); - `CREATE TABLE no_purchaseorder_b (po_document BLOB CHECK (po_document IS JSON)) LOB (po_document) STORE AS (CACHE)` - ]; + try { + await connection.execute(`DROP TABLE no_purchaseorder_b`); + } catch (e) { + if (e.errorNum != 942) + console.error(e); + } - for (const s of stmts) { - try { - await connection.execute(s); - } catch(e) { - if (e.errorNum != 942) - console.error(e); - } + await connection.execute( + `CREATE TABLE no_purchaseorder_b + (po_document BLOB CHECK (po_document IS JSON)) LOB (po_document) STORE AS (CACHE)`); + + console.log('2. Inserting Data'); + + const inssql = `INSERT INTO no_purchaseorder_b (po_document) VALUES (:bv)`; + const data = { "userId": 1, "userName": "Anna", "location": "Australia" }; + + if (oracledb.oracleClientVersion >= 2100000000 && connection.oracleServerVersion >= 2100000000) { + // Take advantage of direct binding of JavaScript objects + await connection.execute(inssql, { bv: { val: data, type: oracledb.DB_TYPE_JSON } }); + } else { + // Insert the data as a JSON string + const s = JSON.stringify(data); + const b = Buffer.from(s, 'utf8'); + await connection.execute(inssql, { bv: { val: b } }); } - let result; + console.log('3. Selecting JSON stored in a BLOB column'); - console.log('Inserting Data'); - const data = { "userId": 2, "userName": "Bob", "location": "USA" }; - const s = JSON.stringify(data); - const b = Buffer.from(s, 'utf8'); - await connection.execute( - `INSERT INTO no_purchaseorder_b (po_document) VALUES (:lobbv)`, - { lobbv: b } - ); + let result, j; - console.log('Selecting JSON stored in a BLOB column:'); result = await connection.execute( `SELECT po_document FROM no_purchaseorder_b - WHERE JSON_EXISTS (po_document, '$.location')`, - [], - { fetchInfo: { "PO_DOCUMENT": { type: oracledb.BUFFER } } } // Fetch as a Buffer instead of a Stream + WHERE JSON_EXISTS (po_document, '$.location') + OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY` ); - if (result.rows.length === 0) - throw new Error('No results'); - console.log(result.rows[0][0].toString('utf8')); + const d = await result.rows[0][0].getData(); + j = await JSON.parse(d); + console.log('Query results: ', j); + + console.log('4. Using JSON_VALUE to extract a value from a JSON column'); - console.log('Selecting a JSON value using "dotted" notation:'); - if (connection.oracleServerVersion < 1202000000) { - throw new Error('This example only works with Oracle Database 12.2 or greater'); - } result = await connection.execute( - `SELECT pob.po_document.location - FROM no_purchaseorder_b pob` + `SELECT JSON_VALUE(po_document, '$.location') + FROM no_purchaseorder_b + OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY` ); - if (result.rows.length === 0) - throw new Error('No results'); - console.log(result.rows[0][0]); + console.log('Query results: ', result.rows[0][0]); // just show first record + + if (connection.oracleServerVersion >= 1202000000) { + + console.log('5. Using dot-notation to extract a value from a JSON column'); + + result = await connection.execute( + `SELECT po.po_document.location + FROM no_purchaseorder_b po + OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY` + ); + console.log('Query results: ', result.rows[0][0]); + + console.log('6. Using JSON_OBJECT to extract relational data as JSON'); + + result = await connection.execute( + `SELECT JSON_OBJECT('key' IS d.dummy) dummy + FROM dual d` + ); + for (let row of result.rows) { + console.log('Query results: ', row[0]); + } + } } catch (err) { console.error(err); diff --git a/javascript/node-oracledb/selectnestedcursor.js b/javascript/node-oracledb/selectnestedcursor.js index 720d4edc..2959315a 100644 --- a/javascript/node-oracledb/selectnestedcursor.js +++ b/javascript/node-oracledb/selectnestedcursor.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -26,12 +26,20 @@ * *****************************************************************************/ -// Using a fixed Oracle time zone helps avoid machine and deployment differences -process.env.ORA_SDTZ = 'UTC'; - const oracledb = require('oracledb'); const dbConfig = require('./dbconfig.js'); +// On Windows and macOS, you can specify the directory containing the Oracle +// Client Libraries at runtime, or before Node.js starts. On other platforms +// the system library search path must always be set before Node.js is started. +// See the node-oracledb installation documentation. +// If the search path is not correct, you will get a DPI-1047 error. +if (process.platform === 'win32') { // Windows + oracledb.initOracleClient({ libDir: 'C:\\oracle\\instantclient_19_11' }); +} else if (process.platform === 'darwin') { // macOS + oracledb.initOracleClient({ libDir: process.env.HOME + '/Downloads/instantclient_19_8' }); +} + async function run() { let connection; @@ -58,7 +66,7 @@ async function run() { for (const s of stmts) { try { await connection.execute(s); - } catch(e) { + } catch (e) { if (e.errorNum != 942) console.error(e); } diff --git a/javascript/node-oracledb/selectobject.js b/javascript/node-oracledb/selectobject.js index 47c28c10..5c326545 100644 --- a/javascript/node-oracledb/selectobject.js +++ b/javascript/node-oracledb/selectobject.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -33,6 +33,21 @@ const oracledb = require('oracledb'); const dbConfig = require('./dbconfig.js'); +// On Windows and macOS, you can specify the directory containing the Oracle +// Client Libraries at runtime, or before Node.js starts. On other platforms +// the system library search path must always be set before Node.js is started. +// See the node-oracledb installation documentation. +// If the search path is not correct, you will get a DPI-1047 error. +if (process.platform === 'win32') { // Windows + oracledb.initOracleClient({ libDir: 'C:\\oracle\\instantclient_19_11' }); +} else if (process.platform === 'darwin') { // macOS + oracledb.initOracleClient({ libDir: process.env.HOME + '/Downloads/instantclient_19_8' }); +} + +// If each object's attributes are accessed multiple times, it may be more +// efficient to fetch as simple JavaScriptobjects. +// oracledb.dbObjectAsPojo = true; + async function run() { let connection, result; @@ -64,7 +79,7 @@ async function run() { for (const s of stmts) { try { await connection.execute(s); - } catch(e) { + } catch (e) { if (e.errorNum != 942 && e.errorNum != 4043) console.error(e); } diff --git a/javascript/node-oracledb/selectstream.js b/javascript/node-oracledb/selectstream.js index bfd84732..171fcdec 100644 --- a/javascript/node-oracledb/selectstream.js +++ b/javascript/node-oracledb/selectstream.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -31,6 +31,17 @@ const oracledb = require('oracledb'); const dbConfig = require('./dbconfig.js'); const demoSetup = require('./demosetup.js'); +// On Windows and macOS, you can specify the directory containing the Oracle +// Client Libraries at runtime, or before Node.js starts. On other platforms +// the system library search path must always be set before Node.js is started. +// See the node-oracledb installation documentation. +// If the search path is not correct, you will get a DPI-1047 error. +if (process.platform === 'win32') { // Windows + oracledb.initOracleClient({ libDir: 'C:\\oracle\\instantclient_19_11' }); +} else if (process.platform === 'darwin') { // macOS + oracledb.initOracleClient({ libDir: process.env.HOME + '/Downloads/instantclient_19_8' }); +} + async function run() { let connection; @@ -39,7 +50,7 @@ async function run() { await demoSetup.setupBf(connection); // create the demo table - const stream = await connection.queryStream( + const stream = connection.queryStream( `SELECT farmer, weight FROM no_banana_farmer ORDER BY id`, diff --git a/javascript/node-oracledb/selectvarray.js b/javascript/node-oracledb/selectvarray.js index cdeb93ec..8b7d0b45 100644 --- a/javascript/node-oracledb/selectvarray.js +++ b/javascript/node-oracledb/selectvarray.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -32,6 +32,17 @@ const oracledb = require('oracledb'); const dbConfig = require('./dbconfig.js'); +// On Windows and macOS, you can specify the directory containing the Oracle +// Client Libraries at runtime, or before Node.js starts. On other platforms +// the system library search path must always be set before Node.js is started. +// See the node-oracledb installation documentation. +// If the search path is not correct, you will get a DPI-1047 error. +if (process.platform === 'win32') { // Windows + oracledb.initOracleClient({ libDir: 'C:\\oracle\\instantclient_19_11' }); +} else if (process.platform === 'darwin') { // macOS + oracledb.initOracleClient({ libDir: process.env.HOME + '/Downloads/instantclient_19_8' }); +} + async function run() { let connection; @@ -60,7 +71,7 @@ async function run() { for (const s of stmts) { try { await connection.execute(s); - } catch(e) { + } catch (e) { if (e.errorNum != 942 && e.errorNum != 4043) console.error(e); } diff --git a/javascript/node-oracledb/sessionfixup.js b/javascript/node-oracledb/sessionfixup.js index 99730c99..3bb2aa30 100644 --- a/javascript/node-oracledb/sessionfixup.js +++ b/javascript/node-oracledb/sessionfixup.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -46,16 +46,27 @@ const oracledb = require('oracledb'); const dbConfig = require('./dbconfig.js'); const httpPort = 7000; +// On Windows and macOS, you can specify the directory containing the Oracle +// Client Libraries at runtime, or before Node.js starts. On other platforms +// the system library search path must always be set before Node.js is started. +// See the node-oracledb installation documentation. +// If the search path is not correct, you will get a DPI-1047 error. +if (process.platform === 'win32') { // Windows + oracledb.initOracleClient({ libDir: 'C:\\oracle\\instantclient_19_11' }); +} else if (process.platform === 'darwin') { // macOS + oracledb.initOracleClient({ libDir: process.env.HOME + '/Downloads/instantclient_19_8' }); +} + // initSession() will be invoked internally when each brand new pooled -// connection is first used. Its callback function 'cb' should be +// connection is first used. Its callback function 'callbackFn' 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) { +function initSession(connection, requestedTag, callbackFn) { console.log('In initSession'); - connection.execute(`ALTER SESSION SET TIME_ZONE = 'UTC'`, cb); + connection.execute(`ALTER SESSION SET TIME_ZONE = 'UTC'`, callbackFn); } async function init() { @@ -116,7 +127,7 @@ async function closePoolAndExit() { // Database are 19c (or later). await oracledb.getPool().close(3); process.exit(0); - } catch(err) { + } catch (err) { console.error(err.message); process.exit(1); } diff --git a/javascript/node-oracledb/sessiontagging1.js b/javascript/node-oracledb/sessiontagging1.js index eff24dcf..ae7b9452 100644 --- a/javascript/node-oracledb/sessiontagging1.js +++ b/javascript/node-oracledb/sessiontagging1.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -49,21 +49,32 @@ const oracledb = require('oracledb'); const dbConfig = require('./dbconfig.js'); const httpPort = 7000; +// On Windows and macOS, you can specify the directory containing the Oracle +// Client Libraries at runtime, or before Node.js starts. On other platforms +// the system library search path must always be set before Node.js is started. +// See the node-oracledb installation documentation. +// If the search path is not correct, you will get a DPI-1047 error. +if (process.platform === 'win32') { // Windows + oracledb.initOracleClient({ libDir: 'C:\\oracle\\instantclient_19_11' }); +} else if (process.platform === 'darwin') { // macOS + oracledb.initOracleClient({ libDir: process.env.HOME + '/Downloads/instantclient_19_8' }); +} + // 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. +// returned. Its callback function 'callbackFn' 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) { +function initSession(connection, requestedTag, callbackFn) { 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')); + callbackFn(new Error('Error: Only property USER_TZ is supported')); return; } @@ -74,7 +85,7 @@ function initSession(connection, requestedTag, cb) { `ALTER SESSION SET TIME_ZONE = '${tagParts[1]}'`, (err) => { connection.tag = requestedTag; // Record the connection's new state - cb(err); + callbackFn(err); } ); } @@ -130,7 +141,7 @@ async function handleRequest(request, response) { // the desired session state be set. connection = await oracledb.getConnection({poolAlias: 'default', tag: sessionTagNeeded /*, matchAnyTag: true */}); const 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]}`); + console.log(`getConnection() tag needed was ${sessionTagNeeded}\n ${result.rows[0][0]}`); } catch (err) { console.error(err.message); } finally { @@ -156,7 +167,7 @@ async function closePoolAndExit() { // Database are 19c (or later). await oracledb.getPool().close(3); process.exit(0); - } catch(err) { + } catch (err) { console.error(err.message); process.exit(1); } diff --git a/javascript/node-oracledb/sessiontagging2.js b/javascript/node-oracledb/sessiontagging2.js index fd74d51d..1ec2f106 100644 --- a/javascript/node-oracledb/sessiontagging2.js +++ b/javascript/node-oracledb/sessiontagging2.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -49,11 +49,22 @@ const oracledb = require('oracledb'); const dbConfig = require('./dbconfig.js'); const httpPort = 7000; +// On Windows and macOS, you can specify the directory containing the Oracle +// Client Libraries at runtime, or before Node.js starts. On other platforms +// the system library search path must always be set before Node.js is started. +// See the node-oracledb installation documentation. +// If the search path is not correct, you will get a DPI-1047 error. +if (process.platform === 'win32') { // Windows + oracledb.initOracleClient({ libDir: 'C:\\oracle\\instantclient_19_11' }); +} else if (process.platform === 'darwin') { // macOS + oracledb.initOracleClient({ libDir: process.env.HOME + '/Downloads/instantclient_19_8' }); +} + // 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. +// connection tag and a connection without an identical tag is returned. +// Its callback function 'callbackFn' 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 @@ -64,17 +75,21 @@ const httpPort = 7000; // asked for in requestedTag. These can be reset, as needed. // // See sessiontagging1.js for a simpler implementation. -function initSession(connection, requestedTag, cb) { +function initSession(connection, requestedTag, callbackFn) { 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];}); + 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];}); + 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 @@ -100,12 +115,12 @@ function initSession(connection, requestedTag, cb) { case 'UTC': break; default: - cb(new Error(`Error: Invalid time zone value ${requestedProperties[k]}`)); + callbackFn(new Error(`Error: Invalid time zone value ${requestedProperties[k]}`)); return; } // add Allow Listing code to check other properties and values here } else { - cb(new Error(`Error: Invalid connection tag property ${k}`)); + callbackFn(new Error(`Error: Invalid connection tag property ${k}`)); return; } s += `${k}='${requestedProperties[k]}' `; @@ -123,7 +138,7 @@ function initSession(connection, requestedTag, cb) { for (let k in actualProperties) { connection.tag += `${k}=${actualProperties[k]};`; } - cb(err); + callbackFn(err); } ); } else { @@ -131,7 +146,7 @@ function initSession(connection, requestedTag, cb) { // why initSession was called), but the properties that this // function validates are already set, so there is no need to call // ALTER SESSION - cb(); + callbackFn(); } } @@ -187,7 +202,7 @@ async function handleRequest(request, response) { // the desired session state be set. connection = await oracledb.getConnection({poolAlias: 'default', tag: sessionTagNeeded /*, matchAnyTag: true */}); const 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]}`); + console.log(`getConnection() tag needed was ${sessionTagNeeded}\n ${result.rows[0][0]}`); } catch (err) { console.error(err.message); } finally { @@ -213,7 +228,7 @@ async function closePoolAndExit() { // Database are 19c (or later). await oracledb.getPool().close(3); process.exit(0); - } catch(err) { + } catch (err) { console.error(err.message); process.exit(1); } diff --git a/javascript/node-oracledb/soda1.js b/javascript/node-oracledb/soda1.js index 625fc65f..3172d8ad 100644 --- a/javascript/node-oracledb/soda1.js +++ b/javascript/node-oracledb/soda1.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -34,6 +34,17 @@ const oracledb = require('oracledb'); const dbConfig = require('./dbconfig.js'); +// On Windows and macOS, you can specify the directory containing the Oracle +// Client Libraries at runtime, or before Node.js starts. On other platforms +// the system library search path must always be set before Node.js is started. +// See the node-oracledb installation documentation. +// If the search path is not correct, you will get a DPI-1047 error. +if (process.platform === 'win32') { // Windows + oracledb.initOracleClient({ libDir: 'C:\\oracle\\instantclient_19_11' }); +} else if (process.platform === 'darwin') { // macOS + oracledb.initOracleClient({ libDir: process.env.HOME + '/Downloads/instantclient_19_8' }); +} + // The general recommendation for simple SODA usage is to enable autocommit oracledb.autoCommit = true; @@ -45,7 +56,7 @@ async function run() { connection = await oracledb.getConnection(dbConfig); if (oracledb.oracleClientVersion < 1803000000) { - throw new Error('node-oracledb SODA requires Oracle Client libaries 18.3 or greater'); + throw new Error('node-oracledb SODA requires Oracle Client libraries 18.3 or greater'); } if (connection.oracleServerVersion < 1803000000) { @@ -55,9 +66,31 @@ async function run() { // Create the parent object for SODA const soda = connection.getSodaDatabase(); + // Explicit metadata is used for maximum version portability. + // Refer to the documentation. + const md = { + "keyColumn": { + "name":"ID" + }, + "contentColumn": { + "name": "JSON_DOCUMENT", + "sqlType": "BLOB" + }, + "versionColumn": { + "name": "VERSION", + "method": "UUID" + }, + "lastModifiedColumn": { + "name": "LAST_MODIFIED" + }, + "creationTimeColumn": { + "name": "CREATED_ON" + } + }; + // Create a new SODA collection and index // This will open an existing collection, if the name is already in use. - collection = await soda.createCollection("mycollection"); + collection = await soda.createCollection("mycollection", { metaData: md }); const indexSpec = { "name": "CITY_IDX", "fields": [ { "path": "address.city", diff --git a/javascript/node-oracledb/version.js b/javascript/node-oracledb/version.js index e75e96b4..873ffff3 100644 --- a/javascript/node-oracledb/version.js +++ b/javascript/node-oracledb/version.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -30,6 +30,17 @@ const oracledb = require('oracledb'); const dbConfig = require('./dbconfig.js'); +// On Windows and macOS, you can specify the directory containing the Oracle +// Client Libraries at runtime, or before Node.js starts. On other platforms +// the system library search path must always be set before Node.js is started. +// See the node-oracledb installation documentation. +// If the search path is not correct, you will get a DPI-1047 error. +if (process.platform === 'win32') { // Windows + oracledb.initOracleClient({ libDir: 'C:\\oracle\\instantclient_19_11' }); +} else if (process.platform === 'darwin') { // macOS + oracledb.initOracleClient({ libDir: process.env.HOME + '/Downloads/instantclient_19_8' }); +} + console.log("Run at: " + new Date()); console.log("Node.js version: " + process.version + " (" + process.platform, process.arch + ")"); diff --git a/javascript/node-oracledb/webappawait.js b/javascript/node-oracledb/webapp.js similarity index 72% rename from javascript/node-oracledb/webappawait.js rename to javascript/node-oracledb/webapp.js index 313ed88a..a5dc88ab 100644 --- a/javascript/node-oracledb/webappawait.js +++ b/javascript/node-oracledb/webapp.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** * @@ -16,7 +16,7 @@ * limitations under the License. * * NAME - * webappawait.js + * webapp.js * * DESCRIPTION * A web based application displaying banana harvest details. @@ -30,7 +30,7 @@ * * In production applications, set poolMin=poolMax (and poolIncrement=0) * - * This example requires node-oracledb 3 or later. + * This example requires node-oracledb 5 or later. * * This example uses Node 8's async/await syntax. * @@ -39,15 +39,32 @@ // If you increase poolMax, you must increase UV_THREADPOOL_SIZE before Node.js // starts its thread pool. If you set UV_THREADPOOL_SIZE too late, the value is // ignored and the default size of 4 is used. -// process.env.UV_THREADPOOL_SIZE = 4; +// process.env.UV_THREADPOOL_SIZE = 10; // set threadpool size to 10 +// +// Note on Windows you must set the UV_THREADPOOL_SIZE environment variable before +// running your application. const http = require('http'); const oracledb = require('oracledb'); const dbConfig = require('./dbconfig.js'); const demoSetup = require('./demosetup.js'); +// On Windows and macOS, you can specify the directory containing the Oracle +// Client Libraries at runtime, or before Node.js starts. On other platforms +// the system library search path must always be set before Node.js is started. +// See the node-oracledb installation documentation. +// If the search path is not correct, you will get a DPI-1047 error. +if (process.platform === 'win32') { // Windows + oracledb.initOracleClient({ libDir: 'C:\\oracle\\instantclient_19_11' }); +} else if (process.platform === 'darwin') { // macOS + oracledb.initOracleClient({ libDir: process.env.HOME + '/Downloads/instantclient_19_8' }); +} + const httpPort = 7000; +// If additionally using Database Resident Connection Pooling (DRCP), then set a connection class: +// oracledb.connectionClass = 'MYAPPNAME'; + // Main entry point. Creates a connection pool and an HTTP server // that executes a query based on the URL parameter given. // The pool values shown are the default values. @@ -69,9 +86,10 @@ async function init() { // poolTimeout: 60, // terminate connections that are idle in the pool for 60 seconds // queueMax: 500, // don't allow more than 500 unsatisfied getConnection() calls in the pool queue // queueTimeout: 60000, // terminate getConnection() calls queued for longer than 60000 milliseconds - // sessionCallback: myFunction, // function invoked for brand new connections or by a connection tag mismatch + // sessionCallback: initSession, // function invoked for brand new connections or by a connection tag mismatch + // sodaMetaDataCache: false, // Set true to improve SODA collection access performance // stmtCacheSize: 30, // number of statements that are cached in the statement cache of each connection - // _enableStats: false // record pool usage statistics that can be output with pool._logStats() + // enableStatistics: false // record pool usage for oracledb.getPool().getStatistics() and logStatistics() }); // create the demo table @@ -95,18 +113,20 @@ async function init() { } } +// initSession() is configured by the pool sessionCallback property. +// It will be invoked internally when each brand new pooled connection +// is first used. See the sessionfixup.js and sessiontaggingX.js examples. +/* +function initSession(connection, requestedTag, cb) { + connection.execute(`ALTER SESSION SET ...'`, cb); +} +*/ + async function handleRequest(request, response) { const urlparts = request.url.split("/"); const id = urlparts[1]; - htmlHeader( - response, - "Banana Farmer Demonstration", - "Example using node-oracledb driver" - ); - if (id == 'favicon.ico') { // ignore requests for the icon - htmlFooter(response); return; } @@ -132,7 +152,12 @@ async function handleRequest(request, response) { [id] // bind variable value ); - displayResults(response, result, id); + displayResults( + response, + "Banana Farmer Demonstration", + "Example using node-oracledb driver", + result, + id); } catch (err) { handleError(response, "handleRequest() error", err); @@ -146,24 +171,31 @@ async function handleRequest(request, response) { } } } - htmlFooter(response); -} - -// Report an error -function handleError(response, text, err) { - if (err) { - text += ": " + err.message; - } - console.error(text); - response.write("

Error: " + text + "

"); } // Display query results -function displayResults(response, result, id) { +function displayResults(response, title, caption, result, id) { + + response.writeHead(200, {"Content-Type": "text/html"}); + response.write(""); + response.write(""); + response.write(""); + response.write("\n"); + response.write("" + caption + ""); + response.write(""); + response.write(""); + response.write("

" + title + "

"); + response.write("

" + "Harvest details for farmer " + id + "

"); + response.write(""); - // Column Title + // Column Titles response.write(""); for (let col = 0; col < result.metaData.length; col++) { response.write(""); @@ -179,29 +211,20 @@ function displayResults(response, result, id) { response.write(""); } response.write("
" + result.metaData[col].name + "
"); -} -// Prepare HTML header -function htmlHeader(response, title, caption) { - response.writeHead(200, {"Content-Type": "text/html"}); - response.write(""); - response.write(""); - response.write(""); - response.write("\n"); - response.write("" + caption + ""); - response.write(""); - response.write(""); - response.write("

" + title + "

"); + response.write("\n"); + response.end(); + } -// Prepare HTML footer -function htmlFooter(response) { - response.write("\n"); +// Report an error +function handleError(response, text, err) { + if (err) { + text += ": " + err.message; + } + console.error(text); + response.writeHead(500, {"Content-Type": "text/html"}); + response.write(text); response.end(); } @@ -216,7 +239,7 @@ async function closePoolAndExit() { await oracledb.getPool().close(10); console.log("Pool closed"); process.exit(0); - } catch(err) { + } catch (err) { console.error(err.message); process.exit(1); } diff --git a/python/BindInsert.py b/python/BindInsert.py deleted file mode 100644 index 48c772bf..00000000 --- a/python/BindInsert.py +++ /dev/null @@ -1,34 +0,0 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. -#------------------------------------------------------------------------------ - -#------------------------------------------------------------------------------ -# BindInsert.py -# -# Demonstrate how to insert a row into a table using bind variables. -#------------------------------------------------------------------------------ - -import cx_Oracle -import SampleEnv - -connection = cx_Oracle.connect(SampleEnv.GetMainConnectString()) - -rows = [ (1, "First" ), - (2, "Second" ), - (3, "Third" ), - (4, "Fourth" ), - (5, "Fifth" ), - (6, "Sixth" ), - (7, "Seventh" ) ] - -cursor = connection.cursor() -cursor.executemany("insert into mytab(id, data) values (:1, :2)", rows) - -# Don't commit - this lets us run the demo multiple times -#connection.commit() - -# Now query the results back - -for row in cursor.execute('select * from mytab'): - print(row) - diff --git a/python/DropSamples.py b/python/DropSamples.py deleted file mode 100644 index 9b801c6c..00000000 --- a/python/DropSamples.py +++ /dev/null @@ -1,24 +0,0 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. -#------------------------------------------------------------------------------ - -#------------------------------------------------------------------------------ -# DropSamples.py -# -# Drops the database objects used for the cx_Oracle samples. -#------------------------------------------------------------------------------ - -import cx_Oracle -import SampleEnv - -def DropSamples(conn): - print("Dropping sample schemas and edition...") - SampleEnv.RunSqlScript(conn, "DropSamples", - main_user = SampleEnv.GetMainUser(), - edition_user = SampleEnv.GetEditionUser(), - edition_name = SampleEnv.GetEditionName()) - -if __name__ == "__main__": - conn = cx_Oracle.connect(SampleEnv.GetAdminConnectString()) - DropSamples(conn) - print("Done.") diff --git a/python/README.md b/python/README.md index f531e03a..81c2286e 100644 --- a/python/README.md +++ b/python/README.md @@ -1,41 +1,47 @@ -This directory contains samples for cx_Oracle. +# cx_Oracle Examples + +This directory contains samples for [cx_Oracle][6]. Documentation is +[here][7]. A separate tutorial is [here][8]. 1. The schemas and SQL objects that are referenced in the samples can be - created by running the Python script [SetupSamples.py][1]. The script + created by running the Python script [setup_samples.py][1]. The script requires SYSDBA privileges and will prompt for these credentials as well as the names of the schemas and edition that will be created, unless a number of environment variables are set as documented in the Python script - [SampleEnv.py][2]. Run the script using the following command: + [sample_env.py][2]. Run the script using the following command: - python SetupSamples.py + python setup_samples.py Alternatively, the [SQL script][3] can be run directly via SQL\*Plus, which will always prompt for the names of the schemas and edition that will be created. - sqlplus sys/syspassword@hostname/servicename @sql/SetupSamples.sql + sqlplus sys/syspassword@hostname/servicename @sql/setup_samples.sql 2. Run a Python script, for example: - python Query.py + python query.py 3. After running cx_Oracle samples, the schemas and SQL objects can be - dropped by running the Python script [DropSamples.py][4]. The script + dropped by running the Python script [drop_samples.py][4]. The script requires SYSDBA privileges and will prompt for these credentials as well as the names of the schemas and edition that will be dropped, unless a number of environment variables are set as documented in the Python script - [SampleEnv.py][2]. Run the script using the following command: + [sample_env.py][2]. Run the script using the following command: - python DropSamples.py + python drop_samples.py Alternatively, the [SQL script][5] can be run directly via SQL\*Plus, which will always prompt for the names of the schemas and edition that will be dropped. - sqlplus sys/syspassword@hostname/servicename @sql/DropSamples.sql + sqlplus sys/syspassword@hostname/servicename @sql/drop_samples.sql -[1]: https://github.com/oracle/python-cx_Oracle/blob/master/samples/SetupSamples.py -[2]: https://github.com/oracle/python-cx_Oracle/blob/master/samples/SampleEnv.py -[3]: https://github.com/oracle/python-cx_Oracle/blob/master/samples/sql/SetupSamples.sql -[4]: https://github.com/oracle/python-cx_Oracle/blob/master/samples/DropSamples.py -[5]: https://github.com/oracle/python-cx_Oracle/blob/master/samples/sql/DropSamples.sql +[1]: https://github.com/oracle/python-cx_Oracle/blob/main/samples/setup_samples.py +[2]: https://github.com/oracle/python-cx_Oracle/blob/main/samples/sample_env.py +[3]: https://github.com/oracle/python-cx_Oracle/blob/main/samples/sql/setup_samples.sql +[4]: https://github.com/oracle/python-cx_Oracle/blob/main/samples/drop_samples.py +[5]: https://github.com/oracle/python-cx_Oracle/blob/main/samples/sql/drop_samples.sql +[6]: https://oracle.github.io/python-cx_Oracle/ +[7]: http://cx-oracle.readthedocs.org/en/latest/index.html +[8]: https://oracle.github.io/python-cx_Oracle/samples/tutorial/Python-and-Oracle-Database-Scripting-for-the-Future.html diff --git a/python/RefCursor.py b/python/RefCursor.py deleted file mode 100644 index 1e362c7b..00000000 --- a/python/RefCursor.py +++ /dev/null @@ -1,29 +0,0 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. -#------------------------------------------------------------------------------ - -#------------------------------------------------------------------------------ -# RefCursor.py -# Demonstrates the use of REF cursors with cx_Oracle. -#------------------------------------------------------------------------------ - -import cx_Oracle -import SampleEnv - -connection = cx_Oracle.connect(SampleEnv.GetMainConnectString()) -cursor = connection.cursor() - -refCursor = connection.cursor() -cursor.callproc("myrefcursorproc", (2, 6, refCursor)) -print("Rows between 2 and 6:") -for row in refCursor: - print(row) -print() - -refCursor = connection.cursor() -cursor.callproc("myrefcursorproc", (8, 9, refCursor)) -print("Rows between 8 and 9:") -for row in refCursor: - print(row) -print() - diff --git a/python/AppContext.py b/python/app_context.py similarity index 83% rename from python/AppContext.py rename to python/app_context.py index 0c9e1122..41c411f8 100644 --- a/python/AppContext.py +++ b/python/app_context.py @@ -1,5 +1,5 @@ #------------------------------------------------------------------------------ -# Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. # # Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved. # @@ -8,7 +8,7 @@ #------------------------------------------------------------------------------ #------------------------------------------------------------------------------ -# AppContext.py +# app_context.py # This script demonstrates the use of application context. Application # context is available within logon triggers and can be retrieved by using the # function sys_context(). @@ -16,8 +16,8 @@ # This script requires cx_Oracle 5.3 and higher. #------------------------------------------------------------------------------ -import cx_Oracle -import SampleEnv +import cx_Oracle as oracledb +import sample_env # define constants used throughout the script; adjust as desired APP_CTX_NAMESPACE = "CLIENTCONTEXT" @@ -27,11 +27,10 @@ ( APP_CTX_NAMESPACE, "ATTR3", "VALUE3" ) ] -connection = cx_Oracle.connect(SampleEnv.GetMainConnectString(), - appcontext = APP_CTX_ENTRIES) +connection = oracledb.connect(sample_env.get_main_connect_string(), + appcontext=APP_CTX_ENTRIES) cursor = connection.cursor() for namespace, name, value in APP_CTX_ENTRIES: cursor.execute("select sys_context(:1, :2) from dual", (namespace, name)) value, = cursor.fetchone() print("Value of context key", name, "is", value) - diff --git a/python/AdvancedQueuingNotification.py b/python/aq_notification.py similarity index 69% rename from python/AdvancedQueuingNotification.py rename to python/aq_notification.py index 7718bb24..728d5b26 100644 --- a/python/AdvancedQueuingNotification.py +++ b/python/aq_notification.py @@ -1,37 +1,39 @@ #------------------------------------------------------------------------------ -# Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. #------------------------------------------------------------------------------ #------------------------------------------------------------------------------ -# AdvancedQueuingNotification.py +# aq_notification.py # This script demonstrates using advanced queuing notification. Once this # script is running, use another session to enqueue a few messages to the # "DEMO_BOOK_QUEUE" queue. This is most easily accomplished by running the -# ObjectAQ.py sample. +# object_aq.py sample. # # This script requires cx_Oracle 6.4 and higher. #------------------------------------------------------------------------------ -import cx_Oracle -import SampleEnv -import threading import time +import cx_Oracle as oracledb +import sample_env + registered = True -def ProcessMessages(message): +def process_messages(message): global registered print("Message type:", message.type) - if message.type == cx_Oracle.EVENT_DEREG: + if message.type == oracledb.EVENT_DEREG: print("Deregistration has taken place...") registered = False return print("Queue name:", message.queueName) print("Consumer name:", message.consumerName) -connection = cx_Oracle.connect(SampleEnv.GetMainConnectString(), events = True) -sub = connection.subscribe(namespace=cx_Oracle.SUBSCR_NAMESPACE_AQ, - name="DEMO_BOOK_QUEUE", callback=ProcessMessages, timeout=300) +connection = oracledb.connect(sample_env.get_main_connect_string(), + events=True) +sub = connection.subscribe(namespace=oracledb.SUBSCR_NAMESPACE_AQ, + name="DEMO_BOOK_QUEUE", callback=process_messages, + timeout=300) print("Subscription:", sub) print("--> Connection:", sub.connection) print("--> Callback:", sub.callback) @@ -42,4 +44,3 @@ def ProcessMessages(message): while registered: print("Waiting for notifications....") time.sleep(5) - diff --git a/python/ArrayDMLRowCounts.py b/python/array_dml_rowcounts.py similarity index 67% rename from python/ArrayDMLRowCounts.py rename to python/array_dml_rowcounts.py index 28d7b382..335d46c3 100644 --- a/python/ArrayDMLRowCounts.py +++ b/python/array_dml_rowcounts.py @@ -1,9 +1,9 @@ #------------------------------------------------------------------------------ -# Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. #------------------------------------------------------------------------------ #------------------------------------------------------------------------------ -# ArrayDMLRowCounts.py +# array_dml_rowcounts.py # # Demonstrate the use of the 12.1 feature that allows cursor.executemany() # to return the number of rows affected by each individual execution as a list. @@ -13,37 +13,36 @@ # This script requires cx_Oracle 5.2 and higher. #------------------------------------------------------------------------------ -import cx_Oracle -import SampleEnv +import cx_Oracle as oracledb +import sample_env -connection = cx_Oracle.connect(SampleEnv.GetMainConnectString()) +connection = oracledb.connect(sample_env.get_main_connect_string()) cursor = connection.cursor() # show the number of rows for each parent ID as a means of verifying the # output from the delete statement -for parentId, count in cursor.execute(""" +for parent_id, count in cursor.execute(""" select ParentId, count(*) from ChildTable group by ParentId order by ParentId"""): - print("Parent ID:", parentId, "has", int(count), "rows.") + print("Parent ID:", parent_id, "has", int(count), "rows.") print() # delete the following parent IDs only -parentIdsToDelete = [20, 30, 50] +parent_ids_to_delete = [20, 30, 50] -print("Deleting Parent IDs:", parentIdsToDelete) +print("Deleting Parent IDs:", parent_ids_to_delete) print() # enable array DML row counts for each iteration executed in executemany() cursor.executemany(""" delete from ChildTable where ParentId = :1""", - [(i,) for i in parentIdsToDelete], + [(i,) for i in parent_ids_to_delete], arraydmlrowcounts = True) # display the number of rows deleted for each parent ID -rowCounts = cursor.getarraydmlrowcounts() -for parentId, count in zip(parentIdsToDelete, rowCounts): - print("Parent ID:", parentId, "deleted", count, "rows.") - +row_counts = cursor.getarraydmlrowcounts() +for parent_id, count in zip(parent_ids_to_delete, row_counts): + print("Parent ID:", parent_id, "deleted", count, "rows.") diff --git a/python/BatchErrors.py b/python/batch_errors.py similarity index 84% rename from python/BatchErrors.py rename to python/batch_errors.py index 20740cc7..8d093bdb 100644 --- a/python/BatchErrors.py +++ b/python/batch_errors.py @@ -1,9 +1,9 @@ #------------------------------------------------------------------------------ -# Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. #------------------------------------------------------------------------------ #------------------------------------------------------------------------------ -# BatchErrors.py +# batch_errors.py # # Demonstrate the use of the Oracle Database 12.1 feature that allows # cursor.executemany() to complete successfully, even if errors take @@ -15,14 +15,14 @@ # This script requires cx_Oracle 5.2 and higher. #------------------------------------------------------------------------------ -import cx_Oracle -import SampleEnv +import cx_Oracle as oracledb +import sample_env -connection = cx_Oracle.connect(SampleEnv.GetMainConnectString()) +connection = oracledb.connect(sample_env.get_main_connect_string()) cursor = connection.cursor() # define data to insert -dataToInsert = [ +data_to_insert = [ (1016, 10, 'Child B of Parent 10'), (1017, 10, 'Child C of Parent 10'), (1018, 20, 'Child D of Parent 20'), @@ -39,15 +39,15 @@ from ChildTable""") count, = cursor.fetchone() print("number of rows in child table:", int(count)) -print("number of rows to insert:", len(dataToInsert)) +print("number of rows to insert:", len(data_to_insert)) # old method: executemany() with data errors results in stoppage after the # first error takes place; the row count is updated to show how many rows # actually succeeded try: cursor.executemany("insert into ChildTable values (:1, :2, :3)", - dataToInsert) -except cx_Oracle.DatabaseError as e: + data_to_insert) +except oracledb.DatabaseError as e: error, = e.args print("FAILED with error:", error.message) print("number of rows which succeeded:", cursor.rowcount) @@ -64,12 +64,12 @@ # new method: executemany() with batch errors enabled (and array DML row counts # also enabled) results in no immediate error being raised -cursor.executemany("insert into ChildTable values (:1, :2, :3)", dataToInsert, - batcherrors = True, arraydmlrowcounts = True) +cursor.executemany("insert into ChildTable values (:1, :2, :3)", + data_to_insert, batcherrors=True, arraydmlrowcounts=True) # where errors have taken place, the row count is 0; otherwise it is 1 -rowCounts = cursor.getarraydmlrowcounts() -print("Array DML row counts:", rowCounts) +row_counts = cursor.getarraydmlrowcounts() +print("Array DML row counts:", row_counts) # display the errors that have taken place errors = cursor.getbatcherrors() diff --git a/python/bind_insert.py b/python/bind_insert.py new file mode 100644 index 00000000..fef635ba --- /dev/null +++ b/python/bind_insert.py @@ -0,0 +1,75 @@ +#------------------------------------------------------------------------------ +# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. +#------------------------------------------------------------------------------ + +#------------------------------------------------------------------------------ +# bind_insert.py +# +# Demonstrate how to insert a row into a table using bind variables. +#------------------------------------------------------------------------------ + +import cx_Oracle as oracledb +import sample_env + +connection = oracledb.connect(sample_env.get_main_connect_string()) + +#------------------------------------------------------------------------------ +# "Bind by position" +#------------------------------------------------------------------------------ + +rows = [ + (1, "First"), + (2, "Second"), + (3, "Third"), + (4, "Fourth"), + (5, None), # Insert a NULL value + (6, "Sixth"), + (7, "Seventh") +] + +cursor = connection.cursor() + +# predefine maximum string size to avoid data scans and memory reallocations; +# the None value indicates that the default processing can take place +cursor.setinputsizes(None, 20) + +cursor.executemany("insert into mytab(id, data) values (:1, :2)", rows) + +#------------------------------------------------------------------------------ +# "Bind by name" +#------------------------------------------------------------------------------ + +rows = [ + {"d": "Eighth", "i": 8}, + {"d": "Ninth", "i": 9}, + {"d": "Tenth", "i": 10} +] + +cursor = connection.cursor() + +# Predefine maximum string size to avoid data scans and memory reallocations +cursor.setinputsizes(d=20) + +cursor.executemany("insert into mytab(id, data) values (:i, :d)", rows) + +#------------------------------------------------------------------------------ +# Inserting a single bind still needs tuples +#------------------------------------------------------------------------------ + +rows = [ + ("Eleventh",), + ("Twelth",) +] + +cursor = connection.cursor() +cursor.executemany("insert into mytab(id, data) values (11, :1)", rows) + +#------------------------------------------------------------------------------ +# Now query the results back +#------------------------------------------------------------------------------ + +# Don't commit - this lets the demo be run multiple times +#connection.commit() + +for row in cursor.execute('select * from mytab'): + print(row) diff --git a/python/BindQuery.py b/python/bind_query.py similarity index 83% rename from python/BindQuery.py rename to python/bind_query.py index be3eda9e..5b09bc7b 100644 --- a/python/BindQuery.py +++ b/python/bind_query.py @@ -1,9 +1,9 @@ #------------------------------------------------------------------------------ -# Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. #------------------------------------------------------------------------------ #------------------------------------------------------------------------------ -# BindQuery.py +# bind_query.py # # Demonstrate how to perform a simple query limiting the rows retrieved using # a bind variable. Since the query that is executed is identical, no additional @@ -12,10 +12,10 @@ # special characters or SQL injection attacks. #------------------------------------------------------------------------------ -import cx_Oracle -import SampleEnv +import cx_Oracle as oracledb +import sample_env -connection = cx_Oracle.connect(SampleEnv.GetMainConnectString()) +connection = oracledb.connect(sample_env.get_main_connect_string()) cursor = connection.cursor() sql = 'select * from SampleQueryTab where id = :bvid' @@ -29,4 +29,3 @@ for row in cursor.execute(sql, bvid = 1): print(row) print() - diff --git a/python/BulkAQ.py b/python/bulk_aq.py similarity index 71% rename from python/BulkAQ.py rename to python/bulk_aq.py index bd02a437..540387fa 100644 --- a/python/BulkAQ.py +++ b/python/bulk_aq.py @@ -1,5 +1,5 @@ #------------------------------------------------------------------------------ -# Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. # # Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved. # @@ -8,16 +8,16 @@ #------------------------------------------------------------------------------ #------------------------------------------------------------------------------ -# BulkAQ.py +# bulk_aq.py # This script demonstrates how to use bulk enqueuing and dequeuing of # messages with advanced queuing using cx_Oracle. It makes use of a RAW queue # created in the sample setup. # -# This script requires cx_Oracle 7.2 and higher. +# This script requires cx_Oracle 8.2 and higher. #------------------------------------------------------------------------------ -import cx_Oracle -import SampleEnv +import cx_Oracle as oracledb +import sample_env QUEUE_NAME = "DEMO_RAW_QUEUE" PAYLOAD_DATA = [ @@ -36,37 +36,37 @@ ] # connect to database -connection = cx_Oracle.connect(SampleEnv.GetMainConnectString()) +connection = oracledb.connect(sample_env.get_main_connect_string()) cursor = connection.cursor() # create queue queue = connection.queue(QUEUE_NAME) -queue.deqOptions.wait = cx_Oracle.DEQ_NO_WAIT -queue.deqOptions.navigation = cx_Oracle.DEQ_FIRST_MSG +queue.deqoptions.wait = oracledb.DEQ_NO_WAIT +queue.deqoptions.navigation = oracledb.DEQ_FIRST_MSG # dequeue all existing messages to ensure the queue is empty, just so that # the results are consistent -while queue.deqOne(): +while queue.deqone(): pass # enqueue a few messages print("Enqueuing messages...") -batchSize = 6 -dataToEnq = PAYLOAD_DATA -while dataToEnq: - batchData = dataToEnq[:batchSize] - dataToEnq = dataToEnq[batchSize:] - messages = [connection.msgproperties(payload=d) for d in batchData] - for data in batchData: +batch_size = 6 +data_to_enqueue = PAYLOAD_DATA +while data_to_enqueue: + batch_data = data_to_enqueue[:batch_size] + data_to_enqueue = data_to_enqueue[batch_size:] + messages = [connection.msgproperties(payload=d) for d in batch_data] + for data in batch_data: print(data) - queue.enqMany(messages) + queue.enqmany(messages) connection.commit() # dequeue the messages print("\nDequeuing messages...") -batchSize = 8 +batch_size = 8 while True: - messages = queue.deqMany(batchSize) + messages = queue.deqmany(batch_size) if not messages: break for props in messages: diff --git a/python/CallTimeout.py b/python/call_timeout.py similarity index 72% rename from python/CallTimeout.py rename to python/call_timeout.py index 5c063162..b665d9f5 100644 --- a/python/CallTimeout.py +++ b/python/call_timeout.py @@ -1,9 +1,9 @@ #------------------------------------------------------------------------------ -# Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. #------------------------------------------------------------------------------ #------------------------------------------------------------------------------ -# CallTimeout.py +# call_timeout.py # # Demonstrate the use of the Oracle Client 18c feature that enables round trips # to the database to time out if a specified amount of time (in milliseconds) @@ -13,12 +13,12 @@ # higher. #------------------------------------------------------------------------------ -import cx_Oracle -import SampleEnv +import cx_Oracle as oracledb +import sample_env -connection = cx_Oracle.connect(SampleEnv.GetMainConnectString()) -connection.callTimeout = 2000 -print("Call timeout set at", connection.callTimeout, "milliseconds...") +connection = oracledb.connect(sample_env.get_main_connect_string()) +connection.call_timeout = 2000 +print("Call timeout set at", connection.call_timeout, "milliseconds...") cursor = connection.cursor() cursor.execute("select sysdate from dual") @@ -26,17 +26,16 @@ print("Fetch of current date before timeout:", today) # dbms_session.sleep() replaces dbms_lock.sleep() from Oracle Database 18c -sleepProcName = "dbms_session.sleep" \ +sleep_proc_name = "dbms_session.sleep" \ if int(connection.version.split(".")[0]) >= 18 \ else "dbms_lock.sleep" print("Sleeping...should time out...") try: - cursor.callproc(sleepProcName, (3,)) -except cx_Oracle.DatabaseError as e: + cursor.callproc(sleep_proc_name, (3,)) +except oracledb.DatabaseError as e: print("ERROR:", e) cursor.execute("select sysdate from dual") today, = cursor.fetchone() print("Fetch of current date after timeout:", today) - diff --git a/python/ConnectionPool.py b/python/connection_pool.py similarity index 56% rename from python/ConnectionPool.py rename to python/connection_pool.py index c8b827a4..f7e72294 100644 --- a/python/ConnectionPool.py +++ b/python/connection_pool.py @@ -1,9 +1,9 @@ #------------------------------------------------------------------------------ -# Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. #------------------------------------------------------------------------------ #------------------------------------------------------------------------------ -# ConnectionPool.py +# connection_pool.py # This script demonstrates the use of connection pooling in cx_Oracle. Pools # can significantly reduce connection times for long running applications that # repeatedly open and close connections. Internal features help protect against @@ -12,34 +12,29 @@ # The script uses threading to show multiple users of the pool. One thread # performs a database sleep while another performs a query. A more typical # application might be a web service that handles requests from multiple users. -# Applications that use connections concurrently in multiple threads should set -# the 'threaded' parameter to True. Note only one operation (such as an execute -# or fetch) can take place at a time on each connection. +# Note only one operation (such as an execute or fetch) can take place at a time +# on each connection. # -# Also see SessionCallback.py. +# Also see session_callback.py. # #------------------------------------------------------------------------------ -import cx_Oracle -import SampleEnv import threading -# Create a Connection Pool -pool = cx_Oracle.SessionPool(SampleEnv.GetMainUser(), - SampleEnv.GetMainPassword(), SampleEnv.GetConnectString(), min=2, - max=5, increment=1, threaded=True) +import cx_Oracle as oracledb +import sample_env -# dbms_session.sleep() replaces dbms_lock.sleep() from Oracle Database 18c -with pool.acquire() as conn: - sleepProcName = "dbms_session.sleep" \ - if int(conn.version.split(".")[0]) >= 18 \ - else "dbms_lock.sleep" +# Create a Connection Pool +pool = oracledb.SessionPool(user=sample_env.get_main_user(), + password=sample_env.get_main_password(), + dsn=sample_env.get_connect_string(), min=2, + max=5, increment=1) -def TheLongQuery(): +def the_long_query(): with pool.acquire() as conn: cursor = conn.cursor() cursor.arraysize = 25000 - print("TheLongQuery(): beginning execute...") + print("the_long_query(): beginning execute...") cursor.execute(""" select * from @@ -49,27 +44,32 @@ def TheLongQuery(): cross join TestNumbers cross join TestNumbers cross join TestNumbers""") - print("TheLongQuery(): done execute...") + print("the_long_query(): done execute...") while True: rows = cursor.fetchmany() if not rows: break - print("TheLongQuery(): fetched", len(rows), "rows...") - print("TheLongQuery(): all done!") + print("the_long_query(): fetched", len(rows), "rows...") + print("the_long_query(): all done!") -def DoALock(): +def do_a_lock(): with pool.acquire() as conn: + # dbms_session.sleep() replaces dbms_lock.sleep() + # from Oracle Database 18c + sleep_proc_name = "dbms_session.sleep" \ + if int(conn.version.split(".")[0]) >= 18 \ + else "dbms_lock.sleep" cursor = conn.cursor() - print("DoALock(): beginning execute...") - cursor.callproc(sleepProcName, (5,)) - print("DoALock(): done execute...") + print("do_a_lock(): beginning execute...") + cursor.callproc(sleep_proc_name, (5,)) + print("do_a_lock(): done execute...") -thread1 = threading.Thread(None, TheLongQuery) +thread1 = threading.Thread(target=the_long_query) thread1.start() -thread2 = threading.Thread(None, DoALock) +thread2 = threading.Thread(target=do_a_lock) thread2.start() thread1.join() diff --git a/python/CQN.py b/python/cqn.py similarity index 80% rename from python/CQN.py rename to python/cqn.py index bc0673af..c87787e9 100644 --- a/python/CQN.py +++ b/python/cqn.py @@ -1,5 +1,5 @@ #------------------------------------------------------------------------------ -# Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. # # Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved. # @@ -8,7 +8,7 @@ #------------------------------------------------------------------------------ #------------------------------------------------------------------------------ -# CQN.py +# cqn.py # This script demonstrates using continuous query notification in Python, a # feature that is available in Oracle 11g and later. Once this script is # running, use another session to insert, update or delete rows from the table @@ -17,10 +17,11 @@ # This script requires cx_Oracle 5.3 and higher. #------------------------------------------------------------------------------ -import cx_Oracle -import SampleEnv import time +import cx_Oracle as oracledb +import sample_env + registered = True def callback(message): @@ -47,9 +48,10 @@ def callback(message): print("-" * 60) print("=" * 60) -connection = cx_Oracle.connect(SampleEnv.GetMainConnectString(), events = True) -sub = connection.subscribe(callback = callback, timeout = 1800, - qos = cx_Oracle.SUBSCR_QOS_QUERY | cx_Oracle.SUBSCR_QOS_ROWIDS) +connection = oracledb.connect(sample_env.get_main_connect_string(), + events=True) +qos = oracledb.SUBSCR_QOS_QUERY | oracledb.SUBSCR_QOS_ROWIDS +sub = connection.subscribe(callback=callback, timeout=1800, qos=qos) print("Subscription:", sub) print("--> Connection:", sub.connection) print("--> Callback:", sub.callback) @@ -57,11 +59,10 @@ def callback(message): print("--> Protocol:", sub.protocol) print("--> Timeout:", sub.timeout) print("--> Operations:", sub.operations) -print("--> Rowids?:", bool(sub.qos & cx_Oracle.SUBSCR_QOS_ROWIDS)) -queryId = sub.registerquery("select * from TestTempTable") -print("Registered query:", queryId) +print("--> Rowids?:", bool(sub.qos & oracledb.SUBSCR_QOS_ROWIDS)) +query_id = sub.registerquery("select * from TestTempTable") +print("Registered query:", query_id) while registered: print("Waiting for notifications....") time.sleep(5) - diff --git a/python/CQN2.py b/python/cqn2.py similarity index 59% rename from python/CQN2.py rename to python/cqn2.py index bd57cb14..49fe1a5e 100644 --- a/python/CQN2.py +++ b/python/cqn2.py @@ -1,25 +1,26 @@ #------------------------------------------------------------------------------ -# Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. #------------------------------------------------------------------------------ #------------------------------------------------------------------------------ -# CQN2.py +# cqn2.py # This script demonstrates using continuous query notification in Python, a # feature that is available in Oracle 11g and later. Once this script is # running, use another session to insert, update or delete rows from the table -# cx_Oracle.TestTempTable and you will see the notification of that change. +# TestTempTable and you will see the notification of that change. # -# This script differs from CQN.py in that it shows how a connection can be +# This script differs from cqn.py in that it shows how a connection can be # acquired from a session pool and used to query the changes that have been # made. # # This script requires cx_Oracle 7 or higher. #------------------------------------------------------------------------------ -import cx_Oracle -import SampleEnv import time +import cx_Oracle as oracledb +import sample_env + registered = True def callback(message): @@ -34,16 +35,16 @@ def callback(message): if table.rows is None: print("Too many row changes detected in table", table.name) continue - numRowsDeleted = 0 + num_rows_deleted = 0 print(len(table.rows), "row changes detected in table", table.name) for row in table.rows: - if row.operation & cx_Oracle.OPCODE_DELETE: - numRowsDeleted += 1 + if row.operation & oracledb.OPCODE_DELETE: + num_rows_deleted += 1 continue ops = [] - if row.operation & cx_Oracle.OPCODE_INSERT: + if row.operation & oracledb.OPCODE_INSERT: ops.append("inserted") - if row.operation & cx_Oracle.OPCODE_UPDATE: + if row.operation & oracledb.OPCODE_UPDATE: ops.append("updated") cursor = connection.cursor() cursor.execute(""" @@ -51,21 +52,22 @@ def callback(message): from TestTempTable where rowid = :rid""", rid=row.rowid) - intCol, = cursor.fetchone() - print(" Row with IntCol", intCol, "was", " and ".join(ops)) - if numRowsDeleted > 0: - print(" ", numRowsDeleted, "rows deleted") + int_col, = cursor.fetchone() + print(" Row with IntCol", int_col, "was", " and ".join(ops)) + if num_rows_deleted > 0: + print(" ", num_rows_deleted, "rows deleted") print("=" * 60) -pool = cx_Oracle.SessionPool(SampleEnv.GetMainUser(), - SampleEnv.GetMainPassword(), SampleEnv.GetConnectString(), min=2, - max=5, increment=1, events=True, threaded=True) +pool = oracledb.SessionPool(user=sample_env.get_main_user(), + password=sample_env.get_main_password(), + dsn=sample_env.get_connect_string(), min=2, max=5, + increment=1, events=True) with pool.acquire() as connection: - sub = connection.subscribe(callback=callback, timeout=1800, - qos=cx_Oracle.SUBSCR_QOS_QUERY | cx_Oracle.SUBSCR_QOS_ROWIDS) + qos = oracledb.SUBSCR_QOS_QUERY | oracledb.SUBSCR_QOS_ROWIDS + sub = connection.subscribe(callback=callback, timeout=1800, qos=qos) print("Subscription created with ID:", sub.id) - queryId = sub.registerquery("select * from TestTempTable") - print("Registered query with ID:", queryId) + query_id = sub.registerquery("select * from TestTempTable") + print("Registered query with ID:", query_id) while registered: print("Waiting for notifications....") diff --git a/python/DatabaseChangeNotification.py b/python/database_change_notification.py similarity index 82% rename from python/DatabaseChangeNotification.py rename to python/database_change_notification.py index 8856d666..db404bd2 100644 --- a/python/DatabaseChangeNotification.py +++ b/python/database_change_notification.py @@ -1,5 +1,5 @@ #------------------------------------------------------------------------------ -# Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. # # Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved. # @@ -8,7 +8,7 @@ #------------------------------------------------------------------------------ #------------------------------------------------------------------------------ -# DatabaseChangeNotification.py +# database_change_notification.py # This script demonstrates using database change notification in Python, a # feature that is available in Oracle 10g Release 2. Once this script is # running, use another session to insert, update or delete rows from the table @@ -17,10 +17,11 @@ # This script requires cx_Oracle 5.3 and higher. #------------------------------------------------------------------------------ -import cx_Oracle -import SampleEnv import time +import cx_Oracle as oracledb +import sample_env + registered = True def callback(message): @@ -44,9 +45,10 @@ def callback(message): print("-" * 60) print("=" * 60) -connection = cx_Oracle.connect(SampleEnv.GetMainConnectString(), events = True) -sub = connection.subscribe(callback = callback, timeout = 1800, - qos = cx_Oracle.SUBSCR_QOS_ROWIDS) +connection = oracledb.connect(sample_env.get_main_connect_string(), + events=True) +sub = connection.subscribe(callback=callback, timeout=1800, + qos=oracledb.SUBSCR_QOS_ROWIDS) print("Subscription:", sub) print("--> Connection:", sub.connection) print("--> ID:", sub.id) @@ -55,10 +57,9 @@ def callback(message): print("--> Protocol:", sub.protocol) print("--> Timeout:", sub.timeout) print("--> Operations:", sub.operations) -print("--> Rowids?:", bool(sub.qos & cx_Oracle.SUBSCR_QOS_ROWIDS)) +print("--> Rowids?:", bool(sub.qos & oracledb.SUBSCR_QOS_ROWIDS)) sub.registerquery("select * from TestTempTable") while registered: print("Waiting for notifications....") time.sleep(5) - diff --git a/python/DatabaseShutdown.py b/python/database_shutdown.py similarity index 69% rename from python/DatabaseShutdown.py rename to python/database_shutdown.py index e6e303a2..63210b5c 100644 --- a/python/DatabaseShutdown.py +++ b/python/database_shutdown.py @@ -1,5 +1,5 @@ #------------------------------------------------------------------------------ -# Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. # # Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved. # @@ -8,22 +8,22 @@ #------------------------------------------------------------------------------ #------------------------------------------------------------------------------ -# DatabaseShutdown.py -# This script demonstrates shutting down a database using Python. It is only -# possible in Oracle 10g Release 2 and higher. The connection used assumes that -# the environment variable ORACLE_SID has been set. +# database_shutdown.py +# This script demonstrates shutting down a database using Python. The +# connection used assumes that the environment variable ORACLE_SID has been +# set. # # This script requires cx_Oracle 4.3 and higher. #------------------------------------------------------------------------------ -import cx_Oracle +import cx_Oracle as oracledb # need to connect as SYSDBA or SYSOPER -connection = cx_Oracle.connect("/", mode = cx_Oracle.SYSDBA) +connection = oracledb.connect(mode=oracledb.SYSDBA) # first shutdown() call must specify the mode, if DBSHUTDOWN_ABORT is used, # there is no need for any of the other steps -connection.shutdown(mode = cx_Oracle.DBSHUTDOWN_IMMEDIATE) +connection.shutdown(mode=oracledb.DBSHUTDOWN_IMMEDIATE) # now close and dismount the database cursor = connection.cursor() @@ -31,5 +31,4 @@ cursor.execute("alter database dismount") # perform the final shutdown call -connection.shutdown(mode = cx_Oracle.DBSHUTDOWN_FINAL) - +connection.shutdown(mode=oracledb.DBSHUTDOWN_FINAL) diff --git a/python/DatabaseStartup.py b/python/database_startup.py similarity index 68% rename from python/DatabaseStartup.py rename to python/database_startup.py index 505ecb8d..e0364585 100644 --- a/python/DatabaseStartup.py +++ b/python/database_startup.py @@ -1,5 +1,5 @@ #------------------------------------------------------------------------------ -# Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. # # Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved. # @@ -8,24 +8,22 @@ #------------------------------------------------------------------------------ #------------------------------------------------------------------------------ -# DatabaseStartup.py -# This script demonstrates starting up a database using Python. It is only -# possible in Oracle 10g Release 2 and higher. The connection used assumes that -# the environment variable ORACLE_SID has been set. +# database_startup.py +# This script demonstrates starting up a database using Python. The +# connection used assumes that the environment variable ORACLE_SID has been +# set. # # This script requires cx_Oracle 4.3 and higher. #------------------------------------------------------------------------------ -import cx_Oracle +import cx_Oracle as oracledb # the connection must be in PRELIM_AUTH mode -connection = cx_Oracle.connect("/", - mode = cx_Oracle.SYSDBA | cx_Oracle.PRELIM_AUTH) +connection = oracledb.connect(mode=oracledb.SYSDBA | oracledb.PRELIM_AUTH) connection.startup() # the following statements must be issued in normal SYSDBA mode -connection = cx_Oracle.connect("/", mode = cx_Oracle.SYSDBA) +connection = oracledb.connect("/", mode=oracledb.SYSDBA) cursor = connection.cursor() cursor.execute("alter database mount") cursor.execute("alter database open") - diff --git a/python/DbmsOutput.py b/python/dbms_output.py similarity index 86% rename from python/DbmsOutput.py rename to python/dbms_output.py index c696dff3..e16ad0d9 100644 --- a/python/DbmsOutput.py +++ b/python/dbms_output.py @@ -1,17 +1,17 @@ #------------------------------------------------------------------------------ -# Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. #------------------------------------------------------------------------------ #------------------------------------------------------------------------------ -# DbmsOutput.py +# dbms_output.py # This script demonstrates one method of fetching the lines produced by # the DBMS_OUTPUT package. #------------------------------------------------------------------------------ -import cx_Oracle -import SampleEnv +import cx_Oracle as oracledb +import sample_env -connection = cx_Oracle.connect(SampleEnv.GetMainConnectString()) +connection = oracledb.connect(sample_env.get_main_connect_string()) cursor = connection.cursor() # enable DBMS_OUTPUT diff --git a/python/DMLReturningMultipleRows.py b/python/dml_returning_multiple_rows.py similarity index 70% rename from python/DMLReturningMultipleRows.py rename to python/dml_returning_multiple_rows.py index cd689f51..cd11c2db 100644 --- a/python/DMLReturningMultipleRows.py +++ b/python/dml_returning_multiple_rows.py @@ -1,5 +1,5 @@ #------------------------------------------------------------------------------ -# Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. # # Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved. # @@ -8,19 +8,18 @@ #------------------------------------------------------------------------------ #------------------------------------------------------------------------------ -# DMLReturningMultipleRows.py +# dml_returning_multiple_rows.py # This script demonstrates the use of DML returning with multiple rows being # returned at once. # # This script requires cx_Oracle 6.0 and higher. #------------------------------------------------------------------------------ -import cx_Oracle -import datetime -import SampleEnv +import cx_Oracle as oracledb +import sample_env # truncate table first so that script can be rerun -connection = cx_Oracle.connect(SampleEnv.GetMainConnectString()) +connection = oracledb.connect(sample_env.get_main_connect_string()) cursor = connection.cursor() print("Truncating table...") cursor.execute("truncate table TestTempTable") @@ -32,15 +31,14 @@ cursor.execute("insert into TestTempTable values (:1, :2)", data) # now delete them and use DML returning to return the data that was inserted -intCol = cursor.var(int) -stringCol = cursor.var(str) +int_col = cursor.var(int) +string_col = cursor.var(str) print("Deleting data with DML returning...") cursor.execute(""" delete from TestTempTable - returning IntCol, StringCol into :intCol, :stringCol""", - intCol = intCol, - stringCol = stringCol) + returning IntCol, StringCol into :int_col, :string_col""", + int_col=int_col, + string_col=string_col) print("Data returned:") -for intVal, stringVal in zip(intCol.getvalue(), stringCol.getvalue()): - print(tuple([intVal, stringVal])) - +for int_val, string_val in zip(int_col.getvalue(), string_col.getvalue()): + print(tuple([int_val, string_val])) diff --git a/python/DRCP.py b/python/drcp.py similarity index 84% rename from python/DRCP.py rename to python/drcp.py index c3b1e097..289b8560 100644 --- a/python/DRCP.py +++ b/python/drcp.py @@ -1,5 +1,5 @@ #------------------------------------------------------------------------------ -# Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. # # Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved. # @@ -8,7 +8,7 @@ #------------------------------------------------------------------------------ #------------------------------------------------------------------------------ -# DRCP.py +# drcp.py # This script demonstrates the use of Database Resident Connection Pooling # (DRCP) which provides a connection pool in the database server, thereby # reducing the cost of creating and tearing down client connections. The pool @@ -32,13 +32,12 @@ # #------------------------------------------------------------------------------ -import cx_Oracle -import SampleEnv +import cx_Oracle as oracledb +import sample_env -conn = cx_Oracle.connect(SampleEnv.GetDrcpConnectString(), cclass = "PYCLASS", - purity = cx_Oracle.ATTR_PURITY_SELF) +conn = oracledb.connect(sample_env.get_drcp_connect_string(), + cclass="PYCLASS", purity=oracledb.ATTR_PURITY_SELF) cursor = conn.cursor() print("Performing query using DRCP...") for row in cursor.execute("select * from TestNumbers order by IntCol"): print(row) - diff --git a/python/drop_samples.py b/python/drop_samples.py new file mode 100644 index 00000000..d3d51c78 --- /dev/null +++ b/python/drop_samples.py @@ -0,0 +1,24 @@ +#------------------------------------------------------------------------------ +# Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. +#------------------------------------------------------------------------------ + +#------------------------------------------------------------------------------ +# drop_samples.py +# +# Drops the database objects used for the cx_Oracle samples. +#------------------------------------------------------------------------------ + +import cx_Oracle as oracledb +import sample_env + +def drop_samples(conn): + print("Dropping sample schemas and edition...") + sample_env.run_sql_script(conn, "drop_samples", + main_user=sample_env.get_main_user(), + edition_user=sample_env.get_edition_user(), + edition_name=sample_env.get_edition_name()) + +if __name__ == "__main__": + conn = oracledb.connect(sample_env.get_admin_connect_string()) + drop_samples(conn) + print("Done.") diff --git a/python/Editioning.py b/python/editioning.py similarity index 69% rename from python/Editioning.py rename to python/editioning.py index 6ac449a2..6492c7df 100644 --- a/python/Editioning.py +++ b/python/editioning.py @@ -1,5 +1,5 @@ #------------------------------------------------------------------------------ -# Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. # # Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved. # @@ -8,7 +8,7 @@ #------------------------------------------------------------------------------ #------------------------------------------------------------------------------ -# Editioning.py +# editioning.py # This script demonstrates the use of Edition-Based Redefinition, available # in Oracle# Database 11.2 and higher. See the Oracle documentation on the # subject for additional information. Adjust the contants at the top of the @@ -17,15 +17,16 @@ # This script requires cx_Oracle 5.3 and higher. #------------------------------------------------------------------------------ -import cx_Oracle -import SampleEnv import os +import cx_Oracle as oracledb +import sample_env + # connect to the editions user and create a procedure -editionConnectString = SampleEnv.GetEditionConnectString() -connection = cx_Oracle.connect(editionConnectString) -print("Edition should be None, actual value is:", - repr(connection.edition)) +edition_connect_string = sample_env.get_edition_connect_string() +edition_name = sample_env.get_edition_name() +connection = oracledb.connect(edition_connect_string) +print("Edition should be None, actual value is:", repr(connection.edition)) cursor = connection.cursor() cursor.execute(""" create or replace function TestEditions return varchar2 as @@ -34,12 +35,12 @@ end;""") result = cursor.callfunc("TestEditions", str) print("Function should return 'Base Procedure', actually returns:", - repr(result)) + repr(result)) # next, change the edition and recreate the procedure in the new edition -cursor.execute("alter session set edition = %s" % SampleEnv.GetEditionName()) -print("Edition should be", repr(SampleEnv.GetEditionName().upper()), - "actual value is:", repr(connection.edition)) +cursor.execute("alter session set edition = %s" % edition_name) +print("Edition should be", repr(edition_name.upper()), + "actual value is:", repr(connection.edition)) cursor.execute(""" create or replace function TestEditions return varchar2 as begin @@ -47,30 +48,29 @@ end;""") result = cursor.callfunc("TestEditions", str) print("Function should return 'Edition 1 Procedure', actually returns:", - repr(result)) + repr(result)) # next, change the edition back to the base edition and demonstrate that the # original function is being called cursor.execute("alter session set edition = ORA$BASE") result = cursor.callfunc("TestEditions", str) print("Function should return 'Base Procedure', actually returns:", - repr(result)) + repr(result)) # the edition can be set upon connection -connection = cx_Oracle.connect(editionConnectString, - edition = SampleEnv.GetEditionName().upper()) +connection = oracledb.connect(edition_connect_string, + edition=edition_name.upper()) cursor = connection.cursor() result = cursor.callfunc("TestEditions", str) print("Function should return 'Edition 1 Procedure', actually returns:", - repr(result)) + repr(result)) # it can also be set via the environment variable ORA_EDITION -os.environ["ORA_EDITION"] = SampleEnv.GetEditionName().upper() -connection = cx_Oracle.connect(editionConnectString) -print("Edition should be", repr(SampleEnv.GetEditionName().upper()), - "actual value is:", repr(connection.edition)) +os.environ["ORA_EDITION"] = edition_name.upper() +connection = oracledb.connect(edition_connect_string) +print("Edition should be", repr(edition_name.upper()), + "actual value is:", repr(connection.edition)) cursor = connection.cursor() result = cursor.callfunc("TestEditions", str) print("Function should return 'Edition 1 Procedure', actually returns:", - repr(result)) - + repr(result)) diff --git a/python/GenericRowFactory.py b/python/generic_row_factory.py similarity index 72% rename from python/GenericRowFactory.py rename to python/generic_row_factory.py index 4c5749d7..1ada24b6 100644 --- a/python/GenericRowFactory.py +++ b/python/generic_row_factory.py @@ -1,39 +1,39 @@ #------------------------------------------------------------------------------ -# Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. #------------------------------------------------------------------------------ #------------------------------------------------------------------------------ -# GenericRowFactory.py +# generic_row_factory.py # # Demonstrate the ability to return named tuples for all queries using a # subclassed cursor and row factory. #------------------------------------------------------------------------------ import collections -import cx_Oracle -import SampleEnv +import cx_Oracle as oracledb +import sample_env -class Connection(cx_Oracle.Connection): +class Connection(oracledb.Connection): def cursor(self): return Cursor(self) -class Cursor(cx_Oracle.Cursor): +class Cursor(oracledb.Cursor): def execute(self, statement, args = None): - prepareNeeded = (self.statement != statement) - result = super(Cursor, self).execute(statement, args or []) - if prepareNeeded: + prepare_needed = (self.statement != statement) + result = super().execute(statement, args or []) + if prepare_needed: description = self.description - if description: + if description is not None: names = [d[0] for d in description] self.rowfactory = collections.namedtuple("GenericQuery", names) return result # create new subclassed connection and cursor -connection = Connection(SampleEnv.GetMainConnectString()) +connection = Connection(sample_env.get_main_connect_string()) cursor = connection.cursor() # the names are now available directly for each query executed @@ -44,4 +44,3 @@ def execute(self, statement, args = None): for row in cursor.execute("select ChildId, Description from ChildTable"): print(row.CHILDID, "->", row.DESCRIPTION) print() - diff --git a/python/ImplicitResults.py b/python/implicit_results.py similarity index 81% rename from python/ImplicitResults.py rename to python/implicit_results.py index 4c18397b..78b70090 100644 --- a/python/ImplicitResults.py +++ b/python/implicit_results.py @@ -1,5 +1,5 @@ #------------------------------------------------------------------------------ -# Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. # # Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved. # @@ -8,7 +8,7 @@ #------------------------------------------------------------------------------ #------------------------------------------------------------------------------ -# ImplicitResults.py +# implicit_results.py # This script demonstrates the use of the 12.1 feature that allows PL/SQL # procedures to return result sets implicitly, without having to explicitly # define them. @@ -16,10 +16,10 @@ # This script requires cx_Oracle 5.3 and higher. #------------------------------------------------------------------------------ -import cx_Oracle -import SampleEnv +import cx_Oracle as oracledb +import sample_env -connection = cx_Oracle.connect(SampleEnv.GetMainConnectString()) +connection = oracledb.connect(sample_env.get_main_connect_string()) cursor = connection.cursor() # use PL/SQL block to return two cursors @@ -42,9 +42,8 @@ end;""") # display results -for ix, resultSet in enumerate(cursor.getimplicitresults()): +for ix, result_set in enumerate(cursor.getimplicitresults()): print("Result Set #" + str(ix + 1)) - for row in resultSet: + for row in result_set: print(row) print() - diff --git a/python/InsertGeometry.py b/python/insert_geometry.py similarity index 71% rename from python/InsertGeometry.py rename to python/insert_geometry.py index 4f90bf17..9df612fa 100644 --- a/python/InsertGeometry.py +++ b/python/insert_geometry.py @@ -1,5 +1,5 @@ #------------------------------------------------------------------------------ -# Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. # # Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved. # @@ -8,26 +8,26 @@ #------------------------------------------------------------------------------ #------------------------------------------------------------------------------ -# InsertGeometry.py +# insert_geometry.py # This script demonstrates the ability to create Oracle objects (this example # uses SDO_GEOMETRY) and insert them into a table. # # This script requires cx_Oracle 5.3 and higher. #------------------------------------------------------------------------------ -import cx_Oracle -import SampleEnv +import cx_Oracle as oracledb +import sample_env # create and populate Oracle objects -connection = cx_Oracle.connect(SampleEnv.GetMainConnectString()) -typeObj = connection.gettype("MDSYS.SDO_GEOMETRY") -elementInfoTypeObj = connection.gettype("MDSYS.SDO_ELEM_INFO_ARRAY") -ordinateTypeObj = connection.gettype("MDSYS.SDO_ORDINATE_ARRAY") -obj = typeObj.newobject() +connection = oracledb.connect(sample_env.get_main_connect_string()) +type_obj = connection.gettype("MDSYS.SDO_GEOMETRY") +element_info_type_obj = connection.gettype("MDSYS.SDO_ELEM_INFO_ARRAY") +ordinate_type_obj = connection.gettype("MDSYS.SDO_ORDINATE_ARRAY") +obj = type_obj.newobject() obj.SDO_GTYPE = 2003 -obj.SDO_ELEM_INFO = elementInfoTypeObj.newobject() +obj.SDO_ELEM_INFO = element_info_type_obj.newobject() obj.SDO_ELEM_INFO.extend([1, 1003, 3]) -obj.SDO_ORDINATES = ordinateTypeObj.newobject() +obj.SDO_ORDINATES = ordinate_type_obj.newobject() obj.SDO_ORDINATES.extend([1, 1, 5, 7]) print("Created object", obj) @@ -50,7 +50,6 @@ print("Removing any existing rows...") cursor.execute("delete from TestGeometry") print("Adding row to table...") -cursor.execute("insert into TestGeometry values (1, :obj)", obj = obj) +cursor.execute("insert into TestGeometry values (1, :obj)", obj=obj) connection.commit() print("Success!") - diff --git a/python/json_blob.py b/python/json_blob.py new file mode 100644 index 00000000..213acc5f --- /dev/null +++ b/python/json_blob.py @@ -0,0 +1,88 @@ +#------------------------------------------------------------------------------ +# Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. +#------------------------------------------------------------------------------ + +#------------------------------------------------------------------------------ +# json_blob.py +# Shows how to use a BLOB as a JSON column store. +# +# Note: with Oracle Database 21c using the new JSON type is recommended +# instead, see json_direct.py +# +# Documentation: +# cx_Oracle: https://cx-oracle.readthedocs.io/en/latest/user_guide/json_data_type.html +# Oracle Database: https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=ADJSN +# +#------------------------------------------------------------------------------ + +import sys +import json +import cx_Oracle as oracledb +import sample_env + +connection = oracledb.connect(sample_env.get_main_connect_string()) + +client_version = oracledb.clientversion()[0] +db_version = int(connection.version.split(".")[0]) + +# Minimum database vesion is 12 +if db_version < 12: + sys.exit("This example requires Oracle Database 12.1.0.2 or later") + +# Create a table + +cursor = connection.cursor() +cursor.execute(""" + begin + execute immediate 'drop table customers'; + exception when others then + if sqlcode <> -942 then + raise; + end if; + end;""") +cursor.execute(""" + create table customers ( + id integer not null primary key, + json_data blob check (json_data is json) + ) lob (json_data) store as (cache)""") + +# Insert JSON data + +data = dict(name="Rod", dept="Sales", location="Germany") +inssql = "insert into customers values (:1, :2)" +if client_version >= 21 and db_version >= 21: + # Take advantage of direct binding + cursor.setinputsizes(None, oracledb.DB_TYPE_JSON) + cursor.execute(inssql, [1, data]) +else: + # Insert the data as a JSON string + cursor.execute(inssql, [1, json.dumps(data)]) + +# Select JSON data + +sql = "SELECT c.json_data FROM customers c" +for j, in cursor.execute(sql): + print(json.loads(j.read())) + +# Using JSON_VALUE to extract a value from a JSON column + +sql = """SELECT JSON_VALUE(json_data, '$.location') + FROM customers + OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY""" +for r in cursor.execute(sql): + print(r) + +# Using dot-notation to extract a value from a JSON (BLOB storage) column + +sql = """SELECT c.json_data.location + FROM customers c + OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY""" +for j, in cursor.execute(sql): + print(j) + +# Using JSON_OBJECT to extract relational data as JSON + +sql = """SELECT JSON_OBJECT('key' IS d.dummy) dummy + FROM dual d""" +for r in cursor.execute(sql): + print(r) diff --git a/python/json_direct.py b/python/json_direct.py new file mode 100644 index 00000000..891b6d88 --- /dev/null +++ b/python/json_direct.py @@ -0,0 +1,93 @@ +#------------------------------------------------------------------------------ +# Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. +#------------------------------------------------------------------------------ + +#------------------------------------------------------------------------------ +# json_direct.py +# Shows some JSON features of Oracle Database 21c. +# See https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=ADJSN +# +# For JSON with older databases see json_blob.py +#------------------------------------------------------------------------------ + +import sys +import json +import cx_Oracle as oracledb +import sample_env + +connection = oracledb.connect(sample_env.get_main_connect_string()) + +client_version = oracledb.clientversion()[0] +db_version = int(connection.version.split(".")[0]) + +# this script only works with Oracle Database 21 + +if db_version < 21: + sys.exit("This example requires Oracle Database 21.1 or later. " + "Try json_blob.py") + +# Create a table + +cursor = connection.cursor() +cursor.execute(""" + begin + execute immediate 'drop table customers'; + exception when others then + if sqlcode <> -942 then + raise; + end if; + end;""") +cursor.execute(""" + create table customers ( + id integer not null primary key, + json_data json + )""") + +# Insert JSON data + +data = dict(name="Rod", dept="Sales", location="Germany") +inssql = "insert into customers values (:1, :2)" +if client_version >= 21: + # Take advantage of direct binding + cursor.setinputsizes(None, oracledb.DB_TYPE_JSON) + cursor.execute(inssql, [1, data]) +else: + # Insert the data as a JSON string + cursor.execute(inssql, [1, json.dumps(data)]) + +# Select JSON data + +sql = "SELECT c.json_data FROM customers c" +if client_version >= 21: + for j, in cursor.execute(sql): + print(j) +else: + for j, in cursor.execute(sql): + print(json.loads(j.read())) + +# Using JSON_VALUE to extract a value from a JSON column + +sql = """SELECT JSON_VALUE(json_data, '$.location') + FROM customers + OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY""" +for r in cursor.execute(sql): + print(r) + +# Using dot-notation to extract a value from a JSON column + +sql = """SELECT c.json_data.location + FROM customers c + OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY""" +if client_version >= 21: + for j, in cursor.execute(sql): + print(j) +else: + for j, in cursor.execute(sql): + print(json.loads(j.read())) + +# Using JSON_OBJECT to extract relational data as JSON + +sql = """SELECT JSON_OBJECT('key' IS d.dummy) dummy + FROM dual d""" +for r in cursor.execute(sql): + print(r) diff --git a/python/LastRowid.py b/python/last_rowid.py similarity index 89% rename from python/LastRowid.py rename to python/last_rowid.py index ebf29a57..948166b7 100644 --- a/python/LastRowid.py +++ b/python/last_rowid.py @@ -1,18 +1,18 @@ #------------------------------------------------------------------------------ -# Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. #------------------------------------------------------------------------------ #------------------------------------------------------------------------------ -# LastRowid.py +# last_rowid.py # Demonstrates the use of the cursor.lastrowid attribute. # # This script requires cx_Oracle 7.3 and higher. #------------------------------------------------------------------------------ -import cx_Oracle -import SampleEnv +import cx_Oracle as oracledb +import sample_env -connection = cx_Oracle.connect(SampleEnv.GetMainConnectString()) +connection = oracledb.connect(sample_env.get_main_connect_string()) row1 = [1, "First"] row2 = [2, "Second"] diff --git a/python/MultiConsumerAQ.py b/python/multi_consumer_aq.py similarity index 64% rename from python/MultiConsumerAQ.py rename to python/multi_consumer_aq.py index 6f8209f1..8e72adaa 100644 --- a/python/MultiConsumerAQ.py +++ b/python/multi_consumer_aq.py @@ -1,5 +1,5 @@ #------------------------------------------------------------------------------ -# Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. # # Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved. # @@ -8,16 +8,15 @@ #------------------------------------------------------------------------------ #------------------------------------------------------------------------------ -# MultiConsumerAQ.py -# This script demonstrates how to use multi-consumer -# advanced queuing using cx_Oracle. It makes use of a RAW queue -# created in the sample setup. +# multi_consumer_aq.py +# This script demonstrates how to use multi-consumer advanced queuing using +# cx_Oracle. It makes use of a RAW queue created in the sample setup. # -# This script requires cx_Oracle 7.2 and higher. +# This script requires cx_Oracle 8.2 and higher. #------------------------------------------------------------------------------ -import cx_Oracle -import SampleEnv +import cx_Oracle as oracledb +import sample_env QUEUE_NAME = "DEMO_RAW_QUEUE_MULTI" PAYLOAD_DATA = [ @@ -28,27 +27,27 @@ ] # connect to database -connection = cx_Oracle.connect(SampleEnv.GetMainConnectString()) +connection = oracledb.connect(sample_env.get_main_connect_string()) cursor = connection.cursor() # create queue queue = connection.queue(QUEUE_NAME) -queue.deqOptions.wait = cx_Oracle.DEQ_NO_WAIT -queue.deqOptions.navigation = cx_Oracle.DEQ_FIRST_MSG +queue.deqoptions.wait = oracledb.DEQ_NO_WAIT +queue.deqoptions.navigation = oracledb.DEQ_FIRST_MSG # enqueue a few messages print("Enqueuing messages...") for data in PAYLOAD_DATA: print(data) - queue.enqOne(connection.msgproperties(payload=data)) + queue.enqone(connection.msgproperties(payload=data)) connection.commit() print() # dequeue the messages for consumer A print("Dequeuing the messages for consumer A...") -queue.deqOptions.consumername = "SUBSCRIBER_A" +queue.deqoptions.consumername = "SUBSCRIBER_A" while True: - props = queue.deqOne() + props = queue.deqone() if not props: break print(props.payload.decode()) @@ -57,9 +56,9 @@ # dequeue the message for consumer B print("Dequeuing the messages for consumer B...") -queue.deqOptions.consumername = "SUBSCRIBER_B" +queue.deqoptions.consumername = "SUBSCRIBER_B" while True: - props = queue.deqOne() + props = queue.deqone() if not props: break print(props.payload.decode()) diff --git a/python/ObjectAQ.py b/python/object_aq.py similarity index 72% rename from python/ObjectAQ.py rename to python/object_aq.py index 56d29897..a8205c60 100644 --- a/python/ObjectAQ.py +++ b/python/object_aq.py @@ -1,5 +1,5 @@ #------------------------------------------------------------------------------ -# Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. # # Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved. # @@ -8,18 +8,19 @@ #------------------------------------------------------------------------------ #------------------------------------------------------------------------------ -# ObjectAQ.py +# object_aq.py # This script demonstrates how to use advanced queuing with objects using # cx_Oracle. It makes use of a simple type and queue created in the sample # setup. # -# This script requires cx_Oracle 7.2 and higher. +# This script requires cx_Oracle 8.2 and higher. #------------------------------------------------------------------------------ -import cx_Oracle -import SampleEnv import decimal +import cx_Oracle as oracledb +import sample_env + BOOK_TYPE_NAME = "UDT_BOOK" QUEUE_NAME = "DEMO_BOOK_QUEUE" BOOK_DATA = [ @@ -30,35 +31,35 @@ ] # connect to database -connection = cx_Oracle.connect(SampleEnv.GetMainConnectString()) +connection = oracledb.connect(sample_env.get_main_connect_string()) cursor = connection.cursor() # create queue -booksType = connection.gettype(BOOK_TYPE_NAME) -queue = connection.queue(QUEUE_NAME, booksType) -queue.deqOptions.wait = cx_Oracle.DEQ_NO_WAIT -queue.deqOptions.navigation = cx_Oracle.DEQ_FIRST_MSG +books_type = connection.gettype(BOOK_TYPE_NAME) +queue = connection.queue(QUEUE_NAME, payload_type=books_type) +queue.deqoptions.wait = oracledb.DEQ_NO_WAIT +queue.deqoptions.navigation = oracledb.DEQ_FIRST_MSG # dequeue all existing messages to ensure the queue is empty, just so that # the results are consistent -while queue.deqOne(): +while queue.deqone(): pass # enqueue a few messages print("Enqueuing messages...") for title, authors, price in BOOK_DATA: - book = booksType.newobject() + book = books_type.newobject() book.TITLE = title book.AUTHORS = authors book.PRICE = price print(title) - queue.enqOne(connection.msgproperties(payload=book)) + queue.enqone(connection.msgproperties(payload=book)) connection.commit() # dequeue the messages print("\nDequeuing messages...") while True: - props = queue.deqOne() + props = queue.deqone() if not props: break print(props.payload.TITLE) diff --git a/python/PLSQLCollection.py b/python/plsql_collection.py similarity index 81% rename from python/PLSQLCollection.py rename to python/plsql_collection.py index b2bb94e3..46997200 100644 --- a/python/PLSQLCollection.py +++ b/python/plsql_collection.py @@ -1,9 +1,9 @@ #------------------------------------------------------------------------------ -# Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. #------------------------------------------------------------------------------ #------------------------------------------------------------------------------ -# PLSQLCollection.py +# plsql_collection.py # # Demonstrate how to get the value of a PL/SQL collection from a stored # procedure. @@ -13,15 +13,15 @@ # is new in cx_Oracle 7.0. #------------------------------------------------------------------------------ -import cx_Oracle -import SampleEnv +import cx_Oracle as oracledb +import sample_env -connection = cx_Oracle.connect(SampleEnv.GetMainConnectString()) +connection = oracledb.connect(sample_env.get_main_connect_string()) # create new empty object of the correct type # note the use of a PL/SQL type defined in a package -typeObj = connection.gettype("PKG_DEMO.UDT_STRINGLIST") -obj = typeObj.newobject() +type_obj = connection.gettype("PKG_DEMO.UDT_STRINGLIST") +obj = type_obj.newobject() # call the stored procedure which will populate the object cursor = connection.cursor() @@ -44,4 +44,3 @@ print("Values of collection as dictionary:") print(obj.asdict()) print() - diff --git a/python/PLSQLFunction.py b/python/plsql_function.py similarity index 71% rename from python/PLSQLFunction.py rename to python/plsql_function.py index 6fd689a1..b67cf4f4 100644 --- a/python/PLSQLFunction.py +++ b/python/plsql_function.py @@ -1,19 +1,18 @@ #------------------------------------------------------------------------------ -# Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. #------------------------------------------------------------------------------ #------------------------------------------------------------------------------ -# PLSQLFunction.py +# plsql_function.py # # Demonstrate how to call a PL/SQL function and get its return value. #------------------------------------------------------------------------------ -import cx_Oracle -import SampleEnv +import cx_Oracle as oracledb +import sample_env -connection = cx_Oracle.connect(SampleEnv.GetMainConnectString()) +connection = oracledb.connect(sample_env.get_main_connect_string()) cursor = connection.cursor() res = cursor.callfunc('myfunc', int, ('abc', 2)) print(res) - diff --git a/python/PLSQLProcedure.py b/python/plsql_procedure.py similarity index 73% rename from python/PLSQLProcedure.py rename to python/plsql_procedure.py index 5a408faf..113d880b 100644 --- a/python/PLSQLProcedure.py +++ b/python/plsql_procedure.py @@ -1,21 +1,20 @@ #------------------------------------------------------------------------------ -# Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. #------------------------------------------------------------------------------ #------------------------------------------------------------------------------ -# PLSQLProcedure.py +# plsql_procedure.py # # Demonstrate how to call a PL/SQL stored procedure and get the results of an # OUT variable. #------------------------------------------------------------------------------ -import cx_Oracle -import SampleEnv +import cx_Oracle as oracledb +import sample_env -connection = cx_Oracle.connect(SampleEnv.GetMainConnectString()) +connection = oracledb.connect(sample_env.get_main_connect_string()) cursor = connection.cursor() myvar = cursor.var(int) cursor.callproc('myproc', (123, myvar)) print(myvar.getvalue()) - diff --git a/python/PLSQLRecord.py b/python/plsql_record.py similarity index 82% rename from python/PLSQLRecord.py rename to python/plsql_record.py index 4691ef49..9e8779e8 100644 --- a/python/PLSQLRecord.py +++ b/python/plsql_record.py @@ -1,9 +1,9 @@ #------------------------------------------------------------------------------ -# Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. #------------------------------------------------------------------------------ #------------------------------------------------------------------------------ -# PLSQLRecord.py +# plsql_record.py # # Demonstrate how to bind (in and out) a PL/SQL record. # @@ -11,17 +11,18 @@ # Database 12.1 and higher. #------------------------------------------------------------------------------ -import cx_Oracle -import SampleEnv import datetime -connection = cx_Oracle.connect(SampleEnv.GetMainConnectString()) +import cx_Oracle as oracledb +import sample_env + +connection = oracledb.connect(sample_env.get_main_connect_string()) # create new object of the correct type # note the use of a PL/SQL record defined in a package # a table record identified by TABLE%ROWTYPE can also be used -typeObj = connection.gettype("PKG_DEMO.UDT_DEMORECORD") -obj = typeObj.newobject() +type_obj = connection.gettype("PKG_DEMO.UDT_DEMORECORD") +obj = type_obj.newobject() obj.NUMBERVALUE = 6 obj.STRINGVALUE = "Test String" obj.DATEVALUE = datetime.datetime(2016, 5, 28) @@ -44,4 +45,3 @@ print("DATEVALUE ->", obj.DATEVALUE) print("BOOLEANVALUE ->", obj.BOOLEANVALUE) print() - diff --git a/python/Query.py b/python/query.py similarity index 82% rename from python/Query.py rename to python/query.py index 17b93148..d96299c8 100644 --- a/python/Query.py +++ b/python/query.py @@ -1,17 +1,17 @@ #------------------------------------------------------------------------------ -# Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. #------------------------------------------------------------------------------ #------------------------------------------------------------------------------ -# Query.py +# query.py # # Demonstrate how to perform a query in different ways. #------------------------------------------------------------------------------ -import cx_Oracle -import SampleEnv +import cx_Oracle as oracledb +import sample_env -connection = cx_Oracle.connect(SampleEnv.GetMainConnectString()) +connection = oracledb.connect(sample_env.get_main_connect_string()) sql = """ select * from SampleQueryTab @@ -34,7 +34,7 @@ print("Fetch many rows") cursor.execute(sql) -res = cursor.fetchmany(numRows=3) +res = cursor.fetchmany(3) print(res) print() diff --git a/python/QueryArraysize.py b/python/query_arraysize.py similarity index 59% rename from python/QueryArraysize.py rename to python/query_arraysize.py index e6b6f2ef..661ddbf5 100644 --- a/python/QueryArraysize.py +++ b/python/query_arraysize.py @@ -1,24 +1,26 @@ #------------------------------------------------------------------------------ -# Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. #------------------------------------------------------------------------------ #------------------------------------------------------------------------------ -# QueryArraysize.py +# query_arraysize.py # -# Demonstrate how to alter the array size on a cursor in order to reduce the -# number of network round trips and overhead required to fetch all of the rows -# from a large table. +# Demonstrate how to alter the array size and prefetch rows value on a cursor +# in order to reduce the number of network round trips and overhead required to +# fetch all of the rows from a large table. #------------------------------------------------------------------------------ import time -import cx_Oracle -import SampleEnv -connection = cx_Oracle.connect(SampleEnv.GetMainConnectString()) +import cx_Oracle as oracledb +import sample_env + +connection = oracledb.connect(sample_env.get_main_connect_string()) start = time.time() cursor = connection.cursor() +cursor.prefetchrows = 1000 cursor.arraysize = 1000 cursor.execute('select * from bigtab') res = cursor.fetchall() @@ -26,4 +28,3 @@ elapsed = (time.time() - start) print("Retrieved", len(res), "rows in", elapsed, "seconds") - diff --git a/python/query_strings_as_bytes.py b/python/query_strings_as_bytes.py new file mode 100644 index 00000000..51b7e43e --- /dev/null +++ b/python/query_strings_as_bytes.py @@ -0,0 +1,49 @@ +#------------------------------------------------------------------------------ +# Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. +#------------------------------------------------------------------------------ + +#------------------------------------------------------------------------------ +# query_strings_as_bytes.py +# +# Demonstrates how to query strings as bytes (bypassing decoding of the bytes +# into a Python string). This can be useful when attempting to fetch data that +# was stored in the database in the wrong encoding. +# +# This script requires cx_Oracle 8.2 and higher. +#------------------------------------------------------------------------------ + +import cx_Oracle as oracledb +import sample_env + +STRING_VAL = 'I bought a cafetière on the Champs-Élysées' + +def return_strings_as_bytes(cursor, name, default_type, size, precision, + scale): + if default_type == oracledb.DB_TYPE_VARCHAR: + return cursor.var(str, arraysize=cursor.arraysize, bypass_decode=True) + +with oracledb.connect(sample_env.get_main_connect_string()) as conn: + + # truncate table and populate with our data of choice + with conn.cursor() as cursor: + cursor.execute("truncate table TestTempTable") + cursor.execute("insert into TestTempTable values (1, :val)", + val=STRING_VAL) + conn.commit() + + # fetch the data normally and show that it is returned as a string + with conn.cursor() as cursor: + cursor.execute("select IntCol, StringCol from TestTempTable") + print("Data fetched using normal technique:") + for row in cursor: + print(row) + print() + + # fetch the data, bypassing the decode and show that it is returned as + # bytes + with conn.cursor() as cursor: + cursor.outputtypehandler = return_strings_as_bytes + cursor.execute("select IntCol, StringCol from TestTempTable") + print("Data fetched using bypass decode technique:") + for row in cursor: + print(row) diff --git a/python/RawAQ.py b/python/raw_aq.py similarity index 74% rename from python/RawAQ.py rename to python/raw_aq.py index 064421b5..3f94c700 100644 --- a/python/RawAQ.py +++ b/python/raw_aq.py @@ -1,5 +1,5 @@ #------------------------------------------------------------------------------ -# Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. # # Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved. # @@ -8,15 +8,15 @@ #------------------------------------------------------------------------------ #------------------------------------------------------------------------------ -# RawAQ.py +# raw_aq.py # This script demonstrates how to use advanced queuing with RAW data using # cx_Oracle. It makes use of a RAW queue created in the sample setup. # -# This script requires cx_Oracle 7.2 and higher. +# This script requires cx_Oracle 8.2 and higher. #------------------------------------------------------------------------------ -import cx_Oracle -import SampleEnv +import cx_Oracle as oracledb +import sample_env QUEUE_NAME = "DEMO_RAW_QUEUE" PAYLOAD_DATA = [ @@ -27,30 +27,30 @@ ] # connect to database -connection = cx_Oracle.connect(SampleEnv.GetMainConnectString()) +connection = oracledb.connect(sample_env.get_main_connect_string()) cursor = connection.cursor() # create queue queue = connection.queue(QUEUE_NAME) -queue.deqOptions.wait = cx_Oracle.DEQ_NO_WAIT -queue.deqOptions.navigation = cx_Oracle.DEQ_FIRST_MSG +queue.deqoptions.wait = oracledb.DEQ_NO_WAIT +queue.deqoptions.navigation = oracledb.DEQ_FIRST_MSG # dequeue all existing messages to ensure the queue is empty, just so that # the results are consistent -while queue.deqOne(): +while queue.deqone(): pass # enqueue a few messages print("Enqueuing messages...") for data in PAYLOAD_DATA: print(data) - queue.enqOne(connection.msgproperties(payload=data)) + queue.enqone(connection.msgproperties(payload=data)) connection.commit() # dequeue the messages print("\nDequeuing messages...") while True: - props = queue.deqOne() + props = queue.deqone() if not props: break print(props.payload.decode()) diff --git a/python/ref_cursor.py b/python/ref_cursor.py new file mode 100644 index 00000000..ffb2ad26 --- /dev/null +++ b/python/ref_cursor.py @@ -0,0 +1,55 @@ +#------------------------------------------------------------------------------ +# Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. +#------------------------------------------------------------------------------ + +#------------------------------------------------------------------------------ +# ref_cursor.py +# Demonstrates the use of REF cursors with cx_Oracle. +#------------------------------------------------------------------------------ + +import cx_Oracle as oracledb +import sample_env + +connection = oracledb.connect(sample_env.get_main_connect_string()) +cursor = connection.cursor() + +ref_cursor = connection.cursor() +cursor.callproc("myrefcursorproc", (2, 6, ref_cursor)) +print("Rows between 2 and 6:") +for row in ref_cursor: + print(row) +print() + +ref_cursor = connection.cursor() +cursor.callproc("myrefcursorproc", (8, 9, ref_cursor)) +print("Rows between 8 and 9:") +for row in ref_cursor: + print(row) +print() + +#------------------------------------------------------------------------------ +# Setting prefetchrows and arraysize of a REF cursor can improve performance +# when fetching a large number of rows (Tuned Fetch) +#------------------------------------------------------------------------------ + +# Truncate the table used for this demo +cursor.execute("truncate table TestTempTable") + +# Populate the table with a large number of rows +num_rows = 50000 +sql = "insert into TestTempTable (IntCol) values (:1)" +data = [(n + 1,) for n in range(num_rows)] +cursor.executemany(sql, data) + +# Set the arraysize and prefetch rows of the REF cursor +ref_cursor = connection.cursor() +ref_cursor.prefetchrows = 1000 +ref_cursor.arraysize = 1000 + +# Perform the tuned fetch +sum_rows = 0 +cursor.callproc("myrefcursorproc2", [ref_cursor]) +print("Sum of IntCol for", num_rows, "rows:") +for row in ref_cursor: + sum_rows += row[0] +print(sum_rows) diff --git a/python/ReturnLobsAsStrings.py b/python/return_lobs_as_strings.py similarity index 63% rename from python/ReturnLobsAsStrings.py rename to python/return_lobs_as_strings.py index 9e1c256a..1c420692 100644 --- a/python/ReturnLobsAsStrings.py +++ b/python/return_lobs_as_strings.py @@ -1,5 +1,5 @@ #------------------------------------------------------------------------------ -# Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. # # Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved. # @@ -8,7 +8,7 @@ #------------------------------------------------------------------------------ #------------------------------------------------------------------------------ -# ReturnLobsAsStrings.py +# return_lobs_as_strings.py # Returns all CLOB values as strings and BLOB values as bytes. The # performance of this technique is significantly better than fetching the LOBs # and then reading the contents of the LOBs as it avoids round-trips to the @@ -18,35 +18,35 @@ # This script requires cx_Oracle 5.0 and higher. #------------------------------------------------------------------------------ -import cx_Oracle -import SampleEnv +import cx_Oracle as oracledb +import sample_env -def OutputTypeHandler(cursor, name, defaultType, size, precision, scale): - if defaultType == cx_Oracle.CLOB: - return cursor.var(cx_Oracle.LONG_STRING, arraysize = cursor.arraysize) - if defaultType == cx_Oracle.BLOB: - return cursor.var(cx_Oracle.LONG_BINARY, arraysize = cursor.arraysize) +def output_type_handler(cursor, name, default_type, size, precision, scale): + if default_type == oracledb.CLOB: + return cursor.var(oracledb.LONG_STRING, arraysize=cursor.arraysize) + if default_type == oracledb.BLOB: + return cursor.var(oracledb.LONG_BINARY, arraysize=cursor.arraysize) -connection = cx_Oracle.connect(SampleEnv.GetMainConnectString()) -connection.outputtypehandler = OutputTypeHandler +connection = oracledb.connect(sample_env.get_main_connect_string()) +connection.outputtypehandler = output_type_handler cursor = connection.cursor() # add some data to the tables print("Populating tables with data...") cursor.execute("truncate table TestClobs") cursor.execute("truncate table TestBlobs") -longString = "" +long_string = "" for i in range(10): char = chr(ord('A') + i) - longString += char * 25000 + long_string += char * 25000 # uncomment the line below for cx_Oracle 5.3 and earlier - # cursor.setinputsizes(None, cx_Oracle.LONG_STRING) + # cursor.setinputsizes(None, oracledb.LONG_STRING) cursor.execute("insert into TestClobs values (:1, :2)", - (i + 1, "STRING " + longString)) + (i + 1, "STRING " + long_string)) # uncomment the line below for cx_Oracle 5.3 and earlier - # cursor.setinputsizes(None, cx_Oracle.LONG_BINARY) + # cursor.setinputsizes(None, oracledb.LONG_BINARY) cursor.execute("insert into TestBlobs values (:1, :2)", - (i + 1, longString.encode("ascii"))) + (i + 1, long_string.encode("ascii"))) connection.commit() # fetch the data and show the results @@ -57,8 +57,8 @@ def OutputTypeHandler(cursor, name, defaultType, size, precision, scale): ClobCol from TestClobs order by IntCol""") -for intCol, value in cursor: - print("Row:", intCol, "string of length", len(value)) +for int_col, value in cursor: + print("Row:", int_col, "string of length", len(value)) print() print("BLOBS returned as bytes") cursor.execute(""" @@ -67,6 +67,5 @@ def OutputTypeHandler(cursor, name, defaultType, size, precision, scale): BlobCol from TestBlobs order by IntCol""") -for intCol, value in cursor: - print("Row:", intCol, "string of length", value and len(value) or 0) - +for int_col, value in cursor: + print("Row:", int_col, "string of length", value and len(value) or 0) diff --git a/python/ReturnNumbersAsDecimals.py b/python/return_numbers_as_decimals.py similarity index 67% rename from python/ReturnNumbersAsDecimals.py rename to python/return_numbers_as_decimals.py index 8d4ca2b6..becb9728 100644 --- a/python/ReturnNumbersAsDecimals.py +++ b/python/return_numbers_as_decimals.py @@ -1,9 +1,9 @@ #------------------------------------------------------------------------------ -# Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. #------------------------------------------------------------------------------ #------------------------------------------------------------------------------ -# ReturnNumbersAsDecimals.py +# return_numbers_as_decimals.py # Returns all numbers as decimals by means of an output type handler. This is # needed if the full decimal precision of Oracle numbers is required by the # application. See this article @@ -14,18 +14,18 @@ # This script requires cx_Oracle 5.0 and higher. #------------------------------------------------------------------------------ -import cx_Oracle import decimal -import SampleEnv -def OutputTypeHandler(cursor, name, defaultType, size, precision, scale): - if defaultType == cx_Oracle.NUMBER: - return cursor.var(decimal.Decimal, arraysize = cursor.arraysize) +import cx_Oracle as oracledb +import sample_env -connection = cx_Oracle.connect(SampleEnv.GetMainConnectString()) -connection.outputtypehandler = OutputTypeHandler +def output_type_handler(cursor, name, default_type, size, precision, scale): + if default_type == oracledb.NUMBER: + return cursor.var(decimal.Decimal, arraysize=cursor.arraysize) + +connection = oracledb.connect(sample_env.get_main_connect_string()) +connection.outputtypehandler = output_type_handler cursor = connection.cursor() cursor.execute("select * from TestNumbers") for row in cursor: print("Row:", row) - diff --git a/python/RowsAsInstance.py b/python/rows_as_instance.py similarity index 89% rename from python/RowsAsInstance.py rename to python/rows_as_instance.py index 827d82b0..1ab1c631 100644 --- a/python/RowsAsInstance.py +++ b/python/rows_as_instance.py @@ -1,5 +1,5 @@ #------------------------------------------------------------------------------ -# Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. # # Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved. # @@ -8,7 +8,7 @@ #------------------------------------------------------------------------------ #------------------------------------------------------------------------------ -# RowsAsInstance.py +# rows_as_instance.py # Returns rows as instances instead of tuples. See the ceDatabase.Row class # in the cx_PyGenLib project (http://cx-pygenlib.sourceforge.net) for a more # advanced example. @@ -16,17 +16,17 @@ # This script requires cx_Oracle 4.3 and higher. #------------------------------------------------------------------------------ -import cx_Oracle -import SampleEnv +import cx_Oracle as oracledb +import sample_env -class Test(object): +class Test: def __init__(self, a, b, c): self.a = a self.b = b self.c = c -connection = cx_Oracle.connect(SampleEnv.GetMainConnectString()) +connection = oracledb.connect(sample_env.get_main_connect_string()) cursor = connection.cursor() # change this to False if you want to create the table yourself using SQL*Plus @@ -55,4 +55,3 @@ def __init__(self, a, b, c): print("Rows:") for row in cursor: print("a = %s, b = %s, c = %s" % (row.a, row.b, row.c)) - diff --git a/python/SampleEnv.py b/python/sample_env.py similarity index 55% rename from python/SampleEnv.py rename to python/sample_env.py index 3d73e773..25006c47 100644 --- a/python/SampleEnv.py +++ b/python/sample_env.py @@ -1,5 +1,5 @@ #------------------------------------------------------------------------------ -# Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. #------------------------------------------------------------------------------ #------------------------------------------------------------------------------ @@ -57,93 +57,95 @@ # directly) and then stored so that a value is not requested more than once PARAMETERS = {} -def GetValue(name, label, defaultValue=""): +def get_value(name, label, default_value=""): value = PARAMETERS.get(name) if value is not None: return value - envName = "CX_ORACLE_SAMPLES_" + name - value = os.environ.get(envName) + env_name = "CX_ORACLE_SAMPLES_" + name + value = os.environ.get(env_name) if value is None: - if defaultValue: - label += " [%s]" % defaultValue + if default_value: + label += " [%s]" % default_value label += ": " - if defaultValue: + if default_value: value = input(label).strip() else: value = getpass.getpass(label) if not value: - value = defaultValue + value = default_value PARAMETERS[name] = value return value -def GetMainUser(): - return GetValue("MAIN_USER", "Main User Name", DEFAULT_MAIN_USER) +def get_main_user(): + return get_value("MAIN_USER", "Main User Name", DEFAULT_MAIN_USER) -def GetMainPassword(): - return GetValue("MAIN_PASSWORD", "Password for %s" % GetMainUser()) +def get_main_password(): + return get_value("MAIN_PASSWORD", "Password for %s" % get_main_user()) -def GetEditionUser(): - return GetValue("EDITION_USER", "Edition User Name", DEFAULT_EDITION_USER) +def get_edition_user(): + return get_value("EDITION_USER", "Edition User Name", DEFAULT_EDITION_USER) -def GetEditionPassword(): - return GetValue("EDITION_PASSWORD", "Password for %s" % GetEditionUser()) +def get_edition_password(): + return get_value("EDITION_PASSWORD", + "Password for %s" % get_edition_user()) -def GetEditionName(): - return GetValue("EDITION_NAME", "Edition Name", DEFAULT_EDITION_NAME) +def get_edition_name(): + return get_value("EDITION_NAME", "Edition Name", DEFAULT_EDITION_NAME) -def GetConnectString(): - return GetValue("CONNECT_STRING", "Connect String", DEFAULT_CONNECT_STRING) +def get_connect_string(): + return get_value("CONNECT_STRING", "Connect String", + DEFAULT_CONNECT_STRING) -def GetMainConnectString(password=None): +def get_main_connect_string(password=None): if password is None: - password = GetMainPassword() - return "%s/%s@%s" % (GetMainUser(), password, GetConnectString()) + password = get_main_password() + return "%s/%s@%s" % (get_main_user(), password, get_connect_string()) -def GetDrcpConnectString(): - connectString = GetValue("DRCP_CONNECT_STRING", "DRCP Connect String", - DEFAULT_DRCP_CONNECT_STRING) - return "%s/%s@%s" % (GetMainUser(), GetMainPassword(), connectString) +def get_drcp_connect_string(): + connect_string = get_value("DRCP_CONNECT_STRING", "DRCP Connect String", + DEFAULT_DRCP_CONNECT_STRING) + return "%s/%s@%s" % (get_main_user(), get_main_password(), connect_string) -def GetEditionConnectString(): +def get_edition_connect_string(): return "%s/%s@%s" % \ - (GetEditionUser(), GetEditionPassword(), GetConnectString()) + (get_edition_user(), get_edition_password(), get_connect_string()) -def GetAdminConnectString(): - adminUser = GetValue("ADMIN_USER", "Administrative user", "admin") - adminPassword = GetValue("ADMIN_PASSWORD", "Password for %s" % adminUser) - return "%s/%s@%s" % (adminUser, adminPassword, GetConnectString()) +def get_admin_connect_string(): + admin_user = get_value("ADMIN_USER", "Administrative user", "admin") + admin_password = get_value("ADMIN_PASSWORD", "Password for %s" % admin_user) + return "%s/%s@%s" % (admin_user, admin_password, get_connect_string()) -def RunSqlScript(conn, scriptName, **kwargs): - statementParts = [] +def run_sql_script(conn, script_name, **kwargs): + statement_parts = [] cursor = conn.cursor() - replaceValues = [("&" + k + ".", v) for k, v in kwargs.items()] + \ - [("&" + k, v) for k, v in kwargs.items()] - scriptDir = os.path.dirname(os.path.abspath(sys.argv[0])) - fileName = os.path.join(scriptDir, "sql", scriptName + "Exec.sql") - for line in open(fileName): + replace_values = [("&" + k + ".", v) for k, v in kwargs.items()] + \ + [("&" + k, v) for k, v in kwargs.items()] + script_dir = os.path.dirname(os.path.abspath(sys.argv[0])) + file_name = os.path.join(script_dir, "sql", script_name + "_exec.sql") + for line in open(file_name): if line.strip() == "/": - statement = "".join(statementParts).strip() + statement = "".join(statement_parts).strip() if statement: - for searchValue, replaceValue in replaceValues: - statement = statement.replace(searchValue, replaceValue) + for search_value, replace_value in replace_values: + statement = statement.replace(search_value, replace_value) try: cursor.execute(statement) except: print("Failed to execute SQL:", statement) raise - statementParts = [] + statement_parts = [] else: - statementParts.append(line) + statement_parts.append(line) cursor.execute(""" select name, type, line, position, text from dba_errors where owner = upper(:owner) order by name, type, line, position""", - owner = GetMainUser()) - prevName = prevObjType = None - for name, objType, lineNum, position, text in cursor: - if name != prevName or objType != prevObjType: - print("%s (%s)" % (name, objType)) - prevName = name - prevObjType = objType - print(" %s/%s %s" % (lineNum, position, text)) + owner = get_main_user()) + prev_name = prev_obj_type = None + for name, obj_type, line_num, position, text in cursor: + if name != prev_name or obj_type != prev_obj_type: + print("%s (%s)" % (name, obj_type)) + prev_name = name + prev_obj_type = obj_type + print(" %s/%s %s" % (line_num, position, text)) diff --git a/python/ScrollableCursors.py b/python/scrollable_cursors.py similarity index 90% rename from python/ScrollableCursors.py rename to python/scrollable_cursors.py index 22ea28f2..3fb855b1 100644 --- a/python/ScrollableCursors.py +++ b/python/scrollable_cursors.py @@ -1,5 +1,5 @@ #------------------------------------------------------------------------------ -# Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. # # Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved. # @@ -8,7 +8,7 @@ #------------------------------------------------------------------------------ #------------------------------------------------------------------------------ -# ScrollableCursors.py +# scrollable_cursors.py # This script demonstrates how to use scrollable cursors. These allow moving # forward and backward in the result set but incur additional overhead on the # server to retain this information. @@ -16,10 +16,10 @@ # This script requires cx_Oracle 5.3 and higher. #------------------------------------------------------------------------------ -import cx_Oracle -import SampleEnv +import cx_Oracle as oracledb +import sample_env -connection = cx_Oracle.connect(SampleEnv.GetMainConnectString()) +connection = oracledb.connect(sample_env.get_main_connect_string()) # show all of the rows available in the table cursor = connection.cursor() @@ -68,4 +68,3 @@ print("SKIP BACK 4 ROWS") print(cursor.fetchone()) print() - diff --git a/python/SessionCallback.py b/python/session_callback.py similarity index 82% rename from python/SessionCallback.py rename to python/session_callback.py index a703d4b5..a1507fc8 100644 --- a/python/SessionCallback.py +++ b/python/session_callback.py @@ -1,9 +1,9 @@ #------------------------------------------------------------------------------ -# Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. #------------------------------------------------------------------------------ #------------------------------------------------------------------------------ -# SessionCallback.py +# session_callback.py # # Demonstrate how to use a connection pool session callback written in # Python. The callback is invoked whenever a newly created session is acquired @@ -16,12 +16,12 @@ # # This script requires cx_Oracle 7.1 or higher. # -# Also see SessionCallbackPLSQL.py +# Also see session_callback_plsql.py # #------------------------------------------------------------------------------ -import cx_Oracle -import SampleEnv +import cx_Oracle as oracledb +import sample_env # define a dictionary of NLS_DATE_FORMAT formats supported by this sample SUPPORTED_FORMATS = { @@ -42,45 +42,46 @@ } # define session callback -def InitSession(conn, requestedTag): +def init_session(conn, requested_tag): # display the requested and actual tags - print("InitSession(): requested tag=%r, actual tag=%r" % \ - (requestedTag, conn.tag)) + print("init_session(): requested tag=%r, actual tag=%r" % \ + (requested_tag, conn.tag)) # tags are expected to be in the form "key1=value1;key2=value2" # in this example, they are used to set NLS parameters and the tag is # parsed to validate it - if requestedTag is not None: - stateParts = [] - for directive in requestedTag.split(";"): + if requested_tag is not None: + state_parts = [] + for directive in requested_tag.split(";"): parts = directive.split("=") if len(parts) != 2: raise ValueError("Tag must contain key=value pairs") key, value = parts - valueDict = SUPPORTED_KEYS.get(key) - if valueDict is None: + value_dict = SUPPORTED_KEYS.get(key) + if value_dict is None: raise ValueError("Tag only supports keys: %s" % \ (", ".join(SUPPORTED_KEYS))) - actualValue = valueDict.get(value) - if actualValue is None: + actual_value = value_dict.get(value) + if actual_value is None: raise ValueError("Key %s only supports values: %s" % \ - (key, ", ".join(valueDict))) - stateParts.append("%s = %s" % (key, actualValue)) - sql = "alter session set %s" % " ".join(stateParts) + (key, ", ".join(value_dict))) + state_parts.append("%s = %s" % (key, actual_value)) + sql = "alter session set %s" % " ".join(state_parts) cursor = conn.cursor() cursor.execute(sql) # assign the requested tag to the connection so that when the connection # is closed, it will automatically be retagged; note that if the requested # tag is None (no tag was requested) this has no effect - conn.tag = requestedTag + conn.tag = requested_tag # create pool with session callback defined -pool = cx_Oracle.SessionPool(SampleEnv.GetMainUser(), - SampleEnv.GetMainPassword(), SampleEnv.GetConnectString(), min=2, - max=5, increment=1, threaded=True, sessionCallback=InitSession) +pool = oracledb.SessionPool(user=sample_env.get_main_user(), + password=sample_env.get_main_password(), + dsn=sample_env.get_connect_string(), min=2, max=5, + increment=1, session_callback=init_session) # acquire session without specifying a tag; since the session returned is # newly created, the callback will be invoked but since there is no tag diff --git a/python/SessionCallbackPLSQL.py b/python/session_callback_plsql.py similarity index 88% rename from python/SessionCallbackPLSQL.py rename to python/session_callback_plsql.py index 7a4f01e0..a36fc5c2 100644 --- a/python/SessionCallbackPLSQL.py +++ b/python/session_callback_plsql.py @@ -1,9 +1,9 @@ #------------------------------------------------------------------------------ -# Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. #------------------------------------------------------------------------------ #------------------------------------------------------------------------------ -# SessionCallbackPLSQL.py +# session_callback_plsql.py # # Demonstrate how to use a connection pool session callback written in # PL/SQL. The callback is invoked whenever the tag requested by the application @@ -13,23 +13,23 @@ # database. # # The primary advantage to this approach over the equivalent approach shown in -# SessionCallback.py is when DRCP is used, as the callback is invoked on the +# session_callback.py is when DRCP is used, as the callback is invoked on the # server and no round trip is required to set state. # # This script requires cx_Oracle 7.1 or higher. # -# Also see SessionCallback.py +# Also see session_callback.py # #------------------------------------------------------------------------------ -import cx_Oracle -import SampleEnv +import cx_Oracle as oracledb +import sample_env # create pool with session callback defined -pool = cx_Oracle.SessionPool(SampleEnv.GetMainUser(), - SampleEnv.GetMainPassword(), SampleEnv.GetConnectString(), min=2, - max=5, increment=1, threaded=True, - sessionCallback="pkg_SessionCallback.TheCallback") +pool = oracledb.SessionPool(user=sample_env.get_main_user(), + password=sample_env.get_main_password(), + dsn=sample_env.get_connect_string(), min=2, max=5, + increment=1, session_callback="pkg_SessionCallback.TheCallback") # truncate table logging calls to PL/SQL session callback with pool.acquire() as conn: diff --git a/python/SetupSamples.py b/python/setup_samples.py similarity index 52% rename from python/SetupSamples.py rename to python/setup_samples.py index 076b354c..6baa4e90 100644 --- a/python/SetupSamples.py +++ b/python/setup_samples.py @@ -1,33 +1,32 @@ #------------------------------------------------------------------------------ -# Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. #------------------------------------------------------------------------------ #------------------------------------------------------------------------------ -# SetupSamples.py +# setup_samples.py # # Creates users and populates their schemas with the tables and packages # necessary for the cx_Oracle samples. An edition is also created for the # demonstration of PL/SQL editioning. #------------------------------------------------------------------------------ -import cx_Oracle +import cx_Oracle as oracledb -import SampleEnv -import DropSamples +import sample_env +import drop_samples # connect as administrative user (usually SYSTEM or ADMIN) -conn = cx_Oracle.connect(SampleEnv.GetAdminConnectString()) +conn = oracledb.connect(sample_env.get_admin_connect_string()) # drop existing users and editions, if applicable -DropSamples.DropSamples(conn) +drop_samples.drop_samples(conn) # create sample schema and edition print("Creating sample schemas and edition...") -SampleEnv.RunSqlScript(conn, "SetupSamples", - main_user = SampleEnv.GetMainUser(), - main_password = SampleEnv.GetMainPassword(), - edition_user = SampleEnv.GetEditionUser(), - edition_password = SampleEnv.GetEditionPassword(), - edition_name = SampleEnv.GetEditionName()) +sample_env.run_sql_script(conn, "setup_samples", + main_user=sample_env.get_main_user(), + main_password=sample_env.get_main_password(), + edition_user=sample_env.get_edition_user(), + edition_password=sample_env.get_edition_password(), + edition_name=sample_env.get_edition_name()) print("Done.") - diff --git a/python/ShardingNumberKey.py b/python/sharding_number_key.py similarity index 63% rename from python/ShardingNumberKey.py rename to python/sharding_number_key.py index 8e4adf25..a71ac1a5 100644 --- a/python/ShardingNumberKey.py +++ b/python/sharding_number_key.py @@ -1,9 +1,9 @@ #------------------------------------------------------------------------------ -# Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. #------------------------------------------------------------------------------ #------------------------------------------------------------------------------ -# ShardingNumberKey.py +# sharding_number_key.py # This script demonstrates how to use sharding keys with a sharded database. # The sample schema provided does not include support for running this demo. A # sharded database must first be created. Information on how to create a @@ -15,20 +15,21 @@ # sharding capabilities. #------------------------------------------------------------------------------ -import cx_Oracle -import SampleEnv +import cx_Oracle as oracledb +import sample_env -pool = cx_Oracle.SessionPool(SampleEnv.GetMainUser(), - SampleEnv.GetMainPassword(), SampleEnv.GetConnectString(), min=1, - max=5, increment=1) +pool = oracledb.SessionPool(user=sample_env.get_main_user(), + password=sample_env.get_main_password(), + dsn=sample_env.get_connect_string(), min=1, max=5, + increment=1) -def ConnectAndDisplay(shardingKey): - print("Connecting with sharding key:", shardingKey) - with pool.acquire(shardingkey=[shardingKey]) as conn: +def connect_and_display(sharding_key): + print("Connecting with sharding key:", sharding_key) + with pool.acquire(shardingkey=[sharding_key]) as conn: cursor = conn.cursor() cursor.execute("select sys_context('userenv', 'db_name') from dual") name, = cursor.fetchone() print("--> connected to database", name) -ConnectAndDisplay(100) -ConnectAndDisplay(167) +connect_and_display(100) +connect_and_display(167) diff --git a/python/SodaBasic.py b/python/soda_basic.py similarity index 69% rename from python/SodaBasic.py rename to python/soda_basic.py index b69330be..a04713af 100644 --- a/python/SodaBasic.py +++ b/python/soda_basic.py @@ -1,9 +1,9 @@ #------------------------------------------------------------------------------ -# Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. #------------------------------------------------------------------------------ #------------------------------------------------------------------------------ -# SodaBasic.py +# soda_basic.py # A basic Simple Oracle Document Access (SODA) example. # # This script requires cx_Oracle 7.0 and higher. @@ -12,10 +12,10 @@ # The user must have been granted the SODA_APP privilege. #------------------------------------------------------------------------------ -import cx_Oracle -import SampleEnv +import cx_Oracle as oracledb +import sample_env -connection = cx_Oracle.connect(SampleEnv.GetMainConnectString()) +connection = oracledb.connect(sample_env.get_main_connect_string()) # The general recommendation for simple SODA usage is to enable autocommit connection.autocommit = True @@ -23,16 +23,49 @@ # Create the parent object for SODA soda = connection.getSodaDatabase() +# drop the collection if it already exists in order to ensure that the sample +# runs smoothly each time +collection = soda.openCollection("mycollection") +if collection is not None: + collection.drop() + +# Explicit metadata is used for maximum version portability. +# Refer to the documentation. +metadata = { + "keyColumn": { + "name": "ID" + }, + "contentColumn": { + "name": "JSON_DOCUMENT", + "sqlType": "BLOB" + }, + "versionColumn": { + "name": "VERSION", + "method": "UUID" + }, + "lastModifiedColumn": { + "name": "LAST_MODIFIED" + }, + "creationTimeColumn": { + "name": "CREATED_ON" + } +} + # Create a new SODA collection and index # This will open an existing collection, if the name is already in use. -collection = soda.createCollection("mycollection") - -indexSpec = { 'name': 'CITY_IDX', - 'fields': [ { - 'path': 'address.city', - 'datatype': 'string', - 'order': 'asc' } ] } -collection.createIndex(indexSpec) +collection = soda.createCollection("mycollection", metadata) + +index_spec = { + 'name': 'CITY_IDX', + 'fields': [ + { + 'path': 'address.city', + 'datatype': 'string', + 'order': 'asc' + } + ] +} +collection.createIndex(index_spec) # Insert a document. # A system generated key is created by default. @@ -85,4 +118,3 @@ # Drop the collection if collection.drop(): print('Collection was dropped') - diff --git a/python/SodaBulkInsert.py b/python/soda_bulk_insert.py similarity index 58% rename from python/SodaBulkInsert.py rename to python/soda_bulk_insert.py index b479a6a7..714276a3 100644 --- a/python/SodaBulkInsert.py +++ b/python/soda_bulk_insert.py @@ -1,9 +1,9 @@ #------------------------------------------------------------------------------ -# Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. #------------------------------------------------------------------------------ #------------------------------------------------------------------------------ -# SodaBulkInsert.py +# soda_bulk_insert.py # Demonstrates the use of SODA bulk insert. # # This script requires cx_Oracle 7.2 and higher. @@ -12,10 +12,10 @@ # The user must have been granted the SODA_APP privilege. #------------------------------------------------------------------------------ -import cx_Oracle -import SampleEnv +import cx_Oracle as oracledb +import sample_env -connection = cx_Oracle.connect(SampleEnv.GetMainConnectString()) +connection = oracledb.connect(sample_env.get_main_connect_string()) # the general recommendation for simple SODA usage is to enable autocommit connection.autocommit = True @@ -23,14 +23,42 @@ # create the parent object for all SODA work soda = connection.getSodaDatabase() +# drop the collection if it already exists in order to ensure that the sample +# runs smoothly each time +collection = soda.openCollection("SodaBulkInsert") +if collection is not None: + collection.drop() + +# Explicit metadata is used for maximum version portability. +# Refer to the documentation. +metadata = { + "keyColumn": { + "name": "ID" + }, + "contentColumn": { + "name": "JSON_DOCUMENT", + "sqlType": "BLOB" + }, + "versionColumn": { + "name": "VERSION", + "method": "UUID" + }, + "lastModifiedColumn": { + "name": "LAST_MODIFIED" + }, + "creationTimeColumn": { + "name": "CREATED_ON" + } +} + # create a new (or open an existing) SODA collection -collection = soda.createCollection("SodaBulkInsert") +collection = soda.createCollection("SodaBulkInsert", metadata) # remove all documents from the collection collection.find().remove() # define some documents that will be stored -inDocs = [ +in_docs = [ dict(name="Sam", age=8), dict(name="George", age=46), dict(name="Bill", age=35), @@ -40,8 +68,8 @@ ] # perform bulk insert -resultDocs = collection.insertManyAndGet(inDocs) -for doc in resultDocs: +result_docs = collection.insertManyAndGet(in_docs) +for doc in result_docs: print("Inserted SODA document with key", doc.key) print() diff --git a/python/SpatialToGeoPandas.py b/python/spatial_to_geopandas.py similarity index 87% rename from python/SpatialToGeoPandas.py rename to python/spatial_to_geopandas.py index a7f59766..1652e128 100644 --- a/python/SpatialToGeoPandas.py +++ b/python/spatial_to_geopandas.py @@ -1,9 +1,9 @@ #------------------------------------------------------------------------------ -# Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. #------------------------------------------------------------------------------ #------------------------------------------------------------------------------ -# SpatialToGeoPandas.py +# spatial_to_geopandas.py # GeoPandas is a popular python library for working with geospatial data. # GeoPandas extends the Pandas data analysis library with geospatial support # using the Shapely library for geometry object support. @@ -22,13 +22,14 @@ # dependencies (see http://geopandas.org/install.html). #------------------------------------------------------------------------------ -import SampleEnv -import cx_Oracle from shapely.wkb import loads import geopandas as gpd +import cx_Oracle as oracledb +import sample_env + # create Oracle connection and cursor objects -connection = cx_Oracle.connect(SampleEnv.GetMainConnectString()) +connection = oracledb.connect(sample_env.get_main_connect_string()) cursor = connection.cursor() # enable autocommit to avoid the additional round trip to the database to @@ -38,10 +39,10 @@ # define output type handler to fetch LOBs, avoiding the second round trip to # the database to read the LOB contents -def OutputTypeHandler(cursor, name, defaultType, size, precision, scale): - if defaultType == cx_Oracle.BLOB: - return cursor.var(cx_Oracle.LONG_BINARY, arraysize = cursor.arraysize) -connection.outputtypehandler = OutputTypeHandler +def output_type_handler(cursor, name, default_type, size, precision, scale): + if default_type == oracledb.BLOB: + return cursor.var(oracledb.LONG_BINARY, arraysize=cursor.arraysize) +connection.outputtypehandler = output_type_handler # drop and create table print("Dropping and creating table...") @@ -60,23 +61,23 @@ def OutputTypeHandler(cursor, name, defaultType, size, precision, scale): )""") # acquire types used for creating SDO_GEOMETRY objects -typeObj = connection.gettype("MDSYS.SDO_GEOMETRY") -elementInfoTypeObj = connection.gettype("MDSYS.SDO_ELEM_INFO_ARRAY") -ordinateTypeObj = connection.gettype("MDSYS.SDO_ORDINATE_ARRAY") +type_obj = connection.gettype("MDSYS.SDO_GEOMETRY") +element_info_type_obj = connection.gettype("MDSYS.SDO_ELEM_INFO_ARRAY") +ordinate_type_obj = connection.gettype("MDSYS.SDO_ORDINATE_ARRAY") # define function for creating an SDO_GEOMETRY object -def CreateGeometryObj(*ordinates): - geometry = typeObj.newobject() +def create_geometry_obj(*ordinates): + geometry = type_obj.newobject() geometry.SDO_GTYPE = 2003 geometry.SDO_SRID = 8307 - geometry.SDO_ELEM_INFO = elementInfoTypeObj.newobject() + geometry.SDO_ELEM_INFO = element_info_type_obj.newobject() geometry.SDO_ELEM_INFO.extend([1, 1003, 1]) - geometry.SDO_ORDINATES = ordinateTypeObj.newobject() + geometry.SDO_ORDINATES = ordinate_type_obj.newobject() geometry.SDO_ORDINATES.extend(ordinates) return geometry # create SDO_GEOMETRY objects for three adjacent states in the USA -geometryNevada = CreateGeometryObj(-114.052025, 37.103989, -114.049797, +geometry_nevada = create_geometry_obj(-114.052025, 37.103989, -114.049797, 37.000423, -113.484375, 37, -112.898598, 37.000401,-112.539604, 37.000683, -112, 37.000977, -111.412048, 37.001514, -111.133018, 37.00079,-110.75, 37.003201, -110.5, 37.004265, -110.469505, 36.998001, @@ -96,7 +97,7 @@ def CreateGeometryObj(*ordinates): -114.049339, 38.572968, -114.049095, 38.14864, -114.0476, 37.80946,-114.05098, 37.746284, -114.051666, 37.604805, -114.052025, 37.103989) -geometryWyoming = CreateGeometryObj(-111.045815, 41.251774, -111.045982, +geometry_wyoming = create_geometry_obj(-111.045815, 41.251774, -111.045982, 40.998013, -110.5, 40.994801, -110.047768, 40.997696, -110, 40.997398, -109.534233, 40.998184, -109.2313, 41.002102, -109.0494, 41.000702, -108.525368, 40.999634, -107.917793, 41.002071, -107.317177, 41.002956, @@ -120,7 +121,7 @@ def CreateGeometryObj(*ordinates): -111.043846, 43.3158, -111.043381, 43.02013, -111.042786, 42.719578, -111.045967, 42.513187, -111.045944, 42.001633, -111.045097, 41.579899, -111.045815, 41.251774) -geometryColorado = CreateGeometryObj(-109.045143, 37.375, -109.044571, +geometry_colorado = create_geometry_obj(-109.045143, 37.375, -109.044571, 36.999088, -108.378571, 36.999516, -107.481133, 37, -107.420311, 37, -106.876701, 37.00013, -106.869209, 36.992416, -106.475639, 36.993748, -106.006058, 36.995327, -105.717834, 36.995823, -105.220055, 36.995144, @@ -151,9 +152,9 @@ def CreateGeometryObj(*ordinates): # will skip the metadata and indexes. print("Adding rows to table...") data = [ - ('Nevada', geometryNevada), - ('Colorado', geometryColorado), - ('Wyoming', geometryWyoming) + ('Nevada', geometry_nevada), + ('Colorado', geometry_colorado), + ('Wyoming', geometry_wyoming) ] cursor.executemany('insert into TestStates values (:state, :obj)', data) @@ -168,7 +169,7 @@ def CreateGeometryObj(*ordinates): cursor.execute(""" SELECT state, sdo_util.to_wkbgeometry(geometry) FROM TestStates""") -gdf = gpd.GeoDataFrame(cursor.fetchall(), columns = ['state', 'wkbgeometry']) +gdf = gpd.GeoDataFrame(cursor.fetchall(), columns=['state', 'wkbgeometry']) # create GeoSeries to replace the WKB geometry column gdf['geometry'] = gpd.GeoSeries(gdf['wkbgeometry'].apply(lambda x: loads(x))) @@ -183,4 +184,3 @@ def CreateGeometryObj(*ordinates): print() print("GeoPandas combining the 3 geometries into a single geometry...") print(gdf.unary_union) - diff --git a/python/sql/DropSamples.sql b/python/sql/drop_samples.sql similarity index 88% rename from python/sql/DropSamples.sql rename to python/sql/drop_samples.sql index 901895c2..eca66a94 100644 --- a/python/sql/DropSamples.sql +++ b/python/sql/drop_samples.sql @@ -3,11 +3,11 @@ *---------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------- - * DropSamples.sql + * drop_samples.sql * Drops database objects used for cx_Oracle samples. * * Run this like: - * sqlplus sys/syspassword@hostname/servicename as sysdba @DropSamples + * sqlplus sys/syspassword@hostname/servicename as sysdba @drop_samples *---------------------------------------------------------------------------*/ whenever sqlerror exit failure @@ -23,7 +23,6 @@ accept edition_name char default python_e1 - set feedback on -- perform work -@@DropSamplesExec.sql +@@drop_samples_exec.sql exit - diff --git a/python/sql/DropSamplesExec.sql b/python/sql/drop_samples_exec.sql similarity index 81% rename from python/sql/DropSamplesExec.sql rename to python/sql/drop_samples_exec.sql index 4f274fd0..dc0ab7a7 100644 --- a/python/sql/DropSamplesExec.sql +++ b/python/sql/drop_samples_exec.sql @@ -3,11 +3,11 @@ *---------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------- - * DropSamplesExec.sql + * drop_samples_exec.sql * This script performs the actual work of dropping the database schemas and - * edition used by the cx_Oracle samples. It is called by the DropSamples.sql - * and SetupSamples.sql files after acquiring the necessary parameters and - * also by the Python script DropSamples.py. + * edition used by the cx_Oracle samples. It is called by the drop_samples.sql + * and setup_samples.sql files after acquiring the necessary parameters and + * also by the Python script drop_samples.py. *---------------------------------------------------------------------------*/ begin @@ -30,4 +30,3 @@ begin end; / - diff --git a/python/sql/SetupSamples.sql b/python/sql/setup_samples.sql similarity index 88% rename from python/sql/SetupSamples.sql rename to python/sql/setup_samples.sql index f28c6af7..56c8554e 100644 --- a/python/sql/SetupSamples.sql +++ b/python/sql/setup_samples.sql @@ -3,13 +3,13 @@ *---------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------- - * SetupSamples.sql + * setup_samples.sql * Creates and populates schemas with the database objects used by the * cx_Oracle samples. An edition is also created for the demonstration of * PL/SQL editioning. * * Run this like: - * sqlplus sys/syspassword@hostname/servicename as sysdba @SetupSamples + * sqlplus sys/syspassword@hostname/servicename as sysdba @setup_samples *---------------------------------------------------------------------------*/ whenever sqlerror exit failure @@ -27,8 +27,7 @@ accept edition_name char default python_e1 - set feedback on -- perform work -@@DropSamplesExec.sql -@@SetupSamplesExec.sql +@@drop_samples_exec.sql +@@setup_samples_exec.sql exit - diff --git a/python/sql/SetupSamplesExec.sql b/python/sql/setup_samples_exec.sql similarity index 97% rename from python/sql/SetupSamplesExec.sql rename to python/sql/setup_samples_exec.sql index 8fc0ebaf..0095e620 100644 --- a/python/sql/SetupSamplesExec.sql +++ b/python/sql/setup_samples_exec.sql @@ -3,12 +3,12 @@ *---------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------- - * SetupSamplesExec.sql + * setup_samples_exec.sql * This script performs the actual work of creating and populating the * schemas with the database objects used by the cx_Oracle samples. An edition * is also created for the demonstration of PL/SQL editioning. It is called by - * the SetupSamples.sql file after acquiring the necessary parameters and also - * by the Python script SetupSamples.py. + * the setup_samples.sql file after acquiring the necessary parameters and also + * by the Python script setup_samples.py. *---------------------------------------------------------------------------*/ alter session set nls_date_format = 'YYYY-MM-DD HH24:MI:SS' @@ -30,7 +30,7 @@ grant to &main_user / -grant execute on dbms_aqadm to &main_user +grant aq_administrator_role to &main_user / begin @@ -382,6 +382,15 @@ begin end; / +create procedure &main_user..myrefcursorproc2 ( + a_RefCursor out sys_refcursor +) as +begin + open a_RefCursor for + select * + from TestTempTable; +end; +/ -- -- Create package for demoing PL/SQL collections and records. @@ -547,4 +556,3 @@ create or replace package body &main_user..pkg_SessionCallback as end; / - diff --git a/python/Subclassing.py b/python/subclassing.py similarity index 69% rename from python/Subclassing.py rename to python/subclassing.py index b4aceacb..13288bc5 100644 --- a/python/Subclassing.py +++ b/python/subclassing.py @@ -1,27 +1,27 @@ #------------------------------------------------------------------------------ -# Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. #------------------------------------------------------------------------------ #------------------------------------------------------------------------------ -# Subclassing.py +# subclassing.py # -# Demonstrate how to subclass cx_Oracle connections and cursors in order to +# Demonstrate how to subclass cx_Oracle connections and cursors in order to # add additional functionality (like logging) or create specialized interfaces # for paticular applications. #------------------------------------------------------------------------------ -import cx_Oracle -import SampleEnv +import cx_Oracle as oracledb +import sample_env # sample subclassed connection which overrides the constructor (so no # parameters are required) and the cursor() method (so that the subclassed # cursor is returned instead of the default cursor implementation) -class Connection(cx_Oracle.Connection): +class Connection(oracledb.Connection): def __init__(self): - connectString = SampleEnv.GetMainConnectString() + connect_string = sample_env.get_main_connect_string() print("CONNECT to database") - return super(Connection, self).__init__(connectString) + super().__init__(connect_string) def cursor(self): return Cursor(self) @@ -29,18 +29,18 @@ def cursor(self): # sample subclassed cursor which overrides the execute() and fetchone() # methods in order to perform some simple logging -class Cursor(cx_Oracle.Cursor): +class Cursor(oracledb.Cursor): def execute(self, statement, args): print("EXECUTE", statement) print("ARGS:") - for argIndex, arg in enumerate(args): - print(" ", argIndex + 1, "=>", repr(arg)) - return super(Cursor, self).execute(statement, args) + for arg_index, arg in enumerate(args): + print(" ", arg_index + 1, "=>", repr(arg)) + return super().execute(statement, args) def fetchone(self): print("FETCH ONE") - return super(Cursor, self).fetchone() + return super().fetchone() # create instances of the subclassed connection and cursor @@ -51,4 +51,3 @@ def fetchone(self): cursor.execute("select count(*) from ChildTable where ParentId = :1", (30,)) count, = cursor.fetchone() print("COUNT:", int(count)) - diff --git a/python/TransactionGuard.py b/python/transaction_guard.py similarity index 80% rename from python/TransactionGuard.py rename to python/transaction_guard.py index 9e26ef1d..82284c01 100644 --- a/python/TransactionGuard.py +++ b/python/transaction_guard.py @@ -1,5 +1,5 @@ #------------------------------------------------------------------------------ -# Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. # # Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved. # @@ -8,7 +8,7 @@ #------------------------------------------------------------------------------ #------------------------------------------------------------------------------ -# TransactionGuard.py +# transaction_guard.py # This script demonstrates the use of Transaction Guard to verify if a # transaction has completed, ensuring that a duplicate transaction is not # created or attempted if the application chooses to handle the error. This @@ -33,17 +33,18 @@ # This script requires cx_Oracle 5.3 and higher. #------------------------------------------------------------------------------ -import cx_Oracle -import SampleEnv import sys +import cx_Oracle as oracledb +import sample_env + # constants CONNECT_STRING = "localhost/orcl-tg" # create transaction and generate a recoverable error -pool = cx_Oracle.SessionPool(SampleEnv.GetMainUser(), - SampleEnv.GetMainPassword(), CONNECT_STRING, min=1, - max=9, increment=2) +pool = oracledb.SessionPool(user=sample_env.get_main_user(), + password=sample_env.get_main_password(), + dsn=CONNECT_STRING, min=1, max=9, increment=2) connection = pool.acquire() cursor = connection.cursor() cursor.execute(""" @@ -53,13 +54,13 @@ insert into TestTempTable values (1, null)""") input("Please kill %s session now. Press ENTER when complete." % \ - SampleEnv.GetMainUser()) + sample_env.get_main_user()) try: connection.commit() # this should fail sys.exit("Session was not killed. Terminating.") -except cx_Oracle.DatabaseError as e: - errorObj, = e.args - if not errorObj.isrecoverable: +except oracledb.DatabaseError as e: + error_obj, = e.args + if not error_obj.isrecoverable: sys.exit("Session is not recoverable. Terminating.") ltxid = connection.ltxid if not ltxid: @@ -69,8 +70,8 @@ # check if previous transaction completed connection = pool.acquire() cursor = connection.cursor() +args = (oracledb.Binary(ltxid), cursor.var(bool), cursor.var(bool)) _, committed, completed = cursor.callproc("dbms_app_cont.get_ltxid_outcome", - (cx_Oracle.Binary(ltxid), cursor.var(bool), cursor.var(bool))) + args) print("Failed transaction was committed:", committed) print("Failed call was completed:", completed) - diff --git a/python/TypeHandlers.py b/python/type_handlers.py similarity index 57% rename from python/TypeHandlers.py rename to python/type_handlers.py index c816b9df..7bdbe866 100644 --- a/python/TypeHandlers.py +++ b/python/type_handlers.py @@ -1,5 +1,5 @@ #------------------------------------------------------------------------------ -# Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. # # Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved. # @@ -8,7 +8,7 @@ #------------------------------------------------------------------------------ #------------------------------------------------------------------------------ -# TypeHandlers.py +# type_handlers.py # This script demonstrates the use of input and output type handlers as well # as variable input and output converters. These methods can be used to extend # cx_Oracle in many ways. This script demonstrates the binding and querying of @@ -17,48 +17,49 @@ # This script requires cx_Oracle 5.0 and higher. #------------------------------------------------------------------------------ -import cx_Oracle import datetime -import SampleEnv -con = cx_Oracle.connect(SampleEnv.GetMainConnectString()) -objType = con.gettype("UDT_BUILDING") +import cx_Oracle as oracledb +import sample_env -class Building(object): +con = oracledb.connect(sample_env.get_main_connect_string()) +obj_type = con.gettype("UDT_BUILDING") - def __init__(self, buildingId, description, numFloors, dateBuilt): - self.buildingId = buildingId +class Building: + + def __init__(self, building_id, description, num_floors, date_built): + self.building_id = building_id self.description = description - self.numFloors = numFloors - self.dateBuilt = dateBuilt + self.num_floors = num_floors + self.date_built = date_built def __repr__(self): - return "" % (self.buildingId, self.description) + return "" % (self.building_id, self.description) -def BuildingInConverter(value): - obj = objType.newobject() - obj.BUILDINGID = value.buildingId +def building_in_converter(value): + obj = obj_type.newobject() + obj.BUILDINGID = value.building_id obj.DESCRIPTION = value.description - obj.NUMFLOORS = value.numFloors - obj.DATEBUILT = value.dateBuilt + obj.NUMFLOORS = value.num_floors + obj.DATEBUILT = value.date_built return obj -def BuildingOutConverter(obj): +def building_out_converter(obj): return Building(int(obj.BUILDINGID), obj.DESCRIPTION, int(obj.NUMFLOORS), - obj.DATEBUILT) + obj.DATEBUILT) -def InputTypeHandler(cursor, value, numElements): +def input_type_handler(cursor, value, num_elements): if isinstance(value, Building): - return cursor.var(cx_Oracle.OBJECT, arraysize = numElements, - inconverter = BuildingInConverter, typename = objType.name) + return cursor.var(obj_type, arraysize=num_elements, + inconverter=building_in_converter) -def OutputTypeHandler(cursor, name, defaultType, size, precision, scale): - if defaultType == cx_Oracle.OBJECT: - return cursor.var(cx_Oracle.OBJECT, arraysize = cursor.arraysize, - outconverter = BuildingOutConverter, typename = objType.name) +def output_type_handler(cursor, name, default_type, size, precision, scale): + if default_type == oracledb.OBJECT: + return cursor.var(obj_type, arraysize=cursor.arraysize, + outconverter=building_out_converter) buildings = [ Building(1, "The First Building", 5, datetime.date(2007, 5, 18)), @@ -67,12 +68,12 @@ def OutputTypeHandler(cursor, name, defaultType, size, precision, scale): ] cur = con.cursor() -cur.inputtypehandler = InputTypeHandler +cur.inputtypehandler = input_type_handler for building in buildings: try: cur.execute("insert into TestBuildings values (:1, :2)", - (building.buildingId, building)) - except cx_Oracle.DatabaseError as e: + (building.building_id, building)) + except oracledb.DatabaseError as e: error, = e.args print("CONTEXT:", error.context) print("MESSAGE:", error.message) @@ -84,9 +85,8 @@ def OutputTypeHandler(cursor, name, defaultType, size, precision, scale): print() cur = con.cursor() -cur.outputtypehandler = OutputTypeHandler +cur.outputtypehandler = output_type_handler print("WITH OUTPUT TYPE HANDLER:") for row in cur.execute("select * from TestBuildings order by BuildingId"): print(row) print() - diff --git a/python/UniversalRowids.py b/python/universal_rowids.py similarity index 83% rename from python/UniversalRowids.py rename to python/universal_rowids.py index e82ad437..f8c5d0e3 100644 --- a/python/UniversalRowids.py +++ b/python/universal_rowids.py @@ -1,5 +1,5 @@ #------------------------------------------------------------------------------ -# Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. # # Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved. # @@ -8,16 +8,17 @@ #------------------------------------------------------------------------------ #------------------------------------------------------------------------------ -# UniversalRowids.py +# universal_rowids.py # This script demonstrates the use of universal rowids. Universal rowids are # used to identify rows in index organized tables. # # This script requires cx_Oracle 6.0 and higher. #------------------------------------------------------------------------------ -import cx_Oracle import datetime -import SampleEnv + +import cx_Oracle as oracledb +import sample_env DATA = [ (1, "String #1", datetime.datetime(2017, 4, 4)), @@ -26,7 +27,7 @@ ] # truncate table so sample can be rerun -connection = cx_Oracle.connect(SampleEnv.GetMainConnectString()) +connection = oracledb.connect(sample_env.get_main_connect_string()) cursor = connection.cursor() print("Truncating table...") cursor.execute("truncate table TestUniversalRowids") @@ -50,8 +51,7 @@ from TestUniversalRowids where rowid = :rid""", rid = rowid) - intCol, stringCol, dateCol = cursor.fetchone() - print("IntCol:", intCol) - print("StringCol:", stringCol) + int_col, string_col, dateCol = cursor.fetchone() + print("IntCol:", int_col) + print("StringCol:", string_col) print("DateCol:", dateCol) -