Skip to content
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

Structures globals within plan to lie within catalogs #1308

Merged
merged 8 commits into from
Dec 15, 2023
Merged
31 changes: 24 additions & 7 deletions partiql-plan/src/main/resources/partiql_plan.ion
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,32 @@ imports::{
}

parti_q_l_plan::{
globals: list::[global], // (globals ...)
catalogs: list::[catalog], // (catalogs ...)
statement: statement, // (statement ...)
}

// Globals

global::{
path: '.identifier.qualified',
type: static_type,
// Represent an instance of a database.
// - Currently, `symbols` represents all values from this catalog to be used in this plan.
// - Eventually, TODO functions may be resolved to a specific namespace within a catalog.
catalog::{
name: string,
symbols: list::[symbol],
_: [
// A reference to a value contained within a catalog.
symbol::{
// The path to a value WITHIN a catalog. Note: This should not start with the catalog's name. Also, this
// should not be empty
path: list::[string],
type: static_type,
_: [
// A reference to a symbol
ref::{
catalog: int,
symbol: int
}
]
}
]
}

// Functions
Expand Down Expand Up @@ -70,7 +87,7 @@ rex::{
},

global::{
ref: int,
ref: '.catalog.symbol.ref'
},

path::{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ internal class PartiQLPlannerDefault(
val typer = PlanTyper(env, onProblem)
val internal = org.partiql.planner.internal.ir.PartiQLPlan(
version = PartiQLVersion.VERSION_0_1,
globals = env.globals,
catalogs = env.catalogs,
statement = typer.resolve(root),
)

Expand Down
63 changes: 48 additions & 15 deletions partiql-planner/src/main/kotlin/org/partiql/planner/internal/Env.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,11 @@ package org.partiql.planner.internal
import org.partiql.planner.Header
import org.partiql.planner.PartiQLPlanner
import org.partiql.planner.internal.ir.Agg
import org.partiql.planner.internal.ir.Catalog
import org.partiql.planner.internal.ir.Fn
import org.partiql.planner.internal.ir.Global
import org.partiql.planner.internal.ir.Identifier
import org.partiql.planner.internal.ir.Rel
import org.partiql.planner.internal.ir.Rex
import org.partiql.planner.internal.ir.global
import org.partiql.planner.internal.ir.identifierQualified
import org.partiql.planner.internal.ir.identifierSymbol
import org.partiql.planner.internal.typer.FnResolver
import org.partiql.spi.BindingCase
Expand Down Expand Up @@ -92,13 +90,15 @@ internal sealed interface ResolvedVar {
* Metadata for a resolved global variable
*
* @property type Resolved StaticType
* @property ordinal Index offset in the environment `globals` list
* @property ordinal The relevant catalog's index offset in the [Env.catalogs] list
* @property depth The depth/level of the path match.
* @property position The relevant value's index offset in the [Catalog.values] list
*/
class Global(
override val type: StaticType,
override val ordinal: Int,
val depth: Int,
val position: Int
) : ResolvedVar
}

Expand All @@ -124,14 +124,14 @@ internal enum class ResolutionStrategy {
*/
internal class Env(
private val headers: List<Header>,
private val catalogs: Map<String, ConnectorMetadata>,
private val connectors: Map<String, ConnectorMetadata>,
private val session: PartiQLPlanner.Session,
) {

/**
* Collect the list of all referenced globals during planning.
*/
public val globals = mutableListOf<Global>()
public val catalogs = mutableListOf<Catalog>()

/**
* Encapsulate all function resolving logic within [FnResolver].
Expand All @@ -144,6 +144,7 @@ internal class Env(
}

/**

* Leverages a [FunctionResolver] to find a matching function defined in the [Header] scalar function catalog.
*/
internal fun resolveFn(fn: Fn.Unresolved, args: List<Rex>) = fnResolver.resolveFn(fn, args)
Expand Down Expand Up @@ -186,8 +187,8 @@ internal class Env(
* @return
*/
private fun getMetadata(catalogName: BindingName): Handle<ConnectorMetadata>? {
val catalogKey = catalogs.keys.firstOrNull { catalogName.isEquivalentTo(it) } ?: return null
val metadata = catalogs[catalogKey] ?: return null
val catalogKey = connectors.keys.firstOrNull { catalogName.isEquivalentTo(it) } ?: return null
val metadata = connectors[catalogKey] ?: return null
return catalogKey to metadata
}

Expand All @@ -208,15 +209,47 @@ internal class Env(
getObjectHandle(cat, catalogPath)?.let { handle ->
getObjectDescriptor(handle).let { type ->
val depth = calculateMatched(originalPath, catalogPath, handle.second.absolutePath)
val qualifiedPath = identifierQualified(
root = handle.first.toIdentifier(),
steps = handle.second.absolutePath.steps.map { it.toIdentifier() }
)
val global = global(qualifiedPath, type)
globals.add(global)
val (catalogIndex, valueIndex) = getOrAddCatalogValue(handle.first, handle.second.absolutePath.steps, type)
// Return resolution metadata
ResolvedVar.Global(type, globals.size - 1, depth)
ResolvedVar.Global(type, catalogIndex, depth, valueIndex)
}
}
}
}

/**
* @return a [Pair] where [Pair.first] is the catalog index and [Pair.second] is the value index within that catalog
*/
private fun getOrAddCatalogValue(catalogName: String, valuePath: List<String>, valueType: StaticType): Pair<Int, Int> {
val catalogIndex = getOrAddCatalog(catalogName)
val symbols = catalogs[catalogIndex].symbols
return symbols.indexOfFirst { value ->
value.path == valuePath
}.let { index ->
when (index) {
-1 -> {
catalogs[catalogIndex] = catalogs[catalogIndex].copy(
symbols = symbols + listOf(Catalog.Symbol(valuePath, valueType))
)
catalogIndex to 0
}
else -> {
catalogIndex to index
}
}
}
}

private fun getOrAddCatalog(catalogName: String): Int {
return catalogs.indexOfFirst { catalog ->
catalog.name == catalogName
}.let {
when (it) {
-1 -> {
catalogs.add(Catalog(catalogName, emptyList()))
catalogs.lastIndex
}
else -> it
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ package org.partiql.planner.internal.ir

import org.partiql.planner.internal.ir.builder.AggResolvedBuilder
import org.partiql.planner.internal.ir.builder.AggUnresolvedBuilder
import org.partiql.planner.internal.ir.builder.CatalogBuilder
import org.partiql.planner.internal.ir.builder.CatalogSymbolBuilder
import org.partiql.planner.internal.ir.builder.CatalogSymbolRefBuilder
import org.partiql.planner.internal.ir.builder.FnResolvedBuilder
import org.partiql.planner.internal.ir.builder.FnUnresolvedBuilder
import org.partiql.planner.internal.ir.builder.GlobalBuilder
import org.partiql.planner.internal.ir.builder.IdentifierQualifiedBuilder
import org.partiql.planner.internal.ir.builder.IdentifierSymbolBuilder
import org.partiql.planner.internal.ir.builder.PartiQlPlanBuilder
Expand Down Expand Up @@ -80,13 +82,13 @@ internal data class PartiQLPlan(
@JvmField
internal val version: PartiQLVersion,
@JvmField
internal val globals: List<Global>,
internal val catalogs: List<Catalog>,
@JvmField
internal val statement: Statement,
) : PlanNode() {
internal override val children: List<PlanNode> by lazy {
val kids = mutableListOf<PlanNode?>()
kids.addAll(globals)
kids.addAll(catalogs)
kids.add(statement)
kids.filterNotNull()
}
Expand All @@ -100,24 +102,58 @@ internal data class PartiQLPlan(
}
}

internal data class Global(
internal data class Catalog(
@JvmField
internal val path: Identifier.Qualified,
internal val name: String,
@JvmField
internal val type: StaticType,
internal val symbols: List<Symbol>,
) : PlanNode() {
internal override val children: List<PlanNode> by lazy {
val kids = mutableListOf<PlanNode?>()
kids.add(path)
kids.addAll(symbols)
kids.filterNotNull()
}

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

internal data class Symbol(
@JvmField
internal val path: List<String>,
@JvmField
internal val type: StaticType,
) : PlanNode() {
internal override val children: List<PlanNode> = emptyList()

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

internal data class Ref(
@JvmField
internal val catalog: Int,
@JvmField
internal val symbol: Int,
) : PlanNode() {
internal override val children: List<PlanNode> = emptyList()

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

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

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

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

Expand Down Expand Up @@ -380,9 +416,13 @@ internal data class Rex(

internal data class Global(
@JvmField
internal val ref: Int,
internal val ref: Catalog.Symbol.Ref,
) : Op() {
internal override val children: List<PlanNode> = emptyList()
internal override val children: List<PlanNode> by lazy {
val kids = mutableListOf<PlanNode?>()
kids.add(ref)
kids.filterNotNull()
}

internal override fun <R, C> accept(visitor: PlanVisitor<R, C>, ctx: C): R =
visitor.visitRexOpGlobal(this, ctx)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,17 @@ import org.partiql.value.PartiQLValueExperimental

internal fun partiQLPlan(
version: PartiQLVersion,
globals: List<Global>,
catalogs: List<Catalog>,
statement: Statement,
): PartiQLPlan = PartiQLPlan(version, globals, statement)
): PartiQLPlan = PartiQLPlan(version, catalogs, statement)

internal fun global(path: Identifier.Qualified, type: StaticType): Global = Global(path, type)
internal fun catalog(name: String, symbols: List<Catalog.Symbol>): Catalog = Catalog(name, symbols)

internal fun catalogSymbol(path: List<String>, type: StaticType): Catalog.Symbol =
Catalog.Symbol(path, type)

internal fun catalogSymbolRef(catalog: Int, symbol: Int): Catalog.Symbol.Ref =
Catalog.Symbol.Ref(catalog, symbol)

internal fun fnResolved(signature: FunctionSignature.Scalar): Fn.Resolved = Fn.Resolved(signature)

Expand Down Expand Up @@ -44,7 +50,7 @@ internal fun rexOpVarResolved(ref: Int): Rex.Op.Var.Resolved = Rex.Op.Var.Resolv
internal fun rexOpVarUnresolved(identifier: Identifier, scope: Rex.Op.Var.Scope):
Rex.Op.Var.Unresolved = Rex.Op.Var.Unresolved(identifier, scope)

internal fun rexOpGlobal(ref: Int): Rex.Op.Global = Rex.Op.Global(ref)
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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
package org.partiql.planner.internal.ir.builder

import org.partiql.planner.internal.ir.Agg
import org.partiql.planner.internal.ir.Catalog
import org.partiql.planner.internal.ir.Fn
import org.partiql.planner.internal.ir.Global
import org.partiql.planner.internal.ir.Identifier
import org.partiql.planner.internal.ir.PartiQLPlan
import org.partiql.planner.internal.ir.PartiQLVersion
Expand All @@ -22,21 +22,41 @@ internal fun <T : PlanNode> plan(block: PlanBuilder.() -> T) = PlanBuilder().blo
internal class PlanBuilder {
internal fun partiQLPlan(
version: PartiQLVersion? = null,
globals: MutableList<Global> = mutableListOf(),
catalogs: MutableList<Catalog> = mutableListOf(),
statement: Statement? = null,
block: PartiQlPlanBuilder.() -> Unit = {},
): PartiQLPlan {
val builder = PartiQlPlanBuilder(version, globals, statement)
val builder = PartiQlPlanBuilder(version, catalogs, statement)
builder.block()
return builder.build()
}

internal fun global(
path: Identifier.Qualified? = null,
internal fun catalog(
name: String? = null,
symbols: MutableList<Catalog.Symbol> = mutableListOf(),
block: CatalogBuilder.() -> Unit = {},
): Catalog {
val builder = CatalogBuilder(name, symbols)
builder.block()
return builder.build()
}

internal fun catalogSymbol(
path: MutableList<String> = mutableListOf(),
type: StaticType? = null,
block: GlobalBuilder.() -> Unit = {},
): Global {
val builder = GlobalBuilder(path, type)
block: CatalogSymbolBuilder.() -> Unit = {},
): Catalog.Symbol {
val builder = CatalogSymbolBuilder(path, type)
builder.block()
return builder.build()
}

internal fun catalogSymbolRef(
catalog: Int? = null,
symbol: Int? = null,
block: CatalogSymbolRefBuilder.() -> Unit = {},
): Catalog.Symbol.Ref {
val builder = CatalogSymbolRefBuilder(catalog, symbol)
builder.block()
return builder.build()
}
Expand Down Expand Up @@ -140,7 +160,10 @@ internal class PlanBuilder {
return builder.build()
}

internal fun rexOpGlobal(ref: Int? = null, block: RexOpGlobalBuilder.() -> Unit = {}): Rex.Op.Global {
internal fun rexOpGlobal(
ref: Catalog.Symbol.Ref? = null,
block: RexOpGlobalBuilder.() -> Unit = {}
): Rex.Op.Global {
val builder = RexOpGlobalBuilder(ref)
builder.block()
return builder.build()
Expand Down
Loading
Loading