Skip to content

Simplifies logical model of the path expression #1306

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Dec 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 8 additions & 22 deletions partiql-plan/src/main/resources/partiql_plan.ion
Original file line number Diff line number Diff line change
Expand Up @@ -90,30 +90,16 @@ rex::{
ref: '.catalog.symbol.ref'
},

path::{
root: rex,
steps: list::[step],
_: [
step::[
// The key MUST be an integer expression. Ex: a[0], a[1 + 1]
index::{ key: rex },

// Case-sensitive lookup. The key MUST be a string expression. Ex: a["b"], a."b", a[CAST(b AS STRING)]
key::{ key: rex },

// Case-insensitive lookup. The key MUST be a literal string. Ex: a.b
symbol::{ key: string },
path::[
// The key MUST be an integer expression. Ex: a[0], a[1 + 1]
index::{ root: rex, key: rex },

// For arrays. Ex: a[*]
// TODO: Do we need this? According to specification: [1,2,3][*] ⇔ SELECT VALUE v FROM [1, 2, 3] AS v
wildcard::{},
// Case-sensitive lookup. The key MUST be a string expression. Ex: a["b"], a."b", a[CAST(b AS STRING)]
key::{ root: rex, key: rex },

// For tuples. Ex: a.*
// TODO: Do we need this? According to specification: {'a':1, 'b':2}.* ⇔ SELECT VALUE v FROM UNPIVOT {'a':1, 'b':2} AS v
unpivot::{},
],
],
},
// Case-insensitive lookup. The key MUST be a literal string. Ex: a.b
symbol::{ root: rex, key: string },
],

