From a07b6aa9fe61f97e1bd13215b38aea60c7629aad Mon Sep 17 00:00:00 2001 From: Yingtao Liu Date: Thu, 7 Dec 2023 18:31:17 -0800 Subject: [PATCH] fix typer/transfomrer --- .../internal/transforms/PlanTransform.kt | 4 +-- .../planner/internal/typer/PlanTyper.kt | 11 ++++++ .../internal/typer/path/SanityTests.kt | 28 +++++++++++++++ .../resources/inputs/basics/paths.sql | 34 +++++++++---------- 4 files changed, 58 insertions(+), 19 deletions(-) create mode 100644 partiql-planner/src/test/kotlin/org/partiql/planner/internal/typer/path/SanityTests.kt diff --git a/partiql-planner/src/main/kotlin/org/partiql/planner/internal/transforms/PlanTransform.kt b/partiql-planner/src/main/kotlin/org/partiql/planner/internal/transforms/PlanTransform.kt index 63ffb05af..b52698db6 100644 --- a/partiql-planner/src/main/kotlin/org/partiql/planner/internal/transforms/PlanTransform.kt +++ b/partiql-planner/src/main/kotlin/org/partiql/planner/internal/transforms/PlanTransform.kt @@ -49,7 +49,7 @@ internal object PlanTransform : PlanBaseVisitor() { override fun visitFnResolved(node: Fn.Resolved, ctx: ProblemCallback) = org.partiql.plan.fn(node.signature) override fun visitFnUnresolved(node: Fn.Unresolved, ctx: ProblemCallback): org.partiql.plan.Rex.Op { - return org.partiql.plan.Rex.Op.Err("Unresolved function") + error("Unresolved function ${node.identifier}") } override fun visitAgg(node: Agg, ctx: ProblemCallback) = super.visitAgg(node, ctx) as org.partiql.plan.Agg @@ -57,7 +57,7 @@ internal object PlanTransform : PlanBaseVisitor() { override fun visitAggResolved(node: Agg.Resolved, ctx: ProblemCallback) = org.partiql.plan.Agg(node.signature) override fun visitAggUnresolved(node: Agg.Unresolved, ctx: ProblemCallback): org.partiql.plan.Rex.Op { - return org.partiql.plan.Rex.Op.Err("Unresolved aggregation") + error("Unresolved aggregation ${node.identifier}") } override fun visitStatement(node: Statement, ctx: ProblemCallback) = diff --git a/partiql-planner/src/main/kotlin/org/partiql/planner/internal/typer/PlanTyper.kt b/partiql-planner/src/main/kotlin/org/partiql/planner/internal/typer/PlanTyper.kt index f757d2040..d81e42b6e 100644 --- a/partiql-planner/src/main/kotlin/org/partiql/planner/internal/typer/PlanTyper.kt +++ b/partiql-planner/src/main/kotlin/org/partiql/planner/internal/typer/PlanTyper.kt @@ -503,6 +503,17 @@ internal class PlanTyper( return rex(type, rexOpPath(root, newSteps)) } + // Default returns the original node, in some case we need the resolved node. + // i.e., the path step is a call node + override fun visitRexOpPathStep(node: Rex.Op.Path.Step, ctx: StaticType?): Rex.Op.Path.Step = + when (node) { + is Rex.Op.Path.Step.Index -> Rex.Op.Path.Step.Index(visitRex(node.key, ctx)) + is Rex.Op.Path.Step.Key -> Rex.Op.Path.Step.Key(visitRex(node.key, ctx)) + is Rex.Op.Path.Step.Symbol -> Rex.Op.Path.Step.Symbol(node.identifier) + is Rex.Op.Path.Step.Unpivot -> Rex.Op.Path.Step.Unpivot() + is Rex.Op.Path.Step.Wildcard -> Rex.Op.Path.Step.Wildcard() + } + /** * Resolve and type scalar function calls. * diff --git a/partiql-planner/src/test/kotlin/org/partiql/planner/internal/typer/path/SanityTests.kt b/partiql-planner/src/test/kotlin/org/partiql/planner/internal/typer/path/SanityTests.kt new file mode 100644 index 000000000..cbe7c7e3f --- /dev/null +++ b/partiql-planner/src/test/kotlin/org/partiql/planner/internal/typer/path/SanityTests.kt @@ -0,0 +1,28 @@ +package org.partiql.planner.internal.typer.path + +import org.junit.jupiter.api.DynamicContainer +import org.junit.jupiter.api.TestFactory +import org.partiql.planner.internal.typer.PartiQLTyperTestBase +import org.partiql.types.StaticType +import java.util.stream.Stream + +/** + * This test makes sure that the planner can resolve various path expression + */ +class SanityTests : PartiQLTyperTestBase() { + @TestFactory + fun path(): Stream { + val tests = buildList { + (0..14).forEach { + this.add("paths-${it.toString().padStart(2,'0')}") + } + }.map { inputs.get("basics", it)!! } + + val argsMap: Map>> = buildMap { + put(TestResult.Success(StaticType.ANY), setOf(listOf(StaticType.ANY, StaticType.ANY))) + put(TestResult.Failure, emptySet>()) + } + + return super.testGen("path", tests, argsMap) + } +} diff --git a/partiql-planner/src/testFixtures/resources/inputs/basics/paths.sql b/partiql-planner/src/testFixtures/resources/inputs/basics/paths.sql index 4837ace0b..6d8270bc4 100644 --- a/partiql-planner/src/testFixtures/resources/inputs/basics/paths.sql +++ b/partiql-planner/src/testFixtures/resources/inputs/basics/paths.sql @@ -4,67 +4,67 @@ --#[paths-00] -- tuple navigation -x.y; +t1.y; --#[paths-01] -- array navigation with literal -x[0]; +t1[0]; --#[paths-02] -- tuple navigation with array notation -x['y']; +t1['y']; --#[paths-03] -- tuple navigation (2) -x."y"; +t1."y"; --#[paths-04] -- tuple navigation with explicit cast as string -x[CAST(z AS STRING)]; +t1[CAST(t2 AS STRING)]; -- ---------------------------------------- -- Composition of Navigation (5 choose 3) -- ---------------------------------------- --#[paths-05] -x.y[0]['y']; +t1.y[0]['y']; --#[paths-06] -x.y[0]."y"; +t1.y[0]."y"; --#[paths-07] -x.y[0][CAST(z AS STRING)]; +t1.y[0][CAST(t2 AS STRING)]; --#[paths-08] -x.y['y']."y"; +t1.y['y']."y"; --#[paths-09] -x.y['y'][CAST(z AS STRING)]; +t1.y['y'][CAST(t2 AS STRING)]; --#[paths-10] -x.y."y"[CAST(z AS STRING)]; +t1.y."y"[CAST(t2 AS STRING)]; --#[paths-11] -x[0]['y']."y"; +t1[0]['y']."y"; --#[paths-12] -x[0]['y'][CAST(z AS STRING)]; +t1[0]['y'][CAST(t2 AS STRING)]; --#[paths-13] -x[0]."y"[CAST(z AS STRING)]; +t1[0]."y"[CAST(t2 AS STRING)]; --#[paths-14] -x['y']."y"[CAST(z AS STRING)]; +t1['y']."y"[CAST(t2 AS STRING)]; -- ---------------------------------------- -- Array Navigation with Expressions -- ---------------------------------------- --#[paths-15] -x[0+1]; +t1[0+1]; --#[paths-16] -x[ABS(1)]; +t1[ABS(1)]; -- ---------------------------------------- -- PartiQL Path Navigation (+SFW)