Skip to content

Commit

Permalink
Renames all hidden built-in functions using unicode non-character (#1695
Browse files Browse the repository at this point in the history
)
  • Loading branch information
johnedquinn authored Jan 7, 2025
1 parent a7eedee commit 0d123c2
Show file tree
Hide file tree
Showing 70 changed files with 531 additions and 310 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,16 @@ internal class PartiQLParserDefault : PartiQLParser {

companion object {

/**
* The internal system prefix is '\uFDEF', one of unicode's 'internal-use' non-characters. This allows us to "hide"
* certain functions from being directly invocable via PartiQL text.
* See:
* - http://www.unicode.org/faq/private_use.html#nonchar1
* - http://www.unicode.org/versions/Unicode5.2.0/ch16.pdf#G19635
* - http://www.unicode.org/versions/corrigendum9.html
*/
private const val SYSTEM_PREFIX_INTERNAL: String = "\uFDEF"

private val rules = GeneratedParser.ruleNames.asList()

/**
Expand Down Expand Up @@ -1751,9 +1761,10 @@ internal class PartiQLParserDefault : PartiQLParser {
val rhs = visitExpr(ctx.expr(1))
val fieldLit = ctx.dt.text.lowercase()
// TODO error on invalid datetime fields like TIMEZONE_HOUR and TIMEZONE_MINUTE
// TODO: This should (maybe) be parsed into its own node. We could convert this into an operator. See https://github.com/partiql/partiql-lang-kotlin/issues/1690.
when {
ctx.DATE_ADD() != null -> exprCall(identifierChain(identifier("date_add_$fieldLit", false), null), listOf(lhs, rhs), null)
ctx.DATE_DIFF() != null -> exprCall(identifierChain(identifier("date_diff_$fieldLit", false), null), listOf(lhs, rhs), null)
ctx.DATE_ADD() != null -> exprCall(identifierChain(identifier("${SYSTEM_PREFIX_INTERNAL}date_add_$fieldLit", false), null), listOf(lhs, rhs), null)
ctx.DATE_DIFF() != null -> exprCall(identifierChain(identifier("${SYSTEM_PREFIX_INTERNAL}date_diff_$fieldLit", false), null), listOf(lhs, rhs), null)
else -> throw error(ctx, "Expected DATE_ADD or DATE_DIFF")
}
}
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
package org.partiql.planner.internal.utils

import org.partiql.ast.DatetimeField

internal object FunctionUtils {

/**
* The internal system prefix is '\uFDEF', one of unicode's 'internal-use' non-characters. This allows us to "hide"
* certain functions from being directly invocable via PartiQL text.
* See:
* - http://www.unicode.org/faq/private_use.html#nonchar1
* - http://www.unicode.org/versions/Unicode5.2.0/ch16.pdf#G19635
* - http://www.unicode.org/versions/corrigendum9.html
*/
private const val SYSTEM_PREFIX_INTERNAL: String = "\uFDEF"

// The following are public functions, able to be directly invoked via PartiQL text.
const val FN_SUBSTRING: String = "substring"
const val FN_CHAR_LENGTH: String = "char_length"

// The following are hidden operators, unable to be invoked via PartiQL text.
val OP_NOT: String = hide("not")
val OP_AND: String = hide("and")
val OP_OR: String = hide("or")
val OP_POSITION: String = hide("position")
val OP_TRIM: String = hide("trim")
val OP_TRIM_CHARS: String = hide("trim_chars")
val OP_TRIM_LEADING: String = hide("trim_leading")
val OP_TRIM_LEADING_CHARS: String = hide("trim_leading_chars")
val OP_TRIM_TRAILING: String = hide("trim_trailing")
val OP_TRIM_TRAILING_CHARS: String = hide("trim_trailing_chars")
val OP_PLUS: String = hide("plus")
val OP_MINUS: String = hide("minus")
val OP_DIVIDE: String = hide("divide")
val OP_TIMES: String = hide("times")
val OP_MODULO: String = hide("modulo")
val OP_BITWISE_AND: String = hide("bitwise_and")
val OP_CONCAT: String = hide("concat")
val OP_NEG: String = hide("neg")
val OP_POS: String = hide("pos")
val OP_EQ: String = hide("eq")
val OP_GTE: String = hide("gte")
val OP_LTE: String = hide("lte")
val OP_GT: String = hide("gt")
val OP_LT: String = hide("lt")
val OP_IS_TRUE: String = hide("is_true")
val OP_IS_FALSE: String = hide("is_false")
val OP_IS_UNKNOWN: String = hide("is_unknown")
val OP_LIKE: String = hide("like")
val OP_LIKE_ESCAPE: String = hide("like_escape")
val OP_BETWEEN: String = hide("between")
val OP_IN_COLLECTION: String = hide("in_collection")
val OP_IS_NULL: String = hide("is_null")
val OP_IS_MISSING: String = hide("is_missing")
val OP_IS_CHAR: String = hide("is_char")
val OP_IS_VARCHAR: String = hide("is_varchar")
val OP_IS_STRING: String = hide("is_string")
val OP_IS_CLOB: String = hide("is_clob")
val OP_IS_BLOB: String = hide("is_blob")
val OP_IS_SYMBOL: String = hide("is_symbol")
val OP_IS_BOOL: String = hide("is_bool")
val OP_IS_BIT: String = hide("is_bit")
val OP_IS_BIT_VARYING: String = hide("is_bit_varying")
val OP_IS_NUMERIC: String = hide("is_numeric")
val OP_IS_INT: String = hide("is_int")
val OP_IS_INT8: String = hide("is_int8")
val OP_IS_INT16: String = hide("is_int16")
val OP_IS_INT32: String = hide("is_int32")
val OP_IS_INT64: String = hide("is_int64")
val OP_IS_FLOAT32: String = hide("is_float32")
val OP_IS_FLOAT64: String = hide("is_float64")
val OP_IS_REAL: String = hide("is_real")
val OP_IS_DECIMAL: String = hide("is_decimal")
val OP_IS_DATE: String = hide("is_date")
val OP_IS_TIME: String = hide("is_time")
val OP_IS_TIMEZ: String = hide("is_timeWithTz")
val OP_IS_TIMESTAMP: String = hide("is_timestamp")
val OP_IS_TIMESTAMPZ: String = hide("is_timestampWithTz")
val OP_IS_INTERVAL: String = hide("is_interval")
val OP_IS_LIST: String = hide("is_list")
val OP_IS_BAG: String = hide("is_bag")
val OP_IS_SEXP: String = hide("is_sexp")
val OP_IS_STRUCT: String = hide("is_struct")
val OP_IS_CUSTOM: String = hide("is_custom")

/**
* Gets the corresponding operator name for the binary operator ([op]).
* TODO eventually move hard-coded operator resolution into SPI
*/
fun getBinaryOp(op: String): String? {
return when (op) {
"<" -> OP_LT
">" -> OP_GT
"<=" -> OP_LTE
">=" -> OP_GTE
"=" -> OP_EQ
"||" -> OP_CONCAT
"+" -> OP_PLUS
"-" -> OP_MINUS
"*" -> OP_TIMES
"/" -> OP_DIVIDE
"%" -> OP_MODULO
"&" -> OP_BITWISE_AND
else -> null
}
}

/**
* Gets the corresponding operator name for the binary operator ([op]).
* TODO eventually move hard-coded operator resolution into SPI
*/
fun getUnaryOp(op: String): String? {
return when (op) {
"-" -> OP_NEG
"+" -> OP_POS
else -> null
}
}

/**
* Returns a hidden function name for the EXTRACT expression, given the [DatetimeField].
*/
fun opExtract(field: DatetimeField): String {
return hide("extract_${field.name().lowercase()}")
}

/**
* Hides a function name by prefixing it with [SYSTEM_PREFIX_INTERNAL].
*/
fun hide(name: String): String {
return SYSTEM_PREFIX_INTERNAL + name
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,27 @@ package org.partiql.spi.function.builtins
import org.partiql.spi.function.Function
import org.partiql.spi.function.Parameter
import org.partiql.spi.function.builtins.TypePrecedence.TYPE_PRECEDENCE
import org.partiql.spi.function.utils.FunctionUtils
import org.partiql.spi.internal.SqlTypeFamily
import org.partiql.spi.value.Datum
import org.partiql.types.PType

/**
* This represents an operator backed by a function provider. Note that the name of the operator is hidden
* using [FunctionUtils.hide].
*
* This carries along with it a static table containing a mapping between the input types and the implementation.
*
* Implementations of this should invoke [fillTable] in the constructor of the function.
*/
internal abstract class DiadicOperator(
private val name: String,
name: String,
private val lhs: Parameter,
private val rhs: Parameter
) : Function {

private val name = FunctionUtils.hide(name)

companion object {
private val DEC_TINY_INT = PType.decimal(3, 0)
private val DEC_SMALL_INT = PType.decimal(5, 0)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@

package org.partiql.spi.function.builtins

import org.partiql.spi.function.Function
import org.partiql.spi.function.Parameter
import org.partiql.spi.function.utils.FunctionUtils
import org.partiql.spi.value.Datum
import org.partiql.types.PType

internal val Fn_AND__BOOL_BOOL__BOOL = Function.static(
internal val Fn_AND__BOOL_BOOL__BOOL = FunctionUtils.hidden(
name = "and",
returns = PType.bool(),
parameters = arrayOf(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@

package org.partiql.spi.function.builtins

import org.partiql.spi.function.Function
import org.partiql.spi.function.Parameter
import org.partiql.spi.function.utils.FunctionUtils
import org.partiql.spi.value.Datum
import org.partiql.types.PType

internal val Fn_BETWEEN__INT8_INT8_INT8__BOOL = Function.static(
internal val Fn_BETWEEN__INT8_INT8_INT8__BOOL = FunctionUtils.hidden(

name = "between",
returns = PType.bool(),
Expand All @@ -25,7 +25,7 @@ internal val Fn_BETWEEN__INT8_INT8_INT8__BOOL = Function.static(
Datum.bool(value in lower..upper)
}

internal val Fn_BETWEEN__INT16_INT16_INT16__BOOL = Function.static(
internal val Fn_BETWEEN__INT16_INT16_INT16__BOOL = FunctionUtils.hidden(

name = "between",
returns = PType.bool(),
Expand All @@ -42,7 +42,7 @@ internal val Fn_BETWEEN__INT16_INT16_INT16__BOOL = Function.static(
Datum.bool(value in lower..upper)
}

internal val Fn_BETWEEN__INT32_INT32_INT32__BOOL = Function.static(
internal val Fn_BETWEEN__INT32_INT32_INT32__BOOL = FunctionUtils.hidden(

name = "between",
returns = PType.bool(),
Expand All @@ -59,7 +59,7 @@ internal val Fn_BETWEEN__INT32_INT32_INT32__BOOL = Function.static(
Datum.bool(value in lower..upper)
}

internal val Fn_BETWEEN__INT64_INT64_INT64__BOOL = Function.static(
internal val Fn_BETWEEN__INT64_INT64_INT64__BOOL = FunctionUtils.hidden(

name = "between",
returns = PType.bool(),
Expand All @@ -76,7 +76,7 @@ internal val Fn_BETWEEN__INT64_INT64_INT64__BOOL = Function.static(
Datum.bool(value in lower..upper)
}

internal val Fn_BETWEEN__INT_INT_INT__BOOL = Function.static(
internal val Fn_BETWEEN__INT_INT_INT__BOOL = FunctionUtils.hidden(

name = "between",
returns = PType.bool(),
Expand All @@ -93,7 +93,7 @@ internal val Fn_BETWEEN__INT_INT_INT__BOOL = Function.static(
Datum.bool(value in lower..upper)
}

internal val Fn_BETWEEN__DECIMAL_ARBITRARY_DECIMAL_ARBITRARY_DECIMAL_ARBITRARY__BOOL = Function.static(
internal val Fn_BETWEEN__DECIMAL_ARBITRARY_DECIMAL_ARBITRARY_DECIMAL_ARBITRARY__BOOL = FunctionUtils.hidden(

name = "between",
returns = PType.bool(),
Expand All @@ -110,7 +110,7 @@ internal val Fn_BETWEEN__DECIMAL_ARBITRARY_DECIMAL_ARBITRARY_DECIMAL_ARBITRARY__
Datum.bool(value in lower..upper)
}

internal val Fn_BETWEEN__FLOAT32_FLOAT32_FLOAT32__BOOL = Function.static(
internal val Fn_BETWEEN__FLOAT32_FLOAT32_FLOAT32__BOOL = FunctionUtils.hidden(

name = "between",
returns = PType.bool(),
Expand All @@ -127,7 +127,7 @@ internal val Fn_BETWEEN__FLOAT32_FLOAT32_FLOAT32__BOOL = Function.static(
Datum.bool(value in lower..upper)
}

internal val Fn_BETWEEN__FLOAT64_FLOAT64_FLOAT64__BOOL = Function.static(
internal val Fn_BETWEEN__FLOAT64_FLOAT64_FLOAT64__BOOL = FunctionUtils.hidden(

name = "between",
returns = PType.bool(),
Expand All @@ -144,7 +144,7 @@ internal val Fn_BETWEEN__FLOAT64_FLOAT64_FLOAT64__BOOL = Function.static(
Datum.bool(value in lower..upper)
}

internal val Fn_BETWEEN__STRING_STRING_STRING__BOOL = Function.static(
internal val Fn_BETWEEN__STRING_STRING_STRING__BOOL = FunctionUtils.hidden(

name = "between",
returns = PType.bool(),
Expand All @@ -161,7 +161,7 @@ internal val Fn_BETWEEN__STRING_STRING_STRING__BOOL = Function.static(
Datum.bool(value in lower..upper)
}

internal val Fn_BETWEEN__CLOB_CLOB_CLOB__BOOL = Function.static(
internal val Fn_BETWEEN__CLOB_CLOB_CLOB__BOOL = FunctionUtils.hidden(

name = "between",
returns = PType.bool(),
Expand All @@ -178,7 +178,7 @@ internal val Fn_BETWEEN__CLOB_CLOB_CLOB__BOOL = Function.static(
Datum.bool(value in lower..upper)
}

internal val Fn_BETWEEN__DATE_DATE_DATE__BOOL = Function.static(
internal val Fn_BETWEEN__DATE_DATE_DATE__BOOL = FunctionUtils.hidden(

name = "between",
returns = PType.bool(),
Expand All @@ -195,7 +195,7 @@ internal val Fn_BETWEEN__DATE_DATE_DATE__BOOL = Function.static(
Datum.bool(value in lower..upper)
}

internal val Fn_BETWEEN__TIME_TIME_TIME__BOOL = Function.static(
internal val Fn_BETWEEN__TIME_TIME_TIME__BOOL = FunctionUtils.hidden(

name = "between",
returns = PType.bool(),
Expand All @@ -212,7 +212,7 @@ internal val Fn_BETWEEN__TIME_TIME_TIME__BOOL = Function.static(
Datum.bool(value in lower..upper)
}

internal val Fn_BETWEEN__TIMESTAMP_TIMESTAMP_TIMESTAMP__BOOL = Function.static(
internal val Fn_BETWEEN__TIMESTAMP_TIMESTAMP_TIMESTAMP__BOOL = FunctionUtils.hidden(

name = "between",
returns = PType.bool(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,17 @@ import org.partiql.spi.function.builtins.internal.AccumulatorEvery
import org.partiql.spi.function.builtins.internal.AccumulatorMax
import org.partiql.spi.function.builtins.internal.AccumulatorMin
import org.partiql.spi.function.builtins.internal.AccumulatorSum
import org.partiql.spi.function.utils.FunctionUtils
import org.partiql.spi.value.Datum
import org.partiql.types.PType

internal abstract class Fn_COLL_AGG__BAG__ANY(
private var name: String,
name: String,
private var isDistinct: Boolean,
private var accumulator: () -> Accumulator,
) : Function {

private val name: String = FunctionUtils.hide(name)
private var parameters = arrayOf(Parameter("value", PType.bag()))
private var returns = PType.dynamic()

Expand All @@ -32,7 +34,7 @@ internal abstract class Fn_COLL_AGG__BAG__ANY(
override fun getInstance(args: Array<PType>): Function.Instance = instance

private val instance = object : Function.Instance(
name,
this.name,
parameters = arrayOf(PType.bag()),
returns = PType.dynamic(),
) {
Expand Down
Loading

0 comments on commit 0d123c2

Please sign in to comment.