Merge 'core/translate: Handle Expr::Id in CREATE INDEX' from Kristofer

I am running into issues when creating indexes and made this PR with a
possible fix.
`Error: cannot use expressions in CREATE INDEX`
In my setup, running on `wasm32-unknown-unknown` (not in the browser), I
can reproduce the issue like this. First, creating a table:
```rust
conn.execute(
    r#"
    CREATE TABLE IF NOT EXISTS users (
        name TEXT,
        created DATETIME DEFAULT CURRENT_TIMESTAMP
    )
    "#,
    (),
)
.await
.unwrap();
```
Here, creating an index for that table:
```rust
conn.execute(
    "CREATE INDEX IF NOT EXISTS idx_users_name ON users(name)",
    (),
)
.await
.unwrap();
```
## Findings
I had a closer look at `resolve_sorted_columns`. In this bit, it checks
the expression of the sorted column.
https://github.com/tursodatabase/turso/blob/a2a31a520ff6e228a00e785026da
e19b5b2cced7/core/translate/index.rs#L252-L257
```rust
let ident = normalize_ident(match &sc.expr {
    // SQLite supports indexes on arbitrary expressions, but we don't (yet).
    // See "How to use indexes on expressions" in https://www.sqlite.org/expridx.html
    Expr::Name(ast::Name::Ident(col_name)) | Expr::Name(ast::Name::Quoted(col_name)) => {
        col_name
    }
    _ => crate::bail_parse_error!("Error: cannot use expressions in CREATE INDEX"),
});
```
If it is not an `Expr::Name`, function fails.
But, the `sc.expr` I am getting is not `Expr::Name` but `Expr::Id`.
Which doesn't seem unexpected but rather expected. Reading up on the
`sqlite3_parser` AST, it seems that both `Name` and `Id` can   be
expected.
Adding `Expr::Id` to the check fixes the issue.
```rust
let ident = normalize_ident(match &sc.expr {
    // SQLite supports indexes on arbitrary expressions, but we don't (yet).
    // See "How to use indexes on expressions" in https://www.sqlite.org/expridx.html
    Expr::Id(ast::Name::Ident(col_name))
    | Expr::Id(ast::Name::Quoted(col_name))
    | Expr::Name(ast::Name::Ident(col_name))
    | Expr::Name(ast::Name::Quoted(col_name)) => col_name,
    _ => crate::bail_parse_error!("Error: cannot use expressions in CREATE INDEX"),
});
```

Closes #2294
This commit is contained in:
Pekka Enberg
2025-07-28 08:54:45 +03:00

View File

@@ -252,9 +252,10 @@ fn resolve_sorted_columns<'a>(
let ident = normalize_ident(match &sc.expr {
// SQLite supports indexes on arbitrary expressions, but we don't (yet).
// See "How to use indexes on expressions" in https://www.sqlite.org/expridx.html
Expr::Name(ast::Name::Ident(col_name)) | Expr::Name(ast::Name::Quoted(col_name)) => {
col_name
}
Expr::Id(ast::Name::Ident(col_name))
| Expr::Id(ast::Name::Quoted(col_name))
| Expr::Name(ast::Name::Ident(col_name))
| Expr::Name(ast::Name::Quoted(col_name)) => col_name,
_ => crate::bail_parse_error!("Error: cannot use expressions in CREATE INDEX"),
});
let Some(col) = table.get_column(&ident) else {