safe_migrate/analysis/
expr_ir.rs1use serde::{Deserialize, Serialize};
3
4#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
5pub enum ExprIr {
6 Literal(String),
7 ColumnRef(String),
8 FunctionCall {
9 name: String,
10 args: Vec<ExprIr>,
11 },
12 BinaryOp {
13 left: Box<ExprIr>,
14 op: String,
15 right: Box<ExprIr>,
16 },
17 Cast {
18 expr: Box<ExprIr>,
19 target_type: String,
20 },
21 Omitted, }
23
24impl ExprIr {
25 pub fn is_volatile(&self) -> bool {
26 match self {
27 ExprIr::FunctionCall { name, args } => {
28 if name.starts_with('<') && name.ends_with('>') {
31 return args.iter().any(|a| a.is_volatile());
32 }
33
34 const VOLATILE: &[&str] = &[
35 "clock_timestamp",
37 "timeofday",
38 "random",
39 "setseed",
40 "txid_current",
41 "txid_current_snapshot",
42 "txid_snapshot_xip",
43 "txid_snapshot_xmax",
44 "txid_snapshot_xmin",
45 "nextval",
46 "currval",
47 "lastval",
48 "setval",
49 "gen_random_uuid",
50 "uuid_generate_v1",
51 "uuid_generate_v1mc",
52 "uuid_generate_v4",
53 ];
58
59 VOLATILE.contains(&name.to_lowercase().as_str())
60 }
61 ExprIr::BinaryOp { left, right, .. } => left.is_volatile() || right.is_volatile(),
62 ExprIr::Cast { expr, .. } => expr.is_volatile(),
63 ExprIr::Literal(_) | ExprIr::ColumnRef(_) | ExprIr::Omitted => false,
64 }
65 }
66}