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}
1087
1088pub trait TypeReference {
1090 type Reference: Clone + Debug + Eq + PartialEq;
1092}
1093
1094#[derive(Clone, Debug, Eq, PartialEq)]
1096pub struct NameReference;
1097
1098impl TypeReference for NameReference {
1099 type Reference = &'static str;
1100}
1101
1102#[derive(Clone, Debug, Eq, PartialEq)]
1104pub struct IdReference;
1105
1106impl TypeReference for IdReference {
1107 type Reference = CatalogItemId;
1108}
1109
1110#[allow(missing_docs)]
1116#[derive(Clone, Debug, Eq, PartialEq)]
1117pub enum CatalogType<T: TypeReference> {
1118 AclItem,
1119 Array {
1120 element_reference: T::Reference,
1121 },
1122 Bool,
1123 Bytes,
1124 Char,
1125 Date,
1126 Float32,
1127 Float64,
1128 Int16,
1129 Int32,
1130 Int64,
1131 UInt16,
1132 UInt32,
1133 UInt64,
1134 MzTimestamp,
1135 Interval,
1136 Jsonb,
1137 List {
1138 element_reference: T::Reference,
1139 element_modifiers: Vec<i64>,
1140 },
1141 Map {
1142 key_reference: T::Reference,
1143 key_modifiers: Vec<i64>,
1144 value_reference: T::Reference,
1145 value_modifiers: Vec<i64>,
1146 },
1147 Numeric,
1148 Oid,
1149 PgLegacyChar,
1150 PgLegacyName,
1151 Pseudo,
1152 Range {
1153 element_reference: T::Reference,
1154 },
1155 Record {
1156 fields: Vec<CatalogRecordField<T>>,
1157 },
1158 RegClass,
1159 RegProc,
1160 RegType,
1161 String,
1162 Time,
1163 Timestamp,
1164 TimestampTz,
1165 Uuid,
1166 VarChar,
1167 Int2Vector,
1168 MzAclItem,
1169}
1170
1171impl CatalogType<IdReference> {
1172 pub fn desc(&self, catalog: &dyn SessionCatalog) -> Result<Option<RelationDesc>, PlanError> {
1175 match &self {
1176 CatalogType::Record { fields } => {
1177 let mut desc = RelationDesc::builder();
1178 let mut budget = query::TypeResolutionBudget::for_root(catalog);
1183 for f in fields {
1184 let name = f.name.clone();
1185 let ty = budget.resolve_child(catalog, f.type_reference, &f.type_modifiers)?;
1186 let ty = ty.nullable(true);
1189 desc = desc.with_column(name, ty);
1190 }
1191 Ok(Some(desc.finish()))
1192 }
1193 _ => Ok(None),
1194 }
1195 }
1196}
1197
1198#[derive(Clone, Debug, Eq, PartialEq)]
1200pub struct CatalogRecordField<T: TypeReference> {
1201 pub name: ColumnName,
1203 pub type_reference: T::Reference,
1205 pub type_modifiers: Vec<i64>,
1207}
1208
1209#[derive(Clone, Debug, Eq, PartialEq)]
1210pub enum TypeCategory {
1218 Array,
1220 BitString,
1222 Boolean,
1224 Composite,
1226 DateTime,
1228 Enum,
1230 Geometric,
1232 List,
1234 NetworkAddress,
1236 Numeric,
1238 Pseudo,
1240 Range,
1242 String,
1244 Timespan,
1246 UserDefined,
1248 Unknown,
1250}
1251
1252impl fmt::Display for TypeCategory {
1253 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1254 f.write_str(match self {
1255 TypeCategory::Array => "array",
1256 TypeCategory::BitString => "bit-string",
1257 TypeCategory::Boolean => "boolean",
1258 TypeCategory::Composite => "composite",
1259 TypeCategory::DateTime => "date-time",
1260 TypeCategory::Enum => "enum",
1261 TypeCategory::Geometric => "geometric",
1262 TypeCategory::List => "list",
1263 TypeCategory::NetworkAddress => "network-address",
1264 TypeCategory::Numeric => "numeric",
1265 TypeCategory::Pseudo => "pseudo",
1266 TypeCategory::Range => "range",
1267 TypeCategory::String => "string",
1268 TypeCategory::Timespan => "timespan",
1269 TypeCategory::UserDefined => "user-defined",
1270 TypeCategory::Unknown => "unknown",
1271 })
1272 }
1273}
1274
1275#[derive(Debug, Clone, PartialEq)]
1299pub struct EnvironmentId {
1300 cloud_provider: CloudProvider,
1301 cloud_provider_region: String,
1302 organization_id: Uuid,
1303 ordinal: u64,
1304}
1305
1306impl EnvironmentId {
1307 pub fn for_tests() -> EnvironmentId {
1309 EnvironmentId {
1310 cloud_provider: CloudProvider::Local,
1311 cloud_provider_region: "az1".into(),
1312 organization_id: Uuid::new_v4(),
1313 ordinal: 0,
1314 }
1315 }
1316
1317 pub fn cloud_provider(&self) -> &CloudProvider {
1319 &self.cloud_provider
1320 }
1321
1322 pub fn cloud_provider_region(&self) -> &str {
1324 &self.cloud_provider_region
1325 }
1326
1327 pub fn region(&self) -> String {
1332 format!("{}/{}", self.cloud_provider, self.cloud_provider_region)
1333 }
1334
1335 pub fn organization_id(&self) -> Uuid {
1337 self.organization_id
1338 }
1339
1340 pub fn ordinal(&self) -> u64 {
1342 self.ordinal
1343 }
1344}
1345
1346impl fmt::Display for EnvironmentId {
1352 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1353 write!(
1354 f,
1355 "{}-{}-{}-{}",
1356 self.cloud_provider, self.cloud_provider_region, self.organization_id, self.ordinal
1357 )
1358 }
1359}
1360
1361impl FromStr for EnvironmentId {
1362 type Err = InvalidEnvironmentIdError;
1363
1364 fn from_str(s: &str) -> Result<EnvironmentId, InvalidEnvironmentIdError> {
1365 static MATCHER: LazyLock<Regex> = LazyLock::new(|| {
1366 Regex::new(
1367 "^(?P<cloud_provider>[[:alnum:]]+)-\
1368 (?P<cloud_provider_region>[[:alnum:]\\-]+)-\
1369 (?P<organization_id>[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})-\
1370 (?P<ordinal>\\d{1,8})$"
1371 ).unwrap()
1372 });
1373 let captures = MATCHER.captures(s).ok_or(InvalidEnvironmentIdError)?;
1374 Ok(EnvironmentId {
1375 cloud_provider: CloudProvider::from_str(&captures["cloud_provider"])?,
1376 cloud_provider_region: captures["cloud_provider_region"].into(),
1377 organization_id: captures["organization_id"]
1378 .parse()
1379 .map_err(|_| InvalidEnvironmentIdError)?,
1380 ordinal: captures["ordinal"]
1381 .parse()
1382 .map_err(|_| InvalidEnvironmentIdError)?,
1383 })
1384 }
1385}
1386
1387#[derive(Debug, Clone, PartialEq)]
1389pub struct InvalidEnvironmentIdError;
1390
1391impl fmt::Display for InvalidEnvironmentIdError {
1392 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1393 f.write_str("invalid environment ID")
1394 }
1395}
1396
1397impl Error for InvalidEnvironmentIdError {}
1398
1399impl From<InvalidCloudProviderError> for InvalidEnvironmentIdError {
1400 fn from(_: InvalidCloudProviderError) -> Self {
1401 InvalidEnvironmentIdError
1402 }
1403}
1404
1405#[derive(Clone, Debug, Eq, PartialEq)]
1407pub enum CatalogError {
1408 UnknownDatabase(String),
1410 DatabaseAlreadyExists(String),
1412 UnknownSchema(String),
1414 SchemaAlreadyExists(String),
1416 UnknownRole(String),
1418 RoleAlreadyExists(String),
1420 NetworkPolicyAlreadyExists(String),
1422 UnknownCluster(String),
1424 UnexpectedBuiltinCluster(String),
1426 UnexpectedBuiltinClusterType(String),
1428 ClusterAlreadyExists(String),
1430 UnknownClusterReplica(String),
1432 UnknownClusterReplicaSize(String),
1434 DuplicateReplica(String, String),
1436 UnknownItem(String),
1438 ItemAlreadyExists(CatalogItemId, String),
1440 UnknownFunction {
1442 name: String,
1444 alternative: Option<String>,
1446 },
1447 UnknownType {
1449 name: String,
1451 },
1452 UnknownConnection(String),
1454 UnknownNetworkPolicy(String),
1456 UnexpectedType {
1458 name: String,
1460 actual_type: CatalogItemType,
1462 expected_type: CatalogItemType,
1464 },
1465 IdExhaustion,
1467 OidExhaustion,
1469 TimelineAlreadyExists(String),
1471 IdAllocatorAlreadyExists(String),
1473 ConfigAlreadyExists(String),
1475 FailedBuiltinSchemaMigration(String),
1477 StorageCollectionMetadataAlreadyExists(GlobalId),
1479}
1480
1481impl fmt::Display for CatalogError {
1482 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1483 match self {
1484 Self::UnknownDatabase(name) => write!(f, "unknown database '{}'", name),
1485 Self::DatabaseAlreadyExists(name) => write!(f, "database '{name}' already exists"),
1486 Self::UnknownFunction { name, .. } => write!(f, "function \"{}\" does not exist", name),
1487 Self::UnknownType { name, .. } => write!(f, "type \"{}\" does not exist", name),
1488 Self::UnknownConnection(name) => write!(f, "connection \"{}\" does not exist", name),
1489 Self::UnknownSchema(name) => write!(f, "unknown schema '{}'", name),
1490 Self::SchemaAlreadyExists(name) => write!(f, "schema '{name}' already exists"),
1491 Self::UnknownRole(name) => write!(f, "unknown role '{}'", name),
1492 Self::RoleAlreadyExists(name) => write!(f, "role '{name}' already exists"),
1493 Self::NetworkPolicyAlreadyExists(name) => {
1494 write!(f, "network policy '{name}' already exists")
1495 }
1496 Self::UnknownCluster(name) => write!(f, "unknown cluster '{}'", name),
1497 Self::UnknownNetworkPolicy(name) => write!(f, "unknown network policy '{}'", name),
1498 Self::UnexpectedBuiltinCluster(name) => {
1499 write!(f, "Unexpected builtin cluster '{}'", name)
1500 }
1501 Self::UnexpectedBuiltinClusterType(name) => {
1502 write!(f, "Unexpected builtin cluster type'{}'", name)
1503 }
1504 Self::ClusterAlreadyExists(name) => write!(f, "cluster '{name}' already exists"),
1505 Self::UnknownClusterReplica(name) => {
1506 write!(f, "unknown cluster replica '{}'", name)
1507 }
1508 Self::UnknownClusterReplicaSize(name) => {
1509 write!(f, "unknown cluster replica size '{}'", name)
1510 }
1511 Self::DuplicateReplica(replica_name, cluster_name) => write!(
1512 f,
1513 "cannot create multiple replicas named '{replica_name}' on cluster '{cluster_name}'"
1514 ),
1515 Self::UnknownItem(name) => write!(f, "unknown catalog item '{}'", name),
1516 Self::ItemAlreadyExists(_gid, name) => {
1517 write!(f, "catalog item '{name}' already exists")
1518 }
1519 Self::UnexpectedType {
1520 name,
1521 actual_type,
1522 expected_type,
1523 } => {
1524 write!(f, "\"{name}\" is a {actual_type} not a {expected_type}")
1525 }
1526 Self::IdExhaustion => write!(f, "id counter overflows i64"),
1527 Self::OidExhaustion => write!(f, "oid counter overflows u32"),
1528 Self::TimelineAlreadyExists(name) => write!(f, "timeline '{name}' already exists"),
1529 Self::IdAllocatorAlreadyExists(name) => {
1530 write!(f, "ID allocator '{name}' already exists")
1531 }
1532 Self::ConfigAlreadyExists(key) => write!(f, "config '{key}' already exists"),
1533 Self::FailedBuiltinSchemaMigration(objects) => {
1534 write!(f, "failed to migrate schema of builtin objects: {objects}")
1535 }
1536 Self::StorageCollectionMetadataAlreadyExists(key) => {
1537 write!(f, "storage metadata for '{key}' already exists")
1538 }
1539 }
1540 }
1541}
1542
1543impl CatalogError {
1544 pub fn hint(&self) -> Option<String> {
1546 match self {
1547 CatalogError::UnknownFunction { alternative, .. } => {
1548 match alternative {
1549 None => Some("No function matches the given name and argument types. You might need to add explicit type casts.".into()),
1550 Some(alt) => Some(format!("Try using {alt}")),
1551 }
1552 }
1553 _ => None,
1554 }
1555 }
1556}
1557
1558impl Error for CatalogError {}
1559
1560#[allow(missing_docs)]
1562#[derive(
1563 Debug,
1564 Clone,
1565 PartialOrd,
1566 Ord,
1567 PartialEq,
1568 Eq,
1569 Hash,
1570 Copy,
1571 Deserialize,
1572 Serialize
1573)]
1574pub enum ObjectType {
1576 Table,
1577 View,
1578 MaterializedView,
1579 Source,
1580 Sink,
1581 MetricSink,
1582 Index,
1583 Type,
1584 Role,
1585 Cluster,
1586 ClusterReplica,
1587 Secret,
1588 Connection,
1589 Database,
1590 Schema,
1591 Func,
1592 NetworkPolicy,
1593}
1594
1595impl ObjectType {
1596 pub fn is_relation(&self) -> bool {
1598 match self {
1599 ObjectType::Table
1600 | ObjectType::View
1601 | ObjectType::MaterializedView
1602 | ObjectType::Source => true,
1603 ObjectType::Sink
1604 | ObjectType::MetricSink
1605 | ObjectType::Index
1606 | ObjectType::Type
1607 | ObjectType::Secret
1608 | ObjectType::Connection
1609 | ObjectType::Func
1610 | ObjectType::Database
1611 | ObjectType::Schema
1612 | ObjectType::Cluster
1613 | ObjectType::ClusterReplica
1614 | ObjectType::Role
1615 | ObjectType::NetworkPolicy => false,
1616 }
1617 }
1618}
1619
1620impl From<mz_sql_parser::ast::ObjectType> for ObjectType {
1621 fn from(value: mz_sql_parser::ast::ObjectType) -> Self {
1622 match value {
1623 mz_sql_parser::ast::ObjectType::Table => ObjectType::Table,
1624 mz_sql_parser::ast::ObjectType::View => ObjectType::View,
1625 mz_sql_parser::ast::ObjectType::MaterializedView => ObjectType::MaterializedView,
1626 mz_sql_parser::ast::ObjectType::Source => ObjectType::Source,
1627 mz_sql_parser::ast::ObjectType::Subsource => ObjectType::Source,
1628 mz_sql_parser::ast::ObjectType::Sink => ObjectType::Sink,
1629 mz_sql_parser::ast::ObjectType::MetricSink => ObjectType::MetricSink,
1630 mz_sql_parser::ast::ObjectType::Index => ObjectType::Index,
1631 mz_sql_parser::ast::ObjectType::Type => ObjectType::Type,
1632 mz_sql_parser::ast::ObjectType::Role => ObjectType::Role,
1633 mz_sql_parser::ast::ObjectType::Cluster => ObjectType::Cluster,
1634 mz_sql_parser::ast::ObjectType::ClusterReplica => ObjectType::ClusterReplica,
1635 mz_sql_parser::ast::ObjectType::Secret => ObjectType::Secret,
1636 mz_sql_parser::ast::ObjectType::Connection => ObjectType::Connection,
1637 mz_sql_parser::ast::ObjectType::Database => ObjectType::Database,
1638 mz_sql_parser::ast::ObjectType::Schema => ObjectType::Schema,
1639 mz_sql_parser::ast::ObjectType::Func => ObjectType::Func,
1640 mz_sql_parser::ast::ObjectType::NetworkPolicy => ObjectType::NetworkPolicy,
1641 }
1642 }
1643}
1644
1645impl From<CommentObjectId> for ObjectType {
1646 fn from(value: CommentObjectId) -> ObjectType {
1647 match value {
1648 CommentObjectId::Table(_) => ObjectType::Table,
1649 CommentObjectId::View(_) => ObjectType::View,
1650 CommentObjectId::MaterializedView(_) => ObjectType::MaterializedView,
1651 CommentObjectId::Source(_) => ObjectType::Source,
1652 CommentObjectId::Sink(_) => ObjectType::Sink,
1653 CommentObjectId::MetricSink(_) => ObjectType::MetricSink,
1654 CommentObjectId::Index(_) => ObjectType::Index,
1655 CommentObjectId::Func(_) => ObjectType::Func,
1656 CommentObjectId::Connection(_) => ObjectType::Connection,
1657 CommentObjectId::Type(_) => ObjectType::Type,
1658 CommentObjectId::Secret(_) => ObjectType::Secret,
1659 CommentObjectId::Role(_) => ObjectType::Role,
1660 CommentObjectId::Database(_) => ObjectType::Database,
1661 CommentObjectId::Schema(_) => ObjectType::Schema,
1662 CommentObjectId::Cluster(_) => ObjectType::Cluster,
1663 CommentObjectId::ClusterReplica(_) => ObjectType::ClusterReplica,
1664 CommentObjectId::NetworkPolicy(_) => ObjectType::NetworkPolicy,
1665 }
1666 }
1667}
1668
1669impl Display for ObjectType {
1670 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1671 f.write_str(match self {
1672 ObjectType::Table => "TABLE",
1673 ObjectType::View => "VIEW",
1674 ObjectType::MaterializedView => "MATERIALIZED VIEW",
1675 ObjectType::Source => "SOURCE",
1676 ObjectType::Sink => "SINK",
1677 ObjectType::MetricSink => "METRIC SINK",
1678 ObjectType::Index => "INDEX",
1679 ObjectType::Type => "TYPE",
1680 ObjectType::Role => "ROLE",
1681 ObjectType::Cluster => "CLUSTER",
1682 ObjectType::ClusterReplica => "CLUSTER REPLICA",
1683 ObjectType::Secret => "SECRET",
1684 ObjectType::Connection => "CONNECTION",
1685 ObjectType::Database => "DATABASE",
1686 ObjectType::Schema => "SCHEMA",
1687 ObjectType::Func => "FUNCTION",
1688 ObjectType::NetworkPolicy => "NETWORK POLICY",
1689 })
1690 }
1691}
1692
1693#[derive(
1694 Debug,
1695 Clone,
1696 PartialOrd,
1697 Ord,
1698 PartialEq,
1699 Eq,
1700 Hash,
1701 Copy,
1702 Deserialize,
1703 Serialize
1704)]
1705pub enum SystemObjectType {
1707 Object(ObjectType),
1709 System,
1711}
1712
1713impl SystemObjectType {
1714 pub fn is_relation(&self) -> bool {
1716 match self {
1717 SystemObjectType::Object(object_type) => object_type.is_relation(),
1718 SystemObjectType::System => false,
1719 }
1720 }
1721}
1722
1723impl Display for SystemObjectType {
1724 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1725 match self {
1726 SystemObjectType::Object(object_type) => std::fmt::Display::fmt(&object_type, f),
1727 SystemObjectType::System => f.write_str("SYSTEM"),
1728 }
1729 }
1730}
1731
1732#[derive(Debug, Clone, PartialEq, Eq)]
1734pub enum ErrorMessageObjectDescription {
1735 Object {
1737 object_type: ObjectType,
1739 object_name: Option<String>,
1741 },
1742 System,
1744}
1745
1746impl ErrorMessageObjectDescription {
1747 pub fn from_id(
1749 object_id: &ObjectId,
1750 catalog: &dyn SessionCatalog,
1751 ) -> ErrorMessageObjectDescription {
1752 let object_name = match object_id {
1753 ObjectId::Cluster(cluster_id) => catalog.get_cluster(*cluster_id).name().to_string(),
1754 ObjectId::ClusterReplica((cluster_id, replica_id)) => catalog
1755 .get_cluster_replica(*cluster_id, *replica_id)
1756 .name()
1757 .to_string(),
1758 ObjectId::Database(database_id) => catalog.get_database(database_id).name().to_string(),
1759 ObjectId::Schema((database_spec, schema_spec)) => {
1760 let name = catalog.get_schema(database_spec, schema_spec).name();
1761 catalog.resolve_full_schema_name(name).to_string()
1762 }
1763 ObjectId::Role(role_id) => catalog.get_role(role_id).name().to_string(),
1764 ObjectId::Item(id) => {
1765 let name = catalog.get_item(id).name();
1766 catalog.resolve_full_name(name).to_string()
1767 }
1768 ObjectId::NetworkPolicy(network_policy_id) => catalog
1769 .get_network_policy(network_policy_id)
1770 .name()
1771 .to_string(),
1772 };
1773 ErrorMessageObjectDescription::Object {
1774 object_type: catalog.get_object_type(object_id),
1775 object_name: Some(object_name),
1776 }
1777 }
1778
1779 pub fn from_sys_id(
1781 object_id: &SystemObjectId,
1782 catalog: &dyn SessionCatalog,
1783 ) -> ErrorMessageObjectDescription {
1784 match object_id {
1785 SystemObjectId::Object(object_id) => {
1786 ErrorMessageObjectDescription::from_id(object_id, catalog)
1787 }
1788 SystemObjectId::System => ErrorMessageObjectDescription::System,
1789 }
1790 }
1791
1792 pub fn from_object_type(object_type: SystemObjectType) -> ErrorMessageObjectDescription {
1794 match object_type {
1795 SystemObjectType::Object(object_type) => ErrorMessageObjectDescription::Object {
1796 object_type,
1797 object_name: None,
1798 },
1799 SystemObjectType::System => ErrorMessageObjectDescription::System,
1800 }
1801 }
1802}
1803
1804impl Display for ErrorMessageObjectDescription {
1805 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1806 match self {
1807 ErrorMessageObjectDescription::Object {
1808 object_type,
1809 object_name,
1810 } => {
1811 let object_name = object_name
1812 .as_ref()
1813 .map(|object_name| format!(" {}", object_name.quoted()))
1814 .unwrap_or_else(|| "".to_string());
1815 write!(f, "{object_type}{object_name}")
1816 }
1817 ErrorMessageObjectDescription::System => f.write_str("SYSTEM"),
1818 }
1819 }
1820}
1821
1822#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd)]
1823#[serde(into = "BTreeMap<String, RoleId>")]
1826#[serde(try_from = "BTreeMap<String, RoleId>")]
1827pub struct RoleMembership {
1829 pub map: BTreeMap<RoleId, RoleId>,
1835}
1836
1837impl RoleMembership {
1838 pub fn new() -> RoleMembership {
1840 RoleMembership {
1841 map: BTreeMap::new(),
1842 }
1843 }
1844}
1845
1846impl From<RoleMembership> for BTreeMap<String, RoleId> {
1847 fn from(value: RoleMembership) -> Self {
1848 value
1849 .map
1850 .into_iter()
1851 .map(|(k, v)| (k.to_string(), v))
1852 .collect()
1853 }
1854}
1855
1856impl TryFrom<BTreeMap<String, RoleId>> for RoleMembership {
1857 type Error = anyhow::Error;
1858
1859 fn try_from(value: BTreeMap<String, RoleId>) -> Result<Self, Self::Error> {
1860 Ok(RoleMembership {
1861 map: value
1862 .into_iter()
1863 .map(|(k, v)| Ok((RoleId::from_str(&k)?, v)))
1864 .collect::<Result<_, anyhow::Error>>()?,
1865 })
1866 }
1867}
1868
1869#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize)]
1871pub struct DefaultPrivilegeObject {
1872 pub role_id: RoleId,
1874 pub database_id: Option<DatabaseId>,
1876 pub schema_id: Option<SchemaId>,
1878 pub object_type: ObjectType,
1880}
1881
1882impl DefaultPrivilegeObject {
1883 pub fn new(
1885 role_id: RoleId,
1886 database_id: Option<DatabaseId>,
1887 schema_id: Option<SchemaId>,
1888 object_type: ObjectType,
1889 ) -> DefaultPrivilegeObject {
1890 DefaultPrivilegeObject {
1891 role_id,
1892 database_id,
1893 schema_id,
1894 object_type,
1895 }
1896 }
1897}
1898
1899impl std::fmt::Display for DefaultPrivilegeObject {
1900 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1901 write!(f, "{self:?}")
1903 }
1904}
1905
1906#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize)]
1908pub struct DefaultPrivilegeAclItem {
1909 pub grantee: RoleId,
1911 pub acl_mode: AclMode,
1913}
1914
1915impl DefaultPrivilegeAclItem {
1916 pub fn new(grantee: RoleId, acl_mode: AclMode) -> DefaultPrivilegeAclItem {
1918 DefaultPrivilegeAclItem { grantee, acl_mode }
1919 }
1920
1921 pub fn mz_acl_item(self, grantor: RoleId) -> MzAclItem {
1923 MzAclItem {
1924 grantee: self.grantee,
1925 grantor,
1926 acl_mode: self.acl_mode,
1927 }
1928 }
1929}
1930
1931#[cfg(test)]
1932mod tests {
1933 use super::{CloudProvider, EnvironmentId, InvalidEnvironmentIdError};
1934
1935 #[mz_ore::test]
1936 fn test_environment_id() {
1937 for (input, expected) in [
1938 (
1939 "local-az1-1497a3b7-a455-4fc4-8752-b44a94b5f90a-452",
1940 Ok(EnvironmentId {
1941 cloud_provider: CloudProvider::Local,
1942 cloud_provider_region: "az1".into(),
1943 organization_id: "1497a3b7-a455-4fc4-8752-b44a94b5f90a".parse().unwrap(),
1944 ordinal: 452,
1945 }),
1946 ),
1947 (
1948 "aws-us-east-1-1497a3b7-a455-4fc4-8752-b44a94b5f90a-0",
1949 Ok(EnvironmentId {
1950 cloud_provider: CloudProvider::Aws,
1951 cloud_provider_region: "us-east-1".into(),
1952 organization_id: "1497a3b7-a455-4fc4-8752-b44a94b5f90a".parse().unwrap(),
1953 ordinal: 0,
1954 }),
1955 ),
1956 (
1957 "gcp-us-central1-1497a3b7-a455-4fc4-8752-b44a94b5f90a-0",
1958 Ok(EnvironmentId {
1959 cloud_provider: CloudProvider::Gcp,
1960 cloud_provider_region: "us-central1".into(),
1961 organization_id: "1497a3b7-a455-4fc4-8752-b44a94b5f90a".parse().unwrap(),
1962 ordinal: 0,
1963 }),
1964 ),
1965 (
1966 "azure-australiaeast-1497a3b7-a455-4fc4-8752-b44a94b5f90a-0",
1967 Ok(EnvironmentId {
1968 cloud_provider: CloudProvider::Azure,
1969 cloud_provider_region: "australiaeast".into(),
1970 organization_id: "1497a3b7-a455-4fc4-8752-b44a94b5f90a".parse().unwrap(),
1971 ordinal: 0,
1972 }),
1973 ),
1974 (
1975 "generic-moon-station-11-darkside-1497a3b7-a455-4fc4-8752-b44a94b5f90a-0",
1976 Ok(EnvironmentId {
1977 cloud_provider: CloudProvider::Generic,
1978 cloud_provider_region: "moon-station-11-darkside".into(),
1979 organization_id: "1497a3b7-a455-4fc4-8752-b44a94b5f90a".parse().unwrap(),
1980 ordinal: 0,
1981 }),
1982 ),
1983 ("", Err(InvalidEnvironmentIdError)),
1984 (
1985 "local-az1-1497a3b7-a455-4fc4-8752-b44a94b5f90a-123456789",
1986 Err(InvalidEnvironmentIdError),
1987 ),
1988 (
1989 "local-1497a3b7-a455-4fc4-8752-b44a94b5f90a-452",
1990 Err(InvalidEnvironmentIdError),
1991 ),
1992 (
1993 "local-az1-1497a3b7-a455-4fc48752-b44a94b5f90a-452",
1994 Err(InvalidEnvironmentIdError),
1995 ),
1996 ] {
1997 let actual = input.parse();
1998 assert_eq!(expected, actual, "input = {}", input);
1999 if let Ok(actual) = actual {
2000 assert_eq!(input, actual.to_string(), "input = {}", input);
2001 }
2002 }
2003 }
2004}