Skip to content
This repository was archived by the owner on Apr 21, 2020. It is now read-only.

Commit e822fe3

Browse files
committed
Correctly implements SQL operator precedence
1 parent c7a0642 commit e822fe3

File tree

5 files changed

+51
-22
lines changed

5 files changed

+51
-22
lines changed

include/sql/predicate.hpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -52,15 +52,15 @@ namespace sql
5252
{
5353
return Left::eval(row) != Right::eval(row);
5454
}
55-
else if constexpr(Op == "and" || Op == "AND")
55+
else if constexpr(Op == "AND")
5656
{
5757
return Left::eval(row) && Right::eval(row);
5858
}
59-
else if constexpr(Op == "or" || Op == "OR")
59+
else if constexpr(Op == "OR")
6060
{
6161
return Left::eval(row) || Right::eval(row);
6262
}
63-
else if constexpr(Op == "not" || Op == "NOT")
63+
else if constexpr(Op == "NOT")
6464
{
6565
return !Left::eval(row);
6666
}

include/sql/query.hpp

+44-15
Original file line numberDiff line numberDiff line change
@@ -116,9 +116,14 @@ namespace sql
116116
return tv[0] == '=' || tv[0] == '!' || tv[0] == '<' || tv[0] == '>';
117117
}
118118

119-
constexpr bool islogical(std::string_view const& tv) noexcept
119+
constexpr bool isor(std::string_view const& tv) noexcept
120120
{
121-
return tv == "or" || tv == "OR" || tv == "and" || tv == "AND";
121+
return tv == "or" || tv == "OR";
122+
}
123+
124+
constexpr bool isand(std::string_view const& tv) noexcept
125+
{
126+
return tv == "and" || tv == "AND";
122127
}
123128

124129
} // namespace
@@ -183,7 +188,7 @@ namespace sql
183188
{
184189
if constexpr (tokens_[Pos] == "(")
185190
{
186-
constexpr auto expr{ parse_logical<Pos + 1, Row>() };
191+
constexpr auto expr{ parse_or<Pos + 1, Row>() };
187192

188193
return TreeNode<expr.pos + 1, typename decltype(expr)::node>{};
189194
}
@@ -242,41 +247,65 @@ namespace sql
242247
if constexpr (tokens_[Pos] == "not" || tokens_[Pos] == "NOT")
243248
{
244249
constexpr auto expr{ parse_comp<Pos + 1, Row>() };
245-
constexpr cexpr::string<char, tokens_[Pos].length() + 1> name{ tokens_[Pos] };
246250

247-
return TreeNode<expr.pos, sql::operation<name, Row, typename decltype(expr)::node>>{};
251+
return TreeNode<expr.pos, sql::operation<"NOT", Row, typename decltype(expr)::node>>{};
248252
}
249253
else
250254
{
251255
return parse_comp<Pos, Row>();
252256
}
253257
}
254258

255-
// recursively parse chained boolean operations
259+
// recursively parse chained AND operations
256260
template <typename Left, typename Row>
257-
static constexpr auto recurse_logical() noexcept
261+
static constexpr auto recurse_and() noexcept
258262
{
259-
if constexpr (!islogical(tokens_[Left::pos]))
263+
if constexpr (!isand(tokens_[Left::pos]))
260264
{
261265
return Left{};
262266
}
263267
else
264268
{
265269
constexpr auto right{ parse_negation<Left::pos + 1, Row>() };
266-
constexpr cexpr::string<char, tokens_[Left::pos].length() + 1> name{ tokens_[Left::pos] };
267-
constexpr auto node{ sql::operation<name, Row, typename Left::node, typename decltype(right)::node>{} };
270+
constexpr auto node{ sql::operation<"AND", Row, typename Left::node, typename decltype(right)::node>{} };
268271

269-
return recurse_logical<TreeNode<right.pos, std::remove_cvref_t<decltype(node)>>, Row>();
272+
return recurse_and<TreeNode<right.pos, std::remove_cvref_t<decltype(node)>>, Row>();
270273
}
271274
}
272275

273-
// descend further then attempt to parse boolean operations
276+
// descend further then attempt to parse AND operations
274277
template <std::size_t Pos, typename Row>
275-
static constexpr auto parse_logical() noexcept
278+
static constexpr auto parse_and() noexcept
276279
{
277280
constexpr auto left{ parse_negation<Pos, Row>() };
278281

279-
return recurse_logical<decltype(left), Row>();
282+
return recurse_and<decltype(left), Row>();
283+
}
284+
285+
// recursively parse chained OR operations
286+
template <typename Left, typename Row>
287+
static constexpr auto recurse_or() noexcept
288+
{
289+
if constexpr (!isor(tokens_[Left::pos]))
290+
{
291+
return Left{};
292+
}
293+
else
294+
{
295+
constexpr auto right{ parse_and<Left::pos + 1, Row>() };
296+
constexpr auto node{ sql::operation<"OR", Row, typename Left::node, typename decltype(right)::node>{} };
297+
298+
return recurse_or<TreeNode<right.pos, std::remove_cvref_t<decltype(node)>>, Row>();
299+
}
300+
}
301+
302+
// descend further then attempt to parse OR operations
303+
template <std::size_t Pos, typename Row>
304+
static constexpr auto parse_or() noexcept
305+
{
306+
constexpr auto left{ parse_and<Pos, Row>() };
307+
308+
return recurse_or<decltype(left), Row>();
280309
}
281310

282311
// find correct schema for terminal relation
@@ -338,7 +367,7 @@ namespace sql
338367

339368
if constexpr (root.pos + 1 < tokens_.count() && (tokens_[root.pos] == "where" || tokens_[root.pos] == "WHERE"))
340369
{
341-
constexpr auto predicate{ parse_logical<root.pos + 1, std::remove_cvref_t<typename decltype(root)::node::output_type>>() };
370+
constexpr auto predicate{ parse_or<root.pos + 1, std::remove_cvref_t<typename decltype(root)::node::output_type>>() };
342371

343372
return ra::selection<typename decltype(predicate)::node, typename decltype(root)::node>{};
344373
}

resources/tests/data.hpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
using books =
99
sql::schema<
1010
sql::index<>,
11-
sql::column<"title", std::string>,
11+
sql::column<"book", std::string>,
1212
sql::column<"genre", std::string>,
1313
sql::column<"year", unsigned>,
1414
sql::column<"pages", unsigned>
@@ -17,7 +17,7 @@ using books =
1717
using stories =
1818
sql::schema<
1919
sql::index<>,
20-
sql::column<"title", std::string>,
20+
sql::column<"story", std::string>,
2121
sql::column<"genre", std::string>,
2222
sql::column<"year", unsigned>
2323
>;

resources/tests/data/library.db

0 Bytes
Binary file not shown.

resources/tests/generate.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66

77
tables = ["books", "stories", "authored", "collected"]
88
columns = {
9-
"books": ["title", "genre", "year", "pages"],
10-
"stories": ["title", "genre", "year"],
9+
"books": ["book", "genre", "year", "pages"],
10+
"stories": ["story", "genre", "year"],
1111
"authored": ["title", "name"],
1212
"collected": ["title", "collection", "pages"]
1313
}

0 commit comments

Comments
 (0)