Skip to content

Commit deaa9c0

Browse files
authored
Merge b6444ff into b1244cc
2 parents b1244cc + b6444ff commit deaa9c0

File tree

21 files changed

+417
-177
lines changed

21 files changed

+417
-177
lines changed

partiql-ast/src/main/kotlin/org/partiql/ast/normalize/NormalizeFromSource.kt

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,19 @@ internal object NormalizeFromSource : AstPass {
5252

5353
override fun visitFromValue(node: From.Value, ctx: Int): From {
5454
val expr = visitExpr(node.expr, ctx) as Expr
55-
val asAlias = node.asAlias ?: expr.toBinder(ctx)
56-
return if (expr !== node.expr || asAlias !== node.asAlias) {
57-
node.copy(expr = expr, asAlias = asAlias)
55+
var i = ctx
56+
var asAlias = node.asAlias
57+
var atAlias = node.atAlias
58+
// derive AS alias
59+
if (asAlias == null) {
60+
asAlias = expr.toBinder(i++)
61+
}
62+
// derive AT binder
63+
if (atAlias == null && node.type == From.Value.Type.UNPIVOT) {
64+
atAlias = expr.toBinder(i++)
65+
}
66+
return if (expr !== node.expr || asAlias !== node.asAlias || atAlias !== node.atAlias) {
67+
node.copy(expr = expr, asAlias = asAlias, atAlias = atAlias)
5868
} else {
5969
node
6070
}

partiql-eval/src/main/kotlin/org/partiql/eval/internal/Compiler.kt

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,12 @@ import org.partiql.eval.PartiQLEngine
44
import org.partiql.eval.internal.operator.Operator
55
import org.partiql.eval.internal.operator.rel.RelAggregate
66
import org.partiql.eval.internal.operator.rel.RelDistinct
7+
import org.partiql.eval.internal.operator.rel.RelExceptAll
8+
import org.partiql.eval.internal.operator.rel.RelExceptDistinct
79
import org.partiql.eval.internal.operator.rel.RelExclude
810
import org.partiql.eval.internal.operator.rel.RelFilter
11+
import org.partiql.eval.internal.operator.rel.RelIntersectAll
12+
import org.partiql.eval.internal.operator.rel.RelIntersectDistinct
913
import org.partiql.eval.internal.operator.rel.RelJoinInner
1014
import org.partiql.eval.internal.operator.rel.RelJoinLeft
1115
import org.partiql.eval.internal.operator.rel.RelJoinOuterFull
@@ -18,13 +22,16 @@ import org.partiql.eval.internal.operator.rel.RelScanIndexed
1822
import org.partiql.eval.internal.operator.rel.RelScanIndexedPermissive
1923
import org.partiql.eval.internal.operator.rel.RelScanPermissive
2024
import org.partiql.eval.internal.operator.rel.RelSort
25+
import org.partiql.eval.internal.operator.rel.RelUnionAll
26+
import org.partiql.eval.internal.operator.rel.RelUnionDistinct
2127
import org.partiql.eval.internal.operator.rel.RelUnpivot
2228
import org.partiql.eval.internal.operator.rex.ExprCallDynamic
2329
import org.partiql.eval.internal.operator.rex.ExprCallStatic
2430
import org.partiql.eval.internal.operator.rex.ExprCase
2531
import org.partiql.eval.internal.operator.rex.ExprCast
2632
import org.partiql.eval.internal.operator.rex.ExprCoalesce
2733
import org.partiql.eval.internal.operator.rex.ExprCollection
34+
import org.partiql.eval.internal.operator.rex.ExprError
2835
import org.partiql.eval.internal.operator.rex.ExprLiteral
2936
import org.partiql.eval.internal.operator.rex.ExprNullIf
3037
import org.partiql.eval.internal.operator.rex.ExprPathIndex
@@ -46,7 +53,6 @@ import org.partiql.plan.Ref
4653
import org.partiql.plan.Rel
4754
import org.partiql.plan.Rex
4855
import org.partiql.plan.Statement
49-
import org.partiql.plan.debug.PlanPrinter
5056
import org.partiql.plan.visitor.PlanBaseVisitor
5157
import org.partiql.spi.fn.Agg
5258
import org.partiql.spi.fn.FnExperimental
@@ -69,12 +75,17 @@ internal class Compiler(
6975
TODO("Not yet implemented")
7076
}
7177

78+
/**
79+
* Realistically, this should never execute -- since the problems of severity ERROR are sent to the problem handler
80+
* at planning time. Implementors SHOULD fail compilation, however, if they decide not to, we will allow its execution
81+
* and will treat this identically to [visitRexOpMissing].
82+
*/
7283
override fun visitRexOpErr(node: Rex.Op.Err, ctx: StaticType?): Operator {
73-
val message = buildString {
74-
this.appendLine(node.message)
75-
PlanPrinter.append(this, plan)
76-
}
77-
throw IllegalStateException(message)
84+
return ExprError(node.message)
85+
}
86+
87+
override fun visitRexOpMissing(node: Rex.Op.Missing, ctx: StaticType?): Operator {
88+
return ExprError(node.message)
7889
}
7990

8091
override fun visitRelOpErr(node: Rel.Op.Err, ctx: StaticType?): Operator {
@@ -268,6 +279,19 @@ internal class Compiler(
268279
}
269280
}
270281

282+
override fun visitRelOpSet(node: Rel.Op.Set, ctx: StaticType?): Operator {
283+
val lhs = visitRel(node.lhs, ctx)
284+
val rhs = visitRel(node.rhs, ctx)
285+
return when (node.type) {
286+
Rel.Op.Set.Type.UNION_ALL -> RelUnionAll(lhs, rhs)
287+
Rel.Op.Set.Type.UNION_DISTINCT -> RelUnionDistinct(lhs, rhs)
288+
Rel.Op.Set.Type.INTERSECT_ALL -> RelIntersectAll(lhs, rhs)
289+
Rel.Op.Set.Type.INTERSECT_DISTINCT -> RelIntersectDistinct(lhs, rhs)
290+
Rel.Op.Set.Type.EXCEPT_ALL -> RelExceptAll(lhs, rhs)
291+
Rel.Op.Set.Type.EXCEPT_DISTINCT -> RelExceptDistinct(lhs, rhs)
292+
}
293+
}
294+
271295
override fun visitRelOpLimit(node: Rel.Op.Limit, ctx: StaticType?): Operator {
272296
val input = visitRel(node.input, ctx)
273297
val limit = visitRex(node.limit, ctx)
@@ -317,7 +341,7 @@ internal class Compiler(
317341

318342
override fun visitRelOpFilter(node: Rel.Op.Filter, ctx: StaticType?): Operator {
319343
val input = visitRel(node.input, ctx)
320-
val condition = visitRex(node.predicate, ctx)
344+
val condition = visitRex(node.predicate, ctx).modeHandled()
321345
return RelFilter(input, condition)
322346
}
323347

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package org.partiql.eval.internal.helpers
2+
3+
/**
4+
* WARNING: You must invoke [hasNext] before calling [next].
5+
*/
6+
internal class IteratorChain<T>(
7+
iterators: Iterable<Iterator<T>>
8+
) : Iterator<T> {
9+
10+
private var iterator = iterators.iterator()
11+
private var current = iterator.next()
12+
13+
override fun hasNext(): Boolean {
14+
return when (current.hasNext()) {
15+
true -> true
16+
false -> {
17+
if (!iterator.hasNext()) {
18+
return false
19+
}
20+
current = iterator.next()
21+
current.hasNext()
22+
}
23+
}
24+
}
25+
26+
override fun next(): T {
27+
return current.next()
28+
}
29+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package org.partiql.eval.internal.operator.rel
2+
3+
import org.partiql.eval.internal.Environment
4+
import org.partiql.eval.internal.Record
5+
import org.partiql.eval.internal.operator.Operator
6+
7+
internal class RelExceptAll(
8+
private val lhs: Operator.Relation,
9+
private val rhs: Operator.Relation,
10+
) : RelPeeking() {
11+
12+
private val seen: MutableMap<Record, Int> = mutableMapOf()
13+
private var init: Boolean = false
14+
15+
override fun open(env: Environment) {
16+
lhs.open(env)
17+
rhs.open(env)
18+
init = false
19+
seen.clear()
20+
super.open(env)
21+
}
22+
23+
override fun peek(): Record? {
24+
if (!init) {
25+
seed()
26+
}
27+
for (row in lhs) {
28+
seen.computeIfPresent(row) { _, y ->
29+
when (y) {
30+
0 -> null
31+
else -> y - 1
32+
}
33+
} ?: return row
34+
}
35+
return null
36+
}
37+
38+
override fun close() {
39+
lhs.close()
40+
rhs.close()
41+
seen.clear()
42+
super.close()
43+
}
44+
45+
/**
46+
* Read the entire left-hand-side into our search structure.
47+
*/
48+
private fun seed() {
49+
init = true
50+
for (row in rhs) {
51+
seen.computeIfPresent(row) { _, y ->
52+
y + 1
53+
} ?: seen.put(row, 1)
54+
}
55+
}
56+
}

partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelExcept.kt renamed to partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelExceptDistinct.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import org.partiql.eval.internal.operator.Operator
1010
* @property lhs
1111
* @property rhs
1212
*/
13-
internal class RelExcept(
13+
internal class RelExceptDistinct(
1414
private val lhs: Operator.Relation,
1515
private val rhs: Operator.Relation,
1616
) : RelPeeking() {
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package org.partiql.eval.internal.operator.rel
2+
3+
import org.partiql.eval.internal.Environment
4+
import org.partiql.eval.internal.Record
5+
import org.partiql.eval.internal.operator.Operator
6+
7+
internal class RelIntersectAll(
8+
private val lhs: Operator.Relation,
9+
private val rhs: Operator.Relation,
10+
) : RelPeeking() {
11+
12+
private val seen: MutableMap<Record, Int> = mutableMapOf()
13+
private var init: Boolean = false
14+
15+
override fun open(env: Environment) {
16+
lhs.open(env)
17+
rhs.open(env)
18+
init = false
19+
seen.clear()
20+
super.open(env)
21+
}
22+
23+
override fun peek(): Record? {
24+
if (!init) {
25+
seed()
26+
}
27+
for (row in rhs) {
28+
seen.computeIfPresent(row) { _, y ->
29+
when (y) {
30+
0 -> null
31+
else -> y - 1
32+
}
33+
}?.let { return row }
34+
}
35+
return null
36+
}
37+
38+
override fun close() {
39+
lhs.close()
40+
rhs.close()
41+
seen.clear()
42+
super.close()
43+
}
44+
45+
/**
46+
* Read the entire left-hand-side into our search structure.
47+
*/
48+
private fun seed() {
49+
init = true
50+
for (row in lhs) {
51+
seen.computeIfPresent(row) { _, y ->
52+
y + 1
53+
} ?: seen.put(row, 1)
54+
}
55+
}
56+
}

partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelIntersect.kt renamed to partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelIntersectDistinct.kt

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,19 @@ import org.partiql.eval.internal.Environment
44
import org.partiql.eval.internal.Record
55
import org.partiql.eval.internal.operator.Operator
66

7-
internal class RelIntersect(
7+
internal class RelIntersectDistinct(
88
private val lhs: Operator.Relation,
99
private val rhs: Operator.Relation,
1010
) : RelPeeking() {
1111

12-
private var seen: MutableSet<Record> = mutableSetOf()
12+
private val seen: MutableSet<Record> = mutableSetOf()
1313
private var init: Boolean = false
1414

1515
override fun open(env: Environment) {
1616
lhs.open(env)
1717
rhs.open(env)
1818
init = false
19-
seen = mutableSetOf()
19+
seen.clear()
2020
super.open(env)
2121
}
2222

@@ -25,7 +25,7 @@ internal class RelIntersect(
2525
seed()
2626
}
2727
for (row in rhs) {
28-
if (seen.contains(row)) {
28+
if (seen.remove(row)) {
2929
return row
3030
}
3131
}
@@ -44,8 +44,7 @@ internal class RelIntersect(
4444
*/
4545
private fun seed() {
4646
init = true
47-
while (true) {
48-
val row = lhs.next() ?: break
47+
for (row in lhs) {
4948
seen.add(row)
5049
}
5150
}

partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelUnion.kt renamed to partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelUnionAll.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import org.partiql.eval.internal.Environment
44
import org.partiql.eval.internal.Record
55
import org.partiql.eval.internal.operator.Operator
66

7-
internal class RelUnion(
7+
internal class RelUnionAll(
88
private val lhs: Operator.Relation,
99
private val rhs: Operator.Relation,
1010
) : Operator.Relation {
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package org.partiql.eval.internal.operator.rel
2+
3+
import org.partiql.eval.internal.Environment
4+
import org.partiql.eval.internal.Record
5+
import org.partiql.eval.internal.helpers.IteratorChain
6+
import org.partiql.eval.internal.operator.Operator
7+
8+
internal class RelUnionDistinct(
9+
private val lhs: Operator.Relation,
10+
private val rhs: Operator.Relation,
11+
) : RelPeeking() {
12+
13+
private val seen: MutableSet<Record> = mutableSetOf()
14+
private lateinit var input: Iterator<Record>
15+
16+
override fun open(env: Environment) {
17+
lhs.open(env)
18+
rhs.open(env)
19+
seen.clear()
20+
input = IteratorChain(listOf(lhs, rhs))
21+
super.open(env)
22+
}
23+
24+
override fun peek(): Record? {
25+
for (record in input) {
26+
if (!seen.contains(record)) {
27+
seen.add(record)
28+
return record
29+
}
30+
}
31+
return null
32+
}
33+
34+
override fun close() {
35+
lhs.close()
36+
rhs.close()
37+
seen.clear()
38+
super.close()
39+
}
40+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package org.partiql.eval.internal.operator.rex
2+
3+
import org.partiql.errors.TypeCheckException
4+
import org.partiql.eval.internal.Environment
5+
import org.partiql.eval.internal.operator.Operator
6+
import org.partiql.value.PartiQLValue
7+
import org.partiql.value.PartiQLValueExperimental
8+
9+
internal class ExprError(
10+
private val message: String,
11+
) : Operator.Expr {
12+
13+
@OptIn(PartiQLValueExperimental::class)
14+
override fun eval(env: Environment): PartiQLValue {
15+
throw TypeCheckException(message)
16+
}
17+
}

0 commit comments

Comments
 (0)