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.
It is convenient for downstream libraries to be able to stash bits of
ASTs into hash maps, e.g., for performing simple common subexpression
elimination.
The only downside to this change is that it requires that the f64 in the
Value enum be wrapped in an OrderedFloat, which provides the necessary
equality semantics to allow Hash to be drived. The reason f64 doesn't
implement Hash by default is because NaN is typically not equal to
itself, so it's not clear what it should hash to. That's less of a
concern in a SQL context, because every SQL database I've looked at
treats NaN as equal to itself, in violation of the IEEE standard, in
order to permit indexing and sorting of float columns.
- 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 `)
This block parses one of:
- `[ INNER ] JOIN <table_factor> <join_constraint>`
- `{ LEFT | RIGHT | FULL } [ OUTER ] JOIN <table_factor> <join_constraint>`
..but it was hard to see because of the duplication.
- use `if !self.consume_token(&Token::Comma) { break; }` to consume the
comma and exit the loop if no comma found.
- coalesce two `{ false }` blocks in `consume_token` by using a match guard
Internal improvements to Parser::next_token/prev_token
This reduces the number of helper functions used by next_token()/prev_token() while slightly improving performance and reducing the chances of coding errors when using prev_token() after hitting end-of-file.
Before this `next_token()` would only increment the index when returning
`Some(token)`. This means that the caller wishing to rewind must be
careful not to call `prev_token()` on EOF (`None`), while not forgetting
to call it for `Some`. Not doing this resulted in bugs in the
undertested code that does error handling.
After making this mistake several times, I'm changing `next_token()` /
`prev_token()` so that calling `next_token(); prev_token(); next_token()`
returns the same token in the first and the last invocation.
- Avoid cloning whitespace tokens in `peek_nth_token()` by using a
&Token from `tokens.get()` instead of a cloned `Token` from `token_at()`
- Similarly avoid cloning in `next_token_no_skip`, and clone the
non-whitespace tokens in `next_token` instead.
- Remove `token_at`, which was only used in `peek_token` and
`peek_nth_token`
- Fold `prev_token_no_skip()` into `prev_token()` and make `prev_token`
return nothing, as the return value isn't used anyway.
* Rewrite parsing of `ALTER TABLE ADD CONSTRAINT`
* Support constraints in CREATE TABLE
* Change `Value::Long()` to be unsigned, use u64 consistently
* Allow trailing comma in CREATE TABLE
The tokenizer emits a separate Token for +/- signs, so the value of
Value::Long() (as well as of parse_literal_int()) may never be negative.
Also we have been using both u64 and usize to represent a parsed
unsigned number. Change to using u64 for consistency.