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 05f31e1b9..538161597 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 @@ -365,7 +365,7 @@ internal object PlanTransform : PlanBaseVisitor() { org.partiql.plan.Agg( FunctionSignature.Aggregation( "UNKNOWN_AGG::$name", - returns = PartiQLValueType.ANY, + returns = PartiQLValueType.ANY, // TODO: Make unknown or something similar parameters = emptyList() ) ) diff --git a/partiql-planner/src/main/kotlin/org/partiql/planner/internal/typer/DynamicTyper.kt b/partiql-planner/src/main/kotlin/org/partiql/planner/internal/typer/DynamicTyper.kt index eebbf3642..2adf62776 100644 --- a/partiql-planner/src/main/kotlin/org/partiql/planner/internal/typer/DynamicTyper.kt +++ b/partiql-planner/src/main/kotlin/org/partiql/planner/internal/typer/DynamicTyper.kt @@ -86,7 +86,7 @@ internal class DynamicTyper { } /** - * This adds non-unknown types (aka not NULL / MISSING literals) to the typing accumulator. + * This adds non-absent types (aka not NULL / MISSING literals) to the typing accumulator. * @param type */ private fun accumulate(type: StaticType) { 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 ba5c9cb15..71a38f6c3 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 @@ -122,6 +122,10 @@ internal class PlanTyper( return statementQuery(root) } + private companion object { + private val FUNCTIONS_HANDLING_MISSING = setOf("is_null", "is_missing", "eq", "and", "or", "not") + } + /** * Types the relational operators of a query expression. * @@ -462,21 +466,21 @@ internal class PlanTyper( return rex(ANY, rexOpErr("Collections must be indexed with integers, found ${key.type}")) } - // Check Root Type - if (!root.type.mayBeType() && !root.type.mayBeType()) { + // Get Element Type(s) + val elementTypes = root.type.allTypes.mapNotNull { type -> + when (type) { + is ListType -> type.elementType + is SexpType -> type.elementType + else -> null + } + } + + // Check that Root was LIST or SEXP by checking accumuated element types + if (elementTypes.isEmpty()) { handleAlwaysMissing() return rex(ANY, rexOpErr("Only lists and s-expressions can be indexed with integers, found ${root.type}")) } - - // Get Element Type - val elementTypes = root.type.allTypes.mapNotNull { type -> - if (type !is ListType && type !is SexpType) { - return@mapNotNull null - } - (type as CollectionType).elementType - }.toSet() - val finalType = unionOf(elementTypes) - return rex(finalType, rexOpPathIndex(root, key)) + return rex(unionOf(elementTypes), rexOpPathIndex(root, key)) } override fun visitRexOpPathKey(node: Rex.Op.Path.Key, ctx: StaticType?): Rex { @@ -625,7 +629,7 @@ internal class PlanTyper( // TODO: The V1 branch has support for isMissable and isMissingCall. This codebase, however, does not // have support for these concepts yet. This specific commit (see Git blame) does not seek to add this // functionality. Below is a work-around for the lack of "isMissable" and "isMissingCall" - if (match.signature.name !in listOf("is_null", "is_missing", "eq", "and", "or", "not")) { + if (match.signature.name !in FUNCTIONS_HANDLING_MISSING) { handleAlwaysMissing() } } diff --git a/test/partiql-tests b/test/partiql-tests index 233713b78..be88ae732 160000 --- a/test/partiql-tests +++ b/test/partiql-tests @@ -1 +1 @@ -Subproject commit 233713b7841eb559c4f4978f2955facf3c92c7d8 +Subproject commit be88ae732bec0388c88acab108a392f586094fc7