1mod coercion;
10mod collations;
11mod constructs;
12mod fields;
13mod functions;
14mod operators;
15mod routines;
16mod rows;
17mod schema;
18mod subscripts;
19pub use routines::{select_routine, RoutineDeclaration};
20pub use schema::{ColumnReference, ExpressionSchema};
21
22use super::{values, Field, Node};
23use crate::ast::{BinaryOp, Expr, FunctionBinding, RoutineInvocationBinding};
24use crate::catalog::type_metadata::{pg_type_collation_oid, pg_type_modifier, pg_type_oid};
25use crate::type_resolution::{
26 binary_operator_catalog_entry, binary_operator_types, common_context_expression_type,
27 FunctionTypeResolver, RoutineCallDescriptor,
28};
29use crate::{ColumnType, SQLError};
30
31pub struct RoutineIdentity {
32 pub oid: i64,
33 pub invocation: RoutineInvocationBinding,
34 pub result_type: ColumnType,
35}
36
37pub trait ExpressionRoutines {
38 fn resolve(
39 &self,
40 name: &str,
41 binding: Option<&FunctionBinding>,
42 call: RoutineCallDescriptor<'_>,
43 ) -> Result<RoutineIdentity, SQLError>;
44}
45
46pub struct ExpressionContext<'a> {
47 pub schema: &'a dyn ExpressionSchema,
48 pub domain_value: Option<&'a ColumnType>,
49 pub types: Option<&'a dyn FunctionTypeResolver>,
50 pub routines: &'a dyn ExpressionRoutines,
51}
52
53struct TypedNode {
54 node: Node,
55 ty: Option<ColumnType>,
57}
58
59impl TypedNode {
60 fn type_ref(&self) -> Result<&ColumnType, SQLError> {
61 self.ty
62 .as_ref()
63 .ok_or_else(|| super::invalid("expected a selected expression type"))
64 }
65}
66
67impl ExpressionContext<'_> {
68 pub fn check(&self, expression: &Expr) -> Result<Node, SQLError> {
69 self.expression(expression, Some(&ColumnType::Boolean))
70 }
71
72 pub fn expression(
74 &self,
75 expression: &Expr,
76 expected: Option<&ColumnType>,
77 ) -> Result<Node, SQLError> {
78 let mut value = self.encode(expression, expected)?;
79 collations::assign(&mut value.node)?;
80 Ok(value.node)
81 }
82
83 pub fn assignment(&self, expression: &Expr, target: &ColumnType) -> Result<Node, SQLError> {
85 let unknown = self.expression_type(expression)?.is_none();
86 let input_type = target.without_type_modifiers();
87 let value = self.encode(expression, unknown.then_some(&input_type))?;
88 let mut value = Self::coerce_assignment(value, target)?;
89 collations::assign(&mut value.node)?;
90 Ok(value.node)
91 }
92
93 fn expression_type(&self, expression: &Expr) -> Result<Option<ColumnType>, SQLError> {
94 let plan = crate::plan::ExpressionPlan::lower(expression.clone());
95 common_context_expression_type(&plan.scalar, self.schema, &[], self.types)
96 }
97
98 fn encode(
99 &self,
100 expression: &Expr,
101 expected: Option<&ColumnType>,
102 ) -> Result<TypedNode, SQLError> {
103 if let Some(clause) = crate::catalog::collations::expression::ast_clause(expression)? {
104 return self.collated_expression(clause, expected);
105 }
106 let value = match expression {
107 Expr::Column(column) => self.column(column, None)?,
108 Expr::QualifiedColumn { qualifier, column } => self.column(column, Some(qualifier))?,
109 Expr::QualifiedStar(qualifier) => {
110 Self::variable(self.schema.whole_row_reference(qualifier)?)
111 }
112 Expr::Literal(value) => self.literal(expression, value, expected)?,
113 Expr::TypedLiteral {
114 value,
115 ty,
116 composite_source,
117 collation_oid,
118 } => self.retained_constant(
119 value,
120 self.resolve_type(ty)?,
121 composite_source.as_deref(),
122 *collation_oid,
123 )?,
124 Expr::Binary { op, lhs, rhs } => self.binary(*op, lhs, rhs)?,
125 Expr::UnaryMinus(argument) => self.unary_minus(argument)?,
126 Expr::Array(elements) => self.array(elements, expected)?,
127 Expr::Row(elements) => self.row(elements)?,
128 Expr::CompositeRow { items, binding } => self.stored_row(items, binding)?,
129 Expr::InList {
130 expr,
131 list,
132 negated,
133 } => self.in_list(expr, list, *negated)?,
134 Expr::Case {
135 base,
136 when,
137 else_branch,
138 } => self.case(expression, base.as_deref(), when, else_branch.as_deref())?,
139 Expr::And(items) => self.boolean("and", items)?,
140 Expr::Or(items) => self.boolean("or", items)?,
141 Expr::Not(item) => self.boolean("not", std::slice::from_ref(item.as_ref()))?,
142 Expr::IsNull { expr, negated } => {
143 let (arg, is_row) = self.uncoerced_input(expr)?;
144 TypedNode {
145 node: Node::new(
146 "NULLTEST",
147 [
148 ("arg", arg.into()),
149 ("nulltesttype", i64::from(*negated).into()),
150 ("argisrow", is_row.into()),
151 ("location", (-1).into()),
152 ],
153 ),
154 ty: Some(ColumnType::Boolean),
155 }
156 }
157 Expr::Between { expr, low, high } => self.boolean(
158 "and",
159 &[
160 Expr::Binary {
161 op: BinaryOp::GreaterEqual,
162 lhs: expr.clone(),
163 rhs: low.clone(),
164 },
165 Expr::Binary {
166 op: BinaryOp::LessEqual,
167 lhs: expr.clone(),
168 rhs: high.clone(),
169 },
170 ],
171 )?,
172 Expr::Func {
173 order_syntax,
174 name,
175 binding,
176 args,
177 distinct: false,
178 order_by,
179 filter: None,
180 } if order_by.is_empty() => {
181 if let Some(value) = self.construct(expression, name, binding.as_ref(), args)? {
182 value
183 } else {
184 self.function(name, binding.as_ref(), args, *order_syntax)?
185 }
186 }
187 Expr::Cast { expr, ty, implicit } => self.cast_expression(expr, ty, *implicit)?,
188 _ => {
189 return Err(SQLError::Unsupported(
190 "catalog expression node encoding for this expression".into(),
191 ))
192 }
193 };
194 if let Some(ty) = expected {
195 Self::coerce(value, ty, 2)
196 } else {
197 Ok(value)
198 }
199 }
200
201 fn literal(
202 &self,
203 expression: &Expr,
204 value: &uqa_core::Value,
205 expected: Option<&ColumnType>,
206 ) -> Result<TypedNode, SQLError> {
207 let source = self.expression_type(expression)?;
208 let ty = source
209 .as_ref()
210 .or(expected)
211 .cloned()
212 .unwrap_or(ColumnType::Text);
213 let value = if source.is_none() {
214 if let Some(value) = crate::expr::enums::fold_unknown_literal(
215 self.types.and_then(FunctionTypeResolver::enum_labels),
216 value,
217 &ty,
218 )? {
219 value
220 } else if let uqa_core::Value::Str(text) = value {
221 if crate::expr::requires_catalog_constant_input(&ty) {
222 self.types
223 .and_then(FunctionTypeResolver::catalog_input_functions)
224 .ok_or_else(|| {
225 SQLError::Internal("catalog input functions are unavailable".into())
226 })?
227 .read_unknown_input(text, &ty)?
228 } else {
229 crate::type_resolution::coerce_common_context_value(
230 value.clone(),
231 None,
232 Some(&ty),
233 )?
234 }
235 } else {
236 crate::type_resolution::coerce_common_context_value(value.clone(), None, Some(&ty))?
237 }
238 } else {
239 crate::type_resolution::coerce_common_context_value(
240 value.clone(),
241 source.as_ref(),
242 Some(&ty),
243 )?
244 };
245 self.constant(&value, ty, None)
246 }
247
248 fn constant(
249 &self,
250 value: &uqa_core::Value,
251 ty: ColumnType,
252 source: Option<&crate::expr::composites::CompositeConstantSource>,
253 ) -> Result<TypedNode, SQLError> {
254 Ok(TypedNode {
255 node: values::constant_with_source(
256 value,
257 &ty,
258 source,
259 self.types.and_then(FunctionTypeResolver::composite_types),
260 )?,
261 ty: Some(ty),
262 })
263 }
264
265 fn retained_constant(
266 &self,
267 value: &uqa_core::Value,
268 ty: ColumnType,
269 source: Option<&crate::expr::composites::CompositeConstantSource>,
270 collation: Option<u32>,
271 ) -> Result<TypedNode, SQLError> {
272 let mut value = self.constant(value, ty, source)?;
273 if let Some(oid) = collation {
274 crate::catalog::collations::expression::validate_literal_collation(
275 value.ty.as_ref(),
276 Some(oid),
277 )?;
278 value
279 .node
280 .fields
281 .iter_mut()
282 .find(|(name, _)| name == "constcollid")
283 .expect("constant collation")
284 .1 = i64::from(oid).into();
285 }
286 Ok(value)
287 }
288
289 fn resolve_type(&self, name: &str) -> Result<ColumnType, SQLError> {
290 if let Some(resolver) = self.types {
291 if let Some(ty) = resolver.resolve_type_name(name)? {
292 return Ok(ty);
293 }
294 }
295 ColumnType::from_sql_name(name)
296 }
297
298 fn column(&self, name: &str, qualifier: Option<&str>) -> Result<TypedNode, SQLError> {
299 if let Some(ty) = self.domain_value {
300 if name != "value" || qualifier.is_some() {
301 return Err(SQLError::UnknownColumn(name.into()));
302 }
303 return Ok(TypedNode {
304 node: Node::new(
305 "COERCETODOMAINVALUE",
306 [
307 ("typeId", pg_type_oid(ty).into()),
308 ("typeMod", pg_type_modifier(ty).into()),
309 ("collation", pg_type_collation_oid(ty).into()),
310 ("location", (-1).into()),
311 ],
312 ),
313 ty: Some(ty.clone()),
314 });
315 }
316 let column = self.schema.column_reference(name, qualifier)?;
317 Ok(Self::variable(column))
318 }
319
320 fn variable(column: ColumnReference<'_>) -> TypedNode {
321 let ty = column.ty;
322 let ordinal = column.attribute_number;
323 TypedNode {
324 node: Node::new(
325 "VAR",
326 [
327 ("varno", 1.into()),
328 ("varattno", ordinal.into()),
329 ("vartype", pg_type_oid(ty).into()),
330 ("vartypmod", pg_type_modifier(ty).into()),
331 ("varcollid", column.collation_oid.into()),
332 ("varnullingrels", Field::List(vec![Field::Atom("b".into())])),
333 ("varlevelsup", 0.into()),
334 ("varreturningtype", 0.into()),
335 ("varnosyn", 1.into()),
336 ("varattnosyn", ordinal.into()),
337 ("location", (-1).into()),
338 ],
339 ),
340 ty: Some(ty.clone()),
341 }
342 }
343
344 fn binary(&self, op: BinaryOp, lhs: &Expr, rhs: &Expr) -> Result<TypedNode, SQLError> {
345 if let (Expr::Row(left), Expr::Row(right)) = (lhs, rhs) {
346 return self.row_comparison(op, left, right);
347 }
348 self.scalar_binary(op, lhs, rhs)
349 }
350
351 fn scalar_binary(&self, op: BinaryOp, lhs: &Expr, rhs: &Expr) -> Result<TypedNode, SQLError> {
352 let types = [self.expression_type(lhs)?, self.expression_type(rhs)?];
353 let [left, right, result] =
354 binary_operator_types(op, types[0].as_ref(), types[1].as_ref())?;
355 let identity = binary_operator_catalog_entry(op, [&left, &right])?;
356 let arguments = [
357 self.encode(lhs, Some(&left))?,
358 self.encode(rhs, Some(&right))?,
359 ];
360 Ok(operator_node(
361 identity.oid,
362 identity.function_oid,
363 arguments,
364 result,
365 ))
366 }
367
368 fn boolean(&self, operator: &str, args: &[Expr]) -> Result<TypedNode, SQLError> {
369 let args = args
370 .iter()
371 .map(|arg| {
372 self.encode(arg, Some(&ColumnType::Boolean))
373 .map(|value| value.node.into())
374 })
375 .collect::<Result<_, _>>()?;
376 Ok(TypedNode {
377 node: Node::new(
378 "BOOLEXPR",
379 [
380 ("boolop", Field::Atom(operator.into())),
381 ("args", Field::List(args)),
382 ("location", (-1).into()),
383 ],
384 ),
385 ty: Some(ColumnType::Boolean),
386 })
387 }
388}
389
390fn operator_node(
391 oid: i64,
392 function_oid: i64,
393 arguments: impl IntoIterator<Item = TypedNode>,
394 result: ColumnType,
395) -> TypedNode {
396 let arguments: Vec<_> = arguments.into_iter().collect();
397 TypedNode {
398 node: Node::new(
399 "OPEXPR",
400 [
401 ("opno", oid.into()),
402 ("opfuncid", function_oid.into()),
403 ("opresulttype", pg_type_oid(&result).into()),
404 ("opretset", false.into()),
405 ("opcollid", pg_type_collation_oid(&result).into()),
406 ("inputcollid", 0.into()),
407 (
408 "args",
409 Field::List(arguments.into_iter().map(|arg| arg.node.into()).collect()),
410 ),
411 ("location", (-1).into()),
412 ],
413 ),
414 ty: Some(result),
415 }
416}