Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Disconnect HANA tenant when deleted #589

Merged
merged 12 commits into from
May 7, 2024
36 changes: 25 additions & 11 deletions hana/lib/HANAService.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class HANAService extends SQLService {
this.on(['BEGIN'], this.onBEGIN)
this.on(['COMMIT'], this.onCOMMIT)
this.on(['ROLLBACK'], this.onROLLBACK)
this.on(['SELECT', 'INSERT', 'UPSERT', 'UPDATE', 'DELETE'], this.onNOTFOUND)
johannes-vogel marked this conversation as resolved.
Show resolved Hide resolved
return super.init()
}

Expand Down Expand Up @@ -135,8 +136,8 @@ class HANAService extends SQLService {
// REVISIT: add prepare options when param:true is used
const sqlScript = isLockQuery ? sql : this.wrapTemporary(temporary, withclause, blobs)
let rows = (values?.length || blobs.length > 0)
? await (await this.prepare(sqlScript, blobs.length)).all(values || [])
: await this.exec(sqlScript)
? await (await this.prepare(sqlScript, blobs.length)).all(values || [])
: await this.exec(sqlScript)

if (isLockQuery) {
// Fetch actual locked results
Expand Down Expand Up @@ -181,6 +182,20 @@ class HANAService extends SQLService {
}
}

async onNOTFOUND(req, next) {
try {
return await next()
} catch (err) {
// TODO: check that the query target is defined in the model
// Ensure that the known entity still exists
if (/*this.context.tenant && */ err.code === 259) {
johannes-vogel marked this conversation as resolved.
Show resolved Hide resolved
BobdenOs marked this conversation as resolved.
Show resolved Hide resolved
// Clear current tenant connection pool
this.disconnect(this.context.tenant)
}
throw err
}
}

// Allow for running complex expand queries in a single statement
wrapTemporary(temporary, withclauses, blobs) {
const blobColumn = b => `"${b.replace(/"/g, '""')}"`
Expand Down Expand Up @@ -1038,10 +1053,10 @@ class HANAService extends SQLService {
return super.dispatch(req)
}

async onCall({ query, data }, name, schema) {
const outParameters = await this._getProcedureMetadata(name, schema)
const ps = await this.prepare(query)
return ps.proc(data, outParameters)
async onCall({ query, data }, name, schema) {
const outParameters = await this._getProcedureMetadata(name, schema)
const ps = await this.prepare(query)
return ps.proc(data, outParameters)
}

async onPlainSQL(req, next) {
Expand All @@ -1057,7 +1072,7 @@ class HANAService extends SQLService {
throw err
}
}

const proc = this._getProcedureNameAndSchema(req.query)
if (proc && proc.name) return this.onCall(req, proc.name, proc.schema)

Expand Down Expand Up @@ -1164,15 +1179,14 @@ class HANAService extends SQLService {
}

async _getProcedureMetadata(name, schema) {
const query = `SELECT PARAMETER_NAME FROM SYS.PROCEDURE_PARAMETERS WHERE SCHEMA_NAME = ${
schema?.toUpperCase?.() === 'SYS' ? `'SYS'` : 'CURRENT_SCHEMA'
const query = `SELECT PARAMETER_NAME FROM SYS.PROCEDURE_PARAMETERS WHERE SCHEMA_NAME = ${schema?.toUpperCase?.() === 'SYS' ? `'SYS'` : 'CURRENT_SCHEMA'
} AND PROCEDURE_NAME = '${name}' AND PARAMETER_TYPE IN ('OUT', 'INOUT') ORDER BY POSITION`
return await super.onPlainSQL({ query, data: [] })
return await super.onPlainSQL({ query, data: [] })
}

_getProcedureNameAndSchema(sql) {
// name delimited with "" allows any character
const match = sql
const match = sql
.match(
/^\s*call \s*(("(?<schema_delimited>\w+)"\.)?("(?<delimited>.+)")|(?<schema_undelimited>\w+\.)?(?<undelimited>\w+))\s*\(/i
)
Expand Down
Loading