risingwave_frontend/optimizer/plan_node/generic/
changelog.rs1use pretty_xmlish::{Pretty, Str, XmlNode};
16use risingwave_common::catalog::{Field, FieldDisplay, Schema};
17use risingwave_common::util::column_index_mapping::ColIndexMapping;
18
19use super::{DistillUnit, GenericPlanNode};
20use crate::OptimizerContextRef;
21use crate::optimizer::plan_node::stream::prelude::GenericPlanRef;
22use crate::optimizer::plan_node::utils::childless_record;
23use crate::optimizer::property::FunctionalDependencySet;
24use crate::utils::ColIndexMappingRewriteExt;
25
26pub const CHANGELOG_OP: &str = "changelog_op";
27pub const _CHANGELOG_ROW_ID: &str = "_changelog_row_id";
28#[derive(Debug, Clone, PartialEq, Eq, Hash)]
29pub struct ChangeLog<PlanRef> {
30 pub input: PlanRef,
31 pub key_indices: Option<Vec<usize>>,
33 pub need_op: bool,
35 pub need_changelog_row_id: bool,
38}
39impl<PlanRef: GenericPlanRef> DistillUnit for ChangeLog<PlanRef> {
40 fn distill_with_name<'a>(&self, name: impl Into<Str<'a>>) -> XmlNode<'a> {
41 let mut fields = Vec::with_capacity(1);
42
43 if let Some(key_indices) = &self.key_indices {
44 let key = Pretty::Array(
45 key_indices
46 .iter()
47 .map(|&index| {
48 let field = &self.input.schema()[index];
49
50 Pretty::display(&FieldDisplay(field))
51 })
52 .collect(),
53 );
54
55 fields.push(("key", key));
56 }
57
58 childless_record(name, fields)
59 }
60}
61impl<PlanRef: GenericPlanRef> ChangeLog<PlanRef> {
62 pub fn new(
63 input: PlanRef,
64 key_indices: Option<Vec<usize>>,
65 need_op: bool,
66 need_changelog_row_id: bool,
67 ) -> Self {
68 ChangeLog {
69 input,
70 key_indices,
71 need_op,
72 need_changelog_row_id,
73 }
74 }
75
76 pub fn clone_with_input<OtherPlanRef>(&self, input: OtherPlanRef) -> ChangeLog<OtherPlanRef> {
77 ChangeLog {
78 input,
79 key_indices: self.key_indices.clone(),
80 need_op: self.need_op,
81 need_changelog_row_id: self.need_changelog_row_id,
82 }
83 }
84
85 pub fn i2o_col_mapping(&self) -> ColIndexMapping {
86 let mut map = vec![None; self.input.schema().len()];
87 (0..self.input.schema().len()).for_each(|i| map[i] = Some(i));
88 ColIndexMapping::new(map, self.schema().len())
89 }
90}
91impl<PlanRef: GenericPlanRef> GenericPlanNode for ChangeLog<PlanRef> {
92 fn schema(&self) -> Schema {
93 let mut fields = self.input.schema().fields.clone();
94 if self.need_op {
95 fields.push(Field::with_name(
96 risingwave_common::types::DataType::Int16,
97 CHANGELOG_OP,
98 ));
99 }
100 if self.need_changelog_row_id {
101 fields.push(Field::with_name(
102 risingwave_common::types::DataType::Serial,
103 _CHANGELOG_ROW_ID,
104 ));
105 }
106 Schema::new(fields)
107 }
108
109 fn stream_key(&self) -> Option<Vec<usize>> {
110 if self.need_changelog_row_id {
111 let keys = vec![self.schema().len() - 1];
112 Some(keys)
113 } else {
114 None
115 }
116 }
117
118 fn ctx(&self) -> OptimizerContextRef {
119 self.input.ctx()
120 }
121
122 fn functional_dependency(&self) -> FunctionalDependencySet {
123 let i2o = self.i2o_col_mapping();
124 i2o.rewrite_functional_dependency_set(self.input.functional_dependency().clone())
125 }
126}