1use super::{DialectImpl, DialectType};
13use crate::error::Result;
14use crate::expressions::{
15 Alias, BinaryOp, CeilFunc, Column, Exists, Expression, From, Function, FunctionBody,
16 Identifier, JsonExtractFunc, LikeOp, Literal, Select, SplitFunc, StringAggFunc, UnaryFunc,
17 UnnestFunc, VarArgFunc, Where,
18};
19use crate::generator::GeneratorConfig;
20use crate::tokens::TokenizerConfig;
21
22pub struct BigQueryDialect;
24
25impl DialectImpl for BigQueryDialect {
26 fn dialect_type(&self) -> DialectType {
27 DialectType::BigQuery
28 }
29
30 fn tokenizer_config(&self) -> TokenizerConfig {
31 let mut config = TokenizerConfig::default();
32 config.identifiers.remove(&'"');
35 config.identifiers.insert('`', '`');
36 config.quotes.insert("\"".to_string(), "\"".to_string());
38 config.quotes.insert("'''".to_string(), "'''".to_string());
40 config
41 .quotes
42 .insert("\"\"\"".to_string(), "\"\"\"".to_string());
43 config.string_escapes = vec!['\'', '\\'];
45 config.b_prefix_is_byte_string = true;
47 config.hex_number_strings = true;
49 config.hex_string_is_integer_type = true;
51 config.hash_comments = true;
53 config
54 }
55
56 fn generator_config(&self) -> GeneratorConfig {
57 use crate::generator::{IdentifierQuoteStyle, NormalizeFunctions};
58 GeneratorConfig {
59 identifier_quote: '`',
60 identifier_quote_style: IdentifierQuoteStyle::BACKTICK,
61 dialect: Some(DialectType::BigQuery),
62 normalize_functions: NormalizeFunctions::None,
64 interval_allows_plural_form: false,
66 join_hints: false,
67 query_hints: false,
68 table_hints: false,
69 limit_fetch_style: crate::generator::LimitFetchStyle::Limit,
70 rename_table_with_db: false,
71 nvl2_supported: false,
72 unnest_with_ordinality: false,
73 collate_is_func: true,
74 limit_only_literals: true,
75 supports_table_alias_columns: false,
76 unpivot_aliases_are_identifiers: false,
77 json_key_value_pair_sep: ",",
78 null_ordering_supported: false,
79 ignore_nulls_in_func: true,
80 json_path_single_quote_escape: true,
81 can_implement_array_any: true,
82 supports_to_number: false,
83 named_placeholder_token: "@",
84 hex_func: "TO_HEX",
85 with_properties_prefix: "OPTIONS",
86 supports_exploding_projections: false,
87 except_intersect_support_all_clause: false,
88 supports_unix_seconds: true,
89 try_supported: true,
91 semi_anti_join_with_side: false,
93 ..Default::default()
94 }
95 }
96
97 fn transform_expr(&self, expr: Expression) -> Result<Expression> {
98 match expr {
99 Expression::DataType(dt) => self.transform_data_type(dt),
101
102 Expression::IfNull(f) => Ok(Expression::IfNull(f)),
105
106 Expression::Nvl(f) => Ok(Expression::IfNull(f)),
108
109 Expression::Coalesce(f) => Ok(Expression::Coalesce(f)),
111
112 Expression::GroupConcat(f) => Ok(Expression::StringAgg(Box::new(StringAggFunc {
115 this: f.this,
116 separator: f.separator,
117 order_by: f.order_by,
118 distinct: f.distinct,
119 filter: f.filter,
120 limit: None,
121 inferred_type: None,
122 }))),
123
124 Expression::TryCast(c) => {
130 let transformed_type = match self.transform_data_type(c.to)? {
131 Expression::DataType(dt) => dt,
132 _ => return Err(crate::error::Error::parse("Expected DataType", 0, 0, 0, 0)),
133 };
134 Ok(Expression::SafeCast(Box::new(crate::expressions::Cast {
135 this: c.this,
136 to: transformed_type,
137 trailing_comments: c.trailing_comments,
138 double_colon_syntax: c.double_colon_syntax,
139 format: c.format,
140 default: c.default,
141 inferred_type: None,
142 })))
143 }
144
145 Expression::ILike(op) => {
148 let lower_left = Expression::Lower(Box::new(UnaryFunc::new(op.left)));
149 let lower_right = Expression::Lower(Box::new(UnaryFunc::new(op.right)));
150 Ok(Expression::Like(Box::new(LikeOp {
151 left: lower_left,
152 right: lower_right,
153 escape: op.escape,
154 quantifier: op.quantifier,
155 inferred_type: None,
156 })))
157 }
158
159 Expression::RegexpLike(f) => Ok(Expression::Function(Box::new(Function::new(
161 "REGEXP_CONTAINS".to_string(),
162 vec![f.this, f.pattern],
163 )))),
164
165 Expression::Explode(f) => Ok(Expression::Unnest(Box::new(
168 crate::expressions::UnnestFunc {
169 this: f.this,
170 expressions: Vec::new(),
171 with_ordinality: false,
172 alias: None,
173 offset_alias: None,
174 },
175 ))),
176
177 Expression::ExplodeOuter(f) => Ok(Expression::Unnest(Box::new(
179 crate::expressions::UnnestFunc {
180 this: f.this,
181 expressions: Vec::new(),
182 with_ordinality: false,
183 alias: None,
184 offset_alias: None,
185 },
186 ))),
187
188 Expression::GenerateSeries(f) => {
190 let mut args = Vec::new();
191 if let Some(start) = f.start {
192 args.push(*start);
193 }
194 if let Some(end) = f.end {
195 args.push(*end);
196 }
197 if let Some(step) = f.step {
198 args.push(*step);
199 }
200 Ok(Expression::Function(Box::new(Function::new(
201 "GENERATE_ARRAY".to_string(),
202 args,
203 ))))
204 }
205
206 Expression::BitwiseAndAgg(f) => Ok(Expression::Function(Box::new(Function::new(
209 "BIT_AND".to_string(),
210 vec![f.this],
211 )))),
212
213 Expression::BitwiseOrAgg(f) => Ok(Expression::Function(Box::new(Function::new(
215 "BIT_OR".to_string(),
216 vec![f.this],
217 )))),
218
219 Expression::BitwiseXorAgg(f) => Ok(Expression::Function(Box::new(Function::new(
221 "BIT_XOR".to_string(),
222 vec![f.this],
223 )))),
224
225 Expression::BitwiseCount(f) => Ok(Expression::Function(Box::new(Function::new(
227 "BIT_COUNT".to_string(),
228 vec![f.this],
229 )))),
230
231 Expression::ByteLength(f) => Ok(Expression::Function(Box::new(Function::new(
233 "BYTE_LENGTH".to_string(),
234 vec![f.this],
235 )))),
236
237 Expression::IntDiv(f) => Ok(Expression::Function(Box::new(Function::new(
239 "DIV".to_string(),
240 vec![f.this, f.expression],
241 )))),
242
243 Expression::Int64(f) => Ok(Expression::Function(Box::new(Function::new(
245 "INT64".to_string(),
246 vec![f.this],
247 )))),
248
249 Expression::Random(_) => Ok(Expression::Rand(Box::new(crate::expressions::Rand {
252 seed: None,
253 lower: None,
254 upper: None,
255 }))),
256
257 Expression::Uuid(_) => Ok(Expression::Function(Box::new(Function::new(
260 "GENERATE_UUID".to_string(),
261 vec![],
262 )))),
263
264 Expression::ApproxDistinct(f) => Ok(Expression::Function(Box::new(Function::new(
267 "APPROX_COUNT_DISTINCT".to_string(),
268 vec![f.this],
269 )))),
270
271 Expression::ArgMax(f) => Ok(Expression::Function(Box::new(Function::new(
273 "MAX_BY".to_string(),
274 vec![*f.this, *f.expression],
275 )))),
276
277 Expression::ArgMin(f) => Ok(Expression::Function(Box::new(Function::new(
279 "MIN_BY".to_string(),
280 vec![*f.this, *f.expression],
281 )))),
282
283 Expression::CountIf(f) => Ok(Expression::Function(Box::new(Function::new(
286 "COUNTIF".to_string(),
287 vec![f.this],
288 )))),
289
290 Expression::StringAgg(f) => Ok(Expression::StringAgg(f)),
293
294 Expression::Unhex(f) => Ok(Expression::Function(Box::new(Function::new(
297 "FROM_HEX".to_string(),
298 vec![*f.this],
299 )))),
300
301 Expression::UnixToTime(f) => {
303 let scale = f.scale.unwrap_or(0);
304 match scale {
305 0 => Ok(Expression::Function(Box::new(Function::new(
306 "TIMESTAMP_SECONDS".to_string(),
307 vec![*f.this],
308 )))),
309 3 => Ok(Expression::Function(Box::new(Function::new(
310 "TIMESTAMP_MILLIS".to_string(),
311 vec![*f.this],
312 )))),
313 6 => Ok(Expression::Function(Box::new(Function::new(
314 "TIMESTAMP_MICROS".to_string(),
315 vec![*f.this],
316 )))),
317 _ => {
318 let div_expr =
320 Expression::Div(Box::new(crate::expressions::BinaryOp::new(
321 *f.this,
322 Expression::Function(Box::new(Function::new(
323 "POWER".to_string(),
324 vec![Expression::number(10), Expression::number(scale)],
325 ))),
326 )));
327 let cast_expr = Expression::Cast(Box::new(crate::expressions::Cast {
328 this: div_expr,
329 to: crate::expressions::DataType::Custom {
330 name: "INT64".to_string(),
331 },
332 double_colon_syntax: false,
333 trailing_comments: vec![],
334 format: None,
335 default: None,
336 inferred_type: None,
337 }));
338 Ok(Expression::Function(Box::new(Function::new(
339 "TIMESTAMP_SECONDS".to_string(),
340 vec![cast_expr],
341 ))))
342 }
343 }
344 }
345
346 Expression::DateDiff(f) => {
349 let unit_str = match f.unit {
351 Some(crate::expressions::IntervalUnit::Year) => "YEAR",
352 Some(crate::expressions::IntervalUnit::Quarter) => "QUARTER",
353 Some(crate::expressions::IntervalUnit::Month) => "MONTH",
354 Some(crate::expressions::IntervalUnit::Week) => "WEEK",
355 Some(crate::expressions::IntervalUnit::Day) => "DAY",
356 Some(crate::expressions::IntervalUnit::Hour) => "HOUR",
357 Some(crate::expressions::IntervalUnit::Minute) => "MINUTE",
358 Some(crate::expressions::IntervalUnit::Second) => "SECOND",
359 Some(crate::expressions::IntervalUnit::Millisecond) => "MILLISECOND",
360 Some(crate::expressions::IntervalUnit::Microsecond) => "MICROSECOND",
361 Some(crate::expressions::IntervalUnit::Nanosecond) => "NANOSECOND",
362 None => "DAY",
363 };
364 let unit = Expression::Identifier(crate::expressions::Identifier {
365 name: unit_str.to_string(),
366 quoted: false,
367 trailing_comments: Vec::new(),
368 span: None,
369 });
370 Ok(Expression::Function(Box::new(Function::new(
371 "DATE_DIFF".to_string(),
372 vec![f.this, f.expression, unit],
373 ))))
374 }
375
376 Expression::VarPop(f) => Ok(Expression::Function(Box::new(Function::new(
379 "VAR_POP".to_string(),
380 vec![f.this],
381 )))),
382
383 Expression::SHA(f) => Ok(Expression::Function(Box::new(Function::new(
386 "SHA1".to_string(),
387 vec![f.this],
388 )))),
389
390 Expression::SHA1Digest(f) => Ok(Expression::Function(Box::new(Function::new(
392 "SHA1".to_string(),
393 vec![f.this],
394 )))),
395
396 Expression::MD5Digest(f) => Ok(Expression::Function(Box::new(Function::new(
398 "MD5".to_string(),
399 vec![*f.this],
400 )))),
401
402 Expression::JSONBool(f) => Ok(Expression::Function(Box::new(Function::new(
405 "BOOL".to_string(),
406 vec![f.this],
407 )))),
408
409 Expression::StringFunc(f) => Ok(Expression::Function(Box::new(Function::new(
411 "STRING".to_string(),
412 vec![*f.this],
413 )))),
414
415 Expression::DateFromUnixDate(f) => Ok(Expression::Function(Box::new(Function::new(
418 "DATE_FROM_UNIX_DATE".to_string(),
419 vec![f.this],
420 )))),
421
422 Expression::UnixDate(f) => Ok(Expression::Function(Box::new(Function::new(
424 "UNIX_DATE".to_string(),
425 vec![f.this],
426 )))),
427
428 Expression::TimestampDiff(f) => Ok(Expression::Function(Box::new(Function::new(
430 "TIMESTAMP_DIFF".to_string(),
431 vec![*f.this, *f.expression],
432 )))),
433
434 Expression::FromTimeZone(f) => Ok(Expression::Function(Box::new(Function::new(
436 "DATETIME".to_string(),
437 vec![*f.this],
438 )))),
439
440 Expression::TsOrDsToDatetime(f) => Ok(Expression::Function(Box::new(Function::new(
442 "DATETIME".to_string(),
443 vec![f.this],
444 )))),
445
446 Expression::TsOrDsToTimestamp(f) => Ok(Expression::Function(Box::new(Function::new(
448 "TIMESTAMP".to_string(),
449 vec![f.this],
450 )))),
451
452 Expression::IfFunc(f) => {
454 let mut args = vec![f.condition, f.true_value];
455 if let Some(false_val) = f.false_value {
456 args.push(false_val);
457 } else {
458 args.push(Expression::Null(crate::expressions::Null));
459 }
460 Ok(Expression::Function(Box::new(Function::new(
461 "IF".to_string(),
462 args,
463 ))))
464 }
465
466 Expression::HexStringExpr(f) => Ok(Expression::Function(Box::new(Function::new(
468 "FROM_HEX".to_string(),
469 vec![*f.this],
470 )))),
471
472 Expression::ApproxTopK(f) => {
475 let mut args = vec![*f.this];
476 if let Some(expr) = f.expression {
477 args.push(*expr);
478 }
479 Ok(Expression::Function(Box::new(Function::new(
480 "APPROX_TOP_COUNT".to_string(),
481 args,
482 ))))
483 }
484
485 Expression::SafeDivide(f) => Ok(Expression::Function(Box::new(Function::new(
487 "SAFE_DIVIDE".to_string(),
488 vec![*f.this, *f.expression],
489 )))),
490
491 Expression::JSONKeysAtDepth(f) => Ok(Expression::Function(Box::new(Function::new(
493 "JSON_KEYS".to_string(),
494 vec![*f.this],
495 )))),
496
497 Expression::JSONValueArray(f) => Ok(Expression::Function(Box::new(Function::new(
499 "JSON_VALUE_ARRAY".to_string(),
500 vec![*f.this],
501 )))),
502
503 Expression::DateFromParts(f) => {
505 let mut args = Vec::new();
506 if let Some(y) = f.year {
507 args.push(*y);
508 }
509 if let Some(m) = f.month {
510 args.push(*m);
511 }
512 if let Some(d) = f.day {
513 args.push(*d);
514 }
515 Ok(Expression::Function(Box::new(Function::new(
516 "DATE".to_string(),
517 args,
518 ))))
519 }
520
521 Expression::Split(f) => {
524 let delimiter = match &f.delimiter {
526 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::String(s) if s.is_empty()) =>
527 {
528 let Literal::String(_) = lit.as_ref() else {
529 unreachable!()
530 };
531 Expression::Literal(Box::new(Literal::String(",".to_string())))
532 }
533 _ => f.delimiter,
534 };
535 Ok(Expression::Split(Box::new(SplitFunc {
536 this: f.this,
537 delimiter,
538 })))
539 }
540
541 Expression::Cast(c) => {
545 use crate::expressions::DataType;
546 let is_json = matches!(c.to, DataType::Json | DataType::JsonB)
548 || matches!(&c.to, DataType::Custom { name } if name.eq_ignore_ascii_case("JSON") || name.eq_ignore_ascii_case("JSONB"));
549 if is_json {
550 return Ok(Expression::ParseJson(Box::new(UnaryFunc::new(c.this))));
551 }
552 if c.format.is_some() {
554 let is_temporal = matches!(
555 c.to,
556 DataType::Date | DataType::Timestamp { .. } | DataType::Time { .. }
557 ) || matches!(&c.to, DataType::Custom { name } if
558 name.eq_ignore_ascii_case("TIMESTAMP") ||
559 name.eq_ignore_ascii_case("DATE") ||
560 name.eq_ignore_ascii_case("DATETIME") ||
561 name.eq_ignore_ascii_case("TIME")
562 );
563 if is_temporal {
564 let format_expr = c.format.as_ref().unwrap().as_ref();
565 let (actual_format, timezone) = match format_expr {
567 Expression::AtTimeZone(ref atz) => {
568 (atz.this.clone(), Some(atz.zone.clone()))
569 }
570 _ => (format_expr.clone(), None),
571 };
572 let strftime_fmt = Self::bq_cast_format_to_strftime(&actual_format);
573 let func_name = match &c.to {
574 DataType::Date => "PARSE_DATE",
575 DataType::Custom { name } if name.eq_ignore_ascii_case("DATE") => {
576 "PARSE_DATE"
577 }
578 DataType::Custom { name } if name.eq_ignore_ascii_case("DATETIME") => {
579 "PARSE_DATETIME"
580 }
581 _ => "PARSE_TIMESTAMP",
582 };
583 let mut func_args = vec![strftime_fmt, c.this];
584 if let Some(tz) = timezone {
585 func_args.push(tz);
586 }
587 return Ok(Expression::Function(Box::new(Function::new(
588 func_name.to_string(),
589 func_args,
590 ))));
591 }
592 }
593 let transformed_type = match self.transform_data_type(c.to)? {
594 Expression::DataType(dt) => dt,
595 _ => return Err(crate::error::Error::parse("Expected DataType", 0, 0, 0, 0)),
596 };
597 Ok(Expression::Cast(Box::new(crate::expressions::Cast {
598 this: c.this,
599 to: transformed_type,
600 trailing_comments: c.trailing_comments,
601 double_colon_syntax: c.double_colon_syntax,
602 format: c.format,
603 default: c.default,
604 inferred_type: None,
605 })))
606 }
607
608 Expression::SafeCast(c) => {
610 let transformed_type = match self.transform_data_type(c.to)? {
611 Expression::DataType(dt) => dt,
612 _ => return Err(crate::error::Error::parse("Expected DataType", 0, 0, 0, 0)),
613 };
614 Ok(Expression::SafeCast(Box::new(crate::expressions::Cast {
615 this: c.this,
616 to: transformed_type,
617 trailing_comments: c.trailing_comments,
618 double_colon_syntax: c.double_colon_syntax,
619 format: c.format,
620 default: c.default,
621 inferred_type: None,
622 })))
623 }
624
625 Expression::Select(mut select) => {
628 if select.group_by.is_some() && select.order_by.is_some() {
629 let aliases: Vec<(Expression, Identifier)> = select
631 .expressions
632 .iter()
633 .filter_map(|e| {
634 if let Expression::Alias(a) = e {
635 Some((a.this.clone(), a.alias.clone()))
636 } else {
637 None
638 }
639 })
640 .collect();
641
642 if let Some(ref mut group_by) = select.group_by {
643 for grouped in group_by.expressions.iter_mut() {
644 if matches!(grouped, Expression::Literal(lit) if matches!(lit.as_ref(), Literal::Number(_)))
646 {
647 continue;
648 }
649 for (expr, alias_ident) in &aliases {
651 if grouped == expr {
652 *grouped = Expression::boxed_column(Column {
653 name: alias_ident.clone(),
654 table: None,
655 join_mark: false,
656 trailing_comments: Vec::new(),
657 span: None,
658 inferred_type: None,
659 });
660 break;
661 }
662 }
663 }
664 }
665 }
666 Ok(Expression::Select(select))
667 }
668
669 Expression::ArrayContains(f) => {
671 let array_expr = f.this;
672 let value_expr = f.expression;
673
674 let unnest = Expression::Unnest(Box::new(UnnestFunc {
676 this: array_expr,
677 expressions: Vec::new(),
678 with_ordinality: false,
679 alias: None,
680 offset_alias: None,
681 }));
682 let aliased_unnest = Expression::Alias(Box::new(Alias {
683 this: unnest,
684 alias: Identifier::new("_col"),
685 column_aliases: Vec::new(),
686 alias_explicit_as: false,
687 alias_keyword: None,
688 pre_alias_comments: Vec::new(),
689 trailing_comments: Vec::new(),
690 inferred_type: None,
691 }));
692 let col_ref = Expression::boxed_column(Column {
693 name: Identifier::new("_col"),
694 table: None,
695 join_mark: false,
696 trailing_comments: Vec::new(),
697 span: None,
698 inferred_type: None,
699 });
700 let where_clause = Where {
701 this: Expression::Eq(Box::new(BinaryOp {
702 left: col_ref,
703 right: value_expr,
704 left_comments: Vec::new(),
705 operator_comments: Vec::new(),
706 trailing_comments: Vec::new(),
707 inferred_type: None,
708 })),
709 };
710 let inner_select = Expression::Select(Box::new(Select {
711 expressions: vec![Expression::Literal(Box::new(Literal::Number(
712 "1".to_string(),
713 )))],
714 from: Some(From {
715 expressions: vec![aliased_unnest],
716 }),
717 where_clause: Some(where_clause),
718 ..Default::default()
719 }));
720 Ok(Expression::Exists(Box::new(Exists {
721 this: inner_select,
722 not: false,
723 })))
724 }
725
726 Expression::JsonObject(mut f) => {
729 if f.pairs.len() == 1 {
730 let keys_exprs = match &f.pairs[0].0 {
732 Expression::Array(arr) => Some(&arr.expressions),
733 Expression::ArrayFunc(arr) => Some(&arr.expressions),
734 _ => None,
735 };
736 let vals_exprs = match &f.pairs[0].1 {
737 Expression::Array(arr) => Some(&arr.expressions),
738 Expression::ArrayFunc(arr) => Some(&arr.expressions),
739 _ => None,
740 };
741 if let (Some(keys), Some(vals)) = (keys_exprs, vals_exprs) {
742 if keys.len() == vals.len() {
743 let new_pairs: Vec<(Expression, Expression)> = keys
744 .iter()
745 .zip(vals.iter())
746 .map(|(k, v)| (k.clone(), v.clone()))
747 .collect();
748 f.pairs = new_pairs;
749 }
750 }
751 }
752 Ok(Expression::JsonObject(f))
753 }
754
755 Expression::ModFunc(mut f) => {
758 if let Expression::Paren(paren) = f.this {
760 f.this = paren.this;
761 }
762 Ok(Expression::ModFunc(f))
763 }
764
765 Expression::JSONExtract(e) if e.variant_extract.is_some() => {
767 let path = match *e.expression {
768 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::String(_)) => {
769 let Literal::String(s) = lit.as_ref() else {
770 unreachable!()
771 };
772 let normalized = if s.starts_with('$') {
773 s.clone()
774 } else if s.starts_with('[') {
775 format!("${}", s)
776 } else {
777 format!("$.{}", s)
778 };
779 Expression::Literal(Box::new(Literal::String(normalized)))
780 }
781 other => other,
782 };
783 Ok(Expression::Function(Box::new(Function::new(
784 "JSON_EXTRACT".to_string(),
785 vec![*e.this, path],
786 ))))
787 }
788
789 Expression::Function(f) => self.transform_function(*f),
791
792 Expression::AggregateFunction(f) => self.transform_aggregate_function(f),
794
795 Expression::MethodCall(mc) => self.transform_method_call(*mc),
798
799 Expression::CreateFunction(mut cf) => {
802 if let Some(ref mut rtb) = cf.returns_table_body {
803 if rtb.starts_with("TABLE (") || rtb.starts_with("TABLE(") {
804 let inner = if rtb.starts_with("TABLE (") {
806 &rtb["TABLE (".len()..rtb.len() - 1]
807 } else {
808 &rtb["TABLE(".len()..rtb.len() - 1]
809 };
810 let converted = inner
812 .replace(" INT,", " INT64,")
813 .replace(" INT)", " INT64)")
814 .replace(" INTEGER,", " INT64,")
815 .replace(" INTEGER)", " INT64)")
816 .replace(" FLOAT,", " FLOAT64,")
817 .replace(" FLOAT)", " FLOAT64)")
818 .replace(" BOOLEAN,", " BOOL,")
819 .replace(" BOOLEAN)", " BOOL)")
820 .replace(" VARCHAR", " STRING")
821 .replace(" TEXT", " STRING");
822 let converted = if converted.ends_with(" INT") {
824 format!("{}{}", &converted[..converted.len() - 4], " INT64")
825 } else {
826 converted
827 };
828 *rtb = format!("TABLE <{}>", converted);
829 cf.is_table_function = true;
830 }
831 }
832 if cf.is_table_function {
834 if let Some(ref body) = cf.body {
835 if matches!(body, FunctionBody::StringLiteral(_)) {
836 if let Some(FunctionBody::StringLiteral(sql)) = cf.body.take() {
837 if let Ok(parsed) = crate::parser::Parser::parse_sql(&sql) {
839 if let Some(stmt) = parsed.into_iter().next() {
840 cf.body = Some(FunctionBody::Expression(stmt));
841 } else {
842 cf.body = Some(FunctionBody::StringLiteral(sql));
843 }
844 } else {
845 cf.body = Some(FunctionBody::StringLiteral(sql));
846 }
847 }
848 }
849 }
850 }
851 Ok(Expression::CreateFunction(cf))
852 }
853
854 _ => Ok(expr),
856 }
857 }
858}
859
860impl BigQueryDialect {
861 fn transform_data_type(&self, dt: crate::expressions::DataType) -> Result<Expression> {
863 use crate::expressions::DataType;
864 let transformed = match dt {
865 DataType::BigInt { .. } => DataType::Custom {
867 name: "INT64".to_string(),
868 },
869 DataType::Int { .. } => DataType::Custom {
871 name: "INT64".to_string(),
872 },
873 DataType::SmallInt { .. } => DataType::Custom {
875 name: "INT64".to_string(),
876 },
877 DataType::TinyInt { .. } => DataType::Custom {
879 name: "INT64".to_string(),
880 },
881 DataType::Float { .. } => DataType::Custom {
883 name: "FLOAT64".to_string(),
884 },
885 DataType::Double { .. } => DataType::Custom {
887 name: "FLOAT64".to_string(),
888 },
889 DataType::Boolean => DataType::Custom {
891 name: "BOOL".to_string(),
892 },
893 DataType::Char { .. } => DataType::Custom {
895 name: "STRING".to_string(),
896 },
897 DataType::VarChar { .. } => DataType::Custom {
899 name: "STRING".to_string(),
900 },
901 DataType::Text => DataType::Custom {
903 name: "STRING".to_string(),
904 },
905 DataType::String { .. } => DataType::Custom {
907 name: "STRING".to_string(),
908 },
909 DataType::Binary { .. } => DataType::Custom {
911 name: "BYTES".to_string(),
912 },
913 DataType::VarBinary { .. } => DataType::Custom {
915 name: "BYTES".to_string(),
916 },
917 DataType::Blob => DataType::Custom {
919 name: "BYTES".to_string(),
920 },
921 DataType::Decimal { .. } => DataType::Custom {
923 name: "NUMERIC".to_string(),
924 },
925 DataType::Timestamp {
929 timezone: false, ..
930 } => DataType::Custom {
931 name: "TIMESTAMP".to_string(),
932 },
933 DataType::Timestamp { timezone: true, .. } => DataType::Custom {
934 name: "TIMESTAMP".to_string(),
935 },
936 DataType::Uuid => DataType::Custom {
938 name: "STRING".to_string(),
939 },
940 DataType::Custom { ref name } if name.eq_ignore_ascii_case("RECORD") => {
942 DataType::Custom {
943 name: "STRUCT".to_string(),
944 }
945 }
946 DataType::Custom { ref name } if name.eq_ignore_ascii_case("TIMESTAMPTZ") => {
948 DataType::Custom {
949 name: "TIMESTAMP".to_string(),
950 }
951 }
952 DataType::Custom { ref name } if name.eq_ignore_ascii_case("BYTEINT") => {
954 DataType::Custom {
955 name: "INT64".to_string(),
956 }
957 }
958 other => other,
960 };
961 Ok(Expression::DataType(transformed))
962 }
963
964 fn transform_function(&self, f: Function) -> Result<Expression> {
965 let name_upper = f.name.to_uppercase();
966 match name_upper.as_str() {
967 "IFNULL" if f.args.len() == 2 => Ok(Expression::Coalesce(Box::new(VarArgFunc {
969 original_name: None,
970 expressions: f.args,
971 inferred_type: None,
972 }))),
973
974 "NVL" if f.args.len() == 2 => Ok(Expression::Coalesce(Box::new(VarArgFunc {
976 original_name: None,
977 expressions: f.args,
978 inferred_type: None,
979 }))),
980
981 "ISNULL" if f.args.len() == 2 => Ok(Expression::Coalesce(Box::new(VarArgFunc {
983 original_name: None,
984 expressions: f.args,
985 inferred_type: None,
986 }))),
987
988 "GROUP_CONCAT" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
990 Function::new("STRING_AGG".to_string(), f.args),
991 ))),
992
993 "SUBSTR" => Ok(Expression::Function(Box::new(Function::new(
995 "SUBSTRING".to_string(),
996 f.args,
997 )))),
998
999 "RANDOM" => Ok(Expression::Rand(Box::new(crate::expressions::Rand {
1001 seed: None,
1002 lower: None,
1003 upper: None,
1004 }))),
1005
1006 "CURRENT_DATE" if f.args.is_empty() => {
1009 Ok(Expression::CurrentDate(crate::expressions::CurrentDate))
1010 }
1011 "CURRENT_DATE" => Ok(Expression::Function(Box::new(Function {
1012 name: "CURRENT_DATE".to_string(),
1013 args: f.args,
1014 distinct: false,
1015 trailing_comments: Vec::new(),
1016 use_bracket_syntax: false,
1017 no_parens: false,
1018 quoted: false,
1019 span: None,
1020 inferred_type: None,
1021 }))),
1022
1023 "NOW" => Ok(Expression::CurrentTimestamp(
1025 crate::expressions::CurrentTimestamp {
1026 precision: None,
1027 sysdate: false,
1028 },
1029 )),
1030
1031 "TO_DATE" => Ok(Expression::Function(Box::new(Function::new(
1033 "PARSE_DATE".to_string(),
1034 f.args,
1035 )))),
1036
1037 "TO_TIMESTAMP" => Ok(Expression::Function(Box::new(Function::new(
1039 "PARSE_TIMESTAMP".to_string(),
1040 f.args,
1041 )))),
1042
1043 "TO_TIME" if f.args.len() == 1 => Ok(Expression::Function(Box::new(Function::new(
1045 "TIME".to_string(),
1046 f.args,
1047 )))),
1048
1049 "DATE_FORMAT" => Ok(Expression::Function(Box::new(Function::new(
1051 "FORMAT_DATE".to_string(),
1052 f.args,
1053 )))),
1054
1055 "POSITION" if f.args.len() == 2 => {
1058 let mut args = f.args;
1059 let first = args.remove(0);
1061 let second = args.remove(0);
1062 Ok(Expression::Function(Box::new(Function::new(
1063 "STRPOS".to_string(),
1064 vec![second, first],
1065 ))))
1066 }
1067
1068 "LEN" if f.args.len() == 1 => Ok(Expression::Length(Box::new(UnaryFunc::new(
1070 f.args.into_iter().next().unwrap(),
1071 )))),
1072
1073 "CEILING" if f.args.len() == 1 => Ok(Expression::Ceil(Box::new(CeilFunc {
1075 this: f.args.into_iter().next().unwrap(),
1076 decimals: None,
1077 to: None,
1078 }))),
1079
1080 "GETDATE" => Ok(Expression::CurrentTimestamp(
1082 crate::expressions::CurrentTimestamp {
1083 precision: None,
1084 sysdate: false,
1085 },
1086 )),
1087
1088 "CARDINALITY" if f.args.len() == 1 => Ok(Expression::ArrayLength(Box::new(
1091 UnaryFunc::new(f.args.into_iter().next().unwrap()),
1092 ))),
1093
1094 "GENERATE_SERIES" => Ok(Expression::Function(Box::new(Function::new(
1098 "GENERATE_ARRAY".to_string(),
1099 f.args,
1100 )))),
1101
1102 "APPROX_DISTINCT" => Ok(Expression::Function(Box::new(Function::new(
1105 "APPROX_COUNT_DISTINCT".to_string(),
1106 f.args,
1107 )))),
1108
1109 "COUNT_IF" => Ok(Expression::Function(Box::new(Function::new(
1111 "COUNTIF".to_string(),
1112 f.args,
1113 )))),
1114
1115 "SHA" => Ok(Expression::Function(Box::new(Function::new(
1117 "SHA1".to_string(),
1118 f.args,
1119 )))),
1120
1121 "SHA2" => Ok(Expression::Function(Box::new(Function::new(
1123 "SHA256".to_string(),
1124 f.args,
1125 )))),
1126
1127 "MD5" => Ok(Expression::Function(Box::new(Function::new(
1130 "MD5".to_string(),
1131 f.args,
1132 )))),
1133
1134 "DATEADD" if f.args.len() == 3 => {
1139 let mut args = f.args;
1140 let unit_expr = args.remove(0);
1141 let amount = args.remove(0);
1142 let date = args.remove(0);
1143 let unit_name = match &unit_expr {
1145 Expression::Identifier(id) => id.name.to_uppercase(),
1146 Expression::Var(v) => v.this.to_uppercase(),
1147 Expression::Column(col) if col.table.is_none() => col.name.name.to_uppercase(),
1148 _ => "DAY".to_string(),
1149 };
1150 let unit = match unit_name.as_str() {
1151 "YEAR" | "YEARS" | "YY" | "YYYY" => crate::expressions::IntervalUnit::Year,
1152 "QUARTER" | "QUARTERS" | "QQ" | "Q" => {
1153 crate::expressions::IntervalUnit::Quarter
1154 }
1155 "MONTH" | "MONTHS" | "MM" | "M" => crate::expressions::IntervalUnit::Month,
1156 "WEEK" | "WEEKS" | "WK" | "WW" => crate::expressions::IntervalUnit::Week,
1157 "DAY" | "DAYS" | "DD" | "D" | "DAYOFMONTH" => {
1158 crate::expressions::IntervalUnit::Day
1159 }
1160 "HOUR" | "HOURS" | "HH" => crate::expressions::IntervalUnit::Hour,
1161 "MINUTE" | "MINUTES" | "MI" | "N" => crate::expressions::IntervalUnit::Minute,
1162 "SECOND" | "SECONDS" | "SS" | "S" => crate::expressions::IntervalUnit::Second,
1163 "MILLISECOND" | "MILLISECONDS" | "MS" => {
1164 crate::expressions::IntervalUnit::Millisecond
1165 }
1166 "MICROSECOND" | "MICROSECONDS" | "US" => {
1167 crate::expressions::IntervalUnit::Microsecond
1168 }
1169 _ => crate::expressions::IntervalUnit::Day,
1170 };
1171 Ok(Expression::DateAdd(Box::new(
1172 crate::expressions::DateAddFunc {
1173 this: date,
1174 interval: amount,
1175 unit,
1176 },
1177 )))
1178 }
1179 "DATE_ADD" => Ok(Expression::Function(Box::new(Function::new(
1180 "DATE_ADD".to_string(),
1181 f.args,
1182 )))),
1183
1184 "DATEDIFF" => Ok(Expression::Function(Box::new(Function::new(
1186 "DATE_DIFF".to_string(),
1187 f.args,
1188 )))),
1189
1190 "TIMESTAMPDIFF" => Ok(Expression::Function(Box::new(Function::new(
1192 "TIMESTAMP_DIFF".to_string(),
1193 f.args,
1194 )))),
1195
1196 "NEWID" | "UUID" => Ok(Expression::Function(Box::new(Function::new(
1203 "GENERATE_UUID".to_string(),
1204 vec![],
1205 )))),
1206
1207 "LEVENSHTEIN" => Ok(Expression::Function(Box::new(Function::new(
1209 "EDIT_DISTANCE".to_string(),
1210 f.args,
1211 )))),
1212
1213 "UNIX_TIMESTAMP" => Ok(Expression::Function(Box::new(Function::new(
1215 "UNIX_SECONDS".to_string(),
1216 f.args,
1217 )))),
1218
1219 "FROM_UNIXTIME" => Ok(Expression::Function(Box::new(Function::new(
1221 "TIMESTAMP_SECONDS".to_string(),
1222 f.args,
1223 )))),
1224
1225 "CHAR_LENGTH" | "CHARACTER_LENGTH" => Ok(Expression::Function(Box::new(
1227 Function::new("LENGTH".to_string(), f.args),
1228 ))),
1229
1230 "OCTET_LENGTH" => Ok(Expression::Function(Box::new(Function::new(
1232 "BYTE_LENGTH".to_string(),
1233 f.args,
1234 )))),
1235
1236 "JSON_EXTRACT_STRING_ARRAY" => Ok(Expression::Function(Box::new(Function::new(
1238 "JSON_VALUE_ARRAY".to_string(),
1239 f.args,
1240 )))),
1241
1242 "SPLIT" if f.args.len() == 1 => {
1247 let mut args = f.args;
1248 args.push(Expression::Literal(Box::new(Literal::String(
1249 ",".to_string(),
1250 ))));
1251 Ok(Expression::Split(Box::new(SplitFunc {
1252 this: args.remove(0),
1253 delimiter: args.remove(0),
1254 })))
1255 }
1256
1257 "SPLIT" if f.args.len() == 2 => {
1259 let mut args = f.args;
1260 Ok(Expression::Split(Box::new(SplitFunc {
1261 this: args.remove(0),
1262 delimiter: args.remove(0),
1263 })))
1264 }
1265
1266 "REGEXP_SUBSTR" if f.args.len() >= 2 => {
1268 let args = if f.args.len() > 4 {
1270 f.args[..4].to_vec()
1271 } else {
1272 f.args
1273 };
1274 Ok(Expression::Function(Box::new(Function::new(
1275 "REGEXP_EXTRACT".to_string(),
1276 args,
1277 ))))
1278 }
1279 "REGEXP_SUBSTR" => Ok(Expression::Function(Box::new(Function::new(
1280 "REGEXP_EXTRACT".to_string(),
1281 f.args,
1282 )))),
1283
1284 "REGEXP_REPLACE" if f.args.len() > 3 => {
1286 let args = f.args[..3].to_vec();
1287 Ok(Expression::Function(Box::new(Function::new(
1288 "REGEXP_REPLACE".to_string(),
1289 args,
1290 ))))
1291 }
1292
1293 "OBJECT_CONSTRUCT_KEEP_NULL" => Ok(Expression::Function(Box::new(Function::new(
1295 "JSON_OBJECT".to_string(),
1296 f.args,
1297 )))),
1298
1299 "EDITDISTANCE" if f.args.len() == 3 => {
1301 let col1 = f.args[0].clone();
1302 let col2 = f.args[1].clone();
1303 let max_dist = f.args[2].clone();
1304 Ok(Expression::Function(Box::new(Function::new(
1305 "EDIT_DISTANCE".to_string(),
1306 vec![
1307 col1,
1308 col2,
1309 Expression::NamedArgument(Box::new(crate::expressions::NamedArgument {
1310 name: crate::expressions::Identifier::new("max_distance".to_string()),
1311 value: max_dist,
1312 separator: crate::expressions::NamedArgSeparator::DArrow,
1313 })),
1314 ],
1315 ))))
1316 }
1317 "EDITDISTANCE" if f.args.len() == 2 => Ok(Expression::Function(Box::new(
1318 Function::new("EDIT_DISTANCE".to_string(), f.args),
1319 ))),
1320
1321 "HEX_DECODE_BINARY" => Ok(Expression::Function(Box::new(Function::new(
1323 "FROM_HEX".to_string(),
1324 f.args,
1325 )))),
1326
1327 "PARSE_DATE"
1330 | "PARSE_DATETIME"
1331 | "PARSE_TIMESTAMP"
1332 | "SAFE.PARSE_DATE"
1333 | "SAFE.PARSE_DATETIME"
1334 | "SAFE.PARSE_TIMESTAMP" => {
1335 let args = self.normalize_time_format_args(f.args);
1336 Ok(Expression::Function(Box::new(Function {
1337 name: f.name,
1338 args,
1339 distinct: f.distinct,
1340 no_parens: f.no_parens,
1341 trailing_comments: f.trailing_comments,
1342 quoted: f.quoted,
1343 use_bracket_syntax: f.use_bracket_syntax,
1344 span: None,
1345 inferred_type: None,
1346 })))
1347 }
1348
1349 "GET_PATH" if f.args.len() == 2 => {
1351 let mut args = f.args;
1352 let this = args.remove(0);
1353 let path = args.remove(0);
1354 let json_path = match &path {
1355 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::String(_)) => {
1356 let Literal::String(s) = lit.as_ref() else {
1357 unreachable!()
1358 };
1359 let normalized = if s.starts_with('$') {
1360 s.clone()
1361 } else if s.starts_with('[') {
1362 format!("${}", s)
1363 } else {
1364 format!("$.{}", s)
1365 };
1366 Expression::Literal(Box::new(Literal::String(normalized)))
1367 }
1368 _ => path,
1369 };
1370 Ok(Expression::JsonExtract(Box::new(JsonExtractFunc {
1371 this,
1372 path: json_path,
1373 returning: None,
1374 arrow_syntax: false,
1375 hash_arrow_syntax: false,
1376 wrapper_option: None,
1377 quotes_option: None,
1378 on_scalar_string: false,
1379 on_error: None,
1380 })))
1381 }
1382
1383 _ => Ok(Expression::Function(Box::new(f))),
1385 }
1386 }
1387
1388 fn transform_aggregate_function(
1389 &self,
1390 f: Box<crate::expressions::AggregateFunction>,
1391 ) -> Result<Expression> {
1392 let name_upper = f.name.to_uppercase();
1393 match name_upper.as_str() {
1394 "GROUP_CONCAT" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
1396 Function::new("STRING_AGG".to_string(), f.args),
1397 ))),
1398
1399 _ => Ok(Expression::AggregateFunction(f)),
1401 }
1402 }
1403
1404 fn transform_method_call(&self, mc: crate::expressions::MethodCall) -> Result<Expression> {
1407 use crate::expressions::MethodCall;
1408
1409 if let Expression::Column(ref col) = mc.this {
1411 if col.name.name.eq_ignore_ascii_case("SAFE") {
1412 let method_upper = mc.method.name.to_uppercase();
1413 if method_upper == "PARSE_DATE"
1414 || method_upper == "PARSE_DATETIME"
1415 || method_upper == "PARSE_TIMESTAMP"
1416 {
1417 let args = self.normalize_time_format_args(mc.args);
1419 return Ok(Expression::MethodCall(Box::new(MethodCall {
1420 this: mc.this,
1421 method: mc.method,
1422 args,
1423 })));
1424 }
1425 }
1426 }
1427
1428 Ok(Expression::MethodCall(Box::new(mc)))
1430 }
1431
1432 fn normalize_time_format_args(&self, args: Vec<Expression>) -> Vec<Expression> {
1435 args.into_iter()
1436 .enumerate()
1437 .map(|(i, arg)| {
1438 if i == 0 {
1440 if let Expression::Literal(ref lit) = arg {
1441 if let Literal::String(s) = lit.as_ref() {
1442 let normalized = self.normalize_time_format(&s);
1443 return Expression::Literal(Box::new(Literal::String(normalized)));
1444 }
1445 }
1446 }
1447 arg
1448 })
1449 .collect()
1450 }
1451
1452 fn normalize_time_format(&self, format: &str) -> String {
1456 format.replace("%Y-%m-%d", "%F").replace("%H:%M:%S", "%T")
1457 }
1458
1459 fn bq_cast_format_to_strftime(format_expr: &Expression) -> Expression {
1462 use crate::expressions::Literal;
1463 if let Expression::Literal(lit) = format_expr {
1464 if let Literal::String(s) = lit.as_ref() {
1465 let result = s
1466 .replace("YYYYMMDD", "%Y%m%d")
1467 .replace("YYYY", "%Y")
1468 .replace("YY", "%y")
1469 .replace("MONTH", "%B")
1470 .replace("MON", "%b")
1471 .replace("MM", "%m")
1472 .replace("DD", "%d")
1473 .replace("HH24", "%H")
1474 .replace("HH12", "%I")
1475 .replace("HH", "%I")
1476 .replace("MI", "%M")
1477 .replace("SSTZH", "%S%z")
1478 .replace("SS", "%S")
1479 .replace("TZH", "%z");
1480 let normalized = result.replace("%Y-%m-%d", "%F").replace("%H:%M:%S", "%T");
1482 return Expression::Literal(Box::new(Literal::String(normalized)));
1483 }
1484 }
1485 format_expr.clone()
1486 }
1487}
1488
1489#[cfg(test)]
1490mod tests {
1491 use super::*;
1492 use crate::dialects::Dialect;
1493 use crate::parse_one;
1494
1495 fn transpile_to_bigquery(sql: &str) -> String {
1496 let dialect = Dialect::get(DialectType::Generic);
1497 let result = dialect
1498 .transpile(sql, DialectType::BigQuery)
1499 .expect("Transpile failed");
1500 result[0].clone()
1501 }
1502
1503 #[test]
1504 fn test_ifnull_identity() {
1505 let result = transpile_to_bigquery("SELECT IFNULL(a, b)");
1507 assert!(
1508 result.contains("COALESCE"),
1509 "Expected COALESCE, got: {}",
1510 result
1511 );
1512 }
1513
1514 #[test]
1515 fn test_nvl_to_ifnull() {
1516 let result = transpile_to_bigquery("SELECT NVL(a, b)");
1518 assert!(
1519 result.contains("IFNULL"),
1520 "Expected IFNULL, got: {}",
1521 result
1522 );
1523 }
1524
1525 #[test]
1526 fn test_try_cast_to_safe_cast() {
1527 let result = transpile_to_bigquery("SELECT TRY_CAST(a AS INT)");
1528 assert!(
1529 result.contains("SAFE_CAST"),
1530 "Expected SAFE_CAST, got: {}",
1531 result
1532 );
1533 }
1534
1535 #[test]
1536 fn test_random_to_rand() {
1537 let result = transpile_to_bigquery("SELECT RANDOM()");
1538 assert!(result.contains("RAND"), "Expected RAND, got: {}", result);
1539 }
1540
1541 #[test]
1542 fn test_basic_select() {
1543 let result = transpile_to_bigquery("SELECT a, b FROM users WHERE id = 1");
1544 assert!(result.contains("SELECT"));
1545 assert!(result.contains("FROM users"));
1546 }
1547
1548 #[test]
1549 fn test_group_concat_to_string_agg() {
1550 let result = transpile_to_bigquery("SELECT GROUP_CONCAT(name)");
1551 assert!(
1552 result.contains("STRING_AGG"),
1553 "Expected STRING_AGG, got: {}",
1554 result
1555 );
1556 }
1557
1558 #[test]
1559 fn test_generate_series_to_generate_array() {
1560 let result = transpile_to_bigquery("SELECT GENERATE_SERIES(1, 10)");
1561 assert!(
1562 result.contains("GENERATE_ARRAY"),
1563 "Expected GENERATE_ARRAY, got: {}",
1564 result
1565 );
1566 }
1567
1568 #[test]
1569 fn test_backtick_identifiers() {
1570 let dialect = BigQueryDialect;
1572 let config = dialect.generator_config();
1573 assert_eq!(config.identifier_quote, '`');
1574 }
1575
1576 fn bigquery_identity(sql: &str, expected: &str) {
1577 let dialect = Dialect::get(DialectType::BigQuery);
1578 let ast = dialect.parse(sql).expect("Parse failed");
1579 let transformed = dialect.transform(ast[0].clone()).expect("Transform failed");
1580 let result = dialect.generate(&transformed).expect("Generate failed");
1581 assert_eq!(result, expected, "SQL: {}", sql);
1582 }
1583
1584 #[test]
1585 fn test_cast_char_to_string() {
1586 bigquery_identity("CAST(x AS CHAR)", "CAST(x AS STRING)");
1587 }
1588
1589 #[test]
1590 fn test_cast_varchar_to_string() {
1591 bigquery_identity("CAST(x AS VARCHAR)", "CAST(x AS STRING)");
1592 }
1593
1594 #[test]
1595 fn test_cast_nchar_to_string() {
1596 bigquery_identity("CAST(x AS NCHAR)", "CAST(x AS STRING)");
1597 }
1598
1599 #[test]
1600 fn test_cast_nvarchar_to_string() {
1601 bigquery_identity("CAST(x AS NVARCHAR)", "CAST(x AS STRING)");
1602 }
1603
1604 #[test]
1605 fn test_cast_timestamptz_to_timestamp() {
1606 bigquery_identity("CAST(x AS TIMESTAMPTZ)", "CAST(x AS TIMESTAMP)");
1607 }
1608
1609 #[test]
1610 fn test_cast_record_to_struct() {
1611 bigquery_identity("CAST(x AS RECORD)", "CAST(x AS STRUCT)");
1612 }
1613
1614 #[test]
1615 fn test_json_literal_to_parse_json() {
1616 bigquery_identity(
1618 "SELECT JSON '\"foo\"' AS json_data",
1619 "SELECT PARSE_JSON('\"foo\"') AS json_data",
1620 );
1621 }
1622
1623 #[test]
1624 fn test_grant_as_alias_not_quoted() {
1625 bigquery_identity(
1627 "SELECT GRANT FROM (SELECT 'input' AS GRANT)",
1628 "SELECT GRANT FROM (SELECT 'input' AS GRANT)",
1629 );
1630 }
1631
1632 #[test]
1633 fn test_timestamp_literal_to_cast() {
1634 bigquery_identity(
1636 "CREATE VIEW `d.v` OPTIONS (expiration_timestamp=TIMESTAMP '2020-01-02T04:05:06.007Z') AS SELECT 1 AS c",
1637 "CREATE VIEW `d.v` OPTIONS (expiration_timestamp=CAST('2020-01-02T04:05:06.007Z' AS TIMESTAMP)) AS SELECT 1 AS c"
1638 );
1639 }
1640
1641 #[test]
1642 fn test_date_literal_to_cast_in_extract() {
1643 bigquery_identity(
1645 "EXTRACT(WEEK(THURSDAY) FROM DATE '2013-12-25')",
1646 "EXTRACT(WEEK(THURSDAY) FROM CAST('2013-12-25' AS DATE))",
1647 );
1648 }
1649
1650 #[test]
1651 fn test_json_object_with_json_literals() {
1652 bigquery_identity(
1654 "SELECT JSON_OBJECT('a', JSON '10') AS json_data",
1655 "SELECT JSON_OBJECT('a', PARSE_JSON('10')) AS json_data",
1656 );
1657 }
1658
1659 #[test]
1664 fn test_safe_parse_date_format_normalization() {
1665 bigquery_identity(
1667 "SAFE.PARSE_DATE('%Y-%m-%d', '2024-01-15')",
1668 "SAFE.PARSE_DATE('%F', '2024-01-15')",
1669 );
1670 }
1671
1672 #[test]
1673 fn test_safe_parse_datetime_format_normalization() {
1674 bigquery_identity(
1676 "SAFE.PARSE_DATETIME('%Y-%m-%d %H:%M:%S', '2024-01-15 10:30:00')",
1677 "SAFE.PARSE_DATETIME('%F %T', '2024-01-15 10:30:00')",
1678 );
1679 }
1680
1681 #[test]
1682 fn test_safe_parse_timestamp_format_normalization() {
1683 bigquery_identity(
1685 "SAFE.PARSE_TIMESTAMP('%Y-%m-%d %H:%M:%S', '2024-01-15 10:30:00')",
1686 "SAFE.PARSE_TIMESTAMP('%F %T', '2024-01-15 10:30:00')",
1687 );
1688 }
1689
1690 #[test]
1691 fn test_datetime_literal_to_cast() {
1692 bigquery_identity(
1694 "LAST_DAY(DATETIME '2008-11-10 15:30:00', WEEK(SUNDAY))",
1695 "LAST_DAY(CAST('2008-11-10 15:30:00' AS DATETIME), WEEK)",
1696 );
1697 }
1698
1699 #[test]
1700 fn test_last_day_week_modifier_stripped() {
1701 bigquery_identity("LAST_DAY(col, WEEK(MONDAY))", "LAST_DAY(col, WEEK)");
1703 }
1704
1705 #[test]
1706 fn test_hash_line_comment_parses() {
1707 let result = parse_one("SELECT 1 as a #hello world", DialectType::BigQuery);
1710 assert!(result.is_ok(), "Expected parse to succeed, got: {result:?}");
1711 }
1712}