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 "now",
36 "clock_timestamp",
37 "transaction_timestamp",
38 "statement_timestamp",
39 "timeofday",
40 "random",
41 "setseed",
42 "txid_current",
43 "txid_current_snapshot",
44 "txid_snapshot_xip",
45 "txid_snapshot_xmax",
46 "txid_snapshot_xmin",
47 "nextval",
48 "currval",
49 "lastval",
50 "setval",
51 "gen_random_uuid",
52 "uuid_generate_v1",
53 "uuid_generate_v1mc",
54 "uuid_generate_v4",
55 ];
56
57 VOLATILE.contains(&name.to_lowercase().as_str())
58 }
59 ExprIr::BinaryOp { left, right, .. } => left.is_volatile() || right.is_volatile(),
60 ExprIr::Cast { expr, .. } => expr.is_volatile(),
61 ExprIr::Literal(_) | ExprIr::ColumnRef(_) | ExprIr::Omitted => false,
62 }
63 }
64}