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