Skip to content
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package org.partiql.planner.internal.typer.functions

import org.junit.jupiter.api.Test
import org.partiql.parser.PartiQLParser
import org.partiql.plan.Action
import org.partiql.planner.PartiQLPlanner
import org.partiql.planner.internal.TestCatalog
import org.partiql.spi.catalog.Session
import org.partiql.spi.types.PType
import kotlin.test.assertEquals

class LowerTest {

@Test
fun `lower preserves CHAR length`() {
val session = Session.builder()
.catalog("default")
.catalogs(
TestCatalog.builder()
.name("default")
.build()
)
.build()
val parseResult = PartiQLParser.standard().parse("LOWER(CAST('hello' AS CHAR(5)))")
val ast = parseResult.statements[0]
val planner = PartiQLPlanner.builder().build()
val result = planner.plan(ast, session)
val query = result.plan.action as Action.Query
val actualType = query.rex.type.pType
assertEquals(PType.CHAR, actualType.code())
assertEquals(5, actualType.length)
}

@Test
fun `lower preserves VARCHAR length`() {
val session = Session.builder()
.catalog("default")
.catalogs(
TestCatalog.builder()
.name("default")
.build()
)
.build()
val parseResult = PartiQLParser.standard().parse("LOWER(CAST('hello' AS VARCHAR(10)))")
val ast = parseResult.statements[0]
val planner = PartiQLPlanner.builder().build()
val result = planner.plan(ast, session)
val query = result.plan.action as Action.Query
val actualType = query.rex.type.pType
assertEquals(PType.VARCHAR, actualType.code())
assertEquals(10, actualType.length)
}

@Test
fun `lower preserves CLOB type`() {
val session = Session.builder()
.catalog("default")
.catalogs(
TestCatalog.builder()
.name("default")
.build()
)
.build()
val parseResult = PartiQLParser.standard().parse("LOWER(CAST('hello' AS CLOB))")
val ast = parseResult.statements[0]
val planner = PartiQLPlanner.builder().build()
val result = planner.plan(ast, session)
val query = result.plan.action as Action.Query
val actualType = query.rex.type.pType
assertEquals(PType.CLOB, actualType.code())
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package org.partiql.planner.internal.typer.functions

import org.junit.jupiter.api.Test
import org.partiql.parser.PartiQLParser
import org.partiql.plan.Action
import org.partiql.planner.PartiQLPlanner
import org.partiql.planner.internal.TestCatalog
import org.partiql.spi.catalog.Session
import org.partiql.spi.types.PType
import kotlin.test.assertEquals

class UpperTest {

@Test
fun `upper preserves CHAR length`() {
val session = Session.builder()
.catalog("default")
.catalogs(
TestCatalog.builder()
.name("default")
.build()
)
.build()
val parseResult = PartiQLParser.standard().parse("UPPER(CAST('HELLO' AS CHAR(5)))")
val ast = parseResult.statements[0]
val planner = PartiQLPlanner.builder().build()
val result = planner.plan(ast, session)
val query = result.plan.action as Action.Query
val actualType = query.rex.type.pType
assertEquals(PType.CHAR, actualType.code())
assertEquals(5, actualType.length)
}

@Test
fun `upper preserves VARCHAR length`() {
val session = Session.builder()
.catalog("default")
.catalogs(
TestCatalog.builder()
.name("default")
.build()
)
.build()
val parseResult = PartiQLParser.standard().parse("UPPER(CAST('HELLO' AS VARCHAR(10)))")
val ast = parseResult.statements[0]
val planner = PartiQLPlanner.builder().build()
val result = planner.plan(ast, session)
val query = result.plan.action as Action.Query
val actualType = query.rex.type.pType
assertEquals(PType.VARCHAR, actualType.code())
assertEquals(10, actualType.length)
}

@Test
fun `upper preserves CLOB type`() {
val session = Session.builder()
.catalog("default")
.catalogs(
TestCatalog.builder()
.name("default")
.build()
)
.build()
val parseResult = PartiQLParser.standard().parse("UPPER(CAST('HELLO' AS CLOB))")
val ast = parseResult.statements[0]
val planner = PartiQLPlanner.builder().build()
val result = planner.plan(ast, session)
val query = result.plan.action as Action.Query
val actualType = query.rex.type.pType
assertEquals(PType.CLOB, actualType.code())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,51 +3,66 @@

package org.partiql.spi.function.builtins

import org.partiql.spi.function.Fn
import org.partiql.spi.function.FnOverload
import org.partiql.spi.function.Function
import org.partiql.spi.function.Parameter
import org.partiql.spi.function.RoutineOverloadSignature
import org.partiql.spi.types.PType
import org.partiql.spi.value.Datum

internal val Fn_LOWER__CHAR__CHAR = Function.overload(
internal object FnLower : FnOverload() {

name = "lower",
returns = PType.character(),
parameters = arrayOf(Parameter("value", PType.character())),
override fun getSignature(): RoutineOverloadSignature {
return RoutineOverloadSignature("lower", listOf(PType.dynamic()))
}

) { args ->
TODO("Not yet implemented")
override fun getInstance(args: Array<PType>): Fn? {
val inputType = args[0]
return when (inputType.code()) {
PType.CHAR -> Function.instance(
name = "lower",
returns = PType.character(inputType.length),
parameters = arrayOf(Parameter("value", inputType)),
) { args ->
val string = args[0].bytes.toString(Charsets.UTF_8)
val result = string.lowercase()
Datum.character(result, inputType.length)
}
PType.VARCHAR -> Function.instance(
name = "lower",
returns = PType.varchar(inputType.length),
parameters = arrayOf(Parameter("value", inputType)),
) { args ->
val string = args[0].bytes.toString(Charsets.UTF_8)
val result = string.lowercase()
Datum.varchar(result, inputType.length)
}
PType.STRING -> Function.instance(
name = "lower",
returns = PType.string(),
parameters = arrayOf(Parameter("value", inputType)),
) { args ->
val string = args[0].string
val result = string.lowercase()
Datum.string(result)
}
PType.CLOB -> Function.instance(
name = "lower",
returns = PType.clob(inputType.length),
parameters = arrayOf(Parameter("value", inputType)),
) { args ->
val string = args[0].bytes.toString(Charsets.UTF_8)
val result = string.lowercase()
Datum.clob(result.toByteArray())
}
else -> null
}
}
}

internal val Fn_LOWER__VARCHAR__VARCHAR = Function.overload(

name = "lower",
returns = PType.varchar(),
parameters = arrayOf(Parameter("value", PType.varchar())),

) { args ->
TODO("Not yet implemented")
}

internal val Fn_LOWER__STRING__STRING = Function.overload(

name = "lower",
returns = PType.string(),
parameters = arrayOf(Parameter("value", PType.string())),

) { args ->
val string = args[0].string
val result = string.lowercase()
Datum.string(result)
}

internal val Fn_LOWER__CLOB__CLOB = Function.overload(

name = "lower",
returns = PType.clob(Int.MAX_VALUE),
parameters = arrayOf(Parameter("value", PType.clob(Int.MAX_VALUE))),

) { args ->
val string = args[0].bytes.toString(Charsets.UTF_8)
val result = string.lowercase()
Datum.clob(result.toByteArray())
}
// Keep the old function names for backward compatibility in Builtins.kt
internal val Fn_LOWER__CHAR__CHAR = FnLower
internal val Fn_LOWER__VARCHAR__VARCHAR = FnLower
internal val Fn_LOWER__STRING__STRING = FnLower
internal val Fn_LOWER__CLOB__CLOB = FnLower
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,6 @@ import org.partiql.spi.utils.FunctionUtils
import org.partiql.spi.utils.StringUtils.codepointTrim
import org.partiql.spi.value.Datum

internal val Fn_TRIM__CHAR__CHAR = FunctionUtils.hidden(

name = "trim",
returns = PType.character(),
parameters = arrayOf(Parameter("value", PType.character())),

) { args ->
TODO("Not yet implemented")
}

internal val Fn_TRIM__VARCHAR__VARCHAR = FunctionUtils.hidden(

name = "trim",
returns = PType.varchar(),
parameters = arrayOf(Parameter("value", PType.varchar())),

) { args ->
TODO("Not yet implemented")
}

/**
* From section 6.7 of SQL 92 spec:
* ```
Expand Down Expand Up @@ -58,26 +38,42 @@ internal val Fn_TRIM__VARCHAR__VARCHAR = FunctionUtils.hidden(
* * `<trim character> ::= <character value expression>`
* * `<trim source> ::= <character value expression>`
*/
internal val Fn_TRIM__STRING__STRING = FunctionUtils.hidden(
internal val Fn_TRIM__CHAR__CHAR = FunctionUtils.hidden(
name = "trim",
returns = PType.character(),
parameters = arrayOf(Parameter("value", PType.character())),
) { args ->
val string = args[0].bytes.toString(Charsets.UTF_8)
val result = string.codepointTrim()
Datum.character(result)
}

internal val Fn_TRIM__VARCHAR__VARCHAR = FunctionUtils.hidden(
name = "trim",
returns = PType.varchar(),
parameters = arrayOf(Parameter("value", PType.varchar())),
) { args ->
val string = args[0].bytes.toString(Charsets.UTF_8)
val result = string.codepointTrim()
Datum.varchar(result)
}

internal val Fn_TRIM__STRING__STRING = FunctionUtils.hidden(
name = "trim",
returns = PType.string(),
parameters = arrayOf(Parameter("value", PType.string())),

) { args ->
val value = args[0].string
val result = value.codepointTrim()
Datum.string(result)
}

internal val Fn_TRIM__CLOB__CLOB = FunctionUtils.hidden(

name = "trim",
returns = PType.clob(Int.MAX_VALUE),
parameters = arrayOf(Parameter("value", PType.clob(Int.MAX_VALUE))),

) { args ->
val string = args[0].bytes.toString(Charsets.UTF_8)
val result = string.codepointTrim()
Datum.clob(result.toByteArray())
}
}
Loading
Loading