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::{ClusterSchedule, CreateClusterPlan, PlanError, PlanNotice, query};
57use crate::session::vars::{OwnedVarInput, SystemVars};
58
59pub trait SessionCatalog: fmt::Debug + ExprHumanizer + Send + Sync + ConnectionResolver {
88 fn active_role_id(&self) -> &RoleId;
90
91 fn active_database_name(&self) -> Option<&str> {
93 self.active_database()
94 .map(|id| self.get_database(id))
95 .map(|db| db.name())
96 }
97
98 fn active_database(&self) -> Option<&DatabaseId>;
100
101 fn active_cluster(&self) -> &str;
103
104 fn search_path(&self) -> &[(ResolvedDatabaseSpecifier, SchemaSpecifier)];
106
107 fn get_prepared_statement_desc(&self, name: &str) -> Option<&StatementDesc>;
110
111 fn get_portal_desc_unverified(&self, portal_name: &str) -> Option<&StatementDesc>;
115
116 fn resolve_database(&self, database_name: &str) -> Result<&dyn CatalogDatabase, CatalogError>;
121
122 fn get_database(&self, id: &DatabaseId) -> &dyn CatalogDatabase;
126
127 fn get_databases(&self) -> Vec<&dyn CatalogDatabase>;
129
130 fn resolve_schema(
135 &self,
136 database_name: Option<&str>,
137 schema_name: &str,
138 ) -> Result<&dyn CatalogSchema, CatalogError>;
139
140 fn resolve_schema_in_database(
145 &self,
146 database_spec: &ResolvedDatabaseSpecifier,
147 schema_name: &str,
148 ) -> Result<&dyn CatalogSchema, CatalogError>;
149
150 fn get_schema(
154 &self,
155 database_spec: &ResolvedDatabaseSpecifier,
156 schema_spec: &SchemaSpecifier,
157 ) -> &dyn CatalogSchema;
158
159 fn get_schemas(&self) -> Vec<&dyn CatalogSchema>;
161
162 fn get_mz_internal_schema_id(&self) -> SchemaId;
164
165 fn get_mz_unsafe_schema_id(&self) -> SchemaId;
167
168 fn is_system_schema_specifier(&self, schema: SchemaSpecifier) -> bool;
170
171 fn resolve_role(&self, role_name: &str) -> Result<&dyn CatalogRole, CatalogError>;
173
174 fn resolve_network_policy(
176 &self,
177 network_policy_name: &str,
178 ) -> Result<&dyn CatalogNetworkPolicy, CatalogError>;
179
180 fn try_get_role(&self, id: &RoleId) -> Option<&dyn CatalogRole>;
182
183 fn get_role(&self, id: &RoleId) -> &dyn CatalogRole;
187
188 fn get_roles(&self) -> Vec<&dyn CatalogRole>;
190
191 fn mz_system_role_id(&self) -> RoleId;
193
194 fn collect_role_membership(&self, id: &RoleId) -> BTreeSet<RoleId>;
196
197 fn get_network_policy(&self, id: &NetworkPolicyId) -> &dyn CatalogNetworkPolicy;
202
203 fn get_network_policies(&self) -> Vec<&dyn CatalogNetworkPolicy>;
205
206 fn resolve_cluster<'a, 'b>(
209 &'a self,
210 cluster_name: Option<&'b str>,
211 ) -> Result<&'a dyn CatalogCluster<'a>, CatalogError>;
212
213 fn resolve_cluster_replica<'a, 'b>(
215 &'a self,
216 cluster_replica_name: &'b QualifiedReplica,
217 ) -> Result<&'a dyn CatalogClusterReplica<'a>, CatalogError>;
218
219 fn resolve_item(&self, item_name: &PartialItemName) -> Result<&dyn CatalogItem, CatalogError>;
234
235 fn resolve_function(
238 &self,
239 item_name: &PartialItemName,
240 ) -> Result<&dyn CatalogItem, CatalogError>;
241
242 fn resolve_type(&self, item_name: &PartialItemName) -> Result<&dyn CatalogItem, CatalogError>;
245
246 fn resolve_item_or_type(
248 &self,
249 name: &PartialItemName,
250 ) -> Result<&dyn CatalogItem, CatalogError> {
251 if let Ok(ty) = self.resolve_type(name) {
252 return Ok(ty);
253 }
254 self.resolve_item(name)
255 }
256
257 fn get_system_type(&self, name: &str) -> &dyn CatalogItem;
263
264 fn try_get_item(&self, id: &CatalogItemId) -> Option<&dyn CatalogItem>;
266
267 fn try_get_item_by_global_id<'a>(
272 &'a self,
273 id: &GlobalId,
274 ) -> Option<Box<dyn CatalogCollectionItem + 'a>>;
275
276 fn get_item(&self, id: &CatalogItemId) -> &dyn CatalogItem;
280
281 fn get_item_by_global_id<'a>(&'a self, id: &GlobalId) -> Box<dyn CatalogCollectionItem + 'a>;
287
288 fn get_items(&self) -> Vec<&dyn CatalogItem>;
290
291 fn get_item_by_name(&self, name: &QualifiedItemName) -> Option<&dyn CatalogItem>;
293
294 fn get_type_by_name(&self, name: &QualifiedItemName) -> Option<&dyn CatalogItem>;
296
297 fn get_cluster(&self, id: ClusterId) -> &dyn CatalogCluster<'_>;
299
300 fn get_clusters(&self) -> Vec<&dyn CatalogCluster<'_>>;
302
303 fn get_cluster_replica(
305 &self,
306 cluster_id: ClusterId,
307 replica_id: ReplicaId,
308 ) -> &dyn CatalogClusterReplica<'_>;
309
310 fn get_cluster_replicas(&self) -> Vec<&dyn CatalogClusterReplica<'_>>;
312
313 fn get_system_privileges(&self) -> &PrivilegeMap;
315
316 fn get_default_privileges(
318 &self,
319 ) -> Vec<(&DefaultPrivilegeObject, Vec<&DefaultPrivilegeAclItem>)>;
320
321 fn find_available_name(&self, name: QualifiedItemName) -> QualifiedItemName;
325
326 fn resolve_full_name(&self, name: &QualifiedItemName) -> FullItemName;
328
329 fn resolve_full_schema_name(&self, name: &QualifiedSchemaName) -> FullSchemaName;
332
333 fn resolve_item_id(&self, global_id: &GlobalId) -> CatalogItemId;
335
336 fn resolve_global_id(
338 &self,
339 item_id: &CatalogItemId,
340 version: RelationVersionSelector,
341 ) -> GlobalId;
342
343 fn config(&self) -> &CatalogConfig;
345
346 fn now(&self) -> EpochMillis;
350
351 fn aws_privatelink_availability_zones(&self) -> Option<BTreeSet<String>>;
353
354 fn system_vars(&self) -> &SystemVars;
356
357 fn system_vars_mut(&mut self) -> &mut SystemVars;
364
365 fn get_owner_id(&self, id: &ObjectId) -> Option<RoleId>;
367
368 fn get_privileges(&self, id: &SystemObjectId) -> Option<&PrivilegeMap>;
370
371 fn object_dependents(&self, ids: &Vec<ObjectId>) -> Vec<ObjectId>;
377
378 fn item_dependents(&self, id: CatalogItemId) -> Vec<ObjectId>;
384
385 fn all_object_privileges(&self, object_type: SystemObjectType) -> AclMode;
387
388 fn get_object_type(&self, object_id: &ObjectId) -> ObjectType;
390
391 fn get_system_object_type(&self, id: &SystemObjectId) -> SystemObjectType;
393
394 fn minimal_qualification(&self, qualified_name: &QualifiedItemName) -> PartialItemName;
397
398 fn add_notice(&self, notice: PlanNotice);
401
402 fn get_item_comments(&self, id: &CatalogItemId) -> Option<&BTreeMap<Option<usize>, String>>;
404
405 fn is_cluster_size_cc(&self, size: &str) -> bool;
408}
409
410#[derive(Debug, Clone)]
412pub struct CatalogConfig {
413 pub start_time: DateTime<Utc>,
415 pub start_instant: Instant,
417 pub nonce: u64,
422 pub environment_id: EnvironmentId,
424 pub session_id: Uuid,
426 pub build_info: &'static BuildInfo,
428 pub now: NowFn,
431 pub connection_context: ConnectionContext,
433 pub builtins_cfg: BuiltinsConfig,
435 pub helm_chart_version: Option<String>,
437}
438
439pub trait CatalogDatabase {
441 fn name(&self) -> &str;
443
444 fn id(&self) -> DatabaseId;
446
447 fn has_schemas(&self) -> bool;
449
450 fn schema_ids(&self) -> &BTreeMap<String, SchemaId>;
453
454 fn schemas(&self) -> Vec<&dyn CatalogSchema>;
456
457 fn owner_id(&self) -> RoleId;
459
460 fn privileges(&self) -> &PrivilegeMap;
462}
463
464pub trait CatalogSchema {
466 fn database(&self) -> &ResolvedDatabaseSpecifier;
468
469 fn name(&self) -> &QualifiedSchemaName;
471
472 fn id(&self) -> &SchemaSpecifier;
474
475 fn has_items(&self) -> bool;
477
478 fn item_ids(&self) -> Box<dyn Iterator<Item = CatalogItemId> + '_>;
480
481 fn owner_id(&self) -> RoleId;
483
484 fn privileges(&self) -> &PrivilegeMap;
486}
487
488#[derive(Debug, Clone, Eq, PartialEq, Arbitrary)]
490pub struct PasswordConfig {
491 pub password: Password,
493 pub scram_iterations: NonZeroU32,
495}
496
497#[derive(Debug, Clone, Eq, PartialEq, Arbitrary)]
499pub enum PasswordAction {
500 Set(PasswordConfig),
502 Clear,
504 NoChange,
506}
507
508#[derive(
510 Debug,
511 Copy,
512 Clone,
513 Eq,
514 PartialEq,
515 Ord,
516 PartialOrd,
517 Serialize,
518 Deserialize,
519 Arbitrary
520)]
521pub enum AutoProvisionSource {
522 Oidc,
524 Frontegg,
526 None,
528}
529
530#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Arbitrary)]
535pub struct RoleAttributesRaw {
536 pub inherit: bool,
538 pub password: Option<Password>,
540 pub scram_iterations: Option<NonZeroU32>,
542 pub superuser: Option<bool>,
544 pub login: Option<bool>,
546 pub auto_provision_source: Option<AutoProvisionSource>,
548 _private: (),
550}
551
552#[derive(
554 Debug,
555 Clone,
556 Eq,
557 Serialize,
558 Deserialize,
559 PartialEq,
560 Ord,
561 PartialOrd,
562 Arbitrary
563)]
564pub struct RoleAttributes {
565 pub inherit: bool,
567 pub superuser: Option<bool>,
569 pub login: Option<bool>,
571 pub auto_provision_source: Option<AutoProvisionSource>,
573 _private: (),
575}
576
577impl RoleAttributesRaw {
578 pub const fn new() -> RoleAttributesRaw {
580 RoleAttributesRaw {
581 inherit: true,
582 password: None,
583 scram_iterations: None,
584 superuser: None,
585 login: None,
586 auto_provision_source: None,
587 _private: (),
588 }
589 }
590
591 pub const fn with_all(mut self) -> RoleAttributesRaw {
593 self.inherit = true;
594 self.superuser = Some(true);
595 self.login = Some(true);
596 self
597 }
598}
599
600impl RoleAttributes {
601 pub const fn new() -> RoleAttributes {
603 RoleAttributes {
604 inherit: true,
605 superuser: None,
606 login: None,
607 auto_provision_source: None,
608 _private: (),
609 }
610 }
611
612 pub const fn with_all(mut self) -> RoleAttributes {
614 self.inherit = true;
615 self.superuser = Some(true);
616 self.login = Some(true);
617 self
618 }
619
620 pub const fn is_inherit(&self) -> bool {
622 self.inherit
623 }
624}
625
626impl From<RoleAttributesRaw> for RoleAttributes {
627 fn from(
628 RoleAttributesRaw {
629 inherit,
630 superuser,
631 login,
632 auto_provision_source,
633 ..
634 }: RoleAttributesRaw,
635 ) -> RoleAttributes {
636 RoleAttributes {
637 inherit,
638 superuser,
639 login,
640 auto_provision_source,
641 _private: (),
642 }
643 }
644}
645
646impl From<RoleAttributes> for RoleAttributesRaw {
647 fn from(
648 RoleAttributes {
649 inherit,
650 superuser,
651 login,
652 auto_provision_source,
653 ..
654 }: RoleAttributes,
655 ) -> RoleAttributesRaw {
656 RoleAttributesRaw {
657 inherit,
658 password: None,
659 scram_iterations: None,
660 superuser,
661 login,
662 auto_provision_source,
663 _private: (),
664 }
665 }
666}
667
668impl From<PlannedRoleAttributes> for RoleAttributesRaw {
669 fn from(
670 PlannedRoleAttributes {
671 inherit,
672 password,
673 scram_iterations,
674 superuser,
675 login,
676 ..
677 }: PlannedRoleAttributes,
678 ) -> RoleAttributesRaw {
679 let default_attributes = RoleAttributesRaw::new();
680 RoleAttributesRaw {
681 inherit: inherit.unwrap_or(default_attributes.inherit),
682 password,
683 scram_iterations,
684 superuser,
685 login,
686 auto_provision_source: None,
687 _private: (),
688 }
689 }
690}
691
692#[derive(Default, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize)]
694pub struct RoleVars {
695 pub map: BTreeMap<String, OwnedVarInput>,
697}
698
699pub trait CatalogRole {
701 fn name(&self) -> &str;
703
704 fn id(&self) -> RoleId;
706
707 fn membership(&self) -> &BTreeMap<RoleId, RoleId>;
712
713 fn attributes(&self) -> &RoleAttributes;
715
716 fn vars(&self) -> &BTreeMap<String, OwnedVarInput>;
718}
719
720pub trait CatalogNetworkPolicy {
722 fn name(&self) -> &str;
724
725 fn id(&self) -> NetworkPolicyId;
727
728 fn owner_id(&self) -> RoleId;
730
731 fn privileges(&self) -> &PrivilegeMap;
733}
734
735pub trait CatalogCluster<'a> {
737 fn name(&self) -> &str;
739
740 fn id(&self) -> ClusterId;
742
743 fn bound_objects(&self) -> &BTreeSet<CatalogItemId>;
745
746 fn replica_ids(&self) -> &BTreeMap<String, ReplicaId>;
749
750 fn replicas(&self) -> Vec<&dyn CatalogClusterReplica<'_>>;
752
753 fn replica(&self, id: ReplicaId) -> &dyn CatalogClusterReplica<'_>;
755
756 fn owner_id(&self) -> RoleId;
758
759 fn privileges(&self) -> &PrivilegeMap;
761
762 fn is_managed(&self) -> bool;
764
765 fn managed_size(&self) -> Option<&str>;
767
768 fn schedule(&self) -> Option<&ClusterSchedule>;
770
771 fn try_to_plan(&self) -> Result<CreateClusterPlan, PlanError>;
774}
775
776pub trait CatalogClusterReplica<'a>: Debug {
778 fn name(&self) -> &str;
780
781 fn cluster_id(&self) -> ClusterId;
783
784 fn replica_id(&self) -> ReplicaId;
786
787 fn owner_id(&self) -> RoleId;
789
790 fn internal(&self) -> bool;
792}
793
794pub trait CatalogItem {
799 fn name(&self) -> &QualifiedItemName;
801
802 fn id(&self) -> CatalogItemId;
804
805 fn global_ids(&self) -> Box<dyn Iterator<Item = GlobalId> + '_>;
807
808 fn oid(&self) -> u32;
810
811 fn func(&self) -> Result<&'static Func, CatalogError>;
816
817 fn source_desc(&self) -> Result<Option<&SourceDesc<ReferencedConnection>>, CatalogError>;
822
823 fn connection(&self) -> Result<Connection<ReferencedConnection>, CatalogError>;
827
828 fn item_type(&self) -> CatalogItemType;
830
831 fn create_sql(&self) -> &str;
834
835 fn references(&self) -> &ResolvedIds;
838
839 fn uses(&self) -> BTreeSet<CatalogItemId>;
842
843 fn referenced_by(&self) -> &[CatalogItemId];
845
846 fn used_by(&self) -> &[CatalogItemId];
848
849 fn subsource_details(
852 &self,
853 ) -> Option<(CatalogItemId, &UnresolvedItemName, &SourceExportDetails)>;
854
855 fn source_export_details(
858 &self,
859 ) -> Option<(
860 CatalogItemId,
861 &UnresolvedItemName,
862 &SourceExportDetails,
863 &SourceExportDataConfig<ReferencedConnection>,
864 )>;
865
866 fn is_progress_source(&self) -> bool;
868
869 fn progress_id(&self) -> Option<CatalogItemId>;
871
872 fn index_details(&self) -> Option<(&[MirScalarExpr], GlobalId)>;
875
876 fn writable_table_details(&self) -> Option<&[Expr<Aug>]>;
879
880 fn replacement_target(&self) -> Option<CatalogItemId>;
882
883 fn type_details(&self) -> Option<&CatalogTypeDetails<IdReference>>;
886
887 fn owner_id(&self) -> RoleId;
889
890 fn privileges(&self) -> &PrivilegeMap;
892
893 fn cluster_id(&self) -> Option<ClusterId>;
895
896 fn at_version(&self, version: RelationVersionSelector) -> Box<dyn CatalogCollectionItem>;
899
900 fn latest_version(&self) -> Option<RelationVersion>;
902}
903
904pub trait CatalogCollectionItem: CatalogItem + Send + Sync {
907 fn relation_desc(&self) -> Option<Cow<'_, RelationDesc>>;
912
913 fn global_id(&self) -> GlobalId;
915}
916
917#[derive(
919 Debug,
920 Deserialize,
921 Clone,
922 Copy,
923 Eq,
924 Hash,
925 Ord,
926 PartialEq,
927 PartialOrd,
928 Serialize
929)]
930pub enum CatalogItemType {
931 Table,
933 Source,
935 Sink,
937 View,
939 MaterializedView,
941 Index,
943 Type,
945 Func,
947 Secret,
949 Connection,
951 ContinualTask,
953}
954
955impl CatalogItemType {
956 pub fn conflicts_with_type(&self) -> bool {
975 match self {
976 CatalogItemType::Table => true,
977 CatalogItemType::Source => true,
978 CatalogItemType::View => true,
979 CatalogItemType::MaterializedView => true,
980 CatalogItemType::Index => true,
981 CatalogItemType::Type => true,
982 CatalogItemType::Sink => false,
983 CatalogItemType::Func => false,
984 CatalogItemType::Secret => false,
985 CatalogItemType::Connection => false,
986 CatalogItemType::ContinualTask => true,
987 }
988 }
989}
990
991impl fmt::Display for CatalogItemType {
992 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
993 match self {
994 CatalogItemType::Table => f.write_str("table"),
995 CatalogItemType::Source => f.write_str("source"),
996 CatalogItemType::Sink => f.write_str("sink"),
997 CatalogItemType::View => f.write_str("view"),
998 CatalogItemType::MaterializedView => f.write_str("materialized view"),
999 CatalogItemType::Index => f.write_str("index"),
1000 CatalogItemType::Type => f.write_str("type"),
1001 CatalogItemType::Func => f.write_str("func"),
1002 CatalogItemType::Secret => f.write_str("secret"),
1003 CatalogItemType::Connection => f.write_str("connection"),
1004 CatalogItemType::ContinualTask => f.write_str("continual task"),
1005 }
1006 }
1007}
1008
1009impl From<CatalogItemType> for ObjectType {
1010 fn from(value: CatalogItemType) -> Self {
1011 match value {
1012 CatalogItemType::Table => ObjectType::Table,
1013 CatalogItemType::Source => ObjectType::Source,
1014 CatalogItemType::Sink => ObjectType::Sink,
1015 CatalogItemType::View => ObjectType::View,
1016 CatalogItemType::MaterializedView => ObjectType::MaterializedView,
1017 CatalogItemType::Index => ObjectType::Index,
1018 CatalogItemType::Type => ObjectType::Type,
1019 CatalogItemType::Func => ObjectType::Func,
1020 CatalogItemType::Secret => ObjectType::Secret,
1021 CatalogItemType::Connection => ObjectType::Connection,
1022 CatalogItemType::ContinualTask => ObjectType::ContinualTask,
1023 }
1024 }
1025}
1026
1027impl From<CatalogItemType> for mz_audit_log::ObjectType {
1028 fn from(value: CatalogItemType) -> Self {
1029 match value {
1030 CatalogItemType::Table => mz_audit_log::ObjectType::Table,
1031 CatalogItemType::Source => mz_audit_log::ObjectType::Source,
1032 CatalogItemType::View => mz_audit_log::ObjectType::View,
1033 CatalogItemType::MaterializedView => mz_audit_log::ObjectType::MaterializedView,
1034 CatalogItemType::Index => mz_audit_log::ObjectType::Index,
1035 CatalogItemType::Type => mz_audit_log::ObjectType::Type,
1036 CatalogItemType::Sink => mz_audit_log::ObjectType::Sink,
1037 CatalogItemType::Func => mz_audit_log::ObjectType::Func,
1038 CatalogItemType::Secret => mz_audit_log::ObjectType::Secret,
1039 CatalogItemType::Connection => mz_audit_log::ObjectType::Connection,
1040 CatalogItemType::ContinualTask => mz_audit_log::ObjectType::ContinualTask,
1041 }
1042 }
1043}
1044
1045#[derive(Clone, Debug, Eq, PartialEq)]
1047pub struct CatalogTypeDetails<T: TypeReference> {
1048 pub array_id: Option<CatalogItemId>,
1050 pub typ: CatalogType<T>,
1052 pub pg_metadata: Option<CatalogTypePgMetadata>,
1054}
1055
1056#[derive(Clone, Debug, Eq, PartialEq)]
1058pub struct CatalogTypePgMetadata {
1059 pub typinput_oid: u32,
1061 pub typreceive_oid: u32,
1063}
1064
1065pub trait TypeReference {
1067 type Reference: Clone + Debug + Eq + PartialEq;
1069}
1070
1071#[derive(Clone, Debug, Eq, PartialEq)]
1073pub struct NameReference;
1074
1075impl TypeReference for NameReference {
1076 type Reference = &'static str;
1077}
1078
1079#[derive(Clone, Debug, Eq, PartialEq)]
1081pub struct IdReference;
1082
1083impl TypeReference for IdReference {
1084 type Reference = CatalogItemId;
1085}
1086
1087#[allow(missing_docs)]
1093#[derive(Clone, Debug, Eq, PartialEq)]
1094pub enum CatalogType<T: TypeReference> {
1095 AclItem,
1096 Array {
1097 element_reference: T::Reference,
1098 },
1099 Bool,
1100 Bytes,
1101 Char,
1102 Date,
1103 Float32,
1104 Float64,
1105 Int16,
1106 Int32,
1107 Int64,
1108 UInt16,
1109 UInt32,
1110 UInt64,
1111 MzTimestamp,
1112 Interval,
1113 Jsonb,
1114 List {
1115 element_reference: T::Reference,
1116 element_modifiers: Vec<i64>,
1117 },
1118 Map {
1119 key_reference: T::Reference,
1120 key_modifiers: Vec<i64>,
1121 value_reference: T::Reference,
1122 value_modifiers: Vec<i64>,
1123 },
1124 Numeric,
1125 Oid,
1126 PgLegacyChar,
1127 PgLegacyName,
1128 Pseudo,
1129 Range {
1130 element_reference: T::Reference,
1131 },
1132 Record {
1133 fields: Vec<CatalogRecordField<T>>,
1134 },
1135 RegClass,
1136 RegProc,
1137 RegType,
1138 String,
1139 Time,
1140 Timestamp,
1141 TimestampTz,
1142 Uuid,
1143 VarChar,
1144 Int2Vector,
1145 MzAclItem,
1146}
1147
1148impl CatalogType<IdReference> {
1149 pub fn desc(&self, catalog: &dyn SessionCatalog) -> Result<Option<RelationDesc>, PlanError> {
1152 match &self {
1153 CatalogType::Record { fields } => {
1154 let mut desc = RelationDesc::builder();
1155 for f in fields {
1156 let name = f.name.clone();
1157 let ty = query::scalar_type_from_catalog(
1158 catalog,
1159 f.type_reference,
1160 &f.type_modifiers,
1161 )?;
1162 let ty = ty.nullable(true);
1165 desc = desc.with_column(name, ty);
1166 }
1167 Ok(Some(desc.finish()))
1168 }
1169 _ => Ok(None),
1170 }
1171 }
1172}
1173
1174#[derive(Clone, Debug, Eq, PartialEq)]
1176pub struct CatalogRecordField<T: TypeReference> {
1177 pub name: ColumnName,
1179 pub type_reference: T::Reference,
1181 pub type_modifiers: Vec<i64>,
1183}
1184
1185#[derive(Clone, Debug, Eq, PartialEq)]
1186pub enum TypeCategory {
1194 Array,
1196 BitString,
1198 Boolean,
1200 Composite,
1202 DateTime,
1204 Enum,
1206 Geometric,
1208 List,
1210 NetworkAddress,
1212 Numeric,
1214 Pseudo,
1216 Range,
1218 String,
1220 Timespan,
1222 UserDefined,
1224 Unknown,
1226}
1227
1228impl fmt::Display for TypeCategory {
1229 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1230 f.write_str(match self {
1231 TypeCategory::Array => "array",
1232 TypeCategory::BitString => "bit-string",
1233 TypeCategory::Boolean => "boolean",
1234 TypeCategory::Composite => "composite",
1235 TypeCategory::DateTime => "date-time",
1236 TypeCategory::Enum => "enum",
1237 TypeCategory::Geometric => "geometric",
1238 TypeCategory::List => "list",
1239 TypeCategory::NetworkAddress => "network-address",
1240 TypeCategory::Numeric => "numeric",
1241 TypeCategory::Pseudo => "pseudo",
1242 TypeCategory::Range => "range",
1243 TypeCategory::String => "string",
1244 TypeCategory::Timespan => "timespan",
1245 TypeCategory::UserDefined => "user-defined",
1246 TypeCategory::Unknown => "unknown",
1247 })
1248 }
1249}
1250
1251#[derive(Debug, Clone, PartialEq)]
1275pub struct EnvironmentId {
1276 cloud_provider: CloudProvider,
1277 cloud_provider_region: String,
1278 organization_id: Uuid,
1279 ordinal: u64,
1280}
1281
1282impl EnvironmentId {
1283 pub fn for_tests() -> EnvironmentId {
1285 EnvironmentId {
1286 cloud_provider: CloudProvider::Local,
1287 cloud_provider_region: "az1".into(),
1288 organization_id: Uuid::new_v4(),
1289 ordinal: 0,
1290 }
1291 }
1292
1293 pub fn cloud_provider(&self) -> &CloudProvider {
1295 &self.cloud_provider
1296 }
1297
1298 pub fn cloud_provider_region(&self) -> &str {
1300 &self.cloud_provider_region
1301 }
1302
1303 pub fn region(&self) -> String {
1308 format!("{}/{}", self.cloud_provider, self.cloud_provider_region)
1309 }
1310
1311 pub fn organization_id(&self) -> Uuid {
1313 self.organization_id
1314 }
1315
1316 pub fn ordinal(&self) -> u64 {
1318 self.ordinal
1319 }
1320}
1321
1322impl fmt::Display for EnvironmentId {
1328 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1329 write!(
1330 f,
1331 "{}-{}-{}-{}",
1332 self.cloud_provider, self.cloud_provider_region, self.organization_id, self.ordinal
1333 )
1334 }
1335}
1336
1337impl FromStr for EnvironmentId {
1338 type Err = InvalidEnvironmentIdError;
1339
1340 fn from_str(s: &str) -> Result<EnvironmentId, InvalidEnvironmentIdError> {
1341 static MATCHER: LazyLock<Regex> = LazyLock::new(|| {
1342 Regex::new(
1343 "^(?P<cloud_provider>[[:alnum:]]+)-\
1344 (?P<cloud_provider_region>[[:alnum:]\\-]+)-\
1345 (?P<organization_id>[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})-\
1346 (?P<ordinal>\\d{1,8})$"
1347 ).unwrap()
1348 });
1349 let captures = MATCHER.captures(s).ok_or(InvalidEnvironmentIdError)?;
1350 Ok(EnvironmentId {
1351 cloud_provider: CloudProvider::from_str(&captures["cloud_provider"])?,
1352 cloud_provider_region: captures["cloud_provider_region"].into(),
1353 organization_id: captures["organization_id"]
1354 .parse()
1355 .map_err(|_| InvalidEnvironmentIdError)?,
1356 ordinal: captures["ordinal"]
1357 .parse()
1358 .map_err(|_| InvalidEnvironmentIdError)?,
1359 })
1360 }
1361}
1362
1363#[derive(Debug, Clone, PartialEq)]
1365pub struct InvalidEnvironmentIdError;
1366
1367impl fmt::Display for InvalidEnvironmentIdError {
1368 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1369 f.write_str("invalid environment ID")
1370 }
1371}
1372
1373impl Error for InvalidEnvironmentIdError {}
1374
1375impl From<InvalidCloudProviderError> for InvalidEnvironmentIdError {
1376 fn from(_: InvalidCloudProviderError) -> Self {
1377 InvalidEnvironmentIdError
1378 }
1379}
1380
1381#[derive(Clone, Debug, Eq, PartialEq)]
1383pub enum CatalogError {
1384 UnknownDatabase(String),
1386 DatabaseAlreadyExists(String),
1388 UnknownSchema(String),
1390 SchemaAlreadyExists(String),
1392 UnknownRole(String),
1394 RoleAlreadyExists(String),
1396 NetworkPolicyAlreadyExists(String),
1398 UnknownCluster(String),
1400 UnexpectedBuiltinCluster(String),
1402 UnexpectedBuiltinClusterType(String),
1404 ClusterAlreadyExists(String),
1406 UnknownClusterReplica(String),
1408 UnknownClusterReplicaSize(String),
1410 DuplicateReplica(String, String),
1412 UnknownItem(String),
1414 ItemAlreadyExists(CatalogItemId, String),
1416 UnknownFunction {
1418 name: String,
1420 alternative: Option<String>,
1422 },
1423 UnknownType {
1425 name: String,
1427 },
1428 UnknownConnection(String),
1430 UnknownNetworkPolicy(String),
1432 UnexpectedType {
1434 name: String,
1436 actual_type: CatalogItemType,
1438 expected_type: CatalogItemType,
1440 },
1441 IdExhaustion,
1443 OidExhaustion,
1445 TimelineAlreadyExists(String),
1447 IdAllocatorAlreadyExists(String),
1449 ConfigAlreadyExists(String),
1451 FailedBuiltinSchemaMigration(String),
1453 StorageCollectionMetadataAlreadyExists(GlobalId),
1455}
1456
1457impl fmt::Display for CatalogError {
1458 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1459 match self {
1460 Self::UnknownDatabase(name) => write!(f, "unknown database '{}'", name),
1461 Self::DatabaseAlreadyExists(name) => write!(f, "database '{name}' already exists"),
1462 Self::UnknownFunction { name, .. } => write!(f, "function \"{}\" does not exist", name),
1463 Self::UnknownType { name, .. } => write!(f, "type \"{}\" does not exist", name),
1464 Self::UnknownConnection(name) => write!(f, "connection \"{}\" does not exist", name),
1465 Self::UnknownSchema(name) => write!(f, "unknown schema '{}'", name),
1466 Self::SchemaAlreadyExists(name) => write!(f, "schema '{name}' already exists"),
1467 Self::UnknownRole(name) => write!(f, "unknown role '{}'", name),
1468 Self::RoleAlreadyExists(name) => write!(f, "role '{name}' already exists"),
1469 Self::NetworkPolicyAlreadyExists(name) => {
1470 write!(f, "network policy '{name}' already exists")
1471 }
1472 Self::UnknownCluster(name) => write!(f, "unknown cluster '{}'", name),
1473 Self::UnknownNetworkPolicy(name) => write!(f, "unknown network policy '{}'", name),
1474 Self::UnexpectedBuiltinCluster(name) => {
1475 write!(f, "Unexpected builtin cluster '{}'", name)
1476 }
1477 Self::UnexpectedBuiltinClusterType(name) => {
1478 write!(f, "Unexpected builtin cluster type'{}'", name)
1479 }
1480 Self::ClusterAlreadyExists(name) => write!(f, "cluster '{name}' already exists"),
1481 Self::UnknownClusterReplica(name) => {
1482 write!(f, "unknown cluster replica '{}'", name)
1483 }
1484 Self::UnknownClusterReplicaSize(name) => {
1485 write!(f, "unknown cluster replica size '{}'", name)
1486 }
1487 Self::DuplicateReplica(replica_name, cluster_name) => write!(
1488 f,
1489 "cannot create multiple replicas named '{replica_name}' on cluster '{cluster_name}'"
1490 ),
1491 Self::UnknownItem(name) => write!(f, "unknown catalog item '{}'", name),
1492 Self::ItemAlreadyExists(_gid, name) => {
1493 write!(f, "catalog item '{name}' already exists")
1494 }
1495 Self::UnexpectedType {
1496 name,
1497 actual_type,
1498 expected_type,
1499 } => {
1500 write!(f, "\"{name}\" is a {actual_type} not a {expected_type}")
1501 }
1502 Self::IdExhaustion => write!(f, "id counter overflows i64"),
1503 Self::OidExhaustion => write!(f, "oid counter overflows u32"),
1504 Self::TimelineAlreadyExists(name) => write!(f, "timeline '{name}' already exists"),
1505 Self::IdAllocatorAlreadyExists(name) => {
1506 write!(f, "ID allocator '{name}' already exists")
1507 }
1508 Self::ConfigAlreadyExists(key) => write!(f, "config '{key}' already exists"),
1509 Self::FailedBuiltinSchemaMigration(objects) => {
1510 write!(f, "failed to migrate schema of builtin objects: {objects}")
1511 }
1512 Self::StorageCollectionMetadataAlreadyExists(key) => {
1513 write!(f, "storage metadata for '{key}' already exists")
1514 }
1515 }
1516 }
1517}
1518
1519impl CatalogError {
1520 pub fn hint(&self) -> Option<String> {
1522 match self {
1523 CatalogError::UnknownFunction { alternative, .. } => {
1524 match alternative {
1525 None => Some("No function matches the given name and argument types. You might need to add explicit type casts.".into()),
1526 Some(alt) => Some(format!("Try using {alt}")),
1527 }
1528 }
1529 _ => None,
1530 }
1531 }
1532}
1533
1534impl Error for CatalogError {}
1535
1536#[allow(missing_docs)]
1538#[derive(
1539 Debug,
1540 Clone,
1541 PartialOrd,
1542 Ord,
1543 PartialEq,
1544 Eq,
1545 Hash,
1546 Copy,
1547 Deserialize,
1548 Serialize
1549)]
1550pub enum ObjectType {
1552 Table,
1553 View,
1554 MaterializedView,
1555 Source,
1556 Sink,
1557 Index,
1558 Type,
1559 Role,
1560 Cluster,
1561 ClusterReplica,
1562 Secret,
1563 Connection,
1564 Database,
1565 Schema,
1566 Func,
1567 ContinualTask,
1568 NetworkPolicy,
1569}
1570
1571impl ObjectType {
1572 pub fn is_relation(&self) -> bool {
1574 match self {
1575 ObjectType::Table
1576 | ObjectType::View
1577 | ObjectType::MaterializedView
1578 | ObjectType::Source
1579 | ObjectType::ContinualTask => true,
1580 ObjectType::Sink
1581 | ObjectType::Index
1582 | ObjectType::Type
1583 | ObjectType::Secret
1584 | ObjectType::Connection
1585 | ObjectType::Func
1586 | ObjectType::Database
1587 | ObjectType::Schema
1588 | ObjectType::Cluster
1589 | ObjectType::ClusterReplica
1590 | ObjectType::Role
1591 | ObjectType::NetworkPolicy => false,
1592 }
1593 }
1594}
1595
1596impl From<mz_sql_parser::ast::ObjectType> for ObjectType {
1597 fn from(value: mz_sql_parser::ast::ObjectType) -> Self {
1598 match value {
1599 mz_sql_parser::ast::ObjectType::Table => ObjectType::Table,
1600 mz_sql_parser::ast::ObjectType::View => ObjectType::View,
1601 mz_sql_parser::ast::ObjectType::MaterializedView => ObjectType::MaterializedView,
1602 mz_sql_parser::ast::ObjectType::Source => ObjectType::Source,
1603 mz_sql_parser::ast::ObjectType::Subsource => ObjectType::Source,
1604 mz_sql_parser::ast::ObjectType::Sink => ObjectType::Sink,
1605 mz_sql_parser::ast::ObjectType::Index => ObjectType::Index,
1606 mz_sql_parser::ast::ObjectType::Type => ObjectType::Type,
1607 mz_sql_parser::ast::ObjectType::Role => ObjectType::Role,
1608 mz_sql_parser::ast::ObjectType::Cluster => ObjectType::Cluster,
1609 mz_sql_parser::ast::ObjectType::ClusterReplica => ObjectType::ClusterReplica,
1610 mz_sql_parser::ast::ObjectType::Secret => ObjectType::Secret,
1611 mz_sql_parser::ast::ObjectType::Connection => ObjectType::Connection,
1612 mz_sql_parser::ast::ObjectType::Database => ObjectType::Database,
1613 mz_sql_parser::ast::ObjectType::Schema => ObjectType::Schema,
1614 mz_sql_parser::ast::ObjectType::Func => ObjectType::Func,
1615 mz_sql_parser::ast::ObjectType::ContinualTask => ObjectType::ContinualTask,
1616 mz_sql_parser::ast::ObjectType::NetworkPolicy => ObjectType::NetworkPolicy,
1617 }
1618 }
1619}
1620
1621impl From<CommentObjectId> for ObjectType {
1622 fn from(value: CommentObjectId) -> ObjectType {
1623 match value {
1624 CommentObjectId::Table(_) => ObjectType::Table,
1625 CommentObjectId::View(_) => ObjectType::View,
1626 CommentObjectId::MaterializedView(_) => ObjectType::MaterializedView,
1627 CommentObjectId::Source(_) => ObjectType::Source,
1628 CommentObjectId::Sink(_) => ObjectType::Sink,
1629 CommentObjectId::Index(_) => ObjectType::Index,
1630 CommentObjectId::Func(_) => ObjectType::Func,
1631 CommentObjectId::Connection(_) => ObjectType::Connection,
1632 CommentObjectId::Type(_) => ObjectType::Type,
1633 CommentObjectId::Secret(_) => ObjectType::Secret,
1634 CommentObjectId::Role(_) => ObjectType::Role,
1635 CommentObjectId::Database(_) => ObjectType::Database,
1636 CommentObjectId::Schema(_) => ObjectType::Schema,
1637 CommentObjectId::Cluster(_) => ObjectType::Cluster,
1638 CommentObjectId::ClusterReplica(_) => ObjectType::ClusterReplica,
1639 CommentObjectId::ContinualTask(_) => ObjectType::ContinualTask,
1640 CommentObjectId::NetworkPolicy(_) => ObjectType::NetworkPolicy,
1641 }
1642 }
1643}
1644
1645impl Display for ObjectType {
1646 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1647 f.write_str(match self {
1648 ObjectType::Table => "TABLE",
1649 ObjectType::View => "VIEW",
1650 ObjectType::MaterializedView => "MATERIALIZED VIEW",
1651 ObjectType::Source => "SOURCE",
1652 ObjectType::Sink => "SINK",
1653 ObjectType::Index => "INDEX",
1654 ObjectType::Type => "TYPE",
1655 ObjectType::Role => "ROLE",
1656 ObjectType::Cluster => "CLUSTER",
1657 ObjectType::ClusterReplica => "CLUSTER REPLICA",
1658 ObjectType::Secret => "SECRET",
1659 ObjectType::Connection => "CONNECTION",
1660 ObjectType::Database => "DATABASE",
1661 ObjectType::Schema => "SCHEMA",
1662 ObjectType::Func => "FUNCTION",
1663 ObjectType::ContinualTask => "CONTINUAL TASK",
1664 ObjectType::NetworkPolicy => "NETWORK POLICY",
1665 })
1666 }
1667}
1668
1669#[derive(
1670 Debug,
1671 Clone,
1672 PartialOrd,
1673 Ord,
1674 PartialEq,
1675 Eq,
1676 Hash,
1677 Copy,
1678 Deserialize,
1679 Serialize
1680)]
1681pub enum SystemObjectType {
1683 Object(ObjectType),
1685 System,
1687}
1688
1689impl SystemObjectType {
1690 pub fn is_relation(&self) -> bool {
1692 match self {
1693 SystemObjectType::Object(object_type) => object_type.is_relation(),
1694 SystemObjectType::System => false,
1695 }
1696 }
1697}
1698
1699impl Display for SystemObjectType {
1700 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1701 match self {
1702 SystemObjectType::Object(object_type) => std::fmt::Display::fmt(&object_type, f),
1703 SystemObjectType::System => f.write_str("SYSTEM"),
1704 }
1705 }
1706}
1707
1708#[derive(Debug, Clone, PartialEq, Eq)]
1710pub enum ErrorMessageObjectDescription {
1711 Object {
1713 object_type: ObjectType,
1715 object_name: Option<String>,
1717 },
1718 System,
1720}
1721
1722impl ErrorMessageObjectDescription {
1723 pub fn from_id(
1725 object_id: &ObjectId,
1726 catalog: &dyn SessionCatalog,
1727 ) -> ErrorMessageObjectDescription {
1728 let object_name = match object_id {
1729 ObjectId::Cluster(cluster_id) => catalog.get_cluster(*cluster_id).name().to_string(),
1730 ObjectId::ClusterReplica((cluster_id, replica_id)) => catalog
1731 .get_cluster_replica(*cluster_id, *replica_id)
1732 .name()
1733 .to_string(),
1734 ObjectId::Database(database_id) => catalog.get_database(database_id).name().to_string(),
1735 ObjectId::Schema((database_spec, schema_spec)) => {
1736 let name = catalog.get_schema(database_spec, schema_spec).name();
1737 catalog.resolve_full_schema_name(name).to_string()
1738 }
1739 ObjectId::Role(role_id) => catalog.get_role(role_id).name().to_string(),
1740 ObjectId::Item(id) => {
1741 let name = catalog.get_item(id).name();
1742 catalog.resolve_full_name(name).to_string()
1743 }
1744 ObjectId::NetworkPolicy(network_policy_id) => catalog
1745 .get_network_policy(network_policy_id)
1746 .name()
1747 .to_string(),
1748 };
1749 ErrorMessageObjectDescription::Object {
1750 object_type: catalog.get_object_type(object_id),
1751 object_name: Some(object_name),
1752 }
1753 }
1754
1755 pub fn from_sys_id(
1757 object_id: &SystemObjectId,
1758 catalog: &dyn SessionCatalog,
1759 ) -> ErrorMessageObjectDescription {
1760 match object_id {
1761 SystemObjectId::Object(object_id) => {
1762 ErrorMessageObjectDescription::from_id(object_id, catalog)
1763 }
1764 SystemObjectId::System => ErrorMessageObjectDescription::System,
1765 }
1766 }
1767
1768 pub fn from_object_type(object_type: SystemObjectType) -> ErrorMessageObjectDescription {
1770 match object_type {
1771 SystemObjectType::Object(object_type) => ErrorMessageObjectDescription::Object {
1772 object_type,
1773 object_name: None,
1774 },
1775 SystemObjectType::System => ErrorMessageObjectDescription::System,
1776 }
1777 }
1778}
1779
1780impl Display for ErrorMessageObjectDescription {
1781 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1782 match self {
1783 ErrorMessageObjectDescription::Object {
1784 object_type,
1785 object_name,
1786 } => {
1787 let object_name = object_name
1788 .as_ref()
1789 .map(|object_name| format!(" {}", object_name.quoted()))
1790 .unwrap_or_else(|| "".to_string());
1791 write!(f, "{object_type}{object_name}")
1792 }
1793 ErrorMessageObjectDescription::System => f.write_str("SYSTEM"),
1794 }
1795 }
1796}
1797
1798#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd)]
1799#[serde(into = "BTreeMap<String, RoleId>")]
1802#[serde(try_from = "BTreeMap<String, RoleId>")]
1803pub struct RoleMembership {
1805 pub map: BTreeMap<RoleId, RoleId>,
1811}
1812
1813impl RoleMembership {
1814 pub fn new() -> RoleMembership {
1816 RoleMembership {
1817 map: BTreeMap::new(),
1818 }
1819 }
1820}
1821
1822impl From<RoleMembership> for BTreeMap<String, RoleId> {
1823 fn from(value: RoleMembership) -> Self {
1824 value
1825 .map
1826 .into_iter()
1827 .map(|(k, v)| (k.to_string(), v))
1828 .collect()
1829 }
1830}
1831
1832impl TryFrom<BTreeMap<String, RoleId>> for RoleMembership {
1833 type Error = anyhow::Error;
1834
1835 fn try_from(value: BTreeMap<String, RoleId>) -> Result<Self, Self::Error> {
1836 Ok(RoleMembership {
1837 map: value
1838 .into_iter()
1839 .map(|(k, v)| Ok((RoleId::from_str(&k)?, v)))
1840 .collect::<Result<_, anyhow::Error>>()?,
1841 })
1842 }
1843}
1844
1845#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize)]
1847pub struct DefaultPrivilegeObject {
1848 pub role_id: RoleId,
1850 pub database_id: Option<DatabaseId>,
1852 pub schema_id: Option<SchemaId>,
1854 pub object_type: ObjectType,
1856}
1857
1858impl DefaultPrivilegeObject {
1859 pub fn new(
1861 role_id: RoleId,
1862 database_id: Option<DatabaseId>,
1863 schema_id: Option<SchemaId>,
1864 object_type: ObjectType,
1865 ) -> DefaultPrivilegeObject {
1866 DefaultPrivilegeObject {
1867 role_id,
1868 database_id,
1869 schema_id,
1870 object_type,
1871 }
1872 }
1873}
1874
1875impl std::fmt::Display for DefaultPrivilegeObject {
1876 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1877 write!(f, "{self:?}")
1879 }
1880}
1881
1882#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize)]
1884pub struct DefaultPrivilegeAclItem {
1885 pub grantee: RoleId,
1887 pub acl_mode: AclMode,
1889}
1890
1891impl DefaultPrivilegeAclItem {
1892 pub fn new(grantee: RoleId, acl_mode: AclMode) -> DefaultPrivilegeAclItem {
1894 DefaultPrivilegeAclItem { grantee, acl_mode }
1895 }
1896
1897 pub fn mz_acl_item(self, grantor: RoleId) -> MzAclItem {
1899 MzAclItem {
1900 grantee: self.grantee,
1901 grantor,
1902 acl_mode: self.acl_mode,
1903 }
1904 }
1905}
1906
1907#[derive(Debug, Clone)]
1913pub struct BuiltinsConfig {
1914 pub include_continual_tasks: bool,
1916}
1917
1918#[cfg(test)]
1919mod tests {
1920 use super::{CloudProvider, EnvironmentId, InvalidEnvironmentIdError};
1921
1922 #[mz_ore::test]
1923 fn test_environment_id() {
1924 for (input, expected) in [
1925 (
1926 "local-az1-1497a3b7-a455-4fc4-8752-b44a94b5f90a-452",
1927 Ok(EnvironmentId {
1928 cloud_provider: CloudProvider::Local,
1929 cloud_provider_region: "az1".into(),
1930 organization_id: "1497a3b7-a455-4fc4-8752-b44a94b5f90a".parse().unwrap(),
1931 ordinal: 452,
1932 }),
1933 ),
1934 (
1935 "aws-us-east-1-1497a3b7-a455-4fc4-8752-b44a94b5f90a-0",
1936 Ok(EnvironmentId {
1937 cloud_provider: CloudProvider::Aws,
1938 cloud_provider_region: "us-east-1".into(),
1939 organization_id: "1497a3b7-a455-4fc4-8752-b44a94b5f90a".parse().unwrap(),
1940 ordinal: 0,
1941 }),
1942 ),
1943 (
1944 "gcp-us-central1-1497a3b7-a455-4fc4-8752-b44a94b5f90a-0",
1945 Ok(EnvironmentId {
1946 cloud_provider: CloudProvider::Gcp,
1947 cloud_provider_region: "us-central1".into(),
1948 organization_id: "1497a3b7-a455-4fc4-8752-b44a94b5f90a".parse().unwrap(),
1949 ordinal: 0,
1950 }),
1951 ),
1952 (
1953 "azure-australiaeast-1497a3b7-a455-4fc4-8752-b44a94b5f90a-0",
1954 Ok(EnvironmentId {
1955 cloud_provider: CloudProvider::Azure,
1956 cloud_provider_region: "australiaeast".into(),
1957 organization_id: "1497a3b7-a455-4fc4-8752-b44a94b5f90a".parse().unwrap(),
1958 ordinal: 0,
1959 }),
1960 ),
1961 (
1962 "generic-moon-station-11-darkside-1497a3b7-a455-4fc4-8752-b44a94b5f90a-0",
1963 Ok(EnvironmentId {
1964 cloud_provider: CloudProvider::Generic,
1965 cloud_provider_region: "moon-station-11-darkside".into(),
1966 organization_id: "1497a3b7-a455-4fc4-8752-b44a94b5f90a".parse().unwrap(),
1967 ordinal: 0,
1968 }),
1969 ),
1970 ("", Err(InvalidEnvironmentIdError)),
1971 (
1972 "local-az1-1497a3b7-a455-4fc4-8752-b44a94b5f90a-123456789",
1973 Err(InvalidEnvironmentIdError),
1974 ),
1975 (
1976 "local-1497a3b7-a455-4fc4-8752-b44a94b5f90a-452",
1977 Err(InvalidEnvironmentIdError),
1978 ),
1979 (
1980 "local-az1-1497a3b7-a455-4fc48752-b44a94b5f90a-452",
1981 Err(InvalidEnvironmentIdError),
1982 ),
1983 ] {
1984 let actual = input.parse();
1985 assert_eq!(expected, actual, "input = {}", input);
1986 if let Ok(actual) = actual {
1987 assert_eq!(input, actual.to_string(), "input = {}", input);
1988 }
1989 }
1990 }
1991}