From 5e68ce321899997ff204ebb4ee62754edbb0ef9f Mon Sep 17 00:00:00 2001 From: Jan Prochazka Date: Wed, 31 Jul 2024 11:20:31 +0200 Subject: [PATCH] oracle thick mode support #843 --- app/package.json | 1 + app/yarn.lock | 5 +++ fillNativeModules.js | 5 ++- packages/api/package.json | 1 + .../settings/ConnectionDriverFields.svelte | 8 ++++ plugins/dbgate-plugin-oracle/package.json | 3 -- .../src/backend/{drivers.js => driver.js} | 43 ++++++++++++++----- .../dbgate-plugin-oracle/src/backend/index.js | 7 ++- .../src/frontend/{drivers.js => driver.js} | 29 ++++++------- .../src/frontend/index.js | 4 +- yarn.lock | 8 ++-- 11 files changed, 75 insertions(+), 39 deletions(-) rename plugins/dbgate-plugin-oracle/src/backend/{drivers.js => driver.js} (90%) rename plugins/dbgate-plugin-oracle/src/frontend/{drivers.js => driver.js} (94%) diff --git a/app/package.json b/app/package.json index f79b1fe7..f090c6ae 100644 --- a/app/package.json +++ b/app/package.json @@ -8,6 +8,7 @@ "electron-log": "^4.4.1", "electron-updater": "^4.6.1", "lodash.clonedeepwith": "^4.5.0", + "oracledb": "^6.6.0", "patch-package": "^6.4.7" }, "repository": { diff --git a/app/yarn.lock b/app/yarn.lock index 63e86571..acc10fc8 100644 --- a/app/yarn.lock +++ b/app/yarn.lock @@ -1944,6 +1944,11 @@ open@^7.4.2: is-docker "^2.0.0" is-wsl "^2.1.1" +oracledb@^6.6.0: + version "6.6.0" + resolved "https://registry.yarnpkg.com/oracledb/-/oracledb-6.6.0.tgz#bb40adbe81a84a1e544c48af9f120c61f030e936" + integrity sha512-T3dx+o3j+tVN53wQyr4yGTmoPHLy+a2V8yb1T2PmWrsj3ZlSt2Yu1BgV2yTDqnmBZYpRi/I3yJXRCOHHD7PiyA== + os-tmpdir@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" diff --git a/fillNativeModules.js b/fillNativeModules.js index 07d7c1cf..23024893 100644 --- a/fillNativeModules.js +++ b/fillNativeModules.js @@ -3,9 +3,10 @@ const fs = require('fs'); let fillContent = ''; if (process.platform == 'win32') { - fillContent += `content.msnodesqlv8 = () => require('msnodesqlv8');`; + fillContent += `content.msnodesqlv8 = () => require('msnodesqlv8');\n`; } -fillContent += `content['better-sqlite3'] = () => require('better-sqlite3');`; +fillContent += `content['better-sqlite3'] = () => require('better-sqlite3');\n`; +fillContent += `content['oracledb'] = () => require('oracledb');\n`; const getContent = empty => ` // this file is generated automatically by script fillNativeModules.js, do not edit it manually diff --git a/packages/api/package.json b/packages/api/package.json index b4c9ed04..39c1e310 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -52,6 +52,7 @@ "ncp": "^2.0.0", "node-cron": "^2.0.3", "on-finished": "^2.4.1", + "oracledb": "^6.6.0", "pinomin": "^1.0.4", "portfinder": "^1.0.28", "rimraf": "^3.0.0", diff --git a/packages/web/src/settings/ConnectionDriverFields.svelte b/packages/web/src/settings/ConnectionDriverFields.svelte index 0bfdc127..f2c410e0 100644 --- a/packages/web/src/settings/ConnectionDriverFields.svelte +++ b/packages/web/src/settings/ConnectionDriverFields.svelte @@ -93,6 +93,14 @@ /> {/if} +{#if driver?.showConnectionField('clientLibraryPath', $values)} + +{/if} + {#if driver?.showConnectionField('server', $values)}
diff --git a/plugins/dbgate-plugin-oracle/package.json b/plugins/dbgate-plugin-oracle/package.json index c53bdb57..85c837f3 100644 --- a/plugins/dbgate-plugin-oracle/package.json +++ b/plugins/dbgate-plugin-oracle/package.json @@ -36,8 +36,5 @@ "lodash": "^4.17.21", "webpack": "^5.91.0", "webpack-cli": "^5.1.4" - }, - "dependencies": { - "oracledb": "^6.5.1" } } diff --git a/plugins/dbgate-plugin-oracle/src/backend/drivers.js b/plugins/dbgate-plugin-oracle/src/backend/driver.js similarity index 90% rename from plugins/dbgate-plugin-oracle/src/backend/drivers.js rename to plugins/dbgate-plugin-oracle/src/backend/driver.js index 31a56657..5d8c73a9 100644 --- a/plugins/dbgate-plugin-oracle/src/backend/drivers.js +++ b/plugins/dbgate-plugin-oracle/src/backend/driver.js @@ -1,13 +1,22 @@ const _ = require('lodash'); const stream = require('stream'); -const driverBases = require('../frontend/drivers'); +const driverBase = require('../frontend/driver'); const Analyser = require('./Analyser'); -//--const pg = require('pg'); -const oracledb = require('oracledb'); const { createBulkInsertStreamBase, makeUniqueColumnNames } = require('dbgate-tools'); const createOracleBulkInsertStream = require('./createOracleBulkInsertStream'); +let requireOracledb; + +let oracledbValue; +function getOracledb() { + if (!oracledbValue) { + oracledbValue = requireOracledb(); + } + return oracledbValue; +} + + /* pg.types.setTypeParser(1082, 'text', val => val); // date pg.types.setTypeParser(1114, 'text', val => val); // timestamp without timezone @@ -33,8 +42,10 @@ function zipDataRow(rowArray, columns) { return obj; } +let oracleClientInitialized = false; + /** @type {import('dbgate-types').EngineDriver} */ -const drivers = driverBases.map(driverBase => ({ +const driver = { ...driverBase, analyserClass: Analyser, @@ -51,8 +62,14 @@ const drivers = driverBases.map(driverBase => ({ ssl, isReadOnly, authType, + clientLibraryPath, socketPath, }) { + const oracledb = getOracledb(); + if (authType == 'thick' && !oracleClientInitialized) { + oracledb.initOracleClient({ libDir: clientLibraryPath }); + oracleClientInitialized = true; + } client = await oracledb.getConnection({ user, password, @@ -312,15 +329,21 @@ const drivers = driverBases.map(driverBase => ({ getAuthTypes() { return [ { - title: 'Host and port', - name: 'hostPort', + title: 'Thin mode (default) - direct connection to Oracle database', + name: 'thin', }, { - title: 'Socket', - name: 'socket', + title: 'Thick mode - connection via Oracle instant client', + name: 'thick', }, ]; }, -})); +}; -module.exports = drivers; +driver.initialize = (dbgateEnv) => { + if (dbgateEnv.nativeModules && dbgateEnv.nativeModules['oracledb']) { + requireOracledb = dbgateEnv.nativeModules['oracledb']; + } +}; + +module.exports = driver; diff --git a/plugins/dbgate-plugin-oracle/src/backend/index.js b/plugins/dbgate-plugin-oracle/src/backend/index.js index de004729..5f45d5a3 100644 --- a/plugins/dbgate-plugin-oracle/src/backend/index.js +++ b/plugins/dbgate-plugin-oracle/src/backend/index.js @@ -1,6 +1,9 @@ -const drivers = require('./drivers'); +const driver = require('./driver'); module.exports = { packageName: 'dbgate-plugin-oracle', - drivers, + drivers: [driver], + initialize(dbgateEnv) { + driver.initialize(dbgateEnv); + }, }; diff --git a/plugins/dbgate-plugin-oracle/src/frontend/drivers.js b/plugins/dbgate-plugin-oracle/src/frontend/driver.js similarity index 94% rename from plugins/dbgate-plugin-oracle/src/frontend/drivers.js rename to plugins/dbgate-plugin-oracle/src/frontend/driver.js index 25b32793..53dcc8c3 100644 --- a/plugins/dbgate-plugin-oracle/src/frontend/drivers.js +++ b/plugins/dbgate-plugin-oracle/src/frontend/driver.js @@ -82,10 +82,15 @@ const dialect = { }, }; -const oracleDriverBase = { - ...driverBase, - dumperClass: Dumper, +/** @type {import('dbgate-types').EngineDriver} */ +const oracleDriver = { + engine: 'oracle@dbgate-plugin-oracle', + title: 'OracleDB', + defaultPort: 1521, + authTypeLabel: 'Driver mode', + defaultAuthTypeName: 'thin', dialect, + dumperClass: Dumper, // showConnectionField: (field, values) => // ['server', 'port', 'user', 'password', 'defaultDatabase', 'singleDatabase'].includes(field), getQuerySplitterOptions: () => oracleSplitterOptions, @@ -93,8 +98,12 @@ const oracleDriverBase = { databaseUrlPlaceholder: 'e.g. localhost:1521/orcl', + showConnectionField: (field, values) => { if (field == 'useDatabaseUrl') return true; + if (field == 'authType') return true; + if (field == 'clientLibraryPath') return values.authType == 'thick'; + if (values.useDatabaseUrl) { return ['databaseUrl', 'user', 'password'].includes(field); } @@ -126,18 +135,6 @@ $$ LANGUAGE plpgsql;`, }, ]; }, -}; - -/** @type {import('dbgate-types').EngineDriver} */ -const oracleDriver = { - ...oracleDriverBase, - engine: 'oracle@dbgate-plugin-oracle', - title: 'OracleDB', - defaultPort: 1521, - dialect: { - ...dialect, - materializedViews: true, - }, dialectByVersion(version) { if (version) { @@ -156,4 +153,4 @@ const oracleDriver = { showConnectionTab: field => field == 'sshTunnel', }; -module.exports = [oracleDriver]; +module.exports = oracleDriver; diff --git a/plugins/dbgate-plugin-oracle/src/frontend/index.js b/plugins/dbgate-plugin-oracle/src/frontend/index.js index ca201649..0659d3a5 100644 --- a/plugins/dbgate-plugin-oracle/src/frontend/index.js +++ b/plugins/dbgate-plugin-oracle/src/frontend/index.js @@ -1,6 +1,6 @@ -import drivers from './drivers'; +import driver from './driver'; export default { packageName: 'dbgate-plugin-oracle', - drivers, + drivers: [driver], }; diff --git a/yarn.lock b/yarn.lock index 7c89521b..817e109d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7978,10 +7978,10 @@ optionator@^0.8.1, optionator@^0.8.3: resolved "https://registry.yarnpkg.com/opts/-/opts-2.0.2.tgz#a17e189fbbfee171da559edd8a42423bc5993ce1" integrity sha512-k41FwbcLnlgnFh69f4qdUfvDQ+5vaSDnVPFI/y5XuhKRq97EnVVneO9F1ESVCdiVu4fCS2L8usX3mU331hB7pg== -oracledb@^6.5.1: - version "6.5.1" - resolved "https://registry.yarnpkg.com/oracledb/-/oracledb-6.5.1.tgz#814d985035acdb1a6470b1152af0ca3767569ede" - integrity sha512-JzoSGei1wnvmqgKnAZK1W650mzHTZXx+7hClV4mwsbY/ZjUtrpnojNJMYJ2jkOhj7XG5oJPfXc4GqDKaNzkxqg== +oracledb@^6.6.0: + version "6.6.0" + resolved "https://registry.yarnpkg.com/oracledb/-/oracledb-6.6.0.tgz#bb40adbe81a84a1e544c48af9f120c61f030e936" + integrity sha512-T3dx+o3j+tVN53wQyr4yGTmoPHLy+a2V8yb1T2PmWrsj3ZlSt2Yu1BgV2yTDqnmBZYpRi/I3yJXRCOHHD7PiyA== os-tmpdir@~1.0.2: version "1.0.2"