1use crate::ast::{ColumnType, FunctionBinding};
10use crate::{SQLError, SQLParam};
11
12use crate::schema::ScalarTypeSchema;
13use crate::{RowSchema, ScalarExpr};
14use uqa_core::Value;
15
16mod array_transform;
17pub(crate) mod between;
18pub(crate) use array_transform::resolve_array_transform_call;
19mod call;
20mod cast_compatibility;
21mod checksum;
22mod common;
23pub(crate) use common::array_element_type;
24pub(crate) use common::literal_input_type_with_control;
25pub(crate) use common::value_type;
26pub(crate) use common::value_type_with_control;
27mod containment;
28pub(crate) mod enums;
29mod equality;
30pub(crate) mod field_selection;
31mod fixed_builtin;
32pub(crate) use fixed_builtin::overloads as fixed_builtin_overloads;
33mod functions;
34mod gamma;
35mod inference;
36use inference::scalar_type_inner_with_control;
37mod introspection;
38mod json_strip;
39mod length;
40mod md5;
41pub(crate) mod membership;
42mod operator_errors;
43pub use operator_errors::{
44 ambiguous_binary_operator, ambiguous_prefix_operator, undefined_binary_operator,
45 undefined_binary_operator_named, undefined_prefix_operator,
46};
47mod operators;
48mod overload_resolution;
49mod qualified_column;
50mod range;
51mod range_offsets;
52pub use range_offsets::range_frame_offset_type;
53mod reverse;
54mod routine_signature;
55mod scalar_input;
56mod stored_constants;
57pub use scalar_input::{
58 scalar_cast_source_type_name_with_control, scalar_integer_operation_width,
59 scalar_integer_operation_width_with_control, scalar_operand_type_name,
60 scalar_operand_type_name_with_control, scalar_record_field_type_with_control,
61};
62pub use stored_constants::{
63 contains_unknown_literal, fold_stored_enum_constants, store_operand_coercions,
64 stored_enum_constant,
65};
66mod string_binary;
67
68pub(crate) use cast_compatibility::cast_catalog_entry_with_control;
69pub use cast_compatibility::{
70 assignment_type_compatible, cast_catalog_entry, cast_volatility, explicit_type_compatible,
71 CastCatalogEntry, CastMethod,
72};
73#[doc(hidden)]
74pub use checksum::{resolve_checksum_overload, ResolvedChecksumOverload};
75pub use common::{
76 common_context_expression_type, common_type, common_type_in, effective_overload_argument_type,
77 effective_overload_argument_type_with_params, function_call_argument_signature,
78 select_common_input_type, values_column_types, CommonTypeContext,
79 FunctionCallArgumentSignature,
80};
81pub use equality::{
82 equality_operand_type, equality_operand_type_with_control, foreign_key_operand_type,
83};
84#[doc(hidden)]
85pub use fixed_builtin::{
86 fixed_builtin_return_type, fixed_builtin_return_type_with_control,
87 is_function as is_fixed_builtin, resolve_fixed_builtin_call, ResolvedFixedBuiltinCall,
88};
89pub use functions::{
90 builtin_function_argument_targets, builtin_function_type, builtin_function_type_with_resolver,
91};
92#[doc(hidden)]
93pub use gamma::{resolve_gamma_overload, ResolvedGammaOverload};
94pub use introspection::{
95 bind_type_introspection, bind_type_introspection_with_control,
96 bind_type_introspection_with_resolver, validate_catalog_literals,
97};
98#[doc(hidden)]
99pub use json_strip::{resolve_json_strip_overload, ResolvedJsonStripOverload};
100#[doc(hidden)]
101pub use length::{resolve_length_overload, ResolvedLengthOverload};
102#[doc(hidden)]
103pub use md5::{resolve_md5_overload, ResolvedMd5Overload};
104#[doc(hidden)]
105pub use operators::{
106 binary_operator_by_oid, binary_operator_catalog_entry, binary_operator_types,
107 binary_operator_types_with_control, binary_result_type, binary_result_type_with_control,
108 numeric_operator_types, numeric_operator_types_with_control, require_equality_operator,
109 require_ordering_operator, unary_minus_catalog_entry, unary_operator_by_oid,
110 BinaryOperatorCatalogEntry, NumericOperatorTypes, UnaryOperatorCatalogEntry,
111};
112#[doc(hidden)]
113pub use overload_resolution::{
114 builtin_binding_matches, builtin_name_matches, canonical_column_type_name,
115 canonical_routine_type_name, function_resolution_error, match_builtin_function_overload,
116 match_function_signature, parse_enum_type_identity, rank_function_matches,
117 resolve_local_builtin_overload, routine_type_accepts_implicit_cast, routine_type_category,
118 routine_type_is_preferred, FunctionParameterDescriptor, MatchedBuiltinFunction,
119 MatchedFunctionSignature, RankedFunctionMatch,
120};
121#[doc(hidden)]
122pub use reverse::{resolve_reverse_overload, ResolvedReverseOverload};
123#[doc(hidden)]
124pub(crate) use routine_signature::match_routine_candidate;
125pub use routine_signature::{
126 match_routine_signature, routine_polymorphic_type, MatchedRoutineSignature,
127 RoutineCallDescriptor, RoutineCoercionTarget, RoutineParameterDescriptor,
128 RoutinePolymorphicFamily, RoutinePolymorphicType, RoutineSignatureMatchError,
129 RoutineTypeSubstitutions, RoutineVariadicMode, RoutineVariadicPlan,
130};
131#[doc(hidden)]
132pub use string_binary::{ResolvedStringBinaryOverload, ResolvedTextByteaOverload};
133
134pub trait FunctionTypeResolver: Send + Sync {
135 fn has_untyped_function(&self, _name: &str) -> bool {
140 false
141 }
142
143 fn resolve_type_name(&self, _name: &str) -> Result<Option<ColumnType>, SQLError> {
146 Ok(None)
147 }
148
149 fn enum_labels(&self) -> Option<&dyn crate::expr::enums::EnumLabelCatalog> {
151 None
152 }
153
154 fn catalog_input_functions(&self) -> Option<&dyn crate::expr::CatalogInputFunctions> {
156 None
157 }
158
159 fn composite_types(&self) -> Option<&dyn crate::expr::composites::CompositeTypeCatalog> {
161 None
162 }
163
164 fn require_type_usage(&self, _ty: &ColumnType) -> Result<(), SQLError> {
166 Ok(())
167 }
168
169 fn resolve_function_type(
170 &self,
171 name: &str,
172 binding: Option<&FunctionBinding>,
173 argument_names: &[Option<String>],
174 argument_types: &[Option<ColumnType>],
175 explicit_variadic: bool,
176 ) -> Result<Option<ColumnType>, SQLError>;
177
178 fn resolve_function_overload(
180 &self,
181 _name: &str,
182 _binding: Option<&FunctionBinding>,
183 _argument_names: &[Option<String>],
184 _argument_types: &[Option<ColumnType>],
185 _explicit_variadic: bool,
186 ) -> Result<Option<ResolvedFunctionOverload>, SQLError> {
187 Ok(None)
188 }
189
190 fn is_scalar_function_binding(&self, _binding: &FunctionBinding) -> Result<bool, SQLError> {
192 Ok(false)
193 }
194
195 fn resolve_function_overload_with_builtins(
200 &self,
201 name: &str,
202 binding: Option<&FunctionBinding>,
203 argument_names: &[Option<String>],
204 argument_types: &[Option<ColumnType>],
205 explicit_variadic: bool,
206 _builtins: &[BuiltinFunctionOverload],
207 ) -> Result<Option<ResolvedFunctionOverload>, SQLError> {
208 self.resolve_function_overload(
209 name,
210 binding,
211 argument_names,
212 argument_types,
213 explicit_variadic,
214 )
215 }
216
217 fn resolve_scalar_subquery_type(
219 &self,
220 _subquery: crate::SubqueryId,
221 _outer_schema: &RowSchema,
222 _params: &[SQLParam],
223 ) -> Result<Option<ColumnType>, SQLError> {
224 Ok(None)
225 }
226}
227
228#[derive(Debug, Clone, PartialEq, Eq)]
229pub struct BuiltinFunctionOverload {
230 pub name: String,
231 pub argument_names: Vec<Option<String>>,
232 pub argument_types: Vec<ColumnType>,
233 pub default_arguments: usize,
234 pub return_type: ColumnType,
235}
236
237#[derive(Debug, Clone, PartialEq, Eq)]
238pub struct ResolvedFunctionOverload {
239 pub binding: FunctionBinding,
240 pub return_type: ColumnType,
241 pub exact_matches: usize,
242 pub known_arguments: usize,
243 pub preferred_matches: usize,
244 pub precedes_pg_catalog: bool,
245}
246
247impl ResolvedFunctionOverload {
248 #[must_use]
249 pub fn is_exact_for_known_arguments(&self) -> bool {
250 self.known_arguments > 0 && self.exact_matches == self.known_arguments
251 }
252}
253
254pub fn scalar_type(
255 expression: &ScalarExpr,
256 schema: &dyn ScalarTypeSchema,
257 params: &[SQLParam],
258) -> Result<Option<ColumnType>, SQLError> {
259 scalar_type_inner(expression, schema, params, None)
260}
261
262pub fn scalar_type_with_control(
264 expression: &ScalarExpr,
265 schema: &dyn ScalarTypeSchema,
266 params: &[SQLParam],
267 control: &uqa_core::memory::ProductionControl<'_>,
268) -> Result<Option<uqa_core::memory::Produced<ColumnType>>, SQLError> {
269 scalar_type_inner_with_control(expression, schema, params, None, control)
270}
271
272pub fn common_context_type_with_control(
274 expression: &ScalarExpr,
275 schema: &dyn ScalarTypeSchema,
276 params: &[SQLParam],
277 control: &uqa_core::memory::ProductionControl<'_>,
278) -> Result<Option<uqa_core::memory::Produced<ColumnType>>, SQLError> {
279 common::common_context_expression_type_with_control(expression, schema, params, None, control)
280}
281
282pub fn scalar_type_with_resolver(
283 expression: &ScalarExpr,
284 schema: &dyn ScalarTypeSchema,
285 params: &[SQLParam],
286 resolver: &dyn FunctionTypeResolver,
287) -> Result<Option<ColumnType>, SQLError> {
288 scalar_type_inner(expression, schema, params, Some(resolver))
289}
290
291pub fn is_unknown_literal(expression: &ScalarExpr) -> bool {
293 matches!(expression, ScalarExpr::Literal(Value::Str(_) | Value::Null))
294}
295
296pub fn catalog_input_type(ty: &ColumnType) -> bool {
298 match ty {
299 ColumnType::Regproc
300 | ColumnType::Regprocedure
301 | ColumnType::Regclass
302 | ColumnType::Regcollation
303 | ColumnType::Regnamespace
304 | ColumnType::Regrole
305 | ColumnType::Regtype
306 | ColumnType::AclItem
307 | ColumnType::PgNodeTree
308 | ColumnType::Named(_)
309 | ColumnType::Enum(_)
310 | ColumnType::Composite(_)
311 | ColumnType::Record
312 | ColumnType::AnyArray
313 | ColumnType::Vector(_)
314 | ColumnType::Tensor(_) => true,
315 ColumnType::Array(inner) | ColumnType::Domain { base: inner, .. } => {
316 catalog_input_type(inner)
317 }
318 _ => false,
319 }
320}
321
322pub fn assignment_source_type(
324 expression: &ScalarExpr,
325 schema: &dyn ScalarTypeSchema,
326 params: &[SQLParam],
327 resolver: &dyn FunctionTypeResolver,
328) -> Result<Option<ColumnType>, SQLError> {
329 if is_unknown_literal(expression) {
330 return Ok(None);
331 }
332 scalar_type_with_resolver(expression, schema, params, resolver)
333}
334
335pub(super) fn scalar_type_inner(
336 expression: &ScalarExpr,
337 schema: &dyn ScalarTypeSchema,
338 params: &[SQLParam],
339 resolver: Option<&dyn FunctionTypeResolver>,
340) -> Result<Option<ColumnType>, SQLError> {
341 scalar_type_inner_with_control(
342 expression,
343 schema,
344 params,
345 resolver,
346 &uqa_core::memory::ProductionControl::uncontrolled(),
347 )
348 .map(|ty| {
349 ty.map(|ty| {
350 ty.into_uncontrolled()
351 .expect("ordinary scalar inference has no reservation")
352 })
353 })
354}
355
356#[cfg(test)]
357mod tests;
358
359mod declaration;
360pub use declaration::{resolve_alter_column_type, resolve_declared_column_type};
361
362mod coercion;
363pub mod composite_rows;
364pub use coercion::coerce_common_context_value;