Skip to main content

sql_fun_sqlast/sem/
problem.rs

1#![doc= include_str!("problem.md")]
2
3mod name_resolution;
4mod overload_resolution;
5mod sql_highlighter;
6
7use std::collections::HashSet;
8
9use miette::{GraphicalReportHandler, LabeledSpan, NamedSource, Report};
10use sql_fun_core::HighlighterTheme;
11
12use crate::{
13    StringSpan,
14    sem::{
15        AnalysisError, DefElemKey, FullName, OperatorName, SemScalarExpr, TypeDefinition,
16        TypeReference, create_table::ViewName, type_system::ArgumentBindingCollection,
17    },
18};
19
20pub use self::name_resolution::{DomainBaseTypeNameNotFound, NameResolution};
21
22pub(crate) use self::{overload_resolution::OverloadResolution, sql_highlighter::SqlHighlighter};
23
24trait Problem {
25    const CODE: &'static str;
26    const MESSAGE: &'static str;
27    const SEVERITY: miette::Severity;
28    const SPAN_LABEL: &'static str;
29
30    fn get_problem_span(&self) -> StringSpan;
31
32    fn labeled_problem_span(&self) -> LabeledSpan {
33        self.get_problem_span().new_labeled_span(Self::SPAN_LABEL)
34    }
35}
36
37trait RenderProblemReport: Problem {
38    fn generate_report(
39        &self,
40        handler: &GraphicalReportHandler,
41        source: String,
42    ) -> Result<String, AnalysisError> {
43        let diag = miette::MietteDiagnostic::new(Self::MESSAGE)
44            .with_code(Self::CODE)
45            .with_severity(Self::SEVERITY)
46            .with_label(self.labeled_problem_span());
47
48        let report = Report::new(diag).with_source_code(NamedSource::new("SQL", source));
49
50        let mut out = String::new();
51        handler.render_report(&mut out, &*report)?;
52        Ok(out)
53    }
54}
55
56/// Semantic analysis problems
57#[allow(clippy::large_enum_variant)]
58#[derive(Debug, Clone)]
59pub enum AnalysisProblem {
60    /// Name resolution problems
61    NameResolution(NameResolution),
62    /// Overload resolution problems
63    OverloadResolution(OverloadResolution),
64
65    /// extension not found
66    ExtensionNotFound(String),
67
68    /// can not to guess nullablity
69    NullabilityUnknown(String),
70
71    /// Argument type missmatch
72    ArgumentTypeMissmatch(FullName, usize),
73
74    /// duplicate def elem key
75    DuplicateDefElemKey(DefElemKey),
76
77    /// explicit cast not defined
78    ExplicitCastNotDefined(TypeReference, TypeReference),
79
80    /// Coalesce expr type unknown
81    CoalesceExprTypeUnknown(Vec<SemScalarExpr>),
82
83    /// Expression type not known
84    ExpressionTypeNotKnown(SemScalarExpr),
85
86    /// Operator Not Defined
87    UndefinedOperator(
88        crate::syn::AExprKind,
89        OperatorName,
90        Option<SemScalarExpr>,
91        Option<SemScalarExpr>,
92    ),
93
94    /// Array Required
95    RequireArray(SemScalarExpr, TypeReference),
96
97    /// sub query not have a derived column
98    SubQueryNotHaveColumnForDerivedColumnName(),
99
100    /// incompatible case values
101    IncompatibleCaseValues(HashSet<TypeReference>),
102
103    /// case when expr type unknown
104    CaseWhenExprTypeUnknown(SemScalarExpr),
105
106    /// array type missmatch
107    ArrayIndexTypeMissmatch(SemScalarExpr, TypeReference),
108
109    /// member access requires composite type
110    MemberAccessRequiresCompositeType(FullName, String),
111
112    /// function argument implicit cast not found
113    FunctionArgImplicitCastNotFound(FullName, usize, TypeDefinition, SemScalarExpr),
114
115    /// implicit cast not found
116    ImplicitCastNotFound(TypeReference, TypeReference),
117}
118
119impl AnalysisProblem {
120    /// covert problem to report
121    pub fn render_report(
122        &self,
123        theme: &HighlighterTheme,
124        source: String,
125    ) -> Result<String, AnalysisError> {
126        let report_handler = GraphicalReportHandler::new()
127            .with_syntax_highlighting(SqlHighlighter::from_theme(theme)?);
128
129        let report = match self {
130            Self::NameResolution(nr) => nr.render_report(&report_handler, source)?,
131            _ => todo!(),
132        };
133        Ok(report)
134    }
135
136    /// extension not found
137    #[tracing::instrument()]
138    pub fn extension_not_found(name: &str) -> Self {
139        Self::ExtensionNotFound(String::from(name))
140    }
141
142    /// expression nullability not known
143    #[tracing::instrument()]
144    pub fn nullability_unknown(item_name: &str) -> Self {
145        Self::NullabilityUnknown(String::from(item_name))
146    }
147
148    /// function argument type missmatch
149    #[tracing::instrument()]
150    pub fn argument_type_missmatch(func_name: &FullName, index: usize) -> Self {
151        Self::ArgumentTypeMissmatch(func_name.clone(), index)
152    }
153
154    /// duplicate name in definition element
155    #[tracing::instrument()]
156    pub fn duplicate_def_elem_key(key: &DefElemKey) -> Self {
157        Self::DuplicateDefElemKey(key.clone())
158    }
159
160    /// doing explicit cast coversion , but not allowed
161    #[tracing::instrument()]
162    pub fn explicit_cast_not_defined(source: &TypeReference, target: &TypeReference) -> Self {
163        Self::ExplicitCastNotDefined(source.clone(), target.clone())
164    }
165
166    /// expression requires array but not
167    #[tracing::instrument()]
168    pub fn array_required(expr: &SemScalarExpr, type_inspected: &TypeReference) -> Self {
169        Self::RequireArray(expr.clone(), type_inspected.clone())
170    }
171
172    /// array index type not integer
173    #[tracing::instrument()]
174    pub fn array_index_type_missmatch(
175        expr: &SemScalarExpr,
176        type_inspected: &TypeReference,
177    ) -> Self {
178        Self::ArrayIndexTypeMissmatch(expr.clone(), type_inspected.clone())
179    }
180
181    /// member accessing to non-composite type
182    #[tracing::instrument()]
183    pub fn member_access_requires_composite_type(type_name: &FullName, member_name: &str) -> Self {
184        Self::MemberAccessRequiresCompositeType(type_name.clone(), member_name.to_string())
185    }
186
187    /// operator not defined
188    #[track_caller]
189    #[tracing::instrument()]
190    pub fn undefined_operator(
191        aexpr_op: crate::syn::AExprKind,
192        name: &OperatorName,
193        left_arg: &Option<SemScalarExpr>,
194        right_arg: &Option<SemScalarExpr>,
195    ) -> Self {
196        Self::UndefinedOperator(aexpr_op, name.clone(), left_arg.clone(), right_arg.clone())
197    }
198
199    /// parameter type can not cast to function argument
200    #[tracing::instrument()]
201    pub fn parameter_type_missmatch_for_table_function(
202        call: &crate::syn::FuncCall,
203        arg_types: ArgumentBindingCollection,
204    ) -> Self {
205        todo!()
206    }
207
208    /// specified function result set type not found
209    #[track_caller]
210    #[tracing::instrument()]
211    pub fn function_result_set_type_not_found(ret_type: &super::FullName) -> Self {
212        todo!("{ret_type:?}")
213    }
214
215    /// coalece argument unreachable
216    #[tracing::instrument()]
217    pub fn unreachable_coalesce_argument(
218        arg_expr: &SemScalarExpr,
219        first_non_null: &SemScalarExpr,
220    ) -> Self {
221        todo!()
222    }
223
224    /// unknown type used in coalesce
225    #[tracing::instrument()]
226    pub fn unknown_type_in_coalesce_expr(arg_expr: &SemScalarExpr) -> Self {
227        todo!()
228    }
229
230    /// colesce expression result type ambiguous
231    #[tracing::instrument()]
232    pub fn coalesce_expr_type_ambiguous(
233        arg_exprs: &Vec<SemScalarExpr>,
234        candiates: &HashSet<TypeReference>,
235        choose: Option<&TypeReference>,
236    ) -> Self {
237        todo!()
238    }
239
240    /// all of coalesce type is not known
241    #[tracing::instrument()]
242    pub fn coalesce_expr_type_unknown(arg_exprs: &[SemScalarExpr]) -> Self {
243        tracing::warn!("{arg_exprs:#?}");
244        Self::CoalesceExprTypeUnknown(arg_exprs.to_vec())
245    }
246
247    /// implicit cast not allowed
248    #[tracing::instrument()]
249    pub fn function_arg_implicit_cast_not_found(
250        func_name: &FullName,
251        index: usize,
252        t: &TypeDefinition,
253        arg: &SemScalarExpr,
254    ) -> Self {
255        Self::FunctionArgImplicitCastNotFound(func_name.clone(), index, t.clone(), arg.clone())
256    }
257
258    /// view used as materialized view, but not a materialized view
259    #[tracing::instrument()]
260    pub fn view_not_matview(view_name: &ViewName) -> Self {
261        todo!()
262    }
263
264    /// operator name syntax is invalid
265    #[tracing::instrument()]
266    pub fn operator_name_syntax(v: &[String]) -> Self {
267        todo!()
268    }
269
270    /// expression type not known
271    #[tracing::instrument()]
272    pub fn expression_type_not_known(expr: &SemScalarExpr) -> Self {
273        Self::ExpressionTypeNotKnown(expr.clone())
274    }
275
276    /// case when type unknown
277    #[tracing::instrument()]
278    pub fn case_when_type_unknown(case_when_expr: SemScalarExpr) -> Self {
279        Self::CaseWhenExprTypeUnknown(case_when_expr)
280    }
281
282    /// implicit cast not found
283    #[tracing::instrument()]
284    pub fn implicit_cast_not_found(ty: &TypeReference, result_type: &TypeReference) -> Self {
285        Self::ImplicitCastNotFound(ty.clone(), result_type.clone())
286    }
287
288    /// incompatible cast values
289    #[tracing::instrument()]
290    pub fn incompatible_case_values(result_types: HashSet<TypeReference>) -> Self {
291        Self::IncompatibleCaseValues(result_types)
292    }
293
294    /// unexpected dynamic type
295    #[tracing::instrument()]
296    pub fn unexpected_dynamic_type(sem_type: &TypeDefinition) -> Self {
297        todo!()
298    }
299
300    /// table not have column
301    #[tracing::instrument()]
302    pub fn table_not_have_column_for_derived_column_name() -> Self {
303        todo!()
304    }
305
306    /// cte not have column
307    #[tracing::instrument()]
308    pub fn cte_not_have_column_for_derived_column_name() -> Self {
309        todo!()
310    }
311
312    /// subquery not have column
313    #[tracing::instrument()]
314    pub fn subquery_not_have_column_for_derived_column_name() -> Self {
315        Self::SubQueryNotHaveColumnForDerivedColumnName()
316    }
317}