Skip to main content

rupg_analyze/
prepare.rs

1//! The parts of `PREPARE` and `EXECUTE` that the analyzer does, as `PrepareQuery` and `EvaluateParams` of `prepare.c` do them.
2
3use rupg_common::{Error, Result, SqlState};
4use rupg_sql::nodes::{List, Node};
5
6use crate::agg::Kind;
7use crate::coerce::{AtOpt, Context};
8use crate::select::{Query, Target};
9use crate::{Analyzer, Env, Params, types};
10
11/// `PrepareQuery`: the type OIDs of the parameters that `PREPARE` declares, as `typenameTypeId` finds them.
12///
13/// # Errors
14///
15/// `42704` for a type that does not exist.
16pub fn param_types(names: &List, env: &dyn Env) -> Result<Vec<u32>> {
17    let mut analyzer = Analyzer::new(env, &Params::default());
18    names
19        .iter()
20        .map(|node| match node {
21            Some(Node::TypeName(name)) => analyzer.type_name(name).map(|(ty, _)| ty),
22            _ => Err(Error::new(SqlState::INTERNAL_ERROR, "a parameter of PREPARE is not a type")),
23        })
24        .collect()
25}
26
27/// `EvaluateParams`: the query that gives the values of the parameters of `EXECUTE`. It has no `FROM` and one column for each expression, which is coerced to the type of its parameter in the assignment context. The caller checks the number of the expressions first.
28///
29/// # Errors
30///
31/// The errors of the expressions, such as a subquery or an aggregate call, and `42804` for an expression that cannot be coerced to the type of its parameter.
32pub fn execute_params(exprs: &List, types: &[u32], env: &dyn Env) -> Result<Query> {
33    let mut analyzer = Analyzer::new(env, &Params::default());
34    let mut targets = Vec::with_capacity(exprs.len());
35    for (i, (node, &ty)) in exprs.iter().zip(types).enumerate() {
36        let expr = analyzer.with_kind(Kind::ExecuteParameter, |an| an.transform(node.as_ref()))?;
37        let (given, at) = (expr.ty, expr.location);
38        let Some(expr) = analyzer.coerce_to_target(expr, ty, -1, Context::Assignment, at)? else {
39            return Err(Error::new(
40                SqlState::DATATYPE_MISMATCH,
41                format!(
42                    "parameter ${} of type {} cannot be coerced to the expected type {}",
43                    i + 1,
44                    types::name(given),
45                    types::name(ty)
46                ),
47            )
48            .with_hint("You will need to rewrite or cast the expression.")
49            .at_opt(at));
50        };
51        targets.push(Target { name: "?column?".into(), expr, origin: None, junk: false });
52    }
53    Ok(Query {
54        relations: Vec::new(),
55        from: Vec::new(),
56        targets,
57        filter: None,
58        grouped: false,
59        group: Vec::new(),
60        grouping_sets: Vec::new(),
61        group_distinct: false,
62        having: None,
63        sort: Vec::new(),
64        distinct: Vec::new(),
65        distinct_on: false,
66        offset: None,
67        limit: None,
68        with_ties: false,
69        params: Vec::new(),
70        notices: analyzer.notices,
71        set_op: None,
72        windows: Vec::new(),
73        ctes: Vec::new(),
74        recursive: false,
75        row_marks: Vec::new(),
76        write: None,
77        out_args: Vec::new(),
78        pulled: 0,
79        pushed: false,
80        barrier: Vec::new(),
81        minmax: None,
82        constraint_deps: Vec::new(),
83        shown: None,
84        perms: Vec::new(),
85        funcs: Vec::new(),
86    })
87}