nodedb_sql/resolver/expr/
functions.rs1use sqlparser::ast;
4
5use crate::error::{Result, SqlError};
6use crate::parser::normalize::{SCHEMA_QUALIFIED_MSG, normalize_ident};
7use crate::types::*;
8
9use super::convert::convert_expr_depth;
10
11pub(super) fn convert_function_depth(func: &ast::Function, depth: &mut usize) -> Result<SqlExpr> {
12 if func.name.0.len() == 1 {
15 let raw_name = match &func.name.0[0] {
16 ast::ObjectNamePart::Identifier(ident) => ident.value.to_ascii_lowercase(),
17 _ => String::new(),
18 };
19 if let Some(expr) = intercept_fts_function(&raw_name, func, depth)? {
20 return Ok(expr);
21 }
22 }
23
24 if func.name.0.len() > 1 {
25 let qualified: String = func
26 .name
27 .0
28 .iter()
29 .map(|p| match p {
30 ast::ObjectNamePart::Identifier(ident) => ident.value.clone(),
31 _ => String::new(),
32 })
33 .collect::<Vec<_>>()
34 .join(".");
35 return Err(SqlError::Unsupported {
36 detail: format!("schema-qualified function name '{qualified}': {SCHEMA_QUALIFIED_MSG}"),
37 });
38 }
39 let name = func
40 .name
41 .0
42 .iter()
43 .map(|p| match p {
44 ast::ObjectNamePart::Identifier(ident) => normalize_ident(ident),
45 _ => String::new(),
46 })
47 .collect::<Vec<_>>()
48 .join(".");
49
50 let args = match &func.args {
51 ast::FunctionArguments::None => Vec::new(),
52 ast::FunctionArguments::Subquery(_) => {
53 return Err(SqlError::Unsupported {
54 detail: "subquery in function args".into(),
55 });
56 }
57 ast::FunctionArguments::List(arg_list) => arg_list
58 .args
59 .iter()
60 .filter_map(|a| match a {
61 ast::FunctionArg::Unnamed(ast::FunctionArgExpr::Expr(e)) => {
62 Some(convert_expr_depth(e, depth))
63 }
64 ast::FunctionArg::Unnamed(ast::FunctionArgExpr::Wildcard) => {
65 Some(Ok(SqlExpr::Wildcard))
66 }
67 ast::FunctionArg::Named {
68 arg: ast::FunctionArgExpr::Expr(e),
69 ..
70 } => Some(convert_expr_depth(e, depth)),
71 _ => None,
72 })
73 .collect::<Result<Vec<_>>>()?,
74 };
75
76 let distinct = match &func.args {
77 ast::FunctionArguments::List(arg_list) => {
78 matches!(
79 arg_list.duplicate_treatment,
80 Some(ast::DuplicateTreatment::Distinct)
81 )
82 }
83 _ => false,
84 };
85
86 Ok(SqlExpr::Function {
87 name,
88 args,
89 distinct,
90 })
91}
92
93fn intercept_fts_function(
99 name: &str,
100 func: &ast::Function,
101 depth: &mut usize,
102) -> Result<Option<SqlExpr>> {
103 use crate::functions::fts_ops::pg_fts_funcs;
104
105 let args = collect_function_args(func, depth)?;
106 match name {
107 "to_tsvector" => Ok(Some(SqlExpr::Function {
108 name: "pg_to_tsvector".into(),
109 args,
110 distinct: false,
111 })),
112 "to_tsquery" => Ok(Some(pg_fts_funcs::lower_pg_to_tsquery(args))),
113 "plainto_tsquery" => Ok(Some(pg_fts_funcs::lower_pg_plainto_tsquery(args))),
114 "phraseto_tsquery" => Ok(Some(pg_fts_funcs::lower_phraseto_tsquery(args))),
115 "websearch_to_tsquery" => Ok(Some(pg_fts_funcs::lower_pg_websearch_to_tsquery(args))),
116 "ts_rank" => Ok(Some(SqlExpr::Function {
117 name: "pg_ts_rank".into(),
118 args,
119 distinct: false,
120 })),
121 "ts_rank_cd" => Err(SqlError::Unsupported {
122 detail: "ts_rank_cd is not supported; use ts_rank or bm25_score instead".into(),
123 }),
124 "ts_headline" => Ok(Some(SqlExpr::Function {
125 name: "pg_ts_headline".into(),
126 args,
127 distinct: false,
128 })),
129 _ => Ok(None),
130 }
131}
132
133fn collect_function_args(func: &ast::Function, depth: &mut usize) -> Result<Vec<SqlExpr>> {
135 match &func.args {
136 ast::FunctionArguments::None => Ok(Vec::new()),
137 ast::FunctionArguments::Subquery(_) => Err(SqlError::Unsupported {
138 detail: "subquery in function args".into(),
139 }),
140 ast::FunctionArguments::List(arg_list) => arg_list
141 .args
142 .iter()
143 .filter_map(|a| match a {
144 ast::FunctionArg::Unnamed(ast::FunctionArgExpr::Expr(e)) => {
145 Some(convert_expr_depth(e, depth))
146 }
147 ast::FunctionArg::Unnamed(ast::FunctionArgExpr::Wildcard) => {
148 Some(Ok(SqlExpr::Wildcard))
149 }
150 ast::FunctionArg::Named {
151 arg: ast::FunctionArgExpr::Expr(e),
152 ..
153 } => Some(convert_expr_depth(e, depth)),
154 _ => None,
155 })
156 .collect::<Result<Vec<_>>>(),
157 }
158}