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