Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions src/arithmetic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -459,10 +459,13 @@ mod tests {
}

#[test]
fn arithmetic_scalar(){
fn arithmetic_scalar() {
let qs = "56";
let res = arithmetic(qs.as_bytes());
assert!(res.is_err());
assert_eq!(nom::Err::Error(nom::error::Error::new(qs.as_bytes(), ErrorKind::Tag)), res.err().unwrap());
assert_eq!(
nom::Err::Error(nom::error::Error::new(qs.as_bytes(), ErrorKind::Tag)),
res.err().unwrap()
);
}
}
160 changes: 123 additions & 37 deletions src/common.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use nom::branch::alt;
use nom::character::complete::{alphanumeric1, digit1, line_ending, multispace0, multispace1};
use nom::character::is_alphanumeric;
use nom::combinator::{map, not, peek};
use nom::combinator::{into, map, not, peek};
use nom::{IResult, InputLength, Parser};
use std::fmt::{self, Display};
use std::str;
Expand All @@ -16,7 +16,9 @@ use nom::combinator::opt;
use nom::error::{ErrorKind, ParseError};
use nom::multi::{fold_many0, many0, many1, separated_list0};
use nom::sequence::{delimited, pair, preceded, separated_pair, terminated, tuple};
use table::Table;
use select::join_clause;
use table::{Table, TableObject, TablePartition, TablePartitionList};
use JoinClause;

#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub enum SqlType {
Expand Down Expand Up @@ -388,7 +390,7 @@ where
let (inp, _) = first.parse(inp)?;
let (inp, o2) = second.parse(inp)?;
third.parse(inp).map(|(i, _)| (i, o2))
},
}
}
}
}
Expand Down Expand Up @@ -641,7 +643,8 @@ pub fn function_argument_parser(i: &[u8]) -> IResult<&[u8], FunctionArgument> {
// present.
pub fn function_arguments(i: &[u8]) -> IResult<&[u8], (FunctionArgument, bool)> {
let distinct_parser = opt(tuple((tag_no_case("distinct"), multispace1)));
let (remaining_input, (distinct, args)) = tuple((distinct_parser, function_argument_parser))(i)?;
let (remaining_input, (distinct, args)) =
tuple((distinct_parser, function_argument_parser))(i)?;
Ok((remaining_input, (args, distinct.is_some())))
}

Expand Down Expand Up @@ -695,12 +698,25 @@ pub fn column_function(i: &[u8]) -> IResult<&[u8], FunctionExpression> {
FunctionExpression::GroupConcat(FunctionArgument::Column(col.clone()), sep)
},
),
map(tuple((sql_identifier, multispace0, tag("("), separated_list0(tag(","), delimited(multispace0, function_argument_parser, multispace0)), tag(")"))), |tuple| {
let (name, _, _, arguments, _) = tuple;
FunctionExpression::Generic(
str::from_utf8(name).unwrap().to_string(),
FunctionArguments::from(arguments))
})
map(
tuple((
sql_identifier,
multispace0,
tag("("),
separated_list0(
tag(","),
delimited(multispace0, function_argument_parser, multispace0),
),
tag(")"),
)),
|tuple| {
let (name, _, _, arguments, _) = tuple;
FunctionExpression::Generic(
str::from_utf8(name).unwrap().to_string(),
FunctionArguments::from(arguments),
)
},
),
))(i)
}

Expand Down Expand Up @@ -893,6 +909,51 @@ pub fn table_list(i: &[u8]) -> IResult<&[u8], Vec<Table>> {
many0(terminated(schema_table_reference, opt(ws_sep_comma)))(i)
}

pub fn table_object_list(i: &[u8]) -> IResult<&[u8], Vec<TableObject>> {
many0(terminated(table_object, opt(ws_sep_comma)))(i)
}

pub fn table_object(i: &[u8]) -> IResult<&[u8], TableObject> {
map(
tuple((
schema_table_reference,
opt(preceded(multispace0, table_partition_list)),
)),
|(table, pl)| TableObject {
table,
partitions: pl.unwrap_or(vec![].into()),
},
)(i)
}

