risingwave_common/catalog/
external_table.rs1use std::collections::{BTreeMap, HashMap};
16
17use risingwave_pb::plan_common::cdc_key_ordering::{Column as PbCdcKeyColumn, Comparison};
18use risingwave_pb::plan_common::{CdcKeyOrdering as PbCdcKeyOrdering, ExternalTableDesc};
19use risingwave_pb::secret::PbSecretRef;
20
21use super::{ColumnDesc, ColumnId, TableId};
22use crate::id::SourceId;
23use crate::util::iter_util::ZipEqFast;
24use crate::util::sort_util::ColumnOrder;
25
26#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
31pub enum CdcKeyComparison {
32 #[default]
33 Native,
34 UnsignedInt64,
35}
36
37impl CdcKeyComparison {
38 pub fn from_protobuf(comparison: Comparison) -> Self {
39 match comparison {
40 Comparison::Unspecified => unreachable!("comparison must be specified"),
41 Comparison::Native => Self::Native,
42 Comparison::UnsignedInt64 => Self::UnsignedInt64,
43 }
44 }
45
46 fn to_protobuf(self) -> Comparison {
47 match self {
48 Self::Native => Comparison::Native,
49 Self::UnsignedInt64 => Comparison::UnsignedInt64,
50 }
51 }
52}
53
54#[derive(Debug, Clone, Default, PartialEq, Eq, Hash)]
57pub struct CdcTableDesc {
58 pub table_id: TableId,
60
61 pub source_id: SourceId,
63
64 pub external_table_name: String,
67 pub pk: Vec<ColumnOrder>,
69 pub pk_comparisons: Vec<CdcKeyComparison>,
71 pub columns: Vec<ColumnDesc>,
73
74 pub stream_key: Vec<usize>,
76
77 pub connect_properties: BTreeMap<String, String>,
79 pub secret_refs: BTreeMap<String, PbSecretRef>,
81}
82
83impl CdcTableDesc {
84 pub fn to_protobuf(&self) -> ExternalTableDesc {
85 assert_eq!(self.pk.len(), self.pk_comparisons.len());
86 ExternalTableDesc {
87 table_id: self.table_id,
88 source_id: self.source_id,
89 columns: self.columns.iter().map(Into::into).collect(),
90 pk: self.pk.iter().map(|column| column.to_protobuf()).collect(),
91 pk_ordering: Some(PbCdcKeyOrdering {
92 columns: self
93 .pk
94 .iter()
95 .zip_eq_fast(&self.pk_comparisons)
96 .map(|(column_order, comparison)| PbCdcKeyColumn {
97 pk_col_idx: column_order.column_index as _,
98 comparison: comparison.to_protobuf() as _,
99 })
100 .collect(),
101 }),
102 table_name: self.external_table_name.clone(),
103 stream_key: self.stream_key.iter().map(|k| *k as _).collect(),
104 connect_properties: self.connect_properties.clone(),
105 secret_refs: self.secret_refs.clone(),
106 }
107 }
108
109 pub fn get_id_to_op_idx_mapping(&self) -> HashMap<ColumnId, usize> {
111 ColumnDesc::get_id_to_op_idx_mapping(self.columns.as_slice(), None)
112 }
113}
114
115#[cfg(test)]
116mod tests {
117 use risingwave_pb::plan_common::cdc_key_ordering::Comparison;
118
119 use super::*;
120 use crate::util::sort_util::OrderType;
121
122 #[test]
123 fn test_cdc_key_comparisons_are_persisted_with_pk_indices() {
124 let table_desc = CdcTableDesc {
125 table_id: TableId::new(1),
126 source_id: SourceId::new(2),
127 external_table_name: "orders".to_owned(),
128 pk: vec![
129 ColumnOrder::new(3, OrderType::ascending()),
130 ColumnOrder::new(1, OrderType::ascending()),
131 ],
132 pk_comparisons: vec![CdcKeyComparison::UnsignedInt64, CdcKeyComparison::Native],
133 columns: vec![],
134 stream_key: vec![3, 1],
135 connect_properties: BTreeMap::new(),
136 secret_refs: BTreeMap::new(),
137 };
138
139 let protobuf = table_desc.to_protobuf();
140 assert_eq!(protobuf.pk.len(), 2);
141 assert_eq!(protobuf.pk[0].column_index, 3);
142 assert_eq!(protobuf.pk[1].column_index, 1);
143
144 let pk_columns = protobuf.pk_ordering.unwrap().columns;
145 assert_eq!(pk_columns.len(), 2);
146 assert_eq!(pk_columns[0].pk_col_idx, 3);
147 assert_eq!(
148 pk_columns[0].get_comparison().unwrap(),
149 Comparison::UnsignedInt64
150 );
151 assert_eq!(pk_columns[1].pk_col_idx, 1);
152 assert_eq!(pk_columns[1].get_comparison().unwrap(), Comparison::Native);
153 }
154}