sql_fun_sqlast/sem/scalar_expr/
arith_expr.rs1mod 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#[derive(Debug, Clone, Eq, Hash, PartialEq, serde::Serialize, serde::Deserialize)]
29pub enum ArithExpr {
30 OpBinary(Box<BinaryOpCallSite>),
32 OpLeftUnary(Box<LeftUnaryCallSite>),
34 OpRightUnary(Box<RightUnaryCallSite>),
36 OpAnyBinary(Box<AnyBinaryCallSite>),
38 OpAllBinary(Box<AllBinaryCallSite>),
40
41 UndefinedOperator(Box<UndefinedOperatorCallSite>),
43 UndefinedOperatorAny(Box<UndefinedOperatorAnyCallSite>),
45 UndefinedOperatorAll(Box<UndefinedOperatorAllCallSite>),
47
48 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}