UNPKG

@sap/hdbext

Version:

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

146 lines (122 loc) 4.93 kB
'use strict'; var async = require('async'); var VError = require('verror'); var debug = require('debug')('hdbext:sp'); var StoredProcedure = require('./StoredProcedure'); module.exports = load; function load(client, schema, name, callback) { var procInfo = { schema: null, name: name, metadata: null }; async.waterfall([ function resolveSchema(cb) { if (schema) { return cb(null, schema); } client.exec('SELECT CURRENT_SCHEMA FROM DUMMY', function (err, rs) { if (err) { return cb(err); } cb(null, rs[0].CURRENT_SCHEMA); }); }, function resolveProcedureInfo(schema, cb) { procInfo.schema = schema; fetchMetadata(client, procInfo, function (err, metadata) { if (err) { return cb(err); } procInfo.metadata = metadata; if (procInfo.metadata.length) { return cb(null, procInfo); } checkIfProcedureExists(client, procInfo, function (err, exists) { if (err) { return cb(err); } if (exists) { debug('Procedure %s.%s does not have any parameters', procInfo.schema, procInfo.name); return cb(null, procInfo); } checkSynonyms(client, procInfo, function (err, result) { if (err) { return cb(err); } if (!result.isSynonym) { return cb(new VError('Procedure %s.%s does not exist', procInfo.schema, procInfo.name)); } debug('%s.%s is a synonym for %s.%s', procInfo.schema, procInfo.name, result.schema, result.name); // use the data of the referenced procedure procInfo.schema = result.schema; procInfo.name = result.name; procInfo.metadata = null; fetchMetadata(client, procInfo, function (err, metadata) { if (err) { return cb(err); } procInfo.metadata = metadata; cb(null, procInfo); }); }); }); }); }, function buildSpFunction(procInfo, cb) { var sp = new StoredProcedure(client, procInfo.schema, procInfo.name, procInfo.metadata); var spFunction = StoredProcedure.prototype.exec.bind(sp); spFunction.paramsMetadata = procInfo.metadata; cb(null, spFunction); } ], callback); } function fetchMetadata(client, procInfo, cb) { var sqlProcedureMetadata = "SELECT \ PARAMS.PARAMETER_NAME, \ PARAMS.DATA_TYPE_NAME, \ PARAMS.PARAMETER_TYPE, \ PARAMS.HAS_DEFAULT_VALUE, \ PARAMS.IS_INPLACE_TYPE, \ PARAMS.TABLE_TYPE_SCHEMA, \ PARAMS.TABLE_TYPE_NAME, \ \ CASE WHEN SYNONYMS.OBJECT_NAME IS NULL THEN 'FALSE' ELSE 'TRUE' END AS IS_TABLE_TYPE_SYNONYM, \ IFNULL(SYNONYMS.OBJECT_SCHEMA, '') AS OBJECT_SCHEMA, \ IFNULL(SYNONYMS.OBJECT_NAME, '') AS OBJECT_NAME \ \ FROM SYS.PROCEDURE_PARAMETERS AS PARAMS \ LEFT JOIN SYS.SYNONYMS AS SYNONYMS \ ON SYNONYMS.SCHEMA_NAME = PARAMS.TABLE_TYPE_SCHEMA AND SYNONYMS.SYNONYM_NAME = PARAMS.TABLE_TYPE_NAME \ WHERE PARAMS.SCHEMA_NAME = ? AND PARAMS.PROCEDURE_NAME = ? \ ORDER BY PARAMS.POSITION"; client.exec(sqlProcedureMetadata, [procInfo.schema, procInfo.name], cb); } function checkSynonyms(client, procInfo, cb) { var sqlLookupSynonym = 'SELECT OBJECT_SCHEMA, OBJECT_NAME, IS_VALID FROM SYS.SYNONYMS WHERE SCHEMA_NAME = ? AND SYNONYM_NAME = ?'; client.exec(sqlLookupSynonym, [procInfo.schema, procInfo.name], function (err, rs) { if (err) { return cb(err); } var result = { isSynonym: !!rs.length }; if (!result.isSynonym) { return cb(null, result); } if (rs[0].IS_VALID !== 'TRUE') { debug('Data for synonym %s.%s: %j', procInfo.schema, procInfo.name, rs[0]); return cb(new VError('Synonym %s.%s is not valid', procInfo.schema, procInfo.name)); } result.schema = rs[0].OBJECT_SCHEMA; result.name = rs[0].OBJECT_NAME; cb(null, result); }); } function checkIfProcedureExists(client, procInfo, cb) { var sqlCheckIfProcedureExists = 'SELECT COUNT(0) AS "count" FROM SYS.PROCEDURES WHERE SCHEMA_NAME = ? AND PROCEDURE_NAME = ?'; client.exec(sqlCheckIfProcedureExists, [procInfo.schema, procInfo.name], function (err, rs) { if (err) { return cb(err); } return cb(null, !!rs[0].count); }); }