UNPKG

@sap/hdbext

Version:

Hana-client extension library and utility functions for using SAP HANA in node.js

151 lines (131 loc) 4.59 kB
'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]; }); }); }