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