use crate::sync::Arc;
use std::fmt;
use std::fmt::{Debug, Display};
use strum::IntoEnumIterator;
use turso_ext::{FinalizeFunction, InitAggFunction, ScalarFunction, StepFunction};
use crate::LimboError;
pub trait Deterministic: std::fmt::Display {
fn is_deterministic(&self) -> bool;
}
pub struct ExternalFunc {
pub name: String,
pub func: ExtFunc,
}
impl Deterministic for ExternalFunc {
fn is_deterministic(&self) -> bool {
false
}
}
#[derive(Debug, Clone)]
pub enum ExtFunc {
Scalar(ScalarFunction),
Aggregate {
argc: usize,
init: InitAggFunction,
step: StepFunction,
finalize: FinalizeFunction,
},
}
impl ExtFunc {
pub fn agg_args(&self) -> Result<usize, ()> {
if let ExtFunc::Aggregate { argc, .. } = self {
return Ok(*argc);
}
Err(())
}
}
impl ExternalFunc {
pub fn new_scalar(name: String, func: ScalarFunction) -> Self {
Self {
name,
func: ExtFunc::Scalar(func),
}
}
pub fn new_aggregate(
name: String,
argc: i32,
func: (InitAggFunction, StepFunction, FinalizeFunction),
) -> Self {
Self {
name,
func: ExtFunc::Aggregate {
argc: argc as usize,
init: func.0,
step: func.1,
finalize: func.2,
},
}
}
}
impl Debug for ExternalFunc {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.name)
}
}
impl Display for ExternalFunc {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.name)
}
}
#[cfg(feature = "json")]
#[derive(Debug, Clone, PartialEq, strum::EnumIter)]
pub enum JsonFunc {
Json,
Jsonb,
JsonArray,
JsonbArray,
JsonArrayLength,
JsonArrowExtract,
JsonArrowShiftExtract,
JsonExtract,
JsonbExtract,
JsonObject,
JsonbObject,
JsonType,
JsonErrorPosition,
JsonValid,
JsonPatch,
JsonbPatch,
JsonRemove,
JsonbRemove,
JsonReplace,
JsonbReplace,
JsonInsert,
JsonbInsert,
JsonPretty,
JsonSet,
JsonbSet,
JsonQuote,
}
#[cfg(feature = "json")]
impl Deterministic for JsonFunc {
fn is_deterministic(&self) -> bool {
true
}
}
#[cfg(feature = "json")]
impl Display for JsonFunc {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{}",
match self {
Self::Json => "json",
Self::Jsonb => "jsonb",
Self::JsonArray => "json_array",
Self::JsonbArray => "jsonb_array",
Self::JsonExtract => "json_extract",
Self::JsonbExtract => "jsonb_extract",
Self::JsonArrayLength => "json_array_length",
Self::JsonArrowExtract => "->",
Self::JsonArrowShiftExtract => "->>",
Self::JsonObject => "json_object",
Self::JsonbObject => "jsonb_object",
Self::JsonType => "json_type",
Self::JsonErrorPosition => "json_error_position",
Self::JsonValid => "json_valid",
Self::JsonPatch => "json_patch",
Self::JsonbPatch => "jsonb_patch",
Self::JsonRemove => "json_remove",
Self::JsonbRemove => "jsonb_remove",
Self::JsonReplace => "json_replace",
Self::JsonbReplace => "jsonb_replace",
Self::JsonInsert => "json_insert",
Self::JsonbInsert => "jsonb_insert",
Self::JsonPretty => "json_pretty",
Self::JsonSet => "json_set",
Self::JsonbSet => "jsonb_set",
Self::JsonQuote => "json_quote",
}
)
}
}
#[cfg(feature = "json")]
impl JsonFunc {
pub fn is_internal(&self) -> bool {
matches!(self, Self::JsonArrowExtract | Self::JsonArrowShiftExtract)
}
pub fn arities(&self) -> &'static [i32] {
match self {
Self::Json
| Self::Jsonb
| Self::JsonQuote
| Self::JsonErrorPosition
| Self::JsonValid => &[1],
Self::JsonPatch | Self::JsonbPatch => &[2],
Self::JsonArrayLength | Self::JsonType => &[1, 2],
Self::JsonArrowExtract | Self::JsonArrowShiftExtract => &[2],
_ => &[-1],
}
}
}
#[derive(Debug, Clone, strum::EnumIter)]
pub enum VectorFunc {
Vector,
Vector32,
Vector32Sparse,
Vector64,
Vector8,
Vector1Bit,
VectorExtract,
VectorDistanceCos,
VectorDistanceL2,
VectorDistanceJaccard,
VectorDistanceDot,
VectorConcat,
VectorSlice,
}
impl Deterministic for VectorFunc {
fn is_deterministic(&self) -> bool {
true
}
}
impl Display for VectorFunc {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let str = match self {
Self::Vector => "vector",
Self::Vector32 => "vector32",
Self::Vector32Sparse => "vector32_sparse",
Self::Vector64 => "vector64",
Self::Vector8 => "vector8",
Self::Vector1Bit => "vector1bit",
Self::VectorExtract => "vector_extract",
Self::VectorDistanceCos => "vector_distance_cos",
Self::VectorDistanceL2 => "vector_distance_l2",
Self::VectorDistanceJaccard => "vector_distance_jaccard",
Self::VectorDistanceDot => "vector_distance_dot",
Self::VectorConcat => "vector_concat",
Self::VectorSlice => "vector_slice",
};
write!(f, "{str}")
}
}
impl VectorFunc {
pub fn arities(&self) -> &'static [i32] {
match self {
Self::Vector
| Self::Vector32
| Self::Vector32Sparse
| Self::Vector64
| Self::Vector8
| Self::Vector1Bit
| Self::VectorExtract => &[1],
Self::VectorDistanceCos
| Self::VectorDistanceL2
| Self::VectorDistanceJaccard
| Self::VectorDistanceDot => &[2],
Self::VectorSlice => &[3],
Self::VectorConcat => &[-1],
}
}
}
#[cfg(all(feature = "fts", not(target_family = "wasm")))]
#[derive(Debug, Clone, PartialEq, strum::EnumIter)]
pub enum FtsFunc {
Score,
Match,
Highlight,
}
#[cfg(all(feature = "fts", not(target_family = "wasm")))]
impl FtsFunc {
pub fn is_deterministic(&self) -> bool {
true
}
pub fn arities(&self) -> &'static [i32] {
match self {
Self::Highlight => &[4],
Self::Score | Self::Match => &[-1],
}
}
}
#[cfg(all(feature = "fts", not(target_family = "wasm")))]
impl Display for FtsFunc {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let str = match self {
Self::Score => "fts_score",
Self::Match => "fts_match",
Self::Highlight => "fts_highlight",
};
write!(f, "{str}")
}
}
#[derive(Debug, Clone, strum::EnumIter)]
pub enum AggFunc {
Avg,
Count,
Count0,
GroupConcat,
Max,
Min,
StringAgg,
Sum,
Total,
#[cfg(feature = "json")]
JsonbGroupArray,
#[cfg(feature = "json")]
JsonGroupArray,
#[cfg(feature = "json")]
JsonbGroupObject,
#[cfg(feature = "json")]
JsonGroupObject,
ArrayAgg,
#[strum(disabled)]
External(Arc<ExtFunc>),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, strum::EnumIter)]
pub enum WindowFunc {
RowNumber,
}
impl WindowFunc {
pub fn arities(&self) -> &'static [i32] {
match self {
Self::RowNumber => &[0],
}
}
}
impl Deterministic for WindowFunc {
fn is_deterministic(&self) -> bool {
true
}
}
impl std::fmt::Display for WindowFunc {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::RowNumber => write!(f, "row_number"),
}
}
}
impl PartialEq for AggFunc {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::Avg, Self::Avg)
| (Self::Count, Self::Count)
| (Self::GroupConcat, Self::GroupConcat)
| (Self::Max, Self::Max)
| (Self::Min, Self::Min)
| (Self::StringAgg, Self::StringAgg)
| (Self::Sum, Self::Sum)
| (Self::Total, Self::Total)
| (Self::ArrayAgg, Self::ArrayAgg) => true,
(Self::External(a), Self::External(b)) => Arc::ptr_eq(a, b),
_ => false,
}
}
}
impl Deterministic for AggFunc {
fn is_deterministic(&self) -> bool {
false }
}
impl std::fmt::Display for AggFunc {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.as_str())
}
}
impl AggFunc {
pub fn num_args(&self) -> usize {
match self {
Self::Avg => 1,
Self::Count0 => 0,
Self::Count => 1,
Self::GroupConcat => 1,
Self::Max => 1,
Self::Min => 1,
Self::StringAgg => 2,
Self::Sum => 1,
Self::Total => 1,
Self::ArrayAgg => 1,
#[cfg(feature = "json")]
Self::JsonGroupArray | Self::JsonbGroupArray => 1,
#[cfg(feature = "json")]
Self::JsonGroupObject | Self::JsonbGroupObject => 2,
Self::External(func) => func.agg_args().unwrap_or(0),
}
}
pub fn arities(&self) -> &'static [i32] {
match self {
Self::Avg => &[1],
Self::Count0 => &[0],
Self::Count => &[1],
Self::GroupConcat => &[1, 2],
Self::Max => &[1],
Self::Min => &[1],
Self::StringAgg => &[2],
Self::Sum => &[1],
Self::Total => &[1],
Self::ArrayAgg => &[1],
#[cfg(feature = "json")]
Self::JsonGroupArray | Self::JsonbGroupArray => &[1],
#[cfg(feature = "json")]
Self::JsonGroupObject | Self::JsonbGroupObject => &[2],
Self::External(_) => &[-1],
}
}
pub fn as_str(&self) -> &'static str {
match self {
Self::Avg => "avg",
Self::Count0 => "count",
Self::Count => "count",
Self::GroupConcat => "group_concat",
Self::Max => "max",
Self::Min => "min",
Self::StringAgg => "string_agg",
Self::Sum => "sum",
Self::Total => "total",
Self::ArrayAgg => "array_agg",
#[cfg(feature = "json")]
Self::JsonbGroupArray => "jsonb_group_array",
#[cfg(feature = "json")]
Self::JsonGroupArray => "json_group_array",
#[cfg(feature = "json")]
Self::JsonbGroupObject => "jsonb_group_object",
#[cfg(feature = "json")]
Self::JsonGroupObject => "json_group_object",
Self::External(_) => "extension function",
}
}
}
#[derive(Debug, Clone, PartialEq, strum::EnumIter)]
pub enum ScalarFunc {
Cast,
Changes,
Char,
Coalesce,
Concat,
ConcatWs,
Glob,
IfNull,
Iif,
Instr,
Like,
Abs,
Upper,
Lower,
Random,
RandomBlob,
Trim,
LTrim,
RTrim,
Round,
Length,
OctetLength,
Min,
Max,
Nullif,
Sign,
Substr,
Substring,
Soundex,
Date,
Time,
TotalChanges,
DateTime,
Typeof,
Unicode,
Unistr,
UnistrQuote,
Quote,
SqliteVersion,
TursoVersion,
SqliteSourceId,
UnixEpoch,
JulianDay,
Hex,
Unhex,
ZeroBlob,
LastInsertRowid,
Replace,
#[cfg(feature = "fs")]
#[cfg(not(target_family = "wasm"))]
LoadExtension,
StrfTime,
Printf,
Likely,
TimeDiff,
Likelihood,
TableColumnsJsonArray,
BinRecordJsonObject,
Attach,
Detach,
Unlikely,
StatInit,
StatPush,
StatGet,
ConnTxnId,
IsAutocommit,
TestUintEncode,
TestUintDecode,
TestUintAdd,
TestUintSub,
TestUintMul,
TestUintDiv,
TestUintLt,
TestUintEq,
StringReverse,
BooleanToInt,
IntToBoolean,
ValidateIpAddr,
NumericEncode,
NumericDecode,
NumericAdd,
NumericSub,
NumericMul,
NumericDiv,
NumericLt,
NumericEq,
Array,
ArrayElement,
ArraySetElement,
ArrayLength,
ArrayAppend,
ArrayPrepend,
ArrayCat,
ArrayRemove,
ArrayContains,
ArrayPosition,
ArraySlice,
StringToArray,
ArrayToString,
ArrayOverlap,
ArrayContainsAll,
StructPack,
StructExtractFunc,
UnionValueFunc,
UnionTagFunc,
UnionExtractFunc,
}
impl Deterministic for ScalarFunc {
fn is_deterministic(&self) -> bool {
match self {
ScalarFunc::Cast => true,
ScalarFunc::Changes => false, ScalarFunc::Char => true,
ScalarFunc::Coalesce => true,
ScalarFunc::Concat => true,
ScalarFunc::ConcatWs => true,
ScalarFunc::Glob => true,
ScalarFunc::IfNull => true,
ScalarFunc::Iif => true,
ScalarFunc::Instr => true,
ScalarFunc::Like => true,
ScalarFunc::Abs => true,
ScalarFunc::Upper => true,
ScalarFunc::Lower => true,
ScalarFunc::Random => false, ScalarFunc::RandomBlob => false, ScalarFunc::Trim => true,
ScalarFunc::LTrim => true,
ScalarFunc::RTrim => true,
ScalarFunc::Round => true,
ScalarFunc::Length => true,
ScalarFunc::OctetLength => true,
ScalarFunc::Min => true,
ScalarFunc::Max => true,
ScalarFunc::Nullif => true,
ScalarFunc::Sign => true,
ScalarFunc::Substr => true,
ScalarFunc::Substring => true,
ScalarFunc::Soundex => true,
ScalarFunc::Date => false,
ScalarFunc::Time => false,
ScalarFunc::TotalChanges => false,
ScalarFunc::DateTime => false,
ScalarFunc::Typeof => true,
ScalarFunc::Unicode => true,
ScalarFunc::Unistr => true,
ScalarFunc::UnistrQuote => true,
ScalarFunc::Quote => true,
ScalarFunc::SqliteVersion => false,
ScalarFunc::TursoVersion => false,
ScalarFunc::SqliteSourceId => false,
ScalarFunc::UnixEpoch => false,
ScalarFunc::JulianDay => false,
ScalarFunc::Hex => true,
ScalarFunc::Unhex => true,
ScalarFunc::ZeroBlob => true,
ScalarFunc::LastInsertRowid => false,
ScalarFunc::Replace => true,
#[cfg(feature = "fs")]
#[cfg(not(target_family = "wasm"))]
ScalarFunc::LoadExtension => false,
ScalarFunc::StrfTime => false,
ScalarFunc::Printf => true,
ScalarFunc::Likely => true,
ScalarFunc::TimeDiff => false,
ScalarFunc::Likelihood => true,
ScalarFunc::TableColumnsJsonArray => true, ScalarFunc::BinRecordJsonObject => true,
ScalarFunc::Attach => false, ScalarFunc::Detach => false, ScalarFunc::Unlikely => true,
ScalarFunc::StatInit => false, ScalarFunc::StatPush => false, ScalarFunc::StatGet => false, ScalarFunc::ConnTxnId => false, ScalarFunc::IsAutocommit => false, ScalarFunc::TestUintEncode
| ScalarFunc::TestUintDecode
| ScalarFunc::TestUintAdd
| ScalarFunc::TestUintSub
| ScalarFunc::TestUintMul
| ScalarFunc::TestUintDiv
| ScalarFunc::TestUintLt
| ScalarFunc::TestUintEq
| ScalarFunc::StringReverse => true,
ScalarFunc::BooleanToInt
| ScalarFunc::IntToBoolean
| ScalarFunc::ValidateIpAddr
| ScalarFunc::NumericEncode
| ScalarFunc::NumericDecode
| ScalarFunc::NumericAdd
| ScalarFunc::NumericSub
| ScalarFunc::NumericMul
| ScalarFunc::NumericDiv
| ScalarFunc::NumericLt
| ScalarFunc::NumericEq => true,
ScalarFunc::Array
| ScalarFunc::ArrayElement
| ScalarFunc::ArraySetElement
| ScalarFunc::ArrayLength
| ScalarFunc::ArrayAppend
| ScalarFunc::ArrayPrepend
| ScalarFunc::ArrayCat
| ScalarFunc::ArrayRemove
| ScalarFunc::ArrayContains
| ScalarFunc::ArrayPosition
| ScalarFunc::ArraySlice
| ScalarFunc::StringToArray
| ScalarFunc::ArrayToString
| ScalarFunc::ArrayOverlap
| ScalarFunc::ArrayContainsAll => true,
ScalarFunc::StructPack
| ScalarFunc::StructExtractFunc
| ScalarFunc::UnionValueFunc
| ScalarFunc::UnionTagFunc
| ScalarFunc::UnionExtractFunc => true,
}
}
}
impl ScalarFunc {
pub fn returns_array_blob(&self) -> bool {
matches!(
self,
Self::Array
| Self::ArraySetElement
| Self::ArrayAppend
| Self::ArrayPrepend
| Self::ArrayCat
| Self::ArrayRemove
| Self::ArraySlice
| Self::StringToArray
)
}
}
impl Display for ScalarFunc {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let str = match self {
Self::Cast => "cast",
Self::Changes => "changes",
Self::Char => "char",
Self::Coalesce => "coalesce",
Self::Concat => "concat",
Self::ConcatWs => "concat_ws",
Self::Glob => "glob",
Self::IfNull => "ifnull",
Self::Iif => "iif",
Self::Instr => "instr",
Self::Like => "like",
Self::Abs => "abs",
Self::Upper => "upper",
Self::Lower => "lower",
Self::Random => "random",
Self::RandomBlob => "randomblob",
Self::Trim => "trim",
Self::LTrim => "ltrim",
Self::RTrim => "rtrim",
Self::Round => "round",
Self::Length => "length",
Self::OctetLength => "octet_length",
Self::Min => "min",
Self::Max => "max",
Self::Nullif => "nullif",
Self::Sign => "sign",
Self::Substr => "substr",
Self::Substring => "substring",
Self::Soundex => "soundex",
Self::Date => "date",
Self::Time => "time",
Self::TotalChanges => "total_changes",
Self::Typeof => "typeof",
Self::Unicode => "unicode",
Self::Unistr => "unistr",
Self::UnistrQuote => "unistr_quote",
Self::Quote => "quote",
Self::SqliteVersion => "sqlite_version",
Self::TursoVersion => "turso_version",
Self::SqliteSourceId => "sqlite_source_id",
Self::JulianDay => "julianday",
Self::UnixEpoch => "unixepoch",
Self::Hex => "hex",
Self::Unhex => "unhex",
Self::ZeroBlob => "zeroblob",
Self::LastInsertRowid => "last_insert_rowid",
Self::Replace => "replace",
Self::DateTime => "datetime",
#[cfg(feature = "fs")]
#[cfg(not(target_family = "wasm"))]
Self::LoadExtension => "load_extension",
Self::StrfTime => "strftime",
Self::Printf => "printf",
Self::Likely => "likely",
Self::TimeDiff => "timediff",
Self::Likelihood => "likelihood",
Self::TableColumnsJsonArray => "table_columns_json_array",
Self::BinRecordJsonObject => "bin_record_json_object",
Self::Attach => "attach",
Self::Detach => "detach",
Self::Unlikely => "unlikely",
Self::StatInit => "stat_init",
Self::StatPush => "stat_push",
Self::StatGet => "stat_get",
Self::ConnTxnId => "conn_txn_id",
Self::IsAutocommit => "is_autocommit",
Self::TestUintEncode => "test_uint_encode",
Self::TestUintDecode => "test_uint_decode",
Self::TestUintAdd => "test_uint_add",
Self::TestUintSub => "test_uint_sub",
Self::TestUintMul => "test_uint_mul",
Self::TestUintDiv => "test_uint_div",
Self::TestUintLt => "test_uint_lt",
Self::TestUintEq => "test_uint_eq",
Self::StringReverse => "string_reverse",
Self::BooleanToInt => "boolean_to_int",
Self::IntToBoolean => "int_to_boolean",
Self::ValidateIpAddr => "validate_ipaddr",
Self::NumericEncode => "numeric_encode",
Self::NumericDecode => "numeric_decode",
Self::NumericAdd => "numeric_add",
Self::NumericSub => "numeric_sub",
Self::NumericMul => "numeric_mul",
Self::NumericDiv => "numeric_div",
Self::NumericLt => "numeric_lt",
Self::NumericEq => "numeric_eq",
Self::Array => "array",
Self::ArrayElement => "array_element",
Self::ArraySetElement => "array_set_element",
Self::ArrayLength => "array_length",
Self::ArrayAppend => "array_append",
Self::ArrayPrepend => "array_prepend",
Self::ArrayCat => "array_cat",
Self::ArrayRemove => "array_remove",
Self::ArrayContains => "array_contains",
Self::ArrayPosition => "array_position",
Self::ArraySlice => "array_slice",
Self::StringToArray => "string_to_array",
Self::ArrayToString => "array_to_string",
Self::ArrayOverlap => "array_overlap",
Self::ArrayContainsAll => "array_contains_all",
Self::StructPack => "struct_pack",
Self::StructExtractFunc => "struct_extract",
Self::UnionValueFunc => "union_value",
Self::UnionTagFunc => "union_tag",
Self::UnionExtractFunc => "union_extract",
};
write!(f, "{str}")
}
}
impl ScalarFunc {
pub fn is_internal(&self) -> bool {
matches!(
self,
Self::Cast
| Self::Array
| Self::ArrayElement
| Self::ArraySetElement
| Self::StatInit
| Self::StatPush
| Self::StatGet
| Self::Attach
| Self::Detach
| Self::TableColumnsJsonArray
| Self::BinRecordJsonObject
| Self::ConnTxnId
| Self::IsAutocommit
)
}
pub fn arities(&self) -> &'static [i32] {
match self {
Self::Changes
| Self::LastInsertRowid
| Self::Random
| Self::SqliteVersion
| Self::TursoVersion
| Self::SqliteSourceId
| Self::TotalChanges => &[0],
Self::Abs
| Self::Hex
| Self::Length
| Self::Lower
| Self::OctetLength
| Self::Quote
| Self::UnistrQuote
| Self::RandomBlob
| Self::Sign
| Self::Soundex
| Self::Typeof
| Self::Unicode
| Self::Unistr
| Self::Upper
| Self::ZeroBlob
| Self::Likely
| Self::Unlikely => &[1],
Self::Glob
| Self::Instr
| Self::Nullif
| Self::IfNull
| Self::Likelihood
| Self::TimeDiff => &[2],
Self::Iif | Self::Replace => &[3],
Self::Like => &[2, 3],
Self::Trim | Self::LTrim | Self::RTrim | Self::Round | Self::Unhex => &[1, 2],
Self::Substr | Self::Substring => &[2, 3],
Self::Char
| Self::Coalesce
| Self::Concat
| Self::ConcatWs
| Self::Date
| Self::Time
| Self::DateTime
| Self::UnixEpoch
| Self::JulianDay
| Self::StrfTime
| Self::Printf => &[-1],
#[cfg(feature = "fs")]
#[cfg(not(target_family = "wasm"))]
Self::LoadExtension => &[-1],
Self::Cast
| Self::StatInit
| Self::StatPush
| Self::StatGet
| Self::Attach
| Self::Detach
| Self::TableColumnsJsonArray
| Self::BinRecordJsonObject
| Self::ConnTxnId
| Self::IsAutocommit => &[0],
Self::Max | Self::Min => &[-1],
Self::TestUintEncode | Self::TestUintDecode | Self::StringReverse => &[1],
Self::TestUintAdd
| Self::TestUintSub
| Self::TestUintMul
| Self::TestUintDiv
| Self::TestUintLt
| Self::TestUintEq => &[2],
Self::BooleanToInt
| Self::IntToBoolean
| Self::ValidateIpAddr
| Self::NumericDecode => &[1],
Self::NumericAdd
| Self::NumericSub
| Self::NumericMul
| Self::NumericDiv
| Self::NumericLt
| Self::NumericEq => &[2],
Self::NumericEncode => &[3],
Self::Array => &[-1], Self::ArrayElement => &[2],
Self::ArraySetElement => &[3],
Self::ArrayLength => &[1, 2],
Self::ArrayAppend
| Self::ArrayPrepend
| Self::ArrayCat
| Self::ArrayRemove
| Self::ArrayContains
| Self::ArrayPosition
| Self::ArrayOverlap
| Self::ArrayContainsAll => &[2],
Self::ArraySlice => &[3],
Self::StringToArray => &[2, 3],
Self::ArrayToString => &[2, 3],
Self::StructPack => &[-1],
Self::StructExtractFunc => &[2], Self::UnionValueFunc => &[2], Self::UnionTagFunc => &[1], Self::UnionExtractFunc => &[2], }
}
pub fn can_mask_nulls(&self) -> bool {
matches!(self, Self::Coalesce | Self::IfNull)
}
}
#[derive(Debug, Clone, PartialEq, strum::EnumIter)]
pub enum MathFunc {
Acos,
Acosh,
Asin,
Asinh,
Atan,
Atan2,
Atanh,
Ceil,
Ceiling,
Cos,
Cosh,
Degrees,
Exp,
Floor,
Ln,
Log,
Log10,
Log2,
Mod,
Pi,
Pow,
Power,
Radians,
Sin,
Sinh,
Sqrt,
Tan,
Tanh,
Trunc,
}
pub enum MathFuncArity {
Nullary,
Unary,
Binary,
UnaryOrBinary,
}
impl Deterministic for MathFunc {
fn is_deterministic(&self) -> bool {
true
}
}
impl MathFunc {
pub fn arity(&self) -> MathFuncArity {
match self {
Self::Pi => MathFuncArity::Nullary,
Self::Acos
| Self::Acosh
| Self::Asin
| Self::Asinh
| Self::Atan
| Self::Atanh
| Self::Ceil
| Self::Ceiling
| Self::Cos
| Self::Cosh
| Self::Degrees
| Self::Exp
| Self::Floor
| Self::Ln
| Self::Log10
| Self::Log2
| Self::Radians
| Self::Sin
| Self::Sinh
| Self::Sqrt
| Self::Tan
| Self::Tanh
| Self::Trunc => MathFuncArity::Unary,
Self::Atan2 | Self::Mod | Self::Pow | Self::Power => MathFuncArity::Binary,
Self::Log => MathFuncArity::UnaryOrBinary,
}
}
pub fn arities(&self) -> &'static [i32] {
match self.arity() {
MathFuncArity::Nullary => &[0],
MathFuncArity::Unary => &[1],
MathFuncArity::Binary => &[2],
MathFuncArity::UnaryOrBinary => &[1, 2],
}
}
}
impl Display for MathFunc {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let str = match self {
Self::Acos => "acos",
Self::Acosh => "acosh",
Self::Asin => "asin",
Self::Asinh => "asinh",
Self::Atan => "atan",
Self::Atan2 => "atan2",
Self::Atanh => "atanh",
Self::Ceil => "ceil",
Self::Ceiling => "ceiling",
Self::Cos => "cos",
Self::Cosh => "cosh",
Self::Degrees => "degrees",
Self::Exp => "exp",
Self::Floor => "floor",
Self::Ln => "ln",
Self::Log => "log",
Self::Log10 => "log10",
Self::Log2 => "log2",
Self::Mod => "mod",
Self::Pi => "pi",
Self::Pow => "pow",
Self::Power => "power",
Self::Radians => "radians",
Self::Sin => "sin",
Self::Sinh => "sinh",
Self::Sqrt => "sqrt",
Self::Tan => "tan",
Self::Tanh => "tanh",
Self::Trunc => "trunc",
};
write!(f, "{str}")
}
}
#[derive(Debug, Clone)]
pub enum AlterTableFunc {
RenameTable,
AlterColumn,
RenameColumn,
}
impl Display for AlterTableFunc {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
AlterTableFunc::RenameTable => write!(f, "limbo_rename_table"),
AlterTableFunc::RenameColumn => write!(f, "limbo_rename_column"),
AlterTableFunc::AlterColumn => write!(f, "limbo_alter_column"),
}
}
}
#[derive(Debug, Clone)]
pub enum Func {
Agg(AggFunc),
Window(WindowFunc),
Scalar(ScalarFunc),
Math(MathFunc),
Vector(VectorFunc),
#[cfg(all(feature = "fts", not(target_family = "wasm")))]
Fts(FtsFunc),
#[cfg(feature = "json")]
Json(JsonFunc),
AlterTable(AlterTableFunc),
External(Arc<ExternalFunc>),
}
impl Display for Func {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Agg(agg_func) => write!(f, "{}", agg_func.as_str()),
Self::Window(window_func) => write!(f, "{window_func}"),
Self::Scalar(scalar_func) => write!(f, "{scalar_func}"),
Self::Math(math_func) => write!(f, "{math_func}"),
Self::Vector(vector_func) => write!(f, "{vector_func}"),
#[cfg(all(feature = "fts", not(target_family = "wasm")))]
Self::Fts(fts_func) => write!(f, "{fts_func}"),
#[cfg(feature = "json")]
Self::Json(json_func) => write!(f, "{json_func}"),
Self::External(generic_func) => write!(f, "{generic_func}"),
Self::AlterTable(alter_func) => write!(f, "{alter_func}"),
}
}
}
#[derive(Debug, Clone)]
pub struct FuncCtx {
pub func: Func,
pub arg_count: usize,
}
impl Deterministic for Func {
fn is_deterministic(&self) -> bool {
match self {
Self::Agg(agg_func) => agg_func.is_deterministic(),
Self::Window(window_func) => window_func.is_deterministic(),
Self::Scalar(scalar_func) => scalar_func.is_deterministic(),
Self::Math(math_func) => math_func.is_deterministic(),
Self::Vector(vector_func) => vector_func.is_deterministic(),
#[cfg(all(feature = "fts", not(target_family = "wasm")))]
Self::Fts(fts_func) => fts_func.is_deterministic(),
#[cfg(feature = "json")]
Self::Json(json_func) => json_func.is_deterministic(),
Self::External(external_func) => external_func.is_deterministic(),
Self::AlterTable(_) => true,
}
}
}
impl Func {
pub fn supports_star_syntax(&self) -> bool {
if self.needs_star_expansion() {
return true;
}
match self {
Self::Scalar(scalar_func) => {
matches!(
scalar_func,
ScalarFunc::Changes
| ScalarFunc::Random
| ScalarFunc::TotalChanges
| ScalarFunc::SqliteVersion
| ScalarFunc::TursoVersion
| ScalarFunc::SqliteSourceId
| ScalarFunc::LastInsertRowid
)
}
Self::Math(math_func) => {
matches!(math_func.arity(), MathFuncArity::Nullary)
}
Self::Agg(_) => false,
Self::Window(_) => false,
_ => false,
}
}
pub fn can_mask_nulls(&self) -> bool {
match self {
Self::Scalar(scalar_func) => scalar_func.can_mask_nulls(),
_ => false,
}
}
#[cfg(feature = "json")]
pub fn needs_star_expansion(&self) -> bool {
matches!(
self,
Self::Json(JsonFunc::JsonObject) | Self::Json(JsonFunc::JsonbObject)
)
}
#[cfg(not(feature = "json"))]
pub fn needs_star_expansion(&self) -> bool {
false
}
pub fn resolve_function(name: &str, arg_count: usize) -> Result<Option<Self>, LimboError> {
let normalized_name = crate::util::normalize_ident(name);
match normalized_name.as_str() {
"avg" => {
if arg_count != 1 {
crate::bail_parse_error!("wrong number of arguments to function {}()", name)
}
Ok(Some(Self::Agg(AggFunc::Avg)))
}
"count" => {
if arg_count == 0 {
Ok(Some(Self::Agg(AggFunc::Count0))) } else if arg_count == 1 {
Ok(Some(Self::Agg(AggFunc::Count))) } else {
crate::bail_parse_error!("wrong number of arguments to function {}()", name)
}
}
"group_concat" => {
if arg_count != 1 && arg_count != 2 {
println!("{arg_count}");
crate::bail_parse_error!("wrong number of arguments to function {}()", name)
}
Ok(Some(Self::Agg(AggFunc::GroupConcat)))
}
"max" if arg_count > 1 => Ok(Some(Self::Scalar(ScalarFunc::Max))),
"max" => {
if arg_count < 1 {
crate::bail_parse_error!("wrong number of arguments to function {}()", name)
}
Ok(Some(Self::Agg(AggFunc::Max)))
}
"min" if arg_count > 1 => Ok(Some(Self::Scalar(ScalarFunc::Min))),
"min" => {
if arg_count < 1 {
crate::bail_parse_error!("wrong number of arguments to function {}()", name)
}
Ok(Some(Self::Agg(AggFunc::Min)))
}
"nullif" if arg_count == 2 => Ok(Some(Self::Scalar(ScalarFunc::Nullif))),
"string_agg" => {
if arg_count != 2 {
crate::bail_parse_error!("wrong number of arguments to function {}()", name)
}
Ok(Some(Self::Agg(AggFunc::StringAgg)))
}
"sum" => {
if arg_count != 1 {
crate::bail_parse_error!("wrong number of arguments to function {}()", name)
}
Ok(Some(Self::Agg(AggFunc::Sum)))
}
"total" => {
if arg_count != 1 {
crate::bail_parse_error!("wrong number of arguments to function {}()", name)
}
Ok(Some(Self::Agg(AggFunc::Total)))
}
"row_number" => {
if arg_count != 0 {
crate::bail_parse_error!("wrong number of arguments to function {}()", name)
}
Ok(Some(Self::Window(WindowFunc::RowNumber)))
}
"timediff" => {
if arg_count != 2 {
crate::bail_parse_error!("wrong number of arguments to function {}()", name)
}
Ok(Some(Self::Scalar(ScalarFunc::TimeDiff)))
}
"array_agg" => Ok(Some(Self::Agg(AggFunc::ArrayAgg))),
#[cfg(feature = "json")]
"jsonb_group_array" => Ok(Some(Self::Agg(AggFunc::JsonbGroupArray))),
#[cfg(feature = "json")]
"json_group_array" => Ok(Some(Self::Agg(AggFunc::JsonGroupArray))),
#[cfg(feature = "json")]
"jsonb_group_object" => Ok(Some(Self::Agg(AggFunc::JsonbGroupObject))),
#[cfg(feature = "json")]
"json_group_object" => Ok(Some(Self::Agg(AggFunc::JsonGroupObject))),
"char" => Ok(Some(Self::Scalar(ScalarFunc::Char))),
"coalesce" => Ok(Some(Self::Scalar(ScalarFunc::Coalesce))),
"concat" => {
if arg_count == 0 {
crate::bail_parse_error!("wrong number of arguments to function {}()", name)
}
Ok(Some(Self::Scalar(ScalarFunc::Concat)))
}
"concat_ws" => {
if arg_count < 2 {
crate::bail_parse_error!("wrong number of arguments to function {}()", name)
}
Ok(Some(Self::Scalar(ScalarFunc::ConcatWs)))
}
"changes" => Ok(Some(Self::Scalar(ScalarFunc::Changes))),
"total_changes" => Ok(Some(Self::Scalar(ScalarFunc::TotalChanges))),
"glob" => Ok(Some(Self::Scalar(ScalarFunc::Glob))),
"ifnull" => Ok(Some(Self::Scalar(ScalarFunc::IfNull))),
"if" | "iif" => Ok(Some(Self::Scalar(ScalarFunc::Iif))),
"instr" => Ok(Some(Self::Scalar(ScalarFunc::Instr))),
"like" => Ok(Some(Self::Scalar(ScalarFunc::Like))),
"abs" => Ok(Some(Self::Scalar(ScalarFunc::Abs))),
"upper" => Ok(Some(Self::Scalar(ScalarFunc::Upper))),
"lower" => Ok(Some(Self::Scalar(ScalarFunc::Lower))),
"random" => Ok(Some(Self::Scalar(ScalarFunc::Random))),
"randomblob" => Ok(Some(Self::Scalar(ScalarFunc::RandomBlob))),
"trim" => Ok(Some(Self::Scalar(ScalarFunc::Trim))),
"ltrim" => Ok(Some(Self::Scalar(ScalarFunc::LTrim))),
"rtrim" => Ok(Some(Self::Scalar(ScalarFunc::RTrim))),
"round" => Ok(Some(Self::Scalar(ScalarFunc::Round))),
"length" => Ok(Some(Self::Scalar(ScalarFunc::Length))),
"octet_length" => Ok(Some(Self::Scalar(ScalarFunc::OctetLength))),
"sign" => Ok(Some(Self::Scalar(ScalarFunc::Sign))),
"substr" => {
if arg_count != 2 && arg_count != 3 {
crate::bail_parse_error!("wrong number of arguments to function {}()", name)
}
Ok(Some(Self::Scalar(ScalarFunc::Substr)))
}
"substring" => {
if arg_count != 2 && arg_count != 3 {
crate::bail_parse_error!("wrong number of arguments to function {}()", name)
}
Ok(Some(Self::Scalar(ScalarFunc::Substring)))
}
"date" => Ok(Some(Self::Scalar(ScalarFunc::Date))),
"time" => Ok(Some(Self::Scalar(ScalarFunc::Time))),
"datetime" => Ok(Some(Self::Scalar(ScalarFunc::DateTime))),
"typeof" => Ok(Some(Self::Scalar(ScalarFunc::Typeof))),
"last_insert_rowid" => Ok(Some(Self::Scalar(ScalarFunc::LastInsertRowid))),
"unicode" => Ok(Some(Self::Scalar(ScalarFunc::Unicode))),
"unistr" => Ok(Some(Self::Scalar(ScalarFunc::Unistr))),
"unistr_quote" => Ok(Some(Self::Scalar(ScalarFunc::UnistrQuote))),
"quote" => Ok(Some(Self::Scalar(ScalarFunc::Quote))),
"sqlite_version" => Ok(Some(Self::Scalar(ScalarFunc::SqliteVersion))),
"turso_version" => Ok(Some(Self::Scalar(ScalarFunc::TursoVersion))),
"sqlite_source_id" => Ok(Some(Self::Scalar(ScalarFunc::SqliteSourceId))),
"replace" => Ok(Some(Self::Scalar(ScalarFunc::Replace))),
"likely" => Ok(Some(Self::Scalar(ScalarFunc::Likely))),
"likelihood" => Ok(Some(Self::Scalar(ScalarFunc::Likelihood))),
"unlikely" => Ok(Some(Self::Scalar(ScalarFunc::Unlikely))),
#[cfg(feature = "json")]
"json" => Ok(Some(Self::Json(JsonFunc::Json))),
#[cfg(feature = "json")]
"jsonb" => Ok(Some(Self::Json(JsonFunc::Jsonb))),
#[cfg(feature = "json")]
"json_array_length" => Ok(Some(Self::Json(JsonFunc::JsonArrayLength))),
#[cfg(feature = "json")]
"json_array" => Ok(Some(Self::Json(JsonFunc::JsonArray))),
#[cfg(feature = "json")]
"jsonb_array" => Ok(Some(Self::Json(JsonFunc::JsonbArray))),
#[cfg(feature = "json")]
"json_extract" => Ok(Some(Func::Json(JsonFunc::JsonExtract))),
#[cfg(feature = "json")]
"jsonb_extract" => Ok(Some(Func::Json(JsonFunc::JsonbExtract))),
#[cfg(feature = "json")]
"json_object" => Ok(Some(Func::Json(JsonFunc::JsonObject))),
#[cfg(feature = "json")]
"jsonb_object" => Ok(Some(Func::Json(JsonFunc::JsonbObject))),
#[cfg(feature = "json")]
"json_type" => Ok(Some(Func::Json(JsonFunc::JsonType))),
#[cfg(feature = "json")]
"json_error_position" => Ok(Some(Self::Json(JsonFunc::JsonErrorPosition))),
#[cfg(feature = "json")]
"json_valid" => Ok(Some(Self::Json(JsonFunc::JsonValid))),
#[cfg(feature = "json")]
"json_patch" => Ok(Some(Self::Json(JsonFunc::JsonPatch))),
#[cfg(feature = "json")]
"json_remove" => Ok(Some(Self::Json(JsonFunc::JsonRemove))),
#[cfg(feature = "json")]
"jsonb_remove" => Ok(Some(Self::Json(JsonFunc::JsonbRemove))),
#[cfg(feature = "json")]
"json_replace" => Ok(Some(Self::Json(JsonFunc::JsonReplace))),
#[cfg(feature = "json")]
"json_insert" => Ok(Some(Self::Json(JsonFunc::JsonInsert))),
#[cfg(feature = "json")]
"jsonb_insert" => Ok(Some(Self::Json(JsonFunc::JsonbInsert))),
#[cfg(feature = "json")]
"jsonb_replace" => Ok(Some(Self::Json(JsonFunc::JsonReplace))),
#[cfg(feature = "json")]
"json_pretty" => Ok(Some(Self::Json(JsonFunc::JsonPretty))),
#[cfg(feature = "json")]
"json_set" => Ok(Some(Self::Json(JsonFunc::JsonSet))),
#[cfg(feature = "json")]
"jsonb_set" => Ok(Some(Self::Json(JsonFunc::JsonbSet))),
#[cfg(feature = "json")]
"json_quote" => Ok(Some(Self::Json(JsonFunc::JsonQuote))),
"unixepoch" => Ok(Some(Self::Scalar(ScalarFunc::UnixEpoch))),
"julianday" => Ok(Some(Self::Scalar(ScalarFunc::JulianDay))),
"hex" => Ok(Some(Self::Scalar(ScalarFunc::Hex))),
"unhex" => Ok(Some(Self::Scalar(ScalarFunc::Unhex))),
"zeroblob" => Ok(Some(Self::Scalar(ScalarFunc::ZeroBlob))),
"soundex" => Ok(Some(Self::Scalar(ScalarFunc::Soundex))),
"table_columns_json_array" => Ok(Some(Self::Scalar(ScalarFunc::TableColumnsJsonArray))),
"bin_record_json_object" => Ok(Some(Self::Scalar(ScalarFunc::BinRecordJsonObject))),
"conn_txn_id" => Ok(Some(Self::Scalar(ScalarFunc::ConnTxnId))),
"is_autocommit" => Ok(Some(Self::Scalar(ScalarFunc::IsAutocommit))),
"acos" => Ok(Some(Self::Math(MathFunc::Acos))),
"acosh" => Ok(Some(Self::Math(MathFunc::Acosh))),
"asin" => Ok(Some(Self::Math(MathFunc::Asin))),
"asinh" => Ok(Some(Self::Math(MathFunc::Asinh))),
"atan" => Ok(Some(Self::Math(MathFunc::Atan))),
"atan2" => Ok(Some(Self::Math(MathFunc::Atan2))),
"atanh" => Ok(Some(Self::Math(MathFunc::Atanh))),
"ceil" => Ok(Some(Self::Math(MathFunc::Ceil))),
"ceiling" => Ok(Some(Self::Math(MathFunc::Ceiling))),
"cos" => Ok(Some(Self::Math(MathFunc::Cos))),
"cosh" => Ok(Some(Self::Math(MathFunc::Cosh))),
"degrees" => Ok(Some(Self::Math(MathFunc::Degrees))),
"exp" => Ok(Some(Self::Math(MathFunc::Exp))),
"floor" => Ok(Some(Self::Math(MathFunc::Floor))),
"ln" => Ok(Some(Self::Math(MathFunc::Ln))),
"log" => Ok(Some(Self::Math(MathFunc::Log))),
"log10" => Ok(Some(Self::Math(MathFunc::Log10))),
"log2" => Ok(Some(Self::Math(MathFunc::Log2))),
"mod" => Ok(Some(Self::Math(MathFunc::Mod))),
"pi" => Ok(Some(Self::Math(MathFunc::Pi))),
"pow" => Ok(Some(Self::Math(MathFunc::Pow))),
"power" => Ok(Some(Self::Math(MathFunc::Power))),
"radians" => Ok(Some(Self::Math(MathFunc::Radians))),
"sin" => Ok(Some(Self::Math(MathFunc::Sin))),
"sinh" => Ok(Some(Self::Math(MathFunc::Sinh))),
"sqrt" => Ok(Some(Self::Math(MathFunc::Sqrt))),
"tan" => Ok(Some(Self::Math(MathFunc::Tan))),
"tanh" => Ok(Some(Self::Math(MathFunc::Tanh))),
"trunc" => Ok(Some(Self::Math(MathFunc::Trunc))),
#[cfg(feature = "fs")]
#[cfg(not(target_family = "wasm"))]
"load_extension" => Ok(Some(Self::Scalar(ScalarFunc::LoadExtension))),
"strftime" => Ok(Some(Self::Scalar(ScalarFunc::StrfTime))),
"printf" | "format" => Ok(Some(Self::Scalar(ScalarFunc::Printf))),
"vector" => Ok(Some(Self::Vector(VectorFunc::Vector))),
"vector32" => Ok(Some(Self::Vector(VectorFunc::Vector32))),
"vector32_sparse" => Ok(Some(Self::Vector(VectorFunc::Vector32Sparse))),
"vector64" => Ok(Some(Self::Vector(VectorFunc::Vector64))),
"vector8" => Ok(Some(Self::Vector(VectorFunc::Vector8))),
"vector1bit" => Ok(Some(Self::Vector(VectorFunc::Vector1Bit))),
"vector_extract" => Ok(Some(Self::Vector(VectorFunc::VectorExtract))),
"vector_distance_cos" => Ok(Some(Self::Vector(VectorFunc::VectorDistanceCos))),
"vector_distance_l2" => Ok(Some(Self::Vector(VectorFunc::VectorDistanceL2))),
"vector_distance_jaccard" => Ok(Some(Self::Vector(VectorFunc::VectorDistanceJaccard))),
"vector_distance_dot" => Ok(Some(Self::Vector(VectorFunc::VectorDistanceDot))),
"vector_concat" => Ok(Some(Self::Vector(VectorFunc::VectorConcat))),
"vector_slice" => Ok(Some(Self::Vector(VectorFunc::VectorSlice))),
#[cfg(all(feature = "fts", not(target_family = "wasm")))]
"fts_score" => Ok(Some(Self::Fts(FtsFunc::Score))),
#[cfg(all(feature = "fts", not(target_family = "wasm")))]
"fts_match" => Ok(Some(Self::Fts(FtsFunc::Match))),
#[cfg(all(feature = "fts", not(target_family = "wasm")))]
"fts_highlight" => Ok(Some(Self::Fts(FtsFunc::Highlight))),
"test_uint_encode" => Ok(Some(Self::Scalar(ScalarFunc::TestUintEncode))),
"test_uint_decode" => Ok(Some(Self::Scalar(ScalarFunc::TestUintDecode))),
"test_uint_add" => Ok(Some(Self::Scalar(ScalarFunc::TestUintAdd))),
"test_uint_sub" => Ok(Some(Self::Scalar(ScalarFunc::TestUintSub))),
"test_uint_mul" => Ok(Some(Self::Scalar(ScalarFunc::TestUintMul))),
"test_uint_div" => Ok(Some(Self::Scalar(ScalarFunc::TestUintDiv))),
"test_uint_lt" => Ok(Some(Self::Scalar(ScalarFunc::TestUintLt))),
"test_uint_eq" => Ok(Some(Self::Scalar(ScalarFunc::TestUintEq))),
"string_reverse" => Ok(Some(Self::Scalar(ScalarFunc::StringReverse))),
"boolean_to_int" => Ok(Some(Self::Scalar(ScalarFunc::BooleanToInt))),
"int_to_boolean" => Ok(Some(Self::Scalar(ScalarFunc::IntToBoolean))),
"validate_ipaddr" => Ok(Some(Self::Scalar(ScalarFunc::ValidateIpAddr))),
"numeric_encode" => Ok(Some(Self::Scalar(ScalarFunc::NumericEncode))),
"numeric_decode" => Ok(Some(Self::Scalar(ScalarFunc::NumericDecode))),
"numeric_add" => Ok(Some(Self::Scalar(ScalarFunc::NumericAdd))),
"numeric_sub" => Ok(Some(Self::Scalar(ScalarFunc::NumericSub))),
"numeric_mul" => Ok(Some(Self::Scalar(ScalarFunc::NumericMul))),
"numeric_div" => Ok(Some(Self::Scalar(ScalarFunc::NumericDiv))),
"numeric_lt" => Ok(Some(Self::Scalar(ScalarFunc::NumericLt))),
"numeric_eq" => Ok(Some(Self::Scalar(ScalarFunc::NumericEq))),
"array" => Ok(Some(Self::Scalar(ScalarFunc::Array))),
"array_element" => Ok(Some(Self::Scalar(ScalarFunc::ArrayElement))),
"array_set_element" => Ok(Some(Self::Scalar(ScalarFunc::ArraySetElement))),
"array_length" => Ok(Some(Self::Scalar(ScalarFunc::ArrayLength))),
"array_append" => Ok(Some(Self::Scalar(ScalarFunc::ArrayAppend))),
"array_prepend" => Ok(Some(Self::Scalar(ScalarFunc::ArrayPrepend))),
"array_cat" => Ok(Some(Self::Scalar(ScalarFunc::ArrayCat))),
"array_remove" => Ok(Some(Self::Scalar(ScalarFunc::ArrayRemove))),
"array_contains" => Ok(Some(Self::Scalar(ScalarFunc::ArrayContains))),
"array_position" => Ok(Some(Self::Scalar(ScalarFunc::ArrayPosition))),
"array_slice" => Ok(Some(Self::Scalar(ScalarFunc::ArraySlice))),
"string_to_array" => Ok(Some(Self::Scalar(ScalarFunc::StringToArray))),
"array_to_string" => Ok(Some(Self::Scalar(ScalarFunc::ArrayToString))),
"array_overlap" | "array_overlaps" => Ok(Some(Self::Scalar(ScalarFunc::ArrayOverlap))),
"array_contains_all" => Ok(Some(Self::Scalar(ScalarFunc::ArrayContainsAll))),
"struct_pack" => Ok(Some(Self::Scalar(ScalarFunc::StructPack))),
"struct_extract" => Ok(Some(Self::Scalar(ScalarFunc::StructExtractFunc))),
"union_value" => Ok(Some(Self::Scalar(ScalarFunc::UnionValueFunc))),
"union_tag" => Ok(Some(Self::Scalar(ScalarFunc::UnionTagFunc))),
"union_extract" => Ok(Some(Self::Scalar(ScalarFunc::UnionExtractFunc))),
_ => Ok(None),
}
}
pub fn builtin_function_list() -> Vec<FunctionListEntry> {
let mut funcs = Vec::new();
let mut push = |name: String, func_type: &'static str, arities: &[i32], det: bool| {
for &narg in arities {
funcs.push(FunctionListEntry {
name: name.clone(),
func_type,
narg,
deterministic: det,
});
}
};
for f in ScalarFunc::iter() {
if f.is_internal() {
continue;
}
push(f.to_string(), "s", f.arities(), f.is_deterministic());
}
for f in AggFunc::iter() {
push(f.to_string(), "w", f.arities(), f.is_deterministic());
}
for f in WindowFunc::iter() {
push(f.to_string(), "w", f.arities(), f.is_deterministic());
}
for f in MathFunc::iter() {
push(f.to_string(), "s", f.arities(), f.is_deterministic());
}
for f in VectorFunc::iter() {
push(f.to_string(), "s", f.arities(), f.is_deterministic());
}
#[cfg(feature = "json")]
for f in JsonFunc::iter() {
if f.is_internal() {
continue;
}
push(f.to_string(), "s", f.arities(), f.is_deterministic());
}
#[cfg(all(feature = "fts", not(target_family = "wasm")))]
for f in FtsFunc::iter() {
push(f.to_string(), "s", f.arities(), f.is_deterministic());
}
funcs.push(FunctionListEntry {
name: "format".into(),
func_type: "s",
narg: -1,
deterministic: true,
});
funcs.push(FunctionListEntry {
name: "if".into(),
func_type: "s",
narg: 3,
deterministic: true,
});
funcs
}
}
pub struct FunctionListEntry {
pub name: String,
pub func_type: &'static str, pub narg: i32, pub deterministic: bool,
}