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