diff --git a/.gitignore b/.gitignore index e68379eed4..288d59c807 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,7 @@ build ~$* .gradle out/ - +partiql-parser/src/main/gen # Created by https://www.toptal.com/developers/gitignore/api/vim,git,java,emacs,kotlin,eclipse,intellij+all,macos # Edit at https://www.toptal.com/developers/gitignore?templates=vim,git,java,emacs,kotlin,eclipse,intellij+all,macos diff --git a/partiql-cli/src/main/kotlin/org/partiql/cli/pipeline/Pipeline.kt b/partiql-cli/src/main/kotlin/org/partiql/cli/pipeline/Pipeline.kt index 1cf4c2f6c5..5b098a0d71 100644 --- a/partiql-cli/src/main/kotlin/org/partiql/cli/pipeline/Pipeline.kt +++ b/partiql-cli/src/main/kotlin/org/partiql/cli/pipeline/Pipeline.kt @@ -7,7 +7,7 @@ import org.partiql.errors.ProblemSeverity import org.partiql.eval.PartiQLEngine import org.partiql.eval.PartiQLResult import org.partiql.parser.PartiQLParser -import org.partiql.plan.PartiQLPlan +import org.partiql.plan.v1.PartiQLPlan import org.partiql.planner.PartiQLPlanner import org.partiql.spi.connector.Connector import java.time.Instant @@ -41,11 +41,6 @@ internal class Pipeline private constructor( .catalog(currentCatalog) .catalogs(*catalogs.toTypedArray()) .build() - - fun engine() = PartiQLEngine.Session( - catalogs = connectors, - mode = mode - ) } /** @@ -69,12 +64,13 @@ internal class Pipeline private constructor( if (errors.isNotEmpty()) { throw RuntimeException(errors.joinToString()) } - return result.plan + TODO("Add V1 planner to the CLI") } private fun execute(plan: PartiQLPlan, session: Session): PartiQLResult { - val statement = engine.prepare(plan, session.engine()) - return engine.execute(statement) + // val statement = engine.prepare(plan, session.mode, session.planner()) + // return engine.execute(statement) + TODO("Add V1 planner to the CLI") } private class ProblemListener : ProblemCallback { @@ -91,14 +87,14 @@ internal class Pipeline private constructor( fun default(): Pipeline { val parser = PartiQLParser.default() val planner = PartiQLPlanner.standard() - val engine = PartiQLEngine.default() + val engine = PartiQLEngine.standard() return Pipeline(parser, planner, engine) } fun strict(): Pipeline { val parser = PartiQLParser.default() val planner = PartiQLPlanner.builder().signal().build() - val engine = PartiQLEngine.default() + val engine = PartiQLEngine.standard() return Pipeline(parser, planner, engine) } } diff --git a/partiql-eval/api/partiql-eval.api b/partiql-eval/api/partiql-eval.api index fa8ddf39c6..8ce2ec852f 100644 --- a/partiql-eval/api/partiql-eval.api +++ b/partiql-eval/api/partiql-eval.api @@ -1,14 +1,13 @@ public abstract interface class org/partiql/eval/PartiQLEngine { public static final field Companion Lorg/partiql/eval/PartiQLEngine$Companion; - public static fun builder ()Lorg/partiql/eval/PartiQLEngineBuilder; - public static fun default ()Lorg/partiql/eval/PartiQLEngine; - public abstract fun execute (Lorg/partiql/eval/PartiQLStatement;)Lorg/partiql/eval/PartiQLResult; - public abstract fun prepare (Lorg/partiql/plan/PartiQLPlan;Lorg/partiql/eval/PartiQLEngine$Session;)Lorg/partiql/eval/PartiQLStatement; + public static fun builder ()Lorg/partiql/eval/builder/PartiQLEngineBuilder; + public abstract fun prepare (Lorg/partiql/plan/v1/PartiQLPlan;Lorg/partiql/eval/PartiQLEngine$Mode;Lorg/partiql/planner/catalog/Session;)Lorg/partiql/eval/PartiQLStatement; + public static fun standard ()Lorg/partiql/eval/PartiQLEngine; } public final class org/partiql/eval/PartiQLEngine$Companion { - public final fun builder ()Lorg/partiql/eval/PartiQLEngineBuilder; - public final fun default ()Lorg/partiql/eval/PartiQLEngine; + public final fun builder ()Lorg/partiql/eval/builder/PartiQLEngineBuilder; + public final fun standard ()Lorg/partiql/eval/PartiQLEngine; } public final class org/partiql/eval/PartiQLEngine$Mode : java/lang/Enum { @@ -18,19 +17,6 @@ public final class org/partiql/eval/PartiQLEngine$Mode : java/lang/Enum { public static fun values ()[Lorg/partiql/eval/PartiQLEngine$Mode; } -public final class org/partiql/eval/PartiQLEngine$Session { - public fun ()V - public fun (Ljava/util/Map;Lorg/partiql/eval/PartiQLEngine$Mode;)V - public synthetic fun (Ljava/util/Map;Lorg/partiql/eval/PartiQLEngine$Mode;ILkotlin/jvm/internal/DefaultConstructorMarker;)V - public final fun getCatalogs ()Ljava/util/Map; - public final fun getMode ()Lorg/partiql/eval/PartiQLEngine$Mode; -} - -public final class org/partiql/eval/PartiQLEngineBuilder { - public fun ()V - public final fun build ()Lorg/partiql/eval/PartiQLEngine; -} - public abstract interface class org/partiql/eval/PartiQLResult { } @@ -57,9 +43,11 @@ public final class org/partiql/eval/PartiQLResult$Value : org/partiql/eval/Parti } public abstract interface class org/partiql/eval/PartiQLStatement { - public abstract fun execute ()Ljava/lang/Object; + public abstract fun execute (Lorg/partiql/planner/catalog/Session;)Lorg/partiql/eval/PartiQLResult; } -public abstract interface class org/partiql/eval/PartiQLStatement$Query : org/partiql/eval/PartiQLStatement { +public final class org/partiql/eval/builder/PartiQLEngineBuilder { + public fun ()V + public final fun build ()Lorg/partiql/eval/PartiQLEngine; } diff --git a/partiql-eval/build.gradle.kts b/partiql-eval/build.gradle.kts index 0c367cf320..67b9eda89f 100644 --- a/partiql-eval/build.gradle.kts +++ b/partiql-eval/build.gradle.kts @@ -38,7 +38,6 @@ dependencies { testImplementation(Deps.junitVintage) // Enables JUnit4 } -// Disabled for partiql-eval project at initialization. kotlin { explicitApi = null } diff --git a/partiql-eval/src/main/kotlin/org/partiql/eval/PartiQLEngine.kt b/partiql-eval/src/main/kotlin/org/partiql/eval/PartiQLEngine.kt index 20f5e81390..23fe4850df 100644 --- a/partiql-eval/src/main/kotlin/org/partiql/eval/PartiQLEngine.kt +++ b/partiql-eval/src/main/kotlin/org/partiql/eval/PartiQLEngine.kt @@ -1,7 +1,8 @@ package org.partiql.eval -import org.partiql.plan.PartiQLPlan -import org.partiql.spi.connector.Connector +import org.partiql.eval.builder.PartiQLEngineBuilder +import org.partiql.plan.v1.PartiQLPlan +import org.partiql.planner.catalog.Session /** * PartiQL's Experimental Engine. @@ -17,13 +18,13 @@ import org.partiql.spi.connector.Connector * This engine also internalizes the mechanics of the engine itself. Internally, it creates a physical plan to operate on, * and it executes directly on that plan. The limited number of APIs exposed in this library is intentional to allow for * under-the-hood experimentation by the PartiQL Community. + * + * + * TODO rename PartiQLEngine to PartiQLCompiler as it produces the statement (statement holds its own execution logic). */ public interface PartiQLEngine { - public fun prepare(plan: PartiQLPlan, session: Session): PartiQLStatement<*> - - // TODO: Pass session variable during statement execution once we finalize data structure for session. - public fun execute(statement: PartiQLStatement<*>): PartiQLResult + public fun prepare(plan: PartiQLPlan, mode: Mode, session: Session): PartiQLStatement companion object { @@ -31,14 +32,12 @@ public interface PartiQLEngine { public fun builder(): PartiQLEngineBuilder = PartiQLEngineBuilder() @JvmStatic - fun default() = PartiQLEngineBuilder().build() + fun standard() = PartiQLEngineBuilder().build() } - public class Session( - val catalogs: Map = mapOf(), - val mode: Mode = Mode.PERMISSIVE - ) - + /** + * TODO move mode to the session ?? + */ public enum class Mode { PERMISSIVE, STRICT // AKA, Type Checking Mode in the PartiQL Specification diff --git a/partiql-eval/src/main/kotlin/org/partiql/eval/PartiQLEngineBuilder.kt b/partiql-eval/src/main/kotlin/org/partiql/eval/PartiQLEngineBuilder.kt deleted file mode 100644 index 0a05f7e3d8..0000000000 --- a/partiql-eval/src/main/kotlin/org/partiql/eval/PartiQLEngineBuilder.kt +++ /dev/null @@ -1,11 +0,0 @@ -package org.partiql.eval - -class PartiQLEngineBuilder { - - /** - * Build the builder, return an implementation of a [PartiQLEngine] - * - * @return - */ - public fun build(): PartiQLEngine = PartiQLEngineDefault() -} diff --git a/partiql-eval/src/main/kotlin/org/partiql/eval/PartiQLEngineDefault.kt b/partiql-eval/src/main/kotlin/org/partiql/eval/PartiQLEngineDefault.kt deleted file mode 100644 index 57ed45f268..0000000000 --- a/partiql-eval/src/main/kotlin/org/partiql/eval/PartiQLEngineDefault.kt +++ /dev/null @@ -1,42 +0,0 @@ -package org.partiql.eval - -import org.partiql.eval.internal.Compiler -import org.partiql.eval.internal.Environment -import org.partiql.eval.internal.Symbols -import org.partiql.plan.PartiQLPlan -import org.partiql.value.PartiQLValue -import org.partiql.value.PartiQLValueExperimental - -internal class PartiQLEngineDefault : PartiQLEngine { - - @OptIn(PartiQLValueExperimental::class) - override fun prepare(plan: PartiQLPlan, session: PartiQLEngine.Session): PartiQLStatement<*> { - try { - // 1. Validate all references - val symbols = Symbols.build(plan, session) - // 2. Compile with built symbols - val compiler = Compiler(plan, session, symbols) - val expression = compiler.compile() - return object : PartiQLStatement.Query { - override fun execute(): PartiQLValue { - return expression.eval(Environment.empty).toPartiQLValue() - } - } - } catch (ex: Exception) { - // TODO wrap in some PartiQL Exception - throw ex - } - } - - @OptIn(PartiQLValueExperimental::class) - override fun execute(statement: PartiQLStatement<*>): PartiQLResult { - return when (statement) { - is PartiQLStatement.Query -> try { - val value = statement.execute() - PartiQLResult.Value(value) - } catch (ex: Exception) { - PartiQLResult.Error(ex) - } - } - } -} diff --git a/partiql-eval/src/main/kotlin/org/partiql/eval/PartiQLStatement.kt b/partiql-eval/src/main/kotlin/org/partiql/eval/PartiQLStatement.kt index f936b26fd9..7164504e64 100644 --- a/partiql-eval/src/main/kotlin/org/partiql/eval/PartiQLStatement.kt +++ b/partiql-eval/src/main/kotlin/org/partiql/eval/PartiQLStatement.kt @@ -1,15 +1,11 @@ package org.partiql.eval -import org.partiql.value.PartiQLValue -import org.partiql.value.PartiQLValueExperimental +import org.partiql.planner.catalog.Session /** - * Represents a compiled PartiQL Plan ready for execution. + * Represents a compiled PartiQL statement ready for execution. */ -sealed interface PartiQLStatement { +public interface PartiQLStatement { - public fun execute(): T - - @OptIn(PartiQLValueExperimental::class) - interface Query : PartiQLStatement + public fun execute(session: Session): PartiQLResult } diff --git a/partiql-eval/src/main/kotlin/org/partiql/eval/builder/PartiQLEngineBuilder.kt b/partiql-eval/src/main/kotlin/org/partiql/eval/builder/PartiQLEngineBuilder.kt new file mode 100644 index 0000000000..b625ceef33 --- /dev/null +++ b/partiql-eval/src/main/kotlin/org/partiql/eval/builder/PartiQLEngineBuilder.kt @@ -0,0 +1,14 @@ +package org.partiql.eval.builder + +import org.partiql.eval.PartiQLEngine +import org.partiql.eval.internal.SqlEngine + +class PartiQLEngineBuilder { + + /** + * Build the builder, return an implementation of a [PartiQLEngine] + * + * @return + */ + public fun build(): PartiQLEngine = SqlEngine() +} diff --git a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/Compiler.kt b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/Compiler.kt deleted file mode 100644 index f2bdd3ff2c..0000000000 --- a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/Compiler.kt +++ /dev/null @@ -1,428 +0,0 @@ -package org.partiql.eval.internal - -import org.partiql.eval.PartiQLEngine -import org.partiql.eval.internal.operator.Operator -import org.partiql.eval.internal.operator.rel.RelAggregate -import org.partiql.eval.internal.operator.rel.RelDistinct -import org.partiql.eval.internal.operator.rel.RelExceptAll -import org.partiql.eval.internal.operator.rel.RelExceptDistinct -import org.partiql.eval.internal.operator.rel.RelExclude -import org.partiql.eval.internal.operator.rel.RelFilter -import org.partiql.eval.internal.operator.rel.RelIntersectAll -import org.partiql.eval.internal.operator.rel.RelIntersectDistinct -import org.partiql.eval.internal.operator.rel.RelJoinInner -import org.partiql.eval.internal.operator.rel.RelJoinOuterFull -import org.partiql.eval.internal.operator.rel.RelJoinOuterLeft -import org.partiql.eval.internal.operator.rel.RelJoinOuterRight -import org.partiql.eval.internal.operator.rel.RelLimit -import org.partiql.eval.internal.operator.rel.RelOffset -import org.partiql.eval.internal.operator.rel.RelProject -import org.partiql.eval.internal.operator.rel.RelScan -import org.partiql.eval.internal.operator.rel.RelScanIndexed -import org.partiql.eval.internal.operator.rel.RelScanIndexedPermissive -import org.partiql.eval.internal.operator.rel.RelScanPermissive -import org.partiql.eval.internal.operator.rel.RelSort -import org.partiql.eval.internal.operator.rel.RelUnionAll -import org.partiql.eval.internal.operator.rel.RelUnionDistinct -import org.partiql.eval.internal.operator.rel.RelUnpivot -import org.partiql.eval.internal.operator.rex.ExprCallDynamic -import org.partiql.eval.internal.operator.rex.ExprCallStatic -import org.partiql.eval.internal.operator.rex.ExprCase -import org.partiql.eval.internal.operator.rex.ExprCast -import org.partiql.eval.internal.operator.rex.ExprCoalesce -import org.partiql.eval.internal.operator.rex.ExprCollection -import org.partiql.eval.internal.operator.rex.ExprLiteral -import org.partiql.eval.internal.operator.rex.ExprMissing -import org.partiql.eval.internal.operator.rex.ExprNullIf -import org.partiql.eval.internal.operator.rex.ExprPathIndex -import org.partiql.eval.internal.operator.rex.ExprPathKey -import org.partiql.eval.internal.operator.rex.ExprPathSymbol -import org.partiql.eval.internal.operator.rex.ExprPermissive -import org.partiql.eval.internal.operator.rex.ExprPivot -import org.partiql.eval.internal.operator.rex.ExprPivotPermissive -import org.partiql.eval.internal.operator.rex.ExprSelect -import org.partiql.eval.internal.operator.rex.ExprStructField -import org.partiql.eval.internal.operator.rex.ExprStructPermissive -import org.partiql.eval.internal.operator.rex.ExprStructStrict -import org.partiql.eval.internal.operator.rex.ExprSubquery -import org.partiql.eval.internal.operator.rex.ExprTable -import org.partiql.eval.internal.operator.rex.ExprTupleUnion -import org.partiql.eval.internal.operator.rex.ExprVarLocal -import org.partiql.eval.internal.operator.rex.ExprVarOuter -import org.partiql.eval.value.Datum -import org.partiql.plan.Catalog -import org.partiql.plan.PartiQLPlan -import org.partiql.plan.PlanNode -import org.partiql.plan.Ref -import org.partiql.plan.Rel -import org.partiql.plan.Rex -import org.partiql.plan.SetQuantifier -import org.partiql.plan.Statement -import org.partiql.plan.debug.PlanPrinter -import org.partiql.plan.visitor.PlanBaseVisitor -import org.partiql.spi.fn.Agg -import org.partiql.types.PType -import org.partiql.value.PartiQLValueExperimental - -internal class Compiler( - private val plan: PartiQLPlan, - private val session: PartiQLEngine.Session, - private val symbols: Symbols, -) : PlanBaseVisitor() { - - fun compile(): Operator.Expr { - return visitPartiQLPlan(plan, null) - } - - override fun defaultReturn(node: PlanNode, ctx: PType?): Operator { - TODO("Not yet implemented") - } - - override fun visitRexOpErr(node: Rex.Op.Err, ctx: PType?): Operator { - val message = buildString { - this.appendLine(node.message) - PlanPrinter.append(this, plan) - } - throw IllegalStateException(message) - } - - override fun visitRelOpErr(node: Rel.Op.Err, ctx: PType?): Operator { - throw IllegalStateException(node.message) - } - - override fun visitPartiQLPlan(node: PartiQLPlan, ctx: PType?): Operator.Expr { - return visitStatement(node.statement, ctx) as Operator.Expr - } - - override fun visitStatementQuery(node: Statement.Query, ctx: PType?): Operator.Expr { - return visitRex(node.root, ctx).modeHandled() - } - - // REX - - override fun visitRex(node: Rex, ctx: PType?): Operator.Expr { - return super.visitRexOp(node.op, node.type) as Operator.Expr - } - - override fun visitRexOpCollection(node: Rex.Op.Collection, ctx: PType?): Operator { - val values = node.values.map { visitRex(it, ctx).modeHandled() } - val type = ctx ?: error("No type provided in ctx") - return ExprCollection(values, type) - } - - override fun visitRexOpStruct(node: Rex.Op.Struct, ctx: PType?): Operator { - val fields = node.fields.map { - val value = visitRex(it.v, ctx).modeHandled() - ExprStructField(visitRex(it.k, ctx), value) - } - return when (session.mode) { - PartiQLEngine.Mode.STRICT -> ExprStructStrict(fields) - PartiQLEngine.Mode.PERMISSIVE -> ExprStructPermissive(fields) - } - } - - override fun visitRexOpSelect(node: Rex.Op.Select, ctx: PType?): Operator { - val rel = visitRel(node.rel, ctx) - val ordered = node.rel.type.props.contains(Rel.Prop.ORDERED) - val constructor = visitRex(node.constructor, ctx).modeHandled() - return ExprSelect(rel, constructor, ordered) - } - - override fun visitRexOpSubquery(node: Rex.Op.Subquery, ctx: PType?): Operator { - val constructor = visitRex(node.constructor, ctx) - val input = visitRel(node.rel, ctx) - return when (node.coercion) { - Rex.Op.Subquery.Coercion.SCALAR -> ExprSubquery.Scalar(constructor, input) - Rex.Op.Subquery.Coercion.ROW -> ExprSubquery.Row(constructor, input) - } - } - - override fun visitRexOpPivot(node: Rex.Op.Pivot, ctx: PType?): Operator { - val rel = visitRel(node.rel, ctx) - val key = visitRex(node.key, ctx) - val value = visitRex(node.value, ctx) - return when (session.mode) { - PartiQLEngine.Mode.PERMISSIVE -> ExprPivotPermissive(rel, key, value) - PartiQLEngine.Mode.STRICT -> ExprPivot(rel, key, value) - } - } - - override fun visitRexOpCoalesce(node: Rex.Op.Coalesce, ctx: PType?): Operator { - val args = Array(node.args.size) { visitRex(node.args[it], node.args[it].type) } - return ExprCoalesce(args) - } - - override fun visitRexOpNullif(node: Rex.Op.Nullif, ctx: PType?): Operator { - val value = visitRex(node.value, node.value.type) - val nullifier = visitRex(node.nullifier, node.value.type) - return ExprNullIf(value, nullifier) - } - - /** - * All variables from the local scope have a depth of 0. - * - * All variables coming from the stack have a depth > 0. To slightly minimize computation at execution, we subtract - * the depth by 1 to account for the fact that the local scope is not kept on the stack. - */ - override fun visitRexOpVar(node: Rex.Op.Var, ctx: PType?): Operator { - return when (node.depth) { - 0 -> ExprVarLocal(node.ref) - else -> { - ExprVarOuter(node.depth, node.ref) - } - } - } - - override fun visitRexOpGlobal(node: Rex.Op.Global, ctx: PType?): Operator { - val table = symbols.getGlobal(node.ref) - return ExprTable(table) - } - - override fun visitRelOpAggregate(node: Rel.Op.Aggregate, ctx: PType?): Operator.Relation { - val input = visitRel(node.input, ctx) - val calls = node.calls.map { - visitRelOpAggregateCall(it, ctx) - } - val groups = node.groups.map { visitRex(it, ctx).modeHandled() } - return RelAggregate(input, groups, calls) - } - - override fun visitRelOpAggregateCall(node: Rel.Op.Aggregate.Call, ctx: PType?): Operator.Aggregation { - val args = node.args.map { visitRex(it, it.type).modeHandled() } - val setQuantifier: Operator.Aggregation.SetQuantifier = when (node.setq) { - SetQuantifier.ALL -> Operator.Aggregation.SetQuantifier.ALL - SetQuantifier.DISTINCT -> Operator.Aggregation.SetQuantifier.DISTINCT - } - val agg = symbols.getAgg(node.agg) - return object : Operator.Aggregation { - override val delegate: Agg = agg - override val args: List = args - override val setQuantifier: Operator.Aggregation.SetQuantifier = setQuantifier - } - } - - override fun visitRexOpPathKey(node: Rex.Op.Path.Key, ctx: PType?): Operator { - val root = visitRex(node.root, ctx) - val key = visitRex(node.key, ctx) - return ExprPathKey(root, key) - } - - override fun visitRexOpPathSymbol(node: Rex.Op.Path.Symbol, ctx: PType?): Operator { - val root = visitRex(node.root, ctx) - val symbol = node.key - return ExprPathSymbol(root, symbol) - } - - override fun visitRexOpPathIndex(node: Rex.Op.Path.Index, ctx: PType?): Operator { - val root = visitRex(node.root, ctx) - val index = visitRex(node.key, ctx) - return ExprPathIndex(root, index) - } - - override fun visitRexOpCallStatic(node: Rex.Op.Call.Static, ctx: PType?): Operator { - val fn = symbols.getFn(node.fn) - val args = node.args.map { visitRex(it, ctx) }.toTypedArray() - val fnTakesInMissing = fn.signature.parameters.any { - it.type.kind == PType.Kind.DYNAMIC // TODO: Is this needed? - } - return when (fnTakesInMissing) { - true -> ExprCallStatic(fn, args.map { it.modeHandled() }.toTypedArray()) - false -> ExprCallStatic(fn, args) - } - } - - override fun visitRexOpCallDynamic(node: Rex.Op.Call.Dynamic, ctx: PType?): Operator { - val args = node.args.map { visitRex(it, ctx).modeHandled() }.toTypedArray() - // Check candidate list size - when (node.candidates.size) { - 0 -> error("Rex.Op.Call.Dynamic had an empty candidates list: $node.") - // TODO this seems like it should be an error, but is possible if the fn match was non-exhaustive - // 1 -> error("Rex.Op.Call.Dynamic had a single candidate; should be Rex.Op.Call.Static") - } - // Check candidate name and arity for uniformity - var arity: Int = -1 - var name: String = "unknown" - // Compile the candidates - val candidates = Array(node.candidates.size) { - val candidate = node.candidates[it] - val fn = symbols.getFn(candidate.fn) - // Check this candidate - val fnArity = fn.signature.parameters.size - val fnName = fn.signature.name.uppercase() - if (arity == -1) { - arity = fnArity - name = fnName - } else { - if (fnArity != arity) { - error("Dynamic call candidate had different arity than others; found $fnArity but expected $arity") - } - if (fnName != name) { - error("Dynamic call candidate had different name than others; found $fnName but expected $name") - } - } - fn - } - return ExprCallDynamic(name, candidates, args) - } - - override fun visitRexOpCast(node: Rex.Op.Cast, ctx: PType?): Operator { - return ExprCast(visitRex(node.arg, ctx), node.cast.target) - } - - override fun visitRexOpMissing(node: Rex.Op.Missing, ctx: PType?): Operator { - return ExprMissing(ctx ?: PType.unknown()) // TODO: Pass a type - } - - // REL - override fun visitRel(node: Rel, ctx: PType?): Operator.Relation { - return super.visitRelOp(node.op, ctx) as Operator.Relation - } - - override fun visitRelOpScan(node: Rel.Op.Scan, ctx: PType?): Operator { - val rex = visitRex(node.rex, ctx) - return when (session.mode) { - PartiQLEngine.Mode.PERMISSIVE -> RelScanPermissive(rex) - PartiQLEngine.Mode.STRICT -> RelScan(rex) - } - } - - override fun visitRelOpProject(node: Rel.Op.Project, ctx: PType?): Operator { - val input = visitRel(node.input, ctx) - val projections = node.projections.map { visitRex(it, ctx).modeHandled() } - return RelProject(input, projections) - } - - override fun visitRelOpScanIndexed(node: Rel.Op.ScanIndexed, ctx: PType?): Operator { - val rex = visitRex(node.rex, ctx) - return when (session.mode) { - PartiQLEngine.Mode.PERMISSIVE -> RelScanIndexedPermissive(rex) - PartiQLEngine.Mode.STRICT -> RelScanIndexed(rex) - } - } - - override fun visitRelOpUnpivot(node: Rel.Op.Unpivot, ctx: PType?): Operator { - val expr = visitRex(node.rex, ctx) - return when (session.mode) { - PartiQLEngine.Mode.PERMISSIVE -> RelUnpivot.Permissive(expr) - PartiQLEngine.Mode.STRICT -> RelUnpivot.Strict(expr) - } - } - - override fun visitRelOpExcept(node: Rel.Op.Except, ctx: PType?): Operator { - val lhs = visitRel(node.lhs, ctx) - val rhs = visitRel(node.rhs, ctx) - return when (node.setq) { - SetQuantifier.ALL -> RelExceptAll(lhs, rhs) - SetQuantifier.DISTINCT -> RelExceptDistinct(lhs, rhs) - } - } - - override fun visitRelOpIntersect(node: Rel.Op.Intersect, ctx: PType?): Operator { - val lhs = visitRel(node.lhs, ctx) - val rhs = visitRel(node.rhs, ctx) - return when (node.setq) { - SetQuantifier.ALL -> RelIntersectAll(lhs, rhs) - SetQuantifier.DISTINCT -> RelIntersectDistinct(lhs, rhs) - } - } - - override fun visitRelOpUnion(node: Rel.Op.Union, ctx: PType?): Operator { - val lhs = visitRel(node.lhs, ctx) - val rhs = visitRel(node.rhs, ctx) - return when (node.setq) { - SetQuantifier.ALL -> RelUnionAll(lhs, rhs) - SetQuantifier.DISTINCT -> RelUnionDistinct(lhs, rhs) - } - } - - override fun visitRelOpLimit(node: Rel.Op.Limit, ctx: PType?): Operator { - val input = visitRel(node.input, ctx) - val limit = visitRex(node.limit, ctx) - return RelLimit(input, limit) - } - - override fun visitRelOpOffset(node: Rel.Op.Offset, ctx: PType?): Operator { - val input = visitRel(node.input, ctx) - val offset = visitRex(node.offset, ctx) - return RelOffset(input, offset) - } - - override fun visitRexOpTupleUnion(node: Rex.Op.TupleUnion, ctx: PType?): Operator { - val args = node.args.map { visitRex(it, ctx) }.toTypedArray() - return ExprTupleUnion(args) - } - - override fun visitRelOpJoin(node: Rel.Op.Join, ctx: PType?): Operator { - val lhs = visitRel(node.lhs, ctx) - val rhs = visitRel(node.rhs, ctx) - val condition = visitRex(node.rex, ctx) - return when (node.type) { - Rel.Op.Join.Type.INNER -> RelJoinInner(lhs, rhs, condition) - Rel.Op.Join.Type.LEFT -> RelJoinOuterLeft(lhs, rhs, condition, rhsType = node.rhs.type) - Rel.Op.Join.Type.RIGHT -> RelJoinOuterRight(lhs, rhs, condition, lhsType = node.lhs.type) - Rel.Op.Join.Type.FULL -> RelJoinOuterFull(lhs, rhs, condition, lhsType = node.lhs.type, rhsType = node.rhs.type) - } - } - - override fun visitRexOpCase(node: Rex.Op.Case, ctx: PType?): Operator { - val branches = node.branches.map { branch -> - visitRex(branch.condition, ctx).modeHandled() to visitRex(branch.rex, ctx) - } - val default = visitRex(node.default, ctx) - return ExprCase(branches, default) - } - - @OptIn(PartiQLValueExperimental::class) - override fun visitRexOpLit(node: Rex.Op.Lit, ctx: PType?): Operator { - return ExprLiteral(Datum.of(node.value)) - } - - override fun visitRelOpDistinct(node: Rel.Op.Distinct, ctx: PType?): Operator { - val input = visitRel(node.input, ctx) - return RelDistinct(input) - } - - override fun visitRelOpFilter(node: Rel.Op.Filter, ctx: PType?): Operator { - val input = visitRel(node.input, ctx) - val condition = visitRex(node.predicate, ctx).modeHandled() - return RelFilter(input, condition) - } - - override fun visitRelOpExclude(node: Rel.Op.Exclude, ctx: PType?): Operator { - val input = visitRel(node.input, ctx) - return RelExclude(input, node.paths) - } - - override fun visitRelOpSort(node: Rel.Op.Sort, ctx: PType?): Operator { - val input = visitRel(node.input, ctx) - val compiledSpecs = node.specs.map { spec -> - val expr = visitRex(spec.rex, ctx) - val order = spec.order - expr to order - } - return RelSort(input, compiledSpecs) - } - - // HELPERS - - private fun Operator.Expr.modeHandled(): Operator.Expr { - return when (session.mode) { - PartiQLEngine.Mode.PERMISSIVE -> ExprPermissive(this) - PartiQLEngine.Mode.STRICT -> this - } - } - - /** - * Get a typed catalog item from a reference - * - * @param T - * @return - */ - private inline fun Ref.get(): T { - val item = plan.catalogs.getOrNull(catalog)?.items?.get(symbol) - if (item == null || item !is T) { - error("Invalid catalog reference, $this for type ${T::class}") - } - return item - } -} diff --git a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/SqlCompiler.kt b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/SqlCompiler.kt new file mode 100644 index 0000000000..89b5424177 --- /dev/null +++ b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/SqlCompiler.kt @@ -0,0 +1,519 @@ +package org.partiql.eval.internal + +// OLD IMPORTS FOR EXCLUDE +import org.partiql.eval.PartiQLEngine +import org.partiql.eval.internal.operator.Operator +import org.partiql.eval.internal.operator.rel.RelOpAggregate +import org.partiql.eval.internal.operator.rel.RelOpDistinct +import org.partiql.eval.internal.operator.rel.RelOpExceptAll +import org.partiql.eval.internal.operator.rel.RelOpExceptDistinct +import org.partiql.eval.internal.operator.rel.RelOpExcludeOld +import org.partiql.eval.internal.operator.rel.RelOpFilter +import org.partiql.eval.internal.operator.rel.RelOpIntersectAll +import org.partiql.eval.internal.operator.rel.RelOpIntersectDistinct +import org.partiql.eval.internal.operator.rel.RelOpIterate +import org.partiql.eval.internal.operator.rel.RelOpIteratePermissive +import org.partiql.eval.internal.operator.rel.RelOpJoinInner +import org.partiql.eval.internal.operator.rel.RelOpJoinOuterFull +import org.partiql.eval.internal.operator.rel.RelOpJoinOuterLeft +import org.partiql.eval.internal.operator.rel.RelOpJoinOuterRight +import org.partiql.eval.internal.operator.rel.RelOpLimit +import org.partiql.eval.internal.operator.rel.RelOpOffset +import org.partiql.eval.internal.operator.rel.RelOpProject +import org.partiql.eval.internal.operator.rel.RelOpScan +import org.partiql.eval.internal.operator.rel.RelOpScanPermissive +import org.partiql.eval.internal.operator.rel.RelOpSort +import org.partiql.eval.internal.operator.rel.RelOpUnionAll +import org.partiql.eval.internal.operator.rel.RelOpUnionDistinct +import org.partiql.eval.internal.operator.rel.RelOpUnpivot +import org.partiql.eval.internal.operator.rex.ExprArray +import org.partiql.eval.internal.operator.rex.ExprBag +import org.partiql.eval.internal.operator.rex.ExprCallDynamic +import org.partiql.eval.internal.operator.rex.ExprCallStatic +import org.partiql.eval.internal.operator.rex.ExprCaseBranch +import org.partiql.eval.internal.operator.rex.ExprCaseSearched +import org.partiql.eval.internal.operator.rex.ExprCast +import org.partiql.eval.internal.operator.rex.ExprCoalesce +import org.partiql.eval.internal.operator.rex.ExprLit +import org.partiql.eval.internal.operator.rex.ExprMissing +import org.partiql.eval.internal.operator.rex.ExprNullIf +import org.partiql.eval.internal.operator.rex.ExprPathIndex +import org.partiql.eval.internal.operator.rex.ExprPathKey +import org.partiql.eval.internal.operator.rex.ExprPathSymbol +import org.partiql.eval.internal.operator.rex.ExprPermissive +import org.partiql.eval.internal.operator.rex.ExprPivot +import org.partiql.eval.internal.operator.rex.ExprPivotPermissive +import org.partiql.eval.internal.operator.rex.ExprSelect +import org.partiql.eval.internal.operator.rex.ExprSpread +import org.partiql.eval.internal.operator.rex.ExprStructField +import org.partiql.eval.internal.operator.rex.ExprStructPermissive +import org.partiql.eval.internal.operator.rex.ExprStructStrict +import org.partiql.eval.internal.operator.rex.ExprSubquery +import org.partiql.eval.internal.operator.rex.ExprSubqueryRow +import org.partiql.eval.internal.operator.rex.ExprTable +import org.partiql.eval.internal.operator.rex.ExprVar +import org.partiql.eval.value.Datum +import org.partiql.plan.relOpExcludePath +import org.partiql.plan.relOpExcludeStep +import org.partiql.plan.relOpExcludeTypeCollIndex +import org.partiql.plan.relOpExcludeTypeCollWildcard +import org.partiql.plan.relOpExcludeTypeStructKey +import org.partiql.plan.relOpExcludeTypeStructSymbol +import org.partiql.plan.relOpExcludeTypeStructWildcard +import org.partiql.plan.rexOpVar +import org.partiql.plan.v1.operator.rel.Rel +import org.partiql.plan.v1.operator.rel.RelAggregate +import org.partiql.plan.v1.operator.rel.RelCollation +import org.partiql.plan.v1.operator.rel.RelDistinct +import org.partiql.plan.v1.operator.rel.RelError +import org.partiql.plan.v1.operator.rel.RelExcept +import org.partiql.plan.v1.operator.rel.RelExclude +import org.partiql.plan.v1.operator.rel.RelExcludeCollectionWildcard +import org.partiql.plan.v1.operator.rel.RelExcludeIndex +import org.partiql.plan.v1.operator.rel.RelExcludeKey +import org.partiql.plan.v1.operator.rel.RelExcludePath +import org.partiql.plan.v1.operator.rel.RelExcludeStep +import org.partiql.plan.v1.operator.rel.RelExcludeStructWildcard +import org.partiql.plan.v1.operator.rel.RelExcludeSymbol +import org.partiql.plan.v1.operator.rel.RelFilter +import org.partiql.plan.v1.operator.rel.RelIntersect +import org.partiql.plan.v1.operator.rel.RelIterate +import org.partiql.plan.v1.operator.rel.RelJoin +import org.partiql.plan.v1.operator.rel.RelJoinType +import org.partiql.plan.v1.operator.rel.RelLimit +import org.partiql.plan.v1.operator.rel.RelOffset +import org.partiql.plan.v1.operator.rel.RelProject +import org.partiql.plan.v1.operator.rel.RelScan +import org.partiql.plan.v1.operator.rel.RelSort +import org.partiql.plan.v1.operator.rel.RelUnion +import org.partiql.plan.v1.operator.rel.RelUnpivot +import org.partiql.plan.v1.operator.rel.RelVisitor +import org.partiql.plan.v1.operator.rex.Rex +import org.partiql.plan.v1.operator.rex.RexArray +import org.partiql.plan.v1.operator.rex.RexBag +import org.partiql.plan.v1.operator.rex.RexCallDynamic +import org.partiql.plan.v1.operator.rex.RexCallStatic +import org.partiql.plan.v1.operator.rex.RexCase +import org.partiql.plan.v1.operator.rex.RexCast +import org.partiql.plan.v1.operator.rex.RexCoalesce +import org.partiql.plan.v1.operator.rex.RexError +import org.partiql.plan.v1.operator.rex.RexLit +import org.partiql.plan.v1.operator.rex.RexMissing +import org.partiql.plan.v1.operator.rex.RexNullIf +import org.partiql.plan.v1.operator.rex.RexPathIndex +import org.partiql.plan.v1.operator.rex.RexPathKey +import org.partiql.plan.v1.operator.rex.RexPathSymbol +import org.partiql.plan.v1.operator.rex.RexPivot +import org.partiql.plan.v1.operator.rex.RexSelect +import org.partiql.plan.v1.operator.rex.RexSpread +import org.partiql.plan.v1.operator.rex.RexStruct +import org.partiql.plan.v1.operator.rex.RexSubquery +import org.partiql.plan.v1.operator.rex.RexSubqueryComp +import org.partiql.plan.v1.operator.rex.RexSubqueryIn +import org.partiql.plan.v1.operator.rex.RexSubqueryTest +import org.partiql.plan.v1.operator.rex.RexTable +import org.partiql.plan.v1.operator.rex.RexVar +import org.partiql.plan.v1.operator.rex.RexVisitor +import org.partiql.planner.catalog.Session +import org.partiql.spi.fn.Agg +import org.partiql.types.PType +import org.partiql.plan.Rel as IRel + +/** + * See https://github.com/partiql/partiql-lang-kotlin/blob/v1/partiql-eval/src/main/kotlin/org/partiql/eval/internal/Compiler.kt + */ +internal class SqlCompiler( + @JvmField var mode: PartiQLEngine.Mode, + @JvmField var session: Session, +) { + + private val relCompiler = RelCompiler() + + private val rexCompiler = RexCompiler() + + fun compile(rex: Rex): Operator.Expr = compile(rex, Unit).catch() + + private fun compile(rel: Rel, ctx: Unit): Operator.Relation = rel.accept(relCompiler, ctx) + + private fun compile(rex: Rex, ctx: Unit): Operator.Expr = rex.accept(rexCompiler, ctx) + + /** + * Transforms plan relation operators into the internal physical operators. + */ + private inner class RelCompiler : RelVisitor { + + override fun defaultReturn(rel: Rel, ctx: Unit): Operator.Relation { + TODO("Evaluation is not implemented for rel: ${rel::class.simpleName}") + } + + override fun visitError(rel: RelError, ctx: Unit): Operator.Relation { + throw IllegalStateException(rel.message) + } + + // OPERATORS + + override fun visitAggregate(rel: RelAggregate, ctx: Unit): Operator.Relation { + val input = compile(rel.getInput(), ctx) + val keys = rel.getGroups().map { compile(it, ctx).catch() } + val aggs = rel.getCalls().map { call -> + val agg = call.getAgg() + val args = call.getArgs().map { compile(it, ctx).catch() } + val setq = when (call.isDistinct()) { + true -> Operator.Aggregation.SetQuantifier.DISTINCT + else -> Operator.Aggregation.SetQuantifier.ALL + } + object : Operator.Aggregation { + override val delegate: Agg = agg + override val args: List = args + override val setQuantifier: Operator.Aggregation.SetQuantifier = setq + } + } + return RelOpAggregate(input, keys, aggs) + } + + override fun visitDistinct(rel: RelDistinct, ctx: Unit): Operator.Relation { + val input = compile(rel.getInput(), ctx) + return RelOpDistinct(input) + } + + override fun visitExcept(rel: RelExcept, ctx: Unit): Operator.Relation { + val lhs = compile(rel.getLeft(), ctx) + val rhs = compile(rel.getRight(), ctx) + return when (rel.isAll()) { + true -> RelOpExceptAll(lhs, rhs) + else -> RelOpExceptDistinct(lhs, rhs) + } + } + + override fun visitExclude(rel: RelExclude, ctx: Unit): Operator.Relation { + val input = compile(rel.getInput(), ctx) + + // !! TEMPORARY BLOCK !! + // + // TODO REPLACE ME WITH NEW IMPLEMENTATION IN LATER PR + // + fun translate(step: RelExcludeStep): IRel.Op.Exclude.Step { + val type = when (step) { + is RelExcludeKey -> relOpExcludeTypeStructKey(step.getKey()) + is RelExcludeIndex -> relOpExcludeTypeCollIndex(step.getIndex()) + is RelExcludeSymbol -> relOpExcludeTypeStructSymbol(step.getSymbol()) + is RelExcludeCollectionWildcard -> relOpExcludeTypeCollWildcard() + is RelExcludeStructWildcard -> relOpExcludeTypeStructWildcard() + else -> error("Unsupported exclude step: $step") + } + val substeps = step.getSubsteps().map { translate(it) } + return relOpExcludeStep(type, substeps) + } + + fun translate(path: RelExcludePath): IRel.Op.Exclude.Path { + val root = path.getRoot() + val steps = path.getSteps().map { translate(it) } + return relOpExcludePath( + root = rexOpVar(root.getDepth(), root.getOffset()), + steps = steps + ) + } + + val paths = rel.getPaths().map { translate(it) } + // + // !! TEMPORARY BLOCK !! + + return RelOpExcludeOld(input, paths) + } + + override fun visitFilter(rel: RelFilter, ctx: Unit): Operator.Relation { + val input = compile(rel.getInput(), ctx) + val predicate = compile(rel.getPredicate(), ctx).catch() + return RelOpFilter(input, predicate) + } + + override fun visitIntersect(rel: RelIntersect, ctx: Unit): Operator.Relation { + val lhs = compile(rel.getLeft(), ctx) + val rhs = compile(rel.getRight(), ctx) + return when (rel.isAll()) { + true -> RelOpIntersectAll(lhs, rhs) + else -> RelOpIntersectDistinct(lhs, rhs) + } + } + + override fun visitIterate(rel: RelIterate, ctx: Unit): Operator.Relation { + val input = compile(rel.getInput(), ctx) + return when (mode) { + PartiQLEngine.Mode.PERMISSIVE -> RelOpIteratePermissive(input) + PartiQLEngine.Mode.STRICT -> RelOpIterate(input) + } + } + + override fun visitJoin(rel: RelJoin, ctx: Unit): Operator.Relation { + val lhs = compile(rel.getLeft(), ctx) + val rhs = compile(rel.getRight(), ctx) + val condition = rel.getCondition()?.let { compile(it, ctx) } ?: ExprLit(Datum.bool(true)) + + // TODO JOIN SCHEMAS + val lhsType = rel.getLeftSchema() + val rhsType = rel.getRightSchema() + + return when (rel.getJoinType()) { + RelJoinType.INNER -> RelOpJoinInner(lhs, rhs, condition) + RelJoinType.LEFT -> RelOpJoinOuterLeft(lhs, rhs, condition, rhsType!!) + RelJoinType.RIGHT -> RelOpJoinOuterRight(lhs, rhs, condition, lhsType!!) + RelJoinType.FULL -> RelOpJoinOuterFull(lhs, rhs, condition, lhsType!!, rhsType!!) + } + } + + override fun visitLimit(rel: RelLimit, ctx: Unit): Operator.Relation { + val input = compile(rel.getInput(), ctx) + val limit = compile(rel.getLimit(), ctx) + return RelOpLimit(input, limit) + } + + override fun visitOffset(rel: RelOffset, ctx: Unit): Operator.Relation { + val input = compile(rel.getInput(), ctx) + val offset = compile(rel.getOffset(), ctx) + return RelOpOffset(input, offset) + } + + override fun visitProject(rel: RelProject, ctx: Unit): Operator.Relation { + val input = compile(rel.getInput(), ctx) + val projections = rel.getProjections().map { compile(it, ctx).catch() } + return RelOpProject(input, projections) + } + + override fun visitScan(rel: RelScan, ctx: Unit): Operator.Relation { + val input = compile(rel.getInput(), ctx) + return when (mode) { + PartiQLEngine.Mode.PERMISSIVE -> RelOpScanPermissive(input) + PartiQLEngine.Mode.STRICT -> RelOpScan(input) + } + } + + override fun visitSort(rel: RelSort, ctx: Unit): Operator.Relation { + val input = compile(rel.getInput(), ctx) + val collations = rel.getCollations().map { + val expr = compile(it.getRex(), ctx) + val desc = it.getOrder() == RelCollation.Order.DESC + val last = it.getNulls() == RelCollation.Nulls.LAST + RelOpSort.Collation(expr, desc, last) + } + return RelOpSort(input, collations) + } + + override fun visitUnion(rel: RelUnion, ctx: Unit): Operator.Relation { + val lhs = compile(rel.getLeft(), ctx) + val rhs = compile(rel.getRight(), ctx) + return when (rel.isAll()) { + true -> RelOpUnionAll(lhs, rhs) + else -> RelOpUnionDistinct(lhs, rhs) + } + } + + override fun visitUnpivot(rel: RelUnpivot, ctx: Unit): Operator.Relation { + val input = compile(rel.getInput(), ctx) + return when (mode) { + PartiQLEngine.Mode.PERMISSIVE -> RelOpUnpivot.Permissive(input) + PartiQLEngine.Mode.STRICT -> RelOpUnpivot.Strict(input) + } + } + } + + /** + * Transforms plan expression operators into the internal physical expressions. + */ + private inner class RexCompiler : RexVisitor { + + // + private val unknown = PType.unknown() + + override fun defaultReturn(rex: Rex, ctx: Unit): Operator.Expr { + TODO("Not yet implemented") + } + + override fun visitError(rex: RexError, ctx: Unit): Operator.Expr { + throw IllegalStateException(rex.getMessage()) + } + + // OPERATORS + + override fun visitArray(rex: RexArray, ctx: Unit): Operator.Expr { + val values = rex.getValues().map { compile(it, ctx).catch() } + return ExprArray(values) + } + + override fun visitBag(rex: RexBag, ctx: Unit): Operator.Expr { + val values = rex.getValues().map { compile(it, ctx).catch() } + return ExprBag(values) + } + + override fun visitCallDynamic(rex: RexCallDynamic, ctx: Unit): Operator.Expr { + // Check candidate name and arity for uniformity + var arity: Int = -1 + var name = "unknown" + // Check the candidate list size + val functions = rex.getFunctions() + if (functions.isEmpty()) { + error("Rex.Op.Call.Dynamic had an empty candidates list: $rex.") + } + // Compile the candidates + val candidates = Array(functions.size) { + val fn = functions[it] + val fnArity = fn.signature.parameters.size + val fnName = fn.signature.name.uppercase() + if (arity == -1) { + arity = fnArity + name = fnName + } else { + if (fnArity != arity) { + error("Dynamic call candidate had different arity than others; found $fnArity but expected $arity") + } + if (fnName != name) { + error("Dynamic call candidate had different name than others; found $fnName but expected $name") + } + } + fn + } + val args = rex.getArgs().map { compile(it, ctx).catch() }.toTypedArray() + return ExprCallDynamic(name, candidates, args) + } + + override fun visitCallStatic(rex: RexCallStatic, ctx: Unit): Operator.Expr { + val fn = rex.getFunction() + val args = rex.getArgs().map { compile(it, ctx) } + val fnTakesInMissing = fn.signature.parameters.any { + it.type.kind == PType.Kind.DYNAMIC // TODO: Is this needed? + } + return when (fnTakesInMissing) { + true -> ExprCallStatic(fn, args.map { it.catch() }.toTypedArray()) + else -> ExprCallStatic(fn, args.toTypedArray()) + } + } + + override fun visitCase(rex: RexCase, ctx: Unit): Operator.Expr { + if (rex.getMatch() != null) { + TODO(" expression") + } + val branches = rex.getBranches().map { + val value = compile(it.getCondition(), ctx).catch() + val result = compile(it.getResult(), ctx) + ExprCaseBranch(value, result) + } + val default = rex.getDefault()?.let { compile(it, ctx) } + return ExprCaseSearched(branches, default) + } + + override fun visitCast(rex: RexCast, ctx: Unit): Operator.Expr { + val operand = compile(rex.getOperand(), ctx) + val target = rex.getTarget() + return ExprCast(operand, target) + } + + override fun visitCoalesce(rex: RexCoalesce, ctx: Unit): Operator.Expr { + val args = rex.getArgs().map { compile(it, ctx) }.toTypedArray() + return ExprCoalesce(args) + } + + override fun visitLit(rex: RexLit, ctx: Unit): Operator.Expr { + return ExprLit(rex.getValue()) + } + + override fun visitMissing(rex: RexMissing, ctx: Unit): Operator.Expr { + return ExprMissing(unknown) + } + + override fun visitNullIf(rex: RexNullIf, ctx: Unit): Operator.Expr { + val value = compile(rex.getValue(), ctx) + val nullifier = compile(rex.getNullifier(), ctx) + return ExprNullIf(value, nullifier) + } + + override fun visitPathIndex(rex: RexPathIndex, ctx: Unit): Operator.Expr { + val operand = compile(rex.getOperand(), ctx) + val index = compile(rex.getIndex(), ctx) + return ExprPathIndex(operand, index) + } + + override fun visitPathKey(rex: RexPathKey, ctx: Unit): Operator.Expr { + val operand = compile(rex.getOperand(), ctx) + val key = compile(rex.getKey(), ctx) + return ExprPathKey(operand, key) + } + + override fun visitPathSymbol(rex: RexPathSymbol, ctx: Unit): Operator.Expr { + val operand = compile(rex.getOperand(), ctx) + val symbol = rex.getSymbol() + return ExprPathSymbol(operand, symbol) + } + + override fun visitPivot(rex: RexPivot, ctx: Unit): Operator.Expr { + val input = compile(rex.getInput(), ctx) + val key = compile(rex.getKey(), ctx) + val value = compile(rex.getValue(), ctx) + return when (mode) { + PartiQLEngine.Mode.PERMISSIVE -> ExprPivotPermissive(input, key, value) + PartiQLEngine.Mode.STRICT -> ExprPivot(input, key, value) + } + } + + override fun visitSelect(rex: RexSelect, ctx: Unit): Operator.Expr { + val input = compile(rex.getInput(), ctx) + val constructor = compile(rex.getConstructor(), ctx).catch() + val ordered = rex.getInput().isOrdered() + return ExprSelect(input, constructor, ordered) + } + + override fun visitStruct(rex: RexStruct, ctx: Unit): Operator.Expr { + val fields = rex.getFields().map { + val k = compile(it.getKey(), ctx) + val v = compile(it.getValue(), ctx).catch() + ExprStructField(k, v) + } + return when (mode) { + PartiQLEngine.Mode.PERMISSIVE -> ExprStructPermissive(fields) + PartiQLEngine.Mode.STRICT -> ExprStructStrict(fields) + } + } + + override fun visitSubquery(rex: RexSubquery, ctx: Unit): Operator.Expr { + val rel = compile(rex.getRel(), ctx) + val constructor = compile(rex.getConstructor(), ctx) + return when (rex.asScalar()) { + true -> ExprSubquery(rel, constructor) + else -> ExprSubqueryRow(rel, constructor) + } + } + + override fun visitSubqueryComp(rex: RexSubqueryComp, ctx: Unit): Operator.Expr { + TODO(" and ") + } + + override fun visitSubqueryIn(rex: RexSubqueryIn, ctx: Unit): Operator.Expr { + TODO("") + } + + override fun visitSubqueryTest(rex: RexSubqueryTest, ctx: Unit): Operator.Expr { + TODO(" and ") + } + + override fun visitSpread(rex: RexSpread, ctx: Unit): Operator.Expr { + val args = rex.getArgs().map { compile(it, ctx) }.toTypedArray() + return ExprSpread(args) + } + + override fun visitTable(rex: RexTable, ctx: Unit): Operator.Expr { + return ExprTable(rex.getTable()) + } + + override fun visitVar(rex: RexVar, ctx: Unit): Operator.Expr { + val depth = rex.getDepth() + val offset = rex.getOffset() + return ExprVar(depth, offset) + } + } + + /** + * Some places "catch" an error and return the MISSING value. + */ + private fun Operator.Expr.catch(): Operator.Expr = when (mode) { + PartiQLEngine.Mode.PERMISSIVE -> ExprPermissive(this) + PartiQLEngine.Mode.STRICT -> this + } +} diff --git a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/SqlEngine.kt b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/SqlEngine.kt new file mode 100644 index 0000000000..25f6dc3bb8 --- /dev/null +++ b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/SqlEngine.kt @@ -0,0 +1,26 @@ +package org.partiql.eval.internal + +import org.partiql.eval.PartiQLEngine +import org.partiql.eval.PartiQLStatement +import org.partiql.eval.internal.statement.QueryStatement +import org.partiql.plan.v1.PartiQLPlan +import org.partiql.plan.v1.Statement +import org.partiql.planner.catalog.Session + +internal class SqlEngine : PartiQLEngine { + + override fun prepare(plan: PartiQLPlan, mode: PartiQLEngine.Mode, session: Session): PartiQLStatement { + try { + val statement = plan.getStatement() + if (statement !is Statement.Query) { + throw IllegalArgumentException("Only query statements are supported") + } + val compiler = SqlCompiler(mode, session) + val root = compiler.compile(statement.getRoot()) + return QueryStatement(root) + } catch (ex: Exception) { + // TODO wrap in some PartiQL Exception + throw ex + } + } +} diff --git a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/Symbols.kt b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/Symbols.kt deleted file mode 100644 index daff32ae4e..0000000000 --- a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/Symbols.kt +++ /dev/null @@ -1,97 +0,0 @@ - -package org.partiql.eval.internal - -import org.partiql.eval.PartiQLEngine -import org.partiql.plan.Catalog -import org.partiql.plan.PartiQLPlan -import org.partiql.plan.Ref -import org.partiql.planner.catalog.Name -import org.partiql.planner.catalog.Session -import org.partiql.planner.catalog.Table -import org.partiql.spi.fn.Agg -import org.partiql.spi.fn.Fn -import org.partiql.spi.fn.SqlFnProvider -import org.partiql.planner.catalog.Catalog as Cat - -/** - * TODO Symbols will be removed in the V1 plan as it is no longer necessary. - */ -internal class Symbols private constructor(private val catalogs: Array) { - - private class C( - val name: String, - val catalog: Cat, - val items: Array, - ) { - - // TEMPORARY UNTIL ENGINE USES V1 PLANS - private val session: Session = Session.empty(catalog.getName()) - - // TEMPORARY FOR DEPENDENCY REASONS - fun getTable(name: Name): Table? = catalog.getTable(session, name) - fun getFn(name: Name, specific: String): Fn? = SqlFnProvider.getFn(specific) - fun getAgg(name: Name, specific: String): Agg? = SqlFnProvider.getAgg(specific) - - override fun toString(): String = name - } - - fun getGlobal(ref: Ref): Table { - val catalog = catalogs[ref.catalog] - val item = catalog.items.getOrNull(ref.symbol) - if (item == null || item !is Catalog.Item.Value) { - error("Invalid reference $ref; missing value entry for catalog `$catalog`.") - } - val name = Name.of(item.path) - return catalog.getTable(name) - ?: error("Catalog `$catalog` has no entry for table $item") - } - - fun getFn(ref: Ref): Fn { - val catalog = catalogs[ref.catalog] - val item = catalog.items.getOrNull(ref.symbol) - if (item == null || item !is Catalog.Item.Fn) { - error("Invalid reference $ref; missing function entry for catalog `$catalog`.") - } - // Lookup in connector - val name = Name.of(item.path) - return catalog.getFn(name, item.specific) - ?: error("Catalog `$catalog` has no entry for function $item") - } - - fun getAgg(ref: Ref): Agg { - val catalog = catalogs[ref.catalog] - val item = catalog.items.getOrNull(ref.symbol) - if (item == null || item !is Catalog.Item.Agg) { - error("Invalid reference $ref; missing aggregation entry for catalog `$catalog`.") - } - // Lookup in connector - val name = Name.of(item.path) - return catalog.getAgg(name, item.specific) - ?: error("Catalog `$catalog` has no entry for aggregation function $item") - } - - companion object { - - /** - * Validate a plan's symbol table (plan.catalogs) and memoized necessary connector entities from the session. - * - * @param plan - * @param session - * @return - */ - @JvmStatic - fun build(plan: PartiQLPlan, session: PartiQLEngine.Session): Symbols { - val catalogs = plan.catalogs.map { - val connector = session.catalogs[it.name] - ?: error("The plan contains a catalog `${it.name}`, but this was absent from the engine's session") - C( - name = it.name, - catalog = connector.getCatalog(), - items = it.items.toTypedArray(), - ) - }.toTypedArray() - - return Symbols(catalogs) - } - } -} diff --git a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelAggregate.kt b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpAggregate.kt similarity index 99% rename from partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelAggregate.kt rename to partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpAggregate.kt index 2e702d05e2..23679ee545 100644 --- a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelAggregate.kt +++ b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpAggregate.kt @@ -8,7 +8,7 @@ import org.partiql.spi.fn.Agg import java.util.TreeMap import java.util.TreeSet -internal class RelAggregate( +internal class RelOpAggregate( val input: Operator.Relation, private val keys: List, private val functions: List diff --git a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelDistinct.kt b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpDistinct.kt similarity index 93% rename from partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelDistinct.kt rename to partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpDistinct.kt index 3f0deda598..b47b6bf5fd 100644 --- a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelDistinct.kt +++ b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpDistinct.kt @@ -5,9 +5,9 @@ import org.partiql.eval.internal.Record import org.partiql.eval.internal.operator.Operator import java.util.TreeSet -internal class RelDistinct( +internal class RelOpDistinct( val input: Operator.Relation -) : RelPeeking() { +) : RelOpPeeking() { private val seen = TreeSet(DatumArrayComparator) diff --git a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelExceptAll.kt b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpExceptAll.kt similarity index 96% rename from partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelExceptAll.kt rename to partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpExceptAll.kt index 03c5b11cc6..20b37ec79a 100644 --- a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelExceptAll.kt +++ b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpExceptAll.kt @@ -7,10 +7,10 @@ import org.partiql.eval.internal.operator.Operator import org.partiql.eval.value.Datum import java.util.TreeMap -internal class RelExceptAll( +internal class RelOpExceptAll( private val lhs: Operator.Relation, private val rhs: Operator.Relation, -) : RelPeeking() { +) : RelOpPeeking() { private val seen = TreeMap, Int>(DatumArrayComparator) private var init: Boolean = false diff --git a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelExceptDistinct.kt b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpExceptDistinct.kt similarity index 95% rename from partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelExceptDistinct.kt rename to partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpExceptDistinct.kt index fdda85bd36..3471502be9 100644 --- a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelExceptDistinct.kt +++ b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpExceptDistinct.kt @@ -12,10 +12,10 @@ import java.util.TreeSet * @property lhs * @property rhs */ -internal class RelExceptDistinct( +internal class RelOpExceptDistinct( private val lhs: Operator.Relation, private val rhs: Operator.Relation, -) : RelPeeking() { +) : RelOpPeeking() { private var seen = TreeSet(DatumArrayComparator) private var init: Boolean = false diff --git a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpExclude.kt b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpExclude.kt new file mode 100644 index 0000000000..582e5714b6 --- /dev/null +++ b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpExclude.kt @@ -0,0 +1,203 @@ +package org.partiql.eval.internal.operator.rel + +import org.partiql.eval.internal.Environment +import org.partiql.eval.internal.Record +import org.partiql.eval.internal.helpers.IteratorSupplier +import org.partiql.eval.internal.operator.Operator +import org.partiql.eval.value.Datum +import org.partiql.eval.value.Field +import org.partiql.plan.v1.operator.rel.RelExcludeCollectionWildcard +import org.partiql.plan.v1.operator.rel.RelExcludeIndex +import org.partiql.plan.v1.operator.rel.RelExcludeKey +import org.partiql.plan.v1.operator.rel.RelExcludePath +import org.partiql.plan.v1.operator.rel.RelExcludeStep +import org.partiql.plan.v1.operator.rel.RelExcludeStructWildcard +import org.partiql.plan.v1.operator.rel.RelExcludeSymbol +import org.partiql.types.PType +import org.partiql.value.PartiQLValue +import org.partiql.value.PartiQLValueType + +/** + * TODO THERE ARE BUGS IN THIS IMPLEMENTATION POSSIBLY DUE TO HASHCODE/EQUALS OF [RelExcludePath]. + */ +internal class RelOpExclude( + private val input: Operator.Relation, + private val exclusions: List, +) : Operator.Relation { + + override fun open(env: Environment) { + input.open(env) + } + + override fun hasNext(): Boolean { + return input.hasNext() + } + + override fun next(): Record { + val record = input.next() + exclusions.forEach { path -> + val o = path.getRoot().getOffset() + val value = record.values[o] + record.values[o] = excludeValue(value, path.getSteps().toList()) + } + return record + } + + override fun close() { + input.close() + } + + private fun excludeFields( + structValue: Datum, + exclusions: List, + ): Datum { + val structSymbolsToRemove = mutableSetOf() + val structKeysToRemove = mutableSetOf() // keys stored as lowercase strings + val branches = mutableMapOf>() + exclusions.forEach { exclusion -> + val substeps = exclusion.getSubsteps() + when (substeps.isEmpty()) { + true -> { + when (exclusion) { + is RelExcludeStructWildcard -> { + // struct wildcard at current level. return empty struct + return Datum.struct(emptyList()) + } + is RelExcludeSymbol -> structSymbolsToRemove.add(exclusion.getSymbol()) + is RelExcludeKey -> structKeysToRemove.add(exclusion.getKey().lowercase()) + else -> { /* coll step; do nothing */ + } + } + } + false -> { + when (exclusion) { + is RelExcludeStructWildcard, + is RelExcludeSymbol, + is RelExcludeKey, + -> { + branches[exclusion] = exclusion.getSubsteps() + } + else -> { /* coll step; do nothing */ + } + } + } + } + } + val structSupplier = IteratorSupplier { structValue.fields } + val finalStruct = structSupplier.mapNotNull { structField -> + if (structSymbolsToRemove.contains(structField.name) || structKeysToRemove.contains(structField.name.lowercase())) { + // struct attr is to be removed at current level + null + } else { + // deeper level exclusions + val name = structField.name + var value = structField.value + // apply struct key exclusions at deeper levels + val structKey = RelExcludeStep.key(name) + branches[structKey]?.let { + value = excludeValue(value, it) + } + // apply struct symbol exclusions at deeper levels + val structSymbol = RelExcludeStep.symbol(name) + branches[structSymbol]?.let { + value = excludeValue(value, it) + } + // apply struct wildcard exclusions at deeper levels + val structWildcard = RelExcludeStep.struct() + branches[structWildcard]?.let { + value = excludeValue(value, it) + } + Pair(name, value) + } + }.map { Field.of(it.first, it.second) } + return Datum.struct(finalStruct) + } + + /** + * Returns a [PartiQLValue] created from an iterable of [coll]. Requires [type] to be a collection type + * (i.e. [PartiQLValueType.LIST], [PartiQLValueType.BAG], or [PartiQLValueType.SEXP]). + */ + private fun newCollValue(type: PType, coll: Iterable): Datum { + return when (type.kind) { + PType.Kind.ARRAY -> Datum.list(coll) + PType.Kind.BAG -> Datum.bag(coll) + PType.Kind.SEXP -> Datum.sexp(coll) + else -> error("Collection type required") + } + } + + private fun excludeCollection( + coll: Iterable, + type: PType, + exclusions: List, + ): Datum { + val indexesToRemove = mutableSetOf() + val branches = mutableMapOf>() + exclusions.forEach { exclusion -> + val substeps = exclusion.getSubsteps() + when (substeps.isEmpty()) { + true -> { + when (exclusion) { + is RelExcludeCollectionWildcard -> { + // collection wildcard at current level. return empty collection + return newCollValue(type, emptyList()) + } + is RelExcludeIndex -> { + indexesToRemove.add(exclusion.getIndex()) + } + else -> { /* struct step; do nothing */ + } + } + } + false -> { + when (exclusion) { + is RelExcludeCollectionWildcard, + is RelExcludeIndex, + -> { + branches[exclusion] = exclusion.getSubsteps() + } + else -> { /* struct step; do nothing */ + } + } + } + } + } + val finalColl = coll.mapIndexedNotNull { index, element -> + if (indexesToRemove.contains(index)) { + // coll index is to be removed at current level + null + } else { + // deeper level exclusions + var value = element + if (type.kind == PType.Kind.ARRAY || type.kind == PType.Kind.SEXP) { + // apply collection index exclusions at deeper levels for lists and sexps + val collIndex = RelExcludeStep.index(index) + branches[collIndex]?.let { + value = excludeValue(element, it) + } + } + // apply collection wildcard exclusions at deeper levels for lists, bags, and sexps + val collWildcard = RelExcludeStep.collection() + branches[collWildcard]?.let { + value = excludeValue(value, it) + } + value + } + } + return newCollValue(type, finalColl) + } + + private fun excludeValue(initialPartiQLValue: Datum, exclusions: List): Datum { + return when (initialPartiQLValue.type.kind) { + PType.Kind.ROW, PType.Kind.STRUCT -> excludeFields(initialPartiQLValue, exclusions) + PType.Kind.BAG, PType.Kind.ARRAY, PType.Kind.SEXP -> excludeCollection( + initialPartiQLValue, + initialPartiQLValue.type, + exclusions + ) + else -> { + initialPartiQLValue + } + } + } +} diff --git a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelExclude.kt b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpExcludeOld.kt similarity index 92% rename from partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelExclude.kt rename to partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpExcludeOld.kt index b1038a65e5..8158d3aaf5 100644 --- a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelExclude.kt +++ b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpExcludeOld.kt @@ -14,12 +14,14 @@ import org.partiql.plan.relOpExcludeTypeStructSymbol import org.partiql.plan.relOpExcludeTypeStructWildcard import org.partiql.types.PType import org.partiql.value.PartiQLValue -import org.partiql.value.PartiQLValueExperimental import org.partiql.value.PartiQLValueType -internal class RelExclude( +/** + * TODO REPLACE WITH [RelOpExclude] IN A LATER PR. + */ +internal class RelOpExcludeOld( private val input: Operator.Relation, - private val exclusions: List + private val exclusions: List, ) : Operator.Relation { override fun open(env: Environment) { @@ -30,7 +32,6 @@ internal class RelExclude( return input.hasNext() } - @OptIn(PartiQLValueExperimental::class) override fun next(): Record { val record = input.next() exclusions.forEach { path -> @@ -47,7 +48,7 @@ internal class RelExclude( private fun excludeFields( structValue: Datum, - exclusions: List + exclusions: List, ): Datum { val structSymbolsToRemove = mutableSetOf() val structKeysToRemove = mutableSetOf() // keys stored as lowercase strings @@ -62,14 +63,16 @@ internal class RelExclude( } is Rel.Op.Exclude.Type.StructSymbol -> structSymbolsToRemove.add(leafType.symbol) is Rel.Op.Exclude.Type.StructKey -> structKeysToRemove.add(leafType.key.lowercase()) - else -> { /* coll step; do nothing */ } + else -> { /* coll step; do nothing */ + } } } false -> { when (exclusion.type) { is Rel.Op.Exclude.Type.StructWildcard, is Rel.Op.Exclude.Type.StructSymbol, is Rel.Op.Exclude.Type.StructKey -> branches[exclusion.type] = exclusion.substeps - else -> { /* coll step; do nothing */ } + else -> { /* coll step; do nothing */ + } } } } @@ -120,7 +123,7 @@ internal class RelExclude( private fun excludeCollection( coll: Iterable, type: PType, - exclusions: List + exclusions: List, ): Datum { val indexesToRemove = mutableSetOf() val branches = mutableMapOf>() @@ -135,14 +138,16 @@ internal class RelExclude( is Rel.Op.Exclude.Type.CollIndex -> { indexesToRemove.add(leafType.index) } - else -> { /* struct step; do nothing */ } + else -> { /* struct step; do nothing */ + } } } false -> { when (exclusion.type) { is Rel.Op.Exclude.Type.CollWildcard, is Rel.Op.Exclude.Type.CollIndex -> branches[exclusion.type] = exclusion.substeps - else -> { /* struct step; do nothing */ } + else -> { /* struct step; do nothing */ + } } } } diff --git a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelFilter.kt b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpFilter.kt similarity index 94% rename from partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelFilter.kt rename to partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpFilter.kt index fbce3305ea..d0d9451031 100644 --- a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelFilter.kt +++ b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpFilter.kt @@ -5,10 +5,10 @@ import org.partiql.eval.internal.Record import org.partiql.eval.internal.helpers.ValueUtility.isTrue import org.partiql.eval.internal.operator.Operator -internal class RelFilter( +internal class RelOpFilter( val input: Operator.Relation, val expr: Operator.Expr -) : RelPeeking() { +) : RelOpPeeking() { private lateinit var env: Environment diff --git a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelIntersectAll.kt b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpIntersectAll.kt similarity index 96% rename from partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelIntersectAll.kt rename to partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpIntersectAll.kt index 294dc183ae..e8cc990302 100644 --- a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelIntersectAll.kt +++ b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpIntersectAll.kt @@ -7,10 +7,10 @@ import org.partiql.eval.internal.operator.Operator import org.partiql.eval.value.Datum import java.util.TreeMap -internal class RelIntersectAll( +internal class RelOpIntersectAll( private val lhs: Operator.Relation, private val rhs: Operator.Relation, -) : RelPeeking() { +) : RelOpPeeking() { private val seen = TreeMap, Int>(DatumArrayComparator) private var init: Boolean = false diff --git a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelIntersectDistinct.kt b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpIntersectDistinct.kt similarity index 95% rename from partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelIntersectDistinct.kt rename to partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpIntersectDistinct.kt index 1ca876c6d5..b3de829ace 100644 --- a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelIntersectDistinct.kt +++ b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpIntersectDistinct.kt @@ -6,10 +6,10 @@ import org.partiql.eval.internal.helpers.RecordUtility.coerceMissing import org.partiql.eval.internal.operator.Operator import java.util.TreeSet -internal class RelIntersectDistinct( +internal class RelOpIntersectDistinct( private val lhs: Operator.Relation, private val rhs: Operator.Relation, -) : RelPeeking() { +) : RelOpPeeking() { private val seen = TreeSet(DatumArrayComparator) private var init: Boolean = false diff --git a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelScanIndexed.kt b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpIterate.kt similarity index 97% rename from partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelScanIndexed.kt rename to partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpIterate.kt index 65f8c65a26..403a4ad82b 100644 --- a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelScanIndexed.kt +++ b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpIterate.kt @@ -7,7 +7,7 @@ import org.partiql.eval.internal.operator.Operator import org.partiql.eval.value.Datum import org.partiql.types.PType -internal class RelScanIndexed( +internal class RelOpIterate( private val expr: Operator.Expr ) : Operator.Relation { diff --git a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelScanIndexedPermissive.kt b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpIteratePermissive.kt similarity index 96% rename from partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelScanIndexedPermissive.kt rename to partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpIteratePermissive.kt index 00b931daf3..713d1f41f2 100644 --- a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelScanIndexedPermissive.kt +++ b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpIteratePermissive.kt @@ -6,7 +6,7 @@ import org.partiql.eval.internal.operator.Operator import org.partiql.eval.value.Datum import org.partiql.types.PType -internal class RelScanIndexedPermissive( +internal class RelOpIteratePermissive( private val expr: Operator.Expr ) : Operator.Relation { diff --git a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelJoinInner.kt b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpJoinInner.kt similarity index 97% rename from partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelJoinInner.kt rename to partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpJoinInner.kt index cc8feae87f..e3af5c4859 100644 --- a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelJoinInner.kt +++ b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpJoinInner.kt @@ -12,11 +12,11 @@ import org.partiql.value.PartiQLValueExperimental * Note: This is currently the lateral version of the inner join. In the future, the two implementations * (lateral vs non-lateral) may be separated for performance improvements. */ -internal class RelJoinInner( +internal class RelOpJoinInner( private val lhs: Operator.Relation, private val rhs: Operator.Relation, private val condition: Operator.Expr, -) : RelPeeking() { +) : RelOpPeeking() { private lateinit var env: Environment private lateinit var iterator: Iterator diff --git a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelJoinOuterFull.kt b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpJoinOuterFull.kt similarity index 88% rename from partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelJoinOuterFull.kt rename to partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpJoinOuterFull.kt index a5b9c6a230..520ce499f2 100644 --- a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelJoinOuterFull.kt +++ b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpJoinOuterFull.kt @@ -5,7 +5,7 @@ import org.partiql.eval.internal.Record import org.partiql.eval.internal.helpers.ValueUtility.isTrue import org.partiql.eval.internal.operator.Operator import org.partiql.eval.value.Datum -import org.partiql.plan.Rel +import org.partiql.plan.v1.Schema /** * Full Outer Join returns all joined records from the [lhs] and [rhs] when the [condition] evaluates to true. For all @@ -14,21 +14,19 @@ import org.partiql.plan.Rel * * Full Outer Join cannot be lateral according to PartiQL Specification Section 5.5. */ -internal class RelJoinOuterFull( +internal class RelOpJoinOuterFull( private val lhs: Operator.Relation, private val rhs: Operator.Relation, private val condition: Operator.Expr, - lhsType: Rel.Type, - rhsType: Rel.Type -) : RelPeeking() { + lhsType: Schema, + rhsType: Schema, +) : RelOpPeeking() { - private val lhsPadded = Record( - Array(rhsType.schema.size) { Datum.nullValue(lhsType.schema[it].type) } - ) - - private val rhsPadded = Record( - Array(rhsType.schema.size) { Datum.nullValue(rhsType.schema[it].type) } - ) + // TODO BETTER MECHANISM FOR NULL PADDING + private val r = rhsType.getFields().toTypedArray() + private val l = lhsType.getFields().toTypedArray() + private val lhsPadded: Record = Record(r.indices.map { Datum.nullValue(l[it].type) }.toTypedArray()) + private val rhsPadded: Record = Record(r.indices.map { Datum.nullValue(r[it].type) }.toTypedArray()) private lateinit var env: Environment private lateinit var iterator: Iterator diff --git a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelJoinOuterLeft.kt b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpJoinOuterLeft.kt similarity index 90% rename from partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelJoinOuterLeft.kt rename to partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpJoinOuterLeft.kt index 6599b1d2d3..b564ac7bdb 100644 --- a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelJoinOuterLeft.kt +++ b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpJoinOuterLeft.kt @@ -5,7 +5,7 @@ import org.partiql.eval.internal.Record import org.partiql.eval.internal.helpers.ValueUtility.isTrue import org.partiql.eval.internal.operator.Operator import org.partiql.eval.value.Datum -import org.partiql.plan.Rel +import org.partiql.plan.v1.Schema import org.partiql.value.PartiQLValueExperimental /** @@ -15,16 +15,15 @@ import org.partiql.value.PartiQLValueExperimental * Note: This is currently the lateral version of the left outer join. In the future, the two implementations * (lateral vs non-lateral) may be separated for performance improvements. */ -internal class RelJoinOuterLeft( +internal class RelOpJoinOuterLeft( private val lhs: Operator.Relation, private val rhs: Operator.Relation, private val condition: Operator.Expr, - rhsType: Rel.Type -) : RelPeeking() { + rhsType: Schema, +) : RelOpPeeking() { - private val rhsPadded = Record( - Array(rhsType.schema.size) { Datum.nullValue(rhsType.schema[it].type) } - ) + // TODO BETTER MECHANISM FOR NULL PADDING + private val rhsPadded = Record(rhsType.getFields().map { Datum.nullValue(it.type) }.toTypedArray()) private lateinit var env: Environment private lateinit var iterator: Iterator diff --git a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelJoinOuterRight.kt b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpJoinOuterRight.kt similarity index 89% rename from partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelJoinOuterRight.kt rename to partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpJoinOuterRight.kt index 71c667f3d0..b0f2ff8b1b 100644 --- a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelJoinOuterRight.kt +++ b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpJoinOuterRight.kt @@ -5,7 +5,7 @@ import org.partiql.eval.internal.Record import org.partiql.eval.internal.helpers.ValueUtility.isTrue import org.partiql.eval.internal.operator.Operator import org.partiql.eval.value.Datum -import org.partiql.plan.Rel +import org.partiql.plan.v1.Schema /** * Right Outer Join returns all joined records from the [lhs] and [rhs] when the [condition] evaluates to true. For all @@ -13,16 +13,15 @@ import org.partiql.plan.Rel * * Right Outer Join cannot be lateral according to PartiQL Specification Section 5.5. */ -internal class RelJoinOuterRight( +internal class RelOpJoinOuterRight( private val lhs: Operator.Relation, private val rhs: Operator.Relation, private val condition: Operator.Expr, - lhsType: Rel.Type -) : RelPeeking() { + lhsType: Schema +) : RelOpPeeking() { - private val lhsPadded = Record( - Array(lhsType.schema.size) { Datum.nullValue(lhsType.schema[it].type) } - ) + // TODO BETTER MECHANISM FOR NULL PADDING + private val lhsPadded = Record(lhsType.getFields().map { Datum.nullValue(it.type) }.toTypedArray()) private lateinit var env: Environment private lateinit var iterator: Iterator diff --git a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelLimit.kt b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpLimit.kt similarity index 97% rename from partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelLimit.kt rename to partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpLimit.kt index b88c7aac1d..16ddc73c14 100644 --- a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelLimit.kt +++ b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpLimit.kt @@ -8,7 +8,7 @@ import org.partiql.value.PartiQLValueExperimental import java.math.BigInteger @OptIn(PartiQLValueExperimental::class) -internal class RelLimit( +internal class RelOpLimit( private val input: Operator.Relation, private val limit: Operator.Expr, ) : Operator.Relation { diff --git a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOffset.kt b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpOffset.kt similarity index 97% rename from partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOffset.kt rename to partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpOffset.kt index d01b65d1aa..53b2721376 100644 --- a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOffset.kt +++ b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpOffset.kt @@ -8,7 +8,7 @@ import org.partiql.value.PartiQLValueExperimental import java.math.BigInteger @OptIn(PartiQLValueExperimental::class) -internal class RelOffset( +internal class RelOpOffset( private val input: Operator.Relation, private val offset: Operator.Expr, ) : Operator.Relation { diff --git a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelPeeking.kt b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpPeeking.kt similarity index 83% rename from partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelPeeking.kt rename to partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpPeeking.kt index 6206b783bf..2bec83ab91 100644 --- a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelPeeking.kt +++ b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpPeeking.kt @@ -9,15 +9,15 @@ import org.partiql.eval.internal.operator.Operator * For [Operator.Relation]'s that MUST materialize data in order to execute [hasNext], this abstract class caches the * result of [peek] to implement both [hasNext] and [next]. */ -internal abstract class RelPeeking : Operator.Relation, IteratorPeeking() { +internal abstract class RelOpPeeking : Operator.Relation, IteratorPeeking() { /** - * This shall have the same functionality as [open]. Implementers of [RelPeeking] shall not override [open]. + * This shall have the same functionality as [open]. Implementers of [RelOpPeeking] shall not override [open]. */ abstract fun openPeeking(env: Environment) /** - * This shall have the same functionality as [close]. Implementers of [RelPeeking] shall not override [close]. + * This shall have the same functionality as [close]. Implementers of [RelOpPeeking] shall not override [close]. */ abstract fun closePeeking() diff --git a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelProject.kt b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpProject.kt similarity index 96% rename from partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelProject.kt rename to partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpProject.kt index 657d7ae634..ead09dae08 100644 --- a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelProject.kt +++ b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpProject.kt @@ -4,7 +4,7 @@ import org.partiql.eval.internal.Environment import org.partiql.eval.internal.Record import org.partiql.eval.internal.operator.Operator -internal class RelProject( +internal class RelOpProject( private val input: Operator.Relation, private val projections: List ) : Operator.Relation { diff --git a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelScan.kt b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpScan.kt similarity index 97% rename from partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelScan.kt rename to partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpScan.kt index ac231ef70c..fc37b051a9 100644 --- a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelScan.kt +++ b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpScan.kt @@ -7,7 +7,7 @@ import org.partiql.eval.internal.helpers.RecordValueIterator import org.partiql.eval.internal.operator.Operator import org.partiql.types.PType -internal class RelScan( +internal class RelOpScan( private val expr: Operator.Expr ) : Operator.Relation { diff --git a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelScanPermissive.kt b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpScanPermissive.kt similarity index 96% rename from partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelScanPermissive.kt rename to partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpScanPermissive.kt index d9dff6924a..4c023b28a9 100644 --- a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelScanPermissive.kt +++ b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpScanPermissive.kt @@ -6,7 +6,7 @@ import org.partiql.eval.internal.helpers.RecordValueIterator import org.partiql.eval.internal.operator.Operator import org.partiql.types.PType -internal class RelScanPermissive( +internal class RelOpScanPermissive( private val expr: Operator.Expr ) : Operator.Relation { diff --git a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelSort.kt b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpSort.kt similarity index 52% rename from partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelSort.kt rename to partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpSort.kt index 0d45d85d45..699410732f 100644 --- a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelSort.kt +++ b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpSort.kt @@ -3,20 +3,20 @@ package org.partiql.eval.internal.operator.rel import org.partiql.eval.internal.Environment import org.partiql.eval.internal.Record import org.partiql.eval.internal.operator.Operator -import org.partiql.eval.value.Datum -import org.partiql.plan.Rel +import org.partiql.value.PartiQLValue +import org.partiql.value.PartiQLValueExperimental import java.util.Collections -internal class RelSort( +@OptIn(PartiQLValueExperimental::class) +internal class RelOpSort( private val input: Operator.Relation, - private val specs: List> - + private val collations: List, ) : Operator.Relation { private var records: Iterator = Collections.emptyIterator() private var init: Boolean = false - private val nullsFirstComparator = Datum.comparator(true) - private val nullsLastComparator = Datum.comparator(false) + private val nullsFirstComparator = PartiQLValue.comparator(nullsFirst = true) + private val nullsLastComparator = PartiQLValue.comparator(nullsFirst = false) private lateinit var env: Environment @@ -29,17 +29,19 @@ internal class RelSort( private val comparator = object : Comparator { override fun compare(l: Record, r: Record): Int { - specs.forEach { spec -> - val lVal = spec.first.eval(env.push(l)) - val rVal = spec.first.eval(env.push(r)) + collations.forEach { spec -> + // TODO: Write comparator for PQLValue + val lVal = spec.expr.eval(env.push(l)).toPartiQLValue() + val rVal = spec.expr.eval(env.push(r)).toPartiQLValue() // DESC_NULLS_FIRST(l, r) == ASC_NULLS_LAST(r, l) // DESC_NULLS_LAST(l, r) == ASC_NULLS_FIRST(r, l) - val cmpResult = when (spec.second) { - Rel.Op.Sort.Order.ASC_NULLS_FIRST -> nullsFirstComparator.compare(lVal, rVal) - Rel.Op.Sort.Order.ASC_NULLS_LAST -> nullsLastComparator.compare(lVal, rVal) - Rel.Op.Sort.Order.DESC_NULLS_FIRST -> nullsLastComparator.compare(rVal, lVal) - Rel.Op.Sort.Order.DESC_NULLS_LAST -> nullsFirstComparator.compare(rVal, lVal) + val cmpResult = when { + !spec.desc && !spec.last -> nullsFirstComparator.compare(lVal, rVal) + !spec.desc && spec.last -> nullsLastComparator.compare(lVal, rVal) + spec.desc && !spec.last -> nullsLastComparator.compare(rVal, lVal) + spec.desc && spec.last -> nullsFirstComparator.compare(rVal, lVal) + else -> 0 // unreachable } if (cmpResult != 0) { return cmpResult @@ -70,4 +72,17 @@ internal class RelSort( init = false input.close() } + + /** + * DO NOT USE FINAL. + * + * @property expr The expression to sort by.. + * @property desc True iff DESC sort, otherwise ASC. + * @property last True iff NULLS LAST sort, otherwise NULLS FIRST. + */ + class Collation( + @JvmField var expr: Operator.Expr, + @JvmField var desc: Boolean, + @JvmField var last: Boolean, + ) } diff --git a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelUnionAll.kt b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpUnionAll.kt similarity index 97% rename from partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelUnionAll.kt rename to partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpUnionAll.kt index ece7a8dde3..bf59b2d25b 100644 --- a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelUnionAll.kt +++ b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpUnionAll.kt @@ -5,7 +5,7 @@ import org.partiql.eval.internal.Record import org.partiql.eval.internal.helpers.RecordUtility.coerceMissing import org.partiql.eval.internal.operator.Operator -internal class RelUnionAll( +internal class RelOpUnionAll( private val lhs: Operator.Relation, private val rhs: Operator.Relation, ) : Operator.Relation { diff --git a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelUnionDistinct.kt b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpUnionDistinct.kt similarity index 95% rename from partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelUnionDistinct.kt rename to partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpUnionDistinct.kt index dea611d6b9..d17b772af7 100644 --- a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelUnionDistinct.kt +++ b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpUnionDistinct.kt @@ -7,10 +7,10 @@ import org.partiql.eval.internal.helpers.RecordUtility.coerceMissing import org.partiql.eval.internal.operator.Operator import java.util.TreeSet -internal class RelUnionDistinct( +internal class RelOpUnionDistinct( private val lhs: Operator.Relation, private val rhs: Operator.Relation, -) : RelPeeking() { +) : RelOpPeeking() { private val seen = TreeSet(DatumArrayComparator) diff --git a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelUnpivot.kt b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpUnpivot.kt similarity index 88% rename from partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelUnpivot.kt rename to partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpUnpivot.kt index e3d46bfde9..b7505512a9 100644 --- a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelUnpivot.kt +++ b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rel/RelOpUnpivot.kt @@ -7,7 +7,6 @@ import org.partiql.eval.internal.operator.Operator import org.partiql.eval.value.Datum import org.partiql.eval.value.Field import org.partiql.types.PType -import org.partiql.value.PartiQLValueExperimental /** * The unpivot operator produces a bag of records from a struct. @@ -15,8 +14,7 @@ import org.partiql.value.PartiQLValueExperimental * Input: { k_0: v_0, ..., k_i: v_i } * Output: [ k_0, v_0 ] ... [ k_i, v_i ] */ -@OptIn(PartiQLValueExperimental::class) -internal sealed class RelUnpivot : Operator.Relation { +internal sealed class RelOpUnpivot : Operator.Relation { /** * Iterator of the struct fields. @@ -56,7 +54,7 @@ internal sealed class RelUnpivot : Operator.Relation { * * @property expr */ - class Strict(private val expr: Operator.Expr) : RelUnpivot() { + class Strict(private val expr: Operator.Expr) : RelOpUnpivot() { override fun struct(): Datum { val v = expr.eval(env.push(Record.empty)) @@ -76,7 +74,7 @@ internal sealed class RelUnpivot : Operator.Relation { * * @property expr */ - class Permissive(private val expr: Operator.Expr) : RelUnpivot() { + class Permissive(private val expr: Operator.Expr) : RelOpUnpivot() { override fun struct(): Datum { val v = expr.eval(env.push(Record.empty)) diff --git a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rex/ExprArray.kt b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rex/ExprArray.kt new file mode 100644 index 0000000000..43d81d0661 --- /dev/null +++ b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rex/ExprArray.kt @@ -0,0 +1,16 @@ +package org.partiql.eval.internal.operator.rex + +import org.partiql.eval.internal.Environment +import org.partiql.eval.internal.operator.Operator +import org.partiql.eval.value.Datum + +/** + * Creates a bag by evaluating each input value expression. + */ +internal class ExprArray(values: List) : Operator.Expr { + + // DO NOT USE FINAL + private var _values = values + + override fun eval(env: Environment): Datum = Datum.list(_values.map { it.eval(env) }) +} diff --git a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rex/ExprBag.kt b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rex/ExprBag.kt new file mode 100644 index 0000000000..8aaeb2ad93 --- /dev/null +++ b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rex/ExprBag.kt @@ -0,0 +1,16 @@ +package org.partiql.eval.internal.operator.rex + +import org.partiql.eval.internal.Environment +import org.partiql.eval.internal.operator.Operator +import org.partiql.eval.value.Datum + +/** + * Creates a bag by evaluating each input value expression. + */ +internal class ExprBag(values: List) : Operator.Expr { + + // DO NOT USE FINAL + private var _values = values + + override fun eval(env: Environment): Datum = Datum.bag(_values.map { it.eval(env) }) +} diff --git a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rex/ExprCaseBranch.kt b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rex/ExprCaseBranch.kt new file mode 100644 index 0000000000..52dfb79bd0 --- /dev/null +++ b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rex/ExprCaseBranch.kt @@ -0,0 +1,46 @@ +package org.partiql.eval.internal.operator.rex + +import org.partiql.eval.internal.Environment +import org.partiql.eval.internal.operator.Operator +import org.partiql.eval.value.Datum +import org.partiql.types.PType + +/** + * Represents a single branch of a or expression. + * + * @param value + * @param result + */ +internal class ExprCaseBranch(value: Operator.Expr, result: Operator.Expr) { + + // DO NOT USE FINAL + private var _value = value + private var _result = result + + /** + * Evaluate the branch and compare against the match; returning the _value if the match succeeds. + */ + fun eval(env: Environment): Datum? { + val v = _value.eval(env) + if (v.type.kind == PType.Kind.BOOL && !v.isNull && !v.isMissing && v.boolean) { + return _result.eval(env) + } + return null + } + + /** + * Evaluate the branch and compare against the match; returning the _value if the match succeeds. + */ + fun eval(env: Environment, match: Datum): Datum? { + return if (equal(match, _value.eval(env))) _result.eval(env) else null + } + + private companion object { + + @JvmStatic + private val comparator = Datum.comparator() + + @JvmStatic + private fun equal(lhs: Datum, rhs: Datum) = comparator.compare(lhs, rhs) == 0 + } +} diff --git a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rex/ExprCaseSearched.kt b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rex/ExprCaseSearched.kt new file mode 100644 index 0000000000..4b2b85d00a --- /dev/null +++ b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rex/ExprCaseSearched.kt @@ -0,0 +1,27 @@ +package org.partiql.eval.internal.operator.rex + +import org.partiql.eval.internal.Environment +import org.partiql.eval.internal.operator.Operator +import org.partiql.eval.value.Datum + +/** + * Implementation of the expression. + */ +internal class ExprCaseSearched(branches: List, default: Operator.Expr?) : Operator.Expr { + + // DO NOT USE FINAL + private var _branches = branches + private var _default = default + + override fun eval(env: Environment): Datum { + // search + for (branch in _branches) { + val result = branch.eval(env) + if (result != null) { + return result + } + } + // default + return _default?.eval(env) ?: Datum.nullValue() + } +} diff --git a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rex/ExprCast.kt b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rex/ExprCast.kt index ab7e1550a4..770da49947 100644 --- a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rex/ExprCast.kt +++ b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rex/ExprCast.kt @@ -5,12 +5,22 @@ import org.partiql.eval.internal.operator.Operator import org.partiql.eval.value.Datum import org.partiql.types.PType -internal class ExprCast( - private val arg: Operator.Expr, - private val cast: PType -) : Operator.Expr { +/** + * Implementation of a CAST expression. + * + * @constructor + * TODO + * + * @param operand + * @param target + */ +internal class ExprCast(operand: Operator.Expr, target: PType) : Operator.Expr { + + // DO NOT USE FINAL + private var _operand = operand + private var _target = target + override fun eval(env: Environment): Datum { - val argDatum = arg.eval(env) - return CastTable.cast(argDatum, cast) + return CastTable.cast(_operand.eval(env), _target) } } diff --git a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rex/ExprCollection.kt b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rex/ExprCollection.kt deleted file mode 100644 index ea96923248..0000000000 --- a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rex/ExprCollection.kt +++ /dev/null @@ -1,23 +0,0 @@ -package org.partiql.eval.internal.operator.rex - -import org.partiql.eval.internal.Environment -import org.partiql.eval.internal.operator.Operator -import org.partiql.eval.value.Datum -import org.partiql.types.PType -import org.partiql.value.PartiQLValueExperimental - -internal class ExprCollection( - private val values: List, - private val type: PType -) : Operator.Expr { - - @PartiQLValueExperimental - override fun eval(env: Environment): Datum { - return when (type.kind) { - PType.Kind.BAG -> Datum.bag(values.map { it.eval(env) }) - PType.Kind.SEXP -> Datum.sexp(values.map { it.eval(env) }) - PType.Kind.ARRAY -> Datum.list(values.map { it.eval(env) }) - else -> error("Unsupported type for collection $type") - } - } -} diff --git a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rex/ExprLit.kt b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rex/ExprLit.kt new file mode 100644 index 0000000000..84718368ee --- /dev/null +++ b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rex/ExprLit.kt @@ -0,0 +1,16 @@ +package org.partiql.eval.internal.operator.rex + +import org.partiql.eval.internal.Environment +import org.partiql.eval.internal.operator.Operator +import org.partiql.eval.value.Datum + +/** + * Literal expression. + */ +internal class ExprLit(value: Datum) : Operator.Expr { + + // DO NOT USE FINAL + private var _value = value + + override fun eval(env: Environment): Datum = _value +} diff --git a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rex/ExprLiteral.kt b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rex/ExprLiteral.kt deleted file mode 100644 index 7736e7b503..0000000000 --- a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rex/ExprLiteral.kt +++ /dev/null @@ -1,13 +0,0 @@ -package org.partiql.eval.internal.operator.rex - -import org.partiql.eval.internal.Environment -import org.partiql.eval.internal.operator.Operator -import org.partiql.eval.value.Datum -import org.partiql.value.PartiQLValueExperimental - -internal class ExprLiteral(private val value: Datum) : Operator.Expr { - @PartiQLValueExperimental - override fun eval(env: Environment): Datum { - return value - } -} diff --git a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rex/ExprPathIndex.kt b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rex/ExprPathIndex.kt index 9501d04219..7595f73013 100644 --- a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rex/ExprPathIndex.kt +++ b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rex/ExprPathIndex.kt @@ -15,8 +15,10 @@ internal class ExprPathIndex( override fun eval(env: Environment): Datum { val input = root.eval(env) val iterator = when (input.type.kind) { - PType.Kind.BAG, PType.Kind.ARRAY, PType.Kind.SEXP -> input.iterator() - else -> throw TypeCheckException() + PType.Kind.BAG, + PType.Kind.ARRAY, + PType.Kind.SEXP -> input.iterator() + else -> throw TypeCheckException("expected collection, found ${input.type.kind}") } // Calculate index diff --git a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rex/ExprTupleUnion.kt b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rex/ExprSpread.kt similarity index 96% rename from partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rex/ExprTupleUnion.kt rename to partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rex/ExprSpread.kt index 2d93741e1f..fbb9f2bbc3 100644 --- a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rex/ExprTupleUnion.kt +++ b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rex/ExprSpread.kt @@ -8,7 +8,7 @@ import org.partiql.types.PType import org.partiql.value.PartiQLValueExperimental import org.partiql.value.PartiQLValueType -internal class ExprTupleUnion( +internal class ExprSpread( val args: Array ) : Operator.Expr { diff --git a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rex/ExprSubquery.kt b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rex/ExprSubquery.kt index d6b3c1a752..7115018b5b 100644 --- a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rex/ExprSubquery.kt +++ b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rex/ExprSubquery.kt @@ -3,80 +3,64 @@ package org.partiql.eval.internal.operator.rex import org.partiql.errors.CardinalityViolation import org.partiql.errors.TypeCheckException import org.partiql.eval.internal.Environment -import org.partiql.eval.internal.helpers.IteratorSupplier import org.partiql.eval.internal.helpers.ValueUtility.check import org.partiql.eval.internal.operator.Operator import org.partiql.eval.value.Datum -import org.partiql.value.PartiQLValueExperimental -import org.partiql.value.PartiQLValueType +import org.partiql.types.PType /** - * The PartiQL Specification talks about subqueries and how they are coerced. Specifically, subqueries are - * modeled as a COLL_TO_SCALAR(SELECT VALUE ...) where the SELECT VALUE must return a single row containing - * a TUPLE. + * Implementation of scalar subquery coercion. * - * @see [getFirst] + * TODO REMOVE CONSTRUCTOR – TEMPORARY UNTIL SUBQUERIES ARE FIXED IN THE PLANNER. */ -internal abstract class ExprSubquery : Operator.Expr { +internal class ExprSubquery(input: Operator.Relation, constructor: Operator.Expr) : Operator.Expr { - abstract val constructor: Operator.Expr - abstract val input: Operator.Relation + // DO NOT USE FINAL + private var _input = input + private var _constructor = constructor - internal class Row( - override val constructor: Operator.Expr, - override val input: Operator.Relation, - ) : ExprSubquery() { - - @PartiQLValueExperimental - override fun eval(env: Environment): Datum { - val tuple = getFirst(env) ?: return Datum.nullValue() - val values = IteratorSupplier { tuple.fields }.map { it.value } - return Datum.list(values) - } + private companion object { + @JvmStatic + private val STRUCT = PType.struct() } - internal class Scalar( - override val constructor: Operator.Expr, - override val input: Operator.Relation, - ) : ExprSubquery() { - - @PartiQLValueExperimental - override fun eval(env: Environment): Datum { - val tuple = getFirst(env) ?: return Datum.nullValue() - val values = tuple.fields.asSequence().map { it.value }.iterator() - if (values.hasNext().not()) { - throw TypeCheckException() - } - val singleValue = values.next() - if (values.hasNext()) { - throw TypeCheckException() - } - return singleValue + /** + * TODO simplify + */ + override fun eval(env: Environment): Datum { + val tuple = getFirst(env) ?: return Datum.nullValue() + val values = tuple.fields.asSequence().map { it.value }.iterator() + if (values.hasNext().not()) { + throw TypeCheckException() + } + val singleValue = values.next() + if (values.hasNext()) { + throw TypeCheckException() } + return singleValue } /** - * This grabs the first row of the [input], asserts that the [constructor] evaluates to a TUPLE, and returns the + * This grabs the first row of the input, asserts that the constructor evaluates to a TUPLE, and returns the * constructed value. * - * @return the constructed [constructor]. Returns null when no rows are returned from the [input]. - * @throws CardinalityViolation when more than one row is returned from the [input]. - * @throws TypeCheckException when the constructor is not a [PartiQLValueType.STRUCT]. + * @return the constructed constructor. Returns null when no rows are returned from the input. + * @throws CardinalityViolation when more than one row is returned from the input. + * @throws TypeCheckException when the constructor is not a struct. */ - @OptIn(PartiQLValueExperimental::class) - fun getFirst(env: Environment): Datum? { - input.open(env) - if (input.hasNext().not()) { - input.close() + private fun getFirst(env: Environment): Datum? { + _input.open(env) + if (_input.hasNext().not()) { + _input.close() return null } - val firstRecord = input.next() - val tuple = constructor.eval(env.push(firstRecord)).check(PartiQLValueType.STRUCT) - if (input.hasNext()) { - input.close() + val firstRecord = _input.next() + val tuple = _constructor.eval(env.push(firstRecord)).check(STRUCT) + if (_input.hasNext()) { + _input.close() throw CardinalityViolation() } - input.close() + _input.close() return tuple } } diff --git a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rex/ExprSubqueryRow.kt b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rex/ExprSubqueryRow.kt new file mode 100644 index 0000000000..e97e88c038 --- /dev/null +++ b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rex/ExprSubqueryRow.kt @@ -0,0 +1,50 @@ +package org.partiql.eval.internal.operator.rex + +import org.partiql.errors.CardinalityViolation +import org.partiql.eval.internal.Environment +import org.partiql.eval.internal.helpers.IteratorSupplier +import org.partiql.eval.internal.helpers.ValueUtility.check +import org.partiql.eval.internal.operator.Operator +import org.partiql.eval.value.Datum +import org.partiql.types.PType + +/** + * TODO REMOVE ME AFTER FIXING SUBQUERIES. + */ +internal class ExprSubqueryRow(input: Operator.Relation, constructor: Operator.Expr) : Operator.Expr { + + // DO NOT USE FINAL + private var _input = input + private var _constructor = constructor + + private companion object { + + @JvmStatic + private val STRUCT = PType.struct() + } + + override fun eval(env: Environment): Datum { + val tuple = getFirst(env) ?: return Datum.nullValue() + val values = IteratorSupplier { tuple.fields }.map { it.value } + return Datum.list(values) + } + + /** + * @See [ExprSubquery.getFirst] + */ + private fun getFirst(env: Environment): Datum? { + _input.open(env) + if (_input.hasNext().not()) { + _input.close() + return null + } + val firstRecord = _input.next() + val tuple = _constructor.eval(env.push(firstRecord)).check(STRUCT) + if (_input.hasNext()) { + _input.close() + throw CardinalityViolation() + } + _input.close() + return tuple + } +} diff --git a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rex/ExprVar.kt b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rex/ExprVar.kt new file mode 100644 index 0000000000..78bc5f222a --- /dev/null +++ b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rex/ExprVar.kt @@ -0,0 +1,28 @@ +package org.partiql.eval.internal.operator.rex + +import org.partiql.eval.internal.Environment +import org.partiql.eval.internal.operator.Operator +import org.partiql.eval.value.Datum + +/** + * Implementation for variable lookup; walks up environments if necessary, otherwise lookup using tuple offset. + */ +internal class ExprVar(depth: Int, offset: Int) : Operator.Expr { + + // DO NOT USE FINAL + private var _depth = depth + private var _offset = offset + + override fun eval(env: Environment): Datum { + // shortcut for depth 0 + if (_depth == 0) { + return env[_offset] + } + // walk up environments + var curr = env + repeat(_depth) { + curr = curr.next() ?: error("We ran out of environments for depth ($_depth) and env: $env.") + } + return curr.getOrNull(_offset) ?: error("The env doesn't have a variable for depth/offset ($_depth/$_offset) and env: $env. Current is: $curr.") + } +} diff --git a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rex/ExprVarLocal.kt b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rex/ExprVarLocal.kt deleted file mode 100644 index 7ddad207fa..0000000000 --- a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rex/ExprVarLocal.kt +++ /dev/null @@ -1,19 +0,0 @@ -package org.partiql.eval.internal.operator.rex - -import org.partiql.eval.internal.Environment -import org.partiql.eval.internal.operator.Operator -import org.partiql.eval.value.Datum -import org.partiql.value.PartiQLValueExperimental - -/** - * Returns the value in the given record index. - */ -internal class ExprVarLocal( - private val ref: Int, -) : Operator.Expr { - - @PartiQLValueExperimental - override fun eval(env: Environment): Datum { - return env[ref] - } -} diff --git a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rex/ExprVarOuter.kt b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rex/ExprVarOuter.kt deleted file mode 100644 index a8e6698e97..0000000000 --- a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/operator/rex/ExprVarOuter.kt +++ /dev/null @@ -1,24 +0,0 @@ -package org.partiql.eval.internal.operator.rex - -import org.partiql.eval.internal.Environment -import org.partiql.eval.internal.operator.Operator -import org.partiql.eval.value.Datum -import org.partiql.value.PartiQLValueExperimental - -/** - * Returns the appropriate value from the stack. - */ -internal class ExprVarOuter( - private val depth: Int, - private val reference: Int, -) : Operator.Expr { - - @PartiQLValueExperimental - override fun eval(env: Environment): Datum { - var current = env - repeat(depth) { - current = current.next() ?: error("We ran out of environments for depth ($depth) and env: $env.") - } - return current.getOrNull(reference) ?: error("The env doesn't have a variable for depth/ref ($depth/$reference) and env: $env. Current is: $current.") - } -} diff --git a/partiql-eval/src/main/kotlin/org/partiql/eval/internal/statement/QueryStatement.kt b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/statement/QueryStatement.kt new file mode 100644 index 0000000000..33dcbde491 --- /dev/null +++ b/partiql-eval/src/main/kotlin/org/partiql/eval/internal/statement/QueryStatement.kt @@ -0,0 +1,21 @@ +package org.partiql.eval.internal.statement + +import org.partiql.eval.PartiQLResult +import org.partiql.eval.PartiQLStatement +import org.partiql.eval.internal.Environment +import org.partiql.eval.internal.operator.Operator +import org.partiql.planner.catalog.Session +import org.partiql.value.PartiQLValueExperimental + +internal class QueryStatement(root: Operator.Expr) : PartiQLStatement { + + // DO NOT USE FINAL + private var _root = root + + @OptIn(PartiQLValueExperimental::class) + override fun execute(session: Session): PartiQLResult { + val datum = _root.eval(Environment.empty) + val value = PartiQLResult.Value(datum.toPartiQLValue()) + return value + } +} diff --git a/partiql-eval/src/test/kotlin/org/partiql/eval/internal/PartiQLEngineDefaultTest.kt b/partiql-eval/src/test/kotlin/org/partiql/eval/internal/PartiQLEngineDefaultTest.kt index 6069fb9c0d..ccd597c78c 100644 --- a/partiql-eval/src/test/kotlin/org/partiql/eval/internal/PartiQLEngineDefaultTest.kt +++ b/partiql-eval/src/test/kotlin/org/partiql/eval/internal/PartiQLEngineDefaultTest.kt @@ -11,11 +11,11 @@ import org.junit.jupiter.params.provider.MethodSource import org.partiql.eval.PartiQLEngine import org.partiql.eval.PartiQLResult import org.partiql.parser.PartiQLParser -import org.partiql.plan.PartiQLPlan -import org.partiql.plan.debug.PlanPrinter +import org.partiql.plan.v1.PartiQLPlan import org.partiql.planner.builder.PartiQLPlannerBuilder import org.partiql.planner.catalog.Name import org.partiql.planner.catalog.Session +import org.partiql.planner.internal.SqlPlannerV1 import org.partiql.plugins.memory.MemoryConnector import org.partiql.plugins.memory.MemoryTable import org.partiql.types.PType @@ -42,7 +42,7 @@ import java.math.BigInteger import kotlin.test.assertNotNull /** - * This holds sanity tests during the development of the [PartiQLEngine.default] implementation. + * This holds sanity tests during the development of the [PartiQLEngine.standard] implementation. */ @OptIn(PartiQLValueExperimental::class) class PartiQLEngineDefaultTest { @@ -1278,18 +1278,19 @@ class PartiQLEngineDefaultTest { .catalog("memory") .catalogs(connector.getCatalog()) .build() - val plan = planner.plan(statement, session) - val prepared = engine.prepare(plan.plan, PartiQLEngine.Session(mapOf("memory" to connector), mode = mode)) - val result = when (val returned = engine.execute(prepared)) { + val plan = SqlPlannerV1.plan(statement, session) + val stmt = engine.prepare(plan, mode, session) + val result = when (val returned = stmt.execute(session)) { is PartiQLResult.Value -> returned is PartiQLResult.Error -> { - PlanPrinter.append(System.err, plan.plan) + // TODO pretty-print V1 plans + System.err.append(plan.toString()) throw returned.cause } } val output = result.value assert(expected == output) { - comparisonString(expected, output, plan.plan) + comparisonString(expected, output, plan) } } @@ -1299,7 +1300,8 @@ class PartiQLEngineDefaultTest { val expectedWriter = PartiQLValueIonWriterBuilder.standardIonTextBuilder().build(expectedBuffer) expectedWriter.append(expected) return buildString { - PlanPrinter.append(this, plan) + // TODO pretty-print V1 plans! + appendLine(plan) appendLine("Expected : $expectedBuffer") expectedBuffer.reset() expectedWriter.append(actual) @@ -1329,7 +1331,8 @@ class PartiQLEngineDefaultTest { } catch (t: Throwable) { val str = buildString { appendLine("Test Name: $name") - PlanPrinter.append(this, permissiveResult.second) + // TODO pretty-print V1 plans! + appendLine(permissiveResult.second) } throw RuntimeException(str, t) } @@ -1355,14 +1358,15 @@ class PartiQLEngineDefaultTest { .catalog("memory") .catalogs(connector.getCatalog()) .build() - val plan = planner.plan(statement, session) - val prepared = engine.prepare(plan.plan, PartiQLEngine.Session(mapOf("memory" to connector), mode = mode)) - when (val result = engine.execute(prepared)) { - is PartiQLResult.Value -> return result.value to plan.plan + val plan = SqlPlannerV1.plan(statement, session) + val stmt = engine.prepare(plan, mode, session) + when (val result = stmt.execute(session)) { + is PartiQLResult.Value -> return result.value to plan is PartiQLResult.Error -> { val str = buildString { appendLine("Execution resulted in an unexpected error. Plan:") - PlanPrinter.append(this, plan.plan) + // TODO pretty-print V1 plans! + appendLine(plan) } throw RuntimeException(str, result.cause) } @@ -1375,7 +1379,8 @@ class PartiQLEngineDefaultTest { val expectedWriter = PartiQLValueIonWriterBuilder.standardIonTextBuilder().build(expectedBuffer) expectedWriter.append(expected) return buildString { - PlanPrinter.append(this, plan) + // TODO pretty-print V1 plans! + appendLine(plan) appendLine("Expected : $expectedBuffer") expectedBuffer.reset() expectedWriter.append(actual) diff --git a/partiql-eval/src/test/kotlin/org/partiql/eval/internal/operator/rex/ExprCallDynamicTest.kt b/partiql-eval/src/test/kotlin/org/partiql/eval/internal/operator/rex/ExprCallDynamicTest.kt index 37441f71a9..bd547f8446 100644 --- a/partiql-eval/src/test/kotlin/org/partiql/eval/internal/operator/rex/ExprCallDynamicTest.kt +++ b/partiql-eval/src/test/kotlin/org/partiql/eval/internal/operator/rex/ExprCallDynamicTest.kt @@ -38,7 +38,7 @@ class ExprCallDynamicTest { val expr = ExprCallDynamic( name = "example_function", candidateFns = candidates, - args = arrayOf(ExprLiteral(lhs), ExprLiteral(rhs)), + args = arrayOf(ExprLit(lhs), ExprLit(rhs)), ) val result = expr.eval(Environment.empty).check(PartiQLValueType.INT32) assertEquals(expectedIndex, result.int) diff --git a/partiql-plan/api/partiql-plan.api b/partiql-plan/api/partiql-plan.api index 807de9293a..a1812c735c 100644 --- a/partiql-plan/api/partiql-plan.api +++ b/partiql-plan/api/partiql-plan.api @@ -2501,6 +2501,11 @@ public abstract interface class org/partiql/plan/v1/PartiQLPlan { public abstract interface class org/partiql/plan/v1/Schema { public abstract fun getField (Ljava/lang/String;)Lorg/partiql/types/Field; public abstract fun getFields ()Ljava/util/List; + public abstract fun getSize ()I +} + +public final class org/partiql/plan/v1/Schema$DefaultImpls { + public static fun getSize (Lorg/partiql/plan/v1/Schema;)I } public abstract interface class org/partiql/plan/v1/Statement { @@ -2518,6 +2523,7 @@ public abstract interface class org/partiql/plan/v1/builder/PlanFactory { public static final field Companion Lorg/partiql/plan/v1/builder/PlanFactory$Companion; public static fun getSTANDARD ()Lorg/partiql/plan/v1/builder/PlanFactory; public abstract fun relAggregate (Lorg/partiql/plan/v1/operator/rel/Rel;Ljava/util/List;Ljava/util/List;)Lorg/partiql/plan/v1/operator/rel/RelAggregate; + public abstract fun relAggregateCall (Lorg/partiql/spi/fn/Agg;Ljava/util/List;Z)Lorg/partiql/plan/v1/operator/rel/RelAggregateCall; public abstract fun relCorrelate (Lorg/partiql/plan/v1/operator/rel/Rel;Lorg/partiql/plan/v1/operator/rel/Rel;)Lorg/partiql/plan/v1/operator/rel/RelCorrelate; public abstract fun relCorrelate (Lorg/partiql/plan/v1/operator/rel/Rel;Lorg/partiql/plan/v1/operator/rel/Rel;Lorg/partiql/plan/v1/operator/rel/RelJoinType;)Lorg/partiql/plan/v1/operator/rel/RelCorrelate; public abstract fun relDistinct (Lorg/partiql/plan/v1/operator/rel/Rel;)Lorg/partiql/plan/v1/operator/rel/RelDistinct; @@ -2529,7 +2535,7 @@ public abstract interface class org/partiql/plan/v1/builder/PlanFactory { public abstract fun relIntersect (Lorg/partiql/plan/v1/operator/rel/Rel;Lorg/partiql/plan/v1/operator/rel/Rel;Z)Lorg/partiql/plan/v1/operator/rel/RelIntersect; public abstract fun relIterate (Lorg/partiql/plan/v1/operator/rex/Rex;)Lorg/partiql/plan/v1/operator/rel/RelIterate; public abstract fun relJoin (Lorg/partiql/plan/v1/operator/rel/Rel;Lorg/partiql/plan/v1/operator/rel/Rel;)Lorg/partiql/plan/v1/operator/rel/RelJoin; - public abstract fun relJoin (Lorg/partiql/plan/v1/operator/rel/Rel;Lorg/partiql/plan/v1/operator/rel/Rel;Lorg/partiql/plan/v1/operator/rex/Rex;Lorg/partiql/plan/v1/operator/rel/RelJoinType;)Lorg/partiql/plan/v1/operator/rel/RelJoin; + public abstract fun relJoin (Lorg/partiql/plan/v1/operator/rel/Rel;Lorg/partiql/plan/v1/operator/rel/Rel;Lorg/partiql/plan/v1/operator/rex/Rex;Lorg/partiql/plan/v1/operator/rel/RelJoinType;Lorg/partiql/plan/v1/Schema;Lorg/partiql/plan/v1/Schema;)Lorg/partiql/plan/v1/operator/rel/RelJoin; public abstract fun relLimit (Lorg/partiql/plan/v1/operator/rel/Rel;Lorg/partiql/plan/v1/operator/rex/Rex;)Lorg/partiql/plan/v1/operator/rel/RelLimit; public abstract fun relOffset (Lorg/partiql/plan/v1/operator/rel/Rel;Lorg/partiql/plan/v1/operator/rex/Rex;)Lorg/partiql/plan/v1/operator/rel/RelOffset; public abstract fun relProject (Lorg/partiql/plan/v1/operator/rel/Rel;Ljava/util/List;)Lorg/partiql/plan/v1/operator/rel/RelProject; @@ -2540,26 +2546,31 @@ public abstract interface class org/partiql/plan/v1/builder/PlanFactory { public abstract fun relUnpivot (Lorg/partiql/plan/v1/operator/rex/Rex;)Lorg/partiql/plan/v1/operator/rel/RelUnpivot; public abstract fun rexArray (Ljava/util/Collection;)Lorg/partiql/plan/v1/operator/rex/RexArray; public abstract fun rexBag (Ljava/util/Collection;)Lorg/partiql/plan/v1/operator/rex/RexBag; - public abstract fun rexCall (Lorg/partiql/spi/fn/Fn;Ljava/util/List;)Lorg/partiql/plan/v1/operator/rex/RexCall; + public abstract fun rexCall (Ljava/util/List;Ljava/util/List;)Lorg/partiql/plan/v1/operator/rex/RexCallDynamic; + public abstract fun rexCall (Lorg/partiql/spi/fn/Fn;Ljava/util/List;)Lorg/partiql/plan/v1/operator/rex/RexCallStatic; public abstract fun rexCase (Ljava/util/List;Lorg/partiql/plan/v1/operator/rex/Rex;)Lorg/partiql/plan/v1/operator/rex/RexCase; public abstract fun rexCase (Lorg/partiql/plan/v1/operator/rex/Rex;Ljava/util/List;Lorg/partiql/plan/v1/operator/rex/Rex;)Lorg/partiql/plan/v1/operator/rex/RexCase; public abstract fun rexCast (Lorg/partiql/plan/v1/operator/rex/Rex;Lorg/partiql/types/PType;)Lorg/partiql/plan/v1/operator/rex/RexCast; public abstract fun rexCoalesce (Ljava/util/List;)Lorg/partiql/plan/v1/operator/rex/RexCoalesce; - public abstract fun rexCol (II)Lorg/partiql/plan/v1/operator/rex/RexVar; public abstract fun rexError (Ljava/lang/String;Ljava/util/List;)Lorg/partiql/plan/v1/operator/rex/RexError; public abstract fun rexLit (Lorg/partiql/eval/value/Datum;)Lorg/partiql/plan/v1/operator/rex/RexLit; public abstract fun rexMissing (Ljava/lang/String;Ljava/util/List;)Lorg/partiql/plan/v1/operator/rex/RexMissing; + public abstract fun rexNullIf (Lorg/partiql/plan/v1/operator/rex/Rex;Lorg/partiql/plan/v1/operator/rex/Rex;)Lorg/partiql/plan/v1/operator/rex/RexNullIf; + public abstract fun rexPathIndex (Lorg/partiql/plan/v1/operator/rex/Rex;Lorg/partiql/plan/v1/operator/rex/Rex;)Lorg/partiql/plan/v1/operator/rex/RexPathIndex; + public abstract fun rexPathKey (Lorg/partiql/plan/v1/operator/rex/Rex;Lorg/partiql/plan/v1/operator/rex/Rex;)Lorg/partiql/plan/v1/operator/rex/RexPathKey; + public abstract fun rexPathSymbol (Lorg/partiql/plan/v1/operator/rex/Rex;Ljava/lang/String;)Lorg/partiql/plan/v1/operator/rex/RexPathSymbol; public abstract fun rexPivot (Lorg/partiql/plan/v1/operator/rel/Rel;Lorg/partiql/plan/v1/operator/rex/Rex;Lorg/partiql/plan/v1/operator/rex/Rex;)Lorg/partiql/plan/v1/operator/rex/RexPivot; public abstract fun rexSelect (Lorg/partiql/plan/v1/operator/rel/Rel;Lorg/partiql/plan/v1/operator/rex/Rex;)Lorg/partiql/plan/v1/operator/rex/RexSelect; public abstract fun rexSpread (Ljava/util/List;)Lorg/partiql/plan/v1/operator/rex/RexSpread; public abstract fun rexStruct (Ljava/util/List;)Lorg/partiql/plan/v1/operator/rex/RexStruct; - public abstract fun rexSubquery (Lorg/partiql/plan/v1/operator/rel/Rel;)Lorg/partiql/plan/v1/operator/rex/RexSubquery; + public abstract fun rexSubquery (Lorg/partiql/plan/v1/operator/rel/Rel;Lorg/partiql/plan/v1/operator/rex/Rex;Z)Lorg/partiql/plan/v1/operator/rex/RexSubquery; public abstract fun rexSubqueryComp (Ljava/util/List;Lorg/partiql/plan/v1/operator/rex/RexSubqueryComp$Comp;Lorg/partiql/plan/v1/operator/rel/Rel;)Lorg/partiql/plan/v1/operator/rex/RexSubqueryComp; public abstract fun rexSubqueryComp (Ljava/util/List;Lorg/partiql/plan/v1/operator/rex/RexSubqueryComp$Comp;Lorg/partiql/plan/v1/operator/rex/RexSubqueryComp$Quantifier;Lorg/partiql/plan/v1/operator/rel/Rel;)Lorg/partiql/plan/v1/operator/rex/RexSubqueryComp; public abstract fun rexSubqueryIn (Ljava/util/List;Lorg/partiql/plan/v1/operator/rel/Rel;)Lorg/partiql/plan/v1/operator/rex/RexSubqueryIn; public abstract fun rexSubqueryIn (Lorg/partiql/plan/v1/operator/rex/Rex;Lorg/partiql/plan/v1/operator/rel/Rel;)Lorg/partiql/plan/v1/operator/rex/RexSubqueryIn; public abstract fun rexSubqueryTest (Lorg/partiql/plan/v1/operator/rex/RexSubqueryTest$Test;Lorg/partiql/plan/v1/operator/rel/Rel;)Lorg/partiql/plan/v1/operator/rex/RexSubqueryTest; - public abstract fun rexTable (Ljava/lang/String;Ljava/lang/String;)Lorg/partiql/plan/v1/operator/rex/RexTable; + public abstract fun rexTable (Lorg/partiql/planner/catalog/Table;)Lorg/partiql/plan/v1/operator/rex/RexTable; + public abstract fun rexVar (II)Lorg/partiql/plan/v1/operator/rex/RexVar; } public final class org/partiql/plan/v1/builder/PlanFactory$Companion { @@ -2568,6 +2579,8 @@ public final class org/partiql/plan/v1/builder/PlanFactory$Companion { public final class org/partiql/plan/v1/builder/PlanFactory$DefaultImpls { public static fun relAggregate (Lorg/partiql/plan/v1/builder/PlanFactory;Lorg/partiql/plan/v1/operator/rel/Rel;Ljava/util/List;Ljava/util/List;)Lorg/partiql/plan/v1/operator/rel/RelAggregate; + public static fun relAggregateCall (Lorg/partiql/plan/v1/builder/PlanFactory;Lorg/partiql/spi/fn/Agg;Ljava/util/List;Z)Lorg/partiql/plan/v1/operator/rel/RelAggregateCall; + public static synthetic fun relAggregateCall$default (Lorg/partiql/plan/v1/builder/PlanFactory;Lorg/partiql/spi/fn/Agg;Ljava/util/List;ZILjava/lang/Object;)Lorg/partiql/plan/v1/operator/rel/RelAggregateCall; public static fun relCorrelate (Lorg/partiql/plan/v1/builder/PlanFactory;Lorg/partiql/plan/v1/operator/rel/Rel;Lorg/partiql/plan/v1/operator/rel/Rel;)Lorg/partiql/plan/v1/operator/rel/RelCorrelate; public static fun relCorrelate (Lorg/partiql/plan/v1/builder/PlanFactory;Lorg/partiql/plan/v1/operator/rel/Rel;Lorg/partiql/plan/v1/operator/rel/Rel;Lorg/partiql/plan/v1/operator/rel/RelJoinType;)Lorg/partiql/plan/v1/operator/rel/RelCorrelate; public static fun relDistinct (Lorg/partiql/plan/v1/builder/PlanFactory;Lorg/partiql/plan/v1/operator/rel/Rel;)Lorg/partiql/plan/v1/operator/rel/RelDistinct; @@ -2579,7 +2592,8 @@ public final class org/partiql/plan/v1/builder/PlanFactory$DefaultImpls { public static fun relIntersect (Lorg/partiql/plan/v1/builder/PlanFactory;Lorg/partiql/plan/v1/operator/rel/Rel;Lorg/partiql/plan/v1/operator/rel/Rel;Z)Lorg/partiql/plan/v1/operator/rel/RelIntersect; public static fun relIterate (Lorg/partiql/plan/v1/builder/PlanFactory;Lorg/partiql/plan/v1/operator/rex/Rex;)Lorg/partiql/plan/v1/operator/rel/RelIterate; public static fun relJoin (Lorg/partiql/plan/v1/builder/PlanFactory;Lorg/partiql/plan/v1/operator/rel/Rel;Lorg/partiql/plan/v1/operator/rel/Rel;)Lorg/partiql/plan/v1/operator/rel/RelJoin; - public static fun relJoin (Lorg/partiql/plan/v1/builder/PlanFactory;Lorg/partiql/plan/v1/operator/rel/Rel;Lorg/partiql/plan/v1/operator/rel/Rel;Lorg/partiql/plan/v1/operator/rex/Rex;Lorg/partiql/plan/v1/operator/rel/RelJoinType;)Lorg/partiql/plan/v1/operator/rel/RelJoin; + public static fun relJoin (Lorg/partiql/plan/v1/builder/PlanFactory;Lorg/partiql/plan/v1/operator/rel/Rel;Lorg/partiql/plan/v1/operator/rel/Rel;Lorg/partiql/plan/v1/operator/rex/Rex;Lorg/partiql/plan/v1/operator/rel/RelJoinType;Lorg/partiql/plan/v1/Schema;Lorg/partiql/plan/v1/Schema;)Lorg/partiql/plan/v1/operator/rel/RelJoin; + public static synthetic fun relJoin$default (Lorg/partiql/plan/v1/builder/PlanFactory;Lorg/partiql/plan/v1/operator/rel/Rel;Lorg/partiql/plan/v1/operator/rel/Rel;Lorg/partiql/plan/v1/operator/rex/Rex;Lorg/partiql/plan/v1/operator/rel/RelJoinType;Lorg/partiql/plan/v1/Schema;Lorg/partiql/plan/v1/Schema;ILjava/lang/Object;)Lorg/partiql/plan/v1/operator/rel/RelJoin; public static fun relLimit (Lorg/partiql/plan/v1/builder/PlanFactory;Lorg/partiql/plan/v1/operator/rel/Rel;Lorg/partiql/plan/v1/operator/rex/Rex;)Lorg/partiql/plan/v1/operator/rel/RelLimit; public static fun relOffset (Lorg/partiql/plan/v1/builder/PlanFactory;Lorg/partiql/plan/v1/operator/rel/Rel;Lorg/partiql/plan/v1/operator/rex/Rex;)Lorg/partiql/plan/v1/operator/rel/RelOffset; public static fun relProject (Lorg/partiql/plan/v1/builder/PlanFactory;Lorg/partiql/plan/v1/operator/rel/Rel;Ljava/util/List;)Lorg/partiql/plan/v1/operator/rel/RelProject; @@ -2590,26 +2604,31 @@ public final class org/partiql/plan/v1/builder/PlanFactory$DefaultImpls { public static fun relUnpivot (Lorg/partiql/plan/v1/builder/PlanFactory;Lorg/partiql/plan/v1/operator/rex/Rex;)Lorg/partiql/plan/v1/operator/rel/RelUnpivot; public static fun rexArray (Lorg/partiql/plan/v1/builder/PlanFactory;Ljava/util/Collection;)Lorg/partiql/plan/v1/operator/rex/RexArray; public static fun rexBag (Lorg/partiql/plan/v1/builder/PlanFactory;Ljava/util/Collection;)Lorg/partiql/plan/v1/operator/rex/RexBag; - public static fun rexCall (Lorg/partiql/plan/v1/builder/PlanFactory;Lorg/partiql/spi/fn/Fn;Ljava/util/List;)Lorg/partiql/plan/v1/operator/rex/RexCall; + public static fun rexCall (Lorg/partiql/plan/v1/builder/PlanFactory;Ljava/util/List;Ljava/util/List;)Lorg/partiql/plan/v1/operator/rex/RexCallDynamic; + public static fun rexCall (Lorg/partiql/plan/v1/builder/PlanFactory;Lorg/partiql/spi/fn/Fn;Ljava/util/List;)Lorg/partiql/plan/v1/operator/rex/RexCallStatic; public static fun rexCase (Lorg/partiql/plan/v1/builder/PlanFactory;Ljava/util/List;Lorg/partiql/plan/v1/operator/rex/Rex;)Lorg/partiql/plan/v1/operator/rex/RexCase; public static fun rexCase (Lorg/partiql/plan/v1/builder/PlanFactory;Lorg/partiql/plan/v1/operator/rex/Rex;Ljava/util/List;Lorg/partiql/plan/v1/operator/rex/Rex;)Lorg/partiql/plan/v1/operator/rex/RexCase; public static fun rexCast (Lorg/partiql/plan/v1/builder/PlanFactory;Lorg/partiql/plan/v1/operator/rex/Rex;Lorg/partiql/types/PType;)Lorg/partiql/plan/v1/operator/rex/RexCast; public static fun rexCoalesce (Lorg/partiql/plan/v1/builder/PlanFactory;Ljava/util/List;)Lorg/partiql/plan/v1/operator/rex/RexCoalesce; - public static fun rexCol (Lorg/partiql/plan/v1/builder/PlanFactory;II)Lorg/partiql/plan/v1/operator/rex/RexVar; public static fun rexError (Lorg/partiql/plan/v1/builder/PlanFactory;Ljava/lang/String;Ljava/util/List;)Lorg/partiql/plan/v1/operator/rex/RexError; public static fun rexLit (Lorg/partiql/plan/v1/builder/PlanFactory;Lorg/partiql/eval/value/Datum;)Lorg/partiql/plan/v1/operator/rex/RexLit; public static fun rexMissing (Lorg/partiql/plan/v1/builder/PlanFactory;Ljava/lang/String;Ljava/util/List;)Lorg/partiql/plan/v1/operator/rex/RexMissing; + public static fun rexNullIf (Lorg/partiql/plan/v1/builder/PlanFactory;Lorg/partiql/plan/v1/operator/rex/Rex;Lorg/partiql/plan/v1/operator/rex/Rex;)Lorg/partiql/plan/v1/operator/rex/RexNullIf; + public static fun rexPathIndex (Lorg/partiql/plan/v1/builder/PlanFactory;Lorg/partiql/plan/v1/operator/rex/Rex;Lorg/partiql/plan/v1/operator/rex/Rex;)Lorg/partiql/plan/v1/operator/rex/RexPathIndex; + public static fun rexPathKey (Lorg/partiql/plan/v1/builder/PlanFactory;Lorg/partiql/plan/v1/operator/rex/Rex;Lorg/partiql/plan/v1/operator/rex/Rex;)Lorg/partiql/plan/v1/operator/rex/RexPathKey; + public static fun rexPathSymbol (Lorg/partiql/plan/v1/builder/PlanFactory;Lorg/partiql/plan/v1/operator/rex/Rex;Ljava/lang/String;)Lorg/partiql/plan/v1/operator/rex/RexPathSymbol; public static fun rexPivot (Lorg/partiql/plan/v1/builder/PlanFactory;Lorg/partiql/plan/v1/operator/rel/Rel;Lorg/partiql/plan/v1/operator/rex/Rex;Lorg/partiql/plan/v1/operator/rex/Rex;)Lorg/partiql/plan/v1/operator/rex/RexPivot; public static fun rexSelect (Lorg/partiql/plan/v1/builder/PlanFactory;Lorg/partiql/plan/v1/operator/rel/Rel;Lorg/partiql/plan/v1/operator/rex/Rex;)Lorg/partiql/plan/v1/operator/rex/RexSelect; public static fun rexSpread (Lorg/partiql/plan/v1/builder/PlanFactory;Ljava/util/List;)Lorg/partiql/plan/v1/operator/rex/RexSpread; public static fun rexStruct (Lorg/partiql/plan/v1/builder/PlanFactory;Ljava/util/List;)Lorg/partiql/plan/v1/operator/rex/RexStruct; - public static fun rexSubquery (Lorg/partiql/plan/v1/builder/PlanFactory;Lorg/partiql/plan/v1/operator/rel/Rel;)Lorg/partiql/plan/v1/operator/rex/RexSubquery; + public static fun rexSubquery (Lorg/partiql/plan/v1/builder/PlanFactory;Lorg/partiql/plan/v1/operator/rel/Rel;Lorg/partiql/plan/v1/operator/rex/Rex;Z)Lorg/partiql/plan/v1/operator/rex/RexSubquery; public static fun rexSubqueryComp (Lorg/partiql/plan/v1/builder/PlanFactory;Ljava/util/List;Lorg/partiql/plan/v1/operator/rex/RexSubqueryComp$Comp;Lorg/partiql/plan/v1/operator/rel/Rel;)Lorg/partiql/plan/v1/operator/rex/RexSubqueryComp; public static fun rexSubqueryComp (Lorg/partiql/plan/v1/builder/PlanFactory;Ljava/util/List;Lorg/partiql/plan/v1/operator/rex/RexSubqueryComp$Comp;Lorg/partiql/plan/v1/operator/rex/RexSubqueryComp$Quantifier;Lorg/partiql/plan/v1/operator/rel/Rel;)Lorg/partiql/plan/v1/operator/rex/RexSubqueryComp; public static fun rexSubqueryIn (Lorg/partiql/plan/v1/builder/PlanFactory;Ljava/util/List;Lorg/partiql/plan/v1/operator/rel/Rel;)Lorg/partiql/plan/v1/operator/rex/RexSubqueryIn; public static fun rexSubqueryIn (Lorg/partiql/plan/v1/builder/PlanFactory;Lorg/partiql/plan/v1/operator/rex/Rex;Lorg/partiql/plan/v1/operator/rel/Rel;)Lorg/partiql/plan/v1/operator/rex/RexSubqueryIn; public static fun rexSubqueryTest (Lorg/partiql/plan/v1/builder/PlanFactory;Lorg/partiql/plan/v1/operator/rex/RexSubqueryTest$Test;Lorg/partiql/plan/v1/operator/rel/Rel;)Lorg/partiql/plan/v1/operator/rex/RexSubqueryTest; - public static fun rexTable (Lorg/partiql/plan/v1/builder/PlanFactory;Ljava/lang/String;Ljava/lang/String;)Lorg/partiql/plan/v1/operator/rex/RexTable; + public static fun rexTable (Lorg/partiql/plan/v1/builder/PlanFactory;Lorg/partiql/planner/catalog/Table;)Lorg/partiql/plan/v1/operator/rex/RexTable; + public static fun rexVar (Lorg/partiql/plan/v1/builder/PlanFactory;II)Lorg/partiql/plan/v1/operator/rex/RexVar; } public final class org/partiql/plan/v1/builder/RelBuilder { @@ -2714,9 +2733,8 @@ public final class org/partiql/plan/v1/operator/rel/RelAggregate$DefaultImpls { } public abstract interface class org/partiql/plan/v1/operator/rel/RelAggregateCall { + public abstract fun getAgg ()Lorg/partiql/spi/fn/Agg; public abstract fun getArgs ()Ljava/util/List; - public abstract fun getName ()Ljava/lang/String; - public abstract fun getType ()Lorg/partiql/types/PType; public abstract fun isDistinct ()Z } @@ -2810,30 +2828,55 @@ public final class org/partiql/plan/v1/operator/rel/RelExclude$DefaultImpls { public static fun isOrdered (Lorg/partiql/plan/v1/operator/rel/RelExclude;)Z } -public abstract interface class org/partiql/plan/v1/operator/rel/RelExcludePath { - public abstract fun getRoot ()Lorg/partiql/plan/v1/operator/rex/RexVar; - public abstract fun getSteps ()Lorg/partiql/plan/v1/operator/rel/RelExcludeStep; +public abstract interface class org/partiql/plan/v1/operator/rel/RelExcludeCollectionWildcard : org/partiql/plan/v1/operator/rel/RelExcludeStep { } -public abstract interface class org/partiql/plan/v1/operator/rel/RelExcludeStep { - public abstract fun getSubsteps ()Ljava/util/List; +public abstract interface class org/partiql/plan/v1/operator/rel/RelExcludeIndex : org/partiql/plan/v1/operator/rel/RelExcludeStep { + public abstract fun getIndex ()I } -public abstract interface class org/partiql/plan/v1/operator/rel/RelExcludeStep$CollectionWildcard : org/partiql/plan/v1/operator/rel/RelExcludeStep { +public abstract interface class org/partiql/plan/v1/operator/rel/RelExcludeKey : org/partiql/plan/v1/operator/rel/RelExcludeStep { + public abstract fun getKey ()Ljava/lang/String; } -public abstract interface class org/partiql/plan/v1/operator/rel/RelExcludeStep$Index : org/partiql/plan/v1/operator/rel/RelExcludeStep { - public abstract fun getIndex ()I +public abstract interface class org/partiql/plan/v1/operator/rel/RelExcludePath { + public static final field Companion Lorg/partiql/plan/v1/operator/rel/RelExcludePath$Companion; + public abstract fun getRoot ()Lorg/partiql/plan/v1/operator/rex/RexVar; + public abstract fun getSteps ()Ljava/util/Collection; + public static fun of (Lorg/partiql/plan/v1/operator/rex/RexVar;Ljava/util/Collection;)Lorg/partiql/plan/v1/operator/rel/RelExcludePath; } -public abstract interface class org/partiql/plan/v1/operator/rel/RelExcludeStep$Key : org/partiql/plan/v1/operator/rel/RelExcludeStep { - public abstract fun getKey ()Ljava/lang/String; +public final class org/partiql/plan/v1/operator/rel/RelExcludePath$Companion { + public final fun of (Lorg/partiql/plan/v1/operator/rex/RexVar;Ljava/util/Collection;)Lorg/partiql/plan/v1/operator/rel/RelExcludePath; +} + +public abstract interface class org/partiql/plan/v1/operator/rel/RelExcludeStep { + public static final field Companion Lorg/partiql/plan/v1/operator/rel/RelExcludeStep$Companion; + public static fun collection (Ljava/util/List;)Lorg/partiql/plan/v1/operator/rel/RelExcludeCollectionWildcard; + public abstract fun getSubsteps ()Ljava/util/List; + public static fun index (ILjava/util/List;)Lorg/partiql/plan/v1/operator/rel/RelExcludeIndex; + public static fun key (Ljava/lang/String;Ljava/util/List;)Lorg/partiql/plan/v1/operator/rel/RelExcludeKey; + public static fun struct (Ljava/util/List;)Lorg/partiql/plan/v1/operator/rel/RelExcludeStructWildcard; + public static fun symbol (Ljava/lang/String;Ljava/util/List;)Lorg/partiql/plan/v1/operator/rel/RelExcludeSymbol; } -public abstract interface class org/partiql/plan/v1/operator/rel/RelExcludeStep$StructWildcard : org/partiql/plan/v1/operator/rel/RelExcludeStep { +public final class org/partiql/plan/v1/operator/rel/RelExcludeStep$Companion { + public final fun collection (Ljava/util/List;)Lorg/partiql/plan/v1/operator/rel/RelExcludeCollectionWildcard; + public static synthetic fun collection$default (Lorg/partiql/plan/v1/operator/rel/RelExcludeStep$Companion;Ljava/util/List;ILjava/lang/Object;)Lorg/partiql/plan/v1/operator/rel/RelExcludeCollectionWildcard; + public final fun index (ILjava/util/List;)Lorg/partiql/plan/v1/operator/rel/RelExcludeIndex; + public static synthetic fun index$default (Lorg/partiql/plan/v1/operator/rel/RelExcludeStep$Companion;ILjava/util/List;ILjava/lang/Object;)Lorg/partiql/plan/v1/operator/rel/RelExcludeIndex; + public final fun key (Ljava/lang/String;Ljava/util/List;)Lorg/partiql/plan/v1/operator/rel/RelExcludeKey; + public static synthetic fun key$default (Lorg/partiql/plan/v1/operator/rel/RelExcludeStep$Companion;Ljava/lang/String;Ljava/util/List;ILjava/lang/Object;)Lorg/partiql/plan/v1/operator/rel/RelExcludeKey; + public final fun struct (Ljava/util/List;)Lorg/partiql/plan/v1/operator/rel/RelExcludeStructWildcard; + public static synthetic fun struct$default (Lorg/partiql/plan/v1/operator/rel/RelExcludeStep$Companion;Ljava/util/List;ILjava/lang/Object;)Lorg/partiql/plan/v1/operator/rel/RelExcludeStructWildcard; + public final fun symbol (Ljava/lang/String;Ljava/util/List;)Lorg/partiql/plan/v1/operator/rel/RelExcludeSymbol; + public static synthetic fun symbol$default (Lorg/partiql/plan/v1/operator/rel/RelExcludeStep$Companion;Ljava/lang/String;Ljava/util/List;ILjava/lang/Object;)Lorg/partiql/plan/v1/operator/rel/RelExcludeSymbol; } -public abstract interface class org/partiql/plan/v1/operator/rel/RelExcludeStep$Symbol : org/partiql/plan/v1/operator/rel/RelExcludeStep { +public abstract interface class org/partiql/plan/v1/operator/rel/RelExcludeStructWildcard : org/partiql/plan/v1/operator/rel/RelExcludeStep { +} + +public abstract interface class org/partiql/plan/v1/operator/rel/RelExcludeSymbol : org/partiql/plan/v1/operator/rel/RelExcludeStep { public abstract fun getSymbol ()Ljava/lang/String; } @@ -2887,7 +2930,9 @@ public abstract interface class org/partiql/plan/v1/operator/rel/RelJoin : org/p public abstract fun getCondition ()Lorg/partiql/plan/v1/operator/rex/Rex; public abstract fun getJoinType ()Lorg/partiql/plan/v1/operator/rel/RelJoinType; public abstract fun getLeft ()Lorg/partiql/plan/v1/operator/rel/Rel; + public abstract fun getLeftSchema ()Lorg/partiql/plan/v1/Schema; public abstract fun getRight ()Lorg/partiql/plan/v1/operator/rel/Rel; + public abstract fun getRightSchema ()Lorg/partiql/plan/v1/Schema; public abstract fun isOrdered ()Z } @@ -3094,16 +3139,28 @@ public final class org/partiql/plan/v1/operator/rex/RexBag$DefaultImpls { public static fun getChildren (Lorg/partiql/plan/v1/operator/rex/RexBag;)Ljava/util/Collection; } -public abstract interface class org/partiql/plan/v1/operator/rex/RexCall : org/partiql/plan/v1/operator/rex/Rex { +public abstract interface class org/partiql/plan/v1/operator/rex/RexCallDynamic : org/partiql/plan/v1/operator/rex/Rex { + public abstract fun accept (Lorg/partiql/plan/v1/operator/rex/RexVisitor;Ljava/lang/Object;)Ljava/lang/Object; + public abstract fun getArgs ()Ljava/util/List; + public abstract fun getChildren ()Ljava/util/Collection; + public abstract fun getFunctions ()Ljava/util/List; +} + +public final class org/partiql/plan/v1/operator/rex/RexCallDynamic$DefaultImpls { + public static fun accept (Lorg/partiql/plan/v1/operator/rex/RexCallDynamic;Lorg/partiql/plan/v1/operator/rex/RexVisitor;Ljava/lang/Object;)Ljava/lang/Object; + public static fun getChildren (Lorg/partiql/plan/v1/operator/rex/RexCallDynamic;)Ljava/util/Collection; +} + +public abstract interface class org/partiql/plan/v1/operator/rex/RexCallStatic : org/partiql/plan/v1/operator/rex/Rex { public abstract fun accept (Lorg/partiql/plan/v1/operator/rex/RexVisitor;Ljava/lang/Object;)Ljava/lang/Object; public abstract fun getArgs ()Ljava/util/List; public abstract fun getChildren ()Ljava/util/Collection; public abstract fun getFunction ()Lorg/partiql/spi/fn/Fn; } -public final class org/partiql/plan/v1/operator/rex/RexCall$DefaultImpls { - public static fun accept (Lorg/partiql/plan/v1/operator/rex/RexCall;Lorg/partiql/plan/v1/operator/rex/RexVisitor;Ljava/lang/Object;)Ljava/lang/Object; - public static fun getChildren (Lorg/partiql/plan/v1/operator/rex/RexCall;)Ljava/util/Collection; +public final class org/partiql/plan/v1/operator/rex/RexCallStatic$DefaultImpls { + public static fun accept (Lorg/partiql/plan/v1/operator/rex/RexCallStatic;Lorg/partiql/plan/v1/operator/rex/RexVisitor;Ljava/lang/Object;)Ljava/lang/Object; + public static fun getChildren (Lorg/partiql/plan/v1/operator/rex/RexCallStatic;)Ljava/util/Collection; } public abstract interface class org/partiql/plan/v1/operator/rex/RexCase : org/partiql/plan/v1/operator/rex/Rex { @@ -3188,40 +3245,48 @@ public final class org/partiql/plan/v1/operator/rex/RexMissing$DefaultImpls { public static fun getType (Lorg/partiql/plan/v1/operator/rex/RexMissing;)Lorg/partiql/types/PType; } -public abstract interface class org/partiql/plan/v1/operator/rex/RexPath : org/partiql/plan/v1/operator/rex/Rex { +public abstract interface class org/partiql/plan/v1/operator/rex/RexNullIf : org/partiql/plan/v1/operator/rex/Rex { public abstract fun accept (Lorg/partiql/plan/v1/operator/rex/RexVisitor;Ljava/lang/Object;)Ljava/lang/Object; - public abstract fun getRoot ()Lorg/partiql/plan/v1/operator/rex/Rex; + public abstract fun getChildren ()Ljava/util/Collection; + public abstract fun getNullifier ()Lorg/partiql/plan/v1/operator/rex/Rex; + public abstract fun getType ()Lorg/partiql/types/PType; + public abstract fun getValue ()Lorg/partiql/plan/v1/operator/rex/Rex; } -public final class org/partiql/plan/v1/operator/rex/RexPath$DefaultImpls { - public static fun accept (Lorg/partiql/plan/v1/operator/rex/RexPath;Lorg/partiql/plan/v1/operator/rex/RexVisitor;Ljava/lang/Object;)Ljava/lang/Object; +public final class org/partiql/plan/v1/operator/rex/RexNullIf$DefaultImpls { + public static fun accept (Lorg/partiql/plan/v1/operator/rex/RexNullIf;Lorg/partiql/plan/v1/operator/rex/RexVisitor;Ljava/lang/Object;)Ljava/lang/Object; + public static fun getChildren (Lorg/partiql/plan/v1/operator/rex/RexNullIf;)Ljava/util/Collection; + public static fun getType (Lorg/partiql/plan/v1/operator/rex/RexNullIf;)Lorg/partiql/types/PType; } -public abstract interface class org/partiql/plan/v1/operator/rex/RexPath$Index : org/partiql/plan/v1/operator/rex/RexPath { +public abstract interface class org/partiql/plan/v1/operator/rex/RexPathIndex : org/partiql/plan/v1/operator/rex/Rex { public abstract fun accept (Lorg/partiql/plan/v1/operator/rex/RexVisitor;Ljava/lang/Object;)Ljava/lang/Object; public abstract fun getIndex ()Lorg/partiql/plan/v1/operator/rex/Rex; + public abstract fun getOperand ()Lorg/partiql/plan/v1/operator/rex/Rex; } -public final class org/partiql/plan/v1/operator/rex/RexPath$Index$DefaultImpls { - public static fun accept (Lorg/partiql/plan/v1/operator/rex/RexPath$Index;Lorg/partiql/plan/v1/operator/rex/RexVisitor;Ljava/lang/Object;)Ljava/lang/Object; +public final class org/partiql/plan/v1/operator/rex/RexPathIndex$DefaultImpls { + public static fun accept (Lorg/partiql/plan/v1/operator/rex/RexPathIndex;Lorg/partiql/plan/v1/operator/rex/RexVisitor;Ljava/lang/Object;)Ljava/lang/Object; } -public abstract interface class org/partiql/plan/v1/operator/rex/RexPath$Key : org/partiql/plan/v1/operator/rex/RexPath { +public abstract interface class org/partiql/plan/v1/operator/rex/RexPathKey : org/partiql/plan/v1/operator/rex/Rex { public abstract fun accept (Lorg/partiql/plan/v1/operator/rex/RexVisitor;Ljava/lang/Object;)Ljava/lang/Object; public abstract fun getKey ()Lorg/partiql/plan/v1/operator/rex/Rex; + public abstract fun getOperand ()Lorg/partiql/plan/v1/operator/rex/Rex; } -public final class org/partiql/plan/v1/operator/rex/RexPath$Key$DefaultImpls { - public static fun accept (Lorg/partiql/plan/v1/operator/rex/RexPath$Key;Lorg/partiql/plan/v1/operator/rex/RexVisitor;Ljava/lang/Object;)Ljava/lang/Object; +public final class org/partiql/plan/v1/operator/rex/RexPathKey$DefaultImpls { + public static fun accept (Lorg/partiql/plan/v1/operator/rex/RexPathKey;Lorg/partiql/plan/v1/operator/rex/RexVisitor;Ljava/lang/Object;)Ljava/lang/Object; } -public abstract interface class org/partiql/plan/v1/operator/rex/RexPath$Symbol : org/partiql/plan/v1/operator/rex/RexPath { +public abstract interface class org/partiql/plan/v1/operator/rex/RexPathSymbol : org/partiql/plan/v1/operator/rex/Rex { public abstract fun accept (Lorg/partiql/plan/v1/operator/rex/RexVisitor;Ljava/lang/Object;)Ljava/lang/Object; + public abstract fun getOperand ()Lorg/partiql/plan/v1/operator/rex/Rex; public abstract fun getSymbol ()Ljava/lang/String; } -public final class org/partiql/plan/v1/operator/rex/RexPath$Symbol$DefaultImpls { - public static fun accept (Lorg/partiql/plan/v1/operator/rex/RexPath$Symbol;Lorg/partiql/plan/v1/operator/rex/RexVisitor;Ljava/lang/Object;)Ljava/lang/Object; +public final class org/partiql/plan/v1/operator/rex/RexPathSymbol$DefaultImpls { + public static fun accept (Lorg/partiql/plan/v1/operator/rex/RexPathSymbol;Lorg/partiql/plan/v1/operator/rex/RexVisitor;Ljava/lang/Object;)Ljava/lang/Object; } public abstract interface class org/partiql/plan/v1/operator/rex/RexPivot : org/partiql/plan/v1/operator/rex/Rex { @@ -3286,6 +3351,8 @@ public abstract interface class org/partiql/plan/v1/operator/rex/RexStruct$Field public abstract interface class org/partiql/plan/v1/operator/rex/RexSubquery : org/partiql/plan/v1/operator/rex/Rex { public abstract fun accept (Lorg/partiql/plan/v1/operator/rex/RexVisitor;Ljava/lang/Object;)Ljava/lang/Object; + public abstract fun asScalar ()Z + public abstract fun getConstructor ()Lorg/partiql/plan/v1/operator/rex/Rex; public abstract fun getRel ()Lorg/partiql/plan/v1/operator/rel/Rel; } @@ -3356,9 +3423,8 @@ public final class org/partiql/plan/v1/operator/rex/RexSubqueryTest$Test : java/ public abstract interface class org/partiql/plan/v1/operator/rex/RexTable : org/partiql/plan/v1/operator/rex/Rex { public abstract fun accept (Lorg/partiql/plan/v1/operator/rex/RexVisitor;Ljava/lang/Object;)Ljava/lang/Object; - public abstract fun getCatalog ()Ljava/lang/String; public abstract fun getChildren ()Ljava/util/Collection; - public abstract fun getName ()Ljava/lang/String; + public abstract fun getTable ()Lorg/partiql/planner/catalog/Table; } public final class org/partiql/plan/v1/operator/rex/RexTable$DefaultImpls { @@ -3384,17 +3450,18 @@ public abstract interface class org/partiql/plan/v1/operator/rex/RexVisitor { public abstract fun visit (Lorg/partiql/plan/v1/operator/rex/Rex;Ljava/lang/Object;)Ljava/lang/Object; public abstract fun visitArray (Lorg/partiql/plan/v1/operator/rex/RexArray;Ljava/lang/Object;)Ljava/lang/Object; public abstract fun visitBag (Lorg/partiql/plan/v1/operator/rex/RexBag;Ljava/lang/Object;)Ljava/lang/Object; - public abstract fun visitCall (Lorg/partiql/plan/v1/operator/rex/RexCall;Ljava/lang/Object;)Ljava/lang/Object; + public abstract fun visitCallDynamic (Lorg/partiql/plan/v1/operator/rex/RexCallDynamic;Ljava/lang/Object;)Ljava/lang/Object; + public abstract fun visitCallStatic (Lorg/partiql/plan/v1/operator/rex/RexCallStatic;Ljava/lang/Object;)Ljava/lang/Object; public abstract fun visitCase (Lorg/partiql/plan/v1/operator/rex/RexCase;Ljava/lang/Object;)Ljava/lang/Object; public abstract fun visitCast (Lorg/partiql/plan/v1/operator/rex/RexCast;Ljava/lang/Object;)Ljava/lang/Object; public abstract fun visitCoalesce (Lorg/partiql/plan/v1/operator/rex/RexCoalesce;Ljava/lang/Object;)Ljava/lang/Object; public abstract fun visitError (Lorg/partiql/plan/v1/operator/rex/RexError;Ljava/lang/Object;)Ljava/lang/Object; public abstract fun visitLit (Lorg/partiql/plan/v1/operator/rex/RexLit;Ljava/lang/Object;)Ljava/lang/Object; public abstract fun visitMissing (Lorg/partiql/plan/v1/operator/rex/RexMissing;Ljava/lang/Object;)Ljava/lang/Object; - public abstract fun visitPath (Lorg/partiql/plan/v1/operator/rex/RexPath;Ljava/lang/Object;)Ljava/lang/Object; - public abstract fun visitPathIndex (Lorg/partiql/plan/v1/operator/rex/RexPath$Index;Ljava/lang/Object;)Ljava/lang/Object; - public abstract fun visitPathKey (Lorg/partiql/plan/v1/operator/rex/RexPath$Key;Ljava/lang/Object;)Ljava/lang/Object; - public abstract fun visitPathSymbol (Lorg/partiql/plan/v1/operator/rex/RexPath$Symbol;Ljava/lang/Object;)Ljava/lang/Object; + public abstract fun visitNullIf (Lorg/partiql/plan/v1/operator/rex/RexNullIf;Ljava/lang/Object;)Ljava/lang/Object; + public abstract fun visitPathIndex (Lorg/partiql/plan/v1/operator/rex/RexPathIndex;Ljava/lang/Object;)Ljava/lang/Object; + public abstract fun visitPathKey (Lorg/partiql/plan/v1/operator/rex/RexPathKey;Ljava/lang/Object;)Ljava/lang/Object; + public abstract fun visitPathSymbol (Lorg/partiql/plan/v1/operator/rex/RexPathSymbol;Ljava/lang/Object;)Ljava/lang/Object; public abstract fun visitPivot (Lorg/partiql/plan/v1/operator/rex/RexPivot;Ljava/lang/Object;)Ljava/lang/Object; public abstract fun visitSelect (Lorg/partiql/plan/v1/operator/rex/RexSelect;Ljava/lang/Object;)Ljava/lang/Object; public abstract fun visitSpread (Lorg/partiql/plan/v1/operator/rex/RexSpread;Ljava/lang/Object;)Ljava/lang/Object; @@ -3412,17 +3479,18 @@ public final class org/partiql/plan/v1/operator/rex/RexVisitor$DefaultImpls { public static fun visit (Lorg/partiql/plan/v1/operator/rex/RexVisitor;Lorg/partiql/plan/v1/operator/rex/Rex;Ljava/lang/Object;)Ljava/lang/Object; public static fun visitArray (Lorg/partiql/plan/v1/operator/rex/RexVisitor;Lorg/partiql/plan/v1/operator/rex/RexArray;Ljava/lang/Object;)Ljava/lang/Object; public static fun visitBag (Lorg/partiql/plan/v1/operator/rex/RexVisitor;Lorg/partiql/plan/v1/operator/rex/RexBag;Ljava/lang/Object;)Ljava/lang/Object; - public static fun visitCall (Lorg/partiql/plan/v1/operator/rex/RexVisitor;Lorg/partiql/plan/v1/operator/rex/RexCall;Ljava/lang/Object;)Ljava/lang/Object; + public static fun visitCallDynamic (Lorg/partiql/plan/v1/operator/rex/RexVisitor;Lorg/partiql/plan/v1/operator/rex/RexCallDynamic;Ljava/lang/Object;)Ljava/lang/Object; + public static fun visitCallStatic (Lorg/partiql/plan/v1/operator/rex/RexVisitor;Lorg/partiql/plan/v1/operator/rex/RexCallStatic;Ljava/lang/Object;)Ljava/lang/Object; public static fun visitCase (Lorg/partiql/plan/v1/operator/rex/RexVisitor;Lorg/partiql/plan/v1/operator/rex/RexCase;Ljava/lang/Object;)Ljava/lang/Object; public static fun visitCast (Lorg/partiql/plan/v1/operator/rex/RexVisitor;Lorg/partiql/plan/v1/operator/rex/RexCast;Ljava/lang/Object;)Ljava/lang/Object; public static fun visitCoalesce (Lorg/partiql/plan/v1/operator/rex/RexVisitor;Lorg/partiql/plan/v1/operator/rex/RexCoalesce;Ljava/lang/Object;)Ljava/lang/Object; public static fun visitError (Lorg/partiql/plan/v1/operator/rex/RexVisitor;Lorg/partiql/plan/v1/operator/rex/RexError;Ljava/lang/Object;)Ljava/lang/Object; public static fun visitLit (Lorg/partiql/plan/v1/operator/rex/RexVisitor;Lorg/partiql/plan/v1/operator/rex/RexLit;Ljava/lang/Object;)Ljava/lang/Object; public static fun visitMissing (Lorg/partiql/plan/v1/operator/rex/RexVisitor;Lorg/partiql/plan/v1/operator/rex/RexMissing;Ljava/lang/Object;)Ljava/lang/Object; - public static fun visitPath (Lorg/partiql/plan/v1/operator/rex/RexVisitor;Lorg/partiql/plan/v1/operator/rex/RexPath;Ljava/lang/Object;)Ljava/lang/Object; - public static fun visitPathIndex (Lorg/partiql/plan/v1/operator/rex/RexVisitor;Lorg/partiql/plan/v1/operator/rex/RexPath$Index;Ljava/lang/Object;)Ljava/lang/Object; - public static fun visitPathKey (Lorg/partiql/plan/v1/operator/rex/RexVisitor;Lorg/partiql/plan/v1/operator/rex/RexPath$Key;Ljava/lang/Object;)Ljava/lang/Object; - public static fun visitPathSymbol (Lorg/partiql/plan/v1/operator/rex/RexVisitor;Lorg/partiql/plan/v1/operator/rex/RexPath$Symbol;Ljava/lang/Object;)Ljava/lang/Object; + public static fun visitNullIf (Lorg/partiql/plan/v1/operator/rex/RexVisitor;Lorg/partiql/plan/v1/operator/rex/RexNullIf;Ljava/lang/Object;)Ljava/lang/Object; + public static fun visitPathIndex (Lorg/partiql/plan/v1/operator/rex/RexVisitor;Lorg/partiql/plan/v1/operator/rex/RexPathIndex;Ljava/lang/Object;)Ljava/lang/Object; + public static fun visitPathKey (Lorg/partiql/plan/v1/operator/rex/RexVisitor;Lorg/partiql/plan/v1/operator/rex/RexPathKey;Ljava/lang/Object;)Ljava/lang/Object; + public static fun visitPathSymbol (Lorg/partiql/plan/v1/operator/rex/RexVisitor;Lorg/partiql/plan/v1/operator/rex/RexPathSymbol;Ljava/lang/Object;)Ljava/lang/Object; public static fun visitPivot (Lorg/partiql/plan/v1/operator/rex/RexVisitor;Lorg/partiql/plan/v1/operator/rex/RexPivot;Ljava/lang/Object;)Ljava/lang/Object; public static fun visitSelect (Lorg/partiql/plan/v1/operator/rex/RexVisitor;Lorg/partiql/plan/v1/operator/rex/RexSelect;Ljava/lang/Object;)Ljava/lang/Object; public static fun visitSpread (Lorg/partiql/plan/v1/operator/rex/RexVisitor;Lorg/partiql/plan/v1/operator/rex/RexSpread;Ljava/lang/Object;)Ljava/lang/Object; diff --git a/partiql-plan/src/main/kotlin/org/partiql/plan/v1/Schema.kt b/partiql-plan/src/main/kotlin/org/partiql/plan/v1/Schema.kt index 67fde5bcb1..2b2d2aa0e9 100644 --- a/partiql-plan/src/main/kotlin/org/partiql/plan/v1/Schema.kt +++ b/partiql-plan/src/main/kotlin/org/partiql/plan/v1/Schema.kt @@ -7,6 +7,8 @@ import org.partiql.types.Field */ public interface Schema { + public fun getSize(): Int = getFields().size + public fun getFields(): List public fun getField(name: String): Field diff --git a/partiql-plan/src/main/kotlin/org/partiql/plan/v1/builder/PlanFactory.kt b/partiql-plan/src/main/kotlin/org/partiql/plan/v1/builder/PlanFactory.kt index 8bc01f219f..00c8ffdd44 100644 --- a/partiql-plan/src/main/kotlin/org/partiql/plan/v1/builder/PlanFactory.kt +++ b/partiql-plan/src/main/kotlin/org/partiql/plan/v1/builder/PlanFactory.kt @@ -1,9 +1,11 @@ package org.partiql.plan.v1.builder import org.partiql.eval.value.Datum +import org.partiql.plan.v1.Schema import org.partiql.plan.v1.operator.rel.Rel import org.partiql.plan.v1.operator.rel.RelAggregate import org.partiql.plan.v1.operator.rel.RelAggregateCall +import org.partiql.plan.v1.operator.rel.RelAggregateCallImpl import org.partiql.plan.v1.operator.rel.RelAggregateImpl import org.partiql.plan.v1.operator.rel.RelCollation import org.partiql.plan.v1.operator.rel.RelCorrelate @@ -43,8 +45,10 @@ import org.partiql.plan.v1.operator.rex.RexArray import org.partiql.plan.v1.operator.rex.RexArrayImpl import org.partiql.plan.v1.operator.rex.RexBag import org.partiql.plan.v1.operator.rex.RexBagImpl -import org.partiql.plan.v1.operator.rex.RexCall -import org.partiql.plan.v1.operator.rex.RexCallImpl +import org.partiql.plan.v1.operator.rex.RexCallDynamic +import org.partiql.plan.v1.operator.rex.RexCallDynamicImpl +import org.partiql.plan.v1.operator.rex.RexCallStatic +import org.partiql.plan.v1.operator.rex.RexCallStaticImpl import org.partiql.plan.v1.operator.rex.RexCase import org.partiql.plan.v1.operator.rex.RexCaseImpl import org.partiql.plan.v1.operator.rex.RexCast @@ -57,6 +61,14 @@ import org.partiql.plan.v1.operator.rex.RexLit import org.partiql.plan.v1.operator.rex.RexLitImpl import org.partiql.plan.v1.operator.rex.RexMissing import org.partiql.plan.v1.operator.rex.RexMissingImpl +import org.partiql.plan.v1.operator.rex.RexNullIf +import org.partiql.plan.v1.operator.rex.RexNullIfImpl +import org.partiql.plan.v1.operator.rex.RexPathIndex +import org.partiql.plan.v1.operator.rex.RexPathIndexImpl +import org.partiql.plan.v1.operator.rex.RexPathKey +import org.partiql.plan.v1.operator.rex.RexPathKeyImpl +import org.partiql.plan.v1.operator.rex.RexPathSymbol +import org.partiql.plan.v1.operator.rex.RexPathSymbolImpl import org.partiql.plan.v1.operator.rex.RexPivot import org.partiql.plan.v1.operator.rex.RexPivotImpl import org.partiql.plan.v1.operator.rex.RexSelect @@ -77,6 +89,8 @@ import org.partiql.plan.v1.operator.rex.RexTable import org.partiql.plan.v1.operator.rex.RexTableImpl import org.partiql.plan.v1.operator.rex.RexVar import org.partiql.plan.v1.operator.rex.RexVarImpl +import org.partiql.planner.catalog.Table +import org.partiql.spi.fn.Agg import org.partiql.spi.fn.Fn import org.partiql.types.PType @@ -112,6 +126,17 @@ public interface PlanFactory { public fun relAggregate(input: Rel, calls: List, groups: List): RelAggregate = RelAggregateImpl(input, calls, groups) + /** + * Create a [RelAggregateCall] instance. + * + * @param aggregation + * @param args + * @param isDistinct + * @return + */ + public fun relAggregateCall(aggregation: Agg, args: List, isDistinct: Boolean = false): RelAggregateCall = + RelAggregateCallImpl(aggregation, args, isDistinct) + /** * Create a [RelCorrelate] instance for a lateral cross join. * @@ -129,7 +154,8 @@ public interface PlanFactory { * @param joinType * @return */ - public fun relCorrelate(lhs: Rel, rhs: Rel, joinType: RelJoinType): RelCorrelate = RelCorrelateImpl(lhs, rhs, joinType) + public fun relCorrelate(lhs: Rel, rhs: Rel, joinType: RelJoinType): RelCorrelate = + RelCorrelateImpl(lhs, rhs, joinType) /** * Create a [RelDistinct] instance. @@ -223,8 +249,8 @@ public interface PlanFactory { * @param type * @return */ - public fun relJoin(lhs: Rel, rhs: Rel, condition: Rex?, type: RelJoinType): RelJoin = - RelJoinImpl(lhs, rhs, condition, type) + public fun relJoin(lhs: Rel, rhs: Rel, condition: Rex?, type: RelJoinType, lhsSchema: Schema? = null, rhsSchema: Schema? = null): RelJoin = + RelJoinImpl(lhs, rhs, condition, type, lhsSchema, rhsSchema) /** * Create a [RelLimit] instance. @@ -315,13 +341,22 @@ public interface PlanFactory { public fun rexBag(values: Collection): RexBag = RexBagImpl(values) /** - * Create a [RexCall] instance. + * Create a [RexCallStatic] instance. * * @param function * @param args * @return */ - public fun rexCall(function: Fn, args: List): RexCall = RexCallImpl(function, args) + public fun rexCall(function: Fn, args: List): RexCallStatic = RexCallStaticImpl(function, args) + + /** + * Create a [RexCallDynamic] instance. + * + * @param functions + * @param args + * @return + */ + public fun rexCall(functions: List, args: List): RexCallDynamic = RexCallDynamicImpl(functions, args) /** * Create a [RexCase] instance for a searched case-when. @@ -367,7 +402,7 @@ public interface PlanFactory { * @param offset * @return */ - public fun rexCol(depth: Int, offset: Int): RexVar = RexVarImpl(depth, offset) + public fun rexVar(depth: Int, offset: Int): RexVar = RexVarImpl(depth, offset) /** * TODO AUDIT ME @@ -397,7 +432,37 @@ public interface PlanFactory { */ public fun rexLit(value: Datum): RexLit = RexLitImpl(value) - // TODO PATHS + /** + * TODO REMOVE ME + */ + public fun rexNullIf(value: Rex, nullifier: Rex): RexNullIf = RexNullIfImpl(value, nullifier) + + /** + * Create a [RexPathIndex] instance. + * + * @param operand + * @param index + * @return + */ + public fun rexPathIndex(operand: Rex, index: Rex): RexPathIndex = RexPathIndexImpl(operand, index) + + /** + * Create a [RexPathKey] instance. + * + * @param operand + * @param key + * @return + */ + public fun rexPathKey(operand: Rex, key: Rex): RexPathKey = RexPathKeyImpl(operand, key) + + /** + * Create a [RexPathSymbol] instance. + * + * @param operand + * @param symbol + * @return + */ + public fun rexPathSymbol(operand: Rex, symbol: String): RexPathSymbol = RexPathSymbolImpl(operand, symbol) /** * Create a [RexPivot] instance. @@ -437,10 +502,13 @@ public interface PlanFactory { /** * Create a [RexSubquery] instance. * + * TODO REMOVE constructor AND asScalar – TEMPORARY UNTIL SUBQUERIES ARE FIXED IN THE PLANNER. + * * @param rel * @return */ - public fun rexSubquery(rel: Rel): RexSubquery = RexSubqueryImpl(rel) + public fun rexSubquery(rel: Rel, constructor: Rex, asScalar: Boolean): RexSubquery = + RexSubqueryImpl(rel, constructor, asScalar) /** * Create a [RexSubqueryComp] instance. @@ -499,9 +567,8 @@ public interface PlanFactory { /** * Create a [RexTable] instance. * - * @param catalog - * @param name + * @param table * @return */ - public fun rexTable(catalog: String, name: String): RexTable = RexTableImpl(catalog, name) + public fun rexTable(table: Table): RexTable = RexTableImpl(table) } diff --git a/partiql-plan/src/main/kotlin/org/partiql/plan/v1/builder/RexBuilder.kt b/partiql-plan/src/main/kotlin/org/partiql/plan/v1/builder/RexBuilder.kt index 7194f19ebf..8d43397e20 100644 --- a/partiql-plan/src/main/kotlin/org/partiql/plan/v1/builder/RexBuilder.kt +++ b/partiql-plan/src/main/kotlin/org/partiql/plan/v1/builder/RexBuilder.kt @@ -36,7 +36,7 @@ public class RexBuilder private constructor(rex: Builder) { @JvmStatic public fun col(depth: Int, offset: Int): RexBuilder = RexBuilder { - it.rexCol(depth, offset) + it.rexVar(depth, offset) } @JvmStatic @@ -86,8 +86,9 @@ public class RexBuilder private constructor(rex: Builder) { */ @JvmStatic public fun subquery(rel: RelBuilder): RexBuilder = RexBuilder { - val _rel = rel.build(it) - it.rexSubquery(_rel) + error("subquery builders are removed until they are fixed in partiql-planner") + // val _rel = rel.build(it) + // it.rexSubquery(_rel) } /** diff --git a/partiql-plan/src/main/kotlin/org/partiql/plan/v1/operator/rel/RelAggregateCall.kt b/partiql-plan/src/main/kotlin/org/partiql/plan/v1/operator/rel/RelAggregateCall.kt index 0f7ab799cb..08a07adf03 100644 --- a/partiql-plan/src/main/kotlin/org/partiql/plan/v1/operator/rel/RelAggregateCall.kt +++ b/partiql-plan/src/main/kotlin/org/partiql/plan/v1/operator/rel/RelAggregateCall.kt @@ -1,18 +1,35 @@ package org.partiql.plan.v1.operator.rel import org.partiql.plan.v1.operator.rex.Rex -import org.partiql.types.PType +import org.partiql.spi.fn.Agg /** * TODO DOCUMENTATION */ public interface RelAggregateCall { - public fun isDistinct(): Boolean + public fun getAgg(): Agg - public fun getName(): String + public fun getArgs(): List - public fun getType(): PType + public fun isDistinct(): Boolean +} - public fun getArgs(): List +/** + * Internal standard implementation of [RelAggregateCall]. + * + * DO NOT USE FINAL. + * + * @property agg + * @property args + * @property isDistinct + */ +internal class RelAggregateCallImpl( + private var agg: Agg, + private var args: List, + private var isDistinct: Boolean, +) : RelAggregateCall { + override fun getAgg(): Agg = agg + override fun getArgs(): List = args + override fun isDistinct(): Boolean = isDistinct } diff --git a/partiql-plan/src/main/kotlin/org/partiql/plan/v1/operator/rel/RelExcludePath.kt b/partiql-plan/src/main/kotlin/org/partiql/plan/v1/operator/rel/RelExcludePath.kt index 7ff9bde09c..49250854e3 100644 --- a/partiql-plan/src/main/kotlin/org/partiql/plan/v1/operator/rel/RelExcludePath.kt +++ b/partiql-plan/src/main/kotlin/org/partiql/plan/v1/operator/rel/RelExcludePath.kt @@ -3,11 +3,31 @@ package org.partiql.plan.v1.operator.rel import org.partiql.plan.v1.operator.rex.RexVar /** - * TODO DOCUMENTATION + * Logical representation of an EXCLUDE path. */ public interface RelExcludePath { public fun getRoot(): RexVar - public fun getSteps(): RelExcludeStep + public fun getSteps(): Collection + + public companion object { + + @JvmStatic + public fun of(root: RexVar, steps: Collection): RelExcludePath = RelExcludePathImpl(root, steps) + } +} + +/** + * Internal standard implementation of [RelExcludePath]. + * + * @property root + * @property steps + */ +internal class RelExcludePathImpl( + private var root: RexVar, + private var steps: Collection, +) : RelExcludePath { + override fun getRoot(): RexVar = root + override fun getSteps(): Collection = steps } diff --git a/partiql-plan/src/main/kotlin/org/partiql/plan/v1/operator/rel/RelExcludeStep.kt b/partiql-plan/src/main/kotlin/org/partiql/plan/v1/operator/rel/RelExcludeStep.kt index ac84b4f17b..3f8bafd82e 100644 --- a/partiql-plan/src/main/kotlin/org/partiql/plan/v1/operator/rel/RelExcludeStep.kt +++ b/partiql-plan/src/main/kotlin/org/partiql/plan/v1/operator/rel/RelExcludeStep.kt @@ -1,40 +1,103 @@ package org.partiql.plan.v1.operator.rel /** - * TODO DOCUMENTATION + * Logical EXCLUDE step, one of: index, key, symbol, struct wildcard, or collection wildcard. */ public interface RelExcludeStep { public fun getSubsteps(): List - /** - * TODO DOCUMENTATION - */ - public interface Index : RelExcludeStep { - public fun getIndex(): Int - } + companion object { - /** - * TODO DOCUMENTATION - */ - public interface Key : RelExcludeStep { - public fun getKey(): String - } + @JvmStatic + public fun index(index: Int, substeps: List = emptyList()): RelExcludeIndex = + RelExcludeIndexImpl(index, substeps) + + @JvmStatic + public fun key(key: String, substeps: List = emptyList()): RelExcludeKey = + RelExcludeKeyImpl(key, substeps) + + @JvmStatic + public fun symbol(symbol: String, substeps: List = emptyList()): RelExcludeSymbol = + RelExcludeSymbolImpl(symbol, substeps) - /** - * TODO DOCUMENTATION - */ - public interface Symbol : RelExcludeStep { - public fun getSymbol(): String + @JvmStatic + public fun struct(substeps: List = emptyList()): RelExcludeStructWildcard = + RelExcludeStructWildcardImpl(substeps) + + @JvmStatic + public fun collection(substeps: List = emptyList()): RelExcludeCollectionWildcard = + RelExcludeCollectionWildcardImpl(substeps) } +} + +/** + * Logical representation of an EXCLUDE path index step. + */ +public interface RelExcludeIndex : RelExcludeStep { + public fun getIndex(): Int +} + +private data class RelExcludeIndexImpl( + private val index: Int, + private val substeps: List = emptyList(), +) : RelExcludeIndex { + override fun getSubsteps(): List = substeps + override fun getIndex(): Int = index +} + +/** + * Logical representation of an EXCLUDE path key step. + */ +public interface RelExcludeKey : RelExcludeStep { + public fun getKey(): String +} - /** - * TODO DOCUMENTATION - */ - public interface StructWildcard : RelExcludeStep +/** + * Logical representation of an EXCLUDE path symbol step. + */ +public interface RelExcludeSymbol : RelExcludeStep { + public fun getSymbol(): String +} + +/** + * Logical representation of an EXCLUDE struct wildcard step. + */ +public interface RelExcludeStructWildcard : RelExcludeStep + +/** + * Logical representation of an EXCLUDE collection wildcard step. + */ +public interface RelExcludeCollectionWildcard : RelExcludeStep + +// TODO hashcode/equals without data class +private data class RelExcludeKeyImpl( + private val key: String, + private val substeps: List = emptyList(), +) : RelExcludeKey { + override fun getSubsteps(): List = substeps + override fun getKey(): String = key +} + +// TODO hashcode/equals without data class +private data class RelExcludeSymbolImpl( + private val symbol: String, + private val substeps: List = emptyList(), +) : RelExcludeSymbol { + override fun getSubsteps(): List = substeps + override fun getSymbol(): String = symbol +} + +// TODO hashcode/equals without data class +private data class RelExcludeStructWildcardImpl( + private val substeps: List = emptyList(), +) : RelExcludeStructWildcard { + override fun getSubsteps(): List = substeps +} - /** - * TODO DOCUMENTATION - */ - public interface CollectionWildcard : RelExcludeStep +// TODO hashcode/equals without data class +private data class RelExcludeCollectionWildcardImpl( + private val substeps: List = emptyList(), +) : RelExcludeCollectionWildcard { + override fun getSubsteps(): List = substeps } diff --git a/partiql-plan/src/main/kotlin/org/partiql/plan/v1/operator/rel/RelJoin.kt b/partiql-plan/src/main/kotlin/org/partiql/plan/v1/operator/rel/RelJoin.kt index f50548225d..aeb31cb289 100644 --- a/partiql-plan/src/main/kotlin/org/partiql/plan/v1/operator/rel/RelJoin.kt +++ b/partiql-plan/src/main/kotlin/org/partiql/plan/v1/operator/rel/RelJoin.kt @@ -10,8 +10,14 @@ public interface RelJoin : Rel { public fun getLeft(): Rel + // TODO REMOVE ME TEMPORARY + public fun getLeftSchema(): Schema? + public fun getRight(): Rel + // TODO REMOVE ME TEMPORARY + public fun getRightSchema(): Schema? + public fun getCondition(): Rex? public fun getJoinType(): RelJoinType @@ -26,13 +32,22 @@ public interface RelJoin : Rel { /** * Default [RelJoin] implementation. */ -internal class RelJoinImpl(left: Rel, right: Rel, condition: Rex?, joinType: RelJoinType) : RelJoin { +internal class RelJoinImpl( + left: Rel, + right: Rel, + condition: Rex?, + joinType: RelJoinType, + leftSchema: Schema?, + rightSchema: Schema?, +) : RelJoin { // DO NOT USE FINAL private var _left = left private var _right = right private var _condition = condition private var _joinType = joinType + private var _leftSchema = leftSchema + private var _rightSchema = rightSchema private var _children: List? = null @@ -44,6 +59,10 @@ internal class RelJoinImpl(left: Rel, right: Rel, condition: Rex?, joinType: Rel override fun getJoinType(): RelJoinType = _joinType + override fun getLeftSchema(): Schema? = _leftSchema + + override fun getRightSchema(): Schema? = _rightSchema + override fun getChildren(): Collection { if (_children == null) { _children = listOf(_left, _right) diff --git a/partiql-plan/src/main/kotlin/org/partiql/plan/v1/operator/rel/RelScan.kt b/partiql-plan/src/main/kotlin/org/partiql/plan/v1/operator/rel/RelScan.kt index 4f8e67d3cb..54a12560c8 100644 --- a/partiql-plan/src/main/kotlin/org/partiql/plan/v1/operator/rel/RelScan.kt +++ b/partiql-plan/src/main/kotlin/org/partiql/plan/v1/operator/rel/RelScan.kt @@ -2,7 +2,6 @@ package org.partiql.plan.v1.operator.rel import org.partiql.plan.v1.Schema import org.partiql.plan.v1.operator.rex.Rex -import org.partiql.types.PType /** * Logical scan corresponding to the clause `FROM AS `. @@ -13,7 +12,7 @@ public interface RelScan : Rel { override fun getChildren(): Collection = emptyList() - override fun isOrdered(): Boolean = getInput().getType().kind == PType.Kind.ARRAY + override fun isOrdered(): Boolean = false override fun accept(visitor: RelVisitor, ctx: C): R = visitor.visitScan(this, ctx) } diff --git a/partiql-plan/src/main/kotlin/org/partiql/plan/v1/operator/rex/RexBag.kt b/partiql-plan/src/main/kotlin/org/partiql/plan/v1/operator/rex/RexBag.kt index 9d8feca613..1691d0237e 100644 --- a/partiql-plan/src/main/kotlin/org/partiql/plan/v1/operator/rex/RexBag.kt +++ b/partiql-plan/src/main/kotlin/org/partiql/plan/v1/operator/rex/RexBag.kt @@ -26,9 +26,7 @@ internal class RexBagImpl(values: Collection) : RexBag { override fun getChildren(): Collection = _values - override fun getType(): PType { - TODO("Not yet implemented") - } + override fun getType(): PType = PType.bag() override fun equals(other: Any?): Boolean { if (this === other) return true diff --git a/partiql-plan/src/main/kotlin/org/partiql/plan/v1/operator/rex/RexCallDynamic.kt b/partiql-plan/src/main/kotlin/org/partiql/plan/v1/operator/rex/RexCallDynamic.kt new file mode 100644 index 0000000000..b48507d96f --- /dev/null +++ b/partiql-plan/src/main/kotlin/org/partiql/plan/v1/operator/rex/RexCallDynamic.kt @@ -0,0 +1,46 @@ +package org.partiql.plan.v1.operator.rex + +import org.partiql.spi.fn.Fn +import org.partiql.types.PType + +/** + * Logical operator for a dynamic scalar function call. + */ +public interface RexCallDynamic : Rex { + + /** + * Returns the function to invoke. + * + * @return + */ + public fun getFunctions(): List + + /** + * Returns the list of function arguments. + */ + public fun getArgs(): List + + override fun getChildren(): Collection = getArgs() + + override fun accept(visitor: RexVisitor, ctx: C): R = visitor.visitCallDynamic(this, ctx) +} + +/** + * Default [RexCallDynamic] implementation meant for extension. + */ +internal class RexCallDynamicImpl(functions: List, args: List) : RexCallDynamic { + + // DO NOT USE FINAL + private var _functions = functions + private var _args = args + + override fun getFunctions(): List = _functions + + override fun getArgs(): List = _args + + override fun getType(): PType { + TODO("Function .getType()") + } + + override fun getChildren(): Collection = _args +} diff --git a/partiql-plan/src/main/kotlin/org/partiql/plan/v1/operator/rex/RexCall.kt b/partiql-plan/src/main/kotlin/org/partiql/plan/v1/operator/rex/RexCallStatic.kt similarity index 74% rename from partiql-plan/src/main/kotlin/org/partiql/plan/v1/operator/rex/RexCall.kt rename to partiql-plan/src/main/kotlin/org/partiql/plan/v1/operator/rex/RexCallStatic.kt index adc9d36d9d..78822813ea 100644 --- a/partiql-plan/src/main/kotlin/org/partiql/plan/v1/operator/rex/RexCall.kt +++ b/partiql-plan/src/main/kotlin/org/partiql/plan/v1/operator/rex/RexCallStatic.kt @@ -4,9 +4,9 @@ import org.partiql.spi.fn.Fn import org.partiql.types.PType /** - * Scalar function calls. + * Logical operator for a scalar function call. */ -public interface RexCall : Rex { +public interface RexCallStatic : Rex { /** * Returns the function to invoke. @@ -22,13 +22,13 @@ public interface RexCall : Rex { override fun getChildren(): Collection = getArgs() - override fun accept(visitor: RexVisitor, ctx: C): R = visitor.visitCall(this, ctx) + override fun accept(visitor: RexVisitor, ctx: C): R = visitor.visitCallStatic(this, ctx) } /** - * Default [RexCall] implementation meant for extension. + * Default [RexCallStatic] implementation meant for extension. */ -internal class RexCallImpl(function: Fn, args: List) : RexCall { +internal class RexCallStaticImpl(function: Fn, args: List) : RexCallStatic { // DO NOT USE FINAL private var _function = function diff --git a/partiql-plan/src/main/kotlin/org/partiql/plan/v1/operator/rex/RexNullIf.kt b/partiql-plan/src/main/kotlin/org/partiql/plan/v1/operator/rex/RexNullIf.kt new file mode 100644 index 0000000000..430ad0e97c --- /dev/null +++ b/partiql-plan/src/main/kotlin/org/partiql/plan/v1/operator/rex/RexNullIf.kt @@ -0,0 +1,51 @@ +package org.partiql.plan.v1.operator.rex + +import org.partiql.types.PType + +/** + * TODO REMOVE ME AFTER EVALUATOR MERGE + */ +public interface RexNullIf : Rex { + + public fun getValue(): Rex + + public fun getNullifier(): Rex + + override fun getType(): PType = PType.bag(getNullifier().getType()) + + override fun getChildren(): Collection = listOf(getNullifier()) + + override fun accept(visitor: RexVisitor, ctx: C): R = visitor.visitNullIf(this, ctx) +} + +/** + * Internal + */ +internal class RexNullIfImpl(value: Rex, nullifier: Rex) : RexNullIf { + + // DO NOT USE FINAL + private var _value = value + private var _nullifier = nullifier + + override fun getValue(): Rex = _value + + override fun getNullifier(): Rex = _nullifier + + override fun getType(): PType = PType.bag(_nullifier.getType()) + + override fun getChildren(): Collection = listOf(_nullifier) + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is RexNullIf) return false + if (_value != other.getValue()) return false + if (_nullifier != other.getNullifier()) return false + return true + } + + override fun hashCode(): Int { + var result = _value.hashCode() + result = 31 * result + _nullifier.hashCode() + return result + } +} diff --git a/partiql-plan/src/main/kotlin/org/partiql/plan/v1/operator/rex/RexPath.kt b/partiql-plan/src/main/kotlin/org/partiql/plan/v1/operator/rex/RexPath.kt deleted file mode 100644 index 34dc179ae2..0000000000 --- a/partiql-plan/src/main/kotlin/org/partiql/plan/v1/operator/rex/RexPath.kt +++ /dev/null @@ -1,41 +0,0 @@ -package org.partiql.plan.v1.operator.rex - -/** - * TODO DOCUMENTATION - */ -public interface RexPath : Rex { - - public fun getRoot(): Rex - - override fun accept(visitor: RexVisitor, ctx: C): R = visitor.visitPath(this, ctx) - - /** - * TODO DOCUMENTATION - */ - public interface Index : RexPath { - - public fun getIndex(): Rex - - override fun accept(visitor: RexVisitor, ctx: C): R = visitor.visitPathIndex(this, ctx) - } - - /** - * TODO DOCUMENTATION - */ - public interface Key : RexPath { - - public fun getKey(): Rex - - override fun accept(visitor: RexVisitor, ctx: C): R = visitor.visitPathKey(this, ctx) - } - - /** - * TODO DOCUMENTATION - */ - public interface Symbol : RexPath { - - public fun getSymbol(): String - - override fun accept(visitor: RexVisitor, ctx: C): R = visitor.visitPathSymbol(this, ctx) - } -} diff --git a/partiql-plan/src/main/kotlin/org/partiql/plan/v1/operator/rex/RexPathIndex.kt b/partiql-plan/src/main/kotlin/org/partiql/plan/v1/operator/rex/RexPathIndex.kt new file mode 100644 index 0000000000..5da907b39b --- /dev/null +++ b/partiql-plan/src/main/kotlin/org/partiql/plan/v1/operator/rex/RexPathIndex.kt @@ -0,0 +1,35 @@ +package org.partiql.plan.v1.operator.rex + +import org.partiql.types.PType + +/** + * Logical path index operator. + */ +public interface RexPathIndex : Rex { + + public fun getOperand(): Rex + + public fun getIndex(): Rex + + override fun accept(visitor: RexVisitor, ctx: C): R = visitor.visitPathIndex(this, ctx) +} + +/** + * Standard internal implementation for [RexPathIndex]. + */ +internal class RexPathIndexImpl(operand: Rex, index: Rex) : RexPathIndex { + + // DO NOT USE FINAL + private var _operand = operand + private var _index = index + + override fun getOperand() = _operand + + override fun getIndex() = _index + + override fun getType(): PType { + TODO("Not yet implemented") + } + + override fun getChildren(): Collection = listOf(_operand, _index) +} diff --git a/partiql-plan/src/main/kotlin/org/partiql/plan/v1/operator/rex/RexPathKey.kt b/partiql-plan/src/main/kotlin/org/partiql/plan/v1/operator/rex/RexPathKey.kt new file mode 100644 index 0000000000..6496944671 --- /dev/null +++ b/partiql-plan/src/main/kotlin/org/partiql/plan/v1/operator/rex/RexPathKey.kt @@ -0,0 +1,35 @@ +package org.partiql.plan.v1.operator.rex + +import org.partiql.types.PType + +/** + * Logical operator for path lookup by key. + */ +public interface RexPathKey : Rex { + + public fun getOperand(): Rex + + public fun getKey(): Rex + + override fun accept(visitor: RexVisitor, ctx: C): R = visitor.visitPathKey(this, ctx) +} + +/** + * Standard internal implementation for [RexPathKey]. + */ +internal class RexPathKeyImpl(operand: Rex, key: Rex) : RexPathKey { + + // DO NOT USE FINAL + private var _operand = operand + private var _key = key + + override fun getOperand() = _operand + + override fun getKey() = _key + + override fun getType(): PType { + TODO("Not yet implemented") + } + + override fun getChildren(): Collection = listOf(_operand, _key) +} diff --git a/partiql-plan/src/main/kotlin/org/partiql/plan/v1/operator/rex/RexPathSymbol.kt b/partiql-plan/src/main/kotlin/org/partiql/plan/v1/operator/rex/RexPathSymbol.kt new file mode 100644 index 0000000000..d4daeafbb3 --- /dev/null +++ b/partiql-plan/src/main/kotlin/org/partiql/plan/v1/operator/rex/RexPathSymbol.kt @@ -0,0 +1,35 @@ +package org.partiql.plan.v1.operator.rex + +import org.partiql.types.PType + +/** + * Logical operator for path lookup by symbol. + */ +public interface RexPathSymbol : Rex { + + public fun getOperand(): Rex + + public fun getSymbol(): String + + override fun accept(visitor: RexVisitor, ctx: C): R = visitor.visitPathSymbol(this, ctx) +} + +/** + * Standard internal implementation for [RexPathSymbol]. + */ +internal class RexPathSymbolImpl(operand: Rex, symbol: String) : RexPathSymbol { + + // DO NOT USE FINAL + private var _operand = operand + private var _symbol = symbol + + override fun getOperand() = _operand + + override fun getSymbol() = _symbol + + override fun getType(): PType { + TODO("Not yet implemented") + } + + override fun getChildren(): Collection = listOf(_operand) +} diff --git a/partiql-plan/src/main/kotlin/org/partiql/plan/v1/operator/rex/RexSubquery.kt b/partiql-plan/src/main/kotlin/org/partiql/plan/v1/operator/rex/RexSubquery.kt index 48600a4d03..307609b03f 100644 --- a/partiql-plan/src/main/kotlin/org/partiql/plan/v1/operator/rex/RexSubquery.kt +++ b/partiql-plan/src/main/kotlin/org/partiql/plan/v1/operator/rex/RexSubquery.kt @@ -10,19 +10,31 @@ public interface RexSubquery : Rex { public fun getRel(): Rel + // TODO REMOVE ME – TEMPORARY UNTIL PLANNER PROPERLY HANDLES SUBQUERIES + public fun getConstructor(): Rex + + // TODO REMOVE ME – TEMPORARY UNTIL PLANNER PROPERLY HANDLES SUBQUERIES + public fun asScalar(): Boolean + override fun accept(visitor: RexVisitor, ctx: C): R = visitor.visitSubquery(this, ctx) } /** * Implementation of scalar subquery coercion. */ -internal class RexSubqueryImpl(rel: Rel) : RexSubquery { +internal class RexSubqueryImpl(rel: Rel, constructor: Rex, asScalar: Boolean) : RexSubquery { // DO NOT USE FINAL private var _rel = rel + private var _constructor = constructor + private var _asScalar = asScalar override fun getRel(): Rel = _rel + override fun getConstructor(): Rex = _constructor + + override fun asScalar(): Boolean = _asScalar + override fun getType(): PType { TODO("Not yet implemented") } diff --git a/partiql-plan/src/main/kotlin/org/partiql/plan/v1/operator/rex/RexTable.kt b/partiql-plan/src/main/kotlin/org/partiql/plan/v1/operator/rex/RexTable.kt index 6f0d7ebb00..494641a47a 100644 --- a/partiql-plan/src/main/kotlin/org/partiql/plan/v1/operator/rex/RexTable.kt +++ b/partiql-plan/src/main/kotlin/org/partiql/plan/v1/operator/rex/RexTable.kt @@ -1,19 +1,14 @@ package org.partiql.plan.v1.operator.rex +import org.partiql.planner.catalog.Table import org.partiql.types.PType /** * Global variable references e.g. tables and views. - * TODO NAMING?? RexTable?? */ public interface RexTable : Rex { - public fun getCatalog(): String - - /** - * TODO replace with Catalog Name - */ - public fun getName(): String + public fun getTable(): Table override fun getChildren(): Collection = emptyList() @@ -23,15 +18,12 @@ public interface RexTable : Rex { /** * Default [RexTable] implementation. */ -internal class RexTableImpl(catalog: String, name: String) : RexTable { +internal class RexTableImpl(table: Table) : RexTable { // DO NOT USE FINAL - private var _catalog = catalog - private var _name = name - - override fun getCatalog(): String = _catalog + private var _table = table - override fun getName(): String = _name + override fun getTable(): Table = _table override fun getType(): PType { TODO("Not yet implemented") @@ -40,15 +32,13 @@ internal class RexTableImpl(catalog: String, name: String) : RexTable { override fun equals(other: Any?): Boolean { if (this === other) return true if (other !is RexTable) return false - if (_catalog != other.getCatalog()) return false - if (_name != other.getName()) return false + if (_table != other.getTable()) return false return true } override fun hashCode(): Int { var result = 1 - result = 31 * result + _catalog.hashCode() - result = 31 * result + _name.hashCode() + result = 31 * result + _table.hashCode() return result } } diff --git a/partiql-plan/src/main/kotlin/org/partiql/plan/v1/operator/rex/RexVisitor.kt b/partiql-plan/src/main/kotlin/org/partiql/plan/v1/operator/rex/RexVisitor.kt index ad1654fee5..fec15ad610 100644 --- a/partiql-plan/src/main/kotlin/org/partiql/plan/v1/operator/rex/RexVisitor.kt +++ b/partiql-plan/src/main/kotlin/org/partiql/plan/v1/operator/rex/RexVisitor.kt @@ -23,7 +23,9 @@ public interface RexVisitor { public fun visitBag(rex: RexBag, ctx: C): R = defaultVisit(rex, ctx) - public fun visitCall(rex: RexCall, ctx: C): R = defaultVisit(rex, ctx) + public fun visitCallStatic(rex: RexCallStatic, ctx: C): R = defaultVisit(rex, ctx) + + public fun visitCallDynamic(rex: RexCallDynamic, ctx: C): R = defaultVisit(rex, ctx) public fun visitCase(rex: RexCase, ctx: C): R = defaultVisit(rex, ctx) @@ -37,13 +39,13 @@ public interface RexVisitor { public fun visitMissing(rex: RexMissing, ctx: C): R = defaultVisit(rex, ctx) - public fun visitPath(rex: RexPath, ctx: C): R = rex.accept(this, ctx) + public fun visitNullIf(rex: RexNullIf, ctx: C): R = defaultVisit(rex, ctx) - public fun visitPathIndex(rex: RexPath.Index, ctx: C): R = defaultVisit(rex, ctx) + public fun visitPathIndex(rex: RexPathIndex, ctx: C): R = defaultVisit(rex, ctx) - public fun visitPathKey(rex: RexPath.Key, ctx: C): R = defaultVisit(rex, ctx) + public fun visitPathKey(rex: RexPathKey, ctx: C): R = defaultVisit(rex, ctx) - public fun visitPathSymbol(rex: RexPath.Symbol, ctx: C): R = defaultVisit(rex, ctx) + public fun visitPathSymbol(rex: RexPathSymbol, ctx: C): R = defaultVisit(rex, ctx) public fun visitPivot(rex: RexPivot, ctx: C): R = defaultVisit(rex, ctx) diff --git a/partiql-planner/api/partiql-planner.api b/partiql-planner/api/partiql-planner.api index 1dcd1a6e2d..a47e8f8c34 100644 --- a/partiql-planner/api/partiql-planner.api +++ b/partiql-planner/api/partiql-planner.api @@ -33,3 +33,9 @@ public final class org/partiql/planner/builder/PartiQLPlannerBuilder { public static synthetic fun signal$default (Lorg/partiql/planner/builder/PartiQLPlannerBuilder;ZILjava/lang/Object;)Lorg/partiql/planner/builder/PartiQLPlannerBuilder; } +public final class org/partiql/planner/internal/SqlPlannerV1 { + public static final field INSTANCE Lorg/partiql/planner/internal/SqlPlannerV1; + public final fun plan (Lorg/partiql/ast/Statement;Lorg/partiql/planner/catalog/Session;Lkotlin/jvm/functions/Function1;)Lorg/partiql/plan/v1/PartiQLPlan; + public static synthetic fun plan$default (Lorg/partiql/planner/internal/SqlPlannerV1;Lorg/partiql/ast/Statement;Lorg/partiql/planner/catalog/Session;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lorg/partiql/plan/v1/PartiQLPlan; +} + diff --git a/partiql-planner/src/main/kotlin/org/partiql/planner/internal/Env.kt b/partiql-planner/src/main/kotlin/org/partiql/planner/internal/Env.kt index 8196e6c850..d39805b378 100644 --- a/partiql-planner/src/main/kotlin/org/partiql/planner/internal/Env.kt +++ b/partiql-planner/src/main/kotlin/org/partiql/planner/internal/Env.kt @@ -90,7 +90,7 @@ internal class Env(private val session: Session) { val refCatalog = catalog.getName() val refName = handle.name val refType = CompilerType(handle.table.getSchema()) - val ref = Ref.Obj(refCatalog, refName, refType) + val ref = Ref.Obj(refCatalog, refName, refType, handle.table) // Convert any remaining identifier parts to a path expression val root = Rex(ref.type, rexOpVarGlobal(ref)) diff --git a/partiql-planner/src/main/kotlin/org/partiql/planner/internal/SqlPlannerV1.kt b/partiql-planner/src/main/kotlin/org/partiql/planner/internal/SqlPlannerV1.kt new file mode 100644 index 0000000000..cd0c7b945b --- /dev/null +++ b/partiql-planner/src/main/kotlin/org/partiql/planner/internal/SqlPlannerV1.kt @@ -0,0 +1,45 @@ +package org.partiql.planner.internal + +import org.partiql.ast.Statement +import org.partiql.ast.normalize.normalize +import org.partiql.errors.ProblemCallback +import org.partiql.plan.v1.PartiQLPlan +import org.partiql.planner.catalog.Session +import org.partiql.planner.internal.transforms.AstToPlan +import org.partiql.planner.internal.transforms.PlanTransformV1 +import org.partiql.planner.internal.typer.PlanTyper + +/** + * Default PartiQL logical query planner. + * + * TODO TEMPORARY WHILE WE SWITCH OUT THE PUBLIC PLAN + */ +public object SqlPlannerV1 { + + // private val flags = setOf(PlannerFlag.SIGNAL_MODE) + private val flags = setOf() + + public fun plan( + statement: Statement, + session: Session, + onProblem: ProblemCallback = {}, + ): PartiQLPlan { + + // 0. Initialize the planning environment + val env = Env(session) + + // 1. Normalize + val ast = statement.normalize() + + // 2. AST to Rel/Rex + val root = AstToPlan.apply(ast, env) + + // 3. Resolve variables + val typer = PlanTyper(env) + val typed = typer.resolve(root) + val internal = org.partiql.planner.internal.ir.PartiQLPlan(typed) + + // 4. Assert plan has been resolved — translating to public API + return PlanTransformV1(flags).transform(internal, onProblem) + } +} diff --git a/partiql-planner/src/main/kotlin/org/partiql/planner/internal/ir/Nodes.kt b/partiql-planner/src/main/kotlin/org/partiql/planner/internal/ir/Nodes.kt index f9adbf6f3f..847876c71e 100644 --- a/partiql-planner/src/main/kotlin/org/partiql/planner/internal/ir/Nodes.kt +++ b/partiql-planner/src/main/kotlin/org/partiql/planner/internal/ir/Nodes.kt @@ -5,8 +5,7 @@ package org.partiql.planner.`internal`.ir import org.partiql.errors.Problem import org.partiql.planner.catalog.Identifier import org.partiql.planner.catalog.Name -import org.partiql.spi.fn.AggSignature -import org.partiql.spi.fn.FnSignature +import org.partiql.planner.catalog.Table import org.partiql.planner.internal.ir.builder.PartiQlPlanBuilder import org.partiql.planner.internal.ir.builder.RefAggBuilder import org.partiql.planner.internal.ir.builder.RefCastBuilder @@ -71,9 +70,10 @@ import org.partiql.planner.internal.ir.builder.RexOpVarUnresolvedBuilder import org.partiql.planner.internal.ir.builder.StatementQueryBuilder import org.partiql.planner.internal.ir.visitor.PlanVisitor import org.partiql.planner.internal.typer.CompilerType +import org.partiql.spi.fn.AggSignature +import org.partiql.spi.fn.FnSignature import org.partiql.value.PartiQLValue import org.partiql.value.PartiQLValueExperimental -import kotlin.collections.Set import kotlin.random.Random internal abstract class PlanNode { @@ -113,11 +113,32 @@ internal sealed class Ref : PlanNode() { @JvmField internal val catalog: String, @JvmField internal val name: Name, @JvmField internal val type: CompilerType, + @JvmField internal val table: Table, ) : Ref() { public override val children: List = emptyList() override fun accept(visitor: PlanVisitor, ctx: C): R = visitor.visitRefObj(this, ctx) + // !! MANUALLY OVERRIDE EQUALS/HASHCODE BECAUSE OF THE `table` + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is Obj) return false + + if (catalog != other.catalog) return false + if (name != other.name) return false + if (type != other.type) return false + + return true + } + + override fun hashCode(): Int { + var result = catalog.hashCode() + result = 31 * result + name.hashCode() + result = 31 * result + type.hashCode() + return result + } + internal companion object { @JvmStatic internal fun builder(): RefObjBuilder = RefObjBuilder() @@ -189,8 +210,7 @@ internal sealed class Statement : PlanNode() { kids.filterNotNull() } - override fun accept(visitor: PlanVisitor, ctx: C): R = - visitor.visitStatementQuery(this, ctx) + override fun accept(visitor: PlanVisitor, ctx: C): R = visitor.visitStatementQuery(this, ctx) internal companion object { @JvmStatic @@ -344,8 +364,7 @@ internal data class Rex( kids.filterNotNull() } - override fun accept(visitor: PlanVisitor, ctx: C): R = - visitor.visitRexOpPathKey(this, ctx) + override fun accept(visitor: PlanVisitor, ctx: C): R = visitor.visitRexOpPathKey(this, ctx) internal companion object { @JvmStatic @@ -556,8 +575,7 @@ internal data class Rex( kids.filterNotNull() } - override fun accept(visitor: PlanVisitor, ctx: C): R = - visitor.visitRexOpNullif(this, ctx) + override fun accept(visitor: PlanVisitor, ctx: C): R = visitor.visitRexOpNullif(this, ctx) internal companion object { @JvmStatic @@ -574,8 +592,7 @@ internal data class Rex( kids.filterNotNull() } - override fun accept(visitor: PlanVisitor, ctx: C): R = - visitor.visitRexOpCoalesce(this, ctx) + override fun accept(visitor: PlanVisitor, ctx: C): R = visitor.visitRexOpCoalesce(this, ctx) internal companion object { @JvmStatic @@ -592,8 +609,7 @@ internal data class Rex( kids.filterNotNull() } - override fun accept(visitor: PlanVisitor, ctx: C): R = - visitor.visitRexOpCollection(this, ctx) + override fun accept(visitor: PlanVisitor, ctx: C): R = visitor.visitRexOpCollection(this, ctx) internal companion object { @JvmStatic @@ -610,8 +626,7 @@ internal data class Rex( kids.filterNotNull() } - override fun accept(visitor: PlanVisitor, ctx: C): R = - visitor.visitRexOpStruct(this, ctx) + override fun accept(visitor: PlanVisitor, ctx: C): R = visitor.visitRexOpStruct(this, ctx) internal data class Field( @JvmField internal val k: Rex, @@ -652,8 +667,7 @@ internal data class Rex( kids.filterNotNull() } - override fun accept(visitor: PlanVisitor, ctx: C): R = - visitor.visitRexOpPivot(this, ctx) + override fun accept(visitor: PlanVisitor, ctx: C): R = visitor.visitRexOpPivot(this, ctx) internal companion object { @JvmStatic @@ -673,8 +687,7 @@ internal data class Rex( kids.filterNotNull() } - override fun accept(visitor: PlanVisitor, ctx: C): R = - visitor.visitRexOpSubquery(this, ctx) + override fun accept(visitor: PlanVisitor, ctx: C): R = visitor.visitRexOpSubquery(this, ctx) internal enum class Coercion { SCALAR, ROW, @@ -697,8 +710,7 @@ internal data class Rex( kids.filterNotNull() } - override fun accept(visitor: PlanVisitor, ctx: C): R = - visitor.visitRexOpSelect(this, ctx) + override fun accept(visitor: PlanVisitor, ctx: C): R = visitor.visitRexOpSelect(this, ctx) internal companion object { @JvmStatic @@ -715,8 +727,7 @@ internal data class Rex( kids.filterNotNull() } - override fun accept(visitor: PlanVisitor, ctx: C): R = - visitor.visitRexOpTupleUnion(this, ctx) + override fun accept(visitor: PlanVisitor, ctx: C): R = visitor.visitRexOpTupleUnion(this, ctx) internal companion object { @JvmStatic @@ -752,8 +763,7 @@ internal data class Rex( kids.filterNotNull() } - override fun accept(visitor: PlanVisitor, ctx: C): R = - visitor.visitRexOpMissing(this, ctx) + override fun accept(visitor: PlanVisitor, ctx: C): R = visitor.visitRexOpMissing(this, ctx) internal companion object { @JvmStatic @@ -851,8 +861,7 @@ internal data class Rel( kids.filterNotNull() } - override fun accept(visitor: PlanVisitor, ctx: C): R = - visitor.visitRelOpScanIndexed(this, ctx) + override fun accept(visitor: PlanVisitor, ctx: C): R = visitor.visitRelOpScanIndexed(this, ctx) internal companion object { @JvmStatic @@ -869,8 +878,7 @@ internal data class Rel( kids.filterNotNull() } - override fun accept(visitor: PlanVisitor, ctx: C): R = - visitor.visitRelOpUnpivot(this, ctx) + override fun accept(visitor: PlanVisitor, ctx: C): R = visitor.visitRelOpUnpivot(this, ctx) internal companion object { @JvmStatic @@ -887,8 +895,7 @@ internal data class Rel( kids.filterNotNull() } - override fun accept(visitor: PlanVisitor, ctx: C): R = - visitor.visitRelOpDistinct(this, ctx) + override fun accept(visitor: PlanVisitor, ctx: C): R = visitor.visitRelOpDistinct(this, ctx) internal companion object { @JvmStatic @@ -907,8 +914,7 @@ internal data class Rel( kids.filterNotNull() } - override fun accept(visitor: PlanVisitor, ctx: C): R = - visitor.visitRelOpFilter(this, ctx) + override fun accept(visitor: PlanVisitor, ctx: C): R = visitor.visitRelOpFilter(this, ctx) internal companion object { @JvmStatic @@ -959,79 +965,61 @@ internal data class Rel( } internal data class Union( - @JvmField - internal val setq: SetQuantifier, - @JvmField - internal val isOuter: Boolean, - @JvmField - internal val lhs: Rel, - @JvmField - internal val rhs: Rel, + @JvmField internal val setq: SetQuantifier, + @JvmField internal val isOuter: Boolean, + @JvmField internal val lhs: Rel, + @JvmField internal val rhs: Rel, ) : Op() { - internal override val children: List by lazy { + public override val children: List by lazy { val kids = mutableListOf() kids.add(lhs) kids.add(rhs) kids.filterNotNull() } - - override fun accept(visitor: PlanVisitor, ctx: C): R = - visitor.visitRelOpUnion(this, ctx) + override fun accept(visitor: PlanVisitor, ctx: C): R = visitor.visitRelOpUnion(this, ctx) internal companion object { @JvmStatic internal fun builder(): RelOpUnionBuilder = RelOpUnionBuilder() } } - + internal data class Intersect( - @JvmField - internal val setq: SetQuantifier, - @JvmField - internal val isOuter: Boolean, - @JvmField - internal val lhs: Rel, - @JvmField - internal val rhs: Rel, + @JvmField internal val setq: SetQuantifier, + @JvmField internal val isOuter: Boolean, + @JvmField internal val lhs: Rel, + @JvmField internal val rhs: Rel, ) : Op() { - internal override val children: List by lazy { + public override val children: List by lazy { val kids = mutableListOf() kids.add(lhs) kids.add(rhs) kids.filterNotNull() } - - override fun accept(visitor: PlanVisitor, ctx: C): R = - visitor.visitRelOpIntersect(this, ctx) + override fun accept(visitor: PlanVisitor, ctx: C): R = visitor.visitRelOpIntersect(this, ctx) internal companion object { @JvmStatic internal fun builder(): RelOpIntersectBuilder = RelOpIntersectBuilder() } } - + internal data class Except( - @JvmField - internal val setq: SetQuantifier, - @JvmField - internal val isOuter: Boolean, - @JvmField - internal val lhs: Rel, - @JvmField - internal val rhs: Rel, + @JvmField internal val setq: SetQuantifier, + @JvmField internal val isOuter: Boolean, + @JvmField internal val lhs: Rel, + @JvmField internal val rhs: Rel, ) : Op() { - internal override val children: List by lazy { + public override val children: List by lazy { val kids = mutableListOf() kids.add(lhs) kids.add(rhs) kids.filterNotNull() } - - override fun accept(visitor: PlanVisitor, ctx: C): R = - visitor.visitRelOpExcept(this, ctx) + override fun accept(visitor: PlanVisitor, ctx: C): R = visitor.visitRelOpExcept(this, ctx) internal companion object { @JvmStatic @@ -1050,8 +1038,7 @@ internal data class Rel( kids.filterNotNull() } - override fun accept(visitor: PlanVisitor, ctx: C): R = - visitor.visitRelOpLimit(this, ctx) + override fun accept(visitor: PlanVisitor, ctx: C): R = visitor.visitRelOpLimit(this, ctx) internal companion object { @JvmStatic @@ -1070,8 +1057,7 @@ internal data class Rel( kids.filterNotNull() } - override fun accept(visitor: PlanVisitor, ctx: C): R = - visitor.visitRelOpOffset(this, ctx) + override fun accept(visitor: PlanVisitor, ctx: C): R = visitor.visitRelOpOffset(this, ctx) internal companion object { @JvmStatic @@ -1090,8 +1076,7 @@ internal data class Rel( kids.filterNotNull() } - override fun accept(visitor: PlanVisitor, ctx: C): R = - visitor.visitRelOpProject(this, ctx) + override fun accept(visitor: PlanVisitor, ctx: C): R = visitor.visitRelOpProject(this, ctx) internal companion object { @JvmStatic @@ -1139,8 +1124,7 @@ internal data class Rel( kids.filterNotNull() } - override fun accept(visitor: PlanVisitor, ctx: C): R = - visitor.visitRelOpAggregate(this, ctx) + override fun accept(visitor: PlanVisitor, ctx: C): R = visitor.visitRelOpAggregate(this, ctx) internal enum class Strategy { FULL, PARTIAL, @@ -1212,8 +1196,7 @@ internal data class Rel( kids.filterNotNull() } - override fun accept(visitor: PlanVisitor, ctx: C): R = - visitor.visitRelOpExclude(this, ctx) + override fun accept(visitor: PlanVisitor, ctx: C): R = visitor.visitRelOpExclude(this, ctx) internal data class Path( @JvmField internal val root: Rex.Op, @@ -1396,6 +1379,5 @@ internal data class Rel( } internal enum class SetQuantifier { - ALL, - DISTINCT, + ALL, DISTINCT, } diff --git a/partiql-planner/src/main/kotlin/org/partiql/planner/internal/transforms/PlanTransformV1.kt b/partiql-planner/src/main/kotlin/org/partiql/planner/internal/transforms/PlanTransformV1.kt new file mode 100644 index 0000000000..bcbb8078dc --- /dev/null +++ b/partiql-planner/src/main/kotlin/org/partiql/planner/internal/transforms/PlanTransformV1.kt @@ -0,0 +1,466 @@ +package org.partiql.planner.internal.transforms + +import org.partiql.errors.Problem +import org.partiql.errors.ProblemCallback +import org.partiql.eval.value.Datum +import org.partiql.plan.v1.PartiQLPlan +import org.partiql.plan.v1.Schema +import org.partiql.plan.v1.Statement +import org.partiql.plan.v1.builder.PlanFactory +import org.partiql.plan.v1.operator.rel.Rel +import org.partiql.plan.v1.operator.rel.RelAggregateCall +import org.partiql.plan.v1.operator.rel.RelCollation +import org.partiql.plan.v1.operator.rel.RelError +import org.partiql.plan.v1.operator.rel.RelExcludePath +import org.partiql.plan.v1.operator.rel.RelExcludeStep +import org.partiql.plan.v1.operator.rel.RelJoinType +import org.partiql.plan.v1.operator.rex.Rex +import org.partiql.plan.v1.operator.rex.RexCase +import org.partiql.plan.v1.operator.rex.RexStruct +import org.partiql.plan.v1.operator.rex.RexVar +import org.partiql.planner.internal.PlannerFlag +import org.partiql.planner.internal.ProblemGenerator +import org.partiql.planner.internal.ir.Ref +import org.partiql.planner.internal.ir.SetQuantifier +import org.partiql.planner.internal.ir.visitor.PlanBaseVisitor +import org.partiql.spi.fn.Agg +import org.partiql.spi.fn.Fn +import org.partiql.spi.fn.SqlFnProvider +import org.partiql.types.Field +import org.partiql.types.PType +import org.partiql.value.PartiQLValueExperimental +import org.partiql.planner.internal.ir.PartiQLPlan as IPlan +import org.partiql.planner.internal.ir.PlanNode as INode +import org.partiql.planner.internal.ir.Rel as IRel +import org.partiql.planner.internal.ir.Rex as IRex +import org.partiql.planner.internal.ir.Statement as IStatement + +/** + * This produces a V1 plan from the internal plan IR. + * + * TODO types and schemas! + */ +internal class PlanTransformV1(private val flags: Set) { + + /** + * Transform the internal IR to the public plan interfaces. + * + * @param internal + * @param onProblem + * @return + */ + fun transform(internal: IPlan, onProblem: ProblemCallback): PartiQLPlan { + val signal = flags.contains(PlannerFlag.SIGNAL_MODE) + val query = (internal.statement as IStatement.Query) + val visitor = Visitor(onProblem, signal) + val root = visitor.visitRex(query.root, query.root.type) + // TODO replace with standard implementations (or just remove plan transform altogether when possible). + return object : PartiQLPlan { + override fun getStatement(): Statement = object : Statement.Query { + override fun getRoot(): Rex = root + } + } + } + + private class Visitor( + private val onProblem: ProblemCallback, + private val signal: Boolean, + ) : PlanBaseVisitor() { + + private val factory = PlanFactory.STANDARD + + override fun defaultReturn(node: INode, ctx: PType): Any { + TODO("Translation not supported for ${node::class.simpleName}") + } + + // ERRORS + + override fun visitRexOpMissing(node: IRex.Op.Missing, ctx: PType): Any { + val trace = node.causes.map { visitRexOp(it, ctx) } + return when (signal) { + true -> { + onProblem.invoke(ProblemGenerator.asError(node.problem)) + err(node.problem, trace) + } + false -> { + onProblem.invoke(ProblemGenerator.asWarning(node.problem)) + factory.rexMissing(node.problem.toString(), trace) + } + } + } + + override fun visitRexOpErr(node: IRex.Op.Err, ctx: PType): Any { + val message = node.problem.toString() + val trace = node.causes.map { visitRexOp(it, ctx) } + onProblem(ProblemGenerator.asError(node.problem)) + return factory.rexError(message, trace) + } + + override fun visitRelOpErr(node: org.partiql.planner.internal.ir.Rel.Op.Err, ctx: PType): Any { + val message = node.message + onProblem(ProblemGenerator.compilerError(message)) + return RelError(message) + } + + // EXPRESSIONS + + override fun visitRex(node: IRex, ctx: PType): Rex = super.visitRexOp(node.op, node.type) as Rex + + override fun visitRexOp(node: IRex.Op, ctx: PType): Rex = super.visitRexOp(node, ctx) as Rex + + override fun visitRexOpTupleUnion(node: IRex.Op.TupleUnion, ctx: PType): Any { + val args = node.args.map { visitRex(it, ctx) } + return factory.rexSpread(args) + } + + override fun visitRexOpSelect(node: IRex.Op.Select, ctx: PType): Any { + val input = visitRel(node.rel, ctx) + val constructor = visitRex(node.constructor, ctx) + return factory.rexSelect(input, constructor) + } + + /** + * TODO proper handling of subqueries in the planner. + * + * @param node + * @param ctx + * @return + */ + override fun visitRexOpSubquery(node: IRex.Op.Subquery, ctx: PType): Any { + val input = visitRel(node.rel, ctx) + val constructor = visitRex(node.constructor, ctx) + val isScalar = node.coercion == IRex.Op.Subquery.Coercion.SCALAR + return factory.rexSubquery(input, constructor, isScalar) + } + + override fun visitRexOpPivot(node: IRex.Op.Pivot, ctx: PType): Any { + val input = visitRel(node.rel, ctx) + val key = visitRex(node.key, ctx) + val value = visitRex(node.value, ctx) + return factory.rexPivot(input, key, value) + } + + override fun visitRexOpStruct(node: IRex.Op.Struct, ctx: PType): Any { + val fields = node.fields.map { field(it) } + return factory.rexStruct(fields) + } + + override fun visitRexOpCollection(node: IRex.Op.Collection, ctx: PType): Any { + val values = node.values.map { visitRex(it, ctx) } + return when (ctx.kind) { + PType.Kind.ARRAY -> factory.rexArray(values) + PType.Kind.BAG -> factory.rexBag(values) + else -> error("Expected bag or array, found ${ctx.kind.name.lowercase()}") + } + } + + override fun visitRexOpCoalesce(node: IRex.Op.Coalesce, ctx: PType): Any { + val args = node.args.map { visitRex(it, ctx) } + return factory.rexCoalesce(args) + } + + override fun visitRexOpNullif(node: IRex.Op.Nullif, ctx: PType): Any { + val value = visitRex(node.value, ctx) + val nullifier = visitRex(node.nullifier, ctx) + return factory.rexNullIf(value, nullifier) + } + + override fun visitRexOpCase(node: IRex.Op.Case, ctx: PType): Any { + val branches = node.branches.map { branch(it) } + val default = visitRex(node.default, ctx) + return factory.rexCase(branches, default) + } + + override fun visitRexOpCallDynamic(node: IRex.Op.Call.Dynamic, ctx: PType): Any { + val fns = node.candidates.map { getFn(it.fn) } + val args = node.args.map { visitRex(it, ctx) } + return factory.rexCall(fns, args) + } + + override fun visitRexOpCallStatic(node: IRex.Op.Call.Static, ctx: PType): Any { + val fn = getFn(node.fn) + val args = node.args.map { visitRex(it, ctx) } + return factory.rexCall(fn, args) + } + + override fun visitRexOpCallUnresolved(node: IRex.Op.Call.Unresolved, ctx: PType): Any { + error("The Internal Node Rex.Op.Call.Unresolved should be converted to an Err Node during type resolution if resolution failed") + } + + /** + * TODO the following comment comes from the existing implementation, but how does it apply to CAST ?? + * + * See PartiQL Specification [Section 4.1.1](https://partiql.org/partiql-lang/#sec:schema-in-tuple-path). + * While it talks about pathing into a tuple, it provides guidance on expressions that always return missing: + * + * > In a more important and common case, an PartiQL implementation can utilize the input data schema to prove + * > that a path expression always returns MISSING and thus throw a compile-time error. + * + * This is accomplished via the signaling mode below. + */ + override fun visitRexOpCastUnresolved(node: IRex.Op.Cast.Unresolved, ctx: PType): Any { + val problem = ProblemGenerator.undefinedCast(node.arg.type, node.target) + return when (signal) { + true -> { + onProblem.invoke(problem) + err(problem, emptyList()) + } + false -> { + onProblem.invoke(ProblemGenerator.asWarning(problem)) + factory.rexMissing(problem.toString(), emptyList()) + } + } + } + + override fun visitRexOpCastResolved(node: IRex.Op.Cast.Resolved, ctx: PType): Any { + val operand = visitRex(node.arg, ctx) + val target = node.cast.target + return factory.rexCast(operand, target) + } + + override fun visitRexOpPathSymbol(node: IRex.Op.Path.Symbol, ctx: PType): Any { + val operand = visitRex(node.root, ctx) + val symbol = node.key + return factory.rexPathSymbol(operand, symbol) + } + + override fun visitRexOpPathKey(node: IRex.Op.Path.Key, ctx: PType): Any { + val operand = visitRex(node.root, ctx) + val key = visitRex(node.key, ctx) + return factory.rexPathKey(operand, key) + } + + override fun visitRexOpPathIndex(node: IRex.Op.Path.Index, ctx: PType): Any { + val operand = visitRex(node.root, ctx) + val index = visitRex(node.key, ctx) + return factory.rexPathIndex(operand, index) + } + + override fun visitRexOpVarGlobal(node: IRex.Op.Var.Global, ctx: PType): Any { + return factory.rexTable(node.ref.table) + } + + override fun visitRexOpVarUnresolved(node: IRex.Op.Var.Unresolved, ctx: PType): Any { + error("The Internal Plan Node Rex.Op.Var.Unresolved should be converted to an MISSING Node during type resolution if resolution failed") + } + + override fun visitRexOpVarLocal(node: IRex.Op.Var.Local, ctx: PType): Any { + return factory.rexVar(depth = node.depth, offset = node.ref) + } + + @OptIn(PartiQLValueExperimental::class) + override fun visitRexOpLit(node: IRex.Op.Lit, ctx: PType): Any { + return factory.rexLit(Datum.of(node.value)) + } + + // RELATION OPERATORS + + override fun visitRel(node: IRel, ctx: PType): Rel = super.visitRelOp(node.op, ctx) as Rel + + override fun visitRelOp(node: IRel.Op, ctx: PType): Rel = super.visitRelOp(node, ctx) as Rel + + override fun visitRelOpAggregate(node: IRel.Op.Aggregate, ctx: PType): Any { + val input = visitRel(node.input, ctx) + val calls = node.calls.map { visitRelOpAggregateCall(it, ctx) as RelAggregateCall } + val groups = node.groups.map { visitRex(it, ctx) } + return factory.relAggregate(input, calls, groups) + } + + override fun visitRelOpAggregateCallUnresolved(node: IRel.Op.Aggregate.Call.Unresolved, ctx: PType): Any { + error("Unresolved aggregate call $node") + } + + override fun visitRelOpAggregateCallResolved(node: IRel.Op.Aggregate.Call.Resolved, ctx: PType): Any { + val agg = getAgg(node.agg) + val args = node.args.map { visitRex(it, ctx) } + val isDistinct = node.setq == SetQuantifier.DISTINCT + return factory.relAggregateCall(agg, args, isDistinct) + } + + override fun visitRelOpJoin(node: IRel.Op.Join, ctx: PType): Any { + val lhs = visitRel(node.lhs, ctx) + val rhs = visitRel(node.rhs, ctx) + val condition = visitRex(node.rex, ctx) + + // TODO CLEANUP JOIN SCHEMA + val lhsType = toSchema(node.lhs.type) + val rhsType = toSchema(node.rhs.type) + + val type = when (node.type) { + IRel.Op.Join.Type.INNER -> RelJoinType.INNER + IRel.Op.Join.Type.LEFT -> RelJoinType.LEFT + IRel.Op.Join.Type.RIGHT -> RelJoinType.RIGHT + IRel.Op.Join.Type.FULL -> RelJoinType.FULL + } + return factory.relJoin(lhs, rhs, condition, type, lhsType, rhsType) + } + + override fun visitRelOpExclude(node: IRel.Op.Exclude, ctx: PType): Any { + val input = visitRel(node.input, ctx) + val paths = node.paths.map { visitRelOpExcludePath(it, ctx) as RelExcludePath } + return factory.relExclude(input, paths) + } + + override fun visitRelOpExcludePath(node: IRel.Op.Exclude.Path, ctx: PType): Any { + val root = visitRexOp(node.root, ctx) as RexVar + val steps = node.steps.map { visitRelOpExcludeStep(it, ctx) as RelExcludeStep } + return RelExcludePath.of(root, steps) + } + + override fun visitRelOpExcludeStep(node: IRel.Op.Exclude.Step, ctx: PType): Any { + val substeps = node.substeps.map { visitRelOpExcludeStep(it, ctx) as RelExcludeStep } + return when (node.type) { + is IRel.Op.Exclude.Type.CollIndex -> RelExcludeStep.index(node.type.index, substeps) + is IRel.Op.Exclude.Type.CollWildcard -> RelExcludeStep.collection(substeps) + is IRel.Op.Exclude.Type.StructKey -> RelExcludeStep.key(node.type.key, substeps) + is IRel.Op.Exclude.Type.StructSymbol -> RelExcludeStep.symbol(node.type.symbol, substeps) + is IRel.Op.Exclude.Type.StructWildcard -> RelExcludeStep.struct(substeps) + } + } + + override fun visitRelOpProject(node: IRel.Op.Project, ctx: PType): Any { + val input = visitRel(node.input, ctx) + val projections = node.projections.map { visitRex(it, ctx) } + return factory.relProject(input, projections) + } + + override fun visitRelOpOffset(node: IRel.Op.Offset, ctx: PType): Any { + val input = visitRel(node.input, ctx) + val offset = visitRex(node.offset, ctx) + return factory.relOffset(input, offset) + } + + override fun visitRelOpLimit(node: IRel.Op.Limit, ctx: PType): Any { + val input = visitRel(node.input, ctx) + val limit = visitRex(node.limit, ctx) + return factory.relLimit(input, limit) + } + + override fun visitRelOpIntersect(node: IRel.Op.Intersect, ctx: PType): Any { + val lhs = visitRel(node.lhs, ctx) + val rhs = visitRel(node.rhs, ctx) + val isAll = node.setq == SetQuantifier.ALL + return factory.relIntersect(lhs, rhs, isAll) + } + + override fun visitRelOpUnion(node: IRel.Op.Union, ctx: PType): Any { + val lhs = visitRel(node.lhs, ctx) + val rhs = visitRel(node.rhs, ctx) + val isAll = node.setq == SetQuantifier.ALL + return factory.relUnion(lhs, rhs, isAll) + } + + override fun visitRelOpExcept(node: IRel.Op.Except, ctx: PType): Any { + val lhs = visitRel(node.lhs, ctx) + val rhs = visitRel(node.rhs, ctx) + val isAll = node.setq == SetQuantifier.ALL + return factory.relExcept(lhs, rhs, isAll) + } + + override fun visitRelOpSort(node: IRel.Op.Sort, ctx: PType): Any { + val input = visitRel(node.input, ctx) + val collations = node.specs.map { collation(it) } + return factory.relSort(input, collations) + } + + override fun visitRelOpFilter(node: IRel.Op.Filter, ctx: PType): Any { + val input = visitRel(node.input, ctx) + val condition = visitRex(node.predicate, ctx) + return factory.relFilter(input, condition) + } + + override fun visitRelOpDistinct(node: IRel.Op.Distinct, ctx: PType): Any { + val input = visitRel(node.input, ctx) + return factory.relDistinct(input) + } + + override fun visitRelOpUnpivot(node: IRel.Op.Unpivot, ctx: PType): Any { + val input = visitRex(node.rex, ctx) + return factory.relUnpivot(input) + } + + override fun visitRelOpScanIndexed(node: IRel.Op.ScanIndexed, ctx: PType): Any { + val input = visitRex(node.rex, ctx) + return factory.relIterate(input) + } + + override fun visitRelOpScan(node: IRel.Op.Scan, ctx: PType): Any { + val input = visitRex(node.rex, ctx) + return factory.relScan(input) + } + + // HELPERS + + /** + * TODO STANDARD COLLATION IMPLEMENTATION. + */ + private fun collation(spec: IRel.Op.Sort.Spec): RelCollation { + val rex = visitRex(spec.rex, spec.rex.type) + val (order, nulls) = when (spec.order) { + IRel.Op.Sort.Order.ASC_NULLS_LAST -> RelCollation.Order.ASC to RelCollation.Nulls.LAST + IRel.Op.Sort.Order.ASC_NULLS_FIRST -> RelCollation.Order.ASC to RelCollation.Nulls.FIRST + IRel.Op.Sort.Order.DESC_NULLS_LAST -> RelCollation.Order.DESC to RelCollation.Nulls.LAST + IRel.Op.Sort.Order.DESC_NULLS_FIRST -> RelCollation.Order.DESC to RelCollation.Nulls.FIRST + } + return object : RelCollation { + override fun getRex(): Rex = rex + override fun getOrder(): RelCollation.Order = order + override fun getNulls(): RelCollation.Nulls = nulls + } + } + + private fun field(field: IRex.Op.Struct.Field): RexStruct.Field { + val key = visitRex(field.k, field.k.type) + val value = visitRex(field.v, field.v.type) + return object : RexStruct.Field { + override fun getKey(): Rex = key + override fun getValue(): Rex = value + } + } + + private fun branch(branch: IRex.Op.Case.Branch): RexCase.Branch { + val condition = visitRex(branch.condition, branch.condition.type) + val result = visitRex(branch.rex, branch.rex.type) + return object : RexCase.Branch { + override fun getCondition(): Rex = condition + override fun getResult(): Rex = result + } + } + + private fun err(problem: Problem, trace: List): Rex = when (signal) { + true -> { + onProblem(ProblemGenerator.asError(problem)) + factory.rexError(message = problem.toString(), trace) + } + false -> { + onProblem(ProblemGenerator.asWarning(problem)) + factory.rexMissing(message = problem.toString(), trace) + } + } + + /** + * TODO TEMPORARY! + */ + private fun getFn(ref: Ref.Fn): Fn { + val specific = ref.signature.specific + return SqlFnProvider.getFn(specific) ?: error("Function not found: $specific") + } + + /** + * TODO TEMPORARY! + */ + private fun getAgg(ref: Ref.Agg): Agg { + val specific = ref.signature.specific + return SqlFnProvider.getAgg(specific) ?: error("Aggregation not found: $specific") + } + + /** + * TODO TEMPORARY! + */ + private fun toSchema(type: IRel.Type): Schema = object : Schema { + private val fields = type.schema.map { Field.of(it.name, it.type) } + override fun getFields(): List = fields + override fun getField(name: String): Field = fields.first { it.name == name } + } + } +} diff --git a/partiql-planner/src/main/resources/partiql_plan_internal.ion b/partiql-planner/src/main/resources/partiql_plan_internal.ion index b210934d39..1cfa36ed79 100644 --- a/partiql-planner/src/main/resources/partiql_plan_internal.ion +++ b/partiql-planner/src/main/resources/partiql_plan_internal.ion @@ -7,7 +7,8 @@ imports::{ static_type::'org.partiql.planner.internal.typer.CompilerType', fn_signature::'org.partiql.spi.fn.FnSignature', agg_signature::'org.partiql.spi.fn.AggSignature', - problem::'org.partiql.errors.Problem' + problem::'org.partiql.errors.Problem', + table::'org.partiql.planner.catalog.Table', ], } @@ -25,6 +26,8 @@ ref::[ catalog: string, name: name, type: static_type, + // TEMPORARY FOR V1 EXECUTION + table: table, }, fn::{ catalog: string, diff --git a/partiql-planner/src/test/kotlin/org/partiql/planner/internal/typer/PlanTyperTest.kt b/partiql-planner/src/test/kotlin/org/partiql/planner/internal/typer/PlanTyperTest.kt index 5254f40f12..1b1bcdc0f3 100644 --- a/partiql-planner/src/test/kotlin/org/partiql/planner/internal/typer/PlanTyperTest.kt +++ b/partiql-planner/src/test/kotlin/org/partiql/planner/internal/typer/PlanTyperTest.kt @@ -5,6 +5,7 @@ import org.junit.jupiter.api.Test import org.partiql.planner.catalog.Identifier import org.partiql.planner.catalog.Name import org.partiql.planner.catalog.Session +import org.partiql.planner.catalog.Table import org.partiql.planner.internal.Env import org.partiql.planner.internal.ir.Rex import org.partiql.planner.internal.ir.Statement @@ -324,10 +325,10 @@ class PlanTyperTest { } private fun global(type: CompilerType, path: List): Rex { - return rex( - type, - rexOpVarGlobal(refObj(catalog = "pql", name = Name.of(path), type)) - ) + val catalog = "pql" + val name = Name.of(path) + val table = Table.Companion.empty(name, type) + return rex(type, rexOpVarGlobal(refObj(catalog, name, type, table))) } private fun assertEquals(expected: Statement, actual: Statement) { diff --git a/test/partiql-tests-runner/src/test/kotlin/org/partiql/runner/ConformanceTestEval.kt b/test/partiql-tests-runner/src/test/kotlin/org/partiql/runner/ConformanceTestEval.kt index ed15d7d134..36445956ed 100644 --- a/test/partiql-tests-runner/src/test/kotlin/org/partiql/runner/ConformanceTestEval.kt +++ b/test/partiql-tests-runner/src/test/kotlin/org/partiql/runner/ConformanceTestEval.kt @@ -9,7 +9,7 @@ import org.partiql.runner.executor.EvalExecutor import org.partiql.runner.report.ReportGenerator import org.partiql.runner.test.TestRunner -class ConformanceTestEval : ConformanceTestBase, PartiQLResult>() { +class ConformanceTestEval : ConformanceTestBase() { companion object { @JvmStatic @RegisterExtension diff --git a/test/partiql-tests-runner/src/test/kotlin/org/partiql/runner/executor/EvalExecutor.kt b/test/partiql-tests-runner/src/test/kotlin/org/partiql/runner/executor/EvalExecutor.kt index cb3bee2a0d..90cf3e0650 100644 --- a/test/partiql-tests-runner/src/test/kotlin/org/partiql/runner/executor/EvalExecutor.kt +++ b/test/partiql-tests-runner/src/test/kotlin/org/partiql/runner/executor/EvalExecutor.kt @@ -17,6 +17,8 @@ import org.partiql.parser.PartiQLParser import org.partiql.plan.Statement import org.partiql.planner.PartiQLPlanner import org.partiql.planner.catalog.Name +import org.partiql.planner.catalog.Session +import org.partiql.planner.internal.SqlPlannerV1 import org.partiql.plugins.memory.MemoryConnector import org.partiql.plugins.memory.MemoryTable import org.partiql.runner.ION @@ -27,22 +29,22 @@ import org.partiql.value.PartiQLValue import org.partiql.value.PartiQLValueExperimental import org.partiql.value.io.PartiQLValueIonReaderBuilder import org.partiql.value.toIon -import org.partiql.planner.catalog.Session as PlannerSession @OptIn(PartiQLValueExperimental::class) class EvalExecutor( - private val plannerSession: PlannerSession, - private val evalSession: PartiQLEngine.Session, -) : TestExecutor, PartiQLResult> { + private val session: Session, + private val mode: PartiQLEngine.Mode, +) : TestExecutor { - override fun prepare(statement: String): PartiQLStatement<*> { + override fun prepare(statement: String): PartiQLStatement { val stmt = parser.parse(statement).root - val plan = planner.plan(stmt, plannerSession) - return engine.prepare(plan.plan, evalSession) + // TODO TEMPORARY REMOVE SqlPlannerV1 once existing public plan is removed. + val plan = SqlPlannerV1.plan(stmt, session) {} + return engine.prepare(plan, mode, session) } - override fun execute(statement: PartiQLStatement<*>): PartiQLResult { - return engine.execute(statement) + override fun execute(statement: PartiQLStatement): PartiQLResult { + return statement.execute(session) } override fun fromIon(value: IonValue): PartiQLResult { @@ -112,35 +114,25 @@ class EvalExecutor( companion object { val parser = PartiQLParser.default() val planner = PartiQLPlanner.standard() - val engine = PartiQLEngine.default() + val engine = PartiQLEngine.standard() val comparator = PartiQLValue.comparator() } - object Factory : TestExecutor.Factory, PartiQLResult> { - - override fun create(env: IonStruct, options: CompileOptions): TestExecutor, PartiQLResult> { + object Factory : TestExecutor.Factory { + override fun create(env: IonStruct, options: CompileOptions): TestExecutor { // infer catalog from conformance test `env` val catalog = "default" val connector = infer(env.toIonElement() as StructElement) - - val session = PlannerSession.builder() + val session = Session.builder() .catalog(catalog) .catalogs(connector.getCatalog()) .build() - val mode = when (options.typingMode) { TypingMode.PERMISSIVE -> PartiQLEngine.Mode.PERMISSIVE TypingMode.LEGACY -> PartiQLEngine.Mode.STRICT } - - val evalSession = PartiQLEngine.Session( - catalogs = mutableMapOf( - "default" to connector - ), - mode = mode - ) - return EvalExecutor(session, evalSession) + return EvalExecutor(session, mode) } /** @@ -165,7 +157,7 @@ class EvalExecutor( */ private fun inferEnv(env: AnyElement): PType { val catalog = MemoryConnector.builder().name("default").build().getCatalog() - val session = PlannerSession.builder() + val session = Session.builder() .catalog("default") .catalogs(catalog) .build() @@ -183,11 +175,11 @@ class EvalExecutor( for (f in env.fields) { val name = Name.of(f.name) - // WITH SHIM (233 failures) + // TODO REMOVE SHIM val value = PartiQLValueIonReaderBuilder.standard().build(f.value).read() val datum = Datum.of(value) - // NO SHIM (343 failures) + // TODO REMOVE SHIM // val datum = IonDatum.of(f.value) val table = MemoryTable.of(