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