Browse Source

Force MySQL to use correct name and collation

This should force all MySQL/MariaDB connections to use the correct names and collation to be `utf8mb4` and `utf8mb4_unicode_ci`.
It will not fix current tables which have the wrong charset or collation, but it should prevent new databases and future additions to use the wrong set.

Also made sure that the init statements are also applied during migrations, which currently did not happen.

Should prevent / resolve #6611 like issues in the future.

Signed-off-by: BlackDex <black.dex@gmail.com>
pull/6694/head
BlackDex 2 weeks ago
parent
commit
9a320171e5
No known key found for this signature in database GPG Key ID: 58C80A2AA6C765E1
  1. 2
      .env.template
  2. 43
      src/db/mod.rs

2
.env.template

@ -97,7 +97,7 @@
## This is mainly useful for connection-scoped pragmas. ## This is mainly useful for connection-scoped pragmas.
## If empty, a database-specific default is used: ## If empty, a database-specific default is used:
## - SQLite: "PRAGMA busy_timeout = 5000; PRAGMA synchronous = NORMAL;" ## - SQLite: "PRAGMA busy_timeout = 5000; PRAGMA synchronous = NORMAL;"
## - MySQL: "" ## - MySQL: "SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci;"
## - PostgreSQL: "" ## - PostgreSQL: ""
# DATABASE_CONN_INIT="" # DATABASE_CONN_INIT=""

43
src/db/mod.rs

