Skip to content

Commit

Permalink
Prohibit ORDER BY, LIMIT, OFFSET on bag ops; change eval impl to use …
Browse files Browse the repository at this point in the history
…lazy
  • Loading branch information
alancai98 committed Aug 8, 2024
1 parent ff35761 commit 28428bf
Show file tree
Hide file tree
Showing 11 changed files with 56 additions and 34 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -274,26 +274,26 @@ internal class Compiler(
val lhs = visitRex(node.lhs, ctx)
val rhs = visitRex(node.rhs, ctx)
return when (node.setq) {
SetQuantifier.ALL -> ExprUnionAll(lhs, rhs)
SetQuantifier.DISTINCT -> ExprUnionDistinct(lhs, rhs)
SetQuantifier.ALL -> ExprUnionAll(lhs, rhs, session.mode == PartiQLEngine.Mode.PERMISSIVE)
SetQuantifier.DISTINCT -> ExprUnionDistinct(lhs, rhs, session.mode == PartiQLEngine.Mode.PERMISSIVE)
}
}

override fun visitRexOpExcept(node: Rex.Op.Except, ctx: PType?): Operator {
val lhs = visitRex(node.lhs, ctx)
val rhs = visitRex(node.rhs, ctx)
return when (node.setq) {
SetQuantifier.ALL -> ExprExceptAll(lhs, rhs)
SetQuantifier.DISTINCT -> ExprExceptDistinct(lhs, rhs)
SetQuantifier.ALL -> ExprExceptAll(lhs, rhs, session.mode == PartiQLEngine.Mode.PERMISSIVE)
SetQuantifier.DISTINCT -> ExprExceptDistinct(lhs, rhs, session.mode == PartiQLEngine.Mode.PERMISSIVE)
}
}

