Skip to content

Commit

Permalink
Merge e595358 into 101c19b
Browse files Browse the repository at this point in the history
  • Loading branch information
johnedquinn authored Jan 26, 2024
2 parents 101c19b + e595358 commit 1d0cb4a
Show file tree
Hide file tree
Showing 20 changed files with 845 additions and 62 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ public interface PartiQLEngine {

public class Session @OptIn(PartiQLFunctionExperimental::class) constructor(
val bindings: Map<String, ConnectorBindings> = mapOf(),
val functions: Map<String, List<PartiQLFunction>> = mapOf()
val functions: Map<String, List<PartiQLFunction>> = mapOf(),
val mode: Mode = Mode.PERMISSIVE
)

public enum class Mode {
PERMISSIVE,
STRICT // AKA, Type Checking Mode in the PartiQL Specification
}
}
51 changes: 40 additions & 11 deletions partiql-eval/src/main/kotlin/org/partiql/eval/internal/Compiler.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import org.partiql.eval.internal.operator.rel.RelJoinRight
import org.partiql.eval.internal.operator.rel.RelProject
import org.partiql.eval.internal.operator.rel.RelScan
import org.partiql.eval.internal.operator.rel.RelScanIndexed
import org.partiql.eval.internal.operator.rel.RelScanIndexedPermissive
import org.partiql.eval.internal.operator.rel.RelScanPermissive
import org.partiql.eval.internal.operator.rex.ExprCallDynamic
import org.partiql.eval.internal.operator.rex.ExprCallStatic
import org.partiql.eval.internal.operator.rex.ExprCase
Expand All @@ -20,7 +22,9 @@ import org.partiql.eval.internal.operator.rex.ExprLiteral
import org.partiql.eval.internal.operator.rex.ExprPathIndex
import org.partiql.eval.internal.operator.rex.ExprPathKey
import org.partiql.eval.internal.operator.rex.ExprPathSymbol
import org.partiql.eval.internal.operator.rex.ExprPermissive
import org.partiql.eval.internal.operator.rex.ExprPivot
import org.partiql.eval.internal.operator.rex.ExprPivotPermissive
import org.partiql.eval.internal.operator.rex.ExprSelect
import org.partiql.eval.internal.operator.rex.ExprStruct
import org.partiql.eval.internal.operator.rex.ExprTupleUnion
Expand All @@ -37,6 +41,7 @@ import org.partiql.spi.function.PartiQLFunction
import org.partiql.spi.function.PartiQLFunctionExperimental
import org.partiql.types.function.FunctionSignature
import org.partiql.value.PartiQLValueExperimental
import org.partiql.value.PartiQLValueType
import java.lang.IllegalStateException

