From 70f079afaaca77f89c90c07f7a85ce030a07adbf Mon Sep 17 00:00:00 2001 From: Abdirahim Musse <33973272+abmusse@users.noreply.github.com> Date: Mon, 29 Apr 2019 13:46:43 -0500 Subject: [PATCH 1/6] [odbcTransport.js] Add odbc transport --- lib/transports/odbcTransport.js | 92 +++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 lib/transports/odbcTransport.js diff --git a/lib/transports/odbcTransport.js b/lib/transports/odbcTransport.js new file mode 100644 index 00000000..99684042 --- /dev/null +++ b/lib/transports/odbcTransport.js @@ -0,0 +1,92 @@ +// Copyright (c) International Business Machines Corp. 2019 +// All Rights Reserved + +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +// associated documentation files (the "Software"), to deal in the Software without restriction, +// including without limitation the rights to use, copy, modify, merge, publish, distribute, +// sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT +// NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +function odbcCall(config, xmlInput, done) { + // eslint-disable-next-line global-require + const { Connection } = require('odbc'); + + const { + host = 'localhost', + username = null, + password = null, + ipc = '*NA', + ctl = '*here', + xslib = 'QXMLSERV', + verbose = false, + dsn = null, + } = config; + + const sql = `call ${xslib}.iPLUGR512K(?,?,?)`; + const driver = 'IBM i Access ODBC Driver'; + let connectionString; + + if (dsn && typeof dsn === 'string') { + connectionString = `DSN=${dsn}`; + } else { + connectionString = `DRIVER=${driver};SYSTEM=${host};`; + + if (username && typeof username === 'string') { + connectionString += `UID=${username};`; + } + if (password && typeof password === 'string') { + connectionString += `PWD=${password};`; + } + } + + if (verbose) { + console.log(`SQL to run is ${sql}`); + } + + let connection; + + // potentially throws an error with invalid SYSTEM, UID, PWD + try { + connection = new Connection(connectionString); + } catch (error) { + done(error, null); + } + + connection.query(sql, [ipc, ctl, xmlInput], (queryError, results) => { + if (queryError) { + done(queryError, null); + return; + } + + connection.close((closeError) => { + if (closeError) { + done(closeError, null); + return; + } + + if (!results) { + done('Empty result set was returned', null); + return; + } + + let xmlOutput = ''; + + results.forEach((chunk) => { + xmlOutput += chunk.OUT151; + }); + + done(null, xmlOutput); + }); + }); +} + +exports.odbcCall = odbcCall; From 61dc37171d6522622e06da5de258f48863ca5223 Mon Sep 17 00:00:00 2001 From: Abdirahim Musse <33973272+abmusse@users.noreply.github.com> Date: Mon, 29 Apr 2019 13:47:10 -0500 Subject: [PATCH 2/6] [Connection.js] Add odbc transport --- lib/Connection.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/Connection.js b/lib/Connection.js index 27f25996..34f2a15f 100644 --- a/lib/Connection.js +++ b/lib/Connection.js @@ -23,11 +23,13 @@ const { const { iRestHttp } = require('./transports/irest'); const { db2Call } = require('./transports/istoredp'); const { sshCall } = require('./transports/sshTransport'); +const { odbcCall } = require('./transports/odbcTransport'); const availableTransports = { idb: db2Call, rest: iRestHttp, ssh: sshCall, + odbc: odbcCall, }; class Connection { From 8fe4deb032d7425e041c971ed2e0b516b93fdd7f Mon Sep 17 00:00:00 2001 From: Abdirahim Musse <33973272+abmusse@users.noreply.github.com> Date: Mon, 29 Apr 2019 15:35:03 -0500 Subject: [PATCH 3/6] [package.json] Add odbc beta dependency --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index fdc3bb12..0405ea44 100644 --- a/package.json +++ b/package.json @@ -50,6 +50,7 @@ "optionalDependencies": { "idb-connector": "^1.1.8", "idb-pconnector": "^1.0.2", - "ssh2": "0.8.2" + "ssh2": "0.8.2", + "odbc": "^2.0.0-beta.1" } } From e73a55dd51189817e685a941502a15c0e7f43294 Mon Sep 17 00:00:00 2001 From: Abdirahim Musse <33973272+abmusse@users.noreply.github.com> Date: Mon, 29 Apr 2019 15:35:59 -0500 Subject: [PATCH 4/6] [utils.js] Add odbc to available transports --- lib/utils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/utils.js b/lib/utils.js index 0e244969..d65fcae6 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -221,7 +221,7 @@ const xmlToJson = (xml) => { function returnTransports(transportOptions) { // eslint-disable-next-line global-require const { Connection } = require('./Connection'); - const availableTransports = ['idb', 'rest', 'ssh']; + const availableTransports = ['idb', 'rest', 'ssh', 'odbc']; const transports = []; const options = { From 428d68b2799916f1be88eac98ee0fcaf2a49329f Mon Sep 17 00:00:00 2001 From: Abdirahim Musse <33973272+abmusse@users.noreply.github.com> Date: Wed, 15 May 2019 15:46:20 -0500 Subject: [PATCH 5/6] [tests] Add config for DSN --- test/functional/CommandCallFunctional.js | 1 + test/functional/ProgramCallFunctional.js | 1 + test/functional/SqlCallFunctional.js | 1 + test/functional/ToolkitFunctional.js | 1 + 4 files changed, 4 insertions(+) diff --git a/test/functional/CommandCallFunctional.js b/test/functional/CommandCallFunctional.js index 25cf221c..58710fe1 100644 --- a/test/functional/CommandCallFunctional.js +++ b/test/functional/CommandCallFunctional.js @@ -38,6 +38,7 @@ const opt = { privateKey, passphrase: process.env.TKPHRASE, verbose: !!process.env.TKVERBOSE, + dsn: process.env.TKDSN, }; const transports = returnTransports(opt); diff --git a/test/functional/ProgramCallFunctional.js b/test/functional/ProgramCallFunctional.js index 6242c14e..88e2d9ab 100644 --- a/test/functional/ProgramCallFunctional.js +++ b/test/functional/ProgramCallFunctional.js @@ -39,6 +39,7 @@ const opt = { privateKey, passphrase: process.env.TKPHRASE, verbose: !!process.env.TKVERBOSE, + dsn: process.env.TKDSN, }; const transports = returnTransports(opt); diff --git a/test/functional/SqlCallFunctional.js b/test/functional/SqlCallFunctional.js index 703024dc..daea7d55 100644 --- a/test/functional/SqlCallFunctional.js +++ b/test/functional/SqlCallFunctional.js @@ -39,6 +39,7 @@ const opt = { privateKey, passphrase: process.env.TKPHRASE, verbose: !!process.env.TKVERBOSE, + dsn: process.env.TKDSN, }; const transports = returnTransports(opt); diff --git a/test/functional/ToolkitFunctional.js b/test/functional/ToolkitFunctional.js index fd865b1e..0fee55d6 100644 --- a/test/functional/ToolkitFunctional.js +++ b/test/functional/ToolkitFunctional.js @@ -39,6 +39,7 @@ const opt = { privateKey, passphrase: process.env.TKPHRASE, verbose: !!process.env.TKVERBOSE, + dsn: process.env.TKDSN, }; const lib = 'NODETKTEST'; From a0c1900acbf941453759645a6d5367cec3f1923a Mon Sep 17 00:00:00 2001 From: Abdirahim Musse <33973272+abmusse@users.noreply.github.com> Date: Fri, 17 May 2019 14:53:01 -0500 Subject: [PATCH 6/6] [README.md] Add doc for odbc transport --- README.md | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 3d8df639..58d3c986 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,7 @@ - [idb-connector](#idb-connector) - [REST](#rest) - [SSH](#ssh) + - [ODBC](#odbc) - [ProgramCall](#programcall) - [Example](#example) - [CommandCall](#commandcall) @@ -39,7 +40,7 @@ Before installing, download and install Node.js The Connection class is used to transport xml input and return xml output. #### Transports -Supported transports include [idb-connector](https://github.com/IBM/nodejs-idb-connector), REST, and SSH. +Supported transports include [idb-connector](https://github.com/IBM/nodejs-idb-connector), REST, SSH, and ODBC. ##### idb-connector The [idb-connector](https://github.com/IBM/nodejs-idb-connector) transport establishes a database connection and calls XMLSERVICE stored procedure. @@ -126,6 +127,59 @@ const connection = new Connection({ }); ``` +##### ODBC +The [ODBC](https://github.com/wankdanker/node-odbc/tree/v2.0) transport establishes a database connection and calls XMLSERVICE stored procedure. + +Before using the ODBC transport ensure all dependencies are installed. + +Ensure the IBM i Access ODBC driver is installed where you will be running Node.js. + +`TODO document installation` + +On the client side ensure `unixODBC` and `unixODBC-devel` are both installed. + +On IBM i this can be done with: + +`yum install unixODBC unixODBC-devel` + +Refer to [node-odbc](https://github.com/wankdanker/node-odbc/tree/v2.0#installation) for how this is done your OS. + +Also on the client side ensure the `IBM i Access ODBC Driver` is installed. + +`TODO document installation` + +To use the `ODBC` transport create an instance of Connection with: + +```javascript +const connection = new Connection({ + transport: 'odbc', + transportOptions: { host: 'myhost', username: 'myuser', password: 'mypassword'} +}); +``` + +Alternatively you can specify a [DSN](https://support.microsoft.com/en-us/help/966849/what-is-a-dsn-data-source-name) to use. + +Create an `.odbc.ini` file within your home directory and add additional configuration options. + +Refer to the [knowledge center](https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_73/rzaik/connectkeywords.htm) for a list of valid options. + +A simple .odbc.ini file: + +``` +[*LOCAL] +Driver=IBM i Access ODBC Driver +UserID=myuser +Password=mypass +System=localhost +``` +To use the `ODBC` transport with a DSN create an instance of Connection with: + +```javascript +const connection = new Connection({ + transport: 'odbc', + transportOptions: { dsn: '*LOCAL'} +}); +``` ### ProgramCall The ProgramCall class is used to call IBM i programs and service programs.