From b1ca7b32deeb4b5a6d32d875ebfbc8b5e2924629 Mon Sep 17 00:00:00 2001 From: Fritz Elfert Date: Tue, 21 Oct 2025 09:35:40 +0200 Subject: [PATCH] fix: mariadb compatibility Partially reverting #1717 According to MySQL docs (even in latest MySQL 9.4) FOR SHARE and LOCK IN SHARE MODE are equivalent. MariaDB implements the latter only. The additional options mentioned in the docs are not used here. Closes #1753 --- syncstorage-mysql/src/diesel_ext.rs | 33 +++++++++++++++++++++++++++++ syncstorage-mysql/src/models.rs | 3 ++- 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/syncstorage-mysql/src/diesel_ext.rs b/syncstorage-mysql/src/diesel_ext.rs index 18abb4a2..61824fd1 100644 --- a/syncstorage-mysql/src/diesel_ext.rs +++ b/syncstorage-mysql/src/diesel_ext.rs @@ -3,11 +3,44 @@ use std::{fmt::Debug, marker::PhantomData}; use diesel::{ backend::Backend, insertable::CanInsertInSingleQuery, + mysql::Mysql, query_builder::{AstPass, InsertStatement, QueryFragment, QueryId}, + query_dsl::methods::LockingDsl, result::QueryResult, Expression, QuerySource, RunQueryDsl, }; +/// Emit MySQL <= 5.7's `LOCK IN SHARE MODE` +/// +/// MySQL 8 supports `FOR SHARE` as an alias (which diesel natively supports) +/// This is required for MariaDB which does not provide that alias. +pub trait LockInShareModeDsl { + type Output; + + fn lock_in_share_mode(self) -> Self::Output; +} + +impl LockInShareModeDsl for T +where + T: LockingDsl, +{ + type Output = >::Output; + + fn lock_in_share_mode(self) -> Self::Output { + self.with_lock(LockInShareMode) + } +} + +#[derive(Debug, Clone, Copy, QueryId)] +pub struct LockInShareMode; + +impl QueryFragment for LockInShareMode { + fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, Mysql>) -> QueryResult<()> { + out.push_sql(" LOCK IN SHARE MODE"); + Ok(()) + } +} + #[allow(dead_code)] // Not really dead, Rust can't see it. #[derive(Debug, Clone)] pub struct OnDuplicateKeyUpdate( diff --git a/syncstorage-mysql/src/models.rs b/syncstorage-mysql/src/models.rs index 7382d1b8..ddcb73a1 100644 --- a/syncstorage-mysql/src/models.rs +++ b/syncstorage-mysql/src/models.rs @@ -19,6 +19,7 @@ use syncstorage_settings::{Quota, DEFAULT_MAX_TOTAL_RECORDS}; use super::{ batch, + diesel_ext::LockInShareModeDsl, pool::{CollectionCache, Conn}, schema::{bso, collections, user_collections}, DbError, DbResult, @@ -133,7 +134,7 @@ impl MysqlDb { .select(user_collections::modified) .filter(user_collections::user_id.eq(user_id)) .filter(user_collections::collection_id.eq(collection_id)) - .for_share() + .lock_in_share_mode() .first(&mut self.conn) .await .optional()?;