Skip to main content

sql_fun_sqlast/sem/scalar_expr/
arith_expr.rs

1mod binary;
2mod call_sites;
3mod impl_analyze;
4mod impl_build_op;
5mod null_if;
6mod unary;
7
8use sql_fun_core::IVec;
9
10use crate::{
11    sem::{
12        AnalysisError, FromClause, ParseContext, SemScalarExpr, TypeReference, WithClause,
13        analyze_scaler_expr, scalar_expr::SemScalarExprNode,
14    },
15    syn::ScanToken,
16};
17
18pub use self::{
19    call_sites::{
20        AllBinaryCallSite, AnyBinaryCallSite, BinaryOpCallSite, LeftUnaryCallSite,
21        RightUnaryCallSite, UndefinedOperatorAllCallSite, UndefinedOperatorAnyCallSite,
22        UndefinedOperatorCallSite,
23    },
24    null_if::NullIfExpr,
25};
26
27/// arith expression
28#[derive(Debug, Clone, Eq, Hash, PartialEq, serde::Serialize, serde::Deserialize)]
29pub enum ArithExpr {
30    /// binary operator expression
31    OpBinary(Box<BinaryOpCallSite>),
32    /// left unary expression
33    OpLeftUnary(Box<LeftUnaryCallSite>),
34    /// right unary expression
35    OpRightUnary(Box<RightUnaryCallSite>),
36    /// any binary expression
37    OpAnyBinary(Box<AnyBinaryCallSite>),
38    /// all binary expression
39    OpAllBinary(Box<AllBinaryCallSite>),
40
41    /// undefined operator
42    UndefinedOperator(Box<UndefinedOperatorCallSite>),
43    /// undefined operator Any
44    UndefinedOperatorAny(Box<UndefinedOperatorAnyCallSite>),
45    /// undefined operator All
46    UndefinedOperatorAll(Box<UndefinedOperatorAllCallSite>),
47
48    /// null-if  expression
49    NullIfExpr(Box<NullIfExpr>),
50}
51
52impl ArithExpr {
53    fn build_distinct<TParseContext>(
54        _context: TParseContext,
55        _lexpr: Option<SemScalarExpr>,
56        _rexpr: Option<SemScalarExpr>,
57    ) -> Result<(SemScalarExpr, TParseContext), AnalysisError> {
58        todo!()
59    }
60
61    fn build_not_distinct<TParseContext>(
62        _context: TParseContext,
63        _lexpr: Option<SemScalarExpr>,
64        _rexpr: Option<SemScalarExpr>,
65    ) -> Result<(SemScalarExpr, TParseContext), AnalysisError> {
66        todo!()
67    }
68
69    fn build_in<TParseContext>(
70        _context: TParseContext,
71        _lexpr: Option<SemScalarExpr>,
72        _rexpr: Option<SemScalarExpr>,
73    ) -> Result<(SemScalarExpr, TParseContext), AnalysisError> {
74        todo!()
75    }
76
77    fn build_like<TParseContext>(
78        _context: TParseContext,
79        _lexpr: Option<SemScalarExpr>,
80        _rexpr: Option<SemScalarExpr>,
81    ) -> Result<(SemScalarExpr, TParseContext), AnalysisError> {
82        todo!()
83    }
84
85    fn build_ilike<TParseContext>(
86        _context: TParseContext,
87        _lexpr: Option<SemScalarExpr>,
88        _rexpr: Option<SemScalarExpr>,
89    ) -> Result<(SemScalarExpr, TParseContext), AnalysisError> {
90        todo!()
91    }
92
93    fn build_similar<TParseContext>(
94        _context: TParseContext,
95        _lexpr: Option<SemScalarExpr>,
96        _rexpr: Option<SemScalarExpr>,
97    ) -> Result<(SemScalarExpr, TParseContext), AnalysisError> {
98        todo!()
99    }
100
101    fn build_between<TParseContext>(
102        _context: TParseContext,
103        _lexpr: Option<SemScalarExpr>,
104        _rexpr: Option<SemScalarExpr>,
105    ) -> Result<(SemScalarExpr, TParseContext), AnalysisError> {
106        todo!()
107    }
108
109    fn build_not_between<TParseContext>(
110        _context: TParseContext,
111        _lexpr: Option<SemScalarExpr>,
112        _rexpr: Option<SemScalarExpr>,
113    ) -> Result<(SemScalarExpr, TParseContext), AnalysisError> {
114        todo!()
115    }
116
117    fn build_between_sym<TParseContext>(
118        _context: TParseContext,
119        _lexpr: Option<SemScalarExpr>,
120        _rexpr: Option<SemScalarExpr>,
121    ) -> Result<(SemScalarExpr, TParseContext), AnalysisError> {
122        todo!()
123    }
124
125    fn build_not_between_sym<TParseContext>(
126        _context: TParseContext,
127        _lexpr: Option<SemScalarExpr>,
128        _rexpr: Option<SemScalarExpr>,
129    ) -> Result<(SemScalarExpr, TParseContext), AnalysisError> {
130        todo!()
131    }
132
133    fn inputs_is_not_null(&self) -> Option<bool> {
134        match &self {
135            Self::OpLeftUnary(call_site) => call_site.is_not_null(),
136            Self::OpRightUnary(call_site) => call_site.is_not_null(),
137            Self::UndefinedOperator(call_site) => call_site.inputs_is_not_null(),
138            Self::OpBinary(call_site) => call_site.is_not_null(),
139            Self::OpAnyBinary(call_site) => call_site.is_not_null(),
140            Self::OpAllBinary(call_site) => call_site.is_not_null(),
141            Self::UndefinedOperatorAny(call_site) => call_site.is_not_null(),
142            Self::UndefinedOperatorAll(call_site) => call_site.is_not_null(),
143            Self::NullIfExpr(null_if) => null_if.is_not_null(),
144        }
145    }
146
147    fn operator_returns_null(&self) -> Option<bool> {
148        None
149    }
150
151    fn analyze_optional_expr<TParseContext>(
152        context: TParseContext,
153        with_clause: &WithClause,
154        from_clause: &FromClause,
155        expr: Option<crate::syn::Node>,
156        tokens: &IVec<ScanToken>,
157    ) -> Result<(Option<SemScalarExpr>, TParseContext), AnalysisError>
158    where
159        TParseContext: ParseContext,
160    {
161        let Some(expr) = expr else {
162            return Ok((None, context));
163        };
164        let (sem_expr, new_context) =
165            analyze_scaler_expr(context, with_clause, from_clause, expr, tokens)?;
166        Ok((Some(sem_expr), new_context))
167    }
168}
169
170impl SemScalarExprNode for ArithExpr {
171    fn get_type(&self) -> Option<TypeReference> {
172        match &self {
173            Self::OpBinary(call_site) => Some(call_site.get_return_type().clone()),
174            Self::OpLeftUnary(call_site) => Some(call_site.get_return_type().clone()),
175            Self::OpRightUnary(call_site) => Some(call_site.get_return_type().clone()),
176            Self::OpAnyBinary(call_site) => Some(call_site.get_return_type().clone()),
177            Self::OpAllBinary(call_site) => Some(call_site.get_return_type().clone()),
178            Self::NullIfExpr(null_if) => null_if.get_type(),
179            Self::UndefinedOperator(_)
180            | Self::UndefinedOperatorAny(_)
181            | Self::UndefinedOperatorAll(_) => None,
182        }
183    }
184
185    fn is_not_null(&self) -> Option<bool> {
186        let is_strict = match &self {
187            Self::OpLeftUnary(site) => site.is_strict(),
188            Self::OpRightUnary(site) => site.is_strict(),
189            Self::OpBinary(call_site) => call_site.is_strict(),
190            Self::OpAnyBinary(call_site) => call_site.is_strict(),
191            Self::OpAllBinary(call_site) => call_site.is_strict(),
192            Self::NullIfExpr(null_if) => null_if.is_strict(),
193            Self::UndefinedOperator(_)
194            | Self::UndefinedOperatorAny(_)
195            | Self::UndefinedOperatorAll(_) => return None,
196        };
197        if is_strict {
198            if matches!(self.inputs_is_not_null(), Some(true)) {
199                if matches!(self.operator_returns_null(), Some(false)) {
200                    Some(true)
201                } else {
202                    Some(false)
203                }
204            } else {
205                Some(false)
206            }
207        } else {
208            None
209        }
210    }
211}