Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions hana/lib/HANAService.js
Original file line number Diff line number Diff line change
Expand Up @@ -1297,8 +1297,7 @@ SELECT ${mixing} FROM JSON_TABLE(SRC.JSON, '$' COLUMNS(${extraction}) ERROR ON E
async onCall({ query, data }, name, schema) {
const isAsync = /\sASYNC\s*$/.test(query)
const outParameters = isAsync ? [{ PARAMETER_NAME: 'ASYNC_CALL_ID' }] : await this._getProcedureMetadata(name, schema)
const ps = await this.prepare(query)
const ret = this.ensureDBC() && await ps.proc(data, outParameters)
const ret = await this.ensureDBC().proc(query, data, outParameters)
return isAsync ? ret.ASYNC_CALL_ID[0] : ret
}

Expand Down
9 changes: 9 additions & 0 deletions hana/lib/drivers/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,15 @@ class HANADriver {
return module.exports.prom(this._native, 'exec')(sql)
}

/**
* Used to execute procedure SQL statement like CALL, DO BEGIN, CALL ASYNC
* @param {string} sql The SQL String to be executed
* @returns {Promise<any>} The result from the database driver
*/
async proc(sql, data = []) {
throw new Error('Implementation missing "proc"')
}

set(variables) {
this._native.set(variables)
}
Expand Down
39 changes: 14 additions & 25 deletions hana/lib/drivers/hana-client.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@ class HANAClientDriver extends driver {
this._native.setAutoCommit(false)
}

async proc(sql, data, outParameters) {
await this.connected
const rows = await prom(this._native, 'exec')(sql, data, {returnMultipleResultSets:true})
return this._getResultForProcedure(rows, outParameters)
}

async prepare(sql, hasBlobs) {
const ret = await super.prepare(sql)
// hana-client ResultSet API does not allow for deferred streaming of blobs
Expand Down Expand Up @@ -132,12 +138,6 @@ class HANAClientDriver extends driver {
return { changes }
}

ret.proc = async (data, outParameters) => {
const stmt = await ret._prep
const rows = await prom(stmt, 'execQuery')(data)
return this._getResultForProcedure(rows, outParameters, stmt)
}

ret.stream = async (values, one, objectMode) => {
const stmt = await ret._prep
values = Array.isArray(values) ? values : []
Expand Down Expand Up @@ -172,28 +172,17 @@ class HANAClientDriver extends driver {
return this._native.state() === 'connected'
}

_getResultForProcedure(rows, outParameters, stmt) {
const result = {}
// build result from scalar params
const paramInfo = stmt.getParameterInfo()
for (let i = 0; i < paramInfo.length; i++) {
if (paramInfo[i].direction > 1) {
result[paramInfo[i].name] = stmt.getParameterValue(i)
}
}

const resultSet = Array.isArray(rows) ? rows[0] : rows
_getResultForProcedure(rows, outParameters) {
// on hdb, rows already contains results for scalar params
const isArray = Array.isArray(rows)
const result = isArray ? { ...rows[0] } : { ...rows }

// merge table output params into scalar params
const params = Array.isArray(outParameters) && outParameters.filter(md => !(md.PARAMETER_NAME in result))
if (params && params.length) {
const args = isArray ? rows.slice(1) : []
if (args && args.length && outParameters) {
const params = outParameters.filter(md => !(md.PARAMETER_NAME in (isArray ? rows[0] : rows)))
for (let i = 0; i < params.length; i++) {
const parameterName = params[i].PARAMETER_NAME
result[parameterName] = []
while (resultSet.next()) {
result[parameterName].push(resultSet.getValues())
}
resultSet.nextResult()
result[params[i].PARAMETER_NAME] = args[i]
}
}

Expand Down
5 changes: 5 additions & 0 deletions hana/lib/drivers/hdb.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,11 @@ class HDBDriver extends driver {
})
}

async proc(sql, data, outParameters) {
const stmt = await this.prepare(sql)
return stmt.proc(data, outParameters)
}

async prepare(sql, hasBlobs) {
const ret = await super.prepare(sql)

Expand Down
8 changes: 4 additions & 4 deletions hana/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,19 +26,19 @@
},
"dependencies": {
"@cap-js/db-service": "^2.1.1",
"hdb": "^0.19.5"
"hdb": "^2.26.1"
},
"peerDependencies": {
"@sap/hana-client": "^2",
"@sap/cds": ">=9"
"@sap/cds": ">=9",
"@sap/hana-client": "^2.27.8"
},
"peerDependenciesMeta": {
"@sap/hana-client": {
"optional": true
}
},
"devDependencies": {
"@sap/hana-client": ">=2"
"@sap/hana-client": ">=2.27.8"
},
"cds": {
"requires": {
Expand Down
4 changes: 2 additions & 2 deletions hana/test/run.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ describe('stored procedures', () => {
await cds.run(`INSERT INTO sap_capire_TestEntity (ID,title) VALUES (20,'FROM TX')`)

// Call the procedure with ASYNC
const { ASYNC_CALL_ID } = await cds.run(`CALL WRITE_PROC() ASYNC`, [])
const { ASYNC_CALL_ID } = await cds.run(`CALL WRITE_PROC() ASYNC`)
const status = await cds.run(`DO (IN ID INTEGER => ?)
BEGIN
USING SQLSCRIPT_SYNC AS SYNCLIB;
Expand All @@ -125,7 +125,7 @@ BEGIN
SELECT ERROR_CODE, ERROR_TEXT, :dur AS WAITED_SECONDS FROM M_PROCEDURE_ASYNC_EXECUTIONS WHERE ASYNC_CALL_ID = :ID;
END;`, [ASYNC_CALL_ID])
// Ensure that the procedure succeeded
expect(status.changes[1][0].ERROR_CODE).to.eq(0)
expect(status.changes?.[0]?.ERROR_CODE ?? status.changes?.[1]?.[0]?.ERROR_CODE).to.eq(0)
throw new Error('ROLLBACK')
}).catch((err) => { if (err.message !== 'ROLLBACK') throw err })

Expand Down
Loading