From c9e305760d622071e1aaa6d8069cab25366d3b9b Mon Sep 17 00:00:00 2001 From: maximelkin Date: Tue, 15 Oct 2019 09:23:07 +0300 Subject: [PATCH] Fix oracledb driver v4 support (#3480) --- .travis.yml | 2 +- lib/dialects/oracledb/index.js | 85 ++++++++++++++++++++++++---------- test/unit/dialects/oracledb.js | 9 ++++ 3 files changed, 71 insertions(+), 25 deletions(-) diff --git a/.travis.yml b/.travis.yml index b030361f18..37f98acdc3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,7 +16,7 @@ matrix: env: TESTSCRIPT=test:everything DB="oracledb mssql mysql mysql2 postgres sqlite3" KNEX_TEST_TIMEOUT=60000 install: - npm i - - (echo $DB | grep oracledb) && npm install oracledb@3.1.2 || true + - (echo $DB | grep oracledb) && npm install oracledb || true before_script: - npm run db:start diff --git a/lib/dialects/oracledb/index.js b/lib/dialects/oracledb/index.js index aed6ded57d..1689f48cdb 100644 --- a/lib/dialects/oracledb/index.js +++ b/lib/dialects/oracledb/index.js @@ -131,7 +131,11 @@ Client_Oracledb.prototype.acquireRawConnection = function() { }; const fetchAsync = promisify(function(sql, bindParams, options, cb) { options = options || {}; - options.outFormat = client.driver.OBJECT; + options.outFormat = + client.driver.OUT_FORMAT_OBJECT || client.driver.OBJECT; + if (!options.outFormat) { + throw new Error('not found oracledb.outFormat constants'); + } if (options.resultSet) { connection.execute(sql, bindParams || [], options, function( err, @@ -202,7 +206,10 @@ Client_Oracledb.prototype.acquireRawConnection = function() { try { for (const lob of lobs) { - results.rows[lob.index][lob.key] = await readStream(lob.stream); + // todo should be fetchAsString/fetchAsBuffer polyfill only + results.rows[lob.index][lob.key] = await lobProcessing( + lob.stream + ); } } catch (e) { await closeResultSet().catch(() => {}); @@ -328,30 +335,29 @@ Client_Oracledb.prototype._query = function(connection, obj) { }); }; -// Handle clob -const readStream = promisify((stream, cb) => { - const oracledb = require('oracledb'); - let data = ''; +/** + * @param stream + * @param {'string' | 'buffer'} type + */ +function readStream(stream, type) { + return new Promise((resolve, reject) => { + let data = ''; - if (stream.iLob.type === oracledb.CLOB) { - stream.setEncoding('utf-8'); - } else { - data = Buffer.alloc(0); - } - stream.on('error', function(err) { - cb(err); - }); - stream.on('data', function(chunk) { - if (stream.iLob.type === oracledb.CLOB) { - data += chunk; - } else { - data = Buffer.concat([data, chunk]); - } - }); - stream.on('end', function() { - cb(null, data); + stream.on('error', function(err) { + reject(err); + }); + stream.on('data', function(chunk) { + if (type === 'string') { + data += chunk; + } else { + data = Buffer.concat([data, chunk]); + } + }); + stream.on('end', function() { + resolve(data); + }); }); -}); +} // Process the response as returned from the query. Client_Oracledb.prototype.processResponse = function(obj, runner) { @@ -387,6 +393,37 @@ Client_Oracledb.prototype.processResponse = function(obj, runner) { } }; +const lobProcessing = function(stream) { + const oracledb = require('oracledb'); + + /** + * @type 'string' | 'buffer' + */ + let type; + + if (stream.type) { + // v1.2-v4 + if (stream.type === oracledb.BLOB) { + type = 'buffer'; + } else if (stream.type === oracledb.CLOB) { + type = 'string'; + } + } else if (stream.iLob) { + // v1 + if (stream.iLob.type === oracledb.CLOB) { + type = 'string'; + } else if (stream.iLob.type === oracledb.BLOB) { + type = 'buffer'; + } + } else { + throw new Error('Unrecognized oracledb lob stream type'); + } + if (type === 'string') { + stream.setEncoding('utf-8'); + } + return readStream(stream, type); +}; + class Oracledb_Formatter extends Oracle_Formatter { // Checks whether a value is a function... if it is, we compile it // otherwise we check whether it's a raw diff --git a/test/unit/dialects/oracledb.js b/test/unit/dialects/oracledb.js index 3819a24ca9..48aaf427b2 100644 --- a/test/unit/dialects/oracledb.js +++ b/test/unit/dialects/oracledb.js @@ -71,6 +71,15 @@ describe('OracleDb parameters', function() { }); }); + it('on clob', function() { + return knexClient + .raw('select TO_CLOB(\'LONG CONTENT\') as "field" from dual') + .then(function(result) { + expect(result[0]).to.be.ok; + expect(result[0].field).to.be.equal('LONG CONTENT'); + }); + }); + after(function() { return knexClient.destroy(); });