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