internal class Compiler @OptIn(PartiQLFunctionExperimental::class) constructor(
Expand Down Expand Up @@ -71,7 +76,7 @@ internal class Compiler @OptIn(PartiQLFunctionExperimental::class) constructor(

// TODO: Re-look at
override fun visitStatementQuery(node: Statement.Query, ctx: Unit): Operator.Expr {
return visitRex(node.root, ctx)
return visitRex(node.root, ctx).modeHandled()
}

// REX
Expand All @@ -81,27 +86,31 @@ internal class Compiler @OptIn(PartiQLFunctionExperimental::class) constructor(
}

override fun visitRexOpCollection(node: Rex.Op.Collection, ctx: Unit): Operator {
val values = node.values.map { visitRex(it, ctx) }
val values = node.values.map { visitRex(it, ctx).modeHandled() }
return ExprCollection(values)
}
override fun visitRexOpStruct(node: Rex.Op.Struct, ctx: Unit): Operator {
val fields = node.fields.map {
ExprStruct.Field(visitRex(it.k, ctx), visitRex(it.v, ctx))
val value = visitRex(it.v, ctx).modeHandled()
ExprStruct.Field(visitRex(it.k, ctx), value)
}
return ExprStruct(fields)
}

override fun visitRexOpSelect(node: Rex.Op.Select, ctx: Unit): Operator {
val rel = visitRel(node.rel, ctx)
val constructor = visitRex(node.constructor, ctx)
val constructor = visitRex(node.constructor, ctx).modeHandled()
return ExprSelect(rel, constructor)
}

override fun visitRexOpPivot(node: Rex.Op.Pivot, ctx: Unit): Operator {
val rel = visitRel(node.rel, ctx)
val key = visitRex(node.key, ctx)
val value = visitRex(node.value, ctx)
return ExprPivot(rel, key, value)
return when (session.mode) {
PartiQLEngine.Mode.PERMISSIVE -> ExprPivotPermissive(rel, key, value)
PartiQLEngine.Mode.STRICT -> ExprPivot(rel, key, value)
}
}
override fun visitRexOpVar(node: Rex.Op.Var, ctx: Unit): Operator {
return ExprVar(node.ref)
Expand Down Expand Up @@ -133,16 +142,22 @@ internal class Compiler @OptIn(PartiQLFunctionExperimental::class) constructor(
return ExprPathIndex(root, index)
}

@OptIn(PartiQLFunctionExperimental::class)
@OptIn(PartiQLFunctionExperimental::class, PartiQLValueExperimental::class)
override fun visitRexOpCallStatic(node: Rex.Op.Call.Static, ctx: Unit): Operator {
val function = getFunction(node.fn.signature)
val args = node.args.map { visitRex(it, ctx) }.toTypedArray()
return ExprCallStatic(function, args)
val fnTakesInMissing = function.signature.parameters.any {
it.type == PartiQLValueType.MISSING || it.type == PartiQLValueType.ANY
}
return when (fnTakesInMissing) {
true -> ExprCallStatic(function, args.map { it.modeHandled() }.toTypedArray())
false -> ExprCallStatic(function, args)
}
}

@OptIn(PartiQLFunctionExperimental::class, PartiQLValueExperimental::class)
override fun visitRexOpCallDynamic(node: Rex.Op.Call.Dynamic, ctx: Unit): Operator {
val args = node.args.map { visitRex(it, ctx) }.toTypedArray()
val args = node.args.map { visitRex(it, ctx).modeHandled() }.toTypedArray()
val candidates = node.candidates.map { candidate ->
val fn = getFunction(candidate.fn.signature)
val coercions = candidate.coercions.map { it?.signature?.let { sig -> getFunction(sig) } }
Expand Down Expand Up @@ -174,18 +189,24 @@ internal class Compiler @OptIn(PartiQLFunctionExperimental::class) constructor(

override fun visitRelOpScan(node: Rel.Op.Scan, ctx: Unit): Operator {
val rex = visitRex(node.rex, ctx)
return RelScan(rex)
return when (session.mode) {
PartiQLEngine.Mode.PERMISSIVE -> RelScanPermissive(rex)
PartiQLEngine.Mode.STRICT -> RelScan(rex)
}
}

override fun visitRelOpProject(node: Rel.Op.Project, ctx: Unit): Operator {
val input = visitRel(node.input, ctx)
val projections = node.projections.map { visitRex(it, ctx) }
val projections = node.projections.map { visitRex(it, ctx).modeHandled() }
return RelProject(input, projections)
}

override fun visitRelOpScanIndexed(node: Rel.Op.ScanIndexed, ctx: Unit): Operator {
val rex = visitRex(node.rex, ctx)
return RelScanIndexed(rex)
return when (session.mode) {
PartiQLEngine.Mode.PERMISSIVE -> RelScanIndexedPermissive(rex)
PartiQLEngine.Mode.STRICT -> RelScanIndexed(rex)
}
}

override fun visitRexOpTupleUnion(node: Rex.Op.TupleUnion, ctx: Unit): Operator {
Expand Down Expand Up @@ -228,4 +249,12 @@ internal class Compiler @OptIn(PartiQLFunctionExperimental::class) constructor(
val condition = visitRex(node.predicate, ctx)
return RelFilter(input, condition)
}

// HELPERS
private fun Operator.Expr.modeHandled(): Operator.Expr {
return when (session.mode) {
PartiQLEngine.Mode.PERMISSIVE -> ExprPermissive(this)
PartiQLEngine.Mode.STRICT -> this
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.partiql.eval.internal.operator.rel

import org.partiql.errors.TypeCheckException
import org.partiql.eval.internal.Record
import org.partiql.eval.internal.operator.Operator
import org.partiql.value.CollectionValue
Expand All @@ -16,7 +17,10 @@ internal class RelScan(
val r = expr.eval(Record.empty)
records = when (r) {
is CollectionValue<*> -> r.map { Record.of(it) }.iterator()
else -> iterator { yield(Record.of(r)) }
else -> {
close()
throw TypeCheckException()
}
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package org.partiql.eval.internal.operator.rel

import org.partiql.errors.TypeCheckException
import org.partiql.eval.internal.Record
import org.partiql.eval.internal.operator.Operator
import org.partiql.value.BagValue
import org.partiql.value.CollectionValue
import org.partiql.value.PartiQLValue
import org.partiql.value.PartiQLValueExperimental
Expand All @@ -19,8 +21,15 @@ internal class RelScanIndexed(
val r = expr.eval(Record.empty)
index = 0
iterator = when (r) {
is BagValue<*> -> {
close()
throw TypeCheckException()
}
is CollectionValue<*> -> r.iterator()
else -> iterator { yield(r) }
else -> {
close()
throw TypeCheckException()
}
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package org.partiql.eval.internal.operator.rel

import org.partiql.eval.internal.Record
import org.partiql.eval.internal.operator.Operator
import org.partiql.value.BagValue
import org.partiql.value.CollectionValue
import org.partiql.value.PartiQLValue
import org.partiql.value.PartiQLValueExperimental
import org.partiql.value.int64Value
import org.partiql.value.missingValue

@OptIn(PartiQLValueExperimental::class)
internal class RelScanIndexedPermissive(
private val expr: Operator.Expr
) : Operator.Relation {

private lateinit var iterator: Iterator<PartiQLValue>
private var index: Long = 0
private var isIndexable: Boolean = true

override fun open() {
val r = expr.eval(Record.empty)
index = 0
iterator = when (r) {
is BagValue<*> -> {
isIndexable = false
r.iterator()
}
is CollectionValue<*> -> r.iterator()
else -> {
isIndexable = false
iterator { yield(r) }
}
}
}

override fun next(): Record? {
if (!iterator.hasNext()) {
return null
}
val v = iterator.next()
return when (isIndexable) {
true -> {
val i = index
index += 1
Record.of(v, int64Value(i))
}
false -> Record.of(v, missingValue())
}
}

override fun close() {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package org.partiql.eval.internal.operator.rel

import org.partiql.eval.internal.Record
import org.partiql.eval.internal.operator.Operator
import org.partiql.value.CollectionValue
import org.partiql.value.PartiQLValueExperimental

@OptIn(PartiQLValueExperimental::class)
internal class RelScanPermissive(
private val expr: Operator.Expr
) : Operator.Relation {

private lateinit var records: Iterator<Record>

override fun open() {
val r = expr.eval(Record.empty)
records = when (r) {
is CollectionValue<*> -> r.map { Record.of(it) }.iterator()
else -> iterator { yield(Record.of(r)) }
}
}

override fun next(): Record? {
return if (records.hasNext()) {
records.next()
} else {
null
}
}

override fun close() {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ internal class ExprCallDynamic(
@OptIn(PartiQLValueExperimental::class)
internal fun matches(args: Array<PartiQLValue>): Boolean {
for (i in args.indices) {
if (types[i] == PartiQLValueType.ANY) {
return true
}
if (args[i].type != types[i]) {
return false
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
package org.partiql.eval.internal.operator.rex

import org.partiql.errors.TypeCheckException
import org.partiql.eval.internal.Record
import org.partiql.eval.internal.helpers.toNull
import org.partiql.eval.internal.operator.Operator
import org.partiql.spi.function.PartiQLFunction
import org.partiql.spi.function.PartiQLFunctionExperimental
import org.partiql.value.PartiQLValue
import org.partiql.value.PartiQLValueExperimental
import org.partiql.value.missingValue

@OptIn(PartiQLValueExperimental::class, PartiQLFunctionExperimental::class)
internal class ExprCallStatic(
Expand All @@ -22,15 +20,13 @@ internal class ExprCallStatic(
@OptIn(PartiQLValueExperimental::class)
private val nil = fn.signature.returns.toNull()

override fun eval(record: Record): PartiQLValue = try {
override fun eval(record: Record): PartiQLValue {
// Evaluate arguments
val args = inputs.map { input ->
val r = input.eval(record)
if (r.isNull && fn.signature.isNullCall) return nil()
r
}.toTypedArray()
fn.invoke(args)
} catch (ex: TypeCheckException) {
missingValue()
return fn.invoke(args)
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.partiql.eval.internal.operator.rex

import org.partiql.errors.TypeCheckException
import org.partiql.eval.internal.Record
import org.partiql.eval.internal.operator.Operator
import org.partiql.value.CollectionValue
Expand All @@ -11,7 +12,6 @@ import org.partiql.value.IntValue
import org.partiql.value.PartiQLValue
import org.partiql.value.PartiQLValueExperimental
import org.partiql.value.check
import org.partiql.value.missingValue

internal class ExprPathIndex(
@JvmField val root: Operator.Expr,
Expand All @@ -21,7 +21,6 @@ internal class ExprPathIndex(
@OptIn(PartiQLValueExperimental::class)
override fun eval(record: Record): PartiQLValue {
val collection = root.eval(record).check<CollectionValue<PartiQLValue>>()
val value = missingValue()

// Calculate index
val index = when (val k = key.eval(record)) {
Expand All @@ -30,8 +29,8 @@ internal class ExprPathIndex(
is Int64Value -> k.int
is Int8Value -> k.int
is IntValue -> k.int
else -> return value
} ?: return value
else -> throw TypeCheckException()
} ?: throw TypeCheckException()

// Get element
val iterator = collection.iterator()
Expand All @@ -43,6 +42,6 @@ internal class ExprPathIndex(
}
i++
}
return value
throw TypeCheckException()
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package org.partiql.eval.internal.operator.rex

import org.partiql.errors.TypeCheckException
import org.partiql.eval.internal.Record
import org.partiql.eval.internal.operator.Operator
import org.partiql.value.PartiQLValue
import org.partiql.value.PartiQLValueExperimental
import org.partiql.value.StringValue
import org.partiql.value.StructValue
import org.partiql.value.check
import org.partiql.value.missingValue

internal class ExprPathKey(
@JvmField val root: Operator.Expr,
Expand All @@ -19,6 +19,6 @@ internal class ExprPathKey(
val rootEvaluated = root.eval(record).check<StructValue<PartiQLValue>>()
val keyEvaluated = key.eval(record).check<StringValue>()
val keyString = keyEvaluated.value ?: error("String value was null")
return rootEvaluated[keyString] ?: missingValue()
return rootEvaluated[keyString] ?: throw TypeCheckException()
}
}
Loading

0 comments on commit 1d0cb4a

Please sign in to comment.