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