diff --git a/diesel/Cargo.toml b/diesel/Cargo.toml index 1dc880a1967a..476ef7e4be52 100644 --- a/diesel/Cargo.toml +++ b/diesel/Cargo.toml @@ -16,16 +16,17 @@ byteorder = "1.0" diesel_derives = "~1.4.0" chrono = { version = "0.4", optional = true } libc = { version = "0.2.0", optional = true } -libsqlite3-sys = { version = ">=0.8.0, <0.17.0", optional = true, features = ["min_sqlite_version_3_7_16"] } +libsqlite3-sys = { version = ">=0.8.0, <0.18.0", optional = true, features = ["min_sqlite_version_3_7_16"] } mysqlclient-sys = { version = ">=0.1.0, <0.3.0", optional = true } pq-sys = { version = ">=0.3.0, <0.5.0", optional = true } quickcheck = { version = "0.4", optional = true } serde_json = { version = ">=0.8.0, <2.0", optional = true } time = { version = "0.1", optional = true } -url = { version = "1.4.0", optional = true } +url = { version = "2.1.0", optional = true } +percent-encoding = { version = "2.1.0", optional = true } uuid = { version = ">=0.2.0, <0.7.0", optional = true, features = ["use_std"] } -uuidv07 = { version = "0.7.0", optional = true, package = "uuid"} -ipnetwork = { version = ">=0.12.2, <0.16.0", optional = true } +uuidv07 = { version = ">=0.7.0, <0.9.0", optional = true, package = "uuid"} +ipnetwork = { version = ">=0.12.2, <0.17.0", optional = true } num-bigint = { version = ">=0.1.41, <0.3", optional = true } num-traits = { version = "0.2", optional = true } num-integer = { version = "0.1.32", optional = true } @@ -53,7 +54,7 @@ x128-column-tables = ["128-column-tables"] 128-column-tables = ["64-column-tables"] postgres = ["pq-sys", "bitflags", "diesel_derives/postgres"] sqlite = ["libsqlite3-sys", "diesel_derives/sqlite"] -mysql = ["mysqlclient-sys", "url", "diesel_derives/mysql"] +mysql = ["mysqlclient-sys", "url", "percent-encoding", "diesel_derives/mysql"] with-deprecated = [] deprecated-time = ["time"] network-address = ["ipnetwork", "libc"] diff --git a/diesel/src/mysql/connection/url.rs b/diesel/src/mysql/connection/url.rs index 2eae2a6ac076..a38cec1fa7c4 100644 --- a/diesel/src/mysql/connection/url.rs +++ b/diesel/src/mysql/connection/url.rs @@ -1,6 +1,7 @@ +extern crate percent_encoding; extern crate url; -use self::url::percent_encoding::percent_decode; +use self::percent_encoding::percent_decode; use self::url::{Host, Url}; use std::ffi::{CStr, CString}; @@ -128,7 +129,27 @@ fn first_path_segment_is_treated_as_database() { #[test] fn userinfo_should_be_percent_decode() { - use self::url::percent_encoding::{utf8_percent_encode, USERINFO_ENCODE_SET}; + use self::percent_encoding::{utf8_percent_encode, AsciiSet, CONTROLS}; + const USERINFO_ENCODE_SET: &AsciiSet = &CONTROLS + .add(b' ') + .add(b'"') + .add(b'<') + .add(b'>') + .add(b'`') + .add(b'#') + .add(b'?') + .add(b'{') + .add(b'}') + .add(b'/') + .add(b':') + .add(b';') + .add(b'=') + .add(b'@') + .add(b'[') + .add(b'\\') + .add(b']') + .add(b'^') + .add(b'|'); let username = "x#gfuL?4Zuj{n73m}eeJt0"; let encoded_username = utf8_percent_encode(username, USERINFO_ENCODE_SET); diff --git a/diesel/src/pg/connection/raw.rs b/diesel/src/pg/connection/raw.rs index abeee8fd896b..6a7ccb0c3bb4 100644 --- a/diesel/src/pg/connection/raw.rs +++ b/diesel/src/pg/connection/raw.rs @@ -106,7 +106,7 @@ fn last_error_message(conn: *const PGconn) -> String { unsafe { let error_ptr = PQerrorMessage(conn); let bytes = CStr::from_ptr(error_ptr).to_bytes(); - str::from_utf8_unchecked(bytes).to_string() + String::from_utf8_lossy(bytes).to_string() } } diff --git a/diesel/src/pg/connection/result.rs b/diesel/src/pg/connection/result.rs index ee2603de2ee9..69c5bd673bb3 100644 --- a/diesel/src/pg/connection/result.rs +++ b/diesel/src/pg/connection/result.rs @@ -52,6 +52,8 @@ impl PgResult { unsafe { let count_char_ptr = PQcmdTuples(self.internal_result.as_ptr()); let count_bytes = CStr::from_ptr(count_char_ptr).to_bytes(); + // Using from_utf8_unchecked is ok here because, we've set the + // client encoding to utf8 let count_str = str::from_utf8_unchecked(count_bytes); match count_str { "" => 0, diff --git a/diesel/src/pg/types/uuid_v0_7.rs b/diesel/src/pg/types/uuid_v0_7.rs index 03ad3ae9a85f..069f11598d26 100644 --- a/diesel/src/pg/types/uuid_v0_7.rs +++ b/diesel/src/pg/types/uuid_v0_7.rs @@ -46,7 +46,10 @@ fn some_uuid_from_sql() { #[test] fn bad_uuid_from_sql() { let uuid = uuid::Uuid::from_sql(Some(b"boom")); - assert_eq!(uuid.unwrap_err().description(), "UUID parse error"); + assert_eq!( + uuid.unwrap_err().to_string(), + "invalid bytes length: expected 16, found 4" + ); } #[test] diff --git a/diesel/src/sqlite/connection/raw.rs b/diesel/src/sqlite/connection/raw.rs index b5a2c392b7a4..820a51ec7d94 100644 --- a/diesel/src/sqlite/connection/raw.rs +++ b/diesel/src/sqlite/connection/raw.rs @@ -133,6 +133,7 @@ impl Drop for RawConnection { fn convert_to_string_and_free(err_msg: *const libc::c_char) -> String { let msg = unsafe { let bytes = CStr::from_ptr(err_msg).to_bytes(); + // sqlite is documented to return utf8 strings here str::from_utf8_unchecked(bytes).into() }; unsafe { ffi::sqlite3_free(err_msg as *mut libc::c_void) }; diff --git a/diesel/src/sqlite/connection/sqlite_value.rs b/diesel/src/sqlite/connection/sqlite_value.rs index 1eef1a5dbb22..c29a18f5e3e7 100644 --- a/diesel/src/sqlite/connection/sqlite_value.rs +++ b/diesel/src/sqlite/connection/sqlite_value.rs @@ -35,6 +35,8 @@ impl SqliteValue { let ptr = ffi::sqlite3_value_text(self.value()); let len = ffi::sqlite3_value_bytes(self.value()); let bytes = slice::from_raw_parts(ptr as *const u8, len as usize); + // The string is guaranteed to be utf8 according to + // https://www.sqlite.org/c3ref/value_blob.html str::from_utf8_unchecked(bytes) } } diff --git a/diesel_cli/Cargo.toml b/diesel_cli/Cargo.toml index 85218045fc56..77aebcc838e5 100644 --- a/diesel_cli/Cargo.toml +++ b/diesel_cli/Cargo.toml @@ -24,15 +24,15 @@ migrations_internals = "~1.4.0" serde = { version = "1.0.0", features = ["derive"] } tempfile = "3.0.0" toml = "0.4.6" -url = { version = "1.4.0", optional = true } +url = { version = "2.1.0", optional = true } barrel = { version = ">= 0.5.0", optional = true, features = ["diesel"] } -libsqlite3-sys = { version = ">=0.8.0, <0.17.0", optional = true, features = ["min_sqlite_version_3_7_16"] } +libsqlite3-sys = { version = ">=0.8.0, <0.18.0", optional = true, features = ["min_sqlite_version_3_7_16"] } [dev-dependencies] difference = "1.0" tempdir = "0.3.4" regex = "0.2" -url = { version = "1.4.0" } +url = { version = "2.1.0" } [features] default = ["postgres", "sqlite", "mysql"] diff --git a/diesel_migrations/migrations_internals/src/migration.rs b/diesel_migrations/migrations_internals/src/migration.rs index fad2ec8c2904..3ccedb907a47 100644 --- a/diesel_migrations/migrations_internals/src/migration.rs +++ b/diesel_migrations/migrations_internals/src/migration.rs @@ -46,12 +46,12 @@ pub fn file_name<'a>(migration: &'a dyn Migration, sql_file: &'a str) -> Migrati impl<'a> fmt::Display for MigrationFileName<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let fpath = match self.migration.file_path() { - None => return Err(fmt::Error), - Some(v) => v.join(self.sql_file), - }; - f.write_str(fpath.to_str().unwrap_or("Invalid utf8 in filename"))?; - Ok(()) + if let Some(path) = self.migration.file_path() { + let fpath = path.join(self.sql_file); + f.write_str(fpath.to_str().unwrap_or("Invalid utf8 in filename")) + } else { + write!(f, "{}/{}", self.migration.version(), self.sql_file) + } } } diff --git a/diesel_tests/Cargo.toml b/diesel_tests/Cargo.toml index 26f262a9c18a..533bad308b14 100644 --- a/diesel_tests/Cargo.toml +++ b/diesel_tests/Cargo.toml @@ -14,14 +14,14 @@ dotenv = ">=0.8, <0.11" [dependencies] assert_matches = "1.0.1" chrono = { version = "0.4" } -diesel = { path = "../diesel", default-features = false, features = ["quickcheck", "chrono", "uuid", "serde_json", "network-address", "numeric", "with-deprecated"] } +diesel = { path = "../diesel", default-features = false, features = ["quickcheck", "chrono", "uuidv07", "serde_json", "network-address", "numeric", "with-deprecated"] } diesel_migrations = { version = "1.4.0" } diesel_infer_schema = { version = "1.4.0" } dotenv = ">=0.8, <0.11" quickcheck = { version = "0.4", features = ["unstable"] } -uuid = { version = ">=0.2.0, <0.7.0" } +uuid = { version = ">=0.7.0, <0.9.0" } serde_json = { version=">=0.9, <2.0" } -ipnetwork = ">=0.12.2, <0.16.0" +ipnetwork = ">=0.12.2, <0.17.0" bigdecimal = ">= 0.0.10, <= 0.1.0" [features]