Skip to content

Commit 31895b5

Browse files
committed
feat: Add APPROXIMATE function keyword support
1 parent 2b18e22 commit 31895b5

File tree

7 files changed

+85
-0
lines changed

7 files changed

+85
-0
lines changed

src/ast/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2231,10 +2231,15 @@ pub struct Function {
22312231
// aggregate functions may specify eg `COUNT(DISTINCT x)`
22322232
pub distinct: bool,
22332233
pub special: bool,
2234+
// Redshift provides `APPROXIMATE` option for some functions, e.g. `COUNT`
2235+
pub approximate: bool,
22342236
}
22352237

22362238
impl fmt::Display for Function {
22372239
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2240+
if self.approximate {
2241+
write!(f, "APPROXIMATE ")?;
2242+
}
22382243
if self.special {
22392244
write!(f, "{}", self.name)?;
22402245
} else {

src/keywords.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ define_keywords!(
7777
AND,
7878
ANY,
7979
APPLY,
80+
APPROXIMATE,
8081
ARE,
8182
ARRAY,
8283
ARRAY_AGG,

src/parser.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,17 @@ impl<'a> Parser<'a> {
330330
}
331331
}
332332
}
333+
Token::Word(w)
334+
if dialect_of!(self is RedshiftSqlDialect | PostgreSqlDialect | GenericDialect)
335+
&& w.keyword == Keyword::APPROXIMATE
336+
&& self.peek_token() != Token::Comma =>
337+
{
338+
let mut expr = self.parse_expr()?;
339+
if let Expr::Function(fun) = &mut expr {
340+
fun.approximate = true;
341+
return Ok(WildcardExpr::Expr(expr));
342+
}
343+
}
333344
Token::Mul => {
334345
return Ok(WildcardExpr::Wildcard);
335346
}
@@ -433,6 +444,7 @@ impl<'a> Parser<'a> {
433444
over: None,
434445
distinct: false,
435446
special: true,
447+
approximate: false,
436448
}))
437449
}
438450
Keyword::CURRENT_TIMESTAMP
@@ -620,6 +632,7 @@ impl<'a> Parser<'a> {
620632
over,
621633
distinct,
622634
special: false,
635+
approximate: false,
623636
}))
624637
}
625638

@@ -635,6 +648,7 @@ impl<'a> Parser<'a> {
635648
over: None,
636649
distinct: false,
637650
special: false,
651+
approximate: false,
638652
}))
639653
}
640654

tests/sqpparser_clickhouse.rs renamed to tests/sqlparser_clickhouse.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ fn parse_map_access_expr() {
5252
over: None,
5353
distinct: false,
5454
special: false,
55+
approximate: false,
5556
})],
5657
})],
5758
into: None,
@@ -88,6 +89,7 @@ fn parse_map_access_expr() {
8889
over: None,
8990
distinct: false,
9091
special: false,
92+
approximate: false,
9193
})]
9294
}),
9395
op: BinaryOperator::NotEq,

tests/sqlparser_common.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,7 @@ fn parse_select_count_wildcard() {
511511
over: None,
512512
distinct: false,
513513
special: false,
514+
approximate: false,
514515
}),
515516
expr_from_projection(only(&select.projection))
516517
);
@@ -530,6 +531,7 @@ fn parse_select_count_distinct() {
530531
over: None,
531532
distinct: true,
532533
special: false,
534+
approximate: false,
533535
}),
534536
expr_from_projection(only(&select.projection))
535537
);
@@ -1335,6 +1337,7 @@ fn parse_select_having() {
13351337
over: None,
13361338
distinct: false,
13371339
special: false,
1340+
approximate: false,
13381341
})),
13391342
op: BinaryOperator::Gt,
13401343
right: Box::new(Expr::Value(number("1")))
@@ -2325,6 +2328,7 @@ fn parse_scalar_function_in_projection() {
23252328
over: None,
23262329
distinct: false,
23272330
special: false,
2331+
approximate: false,
23282332
}),
23292333
expr_from_projection(only(&select.projection))
23302334
);
@@ -2404,6 +2408,7 @@ fn parse_named_argument_function() {
24042408
over: None,
24052409
distinct: false,
24062410
special: false,
2411+
approximate: false,
24072412
}),
24082413
expr_from_projection(only(&select.projection))
24092414
);
@@ -2438,6 +2443,7 @@ fn parse_window_functions() {
24382443
}),
24392444
distinct: false,
24402445
special: false,
2446+
approximate: false,
24412447
}),
24422448
expr_from_projection(&select.projection[0])
24432449
);
@@ -2547,6 +2553,7 @@ fn parse_expr_interval() {
25472553
over: None,
25482554
distinct: false,
25492555
special: false,
2556+
approximate: false,
25502557
});
25512558

