Initial commit
This commit is contained in:
381
node_modules/knex/lib/dialects/oracledb/index.js
generated
vendored
Executable file
381
node_modules/knex/lib/dialects/oracledb/index.js
generated
vendored
Executable file
@@ -0,0 +1,381 @@
|
||||
// Oracledb Client
|
||||
// -------
|
||||
const each = require('lodash/each');
|
||||
const flatten = require('lodash/flatten');
|
||||
const isEmpty = require('lodash/isEmpty');
|
||||
const map = require('lodash/map');
|
||||
|
||||
const Formatter = require('../../formatter');
|
||||
const QueryCompiler = require('./query/oracledb-querycompiler');
|
||||
const TableCompiler = require('./schema/oracledb-tablecompiler');
|
||||
const ColumnCompiler = require('./schema/oracledb-columncompiler');
|
||||
const {
|
||||
BlobHelper,
|
||||
ReturningHelper,
|
||||
monkeyPatchConnection,
|
||||
} = require('./utils');
|
||||
const ViewCompiler = require('./schema/oracledb-viewcompiler');
|
||||
const ViewBuilder = require('./schema/oracledb-viewbuilder');
|
||||
const Transaction = require('./transaction');
|
||||
const Client_Oracle = require('../oracle');
|
||||
const { isString } = require('../../util/is');
|
||||
const { outputQuery, unwrapRaw } = require('../../formatter/wrappingFormatter');
|
||||
const { compileCallback } = require('../../formatter/formatterUtils');
|
||||
|
||||
class Client_Oracledb extends Client_Oracle {
|
||||
constructor(config) {
|
||||
super(config);
|
||||
|
||||
if (this.version) {
|
||||
// Normalize version format; null bad format
|
||||
// to trigger fallback to auto-detect.
|
||||
this.version = parseVersion(this.version);
|
||||
}
|
||||
|
||||
if (this.driver) {
|
||||
process.env.UV_THREADPOOL_SIZE = process.env.UV_THREADPOOL_SIZE || 1;
|
||||
process.env.UV_THREADPOOL_SIZE =
|
||||
parseInt(process.env.UV_THREADPOOL_SIZE) + this.driver.poolMax;
|
||||
}
|
||||
}
|
||||
|
||||
_driver() {
|
||||
const client = this;
|
||||
const oracledb = require('oracledb');
|
||||
client.fetchAsString = [];
|
||||
if (this.config.fetchAsString && Array.isArray(this.config.fetchAsString)) {
|
||||
this.config.fetchAsString.forEach(function (type) {
|
||||
if (!isString(type)) return;
|
||||
type = type.toUpperCase();
|
||||
if (oracledb[type]) {
|
||||
if (
|
||||
type !== 'NUMBER' &&
|
||||
type !== 'DATE' &&
|
||||
type !== 'CLOB' &&
|
||||
type !== 'BUFFER'
|
||||
) {
|
||||
this.logger.warn(
|
||||
'Only "date", "number", "clob" and "buffer" are supported for fetchAsString'
|
||||
);
|
||||
}
|
||||
client.fetchAsString.push(oracledb[type]);
|
||||
}
|
||||
});
|
||||
}
|
||||
return oracledb;
|
||||
}
|
||||
|
||||
queryCompiler(builder, formatter) {
|
||||
return new QueryCompiler(this, builder, formatter);
|
||||
}
|
||||
|
||||
tableCompiler() {
|
||||
return new TableCompiler(this, ...arguments);
|
||||
}
|
||||
|
||||
columnCompiler() {
|
||||
return new ColumnCompiler(this, ...arguments);
|
||||
}
|
||||
|
||||
viewBuilder() {
|
||||
return new ViewBuilder(this, ...arguments);
|
||||
}
|
||||
|
||||
viewCompiler() {
|
||||
return new ViewCompiler(this, ...arguments);
|
||||
}
|
||||
|
||||
formatter(builder) {
|
||||
return new Formatter(this, builder);
|
||||
}
|
||||
|
||||
transaction() {
|
||||
return new Transaction(this, ...arguments);
|
||||
}
|
||||
|
||||
prepBindings(bindings) {
|
||||
return map(bindings, (value) => {
|
||||
if (value instanceof BlobHelper && this.driver) {
|
||||
return { type: this.driver.BLOB, dir: this.driver.BIND_OUT };
|
||||
// Returning helper always use ROWID as string
|
||||
} else if (value instanceof ReturningHelper && this.driver) {
|
||||
return { type: this.driver.STRING, dir: this.driver.BIND_OUT };
|
||||
} else if (typeof value === 'boolean') {
|
||||
return value ? 1 : 0;
|
||||
}
|
||||
return value;
|
||||
});
|
||||
}
|
||||
|
||||
// Checks whether a value is a function... if it is, we compile it
|
||||
// otherwise we check whether it's a raw
|
||||
parameter(value, builder, formatter) {
|
||||
if (typeof value === 'function') {
|
||||
return outputQuery(
|
||||
compileCallback(value, undefined, this, formatter),
|
||||
true,
|
||||
builder,
|
||||
this
|
||||
);
|
||||
} else if (value instanceof BlobHelper) {
|
||||
formatter.bindings.push(value.value);
|
||||
return '?';
|
||||
}
|
||||
return unwrapRaw(value, true, builder, this, formatter) || '?';
|
||||
}
|
||||
|
||||
// Get a raw connection, called by the `pool` whenever a new
|
||||
// connection needs to be added to the pool.
|
||||
acquireRawConnection() {
|
||||
return new Promise((resolver, rejecter) => {
|
||||
// If external authentication don't have to worry about username/password and
|
||||
// if not need to set the username and password
|
||||
const oracleDbConfig = this.connectionSettings.externalAuth
|
||||
? { externalAuth: this.connectionSettings.externalAuth }
|
||||
: {
|
||||
user: this.connectionSettings.user,
|
||||
password: this.connectionSettings.password,
|
||||
};
|
||||
|
||||
// In the case of external authentication connection string will be given
|
||||
oracleDbConfig.connectString = resolveConnectString(
|
||||
this.connectionSettings
|
||||
);
|
||||
|
||||
if (this.connectionSettings.prefetchRowCount) {
|
||||
oracleDbConfig.prefetchRows = this.connectionSettings.prefetchRowCount;
|
||||
}
|
||||
|
||||
if (this.connectionSettings.stmtCacheSize !== undefined) {
|
||||
oracleDbConfig.stmtCacheSize = this.connectionSettings.stmtCacheSize;
|
||||
}
|
||||
|
||||
this.driver.fetchAsString = this.fetchAsString;
|
||||
|
||||
this.driver.getConnection(oracleDbConfig, (err, connection) => {
|
||||
if (err) {
|
||||
return rejecter(err);
|
||||
}
|
||||
monkeyPatchConnection(connection, this);
|
||||
|
||||
resolver(connection);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Used to explicitly close a connection, called internally by the pool
|
||||
// when a connection times out or the pool is shutdown.
|
||||
destroyRawConnection(connection) {
|
||||
return connection.release();
|
||||
}
|
||||
|
||||
// Handle oracle version resolution on acquiring connection from pool instead of connection creation.
|
||||
// Must do this here since only the client used to create a connection would be updated with version
|
||||
// information on creation. Poses a problem when knex instance is cloned since instances share the
|
||||
// connection pool while having their own client instances.
|
||||
async acquireConnection() {
|
||||
const connection = await super.acquireConnection();
|
||||
this.checkVersion(connection);
|
||||
return connection;
|
||||
}
|
||||
|
||||
// In Oracle, we need to check the version to dynamically determine
|
||||
// certain limits. If user did not specify a version, get it from the connection.
|
||||
checkVersion(connection) {
|
||||
// Already determined version before?
|
||||
if (this.version) {
|
||||
return this.version;
|
||||
}
|
||||
|
||||
const detectedVersion = parseVersion(connection.oracleServerVersionString);
|
||||
if (!detectedVersion) {
|
||||
// When original version is set to null, user-provided version was invalid and we fell-back to auto-detect.
|
||||
// Otherwise, we couldn't auto-detect at all. Set error message accordingly.
|
||||
throw new Error(
|
||||
this.version === null
|
||||
? 'Invalid Oracledb version number format passed to knex. Unable to successfully auto-detect as fallback. Please specify a valid oracledb version.'
|
||||
: 'Unable to detect Oracledb version number automatically. Please specify the version in knex configuration.'
|
||||
);
|
||||
}
|
||||
|
||||
this.version = detectedVersion;
|
||||
return detectedVersion;
|
||||
}
|
||||
|
||||
// Runs the query on the specified connection, providing the bindings
|
||||
// and any other necessary prep work.
|
||||
_query(connection, obj) {
|
||||
if (!obj.sql) throw new Error('The query is empty');
|
||||
|
||||
const options = Object.assign({}, obj.options, { autoCommit: false });
|
||||
if (obj.method === 'select') {
|
||||
options.resultSet = true;
|
||||
}
|
||||
return connection
|
||||
.executeAsync(obj.sql, obj.bindings, options)
|
||||
.then(async function (response) {
|
||||
// Flatten outBinds
|
||||
let outBinds = flatten(response.outBinds);
|
||||
obj.response = response.rows || [];
|
||||
obj.rowsAffected = response.rows
|
||||
? response.rows.rowsAffected
|
||||
: response.rowsAffected;
|
||||
|
||||
//added for outBind parameter
|
||||
if (obj.method === 'raw' && outBinds.length > 0) {
|
||||
return {
|
||||
response: outBinds,
|
||||
};
|
||||
}
|
||||
|
||||
if (obj.method === 'update') {
|
||||
const modifiedRowsCount = obj.rowsAffected.length || obj.rowsAffected;
|
||||
const updatedObjOutBinding = [];
|
||||
const updatedOutBinds = [];
|
||||
const updateOutBinds = (i) =>
|
||||
function (value, index) {
|
||||
const OutBindsOffset = index * modifiedRowsCount;
|
||||
updatedOutBinds.push(outBinds[i + OutBindsOffset]);
|
||||
};
|
||||
|
||||
for (let i = 0; i < modifiedRowsCount; i++) {
|
||||
updatedObjOutBinding.push(obj.outBinding[0]);
|
||||
each(obj.outBinding[0], updateOutBinds(i));
|
||||
}
|
||||
outBinds = updatedOutBinds;
|
||||
obj.outBinding = updatedObjOutBinding;
|
||||
}
|
||||
|
||||
if (!obj.returning && outBinds.length === 0) {
|
||||
if (!connection.isTransaction) {
|
||||
await connection.commitAsync();
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
const rowIds = [];
|
||||
let offset = 0;
|
||||
|
||||
for (let line = 0; line < obj.outBinding.length; line++) {
|
||||
const ret = obj.outBinding[line];
|
||||
|
||||
offset =
|
||||
offset +
|
||||
(obj.outBinding[line - 1] ? obj.outBinding[line - 1].length : 0);
|
||||
|
||||
for (let index = 0; index < ret.length; index++) {
|
||||
const out = ret[index];
|
||||
|
||||
await new Promise(function (bindResolver, bindRejecter) {
|
||||
if (out instanceof BlobHelper) {
|
||||
const blob = outBinds[index + offset];
|
||||
if (out.returning) {
|
||||
obj.response[line] = obj.response[line] || {};
|
||||
obj.response[line][out.columnName] = out.value;
|
||||
}
|
||||
blob.on('error', function (err) {
|
||||
bindRejecter(err);
|
||||
});
|
||||
blob.on('finish', function () {
|
||||
bindResolver();
|
||||
});
|
||||
blob.write(out.value);
|
||||
blob.end();
|
||||
} else if (obj.outBinding[line][index] === 'ROWID') {
|
||||
rowIds.push(outBinds[index + offset]);
|
||||
bindResolver();
|
||||
} else {
|
||||
obj.response[line] = obj.response[line] || {};
|
||||
obj.response[line][out] = outBinds[index + offset];
|
||||
bindResolver();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
if (obj.returningSql) {
|
||||
const response = await connection.executeAsync(
|
||||
obj.returningSql(),
|
||||
rowIds,
|
||||
{ resultSet: true }
|
||||
);
|
||||
obj.response = response.rows;
|
||||
}
|
||||
if (connection.isTransaction) {
|
||||
return obj;
|
||||
}
|
||||
await connection.commitAsync();
|
||||
return obj;
|
||||
});
|
||||
}
|
||||
|
||||
// Process the response as returned from the query.
|
||||
processResponse(obj, runner) {
|
||||
const { response } = obj;
|
||||
if (obj.output) {
|
||||
return obj.output.call(runner, response);
|
||||
}
|
||||
switch (obj.method) {
|
||||
case 'select':
|
||||
return response;
|
||||
case 'first':
|
||||
return response[0];
|
||||
case 'pluck':
|
||||
return map(response, obj.pluck);
|
||||
case 'insert':
|
||||
case 'del':
|
||||
case 'update':
|
||||
case 'counter':
|
||||
if ((obj.returning && !isEmpty(obj.returning)) || obj.returningSql) {
|
||||
return response;
|
||||
} else if (obj.rowsAffected !== undefined) {
|
||||
return obj.rowsAffected;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
default:
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
||||
processPassedConnection(connection) {
|
||||
this.checkVersion(connection);
|
||||
monkeyPatchConnection(connection, this);
|
||||
}
|
||||
}
|
||||
|
||||
Client_Oracledb.prototype.driverName = 'oracledb';
|
||||
|
||||
function parseVersion(versionString) {
|
||||
try {
|
||||
// We only care about first two version components at most
|
||||
const versionParts = versionString.split('.').slice(0, 2);
|
||||
// Strip off any character suffixes in version number (ex. 12c => 12, 12.2c => 12.2)
|
||||
versionParts.forEach((versionPart, idx) => {
|
||||
versionParts[idx] = versionPart.replace(/\D$/, '');
|
||||
});
|
||||
const version = versionParts.join('.');
|
||||
return version.match(/^\d+\.?\d*$/) ? version : null;
|
||||
} catch (err) {
|
||||
// Non-string versionString passed in.
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function resolveConnectString(connectionSettings) {
|
||||
if (connectionSettings.connectString) {
|
||||
return connectionSettings.connectString;
|
||||
}
|
||||
|
||||
if (!connectionSettings.port) {
|
||||
return connectionSettings.host + '/' + connectionSettings.database;
|
||||
}
|
||||
|
||||
return (
|
||||
connectionSettings.host +
|
||||
':' +
|
||||
connectionSettings.port +
|
||||
'/' +
|
||||
connectionSettings.database
|
||||
);
|
||||
}
|
||||
|
||||
module.exports = Client_Oracledb;
|
||||
481
node_modules/knex/lib/dialects/oracledb/query/oracledb-querycompiler.js
generated
vendored
Executable file
481
node_modules/knex/lib/dialects/oracledb/query/oracledb-querycompiler.js
generated
vendored
Executable file
@@ -0,0 +1,481 @@
|
||||
const clone = require('lodash/clone');
|
||||
const each = require('lodash/each');
|
||||
const isEmpty = require('lodash/isEmpty');
|
||||
const isPlainObject = require('lodash/isPlainObject');
|
||||
const Oracle_Compiler = require('../../oracle/query/oracle-querycompiler');
|
||||
const ReturningHelper = require('../utils').ReturningHelper;
|
||||
const BlobHelper = require('../utils').BlobHelper;
|
||||
const { isString } = require('../../../util/is');
|
||||
const {
|
||||
columnize: columnize_,
|
||||
} = require('../../../formatter/wrappingFormatter');
|
||||
|
||||
class Oracledb_Compiler extends Oracle_Compiler {
|
||||
// Compiles an "insert" query, allowing for multiple
|
||||
// inserts using a single query statement.
|
||||
insert() {
|
||||
const self = this;
|
||||
const outBindPrep = this._prepOutbindings(
|
||||
this.single.insert,
|
||||
this.single.returning
|
||||
);
|
||||
const outBinding = outBindPrep.outBinding;
|
||||
const returning = outBindPrep.returning;
|
||||
const insertValues = outBindPrep.values;
|
||||
|
||||
if (
|
||||
Array.isArray(insertValues) &&
|
||||
insertValues.length === 1 &&
|
||||
isEmpty(insertValues[0])
|
||||
) {
|
||||
const returningFragment = this.single.returning
|
||||
? ' (' + this.formatter.wrap(this.single.returning) + ')'
|
||||
: '';
|
||||
|
||||
return this._addReturningToSqlAndConvert(
|
||||
'insert into ' +
|
||||
this.tableName +
|
||||
returningFragment +
|
||||
' values (default)',
|
||||
outBinding[0],
|
||||
this.tableName,
|
||||
returning
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
isEmpty(this.single.insert) &&
|
||||
typeof this.single.insert !== 'function'
|
||||
) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const insertData = this._prepInsert(insertValues);
|
||||
|
||||
const sql = {};
|
||||
|
||||
if (isString(insertData)) {
|
||||
return this._addReturningToSqlAndConvert(
|
||||
'insert into ' + this.tableName + ' ' + insertData,
|
||||
outBinding[0],
|
||||
this.tableName,
|
||||
returning
|
||||
);
|
||||
}
|
||||
|
||||
if (insertData.values.length === 1) {
|
||||
return this._addReturningToSqlAndConvert(
|
||||
'insert into ' +
|
||||
this.tableName +
|
||||
' (' +
|
||||
this.formatter.columnize(insertData.columns) +
|
||||
') values (' +
|
||||
this.client.parameterize(
|
||||
insertData.values[0],
|
||||
undefined,
|
||||
this.builder,
|
||||
this.bindingsHolder
|
||||
) +
|
||||
')',
|
||||
outBinding[0],
|
||||
this.tableName,
|
||||
returning
|
||||
);
|
||||
}
|
||||
|
||||
const insertDefaultsOnly = insertData.columns.length === 0;
|
||||
sql.returning = returning;
|
||||
sql.sql =
|
||||
'begin ' +
|
||||
insertData.values
|
||||
.map(function (value, index) {
|
||||
const parameterizedValues = !insertDefaultsOnly
|
||||
? self.client.parameterize(
|
||||
value,
|
||||
self.client.valueForUndefined,
|
||||
self.builder,
|
||||
self.bindingsHolder
|
||||
)
|
||||
: '';
|
||||
let subSql = 'insert into ' + self.tableName;
|
||||
|
||||
if (insertDefaultsOnly) {
|
||||
// No columns given so only the default value
|
||||
subSql +=
|
||||
' (' +
|
||||
self.formatter.wrap(self.single.returning) +
|
||||
') values (default)';
|
||||
} else {
|
||||
subSql +=
|
||||
' (' +
|
||||
self.formatter.columnize(insertData.columns) +
|
||||
') values (' +
|
||||
parameterizedValues +
|
||||
')';
|
||||
}
|
||||
|
||||
let returningClause = '';
|
||||
let intoClause = '';
|
||||
// ToDo review if this code is still needed or could be dropped
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
let usingClause = '';
|
||||
let outClause = '';
|
||||
|
||||
each(value, function (val) {
|
||||
if (!(val instanceof BlobHelper)) {
|
||||
usingClause += ' ?,';
|
||||
}
|
||||
});
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
usingClause = usingClause.slice(0, -1);
|
||||
|
||||
// Build returning and into clauses
|
||||
outBinding[index].forEach(function (ret) {
|
||||
const columnName = ret.columnName || ret;
|
||||
returningClause += self.formatter.wrap(columnName) + ',';
|
||||
intoClause += ' ?,';
|
||||
outClause += ' out ?,';
|
||||
|
||||
// Add Helpers to bindings
|
||||
if (ret instanceof BlobHelper) {
|
||||
return self.formatter.bindings.push(ret);
|
||||
}
|
||||
self.formatter.bindings.push(new ReturningHelper(columnName));
|
||||
});
|
||||
|
||||
// Strip last comma
|
||||
returningClause = returningClause.slice(0, -1);
|
||||
intoClause = intoClause.slice(0, -1);
|
||||
outClause = outClause.slice(0, -1);
|
||||
|
||||
if (returningClause && intoClause) {
|
||||
subSql += ' returning ' + returningClause + ' into' + intoClause;
|
||||
}
|
||||
|
||||
// Pre bind position because subSql is an execute immediate parameter
|
||||
// later position binding will only convert the ? params
|
||||
subSql = self.formatter.client.positionBindings(subSql);
|
||||
const parameterizedValuesWithoutDefaultAndBlob = parameterizedValues
|
||||
.replace(/DEFAULT, /g, '')
|
||||
.replace(/, DEFAULT/g, '')
|
||||
.replace('EMPTY_BLOB(), ', '')
|
||||
.replace(', EMPTY_BLOB()', '');
|
||||
return (
|
||||
"execute immediate '" +
|
||||
subSql.replace(/'/g, "''") +
|
||||
(parameterizedValuesWithoutDefaultAndBlob || value
|
||||
? "' using "
|
||||
: '') +
|
||||
parameterizedValuesWithoutDefaultAndBlob +
|
||||
(parameterizedValuesWithoutDefaultAndBlob && outClause ? ',' : '') +
|
||||
outClause +
|
||||
';'
|
||||
);
|
||||
})
|
||||
.join(' ') +
|
||||
'end;';
|
||||
|
||||
sql.outBinding = outBinding;
|
||||
if (returning[0] === '*') {
|
||||
// Generate select statement with special order by
|
||||
// to keep the order because 'in (..)' may change the order
|
||||
sql.returningSql = function () {
|
||||
return (
|
||||
'select * from ' +
|
||||
self.tableName +
|
||||
' where ROWID in (' +
|
||||
this.outBinding
|
||||
.map(function (v, i) {
|
||||
return ':' + (i + 1);
|
||||
})
|
||||
.join(', ') +
|
||||
')' +
|
||||
' order by case ROWID ' +
|
||||
this.outBinding
|
||||
.map(function (v, i) {
|
||||
return 'when CHARTOROWID(:' + (i + 1) + ') then ' + i;
|
||||
})
|
||||
.join(' ') +
|
||||
' end'
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
return sql;
|
||||
}
|
||||
|
||||
with() {
|
||||
// WITH RECURSIVE is a syntax error in Oracle SQL.
|
||||
// So mark all statements as non-recursive, generate the SQL, then restore.
|
||||
// This approach ensures any changes in base class with() get propagated here.
|
||||
const undoList = [];
|
||||
if (this.grouped.with) {
|
||||
for (const stmt of this.grouped.with) {
|
||||
if (stmt.recursive) {
|
||||
undoList.push(stmt);
|
||||
stmt.recursive = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const result = super.with();
|
||||
|
||||
// Restore the recursive markings, in case this same query gets cloned and passed to other drivers.
|
||||
for (const stmt of undoList) {
|
||||
stmt.recursive = true;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
_addReturningToSqlAndConvert(sql, outBinding, tableName, returning) {
|
||||
const self = this;
|
||||
const res = {
|
||||
sql: sql,
|
||||
};
|
||||
|
||||
if (!outBinding) {
|
||||
return res;
|
||||
}
|
||||
const returningValues = Array.isArray(outBinding)
|
||||
? outBinding
|
||||
: [outBinding];
|
||||
let returningClause = '';
|
||||
let intoClause = '';
|
||||
// Build returning and into clauses
|
||||
returningValues.forEach(function (ret) {
|
||||
const columnName = ret.columnName || ret;
|
||||
returningClause += self.formatter.wrap(columnName) + ',';
|
||||
intoClause += '?,';
|
||||
|
||||
// Add Helpers to bindings
|
||||
if (ret instanceof BlobHelper) {
|
||||
return self.formatter.bindings.push(ret);
|
||||
}
|
||||
self.formatter.bindings.push(new ReturningHelper(columnName));
|
||||
});
|
||||
res.sql = sql;
|
||||
|
||||
// Strip last comma
|
||||
returningClause = returningClause.slice(0, -1);
|
||||
intoClause = intoClause.slice(0, -1);
|
||||
if (returningClause && intoClause) {
|
||||
res.sql += ' returning ' + returningClause + ' into ' + intoClause;
|
||||
}
|
||||
res.outBinding = [outBinding];
|
||||
if (returning[0] === '*') {
|
||||
res.returningSql = function () {
|
||||
return 'select * from ' + self.tableName + ' where ROWID = :1';
|
||||
};
|
||||
}
|
||||
res.returning = returning;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
_prepOutbindings(paramValues, paramReturning) {
|
||||
const result = {};
|
||||
let params = paramValues || [];
|
||||
let returning = paramReturning || [];
|
||||
if (!Array.isArray(params) && isPlainObject(paramValues)) {
|
||||
params = [params];
|
||||
}
|
||||
// Always wrap returning argument in array
|
||||
if (returning && !Array.isArray(returning)) {
|
||||
returning = [returning];
|
||||
}
|
||||
|
||||
const outBinding = [];
|
||||
// Handle Buffer value as Blob
|
||||
each(params, function (values, index) {
|
||||
if (returning[0] === '*') {
|
||||
outBinding[index] = ['ROWID'];
|
||||
} else {
|
||||
outBinding[index] = clone(returning);
|
||||
}
|
||||
each(values, function (value, key) {
|
||||
if (value instanceof Buffer) {
|
||||
values[key] = new BlobHelper(key, value);
|
||||
|
||||
// Delete blob duplicate in returning
|
||||
const blobIndex = outBinding[index].indexOf(key);
|
||||
if (blobIndex >= 0) {
|
||||
outBinding[index].splice(blobIndex, 1);
|
||||
values[key].returning = true;
|
||||
}
|
||||
outBinding[index].push(values[key]);
|
||||
}
|
||||
if (value === undefined) {
|
||||
delete params[index][key];
|
||||
}
|
||||
});
|
||||
});
|
||||
result.returning = returning;
|
||||
result.outBinding = outBinding;
|
||||
result.values = params;
|
||||
return result;
|
||||
}
|
||||
|
||||
_groupOrder(item, type) {
|
||||
return super._groupOrderNulls(item, type);
|
||||
}
|
||||
|
||||
update() {
|
||||
const self = this;
|
||||
const sql = {};
|
||||
const outBindPrep = this._prepOutbindings(
|
||||
this.single.update || this.single.counter,
|
||||
this.single.returning
|
||||
);
|
||||
const outBinding = outBindPrep.outBinding;
|
||||
const returning = outBindPrep.returning;
|
||||
|
||||
const updates = this._prepUpdate(this.single.update);
|
||||
const where = this.where();
|
||||
|
||||
let returningClause = '';
|
||||
let intoClause = '';
|
||||
|
||||
if (isEmpty(updates) && typeof this.single.update !== 'function') {
|
||||
return '';
|
||||
}
|
||||
|
||||
// Build returning and into clauses
|
||||
outBinding.forEach(function (out) {
|
||||
out.forEach(function (ret) {
|
||||
const columnName = ret.columnName || ret;
|
||||
returningClause += self.formatter.wrap(columnName) + ',';
|
||||
intoClause += ' ?,';
|
||||
|
||||
// Add Helpers to bindings
|
||||
if (ret instanceof BlobHelper) {
|
||||
return self.formatter.bindings.push(ret);
|
||||
}
|
||||
self.formatter.bindings.push(new ReturningHelper(columnName));
|
||||
});
|
||||
});
|
||||
// Strip last comma
|
||||
returningClause = returningClause.slice(0, -1);
|
||||
intoClause = intoClause.slice(0, -1);
|
||||
|
||||
sql.outBinding = outBinding;
|
||||
sql.returning = returning;
|
||||
sql.sql =
|
||||
'update ' +
|
||||
this.tableName +
|
||||
' set ' +
|
||||
updates.join(', ') +
|
||||
(where ? ' ' + where : '');
|
||||
if (outBinding.length && !isEmpty(outBinding[0])) {
|
||||
sql.sql += ' returning ' + returningClause + ' into' + intoClause;
|
||||
}
|
||||
if (returning[0] === '*') {
|
||||
sql.returningSql = function () {
|
||||
let sql = 'select * from ' + self.tableName;
|
||||
const modifiedRowsCount = this.rowsAffected.length || this.rowsAffected;
|
||||
let returningSqlIn = ' where ROWID in (';
|
||||
let returningSqlOrderBy = ') order by case ROWID ';
|
||||
|
||||
// Needs special order by because in(...) change result order
|
||||
for (let i = 0; i < modifiedRowsCount; i++) {
|
||||
if (this.returning[0] === '*') {
|
||||
returningSqlIn += ':' + (i + 1) + ', ';
|
||||
returningSqlOrderBy +=
|
||||
'when CHARTOROWID(:' + (i + 1) + ') then ' + i + ' ';
|
||||
}
|
||||
}
|
||||
if (this.returning[0] === '*') {
|
||||
this.returning = this.returning.slice(0, -1);
|
||||
returningSqlIn = returningSqlIn.slice(0, -2);
|
||||
returningSqlOrderBy = returningSqlOrderBy.slice(0, -1);
|
||||
}
|
||||
return (sql += returningSqlIn + returningSqlOrderBy + ' end');
|
||||
};
|
||||
}
|
||||
|
||||
return sql;
|
||||
}
|
||||
|
||||
_jsonPathWrap(extraction) {
|
||||
return `'${extraction.path || extraction[1]}'`;
|
||||
}
|
||||
|
||||
// Json functions
|
||||
jsonExtract(params) {
|
||||
return this._jsonExtract(
|
||||
params.singleValue ? 'json_value' : 'json_query',
|
||||
params
|
||||
);
|
||||
}
|
||||
|
||||
jsonSet(params) {
|
||||
return `json_transform(${columnize_(
|
||||
params.column,
|
||||
this.builder,
|
||||
this.client,
|
||||
this.bindingsHolder
|
||||
)}, set ${this.client.parameter(
|
||||
params.path,
|
||||
this.builder,
|
||||
this.bindingsHolder
|
||||
)} = ${this.client.parameter(
|
||||
params.value,
|
||||
this.builder,
|
||||
this.bindingsHolder
|
||||
)})`;
|
||||
}
|
||||
|
||||
jsonInsert(params) {
|
||||
return `json_transform(${columnize_(
|
||||
params.column,
|
||||
this.builder,
|
||||
this.client,
|
||||
this.bindingsHolder
|
||||
)}, insert ${this.client.parameter(
|
||||
params.path,
|
||||
this.builder,
|
||||
this.bindingsHolder
|
||||
)} = ${this.client.parameter(
|
||||
params.value,
|
||||
this.builder,
|
||||
this.bindingsHolder
|
||||
)})`;
|
||||
}
|
||||
|
||||
jsonRemove(params) {
|
||||
const jsonCol = `json_transform(${columnize_(
|
||||
params.column,
|
||||
this.builder,
|
||||
this.client,
|
||||
this.bindingsHolder
|
||||
)}, remove ${this.client.parameter(
|
||||
params.path,
|
||||
this.builder,
|
||||
this.bindingsHolder
|
||||
)})`;
|
||||
return params.alias
|
||||
? this.client.alias(jsonCol, this.formatter.wrap(params.alias))
|
||||
: jsonCol;
|
||||
}
|
||||
|
||||
whereJsonPath(statement) {
|
||||
return this._whereJsonPath('json_value', statement);
|
||||
}
|
||||
|
||||
whereJsonSupersetOf(statement) {
|
||||
throw new Error(
|
||||
'Json superset where clause not actually supported by Oracle'
|
||||
);
|
||||
}
|
||||
|
||||
whereJsonSubsetOf(statement) {
|
||||
throw new Error(
|
||||
'Json subset where clause not actually supported by Oracle'
|
||||
);
|
||||
}
|
||||
|
||||
onJsonPathEquals(clause) {
|
||||
return this._onJsonPathEquals('json_value', clause);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Oracledb_Compiler;
|
||||
61
node_modules/knex/lib/dialects/oracledb/schema/oracledb-columncompiler.js
generated
vendored
Executable file
61
node_modules/knex/lib/dialects/oracledb/schema/oracledb-columncompiler.js
generated
vendored
Executable file
@@ -0,0 +1,61 @@
|
||||
const ColumnCompiler_Oracle = require('../../oracle/schema/oracle-columncompiler');
|
||||
const { isObject } = require('../../../util/is');
|
||||
|
||||
class ColumnCompiler_Oracledb extends ColumnCompiler_Oracle {
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
this.modifiers = ['defaultTo', 'nullable', 'comment', 'checkJson'];
|
||||
this._addCheckModifiers();
|
||||
}
|
||||
|
||||
datetime(withoutTz) {
|
||||
let useTz;
|
||||
if (isObject(withoutTz)) {
|
||||
({ useTz } = withoutTz);
|
||||
} else {
|
||||
useTz = !withoutTz;
|
||||
}
|
||||
return useTz ? 'timestamp with local time zone' : 'timestamp';
|
||||
}
|
||||
|
||||
timestamp(withoutTz) {
|
||||
let useTz;
|
||||
if (isObject(withoutTz)) {
|
||||
({ useTz } = withoutTz);
|
||||
} else {
|
||||
useTz = !withoutTz;
|
||||
}
|
||||
return useTz ? 'timestamp with local time zone' : 'timestamp';
|
||||
}
|
||||
|
||||
checkRegex(regex, constraintName) {
|
||||
return this._check(
|
||||
`REGEXP_LIKE(${this.formatter.wrap(
|
||||
this.getColumnName()
|
||||
)},${this.client._escapeBinding(regex)})`,
|
||||
constraintName
|
||||
);
|
||||
}
|
||||
|
||||
json() {
|
||||
// implicitly add the check for json
|
||||
this.columnBuilder._modifiers.checkJson = [
|
||||
this.formatter.columnize(this.getColumnName()),
|
||||
];
|
||||
return 'varchar2(4000)';
|
||||
}
|
||||
|
||||
jsonb() {
|
||||
return this.json();
|
||||
}
|
||||
|
||||
checkJson(column) {
|
||||
return `check (${column} is json)`;
|
||||
}
|
||||
}
|
||||
|
||||
ColumnCompiler_Oracledb.prototype.time = 'timestamp with local time zone';
|
||||
ColumnCompiler_Oracledb.prototype.uuid = ({ useBinaryUuid = false } = {}) =>
|
||||
useBinaryUuid ? 'raw(16)' : 'char(36)';
|
||||
|
||||
module.exports = ColumnCompiler_Oracledb;
|
||||
19
node_modules/knex/lib/dialects/oracledb/schema/oracledb-tablecompiler.js
generated
vendored
Executable file
19
node_modules/knex/lib/dialects/oracledb/schema/oracledb-tablecompiler.js
generated
vendored
Executable file
@@ -0,0 +1,19 @@
|
||||
const TableCompiler_Oracle = require('../../oracle/schema/oracle-tablecompiler');
|
||||
|
||||
class TableCompiler_Oracledb extends TableCompiler_Oracle {
|
||||
constructor(client, tableBuilder) {
|
||||
super(client, tableBuilder);
|
||||
}
|
||||
|
||||
_setNullableState(column, isNullable) {
|
||||
const nullability = isNullable ? 'NULL' : 'NOT NULL';
|
||||
const sql = `alter table ${this.tableName()} modify (${this.formatter.wrap(
|
||||
column
|
||||
)} ${nullability})`;
|
||||
return this.pushQuery({
|
||||
sql: sql,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = TableCompiler_Oracledb;
|
||||
13
node_modules/knex/lib/dialects/oracledb/schema/oracledb-viewbuilder.js
generated
vendored
Executable file
13
node_modules/knex/lib/dialects/oracledb/schema/oracledb-viewbuilder.js
generated
vendored
Executable file
@@ -0,0 +1,13 @@
|
||||
const ViewBuilder = require('../../../schema/viewbuilder.js');
|
||||
|
||||
class ViewBuilder_Oracledb extends ViewBuilder {
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
}
|
||||
|
||||
checkOption() {
|
||||
this._single.checkOption = 'default_option';
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ViewBuilder_Oracledb;
|
||||
19
node_modules/knex/lib/dialects/oracledb/schema/oracledb-viewcompiler.js
generated
vendored
Executable file
19
node_modules/knex/lib/dialects/oracledb/schema/oracledb-viewcompiler.js
generated
vendored
Executable file
@@ -0,0 +1,19 @@
|
||||
/* eslint max-len: 0 */
|
||||
|
||||
const ViewCompiler = require('../../../schema/viewcompiler.js');
|
||||
|
||||
class ViewCompiler_Oracledb extends ViewCompiler {
|
||||
constructor(client, viewCompiler) {
|
||||
super(client, viewCompiler);
|
||||
}
|
||||
|
||||
createOrReplace() {
|
||||
this.createQuery(this.columns, this.selectQuery, false, true);
|
||||
}
|
||||
|
||||
createMaterializedView() {
|
||||
this.createQuery(this.columns, this.selectQuery, true);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ViewCompiler_Oracledb;
|
||||
98
node_modules/knex/lib/dialects/oracledb/transaction.js
generated
vendored
Executable file
98
node_modules/knex/lib/dialects/oracledb/transaction.js
generated
vendored
Executable file
@@ -0,0 +1,98 @@
|
||||
const Transaction = require('../../execution/transaction');
|
||||
const { timeout, KnexTimeoutError } = require('../../util/timeout');
|
||||
const debugTx = require('debug')('knex:tx');
|
||||
|
||||
// There's also a "read only", but that's not really an "isolationLevel"
|
||||
const supportedIsolationLevels = ['read committed', 'serializable'];
|
||||
// Remove this if you make it work and set it to true
|
||||
const isIsolationLevelEnabled = false;
|
||||
|
||||
module.exports = class Oracle_Transaction extends Transaction {
|
||||
// disable autocommit to allow correct behavior (default is true)
|
||||
begin(conn) {
|
||||
if (this.isolationLevel) {
|
||||
if (isIsolationLevelEnabled) {
|
||||
if (!supportedIsolationLevels.includes(this.isolationLevel)) {
|
||||
this.client.logger.warn(
|
||||
'Oracle only supports read committed and serializable transactions, ignoring the isolation level param'
|
||||
);
|
||||
} else {
|
||||
// I tried this, but it didn't work
|
||||
// Doc here: https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/SET-TRANSACTION.html
|
||||
return this.query(conn, `SET TRANSACTION ${this.isolationLevel}`);
|
||||
}
|
||||
} else {
|
||||
this.client.logger.warn(
|
||||
'Transaction isolation is not currently supported for Oracle'
|
||||
);
|
||||
}
|
||||
}
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
async commit(conn, value) {
|
||||
this._completed = true;
|
||||
try {
|
||||
await conn.commitAsync();
|
||||
this._resolver(value);
|
||||
} catch (err) {
|
||||
this._rejecter(err);
|
||||
}
|
||||
}
|
||||
|
||||
release(conn, value) {
|
||||
return this._resolver(value);
|
||||
}
|
||||
|
||||
rollback(conn, err) {
|
||||
this._completed = true;
|
||||
debugTx('%s: rolling back', this.txid);
|
||||
return timeout(conn.rollbackAsync(), 5000)
|
||||
.catch((e) => {
|
||||
if (!(e instanceof KnexTimeoutError)) {
|
||||
return Promise.reject(e);
|
||||
}
|
||||
this._rejecter(e);
|
||||
})
|
||||
.then(() => {
|
||||
if (err === undefined) {
|
||||
if (this.doNotRejectOnRollback) {
|
||||
this._resolver();
|
||||
return;
|
||||
}
|
||||
err = new Error(`Transaction rejected with non-error: ${err}`);
|
||||
}
|
||||
this._rejecter(err);
|
||||
});
|
||||
}
|
||||
|
||||
savepoint(conn) {
|
||||
return this.query(conn, `SAVEPOINT ${this.txid}`);
|
||||
}
|
||||
|
||||
async acquireConnection(config, cb) {
|
||||
const configConnection = config && config.connection;
|
||||
|
||||
const connection =
|
||||
configConnection || (await this.client.acquireConnection());
|
||||
try {
|
||||
connection.__knexTxId = this.txid;
|
||||
connection.isTransaction = true;
|
||||
return await cb(connection);
|
||||
} finally {
|
||||
debugTx('%s: releasing connection', this.txid);
|
||||
connection.isTransaction = false;
|
||||
try {
|
||||
await connection.commitAsync();
|
||||
} catch (err) {
|
||||
this._rejecter(err);
|
||||
} finally {
|
||||
if (!configConnection) {
|
||||
await this.client.releaseConnection(connection);
|
||||
} else {
|
||||
debugTx('%s: not releasing external connection', this.txid);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
208
node_modules/knex/lib/dialects/oracledb/utils.js
generated
vendored
Executable file
208
node_modules/knex/lib/dialects/oracledb/utils.js
generated
vendored
Executable file
@@ -0,0 +1,208 @@
|
||||
const Utils = require('../oracle/utils');
|
||||
const { promisify } = require('util');
|
||||
const stream = require('stream');
|
||||
|
||||
function BlobHelper(columnName, value) {
|
||||
this.columnName = columnName;
|
||||
this.value = value;
|
||||
this.returning = false;
|
||||
}
|
||||
|
||||
BlobHelper.prototype.toString = function () {
|
||||
return '[object BlobHelper:' + this.columnName + ']';
|
||||
};
|
||||
|
||||
/**
|
||||
* @param stream
|
||||
* @param {'string' | 'buffer'} type
|
||||
*/
|
||||
function readStream(stream, type) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let data = type === 'string' ? '' : Buffer.alloc(0);
|
||||
|
||||
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);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
function monkeyPatchConnection(connection, client) {
|
||||
// Connection is already monkey-patched
|
||||
if (connection.executeAsync) {
|
||||
return;
|
||||
}
|
||||
|
||||
connection.commitAsync = function () {
|
||||
return new Promise((commitResolve, commitReject) => {
|
||||
this.commit(function (err) {
|
||||
if (err) {
|
||||
return commitReject(err);
|
||||
}
|
||||
commitResolve();
|
||||
});
|
||||
});
|
||||
};
|
||||
connection.rollbackAsync = function () {
|
||||
return new Promise((rollbackResolve, rollbackReject) => {
|
||||
this.rollback(function (err) {
|
||||
if (err) {
|
||||
return rollbackReject(err);
|
||||
}
|
||||
rollbackResolve();
|
||||
});
|
||||
});
|
||||
};
|
||||
const fetchAsync = promisify(function (sql, bindParams, options, cb) {
|
||||
options = options || {};
|
||||
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, result) {
|
||||
if (err) {
|
||||
if (Utils.isConnectionError(err)) {
|
||||
connection.close().catch(function (err) {});
|
||||
connection.__knex__disposed = err;
|
||||
}
|
||||
return cb(err);
|
||||
}
|
||||
const fetchResult = { rows: [], resultSet: result.resultSet };
|
||||
const numRows = 100;
|
||||
const fetchRowsFromRS = function (connection, resultSet, numRows) {
|
||||
resultSet.getRows(numRows, function (err, rows) {
|
||||
if (err) {
|
||||
if (Utils.isConnectionError(err)) {
|
||||
connection.close().catch(function (err) {});
|
||||
connection.__knex__disposed = err;
|
||||
}
|
||||
resultSet.close(function () {
|
||||
return cb(err);
|
||||
});
|
||||
} else if (rows.length === 0) {
|
||||
return cb(null, fetchResult);
|
||||
} else if (rows.length > 0) {
|
||||
if (rows.length === numRows) {
|
||||
fetchResult.rows = fetchResult.rows.concat(rows);
|
||||
fetchRowsFromRS(connection, resultSet, numRows);
|
||||
} else {
|
||||
fetchResult.rows = fetchResult.rows.concat(rows);
|
||||
return cb(null, fetchResult);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
fetchRowsFromRS(connection, result.resultSet, numRows);
|
||||
}
|
||||
);
|
||||
} else {
|
||||
connection.execute(
|
||||
sql,
|
||||
bindParams || [],
|
||||
options,
|
||||
function (err, result) {
|
||||
if (err) {
|
||||
// dispose the connection on connection error
|
||||
if (Utils.isConnectionError(err)) {
|
||||
connection.close().catch(function (err) {});
|
||||
connection.__knex__disposed = err;
|
||||
}
|
||||
return cb(err);
|
||||
}
|
||||
|
||||
return cb(null, result);
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
connection.executeAsync = function (sql, bindParams, options) {
|
||||
// Read all lob
|
||||
return fetchAsync(sql, bindParams, options).then(async (results) => {
|
||||
const closeResultSet = () => {
|
||||
return results.resultSet
|
||||
? promisify(results.resultSet.close).call(results.resultSet)
|
||||
: Promise.resolve();
|
||||
};
|
||||
|
||||
// Collect LOBs to read
|
||||
const lobs = [];
|
||||
if (results.rows) {
|
||||
if (Array.isArray(results.rows)) {
|
||||
for (let i = 0; i < results.rows.length; i++) {
|
||||
// Iterate through the rows
|
||||
const row = results.rows[i];
|
||||
for (const column in row) {
|
||||
if (row[column] instanceof stream.Readable) {
|
||||
lobs.push({ index: i, key: column, stream: row[column] });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
for (const lob of lobs) {
|
||||
// todo should be fetchAsString/fetchAsBuffer polyfill only
|
||||
results.rows[lob.index][lob.key] = await lobProcessing(lob.stream);
|
||||
}
|
||||
} catch (e) {
|
||||
await closeResultSet().catch(() => {});
|
||||
|
||||
throw e;
|
||||
}
|
||||
|
||||
await closeResultSet();
|
||||
|
||||
return results;
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
Utils.BlobHelper = BlobHelper;
|
||||
Utils.monkeyPatchConnection = monkeyPatchConnection;
|
||||
module.exports = Utils;
|
||||
Reference in New Issue
Block a user