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::JsonbToArray
213 | Type::JsonbToRecord
214 | Type::JsonbBuildObjectVariadic
215 | Type::JsonbPathExists
216 | Type::JsonbPathMatch
217 | Type::JsonbPathQueryArray
218 | Type::JsonbPathQueryFirst
219 | Type::JsonbSet
220 | Type::JsonbPopulateMap
221 | Type::IsJson
222 | Type::ToJsonb
223 | Type::Sind
224 | Type::Cosd
225 | Type::Cotd
226 | Type::Asind
227 | Type::Sinh
228 | Type::Cosh
229 | Type::Coth
230 | Type::Tanh
231 | Type::Atanh
232 | Type::Asinh
233 | Type::Acosh
234 | Type::Decode
235 | Type::Encode
236 | Type::Sha1
237 | Type::Sha224
238 | Type::Sha256
239 | Type::Sha384
240 | Type::Sha512
241 | Type::Hmac
242 | Type::SecureCompare
243 | Type::Decrypt
244 | Type::Encrypt
245 | Type::Tand
246 | Type::ArrayPositions
247 | Type::StringToArray
248 | Type::Format
249 | Type::FormatVariadic
250 | Type::PgwireSend
251 | Type::PgwireRecv
252 | Type::ArrayTransform
253 | Type::Greatest
254 | Type::Least
255 | Type::ConvertFrom
256 | Type::ConvertTo
257 | Type::IcebergTransform
258 | Type::InetNtoa
259 | Type::InetAton
260 | Type::QuoteLiteral
261 | Type::QuoteNullable
262 | Type::MapFromEntries
263 | Type::MapAccess
264 | Type::MapKeys
265 | Type::MapValues
266 | Type::MapEntries
267 | Type::MapFromKeyValues
268 | Type::MapCat
269 | Type::MapContains
270 | Type::MapDelete
271 | Type::MapFilter
272 | Type::MapInsert
273 | Type::MapLength
274 | Type::L2Distance
275 | Type::CosineDistance
276 | Type::L1Distance
277 | Type::InnerProduct
278 | Type::VecConcat
279 | Type::L2Norm
280 | Type::L2Normalize
281 | Type::VnodeUser
282 | Type::RwEpochToTs
283 | Type::CheckNotNull
284 | Type::CompositeCast =>
285 {
287 func_call
288 .inputs()
289 .iter()
290 .for_each(|expr| self.visit_expr(expr));
291 }
292 Type::Vnode | Type::TestFeature
295 | Type::License
296 | Type::Proctime
297 | Type::PgSleep
298 | Type::PgSleepFor
299 | Type::PgSleepUntil
300 | Type::CastRegclass
301 | Type::PgGetIndexdef
302 | Type::ColDescription
303 | Type::PgGetViewdef
304 | Type::PgGetUserbyid
305 | Type::PgIndexesSize
306 | Type::PgRelationSize
307 | Type::PgGetSerialSequence
308 | Type::PgIndexColumnHasProperty
309 | Type::HasTablePrivilege
310 | Type::HasAnyColumnPrivilege
311 | Type::HasSchemaPrivilege
312 | Type::MakeTimestamptz
313 | Type::PgIsInRecovery
314 | Type::RwRecoveryStatus
315 | Type::PgTableIsVisible
316 | Type::HasFunctionPrivilege
317 | Type::OpenaiEmbedding
318 | Type::HasDatabasePrivilege
319 | Type::Random => self.impure = true,
320 }
321 }
322}
323
324pub fn is_pure(expr: &ExprImpl) -> bool {
325 !is_impure(expr)
326}
327
328pub fn is_impure(expr: &ExprImpl) -> bool {
329 let mut a = ImpureAnalyzer::default();
330 a.visit_expr(expr);
331 a.impure
332}
333
334pub fn is_impure_func_call(func_call: &FunctionCall) -> bool {
335 let mut a = ImpureAnalyzer::default();
336 a.visit_function_call(func_call);
337 a.impure
338}
339
340#[cfg(test)]
341mod tests {
342 use risingwave_common::types::DataType;
343 use risingwave_pb::expr::expr_node::Type;
344
345 use crate::expr::{ExprImpl, FunctionCall, InputRef, is_impure, is_pure};
346
347 fn expect_pure(expr: &ExprImpl) {
348 assert!(is_pure(expr));
349 assert!(!is_impure(expr));
350 }
351
352 fn expect_impure(expr: &ExprImpl) {
353 assert!(!is_pure(expr));
354 assert!(is_impure(expr));
355 }
356
357 #[test]
358 fn test_pure_funcs() {
359 let e: ExprImpl = FunctionCall::new(
360 Type::Add,
361 vec![
362 InputRef::new(0, DataType::Int16).into(),
363 InputRef::new(0, DataType::Int16).into(),
364 ],
365 )
366 .unwrap()
367 .into();
368 expect_pure(&e);
369
370 let e: ExprImpl = FunctionCall::new(
371 Type::GreaterThan,
372 vec![
373 InputRef::new(0, DataType::Timestamptz).into(),
374 FunctionCall::new(Type::Proctime, vec![]).unwrap().into(),
375 ],
376 )
377 .unwrap()
378 .into();
379 expect_impure(&e);
380 }
381}