The SQL specification prohibits constructions like
SELECT * FROM a NATURAL JOIN (b)
where b sits alone inside parentheses. Parentheses in a FROM entry
always introduce either a derived table or a join.
This commit adds support for derived tables (i.e., subqueries) that
incorporate set operations, like:
SELECT * FROM (((SELECT 1) UNION (SELECT 2)) t1 AS NATURAL JOIN t2)
This introduces a bit of complexity around determining whether a left
paren starts a subquery, starts a nested join, or belongs to an
already-started subquery. The details are explained in a comment within
the patch.
It is useful downstream to have two separate enums, one for unary
operators and one for binary operators, so that the compiler can check
exhaustiveness. Otherwise downstream consumers need to manually encode
which operators are unary and which operators are binary when matching
on an Operator enum.
These were previously called "BinaryExpr" and "Unary"; besides being
inconsistent, it's also not correct to say "binary expression" or "unary
expression", as it's the operators that have arities, not the
expression. Adjust the naming of the variants accordingly.
SELECT * FROM (((SELECT 1))) is just as valid as
SELECT * FROM (SELECT 1). Add a test to ensure that we can parse the
first form.
Addresses a comment from #100.
get_next_precedence deals with left-binding power, not right binding
power. Therefore, when it encounters a standalone NOT operator (i.e., a
"NOT" token that is not followed by "BETWEEN", "LIKE", or "IN"), it
should return 0, because unary NOT is not an infix operator, it's a
prefix operator, and therefore it has no left-binding power.
Standardize the license header, removing the Grove Enterprise copyright
notice where it exists per #58. Also add a CI check to ensure that files
without license headers don't get merged.
Fix#58.
- reduce duplication in the handling of implicit/cross joins and make
the flow of data slightly clearer by returning the `join` instead of
pushing it and exiting early.
(I wanted the block that currently returns `join` to return one of
JoinOperator::* tags, so that `parse_table_factor` and the construction
of the `Join` struct could happen after we've parsed the JOIN keywords,
but that seems impossible.)
- move the check for the NATURAL keyword into the block that deals with
INNER/OUTER joins that support constraints (and thus can be preceded
by "NATURAL")
- add a check for NATURAL not followed by a known join type with a test
- add more tests for NATURAL joins (we didn't have any), and fix
whitespace bug in `to_string()` that was uncovered (we emitted an
extra space: `foo NATURAL JOIN bar `)