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