pub fn table_partition_list(i: &[u8]) -> IResult<&[u8], TablePartitionList> {
let (remaining, (_, _, p, _, _)) = tuple((
tag_no_case("partition ("),
multispace0,
into(many1(terminated(
table_partition,
opt(tuple((multispace0, tag(","), multispace0))),
))),
multispace0,
tag(")"),
))(i)?;

Ok((remaining, p))
}

pub fn table_partition(i: &[u8]) -> IResult<&[u8], TablePartition> {
into(sql_identifier)(i)
}

pub fn from_clause(i: &[u8]) -> IResult<&[u8], Vec<TableObject>> {
let (i, (_, t)) = tuple((
delimited(multispace0, tag_no_case("from"), multispace0),
many1(terminated(table_object, opt(ws_sep_comma))),
))(i)?;

Ok((i, t))
}

// Integer literal value
pub fn integer_literal(i: &[u8]) -> IResult<&[u8], Literal> {
map(pair(opt(tag("-")), digit1), |tup| {
Expand Down Expand Up @@ -1018,25 +1079,44 @@ pub fn value_list(i: &[u8]) -> IResult<&[u8], Vec<Literal>> {
many0(delimited(multispace0, literal, opt(ws_sep_comma)))(i)
}

pub fn relational_objects_clauses(i: &[u8]) -> IResult<&[u8], (Vec<TableObject>, Vec<JoinClause>)> {
match from_clause(i) {
Ok((i, f)) => {
let (i, j) = many0(join_clause)(i).unwrap_or((i, vec![]));

Ok((i, (f, j)))
}
Err(e) => {
if join_clause(i).is_ok() {
//TODO: needs a more helpful error once error handling is improved upon
Err(e)
} else {
Ok((i, (vec![], vec![])))
}
}
}
}

// Parse a reference to a named schema.table, with an optional alias
pub fn schema_table_reference(i: &[u8]) -> IResult<&[u8], Table> {
map(
tuple((
opt(pair(sql_identifier, tag("."))),
sql_identifier,
opt(as_alias)
)),
|tup| Table {
name: String::from(str::from_utf8(tup.1).unwrap()),
alias: match tup.2 {
Some(a) => Some(String::from(a)),
None => None,
},
schema: match tup.0 {
Some((schema, _)) => Some(String::from(str::from_utf8(schema).unwrap())),
None => None,
tuple((
opt(pair(sql_identifier, tag("."))),
sql_identifier,
opt(as_alias),
)),
|tup| Table {
name: String::from(str::from_utf8(tup.1).unwrap()),
alias: match tup.2 {
Some(a) => Some(String::from(a)),
None => None,
},
schema: match tup.0 {
Some((schema, _)) => Some(String::from(str::from_utf8(schema).unwrap())),
None => None,
},
},
})(i)
)(i)
}

// Parse a reference to a named table, with an optional alias
Expand All @@ -1047,7 +1127,7 @@ pub fn table_reference(i: &[u8]) -> IResult<&[u8], Table> {
Some(a) => Some(String::from(a)),
None => None,
},
schema: None,
schema: None,
})(i)
}

Expand Down Expand Up @@ -1137,25 +1217,31 @@ mod tests {
name: String::from("max(addr_id)"),
alias: None,
table: None,
function: Some(Box::new(FunctionExpression::Max(
FunctionArgument::Column(Column::from("addr_id")),
))),
function: Some(Box::new(FunctionExpression::Max(FunctionArgument::Column(
Column::from("addr_id"),
)))),
};
assert_eq!(res.unwrap().1, expected);
}