25522559
assert_eq!(
@@ -2579,6 +2586,7 @@ fn parse_expr_interval() {
25792586
over: None,
25802587
distinct: false,
25812588
special: false,
2589+
approximate: false,
25822590
});
25832591
assert_eq!(
25842592
&Expr::Value(Value::Interval {
@@ -2724,6 +2732,7 @@ fn parse_at_timezone() {
27242732
over: None,
27252733
distinct: false,
27262734
special: false,
2735+
approximate: false,
27272736
})),
27282737
time_zone: "UTC-06:00".to_string()
27292738
},
@@ -2750,6 +2759,7 @@ fn parse_at_timezone() {
27502759
over: None,
27512760
distinct: false,
27522761
special: false,
2762+
approximate: false,
27532763
},)),
27542764
time_zone: "UTC-06:00".to_string(),
27552765
},),),
@@ -2760,6 +2770,7 @@ fn parse_at_timezone() {
27602770
over: None,
27612771
distinct: false,
27622772
special: false,
2773+
approximate: false,
27632774
},),
27642775
alias: Ident {
27652776
value: "hour".to_string(),
@@ -2796,6 +2807,7 @@ fn parse_table_function() {
27962807
over: None,
27972808
distinct: false,
27982809
special: false,
2810+
approximate: false,
27992811
});
28002812
assert_eq!(expr, expected_expr);
28012813
assert_eq!(alias, table_alias("a"))
@@ -2853,6 +2865,7 @@ fn parse_delimited_identifiers() {
28532865
over: None,
28542866
distinct: false,
28552867
special: false,
2868+
approximate: false,
28562869
}),
28572870
expr_from_projection(&select.projection[1]),
28582871
);
@@ -4763,6 +4776,7 @@ fn parse_time_functions() {
47634776
over: None,
47644777
distinct: false,
47654778
special: false,
4779+
approximate: false,
47664780
}),
47674781
expr_from_projection(&select.projection[0])
47684782
);
@@ -4779,6 +4793,7 @@ fn parse_time_functions() {
47794793
over: None,
47804794
distinct: false,
47814795
special: false,
4796+
approximate: false,
47824797
}),
47834798
expr_from_projection(&select.projection[0])
47844799
);
@@ -4795,6 +4810,7 @@ fn parse_time_functions() {
47954810
over: None,
47964811
distinct: false,
47974812
special: false,
4813+
approximate: false,
47984814
}),
47994815
expr_from_projection(&select.projection[0])
48004816
);
@@ -4811,6 +4827,7 @@ fn parse_time_functions() {
48114827
over: None,
48124828
distinct: false,
48134829
special: false,
4830+
approximate: false,
48144831
}),
48154832
expr_from_projection(&select.projection[0])
48164833
);
@@ -4827,6 +4844,7 @@ fn parse_time_functions() {
48274844
over: None,
48284845
distinct: false,
48294846
special: false,
4847+
approximate: false,
48304848
}),
48314849
expr_from_projection(&select.projection[0])
48324850
);

