1pub mod cdc_type_compatibility;
16mod column;
17mod external_table;
18mod internal_table;
19mod physical_table;
20mod schema;
21pub mod test_utils;
22
23use std::fmt::Binary;
24use std::sync::Arc;
25
26pub use column::*;
27pub use external_table::*;
28use futures::stream::BoxStream;
29pub use internal_table::*;
30use parse_display::Display;
31pub use physical_table::*;
32use risingwave_pb::catalog::table::PbEngine;
33use risingwave_pb::catalog::{
34 CreateType as PbCreateType, HandleConflictBehavior as PbHandleConflictBehavior,
35 StreamJobStatus as PbStreamJobStatus,
36};
37use risingwave_pb::plan_common::ColumnDescVersion;
38pub use schema::{Field, FieldDisplay, FieldLike, Schema, test_utils as schema_test_utils};
39
40use crate::array::DataChunk;
41pub use crate::constants::hummock;
42use crate::error::BoxedError;
43pub use crate::id::*;
44
45pub type CatalogVersion = u64;
47
48pub type TableVersionId = u64;
50pub const INITIAL_TABLE_VERSION_ID: u64 = 0;
52pub type SourceVersionId = u64;
54pub const INITIAL_SOURCE_VERSION_ID: u64 = 0;
56
57pub const DEFAULT_DATABASE_NAME: &str = "dev";
58pub const DEFAULT_SCHEMA_NAME: &str = "public";
59pub const PG_CATALOG_SCHEMA_NAME: &str = "pg_catalog";
60pub const INFORMATION_SCHEMA_SCHEMA_NAME: &str = "information_schema";
61pub const RW_CATALOG_SCHEMA_NAME: &str = "rw_catalog";
62pub const RESERVED_PG_SCHEMA_PREFIX: &str = "pg_";
63pub const DEFAULT_SUPER_USER: &str = "root";
64pub const DEFAULT_SUPER_USER_ID: UserId = UserId::new(1);
65pub const DEFAULT_SUPER_USER_FOR_PG: &str = "postgres";
67pub const DEFAULT_SUPER_USER_FOR_PG_ID: u32 = 2;
68
69pub const DEFAULT_SUPER_USER_FOR_ADMIN: &str = "rwadmin";
71pub const DEFAULT_SUPER_USER_FOR_ADMIN_ID: UserId = UserId::new(3);
72
73pub const NON_RESERVED_USER_ID: UserId = UserId::new(11);
74
75pub const MAX_SYS_CATALOG_NUM: i32 = 5000;
76pub const SYS_CATALOG_START_ID: i32 = i32::MAX - MAX_SYS_CATALOG_NUM;
77
78pub use risingwave_pb::id::OBJECT_ID_PLACEHOLDER;
79
80pub const SYSTEM_SCHEMAS: [&str; 3] = [
81 PG_CATALOG_SCHEMA_NAME,
82 INFORMATION_SCHEMA_SCHEMA_NAME,
83 RW_CATALOG_SCHEMA_NAME,
84];
85pub fn is_system_schema(schema_name: &str) -> bool {
86 SYSTEM_SCHEMAS.contains(&schema_name)
87}
88
89pub fn is_reserved_admin_user(user_name: &str) -> bool {
90 user_name == DEFAULT_SUPER_USER_FOR_ADMIN
91}
92
93pub const RW_RESERVED_COLUMN_NAME_PREFIX: &str = "_rw_";
94
95pub const DEFAULT_KEY_COLUMN_NAME: &str = "_rw_key";
99
100pub fn default_key_column_name_version_mapping(version: &ColumnDescVersion) -> &str {
101 match version {
102 ColumnDescVersion::Unspecified => DEFAULT_KEY_COLUMN_NAME,
103 _ => DEFAULT_KEY_COLUMN_NAME,
104 }
105}
106
107pub const KAFKA_TIMESTAMP_COLUMN_NAME: &str = "_rw_kafka_timestamp";
112
113pub const RISINGWAVE_ICEBERG_ROW_ID: &str = "_risingwave_iceberg_row_id";
118
119pub const ROW_ID_COLUMN_NAME: &str = "_row_id";
120pub const ROW_ID_COLUMN_ID: ColumnId = ColumnId::new(0);
122
123pub const USER_COLUMN_ID_OFFSET: i32 = ROW_ID_COLUMN_ID.next().get_id();
127
128pub const RW_TIMESTAMP_COLUMN_NAME: &str = "_rw_timestamp";
129pub const RW_TIMESTAMP_COLUMN_ID: ColumnId = ColumnId::new(-1);
130
131pub const PROJECTED_ROW_ID_COLUMN_NAME: &str = "_rw_projected_row_id";
134
135pub const ICEBERG_SEQUENCE_NUM_COLUMN_NAME: &str = "_iceberg_sequence_number";
136pub const ICEBERG_FILE_PATH_COLUMN_NAME: &str = "_iceberg_file_path";
137pub const ICEBERG_FILE_POS_COLUMN_NAME: &str = "_iceberg_file_pos";
138
139pub const CDC_OFFSET_COLUMN_NAME: &str = "_rw_offset";
140pub const CDC_SOURCE_COLUMN_NUM: u32 = 3;
143pub const CDC_TABLE_NAME_COLUMN_NAME: &str = "_rw_table_name";
144
145pub const ICEBERG_SOURCE_PREFIX: &str = "__iceberg_source_";
146pub const ICEBERG_SINK_PREFIX: &str = "__iceberg_sink_";
147
148pub const RISINGWAVE_ICEBERG_COMMIT_EPOCH: &str = "risingwave.commit.epoch";
152
153pub trait SysCatalogReader: Sync + Send + 'static {
155 fn read_table(&self, table_id: TableId) -> BoxStream<'_, Result<DataChunk, BoxedError>>;
157}
158
159pub type SysCatalogReaderRef = Arc<dyn SysCatalogReader>;
160
161#[derive(Clone, Debug, PartialEq, Default, Copy)]
162pub struct TableOption {
163 pub retention_seconds: Option<u32>, }
165
166impl From<&risingwave_pb::hummock::TableOption> for TableOption {
167 fn from(table_option: &risingwave_pb::hummock::TableOption) -> Self {
168 Self {
169 retention_seconds: table_option.retention_seconds,
170 }
171 }
172}
173
174impl From<&TableOption> for risingwave_pb::hummock::TableOption {
175 fn from(table_option: &TableOption) -> Self {
176 Self {
177 retention_seconds: table_option.retention_seconds,
178 }
179 }
180}
181
182impl TableOption {
183 pub fn new(retention_seconds: Option<u32>) -> Self {
184 TableOption { retention_seconds }
186 }
187}
188
189#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash)]
190pub enum ConflictBehavior {
191 #[default]
192 NoCheck,
193 Overwrite,
194 IgnoreConflict,
195 DoUpdateIfNotNull,
196}
197
198#[macro_export]
199macro_rules! _checked_conflict_behaviors {
200 () => {
201 ConflictBehavior::Overwrite
202 | ConflictBehavior::IgnoreConflict
203 | ConflictBehavior::DoUpdateIfNotNull
204 };
205}
206pub use _checked_conflict_behaviors as checked_conflict_behaviors;
207
208impl ConflictBehavior {
209 pub fn from_protobuf(tb_conflict_behavior: &PbHandleConflictBehavior) -> Self {
210 match tb_conflict_behavior {
211 PbHandleConflictBehavior::Overwrite => ConflictBehavior::Overwrite,
212 PbHandleConflictBehavior::Ignore => ConflictBehavior::IgnoreConflict,
213 PbHandleConflictBehavior::DoUpdateIfNotNull => ConflictBehavior::DoUpdateIfNotNull,
214 PbHandleConflictBehavior::NoCheck | PbHandleConflictBehavior::Unspecified => {
217 ConflictBehavior::NoCheck
218 }
219 }
220 }
221
222 pub fn to_protobuf(self) -> PbHandleConflictBehavior {
223 match self {
224 ConflictBehavior::NoCheck => PbHandleConflictBehavior::NoCheck,
225 ConflictBehavior::Overwrite => PbHandleConflictBehavior::Overwrite,
226 ConflictBehavior::IgnoreConflict => PbHandleConflictBehavior::Ignore,
227 ConflictBehavior::DoUpdateIfNotNull => PbHandleConflictBehavior::DoUpdateIfNotNull,
228 }
229 }
230
231 pub fn debug_to_string(self) -> String {
232 match self {
233 ConflictBehavior::NoCheck => "NoCheck".to_owned(),
234 ConflictBehavior::Overwrite => "Overwrite".to_owned(),
235 ConflictBehavior::IgnoreConflict => "IgnoreConflict".to_owned(),
236 ConflictBehavior::DoUpdateIfNotNull => "DoUpdateIfNotNull".to_owned(),
237 }
238 }
239}
240
241#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash)]
242pub enum Engine {
243 #[default]
244 Hummock,
245 Iceberg,
246}
247
248impl Engine {
249 pub fn from_protobuf(engine: &PbEngine) -> Self {
250 match engine {
251 PbEngine::Hummock | PbEngine::Unspecified => Engine::Hummock,
252 PbEngine::Iceberg => Engine::Iceberg,
253 }
254 }
255
256 pub fn to_protobuf(self) -> PbEngine {
257 match self {
258 Engine::Hummock => PbEngine::Hummock,
259 Engine::Iceberg => PbEngine::Iceberg,
260 }
261 }
262
263 pub fn debug_to_string(self) -> String {
264 match self {
265 Engine::Hummock => "Hummock".to_owned(),
266 Engine::Iceberg => "Iceberg".to_owned(),
267 }
268 }
269}
270
271#[derive(Clone, Copy, Debug, Default, Display, Hash, PartialOrd, PartialEq, Eq, Ord)]
272pub enum StreamJobStatus {
273 #[default]
274 Creating,
275 Created,
276}
277
278impl StreamJobStatus {
279 pub fn from_proto(stream_job_status: PbStreamJobStatus) -> Self {
280 match stream_job_status {
281 PbStreamJobStatus::Creating => StreamJobStatus::Creating,
282 PbStreamJobStatus::Created | PbStreamJobStatus::Unspecified => StreamJobStatus::Created,
283 }
284 }
285
286 pub fn to_proto(self) -> PbStreamJobStatus {
287 match self {
288 StreamJobStatus::Creating => PbStreamJobStatus::Creating,
289 StreamJobStatus::Created => PbStreamJobStatus::Created,
290 }
291 }
292}
293
294#[derive(Clone, Copy, Debug, Display, Hash, PartialOrd, PartialEq, Eq, Ord, Default)]
295pub enum CreateType {
296 #[default]
297 Foreground,
298 Background,
299}
300
301impl CreateType {
302 pub fn from_proto(pb_create_type: PbCreateType) -> Self {
303 match pb_create_type {
304 PbCreateType::Foreground | PbCreateType::Unspecified => CreateType::Foreground,
305 PbCreateType::Background => CreateType::Background,
306 }
307 }
308
309 pub fn to_proto(self) -> PbCreateType {
310 match self {
311 CreateType::Foreground => PbCreateType::Foreground,
312 CreateType::Background => PbCreateType::Background,
313 }
314 }
315}
316
317#[derive(Clone, Debug)]
318pub enum AlterDatabaseParam {
319 BarrierIntervalMs(Option<u32>),
322 CheckpointFrequency(Option<u64>),
323}
324
325macro_rules! for_all_fragment_type_flags {
326 () => {
327 for_all_fragment_type_flags! {
328 {
329 Source,
330 Mview,
331 Sink,
332 Now,
333 StreamScan,
334 BarrierRecv,
335 Values,
336 Dml,
337 CdcFilter,
338 Skipped1,
339 SourceScan,
340 SnapshotBackfillStreamScan,
341 FsFetch,
342 CrossDbSnapshotBackfillStreamScan,
343 StreamCdcScan,
344 VectorIndexWrite,
345 UpstreamSinkUnion,
346 LocalityProvider,
347 IcebergWithPkIndexWriter
348 },
349 {},
350 0
351 }
352 };
353 (
354 {},
355 {
356 $(
357 {$flag:ident, $index:expr}
358 ),*
359 },
360 $next_index:expr
361 ) => {
362 #[derive(Clone, Copy, Debug, Display, Hash, PartialOrd, PartialEq, Eq)]
363 #[repr(u32)]
364 pub enum FragmentTypeFlag {
365 $(
366 $flag = (1 << $index),
367 )*
368 }
369
370 pub const FRAGMENT_TYPE_FLAG_LIST: [FragmentTypeFlag; $next_index] = [
371 $(
372 FragmentTypeFlag::$flag,
373 )*
374 ];
375
376 impl TryFrom<u32> for FragmentTypeFlag {
377 type Error = String;
378
379 fn try_from(value: u32) -> Result<Self, Self::Error> {
380 match value {
381 $(
382 value if value == (FragmentTypeFlag::$flag as u32) => Ok(FragmentTypeFlag::$flag),
383 )*
384 _ => Err(format!("Invalid FragmentTypeFlag value: {}", value)),
385 }
386 }
387 }
388
389 impl FragmentTypeFlag {
390 pub fn as_str_name(&self) -> &'static str {
391 match self {
392 $(
393 FragmentTypeFlag::$flag => paste::paste!{stringify!( [< $flag:snake:upper >] )},
394 )*
395 }
396 }
397 }
398 };
399 (
400 {$first:ident $(, $rest:ident)*},
401 {
402 $(
403 {$flag:ident, $index:expr}
404 ),*
405 },
406 $next_index:expr
407 ) => {
408 for_all_fragment_type_flags! {
409 {$($rest),*},
410 {
411 $({$flag, $index},)*
412 {$first, $next_index}
413 },
414 $next_index + 1
415 }
416 };
417}
418
419for_all_fragment_type_flags!();
420
421impl FragmentTypeFlag {
422 pub fn raw_flag(flags: impl IntoIterator<Item = FragmentTypeFlag>) -> u32 {
423 flags.into_iter().fold(0, |acc, flag| acc | (flag as u32))
424 }
425
426 pub fn backfill_rate_limit_fragments() -> impl Iterator<Item = FragmentTypeFlag> {
428 [
429 FragmentTypeFlag::SourceScan,
430 FragmentTypeFlag::StreamScan,
431 FragmentTypeFlag::LocalityProvider,
432 ]
433 .into_iter()
434 }
435
436 pub fn source_rate_limit_fragments() -> impl Iterator<Item = FragmentTypeFlag> {
439 [FragmentTypeFlag::Source, FragmentTypeFlag::FsFetch].into_iter()
440 }
441
442 pub fn sink_rate_limit_fragments() -> impl Iterator<Item = FragmentTypeFlag> {
444 [FragmentTypeFlag::Sink].into_iter()
445 }
446
447 pub fn rate_limit_fragments() -> impl Iterator<Item = FragmentTypeFlag> {
449 Self::backfill_rate_limit_fragments()
450 .chain(Self::source_rate_limit_fragments())
451 .chain(Self::sink_rate_limit_fragments())
452 .chain(Self::dml_rate_limit_fragments())
453 }
454
455 pub fn dml_rate_limit_fragments() -> impl Iterator<Item = FragmentTypeFlag> {
456 [FragmentTypeFlag::Dml].into_iter()
457 }
458}
459
460#[derive(Clone, Copy, Debug, Hash, PartialOrd, PartialEq, Eq, Default)]
461pub struct FragmentTypeMask(u32);
462
463impl Binary for FragmentTypeMask {
464 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
465 write!(f, "{:b}", self.0)
466 }
467}
468
469impl From<i32> for FragmentTypeMask {
470 fn from(value: i32) -> Self {
471 Self(value as u32)
472 }
473}
474
475impl From<u32> for FragmentTypeMask {
476 fn from(value: u32) -> Self {
477 Self(value)
478 }
479}
480
481impl From<FragmentTypeMask> for u32 {
482 fn from(value: FragmentTypeMask) -> Self {
483 value.0
484 }
485}
486
487impl From<FragmentTypeMask> for i32 {
488 fn from(value: FragmentTypeMask) -> Self {
489 value.0 as _
490 }
491}
492
493impl FragmentTypeMask {
494 pub fn empty() -> Self {
495 FragmentTypeMask(0)
496 }
497
498 pub fn add(&mut self, flag: FragmentTypeFlag) {
499 self.0 |= flag as u32;
500 }
501
502 pub fn contains_any(&self, flags: impl IntoIterator<Item = FragmentTypeFlag>) -> bool {
503 let flag = FragmentTypeFlag::raw_flag(flags);
504 (self.0 & flag) != 0
505 }
506
507 pub fn contains(&self, flag: FragmentTypeFlag) -> bool {
508 self.contains_any([flag])
509 }
510}
511
512#[cfg(test)]
513mod tests {
514 use itertools::Itertools;
515 use risingwave_common::catalog::FRAGMENT_TYPE_FLAG_LIST;
516
517 use crate::catalog::FragmentTypeFlag;
518
519 #[test]
520 fn test_all_fragment_type_flag() {
521 expect_test::expect![[r#"
522 [
523 (
524 Source,
525 1,
526 "SOURCE",
527 ),
528 (
529 Mview,
530 2,
531 "MVIEW",
532 ),
533 (
534 Sink,
535 4,
536 "SINK",
537 ),
538 (
539 Now,
540 8,
541 "NOW",
542 ),
543 (
544 StreamScan,
545 16,
546 "STREAM_SCAN",
547 ),
548 (
549 BarrierRecv,
550 32,
551 "BARRIER_RECV",
552 ),
553 (
554 Values,
555 64,
556 "VALUES",
557 ),
558 (
559 Dml,
560 128,
561 "DML",
562 ),
563 (
564 CdcFilter,
565 256,
566 "CDC_FILTER",
567 ),
568 (
569 Skipped1,
570 512,
571 "SKIPPED1",
572 ),
573 (
574 SourceScan,
575 1024,
576 "SOURCE_SCAN",
577 ),
578 (
579 SnapshotBackfillStreamScan,
580 2048,
581 "SNAPSHOT_BACKFILL_STREAM_SCAN",
582 ),
583 (
584 FsFetch,
585 4096,
586 "FS_FETCH",
587 ),
588 (
589 CrossDbSnapshotBackfillStreamScan,
590 8192,
591 "CROSS_DB_SNAPSHOT_BACKFILL_STREAM_SCAN",
592 ),
593 (
594 StreamCdcScan,
595 16384,
596 "STREAM_CDC_SCAN",
597 ),
598 (
599 VectorIndexWrite,
600 32768,
601 "VECTOR_INDEX_WRITE",
602 ),
603 (
604 UpstreamSinkUnion,
605 65536,
606 "UPSTREAM_SINK_UNION",
607 ),
608 (
609 LocalityProvider,
610 131072,
611 "LOCALITY_PROVIDER",
612 ),
613 (
614 IcebergWithPkIndexWriter,
615 262144,
616 "ICEBERG_WITH_PK_INDEX_WRITER",
617 ),
618 ]
619 "#]]
620 .assert_debug_eq(
621 &FRAGMENT_TYPE_FLAG_LIST
622 .into_iter()
623 .map(|flag| (flag, flag as u32, flag.as_str_name()))
624 .collect_vec(),
625 );
626 for flag in FRAGMENT_TYPE_FLAG_LIST {
627 assert_eq!(FragmentTypeFlag::try_from(flag as u32).unwrap(), flag);
628 }
629 }
630}