diff --git a/CHANGELOG.md b/CHANGELOG.md index f1e0ca1e7a..b92a7cde73 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,8 +28,25 @@ Thank you to all who have contributed! ### Added ### Changed +- **Behavioral change**: The planner now does NOT support the NullType and MissingType variants of StaticType. The logic +is that the null and missing values are part of *all* data types. Therefore, one must assume that the types returned by +the planner allow for NULL and MISSING values. Similarly, the testFixtures Ion-encoded test resources +representing the catalog do not use "null" or "missing". ### Deprecated +- We have deprecated `org.partiql.type.NullType` and `org.partiql.type.MissingType`. Please see the corresponding +information in the "Changed" section. In relation to the deprecation of the above, the following APIs have also +been deprecated: + - `org.partiql.type.StaticType.MISSING` + - `org.partiql.type.StaticType.NULL` + - `org.partiql.type.StaticType.NULL_OR_MISSING` + - `org.partiql.type.StaticType.asNullable()` + - `org.partiql.type.StaticType.isNullable()` + - `org.partiql.type.StaticType.isMissable()` + - `org.partiql.type.StaticType.asOptional()` + - `org.partiql.type.AnyOfType()` + - `org.partiql.value.PartiQLValueType.NULL` + - `org.partiql.value.PartiQLValueType.MISSING` ### Fixed 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 a814cc7a35..05f31e1b94 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.MISSING, + returns = PartiQLValueType.ANY, parameters = emptyList() ) ) diff --git a/partiql-planner/src/main/kotlin/org/partiql/planner/internal/transforms/RexConverter.kt b/partiql-planner/src/main/kotlin/org/partiql/planner/internal/transforms/RexConverter.kt index 8c30083c11..ec696d417c 100644 --- a/partiql-planner/src/main/kotlin/org/partiql/planner/internal/transforms/RexConverter.kt +++ b/partiql-planner/src/main/kotlin/org/partiql/planner/internal/transforms/RexConverter.kt @@ -42,7 +42,6 @@ import org.partiql.planner.internal.ir.rexOpStructField import org.partiql.planner.internal.ir.rexOpSubquery import org.partiql.planner.internal.ir.rexOpTupleUnion import org.partiql.planner.internal.ir.rexOpVarUnresolved -import org.partiql.planner.internal.typer.toNonNullStaticType import org.partiql.planner.internal.typer.toStaticType import org.partiql.types.StaticType import org.partiql.types.TimeType @@ -70,10 +69,7 @@ internal object RexConverter { throw IllegalArgumentException("unsupported rex $node") override fun visitExprLit(node: Expr.Lit, context: Env): Rex { - val type = when (node.value.isNull) { - true -> node.value.type.toStaticType() - else -> node.value.type.toNonNullStaticType() - } + val type = node.value.type.toStaticType() val op = rexOpLit(node.value) return rex(type, op) } @@ -82,10 +78,7 @@ internal object RexConverter { val value = PartiQLValueIonReaderBuilder .standard().build(node.value).read() - val type = when (value.isNull) { - true -> value.type.toStaticType() - else -> value.type.toNonNullStaticType() - } + val type = value.type.toStaticType() return rex(type, rexOpLit(value)) } @@ -287,7 +280,7 @@ internal object RexConverter { }.toMutableList() val defaultRex = when (val default = node.default) { - null -> rex(type = StaticType.NULL, op = rexOpLit(value = nullValue())) + null -> rex(type = StaticType.ANY, op = rexOpLit(value = nullValue())) else -> visitExprCoerce(default, context) } val op = rexOpCase(branches = branches, default = defaultRex) @@ -528,8 +521,8 @@ internal object RexConverter { val type = node.asType val arg0 = visitExprCoerce(node.value, ctx) return when (type) { - is Type.NullType -> rex(StaticType.NULL, call("cast_null", arg0)) - is Type.Missing -> rex(StaticType.MISSING, call("cast_missing", arg0)) + is Type.NullType -> error("Cannot cast any value to NULL") + is Type.Missing -> error("Cannot cast any value to MISSING") is Type.Bool -> rex(StaticType.BOOL, call("cast_bool", arg0)) is Type.Tinyint -> TODO("Static Type does not have TINYINT type") is Type.Smallint, is Type.Int2 -> rex(StaticType.INT2, call("cast_int16", arg0)) 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 9ae72cc6ad..dc846b7069 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 @@ -2,8 +2,7 @@ package org.partiql.planner.internal.typer -import org.partiql.types.MissingType -import org.partiql.types.NullType +import org.partiql.planner.internal.ir.Rex import org.partiql.types.StaticType import org.partiql.value.PartiQLValueExperimental import org.partiql.value.PartiQLValueType @@ -27,8 +26,6 @@ import org.partiql.value.PartiQLValueType.INT64 import org.partiql.value.PartiQLValueType.INT8 import org.partiql.value.PartiQLValueType.INTERVAL import org.partiql.value.PartiQLValueType.LIST -import org.partiql.value.PartiQLValueType.MISSING -import org.partiql.value.PartiQLValueType.NULL import org.partiql.value.PartiQLValueType.SEXP import org.partiql.value.PartiQLValueType.STRING import org.partiql.value.PartiQLValueType.STRUCT @@ -57,51 +54,55 @@ internal class DynamicTyper { private var supertype: PartiQLValueType? = null private var args = mutableListOf() - private var nullable = false - private var missable = false private val types = mutableSetOf() /** - * This primarily unpacks a StaticType because of NULL, MISSING. - * - * - T - * - NULL - * - MISSING - * - (NULL) - * - (MISSING) - * - (T..) - * - (T..|NULL) - * - (T..|MISSING) - * - (T..|NULL|MISSING) - * - (NULL|MISSING) - * + * Adds the [rex]'s [Rex.type] to the typing accumulator (if the [rex] is not a literal NULL/MISSING). + */ + fun accumulate(rex: Rex) { + when (rex.isLiteralAbsent()) { + true -> accumulateUnknown() + false -> accumulate(rex.type) + } + } + + /** + * Checks for literal NULL or MISSING. + */ + private fun Rex.isLiteralAbsent(): Boolean { + val op = this.op + return op is Rex.Op.Lit && (op.value.type == PartiQLValueType.MISSING || op.value.type == PartiQLValueType.NULL) + } + + /** + * When a literal null or missing value is present in the query, its type is unknown. Therefore, its type must be + * inferred. This function ignores literal null/missing values, yet adds their indices to know how to return the + * mapping. + */ + private fun accumulateUnknown() { + args.add(ANY) + } + + /** + * This adds non-unknown types (aka not NULL / MISSING literals) to the typing accumulator. * @param type */ - fun accumulate(type: StaticType) { - val nonAbsentTypes = mutableSetOf() + private fun accumulate(type: StaticType) { val flatType = type.flatten() if (flatType == StaticType.ANY) { - // Use ANY runtime; do not expand ANY types.add(flatType) args.add(ANY) calculate(ANY) return } - for (t in flatType.allTypes) { - when (t) { - is NullType -> nullable = true - is MissingType -> missable = true - else -> nonAbsentTypes.add(t) - } - } - when (nonAbsentTypes.size) { + val allTypes = flatType.allTypes + when (allTypes.size) { 0 -> { - // Ignore in calculating supertype. - args.add(NULL) + error("This should not have happened.") } 1 -> { // Had single type - val single = nonAbsentTypes.first() + val single = allTypes.first() val singleRuntime = single.toRuntimeType() types.add(single) args.add(singleRuntime) @@ -109,7 +110,7 @@ internal class DynamicTyper { } else -> { // Had a union; use ANY runtime - types.addAll(nonAbsentTypes) + types.addAll(allTypes) args.add(ANY) calculate(ANY) } @@ -124,31 +125,20 @@ internal class DynamicTyper { * @return */ fun mapping(): Pair>?> { - val modifiers = mutableSetOf() - if (nullable) modifiers.add(StaticType.NULL) - if (missable) modifiers.add(StaticType.MISSING) // If at top supertype, then return union of all accumulated types if (supertype == ANY) { - return StaticType.unionOf(types + modifiers).flatten() to null + return StaticType.unionOf(types).flatten() to null } // If a collection, then return union of all accumulated types as these coercion rules are not defined by SQL. if (supertype == STRUCT || supertype == BAG || supertype == LIST || supertype == SEXP) { - return StaticType.unionOf(types + modifiers) to null + return StaticType.unionOf(types) to null } // If not initialized, then return null, missing, or null|missing. - val s = supertype - if (s == null) { - val t = if (modifiers.isEmpty()) StaticType.MISSING else StaticType.unionOf(modifiers).flatten() - return t to null - } + val s = supertype ?: return StaticType.ANY to null // Otherwise, return the supertype along with the coercion mapping - val type = s.toNonNullStaticType() + val type = s.toStaticType() val mapping = args.map { it to s } - return if (modifiers.isEmpty()) { - type to mapping - } else { - StaticType.unionOf(setOf(type) + modifiers).flatten() to mapping - } + return type to mapping } private fun calculate(type: PartiQLValueType) { @@ -163,7 +153,7 @@ internal class DynamicTyper { // Lookup and set the new minimum common supertype supertype = when { type == ANY -> type - type == NULL || type == MISSING || s == type -> return // skip + s == type -> return // skip else -> graph[s][type] ?: ANY // lookup, if missing then go to top. } } @@ -206,8 +196,6 @@ internal class DynamicTyper { graph[type] = arrayOfNulls(N) } graph[ANY] = edges() - graph[NULL] = edges() - graph[MISSING] = edges() graph[BOOL] = edges( BOOL to BOOL ) diff --git a/partiql-planner/src/main/kotlin/org/partiql/planner/internal/typer/FnResolver.kt b/partiql-planner/src/main/kotlin/org/partiql/planner/internal/typer/FnResolver.kt index 0cf04f2c59..b4d0cd1229 100644 --- a/partiql-planner/src/main/kotlin/org/partiql/planner/internal/typer/FnResolver.kt +++ b/partiql-planner/src/main/kotlin/org/partiql/planner/internal/typer/FnResolver.kt @@ -5,9 +5,6 @@ import org.partiql.planner.internal.ir.Agg import org.partiql.planner.internal.ir.Fn import org.partiql.planner.internal.ir.Identifier import org.partiql.planner.internal.ir.Rex -import org.partiql.planner.internal.typer.FnResolver.Companion.compareTo -import org.partiql.types.AnyOfType -import org.partiql.types.NullType import org.partiql.types.StaticType import org.partiql.types.function.FunctionParameter import org.partiql.types.function.FunctionSignature @@ -33,8 +30,6 @@ import org.partiql.value.PartiQLValueType.INT64 import org.partiql.value.PartiQLValueType.INT8 import org.partiql.value.PartiQLValueType.INTERVAL import org.partiql.value.PartiQLValueType.LIST -import org.partiql.value.PartiQLValueType.MISSING -import org.partiql.value.PartiQLValueType.NULL import org.partiql.value.PartiQLValueType.SEXP import org.partiql.value.PartiQLValueType.STRING import org.partiql.value.PartiQLValueType.STRUCT @@ -76,27 +71,19 @@ internal sealed class FnMatch { * * @property signature * @property mapping - * @property isMissable TRUE when anyone of the arguments _could_ be MISSING. We *always* propagate MISSING. */ public data class Ok( public val signature: T, public val mapping: Mapping, - public val isMissable: Boolean, ) : FnMatch() /** * This represents dynamic dispatch. * * @property candidates an ordered list of potentially applicable functions to dispatch dynamically. - * @property isMissable TRUE when the argument permutations may not definitively invoke one of the candidates. You - * can think of [isMissable] as being the same as "not exhaustive". For example, if we have ABS(INT | STRING), then - * this function call [isMissable] because there isn't an `ABS(STRING)` function signature AKA we haven't exhausted - * all the arguments. On the other hand, take an "exhaustive" scenario: ABS(INT | DEC). In this case, [isMissable] - * is false because we have functions for each potential argument AKA we have exhausted the arguments. */ public data class Dynamic( - public val candidates: List>, - public val isMissable: Boolean + public val candidates: List> ) : FnMatch() public data class Error( @@ -162,12 +149,8 @@ internal class FnResolver(private val header: Header) { */ public fun resolveFn(fn: Fn.Unresolved, args: List): FnMatch { val candidates = lookup(fn) - var canReturnMissing = false val parameterPermutations = buildArgumentPermutations(args.map { it.type }).mapNotNull { argList -> argList.mapIndexed { i, arg -> - if (arg.isMissable()) { - canReturnMissing = true - } // Skip over if we cannot convert type to runtime type. val argType = arg.toRuntimeTypeOrNull() ?: return@mapNotNull null FunctionParameter("arg-$i", argType) @@ -176,12 +159,10 @@ internal class FnResolver(private val header: Header) { val potentialFunctions = parameterPermutations.mapNotNull { parameters -> when (val match = match(candidates, parameters)) { null -> { - canReturnMissing = true null } else -> { - val isMissable = canReturnMissing || isUnsafeCast(match.signature.specific) - FnMatch.Ok(match.signature, match.mapping, isMissable) + FnMatch.Ok(match.signature, match.mapping) } } } @@ -190,18 +171,12 @@ internal class FnResolver(private val header: Header) { return when (orderedUniqueFunctions.size) { 0 -> FnMatch.Error(fn.identifier, args, candidates) 1 -> orderedUniqueFunctions.first() - else -> FnMatch.Dynamic(orderedUniqueFunctions, canReturnMissing) + else -> FnMatch.Dynamic(orderedUniqueFunctions) } } private fun buildArgumentPermutations(args: List): List> { - val flattenedArgs = args.map { - if (it is AnyOfType) { - it.flatten().allTypes.filter { it !is NullType } - } else { - it.flatten().allTypes - } - } + val flattenedArgs = args.map { it.flatten().allTypes } return buildArgumentPermutations(flattenedArgs, accumulator = emptyList()) } @@ -229,19 +204,13 @@ internal class FnResolver(private val header: Header) { */ public fun resolveAgg(agg: Agg.Unresolved, args: List): FnMatch { val candidates = lookup(agg) - var hadMissingArg = false val parameters = args.mapIndexed { i, arg -> - if (!hadMissingArg && arg.type.isMissable()) { - hadMissingArg = true - } FunctionParameter("arg-$i", arg.type.toRuntimeType()) } - val match = match(candidates, parameters) - return when (match) { + return when (val match = match(candidates, parameters)) { null -> FnMatch.Error(agg.identifier, args, candidates) else -> { - val isMissable = hadMissingArg || isUnsafeCast(match.signature.specific) - FnMatch.Ok(match.signature, match.mapping, isMissable) + FnMatch.Ok(match.signature, match.mapping) } } } @@ -290,9 +259,7 @@ internal class FnResolver(private val header: Header) { a.type == p.type -> mapping.add(null) // 2. Match ANY, no coercion needed p.type == ANY -> mapping.add(null) - // 3. Match NULL argument - a.type == NULL -> mapping.add(null) - // 4. Check for a coercion + // 3. Check for a coercion else -> { val coercion = lookupCoercion(a.type, p.type) when (coercion) { @@ -440,8 +407,10 @@ internal class FnResolver(private val header: Header) { // This is not explicitly defined in the PartiQL Specification!! // This does not imply the ability to CAST; this defines function resolution behavior. private val precedence: Map = listOf( - NULL, - MISSING, + @Suppress("DEPRECATION") + PartiQLValueType.NULL, // TODO: Remove + @Suppress("DEPRECATION") + PartiQLValueType.MISSING, // TODO: Remove BOOL, INT8, INT16, 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 3b275d9d39..e293882505 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 @@ -33,7 +33,6 @@ import org.partiql.planner.internal.ir.aggResolved import org.partiql.planner.internal.ir.fnResolved import org.partiql.planner.internal.ir.identifierSymbol import org.partiql.planner.internal.ir.rel -import org.partiql.planner.internal.ir.relBinding import org.partiql.planner.internal.ir.relOpAggregate import org.partiql.planner.internal.ir.relOpAggregateCall import org.partiql.planner.internal.ir.relOpDistinct @@ -81,14 +80,10 @@ import org.partiql.types.BoolType import org.partiql.types.CollectionType import org.partiql.types.IntType import org.partiql.types.ListType -import org.partiql.types.MissingType -import org.partiql.types.NullType import org.partiql.types.SexpType import org.partiql.types.StaticType import org.partiql.types.StaticType.Companion.ANY import org.partiql.types.StaticType.Companion.BOOL -import org.partiql.types.StaticType.Companion.MISSING -import org.partiql.types.StaticType.Companion.NULL import org.partiql.types.StaticType.Companion.STRING import org.partiql.types.StaticType.Companion.unionOf import org.partiql.types.StringType @@ -97,9 +92,9 @@ import org.partiql.types.TupleConstraint import org.partiql.types.function.FunctionSignature import org.partiql.value.BoolValue import org.partiql.value.PartiQLValueExperimental +import org.partiql.value.PartiQLValueType import org.partiql.value.TextValue import org.partiql.value.boolValue -import org.partiql.value.missingValue import org.partiql.value.stringValue /** @@ -301,14 +296,7 @@ internal class PlanTyper( val rhs = visitRel(node.rhs, ctx) // Calculate output schema given JOIN type - val l = lhs.type.schema - val r = rhs.type.schema - val schema = when (node.type) { - Rel.Op.Join.Type.INNER -> l + r - Rel.Op.Join.Type.LEFT -> l + r.pad() - Rel.Op.Join.Type.RIGHT -> l.pad() + r - Rel.Op.Join.Type.FULL -> l.pad() + r.pad() - } + val schema = lhs.type.schema + rhs.type.schema val type = relType(schema, ctx!!.props) // Type the condition on the output schema @@ -467,16 +455,25 @@ internal class PlanTyper( override fun visitRexOpPathIndex(node: Rex.Op.Path.Index, ctx: StaticType?): Rex { val root = visitRex(node.root, node.root.type) val key = visitRex(node.key, node.key.type) - if (key.type !is IntType) { + + // Check Index Type + if (!key.type.mayBeType()) { + handleAlwaysMissing() + return rex(ANY, rexOpErr("Collections must be indexed with integers, found ${key.type}")) + } + + // Check Root Type + if (!root.type.mayBeType() && !root.type.mayBeType()) { handleAlwaysMissing() - return rex(MISSING, rexOpErr("Collections must be indexed with integers, found ${key.type}")) + return rex(ANY, rexOpErr("Only lists and s-expressions can be indexed with integers, found ${root.type}")) } - val elementTypes = root.type.allTypes.map { type -> - val rootType = type as? CollectionType ?: return@map MISSING - if (rootType !is ListType && rootType !is SexpType) { - return@map MISSING + + // Get Element Type + val elementTypes = root.type.allTypes.mapNotNull { type -> + if (type !is ListType && type !is SexpType) { + return@mapNotNull null } - rootType.elementType + (type as CollectionType).elementType }.toSet() val finalType = unionOf(elementTypes).flatten() return rex(finalType.swallowAny(), rexOpPathIndex(root, key)) @@ -487,26 +484,25 @@ internal class PlanTyper( val key = visitRex(node.key, node.key.type) // Check Key Type - val toAddTypes = key.type.allTypes.mapNotNull { keyType -> - when (keyType) { - is StringType -> null - is NullType -> NULL - else -> MISSING - } - } - if (toAddTypes.size == key.type.allTypes.size && toAddTypes.all { it is MissingType }) { + if (!key.type.mayBeType()) { handleAlwaysMissing() - return rex(MISSING, rexOpErr("Expected string but found: ${key.type}")) + return rex(ANY, rexOpErr("Expected string but found: ${key.type}.")) } - val pathTypes = root.type.allTypes.map { type -> - val struct = type as? StructType ?: return@map MISSING + // Check Root Type + if (!root.type.mayBeType()) { + handleAlwaysMissing() + return rex(ANY, rexOpErr("Key lookup may only occur on structs, not ${root.type}.")) + } + // Get Element Type + val elementType = root.type.inferListNotNull { type -> + val struct = type as? StructType ?: return@inferListNotNull null if (key.op is Rex.Op.Lit) { val lit = key.op.value if (lit is TextValue<*> && !lit.isNull) { val id = identifierSymbol(lit.string!!, Identifier.CaseSensitivity.SENSITIVE) - inferStructLookup(struct, id).first + inferStructLookup(struct, id)?.first } else { error("Expected text literal, but got $lit") } @@ -515,20 +511,31 @@ internal class PlanTyper( // we might improve upon this with some constant folding prior to typing ANY } - }.toSet() - val finalType = unionOf(pathTypes + toAddTypes).flatten() - return rex(finalType.swallowAny(), rexOpPathKey(root, key)) + } + if (elementType.isEmpty()) { + handleAlwaysMissing() + return rex(ANY, rexOpPathKey(root, key)) + } + // TODO: SwallowAny should happen by default + return rex(unionOf(elementType).swallowAny(), rexOpPathKey(root, key)) } override fun visitRexOpPathSymbol(node: Rex.Op.Path.Symbol, ctx: StaticType?): Rex { val root = visitRex(node.root, node.root.type) - val paths = root.type.allTypes.map { type -> - val struct = type as? StructType ?: return@map rex(MISSING, rexOpLit(missingValue())) + // Check Root Type + if (!root.type.mayBeType()) { + handleAlwaysMissing() + return rex(ANY, rexOpErr("Symbol lookup may only occur on structs, not ${root.type}.")) + } + + // Get Element Types + val paths = root.type.inferRexListNotNull { type -> + val struct = type as? StructType ?: return@inferRexListNotNull null val (pathType, replacementId) = inferStructLookup( struct, identifierSymbol(node.key, Identifier.CaseSensitivity.INSENSITIVE) - ) + ) ?: return@inferRexListNotNull null when (replacementId.caseSensitivity) { Identifier.CaseSensitivity.INSENSITIVE -> rex(pathType, rexOpPathSymbol(root, replacementId.symbol)) Identifier.CaseSensitivity.SENSITIVE -> rex( @@ -537,11 +544,21 @@ internal class PlanTyper( ) } } - val type = unionOf(paths.map { it.type }.toSet()).flatten() + // Determine output type + val type = when (paths.size) { + // Escape early since no inference could be made + 0 -> { + handleAlwaysMissing() + return rex(ANY, Rex.Op.Path.Symbol(root, node.key)) + } + // TODO: Flatten() should occur by default + else -> unionOf(paths.map { it.type }.toSet()).flatten() + } // replace step only if all are disambiguated + val allElementsInferred = paths.size == root.type.allTypes.size val firstPathOp = paths.first().op - val replacementOp = when (paths.map { it.op }.all { it == firstPathOp }) { + val replacementOp = when (allElementsInferred && paths.map { it.op }.all { it == firstPathOp }) { true -> firstPathOp false -> rexOpPathSymbol(root, node.key) } @@ -562,15 +579,6 @@ internal class PlanTyper( private fun rexString(str: String) = rex(STRING, rexOpLit(stringValue(str))) - override fun visitRexOpPath(node: Rex.Op.Path, ctx: StaticType?): Rex { - val path = super.visitRexOpPath(node, ctx) as Rex - if (path.type == MISSING) { - handleAlwaysMissing() - return rexErr("Path always returns missing $node") - } - return path - } - /** * Resolve and type scalar function calls. * @@ -584,19 +592,15 @@ internal class PlanTyper( // Type the arguments val fn = node.fn as Fn.Unresolved - val isNotMissable = fn.isNotMissable() val args = node.args.map { visitRex(it, null) } // Try to match the arguments to functions defined in the catalog return when (val match = env.resolveFn(fn, args)) { - is FnMatch.Ok -> toRexCall(match, args, isNotMissable) + is FnMatch.Ok -> toRexCall(match, args) is FnMatch.Dynamic -> { val types = mutableSetOf() - if (match.isMissable && !isNotMissable) { - types.add(MISSING) - } val candidates = match.candidates.map { candidate -> - val rex = toRexCall(candidate, args, isNotMissable) + val rex = toRexCall(candidate, args) val staticCall = rex.op as? Rex.Op.Call.Static ?: error("ToRexCall should always return a static call.") val resolvedFn = staticCall.fn as? Fn.Resolved ?: error("This should have been resolved") @@ -605,7 +609,7 @@ internal class PlanTyper( rexOpCallDynamicCandidate(fn = resolvedFn, coercions = coercions) } val op = rexOpCallDynamic(args = args, candidates = candidates) - rex(type = StaticType.unionOf(types).flatten(), op = op) + rex(type = unionOf(types).flatten(), op = op) } is FnMatch.Error -> { handleUnknownFunction(match) @@ -621,71 +625,29 @@ internal class PlanTyper( private fun toRexCall( match: FnMatch.Ok, args: List, - isNotMissable: Boolean, ): Rex { // Found a match! val newFn = fnResolved(match.signature) val newArgs = rewriteFnArgs(match.mapping, args) - val returns = newFn.signature.returns - // 7.1 All functions return MISSING when one of their inputs is MISSING (except `=`) - newArgs.forEach { - if (it.type == MissingType && !isNotMissable) { - handleAlwaysMissing() - return rex(MISSING, rexOpCallStatic(newFn, newArgs)) - } + // Check literal missing inputs + val argAlwaysMissing = args.any { + val op = it.op as? Rex.Op.Lit ?: return@any false + op.value.type == PartiQLValueType.MISSING } - - // If a function is NOT Missable (i.e., does not propagate MISSING) - // then treat MISSING as null. - var isMissing = false - var isMissable = false - if (isNotMissable) { - if (newArgs.any { it.type is MissingType }) { - isMissing = true - } else if (newArgs.any { it.type.isMissable() }) { - isMissable = true - } - } - - // Determine the nullability of the return type - var isNull = false // True iff NULL CALL and has a NULL arg - var isNullable = false // True iff NULL CALL and has a NULLABLE arg; or is a NULLABLE operator - if (newFn.signature.isNullCall) { - if (isMissing) { - isNull = true - } else if (isMissable) { - isNullable = true - } else { - for (arg in newArgs) { - if (arg.type is NullType) { - isNull = true - break - } - if (arg.type.isNullable()) { - isNullable = true - break - } - } + if (argAlwaysMissing) { + // 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")) { + handleAlwaysMissing() } } - isNullable = isNullable || newFn.signature.isNullable - // Return type with calculated nullability - var type = when { - isNull -> NULL - isNullable -> returns.toStaticType() - else -> returns.toNonNullStaticType() - } - - // Some operators can return MISSING during runtime - if (match.isMissable && !isNotMissable) { - type = StaticType.unionOf(type, MISSING) - } - - // Finally, rewrite this node + // Type return + val returns = newFn.signature.returns val op = rexOpCallStatic(newFn, newArgs) - return rex(type.flatten(), op) + return rex(returns.toStaticType().flatten(), op) } override fun visitRexOpCase(node: Rex.Op.Case, ctx: StaticType?): Rex { @@ -699,34 +661,24 @@ internal class PlanTyper( var branch = oldBranches[i] branch = visitRexOpCaseBranch(branch, branch.rex.type) - // Check if branch condition is a literal - if (boolOrNull(branch.condition.op) == false) { - continue // prune - } - // Emit typing error if a branch condition is never a boolean (prune) - if (!canBeBoolean(branch.condition.type)) { + if (!branch.condition.type.mayBeType()) { onProblem.invoke( Problem( UNKNOWN_PROBLEM_LOCATION, PlanningProblemDetails.IncompatibleTypesForOp(branch.condition.type.allTypes, "CASE_WHEN") ) ) - // prune, always false - continue } - // Accumulate typing information - typer.accumulate(branch.rex.type) + // Accumulate typing information, but skip if literal NULL or MISSING + typer.accumulate(branch.rex) newBranches.add(branch) } // Rewrite ELSE branch var newDefault = visitRex(node.default, null) - if (newBranches.isEmpty()) { - return newDefault - } - typer.accumulate(newDefault.type) + typer.accumulate(newDefault) // Compute the CASE-WHEN type from the accumulator val (type, mapping) = typer.mapping() @@ -775,9 +727,7 @@ internal class PlanTyper( override fun visitRexOpCoalesce(node: Rex.Op.Coalesce, ctx: StaticType?): Rex { val args = node.args.map { visitRex(it, it.type) }.toMutableList() val typer = DynamicTyper() - args.forEach { v -> - typer.accumulate(v.type) - } + args.forEach { v -> typer.accumulate(v) } val (type, mapping) = typer.mapping() if (mapping != null) { assert(mapping.size == args.size) { "Coercion mappings `len ${mapping.size}` did not match the number of COALESCE arguments `len ${args.size}`" } @@ -804,25 +754,14 @@ internal class PlanTyper( val value = visitRex(node.value, node.value.type) val nullifier = visitRex(node.nullifier, node.nullifier.type) val typer = DynamicTyper() - typer.accumulate(NULL) - typer.accumulate(value.type) + + // Accumulate typing information + typer.accumulate(value) val (type, _) = typer.mapping() val op = rexOpNullif(value, nullifier) return rex(type, op) } - /** - * In this context, Boolean means PartiQLValueType Bool, which can be nullable. - * Hence, we permit Static Type BOOL, Static Type NULL, Static Type Missing here. - */ - private fun canBeBoolean(type: StaticType): Boolean { - return type.flatten().allTypes.any { - // TODO: This is a quick fix to unblock the typing or case expression. - // We need to model the truth value better in typer. - it is BoolType || it is NullType || it is MissingType - } - } - /** * Returns the boolean value of the expression. For now, only handle literals. */ @@ -873,7 +812,7 @@ internal class PlanTyper( } val ref = call.args.getOrNull(0) ?: error("IS STRUCT requires an argument.") // Replace the result's type - val type = AnyOfType(ref.type.allTypes.filterIsInstance().toSet()) + val type = unionOf(ref.type.allTypes.filterIsInstance().toSet()) val replacementVal = ref.copy(type = type) when (ref.op is Rex.Op.Var.Resolved) { true -> RexReplacer.replace(result, ref, replacementVal) @@ -897,7 +836,7 @@ internal class PlanTyper( } // Replace the result's type - val type = AnyOfType(ref.type.allTypes.filterIsInstance().toSet()).flatten() + val type = unionOf(ref.type.allTypes.filterIsInstance().toSet()).flatten() val replacementVal = ref.copy(type = type) val rex = when (ref.op is Rex.Op.Var.Resolved) { true -> RexReplacer.replace(result, ref, replacementVal) @@ -909,9 +848,10 @@ internal class PlanTyper( } override fun visitRexOpCollection(node: Rex.Op.Collection, ctx: StaticType?): Rex { + // Check Type if (ctx!! !is CollectionType) { handleUnexpectedType(ctx, setOf(StaticType.LIST, StaticType.BAG, StaticType.SEXP)) - return rex(StaticType.NULL_OR_MISSING, rexOpErr("Expected collection type")) + return rex(ANY, rexOpErr("Expected collection type")) } val values = node.values.map { visitRex(it, it.type) } val t = when (values.size) { @@ -1059,10 +999,14 @@ internal class PlanTyper( ) else -> { val argTypes = args.map { it.type } - val potentialTypes = buildArgumentPermutations(argTypes).map { argumentList -> + val anyArgIsNotStruct = argTypes.any { argType -> !argType.mayBeType() } + if (anyArgIsNotStruct) { + handleAlwaysMissing() + } + val potentialTypes = buildArgumentPermutations(argTypes).mapNotNull { argumentList -> calculateTupleUnionOutputType(argumentList) } - StaticType.unionOf(potentialTypes.toSet()).flatten() + unionOf(potentialTypes.toSet()).flatten() } } val op = rexOpTupleUnion(args) @@ -1083,8 +1027,7 @@ internal class PlanTyper( * * The signature of TUPLEUNION is: (LIST) -> STRUCT. * - * If any of the arguments are NULL (or potentially NULL), we return NULL. - * If any of the arguments are non-struct, we return MISSING. + * If any of the arguments are not a struct, we return null. * * Now, assuming all the other arguments are STRUCT, then we compute the output based on a number of factors: * - closed content @@ -1096,13 +1039,12 @@ internal class PlanTyper( * If all arguments contain unique attributes AND all arguments are closed AND no fields clash, the output has * unique attributes. */ - private fun calculateTupleUnionOutputType(args: List): StaticType { + private fun calculateTupleUnionOutputType(args: List): StaticType? { val structFields = mutableListOf() var structAmount = 0 var structIsClosed = true var structIsOrdered = true var uniqueAttrs = true - val possibleOutputTypes = mutableListOf() args.forEach { arg -> when (arg) { is StructType -> { @@ -1119,13 +1061,9 @@ internal class PlanTyper( PlanningProblemDetails.CompileError("TupleUnion wasn't normalized to exclude union types.") ) ) - possibleOutputTypes.add(MISSING) - } - is NullType -> { - return NULL } else -> { - return MISSING + return null } } } @@ -1205,10 +1143,10 @@ internal class PlanTyper( /** * Logic is as follows: * 1. If [struct] is closed and ordered: - * - If no item is found, return [MissingType] + * - If no item is found, return [AnyType] and reports always missing value * - Else, grab first matching item and make sensitive. * 2. If [struct] is closed - * - AND no item is found, return [MissingType] + * - AND no item is found, return [AnyType] and reports always missing value * - AND only one item is present -> grab item and make sensitive. * - AND more than one item is present, keep sensitivity and grab item. * 3. If [struct] is open, return [AnyType] @@ -1216,7 +1154,7 @@ internal class PlanTyper( * @return a [Pair] where the [Pair.first] represents the type of the [step] and the [Pair.second] represents * the disambiguated [key]. */ - private fun inferStructLookup(struct: StructType, key: Identifier.Symbol): Pair { + private fun inferStructLookup(struct: StructType, key: Identifier.Symbol): Pair? { val binding = key.toBindingName() val isClosed = struct.constraints.contains(TupleConstraint.Open(false)) val isOrdered = struct.constraints.contains(TupleConstraint.Ordered) @@ -1225,13 +1163,17 @@ internal class PlanTyper( isClosed && isOrdered -> { struct.fields.firstOrNull { entry -> binding.isEquivalentTo(entry.key) }?.let { (sensitive(it.key) to it.value) - } ?: (key to MISSING) + } ?: run { + return null + } } // 2. Struct is closed isClosed -> { val matches = struct.fields.filter { entry -> binding.isEquivalentTo(entry.key) } when (matches.size) { - 0 -> (key to MISSING) + 0 -> { + return null + } 1 -> matches.first().let { (sensitive(it.key) to it.value) } else -> { val firstKey = matches.first().key @@ -1239,12 +1181,12 @@ internal class PlanTyper( true -> sensitive(firstKey) false -> key } - sharedKey to StaticType.unionOf(matches.map { it.value }.toSet()).flatten() + sharedKey to unionOf(matches.map { it.value }.toSet()).flatten() } } } // 3. Struct is open - else -> (key to ANY) + else -> key to ANY } return type to name } @@ -1281,14 +1223,9 @@ internal class PlanTyper( val returns = newAgg.signature.returns // Return type with calculated nullability - var type = when { + val type = when { newAgg.signature.isNullable -> returns.toStaticType() - else -> returns.toNonNullStaticType() - } - - // Some operators can return MISSING during runtime - if (match.isMissable) { - type = StaticType.unionOf(type, MISSING).flatten() + else -> returns.toStaticType() } // Finally, rewrite this node @@ -1297,7 +1234,7 @@ internal class PlanTyper( is FnMatch.Dynamic -> TODO("Dynamic aggregates not yet supported.") is FnMatch.Error -> { handleUnknownFunction(match) - return relOpAggregateCall(agg, listOf(rexErr("MISSING"))) to MissingType + return relOpAggregateCall(agg, listOf(rexErr("MISSING"))) to ANY } } } @@ -1311,7 +1248,7 @@ internal class PlanTyper( private fun Rex.type(locals: TypeEnv, strategy: ResolutionStrategy = ResolutionStrategy.LOCAL) = RexTyper(locals, strategy).visitRex(this, this.type) - private fun rexErr(message: String) = rex(MISSING, rexOpErr(message)) + private fun rexErr(message: String) = rex(ANY, rexOpErr(message)) /** * I found decorating the tree with the binding names (for resolution) was easier than associating introduced @@ -1351,13 +1288,13 @@ internal class PlanTyper( /** * Produce a union type from all the */ - private fun List.toUnionType(): StaticType = AnyOfType(map { it.type }.toSet()).flatten() + private fun List.toUnionType(): StaticType = unionOf(map { it.type }.toSet()).flatten() private fun getElementTypeForFromSource(fromSourceType: StaticType): StaticType = when (fromSourceType) { is BagType -> fromSourceType.elementType is ListType -> fromSourceType.elementType is AnyType -> ANY - is AnyOfType -> AnyOfType(fromSourceType.types.map { getElementTypeForFromSource(it) }.toSet()) + is AnyOfType -> unionOf(fromSourceType.types.map { getElementTypeForFromSource(it) }.toSet()) // All the other types coerce into a bag of themselves (including null/missing/sexp). else -> fromSourceType } @@ -1375,7 +1312,7 @@ internal class PlanTyper( val m = mapping[i] if (m != null) { // rewrite - val type = m.returns.toNonNullStaticType() + val type = m.returns.toStaticType() val cast = rexOpCallStatic(fnResolved(m), listOf(a)) a = rex(type, cast) } @@ -1462,48 +1399,6 @@ internal class PlanTyper( } } - /** - * Indicates whether the given functions propagate Missing. - * - * Currently, Logical Functions : AND, OR, NOT, IS NULL, IS MISSING - * the equal function, function do not propagate Missing. - */ - private fun Fn.Unresolved.isNotMissable(): Boolean { - return when (identifier) { - is Identifier.Qualified -> false - is Identifier.Symbol -> when (identifier.symbol) { - "and" -> true - "or" -> true - "not" -> true - "eq" -> true - "is_null" -> true - "is_missing" -> true - else -> false - } - } - } - - private fun Fn.Unresolved.isTypeAssertion(): Boolean { - return (identifier is Identifier.Symbol && identifier.symbol.startsWith("is")) - } - - /** - * This will make all binding values nullables. If the value is a struct, each field will be nullable. - * - * Note, this does not handle union types or nullable struct types. - */ - private fun List.pad() = map { - val type = when (val t = it.type) { - is StructType -> t.withNullableFields() - else -> t.asNullable() - } - relBinding(it.name, type) - } - - private fun StructType.withNullableFields(): StructType { - return copy(fields.map { it.copy(value = it.value.asNullable()) }) - } - private fun excludeBindings(input: List, item: Rel.Op.Exclude.Item): List { var matchedRoot = false val output = input.map { diff --git a/partiql-planner/src/main/kotlin/org/partiql/planner/internal/typer/TypeUtils.kt b/partiql-planner/src/main/kotlin/org/partiql/planner/internal/typer/TypeUtils.kt index d83c45de5f..f27319bac7 100644 --- a/partiql-planner/src/main/kotlin/org/partiql/planner/internal/typer/TypeUtils.kt +++ b/partiql-planner/src/main/kotlin/org/partiql/planner/internal/typer/TypeUtils.kt @@ -2,6 +2,7 @@ package org.partiql.planner.internal.typer import org.partiql.planner.internal.ir.Identifier import org.partiql.planner.internal.ir.Rel +import org.partiql.planner.internal.ir.Rex import org.partiql.types.AnyOfType import org.partiql.types.AnyType import org.partiql.types.BagType @@ -27,36 +28,51 @@ import org.partiql.types.TimestampType import org.partiql.value.PartiQLValueExperimental import org.partiql.value.PartiQLValueType +@Suppress("DEPRECATION") +@Deprecated( + message = "This will be removed in a future major-version bump.", + replaceWith = ReplaceWith("ANY") +) internal fun StaticType.isNullOrMissing(): Boolean = (this is NullType || this is MissingType) -internal fun StaticType.isNumeric(): Boolean = (this is IntType || this is FloatType || this is DecimalType) - -internal fun StaticType.isExactNumeric(): Boolean = (this is IntType || this is DecimalType) - -internal fun StaticType.isApproxNumeric(): Boolean = (this is FloatType) - internal fun StaticType.isText(): Boolean = (this is SymbolType || this is StringType) +@Suppress("DEPRECATION") +@Deprecated( + message = "This will be removed in a future major-version bump.", + replaceWith = ReplaceWith("ANY") +) internal fun StaticType.isUnknown(): Boolean = (this.isNullOrMissing() || this == StaticType.NULL_OR_MISSING) -internal fun StaticType.isOptional(): Boolean = when (this) { - is AnyType, MissingType -> true // Any includes Missing type - is AnyOfType -> types.any { it.isOptional() } - else -> false +/** + * Returns whether [this] *may* be of a specific type. AKA: is it the type? Is it a union that holds the type? + */ +internal inline fun StaticType.mayBeType(): Boolean { + return this.allTypes.any { it is T } } /** - * Per SQL, runtime types are always nullable + * For each type in [this] [StaticType.allTypes], the [block] will be invoked. Non-null outputs to the [block] will be + * returned. */ -@OptIn(PartiQLValueExperimental::class) -internal fun PartiQLValueType.toStaticType(): StaticType = when (this) { - PartiQLValueType.NULL -> StaticType.NULL - PartiQLValueType.MISSING -> StaticType.MISSING - else -> toNonNullStaticType().asNullable() +internal fun StaticType.inferListNotNull(block: (StaticType) -> StaticType?): List { + return this.flatten().allTypes.mapNotNull { type -> block(type) } } +/** + * For each type in [this] [StaticType.allTypes], the [block] will be invoked. Non-null outputs to the [block] will be + * returned. + */ +internal fun StaticType.inferRexListNotNull(block: (StaticType) -> Rex?): List { + return this.flatten().allTypes.mapNotNull { type -> block(type) } +} + +/** + * Per SQL, runtime types are always nullable + */ @OptIn(PartiQLValueExperimental::class) -internal fun PartiQLValueType.toNonNullStaticType(): StaticType = when (this) { +@Suppress("DEPRECATION") +internal fun PartiQLValueType.toStaticType(): StaticType = when (this) { PartiQLValueType.ANY -> StaticType.ANY PartiQLValueType.BOOL -> StaticType.BOOL PartiQLValueType.INT8 -> StaticType.INT2 @@ -83,11 +99,12 @@ internal fun PartiQLValueType.toNonNullStaticType(): StaticType = when (this) { PartiQLValueType.LIST -> StaticType.LIST PartiQLValueType.SEXP -> StaticType.SEXP PartiQLValueType.STRUCT -> StaticType.STRUCT - PartiQLValueType.NULL -> StaticType.NULL - PartiQLValueType.MISSING -> StaticType.MISSING + PartiQLValueType.NULL -> StaticType.ANY + PartiQLValueType.MISSING -> StaticType.ANY } @OptIn(PartiQLValueExperimental::class) +@Suppress("DEPRECATION") internal fun StaticType.toRuntimeType(): PartiQLValueType { if (this is AnyOfType) { // handle anyOf(null, T) cases @@ -110,6 +127,7 @@ internal fun StaticType.toRuntimeTypeOrNull(): PartiQLValueType? { } } +@Suppress("DEPRECATION") @OptIn(PartiQLValueExperimental::class) private fun StaticType.asRuntimeType(): PartiQLValueType = when (this) { is AnyOfType -> PartiQLValueType.ANY @@ -139,8 +157,8 @@ private fun StaticType.asRuntimeType(): PartiQLValueType = when (this) { IntType.IntRangeConstraint.LONG -> PartiQLValueType.INT64 IntType.IntRangeConstraint.UNCONSTRAINED -> PartiQLValueType.INT } - MissingType -> PartiQLValueType.MISSING - is NullType -> PartiQLValueType.NULL + MissingType -> PartiQLValueType.ANY + is NullType -> PartiQLValueType.ANY is StringType -> PartiQLValueType.STRING is StructType -> PartiQLValueType.STRUCT is SymbolType -> PartiQLValueType.SYMBOL @@ -177,7 +195,7 @@ internal fun StructType.exclude(steps: List, lastStepOption val output = fields.map { field -> val newField = if (steps.size == 1) { if (lastStepOptional) { - StructType.Field(field.key, field.value.asOptional()) + StructType.Field(field.key, field.value) // TODO: double check this } else { null } diff --git a/partiql-planner/src/test/kotlin/org/partiql/planner/internal/typer/PartiQLTyperTestBase.kt b/partiql-planner/src/test/kotlin/org/partiql/planner/internal/typer/PartiQLTyperTestBase.kt index 7ad14eb2e7..243c384ef6 100644 --- a/partiql-planner/src/test/kotlin/org/partiql/planner/internal/typer/PartiQLTyperTestBase.kt +++ b/partiql-planner/src/test/kotlin/org/partiql/planner/internal/typer/PartiQLTyperTestBase.kt @@ -99,7 +99,7 @@ abstract class PartiQLTyperTestBase { val result = testingPipeline(statement, testName, metadata, pc) val root = (result.plan.statement as Statement.Query).root val actualType = root.type - assert(actualType == StaticType.MISSING) { + assert(actualType == StaticType.ANY) { buildString { this.appendLine(" expected Type is : MISSING") this.appendLine("actual Type is : $actualType") diff --git a/partiql-planner/src/test/kotlin/org/partiql/planner/internal/typer/PlanTyperTestsPorted.kt b/partiql-planner/src/test/kotlin/org/partiql/planner/internal/typer/PlanTyperTestsPorted.kt index 88cf544510..b6cc704368 100644 --- a/partiql-planner/src/test/kotlin/org/partiql/planner/internal/typer/PlanTyperTestsPorted.kt +++ b/partiql-planner/src/test/kotlin/org/partiql/planner/internal/typer/PlanTyperTestsPorted.kt @@ -30,13 +30,15 @@ import org.partiql.planner.util.ProblemCollector import org.partiql.plugins.local.toStaticType import org.partiql.plugins.memory.MemoryConnector import org.partiql.spi.connector.ConnectorMetadata -import org.partiql.types.AnyOfType import org.partiql.types.AnyType import org.partiql.types.BagType import org.partiql.types.ListType import org.partiql.types.SexpType import org.partiql.types.StaticType -import org.partiql.types.StaticType.Companion.MISSING +import org.partiql.types.StaticType.Companion.ANY +import org.partiql.types.StaticType.Companion.INT +import org.partiql.types.StaticType.Companion.INT4 +import org.partiql.types.StaticType.Companion.INT8 import org.partiql.types.StaticType.Companion.unionOf import org.partiql.types.StructType import org.partiql.types.TupleConstraint @@ -328,7 +330,7 @@ class PlanTyperTestsPorted { ) ), StructType.Field("ssn", StaticType.STRING), - StructType.Field("employer", StaticType.STRING.asNullable()), + StructType.Field("employer", StaticType.STRING), StructType.Field("name", StaticType.STRING), StructType.Field("tax_id", StaticType.INT8), StructType.Field( @@ -515,12 +517,12 @@ class PlanTyperTestsPorted { SuccessTestCase( name = "Current User", query = "CURRENT_USER", - expected = StaticType.unionOf(StaticType.STRING, StaticType.NULL) + expected = StaticType.STRING ), SuccessTestCase( name = "Current User Concat", query = "CURRENT_USER || 'hello'", - expected = StaticType.unionOf(StaticType.STRING, StaticType.NULL) + expected = StaticType.STRING ), SuccessTestCase( name = "Current User in WHERE", @@ -546,11 +548,11 @@ class PlanTyperTestsPorted { expected = BagType( StructType( fields = listOf( - StructType.Field("CURRENT_USER", StaticType.STRING.asNullable()), + StructType.Field("CURRENT_USER", StaticType.STRING), StructType.Field("CURRENT_DATE", StaticType.DATE), - StructType.Field("curr_user", StaticType.STRING.asNullable()), + StructType.Field("curr_user", StaticType.STRING), StructType.Field("curr_date", StaticType.DATE), - StructType.Field("name_desc", StaticType.STRING.asNullable()), + StructType.Field("name_desc", StaticType.STRING), ), contentClosed = true, constraints = setOf( @@ -564,14 +566,14 @@ class PlanTyperTestsPorted { ErrorTestCase( name = "Current User (String) PLUS String", query = "CURRENT_USER + 'hello'", - expected = StaticType.MISSING, + expected = ANY, problemHandler = assertProblemExists { Problem( UNKNOWN_PROBLEM_LOCATION, PlanningProblemDetails.UnknownFunction( "plus", listOf( - StaticType.unionOf(StaticType.STRING, StaticType.NULL), + StaticType.STRING, StaticType.STRING, ), ) @@ -590,7 +592,7 @@ class PlanTyperTestsPorted { SuccessTestCase( name = "BITWISE_AND_2", query = "CAST(1 AS INT2) & CAST(2 AS INT2)", - expected = StaticType.unionOf(StaticType.INT2, StaticType.MISSING) + expected = StaticType.INT2 ), SuccessTestCase( name = "BITWISE_AND_3", @@ -605,17 +607,17 @@ class PlanTyperTestsPorted { SuccessTestCase( name = "BITWISE_AND_5", query = "CAST(1 AS INT2) & 2", - expected = StaticType.unionOf(StaticType.INT4, StaticType.MISSING) + expected = StaticType.INT4 ), SuccessTestCase( name = "BITWISE_AND_6", query = "CAST(1 AS INT2) & CAST(2 AS INT8)", - expected = StaticType.unionOf(StaticType.INT8, StaticType.MISSING) + expected = StaticType.INT8 ), SuccessTestCase( name = "BITWISE_AND_7", query = "CAST(1 AS INT2) & 2", - expected = StaticType.unionOf(StaticType.INT4, StaticType.MISSING) + expected = StaticType.INT4 ), SuccessTestCase( name = "BITWISE_AND_8", @@ -635,26 +637,23 @@ class PlanTyperTestsPorted { SuccessTestCase( name = "BITWISE_AND_NULL_OPERAND", query = "1 & NULL", - expected = StaticType.NULL, + expected = unionOf(INT4, INT8, INT), ), ErrorTestCase( name = "BITWISE_AND_MISSING_OPERAND", query = "1 & MISSING", - expected = StaticType.MISSING, + expected = unionOf(INT4, INT8, INT), problemHandler = assertProblemExists { Problem( sourceLocation = UNKNOWN_PROBLEM_LOCATION, - details = PlanningProblemDetails.UnknownFunction( - "bitwise_and", - listOf(StaticType.INT4, StaticType.MISSING) - ) + details = PlanningProblemDetails.ExpressionAlwaysReturnsNullOrMissing ) } ), ErrorTestCase( name = "BITWISE_AND_NON_INT_OPERAND", query = "1 & 'NOT AN INT'", - expected = StaticType.MISSING, + expected = StaticType.ANY, problemHandler = assertProblemExists { Problem( UNKNOWN_PROBLEM_LOCATION, @@ -703,7 +702,7 @@ class PlanTyperTestsPorted { StructType( fields = mapOf( "a" to StaticType.INT4, - "b" to StaticType.unionOf(StaticType.NULL, StaticType.DECIMAL), + "b" to StaticType.DECIMAL, ), contentClosed = true, constraints = setOf( @@ -720,7 +719,7 @@ class PlanTyperTestsPorted { expected = BagType( StructType( fields = listOf( - StructType.Field("b", StaticType.unionOf(StaticType.NULL, StaticType.DECIMAL)), + StructType.Field("b", StaticType.DECIMAL), StructType.Field("a", StaticType.INT4), ), contentClosed = true, @@ -739,7 +738,7 @@ class PlanTyperTestsPorted { StructType( fields = listOf( StructType.Field("a", StaticType.INT4), - StructType.Field("a", StaticType.unionOf(StaticType.NULL, StaticType.DECIMAL)), + StructType.Field("a", StaticType.DECIMAL), ), contentClosed = true, constraints = setOf( @@ -757,7 +756,7 @@ class PlanTyperTestsPorted { StructType( fields = listOf( StructType.Field("a", StaticType.INT4), - StructType.Field("a", StaticType.unionOf(StaticType.NULL, StaticType.DECIMAL)), + StructType.Field("a", StaticType.DECIMAL), ), contentClosed = true, constraints = setOf( @@ -785,8 +784,8 @@ class PlanTyperTestsPorted { StructType( fields = listOf( StructType.Field("a", StaticType.INT4), - StructType.Field("a", StaticType.unionOf(StaticType.DECIMAL, StaticType.NULL)), - StructType.Field("a", StaticType.unionOf(StaticType.STRING, StaticType.NULL)), + StructType.Field("a", StaticType.DECIMAL), + StructType.Field("a", StaticType.STRING), ), contentClosed = true, constraints = setOf( @@ -804,7 +803,7 @@ class PlanTyperTestsPorted { StructType( fields = listOf( StructType.Field("a", StaticType.INT4), - StructType.Field("a", StaticType.unionOf(StaticType.DECIMAL, StaticType.NULL)), + StructType.Field("a", StaticType.DECIMAL), ), contentClosed = true, constraints = setOf( @@ -891,12 +890,7 @@ class PlanTyperTestsPorted { "c" to ListType( elementType = StructType( fields = mapOf( - "field" to AnyOfType( - setOf( - StaticType.INT4, - StaticType.MISSING // c[1]'s `field` was excluded - ) - ) + "field" to INT4 ), contentClosed = true, constraints = setOf( @@ -1226,7 +1220,7 @@ class PlanTyperTestsPorted { fields = mapOf( "b" to StructType( fields = mapOf( - "c" to StaticType.INT4.asOptional(), + "c" to StaticType.INT4, "d" to StaticType.STRING ), contentClosed = true, @@ -1293,8 +1287,8 @@ class PlanTyperTestsPorted { fields = mapOf( "b" to StructType( fields = mapOf( // all fields of b optional - "c" to StaticType.INT4.asOptional(), - "d" to StaticType.STRING.asOptional() + "c" to StaticType.INT4, + "d" to StaticType.STRING ), contentClosed = true, constraints = setOf( @@ -1378,7 +1372,7 @@ class PlanTyperTestsPorted { "d" to ListType( elementType = StructType( fields = mapOf( - "e" to StaticType.STRING.asOptional(), // last step is optional since only a[1]... is excluded + "e" to StaticType.STRING, // last step is optional since only a[1]... is excluded "f" to StaticType.BOOL ), contentClosed = true, @@ -1425,7 +1419,7 @@ class PlanTyperTestsPorted { "d" to ListType( elementType = StructType( fields = mapOf( // same as above - "e" to StaticType.STRING.asOptional(), + "e" to StaticType.STRING, "f" to StaticType.BOOL ), contentClosed = true, @@ -1649,7 +1643,7 @@ class PlanTyperTestsPorted { ), StructType( fields = mapOf( - "a" to StaticType.NULL + "a" to ANY ), contentClosed = true, constraints = setOf(TupleConstraint.Open(false), TupleConstraint.UniqueAttrs(true)) @@ -1692,7 +1686,7 @@ class PlanTyperTestsPorted { fields = mapOf( "a" to StructType( fields = mapOf( - "c" to StaticType.NULL + "c" to ANY ), contentClosed = true, constraints = setOf( @@ -1937,7 +1931,7 @@ class PlanTyperTestsPorted { StructType( fields = mapOf( "b" to StaticType.INT4, - "c" to StaticType.INT4.asOptional() + "c" to StaticType.INT4 ), contentClosed = true, constraints = setOf( @@ -1948,7 +1942,7 @@ class PlanTyperTestsPorted { StructType( fields = mapOf( "b" to StaticType.INT4, - "c" to StaticType.NULL.asOptional() + "c" to ANY ), contentClosed = true, constraints = setOf( @@ -1959,7 +1953,7 @@ class PlanTyperTestsPorted { StructType( fields = mapOf( "b" to StaticType.INT4, - "c" to StaticType.DECIMAL.asOptional() + "c" to StaticType.DECIMAL ), contentClosed = true, constraints = setOf( @@ -2121,17 +2115,15 @@ class PlanTyperTestsPorted { >> AS t """, expected = BagType( - StaticType.unionOf( - StaticType.MISSING, - StructType( - fields = listOf( - StructType.Field("b", StaticType.INT4), - ), - contentClosed = true, - constraints = setOf( - TupleConstraint.Open(false), - TupleConstraint.UniqueAttrs(true), - ) + StructType( + fields = listOf( + StructType.Field("b", INT4), + ), + contentClosed = true, + constraints = setOf( + TupleConstraint.Open(false), + TupleConstraint.UniqueAttrs(true), + TupleConstraint.Ordered ) ) ), @@ -2144,15 +2136,13 @@ class PlanTyperTestsPorted { ) FROM << { 'a': { 'b': 1 } }, { 'a': { 'b': 'hello' } }, - { 'a': NULL }, + { 'a': 'world' }, { 'a': 4.5 }, { } >> AS t """, expected = BagType( StaticType.unionOf( - StaticType.NULL, - StaticType.MISSING, StructType( fields = listOf( StructType.Field("b", StaticType.INT4), @@ -2185,7 +2175,6 @@ class PlanTyperTestsPorted { """, expected = BagType( StaticType.unionOf( - StaticType.MISSING, StructType( fields = listOf( StructType.Field("first", StaticType.STRING), @@ -2221,7 +2210,6 @@ class PlanTyperTestsPorted { """, expected = BagType( StaticType.unionOf( - StaticType.MISSING, StructType( fields = listOf( StructType.Field("first", StaticType.STRING), @@ -2297,7 +2285,7 @@ class PlanTyperTestsPorted { WHEN TRUE THEN 'hello' END; """, - expected = StaticType.STRING + expected = unionOf(INT4, StaticType.STRING) ), SuccessTestCase( name = "Boolean case when", @@ -2310,14 +2298,14 @@ class PlanTyperTestsPorted { expected = StaticType.BOOL ), SuccessTestCase( - name = "Folded out false", + name = "Typing even with false condition", query = """ CASE WHEN FALSE THEN 'IMPOSSIBLE TO GET' ELSE TRUE END; """, - expected = StaticType.BOOL + expected = unionOf(StaticType.STRING, StaticType.BOOL) ), SuccessTestCase( name = "Folded out false without default", @@ -2326,7 +2314,7 @@ class PlanTyperTestsPorted { WHEN FALSE THEN 'IMPOSSIBLE TO GET' END; """, - expected = StaticType.NULL + expected = StaticType.STRING ), SuccessTestCase( name = "Not folded gives us a nullable without default", @@ -2336,7 +2324,7 @@ class PlanTyperTestsPorted { WHEN 2 THEN FALSE END; """, - expected = StaticType.BOOL.asNullable() + expected = StaticType.BOOL ), SuccessTestCase( name = "Not folded gives us a nullable without default for query", @@ -2353,7 +2341,7 @@ class PlanTyperTestsPorted { expected = BagType( StructType( fields = mapOf( - "breed_descriptor" to StaticType.STRING.asNullable(), + "breed_descriptor" to StaticType.STRING, ), contentClosed = true, constraints = setOf( @@ -2461,22 +2449,22 @@ class PlanTyperTestsPorted { SuccessTestCase( key = PartiQLTest.Key("basics", "case-when-08"), catalog = "pql", - expected = unionOf(StaticType.INT, StaticType.NULL), + expected = StaticType.INT, ), SuccessTestCase( key = PartiQLTest.Key("basics", "case-when-09"), catalog = "pql", - expected = unionOf(StaticType.INT, StaticType.NULL), + expected = StaticType.INT, ), SuccessTestCase( key = PartiQLTest.Key("basics", "case-when-10"), catalog = "pql", - expected = unionOf(StaticType.DECIMAL, StaticType.NULL), + expected = StaticType.DECIMAL, ), SuccessTestCase( key = PartiQLTest.Key("basics", "case-when-11"), catalog = "pql", - expected = unionOf(StaticType.INT, StaticType.MISSING), + expected = StaticType.INT, ), SuccessTestCase( key = PartiQLTest.Key("basics", "case-when-12"), @@ -2486,7 +2474,7 @@ class PlanTyperTestsPorted { SuccessTestCase( key = PartiQLTest.Key("basics", "case-when-13"), catalog = "pql", - expected = unionOf(StaticType.FLOAT, StaticType.NULL), + expected = StaticType.FLOAT, ), SuccessTestCase( key = PartiQLTest.Key("basics", "case-when-14"), @@ -2496,7 +2484,7 @@ class PlanTyperTestsPorted { SuccessTestCase( key = PartiQLTest.Key("basics", "case-when-15"), catalog = "pql", - expected = unionOf(StaticType.STRING, StaticType.NULL), + expected = StaticType.STRING, ), SuccessTestCase( key = PartiQLTest.Key("basics", "case-when-16"), @@ -2506,37 +2494,27 @@ class PlanTyperTestsPorted { SuccessTestCase( key = PartiQLTest.Key("basics", "case-when-17"), catalog = "pql", - expected = unionOf(StaticType.CLOB, StaticType.NULL), + expected = StaticType.CLOB, ), SuccessTestCase( key = PartiQLTest.Key("basics", "case-when-18"), catalog = "pql", - expected = unionOf(StaticType.STRING, StaticType.NULL), + expected = StaticType.STRING, ), SuccessTestCase( key = PartiQLTest.Key("basics", "case-when-19"), catalog = "pql", - expected = unionOf(StaticType.STRING, StaticType.NULL), + expected = StaticType.STRING, ), SuccessTestCase( key = PartiQLTest.Key("basics", "case-when-20"), catalog = "pql", - expected = StaticType.NULL, + expected = StaticType.ANY, ), SuccessTestCase( key = PartiQLTest.Key("basics", "case-when-21"), catalog = "pql", - expected = unionOf(StaticType.STRING, StaticType.NULL), - ), - SuccessTestCase( - key = PartiQLTest.Key("basics", "case-when-22"), - catalog = "pql", - expected = unionOf(StaticType.INT4, StaticType.NULL, StaticType.MISSING), - ), - SuccessTestCase( - key = PartiQLTest.Key("basics", "case-when-23"), - catalog = "pql", - expected = StaticType.INT4, + expected = StaticType.STRING, ), SuccessTestCase( key = PartiQLTest.Key("basics", "case-when-24"), @@ -2546,12 +2524,12 @@ class PlanTyperTestsPorted { SuccessTestCase( key = PartiQLTest.Key("basics", "case-when-25"), catalog = "pql", - expected = unionOf(StaticType.INT4, StaticType.INT8, StaticType.STRING, StaticType.NULL), + expected = unionOf(StaticType.INT4, StaticType.INT8, StaticType.STRING), ), SuccessTestCase( key = PartiQLTest.Key("basics", "case-when-26"), catalog = "pql", - expected = unionOf(StaticType.INT4, StaticType.INT8, StaticType.STRING, StaticType.NULL), + expected = unionOf(StaticType.INT4, StaticType.INT8, StaticType.STRING), ), SuccessTestCase( key = PartiQLTest.Key("basics", "case-when-27"), @@ -2561,7 +2539,7 @@ class PlanTyperTestsPorted { SuccessTestCase( key = PartiQLTest.Key("basics", "case-when-28"), catalog = "pql", - expected = unionOf(StaticType.INT2, StaticType.INT4, StaticType.INT8, StaticType.INT, StaticType.DECIMAL, StaticType.STRING, StaticType.CLOB, StaticType.NULL), + expected = unionOf(StaticType.INT2, StaticType.INT4, StaticType.INT8, StaticType.INT, StaticType.DECIMAL, StaticType.STRING, StaticType.CLOB), ), SuccessTestCase( key = PartiQLTest.Key("basics", "case-when-29"), @@ -2579,13 +2557,12 @@ class PlanTyperTestsPorted { StructType.Field("y", StaticType.INT8), ), ), - StaticType.NULL, ), ), SuccessTestCase( key = PartiQLTest.Key("basics", "case-when-30"), catalog = "pql", - expected = MISSING + expected = ANY ), SuccessTestCase( key = PartiQLTest.Key("basics", "case-when-31"), @@ -2614,32 +2591,32 @@ class PlanTyperTestsPorted { SuccessTestCase( key = PartiQLTest.Key("basics", "nullif-00"), catalog = "pql", - expected = StaticType.INT4.asNullable() + expected = StaticType.INT4 ), SuccessTestCase( key = PartiQLTest.Key("basics", "nullif-01"), catalog = "pql", - expected = StaticType.INT4.asNullable() + expected = StaticType.INT4 ), SuccessTestCase( key = PartiQLTest.Key("basics", "nullif-02"), catalog = "pql", - expected = StaticType.INT4.asNullable() + expected = StaticType.INT4 ), SuccessTestCase( key = PartiQLTest.Key("basics", "nullif-03"), catalog = "pql", - expected = StaticType.INT4.asNullable() + expected = StaticType.INT4 ), SuccessTestCase( key = PartiQLTest.Key("basics", "nullif-04"), catalog = "pql", - expected = StaticType.INT8.asNullable() + expected = StaticType.INT8 ), SuccessTestCase( key = PartiQLTest.Key("basics", "nullif-05"), catalog = "pql", - expected = StaticType.INT4.asNullable() + expected = StaticType.INT4 ), SuccessTestCase( key = PartiQLTest.Key("basics", "nullif-06"), @@ -2649,57 +2626,57 @@ class PlanTyperTestsPorted { SuccessTestCase( key = PartiQLTest.Key("basics", "nullif-07"), catalog = "pql", - expected = StaticType.INT4.asNullable() + expected = StaticType.INT4 ), SuccessTestCase( key = PartiQLTest.Key("basics", "nullif-08"), catalog = "pql", - expected = StaticType.NULL_OR_MISSING + expected = ANY ), SuccessTestCase( key = PartiQLTest.Key("basics", "nullif-09"), catalog = "pql", - expected = StaticType.INT4.asNullable() + expected = StaticType.INT4 ), SuccessTestCase( key = PartiQLTest.Key("basics", "nullif-10"), catalog = "pql", - expected = StaticType.INT4.asNullable() + expected = StaticType.INT4 ), SuccessTestCase( key = PartiQLTest.Key("basics", "nullif-11"), catalog = "pql", - expected = StaticType.INT4.asNullable() + expected = StaticType.INT4 ), SuccessTestCase( key = PartiQLTest.Key("basics", "nullif-12"), catalog = "pql", - expected = StaticType.INT8.asNullable() + expected = StaticType.INT8 ), SuccessTestCase( key = PartiQLTest.Key("basics", "nullif-13"), catalog = "pql", - expected = StaticType.INT4.asNullable() + expected = StaticType.INT4 ), SuccessTestCase( key = PartiQLTest.Key("basics", "nullif-14"), catalog = "pql", - expected = StaticType.STRING.asNullable() + expected = StaticType.STRING ), SuccessTestCase( key = PartiQLTest.Key("basics", "nullif-15"), catalog = "pql", - expected = StaticType.INT4.asNullable() + expected = StaticType.INT4 ), SuccessTestCase( key = PartiQLTest.Key("basics", "nullif-16"), catalog = "pql", - expected = unionOf(StaticType.INT2, StaticType.INT4, StaticType.INT8, StaticType.INT, StaticType.DECIMAL, StaticType.NULL) + expected = unionOf(StaticType.INT2, StaticType.INT4, StaticType.INT8, StaticType.INT, StaticType.DECIMAL) ), SuccessTestCase( key = PartiQLTest.Key("basics", "nullif-17"), catalog = "pql", - expected = StaticType.INT4.asNullable() + expected = StaticType.INT4 ), SuccessTestCase( key = PartiQLTest.Key("basics", "nullif-18"), @@ -2728,17 +2705,17 @@ class PlanTyperTestsPorted { SuccessTestCase( key = PartiQLTest.Key("basics", "coalesce-03"), catalog = "pql", - expected = unionOf(StaticType.NULL, StaticType.DECIMAL) + expected = StaticType.DECIMAL ), SuccessTestCase( key = PartiQLTest.Key("basics", "coalesce-04"), catalog = "pql", - expected = unionOf(StaticType.NULL, StaticType.MISSING, StaticType.DECIMAL) + expected = StaticType.DECIMAL ), SuccessTestCase( key = PartiQLTest.Key("basics", "coalesce-05"), catalog = "pql", - expected = unionOf(StaticType.NULL, StaticType.MISSING, StaticType.DECIMAL) + expected = StaticType.DECIMAL ), SuccessTestCase( key = PartiQLTest.Key("basics", "coalesce-06"), @@ -2758,12 +2735,12 @@ class PlanTyperTestsPorted { SuccessTestCase( key = PartiQLTest.Key("basics", "coalesce-09"), catalog = "pql", - expected = StaticType.INT8.asNullable() + expected = StaticType.INT8 ), SuccessTestCase( key = PartiQLTest.Key("basics", "coalesce-10"), catalog = "pql", - expected = unionOf(StaticType.INT8, StaticType.NULL, StaticType.MISSING) + expected = INT8 ), SuccessTestCase( key = PartiQLTest.Key("basics", "coalesce-11"), @@ -2773,7 +2750,7 @@ class PlanTyperTestsPorted { SuccessTestCase( key = PartiQLTest.Key("basics", "coalesce-12"), catalog = "pql", - expected = unionOf(StaticType.INT8, StaticType.NULL, StaticType.STRING) + expected = unionOf(StaticType.INT8, StaticType.STRING) ), SuccessTestCase( key = PartiQLTest.Key("basics", "coalesce-13"), @@ -2788,7 +2765,7 @@ class PlanTyperTestsPorted { SuccessTestCase( key = PartiQLTest.Key("basics", "coalesce-15"), catalog = "pql", - expected = unionOf(StaticType.INT2, StaticType.INT4, StaticType.INT8, StaticType.INT, StaticType.DECIMAL, StaticType.STRING, StaticType.NULL) + expected = unionOf(StaticType.INT2, StaticType.INT4, StaticType.INT8, StaticType.INT, StaticType.DECIMAL, StaticType.STRING) ), SuccessTestCase( key = PartiQLTest.Key("basics", "coalesce-16"), @@ -2962,7 +2939,7 @@ class PlanTyperTestsPorted { query = """ { 'aBc': 1, 'AbC': 2.0 }['Ab' || 'C']; """, - expected = StaticType.MISSING, + expected = ANY, problemHandler = assertProblemExists { Problem( sourceLocation = UNKNOWN_PROBLEM_LOCATION, @@ -3085,9 +3062,9 @@ class PlanTyperTestsPorted { "a" to StaticType.INT4, "_1" to StaticType.INT8, "_2" to StaticType.INT8, - "_3" to StaticType.INT4.asNullable(), - "_4" to StaticType.INT4.asNullable(), - "_5" to StaticType.INT4.asNullable(), + "_3" to StaticType.INT4, + "_4" to StaticType.INT4, + "_5" to StaticType.INT4, ), contentClosed = true, constraints = setOf( @@ -3107,8 +3084,8 @@ class PlanTyperTestsPorted { "a" to StaticType.INT4, "c_s" to StaticType.INT8, "c" to StaticType.INT8, - "s" to StaticType.INT4.asNullable(), - "m" to StaticType.INT4.asNullable(), + "s" to StaticType.INT4, + "m" to StaticType.INT4, ), contentClosed = true, constraints = setOf( @@ -3127,55 +3104,8 @@ class PlanTyperTestsPorted { fields = mapOf( "a" to StaticType.DECIMAL, "c" to StaticType.INT8, - "s" to StaticType.DECIMAL.asNullable(), - "m" to StaticType.DECIMAL.asNullable(), - ), - contentClosed = true, - constraints = setOf( - TupleConstraint.Open(false), - TupleConstraint.UniqueAttrs(true), - TupleConstraint.Ordered - ) - ) - ) - ), - SuccessTestCase( - name = "AGGREGATE over nullable integers", - query = """ - SELECT - a AS a, - COUNT(*) AS count_star, - COUNT(a) AS count_a, - COUNT(b) AS count_b, - SUM(a) AS sum_a, - SUM(b) AS sum_b, - MIN(a) AS min_a, - MIN(b) AS min_b, - MAX(a) AS max_a, - MAX(b) AS max_b, - AVG(a) AS avg_a, - AVG(b) AS avg_b - FROM << - { 'a': 1, 'b': 2 }, - { 'a': 3, 'b': 4 }, - { 'a': 5, 'b': NULL } - >> GROUP BY a - """.trimIndent(), - expected = BagType( - StructType( - fields = mapOf( - "a" to StaticType.INT4, - "count_star" to StaticType.INT8, - "count_a" to StaticType.INT8, - "count_b" to StaticType.INT8, - "sum_a" to StaticType.INT4.asNullable(), - "sum_b" to StaticType.INT4.asNullable(), - "min_a" to StaticType.INT4.asNullable(), - "min_b" to StaticType.INT4.asNullable(), - "max_a" to StaticType.INT4.asNullable(), - "max_b" to StaticType.INT4.asNullable(), - "avg_a" to StaticType.INT4.asNullable(), - "avg_b" to StaticType.INT4.asNullable(), + "s" to StaticType.DECIMAL, + "m" to StaticType.DECIMAL, ), contentClosed = true, constraints = setOf( @@ -3262,7 +3192,7 @@ class PlanTyperTestsPorted { expected = BagType( StructType( fields = mapOf( - "a" to StaticType.unionOf(StaticType.INT4, StaticType.INT8, StaticType.MISSING), + "a" to StaticType.unionOf(StaticType.INT4, StaticType.INT8), ), contentClosed = true, constraints = setOf( @@ -3286,7 +3216,7 @@ class PlanTyperTestsPorted { expected = BagType( StructType( fields = mapOf( - "a" to StaticType.unionOf(StaticType.INT4, StaticType.INT8, StaticType.MISSING), + "a" to StaticType.unionOf(StaticType.INT4, StaticType.INT8), ), contentClosed = true, constraints = setOf( @@ -3310,7 +3240,7 @@ class PlanTyperTestsPorted { expected = BagType( StructType( fields = mapOf( - "c" to StaticType.unionOf(StaticType.MISSING, StaticType.DECIMAL), + "c" to StaticType.DECIMAL, ), contentClosed = true, constraints = setOf( @@ -3332,7 +3262,7 @@ class PlanTyperTestsPorted { { 'a': 'hello world!' } >> AS t """.trimIndent(), - expected = BagType(StaticType.MISSING), + expected = BagType(ANY), problemHandler = assertProblemExists { Problem( sourceLocation = UNKNOWN_PROBLEM_LOCATION, @@ -3355,7 +3285,7 @@ class PlanTyperTestsPorted { { 'a': <<>> } >> AS t """.trimIndent(), - expected = BagType(StaticType.MISSING), + expected = BagType(ANY), problemHandler = assertProblemExists { Problem( sourceLocation = UNKNOWN_PROBLEM_LOCATION, @@ -3377,14 +3307,11 @@ class PlanTyperTestsPorted { { 'NOT_A': 1 } >> AS t """.trimIndent(), - expected = BagType(StaticType.MISSING), + expected = BagType(unionOf(StaticType.INT2, INT4, INT8, INT, StaticType.FLOAT, StaticType.DECIMAL)), problemHandler = assertProblemExists { Problem( sourceLocation = UNKNOWN_PROBLEM_LOCATION, - details = PlanningProblemDetails.UnknownFunction( - "pos", - listOf(StaticType.MISSING) - ) + details = PlanningProblemDetails.ExpressionAlwaysReturnsNullOrMissing ) } ), @@ -3505,14 +3432,14 @@ class PlanTyperTestsPorted { "count_star" to StaticType.INT8, "count_a" to StaticType.INT8, "count_b" to StaticType.INT8, - "sum_a" to StaticType.DECIMAL.asNullable(), - "sum_b" to StaticType.DECIMAL.asNullable(), - "min_a" to StaticType.DECIMAL.asNullable(), - "min_b" to StaticType.DECIMAL.asNullable(), - "max_a" to StaticType.DECIMAL.asNullable(), - "max_b" to StaticType.DECIMAL.asNullable(), - "avg_a" to StaticType.DECIMAL.asNullable(), - "avg_b" to StaticType.DECIMAL.asNullable(), + "sum_a" to StaticType.DECIMAL, + "sum_b" to StaticType.DECIMAL, + "min_a" to StaticType.DECIMAL, + "min_b" to StaticType.DECIMAL, + "max_a" to StaticType.DECIMAL, + "max_b" to StaticType.DECIMAL, + "avg_a" to StaticType.DECIMAL, + "avg_b" to StaticType.DECIMAL, ), contentClosed = true, constraints = setOf( @@ -4052,7 +3979,7 @@ class PlanTyperTestsPorted { catalog = CATALOG_DB, catalogPath = DB_SCHEMA_MARKETS, query = "order_info.customer_id IN 'hello'", - expected = StaticType.MISSING, + expected = ANY, problemHandler = assertProblemExists { Problem( UNKNOWN_PROBLEM_LOCATION, @@ -4075,7 +4002,7 @@ class PlanTyperTestsPorted { catalog = CATALOG_DB, catalogPath = DB_SCHEMA_MARKETS, query = "order_info.customer_id BETWEEN 1 AND 'a'", - expected = StaticType.MISSING, + expected = ANY, problemHandler = assertProblemExists { Problem( UNKNOWN_PROBLEM_LOCATION, @@ -4102,7 +4029,7 @@ class PlanTyperTestsPorted { catalog = CATALOG_DB, catalogPath = DB_SCHEMA_MARKETS, query = "order_info.ship_option LIKE 3", - expected = StaticType.MISSING, + expected = ANY, problemHandler = assertProblemExists { Problem( UNKNOWN_PROBLEM_LOCATION, @@ -4126,7 +4053,7 @@ class PlanTyperTestsPorted { catalog = CATALOG_DB, catalogPath = DB_SCHEMA_MARKETS, query = "order_info.\"CUSTOMER_ID\" = 1", - expected = StaticType.NULL + expected = StaticType.BOOL ), SuccessTestCase( name = "Case Sensitive success", @@ -4140,14 +4067,14 @@ class PlanTyperTestsPorted { catalog = CATALOG_DB, catalogPath = DB_SCHEMA_MARKETS, query = "(order_info.customer_id = 1) AND (order_info.marketplace_id = 2)", - expected = StaticType.unionOf(StaticType.BOOL, StaticType.NULL) + expected = StaticType.BOOL ), SuccessTestCase( name = "2-Level Junction", catalog = CATALOG_DB, catalogPath = DB_SCHEMA_MARKETS, query = "(order_info.customer_id = 1) AND (order_info.marketplace_id = 2) OR (order_info.customer_id = 3) AND (order_info.marketplace_id = 4)", - expected = StaticType.unionOf(StaticType.BOOL, StaticType.NULL) + expected = StaticType.BOOL ), SuccessTestCase( name = "INT and STR Comparison", @@ -4163,7 +4090,7 @@ class PlanTyperTestsPorted { query = "non_existing_column = 1", // Function resolves to EQ__ANY_ANY__BOOL // Which can return BOOL Or NULL - expected = StaticType.unionOf(StaticType.BOOL, StaticType.NULL), + expected = StaticType.BOOL, problemHandler = assertProblemExists { Problem( UNKNOWN_PROBLEM_LOCATION, @@ -4176,7 +4103,7 @@ class PlanTyperTestsPorted { catalog = CATALOG_DB, catalogPath = DB_SCHEMA_MARKETS, query = "order_info.customer_id = 1 AND 1", - expected = StaticType.MISSING, + expected = ANY, problemHandler = assertProblemExists { Problem( UNKNOWN_PROBLEM_LOCATION, @@ -4192,7 +4119,7 @@ class PlanTyperTestsPorted { catalog = CATALOG_DB, catalogPath = DB_SCHEMA_MARKETS, query = "1 AND order_info.customer_id = 1", - expected = StaticType.MISSING, + expected = ANY, problemHandler = assertProblemExists { Problem( UNKNOWN_PROBLEM_LOCATION, @@ -4273,7 +4200,7 @@ class PlanTyperTestsPorted { query = "SELECT CAST(breed AS INT) AS cast_breed FROM pets", expected = BagType( StructType( - fields = mapOf("cast_breed" to StaticType.unionOf(StaticType.INT, StaticType.MISSING)), + fields = mapOf("cast_breed" to StaticType.INT), contentClosed = true, constraints = setOf( TupleConstraint.Open(false), @@ -4394,7 +4321,7 @@ class PlanTyperTestsPorted { SuccessTestCase( name = "Current User", query = "CURRENT_USER", - expected = StaticType.unionOf(StaticType.STRING, StaticType.NULL) + expected = StaticType.STRING ), SuccessTestCase( name = "Trim", @@ -4404,7 +4331,7 @@ class PlanTyperTestsPorted { SuccessTestCase( name = "Current User Concat", query = "CURRENT_USER || 'hello'", - expected = StaticType.unionOf(StaticType.STRING, StaticType.NULL) + expected = StaticType.STRING ), SuccessTestCase( name = "Current User Concat in WHERE", @@ -4429,7 +4356,7 @@ class PlanTyperTestsPorted { ErrorTestCase( name = "TRIM_2_error", query = "trim(2 FROM ' Hello, World! ')", - expected = StaticType.MISSING, + expected = ANY, problemHandler = assertProblemExists { Problem( UNKNOWN_PROBLEM_LOCATION, diff --git a/partiql-planner/src/test/kotlin/org/partiql/planner/internal/typer/functions/NullIfTest.kt b/partiql-planner/src/test/kotlin/org/partiql/planner/internal/typer/functions/NullIfTest.kt index 6f1a56a84e..dd84ba0db6 100644 --- a/partiql-planner/src/test/kotlin/org/partiql/planner/internal/typer/functions/NullIfTest.kt +++ b/partiql-planner/src/test/kotlin/org/partiql/planner/internal/typer/functions/NullIfTest.kt @@ -30,7 +30,7 @@ class NullIfTest : PartiQLTyperTestBase() { // Generate all success cases cartesianProduct(allSupportedType, allSupportedType).forEach { args -> - val expected = StaticType.unionOf(args[0], StaticType.NULL).flatten() + val expected = args[0] val result = TestResult.Success(expected) argsMap[result] = setOf(args) } diff --git a/partiql-planner/src/test/kotlin/org/partiql/planner/internal/typer/logical/OpLogicalTest.kt b/partiql-planner/src/test/kotlin/org/partiql/planner/internal/typer/logical/OpLogicalTest.kt index 996c318bd8..a788a00f65 100644 --- a/partiql-planner/src/test/kotlin/org/partiql/planner/internal/typer/logical/OpLogicalTest.kt +++ b/partiql-planner/src/test/kotlin/org/partiql/planner/internal/typer/logical/OpLogicalTest.kt @@ -3,7 +3,6 @@ package org.partiql.planner.internal.typer.logical import org.junit.jupiter.api.DynamicContainer import org.junit.jupiter.api.TestFactory import org.partiql.planner.internal.typer.PartiQLTyperTestBase -import org.partiql.planner.internal.typer.isUnknown import org.partiql.planner.util.allSupportedType import org.partiql.planner.util.cartesianProduct import org.partiql.types.StaticType @@ -15,11 +14,7 @@ import java.util.stream.Stream class OpLogicalTest : PartiQLTyperTestBase() { @TestFactory fun not(): Stream { - val supportedType = listOf( - StaticType.BOOL, - StaticType.NULL, - StaticType.MISSING, - ) + val supportedType = listOf(StaticType.BOOL) val unsupportedType = allSupportedType.filterNot { supportedType.contains(it) @@ -32,15 +27,8 @@ class OpLogicalTest : PartiQLTyperTestBase() { val argsMap = buildMap { val successArgs = supportedType.map { t -> listOf(t) }.toSet() successArgs.forEach { args: List -> - val arg = args.first() - if (arg.isUnknown()) { - (this[TestResult.Success(StaticType.NULL)] ?: setOf(args)).let { - put(TestResult.Success(StaticType.NULL), it + setOf(args)) - } - } else { - (this[TestResult.Success(StaticType.BOOL)] ?: setOf(args)).let { - put(TestResult.Success(StaticType.BOOL), it + setOf(args)) - } + (this[TestResult.Success(StaticType.BOOL)] ?: setOf(args)).let { + put(TestResult.Success(StaticType.BOOL), it + setOf(args)) } Unit } @@ -51,15 +39,9 @@ class OpLogicalTest : PartiQLTyperTestBase() { return super.testGen("not", tests, argsMap) } - // TODO: There is no good way to have the inferencer to distinguish whether the logical operator returns - // NULL, OR BOOL, OR UnionOf(Bool, NULL), other than have a lookup table in the inferencer. @TestFactory fun booleanConnective(): Stream { - val supportedType = listOf( - StaticType.BOOL, - StaticType.NULL, - StaticType.MISSING - ) + val supportedType = listOf(StaticType.BOOL) val tests = listOf( "expr-00", // OR @@ -75,7 +57,7 @@ class OpLogicalTest : PartiQLTyperTestBase() { successArgs.contains(it) }.toSet() - put(TestResult.Success(StaticType.unionOf(StaticType.BOOL, StaticType.NULL)), successArgs) + put(TestResult.Success(StaticType.BOOL), successArgs) put(TestResult.Failure, failureArgs) } diff --git a/partiql-planner/src/test/kotlin/org/partiql/planner/internal/typer/operator/OpArithmeticTest.kt b/partiql-planner/src/test/kotlin/org/partiql/planner/internal/typer/operator/OpArithmeticTest.kt index 940aa1dd21..9ab1d9123d 100644 --- a/partiql-planner/src/test/kotlin/org/partiql/planner/internal/typer/operator/OpArithmeticTest.kt +++ b/partiql-planner/src/test/kotlin/org/partiql/planner/internal/typer/operator/OpArithmeticTest.kt @@ -23,8 +23,7 @@ class OpArithmeticTest : PartiQLTyperTestBase() { ).map { inputs.get("basics", it)!! } val argsMap: Map>> = buildMap { - val successArgs = (allNumberType + listOf(StaticType.NULL)) - .let { cartesianProduct(it, it) } + val successArgs = allNumberType.let { cartesianProduct(it, it) } val failureArgs = cartesianProduct( allSupportedType, allSupportedType @@ -35,11 +34,7 @@ class OpArithmeticTest : PartiQLTyperTestBase() { successArgs.forEach { args: List -> val arg0 = args.first() val arg1 = args[1] - if (args.contains(StaticType.NULL)) { - (this[TestResult.Success(StaticType.NULL)] ?: setOf(args)).let { - put(TestResult.Success(StaticType.NULL), it + setOf(args)) - } - } else if (arg0 == arg1) { + if (arg0 == arg1) { (this[TestResult.Success(arg1)] ?: setOf(args)).let { put(TestResult.Success(arg1), it + setOf(args)) } diff --git a/partiql-planner/src/test/kotlin/org/partiql/planner/internal/typer/operator/OpBitwiseAndTest.kt b/partiql-planner/src/test/kotlin/org/partiql/planner/internal/typer/operator/OpBitwiseAndTest.kt index 398ebe805e..54822244b0 100644 --- a/partiql-planner/src/test/kotlin/org/partiql/planner/internal/typer/operator/OpBitwiseAndTest.kt +++ b/partiql-planner/src/test/kotlin/org/partiql/planner/internal/typer/operator/OpBitwiseAndTest.kt @@ -19,8 +19,7 @@ class OpBitwiseAndTest : PartiQLTyperTestBase() { ).map { inputs.get("basics", it)!! } val argsMap = buildMap { - val successArgs = (allIntType + listOf(StaticType.NULL)) - .let { cartesianProduct(it, it) } + val successArgs = allIntType.let { cartesianProduct(it, it) } val failureArgs = cartesianProduct( allSupportedType, allSupportedType @@ -31,11 +30,7 @@ class OpBitwiseAndTest : PartiQLTyperTestBase() { successArgs.forEach { args: List -> val arg0 = args.first() val arg1 = args[1] - if (args.contains(StaticType.NULL)) { - (this[TestResult.Success(StaticType.NULL)] ?: setOf(args)).let { - put(TestResult.Success(StaticType.NULL), it + setOf(args)) - } - } else if (arg0 == arg1) { + if (arg0 == arg1) { (this[TestResult.Success(arg1)] ?: setOf(args)).let { put(TestResult.Success(arg1), it + setOf(args)) } diff --git a/partiql-planner/src/test/kotlin/org/partiql/planner/internal/typer/operator/OpConcatTest.kt b/partiql-planner/src/test/kotlin/org/partiql/planner/internal/typer/operator/OpConcatTest.kt index b445d81818..87a2989212 100644 --- a/partiql-planner/src/test/kotlin/org/partiql/planner/internal/typer/operator/OpConcatTest.kt +++ b/partiql-planner/src/test/kotlin/org/partiql/planner/internal/typer/operator/OpConcatTest.kt @@ -19,8 +19,7 @@ class OpConcatTest : PartiQLTyperTestBase() { ).map { inputs.get("basics", it)!! } val argsMap = buildMap { - val successArgs = (allTextType + listOf(StaticType.NULL)) - .let { cartesianProduct(it, it) } + val successArgs = allTextType.let { cartesianProduct(it, it) } val failureArgs = cartesianProduct( allSupportedType, allSupportedType @@ -31,11 +30,7 @@ class OpConcatTest : PartiQLTyperTestBase() { successArgs.forEach { args: List -> val arg0 = args.first() val arg1 = args[1] - if (args.contains(StaticType.NULL)) { - (this[TestResult.Success(StaticType.NULL)] ?: setOf(args)).let { - put(TestResult.Success(StaticType.NULL), it + setOf(args)) - } - } else if (arg0 == arg1) { + if (arg0 == arg1) { (this[TestResult.Success(arg1)] ?: setOf(args)).let { put(TestResult.Success(arg1), it + setOf(args)) } diff --git a/partiql-planner/src/test/kotlin/org/partiql/planner/internal/typer/predicate/OpBetweenTest.kt b/partiql-planner/src/test/kotlin/org/partiql/planner/internal/typer/predicate/OpBetweenTest.kt index c42aa80fad..c51f64b4d9 100644 --- a/partiql-planner/src/test/kotlin/org/partiql/planner/internal/typer/predicate/OpBetweenTest.kt +++ b/partiql-planner/src/test/kotlin/org/partiql/planner/internal/typer/predicate/OpBetweenTest.kt @@ -21,25 +21,25 @@ class OpBetweenTest : PartiQLTyperTestBase() { val argsMap = buildMap { val successArgs = cartesianProduct( - allNumberType + listOf(StaticType.NULL), - allNumberType + listOf(StaticType.NULL), - allNumberType + listOf(StaticType.NULL), + allNumberType, + allNumberType, + allNumberType, ) + cartesianProduct( - StaticType.TEXT.allTypes + listOf(StaticType.CLOB, StaticType.NULL), - StaticType.TEXT.allTypes + listOf(StaticType.CLOB, StaticType.NULL), - StaticType.TEXT.allTypes + listOf(StaticType.CLOB, StaticType.NULL) + StaticType.TEXT.allTypes + listOf(StaticType.CLOB), + StaticType.TEXT.allTypes + listOf(StaticType.CLOB), + StaticType.TEXT.allTypes + listOf(StaticType.CLOB) ) + cartesianProduct( - listOf(StaticType.DATE, StaticType.NULL), - listOf(StaticType.DATE, StaticType.NULL), - listOf(StaticType.DATE, StaticType.NULL) + listOf(StaticType.DATE), + listOf(StaticType.DATE), + listOf(StaticType.DATE) ) + cartesianProduct( - listOf(StaticType.TIME, StaticType.NULL), - listOf(StaticType.TIME, StaticType.NULL), - listOf(StaticType.TIME, StaticType.NULL) + listOf(StaticType.TIME), + listOf(StaticType.TIME), + listOf(StaticType.TIME) ) + cartesianProduct( - listOf(StaticType.TIMESTAMP, StaticType.NULL), - listOf(StaticType.TIMESTAMP, StaticType.NULL), - listOf(StaticType.TIMESTAMP, StaticType.NULL) + listOf(StaticType.TIMESTAMP), + listOf(StaticType.TIMESTAMP), + listOf(StaticType.TIMESTAMP) ) val failureArgs = cartesianProduct( @@ -51,17 +51,8 @@ class OpBetweenTest : PartiQLTyperTestBase() { }.toSet() successArgs.forEach { args: List -> - val arg0 = args.first() - val arg1 = args[1] - val arg2 = args[2] - if (args.contains(StaticType.NULL)) { - (this[TestResult.Success(StaticType.NULL)] ?: setOf(args)).let { - put(TestResult.Success(StaticType.NULL), it + setOf(args)) - } - } else { - (this[TestResult.Success(StaticType.BOOL)] ?: setOf(args)).let { - put(TestResult.Success(StaticType.BOOL), it + setOf(args)) - } + (this[TestResult.Success(StaticType.BOOL)] ?: setOf(args)).let { + put(TestResult.Success(StaticType.BOOL), it + setOf(args)) } Unit } diff --git a/partiql-planner/src/test/kotlin/org/partiql/planner/internal/typer/predicate/OpComparisonTest.kt b/partiql-planner/src/test/kotlin/org/partiql/planner/internal/typer/predicate/OpComparisonTest.kt index 9e7130aa76..cbe2a515c5 100644 --- a/partiql-planner/src/test/kotlin/org/partiql/planner/internal/typer/predicate/OpComparisonTest.kt +++ b/partiql-planner/src/test/kotlin/org/partiql/planner/internal/typer/predicate/OpComparisonTest.kt @@ -22,18 +22,8 @@ class OpComparisonTest : PartiQLTyperTestBase() { val successArgs = cartesianProduct(allSupportedType, allSupportedType) successArgs.forEach { args: List -> - if (args.contains(StaticType.MISSING)) { - (this[TestResult.Success(StaticType.NULL)] ?: setOf(args)).let { - put(TestResult.Success(StaticType.NULL), it + setOf(args)) - } - } else if (args.contains(StaticType.NULL)) { - (this[TestResult.Success(StaticType.NULL)] ?: setOf(args)).let { - put(TestResult.Success(StaticType.NULL), it + setOf(args)) - } - } else { - (this[TestResult.Success(StaticType.BOOL)] ?: setOf(args)).let { - put(TestResult.Success(StaticType.BOOL), it + setOf(args)) - } + (this[TestResult.Success(StaticType.BOOL)] ?: setOf(args)).let { + put(TestResult.Success(StaticType.BOOL), it + setOf(args)) } put(TestResult.Failure, emptySet>()) } @@ -55,23 +45,23 @@ class OpComparisonTest : PartiQLTyperTestBase() { val argsMap = buildMap { val successArgs = cartesianProduct( - StaticType.NUMERIC.allTypes + listOf(StaticType.NULL), - StaticType.NUMERIC.allTypes + listOf(StaticType.NULL) + StaticType.NUMERIC.allTypes, + StaticType.NUMERIC.allTypes ) + cartesianProduct( - StaticType.TEXT.allTypes + listOf(StaticType.CLOB, StaticType.NULL), - StaticType.TEXT.allTypes + listOf(StaticType.CLOB, StaticType.NULL) + StaticType.TEXT.allTypes + listOf(StaticType.CLOB), + StaticType.TEXT.allTypes + listOf(StaticType.CLOB) ) + cartesianProduct( - listOf(StaticType.BOOL, StaticType.NULL), - listOf(StaticType.BOOL, StaticType.NULL) + listOf(StaticType.BOOL), + listOf(StaticType.BOOL) ) + cartesianProduct( - listOf(StaticType.DATE, StaticType.NULL), - listOf(StaticType.DATE, StaticType.NULL) + listOf(StaticType.DATE), + listOf(StaticType.DATE) ) + cartesianProduct( - listOf(StaticType.TIME, StaticType.NULL), - listOf(StaticType.TIME, StaticType.NULL) + listOf(StaticType.TIME), + listOf(StaticType.TIME) ) + cartesianProduct( - listOf(StaticType.TIMESTAMP, StaticType.NULL), - listOf(StaticType.TIMESTAMP, StaticType.NULL) + listOf(StaticType.TIMESTAMP), + listOf(StaticType.TIMESTAMP) ) val failureArgs = cartesianProduct( @@ -82,14 +72,8 @@ class OpComparisonTest : PartiQLTyperTestBase() { }.toSet() successArgs.forEach { args: List -> - if (args.contains(StaticType.NULL)) { - (this[TestResult.Success(StaticType.NULL)] ?: setOf(args)).let { - put(TestResult.Success(StaticType.NULL), it + setOf(args)) - } - } else { - (this[TestResult.Success(StaticType.BOOL)] ?: setOf(args)).let { - put(TestResult.Success(StaticType.BOOL), it + setOf(args)) - } + (this[TestResult.Success(StaticType.BOOL)] ?: setOf(args)).let { + put(TestResult.Success(StaticType.BOOL), it + setOf(args)) } Unit } diff --git a/partiql-planner/src/test/kotlin/org/partiql/planner/internal/typer/predicate/OpInTest.kt b/partiql-planner/src/test/kotlin/org/partiql/planner/internal/typer/predicate/OpInTest.kt index 04ee00a47c..d7c477d77a 100644 --- a/partiql-planner/src/test/kotlin/org/partiql/planner/internal/typer/predicate/OpInTest.kt +++ b/partiql-planner/src/test/kotlin/org/partiql/planner/internal/typer/predicate/OpInTest.kt @@ -6,7 +6,6 @@ import org.partiql.planner.internal.typer.PartiQLTyperTestBase import org.partiql.planner.util.allCollectionType import org.partiql.planner.util.allSupportedType import org.partiql.planner.util.cartesianProduct -import org.partiql.types.MissingType import org.partiql.types.StaticType import java.util.stream.Stream @@ -21,19 +20,12 @@ class OpInTest : PartiQLTyperTestBase() { val argsMap = buildMap { val successArgs = allSupportedType - .filterNot { it is MissingType } .map { t -> listOf(t) } .toSet() successArgs.forEach { args: List -> - if (args.contains(StaticType.NULL)) { - (this[TestResult.Success(StaticType.NULL)] ?: setOf(args)).let { - put(TestResult.Success(StaticType.NULL), it + setOf(args)) - } - } else { - (this[TestResult.Success(StaticType.BOOL)] ?: setOf(args)).let { - put(TestResult.Success(StaticType.BOOL), it + setOf(args)) - } + (this[TestResult.Success(StaticType.BOOL)] ?: setOf(args)).let { + put(TestResult.Success(StaticType.BOOL), it + setOf(args)) } Unit } @@ -51,8 +43,8 @@ class OpInTest : PartiQLTyperTestBase() { val argsMap = buildMap { val successArgs = cartesianProduct( - allSupportedType.filterNot { it is MissingType }, - (allCollectionType + listOf(StaticType.NULL)) + allSupportedType, + allCollectionType ) val failureArgs = cartesianProduct( allSupportedType, @@ -62,14 +54,8 @@ class OpInTest : PartiQLTyperTestBase() { }.toSet() successArgs.forEach { args: List -> - if (args.contains(StaticType.NULL)) { - (this[TestResult.Success(StaticType.NULL)] ?: setOf(args)).let { - put(TestResult.Success(StaticType.NULL), it + setOf(args)) - } - } else { - (this[TestResult.Success(StaticType.BOOL)] ?: setOf(args)).let { - put(TestResult.Success(StaticType.BOOL), it + setOf(args)) - } + (this[TestResult.Success(StaticType.BOOL)] ?: setOf(args)).let { + put(TestResult.Success(StaticType.BOOL), it + setOf(args)) } Unit } diff --git a/partiql-planner/src/test/kotlin/org/partiql/planner/internal/typer/predicate/OpLikeTest.kt b/partiql-planner/src/test/kotlin/org/partiql/planner/internal/typer/predicate/OpLikeTest.kt index 8f7ec051f6..3e7b3d3fee 100644 --- a/partiql-planner/src/test/kotlin/org/partiql/planner/internal/typer/predicate/OpLikeTest.kt +++ b/partiql-planner/src/test/kotlin/org/partiql/planner/internal/typer/predicate/OpLikeTest.kt @@ -17,7 +17,7 @@ class OpLikeTest : PartiQLTyperTestBase() { ).map { inputs.get("basics", it)!! } val argsMap = buildMap { - val successArgs = (allTextType + listOf(StaticType.NULL)) + val successArgs = (allTextType) .let { cartesianProduct(it, it) } val failureArgs = cartesianProduct( allSupportedType, @@ -27,14 +27,8 @@ class OpLikeTest : PartiQLTyperTestBase() { }.toSet() successArgs.forEach { args: List -> - if (args.contains(StaticType.NULL)) { - (this[TestResult.Success(StaticType.NULL)] ?: setOf(args)).let { - put(TestResult.Success(StaticType.NULL), it + setOf(args)) - } - } else { - (this[TestResult.Success(StaticType.BOOL)] ?: setOf(args)).let { - put(TestResult.Success(StaticType.BOOL), it + setOf(args)) - } + (this[TestResult.Success(StaticType.BOOL)] ?: setOf(args)).let { + put(TestResult.Success(StaticType.BOOL), it + setOf(args)) } Unit } @@ -51,7 +45,7 @@ class OpLikeTest : PartiQLTyperTestBase() { ).map { inputs.get("basics", it)!! } val argsMap = buildMap { - val successArgs = (allTextType + listOf(StaticType.NULL)) + val successArgs = (allTextType) .let { cartesianProduct(it, it, it) } val failureArgs = cartesianProduct( allSupportedType, @@ -62,14 +56,8 @@ class OpLikeTest : PartiQLTyperTestBase() { }.toSet() successArgs.forEach { args: List -> - if (args.contains(StaticType.NULL)) { - (this[TestResult.Success(StaticType.NULL)] ?: setOf(args)).let { - put(TestResult.Success(StaticType.NULL), it + setOf(args)) - } - } else { - (this[TestResult.Success(StaticType.BOOL)] ?: setOf(args)).let { - put(TestResult.Success(StaticType.BOOL), it + setOf(args)) - } + (this[TestResult.Success(StaticType.BOOL)] ?: setOf(args)).let { + put(TestResult.Success(StaticType.BOOL), it + setOf(args)) } Unit } diff --git a/partiql-planner/src/test/kotlin/org/partiql/planner/internal/typer/predicate/OpTypeAssertionTest.kt b/partiql-planner/src/test/kotlin/org/partiql/planner/internal/typer/predicate/OpTypeAssertionTest.kt index d418b7b313..dad9bc9dd7 100644 --- a/partiql-planner/src/test/kotlin/org/partiql/planner/internal/typer/predicate/OpTypeAssertionTest.kt +++ b/partiql-planner/src/test/kotlin/org/partiql/planner/internal/typer/predicate/OpTypeAssertionTest.kt @@ -4,7 +4,7 @@ import org.junit.jupiter.api.DynamicContainer import org.junit.jupiter.api.TestFactory import org.partiql.planner.internal.typer.PartiQLTyperTestBase import org.partiql.planner.util.allSupportedType -import org.partiql.types.MissingType +import org.partiql.types.SingleType import org.partiql.types.StaticType import java.util.stream.Stream @@ -18,12 +18,11 @@ class OpTypeAssertionTest : PartiQLTyperTestBase() { }.map { inputs.get("basics", it)!! } val argsMap = buildMap { - val successArgs = allSupportedType.filterNot { it is MissingType }.flatMap { t -> + val successArgs = allSupportedType.flatMap { t -> setOf(listOf(t)) }.toSet() - val failureArgs = setOf(listOf(MissingType)) put(TestResult.Success(StaticType.BOOL), successArgs) - put(TestResult.Failure, failureArgs) + put(TestResult.Failure, emptySet>()) } return super.testGen("type-assertion", tests, argsMap) diff --git a/partiql-planner/src/test/kotlin/org/partiql/planner/util/Utils.kt b/partiql-planner/src/test/kotlin/org/partiql/planner/util/Utils.kt index a94fae4600..adcd569fa9 100644 --- a/partiql-planner/src/test/kotlin/org/partiql/planner/util/Utils.kt +++ b/partiql-planner/src/test/kotlin/org/partiql/planner/util/Utils.kt @@ -28,7 +28,13 @@ fun cartesianProduct(a: List, b: List, vararg lists: List): Set set.map { element -> list + element } } }.toSet() -val allSupportedType = StaticType.ALL_TYPES.filterNot { it == StaticType.GRAPH } +val allSupportedType = StaticType.ALL_TYPES.filterNot { + it == StaticType.GRAPH +}.filterNot { + it is NullType +}.filterNot { + it is MissingType +} val allSupportedTypeNotUnknown = allSupportedType.filterNot { it == StaticType.MISSING || it == StaticType.NULL } diff --git a/partiql-planner/src/testFixtures/resources/catalogs/default/pql/main/item.ion b/partiql-planner/src/testFixtures/resources/catalogs/default/pql/main/item.ion index 2622a7b130..cac9705ceb 100644 --- a/partiql-planner/src/testFixtures/resources/catalogs/default/pql/main/item.ion +++ b/partiql-planner/src/testFixtures/resources/catalogs/default/pql/main/item.ion @@ -5,17 +5,11 @@ fields: [ { name: "i_item_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "i_item_id", - type: [ - "string", - "null" - ] + type: "string" }, { name: "i_rec", @@ -25,27 +19,18 @@ fields: [ { name: "i_rec_start_date", - type: [ - "int64", - "null" - ] + type: "int64" }, { name: "i_rec_end_date", - type: [ - "int64", - "null" - ] + type: "int64" }, ] }, }, { name: "i_item_desc", - type: [ - "string", - "null" - ] + type: "string" }, { name: "pricing", @@ -54,111 +39,66 @@ fields: [ { name: "i_current_price", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "i_wholesale_cost", - type: [ - "float64", - "null" - ] + type: "float64" }, ] }, }, { name: "i_brand_id", - type: [ - "int32", - "null" - ] + type: "int32" }, { name: "i_brand", - type: [ - "string", - "null" - ] + type: "string" }, { name: "i_class_id", - type: [ - "int32", - "null" - ] + type: "int32" }, { name: "i_class", - type: [ - "string", - "null" - ] + type: "string" }, { name: "i_category_id", - type: [ - "int32", - "null" - ] + type: "int32" }, { name: "i_category", - type: [ - "string", - "null" - ] + type: "string" }, { name: "i_manufact_id", - type: [ - "int32", - "null" - ] + type: "int32" }, { name: "i_manufact", - type: [ - "string", - "null" - ] + type: "string" }, { name: "i_size", - type: [ - "string", - "null" - ] + type: "string" }, { name: "i_formulation", - type: [ - "string", - "null" - ] + type: "string" }, { name: "i_color", - type: [ - "string", - "null" - ] + type: "string" }, { name: "i_units", - type: [ - "string", - "null" - ] + type: "string" }, { name: "i_container", - type: [ - "string", - "null" - ] + type: "string" }, { name: "manager_info", @@ -174,12 +114,11 @@ }, { name: "manager_name", - type: ["string", "null"] + type: "string" }, { name: "manager_address", type: [ - "null", { type: "struct", constraints: [ closed, unique, ordered ], @@ -190,7 +129,7 @@ }, { name: "house_number", - type: ["int32", "null"] + type: "int32" } ] } @@ -201,10 +140,7 @@ }, { name: "i_product_name", - type: [ - "string", - "null" - ] + type: "string" } ] } diff --git a/partiql-planner/src/testFixtures/resources/catalogs/default/pql/main/person.ion b/partiql-planner/src/testFixtures/resources/catalogs/default/pql/main/person.ion index 70afca8674..cadd433342 100644 --- a/partiql-planner/src/testFixtures/resources/catalogs/default/pql/main/person.ion +++ b/partiql-planner/src/testFixtures/resources/catalogs/default/pql/main/person.ion @@ -26,10 +26,7 @@ }, { name: "employer", - type: [ - "string", - "null" - ] + type: "string" } ] } diff --git a/partiql-planner/src/testFixtures/resources/catalogs/default/pql/numbers.ion b/partiql-planner/src/testFixtures/resources/catalogs/default/pql/numbers.ion index 311e5a474d..fe5789214b 100644 --- a/partiql-planner/src/testFixtures/resources/catalogs/default/pql/numbers.ion +++ b/partiql-planner/src/testFixtures/resources/catalogs/default/pql/numbers.ion @@ -6,40 +6,28 @@ name: "nullable_int16s", type: { type: "list", - items: [ - "int16", - "null" - ] + items: "int16" } }, { name: "nullable_int32s", type: { type: "list", - items: [ - "int32", - "null" - ] + items: "int32" } }, { name: "nullable_int64s", type: { type: "list", - items: [ - "int64", - "null" - ] + items: "int64" } }, { name: "nullable_ints", type: { type: "list", - items: [ - "int", - "null" - ] + items: "int" } }, { @@ -85,20 +73,14 @@ name: "nullable_float32s", type: { type: "list", - items: [ - "float32", - "null" - ] + items: "float32" } }, { name: "nullable_float64s", type: { type: "list", - items: [ - "float64", - "null" - ] + items: "float64" } }, { diff --git a/partiql-planner/src/testFixtures/resources/catalogs/default/pql/t_item.ion b/partiql-planner/src/testFixtures/resources/catalogs/default/pql/t_item.ion index e4435d624c..6aac443aa4 100644 --- a/partiql-planner/src/testFixtures/resources/catalogs/default/pql/t_item.ion +++ b/partiql-planner/src/testFixtures/resources/catalogs/default/pql/t_item.ion @@ -10,7 +10,7 @@ }, { name: "t_bool_nul", - type: ["bool","null"], + type: "bool", }, // Exact Numeric // { @@ -19,7 +19,7 @@ // }, // { // name: "t_int8_null", -// type: ["int8", "null"], +// type: "int8", // }, { name: "t_int16", @@ -27,7 +27,7 @@ }, { name: "t_int16_null", - type: ["int16", "null"], + type: "int16", }, { name: "t_int32", @@ -35,7 +35,7 @@ }, { name: "t_int32_null", - type: ["int32", "null"], + type: "int32", }, { name: "t_int64", @@ -43,7 +43,7 @@ }, { name: "t_int64_null", - type: ["int64", "null"], + type: "int64", }, { name: "t_int", @@ -51,7 +51,7 @@ }, { name: "t_int_null", - type: ["int", "null"], + type: "int", }, { name: "t_decimal", @@ -59,7 +59,7 @@ }, { name: "t_decimal_null", - type: ["decimal", "null"], + type: "decimal", }, // Approximate Numeric { @@ -68,7 +68,7 @@ }, { name: "t_float32_null", - type: ["float32", "null"], + type: "float32", }, { name: "t_float64", @@ -76,7 +76,7 @@ }, { name: "t_float64_null", - type: ["float64", "null"], + type: "float64", }, // Strings { @@ -85,7 +85,7 @@ }, { name: "t_string_null", - type: ["string", "null"], + type: "string", }, { name: "t_clob", @@ -93,20 +93,20 @@ }, { name: "t_clob_null", - type: ["clob", "null"], + type: "clob", }, - // absent + // potentially absent { name: "t_null", - type: "null", + type: "any", }, { name: "t_missing", - type: "missing", + type: "any", }, { name: "t_absent", - type: ["null", "missing"], + type: "any", }, // collections { @@ -174,7 +174,7 @@ }, { name: "t_num_exact_null", - type: [ "int16", "int32", "int64", "int", "decimal", "null" ], + type: [ "int16", "int32", "int64", "int", "decimal" ], }, { name: "t_str", diff --git a/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/call_center.ion b/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/call_center.ion index ea3dc3c061..c946260ea9 100644 --- a/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/call_center.ion +++ b/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/call_center.ion @@ -13,206 +13,119 @@ call_center::{ }, { name: "cc_rec_start_date", - type: [ - "int64", - "null" - ] + type: "int64" }, { name: "cc_rec_end_date", - type: [ - "int64", - "null" - ] + type: "int64" }, { name: "cc_closed_date_sk", - type: [ - "int32", - "null" - ] + type: "int32" }, { name: "cc_open_date_sk", - type: [ - "int32", - "null" - ] + type: "int32" }, { name: "cc_name", - type: [ - "string", - "null" - ] + type: "string" }, { name: "cc_class", - type: [ - "string", - "null" - ] + type: "string" }, { name: "cc_employees", - type: [ - "int32", - "null" - ] + type: "int32" }, { name: "cc_sq_ft", - type: [ - "int32", - "null" - ] + type: "int32" }, { name: "cc_hours", - type: [ - "string", - "null" - ] + type: "string" }, { name: "cc_manager", - type: [ - "string", - "null" - ] + type: "string" }, { name: "cc_mkt_id", - type: [ - "int32", - "null" - ] + type: "int32" }, { name: "cc_mkt_class", - type: [ - "string", - "null" - ] + type: "string" }, { name: "cc_mkt_desc", - type: [ - "string", - "null" - ] + type: "string" }, { name: "cc_market_manager", - type: [ - "string", - "null" - ] + type: "string" }, { name: "cc_division", - type: [ - "int32", - "null" - ] + type: "int32" }, { name: "cc_division_name", - type: [ - "string", - "null" - ] + type: "string" }, { name: "cc_company", - type: [ - "int32", - "null" - ] + type: "int32" }, { name: "cc_company_name", - type: [ - "string", - "null" - ] + type: "string" }, { name: "cc_street_number", - type: [ - "string", - "null" - ] + type: "string" }, { name: "cc_street_name", - type: [ - "string", - "null" - ] + type: "string" }, { name: "cc_street_type", - type: [ - "string", - "null" - ] + type: "string" }, { name: "cc_suite_number", - type: [ - "string", - "null" - ] + type: "string" }, { name: "cc_city", - type: [ - "string", - "null" - ] + type: "string" }, { name: "cc_county", - type: [ - "string", - "null" - ] + type: "string" }, { name: "cc_state", - type: [ - "string", - "null" - ] + type: "string" }, { name: "cc_zip", - type: [ - "string", - "null" - ] + type: "string" }, { name: "cc_country", - type: [ - "string", - "null" - ] + type: "string" }, { name: "cc_gmt_offset", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "cc_tax_percentage", - type: [ - "float64", - "null" - ] + type: "float64" } ] } diff --git a/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/catalog_page.ion b/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/catalog_page.ion index 272df0daa9..e46326535d 100644 --- a/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/catalog_page.ion +++ b/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/catalog_page.ion @@ -5,66 +5,39 @@ catalog_page::{ fields: [ { name: "cp_catalog_page_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "cp_catalog_page_id", - type: [ - "string", - "null" - ] + type: "string" }, { name: "cp_start_date_sk", - type: [ - "int32", - "null" - ] + type: "int32" }, { name: "cp_end_date_sk", - type: [ - "int32", - "null" - ] + type: "int32" }, { name: "cp_department", - type: [ - "string", - "null" - ] + type: "string" }, { name: "cp_catalog_number", - type: [ - "int32", - "null" - ] + type: "int32" }, { name: "cp_catalog_page_number", - type: [ - "int32", - "null" - ] + type: "int32" }, { name: "cp_description", - type: [ - "string", - "null" - ] + type: "string" }, { name: "cp_type", - type: [ - "string", - "null" - ] + type: "string" } ] } diff --git a/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/catalog_returns.ion b/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/catalog_returns.ion index bd881456c5..6562469e16 100644 --- a/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/catalog_returns.ion +++ b/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/catalog_returns.ion @@ -5,192 +5,111 @@ catalog_returns::{ fields: [ { name: "cr_returned_date_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "cr_returned_time_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "cr_item_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "cr_refunded_customer_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "cr_refunded_cdemo_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "cr_refunded_hdemo_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "cr_refunded_addr_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "cr_returning_customer_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "cr_returning_cdemo_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "cr_returning_hdemo_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "cr_returning_addr_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "cr_call_center_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "cr_catalog_page_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "cr_ship_mode_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "cr_warehouse_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "cr_reason_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "cr_order_number", - type: [ - "string", - "null" - ] + type: "string" }, { name: "cr_return_quantity", - type: [ - "int32", - "null" - ] + type: "int32" }, { name: "cr_return_amount", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "cr_return_tax", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "cr_return_amt_inc_tax", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "cr_fee", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "cr_return_ship_cost", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "cr_refunded_cash", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "cr_reversed_charge", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "cr_store_credit", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "cr_net_loss", - type: [ - "float64", - "null" - ] + type: "float64" } ] } diff --git a/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/catalog_sales.ion b/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/catalog_sales.ion index b6f620e99c..086632b48d 100644 --- a/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/catalog_sales.ion +++ b/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/catalog_sales.ion @@ -5,108 +5,63 @@ catalog_sales::{ fields: [ { name: "cs_sold_date_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "cs_sold_time_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "cs_ship_date_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "cs_bill_customer_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "cs_bill_cdemo_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "cs_bill_hdemo_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "cs_bill_addr_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "cs_ship_customer_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "cs_ship_cdemo_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "cs_ship_hdemo_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "cs_ship_addr_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "cs_call_center_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "cs_catalog_page_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "cs_ship_mode_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "cs_warehouse_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "cs_item_sk", @@ -114,10 +69,7 @@ catalog_sales::{ }, { name: "cs_promo_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "cs_order_number", @@ -125,115 +77,67 @@ catalog_sales::{ }, { name: "cs_quantity", - type: [ - "int32", - "null" - ] + type: "int32" }, { name: "cs_wholesale_cost", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "cs_list_price", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "cs_sales_price", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "cs_ext_discount_amt", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "cs_ext_sales_price", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "cs_ext_wholesale_cost", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "cs_ext_list_price", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "cs_ext_tax", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "cs_coupon_amt", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "cs_ext_ship_cost", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "cs_net_paid", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "cs_net_paid_inc_tax", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "cs_net_paid_inc_ship", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "cs_net_paid_inc_ship_tax", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "cs_net_profit", - type: [ - "float64", - "null" - ] + type: "float64" } ] } diff --git a/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/customer.ion b/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/customer.ion index 55b76c52ec..1f3e5a859c 100644 --- a/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/customer.ion +++ b/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/customer.ion @@ -5,129 +5,75 @@ customer::{ fields: [ { name: "c_customer_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "c_customer_id", - type: [ - "string", - "null" - ] + type: "string" }, { name: "c_current_cdemo_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "c_current_hdemo_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "c_current_addr_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "c_first_shipto_date_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "c_first_sales_date_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "c_salutation", - type: [ - "string", - "null" - ] + type: "string" }, { name: "c_first_name", - type: [ - "string", - "null" - ] + type: "string" }, { name: "c_last_name", - type: [ - "string", - "null" - ] + type: "string" }, { name: "c_preferred_cust_flag", - type: [ - "string", - "null" - ] + type: "string" }, { name: "c_birth_day", - type: [ - "int32", - "null" - ] + type: "int32" }, { name: "c_birth_month", - type: [ - "int32", - "null" - ] + type: "int32" }, { name: "c_birth_year", - type: [ - "int32", - "null" - ] + type: "int32" }, { name: "c_birth_country", - type: [ - "string", - "null" - ] + type: "string" }, { name: "c_login", - type: [ - "string", - "null" - ] + type: "string" }, { name: "c_email_address", - type: [ - "string", - "null" - ] + type: "string" }, { name: "c_last_review_date_sk", - type: [ - "string", - "null" - ] + type: "string" } ] } diff --git a/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/customer_address.ion b/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/customer_address.ion index 7105c7d866..557721601c 100644 --- a/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/customer_address.ion +++ b/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/customer_address.ion @@ -5,94 +5,55 @@ customer_address::{ fields: [ { name: "ca_address_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "ca_address_id", - type: [ - "string", - "null" - ] + type: "string" }, { name: "ca_street_number", - type: [ - "string", - "null" - ] + type: "string" }, { name: "ca_street_name", - type: [ - "string", - "null" - ] + type: "string" }, { name: "ca_street_type", - type: [ - "string", - "null" - ] + type: "string" }, { name: "ca_suite_number", - type: [ - "string", - "null" - ] + type: "string" }, { name: "ca_city", - type: [ - "string", - "null" - ] + type: "string" }, { name: "ca_county", - type: [ - "string", - "null" - ] + type: "string" }, { name: "ca_state", - type: [ - "string", - "null" - ] + type: "string" }, { name: "ca_zip", - type: [ - "string", - "null" - ] + type: "string" }, { name: "ca_country", - type: [ - "string", - "null" - ] + type: "string" }, { name: "ca_gmt_offset", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "ca_location_type", - type: [ - "string", - "null" - ] + type: "string" } ] } diff --git a/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/customer_demographics.ion b/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/customer_demographics.ion index 9634b7762c..bf5bfda9cf 100644 --- a/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/customer_demographics.ion +++ b/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/customer_demographics.ion @@ -5,66 +5,39 @@ customer_demographics::{ fields: [ { name: "cd_demo_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "cd_gender", - type: [ - "string", - "null" - ] + type: "string" }, { name: "cd_marital_status", - type: [ - "string", - "null" - ] + type: "string" }, { name: "cd_education_status", - type: [ - "string", - "null" - ] + type: "string" }, { name: "cd_purchase_estimate", - type: [ - "int32", - "null" - ] + type: "int32" }, { name: "cd_credit_rating", - type: [ - "string", - "null" - ] + type: "string" }, { name: "cd_dep_count", - type: [ - "int32", - "null" - ] + type: "int32" }, { name: "cd_dep_employed_count", - type: [ - "int32", - "null" - ] + type: "int32" }, { name: "cd_dep_college_count", - type: [ - "int32", - "null" - ] + type: "int32" } ] } diff --git a/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/date_dim.ion b/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/date_dim.ion index 9ae5bb3789..99624477b7 100644 --- a/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/date_dim.ion +++ b/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/date_dim.ion @@ -5,199 +5,115 @@ date_dim::{ fields: [ { name: "d_date_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "d_date_id", - type: [ - "string", - "null" - ] + type: "string" }, { name: "d_date", - type: [ - "int64", - "null" - ] + type: "int64" }, { name: "d_month_seq", - type: [ - "int32", - "null" - ] + type: "int32" }, { name: "d_week_seq", - type: [ - "int32", - "null" - ] + type: "int32" }, { name: "d_quarter_seq", - type: [ - "int32", - "null" - ] + type: "int32" }, { name: "d_year", - type: [ - "int32", - "null" - ] + type: "int32" }, { name: "d_dow", - type: [ - "int32", - "null" - ] + type: "int32" }, { name: "d_moy", - type: [ - "int32", - "null" - ] + type: "int32" }, { name: "d_dom", - type: [ - "int32", - "null" - ] + type: "int32" }, { name: "d_qoy", - type: [ - "int32", - "null" - ] + type: "int32" }, { name: "d_fy_year", - type: [ - "int32", - "null" - ] + type: "int32" }, { name: "d_fy_quarter_seq", - type: [ - "int32", - "null" - ] + type: "int32" }, { name: "d_fy_week_seq", - type: [ - "int32", - "null" - ] + type: "int32" }, { name: "d_day_name", - type: [ - "string", - "null" - ] + type: "string" }, { name: "d_quarter_name", - type: [ - "string", - "null" - ] + type: "string" }, { name: "d_holiday", - type: [ - "string", - "null" - ] + type: "string" }, { name: "d_weekend", - type: [ - "string", - "null" - ] + type: "string" }, { name: "d_following_holiday", - type: [ - "string", - "null" - ] + type: "string" }, { name: "d_first_dom", - type: [ - "int32", - "null" - ] + type: "int32" }, { name: "d_last_dom", - type: [ - "int32", - "null" - ] + type: "int32" }, { name: "d_same_day_ly", - type: [ - "int32", - "null" - ] + type: "int32" }, { name: "d_same_day_lq", - type: [ - "int32", - "null" - ] + type: "int32" }, { name: "d_current_day", - type: [ - "string", - "null" - ] + type: "string" }, { name: "d_current_week", - type: [ - "string", - "null" - ] + type: "string" }, { name: "d_current_month", - type: [ - "string", - "null" - ] + type: "string" }, { name: "d_current_quarter", - type: [ - "string", - "null" - ] + type: "string" }, { name: "d_current_year", - type: [ - "string", - "null" - ] + type: "string" } ] } diff --git a/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/dbgen_version.ion b/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/dbgen_version.ion index 1f66c8ea37..7c0b3760b5 100644 --- a/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/dbgen_version.ion +++ b/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/dbgen_version.ion @@ -5,31 +5,19 @@ dbgen_version::{ fields: [ { name: "dv_version", - type: [ - "string", - "null" - ] + type: "string" }, { name: "dv_create_date", - type: [ - "int64", - "null" - ] + type: "int64" }, { name: "dv_create_time", - type: [ - "int64", - "null" - ] + type: "int64" }, { name: "dv_cmdline_args", - type: [ - "string", - "null" - ] + type: "string" } ] } diff --git a/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/household_demographics.ion b/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/household_demographics.ion index 6f361cfb82..04003e132e 100644 --- a/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/household_demographics.ion +++ b/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/household_demographics.ion @@ -5,38 +5,23 @@ household_demographics::{ fields: [ { name: "hd_demo_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "hd_income_band_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "hd_buy_potential", - type: [ - "string", - "null" - ] + type: "string" }, { name: "hd_dep_count", - type: [ - "int32", - "null" - ] + type: "int32" }, { name: "hd_vehicle_count", - type: [ - "int32", - "null" - ] + type: "int32" } ] } diff --git a/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/income_band.ion b/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/income_band.ion index ccf094c26d..4ec6f28903 100644 --- a/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/income_band.ion +++ b/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/income_band.ion @@ -5,24 +5,15 @@ income_band::{ fields: [ { name: "ib_income_band_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "ib_lower_bound", - type: [ - "int32", - "null" - ] + type: "int32" }, { name: "ib_upper_bound", - type: [ - "int32", - "null" - ] + type: "int32" } ] } diff --git a/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/inventory.ion b/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/inventory.ion index 6552d9111c..2cf1765947 100644 --- a/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/inventory.ion +++ b/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/inventory.ion @@ -5,31 +5,19 @@ inventory::{ fields: [ { name: "inv_date_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "inv_item_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "inv_warehouse_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "inv_quantity_on_hand", - type: [ - "int32", - "null" - ] + type: "int32" } ] } diff --git a/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/item.ion b/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/item.ion index b6cb30233c..becd58f9c6 100644 --- a/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/item.ion +++ b/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/item.ion @@ -5,157 +5,91 @@ item::{ fields: [ { name: "i_item_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "i_item_id", - type: [ - "string", - "null" - ] + type: "string" }, { name: "i_rec_start_date", - type: [ - "int64", - "null" - ] + type: "int64" }, { name: "i_rec_end_date", - type: [ - "int64", - "null" - ] + type: "int64" }, { name: "i_item_desc", - type: [ - "string", - "null" - ] + type: "string" }, { name: "i_current_price", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "i_wholesale_cost", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "i_brand_id", - type: [ - "int32", - "null" - ] + type: "int32" }, { name: "i_brand", - type: [ - "string", - "null" - ] + type: "string" }, { name: "i_class_id", - type: [ - "int32", - "null" - ] + type: "int32" }, { name: "i_class", - type: [ - "string", - "null" - ] + type: "string" }, { name: "i_category_id", - type: [ - "int32", - "null" - ] + type: "int32" }, { name: "i_category", - type: [ - "string", - "null" - ] + type: "string" }, { name: "i_manufact_id", - type: [ - "int32", - "null" - ] + type: "int32" }, { name: "i_manufact", - type: [ - "string", - "null" - ] + type: "string" }, { name: "i_size", - type: [ - "string", - "null" - ] + type: "string" }, { name: "i_formulation", - type: [ - "string", - "null" - ] + type: "string" }, { name: "i_color", - type: [ - "string", - "null" - ] + type: "string" }, { name: "i_units", - type: [ - "string", - "null" - ] + type: "string" }, { name: "i_container", - type: [ - "string", - "null" - ] + type: "string" }, { name: "i_manager_id", - type: [ - "int32", - "null" - ] + type: "int32" }, { name: "i_product_name", - type: [ - "string", - "null" - ] + type: "string" } ] } diff --git a/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/promotion.ion b/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/promotion.ion index be727f19f6..c6b3b8f766 100644 --- a/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/promotion.ion +++ b/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/promotion.ion @@ -5,136 +5,79 @@ promotion::{ fields: [ { name: "p_promo_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "p_promo_id", - type: [ - "string", - "null" - ] + type: "string" }, { name: "p_start_date_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "p_end_date_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "p_item_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "p_cost", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "p_response_targe", - type: [ - "int32", - "null" - ] + type: "int32" }, { name: "p_promo_name", - type: [ - "string", - "null" - ] + type: "string" }, { name: "p_channel_dmail", - type: [ - "string", - "null" - ] + type: "string" }, { name: "p_channel_email", - type: [ - "string", - "null" - ] + type: "string" }, { name: "p_channel_catalog", - type: [ - "string", - "null" - ] + type: "string" }, { name: "p_channel_tv", - type: [ - "string", - "null" - ] + type: "string" }, { name: "p_channel_radio", - type: [ - "string", - "null" - ] + type: "string" }, { name: "p_channel_press", - type: [ - "string", - "null" - ] + type: "string" }, { name: "p_channel_event", - type: [ - "string", - "null" - ] + type: "string" }, { name: "p_channel_demo", - type: [ - "string", - "null" - ] + type: "string" }, { name: "p_channel_details", - type: [ - "string", - "null" - ] + type: "string" }, { name: "p_purpose", - type: [ - "string", - "null" - ] + type: "string" }, { name: "p_discount_active", - type: [ - "string", - "null" - ] + type: "string" } ] } diff --git a/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/reason.ion b/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/reason.ion index 4223e44e71..2801abf7d6 100644 --- a/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/reason.ion +++ b/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/reason.ion @@ -5,24 +5,15 @@ reason::{ fields: [ { name: "r_reason_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "r_reason_id", - type: [ - "string", - "null" - ] + type: "string" }, { name: "r_reason_desc", - type: [ - "string", - "null" - ] + type: "string" } ] } diff --git a/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/ship_mode.ion b/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/ship_mode.ion index 08ae3fbcb1..d80c3909df 100644 --- a/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/ship_mode.ion +++ b/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/ship_mode.ion @@ -5,45 +5,27 @@ ship_mode::{ fields: [ { name: "sm_ship_mode_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "sm_ship_mode_id", - type: [ - "string", - "null" - ] + type: "string" }, { name: "sm_type", - type: [ - "string", - "null" - ] + type: "string" }, { name: "sm_code", - type: [ - "string", - "null" - ] + type: "string" }, { name: "sm_carrier", - type: [ - "string", - "null" - ] + type: "string" }, { name: "sm_contract", - type: [ - "string", - "null" - ] + type: "string" } ] } diff --git a/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/store.ion b/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/store.ion index b0a3566a7d..65cf1aa5f6 100644 --- a/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/store.ion +++ b/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/store.ion @@ -13,192 +13,111 @@ store::{ }, { name: "s_rec_start_date", - type: [ - "date", - "null" - ] + type: "date" }, { name: "s_rec_end_date", - type: [ - "date", - "null" - ] + type: "date" }, { name: "s_closed_date_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "s_store_name", - type: [ - "string", - "null" - ] + type: "string" }, { name: "s_number_employees", - type: [ - "int32", - "null" - ] + type: "int32" }, { name: "s_floor_space", - type: [ - "int32", - "null" - ] + type: "int32" }, { name: "s_hours", - type: [ - "string", - "null" - ] + type: "string" }, { name: "s_manager", - type: [ - "string", - "null" - ] + type: "string" }, { name: "s_market_id", - type: [ - "int32", - "null" - ] + type: "int32" }, { name: "s_geography_class", - type: [ - "string", - "null" - ] + type: "string" }, { name: "s_market_desc", - type: [ - "string", - "null" - ] + type: "string" }, { name: "s_market_manager", - type: [ - "string", - "null" - ] + type: "string" }, { name: "s_division_id", - type: [ - "int32", - "null" - ] + type: "int32" }, { name: "s_division_name", - type: [ - "string", - "null" - ] + type: "string" }, { name: "s_company_id", - type: [ - "int32", - "null" - ] + type: "int32" }, { name: "s_company_name", - type: [ - "string", - "null" - ] + type: "string" }, { name: "s_street_number", - type: [ - "string", - "null" - ] + type: "string" }, { name: "s_street_name", - type: [ - "string", - "null" - ] + type: "string" }, { name: "s_street_type", - type: [ - "string", - "null" - ] + type: "string" }, { name: "s_suite_number", - type: [ - "string", - "null" - ] + type: "string" }, { name: "s_city", - type: [ - "string", - "null" - ] + type: "string" }, { name: "s_county", - type: [ - "string", - "null" - ] + type: "string" }, { name: "s_state", - type: [ - "string", - "null" - ] + type: "string" }, { name: "s_zip", - type: [ - "string", - "null" - ] + type: "string" }, { name: "s_country", - type: [ - "string", - "null" - ] + type: "string" }, { name: "s_gmt_offset", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "s_tax_precentage", - type: [ - "float64", - "null" - ] + type: "float64" } ] } diff --git a/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/store_returns.ion b/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/store_returns.ion index 55347e7e46..859746a5d8 100644 --- a/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/store_returns.ion +++ b/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/store_returns.ion @@ -5,17 +5,11 @@ store_returns::{ fields: [ { name: "sr_returned_date_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "sr_return_time_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "sr_item_sk", @@ -23,45 +17,27 @@ store_returns::{ }, { name: "sr_customer_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "sr_cdemo_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "sr_hdemo_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "sr_addr_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "sr_store_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "sr_reason_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "sr_ticket_number", @@ -69,73 +45,43 @@ store_returns::{ }, { name: "sr_return_quantity", - type: [ - "int32", - "null" - ] + type: "int32" }, { name: "sr_return_amt", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "sr_return_tax", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "sr_return_amt_inc_tax", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "sr_fee", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "sr_return_ship_cost", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "sr_refunded_cash", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "sr_reversed_charge", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "sr_store_credit", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "sr_net_loss", - type: [ - "float64", - "null" - ] + type: "float64" } ] } diff --git a/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/store_sales.ion b/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/store_sales.ion index 64676ed271..af84c06375 100644 --- a/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/store_sales.ion +++ b/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/store_sales.ion @@ -5,17 +5,11 @@ store_sales::{ fields: [ { name: "ss_sold_date_sk", - type: [ - "date", - "null" - ] + type: "date" }, { name: "ss_sold_time_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "ss_item_sk", @@ -23,45 +17,27 @@ store_sales::{ }, { name: "ss_customer_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "ss_cdemo_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "ss_hdemo_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "ss_addr_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "ss_store_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "ss_promo_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "ss_ticket_number", @@ -69,94 +45,55 @@ store_sales::{ }, { name: "ss_quantity", - type: [ - "int32", - "null" - ] + type: "int32" }, { name: "ss_wholesale_cost", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "ss_list_price", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "ss_sales_price", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "ss_ext_discount_amt", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "ss_ext_sales_price", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "ss_ext_wholesale_cost", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "ss_ext_list_price", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "ss_ext_tax", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "ss_coupon_amt", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "ss_net_paid", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "ss_net_paid_inc_tax", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "ss_net_profit", - type: [ - "float64", - "null" - ] + type: "float64" } ] } diff --git a/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/time_dim.ion b/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/time_dim.ion index 55b5ce4f47..7444737c03 100644 --- a/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/time_dim.ion +++ b/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/time_dim.ion @@ -5,73 +5,43 @@ time_dim::{ fields: [ { name: "t_time_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "t_time_id", - type: [ - "string", - "null" - ] + type: "string" }, { name: "t_time", - type: [ - "int32", - "null" - ] + type: "int32" }, { name: "t_hour", - type: [ - "int32", - "null" - ] + type: "int32" }, { name: "t_minute", - type: [ - "int32", - "null" - ] + type: "int32" }, { name: "t_second", - type: [ - "int32", - "null" - ] + type: "int32" }, { name: "t_am_pm", - type: [ - "string", - "null" - ] + type: "string" }, { name: "t_shift", - type: [ - "string", - "null" - ] + type: "string" }, { name: "t_sub_shift", - type: [ - "string", - "null" - ] + type: "string" }, { name: "t_meal_time", - type: [ - "string", - "null" - ] + type: "string" } ] } diff --git a/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/warehouse.ion b/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/warehouse.ion index 170d486ce5..dac47af60d 100644 --- a/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/warehouse.ion +++ b/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/warehouse.ion @@ -5,101 +5,59 @@ warehouse::{ fields: [ { name: "w_warehouse_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "w_warehouse_id", - type: [ - "string", - "null" - ] + type: "string" }, { name: "w_warehouse_name", - type: [ - "string", - "null" - ] + type: "string" }, { name: "w_warehouse_sq_ft", - type: [ - "int32", - "null" - ] + type: "int32" }, { name: "w_street_number", - type: [ - "string", - "null" - ] + type: "string" }, { name: "w_street_name", - type: [ - "string", - "null" - ] + type: "string" }, { name: "w_street_type", - type: [ - "string", - "null" - ] + type: "string" }, { name: "w_suite_number", - type: [ - "string", - "null" - ] + type: "string" }, { name: "w_city", - type: [ - "string", - "null" - ] + type: "string" }, { name: "w_county", - type: [ - "string", - "null" - ] + type: "string" }, { name: "w_state", - type: [ - "string", - "null" - ] + type: "string" }, { name: "w_zip", - type: [ - "string", - "null" - ] + type: "string" }, { name: "w_country", - type: [ - "string", - "null" - ] + type: "string" }, { name: "w_gmt_offset", - type: [ - "float64", - "null" - ] + type: "float64" } ] } diff --git a/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/web_page.ion b/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/web_page.ion index 56b421dc5e..e60bf06f90 100644 --- a/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/web_page.ion +++ b/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/web_page.ion @@ -5,101 +5,59 @@ web_page::{ fields: [ { name: "wp_web_page_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "wp_web_page_id", - type: [ - "string", - "null" - ] + type: "string" }, { name: "wp_rec_start_date", - type: [ - "int64", - "null" - ] + type: "int64" }, { name: "wp_rec_end_date", - type: [ - "int64", - "null" - ] + type: "int64" }, { name: "wp_creation_date_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "wp_access_date_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "wp_autogen_flag", - type: [ - "string", - "null" - ] + type: "string" }, { name: "wp_customer_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "wp_url", - type: [ - "string", - "null" - ] + type: "string" }, { name: "wp_type", - type: [ - "string", - "null" - ] + type: "string" }, { name: "wp_char_count", - type: [ - "int32", - "null" - ] + type: "int32" }, { name: "wp_link_count", - type: [ - "int32", - "null" - ] + type: "int32" }, { name: "wp_image_count", - type: [ - "int32", - "null" - ] + type: "int32" }, { name: "wp_max_ad_count", - type: [ - "int32", - "null" - ] + type: "int32" } ] } diff --git a/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/web_returns.ion b/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/web_returns.ion index 336733c5ce..c1bfaf3b20 100644 --- a/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/web_returns.ion +++ b/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/web_returns.ion @@ -5,171 +5,99 @@ web_returns::{ fields: [ { name: "wr_returned_date_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "wr_returned_time_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "wr_item_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "wr_refunded_customer_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "wr_refunded_cdemo_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "wr_refunded_hdemo_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "wr_refunded_addr_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "wr_returning_customer_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "wr_returning_cdemo_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "wr_returning_hdemo_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "wr_returning_addr_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "wr_web_page_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "wr_reason_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "wr_order_number", - type: [ - "string", - "null" - ] + type: "string" }, { name: "wr_return_quantity", - type: [ - "int32", - "null" - ] + type: "int32" }, { name: "wr_return_amt", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "wr_return_tax", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "wr_return_amt_inc_tax", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "wr_fee", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "wr_return_ship_cost", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "wr_refunded_cash", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "wr_reversed_charge", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "wr_account_credit", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "wr_net_loss", - type: [ - "float64", - "null" - ] + type: "float64" } ] } diff --git a/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/web_sales.ion b/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/web_sales.ion index cb1f356148..3e50eee4e2 100644 --- a/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/web_sales.ion +++ b/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/web_sales.ion @@ -5,241 +5,139 @@ web_sales::{ fields: [ { name: "ws_sold_date_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "ws_sold_time_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "ws_ship_date_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "ws_item_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "ws_bill_customer_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "ws_bill_cdemo_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "ws_bill_hdemo_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "ws_bill_addr_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "ws_ship_customer_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "ws_ship_cdemo_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "ws_ship_hdemo_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "ws_ship_addr_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "ws_web_page_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "ws_web_site_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "ws_ship_mode_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "ws_warehouse_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "ws_promo_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "ws_order_number", - type: [ - "string", - "null" - ] + type: "string" }, { name: "ws_quantity", - type: [ - "int32", - "null" - ] + type: "int32" }, { name: "ws_wholesale_cost", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "ws_list_price", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "ws_sales_price", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "ws_ext_discount_amt", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "ws_ext_sales_price", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "ws_ext_wholesale_cost", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "ws_ext_list_price", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "ws_ext_tax", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "ws_coupon_amt", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "ws_ext_ship_cost", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "ws_net_paid", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "ws_net_paid_inc_tax", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "ws_net_paid_inc_ship", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "ws_net_paid_inc_ship_tax", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "ws_net_profit", - type: [ - "float64", - "null" - ] + type: "float64" } ] } diff --git a/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/web_site.ion b/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/web_site.ion index 372c16bac1..109750191c 100644 --- a/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/web_site.ion +++ b/partiql-planner/src/testFixtures/resources/catalogs/tpc_ds/web_site.ion @@ -5,185 +5,107 @@ web_site::{ fields: [ { name: "web_site_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "web_site_id", - type: [ - "string", - "null" - ] + type: "string" }, { name: "web_rec_start_date", - type: [ - "int64", - "null" - ] + type: "int64" }, { name: "web_rec_end_date", - type: [ - "int64", - "null" - ] + type: "int64" }, { name: "web_name", - type: [ - "string", - "null" - ] + type: "string" }, { name: "web_open_date_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "web_close_date_sk", - type: [ - "string", - "null" - ] + type: "string" }, { name: "web_class", - type: [ - "string", - "null" - ] + type: "string" }, { name: "web_manager", - type: [ - "string", - "null" - ] + type: "string" }, { name: "web_mkt_id", - type: [ - "int32", - "null" - ] + type: "int32" }, { name: "web_mkt_class", - type: [ - "string", - "null" - ] + type: "string" }, { name: "web_mkt_desc", - type: [ - "string", - "null" - ] + type: "string" }, { name: "web_market_manager", - type: [ - "string", - "null" - ] + type: "string" }, { name: "web_company_id", - type: [ - "int32", - "null" - ] + type: "int32" }, { name: "web_company_name", - type: [ - "string", - "null" - ] + type: "string" }, { name: "web_street_number", - type: [ - "string", - "null" - ] + type: "string" }, { name: "web_street_name", - type: [ - "string", - "null" - ] + type: "string" }, { name: "web_street_type", - type: [ - "string", - "null" - ] + type: "string" }, { name: "web_suite_number", - type: [ - "string", - "null" - ] + type: "string" }, { name: "web_city", - type: [ - "string", - "null" - ] + type: "string" }, { name: "web_county", - type: [ - "string", - "null" - ] + type: "string" }, { name: "web_state", - type: [ - "string", - "null" - ] + type: "string" }, { name: "web_zip", - type: [ - "string", - "null" - ] + type: "string" }, { name: "web_country", - type: [ - "string", - "null" - ] + type: "string" }, { name: "web_gmt_offset", - type: [ - "float64", - "null" - ] + type: "float64" }, { name: "web_tax_percentage", - type: [ - "float64", - "null" - ] + type: "float64" } ] } diff --git a/partiql-planner/src/testFixtures/resources/tests/aggregations.ion b/partiql-planner/src/testFixtures/resources/tests/aggregations.ion index 2badeb8dd6..b78c2a0d43 100644 --- a/partiql-planner/src/testFixtures/resources/tests/aggregations.ion +++ b/partiql-planner/src/testFixtures/resources/tests/aggregations.ion @@ -19,10 +19,7 @@ suite::{ fields: [ { name: "avg", - type: [ - "int32", - "null", - ], + type: "int32", }, ], }, @@ -56,10 +53,7 @@ suite::{ fields: [ { name: "min", - type: [ - "int32", - "null", - ], + type: "int32", }, ], }, @@ -76,10 +70,7 @@ suite::{ fields: [ { name: "max", - type: [ - "int32", - "null", - ], + type: "int32", }, ], }, @@ -96,10 +87,7 @@ suite::{ fields: [ { name: "sum", - type: [ - "int32", - "null", - ], + type: "int32", }, ], }, @@ -116,10 +104,7 @@ suite::{ fields: [ { name: "avg", - type: [ - "int32", - "null" - ], + type: "int32", }, ], }, @@ -153,10 +138,7 @@ suite::{ fields: [ { name: "min", - type: [ - "int32", - "null" - ], + type: "int32", }, ], }, @@ -173,10 +155,7 @@ suite::{ fields: [ { name: "max", - type: [ - "int32", - "null" - ], + type: "int32", }, ], }, @@ -193,10 +172,7 @@ suite::{ fields: [ { name: "sum", - type: [ - "int32", - "null" - ], + type: "int32", }, ], }, @@ -236,10 +212,7 @@ suite::{ fields: [ { name: "_1", - type: [ - "float32", - "null" - ], + type: "float32", }, { name: "y", @@ -265,10 +238,7 @@ suite::{ fields: [ { name: "_1", - type: [ - "float32", - "null" - ], + type: "float32", }, { name: "a", diff --git a/partiql-types/src/main/kotlin/org/partiql/types/StaticType.kt b/partiql-types/src/main/kotlin/org/partiql/types/StaticType.kt index 5eeba1b397..5c39019a3c 100644 --- a/partiql-types/src/main/kotlin/org/partiql/types/StaticType.kt +++ b/partiql-types/src/main/kotlin/org/partiql/types/StaticType.kt @@ -20,7 +20,7 @@ public sealed class StaticType { */ @JvmStatic public fun unionOf(vararg types: StaticType, metas: Map = mapOf()): StaticType = - unionOf(types.toSet(), metas) + unionOf(types.toSet(), metas).flatten() /** * Creates a new [StaticType] as a union of the passed [types]. The values typed by the returned type @@ -30,15 +30,65 @@ public sealed class StaticType { * @return [StaticType] representing the union of [types] */ @JvmStatic - public fun unionOf(types: Set, metas: Map = mapOf()): StaticType = AnyOfType(types, metas) + @Suppress("DEPRECATION") + public fun unionOf( + types: Set, + metas: Map = mapOf(), + errorOnEmptyTypes: Boolean = false + ): StaticType { + if (errorOnEmptyTypes && types.isEmpty()) { + throw IllegalStateException("Cannot make a union of zero types.") + } + return when (types.isEmpty()) { + true -> ANY + false -> AnyOfType(types, metas).flatten() + } + } + + /** + * Creates a new [StaticType] as a union of the passed [types]. The values typed by the returned type + * are defined as the union of all values typed as [types] + * + * @param types [StaticType] to be unioned. + * @return [StaticType] representing the union of [types] + */ + @JvmStatic + @Suppress("DEPRECATION") + public fun unionOf( + types: Collection, + metas: Map = mapOf(), + ): StaticType { + return when (types.isEmpty()) { + true -> ANY + false -> AnyOfType(types.toSet(), metas).flatten() + } + } // TODO consider making these into an enumeration... // Convenient enums to create a bare bones instance of StaticType + @Suppress("DEPRECATION") + @Deprecated( + message = "This will be removed in a future major-version bump.", + replaceWith = ReplaceWith("ANY") + ) @JvmField public val MISSING: MissingType = MissingType + + @Suppress("DEPRECATION") + @Deprecated( + message = "This will be removed in a future major-version bump.", + replaceWith = ReplaceWith("ANY") + ) @JvmField public val NULL: NullType = NullType() - @JvmField public val ANY: AnyType = AnyType() + + @Suppress("DEPRECATION") + @Deprecated( + message = "This will be removed in a future major-version bump.", + replaceWith = ReplaceWith("ANY") + ) @JvmField public val NULL_OR_MISSING: StaticType = unionOf(NULL, MISSING) + + @JvmField public val ANY: AnyType = AnyType() @JvmField public val BOOL: BoolType = BoolType() @JvmField public val INT2: IntType = IntType(IntType.IntRangeConstraint.SHORT) @JvmField public val INT4: IntType = IntType(IntType.IntRangeConstraint.INT4) @@ -68,7 +118,9 @@ public sealed class StaticType { @OptIn(PartiQLTimestampExperimental::class) @JvmStatic public val ALL_TYPES: List = listOf( + @Suppress("DEPRECATION") MISSING, + @Suppress("DEPRECATION") NULL, BOOL, INT2, @@ -97,8 +149,14 @@ public sealed class StaticType { * * If it already nullable, returns the original type. */ + @Suppress("DEPRECATION") + @Deprecated( + message = "This will be removed in a future major-version bump.", + replaceWith = ReplaceWith("") + ) public fun asNullable(): StaticType = when { + @Suppress("DEPRECATION") this.isNullable() -> this else -> unionOf(this, NULL).flatten() } @@ -108,6 +166,11 @@ public sealed class StaticType { * * If it already optional, returns the original type. */ + @Suppress("DEPRECATION") + @Deprecated( + message = "This will be removed in a future major-version bump.", + replaceWith = ReplaceWith("") + ) public fun asOptional(): StaticType = when { this.isOptional() -> this @@ -121,6 +184,7 @@ public sealed class StaticType { * MissingType is a singleton and there can only be one representation for it * i.e. you cannot have two instances of MissingType with different metas. */ + @Suppress("DEPRECATION") public fun withMetas(metas: Map): StaticType = when (this) { is AnyType -> copy(metas = metas) @@ -148,6 +212,11 @@ public sealed class StaticType { /** * Type is nullable if it is of Null type or is an AnyOfType that contains a Null type */ + @Suppress("DEPRECATION") + @Deprecated( + message = "This will be removed in a future major-version bump.", + replaceWith = ReplaceWith("true") + ) public fun isNullable(): Boolean = when (this) { is AnyOfType -> types.any { it.isNullable() } @@ -160,6 +229,11 @@ public sealed class StaticType { * * @return */ + @Suppress("DEPRECATION") + @Deprecated( + message = "This will be removed in a future major-version bump.", + replaceWith = ReplaceWith("true") + ) public fun isMissable(): Boolean = when (this) { is AnyOfType -> types.any { it.isMissable() } @@ -170,6 +244,11 @@ public sealed class StaticType { /** * Type is optional if it is Any, or Missing, or an AnyOfType that contains Any or Missing type */ + @Suppress("DEPRECATION") + @Deprecated( + message = "This will be removed in a future major-version bump.", + replaceWith = ReplaceWith("true") + ) private fun isOptional(): Boolean = when (this) { is AnyType, MissingType -> true // Any includes Missing type @@ -198,7 +277,7 @@ public data class AnyType(override val metas: Map = mapOf()) : Stat * Converts this into an [AnyOfType] representation. This method is helpful in inference when * it wants to iterate over all possible types of an expression. */ - public fun toAnyOfType(): AnyOfType = AnyOfType(ALL_TYPES.toSet()) + public fun toAnyOfType(): AnyOfType = unionOf(ALL_TYPES.toSet()) as AnyOfType override fun flatten(): StaticType = this @@ -250,6 +329,10 @@ public class UnsupportedTypeConstraint(message: String) : Exception(message) * * This is not a singleton since there may be more that one representation of a Null type (each with different metas) */ +@Deprecated( + message = "This will be removed in a future major-version bump.", + replaceWith = ReplaceWith("AnyType") +) public data class NullType(override val metas: Map = mapOf()) : SingleType() { override val allTypes: List get() = listOf(this) @@ -263,6 +346,10 @@ public data class NullType(override val metas: Map = mapOf()) : Sin * This is a singleton unlike the rest of the types as there cannot be * more that one representations of a missing type. */ +@Deprecated( + message = "This will be removed in a future major-version bump.", + replaceWith = ReplaceWith("AnyType") +) public object MissingType : SingleType() { override val metas: Map = mapOf() @@ -621,7 +708,14 @@ public data class GraphType( /** * Represents a [StaticType] that's defined by the union of multiple [StaticType]s. */ -public data class AnyOfType(val types: Set, override val metas: Map = mapOf()) : StaticType() { +public data class AnyOfType @Deprecated( + message = "This will be removed in a future major-version bump.", + replaceWith = ReplaceWith("StaticType.unionOf(types)") +) public constructor( + val types: Set, + override val metas: Map = mapOf() +) : StaticType() { + /** * Flattens a union type by traversing the types and recursively bubbling up the underlying union types. * @@ -704,7 +798,9 @@ public sealed class CollectionConstraint { public data class PartitionKey(val keys: Set) : TupleCollectionConstraint, CollectionConstraint() } +@Suppress("DEPRECATION") internal fun StaticType.isNullOrMissing(): Boolean = (this is NullType || this is MissingType) internal fun StaticType.isNumeric(): Boolean = (this is IntType || this is FloatType || this is DecimalType) internal fun StaticType.isText(): Boolean = (this is SymbolType || this is StringType) +@Suppress("DEPRECATION") internal fun StaticType.isUnknown(): Boolean = (this.isNullOrMissing() || this == StaticType.NULL_OR_MISSING) diff --git a/partiql-types/src/main/kotlin/org/partiql/value/PartiQLValueType.kt b/partiql-types/src/main/kotlin/org/partiql/value/PartiQLValueType.kt index 118e1e380b..8cc1393447 100644 --- a/partiql-types/src/main/kotlin/org/partiql/value/PartiQLValueType.kt +++ b/partiql-types/src/main/kotlin/org/partiql/value/PartiQLValueType.kt @@ -45,6 +45,16 @@ public enum class PartiQLValueType { LIST, SEXP, STRUCT, + + @Deprecated( + message = "This will be removed in a future major-version bump.", + replaceWith = ReplaceWith("ANY") + ) NULL, + + @Deprecated( + message = "This will be removed in a future major-version bump.", + replaceWith = ReplaceWith("ANY") + ) MISSING, } diff --git a/plugins/partiql-local/src/main/kotlin/org/partiql/plugins/local/LocalSchema.kt b/plugins/partiql-local/src/main/kotlin/org/partiql/plugins/local/LocalSchema.kt index 5e1cdde347..1603c0cc28 100644 --- a/plugins/partiql-local/src/main/kotlin/org/partiql/plugins/local/LocalSchema.kt +++ b/plugins/partiql-local/src/main/kotlin/org/partiql/plugins/local/LocalSchema.kt @@ -82,8 +82,6 @@ public fun StringElement.toStaticType(): StaticType = when (textValue) { "list" -> error("`list` is not an atomic type") "sexp" -> error("`sexp` is not an atomic type") "struct" -> error("`struct` is not an atomic type") - "null" -> StaticType.NULL - "missing" -> StaticType.MISSING else -> error("Invalid type `$textValue`") } @@ -168,13 +166,12 @@ public fun StaticType.toIon(): IonElement = when (this) { IntType.IntRangeConstraint.LONG -> ionString("int64") IntType.IntRangeConstraint.UNCONSTRAINED -> ionString("int") } - MissingType -> ionString("missing") - is NullType -> ionString("null") is StringType -> ionString("string") // TODO char is StructType -> this.toIon() is SymbolType -> ionString("symbol") is TimeType -> ionString("time") is TimestampType -> ionString("timestamp") + is MissingType, is NullType -> error("Cannot output absent type ($this) to Ion.") } private fun AnyOfType.toIon(): IonElement {