1use hawdb_core::Value;
21
22mod numeric;
23pub use numeric::{bind_constant_numeric, bind_sql_value};
24
25#[derive(Debug, Clone, PartialEq, Eq)]
26pub enum SqlValue {
27 Literal(Value),
28 Parameter(usize),
29 Expression(Box<Expr>),
31}
32
33#[derive(Debug, Clone, PartialEq, Eq)]
35pub struct Expr {
36 pub kind: ExprKind,
37 pub span: SqlSourceSpan,
38}
39
40#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
43pub struct SqlSourceSpan {
44 pub start: SqlSourceLocation,
45 pub end: SqlSourceLocation,
46}
47
48#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
49pub struct SqlSourceLocation {
50 pub line: u64,
51 pub column: u64,
52}
53
54#[derive(Debug, Clone, PartialEq, Eq)]
55pub enum ExprKind {
56 Column(SqlColumnRef),
57 Value(SqlValue),
58 Arithmetic {
59 left: Box<Expr>,
60 op: hawdb_core::numeric::NumericBinaryOp,
61 right: Box<Expr>,
62 },
63 Negate(Box<Expr>),
64 Cast {
65 expression: Box<Expr>,
66 target: hawdb_core::numeric::NumericType,
67 },
68 Function {
69 name: String,
70 arguments: Vec<SqlFunctionArgument>,
71 distinct: bool,
72 filter: Option<Box<Expr>>,
73 },
74 And(Box<Expr>, Box<Expr>),
75 Or(Box<Expr>, Box<Expr>),
76 Not(Box<Expr>),
77 Compare {
78 left: Box<Expr>,
79 op: SqlComparisonOp,
80 right: Box<Expr>,
81 },
82 InList {
83 left: Box<Expr>,
84 values: Vec<Expr>,
85 negated: bool,
86 },
87 Like {
88 left: Box<Expr>,
89 pattern: Box<Expr>,
90 case_insensitive: bool,
91 negated: bool,
92 escape: SqlLikeEscape,
93 },
94 IsNull {
95 expression: Box<Expr>,
96 negated: bool,
97 },
98}
99
100pub type SqlExpression = Expr;
102pub type SqlPredicate = Expr;
104
105impl Expr {
106 pub fn unspanned(kind: ExprKind) -> Self {
107 Self {
108 kind,
109 span: SqlSourceSpan::default(),
110 }
111 }
112
113 pub fn column(column: SqlColumnRef) -> Self {
114 Self::unspanned(ExprKind::Column(column))
115 }
116
117 pub fn value(value: SqlValue) -> Self {
118 Self::unspanned(ExprKind::Value(value))
119 }
120
121 pub fn as_column(&self) -> Option<&SqlColumnRef> {
122 match &self.kind {
123 ExprKind::Column(column) => Some(column),
124 _ => None,
125 }
126 }
127
128 pub fn as_value(&self) -> Option<&SqlValue> {
129 match &self.kind {
130 ExprKind::Value(value) => Some(value),
131 _ => None,
132 }
133 }
134
135 pub fn require_column(&self) -> hawdb_core::Result<&SqlColumnRef> {
136 self.as_column().ok_or_else(|| {
137 hawdb_core::HawDBError::Semantic(
138 "this SQL expression position requires a column reference".to_owned(),
139 )
140 })
141 }
142
143 pub fn require_value(&self) -> hawdb_core::Result<&SqlValue> {
144 self.as_value().ok_or_else(|| {
145 hawdb_core::HawDBError::Semantic(
146 "this SQL expression position requires a literal or parameter".to_owned(),
147 )
148 })
149 }
150
151 pub fn try_visit_mut<E>(
154 &mut self,
155 visitor: &mut impl FnMut(&mut Self) -> std::result::Result<(), E>,
156 ) -> std::result::Result<(), E> {
157 match &mut self.kind {
158 ExprKind::Value(SqlValue::Expression(expression)) => {
159 expression.try_visit_mut(visitor)?
160 }
161 ExprKind::Column(_) | ExprKind::Value(_) => {}
162 ExprKind::Function {
163 arguments, filter, ..
164 } => {
165 for argument in arguments {
166 if let SqlFunctionArgument::Expression(expression) = argument {
167 expression.try_visit_mut(visitor)?;
168 }
169 }
170 if let Some(filter) = filter {
171 filter.try_visit_mut(visitor)?;
172 }
173 }
174 ExprKind::And(left, right)
175 | ExprKind::Or(left, right)
176 | ExprKind::Compare { left, right, .. }
177 | ExprKind::Arithmetic { left, right, .. } => {
178 left.try_visit_mut(visitor)?;
179 right.try_visit_mut(visitor)?;
180 }
181 ExprKind::Not(expression)
182 | ExprKind::IsNull { expression, .. }
183 | ExprKind::Negate(expression)
184 | ExprKind::Cast { expression, .. } => expression.try_visit_mut(visitor)?,
185 ExprKind::InList { left, values, .. } => {
186 left.try_visit_mut(visitor)?;
187 for value in values {
188 value.try_visit_mut(visitor)?;
189 }
190 }
191 ExprKind::Like { left, pattern, .. } => {
192 left.try_visit_mut(visitor)?;
193 pattern.try_visit_mut(visitor)?;
194 }
195 }
196 visitor(self)
197 }
198
199 pub fn visit<'a>(&'a self, visitor: &mut impl FnMut(&'a Self)) {
201 visitor(self);
202 match &self.kind {
203 ExprKind::Value(SqlValue::Expression(expression)) => expression.visit(visitor),
204 ExprKind::Column(_) | ExprKind::Value(_) => {}
205 ExprKind::Function {
206 arguments, filter, ..
207 } => {
208 for argument in arguments {
209 if let SqlFunctionArgument::Expression(expression) = argument {
210 expression.visit(visitor);
211 }
212 }
213 if let Some(filter) = filter {
214 filter.visit(visitor);
215 }
216 }
217 ExprKind::And(left, right)
218 | ExprKind::Or(left, right)
219 | ExprKind::Compare { left, right, .. }
220 | ExprKind::Arithmetic { left, right, .. } => {
221 left.visit(visitor);
222 right.visit(visitor);
223 }
224 ExprKind::Not(expression)
225 | ExprKind::IsNull { expression, .. }
226 | ExprKind::Negate(expression)
227 | ExprKind::Cast { expression, .. } => expression.visit(visitor),
228 ExprKind::InList { left, values, .. } => {
229 left.visit(visitor);
230 for value in values {
231 value.visit(visitor);
232 }
233 }
234 ExprKind::Like { left, pattern, .. } => {
235 left.visit(visitor);
236 pattern.visit(visitor);
237 }
238 }
239 }
240}
241
242#[derive(Debug, Clone, PartialEq, Eq)]
243pub enum SqlFunctionArgument {
244 Expression(SqlExpression),
245 Wildcard,
246}
247
248#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
249pub struct SqlColumnRef {
250 pub qualifier: Option<String>,
251 pub name: String,
252}
253
254#[derive(Debug, Clone, PartialEq, Eq)]
255pub struct SqlOrderItem {
256 pub expression: Expr,
257 pub direction: SqlOrderDirection,
258 pub nulls: SqlNullOrder,
259}
260
261#[derive(Debug, Clone, PartialEq, Eq)]
263pub struct SqlIndexColumn {
264 pub column: SqlColumnRef,
265 pub direction: SqlOrderDirection,
266 pub nulls: SqlNullOrder,
267}
268
269#[derive(Debug, Clone, Copy, PartialEq, Eq)]
270pub enum SqlOrderDirection {
271 Asc,
272 Desc,
273}
274
275#[derive(Debug, Clone, Copy, PartialEq, Eq)]
276pub enum SqlNullOrder {
277 DialectDefault,
278 First,
279 Last,
280}
281
282#[derive(Debug, Clone, Copy, PartialEq, Eq)]
283pub enum SqlLikeEscape {
284 Character(char),
285 Disabled,
286}
287
288#[derive(Debug, Clone, Copy, PartialEq, Eq)]
289pub enum SqlComparisonOp {
290 Eq,
291 NotEq,
292 Lt,
293 Lte,
294 Gt,
295 Gte,
296}
297
298impl std::fmt::Display for SqlValue {
299 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
300 match self {
301 Self::Literal(value) => write!(formatter, "{value}"),
302 Self::Parameter(position) => write!(formatter, "${position}"),
303 Self::Expression(expression) => write!(formatter, "{:?}", expression.kind),
304 }
305 }
306}