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