apache / apache/datafusion-sqlparser-rs

Support for `IN $placeholder` syntax

Offen
#1,962 0 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen
Vorherrschende Sprache
Rust
Sterne
3.5k
Forks
772
Ø Merge
4 T. 9 Std.
Gemergte PRs (30 T.)
17

Beschreibung

Some DBs support using placeholders for `IN` clauses in prepared statements. For example in DuckDB:

```
$ duckdb
DuckDB v1.3.0 (Ossivalis) 71c5c07cdd
Enter ".help" for usage hints.
Connected to a transient in-memory database.
Use ".open FILENAME" to reopen on a persistent database.
D PREPARE qry AS SELECT 'a' in $list;
D EXECUTE qry(list := ['a', 'b']);
┌──────────────────────┐
│ contains($list, 'a') │
│ boolean │
├──────────────────────┤
│ true │
└──────────────────────┘
```

However, currently the parser doesn't handle this, for example:

```rust
#[test]
fn test_parse_in_placeholder() {
let stmt = all_dialects().verified_stmt("SELECT i IN $placeholder");
dbg!(&stmt);
}
```

Fails w/ `SELECT i IN $placeholder: ParserError("Expected: (, found: $placeholder")`.

To fix this, I think we would need to make two changes:

First off, the definition of `Expr::InList`:

```rust
/// `[ NOT ] IN (val1, val2, ...)`
InList {
expr: Box,
list: Vec,
negated: bool,
},
```

The issue is that `list` is always a Vec, where in this case we want list to be a `Expr::Value` w/ `value = Placeholder("$placeholder")`.

If `InList` supports that, then in `parse_in` we can do a check like this before the `expect_token(LParen)`:

```rust
if let Token::Placeholder(_) = &self.peek_token_ref().token {
let placeholder = self.parse_expr()?;
return Ok(Expr::InList {
expr: Box::new(expr),
list: placeholder,
negated,
})
};
self.expect_token(&Token::LParen)?;
```

But, how can we cleanly support this, without too much breakage for existing consumers? Note that I considered just putting the placeholder inside the list, but that doesn't work since that would represent `IN ($placeholder)` which has a very different meaning.

Beitragsleitfaden

Für dieses Repository ist kein Beitragsleitfaden indexiert

Rechercherichtung

Beginne mit der Definition von Expr::InList und der parse_in-Logik des Parsers und führe dann den bereitgestellten Fall all_dialects().verified_stmt("SELECT i IN $placeholder") aus, um den Fehler zu reproduzieren. Bestimme eine Darstellung, die IN $placeholder von IN ($placeholder) unterscheidet und gleichzeitig die Auswirkungen auf bestehende Consumer begrenzt, und füge Tests hinzu, die zeigen, dass beide Formen korrekt geparst werden.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Tech-Stack
rust, sql
Bereich
compilers, databases
Issue-Typ
Feature
Schwierigkeit
4/5
Geschätzter Aufwand
3-5 Tage
Aktivitätsstatus
Veraltet
Klarheit
Größtenteils klar
Anfängerfreundlichkeit
35/100

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.