Skip to main content

rupg_analyze/
from.rs

1//! `transformFromClause` of `parse_clause.c` and the name lookup of `parse_relation.c`: the relations of `FROM`, the joins, and the column that a name gives.
2
3use rupg_catalog::RelKind;
4use rupg_common::{Error, Result, SqlState};
5use rupg_pgcatalog::Values;
6use rupg_pgcatalog::builtin::{self, Named};
7use rupg_sql::nodes::{
8    Alias, CoercionForm, ColumnRef, FuncCall, JoinExpr, JoinType, JsonTable, Node, RangeFunction,
9    RangeSubselect, RangeTableSample, RangeVar, SelectStmt,
10};
11use rupg_types::oid;
12
13use crate::Analyzer;
14use crate::agg::Kind;
15use crate::coerce::{AtOpt, Context};
16use crate::colname::figure_colname;
17use crate::cte::{CteItem, CteRef};
18use crate::expr::{CastForm, Expr, ExprKind, JoinRow, Var};
19use crate::insert::WriteKind;
20use crate::perm::{ACL_SELECT, PermInfo};
21use crate::typename::place;
22use crate::types;
23
24/// `MAX_FUZZY_DISTANCE` of `parse_relation.c`: the largest distance of a name that an error suggests.
25const MAX_FUZZY_DISTANCE: usize = 3;
26
27/// The attribute number of the system column `tableoid`.
28pub const TABLE_OID_ATTNUM: i16 = -6;
29
30/// The system columns other than `tableoid`, with their numbers and types.
31const OTHER_SYSTEM_COLUMNS: [(&str, i16, u32); 5] = [
32    ("ctid", -1, oid::TID),
33    ("xmin", -2, oid::XID),
34    ("cmin", -3, oid::CID),
35    ("xmax", -4, oid::XID),
36    ("cmax", -5, oid::CID),
37];
38
39/// True when `name` is the name of a system column.
40fn is_system_column(name: &str) -> bool {
41    name == "tableoid" || OTHER_SYSTEM_COLUMNS.iter().any(|c| c.0 == name)
42}
43
44/// The attribute number and the type of a system column, as `SystemAttributeByName` gives them.
45pub(crate) fn system_column(name: &str) -> Option<(i16, u32)> {
46    if name == "tableoid" {
47        return Some((TABLE_OID_ATTNUM, oid::OID));
48    }
49    OTHER_SYSTEM_COLUMNS.iter().find(|c| c.0 == name).map(|c| (c.1, c.2))
50}
51
52/// A relation of `FROM`, as a `RangeTblEntry` of the kind `RTE_RELATION` or `RTE_SUBQUERY`.
53#[derive(Clone, Debug, PartialEq)]
54pub struct Relation {
55    /// The OID of the `pg_class` row, or 0 for a subquery.
56    pub oid: u32,
57    /// The columns of the relation, with their real names. The columns of a subquery are the columns of its result.
58    pub columns: Vec<Column>,
59    /// The query of a subquery in `FROM`, or the query of a view, which the executor reads in place of the view.
60    pub subquery: Option<Box<crate::Query>>,
61    /// The calls of a function in `FROM`.
62    pub function: Option<FromFunction>,
63    /// The rows of a `VALUES` list, each with one expression for each column.
64    pub values: Option<Vec<Vec<Expr>>>,
65    /// `eref->aliasname`: the alias, or the name that the analyzer gives the relation, such as the name of the table, `unnamed_subquery` or the name of the function.
66    pub name: String,
67    /// The names of the columns of the alias when the query gives the relation an alias, as `alias->colnames`. [`Relation::name`] is then the name of the alias.
68    pub alias: Option<Vec<String>>,
69    /// True when the query writes `LATERAL` before a subquery or a function.
70    pub lateral: bool,
71    /// The query of `WITH` that the relation reads.
72    pub cte: Option<CteRef>,
73    /// The `TABLESAMPLE` clause of a table.
74    pub tablesample: Option<TableSample>,
75    /// True for `ONLY` before the name of a table. A partitioned table then gives no rows, and a table gives no rows of its children of `INHERITS`.
76    pub only: bool,
77    /// `perminfoindex`: the index of the privileges of a table or a view in the privileges of the statement while the analyzer reads the statement, or `None` for a relation that needs no privileges.
78    pub perm: Option<usize>,
79}
80
81impl Relation {
82    /// A relation with no name, no alias and no `LATERAL`. `add_relation` gives it its name.
83    pub(crate) fn new(
84        oid: u32,
85        columns: Vec<Column>,
86        subquery: Option<Box<crate::Query>>,
87        function: Option<FromFunction>,
88        values: Option<Vec<Vec<Expr>>>,
89    ) -> Relation {
90        Relation {
91            oid,
92            columns,
93            subquery,
94            function,
95            values,
96            name: String::new(),
97            alias: None,
98            lateral: false,
99            cte: None,
100            tablesample: None,
101            only: false,
102            perm: None,
103        }
104    }
105
106    /// True when the columns of the relation are the columns of a table, with its dropped columns: a table, or a transition table of a trigger.
107    pub(crate) fn of_table(&self) -> bool {
108        self.oid != 0 || self.cte.as_ref().is_some_and(|c| c.transition)
109    }
110
111    /// The call of `JSON_TABLE` when the relation is one.
112    pub fn json_table(&self) -> Option<&crate::expr::JsonTable> {
113        match self.function.as_ref()?.calls.as_slice() {
114            [(Expr { kind: ExprKind::JsonTable(table), .. }, _)] => Some(table),
115            _ => None,
116        }
117    }
118}
119
120/// `TableSampleClause`: the sample method of `TABLESAMPLE` and its arguments.
121#[derive(Clone, Debug, PartialEq)]
122pub struct TableSample {
123    /// The OID of the handler function of the method.
124    pub handler: u32,
125    /// The arguments, each with the type that the method gives for it.
126    pub args: Vec<Expr>,
127    /// The seed of `REPEATABLE`, of type `double precision`.
128    pub repeatable: Option<Expr>,
129}
130
131/// A call of a function in `FROM` with its name and its column definition list.
132type FunctionCall<'n> = (Expr, String, &'n [Option<Node>]);
133
134/// A function in `FROM`, as the `functions` and `funcordinality` of a `RangeTblEntry` of the kind `RTE_FUNCTION`.
135#[derive(Clone, Debug, PartialEq)]
136pub struct FromFunction {
137    /// The call of the function, or of each function of `ROWS FROM`, with the number of columns that it gives. The rows of the calls go side by side, and a call with fewer rows gives nulls.
138    pub calls: Vec<(Expr, usize)>,
139    /// `WITH ORDINALITY`: the last column is the number of the row, from 1.
140    pub ordinality: bool,
141    /// For each call, true when the query gives a column definition list for it, as `funccolnames` of `RangeTblFunction`.
142    pub coldefs: Vec<bool>,
143}
144
145/// A column of a relation.
146#[derive(Clone, Debug, PartialEq)]
147pub struct Column {
148    pub name: String,
149    pub ty: u32,
150    pub typmod: i32,
151    /// `attnullability` is `ATTNULLABLE_VALID`: the column has a valid not-null constraint, so no row has a null in it.
152    pub not_null: bool,
153}
154
155impl Column {
156    /// True for a dropped column of a table, which keeps its place with no name and the type 0.
157    pub(crate) fn is_dropped(&self) -> bool {
158        self.ty == 0 && self.name.is_empty()
159    }
160}
161
162/// The name, the type and the type modifier of a column of the catalog for [`Analyzer::add_table`]. A dropped column has no name.
163pub(crate) fn scope_column(c: &rupg_catalog::Column) -> (String, u32, i32) {
164    (if c.dropped { String::new() } else { c.name.clone() }, c.ty, c.typmod)
165}
166
167/// A part of `FROM`: a relation or a join.
168#[derive(Clone, Debug, PartialEq)]
169pub enum FromItem {
170    /// The relation with this index in [`crate::Query::relations`].
171    Relation(usize),
172    Join(Box<Join>),
173}
174
175/// A join of two parts of `FROM`.
176#[derive(Clone, Debug, PartialEq)]
177pub struct Join {
178    pub kind: JoinKind,
179    pub left: FromItem,
180    pub right: FromItem,
181    /// The condition of `ON` or of `USING`, of type `boolean`, or `None` for a cross join.
182    pub on: Option<Expr>,
183    /// The names of the columns of `USING`, or the common columns of a natural join.
184    pub using: Vec<String>,
185    /// True when each merged column of `USING` is a column of one side with no cast. A merged column of a full join, or with a cast, is not a column of one side, as `has_dangerous_join_using` finds.
186    pub plain_using: bool,
187    /// The alias of the join.
188    pub alias: Option<String>,
189    /// The alias of `USING (...) AS name`.
190    pub using_alias: Option<String>,
191    /// The value of each column of `USING`, as `joinaliasvars` has it: a column of one side, a cast of it, or `COALESCE` of the two sides for a full join.
192    pub merged: Vec<Expr>,
193    /// The name and the value of each column of the join, as `eref->colnames` and `joinaliasvars`: the columns of `USING` first, then the other columns of the left side, then the other columns of the right side.
194    pub columns: Vec<(String, Expr)>,
195    /// The names of the columns that the alias of the join gives, as `alias->colnames`.
196    pub aliases: Vec<String>,
197    /// For each column of the join, the number from 1 of the column of the left side and of the right side that it reads, or 0, as `joinleftcols` and `joinrightcols`.
198    pub sources: Vec<(usize, usize)>,
199}
200
201/// The kinds of join. Only the planner makes a semi join or an anti join, as `pull_up_sublinks` makes them from `EXISTS` and `IN`.
202#[derive(Clone, Copy, Debug, PartialEq, Eq)]
203pub enum JoinKind {
204    Inner,
205    Left,
206    Right,
207    Full,
208    /// Each row of the left side that has a row of the right side that matches, once, as `JOIN_SEMI`.
209    Semi,
210    /// Each row of the left side that has no row of the right side that matches, as `JOIN_ANTI`.
211    Anti,
212    /// A semi join with the sides swapped, as `JOIN_RIGHT_SEMI`.
213    RightSemi,
214    /// An anti join with the sides swapped, as `JOIN_RIGHT_ANTI`.
215    RightAnti,
216}
217
218/// An entry of the range table, as `RangeTblEntry`: a relation or a join. The errors search all the entries, also the entries that a name cannot see.
219#[derive(Clone, Debug)]
220pub(crate) struct Entry {
221    /// `eref->aliasname`: the alias, or the name of the relation.
222    name: String,
223    /// True when the query gives an alias.
224    aliased: bool,
225    /// `eref->colnames`.
226    columns: Vec<String>,
227    /// The index in the relations for a relation, or `None` for a join.
228    relation: Option<usize>,
229    /// The OID of the relation, or 0 for a join.
230    oid: u32,
231}
232
233/// An item of the namespace, as `ParseNamespaceItem`: a name that the query can use and its columns.
234#[derive(Clone, Debug)]
235pub(crate) struct Item {
236    /// The index of the entry in the range table.
237    entry: usize,
238    /// The name that qualifies the columns.
239    name: String,
240    /// The name and the value of each column that the item gives.
241    columns: Vec<(String, Expr)>,
242    /// True when a qualified name can use the item.
243    rel_visible: bool,
244    /// True when an unqualified column name can use the item.
245    cols_visible: bool,
246    /// The number of the last columns that `*` does not give, as `p_dontexpand`: the columns of `SEARCH` and `CYCLE` in a reference from inside the query of `WITH`.
247    hidden: usize,
248    /// True for the items `old` and `new` of `RETURNING`, whose `p_returning_type` is not `VAR_RETURNING_DEFAULT`. A name with a schema does not find them.
249    returning: bool,
250}
251
252impl Item {
253    /// The columns of an automatically updatable view in place of the columns of its base relation.
254    pub(crate) fn set_columns(&mut self, columns: impl Iterator<Item = (String, Expr)>) {
255        self.columns = columns.collect();
256    }
257
258    /// Keeps the last `count` columns out of `*`.
259    pub(crate) fn hide_last(&mut self, count: usize) {
260        self.hidden = count;
261    }
262}
263
264/// The state of the names of `FROM`.
265#[derive(Clone, Debug, Default)]
266pub(crate) struct Scope {
267    pub(crate) relations: Vec<Relation>,
268    entries: Vec<Entry>,
269    namespace: Vec<Item>,
270    /// The items that only a `LATERAL` subquery can see, as the items with `p_lateral_only`, each with `p_lateral_ok`: the parts of `FROM` before a subquery, and the left side of a join while the analyzer reads the right side.
271    lateral: Vec<(Item, bool)>,
272    /// `p_lateral_active`: true while the analyzer reads a `LATERAL` subquery of this query, which can see the items of `lateral`.
273    lateral_active: bool,
274    /// `p_ctenamespace`: the queries of the `WITH` clause of this query.
275    pub(crate) ctes: Vec<CteItem>,
276    /// The relation that gives `merge_action()` while the analyzer reads the `RETURNING` list of a `MERGE`.
277    pub(crate) merge_action: Option<usize>,
278}
279
280impl Scope {
281    /// The items that a name can find, each with `p_lateral_ok`: the namespace, then the items that only `LATERAL` can see when a `LATERAL` subquery is active.
282    fn visible(&self) -> impl Iterator<Item = (&Item, bool)> {
283        let lateral = self.lateral.iter().filter(|_| self.lateral_active);
284        self.namespace.iter().map(|i| (i, true)).chain(lateral.map(|(i, ok)| (i, *ok)))
285    }
286}
287
288/// `check_lateral_ref_ok`: an item on the left side of a full or a right join is visible in a `LATERAL` subquery on the right side, but a reference to it is an error.
289fn check_lateral_ok(item: &Item, ok: bool, at: Option<usize>) -> Result<()> {
290    if ok {
291        return Ok(());
292    }
293    Err(Error::new(
294        SqlState::INVALID_COLUMN_REFERENCE,
295        format!("invalid reference to FROM-clause entry for table \"{}\"", item.name),
296    )
297    .with_detail("The combining JOIN type must be INNER or LEFT for a LATERAL reference.")
298    .at_opt(at))
299}
300
301/// `varstr_levenshtein` with costs of 1: the edit distance of two names, by characters.
302fn levenshtein(a: &str, b: &str) -> usize {
303    let b: Vec<char> = b.chars().collect();
304    let mut row: Vec<usize> = (0..=b.len()).collect();
305    for (i, ca) in a.chars().enumerate() {
306        let mut prev = row[0];
307        row[0] = i + 1;
308        for (j, cb) in b.iter().enumerate() {
309            let cost = usize::from(ca != *cb);
310            let next = (row[j] + 1).min(row[j + 1] + 1).min(prev + cost);
311            prev = row[j + 1];
312            row[j + 1] = next;
313        }
314    }
315    row[b.len()]
316}
317
318/// `FuzzyAttrMatchState`: the best matches of a column name that does not exist.
319struct Fuzzy {
320    distance: usize,
321    first: Option<(Place, usize)>,
322    second: Option<(Place, usize)>,
323    exact: Vec<Place>,
324}
325
326/// The place of an entry of the range table: the query level, 0 for the query of the name, and the index of the entry at that level.
327type Place = (usize, usize);
328
329impl Fuzzy {
330    /// `updateFuzzyAttrMatchState`.
331    fn update(&mut self, penalty: usize, entry: Place, actual: &str, wanted: &str, column: usize) {
332        if penalty > self.distance || actual.is_empty() {
333            return;
334        }
335        let distance = levenshtein(actual, wanted);
336        if distance > wanted.len() / 2 {
337            return;
338        }
339        let distance = distance + penalty;
340        if distance < self.distance {
341            self.distance = distance;
342            self.first = Some((entry, column));
343            self.second = None;
344        } else if distance == self.distance {
345            if self.second.is_some() {
346                self.first = None;
347                self.second = None;
348            } else if self.first.is_some() {
349                self.second = Some((entry, column));
350            }
351        }
352    }
353}
354
355/// The names of an alias column list.
356fn alias_columns(alias: &Alias) -> Vec<String> {
357    alias
358        .colnames
359        .iter()
360        .filter_map(|n| match n {
361            Some(Node::String(s)) => Some(s.to_string()),
362            _ => None,
363        })
364        .collect()
365}
366
367/// The strings of a list of `String` nodes, where `None` is `*`.
368fn fields(list: &[Option<Node>]) -> Vec<Option<&str>> {
369    list.iter()
370        .map(|f| match f {
371            Some(Node::String(s)) => Some(&**s),
372            _ => None,
373        })
374        .collect()
375}
376
377impl Analyzer<'_> {
378    /// `transformFromClause`: the parts of `FROM`, with their names in the namespace.
379    pub(crate) fn transform_from(&mut self, list: &[Option<Node>]) -> Result<Vec<FromItem>> {
380        let mut items = Vec::with_capacity(list.len());
381        for node in list {
382            let node = node.as_ref().ok_or_else(|| Error::internal("an empty FROM item"))?;
383            let (item, _, namespace) = self.transform_from_item(node)?;
384            self.check_conflicts(&self.scope.namespace, &namespace)?;
385            self.scope.namespace.extend(namespace);
386            items.push(item);
387        }
388        Ok(items)
389    }
390
391    /// `transformFromClauseItem`: one part of `FROM`, the namespace item of its result, and the namespace that it adds.
392    fn transform_from_item(&mut self, node: &Node) -> Result<(FromItem, Item, Vec<Item>)> {
393        match node {
394            Node::RangeVar(rv) => {
395                let item = self.relation(rv)?;
396                let index = self.scope.entries[item.entry].relation.unwrap_or_default();
397                Ok((FromItem::Relation(index), item.clone(), vec![item]))
398            }
399            Node::JoinExpr(j) => self.join(j),
400            Node::RangeSubselect(r) if r.subquery.as_ref().is_some_and(crate::rules::is_write) => {
401                self.rule_relation(r)
402            }
403            Node::RangeSubselect(r) => {
404                let item = self.range_subselect(r)?;
405                let index = self.scope.entries[item.entry].relation.unwrap_or_default();
406                Ok((FromItem::Relation(index), item.clone(), vec![item]))
407            }
408            Node::RangeFunction(r) => {
409                let item = self.range_function(r)?;
410                let index = self.scope.entries[item.entry].relation.unwrap_or_default();
411                Ok((FromItem::Relation(index), item.clone(), vec![item]))
412            }
413            Node::RangeTableSample(r) => self.range_table_sample(r),
414            Node::RangeTableFunc(_) => Err(not_yet("XMLTABLE", None)),
415            Node::JsonTable(jt) => {
416                let item = self.range_json_table(jt)?;
417                let index = self.scope.entries[item.entry].relation.unwrap_or_default();
418                Ok((FromItem::Relation(index), item.clone(), vec![item]))
419            }
420            _ => Err(Error::internal("unrecognized node type in FROM")),
421        }
422    }
423
424    /// The part of `transformFromClauseItem` for `TABLESAMPLE`: the relation must be a table or a materialized view, and the clause goes on its entry.
425    fn range_table_sample(&mut self, r: &RangeTableSample) -> Result<(FromItem, Item, Vec<Item>)> {
426        let node =
427            r.relation.as_ref().ok_or_else(|| Error::internal("a TABLESAMPLE with no relation"))?;
428        let (item, top, namespace) = self.transform_from_item(node)?;
429        let index = self.scope.entries[top.entry].relation.unwrap_or_default();
430        let relation = &self.scope.relations[index];
431        if relation.oid == 0
432            || relation.cte.is_some()
433            || !matches!(crate::ddl::relkind(self.env, relation.oid), b'r' | b'm' | b'p')
434        {
435            let at = match node {
436                Node::RangeVar(rv) => place(rv.location),
437                _ => None,
438            };
439            return Err(Error::new(
440                SqlState::FEATURE_NOT_SUPPORTED,
441                "TABLESAMPLE clause can only be applied to tables and materialized views",
442            )
443            .at_opt(at));
444        }
445        // The arguments cannot see the parts of `FROM` before the relation, because `p_lateral_active` stays false.
446        let before = self.scope.lateral.len();
447        let hidden = std::mem::take(&mut self.scope.namespace);
448        self.scope.lateral.extend(hidden.into_iter().map(|item| (item, true)));
449        let active = std::mem::replace(&mut self.scope.lateral_active, false);
450        let sample = self.table_sample(r);
451        self.scope.lateral_active = active;
452        self.scope.namespace =
453            self.scope.lateral.split_off(before).into_iter().map(|(item, _)| item).collect();
454        self.scope.relations[index].tablesample = Some(sample?);
455        Ok((item, top, namespace))
456    }
457
458    /// `transformRangeTableSample`: the handler of the method, which has the name of the method, one argument of type `internal` and the result type `tsm_handler`, and the arguments with the types of the method.
459    fn table_sample(&mut self, r: &RangeTableSample) -> Result<TableSample> {
460        let at = place(r.location);
461        let names: Vec<&str> = fields(&r.method).into_iter().flatten().collect();
462        let shown = names.join(".");
463        let missing = || {
464            Error::new(
465                SqlState::UNDEFINED_OBJECT,
466                format!("tablesample method {shown} does not exist"),
467            )
468            .at_opt(at)
469        };
470        let (schema, name) = match names.as_slice() {
471            [schema, name] => (Some(self.schema(schema).ok_or_else(missing)?), *name),
472            _ => self.split_name(&names, None)?,
473        };
474        let schemas = match schema {
475            Some(namespace) => vec![namespace],
476            None => self.path.clone(),
477        };
478        let found = schemas.iter().find_map(|&namespace| {
479            let user = self.env.catalog().and_then(|c| {
480                c.functions()
481                    .find(|f| {
482                        f.namespace == namespace && f.name == name && f.argtypes == [oid::INTERNAL]
483                    })
484                    .map(|f| (f.oid, f.rettype))
485            });
486            user.or_else(|| {
487                builtin::procs_named(name)
488                    .find(|p| p.namespace == namespace && p.argtypes == [oid::INTERNAL])
489                    .map(|p| (p.oid, p.rettype))
490            })
491        });
492        let Some((handler, rettype)) = found else { return Err(missing()) };
493        if rettype != oid::TSM_HANDLER {
494            return Err(Error::new(
495                SqlState::WRONG_OBJECT_TYPE,
496                format!("function {shown} must return type tsm_handler"),
497            )
498            .at_opt(at));
499        }
500        // `GetTsmRoutine`: the methods `system` and `bernoulli` take the percentage of the rows as `real`, and accept `REPEATABLE`.
501        let params = [oid::FLOAT4];
502        if r.args.len() != params.len() {
503            let count = params.len();
504            let noun = if count == 1 { "argument" } else { "arguments" };
505            return Err(Error::new(
506                SqlState::INVALID_TABLESAMPLE_ARGUMENT,
507                format!("tablesample method {shown} requires {count} {noun}, not {}", r.args.len()),
508            )
509            .at_opt(at));
510        }
511        let mut args = Vec::with_capacity(params.len());
512        for (arg, &ty) in r.args.iter().zip(&params) {
513            let expr = self.with_kind(Kind::FromFunction, |a| a.transform(arg.as_ref()))?;
514            args.push(self.coerce_to_specific(expr, ty, "TABLESAMPLE")?);
515        }
516        let repeatable = match &r.repeatable {
517            Some(node) => {
518                let expr = self.with_kind(Kind::FromFunction, |a| a.transform(Some(node)))?;
519                Some(self.coerce_to_specific(expr, oid::FLOAT8, "REPEATABLE")?)
520            }
521            None => None,
522        };
523        Ok(TableSample { handler, args, repeatable })
524    }
525
526    /// A relation of `FROM` with a name: a query of `WITH`, a transition table of a trigger, or a table of the catalog.
527    fn relation(&mut self, rv: &RangeVar) -> Result<Item> {
528        if let Some(item) = self.cte_reference(rv)? {
529            return Ok(item);
530        }
531        if let Some(item) = self.transition_reference(rv)? {
532            return Ok(item);
533        }
534        self.catalog_relation(rv, false)
535    }
536
537    /// `addRangeTableEntry` for a table of the catalog: the entry and its namespace item. The target table of a write is a table of the catalog also when a query of `WITH` has its name, as `setTargetTable` finds it.
538    ///
539    /// The relation needs `SELECT`, or for the target table of a write with `target`, the privileges that [`Analyzer::target_table`] gave it.
540    fn catalog_relation(&mut self, rv: &RangeVar, target: bool) -> Result<Item> {
541        if target && let Some(item) = self.auto_view_item(rv)? {
542            return Ok(item);
543        }
544        let at = place(rv.location);
545        let name = rv.relname.as_deref().unwrap_or_default();
546        let oid = self.lookup_relation(rv)?.ok_or_else(|| {
547            let error = match &rv.schemaname {
548                Some(schema) => Error::new(
549                    SqlState::UNDEFINED_TABLE,
550                    format!("relation \"{schema}.{name}\" does not exist"),
551                ),
552                None if self.future_cte(name) => Error::new(
553                    SqlState::UNDEFINED_TABLE,
554                    format!("relation \"{name}\" does not exist"),
555                )
556                .with_detail(format!(
557                    "There is a WITH item named \"{name}\", but it cannot be referenced from this part of the query."
558                ))
559                .with_hint(
560                    "Use WITH RECURSIVE, or re-order the WITH items to remove forward references.",
561                ),
562                None => Error::new(
563                    SqlState::UNDEFINED_TABLE,
564                    format!("relation \"{name}\" does not exist"),
565                ),
566            };
567            error.at_opt(at)
568        })?;
569        let columns = self.open_relation(oid, name, at)?;
570        let perm = if target { self.target_perm } else { Some(self.add_perm(oid, ACL_SELECT)) };
571        let subquery = match self.view_query_perms(oid)? {
572            // The target of a write is a view with a trigger `INSTEAD OF`, which reads no table of the view.
573            Some((mut query, perms)) => {
574                if target {
575                    crate::perm::forget(&mut query);
576                } else {
577                    self.add_view_perms(oid, &mut query, perms);
578                }
579                Some(Box::new(query))
580            }
581            None => None,
582        };
583        let alias = rv.alias.as_deref();
584        let refname = alias.and_then(|a| a.aliasname.as_deref()).unwrap_or(name).to_string();
585        let mut relation = Relation::new(oid, columns, subquery, None, None);
586        relation.only = !rv.inh;
587        relation.perm = perm;
588        self.add_relation(relation, refname, alias)
589    }
590
591    /// `ApplyRetrieveRule`: the query of a view of the user, which takes the place of the view as a subquery, or `None` for a relation that is not a view. A materialized view gives its rows from its heap, so its query takes its place only for the `INSERT` that fills it, as `refresh_matview_datafill` runs the query.
592    pub(crate) fn view_query(&self, oid: u32) -> Result<Option<crate::Query>> {
593        Ok(self.view_query_perms(oid)?.map(|(query, _)| query))
594    }
595
596    /// [`Analyzer::view_query`] with the privileges that the query of the view needs.
597    fn view_query_perms(&self, oid: u32) -> Result<Option<(crate::Query, Vec<PermInfo>)>> {
598        let Some(rel) = self.env.catalog().and_then(|c| c.relation(oid)) else { return Ok(None) };
599        if rel.kind == RelKind::MatView && self.env.filling() != oid {
600            return Ok(None);
601        }
602        self.stored_query_perms(oid)
603    }
604
605    /// The query of a view or of a materialized view of the user, or `None` for a relation that has no query. The analyzer reads the statement that made the view again, with the schemas of `search_path` of that statement. An error in the query of the view has no position, and the warnings of the query go.
606    pub(crate) fn stored_query(&self, oid: u32) -> Result<Option<crate::Query>> {
607        Ok(self.stored_query_perms(oid)?.map(|(query, _)| query))
608    }
609
610    /// [`Analyzer::stored_query`] with the privileges that the query needs.
611    pub(crate) fn stored_query_perms(
612        &self,
613        oid: u32,
614    ) -> Result<Option<(crate::Query, Vec<PermInfo>)>> {
615        let Some(rel) = self.env.catalog().and_then(|c| c.relation(oid)) else { return Ok(None) };
616        let Some(view) = &rel.view else { return Ok(None) };
617        if self.views.contains(&oid) {
618            return Err(Error::new(
619                SqlState::INVALID_OBJECT_DEFINITION,
620                format!("infinite recursion detected in rules for relation \"{}\"", rel.name),
621            ));
622        }
623        let (list, _) = rupg_sql::parse(&view.text).map_err(Error::from)?;
624        let query = list.iter().flatten().find_map(|node| match node {
625            Node::RawStmt(raw) => match raw.stmt.as_ref() {
626                Some(Node::ViewStmt(stmt)) => stmt.query.as_ref(),
627                Some(Node::CreateTableAsStmt(stmt)) => stmt.query.as_ref(),
628                _ => None,
629            },
630            _ => None,
631        });
632        let Some(Node::SelectStmt(select)) = query else {
633            return Err(Error::internal("the query of a view is not a SELECT"));
634        };
635        let mut an = Analyzer::new(self.env, &crate::Params::default());
636        an.set_path(&view.path);
637        an.views.clone_from(&self.views);
638        an.views.push(oid);
639        let mut query = an.select(select).map_err(|error| error.with_position(None))?;
640        query.funcs = an.funcs;
641        Ok(Some((query, an.perms)))
642    }
643
644    /// `transformRangeSubselect` and `addRangeTableEntryForSubquery`: a subquery in `FROM` and its namespace item. With no alias, the name of the entry is `unnamed_subquery`, and a qualified name cannot use it.
645    fn range_subselect(&mut self, r: &RangeSubselect) -> Result<Item> {
646        let query = self.subquery_in_from(r.subquery.as_ref(), r.lateral)?;
647        let columns = query
648            .targets
649            .iter()
650            .filter(|t| !t.junk)
651            .map(|t| Column {
652                name: t.name.clone(),
653                ty: t.expr.ty,
654                typmod: t.expr.typmod,
655                not_null: false,
656            })
657            .collect();
658        let alias = r.alias.as_deref();
659        let refname = alias.and_then(|a| a.aliasname.as_deref()).unwrap_or("unnamed_subquery");
660        let mut relation = Relation::new(0, columns, Some(Box::new(query)), None, None);
661        relation.lateral = r.lateral;
662        let mut item = self.add_relation(relation, refname.to_string(), alias)?;
663        item.rel_visible = alias.is_some();
664        Ok(item)
665    }
666
667    /// The subquery `*rule*` of an action of a rule, which [`crate::rules`] makes: the rows that the statement of the user writes, with no write. The names `old` and `new` give the old row and the new row of each row, as `rewriteRuleAction` puts the target table of the statement and its new values in the action.
668    fn rule_relation(&mut self, r: &RangeSubselect) -> Result<(FromItem, Item, Vec<Item>)> {
669        let Some(stmt) = r.subquery.as_ref() else {
670            return Err(Error::internal("a rule subquery with no statement"));
671        };
672        let perm = self.target_perm;
673        let query = self.sub_level(false, |analyzer| {
674            analyzer.rule.rows = true;
675            let query = match stmt {
676                Node::InsertStmt(s) => analyzer.insert(s),
677                Node::UpdateStmt(s) => analyzer.update(s),
678                Node::DeleteStmt(s) => analyzer.delete(s),
679                _ => Err(Error::internal("a rule subquery that is not a write")),
680            };
681            analyzer.rule.rows = false;
682            query
683        });
684        self.target_perm = perm;
685        let query = query?;
686        let table = std::mem::take(&mut self.rule.columns);
687        let columns = query
688            .targets
689            .iter()
690            .map(|t| Column {
691                name: t.name.clone(),
692                ty: t.expr.ty,
693                typmod: t.expr.typmod,
694                not_null: false,
695            })
696            .collect();
697        let relation = Relation::new(0, columns, Some(Box::new(query)), None, None);
698        let mut top = self.add_relation(relation, "*rule*".to_string(), None)?;
699        top.rel_visible = false;
700        top.cols_visible = false;
701        let index = self.scope.entries[top.entry].relation.unwrap_or_default();
702        let width = table.len();
703        let rows: &[(&str, usize)] = match stmt {
704            Node::InsertStmt(_) => &[("new", 0)],
705            Node::UpdateStmt(_) => &[("old", width), ("new", 0)],
706            _ => &[("old", 0)],
707        };
708        let mut items = Vec::with_capacity(rows.len());
709        for &(name, offset) in rows {
710            let row = crate::rules::relation_row(&table, index, offset);
711            items.push(self.rule_item(name, crate::rules::named_row(&table, row)));
712        }
713        Ok((FromItem::Relation(index), top, items))
714    }
715
716    /// A namespace item `old` or `new` of a rule, whose columns are the values of `columns`: a qualified name can use it, and an unqualified name cannot.
717    pub(crate) fn rule_item(&mut self, name: &str, columns: Vec<(String, Expr)>) -> Item {
718        let entry = self.scope.entries.len();
719        self.scope.entries.push(Entry {
720            name: name.to_string(),
721            aliased: true,
722            columns: columns.iter().map(|(n, _)| n.clone()).collect(),
723            relation: None,
724            oid: 0,
725        });
726        Item {
727            entry,
728            name: name.to_string(),
729            columns,
730            rel_visible: true,
731            cols_visible: false,
732            hidden: 0,
733            returning: false,
734        }
735    }
736
737    /// Adds the item to the namespace of this query.
738    pub(crate) fn push_item(&mut self, item: Item) {
739        self.scope.namespace.push(item);
740    }
741
742    /// `parse_sub_analyze` for a subquery in `FROM`: the subquery sees the queries outside this query. It sees the parts of `FROM` before it only with `LATERAL`.
743    fn subquery_in_from(&mut self, node: Option<&Node>, lateral: bool) -> Result<crate::Query> {
744        let Some(Node::SelectStmt(stmt)) = node else {
745            return Err(Error::internal("a subquery in FROM that is not SelectStmt"));
746        };
747        self.sub_select(stmt, lateral)
748    }
749
750    /// `parse_sub_analyze`: the query tree of a subquery of this query, which sees the queries outside this query. It sees the parts of `FROM` of this query only with `LATERAL`.
751    pub(crate) fn sub_select(&mut self, stmt: &SelectStmt, lateral: bool) -> Result<crate::Query> {
752        self.sub_level(lateral, |analyzer| analyzer.select(stmt))
753    }
754
755    /// The analysis `f` of a statement in a new level below this query, as `parse_sub_analyze` makes a `ParseState` with this query as its parent.
756    pub(crate) fn sub_level(
757        &mut self,
758        lateral: bool,
759        f: impl FnOnce(&mut Self) -> Result<crate::Query>,
760    ) -> Result<crate::Query> {
761        let mut scope = std::mem::take(&mut self.scope);
762        let before = scope.lateral.len();
763        let hidden = std::mem::take(&mut scope.namespace);
764        scope.lateral.extend(hidden.into_iter().map(|item| (item, true)));
765        let active = std::mem::replace(&mut scope.lateral_active, lateral);
766        self.outer.push(scope);
767        let kind = std::mem::replace(&mut self.kind, Kind::Other);
768        let has_aggs = std::mem::replace(&mut self.has_aggs, false);
769        self.outer_kinds.push((None, has_aggs));
770        let srfs = self.srfs;
771        let result = f(self);
772        self.srfs = srfs;
773        self.has_aggs = self.outer_kinds.pop().map_or(has_aggs, |(_, has_aggs)| has_aggs);
774        self.kind = kind;
775        let mut scope = self.outer.pop().unwrap_or_default();
776        scope.lateral_active = active;
777        scope.namespace =
778            scope.lateral.split_off(before).into_iter().map(|(item, _)| item).collect();
779        self.scope = scope;
780        result
781    }
782
783    /// `transformRangeFunction` and `addRangeTableEntryForFunction`: a function in `FROM`, or the functions of `ROWS FROM`, and its namespace item. The arguments can read the parts of `FROM` before the function, also with no `LATERAL`.
784    fn range_function(&mut self, r: &RangeFunction) -> Result<Item> {
785        let before = self.scope.lateral.len();
786        let hidden = std::mem::take(&mut self.scope.namespace);
787        self.scope.lateral.extend(hidden.into_iter().map(|item| (item, true)));
788        let active = std::mem::replace(&mut self.scope.lateral_active, true);
789        let calls = self.function_calls(r);
790        self.scope.lateral_active = active;
791        self.scope.namespace =
792            self.scope.lateral.split_off(before).into_iter().map(|(item, _)| item).collect();
793        let mut calls = calls?;
794        if let Some(Some(Node::ColumnDef(first))) = r.coldeflist.first() {
795            let at = place(first.location);
796            if calls.len() != 1 {
797                let (message, hint) = if r.is_rowsfrom {
798                    (
799                        "ROWS FROM() with multiple functions cannot have a column definition list",
800                        "Put a separate column definition list for each function inside ROWS FROM().",
801                    )
802                } else {
803                    (
804                        "UNNEST() with multiple arguments cannot have a column definition list",
805                        "Use separate UNNEST() calls inside ROWS FROM(), and attach a column definition list to each one.",
806                    )
807                };
808                return Err(Error::new(SqlState::SYNTAX_ERROR, message).with_hint(hint).at_opt(at));
809            }
810            if r.ordinality {
811                return Err(Error::new(
812                    SqlState::SYNTAX_ERROR,
813                    "WITH ORDINALITY cannot be used with a column definition list",
814                )
815                .with_hint("Put the column definition list inside ROWS FROM().")
816                .at_opt(at));
817            }
818            calls[0].2 = &r.coldeflist;
819        }
820        let alias = r.alias.as_deref();
821        let first = calls.first().map(|c| c.1.clone()).unwrap_or_default();
822        let refname = alias.and_then(|a| a.aliasname.as_deref()).map_or(first, str::to_string);
823        let count = calls.len();
824        let mut columns = Vec::new();
825        let mut out = Vec::with_capacity(count);
826        let mut defined = Vec::with_capacity(count);
827        for (expr, name, coldefs) in calls {
828            let given = self.function_columns(&expr, &name, coldefs, alias, count)?;
829            defined.push(!coldefs.is_empty());
830            out.push((expr, given.len()));
831            columns.extend(given);
832        }
833        if r.ordinality {
834            let name = "ordinality".to_string();
835            columns.push(Column { name, ty: oid::INT8, typmod: -1, not_null: false });
836        }
837        let function = FromFunction { calls: out, ordinality: r.ordinality, coldefs: defined };
838        let mut relation = Relation::new(0, columns, None, Some(function), None);
839        relation.lateral = r.lateral;
840        self.add_relation(relation, refname, alias)
841    }
842
843    /// `transformJsonTable` and `addRangeTableEntryForTableFunc`: `JSON_TABLE` and its namespace item. The expressions can read the parts of `FROM` before it, also with no `LATERAL`.
844    fn range_json_table(&mut self, jt: &JsonTable) -> Result<Item> {
845        let before = self.scope.lateral.len();
846        let hidden = std::mem::take(&mut self.scope.namespace);
847        self.scope.lateral.extend(hidden.into_iter().map(|item| (item, true)));
848        let active = std::mem::replace(&mut self.scope.lateral_active, true);
849        let table = self.with_kind(Kind::FromFunction, |a| a.json_table(jt));
850        self.scope.lateral_active = active;
851        self.scope.namespace =
852            self.scope.lateral.split_off(before).into_iter().map(|(item, _)| item).collect();
853        let (call, table_columns) = table?;
854        let alias = jt.alias.as_deref();
855        if let Some(alias) = alias {
856            let given = alias_columns(alias).len();
857            if given > table_columns.len() {
858                return Err(Error::new(
859                    SqlState::INVALID_COLUMN_REFERENCE,
860                    format!(
861                        "JSON_TABLE function has {} columns available but {given} columns specified",
862                        table_columns.len()
863                    ),
864                ));
865            }
866        }
867        let refname = alias
868            .and_then(|a| a.aliasname.as_deref())
869            .map_or_else(|| "json_table".to_string(), str::to_string);
870        let columns: Vec<Column> = table_columns
871            .into_iter()
872            .map(|c| Column { name: c.name, ty: c.ty, typmod: c.typmod, not_null: false })
873            .collect();
874        let width = columns.len();
875        let function =
876            FromFunction { calls: vec![(call, width)], ordinality: false, coldefs: vec![false] };
877        let mut relation = Relation::new(0, columns, None, Some(function), None);
878        relation.lateral = jt.lateral;
879        self.add_relation(relation, refname, alias)
880    }
881
882    /// The calls of a function in `FROM`, each with the name that `FigureColname` gives it and its column definition list. A call of `unnest` with more than one argument and no other parts becomes a call of `pg_catalog.unnest` for each argument, as `ROWS FROM` does.
883    fn function_calls<'n>(&mut self, r: &'n RangeFunction) -> Result<Vec<FunctionCall<'n>>> {
884        let mut out = Vec::with_capacity(r.functions.len());
885        for pair in &r.functions {
886            let Some(Node::List(pair)) = pair else {
887                return Err(Error::internal("a function in FROM that is not a pair"));
888            };
889            let node = pair.first().and_then(Option::as_ref);
890            let coldefs: &[Option<Node>] = match pair.get(1) {
891                Some(Some(Node::List(list))) => list,
892                _ => &[],
893            };
894            if let Some(Node::FuncCall(fc)) = node
895                && fc.funcname.len() == 1
896                && fields(&fc.funcname) == [Some("unnest")]
897                && fc.args.len() > 1
898                && fc.agg_order.is_empty()
899                && fc.agg_filter.is_none()
900                && fc.over.is_none()
901                && !fc.agg_star
902                && !fc.agg_distinct
903                && !fc.func_variadic
904                && coldefs.is_empty()
905            {
906                for arg in &fc.args {
907                    let call = FuncCall {
908                        funcname: vec![
909                            Some(Node::String("pg_catalog".into())),
910                            Some(Node::String("unnest".into())),
911                        ],
912                        args: vec![arg.clone()],
913                        funcformat: CoercionForm::COERCE_EXPLICIT_CALL,
914                        location: fc.location,
915                        ..FuncCall::default()
916                    };
917                    let call = Node::FuncCall(Box::new(call));
918                    let expr = self.function_expr(Some(&call))?;
919                    out.push((expr, figure_colname(Some(&call)), &[][..]));
920                }
921                continue;
922            }
923            let expr = self.function_expr(node)?;
924            if !coldefs.is_empty()
925                && let Some(Some(Node::ColumnDef(first))) = r.coldeflist.first()
926            {
927                return Err(Error::new(
928                    SqlState::SYNTAX_ERROR,
929                    "multiple column definition lists are not allowed for the same function",
930                )
931                .at_opt(place(first.location)));
932            }
933            out.push((expr, figure_colname(node), coldefs));
934        }
935        Ok(out)
936    }
937
938    /// The expression of a function in `FROM`. A set-returning function can only be at the top, because `nodeFunctionscan.c` calls only that function as a set.
939    fn function_expr(&mut self, node: Option<&Node>) -> Result<Expr> {
940        let expr = self.with_kind(Kind::FromFunction, |a| a.transform(node))?;
941        let retset = |e: &Expr| match &e.kind {
942            ExprKind::Func(f) => builtin::proc_by_oid(f.oid).is_some_and(|p| p.retset),
943            _ => false,
944        };
945        let mut nested = |e: &Expr, depth: usize| (depth == 0 && retset(e)).then_some(e.location);
946        let found = match &expr.kind {
947            ExprKind::Func(f) if retset(&expr) => {
948                f.args.iter().find_map(|a| a.find(0, &mut nested))
949            }
950            _ => expr.find(0, &mut nested),
951        };
952        if let Some(at) = found {
953            return Err(Error::new(
954                SqlState::FEATURE_NOT_SUPPORTED,
955                "set-returning functions must appear at top level of FROM",
956            )
957            .at_opt(at));
958        }
959        Ok(expr)
960    }
961
962    /// `get_expr_result_type` and the column definition list of `addRangeTableEntryForFunction`: the columns of one call of a function in `FROM`. A function with two or more `OUT` parameters gives a column for each, a function that gives `record` takes its columns from the column definition list, and a function of another type gives one column.
963    fn function_columns(
964        &mut self,
965        expr: &Expr,
966        name: &str,
967        coldefs: &[Option<Node>],
968        alias: Option<&Alias>,
969        count: usize,
970    ) -> Result<Vec<Column>> {
971        let at = coldefs.first().and_then(|c| match c {
972            Some(Node::ColumnDef(def)) => place(def.location),
973            _ => None,
974        });
975        if let ExprKind::Func(f) = &expr.kind
976            && expr.ty == oid::RECORD
977            && let Some(columns) = crate::record::out_columns(f)?
978        {
979            if !coldefs.is_empty() {
980                return Err(Error::new(
981                    SqlState::SYNTAX_ERROR,
982                    "a column definition list is redundant for a function with OUT parameters",
983                )
984                .at_opt(at));
985            }
986            return Ok(columns);
987        }
988        let proc = match &expr.kind {
989            ExprKind::Func(f) => builtin::proc_by_oid(f.oid),
990            _ => None,
991        };
992        // The OUT, INOUT and TABLE parameters, as `build_function_result_tupdesc_d` reads them.
993        let mut outs: Vec<(Option<&str>, u32)> = Vec::new();
994        if let Some(p) = proc
995            && let (Some(types), Some(modes)) = (p.allargtypes, p.argmodes)
996        {
997            for (i, (ty, mode)) in types.iter().zip(modes).enumerate() {
998                if matches!(mode, b'o' | b'b' | b't') {
999                    let named =
1000                        p.argnames.and_then(|n| n.get(i)).copied().filter(|n| !n.is_empty());
1001                    outs.push((named, *ty));
1002                }
1003            }
1004        }
1005        let row = types::row(expr.ty);
1006        if expr.ty == oid::RECORD {
1007            if coldefs.is_empty() {
1008                return Err(Error::new(
1009                    SqlState::SYNTAX_ERROR,
1010                    "a column definition list is required for functions returning \"record\"",
1011                )
1012                .at_opt(expr.place()));
1013            }
1014            return self.column_definitions(coldefs);
1015        }
1016        if row.is_some_and(|r| r.kind == b'c') {
1017            if !coldefs.is_empty() {
1018                return Err(Error::new(
1019                    SqlState::SYNTAX_ERROR,
1020                    "a column definition list is redundant for a function returning a named composite type",
1021                )
1022                .at_opt(at));
1023            }
1024            // `TYPEFUNC_COMPOSITE`: a column for each attribute of the type.
1025            return self
1026                .row_columns(expr.ty)
1027                .ok_or_else(|| Error::internal("a composite type with no relation"));
1028        }
1029        if !coldefs.is_empty() {
1030            return Err(Error::new(
1031                SqlState::SYNTAX_ERROR,
1032                "a column definition list is only allowed for functions returning \"record\"",
1033            )
1034            .at_opt(at));
1035        }
1036        if row.is_some_and(|r| r.kind == b'p') && !matches!(expr.ty, oid::VOID | oid::CSTRING) {
1037            return Err(Error::new(
1038                SqlState::DATATYPE_MISMATCH,
1039                format!(
1040                    "function \"{name}\" in FROM has unsupported return type {}",
1041                    types::name(expr.ty)
1042                ),
1043            )
1044            .at_opt(expr.place()));
1045        }
1046        // chooseScalarFunctionAlias: the name of the one OUT parameter, or else the alias of a single function, or else the name of the function.
1047        let column = match outs.as_slice() {
1048            [(Some(n), _)] => (*n).to_string(),
1049            _ => match alias.and_then(|a| a.aliasname.as_deref()) {
1050                Some(a) if count == 1 => a.to_string(),
1051                _ => name.to_string(),
1052            },
1053        };
1054        Ok(vec![Column { name: column, ty: expr.ty, typmod: expr.typmod, not_null: false }])
1055    }
1056
1057    /// The columns of a column definition list, with the checks of `CheckAttributeNamesTypes`: no name twice, and no pseudo-type other than `record` and `record[]`.
1058    fn column_definitions(&mut self, coldefs: &[Option<Node>]) -> Result<Vec<Column>> {
1059        let mut columns: Vec<Column> = Vec::with_capacity(coldefs.len());
1060        for def in coldefs {
1061            let Some(Node::ColumnDef(def)) = def else {
1062                return Err(Error::internal("a column definition that is not ColumnDef"));
1063            };
1064            let name = def.colname.as_deref().unwrap_or_default().to_string();
1065            let type_name =
1066                def.typeName.as_deref().ok_or_else(|| Error::internal("a column with no type"))?;
1067            if type_name.setof {
1068                return Err(Error::new(
1069                    SqlState::INVALID_TABLE_DEFINITION,
1070                    format!("column \"{name}\" cannot be declared SETOF"),
1071                )
1072                .at_opt(place(def.location)));
1073            }
1074            let (ty, typmod) = self.type_name(type_name)?;
1075            columns.push(Column { name, ty, typmod, not_null: false });
1076        }
1077        for (i, column) in columns.iter().enumerate() {
1078            if columns[..i].iter().any(|c| c.name == column.name) {
1079                return Err(Error::new(
1080                    SqlState::DUPLICATE_COLUMN,
1081                    format!("column name \"{}\" specified more than once", column.name),
1082                ));
1083            }
1084        }
1085        for column in &columns {
1086            if !matches!(column.ty, oid::RECORD | oid::RECORD_ARRAY) {
1087                crate::ddl::check_attribute_type(&column.name, column.ty, false)?;
1088            }
1089        }
1090        Ok(columns)
1091    }
1092
1093    /// `buildNSItemFromLists`: adds a relation to the range table with the name `refname`, and gives its namespace item. The names of the alias replace the first names of the columns.
1094    pub(crate) fn add_relation(
1095        &mut self,
1096        relation: Relation,
1097        refname: String,
1098        alias: Option<&Alias>,
1099    ) -> Result<Item> {
1100        let columns = &relation.columns;
1101        let mut colnames: Vec<String> = columns.iter().map(|c| c.name.clone()).collect();
1102        // A dropped column of a table keeps its place in the range table, but it has no name and the alias does not name it.
1103        let dropped: Vec<bool> =
1104            columns.iter().map(|c| relation.of_table() && c.is_dropped()).collect();
1105        if let Some(alias) = alias {
1106            let given = alias_columns(alias);
1107            let live = dropped.iter().filter(|&&d| !d).count();
1108            if given.len() > live {
1109                return Err(Error::new(
1110                    SqlState::INVALID_COLUMN_REFERENCE,
1111                    format!(
1112                        "table \"{refname}\" has {live} columns available but {} columns specified",
1113                        given.len()
1114                    ),
1115                ));
1116            }
1117            let slots = colnames.iter_mut().zip(&dropped).filter(|(_, d)| !**d);
1118            for ((slot, _), name) in slots.zip(given) {
1119                *slot = name;
1120            }
1121        }
1122        let index = self.scope.relations.len();
1123        let exprs: Vec<(String, Expr)> = colnames
1124            .iter()
1125            .zip(columns)
1126            .enumerate()
1127            .filter(|&(i, _)| !dropped[i])
1128            .map(|(i, (n, c))| {
1129                let attnum = i16::try_from(i + 1).unwrap_or(i16::MAX);
1130                let var = Var { relation: index, attnum, levels_up: 0 };
1131                let mut expr = Expr::new(ExprKind::Var(var), c.ty);
1132                expr.typmod = c.typmod;
1133                (n.clone(), expr)
1134            })
1135            .collect();
1136        let oid = relation.oid;
1137        let mut relation = relation;
1138        relation.name.clone_from(&refname);
1139        relation.alias = alias.map(alias_columns);
1140        self.scope.relations.push(relation);
1141        let entry = self.scope.entries.len();
1142        self.scope.entries.push(Entry {
1143            name: refname.clone(),
1144            aliased: alias.is_some(),
1145            columns: colnames,
1146            relation: Some(index),
1147            oid,
1148        });
1149        Ok(Item {
1150            entry,
1151            name: refname,
1152            columns: exprs,
1153            rel_visible: true,
1154            cols_visible: true,
1155            hidden: 0,
1156            returning: false,
1157        })
1158    }
1159
1160    /// `addRangeTableEntryForValues` and `addNSItemToQuery`: adds the relation of a `VALUES` list with the name `*VALUES*`, and gives its index and its columns.
1161    pub(crate) fn add_values(
1162        &mut self,
1163        relation: Relation,
1164    ) -> Result<(usize, Vec<(String, Expr)>)> {
1165        let item = self.add_relation(relation, "*VALUES*".to_string(), None)?;
1166        let index = self.scope.entries[item.entry].relation.unwrap_or_default();
1167        let columns = item.columns.clone();
1168        self.scope.namespace.push(item);
1169        Ok((index, columns))
1170    }
1171
1172    /// `addRangeTableEntryForJoin` and `addNSItemToQuery` for the columns of a set operation: an unqualified name in `ORDER BY` can find the columns, and a qualified name cannot. It gives the number of entries and of items before the change, for [`Analyzer::remove_columns`].
1173    pub(crate) fn add_columns(&mut self, columns: Vec<(String, Expr)>) -> (usize, usize) {
1174        let before = (self.scope.entries.len(), self.scope.namespace.len());
1175        let names = columns.iter().map(|(n, _)| n.clone()).collect();
1176        let entry = self.scope.entries.len();
1177        self.scope.entries.push(Entry {
1178            name: "unnamed_join".to_string(),
1179            aliased: false,
1180            columns: names,
1181            relation: None,
1182            oid: 0,
1183        });
1184        self.scope.namespace.push(Item {
1185            entry,
1186            name: "unnamed_join".to_string(),
1187            columns,
1188            rel_visible: false,
1189            cols_visible: true,
1190            hidden: 0,
1191            returning: false,
1192        });
1193        before
1194    }
1195
1196    /// Removes the entry and the item that [`Analyzer::add_columns`] added.
1197    pub(crate) fn remove_columns(&mut self, (entries, items): (usize, usize)) {
1198        self.scope.entries.truncate(entries);
1199        self.scope.namespace.truncate(items);
1200    }
1201
1202    /// `addNSItemForReturning`: adds the target table, which is the first relation of the scope, with the name `old` or `new` of `RETURNING`, the old row when `old` is true, for a write of `kind`. A qualified name can use the item, but an unqualified name cannot. It gives the index of the new relation.
1203    pub(crate) fn add_returning_item(
1204        &mut self,
1205        name: &str,
1206        old: bool,
1207        kind: WriteKind,
1208    ) -> Result<usize> {
1209        let target = self
1210            .scope
1211            .relations
1212            .first()
1213            .ok_or_else(|| Error::internal("RETURNING with no table"))?;
1214        let mut relation = Relation::new(target.oid, target.columns.clone(), None, None, None);
1215        relation.perm = target.perm;
1216        let index = self.scope.relations.len();
1217        let mut item = self.add_relation(relation, name.to_string(), None)?;
1218        item.cols_visible = false;
1219        item.returning = true;
1220        self.auto_view_returning(&mut item, index, Some((kind, old)))?;
1221        self.scope.namespace.push(item);
1222        Ok(index)
1223    }
1224
1225    /// The part of `transformOnConflictClause` that adds `EXCLUDED` for `ON CONFLICT DO UPDATE`: the row that the statement proposed, with the columns of the target table, which is the first relation of the scope. The entry has no system columns, as an entry of a composite type. It gives the index of the new relation.
1226    pub(crate) fn add_excluded(&mut self) -> Result<usize> {
1227        let target = self
1228            .scope
1229            .relations
1230            .first()
1231            .ok_or_else(|| Error::internal("ON CONFLICT with no table"))?;
1232        let relation = Relation::new(target.oid, target.columns.clone(), None, None, None);
1233        let index = self.scope.relations.len();
1234        let mut item = self.add_relation(relation, "excluded".to_string(), None)?;
1235        // `EXCLUDED` of an updatable view has the columns of the view.
1236        self.auto_view_returning(&mut item, index, None)?;
1237        self.scope.entries[item.entry].oid = 0;
1238        self.scope.namespace.push(item);
1239        Ok(index)
1240    }
1241
1242    /// The relations of the scope whose entries have the OID `oid`, as the relations that give the columns of an automatically updatable view.
1243    pub(crate) fn entry_relations(&self, oid: u32) -> std::collections::BTreeSet<usize> {
1244        self.scope.entries.iter().filter(|e| e.oid == oid).filter_map(|e| e.relation).collect()
1245    }
1246
1247    /// The OID of the entry of the item and the names of its columns, which are the OID and the columns of the view for the base relation of an automatically updatable view.
1248    pub(crate) fn set_entry_oid(&mut self, item: &Item, oid: u32) {
1249        let entry = &mut self.scope.entries[item.entry];
1250        entry.oid = oid;
1251        entry.columns = item.columns.iter().map(|(name, _)| name.clone()).collect();
1252    }
1253
1254    /// `setTargetTable`: a transition table of a trigger cannot be the target of a write.
1255    pub(crate) fn check_target(&self, rv: &RangeVar) -> Result<()> {
1256        let name = rv.relname.as_deref().unwrap_or_default();
1257        if rv.schemaname.is_none() && self.env.transition_table(name).is_some() {
1258            return Err(Error::new(
1259                SqlState::FEATURE_NOT_SUPPORTED,
1260                format!("relation \"{name}\" cannot be the target of a modifying statement"),
1261            ));
1262        }
1263        Ok(())
1264    }
1265
1266    /// `setTargetTable` for an `UPDATE` or a `DELETE`: the target table as the first part of `FROM`, in the namespace.
1267    pub(crate) fn target_relation(&mut self, rv: &RangeVar) -> Result<FromItem> {
1268        self.check_target(rv)?;
1269        let item = self.catalog_relation(rv, true)?;
1270        let index = self.scope.entries[item.entry].relation.unwrap_or_default();
1271        self.scope.namespace.push(item);
1272        Ok(FromItem::Relation(index))
1273    }
1274
1275    /// The part of `transformMergeStmt` that adds the target table and the source: the target table is the relation 0, and the namespace has the items of the source, then the item of the target table. It gives the part of `FROM` of the source.
1276    ///
1277    /// # Errors
1278    ///
1279    /// `42712` when the source has the name of the target table, and the errors of the source.
1280    pub(crate) fn merge_from(&mut self, rv: &RangeVar, source: &Node) -> Result<FromItem> {
1281        self.check_target(rv)?;
1282        let target = self.catalog_relation(rv, true)?;
1283        let (item, _, namespace) = self.transform_from_item(source)?;
1284        if namespace.iter().any(|other| other.name == target.name) {
1285            return Err(Error::new(
1286                SqlState::DUPLICATE_ALIAS,
1287                format!("name \"{}\" specified more than once", target.name),
1288            )
1289            .with_detail("The name is used both as MERGE target table and data source."));
1290        }
1291        self.scope.namespace.extend(namespace);
1292        self.scope.namespace.push(target);
1293        Ok(item)
1294    }
1295
1296    /// `setNamespaceForMergeWhen`: the items that a `WHEN` clause of `MERGE` can see. A clause for a source row with no target row cannot see the target table, which is the last item, and a clause for a target row with no source row cannot see the source. It gives the full namespace, which [`Analyzer::set_namespace`] puts back.
1297    pub(crate) fn merge_namespace(&mut self, target: bool, source: bool) -> Vec<Item> {
1298        let full = self.scope.namespace.clone();
1299        let Some((last, before)) = full.split_last() else { return full };
1300        self.scope.namespace = match (target, source) {
1301            (true, true) => full.clone(),
1302            (false, _) => before.to_vec(),
1303            (true, false) => vec![last.clone()],
1304        };
1305        full
1306    }
1307
1308    /// Puts back the namespace that [`Analyzer::merge_namespace`] gave.
1309    pub(crate) fn set_namespace(&mut self, namespace: Vec<Item>) {
1310        self.scope.namespace = namespace;
1311    }
1312
1313    /// Removes the last item of the namespace and keeps its entry, as `transformOnConflictClause` removes `EXCLUDED` after `SET` and `WHERE`. A name of the entry is then an error.
1314    pub(crate) fn hide_last_item(&mut self) {
1315        self.scope.namespace.pop();
1316    }
1317
1318    /// True when a table name gives an item of the scope or of a scope outside it, as `refnameNamespaceItem` finds it.
1319    pub(crate) fn has_refname(&self, name: &str) -> Result<bool> {
1320        Ok(self.item_by_name(None, name, None)?.is_some())
1321    }
1322
1323    /// The number of relations, entries and items of the scope, which [`Analyzer::truncate_scope`] goes back to.
1324    pub(crate) fn scope_size(&self) -> (usize, usize, usize) {
1325        (self.scope.relations.len(), self.scope.entries.len(), self.scope.namespace.len())
1326    }
1327
1328    /// Removes the relations, the entries and the items that the scope got after [`Analyzer::scope_size`].
1329    pub(crate) fn truncate_scope(&mut self, (relations, entries, items): (usize, usize, usize)) {
1330        self.scope.relations.truncate(relations);
1331        self.scope.entries.truncate(entries);
1332        self.scope.namespace.truncate(items);
1333    }
1334
1335    /// `addRangeTableEntryForRelation` and `addNSItemToQuery` for a table of a statement that defines an object: the expressions of the statement can use the columns and the whole row, which has the type `row_type`. Each column is a name, a type and a typmod.
1336    pub(crate) fn add_table(
1337        &mut self,
1338        oid: u32,
1339        name: &str,
1340        columns: &[(String, u32, i32)],
1341        row_type: u32,
1342    ) {
1343        if row_type != 0 {
1344            self.row_types.insert(oid, row_type);
1345        }
1346        let index = self.scope.relations.len();
1347        let exprs: Vec<(String, Expr)> = columns
1348            .iter()
1349            .enumerate()
1350            .filter(|(_, (n, ty, _))| !(n.is_empty() && *ty == 0))
1351            .map(|(i, (n, ty, typmod))| {
1352                let attnum = i16::try_from(i + 1).unwrap_or(i16::MAX);
1353                let var = Var { relation: index, attnum, levels_up: 0 };
1354                let mut expr = Expr::new(ExprKind::Var(var), *ty);
1355                expr.typmod = *typmod;
1356                (n.clone(), expr)
1357            })
1358            .collect();
1359        let columns: Vec<Column> = columns
1360            .iter()
1361            .map(|(n, ty, typmod)| Column {
1362                name: n.clone(),
1363                ty: *ty,
1364                typmod: *typmod,
1365                not_null: false,
1366            })
1367            .collect();
1368        let colnames = columns.iter().map(|c| c.name.clone()).collect();
1369        let mut relation = Relation::new(oid, columns, None, None, None);
1370        relation.name = name.to_string();
1371        self.scope.relations.push(relation);
1372        let entry = self.scope.entries.len();
1373        self.scope.entries.push(Entry {
1374            name: name.to_string(),
1375            aliased: false,
1376            columns: colnames,
1377            relation: Some(index),
1378            oid,
1379        });
1380        self.scope.namespace.push(Item {
1381            entry,
1382            name: name.to_string(),
1383            columns: exprs,
1384            rel_visible: true,
1385            cols_visible: true,
1386            hidden: 0,
1387            returning: false,
1388        });
1389    }
1390
1391    /// The range table of `transformRuleStmt`: a new scope with the relation of a rule as `old`, then as `new`. A qualified name can use the names of `visible`, and an unqualified name can use their columns only with `columns`.
1392    pub(crate) fn rule_scope(
1393        &mut self,
1394        oid: u32,
1395        name: &str,
1396        visible: [bool; 2],
1397        columns: bool,
1398    ) -> Result<()> {
1399        self.scope = Scope::default();
1400        for (refname, visible) in ["old", "new"].into_iter().zip(visible) {
1401            let alias = Alias { aliasname: Some(refname.into()), ..Alias::default() };
1402            let relation =
1403                Relation::new(oid, self.open_relation(oid, name, None)?, None, None, None);
1404            let mut item = self.add_relation(relation, refname.to_string(), Some(&alias))?;
1405            item.cols_visible = columns;
1406            if visible {
1407                self.scope.namespace.push(item);
1408            }
1409        }
1410        Ok(())
1411    }
1412
1413    /// `RangeVarGetRelid`: the OID of the relation that a name gives, or `None`. The relation can be of any kind.
1414    pub(crate) fn lookup_relation(&self, rv: &RangeVar) -> Result<Option<u32>> {
1415        let at = place(rv.location);
1416        let name = rv.relname.as_deref().unwrap_or_default();
1417        if let Some(database) = &rv.catalogname
1418            && **database != self.env.database()
1419        {
1420            return Err(Error::new(
1421                SqlState::FEATURE_NOT_SUPPORTED,
1422                format!(
1423                    "cross-database references are not implemented: \"{database}.{}.{name}\"",
1424                    rv.schemaname.as_deref().unwrap_or_default()
1425                ),
1426            )
1427            .at_opt(at));
1428        }
1429        let in_schema = |namespace: u32| {
1430            builtin::named(Named::Class)
1431                .iter()
1432                .find(|r| r.namespace == namespace && r.name == name)
1433                .map(|r| r.oid)
1434                .or_else(|| self.env.catalog()?.relation_by_name(namespace, name).map(|r| r.oid))
1435        };
1436        match &rv.schemaname {
1437            // A schema that does not exist has no relation, as RangeVarGetRelid with missing_ok gives.
1438            Some(schema) => Ok(self.schema(schema).and_then(in_schema)),
1439            None => Ok(self.temp_path.iter().find_map(|&ns| in_schema(ns))),
1440        }
1441    }
1442
1443    /// The checks of `table_open` for a relation in `FROM`, and the columns of the relation. A table of the catalog, a table of the user and a sequence of the user can be in `FROM`. An index gives `42809`, and a built-in view gives `0A000`.
1444    pub(crate) fn open_relation(
1445        &self,
1446        oid: u32,
1447        name: &str,
1448        at: Option<usize>,
1449    ) -> Result<Vec<Column>> {
1450        let index_error = || {
1451            Error::new(SqlState::WRONG_OBJECT_TYPE, format!("cannot open relation \"{name}\""))
1452                .with_detail("This operation is not supported for indexes.")
1453                .at_opt(at)
1454        };
1455        if let Some(catalog) = rupg_pgcatalog::catalog_by_oid(oid) {
1456            return Ok(catalog
1457                .columns
1458                .iter()
1459                .map(|c| Column {
1460                    name: c.name.to_string(),
1461                    ty: c.type_oid,
1462                    typmod: -1,
1463                    not_null: c.not_null,
1464                })
1465                .collect());
1466        }
1467        if let Some(rel) = self.env.catalog().and_then(|c| c.relation(oid)) {
1468            if matches!(rel.kind, RelKind::Index | RelKind::PartitionedIndex) {
1469                return Err(index_error());
1470            }
1471            return Ok(rel
1472                .columns
1473                .iter()
1474                // A dropped column keeps its place with no name and the type 0.
1475                .map(|c| Column {
1476                    name: if c.dropped { String::new() } else { c.name.clone() },
1477                    ty: c.ty,
1478                    typmod: c.typmod,
1479                    not_null: c.not_null && !c.not_null_invalid,
1480                })
1481                .collect());
1482        }
1483        if builtin_relkind(oid) == Some(b'i') {
1484            return Err(index_error());
1485        }
1486        Err(not_yet(&format!("the system relation \"{name}\""), at))
1487    }
1488
1489    /// `checkNameSpaceConflicts`: two items that the same name qualifies are an error, except two relations with no alias that are not the same relation.
1490    fn check_conflicts(&self, first: &[Item], second: &[Item]) -> Result<()> {
1491        for a in first.iter().filter(|i| i.rel_visible) {
1492            for b in second.iter().filter(|i| i.rel_visible) {
1493                if a.name != b.name {
1494                    continue;
1495                }
1496                let (ea, eb) = (&self.scope.entries[a.entry], &self.scope.entries[b.entry]);
1497                let plain = |e: &Entry| e.relation.is_some() && !e.aliased;
1498                if plain(ea) && plain(eb) && ea.oid != eb.oid {
1499                    continue;
1500                }
1501                return Err(Error::new(
1502                    SqlState::DUPLICATE_ALIAS,
1503                    format!("table name \"{}\" specified more than once", a.name),
1504                ));
1505            }
1506        }
1507        Ok(())
1508    }
1509
1510    /// The `JoinExpr` case of `transformFromClauseItem`.
1511    fn join(&mut self, j: &JoinExpr) -> Result<(FromItem, Item, Vec<Item>)> {
1512        let left_node = j.larg.as_ref().ok_or_else(|| Error::internal("a join with no left"))?;
1513        let right_node = j.rarg.as_ref().ok_or_else(|| Error::internal("a join with no right"))?;
1514        let kind = match j.jointype {
1515            JoinType::JOIN_INNER => JoinKind::Inner,
1516            JoinType::JOIN_LEFT => JoinKind::Left,
1517            JoinType::JOIN_RIGHT => JoinKind::Right,
1518            JoinType::JOIN_FULL => JoinKind::Full,
1519            _ => return Err(Error::internal("unrecognized join type")),
1520        };
1521        let (left, l_item, l_namespace) = self.transform_from_item(left_node)?;
1522        // The right side can see the left side only with LATERAL, and only for an inner or a left join.
1523        let before = self.scope.lateral.len();
1524        let lateral_ok = matches!(kind, JoinKind::Inner | JoinKind::Left);
1525        self.scope.lateral.extend(l_namespace.iter().map(|item| (item.clone(), lateral_ok)));
1526        let right = self.transform_from_item(right_node);
1527        self.scope.lateral.truncate(before);
1528        let (right, r_item, r_namespace) = right?;
1529        self.check_conflicts(&l_namespace, &r_namespace)?;
1530        let mut namespace = l_namespace;
1531        namespace.extend(r_namespace);
1532        let l_names: Vec<&str> = l_item.columns.iter().map(|(n, _)| n.as_str()).collect();
1533        let r_names: Vec<&str> = r_item.columns.iter().map(|(n, _)| n.as_str()).collect();
1534        let using: Vec<String> = if j.isNatural {
1535            l_names.iter().filter(|n| r_names.contains(n)).map(|n| (*n).to_string()).collect()
1536        } else {
1537            fields(&j.usingClause).into_iter().flatten().map(str::to_string).collect()
1538        };
1539        let mut merged: Vec<(String, Expr)> = Vec::new();
1540        let mut l_used = Vec::new();
1541        let mut r_used = Vec::new();
1542        let mut on = None;
1543        if !using.is_empty() {
1544            let mut pairs = Vec::new();
1545            for name in &using {
1546                if merged.iter().any(|(n, _)| n == name) || pairs.iter().any(|(n, _, _)| n == name)
1547                {
1548                    return Err(Error::new(
1549                        SqlState::DUPLICATE_COLUMN,
1550                        format!("column name \"{name}\" appears more than once in USING clause"),
1551                    ));
1552                }
1553                let find = |names: &[&str], side: &str| -> Result<usize> {
1554                    let mut found = None;
1555                    for (i, n) in names.iter().enumerate() {
1556                        if n == name {
1557                            if found.is_some() {
1558                                return Err(Error::new(
1559                                    SqlState::AMBIGUOUS_COLUMN,
1560                                    format!(
1561                                        "common column name \"{name}\" appears more than once in {side} table"
1562                                    ),
1563                                ));
1564                            }
1565                            found = Some(i);
1566                        }
1567                    }
1568                    found.ok_or_else(|| {
1569                        Error::new(
1570                            SqlState::UNDEFINED_COLUMN,
1571                            format!("column \"{name}\" specified in USING clause does not exist in {side} table"),
1572                        )
1573                    })
1574                };
1575                let l = find(&l_names, "left")?;
1576                let r = find(&r_names, "right")?;
1577                pairs.push((name.clone(), l, r));
1578            }
1579            // transformJoinUsingClause: `l = r` for each column, joined with AND.
1580            let mut conds = Vec::new();
1581            for (_, l, r) in &pairs {
1582                let (lv, rv) = (l_item.columns[*l].1.clone(), r_item.columns[*r].1.clone());
1583                conds.push(self.make_op(&["="], Some(lv), rv, None)?);
1584            }
1585            let cond = if conds.len() == 1 {
1586                conds.remove(0)
1587            } else {
1588                Expr::new(ExprKind::Bool(crate::expr::BoolOp::And, conds), oid::BOOL)
1589            };
1590            self.mark_select(&cond);
1591            on = Some(self.coerce_to_boolean(cond, "JOIN/USING")?);
1592            for (name, l, r) in pairs {
1593                let expr = self.merged_column(
1594                    kind,
1595                    l_item.columns[l].1.clone(),
1596                    r_item.columns[r].1.clone(),
1597                )?;
1598                merged.push((name, expr));
1599                l_used.push(l);
1600                r_used.push(r);
1601            }
1602        } else if let Some(quals) = &j.quals {
1603            // transformJoinOnClause: the condition sees only the two sides of the join.
1604            let saved = std::mem::replace(&mut self.scope.namespace, namespace.clone());
1605            let lateral = std::mem::take(&mut self.scope.lateral);
1606            let result = self.with_kind(Kind::JoinOn, |a| a.transform(Some(quals)));
1607            self.scope.namespace = saved;
1608            self.scope.lateral = lateral;
1609            on = Some(self.coerce_to_boolean(result?, "JOIN/ON")?);
1610        }
1611        let plain_using = merged.iter().all(|(_, e)| matches!(e.kind, ExprKind::Var(_)));
1612        let merged_values: Vec<Expr> = merged.iter().map(|(_, e)| e.clone()).collect();
1613        let mut columns = merged;
1614        let using_count = columns.len();
1615        let mut sources: Vec<(usize, usize)> =
1616            l_used.iter().zip(&r_used).map(|(l, r)| (l + 1, r + 1)).collect();
1617        for (i, c) in l_item.columns.iter().enumerate() {
1618            if !l_used.contains(&i) {
1619                columns.push(c.clone());
1620                sources.push((i + 1, 0));
1621            }
1622        }
1623        for (i, c) in r_item.columns.iter().enumerate() {
1624            if !r_used.contains(&i) {
1625                columns.push(c.clone());
1626                sources.push((0, i + 1));
1627            }
1628        }
1629        let alias = j.alias.as_deref();
1630        let mut aliases = Vec::new();
1631        if let Some(alias) = alias {
1632            let given = alias_columns(alias);
1633            aliases.clone_from(&given);
1634            let name = alias.aliasname.as_deref().unwrap_or_default();
1635            if given.len() > columns.len() {
1636                return Err(Error::new(
1637                    SqlState::INVALID_COLUMN_REFERENCE,
1638                    format!(
1639                        "join expression \"{name}\" has {} columns available but {} columns specified",
1640                        columns.len(),
1641                        given.len()
1642                    ),
1643                ));
1644            }
1645            for (slot, n) in columns.iter_mut().zip(given) {
1646                slot.0 = n;
1647            }
1648        }
1649        let entry = self.scope.entries.len();
1650        let name = alias.and_then(|a| a.aliasname.as_deref()).unwrap_or("unnamed_join");
1651        self.scope.entries.push(Entry {
1652            name: name.to_string(),
1653            aliased: alias.is_some(),
1654            columns: columns.iter().map(|(n, _)| n.clone()).collect(),
1655            relation: None,
1656            oid: 0,
1657        });
1658        if let Some(using_alias) = j.join_using_alias.as_deref() {
1659            let item = Item {
1660                entry,
1661                name: using_alias.aliasname.as_deref().unwrap_or_default().to_string(),
1662                columns: columns[..using_count].to_vec(),
1663                rel_visible: true,
1664                cols_visible: true,
1665                hidden: 0,
1666                returning: false,
1667            };
1668            self.check_conflicts(std::slice::from_ref(&item), &namespace)?;
1669            namespace.push(item);
1670        }
1671        if alias.is_some() {
1672            namespace.clear();
1673        } else {
1674            for item in &mut namespace {
1675                item.cols_visible = false;
1676            }
1677        }
1678        let item = Item {
1679            entry,
1680            name: name.to_string(),
1681            columns,
1682            rel_visible: alias.is_some(),
1683            cols_visible: true,
1684            hidden: 0,
1685            returning: false,
1686        };
1687        namespace.push(item.clone());
1688        let join = Join {
1689            kind,
1690            left,
1691            right,
1692            on,
1693            plain_using,
1694            using,
1695            alias: alias.and_then(|a| a.aliasname.as_deref()).map(str::to_string),
1696            using_alias: j
1697                .join_using_alias
1698                .as_deref()
1699                .and_then(|a| a.aliasname.as_deref())
1700                .map(str::to_string),
1701            merged: merged_values,
1702            columns: item.columns.clone(),
1703            aliases,
1704            sources,
1705        };
1706        Ok((FromItem::Join(Box::new(join)), item, namespace))
1707    }
1708
1709    /// `buildMergedJoinVar`: the value of a column of `USING`.
1710    fn merged_column(&mut self, kind: JoinKind, l: Expr, r: Expr) -> Result<Expr> {
1711        let pair = [l, r];
1712        let ty = self.common_type(&pair, "JOIN/USING")?;
1713        let [l, r] = pair;
1714        let typmod = if l.typmod == r.typmod { l.typmod } else { -1 };
1715        let mut fix = |e: Expr| -> Result<Expr> {
1716            if e.ty != ty {
1717                self.coerce(e, ty, typmod, Context::Implicit, None)
1718            } else if e.typmod != typmod {
1719                Ok(Expr {
1720                    kind: ExprKind::Relabel(Box::new(e), CastForm::Implicit),
1721                    ty,
1722                    typmod,
1723                    location: None,
1724                })
1725            } else {
1726                Ok(e)
1727            }
1728        };
1729        let (l, r) = (fix(l)?, fix(r)?);
1730        let is_var = |e: &Expr| matches!(e.kind, ExprKind::Var(_));
1731        Ok(match kind {
1732            JoinKind::Inner if !is_var(&l) && is_var(&r) => r,
1733            JoinKind::Inner | JoinKind::Left | JoinKind::Semi | JoinKind::Anti => l,
1734            JoinKind::Right | JoinKind::RightSemi | JoinKind::RightAnti => r,
1735            JoinKind::Full => {
1736                Expr { kind: ExprKind::Coalesce(vec![l, r]), ty, typmod: -1, location: None }
1737            }
1738        })
1739    }
1740
1741    /// `transformColumnRef`: the value of a column name.
1742    ///
1743    /// Each column that the reference reads needs `SELECT`, as `markVarForSelectPriv` marks it.
1744    pub(crate) fn column_ref(&mut self, c: &ColumnRef) -> Result<Expr> {
1745        let expr = self.resolve_column_ref(c)?;
1746        self.mark_select(&expr);
1747        Ok(expr)
1748    }
1749
1750    /// The body of [`Analyzer::column_ref`].
1751    fn resolve_column_ref(&mut self, c: &ColumnRef) -> Result<Expr> {
1752        let at = place(c.location);
1753        if self.kind == Kind::ColumnDefault {
1754            return Err(Error::new(
1755                SqlState::FEATURE_NOT_SUPPORTED,
1756                "cannot use column reference in DEFAULT expression",
1757            )
1758            .at_opt(at));
1759        }
1760        if self.kind == Kind::PartitionBound {
1761            return Err(Error::new(
1762                SqlState::FEATURE_NOT_SUPPORTED,
1763                "cannot use column reference in partition bound expression",
1764            )
1765            .at_opt(at));
1766        }
1767        let names = fields(&c.fields);
1768        // `replace_domain_constraint_value`: in a check constraint of a domain, `value` is the value that the domain checks.
1769        if let Some((ty, typmod)) = self.domain_value
1770            && names.as_slice() == [Some("value")]
1771        {
1772            return Ok(Expr { kind: ExprKind::DomainValue, ty, typmod, location: at });
1773        }
1774        let (schema, table, column) = match names.as_slice() {
1775            [Some(column)] => {
1776                if let Some(expr) = self.column_by_name(column, at)? {
1777                    return Ok(expr);
1778                }
1779                if let Some((level, item)) = self.item_by_name(None, column, at)? {
1780                    return self.whole_row(level, &item, at);
1781                }
1782                if let Some(expr) = self.function_argument(&names, at)? {
1783                    return Ok(expr);
1784                }
1785                return Err(self.missing_column(None, column, at));
1786            }
1787            [Some(table), None] => {
1788                let Some((level, item)) = self.item_by_name(None, table, at)? else {
1789                    return Err(self.missing_entry(None, table, at));
1790                };
1791                return self.whole_row(level, &item, at);
1792            }
1793            [None] => {
1794                return Err(Error::new(
1795                    SqlState::SYNTAX_ERROR,
1796                    "SELECT * with no tables specified is not valid",
1797                )
1798                .at_opt(at));
1799            }
1800            [Some(table), Some(column)] => (None, *table, *column),
1801            [Some(schema), Some(table), Some(column)] => (Some(*schema), *table, *column),
1802            [Some(database), Some(schema), Some(table), Some(column)] => {
1803                if *database != self.env.database() {
1804                    return Err(Error::new(
1805                        SqlState::FEATURE_NOT_SUPPORTED,
1806                        format!(
1807                            "cross-database references are not implemented: {}",
1808                            names.iter().map(|n| n.unwrap_or("*")).collect::<Vec<_>>().join(".")
1809                        ),
1810                    )
1811                    .at_opt(at));
1812                }
1813                (Some(*schema), *table, *column)
1814            }
1815            [.., None] if names.len() <= 4 => {
1816                return Err(Error::new(
1817                    SqlState::FEATURE_NOT_SUPPORTED,
1818                    "a row expansion with * is supported only in the target list",
1819                )
1820                .at_opt(at));
1821            }
1822            _ => {
1823                let text: Vec<&str> = names.iter().map(|f| f.unwrap_or("*")).collect();
1824                return Err(Error::new(
1825                    SqlState::SYNTAX_ERROR,
1826                    format!("improper qualified name (too many dotted names): {}", text.join(".")),
1827                )
1828                .at_opt(at));
1829            }
1830        };
1831        let Some((level, item)) = self.item_by_name(schema, table, at)? else {
1832            if let Some(expr) = self.function_argument(&names, at)? {
1833                return Ok(expr);
1834            }
1835            return Err(self.missing_entry(schema, table, at));
1836        };
1837        match self.column_in(level, &item, column, at)? {
1838            Some(expr) => Ok(expr),
1839            None => match self.function_argument(&names, at)? {
1840                Some(expr) => Ok(expr),
1841                None => Err(self.missing_column(Some(table), column, at)),
1842            },
1843        }
1844    }
1845
1846    /// `sql_fn_post_column_ref`: in the body of a function in SQL, a name that is no column can be an argument: `arg`, `function.arg`, `arg.field` or `function.arg.field`.
1847    fn function_argument(
1848        &mut self,
1849        names: &[Option<&str>],
1850        at: Option<usize>,
1851    ) -> Result<Option<Expr>> {
1852        let Some((function, args)) = &self.sql_function else { return Ok(None) };
1853        let arg = |name: &str| args.iter().position(|a| a == name);
1854        let found = match names {
1855            [Some(name)] => arg(name).map(|n| (n, None)),
1856            [Some(first), Some(name)] if *first == function.as_str() && arg(name).is_some() => {
1857                arg(name).map(|n| (n, None))
1858            }
1859            [Some(name), Some(field)] => arg(name).map(|n| (n, Some(*field))),
1860            [Some(first), Some(name), Some(field)] if *first == function.as_str() => {
1861                arg(name).map(|n| (n, Some(*field)))
1862            }
1863            _ => None,
1864        };
1865        let Some((n, field)) = found else { return Ok(None) };
1866        let number = i32::try_from(n + 1).map_err(|_| Error::internal("too many arguments"))?;
1867        let param = self.transform_param(number, at)?;
1868        match field {
1869            Some(field) => self.field_select(param, field, at).map(Some),
1870            None => Ok(Some(param)),
1871        }
1872    }
1873
1874    /// `transformWholeRowRef`: the whole row of the relation of an item, as a `Var` with the attribute number 0. Its type is the row type of the relation, or `record` for a subquery, a function and `VALUES`.
1875    fn whole_row(&self, level: usize, item: &Item, at: Option<usize>) -> Result<Expr> {
1876        let entry = &self.level(level).entries[item.entry];
1877        // `ReplaceVarsFromTargetList`: the whole row of an automatically updatable view is a row of the columns of the view, with the row type of the view.
1878        let base = entry.relation.and_then(|r| self.level(level).relations.get(r));
1879        if entry.oid != 0 && base.is_some_and(|r| r.oid != entry.oid) {
1880            let fields = item.columns.iter().map(|(_, expr)| {
1881                let mut expr = expr.clone();
1882                expr.raise(level);
1883                expr
1884            });
1885            let ty = self
1886                .row_type(entry.oid)
1887                .ok_or_else(|| not_yet("a whole-row reference to this relation", at))?;
1888            let row = ExprKind::Row(fields.collect(), CastForm::Implicit);
1889            return Ok(Expr::new(row, ty).at(at));
1890        }
1891        let Some(relation) = entry.relation else {
1892            // The alias of `USING` is an item of the entry of the join with other columns.
1893            let alias = (entry.aliased && item.name == entry.name).then(|| item.name.clone());
1894            let mut fields = Vec::with_capacity(item.columns.len());
1895            let mut names = Vec::with_capacity(item.columns.len());
1896            for (name, expr) in &item.columns {
1897                let mut expr = expr.clone();
1898                expr.raise(level);
1899                fields.push(expr);
1900                names.push(name.clone());
1901            }
1902            let row = JoinRow { alias, names, fields };
1903            return Ok(Expr::new(ExprKind::JoinRow(Box::new(row)), oid::RECORD).at(at));
1904        };
1905        let ty = match entry.oid {
1906            0 => oid::RECORD,
1907            // The table of a generation expression is new, and `check_nested_generated` gives the error for its whole row.
1908            _ if self.kind == Kind::Generated => oid::RECORD,
1909            rel => self
1910                .row_type(rel)
1911                .ok_or_else(|| not_yet("a whole-row reference to this relation", at))?,
1912        };
1913        let var = Var { relation, attnum: 0, levels_up: level };
1914        Ok(Expr::new(ExprKind::Var(var), ty).at(at))
1915    }
1916
1917    /// `get_rel_type_id`: the row type of a relation, or `None`.
1918    fn row_type(&self, rel: u32) -> Option<u32> {
1919        if let Some(catalog) = rupg_pgcatalog::catalog_by_oid(rel) {
1920            return Some(catalog.rowtype_oid).filter(|&ty| ty != 0);
1921        }
1922        if let Some(&ty) = self.row_types.get(&rel) {
1923            return Some(ty);
1924        }
1925        self.env.catalog()?.relation(rel).map(|r| r.row_type).filter(|&ty| ty != 0)
1926    }
1927
1928    /// The columns of a row type, which are the columns of its relation, or `None` for a type that is not the row type of a relation.
1929    pub(crate) fn row_columns(&self, ty: u32) -> Option<Vec<Column>> {
1930        let relid = match types::row(ty) {
1931            Some(row) if row.kind == b'c' => row.relid,
1932            Some(_) => return None,
1933            None => self.env.catalog()?.relations().find(|r| r.row_type == ty)?.oid,
1934        };
1935        let mut columns = self.open_relation(relid, "", None).ok()?;
1936        // The row type has no field for a dropped column.
1937        columns.retain(|c| !c.is_dropped());
1938        Some(columns)
1939    }
1940
1941    /// `scanNSItemForColumn` for a field of a whole-row `Var`: the column of the relation with the name, as `(t).a` is `t.a`. The error names the relation by its alias.
1942    pub(crate) fn whole_row_field(&self, var: Var, name: &str, at: Option<usize>) -> Result<Expr> {
1943        let scope = self.level(var.levels_up);
1944        let entry = scope
1945            .entries
1946            .iter()
1947            .find(|e| e.relation == Some(var.relation))
1948            .ok_or_else(|| Error::internal("a whole-row reference has no entry"))?;
1949        let column = entry.columns.iter().position(|c| c == name).and_then(|i| {
1950            let column = scope.relations.get(var.relation)?.columns.get(i)?;
1951            Some((i, column))
1952        });
1953        let Some((i, column)) = column else {
1954            return Err(Error::new(
1955                SqlState::UNDEFINED_COLUMN,
1956                format!("column {}.{name} does not exist", entry.name),
1957            )
1958            .at_opt(at));
1959        };
1960        let attnum = i16::try_from(i + 1).map_err(|_| Error::internal("too many columns"))?;
1961        let var = Var { attnum, ..var };
1962        let mut expr = Expr::new(ExprKind::Var(var), column.ty).at(at);
1963        expr.typmod = column.typmod;
1964        Ok(expr)
1965    }
1966
1967    /// `ExpandRowReference` of a whole-row reference: the columns of the relation, as for `t.*`.
1968    pub(crate) fn whole_row_columns(
1969        &self,
1970        var: Var,
1971        at: Option<usize>,
1972    ) -> Result<Vec<(String, Expr)>> {
1973        let scope = self.level(var.levels_up);
1974        let entry = scope
1975            .entries
1976            .iter()
1977            .find(|e| e.relation == Some(var.relation))
1978            .ok_or_else(|| Error::internal("a whole-row reference has no entry"))?;
1979        let relation = scope
1980            .relations
1981            .get(var.relation)
1982            .ok_or_else(|| Error::internal("a whole-row reference has no relation"))?;
1983        let mut columns = Vec::with_capacity(entry.columns.len());
1984        for (i, (name, column)) in entry.columns.iter().zip(&relation.columns).enumerate() {
1985            if relation.of_table() && column.is_dropped() {
1986                continue;
1987            }
1988            let attnum = i16::try_from(i + 1).map_err(|_| Error::internal("too many columns"))?;
1989            let mut expr = Expr::new(ExprKind::Var(Var { attnum, ..var }), column.ty).at(at);
1990            expr.typmod = column.typmod;
1991            columns.push((name.clone(), expr));
1992        }
1993        Ok(columns)
1994    }
1995
1996    /// The scopes of the query and of the queries outside it, with their levels: 0 for the query, 1 for the query outside it, and so on.
1997    pub(crate) fn levels(&self) -> impl Iterator<Item = (usize, &Scope)> {
1998        std::iter::once(&self.scope).chain(self.outer.iter().rev()).enumerate()
1999    }
2000
2001    /// The scope of a level.
2002    pub(crate) fn level(&self, level: usize) -> &Scope {
2003        self.levels().nth(level).map_or(&self.scope, |(_, scope)| scope)
2004    }
2005
2006    /// `scanNSItemForColumn`: the column of an item of a level with this name, or `None`. The columns of the expression are `levels_up` of the level.
2007    fn column_in(
2008        &self,
2009        level: usize,
2010        item: &Item,
2011        name: &str,
2012        at: Option<usize>,
2013    ) -> Result<Option<Expr>> {
2014        let mut found = None;
2015        for (n, expr) in &item.columns {
2016            if n == name {
2017                if found.is_some() {
2018                    return Err(ambiguous(name, at));
2019                }
2020                found = Some(expr);
2021            }
2022        }
2023        if let Some(expr) = found {
2024            let mut expr = expr.clone().at(at);
2025            expr.raise(level);
2026            return Ok(Some(expr));
2027        }
2028        let entry = &self.level(level).entries[item.entry];
2029        let Some(relation) = entry.relation else { return Ok(None) };
2030        let rel = self.level(level).relations.get(relation);
2031        let view = rel.is_some_and(|r| r.subquery.is_some() || r.oid != entry.oid);
2032        let live = rel.map_or(0, |r| r.columns.iter().filter(|c| !c.is_dropped()).count());
2033        if item.columns.len() != live || entry.oid == 0 || view {
2034            // The item of a USING alias gives only the columns of USING, and a subquery and a view have no system columns.
2035            return Ok(None);
2036        }
2037        if name == "tableoid" {
2038            let var = Var { relation, attnum: TABLE_OID_ATTNUM, levels_up: level };
2039            return Ok(Some(Expr::new(ExprKind::Var(var), oid::OID).at(at)));
2040        }
2041        let Some(&(_, attnum, type_oid)) = OTHER_SYSTEM_COLUMNS.iter().find(|c| c.0 == name) else {
2042            return Ok(None);
2043        };
2044        if self.kind == Kind::Check {
2045            return Err(Error::new(
2046                SqlState::INVALID_COLUMN_REFERENCE,
2047                format!("system column \"{name}\" reference in check constraint is invalid"),
2048            )
2049            .at_opt(at));
2050        }
2051        // `scanNSItemForColumn`: a generation expression can use only the system column `tableoid`.
2052        if self.kind == Kind::Generated {
2053            return Err(Error::new(
2054                SqlState::INVALID_COLUMN_REFERENCE,
2055                format!("cannot use system column \"{name}\" in column generation expression"),
2056            )
2057            .at_opt(at));
2058        }
2059        // The condition of a trigger names the system columns of the row, and `CREATE TRIGGER` gives the error for a `BEFORE` trigger. A table of the catalog has no IDs of the versions of its rows.
2060        if name == "ctid"
2061            && self.kind != Kind::TriggerWhen
2062            && entry.oid < rupg_catalog::FIRST_NORMAL_OID
2063        {
2064            return Err(not_yet("the system column \"ctid\"", at));
2065        }
2066        let var = Var { relation, attnum, levels_up: level };
2067        Ok(Some(Expr::new(ExprKind::Var(var), type_oid).at(at)))
2068    }
2069
2070    /// The name of the relation and the name of the column of a `Var`, as `eref->aliasname` and `get_rte_attribute_name` give them for an error.
2071    pub(crate) fn column_names(&self, var: Var) -> (String, String) {
2072        let scope = self.level(var.levels_up);
2073        let Some(entry) = scope.entries.iter().find(|e| e.relation == Some(var.relation)) else {
2074            return (String::new(), String::new());
2075        };
2076        let column = match usize::try_from(var.attnum) {
2077            Ok(n) if n > 0 => entry.columns.get(n - 1).cloned().unwrap_or_default(),
2078            _ => OTHER_SYSTEM_COLUMNS
2079                .iter()
2080                .find(|c| c.1 == var.attnum)
2081                .map_or("tableoid", |c| c.0)
2082                .to_string(),
2083        };
2084        (entry.name.clone(), column)
2085    }
2086
2087    /// `colNameToVar`: the column that an unqualified name gives, or `None`. The search goes up the query levels and stops at the first level that has the name.
2088    pub(crate) fn column_by_name(&self, name: &str, at: Option<usize>) -> Result<Option<Expr>> {
2089        for (level, scope) in self.levels() {
2090            let mut result = None;
2091            for (item, ok) in scope.visible().filter(|(i, _)| i.cols_visible) {
2092                if let Some(expr) = self.column_in(level, item, name, at)? {
2093                    if result.is_some() {
2094                        return Err(ambiguous(name, at));
2095                    }
2096                    check_lateral_ok(item, ok, at)?;
2097                    result = Some(expr);
2098                }
2099            }
2100            if result.is_some() {
2101                return Ok(result);
2102            }
2103        }
2104        Ok(None)
2105    }
2106
2107    /// `refnameNamespaceItem`: the item that a table name gives and its level, or `None`. The search goes up the query levels and stops at the first level that has the name.
2108    fn item_by_name(
2109        &self,
2110        schema: Option<&str>,
2111        name: &str,
2112        at: Option<usize>,
2113    ) -> Result<Option<(usize, Item)>> {
2114        for (level, scope) in self.levels() {
2115            if let Some(item) = self.item_in(scope, schema, name, at)? {
2116                return Ok(Some((level, item)));
2117            }
2118        }
2119        Ok(None)
2120    }
2121
2122    /// `scanNameSpaceForRefname` and `scanNameSpaceForRelid`: the item of a scope that a table name gives, or `None`.
2123    fn item_in(
2124        &self,
2125        scope: &Scope,
2126        schema: Option<&str>,
2127        name: &str,
2128        at: Option<usize>,
2129    ) -> Result<Option<Item>> {
2130        if let Some(schema) = schema {
2131            // scanNameSpaceForRelid: a relation with no alias in that schema.
2132            let rv = RangeVar {
2133                schemaname: Some(schema.into()),
2134                relname: Some(name.into()),
2135                location: at.map_or(-1, |a| i32::try_from(a).unwrap_or(-1)),
2136                ..RangeVar::default()
2137            };
2138            let Some(oid) = self.lookup_relation(&rv)? else { return Ok(None) };
2139            let mut result = None;
2140            for (item, ok) in scope.visible().filter(|(i, _)| i.rel_visible && !i.returning) {
2141                let entry = &scope.entries[item.entry];
2142                if entry.relation.is_some() && !entry.aliased && entry.oid == oid {
2143                    if result.is_some() {
2144                        return Err(Error::new(
2145                            SqlState::AMBIGUOUS_ALIAS,
2146                            format!("table reference {oid} is ambiguous"),
2147                        )
2148                        .at_opt(at));
2149                    }
2150                    check_lateral_ok(item, ok, at)?;
2151                    result = Some(item.clone());
2152                }
2153            }
2154            return Ok(result);
2155        }
2156        let mut result = None;
2157        for (item, ok) in scope.visible().filter(|(i, _)| i.rel_visible) {
2158            if item.name == name {
2159                if result.is_some() {
2160                    return Err(Error::new(
2161                        SqlState::AMBIGUOUS_ALIAS,
2162                        format!("table reference \"{name}\" is ambiguous"),
2163                    )
2164                    .at_opt(at));
2165                }
2166                check_lateral_ok(item, ok, at)?;
2167                result = Some(item.clone());
2168            }
2169        }
2170        Ok(result)
2171    }
2172
2173    /// `errorMissingRTE`.
2174    fn missing_entry(&self, schema: Option<&str>, name: &str, at: Option<usize>) -> Error {
2175        // searchRangeTableForRel: an entry for the relation or with the name.
2176        let rv = RangeVar {
2177            schemaname: schema.map(Into::into),
2178            relname: Some(name.into()),
2179            ..RangeVar::default()
2180        };
2181        let oid = self.lookup_relation(&rv).ok().flatten();
2182        let found = self.levels().find_map(|(level, scope)| {
2183            let index = scope
2184                .entries
2185                .iter()
2186                .position(|e| (e.relation.is_some() && Some(e.oid) == oid) || e.name == name)?;
2187            Some((level, index))
2188        });
2189        let Some((level, found)) = found else {
2190            return Error::new(
2191                SqlState::UNDEFINED_TABLE,
2192                format!("missing FROM-clause entry for table \"{name}\""),
2193            )
2194            .at_opt(at);
2195        };
2196        let entry = &self.level(level).entries[found];
2197        let error = Error::new(
2198            SqlState::UNDEFINED_TABLE,
2199            format!("invalid reference to FROM-clause entry for table \"{name}\""),
2200        )
2201        .at_opt(at);
2202        if entry.aliased && entry.name != name {
2203            let visible = matches!(
2204                self.item_by_name(None, &entry.name, None),
2205                Ok(Some((l, item))) if l == level && item.entry == found
2206            );
2207            if visible {
2208                return error.with_hint(format!(
2209                    "Perhaps you meant to reference the table alias \"{}\".",
2210                    entry.name
2211                ));
2212            }
2213        }
2214        let error = error.with_detail(format!(
2215            "There is an entry for table \"{}\", but it cannot be referenced from this part of the query.",
2216            entry.name
2217        ));
2218        if self.visible_if_lateral((level, found)) {
2219            return error
2220                .with_hint("To reference that table, you must mark this subquery with LATERAL.");
2221        }
2222        error
2223    }
2224
2225    /// `rte_visible_if_lateral`: true when a `LATERAL` subquery could see the entry.
2226    fn visible_if_lateral(&self, (level, index): Place) -> bool {
2227        if self.scope.lateral_active {
2228            return false;
2229        }
2230        self.level(level).lateral.iter().any(|(item, ok)| item.entry == index && *ok)
2231    }
2232
2233    /// `errorMissingColumn`, with the hint of a close name.
2234    fn missing_column(&self, table: Option<&str>, column: &str, at: Option<usize>) -> Error {
2235        let mut fuzzy = Fuzzy {
2236            distance: MAX_FUZZY_DISTANCE + 1,
2237            first: None,
2238            second: None,
2239            exact: Vec::new(),
2240        };
2241        let entries = self.levels().flat_map(|(level, scope)| {
2242            scope.entries.iter().enumerate().map(move |(index, entry)| ((level, index), entry))
2243        });
2244        for (index, entry) in entries {
2245            let Some(relation) = entry.relation else { continue };
2246            // The base relation of an automatically updatable view has the columns of the view and no system columns.
2247            let relation = self.level(index.0).relations.get(relation);
2248            let system = entry.oid != 0 && relation.is_none_or(|r| r.oid == entry.oid);
2249            let penalty =
2250                table.map_or(0, |t| levenshtein(t, &entry.name).min(MAX_FUZZY_DISTANCE + 1));
2251            let mut exact = false;
2252            for (i, name) in entry.columns.iter().enumerate() {
2253                if name == column {
2254                    exact = true;
2255                }
2256                fuzzy.update(penalty, index, name, column, i);
2257            }
2258            if (exact || (is_system_column(column) && system)) && penalty == 0 {
2259                fuzzy.exact.push(index);
2260            }
2261        }
2262        let message = match table {
2263            Some(t) => format!("column {t}.{column} does not exist"),
2264            None => format!("column \"{column}\" does not exist"),
2265        };
2266        let error = Error::new(SqlState::UNDEFINED_COLUMN, message).at_opt(at);
2267        let entry = |(level, index): Place| &self.level(level).entries[index];
2268        if fuzzy.exact.len() > 1 {
2269            let error = error.with_detail(format!("There are columns named \"{column}\", but they are in tables that cannot be referenced from this part of the query."));
2270            return if table.is_none() {
2271                error.with_hint("Try using a table-qualified name.")
2272            } else {
2273                error
2274            };
2275        }
2276        if let Some(&index) = fuzzy.exact.first() {
2277            let error = error.with_detail(format!("There is a column named \"{column}\" in table \"{}\", but it cannot be referenced from this part of the query.", entry(index).name));
2278            // rte_visible_if_qualified: the item has a name that a query can qualify.
2279            let qualified = self.levels().any(|(level, scope)| {
2280                level == index.0
2281                    && scope.namespace.iter().any(|i| i.entry == index.1 && i.rel_visible)
2282            });
2283            return if self.visible_if_lateral(index) {
2284                error.with_hint(
2285                    "To reference that column, you must mark this subquery with LATERAL.",
2286                )
2287            } else if table.is_none() && qualified {
2288                error.with_hint("To reference that column, you must use a table-qualified name.")
2289            } else {
2290                error
2291            };
2292        }
2293        let name = |(e, c): (Place, usize)| format!("{}.{}", entry(e).name, entry(e).columns[c]);
2294        match (fuzzy.first, fuzzy.second) {
2295            (Some(first), None) => error.with_hint(format!(
2296                "Perhaps you meant to reference the column \"{}\".",
2297                name(first)
2298            )),
2299            (Some(first), Some(second)) => error.with_hint(format!(
2300                "Perhaps you meant to reference the column \"{}\" or the column \"{}\".",
2301                name(first),
2302                name(second)
2303            )),
2304            _ => error,
2305        }
2306    }
2307
2308    /// `ExpandColumnRefStar`: the columns of `*` or `t.*` in a target list, with their names.
2309    pub(crate) fn expand_star(&mut self, c: &ColumnRef) -> Result<Option<Vec<(String, Expr)>>> {
2310        let at = place(c.location);
2311        let names = fields(&c.fields);
2312        let Some((None, qualifier)) = names.split_last() else { return Ok(None) };
2313        let items: Vec<(usize, Item)> = match qualifier {
2314            [] => {
2315                let visible: Vec<(usize, Item)> = self
2316                    .scope
2317                    .namespace
2318                    .iter()
2319                    .filter(|i| i.cols_visible)
2320                    .map(|i| (0, i.clone()))
2321                    .collect();
2322                if visible.is_empty() {
2323                    return Err(Error::new(
2324                        SqlState::SYNTAX_ERROR,
2325                        "SELECT * with no tables specified is not valid",
2326                    )
2327                    .at_opt(at));
2328                }
2329                visible
2330            }
2331            [Some(table)] | [Some(_), Some(table)] | [Some(_), Some(_), Some(table)] => {
2332                let schema = match qualifier {
2333                    [Some(schema), _] | [_, Some(schema), _] => Some(*schema),
2334                    _ => None,
2335                };
2336                if let [Some(database), _, _] = qualifier
2337                    && *database != self.env.database()
2338                {
2339                    return Err(Error::new(
2340                        SqlState::FEATURE_NOT_SUPPORTED,
2341                        format!(
2342                            "cross-database references are not implemented: {}",
2343                            names.iter().map(|n| n.unwrap_or("*")).collect::<Vec<_>>().join(".")
2344                        ),
2345                    )
2346                    .at_opt(at));
2347                }
2348                match self.item_by_name(schema, table, at)? {
2349                    // The columns of a relation of a query outside this query are references to the outer query.
2350                    Some((level, mut item)) => {
2351                        for (_, expr) in &mut item.columns {
2352                            expr.raise(level);
2353                        }
2354                        vec![(level, item)]
2355                    }
2356                    None if schema.is_none() && qualifier.len() == 1 => {
2357                        // `plpgsql_post_column_ref`: `r.*` of a variable of a composite type gives the fields of the variable.
2358                        if let Some(variable) = self.composite_variable(&[*table], at)? {
2359                            let expr = self.variable_param(variable, at);
2360                            return self.composite_fields(expr).map(Some);
2361                        }
2362                        return Err(self.missing_entry(schema, table, at));
2363                    }
2364                    None => return Err(self.missing_entry(schema, table, at)),
2365                }
2366            }
2367            _ => return Ok(None),
2368        };
2369        let mut columns = Vec::new();
2370        for (level, item) in items {
2371            // `expandNSItemAttrs`: the relation needs `SELECT` also when it has no columns.
2372            if let Some(relation) = self.level(level).entries[item.entry].relation {
2373                self.mark_relation(level, relation);
2374            }
2375            let shown = item.columns.len() - item.hidden;
2376            for (_, expr) in item.columns.iter().take(shown) {
2377                self.mark_select(expr);
2378            }
2379            for (name, expr) in item.columns.into_iter().take(shown) {
2380                columns.push((name, expr.at(at)));
2381            }
2382        }
2383        Ok(Some(columns))
2384    }
2385}
2386
2387/// The error of a name that two columns have.
2388fn ambiguous(name: &str, at: Option<usize>) -> Error {
2389    Error::new(SqlState::AMBIGUOUS_COLUMN, format!("column reference \"{name}\" is ambiguous"))
2390        .at_opt(at)
2391}
2392
2393/// The `relkind` of a built-in relation, from the static rows of `pg_class`.
2394fn builtin_relkind(oid: u32) -> Option<u8> {
2395    let class = rupg_pgcatalog::catalog("pg_class")?;
2396    let (Values::Oid(oids), Values::Char(kinds)) =
2397        (&class.rows[class.column("oid")?].values, &class.rows[class.column("relkind")?].values)
2398    else {
2399        return None;
2400    };
2401    oids.iter().position(|&o| o == oid).map(|row| kinds[row])
2402}
2403
2404/// The error of a part of `FROM` that the analyzer does not take yet.
2405fn not_yet(what: &str, at: Option<usize>) -> Error {
2406    Error::new(SqlState::FEATURE_NOT_SUPPORTED, format!("{what} is not supported yet")).at_opt(at)
2407}
2408
2409#[cfg(test)]
2410mod tests {
2411    use super::levenshtein;
2412
2413    #[test]
2414    fn distances() {
2415        assert_eq!(levenshtein("relname", "relnam"), 1);
2416        assert_eq!(levenshtein("oid", "iod"), 2);
2417        assert_eq!(levenshtein("", "abc"), 3);
2418        assert_eq!(levenshtein("kitten", "sitting"), 3);
2419    }
2420}