1use std::fmt::Display;
16use std::ops::Deref;
17use std::sync::Arc;
18
19use anyhow::Context;
20use educe::Educe;
21use risingwave_common::bail;
22use risingwave_common::row::OwnedRow;
23use risingwave_common::types::{
24 DataType, Datum, IsNegative, ScalarImpl, ScalarRefImpl, Sentinelled, ToOwnedDatum, ToText,
25};
26use risingwave_common::util::sort_util::{Direction, OrderType};
27use risingwave_common::util::value_encoding::{DatumFromProtoExt, DatumToProtoExt};
28use risingwave_pb::expr::window_frame::{PbBoundType, PbRangeFrameBound, PbRangeFrameBounds};
29
30use super::FrameBound::{
31 self, CurrentRow, Following, Preceding, UnboundedFollowing, UnboundedPreceding,
32};
33use super::FrameBoundsImpl;
34use crate::Result;
35use crate::expr::{
36 InputRefExpression, LiteralExpression, SyncExpression, SyncExpressionBoxExt, build_func,
37};
38
39#[derive(Debug, Clone, Eq, PartialEq, Hash)]
40pub struct RangeFrameBounds {
41 pub order_data_type: DataType,
42 pub order_type: OrderType,
43 pub offset_data_type: DataType,
44 pub start: RangeFrameBound,
45 pub end: RangeFrameBound,
46}
47
48impl RangeFrameBounds {
49 pub(super) fn from_protobuf(bounds: &PbRangeFrameBounds) -> Result<Self> {
50 let order_data_type = DataType::from(bounds.get_order_data_type()?);
51 let order_type = OrderType::from_protobuf(bounds.get_order_type()?);
52 let offset_data_type = DataType::from(bounds.get_offset_data_type()?);
53 let start = FrameBound::<RangeFrameOffset>::from_protobuf(
54 bounds.get_start()?,
55 &order_data_type,
56 &offset_data_type,
57 )?;
58 let end = FrameBound::<RangeFrameOffset>::from_protobuf(
59 bounds.get_end()?,
60 &order_data_type,
61 &offset_data_type,
62 )?;
63 Ok(Self {
64 order_data_type,
65 order_type,
66 offset_data_type,
67 start,
68 end,
69 })
70 }
71
72 pub(super) fn to_protobuf(&self) -> PbRangeFrameBounds {
73 PbRangeFrameBounds {
74 start: Some(self.start.to_protobuf()),
75 end: Some(self.end.to_protobuf()),
76 order_data_type: Some(self.order_data_type.to_protobuf()),
77 order_type: Some(self.order_type.to_protobuf()),
78 offset_data_type: Some(self.offset_data_type.to_protobuf()),
79 }
80 }
81}
82
83impl Display for RangeFrameBounds {
84 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
85 write!(
86 f,
87 "RANGE BETWEEN {} AND {}",
88 self.start.for_display(),
89 self.end.for_display()
90 )?;
91 Ok(())
92 }
93}
94
95impl FrameBoundsImpl for RangeFrameBounds {
96 fn validate(&self) -> Result<()> {
97 fn validate_non_negative(val: impl IsNegative + Display) -> Result<()> {
98 if val.is_negative() {
99 bail!(
100 "frame bound offset should be non-negative, but {} is given",
101 val
102 );
103 }
104 Ok(())
105 }
106
107 FrameBound::validate_bounds(&self.start, &self.end, |offset| {
108 match offset.as_scalar_ref_impl() {
109 ScalarRefImpl::Int16(val) => validate_non_negative(val)?,
111 ScalarRefImpl::Int32(val) => validate_non_negative(val)?,
112 ScalarRefImpl::Int64(val) => validate_non_negative(val)?,
113 ScalarRefImpl::Float32(val) => validate_non_negative(val)?,
114 ScalarRefImpl::Float64(val) => validate_non_negative(val)?,
115 ScalarRefImpl::Decimal(val) => validate_non_negative(val)?,
116 ScalarRefImpl::Interval(val) => {
117 if !val.is_never_negative() {
118 bail!(
119 "for frame bound offset of type `interval`, each field should be non-negative, but {} is given",
120 val
121 );
122 }
123 if matches!(self.order_data_type, DataType::Timestamptz) {
124 if val.months() != 0 || val.days() != 0 {
126 bail!(
127 "for frame order column of type `timestamptz`, offset should not have non-zero `month` and `day`",
128 );
129 }
130 }
131 }
132 _ => unreachable!(
133 "other order column data types are not supported and should be banned in frontend"
134 ),
135 }
136 Ok(())
137 })
138 }
139}
140
141impl RangeFrameBounds {
142 pub fn frame_start_of(&self, order_value: impl ToOwnedDatum) -> Sentinelled<Datum> {
172 self.start.for_calc().bound_of(order_value, self.order_type)
173 }
174
175 pub fn frame_end_of(&self, order_value: impl ToOwnedDatum) -> Sentinelled<Datum> {
178 self.end.for_calc().bound_of(order_value, self.order_type)
179 }
180
181 pub fn first_curr_of(&self, order_value: impl ToOwnedDatum) -> Sentinelled<Datum> {
211 self.end
212 .for_calc()
213 .reverse()
214 .bound_of(order_value, self.order_type)
215 }
216
217 pub fn last_curr_of(&self, order_value: impl ToOwnedDatum) -> Sentinelled<Datum> {
220 self.start
221 .for_calc()
222 .reverse()
223 .bound_of(order_value, self.order_type)
224 }
225}
226
227pub type RangeFrameBound = FrameBound<RangeFrameOffset>;
228
229impl RangeFrameBound {
230 fn from_protobuf(
231 bound: &PbRangeFrameBound,
232 order_data_type: &DataType,
233 offset_data_type: &DataType,
234 ) -> Result<Self> {
235 let bound = match bound.get_type()? {
236 PbBoundType::Unspecified => bail!("unspecified type of `RangeFrameBound`"),
237 PbBoundType::UnboundedPreceding => Self::UnboundedPreceding,
238 PbBoundType::CurrentRow => Self::CurrentRow,
239 PbBoundType::UnboundedFollowing => Self::UnboundedFollowing,
240 bound_type @ (PbBoundType::Preceding | PbBoundType::Following) => {
241 let offset_value = Datum::from_protobuf(bound.get_offset()?, offset_data_type)
242 .context("offset `Datum` is not decodable")?
243 .context("offset of `RangeFrameBound` must be non-NULL")?;
244 let mut offset = RangeFrameOffset::new(offset_value);
245 offset.prepare(order_data_type, offset_data_type)?;
246 if bound_type == PbBoundType::Preceding {
247 Self::Preceding(offset)
248 } else {
249 Self::Following(offset)
250 }
251 }
252 };
253 Ok(bound)
254 }
255
256 fn to_protobuf(&self) -> PbRangeFrameBound {
257 let (r#type, offset) = match self {
258 Self::UnboundedPreceding => (PbBoundType::UnboundedPreceding, None),
259 Self::Preceding(offset) => (
260 PbBoundType::Preceding,
261 Some(Some(offset.as_scalar_ref_impl()).to_protobuf()),
262 ),
263 Self::CurrentRow => (PbBoundType::CurrentRow, None),
264 Self::Following(offset) => (
265 PbBoundType::Following,
266 Some(Some(offset.as_scalar_ref_impl()).to_protobuf()),
267 ),
268 Self::UnboundedFollowing => (PbBoundType::UnboundedFollowing, None),
269 };
270 PbRangeFrameBound {
271 r#type: r#type as _,
272 offset,
273 }
274 }
275}
276
277impl RangeFrameBound {
278 fn for_display(&self) -> FrameBound<String> {
279 match self {
280 UnboundedPreceding => UnboundedPreceding,
281 Preceding(offset) => Preceding(offset.as_scalar_ref_impl().to_text()),
282 CurrentRow => CurrentRow,
283 Following(offset) => Following(offset.as_scalar_ref_impl().to_text()),
284 UnboundedFollowing => UnboundedFollowing,
285 }
286 }
287
288 fn for_calc(&self) -> FrameBound<RangeFrameOffsetRef<'_>> {
289 match self {
290 UnboundedPreceding => UnboundedPreceding,
291 Preceding(offset) => Preceding(RangeFrameOffsetRef {
292 add_expr: offset.add_expr.as_ref().unwrap().as_ref(),
293 sub_expr: offset.sub_expr.as_ref().unwrap().as_ref(),
294 }),
295 CurrentRow => CurrentRow,
296 Following(offset) => Following(RangeFrameOffsetRef {
297 add_expr: offset.add_expr.as_ref().unwrap().as_ref(),
298 sub_expr: offset.sub_expr.as_ref().unwrap().as_ref(),
299 }),
300 UnboundedFollowing => UnboundedFollowing,
301 }
302 }
303}
304
305#[derive(Debug, Clone, Educe)]
308#[educe(PartialEq, Eq, Hash)]
309pub struct RangeFrameOffset {
310 offset: ScalarImpl,
312 #[educe(PartialEq(ignore), Hash(ignore))]
314 add_expr: Option<Arc<dyn SyncExpression>>,
315 #[educe(PartialEq(ignore), Hash(ignore))]
317 sub_expr: Option<Arc<dyn SyncExpression>>,
318}
319
320impl RangeFrameOffset {
321 pub fn new(offset: ScalarImpl) -> Self {
322 Self {
323 offset,
324 add_expr: None,
325 sub_expr: None,
326 }
327 }
328
329 fn prepare(&mut self, order_data_type: &DataType, offset_data_type: &DataType) -> Result<()> {
330 use risingwave_pb::expr::expr_node::PbType as PbExprType;
331
332 let input_expr = InputRefExpression::new(order_data_type.clone(), 0);
333 let offset_expr =
334 LiteralExpression::new(offset_data_type.clone(), Some(self.offset.clone()));
335 let add_expr = build_func(
336 PbExprType::Add,
337 order_data_type.clone(),
338 vec![input_expr.clone().boxed(), offset_expr.clone().boxed()],
339 )?;
340 let crate::expr::BoxedExpression::Sync(add_expr) = add_expr else {
341 bail!("range frame offset add expression must be sync");
342 };
343 self.add_expr = Some(add_expr);
344
345 let sub_expr = build_func(
346 PbExprType::Subtract,
347 order_data_type.clone(),
348 vec![input_expr.boxed(), offset_expr.boxed()],
349 )?;
350 let crate::expr::BoxedExpression::Sync(sub_expr) = sub_expr else {
351 bail!("range frame offset subtract expression must be sync");
352 };
353 self.sub_expr = Some(sub_expr);
354 Ok(())
355 }
356
357 pub fn new_for_test(
358 offset: ScalarImpl,
359 order_data_type: &DataType,
360 offset_data_type: &DataType,
361 ) -> Self {
362 let mut offset = Self::new(offset);
363 offset.prepare(order_data_type, offset_data_type).unwrap();
364 offset
365 }
366}
367
368impl Deref for RangeFrameOffset {
369 type Target = ScalarImpl;
370
371 fn deref(&self) -> &Self::Target {
372 &self.offset
373 }
374}
375
376#[derive(Debug, Educe)]
377#[educe(Clone, Copy)]
378struct RangeFrameOffsetRef<'a> {
379 add_expr: &'a dyn SyncExpression,
381 sub_expr: &'a dyn SyncExpression,
383}
384
385impl FrameBound<RangeFrameOffsetRef<'_>> {
386 fn bound_of(self, order_value: impl ToOwnedDatum, order_type: OrderType) -> Sentinelled<Datum> {
387 let expr = match (self, order_type.direction()) {
388 (UnboundedPreceding, _) => return Sentinelled::Smallest,
389 (UnboundedFollowing, _) => return Sentinelled::Largest,
390 (CurrentRow, _) => return Sentinelled::Normal(order_value.to_owned_datum()),
391 (Preceding(offset), Direction::Ascending)
392 | (Following(offset), Direction::Descending) => {
393 offset.sub_expr
395 }
396 (Following(offset), Direction::Ascending)
397 | (Preceding(offset), Direction::Descending) => {
398 offset.add_expr
400 }
401 };
402 let row = OwnedRow::new(vec![order_value.to_owned_datum()]);
403 Sentinelled::Normal(
404 expr.eval_row(&row)
405 .expect("just simple calculation, should succeed"), )
407 }
408}