uqa_sql/assignment/
routines.rs1use crate::{
8 ast::ColumnType, expr::cast_value, type_resolution::canonical_routine_type_name, SQLError,
9};
10use uqa_core::Value;
11pub trait RoutineValueContext: super::AssignmentContext {
12 fn catalog_column_type(&self, name: &str) -> Option<ColumnType>;
13}
14pub fn coerce_routine_value(
15 context: &dyn RoutineValueContext,
16 value: &Value,
17 type_name: &str,
18) -> Result<Value, SQLError> {
19 coerce_routine_value_from(context, value, type_name, None)
20}
21
22pub fn coerce_routine_value_from(
23 context: &dyn RoutineValueContext,
24 value: &Value,
25 type_name: &str,
26 source: Option<&ColumnType>,
27) -> Result<Value, SQLError> {
28 match canonical_routine_type_name(type_name).as_str() {
29 "record" => match value {
30 Value::Record(_) | Value::Null => Ok(value.clone()),
31 Value::Row(row) if row.field_types().is_some() => Ok(value.clone()),
32 Value::Row(values) => Ok(Value::Record(
33 values
34 .iter()
35 .cloned()
36 .enumerate()
37 .map(|(index, value)| (format!("f{}", index + 1), value))
38 .collect::<Vec<_>>()
39 .into(),
40 )),
41 _ => Err(SQLError::Routine {
42 sqlstate: "42804".into(),
43 message: "cannot cast non-composite value to type record".into(),
44 }),
45 },
46 "trigger" => match value {
47 Value::Record(_) | Value::Row(_) | Value::Null => Ok(value.clone()),
48 _ => Err(SQLError::Routine {
49 sqlstate: "42804".into(),
50 message: "trigger function must return a row or NULL".into(),
51 }),
52 },
53 "anyarray" => match value {
54 Value::Array(_) | Value::LegacyVector(_) | Value::List(_) | Value::Null => {
55 Ok(value.clone())
56 }
57 _ => Err(SQLError::Routine {
58 sqlstate: "42804".into(),
59 message: "cannot cast non-array value to type anyarray".into(),
60 }),
61 },
62 "refcursor" => match value {
63 Value::Str(_) | Value::Null => Ok(value.clone()),
64 _ => Err(SQLError::Routine {
65 sqlstate: "42804".into(),
66 message: "cannot cast value to type refcursor".into(),
67 }),
68 },
69 "void" if matches!(value, Value::Null) => Ok(Value::Null),
70 "void" => Err(SQLError::Routine {
71 sqlstate: "42804".into(),
72 message: "cannot cast non-null value to type void".into(),
73 }),
74 _ => {
75 if let Some(target) = context.catalog_column_type(type_name) {
76 return crate::assignment::conversion::coerce_assignment_value(
77 context,
78 value.clone(),
79 &target,
80 source,
81 );
82 }
83 cast_value(value, type_name)
84 }
85 }
86}