Skip to main content

risingwave_common/catalog/
mod.rs

1// Copyright 2022 RisingWave Labs
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15pub 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
45/// The global version of the catalog.
46pub type CatalogVersion = u64;
47
48/// The version number of the per-table catalog.
49pub type TableVersionId = u64;
50/// The default version ID for a new table.
51pub const INITIAL_TABLE_VERSION_ID: u64 = 0;
52/// The version number of the per-source catalog.
53pub type SourceVersionId = u64;
54/// The default version ID for a new source.
55pub 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);
65// This is for compatibility with customized utils for PostgreSQL.
66pub const DEFAULT_SUPER_USER_FOR_PG: &str = "postgres";
67pub const DEFAULT_SUPER_USER_FOR_PG_ID: u32 = 2;
68
69// This is the default superuser for admin, which is used only for cloud control plane.
70pub 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
95/// When there is no primary key specified while creating source, will use
96/// the message key as primary key in `BYTEA` type with this name.
97/// Note: the field has version to track, please refer to [`default_key_column_name_version_mapping`]
98pub 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
107/// For kafka source, we attach a hidden column [`KAFKA_TIMESTAMP_COLUMN_NAME`] to it, so that we
108/// can limit the timestamp range when querying it directly with batch query. The column type is
109/// [`crate::types::DataType::Timestamptz`]. For more details, please refer to
110/// [this rfc](https://github.com/risingwavelabs/rfcs/pull/20).
111pub const KAFKA_TIMESTAMP_COLUMN_NAME: &str = "_rw_kafka_timestamp";
112
113/// RisingWave iceberg table engine will create the column `_risingwave_iceberg_row_id` in the iceberg table.
114///
115/// Iceberg V3 spec use `_row_id` as a reserved column name for row lineage, so if the table without primary key,
116/// we can't use `_row_id` directly for iceberg, so use `_risingwave_iceberg_row_id` instead.
117pub const RISINGWAVE_ICEBERG_ROW_ID: &str = "_risingwave_iceberg_row_id";
118
119pub const ROW_ID_COLUMN_NAME: &str = "_row_id";
120/// The column ID preserved for the row ID column.
121pub const ROW_ID_COLUMN_ID: ColumnId = ColumnId::new(0);
122
123/// The column ID offset for user-defined columns.
124///
125/// All IDs of user-defined columns must be greater or equal to this value.
126pub 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
131/// The column name for the projected row ID in `ProjectSet`.
132/// This is a hidden column used to track row indices when expanding set-returning functions.
133pub 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";
140/// The number of columns output by the cdc source job
141/// see [`ColumnCatalog::debezium_cdc_source_cols()`] for details
142pub 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
148/// The local system catalog reader in the frontend node.
149pub trait SysCatalogReader: Sync + Send + 'static {
150    /// Reads the data of the system catalog table.
151    fn read_table(&self, table_id: TableId) -> BoxStream<'_, Result<DataChunk, BoxedError>>;
152}
153
154pub type SysCatalogReaderRef = Arc<dyn SysCatalogReader>;
155
156#[derive(Clone, Debug, PartialEq, Default, Copy)]
157pub struct TableOption {
158    pub retention_seconds: Option<u32>, // second
159}
160
161impl From<&risingwave_pb::hummock::TableOption> for TableOption {
162    fn from(table_option: &risingwave_pb::hummock::TableOption) -> Self {
163        Self {
164            retention_seconds: table_option.retention_seconds,
165        }
166    }
167}
168
169impl From<&TableOption> for risingwave_pb::hummock::TableOption {
170    fn from(table_option: &TableOption) -> Self {
171        Self {
172            retention_seconds: table_option.retention_seconds,
173        }
174    }
175}
176
177impl TableOption {
178    pub fn new(retention_seconds: Option<u32>) -> Self {
179        // now we only support ttl for TableOption
180        TableOption { retention_seconds }
181    }
182}
183
184#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash)]
185pub enum ConflictBehavior {
186    #[default]
187    NoCheck,
188    Overwrite,
189    IgnoreConflict,
190    DoUpdateIfNotNull,
191}
192
193#[macro_export]
194macro_rules! _checked_conflict_behaviors {
195    () => {
196        ConflictBehavior::Overwrite
197            | ConflictBehavior::IgnoreConflict
198            | ConflictBehavior::DoUpdateIfNotNull
199    };
200}
201pub use _checked_conflict_behaviors as checked_conflict_behaviors;
202
203impl ConflictBehavior {
204    pub fn from_protobuf(tb_conflict_behavior: &PbHandleConflictBehavior) -> Self {
205        match tb_conflict_behavior {
206            PbHandleConflictBehavior::Overwrite => ConflictBehavior::Overwrite,
207            PbHandleConflictBehavior::Ignore => ConflictBehavior::IgnoreConflict,
208            PbHandleConflictBehavior::DoUpdateIfNotNull => ConflictBehavior::DoUpdateIfNotNull,
209            // This is for backward compatibility, in the previous version
210            // `HandleConflictBehavior::Unspecified` represented `NoCheck`, so just treat it as `NoCheck`.
211            PbHandleConflictBehavior::NoCheck | PbHandleConflictBehavior::Unspecified => {
212                ConflictBehavior::NoCheck
213            }
214        }
215    }
216
217    pub fn to_protobuf(self) -> PbHandleConflictBehavior {
218        match self {
219            ConflictBehavior::NoCheck => PbHandleConflictBehavior::NoCheck,
220            ConflictBehavior::Overwrite => PbHandleConflictBehavior::Overwrite,
221            ConflictBehavior::IgnoreConflict => PbHandleConflictBehavior::Ignore,
222            ConflictBehavior::DoUpdateIfNotNull => PbHandleConflictBehavior::DoUpdateIfNotNull,
223        }
224    }
225
226    pub fn debug_to_string(self) -> String {
227        match self {
228            ConflictBehavior::NoCheck => "NoCheck".to_owned(),
229            ConflictBehavior::Overwrite => "Overwrite".to_owned(),
230            ConflictBehavior::IgnoreConflict => "IgnoreConflict".to_owned(),
231            ConflictBehavior::DoUpdateIfNotNull => "DoUpdateIfNotNull".to_owned(),
232        }
233    }
234}
235
236#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash)]
237pub enum Engine {
238    #[default]
239    Hummock,
240    Iceberg,
241}
242
243impl Engine {
244    pub fn from_protobuf(engine: &PbEngine) -> Self {
245        match engine {
246            PbEngine::Hummock | PbEngine::Unspecified => Engine::Hummock,
247            PbEngine::Iceberg => Engine::Iceberg,
248        }
249    }
250
251    pub fn to_protobuf(self) -> PbEngine {
252        match self {
253            Engine::Hummock => PbEngine::Hummock,
254            Engine::Iceberg => PbEngine::Iceberg,
255        }
256    }
257
258    pub fn debug_to_string(self) -> String {
259        match self {
260            Engine::Hummock => "Hummock".to_owned(),
261            Engine::Iceberg => "Iceberg".to_owned(),
262        }
263    }
264}
265
266#[derive(Clone, Copy, Debug, Default, Display, Hash, PartialOrd, PartialEq, Eq, Ord)]
267pub enum StreamJobStatus {
268    #[default]
269    Creating,
270    Created,
271}
272
273impl StreamJobStatus {
274    pub fn from_proto(stream_job_status: PbStreamJobStatus) -> Self {
275        match stream_job_status {
276            PbStreamJobStatus::Creating => StreamJobStatus::Creating,
277            PbStreamJobStatus::Created | PbStreamJobStatus::Unspecified => StreamJobStatus::Created,
278        }
279    }
280
281    pub fn to_proto(self) -> PbStreamJobStatus {
282        match self {
283            StreamJobStatus::Creating => PbStreamJobStatus::Creating,
284            StreamJobStatus::Created => PbStreamJobStatus::Created,
285        }
286    }
287}
288
289#[derive(Clone, Copy, Debug, Display, Hash, PartialOrd, PartialEq, Eq, Ord, Default)]
290pub enum CreateType {
291    #[default]
292    Foreground,
293    Background,
294}
295
296impl CreateType {
297    pub fn from_proto(pb_create_type: PbCreateType) -> Self {
298        match pb_create_type {
299            PbCreateType::Foreground | PbCreateType::Unspecified => CreateType::Foreground,
300            PbCreateType::Background => CreateType::Background,
301        }
302    }
303
304    pub fn to_proto(self) -> PbCreateType {
305        match self {
306            CreateType::Foreground => PbCreateType::Foreground,
307            CreateType::Background => PbCreateType::Background,
308        }
309    }
310}
311
312#[derive(Clone, Debug)]
313pub enum AlterDatabaseParam {
314    // Barrier related parameters, per database.
315    // None represents the default value, which means it follows `SystemParams`.
316    BarrierIntervalMs(Option<u32>),
317    CheckpointFrequency(Option<u64>),
318}
319
320macro_rules! for_all_fragment_type_flags {
321    () => {
322        for_all_fragment_type_flags! {
323            {
324                Source,
325                Mview,
326                Sink,
327                Now,
328                StreamScan,
329                BarrierRecv,
330                Values,
331                Dml,
332                CdcFilter,
333                Skipped1,
334                SourceScan,
335                SnapshotBackfillStreamScan,
336                FsFetch,
337                CrossDbSnapshotBackfillStreamScan,
338                StreamCdcScan,
339                VectorIndexWrite,
340                UpstreamSinkUnion,
341                LocalityProvider
342            },
343            {},
344            0
345        }
346    };
347    (
348        {},
349        {
350            $(
351                {$flag:ident, $index:expr}
352            ),*
353        },
354        $next_index:expr
355    ) => {
356        #[derive(Clone, Copy, Debug, Display, Hash, PartialOrd, PartialEq, Eq)]
357        #[repr(u32)]
358        pub enum FragmentTypeFlag {
359            $(
360                $flag = (1 << $index),
361            )*
362        }
363
364        pub const FRAGMENT_TYPE_FLAG_LIST: [FragmentTypeFlag; $next_index] = [
365            $(
366                FragmentTypeFlag::$flag,
367            )*
368        ];
369
370        impl TryFrom<u32> for FragmentTypeFlag {
371            type Error = String;
372
373            fn try_from(value: u32) -> Result<Self, Self::Error> {
374                match value {
375                    $(
376                        value if value == (FragmentTypeFlag::$flag as u32) => Ok(FragmentTypeFlag::$flag),
377                    )*
378                    _ => Err(format!("Invalid FragmentTypeFlag value: {}", value)),
379                }
380            }
381        }
382
383        impl FragmentTypeFlag {
384            pub fn as_str_name(&self) -> &'static str {
385                match self {
386                    $(
387                        FragmentTypeFlag::$flag => paste::paste!{stringify!( [< $flag:snake:upper >] )},
388                    )*
389                }
390            }
391        }
392    };
393    (
394        {$first:ident $(, $rest:ident)*},
395        {
396            $(
397                {$flag:ident, $index:expr}
398            ),*
399        },
400        $next_index:expr
401    ) => {
402        for_all_fragment_type_flags! {
403            {$($rest),*},
404            {
405                $({$flag, $index},)*
406                {$first, $next_index}
407            },
408            $next_index + 1
409        }
410    };
411}
412
413for_all_fragment_type_flags!();
414
415impl FragmentTypeFlag {
416    pub fn raw_flag(flags: impl IntoIterator<Item = FragmentTypeFlag>) -> u32 {
417        flags.into_iter().fold(0, |acc, flag| acc | (flag as u32))
418    }
419
420    /// Fragments that may be affected by `BACKFILL_RATE_LIMIT`.
421    pub fn backfill_rate_limit_fragments() -> impl Iterator<Item = FragmentTypeFlag> {
422        [FragmentTypeFlag::SourceScan, FragmentTypeFlag::StreamScan].into_iter()
423    }
424
425    /// Fragments that may be affected by `SOURCE_RATE_LIMIT`.
426    /// Note: for `FsFetch`, old fragments don't have this flag set, so don't use this to check.
427    pub fn source_rate_limit_fragments() -> impl Iterator<Item = FragmentTypeFlag> {
428        [FragmentTypeFlag::Source, FragmentTypeFlag::FsFetch].into_iter()
429    }
430
431    /// Fragments that may be affected by `BACKFILL_RATE_LIMIT`.
432    pub fn sink_rate_limit_fragments() -> impl Iterator<Item = FragmentTypeFlag> {
433        [FragmentTypeFlag::Sink].into_iter()
434    }
435
436    /// Note: this doesn't include `FsFetch` created in old versions.
437    pub fn rate_limit_fragments() -> impl Iterator<Item = FragmentTypeFlag> {
438        Self::backfill_rate_limit_fragments()
439            .chain(Self::source_rate_limit_fragments())
440            .chain(Self::sink_rate_limit_fragments())
441    }
442
443    pub fn dml_rate_limit_fragments() -> impl Iterator<Item = FragmentTypeFlag> {
444        [FragmentTypeFlag::Dml].into_iter()
445    }
446}
447
448#[derive(Clone, Copy, Debug, Hash, PartialOrd, PartialEq, Eq, Default)]
449pub struct FragmentTypeMask(u32);
450
451impl Binary for FragmentTypeMask {
452    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
453        write!(f, "{:b}", self.0)
454    }
455}
456
457impl From<i32> for FragmentTypeMask {
458    fn from(value: i32) -> Self {
459        Self(value as u32)
460    }
461}
462
463impl From<u32> for FragmentTypeMask {
464    fn from(value: u32) -> Self {
465        Self(value)
466    }
467}
468
469impl From<FragmentTypeMask> for u32 {
470    fn from(value: FragmentTypeMask) -> Self {
471        value.0
472    }
473}
474
475impl From<FragmentTypeMask> for i32 {
476    fn from(value: FragmentTypeMask) -> Self {
477        value.0 as _
478    }
479}
480
481impl FragmentTypeMask {
482    pub fn empty() -> Self {
483        FragmentTypeMask(0)
484    }
485
486    pub fn add(&mut self, flag: FragmentTypeFlag) {
487        self.0 |= flag as u32;
488    }
489
490    pub fn contains_any(&self, flags: impl IntoIterator<Item = FragmentTypeFlag>) -> bool {
491        let flag = FragmentTypeFlag::raw_flag(flags);
492        (self.0 & flag) != 0
493    }
494
495    pub fn contains(&self, flag: FragmentTypeFlag) -> bool {
496        self.contains_any([flag])
497    }
498}
499
500#[cfg(test)]
501mod tests {
502    use itertools::Itertools;
503    use risingwave_common::catalog::FRAGMENT_TYPE_FLAG_LIST;
504
505    use crate::catalog::FragmentTypeFlag;
506
507    #[test]
508    fn test_all_fragment_type_flag() {
509        expect_test::expect![[r#"
510            [
511                (
512                    Source,
513                    1,
514                    "SOURCE",
515                ),
516                (
517                    Mview,
518                    2,
519                    "MVIEW",
520                ),
521                (
522                    Sink,
523                    4,
524                    "SINK",
525                ),
526                (
527                    Now,
528                    8,
529                    "NOW",
530                ),
531                (
532                    StreamScan,
533                    16,
534                    "STREAM_SCAN",
535                ),
536                (
537                    BarrierRecv,
538                    32,
539                    "BARRIER_RECV",
540                ),
541                (
542                    Values,
543                    64,
544                    "VALUES",
545                ),
546                (
547                    Dml,
548                    128,
549                    "DML",
550                ),
551                (
552                    CdcFilter,
553                    256,
554                    "CDC_FILTER",
555                ),
556                (
557                    Skipped1,
558                    512,
559                    "SKIPPED1",
560                ),
561                (
562                    SourceScan,
563                    1024,
564                    "SOURCE_SCAN",
565                ),
566                (
567                    SnapshotBackfillStreamScan,
568                    2048,
569                    "SNAPSHOT_BACKFILL_STREAM_SCAN",
570                ),
571                (
572                    FsFetch,
573                    4096,
574                    "FS_FETCH",
575                ),
576                (
577                    CrossDbSnapshotBackfillStreamScan,
578                    8192,
579                    "CROSS_DB_SNAPSHOT_BACKFILL_STREAM_SCAN",
580                ),
581                (
582                    StreamCdcScan,
583                    16384,
584                    "STREAM_CDC_SCAN",
585                ),
586                (
587                    VectorIndexWrite,
588                    32768,
589                    "VECTOR_INDEX_WRITE",
590                ),
591                (
592                    UpstreamSinkUnion,
593                    65536,
594                    "UPSTREAM_SINK_UNION",
595                ),
596                (
597                    LocalityProvider,
598                    131072,
599                    "LOCALITY_PROVIDER",
600                ),
601            ]
602        "#]]
603        .assert_debug_eq(
604            &FRAGMENT_TYPE_FLAG_LIST
605                .into_iter()
606                .map(|flag| (flag, flag as u32, flag.as_str_name()))
607                .collect_vec(),
608        );
609        for flag in FRAGMENT_TYPE_FLAG_LIST {
610            assert_eq!(FragmentTypeFlag::try_from(flag as u32).unwrap(), flag);
611        }
612    }
613}