Skip to content

Commit 8b4e0d3

Browse files
authored
Merge pull request #1508 from johnedquinn/v1-conformance-variable-resolution
Updates rules for variable resolution
2 parents ff03b0a + 86718c2 commit 8b4e0d3

File tree

14 files changed

+386
-341
lines changed

14 files changed

+386
-341
lines changed

partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rex/ExprCast.kt

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import org.partiql.value.Int64Value
2323
import org.partiql.value.Int8Value
2424
import org.partiql.value.IntValue
2525
import org.partiql.value.ListValue
26+
import org.partiql.value.MissingValue
2627
import org.partiql.value.NullValue
2728
import org.partiql.value.NumericValue
2829
import org.partiql.value.PartiQLValue
@@ -46,6 +47,7 @@ import org.partiql.value.int64Value
4647
import org.partiql.value.int8Value
4748
import org.partiql.value.intValue
4849
import org.partiql.value.listValue
50+
import org.partiql.value.missingValue
4951
import org.partiql.value.sexpValue
5052
import org.partiql.value.stringValue
5153
import org.partiql.value.structValue
@@ -59,7 +61,8 @@ import java.math.BigInteger
5961
internal class ExprCast(val arg: Operator.Expr, val cast: Ref.Cast) : Operator.Expr {
6062
@OptIn(PartiQLValueExperimental::class)
6163
override fun eval(env: Environment): Datum {
62-
val arg = arg.eval(env).toPartiQLValue()
64+
val argDatum = arg.eval(env)
65+
val arg = argDatum.toPartiQLValue()
6366
try {
6467
val partiqlValue = when (PType.fromPartiQLValueType(arg.type).kind) {
6568
PType.Kind.DYNAMIC -> TODO("Not Possible")
@@ -86,9 +89,9 @@ internal class ExprCast(val arg: Operator.Expr, val cast: Ref.Cast) : Operator.E
8689
PType.Kind.BAG -> castFromCollection(arg as BagValue<*>, cast.target)
8790
PType.Kind.LIST -> castFromCollection(arg as ListValue<*>, cast.target)
8891
PType.Kind.SEXP -> castFromCollection(arg as SexpValue<*>, cast.target)
89-
PType.Kind.STRUCT -> TODO("CAST FROM STRUCT not yet implemented")
92+
PType.Kind.STRUCT -> castFromStruct(argDatum, cast.target).toPartiQLValue()
9093
PType.Kind.ROW -> TODO("CAST FROM ROW not yet implemented")
91-
PType.Kind.UNKNOWN -> TODO("CAST FROM UNKNOWN not yet implemented")
94+
PType.Kind.UNKNOWN -> castFromUnknown(arg, cast.target)
9295
PType.Kind.VARCHAR -> TODO("CAST FROM VARCHAR not yet implemented")
9396
}
9497
return Datum.of(partiqlValue)
@@ -97,6 +100,22 @@ internal class ExprCast(val arg: Operator.Expr, val cast: Ref.Cast) : Operator.E
97100
}
98101
}
99102

103+
/**
104+
* For now, we cannot cast from struct to anything else. Throw a type check exception.
105+
*/
106+
private fun castFromStruct(value: Datum, t: PType): Datum {
107+
throw TypeCheckException()
108+
}
109+
110+
@OptIn(PartiQLValueExperimental::class)
111+
private fun castFromUnknown(value: PartiQLValue, t: PType): PartiQLValue {
112+
return when (value) {
113+
is NullValue -> castFromNull(value, t)
114+
is MissingValue -> missingValue() // TODO: Is this allowed?
115+
else -> error("This shouldn't have happened")
116+
}
117+
}
118+
100119
@OptIn(PartiQLValueExperimental::class)
101120
private fun castFromNull(value: NullValue, t: PType): PartiQLValue {
102121
return when (t.kind) {

partiql-eval/src/test/kotlin/org/partiql/eval/internal/PartiQLEngineDefaultTest.kt

Lines changed: 34 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1311,7 +1311,16 @@ class PartiQLEngineDefaultTest {
13111311

13121312
internal fun assert() {
13131313
val permissiveResult = run(mode = PartiQLEngine.Mode.PERMISSIVE)
1314-
assert(expectedPermissive == permissiveResult.first) {
1314+
val assertionCondition = try {
1315+
expectedPermissive == permissiveResult.first
1316+
} catch (t: Throwable) {
1317+
val str = buildString {
1318+
appendLine("Test Name: $name")
1319+
PlanPrinter.append(this, permissiveResult.second)
1320+
}
1321+
throw RuntimeException(str, t)
1322+
}
1323+
assert(assertionCondition) {
13151324
comparisonString(expectedPermissive, permissiveResult.first, permissiveResult.second)
13161325
}
13171326
var error: Throwable? = null
@@ -1344,7 +1353,13 @@ class PartiQLEngineDefaultTest {
13441353
val prepared = engine.prepare(plan.plan, PartiQLEngine.Session(mapOf("memory" to connector), mode = mode))
13451354
when (val result = engine.execute(prepared)) {
13461355
is PartiQLResult.Value -> return result.value to plan.plan
1347-
is PartiQLResult.Error -> throw result.cause
1356+
is PartiQLResult.Error -> {
1357+
val str = buildString {
1358+
appendLine("Execution resulted in an unexpected error. Plan:")
1359+
PlanPrinter.append(this, plan.plan)
1360+
}
1361+
throw RuntimeException(str, result.cause)
1362+
}
13481363
}
13491364
}
13501365

@@ -1368,51 +1383,26 @@ class PartiQLEngineDefaultTest {
13681383
}
13691384

13701385
@Test
1386+
@Disabled
13711387
fun developmentTest() {
13721388
val tc = SuccessTestCase(
13731389
input = """
1374-
SELECT *
1375-
EXCLUDE
1376-
t.a.b.c[*].field_x
1377-
FROM [{
1378-
'a': {
1379-
'b': {
1380-
'c': [
1381-
{ -- c[0]; field_x to be removed
1382-
'field_x': 0,
1383-
'field_y': 0
1384-
},
1385-
{ -- c[1]; field_x to be removed
1386-
'field_x': 1,
1387-
'field_y': 1
1388-
},
1389-
{ -- c[2]; field_x to be removed
1390-
'field_x': 2,
1391-
'field_y': 2
1392-
}
1393-
]
1394-
}
1395-
}
1396-
}] AS t
1397-
""".trimIndent(),
1398-
expected = bagValue(
1399-
structValue(
1400-
"a" to structValue(
1401-
"b" to structValue(
1402-
"c" to listValue(
1403-
structValue(
1404-
"field_y" to int32Value(0)
1405-
),
1406-
structValue(
1407-
"field_y" to int32Value(1)
1408-
),
1409-
structValue(
1410-
"field_y" to int32Value(2)
1411-
)
1412-
)
1413-
)
1414-
)
1415-
)
1390+
SELECT VALUE
1391+
CASE x + 1
1392+
WHEN NULL THEN 'shouldnt be null'
1393+
WHEN MISSING THEN 'shouldnt be missing'
1394+
WHEN i THEN 'ONE'
1395+
WHEN f THEN 'TWO'
1396+
WHEN d THEN 'THREE'
1397+
ELSE '?'
1398+
END
1399+
FROM << i, f, d, null, missing >> AS x
1400+
""",
1401+
expected = boolValue(true),
1402+
globals = listOf(
1403+
SuccessTestCase.Global("i", "1"),
1404+
SuccessTestCase.Global("f", "2e0"),
1405+
SuccessTestCase.Global("d", "3.")
14161406
)
14171407
)
14181408
tc.assert()

partiql-planner/src/main/kotlin/org/partiql/planner/internal/Env.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import org.partiql.planner.internal.ir.rexOpCallDynamicCandidate
1616
import org.partiql.planner.internal.ir.rexOpCastResolved
1717
import org.partiql.planner.internal.ir.rexOpVarGlobal
1818
import org.partiql.planner.internal.typer.CompilerType
19-
import org.partiql.planner.internal.typer.TypeEnv.Companion.toPath
19+
import org.partiql.planner.internal.typer.Scope.Companion.toPath
2020
import org.partiql.spi.BindingCase
2121
import org.partiql.spi.BindingName
2222
import org.partiql.spi.BindingPath

partiql-planner/src/main/kotlin/org/partiql/planner/internal/FnResolver.kt

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package org.partiql.planner.internal
33
import org.partiql.planner.internal.casts.Coercions
44
import org.partiql.planner.internal.ir.Ref
55
import org.partiql.planner.internal.typer.CompilerType
6+
import org.partiql.planner.internal.typer.PlanTyper.Companion.toCType
67
import org.partiql.spi.fn.FnExperimental
78
import org.partiql.spi.fn.FnSignature
89
import org.partiql.types.PType.Kind
@@ -144,10 +145,14 @@ internal object FnResolver {
144145
exactInputTypes++
145146
continue
146147
}
147-
// 2. Match ANY, no coercion needed
148-
// TODO: Rewrite args in this scenario
149-
arg.kind == Kind.UNKNOWN || p.type.kind == Kind.DYNAMIC || arg.kind == Kind.DYNAMIC -> continue
150-
// 3. Check for a coercion
148+
// 2. Match ANY parameter, no coercion needed
149+
p.type.kind == Kind.DYNAMIC -> continue
150+
arg.kind == Kind.UNKNOWN -> continue
151+
// 3. Allow for ANY arguments
152+
arg.kind == Kind.DYNAMIC -> {
153+
mapping[i] = Ref.Cast(arg, p.type.toCType(), Ref.Cast.Safety.UNSAFE, true)
154+
}
155+
// 4. Check for a coercion
151156
else -> when (val coercion = Coercions.get(arg, p.type)) {
152157
null -> return null // short-circuit
153158
else -> mapping[i] = coercion

0 commit comments

Comments
 (0)