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