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

Updates pivot on rebase and join tests #1316

Merged
merged 2 commits into from
Dec 20, 2023
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
44 changes: 35 additions & 9 deletions partiql-eval/src/main/kotlin/org/partiql/eval/internal/Compiler.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,12 @@ import org.partiql.eval.internal.operator.rel.RelJoinOuterFull
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.rex.ExprCase
import org.partiql.eval.internal.operator.rex.ExprCollection
import org.partiql.eval.internal.operator.rex.ExprLiteral
import org.partiql.eval.internal.operator.rex.ExprPathKey
import org.partiql.eval.internal.operator.rex.ExprPivot
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 @@ -30,10 +33,13 @@ internal object Compiler {
}

private object PlanToCodeTransformer : PlanBaseVisitor<Operator, Unit>() {

override fun defaultReturn(node: PlanNode, ctx: Unit): Operator {
TODO("Not yet implemented")
}

// REX

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))
Expand All @@ -45,33 +51,53 @@ internal object Compiler {
return ExprVar(node.ref)
}

override fun visitRexOpPathKey(node: Rex.Op.Path.Key, ctx: Unit): Operator {
val root = visitRex(node.root, ctx)
val key = visitRex(node.key, ctx)
return ExprPathKey(root, key)
}

override fun visitRexOpCollection(node: Rex.Op.Collection, ctx: Unit): Operator {
val values = node.values.map { visitRex(it, ctx) }
return ExprCollection(values)
}

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

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

override fun visitRelOpScan(node: Rel.Op.Scan, ctx: Unit): Operator {
val rex = visitRex(node.rex, ctx)
return RelScan(rex)
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)
}

@OptIn(PartiQLValueExperimental::class)
override fun visitRexOpLit(node: Rex.Op.Lit, ctx: Unit): Operator {
return ExprLiteral(node.value)
}

// REL

override fun visitRelOpScan(node: Rel.Op.Scan, ctx: Unit): Operator {
val rex = visitRex(node.rex, ctx)
return 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) }
return RelProject(input, projections)
}

override fun visitRelOpScanIndexed(node: Rel.Op.ScanIndexed, ctx: Unit): Operator {
val rex = visitRex(node.rex, ctx)
return RelScanIndexed(rex)
}

