|
13 | 13 | // limitations under the License.
|
14 | 14 |
|
15 | 15 | use std::fmt;
|
| 16 | +use std::num::NonZeroUsize; |
16 | 17 |
|
17 | 18 | use itertools::Itertools;
|
18 | 19 | use risingwave_common::catalog::{Field, Schema};
|
| 20 | +use risingwave_common::error::Result; |
19 | 21 | use risingwave_common::types::{DataType, IntervalUnit, IntervalUnitDisplay};
|
| 22 | +use risingwave_common::util::column_index_mapping::ColIndexMapping; |
| 23 | +use risingwave_expr::ExprError; |
20 | 24 |
|
21 | 25 | use super::super::utils::IndicesDisplay;
|
22 | 26 | use super::{GenericPlanNode, GenericPlanRef};
|
23 |
| -use crate::expr::{InputRef, InputRefDisplay}; |
| 27 | +use crate::expr::{ExprImpl, ExprType, FunctionCall, InputRef, InputRefDisplay, Literal}; |
24 | 28 | use crate::optimizer::optimizer_context::OptimizerContextRef;
|
25 | 29 |
|
26 | 30 | /// [`HopWindow`] implements Hop Table Function.
|
@@ -104,6 +108,141 @@ impl<PlanRef: GenericPlanRef> HopWindow<PlanRef> {
|
104 | 108 | )
|
105 | 109 | }
|
106 | 110 |
|
| 111 | + pub fn internal_window_start_col_idx(&self) -> usize { |
| 112 | + self.input.schema().len() |
| 113 | + } |
| 114 | + |
| 115 | + pub fn internal_window_end_col_idx(&self) -> usize { |
| 116 | + self.internal_window_start_col_idx() + 1 |
| 117 | + } |
| 118 | + |
| 119 | + pub fn o2i_col_mapping(&self) -> ColIndexMapping { |
| 120 | + self.output2internal_col_mapping() |
| 121 | + .composite(&self.internal2input_col_mapping()) |
| 122 | + } |
| 123 | + |
| 124 | + pub fn i2o_col_mapping(&self) -> ColIndexMapping { |
| 125 | + self.input2internal_col_mapping() |
| 126 | + .composite(&self.internal2output_col_mapping()) |
| 127 | + } |
| 128 | + |
| 129 | + pub fn internal_column_num(&self) -> usize { |
| 130 | + self.internal_window_start_col_idx() + 2 |
| 131 | + } |
| 132 | + |
| 133 | + pub fn output2internal_col_mapping(&self) -> ColIndexMapping { |
| 134 | + self.internal2output_col_mapping().inverse() |
| 135 | + } |
| 136 | + |
| 137 | + pub fn internal2output_col_mapping(&self) -> ColIndexMapping { |
| 138 | + ColIndexMapping::with_remaining_columns(&self.output_indices, self.internal_column_num()) |
| 139 | + } |
| 140 | + |
| 141 | + pub fn input2internal_col_mapping(&self) -> ColIndexMapping { |
| 142 | + ColIndexMapping::identity_or_none( |
| 143 | + self.internal_window_start_col_idx(), |
| 144 | + self.internal_column_num(), |
| 145 | + ) |
| 146 | + } |
| 147 | + |
| 148 | + pub fn internal2input_col_mapping(&self) -> ColIndexMapping { |
| 149 | + ColIndexMapping::identity_or_none( |
| 150 | + self.internal_column_num(), |
| 151 | + self.internal_window_start_col_idx(), |
| 152 | + ) |
| 153 | + } |
| 154 | + |
| 155 | + pub fn derive_window_start_and_end_exprs(&self) -> Result<(Vec<ExprImpl>, Vec<ExprImpl>)> { |
| 156 | + let Self { |
| 157 | + window_size, |
| 158 | + window_slide, |
| 159 | + time_col, |
| 160 | + .. |
| 161 | + } = &self; |
| 162 | + let units = window_size |
| 163 | + .exact_div(window_slide) |
| 164 | + .and_then(|x| NonZeroUsize::new(usize::try_from(x).ok()?)) |
| 165 | + .ok_or_else(|| ExprError::InvalidParam { |
| 166 | + name: "window", |
| 167 | + reason: format!( |
| 168 | + "window_size {} cannot be divided by window_slide {}", |
| 169 | + window_size, window_slide |
| 170 | + ), |
| 171 | + })? |
| 172 | + .get(); |
| 173 | + let window_size_expr = Literal::new(Some((*window_size).into()), DataType::Interval).into(); |
| 174 | + let window_slide_expr: ExprImpl = |
| 175 | + Literal::new(Some((*window_slide).into()), DataType::Interval).into(); |
| 176 | + let window_size_sub_slide = FunctionCall::new( |
| 177 | + ExprType::Subtract, |
| 178 | + vec![window_size_expr, window_slide_expr.clone()], |
| 179 | + )? |
| 180 | + .into(); |
| 181 | + |
| 182 | + let time_col_shifted = FunctionCall::new( |
| 183 | + ExprType::Subtract, |
| 184 | + vec![ |
| 185 | + ExprImpl::InputRef(Box::new(time_col.clone())), |
| 186 | + window_size_sub_slide, |
| 187 | + ], |
| 188 | + )? |
| 189 | + .into(); |
| 190 | + |
| 191 | + let hop_start: ExprImpl = FunctionCall::new( |
| 192 | + ExprType::TumbleStart, |
| 193 | + vec![time_col_shifted, window_slide_expr], |
| 194 | + )? |
| 195 | + .into(); |
| 196 | + |
| 197 | + let mut window_start_exprs = Vec::with_capacity(units); |
| 198 | + let mut window_end_exprs = Vec::with_capacity(units); |
| 199 | + for i in 0..units { |
| 200 | + { |
| 201 | + let window_start_offset = |
| 202 | + window_slide |
| 203 | + .checked_mul_int(i) |
| 204 | + .ok_or_else(|| ExprError::InvalidParam { |
| 205 | + name: "window", |
| 206 | + reason: format!( |
| 207 | + "window_slide {} cannot be multiplied by {}", |
| 208 | + window_slide, i |
| 209 | + ), |
| 210 | + })?; |
| 211 | + let window_start_offset_expr = |
| 212 | + Literal::new(Some(window_start_offset.into()), DataType::Interval).into(); |
| 213 | + let window_start_expr = FunctionCall::new( |
| 214 | + ExprType::Add, |
| 215 | + vec![hop_start.clone(), window_start_offset_expr], |
| 216 | + )? |
| 217 | + .into(); |
| 218 | + window_start_exprs.push(window_start_expr); |
| 219 | + } |
| 220 | + { |
| 221 | + let window_end_offset = |
| 222 | + window_slide.checked_mul_int(i + units).ok_or_else(|| { |
| 223 | + ExprError::InvalidParam { |
| 224 | + name: "window", |
| 225 | + reason: format!( |
| 226 | + "window_slide {} cannot be multiplied by {}", |
| 227 | + window_slide, |
| 228 | + i + units |
| 229 | + ), |
| 230 | + } |
| 231 | + })?; |
| 232 | + let window_end_offset_expr = |
| 233 | + Literal::new(Some(window_end_offset.into()), DataType::Interval).into(); |
| 234 | + let window_end_expr = FunctionCall::new( |
| 235 | + ExprType::Add, |
| 236 | + vec![hop_start.clone(), window_end_offset_expr], |
| 237 | + )? |
| 238 | + .into(); |
| 239 | + window_end_exprs.push(window_end_expr); |
| 240 | + } |
| 241 | + } |
| 242 | + assert_eq!(window_start_exprs.len(), window_end_exprs.len()); |
| 243 | + Ok((window_start_exprs, window_end_exprs)) |
| 244 | + } |
| 245 | + |
107 | 246 | pub fn fmt_fields_with_builder(&self, builder: &mut fmt::DebugStruct<'_, '_>) {
|
108 | 247 | let output_type = DataType::window_of(&self.time_col.data_type).unwrap();
|
109 | 248 | builder.field(
|
|
0 commit comments