Skip to main content

rupg_analyze/ddl/
function.rs

1//! `CreateFunction`: `CREATE FUNCTION` for a function in SQL, as `interpret_AS_clause`, `ProcedureCreate` and `fmgr_sql_validator` run it. The body is a `RETURN` expression, a query in `BEGIN ATOMIC` or a query in a string.
2//!
3//! The catalog keeps the text of the statement and the schemas of `search_path`, and the analyzer reads the body again each time a query calls the function, as it reads the query of a view. The analysis of a call uses the types of the arguments of the call, so a polymorphic argument has its actual type. The setup of a new cluster runs `CREATE FUNCTION` for the functions of `information_schema` too.
4
5use rupg_catalog::{
6    Catalog, Function, FunctionBody, ObjRef, PG_PROC, PG_TYPE, eliminate_duplicates,
7};
8use rupg_common::{Error, Result, SqlState};
9use rupg_pgcatalog::builtin;
10use rupg_sql::nodes::{
11    CreateFunctionStmt, DefElem, FunctionParameterMode, Node, VariableSetKind, VariableSetStmt,
12};
13use rupg_types::oid;
14
15use super::{Definer, not_yet};
16use crate::agg::Kind;
17use crate::coerce::{AtOpt, Context};
18use crate::expr::Expr;
19use crate::select::Query;
20use crate::typename::{names, place};
21use crate::{Analyzer, Env, Params, node, poly, types};
22
23/// The OID of the language `sql`.
24const SQL_LANGUAGE: u32 = 14;
25/// The OID of the language `plpgsql`, which the extension `plpgsql` of a new cluster makes.
26const PLPGSQL_LANGUAGE: u32 = 13708;
27/// The OID of the language `internal`, the built-in functions.
28const INTERNAL_LANGUAGE: u32 = 12;
29/// The OID of the language `c`, the functions of a library.
30const C_LANGUAGE: u32 = 13;
31/// The default `procost` of a function in a language other than C and `internal`.
32const DEFAULT_COST: f32 = 100.0;
33/// The suffix of the file of a library, `DLSUFFIX` on Linux.
34const DLSUFFIX: &str = ".so";
35/// The name of the library of the regression tests of PostgreSQL, `regress.so`.
36const REGRESS_LIBRARY: &str = "regress";
37
38/// The functions of `regress.c` that have `PG_FUNCTION_INFO_V1`. A function in C can link to them in the library of the regression tests, and `rupg-func` runs some of them.
39pub const REGRESS_SYMBOLS: &[&str] = &[
40    "interpt_pp",
41    "overpaid",
42    "widget_in",
43    "widget_out",
44    "pt_in_widget",
45    "reverse_name",
46    "trigger_return_old",
47    "int44in",
48    "int44out",
49    "test_canonicalize_path",
50    "make_tuple_indirect",
51    "get_environ",
52    "regress_setenv",
53    "wait_pid",
54    "test_atomic_ops",
55    "test_fdw_handler",
56    "test_fdw_connection",
57    "is_catalog_text_unique_index_oid",
58    "test_support_func",
59    "test_inline_in_from_support_func",
60    "test_opclass_options_func",
61    "test_enc_setup",
62    "test_enc_conversion",
63    "test_bytea_to_text",
64    "test_text_to_bytea",
65    "test_mblen_func",
66    "test_text_to_wchars",
67    "test_wchars_to_text",
68    "test_valid_server_encoding",
69    "binary_coercible",
70    "test_relpath",
71    "test_translation",
72    "test_instr_time",
73    "test_pglz_compress",
74    "test_pglz_decompress",
75    "test_pg_locale_apis",
76];
77
78/// `expand_dynamic_library_name` and the `stat` of `internal_load_library`: the full name of the library `name`. The only library that rupg has is the library of the regression tests, by a path that ends in `regress` or `regress.so`. A name without a directory is in `$libdir`, which does not have that library.
79///
80/// # Errors
81///
82/// `58P01` for a library that rupg does not have.
83pub fn find_library(name: &str) -> Result<String> {
84    let file = name.rsplit_once('/').map(|(_, file)| file);
85    let stem = file.map(|file| file.strip_suffix(DLSUFFIX).unwrap_or(file));
86    if stem != Some(REGRESS_LIBRARY) {
87        return Err(Error::new(
88            SqlState::UNDEFINED_FILE,
89            format!("could not access file \"{name}\": No such file or directory"),
90        ));
91    }
92    Ok(if name.ends_with(DLSUFFIX) { name.to_string() } else { format!("{name}{DLSUFFIX}") })
93}
94/// The default `prorows` of a function that returns a set.
95const DEFAULT_ROWS: u32 = 1000;
96
97/// The body of a function in SQL, as the analyzer reads it for the types of the arguments of a call.
98#[derive(Debug)]
99pub enum Body {
100    /// A `RETURN` body: the value of the function, with `$1` as the first argument.
101    Value(Expr),
102    /// A body with a query, in `BEGIN ATOMIC` or in a string. A function that returns a set gives the rows of the query, and another function gives the first column of the first row, or null when the query gives no row.
103    Query(Box<Query>),
104    /// A body with more than one statement, or with a statement that is not `SELECT`. The session runs the statements one after the other with [`function_script`], and the last statement gives the rows of the result. It has the types of the columns of the result, or no types for a function that returns `record` with no `OUT` parameter.
105    Statements(Vec<u32>),
106}
107
108/// The facts of the options of `CREATE FUNCTION`.
109struct Options {
110    /// The OID of the language.
111    language: u32,
112    /// The name of the language, `lanname`.
113    language_name: String,
114    strict: bool,
115    leakproof: bool,
116    volatile: u8,
117    parallel: u8,
118    cost: Option<f32>,
119    rows: Option<u32>,
120    support: Option<Vec<String>>,
121    /// The body in a string, from `AS`. For a function in C it is the file of the library.
122    src: Option<String>,
123    /// The second item of `AS`, the link symbol of a function in C.
124    link: Option<String>,
125    /// The place of `AS` in the query text.
126    src_at: Option<usize>,
127    /// The settings of the clauses `SET`, as `proconfig` keeps them.
128    config: Vec<String>,
129    /// True for `SECURITY DEFINER`.
130    secdef: bool,
131}
132
133/// `update_proconfig_value`: the settings of a function after a clause `SET` or `RESET`. `GUCArrayAdd` puts a new value in place of the value of the same parameter, and `GUCArrayDelete` and `RESET ALL` remove values.
134pub(super) fn update_config(
135    env: &dyn Env,
136    config: &mut Vec<String>,
137    set: &VariableSetStmt,
138) -> Result<()> {
139    if set.kind == VariableSetKind::VAR_RESET_ALL {
140        config.clear();
141        return Ok(());
142    }
143    let (name, value) = env.function_setting(set)?;
144    let prefix = format!("{name}=");
145    let at = config.iter().position(|item| item.starts_with(&prefix));
146    match (value, at) {
147        (Some(value), Some(at)) => config[at] = format!("{prefix}{value}"),
148        (Some(value), None) => config.push(format!("{prefix}{value}")),
149        (None, Some(at)) => {
150            config.remove(at);
151        }
152        (None, None) => {}
153    }
154    Ok(())
155}
156
157/// True when the settings of a function set `search_path`, so that a body in a string reads its names with that path.
158fn sets_path(config: &[String]) -> bool {
159    config.iter().any(|item| item.starts_with("search_path="))
160}
161
162/// The error of `CreateFunction` and `AlterFunction` for `LEAKPROOF` from a role that is not a superuser.
163pub(super) fn only_superuser_leakproof() -> Error {
164    Error::new(SqlState::INSUFFICIENT_PRIVILEGE, "only superuser can define a leakproof function")
165}
166
167/// The text of the argument of an option.
168fn option_text(def: &DefElem) -> Option<&str> {
169    match &def.arg {
170        Some(Node::String(s)) => Some(s),
171        _ => None,
172    }
173}
174
175/// The texts of the argument of an option that takes a list of names or of strings.
176fn option_list(def: &DefElem) -> Option<Vec<String>> {
177    match &def.arg {
178        Some(Node::List(list)) => list
179            .iter()
180            .map(|n| match n {
181                Some(Node::String(s)) => Some(s.to_string()),
182                _ => None,
183            })
184            .collect(),
185        _ => None,
186    }
187}
188
189/// `compute_function_attributes`: the options of the function. Each option that rupg does not have gives an error. An option that only a function can have gives `42P13` for a procedure.
190fn options(stmt: &CreateFunctionStmt, env: &dyn Env) -> Result<Options> {
191    let mut out = Options {
192        language: SQL_LANGUAGE,
193        language_name: "sql".to_string(),
194        strict: false,
195        leakproof: false,
196        volatile: b'v',
197        parallel: b'u',
198        cost: None,
199        rows: None,
200        support: None,
201        src: None,
202        link: None,
203        src_at: None,
204        config: Vec::new(),
205        secdef: false,
206    };
207    for def in stmt.options.iter().flatten() {
208        let Node::DefElem(def) = def else { continue };
209        let name = def.defname.as_deref().unwrap_or_default();
210        let at = place(def.location);
211        let bad = || not_yet(&format!("the option {name} of a function"), at);
212        let attribute = matches!(
213            name,
214            "volatility"
215                | "strict"
216                | "leakproof"
217                | "cost"
218                | "rows"
219                | "support"
220                | "parallel"
221                | "window"
222        );
223        if stmt.is_procedure && attribute {
224            return Err(Error::new(
225                SqlState::INVALID_FUNCTION_DEFINITION,
226                "invalid attribute in procedure definition",
227            )
228            .at_opt(at));
229        }
230        match (name, option_text(def)) {
231            ("language", Some(language)) => {
232                out.language = match language {
233                    "sql" => SQL_LANGUAGE,
234                    "plpgsql" => PLPGSQL_LANGUAGE,
235                    "internal" => INTERNAL_LANGUAGE,
236                    "c" => C_LANGUAGE,
237                    _ => {
238                        return Err(not_yet(&format!("a function in the language {language}"), at));
239                    }
240                };
241                out.language_name = language.to_string();
242            }
243            ("strict", _) => out.strict = matches!(def.arg, Some(Node::Boolean(true))),
244            ("leakproof", _) => out.leakproof = matches!(def.arg, Some(Node::Boolean(true))),
245            ("volatility", Some("immutable")) => out.volatile = b'i',
246            ("volatility", Some("stable")) => out.volatile = b's',
247            ("volatility", Some("volatile")) => out.volatile = b'v',
248            ("parallel", Some("safe")) => out.parallel = b's',
249            ("parallel", Some("restricted")) => out.parallel = b'r',
250            ("parallel", Some("unsafe")) => out.parallel = b'u',
251            ("cost", _) => out.cost = Some(super::alter_function::positive_cost(def)?),
252            ("rows", _) => match def.arg {
253                Some(Node::Integer(rows)) if rows > 0 => out.rows = Some(rows.unsigned_abs()),
254                _ => return Err(bad()),
255            },
256            ("support", _) => out.support = Some(option_list(def).ok_or_else(bad)?),
257            ("set", _) => match &def.arg {
258                Some(Node::VariableSetStmt(set)) => update_config(env, &mut out.config, set)?,
259                _ => return Err(bad()),
260            },
261            ("security", _) => out.secdef = matches!(def.arg, Some(Node::Boolean(true))),
262            ("as", _) => match option_list(def).as_deref() {
263                // The grammar gives one item, or two for a function in C.
264                Some([src, rest @ ..]) if rest.len() < 2 => {
265                    out.src = Some(src.clone());
266                    out.link = rest.first().cloned();
267                    out.src_at = at;
268                }
269                _ => return Err(bad()),
270            },
271            _ => return Err(bad()),
272        }
273    }
274    Ok(out)
275}
276
277/// `interpret_AS_clause`: `prosrc` and `probin` of the function `name` from `AS`. A function in C has the file of the library in `probin` and the link symbol in `prosrc`, which is the name of the function when `AS` has no symbol or the symbol `-`. A function in `internal` with an empty `AS` has its own name in `prosrc`. The other languages have the body in `prosrc`.
278fn interpret_as(
279    stmt: &CreateFunctionStmt,
280    options: &Options,
281    name: &str,
282) -> Result<(String, String)> {
283    let bad = |message: String| Err(Error::new(SqlState::INVALID_FUNCTION_DEFINITION, message));
284    if matches!(options.language, INTERNAL_LANGUAGE | C_LANGUAGE) {
285        match (&options.src, &stmt.sql_body) {
286            (None, None) => return bad("no function body specified".into()),
287            (Some(_), Some(_)) => return bad("duplicate function body specified".into()),
288            (None, Some(_)) => {
289                return bad("inline SQL function body only valid for language SQL".into());
290            }
291            (Some(_), None) => {}
292        }
293    }
294    let src = options.src.clone().unwrap_or_default();
295    if options.language == C_LANGUAGE {
296        let link = options.link.as_deref().filter(|link| *link != "-").unwrap_or(name);
297        return Ok((link.to_string(), src));
298    }
299    if options.link.is_some() {
300        return bad(format!("only one AS item needed for language \"{}\"", options.language_name));
301    }
302    if options.language == INTERNAL_LANGUAGE && src.is_empty() {
303        return Ok((name.to_string(), String::new()));
304    }
305    Ok((src, String::new()))
306}
307
308/// `fmgr_internal_validator` and `fmgr_c_validator`: a function in `internal` names a built-in function, and a function in C names a function of a library that rupg has.
309fn check_untrusted(function: &Function) -> Result<()> {
310    if function.lang == INTERNAL_LANGUAGE {
311        let found =
312            builtin::procs().iter().any(|p| p.lang == INTERNAL_LANGUAGE && p.src == function.src);
313        if !found {
314            return Err(Error::new(
315                SqlState::UNDEFINED_FUNCTION,
316                format!("there is no built-in function named \"{}\"", function.src),
317            ));
318        }
319        return Ok(());
320    }
321    let file = find_library(&function.bin)?;
322    if !REGRESS_SYMBOLS.contains(&function.src.as_str()) {
323        return Err(Error::new(
324            SqlState::UNDEFINED_FUNCTION,
325            format!("could not find function \"{}\" in file \"{file}\"", function.src),
326        ));
327    }
328    Ok(())
329}
330
331/// The statements of a body in SQL, from the statement that made the function: the `RETURN` expression, the statements of `BEGIN ATOMIC`, or the statements of the string of `AS`.
332enum Statements<'s> {
333    Return(Option<&'s Node>),
334    Atomic(Vec<&'s Node>),
335    /// The statements of a body in a string, each with its text.
336    String(Vec<(Node, String)>),
337}
338
339/// The body of the statement.
340fn statements<'s>(stmt: &'s CreateFunctionStmt, src: Option<&str>) -> Result<Statements<'s>> {
341    match (&stmt.sql_body, src) {
342        (Some(Node::ReturnStmt(ret)), None) => Ok(Statements::Return(ret.returnval.as_ref())),
343        (Some(Node::List(outer)), None) => match outer.first() {
344            Some(Some(Node::List(list))) => Ok(Statements::Atomic(list.iter().flatten().collect())),
345            // `BEGIN ATOMIC END` gives an empty list, and the tree keeps an empty list as no node.
346            Some(None) | None => Ok(Statements::Atomic(Vec::new())),
347            Some(Some(_)) => Err(Error::internal("a BEGIN ATOMIC body that is not a list")),
348        },
349        (Some(_), Some(_)) => Err(Error::new(
350            SqlState::INVALID_FUNCTION_DEFINITION,
351            "duplicate function body specified",
352        )),
353        (Some(_), None) => Err(Error::internal("a function body of an unknown form")),
354        (None, Some(src)) => {
355            let (list, _) = rupg_sql::parse(src).map_err(|error| {
356                let at = error.location;
357                Error::from(error).with_position(at)
358            })?;
359            let stmts = list
360                .into_iter()
361                .flatten()
362                .filter_map(|node| match node {
363                    Node::RawStmt(raw) => {
364                        let start = usize::try_from(raw.stmt_location).unwrap_or(0);
365                        // A length of 0 is the rest of the text.
366                        let end = match usize::try_from(raw.stmt_len) {
367                            Ok(0) | Err(_) => src.len(),
368                            Ok(len) => start + len,
369                        };
370                        let text = src.get(start..end).unwrap_or(src).to_string();
371                        raw.stmt.map(|stmt| (stmt, text))
372                    }
373                    _ => None,
374                })
375                .collect();
376            Ok(Statements::String(stmts))
377        }
378        (None, None) => {
379            Err(Error::new(SqlState::INVALID_FUNCTION_DEFINITION, "no function body specified"))
380        }
381    }
382}
383
384/// The types of the columns of the result of a function: the `OUT` parameters of a function that returns `record`, or else the result type. A polymorphic type takes the actual type that `inputs`, the types of the arguments of a call, give. A function that returns `record` with no `OUT` parameter has no known columns.
385fn result_types(function: &Function, inputs: &[u32]) -> Result<Vec<u32>> {
386    let declared: Vec<u32> = if function.rettype == oid::RECORD {
387        function
388            .allargtypes
389            .iter()
390            .zip(&function.argmodes)
391            .filter(|(_, mode)| matches!(mode, b'o' | b'b' | b't'))
392            .map(|(ty, _)| *ty)
393            .collect()
394    } else {
395        vec![function.rettype]
396    };
397    declared
398        .into_iter()
399        .map(|ty| {
400            if types::is_polymorphic(ty) {
401                poly::resolve(inputs, &mut function.argtypes.clone(), ty)
402            } else {
403                Ok(ty)
404            }
405        })
406        .collect()
407}
408
409/// `function_parse_error_transpose` and `match_prosrc_to_query`: the place in the query text of the body `src` of a function, in a string after `AS`, so that an error in the body has its place in the query. `text` is the text of the statement, and `as_at` is the place of `AS` in the query text. `None` when the string is not in the text.
410fn body_place(text: &str, src: &str, as_at: Option<usize>) -> Option<usize> {
411    let as_at = as_at?;
412    let quoted = src.replace('\'', "''");
413    let local = [src, quoted.as_str()].into_iter().find_map(|raw| {
414        text.match_indices(raw)
415            .map(|(i, _)| i)
416            .find(|&i| matches!(text.as_bytes()[..i].last(), Some(b'$' | b'\'')))
417    })?;
418    // The string comes after `AS`, so `AS` is the last word before it.
419    let keyword = text[..local].to_ascii_lowercase().rfind("as")?;
420    Some(as_at.checked_sub(keyword)? + local)
421}
422
423/// The names of the input arguments of a function, in the order of their numbers. An argument with no name has an empty name.
424fn input_names(function: &Function) -> Vec<String> {
425    if function.argmodes.is_empty() {
426        return function.argnames.clone();
427    }
428    function
429        .argmodes
430        .iter()
431        .zip(&function.argnames)
432        .filter(|(mode, _)| matches!(mode, b'i' | b'b' | b'v'))
433        .map(|(_, name)| name.clone())
434        .collect()
435}
436
437/// The error of `check_sql_fn_retval` for a body with the wrong columns.
438fn mismatch(rettype: u32, detail: String) -> Error {
439    Error::new(
440        SqlState::INVALID_FUNCTION_DEFINITION,
441        format!("return type mismatch in function declared to return {}", types::name(rettype)),
442    )
443    .with_detail(detail)
444}
445
446/// The error of `check_sql_fn_retval` for a body whose last statement gives no rows.
447fn no_final_query(rettype: u32) -> Error {
448    mismatch(
449        rettype,
450        "Function's final statement must be SELECT or INSERT/UPDATE/DELETE/MERGE RETURNING.".into(),
451    )
452}
453
454/// True for a statement that has a plan, which `fmgr_sql` runs with the executor. The other statements run with `ProcessUtility`.
455fn planned(node: &Node) -> bool {
456    match node {
457        Node::SelectStmt(select) => select.intoClause.is_none(),
458        Node::InsertStmt(_)
459        | Node::UpdateStmt(_)
460        | Node::DeleteStmt(_)
461        | Node::MergeStmt(_)
462        | Node::CallStmt(_) => true,
463        _ => false,
464    }
465}
466
467/// `prepare_next_query`: the query of the statement `node` of the body of `function`, for a call with arguments of the types `inputs`, with the names of the search path `path`. The last statement gives the result of the function, as `check_sql_fn_retval` checks it. `None` for a statement that has no plan, which can be the last statement only of a function that returns `void`.
468fn statement_query(
469    env: &dyn Env,
470    function: &Function,
471    path: Option<&[u32]>,
472    inputs: &[u32],
473    node: &Node,
474    last: bool,
475) -> Result<Option<Query>> {
476    let params = Params { types: inputs.to_vec(), variable: false };
477    let mut an = Analyzer::new(env, &params);
478    if let Some(path) = path {
479        an.set_path(path);
480    }
481    an.sql_function = Some((function.name.clone(), input_names(function)));
482    let query = if planned(node) { Some(an.statement(node)?) } else { None };
483    if let Some(query) = &query
484        && !query.out_args.is_empty()
485    {
486        return Err(Error::new(
487            SqlState::FEATURE_NOT_SUPPORTED,
488            "calling procedures with output arguments is not supported in SQL functions",
489        ));
490    }
491    let Some(mut query) = query else {
492        if last {
493            let (rettype, _) = an.result_shape(function, inputs)?;
494            if rettype != oid::VOID {
495                return Err(no_final_query(rettype));
496            }
497        }
498        return Ok(None);
499    };
500    if last {
501        let (rettype, columns) = an.result_shape(function, inputs)?;
502        // `CALL` gives no rows.
503        if rettype != oid::VOID && matches!(node, Node::CallStmt(_)) {
504            return Err(no_final_query(rettype));
505        }
506        an.result_columns(&mut query, rettype, &columns)?;
507    }
508    an.finish(query).map(Some)
509}
510
511/// `fmgr_sql_validator` for a body that is not one `SELECT`: the query of each statement that has a plan, with the checks of `check_sql_fn_retval` on the last statement. A body with no statement must be the body of a function that returns `void`.
512fn check_statements(
513    env: &dyn Env,
514    function: &Function,
515    path: Option<&[u32]>,
516    list: &[&Node],
517) -> Result<Vec<Query>> {
518    let inputs = &function.argtypes;
519    if list.is_empty() {
520        let rettype = result_type(function, &result_types(function, inputs)?);
521        if rettype != oid::VOID {
522            return Err(no_final_query(rettype));
523        }
524    }
525    let mut queries = Vec::new();
526    for (i, node) in list.iter().enumerate() {
527        let last = i + 1 == list.len();
528        queries.extend(statement_query(env, function, path, inputs, node, last)?);
529    }
530    Ok(queries)
531}
532
533/// The result type of a call of `function` whose result has columns of the types `columns`: the one type of a function that does not return `record`, or else the declared type.
534fn result_type(function: &Function, columns: &[u32]) -> u32 {
535    match columns {
536        [ty] if function.rettype != oid::RECORD => *ty,
537        _ => function.rettype,
538    }
539}
540
541/// The objects that an expression of a function refers to, as `recordDependencyOnExpr` records them: the objects that [`super::view::expr_references`] finds, also in the subqueries, in the order of `eliminate_duplicate_dependencies`. The catalog drops the references to pinned objects.
542fn body_references(catalog: &Catalog, body: &Expr) -> Result<Vec<ObjRef>> {
543    super::shared_constants(&[body])?;
544    let mut refs = Vec::new();
545    super::view::expr_references(catalog, body, &[], &mut refs);
546    Ok(eliminate_duplicates(&refs))
547}
548
549impl Analyzer<'_> {
550    /// `transformReturnStmt` and `check_sql_fn_retval`: the `RETURN` expression, as a value of the result type. A value of type `unknown` becomes `text` first, and then the cast to the result type is an assignment cast.
551    fn return_body(&mut self, value: Option<&Node>, rettype: u32) -> Result<Expr> {
552        let mut expr = self.with_kind(Kind::Select, |an| an.transform(value))?;
553        // A function that returns `void` takes any value, and the call gives null.
554        if rettype == oid::VOID {
555            return Ok(expr);
556        }
557        if expr.ty == oid::UNKNOWN {
558            expr = self.coerce(expr, oid::TEXT, -1, Context::Implicit, None)?;
559        }
560        let actual = expr.ty;
561        self.coerce_to_target(expr, rettype, -1, Context::Assignment, None)?.ok_or_else(|| {
562            mismatch(rettype, format!("Actual return type is {}.", types::name(actual)))
563        })
564    }
565
566    /// The body of the statements `stmts`: a body of one `SELECT` is its query, as [`Analyzer::result_columns`] checks it, and the session runs the statements of another body one after the other.
567    fn list_body(&mut self, stmts: &[&Node], rettype: u32, columns: &[u32]) -> Result<Body> {
568        let [Node::SelectStmt(select)] = stmts else {
569            return Ok(Body::Statements(columns.to_vec()));
570        };
571        let mut query = self.select(select)?;
572        query.params.clone_from(&self.params);
573        self.result_columns(&mut query, rettype, columns)?;
574        Ok(Body::Query(Box::new(query)))
575    }
576
577    /// The query of the last statement of a body, as `check_sql_fn_retval` checks it: the columns of the query, or of the `RETURNING` list of a write, must be the columns of the result, and each column takes an assignment cast to the type of the result column. A function that returns a composite type can also give one column of that type, and a function that returns `void` can give any columns. A write with no `RETURNING` gives no rows, so it can be the last statement only of a function that returns `void`.
578    fn result_columns(&mut self, query: &mut Query, rettype: u32, columns: &[u32]) -> Result<()> {
579        if rettype == oid::VOID {
580            return Ok(());
581        }
582        let query = if query.write.is_some() {
583            let returning = query.write.as_mut().and_then(|w| w.returning.as_deref_mut());
584            returning.ok_or_else(|| no_final_query(rettype))?
585        } else {
586            query
587        };
588        let width = query.targets.iter().take_while(|t| !t.junk).count();
589        let row = rettype == oid::RECORD || columns.len() != 1 || columns != [rettype];
590        let whole_row = [rettype];
591        let columns: &[u32] = if row && width == 1 && query.targets[0].expr.ty == rettype {
592            &whole_row
593        } else {
594            columns
595        };
596        if !row && width != 1 {
597            return Err(mismatch(
598                rettype,
599                "Final statement must return exactly one column.".into(),
600            ));
601        }
602        if row && !columns.is_empty() && width != columns.len() {
603            let what = if width > columns.len() { "many" } else { "few" };
604            return Err(mismatch(rettype, format!("Final statement returns too {what} columns.")));
605        }
606        for (i, &ty) in columns.iter().enumerate() {
607            let target = &mut query.targets[i];
608            let actual = target.expr.ty;
609            if actual == ty {
610                continue;
611            }
612            let sorted = query.sort.iter().chain(&query.group).chain(&query.distinct);
613            if sorted.into_iter().any(|s| s.target == i) {
614                return Err(not_yet("a cast of a sorted column of the result of a function", None));
615            }
616            let cast =
617                self.coerce_to_target(target.expr.clone(), ty, -1, Context::Assignment, None)?;
618            target.expr = cast.ok_or_else(|| {
619                mismatch(
620                    rettype,
621                    format!(
622                        "Final statement returns {} instead of {} at column {}.",
623                        types::name(actual),
624                        types::name(ty),
625                        i + 1
626                    ),
627                )
628            })?;
629        }
630        Ok(())
631    }
632
633    /// The result type of a call of `function` with arguments of the types `inputs`, and the types of the columns of the result. A composite type gives the columns of its relation.
634    fn result_shape(&self, function: &Function, inputs: &[u32]) -> Result<(u32, Vec<u32>)> {
635        let mut columns = result_types(function, inputs)?;
636        let rettype = result_type(function, &columns);
637        if rettype != oid::RECORD
638            && let Some(fields) = self.row_columns(rettype)
639        {
640            columns = fields.iter().map(|c| c.ty).collect();
641        }
642        Ok((rettype, columns))
643    }
644
645    /// The body of a function for a call with arguments of the types `inputs`.
646    fn body(
647        &mut self,
648        function: &Function,
649        stmts: &Statements<'_>,
650        inputs: &[u32],
651    ) -> Result<Body> {
652        let (rettype, columns) = self.result_shape(function, inputs)?;
653        match stmts {
654            Statements::Return(value) => Ok(Body::Value(self.return_body(*value, rettype)?)),
655            Statements::Atomic(list) => self.list_body(list, rettype, &columns),
656            Statements::String(list) => {
657                let list: Vec<&Node> = list.iter().map(|(node, _)| node).collect();
658                self.list_body(&list, rettype, &columns)
659            }
660        }
661    }
662
663    /// `interpret_func_support`: the support function with the name, which takes and returns `internal`.
664    fn support_function(&self, names: &[String]) -> Result<u32> {
665        let parts: Vec<&str> = names.iter().map(String::as_str).collect();
666        let (schema, name) = self.split_name(&parts, None)?;
667        let path = schema.map_or_else(|| self.path.clone(), |schema| vec![schema]);
668        let found = path.iter().find_map(|&namespace| {
669            builtin::procs_named(name)
670                .find(|p| p.namespace == namespace && p.argtypes == [oid::INTERNAL])
671        });
672        let proc = found.ok_or_else(|| {
673            Error::new(
674                SqlState::UNDEFINED_FUNCTION,
675                format!("function {}(internal) does not exist", parts.join(".")),
676            )
677        })?;
678        if proc.rettype != oid::INTERNAL {
679            return Err(Error::new(
680                SqlState::INVALID_OBJECT_DEFINITION,
681                format!("support function {} must return type internal", parts.join(".")),
682            ));
683        }
684        Ok(proc.oid)
685    }
686}
687
688/// The body of a function in SQL as the analyzer reads it from the text that the catalog keeps, for a call with arguments of the types `inputs`, with `$1` as the first argument. `None` when the catalog has no function in SQL with the OID.
689///
690/// # Errors
691///
692/// The errors of the analysis of the body.
693pub fn function_body(env: &dyn Env, oid: u32, inputs: &[u32]) -> Result<Option<Body>> {
694    with_statement(env, oid, |function, body, stmt| {
695        let src = (!function.src.is_empty()).then_some(function.src.as_str());
696        let stmts = statements(stmt, src)?;
697        let params = Params { types: inputs.to_vec(), variable: false };
698        let mut an = Analyzer::new(env, &params);
699        // A body in a string of a function that sets `search_path` takes the current path, which the settings of the call gave.
700        if stmt.sql_body.is_some() || !sets_path(&function.config) {
701            an.set_path(&body.path);
702        }
703        an.sql_function = Some((function.name.clone(), input_names(function)));
704        let mut body = an.body(function, &stmts, inputs)?;
705        if let Some(catalog) = env.catalog() {
706            crate::expand_virtual_body(&mut body, catalog)?;
707        }
708        Ok(Some(body))
709    })
710}
711
712/// The statements of the body of a function in SQL that [`Body::Statements`] runs, which `fmgr_sql` analyzes and runs one after the other, as `prepare_next_query` and `init_execution_state` do. A statement can see the changes of the statements before it.
713#[derive(Debug)]
714pub struct Script {
715    function: Function,
716    /// The search path of the names of the statements, or `None` for the current path.
717    path: Option<Vec<u32>>,
718    /// Each statement, with its text.
719    pub statements: Vec<(Node, String)>,
720}
721
722impl Script {
723    /// The name of the function.
724    pub fn name(&self) -> &str {
725        &self.function.name
726    }
727
728    /// The body in a string, or an empty text for a body in `BEGIN ATOMIC`.
729    pub fn src(&self) -> &str {
730        &self.function.src
731    }
732
733    /// True for a function that is not volatile, which can run only statements that do not write, as `readonly_func` of `SQLFunctionHashEntry` is.
734    pub fn read_only(&self) -> bool {
735        self.function.volatile != b'v'
736    }
737
738    /// True when the statement `i` has a plan. The other statements run as utility statements.
739    pub fn planned(&self, i: usize) -> bool {
740        self.statements.get(i).is_some_and(|(node, _)| planned(node))
741    }
742
743    /// `prepare_next_query`: the query of the statement `i` for a call with arguments of the types `inputs`. The last statement gives the result of the function, as `check_sql_fn_retval` checks it. `None` for a statement with no plan.
744    ///
745    /// # Errors
746    ///
747    /// The errors of the analysis of the statement, and `42P13` for a last statement that does not give the result of the function.
748    pub fn analyze(&self, env: &dyn Env, inputs: &[u32], i: usize) -> Result<Option<Query>> {
749        let Some((node, _)) = self.statements.get(i) else { return Ok(None) };
750        let last = i + 1 == self.statements.len();
751        statement_query(env, &self.function, self.path.as_deref(), inputs, node, last)
752    }
753}
754
755/// The statements of the body of the function in SQL with the OID, for [`Body::Statements`]. `None` when the catalog has no function in SQL with the OID, or when the body is `RETURN`.
756///
757/// # Errors
758///
759/// The errors of the parse of the body, and `42P13` for a body with no statement in a function that does not return `void`.
760pub fn function_script(env: &dyn Env, oid: u32) -> Result<Option<Script>> {
761    with_statement(env, oid, |function, body, stmt| {
762        let src = (!function.src.is_empty()).then_some(function.src.as_str());
763        let statements = match statements(stmt, src)? {
764            Statements::Return(_) => return Ok(None),
765            Statements::Atomic(list) => {
766                list.into_iter().map(|node| (node.clone(), String::new())).collect()
767            }
768            Statements::String(list) => list,
769        };
770        if statements.is_empty() && function.rettype != oid::VOID {
771            return Err(no_final_query(function.rettype));
772        }
773        let path =
774            (stmt.sql_body.is_some() || !sets_path(&function.config)).then(|| body.path.clone());
775        Ok(Some(Script { function: function.clone(), path, statements }))
776    })
777}
778
779/// The body in SQL of a function, as `prosqlbody` keeps it.
780#[derive(Debug)]
781pub enum SqlBody {
782    /// A `RETURN` body: the value, with no cast to the result type.
783    Return(Expr),
784    /// A `BEGIN ATOMIC` body: the query of each statement.
785    Atomic(Vec<Query>),
786}
787
788/// The body in SQL of the function with the OID, as `interpret_AS_clause` analyzes it for `prosqlbody`: the arguments have their declared types, and the value of `RETURN` and the columns of the queries do not take a cast to the result type. `None` when the catalog has no function in SQL with the OID, or when the function has its body in a string.
789///
790/// # Errors
791///
792/// The errors of the analysis of the body.
793pub fn function_sqlbody(env: &dyn Env, oid: u32) -> Result<Option<SqlBody>> {
794    with_statement(env, oid, |function, body, stmt| {
795        if stmt.sql_body.is_none() {
796            return Ok(None);
797        }
798        let params = Params { types: function.argtypes.clone(), variable: false };
799        let analyzer = || {
800            let mut an = Analyzer::new(env, &params);
801            an.set_path(&body.path);
802            an.sql_function = Some((function.name.clone(), input_names(function)));
803            an
804        };
805        Ok(Some(match statements(stmt, None)? {
806            Statements::Return(value) => {
807                let mut an = analyzer();
808                let expr = an.with_kind(Kind::Select, |an| an.transform(value))?;
809                // `transformReturnStmt` gives the type `text` to a literal of an unknown type.
810                if expr.ty == oid::UNKNOWN {
811                    SqlBody::Return(an.coerce(expr, oid::TEXT, -1, Context::Implicit, None)?)
812                } else {
813                    SqlBody::Return(expr)
814                }
815            }
816            Statements::Atomic(list) => SqlBody::Atomic(
817                list.into_iter()
818                    .map(|node| crate::analyze_in(analyzer(), node, None))
819                    .collect::<Result<_>>()?,
820            ),
821            Statements::String(_) => return Ok(None),
822        }))
823    })
824}
825
826/// Runs `f` with the function in SQL with the OID, the text that the catalog keeps for it, and the `CREATE FUNCTION` statement of that text. `None` when the catalog has no function in SQL with the OID.
827fn with_statement<T>(
828    env: &dyn Env,
829    oid: u32,
830    f: impl FnOnce(&Function, &FunctionBody, &CreateFunctionStmt) -> Result<Option<T>>,
831) -> Result<Option<T>> {
832    let built_in;
833    let function = match env.catalog().and_then(|c| c.function(oid)) {
834        Some(function) => function,
835        None => {
836            let Some(function) = builtin_function(oid) else { return Ok(None) };
837            built_in = function;
838            &built_in
839        }
840    };
841    let Some(body) = function.body.as_ref().filter(|_| function.lang == SQL_LANGUAGE) else {
842        return Ok(None);
843    };
844    let (list, _) = rupg_sql::parse(&body.text).map_err(Error::from)?;
845    let stmt = list.iter().flatten().find_map(|node| match node {
846        Node::RawStmt(raw) => match raw.stmt.as_ref() {
847            Some(Node::CreateFunctionStmt(stmt)) => Some(stmt),
848            _ => None,
849        },
850        _ => None,
851    });
852    let stmt =
853        stmt.ok_or_else(|| Error::internal("the body of a function is not CREATE FUNCTION"))?;
854    f(function, body, stmt)
855}
856
857/// A built-in function with a body in SQL, which `system_functions.sql` gives it. `initdb` runs that script with `search_path` set to `pg_catalog`.
858fn builtin_function(oid: u32) -> Option<Function> {
859    let proc = builtin::proc_by_oid(oid)?;
860    let text = proc.sqlbody?;
861    Some(Function {
862        oid,
863        name: proc.name.into(),
864        namespace: proc.namespace,
865        // The bootstrap superuser.
866        owner: 10,
867        lang: proc.lang,
868        cost: DEFAULT_COST,
869        rows: 0,
870        support: 0,
871        kind: b'f',
872        strict: proc.strict,
873        leakproof: false,
874        volatile: proc.volatile,
875        parallel: b's',
876        rettype: proc.rettype,
877        retset: proc.retset,
878        argtypes: proc.argtypes.to_vec(),
879        allargtypes: proc.allargtypes.unwrap_or_default().to_vec(),
880        argmodes: proc.argmodes.unwrap_or_default().to_vec(),
881        argnames: proc.argnames.unwrap_or_default().iter().map(|n| (*n).into()).collect(),
882        // The body does not read the defaults.
883        argdefaults: None,
884        nargdefaults: 0,
885        src: String::new(),
886        bin: String::new(),
887        body: Some(FunctionBody { text: text.into(), path: vec![crate::PG_CATALOG_NAMESPACE] }),
888        config: Vec::new(),
889        secdef: false,
890    })
891}
892
893impl Definer<'_, '_> {
894    /// `CreateFunction` for a function in SQL. `text` is the text of the statement, which the catalog keeps. The return value is the OID of the function.
895    pub(super) fn create_function(&mut self, stmt: &CreateFunctionStmt, text: &str) -> Result<u32> {
896        let parts = names(&stmt.funcname);
897        let (schema, name) = self.an.split_name(&parts, None)?;
898        let namespace = match schema {
899            Some(namespace) => namespace,
900            None => self.an.env.search_path().first().copied().ok_or_else(|| {
901                Error::new(SqlState::UNDEFINED_SCHEMA, "no schema has been selected to create in")
902            })?,
903        };
904        self.check_create_in(namespace, None)?;
905        let options = options(stmt, self.an.env)?;
906        // A function in C or in `internal` runs code that the database does not check, so these languages are not trusted.
907        let untrusted = matches!(options.language, INTERNAL_LANGUAGE | C_LANGUAGE);
908        if untrusted && !self.is_superuser() {
909            return Err(Error::new(
910                SqlState::INSUFFICIENT_PRIVILEGE,
911                format!("permission denied for language {}", options.language_name),
912            ));
913        }
914        if options.leakproof && !self.is_superuser() {
915            return Err(only_superuser_leakproof());
916        }
917        let procedure = stmt.is_procedure;
918        let mut argtypes = Vec::new();
919        let mut allargtypes = Vec::new();
920        let mut argmodes = Vec::new();
921        let mut argnames = Vec::new();
922        let mut outs = Vec::new();
923        let mut defaults = Vec::new();
924        let bad = |message: &str, at| {
925            Err(Error::new(SqlState::INVALID_FUNCTION_DEFINITION, message.to_string()).at_opt(at))
926        };
927        for param in stmt.parameters.iter().flatten() {
928            let Node::FunctionParameter(param) = param else { continue };
929            let at = place(param.location);
930            let mode = match param.mode {
931                FunctionParameterMode::FUNC_PARAM_OUT => b'o',
932                FunctionParameterMode::FUNC_PARAM_INOUT => b'b',
933                FunctionParameterMode::FUNC_PARAM_TABLE => b't',
934                FunctionParameterMode::FUNC_PARAM_VARIADIC => b'v',
935                _ => b'i',
936            };
937            let ty = param.argType.as_deref().ok_or_else(|| Error::internal("an argument type"))?;
938            if ty.setof && procedure {
939                return bad("procedures cannot accept set arguments", at);
940            }
941            if ty.setof {
942                return bad("functions cannot accept set arguments", at);
943            }
944            let ty = self.an.type_name(ty)?.0;
945            let input = matches!(mode, b'i' | b'b' | b'v');
946            if input && argmodes.contains(&b'v') {
947                return bad("VARIADIC parameter must be the last input parameter", at);
948            }
949            // A `CALL` gives the output arguments too, so in a procedure an output parameter cannot come after `VARIADIC`.
950            if procedure && !input && argmodes.contains(&b'v') {
951                return bad("VARIADIC parameter must be the last parameter", at);
952            }
953            if mode == b'v'
954                && !matches!(ty, oid::ANYARRAY | oid::ANYCOMPATIBLEARRAY | oid::ANY)
955                && types::element(ty) == 0
956            {
957                return bad("VARIADIC parameter must be an array", at);
958            }
959            // Two input parameters or two output parameters cannot have the same name. An input parameter and an output parameter can.
960            let name = param.name.as_deref().unwrap_or_default();
961            let clash = argnames.iter().zip(&argmodes).any(|(other, &other_mode)| {
962                let pure = |m: u8| match m {
963                    b'i' | b'v' => Some(true),
964                    b'o' | b't' => Some(false),
965                    _ => None,
966                };
967                let apart = matches!((pure(mode), pure(other_mode)), (Some(a), Some(b)) if a != b);
968                !name.is_empty() && other == name && !apart
969            });
970            if clash {
971                return bad(&format!("parameter name \"{name}\" used more than once"), at);
972            }
973            if let Some(raw) = &param.defexpr {
974                if !input {
975                    return bad("only input parameters can have default values", at);
976                }
977                let expr =
978                    self.an.with_kind(Kind::FunctionDefault, |an| an.transform(Some(raw)))?;
979                defaults.push(self.an.coerce_to_specific(expr, ty, "DEFAULT")?);
980            } else if input && !defaults.is_empty() {
981                return bad(
982                    "input parameters after one with a default value must also have defaults",
983                    at,
984                );
985            } else if procedure && !defaults.is_empty() {
986                return bad(
987                    "procedure OUT parameters cannot appear after one with a default value",
988                    at,
989                );
990            }
991            if input {
992                argtypes.push(ty);
993            }
994            if matches!(mode, b'o' | b'b' | b't') {
995                outs.push(ty);
996            }
997            allargtypes.push(ty);
998            argmodes.push(mode);
999            argnames.push(name.to_string());
1000        }
1001        if argnames.iter().all(String::is_empty) {
1002            argnames.clear();
1003        }
1004        if argmodes.iter().all(|&mode| mode == b'i') {
1005            allargtypes.clear();
1006            argmodes.clear();
1007        }
1008        // `interpret_function_parameter_list`: the result type that the `OUT` parameters need.
1009        // A procedure with output parameters gives a row, also with one of them.
1010        let required = match outs.as_slice() {
1011            [] => None,
1012            [ty] if !procedure => Some(*ty),
1013            _ => Some(oid::RECORD),
1014        };
1015        let (rettype, retset) = match (stmt.returnType.as_deref(), required) {
1016            (_, required) if procedure => (required.unwrap_or(oid::VOID), false),
1017            (Some(ret), _) => {
1018                let rettype = self.an.type_name(ret)?.0;
1019                if let Some(required) = required.filter(|&r| r != rettype) {
1020                    return Err(Error::new(
1021                        SqlState::INVALID_FUNCTION_DEFINITION,
1022                        format!(
1023                            "function result type must be {} because of OUT parameters",
1024                            types::name(required)
1025                        ),
1026                    ));
1027                }
1028                (rettype, ret.setof)
1029            }
1030            (None, Some(required)) => (required, false),
1031            (None, None) => {
1032                return Err(Error::new(
1033                    SqlState::INVALID_FUNCTION_DEFINITION,
1034                    "function result type must be specified",
1035                ));
1036            }
1037        };
1038        if options.rows.is_some() && !retset {
1039            return Err(Error::new(
1040                SqlState::INVALID_PARAMETER_VALUE,
1041                "ROWS is not applicable when function does not return a set",
1042            ));
1043        }
1044        let support = match &options.support {
1045            Some(names) => self.an.support_function(names)?,
1046            None => 0,
1047        };
1048        let (src, bin) = interpret_as(stmt, &options, name)?;
1049        let function = Function {
1050            oid: 0,
1051            name: name.to_string(),
1052            namespace,
1053            owner: self.user,
1054            lang: options.language,
1055            cost: options.cost.unwrap_or(if untrusted { 1.0 } else { DEFAULT_COST }),
1056            rows: if retset { options.rows.unwrap_or(DEFAULT_ROWS) } else { 0 },
1057            support,
1058            kind: if stmt.is_procedure { b'p' } else { b'f' },
1059            strict: options.strict,
1060            leakproof: options.leakproof,
1061            volatile: options.volatile,
1062            parallel: options.parallel,
1063            rettype,
1064            retset,
1065            argtypes,
1066            allargtypes,
1067            argmodes,
1068            argnames,
1069            argdefaults: if defaults.is_empty() {
1070                None
1071            } else {
1072                Some(node::write_list(&defaults)?)
1073            },
1074            nargdefaults: i16::try_from(defaults.len()).unwrap_or(i16::MAX),
1075            src,
1076            bin,
1077            body: (!untrusted)
1078                .then(|| FunctionBody { text: text.to_string(), path: self.an.path.clone() }),
1079            config: options.config.clone(),
1080            secdef: options.secdef,
1081        };
1082        // `function_parse_error_transpose`: an error in a body in a string has its place in the query text.
1083        let transpose = |error: Error| match (&options.src, error.position()) {
1084            (Some(src), Some(inner)) => {
1085                let outer = body_place(text, src, options.src_at).map(|at| at + inner);
1086                error.with_position(outer)
1087            }
1088            _ => error,
1089        };
1090        // `sql_function_parse_error_callback`: an error in the check of a body that has no place in the query text names the function.
1091        let checked = |error: Error| match error.position() {
1092            Some(_) => transpose(error),
1093            None => error.with_context(format!("SQL function \"{name}\"")),
1094        };
1095        let old = self
1096            .catalog
1097            .functions()
1098            .find(|f| f.namespace == namespace && f.name == name && f.argtypes == function.argtypes)
1099            .cloned();
1100        if let Some(old) = &old {
1101            if !stmt.replace {
1102                return Err(Error::new(
1103                    SqlState::DUPLICATE_FUNCTION,
1104                    format!("function \"{name}\" already exists with same argument types"),
1105                ));
1106            }
1107            self.check_replace(old, &function)?;
1108        }
1109        let pseudo = |ty: u32| {
1110            builtin::type_by_oid(ty).is_some_and(|t| t.kind == b'p') && !types::is_polymorphic(ty)
1111        };
1112        if untrusted {
1113            check_untrusted(&function)?;
1114            return self.store_function(old, function, &defaults, support, Vec::new());
1115        }
1116        if function.lang == PLPGSQL_LANGUAGE {
1117            // `plpgsql_validator` compiles the body only when `check_function_bodies` is on.
1118            if self.an.env.check_function_bodies() {
1119                self.with_settings(&function.config, |d| d.check_plpgsql(stmt, &function))
1120                    .map_err(transpose)?;
1121            }
1122            return self.store_function(old, function, &defaults, support, Vec::new());
1123        }
1124        // `fmgr_sql_validator`: the only pseudo-types that a function in SQL can take are the polymorphic types, and it can also return `void` and `record`.
1125        if pseudo(rettype) && !matches!(rettype, oid::VOID | oid::RECORD) {
1126            return Err(Error::new(
1127                SqlState::INVALID_FUNCTION_DEFINITION,
1128                format!("SQL functions cannot return type {}", types::name(rettype)),
1129            ));
1130        }
1131        if let Some(&ty) = function.argtypes.iter().find(|&&ty| pseudo(ty)) {
1132            return Err(Error::new(
1133                SqlState::INVALID_FUNCTION_DEFINITION,
1134                format!("SQL functions cannot have arguments of type {}", types::name(ty)),
1135            ));
1136        }
1137        let stmts = statements(stmt, options.src.as_deref()).map_err(transpose)?;
1138        // `fmgr_sql_validator` reads a body in a string only when no argument is polymorphic and `check_function_bodies` is on, and a body in SQL always.
1139        let polymorphic = function.argtypes.iter().any(|&ty| types::is_polymorphic(ty));
1140        if let Statements::String(_) = &stmts {
1141            // `ProcedureCreate` adds the function before `fmgr_sql_validator` reads a body in a string, so the body can call the function.
1142            let oid = self.store_function(old, function.clone(), &defaults, support, Vec::new())?;
1143            if !polymorphic && self.an.env.check_function_bodies() {
1144                self.an.env.command_counter_increment(self.catalog);
1145                self.with_settings(&function.config, |d| d.sql_body(&function, &stmts))
1146                    .map_err(checked)?;
1147            }
1148            return Ok(oid);
1149        }
1150        let (body, queries) = self.sql_body(&function, &stmts).map_err(checked)?;
1151        let refs = match &body {
1152            Body::Value(expr) => body_references(self.catalog, expr)?,
1153            Body::Query(query) => {
1154                eliminate_duplicates(&super::view::function_references(self.catalog, query))
1155            }
1156            Body::Statements(_) => {
1157                let refs: Vec<ObjRef> = queries
1158                    .iter()
1159                    .flat_map(|query| super::view::function_references(self.catalog, query))
1160                    .collect();
1161                eliminate_duplicates(&refs)
1162            }
1163        };
1164        self.store_function(old, function, &defaults, support, refs)
1165    }
1166
1167    /// `ProcedureCreate`: the validator of the language runs with the settings of the function, which `ProcessGUCArray` gives with `GUC_ACTION_SAVE`, and the settings go back after it.
1168    fn with_settings<T>(
1169        &mut self,
1170        config: &[String],
1171        f: impl FnOnce(&mut Self) -> Result<T>,
1172    ) -> Result<T> {
1173        if config.is_empty() {
1174            return f(self);
1175        }
1176        self.an.env.push_function_settings(config)?;
1177        let result = f(self);
1178        self.an.env.pop_function_settings();
1179        result
1180    }
1181
1182    /// `fmgr_sql_validator`: the body of a new function in SQL, for a call with arguments of the types of its parameters, and the queries of the statements of a body that is not one `SELECT`. A body in a string reads its names with the `search_path` of the settings of the function, when they set it.
1183    fn sql_body(
1184        &mut self,
1185        function: &Function,
1186        stmts: &Statements<'_>,
1187    ) -> Result<(Body, Vec<Query>)> {
1188        let params = Params { types: function.argtypes.clone(), variable: false };
1189        let mut an = Analyzer::new(self.an.env, &params);
1190        // The new analyzer takes the current path, which the settings gave.
1191        let path = (!matches!(stmts, Statements::String(_)) || !sets_path(&function.config))
1192            .then(|| self.an.path.clone());
1193        if let Some(path) = &path {
1194            an.set_path(path);
1195        }
1196        an.sql_function = Some((function.name.clone(), input_names(function)));
1197        let body = an.body(function, stmts, &function.argtypes)?;
1198        self.an.notices.append(&mut an.notices);
1199        let mut queries = Vec::new();
1200        if let Body::Statements(_) = &body {
1201            let list: Vec<&Node> = match stmts {
1202                Statements::Return(_) => Vec::new(),
1203                Statements::Atomic(list) => list.clone(),
1204                Statements::String(list) => list.iter().map(|(node, _)| node).collect(),
1205            };
1206            queries = check_statements(self.an.env, function, path.as_deref(), &list)?;
1207            for query in &mut queries {
1208                self.an.notices.append(&mut query.notices);
1209            }
1210        }
1211        Ok((body, queries))
1212    }
1213
1214    /// `ProcedureCreate`: adds the function to the catalog, or replaces `old`, with the dependencies `refs` of its body and the dependencies of its support function, its defaults and its types.
1215    fn store_function(
1216        &mut self,
1217        old: Option<Function>,
1218        function: Function,
1219        defaults: &[Expr],
1220        support: u32,
1221        refs: Vec<ObjRef>,
1222    ) -> Result<u32> {
1223        let refs = self.function_refs(&function, defaults, support, refs)?;
1224        match old {
1225            Some(old) => self.catalog.replace_function(old.oid, function, &refs).map(|()| old.oid),
1226            None => {
1227                let oid = self.catalog.create_function(function, &refs)?;
1228                self.apply_default_acl(ObjRef::new(PG_PROC, oid))?;
1229                Ok(oid)
1230            }
1231        }
1232    }
1233
1234    /// The dependencies of `ProcedureCreate` for a function: `refs`, then its support function, its defaults and its types.
1235    pub(super) fn function_refs(
1236        &self,
1237        function: &Function,
1238        defaults: &[Expr],
1239        support: u32,
1240        mut refs: Vec<ObjRef>,
1241    ) -> Result<Vec<ObjRef>> {
1242        if support != 0 {
1243            refs.push(ObjRef::new(PG_PROC, support));
1244        }
1245        for default in defaults {
1246            for found in body_references(self.catalog, default)? {
1247                if !refs.contains(&found) {
1248                    refs.push(found);
1249                }
1250            }
1251        }
1252        // `ProcedureCreate`: the function depends on the types of its result and of its arguments.
1253        let args = if function.allargtypes.is_empty() {
1254            &function.argtypes
1255        } else {
1256            &function.allargtypes
1257        };
1258        for &ty in std::iter::once(&function.rettype).chain(args) {
1259            let found = ObjRef::new(PG_TYPE, ty);
1260            if !refs.contains(&found) {
1261                refs.push(found);
1262            }
1263        }
1264        Ok(refs)
1265    }
1266
1267    /// `plpgsql_validator`: a function in PL/pgSQL has a body in a string, and the only pseudo-types that it can take are the polymorphic types and `record`. It can also return `void`, `trigger` and `event_trigger`. Then the session compiles the body.
1268    fn check_plpgsql(&self, stmt: &CreateFunctionStmt, function: &Function) -> Result<()> {
1269        if stmt.sql_body.is_some() {
1270            return Err(Error::new(
1271                SqlState::INVALID_FUNCTION_DEFINITION,
1272                "inline SQL function body only valid for language SQL",
1273            ));
1274        }
1275        if function.src.is_empty()
1276            && !stmt
1277                .options
1278                .iter()
1279                .flatten()
1280                .any(|o| matches!(o, Node::DefElem(def) if def.defname.as_deref() == Some("as")))
1281        {
1282            return Err(Error::new(
1283                SqlState::INVALID_FUNCTION_DEFINITION,
1284                "no function body specified",
1285            ));
1286        }
1287        let pseudo = |ty: u32| builtin::type_by_oid(ty).is_some_and(|t| t.kind == b'p');
1288        let ret = function.rettype;
1289        if pseudo(ret)
1290            && !matches!(ret, oid::TRIGGER | oid::EVENT_TRIGGER | oid::RECORD | oid::VOID)
1291            && !types::is_polymorphic(ret)
1292        {
1293            return Err(Error::new(
1294                SqlState::FEATURE_NOT_SUPPORTED,
1295                format!("PL/pgSQL functions cannot return type {}", types::name(ret)),
1296            ));
1297        }
1298        let args = if function.allargtypes.is_empty() {
1299            &function.argtypes
1300        } else {
1301            &function.allargtypes
1302        };
1303        if let Some(&ty) =
1304            args.iter().find(|&&ty| pseudo(ty) && ty != oid::RECORD && !types::is_polymorphic(ty))
1305        {
1306            return Err(Error::new(
1307                SqlState::FEATURE_NOT_SUPPORTED,
1308                format!("PL/pgSQL functions cannot accept type {}", types::name(ty)),
1309            ));
1310        }
1311        self.an.env.check_function(function)
1312    }
1313
1314    /// The checks of `ProcedureCreate` for `CREATE OR REPLACE FUNCTION` of the function `old`: the owner, the kind, the result type, the row type of the `OUT` parameters, the names of the input arguments and the defaults do not change. New defaults can be added before the old ones.
1315    pub(super) fn check_replace(&self, old: &Function, new: &Function) -> Result<()> {
1316        if !self.is_superuser() && old.owner != self.user {
1317            return Err(super::comment::not_owner("function", &old.name));
1318        }
1319        if old.kind != new.kind {
1320            let what = match old.kind {
1321                b'a' => "an aggregate function",
1322                b'p' => "a procedure",
1323                b'w' => "a window function",
1324                _ => "a function",
1325            };
1326            return Err(Error::new(SqlState::WRONG_OBJECT_TYPE, "cannot change routine kind")
1327                .with_detail(format!("\"{}\" is {what}.", old.name)));
1328        }
1329        let signature = self.describe(ObjRef::new(PG_PROC, old.oid));
1330        let signature = signature.split_once(' ').map_or(&*signature, |(_, rest)| rest);
1331        let drop = match new.kind {
1332            b'p' => "DROP PROCEDURE",
1333            b'a' => "DROP AGGREGATE",
1334            _ => "DROP FUNCTION",
1335        };
1336        let error = |message: String| {
1337            Error::new(SqlState::INVALID_FUNCTION_DEFINITION, message)
1338                .with_hint(format!("Use {drop} {signature} first."))
1339        };
1340        let changed = "cannot change return type of existing function".to_string();
1341        if (old.rettype != new.rettype || old.retset != new.retset) && new.kind == b'p' {
1342            return Err(error("cannot change whether a procedure has output parameters".into()));
1343        }
1344        if old.rettype != new.rettype || old.retset != new.retset {
1345            return Err(error(changed));
1346        }
1347        let outs = |f: &Function| -> Vec<(u32, String)> {
1348            f.allargtypes
1349                .iter()
1350                .zip(&f.argmodes)
1351                .zip(f.argnames.iter().map(String::as_str).chain(std::iter::repeat("")))
1352                .filter(|((_, mode), _)| matches!(mode, b'o' | b'b' | b't'))
1353                .map(|((&ty, _), name)| (ty, name.to_string()))
1354                .collect()
1355        };
1356        if old.rettype == oid::RECORD && outs(old) != outs(new) {
1357            return Err(
1358                error(changed).with_detail("Row type defined by OUT parameters is different.")
1359            );
1360        }
1361        let names = input_names(new);
1362        for (i, name) in input_names(old).iter().enumerate() {
1363            if !name.is_empty() && names.get(i) != Some(name) {
1364                return Err(error(format!("cannot change name of input parameter \"{name}\"")));
1365            }
1366        }
1367        if old.nargdefaults > 0 {
1368            if new.nargdefaults < old.nargdefaults {
1369                return Err(error(
1370                    "cannot remove parameter defaults from existing function".into(),
1371                ));
1372            }
1373            let defaults =
1374                |f: &Function| f.argdefaults.as_deref().map_or(Ok(Vec::new()), node::read_list);
1375            let (olds, news) = (defaults(old)?, defaults(new)?);
1376            let skip = news.len().saturating_sub(olds.len());
1377            if olds.iter().zip(&news[skip..]).any(|(o, n)| o.ty != n.ty) {
1378                return Err(error(
1379                    "cannot change data type of existing parameter default value".into(),
1380                ));
1381            }
1382        }
1383        Ok(())
1384    }
1385}