diff --git a/lang/src/org/partiql/lang/eval/CompileOptions.kt b/lang/src/org/partiql/lang/eval/CompileOptions.kt index 84b7e1edb..78d77940c 100644 --- a/lang/src/org/partiql/lang/eval/CompileOptions.kt +++ b/lang/src/org/partiql/lang/eval/CompileOptions.kt @@ -59,12 +59,18 @@ enum class VisitorTransformMode { /** * Specifies options that effect the behavior of the PartiQL compiler. + * @property interruptible specifies whether the compilation and execution of the compiled statement is interruptible. If + * set to true, the compilation and execution of statements will check [Thread.interrupted] frequently. If set to + * false, the compilation and execution of statements is not guaranteed to be interruptible. It *may* still be interrupted, + * however, it is not guaranteed. The default is false. */ data class CompileOptions private constructor ( val undefinedVariable: UndefinedVariableBehavior, val projectionIteration: ProjectionIterationBehavior = ProjectionIterationBehavior.FILTER_MISSING, val visitorTransformMode: VisitorTransformMode = VisitorTransformMode.DEFAULT, - val thunkOptions: ThunkOptions = ThunkOptions.standard() + val thunkOptions: ThunkOptions = ThunkOptions.standard(), + @Deprecated("This will be removed in v0.3.0. However, this is re-added in v0.13.1.", level = DeprecationLevel.WARNING) + val interruptible: Boolean = false ) { companion object { @@ -97,6 +103,10 @@ data class CompileOptions private constructor ( fun projectionIteration(value: ProjectionIterationBehavior) = set { copy(projectionIteration = value) } fun visitorTransformMode(value: VisitorTransformMode) = set { copy(visitorTransformMode = value) } fun thunkOptions(value: ThunkOptions) = set { copy(thunkOptions = value)} + + @Deprecated("This will be removed in v0.3.0. However, this is re-added in v0.13.1.", level = DeprecationLevel.WARNING) + fun isInterruptible(value: Boolean) = set { copy(interruptible = value) } + private inline fun set(block: CompileOptions.() -> CompileOptions) : Builder { options = block(options) return this diff --git a/lang/src/org/partiql/lang/eval/EvaluatingCompiler.kt b/lang/src/org/partiql/lang/eval/EvaluatingCompiler.kt index 1f1cafbc2..5d6df809d 100644 --- a/lang/src/org/partiql/lang/eval/EvaluatingCompiler.kt +++ b/lang/src/org/partiql/lang/eval/EvaluatingCompiler.kt @@ -77,10 +77,13 @@ internal class EvaluatingCompiler( * [CompileOptions.interruptible], the invocation of this function will insert a Thread interruption check. If not * specified, it will not perform the check during compilation/evaluation/materialization. */ - private val interruptionCheck: () -> Unit = { + private val interruptionCheck: () -> Unit = when (compileOptions.interruptible) { + true -> { -> if (Thread.interrupted()) { throw InterruptedException() } + } + false -> { -> Unit } } //Note: please don't make this inline -- it messes up [EvaluationException] stack traces and diff --git a/lang/test/org/partiql/lang/eval/EvaluatingCompilerInterruptTests.kt b/lang/test/org/partiql/lang/eval/EvaluatingCompilerInterruptTests.kt index 117d4119d..c5aee4cb8 100644 --- a/lang/test/org/partiql/lang/eval/EvaluatingCompilerInterruptTests.kt +++ b/lang/test/org/partiql/lang/eval/EvaluatingCompilerInterruptTests.kt @@ -29,7 +29,8 @@ class EvaluatingCompilerInterruptTests { private val ion = IonSystemBuilder.standard().build() private val factory = ExprValueFactory.standard(ion) private val session = EvaluationSession.standard() - private val pipeline = CompilerPipeline.standard(ion) + private val options = CompileOptions.Builder().isInterruptible(true).build() + private val pipeline = CompilerPipeline.Builder(factory).compileOptions(options).build() companion object { /** How long (in millis) to wait after starting a thread to set the interrupted flag. */