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