Skip to main content

rupg_analyze/
sort.rs

1//! `ORDER BY`, `GROUP BY`, `DISTINCT`, `DISTINCT ON`, `LIMIT` and `OFFSET`, as `transformSortClause`, `transformGroupClause`, `transformDistinctClause`, `transformDistinctOnClause` and `transformLimitClause` of `parse_clause.c` make them.
2
3use rupg_common::{Error, Result, SqlState};
4use rupg_pgcatalog::builtin;
5use rupg_sql::nodes::{CoercionForm, GroupingSetKind, List, Node, SortBy, SortByDir, SortByNulls};
6use rupg_types::oid;
7
8use crate::Analyzer;
9use crate::agg::{Kind, grouping_error};
10use crate::coerce::{AtOpt, Context};
11use crate::expr::{Expr, ExprKind};
12use crate::select::Target;
13use crate::typcache::{self, is_binary_coercible};
14use crate::typename::place;
15use crate::types;
16
17/// An item of `ORDER BY`, `GROUP BY`, `DISTINCT` or `DISTINCT ON`, as `SortGroupClause`.
18#[derive(Clone, Debug, PartialEq, Eq)]
19pub struct SortGroup {
20    /// The index of the column in [`crate::Query::targets`].
21    pub target: usize,
22    /// The OID of the sort operator, or 0.
23    pub operator: u32,
24    /// The function of the operator that puts a value first, `<` for `ASC` and `>` for `DESC`, or 0 when the type has no order.
25    pub sort: u32,
26    /// The function of the `=` operator.
27    pub equal: u32,
28    /// True when a null comes before the other values.
29    pub nulls_first: bool,
30    /// True when the `=` operator can use a hash table, as `op_hashjoinable` gives it.
31    pub hashable: bool,
32}
33
34/// A grouping set of `GROUP BY`, as `GroupingSet` after `transformGroupClause`. A simple set names its items by the index of their targets in [`crate::Query::targets`].
35#[derive(Clone, Debug, PartialEq, Eq)]
36pub enum GroupingSet {
37    /// `()`.
38    Empty,
39    /// A list of items.
40    Simple(Vec<usize>),
41    /// `ROLLUP`, of simple sets.
42    Rollup(Vec<GroupingSet>),
43    /// `CUBE`, of simple sets.
44    Cube(Vec<GroupingSet>),
45    /// `GROUPING SETS`, of sets of the other kinds.
46    Sets(Vec<GroupingSet>),
47}
48
49impl GroupingSet {
50    /// `expand_groupingset_node`: the lists of items of the set.
51    fn expand(&self) -> Vec<Vec<usize>> {
52        fn items(set: &GroupingSet) -> &[usize] {
53            match set {
54                GroupingSet::Simple(items) => items,
55                _ => &[],
56            }
57        }
58        match self {
59            GroupingSet::Empty => vec![Vec::new()],
60            GroupingSet::Simple(items) => vec![items.clone()],
61            GroupingSet::Rollup(content) => {
62                let mut out: Vec<Vec<usize>> = (1..=content.len())
63                    .rev()
64                    .map(|n| content[..n].iter().flat_map(|s| items(s).iter().copied()).collect())
65                    .collect();
66                out.push(Vec::new());
67                out
68            }
69            GroupingSet::Cube(content) => (0..1u32 << content.len())
70                .map(|mask| {
71                    content
72                        .iter()
73                        .enumerate()
74                        .filter(|(i, _)| mask & (1 << i) != 0)
75                        .flat_map(|(_, s)| items(s).iter().copied())
76                        .collect()
77                })
78                .collect(),
79            GroupingSet::Sets(content) => content.iter().flat_map(GroupingSet::expand).collect(),
80        }
81    }
82}
83
84/// `expand_grouping_sets`: the grouping sets of `GROUP BY` as lists of items, with the shortest lists first. Each set is the product of the expansions of the items of `GROUP BY`. With `distinct` the same set comes once. The result is `None` when there are more than `limit` sets.
85pub fn expand_grouping_sets(
86    sets: &[GroupingSet],
87    distinct: bool,
88    limit: usize,
89) -> Option<Vec<Vec<usize>>> {
90    // `list_union_int`: the items of `a`, then the items of `b` that are not in it.
91    fn union(a: &[usize], b: &[usize]) -> Vec<usize> {
92        let mut out = a.to_vec();
93        for &item in b {
94            if !out.contains(&item) {
95                out.push(item);
96            }
97        }
98        out
99    }
100    let mut count = 1.0;
101    let mut expanded = Vec::with_capacity(sets.len());
102    for set in sets {
103        let lists = set.expand();
104        count *= lists.len() as f64;
105        if count > limit as f64 {
106            return None;
107        }
108        expanded.push(lists);
109    }
110    let Some((first, rest)) = expanded.split_first() else { return Some(Vec::new()) };
111    let mut result: Vec<Vec<usize>> = first.iter().map(|l| union(&[], l)).collect();
112    for lists in rest {
113        result = result.iter().flat_map(|q| lists.iter().map(|l| union(q, l))).collect();
114    }
115    if distinct && result.len() > 1 {
116        for list in &mut result {
117            list.sort_unstable();
118        }
119        result.sort_by(|a, b| a.len().cmp(&b.len()).then_with(|| a.cmp(b)));
120        result.dedup();
121    } else {
122        result.sort_by_key(Vec::len);
123    }
124    Some(result)
125}
126
127/// An item of `GROUP BY` after `flatten_grouping_sets`.
128enum Flat<'a> {
129    /// An expression.
130    Item(Option<&'a Node>),
131    /// The expressions of a row in parentheses in a grouping set.
132    Row(Vec<Option<&'a Node>>),
133    /// A grouping set, its flat content and its place.
134    Set(GroupingSetKind, Vec<Flat<'a>>, Option<usize>),
135}
136
137/// True for a row in parentheses with no `ROW`, which `GROUP BY` takes as a list of items.
138fn implicit_row(node: &Node) -> Option<&List> {
139    match node {
140        Node::RowExpr(row) if row.row_format == CoercionForm::COERCE_IMPLICIT_CAST => {
141            Some(&row.args)
142        }
143        _ => None,
144    }
145}
146
147/// The expressions of a row in parentheses, with the rows in it as their expressions.
148fn row_items<'a>(list: &'a List, out: &mut Vec<Option<&'a Node>>) {
149    for node in list {
150        match node.as_ref().and_then(implicit_row) {
151            Some(args) => row_items(args, out),
152            None => out.push(node.as_ref()),
153        }
154    }
155}
156
157/// `flatten_grouping_sets` at the top of `GROUP BY`: a row adds its expressions as items, and the empty grouping set `()` adds nothing. `has_sets` becomes true when the list has a grouping set.
158fn flatten_top<'a>(list: &'a List, has_sets: &mut bool) -> Vec<Flat<'a>> {
159    let mut out = Vec::new();
160    for node in list {
161        match node {
162            Some(Node::GroupingSet(set)) => {
163                *has_sets = true;
164                if set.kind != GroupingSetKind::GROUPING_SET_EMPTY {
165                    out.push(Flat::Set(
166                        set.kind,
167                        flatten_content(&set.content),
168                        place(set.location),
169                    ));
170                }
171            }
172            node => match node.as_ref().and_then(implicit_row) {
173                Some(args) => {
174                    let mut items = Vec::new();
175                    row_items(args, &mut items);
176                    out.extend(items.into_iter().map(Flat::Item));
177                }
178                None => out.push(Flat::Item(node.as_ref())),
179            },
180        }
181    }
182    out
183}
184
185/// `flatten_grouping_sets` in a grouping set: the content of `GROUPING SETS` in `GROUPING SETS` comes into the outer set.
186fn flatten_content(list: &List) -> Vec<Flat<'_>> {
187    let mut out = Vec::new();
188    for node in list {
189        match node {
190            Some(Node::GroupingSet(set)) if set.kind == GroupingSetKind::GROUPING_SET_SETS => {
191                out.extend(flatten_content(&set.content));
192            }
193            Some(Node::GroupingSet(set)) => {
194                out.push(Flat::Set(set.kind, flatten_content(&set.content), place(set.location)));
195            }
196            node => match node.as_ref().and_then(implicit_row) {
197                Some(args) => {
198                    let mut items = Vec::new();
199                    row_items(args, &mut items);
200                    out.push(Flat::Row(items));
201                }
202                None => out.push(Flat::Item(node.as_ref())),
203            },
204        }
205    }
206    out
207}
208
209/// `leftmostLoc`.
210fn leftmost(a: Option<usize>, b: Option<usize>) -> Option<usize> {
211    match (a, b) {
212        (Some(a), Some(b)) => Some(a.min(b)),
213        (a, b) => a.or(b),
214    }
215}
216
217/// `exprLocation` of the first item of a list that has a location.
218pub(crate) fn list_location(list: &List) -> Option<usize> {
219    list.iter().find_map(|node| raw_location(node.as_ref()))
220}
221
222/// `exprLocation` of a raw expression of the parser.
223pub(crate) fn raw_location(node: Option<&Node>) -> Option<usize> {
224    match node? {
225        Node::ColumnRef(c) => place(c.location),
226        Node::SortBy(s) => raw_location(s.node.as_ref()),
227        Node::ParamRef(p) => place(p.location),
228        Node::A_Const(c) => place(c.location),
229        Node::A_ArrayExpr(a) => place(a.location),
230        Node::CaseExpr(c) => place(c.location),
231        Node::CoalesceExpr(c) => place(c.location),
232        Node::MinMaxExpr(m) => place(m.location),
233        Node::SQLValueFunction(f) => place(f.location),
234        Node::RowExpr(r) => place(r.location),
235        Node::A_Expr(a) => leftmost(place(a.location), raw_location(a.lexpr.as_ref())),
236        Node::FuncCall(f) => leftmost(place(f.location), list_location(&f.args)),
237        Node::BoolExpr(b) => leftmost(place(b.location), list_location(&b.args)),
238        Node::NullTest(n) => leftmost(place(n.location), raw_location(n.arg.as_ref())),
239        Node::BooleanTest(b) => leftmost(place(b.location), raw_location(b.arg.as_ref())),
240        Node::SubLink(s) => leftmost(raw_location(s.testexpr.as_ref()), place(s.location)),
241        Node::CollateClause(c) => raw_location(c.arg.as_ref()),
242        Node::TypeCast(t) => {
243            let at = raw_location(t.arg.as_ref());
244            let at = leftmost(at, t.typeName.as_ref().and_then(|n| place(n.location)));
245            leftmost(at, place(t.location))
246        }
247        _ => None,
248    }
249}
250
251/// The error of a clause that names a column that is not in the select list.
252pub(crate) fn invalid_reference(message: String, at: Option<usize>) -> Error {
253    Error::new(SqlState::INVALID_COLUMN_REFERENCE, message).at_opt(at)
254}
255
256impl Analyzer<'_> {
257    /// `findTargetlistEntrySQL92`: the column of the select list that an item of `ORDER BY`, `GROUP BY` or `DISTINCT ON` names. A bare name is an output column, and an integer is a position in the select list. In `GROUP BY` a column of `FROM` comes before an output column. Any other expression goes to [`Analyzer::target_sql99`].
258    fn target_sql92(
259        &mut self,
260        node: Option<&Node>,
261        targets: &mut Vec<Target>,
262        kind: Kind,
263    ) -> Result<usize> {
264        if let Some(Node::ColumnRef(c)) = node
265            && let [Some(Node::String(name))] = c.fields.as_slice()
266            && (kind != Kind::GroupBy || self.column_by_name(name, place(c.location))?.is_none())
267        {
268            let mut found: Option<usize> = None;
269            for (i, target) in targets.iter().enumerate() {
270                if target.junk || target.name != **name {
271                    continue;
272                }
273                match found {
274                    Some(first) if !targets[first].expr.same(&target.expr) => {
275                        return Err(Error::new(
276                            SqlState::AMBIGUOUS_COLUMN,
277                            format!("{} \"{name}\" is ambiguous", kind.name()),
278                        )
279                        .at_opt(place(c.location)));
280                    }
281                    Some(_) => {}
282                    None => found = Some(i),
283                }
284            }
285            if let Some(i) = found {
286                self.check_sql92(&targets[i], kind)?;
287                return Ok(i);
288            }
289        }
290        if let Some(Node::A_Const(c)) = node {
291            let at = place(c.location);
292            let Some(Node::Integer(position)) = c.val.as_ref().filter(|_| !c.isnull) else {
293                return Err(Error::new(
294                    SqlState::SYNTAX_ERROR,
295                    format!("non-integer constant in {}", kind.name()),
296                )
297                .at_opt(at));
298            };
299            let visible = targets.iter().enumerate().filter(|(_, t)| !t.junk);
300            let mut seen = 0;
301            for (i, _) in visible {
302                seen += 1;
303                if seen == *position {
304                    self.check_sql92(&targets[i], kind)?;
305                    return Ok(i);
306                }
307            }
308            return Err(invalid_reference(
309                format!("{} position {position} is not in select list", kind.name()),
310                at,
311            ));
312        }
313        self.target_sql99(node, targets, kind)
314    }
315
316    /// `checkTargetlistEntrySQL92`: an item of `GROUP BY` that names a column of the select list cannot name an aggregate call.
317    fn check_sql92(&self, target: &Target, kind: Kind) -> Result<()> {
318        if kind == Kind::GroupBy
319            && self.has_aggs
320            && let Some(agg) = target.expr.first_agg()
321        {
322            return Err(grouping_error(
323                format!("aggregate functions are not allowed in {}", kind.name()),
324                agg.location,
325            ));
326        }
327        Ok(())
328    }
329
330    /// `findTargetlistEntrySQL99`: the column of the select list with the same expression, or a new junk column that the result does not show. A cast that the analyzer added to a column does not count.
331    fn target_sql99(
332        &mut self,
333        node: Option<&Node>,
334        targets: &mut Vec<Target>,
335        kind: Kind,
336    ) -> Result<usize> {
337        let expr = self.with_kind(kind, |a| a.transform(node))?;
338        if let Some(i) = targets.iter().position(|t| t.expr.strip_implicit().same(&expr)) {
339            return Ok(i);
340        }
341        targets.push(Target { name: String::new(), expr, origin: None, junk: true });
342        Ok(targets.len() - 1)
343    }
344
345    /// The column as `text` when its type is `unknown`, as `addTargetToSortList` does.
346    fn resolve_unknown(&mut self, target: &mut Target) -> Result<()> {
347        if target.expr.ty == oid::UNKNOWN {
348            let expr = std::mem::replace(&mut target.expr, Expr::new(ExprKind::CaseTest, 0));
349            target.expr = self.coerce(expr, oid::TEXT, -1, Context::Implicit, None)?;
350        }
351        Ok(())
352    }
353
354    /// `transformSortClause` of the `ORDER BY` of a query.
355    pub(crate) fn sort_clause(
356        &mut self,
357        list: &List,
358        targets: &mut Vec<Target>,
359    ) -> Result<Vec<SortGroup>> {
360        self.sort_list(list, targets, false, Kind::OrderBy)
361    }
362
363    /// `transformSortClause` of the `ORDER BY` of an aggregate call, which uses the rules of SQL99 only.
364    pub(crate) fn sort_clause_sql99(
365        &mut self,
366        list: &List,
367        targets: &mut Vec<Target>,
368    ) -> Result<Vec<SortGroup>> {
369        self.sort_list(list, targets, true, Kind::OrderBy)
370    }
371
372    /// `transformSortClause` of the `ORDER BY` of a window, which uses the rules of SQL99 only.
373    pub(crate) fn window_order(
374        &mut self,
375        list: &List,
376        targets: &mut Vec<Target>,
377    ) -> Result<Vec<SortGroup>> {
378        self.sort_list(list, targets, true, Kind::WindowOrder)
379    }
380
381    /// `transformGroupClause` of the `PARTITION BY` of a window, which uses the rules of SQL99 only. An item that is also an item of the `ORDER BY` of the window takes its operator.
382    pub(crate) fn window_partition(
383        &mut self,
384        list: &List,
385        targets: &mut Vec<Target>,
386        order: &[SortGroup],
387    ) -> Result<Vec<SortGroup>> {
388        let mut result = Vec::new();
389        for node in list {
390            let target = self.target_sql99(node.as_ref(), targets, Kind::WindowPartition)?;
391            if result.iter().any(|g: &SortGroup| g.target == target) {
392                continue;
393            }
394            if let Some(item) = order.iter().find(|s| s.target == target) {
395                result.push(item.clone());
396                continue;
397            }
398            self.add_group(target, targets, &mut result, raw_location(node.as_ref()))?;
399        }
400        Ok(result)
401    }
402
403    fn sort_list(
404        &mut self,
405        list: &List,
406        targets: &mut Vec<Target>,
407        sql99: bool,
408        kind: Kind,
409    ) -> Result<Vec<SortGroup>> {
410        let mut sort = Vec::new();
411        for item in list {
412            let Some(Node::SortBy(by)) = item else {
413                return Err(Error::internal("an item of ORDER BY that is not SortBy"));
414            };
415            let target = if sql99 {
416                self.target_sql99(by.node.as_ref(), targets, kind)?
417            } else {
418                self.target_sql92(by.node.as_ref(), targets, Kind::OrderBy)?
419            };
420            self.add_sort(by, target, targets, &mut sort)?;
421        }
422        Ok(sort)
423    }
424
425    /// `transformGroupClause`: the items of `GROUP BY`, each once, and the grouping sets. The list of grouping sets is empty when `GROUP BY` has no grouping set. With only empty grouping sets it is `()` and the list of items is empty.
426    pub(crate) fn group_clause(
427        &mut self,
428        list: &List,
429        targets: &mut Vec<Target>,
430        sort: &[SortGroup],
431    ) -> Result<(Vec<SortGroup>, Vec<GroupingSet>)> {
432        let mut has_sets = false;
433        let flat = flatten_top(list, &mut has_sets);
434        let mut result = Vec::new();
435        let mut sets = Vec::new();
436        if flat.is_empty() && has_sets {
437            sets.push(GroupingSet::Empty);
438        }
439        let mut seen = Vec::new();
440        for item in &flat {
441            match item {
442                Flat::Set(kind, content, at) => {
443                    sets.push(self.grouping_set(
444                        *kind,
445                        content,
446                        *at,
447                        targets,
448                        sort,
449                        &mut result,
450                    )?);
451                }
452                Flat::Row(_) => return Err(Error::internal("a row at the top of GROUP BY")),
453                Flat::Item(node) => {
454                    let target =
455                        self.group_item(*node, Some(&mut seen), targets, sort, &mut result, true)?;
456                    if let Some(target) = target
457                        && has_sets
458                    {
459                        sets.push(GroupingSet::Simple(vec![target]));
460                    }
461                }
462            }
463        }
464        Ok((result, sets))
465    }
466
467    /// `transformGroupClauseExpr`: the target of an item of `GROUP BY`, which comes in `result` once. An item that is also an item of `ORDER BY` takes the operator of `ORDER BY`, but in a grouping set it puts nulls last. `seen` has the targets of the list that has the item, and an item that is in it again gives `None`.
468    fn group_item(
469        &mut self,
470        node: Option<&Node>,
471        seen: Option<&mut Vec<usize>>,
472        targets: &mut Vec<Target>,
473        sort: &[SortGroup],
474        result: &mut Vec<SortGroup>,
475        toplevel: bool,
476    ) -> Result<Option<usize>> {
477        let target = self.target_sql92(node, targets, Kind::GroupBy)?;
478        if let Some(seen) = seen {
479            if seen.contains(&target) {
480                return Ok(None);
481            }
482            seen.push(target);
483        }
484        if result.iter().any(|g| g.target == target) {
485            return Ok(Some(target));
486        }
487        match sort.iter().find(|s| s.target == target) {
488            Some(item) => {
489                result
490                    .push(SortGroup { nulls_first: item.nulls_first && toplevel, ..item.clone() });
491            }
492            None => self.add_group(target, targets, result, raw_location(node))?,
493        }
494        Ok(Some(target))
495    }
496
497    /// `transformGroupingSet`: a grouping set with the targets of its items. A row in parentheses is a simple set with each item once.
498    fn grouping_set(
499        &mut self,
500        kind: GroupingSetKind,
501        content: &[Flat<'_>],
502        at: Option<usize>,
503        targets: &mut Vec<Target>,
504        sort: &[SortGroup],
505        result: &mut Vec<SortGroup>,
506    ) -> Result<GroupingSet> {
507        let mut sets = Vec::with_capacity(content.len());
508        for item in content {
509            sets.push(match item {
510                Flat::Row(nodes) => {
511                    let mut seen = Vec::new();
512                    let mut items = Vec::with_capacity(nodes.len());
513                    for &node in nodes {
514                        let target =
515                            self.group_item(node, Some(&mut seen), targets, sort, result, false)?;
516                        items.extend(target);
517                    }
518                    GroupingSet::Simple(items)
519                }
520                Flat::Set(kind, content, at) => {
521                    self.grouping_set(*kind, content, *at, targets, sort, result)?
522                }
523                Flat::Item(node) => {
524                    let target = self.group_item(*node, None, targets, sort, result, false)?;
525                    GroupingSet::Simple(target.into_iter().collect())
526                }
527            });
528        }
529        // The number of the sets of `CUBE` grows as a power of 2.
530        if kind == GroupingSetKind::GROUPING_SET_CUBE && sets.len() > 12 {
531            return Err(
532                Error::new(SqlState::TOO_MANY_COLUMNS, "CUBE is limited to 12 elements").at_opt(at)
533            );
534        }
535        Ok(match kind {
536            GroupingSetKind::GROUPING_SET_EMPTY => GroupingSet::Empty,
537            GroupingSetKind::GROUPING_SET_ROLLUP => GroupingSet::Rollup(sets),
538            GroupingSetKind::GROUPING_SET_CUBE => GroupingSet::Cube(sets),
539            _ => GroupingSet::Sets(sets),
540        })
541    }
542
543    /// `addTargetToSortList`.
544    pub(crate) fn add_sort(
545        &mut self,
546        by: &SortBy,
547        target: usize,
548        targets: &mut [Target],
549        sort: &mut Vec<SortGroup>,
550    ) -> Result<()> {
551        self.resolve_unknown(&mut targets[target])?;
552        let ty = targets[target].expr.ty;
553        // An error points at the operator of `USING`, or else at the expression.
554        let at = place(by.location).or_else(|| raw_location(by.node.as_ref()));
555        let (sort_op, eq_op, reverse) = match by.sortby_dir {
556            SortByDir::SORTBY_USING => self.using_operator(&by.useOp, ty, at)?,
557            dir => {
558                let reverse = dir == SortByDir::SORTBY_DESC;
559                let ops = typcache::operators(ty);
560                let sort_op = if reverse { ops.gt } else { ops.lt };
561                if sort_op == 0 {
562                    return Err(no_ordering(ty, at));
563                }
564                if ops.eq == 0 {
565                    return Err(no_equality(ty, at));
566                }
567                (sort_op, ops.eq, reverse)
568            }
569        };
570        let nulls_first = match by.sortby_nulls {
571            SortByNulls::SORTBY_NULLS_FIRST => true,
572            SortByNulls::SORTBY_NULLS_LAST => false,
573            _ => reverse,
574        };
575        // `targetIsInSortList`: a column is in the list once with an operator and its commutator.
576        let commutator = |op: u32| builtin::operator_by_oid(op).map_or(0, |o| o.commutator);
577        if !sort.iter().any(|s| {
578            s.target == target && (s.operator == sort_op || commutator(s.operator) == sort_op)
579        }) {
580            sort.push(SortGroup {
581                target,
582                operator: sort_op,
583                sort: function_of(sort_op),
584                equal: function_of(eq_op),
585                nulls_first,
586                hashable: typcache::hashable(eq_op, ty),
587            });
588        }
589        Ok(())
590    }
591
592    /// The operator of `ORDER BY ... USING op`, its `=` operator and true when it sorts in descending order.
593    fn using_operator(&self, names: &List, ty: u32, at: Option<usize>) -> Result<(u32, u32, bool)> {
594        let names: Vec<&str> = names
595            .iter()
596            .map(|n| match n {
597                Some(Node::String(s)) => Ok(&**s),
598                _ => Err(Error::internal("an operator name that is not a string")),
599            })
600            .collect::<Result<_>>()?;
601        let op = self.find_operator(&names, ty, ty, at)?;
602        // `compatible_oper`: the inputs must have the types of the operator with no cast.
603        if !is_binary_coercible(ty, op.left) || !is_binary_coercible(ty, op.right) {
604            let name = names.join(".");
605            let ty = types::name(ty);
606            return Err(Error::new(
607                SqlState::UNDEFINED_FUNCTION,
608                format!("operator requires run-time type coercion: {ty} {name} {ty}"),
609            )
610            .at_opt(at));
611        }
612        let Some((eq, reverse)) = typcache::equality_for_ordering(op.oid) else {
613            return Err(Error::new(
614                SqlState::WRONG_OBJECT_TYPE,
615                format!(
616                    "operator {} is not a valid ordering operator",
617                    names.last().copied().unwrap_or_default()
618                ),
619            )
620            .with_hint(
621                "Ordering operators must be \"<\" or \">\" members of btree operator families.",
622            )
623            .at_opt(at));
624        };
625        Ok((op.oid, eq, reverse))
626    }
627
628    /// `addTargetToGroupList`: a column of `DISTINCT` with the default operators of its type. A type with `=` and no order has no sort function.
629    fn add_group(
630        &mut self,
631        target: usize,
632        targets: &mut [Target],
633        list: &mut Vec<SortGroup>,
634        at: Option<usize>,
635    ) -> Result<()> {
636        self.resolve_unknown(&mut targets[target])?;
637        if list.iter().any(|s| s.target == target) {
638            return Ok(());
639        }
640        let ty = targets[target].expr.ty;
641        let ops = typcache::operators(ty);
642        if ops.eq == 0 {
643            return Err(no_equality(ty, at));
644        }
645        list.push(SortGroup {
646            target,
647            operator: ops.lt,
648            sort: function_of(ops.lt),
649            equal: function_of(ops.eq),
650            nulls_first: false,
651            hashable: typcache::hashable(ops.eq, ty),
652        });
653        Ok(())
654    }
655
656    /// `transformDistinctClause`: the items of `ORDER BY`, then the other columns of the select list or the other arguments of the aggregate call.
657    pub(crate) fn distinct_clause(
658        &mut self,
659        targets: &mut [Target],
660        sort: &[SortGroup],
661        is_agg: bool,
662    ) -> Result<Vec<SortGroup>> {
663        let mut list = Vec::new();
664        for item in sort {
665            let target = &targets[item.target];
666            if target.junk {
667                let message = if is_agg {
668                    "in an aggregate with DISTINCT, ORDER BY expressions must appear in argument list"
669                } else {
670                    "for SELECT DISTINCT, ORDER BY expressions must appear in select list"
671                };
672                return Err(invalid_reference(message.into(), target.expr.place()));
673            }
674            list.push(item.clone());
675        }
676        for i in 0..targets.len() {
677            if !targets[i].junk {
678                let at = targets[i].expr.place();
679                self.add_group(i, targets, &mut list, at)?;
680            }
681        }
682        if list.is_empty() {
683            let message = if is_agg {
684                "an aggregate with DISTINCT must have at least one argument"
685            } else {
686                "SELECT DISTINCT must have at least one column"
687            };
688            return Err(Error::new(SqlState::SYNTAX_ERROR, message));
689        }
690        Ok(list)
691    }
692
693    /// `transformDistinctOnClause`: the items of `ORDER BY` that `DISTINCT ON` names, then the other items of `DISTINCT ON`. The items of `DISTINCT ON` must come first in `ORDER BY`.
694    pub(crate) fn distinct_on_clause(
695        &mut self,
696        on: &List,
697        targets: &mut Vec<Target>,
698        sort: &[SortGroup],
699    ) -> Result<Vec<SortGroup>> {
700        let mut refs = Vec::with_capacity(on.len());
701        for node in on {
702            refs.push(self.target_sql92(node.as_ref(), targets, Kind::DistinctOn)?);
703        }
704        let mismatch = |at| {
705            invalid_reference(
706                "SELECT DISTINCT ON expressions must match initial ORDER BY expressions".into(),
707                at,
708            )
709        };
710        let mut list = Vec::new();
711        let mut skipped = false;
712        for item in sort {
713            match refs.iter().position(|&r| r == item.target) {
714                Some(_) if skipped => {
715                    let first = refs.iter().position(|&r| r == item.target);
716                    return Err(mismatch(first.and_then(|i| raw_location(on[i].as_ref()))));
717                }
718                Some(_) => list.push(item.clone()),
719                None => skipped = true,
720            }
721        }
722        for (node, &target) in on.iter().zip(&refs) {
723            if list.iter().any(|s| s.target == target) {
724                continue;
725            }
726            let at = raw_location(node.as_ref());
727            if skipped {
728                return Err(mismatch(at));
729            }
730            self.add_group(target, targets, &mut list, at)?;
731        }
732        Ok(list)
733    }
734
735    /// `transformLimitClause`: the value of `LIMIT` or `OFFSET` as `bigint`. It cannot read a column.
736    pub(crate) fn limit_clause(
737        &mut self,
738        node: Option<&Node>,
739        construct: &str,
740        with_ties: bool,
741    ) -> Result<Option<Expr>> {
742        let Some(node) = node else { return Ok(None) };
743        let expr = self.transform(Some(node))?;
744        let expr = self.coerce_to_specific(expr, oid::INT8, construct)?;
745        if let Some(var) = expr.first_var() {
746            return Err(invalid_reference(
747                format!("argument of {construct} must not contain variables"),
748                var.location,
749            ));
750        }
751        if with_ties && construct == "LIMIT" && matches!(node, Node::A_Const(c) if c.isnull) {
752            return Err(Error::new(
753                SqlState::INVALID_ROW_COUNT_IN_LIMIT_CLAUSE,
754                "row count cannot be null in FETCH FIRST ... WITH TIES clause",
755            ));
756        }
757        Ok(Some(expr))
758    }
759}
760
761/// The function of an operator, or 0.
762fn function_of(operator: u32) -> u32 {
763    builtin::operator_by_oid(operator).map_or(0, |op| op.code)
764}
765
766fn no_ordering(ty: u32, at: Option<usize>) -> Error {
767    Error::new(
768        SqlState::UNDEFINED_FUNCTION,
769        format!("could not identify an ordering operator for type {}", types::name(ty)),
770    )
771    .with_hint("Use an explicit ordering operator or modify the query.")
772    .at_opt(at)
773}
774
775/// `makeSortGroupClauseForSetOp`: the operators that a set operation uses for a column, to find the rows that are equal.
776pub(crate) fn set_group(target: usize, ty: u32, at: Option<usize>) -> Result<SortGroup> {
777    let ops = typcache::operators(ty);
778    if ops.eq == 0 {
779        return Err(no_equality(ty, at));
780    }
781    Ok(SortGroup {
782        target,
783        operator: ops.lt,
784        sort: function_of(ops.lt),
785        equal: function_of(ops.eq),
786        nulls_first: false,
787        hashable: typcache::hashable(ops.eq, ty),
788    })
789}
790
791fn no_equality(ty: u32, at: Option<usize>) -> Error {
792    Error::new(
793        SqlState::UNDEFINED_FUNCTION,
794        format!("could not identify an equality operator for type {}", types::name(ty)),
795    )
796    .at_opt(at)
797}