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