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::Concat
109 | Type::ConcatVariadic
110 | Type::BoolOut
111 | Type::OctetLength
112 | Type::BitLength
113 | Type::Overlay
114 | Type::RegexpMatch
115 | Type::RegexpReplace
116 | Type::RegexpCount
117 | Type::RegexpSplitToArray
118 | Type::RegexpEq
119 | Type::Pow
120 | Type::Exp
121 | Type::Ln
122 | Type::Log10
123 | Type::Chr
124 | Type::StartsWith
125 | Type::Initcap
126 | Type::Lpad
127 | Type::Rpad
128 | Type::Reverse
129 | Type::Strpos
130 | Type::ToAscii
131 | Type::ToHex
132 | Type::QuoteIdent
133 | Type::Sin
134 | Type::Cos
135 | Type::Tan
136 | Type::Cot
137 | Type::Asin
138 | Type::Acos
139 | Type::Acosd
140 | Type::Atan
141 | Type::Atan2
142 | Type::Atand
143 | Type::Atan2d
144 | Type::Sqrt
145 | Type::Cbrt
146 | Type::Sign
147 | Type::Scale
148 | Type::MinScale
149 | Type::TrimScale
150 | Type::Left
151 | Type::Right
152 | Type::Degrees
153 | Type::Radians
154 | Type::IsTrue
155 | Type::IsNotTrue
156 | Type::IsFalse
157 | Type::IsNotFalse
158 | Type::IsNull
159 | Type::IsNotNull
160 | Type::IsDistinctFrom
161 | Type::IsNotDistinctFrom
162 | Type::Neg
163 | Type::Field
164 | Type::Array
165 | Type::ArrayAccess
166 | Type::ArrayRangeAccess
167 | Type::Row
168 | Type::ArrayToString
169 | Type::ArrayCat
170 | Type::ArrayMax
171 | Type::ArraySum
172 | Type::ArraySort
173 | Type::ArrayAppend
174 | Type::ArrayPrepend
175 | Type::FormatType
176 | Type::ArrayDistinct
177 | Type::ArrayMin
178 | Type::ArrayDims
179 | Type::ArrayLength
180 | Type::Cardinality
181 | Type::TrimArray
182 | Type::ArrayRemove
183 | Type::ArrayReplace
184 | Type::ArrayPosition
185 | Type::ArrayContains
186 | Type::ArrayContained
187 | Type::ArrayFlatten
188 | Type::HexToInt256
189 | Type::JsonbConcat
190 | Type::JsonbAccess
191 | Type::JsonbAccessStr
192 | Type::JsonbExtractPath
193 | Type::JsonbExtractPathVariadic
194 | Type::JsonbExtractPathText
195 | Type::JsonbExtractPathTextVariadic
196 | Type::JsonbTypeof
197 | Type::JsonbArrayLength
198 | Type::JsonbObject
199 | Type::JsonbPretty
200 | Type::JsonbDeletePath
201 | Type::JsonbContains
202 | Type::JsonbContained
203 | Type::JsonbExists
204 | Type::JsonbExistsAny
205 | Type::JsonbExistsAll
206 | Type::JsonbStripNulls
207 | Type::JsonbBuildArray
208 | Type::JsonbBuildArrayVariadic
209 | Type::JsonbBuildObject
210 | Type::JsonbPopulateRecord
211 | Type::JsonbToRecord
212 | Type::JsonbBuildObjectVariadic
213 | Type::JsonbPathExists
214 | Type::JsonbPathMatch
215 | Type::JsonbPathQueryArray
216 | Type::JsonbPathQueryFirst
217 | Type::JsonbSet
218 | Type::JsonbPopulateMap
219 | Type::IsJson
220 | Type::ToJsonb
221 | Type::Sind
222 | Type::Cosd
223 | Type::Cotd
224 | Type::Asind
225 | Type::Sinh
226 | Type::Cosh
227 | Type::Coth
228 | Type::Tanh
229 | Type::Atanh
230 | Type::Asinh
231 | Type::Acosh
232 | Type::Decode
233 | Type::Encode
234 | Type::Sha1
235 | Type::Sha224
236 | Type::Sha256
237 | Type::Sha384
238 | Type::Sha512
239 | Type::Hmac
240 | Type::SecureCompare
241 | Type::Decrypt
242 | Type::Encrypt
243 | Type::Tand
244 | Type::ArrayPositions
245 | Type::StringToArray
246 | Type::Format
247 | Type::FormatVariadic
248 | Type::PgwireSend
249 | Type::PgwireRecv
250 | Type::ArrayTransform
251 | Type::Greatest
252 | Type::Least
253 | Type::ConvertFrom
254 | Type::ConvertTo
255 | Type::IcebergTransform
256 | Type::InetNtoa
257 | Type::InetAton
258 | Type::QuoteLiteral
259 | Type::QuoteNullable
260 | Type::MapFromEntries
261 | Type::MapAccess
262 | Type::MapKeys
263 | Type::MapValues
264 | Type::MapEntries
265 | Type::MapFromKeyValues
266 | Type::MapCat
267 | Type::MapContains
268 | Type::MapDelete
269 | Type::MapInsert
270 | Type::MapLength
271 | Type::VnodeUser
272 | Type::RwEpochToTs
273 | Type::CheckNotNull =>
274 {
276 func_call
277 .inputs()
278 .iter()
279 .for_each(|expr| self.visit_expr(expr));
280 }
281 Type::Vnode | Type::TestPaidTier
284 | Type::License
285 | Type::Proctime
286 | Type::PgSleep
287 | Type::PgSleepFor
288 | Type::PgSleepUntil
289 | Type::CastRegclass
290 | Type::PgGetIndexdef
291 | Type::ColDescription
292 | Type::PgGetViewdef
293 | Type::PgGetUserbyid
294 | Type::PgIndexesSize
295 | Type::PgRelationSize
296 | Type::PgGetSerialSequence
297 | Type::PgIndexColumnHasProperty
298 | Type::HasTablePrivilege
299 | Type::HasAnyColumnPrivilege
300 | Type::HasSchemaPrivilege
301 | Type::MakeTimestamptz
302 | Type::PgIsInRecovery
303 | Type::RwRecoveryStatus
304 | Type::PgTableIsVisible
305 | Type::HasFunctionPrivilege => self.impure = true,
306 }
307 }
308}
309
310pub fn is_pure(expr: &ExprImpl) -> bool {
311 !is_impure(expr)
312}
313
314pub fn is_impure(expr: &ExprImpl) -> bool {
315 let mut a = ImpureAnalyzer::default();
316 a.visit_expr(expr);
317 a.impure
318}
319
320pub fn is_impure_func_call(func_call: &FunctionCall) -> bool {
321 let mut a = ImpureAnalyzer::default();
322 a.visit_function_call(func_call);
323 a.impure
324}
325
326#[cfg(test)]
327mod tests {
328 use risingwave_common::types::DataType;
329 use risingwave_pb::expr::expr_node::Type;
330
331 use crate::expr::{ExprImpl, FunctionCall, InputRef, is_impure, is_pure};
332
333 fn expect_pure(expr: &ExprImpl) {
334 assert!(is_pure(expr));
335 assert!(!is_impure(expr));
336 }
337
338 fn expect_impure(expr: &ExprImpl) {
339 assert!(!is_pure(expr));
340 assert!(is_impure(expr));
341 }
342
343 #[test]
344 fn test_pure_funcs() {
345 let e: ExprImpl = FunctionCall::new(
346 Type::Add,
347 vec![
348 InputRef::new(0, DataType::Int16).into(),
349 InputRef::new(0, DataType::Int16).into(),
350 ],
351 )
352 .unwrap()
353 .into();
354 expect_pure(&e);
355
356 let e: ExprImpl = FunctionCall::new(
357 Type::GreaterThan,
358 vec![
359 InputRef::new(0, DataType::Timestamptz).into(),
360 FunctionCall::new(Type::Proctime, vec![]).unwrap().into(),
361 ],
362 )
363 .unwrap()
364 .into();
365 expect_impure(&e);
366 }
367}