123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274 |
- 'use strict';
- var _ = require('lodash');
- var inherits = require('inherits');
- var Oracle_Compiler = require('../../oracle/query/compiler');
- var ReturningHelper = require('../utils').ReturningHelper;
- var BlobHelper = require('../utils').BlobHelper;
- function Oracledb_Compiler(client, builder) {
- Oracle_Compiler.call(this, client, builder);
- }
- inherits(Oracledb_Compiler, Oracle_Compiler);
- _.assign(Oracledb_Compiler.prototype, {
- // Compiles an "insert" query, allowing for multiple
- // inserts using a single query statement.
- insert: function insert() {
- var self = this;
- var outBindPrep = this._prepOutbindings(this.single.insert, this.single.returning);
- var outBinding = outBindPrep.outBinding;
- var returning = outBindPrep.returning;
- var insertValues = outBindPrep.values;
- if (Array.isArray(insertValues) && insertValues.length === 1 && _.isEmpty(insertValues[0])) {
- return this._addReturningToSqlAndConvert('insert into ' + this.tableName + ' (' + this.formatter.wrap(this.single.returning) + ') values (default)', outBinding[0], this.tableName, returning);
- }
- if (_.isEmpty(this.single.insert) && typeof this.single.insert !== 'function') {
- return '';
- }
- var insertData = this._prepInsert(insertValues);
- var 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.formatter.parameterize(insertData.values[0]) + ')', outBinding[0], this.tableName, returning);
- }
- var insertDefaultsOnly = insertData.columns.length === 0;
- sql.returning = returning;
- sql.sql = 'begin ' + _.map(insertData.values, function (value, index) {
- var parameterizedValues = !insertDefaultsOnly ? self.formatter.parameterize(value, self.client.valueForUndefined) : '';
- var 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 + ')';
- }
- var returningClause = '';
- var intoClause = '';
- var usingClause = '';
- var outClause = '';
- _.each(value, function (val) {
- if (!(val instanceof BlobHelper)) {
- usingClause += ' ?,';
- }
- });
- usingClause = usingClause.slice(0, -1);
- // Build returning and into clauses
- _.each(outBinding[index], function (ret) {
- var columnName = ret.columnName || ret;
- returningClause += '"' + 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);
- var parameterizedValuesWithoutDefaultAndBlob = parameterizedValues.replace('DEFAULT, ', '').replace(', DEFAULT', '').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] === '*') {
- returning = returning.slice(0, -1);
- // 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;
- },
- _addReturningToSqlAndConvert: function _addReturningToSqlAndConvert(sql, outBinding, tableName, returning) {
- var self = this;
- var res = {
- sql: sql
- };
- if (!outBinding) {
- return res;
- }
- var returningValues = Array.isArray(outBinding) ? outBinding : [outBinding];
- var returningClause = '';
- var intoClause = '';
- // Build returning and into clauses
- _.each(returningValues, function (ret) {
- var columnName = ret.columnName || ret;
- returningClause += '"' + 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: function _prepOutbindings(paramValues, paramReturning) {
- var result = {};
- var params = paramValues || [];
- var returning = paramReturning || [];
- if (!Array.isArray(params) && _.isPlainObject(paramValues)) {
- params = [params];
- }
- // Always wrap returning argument in array
- if (returning && !Array.isArray(returning)) {
- returning = [returning];
- }
- var 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
- var blobIndex = outBinding[index].indexOf(key);
- if (blobIndex >= 0) {
- outBinding[index].splice(blobIndex, 1);
- values[key].returning = true;
- }
- outBinding[index].push(values[key]);
- }
- if (_.isUndefined(value)) {
- delete params[index][key];
- }
- });
- });
- result.returning = returning;
- result.outBinding = outBinding;
- result.values = params;
- return result;
- },
- update: function update() {
- var self = this;
- var sql = {};
- var outBindPrep = this._prepOutbindings(this.single.update, this.single.returning);
- var outBinding = outBindPrep.outBinding;
- var returning = outBindPrep.returning;
- var updates = this._prepUpdate(this.single.update);
- var where = this.where();
- var returningClause = '';
- var intoClause = '';
- if (_.isEmpty(this.single.update) && typeof this.single.update !== 'function') {
- return '';
- }
- // Build returning and into clauses
- _.each(outBinding, function (out) {
- _.each(out, function (ret) {
- var columnName = ret.columnName || ret;
- returningClause += '"' + 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 () {
- var sql = 'select * from ' + self.tableName;
- var modifiedRowsCount = this.rowsAffected.length || this.rowsAffected;
- var returningSqlIn = ' where ROWID in (';
- var returningSqlOrderBy = ') order by case ROWID ';
- // Needs special order by because in(...) change result order
- for (var 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;
- }
- });
- module.exports = Oracledb_Compiler;
|