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::MetricSink(item_id)
1236 | CommentObjectId::Index(item_id)
1237 | CommentObjectId::Func(item_id)
1238 | CommentObjectId::Connection(item_id)
1239 | CommentObjectId::Type(item_id)
1240 | CommentObjectId::Secret(item_id) => ObjectId::Item(item_id),
1241 CommentObjectId::Role(id) => ObjectId::Role(id),
1242 CommentObjectId::Database(id) => ObjectId::Database(id),
1243 CommentObjectId::Schema(id) => ObjectId::Schema(id),
1244 CommentObjectId::Cluster(id) => ObjectId::Cluster(id),
1245 CommentObjectId::ClusterReplica(id) => ObjectId::ClusterReplica(id),
1246 CommentObjectId::NetworkPolicy(id) => ObjectId::NetworkPolicy(id),
1247 }
1248 }
1249}
1250
1251#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
1252pub enum SystemObjectId {
1253 Object(ObjectId),
1255 System,
1257}
1258
1259impl SystemObjectId {
1260 pub fn object_id(&self) -> Option<&ObjectId> {
1261 match self {
1262 SystemObjectId::Object(object_id) => Some(object_id),
1263 SystemObjectId::System => None,
1264 }
1265 }
1266
1267 pub fn is_system(&self) -> bool {
1268 matches!(self, SystemObjectId::System)
1269 }
1270}
1271
1272impl From<ObjectId> for SystemObjectId {
1273 fn from(id: ObjectId) -> Self {
1274 SystemObjectId::Object(id)
1275 }
1276}
1277
1278#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize)]
1290pub enum CommentObjectId {
1291 Table(CatalogItemId),
1292 View(CatalogItemId),
1293 MaterializedView(CatalogItemId),
1294 Source(CatalogItemId),
1295 Sink(CatalogItemId),
1296 MetricSink(CatalogItemId),
1297 Index(CatalogItemId),
1298 Func(CatalogItemId),
1299 Connection(CatalogItemId),
1300 Type(CatalogItemId),
1301 Secret(CatalogItemId),
1302 Role(RoleId),
1303 Database(DatabaseId),
1304 Schema((ResolvedDatabaseSpecifier, SchemaSpecifier)),
1305 Cluster(ClusterId),
1306 ClusterReplica((ClusterId, ReplicaId)),
1307 NetworkPolicy(NetworkPolicyId),
1308}
1309
1310#[derive(Debug, Clone, Copy)]
1321struct ItemResolutionConfig {
1322 types: bool,
1323 functions: bool,
1324 relations: bool,
1325}
1326
1327#[derive(Debug)]
1328pub struct NameResolver<'a> {
1329 catalog: &'a dyn SessionCatalog,
1330 ctes: BTreeMap<String, LocalId>,
1331 next_cte_id: u64,
1336 status: Result<(), PlanError>,
1337 ids: BTreeMap<CatalogItemId, BTreeSet<GlobalId>>,
1338}
1339
1340impl<'a> NameResolver<'a> {
1341 fn new(catalog: &'a dyn SessionCatalog) -> NameResolver<'a> {
1342 NameResolver {
1343 catalog,
1344 ctes: BTreeMap::new(),
1345 next_cte_id: 0,
1346 status: Ok(()),
1347 ids: BTreeMap::new(),
1348 }
1349 }
1350
1351 fn allocate_cte_id(&mut self) -> LocalId {
1352 let id = LocalId::new(self.next_cte_id);
1353 self.next_cte_id += 1;
1354 id
1355 }
1356
1357 fn resolve_data_type(&mut self, data_type: RawDataType) -> Result<ResolvedDataType, PlanError> {
1358 match data_type {
1359 RawDataType::Array(elem_type) => {
1360 let name = elem_type.to_string();
1361 match self.resolve_data_type(*elem_type)? {
1362 ResolvedDataType::AnonymousList(_) | ResolvedDataType::AnonymousMap { .. } => {
1363 sql_bail!("type \"{}[]\" does not exist", name)
1364 }
1365 ResolvedDataType::Named { id, modifiers, .. } => {
1366 let element_item = self.catalog.get_item(&id);
1367 let array_item = match element_item.type_details() {
1368 Some(CatalogTypeDetails {
1369 array_id: Some(array_id),
1370 ..
1371 }) => self.catalog.get_item(array_id),
1372 Some(_) => sql_bail!("type \"{}[]\" does not exist", name),
1373 None => {
1374 sql_bail!(
1379 "internal error: {} does not refer to a type",
1380 self.catalog
1381 .resolve_full_name(element_item.name())
1382 .to_string()
1383 .quoted()
1384 );
1385 }
1386 };
1387 self.ids.insert(array_item.id(), BTreeSet::new());
1388 Ok(ResolvedDataType::Named {
1389 id: array_item.id(),
1390 qualifiers: array_item.name().qualifiers.clone(),
1391 full_name: self.catalog.resolve_full_name(array_item.name()),
1392 modifiers,
1393 print_id: true,
1394 })
1395 }
1396 ResolvedDataType::Error => sql_bail!("type \"{}[]\" does not exist", name),
1397 }
1398 }
1399 RawDataType::List(elem_type) => {
1400 let elem_type = self.resolve_data_type(*elem_type)?;
1401 Ok(ResolvedDataType::AnonymousList(Box::new(elem_type)))
1402 }
1403 RawDataType::Map {
1404 key_type,
1405 value_type,
1406 } => {
1407 let key_type = self.resolve_data_type(*key_type)?;
1408 let value_type = self.resolve_data_type(*value_type)?;
1409 Ok(ResolvedDataType::AnonymousMap {
1410 key_type: Box::new(key_type),
1411 value_type: Box::new(value_type),
1412 })
1413 }
1414 RawDataType::Other { name, typ_mod } => {
1415 let (full_name, item) = match name {
1416 RawItemName::Name(name) => {
1417 let name = normalize::unresolved_item_name(name)?;
1418 let item = self.catalog.resolve_type(&name)?;
1419 let full_name = self.catalog.resolve_full_name(item.name());
1420 (full_name, item)
1421 }
1422 RawItemName::Id(id, name, version) => {
1423 let id: CatalogItemId = id.parse()?;
1424 let item = match self.catalog.try_get_item(&id) {
1425 Some(item) => item,
1426 None => return Err(PlanError::InvalidId(id)),
1427 };
1428 let full_name = normalize::full_name(name)?;
1429 if version.is_some() {
1430 sql_bail!("specifying a version for a type reference is not supported");
1431 }
1432
1433 (full_name, item)
1434 }
1435 };
1436 self.ids.insert(item.id(), BTreeSet::new());
1437 if let Some(CatalogTypeDetails {
1442 typ: CatalogType::Array { element_reference },
1443 ..
1444 }) = item.type_details()
1445 {
1446 self.ids.insert(*element_reference, BTreeSet::new());
1447 }
1448 Ok(ResolvedDataType::Named {
1449 id: item.id(),
1450 qualifiers: item.name().qualifiers.clone(),
1451 full_name,
1452 modifiers: typ_mod,
1453 print_id: true,
1454 })
1455 }
1456 }
1457 }
1458
1459 fn resolve_item_name(
1460 &mut self,
1461 item_name: RawItemName,
1462 config: ItemResolutionConfig,
1463 ) -> ResolvedItemName {
1464 match item_name {
1465 RawItemName::Name(name) => self.resolve_item_name_name(name, config),
1466 RawItemName::Id(id, raw_name, version) => {
1467 self.resolve_item_name_id(id, raw_name, version)
1468 }
1469 }
1470 }
1471
1472 fn resolve_item_name_name(
1473 &mut self,
1474 raw_name: UnresolvedItemName,
1475 config: ItemResolutionConfig,
1476 ) -> ResolvedItemName {
1477 let raw_name = match normalize::unresolved_item_name(raw_name) {
1478 Ok(raw_name) => raw_name,
1479 Err(e) => {
1480 if self.status.is_ok() {
1481 self.status = Err(e);
1482 }
1483 return ResolvedItemName::Error;
1484 }
1485 };
1486
1487 let mut r: Result<&dyn CatalogItem, CatalogError> =
1488 Err(CatalogError::UnknownItem(raw_name.to_string()));
1489
1490 if r.is_err() && config.types {
1491 r = self.catalog.resolve_type(&raw_name);
1492 }
1493
1494 if r.is_err() && config.functions {
1495 r = self.catalog.resolve_function(&raw_name);
1496 }
1497
1498 if r.is_err() && config.relations {
1499 if raw_name.database.is_none() && raw_name.schema.is_none() {
1504 let norm_name = normalize::ident(Ident::new_unchecked(&raw_name.item));
1505 if let Some(id) = self.ctes.get(&norm_name) {
1506 return ResolvedItemName::Cte {
1507 id: *id,
1508 name: norm_name,
1509 };
1510 }
1511 }
1512 r = self.catalog.resolve_item(&raw_name);
1513 };
1514
1515 match r {
1516 Ok(item) => {
1517 let item = item.at_version(RelationVersionSelector::Latest);
1519 self.ids
1520 .entry(item.id())
1521 .or_default()
1522 .insert(item.global_id());
1523 let print_id = !matches!(
1524 item.item_type(),
1525 CatalogItemType::Func | CatalogItemType::Type
1526 );
1527 let alter_table_enabled =
1528 self.catalog.system_vars().enable_alter_table_add_column();
1529 let version = match item.latest_version() {
1530 Some(v) if item.id().is_user() && alter_table_enabled => {
1532 RelationVersionSelector::Specific(v)
1533 }
1534 _ => RelationVersionSelector::Latest,
1535 };
1536
1537 ResolvedItemName::Item {
1538 id: item.id(),
1539 qualifiers: item.name().qualifiers.clone(),
1540 full_name: self.catalog.resolve_full_name(item.name()),
1541 print_id,
1542 version,
1543 }
1544 }
1545 Err(mut e) => {
1546 if self.status.is_ok() {
1547 match &mut e {
1548 CatalogError::UnknownFunction {
1549 name: _,
1550 alternative,
1551 } => {
1552 if raw_name.database.is_none()
1555 && (raw_name.schema.is_none()
1556 || raw_name.schema.as_deref() == Some("pg_catalog")
1557 && raw_name.item.starts_with("json_"))
1558 {
1559 let jsonb_name = PartialItemName {
1560 item: raw_name.item.replace("json_", "jsonb_"),
1561 ..raw_name
1562 };
1563 if self.catalog.resolve_function(&jsonb_name).is_ok() {
1564 *alternative = Some(jsonb_name.to_string());
1565 }
1566 }
1567 }
1568 _ => (),
1569 }
1570
1571 self.status = Err(e.into());
1572 }
1573 ResolvedItemName::Error
1574 }
1575 }
1576 }
1577
1578 fn resolve_item_name_id(
1579 &mut self,
1580 id: String,
1581 raw_name: UnresolvedItemName,
1582 version: Option<Version>,
1583 ) -> ResolvedItemName {
1584 let id: CatalogItemId = match id.parse() {
1585 Ok(id) => id,
1586 Err(e) => {
1587 if self.status.is_ok() {
1588 self.status = Err(e.into());
1589 }
1590 return ResolvedItemName::Error;
1591 }
1592 };
1593 let item = match self.catalog.try_get_item(&id) {
1594 Some(item) => item,
1595 None => {
1596 if self.status.is_ok() {
1597 self.status = Err(PlanError::InvalidId(id));
1598 }
1599 return ResolvedItemName::Error;
1600 }
1601 };
1602 let alter_table_enabled = self.catalog.system_vars().enable_alter_table_add_column();
1603 let version = match version {
1604 None => match item.latest_version() {
1607 Some(v) if id.is_user() && alter_table_enabled => {
1612 RelationVersionSelector::Specific(v)
1613 }
1614 _ => RelationVersionSelector::Latest,
1615 },
1616 Some(v) => {
1618 let specified_version = RelationVersion::from(v);
1619 match item.latest_version() {
1620 Some(latest) if latest >= specified_version => {
1621 RelationVersionSelector::Specific(specified_version)
1622 }
1623 _ if !id.is_user() => RelationVersionSelector::Latest,
1629 _ => {
1630 if self.status.is_ok() {
1631 self.status = Err(PlanError::InvalidVersion {
1632 name: item.name().item.clone(),
1633 version: v.to_string(),
1634 })
1635 }
1636 return ResolvedItemName::Error;
1637 }
1638 }
1639 }
1640 };
1641 let item = item.at_version(version);
1642 self.ids
1643 .entry(item.id())
1644 .or_default()
1645 .insert(item.global_id());
1646
1647 let full_name = match normalize::full_name(raw_name) {
1648 Ok(full_name) => full_name,
1649 Err(e) => {
1650 if self.status.is_ok() {
1651 self.status = Err(e);
1652 }
1653 return ResolvedItemName::Error;
1654 }
1655 };
1656 ResolvedItemName::Item {
1657 id,
1658 qualifiers: item.name().qualifiers.clone(),
1659 full_name,
1660 print_id: true,
1661 version,
1662 }
1663 }
1664}
1665
1666impl<'a> Fold<Raw, Aug> for NameResolver<'a> {
1667 fn fold_nested_statement(
1668 &mut self,
1669 stmt: <Raw as AstInfo>::NestedStatement,
1670 ) -> <Aug as AstInfo>::NestedStatement {
1671 stmt
1672 }
1673
1674 fn fold_query(&mut self, q: Query<Raw>) -> Query<Aug> {
1675 let mut shadowed_cte_ids = Vec::new();
1678
1679 use itertools::Itertools;
1681 if let Some(ident) = q.ctes.bound_identifiers().duplicates().next() {
1682 self.status = Err(sql_err!(
1683 "WITH query name \"{}\" specified more than once",
1684 normalize::ident_ref(ident),
1685 ));
1686 }
1687
1688 let ctes: CteBlock<Aug> = match q.ctes {
1689 CteBlock::Simple(ctes) => {
1690 let mut result_ctes = Vec::<Cte<Aug>>::new();
1691
1692 for cte in ctes.into_iter() {
1693 let cte_name = normalize::ident(cte.alias.name.clone());
1694 let local_id = self.allocate_cte_id();
1695
1696 result_ctes.push(Cte {
1697 alias: cte.alias,
1698 id: local_id,
1699 query: self.fold_query(cte.query),
1700 });
1701
1702 let shadowed_id = self.ctes.insert(cte_name.clone(), local_id);
1703 shadowed_cte_ids.push((cte_name, shadowed_id));
1704 }
1705 CteBlock::Simple(result_ctes)
1706 }
1707 CteBlock::MutuallyRecursive(MutRecBlock { options, ctes }) => {
1708 let mut result_ctes = Vec::<CteMutRec<Aug>>::new();
1709
1710 let mut local_ids = Vec::with_capacity(ctes.len());
1713 for cte in ctes.iter() {
1714 let cte_name = normalize::ident(cte.name.clone());
1715 let local_id = self.allocate_cte_id();
1716 let shadowed_id = self.ctes.insert(cte_name.clone(), local_id);
1717 shadowed_cte_ids.push((cte_name, shadowed_id));
1718 local_ids.push(local_id);
1719 }
1720
1721 for (cte, local_id) in ctes.into_iter().zip_eq(local_ids) {
1722 let columns = cte
1723 .columns
1724 .into_iter()
1725 .map(|column| self.fold_cte_mut_rec_column_def(column))
1726 .collect();
1727 let query = self.fold_query(cte.query);
1728 result_ctes.push(CteMutRec {
1729 name: cte.name,
1730 columns,
1731 id: local_id,
1732 query,
1733 });
1734 }
1735 CteBlock::MutuallyRecursive(MutRecBlock {
1736 options: options
1737 .into_iter()
1738 .map(|option| self.fold_mut_rec_block_option(option))
1739 .collect(),
1740 ctes: result_ctes,
1741 })
1742 }
1743 };
1744
1745 let result = Query {
1746 ctes,
1747 body: mz_ore::stack::maybe_grow(|| self.fold_set_expr(q.body)),
1749 limit: q.limit.map(|l| self.fold_limit(l)),
1750 offset: q.offset.map(|l| self.fold_expr(l)),
1751 order_by: q
1752 .order_by
1753 .into_iter()
1754 .map(|c| self.fold_order_by_expr(c))
1755 .collect(),
1756 };
1757
1758 for (name, value) in shadowed_cte_ids.iter() {
1760 match value {
1761 Some(value) => {
1762 self.ctes.insert(name.to_string(), value.clone());
1763 }
1764 None => {
1765 self.ctes.remove(name);
1766 }
1767 };
1768 }
1769
1770 result
1771 }
1772
1773 fn fold_cte_id(&mut self, _id: <Raw as AstInfo>::CteId) -> <Aug as AstInfo>::CteId {
1774 panic!("this should have been handled when walking the CTE");
1775 }
1776
1777 fn fold_item_name(
1778 &mut self,
1779 item_name: <Raw as AstInfo>::ItemName,
1780 ) -> <Aug as AstInfo>::ItemName {
1781 self.resolve_item_name(
1782 item_name,
1783 ItemResolutionConfig {
1786 functions: false,
1787 types: false,
1788 relations: true,
1789 },
1790 )
1791 }
1792
1793 fn fold_column_name(&mut self, column_name: ast::ColumnName<Raw>) -> ast::ColumnName<Aug> {
1794 let item_name = self.resolve_item_name(
1795 column_name.relation,
1796 ItemResolutionConfig {
1797 functions: false,
1798 types: true,
1799 relations: true,
1800 },
1801 );
1802
1803 match &item_name {
1804 ResolvedItemName::Item {
1805 id,
1806 full_name,
1807 version,
1808 qualifiers: _,
1809 print_id: _,
1810 } => {
1811 let item = self.catalog.get_item(id).at_version(*version);
1812 let name = normalize::column_name(column_name.column.clone());
1813
1814 let maybe_desc = match item.type_details() {
1815 Some(details) => match details.typ.desc(self.catalog) {
1816 Ok(desc) => desc.map(Cow::Owned),
1817 Err(e) => {
1818 if self.status.is_ok() {
1819 self.status = Err(e);
1820 }
1821 return ast::ColumnName {
1822 relation: ResolvedItemName::Error,
1823 column: ResolvedColumnReference::Error,
1824 };
1825 }
1826 },
1827 None => item.relation_desc(),
1828 };
1829 let Some(desc) = maybe_desc else {
1830 if self.status.is_ok() {
1831 self.status = Err(PlanError::ItemWithoutColumns {
1832 name: full_name.to_string(),
1833 item_type: item.item_type(),
1834 });
1835 }
1836 return ast::ColumnName {
1837 relation: ResolvedItemName::Error,
1838 column: ResolvedColumnReference::Error,
1839 };
1840 };
1841
1842 let Some((index, _typ)) = desc.get_by_name(&name) else {
1843 if self.status.is_ok() {
1844 let similar = desc.iter_similar_names(&name).cloned().collect();
1845 self.status = Err(PlanError::UnknownColumn {
1846 table: Some(full_name.clone().into()),
1847 column: name,
1848 similar,
1849 })
1850 }
1851 return ast::ColumnName {
1852 relation: ResolvedItemName::Error,
1853 column: ResolvedColumnReference::Error,
1854 };
1855 };
1856
1857 ast::ColumnName {
1858 relation: item_name,
1859 column: ResolvedColumnReference::Column { name, index },
1860 }
1861 }
1862 ResolvedItemName::Cte { .. } | ResolvedItemName::Error => ast::ColumnName {
1863 relation: ResolvedItemName::Error,
1864 column: ResolvedColumnReference::Error,
1865 },
1866 }
1867 }
1868
1869 fn fold_column_reference(
1870 &mut self,
1871 _node: <Raw as AstInfo>::ColumnReference,
1872 ) -> <Aug as AstInfo>::ColumnReference {
1873 ResolvedColumnReference::Error
1875 }
1876
1877 fn fold_data_type(
1878 &mut self,
1879 data_type: <Raw as AstInfo>::DataType,
1880 ) -> <Aug as AstInfo>::DataType {
1881 match self.resolve_data_type(data_type) {
1882 Ok(data_type) => data_type,
1883 Err(e) => {
1884 if self.status.is_ok() {
1885 self.status = Err(e);
1886 }
1887 ResolvedDataType::Error
1888 }
1889 }
1890 }
1891
1892 fn fold_schema_name(
1893 &mut self,
1894 name: <Raw as AstInfo>::SchemaName,
1895 ) -> <Aug as AstInfo>::SchemaName {
1896 let norm_name = match normalize::unresolved_schema_name(name) {
1897 Ok(norm_name) => norm_name,
1898 Err(e) => {
1899 if self.status.is_ok() {
1900 self.status = Err(e);
1901 }
1902 return ResolvedSchemaName::Error;
1903 }
1904 };
1905
1906 if norm_name.database.is_none() && norm_name.schema == mz_repr::namespaces::MZ_TEMP_SCHEMA {
1910 return ResolvedSchemaName::Schema {
1911 database_spec: ResolvedDatabaseSpecifier::Ambient,
1912 schema_spec: SchemaSpecifier::Temporary,
1913 full_name: FullSchemaName {
1914 database: RawDatabaseSpecifier::Ambient,
1915 schema: mz_repr::namespaces::MZ_TEMP_SCHEMA.to_string(),
1916 },
1917 };
1918 }
1919
1920 match self
1921 .catalog
1922 .resolve_schema(norm_name.database.as_deref(), norm_name.schema.as_str())
1923 {
1924 Ok(schema) => {
1925 let raw_database_spec = match schema.database() {
1926 ResolvedDatabaseSpecifier::Ambient => RawDatabaseSpecifier::Ambient,
1927 ResolvedDatabaseSpecifier::Id(id) => {
1928 RawDatabaseSpecifier::Name(self.catalog.get_database(id).name().to_string())
1929 }
1930 };
1931 ResolvedSchemaName::Schema {
1932 database_spec: schema.database().clone(),
1933 schema_spec: schema.id().clone(),
1934 full_name: FullSchemaName {
1935 database: raw_database_spec,
1936 schema: schema.name().schema.clone(),
1937 },
1938 }
1939 }
1940 Err(e) => {
1941 if self.status.is_ok() {
1942 self.status = Err(e.into());
1943 }
1944 ResolvedSchemaName::Error
1945 }
1946 }
1947 }
1948
1949 fn fold_database_name(
1950 &mut self,
1951 database_name: <Raw as AstInfo>::DatabaseName,
1952 ) -> <Aug as AstInfo>::DatabaseName {
1953 match self.catalog.resolve_database(database_name.0.as_str()) {
1954 Ok(database) => ResolvedDatabaseName::Database {
1955 id: database.id(),
1956 name: database_name.0.into_string(),
1957 },
1958 Err(e) => {
1959 if self.status.is_ok() {
1960 self.status = Err(e.into());
1961 }
1962 ResolvedDatabaseName::Error
1963 }
1964 }
1965 }
1966
1967 fn fold_cluster_name(
1968 &mut self,
1969 cluster_name: <Raw as AstInfo>::ClusterName,
1970 ) -> <Aug as AstInfo>::ClusterName {
1971 match cluster_name {
1972 RawClusterName::Unresolved(ident) => {
1973 match self.catalog.resolve_cluster(Some(ident.as_str())) {
1974 Ok(cluster) => ResolvedClusterName {
1975 id: cluster.id(),
1976 print_name: None,
1977 },
1978 Err(e) => {
1979 self.status = Err(e.into());
1980 ResolvedClusterName {
1981 id: ClusterId::system(0).expect("0 is a valid ID"),
1984 print_name: None,
1985 }
1986 }
1987 }
1988 }
1989 RawClusterName::Resolved(ident) => match ident.parse() {
1990 Ok(id) => ResolvedClusterName {
1991 id,
1992 print_name: None,
1993 },
1994 Err(e) => {
1995 self.status = Err(e.into());
1996 ResolvedClusterName {
1997 id: ClusterId::system(0).expect("0 is a valid ID"),
2000 print_name: None,
2001 }
2002 }
2003 },
2004 }
2005 }
2006
2007 fn fold_with_option_value(
2008 &mut self,
2009 node: mz_sql_parser::ast::WithOptionValue<Raw>,
2010 ) -> mz_sql_parser::ast::WithOptionValue<Aug> {
2011 use mz_sql_parser::ast::WithOptionValue::*;
2012 match node {
2013 Sequence(vs) => Sequence(
2014 vs.into_iter()
2015 .map(|v| self.fold_with_option_value(v))
2016 .collect(),
2017 ),
2018 Map(map) => Map(map
2019 .into_iter()
2020 .map(|(k, v)| (k, self.fold_with_option_value(v)))
2021 .collect()),
2022 Value(v) => Value(self.fold_value(v)),
2023 DataType(dt) => DataType(self.fold_data_type(dt)),
2024 Secret(secret) => {
2025 let item_name = self.fold_item_name(secret);
2026 match &item_name {
2027 ResolvedItemName::Item { id, .. } => {
2028 let item = self.catalog.get_item(id);
2029 if item.item_type() != CatalogItemType::Secret {
2030 self.status =
2031 Err(PlanError::InvalidSecret(Box::new(item_name.clone())));
2032 }
2033 }
2034 ResolvedItemName::Cte { .. } => {
2035 self.status = Err(PlanError::InvalidSecret(Box::new(item_name.clone())));
2036 }
2037 ResolvedItemName::Error => {}
2038 }
2039 Secret(item_name)
2040 }
2041 Item(obj) => {
2042 let item_name = self.fold_item_name(obj);
2043 match &item_name {
2044 ResolvedItemName::Item { .. } => {}
2045 ResolvedItemName::Cte { .. } => {
2046 self.status = Err(PlanError::InvalidObject(Box::new(item_name.clone())));
2047 }
2048 ResolvedItemName::Error => {}
2049 }
2050 Item(item_name)
2051 }
2052 UnresolvedItemName(name) => UnresolvedItemName(self.fold_unresolved_item_name(name)),
2053 Ident(name) => Ident(self.fold_ident(name)),
2054 Expr(e) => Expr(self.fold_expr(e)),
2055 ClusterReplicas(replicas) => ClusterReplicas(
2056 replicas
2057 .into_iter()
2058 .map(|r| self.fold_replica_definition(r))
2059 .collect(),
2060 ),
2061 ConnectionKafkaBroker(broker) => ConnectionKafkaBroker(self.fold_kafka_broker(broker)),
2062 ConnectionAwsPrivatelink(privatelink) => {
2063 ConnectionAwsPrivatelink(self.fold_connection_default_aws_privatelink(privatelink))
2064 }
2065 KafkaMatchingBrokerRule(x) => {
2066 KafkaMatchingBrokerRule(self.fold_kafka_matching_broker_rule(x))
2067 }
2068 RetainHistoryFor(value) => RetainHistoryFor(self.fold_value(value)),
2069 Refresh(refresh) => Refresh(self.fold_refresh_option_value(refresh)),
2070 ClusterScheduleOptionValue(value) => ClusterScheduleOptionValue(value),
2071 ClusterAutoScalingStrategyOptionValue(value) => {
2072 ClusterAutoScalingStrategyOptionValue(value)
2073 }
2074 ClusterAlterStrategy(value) => {
2075 ClusterAlterStrategy(self.fold_cluster_alter_option_value(value))
2076 }
2077 NetworkPolicyRules(rules) => NetworkPolicyRules(
2078 rules
2079 .into_iter()
2080 .map(|r| self.fold_network_policy_rule_definition(r))
2081 .collect(),
2082 ),
2083 }
2084 }
2085
2086 fn fold_role_name(&mut self, name: <Raw as AstInfo>::RoleName) -> <Aug as AstInfo>::RoleName {
2087 match self.catalog.resolve_role(name.as_str()) {
2088 Ok(role) => ResolvedRoleName {
2089 id: role.id(),
2090 name: role.name().to_string(),
2091 },
2092 Err(e) => {
2093 if self.status.is_ok() {
2094 self.status = Err(e.into());
2095 }
2096 ResolvedRoleName {
2098 id: RoleId::User(0),
2099 name: "".to_string(),
2100 }
2101 }
2102 }
2103 }
2104
2105 fn fold_network_policy_name(
2106 &mut self,
2107 name: <Raw as AstInfo>::NetworkPolicyName,
2108 ) -> <Aug as AstInfo>::NetworkPolicyName {
2109 let name_str = match &name {
2110 RawNetworkPolicyName::Unresolved(ident) => ident.as_str(),
2111 RawNetworkPolicyName::Resolved(s) => s.as_str(),
2112 };
2113 match self.catalog.resolve_network_policy(name_str) {
2114 Ok(policy) => ResolvedNetworkPolicyName {
2115 id: policy.id(),
2116 name: policy.name().to_string(),
2117 },
2118 Err(e) => {
2119 if self.status.is_ok() {
2120 self.status = Err(e.into());
2121 }
2122 ResolvedNetworkPolicyName {
2124 id: NetworkPolicyId::User(0),
2125 name: "".to_string(),
2126 }
2127 }
2128 }
2129 }
2130
2131 fn fold_object_name(
2132 &mut self,
2133 name: <Raw as AstInfo>::ObjectName,
2134 ) -> <Aug as AstInfo>::ObjectName {
2135 match name {
2136 UnresolvedObjectName::Cluster(name) => ResolvedObjectName::Cluster(
2137 self.fold_cluster_name(RawClusterName::Unresolved(name)),
2138 ),
2139 UnresolvedObjectName::ClusterReplica(name) => {
2140 match self.catalog.resolve_cluster_replica(&name) {
2141 Ok(cluster_replica) => {
2142 ResolvedObjectName::ClusterReplica(ResolvedClusterReplicaName {
2143 cluster_id: cluster_replica.cluster_id(),
2144 replica_id: cluster_replica.replica_id(),
2145 })
2146 }
2147 Err(e) => {
2148 self.status = Err(e.into());
2149 ResolvedObjectName::ClusterReplica(ResolvedClusterReplicaName {
2150 cluster_id: ClusterId::system(0).expect("0 is a valid ID"),
2153 replica_id: ReplicaId::System(0),
2154 })
2155 }
2156 }
2157 }
2158 UnresolvedObjectName::Database(name) => {
2159 ResolvedObjectName::Database(self.fold_database_name(name))
2160 }
2161 UnresolvedObjectName::Schema(name) => {
2162 ResolvedObjectName::Schema(self.fold_schema_name(name))
2163 }
2164 UnresolvedObjectName::Role(name) => ResolvedObjectName::Role(self.fold_role_name(name)),
2165 UnresolvedObjectName::Item(name) => {
2166 ResolvedObjectName::Item(self.fold_item_name(RawItemName::Name(name)))
2167 }
2168 UnresolvedObjectName::NetworkPolicy(name) => ResolvedObjectName::NetworkPolicy(
2169 self.fold_network_policy_name(RawNetworkPolicyName::Unresolved(name)),
2170 ),
2171 }
2172 }
2173
2174 fn fold_function(
2175 &mut self,
2176 node: mz_sql_parser::ast::Function<Raw>,
2177 ) -> mz_sql_parser::ast::Function<Aug> {
2178 mz_ore::stack::maybe_grow(|| {
2181 mz_sql_parser::ast::Function {
2182 name: self.resolve_item_name(
2183 node.name,
2184 ItemResolutionConfig {
2187 functions: true,
2188 types: false,
2189 relations: false,
2190 },
2191 ),
2192 args: self.fold_function_args(node.args),
2193 filter: node.filter.map(|expr| Box::new(self.fold_expr(*expr))),
2194 over: node.over.map(|over| self.fold_window_spec(over)),
2195 distinct: node.distinct,
2196 }
2197 })
2198 }
2199
2200 fn fold_table_factor(
2201 &mut self,
2202 node: mz_sql_parser::ast::TableFactor<Raw>,
2203 ) -> mz_sql_parser::ast::TableFactor<Aug> {
2204 use mz_sql_parser::ast::TableFactor::*;
2205 match node {
2206 Table { name, alias } => Table {
2207 name: self.fold_item_name(name),
2208 alias: alias.map(|alias| self.fold_table_alias(alias)),
2209 },
2210 Function {
2211 function,
2212 alias,
2213 with_ordinality,
2214 } => {
2215 match &function.name {
2216 RawItemName::Name(name) => {
2217 if *name == UnresolvedItemName::unqualified(ident!("values"))
2218 && self.status.is_ok()
2219 {
2220 self.status = Err(PlanError::FromValueRequiresParen);
2221 }
2222 }
2223 RawItemName::Id(..) => {}
2224 }
2225
2226 Function {
2227 function: self.fold_function(function),
2228 alias: alias.map(|alias| self.fold_table_alias(alias)),
2229 with_ordinality,
2230 }
2231 }
2232 RowsFrom {
2233 functions,
2234 alias,
2235 with_ordinality,
2236 } => RowsFrom {
2237 functions: functions
2238 .into_iter()
2239 .map(|f| self.fold_function(f))
2240 .collect(),
2241 alias: alias.map(|alias| self.fold_table_alias(alias)),
2242 with_ordinality,
2243 },
2244 Derived {
2245 lateral,
2246 subquery,
2247 alias,
2248 } => Derived {
2249 lateral,
2250 subquery: Box::new(self.fold_query(*subquery)),
2251 alias: alias.map(|alias| self.fold_table_alias(alias)),
2252 },
2253 NestedJoin { join, alias } => NestedJoin {
2254 join: Box::new(self.fold_table_with_joins(*join)),
2255 alias: alias.map(|alias| self.fold_table_alias(alias)),
2256 },
2257 }
2258 }
2259
2260 fn fold_grant_target_specification(
2261 &mut self,
2262 node: GrantTargetSpecification<Raw>,
2263 ) -> GrantTargetSpecification<Aug> {
2264 match node {
2265 GrantTargetSpecification::Object {
2266 object_type: ObjectType::Type,
2267 object_spec_inner: GrantTargetSpecificationInner::Objects { names },
2268 } => GrantTargetSpecification::Object {
2269 object_type: ObjectType::Type,
2270 object_spec_inner: GrantTargetSpecificationInner::Objects {
2271 names: names
2272 .into_iter()
2273 .map(|name| match name {
2274 UnresolvedObjectName::Item(name) => {
2275 ResolvedObjectName::Item(self.resolve_item_name_name(
2276 name,
2277 ItemResolutionConfig {
2280 functions: false,
2281 types: true,
2282 relations: false,
2283 },
2284 ))
2285 }
2286 _ => self.fold_object_name(name),
2287 })
2288 .collect(),
2289 },
2290 },
2291 _ => mz_sql_parser::ast::fold::fold_grant_target_specification(self, node),
2292 }
2293 }
2294
2295 fn fold_doc_on_identifier(&mut self, node: DocOnIdentifier<Raw>) -> DocOnIdentifier<Aug> {
2296 match node {
2297 DocOnIdentifier::Column(name) => DocOnIdentifier::Column(self.fold_column_name(name)),
2298 DocOnIdentifier::Type(name) => DocOnIdentifier::Type(self.resolve_item_name(
2299 name,
2300 ItemResolutionConfig {
2306 functions: false,
2307 types: true,
2308 relations: true,
2309 },
2310 )),
2311 }
2312 }
2313
2314 fn fold_expr(&mut self, node: Expr<Raw>) -> Expr<Aug> {
2315 mz_ore::stack::maybe_grow(|| mz_sql_parser::ast::fold::fold_expr(self, node))
2317 }
2318}
2319
2320#[mz_ore::instrument(target = "compiler", level = "trace", name = "ast_resolve_names")]
2322pub fn resolve<N>(
2323 catalog: &dyn SessionCatalog,
2324 node: N,
2325) -> Result<(N::Folded, ResolvedIds), PlanError>
2326where
2327 N: FoldNode<Raw, Aug>,
2328{
2329 let mut resolver = NameResolver::new(catalog);
2330 let result = node.fold(&mut resolver);
2331 resolver.status?;
2332 Ok((result, ResolvedIds::new(resolver.ids)))
2333}
2334
2335#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
2340pub struct ResolvedIds {
2341 #[serde(serialize_with = "mz_ore::serde::map_key_to_string")]
2342 entries: BTreeMap<CatalogItemId, BTreeSet<GlobalId>>,
2343}
2344
2345impl ResolvedIds {
2346 fn new(entries: BTreeMap<CatalogItemId, BTreeSet<GlobalId>>) -> Self {
2347 ResolvedIds { entries }
2348 }
2349
2350 pub fn empty() -> Self {
2352 ResolvedIds {
2353 entries: BTreeMap::new(),
2354 }
2355 }
2356
2357 pub fn is_empty(&self) -> bool {
2359 self.entries.is_empty()
2360 }
2361
2362 pub fn collections(&self) -> impl Iterator<Item = &GlobalId> {
2364 self.entries.values().flat_map(|gids| gids.into_iter())
2365 }
2366
2367 pub fn items(&self) -> impl Iterator<Item = &CatalogItemId> {
2369 self.entries.keys()
2370 }
2371
2372 pub fn contains_item(&self, item: &CatalogItemId) -> bool {
2374 self.entries.contains_key(item)
2375 }
2376
2377 pub fn add_item(&mut self, item: CatalogItemId) {
2378 self.entries.insert(item, BTreeSet::new());
2379 }
2380
2381 pub fn remove_item(&mut self, item: &CatalogItemId) {
2382 self.entries.remove(item);
2383 }
2384
2385 pub fn extend_from(&mut self, other: &ResolvedIds) {
2387 for (id, gids) in &other.entries {
2388 self.entries
2389 .entry(*id)
2390 .or_default()
2391 .extend(gids.iter().copied());
2392 }
2393 }
2394
2395 pub fn retain_items<F>(&self, predicate: F) -> Self
2398 where
2399 F: Fn(&CatalogItemId) -> bool,
2400 {
2401 let mut new_ids = self.clone();
2402 new_ids
2403 .entries
2404 .retain(|item_id, _global_ids| predicate(item_id));
2405 new_ids
2406 }
2407}
2408
2409impl FromIterator<(CatalogItemId, GlobalId)> for ResolvedIds {
2410 fn from_iter<T: IntoIterator<Item = (CatalogItemId, GlobalId)>>(iter: T) -> Self {
2411 let mut ids = ResolvedIds::empty();
2412 ids.extend(iter);
2413 ids
2414 }
2415}
2416
2417impl Extend<(CatalogItemId, GlobalId)> for ResolvedIds {
2418 fn extend<T: IntoIterator<Item = (CatalogItemId, GlobalId)>>(&mut self, iter: T) {
2419 for (item_id, global_id) in iter {
2420 self.entries.entry(item_id).or_default().insert(global_id);
2421 }
2422 }
2423}
2424
2425#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
2427pub struct DependencyIds(pub BTreeSet<CatalogItemId>);
2428
2429impl FromIterator<CatalogItemId> for DependencyIds {
2430 fn from_iter<T: IntoIterator<Item = CatalogItemId>>(iter: T) -> Self {
2431 DependencyIds(iter.into_iter().collect())
2432 }
2433}
2434
2435#[derive(Debug)]
2436pub struct DependencyVisitor<'a> {
2437 catalog: &'a dyn SessionCatalog,
2438 ids: BTreeMap<CatalogItemId, BTreeSet<GlobalId>>,
2439}
2440
2441impl<'a> DependencyVisitor<'a> {
2442 pub fn new(catalog: &'a dyn SessionCatalog) -> Self {
2443 DependencyVisitor {
2444 catalog,
2445 ids: Default::default(),
2446 }
2447 }
2448}
2449
2450impl<'a, 'ast> Visit<'ast, Aug> for DependencyVisitor<'a> {
2451 fn visit_item_name(&mut self, item_name: &'ast <Aug as AstInfo>::ItemName) {
2452 if let ResolvedItemName::Item { id, version, .. } = item_name {
2453 let global_ids = self.ids.entry(*id).or_default();
2454 if let Some(item) = self.catalog.try_get_item(id) {
2455 global_ids.insert(item.at_version(*version).global_id());
2456 }
2457 }
2458 }
2459
2460 fn visit_data_type(&mut self, data_type: &'ast <Aug as AstInfo>::DataType) {
2461 match data_type {
2462 ResolvedDataType::AnonymousList(data_type) => self.visit_data_type(data_type),
2463 ResolvedDataType::AnonymousMap {
2464 key_type,
2465 value_type,
2466 } => {
2467 self.visit_data_type(key_type);
2468 self.visit_data_type(value_type);
2469 }
2470 ResolvedDataType::Named { id, .. } => {
2471 self.ids.entry(*id).or_default();
2472 }
2473 ResolvedDataType::Error => {}
2474 }
2475 }
2476}
2477
2478pub fn visit_dependencies<'ast, N>(catalog: &dyn SessionCatalog, node: &'ast N) -> ResolvedIds
2479where
2480 N: VisitNode<'ast, Aug> + 'ast,
2481{
2482 let mut visitor = DependencyVisitor::new(catalog);
2483 node.visit(&mut visitor);
2484 ResolvedIds::new(visitor.ids)
2485}
2486
2487#[derive(Debug)]
2488pub struct ItemDependencyModifier<'a> {
2489 pub modified: bool,
2490 pub id_map: &'a BTreeMap<CatalogItemId, CatalogItemId>,
2491}
2492
2493impl<'ast, 'a> VisitMut<'ast, Raw> for ItemDependencyModifier<'a> {
2494 fn visit_item_name_mut(&mut self, item_name: &mut RawItemName) {
2495 if let RawItemName::Id(id, _, _) = item_name {
2496 let parsed_id = id.parse::<CatalogItemId>().unwrap();
2497 if let Some(new_id) = self.id_map.get(&parsed_id) {
2498 *id = new_id.to_string();
2499 self.modified = true;
2500 }
2501 }
2502 }
2503}
2504
2505pub fn modify_dependency_item_ids<'ast, N>(
2510 node: &'ast mut N,
2511 id_map: &BTreeMap<CatalogItemId, CatalogItemId>,
2512) -> bool
2513where
2514 N: VisitMutNode<'ast, Raw>,
2515{
2516 let mut modifier = ItemDependencyModifier {
2517 id_map,
2518 modified: false,
2519 };
2520 node.visit_mut(&mut modifier);
2521
2522 modifier.modified
2523}
2524
2525#[derive(Debug)]
2528pub struct NameSimplifier<'a> {
2529 pub catalog: &'a dyn SessionCatalog,
2530}
2531
2532impl<'ast, 'a> VisitMut<'ast, Aug> for NameSimplifier<'a> {
2533 fn visit_cluster_name_mut(&mut self, node: &mut ResolvedClusterName) {
2534 node.print_name = Some(self.catalog.get_cluster(node.id).name().into());
2535 }
2536
2537 fn visit_item_name_mut(&mut self, name: &mut ResolvedItemName) {
2538 if let ResolvedItemName::Item {
2539 id,
2540 full_name,
2541 print_id,
2542 ..
2543 } = name
2544 {
2545 let item = self.catalog.get_item(id);
2546 let catalog_full_name = self.catalog.resolve_full_name(item.name());
2547 if catalog_full_name == *full_name {
2548 *print_id = false;
2549 }
2550 }
2551 }
2552
2553 fn visit_data_type_mut(&mut self, name: &mut ResolvedDataType) {
2554 if let ResolvedDataType::Named {
2555 id,
2556 full_name,
2557 print_id,
2558 ..
2559 } = name
2560 {
2561 let item = self.catalog.get_item(id);
2562 let catalog_full_name = self.catalog.resolve_full_name(item.name());
2563 if catalog_full_name == *full_name {
2564 *print_id = false;
2565 }
2566 }
2567 }
2568}
2569
2570pub fn dependencies<'ast, N>(node: &'ast N) -> Result<BTreeSet<CatalogItemId>, anyhow::Error>
2575where
2576 N: VisitNode<'ast, Raw>,
2577{
2578 let mut visitor = IdDependencVisitor::default();
2579 node.visit(&mut visitor);
2580 match visitor.error {
2581 Some(error) => Err(error),
2582 None => Ok(visitor.ids),
2583 }
2584}
2585
2586#[derive(Debug, Default)]
2587struct IdDependencVisitor {
2588 ids: BTreeSet<CatalogItemId>,
2589 error: Option<anyhow::Error>,
2590}
2591
2592impl<'ast> Visit<'ast, Raw> for IdDependencVisitor {
2593 fn visit_item_name(&mut self, node: &'ast <Raw as AstInfo>::ItemName) {
2594 if self.error.is_some() {
2596 return;
2597 }
2598
2599 match node {
2600 RawItemName::Name(_) => (),
2602 RawItemName::Id(id, _name, _version) => match id.parse::<CatalogItemId>() {
2603 Ok(id) => {
2604 self.ids.insert(id);
2605 }
2606 Err(e) => {
2607 self.error = Some(e);
2608 }
2609 },
2610 }
2611 }
2612}
2613
2614#[cfg(test)]
2615mod tests {
2616 use proptest::prelude::*;
2617
2618 use super::*;
2619
2620 #[mz_ore::test]
2621 fn proptest_schema_id_roundtrips() {
2622 fn testcase(og: SchemaId) {
2623 let s = og.to_string();
2624 let rnd: SchemaId = s.parse().unwrap();
2625 assert_eq!(og, rnd);
2626 }
2627
2628 proptest!(|(id in any::<SchemaId>())| {
2629 testcase(id);
2630 })
2631 }
2632
2633 #[mz_ore::test]
2634 fn proptest_database_id_roundtrips() {
2635 fn testcase(og: DatabaseId) {
2636 let s = og.to_string();
2637 let rnd: DatabaseId = s.parse().unwrap();
2638 assert_eq!(og, rnd);
2639 }
2640
2641 proptest!(|(id in any::<DatabaseId>())| {
2642 testcase(id);
2643 })
2644 }
2645
2646 #[mz_ore::test]
2647 fn test_schema_id_from_str() {
2648 assert_eq!("s5".parse::<SchemaId>().unwrap(), SchemaId::System(5));
2649 assert_eq!("u5".parse::<SchemaId>().unwrap(), SchemaId::User(5));
2650
2651 for invalid in ["ü1", "ü", "é42", "🦀7", "", "x1", "s"] {
2654 assert!(
2655 invalid.parse::<SchemaId>().is_err(),
2656 "expected {invalid:?} to fail to parse"
2657 );
2658 }
2659 }
2660
2661 #[mz_ore::test]
2662 fn test_database_id_from_str() {
2663 assert_eq!("s5".parse::<DatabaseId>().unwrap(), DatabaseId::System(5));
2664 assert_eq!("u5".parse::<DatabaseId>().unwrap(), DatabaseId::User(5));
2665
2666 for invalid in ["ü1", "ü", "é42", "🦀7", "", "x1", "u"] {
2669 assert!(
2670 invalid.parse::<DatabaseId>().is_err(),
2671 "expected {invalid:?} to fail to parse"
2672 );
2673 }
2674 }
2675}