beck_core/
read.rs

1//! The read model: a program's maintained state as relations, and a small SQL over them.
2//!
3//! [`docs/05-tier-lowering.md`](../../../../../docs/05-tier-lowering.md) §5.3 names this as one of
4//! the four things the data tier owes:
5//!
6//! > Read models … one-shot queries and **pgwire access for the outside world**: `psql`, BI tools,
7//! > DBeaver see materialized views as ordinary tables — the single cheapest trust-builder for
8//! > adopting teams
9//!
10//! # What a read model is here, and what it is not
11//!
12//! §5.3's row also says "generated tables in the same Postgres", and that is **not** what this
13//! builds. A read model is not a second copy of the state written on the append path; it is the
14//! collection the fold already holds and the arrangement [`crate::engine`] already maintains,
15//! *projected*. Three consequences, and they are the argument for it:
16//!
17//! * **A read model costs nothing per event.** Nothing is written, nothing is projected, and the
18//!   sequencer is untouched — which is [`docs/23`](../../../../../docs/23-incremental-views-report.md)
19//!   §23.9's rule ("who advances it: not the sequencer") applied to a second kind of reader rather
20//!   than argued with.
21//! * **It cannot disagree with the page.** A durable projection is a second code path, and a second
22//!   code path over the same events is a thing that can drift. These rows are read from the same
23//!   arrangement the view renders from, so the recompute oracle already covers them.
24//! * **It is exactly as fresh as the query.** A query advances the dataflow to the log's head and
25//!   then reads, so a `SELECT` issued after an ack sees that ack's event. There is no projection
26//!   lag because there is no projection.
27//!
28//! What that costs is the one-transaction property [`67`](../../../../../docs/67-sqlite-report.md)
29//! §67.1 held open: an append and its projection are still not one transaction, because there is
30//! still no projection. §23.19 is the row-by-row list.
31//!
32//! # Where the tables come from
33//!
34//! | Table | Rows | Read from |
35//! |---|---|---|
36//! | a collection-valued field of the accumulator | its elements | the state value |
37//! | the accumulator's remaining scalar fields | one | the state value |
38//! | a declared signal that does not read the session | its elements, or one | the maintained node |
39//!
40//! The third row is the interesting one: **a read model is a view that does not depend on who is
41//! asking**, which is the same cut §5.3 draws for arrangement sharing. A `per_session` signal is not
42//! a table because a SQL client is not a session — it has no `Session` to be rendered for, and
43//! inventing one would answer a question nobody asked.
44//!
45//! # What this is not
46//!
47//! It is not a query planner, and it does not become one by having a join. What [`parse`] accepts
48//! is a documented subset — a scan with a `where`, an `order by` and a `limit`; an equi-join, inner
49//! or left; a `group by` with `count`, `min`, `max` and `sum`; `distinct`; and `union` — with the
50//! `from` list fixing a left-deep join order rather than a cost model choosing one. It exists so
51//! that an outside tool can read what the program holds, which is what §5.3's row is for.
52//!
53//! It does have a **scalar expression language** ([`Expr`]) — `case`, a call, a cast, `in`, `is`,
54//! `||`, and the four POSIX regular-expression operators — and that is a debt `pg_catalog` called
55//! in rather than a change of mind: `psql` writes all of them into the queries it sends the
56//! catalogue ([`crate::pg`]), and a catalogue that is a read model is read by this SQL or by
57//! nothing. It computes no arithmetic, because nothing asks for any. A subquery is parsed and
58//! answered only where it is **provably** row-independent (see [`Eval::subquery`]); a correlated
59//! one is refused by name, as is `having`.
60//!
61//! **What the relational half is made of is not here either.** A join, a `group by` and a
62//! `distinct` are compiled into a [`crate::plan::Plan`] by [`crate::query`] and run by
63//! [`crate::engine`], so the operators answering them are [`crate::plan::Op::Join`],
64//! [`crate::plan::Op::ArrangeBy`], [`crate::plan::Op::GroupBy`] and
65//! [`crate::plan::Op::Distinct`] — the ones a program's own view compiles to
66//! ([`docs/99`](../../../../../docs/99-the-data-tier-means-of-combination.md) §99.9 item 9). This
67//! module keeps the parser, the schema, the scan and the row-level `where`, `order by` and
68//! `limit` that are the same either way.
69
70use std::collections::{BTreeMap, BTreeSet};
71use std::fmt::Write as _;
72use std::sync::Arc;
73
74use crate::core::Value;
75use crate::plan::{Agg, OpId, Plan};
76use crate::split::Placed;
77use crate::ty::{Ty, TyDecl};
78
79// -------------------------------------------------------------------------------------------
80// Types
81// -------------------------------------------------------------------------------------------
82
83/// The four SQL types a Beck scalar maps onto.
84///
85/// Deliberately four. Every one of them is a type OID a Postgres client already knows, so a driver
86/// never has to ask the catalogue what it just received — which matters more than breadth here,
87/// because there is no catalogue to ask ([`Schema::CATALOGUE`] is what stands in for one).
88#[derive(Clone, Copy, Debug, PartialEq, Eq)]
89pub enum SqlTy {
90    Boolean,
91    Bigint,
92    Double,
93    Text,
94}
95
96impl SqlTy {
97    /// The Postgres type OID, as it goes on the wire in a `RowDescription`.
98    pub fn oid(self) -> u32 {
99        match self {
100            SqlTy::Boolean => 16,
101            SqlTy::Bigint => 20,
102            SqlTy::Text => 25,
103            SqlTy::Double => 701,
104        }
105    }
106
107    /// The width a fixed-size type has, or -1 for a variable one.
108    pub fn width(self) -> i16 {
109        match self {
110            SqlTy::Boolean => 1,
111            SqlTy::Bigint | SqlTy::Double => 8,
112            SqlTy::Text => -1,
113        }
114    }
115
116    pub fn name(self) -> &'static str {
117        match self {
118            SqlTy::Boolean => "boolean",
119            SqlTy::Bigint => "bigint",
120            SqlTy::Double => "double precision",
121            SqlTy::Text => "text",
122        }
123    }
124}
125
126#[derive(Clone, Debug)]
127pub struct Column {
128    pub name: Arc<str>,
129    pub ty: SqlTy,
130    /// Only an `Option[T]` field is nullable. Beck has no null, so this is the one place one comes
131    /// from — and a column that is not an `Option` never holds one.
132    pub nullable: bool,
133}
134
135/// Where a table's rows are read from.
136#[derive(Clone, Debug, PartialEq, Eq)]
137pub enum Source {
138    /// A path of field names from the accumulator to a collection, or to the accumulator itself.
139    ///
140    /// Read from the state value the fold produced, not from an arrangement: a base table's rows
141    /// *are* the fold's collection, and a scan is `O(rows)` in any database.
142    State(Vec<Arc<str>>),
143    /// A plan operator that does not read the session, read from the maintained dataflow.
144    ///
145    /// This is the one that earns the engine its keep: the rows of a derived table are whatever the
146    /// arrangement holds, and the arrangement was maintained for the page.
147    View(OpId),
148    /// The schema describing itself.
149    Catalogue,
150    /// One relation of the emulated `pg_catalog`, built from the schema by [`crate::pg`].
151    Pg(crate::pg::Rel),
152}
153
154/// How many rows a table can have, which is a fact about its shape rather than about its data.
155#[derive(Clone, Copy, Debug, PartialEq, Eq)]
156pub enum Cardinality {
157    /// A collection: as many rows as it has elements.
158    Many,
159    /// A record or a scalar: exactly one row, always.
160    One,
161}
162
163#[derive(Clone, Debug)]
164pub struct Table {
165    pub name: Arc<str>,
166    pub columns: Vec<Column>,
167    pub source: Source,
168    pub cardinality: Cardinality,
169    /// The Beck type one row stands for, for `beck explain sql` to print.
170    pub element: Arc<str>,
171}
172
173impl Table {
174    pub fn column(&self, name: &str) -> Option<(usize, &Column)> {
175        self.columns
176            .iter()
177            .enumerate()
178            .find(|(_, c)| c.name.as_ref() == name)
179    }
180
181    /// One value as one row's worth of *values*, one per column.
182    ///
183    /// This is the rule that says what a column **is**, and it is shared rather than restated:
184    /// [`Table::row`] builds a scan's cells from it and [`crate::query`] normalises a table's rows
185    /// with it before compiling them into a plan, so a `select` that scans and a `select` that
186    /// joins cannot disagree about which part of an element a column names.
187    ///
188    /// [`Value::Unit`] stands for a field the value does not have, which becomes NULL in every
189    /// column type.
190    pub fn row_values(&self, v: &Value) -> Vec<Value> {
191        match unwrap(v) {
192            // A record: one column per field, by name.
193            Value::Data(d) if d.variant.is_none() && !d.fields.is_empty() => self
194                .columns
195                .iter()
196                .map(|c| match d.fields.get(&c.name) {
197                    Some(f) => column_value(f),
198                    None => Value::Unit,
199                })
200                .collect(),
201            // A scalar, or anything else: the single column this table then has.
202            other => self.columns.iter().map(|_| column_value(other)).collect(),
203        }
204    }
205
206    /// One value as one row, coerced to the columns this table declares.
207    ///
208    /// Coerced rather than trusted: the column types come from the *declared* type and the value
209    /// comes from a running program, so a value that does not fit its column becomes NULL rather
210    /// than a wrongly-encoded field on the wire. Nothing in the corpus reaches that branch; the
211    /// branch is there because "cannot happen" is not a wire format.
212    pub fn row(&self, v: &Value) -> Vec<Cell> {
213        self.row_values(v)
214            .iter()
215            .zip(&self.columns)
216            .map(|(v, c)| cell_of(v, c))
217            .collect()
218    }
219}
220
221/// A value in one column, or SQL NULL.
222pub type Cell = Option<Datum>;
223
224#[derive(Clone, Debug, PartialEq)]
225pub enum Datum {
226    Boolean(bool),
227    Bigint(i64),
228    Double(f64),
229    Text(String),
230}
231
232impl Datum {
233    pub fn ty(&self) -> SqlTy {
234        match self {
235            Datum::Boolean(_) => SqlTy::Boolean,
236            Datum::Bigint(_) => SqlTy::Bigint,
237            Datum::Double(_) => SqlTy::Double,
238            Datum::Text(_) => SqlTy::Text,
239        }
240    }
241
242    /// The text form, which is both what the simple query protocol sends and what `ORDER BY`
243    /// compares for a text column.
244    pub fn text(&self) -> String {
245        match self {
246            Datum::Boolean(b) => if *b { "t" } else { "f" }.to_string(),
247            Datum::Bigint(i) => i.to_string(),
248            // Postgres prints a float with enough digits to round-trip, and so does Rust's `{}`
249            // for `f64` — except that Rust drops the fractional part of a whole number, where
250            // Postgres keeps none either. `1` and `1` agree; nothing here needs `1.0`.
251            Datum::Double(f) => f.to_string(),
252            Datum::Text(s) => s.clone(),
253        }
254    }
255}
256
257/// One Beck value in one column, or NULL.
258pub fn cell_of(v: &Value, c: &Column) -> Cell {
259    let v = unwrap(v);
260    // `None` is the only null this language has, and it is only reachable through an `Option`
261    // column — a non-nullable column holding one would be a value that does not fit its type.
262    if let Value::Data(d) = v {
263        if d.variant.as_deref() == Some("None") {
264            return None;
265        }
266        if d.variant.as_deref() == Some("Some") {
267            return match d.fields.values().next() {
268                Some(inner) => cell_of(inner, c),
269                None => None,
270            };
271        }
272    }
273    match (c.ty, v) {
274        (SqlTy::Boolean, Value::Bool(b)) => Some(Datum::Boolean(*b)),
275        (SqlTy::Bigint, Value::Int(i)) => Some(Datum::Bigint(*i)),
276        (SqlTy::Double, _) => v.as_f64().map(Datum::Double),
277        (SqlTy::Text, Value::Str(s)) => Some(Datum::Text(s.to_string())),
278        // A composite column — a list, a map, a nested record, a union variant. JSON is the wire
279        // form this language already has for a value a browser reads (`Value::to_json`), so it is
280        // the one a SQL client gets too rather than a second rendering invented here.
281        (SqlTy::Text, other) => Some(Datum::Text(match other {
282            Value::Unit => return None,
283            _ => serde_json::to_string(&other.to_json()).unwrap_or_else(|_| other.display()),
284        })),
285        _ => None,
286    }
287}
288
289/// One field as the value its column *is*: a newtype seen through, an `Option` flattened, and
290/// [`Value::Unit`] for the SQL NULL a `None` becomes.
291///
292/// The point is that two things agree. [`cell_of`] already saw through both when it built the cell
293/// a client is shown, so a `Str` behind a newtype has always **displayed** as its payload; what a
294/// join compares is the [`Value`] itself, and a key that compared `Id("p1")` where the column shows
295/// `p1` would answer no rows for two columns a person can see are equal. Normalising here rather
296/// than at the comparison is what makes that one rule instead of two.
297fn column_value(v: &Value) -> Value {
298    let v = unwrap(v);
299    if let Value::Data(d) = v {
300        match d.variant.as_deref() {
301            Some("None") => return Value::Unit,
302            Some("Some") => {
303                return match d.fields.values().next() {
304                    Some(inner) => column_value(inner),
305                    None => Value::Unit,
306                }
307            }
308            _ => {}
309        }
310    }
311    v.clone()
312}
313
314/// See through a newtype, which at run time is a one-field record with no variant.
315fn unwrap(v: &Value) -> &Value {
316    match v {
317        Value::Data(d) if d.variant.is_none() && d.fields.len() == 1 => {
318            match d.fields.values().next() {
319                Some(inner) => unwrap(inner),
320                None => v,
321            }
322        }
323        _ => v,
324    }
325}
326
327// -------------------------------------------------------------------------------------------
328// The schema
329// -------------------------------------------------------------------------------------------
330
331/// Every table a program's read model has.
332#[derive(Clone, Debug, Default)]
333pub struct Schema {
334    /// The program's own read models, in the `public` namespace — and [`Schema::CATALOGUE`].
335    pub tables: Vec<Table>,
336    /// `pg_catalog`, in the `pg_catalog` namespace: the same schema under the names an outside
337    /// tool already knows ([`crate::pg`]).
338    ///
339    /// A separate list rather than more entries in `tables`, because these describe the read
340    /// models and are not read models themselves: `select * from beck_columns` and
341    /// `beck explain sql` are about what the *program* holds, and a catalogue that listed itself
342    /// there would answer a question nobody asked.
343    pub pg: Vec<Table>,
344}
345
346impl Schema {
347    /// The name of the catalogue table, which says what a table is *derived from* — the question
348    /// `pg_catalog` has no column for, because PostgreSQL has no such thing to describe.
349    pub const CATALOGUE: &'static str = "beck_columns";
350
351    pub fn table(&self, name: &str) -> Option<&Table> {
352        self.tables.iter().find(|t| t.name.as_ref() == name)
353    }
354
355    /// A relation named by a `from` entry: a read model, or one of `pg_catalog`'s.
356    ///
357    /// An unqualified name is a read model first, so a program with a table called `pg_class`
358    /// gets its own. A name qualified with `pg_catalog` is only ever the catalogue's, and one
359    /// qualified with anything else is refused rather than searched for: two namespaces is all
360    /// there is, and a client that asked a third a question deserves to be told so.
361    pub fn relation(&self, namespace: Option<&str>, name: &str) -> Result<&Table, SqlError> {
362        match namespace {
363            None => self
364                .table(name)
365                .or_else(|| self.pg.iter().find(|t| t.name.as_ref() == name))
366                .ok_or_else(|| {
367                    SqlError::no_table(format!(
368                        "there is no read model called \"{name}\". `select * from {}` lists what \
369                         there is",
370                        Schema::CATALOGUE
371                    ))
372                }),
373            Some(crate::pg::CATALOG) => self
374                .pg
375                .iter()
376                .find(|t| t.name.as_ref() == name)
377                .ok_or_else(|| SqlError::no_table(crate::pg::Rel::missing(name))),
378            Some(crate::pg::PUBLIC) => self.table(name).ok_or_else(|| {
379                SqlError::no_table(format!(
380                    "there is no read model called \"{name}\". `select * from {}` lists what \
381                     there is",
382                    Schema::CATALOGUE
383                ))
384            }),
385            Some(other) => Err(SqlError::no_table(format!(
386                "there is no schema called \"{other}\" here. A program's read models are in \
387                 \"{}\" and the catalogue that describes them is in \"{}\"",
388                crate::pg::PUBLIC,
389                crate::pg::CATALOG
390            ))),
391        }
392    }
393
394    /// The rows of a table this module builds rather than reads from a running program.
395    ///
396    /// One place, so a scan and a join get the same rows: [`Rows::scan`] never sees one of these,
397    /// and a reader with no program behind it can still answer the catalogue.
398    pub fn builtin_rows(&self, t: &Table) -> Option<Vec<Value>> {
399        match &t.source {
400            Source::Catalogue => Some(self.catalogue_values()),
401            Source::Pg(rel) => Some(crate::pg::rows(*rel, self)),
402            _ => None,
403        }
404    }
405
406    /// Derive the read model of a sliced program.
407    pub fn of(placed: &Placed, plan: &Plan) -> Schema {
408        let types = &placed.program.types;
409        let mut tables: Vec<Table> = Vec::new();
410        let mut taken: BTreeSet<Arc<str>> = BTreeSet::new();
411
412        for role in &placed.roles.states {
413            let base: Vec<Arc<str>> = role.field.iter().cloned().collect();
414            let ty = resolve(&role.ty, types);
415            match collection_elem(&ty, types) {
416                // The whole accumulator is a collection: one table, named after the fold.
417                Some(elem) => push(
418                    &mut tables,
419                    &mut taken,
420                    table(
421                        role.name.clone(),
422                        &elem,
423                        types,
424                        Source::State(base),
425                        Cardinality::Many,
426                    ),
427                ),
428                None => {
429                    let fields = model_fields(&ty, types).unwrap_or_default();
430                    let mut scalars: Vec<(Arc<str>, Ty)> = Vec::new();
431                    for (name, fty) in fields {
432                        let fty = resolve(&fty, types);
433                        match collection_elem(&fty, types) {
434                            Some(elem) => {
435                                let mut path = base.clone();
436                                path.push(name.clone());
437                                push(
438                                    &mut tables,
439                                    &mut taken,
440                                    table(
441                                        name,
442                                        &elem,
443                                        types,
444                                        Source::State(path),
445                                        Cardinality::Many,
446                                    ),
447                                );
448                            }
449                            None => scalars.push((name, fty)),
450                        }
451                    }
452                    // Whatever is left of the accumulator is a singleton: `State(charged=0,
453                    // refused=0)` is one row of two columns, which is the relational shape of a
454                    // state that is not a collection. A fold whose every field is a collection
455                    // leaves nothing here and gets no such table.
456                    if !scalars.is_empty() {
457                        push(
458                            &mut tables,
459                            &mut taken,
460                            Table {
461                                name: role.name.clone(),
462                                columns: scalars
463                                    .iter()
464                                    .map(|(n, t)| column(n.clone(), t, types))
465                                    .collect(),
466                                source: Source::State(base.clone()),
467                                cardinality: Cardinality::One,
468                                element: Arc::from(ty.to_string()),
469                            },
470                        );
471                    }
472                }
473            }
474        }
475
476        // Derived signals, which is where a maintained arrangement becomes a table. The page is
477        // excluded by its type rather than by its name: `Html` is not a relation.
478        let by_op: BTreeMap<&str, OpId> = plan
479            .signals
480            .iter()
481            .map(|(n, id)| (n.as_ref(), *id))
482            .collect();
483        let folds: BTreeSet<&str> = placed
484            .roles
485            .states
486            .iter()
487            .map(|s| s.name.as_ref())
488            .collect();
489        for (name, &sig) in &placed.graph.by_name {
490            let Some(&op) = by_op.get(name.as_ref()) else {
491                continue;
492            };
493            if plan.nodes[op].per_session {
494                continue;
495            }
496            // The accumulator is not a table: its collections and its scalars are, and they are
497            // above. A `Signal[State]` here would be one row whose collection fields are rendered
498            // as JSON — the same data, in the shape nothing can query.
499            if folds.contains(name.as_ref()) {
500                continue;
501            }
502            let ty = resolve(
503                &crate::signal::signal_elem(&placed.graph.node(sig).ty),
504                types,
505            );
506            let t = match collection_elem(&ty, types) {
507                Some(elem) => table(
508                    name.clone(),
509                    &elem,
510                    types,
511                    Source::View(op),
512                    Cardinality::Many,
513                ),
514                // A record or a scalar signal is one row. A `Signal[State]` is neither useful nor
515                // harmful here — its fields are already base tables — so a name already taken
516                // wins, which `push` decides.
517                None if model_fields(&ty, types).is_some() || scalar(&ty).is_some() => {
518                    table(name.clone(), &ty, types, Source::View(op), Cardinality::One)
519                }
520                None => continue,
521            };
522            push(&mut tables, &mut taken, t);
523        }
524
525        tables.sort_by(|a, b| a.name.cmp(&b.name));
526        tables.push(Table {
527            name: Arc::from(Schema::CATALOGUE),
528            columns: [
529                "table_name",
530                "column_name",
531                "data_type",
532                "nullable",
533                "position",
534            ]
535            .iter()
536            .enumerate()
537            .map(|(i, n)| Column {
538                name: Arc::from(*n),
539                ty: if i == 4 {
540                    SqlTy::Bigint
541                } else if i == 3 {
542                    SqlTy::Boolean
543                } else {
544                    SqlTy::Text
545                },
546                nullable: false,
547            })
548            .collect(),
549            source: Source::Catalogue,
550            cardinality: Cardinality::Many,
551            element: Arc::from("Column"),
552        });
553        Schema {
554            tables,
555            pg: crate::pg::relations(),
556        }
557    }
558
559    /// The catalogue's own rows as **values**, which is what a query that joins it reads.
560    ///
561    /// It is built on demand: the catalogue is a handful of rows describing a schema that cannot
562    /// change while a process is running, and a cache would be a second copy of it to keep true.
563    pub fn catalogue_values(&self) -> Vec<Value> {
564        let mut rows = Vec::new();
565        for t in &self.tables {
566            for (i, c) in t.columns.iter().enumerate() {
567                rows.push(Value::record(
568                    "Column",
569                    None,
570                    [
571                        ("table_name", Value::text(t.name.to_string())),
572                        ("column_name", Value::text(c.name.to_string())),
573                        ("data_type", Value::text(c.ty.name().to_string())),
574                        ("nullable", Value::Bool(c.nullable)),
575                        ("position", Value::Int(i as i64 + 1)),
576                    ],
577                ));
578            }
579        }
580        rows
581    }
582
583    /// The schema as `CREATE TABLE` statements, for `beck explain sql`.
584    ///
585    /// Nothing executes this — there is no database to execute it against, and saying so is the
586    /// point. It is the shape a person needs in order to write the query they were going to write.
587    pub fn ddl(&self) -> String {
588        let mut out = String::new();
589        for t in &self.tables {
590            let what = match &t.source {
591                Source::State(path) if path.is_empty() => "the accumulator".to_string(),
592                Source::State(path) => format!("state.{}", join(path)),
593                Source::View(op) => format!("plan operator {op}, maintained and shared"),
594                Source::Catalogue => "this schema".to_string(),
595                Source::Pg(rel) => format!("this schema, as {}", rel.name()),
596            };
597            let _ = writeln!(
598                out,
599                "-- {} of {}, from {what}",
600                match t.cardinality {
601                    Cardinality::Many => "the elements",
602                    Cardinality::One => "one row",
603                },
604                t.element
605            );
606            let _ = writeln!(out, "create table {} (", quote_ident(&t.name));
607            let n = t.columns.len();
608            for (i, c) in t.columns.iter().enumerate() {
609                let _ = writeln!(
610                    out,
611                    "    {:<20} {}{}{}",
612                    quote_ident(&c.name),
613                    c.ty.name(),
614                    if c.nullable { "" } else { " not null" },
615                    if i + 1 == n { "" } else { "," }
616                );
617            }
618            let _ = writeln!(out, ");");
619        }
620        out
621    }
622}
623
624/// The words this SQL reads as syntax rather than as a name.
625///
626/// A Beck field may be called `distinct` or `order` — `corpus/17-derived.beck` has a `Summary` with
627/// a field called `distinct` — and a column whose name has to be quoted is a column a person must
628/// be *told* to quote. So the DDL quotes it, which is the one place they will see it written down.
629const RESERVED: &[&str] = &[
630    "abort", "and", "as", "asc", "begin", "by", "commit", "count", "cross", "desc", "discard",
631    "distinct", "end", "false", "from", "full", "group", "having", "inner", "is", "join", "left",
632    "limit", "natural", "not", "null", "offset", "on", "or", "order", "outer", "right", "rollback",
633    "select", "set", "start", "table", "true", "where",
634];
635
636/// A name as it has to be written in this SQL: bare when it can be, quoted when it cannot.
637pub fn quote_ident(name: &str) -> String {
638    let plain = !name.is_empty()
639        && !name.starts_with(|c: char| c.is_ascii_digit())
640        && name
641            .chars()
642            .all(|c| c == '_' || c.is_ascii_lowercase() || c.is_ascii_digit());
643    if plain && !RESERVED.contains(&name) {
644        return name.to_string();
645    }
646    format!("\"{}\"", name.replace('"', "\"\""))
647}
648
649fn join(path: &[Arc<str>]) -> String {
650    path.iter()
651        .map(|p| p.to_string())
652        .collect::<Vec<_>>()
653        .join(".")
654}
655
656/// Add a table unless its name is taken. First wins, and the order is base tables then derived
657/// ones, so a signal named after the fold does not shadow the fold's own collections.
658fn push(tables: &mut Vec<Table>, taken: &mut BTreeSet<Arc<str>>, t: Table) {
659    if taken.insert(t.name.clone()) {
660        tables.push(t);
661    }
662}
663
664fn table(
665    name: Arc<str>,
666    elem: &Ty,
667    types: &BTreeMap<Arc<str>, TyDecl>,
668    source: Source,
669    cardinality: Cardinality,
670) -> Table {
671    let elem = resolve(elem, types);
672    let columns = match model_fields(&elem, types) {
673        Some(fields) => fields
674            .into_iter()
675            .map(|(n, t)| column(n, &t, types))
676            .collect(),
677        // A collection of scalars, or of anything else: one column, and the row is the element.
678        None => vec![column(Arc::from("value"), &elem, types)],
679    };
680    Table {
681        name,
682        columns,
683        source,
684        cardinality,
685        element: Arc::from(elem.to_string()),
686    }
687}
688
689fn column(name: Arc<str>, ty: &Ty, types: &BTreeMap<Arc<str>, TyDecl>) -> Column {
690    let (ty, nullable) = sql_ty(ty, types);
691    Column { name, ty, nullable }
692}
693
694/// The SQL type of a Beck type, and whether it can be null.
695fn sql_ty(ty: &Ty, types: &BTreeMap<Arc<str>, TyDecl>) -> (SqlTy, bool) {
696    let ty = resolve(ty, types);
697    if let Ty::Con(n, args) = &ty {
698        if n.as_ref() == Ty::OPTION && args.len() == 1 {
699            return (sql_ty(&args[0], types).0, true);
700        }
701    }
702    (scalar(&ty).unwrap_or(SqlTy::Text), false)
703}
704
705/// The SQL type of a Beck *scalar*, or nothing if it is not one.
706fn scalar(ty: &Ty) -> Option<SqlTy> {
707    match ty {
708        Ty::Con(n, args) if args.is_empty() => match n.as_ref() {
709            Ty::INT => Some(SqlTy::Bigint),
710            Ty::FLOAT => Some(SqlTy::Double),
711            Ty::BOOL => Some(SqlTy::Boolean),
712            Ty::STR => Some(SqlTy::Text),
713            _ => None,
714        },
715        _ => None,
716    }
717}
718
719/// See through aliases and newtypes, which are the two declarations that mean "this type, spelled
720/// differently". A `model` and a `union` are not resolved: they are the thing itself.
721fn resolve(ty: &Ty, types: &BTreeMap<Arc<str>, TyDecl>) -> Ty {
722    let mut ty = ty.clone();
723    // Bounded because a `type` alias can be recursive in a program that did not compile, and this
724    // runs over whatever it is handed.
725    for _ in 0..16 {
726        let Ty::Con(name, args) = &ty else { return ty };
727        let next = match types.get(name) {
728            Some(TyDecl::Newtype { params, inner, .. }) => substitute(inner, params, args),
729            Some(TyDecl::Alias { params, ty: t, .. }) => substitute(t, params, args),
730            _ => return ty,
731        };
732        ty = next;
733    }
734    ty
735}
736
737fn substitute(ty: &Ty, params: &[Arc<str>], args: &[Ty]) -> Ty {
738    if params.is_empty() {
739        return ty.clone();
740    }
741    match ty {
742        Ty::Con(n, inner) if inner.is_empty() => match params.iter().position(|p| p == n) {
743            Some(i) if i < args.len() => args[i].clone(),
744            _ => ty.clone(),
745        },
746        Ty::Con(n, inner) => Ty::Con(
747            n.clone(),
748            inner.iter().map(|t| substitute(t, params, args)).collect(),
749        ),
750        _ => ty.clone(),
751    }
752}
753
754/// The element type of a `list[T]` or a `Map[K, V]`, or nothing.
755fn collection_elem(ty: &Ty, types: &BTreeMap<Arc<str>, TyDecl>) -> Option<Ty> {
756    match resolve(ty, types) {
757        Ty::Con(n, args) if n.as_ref() == Ty::LIST && args.len() == 1 => Some(args[0].clone()),
758        Ty::Con(n, args) if n.as_ref() == Ty::MAP && args.len() == 2 => Some(args[1].clone()),
759        _ => None,
760    }
761}
762
763/// A `model`'s fields, in the order they were written.
764///
765/// Declared order rather than name order, which is the one place this disagrees with the run-time
766/// representation ([`crate::core::Fields`] sorts by name, and `docs/46` §46.6 pinned that). Columns
767/// are read by name, so the disagreement costs nothing and the person reading `select *` gets their
768/// own declaration back.
769fn model_fields(ty: &Ty, types: &BTreeMap<Arc<str>, TyDecl>) -> Option<Vec<(Arc<str>, Ty)>> {
770    let Ty::Con(name, args) = resolve(ty, types) else {
771        return None;
772    };
773    match types.get(&name) {
774        Some(TyDecl::Model { params, fields, .. }) if !fields.is_empty() => Some(
775            fields
776                .iter()
777                .map(|(n, t)| (n.clone(), substitute(t, params, &args)))
778                .collect(),
779        ),
780        _ => None,
781    }
782}
783
784/// The elements of a collection value, in the order it holds them.
785pub fn elements(v: &Value) -> Vec<Value> {
786    match v {
787        Value::List(xs) => xs.to_vec(),
788        Value::Map(m) => m.iter().map(|(_, v)| v.clone()).collect(),
789        other => vec![other.clone()],
790    }
791}
792
793/// Follow a path of field names into a value.
794pub fn at_path(v: &Value, path: &[Arc<str>]) -> Option<Value> {
795    let mut cur = v.clone();
796    for step in path {
797        let Value::Data(d) = &cur else { return None };
798        cur = d.fields.get(step)?.clone();
799    }
800    Some(cur)
801}
802
803// -------------------------------------------------------------------------------------------
804// The query
805// -------------------------------------------------------------------------------------------
806
807/// What a query asks for.
808///
809/// The **relational** half is several tables joined by an equality, a `group by` with its
810/// aggregates, and `distinct`. None of those is interpreted here — [`crate::query`] compiles them
811/// into a [`crate::plan::Plan`] and [`crate::engine`] runs it, so the join in a `select` and the
812/// join in a `for` loop are one operator
813/// ([`docs/99`](../../../../../docs/99-the-data-tier-means-of-combination.md) §99.9 item 9).
814///
815/// The **scalar** half is [`Expr`], and it is a per-row expression language rather than the
816/// [`04`](../../../../../docs/04-compiler-architecture.md) §4.2 `Query` sub-language: it computes
817/// nothing a program could not, and it exists because `psql` writes `case`, a function call and a
818/// regular expression into the queries it sends the catalogue ([`crate::pg`]).
819#[derive(Clone, Debug)]
820pub struct Select {
821    /// `select distinct` — the algebra's δ, and [`crate::plan::Op::Distinct`] is what answers it.
822    pub distinct: bool,
823    pub items: Vec<Item>,
824    /// The tables, in the order they were written. Empty for `select 1`; one for a scan; more when
825    /// the query joins, and every entry after the first carries the equality that joins it.
826    pub from: Vec<From>,
827    /// The `where`, as the conjunction it is: every term must be true of a row.
828    ///
829    /// A conjunction rather than one expression because that is the unit a term can be *pushed
830    /// into a scan* as — [`crate::query`] splits these by the table each names — and `and` is the
831    /// operator that makes splitting them sound.
832    pub filter: Vec<Expr>,
833    /// `group by` — the columns whose distinct values are the output's rows.
834    pub group: Vec<Name>,
835    /// `order by`, in the order the keys were written; the first that distinguishes two rows
836    /// decides.
837    pub order: Vec<Order>,
838    pub limit: Option<usize>,
839    pub offset: usize,
840}
841
842/// One `order by` key.
843#[derive(Clone, Debug)]
844pub struct Order {
845    pub by: OrderBy,
846    pub asc: bool,
847}
848
849/// What an `order by` key names.
850#[derive(Clone, Debug)]
851pub enum OrderBy {
852    /// `order by 2` — the second column of the select list, one-based, as SQL numbers them.
853    Ordinal(usize),
854    /// An expression over the row, which for `order by c` is the column `c`. A name that matches
855    /// an output column's name is that output column, and only then a column of a table: SQL
856    /// resolves an `order by` against the select list first, and a query may order by something it
857    /// computed.
858    Expr(Expr),
859}
860
861/// One entry of the `from` list: a table, what this query calls it, and what joins it.
862#[derive(Clone, Debug)]
863pub struct From {
864    /// The schema qualifying the table's name, if it was written: `pg_catalog.pg_class`.
865    pub namespace: Option<String>,
866    /// The table's name in the schema.
867    pub table: String,
868    /// The name a qualified column reference uses — the alias, or the table's own name.
869    pub alias: String,
870    /// The `on` equalities, as (this table's column, an earlier table's column). Empty for the
871    /// first entry, which nothing joins to, and for a comma join, whose equality is in the
872    /// `where`.
873    pub on: Vec<(Name, Name)>,
874    /// `left join`: a row of the table before this one survives with nulls where this one has no
875    /// match. The catalogue is full of them — `pg_class left join pg_am` is how `psql` asks for a
876    /// table's access method without losing the tables that have none.
877    pub left: bool,
878    /// A `from` item that is a function call rather than a relation. Parsed so that a query
879    /// carrying one in a branch nothing evaluates is not refused for it, and refused by name if
880    /// anything asks it for a row.
881    pub function: Option<String>,
882}
883
884/// A column reference, qualified by a table's name in this query or not.
885#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
886pub struct Name {
887    pub table: Option<String>,
888    pub column: String,
889}
890
891impl Name {
892    pub fn bare(column: impl Into<String>) -> Name {
893        Name {
894            table: None,
895            column: column.into(),
896        }
897    }
898}
899
900impl std::fmt::Display for Name {
901    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
902        match &self.table {
903            Some(t) => write!(f, "{t}.{}", self.column),
904            None => f.write_str(&self.column),
905        }
906    }
907}
908
909#[derive(Clone, Debug)]
910pub enum Item {
911    /// `*`, or `t.*`.
912    All(Option<String>),
913    Column(Name, Option<String>),
914    Count(Option<String>),
915    /// `min(c)`, `max(c)` or `sum(c)` — the three aggregates whose answer depends on what the rows
916    /// say. [`crate::plan::Op::GroupBy`] is what maintains each, and `count` is not one of them
917    /// because a count needs nothing of the row at all.
918    Aggregate(Agg, Name, Option<String>),
919    Literal(Datum, Option<String>),
920    /// Anything else a select list can hold — a `case`, a call, a comparison, a cast.
921    ///
922    /// Separate from [`Item::Column`] and [`Item::Literal`] rather than subsuming them, because
923    /// those two are what [`crate::query`] compiles into the plan for a `group by` and a
924    /// `distinct`: an expression there would be an expression *inside* an operator, and this
925    /// evaluates them over the rows an operator produced.
926    Expr(Expr, Option<String>),
927}
928
929impl Item {
930    /// Whether this item is an aggregate, which is what decides that a query groups.
931    pub fn aggregates(&self) -> bool {
932        matches!(self, Item::Count(_) | Item::Aggregate(..))
933    }
934}
935
936/// A scalar expression, evaluated over one row.
937///
938/// Every variant here is something a catalogue query writes. What is *not* here is arithmetic,
939/// because nothing asks for it: a read model computes its numbers in the program.
940#[derive(Clone, Debug)]
941pub enum Expr {
942    Column(Name),
943    /// A literal, or `null` — which is why this is a [`Cell`] rather than a [`Datum`].
944    Literal(Cell),
945    And(Vec<Expr>),
946    Or(Vec<Expr>),
947    Not(Box<Expr>),
948    /// `a = b`, and the other five comparisons. Three-valued: a comparison against NULL is
949    /// unknown, and unknown is not true.
950    Cmp(Box<Expr>, CmpOp, Box<Expr>),
951    /// `a is null` / `a is not null`, and `a is true` / `a is not false`.
952    Is {
953        value: Box<Expr>,
954        /// `None` for `is null`.
955        to: Option<bool>,
956        negated: bool,
957    },
958    /// `c in ('r', 'v')` — the form `psql` narrows `relkind` with.
959    In {
960        value: Box<Expr>,
961        list: Vec<Expr>,
962        negated: bool,
963    },
964    /// `~`, `!~`, `~*`, `!~*` — a POSIX regular expression match, run by a simulation over a set
965    /// of states rather than by backtracking, because the pattern arrives from a client.
966    Match {
967        value: Box<Expr>,
968        pattern: Box<Expr>,
969        negated: bool,
970        insensitive: bool,
971    },
972    /// `case … when … then … else … end`, in both SQL's forms.
973    ///
974    /// **Lazy**, as SQL specifies: the arms after the one that matched are not evaluated. That is
975    /// load-bearing here rather than an optimisation — `psql` writes `case when c.reloftype = 0
976    /// then '' else c.reloftype::regtype::text end`, and the branch this catalogue cannot compute
977    /// is the branch no row reaches.
978    Case {
979        operand: Option<Box<Expr>>,
980        arms: Vec<(Expr, Expr)>,
981        otherwise: Option<Box<Expr>>,
982    },
983    /// A function call. [`crate::pg::call`] is what answers one, and a name it does not know is
984    /// refused *by name* rather than answered NULL.
985    Call {
986        name: String,
987        args: Vec<Expr>,
988    },
989    /// `x::text`. A cast to a type this has is the value; to anything else it is refused by name,
990    /// which is why the `case` above has to be lazy.
991    Cast {
992        value: Box<Expr>,
993        ty: String,
994    },
995    /// `a || b`, string concatenation.
996    Concat(Box<Expr>, Box<Expr>),
997    /// A scalar subquery — `(select … from …)`.
998    ///
999    /// The `id` distinguishes two subqueries in one statement, so the answer to each can be
1000    /// computed once rather than once per row: see [`Eval::subquery`] for why it is the same for
1001    /// every row.
1002    Subquery {
1003        id: usize,
1004        select: Box<Select>,
1005    },
1006    /// `array(select …)` and `any(x)`: parsed, and refused by name if a row ever asks. Both appear
1007    /// in `psql`'s catalogue queries inside branches that no row reaches, and a query refused at
1008    /// parse time for a branch it never takes is a `\d` that does not work.
1009    Array {
1010        id: usize,
1011        select: Box<Select>,
1012    },
1013    Any(Box<Expr>),
1014    /// `x[i]`, an array subscript. Parsed for [`Expr::Array`]'s reason and refused for the same
1015    /// one.
1016    Subscript(Box<Expr>, Box<Expr>),
1017}
1018
1019impl Expr {
1020    /// Every column this expression names, including those in a subquery it carries.
1021    ///
1022    /// [`crate::query`] uses it to decide which table a `where` term narrows, so a term that names
1023    /// a column inside a subquery counts as naming it: pushing such a term into one table's scan
1024    /// would evaluate the subquery against the wrong rows.
1025    pub fn names(&self, out: &mut Vec<Name>) {
1026        match self {
1027            Expr::Column(n) => out.push(n.clone()),
1028            Expr::Literal(_) => {}
1029            Expr::And(xs) | Expr::Or(xs) => xs.iter().for_each(|x| x.names(out)),
1030            Expr::Not(x) | Expr::Any(x) => x.names(out),
1031            Expr::Cmp(a, _, b) | Expr::Concat(a, b) | Expr::Subscript(a, b) => {
1032                a.names(out);
1033                b.names(out);
1034            }
1035            Expr::Is { value, .. } | Expr::Cast { value, .. } => value.names(out),
1036            Expr::In { value, list, .. } => {
1037                value.names(out);
1038                list.iter().for_each(|x| x.names(out));
1039            }
1040            Expr::Match { value, pattern, .. } => {
1041                value.names(out);
1042                pattern.names(out);
1043            }
1044            Expr::Case {
1045                operand,
1046                arms,
1047                otherwise,
1048            } => {
1049                if let Some(o) = operand {
1050                    o.names(out);
1051                }
1052                for (w, t) in arms {
1053                    w.names(out);
1054                    t.names(out);
1055                }
1056                if let Some(e) = otherwise {
1057                    e.names(out);
1058                }
1059            }
1060            Expr::Call { args, .. } => args.iter().for_each(|x| x.names(out)),
1061            Expr::Subquery { select, .. } | Expr::Array { select, .. } => {
1062                for item in &select.items {
1063                    match item {
1064                        Item::Column(n, _) => out.push(n.clone()),
1065                        Item::Aggregate(_, n, _) => out.push(n.clone()),
1066                        Item::Expr(e, _) => e.names(out),
1067                        _ => {}
1068                    }
1069                }
1070                select.filter.iter().for_each(|x| x.names(out));
1071            }
1072        }
1073    }
1074}
1075
1076#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1077pub enum CmpOp {
1078    Eq,
1079    Ne,
1080    Lt,
1081    Le,
1082    Gt,
1083    Ge,
1084}
1085
1086impl CmpOp {
1087    fn holds(self, o: std::cmp::Ordering) -> bool {
1088        match self {
1089            CmpOp::Eq => o.is_eq(),
1090            CmpOp::Ne => o.is_ne(),
1091            CmpOp::Lt => o.is_lt(),
1092            CmpOp::Le => o.is_le(),
1093            CmpOp::Gt => o.is_gt(),
1094            CmpOp::Ge => o.is_ge(),
1095        }
1096    }
1097}
1098
1099/// A statement, which is a `select` or one of the two things a client says before it asks for
1100/// anything.
1101#[derive(Clone, Debug)]
1102pub enum Stmt {
1103    Select(Select),
1104    /// Two or more selects, `union`ed. The branches answer in turn and the answers are stacked;
1105    /// without `all` the stack is deduplicated, which is what `union` means.
1106    ///
1107    /// It is here because `psql` asks for a table's publications as a union of three queries over
1108    /// relations a read model has none of, and one of the three is what tells it there are none.
1109    Union {
1110        branches: Vec<Select>,
1111        all: bool,
1112        order: Vec<Order>,
1113        limit: Option<usize>,
1114        offset: usize,
1115    },
1116    /// `SET …` and `BEGIN`/`COMMIT`/`ROLLBACK`: acknowledged and ignored. A read model has nothing
1117    /// to set and nothing to roll back, and a driver that opens a transaction out of habit should
1118    /// not be refused for it.
1119    Ignored(&'static str),
1120}
1121
1122/// What a query answered.
1123pub struct Answer {
1124    pub columns: Vec<Column>,
1125    pub rows: Vec<Vec<Cell>>,
1126    /// The `CommandComplete` tag.
1127    pub tag: String,
1128}
1129
1130/// Why a query could not be answered. The message reaches the client verbatim.
1131#[derive(Clone, Debug, PartialEq, Eq)]
1132pub struct SqlError {
1133    pub message: String,
1134    /// The five-character SQLSTATE. A driver reads this; a person reads the message.
1135    pub code: &'static str,
1136}
1137
1138impl SqlError {
1139    pub fn syntax(m: impl Into<String>) -> SqlError {
1140        SqlError {
1141            message: m.into(),
1142            code: "42601",
1143        }
1144    }
1145    pub fn no_table(m: impl Into<String>) -> SqlError {
1146        SqlError {
1147            message: m.into(),
1148            code: "42P01",
1149        }
1150    }
1151    pub fn no_column(m: impl Into<String>) -> SqlError {
1152        SqlError {
1153            message: m.into(),
1154            code: "42703",
1155        }
1156    }
1157    pub fn unsupported(m: impl Into<String>) -> SqlError {
1158        SqlError {
1159            message: m.into(),
1160            code: "0A000",
1161        }
1162    }
1163}
1164
1165impl std::fmt::Display for SqlError {
1166    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1167        f.write_str(&self.message)
1168    }
1169}
1170
1171impl std::error::Error for SqlError {}
1172
1173/// Where a table's rows come from. Implemented by whoever holds the running program.
1174pub trait Rows {
1175    /// Every row of one table, in the order the collection holds them.
1176    fn scan(&self, table: &Table) -> Result<Vec<Value>, SqlError>;
1177
1178    /// **How many rows there are, if that can be answered without building them.**
1179    ///
1180    /// [`23`](../../../../../docs/23-incremental-views-report.md) §23.19: "`count(*)` without
1181    /// scanning — **not built**. The plan's `list_len` is ±1 per delta; the SQL count is over the
1182    /// rows it scanned." This is the seam that closes it. A maintained arrangement and a `Map` in
1183    /// the accumulator each know their size, so a query whose whole answer is a number should not
1184    /// clone every value and build a `Cell` for every column of every one.
1185    ///
1186    /// `None` means "not without a scan", and the caller falls back — so an implementation that
1187    /// does not override this is correct and merely as slow as it was. That default is the point:
1188    /// the seam cannot make a reader wrong, only faster.
1189    fn count(&self, table: &Table) -> Result<Option<u64>, SqlError> {
1190        let _ = table;
1191        Ok(None)
1192    }
1193
1194    /// **The backend a relational query's operators are prepared against.**
1195    ///
1196    /// A `join`, a `group by` and a `distinct` are compiled into a [`crate::plan::Plan`] and run by
1197    /// [`crate::engine`] rather than interpreted here
1198    /// ([`docs/99`](../../../../../docs/99-the-data-tier-means-of-combination.md) §99.9 item 9), and
1199    /// preparing a plan means turning its per-element functions into
1200    /// [`crate::backend::Callable`]s — which is a backend's job and not this module's.
1201    ///
1202    /// `None` is the honest answer for a reader with no executor behind it: those three queries are
1203    /// refused with a message saying so, and every other query is answered exactly as before. The
1204    /// default is `None` for [`Rows::count`]'s reason — a seam may make a reader faster or narrower,
1205    /// never wrong.
1206    fn backend(&self) -> Option<&dyn crate::backend::Backend> {
1207        None
1208    }
1209}
1210
1211/// One column of the rows a query produced, and the table name a reference may qualify it with.
1212///
1213/// A `Column` is what goes on the wire; this is what a `where`, an `order by` and a select list
1214/// resolve a name against. The two are separate because a joined row has columns from several
1215/// tables and two of them may share a name — which is a question about the *query* rather than
1216/// about the wire, where a column is a name and a type OID and nothing else.
1217#[derive(Clone, Debug)]
1218pub struct Field {
1219    pub column: Column,
1220    /// The table this came from, as this query knows it. `None` for a computed column — an
1221    /// aggregate, a literal, or anything given an alias, none of which a qualified name may reach.
1222    pub of: Option<Arc<str>>,
1223}
1224
1225impl Field {
1226    /// A base table's own columns, which is what a query over one table resolves against.
1227    pub fn of_table(t: &Table) -> Vec<Field> {
1228        Field::of_table_as(t, t.name.clone())
1229    }
1230
1231    /// The same, under the name the query calls the table.
1232    ///
1233    /// A qualified reference names the *alias* — `from pg_attribute a … where a.attnum > 0` — so a
1234    /// query over one table has to resolve names against the alias exactly as a join does. One
1235    /// rule, in both places, because a name that resolved one way in a scan and another in a join
1236    /// would be two.
1237    pub fn of_table_as(t: &Table, alias: Arc<str>) -> Vec<Field> {
1238        t.columns
1239            .iter()
1240            .map(|c| Field {
1241                column: c.clone(),
1242                of: Some(alias.clone()),
1243            })
1244            .collect()
1245    }
1246}
1247
1248impl Schema {
1249    /// Parse and run one statement.
1250    pub fn run(&self, sql: &str, rows: &dyn Rows) -> Result<Answer, SqlError> {
1251        match parse(sql)? {
1252            Stmt::Ignored(tag) => Ok(Answer {
1253                columns: Vec::new(),
1254                rows: Vec::new(),
1255                tag: tag.to_string(),
1256            }),
1257            Stmt::Select(s) => self.select(&s, rows),
1258            Stmt::Union {
1259                branches,
1260                all,
1261                order,
1262                limit,
1263                offset,
1264            } => self.union(&branches, all, &order, limit, offset, rows),
1265        }
1266    }
1267
1268    /// The branches in turn, stacked, and deduplicated unless `all`.
1269    ///
1270    /// `O(rows log rows)` for the deduplication, over the rows the branches produced together.
1271    #[allow(clippy::too_many_arguments)]
1272    fn union(
1273        &self,
1274        branches: &[Select],
1275        all: bool,
1276        order: &[Order],
1277        limit: Option<usize>,
1278        offset: usize,
1279        rows_of: &dyn Rows,
1280    ) -> Result<Answer, SqlError> {
1281        let mut columns: Vec<Column> = Vec::new();
1282        let mut rows: Vec<Vec<Cell>> = Vec::new();
1283        for (i, b) in branches.iter().enumerate() {
1284            let answer = self.select(b, rows_of)?;
1285            if i == 0 {
1286                columns = answer.columns;
1287            } else if answer.columns.len() != columns.len() {
1288                return Err(SqlError::syntax(format!(
1289                    "each `union` branch has to answer the same number of columns; the first \
1290                     answers {} and this one answers {}",
1291                    columns.len(),
1292                    answer.columns.len()
1293                )));
1294            }
1295            rows.extend(answer.rows);
1296        }
1297        if !all {
1298            let mut seen = BTreeSet::new();
1299            rows.retain(|r| seen.insert(row_key(r)));
1300        }
1301        let fields: Vec<Field> = columns
1302            .iter()
1303            .map(|c| Field {
1304                column: c.clone(),
1305                of: None,
1306            })
1307            .collect();
1308        let proj: Vec<Proj> = (0..columns.len()).map(Proj::Column).collect();
1309        let ev = Eval::new(self, &fields, rows_of);
1310        let mut rows = order_rows(&ev, order, &columns, &proj, rows)?;
1311        cut(&mut rows, offset, limit);
1312        Ok(Answer {
1313            tag: format!("SELECT {}", rows.len()),
1314            columns,
1315            rows,
1316        })
1317    }
1318
1319    /// What a statement's result looks like, without running it. `Describe` needs this before
1320    /// `Execute` has happened.
1321    pub fn describe(&self, sql: &str) -> Result<Vec<Column>, SqlError> {
1322        match parse(sql)? {
1323            Stmt::Ignored(_) => Ok(Vec::new()),
1324            Stmt::Union { branches, .. } => match branches.first() {
1325                Some(first) => self.describe_select(first),
1326                None => Ok(Vec::new()),
1327            },
1328            Stmt::Select(s) => self.describe_select(&s),
1329        }
1330    }
1331
1332    fn describe_select(&self, s: &Select) -> Result<Vec<Column>, SqlError> {
1333        if crate::query::relational(s) {
1334            let compiled = crate::query::compile(self, s)?;
1335            if compiled.projected {
1336                return Ok(compiled.fields.iter().map(|f| f.column.clone()).collect());
1337            }
1338            return Ok(self.project_columns(s, &compiled.fields)?.0);
1339        }
1340        let fields = self.scan_fields(s)?;
1341        Ok(self.project_columns(s, &fields)?.0)
1342    }
1343
1344    /// The columns a one-table query resolves names against, under the name it calls the table.
1345    fn scan_fields(&self, s: &Select) -> Result<Vec<Field>, SqlError> {
1346        Ok(match (self.resolve_from(s)?, s.from.first()) {
1347            (Some(t), Some(f)) => Field::of_table_as(t, Arc::from(f.alias.as_str())),
1348            _ => Vec::new(),
1349        })
1350    }
1351
1352    /// The one table a non-relational query reads, if it has one.
1353    fn resolve_from(&self, s: &Select) -> Result<Option<&Table>, SqlError> {
1354        match s.from.first() {
1355            None => Ok(None),
1356            Some(f) => {
1357                if let Some(call) = &f.function {
1358                    return Err(SqlError::unsupported(format!(
1359                        "`{call}(…)` in a `from` is a set-returning function, and this read model \
1360                         has none: what a `from` names here is a relation"
1361                    )));
1362                }
1363                self.relation(f.namespace.as_deref(), &f.table).map(Some)
1364            }
1365        }
1366    }
1367
1368    /// The columns a select produces, and how to build each from a source row.
1369    fn project_columns(
1370        &self,
1371        s: &Select,
1372        fields: &[Field],
1373    ) -> Result<(Vec<Column>, Vec<Proj>), SqlError> {
1374        let mut columns = Vec::new();
1375        let mut proj = Vec::new();
1376        for item in &s.items {
1377            match item {
1378                Item::All(qualifier) => {
1379                    if fields.is_empty() {
1380                        return Err(SqlError::syntax("`select *` needs a `from`"));
1381                    }
1382                    for (i, f) in fields.iter().enumerate() {
1383                        if let Some(t) = qualifier {
1384                            if f.of.as_deref() != Some(t.as_str()) {
1385                                continue;
1386                            }
1387                        }
1388                        columns.push(f.column.clone());
1389                        proj.push(Proj::Column(i));
1390                    }
1391                }
1392                Item::Column(name, alias) => {
1393                    if fields.is_empty() {
1394                        return Err(SqlError::no_column(format!(
1395                            "there is no column \"{name}\" here, because there is no `from`"
1396                        )));
1397                    }
1398                    let i = resolve_field(fields, name)?;
1399                    let mut c = fields[i].column.clone();
1400                    if let Some(a) = alias {
1401                        c.name = Arc::from(a.as_str());
1402                    }
1403                    columns.push(c);
1404                    proj.push(Proj::Column(i));
1405                }
1406                Item::Count(alias) => {
1407                    columns.push(Column {
1408                        name: Arc::from(alias.as_deref().unwrap_or("count")),
1409                        ty: SqlTy::Bigint,
1410                        nullable: false,
1411                    });
1412                    proj.push(Proj::Count);
1413                }
1414                // An aggregate reaches this only on the path that did not compile a plan, and
1415                // nothing routes one there: `query::relational` sends every query with one to the
1416                // plan, where the operator that answers it lives.
1417                Item::Aggregate(agg, name, _) => {
1418                    return Err(SqlError::unsupported(format!(
1419                        "`{}({name})` is a question about a group, and this query has none",
1420                        agg.name()
1421                    )))
1422                }
1423                Item::Literal(d, alias) => {
1424                    columns.push(Column {
1425                        name: Arc::from(alias.as_deref().unwrap_or("?column?")),
1426                        ty: d.ty(),
1427                        nullable: false,
1428                    });
1429                    proj.push(Proj::Literal(d.clone()));
1430                }
1431                // An expression's type is not worked out before it is evaluated: it may be a
1432                // `case` whose arms disagree, or a call whose answer depends on a row. Text is
1433                // what every client can read whatever comes back, and NULL is possible for all of
1434                // them, which is what `nullable` says.
1435                Item::Expr(e, alias) => {
1436                    columns.push(Column {
1437                        name: Arc::from(match alias.as_deref() {
1438                            Some(a) => a,
1439                            // A call's column is named after the function, as PostgreSQL names
1440                            // one — `select version()` has a column called `version`.
1441                            None => match e {
1442                                Expr::Call { name, .. } => name.as_str(),
1443                                _ => "?column?",
1444                            },
1445                        }),
1446                        ty: SqlTy::Text,
1447                        nullable: true,
1448                    });
1449                    proj.push(Proj::Expr(e.clone()));
1450                }
1451            }
1452        }
1453        Ok((columns, proj))
1454    }
1455
1456    fn select(&self, s: &Select, rows_of: &dyn Rows) -> Result<Answer, SqlError> {
1457        // A join, a `group by` or a `distinct`: compiled into the plan and run by the engine, so
1458        // the operators are the ones a program's view uses (docs/99 §99.9 item 9). What comes back
1459        // is rows and what they are called; the `where` this could not push into a scan, the
1460        // `order by` and the `limit` are below, shared with every other query.
1461        if crate::query::relational(s) {
1462            let compiled = crate::query::compile(self, s)?;
1463            let rows = compiled.run(self, rows_of)?;
1464            return self.finish(
1465                s,
1466                &compiled.fields,
1467                rows,
1468                &compiled.residual,
1469                compiled.projected,
1470                rows_of,
1471            );
1472        }
1473
1474        let table = self.resolve_from(s)?;
1475        let fields = self.scan_fields(s)?;
1476        let (columns, proj) = self.project_columns(s, &fields)?;
1477
1478        // `select count(*) from t`, with nothing to narrow it: the answer is the collection's size,
1479        // and the collection already knows it (§23.19). Everything below this would clone every
1480        // value, build a `Cell` per column of every row, and then count the rows — `O(n)` cells for
1481        // an answer that is one integer.
1482        //
1483        // The conditions are conservative on purpose. A `where` needs the rows to test; an `order`,
1484        // `limit` or `offset` is applied *before* the collapse below, so honouring one of those on
1485        // this path would mean reproducing that behaviour rather than skipping work.
1486        if let Some(t) = table {
1487            let bare = proj.iter().any(|p| matches!(p, Proj::Count))
1488                && proj
1489                    .iter()
1490                    .all(|p| matches!(p, Proj::Count | Proj::Literal(_)))
1491                && s.filter.is_empty()
1492                && s.order.is_empty()
1493                && s.limit.is_none()
1494                && s.offset == 0;
1495            if bare {
1496                let n = match self.builtin_rows(t) {
1497                    Some(rows) => Some(rows.len() as u64),
1498                    None => rows_of.count(t)?,
1499                };
1500                if let Some(n) = n {
1501                    let n = match t.cardinality {
1502                        Cardinality::Many => n,
1503                        Cardinality::One => n.min(1),
1504                    };
1505                    let row: Vec<Cell> = proj
1506                        .iter()
1507                        .map(|p| match p {
1508                            Proj::Count => Some(Datum::Bigint(n as i64)),
1509                            Proj::Literal(d) => Some(d.clone()),
1510                            Proj::Column(_) | Proj::Expr(_) => None,
1511                        })
1512                        .collect();
1513                    return Ok(Answer {
1514                        tag: "SELECT 1".to_string(),
1515                        columns,
1516                        rows: vec![row],
1517                    });
1518                }
1519            }
1520        }
1521
1522        // `select 1` and friends: one row, no table, and the four things a driver asks before it
1523        // trusts a connection.
1524        let Some(t) = table else {
1525            let ev = Eval::new(self, &fields, rows_of);
1526            let row: Vec<Cell> = proj
1527                .iter()
1528                .map(|p| match p {
1529                    Proj::Literal(d) => Ok(Some(d.clone())),
1530                    Proj::Count => Ok(Some(Datum::Bigint(1))),
1531                    Proj::Expr(e) => ev.cell(e, &[]),
1532                    Proj::Column(_) => Ok(None),
1533                })
1534                .collect::<Result<_, _>>()?;
1535            return Ok(Answer {
1536                tag: "SELECT 1".to_string(),
1537                columns,
1538                rows: vec![row],
1539            });
1540        };
1541
1542        let rows: Vec<Vec<Cell>> = match self.builtin_rows(t) {
1543            Some(values) => values.iter().map(|v| t.row(v)).collect(),
1544            None => {
1545                let values = rows_of.scan(t)?;
1546                match t.cardinality {
1547                    Cardinality::Many => values.iter().map(|v| t.row(v)).collect(),
1548                    // A singleton is one row even when the reader hands over the value inside a
1549                    // one-element list, which is what `elements` does with a record.
1550                    Cardinality::One => values.iter().take(1).map(|v| t.row(v)).collect(),
1551                }
1552            }
1553        };
1554        self.finish(s, &fields, rows, &s.filter, false, rows_of)
1555    }
1556
1557    /// Filter, order, project, and cut — the half of a `select` that is the same whether the rows
1558    /// were scanned out of a collection or produced by the plan's operators.
1559    fn finish(
1560        &self,
1561        s: &Select,
1562        fields: &[Field],
1563        mut rows: Vec<Vec<Cell>>,
1564        filter: &[Expr],
1565        projected: bool,
1566        rows_of: &dyn Rows,
1567    ) -> Result<Answer, SqlError> {
1568        let ev = Eval::new(self, fields, rows_of);
1569
1570        // The plan already projected: its operators were compiled from the select list, so its
1571        // rows are the answer and the only thing left is what a `where` could not be pushed into.
1572        let (columns, proj) = match projected {
1573            true => (
1574                fields.iter().map(|f| f.column.clone()).collect(),
1575                (0..fields.len()).map(Proj::Column).collect(),
1576            ),
1577            false => self.project_columns(s, fields)?,
1578        };
1579
1580        // Filter, then order, then offset and limit — the order SQL specifies, and the order that
1581        // makes `limit` mean what a person expects.
1582        if !filter.is_empty() {
1583            let mut kept = Vec::with_capacity(rows.len());
1584            for row in rows {
1585                if ev.holds(filter, &row)? {
1586                    kept.push(row);
1587                }
1588            }
1589            rows = kept;
1590        }
1591        rows = order_rows(&ev, &s.order, &columns, &proj, rows)?;
1592        cut(&mut rows, s.offset, s.limit);
1593
1594        if projected {
1595            return Ok(Answer {
1596                tag: format!("SELECT {}", rows.len()),
1597                columns,
1598                rows,
1599            });
1600        }
1601
1602        // `count(*)` collapses. Mixing it with a column would be a group-by, which this path has
1603        // none of, so it is refused at parse time rather than answered wrongly.
1604        let out: Vec<Vec<Cell>> = if proj.iter().any(|p| matches!(p, Proj::Count)) {
1605            let n = rows.len();
1606            vec![proj
1607                .iter()
1608                .map(|p| match p {
1609                    Proj::Count => Ok(Some(Datum::Bigint(n as i64))),
1610                    Proj::Literal(d) => Ok(Some(d.clone())),
1611                    // An expression beside `count(*)` is evaluated over the first row, which is
1612                    // the only row a collapsed answer has to be about; with no rows there is
1613                    // nothing to evaluate it over and it is null.
1614                    Proj::Expr(e) => match rows.first() {
1615                        Some(r) => ev.cell(e, r),
1616                        None => Ok(None),
1617                    },
1618                    Proj::Column(_) => Ok(None),
1619                })
1620                .collect::<Result<_, _>>()?]
1621        } else {
1622            let mut out = Vec::with_capacity(rows.len());
1623            for r in &rows {
1624                out.push(project(&ev, &proj, r)?);
1625            }
1626            out
1627        };
1628        Ok(Answer {
1629            tag: format!("SELECT {}", out.len()),
1630            columns,
1631            rows: out,
1632        })
1633    }
1634}
1635
1636/// One row through the select list.
1637fn project(ev: &Eval, proj: &[Proj], row: &[Cell]) -> Result<Vec<Cell>, SqlError> {
1638    proj.iter()
1639        .map(|p| match p {
1640            Proj::Column(i) => Ok(row[*i].clone()),
1641            Proj::Literal(d) => Ok(Some(d.clone())),
1642            Proj::Expr(e) => ev.cell(e, row),
1643            Proj::Count => Ok(None),
1644        })
1645        .collect()
1646}
1647
1648/// Sort rows by the `order by` keys, first key first.
1649///
1650/// A key is resolved the way SQL resolves one: an ordinal or a name that matches an output column
1651/// is *that output column*, computed for each row by the projection that produces it; anything
1652/// else is an expression over the row the query has. Both are functions of the row this holds, so
1653/// the sort happens before the projection either way and a `limit` still cuts the rows a person
1654/// asked to see.
1655///
1656/// `O(rows log rows)` comparisons, each `O(keys)`, with the keys computed once per row rather than
1657/// once per comparison — a sort key that called a function per comparison would be `O(n log n)`
1658/// calls for `O(n)` distinct answers.
1659fn order_rows(
1660    ev: &Eval,
1661    order: &[Order],
1662    columns: &[Column],
1663    proj: &[Proj],
1664    rows: Vec<Vec<Cell>>,
1665) -> Result<Vec<Vec<Cell>>, SqlError> {
1666    if order.is_empty() || rows.len() < 2 {
1667        return Ok(rows);
1668    }
1669    // What each key reads: a projection of the output, or an expression over the input.
1670    enum Key<'a> {
1671        Out(&'a Proj),
1672        Expr(&'a Expr),
1673    }
1674    let mut keys = Vec::with_capacity(order.len());
1675    for o in order {
1676        let key = match &o.by {
1677            OrderBy::Ordinal(n) => match n.checked_sub(1).and_then(|i| proj.get(i)) {
1678                Some(p) => Key::Out(p),
1679                None => {
1680                    return Err(SqlError::no_column(format!(
1681                        "`order by {n}` names the {n}th column of the select list, and there {}",
1682                        match columns.len() {
1683                            0 => "is none".to_string(),
1684                            1 => "is one".to_string(),
1685                            n => format!("are {n}"),
1686                        }
1687                    )))
1688                }
1689            },
1690            // A bare name that is an output column's name is that output column, **before** it is
1691            // a column of a table: that is SQL's own resolution order for an `order by`, and it is
1692            // what lets a query order by something it computed and gave a name to.
1693            OrderBy::Expr(Expr::Column(n))
1694                if n.table.is_none() && columns.iter().any(|c| c.name.as_ref() == n.column) =>
1695            {
1696                let i = columns
1697                    .iter()
1698                    .position(|c| c.name.as_ref() == n.column)
1699                    .expect("just found");
1700                Key::Out(&proj[i])
1701            }
1702            OrderBy::Expr(e) => Key::Expr(e),
1703        };
1704        keys.push((key, o.asc));
1705    }
1706
1707    // The keys, computed once per row. A failure to *resolve* one is reported here rather than
1708    // per comparison, so a wrong `order by` is one error rather than `n log n` of them.
1709    let mut keyed: Vec<(Vec<Cell>, Vec<Cell>)> = Vec::with_capacity(rows.len());
1710    for row in rows {
1711        let mut k = Vec::with_capacity(keys.len());
1712        for (key, _) in &keys {
1713            k.push(match key {
1714                Key::Out(p) => project(ev, std::slice::from_ref(*p), &row)?.remove(0),
1715                Key::Expr(e) => ev.cell(e, &row)?,
1716            });
1717        }
1718        keyed.push((k, row));
1719    }
1720    // Stable, so the order the collection holds its elements in survives ties — which is the
1721    // arrangement's key order, and therefore the order the page renders in.
1722    keyed.sort_by(|a, b| {
1723        for (i, (_, asc)) in keys.iter().enumerate() {
1724            let o = compare(&a.0[i], &b.0[i]);
1725            let o = if *asc { o } else { o.reverse() };
1726            if !o.is_eq() {
1727                return o;
1728            }
1729        }
1730        std::cmp::Ordering::Equal
1731    });
1732    Ok(keyed.into_iter().map(|(_, row)| row).collect())
1733}
1734
1735fn cut(rows: &mut Vec<Vec<Cell>>, offset: usize, limit: Option<usize>) {
1736    if offset > 0 {
1737        *rows = rows.split_off(offset.min(rows.len()));
1738    }
1739    if let Some(n) = limit {
1740        rows.truncate(n);
1741    }
1742}
1743
1744/// A row as something a `BTreeSet` can hold, for `union`'s deduplication.
1745///
1746/// The text form rather than the values: a `Datum` holds an `f64` and is therefore not `Ord`, and
1747/// two rows a client cannot tell apart are two rows `union` should not answer twice.
1748fn row_key(row: &[Cell]) -> Vec<Option<String>> {
1749    row.iter().map(|c| c.as_ref().map(Datum::text)).collect()
1750}
1751
1752enum Proj {
1753    Column(usize),
1754    Count,
1755    Literal(Datum),
1756    Expr(Expr),
1757}
1758
1759/// A column reference, as an index into the row a query produced.
1760///
1761/// Shared by the select list, the `where` and the `order by`, and by [`crate::query`]'s own
1762/// resolution of a join's `on` — one rule for what a name means, so a query cannot resolve a name
1763/// two ways.
1764pub fn resolve_field(fields: &[Field], n: &Name) -> Result<usize, SqlError> {
1765    let matching: Vec<usize> = (0..fields.len())
1766        .filter(|&i| {
1767            fields[i].column.name.as_ref() == n.column
1768                && match &n.table {
1769                    Some(t) => fields[i].of.as_deref() == Some(t.as_str()),
1770                    None => true,
1771                }
1772        })
1773        .collect();
1774    match matching.as_slice() {
1775        [one] => Ok(*one),
1776        [] => Err(SqlError::no_column(format!(
1777            "there is no column \"{n}\" here; there is {}",
1778            names_of(fields)
1779        ))),
1780        _ => Err(SqlError::no_column(format!(
1781            "\"{n}\" is ambiguous: more than one table in this query has a column called \
1782             \"{}\", so qualify it — `t.{}`",
1783            n.column, n.column
1784        ))),
1785    }
1786}
1787
1788/// The columns a query has, as a person is told about them.
1789pub fn names_of(fields: &[Field]) -> String {
1790    fields
1791        .iter()
1792        .map(|f| match &f.of {
1793            Some(t) => format!("\"{t}.{}\"", f.column.name),
1794            None => format!("\"{}\"", f.column.name),
1795        })
1796        .collect::<Vec<_>>()
1797        .join(", ")
1798}
1799
1800// -------------------------------------------------------------------------------------------
1801// Evaluating an expression over a row
1802// -------------------------------------------------------------------------------------------
1803
1804/// What an [`Expr`] is evaluated against: the columns a row has, and the reader behind them.
1805///
1806/// Two things are memoised, and both are memoised because they are the *same answer for every
1807/// row*:
1808///
1809/// * **A name's column index.** Resolution is a scan of the query's fields, and a query over a
1810///   million rows would otherwise do it a million times per reference.
1811/// * **A subquery's value.** See [`Eval::subquery`] — what is evaluated there is by construction
1812///   uncorrelated, so it cannot depend on the row.
1813///
1814/// Neither memo can make an answer wrong, only repeated: a name resolves to one index for the
1815/// whole query, and a query whose fields changed would be a different `Eval`.
1816pub struct Eval<'a> {
1817    schema: &'a Schema,
1818    fields: &'a [Field],
1819    rows: &'a dyn Rows,
1820    resolved: std::cell::RefCell<BTreeMap<Name, usize>>,
1821    subqueries: std::cell::RefCell<BTreeMap<usize, Cell>>,
1822}
1823
1824impl<'a> Eval<'a> {
1825    pub fn new(schema: &'a Schema, fields: &'a [Field], rows: &'a dyn Rows) -> Eval<'a> {
1826        Eval {
1827            schema,
1828            fields,
1829            rows,
1830            resolved: Default::default(),
1831            subqueries: Default::default(),
1832        }
1833    }
1834
1835    /// Where a name's value sits in a row.
1836    pub fn resolve(&self, n: &Name) -> Result<usize, SqlError> {
1837        if let Some(i) = self.resolved.borrow().get(n) {
1838            return Ok(*i);
1839        }
1840        let i = resolve_field(self.fields, n)?;
1841        self.resolved.borrow_mut().insert(n.clone(), i);
1842        Ok(i)
1843    }
1844
1845    /// Whether every term of a conjunction is true of this row.
1846    pub fn holds(&self, terms: &[Expr], row: &[Cell]) -> Result<bool, SqlError> {
1847        for t in terms {
1848            if !truthy(&self.cell(t, row)?) {
1849                return Ok(false);
1850            }
1851        }
1852        Ok(true)
1853    }
1854
1855    /// One expression's value for one row.
1856    ///
1857    /// `O(1)` per node, and every node is visited at most once — except the arms of a `case`,
1858    /// which are visited until one matches and never after.
1859    pub fn cell(&self, e: &Expr, row: &[Cell]) -> Result<Cell, SqlError> {
1860        match e {
1861            Expr::Column(n) => Ok(row.get(self.resolve(n)?).cloned().flatten()),
1862            Expr::Literal(c) => Ok(c.clone()),
1863            // Three-valued `and` and `or`, which is what makes `null` propagate the way a client
1864            // expects: `false and null` is false, `true and null` is unknown.
1865            Expr::And(xs) => {
1866                let mut unknown = false;
1867                for x in xs {
1868                    match self.cell(x, row)? {
1869                        Some(Datum::Boolean(false)) => return Ok(Some(Datum::Boolean(false))),
1870                        Some(Datum::Boolean(true)) => {}
1871                        _ => unknown = true,
1872                    }
1873                }
1874                Ok(match unknown {
1875                    true => None,
1876                    false => Some(Datum::Boolean(true)),
1877                })
1878            }
1879            Expr::Or(xs) => {
1880                let mut unknown = false;
1881                for x in xs {
1882                    match self.cell(x, row)? {
1883                        Some(Datum::Boolean(true)) => return Ok(Some(Datum::Boolean(true))),
1884                        Some(Datum::Boolean(false)) => {}
1885                        _ => unknown = true,
1886                    }
1887                }
1888                Ok(match unknown {
1889                    true => None,
1890                    false => Some(Datum::Boolean(false)),
1891                })
1892            }
1893            Expr::Not(x) => Ok(match self.cell(x, row)? {
1894                Some(Datum::Boolean(b)) => Some(Datum::Boolean(!b)),
1895                _ => None,
1896            }),
1897            Expr::Cmp(a, op, b) => {
1898                let (a, b) = (self.cell(a, row)?, self.cell(b, row)?);
1899                Ok(match (a, b) {
1900                    (Some(a), Some(b)) => {
1901                        Some(Datum::Boolean(op.holds(compare(&Some(a), &Some(b)))))
1902                    }
1903                    // A comparison against NULL is unknown, and unknown is not true.
1904                    _ => None,
1905                })
1906            }
1907            Expr::Is { value, to, negated } => {
1908                let v = self.cell(value, row)?;
1909                let is = match to {
1910                    None => v.is_none(),
1911                    Some(b) => v == Some(Datum::Boolean(*b)),
1912                };
1913                Ok(Some(Datum::Boolean(is != *negated)))
1914            }
1915            Expr::In {
1916                value,
1917                list,
1918                negated,
1919            } => {
1920                let v = self.cell(value, row)?;
1921                if v.is_none() {
1922                    return Ok(None);
1923                }
1924                let mut unknown = false;
1925                for item in list {
1926                    match self.cell(item, row)? {
1927                        None => unknown = true,
1928                        other if other == v => return Ok(Some(Datum::Boolean(!*negated))),
1929                        _ => {}
1930                    }
1931                }
1932                Ok(match unknown {
1933                    true => None,
1934                    false => Some(Datum::Boolean(*negated)),
1935                })
1936            }
1937            Expr::Match {
1938                value,
1939                pattern,
1940                negated,
1941                insensitive,
1942            } => {
1943                let (v, p) = (self.cell(value, row)?, self.cell(pattern, row)?);
1944                let (Some(v), Some(p)) = (v, p) else {
1945                    return Ok(None);
1946                };
1947                let hit = regex::matches(&p.text(), &v.text(), *insensitive)?;
1948                Ok(Some(Datum::Boolean(hit != *negated)))
1949            }
1950            Expr::Case {
1951                operand,
1952                arms,
1953                otherwise,
1954            } => {
1955                let subject = match operand {
1956                    Some(o) => Some(self.cell(o, row)?),
1957                    None => None,
1958                };
1959                for (when, then) in arms {
1960                    let hit = match &subject {
1961                        // `case x when a then …`: an equality, and a NULL matches nothing.
1962                        Some(s) => {
1963                            let w = self.cell(when, row)?;
1964                            s.is_some() && w.is_some() && compare(s, &w).is_eq()
1965                        }
1966                        None => truthy(&self.cell(when, row)?),
1967                    };
1968                    if hit {
1969                        return self.cell(then, row);
1970                    }
1971                }
1972                match otherwise {
1973                    Some(e) => self.cell(e, row),
1974                    // A `case` with no `else` and no arm taken is NULL, which is what `psql` reads
1975                    // as an empty cell.
1976                    None => Ok(None),
1977                }
1978            }
1979            Expr::Call { name, args } => {
1980                let mut values = Vec::with_capacity(args.len());
1981                for a in args {
1982                    values.push(self.cell(a, row)?);
1983                }
1984                match crate::pg::call(name, &values) {
1985                    Some(Ok(c)) => Ok(c),
1986                    Some(Err(why)) => Err(SqlError::unsupported(why)),
1987                    None => Err(SqlError::unsupported(format!(
1988                        "`{name}(…)` is not a function this read model has. The catalogue answers \
1989                         the ones `psql` asks it — format_type, pg_get_userbyid, \
1990                         pg_table_is_visible, pg_get_expr, pg_encoding_to_char — and there is no \
1991                         expression language behind them"
1992                    ))),
1993                }
1994            }
1995            Expr::Cast { value, ty } => {
1996                let v = self.cell(value, row)?;
1997                Ok(match (v, ty.as_str()) {
1998                    (None, _) => None,
1999                    (Some(v), "text" | "varchar" | "name" | "char") => Some(Datum::Text(v.text())),
2000                    (Some(v), "bool" | "boolean") => match v {
2001                        Datum::Boolean(_) => Some(v),
2002                        other => Some(Datum::Boolean(other.text() == "t")),
2003                    },
2004                    (Some(v), "int" | "int2" | "int4" | "int8" | "bigint" | "integer" | "oid") => {
2005                        match v {
2006                            Datum::Bigint(_) => Some(v),
2007                            other => other.text().parse::<i64>().ok().map(Datum::Bigint),
2008                        }
2009                    }
2010                    (Some(v), "float4" | "float8" | "real" | "numeric") => match v {
2011                        Datum::Double(_) => Some(v),
2012                        other => other.text().parse::<f64>().ok().map(Datum::Double),
2013                    },
2014                    (Some(_), other) => {
2015                        return Err(SqlError::unsupported(format!(
2016                            "`::{other}` is a cast to a type this read model has no values of. \
2017                             The four types are boolean, bigint, double precision and text, and \
2018                             an object identifier printed as a name is a lookup in a catalogue \
2019                             with nothing to look up"
2020                        )))
2021                    }
2022                })
2023            }
2024            Expr::Concat(a, b) => {
2025                let (a, b) = (self.cell(a, row)?, self.cell(b, row)?);
2026                Ok(match (a, b) {
2027                    (Some(a), Some(b)) => Some(Datum::Text(format!("{}{}", a.text(), b.text()))),
2028                    _ => None,
2029                })
2030            }
2031            Expr::Subquery { id, select } => self.subquery(*id, select),
2032            Expr::Array { .. } => Err(SqlError::unsupported(
2033                "`array(select …)` builds an array, and an array is not one of this read model's \
2034                 four types",
2035            )),
2036            Expr::Any(_) => Err(SqlError::unsupported(
2037                "`any(…)` compares against the elements of an array, and an array is not one of \
2038                 this read model's four types",
2039            )),
2040            Expr::Subscript(..) => Err(SqlError::unsupported(
2041                "`x[i]` reads an element of an array, and an array is not one of this read \
2042                 model's four types",
2043            )),
2044        }
2045    }
2046
2047    /// A scalar subquery's value, when it can be established without correlation.
2048    ///
2049    /// The rule, and it is the whole of it: **drop the terms that name something this subquery's
2050    /// own tables do not have** — those are the ones correlated to the outer row — and run what is
2051    /// left. Dropping a term can only *add* rows, so a widened query that answers nothing proves
2052    /// the original answers nothing, and a scalar subquery with no rows is NULL. That is the
2053    /// answer for every outer row, which is why it is computed once.
2054    ///
2055    /// When the widened query does have rows the answer depends on the correlation, and it is
2056    /// refused by name rather than guessed at. Every scalar subquery `psql` sends the catalogue
2057    /// asks about a default expression or a collation — relations a read model has none of — so
2058    /// the empty case is the one that happens, and the refusal is what would happen if that ever
2059    /// stopped being true.
2060    pub fn subquery(&self, id: usize, select: &Select) -> Result<Cell, SqlError> {
2061        if let Some(c) = self.subqueries.borrow().get(&id) {
2062            return Ok(c.clone());
2063        }
2064        let mut widened = select.clone();
2065        let own: Vec<Field> = widened
2066            .from
2067            .iter()
2068            .filter(|f| f.function.is_none())
2069            .try_fold(Vec::new(), |mut acc: Vec<Field>, f| {
2070                acc.extend(Field::of_table_as(
2071                    self.schema.relation(f.namespace.as_deref(), &f.table)?,
2072                    Arc::from(f.alias.as_str()),
2073                ));
2074                Ok::<_, SqlError>(acc)
2075            })?;
2076        widened.filter.retain(|term| {
2077            let mut names = Vec::new();
2078            term.names(&mut names);
2079            names.iter().all(|n| resolve_field(&own, n).is_ok())
2080        });
2081        let answer = self.schema.select(&widened, self.rows)?;
2082        let value = match answer.rows.len() {
2083            0 => None,
2084            _ => {
2085                return Err(SqlError::unsupported(format!(
2086                    "this subquery answers {} row{} once the conditions that mention the outer \
2087                     query are dropped, so its value depends on which row is asking — and a \
2088                     correlated subquery is not in this SQL subset",
2089                    answer.rows.len(),
2090                    match answer.rows.len() {
2091                        1 => "",
2092                        _ => "s",
2093                    }
2094                )))
2095            }
2096        };
2097        self.subqueries.borrow_mut().insert(id, value.clone());
2098        Ok(value)
2099    }
2100}
2101
2102/// Whether a cell is SQL's `true`. NULL is not, which is the whole of three-valued logic where a
2103/// `where` is concerned.
2104fn truthy(c: &Cell) -> bool {
2105    matches!(c, Some(Datum::Boolean(true)))
2106}
2107
2108/// NULLs sort last, as they do in Postgres for an ascending order.
2109fn compare(a: &Cell, b: &Cell) -> std::cmp::Ordering {
2110    use std::cmp::Ordering;
2111    match (a, b) {
2112        (None, None) => Ordering::Equal,
2113        (None, Some(_)) => Ordering::Greater,
2114        (Some(_), None) => Ordering::Less,
2115        (Some(x), Some(y)) => match (x, y) {
2116            (Datum::Bigint(p), Datum::Bigint(q)) => p.cmp(q),
2117            (Datum::Double(p), Datum::Double(q)) => p.partial_cmp(q).unwrap_or(Ordering::Equal),
2118            (Datum::Bigint(p), Datum::Double(q)) => {
2119                (*p as f64).partial_cmp(q).unwrap_or(Ordering::Equal)
2120            }
2121            (Datum::Double(p), Datum::Bigint(q)) => {
2122                p.partial_cmp(&(*q as f64)).unwrap_or(Ordering::Equal)
2123            }
2124            (Datum::Boolean(p), Datum::Boolean(q)) => p.cmp(q),
2125            (Datum::Text(p), Datum::Text(q)) => p.cmp(q),
2126            // Across kinds, compare the text. Nothing in a typed column reaches this; a literal
2127            // compared against a column of another type does, and `c.oid = '16384'` — a number
2128            // written as a string, which is how `psql` writes every one of them — is that.
2129            _ => x.text().cmp(&y.text()),
2130        },
2131    }
2132}
2133
2134// -------------------------------------------------------------------------------------------
2135// The regular expression `~` matches against
2136// -------------------------------------------------------------------------------------------
2137
2138/// POSIX regular expressions, for the four operators `~`, `!~`, `~*` and `!~*`.
2139///
2140/// Written here for [`crate::read`]'s reason and not a new one: `psql` sends `relname ~
2141/// '^(todos)$'` to find a table and `nspname !~ '^pg_toast'` to hide the ones it does not want,
2142/// so the catalogue cannot be read without one — and a regular expression crate would be a
2143/// dependency for two operators over patterns a client generates.
2144///
2145/// # Why it is a simulation and not a backtracker
2146///
2147/// **The pattern arrives from a client.** A backtracking matcher is exponential on patterns like
2148/// `(a|a)*b`, and one is three characters to type. This compiles the pattern to an NFA and
2149/// advances a *set* of states one character at a time, which is `O(pattern × text)` for every
2150/// pattern there is — the cost is a property of the algorithm rather than of the input, so there
2151/// is no budget to tune and nothing to refuse.
2152///
2153/// # What it has
2154///
2155/// `^ $ . * + ? | ( ) [ ] [^ ] -` and `\` before any character. What it does not have is
2156/// back-references — which is what makes the simulation possible — and counted repetition
2157/// `{n,m}`, which nothing sends; both are refused by name.
2158mod regex {
2159    use super::SqlError;
2160
2161    /// Whether `text` matches `pattern` anywhere in it, which is what POSIX `~` asks.
2162    pub fn matches(pattern: &str, text: &str, insensitive: bool) -> Result<bool, SqlError> {
2163        let program = compile(pattern, insensitive)?;
2164        Ok(run(&program, text, insensitive))
2165    }
2166
2167    enum Ins {
2168        Char(char),
2169        Any,
2170        /// A bracket expression, as ranges, and whether it is negated.
2171        Class(Vec<(char, char)>, bool),
2172        /// The zero-width assertions. There is no multi-line mode, so these are the ends of the
2173        /// text rather than of a line.
2174        Start,
2175        End,
2176        Split(usize, usize),
2177        Jmp(usize),
2178        Match,
2179    }
2180
2181    /// A parsed pattern, as a tree, before it becomes instructions.
2182    enum Node {
2183        Empty,
2184        Char(char),
2185        Any,
2186        Class(Vec<(char, char)>, bool),
2187        Start,
2188        End,
2189        Concat(Vec<Node>),
2190        Alt(Vec<Node>),
2191        /// `x*`, `x+`, `x?` — the minimum and whether it repeats.
2192        Repeat(Box<Node>, u32, bool),
2193    }
2194
2195    struct P<'a> {
2196        cs: &'a [char],
2197        i: usize,
2198    }
2199
2200    impl P<'_> {
2201        fn peek(&self) -> Option<char> {
2202            self.cs.get(self.i).copied()
2203        }
2204
2205        fn alt(&mut self) -> Result<Node, SqlError> {
2206            let mut branches = vec![self.concat()?];
2207            while self.peek() == Some('|') {
2208                self.i += 1;
2209                branches.push(self.concat()?);
2210            }
2211            Ok(match branches.len() {
2212                1 => branches.pop().expect("one branch"),
2213                _ => Node::Alt(branches),
2214            })
2215        }
2216
2217        fn concat(&mut self) -> Result<Node, SqlError> {
2218            let mut parts = Vec::new();
2219            while !matches!(self.peek(), None | Some('|') | Some(')')) {
2220                parts.push(self.repeat()?);
2221            }
2222            Ok(match parts.len() {
2223                0 => Node::Empty,
2224                1 => parts.pop().expect("one part"),
2225                _ => Node::Concat(parts),
2226            })
2227        }
2228
2229        fn repeat(&mut self) -> Result<Node, SqlError> {
2230            let mut node = self.atom()?;
2231            loop {
2232                node = match self.peek() {
2233                    Some('*') => Node::Repeat(Box::new(node), 0, true),
2234                    Some('+') => Node::Repeat(Box::new(node), 1, true),
2235                    Some('?') => Node::Repeat(Box::new(node), 0, false),
2236                    Some('{') => {
2237                        return Err(SqlError::unsupported(
2238                            "a counted repetition `{n,m}` is not in this regular expression \
2239                             subset: `*`, `+` and `?` are what there is",
2240                        ))
2241                    }
2242                    _ => return Ok(node),
2243                };
2244                self.i += 1;
2245            }
2246        }
2247
2248        fn atom(&mut self) -> Result<Node, SqlError> {
2249            let Some(c) = self.peek() else {
2250                return Ok(Node::Empty);
2251            };
2252            self.i += 1;
2253            Ok(match c {
2254                '(' => {
2255                    let inner = self.alt()?;
2256                    if self.peek() != Some(')') {
2257                        return Err(SqlError::syntax(
2258                            "a group in a regular expression is not closed",
2259                        ));
2260                    }
2261                    self.i += 1;
2262                    inner
2263                }
2264                '[' => self.class()?,
2265                '.' => Node::Any,
2266                '^' => Node::Start,
2267                '$' => Node::End,
2268                '\\' => match self.peek() {
2269                    Some(e) => {
2270                        self.i += 1;
2271                        Node::Char(e)
2272                    }
2273                    None => {
2274                        return Err(SqlError::syntax(
2275                            "a regular expression ends in a backslash, which escapes nothing",
2276                        ))
2277                    }
2278                },
2279                other => Node::Char(other),
2280            })
2281        }
2282
2283        fn class(&mut self) -> Result<Node, SqlError> {
2284            let negated = self.peek() == Some('^');
2285            if negated {
2286                self.i += 1;
2287            }
2288            let mut ranges = Vec::new();
2289            // A `]` first is a literal `]`, which is POSIX's rule for including one.
2290            let mut first = true;
2291            loop {
2292                let Some(c) = self.peek() else {
2293                    return Err(SqlError::syntax(
2294                        "a bracket expression in a regular expression is not closed",
2295                    ));
2296                };
2297                if c == ']' && !first {
2298                    self.i += 1;
2299                    return Ok(Node::Class(ranges, negated));
2300                }
2301                first = false;
2302                self.i += 1;
2303                let lo = match c {
2304                    '\\' => match self.peek() {
2305                        Some(e) => {
2306                            self.i += 1;
2307                            e
2308                        }
2309                        None => {
2310                            return Err(SqlError::syntax(
2311                                "a bracket expression ends in a backslash",
2312                            ))
2313                        }
2314                    },
2315                    other => other,
2316                };
2317                if self.peek() == Some('-') && self.cs.get(self.i + 1).is_some_and(|c| *c != ']') {
2318                    self.i += 1;
2319                    let hi = self.cs[self.i];
2320                    self.i += 1;
2321                    ranges.push((lo, hi));
2322                } else {
2323                    ranges.push((lo, lo));
2324                }
2325            }
2326        }
2327    }
2328
2329    fn compile(pattern: &str, insensitive: bool) -> Result<Vec<Ins>, SqlError> {
2330        let cs: Vec<char> = pattern.chars().collect();
2331        let mut p = P { cs: &cs, i: 0 };
2332        let node = p.alt()?;
2333        if p.i < cs.len() {
2334            return Err(SqlError::syntax(format!(
2335                "a regular expression has a `{}` with no group to close",
2336                cs[p.i]
2337            )));
2338        }
2339        let mut out = Vec::new();
2340        emit(&node, &mut out, insensitive);
2341        out.push(Ins::Match);
2342        Ok(out)
2343    }
2344
2345    fn emit(node: &Node, out: &mut Vec<Ins>, insensitive: bool) {
2346        let fold = |c: char| match insensitive {
2347            true => c.to_lowercase().next().unwrap_or(c),
2348            false => c,
2349        };
2350        match node {
2351            Node::Empty => {}
2352            Node::Char(c) => out.push(Ins::Char(fold(*c))),
2353            Node::Any => out.push(Ins::Any),
2354            Node::Class(ranges, negated) => out.push(Ins::Class(
2355                ranges.iter().map(|(a, b)| (fold(*a), fold(*b))).collect(),
2356                *negated,
2357            )),
2358            Node::Start => out.push(Ins::Start),
2359            Node::End => out.push(Ins::End),
2360            Node::Concat(parts) => parts.iter().for_each(|p| emit(p, out, insensitive)),
2361            Node::Alt(branches) => {
2362                // A chain of splits, each falling through to the next branch.
2363                let mut jumps = Vec::new();
2364                for (i, b) in branches.iter().enumerate() {
2365                    if i + 1 < branches.len() {
2366                        let split = out.len();
2367                        out.push(Ins::Split(0, 0));
2368                        emit(b, out, insensitive);
2369                        jumps.push(out.len());
2370                        out.push(Ins::Jmp(0));
2371                        let next = out.len();
2372                        out[split] = Ins::Split(split + 1, next);
2373                    } else {
2374                        emit(b, out, insensitive);
2375                    }
2376                }
2377                let end = out.len();
2378                for j in jumps {
2379                    out[j] = Ins::Jmp(end);
2380                }
2381            }
2382            Node::Repeat(inner, min, many) => {
2383                if *min == 1 {
2384                    // `x+` is `x` then `x*`, which keeps one copy of the instructions for the
2385                    // first iteration and one for the loop.
2386                    emit(inner, out, insensitive);
2387                }
2388                let split = out.len();
2389                out.push(Ins::Split(0, 0));
2390                emit(inner, out, insensitive);
2391                if *many {
2392                    out.push(Ins::Jmp(split));
2393                }
2394                let after = out.len();
2395                out[split] = Ins::Split(split + 1, after);
2396            }
2397        }
2398    }
2399
2400    /// Advance a set of states over the text.
2401    ///
2402    /// `O(states × text)`: each character adds every state at most once to the next set, and the
2403    /// `on` vector is what makes "at most once" true.
2404    fn run(program: &[Ins], text: &str, insensitive: bool) -> bool {
2405        let cs: Vec<char> = match insensitive {
2406            true => text.to_lowercase().chars().collect(),
2407            false => text.chars().collect(),
2408        };
2409        let mut current: Vec<usize> = Vec::new();
2410        add(
2411            program,
2412            0,
2413            0,
2414            cs.len(),
2415            &mut current,
2416            &mut vec![false; program.len()],
2417        );
2418        for (i, c) in cs.iter().enumerate() {
2419            let mut next = Vec::new();
2420            // One "already added" flag per instruction per position, which is what bounds the set
2421            // to the program's length and the whole match to `O(states × text)`.
2422            let mut next_on = vec![false; program.len()];
2423            for pc in &current {
2424                let step = match &program[*pc] {
2425                    Ins::Char(want) => *want == *c,
2426                    Ins::Any => true,
2427                    Ins::Class(ranges, negated) => {
2428                        ranges.iter().any(|(lo, hi)| *lo <= *c && *c <= *hi) != *negated
2429                    }
2430                    Ins::Match => return true,
2431                    _ => continue,
2432                };
2433                if step {
2434                    add(program, pc + 1, i + 1, cs.len(), &mut next, &mut next_on);
2435                }
2436            }
2437            // POSIX `~` searches rather than anchors, so a match may start at any position: the
2438            // thread that has not started yet is added at every one.
2439            add(program, 0, i + 1, cs.len(), &mut next, &mut next_on);
2440            current = next;
2441        }
2442        current.iter().any(|pc| matches!(program[*pc], Ins::Match))
2443    }
2444
2445    /// Add a state and everything reachable from it without consuming a character.
2446    fn add(
2447        program: &[Ins],
2448        pc: usize,
2449        at: usize,
2450        len: usize,
2451        set: &mut Vec<usize>,
2452        on: &mut [bool],
2453    ) {
2454        if on[pc] {
2455            return;
2456        }
2457        on[pc] = true;
2458        match &program[pc] {
2459            Ins::Jmp(to) => add(program, *to, at, len, set, on),
2460            Ins::Split(a, b) => {
2461                add(program, *a, at, len, set, on);
2462                add(program, *b, at, len, set, on);
2463            }
2464            Ins::Start if at == 0 => add(program, pc + 1, at, len, set, on),
2465            Ins::End if at == len => add(program, pc + 1, at, len, set, on),
2466            // An assertion that does not hold here kills the thread rather than advancing it.
2467            Ins::Start | Ins::End => {}
2468            _ => set.push(pc),
2469        }
2470    }
2471}
2472
2473// -------------------------------------------------------------------------------------------
2474// The parser
2475// -------------------------------------------------------------------------------------------
2476
2477#[derive(Clone, Debug, PartialEq)]
2478enum Tok {
2479    Word(String),
2480    Quoted(String),
2481    Str(String),
2482    Num(String),
2483    Sym(String),
2484}
2485
2486fn lex(sql: &str) -> Result<Vec<Tok>, SqlError> {
2487    let cs: Vec<char> = sql.chars().collect();
2488    let mut i = 0;
2489    let mut out = Vec::new();
2490    while i < cs.len() {
2491        let c = cs[i];
2492        if c.is_whitespace() {
2493            i += 1;
2494        } else if c == '-' && cs.get(i + 1) == Some(&'-') {
2495            while i < cs.len() && cs[i] != '\n' {
2496                i += 1;
2497            }
2498        } else if (c == 'E' || c == 'e') && cs.get(i + 1) == Some(&'\'') {
2499            // `E'\n'` — PostgreSQL's escape string, which `psql` writes the separator of a `\l`
2500            // with. The escapes are read rather than passed through, because a client that asked
2501            // for a newline and got a backslash and an `n` would be told something false.
2502            i += 2;
2503            let mut s = String::new();
2504            loop {
2505                match cs.get(i) {
2506                    None => return Err(SqlError::syntax("an escape string is not closed")),
2507                    Some('\'') if cs.get(i + 1) == Some(&'\'') => {
2508                        s.push('\'');
2509                        i += 2;
2510                    }
2511                    Some('\'') => {
2512                        i += 1;
2513                        break;
2514                    }
2515                    Some('\\') => {
2516                        i += 1;
2517                        let e = cs.get(i).copied().unwrap_or('\\');
2518                        i += 1;
2519                        s.push(match e {
2520                            'n' => '\n',
2521                            't' => '\t',
2522                            'r' => '\r',
2523                            other => other,
2524                        });
2525                    }
2526                    Some(ch) => {
2527                        s.push(*ch);
2528                        i += 1;
2529                    }
2530                }
2531            }
2532            out.push(Tok::Str(s));
2533        } else if c == '_' || c.is_alphabetic() {
2534            let start = i;
2535            while i < cs.len() && (cs[i] == '_' || cs[i] == '$' || cs[i].is_alphanumeric()) {
2536                i += 1;
2537            }
2538            out.push(Tok::Word(cs[start..i].iter().collect()));
2539        } else if c.is_ascii_digit()
2540            || (c == '.' && cs.get(i + 1).is_some_and(char::is_ascii_digit))
2541        {
2542            let start = i;
2543            while i < cs.len() && (cs[i].is_ascii_digit() || cs[i] == '.') {
2544                i += 1;
2545            }
2546            out.push(Tok::Num(cs[start..i].iter().collect()));
2547        } else if c == '\'' {
2548            i += 1;
2549            let mut s = String::new();
2550            loop {
2551                match cs.get(i) {
2552                    None => return Err(SqlError::syntax("a string literal is not closed")),
2553                    // '' is an escaped quote, which is the only escape standard SQL has.
2554                    Some('\'') if cs.get(i + 1) == Some(&'\'') => {
2555                        s.push('\'');
2556                        i += 2;
2557                    }
2558                    Some('\'') => {
2559                        i += 1;
2560                        break;
2561                    }
2562                    Some(ch) => {
2563                        s.push(*ch);
2564                        i += 1;
2565                    }
2566                }
2567            }
2568            out.push(Tok::Str(s));
2569        } else if c == '"' {
2570            i += 1;
2571            let mut s = String::new();
2572            loop {
2573                match cs.get(i) {
2574                    None => return Err(SqlError::syntax("a quoted name is not closed")),
2575                    Some('"') if cs.get(i + 1) == Some(&'"') => {
2576                        s.push('"');
2577                        i += 2;
2578                    }
2579                    Some('"') => {
2580                        i += 1;
2581                        break;
2582                    }
2583                    Some(ch) => {
2584                        s.push(*ch);
2585                        i += 1;
2586                    }
2587                }
2588            }
2589            out.push(Tok::Quoted(s));
2590        } else {
2591            // The longest operator first, so `<=` does not lex as `<` then `=` and `!~*` does not
2592            // lex as `!=`.
2593            let three: String = cs[i..(i + 3).min(cs.len())].iter().collect();
2594            let two: String = cs[i..(i + 2).min(cs.len())].iter().collect();
2595            if three == "!~*" {
2596                out.push(Tok::Sym(three));
2597                i += 3;
2598            } else if matches!(
2599                two.as_str(),
2600                "<=" | ">=" | "<>" | "!=" | "::" | "||" | "!~" | "~*"
2601            ) {
2602                out.push(Tok::Sym(two));
2603                i += 2;
2604            } else {
2605                out.push(Tok::Sym(c.to_string()));
2606                i += 1;
2607            }
2608        }
2609    }
2610    Ok(out)
2611}
2612
2613struct P {
2614    toks: Vec<Tok>,
2615    i: usize,
2616    /// How many subqueries have been parsed, which is what gives each one a name of its own so
2617    /// its answer can be computed once rather than once per row ([`Eval::subquery`]).
2618    subqueries: usize,
2619}
2620
2621impl P {
2622    fn subquery_id(&mut self) -> usize {
2623        self.subqueries += 1;
2624        self.subqueries - 1
2625    }
2626
2627    fn peek(&self) -> Option<&Tok> {
2628        self.toks.get(self.i)
2629    }
2630
2631    /// The next token as a lower-cased keyword, if it is a bare word.
2632    fn keyword(&self) -> Option<String> {
2633        match self.peek() {
2634            Some(Tok::Word(w)) => Some(w.to_lowercase()),
2635            _ => None,
2636        }
2637    }
2638
2639    fn eat_keyword(&mut self, k: &str) -> bool {
2640        if self.keyword().as_deref() == Some(k) {
2641            self.i += 1;
2642            return true;
2643        }
2644        false
2645    }
2646
2647    fn eat_sym(&mut self, s: &str) -> bool {
2648        if self.peek() == Some(&Tok::Sym(s.to_string())) {
2649            self.i += 1;
2650            return true;
2651        }
2652        false
2653    }
2654
2655    /// An identifier: a bare word, case-folded the way an unquoted SQL name is, or a quoted one
2656    /// taken exactly as written. Beck names are lower-case, so folding down is what matches.
2657    fn name(&mut self) -> Option<String> {
2658        match self.peek().cloned() {
2659            Some(Tok::Word(w)) => {
2660                self.i += 1;
2661                Some(w.to_lowercase())
2662            }
2663            Some(Tok::Quoted(w)) => {
2664                self.i += 1;
2665                Some(w)
2666            }
2667            _ => None,
2668        }
2669    }
2670
2671    fn literal(&mut self) -> Option<Option<Datum>> {
2672        match self.peek().cloned() {
2673            Some(Tok::Str(s)) => {
2674                self.i += 1;
2675                Some(Some(Datum::Text(s)))
2676            }
2677            Some(Tok::Num(n)) => {
2678                self.i += 1;
2679                Some(Some(match n.parse::<i64>() {
2680                    Ok(i) => Datum::Bigint(i),
2681                    Err(_) => Datum::Double(n.parse::<f64>().unwrap_or(0.0)),
2682                }))
2683            }
2684            Some(Tok::Sym(s)) if s == "-" => {
2685                self.i += 1;
2686                match self.literal() {
2687                    Some(Some(Datum::Bigint(i))) => Some(Some(Datum::Bigint(-i))),
2688                    Some(Some(Datum::Double(f))) => Some(Some(Datum::Double(-f))),
2689                    _ => None,
2690                }
2691            }
2692            Some(Tok::Word(w)) => match w.to_lowercase().as_str() {
2693                "true" => {
2694                    self.i += 1;
2695                    Some(Some(Datum::Boolean(true)))
2696                }
2697                "false" => {
2698                    self.i += 1;
2699                    Some(Some(Datum::Boolean(false)))
2700                }
2701                "null" => {
2702                    self.i += 1;
2703                    Some(None)
2704                }
2705                _ => None,
2706            },
2707            _ => None,
2708        }
2709    }
2710}
2711
2712/// Parse one statement.
2713pub fn parse(sql: &str) -> Result<Stmt, SqlError> {
2714    let toks = lex(sql)?;
2715    let mut p = P {
2716        toks,
2717        i: 0,
2718        subqueries: 0,
2719    };
2720    let head = p.keyword().unwrap_or_default();
2721    match head.as_str() {
2722        "select" => {
2723            p.i += 1;
2724            let mut branches = vec![select(&mut p)?];
2725            let mut all = false;
2726            for word in ["intersect", "except"] {
2727                if p.keyword().as_deref() == Some(word) {
2728                    return Err(SqlError::unsupported(format!(
2729                        "`{word}` is not in this SQL subset; `union` is the one set operation \
2730                         there is"
2731                    )));
2732                }
2733            }
2734            while p.eat_keyword("union") {
2735                all |= p.eat_keyword("all");
2736                if !p.eat_keyword("select") {
2737                    return Err(SqlError::syntax("`union` wants a `select` after it"));
2738                }
2739                branches.push(select(&mut p)?);
2740            }
2741            // A trailing `;` is a statement separator, and a second statement is not supported —
2742            // saying so beats answering the first and dropping the rest.
2743            p.eat_sym(";");
2744            if p.peek().is_some() {
2745                return Err(SqlError::unsupported(
2746                    "one statement per query: this SQL has no multi-statement form",
2747                ));
2748            }
2749            if branches.len() == 1 {
2750                return Ok(Stmt::Select(branches.pop().expect("one branch")));
2751            }
2752            // `order by` and `limit` after the last branch belong to the union, which is what SQL
2753            // says and what the parse has to be told: each branch was parsed as a whole select.
2754            let last = branches.last_mut().expect("at least two branches");
2755            let order = std::mem::take(&mut last.order);
2756            let limit = last.limit.take();
2757            let offset = std::mem::replace(&mut last.offset, 0);
2758            Ok(Stmt::Union {
2759                branches,
2760                all,
2761                order,
2762                limit,
2763                offset,
2764            })
2765        }
2766        "set" => Ok(Stmt::Ignored("SET")),
2767        "begin" | "start" => Ok(Stmt::Ignored("BEGIN")),
2768        "commit" | "end" => Ok(Stmt::Ignored("COMMIT")),
2769        "rollback" | "abort" => Ok(Stmt::Ignored("ROLLBACK")),
2770        "discard" => Ok(Stmt::Ignored("DISCARD ALL")),
2771        "" => Err(SqlError::syntax("an empty query")),
2772        other => Err(SqlError::unsupported(format!(
2773            "a read model is read-only and this SQL is a subset: `{other}` is not one of \
2774             select, set, begin, commit, rollback"
2775        ))),
2776    }
2777}
2778
2779fn select(p: &mut P) -> Result<Select, SqlError> {
2780    // `distinct` is the algebra's δ and it is a *plan* operator rather than a comparison over whole
2781    // rows here — `list_unique` names it and [`crate::plan::Op::Distinct`] maintains it, so this
2782    // surface grows it by compiling into the plan (docs/99 §99.9 item 7).
2783    let distinct = p.eat_keyword("distinct");
2784    if p.eat_keyword("on") {
2785        return Err(SqlError::unsupported(
2786            "`distinct on` is a PostgreSQL extension this SQL does not have; \
2787             `distinct` over the whole select list is what there is",
2788        ));
2789    }
2790    let mut items = Vec::new();
2791    loop {
2792        items.push(item(p)?);
2793        if !p.eat_sym(",") {
2794            break;
2795        }
2796    }
2797
2798    let mut from = Vec::new();
2799    if p.eat_keyword("from") {
2800        from.push(from_item(p, false)?);
2801        loop {
2802            // A comma join is a cross product the `where` then narrows, which is the same query as
2803            // a `join … on` — and `crate::query` recognises the equality and gives it the same
2804            // indexed operator rather than leaving it a nested loop.
2805            if p.eat_sym(",") {
2806                from.push(from_item(p, false)?);
2807                continue;
2808            }
2809            if p.eat_keyword("natural") {
2810                return Err(SqlError::unsupported(
2811                    "a natural join names no key, and every join in this SQL is an equi-join \
2812                     because that is the operator underneath it: write `join … on <equality>`",
2813                ));
2814            }
2815            if p.eat_keyword("cross") {
2816                if !p.eat_keyword("join") {
2817                    return Err(SqlError::syntax("`cross` wants `join`"));
2818                }
2819                from.push(from_item(p, false)?);
2820                continue;
2821            }
2822            for outer in ["right", "full"] {
2823                if p.keyword().as_deref() == Some(outer) {
2824                    return Err(SqlError::unsupported(format!(
2825                        "`{outer} join` is not in this SQL subset. The `from` list is joined \
2826                         left-deep, one stage per entry, so the rows a `{outer} join` keeps are \
2827                         the ones no stage has yet produced; write it as a `left join` with the \
2828                         tables the other way round"
2829                    )));
2830                }
2831            }
2832            let left = p.eat_keyword("left");
2833            if left {
2834                p.eat_keyword("outer");
2835            } else {
2836                p.eat_keyword("inner");
2837            }
2838            if !p.eat_keyword("join") {
2839                break;
2840            }
2841            let mut entry = from_item(p, left)?;
2842            if !p.eat_keyword("on") {
2843                return Err(SqlError::syntax(format!(
2844                    "`join {}` wants `on <column> = <column>`",
2845                    entry.table
2846                )));
2847            }
2848            // `on (a = b)` and `on a = b` are the same thing, and `psql` writes both.
2849            let parenthesised = p.eat_sym("(");
2850            loop {
2851                let left = column_name(p).ok_or_else(|| SqlError::syntax("`on` wants a column"))?;
2852                if !p.eat_sym("=") {
2853                    return Err(SqlError::unsupported(format!(
2854                        "a join is an equality here: `on {left} = <column>`, and no other \
2855                         comparison"
2856                    )));
2857                }
2858                let right =
2859                    column_name(p).ok_or_else(|| SqlError::syntax("`on` wants a column"))?;
2860                entry.on.push((left, right));
2861                if !p.eat_keyword("and") {
2862                    break;
2863                }
2864            }
2865            if parenthesised && !p.eat_sym(")") {
2866                return Err(SqlError::syntax("an `on` in brackets is not closed"));
2867            }
2868            from.push(entry);
2869        }
2870    }
2871
2872    let mut filter = Vec::new();
2873    if p.eat_keyword("where") {
2874        conjuncts(expr(p)?, &mut filter);
2875    }
2876
2877    let mut group = Vec::new();
2878    if p.eat_keyword("group") {
2879        if !p.eat_keyword("by") {
2880            return Err(SqlError::syntax("`group` wants `by`"));
2881        }
2882        loop {
2883            group
2884                .push(column_name(p).ok_or_else(|| SqlError::syntax("`group by` wants a column"))?);
2885            if !p.eat_sym(",") {
2886                break;
2887            }
2888        }
2889    }
2890    if p.eat_keyword("having") {
2891        return Err(SqlError::unsupported(
2892            "`having` is not in this SQL subset: a `where` narrows the rows before they are \
2893             grouped, and there is no filter over the groups themselves",
2894        ));
2895    }
2896
2897    // `count(*)` beside a column collapses one way with a `group by` and another without one, so
2898    // the check is about which of the two this is rather than about the item list alone.
2899    if group.is_empty()
2900        && items.iter().any(Item::aggregates)
2901        && items
2902            .iter()
2903            .any(|i| matches!(i, Item::All(_) | Item::Column(..)))
2904    {
2905        return Err(SqlError::unsupported(
2906            "an aggregate beside a column needs a `group by` saying which rows it aggregates",
2907        ));
2908    }
2909
2910    let mut order = Vec::new();
2911    if p.eat_keyword("order") {
2912        if !p.eat_keyword("by") {
2913            return Err(SqlError::syntax("`order` wants `by`"));
2914        }
2915        loop {
2916            let e = expr(p)?;
2917            let by = match e {
2918                // `order by 2` is the second select item, which is SQL's own shorthand and the
2919                // only place a bare number means a column.
2920                Expr::Literal(Some(Datum::Bigint(n))) if n > 0 => OrderBy::Ordinal(n as usize),
2921                other => OrderBy::Expr(other),
2922            };
2923            let asc = if p.eat_keyword("desc") {
2924                false
2925            } else {
2926                p.eat_keyword("asc");
2927                true
2928            };
2929            // `nulls first` / `nulls last`: nulls sort last ascending here, as they do in
2930            // PostgreSQL, and a query that asked for the other order would be answered the
2931            // default one rather than told so.
2932            if p.eat_keyword("nulls") {
2933                let which = p.name().unwrap_or_default();
2934                return Err(SqlError::unsupported(format!(
2935                    "`nulls {which}` is not in this SQL subset: nulls sort last ascending and \
2936                     first descending, which is PostgreSQL's default and the only order there is"
2937                )));
2938            }
2939            order.push(Order { by, asc });
2940            if !p.eat_sym(",") {
2941                break;
2942            }
2943        }
2944    }
2945
2946    let mut limit = None;
2947    let mut offset = 0;
2948    loop {
2949        if p.eat_keyword("limit") {
2950            match p.literal() {
2951                Some(Some(Datum::Bigint(n))) if n >= 0 => limit = Some(n as usize),
2952                _ => return Err(SqlError::syntax("`limit` wants a whole number")),
2953            }
2954        } else if p.eat_keyword("offset") {
2955            match p.literal() {
2956                Some(Some(Datum::Bigint(n))) if n >= 0 => offset = n as usize,
2957                _ => return Err(SqlError::syntax("`offset` wants a whole number")),
2958            }
2959        } else {
2960            break;
2961        }
2962    }
2963
2964    Ok(Select {
2965        distinct,
2966        items,
2967        from,
2968        filter,
2969        group,
2970        order,
2971        limit,
2972        offset,
2973    })
2974}
2975
2976/// The top-level `and` terms of a `where`, which is the unit a term is pushed into a scan as.
2977fn conjuncts(e: Expr, out: &mut Vec<Expr>) {
2978    match e {
2979        Expr::And(xs) => xs.into_iter().for_each(|x| conjuncts(x, out)),
2980        other => out.push(other),
2981    }
2982}
2983
2984/// One entry of a `from` list: `t`, `s.t`, `t as x`, or a function call this does not have.
2985fn from_item(p: &mut P, left: bool) -> Result<From, SqlError> {
2986    let first = p
2987        .name()
2988        .ok_or_else(|| SqlError::syntax("`from` wants a table name"))?;
2989    let (namespace, name) = match p.eat_sym(".") {
2990        true => (
2991            Some(first),
2992            p.name()
2993                .ok_or_else(|| SqlError::syntax("a qualified name wants a table after the `.`"))?,
2994        ),
2995        false => (None, first),
2996    };
2997    // A set-returning function in a `from`. Its arguments are read so the rest of the statement
2998    // parses; what it is refused with is `resolve_from`'s message, and only if a row asks.
2999    let function = match p.eat_sym("(") {
3000        false => None,
3001        true => {
3002            let mut depth = 1;
3003            while depth > 0 {
3004                match p.peek() {
3005                    None => return Err(SqlError::syntax("a call in a `from` is not closed")),
3006                    Some(Tok::Sym(s)) if s == "(" => depth += 1,
3007                    Some(Tok::Sym(s)) if s == ")" => depth -= 1,
3008                    _ => {}
3009                }
3010                p.i += 1;
3011            }
3012            Some(name.clone())
3013        }
3014    };
3015    let alias = table_alias(p)?.unwrap_or_else(|| name.clone());
3016    Ok(From {
3017        namespace,
3018        table: name,
3019        alias,
3020        on: Vec::new(),
3021        left,
3022        function,
3023    })
3024}
3025
3026/// The name a `from` entry is known by in the rest of the query: `t x`, `t as x`, or nothing.
3027///
3028/// Separate from [`alias`] because the words that may follow a table are not the words that may
3029/// follow a select item, and a `from todos where …` whose `where` was taken as an alias would
3030/// refuse the query for a missing clause it does have.
3031fn table_alias(p: &mut P) -> Result<Option<String>, SqlError> {
3032    if p.eat_keyword("as") {
3033        return Ok(Some(
3034            p.name()
3035                .ok_or_else(|| SqlError::syntax("`as` wants a name"))?,
3036        ));
3037    }
3038    match p.keyword().as_deref() {
3039        Some("where") | Some("order") | Some("group") | Some("having") | Some("limit")
3040        | Some("offset") | Some("join") | Some("inner") | Some("left") | Some("right")
3041        | Some("full") | Some("outer") | Some("cross") | Some("natural") | Some("on")
3042        | Some("union") | Some("intersect") | Some("except") | None => Ok(None),
3043        Some(_) => Ok(p.name()),
3044    }
3045}
3046
3047/// A column reference: `c`, or `t.c`.
3048fn column_name(p: &mut P) -> Option<Name> {
3049    let first = p.name()?;
3050    if p.eat_sym(".") {
3051        return match p.name() {
3052            Some(column) => Some(Name {
3053                table: Some(first),
3054                column,
3055            }),
3056            None => Some(Name::bare(first)),
3057        };
3058    }
3059    Some(Name::bare(first))
3060}
3061
3062fn item(p: &mut P) -> Result<Item, SqlError> {
3063    if p.eat_sym("*") {
3064        return Ok(Item::All(None));
3065    }
3066    // `t.*`, and the four aggregates. Both are decided by looking one or two tokens ahead and
3067    // then putting them back: a select item is an expression, and `count` is a name until the `(`
3068    // says otherwise.
3069    let save = p.i;
3070    if let Some(name) = p.name() {
3071        if p.eat_sym(".") && p.eat_sym("*") {
3072            return Ok(Item::All(Some(name)));
3073        }
3074        p.i = save;
3075    }
3076    let save = p.i;
3077    if let Some(name) = p.name() {
3078        if p.eat_sym("(") {
3079            // Every one of the four is a plan operator rather than a loop here: `count` is the
3080            // join's own tally and the other three are [`crate::plan::Op::GroupBy`]'s
3081            // (docs/99 §99.9 item 6).
3082            let aggregate = match name.as_str() {
3083                "count" => {
3084                    if !p.eat_sym("*") {
3085                        return Err(SqlError::unsupported(
3086                            "`count` counts rows here: `count(*)` is the only form, and \
3087                             `count(c)` would be a count of the rows whose `c` is not null",
3088                        ));
3089                    }
3090                    Some(Item::Count(None))
3091                }
3092                "min" | "max" | "sum" => {
3093                    let agg = match name.as_str() {
3094                        "min" => Agg::Min,
3095                        "max" => Agg::Max,
3096                        _ => Agg::Sum,
3097                    };
3098                    let column = column_name(p).ok_or_else(|| {
3099                        SqlError::unsupported(format!(
3100                            "`{name}` takes a column here: `{name}(c)`, and no expression"
3101                        ))
3102                    })?;
3103                    Some(Item::Aggregate(agg, column, None))
3104                }
3105                _ => None,
3106            };
3107            if let Some(aggregate) = aggregate {
3108                if !p.eat_sym(")") {
3109                    return Err(SqlError::syntax("a call is not closed"));
3110                }
3111                let a = alias(p);
3112                return Ok(match aggregate {
3113                    Item::Count(_) => Item::Count(a),
3114                    Item::Aggregate(agg, c, _) => Item::Aggregate(agg, c, a),
3115                    other => other,
3116                });
3117            }
3118        }
3119        p.i = save;
3120    }
3121    let e = expr(p)?;
3122    let a = alias(p);
3123    // A column and a literal keep their own item kinds: those are what `crate::query` compiles
3124    // into the plan for a `group by` and a `distinct`, and an expression there would have to be
3125    // compiled rather than evaluated over what came back.
3126    Ok(match e {
3127        Expr::Column(n) => Item::Column(n, a),
3128        Expr::Literal(Some(d)) => Item::Literal(d, a),
3129        other => Item::Expr(other, a),
3130    })
3131}
3132
3133fn alias(p: &mut P) -> Option<String> {
3134    if p.eat_keyword("as") {
3135        return p.name();
3136    }
3137    // A bare alias, but not one of the words that ends a select item.
3138    match p.keyword().as_deref() {
3139        Some("from") | Some("where") | Some("group") | Some("having") | Some("order")
3140        | Some("limit") | Some("offset") | Some("as") | Some("union") | Some("intersect")
3141        | Some("except") | None => None,
3142        Some(_) => p.name(),
3143    }
3144}
3145
3146// -------------------------------------------------------------------------------------------
3147// Expressions
3148// -------------------------------------------------------------------------------------------
3149
3150/// `or` is the loosest, then `and`, then `not`, then the comparisons, then `||`, then a postfix
3151/// cast — PostgreSQL's precedence, and the reason a `where` is parsed as one expression rather
3152/// than as a list of conditions: `a = 1 or b = 2 and c = 3` means `a = 1 or (b = 2 and c = 3)`,
3153/// and a shape that could only hold a conjunction of disjunctions could not say so.
3154fn expr(p: &mut P) -> Result<Expr, SqlError> {
3155    let mut xs = vec![and_expr(p)?];
3156    while p.eat_keyword("or") {
3157        xs.push(and_expr(p)?);
3158    }
3159    Ok(match xs.len() {
3160        1 => xs.pop().expect("one term"),
3161        _ => Expr::Or(xs),
3162    })
3163}
3164
3165fn and_expr(p: &mut P) -> Result<Expr, SqlError> {
3166    let mut xs = vec![not_expr(p)?];
3167    while p.eat_keyword("and") {
3168        xs.push(not_expr(p)?);
3169    }
3170    Ok(match xs.len() {
3171        1 => xs.pop().expect("one term"),
3172        _ => Expr::And(xs),
3173    })
3174}
3175
3176fn not_expr(p: &mut P) -> Result<Expr, SqlError> {
3177    if p.eat_keyword("not") {
3178        return Ok(Expr::Not(Box::new(not_expr(p)?)));
3179    }
3180    cmp_expr(p)
3181}
3182
3183fn cmp_expr(p: &mut P) -> Result<Expr, SqlError> {
3184    let lhs = concat_expr(p)?;
3185    if p.eat_keyword("is") {
3186        let negated = p.eat_keyword("not");
3187        let to =
3188            match p.keyword().as_deref() {
3189                Some("null") => None,
3190                Some("true") => Some(true),
3191                Some("false") => Some(false),
3192                _ => return Err(SqlError::unsupported(
3193                    "`is` is followed by `null`, `true` or `false` here; `is distinct from` and \
3194                     `is unknown` are not in this SQL subset",
3195                )),
3196            };
3197        p.i += 1;
3198        return Ok(Expr::Is {
3199            value: Box::new(lhs),
3200            to,
3201            negated,
3202        });
3203    }
3204    let negated = match p.keyword().as_deref() {
3205        Some("not") if p.toks.get(p.i + 1) == Some(&Tok::Word("in".into())) => {
3206            p.i += 1;
3207            true
3208        }
3209        _ => false,
3210    };
3211    if p.eat_keyword("in") {
3212        if !p.eat_sym("(") {
3213            return Err(SqlError::syntax("`in` wants a bracketed list"));
3214        }
3215        let mut list = Vec::new();
3216        if !p.eat_sym(")") {
3217            loop {
3218                list.push(expr(p)?);
3219                if !p.eat_sym(",") {
3220                    break;
3221                }
3222            }
3223            if !p.eat_sym(")") {
3224                return Err(SqlError::syntax("an `in` list is not closed"));
3225            }
3226        }
3227        return Ok(Expr::In {
3228            value: Box::new(lhs),
3229            list,
3230            negated,
3231        });
3232    }
3233    if negated {
3234        return Err(SqlError::syntax("`not` here wants `in`"));
3235    }
3236    // `a OPERATOR(pg_catalog.~) b` — the fully-qualified spelling of an operator, which is what
3237    // `psql` writes so that a search path cannot change what its own query means.
3238    let symbol = if p.eat_keyword("operator") {
3239        if !p.eat_sym("(") {
3240            return Err(SqlError::syntax(
3241                "`operator` wants a bracketed operator name",
3242            ));
3243        }
3244        let mut sym = String::new();
3245        loop {
3246            match p.peek().cloned() {
3247                Some(Tok::Sym(s)) if s == ")" => {
3248                    p.i += 1;
3249                    break;
3250                }
3251                // The schema qualifying it is read and dropped: there is one operator of each
3252                // name here, and it is this one.
3253                Some(Tok::Sym(s)) if s == "." => {
3254                    sym.clear();
3255                    p.i += 1;
3256                }
3257                Some(Tok::Sym(s)) => {
3258                    sym.push_str(&s);
3259                    p.i += 1;
3260                }
3261                Some(Tok::Word(_)) => {
3262                    p.i += 1;
3263                }
3264                _ => return Err(SqlError::syntax("an `operator(…)` is not closed")),
3265            }
3266        }
3267        Some(sym)
3268    } else {
3269        None
3270    };
3271    let take = |p: &mut P, s: &str| -> bool {
3272        match &symbol {
3273            Some(sym) => sym == s,
3274            None => p.eat_sym(s),
3275        }
3276    };
3277    let op = if take(p, "=") {
3278        CmpOp::Eq
3279    } else if take(p, "<>") || take(p, "!=") {
3280        CmpOp::Ne
3281    } else if take(p, "<=") {
3282        CmpOp::Le
3283    } else if take(p, ">=") {
3284        CmpOp::Ge
3285    } else if take(p, "<") {
3286        CmpOp::Lt
3287    } else if take(p, ">") {
3288        CmpOp::Gt
3289    } else {
3290        for (sym, negated, insensitive) in [
3291            ("~", false, false),
3292            ("!~", true, false),
3293            ("~*", false, true),
3294            ("!~*", true, true),
3295        ] {
3296            if take(p, sym) {
3297                return Ok(Expr::Match {
3298                    value: Box::new(lhs),
3299                    pattern: Box::new(concat_expr(p)?),
3300                    negated,
3301                    insensitive,
3302                });
3303            }
3304        }
3305        return match symbol {
3306            Some(sym) => Err(SqlError::unsupported(format!(
3307                "`operator({sym})` is not one of the comparisons here: =, <>, <, <=, >, >=, and \
3308                 the four regular-expression matches ~, !~, ~*, !~*"
3309            ))),
3310            None => Ok(lhs),
3311        };
3312    };
3313    Ok(Expr::Cmp(Box::new(lhs), op, Box::new(concat_expr(p)?)))
3314}
3315
3316fn concat_expr(p: &mut P) -> Result<Expr, SqlError> {
3317    let mut e = postfix(p)?;
3318    while p.eat_sym("||") {
3319        e = Expr::Concat(Box::new(e), Box::new(postfix(p)?));
3320    }
3321    Ok(e)
3322}
3323
3324/// A primary, then whatever follows it: a cast, a subscript, or a collation.
3325fn postfix(p: &mut P) -> Result<Expr, SqlError> {
3326    let mut e = primary(p)?;
3327    loop {
3328        if p.eat_sym("::") {
3329            // `pg_catalog.regtype` and `int2[]`: the schema and the array brackets are read and
3330            // dropped, because what a cast is refused for is the type's own name.
3331            let mut ty = p
3332                .name()
3333                .ok_or_else(|| SqlError::syntax("`::` wants a type name"))?;
3334            if p.eat_sym(".") {
3335                ty = p
3336                    .name()
3337                    .ok_or_else(|| SqlError::syntax("a qualified type wants a name"))?;
3338            }
3339            while p.eat_sym("[") {
3340                if !p.eat_sym("]") {
3341                    return Err(SqlError::syntax("an array type wants `[]`"));
3342                }
3343            }
3344            e = Expr::Cast {
3345                value: Box::new(e),
3346                ty,
3347            };
3348        } else if p.eat_sym("[") {
3349            let index = expr(p)?;
3350            if !p.eat_sym("]") {
3351                return Err(SqlError::syntax("a subscript is not closed"));
3352            }
3353            e = Expr::Subscript(Box::new(e), Box::new(index));
3354        } else if p.eat_keyword("collate") {
3355            // There is one collation and it is the one every text column already compares in.
3356            let _ = column_name(p);
3357        } else {
3358            return Ok(e);
3359        }
3360    }
3361}
3362
3363fn primary(p: &mut P) -> Result<Expr, SqlError> {
3364    if let Some(lit) = p.literal() {
3365        return Ok(Expr::Literal(lit));
3366    }
3367    if p.eat_sym("(") {
3368        // A bracketed expression, or a subquery.
3369        let e = match p.keyword().as_deref() {
3370            Some("select") => {
3371                p.i += 1;
3372                let id = p.subquery_id();
3373                Expr::Subquery {
3374                    id,
3375                    select: Box::new(select(p)?),
3376                }
3377            }
3378            _ => expr(p)?,
3379        };
3380        if !p.eat_sym(")") {
3381            return Err(SqlError::syntax("a bracket is not closed"));
3382        }
3383        return Ok(e);
3384    }
3385    if p.eat_keyword("case") {
3386        let operand = match p.keyword().as_deref() {
3387            Some("when") => None,
3388            _ => Some(Box::new(expr(p)?)),
3389        };
3390        let mut arms = Vec::new();
3391        while p.eat_keyword("when") {
3392            let when = expr(p)?;
3393            if !p.eat_keyword("then") {
3394                return Err(SqlError::syntax("a `case` arm wants `then`"));
3395            }
3396            arms.push((when, expr(p)?));
3397        }
3398        let otherwise = match p.eat_keyword("else") {
3399            true => Some(Box::new(expr(p)?)),
3400            false => None,
3401        };
3402        if !p.eat_keyword("end") {
3403            return Err(SqlError::syntax("a `case` wants `end`"));
3404        }
3405        return Ok(Expr::Case {
3406            operand,
3407            arms,
3408            otherwise,
3409        });
3410    }
3411    let first = p
3412        .name()
3413        .ok_or_else(|| SqlError::syntax("an expression wants a column, a literal or a call"))?;
3414    if p.peek() == Some(&Tok::Sym("(".into())) {
3415        return call(p, first);
3416    }
3417    if p.eat_sym(".") {
3418        let second = p
3419            .name()
3420            .ok_or_else(|| SqlError::syntax(format!("`{first}.` wants a name")))?;
3421        // `pg_catalog.f(…)` — the schema is dropped, because there is one function of each name.
3422        if p.peek() == Some(&Tok::Sym("(".into())) {
3423            return call(p, second);
3424        }
3425        // `s.t.c` — a column qualified by a schema and a table. The schema is dropped for the
3426        // same reason a `from` entry's is: two namespaces, and a column belongs to a table.
3427        if p.eat_sym(".") {
3428            let third = p
3429                .name()
3430                .ok_or_else(|| SqlError::syntax("a qualified column wants a name"))?;
3431            return Ok(Expr::Column(Name {
3432                table: Some(second),
3433                column: third,
3434            }));
3435        }
3436        return Ok(Expr::Column(Name {
3437            table: Some(first),
3438            column: second,
3439        }));
3440    }
3441    Ok(Expr::Column(Name::bare(first)))
3442}
3443
3444/// A call, with the `(` still unread.
3445fn call(p: &mut P, name: String) -> Result<Expr, SqlError> {
3446    p.eat_sym("(");
3447    // `array(select …)` is a constructor rather than a call, and it is the one place a subquery
3448    // stands where an argument would.
3449    if p.keyword().as_deref() == Some("select") {
3450        p.i += 1;
3451        let id = p.subquery_id();
3452        let inner = Box::new(select(p)?);
3453        if !p.eat_sym(")") {
3454            return Err(SqlError::syntax("a subquery is not closed"));
3455        }
3456        return Ok(match name.as_str() {
3457            "array" => Expr::Array { id, select: inner },
3458            _ => Expr::Call {
3459                name,
3460                args: vec![Expr::Subquery { id, select: inner }],
3461            },
3462        });
3463    }
3464    let mut args = Vec::new();
3465    if !p.eat_sym(")") {
3466        loop {
3467            args.push(expr(p)?);
3468            if !p.eat_sym(",") {
3469                break;
3470            }
3471        }
3472        if !p.eat_sym(")") {
3473            return Err(SqlError::syntax(format!("`{name}(` is not closed")));
3474        }
3475    }
3476    Ok(match (name.as_str(), args.len()) {
3477        ("any", 1) => Expr::Any(Box::new(args.pop().expect("one argument"))),
3478        _ => Expr::Call { name, args },
3479    })
3480}
3481
3482/// What `select version()` answers.
3483///
3484/// It names Beck rather than pretending to be Postgres. A client that branches on this string is
3485/// better off failing on a name it does not know than succeeding on a version it will be wrong
3486/// about — and the `pg` prefix is there because a driver that parses this expects to find one.
3487pub fn version() -> String {
3488    format!(
3489        "PostgreSQL 15.0 (beck {}) — a read model, not a database",
3490        env!("CARGO_PKG_VERSION")
3491    )
3492}
3493
3494#[cfg(test)]
3495mod tests {
3496    use super::*;
3497
3498    fn ok(sql: &str) -> Select {
3499        match parse(sql).expect("parses") {
3500            Stmt::Select(s) => s,
3501            other => panic!("not a select: {other:?}"),
3502        }
3503    }
3504
3505    /// A reader with no program behind it, for the expressions that do not read one.
3506    struct NoRows;
3507
3508    impl Rows for NoRows {
3509        fn scan(&self, table: &Table) -> Result<Vec<Value>, SqlError> {
3510            Err(SqlError::no_table(format!(
3511                "no program: \"{}\"",
3512                table.name
3513            )))
3514        }
3515    }
3516
3517    /// The one literal a `where` compares against, for the parse tests below.
3518    fn literal_of(e: &Expr) -> &Cell {
3519        match e {
3520            Expr::Cmp(_, _, rhs) => match &**rhs {
3521                Expr::Literal(c) => c,
3522                other => panic!("not a literal: {other:?}"),
3523            },
3524            other => panic!("not a comparison: {other:?}"),
3525        }
3526    }
3527
3528    #[test]
3529    fn a_select_is_case_folded_and_a_quoted_name_is_not() {
3530        let s = ok("SELECT Text FROM Todos");
3531        assert_eq!(s.from[0].table, "todos");
3532        assert!(matches!(&s.items[0], Item::Column(c, _) if c.column == "text"));
3533        let s = ok(r#"select "Text" from "Todos""#);
3534        assert_eq!(s.from[0].table, "Todos");
3535        assert!(matches!(&s.items[0], Item::Column(c, _) if c.column == "Text"));
3536    }
3537
3538    /// `and` binds tighter than `or`, which is SQL's precedence and the one a person expects.
3539    ///
3540    /// The negative half is the one that matters: the whole `where` is **one** term, because `or`
3541    /// is at the top of it. A `where` parsed the other way round — `(a or b) and c` — is two terms
3542    /// and `crate::query` would push one of them into a scan on its own, which answers a different
3543    /// question.
3544    #[test]
3545    fn and_binds_tighter_than_or() {
3546        let s = ok("select * from t where a = 1 or b = 2 and c = 3");
3547        assert_eq!(s.filter.len(), 1);
3548        let Expr::Or(branches) = &s.filter[0] else {
3549            panic!("not an `or`: {:?}", s.filter[0])
3550        };
3551        assert_eq!(branches.len(), 2);
3552        assert!(matches!(&branches[0], Expr::Cmp(..)));
3553        assert!(
3554            matches!(&branches[1], Expr::And(xs) if xs.len() == 2),
3555            "{:?}",
3556            branches[1]
3557        );
3558        // And `a and b or c` is `(a and b) or c` from the other side, still one term.
3559        let s = ok("select * from t where a = 1 and b = 2 or c = 3");
3560        assert_eq!(s.filter.len(), 1);
3561        assert!(matches!(&s.filter[0], Expr::Or(xs) if xs.len() == 2));
3562    }
3563
3564    #[test]
3565    fn an_and_is_the_unit_a_where_is_pushed_down_as() {
3566        let s = ok("select * from t where a = 1 and b = 2 and c = 3");
3567        assert_eq!(s.filter.len(), 3);
3568    }
3569
3570    #[test]
3571    fn a_negative_literal_is_one_number() {
3572        let s = ok("select * from t where n < -3");
3573        assert_eq!(literal_of(&s.filter[0]), &Some(Datum::Bigint(-3)));
3574    }
3575
3576    #[test]
3577    fn an_escaped_quote_is_one_character() {
3578        let s = ok("select * from t where name = 'it''s'");
3579        assert_eq!(
3580            literal_of(&s.filter[0]),
3581            &Some(Datum::Text("it's".to_string()))
3582        );
3583        // And an escape string reads its escapes, which is what `E'\n'` is written for.
3584        let s = ok(r"select * from t where name = E'a\nb'");
3585        assert_eq!(
3586            literal_of(&s.filter[0]),
3587            &Some(Datum::Text("a\nb".to_string()))
3588        );
3589    }
3590
3591    #[test]
3592    fn a_write_is_refused_by_name() {
3593        let e = parse("insert into todos values (1)").expect_err("refused");
3594        assert_eq!(e.code, "0A000");
3595        assert!(e.message.contains("read-only"), "{}", e.message);
3596    }
3597
3598    #[test]
3599    fn an_aggregate_beside_a_column_needs_a_group_by() {
3600        let e = parse("select id, count(*) from todos").expect_err("refused");
3601        assert!(e.message.contains("group by"), "{}", e.message);
3602        // And with one, it is an ordinary query rather than a refusal.
3603        let s = ok("select id, count(*) from todos group by id");
3604        assert_eq!(s.group.len(), 1);
3605        assert!(crate::query::relational(&s));
3606    }
3607
3608    #[test]
3609    fn a_second_statement_is_refused() {
3610        assert!(parse("select 1; select 2").is_err());
3611    }
3612
3613    #[test]
3614    fn nulls_sort_last_and_compare_as_unknown() {
3615        let schema = Schema::default();
3616        let fields = vec![Field {
3617            column: Column {
3618                name: Arc::from("x"),
3619                ty: SqlTy::Bigint,
3620                nullable: true,
3621            },
3622            of: None,
3623        }];
3624        let ev = Eval::new(&schema, &fields, &NoRows);
3625        let term = |sql: &str| ok(&format!("select * from t where {sql}")).filter.remove(0);
3626        // A comparison against NULL is unknown, and unknown is neither true nor false.
3627        assert_eq!(ev.cell(&term("x = 1"), &[None]).expect("evaluates"), None);
3628        assert!(!ev.holds(&[term("x = 1")], &[None]).expect("evaluates"));
3629        assert!(!ev.holds(&[term("x <> 1")], &[None]).expect("evaluates"));
3630        // `is null` is the one comparison that answers about a NULL rather than propagating it.
3631        assert!(ev.holds(&[term("x is null")], &[None]).expect("evaluates"));
3632        assert!(!ev
3633            .holds(&[term("x is null")], &[Some(Datum::Bigint(1))])
3634            .expect("evaluates"));
3635        assert!(compare(&None, &Some(Datum::Bigint(1))).is_gt());
3636    }
3637
3638    #[test]
3639    fn a_case_evaluates_the_arm_that_matches_and_no_other() {
3640        let schema = Schema::default();
3641        let fields = Vec::new();
3642        let ev = Eval::new(&schema, &fields, &NoRows);
3643        let one = |sql: &str| {
3644            let s = ok(sql);
3645            let Item::Expr(e, _) = &s.items[0] else {
3646                panic!("not an expression: {:?}", s.items[0])
3647            };
3648            ev.cell(e, &[]).expect("evaluates")
3649        };
3650        // The `else` names a function this read model does not have, and is never reached — which
3651        // is the property `psql`'s `case when c.reloftype = 0 then '' else …::regtype…` needs.
3652        assert_eq!(
3653            one("select case when 1 = 1 then 'yes' else no_such_function() end"),
3654            Some(Datum::Text("yes".into()))
3655        );
3656        // Both forms, and a `case` that matches nothing is null rather than an error.
3657        assert_eq!(
3658            one("select case 2 when 1 then 'a' when 2 then 'b' end"),
3659            Some(Datum::Text("b".into()))
3660        );
3661        assert_eq!(one("select case 9 when 1 then 'a' end"), None);
3662    }
3663
3664    /// A regular expression is matched by a simulation, so a pattern that would make a
3665    /// backtracking matcher take exponential time takes linear time here instead.
3666    #[test]
3667    fn a_regular_expression_anchors_alternates_and_does_not_backtrack() {
3668        assert!(regex::matches("^(todos)$", "todos", false).expect("matches"));
3669        assert!(!regex::matches("^(todos)$", "my_todos", false).expect("matches"));
3670        assert!(regex::matches("^pg_", "pg_class", false).expect("matches"));
3671        assert!(!regex::matches("^pg_toast", "pg_class", false).expect("matches"));
3672        assert!(regex::matches("^(a|b)c$", "bc", false).expect("matches"));
3673        assert!(regex::matches("os", "todos", false).expect("matches"));
3674        assert!(regex::matches("^TODOS$", "todos", true).expect("matches"));
3675        assert!(regex::matches(r"^a\.b$", "a.b", false).expect("matches"));
3676        assert!(!regex::matches(r"^a\.b$", "axb", false).expect("matches"));
3677        assert!(regex::matches("^[a-c]+$", "abcabc", false).expect("matches"));
3678        assert!(!regex::matches("^[^a-c]+$", "abc", false).expect("matches"));
3679        // The one a backtracker cannot answer: 24 characters against a pattern whose branches
3680        // agree, which is `2^24` paths to try and one set of states to advance.
3681        assert!(!regex::matches("^(a|a)*b$", "aaaaaaaaaaaaaaaaaaaaaaaa", false).expect("matches"));
3682    }
3683
3684    #[test]
3685    fn a_join_carries_its_tables_its_names_and_its_equality() {
3686        let s = ok(
3687            "select o.id, i.name from orders o join items as i on o.item = i.id \
3688             where i.stocked = true order by o.id limit 5",
3689        );
3690        assert_eq!(s.from.len(), 2);
3691        assert_eq!(
3692            (s.from[0].table.as_str(), s.from[0].alias.as_str()),
3693            ("orders", "o")
3694        );
3695        assert_eq!(
3696            (s.from[1].table.as_str(), s.from[1].alias.as_str()),
3697            ("items", "i")
3698        );
3699        assert_eq!(s.from[1].on.len(), 1);
3700        assert_eq!(s.from[1].on[0].0.to_string(), "o.item");
3701        assert_eq!(s.from[1].on[0].1.to_string(), "i.id");
3702        // The clauses after the join still parse: an alias must not swallow `where`.
3703        assert_eq!(s.filter.len(), 1);
3704        assert_eq!(s.order.len(), 1);
3705        assert!(
3706            matches!(&s.order[0].by, OrderBy::Expr(Expr::Column(n)) if n.to_string() == "o.id"),
3707            "{:?}",
3708            s.order[0].by
3709        );
3710        assert_eq!(s.limit, Some(5));
3711        assert!(crate::query::relational(&s));
3712    }
3713
3714    #[test]
3715    fn a_bare_from_takes_the_tables_own_name_and_no_clause_becomes_an_alias() {
3716        for sql in [
3717            "select * from todos where done = true",
3718            "select * from todos order by text",
3719            "select count(*) from todos group by owner",
3720            "select * from todos limit 1",
3721        ] {
3722            let s = ok(sql);
3723            assert_eq!(s.from[0].alias, "todos", "{sql}");
3724        }
3725    }
3726
3727    /// A `left join` keeps the rows the right side has no match for, and the two joins the
3728    /// left-deep `from` list cannot express are refused by name.
3729    #[test]
3730    fn a_left_join_parses_and_the_two_that_cannot_be_left_deep_are_refused() {
3731        let s = ok("select * from a left outer join b on a.k = b.k");
3732        assert_eq!(s.from.len(), 2);
3733        assert!(s.from[1].left);
3734        assert!(!s.from[0].left);
3735        for sql in [
3736            "select * from a right join b on a.k = b.k",
3737            "select * from a full outer join b on a.k = b.k",
3738            "select * from a natural join b",
3739        ] {
3740            let e = parse(sql).expect_err("refused");
3741            assert_eq!(e.code, "0A000", "{sql}");
3742        }
3743        // A comma join and a `cross join` are the same thing, and neither carries an `on`.
3744        for sql in [
3745            "select * from a, b where a.k = b.k",
3746            "select * from a cross join b",
3747        ] {
3748            let s = ok(sql);
3749            assert_eq!(s.from.len(), 2, "{sql}");
3750            assert!(s.from[1].on.is_empty(), "{sql}");
3751        }
3752        // A join on something that is not an equality says so rather than parsing as a filter.
3753        let e = parse("select * from a join b on a.k < b.k").expect_err("refused");
3754        assert!(e.message.contains("equality"), "{}", e.message);
3755    }
3756
3757    #[test]
3758    fn a_catalogue_query_parses_the_way_psql_writes_one() {
3759        // The whole of `\d`'s list query, which is the shape everything here exists for.
3760        let s = ok("SELECT n.nspname as \"Schema\", c.relname as \"Name\", \
3761             CASE c.relkind WHEN 'r' THEN 'table' WHEN 'v' THEN 'view' END as \"Type\", \
3762             pg_catalog.pg_get_userbyid(c.relowner) as \"Owner\" \
3763             FROM pg_catalog.pg_class c \
3764             LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace \
3765             LEFT JOIN pg_catalog.pg_am am ON am.oid = c.relam \
3766             WHERE c.relkind IN ('r','p','v','m','S','f','') \
3767             AND n.nspname <> 'pg_catalog' AND n.nspname !~ '^pg_toast' \
3768             AND pg_catalog.pg_table_is_visible(c.oid) ORDER BY 1,2");
3769        assert_eq!(s.from.len(), 3);
3770        assert_eq!(s.from[0].namespace.as_deref(), Some("pg_catalog"));
3771        assert!(s.from[1].left && s.from[2].left);
3772        assert_eq!(s.filter.len(), 4);
3773        assert!(matches!(&s.filter[0], Expr::In { .. }));
3774        assert!(matches!(&s.filter[2], Expr::Match { negated: true, .. }));
3775        assert_eq!(s.order.len(), 2);
3776        assert!(matches!(s.order[0].by, OrderBy::Ordinal(1)));
3777        assert!(matches!(s.order[1].by, OrderBy::Ordinal(2)));
3778        // And the operator spelling `psql` uses so a search path cannot change what it means.
3779        let s = ok("select c.oid from pg_catalog.pg_class c \
3780             where c.relname OPERATOR(pg_catalog.~) '^(todos)$' COLLATE pg_catalog.default");
3781        assert!(matches!(&s.filter[0], Expr::Match { negated: false, .. }));
3782    }
3783
3784    #[test]
3785    fn a_union_is_one_statement_and_its_order_by_is_the_unions() {
3786        let Stmt::Union {
3787            branches,
3788            all,
3789            order,
3790            ..
3791        } = parse("select a from t union select b from u order by 1").expect("parses")
3792        else {
3793            panic!("not a union")
3794        };
3795        assert_eq!(branches.len(), 2);
3796        assert!(!all);
3797        assert_eq!(order.len(), 1);
3798        assert!(branches[1].order.is_empty());
3799        assert!(parse("select 1 intersect select 2").is_err());
3800    }
3801
3802    #[test]
3803    fn a_having_is_refused_and_says_what_a_where_does_instead() {
3804        let e = parse("select owner, count(*) from t group by owner having count(*) > 1")
3805            .expect_err("refused");
3806        assert!(
3807            e.message.contains("before they are grouped"),
3808            "{}",
3809            e.message
3810        );
3811    }
3812
3813    #[test]
3814    fn only_a_query_that_relates_groups_or_deduplicates_needs_the_plan() {
3815        // The scan answers these, `count(*)` included: an arrangement already knows its size.
3816        for sql in [
3817            "select * from todos",
3818            "select count(*) from todos",
3819            "select count(*) from todos where done = false",
3820            "select 1",
3821        ] {
3822            assert!(!crate::query::relational(&ok(sql)), "{sql}");
3823        }
3824        for sql in [
3825            "select distinct owner from todos",
3826            "select owner, count(*) from todos group by owner",
3827            "select sum(amount) from postings",
3828            "select * from a join b on a.k = b.k",
3829        ] {
3830            assert!(crate::query::relational(&ok(sql)), "{sql}");
3831        }
3832    }
3833}