Skip to content
Merged
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
102 changes: 30 additions & 72 deletions src/db/table/helpers/order_by_clause.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ pub fn apply_order_by_from_precomputed<T: Clone>(

fn perform_comparisons(row1: &Row, row2: &Row, order_by_clause: &OrderByClause) -> Ordering {
// TODO: small optimization: only compute subsequent selectables if the previous ordering resulted in equality
// Fletcher - I think this is done here? Can this comment be removed?
for (i, direction) in order_by_clause.directions.iter().enumerate() {
let ordering = row1[i].compare(&row2[i], direction);
if ordering != Ordering::Equal {
Expand All @@ -35,78 +36,35 @@ fn perform_comparisons(row1: &Row, row2: &Row, order_by_clause: &OrderByClause)

#[cfg(test)]
mod tests {
use crate::db::table::{ColumnDefinition, DataType, Row, RowStack, Table, Value};
use super::*;
use crate::db::table::{Row, Value};
use crate::interpreter::ast::OrderByClause;
use crate::interpreter::ast::OrderByDirection;
use crate::interpreter::ast::SelectableStack;
use crate::interpreter::ast::SelectableStackElement;

fn _default_table() -> Table {
Table {
name: "users".to_string(),
columns: vec![
ColumnDefinition {
name: "id".to_string(),
data_type: DataType::Integer,
constraints: vec![],
},
ColumnDefinition {
name: "name".to_string(),
data_type: DataType::Text,
constraints: vec![],
},
ColumnDefinition {
name: "money".to_string(),
data_type: DataType::Real,
constraints: vec![],
},
ColumnDefinition {
name: "some_data".to_string(),
data_type: DataType::Blob,
constraints: vec![],
},
],
rows: vec![
RowStack::new(Row(vec![
Value::Integer(3),
Value::Text("c_Jim".to_string()),
Value::Real(3000.0),
Value::Blob(b"0022".to_vec()),
])),
RowStack::new(Row(vec![
Value::Integer(1),
Value::Text("a_John".to_string()),
Value::Real(1000.0),
Value::Blob(b"0000".to_vec()),
])),
RowStack::new(Row(vec![
Value::Null,
Value::Null,
Value::Null,
Value::Null,
])),
RowStack::new(Row(vec![
Value::Integer(2),
Value::Text("b_Jane".to_string()),
Value::Real(2000.0),
Value::Blob(b"0201".to_vec()),
])),
RowStack::new(Row(vec![
Value::Integer(3),
Value::Text("b_Jim".to_string()),
Value::Real(1500.0),
Value::Blob(b"0102".to_vec()),
])),
RowStack::new(Row(vec![
Value::Integer(4),
Value::Text("a_Jim".to_string()),
Value::Real(500.0),
Value::Blob(b"0101".to_vec()),
])),
RowStack::new(Row(vec![
Value::Integer(1),
Value::Text("a_Jim".to_string()),
Value::Real(5000.0),
Value::Blob(b"0401".to_vec()),
])),
],
}
#[test]
fn apply_order_by_from_precomputed_single_column_asc() {
let mut to_order = vec!["second", "fourth", "third", "first"];

let precomputed = vec![
Row(vec![Value::Integer(25)]),
Row(vec![Value::Integer(55)]),
Row(vec![Value::Integer(35)]),
Row(vec![Value::Integer(22)]),
];

let order_by_clause = OrderByClause {
columns: SelectableStack {
selectables: vec![SelectableStackElement::Column("age".to_string())],
},
column_names: vec!["age".to_string()],
directions: vec![OrderByDirection::Asc],
};

apply_order_by_from_precomputed(&mut to_order, precomputed, "default", &order_by_clause);

assert_eq!(to_order, vec!["first", "second", "third", "fourth"]);
}
// TODO: tests
// TODO: add more tests
}
43 changes: 36 additions & 7 deletions src/interpreter/ast/helpers/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use crate::interpreter::{
},
tokenizer::token::TokenTypes,
};
use std::cmp::Ordering;

// Returns an error if the current token does not match the given token type
pub fn expect_token_type(parser: &Parser, token_type: TokenTypes) -> Result<(), String> {
Expand Down Expand Up @@ -191,7 +192,7 @@ pub fn get_selectables(
match operators.last() {
Some(last) => match last {
ExtendedSelectableStackElement::SelectableStackElement(inner) => {
if compare_precedence(&value, inner)? > 0 {
if compare_precedence(&value, inner)? == Ordering::Greater {
output.push(inner.clone());
operators.pop();
} else {
Expand Down Expand Up @@ -221,7 +222,7 @@ pub fn get_selectables(
// Literals
TokenTypes::IntLiteral => SelectableStackElement::Value(token_to_value(parser)?),
TokenTypes::RealLiteral => SelectableStackElement::Value(token_to_value(parser)?),
TokenTypes::String => SelectableStackElement::Value(token_to_value(parser)?),
TokenTypes::StringLiteral => SelectableStackElement::Value(token_to_value(parser)?),
TokenTypes::HexLiteral => SelectableStackElement::Value(token_to_value(parser)?),
TokenTypes::Null => SelectableStackElement::Value(token_to_value(parser)?),
// TODO: handle ValueList (arrays)
Expand Down Expand Up @@ -277,15 +278,15 @@ pub fn exists_clause(
pub fn compare_precedence(
first: &SelectableStackElement,
second: &SelectableStackElement,
) -> Result<i32, String> {
) -> Result<Ordering, String> {
let first_precedence = get_precedence(first)?;
let second_precedence = get_precedence(second)?;
return if second_precedence == first_precedence {
Ok(0)
Ok(Ordering::Equal)
} else if second_precedence > first_precedence {
Ok(-1)
Ok(Ordering::Less)
} else {
Ok(1)
Ok(Ordering::Greater)
};
}

Expand Down Expand Up @@ -336,7 +337,6 @@ pub fn hex_decode(hex: &str) -> Result<Vec<u8>, String> {
#[cfg(test)]
mod tests {
use super::*;
// TODO: add more tests

#[test]
fn decode_handles_valid_hex_string() {
Expand All @@ -358,4 +358,33 @@ mod tests {
let expected = "Hex string must have even length";
assert_eq!(expected, result.err().unwrap());
}

#[test]
fn precedence_handles_correctly() {
let result = compare_precedence(
&SelectableStackElement::MathOperator(MathOperator::Multiply),
&SelectableStackElement::MathOperator(MathOperator::Add),
);
assert!(result.is_ok());
assert_eq!(Ordering::Greater, result.unwrap());
let result = compare_precedence(
&SelectableStackElement::MathOperator(MathOperator::Add),
&SelectableStackElement::MathOperator(MathOperator::Multiply),
);
assert!(result.is_ok());
assert_eq!(Ordering::Less, result.unwrap());
let result = compare_precedence(
&SelectableStackElement::LogicalOperator(LogicalOperator::And),
&SelectableStackElement::LogicalOperator(LogicalOperator::Or),
);
assert!(result.is_ok());
assert_eq!(Ordering::Greater, result.unwrap());
let result = compare_precedence(
&SelectableStackElement::LogicalOperator(LogicalOperator::Not),
&SelectableStackElement::LogicalOperator(LogicalOperator::And),
);
assert!(result.is_ok());
assert_eq!(Ordering::Greater, result.unwrap());
}
// TODO: add more tests
}
6 changes: 3 additions & 3 deletions src/interpreter/ast/helpers/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ pub fn token_to_value(parser: &Parser) -> Result<Value, String> {
.map_err(|_| parser.format_error())?;
Ok(Value::Real(num))
}
TokenTypes::String => Ok(Value::Text(token.value.to_string())),
TokenTypes::Blob => {
TokenTypes::StringLiteral => Ok(Value::Text(token.value.to_string())), // TODO: rename to StringLiteral
TokenTypes::HexLiteral => {
let bytes = hex_decode(token.value).map_err(|_| parser.format_error())?;
Ok(Value::Blob(bytes))
}
Expand Down Expand Up @@ -70,7 +70,7 @@ pub fn token_to_data_type(parser: &mut Parser) -> Result<DataType, String> {

pub fn token_to_string(token: &Token) -> String {
match token.token_type {
TokenTypes::String => format!("'{}'", token.value),
TokenTypes::StringLiteral => format!("'{}'", token.value),
TokenTypes::HexLiteral => format!("X'{}'", token.value),
TokenTypes::EOF
| TokenTypes::SemiColon
Expand Down
14 changes: 7 additions & 7 deletions src/interpreter/ast/helpers/where_clause/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ mod tests {
token(TokenTypes::And, "AND"),
token(TokenTypes::Identifier, "name"),
token(TokenTypes::Equals, "="),
token(TokenTypes::String, "John"),
token(TokenTypes::StringLiteral, "John"),
token(TokenTypes::SemiColon, ";"),
];
let mut parser = Parser::new(tokens);
Expand Down Expand Up @@ -171,7 +171,7 @@ mod tests {
token(TokenTypes::And, "AND"),
token(TokenTypes::Identifier, "name"),
token(TokenTypes::Equals, "="),
token(TokenTypes::String, "John"),
token(TokenTypes::StringLiteral, "John"),
token(TokenTypes::Or, "OR"),
token(TokenTypes::Identifier, "age"),
token(TokenTypes::GreaterThan, ">"),
Expand Down Expand Up @@ -209,7 +209,7 @@ mod tests {
token(TokenTypes::Not, "NOT"),
token(TokenTypes::Identifier, "name"),
token(TokenTypes::Equals, "="),
token(TokenTypes::String, "John"),
token(TokenTypes::StringLiteral, "John"),
token(TokenTypes::And, "AND"),
token(TokenTypes::Not, "NOT"),
token(TokenTypes::Identifier, "age"),
Expand Down Expand Up @@ -249,7 +249,7 @@ mod tests {
token(TokenTypes::Or, "OR"),
token(TokenTypes::Identifier, "name"),
token(TokenTypes::Equals, "="),
token(TokenTypes::String, "John"),
token(TokenTypes::StringLiteral, "John"),
token(TokenTypes::RightParen, ")"),
token(TokenTypes::And, "AND"),
token(TokenTypes::Not, "NOT"),
Expand Down Expand Up @@ -299,7 +299,7 @@ mod tests {
token(TokenTypes::LeftParen, "("),
token(TokenTypes::Identifier, "name"),
token(TokenTypes::Equals, "="),
token(TokenTypes::String, "John"),
token(TokenTypes::StringLiteral, "John"),
token(TokenTypes::And, "AND"),
token(TokenTypes::Identifier, "age"),
token(TokenTypes::GreaterThan, ">"),
Expand Down Expand Up @@ -339,7 +339,7 @@ mod tests {
token(TokenTypes::Or, "OR"),
token(TokenTypes::Identifier, "name"),
token(TokenTypes::Equals, "="),
token(TokenTypes::String, "John"),
token(TokenTypes::StringLiteral, "John"),
token(TokenTypes::SemiColon, ";"),
];
let mut parser = Parser::new(tokens);
Expand All @@ -365,7 +365,7 @@ mod tests {
token(TokenTypes::Or, "OR"),
token(TokenTypes::Identifier, "name"),
token(TokenTypes::Equals, "="),
token(TokenTypes::String, "John"),
token(TokenTypes::StringLiteral, "John"),
token(TokenTypes::RightParen, ")"),
token(TokenTypes::RightParen, ")"),
token(TokenTypes::SemiColon, ";"),
Expand Down
8 changes: 4 additions & 4 deletions src/interpreter/ast/helpers/where_clause/where_condition.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ pub fn get_operand(parser: &mut Parser) -> Result<Operand, String> {
TokenTypes::Identifier => Ok(Operand::Identifier(token.value.to_string())),
TokenTypes::IntLiteral => Ok(Operand::Value(token_to_value(parser)?)),
TokenTypes::RealLiteral => Ok(Operand::Value(token_to_value(parser)?)),
TokenTypes::String => Ok(Operand::Value(token_to_value(parser)?)),
TokenTypes::Blob => Ok(Operand::Value(token_to_value(parser)?)),
TokenTypes::StringLiteral => Ok(Operand::Value(token_to_value(parser)?)),
TokenTypes::HexLiteral => Ok(Operand::Value(token_to_value(parser)?)),
TokenTypes::Null => Ok(Operand::Value(token_to_value(parser)?)),
TokenTypes::LeftParen => {
parser.advance()?;
Expand Down Expand Up @@ -188,7 +188,7 @@ mod tests {
fn where_stack_handles_reversed_condition() {
// "fletcher" < id;...
let tokens = vec![
token(TokenTypes::String, "fletcher"),
token(TokenTypes::StringLiteral, "fletcher"),
token(TokenTypes::LessThan, "<"),
token(TokenTypes::Identifier, "id"),
token(TokenTypes::SemiColon, ";"),
Expand Down Expand Up @@ -226,7 +226,7 @@ mod tests {
fn where_condition_handles_invalid_not_in_statement() {
// X'00' NOT (1);...
let tokens = vec![
token(TokenTypes::Blob, "00"),
token(TokenTypes::HexLiteral, "FF"),
token(TokenTypes::Not, "NOT"),
token(TokenTypes::LeftParen, "("),
token(TokenTypes::IntLiteral, "1"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ pub fn get_where_stack_element(
TokenTypes::Identifier
| TokenTypes::IntLiteral
| TokenTypes::RealLiteral
| TokenTypes::String
| TokenTypes::StringLiteral
| TokenTypes::Blob
| TokenTypes::Null => {
return Ok(Some(WhereStackElement::Condition(get_condition(parser)?)));
Expand Down
20 changes: 10 additions & 10 deletions src/interpreter/ast/insert_statement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ mod tests {
token(TokenTypes::LeftParen, "("),
token(TokenTypes::IntLiteral, "1"),
token(TokenTypes::Comma, ","),
token(TokenTypes::String, "Alice"),
token(TokenTypes::StringLiteral, "Alice"),
token(TokenTypes::RightParen, ")"),
token(TokenTypes::SemiColon, ";"),
];
Expand Down Expand Up @@ -178,13 +178,13 @@ mod tests {
token(TokenTypes::LeftParen, "("),
token(TokenTypes::IntLiteral, "1"),
token(TokenTypes::Comma, ","),
token(TokenTypes::String, "Alice"),
token(TokenTypes::StringLiteral, "Alice"),
token(TokenTypes::RightParen, ")"),
token(TokenTypes::Comma, ","),
token(TokenTypes::LeftParen, "("),
token(TokenTypes::IntLiteral, "2"),
token(TokenTypes::Comma, ","),
token(TokenTypes::String, "Bob"),
token(TokenTypes::StringLiteral, "Bob"),
token(TokenTypes::RightParen, ")"),
token(TokenTypes::SemiColon, ";"),
];
Expand Down Expand Up @@ -223,7 +223,7 @@ mod tests {
token(TokenTypes::LeftParen, "("),
token(TokenTypes::RealLiteral, "1.1"),
token(TokenTypes::Comma, ","),
token(TokenTypes::Blob, "AAB000"),
token(TokenTypes::HexLiteral, "AAB000"),
token(TokenTypes::Comma, ","),
token(TokenTypes::Null, "NULL"),
token(TokenTypes::RightParen, ")"),
Expand Down Expand Up @@ -259,7 +259,7 @@ mod tests {
token(TokenTypes::LeftParen, "("),
token(TokenTypes::IntLiteral, "1"),
token(TokenTypes::Comma, ","),
token(TokenTypes::String, "Alice"),
token(TokenTypes::StringLiteral, "Alice"),
token(TokenTypes::RightParen, ")"),
token(TokenTypes::SemiColon, ";"),
];
Expand Down Expand Up @@ -295,15 +295,15 @@ mod tests {
token(TokenTypes::LeftParen, "("),
token(TokenTypes::IntLiteral, "1"),
token(TokenTypes::Comma, ","),
token(TokenTypes::String, "Alice"),
token(TokenTypes::StringLiteral, "Alice"),
token(TokenTypes::RightParen, ")"),
token(TokenTypes::Comma, ","),
token(TokenTypes::LeftParen, "("),
token(TokenTypes::IntLiteral, "2"),
token(TokenTypes::Comma, ","),
token(TokenTypes::String, "Bob"),
token(TokenTypes::StringLiteral, "Bob"),
token(TokenTypes::Comma, ","),
token(TokenTypes::String, "Charlie"),
token(TokenTypes::StringLiteral, "Charlie"),
token(TokenTypes::RightParen, ")"),
token(TokenTypes::SemiColon, ";"),
];
Expand All @@ -330,9 +330,9 @@ mod tests {
token(TokenTypes::LeftParen, "("),
token(TokenTypes::IntLiteral, "1"),
token(TokenTypes::Comma, ","),
token(TokenTypes::String, "Alice"),
token(TokenTypes::StringLiteral, "Alice"),
token(TokenTypes::Comma, ","),
token(TokenTypes::String, "Bob"),
token(TokenTypes::StringLiteral, "Bob"),
token(TokenTypes::RightParen, ")"),
token(TokenTypes::SemiColon, ";"),
];
Expand Down
Loading
Loading