From 41a2f79a57f586c71f3db63114f8f288d3b6f376 Mon Sep 17 00:00:00 2001 From: "R. C. Howell" Date: Tue, 16 Apr 2024 18:24:15 -0700 Subject: [PATCH] Fixes to UNPIVOT normalization and empty struct typing --- .../org/partiql/ast/normalize/NormalizeFromSource.kt | 6 ++++-- .../org/partiql/planner/internal/typer/PlanTyper.kt | 11 +++-------- test/partiql-tests-runner/build.gradle.kts | 4 ++-- 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/partiql-ast/src/main/kotlin/org/partiql/ast/normalize/NormalizeFromSource.kt b/partiql-ast/src/main/kotlin/org/partiql/ast/normalize/NormalizeFromSource.kt index 081321f46d..fe2e2dc776 100644 --- a/partiql-ast/src/main/kotlin/org/partiql/ast/normalize/NormalizeFromSource.kt +++ b/partiql-ast/src/main/kotlin/org/partiql/ast/normalize/NormalizeFromSource.kt @@ -53,8 +53,10 @@ internal object NormalizeFromSource : AstPass { override fun visitFromValue(node: From.Value, ctx: Int): From { val expr = visitExpr(node.expr, ctx) as Expr val asAlias = node.asAlias ?: expr.toBinder(ctx) - return if (expr !== node.expr || asAlias !== node.asAlias) { - node.copy(expr = expr, asAlias = asAlias) + val atAlias = node.atAlias ?: expr.toBinder(ctx + 1) + val byAlias = node.byAlias ?: expr.toBinder(ctx + 2) + return if (expr !== node.expr || asAlias !== node.asAlias || atAlias !== node.atAlias || byAlias !== node.byAlias) { + node.copy(expr = expr, asAlias = asAlias, atAlias = atAlias, byAlias = byAlias) } else { node } 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 8c139be9f0..e50d600fd3 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 @@ -167,17 +167,13 @@ internal class PlanTyper( * TODO handle NULL|STRUCT type */ override fun visitRelOpUnpivot(node: Rel.Op.Unpivot, ctx: Rel.Type?): Rel { - // descend, with GLOBAL resolution strategy val rex = node.rex.type(emptyList(), outer, Scope.GLOBAL) - // key type, always a string. val kType = STRING - - // value type, possibly coerced. - val vType = rex.type.allTypes.map { type -> + val vTypes = rex.type.allTypes.map { type -> when (type) { is StructType -> { - if (type.contentClosed || type.constraints.contains(TupleConstraint.Open(false))) { + if ((type.contentClosed || type.constraints.contains(TupleConstraint.Open(false))) && type.fields.isNotEmpty()) { unionOf(type.fields.map { it.value }.toSet()).flatten() } else { ANY @@ -185,9 +181,8 @@ internal class PlanTyper( } else -> type } - }.let { - unionOf(it.toSet()).flatten() } + val vType = unionOf(vTypes.toSet()).flatten() // rewrite val type = ctx!!.copyWithSchema(listOf(kType, vType)) diff --git a/test/partiql-tests-runner/build.gradle.kts b/test/partiql-tests-runner/build.gradle.kts index 9fa06449da..6f9cb78b67 100644 --- a/test/partiql-tests-runner/build.gradle.kts +++ b/test/partiql-tests-runner/build.gradle.kts @@ -64,8 +64,8 @@ val generateTestReport by tasks.registering(Test::class) { environment(Env.PARTIQL_EQUIV, file("$tests/eval-equiv/").absolutePath) environment("conformanceReportDir", reportDir) include("org/partiql/runner/ConformanceTestEval.class", "org/partiql/runner/ConformanceTestLegacy.class") - if (project.hasProperty("Engine")) { - val engine = property("Engine")!! as String + if (project.hasProperty("engine")) { + val engine = project.property("engine")!! as String if (engine.toLowerCase() == "legacy") { exclude("org/partiql/runner/ConformanceTestEval.class") } else if (engine.toLowerCase() == "eval") {