From ec5d7c3227dd3ee44086520cea2859083cd4f24e Mon Sep 17 00:00:00 2001 From: Mark Johnson Date: Wed, 11 Oct 2023 16:07:45 +0100 Subject: [PATCH] MDL-79639 quiz_statistics: Prevent database deadlocks This changes the cache purge code to select IDs for deletion first, rather than using a subquery in a DELETE, since this risks causing a deadlock in MySQL. --- .../responses/analysis_for_question.php | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/question/classes/statistics/responses/analysis_for_question.php b/question/classes/statistics/responses/analysis_for_question.php index 4e1fd670332..a2520f923af 100644 --- a/question/classes/statistics/responses/analysis_for_question.php +++ b/question/classes/statistics/responses/analysis_for_question.php @@ -208,15 +208,21 @@ class analysis_for_question { $transaction = $DB->start_delegated_transaction(); - $DB->delete_records_select('question_response_count', - 'analysisid IN ( - SELECT id - FROM {question_response_analysis} - WHERE hashcode= ? AND whichtries = ? AND questionid = ? - )', [$qubaids->get_hash_code(), $whichtries, $questionid]); - - $DB->delete_records('question_response_analysis', - ['hashcode' => $qubaids->get_hash_code(), 'whichtries' => $whichtries, 'questionid' => $questionid]); + $analysisids = $DB->get_fieldset_select( + 'question_response_analysis', + 'id', + 'hashcode = ? AND whichtries = ? AND questionid = ?', + [ + $qubaids->get_hash_code(), + $whichtries, + $questionid, + ] + ); + if (!empty($analysisids)) { + [$insql, $params] = $DB->get_in_or_equal($analysisids); + $DB->delete_records_select('question_response_count', 'analysisid ' . $insql, $params); + $DB->delete_records_select('question_response_analysis', 'id ' . $insql, $params); + } foreach ($this->get_variant_nos() as $variantno) { foreach ($this->get_subpart_ids($variantno) as $subpartid) {