WIP: Compiled SQL function #33

Draft
flecomte wants to merge 37 commits from compiled_sql_function into master
3 changed files with 98 additions and 9 deletions
Showing only changes of commit 7c26670a1b - Show all commits

View File

@@ -106,7 +106,7 @@ private class ParameterNameMalformed(val script: ScriptPart, cause: Throwable) :
@Throws(ParameterTypeMalformed::class)
private fun ScriptPart.getParameterType(): NextScript<ParameterType> {
val fullType = try {
val endTextList = arrayOf(" default ", "=", ")")
val endTextList = arrayOf(" default ", "=")
getNextScript { afterBeginBy(texts = endTextList) }
} catch (e: ParseError) {
throw ParameterTypeMalformed(this, e)
@@ -115,20 +115,26 @@ private fun ScriptPart.getParameterType(): NextScript<ParameterType> {
var rest: ScriptPart = fullType.valueAsScriptPart()
val name = rest
.getNextScript { afterBeginBy("(") }
.getNextScript { afterBeginBy("(", "[") }
.apply { rest = nextScriptPart }
rest = rest.trimStart(' ', '\n', '\t', ',', '(')
val precision = rest
.getNextInteger()
.apply { rest = nextScriptPart }
rest = rest.trimStart(' ', '\n', '\t', ',')
val scale = rest
.getNextInteger()
.apply { rest = nextScriptPart }
rest = rest.trimStart(' ', '\n', '\t', ')')
val isArray = rest.restOfScript.contains("[]")
return NextScript(
ParameterType(
name = name.value.trim(),
name = name.value.trim().trim('[', ']'),
precision = precision.value,
scale = scale.value
scale = scale.value,
isArray = isArray
),
fullType.nextScriptPart.restOfScript
)

View File

@@ -60,12 +60,20 @@ internal fun ScriptPart.getNextScript(isEnd: Context.() -> Boolean = { false }):
}
if (isEnd(Context(index, c, status.copy(), restOfScript))) {
return NextScript(restOfScript.take(index + 1).unescape(), restOfScript.drop(index + 1))
return NextScript(
restOfScript.take(index + 1).unescape(),
restOfScript.drop(index + 1),
)
}
}
if (status.isNotEscaped()) {
return NextScript(restOfScript.trim(), "").trimSpace()
return NextScript(
restOfScript.trim(),
"",
)
}
throw ParseError()
}
@@ -99,6 +107,10 @@ internal fun <T> NextScript<T>.trim(vararg chars: Char): NextScript<T> {
return NextScript(value, restOfScript.apply { dropWhile { it in chars } })
}
internal fun ScriptPart.trimStart(vararg chars: Char): ScriptPart {
return this.change { dropWhile { it in chars } }
}
internal fun ScriptPart.trimEnd(vararg chars: Char): ScriptPart {
return this.change { dropLastWhile { it in chars } }
}
@@ -131,9 +143,8 @@ internal inline fun ScriptPart.change(block: String.() -> String): ScriptPart {
}
internal fun ScriptPart.getNextInteger(): NextScript<Int?> {
val trimmed = restOfScript.trimStart { !it.isDigit() }
val digits = trimmed.takeWhile { it.isDigit() }
val restOfScript = trimmed.trimStart { it.isDigit() }
val digits = restOfScript.takeWhile { it.isDigit() }
val restOfScript = restOfScript.trimStart { it.isDigit() }
return NextScript(digits.toIntOrNull(), restOfScript).trimSpace()
}

View File

@@ -309,6 +309,78 @@ class FunctionTest : FreeSpec({
param[3].direction shouldBe IN
}
}
"Parameters with type array of numeric" - {
val param = parseFunction(
// language=PostgreSQL
"""
create or replace function myfun(one numeric(10, 2)[]) language plpgsql as
$$ begin end;$$;
""".trimIndent()
).parameters
"should have 1 parameters" {
param shouldHaveSize 1
}
"should have parameter name" {
param[0].name shouldBe "one"
}
"should have parameter type is array" {
param[0].type.isArray shouldBe true
}
"should have parameter type name" {
param[0].type.name shouldBe "numeric"
}
"should have parameter type precision" {
param[0].type.precision shouldBe 10
}
"should have parameter type scale" {
param[0].type.scale shouldBe 2
}
}
"Parameters with type array of text" - {
val param = parseFunction(
// language=PostgreSQL
"""
create or replace function myfun(one text[], two int[], three text) language plpgsql as
$$ begin end;$$;
""".trimIndent()
).parameters
"should have 2 parameters" {
param shouldHaveSize 3
}
"should have parameter name" {
param[0].name shouldBe "one"
param[1].name shouldBe "two"
param[2].name shouldBe "three"
}
"should have parameter type is array" {
param[0].type.isArray shouldBe true
param[1].type.isArray shouldBe true
param[2].type.isArray shouldBe false
}
"should have parameter type name" {
param[0].type.name shouldBe "text"
param[1].type.name shouldBe "int"
param[2].type.name shouldBe "text"
}
"should have parameter direction" {
param[0].direction shouldBe IN
param[1].direction shouldBe IN
param[2].direction shouldBe IN
}
}
}
"Function Returns" - {