#[test]
fn simple_generic_function() {
let qlist = ["coalesce(a,b,c)".as_bytes(), "coalesce (a,b,c)".as_bytes(), "coalesce(a ,b,c)".as_bytes(), "coalesce(a, b,c)".as_bytes()];
let qlist = [
"coalesce(a,b,c)".as_bytes(),
"coalesce (a,b,c)".as_bytes(),
"coalesce(a ,b,c)".as_bytes(),
"coalesce(a, b,c)".as_bytes(),
];
for q in qlist.iter() {
let res = column_function(q);
let expected = FunctionExpression::Generic("coalesce".to_string(),
FunctionArguments::from(
vec!(
FunctionArgument::Column(Column::from("a")),
FunctionArgument::Column(Column::from("b")),
FunctionArgument::Column(Column::from("c"))
)));
let expected = FunctionExpression::Generic(
"coalesce".to_string(),
FunctionArguments::from(vec![
FunctionArgument::Column(Column::from("a")),
FunctionArgument::Column(Column::from("b")),
FunctionArgument::Column(Column::from("c")),
]),
);
assert_eq!(res, Ok((&b""[..], expected)));
}
}
Expand Down
26 changes: 16 additions & 10 deletions src/compound_select.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ mod tests {
use super::*;
use column::Column;
use common::{FieldDefinitionExpression, FieldValueExpression, Literal};
use table::Table;
use table::TableObject;

#[test]
fn union() {
Expand All @@ -143,7 +143,7 @@ mod tests {
let res2 = compound_selection(qstr2.as_bytes());

let first_select = SelectStatement {
tables: vec![Table::from("Vote")],
tables: vec![TableObject::from("Vote")],
fields: vec![
FieldDefinitionExpression::Col(Column::from("id")),
FieldDefinitionExpression::Value(FieldValueExpression::Literal(
Expand All @@ -153,7 +153,7 @@ mod tests {
..Default::default()
};
let second_select = SelectStatement {
tables: vec![Table::from("Rating")],
tables: vec![TableObject::from("Rating")],
fields: vec![
FieldDefinitionExpression::Col(Column::from("id")),
FieldDefinitionExpression::Col(Column::from("stars")),
Expand Down Expand Up @@ -185,12 +185,18 @@ mod tests {
assert!(&res.is_err());
assert_eq!(
res.unwrap_err(),
nom::Err::Error(nom::error::Error::new(");".as_bytes(), nom::error::ErrorKind::Tag))
nom::Err::Error(nom::error::Error::new(
");".as_bytes(),
nom::error::ErrorKind::Tag
))
);
assert!(&res2.is_err());
assert_eq!(
res2.unwrap_err(),
nom::Err::Error(nom::error::Error::new(";".as_bytes(), nom::error::ErrorKind::Tag))
nom::Err::Error(nom::error::Error::new(
";".as_bytes(),
nom::error::ErrorKind::Tag
))
);
assert!(&res3.is_err());
assert_eq!(
Expand All @@ -210,7 +216,7 @@ mod tests {
let res = compound_selection(qstr.as_bytes());

let first_select = SelectStatement {
tables: vec![Table::from("Vote")],
tables: vec![TableObject::from("Vote")],
fields: vec![
FieldDefinitionExpression::Col(Column::from("id")),
FieldDefinitionExpression::Value(FieldValueExpression::Literal(
Expand All @@ -220,15 +226,15 @@ mod tests {
..Default::default()
};
let second_select = SelectStatement {
tables: vec![Table::from("Rating")],
tables: vec![TableObject::from("Rating")],
fields: vec![
FieldDefinitionExpression::Col(Column::from("id")),
FieldDefinitionExpression::Col(Column::from("stars")),
],
..Default::default()
};
let third_select = SelectStatement {
tables: vec![Table::from("Vote")],
tables: vec![TableObject::from("Vote")],
fields: vec![
FieldDefinitionExpression::Value(FieldValueExpression::Literal(
Literal::Integer(42).into(),
Expand Down Expand Up @@ -259,7 +265,7 @@ mod tests {
let res = compound_selection(qstr.as_bytes());

let first_select = SelectStatement {
tables: vec![Table::from("Vote")],
tables: vec![TableObject::from("Vote")],
fields: vec![
FieldDefinitionExpression::Col(Column::from("id")),
FieldDefinitionExpression::Value(FieldValueExpression::Literal(
Expand All @@ -269,7 +275,7 @@ mod tests {
..Default::default()
};
let second_select = SelectStatement {
tables: vec![Table::from("Rating")],
tables: vec![TableObject::from("Rating")],
fields: vec![
FieldDefinitionExpression::Col(Column::from("id")),
FieldDefinitionExpression::Col(Column::from("stars")),
Expand Down
Loading