risingwave_frontend/expr/
pure.rs1use expr_node::Type;
16use risingwave_pb::expr::expr_node;
17
18use super::{ExprImpl, ExprVisitor};
19use crate::expr::FunctionCall;
20
21#[derive(Default)]
22pub(crate) struct ImpureAnalyzer {
23 pub(crate) impure: bool,
24}
25
26impl ExprVisitor for ImpureAnalyzer {
27 fn visit_user_defined_function(&mut self, _func_call: &super::UserDefinedFunction) {
28 self.impure = true;
29 }
30
31 fn visit_now(&mut self, _: &super::Now) {
32 self.impure = true;
33 }
34
35 fn visit_function_call(&mut self, func_call: &super::FunctionCall) {
36 match func_call.func_type() {
37 Type::Unspecified => unreachable!(),
38 Type::Add
39 | Type::Subtract
40 | Type::Multiply
41 | Type::Divide
42 | Type::Modulus
43 | Type::Equal
44 | Type::NotEqual
45 | Type::LessThan
46 | Type::LessThanOrEqual
47 | Type::GreaterThan
48 | Type::GreaterThanOrEqual
49 | Type::And
50 | Type::Or
51 | Type::Not
52 | Type::In
53 | Type::Some
54 | Type::All
55 | Type::BitwiseAnd
56 | Type::BitwiseOr
57 | Type::BitwiseXor
58 | Type::BitwiseNot
59 | Type::BitwiseShiftLeft
60 | Type::BitwiseShiftRight
61 | Type::Extract
62 | Type::DatePart
63 | Type::TumbleStart
64 | Type::SecToTimestamptz
65 | Type::AtTimeZone
66 | Type::DateTrunc
67 | Type::DateBin
68 | Type::MakeDate
69 | Type::MakeTime
70 | Type::MakeTimestamp
71 | Type::CharToTimestamptz
72 | Type::CharToDate
73 | Type::CastWithTimeZone
74 | Type::AddWithTimeZone
75 | Type::SubtractWithTimeZone
76 | Type::Cast
77 | Type::Substr
78 | Type::Length
79 | Type::Like
80 | Type::ILike
81 | Type::SimilarToEscape
82 | Type::Upper
83 | Type::Lower
84 | Type::Trim
85 | Type::Replace
86 | Type::Position
87 | Type::Ltrim
88 | Type::Rtrim
89 | Type::Case
90 | Type::ConstantLookup
91 | Type::RoundDigit
92 | Type::Round
93 | Type::Ascii
94 | Type::Translate
95 | Type::Coalesce
96 | Type::ConcatWs
97 | Type::ConcatWsVariadic
98 | Type::Abs
99 | Type::SplitPart
100 | Type::Ceil
101 | Type::Floor
102 | Type::Trunc
103 | Type::ToChar
104 | Type::Md5
105 | Type::CharLength
106 | Type::Repeat
107 | Type::ConcatOp
108 | Type::ByteaConcatOp
109 | Type::Concat
110 | Type::ConcatVariadic
111 | Type::BoolOut
112 | Type::OctetLength
113 | Type::BitLength
114 | Type::Overlay
115 | Type::RegexpMatch
116 | Type::RegexpReplace
117 | Type::RegexpCount
118 | Type::RegexpSplitToArray
119 | Type::RegexpEq
120 | Type::Pow
121 | Type::Exp
122 | Type::Ln
123 | Type::Log10
124 | Type::Chr
125 | Type::StartsWith
126 | Type::Initcap
127 | Type::Lpad
128 | Type::Rpad
129 | Type::Reverse
130 | Type::Strpos
131 | Type::ToAscii
132 | Type::ToHex
133 | Type::QuoteIdent
134 | Type::Sin
135 | Type::Cos
136 | Type::Tan
137 | Type::Cot
138 | Type::Asin
139 | Type::Acos
140 | Type::Acosd
141 | Type::Atan
142 | Type::Atan2
143 | Type::Atand
144 | Type::Atan2d
145 | Type::Sqrt
146 | Type::Cbrt
147 | Type::Sign
148 | Type::Scale
149 | Type::MinScale
150 | Type::TrimScale
151 | Type::Left
152 | Type::Right
153 | Type::Degrees
154 | Type::Radians
155 | Type::IsTrue
156 | Type::IsNotTrue
157 | Type::IsFalse
158 | Type::IsNotFalse
159 | Type::IsNull
160 | Type::IsNotNull
161 | Type::IsDistinctFrom
162 | Type::IsNotDistinctFrom
163 | Type::Neg
164 | Type::Field
165 | Type::Array
166 | Type::ArrayAccess
167 | Type::ArrayRangeAccess
168 | Type::Row
169 | Type::ArrayToString
170 | Type::ArrayCat
171 | Type::ArrayMax
172 | Type::ArraySum
173 | Type::ArraySort
174 | Type::ArrayAppend
175 | Type::ArrayPrepend
176 | Type::FormatType
177 | Type::ArrayDistinct
178 | Type::ArrayMin
179 | Type::ArrayDims
180 | Type::ArrayLength
181 | Type::Cardinality
182 | Type::TrimArray
183 | Type::ArrayRemove
184 | Type::ArrayReplace
185 | Type::ArrayPosition
186 | Type::ArrayContains
187 | Type::ArrayContained
188 | Type::ArrayFlatten
189 | Type::HexToInt256
190 | Type::JsonbConcat
191 | Type::JsonbAccess
192 | Type::JsonbAccessStr
193 | Type::JsonbExtractPath
194 | Type::JsonbExtractPathVariadic
195 | Type::JsonbExtractPathText
196 | Type::JsonbExtractPathTextVariadic
197 | Type::JsonbTypeof
198 | Type::JsonbArrayLength
199 | Type::JsonbObject
200 | Type::JsonbPretty
201 | Type::JsonbDeletePath
202 | Type::JsonbContains
203 | Type::JsonbContained
204 | Type::JsonbExists
205 | Type::JsonbExistsAny
206 | Type::JsonbExistsAll
207 | Type::JsonbStripNulls
208 | Type::JsonbBuildArray
209 | Type::JsonbBuildArrayVariadic
210 | Type::JsonbBuildObject
211 | Type::JsonbPopulateRecord
212 | Type::JsonbToRecord
213 | Type::JsonbBuildObjectVariadic
214 | Type::JsonbPathExists
215 | Type::JsonbPathMatch
216 | Type::JsonbPathQueryArray
217 | Type::JsonbPathQueryFirst
218 | Type::JsonbSet
219 | Type::JsonbPopulateMap
220 | Type::IsJson
221 | Type::ToJsonb
222 | Type::Sind
223 | Type::Cosd
224 | Type::Cotd
225 | Type::Asind
226 | Type::Sinh
227 | Type::Cosh
228 | Type::Coth
229 | Type::Tanh
230 | Type::Atanh
231 | Type::Asinh
232 | Type::Acosh
233 | Type::Decode
234 | Type::Encode
235 | Type::Sha1
236 | Type::Sha224
237 | Type::Sha256
238 | Type::Sha384
239 | Type::Sha512
240 | Type::Hmac
241 | Type::SecureCompare
242 | Type::Decrypt
243 | Type::Encrypt
244 | Type::Tand
245 | Type::ArrayPositions
246 | Type::StringToArray
247 | Type::Format
248 | Type::FormatVariadic
249 | Type::PgwireSend
250 | Type::PgwireRecv
251 | Type::ArrayTransform
252 | Type::Greatest
253 | Type::Least
254 | Type::ConvertFrom
255 | Type::ConvertTo
256 | Type::IcebergTransform
257 | Type::InetNtoa
258 | Type::InetAton
259 | Type::QuoteLiteral
260 | Type::QuoteNullable
261 | Type::MapFromEntries
262 | Type::MapAccess
263 | Type::MapKeys
264 | Type::MapValues
265 | Type::MapEntries
266 | Type::MapFromKeyValues
267 | Type::MapCat
268 | Type::MapContains
269 | Type::MapDelete
270 | Type::MapFilter
271 | Type::MapInsert
272 | Type::MapLength
273 | Type::VnodeUser
274 | Type::RwEpochToTs
275 | Type::CheckNotNull
276 | Type::CompositeCast =>
277 {
279 func_call
280 .inputs()
281 .iter()
282 .for_each(|expr| self.visit_expr(expr));
283 }
284 Type::Vnode | Type::TestPaidTier
287 | Type::License
288 | Type::Proctime
289 | Type::PgSleep
290 | Type::PgSleepFor
291 | Type::PgSleepUntil
292 | Type::CastRegclass
293 | Type::PgGetIndexdef
294 | Type::ColDescription
295 | Type::PgGetViewdef
296 | Type::PgGetUserbyid
297 | Type::PgIndexesSize
298 | Type::PgRelationSize
299 | Type::PgGetSerialSequence
300 | Type::PgIndexColumnHasProperty
301 | Type::HasTablePrivilege
302 | Type::HasAnyColumnPrivilege
303 | Type::HasSchemaPrivilege
304 | Type::MakeTimestamptz
305 | Type::PgIsInRecovery
306 | Type::RwRecoveryStatus
307 | Type::PgTableIsVisible
308 | Type::HasFunctionPrivilege => self.impure = true,
309 }
310 }
311}
312
313pub fn is_pure(expr: &ExprImpl) -> bool {
314 !is_impure(expr)
315}
316
317pub fn is_impure(expr: &ExprImpl) -> bool {
318 let mut a = ImpureAnalyzer::default();
319 a.visit_expr(expr);
320 a.impure
321}
322
323pub fn is_impure_func_call(func_call: &FunctionCall) -> bool {
324 let mut a = ImpureAnalyzer::default();
325 a.visit_function_call(func_call);
326 a.impure
327}
328
329#[cfg(test)]
330mod tests {
331 use risingwave_common::types::DataType;
332 use risingwave_pb::expr::expr_node::Type;
333
334 use crate::expr::{ExprImpl, FunctionCall, InputRef, is_impure, is_pure};
335
336 fn expect_pure(expr: &ExprImpl) {
337 assert!(is_pure(expr));
338 assert!(!is_impure(expr));
339 }
340
341 fn expect_impure(expr: &ExprImpl) {
342 assert!(!is_pure(expr));
343 assert!(is_impure(expr));
344 }
345
346 #[test]
347 fn test_pure_funcs() {
348 let e: ExprImpl = FunctionCall::new(
349 Type::Add,
350 vec![
351 InputRef::new(0, DataType::Int16).into(),
352 InputRef::new(0, DataType::Int16).into(),
353 ],
354 )
355 .unwrap()
356 .into();
357 expect_pure(&e);
358
359 let e: ExprImpl = FunctionCall::new(
360 Type::GreaterThan,
361 vec![
362 InputRef::new(0, DataType::Timestamptz).into(),
363 FunctionCall::new(Type::Proctime, vec![]).unwrap().into(),
364 ],
365 )
366 .unwrap()
367 .into();
368 expect_impure(&e);
369 }
370}