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 Jul 9, 2024
1 parent 5b86afc commit 7d69467
Show file tree
Hide file tree
Showing 16 changed files with 542 additions and 217 deletions.
2 changes: 0 additions & 2 deletions partiql-eval/src/main/java/org/partiql/eval/value/Datum.java
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,6 @@ default Iterator<Field> getFields() {
* @throws NullPointerException if this instance also returns true on {@link #isNull()}; callers should check that
* {@link #isNull()} returns false before attempting to invoke this method.
*/
@NotNull
default Datum get(@NotNull String name) {
throw new UnsupportedOperationException();
}
Expand All @@ -331,7 +330,6 @@ default Datum get(@NotNull String name) {
* @throws NullPointerException if this instance also returns true on {@link #isNull()}; callers should check that
* {@link #isNull()} returns false before attempting to invoke this method.
*/
@NotNull
default Datum getInsensitive(@NotNull String name) {
throw new UnsupportedOperationException();
}
Expand Down
42 changes: 30 additions & 12 deletions partiql-eval/src/main/java/org/partiql/eval/value/DatumStruct.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@
class DatumStruct implements Datum {

@NotNull
private final Map<String, List<Datum>> _delegate;
private final HashMap<String, List<Datum>> _delegate;

@NotNull
private final Map<String, List<Datum>> _delegateNormalized;
private final HashMap<String, List<Datum>> _delegateNormalized;

private final static PType _type = PType.typeStruct();

Expand Down Expand Up @@ -50,29 +50,47 @@ public Iterator<Field> getFields() {
).iterator();
}

@NotNull
@Override
public Datum get(@NotNull String name) {
try {
return _delegate.get(name).get(0);
} catch (IndexOutOfBoundsException ex) {
throw new NullPointerException("Could not find struct key: " + name);
List<Datum> values = _delegate.get(name);
if (values == null) {
return null;
}
if (values.isEmpty()) {
return null;
}
return values.get(0);
}

@NotNull
@Override
public Datum getInsensitive(@NotNull String name) {
try {
return _delegateNormalized.get(name).get(0);
} catch (IndexOutOfBoundsException ex) {
throw new NullPointerException("Could not find struct key: " + name);
List<Datum> values = _delegateNormalized.get(name.toLowerCase());
if (values == null) {
return null;
}
if (values.isEmpty()) {
return null;
}
return values.get(0);
}

@NotNull
@Override
public PType getType() {
return _type;
}

@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("struct::{ ");
for (Map.Entry<String, List<Datum>> entry : _delegate.entrySet()) {
sb.append(entry.getKey());
sb.append(": ");
sb.append(entry.getValue().toString());
sb.append(", ");
}
sb.append(" }");
return sb.toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ import org.partiql.eval.internal.operator.rel.RelFilter
import org.partiql.eval.internal.operator.rel.RelIntersectAll
import org.partiql.eval.internal.operator.rel.RelIntersectDistinct
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 @@ -364,9 +364,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
@@ -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
Expand Up @@ -49,7 +49,6 @@ internal object ValueUtility {
* @throws NullPointerException if the value is null
* @throws TypeCheckException if the value's type is not a text type (string, symbol, char)
*/
@OptIn(PartiQLValueExperimental::class)
fun Datum.getText(): String {
return when (this.type.kind) {
PType.Kind.STRING, PType.Kind.SYMBOL, PType.Kind.CHAR -> this.string
Expand All @@ -67,7 +66,6 @@ internal object ValueUtility {
* @throws NullPointerException if the value is null
* @throws TypeCheckException if type is not an integer type
*/
@OptIn(PartiQLValueExperimental::class)
fun Datum.getBigIntCoerced(): BigInteger {
return when (this.type.kind) {
PType.Kind.TINYINT -> this.byte.toInt().toBigInteger()
Expand All @@ -90,7 +88,6 @@ internal object ValueUtility {
* @throws NullPointerException if the value is null
* @throws TypeCheckException if type is not an integer type
*/
@OptIn(PartiQLValueExperimental::class)
fun Datum.getInt32Coerced(): Int {
return when (this.type.kind) {
PType.Kind.TINYINT -> this.byte.toInt()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,64 @@
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 openPeeking(env: Environment) {
this.env = env
lhs.open(env)
iterator = implementation()
}

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

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

/**
* 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 7d69467

Please sign in to comment.