Now really safe wrappers for queries executing

This commit is contained in:
Andrew Golovashevich 2025-02-25 01:24:32 +03:00
parent e1e014cd1d
commit b6bc3c1214
5 changed files with 324 additions and 278 deletions

View File

@ -5,25 +5,99 @@ package ru.landgrafhomyak.db.serdha0.user_commons.executors
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
import kotlin.jvm.JvmName
import ru.landgrafhomyak.db.serdha0.api.LowLevelApi
import ru.landgrafhomyak.db.serdha0.api.runtime.InputRow
import ru.landgrafhomyak.db.serdha0.api.runtime.OutputRow
@Suppress("FunctionName")
@PublishedApi
internal inline fun <R> _safeAutoClose(onAbort: () -> Unit = {}, action: () -> R): R {
internal inline fun <R> _safeAutoClose(onAbort: () -> Unit = {}, onSuccess: () -> Unit = {}, action: () -> R): R {
contract {
callsInPlace(action, InvocationKind.EXACTLY_ONCE)
callsInPlace(onAbort, InvocationKind.AT_MOST_ONCE)
callsInPlace(onSuccess, InvocationKind.EXACTLY_ONCE)
}
val ret: R
var wasError = false
try {
ret = action()
} catch (e1: Throwable) {
wasError = true
try {
onAbort()
} catch (e2: Throwable) {
e1.addSuppressed(e2)
}
throw e1
} finally {
if (!wasError)
onSuccess()
}
return ret
}
@Suppress("ClassName")
public class _ReturnFromInputError : Error("Returning from outer function from input row initializer block is undefined behaviour")
@Suppress("FunctionName", "REDUNDANT_INLINE_SUSPEND_FUNCTION_TYPE")
@LowLevelApi
public suspend inline fun <I : InputRow._Scope<*, O>, O : OutputRow._Iterator<*, Unit>> _safeAutoClose_IO(
iRow: I,
inputAction: suspend (I) -> Unit,
outputAction: suspend (O) -> Unit,
) {
contract {
callsInPlace(inputAction, InvocationKind.EXACTLY_ONCE)
callsInPlace(outputAction, InvocationKind.EXACTLY_ONCE)
}
var crossReturned = true
_safeAutoClose(
onAbort = { iRow._abort() },
action = { inputAction(iRow); crossReturned = false },
onSuccess = {
if (crossReturned) throw _ReturnFromInputError()
val oRow = iRow._finish()
_safeAutoClose(
onAbort = { oRow._abort() },
action = { outputAction(oRow) },
onSuccess = { oRow._finish() }
)
}
)
}
@Suppress("FunctionName", "REDUNDANT_INLINE_SUSPEND_FUNCTION_TYPE")
@LowLevelApi
public suspend inline fun <I : InputRow._Scope<*, Unit>> _safeAutoClose_I(
iRow: I,
inputAction: suspend (I) -> Unit,
) {
contract {
callsInPlace(inputAction, InvocationKind.EXACTLY_ONCE)
}
_safeAutoClose(
onAbort = { iRow._abort() },
action = { inputAction(iRow) },
onSuccess = { iRow._finish() }
)
}
@Suppress("FunctionName", "REDUNDANT_INLINE_SUSPEND_FUNCTION_TYPE")
@LowLevelApi
public suspend inline fun <O : OutputRow._Iterator<*, Unit>> _safeAutoClose_O(
oRow: O,
outputAction: suspend (O) -> Unit,
) {
contract {
callsInPlace(outputAction, InvocationKind.EXACTLY_ONCE)
}
_safeAutoClose(
onAbort = { oRow._abort() },
action = { outputAction(oRow) },
onSuccess = { oRow._finish() }
)
}
public fun test() {
}

View File

@ -17,38 +17,35 @@ public suspend inline fun <qUE : Any, R> Transaction.selectExactlyOneOrError(
params: RowProducer0<qUE>,
result: RowConsumer0<qUE, R>
): R {
val iRow = this._executeQuery(compiledQuery)
_safeAutoClose(onAbort = { iRow._abort() }) {
params.initializeRow(iRow)
}
val oRow = iRow._finish()
val ret: R
_safeAutoClose(onAbort = { oRow._abort() }) {
_safeAutoClose_IO(
iRow = this._executeQuery(compiledQuery),
inputAction = params::initializeRow,
outputAction = { oRow ->
if (!oRow._next())
throw ExpectedOneRowException()
ret = result.transformRow(oRow)
val ret = result.transformRow(oRow)
if (oRow._next())
throw TooManyRowsException()
}
oRow._finish()
return ret
}
)
}
public suspend inline fun <qUE : Any, R> Transaction.selectExactlyOneOrError(
compiledQuery: _Query.Void2Table<qUE>,
result: RowConsumer0<qUE, R>
): R {
val oRow = this._executeQuery(compiledQuery)
val ret: R
_safeAutoClose(onAbort = { oRow._abort() }) {
_safeAutoClose_O(
oRow = this._executeQuery(compiledQuery),
outputAction = { oRow ->
if (!oRow._next())
throw ExpectedOneRowException()
ret = result.transformRow(oRow)
val ret = result.transformRow(oRow)
if (oRow._next())
throw TooManyRowsException()
}
oRow._finish()
return ret
}
)
}
public suspend inline fun <qUE : Any, R> Transaction.selectExactlyOneOrNull(
@ -56,76 +53,65 @@ public suspend inline fun <qUE : Any, R> Transaction.selectExactlyOneOrNull(
params: RowProducer0<qUE>,
result: RowConsumer0<qUE, R>
): R? {
val iRow = this._executeQuery(compiledQuery)
_safeAutoClose(onAbort = { iRow._abort() }) {
params.initializeRow(iRow)
}
val oRow = iRow._finish()
val ret: R?
_safeAutoClose(onAbort = { oRow._abort() }) {
if (!oRow._next()) {
ret = null
return@_safeAutoClose
}
ret = result.transformRow(oRow)
_safeAutoClose_IO(
iRow = this._executeQuery(compiledQuery),
inputAction = params::initializeRow,
outputAction = { oRow ->
if (!oRow._next())
return null
val ret = result.transformRow(oRow)
if (oRow._next())
throw TooManyRowsException()
}
oRow._finish()
return ret
}
)
}
public suspend inline fun <qUE : Any, R> Transaction.selectExactlyOneOrNull(
compiledQuery: _Query.Void2Table<qUE>,
result: RowConsumer0<qUE, R>
): R? {
val oRow = this._executeQuery(compiledQuery)
val ret: R?
_safeAutoClose(onAbort = { oRow._abort() }) {
if (!oRow._next()) {
ret = null
return@_safeAutoClose
}
ret = result.transformRow(oRow)
_safeAutoClose_O(
oRow = this._executeQuery(compiledQuery),
outputAction = { oRow ->
if (!oRow._next())
return null
val ret = result.transformRow(oRow)
if (oRow._next())
throw TooManyRowsException()
}
oRow._finish()
return ret
}
)
}
public suspend inline fun <qUE : Any, R> Transaction.selectFirstOrError(
compiledQuery: _Query.Params2Table<qUE>,
params: RowProducer0<qUE>,
result: RowConsumer0<qUE, R>
): R {
val iRow = this._executeQuery(compiledQuery)
_safeAutoClose(onAbort = { iRow._abort() }) {
params.initializeRow(iRow)
}
val oRow = iRow._finish()
val ret: R
_safeAutoClose(onAbort = { oRow._abort() }) {
_safeAutoClose_IO(
iRow = this._executeQuery(compiledQuery),
inputAction = params::initializeRow,
outputAction = { oRow ->
if (!oRow._next())
throw ExpectedOneRowException()
ret = result.transformRow(oRow)
return result.transformRow(oRow)
}
oRow._finish()
return ret
)
}
public suspend inline fun <qUE : Any, R> Transaction.selectFirstOrError(
compiledQuery: _Query.Void2Table<qUE>,
result: RowConsumer0<qUE, R>
): R {
val oRow = this._executeQuery(compiledQuery)
val ret: R
_safeAutoClose(onAbort = { oRow._abort() }) {
_safeAutoClose_O(
oRow = this._executeQuery(compiledQuery),
outputAction = { oRow ->
if (!oRow._next())
throw ExpectedOneRowException()
ret = result.transformRow(oRow)
return result.transformRow(oRow)
}
oRow._finish()
return ret
)
}
public suspend inline fun <qUE : Any, R> Transaction.selectFirstOrNull(
@ -133,36 +119,27 @@ public suspend inline fun <qUE : Any, R> Transaction.selectFirstOrNull(
params: RowProducer0<qUE>,
result: RowConsumer0<qUE, R>
): R? {
val iRow = this._executeQuery(compiledQuery)
_safeAutoClose(onAbort = { iRow._abort() }) {
params.initializeRow(iRow)
_safeAutoClose_IO(
iRow = this._executeQuery(compiledQuery),
inputAction = params::initializeRow,
outputAction = { oRow ->
if (!oRow._next())
return null
return result.transformRow(oRow)
}
val oRow = iRow._finish()
val ret: R?
_safeAutoClose(onAbort = { oRow._abort() }) {
if (!oRow._next()) {
ret = null
return@_safeAutoClose
}
ret = result.transformRow(oRow)
}
oRow._finish()
return ret
)
}
public suspend inline fun <qUE : Any, R> Transaction.selectFirstOrNull(
compiledQuery: _Query.Void2Table<qUE>,
result: RowConsumer0<qUE, R>
): R? {
val oRow = this._executeQuery(compiledQuery)
val ret: R?
_safeAutoClose(onAbort = { oRow._abort() }) {
if (!oRow._next()) {
ret = null
return@_safeAutoClose
_safeAutoClose_O(
oRow = this._executeQuery(compiledQuery),
outputAction = { oRow ->
if (!oRow._next())
return null
return result.transformRow(oRow)
}
ret = result.transformRow(oRow)
}
oRow._finish()
return ret
)
}

View File

@ -14,28 +14,27 @@ public suspend inline fun <qUE : Any> Transaction.select(
params: RowProducer0<qUE>,
transform: RowConsumer0<qUE, Unit>
) {
val iRow = this._executeQuery(compiledQuery)
_safeAutoClose(onAbort = { iRow._abort() }) {
params.initializeRow(iRow)
}
val oRow = iRow._finish()
_safeAutoClose(onAbort = { oRow._abort() }) {
_safeAutoClose_IO(
iRow = this._executeQuery(compiledQuery),
inputAction = params::initializeRow,
outputAction = { oRow ->
while (oRow._next())
transform.transformRow(oRow)
}
oRow._finish()
)
}
public suspend inline fun <qUE : Any> Transaction.select(
compiledQuery: _Query.Void2Table<qUE>,
transform: RowConsumer0<qUE, Unit>
) {
val oRow = this._executeQuery(compiledQuery)
_safeAutoClose(onAbort = { oRow._abort() }) {
_safeAutoClose_O(
oRow = this._executeQuery(compiledQuery),
outputAction = { oRow ->
while (oRow._next())
transform.transformRow(oRow)
}
oRow._finish()
)
}
public suspend inline fun <qUE : Any, E> Transaction.mapRows(
@ -43,32 +42,31 @@ public suspend inline fun <qUE : Any, E> Transaction.mapRows(
params: RowProducer0<qUE>,
transform: RowConsumer0<qUE, E>
): List<E> {
val iRow = this._executeQuery(compiledQuery)
_safeAutoClose(onAbort = { iRow._abort() }) {
params.initializeRow(iRow)
}
val oRow = iRow._finish()
val out = ArrayList<E>()
_safeAutoClose(onAbort = { oRow._abort() }) {
_safeAutoClose_IO(
iRow = this._executeQuery(compiledQuery),
inputAction = params::initializeRow,
outputAction = { oRow ->
val dst = ArrayList<E>()
while (oRow._next())
out.add(transform.transformRow(oRow))
dst.add(transform.transformRow(oRow))
return dst
}
oRow._finish()
return out
)
}
public suspend inline fun <qUE : Any, E> Transaction.mapRows(
compiledQuery: _Query.Void2Table<qUE>,
transform: RowConsumer0<qUE, E>
): List<E> {
val oRow = this._executeQuery(compiledQuery)
val out = ArrayList<E>()
_safeAutoClose(onAbort = { oRow._abort() }) {
_safeAutoClose_O(
oRow = this._executeQuery(compiledQuery),
outputAction = { oRow ->
val dst = ArrayList<E>()
while (oRow._next())
out.add(transform.transformRow(oRow))
dst.add(transform.transformRow(oRow))
return dst
}
oRow._finish()
return out
)
}
public suspend inline fun <qUE : Any, E> Transaction.mapRowsIndexed(
@ -77,19 +75,17 @@ public suspend inline fun <qUE : Any, E> Transaction.mapRowsIndexed(
firstIndex: Int = 0,
transform: RowConsumer1<qUE, E>
): List<E> {
val iRow = this._executeQuery(compiledQuery)
_safeAutoClose(onAbort = { iRow._abort() }) {
params.initializeRow(iRow)
}
val oRow = iRow._finish()
val out = ArrayList<E>()
_safeAutoClose(onAbort = { oRow._abort() }) {
_safeAutoClose_IO(
iRow = this._executeQuery(compiledQuery),
inputAction = params::initializeRow,
outputAction = { oRow ->
val dst = ArrayList<E>()
var i = firstIndex
while (oRow._next())
out.add(transform.transformRow(oRow, i++))
dst.add(transform.transformRow(oRow, i++))
return dst
}
oRow._finish()
return out
)
}
public suspend inline fun <qUE : Any, E> Transaction.mapRowsIndexed(
@ -97,15 +93,16 @@ public suspend inline fun <qUE : Any, E> Transaction.mapRowsIndexed(
firstIndex: Int = 0,
transform: RowConsumer1<qUE, E>
): List<E> {
val oRow = this._executeQuery(compiledQuery)
val out = ArrayList<E>()
_safeAutoClose(onAbort = { oRow._abort() }) {
_safeAutoClose_O(
oRow = this._executeQuery(compiledQuery),
outputAction = { oRow ->
val dst = ArrayList<E>()
var i = firstIndex
while (oRow._next())
out.add(transform.transformRow(oRow, i++))
dst.add(transform.transformRow(oRow, i++))
return dst
}
oRow._finish()
return out
)
}
public suspend inline fun <qUE : Any, E, C : MutableCollection<E>> Transaction.mapRowsTo(
@ -114,17 +111,15 @@ public suspend inline fun <qUE : Any, E, C : MutableCollection<E>> Transaction.m
dst: C,
transform: RowConsumer0<qUE, E>
): C {
val iRow = this._executeQuery(compiledQuery)
_safeAutoClose(onAbort = { iRow._abort() }) {
params.initializeRow(iRow)
}
val oRow = iRow._finish()
_safeAutoClose(onAbort = { oRow._abort() }) {
_safeAutoClose_IO(
iRow = this._executeQuery(compiledQuery),
inputAction = params::initializeRow,
outputAction = { oRow ->
while (oRow._next())
dst.add(transform.transformRow(oRow))
}
oRow._finish()
return dst
}
)
}
public suspend inline fun <qUE : Any, E, C : MutableCollection<E>> Transaction.mapRowsTo(
@ -132,13 +127,14 @@ public suspend inline fun <qUE : Any, E, C : MutableCollection<E>> Transaction.m
dst: C,
transform: RowConsumer0<qUE, E>
): C {
val oRow = this._executeQuery(compiledQuery)
_safeAutoClose(onAbort = { oRow._abort() }) {
_safeAutoClose_O(
oRow = this._executeQuery(compiledQuery),
outputAction = { oRow ->
while (oRow._next())
dst.add(transform.transformRow(oRow))
}
oRow._finish()
return dst
}
)
}
public suspend inline fun <qUE : Any, E, C : MutableCollection<E>> Transaction.mapRowsIndexedTo(
@ -147,18 +143,16 @@ public suspend inline fun <qUE : Any, E, C : MutableCollection<E>> Transaction.m
dst: C, firstIndex: Int = 0,
transform: RowConsumer1<qUE, E>
): C {
val iRow = this._executeQuery(compiledQuery)
_safeAutoClose(onAbort = { iRow._abort() }) {
params.initializeRow(iRow)
}
val oRow = iRow._finish()
_safeAutoClose(onAbort = { oRow._abort() }) {
_safeAutoClose_IO(
iRow = this._executeQuery(compiledQuery),
inputAction = params::initializeRow,
outputAction = { oRow ->
var i = firstIndex
while (oRow._next())
dst.add(transform.transformRow(oRow, i++))
}
oRow._finish()
return dst
}
)
}
public suspend inline fun <qUE : Any, E, C : MutableCollection<E>> Transaction.mapRowsIndexedTo(
@ -166,14 +160,15 @@ public suspend inline fun <qUE : Any, E, C : MutableCollection<E>> Transaction.m
dst: C, firstIndex: Int = 0,
transform: RowConsumer1<qUE, E>
): C {
val oRow = this._executeQuery(compiledQuery)
_safeAutoClose(onAbort = { oRow._abort() }) {
_safeAutoClose_O(
oRow = this._executeQuery(compiledQuery),
outputAction = { oRow ->
var i = firstIndex
while (oRow._next())
dst.add(transform.transformRow(oRow, i++))
}
oRow._finish()
return dst
}
)
}
public suspend inline fun <qUE : Any, E> Transaction.mapRowsTo(
@ -182,18 +177,16 @@ public suspend inline fun <qUE : Any, E> Transaction.mapRowsTo(
dst: Array<E>, dstOffset: Int = 0,
transform: RowConsumer0<qUE, E>
): Array<E> {
val iRow = this._executeQuery(compiledQuery)
_safeAutoClose(onAbort = { iRow._abort() }) {
params.initializeRow(iRow)
}
val oRow = iRow._finish()
_safeAutoClose(onAbort = { oRow._abort() }) {
_safeAutoClose_IO(
iRow = this._executeQuery(compiledQuery),
inputAction = params::initializeRow,
outputAction = { oRow ->
var i = dstOffset
while (oRow._next())
dst[i++] = transform.transformRow(oRow)
}
oRow._finish()
return dst
}
)
}
public suspend inline fun <qUE : Any, E> Transaction.mapRowsTo(
@ -201,12 +194,13 @@ public suspend inline fun <qUE : Any, E> Transaction.mapRowsTo(
dst: Array<E>, dstOffset: Int = 0,
transform: RowConsumer0<qUE, E>
): Array<E> {
val oRow = this._executeQuery(compiledQuery)
_safeAutoClose(onAbort = { oRow._abort() }) {
_safeAutoClose_O(
oRow = this._executeQuery(compiledQuery),
outputAction = { oRow ->
var i = dstOffset
while (oRow._next())
dst[i++] = transform.transformRow(oRow)
}
oRow._finish()
return dst
}
)
}

View File

@ -13,20 +13,19 @@ public suspend inline fun <qUE : Any> Transaction.executeWithParams(
compiledQuery: _Query.Params2Void<qUE>,
params: RowProducer0<qUE>
) {
val iRow = this._executeQuery(compiledQuery)
_safeAutoClose(onAbort = { iRow._abort() }) {
params.initializeRow(iRow)
}
iRow._finish()
_safeAutoClose_I(
iRow = this._executeQuery(compiledQuery),
inputAction = params::initializeRow
)
}
public suspend inline fun <qUE : Any> Transaction.executeWithParams(
compiledQuery: _Query.Params2Table<qUE>,
params: RowProducer0<qUE>
) {
val iRow = this._executeQuery(compiledQuery)
_safeAutoClose(onAbort = { iRow._abort() }) {
params.initializeRow(iRow)
}
iRow._finish()._finish()
_safeAutoClose_IO(
iRow = this._executeQuery(compiledQuery),
inputAction = params::initializeRow,
outputAction = {}
)
}

View File

@ -4,7 +4,6 @@
package ru.landgrafhomyak.db.serdha0.user_commons.executors
import kotlin.contracts.contract
import kotlin.jvm.JvmName
import ru.landgrafhomyak.db.serdha0.api.LowLevelApi
import ru.landgrafhomyak.db.serdha0.api.queries._Query
@ -15,14 +14,15 @@ public suspend inline fun <qUE : Any, E> Transaction.mapToRows(
collection: Iterable<E>,
transform: RowProducer1<qUE, E>
) {
val iRow = this._executeQuery(compiledQuery)
_safeAutoClose(onAbort = { iRow._abort() }) {
_safeAutoClose_I(
iRow = this._executeQuery(compiledQuery),
inputAction = { iRow ->
for (elem in collection) {
iRow._next()
transform.transformToRow(iRow, elem)
}
}
iRow._finish()
)
}
public suspend inline fun <qUE : Any, E> Transaction.mapToRowsIndexed(
@ -31,16 +31,16 @@ public suspend inline fun <qUE : Any, E> Transaction.mapToRowsIndexed(
firstIndex: Int = 0,
transform: RowProducer2<qUE, E>
) {
val iRow = this._executeQuery(compiledQuery)
_safeAutoClose_I(
iRow = this._executeQuery(compiledQuery),
inputAction = { iRow ->
var index = firstIndex
_safeAutoClose(onAbort = { iRow._abort() }) {
for (elem in collection) {
iRow._next()
transform.transformToRow(iRow, index, elem)
index++
transform.transformToRow(iRow, index++, elem)
}
}
iRow._finish()
)
}
public suspend inline fun <qUE : Any, E> Transaction.mapToRows(
@ -48,14 +48,15 @@ public suspend inline fun <qUE : Any, E> Transaction.mapToRows(
sequence: Sequence<E>,
transform: RowProducer1<qUE, E>
) {
val iRow = this._executeQuery(compiledQuery)
_safeAutoClose(onAbort = { iRow._abort() }) {
_safeAutoClose_I(
iRow = this._executeQuery(compiledQuery),
inputAction = { iRow ->
for (elem in sequence) {
iRow._next()
transform.transformToRow(iRow, elem)
}
}
iRow._finish()
)
}
public suspend inline fun <qUE : Any, E> Transaction.mapToRowsIndexed(
@ -64,47 +65,48 @@ public suspend inline fun <qUE : Any, E> Transaction.mapToRowsIndexed(
firstIndex: Int = 0,
transform: RowProducer2<qUE, E>
) {
val iRow = this._executeQuery(compiledQuery)
_safeAutoClose_I(
iRow = this._executeQuery(compiledQuery),
inputAction = { iRow ->
var index = firstIndex
_safeAutoClose(onAbort = { iRow._abort() }) {
for (elem in sequence) {
iRow._next()
transform.transformToRow(iRow, index, elem)
index++
transform.transformToRow(iRow, index++, elem)
}
}
iRow._finish()
)
}
public suspend inline fun <qUE : Any, E> Transaction.mapToRows(
compiledQuery: _Query.Table2Void<qUE>,
sequence: Array<E>,
array: Array<E>,
transform: RowProducer1<qUE, E>
) {
val iRow = this._executeQuery(compiledQuery)
_safeAutoClose(onAbort = { iRow._abort() }) {
for (elem in sequence) {
_safeAutoClose_I(
iRow = this._executeQuery(compiledQuery),
inputAction = { iRow ->
for (elem in array) {
iRow._next()
transform.transformToRow(iRow, elem)
}
}
iRow._finish()
)
}
public suspend inline fun <qUE : Any, E> Transaction.mapToRowsIndexed(
compiledQuery: _Query.Table2Void<qUE>,
sequence: Array<E>,
array: Array<E>,
firstIndex: Int = 0,
transform: RowProducer2<qUE, E>
) {
val iRow = this._executeQuery(compiledQuery)
_safeAutoClose_I(
iRow = this._executeQuery(compiledQuery),
inputAction = { iRow ->
var index = firstIndex
_safeAutoClose(onAbort = { iRow._abort() }) {
for (elem in sequence) {
for (elem in array) {
iRow._next()
transform.transformToRow(iRow, index, elem)
index++
transform.transformToRow(iRow, index++, elem)
}
}
iRow._finish()
)
}