Skip to content

Commit

Permalink
fix: large amounts of expands in HANA Service (#355)
Browse files Browse the repository at this point in the history
Co-authored-by: Johannes Vogel <[email protected]>
  • Loading branch information
BobdenOs and johannes-vogel authored Nov 29, 2023
1 parent 6aedb7d commit 7d8521a
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 18 deletions.
3 changes: 2 additions & 1 deletion hana/lib/HANAService.js
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,8 @@ class HANAService extends SQLService {
})
break
} else {
level.data.push(data)
// REVISIT: identify why sometimes not all parent rows are returned
level.data.push?.(data)
levels.push({
data: data,
path: row._path_,
Expand Down
17 changes: 10 additions & 7 deletions hana/lib/drivers/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -222,10 +222,11 @@ const handleLevel = function (levels, path, expands) {
path: path.slice(0, -6),
expands,
})
} else {
// Current row is on the same level now so incrementing the index
// If the index was not 0 it should add a comma
if (level.index++) buffer += ','
}
// Current row is on the same level now so incrementing the index
// If the index was not 0 it should add a comma
if (level.index++) buffer += ','
levels.push({
index: 0,
suffix: '}',
Expand All @@ -236,10 +237,12 @@ const handleLevel = function (levels, path, expands) {
} else {
// Step up if it is not a child of the current level
const level = levels.pop()
const leftOverExpands = Object.keys(level.expands)
// Fill in all missing expands
if (leftOverExpands.length) {
buffer += leftOverExpands.map(p => `${JSON.stringify(p)}:${JSON.stringify(level.expands[p])}`).join(',')
if (level.suffix === '}') {
const leftOverExpands = Object.keys(level.expands)
// Fill in all missing expands
if (leftOverExpands.length) {
buffer += (level.hasProperties ? ',' : '') + leftOverExpands.map(p => `${JSON.stringify(p)}:${JSON.stringify(level.expands[p])}`).join(',')
}
}
if (level.suffix) buffer += level.suffix
}
Expand Down
30 changes: 20 additions & 10 deletions hana/lib/drivers/hdb.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ class HDBDriver extends driver {
const ret = await super.prepare(sql)
ret.stream = async (values, one) => {
const stmt = await ret._prep
const rs = await prom(stmt, 'execute')(values)
const rs = await prom(stmt, 'execute')(values || [])
const cols = rs.metadata
// If the query only returns a single row with a single blob it is the final stream
if (cols.length === 1 && cols[0].length === -1) {
Expand Down Expand Up @@ -129,6 +129,10 @@ async function* rsIterator(rs, one) {
this.reading = 0
this.writing = 0
})
.catch(e => {

Check warning on line 132 in hana/lib/drivers/hdb.js

View workflow job for this annotation

GitHub Actions / HANA Node.js 18

'e' is defined but never used. Allowed unused args must match /lazy/u

Check warning on line 132 in hana/lib/drivers/hdb.js

View workflow job for this annotation

GitHub Actions / Node.js 18

'e' is defined but never used. Allowed unused args must match /lazy/u
// TODO: check whether the error is early close
return true
})
}
},
ensure(size) {
Expand Down Expand Up @@ -251,8 +255,9 @@ async function* rsIterator(rs, one) {

state.inject(handleLevel(levels, path, expands))

// REVISIT: allow streaming with both NVARCHAR and NCLOB
// Read and write JSON blob data
const jsonLength = readBlob(state)
const jsonLength = readString(state, true)
let hasProperties = (typeof jsonLength === 'number' ? jsonLength : await jsonLength) > 2

for (const blobColumn of nativeBlobs) {
Expand Down Expand Up @@ -304,9 +309,9 @@ async function* rsIterator(rs, one) {
rs.close()
}

const readString = function (state) {
const readString = function (state, isJson = false) {
let ens = state.ensure(1)
if (ens) return ens.then(() => readString(state))
if (ens) return ens.then(() => readString(state, isJson))

let length = state.buffer[state.reading]
let offset = 1
Expand All @@ -315,21 +320,26 @@ const readString = function (state) {
throw new Error('Missing stream metadata')
case 0xf6:
ens = state.ensure(2)
if (ens) return ens.then(() => readString(state))
length = state.buffer.readInt16LE(state.reading)
offset = 2
if (ens) return ens.then(() => readString(state, isJson))
length = state.buffer.readInt16LE(state.reading + offset)
offset += 2
break
case 0xf7:
ens = state.ensure(4)
if (ens) return ens.then(() => readString(state))
length = state.buffer.readInt32LE(state.reading)
offset = 4
if (ens) return ens.then(() => readString(state, isJson))
length = state.buffer.readInt32LE(state.reading + offset)
offset += 4
break
default:
}

// Read the string value
state.read(offset)
if (isJson) {
state.write(length - 1)
state.read(1)
return length
}
return state.slice(length)
}

Expand Down

0 comments on commit 7d8521a

Please sign in to comment.