@sap/hdbext
Version:
Hana-client extension library and utility functions for using SAP HANA in node.js
151 lines (131 loc) • 4.59 kB
JavaScript
'use strict';
var format = require('util').format;
var safeSql = require('../safe-sql');
var debug = require('debug')('hdbext:sp');
module.exports = TempTable;
function TempTable(sp, paramMeta, data) {
this._client = sp._client;
this._procSchema = sp._schema;
this._procName = sp._name;
this._name = createTempTableName(this._procName, paramMeta.PARAMETER_NAME);
this._paramMeta = paramMeta;
this._data = data;
}
TempTable.prototype.getName = function () {
return this._name;
};
TempTable.prototype.create = function (callback) {
var self = this;
this._generateCreateTableSql(function (err, sqlCreateTable) {
if (err) {
return callback(err);
}
debug(sqlCreateTable);
self._client.exec(sqlCreateTable, function (err) {
if (err) {
return callback(err);
}
if (!self._data.length) {
return callback();
}
var columnNames = extractColumnNames(self._data);
var sqlInsertInto = generateInsertIntoSql(self._name, columnNames);
debug(sqlInsertInto);
self._client.prepare(sqlInsertInto, function (err, stmt) {
if (err) {
return callback(err);
}
var normalizedData = normalizeData(self._data, columnNames);
stmt.execBatch(normalizedData, function (err) {
stmt.drop(function (dropErr) {
if (dropErr) {
debug('Could not drop statement for inserting data into temp table:', dropErr);
}
callback(err);
});
});
});
});
});
};
TempTable.prototype.dropInBackground = function () {
var sqlDropTable = 'DROP TABLE ' + safeSql.identifier(this._name);
debug(sqlDropTable);
this._client.exec(sqlDropTable, function (err) {
if (err) {
debug('Could not drop temp table (%s):', sqlDropTable, err);
}
});
};
TempTable.prototype._generateCreateTableSql = function (cb) {
if (this._paramMeta.IS_INPLACE_TYPE === 'FALSE') {
if (this._paramMeta.IS_TABLE_TYPE_SYNONYM === 'FALSE') {
var schema = this._paramMeta.TABLE_TYPE_SCHEMA;
var table = this._paramMeta.TABLE_TYPE_NAME;
} else {
schema = this._paramMeta.OBJECT_SCHEMA;
table = this._paramMeta.OBJECT_NAME;
}
return cb(null, format('CREATE LOCAL TEMPORARY COLUMN TABLE %s LIKE %s.%s',
safeSql.identifier(this._name),
safeSql.identifier(schema),
safeSql.identifier(table)));
}
var self = this;
var columnDefinitions = [];
var sqlInplaceTableMetadata = 'SELECT COLUMN_NAME, DATA_TYPE_NAME, LENGTH, SCALE FROM SYS.PROCEDURE_PARAMETER_COLUMNS \
WHERE SCHEMA_NAME = ? AND PROCEDURE_NAME = ? AND PARAMETER_NAME = ? ORDER BY POSITION';
this._client.exec(sqlInplaceTableMetadata, [this._procSchema, this._procName, this._paramMeta.PARAMETER_NAME], function (err, rs) {
if (err) {
return cb(err);
}
rs.forEach(function (row) {
// Reference: https://help.sap.com/saphelp_hanaplatform/helpdata/en/20/d58a5f75191014b2fe92141b7df228/frameset.htm
var str = format('%s %s', safeSql.identifier(row.COLUMN_NAME), row.DATA_TYPE_NAME);
switch (row.DATA_TYPE_NAME) {
case 'DECIMAL':
str += '(' + row.LENGTH;
if (row.SCALE !== null) {
str += ', ' + row.SCALE;
}
str += ')';
break;
case 'CHAR':
case 'NCHAR':
case 'VARCHAR':
case 'NVARCHAR':
case 'ALPHANUM':
case 'BINARY':
case 'VARBINARY':
case 'SHORTTEXT':
// FLOAT data type is represented as REAL or DOUBLE in the database
str += '(' + row.LENGTH + ')';
break;
}
columnDefinitions.push(str);
});
cb(null, format('CREATE LOCAL TEMPORARY COLUMN TABLE %s (%s)', safeSql.identifier(self._name), columnDefinitions.join(', ')));
});
};
function createTempTableName(procName, paramName) {
var random = Math.floor(Math.random() * 1000) + Date.now();
return format('#%s_%s_%d', procName, paramName, random);
}
function extractColumnNames(data) {
var firstRow = data[0];
return Object.keys(firstRow);
}
function generateInsertIntoSql(tableName, columnNames) {
var listColumns = columnNames.map(safeSql.identifier).join(', ');
var listPlaceholders = columnNames.map(function () {
return '?';
}).join(', ');
return format('INSERT INTO %s(%s) VALUES (%s)', safeSql.identifier(tableName), listColumns, listPlaceholders);
}
function normalizeData(data, columnNames) {
return data.map(function (row) {
return columnNames.map(function (column) {
return row[column];
});
});
}