override fun visitRexOpIntersect(node: Rex.Op.Intersect, ctx: PType?): Operator {
val lhs = visitRex(node.lhs, ctx)
val rhs = visitRex(node.rhs, ctx)
return when (node.setq) {
SetQuantifier.ALL -> ExprIntersectAll(lhs, rhs)
SetQuantifier.DISTINCT -> ExprIntersectDistinct(lhs, rhs)
SetQuantifier.ALL -> ExprIntersectAll(lhs, rhs, session.mode == PartiQLEngine.Mode.PERMISSIVE)
SetQuantifier.DISTINCT -> ExprIntersectDistinct(lhs, rhs, session.mode == PartiQLEngine.Mode.PERMISSIVE)
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,35 @@
package org.partiql.eval.internal.helpers

import org.partiql.errors.TypeCheckException
import org.partiql.eval.value.Datum
import org.partiql.types.PType

/**
* Coercion function F for bag operators described in RFC-0007
* Coercion function F for bag operators described in RFC-0007.
* - F(absent_value) -> << >>
* - F(scalar_value) -> << scalar_value >> # singleton bag
* - F(tuple_value) -> << tuple_value >> # singleton bag, see future extensions
* - F(array_value) -> bag_value # discard ordering
* - F(bag_value) -> bag_value # identity
*
* Throws a [TypeCheckException] when coercing a non-collection to a bag.
*/
internal fun Datum.asIterator(): Iterator<Datum> {
internal fun Datum.asIterator(coerce: Boolean): Iterator<Datum> {
val d = this
return if (d.isNull || d.isMissing) {
emptyList<Datum>().iterator()
coerce.throwOrIterator(emptyList<Datum>().iterator())
} else {
when (d.type.kind) {
PType.Kind.LIST, PType.Kind.BAG, PType.Kind.SEXP -> d.iterator()
else -> listOf(d).iterator()
else -> coerce.throwOrIterator(listOf(d).iterator())
}
}
}

private fun Boolean.throwOrIterator(iterator: Iterator<Datum>): Iterator<Datum> {
if (this) {
return iterator
} else {
throw TypeCheckException()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,15 @@ import org.partiql.value.PartiQLValueExperimental
internal class ExprExceptAll(
private val lhs: Operator.Expr,
private val rhs: Operator.Expr,
private val coerce: Boolean,
) : Operator.Expr {

// TODO: Add support for equals/hashcode in Datum
private val counts: MutableMap<PartiQLValue, Int> = mutableMapOf()

override fun eval(env: Environment): Datum {
val lIter = lhs.eval(env).asIterator()
val rIter = rhs.eval(env).asIterator()
val lIter = lhs.eval(env).asIterator(coerce)
val rIter = rhs.eval(env).asIterator(coerce)
// read in RHS first
for (d in rIter) {
val value = d.toPartiQLValue()
Expand All @@ -36,6 +37,6 @@ internal class ExprExceptAll(
yield(d)
}
}
return Datum.bagValue(excepted.toList())
return Datum.bagValue(excepted.asIterable())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,14 @@ import org.partiql.value.PartiQLValueExperimental
internal class ExprExceptDistinct(
private val lhs: Operator.Expr,
private val rhs: Operator.Expr,
private val coerce: Boolean,
) : Operator.Expr {
// TODO: Add support for equals/hashcode in Datum
private val seen: MutableSet<PartiQLValue> = mutableSetOf()

override fun eval(env: Environment): Datum {
val lIter = lhs.eval(env).asIterator()
val rIter = rhs.eval(env).asIterator()
val lIter = lhs.eval(env).asIterator(coerce)
val rIter = rhs.eval(env).asIterator(coerce)
// read in RHS first
for (d in rIter) {
val value = d.toPartiQLValue()
Expand All @@ -31,6 +32,6 @@ internal class ExprExceptDistinct(
}
}
}
return Datum.bagValue(excepted.toList())
return Datum.bagValue(excepted.asIterable())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,14 @@ import org.partiql.value.PartiQLValueExperimental
internal class ExprIntersectAll(
private val lhs: Operator.Expr,
private val rhs: Operator.Expr,
private val coerce: Boolean,
) : Operator.Expr {
// TODO: Add support for equals/hashcode in Datum
private val counts: MutableMap<PartiQLValue, Int> = mutableMapOf()

override fun eval(env: Environment): Datum {
val lIter = lhs.eval(env).asIterator()
val rIter = rhs.eval(env).asIterator()
val lIter = lhs.eval(env).asIterator(coerce)
val rIter = rhs.eval(env).asIterator(coerce)
// read in LHS first
for (d in lIter) {
val value = d.toPartiQLValue()
Expand All @@ -34,6 +35,6 @@ internal class ExprIntersectAll(
}
}
}
return Datum.bagValue(intersected.toList())
return Datum.bagValue(intersected.asIterable())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,14 @@ import org.partiql.value.PartiQLValueExperimental
internal class ExprIntersectDistinct(
private val lhs: Operator.Expr,
private val rhs: Operator.Expr,
private val coerce: Boolean,
) : Operator.Expr {
// TODO: Add support for equals/hashcode in Datum
private val seen: MutableSet<PartiQLValue> = mutableSetOf()

override fun eval(env: Environment): Datum {
val lIter = lhs.eval(env).asIterator()
val rIter = rhs.eval(env).asIterator()
val lIter = lhs.eval(env).asIterator(coerce)
val rIter = rhs.eval(env).asIterator(coerce)
// read in LHS first
for (d in lIter) {
val value = d.toPartiQLValue()
Expand All @@ -31,6 +32,6 @@ internal class ExprIntersectDistinct(
}
}
}
return Datum.bagValue(intersected.toList())
return Datum.bagValue(intersected.asIterable())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@ import org.partiql.eval.value.Datum
internal class ExprUnionAll(
private val lhs: Operator.Expr,
private val rhs: Operator.Expr,
private val coerce: Boolean,
) : Operator.Expr {
override fun eval(env: Environment): Datum {
val lIter = lhs.eval(env).asIterator()
val rIter = rhs.eval(env).asIterator()
val lIter = lhs.eval(env).asIterator(coerce)
val rIter = rhs.eval(env).asIterator(coerce)
val unioned = lIter.asSequence() + rIter.asSequence()
return Datum.bagValue(unioned.toList())
return Datum.bagValue(unioned.asIterable())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,14 @@ import org.partiql.value.PartiQLValueExperimental
internal class ExprUnionDistinct(
private val lhs: Operator.Expr,
private val rhs: Operator.Expr,
private val coerce: Boolean,
) : Operator.Expr {
// TODO: Add support for equals/hashcode in Datum
private val seen: MutableSet<PartiQLValue> = mutableSetOf()

override fun eval(env: Environment): Datum {
val lIter = lhs.eval(env).asIterator()
val rIter = rhs.eval(env).asIterator()
val lIter = lhs.eval(env).asIterator(coerce)
val rIter = rhs.eval(env).asIterator(coerce)
val unioned = lIter.asSequence() + rIter.asSequence()
val distinct = sequence {
for (d in unioned) {
Expand All @@ -28,6 +29,6 @@ internal class ExprUnionDistinct(
}
}
}
return Datum.bagValue(distinct.toList())
return Datum.bagValue(distinct.asIterable())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1158,6 +1158,15 @@ internal class PartiQLParserDefault : PartiQLParser {
offset = offset,
)
} else {
if (ctx.order != null) {
error("ORDER BY not supported for bag ops")
}
if (ctx.limit != null) {
error("LIMIT not supported for bag ops")
}
if (ctx.offset != null) {
error("OFFSET not supported for bag ops")
}
exprBagOp(
type = op,
lhs = lhs,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,11 +127,7 @@ internal object RelConverter {
}
}
is QueryExpr.SetOp -> {
val rel = body.accept(ToRel(env), nil)
assert(rel.type.schema.size == 1) {
"Expected SELECT VALUE's input to have a single binding. " +
"However, it contained: ${rel.type.schema.map { it.name }}."
}
val rel = newQSet.accept(ToRel(env), nil)
val constructor = rex(ANY, rexOpVarLocal(0, 0))
val op = rexOpSelect(constructor, rel)
val type = when (rel.type.props.contains(Rel.Prop.ORDERED)) {
Expand Down

0 comments on commit 28428bf

Please sign in to comment.