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 helm_chart_version: Option<String>,
445}
446
447pub trait CatalogDatabase {
449 fn name(&self) -> &str;
451
452 fn id(&self) -> DatabaseId;
454
455 fn has_schemas(&self) -> bool;
457
458 fn schema_ids(&self) -> &BTreeMap<String, SchemaId>;
461
462 fn schemas(&self) -> Vec<&dyn CatalogSchema>;
464
465 fn owner_id(&self) -> RoleId;
467
468 fn privileges(&self) -> &PrivilegeMap;
470}
471
472pub trait CatalogSchema {
474 fn database(&self) -> &ResolvedDatabaseSpecifier;
476
477 fn name(&self) -> &QualifiedSchemaName;
479
480 fn id(&self) -> &SchemaSpecifier;
482
483 fn has_items(&self) -> bool;
485
486 fn item_ids(&self) -> Box<dyn Iterator<Item = CatalogItemId> + '_>;
488
489 fn owner_id(&self) -> RoleId;
491
492 fn privileges(&self) -> &PrivilegeMap;
494}
495
496#[derive(Debug, Clone, Eq, PartialEq, Arbitrary)]
498pub struct PasswordConfig {
499 pub password: Password,
501 pub scram_iterations: NonZeroU32,
503}
504
505#[derive(Debug, Clone, Eq, PartialEq, Arbitrary)]
507pub enum PasswordAction {
508 Set(PasswordConfig),
510 Clear,
512 NoChange,
514}
515
516#[derive(
518 Debug,
519 Copy,
520 Clone,
521 Eq,
522 PartialEq,
523 Ord,
524 PartialOrd,
525 Serialize,
526 Deserialize,
527 Arbitrary
528)]
529pub enum AutoProvisionSource {
530 Oidc,
532 Frontegg,
534 None,
536}
537
538#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Arbitrary)]
543pub struct RoleAttributesRaw {
544 pub inherit: bool,
546 pub password: Option<Password>,
548 pub scram_iterations: Option<NonZeroU32>,
550 pub superuser: Option<bool>,
552 pub login: Option<bool>,
554 pub auto_provision_source: Option<AutoProvisionSource>,
556 _private: (),
558}
559
560#[derive(
562 Debug,
563 Clone,
564 Eq,
565 Serialize,
566 Deserialize,
567 PartialEq,
568 Ord,
569 PartialOrd,
570 Arbitrary
571)]
572pub struct RoleAttributes {
573 pub inherit: bool,
575 pub superuser: Option<bool>,
577 pub login: Option<bool>,
579 pub auto_provision_source: Option<AutoProvisionSource>,
581 _private: (),
583}
584
585impl RoleAttributesRaw {
586 pub const fn new() -> RoleAttributesRaw {
588 RoleAttributesRaw {
589 inherit: true,
590 password: None,
591 scram_iterations: None,
592 superuser: None,
593 login: None,
594 auto_provision_source: None,
595 _private: (),
596 }
597 }
598
599 pub const fn with_all(mut self) -> RoleAttributesRaw {
601 self.inherit = true;
602 self.superuser = Some(true);
603 self.login = Some(true);
604 self
605 }
606}
607
608impl RoleAttributes {
609 pub const fn new() -> RoleAttributes {
611 RoleAttributes {
612 inherit: true,
613 superuser: None,
614 login: None,
615 auto_provision_source: None,
616 _private: (),
617 }
618 }
619
620 pub const fn with_all(mut self) -> RoleAttributes {
622 self.inherit = true;
623 self.superuser = Some(true);
624 self.login = Some(true);
625 self
626 }
627
628 pub const fn is_inherit(&self) -> bool {
630 self.inherit
631 }
632}
633
634impl From<RoleAttributesRaw> for RoleAttributes {
635 fn from(
636 RoleAttributesRaw {
637 inherit,
638 superuser,
639 login,
640 auto_provision_source,
641 ..
642 }: RoleAttributesRaw,
643 ) -> RoleAttributes {
644 RoleAttributes {
645 inherit,
646 superuser,
647 login,
648 auto_provision_source,
649 _private: (),
650 }
651 }
652}
653
654impl From<RoleAttributes> for RoleAttributesRaw {
655 fn from(
656 RoleAttributes {
657 inherit,
658 superuser,
659 login,
660 auto_provision_source,
661 ..
662 }: RoleAttributes,
663 ) -> RoleAttributesRaw {
664 RoleAttributesRaw {
665 inherit,
666 password: None,
667 scram_iterations: None,
668 superuser,
669 login,
670 auto_provision_source,
671 _private: (),
672 }
673 }
674}
675
676impl From<PlannedRoleAttributes> for RoleAttributesRaw {
677 fn from(
678 PlannedRoleAttributes {
679 inherit,
680 password,
681 scram_iterations,
682 superuser,
683 login,
684 ..
685 }: PlannedRoleAttributes,
686 ) -> RoleAttributesRaw {
687 let default_attributes = RoleAttributesRaw::new();
688 RoleAttributesRaw {
689 inherit: inherit.unwrap_or(default_attributes.inherit),
690 password,
691 scram_iterations,
692 superuser,
693 login,
694 auto_provision_source: None,
695 _private: (),
696 }
697 }
698}
699
700#[derive(Default, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize)]
702pub struct RoleVars {
703 pub map: BTreeMap<String, OwnedVarInput>,
705}
706
707pub trait CatalogRole {
709 fn name(&self) -> &str;
711
712 fn id(&self) -> RoleId;
714
715 fn membership(&self) -> &BTreeMap<RoleId, RoleId>;
720
721 fn attributes(&self) -> &RoleAttributes;
723
724 fn vars(&self) -> &BTreeMap<String, OwnedVarInput>;
726}
727
728pub trait CatalogNetworkPolicy {
730 fn name(&self) -> &str;
732
733 fn id(&self) -> NetworkPolicyId;
735
736 fn owner_id(&self) -> RoleId;
738
739 fn privileges(&self) -> &PrivilegeMap;
741}
742
743pub trait CatalogCluster<'a> {
745 fn name(&self) -> &str;
747
748 fn id(&self) -> ClusterId;
750
751 fn bound_objects(&self) -> &BTreeSet<CatalogItemId>;
753
754 fn replica_ids(&self) -> &BTreeMap<String, ReplicaId>;
757
758 fn replicas(&self) -> Vec<&dyn CatalogClusterReplica<'_>>;
760
761 fn replica(&self, id: ReplicaId) -> &dyn CatalogClusterReplica<'_>;
763
764 fn owner_id(&self) -> RoleId;
766
767 fn privileges(&self) -> &PrivilegeMap;
769
770 fn is_managed(&self) -> bool;
772
773 fn managed_size(&self) -> Option<&str>;
775
776 fn schedule(&self) -> Option<&ClusterSchedule>;
778
779 fn replication_factor(&self) -> Option<u32>;
781
782 fn auto_scaling_strategy(&self) -> Option<&AutoScalingStrategy>;
785 fn try_to_plan(&self) -> Result<CreateClusterPlan, PlanError>;
788}
789
790pub trait CatalogClusterReplica<'a>: Debug {
792 fn name(&self) -> &str;
794
795 fn cluster_id(&self) -> ClusterId;
797
798 fn replica_id(&self) -> ReplicaId;
800
801 fn owner_id(&self) -> RoleId;
803
804 fn internal(&self) -> bool;
806}
807
808pub trait CatalogItem {
813 fn name(&self) -> &QualifiedItemName;
815
816 fn id(&self) -> CatalogItemId;
818
819 fn global_ids(&self) -> Box<dyn Iterator<Item = GlobalId> + '_>;
821
822 fn oid(&self) -> u32;
824
825 fn func(&self) -> Result<&'static Func, CatalogError>;
830
831 fn source_desc(&self) -> Result<Option<&SourceDesc<ReferencedConnection>>, CatalogError>;
836
837 fn connection(&self) -> Result<Connection<ReferencedConnection>, CatalogError>;
841
842 fn item_type(&self) -> CatalogItemType;
844
845 fn create_sql(&self) -> &str;
848
849 fn references(&self) -> &ResolvedIds;
852
853 fn uses(&self) -> BTreeSet<CatalogItemId>;
856
857 fn referenced_by(&self) -> &[CatalogItemId];
859
860 fn used_by(&self) -> &[CatalogItemId];
862
863 fn subsource_details(
866 &self,
867 ) -> Option<(CatalogItemId, &UnresolvedItemName, &SourceExportDetails)>;
868
869 fn source_export_details(
872 &self,
873 ) -> Option<(
874 CatalogItemId,
875 &UnresolvedItemName,
876 &SourceExportDetails,
877 &SourceExportDataConfig<ReferencedConnection>,
878 )>;
879
880 fn is_progress_source(&self) -> bool;
882
883 fn progress_id(&self) -> Option<CatalogItemId>;
885
886 fn index_details(&self) -> Option<(&[MirScalarExpr], GlobalId)>;
889
890 fn writable_table_details(&self) -> Option<&[Expr<Aug>]>;
893
894 fn replacement_target(&self) -> Option<CatalogItemId>;
896
897 fn type_details(&self) -> Option<&CatalogTypeDetails<IdReference>>;
900
901 fn owner_id(&self) -> RoleId;
903
904 fn privileges(&self) -> &PrivilegeMap;
906
907 fn cluster_id(&self) -> Option<ClusterId>;
909
910 fn at_version(&self, version: RelationVersionSelector) -> Box<dyn CatalogCollectionItem>;
913
914 fn latest_version(&self) -> Option<RelationVersion>;
916}
917
918pub trait CatalogCollectionItem: CatalogItem + Send + Sync {
921 fn relation_desc(&self) -> Option<Cow<'_, RelationDesc>>;
926
927 fn global_id(&self) -> GlobalId;
929}
930
931#[derive(
933 Debug,
934 Deserialize,
935 Clone,
936 Copy,
937 Eq,
938 Hash,
939 Ord,
940 PartialEq,
941 PartialOrd,
942 Serialize
943)]
944pub enum CatalogItemType {
945 Table,
947 Source,
949 Sink,
951 View,
953 MaterializedView,
955 Index,
957 Type,
959 Func,
961 Secret,
963 Connection,
965}
966
967impl CatalogItemType {
968 pub fn conflicts_with_type(&self) -> bool {
987 match self {
988 CatalogItemType::Table => true,
989 CatalogItemType::Source => true,
990 CatalogItemType::View => true,
991 CatalogItemType::MaterializedView => true,
992 CatalogItemType::Index => true,
993 CatalogItemType::Type => true,
994 CatalogItemType::Sink => false,
995 CatalogItemType::Func => false,
996 CatalogItemType::Secret => false,
997 CatalogItemType::Connection => false,
998 }
999 }
1000}
1001
1002impl fmt::Display for CatalogItemType {
1003 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1004 match self {
1005 CatalogItemType::Table => f.write_str("table"),
1006 CatalogItemType::Source => f.write_str("source"),
1007 CatalogItemType::Sink => f.write_str("sink"),
1008 CatalogItemType::View => f.write_str("view"),
1009 CatalogItemType::MaterializedView => f.write_str("materialized view"),
1010 CatalogItemType::Index => f.write_str("index"),
1011 CatalogItemType::Type => f.write_str("type"),
1012 CatalogItemType::Func => f.write_str("func"),
1013 CatalogItemType::Secret => f.write_str("secret"),
1014 CatalogItemType::Connection => f.write_str("connection"),
1015 }
1016 }
1017}
1018
1019impl From<CatalogItemType> for ObjectType {
1020 fn from(value: CatalogItemType) -> Self {
1021 match value {
1022 CatalogItemType::Table => ObjectType::Table,
1023 CatalogItemType::Source => ObjectType::Source,
1024 CatalogItemType::Sink => ObjectType::Sink,
1025 CatalogItemType::View => ObjectType::View,
1026 CatalogItemType::MaterializedView => ObjectType::MaterializedView,
1027 CatalogItemType::Index => ObjectType::Index,
1028 CatalogItemType::Type => ObjectType::Type,
1029 CatalogItemType::Func => ObjectType::Func,
1030 CatalogItemType::Secret => ObjectType::Secret,
1031 CatalogItemType::Connection => ObjectType::Connection,
1032 }
1033 }
1034}
1035
1036impl From<CatalogItemType> for mz_audit_log::ObjectType {
1037 fn from(value: CatalogItemType) -> Self {
1038 match value {
1039 CatalogItemType::Table => mz_audit_log::ObjectType::Table,
1040 CatalogItemType::Source => mz_audit_log::ObjectType::Source,
1041 CatalogItemType::View => mz_audit_log::ObjectType::View,
1042 CatalogItemType::MaterializedView => mz_audit_log::ObjectType::MaterializedView,
1043 CatalogItemType::Index => mz_audit_log::ObjectType::Index,
1044 CatalogItemType::Type => mz_audit_log::ObjectType::Type,
1045 CatalogItemType::Sink => mz_audit_log::ObjectType::Sink,
1046 CatalogItemType::Func => mz_audit_log::ObjectType::Func,
1047 CatalogItemType::Secret => mz_audit_log::ObjectType::Secret,
1048 CatalogItemType::Connection => mz_audit_log::ObjectType::Connection,
1049 }
1050 }
1051}
1052
1053#[derive(Clone, Debug, Eq, PartialEq)]
1055pub struct CatalogTypeDetails<T: TypeReference> {
1056 pub array_id: Option<CatalogItemId>,
1058 pub typ: CatalogType<T>,
1060 pub pg_metadata: Option<CatalogTypePgMetadata>,
1062}
1063
1064#[derive(Clone, Debug, Eq, PartialEq)]
1066pub struct CatalogTypePgMetadata {
1067 pub typinput_oid: u32,
1069 pub typreceive_oid: u32,
1071}
1072
1073pub trait TypeReference {
1075 type Reference: Clone + Debug + Eq + PartialEq;
1077}
1078
1079#[derive(Clone, Debug, Eq, PartialEq)]
1081pub struct NameReference;
1082
1083impl TypeReference for NameReference {
1084 type Reference = &'static str;
1085}
1086
1087#[derive(Clone, Debug, Eq, PartialEq)]
1089pub struct IdReference;
1090
1091impl TypeReference for IdReference {
1092 type Reference = CatalogItemId;
1093}
1094
1095#[allow(missing_docs)]
1101#[derive(Clone, Debug, Eq, PartialEq)]
1102pub enum CatalogType<T: TypeReference> {
1103 AclItem,
1104 Array {
1105 element_reference: T::Reference,
1106 },
1107 Bool,
1108 Bytes,
1109 Char,
1110 Date,
1111 Float32,
1112 Float64,
1113 Int16,
1114 Int32,
1115 Int64,
1116 UInt16,
1117 UInt32,
1118 UInt64,
1119 MzTimestamp,
1120 Interval,
1121 Jsonb,
1122 List {
1123 element_reference: T::Reference,
1124 element_modifiers: Vec<i64>,
1125 },
1126 Map {
1127 key_reference: T::Reference,
1128 key_modifiers: Vec<i64>,
1129 value_reference: T::Reference,
1130 value_modifiers: Vec<i64>,
1131 },
1132 Numeric,
1133 Oid,
1134 PgLegacyChar,
1135 PgLegacyName,
1136 Pseudo,
1137 Range {
1138 element_reference: T::Reference,
1139 },
1140 Record {
1141 fields: Vec<CatalogRecordField<T>>,
1142 },
1143 RegClass,
1144 RegProc,
1145 RegType,
1146 String,
1147 Time,
1148 Timestamp,
1149 TimestampTz,
1150 Uuid,
1151 VarChar,
1152 Int2Vector,
1153 MzAclItem,
1154}
1155
1156impl CatalogType<IdReference> {
1157 pub fn desc(&self, catalog: &dyn SessionCatalog) -> Result<Option<RelationDesc>, PlanError> {
1160 match &self {
1161 CatalogType::Record { fields } => {
1162 let mut desc = RelationDesc::builder();
1163 let mut budget = query::TypeResolutionBudget::for_root(catalog);
1168 for f in fields {
1169 let name = f.name.clone();
1170 let ty = budget.resolve_child(catalog, f.type_reference, &f.type_modifiers)?;
1171 let ty = ty.nullable(true);
1174 desc = desc.with_column(name, ty);
1175 }
1176 Ok(Some(desc.finish()))
1177 }
1178 _ => Ok(None),
1179 }
1180 }
1181}
1182
1183#[derive(Clone, Debug, Eq, PartialEq)]
1185pub struct CatalogRecordField<T: TypeReference> {
1186 pub name: ColumnName,
1188 pub type_reference: T::Reference,
1190 pub type_modifiers: Vec<i64>,
1192}
1193
1194#[derive(Clone, Debug, Eq, PartialEq)]
1195pub enum TypeCategory {
1203 Array,
1205 BitString,
1207 Boolean,
1209 Composite,
1211 DateTime,
1213 Enum,
1215 Geometric,
1217 List,
1219 NetworkAddress,
1221 Numeric,
1223 Pseudo,
1225 Range,
1227 String,
1229 Timespan,
1231 UserDefined,
1233 Unknown,
1235}
1236
1237impl fmt::Display for TypeCategory {
1238 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1239 f.write_str(match self {
1240 TypeCategory::Array => "array",
1241 TypeCategory::BitString => "bit-string",
1242 TypeCategory::Boolean => "boolean",
1243 TypeCategory::Composite => "composite",
1244 TypeCategory::DateTime => "date-time",
1245 TypeCategory::Enum => "enum",
1246 TypeCategory::Geometric => "geometric",
1247 TypeCategory::List => "list",
1248 TypeCategory::NetworkAddress => "network-address",
1249 TypeCategory::Numeric => "numeric",
1250 TypeCategory::Pseudo => "pseudo",
1251 TypeCategory::Range => "range",
1252 TypeCategory::String => "string",
1253 TypeCategory::Timespan => "timespan",
1254 TypeCategory::UserDefined => "user-defined",
1255 TypeCategory::Unknown => "unknown",
1256 })
1257 }
1258}
1259
1260#[derive(Debug, Clone, PartialEq)]
1284pub struct EnvironmentId {
1285 cloud_provider: CloudProvider,
1286 cloud_provider_region: String,
1287 organization_id: Uuid,
1288 ordinal: u64,
1289}
1290
1291impl EnvironmentId {
1292 pub fn for_tests() -> EnvironmentId {
1294 EnvironmentId {
1295 cloud_provider: CloudProvider::Local,
1296 cloud_provider_region: "az1".into(),
1297 organization_id: Uuid::new_v4(),
1298 ordinal: 0,
1299 }
1300 }
1301
1302 pub fn cloud_provider(&self) -> &CloudProvider {
1304 &self.cloud_provider
1305 }
1306
1307 pub fn cloud_provider_region(&self) -> &str {
1309 &self.cloud_provider_region
1310 }
1311
1312 pub fn region(&self) -> String {
1317 format!("{}/{}", self.cloud_provider, self.cloud_provider_region)
1318 }
1319
1320 pub fn organization_id(&self) -> Uuid {
1322 self.organization_id
1323 }
1324
1325 pub fn ordinal(&self) -> u64 {
1327 self.ordinal
1328 }
1329}
1330
1331impl fmt::Display for EnvironmentId {
1337 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1338 write!(
1339 f,
1340 "{}-{}-{}-{}",
1341 self.cloud_provider, self.cloud_provider_region, self.organization_id, self.ordinal
1342 )
1343 }
1344}
1345
1346impl FromStr for EnvironmentId {
1347 type Err = InvalidEnvironmentIdError;
1348
1349 fn from_str(s: &str) -> Result<EnvironmentId, InvalidEnvironmentIdError> {
1350 static MATCHER: LazyLock<Regex> = LazyLock::new(|| {
1351 Regex::new(
1352 "^(?P<cloud_provider>[[:alnum:]]+)-\
1353 (?P<cloud_provider_region>[[:alnum:]\\-]+)-\
1354 (?P<organization_id>[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})-\
1355 (?P<ordinal>\\d{1,8})$"
1356 ).unwrap()
1357 });
1358 let captures = MATCHER.captures(s).ok_or(InvalidEnvironmentIdError)?;
1359 Ok(EnvironmentId {
1360 cloud_provider: CloudProvider::from_str(&captures["cloud_provider"])?,
1361 cloud_provider_region: captures["cloud_provider_region"].into(),
1362 organization_id: captures["organization_id"]
1363 .parse()
1364 .map_err(|_| InvalidEnvironmentIdError)?,
1365 ordinal: captures["ordinal"]
1366 .parse()
1367 .map_err(|_| InvalidEnvironmentIdError)?,
1368 })
1369 }
1370}
1371
1372#[derive(Debug, Clone, PartialEq)]
1374pub struct InvalidEnvironmentIdError;
1375
1376impl fmt::Display for InvalidEnvironmentIdError {
1377 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1378 f.write_str("invalid environment ID")
1379 }
1380}
1381
1382impl Error for InvalidEnvironmentIdError {}
1383
1384impl From<InvalidCloudProviderError> for InvalidEnvironmentIdError {
1385 fn from(_: InvalidCloudProviderError) -> Self {
1386 InvalidEnvironmentIdError
1387 }
1388}
1389
1390#[derive(Clone, Debug, Eq, PartialEq)]
1392pub enum CatalogError {
1393 UnknownDatabase(String),
1395 DatabaseAlreadyExists(String),
1397 UnknownSchema(String),
1399 SchemaAlreadyExists(String),
1401 UnknownRole(String),
1403 RoleAlreadyExists(String),
1405 NetworkPolicyAlreadyExists(String),
1407 UnknownCluster(String),
1409 UnexpectedBuiltinCluster(String),
1411 UnexpectedBuiltinClusterType(String),
1413 ClusterAlreadyExists(String),
1415 UnknownClusterReplica(String),
1417 UnknownClusterReplicaSize(String),
1419 DuplicateReplica(String, String),
1421 UnknownItem(String),
1423 ItemAlreadyExists(CatalogItemId, String),
1425 UnknownFunction {
1427 name: String,
1429 alternative: Option<String>,
1431 },
1432 UnknownType {
1434 name: String,
1436 },
1437 UnknownConnection(String),
1439 UnknownNetworkPolicy(String),
1441 UnexpectedType {
1443 name: String,
1445 actual_type: CatalogItemType,
1447 expected_type: CatalogItemType,
1449 },
1450 IdExhaustion,
1452 OidExhaustion,
1454 TimelineAlreadyExists(String),
1456 IdAllocatorAlreadyExists(String),
1458 ConfigAlreadyExists(String),
1460 FailedBuiltinSchemaMigration(String),
1462 StorageCollectionMetadataAlreadyExists(GlobalId),
1464}
1465
1466impl fmt::Display for CatalogError {
1467 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1468 match self {
1469 Self::UnknownDatabase(name) => write!(f, "unknown database '{}'", name),
1470 Self::DatabaseAlreadyExists(name) => write!(f, "database '{name}' already exists"),
1471 Self::UnknownFunction { name, .. } => write!(f, "function \"{}\" does not exist", name),
1472 Self::UnknownType { name, .. } => write!(f, "type \"{}\" does not exist", name),
1473 Self::UnknownConnection(name) => write!(f, "connection \"{}\" does not exist", name),
1474 Self::UnknownSchema(name) => write!(f, "unknown schema '{}'", name),
1475 Self::SchemaAlreadyExists(name) => write!(f, "schema '{name}' already exists"),
1476 Self::UnknownRole(name) => write!(f, "unknown role '{}'", name),
1477 Self::RoleAlreadyExists(name) => write!(f, "role '{name}' already exists"),
1478 Self::NetworkPolicyAlreadyExists(name) => {
1479 write!(f, "network policy '{name}' already exists")
1480 }
1481 Self::UnknownCluster(name) => write!(f, "unknown cluster '{}'", name),
1482 Self::UnknownNetworkPolicy(name) => write!(f, "unknown network policy '{}'", name),
1483 Self::UnexpectedBuiltinCluster(name) => {
1484 write!(f, "Unexpected builtin cluster '{}'", name)
1485 }
1486 Self::UnexpectedBuiltinClusterType(name) => {
1487 write!(f, "Unexpected builtin cluster type'{}'", name)
1488 }
1489 Self::ClusterAlreadyExists(name) => write!(f, "cluster '{name}' already exists"),
1490 Self::UnknownClusterReplica(name) => {
1491 write!(f, "unknown cluster replica '{}'", name)
1492 }
1493 Self::UnknownClusterReplicaSize(name) => {
1494 write!(f, "unknown cluster replica size '{}'", name)
1495 }
1496 Self::DuplicateReplica(replica_name, cluster_name) => write!(
1497 f,
1498 "cannot create multiple replicas named '{replica_name}' on cluster '{cluster_name}'"
1499 ),
1500 Self::UnknownItem(name) => write!(f, "unknown catalog item '{}'", name),
1501 Self::ItemAlreadyExists(_gid, name) => {
1502 write!(f, "catalog item '{name}' already exists")
1503 }
1504 Self::UnexpectedType {
1505 name,
1506 actual_type,
1507 expected_type,
1508 } => {
1509 write!(f, "\"{name}\" is a {actual_type} not a {expected_type}")
1510 }
1511 Self::IdExhaustion => write!(f, "id counter overflows i64"),
1512 Self::OidExhaustion => write!(f, "oid counter overflows u32"),
1513 Self::TimelineAlreadyExists(name) => write!(f, "timeline '{name}' already exists"),
1514 Self::IdAllocatorAlreadyExists(name) => {
1515 write!(f, "ID allocator '{name}' already exists")
1516 }
1517 Self::ConfigAlreadyExists(key) => write!(f, "config '{key}' already exists"),
1518 Self::FailedBuiltinSchemaMigration(objects) => {
1519 write!(f, "failed to migrate schema of builtin objects: {objects}")
1520 }
1521 Self::StorageCollectionMetadataAlreadyExists(key) => {
1522 write!(f, "storage metadata for '{key}' already exists")
1523 }
1524 }
1525 }
1526}
1527
1528impl CatalogError {
1529 pub fn hint(&self) -> Option<String> {
1531 match self {
1532 CatalogError::UnknownFunction { alternative, .. } => {
1533 match alternative {
1534 None => Some("No function matches the given name and argument types. You might need to add explicit type casts.".into()),
1535 Some(alt) => Some(format!("Try using {alt}")),
1536 }
1537 }
1538 _ => None,
1539 }
1540 }
1541}
1542
1543impl Error for CatalogError {}
1544
1545#[allow(missing_docs)]
1547#[derive(
1548 Debug,
1549 Clone,
1550 PartialOrd,
1551 Ord,
1552 PartialEq,
1553 Eq,
1554 Hash,
1555 Copy,
1556 Deserialize,
1557 Serialize
1558)]
1559pub enum ObjectType {
1561 Table,
1562 View,
1563 MaterializedView,
1564 Source,
1565 Sink,
1566 Index,
1567 Type,
1568 Role,
1569 Cluster,
1570 ClusterReplica,
1571 Secret,
1572 Connection,
1573 Database,
1574 Schema,
1575 Func,
1576 NetworkPolicy,
1577}
1578
1579impl ObjectType {
1580 pub fn is_relation(&self) -> bool {
1582 match self {
1583 ObjectType::Table
1584 | ObjectType::View
1585 | ObjectType::MaterializedView
1586 | ObjectType::Source => true,
1587 ObjectType::Sink
1588 | ObjectType::Index
1589 | ObjectType::Type
1590 | ObjectType::Secret
1591 | ObjectType::Connection
1592 | ObjectType::Func
1593 | ObjectType::Database
1594 | ObjectType::Schema
1595 | ObjectType::Cluster
1596 | ObjectType::ClusterReplica
1597 | ObjectType::Role
1598 | ObjectType::NetworkPolicy => false,
1599 }
1600 }
1601}
1602
1603impl From<mz_sql_parser::ast::ObjectType> for ObjectType {
1604 fn from(value: mz_sql_parser::ast::ObjectType) -> Self {
1605 match value {
1606 mz_sql_parser::ast::ObjectType::Table => ObjectType::Table,
1607 mz_sql_parser::ast::ObjectType::View => ObjectType::View,
1608 mz_sql_parser::ast::ObjectType::MaterializedView => ObjectType::MaterializedView,
1609 mz_sql_parser::ast::ObjectType::Source => ObjectType::Source,
1610 mz_sql_parser::ast::ObjectType::Subsource => ObjectType::Source,
1611 mz_sql_parser::ast::ObjectType::Sink => ObjectType::Sink,
1612 mz_sql_parser::ast::ObjectType::Index => ObjectType::Index,
1613 mz_sql_parser::ast::ObjectType::Type => ObjectType::Type,
1614 mz_sql_parser::ast::ObjectType::Role => ObjectType::Role,
1615 mz_sql_parser::ast::ObjectType::Cluster => ObjectType::Cluster,
1616 mz_sql_parser::ast::ObjectType::ClusterReplica => ObjectType::ClusterReplica,
1617 mz_sql_parser::ast::ObjectType::Secret => ObjectType::Secret,
1618 mz_sql_parser::ast::ObjectType::Connection => ObjectType::Connection,
1619 mz_sql_parser::ast::ObjectType::Database => ObjectType::Database,
1620 mz_sql_parser::ast::ObjectType::Schema => ObjectType::Schema,
1621 mz_sql_parser::ast::ObjectType::Func => ObjectType::Func,
1622 mz_sql_parser::ast::ObjectType::NetworkPolicy => ObjectType::NetworkPolicy,
1623 }
1624 }
1625}
1626
1627impl From<CommentObjectId> for ObjectType {
1628 fn from(value: CommentObjectId) -> ObjectType {
1629 match value {
1630 CommentObjectId::Table(_) => ObjectType::Table,
1631 CommentObjectId::View(_) => ObjectType::View,
1632 CommentObjectId::MaterializedView(_) => ObjectType::MaterializedView,
1633 CommentObjectId::Source(_) => ObjectType::Source,
1634 CommentObjectId::Sink(_) => ObjectType::Sink,
1635 CommentObjectId::Index(_) => ObjectType::Index,
1636 CommentObjectId::Func(_) => ObjectType::Func,
1637 CommentObjectId::Connection(_) => ObjectType::Connection,
1638 CommentObjectId::Type(_) => ObjectType::Type,
1639 CommentObjectId::Secret(_) => ObjectType::Secret,
1640 CommentObjectId::Role(_) => ObjectType::Role,
1641 CommentObjectId::Database(_) => ObjectType::Database,
1642 CommentObjectId::Schema(_) => ObjectType::Schema,
1643 CommentObjectId::Cluster(_) => ObjectType::Cluster,
1644 CommentObjectId::ClusterReplica(_) => ObjectType::ClusterReplica,
1645 CommentObjectId::NetworkPolicy(_) => ObjectType::NetworkPolicy,
1646 }
1647 }
1648}
1649
1650impl Display for ObjectType {
1651 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1652 f.write_str(match self {
1653 ObjectType::Table => "TABLE",
1654 ObjectType::View => "VIEW",
1655 ObjectType::MaterializedView => "MATERIALIZED VIEW",
1656 ObjectType::Source => "SOURCE",
1657 ObjectType::Sink => "SINK",
1658 ObjectType::Index => "INDEX",
1659 ObjectType::Type => "TYPE",
1660 ObjectType::Role => "ROLE",
1661 ObjectType::Cluster => "CLUSTER",
1662 ObjectType::ClusterReplica => "CLUSTER REPLICA",
1663 ObjectType::Secret => "SECRET",
1664 ObjectType::Connection => "CONNECTION",
1665 ObjectType::Database => "DATABASE",
1666 ObjectType::Schema => "SCHEMA",
1667 ObjectType::Func => "FUNCTION",
1668 ObjectType::NetworkPolicy => "NETWORK POLICY",
1669 })
1670 }
1671}
1672
1673#[derive(
1674 Debug,
1675 Clone,
1676 PartialOrd,
1677 Ord,
1678 PartialEq,
1679 Eq,
1680 Hash,
1681 Copy,
1682 Deserialize,
1683 Serialize
1684)]
1685pub enum SystemObjectType {
1687 Object(ObjectType),
1689 System,
1691}
1692
1693impl SystemObjectType {
1694 pub fn is_relation(&self) -> bool {
1696 match self {
1697 SystemObjectType::Object(object_type) => object_type.is_relation(),
1698 SystemObjectType::System => false,
1699 }
1700 }
1701}
1702
1703impl Display for SystemObjectType {
1704 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1705 match self {
1706 SystemObjectType::Object(object_type) => std::fmt::Display::fmt(&object_type, f),
1707 SystemObjectType::System => f.write_str("SYSTEM"),
1708 }
1709 }
1710}
1711
1712#[derive(Debug, Clone, PartialEq, Eq)]
1714pub enum ErrorMessageObjectDescription {
1715 Object {
1717 object_type: ObjectType,
1719 object_name: Option<String>,
1721 },
1722 System,
1724}
1725
1726impl ErrorMessageObjectDescription {
1727 pub fn from_id(
1729 object_id: &ObjectId,
1730 catalog: &dyn SessionCatalog,
1731 ) -> ErrorMessageObjectDescription {
1732 let object_name = match object_id {
1733 ObjectId::Cluster(cluster_id) => catalog.get_cluster(*cluster_id).name().to_string(),
1734 ObjectId::ClusterReplica((cluster_id, replica_id)) => catalog
1735 .get_cluster_replica(*cluster_id, *replica_id)
1736 .name()
1737 .to_string(),
1738 ObjectId::Database(database_id) => catalog.get_database(database_id).name().to_string(),
1739 ObjectId::Schema((database_spec, schema_spec)) => {
1740 let name = catalog.get_schema(database_spec, schema_spec).name();
1741 catalog.resolve_full_schema_name(name).to_string()
1742 }
1743 ObjectId::Role(role_id) => catalog.get_role(role_id).name().to_string(),
1744 ObjectId::Item(id) => {
1745 let name = catalog.get_item(id).name();
1746 catalog.resolve_full_name(name).to_string()
1747 }
1748 ObjectId::NetworkPolicy(network_policy_id) => catalog
1749 .get_network_policy(network_policy_id)
1750 .name()
1751 .to_string(),
1752 };
1753 ErrorMessageObjectDescription::Object {
1754 object_type: catalog.get_object_type(object_id),
1755 object_name: Some(object_name),
1756 }
1757 }
1758
1759 pub fn from_sys_id(
1761 object_id: &SystemObjectId,
1762 catalog: &dyn SessionCatalog,
1763 ) -> ErrorMessageObjectDescription {
1764 match object_id {
1765 SystemObjectId::Object(object_id) => {
1766 ErrorMessageObjectDescription::from_id(object_id, catalog)
1767 }
1768 SystemObjectId::System => ErrorMessageObjectDescription::System,
1769 }
1770 }
1771
1772 pub fn from_object_type(object_type: SystemObjectType) -> ErrorMessageObjectDescription {
1774 match object_type {
1775 SystemObjectType::Object(object_type) => ErrorMessageObjectDescription::Object {
1776 object_type,
1777 object_name: None,
1778 },
1779 SystemObjectType::System => ErrorMessageObjectDescription::System,
1780 }
1781 }
1782}
1783
1784impl Display for ErrorMessageObjectDescription {
1785 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1786 match self {
1787 ErrorMessageObjectDescription::Object {
1788 object_type,
1789 object_name,
1790 } => {
1791 let object_name = object_name
1792 .as_ref()
1793 .map(|object_name| format!(" {}", object_name.quoted()))
1794 .unwrap_or_else(|| "".to_string());
1795 write!(f, "{object_type}{object_name}")
1796 }
1797 ErrorMessageObjectDescription::System => f.write_str("SYSTEM"),
1798 }
1799 }
1800}
1801
1802#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd)]
1803#[serde(into = "BTreeMap<String, RoleId>")]
1806#[serde(try_from = "BTreeMap<String, RoleId>")]
1807pub struct RoleMembership {
1809 pub map: BTreeMap<RoleId, RoleId>,
1815}
1816
1817impl RoleMembership {
1818 pub fn new() -> RoleMembership {
1820 RoleMembership {
1821 map: BTreeMap::new(),
1822 }
1823 }
1824}
1825
1826impl From<RoleMembership> for BTreeMap<String, RoleId> {
1827 fn from(value: RoleMembership) -> Self {
1828 value
1829 .map
1830 .into_iter()
1831 .map(|(k, v)| (k.to_string(), v))
1832 .collect()
1833 }
1834}
1835
1836impl TryFrom<BTreeMap<String, RoleId>> for RoleMembership {
1837 type Error = anyhow::Error;
1838
1839 fn try_from(value: BTreeMap<String, RoleId>) -> Result<Self, Self::Error> {
1840 Ok(RoleMembership {
1841 map: value
1842 .into_iter()
1843 .map(|(k, v)| Ok((RoleId::from_str(&k)?, v)))
1844 .collect::<Result<_, anyhow::Error>>()?,
1845 })
1846 }
1847}
1848
1849#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize)]
1851pub struct DefaultPrivilegeObject {
1852 pub role_id: RoleId,
1854 pub database_id: Option<DatabaseId>,
1856 pub schema_id: Option<SchemaId>,
1858 pub object_type: ObjectType,
1860}
1861
1862impl DefaultPrivilegeObject {
1863 pub fn new(
1865 role_id: RoleId,
1866 database_id: Option<DatabaseId>,
1867 schema_id: Option<SchemaId>,
1868 object_type: ObjectType,
1869 ) -> DefaultPrivilegeObject {
1870 DefaultPrivilegeObject {
1871 role_id,
1872 database_id,
1873 schema_id,
1874 object_type,
1875 }
1876 }
1877}
1878
1879impl std::fmt::Display for DefaultPrivilegeObject {
1880 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1881 write!(f, "{self:?}")
1883 }
1884}
1885
1886#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize)]
1888pub struct DefaultPrivilegeAclItem {
1889 pub grantee: RoleId,
1891 pub acl_mode: AclMode,
1893}
1894
1895impl DefaultPrivilegeAclItem {
1896 pub fn new(grantee: RoleId, acl_mode: AclMode) -> DefaultPrivilegeAclItem {
1898 DefaultPrivilegeAclItem { grantee, acl_mode }
1899 }
1900
1901 pub fn mz_acl_item(self, grantor: RoleId) -> MzAclItem {
1903 MzAclItem {
1904 grantee: self.grantee,
1905 grantor,
1906 acl_mode: self.acl_mode,
1907 }
1908 }
1909}
1910
1911#[cfg(test)]
1912mod tests {
1913 use super::{CloudProvider, EnvironmentId, InvalidEnvironmentIdError};
1914
1915 #[mz_ore::test]
1916 fn test_environment_id() {
1917 for (input, expected) in [
1918 (
1919 "local-az1-1497a3b7-a455-4fc4-8752-b44a94b5f90a-452",
1920 Ok(EnvironmentId {
1921 cloud_provider: CloudProvider::Local,
1922 cloud_provider_region: "az1".into(),
1923 organization_id: "1497a3b7-a455-4fc4-8752-b44a94b5f90a".parse().unwrap(),
1924 ordinal: 452,
1925 }),
1926 ),
1927 (
1928 "aws-us-east-1-1497a3b7-a455-4fc4-8752-b44a94b5f90a-0",
1929 Ok(EnvironmentId {
1930 cloud_provider: CloudProvider::Aws,
1931 cloud_provider_region: "us-east-1".into(),
1932 organization_id: "1497a3b7-a455-4fc4-8752-b44a94b5f90a".parse().unwrap(),
1933 ordinal: 0,
1934 }),
1935 ),
1936 (
1937 "gcp-us-central1-1497a3b7-a455-4fc4-8752-b44a94b5f90a-0",
1938 Ok(EnvironmentId {
1939 cloud_provider: CloudProvider::Gcp,
1940 cloud_provider_region: "us-central1".into(),
1941 organization_id: "1497a3b7-a455-4fc4-8752-b44a94b5f90a".parse().unwrap(),
1942 ordinal: 0,
1943 }),
1944 ),
1945 (
1946 "azure-australiaeast-1497a3b7-a455-4fc4-8752-b44a94b5f90a-0",
1947 Ok(EnvironmentId {
1948 cloud_provider: CloudProvider::Azure,
1949 cloud_provider_region: "australiaeast".into(),
1950 organization_id: "1497a3b7-a455-4fc4-8752-b44a94b5f90a".parse().unwrap(),
1951 ordinal: 0,
1952 }),
1953 ),
1954 (
1955 "generic-moon-station-11-darkside-1497a3b7-a455-4fc4-8752-b44a94b5f90a-0",
1956 Ok(EnvironmentId {
1957 cloud_provider: CloudProvider::Generic,
1958 cloud_provider_region: "moon-station-11-darkside".into(),
1959 organization_id: "1497a3b7-a455-4fc4-8752-b44a94b5f90a".parse().unwrap(),
1960 ordinal: 0,
1961 }),
1962 ),
1963 ("", Err(InvalidEnvironmentIdError)),
1964 (
1965 "local-az1-1497a3b7-a455-4fc4-8752-b44a94b5f90a-123456789",
1966 Err(InvalidEnvironmentIdError),
1967 ),
1968 (
1969 "local-1497a3b7-a455-4fc4-8752-b44a94b5f90a-452",
1970 Err(InvalidEnvironmentIdError),
1971 ),
1972 (
1973 "local-az1-1497a3b7-a455-4fc48752-b44a94b5f90a-452",
1974 Err(InvalidEnvironmentIdError),
1975 ),
1976 ] {
1977 let actual = input.parse();
1978 assert_eq!(expected, actual, "input = {}", input);
1979 if let Ok(actual) = actual {
1980 assert_eq!(input, actual.to_string(), "input = {}", input);
1981 }
1982 }
1983 }
1984}