@ -197,15 +197,15 @@ impl DbPool {
match conn_type { match conn_type {
#[cfg(mysql)] #[cfg(mysql)]
DbConnType::Mysql => { DbConnType::Mysql => {
mysql_migrations::run_migrations(&db_url)?; mysql_migrations::run_migrations(&db_url, &conn_type)?;
} }
#[cfg(postgresql)] #[cfg(postgresql)]
DbConnType::Postgresql => { DbConnType::Postgresql => {
postgresql_migrations::run_migrations(&db_url)?; postgresql_migrations::run_migrations(&db_url, &conn_type)?;
} }
#[cfg(sqlite)] #[cfg(sqlite)]
DbConnType::Sqlite => { DbConnType::Sqlite => {
sqlite_migrations::run_migrations(&db_url)?; sqlite_migrations::run_migrations(&db_url, &conn_type)?;
} }
} }
@ -294,7 +294,7 @@ impl DbConnType {
pub fn default_init_stmts(&self) -> String { pub fn default_init_stmts(&self) -> String {
match self { match self {
#[cfg(mysql)] #[cfg(mysql)]
Self::Mysql => String::new(), Self::Mysql => "SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci;".to_string(),
#[cfg(postgresql)] #[cfg(postgresql)]
Self::Postgresql => String::new(), Self::Postgresql => String::new(),
#[cfg(sqlite)] #[cfg(sqlite)]
@ -460,16 +460,24 @@ impl<'r> FromRequest<'r> for DbConn {
// https://docs.rs/diesel_migrations/*/diesel_migrations/macro.embed_migrations.html // https://docs.rs/diesel_migrations/*/diesel_migrations/macro.embed_migrations.html
#[cfg(sqlite)] #[cfg(sqlite)]
mod sqlite_migrations { mod sqlite_migrations {
use super::DbConnType;
use diesel::{Connection, RunQueryDsl}; use diesel::{Connection, RunQueryDsl};
use diesel_migrations::{EmbeddedMigrations, MigrationHarness}; use diesel_migrations::{EmbeddedMigrations, MigrationHarness};
pub const MIGRATIONS: EmbeddedMigrations = embed_migrations!("migrations/sqlite"); pub const MIGRATIONS: EmbeddedMigrations = embed_migrations!("migrations/sqlite");
pub fn run_migrations(db_url: &str) -> Result<(), super::Error> { pub fn run_migrations(db_url: &str, conn_type: &DbConnType) -> Result<(), super::Error> {
// Establish a connection to the sqlite database (this will create a new one, if it does // Establish a connection to the sqlite database (this will create a new one, if it does
// not exist, and exit if there is an error). // not exist, and exit if there is an error).
let mut connection = diesel::sqlite::SqliteConnection::establish(db_url)?; let mut connection = diesel::sqlite::SqliteConnection::establish(db_url)?;
// Run the migrations after successfully establishing a connection // Run the migrations after successfully establishing a connection
// First run any init statement
let init_stmts = conn_type.get_init_stmts();
if !init_stmts.is_empty() {
diesel::sql_query(init_stmts)
.execute(&mut connection)
.expect("Failed execute init statements during migrations");
}
// Disable Foreign Key Checks during migration // Disable Foreign Key Checks during migration
// Scoped to a connection. // Scoped to a connection.
diesel::sql_query("PRAGMA foreign_keys = OFF") diesel::sql_query("PRAGMA foreign_keys = OFF")
@ -488,14 +496,23 @@ mod sqlite_migrations {
#[cfg(mysql)] #[cfg(mysql)]
mod mysql_migrations { mod mysql_migrations {
use super::DbConnType;
use diesel::{Connection, RunQueryDsl}; use diesel::{Connection, RunQueryDsl};
use diesel_migrations::{EmbeddedMigrations, MigrationHarness}; use diesel_migrations::{EmbeddedMigrations, MigrationHarness};
pub const MIGRATIONS: EmbeddedMigrations = embed_migrations!("migrations/mysql"); pub const MIGRATIONS: EmbeddedMigrations = embed_migrations!("migrations/mysql");
pub fn run_migrations(db_url: &str) -> Result<(), super::Error> { pub fn run_migrations(db_url: &str, conn_type: &DbConnType) -> Result<(), super::Error> {
// Make sure the database is up to date (create if it doesn't exist, or run the migrations) // Make sure the database is up to date (create if it doesn't exist, or run the migrations)
let mut connection = diesel::mysql::MysqlConnection::establish(db_url)?; let mut connection = diesel::mysql::MysqlConnection::establish(db_url)?;
// Run the migrations after successfully establishing a connection
// First run any init statement
let init_stmts = conn_type.get_init_stmts();
if !init_stmts.is_empty() {
diesel::sql_query(init_stmts)
.execute(&mut connection)
.expect("Failed execute init statements during migrations");
}
// Disable Foreign Key Checks during migration // Disable Foreign Key Checks during migration
// Scoped to a connection/session. // Scoped to a connection/session.
diesel::sql_query("SET FOREIGN_KEY_CHECKS = 0") diesel::sql_query("SET FOREIGN_KEY_CHECKS = 0")
@ -509,14 +526,24 @@ mod mysql_migrations {
#[cfg(postgresql)] #[cfg(postgresql)]
mod postgresql_migrations { mod postgresql_migrations {
use diesel::Connection; use super::DbConnType;
use diesel::{Connection, RunQueryDsl};
use diesel_migrations::{EmbeddedMigrations, MigrationHarness}; use diesel_migrations::{EmbeddedMigrations, MigrationHarness};
pub const MIGRATIONS: EmbeddedMigrations = embed_migrations!("migrations/postgresql"); pub const MIGRATIONS: EmbeddedMigrations = embed_migrations!("migrations/postgresql");
pub fn run_migrations(db_url: &str) -> Result<(), super::Error> { pub fn run_migrations(db_url: &str, conn_type: &DbConnType) -> Result<(), super::Error> {
// Make sure the database is up to date (create if it doesn't exist, or run the migrations) // Make sure the database is up to date (create if it doesn't exist, or run the migrations)
let mut connection = diesel::pg::PgConnection::establish(db_url)?; let mut connection = diesel::pg::PgConnection::establish(db_url)?;
// Run the migrations after successfully establishing a connection
// First run any init statement
let init_stmts = conn_type.get_init_stmts();
if !init_stmts.is_empty() {
diesel::sql_query(init_stmts)
.execute(&mut connection)
.expect("Failed execute init statements during migrations");
}
connection.run_pending_migrations(MIGRATIONS).expect("Error running migrations"); connection.run_pending_migrations(MIGRATIONS).expect("Error running migrations");
Ok(()) Ok(())
} }

Loading…
Cancel
Save