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