Skip to content

Commit

Permalink
Simplifies joins and fixes bugs
Browse files Browse the repository at this point in the history
  • Loading branch information
johnedquinn committed Apr 23, 2024
1 parent 7289c9b commit d114152
Show file tree
Hide file tree
Showing 14 changed files with 554 additions and 198 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ import org.partiql.eval.internal.operator.rel.RelDistinct
import org.partiql.eval.internal.operator.rel.RelExclude
import org.partiql.eval.internal.operator.rel.RelFilter
import org.partiql.eval.internal.operator.rel.RelJoinInner
import org.partiql.eval.internal.operator.rel.RelJoinLeft
import org.partiql.eval.internal.operator.rel.RelJoinOuterFull
import org.partiql.eval.internal.operator.rel.RelJoinRight
import org.partiql.eval.internal.operator.rel.RelJoinOuterLeft
import org.partiql.eval.internal.operator.rel.RelJoinOuterRight
import org.partiql.eval.internal.operator.rel.RelLimit
import org.partiql.eval.internal.operator.rel.RelOffset
import org.partiql.eval.internal.operator.rel.RelProject
Expand Down Expand Up @@ -331,9 +331,9 @@ internal class Compiler(
val condition = visitRex(node.rex, ctx)
return when (node.type) {
Rel.Op.Join.Type.INNER -> RelJoinInner(lhs, rhs, condition)
Rel.Op.Join.Type.LEFT -> RelJoinLeft(lhs, rhs, condition)
Rel.Op.Join.Type.RIGHT -> RelJoinRight(lhs, rhs, condition)
Rel.Op.Join.Type.FULL -> RelJoinOuterFull(lhs, rhs, condition)
Rel.Op.Join.Type.LEFT -> RelJoinOuterLeft(lhs, rhs, condition, rhsType = node.rhs.type)
Rel.Op.Join.Type.RIGHT -> RelJoinOuterRight(lhs, rhs, condition, lhsType = node.lhs.type)
Rel.Op.Join.Type.FULL -> RelJoinOuterFull(lhs, rhs, condition, lhsType = node.lhs.type, rhsType = node.rhs.type)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@ internal class Environment(

@OptIn(PartiQLValueExperimental::class)
operator fun get(index: Int): PartiQLValue {
return this.bindings[index]
try {
return this.bindings[index]
} catch (_: Throwable) {
throw IllegalStateException("Received error when searching for binding at index $index. Current bindings are: $this.")
}
}

@OptIn(PartiQLValueExperimental::class)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package org.partiql.eval.internal.helpers

import org.partiql.types.AnyOfType
import org.partiql.types.AnyType
import org.partiql.types.BagType
import org.partiql.types.BlobType
import org.partiql.types.BoolType
import org.partiql.types.ClobType
import org.partiql.types.DateType
import org.partiql.types.DecimalType
import org.partiql.types.FloatType
import org.partiql.types.GraphType
import org.partiql.types.IntType
import org.partiql.types.ListType
import org.partiql.types.MissingType
import org.partiql.types.NullType
import org.partiql.types.SexpType
import org.partiql.types.StaticType
import org.partiql.types.StringType
import org.partiql.types.StructType
import org.partiql.types.SymbolType
import org.partiql.types.TimeType
import org.partiql.types.TimestampType
import org.partiql.value.PartiQLValueExperimental
import org.partiql.value.PartiQLValueType

internal object TypesUtility {

@OptIn(PartiQLValueExperimental::class)
internal fun StaticType.toRuntimeType(): PartiQLValueType {
if (this is AnyOfType) {
// handle anyOf(null, T) cases
val t = types.filter { it !is NullType && it !is MissingType }
return if (t.size != 1) {
PartiQLValueType.ANY
} else {
t.first().asRuntimeType()
}
}
return this.asRuntimeType()
}

@OptIn(PartiQLValueExperimental::class)
private fun StaticType.asRuntimeType(): PartiQLValueType = when (this) {
is AnyOfType -> PartiQLValueType.ANY
is AnyType -> PartiQLValueType.ANY
is BlobType -> PartiQLValueType.BLOB
is BoolType -> PartiQLValueType.BOOL
is ClobType -> PartiQLValueType.CLOB
is BagType -> PartiQLValueType.BAG
is ListType -> PartiQLValueType.LIST
is SexpType -> PartiQLValueType.SEXP
is DateType -> PartiQLValueType.DATE
// TODO: Run time decimal type does not model precision scale constraint yet
// despite that we match to Decimal vs Decimal_ARBITRARY (PVT) here
// but when mapping it back to Static Type, (i.e, mapping function return type to Value Type)
// we can only map to Unconstrained decimal (Static Type)
is DecimalType -> {
when (this.precisionScaleConstraint) {
is DecimalType.PrecisionScaleConstraint.Constrained -> PartiQLValueType.DECIMAL
DecimalType.PrecisionScaleConstraint.Unconstrained -> PartiQLValueType.DECIMAL_ARBITRARY
}
}
is FloatType -> PartiQLValueType.FLOAT64
is GraphType -> error("Graph type missing from runtime types")
is IntType -> when (this.rangeConstraint) {
IntType.IntRangeConstraint.SHORT -> PartiQLValueType.INT16
IntType.IntRangeConstraint.INT4 -> PartiQLValueType.INT32
IntType.IntRangeConstraint.LONG -> PartiQLValueType.INT64
IntType.IntRangeConstraint.UNCONSTRAINED -> PartiQLValueType.INT
}
MissingType -> PartiQLValueType.MISSING
is NullType -> PartiQLValueType.NULL
is StringType -> PartiQLValueType.STRING
is StructType -> PartiQLValueType.STRUCT
is SymbolType -> PartiQLValueType.SYMBOL
is TimeType -> PartiQLValueType.TIME
is TimestampType -> PartiQLValueType.TIMESTAMP
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package org.partiql.eval.internal.helpers

import org.partiql.value.BoolValue
import org.partiql.value.PartiQLValue
import org.partiql.value.PartiQLValueExperimental

/**
* Holds helper functions for [PartiQLValue].
*/
internal object ValueUtility {

/**
* @return whether the value is a boolean and the value itself is not-null and true.
*/
@OptIn(PartiQLValueExperimental::class)
@JvmStatic
fun PartiQLValue.isTrue(): Boolean {
return this is BoolValue && this.value == true
}
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,66 @@
package org.partiql.eval.internal.operator.rel

import org.partiql.eval.internal.Environment
import org.partiql.eval.internal.Record
import org.partiql.eval.internal.helpers.ValueUtility.isTrue
import org.partiql.eval.internal.operator.Operator
import org.partiql.value.PartiQLValueExperimental

internal class RelJoinInner(
override val lhs: Operator.Relation,
override val rhs: Operator.Relation,
override val condition: Operator.Expr,
) : RelJoinNestedLoop() {
override fun join(condition: Boolean, lhs: Record, rhs: Record): Record? {
return when (condition) {
true -> lhs + rhs
private val lhs: Operator.Relation,
private val rhs: Operator.Relation,
private val condition: Operator.Expr,
) : RelPeeking() {

private lateinit var env: Environment
private lateinit var iterator: Iterator<Record>

override fun open(env: Environment) {
this.env = env
lhs.open(env)
iterator = implementation()
super.open(env)
}

override fun peek(): Record? {
return when (iterator.hasNext()) {
true -> iterator.next()
false -> null
}
}

override fun close() {
lhs.close()
rhs.close()
iterator = emptyList<Record>().iterator()
super.close()
}

/**
* INNER JOIN (LATERAL)
*
* Algorithm:
* ```
* for lhsRecord in lhs:
* for rhsRecord in rhs(lhsRecord):
* if (condition matches):
* conditionMatched = true
* yield(lhsRecord + rhsRecord)
* ```
*
* Development Note: The non-lateral version wouldn't need to push to the current environment.
*/
@OptIn(PartiQLValueExperimental::class)
private fun implementation() = iterator {
for (lhsRecord in lhs) {
rhs.open(env.push(lhsRecord))
for (rhsRecord in rhs) {
val input = lhsRecord + rhsRecord
val result = condition.eval(env.push(input))
if (result.isTrue()) {
yield(lhsRecord + rhsRecord)
}
}
}
}
}

This file was deleted.

This file was deleted.

Loading

0 comments on commit d114152

Please sign in to comment.