1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
use super::ParseError;
use crate::{Field, Fields, Groups, Idiom, Orders, Splits, Value};
use nom::Err;
use nom::Err::Failure;
/// Check to see whether the expression is in the SELECT clause
fn contains_idiom(fields: &Fields, idiom: &Idiom) -> bool {
fields.iter().any(|field| {
match field {
// There is a SELECT * expression, so presume everything is ok
Field::All => true,
// Check each field
Field::Single {
expr,
alias,
} => {
if let Some(i) = alias {
// This field is aliased, so check the alias name
i.as_ref() == idiom.as_ref()
} else {
// This field is not aliased, so check the field value
match expr {
// Use raw idiom (TODO: should this use `simplify`?)
Value::Idiom(i) => i.as_ref() == idiom.as_ref(),
// Check the expression
v => v.to_idiom().as_ref() == idiom.as_ref(),
}
}
}
}
})
}
pub fn check_split_on_fields<'a>(
i: &'a str,
fields: &Fields,
splits: &Option<Splits>,
) -> Result<(), Err<ParseError<&'a str>>> {
// Check to see if a SPLIT ON clause has been defined
if let Some(splits) = splits {
// Loop over each of the expressions in the SPLIT ON clause
for split in splits.iter() {
if !contains_idiom(fields, &split.0) {
// If the expression isn't specified in the SELECT clause, then error
return Err(Failure(ParseError::Split(i, split.to_string())));
}
}
}
// This query is ok to run
Ok(())
}
pub fn check_order_by_fields<'a>(
i: &'a str,
fields: &Fields,
orders: &Option<Orders>,
) -> Result<(), Err<ParseError<&'a str>>> {
// Check to see if a ORDER BY clause has been defined
if let Some(orders) = orders {
// Loop over each of the expressions in the ORDER BY clause
for order in orders.iter() {
if order.random {
// don't check for a field if the order is random.
continue;
}
if !contains_idiom(fields, order) {
// If the expression isn't specified in the SELECT clause, then error
return Err(Failure(ParseError::Order(i, order.to_string())));
}
}
}
// This query is ok to run
Ok(())
}
pub fn check_group_by_fields<'a>(
i: &'a str,
fields: &Fields,
groups: &Option<Groups>,
) -> Result<(), Err<ParseError<&'a str>>> {
// Check to see if a GROUP BY clause has been defined
if let Some(groups) = groups {
// Loop over each of the expressions in the GROUP BY clause
for group in groups.iter() {
if !contains_idiom(fields, &group.0) {
// If the expression isn't specified in the SELECT clause, then error
return Err(Failure(ParseError::Group(i, group.to_string())));
}
}
// Check if this is a GROUP ALL clause or a GROUP BY clause
if !groups.is_empty() {
// Loop over each of the expressions in the SELECT clause
'outer: for field in fields.iter() {
// Loop over each of the expressions in the GROUP BY clause
for group in groups.iter() {
// Check to see whether the expression is in the GROUP BY clause or is an aggregate
if let Field::Single {
expr,
alias,
} = field
{
if alias.as_ref().map(|i| i.as_ref() == group.as_ref()).unwrap_or(false) {
// This field is aliased, and the alias name matched
continue 'outer;
} else {
match expr {
// If the expression in the SELECT clause is a field, check to see if it exists in the GROUP BY
Value::Idiom(i) if i == &group.0 => continue 'outer,
// If the expression in the SELECT clause is a function, check to see if it is an aggregate function
Value::Function(f) if f.is_aggregate() => continue 'outer,
// Otherwise check if the expression itself exists in the GROUP BY clause
v if v.to_idiom() == group.0 => continue 'outer,
// Check if this is a static value which can be used in the GROUP BY clause
v if v.is_static() => continue 'outer,
// If not, then this query should fail
_ => (),
}
}
}
}
// If the expression isn't an aggregate function and isn't specified in the GROUP BY clause, then error
return Err(Failure(ParseError::Field(i, field.to_string())));
}
}
}
// This query is ok to run
Ok(())
}