1use mz_expr::{BinaryFunc, MirScalarExpr, UnaryFunc, VariadicFunc, func};
19use mz_repr::adt::jsonb::JsonbRef;
20use mz_repr::{Datum, ReprColumnType, ReprScalarType, SqlScalarType};
21
22pub fn print_scalar(expr: &MirScalarExpr) -> Result<String, String> {
27 use MirScalarExpr::*;
28 match expr {
29 Column(i, _name) => Ok(format!("#{i}")),
30 Literal(Ok(row), typ) => print_literal(row.unpack_first(), typ),
31 Literal(Err(err), _typ) => match err {
32 mz_expr::EvalError::Internal(msg) => Ok(format!("error(\"internal error: {msg}\")")),
33 err => Err(format!("cannot print error literal: {err}")),
34 },
35 CallUnmaterializable(func) => Ok(format!("{func}()")),
36 CallUnary { func, expr } => {
37 let expr = print_scalar(expr)?;
38 match func {
39 UnaryFunc::IsNull(_) => Ok(format!("(({expr}) IS NULL)")),
40 UnaryFunc::RecordGet(func::RecordGet(index)) => {
41 Ok(format!("record_get[{index}]({expr})"))
42 }
43 UnaryFunc::CastInt32ToNumeric(func::CastInt32ToNumeric(Some(scale))) => Ok(
44 format!("cast_int32_to_numeric[{}]({expr})", scale.into_u8()),
45 ),
46 func => Ok(format!("{}({expr})", func.variant_name())),
47 }
48 }
49 CallBinary { func, expr1, expr2 } => {
50 let expr1 = print_scalar(expr1)?;
51 let expr2 = print_scalar(expr2)?;
52 let infix = match func {
55 BinaryFunc::Eq(_) => Some("="),
56 BinaryFunc::NotEq(_) => Some("!="),
57 BinaryFunc::Lt(_) => Some("<"),
58 BinaryFunc::Lte(_) => Some("<="),
59 BinaryFunc::Gt(_) => Some(">"),
60 BinaryFunc::Gte(_) => Some(">="),
61 _ => None,
62 };
63 match infix {
64 Some(op) => Ok(format!("({expr1} {op} {expr2})")),
65 None => Ok(format!("{}({expr1}, {expr2})", func.variant_name())),
66 }
67 }
68 CallVariadic { func, exprs } => {
69 let args = exprs
70 .iter()
71 .map(print_scalar)
72 .collect::<Result<Vec<_>, _>>()?;
73 let infix_safe = || {
78 exprs.len() >= 2
79 && !exprs
80 .iter()
81 .any(|e| matches!(e, CallVariadic { func: f, .. } if f == func))
82 };
83 match func {
84 VariadicFunc::And(_) if infix_safe() => Ok(format!("({})", args.join(" AND "))),
85 VariadicFunc::Or(_) if infix_safe() => Ok(format!("({})", args.join(" OR "))),
86 VariadicFunc::RecordCreate(func::variadic::RecordCreate { field_names }) => {
87 let names = field_names
88 .iter()
89 .map(|n| format!("{:?}", n.as_str()))
90 .collect::<Vec<_>>()
91 .join(", ");
92 Ok(format!("record_create[{names}]({})", args.join(", ")))
93 }
94 VariadicFunc::ListCreate(func::variadic::ListCreate { elem_type }) => {
95 let elem_type = print_sql_scalar_type(elem_type)?;
96 Ok(format!("list_create[{elem_type}]({})", args.join(", ")))
97 }
98 func => Ok(format!("{}({})", func.variant_name(), args.join(", "))),
99 }
100 }
101 If { cond, then, els } => Ok(format!(
102 "case when {} then {} else {} end",
103 print_scalar(cond)?,
104 print_scalar(then)?,
105 print_scalar(els)?
106 )),
107 }
108}
109
110fn print_literal(datum: Datum, typ: &ReprColumnType) -> Result<String, String> {
111 let unsupported = |what: &dyn std::fmt::Debug| Err(format!("cannot print literal {what:?}"));
112 match datum {
113 Datum::Null => Ok(format!(
114 "null::{}",
115 print_repr_scalar_type(&typ.scalar_type)?
116 )),
117 Datum::True => Ok("true".to_string()),
118 Datum::False => Ok("false".to_string()),
119 Datum::Int16(i) => Ok(format!("{i}::smallint")),
120 Datum::Int32(i) => Ok(format!("{i}::integer")),
121 Datum::Int64(i) => Ok(format!("{i}")),
122 Datum::Float64(f) => Ok(format!("{:?}", f.into_inner())),
123 Datum::Numeric(n) => Ok(format!("{n}::numeric")),
124 Datum::String(s) => Ok(format!("{s:?}")),
125 datum if typ.scalar_type == ReprScalarType::Jsonb => Ok(format!(
126 "{:?}::jsonb",
127 JsonbRef::from_datum(datum).to_string()
128 )),
129 datum => unsupported(&datum),
130 }
131}
132
133fn print_repr_scalar_type(typ: &ReprScalarType) -> Result<String, String> {
134 let name = match typ {
135 ReprScalarType::Bool => "boolean",
136 ReprScalarType::Int16 => "smallint",
137 ReprScalarType::Int32 => "integer",
138 ReprScalarType::Int64 => "bigint",
139 ReprScalarType::Float64 => "double precision",
140 ReprScalarType::Numeric => "numeric",
141 ReprScalarType::String => "text",
142 ReprScalarType::Jsonb => "jsonb",
143 typ => Err(format!("cannot print scalar type {typ:?}"))?,
144 };
145 Ok(name.to_string())
146}
147
148fn print_sql_scalar_type(typ: &SqlScalarType) -> Result<String, String> {
149 print_repr_scalar_type(&ReprScalarType::from(typ))
150}