1use super::{ScalarExpr, ScalarOrder};
10use crate::ast::{FunctionBinding, FunctionDispatch};
11use crate::SQLError;
12use uqa_core::{
13 memory::{Produced, ProductionControl, ProductionVec},
14 Value,
15};
16
17#[doc(hidden)]
19#[derive(Debug, Clone, Copy, PartialEq)]
20pub struct ScalarCallArgument<'a> {
21 pub name: Option<&'a str>,
22 pub value: &'a ScalarExpr,
23 pub explicit_variadic: bool,
24}
25
26#[doc(hidden)]
28pub fn scalar_call_arguments(
29 arguments: &[ScalarExpr],
30) -> Result<Vec<ScalarCallArgument<'_>>, SQLError> {
31 scalar_call_arguments_with_control(arguments, &ProductionControl::uncontrolled()).map(
32 |decoded| {
33 decoded
34 .into_uncontrolled()
35 .expect("ordinary call argument decoding has no reservation")
36 },
37 )
38}
39
40pub fn scalar_call_arguments_with_control<'a>(
42 arguments: &'a [ScalarExpr],
43 control: &ProductionControl<'_>,
44) -> Result<Produced<Vec<ScalarCallArgument<'a>>>, SQLError> {
45 let mut decoded = ProductionVec::new(*control);
46 decoded.reserve(arguments.len())?;
47 for argument in arguments {
48 control.check()?;
49 decoded.push_copy(scalar_call_argument(argument)?)?;
50 }
51 validate_scalar_call_arguments(&decoded)?;
52 decoded.finish().map_err(Into::into)
53}
54
55#[doc(hidden)]
57pub fn validate_scalar_call_arguments(
58 arguments: &[ScalarCallArgument<'_>],
59) -> Result<bool, SQLError> {
60 let mut count = 0;
61 let mut last_position = None;
62 for (position, argument) in arguments.iter().enumerate() {
63 if argument.explicit_variadic {
64 count += 1;
65 last_position = Some(position);
66 }
67 }
68 if count > 1 {
69 return Err(malformed_call_argument(
70 "call contains more than one explicit VARIADIC argument",
71 ));
72 }
73 if last_position.is_some_and(|position| position + 1 != arguments.len()) {
74 return Err(malformed_call_argument(
75 "explicit VARIADIC argument must be the final call argument",
76 ));
77 }
78 Ok(count != 0)
79}
80
81#[doc(hidden)]
83pub fn scalar_call_argument(expression: &ScalarExpr) -> Result<ScalarCallArgument<'_>, SQLError> {
84 let ScalarExpr::Func {
85 name,
86 args,
87 binding,
88 distinct,
89 order_by,
90 filter,
91 } = expression
92 else {
93 return Ok(ScalarCallArgument {
94 name: None,
95 value: expression,
96 explicit_variadic: false,
97 });
98 };
99 if binding.as_ref().and_then(|binding| binding.dispatch)
100 == Some(FunctionDispatch::NamedArgument)
101 {
102 validate_marker_shape(
103 binding.as_ref(),
104 FunctionDispatch::NamedArgument,
105 *distinct,
106 order_by,
107 filter.as_deref(),
108 name,
109 )?;
110 let [ScalarExpr::Literal(Value::Str(argument_name)), value] = args.as_slice() else {
111 return Err(malformed_call_argument(
112 "named argument marker must contain a string name and one value",
113 ));
114 };
115 let (value, explicit_variadic) = direct_variadic_argument(value)?;
116 if !explicit_variadic
117 && matches!(
118 value,
119 ScalarExpr::Func { binding, .. }
120 if binding.as_ref().and_then(|binding| binding.dispatch)
121 == Some(FunctionDispatch::NamedArgument)
122 )
123 {
124 return Err(malformed_call_argument(
125 "call argument contains nested syntax markers",
126 ));
127 }
128 return Ok(ScalarCallArgument {
129 name: Some(argument_name),
130 value,
131 explicit_variadic,
132 });
133 }
134 let (value, explicit_variadic) = direct_variadic_argument(expression)?;
135 Ok(ScalarCallArgument {
136 name: None,
137 value,
138 explicit_variadic,
139 })
140}
141
142fn direct_variadic_argument(expression: &ScalarExpr) -> Result<(&ScalarExpr, bool), SQLError> {
143 let ScalarExpr::Func {
144 name,
145 args,
146 binding,
147 distinct,
148 order_by,
149 filter,
150 } = expression
151 else {
152 return Ok((expression, false));
153 };
154 if binding.as_ref().and_then(|binding| binding.dispatch)
155 != Some(FunctionDispatch::VariadicArgument)
156 {
157 return Ok((expression, false));
158 }
159 validate_marker_shape(
160 binding.as_ref(),
161 FunctionDispatch::VariadicArgument,
162 *distinct,
163 order_by,
164 filter.as_deref(),
165 name,
166 )?;
167 let [value] = args.as_slice() else {
168 return Err(malformed_call_argument(
169 "VARIADIC argument marker must contain exactly one value",
170 ));
171 };
172 if matches!(
173 value,
174 ScalarExpr::Func { binding, .. }
175 if matches!(
176 binding.as_ref().and_then(|binding| binding.dispatch),
177 Some(FunctionDispatch::VariadicArgument | FunctionDispatch::NamedArgument)
178 )
179 ) {
180 return Err(malformed_call_argument(
181 "call argument contains nested syntax markers",
182 ));
183 }
184 Ok((value, true))
185}
186
187fn validate_marker_shape(
188 binding: Option<&FunctionBinding>,
189 expected_dispatch: FunctionDispatch,
190 distinct: bool,
191 order_by: &[ScalarOrder],
192 filter: Option<&ScalarExpr>,
193 name: &str,
194) -> Result<(), SQLError> {
195 if binding.is_none_or(|binding| {
196 !binding.builtin
197 || binding.dispatch != Some(expected_dispatch)
198 || !binding.argument_types.is_empty()
199 || binding.invocation.is_some()
200 || binding.resolution_error.is_some()
201 }) || distinct
202 || !order_by.is_empty()
203 || filter.is_some()
204 {
205 return Err(malformed_call_argument(&format!(
206 "{name} syntax marker contains function-call metadata"
207 )));
208 }
209 Ok(())
210}
211
212fn malformed_call_argument(message: &str) -> SQLError {
213 SQLError::Internal(format!("malformed call argument: {message}"))
214}
215
216pub fn analyze_expression_call_arguments(
218 arguments: &[crate::plan::ExpressionPlan],
219) -> Result<(Vec<ScalarCallArgument<'_>>, bool), SQLError> {
220 let decoded = arguments
221 .iter()
222 .map(|argument| scalar_call_argument(&argument.scalar))
223 .collect::<Result<Vec<_>, _>>()?;
224 let explicit_variadic = validate_scalar_call_arguments(&decoded)?;
225 Ok((decoded, explicit_variadic))
226}
227
228#[cfg(test)]
229mod production_tests;