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("TEXT"),
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.unsigned_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: &Context,
645 op_type: BinaryOpType,
646 ) -> (&str, &str, &str, bool, bool) {
647 match op_type {
648 BinaryOpType::Indexing => ("", "[", "]", false, true),
649 BinaryOpType::Cast => ("CAST(", " AS ", ")", true, true),
650 BinaryOpType::Multiplication => ("", " * ", "", false, false),
651 BinaryOpType::Division => ("", " / ", "", false, false),
652 BinaryOpType::Remainder => ("", " % ", "", false, false),
653 BinaryOpType::Addition => ("", " + ", "", false, false),
654 BinaryOpType::Subtraction => ("", " - ", "", false, false),
655 BinaryOpType::ShiftLeft => ("", " << ", "", false, false),
656 BinaryOpType::ShiftRight => ("", " >> ", "", false, false),
657 BinaryOpType::BitwiseAnd => ("", " & ", "", false, false),
658 BinaryOpType::BitwiseOr => ("", " | ", "", false, false),
659 BinaryOpType::In => ("", " IN ", "", false, false),
660 BinaryOpType::NotIn => ("", " NOT IN ", "", false, false),
661 BinaryOpType::Is => ("", " IS ", "", false, false),
662 BinaryOpType::IsNot => ("", " IS NOT ", "", false, false),
663 BinaryOpType::Like => ("", " LIKE ", "", false, false),
664 BinaryOpType::NotLike => ("", " NOT LIKE ", "", false, false),
665 BinaryOpType::Regexp => ("", " REGEXP ", "", false, false),
666 BinaryOpType::NotRegexp => ("", " NOT REGEXP ", "", false, false),
667 BinaryOpType::Glob => ("", " GLOB ", "", false, false),
668 BinaryOpType::NotGlob => ("", " NOT GLOB ", "", false, false),
669 BinaryOpType::Equal => ("", " = ", "", false, false),
670 BinaryOpType::NotEqual => ("", " != ", "", false, false),
671 BinaryOpType::Less => ("", " < ", "", false, false),
672 BinaryOpType::LessEqual => ("", " <= ", "", false, false),
673 BinaryOpType::Greater => ("", " > ", "", false, false),
674 BinaryOpType::GreaterEqual => ("", " >= ", "", false, false),
675 BinaryOpType::And => ("", " AND ", "", false, false),
676 BinaryOpType::Or => ("", " OR ", "", false, false),
677 BinaryOpType::Alias => ("", " AS ", "", false, false),
678 }
679 }
680
681 fn write_operand(&self, context: &mut Context, out: &mut DynQuery, value: &Operand) {
682 match value {
683 Operand::Null => self.write_null(context, out),
684 Operand::LitBool(v) => self.write_bool(context, out, *v),
685 Operand::LitInt(v) => self.write_value_i128(context, out, *v),
686 Operand::LitFloat(v) => self.write_value_f64(context, out, *v),
687 Operand::LitStr(v) => self.write_string(context, out, v),
688 Operand::LitIdent(v) => {
689 self.write_identifier(context, out, v, context.fragment == Fragment::Aliasing)
690 }
691 Operand::LitField(v) => {
692 let separator = self.separator();
693 for (i, part) in v.iter().enumerate() {
694 if i > 0 {
695 out.push_str(separator);
696 }
697 out.push_str(part);
698 }
699 }
700 Operand::LitList(v) => self.write_list(
701 context,
702 out,
703 &mut v.iter().map(|v| v as &dyn Expression),
704 None,
705 false,
706 ),
707 Operand::LitTuple(v) => {
708 self.write_tuple(context, out, &mut v.iter().map(|v| v as &dyn Expression))
709 }
710 Operand::Type(v) => self.write_column_type(context, out, v),
711 Operand::Variable(v) => self.write_value(context, out, v),
712 Operand::Value(v) => self.write_value(context, out, v),
713 Operand::Call(f, args) => self.write_function(context, out, f, args),
714 Operand::Asterisk => drop(out.push('*')),
715 Operand::QuestionMark => self.write_question_mark(context, out),
716 Operand::CurrentTimestampMs => self.write_current_timestamp_ms(context, out),
717 };
718 }
719
720 fn write_question_mark(&self, context: &mut Context, out: &mut DynQuery) {
721 context.counter += 1;
722 out.push('?');
723 }
724
725 fn write_current_timestamp_ms(&self, _context: &mut Context, out: &mut DynQuery) {
726 out.push_str("NOW()");
727 }
728
729 fn write_unary_op(
730 &self,
731 context: &mut Context,
732 out: &mut DynQuery,
733 value: &UnaryOp<&dyn Expression>,
734 ) {
735 match value.op {
736 UnaryOpType::Negative => out.push('-'),
737 UnaryOpType::Not => out.push_str("NOT "),
738 };
739 possibly_parenthesized!(
740 out,
741 value.arg.precedence(self.as_dyn()) <= self.expression_unary_op_precedence(&value.op),
742 value.arg.write_query(self.as_dyn(), context, out)
743 );
744 }
745
746 fn write_binary_op(
748 &self,
749 context: &mut Context,
750 out: &mut DynQuery,
751 value: &BinaryOp<&dyn Expression, &dyn Expression>,
752 ) {
753 if value.op == BinaryOpType::Alias
755 && matches!(
756 context.fragment,
757 Fragment::SqlSelectOrderBy | Fragment::SqlSelectGroupBy
758 )
759 {
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(match value.op {
773 BinaryOpType::Cast => Fragment::Casting,
774 BinaryOpType::Alias => Fragment::Aliasing,
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 if !out.is_empty() {
868 out.push('\n');
869 }
870 out.push_str("BEGIN;");
871 }
872
873 fn write_transaction_commit(&self, out: &mut DynQuery) {
875 if !out.is_empty() {
876 out.push('\n');
877 }
878 out.push_str("COMMIT;");
879 }
880
881 fn write_transaction_rollback(&self, out: &mut DynQuery) {
883 if !out.is_empty() {
884 out.push('\n');
885 }
886 out.push_str("ROLLBACK;");
887 }
888
889 fn write_create_schema<E>(&self, out: &mut DynQuery, if_not_exists: bool)
891 where
892 Self: Sized,
893 E: Entity,
894 {
895 let table = E::table();
896 out.buffer().reserve(32 + table.schema.len());
897 if !out.is_empty() {
898 out.push('\n');
899 }
900 out.push_str("CREATE SCHEMA ");
901 let mut context = Context::new(Fragment::SqlCreateSchema, E::qualified_columns());
902 if if_not_exists {
903 out.push_str("IF NOT EXISTS ");
904 }
905 self.write_identifier(&mut context, out, &table.schema, true);
906 out.push(';');
907 }
908
909 fn write_drop_schema<E>(&self, out: &mut DynQuery, if_exists: bool)
911 where
912 Self: Sized,
913 E: Entity,
914 {
915 let mut context = Context::new(Fragment::SqlDropSchema, E::qualified_columns());
916 let table = E::table();
917 out.buffer().reserve(32 + table.schema.len());
918 if !out.is_empty() {
919 out.push('\n');
920 }
921 out.push_str("DROP SCHEMA ");
922 if if_exists {
923 out.push_str("IF EXISTS ");
924 }
925 self.write_identifier(&mut context, out, &table.schema, true);
926 out.push(';');
927 }
928
929 fn write_create_table<E>(&self, out: &mut DynQuery, if_not_exists: bool)
931 where
932 Self: Sized,
933 E: Entity,
934 {
935 let mut context = Context::new(Fragment::SqlCreateTable, E::qualified_columns());
936 let table = E::table();
937 let estimated = 128 + E::columns().len() * 64 + E::primary_key_def().len() * 24;
938 out.buffer().reserve(estimated);
939 if !out.is_empty() {
940 out.push('\n');
941 }
942 out.push_str("CREATE TABLE ");
943 if if_not_exists {
944 out.push_str("IF NOT EXISTS ");
945 }
946 self.write_table_ref(&mut context, out, table);
947 out.push_str(" (\n");
948 separated_by(
949 out,
950 E::columns(),
951 |out, col| {
952 self.write_create_table_column_fragment(&mut context, out, col);
953 },
954 ",\n",
955 );
956 let pk = E::primary_key_def();
957 if pk.len() > 1 {
958 self.write_create_table_primary_key_fragment(&mut context, out, pk.iter().map(|v| *v));
959 }
960 for unique in E::unique_defs() {
961 if unique.len() > 0 {
962 out.push_str(",\nUNIQUE (");
963 separated_by(
964 out,
965 unique,
966 |out, col| {
967 self.write_identifier(
968 &mut context
969 .switch_fragment(Fragment::SqlCreateTableUnique)
970 .current,
971 out,
972 col.name(),
973 true,
974 );
975 },
976 ", ",
977 );
978 out.push(')');
979 }
980 }
981 let foreign_keys = E::columns().iter().filter(|c| c.references.is_some());
982 separated_by(
983 out,
984 foreign_keys,
985 |out, column| {
986 let references = column.references.as_ref().unwrap();
987 out.push_str(",\nFOREIGN KEY (");
988 self.write_identifier(&mut context, out, &column.name(), true);
989 out.push_str(") REFERENCES ");
990 self.write_table_ref(&mut context, out, &references.table());
991 out.push('(');
992 self.write_column_ref(&mut context, out, references);
993 out.push(')');
994 if let Some(on_delete) = &column.on_delete {
995 out.push_str(" ON DELETE ");
996 self.write_create_table_references_action(&mut context, out, on_delete);
997 }
998 if let Some(on_update) = &column.on_update {
999 out.push_str(" ON UPDATE ");
1000 self.write_create_table_references_action(&mut context, out, on_update);
1001 }
1002 },
1003 "",
1004 );
1005 out.push_str(");");
1006 }
1007
1008 fn write_create_table_column_fragment(
1010 &self,
1011 context: &mut Context,
1012 out: &mut DynQuery,
1013 column: &ColumnDef,
1014 ) where
1015 Self: Sized,
1016 {
1017 self.write_identifier(context, out, &column.name(), true);
1018 out.push(' ');
1019 let len = out.len();
1020 self.write_column_overridden_type(context, out, column, &column.column_type);
1021 let didnt_write_type = out.len() == len;
1022 if didnt_write_type {
1023 SqlWriter::write_column_type(self, context, out, &column.value);
1024 }
1025 if !column.nullable && column.primary_key == PrimaryKeyType::None {
1026 out.push_str(" NOT NULL");
1027 }
1028 if column.default.is_set() {
1029 out.push_str(" DEFAULT ");
1030 column.default.write_query(self.as_dyn(), context, out);
1031 }
1032 if column.primary_key == PrimaryKeyType::PrimaryKey {
1033 out.push_str(" PRIMARY KEY");
1035 }
1036 if column.unique && column.primary_key != PrimaryKeyType::PrimaryKey {
1037 out.push_str(" UNIQUE");
1038 }
1039 if !column.comment.is_empty() {
1040 self.write_column_comment_inline(context, out, column);
1041 }
1042 }
1043
1044 fn write_create_table_primary_key_fragment<'a, It>(
1046 &self,
1047 context: &mut Context,
1048 out: &mut DynQuery,
1049 primary_key: It,
1050 ) where
1051 Self: Sized,
1052 It: IntoIterator<Item = &'a ColumnDef>,
1053 It::IntoIter: Clone,
1054 {
1055 out.push_str(",\nPRIMARY KEY (");
1056 separated_by(
1057 out,
1058 primary_key,
1059 |out, col| {
1060 self.write_identifier(
1061 &mut context
1062 .switch_fragment(Fragment::SqlCreateTablePrimaryKey)
1063 .current,
1064 out,
1065 col.name(),
1066 true,
1067 );
1068 },
1069 ", ",
1070 );
1071 out.push(')');
1072 }
1073
1074 fn write_create_table_references_action(
1076 &self,
1077 _context: &mut Context,
1078 out: &mut DynQuery,
1079 action: &Action,
1080 ) {
1081 out.push_str(match action {
1082 Action::NoAction => "NO ACTION",
1083 Action::Restrict => "RESTRICT",
1084 Action::Cascade => "CASCADE",
1085 Action::SetNull => "SET NULL",
1086 Action::SetDefault => "SET DEFAULT",
1087 });
1088 }
1089
1090 fn write_column_comment_inline(
1091 &self,
1092 _context: &mut Context,
1093 _out: &mut DynQuery,
1094 _column: &ColumnDef,
1095 ) where
1096 Self: Sized,
1097 {
1098 }
1099
1100 fn write_column_comment(&self, context: &mut Context, out: &mut DynQuery, column: &ColumnDef) {
1102 let mut context = context.switch_fragment(Fragment::SqlCommentOnColumn);
1103 context.current.qualify_columns = true;
1104 if !out.is_empty() {
1105 out.push('\n');
1106 }
1107 out.push_str("COMMENT ON COLUMN ");
1108 self.write_column_ref(&mut context.current, out, column.into());
1109 out.push_str(" IS ");
1110 self.write_string(&mut context.current, out, column.comment);
1111 out.push(';');
1112 }
1113
1114 fn write_drop_table<E>(&self, out: &mut DynQuery, if_exists: bool)
1116 where
1117 Self: Sized,
1118 E: Entity,
1119 {
1120 let table = E::table();
1121 out.buffer()
1122 .reserve(24 + table.schema.len() + table.name.len());
1123 if !out.is_empty() {
1124 out.push('\n');
1125 }
1126 out.push_str("DROP TABLE ");
1127 let mut context = Context::new(Fragment::SqlDropTable, E::qualified_columns());
1128 if if_exists {
1129 out.push_str("IF EXISTS ");
1130 }
1131 self.write_table_ref(&mut context, out, table);
1132 out.push(';');
1133 }
1134
1135 fn write_select<'a, Data>(&self, out: &mut DynQuery, query: &impl SelectQuery<Data>)
1137 where
1138 Self: Sized,
1139 Data: Dataset + 'a,
1140 {
1141 let Some(from) = query.get_from() else {
1142 log::error!("The query does not have the FROM clause");
1143 return;
1144 };
1145 let columns = query.get_select();
1146 let columns_count = columns.clone().into_iter().count();
1147 out.buffer().reserve(128 + columns_count * 32);
1148 if !out.is_empty() {
1149 out.push('\n');
1150 }
1151 out.push_str("SELECT ");
1152 let mut context = Context::new(Fragment::SqlSelect, Data::qualified_columns());
1153 if columns_count != 0 {
1154 separated_by(
1155 out,
1156 columns.clone(),
1157 |out, col| {
1158 col.write_query(self, &mut context, out);
1159 },
1160 ", ",
1161 );
1162 } else {
1163 out.push('*');
1164 }
1165 out.push_str("\nFROM ");
1166 from.write_table_name(
1167 self,
1168 &mut context.switch_fragment(Fragment::SqlSelectFrom).current,
1169 out,
1170 );
1171 if let Some(condition) = query.get_where()
1172 && !condition.accept_visitor(&mut IsTrue, self, &mut context, out)
1173 {
1174 out.push_str("\nWHERE ");
1175 condition.write_query(
1176 self,
1177 &mut context.switch_fragment(Fragment::SqlSelectWhere).current,
1178 out,
1179 );
1180 }
1181 let mut group_by = query.get_group_by().peekable();
1182 if group_by.peek().is_some() {
1183 out.push_str("\nGROUP BY ");
1184 let mut context = context.switch_fragment(Fragment::SqlSelectGroupBy);
1185 separated_by(
1186 out,
1187 group_by,
1188 |out, col| {
1189 col.write_query(self, &mut context.current, out);
1190 },
1191 ", ",
1192 );
1193 }
1194 if let Some(having) = query.get_having() {
1195 out.push_str("\nHAVING ");
1196 having.write_query(
1197 self,
1198 &mut context.switch_fragment(Fragment::SqlSelectHaving).current,
1199 out,
1200 );
1201 }
1202 let mut order_by = query.get_order_by().peekable();
1203 if order_by.peek().is_some() {
1204 out.push_str("\nORDER BY ");
1205 let mut context = context.switch_fragment(Fragment::SqlSelectOrderBy);
1206 separated_by(
1207 out,
1208 order_by,
1209 |out, col| {
1210 col.write_query(self, &mut context.current, out);
1211 },
1212 ", ",
1213 );
1214 }
1215 if let Some(limit) = query.get_limit() {
1216 let _ = write!(out, "\nLIMIT {limit}");
1217 }
1218 out.push(';');
1219 }
1220
1221 fn write_insert<It>(&self, out: &mut DynQuery, entities: It, update: bool)
1223 where
1224 Self: Sized,
1225 It: IntoIterator,
1226 It::Item: AsEntity,
1227 {
1228 type E<It> = <<It as IntoIterator>::Item as AsEntity>::Entity;
1229 let table = E::<It>::table();
1230 let mut entities = entities.into_iter().peekable();
1231 if entities.peek().is_none() {
1232 return;
1233 };
1234 let cols = E::<It>::columns().len();
1235 let rows = entities.size_hint().0.max(1);
1236 out.buffer().reserve(128 + (cols + rows * cols) * 16);
1237 if !out.is_empty() {
1238 out.push('\n');
1239 }
1240 out.push_str("INSERT INTO ");
1241 let mut context = Context::new(Fragment::SqlInsertInto, E::<It>::qualified_columns());
1242 self.write_table_ref(&mut context, out, table);
1243 out.push_str(" (");
1244 separated_by(
1245 out,
1246 E::<It>::columns().iter(),
1247 |out, col| {
1248 self.write_identifier(&mut context, out, col.name(), true);
1249 },
1250 ", ",
1251 );
1252 out.push_str(") VALUES");
1253 let mut context = context.switch_fragment(Fragment::SqlInsertIntoValues);
1254 separated_by(
1255 out,
1256 entities,
1257 |out, entity| {
1258 out.push_str("\n(");
1259 entity
1260 .as_entity()
1261 .write_query(self.as_dyn(), &mut context.current, out);
1262 out.push(')');
1263 },
1264 ",",
1265 );
1266 if update {
1267 self.write_insert_update_fragment::<E<It>>(
1268 &mut context.current,
1269 out,
1270 E::<It>::columns().iter(),
1271 );
1272 }
1273 out.push(';');
1274 }
1275
1276 fn write_insert_update_fragment<'a, E>(
1278 &self,
1279 context: &mut Context,
1280 out: &mut DynQuery,
1281 columns: impl Iterator<Item = &'a ColumnDef> + Clone,
1282 ) where
1283 Self: Sized,
1284 E: Entity,
1285 {
1286 let pk = E::primary_key_def();
1287 if pk.is_empty() {
1288 return;
1289 }
1290 out.push_str("\nON CONFLICT");
1291 context.fragment = Fragment::SqlInsertIntoOnConflict;
1292 out.push_str(" (");
1293 separated_by(
1294 out,
1295 pk,
1296 |out, col| {
1297 self.write_identifier(context, out, col.name(), true);
1298 },
1299 ", ",
1300 );
1301 out.push(')');
1302 let mut update_cols = columns
1303 .filter(|c| c.primary_key == PrimaryKeyType::None)
1304 .peekable();
1305 if update_cols.peek().is_some() {
1306 out.push_str(" DO UPDATE SET\n");
1307 separated_by(
1308 out,
1309 update_cols,
1310 |out, col| {
1311 self.write_identifier(context, out, col.name(), true);
1312 out.push_str(" = EXCLUDED.");
1313 self.write_identifier(context, out, col.name(), true);
1314 },
1315 ",\n",
1316 );
1317 } else {
1318 out.push_str(" DO NOTHING");
1319 }
1320 }
1321
1322 fn write_delete<E>(&self, out: &mut DynQuery, condition: impl Expression)
1324 where
1325 Self: Sized,
1326 E: Entity,
1327 {
1328 let table = E::table();
1329 out.buffer().reserve(128);
1330 if !out.is_empty() {
1331 out.push('\n');
1332 }
1333 out.push_str("DELETE FROM ");
1334 let mut context = Context::new(Fragment::SqlDeleteFrom, E::qualified_columns());
1335 self.write_table_ref(&mut context, out, table);
1336 out.push_str("\nWHERE ");
1337 condition.write_query(
1338 self,
1339 &mut context
1340 .switch_fragment(Fragment::SqlDeleteFromWhere)
1341 .current,
1342 out,
1343 );
1344 out.push(';');
1345 }
1346}
1347
1348pub struct GenericSqlWriter;
1350impl GenericSqlWriter {
1351 pub fn new() -> Self {
1353 Self {}
1354 }
1355}
1356impl SqlWriter for GenericSqlWriter {
1357 fn as_dyn(&self) -> &dyn SqlWriter {
1358 self
1359 }
1360}