call::[
static::{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,13 @@ internal class TypeEnv(

/**
* Metadata regarding a resolved variable.
* @property depth The depth/level of the path match.
*/
internal sealed interface ResolvedVar {

public val type: StaticType
public val ordinal: Int
public val depth: Int

/**
* Metadata for a resolved local variable.
Expand All @@ -83,7 +85,7 @@ internal sealed interface ResolvedVar {
override val ordinal: Int,
val rootType: StaticType,
val replacementSteps: List<BindingName>,
val depth: Int
override val depth: Int
) : ResolvedVar

/**
Expand All @@ -97,7 +99,7 @@ internal sealed interface ResolvedVar {
class Global(
override val type: StaticType,
override val ordinal: Int,
val depth: Int,
override val depth: Int,
val position: Int
) : ResolvedVar
}
Expand Down
181 changes: 57 additions & 124 deletions partiql-planner/src/main/kotlin/org/partiql/planner/internal/ir/Nodes.kt
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,9 @@ import org.partiql.planner.internal.ir.builder.RexOpCollectionBuilder
import org.partiql.planner.internal.ir.builder.RexOpErrBuilder
import org.partiql.planner.internal.ir.builder.RexOpGlobalBuilder
import org.partiql.planner.internal.ir.builder.RexOpLitBuilder
import org.partiql.planner.internal.ir.builder.RexOpPathBuilder
import org.partiql.planner.internal.ir.builder.RexOpPathStepIndexBuilder
import org.partiql.planner.internal.ir.builder.RexOpPathStepSymbolBuilder
import org.partiql.planner.internal.ir.builder.RexOpPathStepUnpivotBuilder
import org.partiql.planner.internal.ir.builder.RexOpPathStepWildcardBuilder
import org.partiql.planner.internal.ir.builder.RexOpPathIndexBuilder
import org.partiql.planner.internal.ir.builder.RexOpPathKeyBuilder
import org.partiql.planner.internal.ir.builder.RexOpPathSymbolBuilder
import org.partiql.planner.internal.ir.builder.RexOpPivotBuilder
import org.partiql.planner.internal.ir.builder.RexOpSelectBuilder
import org.partiql.planner.internal.ir.builder.RexOpStructBuilder
Expand Down Expand Up @@ -433,142 +431,77 @@ internal data class Rex(
}
}

internal data class Path(
@JvmField
internal val root: Rex,
@JvmField
internal val steps: List<Step>,
) : Op() {
internal override val children: List<PlanNode> by lazy {
val kids = mutableListOf<PlanNode?>()
kids.add(root)
kids.addAll(steps)
kids.filterNotNull()
internal sealed class Path : Op() {
internal override fun <R, C> accept(visitor: PlanVisitor<R, C>, ctx: C): R = when (this) {
is Index -> visitor.visitRexOpPathIndex(this, ctx)
is Key -> visitor.visitRexOpPathKey(this, ctx)
is Symbol -> visitor.visitRexOpPathSymbol(this, ctx)
}

internal override fun <R, C> accept(visitor: PlanVisitor<R, C>, ctx: C): R =
visitor.visitRexOpPath(this, ctx)

internal sealed class Step : PlanNode() {
internal override fun <R, C> accept(visitor: PlanVisitor<R, C>, ctx: C): R = when (this) {
is Index -> visitor.visitRexOpPathStepIndex(this, ctx)
is Symbol -> visitor.visitRexOpPathStepSymbol(this, ctx)
is Wildcard -> visitor.visitRexOpPathStepWildcard(this, ctx)
is Unpivot -> visitor.visitRexOpPathStepUnpivot(this, ctx)
is Key -> visitor.visitRexOpPathStepKey(this, ctx)
internal data class Index(
@JvmField
internal val root: Rex,
@JvmField
internal val key: Rex,
) : Path() {
internal override val children: List<PlanNode> by lazy {
val kids = mutableListOf<PlanNode?>()
kids.add(root)
kids.add(key)
kids.filterNotNull()
}

internal data class Index(
@JvmField
internal val key: Rex,
) : Step() {
internal override val children: List<PlanNode> by lazy {
val kids = mutableListOf<PlanNode?>()
kids.add(key)
kids.filterNotNull()
}

internal override fun <R, C> accept(visitor: PlanVisitor<R, C>, ctx: C): R =
visitor.visitRexOpPathStepIndex(this, ctx)
internal override fun <R, C> accept(visitor: PlanVisitor<R, C>, ctx: C): R =
visitor.visitRexOpPathIndex(this, ctx)

internal companion object {
@JvmStatic
internal fun builder(): RexOpPathStepIndexBuilder = RexOpPathStepIndexBuilder()
}
internal companion object {
@JvmStatic
internal fun builder(): RexOpPathIndexBuilder = RexOpPathIndexBuilder()
}
}

/**
* This represents a case-sensitive lookup on a tuple. Ex: a['b'] or a[CAST('a' || 'b' AS STRING)].
* This would normally contain the dot notation for case-sensitive lookup, however, due to
* limitations -- we cannot consolidate these. See [Symbol] for more information.
*
* The main difference is that this does NOT include `a."b"`
*/
internal data class Key(
@JvmField
internal val key: Rex,
) : Step() {
internal override val children: List<PlanNode> by lazy {
val kids = mutableListOf<PlanNode?>()
kids.add(key)
kids.filterNotNull()
}

internal override fun <R, C> accept(visitor: PlanVisitor<R, C>, ctx: C): R =
visitor.visitRexOpPathStepKey(this, ctx)

internal companion object {
@JvmStatic
internal fun builder(): RexOpPathStepIndexBuilder = RexOpPathStepIndexBuilder()
}
internal data class Key(
@JvmField
internal val root: Rex,
@JvmField
internal val key: Rex,
) : Path() {
internal override val children: List<PlanNode> by lazy {
val kids = mutableListOf<PlanNode?>()
kids.add(root)
kids.add(key)
kids.filterNotNull()
}

/**
* This represents a lookup on a tuple. We differentiate a [Key] and a [Symbol] at this point in the
* pipeline because we NEED to retain some syntactic knowledge for the following reason: we cannot
* use the syntactic index operation on a schema -- as it is not synonymous with a tuple. In other words,
* `<schema-name>."<value-name>"` is not interchangeable with `<schema-name>['<value-name>']`.
*
* So, in order to temporarily differentiate the `a."b"` from `a['b']` (see [Key]), we need to maintain
* the syntactic difference here. Note that this would potentially be mitigated by typing during the AST to Plan
* transformation.
*
* That being said, this represents a lookup on a tuple such as `a.b` or `a."b"`.
*/
internal data class Symbol(
@JvmField
internal val identifier: Identifier.Symbol,
) : Step() {
internal override val children: List<PlanNode> by lazy {
val kids = mutableListOf<PlanNode?>()
kids.add(identifier)
kids.filterNotNull()
}

internal override fun <R, C> accept(visitor: PlanVisitor<R, C>, ctx: C): R =
visitor.visitRexOpPathStepSymbol(this, ctx)
internal override fun <R, C> accept(visitor: PlanVisitor<R, C>, ctx: C): R =
visitor.visitRexOpPathKey(this, ctx)

internal companion object {
@JvmStatic
internal fun builder(): RexOpPathStepSymbolBuilder = RexOpPathStepSymbolBuilder()
}
internal companion object {
@JvmStatic
fun builder(): RexOpPathKeyBuilder = RexOpPathKeyBuilder()
}
}

internal data class Wildcard(
@JvmField
internal val ` `: Char = ' ',
) : Step() {
internal override val children: List<PlanNode> = emptyList()

internal override fun <R, C> accept(visitor: PlanVisitor<R, C>, ctx: C): R =
visitor.visitRexOpPathStepWildcard(this, ctx)

internal companion object {
@JvmStatic
internal fun builder(): RexOpPathStepWildcardBuilder = RexOpPathStepWildcardBuilder()
}
internal data class Symbol(
@JvmField
internal val root: Rex,
@JvmField
internal val key: String,
) : Path() {
internal override val children: List<PlanNode> by lazy {
val kids = mutableListOf<PlanNode?>()
kids.add(root)
kids.filterNotNull()
}

internal data class Unpivot(
@JvmField
internal val ` `: Char = ' ',
) : Step() {
internal override val children: List<PlanNode> = emptyList()

internal override fun <R, C> accept(visitor: PlanVisitor<R, C>, ctx: C): R =
visitor.visitRexOpPathStepUnpivot(this, ctx)
internal override fun <R, C> accept(visitor: PlanVisitor<R, C>, ctx: C): R =
visitor.visitRexOpPathSymbol(this, ctx)

internal companion object {
@JvmStatic
internal fun builder(): RexOpPathStepUnpivotBuilder = RexOpPathStepUnpivotBuilder()
}
internal companion object {
@JvmStatic
internal fun builder(): RexOpPathSymbolBuilder = RexOpPathSymbolBuilder()
}
}

internal companion object {
@JvmStatic
internal fun builder(): RexOpPathBuilder = RexOpPathBuilder()
}
}

internal sealed class Call : Op() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,21 +52,14 @@ internal fun rexOpVarUnresolved(identifier: Identifier, scope: Rex.Op.Var.Scope)

internal fun rexOpGlobal(ref: Catalog.Symbol.Ref): Rex.Op.Global = Rex.Op.Global(ref)

internal fun rexOpPath(root: Rex, steps: List<Rex.Op.Path.Step>): Rex.Op.Path = Rex.Op.Path(
root,
steps
)

internal fun rexOpPathStepIndex(key: Rex): Rex.Op.Path.Step.Index = Rex.Op.Path.Step.Index(key)

internal fun rexOpPathStepKey(key: Rex): Rex.Op.Path.Step.Key = Rex.Op.Path.Step.Key(key)
internal fun rexOpPathIndex(root: Rex, key: Rex): Rex.Op.Path.Index = Rex.Op.Path.Index(root, key)

internal fun rexOpPathStepSymbol(identifier: Identifier.Symbol): Rex.Op.Path.Step.Symbol =
Rex.Op.Path.Step.Symbol(identifier)
internal fun rexOpPathKey(root: Rex, key: Rex): Rex.Op.Path.Key = Rex.Op.Path.Key(root, key)

internal fun rexOpPathStepWildcard(): Rex.Op.Path.Step.Wildcard = Rex.Op.Path.Step.Wildcard()

internal fun rexOpPathStepUnpivot(): Rex.Op.Path.Step.Unpivot = Rex.Op.Path.Step.Unpivot()
internal fun rexOpPathSymbol(root: Rex, key: String): Rex.Op.Path.Symbol = Rex.Op.Path.Symbol(
root,
key
)

internal fun rexOpCallStatic(fn: Fn, args: List<Rex>): Rex.Op.Call.Static = Rex.Op.Call.Static(
fn,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,51 +169,32 @@ internal class PlanBuilder {
return builder.build()
}

internal fun rexOpPath(
internal fun rexOpPathIndex(
root: Rex? = null,
steps: MutableList<Rex.Op.Path.Step> = mutableListOf(),
block: RexOpPathBuilder.() -> Unit = {},
): Rex.Op.Path {
val builder = RexOpPathBuilder(root, steps)
builder.block()
return builder.build()
}

internal fun rexOpPathStepIndex(
key: Rex? = null,
block: RexOpPathStepIndexBuilder.() -> Unit = {},
): Rex.Op.Path.Step.Index {
val builder = RexOpPathStepIndexBuilder(key)
block: RexOpPathIndexBuilder.() -> Unit = {},
): Rex.Op.Path.Index {
val builder = RexOpPathIndexBuilder(root, key)
builder.block()
return builder.build()
}

internal fun rexOpPathStepKey(
internal fun rexOpPathKey(
root: Rex? = null,
key: Rex? = null,
block: RexOpPathStepKeyBuilder.() -> Unit = {},
): Rex.Op.Path.Step.Key {
val builder = RexOpPathStepKeyBuilder(key)
builder.block()
return builder.build()
}

internal fun rexOpPathStepSymbol(
identifier: Identifier.Symbol? = null,
block: RexOpPathStepSymbolBuilder.() -> Unit = {},
): Rex.Op.Path.Step.Symbol {
val builder = RexOpPathStepSymbolBuilder(identifier)
block: RexOpPathKeyBuilder.() -> Unit = {},
): Rex.Op.Path.Key {
val builder = RexOpPathKeyBuilder(root, key)
builder.block()
return builder.build()
}

internal fun rexOpPathStepWildcard(block: RexOpPathStepWildcardBuilder.() -> Unit = {}): Rex.Op.Path.Step.Wildcard {
val builder = RexOpPathStepWildcardBuilder()
builder.block()
return builder.build()
}

internal fun rexOpPathStepUnpivot(block: RexOpPathStepUnpivotBuilder.() -> Unit = {}): Rex.Op.Path.Step.Unpivot {
val builder = RexOpPathStepUnpivotBuilder()
internal fun rexOpPathSymbol(
root: Rex? = null,
key: String? = null,
block: RexOpPathSymbolBuilder.() -> Unit = {},
): Rex.Op.Path.Symbol {
val builder = RexOpPathSymbolBuilder(root, key)
builder.block()
return builder.build()
}
Expand Down
Loading