override fun visitRel(node: Rel, ctx: Unit): Operator.Relation {
return super.visitRelOp(node.op, ctx) as Operator.Relation
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
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.PartiQLValue
import org.partiql.value.PartiQLValueExperimental
import org.partiql.value.int64Value

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

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

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

override fun next(): Record? {
if (!iterator.hasNext()) {
return null
}
val i = index
val v = iterator.next()
index += 1
return Record.of(v, int64Value(i))
}

override fun close() {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import org.partiql.value.check
import org.partiql.value.missingValue

internal class ExprPathKey(
val root: Operator.Expr,
val key: Operator.Expr
@JvmField val root: Operator.Expr,
@JvmField val key: Operator.Expr
) : Operator.Expr {

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

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.check
import org.partiql.value.structValue

@OptIn(PartiQLValueExperimental::class)
internal class ExprPivot(
private val input: Operator.Relation,
private val key: Operator.Expr,
private val value: Operator.Expr,
) : Operator.Expr {

override fun eval(record: Record): PartiQLValue {
input.open()
val fields = mutableListOf<Pair<String, PartiQLValue>>()
while (true) {
val row = input.next() ?: break
val k = key.eval(row).check<StringValue>()
val v = value.eval(row)
fields.add(k.value!! to v)
}
input.close()
return structValue(fields)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@ import org.partiql.planner.PartiQLPlannerBuilder
import org.partiql.value.BagValue
import org.partiql.value.PartiQLValue
import org.partiql.value.PartiQLValueExperimental
import org.partiql.value.StructValue
import org.partiql.value.bagValue
import org.partiql.value.boolValue
import org.partiql.value.int32Value
import org.partiql.value.int64Value
import org.partiql.value.io.PartiQLValueIonWriterBuilder
import org.partiql.value.missingValue
import org.partiql.value.nullValue
Expand All @@ -23,10 +25,11 @@ import kotlin.test.assertEquals

/**
* This holds sanity tests during the development of the [PartiQLEngine.default] implementation.
<<<<<<< HEAD
=======
*
* TODO need to update implementations
>>>>>>> 1772f0ed (Updates JOIN tests)
*/
@Disabled
class PartiQLEngineDefaultTest {

private val engine = PartiQLEngine.default()
Expand Down Expand Up @@ -82,7 +85,7 @@ class PartiQLEngineDefaultTest {
@OptIn(PartiQLValueExperimental::class)
@Test
fun testJoinInner() {
val statement = parser.parse("SELECT a, b FROM << { 'a': 1 } >> t, << { 'b': 2 } >> s;").root
val statement = parser.parse("SELECT t.a, s.b FROM << { 'a': 1 } >> t, << { 'b': 2 } >> s;").root
val session = PartiQLPlanner.Session("q", "u")
val plan = planner.plan(statement, session)

Expand All @@ -97,7 +100,7 @@ class PartiQLEngineDefaultTest {
@OptIn(PartiQLValueExperimental::class)
@Test
fun testJoinLeft() {
val statement = parser.parse("SELECT a, b FROM << { 'a': 1 } >> t LEFT JOIN << { 'b': 2 } >> s ON false;").root
val statement = parser.parse("SELECT t.a, s.b FROM << { 'a': 1 } >> t LEFT JOIN << { 'b': 2 } >> s ON false;").root
val session = PartiQLPlanner.Session("q", "u")
val plan = planner.plan(statement, session)

Expand All @@ -113,8 +116,7 @@ class PartiQLEngineDefaultTest {
@Test
fun testJoinOuterFull() {
val statement =
parser.parse("SELECT a, b FROM << { 'a': 1 } >> t FULL OUTER JOIN << { 'b': 2 } >> s ON false;").root

parser.parse("SELECT t.a, s.b FROM << { 'a': 1 } >> t FULL OUTER JOIN << { 'b': 2 } >> s ON false;").root
val session = PartiQLPlanner.Session("q", "u")
val plan = planner.plan(statement, session)

Expand All @@ -128,14 +130,14 @@ class PartiQLEngineDefaultTest {
val output = result.value as BagValue<*>

val expected = bagValue(
structValue(
"a" to int32Value(1),
"b" to nullValue()
),
structValue(
"a" to nullValue(),
"b" to int32Value(2)
),
structValue(
"a" to int32Value(1),
"b" to nullValue()
),
)
assertEquals(expected, output, comparisonString(expected, output))
}
Expand Down Expand Up @@ -194,7 +196,7 @@ class PartiQLEngineDefaultTest {
@Test
fun testJoinOuterFullOnTrue() {
val statement =
parser.parse("SELECT a, b FROM << { 'a': 1 } >> t FULL OUTER JOIN << { 'b': 2 } >> s ON TRUE;").root
parser.parse("SELECT t.a, s.b FROM << { 'a': 1 } >> t FULL OUTER JOIN << { 'b': 2 } >> s ON TRUE;").root

val session = PartiQLPlanner.Session("q", "u")
val plan = planner.plan(statement, session)
Expand Down Expand Up @@ -412,19 +414,22 @@ class PartiQLEngineDefaultTest {
SELECT VALUE {
'a': 1,
'b': NULL,
c : d
t.c : t.d
}
FROM <<
{ 'c': 'hello', 'd': 'world' }
>>
>> AS t
""".trimIndent()
val statement = parser.parse(source).root
val session = PartiQLPlanner.Session("q", "u")
val plan = planner.plan(statement, session)

val prepared = engine.prepare(plan.plan)
val result = engine.execute(prepared) as PartiQLResult.Value
val output = result.value
val result = engine.execute(prepared)
if (result is PartiQLResult.Error) {
throw result.cause
}
val output = (result as PartiQLResult.Value).value

val expected: PartiQLValue = bagValue(
structValue(
Expand All @@ -435,4 +440,63 @@ class PartiQLEngineDefaultTest {
)
assertEquals(expected, output)
}

@OptIn(PartiQLValueExperimental::class)
@Test
fun testScanIndexed() {
val statement = parser.parse("SELECT v, i FROM << 'a', 'b', 'c' >> AS v AT i").root
val session = PartiQLPlanner.Session("q", "u")
val plan = planner.plan(statement, session)

val prepared = engine.prepare(plan.plan)
val result = engine.execute(prepared) as PartiQLResult.Value
val output = result.value

val expected = bagValue(
structValue(
"v" to stringValue("a"),
"i" to int64Value(0),
),
structValue(
"v" to stringValue("b"),
"i" to int64Value(1),
),
structValue(
"v" to stringValue("c"),
"i" to int64Value(2),
),
)
assertEquals(expected, output, comparisonString(expected, output))
}

@OptIn(PartiQLValueExperimental::class)
@Test
fun testPivot() {
val statement = parser.parse(
"""
PIVOT x.v AT x.k FROM <<
{ 'k': 'a', 'v': 'x' },
{ 'k': 'b', 'v': 'y' },
{ 'k': 'c', 'v': 'z' }
>> AS x
""".trimIndent()
).root
val session = PartiQLPlanner.Session("q", "u")
val plan = planner.plan(statement, session)

val prepared = engine.prepare(plan.plan)
val result = engine.execute(prepared)
if (result is PartiQLResult.Error) {
throw result.cause
}
result as PartiQLResult.Value
val output = result.value as StructValue<*>

val expected = structValue(
"a" to stringValue("x"),
"b" to stringValue("y"),
"c" to stringValue("z"),
)
assertEquals(expected, output, comparisonString(expected, output))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -115,13 +115,13 @@ internal object PlanTransform : PlanBaseVisitor<PlanNode, ProblemCallback>() {

override fun visitRexOpPathIndex(node: Rex.Op.Path.Index, ctx: ProblemCallback): PlanNode {
val root = visitRex(node.root, ctx)
val key = visitRex(node.root, ctx)
val key = visitRex(node.key, ctx)
return org.partiql.plan.Rex.Op.Path.Index(root, key)
}

override fun visitRexOpPathKey(node: Rex.Op.Path.Key, ctx: ProblemCallback): PlanNode {
val root = visitRex(node.root, ctx)
val key = visitRex(node.root, ctx)
val key = visitRex(node.key, ctx)
return org.partiql.plan.Rex.Op.Path.Key(root, key)
}

Expand Down
Loading