Skip to main content

tank_core/writer/
sql_writer.rs

1use crate::{
2    Action, BinaryOp, BinaryOpType, ColumnDef, ColumnRef, Dataset, DynQuery, EitherIterator,
3    Entity, Expression, Fragment, Interval, IsTrue, Join, JoinType, Operand, Order, Ordered,
4    PrimaryKeyType, SelectQuery, TableRef, UnaryOp, UnaryOpType, Value, possibly_parenthesized,
5    separated_by, write_escaped, writer::Context,
6};
7use core::f64;
8use std::{
9    collections::{BTreeMap, HashMap},
10    fmt::Write,
11    mem,
12};
13use time::{Date, OffsetDateTime, PrimitiveDateTime, Time};
14use uuid::Uuid;
15
16macro_rules! write_integer_fn {
17    ($fn_name:ident, $ty:ty) => {
18        fn $fn_name(&self, context: &mut Context, out: &mut DynQuery, value: $ty) {
19            if context.fragment == Fragment::JsonKey {
20                out.push('"');
21            }
22            let mut buffer = itoa::Buffer::new();
23            out.push_str(buffer.format(value));
24            if context.fragment == Fragment::JsonKey {
25                out.push('"');
26            }
27        }
28    };
29}
30
31macro_rules! write_float_fn {
32    ($fn_name:ident, $ty:ty) => {
33        fn $fn_name(&self, context: &mut Context, out: &mut DynQuery, value: $ty) {
34            let mut buffer = ryu::Buffer::new();
35            if value.is_infinite() {
36                self.write_binary_op(
37                    context,
38                    out,
39                    &BinaryOp {
40                        op: BinaryOpType::Cast,
41                        lhs: &Operand::LitStr(buffer.format(if value.is_sign_negative() {
42                            f64::NEG_INFINITY
43                        } else {
44                            f64::INFINITY
45                        })),
46                        rhs: &Operand::Type(Value::Float64(None)),
47                    },
48                );
49            } else if value.is_nan() {
50                self.write_binary_op(
51                    context,
52                    out,
53                    &BinaryOp {
54                        op: BinaryOpType::Cast,
55                        lhs: &Operand::LitStr(buffer.format(f64::NAN)),
56                        rhs: &Operand::Type(Value::Float64(None)),
57                    },
58                );
59            } else {
60                if context.fragment == Fragment::JsonKey {
61                    out.push('"');
62                }
63                out.push_str(buffer.format(value));
64                if context.fragment == Fragment::JsonKey {
65                    out.push('"');
66                }
67            }
68        }
69    };
70}
71
72/// SQL dialect printer.
73pub trait SqlWriter: Send {
74    /// Upcasts self to a distinct dynamic object.
75    fn as_dyn(&self) -> &dyn SqlWriter;
76
77    /// Separator used for qualified names (e.g., schema.table.column)
78    fn separator(&self) -> &str {
79        "."
80    }
81
82    /// Determines if the current SQL context supports alias declarations.
83    fn is_alias_declaration(&self, context: &mut Context) -> bool {
84        match context.fragment {
85            Fragment::SqlSelectFrom | Fragment::SqlJoin => true,
86            _ => false,
87        }
88    }
89
90    /// Writes an identifier (like a table or column name) to the query builder, optionally quoting it.
91    fn write_identifier(
92        &self,
93        _context: &mut Context,
94        out: &mut DynQuery,
95        value: &str,
96        quoted: bool,
97    ) {
98        if quoted {
99            out.push('"');
100            write_escaped(out, value, '"', "\"\"");
101            out.push('"');
102        } else {
103            out.push_str(value);
104        }
105    }
106
107    /// Write table reference.
108    fn write_table_ref(&self, context: &mut Context, out: &mut DynQuery, value: &TableRef) {
109        if self.is_alias_declaration(context) || value.alias.is_empty() {
110            if !value.schema.is_empty() {
111                self.write_identifier(context, out, &value.schema, context.quote_identifiers);
112                out.push_str(self.separator());
113            }
114            self.write_identifier(context, out, &value.name, context.quote_identifiers);
115        }
116        if !value.alias.is_empty() {
117            let _ = write!(out, " {}", value.alias);
118        }
119    }
120
121    /// Write column reference.
122    fn write_column_ref(&self, context: &mut Context, out: &mut DynQuery, value: &ColumnRef) {
123        if context.qualify_columns {
124            let table_ref = mem::take(&mut context.table_ref);
125            let mut schema = &table_ref.schema;
126            if schema.is_empty() {
127                schema = &value.schema;
128            }
129            let mut table = &table_ref.alias;
130            if table.is_empty() {
131                table = &table_ref.name;
132            }
133            if table.is_empty() {
134                table = &value.table;
135            }
136            if !table.is_empty() {
137                if !schema.is_empty() {
138                    self.write_identifier(context, out, schema, context.quote_identifiers);
139                    out.push_str(self.separator());
140                }
141                self.write_identifier(context, out, table, context.quote_identifiers);
142                out.push_str(self.separator());
143            }
144            context.table_ref = table_ref
145        }
146        self.write_identifier(context, out, &value.name, context.quote_identifiers);
147    }
148
149    /// Write overridden type.
150    fn write_column_overridden_type(
151        &self,
152        _context: &mut Context,
153        out: &mut DynQuery,
154        _column: &ColumnDef,
155        types: &BTreeMap<&'static str, &'static str>,
156    ) {
157        if let Some(t) = types
158            .iter()
159            .find_map(|(k, v)| if *k == "" { Some(v) } else { None })
160        {
161            out.push_str(t);
162        }
163    }
164
165    /// Write SQL type name.
166    fn write_column_type(&self, context: &mut Context, out: &mut DynQuery, value: &Value) {
167        match value {
168            Value::Boolean(..) => out.push_str("BOOLEAN"),
169            Value::Int8(..) => out.push_str("TINYINT"),
170            Value::Int16(..) => out.push_str("SMALLINT"),
171            Value::Int32(..) => out.push_str("INTEGER"),
172            Value::Int64(..) => out.push_str("BIGINT"),
173            Value::Int128(..) => out.push_str("HUGEINT"),
174            Value::UInt8(..) => out.push_str("UTINYINT"),
175            Value::UInt16(..) => out.push_str("USMALLINT"),
176            Value::UInt32(..) => out.push_str("UINTEGER"),
177            Value::UInt64(..) => out.push_str("UBIGINT"),
178            Value::UInt128(..) => out.push_str("UHUGEINT"),
179            Value::Float32(..) => out.push_str("FLOAT"),
180            Value::Float64(..) => out.push_str("DOUBLE"),
181            Value::Decimal(.., precision, scale) => {
182                out.push_str("DECIMAL");
183                if (precision, scale) != (&0, &0) {
184                    let _ = write!(out, "({precision},{scale})");
185                }
186            }
187            Value::Char(..) => out.push_str("CHAR(1)"),
188            Value::Varchar(..) => out.push_str("VARCHAR"),
189            Value::Blob(..) => out.push_str("BLOB"),
190            Value::Date(..) => out.push_str("DATE"),
191            Value::Time(..) => out.push_str("TIME"),
192            Value::Timestamp(..) => out.push_str("TIMESTAMP"),
193            Value::TimestampWithTimezone(..) => out.push_str("TIMESTAMPTZ"),
194            Value::Interval(..) => out.push_str("INTERVAL"),
195            Value::Uuid(..) => out.push_str("UUID"),
196            Value::Array(.., inner, size) => {
197                self.write_column_type(context, out, inner);
198                let _ = write!(out, "[{size}]");
199            }
200            Value::List(.., inner) => {
201                self.write_column_type(context, out, inner);
202                out.push_str("[]");
203            }
204            Value::Map(.., key, value) => {
205                out.push_str("MAP(");
206                self.write_column_type(context, out, key);
207                out.push(',');
208                self.write_column_type(context, out, value);
209                out.push(')');
210            }
211            Value::Json(..) => out.push_str("JSON"),
212            _ => log::error!("Unexpected tank::Value, variant {value:?} is not supported"),
213        };
214    }
215
216    /// Write value.
217    fn write_value(&self, context: &mut Context, out: &mut DynQuery, value: &Value) {
218        let delimiter = if context.fragment == Fragment::JsonKey {
219            "\""
220        } else {
221            ""
222        };
223        match value {
224            v if v.is_null() => self.write_null(context, out),
225            Value::Boolean(Some(v), ..) => self.write_bool(context, out, *v),
226            Value::Int8(Some(v), ..) => self.write_value_i8(context, out, *v),
227            Value::Int16(Some(v), ..) => self.write_value_i16(context, out, *v),
228            Value::Int32(Some(v), ..) => self.write_value_i32(context, out, *v),
229            Value::Int64(Some(v), ..) => self.write_value_i64(context, out, *v),
230            Value::Int128(Some(v), ..) => self.write_value_i128(context, out, *v),
231            Value::UInt8(Some(v), ..) => self.write_value_u8(context, out, *v),
232            Value::UInt16(Some(v), ..) => self.write_value_u16(context, out, *v),
233            Value::UInt32(Some(v), ..) => self.write_value_u32(context, out, *v),
234            Value::UInt64(Some(v), ..) => self.write_value_u64(context, out, *v),
235            Value::UInt128(Some(v), ..) => self.write_value_u128(context, out, *v),
236            Value::Float32(Some(v), ..) => self.write_value_f32(context, out, *v),
237            Value::Float64(Some(v), ..) => self.write_value_f64(context, out, *v),
238            Value::Decimal(Some(v), ..) => drop(write!(out, "{delimiter}{v}{delimiter}")),
239            Value::Char(Some(v), ..) => {
240                let mut buf = [0u8; 4];
241                self.write_string(context, out, v.encode_utf8(&mut buf));
242            }
243            Value::Varchar(Some(v), ..) => self.write_string(context, out, v),
244            Value::Blob(Some(v), ..) => self.write_blob(context, out, v.as_ref()),
245            Value::Date(Some(v), ..) => self.write_date(context, out, v),
246            Value::Time(Some(v), ..) => self.write_time(context, out, v),
247            Value::Timestamp(Some(v), ..) => self.write_timestamp(context, out, v),
248            Value::TimestampWithTimezone(Some(v), ..) => self.write_timestamptz(context, out, v),
249            Value::Interval(Some(v), ..) => self.write_interval(context, out, v),
250            Value::Uuid(Some(v), ..) => self.write_uuid(context, out, v),
251            Value::Array(Some(..), elem_ty, ..) | Value::List(Some(..), elem_ty, ..) => match value
252            {
253                Value::Array(Some(v), ..) => self.write_list(
254                    context,
255                    out,
256                    &mut v.iter().map(|v| v as &dyn Expression),
257                    Some(&*elem_ty),
258                    true,
259                ),
260                Value::List(Some(v), ..) => self.write_list(
261                    context,
262                    out,
263                    &mut v.iter().map(|v| v as &dyn Expression),
264                    Some(&*elem_ty),
265                    false,
266                ),
267                _ => unreachable!(),
268            },
269            Value::Map(Some(v), ..) => self.write_map(context, out, v),
270            Value::Json(Some(v), ..) => self.write_json(context, out, v),
271            Value::Struct(Some(v), ..) => self.write_struct(context, out, v),
272            _ => {
273                log::error!("Cannot write {value:?}");
274            }
275        };
276    }
277
278    fn write_null(&self, context: &mut Context, out: &mut DynQuery) {
279        out.push_str(if context.fragment == Fragment::Json {
280            "null"
281        } else {
282            "NULL"
283        });
284    }
285
286    fn write_bool(&self, context: &mut Context, out: &mut DynQuery, value: bool) {
287        if context.fragment == Fragment::JsonKey {
288            out.push('"');
289        }
290        out.push_str(["false", "true"][value as usize]);
291        if context.fragment == Fragment::JsonKey {
292            out.push('"');
293        }
294    }
295
296    write_integer_fn!(write_value_i8, i8);
297    write_integer_fn!(write_value_i16, i16);
298    write_integer_fn!(write_value_i32, i32);
299    write_integer_fn!(write_value_i64, i64);
300    write_integer_fn!(write_value_i128, i128);
301    write_integer_fn!(write_value_u8, u8);
302    write_integer_fn!(write_value_u16, u16);
303    write_integer_fn!(write_value_u32, u32);
304    write_integer_fn!(write_value_u64, u64);
305    write_integer_fn!(write_value_u128, u128);
306
307    write_float_fn!(write_value_f32, f32);
308    write_float_fn!(write_value_f64, f64);
309
310    fn write_string(&self, context: &mut Context, out: &mut DynQuery, value: &str) {
311        let (delimiter, escaped) = match context.fragment {
312            Fragment::None | Fragment::ParameterBinding => (None, ""),
313            Fragment::Json | Fragment::JsonKey => (Some('"'), r#"\""#),
314            _ => (Some('\''), "''"),
315        };
316        if let Some(delimiter) = delimiter {
317            out.push(delimiter);
318            let mut pos = 0;
319            for (i, c) in value.char_indices() {
320                if c == delimiter {
321                    out.push_str(&value[pos..i]);
322                    out.push_str(escaped);
323                    pos = i + 1;
324                } else if c == '\n' {
325                    out.push_str(&value[pos..i]);
326                    out.push_str("\\n");
327                    pos = i + 1;
328                }
329            }
330            out.push_str(&value[pos..]);
331            out.push(delimiter);
332        } else {
333            out.push_str(value);
334        }
335    }
336
337    fn write_blob(&self, context: &mut Context, out: &mut DynQuery, value: &[u8]) {
338        let delimiter = match context.fragment {
339            Fragment::None | Fragment::ParameterBinding => "",
340            Fragment::Json | Fragment::JsonKey => "\"",
341            _ => "'",
342        };
343        out.push_str(delimiter);
344        for v in value {
345            let _ = write!(out, "\\x{:02X}", v);
346        }
347        out.push_str(delimiter);
348    }
349
350    fn write_date(&self, context: &mut Context, out: &mut DynQuery, value: &Date) {
351        let d = match context.fragment {
352            Fragment::None | Fragment::ParameterBinding | Fragment::Timestamp => "",
353            Fragment::Json | Fragment::JsonKey => "\"",
354            _ => "'",
355        };
356        let year = value.year();
357        let month = value.month() as u8;
358        let day = value.day();
359        let _ = write!(out, "{d}{year:04}-{month:02}-{day:02}{d}");
360    }
361
362    fn write_time(&self, context: &mut Context, out: &mut DynQuery, value: &Time) {
363        let d = match context.fragment {
364            Fragment::None | Fragment::ParameterBinding | Fragment::Timestamp => "",
365            Fragment::Json | Fragment::JsonKey => "\"",
366            _ => "'",
367        };
368        let (h, m, s, ns) = value.as_hms_nano();
369        let mut subsecond = ns;
370        let mut width = 9;
371        while width > 1 && subsecond % 10 == 0 {
372            subsecond /= 10;
373            width -= 1;
374        }
375        let _ = write!(out, "{d}{h:02}:{m:02}:{s:02}.{subsecond:0width$}{d}");
376    }
377
378    fn write_timestamp(
379        &self,
380        context: &mut Context,
381        out: &mut DynQuery,
382        value: &PrimitiveDateTime,
383    ) {
384        let d = match context.fragment {
385            Fragment::None | Fragment::ParameterBinding | Fragment::Timestamp => "",
386            Fragment::Json | Fragment::JsonKey => "\"",
387            _ => "'",
388        };
389        let mut context = context.switch_fragment(Fragment::Timestamp);
390        out.push_str(d);
391        self.write_date(&mut context.current, out, &value.date());
392        out.push(' ');
393        self.write_time(&mut context.current, out, &value.time());
394        out.push_str(d);
395    }
396
397    fn write_timestamptz(&self, context: &mut Context, out: &mut DynQuery, value: &OffsetDateTime) {
398        let d = match context.fragment {
399            Fragment::None | Fragment::ParameterBinding => "",
400            Fragment::Json | Fragment::JsonKey => "\"",
401            _ => "'",
402        };
403        let mut context = context.switch_fragment(Fragment::Timestamp);
404        out.push_str(d);
405        self.write_timestamp(
406            &mut context.current,
407            out,
408            &PrimitiveDateTime::new(value.date(), value.time()),
409        );
410        let (h, m, s) = value.offset().as_hms();
411        if h != 0 || m != 0 || s != 0 {
412            out.push(if h >= 0 { '+' } else { '-' });
413            let _ = write!(out, "{h:02}");
414            if m != 0 || s != 0 {
415                let _ = write!(out, ":{m:02}");
416                if s != 0 {
417                    let _ = write!(out, ":{s:02}");
418                }
419            }
420        }
421        out.push_str(d);
422    }
423
424    /// Units used to decompose intervals (notice the decreasing order).
425    fn value_interval_units(&self) -> &[(&str, i128)] {
426        static UNITS: &[(&str, i128)] = &[
427            ("DAY", Interval::NANOS_IN_DAY),
428            ("HOUR", Interval::NANOS_IN_SEC * 3600),
429            ("MINUTE", Interval::NANOS_IN_SEC * 60),
430            ("SECOND", Interval::NANOS_IN_SEC),
431            ("MICROSECOND", 1_000),
432            ("NANOSECOND", 1),
433        ];
434        UNITS
435    }
436
437    fn write_interval(&self, context: &mut Context, out: &mut DynQuery, value: &Interval) {
438        out.push_str("INTERVAL ");
439        let d = match context.fragment {
440            Fragment::None => "",
441            Fragment::Json | Fragment::JsonKey => "\"",
442            _ => "'",
443        };
444        out.push_str(d);
445        if value.is_zero() {
446            out.push_str("0 SECONDS");
447        }
448        macro_rules! write_unit {
449            ($out:ident, $len:ident, $val:expr, $unit:expr) => {
450                if $out.len() > $len {
451                    $out.push(' ');
452                    $len = $out.len();
453                }
454                let _ = write!(
455                    $out,
456                    "{} {}{}",
457                    $val,
458                    $unit,
459                    if $val != 1 { "S" } else { "" }
460                );
461            };
462        }
463        let mut months = value.months;
464        let mut nanos = value.nanos + value.days as i128 * Interval::NANOS_IN_DAY;
465        let mut len = out.len();
466        if months != 0 {
467            if months > 48 || months % 12 == 0 {
468                write_unit!(out, len, months / 12, "YEAR");
469                months = months % 12;
470            }
471            if months != 0 {
472                write_unit!(out, len, months, "MONTH");
473            }
474        }
475        for &(name, factor) in self.value_interval_units() {
476            let rem = nanos % factor;
477            if rem == 0 || factor / rem > 1_000_000 {
478                let value = nanos / factor;
479                if value != 0 {
480                    write_unit!(out, len, value, name);
481                    nanos = rem;
482                    if nanos == 0 {
483                        break;
484                    }
485                }
486            }
487        }
488        out.push_str(d);
489    }
490
491    fn write_uuid(&self, context: &mut Context, out: &mut DynQuery, value: &Uuid) {
492        let d = match context.fragment {
493            Fragment::None => "",
494            Fragment::Json | Fragment::JsonKey => "\"",
495            _ => "'",
496        };
497        let _ = write!(out, "{d}{value}{d}");
498    }
499
500    fn write_list(
501        &self,
502        context: &mut Context,
503        out: &mut DynQuery,
504        value: &mut dyn Iterator<Item = &dyn Expression>,
505        _ty: Option<&Value>,
506        _is_array: bool,
507    ) {
508        out.push('[');
509        separated_by(
510            out,
511            value,
512            |out, v| {
513                v.write_query(self.as_dyn(), context, out);
514            },
515            ",",
516        );
517        out.push(']');
518    }
519
520    fn write_tuple(
521        &self,
522        context: &mut Context,
523        out: &mut DynQuery,
524        value: &mut dyn Iterator<Item = &dyn Expression>,
525    ) {
526        out.push('(');
527        separated_by(
528            out,
529            value,
530            |out, v| {
531                v.write_query(self.as_dyn(), context, out);
532            },
533            ",",
534        );
535        out.push(')');
536    }
537
538    fn write_map(&self, context: &mut Context, out: &mut DynQuery, value: &HashMap<Value, Value>) {
539        out.push('{');
540        separated_by(
541            out,
542            value,
543            |out, (k, v)| {
544                self.write_value(context, out, k);
545                out.push(':');
546                self.write_value(context, out, v);
547            },
548            ",",
549        );
550        out.push('}');
551    }
552
553    fn write_json(&self, context: &mut Context, out: &mut DynQuery, value: &serde_json::Value) {
554        self.write_string(context, out, &value.to_string());
555    }
556
557    fn write_struct(
558        &self,
559        context: &mut Context,
560        out: &mut DynQuery,
561        value: &Vec<(String, Value)>,
562    ) {
563        out.push('{');
564        separated_by(
565            out,
566            value,
567            |out, (k, v)| {
568                self.write_string(context, out, k);
569                out.push(':');
570                self.write_value(context, out, v);
571            },
572            ",",
573        );
574        out.push('}');
575    }
576
577    fn write_function(
578        &self,
579        context: &mut Context,
580        out: &mut DynQuery,
581        function: &str,
582        args: &[&dyn Expression],
583    ) {
584        out.push_str(function);
585        out.push('(');
586        separated_by(
587            out,
588            args,
589            |out, expr| {
590                expr.write_query(self.as_dyn(), context, out);
591            },
592            ",",
593        );
594        out.push(')');
595    }
596
597    /// Precedence table for unary operators.
598    fn expression_unary_op_precedence(&self, value: &UnaryOpType) -> i32 {
599        match value {
600            UnaryOpType::Negative => 1250,
601            UnaryOpType::Not => 250,
602        }
603    }
604
605    /// Precedence table for binary operators.
606    fn expression_binary_op_precedence(&self, value: &BinaryOpType) -> i32 {
607        match value {
608            BinaryOpType::Or => 100,
609            BinaryOpType::And => 200,
610            BinaryOpType::Equal => 300,
611            BinaryOpType::NotEqual => 300,
612            BinaryOpType::Less => 300,
613            BinaryOpType::Greater => 300,
614            BinaryOpType::LessEqual => 300,
615            BinaryOpType::GreaterEqual => 300,
616            BinaryOpType::In => 400,
617            BinaryOpType::NotIn => 400,
618            BinaryOpType::Is => 400,
619            BinaryOpType::IsNot => 400,
620            BinaryOpType::Like => 400,
621            BinaryOpType::NotLike => 400,
622            BinaryOpType::Regexp => 400,
623            BinaryOpType::NotRegexp => 400,
624            BinaryOpType::Glob => 400,
625            BinaryOpType::NotGlob => 400,
626            BinaryOpType::BitwiseOr => 500,
627            BinaryOpType::BitwiseAnd => 600,
628            BinaryOpType::ShiftLeft => 700,
629            BinaryOpType::ShiftRight => 700,
630            BinaryOpType::Subtraction => 800,
631            BinaryOpType::Addition => 800,
632            BinaryOpType::Multiplication => 900,
633            BinaryOpType::Division => 900,
634            BinaryOpType::Remainder => 900,
635            BinaryOpType::Indexing => 1000,
636            BinaryOpType::Cast => 1100,
637            BinaryOpType::Alias => 1200,
638        }
639    }
640
641    fn write_operand(&self, context: &mut Context, out: &mut DynQuery, value: &Operand) {
642        match value {
643            Operand::Null => self.write_null(context, out),
644            Operand::LitBool(v) => self.write_bool(context, out, *v),
645            Operand::LitInt(v) => self.write_value_i128(context, out, *v),
646            Operand::LitFloat(v) => self.write_value_f64(context, out, *v),
647            Operand::LitStr(v) => self.write_string(context, out, v),
648            Operand::LitIdent(v) => {
649                self.write_identifier(context, out, v, context.fragment == Fragment::Aliasing)
650            }
651            Operand::LitField(v) => {
652                self.write_identifier(context, out, &v.join(self.separator()), false)
653            }
654            Operand::LitList(v) => self.write_list(
655                context,
656                out,
657                &mut v.iter().map(|v| v as &dyn Expression),
658                None,
659                false,
660            ),
661            Operand::LitTuple(v) => {
662                self.write_tuple(context, out, &mut v.iter().map(|v| v as &dyn Expression))
663            }
664            Operand::Type(v) => self.write_column_type(context, out, v),
665            Operand::Variable(v) => self.write_value(context, out, v),
666            Operand::Value(v) => self.write_value(context, out, v),
667            Operand::Call(f, args) => self.write_function(context, out, f, args),
668            Operand::Asterisk => drop(out.push('*')),
669            Operand::QuestionMark => self.write_question_mark(context, out),
670            Operand::CurrentTimestampMs => self.write_current_timestamp_ms(context, out),
671        };
672    }
673
674    fn write_question_mark(&self, context: &mut Context, out: &mut DynQuery) {
675        context.counter += 1;
676        out.push('?');
677    }
678
679    fn write_current_timestamp_ms(&self, _context: &mut Context, out: &mut DynQuery) {
680        out.push_str("NOW()");
681    }
682
683    fn write_unary_op(
684        &self,
685        context: &mut Context,
686        out: &mut DynQuery,
687        value: &UnaryOp<&dyn Expression>,
688    ) {
689        match value.op {
690            UnaryOpType::Negative => out.push('-'),
691            UnaryOpType::Not => out.push_str("NOT "),
692        };
693        possibly_parenthesized!(
694            out,
695            value.arg.precedence(self.as_dyn()) <= self.expression_unary_op_precedence(&value.op),
696            value.arg.write_query(self.as_dyn(), context, out)
697        );
698    }
699
700    /// Render binary operator expression handling precedence and parenthesis.
701    fn write_binary_op(
702        &self,
703        context: &mut Context,
704        out: &mut DynQuery,
705        value: &BinaryOp<&dyn Expression, &dyn Expression>,
706    ) {
707        let (prefix, infix, suffix, lhs_parenthesized, rhs_parenthesized) = match value.op {
708            BinaryOpType::Indexing => ("", "[", "]", false, true),
709            BinaryOpType::Cast => {
710                return self.write_cast(context, out, value.lhs, value.rhs);
711            }
712            BinaryOpType::Multiplication => ("", " * ", "", false, false),
713            BinaryOpType::Division => ("", " / ", "", false, false),
714            BinaryOpType::Remainder => ("", " % ", "", false, false),
715            BinaryOpType::Addition => ("", " + ", "", false, false),
716            BinaryOpType::Subtraction => ("", " - ", "", false, false),
717            BinaryOpType::ShiftLeft => ("", " << ", "", false, false),
718            BinaryOpType::ShiftRight => ("", " >> ", "", false, false),
719            BinaryOpType::BitwiseAnd => ("", " & ", "", false, false),
720            BinaryOpType::BitwiseOr => ("", " | ", "", false, false),
721            BinaryOpType::In => ("", " IN ", "", false, false),
722            BinaryOpType::NotIn => ("", " NOT IN ", "", false, false),
723            BinaryOpType::Is => ("", " IS ", "", false, false),
724            BinaryOpType::IsNot => ("", " IS NOT ", "", false, false),
725            BinaryOpType::Like => ("", " LIKE ", "", false, false),
726            BinaryOpType::NotLike => ("", " NOT LIKE ", "", false, false),
727            BinaryOpType::Regexp => ("", " REGEXP ", "", false, false),
728            BinaryOpType::NotRegexp => ("", " NOT REGEXP ", "", false, false),
729            BinaryOpType::Glob => ("", " GLOB ", "", false, false),
730            BinaryOpType::NotGlob => ("", " NOT GLOB ", "", false, false),
731            BinaryOpType::Equal => ("", " = ", "", false, false),
732            BinaryOpType::NotEqual => ("", " != ", "", false, false),
733            BinaryOpType::Less => ("", " < ", "", false, false),
734            BinaryOpType::LessEqual => ("", " <= ", "", false, false),
735            BinaryOpType::Greater => ("", " > ", "", false, false),
736            BinaryOpType::GreaterEqual => ("", " >= ", "", false, false),
737            BinaryOpType::And => ("", " AND ", "", false, false),
738            BinaryOpType::Or => ("", " OR ", "", false, false),
739            BinaryOpType::Alias => {
740                if context.fragment == Fragment::SqlSelectOrderBy {
741                    return value.lhs.write_query(self.as_dyn(), context, out);
742                } else {
743                    ("", " AS ", "", false, false)
744                }
745            }
746        };
747        let precedence = self.expression_binary_op_precedence(&value.op);
748        out.push_str(prefix);
749        possibly_parenthesized!(
750            out,
751            !lhs_parenthesized && value.lhs.precedence(self.as_dyn()) < precedence,
752            value.lhs.write_query(self.as_dyn(), context, out)
753        );
754        out.push_str(infix);
755        let mut context = context.switch_fragment(if value.op == BinaryOpType::Alias {
756            Fragment::Aliasing
757        } else {
758            context.fragment
759        });
760        possibly_parenthesized!(
761            out,
762            !rhs_parenthesized && value.rhs.precedence(self.as_dyn()) <= precedence,
763            value
764                .rhs
765                .write_query(self.as_dyn(), &mut context.current, out)
766        );
767        out.push_str(suffix);
768    }
769
770    fn write_cast(
771        &self,
772        context: &mut Context,
773        out: &mut DynQuery,
774        expr: &dyn Expression,
775        ty: &dyn Expression,
776    ) {
777        let mut context = context.switch_fragment(Fragment::Casting);
778        out.push_str("CAST(");
779        expr.write_query(self.as_dyn(), &mut context.current, out);
780        out.push_str(" AS ");
781        ty.write_query(self.as_dyn(), &mut context.current, out);
782        out.push(')');
783    }
784
785    /// Render ordered expression inside ORDER BY.
786    fn write_ordered(
787        &self,
788        context: &mut Context,
789        out: &mut DynQuery,
790        value: &Ordered<&dyn Expression>,
791    ) {
792        value.expression.write_query(self.as_dyn(), context, out);
793        if context.fragment == Fragment::SqlSelectOrderBy {
794            let _ = write!(
795                out,
796                " {}",
797                match value.order {
798                    Order::ASC => "ASC",
799                    Order::DESC => "DESC",
800                }
801            );
802        }
803    }
804
805    /// Render join keyword(s) for the given join type.
806    fn write_join_type(&self, _context: &mut Context, out: &mut DynQuery, join_type: &JoinType) {
807        out.push_str(match &join_type {
808            JoinType::Default => "JOIN",
809            JoinType::Inner => "INNER JOIN",
810            JoinType::Outer => "OUTER JOIN",
811            JoinType::Left => "LEFT JOIN",
812            JoinType::Right => "RIGHT JOIN",
813            JoinType::Cross => "CROSS JOIN",
814            JoinType::Natural => "NATURAL JOIN",
815        });
816    }
817
818    /// Render a JOIN clause.
819    fn write_join(
820        &self,
821        context: &mut Context,
822        out: &mut DynQuery,
823        join: &Join<&dyn Dataset, &dyn Dataset, &dyn Expression>,
824    ) {
825        let mut context = context.switch_fragment(Fragment::SqlJoin);
826        context.current.qualify_columns = true;
827        join.lhs
828            .write_query(self.as_dyn(), &mut context.current, out);
829        out.push(' ');
830        self.write_join_type(&mut context.current, out, &join.join);
831        out.push(' ');
832        join.rhs
833            .write_query(self.as_dyn(), &mut context.current, out);
834        if let Some(on) = &join.on {
835            out.push_str(" ON ");
836            on.write_query(self.as_dyn(), &mut context.current, out);
837        }
838    }
839
840    /// Emit BEGIN statement.
841    fn write_transaction_begin(&self, out: &mut DynQuery) {
842        out.push_str("BEGIN;");
843    }
844
845    /// Emit COMMIT statement.
846    fn write_transaction_commit(&self, out: &mut DynQuery) {
847        out.push_str("COMMIT;");
848    }
849
850    /// Emit ROLLBACK statement.
851    fn write_transaction_rollback(&self, out: &mut DynQuery) {
852        out.push_str("ROLLBACK;");
853    }
854
855    /// Emit CREATE SCHEMA.
856    fn write_create_schema<E>(&self, out: &mut DynQuery, if_not_exists: bool)
857    where
858        Self: Sized,
859        E: Entity,
860    {
861        let table = E::table();
862        out.buffer().reserve(32 + table.schema.len());
863        if !out.is_empty() {
864            out.push('\n');
865        }
866        out.push_str("CREATE SCHEMA ");
867        let mut context = Context::new(Fragment::SqlCreateSchema, E::qualified_columns());
868        if if_not_exists {
869            out.push_str("IF NOT EXISTS ");
870        }
871        self.write_identifier(&mut context, out, &table.schema, true);
872        out.push(';');
873    }
874
875    /// Emit DROP SCHEMA.
876    fn write_drop_schema<E>(&self, out: &mut DynQuery, if_exists: bool)
877    where
878        Self: Sized,
879        E: Entity,
880    {
881        let mut context = Context::new(Fragment::SqlDropSchema, E::qualified_columns());
882        let table = E::table();
883        out.buffer().reserve(32 + table.schema.len());
884        if !out.is_empty() {
885            out.push('\n');
886        }
887        out.push_str("DROP SCHEMA ");
888        if if_exists {
889            out.push_str("IF EXISTS ");
890        }
891        self.write_identifier(&mut context, out, &table.schema, true);
892        out.push(';');
893    }
894
895    /// Emit CREATE TABLE with columns, constraints & comments.
896    fn write_create_table<E>(&self, out: &mut DynQuery, if_not_exists: bool)
897    where
898        Self: Sized,
899        E: Entity,
900    {
901        let mut context = Context::new(Fragment::SqlCreateTable, E::qualified_columns());
902        let table = E::table();
903        let estimated = 128 + E::columns().len() * 64 + E::primary_key_def().len() * 24;
904        out.buffer().reserve(estimated);
905        if !out.is_empty() {
906            out.push('\n');
907        }
908        out.push_str("CREATE TABLE ");
909        if if_not_exists {
910            out.push_str("IF NOT EXISTS ");
911        }
912        self.write_table_ref(&mut context, out, table);
913        out.push_str(" (\n");
914        separated_by(
915            out,
916            E::columns(),
917            |out, col| {
918                self.write_create_table_column_fragment(&mut context, out, col);
919            },
920            ",\n",
921        );
922        let pk = E::primary_key_def();
923        if pk.len() > 1 {
924            self.write_create_table_primary_key_fragment(&mut context, out, pk.iter().map(|v| *v));
925        }
926        for unique in E::unique_defs() {
927            if unique.len() > 1 {
928                out.push_str(",\nUNIQUE (");
929                separated_by(
930                    out,
931                    unique,
932                    |out, col| {
933                        self.write_identifier(
934                            &mut context
935                                .switch_fragment(Fragment::SqlCreateTableUnique)
936                                .current,
937                            out,
938                            col.name(),
939                            true,
940                        );
941                    },
942                    ", ",
943                );
944                out.push(')');
945            }
946        }
947        let foreign_keys = E::columns().iter().filter(|c| c.references.is_some());
948        separated_by(
949            out,
950            foreign_keys,
951            |out, column| {
952                let references = column.references.as_ref().unwrap();
953                out.push_str(",\nFOREIGN KEY (");
954                self.write_identifier(&mut context, out, &column.name(), true);
955                out.push_str(") REFERENCES ");
956                self.write_table_ref(&mut context, out, &references.table());
957                out.push('(');
958                self.write_column_ref(&mut context, out, references);
959                out.push(')');
960                if let Some(on_delete) = &column.on_delete {
961                    out.push_str(" ON DELETE ");
962                    self.write_create_table_references_action(&mut context, out, on_delete);
963                }
964                if let Some(on_update) = &column.on_update {
965                    out.push_str(" ON UPDATE ");
966                    self.write_create_table_references_action(&mut context, out, on_update);
967                }
968            },
969            "",
970        );
971        out.push_str(");");
972        self.write_column_comments_statements::<E>(&mut context, out);
973    }
974
975    /// Emit single column definition fragment.
976    fn write_create_table_column_fragment(
977        &self,
978        context: &mut Context,
979        out: &mut DynQuery,
980        column: &ColumnDef,
981    ) where
982        Self: Sized,
983    {
984        self.write_identifier(context, out, &column.name(), true);
985        out.push(' ');
986        let len = out.len();
987        self.write_column_overridden_type(context, out, column, &column.column_type);
988        let didnt_write_type = out.len() == len;
989        if didnt_write_type {
990            SqlWriter::write_column_type(self, context, out, &column.value);
991        }
992        if !column.nullable && column.primary_key == PrimaryKeyType::None {
993            out.push_str(" NOT NULL");
994        }
995        if column.default.is_set() {
996            out.push_str(" DEFAULT ");
997            column.default.write_query(self.as_dyn(), context, out);
998        }
999        if column.primary_key == PrimaryKeyType::PrimaryKey {
1000            // Composite primary key will be printed elsewhere
1001            out.push_str(" PRIMARY KEY");
1002        }
1003        if column.unique && column.primary_key != PrimaryKeyType::PrimaryKey {
1004            out.push_str(" UNIQUE");
1005        }
1006        if !column.comment.is_empty() {
1007            self.write_column_comment_inline(context, out, column);
1008        }
1009    }
1010
1011    /// Write PRIMARY KEY constraint.
1012    fn write_create_table_primary_key_fragment<'a, It>(
1013        &self,
1014        context: &mut Context,
1015        out: &mut DynQuery,
1016        primary_key: It,
1017    ) where
1018        Self: Sized,
1019        It: IntoIterator<Item = &'a ColumnDef>,
1020        It::IntoIter: Clone,
1021    {
1022        out.push_str(",\nPRIMARY KEY (");
1023        separated_by(
1024            out,
1025            primary_key,
1026            |out, col| {
1027                self.write_identifier(
1028                    &mut context
1029                        .switch_fragment(Fragment::SqlCreateTablePrimaryKey)
1030                        .current,
1031                    out,
1032                    col.name(),
1033                    true,
1034                );
1035            },
1036            ", ",
1037        );
1038        out.push(')');
1039    }
1040
1041    /// Write referential action.
1042    fn write_create_table_references_action(
1043        &self,
1044        _context: &mut Context,
1045        out: &mut DynQuery,
1046        action: &Action,
1047    ) {
1048        out.push_str(match action {
1049            Action::NoAction => "NO ACTION",
1050            Action::Restrict => "RESTRICT",
1051            Action::Cascade => "CASCADE",
1052            Action::SetNull => "SET NULL",
1053            Action::SetDefault => "SET DEFAULT",
1054        });
1055    }
1056
1057    fn write_column_comment_inline(
1058        &self,
1059        _context: &mut Context,
1060        _out: &mut DynQuery,
1061        _column: &ColumnDef,
1062    ) where
1063        Self: Sized,
1064    {
1065    }
1066
1067    /// Write column comments.
1068    fn write_column_comments_statements<E>(&self, context: &mut Context, out: &mut DynQuery)
1069    where
1070        Self: Sized,
1071        E: Entity,
1072    {
1073        let mut context = context.switch_fragment(Fragment::SqlCommentOnColumn);
1074        context.current.qualify_columns = true;
1075        for c in E::columns().iter().filter(|c| !c.comment.is_empty()) {
1076            out.push_str("\nCOMMENT ON COLUMN ");
1077            self.write_column_ref(&mut context.current, out, c.into());
1078            out.push_str(" IS ");
1079            self.write_string(&mut context.current, out, c.comment);
1080            out.push(';');
1081        }
1082    }
1083
1084    /// Write DROP TABLE statement.
1085    fn write_drop_table<E>(&self, out: &mut DynQuery, if_exists: bool)
1086    where
1087        Self: Sized,
1088        E: Entity,
1089    {
1090        let table = E::table();
1091        out.buffer()
1092            .reserve(24 + table.schema.len() + table.name.len());
1093        if !out.is_empty() {
1094            out.push('\n');
1095        }
1096        out.push_str("DROP TABLE ");
1097        let mut context = Context::new(Fragment::SqlDropTable, E::qualified_columns());
1098        if if_exists {
1099            out.push_str("IF EXISTS ");
1100        }
1101        self.write_table_ref(&mut context, out, table);
1102        out.push(';');
1103    }
1104
1105    /// Write SELECT statement.
1106    fn write_select<'a, Data>(&self, out: &mut DynQuery, query: &impl SelectQuery<Data>)
1107    where
1108        Self: Sized,
1109        Data: Dataset + 'a,
1110    {
1111        let Some(from) = query.get_from() else {
1112            log::error!("The query does not have the FROM clause");
1113            return;
1114        };
1115        let columns = query.get_select();
1116        let columns_count = columns.clone().into_iter().count();
1117        out.buffer().reserve(128 + columns_count * 32);
1118        if !out.is_empty() {
1119            out.push('\n');
1120        }
1121        out.push_str("SELECT ");
1122        let mut context = Context::new(Fragment::SqlSelect, Data::qualified_columns());
1123        if columns_count != 0 {
1124            separated_by(
1125                out,
1126                columns.clone(),
1127                |out, col| {
1128                    col.write_query(self, &mut context, out);
1129                },
1130                ", ",
1131            );
1132        } else {
1133            out.push('*');
1134        }
1135        out.push_str("\nFROM ");
1136        from.write_query(
1137            self,
1138            &mut context.switch_fragment(Fragment::SqlSelectFrom).current,
1139            out,
1140        );
1141        if let Some(condition) = query.get_where()
1142            && !condition.accept_visitor(&mut IsTrue, self, &mut context, out)
1143        {
1144            out.push_str("\nWHERE ");
1145            condition.write_query(
1146                self,
1147                &mut context.switch_fragment(Fragment::SqlSelectWhere).current,
1148                out,
1149            );
1150        }
1151        let mut group_by = query.get_group_by().peekable();
1152        if group_by.peek().is_some() {
1153            out.push_str("\nGROUP BY ");
1154            let mut context = context.switch_fragment(Fragment::SqlSelectGroupBy);
1155            separated_by(
1156                out,
1157                group_by,
1158                |out, col| {
1159                    col.write_query(self, &mut context.current, out);
1160                },
1161                ", ",
1162            );
1163        }
1164        if let Some(having) = query.get_having() {
1165            out.push_str("\nHAVING ");
1166            having.write_query(
1167                self,
1168                &mut context.switch_fragment(Fragment::SqlSelectWhere).current,
1169                out,
1170            );
1171        }
1172        let mut order_by = query.get_order_by().peekable();
1173        if order_by.peek().is_some() {
1174            out.push_str("\nORDER BY ");
1175            let mut context = context.switch_fragment(Fragment::SqlSelectOrderBy);
1176            separated_by(
1177                out,
1178                order_by,
1179                |out, col| {
1180                    col.write_query(self, &mut context.current, out);
1181                },
1182                ", ",
1183            );
1184        }
1185        if let Some(limit) = query.get_limit() {
1186            let _ = write!(out, "\nLIMIT {limit}");
1187        }
1188        out.push(';');
1189    }
1190
1191    /// Write INSERT statement.
1192    fn write_insert<'b, E>(
1193        &self,
1194        out: &mut DynQuery,
1195        entities: impl IntoIterator<Item = &'b E>,
1196        update: bool,
1197    ) where
1198        Self: Sized,
1199        E: Entity + 'b,
1200    {
1201        let table = E::table();
1202        let mut rows = entities.into_iter().map(Entity::row_filtered).peekable();
1203        let Some(mut row) = rows.next() else {
1204            return;
1205        };
1206        let single = rows.peek().is_none();
1207        let cols = E::columns().len();
1208        out.buffer().reserve(128 + cols * 32);
1209        if !out.is_empty() {
1210            out.push('\n');
1211        }
1212        out.push_str("INSERT INTO ");
1213        let mut context = Context::new(Fragment::SqlInsertInto, E::qualified_columns());
1214        self.write_table_ref(&mut context, out, table);
1215        out.push_str(" (");
1216        let columns = E::columns().iter();
1217        if single {
1218            // Inserting a single row uses row_labeled to filter out Passive::NotSet columns
1219            separated_by(
1220                out,
1221                row.iter(),
1222                |out, (name, ..)| {
1223                    self.write_identifier(&mut context, out, name, true);
1224                },
1225                ", ",
1226            );
1227        } else {
1228            separated_by(
1229                out,
1230                columns.clone(),
1231                |out, col| {
1232                    self.write_identifier(&mut context, out, col.name(), true);
1233                },
1234                ", ",
1235            );
1236        };
1237        out.push_str(") VALUES\n");
1238        let mut context = context.switch_fragment(Fragment::SqlInsertIntoValues);
1239        let mut first_row = None;
1240        let mut separate = false;
1241        loop {
1242            if separate {
1243                out.push_str(",\n");
1244            }
1245            out.push('(');
1246            let mut fields = row.iter();
1247            let mut field = fields.next();
1248            separated_by(
1249                out,
1250                E::columns(),
1251                |out, col| {
1252                    if Some(col.name()) == field.map(|v| v.0) {
1253                        self.write_value(
1254                            &mut context.current,
1255                            out,
1256                            field
1257                                .map(|v| &v.1)
1258                                .expect(&format!("Column {} does not have a value", col.name())),
1259                        );
1260                        field = fields.next();
1261                    } else if !single {
1262                        out.push_str("DEFAULT");
1263                    }
1264                },
1265                ", ",
1266            );
1267            out.push(')');
1268            separate = true;
1269            if first_row.is_none() {
1270                first_row = row.into();
1271            }
1272            if let Some(next) = rows.next() {
1273                row = next;
1274            } else {
1275                break;
1276            };
1277        }
1278        let first_row = first_row
1279            .expect("Should have at least one row")
1280            .into_iter()
1281            .map(|(v, _)| v);
1282        if update {
1283            self.write_insert_update_fragment::<E>(
1284                &mut context.current,
1285                out,
1286                if single {
1287                    EitherIterator::Left(
1288                        // If there is only one row to insert then list only the columns that appear
1289                        columns.filter(|c| first_row.clone().find(|n| *n == c.name()).is_some()),
1290                    )
1291                } else {
1292                    EitherIterator::Right(columns)
1293                },
1294            );
1295        }
1296        out.push(';');
1297    }
1298
1299    /// Write ON CONFLICT DO UPDATE fragment for upsert.
1300    fn write_insert_update_fragment<'a, E>(
1301        &self,
1302        context: &mut Context,
1303        out: &mut DynQuery,
1304        columns: impl Iterator<Item = &'a ColumnDef> + Clone,
1305    ) where
1306        Self: Sized,
1307        E: Entity,
1308    {
1309        let pk = E::primary_key_def();
1310        if pk.len() == 0 {
1311            return;
1312        }
1313        out.push_str("\nON CONFLICT");
1314        context.fragment = Fragment::SqlInsertIntoOnConflict;
1315        if pk.len() > 0 {
1316            out.push_str(" (");
1317            separated_by(
1318                out,
1319                pk,
1320                |out, col| {
1321                    self.write_identifier(context, out, col.name(), true);
1322                },
1323                ", ",
1324            );
1325            out.push(')');
1326        }
1327        let mut update_cols = columns
1328            .filter(|c| c.primary_key == PrimaryKeyType::None)
1329            .peekable();
1330        if update_cols.peek().is_some() {
1331            out.push_str(" DO UPDATE SET\n");
1332            separated_by(
1333                out,
1334                update_cols,
1335                |out, col| {
1336                    self.write_identifier(context, out, col.name(), true);
1337                    out.push_str(" = EXCLUDED.");
1338                    self.write_identifier(context, out, col.name(), true);
1339                },
1340                ",\n",
1341            );
1342        } else {
1343            out.push_str(" DO NOTHING");
1344        }
1345    }
1346
1347    /// Write DELETE statement.
1348    fn write_delete<E>(&self, out: &mut DynQuery, condition: impl Expression)
1349    where
1350        Self: Sized,
1351        E: Entity,
1352    {
1353        let table = E::table();
1354        out.buffer().reserve(128);
1355        if !out.is_empty() {
1356            out.push('\n');
1357        }
1358        out.push_str("DELETE FROM ");
1359        let mut context = Context::new(Fragment::SqlDeleteFrom, E::qualified_columns());
1360        self.write_table_ref(&mut context, out, table);
1361        out.push_str("\nWHERE ");
1362        condition.write_query(
1363            self,
1364            &mut context
1365                .switch_fragment(Fragment::SqlDeleteFromWhere)
1366                .current,
1367            out,
1368        );
1369        out.push(';');
1370    }
1371}
1372
1373/// Generic SQL writer.
1374pub struct GenericSqlWriter;
1375impl GenericSqlWriter {
1376    /// New generic writer.
1377    pub fn new() -> Self {
1378        Self {}
1379    }
1380}
1381impl SqlWriter for GenericSqlWriter {
1382    fn as_dyn(&self) -> &dyn SqlWriter {
1383        self
1384    }
1385}