1use std::sync::Arc;
18
19use risingwave_common::array::*;
20use risingwave_common::row::OwnedRow;
21use risingwave_common::types::{DataType, Datum, Scalar};
22use risingwave_expr_macro::build_function;
23use risingwave_pb::expr::expr_node::Type;
24
25use super::{
26 AsyncExpression, AsyncExpressionBoxExt, BoxedExpression, ExpressionInfo, SyncExpression,
27 SyncExpressionBoxExt,
28};
29use crate::Result;
30
31#[derive(Debug)]
34pub struct BinaryShortCircuitExpression<E> {
35 expr_ia1: E,
36 expr_ia2: E,
37 expr_type: Type,
38}
39
40impl<E: ExpressionInfo> ExpressionInfo for BinaryShortCircuitExpression<E> {
41 fn return_type(&self) -> DataType {
42 DataType::Boolean
43 }
44}
45
46macro_rules! eval_short_circuit {
47 ($mode:ident, $this:expr, $input:expr) => {{
48 let left = forward!($mode, $this.expr_ia1, eval($input))?;
49 let left = left.as_bool();
50
51 let res_vis = match $this.expr_type {
52 Type::Or => !left.to_bitmap(),
55 Type::And => left.data() | !left.null_bitmap(),
58 _ => unimplemented!(),
59 };
60 let new_vis = $input.visibility() & res_vis;
61 let mut input1 = $input.clone();
62 input1.set_visibility(new_vis);
63
64 let right = forward!($mode, $this.expr_ia2, eval(&input1))?;
65 let right = right.as_bool();
66 assert_eq!(left.len(), right.len());
67
68 let mut bitmap = $input.visibility() & left.null_bitmap() & right.null_bitmap();
69
70 let c = match $this.expr_type {
71 Type::Or => {
72 let data = left.to_bitmap() | right.to_bitmap();
73 bitmap |= &data; BoolArray::new(data, bitmap)
75 }
76 Type::And => {
77 let data = left.to_bitmap() & right.to_bitmap();
78 bitmap |= !left.data() & left.null_bitmap(); bitmap |= !right.data() & right.null_bitmap(); BoolArray::new(data, bitmap)
81 }
82 _ => unimplemented!(),
83 };
84 Ok(Arc::new(c.into()))
85 }};
86}
87
88macro_rules! eval_row_short_circuit {
89 ($mode:ident, $this:expr, $input:expr) => {{
90 let ret_ia1 = forward!($mode, $this.expr_ia1, eval_row($input))?.map(|x| x.into_bool());
91 match $this.expr_type {
92 Type::Or if ret_ia1 == Some(true) => return Ok(Some(true.to_scalar_value())),
93 Type::And if ret_ia1 == Some(false) => return Ok(Some(false.to_scalar_value())),
94 _ => {}
95 }
96 let ret_ia2 = forward!($mode, $this.expr_ia2, eval_row($input))?.map(|x| x.into_bool());
97 match $this.expr_type {
98 Type::Or => Ok(or(ret_ia1, ret_ia2).map(|x| x.to_scalar_value())),
99 Type::And => Ok(and(ret_ia1, ret_ia2).map(|x| x.to_scalar_value())),
100 _ => unimplemented!(),
101 }
102 }};
103}
104
105impl<E: SyncExpression> SyncExpression for BinaryShortCircuitExpression<E> {
106 fn eval(&self, input: &DataChunk) -> Result<ArrayRef> {
107 eval_short_circuit!(sync, self, input)
108 }
109
110 fn eval_row(&self, input: &OwnedRow) -> Result<Datum> {
111 eval_row_short_circuit!(sync, self, input)
112 }
113}
114
115impl<E: AsyncExpression> AsyncExpression for BinaryShortCircuitExpression<E> {
116 async fn eval(&self, input: &DataChunk) -> Result<ArrayRef> {
117 eval_short_circuit!(async, self, input)
118 }
119
120 async fn eval_row(&self, input: &OwnedRow) -> Result<Datum> {
121 eval_row_short_circuit!(async, self, input)
122 }
123}
124
125#[build_function("and(boolean, boolean) -> boolean")]
126fn build_and_expr(_: DataType, children: Vec<BoxedExpression>) -> Result<BoxedExpression> {
127 build_binary_short_circuit(children, Type::And)
128}
129
130#[build_function("or(boolean, boolean) -> boolean")]
131fn build_or_expr(_: DataType, children: Vec<BoxedExpression>) -> Result<BoxedExpression> {
132 build_binary_short_circuit(children, Type::Or)
133}
134
135fn build_binary_short_circuit(
136 children: Vec<BoxedExpression>,
137 expr_type: Type,
138) -> Result<BoxedExpression> {
139 let [left, right]: [_; 2] = children.try_into().unwrap();
140 Ok(match (left, right) {
141 (BoxedExpression::Sync(left), BoxedExpression::Sync(right)) => {
142 BinaryShortCircuitExpression {
143 expr_ia1: left,
144 expr_ia2: right,
145 expr_type,
146 }
147 .boxed()
148 }
149 (left, right) => BinaryShortCircuitExpression {
150 expr_ia1: left,
151 expr_ia2: right,
152 expr_type,
153 }
154 .boxed(),
155 })
156}
157
158fn and(l: Option<bool>, r: Option<bool>) -> Option<bool> {
160 match (l, r) {
161 (Some(lb), Some(lr)) => Some(lb & lr),
162 (Some(true), None) => None,
163 (None, Some(true)) => None,
164 (Some(false), None) => Some(false),
165 (None, Some(false)) => Some(false),
166 (None, None) => None,
167 }
168}
169
170fn or(l: Option<bool>, r: Option<bool>) -> Option<bool> {
172 match (l, r) {
173 (Some(lb), Some(lr)) => Some(lb | lr),
174 (Some(true), None) => Some(true),
175 (None, Some(true)) => Some(true),
176 (Some(false), None) => None,
177 (None, Some(false)) => None,
178 (None, None) => None,
179 }
180}
181
182#[cfg(test)]
183mod tests {
184 use super::*;
185 use crate::expr::build_from_pretty;
186
187 #[tokio::test]
188 async fn test_and() {
189 let (input, target) = DataChunk::from_pretty(
190 "
191 B B B
192 t t t
193 t f f
194 t . .
195 f t f
196 f f f
197 f . f
198 . t .
199 . f f
200 . . .
201 ",
202 )
203 .split_column_at(2);
204 let expr = build_from_pretty("(and:boolean $0:boolean $1:boolean)");
205 let result = expr.eval(&input).await.unwrap();
206 assert_eq!(&result, target.column_at(0));
207 }
208
209 #[tokio::test]
210 async fn test_or() {
211 let (input, target) = DataChunk::from_pretty(
212 "
213 B B B
214 t t t
215 t f t
216 t . t
217 f t t
218 f f f
219 f . .
220 . t t
221 . f .
222 . . .
223 ",
224 )
225 .split_column_at(2);
226 let expr = build_from_pretty("(or:boolean $0:boolean $1:boolean)");
227 let result = expr.eval(&input).await.unwrap();
228 assert_eq!(&result, target.column_at(0));
229 }
230
231 #[test]
232 fn test_and_() {
233 assert_eq!(Some(true), and(Some(true), Some(true)));
234 assert_eq!(Some(false), and(Some(true), Some(false)));
235 assert_eq!(Some(false), and(Some(false), Some(false)));
236 assert_eq!(None, and(Some(true), None));
237 assert_eq!(Some(false), and(Some(false), None));
238 assert_eq!(None, and(None, None));
239 }
240
241 #[test]
242 fn test_or_() {
243 assert_eq!(Some(true), or(Some(true), Some(true)));
244 assert_eq!(Some(true), or(Some(true), Some(false)));
245 assert_eq!(Some(false), or(Some(false), Some(false)));
246 assert_eq!(Some(true), or(Some(true), None));
247 assert_eq!(None, or(Some(false), None));
248 assert_eq!(None, or(None, None));
249 }
250}