1use rupg_common::Result;
4use rupg_pgcatalog::builtin;
5
6use crate::expr::{Expr, ExprKind, Func};
7use crate::from::{Column, Relation};
8use crate::{Analyzer, poly, types};
9
10pub fn out_columns(func: &Func) -> Result<Option<Vec<Column>>> {
16 let Some(proc) = builtin::proc_by_oid(func.oid) else { return Ok(None) };
17 let (Some(all), Some(modes)) = (proc.allargtypes, proc.argmodes) else { return Ok(None) };
18 let mut columns: Vec<Column> = Vec::new();
19 for (i, (&ty, mode)) in all.iter().zip(modes).enumerate() {
20 if !matches!(mode, b'o' | b'b' | b't') {
21 continue;
22 }
23 let name = proc.argnames.and_then(|n| n.get(i)).copied().filter(|n| !n.is_empty());
24 let name = name.map_or_else(|| format!("column{}", columns.len() + 1), str::to_string);
25 let ty = if types::is_polymorphic(ty) {
26 let inputs: Vec<u32> = func.args.iter().map(|a| a.ty).collect();
27 poly::resolve(&inputs, &mut proc.argtypes.to_vec(), ty)?
28 } else {
29 ty
30 };
31 columns.push(Column { name, ty, typmod: -1, not_null: false });
32 }
33 let procedure = proc.kind == b'p' && !columns.is_empty();
34 Ok((columns.len() > 1 || procedure).then_some(columns))
35}
36
37pub fn record_fields(expr: &Expr, levels: &[&[Relation]]) -> Result<Option<Vec<Column>>> {
43 match &expr.kind {
44 ExprKind::Func(f) => out_columns(f),
45 ExprKind::JoinRow(row) => Ok(Some(
46 row.names
47 .iter()
48 .zip(&row.fields)
49 .map(|(name, field)| Column {
50 name: name.clone(),
51 ty: field.ty,
52 typmod: field.typmod,
53 not_null: false,
54 })
55 .collect(),
56 )),
57 ExprKind::Var(var) => {
58 let Some(relation) = levels.get(var.levels_up).and_then(|r| r.get(var.relation)) else {
59 return Ok(None);
60 };
61 if var.attnum == 0 {
62 let mut columns = relation.columns.clone();
63 if relation.oid != 0 {
64 columns.retain(|c| !c.is_dropped());
65 }
66 if let Some(names) = &relation.alias {
67 for (column, name) in columns.iter_mut().zip(names) {
68 column.name.clone_from(name);
69 }
70 }
71 return Ok(Some(columns));
72 }
73 let (0, Some(query)) = (relation.oid, &relation.subquery) else { return Ok(None) };
75 let target = usize::try_from(var.attnum - 1).ok().and_then(|i| query.targets.get(i));
76 let Some(target) = target else { return Ok(None) };
77 let mut inner = vec![&query.relations[..]];
78 inner.extend_from_slice(&levels[var.levels_up..]);
79 record_fields(&target.expr, &inner)
80 }
81 _ => Ok(None),
82 }
83}
84
85impl Analyzer<'_> {
86 pub(crate) fn record_columns(&self, expr: &Expr) -> Result<Option<Vec<Column>>> {
88 let levels: Vec<&[Relation]> = self.levels().map(|(_, s)| &s.relations[..]).collect();
89 record_fields(expr, &levels)
90 }
91}