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