Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support IN () syntax of SQLite #1005

Closed
wants to merge 7 commits into from

Conversation

lewiszlw
Copy link
Member

image
SQLite3 supports in empty list expression.

Copy link
Contributor

@alamb alamb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the contribution @lewiszlw -- this looks good to me other than the renaming of parse_comma_separated1

src/parser/mod.rs Outdated Show resolved Hide resolved
Copy link
Contributor

@alamb alamb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the contribution as well as the testing @lewiszlw

@alamb
Copy link
Contributor

alamb commented Oct 23, 2023

It appears there are some CI on this PR

@lewiszlw lewiszlw requested a review from alamb October 24, 2023 06:08
@alamb alamb changed the title Allow in empty list expr for SQLite Support IN () syntax of SQLite Oct 24, 2023
Copy link
Contributor

@alamb alamb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @lewiszlw -- thank you for this PR.

I was going through it and I don't fully understand all the code in parse_comma_separated0

Using the following version, the tests/sqlparser_sqlite.rs test passes (though some of the unit tests do not)

Can you please add tests in tests/sqlparser_sqlite.rs that show what this extra code is doing / what types of queries it is parsing?

    /// Parse a comma-separated list of 0+ items accepted by `F`
    pub fn parse_comma_separated0<T, F>(&mut self, f: F) -> Result<Vec<T>, ParserError>
    where
        F: FnMut(&mut Parser<'a>) -> Result<T, ParserError>,
    {
        if matches!(self.peek_token().token, Token::RParen)
        {
            return Ok(vec![])
        }

        self.parse_comma_separated(f)
    }

@alamb
Copy link
Contributor

alamb commented Oct 26, 2023

my plan with this PR is to use the simplified version of the code I suggested above and merge it tomorrow unless I hear otherwise. Thanks again @lewiszlw and @lovasoa

@lovasoa
Copy link
Contributor

lovasoa commented Oct 26, 2023

Great ! Can we make a new release after that ?

@lewiszlw
Copy link
Member Author

lewiszlw commented Oct 27, 2023

@alamb Sorry for late.
I tested with your code

#[test]
fn parse_where_in_empty_list() {

    // case1 succeed
    let sql = "SELECT * FROM t1 WHERE a IN ()";
    let select = sqlite().verified_only_select(sql);
    if let Expr::InList { list, .. } = select.selection.as_ref().unwrap() {
        assert_eq!(list.len(), 0);
    } else {
        unreachable!()
    }

    // case2 fail with `ParserError("Expected an expression:, found: ,")`
    let sql = "SELECT * FROM t1 WHERE a IN (,)";
    let select = sqlite_with_options(ParserOptions::new().with_trailing_commas(true))
        .verified_only_select(sql);
    if let Expr::InList { list, .. } = select.selection.as_ref().unwrap() {
        assert_eq!(list.len(), 0);
    } else {
        unreachable!()
    }

    // case3 succeed
    let sql = "SELECT * FROM t1 WHERE a IN (1)";
    let select = sqlite().verified_only_select(sql);
    if let Expr::InList { list, .. } = select.selection.as_ref().unwrap() {
        assert_eq!(list.len(), 1);
    } else {
        unreachable!()
    }
    
    // case4 succeed
    let sql = "SELECT * FROM t1 WHERE a IN (1,)";
    let select = sqlite_with_options(ParserOptions::new().with_trailing_commas(true))
        .verified_only_select(sql);
    if let Expr::InList { list, .. } = select.selection.as_ref().unwrap() {
        assert_eq!(list.len(), 1);
    } else {
        unreachable!()
    }
}

My latest code works for case2.

If your code changed like this, then also works for case2

    pub fn parse_comma_separated0<T, F>(&mut self, f: F) -> Result<Vec<T>, ParserError>
    where
        F: FnMut(&mut Parser<'a>) -> Result<T, ParserError>,
    {
        if matches!(self.peek_token().token, Token::RParen) {
            return Ok(vec![]);
        }
        if matches!(self.peek_token().token, Token::Comma) && self.options.trailing_commas {
            let _ = self.consume_token(&Token::Comma);
            return if matches!(self.peek_token().token, Token::RParen) {
                Ok(vec![])
            } else {
                Err(ParserError::ParserError("Could not parse ','".to_string()))
            }
        }

        self.parse_comma_separated(f)
    }

Copy link
Contributor

@alamb alamb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you again for your contribution @lewiszlw

I am worried that this PR may have unintended side effects of parsing comma separated values which is critical functionality for sqlparser.

Thus I would like to request we keep this change simpler and thus less likely to cause unintended consequences.

Here is an alternate proposal: #1028

}

sqlite_with_options(ParserOptions::new().with_trailing_commas(true)).one_statement_parses_to(
"SELECT * FROM t1 WHERE a IN (,)",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW this doesn't appear to be valid SQLite syntax:

sqlite> create table t as values (1);
sqlite> select * from t where column1 IN (,);
Parse error: near ",": syntax error
  select * from t where column1 IN (,);
                      error here ---^

@lewiszlw
Copy link
Member Author

Close in favor of #1028

@lewiszlw lewiszlw closed this Oct 28, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants