Skip to content

Opening "sqlite::memory:" is broken for SqlitePool #362

@therocode

Description

@therocode

With sqlx 0.3.5 It is not possible to do
sqlx::SqlitePool::new("sqlite::memory:")

The connection seems like it works, but when using queries with this pool, sqlx panics with "Error: bad parameter or other API misuse".

I have drilled down the issue to the hack in url.rs line 82 in sqlx_core. That is the following snippet:

    /// Undo URL percent-encoding and return [authority]path[query]
    ///
    /// Mostly a hack to fix special-character handling for SQLite as its connection string is a
    /// file path and not _really_ a URL
    pub fn path_decoded(&self) -> Cow<str> {
        // omit scheme (e.g. `sqlite://`, `mysql://`)
        let mut url_str = &self.0.as_str()[self.0.scheme().len()..]
            .trim_start_matches(':')
            .trim_start_matches("//");

This turns "sqlite::memory:" into "memory:" which is not a valid sqlite file to open. This path is not hit at all when using a direct connection instead of a pool, so that's why this error doesn't show up on the tests since they don't use pools.

I can fix it locally by doing

        //the above hack breaks using sqlite::memory: since it turns it into just memory: so this hack undos that
        if *url_str == "memory:" {
            url_str = &":memory:";
        }

afterwards but that's an as ugly of a hack and I'm not happy to make a PR out of that. I feel there's a better fix but I am not knowledgable enough to know what it would be.

Note that you cannot workaround this by opening just ":memory:" instead of "sqlite::memory:" since the URL parser will panic saying that it's a relative URL with no base

The following application reproduces the error:

#[tokio::main]
async fn main() -> anyhow::Result<()>{
    
    //gives error: "relative URL without a base"
    //let pool = sqlx::SqlitePool::new(":memory:").await?;
    //gives error: "Error: bad parameter or other API misuse"
    let pool = sqlx::SqlitePool::new("sqlite::memory:").await?;


    sqlx::query(
        "CREATE TABLE IF NOT EXISTS tracks(
            id INTEGER PRIMARY KEY,
            track_num INTEGER NOT NULL,
            title TEXT NOT NULL,
            url TEXT);"
    )
    .execute(&pool)
    .await?;

    sqlx::query(
        "INSERT INTO tracks (track_num, title, url)
         VALUES ($1, $2, $3);",
    )
    .bind(&1i32)
    .bind(&"asdf")
    .bind(&"asdf")
    .execute(&pool)
    .await?;

    Ok(())
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions