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 let desc = match item.item_type() {
1767 CatalogItemType::Type => {
1768 let details = item
1769 .type_details()
1770 .expect("type items must carry type details");
1771 match details.typ.desc(self.catalog) {
1772 Ok(Some(desc)) => Cow::Owned(desc),
1773 Ok(None) => {
1774 if self.status.is_ok() {
1775 self.status = Err(PlanError::TypeWithoutColumns {
1776 type_name: full_name.clone().into(),
1777 });
1778 }
1779 return ast::ColumnName {
1780 relation: ResolvedItemName::Error,
1781 column: ResolvedColumnReference::Error,
1782 };
1783 }
1784 Err(e) => {
1785 if self.status.is_ok() {
1786 self.status = Err(e);
1787 }
1788 return ast::ColumnName {
1789 relation: ResolvedItemName::Error,
1790 column: ResolvedColumnReference::Error,
1791 };
1792 }
1793 }
1794 }
1795 _ => match item.desc(full_name) {
1796 Ok(desc) => desc,
1797 Err(e) => {
1798 if self.status.is_ok() {
1799 self.status = Err(e.into());
1800 }
1801 return ast::ColumnName {
1802 relation: ResolvedItemName::Error,
1803 column: ResolvedColumnReference::Error,
1804 };
1805 }
1806 },
1807 };
1808
1809 let Some((index, _typ)) = desc.get_by_name(&name) else {
1810 if self.status.is_ok() {
1811 let similar = desc.iter_similar_names(&name).cloned().collect();
1812 self.status = Err(PlanError::UnknownColumn {
1813 table: Some(full_name.clone().into()),
1814 column: name,
1815 similar,
1816 })
1817 }
1818 return ast::ColumnName {
1819 relation: ResolvedItemName::Error,
1820 column: ResolvedColumnReference::Error,
1821 };
1822 };
1823
1824 ast::ColumnName {
1825 relation: item_name,
1826 column: ResolvedColumnReference::Column { name, index },
1827 }
1828 }
1829 ResolvedItemName::Cte { .. }
1830 | ResolvedItemName::ContinualTask { .. }
1831 | ResolvedItemName::Error => ast::ColumnName {
1832 relation: ResolvedItemName::Error,
1833 column: ResolvedColumnReference::Error,
1834 },
1835 }
1836 }
1837
1838 fn fold_column_reference(
1839 &mut self,
1840 _node: <Raw as AstInfo>::ColumnReference,
1841 ) -> <Aug as AstInfo>::ColumnReference {
1842 ResolvedColumnReference::Error
1844 }
1845
1846 fn fold_data_type(
1847 &mut self,
1848 data_type: <Raw as AstInfo>::DataType,
1849 ) -> <Aug as AstInfo>::DataType {
1850 match self.resolve_data_type(data_type) {
1851 Ok(data_type) => data_type,
1852 Err(e) => {
1853 if self.status.is_ok() {
1854 self.status = Err(e);
1855 }
1856 ResolvedDataType::Error
1857 }
1858 }
1859 }
1860
1861 fn fold_schema_name(
1862 &mut self,
1863 name: <Raw as AstInfo>::SchemaName,
1864 ) -> <Aug as AstInfo>::SchemaName {
1865 let norm_name = match normalize::unresolved_schema_name(name) {
1866 Ok(norm_name) => norm_name,
1867 Err(e) => {
1868 if self.status.is_ok() {
1869 self.status = Err(e);
1870 }
1871 return ResolvedSchemaName::Error;
1872 }
1873 };
1874 match self
1875 .catalog
1876 .resolve_schema(norm_name.database.as_deref(), norm_name.schema.as_str())
1877 {
1878 Ok(schema) => {
1879 let raw_database_spec = match schema.database() {
1880 ResolvedDatabaseSpecifier::Ambient => RawDatabaseSpecifier::Ambient,
1881 ResolvedDatabaseSpecifier::Id(id) => {
1882 RawDatabaseSpecifier::Name(self.catalog.get_database(id).name().to_string())
1883 }
1884 };
1885 ResolvedSchemaName::Schema {
1886 database_spec: schema.database().clone(),
1887 schema_spec: schema.id().clone(),
1888 full_name: FullSchemaName {
1889 database: raw_database_spec,
1890 schema: schema.name().schema.clone(),
1891 },
1892 }
1893 }
1894 Err(e) => {
1895 if self.status.is_ok() {
1896 self.status = Err(e.into());
1897 }
1898 ResolvedSchemaName::Error
1899 }
1900 }
1901 }
1902
1903 fn fold_database_name(
1904 &mut self,
1905 database_name: <Raw as AstInfo>::DatabaseName,
1906 ) -> <Aug as AstInfo>::DatabaseName {
1907 match self.catalog.resolve_database(database_name.0.as_str()) {
1908 Ok(database) => ResolvedDatabaseName::Database {
1909 id: database.id(),
1910 name: database_name.0.into_string(),
1911 },
1912 Err(e) => {
1913 if self.status.is_ok() {
1914 self.status = Err(e.into());
1915 }
1916 ResolvedDatabaseName::Error
1917 }
1918 }
1919 }
1920
1921 fn fold_cluster_name(
1922 &mut self,
1923 cluster_name: <Raw as AstInfo>::ClusterName,
1924 ) -> <Aug as AstInfo>::ClusterName {
1925 match cluster_name {
1926 RawClusterName::Unresolved(ident) => {
1927 match self.catalog.resolve_cluster(Some(ident.as_str())) {
1928 Ok(cluster) => ResolvedClusterName {
1929 id: cluster.id(),
1930 print_name: None,
1931 },
1932 Err(e) => {
1933 self.status = Err(e.into());
1934 ResolvedClusterName {
1935 id: ClusterId::system(0).expect("0 is a valid ID"),
1938 print_name: None,
1939 }
1940 }
1941 }
1942 }
1943 RawClusterName::Resolved(ident) => match ident.parse() {
1944 Ok(id) => ResolvedClusterName {
1945 id,
1946 print_name: None,
1947 },
1948 Err(e) => {
1949 self.status = Err(e.into());
1950 ResolvedClusterName {
1951 id: ClusterId::system(0).expect("0 is a valid ID"),
1954 print_name: None,
1955 }
1956 }
1957 },
1958 }
1959 }
1960
1961 fn fold_with_option_value(
1962 &mut self,
1963 node: mz_sql_parser::ast::WithOptionValue<Raw>,
1964 ) -> mz_sql_parser::ast::WithOptionValue<Aug> {
1965 use mz_sql_parser::ast::WithOptionValue::*;
1966 match node {
1967 Sequence(vs) => Sequence(
1968 vs.into_iter()
1969 .map(|v| self.fold_with_option_value(v))
1970 .collect(),
1971 ),
1972 Map(map) => Map(map
1973 .into_iter()
1974 .map(|(k, v)| (k, self.fold_with_option_value(v)))
1975 .collect()),
1976 Value(v) => Value(self.fold_value(v)),
1977 DataType(dt) => DataType(self.fold_data_type(dt)),
1978 Secret(secret) => {
1979 let item_name = self.fold_item_name(secret);
1980 match &item_name {
1981 ResolvedItemName::Item { id, .. } => {
1982 let item = self.catalog.get_item(id);
1983 if item.item_type() != CatalogItemType::Secret {
1984 self.status =
1985 Err(PlanError::InvalidSecret(Box::new(item_name.clone())));
1986 }
1987 }
1988 ResolvedItemName::Cte { .. } | ResolvedItemName::ContinualTask { .. } => {
1989 self.status = Err(PlanError::InvalidSecret(Box::new(item_name.clone())));
1990 }
1991 ResolvedItemName::Error => {}
1992 }
1993 Secret(item_name)
1994 }
1995 Item(obj) => {
1996 let item_name = self.fold_item_name(obj);
1997 match &item_name {
1998 ResolvedItemName::Item { .. } => {}
1999 ResolvedItemName::Cte { .. } | ResolvedItemName::ContinualTask { .. } => {
2000 self.status = Err(PlanError::InvalidObject(Box::new(item_name.clone())));
2001 }
2002 ResolvedItemName::Error => {}
2003 }
2004 Item(item_name)
2005 }
2006 UnresolvedItemName(name) => UnresolvedItemName(self.fold_unresolved_item_name(name)),
2007 Ident(name) => Ident(self.fold_ident(name)),
2008 Expr(e) => Expr(self.fold_expr(e)),
2009 ClusterReplicas(replicas) => ClusterReplicas(
2010 replicas
2011 .into_iter()
2012 .map(|r| self.fold_replica_definition(r))
2013 .collect(),
2014 ),
2015 ConnectionKafkaBroker(broker) => ConnectionKafkaBroker(self.fold_kafka_broker(broker)),
2016 ConnectionAwsPrivatelink(privatelink) => {
2017 ConnectionAwsPrivatelink(self.fold_connection_default_aws_privatelink(privatelink))
2018 }
2019 RetainHistoryFor(value) => RetainHistoryFor(self.fold_value(value)),
2020 Refresh(refresh) => Refresh(self.fold_refresh_option_value(refresh)),
2021 ClusterScheduleOptionValue(value) => ClusterScheduleOptionValue(value),
2022 ClusterAlterStrategy(value) => {
2023 ClusterAlterStrategy(self.fold_cluster_alter_option_value(value))
2024 }
2025 NetworkPolicyRules(rules) => NetworkPolicyRules(
2026 rules
2027 .into_iter()
2028 .map(|r| self.fold_network_policy_rule_definition(r))
2029 .collect(),
2030 ),
2031 }
2032 }
2033
2034 fn fold_role_name(&mut self, name: <Raw as AstInfo>::RoleName) -> <Aug as AstInfo>::RoleName {
2035 match self.catalog.resolve_role(name.as_str()) {
2036 Ok(role) => ResolvedRoleName {
2037 id: role.id(),
2038 name: role.name().to_string(),
2039 },
2040 Err(e) => {
2041 if self.status.is_ok() {
2042 self.status = Err(e.into());
2043 }
2044 ResolvedRoleName {
2046 id: RoleId::User(0),
2047 name: "".to_string(),
2048 }
2049 }
2050 }
2051 }
2052
2053 fn fold_network_policy_name(
2054 &mut self,
2055 name: <Raw as AstInfo>::NetworkPolicyName,
2056 ) -> <Aug as AstInfo>::NetworkPolicyName {
2057 match self.catalog.resolve_network_policy(&name.to_string()) {
2058 Ok(policy) => ResolvedNetworkPolicyName {
2059 id: policy.id(),
2060 name: policy.name().to_string(),
2061 },
2062 Err(e) => {
2063 if self.status.is_ok() {
2064 self.status = Err(e.into());
2065 }
2066 ResolvedNetworkPolicyName {
2068 id: NetworkPolicyId::User(0),
2069 name: "".to_string(),
2070 }
2071 }
2072 }
2073 }
2074
2075 fn fold_object_name(
2076 &mut self,
2077 name: <Raw as AstInfo>::ObjectName,
2078 ) -> <Aug as AstInfo>::ObjectName {
2079 match name {
2080 UnresolvedObjectName::Cluster(name) => ResolvedObjectName::Cluster(
2081 self.fold_cluster_name(RawClusterName::Unresolved(name)),
2082 ),
2083 UnresolvedObjectName::ClusterReplica(name) => {
2084 match self.catalog.resolve_cluster_replica(&name) {
2085 Ok(cluster_replica) => {
2086 ResolvedObjectName::ClusterReplica(ResolvedClusterReplicaName {
2087 cluster_id: cluster_replica.cluster_id(),
2088 replica_id: cluster_replica.replica_id(),
2089 })
2090 }
2091 Err(e) => {
2092 self.status = Err(e.into());
2093 ResolvedObjectName::ClusterReplica(ResolvedClusterReplicaName {
2094 cluster_id: ClusterId::system(0).expect("0 is a valid ID"),
2097 replica_id: ReplicaId::System(0),
2098 })
2099 }
2100 }
2101 }
2102 UnresolvedObjectName::Database(name) => {
2103 ResolvedObjectName::Database(self.fold_database_name(name))
2104 }
2105 UnresolvedObjectName::Schema(name) => {
2106 ResolvedObjectName::Schema(self.fold_schema_name(name))
2107 }
2108 UnresolvedObjectName::Role(name) => ResolvedObjectName::Role(self.fold_role_name(name)),
2109 UnresolvedObjectName::Item(name) => {
2110 ResolvedObjectName::Item(self.fold_item_name(RawItemName::Name(name)))
2111 }
2112 UnresolvedObjectName::NetworkPolicy(name) => ResolvedObjectName::NetworkPolicy(
2113 self.fold_network_policy_name(RawNetworkPolicyName::Unresolved(name)),
2114 ),
2115 }
2116 }
2117
2118 fn fold_function(
2119 &mut self,
2120 node: mz_sql_parser::ast::Function<Raw>,
2121 ) -> mz_sql_parser::ast::Function<Aug> {
2122 mz_ore::stack::maybe_grow(|| {
2125 mz_sql_parser::ast::Function {
2126 name: self.resolve_item_name(
2127 node.name,
2128 ItemResolutionConfig {
2131 functions: true,
2132 types: false,
2133 relations: false,
2134 },
2135 ),
2136 args: self.fold_function_args(node.args),
2137 filter: node.filter.map(|expr| Box::new(self.fold_expr(*expr))),
2138 over: node.over.map(|over| self.fold_window_spec(over)),
2139 distinct: node.distinct,
2140 }
2141 })
2142 }
2143
2144 fn fold_table_factor(
2145 &mut self,
2146 node: mz_sql_parser::ast::TableFactor<Raw>,
2147 ) -> mz_sql_parser::ast::TableFactor<Aug> {
2148 use mz_sql_parser::ast::TableFactor::*;
2149 match node {
2150 Table { name, alias } => Table {
2151 name: self.fold_item_name(name),
2152 alias: alias.map(|alias| self.fold_table_alias(alias)),
2153 },
2154 Function {
2155 function,
2156 alias,
2157 with_ordinality,
2158 } => {
2159 match &function.name {
2160 RawItemName::Name(name) => {
2161 if *name == UnresolvedItemName::unqualified(ident!("values"))
2162 && self.status.is_ok()
2163 {
2164 self.status = Err(PlanError::FromValueRequiresParen);
2165 }
2166 }
2167 _ => {}
2168 }
2169
2170 Function {
2171 function: self.fold_function(function),
2172 alias: alias.map(|alias| self.fold_table_alias(alias)),
2173 with_ordinality,
2174 }
2175 }
2176 RowsFrom {
2177 functions,
2178 alias,
2179 with_ordinality,
2180 } => RowsFrom {
2181 functions: functions
2182 .into_iter()
2183 .map(|f| self.fold_function(f))
2184 .collect(),
2185 alias: alias.map(|alias| self.fold_table_alias(alias)),
2186 with_ordinality,
2187 },
2188 Derived {
2189 lateral,
2190 subquery,
2191 alias,
2192 } => Derived {
2193 lateral,
2194 subquery: Box::new(self.fold_query(*subquery)),
2195 alias: alias.map(|alias| self.fold_table_alias(alias)),
2196 },
2197 NestedJoin { join, alias } => NestedJoin {
2198 join: Box::new(self.fold_table_with_joins(*join)),
2199 alias: alias.map(|alias| self.fold_table_alias(alias)),
2200 },
2201 }
2202 }
2203
2204 fn fold_grant_target_specification(
2205 &mut self,
2206 node: GrantTargetSpecification<Raw>,
2207 ) -> GrantTargetSpecification<Aug> {
2208 match node {
2209 GrantTargetSpecification::Object {
2210 object_type: ObjectType::Type,
2211 object_spec_inner: GrantTargetSpecificationInner::Objects { names },
2212 } => GrantTargetSpecification::Object {
2213 object_type: ObjectType::Type,
2214 object_spec_inner: GrantTargetSpecificationInner::Objects {
2215 names: names
2216 .into_iter()
2217 .map(|name| match name {
2218 UnresolvedObjectName::Item(name) => {
2219 ResolvedObjectName::Item(self.resolve_item_name_name(
2220 name,
2221 ItemResolutionConfig {
2224 functions: false,
2225 types: true,
2226 relations: false,
2227 },
2228 ))
2229 }
2230 _ => self.fold_object_name(name),
2231 })
2232 .collect(),
2233 },
2234 },
2235 _ => mz_sql_parser::ast::fold::fold_grant_target_specification(self, node),
2236 }
2237 }
2238
2239 fn fold_doc_on_identifier(&mut self, node: DocOnIdentifier<Raw>) -> DocOnIdentifier<Aug> {
2240 match node {
2241 DocOnIdentifier::Column(name) => DocOnIdentifier::Column(self.fold_column_name(name)),
2242 DocOnIdentifier::Type(name) => DocOnIdentifier::Type(self.resolve_item_name(
2243 name,
2244 ItemResolutionConfig {
2250 functions: false,
2251 types: true,
2252 relations: true,
2253 },
2254 )),
2255 }
2256 }
2257
2258 fn fold_expr(&mut self, node: Expr<Raw>) -> Expr<Aug> {
2259 mz_ore::stack::maybe_grow(|| mz_sql_parser::ast::fold::fold_expr(self, node))
2261 }
2262}
2263
2264#[mz_ore::instrument(target = "compiler", level = "trace", name = "ast_resolve_names")]
2266pub fn resolve<N>(
2267 catalog: &dyn SessionCatalog,
2268 node: N,
2269) -> Result<(N::Folded, ResolvedIds), PlanError>
2270where
2271 N: FoldNode<Raw, Aug>,
2272{
2273 let mut resolver = NameResolver::new(catalog);
2274 let result = node.fold(&mut resolver);
2275 resolver.status?;
2276 Ok((result, ResolvedIds::new(resolver.ids)))
2277}
2278
2279#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
2284pub struct ResolvedIds {
2285 #[serde(serialize_with = "mz_ore::serde::map_key_to_string")]
2286 entries: BTreeMap<CatalogItemId, BTreeSet<GlobalId>>,
2287}
2288
2289impl ResolvedIds {
2290 fn new(entries: BTreeMap<CatalogItemId, BTreeSet<GlobalId>>) -> Self {
2291 ResolvedIds { entries }
2292 }
2293
2294 pub fn empty() -> Self {
2296 ResolvedIds {
2297 entries: BTreeMap::new(),
2298 }
2299 }
2300
2301 pub fn is_empty(&self) -> bool {
2303 self.entries.is_empty()
2304 }
2305
2306 pub fn collections(&self) -> impl Iterator<Item = &GlobalId> {
2308 self.entries.values().flat_map(|gids| gids.into_iter())
2309 }
2310
2311 pub fn items(&self) -> impl Iterator<Item = &CatalogItemId> {
2313 self.entries.keys()
2314 }
2315
2316 pub fn contains_item(&self, item: &CatalogItemId) -> bool {
2318 self.entries.contains_key(item)
2319 }
2320
2321 pub fn add_item(&mut self, item: CatalogItemId) {
2322 self.entries.insert(item, BTreeSet::new());
2323 }
2324
2325 pub fn remove_item(&mut self, item: &CatalogItemId) {
2326 self.entries.remove(item);
2327 }
2328
2329 pub fn retain_items<F>(&self, predicate: F) -> Self
2332 where
2333 F: Fn(&CatalogItemId) -> bool,
2334 {
2335 let mut new_ids = self.clone();
2336 new_ids
2337 .entries
2338 .retain(|item_id, _global_ids| predicate(item_id));
2339 new_ids
2340 }
2341}
2342
2343impl FromIterator<(CatalogItemId, GlobalId)> for ResolvedIds {
2344 fn from_iter<T: IntoIterator<Item = (CatalogItemId, GlobalId)>>(iter: T) -> Self {
2345 let mut ids = ResolvedIds::empty();
2346 ids.extend(iter);
2347 ids
2348 }
2349}
2350
2351impl Extend<(CatalogItemId, GlobalId)> for ResolvedIds {
2352 fn extend<T: IntoIterator<Item = (CatalogItemId, GlobalId)>>(&mut self, iter: T) {
2353 for (item_id, global_id) in iter {
2354 self.entries.entry(item_id).or_default().insert(global_id);
2355 }
2356 }
2357}
2358
2359#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
2361pub struct DependencyIds(pub BTreeSet<CatalogItemId>);
2362
2363impl FromIterator<CatalogItemId> for DependencyIds {
2364 fn from_iter<T: IntoIterator<Item = CatalogItemId>>(iter: T) -> Self {
2365 DependencyIds(iter.into_iter().collect())
2366 }
2367}
2368
2369#[derive(Debug)]
2370pub struct DependencyVisitor<'a> {
2371 catalog: &'a dyn SessionCatalog,
2372 ids: BTreeMap<CatalogItemId, BTreeSet<GlobalId>>,
2373}
2374
2375impl<'a> DependencyVisitor<'a> {
2376 pub fn new(catalog: &'a dyn SessionCatalog) -> Self {
2377 DependencyVisitor {
2378 catalog,
2379 ids: Default::default(),
2380 }
2381 }
2382}
2383
2384impl<'a, 'ast> Visit<'ast, Aug> for DependencyVisitor<'a> {
2385 fn visit_item_name(&mut self, item_name: &'ast <Aug as AstInfo>::ItemName) {
2386 if let ResolvedItemName::Item { id, version, .. } = item_name {
2387 let global_ids = self.ids.entry(*id).or_default();
2388 if let Some(item) = self.catalog.try_get_item(id) {
2389 global_ids.insert(item.at_version(*version).global_id());
2390 }
2391 }
2392 }
2393
2394 fn visit_data_type(&mut self, data_type: &'ast <Aug as AstInfo>::DataType) {
2395 match data_type {
2396 ResolvedDataType::AnonymousList(data_type) => self.visit_data_type(data_type),
2397 ResolvedDataType::AnonymousMap {
2398 key_type,
2399 value_type,
2400 } => {
2401 self.visit_data_type(key_type);
2402 self.visit_data_type(value_type);
2403 }
2404 ResolvedDataType::Named { id, .. } => {
2405 self.ids.entry(*id).or_default();
2406 }
2407 ResolvedDataType::Error => {}
2408 }
2409 }
2410}
2411
2412pub fn visit_dependencies<'ast, N>(catalog: &dyn SessionCatalog, node: &'ast N) -> ResolvedIds
2413where
2414 N: VisitNode<'ast, Aug> + 'ast,
2415{
2416 let mut visitor = DependencyVisitor::new(catalog);
2417 node.visit(&mut visitor);
2418 ResolvedIds::new(visitor.ids)
2419}
2420
2421#[derive(Debug)]
2422pub struct ItemDependencyModifier<'a> {
2423 pub modified: bool,
2424 pub id_map: &'a BTreeMap<CatalogItemId, CatalogItemId>,
2425}
2426
2427impl<'ast, 'a> VisitMut<'ast, Raw> for ItemDependencyModifier<'a> {
2428 fn visit_item_name_mut(&mut self, item_name: &mut RawItemName) {
2429 if let RawItemName::Id(id, _, _) = item_name {
2430 let parsed_id = id.parse::<CatalogItemId>().unwrap();
2431 if let Some(new_id) = self.id_map.get(&parsed_id) {
2432 *id = new_id.to_string();
2433 self.modified = true;
2434 }
2435 }
2436 }
2437}
2438
2439pub fn modify_dependency_item_ids<'ast, N>(
2444 node: &'ast mut N,
2445 id_map: &BTreeMap<CatalogItemId, CatalogItemId>,
2446) -> bool
2447where
2448 N: VisitMutNode<'ast, Raw>,
2449{
2450 let mut modifier = ItemDependencyModifier {
2451 id_map,
2452 modified: false,
2453 };
2454 node.visit_mut(&mut modifier);
2455
2456 modifier.modified
2457}
2458
2459#[derive(Debug)]
2462pub struct NameSimplifier<'a> {
2463 pub catalog: &'a dyn SessionCatalog,
2464}
2465
2466impl<'ast, 'a> VisitMut<'ast, Aug> for NameSimplifier<'a> {
2467 fn visit_cluster_name_mut(&mut self, node: &mut ResolvedClusterName) {
2468 node.print_name = Some(self.catalog.get_cluster(node.id).name().into());
2469 }
2470
2471 fn visit_item_name_mut(&mut self, name: &mut ResolvedItemName) {
2472 if let ResolvedItemName::Item {
2473 id,
2474 full_name,
2475 print_id,
2476 ..
2477 } = name
2478 {
2479 let item = self.catalog.get_item(id);
2480 let catalog_full_name = self.catalog.resolve_full_name(item.name());
2481 if catalog_full_name == *full_name {
2482 *print_id = false;
2483 }
2484 }
2485 }
2486
2487 fn visit_data_type_mut(&mut self, name: &mut ResolvedDataType) {
2488 if let ResolvedDataType::Named {
2489 id,
2490 full_name,
2491 print_id,
2492 ..
2493 } = name
2494 {
2495 let item = self.catalog.get_item(id);
2496 let catalog_full_name = self.catalog.resolve_full_name(item.name());
2497 if catalog_full_name == *full_name {
2498 *print_id = false;
2499 }
2500 }
2501 }
2502}
2503
2504pub fn dependencies<'ast, N>(node: &'ast N) -> Result<BTreeSet<CatalogItemId>, anyhow::Error>
2509where
2510 N: VisitNode<'ast, Raw>,
2511{
2512 let mut visitor = IdDependencVisitor::default();
2513 node.visit(&mut visitor);
2514 match visitor.error {
2515 Some(error) => Err(error),
2516 None => Ok(visitor.ids),
2517 }
2518}
2519
2520#[derive(Debug, Default)]
2521struct IdDependencVisitor {
2522 ids: BTreeSet<CatalogItemId>,
2523 error: Option<anyhow::Error>,
2524}
2525
2526impl<'ast> Visit<'ast, Raw> for IdDependencVisitor {
2527 fn visit_item_name(&mut self, node: &'ast <Raw as AstInfo>::ItemName) {
2528 if self.error.is_some() {
2530 return;
2531 }
2532
2533 match node {
2534 RawItemName::Name(_) => (),
2536 RawItemName::Id(id, _name, _version) => match id.parse::<CatalogItemId>() {
2537 Ok(id) => {
2538 self.ids.insert(id);
2539 }
2540 Err(e) => {
2541 self.error = Some(e);
2542 }
2543 },
2544 }
2545 }
2546}