@@ -227,8 +227,57 @@ function delete_existing_prototypes($contextid) {
227227 AND q.name LIKE 'BUILT%IN_PROTOTYPE_%' " ;
228228 $ prototypes = $ DB ->get_records_sql ($ query , [$ contextid ]);
229229 foreach ($ prototypes as $ question ) {
230- $ DB ->delete_records ('question_coderunner_options ' , ['questionid ' => $ question ->id ]);
231- $ DB ->delete_records ('question ' , ['id ' => $ question ->id ]);
230+ // Use Moodle's proper question deletion API which handles all related tables
231+ // including question_versions, question_bank_entries, and other dependencies.
232+ question_delete_question ($ question ->id );
233+ }
234+
235+ // Clean up any orphaned version records from previous upgrades that used
236+ // the old direct deletion method. Only clean up records that were originally
237+ // BUILTIN_PROTOTYPE questions by checking the naming pattern.
238+ $ orphanedversions = $ DB ->get_records_sql (
239+ "SELECT DISTINCT qv.id
240+ FROM {question_versions} qv
241+ JOIN {question_bank_entries} qbe ON qbe.id = qv.questionbankentryid
242+ JOIN {question_categories} qc ON qc.id = qbe.questioncategoryid
243+ LEFT JOIN {question} q ON q.id = qv.questionid
244+ WHERE qc.contextid = ?
245+ AND qc.name = 'CR_PROTOTYPES'
246+ AND q.id IS NULL
247+ AND EXISTS (
248+ SELECT 1 FROM {question_versions} qv2
249+ JOIN {question} q2 ON q2.id = qv2.questionid
250+ WHERE qv2.questionbankentryid = qbe.id
251+ AND q2.name LIKE 'BUILT%IN_PROTOTYPE_%'
252+ ) " ,
253+ [$ contextid ]
254+ );
255+
256+ if (!empty ($ orphanedversions )) {
257+ mtrace (" Cleaning up " . count ($ orphanedversions ) . " orphaned prototype version records " );
258+ foreach ($ orphanedversions as $ versionrecord ) {
259+ $ DB ->delete_records ('question_versions ' , ['id ' => $ versionrecord ->id ]);
260+ }
261+ }
262+
263+ // Clean up any orphaned bank entries that have no versions left and were
264+ // originally for prototypes.
265+ $ orphanedentries = $ DB ->get_records_sql (
266+ "SELECT DISTINCT qbe.id
267+ FROM {question_bank_entries} qbe
268+ JOIN {question_categories} qc ON qc.id = qbe.questioncategoryid
269+ LEFT JOIN {question_versions} qv ON qv.questionbankentryid = qbe.id
270+ WHERE qc.contextid = ?
271+ AND qc.name = 'CR_PROTOTYPES'
272+ AND qv.id IS NULL " ,
273+ [$ contextid ]
274+ );
275+
276+ if (!empty ($ orphanedentries )) {
277+ mtrace (" Cleaning up " . count ($ orphanedentries ) . " orphaned prototype bank entries " );
278+ foreach ($ orphanedentries as $ entryrecord ) {
279+ $ DB ->delete_records ('question_bank_entries ' , ['id ' => $ entryrecord ->id ]);
280+ }
232281 }
233282}
234283
0 commit comments