Repository: diesel-rs/diesel (language: rust)

Issue:
minor: create_database_if_needed assumes URL is a path
Gonna ignore the template since I just found this from reading diesel_cli's source; sorry if that's a problem.

```
/// Creates the database specified in the connection url. It returns an error
/// it was unable to create the database.
fn create_database_if_needed(database_url: &str) -> DatabaseResult<()> {
    match Backend::for_url(database_url) {
        #[cfg(feature = "postgres")]
        Backend::Pg => {
            if PgConnection::establish(database_url).is_err() {
                let (database, postgres_url) = change_database_of_url(database_url, "postgres");
                println!("Creating database: {}", database);
                let mut conn = PgConnection::establish(&postgres_url)?;
                query_helper::create_database(&database).execute(&mut conn)?;
            }
        }
        #[cfg(feature = "sqlite")]
        Backend::Sqlite => {
            if !::std::path::Path::new(database_url).exists() {
                println!("Creating database: {}", database_url);
                SqliteConnection::establish(database_url)?;
            }
        }
        #[cfg(feature = "mysql")]
        Backend::Mysql => {
            if MysqlConnection::establish(database_url).is_err() {
                let (database, mysql_url) =
                    change_database_of_url(database_url, "information_schema");
                println!("Creating database: {}", database);
                let mut conn = MysqlConnection::establish(&mysql_url)?;
                query_helper::create_database(&database).execute(&mut conn)?;
            }
        }
    }

    Ok(())
}
```

[Permalink to problem line](https://github.com/diesel-rs/diesel/blob/1327fba7b2d0419b631e4ff24e4ca430d62fc2fe/diesel_cli/src/database.rs#L175).

The `Backend::Sqlite` case assumes that `database_url` is a bare path (as opposed to, say, a `file:` URL, which is otherwise valid) when checking if the path exists, so it may enter the wrong branch if given a non-path argument (e.g. if given a `file:///foo/bar` url, this code seems to check for a relative path `file:/foo/bar` instead of an absolute path `/foo/bar`).


Discussion / hints:
Yes that's a bug. Thanks for reporting. Mind filling a PR fixing this?
Will do.

Fix patch:
diff --git a/diesel_cli/Cargo.toml b/diesel_cli/Cargo.toml
index 5f8555d1d26b..ed7e2ceded05 100644
--- a/diesel_cli/Cargo.toml
+++ b/diesel_cli/Cargo.toml
@@ -26,7 +26,7 @@ dotenvy = "0.15"
 heck = "0.4.0"
 serde = { version = "1.0.0", features = ["derive"] }
 toml = "0.5"
-url = { version = "2.2.2", optional = true }
+url = { version = "2.2.2" }
 libsqlite3-sys = { version = ">=0.17.2, <0.26.0", optional = true }
 diffy = "0.2.0"
 regex = "1.0.6"
@@ -49,9 +49,9 @@ url = { version = "2.2.2" }
 
 [features]
 default = ["postgres", "sqlite", "mysql"]
-postgres = ["diesel/postgres", "url", "uses_information_schema"]
+postgres = ["diesel/postgres", "uses_information_schema"]
 sqlite = ["diesel/sqlite"]
-mysql = ["diesel/mysql", "url", "uses_information_schema"]
+mysql = ["diesel/mysql", "uses_information_schema"]
 sqlite-bundled = ["sqlite", "libsqlite3-sys/bundled"]
 uses_information_schema = []
 
diff --git a/diesel_cli/src/database.rs b/diesel_cli/src/database.rs
index c8f646328814..b921cb01d667 100644
--- a/diesel_cli/src/database.rs
+++ b/diesel_cli/src/database.rs
@@ -172,7 +172,8 @@ fn create_database_if_needed(database_url: &str) -> DatabaseResult<()> {
         }
         #[cfg(feature = "sqlite")]
         Backend::Sqlite => {
-            if !::std::path::Path::new(database_url).exists() {
+            let path = path_from_sqlite_url(database_url)?;
+            if !path.exists() {
                 println!("Creating database: {}", database_url);
                 SqliteConnection::establish(database_url)?;
             }
@@ -361,6 +362,30 @@ fn change_database_of_url(database_url: &str, default_database: &str) -> (String
     (database, new_url.into())
 }
 
+#[cfg(feature = "sqlite")]
+/// sqlite accepts either file: URLs, or bare paths (the latter of which may be relative).
+/// Check for which case we're in and return the path if we can retrieve it.
+fn path_from_sqlite_url(database_url: &str) -> DatabaseResult<::std::path::PathBuf> {
+    if database_url.starts_with("file:/") {
+        // looks like a file URL
+        match ::url::Url::parse(database_url) {
+            Ok(url) if url.scheme() == "file" => Ok(url.to_file_path().map_err(|_err| {
+                result::ConnectionError::InvalidConnectionUrl(String::from(database_url))
+            })?),
+            _ => {
+                // invalid URL or scheme
+                Err(
+                    result::ConnectionError::InvalidConnectionUrl(String::from(database_url))
+                        .into(),
+                )
+            }
+        }
+    } else {
+        // assume it's a bare path
+        Ok(::std::path::PathBuf::from(database_url))
+    }
+}
+
 fn handle_error<E: Error, T>(error: E) -> T {
     println!("{}", error);
     ::std::process::exit(1);


Test patch: