risingwave_frontend/optimizer/plan_expr_visitor/
strong.rs1use fixedbitset::FixedBitSet;
16
17use crate::expr::{ExprImpl, ExprType, FunctionCall, InputRef};
18
19#[derive(Default)]
38pub struct Strong {
39 null_columns: FixedBitSet,
40}
41
42impl Strong {
43 fn new(null_columns: FixedBitSet) -> Self {
44 Self { null_columns }
45 }
46
47 pub fn is_null(expr: &ExprImpl, null_columns: FixedBitSet) -> bool {
51 let strong = Strong::new(null_columns);
52 strong.is_null_visit(expr)
53 }
54
55 fn is_input_ref_null(&self, input_ref: &InputRef) -> bool {
56 self.null_columns.contains(input_ref.index())
57 }
58
59 fn is_null_visit(&self, expr: &ExprImpl) -> bool {
60 match expr {
61 ExprImpl::InputRef(input_ref) => self.is_input_ref_null(input_ref),
62 ExprImpl::Literal(literal) => literal.get_data().is_none(),
63 ExprImpl::FunctionCall(func_call) => self.is_null_function_call(func_call),
64 ExprImpl::FunctionCallWithLambda(_) => false,
65 ExprImpl::AggCall(_) => false,
66 ExprImpl::Subquery(_) => false,
67 ExprImpl::CorrelatedInputRef(_) => false,
68 ExprImpl::TableFunction(_) => false,
69 ExprImpl::WindowFunction(_) => false,
70 ExprImpl::UserDefinedFunction(_) => false,
71 ExprImpl::Parameter(_) => false,
72 ExprImpl::Now(_) => false,
73 }
74 }
75
76 fn is_null_function_call(&self, func_call: &FunctionCall) -> bool {
77 match func_call.func_type() {
78 ExprType::IsNull
80 | ExprType::IsNotNull
81 | ExprType::IsDistinctFrom
82 | ExprType::IsNotDistinctFrom
83 | ExprType::IsTrue
84 | ExprType::QuoteNullable
85 | ExprType::IsNotTrue
86 | ExprType::IsFalse
87 | ExprType::IsNotFalse
88 | ExprType::CheckNotNull => false,
89 ExprType::Not
91 | ExprType::Equal
92 | ExprType::NotEqual
93 | ExprType::LessThan
94 | ExprType::LessThanOrEqual
95 | ExprType::GreaterThan
96 | ExprType::GreaterThanOrEqual
97 | ExprType::Like
98 | ExprType::Add
99 | ExprType::AddWithTimeZone
100 | ExprType::Subtract
101 | ExprType::Multiply
102 | ExprType::Modulus
103 | ExprType::Divide
104 | ExprType::Cast
105 | ExprType::Trim
106 | ExprType::Ltrim
107 | ExprType::Rtrim
108 | ExprType::Ceil
109 | ExprType::Floor
110 | ExprType::Extract
111 | ExprType::L2Distance
112 | ExprType::CosineDistance
113 | ExprType::L1Distance
114 | ExprType::InnerProduct
115 | ExprType::VecConcat
116 | ExprType::L2Norm
117 | ExprType::L2Normalize
118 | ExprType::Subvector
119 | ExprType::Greatest
120 | ExprType::Least => self.any_null(func_call),
121 ExprType::And | ExprType::Or | ExprType::Coalesce => self.all_null(func_call),
123 ExprType::In
126 | ExprType::Some
127 | ExprType::All
128 | ExprType::BitwiseAnd
129 | ExprType::BitwiseOr
130 | ExprType::BitwiseXor
131 | ExprType::BitwiseNot
132 | ExprType::BitwiseShiftLeft
133 | ExprType::BitwiseShiftRight
134 | ExprType::DatePart
135 | ExprType::TumbleStart
136 | ExprType::MakeDate
137 | ExprType::MakeTime
138 | ExprType::MakeTimestamp
139 | ExprType::SecToTimestamptz
140 | ExprType::AtTimeZone
141 | ExprType::DateTrunc
142 | ExprType::DateBin
143 | ExprType::CharToTimestamptz
144 | ExprType::CharToDate
145 | ExprType::CastWithTimeZone
146 | ExprType::SubtractWithTimeZone
147 | ExprType::MakeTimestamptz
148 | ExprType::Substr
149 | ExprType::Length
150 | ExprType::ILike
151 | ExprType::SimilarToEscape
152 | ExprType::Upper
153 | ExprType::Lower
154 | ExprType::Replace
155 | ExprType::Position
156 | ExprType::Case
157 | ExprType::ConstantLookup
158 | ExprType::RoundDigit
159 | ExprType::Round
160 | ExprType::Ascii
161 | ExprType::Translate
162 | ExprType::Concat
163 | ExprType::ConcatVariadic
164 | ExprType::ConcatWs
165 | ExprType::ConcatWsVariadic
166 | ExprType::Abs
167 | ExprType::SplitPart
168 | ExprType::ToChar
169 | ExprType::Md5
170 | ExprType::CharLength
171 | ExprType::Repeat
172 | ExprType::ConcatOp
173 | ExprType::ByteaConcatOp
174 | ExprType::BoolOut
175 | ExprType::OctetLength
176 | ExprType::BitLength
177 | ExprType::Overlay
178 | ExprType::RegexpMatch
179 | ExprType::RegexpReplace
180 | ExprType::RegexpCount
181 | ExprType::RegexpSplitToArray
182 | ExprType::RegexpEq
183 | ExprType::Pow
184 | ExprType::Exp
185 | ExprType::Chr
186 | ExprType::StartsWith
187 | ExprType::Initcap
188 | ExprType::Lpad
189 | ExprType::Rpad
190 | ExprType::Reverse
191 | ExprType::Strpos
192 | ExprType::ToAscii
193 | ExprType::ToHex
194 | ExprType::QuoteIdent
195 | ExprType::QuoteLiteral
196 | ExprType::Sin
197 | ExprType::Cos
198 | ExprType::Tan
199 | ExprType::Cot
200 | ExprType::Asin
201 | ExprType::Acos
202 | ExprType::Acosd
203 | ExprType::Atan
204 | ExprType::Atan2
205 | ExprType::Atand
206 | ExprType::Atan2d
207 | ExprType::Sind
208 | ExprType::Cosd
209 | ExprType::Cotd
210 | ExprType::Tand
211 | ExprType::Asind
212 | ExprType::Sqrt
213 | ExprType::Degrees
214 | ExprType::Radians
215 | ExprType::Cosh
216 | ExprType::Tanh
217 | ExprType::Coth
218 | ExprType::Asinh
219 | ExprType::Acosh
220 | ExprType::Atanh
221 | ExprType::Sinh
222 | ExprType::Trunc
223 | ExprType::Ln
224 | ExprType::Log10
225 | ExprType::Cbrt
226 | ExprType::Sign
227 | ExprType::Scale
228 | ExprType::MinScale
229 | ExprType::TrimScale
230 | ExprType::Encode
231 | ExprType::Decode
232 | ExprType::Sha1
233 | ExprType::Sha224
234 | ExprType::Sha256
235 | ExprType::Sha384
236 | ExprType::Sha512
237 | ExprType::GetBit
238 | ExprType::GetByte
239 | ExprType::SetBit
240 | ExprType::SetByte
241 | ExprType::BitCount
242 | ExprType::Hmac
243 | ExprType::SecureCompare
244 | ExprType::Left
245 | ExprType::Right
246 | ExprType::Format
247 | ExprType::FormatVariadic
248 | ExprType::PgwireSend
249 | ExprType::PgwireRecv
250 | ExprType::ConvertFrom
251 | ExprType::ConvertTo
252 | ExprType::Decrypt
253 | ExprType::Encrypt
254 | ExprType::Neg
255 | ExprType::Field
256 | ExprType::Array
257 | ExprType::ArrayAccess
258 | ExprType::Row
259 | ExprType::ArrayToString
260 | ExprType::ArrayRangeAccess
261 | ExprType::ArrayCat
262 | ExprType::ArrayAppend
263 | ExprType::ArrayPrepend
264 | ExprType::FormatType
265 | ExprType::ArrayDistinct
266 | ExprType::ArrayLength
267 | ExprType::Cardinality
268 | ExprType::ArrayRemove
269 | ExprType::ArrayPositions
270 | ExprType::TrimArray
271 | ExprType::StringToArray
272 | ExprType::ArrayPosition
273 | ExprType::ArrayReplace
274 | ExprType::ArrayDims
275 | ExprType::ArrayTransform
276 | ExprType::ArrayMin
277 | ExprType::ArrayMax
278 | ExprType::ArraySum
279 | ExprType::ArraySort
280 | ExprType::ArrayContains
281 | ExprType::ArrayContained
282 | ExprType::ArrayFlatten
283 | ExprType::HexToInt256
284 | ExprType::JsonbAccess
285 | ExprType::JsonbAccessStr
286 | ExprType::JsonbExtractPath
287 | ExprType::JsonbExtractPathVariadic
288 | ExprType::JsonbExtractPathText
289 | ExprType::JsonbExtractPathTextVariadic
290 | ExprType::JsonbTypeof
291 | ExprType::JsonbArrayLength
292 | ExprType::IsJson
293 | ExprType::JsonbConcat
294 | ExprType::JsonbObject
295 | ExprType::JsonbPretty
296 | ExprType::JsonbContains
297 | ExprType::JsonbContained
298 | ExprType::JsonbExists
299 | ExprType::JsonbExistsAny
300 | ExprType::JsonbExistsAll
301 | ExprType::JsonbDeletePath
302 | ExprType::JsonbStripNulls
303 | ExprType::ToJsonb
304 | ExprType::JsonbBuildArray
305 | ExprType::JsonbBuildArrayVariadic
306 | ExprType::JsonbBuildObject
307 | ExprType::JsonbBuildObjectVariadic
308 | ExprType::JsonbPathExists
309 | ExprType::JsonbPathMatch
310 | ExprType::JsonbPathQueryArray
311 | ExprType::JsonbPathQueryFirst
312 | ExprType::JsonbPopulateRecord
313 | ExprType::JsonbToArray
314 | ExprType::JsonbToRecord
315 | ExprType::JsonbSet
316 | ExprType::JsonbPopulateMap
317 | ExprType::MapFromEntries
318 | ExprType::MapAccess
319 | ExprType::MapKeys
320 | ExprType::MapValues
321 | ExprType::MapEntries
322 | ExprType::MapFromKeyValues
323 | ExprType::MapCat
324 | ExprType::MapContains
325 | ExprType::MapDelete
326 | ExprType::MapFilter
327 | ExprType::MapInsert
328 | ExprType::MapLength
329 | ExprType::Vnode
330 | ExprType::VnodeUser
331 | ExprType::TestFeature
332 | ExprType::License
333 | ExprType::Proctime
334 | ExprType::PgSleep
335 | ExprType::PgSleepFor
336 | ExprType::PgSleepUntil
337 | ExprType::CastRegclass
338 | ExprType::PgGetIndexdef
339 | ExprType::ColDescription
340 | ExprType::PgGetViewdef
341 | ExprType::PgGetUserbyid
342 | ExprType::PgIndexesSize
343 | ExprType::PgRelationSize
344 | ExprType::PgGetSerialSequence
345 | ExprType::PgIndexColumnHasProperty
346 | ExprType::PgIsInRecovery
347 | ExprType::PgTableIsVisible
348 | ExprType::RwRecoveryStatus
349 | ExprType::RwClusterId
350 | ExprType::RwFragmentVnodes
351 | ExprType::RwActorVnodes
352 | ExprType::IcebergTransform
353 | ExprType::HasTablePrivilege
354 | ExprType::HasFunctionPrivilege
355 | ExprType::HasAnyColumnPrivilege
356 | ExprType::HasSchemaPrivilege
357 | ExprType::InetAton
358 | ExprType::InetNtoa
359 | ExprType::CompositeCast
360 | ExprType::RwEpochToTs
361 | ExprType::OpenaiEmbedding
362 | ExprType::HasDatabasePrivilege
363 | ExprType::Random => false,
364 ExprType::Unspecified => unreachable!(),
365 }
366 }
367
368 fn any_null(&self, func_call: &FunctionCall) -> bool {
369 func_call
370 .inputs()
371 .iter()
372 .any(|expr| self.is_null_visit(expr))
373 }
374
375 fn all_null(&self, func_call: &FunctionCall) -> bool {
376 func_call
377 .inputs()
378 .iter()
379 .all(|expr| self.is_null_visit(expr))
380 }
381}
382
383#[cfg(test)]
384mod tests {
385 use risingwave_common::types::DataType;
386
387 use super::*;
388 use crate::expr::ExprImpl::Literal;
389
390 #[test]
391 fn test_literal() {
392 let null_columns = FixedBitSet::with_capacity(1);
393 let expr = Literal(crate::expr::Literal::new(None, DataType::Varchar).into());
394 assert!(Strong::is_null(&expr, null_columns.clone()));
395
396 let expr = Literal(
397 crate::expr::Literal::new(Some("test".to_owned().into()), DataType::Varchar).into(),
398 );
399 assert!(!Strong::is_null(&expr, null_columns));
400 }
401
402 #[test]
403 fn test_input_ref1() {
404 let null_columns = FixedBitSet::with_capacity(2);
405 let expr = InputRef::new(0, DataType::Varchar).into();
406 assert!(!Strong::is_null(&expr, null_columns.clone()));
407
408 let expr = InputRef::new(1, DataType::Varchar).into();
409 assert!(!Strong::is_null(&expr, null_columns));
410 }
411
412 #[test]
413 fn test_input_ref2() {
414 let mut null_columns = FixedBitSet::with_capacity(2);
415 null_columns.insert(0);
416 null_columns.insert(1);
417 let expr = InputRef::new(0, DataType::Varchar).into();
418 assert!(Strong::is_null(&expr, null_columns.clone()));
419
420 let expr = InputRef::new(1, DataType::Varchar).into();
421 assert!(Strong::is_null(&expr, null_columns));
422 }
423
424 #[test]
425 fn test_c1_equal_1_or_c2_is_null() {
426 let mut null_columns = FixedBitSet::with_capacity(2);
427 null_columns.insert(0);
428 let expr = FunctionCall::new_unchecked(
429 ExprType::Or,
430 vec![
431 FunctionCall::new_unchecked(
432 ExprType::Equal,
433 vec![
434 InputRef::new(0, DataType::Int64).into(),
435 Literal(crate::expr::Literal::new(Some(1.into()), DataType::Int32).into()),
436 ],
437 DataType::Boolean,
438 )
439 .into(),
440 FunctionCall::new_unchecked(
441 ExprType::IsNull,
442 vec![InputRef::new(1, DataType::Int64).into()],
443 DataType::Boolean,
444 )
445 .into(),
446 ],
447 DataType::Boolean,
448 )
449 .into();
450 assert!(!Strong::is_null(&expr, null_columns));
451 }
452
453 #[test]
454 fn test_divide() {
455 let mut null_columns = FixedBitSet::with_capacity(2);
456 null_columns.insert(0);
457 null_columns.insert(1);
458 let expr = FunctionCall::new_unchecked(
459 ExprType::Divide,
460 vec![
461 InputRef::new(0, DataType::Decimal).into(),
462 InputRef::new(1, DataType::Decimal).into(),
463 ],
464 DataType::Varchar,
465 )
466 .into();
467 assert!(Strong::is_null(&expr, null_columns));
468 }
469
470 #[test]
472 fn test_multiply_divide() {
473 let mut null_columns = FixedBitSet::with_capacity(2);
474 null_columns.insert(0);
475 let expr = FunctionCall::new_unchecked(
476 ExprType::Multiply,
477 vec![
478 Literal(crate::expr::Literal::new(Some(0.8f64.into()), DataType::Float64).into()),
479 FunctionCall::new_unchecked(
480 ExprType::Divide,
481 vec![
482 InputRef::new(0, DataType::Decimal).into(),
483 InputRef::new(1, DataType::Decimal).into(),
484 ],
485 DataType::Decimal,
486 )
487 .into(),
488 ],
489 DataType::Decimal,
490 )
491 .into();
492 assert!(Strong::is_null(&expr, null_columns));
493 }
494
495 macro_rules! gen_test {
497 ($func:ident, $expr:expr, $expected:expr) => {
498 #[test]
499 fn $func() {
500 let null_columns = FixedBitSet::with_capacity(2);
501 let expr = $expr;
502 assert_eq!(Strong::is_null(&expr, null_columns), $expected);
503 }
504 };
505 }
506
507 gen_test!(
508 test_is_not_null,
509 FunctionCall::new_unchecked(
510 ExprType::IsNotNull,
511 vec![InputRef::new(0, DataType::Varchar).into()],
512 DataType::Varchar
513 )
514 .into(),
515 false
516 );
517 gen_test!(
518 test_is_null,
519 FunctionCall::new_unchecked(
520 ExprType::IsNull,
521 vec![InputRef::new(0, DataType::Varchar).into()],
522 DataType::Varchar
523 )
524 .into(),
525 false
526 );
527 gen_test!(
528 test_is_distinct_from,
529 FunctionCall::new_unchecked(
530 ExprType::IsDistinctFrom,
531 vec![
532 InputRef::new(0, DataType::Varchar).into(),
533 InputRef::new(1, DataType::Varchar).into()
534 ],
535 DataType::Varchar
536 )
537 .into(),
538 false
539 );
540 gen_test!(
541 test_is_not_distinct_from,
542 FunctionCall::new_unchecked(
543 ExprType::IsNotDistinctFrom,
544 vec![
545 InputRef::new(0, DataType::Varchar).into(),
546 InputRef::new(1, DataType::Varchar).into()
547 ],
548 DataType::Varchar
549 )
550 .into(),
551 false
552 );
553 gen_test!(
554 test_is_true,
555 FunctionCall::new_unchecked(
556 ExprType::IsTrue,
557 vec![InputRef::new(0, DataType::Varchar).into()],
558 DataType::Varchar
559 )
560 .into(),
561 false
562 );
563 gen_test!(
564 test_is_not_true,
565 FunctionCall::new_unchecked(
566 ExprType::IsNotTrue,
567 vec![InputRef::new(0, DataType::Varchar).into()],
568 DataType::Varchar
569 )
570 .into(),
571 false
572 );
573 gen_test!(
574 test_is_false,
575 FunctionCall::new_unchecked(
576 ExprType::IsFalse,
577 vec![InputRef::new(0, DataType::Varchar).into()],
578 DataType::Varchar
579 )
580 .into(),
581 false
582 );
583}