Skip to main content

risingwave_expr/expr/
expr_some_all.rs

1// Copyright 2023 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
15use std::sync::Arc;
16
17use risingwave_common::array::{Array, ArrayRef, BoolArray, DataChunk};
18use risingwave_common::row::OwnedRow;
19use risingwave_common::types::{DataType, Datum, Scalar, ScalarRefImpl};
20use risingwave_common::util::iter_util::ZipEqFast;
21use risingwave_common::{bail, ensure};
22use risingwave_pb::expr::expr_node::{RexNode, Type};
23use risingwave_pb::expr::{ExprNode, FunctionCall};
24
25use super::build::get_children_and_return_type;
26use super::{
27    AsyncExpression, AsyncExpressionBoxExt, BoxedExpression, BuildBoxed, ExpressionInfo,
28    SyncExpression, SyncExpressionBoxExt,
29};
30use crate::Result;
31
32#[derive(Debug)]
33pub struct SomeAllExpression<E> {
34    left_expr: E,
35    right_expr: E,
36    expr_type: Type,
37    func: E,
38}
39
40impl<E> SomeAllExpression<E> {
41    pub fn new(left_expr: E, right_expr: E, expr_type: Type, func: E) -> Self {
42        SomeAllExpression {
43            left_expr,
44            right_expr,
45            expr_type,
46            func,
47        }
48    }
49
50    // Notice that this function may not exhaust the iterator,
51    // so never pass an iterator created `by_ref`.
52    fn resolve_bools(&self, bools: impl Iterator<Item = Option<bool>>) -> Option<bool> {
53        match self.expr_type {
54            Type::Some => {
55                let mut any_none = false;
56                for b in bools {
57                    match b {
58                        Some(true) => return Some(true),
59                        Some(false) => continue,
60                        None => any_none = true,
61                    }
62                }
63                if any_none { None } else { Some(false) }
64            }
65            Type::All => {
66                let mut all_true = true;
67                for b in bools {
68                    if b == Some(false) {
69                        return Some(false);
70                    }
71                    if b != Some(true) {
72                        all_true = false;
73                    }
74                }
75                if all_true { Some(true) } else { None }
76            }
77            _ => unreachable!(),
78        }
79    }
80}
81
82impl<E: ExpressionInfo> ExpressionInfo for SomeAllExpression<E> {
83    fn return_type(&self) -> DataType {
84        DataType::Boolean
85    }
86}
87
88macro_rules! eval_some_all {
89    ($mode:ident, $this:expr, $data_chunk:expr) => {{
90        let arr_left = forward!($mode, $this.left_expr, eval($data_chunk))?;
91        let arr_right = forward!($mode, $this.right_expr, eval($data_chunk))?;
92        let mut num_array = Vec::with_capacity($data_chunk.capacity());
93
94        let arr_right_inner = arr_right.as_list();
95        let elem_type = arr_right_inner.data_type().into_list_elem();
96        let capacity = arr_right_inner.flatten().len();
97
98        let mut unfolded_arr_left_builder = arr_left.create_builder(capacity);
99        let mut unfolded_arr_right_builder = elem_type.create_array_builder(capacity);
100
101        let mut unfolded_left_right =
102            |left: Option<ScalarRefImpl<'_>>,
103             right: Option<ScalarRefImpl<'_>>,
104             num_array: &mut Vec<Option<usize>>| {
105                if right.is_none() {
106                    num_array.push(None);
107                    return;
108                }
109
110                let array = right.unwrap().into_list();
111                let flattened = array.flatten();
112                let len = flattened.len();
113                num_array.push(Some(len));
114                unfolded_arr_left_builder.append_n(len, left);
115                for item in flattened.iter() {
116                    unfolded_arr_right_builder.append(item);
117                }
118            };
119
120        if $data_chunk.is_vis_compacted() {
121            for (left, right) in arr_left.iter().zip_eq_fast(arr_right.iter()) {
122                unfolded_left_right(left, right, &mut num_array);
123            }
124        } else {
125            for ((left, right), visible) in arr_left
126                .iter()
127                .zip_eq_fast(arr_right.iter())
128                .zip_eq_fast($data_chunk.visibility().iter())
129            {
130                if !visible {
131                    num_array.push(None);
132                    continue;
133                }
134                unfolded_left_right(left, right, &mut num_array);
135            }
136        }
137
138        assert_eq!(num_array.len(), $data_chunk.capacity());
139
140        let unfolded_arr_left = unfolded_arr_left_builder.finish();
141        let unfolded_arr_right = unfolded_arr_right_builder.finish();
142
143        // Unfolded array are actually compacted, and the visibility of the output array will be
144        // further restored by `num_array`.
145        assert_eq!(unfolded_arr_left.len(), unfolded_arr_right.len());
146        let unfolded_compact_len = unfolded_arr_left.len();
147
148        let data_chunk = DataChunk::new(
149            vec![unfolded_arr_left.into(), unfolded_arr_right.into()],
150            unfolded_compact_len,
151        );
152
153        let func_results = forward!($mode, $this.func, eval(&data_chunk))?;
154        let bools = func_results.as_bool();
155        let mut offset = 0;
156        Ok(Arc::new(
157            num_array
158                .into_iter()
159                .map(|num| match num {
160                    Some(num) => {
161                        let range = offset..offset + num;
162                        offset += num;
163                        $this.resolve_bools(range.map(|i| bools.value_at(i)))
164                    }
165                    None => None,
166                })
167                .collect::<BoolArray>()
168                .into(),
169        ))
170    }};
171}
172
173macro_rules! eval_row_some_all {
174    ($mode:ident, $this:expr, $row:expr) => {{
175        let datum_left = forward!($mode, $this.left_expr, eval_row($row))?;
176        let datum_right = forward!($mode, $this.right_expr, eval_row($row))?;
177        let Some(array_right) = datum_right else {
178            return Ok(None);
179        };
180        let array_right = array_right.into_list().into_array();
181        let len = array_right.len();
182
183        // expand left to array
184        let array_left = {
185            let mut builder = $this.left_expr.return_type().create_array_builder(len);
186            builder.append_n(len, datum_left);
187            builder.finish().into_ref()
188        };
189
190        let chunk = DataChunk::new(vec![array_left, Arc::new(array_right)], len);
191        let bools = forward!($mode, $this.func, eval(&chunk))?;
192
193        Ok($this
194            .resolve_bools(bools.as_bool().iter())
195            .map(|b| b.to_scalar_value()))
196    }};
197}
198
199impl<E: SyncExpression> SyncExpression for SomeAllExpression<E> {
200    fn eval(&self, data_chunk: &DataChunk) -> Result<ArrayRef> {
201        eval_some_all!(sync, self, data_chunk)
202    }
203
204    fn eval_row(&self, row: &OwnedRow) -> Result<Datum> {
205        eval_row_some_all!(sync, self, row)
206    }
207}
208
209impl<E: AsyncExpression> AsyncExpression for SomeAllExpression<E> {
210    async fn eval(&self, data_chunk: &DataChunk) -> Result<ArrayRef> {
211        eval_some_all!(async, self, data_chunk)
212    }
213
214    async fn eval_row(&self, row: &OwnedRow) -> Result<Datum> {
215        eval_row_some_all!(async, self, row)
216    }
217}
218
219impl SomeAllExpression<BoxedExpression> {
220    fn build(
221        prost: &ExprNode,
222        build_child: impl Fn(&ExprNode) -> Result<BoxedExpression>,
223    ) -> Result<Self> {
224        let outer_expr_type = prost.get_function_type().unwrap();
225        let (outer_children, outer_return_type) = get_children_and_return_type(prost)?;
226        ensure!(matches!(outer_return_type, DataType::Boolean));
227
228        let mut inner_expr_type = outer_children[0].get_function_type().unwrap();
229        let (mut inner_children, mut inner_return_type) =
230            get_children_and_return_type(&outer_children[0])?;
231        let mut stack = vec![];
232        while inner_children.len() != 2 {
233            stack.push((inner_expr_type, inner_return_type));
234            inner_expr_type = inner_children[0].get_function_type().unwrap();
235            (inner_children, inner_return_type) = get_children_and_return_type(&inner_children[0])?;
236        }
237
238        let left_expr = build_child(&inner_children[0])?;
239        let right_expr = build_child(&inner_children[1])?;
240
241        let DataType::List(right_list_type) = right_expr.return_type() else {
242            bail!("Expect Array Type");
243        };
244        let right_expr_return_type = right_list_type.into_elem();
245
246        let eval_func = {
247            let left_expr_input_ref = ExprNode {
248                function_type: Type::Unspecified as i32,
249                return_type: Some(left_expr.return_type().to_protobuf()),
250                rex_node: Some(RexNode::InputRef(0)),
251            };
252            let right_expr_input_ref = ExprNode {
253                function_type: Type::Unspecified as i32,
254                return_type: Some(right_expr_return_type.to_protobuf()),
255                rex_node: Some(RexNode::InputRef(1)),
256            };
257            let mut root_expr_node = ExprNode {
258                function_type: inner_expr_type as i32,
259                return_type: Some(inner_return_type.to_protobuf()),
260                rex_node: Some(RexNode::FuncCall(FunctionCall {
261                    children: vec![left_expr_input_ref, right_expr_input_ref],
262                })),
263            };
264            while let Some((expr_type, return_type)) = stack.pop() {
265                root_expr_node = ExprNode {
266                    function_type: expr_type as i32,
267                    return_type: Some(return_type.to_protobuf()),
268                    rex_node: Some(RexNode::FuncCall(FunctionCall {
269                        children: vec![root_expr_node],
270                    })),
271                }
272            }
273            build_child(&root_expr_node)?
274        };
275
276        Ok(SomeAllExpression::new(
277            left_expr,
278            right_expr,
279            outer_expr_type,
280            eval_func,
281        ))
282    }
283}
284
285impl BuildBoxed for SomeAllExpression<BoxedExpression> {
286    fn build_boxed(
287        prost: &ExprNode,
288        build_child: impl Fn(&ExprNode) -> Result<BoxedExpression>,
289    ) -> Result<BoxedExpression> {
290        let expr = Self::build(prost, build_child)?;
291        Ok(match (expr.left_expr, expr.right_expr, expr.func) {
292            (
293                BoxedExpression::Sync(left_expr),
294                BoxedExpression::Sync(right_expr),
295                BoxedExpression::Sync(func),
296            ) => SomeAllExpression::new(left_expr, right_expr, expr.expr_type, func).boxed(),
297            (left_expr, right_expr, func) => {
298                SomeAllExpression::new(left_expr, right_expr, expr.expr_type, func).boxed()
299            }
300        })
301    }
302}
303
304#[cfg(test)]
305mod tests {
306    use risingwave_common::row::Row;
307    use risingwave_common::test_prelude::DataChunkTestExt;
308    use risingwave_common::types::ToOwnedDatum;
309    use risingwave_common::util::iter_util::ZipEqDebug;
310    use risingwave_expr::expr::build_from_pretty;
311
312    use super::*;
313
314    #[tokio::test]
315    async fn test_some() {
316        let expr = SomeAllExpression::new(
317            build_from_pretty("0:int4"),
318            build_from_pretty("$0:boolean"),
319            Type::Some,
320            build_from_pretty("$1:boolean"),
321        );
322        let (input, expected) = DataChunk::from_pretty(
323            "B[]        B
324             .          .
325             {}         f
326             {NULL}     .
327             {NULL,f}   .
328             {NULL,t}   t
329             {t,f}      t
330             {f,t}      t", // <- regression test for #14214
331        )
332        .split_column_at(1);
333
334        // test eval
335        let output = expr.eval(&input).await.unwrap();
336        assert_eq!(&output, expected.column_at(0));
337
338        // test eval_row
339        for (row, expected) in input.rows().zip_eq_debug(expected.rows()) {
340            let result = expr.eval_row(&row.to_owned_row()).await.unwrap();
341            assert_eq!(result, expected.datum_at(0).to_owned_datum());
342        }
343    }
344
345    #[tokio::test]
346    async fn test_all() {
347        let expr = SomeAllExpression::new(
348            build_from_pretty("0:int4"),
349            build_from_pretty("$0:boolean"),
350            Type::All,
351            build_from_pretty("$1:boolean"),
352        );
353        let (input, expected) = DataChunk::from_pretty(
354            "B[]        B
355             .          .
356             {}         t
357             {NULL}     .
358             {NULL,t}   .
359             {NULL,f}   f
360             {f,f}      f
361             {t}        t", // <- regression test for #14214
362        )
363        .split_column_at(1);
364
365        // test eval
366        let output = expr.eval(&input).await.unwrap();
367        assert_eq!(&output, expected.column_at(0));
368
369        // test eval_row
370        for (row, expected) in input.rows().zip_eq_debug(expected.rows()) {
371            let result = expr.eval_row(&row.to_owned_row()).await.unwrap();
372            assert_eq!(result, expected.datum_at(0).to_owned_datum());
373        }
374    }
375}