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

Add PlannerPipeline #590

Merged
merged 15 commits into from
May 24, 2022
Merged
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
14 changes: 8 additions & 6 deletions lang/src/org/partiql/lang/SqlException.kt
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,10 @@ import org.partiql.lang.util.propertyValueMapOf
*
* @param message the message for this exception
* @param errorCode the error code for this exception
* @param errorContextArg context for this error, contains details like line & column number among other attributes.
* @param errorContext context for this error, includes details like line & character offsets, among others.
* @param internal True to indicate that this exception a bug in ParitQL itself. False to indicate it was caused by
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit.: is a bug.

* incorrect usage of APIs or invalid end-user queries.
* @param cause for this exception
*
* @constructor a custom error [message], the [errorCode], error context as a [propertyValueMap] and optional [cause] creates an
* [SqlException]. This is the constructor for the second configuration explained above.
*
*/
open class SqlException(
override var message: String,
Expand Down Expand Up @@ -83,7 +81,7 @@ open class SqlException(
*
* * ErrorCategory is one of `Lexer Error`, `Parser Error`, `Runtime Error`
* * ErrorLocation is the line and column where the error occurred
* * Errormessatge is the **generated** error message
* * ErrorMessage is the **generated** error message
*
*
* TODO: Prepend to the auto-generated message the file name.
Expand All @@ -92,6 +90,10 @@ open class SqlException(
fun generateMessage(): String =
"${errorCategory(errorCode)}: ${errorLocation(errorContext)}: ${errorMessage(errorCode, errorContext)}"

/** Same as [generateMessage] but without the location. */
fun generateMessageNoLocation(): String =
"${errorCategory(errorCode)}: ${errorMessage(errorCode, errorContext)}"

private fun errorMessage(errorCode: ErrorCode?, propertyValueMap: PropertyValueMap?): String =
errorCode?.getErrorMessage(propertyValueMap) ?: UNKNOWN

Expand Down
85 changes: 85 additions & 0 deletions lang/src/org/partiql/lang/planner/EvaluatorOptions.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package org.partiql.lang.planner

import org.partiql.lang.eval.ProjectionIterationBehavior
import org.partiql.lang.eval.ThunkOptions
import org.partiql.lang.eval.TypedOpBehavior
import org.partiql.lang.eval.TypingMode
import java.time.ZoneOffset

/*

Differences between CompilerOptions and EvaluatorOptions:

- There is no EvaluatorOptions equivalent for CompileOptions.visitorTransformMode since the planner always runs some basic
normalization and variable resolution passes *before* the customer can inject their own transforms.
- There is no EvaluatorOptions equivalent for CompileOptions.thunkReturnTypeAssertions since PlannerPipeline does not
support the static type inferencer (yet).
- EvaluatorOptions.allowUndefinedVariables is new.
- EvaluatorOptions has no equivalent for CompileOptions.undefinedVariableBehavior -- this was added for backward
compatibility on behalf of a customer we don't have anymore. Internal bug number is IONSQL-134.
*/

/**
* Specifies options that effect the behavior of the PartiQL physical plan evaluator.
*
* @param defaultTimezoneOffset Default timezone offset to be used when TIME WITH TIME ZONE does not explicitly
* specify the time zone. Defaults to [ZoneOffset.UTC].
*/
@Suppress("DataClassPrivateConstructor")
data class EvaluatorOptions private constructor (
val projectionIteration: ProjectionIterationBehavior = ProjectionIterationBehavior.FILTER_MISSING,
val thunkOptions: ThunkOptions = ThunkOptions.standard(),
val typingMode: TypingMode = TypingMode.LEGACY,
val typedOpBehavior: TypedOpBehavior = TypedOpBehavior.LEGACY,
val defaultTimezoneOffset: ZoneOffset = ZoneOffset.UTC
) {
companion object {

/**
* Creates a java style builder that will choose the default values for any unspecified options.
*/
@JvmStatic
fun builder() = Builder()

/**
* Creates a java style builder that will clone the [EvaluatorOptions] passed to the constructor.
*/
@JvmStatic
fun builder(options: EvaluatorOptions) = Builder(options)

/**
* Kotlin style builder that will choose the default values for any unspecified options.
*/
fun build(block: Builder.() -> Unit) = Builder().apply(block).build()

/**
* Kotlin style builder that will clone the [EvaluatorOptions] passed to the constructor.
*/
fun build(options: EvaluatorOptions, block: Builder.() -> Unit) = Builder(options).apply(block).build()

/**
* Creates a [EvaluatorOptions] instance with the standard values for use by the legacy AST compiler.
*/
@JvmStatic
fun standard() = Builder().build()
}

/**
* Builds a [EvaluatorOptions] instance.
*/
class Builder(private var options: EvaluatorOptions = EvaluatorOptions()) {

fun projectionIteration(value: ProjectionIterationBehavior) = set { copy(projectionIteration = value) }
fun typingMode(value: TypingMode) = set { copy(typingMode = value) }
fun typedOpBehavior(value: TypedOpBehavior) = set { copy(typedOpBehavior = value) }
fun thunkOptions(value: ThunkOptions) = set { copy(thunkOptions = value) }
fun defaultTimezoneOffset(value: ZoneOffset) = set { copy(defaultTimezoneOffset = value) }

private inline fun set(block: EvaluatorOptions.() -> EvaluatorOptions): Builder {
options = block(options)
return this
}

fun build() = options
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ sealed class ResolutionResult {
/**
* A success case, indicates the [uniqueId] of the match to the [BindingName] in the global scope.
* Typically, this is defined by the storage layer.
*
* In the future, this will likely contain much more than just a unique id. It might include detailed schema
* information about global variables.
*/
data class GlobalVariable(val uniqueId: String) : ResolutionResult()

Expand All @@ -22,9 +25,19 @@ sealed class ResolutionResult {
object Undefined : ResolutionResult()
}

fun interface UniqueIdResolver {
/**
* Supplies the query planner with metadata about the current database. Meant to be implemented by the application
* embedding PartiQL.
*
* Metadata is associated with global variables. Global variables can be tables or (less commonly) any other
* application specific global variable.
*
* In the future, new methods could be added which expose information about other types of database metadata such as
* available indexes and table statistics.
*/
interface MetadataResolver {
/**
* Implementations try to resolve a global variable which is typically a database table to a unique identifier
* Implementations try to resolve a variable which is typically a database table to a schema
* using [bindingName]. [bindingName] includes both the name as specified by the query author and a [BindingCase]
* which indicates if query author included double quotes (") which mean the lookup should be case-sensitive.
*
Expand All @@ -41,10 +54,12 @@ fun interface UniqueIdResolver {
* Note that while [ResolutionResult.LocalVariable] exists, it is intentionally marked `internal` and cannot
* be used by outside this project.
*/
fun resolve(bindingName: BindingName): ResolutionResult
fun resolveVariable(bindingName: BindingName): ResolutionResult
}

private val EMPTY = UniqueIdResolver { ResolutionResult.Undefined }
private val EMPTY: MetadataResolver = object : MetadataResolver {
override fun resolveVariable(bindingName: BindingName): ResolutionResult = ResolutionResult.Undefined
}

/** Convenience function for obtaining an instance of [UniqueIdResolver] with no defined variables. */
fun emptyUniqueIdResolver(): UniqueIdResolver = EMPTY
/** Convenience function for obtaining an instance of [MetadataResolver] with no defined variables. */
fun emptyMetadataResolver(): MetadataResolver = EMPTY
Loading