Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
3 changes: 1 addition & 2 deletions docs/wiki/tutorials/Pluggable Functions Tutorial.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import org.partiql.types.PartiQLValueType
import org.partiql.types.function.FunctionParameter
import org.partiql.types.function.FunctionSignature
import org.partiql.value.PartiQLValue
import org.partiql.value.PartiQLValueExperimental

import org.partiql.value.StringValue
import org.partiql.value.stringValue

Expand All @@ -43,7 +43,6 @@ object TrimLead : PartiQLFunction {
description = "Trims leading whitespace of a [str]." // A brief description of your function
)

@OptIn(PartiQLValueExperimental::class)
override operator fun invoke(session: ConnectorSession, arguments: List<PartiQLValue>): PartiQLValue {
// Implement the function logic here
val str = (arguments[0] as? StringValue)?.string ?: ""
Expand Down
1 change: 1 addition & 0 deletions partiql-cli/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ dependencies {
implementation(project(":partiql-planner"))
implementation(project(":partiql-types"))
implementation(project(":partiql-spi"))
implementation(testFixtures(project(":partiql-spi")))
implementation(Deps.csv)
implementation(Deps.awsSdkBom)
implementation(Deps.awsSdkDynamodb)
Expand Down
8 changes: 4 additions & 4 deletions partiql-cli/src/main/kotlin/org/partiql/cli/Main.kt
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ import org.partiql.spi.catalog.Session
import org.partiql.spi.catalog.Table
import org.partiql.spi.value.Datum
import org.partiql.spi.value.DatumReader
import org.partiql.value.PartiQLValueExperimental
import org.partiql.value.io.PartiQLValueTextWriter
import org.partiql.spi.value.DatumUtils
import org.partiql.spi.value.io.PartiQLValueTextWriter
import picocli.CommandLine
import java.io.File
import java.io.InputStream
Expand Down Expand Up @@ -187,7 +187,6 @@ internal class MainCommand : Runnable {
Shell(pipeline, session(), debug).start()
}

@OptIn(PartiQLValueExperimental::class)
private fun run(statement: String) {
val config = getPipelineConfig()
val pipeline = when (strict) {
Expand All @@ -206,7 +205,8 @@ internal class MainCommand : Runnable {
// TODO add format support
checkFormat(format)
val writer = PartiQLValueTextWriter(System.out)
writer.append(result.toPartiQLValue()) // TODO: Create a Datum writer
val p = DatumUtils.toPartiQLValue(result)
writer.append(p) // TODO: Create a Datum writer
println()
}

Expand Down
8 changes: 4 additions & 4 deletions partiql-cli/src/main/kotlin/org/partiql/cli/shell/Shell.kt
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ import org.jline.utils.InfoCmp
import org.joda.time.Duration
import org.partiql.cli.pipeline.Pipeline
import org.partiql.spi.catalog.Session
import org.partiql.value.PartiQLValueExperimental
import org.partiql.value.io.PartiQLValueTextWriter
import org.partiql.spi.value.DatumUtils
import org.partiql.spi.value.io.PartiQLValueTextWriter
import java.io.Closeable
import java.io.PrintStream
import java.nio.file.Path
Expand Down Expand Up @@ -161,7 +161,6 @@ internal class Shell(
}
}

@OptIn(PartiQLValueExperimental::class)
private fun run(exiting: AtomicBoolean) = TerminalBuilder.builder()
.name("PartiQL")
.nativeSignals(true)
Expand Down Expand Up @@ -276,7 +275,8 @@ internal class Shell(
out.appendLine()
out.info("=== RESULT ===")
val writer = PartiQLValueTextWriter(out)
writer.append(result.toPartiQLValue()) // TODO: Create a Datum writer
val p = DatumUtils.toPartiQLValue(result)
writer.append(p) // TODO: Create a Datum writer
out.appendLine()
out.appendLine()
out.success("OK!")
Expand Down
1 change: 1 addition & 0 deletions partiql-eval/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ dependencies {
// Test
testImplementation(project(":partiql-parser"))
testImplementation(testFixtures(project(":partiql-types"))) // TODO: Remove use of StaticType
testImplementation(testFixtures(project(":partiql-spi")))
testImplementation(Deps.junit4)
testImplementation(Deps.junit4Params)
testImplementation(Deps.junitVintage) // Enables JUnit4
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,10 @@ package org.partiql.eval.internal.helpers
import org.partiql.errors.TypeCheckException
import org.partiql.spi.value.Datum
import org.partiql.types.PType
import org.partiql.value.PartiQLValue
import org.partiql.value.PartiQLValueExperimental
import org.partiql.value.PartiQLValueType
import java.math.BigInteger

/**
* Holds helper functions for [PartiQLValue].
* Holds helper functions for [Datum].
*/
internal object ValueUtility {

Expand All @@ -18,12 +15,13 @@ internal object ValueUtility {
*/
@JvmStatic
fun Datum.isTrue(): Boolean {
return this.type.code() == PType.BOOL && !this.isNull && !this.isMissing && this.boolean
}

@OptIn(PartiQLValueExperimental::class)
fun Datum.check(type: PartiQLValueType): Datum {
return this.check(type.toPType())
if (this.isNull || this.isMissing) {
return false
}
if (this.type.code() == PType.VARIANT) {
return this.lower().isTrue()
}
return this.type.code() == PType.BOOL && this.boolean
}

/**
Expand All @@ -37,6 +35,9 @@ internal object ValueUtility {
if (this.type == type) {
return this
}
if (this.type.code() == PType.VARIANT) {
return this.lower().check(type)
}
if (!this.isNull) {
throw TypeCheckException("Expected type $type but received ${this.type}.")
}
Expand All @@ -51,29 +52,42 @@ internal object ValueUtility {
*/
fun Datum.getText(): String {
return when (this.type.code()) {
PType.VARIANT -> this.lower().getText()
PType.STRING, PType.CHAR -> this.string
else -> throw TypeCheckException("Expected text, but received ${this.type}.")
}
}

/**
* Takes in a [Datum] that is any integer type ([PartiQLValueType.INT8], [PartiQLValueType.INT8],
* [PartiQLValueType.INT8], [PartiQLValueType.INT8], [PartiQLValueType.INT8]) and returns the [BigInteger] (potentially
* coerced) that represents the integer.
* Converts all number values to [BigInteger]. If the number is [PType.DECIMAL] or [PType.NUMERIC], this asserts that
* the scale is zero.
*
* INTERNAL NOTE: The PLANNER should be handling the coercion. This function should not be necessary.
*
* TODO: This is used specifically for LIMIT and OFFSET. This makes the conformance tests pass by coercing values
* of type [PType.NUMERIC] and [PType.DECIMAL], but this is unspecified. Do we allow for LIMIT 2.0? Or of
* a value that is greater than [PType.BIGINT]'s MAX value by using a [PType.DECIMAL] with a high precision and scale
* of zero? This hasn't been decided, however, as the conformance tests allow for this, this function coerces
* the value to a [BigInteger] regardless of the number's type.
*
* @throws NullPointerException if the value is null
* @throws TypeCheckException if type is not an integer type
*/
fun Datum.getBigIntCoerced(): BigInteger {
return when (this.type.code()) {
PType.VARIANT -> this.lower().getBigIntCoerced()
PType.TINYINT -> this.byte.toInt().toBigInteger()
PType.SMALLINT -> this.short.toInt().toBigInteger()
PType.INTEGER -> this.int.toBigInteger()
PType.BIGINT -> this.long.toBigInteger()
PType.NUMERIC -> this.bigInteger
else -> throw TypeCheckException()
PType.NUMERIC, PType.DECIMAL -> {
val decimal = this.bigDecimal
if (decimal.scale() != 0) {
throw TypeCheckException("Expected integer, but received decimal.")
}
return decimal.toBigInteger()
}
else -> throw TypeCheckException("Type: ${this.type}")
}
}

Expand All @@ -90,6 +104,7 @@ internal object ValueUtility {
*/
fun Datum.getInt32Coerced(): Int {
return when (this.type.code()) {
PType.VARIANT -> this.lower().getInt32Coerced()
PType.TINYINT -> this.byte.toInt()
PType.SMALLINT -> this.short.toInt()
PType.INTEGER -> this.int
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ import org.partiql.plan.Exclusion
import org.partiql.spi.value.Datum
import org.partiql.spi.value.Field
import org.partiql.types.PType
import org.partiql.value.PartiQLValue
import org.partiql.value.PartiQLValueType

/**
* Implementation of the EXCLUDE clause; there are good opportunities to tune/optimize this.
Expand Down Expand Up @@ -133,8 +131,8 @@ internal class RelOpExclude(
}

/**
* Returns a [PartiQLValue] created from an iterable of [coll]. Requires [type] to be a collection type
* (i.e. [PartiQLValueType.LIST] or [PartiQLValueType.BAG].).
* Returns a [Datum] created from an iterable of [coll]. Requires [type] to be a collection type
* (i.e. [PType.ARRAY] or [PType.BAG].).
*/
private fun newCollValue(type: PType, coll: Iterable<Datum>): Datum {
return when (type.code()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,12 @@ internal class RelOpIterate(
override fun open(env: Environment) {
val r = expr.eval(env.push(Row()))
index = 0
iterator = when (r.type.code()) {
iterator = records(r)
}

private fun records(r: Datum): Iterator<Datum> {
return when (r.type.code()) {
PType.VARIANT -> records(r.lower())
PType.BAG -> {
close()
throw TypeCheckException()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,12 @@ internal class RelOpIteratePermissive(
override fun open(env: Environment) {
val r = expr.eval(env.push(Row()))
index = 0
iterator = when (r.type.code()) {
iterator = records(r)
}

private fun records(r: Datum): Iterator<Datum> {
return when (r.type.code()) {
PType.VARIANT -> records(r.lower())
PType.BAG -> {
isIndexable = false
r.iterator()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import org.partiql.eval.ExprRelation
import org.partiql.eval.ExprValue
import org.partiql.eval.Row
import org.partiql.eval.internal.helpers.RecordValueIterator
import org.partiql.spi.value.Datum
import org.partiql.types.PType

internal class RelOpScan(
Expand All @@ -16,11 +17,16 @@ internal class RelOpScan(

override fun open(env: Environment) {
val r = expr.eval(env.push(Row()))
records = when (r.type.code()) {
PType.ARRAY, PType.BAG -> RecordValueIterator(r.iterator())
records = r.records()
}

private fun Datum.records(): RecordValueIterator {
return when (this.type.code()) {
PType.VARIANT -> this.lower().records()
PType.ARRAY, PType.BAG -> RecordValueIterator(this.iterator())
else -> {
close()
throw TypeCheckException("Unexpected type for scan: ${r.type}")
throw TypeCheckException("Unexpected type for scan: ${this.type}")
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import org.partiql.eval.ExprRelation
import org.partiql.eval.ExprValue
import org.partiql.eval.Row
import org.partiql.eval.internal.helpers.RecordValueIterator
import org.partiql.spi.value.Datum
import org.partiql.types.PType

internal class RelOpScanPermissive(
Expand All @@ -15,7 +16,13 @@ internal class RelOpScanPermissive(

override fun open(env: Environment) {
val r = expr.eval(env.push(Row()))
records = when (r.type.code()) {
records = r.records()
}

private fun Datum.records(): Iterator<Row> {
val r = this
return when (type.code()) {
PType.VARIANT -> r.lower().records()
PType.BAG, PType.ARRAY -> RecordValueIterator(r.iterator())
else -> iterator { yield(Row(arrayOf(r))) }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,13 @@ internal sealed class RelOpUnpivot : ExprRelation {
class Strict(private val expr: ExprValue) : RelOpUnpivot() {

override fun struct(): Datum {
val v = expr.eval(env.push(Row()))
val v = expr.eval(env.push(Row())).let {
if (it.type.code() == PType.VARIANT) {
it.lower()
} else {
it
}
}
if (v.type.code() != PType.STRUCT && v.type.code() != PType.ROW) {
throw TypeCheckException()
}
Expand All @@ -78,7 +84,13 @@ internal sealed class RelOpUnpivot : ExprRelation {
class Permissive(private val expr: ExprValue) : RelOpUnpivot() {

override fun struct(): Datum {
val v = expr.eval(env.push(Row()))
val v = expr.eval(env.push(Row())).let {
if (it.type.code() == PType.VARIANT) {
it.lower()
} else {
it
}
}
if (v.isMissing) {
return Datum.struct(emptyList())
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import org.partiql.types.PType.TIMESTAMPZ
import org.partiql.types.PType.TIMEZ
import org.partiql.types.PType.TINYINT
import org.partiql.types.PType.VARCHAR
import org.partiql.types.PType.VARIANT
import org.partiql.value.datetime.DateTimeValue
import java.math.BigDecimal
import java.math.BigInteger
Expand Down Expand Up @@ -70,6 +71,9 @@ internal object CastTable {
if (target.code() == DYNAMIC) {
return source
}
if (source.type.code() == VARIANT) {
return cast(source.lower(), target)
}
val cast = _table[source.type.code()][target.code()]
?: throw TypeCheckException("CAST(${source.type} AS $target) is not supported.")
return try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import org.partiql.eval.internal.operator.rex.ExprCallDynamic.CoercionFamily.UNK
import org.partiql.spi.function.Function
import org.partiql.spi.value.Datum
import org.partiql.types.PType
import org.partiql.value.PartiQLValue

/**
* Implementation of Dynamic Dispatch.
Expand All @@ -23,7 +22,7 @@ import org.partiql.value.PartiQLValue
* 3. Lookup the candidate to dispatch to and invoke.
*
* This implementation can evaluate ([eval]) the input [Row], execute and gather the
* arguments, and pass the [PartiQLValue]s directly to the [Candidate.eval].
* arguments, and pass the values directly to the [Candidate.eval].
*
* This implementation also caches previously resolved candidates.
*
Expand All @@ -46,7 +45,14 @@ internal class ExprCallDynamic(
private val candidates: MutableMap<List<PType>, Candidate> = mutableMapOf()

override fun eval(env: Environment): Datum {
val actualArgs = args.map { it.eval(env) }.toTypedArray()
val actualArgs = args.map {
val arg = it.eval(env)
if (arg.type.code() == PType.VARIANT) {
arg.lower()
} else {
arg
}
}.toTypedArray()
val actualTypes = actualArgs.map { it.type }
var candidate = candidates[actualTypes]
if (candidate == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,11 @@ package org.partiql.eval.internal.operator.rex
import org.partiql.eval.Environment
import org.partiql.eval.ExprValue
import org.partiql.spi.value.Datum
import org.partiql.value.PartiQLValueExperimental

internal class ExprCoalesce(
private val args: Array<ExprValue>
) : ExprValue {

@PartiQLValueExperimental
override fun eval(env: Environment): Datum {
for (arg in args) {
val result = arg.eval(env)
Expand Down
Loading
Loading