-
Notifications
You must be signed in to change notification settings - Fork 62
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adds catalog interfaces to partiql-planner
- Loading branch information
Showing
11 changed files
with
1,475 additions
and
0 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
72 changes: 72 additions & 0 deletions
72
partiql-planner/src/main/kotlin/org/partiql/planner/catalog/Catalog.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
package org.partiql.planner.catalog | ||
|
||
/** | ||
* Catalog interface for access to tables and routines. | ||
* | ||
* Related | ||
* - Iceberg — https://github.com/apache/iceberg/blob/main/api/src/main/java/org/apache/iceberg/catalog/Catalog.java | ||
* - Calcite — https://github.com/apache/calcite/blob/main/core/src/main/java/org/apache/calcite/schema/Schema.java | ||
*/ | ||
public interface Catalog { | ||
|
||
/** | ||
* Returns the catalog name. | ||
*/ | ||
public fun getName(): String | ||
|
||
/** | ||
* Get a table by name. | ||
*/ | ||
public fun getTable(session: Session, name: Name): Table? = null | ||
|
||
/** | ||
* Given an [Identifier], returns a [Table.Handle] that corresponds to the longest-available requested path. | ||
* | ||
* For example, given a table named "Table" located within Catalog "AWS" and Namespace "a".b"."c", a user could | ||
* call [getTableHandle] with the identifier "a"."b"."c"."Table". The returned [Table.Handle] will contain the table | ||
* representation and the matching path: "a"."b"."c"."Table" | ||
* | ||
* As another example, consider a table within a [Namespace] that may be a struct with nested attributes. | ||
* A user could call [getTableHandle] with the identifier "a"."b"."c"."Table"."x". In the Namespace, only table | ||
* "Table" exists. Therefore, this method will return a [Table.Handle] with the "Table" representation and the | ||
* matching path: "a"."b"."c"."Table". | ||
* | ||
* IMPORTANT: The returned [Table.Handle.name] must be correct for correct evaluation. | ||
* | ||
* If the [Identifier] does not correspond to an existing [Table], implementers should return null. | ||
*/ | ||
public fun getTableHandle(session: Session, identifier: Identifier): Table.Handle? = null | ||
|
||
/** | ||
* List top-level tables. | ||
*/ | ||
public fun listTables(session: Session): Collection<Name> = listTables(session, Namespace.empty()) | ||
|
||
/** | ||
* List all tables under this namespace. | ||
*/ | ||
public fun listTables(session: Session, namespace: Namespace): Collection<Name> = emptyList() | ||
|
||
/** | ||
* List top-level namespaces from the catalog. | ||
*/ | ||
public fun listNamespaces(session: Session): Collection<Namespace> = listNamespaces(session, Namespace.empty()) | ||
|
||
/** | ||
* List all child namespaces from the namespace. | ||
* | ||
* @param namespace | ||
*/ | ||
public fun listNamespaces(session: Session, namespace: Namespace): Collection<Namespace> = emptyList() | ||
|
||
/** | ||
* Get a routine's variants by name; the default implementation is backed by the SQL-99 builtins. | ||
*/ | ||
public fun getFunctions(session: Session, name: Name): Collection<Function> { | ||
// if (name.hasNamespace()) { | ||
// error("The default catalog implementation does not support namespaced functions, found: $name") | ||
// } | ||
// return SqlFunctions.getFunctions(name.getName()) | ||
error("Catalog functions are not implemented.") | ||
} | ||
} |
108 changes: 108 additions & 0 deletions
108
partiql-planner/src/main/kotlin/org/partiql/planner/catalog/Catalogs.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
package org.partiql.planner.catalog | ||
|
||
/** | ||
* Catalogs is used to provide the default catalog and possibly others by name. | ||
*/ | ||
public interface Catalogs { | ||
|
||
/** | ||
* Returns the default catalog. Required. | ||
*/ | ||
public fun default(): Catalog | ||
|
||
/** | ||
* Returns a catalog by name (single identifier). | ||
*/ | ||
public fun get(name: String, ignoreCase: Boolean = false): Catalog? { | ||
val default = default() | ||
return if (name.equals(default.getName(), ignoreCase)) { | ||
default | ||
} else { | ||
null | ||
} | ||
} | ||
|
||
/** | ||
* Returns a list of all available catalogs. | ||
*/ | ||
public fun list(): Collection<Catalog> = listOf(default()) | ||
|
||
/** | ||
* Factory methods and builder. | ||
*/ | ||
public companion object { | ||
|
||
@JvmStatic | ||
public fun of(vararg catalogs: Catalog): Catalogs = of(catalogs.toList()) | ||
|
||
@JvmStatic | ||
public fun of(catalogs: Collection<Catalog>): Catalogs { | ||
if (catalogs.isEmpty()) { | ||
error("Cannot create `Catalogs` with empty catalogs list.") | ||
} | ||
return builder().apply { catalogs.forEach { add(it) } }.build() | ||
} | ||
|
||
@JvmStatic | ||
public fun builder(): Builder = Builder() | ||
} | ||
|
||
/** | ||
* Java-style builder for a default [Catalogs] implementation. | ||
*/ | ||
public class Builder { | ||
|
||
private var default: Catalog? = null | ||
private val catalogs = mutableMapOf<String, Catalog>() | ||
|
||
/** | ||
* Sets the default catalog. | ||
*/ | ||
public fun default(default: Catalog): Builder = this.apply { | ||
this.default = default | ||
catalogs[default.getName()] = default | ||
} | ||
|
||
/** | ||
* Adds this catalog, overwriting any existing one with the same name. | ||
*/ | ||
public fun add(catalog: Catalog): Builder = this.apply { | ||
if (default == null) { | ||
this.default = catalog | ||
} | ||
catalogs[catalog.getName()] = catalog | ||
} | ||
|
||
public fun build(): Catalogs { | ||
|
||
val default = default ?: error("Default catalog is required") | ||
|
||
return object : Catalogs { | ||
|
||
override fun default(): Catalog = default | ||
|
||
override fun get(name: String, ignoreCase: Boolean): Catalog? { | ||
if (ignoreCase) { | ||
// search | ||
var match: Catalog? = null | ||
for (catalog in list()) { | ||
if (catalog.getName().equals(name, ignoreCase = true)) { | ||
if (match != null) { | ||
// TODO exceptions for ambiguous catalog name lookup | ||
error("Catalog name is ambiguous, found more than one match.") | ||
} else { | ||
match = catalog | ||
} | ||
} | ||
} | ||
return match | ||
} | ||
// lookup | ||
return catalogs[name] | ||
} | ||
|
||
override fun list(): Collection<Catalog> = catalogs.values | ||
} | ||
} | ||
} | ||
} |
115 changes: 115 additions & 0 deletions
115
partiql-planner/src/main/kotlin/org/partiql/planner/catalog/Function.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
package org.partiql.planner.catalog | ||
|
||
import org.partiql.planner.internal.SqlTypes | ||
import org.partiql.types.PType | ||
|
||
/** | ||
* A [Function] is a PartiQL-routine callable from an expression context. | ||
*/ | ||
public sealed interface Function { | ||
|
||
/** | ||
* The routine name. Required. | ||
*/ | ||
public fun getName(): String | ||
|
||
/** | ||
* The formal argument definitions. Optional. | ||
*/ | ||
public fun getParameters(): Array<Parameter> = DEFAULT_PARAMETERS | ||
|
||
/** | ||
* The function return type. Required. | ||
*/ | ||
public fun getReturnType(): PType.Kind | ||
|
||
/** | ||
* Compute a [PType] from the given arguments. | ||
*/ | ||
public fun computeReturnType(args: List<PType>): PType = SqlTypes.from(getReturnType()) | ||
|
||
/** | ||
* !! DO NOT OVERRIDE !! | ||
*/ | ||
public fun getSpecific(): String | ||
|
||
/** | ||
* Represents an SQL row-value expression call. | ||
*/ | ||
public interface Scalar : Function { | ||
|
||
/** | ||
* SQL NULL CALL -> RETURNS NULL ON NULL INPUT | ||
*/ | ||
public fun isNullCall(): Boolean = true | ||
|
||
/** | ||
* !! DO NOT OVERRIDE !! | ||
*/ | ||
public override fun getSpecific(): String { | ||
val name = getName().uppercase() | ||
val parameters = getParameters().joinToString("__") { it.type.name } | ||
val returnType = getReturnType().name | ||
return "FN_${name}___${parameters}___$returnType" | ||
} | ||
} | ||
|
||
/** | ||
* Represents an SQL table-value expression call. | ||
*/ | ||
public interface Aggregation : Function { | ||
|
||
public fun isDecomposable(): Boolean = true | ||
|
||
/** | ||
* !! DO NOT OVERRIDE !! | ||
*/ | ||
public override fun getSpecific(): String { | ||
val name = getName() | ||
val parameters = getParameters().joinToString("__") { it.type.name } | ||
val returnType = getReturnType().name | ||
return "AGG_${name}___${parameters}___$returnType" | ||
} | ||
} | ||
|
||
/** | ||
* [Parameter] is a formal argument's definition. | ||
* | ||
* @property name | ||
* @property type | ||
*/ | ||
public data class Parameter( | ||
@JvmField public val name: String, | ||
@JvmField public val type: PType.Kind, | ||
) | ||
|
||
/** | ||
* Memoized defaults. | ||
*/ | ||
public companion object { | ||
|
||
private val DEFAULT_PARAMETERS = emptyArray<Parameter>() | ||
|
||
@JvmStatic | ||
public fun scalar( | ||
name: String, | ||
parameters: Collection<Parameter>, | ||
returnType: PType.Kind, | ||
): Scalar = object : Scalar { | ||
override fun getName(): String = name | ||
override fun getParameters(): Array<Parameter> = parameters.toTypedArray() | ||
override fun getReturnType(): PType.Kind = returnType | ||
} | ||
|
||
@JvmStatic | ||
public fun aggregation( | ||
name: String, | ||
parameters: Collection<Parameter>, | ||
returnType: PType.Kind, | ||
): Aggregation = object : Aggregation { | ||
override fun getName(): String = name | ||
override fun getParameters(): Array<Parameter> = parameters.toTypedArray() | ||
override fun getReturnType(): PType.Kind = returnType | ||
} | ||
} | ||
} |
Oops, something went wrong.