Skip to main content

mz_sql/
names.rs

1// Copyright Materialize, Inc. and contributors. All rights reserved.
2//
3// Use of this software is governed by the Business Source License
4// included in the LICENSE file.
5//
6// As of the Change Date specified in that file, in accordance with
7// the Business Source License, use of this software will be governed
8// by the Apache License, Version 2.0.
9
10//! Structured name types for SQL objects.
11
12use std::borrow::Cow;
13use std::collections::{BTreeMap, BTreeSet};
14use std::fmt;
15use std::str::FromStr;
16use std::sync::LazyLock;
17
18use anyhow::anyhow;
19use mz_controller_types::{ClusterId, ReplicaId};
20use mz_expr::LocalId;
21use mz_ore::assert_none;
22use mz_ore::cast::CastFrom;
23use mz_ore::str::StrExt;
24use mz_repr::network_policy_id::NetworkPolicyId;
25use mz_repr::role_id::RoleId;
26use mz_repr::{CatalogItemId, GlobalId, RelationVersion};
27use mz_repr::{ColumnName, RelationVersionSelector};
28use mz_sql_parser::ast::visit_mut::VisitMutNode;
29use mz_sql_parser::ast::{Expr, RawNetworkPolicyName, Version};
30use mz_sql_parser::ident;
31use proptest_derive::Arbitrary;
32use serde::{Deserialize, Serialize};
33use uncased::UncasedStr;
34
35use crate::ast::display::{AstDisplay, AstFormatter};
36use crate::ast::fold::{Fold, FoldNode};
37use crate::ast::visit::{Visit, VisitNode};
38use crate::ast::visit_mut::VisitMut;
39use crate::ast::{
40    self, AstInfo, Cte, CteBlock, CteMutRec, DocOnIdentifier, GrantTargetSpecification,
41    GrantTargetSpecificationInner, Ident, MutRecBlock, ObjectType, Query, Raw, RawClusterName,
42    RawDataType, RawItemName, Statement, UnresolvedItemName, UnresolvedObjectName,
43};
44use crate::catalog::{
45    CatalogError, CatalogItem, CatalogItemType, CatalogType, CatalogTypeDetails, SessionCatalog,
46};
47use crate::normalize;
48use crate::plan::PlanError;
49
50/// A fully-qualified human readable name of an item in the catalog.
51///
52/// Catalog names compare case sensitively. Use
53/// [`normalize::unresolved_item_name`] to
54/// perform proper case folding if converting an [`UnresolvedItemName`] to a
55/// `FullItemName`.
56///
57/// [`normalize::unresolved_item_name`]: crate::normalize::unresolved_item_name
58#[derive(
59    Debug,
60    Clone,
61    Eq,
62    PartialEq,
63    Hash,
64    Ord,
65    PartialOrd,
66    Serialize,
67    Deserialize
68)]
69pub struct FullItemName {
70    /// The database name.
71    pub database: RawDatabaseSpecifier,
72    /// The schema name.
73    pub schema: String,
74    /// The item name.
75    pub item: String,
76}
77
78impl FullItemName {
79    /// Converts the name into a string vector of its constituent parts:
80    /// database (if present), schema, and item.
81    pub fn into_parts(self) -> Vec<String> {
82        let mut parts = vec![];
83        if let RawDatabaseSpecifier::Name(name) = self.database {
84            parts.push(name);
85        }
86        parts.push(self.schema);
87        parts.push(self.item);
88        parts
89    }
90}
91
92impl fmt::Display for FullItemName {
93    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
94        if let RawDatabaseSpecifier::Name(database) = &self.database {
95            write!(f, "{}.", database)?;
96        }
97        write!(f, "{}.{}", self.schema, self.item)
98    }
99}
100
101impl From<FullItemName> for UnresolvedItemName {
102    fn from(full_name: FullItemName) -> UnresolvedItemName {
103        // TODO(parkmycar): Change UnresolvedItemName to use `Ident` internally.
104        let mut name_parts = Vec::new();
105        if let RawDatabaseSpecifier::Name(database) = full_name.database {
106            name_parts.push(Ident::new_unchecked(database));
107        }
108        name_parts.push(Ident::new_unchecked(full_name.schema));
109        name_parts.push(Ident::new_unchecked(full_name.item));
110        UnresolvedItemName(name_parts)
111    }
112}
113
114/// A fully-qualified non-human readable name of an item in the catalog using IDs for the database
115/// and schema.
116#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize)]
117pub struct QualifiedItemName {
118    pub qualifiers: ItemQualifiers,
119    pub item: String,
120}
121
122// Do not implement [`Display`] for [`QualifiedItemName`]. [`FullItemName`] should always be
123// displayed instead.
124static_assertions::assert_not_impl_any!(QualifiedItemName: fmt::Display);
125
126/// An optionally-qualified human-readable name of an item in the catalog.
127///
128/// This is like a [`FullItemName`], but either the database or schema name may be
129/// omitted.
130#[derive(
131    Clone,
132    Debug,
133    Serialize,
134    Deserialize,
135    PartialEq,
136    Eq,
137    PartialOrd,
138    Ord,
139    Hash
140)]
141pub struct PartialItemName {
142    pub database: Option<String>,
143    pub schema: Option<String>,
144    pub item: String,
145}
146
147impl PartialItemName {
148    // Whether either self or other might be a (possibly differently qualified)
149    // version of the other.
150    pub fn matches(&self, other: &Self) -> bool {
151        match (&self.database, &other.database) {
152            (Some(d1), Some(d2)) if d1 != d2 => return false,
153            _ => (),
154        }
155        match (&self.schema, &other.schema) {
156            (Some(s1), Some(s2)) if s1 != s2 => return false,
157            _ => (),
158        }
159        self.item == other.item
160    }
161}
162
163impl fmt::Display for PartialItemName {
164    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
165        if let Some(database) = &self.database {
166            write!(f, "{}.", database)?;
167        }
168        if let Some(schema) = &self.schema {
169            write!(f, "{}.", schema)?;
170        }
171        write!(f, "{}", self.item)
172    }
173}
174
175impl From<FullItemName> for PartialItemName {
176    fn from(n: FullItemName) -> PartialItemName {
177        let database = match n.database {
178            RawDatabaseSpecifier::Ambient => None,
179            RawDatabaseSpecifier::Name(name) => Some(name),
180        };
181        PartialItemName {
182            database,
183            schema: Some(n.schema),
184            item: n.item,
185        }
186    }
187}
188
189impl From<String> for PartialItemName {
190    fn from(item: String) -> Self {
191        PartialItemName {
192            database: None,
193            schema: None,
194            item,
195        }
196    }
197}
198
199impl From<PartialItemName> for UnresolvedItemName {
200    fn from(partial_name: PartialItemName) -> UnresolvedItemName {
201        // TODO(parkmycar): Change UnresolvedItemName to use `Ident` internally.
202        let mut name_parts = Vec::new();
203        if let Some(database) = partial_name.database {
204            name_parts.push(Ident::new_unchecked(database));
205        }
206        if let Some(schema) = partial_name.schema {
207            name_parts.push(Ident::new_unchecked(schema));
208        }
209        name_parts.push(Ident::new_unchecked(partial_name.item));
210        UnresolvedItemName(name_parts)
211    }
212}
213
214/// A fully-qualified human readable name of a schema in the catalog.
215#[derive(
216    Debug,
217    Clone,
218    Eq,
219    PartialEq,
220    Hash,
221    PartialOrd,
222    Ord,
223    Serialize,
224    Deserialize
225)]
226pub struct FullSchemaName {
227    /// The database name
228    pub database: RawDatabaseSpecifier,
229    /// The schema name
230    pub schema: String,
231}
232
233impl fmt::Display for FullSchemaName {
234    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
235        if let RawDatabaseSpecifier::Name(database) = &self.database {
236            write!(f, "{}.", database)?;
237        }
238        write!(f, "{}", self.schema)
239    }
240}
241
242/// The fully-qualified non-human readable name of a schema in the catalog.
243#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
244pub struct QualifiedSchemaName {
245    pub database: ResolvedDatabaseSpecifier,
246    pub schema: String,
247}
248
249impl fmt::Display for QualifiedSchemaName {
250    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
251        match &self.database {
252            ResolvedDatabaseSpecifier::Ambient => f.write_str(&self.schema),
253            ResolvedDatabaseSpecifier::Id(id) => write!(f, "{}.{}", id, self.schema),
254        }
255    }
256}
257
258/// An optionally-qualified name of an schema in the catalog.
259///
260/// This is like a [`FullSchemaName`], but either the database or schema name may be
261/// omitted.
262#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
263pub struct PartialSchemaName {
264    pub database: Option<String>,
265    pub schema: String,
266}
267
268impl fmt::Display for PartialSchemaName {
269    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
270        if let Some(database) = &self.database {
271            write!(f, "{}.", database)?;
272        }
273        write!(f, "{}", self.schema)
274    }
275}
276
277/// A human readable name of a database.
278#[derive(
279    Debug,
280    Clone,
281    Eq,
282    PartialEq,
283    Ord,
284    PartialOrd,
285    Hash,
286    Serialize,
287    Deserialize
288)]
289pub enum RawDatabaseSpecifier {
290    /// The "ambient" database, which is always present and is not named
291    /// explicitly, but by omission.
292    Ambient,
293    /// A normal database with a name.
294    Name(String),
295}
296
297impl fmt::Display for RawDatabaseSpecifier {
298    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
299        match self {
300            Self::Ambient => f.write_str("<none>"),
301            Self::Name(name) => f.write_str(name),
302        }
303    }
304}
305
306impl From<Option<String>> for RawDatabaseSpecifier {
307    fn from(s: Option<String>) -> RawDatabaseSpecifier {
308        match s {
309            None => Self::Ambient,
310            Some(name) => Self::Name(name),
311        }
312    }
313}
314
315/// An id of a database.
316#[derive(
317    Debug,
318    Clone,
319    Copy,
320    Eq,
321    PartialEq,
322    Hash,
323    PartialOrd,
324    Ord,
325    Serialize,
326    Deserialize,
327    Arbitrary
328)]
329pub enum ResolvedDatabaseSpecifier {
330    /// The "ambient" database, which is always present and is not named
331    /// explicitly, but by omission.
332    Ambient,
333    /// A normal database with a name.
334    Id(DatabaseId),
335}
336
337impl ResolvedDatabaseSpecifier {
338    pub fn id(&self) -> Option<DatabaseId> {
339        match self {
340            ResolvedDatabaseSpecifier::Ambient => None,
341            ResolvedDatabaseSpecifier::Id(id) => Some(*id),
342        }
343    }
344}
345
346impl fmt::Display for ResolvedDatabaseSpecifier {
347    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
348        match self {
349            Self::Ambient => f.write_str("<none>"),
350            Self::Id(id) => write!(f, "{}", id),
351        }
352    }
353}
354
355impl AstDisplay for ResolvedDatabaseSpecifier {
356    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
357        f.write_str(format!("{}", self));
358    }
359}
360
361impl From<DatabaseId> for ResolvedDatabaseSpecifier {
362    fn from(id: DatabaseId) -> Self {
363        Self::Id(id)
364    }
365}
366
367impl From<Option<DatabaseId>> for ResolvedDatabaseSpecifier {
368    fn from(id: Option<DatabaseId>) -> Self {
369        match id {
370            Some(id) => Self::Id(id),
371            None => Self::Ambient,
372        }
373    }
374}
375
376/*
377 * TODO(jkosh44) It's possible that in order to fix
378 * https://github.com/MaterializeInc/database-issues/issues/2689 we will need to assign temporary
379 * schemas unique Ids. If/when that happens we can remove this enum and refer to all schemas by
380 * their Id.
381 */
382/// An id of a schema.
383#[derive(
384    Debug,
385    Clone,
386    Copy,
387    Eq,
388    PartialEq,
389    Hash,
390    PartialOrd,
391    Ord,
392    Serialize,
393    Deserialize
394)]
395pub enum SchemaSpecifier {
396    /// A temporary schema
397    Temporary,
398    /// A normal database with a name.
399    Id(SchemaId),
400}
401
402impl SchemaSpecifier {
403    const TEMPORARY_SCHEMA_ID: u64 = 0;
404
405    pub fn is_system(&self) -> bool {
406        match self {
407            SchemaSpecifier::Temporary => false,
408            SchemaSpecifier::Id(id) => id.is_system(),
409        }
410    }
411
412    pub fn is_user(&self) -> bool {
413        match self {
414            SchemaSpecifier::Temporary => true,
415            SchemaSpecifier::Id(id) => id.is_user(),
416        }
417    }
418
419    pub fn is_temporary(&self) -> bool {
420        matches!(self, SchemaSpecifier::Temporary)
421    }
422}
423
424impl fmt::Display for SchemaSpecifier {
425    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
426        match self {
427            Self::Temporary => f.write_str(format!("{}", Self::TEMPORARY_SCHEMA_ID).as_str()),
428            Self::Id(id) => write!(f, "{}", id),
429        }
430    }
431}
432
433impl AstDisplay for SchemaSpecifier {
434    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
435        f.write_str(format!("{}", self));
436    }
437}
438
439impl From<SchemaId> for SchemaSpecifier {
440    fn from(id: SchemaId) -> SchemaSpecifier {
441        match id {
442            SchemaId::User(id) if id == SchemaSpecifier::TEMPORARY_SCHEMA_ID => {
443                SchemaSpecifier::Temporary
444            }
445            schema_id => SchemaSpecifier::Id(schema_id),
446        }
447    }
448}
449
450impl From<&SchemaSpecifier> for SchemaId {
451    fn from(schema_spec: &SchemaSpecifier) -> Self {
452        match schema_spec {
453            SchemaSpecifier::Temporary => SchemaId::User(SchemaSpecifier::TEMPORARY_SCHEMA_ID),
454            SchemaSpecifier::Id(id) => id.clone(),
455        }
456    }
457}
458
459impl From<SchemaSpecifier> for SchemaId {
460    fn from(schema_spec: SchemaSpecifier) -> Self {
461        match schema_spec {
462            SchemaSpecifier::Temporary => SchemaId::User(SchemaSpecifier::TEMPORARY_SCHEMA_ID),
463            SchemaSpecifier::Id(id) => id,
464        }
465    }
466}
467
468// Aug is the type variable assigned to an AST that has already been
469// name-resolved. An AST in this state has global IDs populated next to table
470// names, and local IDs assigned to CTE definitions and references.
471#[derive(Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Copy, Clone, Default)]
472pub struct Aug;
473
474#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord, Serialize)]
475pub struct ItemQualifiers {
476    pub database_spec: ResolvedDatabaseSpecifier,
477    pub schema_spec: SchemaSpecifier,
478}
479
480#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
481pub enum ResolvedItemName {
482    Item {
483        id: CatalogItemId,
484        qualifiers: ItemQualifiers,
485        full_name: FullItemName,
486        // Whether this object, when printed out, should use [id AS name] syntax. We
487        // want this for things like tables and sources, but not for things like
488        // types.
489        print_id: bool,
490        version: RelationVersionSelector,
491    },
492    Cte {
493        id: LocalId,
494        name: String,
495    },
496    Error,
497}
498
499impl ResolvedItemName {
500    pub fn full_name_str(&self) -> String {
501        match self {
502            ResolvedItemName::Item { full_name, .. } => full_name.to_string(),
503            ResolvedItemName::Cte { name, .. } => name.clone(),
504            ResolvedItemName::Error => "error in name resolution".to_string(),
505        }
506    }
507
508    pub fn full_item_name(&self) -> &FullItemName {
509        match self {
510            ResolvedItemName::Item { full_name, .. } => full_name,
511            _ => panic!("cannot call object_full_name on non-object"),
512        }
513    }
514
515    pub fn item_id(&self) -> &CatalogItemId {
516        match self {
517            ResolvedItemName::Item { id, .. } => id,
518            _ => panic!("cannot call item_id on non-object"),
519        }
520    }
521
522    pub fn version(&self) -> &RelationVersionSelector {
523        match self {
524            ResolvedItemName::Item { version, .. } => version,
525            _ => panic!("cannot call version on non-object"),
526        }
527    }
528}
529
530impl AstDisplay for ResolvedItemName {
531    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
532        match self {
533            ResolvedItemName::Item {
534                id,
535                qualifiers: _,
536                full_name,
537                print_id,
538                version,
539            } => {
540                if *print_id {
541                    f.write_str(format!("[{} AS ", id));
542                }
543                if let RawDatabaseSpecifier::Name(database) = &full_name.database {
544                    f.write_node(&Ident::new_unchecked(database));
545                    f.write_str(".");
546                }
547                f.write_node(&Ident::new_unchecked(&full_name.schema));
548                f.write_str(".");
549                f.write_node(&Ident::new_unchecked(&full_name.item));
550
551                if *print_id {
552                    if let RelationVersionSelector::Specific(version) = version {
553                        let version: Version = (*version).into();
554                        f.write_str(" VERSION ");
555                        f.write_node(&version);
556                    }
557                }
558
559                if *print_id {
560                    f.write_str("]");
561                }
562            }
563            ResolvedItemName::Cte { name, .. } => f.write_node(&Ident::new_unchecked(name)),
564            ResolvedItemName::Error => {}
565        }
566    }
567}
568
569impl std::fmt::Display for ResolvedItemName {
570    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
571        f.write_str(self.to_ast_string_simple().as_str())
572    }
573}
574
575#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
576pub enum ResolvedColumnReference {
577    Column { name: ColumnName, index: usize },
578    Error,
579}
580
581impl AstDisplay for ResolvedColumnReference {
582    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
583        match self {
584            ResolvedColumnReference::Column { name, .. } => {
585                f.write_node(&Ident::new_unchecked(name.as_str()));
586            }
587            ResolvedColumnReference::Error => {}
588        }
589    }
590}
591
592impl std::fmt::Display for ResolvedColumnReference {
593    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
594        f.write_str(self.to_ast_string_simple().as_str())
595    }
596}
597
598#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
599pub enum ResolvedSchemaName {
600    Schema {
601        database_spec: ResolvedDatabaseSpecifier,
602        schema_spec: SchemaSpecifier,
603        full_name: FullSchemaName,
604    },
605    Error,
606}
607
608impl ResolvedSchemaName {
609    /// Panics if this is `Self::Error`.
610    pub fn database_spec(&self) -> &ResolvedDatabaseSpecifier {
611        match self {
612            ResolvedSchemaName::Schema { database_spec, .. } => database_spec,
613            ResolvedSchemaName::Error => {
614                unreachable!("should have been handled by name resolution")
615            }
616        }
617    }
618
619    /// Panics if this is `Self::Error`.
620    pub fn schema_spec(&self) -> &SchemaSpecifier {
621        match self {
622            ResolvedSchemaName::Schema { schema_spec, .. } => schema_spec,
623            ResolvedSchemaName::Error => {
624                unreachable!("should have been handled by name resolution")
625            }
626        }
627    }
628}
629
630impl AstDisplay for ResolvedSchemaName {
631    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
632        match self {
633            ResolvedSchemaName::Schema { full_name, .. } => {
634                if let RawDatabaseSpecifier::Name(database) = &full_name.database {
635                    f.write_node(&Ident::new_unchecked(database));
636                    f.write_str(".");
637                }
638                f.write_node(&Ident::new_unchecked(&full_name.schema));
639            }
640            ResolvedSchemaName::Error => {}
641        }
642    }
643}
644
645#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
646pub enum ResolvedDatabaseName {
647    Database { id: DatabaseId, name: String },
648    Error,
649}
650
651impl ResolvedDatabaseName {
652    /// Panics if this is `Self::Error`.
653    pub fn database_id(&self) -> &DatabaseId {
654        match self {
655            ResolvedDatabaseName::Database { id, .. } => id,
656            ResolvedDatabaseName::Error => {
657                unreachable!("should have been handled by name resolution")
658            }
659        }
660    }
661}
662
663impl AstDisplay for ResolvedDatabaseName {
664    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
665        match self {
666            ResolvedDatabaseName::Database { name, .. } => {
667                f.write_node(&Ident::new_unchecked(name))
668            }
669            ResolvedDatabaseName::Error => {}
670        }
671    }
672}
673
674#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
675pub struct ResolvedClusterName {
676    pub id: ClusterId,
677    /// If set, a name to print in the `AstDisplay` implementation instead of
678    /// `None`. This is only meant to be used by the `NameSimplifier`.
679    ///
680    /// NOTE(benesch): it would be much clearer if the `NameSimplifier` folded
681    /// the AST into a different metadata type, to avoid polluting the resolved
682    /// AST with this field.
683    pub print_name: Option<String>,
684}
685
686impl AstDisplay for ResolvedClusterName {
687    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
688        if let Some(print_name) = &self.print_name {
689            f.write_node(&Ident::new_unchecked(print_name))
690        } else {
691            f.write_str(format!("[{}]", self.id))
692        }
693    }
694}
695
696#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
697pub struct ResolvedClusterReplicaName {
698    pub cluster_id: ClusterId,
699    pub replica_id: ReplicaId,
700}
701
702impl AstDisplay for ResolvedClusterReplicaName {
703    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
704        f.write_str(format!("[{}.{}]", self.cluster_id, self.replica_id))
705    }
706}
707
708#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
709pub enum ResolvedDataType {
710    AnonymousList(Box<ResolvedDataType>),
711    AnonymousMap {
712        key_type: Box<ResolvedDataType>,
713        value_type: Box<ResolvedDataType>,
714    },
715    Named {
716        id: CatalogItemId,
717        qualifiers: ItemQualifiers,
718        full_name: FullItemName,
719        modifiers: Vec<i64>,
720        print_id: bool,
721    },
722    Error,
723}
724
725impl AstDisplay for ResolvedDataType {
726    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
727        match self {
728            ResolvedDataType::AnonymousList(element_type) => {
729                element_type.fmt(f);
730                f.write_str(" list");
731            }
732            ResolvedDataType::AnonymousMap {
733                key_type,
734                value_type,
735            } => {
736                f.write_str("map[");
737                key_type.fmt(f);
738                f.write_str("=>");
739                value_type.fmt(f);
740                f.write_str("]");
741            }
742            ResolvedDataType::Named {
743                id,
744                full_name,
745                modifiers,
746                print_id,
747                ..
748            } => {
749                if *print_id {
750                    f.write_str(format!("[{} AS ", id));
751                }
752                if let RawDatabaseSpecifier::Name(database) = &full_name.database {
753                    f.write_node(&Ident::new_unchecked(database));
754                    f.write_str(".");
755                }
756
757                f.write_node(&Ident::new_unchecked(&full_name.schema));
758                f.write_str(".");
759
760                f.write_node(&Ident::new_unchecked(&full_name.item));
761                if *print_id {
762                    f.write_str("]");
763                }
764                if modifiers.len() > 0 {
765                    f.write_str("(");
766                    f.write_node(&ast::display::comma_separated(modifiers));
767                    f.write_str(")");
768                }
769            }
770            ResolvedDataType::Error => {}
771        }
772    }
773}
774
775impl ResolvedDataType {
776    /// Return the name of `self`'s item without qualification or IDs.
777    ///
778    /// This is used to generate default column names for cast operations.
779    pub fn unqualified_item_name(&self) -> String {
780        let mut res = String::new();
781        match self {
782            ResolvedDataType::AnonymousList(element_type) => {
783                res += &element_type.unqualified_item_name();
784                res += " list";
785            }
786            ResolvedDataType::AnonymousMap {
787                key_type,
788                value_type,
789            } => {
790                res += "map[";
791                res += &key_type.unqualified_item_name();
792                res += "=>";
793                res += &value_type.unqualified_item_name();
794                res += "]";
795            }
796            ResolvedDataType::Named { full_name, .. } => {
797                res += &full_name.item;
798            }
799            ResolvedDataType::Error => {}
800        }
801        res
802    }
803
804    /// Return the name of `self`'s without IDs or modifiers.
805    ///
806    /// This is used for error messages.
807    pub fn human_readable_name(&self) -> String {
808        let mut res = String::new();
809        match self {
810            ResolvedDataType::AnonymousList(element_type) => {
811                res += &element_type.human_readable_name();
812                res += " list";
813            }
814            ResolvedDataType::AnonymousMap {
815                key_type,
816                value_type,
817            } => {
818                res += "map[";
819                res += &key_type.human_readable_name();
820                res += "=>";
821                res += &value_type.human_readable_name();
822                res += "]";
823            }
824            ResolvedDataType::Named { full_name, .. } => {
825                if let RawDatabaseSpecifier::Name(database) = &full_name.database {
826                    res += database;
827                    res += ".";
828                }
829                res += &full_name.schema;
830                res += ".";
831                res += &full_name.item;
832            }
833            ResolvedDataType::Error => {}
834        }
835        res
836    }
837}
838
839impl fmt::Display for ResolvedDataType {
840    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
841        f.write_str(self.to_ast_string_simple().as_str())
842    }
843}
844
845#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
846pub struct ResolvedRoleName {
847    pub id: RoleId,
848    pub name: String,
849}
850
851impl AstDisplay for ResolvedRoleName {
852    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
853        f.write_str(format!("[{} AS {}]", self.id, self.name));
854    }
855}
856
857#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
858pub struct ResolvedNetworkPolicyName {
859    pub id: NetworkPolicyId,
860    pub name: String,
861}
862
863impl AstDisplay for ResolvedNetworkPolicyName {
864    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
865        f.write_str(format!("[{} AS {}]", self.id, self.name));
866    }
867}
868
869#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
870pub enum ResolvedObjectName {
871    Cluster(ResolvedClusterName),
872    ClusterReplica(ResolvedClusterReplicaName),
873    Database(ResolvedDatabaseName),
874    Schema(ResolvedSchemaName),
875    Role(ResolvedRoleName),
876    NetworkPolicy(ResolvedNetworkPolicyName),
877    Item(ResolvedItemName),
878}
879
880impl AstDisplay for ResolvedObjectName {
881    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
882        match self {
883            ResolvedObjectName::Cluster(n) => f.write_node(n),
884            ResolvedObjectName::ClusterReplica(n) => f.write_node(n),
885            ResolvedObjectName::Database(n) => f.write_node(n),
886            ResolvedObjectName::Schema(n) => f.write_node(n),
887            ResolvedObjectName::Role(n) => f.write_node(n),
888            ResolvedObjectName::Item(n) => f.write_node(n),
889            ResolvedObjectName::NetworkPolicy(n) => f.write_node(n),
890        }
891    }
892}
893
894impl AstInfo for Aug {
895    type NestedStatement = Statement<Raw>;
896    type ItemName = ResolvedItemName;
897    type ColumnReference = ResolvedColumnReference;
898    type SchemaName = ResolvedSchemaName;
899    type DatabaseName = ResolvedDatabaseName;
900    type ClusterName = ResolvedClusterName;
901    type DataType = ResolvedDataType;
902    type CteId = LocalId;
903    type RoleName = ResolvedRoleName;
904    type ObjectName = ResolvedObjectName;
905    type NetworkPolicyName = ResolvedNetworkPolicyName;
906}
907
908/// The identifier for a schema.
909#[derive(
910    Clone,
911    Copy,
912    Debug,
913    Eq,
914    PartialEq,
915    Ord,
916    PartialOrd,
917    Hash,
918    Serialize,
919    Deserialize,
920    Arbitrary
921)]
922pub enum SchemaId {
923    User(u64),
924    System(u64),
925}
926
927impl SchemaId {
928    pub fn is_user(&self) -> bool {
929        matches!(self, SchemaId::User(_))
930    }
931
932    pub fn is_system(&self) -> bool {
933        matches!(self, SchemaId::System(_))
934    }
935}
936
937impl fmt::Display for SchemaId {
938    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
939        match self {
940            SchemaId::System(id) => write!(f, "s{}", id),
941            SchemaId::User(id) => write!(f, "u{}", id),
942        }
943    }
944}
945
946impl FromStr for SchemaId {
947    type Err = PlanError;
948
949    fn from_str(s: &str) -> Result<Self, Self::Err> {
950        if s.len() < 2 {
951            return Err(PlanError::Unstructured(format!(
952                "couldn't parse SchemaId {}",
953                s
954            )));
955        }
956        let val: u64 = s[1..].parse()?;
957        match s.chars().next() {
958            Some('s') => Ok(SchemaId::System(val)),
959            Some('u') => Ok(SchemaId::User(val)),
960            _ => Err(PlanError::Unstructured(format!(
961                "couldn't parse SchemaId {}",
962                s
963            ))),
964        }
965    }
966}
967
968/// The identifier for a database.
969#[derive(
970    Clone,
971    Copy,
972    Debug,
973    Eq,
974    PartialEq,
975    Ord,
976    PartialOrd,
977    Hash,
978    Serialize,
979    Deserialize,
980    Arbitrary
981)]
982pub enum DatabaseId {
983    User(u64),
984    System(u64),
985}
986
987impl DatabaseId {
988    pub fn is_user(&self) -> bool {
989        matches!(self, DatabaseId::User(_))
990    }
991
992    pub fn is_system(&self) -> bool {
993        matches!(self, DatabaseId::System(_))
994    }
995}
996
997impl fmt::Display for DatabaseId {
998    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
999        match self {
1000            DatabaseId::System(id) => write!(f, "s{}", id),
1001            DatabaseId::User(id) => write!(f, "u{}", id),
1002        }
1003    }
1004}
1005
1006impl FromStr for DatabaseId {
1007    type Err = PlanError;
1008
1009    fn from_str(s: &str) -> Result<Self, Self::Err> {
1010        if s.len() < 2 {
1011            return Err(PlanError::Unstructured(format!(
1012                "couldn't parse DatabaseId {}",
1013                s
1014            )));
1015        }
1016        let val: u64 = s[1..].parse()?;
1017        match s.chars().next() {
1018            Some('s') => Ok(DatabaseId::System(val)),
1019            Some('u') => Ok(DatabaseId::User(val)),
1020            _ => Err(PlanError::Unstructured(format!(
1021                "couldn't parse DatabaseId {}",
1022                s
1023            ))),
1024        }
1025    }
1026}
1027
1028pub static PUBLIC_ROLE_NAME: LazyLock<&UncasedStr> = LazyLock::new(|| UncasedStr::new("PUBLIC"));
1029
1030#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
1031pub enum ObjectId {
1032    Cluster(ClusterId),
1033    ClusterReplica((ClusterId, ReplicaId)),
1034    Database(DatabaseId),
1035    Schema((ResolvedDatabaseSpecifier, SchemaSpecifier)),
1036    Role(RoleId),
1037    Item(CatalogItemId),
1038    NetworkPolicy(NetworkPolicyId),
1039}
1040
1041impl ObjectId {
1042    pub fn unwrap_cluster_id(self) -> ClusterId {
1043        match self {
1044            ObjectId::Cluster(id) => id,
1045            _ => panic!("ObjectId::unwrap_cluster_id called on {self:?}"),
1046        }
1047    }
1048    pub fn unwrap_cluster_replica_id(self) -> (ClusterId, ReplicaId) {
1049        match self {
1050            ObjectId::ClusterReplica(id) => id,
1051            _ => panic!("ObjectId::unwrap_cluster_replica_id called on {self:?}"),
1052        }
1053    }
1054    pub fn unwrap_database_id(self) -> DatabaseId {
1055        match self {
1056            ObjectId::Database(id) => id,
1057            _ => panic!("ObjectId::unwrap_database_id called on {self:?}"),
1058        }
1059    }
1060    pub fn unwrap_schema_id(self) -> (ResolvedDatabaseSpecifier, SchemaSpecifier) {
1061        match self {
1062            ObjectId::Schema(id) => id,
1063            _ => panic!("ObjectId::unwrap_schema_id called on {self:?}"),
1064        }
1065    }
1066    pub fn unwrap_role_id(self) -> RoleId {
1067        match self {
1068            ObjectId::Role(id) => id,
1069            _ => panic!("ObjectId::unwrap_role_id called on {self:?}"),
1070        }
1071    }
1072    pub fn unwrap_item_id(self) -> CatalogItemId {
1073        match self {
1074            ObjectId::Item(id) => id,
1075            _ => panic!("ObjectId::unwrap_item_id called on {self:?}"),
1076        }
1077    }
1078
1079    pub fn is_system(&self) -> bool {
1080        match self {
1081            ObjectId::Cluster(cluster_id) => cluster_id.is_system(),
1082            ObjectId::ClusterReplica((_cluster_id, replica_id)) => replica_id.is_system(),
1083            ObjectId::Database(database_id) => database_id.is_system(),
1084            ObjectId::Schema((_database_id, schema_id)) => schema_id.is_system(),
1085            ObjectId::Role(role_id) => role_id.is_system(),
1086            ObjectId::Item(global_id) => global_id.is_system(),
1087            ObjectId::NetworkPolicy(network_policy_id) => network_policy_id.is_system(),
1088        }
1089    }
1090
1091    pub fn is_user(&self) -> bool {
1092        match self {
1093            ObjectId::Cluster(cluster_id) => cluster_id.is_user(),
1094            ObjectId::ClusterReplica((_cluster_id, replica_id)) => replica_id.is_user(),
1095            ObjectId::Database(database_id) => database_id.is_user(),
1096            ObjectId::Schema((_database_id, schema_id)) => schema_id.is_user(),
1097            ObjectId::Role(role_id) => role_id.is_user(),
1098            ObjectId::Item(global_id) => global_id.is_user(),
1099            ObjectId::NetworkPolicy(network_policy_id) => network_policy_id.is_user(),
1100        }
1101    }
1102}
1103
1104impl fmt::Display for ObjectId {
1105    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1106        match self {
1107            ObjectId::Cluster(cluster_id) => write!(f, "C{cluster_id}"),
1108            ObjectId::ClusterReplica((cluster_id, replica_id)) => {
1109                write!(f, "CR{cluster_id}.{replica_id}")
1110            }
1111            ObjectId::Database(database_id) => write!(f, "D{database_id}"),
1112            ObjectId::Schema((database_spec, schema_spec)) => {
1113                let database_id = match database_spec {
1114                    ResolvedDatabaseSpecifier::Ambient => "".to_string(),
1115                    ResolvedDatabaseSpecifier::Id(database_id) => format!("{database_id}."),
1116                };
1117                write!(f, "S{database_id}{schema_spec}")
1118            }
1119            ObjectId::Role(role_id) => write!(f, "R{role_id}"),
1120            ObjectId::Item(item_id) => write!(f, "I{item_id}"),
1121            ObjectId::NetworkPolicy(network_policy_id) => write!(f, "NP{network_policy_id}"),
1122        }
1123    }
1124}
1125
1126impl TryFrom<ResolvedObjectName> for ObjectId {
1127    type Error = anyhow::Error;
1128
1129    fn try_from(name: ResolvedObjectName) -> Result<ObjectId, Self::Error> {
1130        match name {
1131            ResolvedObjectName::Cluster(name) => Ok(ObjectId::Cluster(name.id)),
1132            ResolvedObjectName::ClusterReplica(name) => {
1133                Ok(ObjectId::ClusterReplica((name.cluster_id, name.replica_id)))
1134            }
1135            ResolvedObjectName::Database(name) => Ok(ObjectId::Database(*name.database_id())),
1136            ResolvedObjectName::Schema(name) => match name {
1137                ResolvedSchemaName::Schema {
1138                    database_spec,
1139                    schema_spec,
1140                    ..
1141                } => Ok(ObjectId::Schema((database_spec, schema_spec))),
1142                ResolvedSchemaName::Error => Err(anyhow!("error in name resolution")),
1143            },
1144            ResolvedObjectName::Role(name) => Ok(ObjectId::Role(name.id)),
1145            ResolvedObjectName::Item(name) => match name {
1146                ResolvedItemName::Item { id, .. } => Ok(ObjectId::Item(id)),
1147                ResolvedItemName::Cte { .. } => Err(anyhow!("CTE does not correspond to object")),
1148                ResolvedItemName::Error => Err(anyhow!("error in name resolution")),
1149            },
1150            ResolvedObjectName::NetworkPolicy(name) => Ok(ObjectId::NetworkPolicy(name.id)),
1151        }
1152    }
1153}
1154
1155impl From<ClusterId> for ObjectId {
1156    fn from(id: ClusterId) -> Self {
1157        ObjectId::Cluster(id)
1158    }
1159}
1160
1161impl From<&ClusterId> for ObjectId {
1162    fn from(id: &ClusterId) -> Self {
1163        ObjectId::Cluster(*id)
1164    }
1165}
1166
1167impl From<(ClusterId, ReplicaId)> for ObjectId {
1168    fn from(id: (ClusterId, ReplicaId)) -> Self {
1169        ObjectId::ClusterReplica(id)
1170    }
1171}
1172
1173impl From<&(ClusterId, ReplicaId)> for ObjectId {
1174    fn from(id: &(ClusterId, ReplicaId)) -> Self {
1175        ObjectId::ClusterReplica(*id)
1176    }
1177}
1178
1179impl From<DatabaseId> for ObjectId {
1180    fn from(id: DatabaseId) -> Self {
1181        ObjectId::Database(id)
1182    }
1183}
1184
1185impl From<&DatabaseId> for ObjectId {
1186    fn from(id: &DatabaseId) -> Self {
1187        ObjectId::Database(*id)
1188    }
1189}
1190
1191impl From<ItemQualifiers> for ObjectId {
1192    fn from(qualifiers: ItemQualifiers) -> Self {
1193        ObjectId::Schema((qualifiers.database_spec, qualifiers.schema_spec))
1194    }
1195}
1196
1197impl From<&ItemQualifiers> for ObjectId {
1198    fn from(qualifiers: &ItemQualifiers) -> Self {
1199        ObjectId::Schema((qualifiers.database_spec, qualifiers.schema_spec))
1200    }
1201}
1202
1203impl From<(ResolvedDatabaseSpecifier, SchemaSpecifier)> for ObjectId {
1204    fn from(id: (ResolvedDatabaseSpecifier, SchemaSpecifier)) -> Self {
1205        ObjectId::Schema(id)
1206    }
1207}
1208
1209impl From<&(ResolvedDatabaseSpecifier, SchemaSpecifier)> for ObjectId {
1210    fn from(id: &(ResolvedDatabaseSpecifier, SchemaSpecifier)) -> Self {
1211        ObjectId::Schema(*id)
1212    }
1213}
1214
1215impl From<RoleId> for ObjectId {
1216    fn from(id: RoleId) -> Self {
1217        ObjectId::Role(id)
1218    }
1219}
1220
1221impl From<&RoleId> for ObjectId {
1222    fn from(id: &RoleId) -> Self {
1223        ObjectId::Role(*id)
1224    }
1225}
1226
1227impl From<CatalogItemId> for ObjectId {
1228    fn from(id: CatalogItemId) -> Self {
1229        ObjectId::Item(id)
1230    }
1231}
1232
1233impl From<&CatalogItemId> for ObjectId {
1234    fn from(id: &CatalogItemId) -> Self {
1235        ObjectId::Item(*id)
1236    }
1237}
1238
1239impl From<CommentObjectId> for ObjectId {
1240    fn from(id: CommentObjectId) -> Self {
1241        match id {
1242            CommentObjectId::Table(item_id)
1243            | CommentObjectId::View(item_id)
1244            | CommentObjectId::MaterializedView(item_id)
1245            | CommentObjectId::Source(item_id)
1246            | CommentObjectId::Sink(item_id)
1247            | CommentObjectId::Index(item_id)
1248            | CommentObjectId::Func(item_id)
1249            | CommentObjectId::Connection(item_id)
1250            | CommentObjectId::Type(item_id)
1251            | CommentObjectId::Secret(item_id) => ObjectId::Item(item_id),
1252            CommentObjectId::Role(id) => ObjectId::Role(id),
1253            CommentObjectId::Database(id) => ObjectId::Database(id),
1254            CommentObjectId::Schema(id) => ObjectId::Schema(id),
1255            CommentObjectId::Cluster(id) => ObjectId::Cluster(id),
1256            CommentObjectId::ClusterReplica(id) => ObjectId::ClusterReplica(id),
1257            CommentObjectId::NetworkPolicy(id) => ObjectId::NetworkPolicy(id),
1258        }
1259    }
1260}
1261
1262#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
1263pub enum SystemObjectId {
1264    /// The ID of a specific object.
1265    Object(ObjectId),
1266    /// Identifier for the entire system.
1267    System,
1268}
1269
1270impl SystemObjectId {
1271    pub fn object_id(&self) -> Option<&ObjectId> {
1272        match self {
1273            SystemObjectId::Object(object_id) => Some(object_id),
1274            SystemObjectId::System => None,
1275        }
1276    }
1277
1278    pub fn is_system(&self) -> bool {
1279        matches!(self, SystemObjectId::System)
1280    }
1281}
1282
1283impl From<ObjectId> for SystemObjectId {
1284    fn from(id: ObjectId) -> Self {
1285        SystemObjectId::Object(id)
1286    }
1287}
1288
1289/// Comments can be applied to multiple kinds of objects (e.g. Tables and Role), so we need a way
1290/// to represent these different types and their IDs (e.g. [`CatalogItemId`] and [`RoleId`]), as
1291/// well as the inner kind of object that is represented, e.g. [`CatalogItemId`] is used to
1292/// identify both Tables and Views. No other kind of ID encapsulates all of this, hence this new
1293/// "*Id" type.
1294#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize)]
1295pub enum CommentObjectId {
1296    Table(CatalogItemId),
1297    View(CatalogItemId),
1298    MaterializedView(CatalogItemId),
1299    Source(CatalogItemId),
1300    Sink(CatalogItemId),
1301    Index(CatalogItemId),
1302    Func(CatalogItemId),
1303    Connection(CatalogItemId),
1304    Type(CatalogItemId),
1305    Secret(CatalogItemId),
1306    Role(RoleId),
1307    Database(DatabaseId),
1308    Schema((ResolvedDatabaseSpecifier, SchemaSpecifier)),
1309    Cluster(ClusterId),
1310    ClusterReplica((ClusterId, ReplicaId)),
1311    NetworkPolicy(NetworkPolicyId),
1312}
1313
1314/// Whether to resolve an name in the types namespace, the functions namespace,
1315/// or the relations namespace. It is possible to resolve name in multiple
1316/// namespaces, in which case types are preferred to functions are preferred to
1317/// relations.
1318// NOTE(benesch,sploiselle): The fact that some names are looked up in multiple
1319// namespaces is a bit dubious, and stems from the fact that we don't
1320// automatically create types for relations (see database-issues#7142). It's possible that we
1321// don't allow names to be looked up in multiple namespaces (i.e., this becomes
1322// `enum ItemResolutionNamespace`), but it's also possible that the design of
1323// the `DOC ON TYPE` option means we're forever stuck with this complexity.
1324#[derive(Debug, Clone, Copy)]
1325struct ItemResolutionConfig {
1326    types: bool,
1327    functions: bool,
1328    relations: bool,
1329}
1330
1331#[derive(Debug)]
1332pub struct NameResolver<'a> {
1333    catalog: &'a dyn SessionCatalog,
1334    ctes: BTreeMap<String, LocalId>,
1335    status: Result<(), PlanError>,
1336    ids: BTreeMap<CatalogItemId, BTreeSet<GlobalId>>,
1337}
1338
1339impl<'a> NameResolver<'a> {
1340    fn new(catalog: &'a dyn SessionCatalog) -> NameResolver<'a> {
1341        NameResolver {
1342            catalog,
1343            ctes: BTreeMap::new(),
1344            status: Ok(()),
1345            ids: BTreeMap::new(),
1346        }
1347    }
1348
1349    fn resolve_data_type(&mut self, data_type: RawDataType) -> Result<ResolvedDataType, PlanError> {
1350        match data_type {
1351            RawDataType::Array(elem_type) => {
1352                let name = elem_type.to_string();
1353                match self.resolve_data_type(*elem_type)? {
1354                    ResolvedDataType::AnonymousList(_) | ResolvedDataType::AnonymousMap { .. } => {
1355                        sql_bail!("type \"{}[]\" does not exist", name)
1356                    }
1357                    ResolvedDataType::Named { id, modifiers, .. } => {
1358                        let element_item = self.catalog.get_item(&id);
1359                        let array_item = match element_item.type_details() {
1360                            Some(CatalogTypeDetails {
1361                                array_id: Some(array_id),
1362                                ..
1363                            }) => self.catalog.get_item(array_id),
1364                            Some(_) => sql_bail!("type \"{}[]\" does not exist", name),
1365                            None => {
1366                                // Resolution should never produce a
1367                                // `ResolvedDataType::Named` with an ID of a
1368                                // non-type, but we error gracefully just in
1369                                // case.
1370                                sql_bail!(
1371                                    "internal error: {} does not refer to a type",
1372                                    self.catalog
1373                                        .resolve_full_name(element_item.name())
1374                                        .to_string()
1375                                        .quoted()
1376                                );
1377                            }
1378                        };
1379                        self.ids.insert(array_item.id(), BTreeSet::new());
1380                        Ok(ResolvedDataType::Named {
1381                            id: array_item.id(),
1382                            qualifiers: array_item.name().qualifiers.clone(),
1383                            full_name: self.catalog.resolve_full_name(array_item.name()),
1384                            modifiers,
1385                            print_id: true,
1386                        })
1387                    }
1388                    ResolvedDataType::Error => sql_bail!("type \"{}[]\" does not exist", name),
1389                }
1390            }
1391            RawDataType::List(elem_type) => {
1392                let elem_type = self.resolve_data_type(*elem_type)?;
1393                Ok(ResolvedDataType::AnonymousList(Box::new(elem_type)))
1394            }
1395            RawDataType::Map {
1396                key_type,
1397                value_type,
1398            } => {
1399                let key_type = self.resolve_data_type(*key_type)?;
1400                let value_type = self.resolve_data_type(*value_type)?;
1401                Ok(ResolvedDataType::AnonymousMap {
1402                    key_type: Box::new(key_type),
1403                    value_type: Box::new(value_type),
1404                })
1405            }
1406            RawDataType::Other { name, typ_mod } => {
1407                let (full_name, item) = match name {
1408                    RawItemName::Name(name) => {
1409                        let name = normalize::unresolved_item_name(name)?;
1410                        let item = self.catalog.resolve_type(&name)?;
1411                        let full_name = self.catalog.resolve_full_name(item.name());
1412                        (full_name, item)
1413                    }
1414                    RawItemName::Id(id, name, version) => {
1415                        let id: CatalogItemId = id.parse()?;
1416                        let item = self.catalog.get_item(&id);
1417                        let full_name = normalize::full_name(name)?;
1418                        assert_none!(version, "no support for versioning data types");
1419
1420                        (full_name, item)
1421                    }
1422                };
1423                self.ids.insert(item.id(), BTreeSet::new());
1424                // If this is a named array type, then make sure to include the element reference
1425                // in the resolved IDs. This helps ensure that named array types are resolved the
1426                // same as an array type with the same element type. For example, `int4[]` and
1427                // `_int4` should have the same set of resolved IDs.
1428                if let Some(CatalogTypeDetails {
1429                    typ: CatalogType::Array { element_reference },
1430                    ..
1431                }) = item.type_details()
1432                {
1433                    self.ids.insert(*element_reference, BTreeSet::new());
1434                }
1435                Ok(ResolvedDataType::Named {
1436                    id: item.id(),
1437                    qualifiers: item.name().qualifiers.clone(),
1438                    full_name,
1439                    modifiers: typ_mod,
1440                    print_id: true,
1441                })
1442            }
1443        }
1444    }
1445
1446    fn resolve_item_name(
1447        &mut self,
1448        item_name: RawItemName,
1449        config: ItemResolutionConfig,
1450    ) -> ResolvedItemName {
1451        match item_name {
1452            RawItemName::Name(name) => self.resolve_item_name_name(name, config),
1453            RawItemName::Id(id, raw_name, version) => {
1454                self.resolve_item_name_id(id, raw_name, version)
1455            }
1456        }
1457    }
1458
1459    fn resolve_item_name_name(
1460        &mut self,
1461        raw_name: UnresolvedItemName,
1462        config: ItemResolutionConfig,
1463    ) -> ResolvedItemName {
1464        let raw_name = match normalize::unresolved_item_name(raw_name) {
1465            Ok(raw_name) => raw_name,
1466            Err(e) => {
1467                if self.status.is_ok() {
1468                    self.status = Err(e);
1469                }
1470                return ResolvedItemName::Error;
1471            }
1472        };
1473
1474        let mut r: Result<&dyn CatalogItem, CatalogError> =
1475            Err(CatalogError::UnknownItem(raw_name.to_string()));
1476
1477        if r.is_err() && config.types {
1478            r = self.catalog.resolve_type(&raw_name);
1479        }
1480
1481        if r.is_err() && config.functions {
1482            r = self.catalog.resolve_function(&raw_name);
1483        }
1484
1485        if r.is_err() && config.relations {
1486            // Check if unqualified name refers to a CTE.
1487            //
1488            // Note that this is done in non-function contexts as CTEs
1489            // are treated as relations.
1490            if raw_name.database.is_none() && raw_name.schema.is_none() {
1491                let norm_name = normalize::ident(Ident::new_unchecked(&raw_name.item));
1492                if let Some(id) = self.ctes.get(&norm_name) {
1493                    return ResolvedItemName::Cte {
1494                        id: *id,
1495                        name: norm_name,
1496                    };
1497                }
1498            }
1499            r = self.catalog.resolve_item(&raw_name);
1500        };
1501
1502        match r {
1503            Ok(item) => {
1504                // Record the item at its current version.
1505                let item = item.at_version(RelationVersionSelector::Latest);
1506                self.ids
1507                    .entry(item.id())
1508                    .or_default()
1509                    .insert(item.global_id());
1510                let print_id = !matches!(
1511                    item.item_type(),
1512                    CatalogItemType::Func | CatalogItemType::Type
1513                );
1514                let alter_table_enabled =
1515                    self.catalog.system_vars().enable_alter_table_add_column();
1516                let version = match item.latest_version() {
1517                    // Only track the version of referenced object if the feature is enabled.
1518                    Some(v) if item.id().is_user() && alter_table_enabled => {
1519                        RelationVersionSelector::Specific(v)
1520                    }
1521                    _ => RelationVersionSelector::Latest,
1522                };
1523
1524                ResolvedItemName::Item {
1525                    id: item.id(),
1526                    qualifiers: item.name().qualifiers.clone(),
1527                    full_name: self.catalog.resolve_full_name(item.name()),
1528                    print_id,
1529                    version,
1530                }
1531            }
1532            Err(mut e) => {
1533                if self.status.is_ok() {
1534                    match &mut e {
1535                        CatalogError::UnknownFunction {
1536                            name: _,
1537                            alternative,
1538                        } => {
1539                            // Suggest using the `jsonb_` version of `json_`
1540                            // functions that do not exist.
1541                            if raw_name.database.is_none()
1542                                && (raw_name.schema.is_none()
1543                                    || raw_name.schema.as_deref() == Some("pg_catalog")
1544                                        && raw_name.item.starts_with("json_"))
1545                            {
1546                                let jsonb_name = PartialItemName {
1547                                    item: raw_name.item.replace("json_", "jsonb_"),
1548                                    ..raw_name
1549                                };
1550                                if self.catalog.resolve_function(&jsonb_name).is_ok() {
1551                                    *alternative = Some(jsonb_name.to_string());
1552                                }
1553                            }
1554                        }
1555                        _ => (),
1556                    }
1557
1558                    self.status = Err(e.into());
1559                }
1560                ResolvedItemName::Error
1561            }
1562        }
1563    }
1564
1565    fn resolve_item_name_id(
1566        &mut self,
1567        id: String,
1568        raw_name: UnresolvedItemName,
1569        version: Option<Version>,
1570    ) -> ResolvedItemName {
1571        let id: CatalogItemId = match id.parse() {
1572            Ok(id) => id,
1573            Err(e) => {
1574                if self.status.is_ok() {
1575                    self.status = Err(e.into());
1576                }
1577                return ResolvedItemName::Error;
1578            }
1579        };
1580        let item = match self.catalog.try_get_item(&id) {
1581            Some(item) => item,
1582            None => {
1583                if self.status.is_ok() {
1584                    self.status = Err(PlanError::InvalidId(id));
1585                }
1586                return ResolvedItemName::Error;
1587            }
1588        };
1589        let alter_table_enabled = self.catalog.system_vars().enable_alter_table_add_column();
1590        let version = match version {
1591            // If there isn't a version specified, and this item supports versioning, track the
1592            // latest.
1593            None => match item.latest_version() {
1594                // Only track the version of the referenced object, if the feature is enabled.
1595                Some(v) if alter_table_enabled => RelationVersionSelector::Specific(v),
1596                _ => RelationVersionSelector::Latest,
1597            },
1598            // Note: Return the specific version if one is specified, even if the feature is off.
1599            Some(v) => {
1600                let specified_version = RelationVersion::from(v);
1601                match item.latest_version() {
1602                    Some(latest) if latest >= specified_version => {
1603                        RelationVersionSelector::Specific(specified_version)
1604                    }
1605                    _ => {
1606                        if self.status.is_ok() {
1607                            self.status = Err(PlanError::InvalidVersion {
1608                                name: item.name().item.clone(),
1609                                version: v.to_string(),
1610                            })
1611                        }
1612                        return ResolvedItemName::Error;
1613                    }
1614                }
1615            }
1616        };
1617        let item = item.at_version(version);
1618        self.ids
1619            .entry(item.id())
1620            .or_default()
1621            .insert(item.global_id());
1622
1623        let full_name = match normalize::full_name(raw_name) {
1624            Ok(full_name) => full_name,
1625            Err(e) => {
1626                if self.status.is_ok() {
1627                    self.status = Err(e);
1628                }
1629                return ResolvedItemName::Error;
1630            }
1631        };
1632        ResolvedItemName::Item {
1633            id,
1634            qualifiers: item.name().qualifiers.clone(),
1635            full_name,
1636            print_id: true,
1637            version,
1638        }
1639    }
1640}
1641
1642impl<'a> Fold<Raw, Aug> for NameResolver<'a> {
1643    fn fold_nested_statement(
1644        &mut self,
1645        stmt: <Raw as AstInfo>::NestedStatement,
1646    ) -> <Aug as AstInfo>::NestedStatement {
1647        stmt
1648    }
1649
1650    fn fold_query(&mut self, q: Query<Raw>) -> Query<Aug> {
1651        // Retain the old values of various CTE names so that we can restore them after we're done
1652        // planning this SELECT.
1653        let mut shadowed_cte_ids = Vec::new();
1654
1655        // A reused identifier indicates a reused name.
1656        use itertools::Itertools;
1657        if let Some(ident) = q.ctes.bound_identifiers().duplicates().next() {
1658            self.status = Err(sql_err!(
1659                "WITH query name \"{}\" specified more than once",
1660                normalize::ident_ref(ident),
1661            ));
1662        }
1663
1664        let ctes: CteBlock<Aug> = match q.ctes {
1665            CteBlock::Simple(ctes) => {
1666                let mut result_ctes = Vec::<Cte<Aug>>::new();
1667
1668                let initial_id = self.ctes.len();
1669
1670                for (offset, cte) in ctes.into_iter().enumerate() {
1671                    let cte_name = normalize::ident(cte.alias.name.clone());
1672                    let local_id = LocalId::new(u64::cast_from(initial_id + offset));
1673
1674                    result_ctes.push(Cte {
1675                        alias: cte.alias,
1676                        id: local_id,
1677                        query: self.fold_query(cte.query),
1678                    });
1679
1680                    let shadowed_id = self.ctes.insert(cte_name.clone(), local_id);
1681                    shadowed_cte_ids.push((cte_name, shadowed_id));
1682                }
1683                CteBlock::Simple(result_ctes)
1684            }
1685            CteBlock::MutuallyRecursive(MutRecBlock { options, ctes }) => {
1686                let mut result_ctes = Vec::<CteMutRec<Aug>>::new();
1687
1688                let initial_id = self.ctes.len();
1689
1690                // The identifiers for each CTE will be `initial_id` plus their offset in `q.ctes`.
1691                for (offset, cte) in ctes.iter().enumerate() {
1692                    let cte_name = normalize::ident(cte.name.clone());
1693                    let local_id = LocalId::new(u64::cast_from(initial_id + offset));
1694                    let shadowed_id = self.ctes.insert(cte_name.clone(), local_id);
1695                    shadowed_cte_ids.push((cte_name, shadowed_id));
1696                }
1697
1698                for (offset, cte) in ctes.into_iter().enumerate() {
1699                    let local_id = LocalId::new(u64::cast_from(initial_id + offset));
1700
1701                    let columns = cte
1702                        .columns
1703                        .into_iter()
1704                        .map(|column| self.fold_cte_mut_rec_column_def(column))
1705                        .collect();
1706                    let query = self.fold_query(cte.query);
1707                    result_ctes.push(CteMutRec {
1708                        name: cte.name,
1709                        columns,
1710                        id: local_id,
1711                        query,
1712                    });
1713                }
1714                CteBlock::MutuallyRecursive(MutRecBlock {
1715                    options: options
1716                        .into_iter()
1717                        .map(|option| self.fold_mut_rec_block_option(option))
1718                        .collect(),
1719                    ctes: result_ctes,
1720                })
1721            }
1722        };
1723
1724        let result = Query {
1725            ctes,
1726            // Queries can be recursive, so need the ability to grow the stack.
1727            body: mz_ore::stack::maybe_grow(|| self.fold_set_expr(q.body)),
1728            limit: q.limit.map(|l| self.fold_limit(l)),
1729            offset: q.offset.map(|l| self.fold_expr(l)),
1730            order_by: q
1731                .order_by
1732                .into_iter()
1733                .map(|c| self.fold_order_by_expr(c))
1734                .collect(),
1735        };
1736
1737        // Restore the old values of the CTEs.
1738        for (name, value) in shadowed_cte_ids.iter() {
1739            match value {
1740                Some(value) => {
1741                    self.ctes.insert(name.to_string(), value.clone());
1742                }
1743                None => {
1744                    self.ctes.remove(name);
1745                }
1746            };
1747        }
1748
1749        result
1750    }
1751
1752    fn fold_cte_id(&mut self, _id: <Raw as AstInfo>::CteId) -> <Aug as AstInfo>::CteId {
1753        panic!("this should have been handled when walking the CTE");
1754    }
1755
1756    fn fold_item_name(
1757        &mut self,
1758        item_name: <Raw as AstInfo>::ItemName,
1759    ) -> <Aug as AstInfo>::ItemName {
1760        self.resolve_item_name(
1761            item_name,
1762            // By default, when resolving an item name, we assume only relations
1763            // should be in scope.
1764            ItemResolutionConfig {
1765                functions: false,
1766                types: false,
1767                relations: true,
1768            },
1769        )
1770    }
1771
1772    fn fold_column_name(&mut self, column_name: ast::ColumnName<Raw>) -> ast::ColumnName<Aug> {
1773        let item_name = self.resolve_item_name(
1774            column_name.relation,
1775            ItemResolutionConfig {
1776                functions: false,
1777                types: true,
1778                relations: true,
1779            },
1780        );
1781
1782        match &item_name {
1783            ResolvedItemName::Item {
1784                id,
1785                full_name,
1786                version,
1787                qualifiers: _,
1788                print_id: _,
1789            } => {
1790                let item = self.catalog.get_item(id).at_version(*version);
1791                let name = normalize::column_name(column_name.column.clone());
1792
1793                let maybe_desc = match item.type_details() {
1794                    Some(details) => match details.typ.desc(self.catalog) {
1795                        Ok(desc) => desc.map(Cow::Owned),
1796                        Err(e) => {
1797                            if self.status.is_ok() {
1798                                self.status = Err(e);
1799                            }
1800                            return ast::ColumnName {
1801                                relation: ResolvedItemName::Error,
1802                                column: ResolvedColumnReference::Error,
1803                            };
1804                        }
1805                    },
1806                    None => item.relation_desc(),
1807                };
1808                let Some(desc) = maybe_desc else {
1809                    if self.status.is_ok() {
1810                        self.status = Err(PlanError::ItemWithoutColumns {
1811                            name: full_name.to_string(),
1812                            item_type: item.item_type(),
1813                        });
1814                    }
1815                    return ast::ColumnName {
1816                        relation: ResolvedItemName::Error,
1817                        column: ResolvedColumnReference::Error,
1818                    };
1819                };
1820
1821                let Some((index, _typ)) = desc.get_by_name(&name) else {
1822                    if self.status.is_ok() {
1823                        let similar = desc.iter_similar_names(&name).cloned().collect();
1824                        self.status = Err(PlanError::UnknownColumn {
1825                            table: Some(full_name.clone().into()),
1826                            column: name,
1827                            similar,
1828                        })
1829                    }
1830                    return ast::ColumnName {
1831                        relation: ResolvedItemName::Error,
1832                        column: ResolvedColumnReference::Error,
1833                    };
1834                };
1835
1836                ast::ColumnName {
1837                    relation: item_name,
1838                    column: ResolvedColumnReference::Column { name, index },
1839                }
1840            }
1841            ResolvedItemName::Cte { .. } | ResolvedItemName::Error => ast::ColumnName {
1842                relation: ResolvedItemName::Error,
1843                column: ResolvedColumnReference::Error,
1844            },
1845        }
1846    }
1847
1848    fn fold_column_reference(
1849        &mut self,
1850        _node: <Raw as AstInfo>::ColumnReference,
1851    ) -> <Aug as AstInfo>::ColumnReference {
1852        // Do not call this function directly; instead resolve through `fold_column_name`
1853        ResolvedColumnReference::Error
1854    }
1855
1856    fn fold_data_type(
1857        &mut self,
1858        data_type: <Raw as AstInfo>::DataType,
1859    ) -> <Aug as AstInfo>::DataType {
1860        match self.resolve_data_type(data_type) {
1861            Ok(data_type) => data_type,
1862            Err(e) => {
1863                if self.status.is_ok() {
1864                    self.status = Err(e);
1865                }
1866                ResolvedDataType::Error
1867            }
1868        }
1869    }
1870
1871    fn fold_schema_name(
1872        &mut self,
1873        name: <Raw as AstInfo>::SchemaName,
1874    ) -> <Aug as AstInfo>::SchemaName {
1875        let norm_name = match normalize::unresolved_schema_name(name) {
1876            Ok(norm_name) => norm_name,
1877            Err(e) => {
1878                if self.status.is_ok() {
1879                    self.status = Err(e);
1880                }
1881                return ResolvedSchemaName::Error;
1882            }
1883        };
1884
1885        // Special case for mz_temp: with lazy temporary schema creation, the temp
1886        // schema may not exist yet. Return a resolved name with SchemaSpecifier::Temporary
1887        // so that downstream code can handle it appropriately (e.g., return a proper error).
1888        if norm_name.database.is_none() && norm_name.schema == mz_repr::namespaces::MZ_TEMP_SCHEMA {
1889            return ResolvedSchemaName::Schema {
1890                database_spec: ResolvedDatabaseSpecifier::Ambient,
1891                schema_spec: SchemaSpecifier::Temporary,
1892                full_name: FullSchemaName {
1893                    database: RawDatabaseSpecifier::Ambient,
1894                    schema: mz_repr::namespaces::MZ_TEMP_SCHEMA.to_string(),
1895                },
1896            };
1897        }
1898
1899        match self
1900            .catalog
1901            .resolve_schema(norm_name.database.as_deref(), norm_name.schema.as_str())
1902        {
1903            Ok(schema) => {
1904                let raw_database_spec = match schema.database() {
1905                    ResolvedDatabaseSpecifier::Ambient => RawDatabaseSpecifier::Ambient,
1906                    ResolvedDatabaseSpecifier::Id(id) => {
1907                        RawDatabaseSpecifier::Name(self.catalog.get_database(id).name().to_string())
1908                    }
1909                };
1910                ResolvedSchemaName::Schema {
1911                    database_spec: schema.database().clone(),
1912                    schema_spec: schema.id().clone(),
1913                    full_name: FullSchemaName {
1914                        database: raw_database_spec,
1915                        schema: schema.name().schema.clone(),
1916                    },
1917                }
1918            }
1919            Err(e) => {
1920                if self.status.is_ok() {
1921                    self.status = Err(e.into());
1922                }
1923                ResolvedSchemaName::Error
1924            }
1925        }
1926    }
1927
1928    fn fold_database_name(
1929        &mut self,
1930        database_name: <Raw as AstInfo>::DatabaseName,
1931    ) -> <Aug as AstInfo>::DatabaseName {
1932        match self.catalog.resolve_database(database_name.0.as_str()) {
1933            Ok(database) => ResolvedDatabaseName::Database {
1934                id: database.id(),
1935                name: database_name.0.into_string(),
1936            },
1937            Err(e) => {
1938                if self.status.is_ok() {
1939                    self.status = Err(e.into());
1940                }
1941                ResolvedDatabaseName::Error
1942            }
1943        }
1944    }
1945
1946    fn fold_cluster_name(
1947        &mut self,
1948        cluster_name: <Raw as AstInfo>::ClusterName,
1949    ) -> <Aug as AstInfo>::ClusterName {
1950        match cluster_name {
1951            RawClusterName::Unresolved(ident) => {
1952                match self.catalog.resolve_cluster(Some(ident.as_str())) {
1953                    Ok(cluster) => ResolvedClusterName {
1954                        id: cluster.id(),
1955                        print_name: None,
1956                    },
1957                    Err(e) => {
1958                        self.status = Err(e.into());
1959                        ResolvedClusterName {
1960                            // The ID is arbitrary here; we just need some dummy
1961                            // value to return.
1962                            id: ClusterId::system(0).expect("0 is a valid ID"),
1963                            print_name: None,
1964                        }
1965                    }
1966                }
1967            }
1968            RawClusterName::Resolved(ident) => match ident.parse() {
1969                Ok(id) => ResolvedClusterName {
1970                    id,
1971                    print_name: None,
1972                },
1973                Err(e) => {
1974                    self.status = Err(e.into());
1975                    ResolvedClusterName {
1976                        // The ID is arbitrary here; we just need some dummy
1977                        // value to return.
1978                        id: ClusterId::system(0).expect("0 is a valid ID"),
1979                        print_name: None,
1980                    }
1981                }
1982            },
1983        }
1984    }
1985
1986    fn fold_with_option_value(
1987        &mut self,
1988        node: mz_sql_parser::ast::WithOptionValue<Raw>,
1989    ) -> mz_sql_parser::ast::WithOptionValue<Aug> {
1990        use mz_sql_parser::ast::WithOptionValue::*;
1991        match node {
1992            Sequence(vs) => Sequence(
1993                vs.into_iter()
1994                    .map(|v| self.fold_with_option_value(v))
1995                    .collect(),
1996            ),
1997            Map(map) => Map(map
1998                .into_iter()
1999                .map(|(k, v)| (k, self.fold_with_option_value(v)))
2000                .collect()),
2001            Value(v) => Value(self.fold_value(v)),
2002            DataType(dt) => DataType(self.fold_data_type(dt)),
2003            Secret(secret) => {
2004                let item_name = self.fold_item_name(secret);
2005                match &item_name {
2006                    ResolvedItemName::Item { id, .. } => {
2007                        let item = self.catalog.get_item(id);
2008                        if item.item_type() != CatalogItemType::Secret {
2009                            self.status =
2010                                Err(PlanError::InvalidSecret(Box::new(item_name.clone())));
2011                        }
2012                    }
2013                    ResolvedItemName::Cte { .. } => {
2014                        self.status = Err(PlanError::InvalidSecret(Box::new(item_name.clone())));
2015                    }
2016                    ResolvedItemName::Error => {}
2017                }
2018                Secret(item_name)
2019            }
2020            Item(obj) => {
2021                let item_name = self.fold_item_name(obj);
2022                match &item_name {
2023                    ResolvedItemName::Item { .. } => {}
2024                    ResolvedItemName::Cte { .. } => {
2025                        self.status = Err(PlanError::InvalidObject(Box::new(item_name.clone())));
2026                    }
2027                    ResolvedItemName::Error => {}
2028                }
2029                Item(item_name)
2030            }
2031            UnresolvedItemName(name) => UnresolvedItemName(self.fold_unresolved_item_name(name)),
2032            Ident(name) => Ident(self.fold_ident(name)),
2033            Expr(e) => Expr(self.fold_expr(e)),
2034            ClusterReplicas(replicas) => ClusterReplicas(
2035                replicas
2036                    .into_iter()
2037                    .map(|r| self.fold_replica_definition(r))
2038                    .collect(),
2039            ),
2040            ConnectionKafkaBroker(broker) => ConnectionKafkaBroker(self.fold_kafka_broker(broker)),
2041            ConnectionAwsPrivatelink(privatelink) => {
2042                ConnectionAwsPrivatelink(self.fold_connection_default_aws_privatelink(privatelink))
2043            }
2044            KafkaMatchingBrokerRule(x) => {
2045                KafkaMatchingBrokerRule(self.fold_kafka_matching_broker_rule(x))
2046            }
2047            RetainHistoryFor(value) => RetainHistoryFor(self.fold_value(value)),
2048            Refresh(refresh) => Refresh(self.fold_refresh_option_value(refresh)),
2049            ClusterScheduleOptionValue(value) => ClusterScheduleOptionValue(value),
2050            ClusterAlterStrategy(value) => {
2051                ClusterAlterStrategy(self.fold_cluster_alter_option_value(value))
2052            }
2053            NetworkPolicyRules(rules) => NetworkPolicyRules(
2054                rules
2055                    .into_iter()
2056                    .map(|r| self.fold_network_policy_rule_definition(r))
2057                    .collect(),
2058            ),
2059        }
2060    }
2061
2062    fn fold_role_name(&mut self, name: <Raw as AstInfo>::RoleName) -> <Aug as AstInfo>::RoleName {
2063        match self.catalog.resolve_role(name.as_str()) {
2064            Ok(role) => ResolvedRoleName {
2065                id: role.id(),
2066                name: role.name().to_string(),
2067            },
2068            Err(e) => {
2069                if self.status.is_ok() {
2070                    self.status = Err(e.into());
2071                }
2072                // garbage value that will be ignored since there's an error.
2073                ResolvedRoleName {
2074                    id: RoleId::User(0),
2075                    name: "".to_string(),
2076                }
2077            }
2078        }
2079    }
2080
2081    fn fold_network_policy_name(
2082        &mut self,
2083        name: <Raw as AstInfo>::NetworkPolicyName,
2084    ) -> <Aug as AstInfo>::NetworkPolicyName {
2085        match self.catalog.resolve_network_policy(&name.to_string()) {
2086            Ok(policy) => ResolvedNetworkPolicyName {
2087                id: policy.id(),
2088                name: policy.name().to_string(),
2089            },
2090            Err(e) => {
2091                if self.status.is_ok() {
2092                    self.status = Err(e.into());
2093                }
2094                // garbage value that will be ignored since there's an error.
2095                ResolvedNetworkPolicyName {
2096                    id: NetworkPolicyId::User(0),
2097                    name: "".to_string(),
2098                }
2099            }
2100        }
2101    }
2102
2103    fn fold_object_name(
2104        &mut self,
2105        name: <Raw as AstInfo>::ObjectName,
2106    ) -> <Aug as AstInfo>::ObjectName {
2107        match name {
2108            UnresolvedObjectName::Cluster(name) => ResolvedObjectName::Cluster(
2109                self.fold_cluster_name(RawClusterName::Unresolved(name)),
2110            ),
2111            UnresolvedObjectName::ClusterReplica(name) => {
2112                match self.catalog.resolve_cluster_replica(&name) {
2113                    Ok(cluster_replica) => {
2114                        ResolvedObjectName::ClusterReplica(ResolvedClusterReplicaName {
2115                            cluster_id: cluster_replica.cluster_id(),
2116                            replica_id: cluster_replica.replica_id(),
2117                        })
2118                    }
2119                    Err(e) => {
2120                        self.status = Err(e.into());
2121                        ResolvedObjectName::ClusterReplica(ResolvedClusterReplicaName {
2122                            // The ID is arbitrary here; we just need some dummy
2123                            // value to return.
2124                            cluster_id: ClusterId::system(0).expect("0 is a valid ID"),
2125                            replica_id: ReplicaId::System(0),
2126                        })
2127                    }
2128                }
2129            }
2130            UnresolvedObjectName::Database(name) => {
2131                ResolvedObjectName::Database(self.fold_database_name(name))
2132            }
2133            UnresolvedObjectName::Schema(name) => {
2134                ResolvedObjectName::Schema(self.fold_schema_name(name))
2135            }
2136            UnresolvedObjectName::Role(name) => ResolvedObjectName::Role(self.fold_role_name(name)),
2137            UnresolvedObjectName::Item(name) => {
2138                ResolvedObjectName::Item(self.fold_item_name(RawItemName::Name(name)))
2139            }
2140            UnresolvedObjectName::NetworkPolicy(name) => ResolvedObjectName::NetworkPolicy(
2141                self.fold_network_policy_name(RawNetworkPolicyName::Unresolved(name)),
2142            ),
2143        }
2144    }
2145
2146    fn fold_function(
2147        &mut self,
2148        node: mz_sql_parser::ast::Function<Raw>,
2149    ) -> mz_sql_parser::ast::Function<Aug> {
2150        // Functions implemented as SQL statements can have very deeply nested
2151        // and recursive structures, so need the ability to grow the stack.
2152        mz_ore::stack::maybe_grow(|| {
2153            mz_sql_parser::ast::Function {
2154                name: self.resolve_item_name(
2155                    node.name,
2156                    // When resolving a function name, only function items should be
2157                    // considered.
2158                    ItemResolutionConfig {
2159                        functions: true,
2160                        types: false,
2161                        relations: false,
2162                    },
2163                ),
2164                args: self.fold_function_args(node.args),
2165                filter: node.filter.map(|expr| Box::new(self.fold_expr(*expr))),
2166                over: node.over.map(|over| self.fold_window_spec(over)),
2167                distinct: node.distinct,
2168            }
2169        })
2170    }
2171
2172    fn fold_table_factor(
2173        &mut self,
2174        node: mz_sql_parser::ast::TableFactor<Raw>,
2175    ) -> mz_sql_parser::ast::TableFactor<Aug> {
2176        use mz_sql_parser::ast::TableFactor::*;
2177        match node {
2178            Table { name, alias } => Table {
2179                name: self.fold_item_name(name),
2180                alias: alias.map(|alias| self.fold_table_alias(alias)),
2181            },
2182            Function {
2183                function,
2184                alias,
2185                with_ordinality,
2186            } => {
2187                match &function.name {
2188                    RawItemName::Name(name) => {
2189                        if *name == UnresolvedItemName::unqualified(ident!("values"))
2190                            && self.status.is_ok()
2191                        {
2192                            self.status = Err(PlanError::FromValueRequiresParen);
2193                        }
2194                    }
2195                    RawItemName::Id(..) => {}
2196                }
2197
2198                Function {
2199                    function: self.fold_function(function),
2200                    alias: alias.map(|alias| self.fold_table_alias(alias)),
2201                    with_ordinality,
2202                }
2203            }
2204            RowsFrom {
2205                functions,
2206                alias,
2207                with_ordinality,
2208            } => RowsFrom {
2209                functions: functions
2210                    .into_iter()
2211                    .map(|f| self.fold_function(f))
2212                    .collect(),
2213                alias: alias.map(|alias| self.fold_table_alias(alias)),
2214                with_ordinality,
2215            },
2216            Derived {
2217                lateral,
2218                subquery,
2219                alias,
2220            } => Derived {
2221                lateral,
2222                subquery: Box::new(self.fold_query(*subquery)),
2223                alias: alias.map(|alias| self.fold_table_alias(alias)),
2224            },
2225            NestedJoin { join, alias } => NestedJoin {
2226                join: Box::new(self.fold_table_with_joins(*join)),
2227                alias: alias.map(|alias| self.fold_table_alias(alias)),
2228            },
2229        }
2230    }
2231
2232    fn fold_grant_target_specification(
2233        &mut self,
2234        node: GrantTargetSpecification<Raw>,
2235    ) -> GrantTargetSpecification<Aug> {
2236        match node {
2237            GrantTargetSpecification::Object {
2238                object_type: ObjectType::Type,
2239                object_spec_inner: GrantTargetSpecificationInner::Objects { names },
2240            } => GrantTargetSpecification::Object {
2241                object_type: ObjectType::Type,
2242                object_spec_inner: GrantTargetSpecificationInner::Objects {
2243                    names: names
2244                        .into_iter()
2245                        .map(|name| match name {
2246                            UnresolvedObjectName::Item(name) => {
2247                                ResolvedObjectName::Item(self.resolve_item_name_name(
2248                                    name,
2249                                    // `{GRANT|REVOKE} ... ON TYPE ...` can only
2250                                    // refer to type names.
2251                                    ItemResolutionConfig {
2252                                        functions: false,
2253                                        types: true,
2254                                        relations: false,
2255                                    },
2256                                ))
2257                            }
2258                            _ => self.fold_object_name(name),
2259                        })
2260                        .collect(),
2261                },
2262            },
2263            _ => mz_sql_parser::ast::fold::fold_grant_target_specification(self, node),
2264        }
2265    }
2266
2267    fn fold_doc_on_identifier(&mut self, node: DocOnIdentifier<Raw>) -> DocOnIdentifier<Aug> {
2268        match node {
2269            DocOnIdentifier::Column(name) => DocOnIdentifier::Column(self.fold_column_name(name)),
2270            DocOnIdentifier::Type(name) => DocOnIdentifier::Type(self.resolve_item_name(
2271                name,
2272                // In `DOC ON TYPE ...`, the type can refer to either a type or
2273                // a relation.
2274                //
2275                // It's possible this will get simpler once database-issues#7142 is fixed. See
2276                // the comment on `ItemResolutionConfig` for details.
2277                ItemResolutionConfig {
2278                    functions: false,
2279                    types: true,
2280                    relations: true,
2281                },
2282            )),
2283        }
2284    }
2285
2286    fn fold_expr(&mut self, node: Expr<Raw>) -> Expr<Aug> {
2287        // Exprs can be recursive, so need the ability to grow the stack.
2288        mz_ore::stack::maybe_grow(|| mz_sql_parser::ast::fold::fold_expr(self, node))
2289    }
2290}
2291
2292/// Resolves names in an AST node using the provided catalog.
2293#[mz_ore::instrument(target = "compiler", level = "trace", name = "ast_resolve_names")]
2294pub fn resolve<N>(
2295    catalog: &dyn SessionCatalog,
2296    node: N,
2297) -> Result<(N::Folded, ResolvedIds), PlanError>
2298where
2299    N: FoldNode<Raw, Aug>,
2300{
2301    let mut resolver = NameResolver::new(catalog);
2302    let result = node.fold(&mut resolver);
2303    resolver.status?;
2304    Ok((result, ResolvedIds::new(resolver.ids)))
2305}
2306
2307/// A set of items and their corresponding collections resolved by name resolution.
2308///
2309/// This is a newtype of a [`BTreeMap`] that is provided to make it harder to confuse a set of
2310/// resolved IDs with other collections of [`CatalogItemId`].
2311#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
2312pub struct ResolvedIds {
2313    #[serde(serialize_with = "mz_ore::serde::map_key_to_string")]
2314    entries: BTreeMap<CatalogItemId, BTreeSet<GlobalId>>,
2315}
2316
2317impl ResolvedIds {
2318    fn new(entries: BTreeMap<CatalogItemId, BTreeSet<GlobalId>>) -> Self {
2319        ResolvedIds { entries }
2320    }
2321
2322    /// Returns an emptry [`ResolvedIds`].
2323    pub fn empty() -> Self {
2324        ResolvedIds {
2325            entries: BTreeMap::new(),
2326        }
2327    }
2328
2329    /// Returns if the set of IDs is empty.
2330    pub fn is_empty(&self) -> bool {
2331        self.entries.is_empty()
2332    }
2333
2334    /// Returns all of the [`GlobalId`]s in this set.
2335    pub fn collections(&self) -> impl Iterator<Item = &GlobalId> {
2336        self.entries.values().flat_map(|gids| gids.into_iter())
2337    }
2338
2339    /// Returns all of the [`CatalogItemId`]s in this set.
2340    pub fn items(&self) -> impl Iterator<Item = &CatalogItemId> {
2341        self.entries.keys()
2342    }
2343
2344    /// Returns if this set of IDs contains the provided [`CatalogItemId`].
2345    pub fn contains_item(&self, item: &CatalogItemId) -> bool {
2346        self.entries.contains_key(item)
2347    }
2348
2349    pub fn add_item(&mut self, item: CatalogItemId) {
2350        self.entries.insert(item, BTreeSet::new());
2351    }
2352
2353    pub fn remove_item(&mut self, item: &CatalogItemId) {
2354        self.entries.remove(item);
2355    }
2356
2357    /// Create a new [`ResolvedIds`] that contains the elements from `self`
2358    /// where `predicate` returns `true`.
2359    pub fn retain_items<F>(&self, predicate: F) -> Self
2360    where
2361        F: Fn(&CatalogItemId) -> bool,
2362    {
2363        let mut new_ids = self.clone();
2364        new_ids
2365            .entries
2366            .retain(|item_id, _global_ids| predicate(item_id));
2367        new_ids
2368    }
2369}
2370
2371impl FromIterator<(CatalogItemId, GlobalId)> for ResolvedIds {
2372    fn from_iter<T: IntoIterator<Item = (CatalogItemId, GlobalId)>>(iter: T) -> Self {
2373        let mut ids = ResolvedIds::empty();
2374        ids.extend(iter);
2375        ids
2376    }
2377}
2378
2379impl Extend<(CatalogItemId, GlobalId)> for ResolvedIds {
2380    fn extend<T: IntoIterator<Item = (CatalogItemId, GlobalId)>>(&mut self, iter: T) {
2381        for (item_id, global_id) in iter {
2382            self.entries.entry(item_id).or_default().insert(global_id);
2383        }
2384    }
2385}
2386
2387/// A set of IDs references by the `HirRelationExpr` of an object.
2388#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
2389pub struct DependencyIds(pub BTreeSet<CatalogItemId>);
2390
2391impl FromIterator<CatalogItemId> for DependencyIds {
2392    fn from_iter<T: IntoIterator<Item = CatalogItemId>>(iter: T) -> Self {
2393        DependencyIds(iter.into_iter().collect())
2394    }
2395}
2396
2397#[derive(Debug)]
2398pub struct DependencyVisitor<'a> {
2399    catalog: &'a dyn SessionCatalog,
2400    ids: BTreeMap<CatalogItemId, BTreeSet<GlobalId>>,
2401}
2402
2403impl<'a> DependencyVisitor<'a> {
2404    pub fn new(catalog: &'a dyn SessionCatalog) -> Self {
2405        DependencyVisitor {
2406            catalog,
2407            ids: Default::default(),
2408        }
2409    }
2410}
2411
2412impl<'a, 'ast> Visit<'ast, Aug> for DependencyVisitor<'a> {
2413    fn visit_item_name(&mut self, item_name: &'ast <Aug as AstInfo>::ItemName) {
2414        if let ResolvedItemName::Item { id, version, .. } = item_name {
2415            let global_ids = self.ids.entry(*id).or_default();
2416            if let Some(item) = self.catalog.try_get_item(id) {
2417                global_ids.insert(item.at_version(*version).global_id());
2418            }
2419        }
2420    }
2421
2422    fn visit_data_type(&mut self, data_type: &'ast <Aug as AstInfo>::DataType) {
2423        match data_type {
2424            ResolvedDataType::AnonymousList(data_type) => self.visit_data_type(data_type),
2425            ResolvedDataType::AnonymousMap {
2426                key_type,
2427                value_type,
2428            } => {
2429                self.visit_data_type(key_type);
2430                self.visit_data_type(value_type);
2431            }
2432            ResolvedDataType::Named { id, .. } => {
2433                self.ids.entry(*id).or_default();
2434            }
2435            ResolvedDataType::Error => {}
2436        }
2437    }
2438}
2439
2440pub fn visit_dependencies<'ast, N>(catalog: &dyn SessionCatalog, node: &'ast N) -> ResolvedIds
2441where
2442    N: VisitNode<'ast, Aug> + 'ast,
2443{
2444    let mut visitor = DependencyVisitor::new(catalog);
2445    node.visit(&mut visitor);
2446    ResolvedIds::new(visitor.ids)
2447}
2448
2449#[derive(Debug)]
2450pub struct ItemDependencyModifier<'a> {
2451    pub modified: bool,
2452    pub id_map: &'a BTreeMap<CatalogItemId, CatalogItemId>,
2453}
2454
2455impl<'ast, 'a> VisitMut<'ast, Raw> for ItemDependencyModifier<'a> {
2456    fn visit_item_name_mut(&mut self, item_name: &mut RawItemName) {
2457        if let RawItemName::Id(id, _, _) = item_name {
2458            let parsed_id = id.parse::<CatalogItemId>().unwrap();
2459            if let Some(new_id) = self.id_map.get(&parsed_id) {
2460                *id = new_id.to_string();
2461                self.modified = true;
2462            }
2463        }
2464    }
2465}
2466
2467/// Updates any references in the provided AST node that are keys in `id_map`.
2468/// If an id is found it will be updated to the value of the key in `id_map`.
2469/// This assumes the names of the reference(s) are unmodified (e.g. each pair of
2470/// ids refer to an item of the same name, whose id has changed).
2471pub fn modify_dependency_item_ids<'ast, N>(
2472    node: &'ast mut N,
2473    id_map: &BTreeMap<CatalogItemId, CatalogItemId>,
2474) -> bool
2475where
2476    N: VisitMutNode<'ast, Raw>,
2477{
2478    let mut modifier = ItemDependencyModifier {
2479        id_map,
2480        modified: false,
2481    };
2482    node.visit_mut(&mut modifier);
2483
2484    modifier.modified
2485}
2486
2487// Used when displaying a view's source for human creation. If the name
2488// specified is the same as the name in the catalog, we don't use the ID format.
2489#[derive(Debug)]
2490pub struct NameSimplifier<'a> {
2491    pub catalog: &'a dyn SessionCatalog,
2492}
2493
2494impl<'ast, 'a> VisitMut<'ast, Aug> for NameSimplifier<'a> {
2495    fn visit_cluster_name_mut(&mut self, node: &mut ResolvedClusterName) {
2496        node.print_name = Some(self.catalog.get_cluster(node.id).name().into());
2497    }
2498
2499    fn visit_item_name_mut(&mut self, name: &mut ResolvedItemName) {
2500        if let ResolvedItemName::Item {
2501            id,
2502            full_name,
2503            print_id,
2504            ..
2505        } = name
2506        {
2507            let item = self.catalog.get_item(id);
2508            let catalog_full_name = self.catalog.resolve_full_name(item.name());
2509            if catalog_full_name == *full_name {
2510                *print_id = false;
2511            }
2512        }
2513    }
2514
2515    fn visit_data_type_mut(&mut self, name: &mut ResolvedDataType) {
2516        if let ResolvedDataType::Named {
2517            id,
2518            full_name,
2519            print_id,
2520            ..
2521        } = name
2522        {
2523            let item = self.catalog.get_item(id);
2524            let catalog_full_name = self.catalog.resolve_full_name(item.name());
2525            if catalog_full_name == *full_name {
2526                *print_id = false;
2527            }
2528        }
2529    }
2530}
2531
2532/// Returns the [`CatalogItemId`] dependencies the provided `node` has.
2533///
2534/// _DOES NOT_ resolve names, simply does a recursive walk through an object to
2535/// find all of the IDs.
2536pub fn dependencies<'ast, N>(node: &'ast N) -> Result<BTreeSet<CatalogItemId>, anyhow::Error>
2537where
2538    N: VisitNode<'ast, Raw>,
2539{
2540    let mut visitor = IdDependencVisitor::default();
2541    node.visit(&mut visitor);
2542    match visitor.error {
2543        Some(error) => Err(error),
2544        None => Ok(visitor.ids),
2545    }
2546}
2547
2548#[derive(Debug, Default)]
2549struct IdDependencVisitor {
2550    ids: BTreeSet<CatalogItemId>,
2551    error: Option<anyhow::Error>,
2552}
2553
2554impl<'ast> Visit<'ast, Raw> for IdDependencVisitor {
2555    fn visit_item_name(&mut self, node: &'ast <Raw as AstInfo>::ItemName) {
2556        // Bail early if we're already in an error state.
2557        if self.error.is_some() {
2558            return;
2559        }
2560
2561        match node {
2562            // Nothing to do! We don't lookup names.
2563            RawItemName::Name(_) => (),
2564            RawItemName::Id(id, _name, _version) => match id.parse::<CatalogItemId>() {
2565                Ok(id) => {
2566                    self.ids.insert(id);
2567                }
2568                Err(e) => {
2569                    self.error = Some(e);
2570                }
2571            },
2572        }
2573    }
2574}