tests/sqlparser_mysql.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -694,6 +694,7 @@ fn parse_insert_with_on_duplicate_update() {
694694
over: None,
695695
distinct: false,
696696
special: false,
697+
approximate: false,
697698
})
698699
},
699700
Assignment {
@@ -706,6 +707,7 @@ fn parse_insert_with_on_duplicate_update() {
706707
over: None,
707708
distinct: false,
708709
special: false,
710+
approximate: false,
709711
})
710712
},
711713
Assignment {
@@ -718,6 +720,7 @@ fn parse_insert_with_on_duplicate_update() {
718720
over: None,
719721
distinct: false,
720722
special: false,
723+
approximate: false,
721724
})
722725
},
723726
Assignment {
@@ -730,6 +733,7 @@ fn parse_insert_with_on_duplicate_update() {
730733
over: None,
731734
distinct: false,
732735
special: false,
736+
approximate: false,
733737
})
734738
},
735739
Assignment {
@@ -742,6 +746,7 @@ fn parse_insert_with_on_duplicate_update() {
742746
over: None,
743747
distinct: false,
744748
special: false,
749+
approximate: false,
745750
})
746751
},
747752
])),

tests/sqlparser_postgres.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1418,6 +1418,7 @@ fn parse_current_functions() {
14181418
over: None,
14191419
distinct: false,
14201420
special: true,
1421+
approximate: false,
14211422
}),
14221423
expr_from_projection(&select.projection[0])
14231424
);
@@ -1428,6 +1429,7 @@ fn parse_current_functions() {
14281429
over: None,
14291430
distinct: false,
14301431
special: true,
1432+
approximate: false,
14311433
}),
14321434
expr_from_projection(&select.projection[1])
14331435
);
@@ -1438,6 +1440,7 @@ fn parse_current_functions() {
14381440
over: None,
14391441
distinct: false,
14401442
special: true,
1443+
approximate: false,
14411444
}),
14421445
expr_from_projection(&select.projection[2])
14431446
);
@@ -1448,6 +1451,7 @@ fn parse_current_functions() {
14481451
over: None,
14491452
distinct: false,
14501453
special: true,
1454+
approximate: false,
14511455
}),
14521456
expr_from_projection(&select.projection[3])
14531457
);
@@ -1571,3 +1575,39 @@ fn parse_pg_extract() {
15711575
res.unwrap_err()
15721576
);
15731577
}
1578+
1579+
#[test]
1580+
fn parse_approximate_count() {
1581+
let sql = "SELECT APPROXIMATE COUNT(DISTINCT column)";
1582+
let select = pg_and_generic().verified_only_select(sql);
1583+
assert_eq!(
1584+
&Expr::Function(Function {
1585+
name: ObjectName(vec!["COUNT".into()]),
1586+
args: vec![FunctionArg::Unnamed(FunctionArgExpr::Expr(
1587+
Expr::Identifier(Ident::new("column"))
1588+
)),],
1589+
over: None,
1590+
distinct: true,
1591+
special: false,
1592+
approximate: true,
1593+
}),
1594+
expr_from_projection(only(&select.projection)),
1595+
);
1596+
1597+
let sql = "SELECT APPROXIMATE AS alias";
1598+
let select = pg_and_generic().verified_only_select(sql);
1599+
assert_eq!(
1600+
SelectItem::ExprWithAlias {
1601+
expr: Expr::Identifier(Ident::new("APPROXIMATE")),
1602+
alias: Ident::new("alias"),
1603+
},
1604+
select.projection[0]
1605+
);
1606+
1607+
let sql = "SELECT APPROXIMATE, COUNT(DISTINCT column)";
1608+
let select = pg_and_generic().verified_only_select(sql);
1609+
assert_eq!(
1610+
SelectItem::UnnamedExpr(Expr::Identifier(Ident::new("APPROXIMATE"))),
1611+
select.projection[0]
1612+
);
1613+
}

0 commit comments

Comments
 (0)