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

Cast Impl & Char_length & Abs function #1363

Merged
merged 3 commits into from
Feb 7, 2024
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

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.partiql.eval.internal.operator.rex

import org.partiql.errors.DataException
import org.partiql.errors.TypeCheckException
import org.partiql.eval.internal.Record
import org.partiql.eval.internal.operator.Operator
Expand All @@ -9,6 +10,7 @@ import org.partiql.value.Int32Value
import org.partiql.value.Int64Value
import org.partiql.value.Int8Value
import org.partiql.value.IntValue
import org.partiql.value.NumericValue
import org.partiql.value.PartiQLValue
import org.partiql.value.PartiQLValueExperimental
import org.partiql.value.check
Expand All @@ -24,11 +26,15 @@ internal class ExprPathIndex(

// Calculate index
val index = when (val k = key.eval(record)) {
is Int16Value -> k.int
is Int32Value -> k.int
is Int64Value -> k.int
is Int8Value -> k.int
is IntValue -> k.int
is Int16Value,
is Int32Value,
is Int64Value,
is Int8Value,
is IntValue -> try {
(k as NumericValue<*>).toInt32().value
} catch (e: DataException) {
throw TypeCheckException()
}
else -> throw TypeCheckException()
} ?: throw TypeCheckException()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ import org.partiql.eval.internal.operator.Operator
import org.partiql.value.MissingValue
import org.partiql.value.PartiQLValue
import org.partiql.value.PartiQLValueExperimental
import org.partiql.value.StringValue
import org.partiql.value.TextValue
import org.partiql.value.check
import org.partiql.value.structValue

internal class ExprStruct(val fields: List<Field>) : Operator.Expr {
@OptIn(PartiQLValueExperimental::class)
override fun eval(record: Record): PartiQLValue {
val fields = fields.mapNotNull {
val key = it.key.eval(record).check<StringValue>()
val key = it.key.eval(record).check<TextValue<String>>()
when (val value = it.value.eval(record)) {
is MissingValue -> null
else -> key.value!! to value
Expand Down
3 changes: 2 additions & 1 deletion partiql-parser/src/main/antlr/PartiQL.g4
Original file line number Diff line number Diff line change
Expand Up @@ -716,7 +716,8 @@ functionCall

// SQL-99 10.4 — <routine name> ::= [ <schema name> <period> ] <qualified identifier>
functionName
: (qualifier+=symbolPrimitive PERIOD)* name=( CHAR_LENGTH | CHARACTER_LENGTH | OCTET_LENGTH | BIT_LENGTH | UPPER | LOWER | SIZE | EXISTS | COUNT ) # FunctionNameReserved
: (qualifier+=symbolPrimitive PERIOD)* name=( CHAR_LENGTH | CHARACTER_LENGTH | OCTET_LENGTH | BIT_LENGTH |
UPPER | LOWER | SIZE | EXISTS | COUNT | MOD) # FunctionNameReserved
| (qualifier+=symbolPrimitive PERIOD)* name=symbolPrimitive # FunctionNameSymbol
;

Expand Down
1 change: 1 addition & 0 deletions partiql-parser/src/main/antlr/PartiQLTokens.g4
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ LOWER: 'LOWER';
MATCH: 'MATCH';
MAX: 'MAX';
MIN: 'MIN';
MOD: 'MOD';
MODULE: 'MODULE';
NAMES: 'NAMES';
NATIONAL: 'NATIONAL';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -854,7 +854,7 @@ internal class PartiQLParserDefault : PartiQLParser {
throw error(ctx, "Expected a path element literal")
}
when (val i = v.value) {
is NumericValue<*> -> pathStepIndex(i.int!!)
is NumericValue<*> -> pathStepIndex(i.toInt32().value!!)
is StringValue -> pathStepSymbol(
identifierSymbol(
i.value!!, Identifier.CaseSensitivity.SENSITIVE
Expand Down Expand Up @@ -1725,14 +1725,30 @@ internal class PartiQLParserDefault : PartiQLParser {
}

override fun visitFunctionCall(ctx: GeneratedParser.FunctionCallContext) = translate(ctx) {
val function = visit(ctx.functionName()) as Identifier
val args = visitOrEmpty<Expr>(ctx.expr())
exprCall(function, args)
when (val funcName = ctx.functionName()) {
is GeneratedParser.FunctionNameReservedContext -> {
when (funcName.name.type) {
GeneratedParser.MOD -> exprBinary(Expr.Binary.Op.MODULO, args[0], args[1])
else -> visitNonReservedFunctionCall(ctx, args)
Comment on lines +1732 to +1733
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm very curious to explore why we have the reserved function names at all. Other SQL ANTLR grammars simply use a qualified name. I don't think we should change it here, but let's check with John as to why he included those.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree. Maybe we can have an alias parameter in FnSignature or something to resolve the multiple naming issue. (i.e., char_length and character_length)

}
}
else -> visitNonReservedFunctionCall(ctx, args)
}
}
private fun visitNonReservedFunctionCall(ctx: GeneratedParser.FunctionCallContext, args: List<Expr>): Expr.Call {
val function = visit(ctx.functionName()) as Identifier
return exprCall(function, args)
}

override fun visitFunctionNameReserved(ctx: GeneratedParser.FunctionNameReservedContext): Identifier {
val path = ctx.qualifier.map { visitSymbolPrimitive(it) }
val name = identifierSymbol(ctx.name.text, Identifier.CaseSensitivity.INSENSITIVE)
val name = when (ctx.name.type) {
GeneratedParser.CHARACTER_LENGTH, GeneratedParser.CHAR_LENGTH ->
identifierSymbol("char_length", Identifier.CaseSensitivity.INSENSITIVE)
else ->
identifierSymbol(ctx.name.text, Identifier.CaseSensitivity.INSENSITIVE)
}
return if (path.isEmpty()) {
name
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,17 @@ internal object SqlBuiltins {

@JvmStatic
val builtins: List<Fn> = listOf(
Fn_ABS__INT8__INT8,
Fn_ABS__INT16__INT16,
Fn_ABS__INT32__INT32,
Fn_ABS__INT64__INT64,
Fn_ABS__INT__INT,
Fn_ABS__DECIMAL_ARBITRARY__DECIMAL_ARBITRARY,
Fn_ABS__FLOAT32__FLOAT32,
Fn_ABS__FLOAT64__FLOAT64,
Fn_CHAR_LENGTH__STRING__INT,
Fn_CHAR_LENGTH__SYMBOL__INT,
Fn_CHAR_LENGTH__CLOB__INT,
Fn_POS__INT8__INT8,
Fn_POS__INT16__INT16,
Fn_POS__INT32__INT32,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
// ktlint-disable filename
@file:Suppress("ClassName")

package org.partiql.spi.connector.sql.builtins

import org.partiql.spi.fn.Fn
import org.partiql.spi.fn.FnExperimental
import org.partiql.spi.fn.FnParameter
import org.partiql.spi.fn.FnSignature
import org.partiql.value.DecimalValue
import org.partiql.value.Float32Value
import org.partiql.value.Float64Value
import org.partiql.value.Int16Value
import org.partiql.value.Int32Value
import org.partiql.value.Int64Value
import org.partiql.value.Int8Value
import org.partiql.value.IntValue
import org.partiql.value.PartiQLValue
import org.partiql.value.PartiQLValueExperimental
import org.partiql.value.PartiQLValueType.DECIMAL_ARBITRARY
import org.partiql.value.PartiQLValueType.FLOAT32
import org.partiql.value.PartiQLValueType.FLOAT64
import org.partiql.value.PartiQLValueType.INT
import org.partiql.value.PartiQLValueType.INT16
import org.partiql.value.PartiQLValueType.INT32
import org.partiql.value.PartiQLValueType.INT64
import org.partiql.value.PartiQLValueType.INT8
import org.partiql.value.check
import org.partiql.value.decimalValue
import org.partiql.value.float32Value
import org.partiql.value.float64Value
import org.partiql.value.int16Value
import org.partiql.value.int32Value
import org.partiql.value.int64Value
import org.partiql.value.int8Value
import org.partiql.value.intValue
import kotlin.math.absoluteValue

// TODO: When negate a negative value, we need to consider overflow
@OptIn(PartiQLValueExperimental::class, FnExperimental::class)
internal object Fn_ABS__INT8__INT8 : Fn {

override val signature = FnSignature(
name = "abs",
returns = INT8,
parameters = listOf(FnParameter("value", INT8)),
isNullCall = true,
isNullable = false,
)

override fun invoke(args: Array<PartiQLValue>): Int8Value {
val value = args[0].check<Int8Value>().value!!
return if (value < 0) int8Value(value.times(-1).toByte()) else int8Value(value)
}
}

@OptIn(PartiQLValueExperimental::class, FnExperimental::class)
internal object Fn_ABS__INT16__INT16 : Fn {

override val signature = FnSignature(
name = "abs",
returns = INT16,
parameters = listOf(FnParameter("value", INT16)),
isNullCall = true,
isNullable = false,
)

override fun invoke(args: Array<PartiQLValue>): Int16Value {
val value = args[0].check<Int16Value>().value!!
return if (value < 0) int16Value(value.times(-1).toShort()) else int16Value(value)
}
}

@OptIn(PartiQLValueExperimental::class, FnExperimental::class)
internal object Fn_ABS__INT32__INT32 : Fn {

override val signature = FnSignature(
name = "abs",
returns = INT32,
parameters = listOf(FnParameter("value", INT32)),
isNullCall = true,
isNullable = false,
)

override fun invoke(args: Array<PartiQLValue>): Int32Value {
val value = args[0].check<Int32Value>().value!!
return int32Value(value.absoluteValue)
}
}

@OptIn(PartiQLValueExperimental::class, FnExperimental::class)
internal object Fn_ABS__INT64__INT64 : Fn {

override val signature = FnSignature(
name = "abs",
returns = INT64,
parameters = listOf(FnParameter("value", INT64)),
isNullCall = true,
isNullable = false,
)

override fun invoke(args: Array<PartiQLValue>): Int64Value {
val value = args[0].check<Int64Value>().value!!
return int64Value(value.absoluteValue)
}
}

@OptIn(PartiQLValueExperimental::class, FnExperimental::class)
internal object Fn_ABS__INT__INT : Fn {

override val signature = FnSignature(
name = "abs",
returns = INT,
parameters = listOf(FnParameter("value", INT)),
isNullCall = true,
isNullable = false,
)

override fun invoke(args: Array<PartiQLValue>): IntValue {
val value = args[0].check<IntValue>().value!!
return intValue(value.abs())
}
}

@OptIn(PartiQLValueExperimental::class, FnExperimental::class)
internal object Fn_ABS__DECIMAL_ARBITRARY__DECIMAL_ARBITRARY : Fn {

override val signature = FnSignature(
name = "abs",
returns = DECIMAL_ARBITRARY,
parameters = listOf(FnParameter("value", DECIMAL_ARBITRARY)),
isNullCall = true,
isNullable = false,
)

override fun invoke(args: Array<PartiQLValue>): DecimalValue {
val value = args[0].check<DecimalValue>().value!!
return decimalValue(value.abs())
}
}

@OptIn(PartiQLValueExperimental::class, FnExperimental::class)
internal object Fn_ABS__FLOAT32__FLOAT32 : Fn {

override val signature = FnSignature(
name = "abs",
returns = FLOAT32,
parameters = listOf(FnParameter("value", FLOAT32)),
isNullCall = true,
isNullable = false,
)

override fun invoke(args: Array<PartiQLValue>): Float32Value {
val value = args[0].check<Float32Value>().value!!
return float32Value(value.absoluteValue)
}
}

@OptIn(PartiQLValueExperimental::class, FnExperimental::class)
internal object Fn_ABS__FLOAT64__FLOAT64 : Fn {

override val signature = FnSignature(
name = "abs",
returns = FLOAT64,
parameters = listOf(FnParameter("value", FLOAT64)),
isNullCall = true,
isNullable = false,
)

override fun invoke(args: Array<PartiQLValue>): Float64Value {
val value = args[0].check<Float64Value>().value!!
return float64Value(value.absoluteValue)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// ktlint-disable filename
@file:Suppress("ClassName")

package org.partiql.spi.connector.sql.builtins

import org.partiql.spi.fn.Fn
import org.partiql.spi.fn.FnExperimental
import org.partiql.spi.fn.FnParameter
import org.partiql.spi.fn.FnSignature
import org.partiql.value.ClobValue
import org.partiql.value.Int32Value
import org.partiql.value.PartiQLValue
import org.partiql.value.PartiQLValueExperimental
import org.partiql.value.PartiQLValueType.CLOB
import org.partiql.value.PartiQLValueType.INT32
import org.partiql.value.PartiQLValueType.STRING
import org.partiql.value.PartiQLValueType.SYMBOL
import org.partiql.value.StringValue
import org.partiql.value.SymbolValue
import org.partiql.value.check
import org.partiql.value.int32Value

@OptIn(PartiQLValueExperimental::class, FnExperimental::class)
internal object Fn_CHAR_LENGTH__STRING__INT : Fn {

override val signature = FnSignature(
name = "char_length",
returns = INT32,
parameters = listOf(
FnParameter("value", STRING),
),
isNullCall = true,
isNullable = false,
)

override fun invoke(args: Array<PartiQLValue>): Int32Value {
val value = args[0].check<StringValue>().value!!
return int32Value(value.codePointCount(0, value.length))
}
}

@OptIn(PartiQLValueExperimental::class, FnExperimental::class)
internal object Fn_CHAR_LENGTH__SYMBOL__INT : Fn {

override val signature = FnSignature(
name = "char_length",
returns = INT32,
parameters = listOf(
FnParameter("lhs", SYMBOL),
),
isNullCall = true,
isNullable = false,
)

override fun invoke(args: Array<PartiQLValue>): Int32Value {
val value = args[0].check<SymbolValue>().value!!
return int32Value(value.codePointCount(0, value.length))
}
}

@OptIn(PartiQLValueExperimental::class, FnExperimental::class)
internal object Fn_CHAR_LENGTH__CLOB__INT : Fn {

override val signature = FnSignature(
name = "char_length",
returns = INT32,
parameters = listOf(
FnParameter("lhs", CLOB),
),
isNullCall = true,
isNullable = false,
)

override fun invoke(args: Array<PartiQLValue>): Int32Value {
val value = args[0].check<ClobValue>().value!!
return int32Value(value.size)
}
}
Loading
Loading