1#![warn(missing_docs)]
11
12use std::borrow::Cow;
15use std::collections::{BTreeMap, BTreeSet};
16use std::error::Error;
17use std::fmt;
18use std::fmt::{Debug, Display, Formatter};
19use std::num::NonZeroU32;
20use std::str::FromStr;
21use std::sync::LazyLock;
22use std::time::Instant;
23
24use chrono::{DateTime, Utc};
25use mz_auth::password::Password;
26use mz_build_info::BuildInfo;
27use mz_cloud_provider::{CloudProvider, InvalidCloudProviderError};
28use mz_controller_types::{ClusterId, ReplicaId};
29use mz_expr::MirScalarExpr;
30use mz_ore::now::{EpochMillis, NowFn};
31use mz_ore::str::StrExt;
32use mz_repr::adt::mz_acl_item::{AclMode, MzAclItem, PrivilegeMap};
33use mz_repr::explain::ExprHumanizer;
34use mz_repr::network_policy_id::NetworkPolicyId;
35use mz_repr::role_id::RoleId;
36use mz_repr::{
37 CatalogItemId, ColumnName, GlobalId, RelationDesc, RelationVersion, RelationVersionSelector,
38};
39use mz_sql_parser::ast::{Expr, QualifiedReplica, UnresolvedItemName};
40use mz_storage_types::connections::inline::{ConnectionResolver, ReferencedConnection};
41use mz_storage_types::connections::{Connection, ConnectionContext};
42use mz_storage_types::sources::{SourceDesc, SourceExportDataConfig, SourceExportDetails};
43use proptest_derive::Arbitrary;
44use regex::Regex;
45use serde::{Deserialize, Serialize};
46use uuid::Uuid;
47
48use crate::func::Func;
49use crate::names::{
50 Aug, CommentObjectId, DatabaseId, FullItemName, FullSchemaName, ObjectId, PartialItemName,
51 QualifiedItemName, QualifiedSchemaName, ResolvedDatabaseSpecifier, ResolvedIds, SchemaId,
52 SchemaSpecifier, SystemObjectId,
53};
54use crate::plan::statement::StatementDesc;
55use crate::plan::statement::ddl::PlannedRoleAttributes;
56use crate::plan::{
57 AutoScalingStrategy, ClusterSchedule, CreateClusterPlan, PlanError, PlanNotice, query,
58};
59use crate::session::vars::{OwnedVarInput, SystemVars};
60
61pub trait SessionCatalog: fmt::Debug + ExprHumanizer + Send + Sync + ConnectionResolver {
90 fn active_role_id(&self) -> &RoleId;
92
93 fn active_database_name(&self) -> Option<&str> {
95 self.active_database()
96 .map(|id| self.get_database(id))
97 .map(|db| db.name())
98 }
99
100 fn active_database(&self) -> Option<&DatabaseId>;
102
103 fn active_cluster(&self) -> &str;
105
106 fn search_path(&self) -> &[(ResolvedDatabaseSpecifier, SchemaSpecifier)];
108
109 fn get_prepared_statement_desc(&self, name: &str) -> Option<&StatementDesc>;
112
113 fn get_portal_desc_unverified(&self, portal_name: &str) -> Option<&StatementDesc>;
117
118 fn resolve_database(&self, database_name: &str) -> Result<&dyn CatalogDatabase, CatalogError>;
123
124 fn get_database(&self, id: &DatabaseId) -> &dyn CatalogDatabase;
128
129 fn get_databases(&self) -> Vec<&dyn CatalogDatabase>;
131
132 fn resolve_schema(
137 &self,
138 database_name: Option<&str>,
139 schema_name: &str,
140 ) -> Result<&dyn CatalogSchema, CatalogError>;
141
142 fn resolve_schema_in_database(
147 &self,
148 database_spec: &ResolvedDatabaseSpecifier,
149 schema_name: &str,
150 ) -> Result<&dyn CatalogSchema, CatalogError>;
151
152 fn get_schema(
156 &self,
157 database_spec: &ResolvedDatabaseSpecifier,
158 schema_spec: &SchemaSpecifier,
159 ) -> &dyn CatalogSchema;
160
161 fn get_schemas(&self) -> Vec<&dyn CatalogSchema>;
163
164 fn get_mz_internal_schema_id(&self) -> SchemaId;
166
167 fn get_mz_unsafe_schema_id(&self) -> SchemaId;
169
170 fn is_system_schema_specifier(&self, schema: SchemaSpecifier) -> bool;
172
173 fn resolve_role(&self, role_name: &str) -> Result<&dyn CatalogRole, CatalogError>;
175
176 fn resolve_network_policy(
178 &self,
179 network_policy_name: &str,
180 ) -> Result<&dyn CatalogNetworkPolicy, CatalogError>;
181
182 fn try_get_role(&self, id: &RoleId) -> Option<&dyn CatalogRole>;
184
185 fn get_role(&self, id: &RoleId) -> &dyn CatalogRole;
189
190 fn get_roles(&self) -> Vec<&dyn CatalogRole>;
192
193 fn mz_system_role_id(&self) -> RoleId;
195
196 fn collect_role_membership(&self, id: &RoleId) -> BTreeSet<RoleId>;
198
199 fn get_network_policy(&self, id: &NetworkPolicyId) -> &dyn CatalogNetworkPolicy;
204
205 fn get_network_policies(&self) -> Vec<&dyn CatalogNetworkPolicy>;
207
208 fn resolve_cluster<'a, 'b>(
211 &'a self,
212 cluster_name: Option<&'b str>,
213 ) -> Result<&'a dyn CatalogCluster<'a>, CatalogError>;
214
215 fn resolve_cluster_replica<'a, 'b>(
217 &'a self,
218 cluster_replica_name: &'b QualifiedReplica,
219 ) -> Result<&'a dyn CatalogClusterReplica<'a>, CatalogError>;
220
221 fn resolve_item(&self, item_name: &PartialItemName) -> Result<&dyn CatalogItem, CatalogError>;
236
237 fn resolve_function(
240 &self,
241 item_name: &PartialItemName,
242 ) -> Result<&dyn CatalogItem, CatalogError>;
243
244 fn resolve_type(&self, item_name: &PartialItemName) -> Result<&dyn CatalogItem, CatalogError>;
247
248 fn resolve_item_or_type(
250 &self,
251 name: &PartialItemName,
252 ) -> Result<&dyn CatalogItem, CatalogError> {
253 if let Ok(ty) = self.resolve_type(name) {
254 return Ok(ty);
255 }
256 self.resolve_item(name)
257 }
258
259 fn get_system_type(&self, name: &str) -> &dyn CatalogItem;
265
266 fn try_get_item(&self, id: &CatalogItemId) -> Option<&dyn CatalogItem>;
268
269 fn try_get_item_by_global_id<'a>(
274 &'a self,
275 id: &GlobalId,
276 ) -> Option<Box<dyn CatalogCollectionItem + 'a>>;
277
278 fn get_item(&self, id: &CatalogItemId) -> &dyn CatalogItem;
282
283 fn get_item_by_global_id<'a>(&'a self, id: &GlobalId) -> Box<dyn CatalogCollectionItem + 'a>;
289
290 fn get_items(&self) -> Vec<&dyn CatalogItem>;
292
293 fn get_item_by_name(&self, name: &QualifiedItemName) -> Option<&dyn CatalogItem>;
295
296 fn get_type_by_name(&self, name: &QualifiedItemName) -> Option<&dyn CatalogItem>;
298
299 fn get_cluster(&self, id: ClusterId) -> &dyn CatalogCluster<'_>;
301
302 fn get_clusters(&self) -> Vec<&dyn CatalogCluster<'_>>;
304
305 fn get_cluster_replica(
307 &self,
308 cluster_id: ClusterId,
309 replica_id: ReplicaId,
310 ) -> &dyn CatalogClusterReplica<'_>;
311
312 fn get_cluster_replicas(&self) -> Vec<&dyn CatalogClusterReplica<'_>>;
314
315 fn get_system_privileges(&self) -> &PrivilegeMap;
317
318 fn get_default_privileges(
320 &self,
321 ) -> Vec<(&DefaultPrivilegeObject, Vec<&DefaultPrivilegeAclItem>)>;
322
323 fn find_available_name(&self, name: QualifiedItemName) -> QualifiedItemName;
327
328 fn resolve_full_name(&self, name: &QualifiedItemName) -> FullItemName;
330
331 fn resolve_full_schema_name(&self, name: &QualifiedSchemaName) -> FullSchemaName;
334
335 fn resolve_item_id(&self, global_id: &GlobalId) -> CatalogItemId;
337
338 fn resolve_global_id(
340 &self,
341 item_id: &CatalogItemId,
342 version: RelationVersionSelector,
343 ) -> GlobalId;
344
345 fn config(&self) -> &CatalogConfig;
347
348 fn now(&self) -> EpochMillis;
352
353 fn aws_privatelink_availability_zones(&self) -> Option<BTreeSet<String>>;
355
356 fn restrict_to_user_objects(&self) -> bool {
361 false
362 }
363
364 fn system_vars(&self) -> &SystemVars;
366
367 fn system_vars_mut(&mut self) -> &mut SystemVars;
374
375 fn get_owner_id(&self, id: &ObjectId) -> Option<RoleId>;
377
378 fn get_privileges(&self, id: &SystemObjectId) -> Option<&PrivilegeMap>;
380
381 fn object_dependents(&self, ids: &Vec<ObjectId>) -> Vec<ObjectId>;
387
388 fn item_dependents(&self, id: CatalogItemId) -> Vec<ObjectId>;
394
395 fn all_object_privileges(&self, object_type: SystemObjectType) -> AclMode;
397
398 fn get_object_type(&self, object_id: &ObjectId) -> ObjectType;
400
401 fn get_system_object_type(&self, id: &SystemObjectId) -> SystemObjectType;
403
404 fn minimal_qualification(&self, qualified_name: &QualifiedItemName) -> PartialItemName;
407
408 fn add_notice(&self, notice: PlanNotice);
411
412 fn get_item_comments(&self, id: &CatalogItemId) -> Option<&BTreeMap<Option<usize>, String>>;
414
415 fn is_cluster_size_cc(&self, size: &str) -> bool;
418}
419
420#[derive(Debug, Clone)]
422pub struct CatalogConfig {
423 pub start_time: DateTime<Utc>,
425 pub start_instant: Instant,
427 pub nonce: u64,
432 pub environment_id: EnvironmentId,
434 pub session_id: Uuid,
436 pub build_info: &'static BuildInfo,
438 pub now: NowFn,
441 pub connection_context: ConnectionContext,
443 pub aws_account_id: Option<String>,
452 pub helm_chart_version: Option<String>,
454}
455
456pub trait CatalogDatabase {
458 fn name(&self) -> &str;
460
461 fn id(&self) -> DatabaseId;
463
464 fn has_schemas(&self) -> bool;
466
467 fn schema_ids(&self) -> &BTreeMap<String, SchemaId>;
470
471 fn schemas(&self) -> Vec<&dyn CatalogSchema>;
473
474 fn owner_id(&self) -> RoleId;
476
477 fn privileges(&self) -> &PrivilegeMap;
479}
480
481pub trait CatalogSchema {
483 fn database(&self) -> &ResolvedDatabaseSpecifier;
485
486 fn name(&self) -> &QualifiedSchemaName;
488
489 fn id(&self) -> &SchemaSpecifier;
491
492 fn has_items(&self) -> bool;
494
495 fn item_ids(&self) -> Box<dyn Iterator<Item = CatalogItemId> + '_>;
497
498 fn owner_id(&self) -> RoleId;
500
501 fn privileges(&self) -> &PrivilegeMap;
503}
504
505#[derive(Debug, Clone, Eq, PartialEq, Arbitrary)]
507pub struct PasswordConfig {
508 pub password: Password,
510 pub scram_iterations: NonZeroU32,
512}
513
514#[derive(Debug, Clone, Eq, PartialEq, Arbitrary)]
516pub enum PasswordAction {
517 Set(PasswordConfig),
519 Clear,
521 NoChange,
523}
524
525#[derive(
527 Debug,
528 Copy,
529 Clone,
530 Eq,
531 PartialEq,
532 Ord,
533 PartialOrd,
534 Serialize,
535 Deserialize,
536 Arbitrary
537)]
538pub enum AutoProvisionSource {
539 Oidc,
541 Frontegg,
543 None,
545}
546
547#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Arbitrary)]
552pub struct RoleAttributesRaw {
553 pub inherit: bool,
555 pub password: Option<Password>,
557 pub scram_iterations: Option<NonZeroU32>,
559 pub superuser: Option<bool>,
561 pub login: Option<bool>,
563 pub auto_provision_source: Option<AutoProvisionSource>,
565 _private: (),
567}
568
569#[derive(
571 Debug,
572 Clone,
573 Eq,
574 Serialize,
575 Deserialize,
576 PartialEq,
577 Ord,
578 PartialOrd,
579 Arbitrary
580)]
581pub struct RoleAttributes {
582 pub inherit: bool,
584 pub superuser: Option<bool>,
586 pub login: Option<bool>,
588 pub auto_provision_source: Option<AutoProvisionSource>,
590 _private: (),
592}
593
594impl RoleAttributesRaw {
595 pub const fn new() -> RoleAttributesRaw {
597 RoleAttributesRaw {
598 inherit: true,
599 password: None,
600 scram_iterations: None,
601 superuser: None,
602 login: None,
603 auto_provision_source: None,
604 _private: (),
605 }
606 }
607
608 pub const fn with_all(mut self) -> RoleAttributesRaw {
610 self.inherit = true;
611 self.superuser = Some(true);
612 self.login = Some(true);
613 self
614 }
615}
616
617impl RoleAttributes {
618 pub const fn new() -> RoleAttributes {
620 RoleAttributes {
621 inherit: true,
622 superuser: None,
623 login: None,
624 auto_provision_source: None,
625 _private: (),
626 }
627 }
628
629 pub const fn with_all(mut self) -> RoleAttributes {
631 self.inherit = true;
632 self.superuser = Some(true);
633 self.login = Some(true);
634 self
635 }
636
637 pub const fn is_inherit(&self) -> bool {
639 self.inherit
640 }
641}
642
643impl From<RoleAttributesRaw> for RoleAttributes {
644 fn from(
645 RoleAttributesRaw {
646 inherit,
647 superuser,
648 login,
649 auto_provision_source,
650 ..
651 }: RoleAttributesRaw,
652 ) -> RoleAttributes {
653 RoleAttributes {
654 inherit,
655 superuser,
656 login,
657 auto_provision_source,
658 _private: (),
659 }
660 }
661}
662
663impl From<RoleAttributes> for RoleAttributesRaw {
664 fn from(
665 RoleAttributes {
666 inherit,
667 superuser,
668 login,
669 auto_provision_source,
670 ..
671 }: RoleAttributes,
672 ) -> RoleAttributesRaw {
673 RoleAttributesRaw {
674 inherit,
675 password: None,
676 scram_iterations: None,
677 superuser,
678 login,
679 auto_provision_source,
680 _private: (),
681 }
682 }
683}
684
685impl From<PlannedRoleAttributes> for RoleAttributesRaw {
686 fn from(
687 PlannedRoleAttributes {
688 inherit,
689 password,
690 scram_iterations,
691 superuser,
692 login,
693 ..
694 }: PlannedRoleAttributes,
695 ) -> RoleAttributesRaw {
696 let default_attributes = RoleAttributesRaw::new();
697 RoleAttributesRaw {
698 inherit: inherit.unwrap_or(default_attributes.inherit),
699 password,
700 scram_iterations,
701 superuser,
702 login,
703 auto_provision_source: None,
704 _private: (),
705 }
706 }
707}
708
709#[derive(Default, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize)]
711pub struct RoleVars {
712 pub map: BTreeMap<String, OwnedVarInput>,
714}
715
716pub trait CatalogRole {
718 fn name(&self) -> &str;
720
721 fn id(&self) -> RoleId;
723
724 fn membership(&self) -> &BTreeMap<RoleId, RoleId>;
729
730 fn attributes(&self) -> &RoleAttributes;
732
733 fn vars(&self) -> &BTreeMap<String, OwnedVarInput>;
735}
736
737pub trait CatalogNetworkPolicy {
739 fn name(&self) -> &str;
741
742 fn id(&self) -> NetworkPolicyId;
744
745 fn owner_id(&self) -> RoleId;
747
748 fn privileges(&self) -> &PrivilegeMap;
750}
751
752pub trait CatalogCluster<'a> {
754 fn name(&self) -> &str;
756
757 fn id(&self) -> ClusterId;
759
760 fn bound_objects(&self) -> &BTreeSet<CatalogItemId>;
762
763 fn replica_ids(&self) -> &BTreeMap<String, ReplicaId>;
766
767 fn replicas(&self) -> Vec<&dyn CatalogClusterReplica<'_>>;
769
770 fn replica(&self, id: ReplicaId) -> &dyn CatalogClusterReplica<'_>;
772
773 fn owner_id(&self) -> RoleId;
775
776 fn privileges(&self) -> &PrivilegeMap;
778
779 fn is_managed(&self) -> bool;
781
782 fn managed_size(&self) -> Option<&str>;
784
785 fn schedule(&self) -> Option<&ClusterSchedule>;
787
788 fn replication_factor(&self) -> Option<u32>;
790
791 fn auto_scaling_strategy(&self) -> Option<&AutoScalingStrategy>;
794 fn try_to_plan(&self) -> Result<CreateClusterPlan, PlanError>;
797}
798
799pub trait CatalogClusterReplica<'a>: Debug {
801 fn name(&self) -> &str;
803
804 fn cluster_id(&self) -> ClusterId;
806
807 fn replica_id(&self) -> ReplicaId;
809
810 fn owner_id(&self) -> RoleId;
812
813 fn internal(&self) -> bool;
815}
816
817pub trait CatalogItem {
822 fn name(&self) -> &QualifiedItemName;
824
825 fn id(&self) -> CatalogItemId;
827
828 fn global_ids(&self) -> Box<dyn Iterator<Item = GlobalId> + '_>;
830
831 fn oid(&self) -> u32;
833
834 fn func(&self) -> Result<&'static Func, CatalogError>;
839
840 fn source_desc(&self) -> Result<Option<&SourceDesc<ReferencedConnection>>, CatalogError>;
845
846 fn connection(&self) -> Result<Connection<ReferencedConnection>, CatalogError>;
850
851 fn item_type(&self) -> CatalogItemType;
853
854 fn create_sql(&self) -> &str;
857
858 fn references(&self) -> &ResolvedIds;
861
862 fn uses(&self) -> BTreeSet<CatalogItemId>;
865
866 fn referenced_by(&self) -> &[CatalogItemId];
868
869 fn used_by(&self) -> &[CatalogItemId];
871
872 fn subsource_details(
875 &self,
876 ) -> Option<(CatalogItemId, &UnresolvedItemName, &SourceExportDetails)>;
877
878 fn source_export_details(
881 &self,
882 ) -> Option<(
883 CatalogItemId,
884 &UnresolvedItemName,
885 &SourceExportDetails,
886 &SourceExportDataConfig<ReferencedConnection>,
887 )>;
888
889 fn is_progress_source(&self) -> bool;
891
892 fn progress_id(&self) -> Option<CatalogItemId>;
894
895 fn index_details(&self) -> Option<(&[MirScalarExpr], GlobalId)>;
898
899 fn writable_table_details(&self) -> Option<&[Expr<Aug>]>;
902
903 fn replacement_target(&self) -> Option<CatalogItemId>;
905
906 fn type_details(&self) -> Option<&CatalogTypeDetails<IdReference>>;
909
910 fn owner_id(&self) -> RoleId;
912
913 fn privileges(&self) -> &PrivilegeMap;
915
916 fn cluster_id(&self) -> Option<ClusterId>;
918
919 fn at_version(&self, version: RelationVersionSelector) -> Box<dyn CatalogCollectionItem>;
922
923 fn latest_version(&self) -> Option<RelationVersion>;
925}
926
927pub trait CatalogCollectionItem: CatalogItem + Send + Sync {
930 fn relation_desc(&self) -> Option<Cow<'_, RelationDesc>>;
935
936 fn global_id(&self) -> GlobalId;
938}
939
940#[derive(
942 Debug,
943 Deserialize,
944 Clone,
945 Copy,
946 Eq,
947 Hash,
948 Ord,
949 PartialEq,
950 PartialOrd,
951 Serialize
952)]
953pub enum CatalogItemType {
954 Table,
956 Source,
958 Sink,
960 View,
962 MaterializedView,
964 Index,
966 Type,
968 Func,
970 Secret,
972 Connection,
974 MetricSink,
976}
977
978impl CatalogItemType {
979 pub fn conflicts_with_type(&self) -> bool {
998 match self {
999 CatalogItemType::Table => true,
1000 CatalogItemType::Source => true,
1001 CatalogItemType::View => true,
1002 CatalogItemType::MaterializedView => true,
1003 CatalogItemType::Index => true,
1004 CatalogItemType::Type => true,
1005 CatalogItemType::Sink => false,
1006 CatalogItemType::Func => false,
1007 CatalogItemType::Secret => false,
1008 CatalogItemType::Connection => false,
1009 CatalogItemType::MetricSink => false,
1010 }
1011 }
1012}
1013
1014impl fmt::Display for CatalogItemType {
1015 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1016 match self {
1017 CatalogItemType::Table => f.write_str("table"),
1018 CatalogItemType::Source => f.write_str("source"),
1019 CatalogItemType::Sink => f.write_str("sink"),
1020 CatalogItemType::View => f.write_str("view"),
1021 CatalogItemType::MaterializedView => f.write_str("materialized view"),
1022 CatalogItemType::Index => f.write_str("index"),
1023 CatalogItemType::Type => f.write_str("type"),
1024 CatalogItemType::Func => f.write_str("func"),
1025 CatalogItemType::Secret => f.write_str("secret"),
1026 CatalogItemType::Connection => f.write_str("connection"),
1027 CatalogItemType::MetricSink => f.write_str("metric sink"),
1028 }
1029 }
1030}
1031
1032impl From<CatalogItemType> for ObjectType {
1033 fn from(value: CatalogItemType) -> Self {
1034 match value {
1035 CatalogItemType::Table => ObjectType::Table,
1036 CatalogItemType::Source => ObjectType::Source,
1037 CatalogItemType::Sink => ObjectType::Sink,
1038 CatalogItemType::View => ObjectType::View,
1039 CatalogItemType::MaterializedView => ObjectType::MaterializedView,
1040 CatalogItemType::Index => ObjectType::Index,
1041 CatalogItemType::Type => ObjectType::Type,
1042 CatalogItemType::Func => ObjectType::Func,
1043 CatalogItemType::Secret => ObjectType::Secret,
1044 CatalogItemType::Connection => ObjectType::Connection,
1045 CatalogItemType::MetricSink => ObjectType::MetricSink,
1046 }
1047 }
1048}
1049
1050impl From<CatalogItemType> for mz_audit_log::ObjectType {
1051 fn from(value: CatalogItemType) -> Self {
1052 match value {
1053 CatalogItemType::Table => mz_audit_log::ObjectType::Table,
1054 CatalogItemType::Source => mz_audit_log::ObjectType::Source,
1055 CatalogItemType::View => mz_audit_log::ObjectType::View,
1056 CatalogItemType::MaterializedView => mz_audit_log::ObjectType::MaterializedView,
1057 CatalogItemType::Index => mz_audit_log::ObjectType::Index,
1058 CatalogItemType::Type => mz_audit_log::ObjectType::Type,
1059 CatalogItemType::Sink => mz_audit_log::ObjectType::Sink,
1060 CatalogItemType::Func => mz_audit_log::ObjectType::Func,
1061 CatalogItemType::Secret => mz_audit_log::ObjectType::Secret,
1062 CatalogItemType::Connection => mz_audit_log::ObjectType::Connection,
1063 CatalogItemType::MetricSink => mz_audit_log::ObjectType::MetricSink,
1064 }
1065 }
1066}
1067
1068#[derive(Clone, Debug, Eq, PartialEq)]
1070pub struct CatalogTypeDetails<T: TypeReference> {
1071 pub array_id: Option<CatalogItemId>,
1073 pub typ: CatalogType<T>,
1075 pub pg_metadata: Option<CatalogTypePgMetadata>,
1077}
1078
1079#[derive(Clone, Debug, Eq, PartialEq)]
1081pub struct CatalogTypePgMetadata {
1082 pub typinput_oid: u32,
1084 pub typreceive_oid: u32,
1086 pub typsend_oid: u32,
1088}
1089
1090pub trait TypeReference {
1092 type Reference: Clone + Debug + Eq + PartialEq;
1094}
1095
1096#[derive(Clone, Debug, Eq, PartialEq)]
1098pub struct NameReference;
1099
1100impl TypeReference for NameReference {
1101 type Reference = &'static str;
1102}
1103
1104#[derive(Clone, Debug, Eq, PartialEq)]
1106pub struct IdReference;
1107
1108impl TypeReference for IdReference {
1109 type Reference = CatalogItemId;
1110}
1111
1112#[allow(missing_docs)]
1118#[derive(Clone, Debug, Eq, PartialEq)]
1119pub enum CatalogType<T: TypeReference> {
1120 AclItem,
1121 Array {
1122 element_reference: T::Reference,
1123 },
1124 Bool,
1125 Bytes,
1126 Char,
1127 Date,
1128 Float32,
1129 Float64,
1130 Int16,
1131 Int32,
1132 Int64,
1133 UInt16,
1134 UInt32,
1135 UInt64,
1136 MzTimestamp,
1137 Interval,
1138 Jsonb,
1139 List {
1140 element_reference: T::Reference,
1141 element_modifiers: Vec<i64>,
1142 },
1143 Map {
1144 key_reference: T::Reference,
1145 key_modifiers: Vec<i64>,
1146 value_reference: T::Reference,
1147 value_modifiers: Vec<i64>,
1148 },
1149 Numeric,
1150 Oid,
1151 PgLegacyChar,
1152 PgLegacyName,
1153 Pseudo,
1154 Range {
1155 element_reference: T::Reference,
1156 },
1157 Record {
1158 fields: Vec<CatalogRecordField<T>>,
1159 },
1160 RegClass,
1161 RegProc,
1162 RegType,
1163 String,
1164 Time,
1165 Timestamp,
1166 TimestampTz,
1167 Uuid,
1168 VarChar,
1169 Int2Vector,
1170 MzAclItem,
1171}
1172
1173impl CatalogType<IdReference> {
1174 pub fn desc(&self, catalog: &dyn SessionCatalog) -> Result<Option<RelationDesc>, PlanError> {
1177 match &self {
1178 CatalogType::Record { fields } => {
1179 let mut desc = RelationDesc::builder();
1180 let mut budget = query::TypeResolutionBudget::for_root(catalog);
1185 for f in fields {
1186 let name = f.name.clone();
1187 let ty = budget.resolve_child(catalog, f.type_reference, &f.type_modifiers)?;
1188 let ty = ty.nullable(true);
1191 desc = desc.with_column(name, ty);
1192 }
1193 Ok(Some(desc.finish()))
1194 }
1195 _ => Ok(None),
1196 }
1197 }
1198}
1199
1200#[derive(Clone, Debug, Eq, PartialEq)]
1202pub struct CatalogRecordField<T: TypeReference> {
1203 pub name: ColumnName,
1205 pub type_reference: T::Reference,
1207 pub type_modifiers: Vec<i64>,
1209}
1210
1211#[derive(Clone, Debug, Eq, PartialEq)]
1212pub enum TypeCategory {
1220 Array,
1222 BitString,
1224 Boolean,
1226 Composite,
1228 DateTime,
1230 Enum,
1232 Geometric,
1234 List,
1236 NetworkAddress,
1238 Numeric,
1240 Pseudo,
1242 Range,
1244 String,
1246 Timespan,
1248 UserDefined,
1250 Unknown,
1252}
1253
1254impl fmt::Display for TypeCategory {
1255 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1256 f.write_str(match self {
1257 TypeCategory::Array => "array",
1258 TypeCategory::BitString => "bit-string",
1259 TypeCategory::Boolean => "boolean",
1260 TypeCategory::Composite => "composite",
1261 TypeCategory::DateTime => "date-time",
1262 TypeCategory::Enum => "enum",
1263 TypeCategory::Geometric => "geometric",
1264 TypeCategory::List => "list",
1265 TypeCategory::NetworkAddress => "network-address",
1266 TypeCategory::Numeric => "numeric",
1267 TypeCategory::Pseudo => "pseudo",
1268 TypeCategory::Range => "range",
1269 TypeCategory::String => "string",
1270 TypeCategory::Timespan => "timespan",
1271 TypeCategory::UserDefined => "user-defined",
1272 TypeCategory::Unknown => "unknown",
1273 })
1274 }
1275}
1276
1277#[derive(Debug, Clone, PartialEq)]
1301pub struct EnvironmentId {
1302 cloud_provider: CloudProvider,
1303 cloud_provider_region: String,
1304 organization_id: Uuid,
1305 ordinal: u64,
1306}
1307
1308impl EnvironmentId {
1309 pub fn for_tests() -> EnvironmentId {
1311 EnvironmentId {
1312 cloud_provider: CloudProvider::Local,
1313 cloud_provider_region: "az1".into(),
1314 organization_id: Uuid::new_v4(),
1315 ordinal: 0,
1316 }
1317 }
1318
1319 pub fn cloud_provider(&self) -> &CloudProvider {
1321 &self.cloud_provider
1322 }
1323
1324 pub fn cloud_provider_region(&self) -> &str {
1326 &self.cloud_provider_region
1327 }
1328
1329 pub fn region(&self) -> String {
1334 format!("{}/{}", self.cloud_provider, self.cloud_provider_region)
1335 }
1336
1337 pub fn organization_id(&self) -> Uuid {
1339 self.organization_id
1340 }
1341
1342 pub fn ordinal(&self) -> u64 {
1344 self.ordinal
1345 }
1346}
1347
1348impl fmt::Display for EnvironmentId {
1354 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1355 write!(
1356 f,
1357 "{}-{}-{}-{}",
1358 self.cloud_provider, self.cloud_provider_region, self.organization_id, self.ordinal
1359 )
1360 }
1361}
1362
1363impl FromStr for EnvironmentId {
1364 type Err = InvalidEnvironmentIdError;
1365
1366 fn from_str(s: &str) -> Result<EnvironmentId, InvalidEnvironmentIdError> {
1367 static MATCHER: LazyLock<Regex> = LazyLock::new(|| {
1368 Regex::new(
1369 "^(?P<cloud_provider>[[:alnum:]]+)-\
1370 (?P<cloud_provider_region>[[:alnum:]\\-]+)-\
1371 (?P<organization_id>[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})-\
1372 (?P<ordinal>\\d{1,8})$"
1373 ).unwrap()
1374 });
1375 let captures = MATCHER.captures(s).ok_or(InvalidEnvironmentIdError)?;
1376 Ok(EnvironmentId {
1377 cloud_provider: CloudProvider::from_str(&captures["cloud_provider"])?,
1378 cloud_provider_region: captures["cloud_provider_region"].into(),
1379 organization_id: captures["organization_id"]
1380 .parse()
1381 .map_err(|_| InvalidEnvironmentIdError)?,
1382 ordinal: captures["ordinal"]
1383 .parse()
1384 .map_err(|_| InvalidEnvironmentIdError)?,
1385 })
1386 }
1387}
1388
1389#[derive(Debug, Clone, PartialEq)]
1391pub struct InvalidEnvironmentIdError;
1392
1393impl fmt::Display for InvalidEnvironmentIdError {
1394 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1395 f.write_str("invalid environment ID")
1396 }
1397}
1398
1399impl Error for InvalidEnvironmentIdError {}
1400
1401impl From<InvalidCloudProviderError> for InvalidEnvironmentIdError {
1402 fn from(_: InvalidCloudProviderError) -> Self {
1403 InvalidEnvironmentIdError
1404 }
1405}
1406
1407#[derive(Clone, Debug, Eq, PartialEq)]
1409pub enum CatalogError {
1410 UnknownDatabase(String),
1412 DatabaseAlreadyExists(String),
1414 UnknownSchema(String),
1416 SchemaAlreadyExists(String),
1418 UnknownRole(String),
1420 RoleAlreadyExists(String),
1422 NetworkPolicyAlreadyExists(String),
1424 UnknownCluster(String),
1426 UnexpectedBuiltinCluster(String),
1428 UnexpectedBuiltinClusterType(String),
1430 ClusterAlreadyExists(String),
1432 UnknownClusterReplica(String),
1434 UnknownClusterReplicaSize(String),
1436 DuplicateReplica(String, String),
1438 UnknownItem(String),
1440 ItemAlreadyExists(CatalogItemId, String),
1442 UnknownFunction {
1444 name: String,
1446 alternative: Option<String>,
1448 },
1449 UnknownType {
1451 name: String,
1453 },
1454 UnknownConnection(String),
1456 UnknownNetworkPolicy(String),
1458 UnexpectedType {
1460 name: String,
1462 actual_type: CatalogItemType,
1464 expected_type: CatalogItemType,
1466 },
1467 IdExhaustion,
1469 OidExhaustion,
1471 TimelineAlreadyExists(String),
1473 IdAllocatorAlreadyExists(String),
1475 ConfigAlreadyExists(String),
1477 FailedBuiltinSchemaMigration(String),
1479 StorageCollectionMetadataAlreadyExists(GlobalId),
1481}
1482
1483impl fmt::Display for CatalogError {
1484 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1485 match self {
1486 Self::UnknownDatabase(name) => write!(f, "unknown database '{}'", name),
1487 Self::DatabaseAlreadyExists(name) => write!(f, "database '{name}' already exists"),
1488 Self::UnknownFunction { name, .. } => write!(f, "function \"{}\" does not exist", name),
1489 Self::UnknownType { name, .. } => write!(f, "type \"{}\" does not exist", name),
1490 Self::UnknownConnection(name) => write!(f, "connection \"{}\" does not exist", name),
1491 Self::UnknownSchema(name) => write!(f, "unknown schema '{}'", name),
1492 Self::SchemaAlreadyExists(name) => write!(f, "schema '{name}' already exists"),
1493 Self::UnknownRole(name) => write!(f, "unknown role '{}'", name),
1494 Self::RoleAlreadyExists(name) => write!(f, "role '{name}' already exists"),
1495 Self::NetworkPolicyAlreadyExists(name) => {
1496 write!(f, "network policy '{name}' already exists")
1497 }
1498 Self::UnknownCluster(name) => write!(f, "unknown cluster '{}'", name),
1499 Self::UnknownNetworkPolicy(name) => write!(f, "unknown network policy '{}'", name),
1500 Self::UnexpectedBuiltinCluster(name) => {
1501 write!(f, "Unexpected builtin cluster '{}'", name)
1502 }
1503 Self::UnexpectedBuiltinClusterType(name) => {
1504 write!(f, "Unexpected builtin cluster type'{}'", name)
1505 }
1506 Self::ClusterAlreadyExists(name) => write!(f, "cluster '{name}' already exists"),
1507 Self::UnknownClusterReplica(name) => {
1508 write!(f, "unknown cluster replica '{}'", name)
1509 }
1510 Self::UnknownClusterReplicaSize(name) => {
1511 write!(f, "unknown cluster replica size '{}'", name)
1512 }
1513 Self::DuplicateReplica(replica_name, cluster_name) => write!(
1514 f,
1515 "cannot create multiple replicas named '{replica_name}' on cluster '{cluster_name}'"
1516 ),
1517 Self::UnknownItem(name) => write!(f, "unknown catalog item '{}'", name),
1518 Self::ItemAlreadyExists(_gid, name) => {
1519 write!(f, "catalog item '{name}' already exists")
1520 }
1521 Self::UnexpectedType {
1522 name,
1523 actual_type,
1524 expected_type,
1525 } => {
1526 write!(f, "\"{name}\" is a {actual_type} not a {expected_type}")
1527 }
1528 Self::IdExhaustion => write!(f, "id counter overflows i64"),
1529 Self::OidExhaustion => write!(f, "oid counter overflows u32"),
1530 Self::TimelineAlreadyExists(name) => write!(f, "timeline '{name}' already exists"),
1531 Self::IdAllocatorAlreadyExists(name) => {
1532 write!(f, "ID allocator '{name}' already exists")
1533 }
1534 Self::ConfigAlreadyExists(key) => write!(f, "config '{key}' already exists"),
1535 Self::FailedBuiltinSchemaMigration(objects) => {
1536 write!(f, "failed to migrate schema of builtin objects: {objects}")
1537 }
1538 Self::StorageCollectionMetadataAlreadyExists(key) => {
1539 write!(f, "storage metadata for '{key}' already exists")
1540 }
1541 }
1542 }
1543}
1544
1545impl CatalogError {
1546 pub fn hint(&self) -> Option<String> {
1548 match self {
1549 CatalogError::UnknownFunction { alternative, .. } => {
1550 match alternative {
1551 None => Some("No function matches the given name and argument types. You might need to add explicit type casts.".into()),
1552 Some(alt) => Some(format!("Try using {alt}")),
1553 }
1554 }
1555 _ => None,
1556 }
1557 }
1558}
1559
1560impl Error for CatalogError {}
1561
1562#[allow(missing_docs)]
1564#[derive(
1565 Debug,
1566 Clone,
1567 PartialOrd,
1568 Ord,
1569 PartialEq,
1570 Eq,
1571 Hash,
1572 Copy,
1573 Deserialize,
1574 Serialize
1575)]
1576pub enum ObjectType {
1578 Table,
1579 View,
1580 MaterializedView,
1581 Source,
1582 Sink,
1583 MetricSink,
1584 Index,
1585 Type,
1586 Role,
1587 Cluster,
1588 ClusterReplica,
1589 Secret,
1590 Connection,
1591 Database,
1592 Schema,
1593 Func,
1594 NetworkPolicy,
1595}
1596
1597impl ObjectType {
1598 pub fn is_relation(&self) -> bool {
1600 match self {
1601 ObjectType::Table
1602 | ObjectType::View
1603 | ObjectType::MaterializedView
1604 | ObjectType::Source => true,
1605 ObjectType::Sink
1606 | ObjectType::MetricSink
1607 | ObjectType::Index
1608 | ObjectType::Type
1609 | ObjectType::Secret
1610 | ObjectType::Connection
1611 | ObjectType::Func
1612 | ObjectType::Database
1613 | ObjectType::Schema
1614 | ObjectType::Cluster
1615 | ObjectType::ClusterReplica
1616 | ObjectType::Role
1617 | ObjectType::NetworkPolicy => false,
1618 }
1619 }
1620}
1621
1622impl From<mz_sql_parser::ast::ObjectType> for ObjectType {
1623 fn from(value: mz_sql_parser::ast::ObjectType) -> Self {
1624 match value {
1625 mz_sql_parser::ast::ObjectType::Table => ObjectType::Table,
1626 mz_sql_parser::ast::ObjectType::View => ObjectType::View,
1627 mz_sql_parser::ast::ObjectType::MaterializedView => ObjectType::MaterializedView,
1628 mz_sql_parser::ast::ObjectType::Source => ObjectType::Source,
1629 mz_sql_parser::ast::ObjectType::Subsource => ObjectType::Source,
1630 mz_sql_parser::ast::ObjectType::Sink => ObjectType::Sink,
1631 mz_sql_parser::ast::ObjectType::MetricSink => ObjectType::MetricSink,
1632 mz_sql_parser::ast::ObjectType::Index => ObjectType::Index,
1633 mz_sql_parser::ast::ObjectType::Type => ObjectType::Type,
1634 mz_sql_parser::ast::ObjectType::Role => ObjectType::Role,
1635 mz_sql_parser::ast::ObjectType::Cluster => ObjectType::Cluster,
1636 mz_sql_parser::ast::ObjectType::ClusterReplica => ObjectType::ClusterReplica,
1637 mz_sql_parser::ast::ObjectType::Secret => ObjectType::Secret,
1638 mz_sql_parser::ast::ObjectType::Connection => ObjectType::Connection,
1639 mz_sql_parser::ast::ObjectType::Database => ObjectType::Database,
1640 mz_sql_parser::ast::ObjectType::Schema => ObjectType::Schema,
1641 mz_sql_parser::ast::ObjectType::Func => ObjectType::Func,
1642 mz_sql_parser::ast::ObjectType::NetworkPolicy => ObjectType::NetworkPolicy,
1643 }
1644 }
1645}
1646
1647impl From<CommentObjectId> for ObjectType {
1648 fn from(value: CommentObjectId) -> ObjectType {
1649 match value {
1650 CommentObjectId::Table(_) => ObjectType::Table,
1651 CommentObjectId::View(_) => ObjectType::View,
1652 CommentObjectId::MaterializedView(_) => ObjectType::MaterializedView,
1653 CommentObjectId::Source(_) => ObjectType::Source,
1654 CommentObjectId::Sink(_) => ObjectType::Sink,
1655 CommentObjectId::MetricSink(_) => ObjectType::MetricSink,
1656 CommentObjectId::Index(_) => ObjectType::Index,
1657 CommentObjectId::Func(_) => ObjectType::Func,
1658 CommentObjectId::Connection(_) => ObjectType::Connection,
1659 CommentObjectId::Type(_) => ObjectType::Type,
1660 CommentObjectId::Secret(_) => ObjectType::Secret,
1661 CommentObjectId::Role(_) => ObjectType::Role,
1662 CommentObjectId::Database(_) => ObjectType::Database,
1663 CommentObjectId::Schema(_) => ObjectType::Schema,
1664 CommentObjectId::Cluster(_) => ObjectType::Cluster,
1665 CommentObjectId::ClusterReplica(_) => ObjectType::ClusterReplica,
1666 CommentObjectId::NetworkPolicy(_) => ObjectType::NetworkPolicy,
1667 }
1668 }
1669}
1670
1671impl Display for ObjectType {
1672 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1673 f.write_str(match self {
1674 ObjectType::Table => "TABLE",
1675 ObjectType::View => "VIEW",
1676 ObjectType::MaterializedView => "MATERIALIZED VIEW",
1677 ObjectType::Source => "SOURCE",
1678 ObjectType::Sink => "SINK",
1679 ObjectType::MetricSink => "METRIC SINK",
1680 ObjectType::Index => "INDEX",
1681 ObjectType::Type => "TYPE",
1682 ObjectType::Role => "ROLE",
1683 ObjectType::Cluster => "CLUSTER",
1684 ObjectType::ClusterReplica => "CLUSTER REPLICA",
1685 ObjectType::Secret => "SECRET",
1686 ObjectType::Connection => "CONNECTION",
1687 ObjectType::Database => "DATABASE",
1688 ObjectType::Schema => "SCHEMA",
1689 ObjectType::Func => "FUNCTION",
1690 ObjectType::NetworkPolicy => "NETWORK POLICY",
1691 })
1692 }
1693}
1694
1695#[derive(
1696 Debug,
1697 Clone,
1698 PartialOrd,
1699 Ord,
1700 PartialEq,
1701 Eq,
1702 Hash,
1703 Copy,
1704 Deserialize,
1705 Serialize
1706)]
1707pub enum SystemObjectType {
1709 Object(ObjectType),
1711 System,
1713}
1714
1715impl SystemObjectType {
1716 pub fn is_relation(&self) -> bool {
1718 match self {
1719 SystemObjectType::Object(object_type) => object_type.is_relation(),
1720 SystemObjectType::System => false,
1721 }
1722 }
1723}
1724
1725impl Display for SystemObjectType {
1726 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1727 match self {
1728 SystemObjectType::Object(object_type) => std::fmt::Display::fmt(&object_type, f),
1729 SystemObjectType::System => f.write_str("SYSTEM"),
1730 }
1731 }
1732}
1733
1734#[derive(Debug, Clone, PartialEq, Eq)]
1736pub enum ErrorMessageObjectDescription {
1737 Object {
1739 object_type: ObjectType,
1741 object_name: Option<String>,
1743 },
1744 System,
1746}
1747
1748impl ErrorMessageObjectDescription {
1749 pub fn from_id(
1751 object_id: &ObjectId,
1752 catalog: &dyn SessionCatalog,
1753 ) -> ErrorMessageObjectDescription {
1754 let object_name = match object_id {
1755 ObjectId::Cluster(cluster_id) => catalog.get_cluster(*cluster_id).name().to_string(),
1756 ObjectId::ClusterReplica((cluster_id, replica_id)) => catalog
1757 .get_cluster_replica(*cluster_id, *replica_id)
1758 .name()
1759 .to_string(),
1760 ObjectId::Database(database_id) => catalog.get_database(database_id).name().to_string(),
1761 ObjectId::Schema((database_spec, schema_spec)) => {
1762 let name = catalog.get_schema(database_spec, schema_spec).name();
1763 catalog.resolve_full_schema_name(name).to_string()
1764 }
1765 ObjectId::Role(role_id) => catalog.get_role(role_id).name().to_string(),
1766 ObjectId::Item(id) => {
1767 let name = catalog.get_item(id).name();
1768 catalog.resolve_full_name(name).to_string()
1769 }
1770 ObjectId::NetworkPolicy(network_policy_id) => catalog
1771 .get_network_policy(network_policy_id)
1772 .name()
1773 .to_string(),
1774 };
1775 ErrorMessageObjectDescription::Object {
1776 object_type: catalog.get_object_type(object_id),
1777 object_name: Some(object_name),
1778 }
1779 }
1780
1781 pub fn from_sys_id(
1783 object_id: &SystemObjectId,
1784 catalog: &dyn SessionCatalog,
1785 ) -> ErrorMessageObjectDescription {
1786 match object_id {
1787 SystemObjectId::Object(object_id) => {
1788 ErrorMessageObjectDescription::from_id(object_id, catalog)
1789 }
1790 SystemObjectId::System => ErrorMessageObjectDescription::System,
1791 }
1792 }
1793
1794 pub fn from_object_type(object_type: SystemObjectType) -> ErrorMessageObjectDescription {
1796 match object_type {
1797 SystemObjectType::Object(object_type) => ErrorMessageObjectDescription::Object {
1798 object_type,
1799 object_name: None,
1800 },
1801 SystemObjectType::System => ErrorMessageObjectDescription::System,
1802 }
1803 }
1804}
1805
1806impl Display for ErrorMessageObjectDescription {
1807 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1808 match self {
1809 ErrorMessageObjectDescription::Object {
1810 object_type,
1811 object_name,
1812 } => {
1813 let object_name = object_name
1814 .as_ref()
1815 .map(|object_name| format!(" {}", object_name.quoted()))
1816 .unwrap_or_else(|| "".to_string());
1817 write!(f, "{object_type}{object_name}")
1818 }
1819 ErrorMessageObjectDescription::System => f.write_str("SYSTEM"),
1820 }
1821 }
1822}
1823
1824#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd)]
1825#[serde(into = "BTreeMap<String, RoleId>")]
1828#[serde(try_from = "BTreeMap<String, RoleId>")]
1829pub struct RoleMembership {
1831 pub map: BTreeMap<RoleId, RoleId>,
1837}
1838
1839impl RoleMembership {
1840 pub fn new() -> RoleMembership {
1842 RoleMembership {
1843 map: BTreeMap::new(),
1844 }
1845 }
1846}
1847
1848impl From<RoleMembership> for BTreeMap<String, RoleId> {
1849 fn from(value: RoleMembership) -> Self {
1850 value
1851 .map
1852 .into_iter()
1853 .map(|(k, v)| (k.to_string(), v))
1854 .collect()
1855 }
1856}
1857
1858impl TryFrom<BTreeMap<String, RoleId>> for RoleMembership {
1859 type Error = anyhow::Error;
1860
1861 fn try_from(value: BTreeMap<String, RoleId>) -> Result<Self, Self::Error> {
1862 Ok(RoleMembership {
1863 map: value
1864 .into_iter()
1865 .map(|(k, v)| Ok((RoleId::from_str(&k)?, v)))
1866 .collect::<Result<_, anyhow::Error>>()?,
1867 })
1868 }
1869}
1870
1871#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize)]
1873pub struct DefaultPrivilegeObject {
1874 pub role_id: RoleId,
1876 pub database_id: Option<DatabaseId>,
1878 pub schema_id: Option<SchemaId>,
1880 pub object_type: ObjectType,
1882}
1883
1884impl DefaultPrivilegeObject {
1885 pub fn new(
1887 role_id: RoleId,
1888 database_id: Option<DatabaseId>,
1889 schema_id: Option<SchemaId>,
1890 object_type: ObjectType,
1891 ) -> DefaultPrivilegeObject {
1892 DefaultPrivilegeObject {
1893 role_id,
1894 database_id,
1895 schema_id,
1896 object_type,
1897 }
1898 }
1899}
1900
1901impl std::fmt::Display for DefaultPrivilegeObject {
1902 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1903 write!(f, "{self:?}")
1905 }
1906}
1907
1908#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize)]
1910pub struct DefaultPrivilegeAclItem {
1911 pub grantee: RoleId,
1913 pub acl_mode: AclMode,
1915}
1916
1917impl DefaultPrivilegeAclItem {
1918 pub fn new(grantee: RoleId, acl_mode: AclMode) -> DefaultPrivilegeAclItem {
1920 DefaultPrivilegeAclItem { grantee, acl_mode }
1921 }
1922
1923 pub fn mz_acl_item(self, grantor: RoleId) -> MzAclItem {
1925 MzAclItem {
1926 grantee: self.grantee,
1927 grantor,
1928 acl_mode: self.acl_mode,
1929 }
1930 }
1931}
1932
1933#[cfg(test)]
1934mod tests {
1935 use super::{CloudProvider, EnvironmentId, InvalidEnvironmentIdError};
1936
1937 #[mz_ore::test]
1938 fn test_environment_id() {
1939 for (input, expected) in [
1940 (
1941 "local-az1-1497a3b7-a455-4fc4-8752-b44a94b5f90a-452",
1942 Ok(EnvironmentId {
1943 cloud_provider: CloudProvider::Local,
1944 cloud_provider_region: "az1".into(),
1945 organization_id: "1497a3b7-a455-4fc4-8752-b44a94b5f90a".parse().unwrap(),
1946 ordinal: 452,
1947 }),
1948 ),
1949 (
1950 "aws-us-east-1-1497a3b7-a455-4fc4-8752-b44a94b5f90a-0",
1951 Ok(EnvironmentId {
1952 cloud_provider: CloudProvider::Aws,
1953 cloud_provider_region: "us-east-1".into(),
1954 organization_id: "1497a3b7-a455-4fc4-8752-b44a94b5f90a".parse().unwrap(),
1955 ordinal: 0,
1956 }),
1957 ),
1958 (
1959 "gcp-us-central1-1497a3b7-a455-4fc4-8752-b44a94b5f90a-0",
1960 Ok(EnvironmentId {
1961 cloud_provider: CloudProvider::Gcp,
1962 cloud_provider_region: "us-central1".into(),
1963 organization_id: "1497a3b7-a455-4fc4-8752-b44a94b5f90a".parse().unwrap(),
1964 ordinal: 0,
1965 }),
1966 ),
1967 (
1968 "azure-australiaeast-1497a3b7-a455-4fc4-8752-b44a94b5f90a-0",
1969 Ok(EnvironmentId {
1970 cloud_provider: CloudProvider::Azure,
1971 cloud_provider_region: "australiaeast".into(),
1972 organization_id: "1497a3b7-a455-4fc4-8752-b44a94b5f90a".parse().unwrap(),
1973 ordinal: 0,
1974 }),
1975 ),
1976 (
1977 "generic-moon-station-11-darkside-1497a3b7-a455-4fc4-8752-b44a94b5f90a-0",
1978 Ok(EnvironmentId {
1979 cloud_provider: CloudProvider::Generic,
1980 cloud_provider_region: "moon-station-11-darkside".into(),
1981 organization_id: "1497a3b7-a455-4fc4-8752-b44a94b5f90a".parse().unwrap(),
1982 ordinal: 0,
1983 }),
1984 ),
1985 ("", Err(InvalidEnvironmentIdError)),
1986 (
1987 "local-az1-1497a3b7-a455-4fc4-8752-b44a94b5f90a-123456789",
1988 Err(InvalidEnvironmentIdError),
1989 ),
1990 (
1991 "local-1497a3b7-a455-4fc4-8752-b44a94b5f90a-452",
1992 Err(InvalidEnvironmentIdError),
1993 ),
1994 (
1995 "local-az1-1497a3b7-a455-4fc48752-b44a94b5f90a-452",
1996 Err(InvalidEnvironmentIdError),
1997 ),
1998 ] {
1999 let actual = input.parse();
2000 assert_eq!(expected, actual, "input = {}", input);
2001 if let Ok(actual) = actual {
2002 assert_eq!(input, actual.to_string(), "input = {}", input);
2003 }
2004 }
2005 }
2006}