use crate::ast::{ColumnType, FunctionBinding};
use crate::{SQLError, SQLParam};
use crate::schema::ScalarTypeSchema;
use crate::{RowSchema, ScalarExpr};
use uqa_core::Value;
mod array_transform;
pub(crate) use array_transform::resolve_array_transform_call;
mod call;
mod cast_compatibility;
mod checksum;
mod common;
pub(crate) use common::array_element_type;
pub(crate) use common::literal_input_type_with_control;
pub(crate) use common::value_type;
pub(crate) use common::value_type_with_control;
mod containment;
pub(crate) mod enums;
mod equality;
pub(crate) mod field_selection;
mod fixed_builtin;
pub(crate) use fixed_builtin::overloads as fixed_builtin_overloads;
mod functions;
mod gamma;
mod inference;
use inference::scalar_type_inner_with_control;
mod introspection;
mod json_strip;
mod length;
mod md5;
pub(crate) mod membership;
mod operator_errors;
pub use operator_errors::{
ambiguous_binary_operator, ambiguous_prefix_operator, undefined_binary_operator,
undefined_binary_operator_named, undefined_prefix_operator,
};
mod operators;
mod overload_resolution;
mod qualified_column;
mod range;
mod range_offsets;
pub use range_offsets::range_frame_offset_type;
mod reverse;
mod routine_signature;
mod scalar_input;
mod stored_constants;
pub use scalar_input::{
scalar_cast_source_type_name_with_control, scalar_integer_operation_width,
scalar_integer_operation_width_with_control, scalar_operand_type_name,
scalar_operand_type_name_with_control, scalar_record_field_type_with_control,
};
pub use stored_constants::{
contains_unknown_literal, fold_stored_enum_constants, store_operand_coercions,
stored_enum_constant,
};
mod string_binary;
pub(crate) use cast_compatibility::cast_catalog_entry_with_control;
pub use cast_compatibility::{
assignment_type_compatible, cast_catalog_entry, cast_volatility, explicit_type_compatible,
CastCatalogEntry, CastMethod,
};
#[doc(hidden)]
pub use checksum::{resolve_checksum_overload, ResolvedChecksumOverload};
pub use common::{
common_context_expression_type, common_type, common_type_in, effective_overload_argument_type,
effective_overload_argument_type_with_params, function_call_argument_signature,
select_common_input_type, values_column_types, CommonTypeContext,
FunctionCallArgumentSignature,
};
pub use equality::{
equality_operand_type, equality_operand_type_with_control, foreign_key_operand_type,
};
#[doc(hidden)]
pub use fixed_builtin::{
fixed_builtin_return_type, fixed_builtin_return_type_with_control,
is_function as is_fixed_builtin, resolve_fixed_builtin_call, ResolvedFixedBuiltinCall,
};
pub use functions::{
builtin_function_argument_targets, builtin_function_type, builtin_function_type_with_resolver,
};
#[doc(hidden)]
pub use gamma::{resolve_gamma_overload, ResolvedGammaOverload};
pub use introspection::{
bind_type_introspection, bind_type_introspection_with_control,
bind_type_introspection_with_resolver, validate_catalog_literals,
};
#[doc(hidden)]
pub use json_strip::{resolve_json_strip_overload, ResolvedJsonStripOverload};
#[doc(hidden)]
pub use length::{resolve_length_overload, ResolvedLengthOverload};
#[doc(hidden)]
pub use md5::{resolve_md5_overload, ResolvedMd5Overload};
#[doc(hidden)]
pub use operators::{
binary_operator_by_oid, binary_operator_catalog_entry, binary_operator_types,
binary_operator_types_with_control, binary_result_type, binary_result_type_with_control,
numeric_operator_types, numeric_operator_types_with_control, require_equality_operator,
require_ordering_operator, unary_minus_catalog_entry, unary_operator_by_oid,
BinaryOperatorCatalogEntry, NumericOperatorTypes, UnaryOperatorCatalogEntry,
};
#[doc(hidden)]
pub use overload_resolution::{
builtin_binding_matches, builtin_name_matches, canonical_column_type_name,
canonical_routine_type_name, function_resolution_error, match_builtin_function_overload,
match_function_signature, parse_enum_type_identity, rank_function_matches,
resolve_local_builtin_overload, routine_type_accepts_implicit_cast, routine_type_category,
routine_type_is_preferred, FunctionParameterDescriptor, MatchedBuiltinFunction,
MatchedFunctionSignature, RankedFunctionMatch,
};
#[doc(hidden)]
pub use reverse::{resolve_reverse_overload, ResolvedReverseOverload};
#[doc(hidden)]
pub(crate) use routine_signature::match_routine_candidate;
pub use routine_signature::{
match_routine_signature, routine_polymorphic_type, MatchedRoutineSignature,
RoutineCallDescriptor, RoutineCoercionTarget, RoutineParameterDescriptor,
RoutinePolymorphicFamily, RoutinePolymorphicType, RoutineSignatureMatchError,
RoutineTypeSubstitutions, RoutineVariadicMode, RoutineVariadicPlan,
};
#[doc(hidden)]
pub use string_binary::{ResolvedStringBinaryOverload, ResolvedTextByteaOverload};
pub trait FunctionTypeResolver: Send + Sync {
fn has_untyped_function(&self, _name: &str) -> bool {
false
}
fn resolve_type_name(&self, _name: &str) -> Result<Option<ColumnType>, SQLError> {
Ok(None)
}
fn enum_labels(&self) -> Option<&dyn crate::expr::enums::EnumLabelCatalog> {
None
}
fn catalog_input_functions(&self) -> Option<&dyn crate::expr::CatalogInputFunctions> {
None
}
fn composite_types(&self) -> Option<&dyn crate::expr::composites::CompositeTypeCatalog> {
None
}
fn require_type_usage(&self, _ty: &ColumnType) -> Result<(), SQLError> {
Ok(())
}
fn resolve_function_type(
&self,
name: &str,
binding: Option<&FunctionBinding>,
argument_names: &[Option<String>],
argument_types: &[Option<ColumnType>],
explicit_variadic: bool,
) -> Result<Option<ColumnType>, SQLError>;
fn resolve_function_overload(
&self,
_name: &str,
_binding: Option<&FunctionBinding>,
_argument_names: &[Option<String>],
_argument_types: &[Option<ColumnType>],
_explicit_variadic: bool,
) -> Result<Option<ResolvedFunctionOverload>, SQLError> {
Ok(None)
}
fn is_scalar_function_binding(&self, _binding: &FunctionBinding) -> Result<bool, SQLError> {
Ok(false)
}
fn resolve_function_overload_with_builtins(
&self,
name: &str,
binding: Option<&FunctionBinding>,
argument_names: &[Option<String>],
argument_types: &[Option<ColumnType>],
explicit_variadic: bool,
_builtins: &[BuiltinFunctionOverload],
) -> Result<Option<ResolvedFunctionOverload>, SQLError> {
self.resolve_function_overload(
name,
binding,
argument_names,
argument_types,
explicit_variadic,
)
}
fn resolve_scalar_subquery_type(
&self,
_subquery: crate::SubqueryId,
_outer_schema: &RowSchema,
_params: &[SQLParam],
) -> Result<Option<ColumnType>, SQLError> {
Ok(None)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct BuiltinFunctionOverload {
pub name: String,
pub argument_names: Vec<Option<String>>,
pub argument_types: Vec<ColumnType>,
pub default_arguments: usize,
pub return_type: ColumnType,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ResolvedFunctionOverload {
pub binding: FunctionBinding,
pub return_type: ColumnType,
pub exact_matches: usize,
pub known_arguments: usize,
pub preferred_matches: usize,
pub precedes_pg_catalog: bool,
}
impl ResolvedFunctionOverload {
#[must_use]
pub fn is_exact_for_known_arguments(&self) -> bool {
self.known_arguments > 0 && self.exact_matches == self.known_arguments
}
}
pub fn scalar_type(
expression: &ScalarExpr,
schema: &dyn ScalarTypeSchema,
params: &[SQLParam],
) -> Result<Option<ColumnType>, SQLError> {
scalar_type_inner(expression, schema, params, None)
}
pub fn scalar_type_with_control(
expression: &ScalarExpr,
schema: &dyn ScalarTypeSchema,
params: &[SQLParam],
control: &uqa_core::memory::ProductionControl<'_>,
) -> Result<Option<uqa_core::memory::Produced<ColumnType>>, SQLError> {
scalar_type_inner_with_control(expression, schema, params, None, control)
}
pub fn common_context_type_with_control(
expression: &ScalarExpr,
schema: &dyn ScalarTypeSchema,
params: &[SQLParam],
control: &uqa_core::memory::ProductionControl<'_>,
) -> Result<Option<uqa_core::memory::Produced<ColumnType>>, SQLError> {
common::common_context_expression_type_with_control(expression, schema, params, None, control)
}
pub fn scalar_type_with_resolver(
expression: &ScalarExpr,
schema: &dyn ScalarTypeSchema,
params: &[SQLParam],
resolver: &dyn FunctionTypeResolver,
) -> Result<Option<ColumnType>, SQLError> {
scalar_type_inner(expression, schema, params, Some(resolver))
}
pub fn is_unknown_literal(expression: &ScalarExpr) -> bool {
matches!(expression, ScalarExpr::Literal(Value::Str(_) | Value::Null))
}
pub fn catalog_input_type(ty: &ColumnType) -> bool {
match ty {
ColumnType::Regproc
| ColumnType::Regprocedure
| ColumnType::Regclass
| ColumnType::Regnamespace
| ColumnType::Regrole
| ColumnType::Regtype
| ColumnType::AclItem
| ColumnType::PgNodeTree
| ColumnType::Named(_)
| ColumnType::Enum(_)
| ColumnType::Composite(_)
| ColumnType::Record
| ColumnType::AnyArray
| ColumnType::Vector(_)
| ColumnType::Tensor(_) => true,
ColumnType::Array(inner) | ColumnType::Domain { base: inner, .. } => {
catalog_input_type(inner)
}
_ => false,
}
}
pub fn assignment_source_type(
expression: &ScalarExpr,
schema: &dyn ScalarTypeSchema,
params: &[SQLParam],
resolver: &dyn FunctionTypeResolver,
) -> Result<Option<ColumnType>, SQLError> {
if is_unknown_literal(expression) {
return Ok(None);
}
scalar_type_with_resolver(expression, schema, params, resolver)
}
pub(super) fn scalar_type_inner(
expression: &ScalarExpr,
schema: &dyn ScalarTypeSchema,
params: &[SQLParam],
resolver: Option<&dyn FunctionTypeResolver>,
) -> Result<Option<ColumnType>, SQLError> {
scalar_type_inner_with_control(
expression,
schema,
params,
resolver,
&uqa_core::memory::ProductionControl::uncontrolled(),
)
.map(|ty| {
ty.map(|ty| {
ty.into_uncontrolled()
.expect("ordinary scalar inference has no reservation")
})
})
}
#[cfg(test)]
mod tests;
mod declaration;
pub use declaration::{resolve_alter_column_type, resolve_declared_column_type};
mod coercion;
pub mod composite_rows;
pub use coercion::coerce_common_context_value;