]> git.mjollnir.org Git - moodle.git/commitdiff
fix undefined variable $db
authorgbateson <gbateson>
Fri, 28 Apr 2006 00:59:57 +0000 (00:59 +0000)
committergbateson <gbateson>
Fri, 28 Apr 2006 00:59:57 +0000 (00:59 +0000)
mod/hotpot/db/update_to_v2.php

index d6ce9a2a60d459ed0a6f8cd50542d7cb2bc194a4..3d2cba9a4938957b593ed9eafac0fdd3da78d991 100644 (file)
-<?PHP\r
-function hotpot_update_to_v2_1_18() {\r
-       $ok = true;\r
-\r
-       // remove all orphan records (there shouldn't be any, but if there are they can mess up the utfdbmigrate)\r
-\r
-       $ok = $ok && hotpot_remove_orphans('hotpot_attempts', 'hotpot', 'hotpot');\r
-       $ok = $ok && hotpot_remove_orphans('hotpot_questions', 'hotpot', 'hotpot');\r
-       $ok = $ok && hotpot_remove_orphans('hotpot_responses', 'attempt', 'hotpot_attempts');\r
-       $ok = $ok && hotpot_remove_orphans('hotpot_responses', 'question', 'hotpot_questions');\r
-       $ok = $ok && hotpot_remove_orphans('hotpot_details', 'attempt', 'hotpot_attempts');\r
-\r
-       return $ok;\r
-}\r
-function hotpot_remove_orphans($secondarytable, $secondarykeyfield, $primarytable, $primarykeyfield='id') {\r
-       global $CFG;\r
-       $ok = true;\r
-\r
-       // save and switch off SQL message echo\r
-       $debug = $db->debug;\r
-       $db->debug = false;\r
-\r
-       $records = get_records_sql("\r
-               SELECT \r
-                       t2.$secondarykeyfield, t2.$secondarykeyfield\r
-               FROM \r
-                       {$CFG->prefix}$secondarytable AS t2 LEFT JOIN {$CFG->prefix}$primarytable AS t1 \r
-                       ON (t2.$secondarykeyfield = t1.$primarykeyfield)\r
-               WHERE \r
-                       t1.$primarykeyfield IS NULL\r
-               ORDER BY \r
-                       t2.$secondarykeyfield\r
-       ");\r
-\r
-       // restore SQL message echo setting\r
-       $db->debug = $debug;\r
-\r
-       if ($records) {\r
-               $ids = implode(',', array_keys($records));\r
-               print 'removing '.count($ids).' orphan record(s) from {$CFG->prefix}$secondarytable (key=$secondarykeyfield) ...<br>';\r
-               $ok = $ok && execute_sql("DELETE FROM {$CFG->prefix}$secondarytable WHERE $secondarykeyfield IN ($ids)");\r
-       }\r
-\r
-       return $ok;\r
-}\r
-function hotpot_update_to_v2_1_17() {\r
-       global $CFG;\r
-       $ok = true;\r
-\r
-       // convert and disable null values on certain numeric fields\r
-\r
-       $ok = $ok && hotpot_denull_int_field('hotpot_attempts', 'starttime', '10');\r
-       $ok = $ok && hotpot_denull_int_field('hotpot_attempts', 'endtime', '10');\r
-       $ok = $ok && hotpot_denull_int_field('hotpot_attempts', 'score', '6');\r
-       $ok = $ok && hotpot_denull_int_field('hotpot_attempts', 'penalties',  '6');\r
-       $ok = $ok && hotpot_denull_int_field('hotpot_attempts', 'timestart', '10');\r
-       $ok = $ok && hotpot_denull_int_field('hotpot_attempts', 'timefinish', '10');\r
-       $ok = $ok && hotpot_denull_int_field('hotpot_attempts', 'clickreportid', '10');\r
-\r
-       $ok = $ok && hotpot_denull_int_field('hotpot_questions', 'type', '4');\r
-       $ok = $ok && hotpot_denull_int_field('hotpot_questions', 'text', '10');\r
-\r
-       $ok = $ok && hotpot_denull_int_field('hotpot_responses', 'weighting', '6');\r
-       $ok = $ok && hotpot_denull_int_field('hotpot_responses', 'score', '6');\r
-       $ok = $ok && hotpot_denull_int_field('hotpot_responses', 'hints', '6');\r
-       $ok = $ok && hotpot_denull_int_field('hotpot_responses', 'clues', '6');\r
-       $ok = $ok && hotpot_denull_int_field('hotpot_responses', 'checks', '6');\r
-       return $ok;\r
-}\r
-function hotpot_denull_int_field($table, $field, $size) {\r
-       global $CFG;\r
-       $ok = true;\r
-\r
-       $ok = $ok && execute_sql("UPDATE {$CFG->prefix}$table SET $field=0 WHERE $field IS NULL");\r
-       $ok = $ok && hotpot_db_update_field_type($table, $field, $field, 'INTEGER', $size, 'UNSIGNED', 'NOT NULL', 0);\r
-\r
-       return $ok;\r
-}\r
-function hotpot_update_to_v2_1_16() {\r
-       global $CFG;\r
-       $ok = true;\r
-\r
-       // settings for the "hotpot_questions_name_idx" index\r
-       $length = 20;\r
-       $field = 'name';\r
-       $table = 'hotpot_questions';\r
-       $index = "{$table}_{$field}_idx";\r
-\r
-       // remove the index\r
-       hotpot_db_delete_index("{$CFG->prefix}$table", $index);\r
-       hotpot_db_delete_index("{$CFG->prefix}$table", "{$CFG->prefix}$index");\r
-\r
-       // make sure type of 'name' is a text field (not varchar 255)\r
-       $ok = $ok && hotpot_db_update_field_type($table, $field, $field, 'TEXT',   '',  '', 'NOT NULL', '');\r
-\r
-       // restore the index\r
-       $ok = $ok && hotpot_db_add_index($table, $field, $length);\r
-\r
-       if (strtolower($CFG->dbtype)=='mysql') {\r
-\r
-               // set default values on certain VARCHAR(255) fields\r
-               $varchar_fields = array(\r
-                       'hotpot.studentfeedbackurl',\r
-                       'hotpot_responses.correct',\r
-                       'hotpot_responses.wrong',\r
-                       'hotpot_responses.ignored'\r
-               );\r
-               foreach ($varchar_fields as $varchar_field) {\r
-                       list ($table, $field) = explode('.', $varchar_field);\r
-                       execute_sql("UPDATE {$CFG->prefix}$table SET $field='' WHERE $field IS NULL");\r
-                       $ok = $ok && hotpot_db_update_field_type($table, $field, $field, 'VARCHAR', 255, '', 'NOT NULL', '');\r
-               }\r
-\r
-               // remove $CFG->prefix from all index names\r
-               $ok = $ok && hotpot_index_remove_prefix('hotpot_attempts', 'hotpot');\r
-               $ok = $ok && hotpot_index_remove_prefix('hotpot_attempts', 'userid');\r
-               $ok = $ok && hotpot_index_remove_prefix('hotpot_details', 'attempt');\r
-               $ok = $ok && hotpot_index_remove_prefix('hotpot_questions', 'hotpot');\r
-               //$ok = $ok && hotpot_index_remove_prefix('hotpot_questions', 'name', 20);\r
-               $ok = $ok && hotpot_index_remove_prefix('hotpot_responses', 'attempt');\r
-               $ok = $ok && hotpot_index_remove_prefix('hotpot_responses', 'question');\r
-               $ok = $ok && hotpot_index_remove_prefix('hotpot_strings', 'string', 20);\r
-       }\r
-       return $ok;\r
-}\r
-function hotpot_index_remove_prefix($table, $field, $length=0) {\r
-       global $CFG;\r
-       $index = "{$table}_{$field}_idx";\r
-       hotpot_db_delete_index("{$CFG->prefix}$table", "{$CFG->prefix}$index");\r
-       hotpot_db_delete_index("{$CFG->prefix}$table", $index);\r
-       return hotpot_db_add_index($table, $field, $length);\r
-}\r
-\r
-function hotpot_update_to_v2_1_8() {\r
-       global $CFG;\r
-       $ok = true;\r
-       if (strtolower($CFG->dbtype)=='postgres7') {\r
-               // add, delete and rename certain fields and indexes\r
-               // that were not correctly setup by postgres7.sql\r
-\r
-               // hotpot\r
-               $table = 'hotpot';\r
-               if (hotpot_db_field_exists($table, 'microreporting')) {\r
-                       $ok = $ok && hotpot_db_update_field_type($table, 'microreporting', 'clickreporting', 'INTEGER', 4, 'UNSIGNED', 'NOT NULL', '0');\r
-               }\r
-       }\r
-       return $ok;\r
-}\r
-function hotpot_update_to_v2_1_6() {\r
-       global $CFG;\r
-       $ok = true;\r
-\r
-       if (strtolower($CFG->dbtype)=='postgres7') {\r
-               // add, delete and rename certain fields and indexes\r
-               // that were not correctly setup by postgres7.sql\r
-\r
-               // hotpot\r
-               $table = 'hotpot';\r
-               if (hotpot_db_field_exists($table, 'studentfeedback') && !hotpot_db_field_exists($table, 'studentfeedbackurl')) {\r
-                       $ok = $ok && hotpot_db_update_field_type($table, 'studentfeedback', 'studentfeedbackurl', 'VARCHAR', 255, '', 'NULL');\r
-                       $ok = $ok && hotpot_db_update_field_type($table, '', 'studentfeedback', 'INTEGER', 4, 'UNSIGNED', 'NOT NULL', '0');\r
-               }\r
-\r
-               // hotpot_attempts\r
-               $table = 'hotpot_attempts';\r
-               $ok = $ok && hotpot_db_remove_field($table, 'groupid');\r
-               if (hotpot_db_field_exists($table, 'microreportid') && !hotpot_db_field_exists($table, 'clickreportid')) {\r
-                       $ok = $ok && hotpot_db_update_field_type($table, 'microreportid', 'clickreportid', 'INTEGER', 10, 'UNSIGNED', 'NULL');\r
-               }\r
-\r
-               // hotpot_questions (add index on question "name")\r
-               $table = 'hotpot_questions';\r
-               $field = 'name';\r
-               $index = "{$table}_{$field}_idx";\r
-               if (!hotpot_db_index_exists("{$CFG->prefix}$table", "{$CFG->prefix}$index")) {\r
-                       hotpot_db_add_index($table, $field, '20');\r
-               }\r
-\r
-               // hotpot_strings (add index on "string")\r
-               $table = "hotpot_strings";\r
-               $field = 'string';\r
-               $index = "{$table}_{$field}_idx";\r
-               if (!hotpot_db_index_exists("{$CFG->prefix}$table", "{$CFG->prefix}$index")) {\r
-                       hotpot_db_add_index($table, $field, '20');\r
-               }\r
-       }\r
-\r
-       return $ok;\r
-}\r
-function hotpot_update_to_v2_1_2() {\r
-       global $CFG, $db;\r
-       $ok = true;\r
-\r
-       // save and switch off SQL message echo\r
-       $debug = $db->debug;\r
-       $db->debug = false;\r
-\r
-       // extract info about attempts by each user on each hotpot (cases where \r
-       // the user has only one attempt, or no "in progess" attempt are ignored)\r
-       $rs = $db->Execute("\r
-               SELECT userid, hotpot, COUNT(*), MIN(status)\r
-               FROM {$CFG->prefix}hotpot_attempts\r
-               GROUP BY userid, hotpot\r
-               HAVING COUNT(*)>1 AND MIN(status)=1\r
-       ");\r
-       if ($rs && $rs->RecordCount()) {\r
-               $records = $rs->GetArray();\r
-\r
-               // start message to browser\r
-               print "adjusting status of ".count($records)." &quot;in progress&quot; attempts ... ";\r
-\r
-               // loop through records\r
-               foreach ($records as $record) {\r
-\r
-                       // get all attempts by this user at this hotpot\r
-                       $attempts = get_records_sql("\r
-                               SELECT id, userid, hotpot, score, timestart, timefinish, status \r
-                               FROM {$CFG->prefix}hotpot_attempts \r
-                               WHERE userid = ".$record['userid']." AND hotpot=".$record['hotpot']."\r
-                               ORDER BY timestart DESC, id DESC\r
-                       ");\r
-\r
-                       unset($previous_timestart);\r
-\r
-                       foreach ($attempts as $attempt) {\r
-                               // if this attempt has a status of "in progress" and is not \r
-                               // the most recent one in the group, set the status to "abandoned"\r
-                               if ($attempt->status==1 && isset($previous_timestart)) {\r
-                                       $values = 'status=3';\r
-                                       if (empty($attempt->score)) {\r
-                                               $values .= ',score=0';\r
-                                       }\r
-                                       if (empty($attempt->timefinish)) {\r
-                                               $values .= ",timefinish=$previous_timestart";\r
-                                       }\r
-                                       execute_sql("UPDATE {$CFG->prefix}hotpot_attempts SET $values WHERE id=$attempt->id", false);\r
-                                       print ".";\r
-                                       hotpot_flush(300);\r
-                               }\r
-                               $previous_timestart = $attempt->timestart;\r
-                       } // end foreach $attempts\r
-               } // end foreach $records\r
-\r
-               // finish message to browser\r
-               print $ok ? get_string('success') : 'failed';\r
-               print "<br />\n";\r
-       }\r
-\r
-       // restore SQL message echo setting\r
-       $db->debug = $debug;\r
-\r
-       return $ok;\r
-}\r
-function hotpot_update_to_v2_1() {\r
-       global $CFG, $db;\r
-       $ok = true;\r
-       // hotpot_questions: reduce size of "type" field to "4"\r
-       $ok = $ok && hotpot_db_update_field_type('hotpot_questions', 'type', 'type', 'INTEGER', 4,  'UNSIGNED', 'NULL');\r
-       // hotpot_questions: change type of "name" field to "text"\r
-       $ok = $ok && hotpot_db_update_field_type('hotpot_questions', 'name', 'name', 'TEXT',   '',  '', 'NOT NULL', '');\r
-       // hotpot_questions: nullify empty and non-numeric (shouldn't be any) values in "text" field\r
-       switch (strtolower($CFG->dbtype)) {\r
-               case 'mysql' : \r
-                       $NOT_REGEXP = 'NOT REGEXP';\r
-               break;\r
-               case 'postgres7' :\r
-                       $NOT_REGEXP = '!~';\r
-               break;\r
-               default:\r
-                       $NOT_REGEXP = '';\r
-               break;\r
-       }\r
-       if ($NOT_REGEXP) {\r
-               $ok = $ok && execute_sql("UPDATE {$CFG->prefix}hotpot_questions SET text=NULL WHERE text $NOT_REGEXP '^[0-9]+$'");\r
-       }\r
-       // hotpot_questions: change type of "text" field to "INT(10)"\r
-       $ok = $ok && hotpot_db_update_field_type('hotpot_questions', 'text', 'text', 'INTEGER', 10, 'UNSIGNED', 'NULL');\r
-       // hotpot_attempts\r
-       // hotpot_attempts: move "details" to separate table\r
-       $table = 'hotpot_details';\r
-       if (hotpot_db_table_exists($table)) {\r
-               // do nothing\r
-       } else {\r
-               $ok = $ok && hotpot_create_table($table);\r
-               switch (strtolower($CFG->dbtype)) {\r
-                       case 'mysql' : \r
-                       case 'postgres7' :\r
-                               $sql = "\r
-                                       INSERT INTO {$CFG->prefix}$table (attempt, details) \r
-                                       SELECT a.id AS attempt, a.details AS details\r
-                                               FROM {$CFG->prefix}hotpot_attempts AS a\r
-                                               WHERE \r
-                                                       a.details IS NOT NULL AND a.details <> ''\r
-                                                       AND a.details LIKE '<?xml%' AND a.details LIKE '%</hpjsresult>'\r
-                               ";\r
-                       break;\r
-                       default:\r
-                               $sql = '';\r
-                       break;\r
-               }\r
-               if ($sql) {\r
-                       $ok = $ok && execute_sql($sql);\r
-               }\r
-       }\r
-       // hotpot_attempts: remove the "details" field\r
-       $ok = $ok && hotpot_db_remove_field('hotpot_attempts', 'details');\r
-       // hotpot_attempts: create and set status field (1=in-progress, 2=timed-out, 3=abandoned, 4=completed)\r
-       $ok = $ok && hotpot_db_update_field_type('hotpot_attempts', '', 'status', 'INTEGER', 4, 'UNSIGNED', 'NOT NULL', 1);\r
-       $ok = $ok && execute_sql("UPDATE {$CFG->prefix}hotpot_attempts SET status=1 WHERE timefinish=0 AND SCORE IS NULL");\r
-       $ok = $ok && execute_sql("UPDATE {$CFG->prefix}hotpot_attempts SET status=3 WHERE timefinish>0 AND SCORE IS NULL");\r
-       $ok = $ok && execute_sql("UPDATE {$CFG->prefix}hotpot_attempts SET status=4 WHERE timefinish>0 AND SCORE IS NOT NULL");\r
-       // hotpot_attempts: create and set clickreport fields\r
-       $ok = $ok && hotpot_db_update_field_type('hotpot', '', 'clickreporting', 'INTEGER', 4, 'UNSIGNED', 'NOT NULL', 0);\r
-       $ok = $ok && hotpot_db_update_field_type('hotpot_attempts', '', 'clickreportid', 'INTEGER', 10, 'UNSIGNED', 'NULL');\r
-       $ok = $ok && execute_sql("UPDATE {$CFG->prefix}hotpot_attempts SET clickreportid=id WHERE clickreportid IS NULL");\r
-       // hotpot_attempts: create and set studentfeedback field (0=none, 1=formmail, 2=moodleforum, 3=moodlemessaging)\r
-       $ok = $ok && hotpot_db_update_field_type('hotpot', '', 'studentfeedback', 'INTEGER', 4, 'UNSIGNED', 'NOT NULL', '0');\r
-       $ok = $ok && hotpot_db_update_field_type('hotpot', '', 'studentfeedbackurl', 'VARCHAR', 255, '', 'NULL');\r
-       // add indexes\r
-       $ok = $ok && hotpot_db_add_index('hotpot_attempts', 'hotpot');\r
-       $ok = $ok && hotpot_db_add_index('hotpot_attempts', 'userid');\r
-       $ok = $ok && hotpot_db_add_index('hotpot_details', 'attempt');\r
-       $ok = $ok && hotpot_db_add_index('hotpot_questions', 'name', 20);\r
-       $ok = $ok && hotpot_db_add_index('hotpot_questions', 'hotpot');\r
-       $ok = $ok && hotpot_db_add_index('hotpot_responses', 'attempt');\r
-       $ok = $ok && hotpot_db_add_index('hotpot_responses', 'question');\r
-       $ok = $ok && hotpot_db_add_index('hotpot_strings', 'string', 20);\r
-       // hotpot_string: correct double-encoded HTML entities\r
-       $ok = $ok && execute_sql("\r
-               UPDATE {$CFG->prefix}hotpot_strings \r
-               SET string = REPLACE(string, '&amp;','&') \r
-               WHERE string LIKE '%&amp;#%' \r
-               AND (string LIKE '<' OR string LIKE '>')\r
-       ");\r
-       // hotpot_question: remove questions which refer to deleted hotpots\r
-       if ($ok) {\r
-               // try and get all hotpot records\r
-               if ($records = get_records('hotpot')) {\r
-                       $ids = implode(',', array_keys($records));\r
-                       $sql = "DELETE FROM {$CFG->prefix}hotpot_questions WHERE hotpot NOT IN ($ids)";\r
-               } else {\r
-                       // remove all question records (because there are no valid hotpot ids)\r
-                       $sql = "TRUNCATE {$CFG->prefix}hotpot_questions";\r
-               }\r
-               print "Removing unused question records ...";\r
-               execute_sql($sql);\r
-       }\r
-       if ($ok) {\r
-               // remove old 'v6' templates folder (replaced by 'template' folder)\r
-               $ds = DIRECTORY_SEPARATOR;\r
-               $dir = "mod{$ds}hotpot{$ds}v6";\r
-               print "removing old templates ($dir) ... ";\r
-               if (hotpot_rm("$CFG->dirroot{$ds}$dir", false)) {\r
-                       print get_string('success');\r
-               } else {\r
-                       print "failed<br>Please remove '$CFG->dirroot{$ds}$dir' manually";\r
-               }\r
-               print "<br />\n";\r
-       }\r
-       return $ok;\r
-}\r
-function hotpot_update_to_v2_from_v1() {\r
-       global $CFG;\r
-       $ok = true;\r
-       // remove, alter and add fields in database\r
-       $table = 'hotpot';\r
-       if (hotpot_db_table_exists($table)) {\r
-               $ok = $ok && hotpot_update_fields($table);\r
-       } else {\r
-               $ok = $ok && hotpot_create_table($table);\r
-       }\r
-       $table = 'hotpot_attempts';\r
-       $oldtable = 'hotpot_events';\r
-       if (hotpot_db_table_exists($oldtable)) {\r
-               $ok = $ok && hotpot_update_fields($oldtable);\r
-               $ok = $ok && hotpot_db_append_table($oldtable, $table);\r
-       } else {\r
-               $ok = $ok && hotpot_create_table($table);\r
-       }\r
-       // create new tables (from mysql.sql)\r
-       $ok = $ok && hotpot_create_table('hotpot_questions');\r
-       $ok = $ok && hotpot_create_table('hotpot_responses');\r
-       $ok = $ok && hotpot_create_table('hotpot_strings');\r
-       // remove redundant scripts\r
-       $files = array('coursefiles.php', 'details.php', 'dummy.html', 'hotpot.php', 'hotpot2db.php');\r
-       foreach ($files as $file) {\r
-               $filepath = "$CFG->dirroot/mod/hotpot/$file";\r
-               if (file_exists($filepath)) {\r
-                       @unlink($filepath); // don't worry about errors\r
-               }\r
-       }\r
-       return $ok;\r
-}\r
-function hotpot_update_to_v2_from_hotpotatoes() {\r
-       global $CFG;\r
-       $ok = true; // hope for the best!\r
-       // check we have the minimum required hotpot module\r
-       $minimum = 2005031400; \r
-       $module = get_record("modules", "name", "hotpot");\r
-       if (empty($module) || $module->version<$minimum) {\r
-               if ($module) {\r
-                       print ("<p>The update to the HotPotatoes module requires at least version $minimum of the HotPot module.</p>");\r
-                       print ("<p>The current version of the HotPot module on this site is $module->version.</p>");\r
-               }\r
-               print ("<p>Please install the latest version of the HotPot module and then try the update again.</p>");\r
-               $ok = false;\r
-       } else {\r
-               // arrays to map foreign keys\r
-               $new = array();\r
-               $new['hotpot'] = array();\r
-               $new['attempt'] = array();\r
-               $new['question'] = array();\r
-               $new['string'] = array();\r
-               // save and switch off SQL message echo\r
-               global $db;\r
-               $debug = $db->debug;\r
-               $db->debug = false;\r
-               // import hotpotatoes (and save old ids)\r
-               $ok = $ok && hotpot_update_fields('hotpotatoes');\r
-               $ok = $ok && hotpot_transfer_records('hotpotatoes', 'hotpot', array(), 'hotpot', $new);\r
-               // update course modules and logs\r
-               $ok = $ok && hotpot_update_course_modules('hotpotatoes', 'hotpot', $new);\r
-               // import hotpotatoes_strings (and save old ids)\r
-               $ok = $ok && hotpot_transfer_records('hotpotatoes_strings', 'hotpot_strings', array(), 'string', $new);\r
-               // import hotpotatoes_attempts (and save old ids)\r
-               $ok = $ok && hotpot_transfer_records('hotpotatoes_attempts', 'hotpot_attempts', array('hotpotatoes'=>'hotpot'), 'attempt', $new);\r
-               // import hotpotatoes_questions (and save old ids)\r
-               $ok = $ok && hotpot_transfer_records('hotpotatoes_questions', 'hotpot_questions', array('hotpotatoes'=>'hotpot'), 'question', $new);\r
-               // import hotpotatoes_responses\r
-               $ok = $ok && hotpot_transfer_records('hotpotatoes_responses', 'hotpot_responses', array('attempt'=>'attempt', 'question'=>'question'), 'response', $new);\r
-               // restore SQL message echo setting\r
-               $db->debug = $debug;\r
-               // remove the hotpotatoes tables, if the update went ok\r
-               if ($ok) {\r
-               //      hotpot_db_remove_table('hotpotatoes');\r
-               //      hotpot_db_remove_table('hotpotatoes_attempts');\r
-               //      hotpot_db_remove_table('hotpotatoes_questions');\r
-               //      hotpot_db_remove_table('hotpotatoes_responses');\r
-               //      hotpot_db_remove_table('hotpotatoes_strings');\r
-               }\r
-               // hide the hotpotatoes module (see admin/modules.php))\r
-               if ($ok && ($module = get_record("modules", "name", "hotpotatoes"))) {\r
-                       set_field("modules", "visible", "0", "id", $module->id);\r
-                       print '<p>All HotPotatoes activities have been imported to the HotPot module.<br />'."\n";\r
-                       print 'The HotPotatoes module has been hidden and can safely be deleted from this Moodle site.<br />'."\n";\r
-                       print ' &nbsp; &nbsp; <a href="'.$CFG->wwwroot.'/admin/modules.php">Configuration -> Modules</A>, then click &quot;Delete&quot; for &quot;Hot Potatoes XML Quiz&quot;</p>'."\n";\r
-               }\r
-       }\r
-       if ($ok) {\r
-               print '<p align="center">Thank you for using the HotPotatoes module.<br />';\r
-               print 'The HotPotatoes module has been replaced by<br />version 2 of the HotPot module. Enjoy!</p>';\r
-       }\r
-       return $ok;\r
-}\r
-function hotpot_create_table($table) {\r
-       global $CFG;\r
-       $ok = true;\r
-       static $sql;\r
-       if (empty($sql)) { // first time only\r
-               $filepath = "$CFG->dirroot/mod/hotpot/db/$CFG->dbtype.sql";\r
-               if (function_exists('file_get_contents')) {\r
-                       $sql = file_get_contents($filepath);\r
-               } else { // PHP < 4.3\r
-                       $sql = file($filepath);\r
-                       if (is_array($sql)) {\r
-                                $sql = implode('', $sql);\r
-                       }\r
-               }\r
-               if(empty($sql)) { // $sql==false\r
-                        $sql = '';\r
-               }\r
-       }\r
-       // check table does not already exist\r
-       if (!hotpot_db_table_exists($table)) {\r
-               // extract and execute all CREATE statements relating to this table\r
-               if (preg_match_all("/CREATE (TABLE|INDEX)(\s[^;]*)? prefix_{$table}(\s[^;]*)?;/s", $sql, $strings)) {\r
-                       foreach ($strings[0] as $string) {\r
-                               $ok = $ok && modify_database('', $string);\r
-                       }\r
-               } else {\r
-                       // no CREATE statements found for this $table\r
-                       $ok = false;\r
-               }\r
-       }\r
-       return $ok;\r
-}\r
-function hotpot_transfer_records($oldtable, $table, $foreignkeys, $primarykey, &$new) {\r
-       global $db;\r
-       $ok = true;\r
-       // get the records, if any\r
-       if (hotpot_db_table_exists($oldtable) && ($records = get_records($oldtable))) {\r
-               // start progress report\r
-               $i = 0;\r
-               $count = count($records);\r
-               hotpot_update_print("Transferring $count records from &quot;$oldtable&quot; to &quot;$table&quot; ... ");\r
-               // transfer all $records\r
-               foreach ($records as $record) {\r
-                       switch ($table) {\r
-                               case 'hotpot' :\r
-                                       $record->summary = addslashes($record->summary);\r
-                                       break;\r
-                               case 'hotpot_attempts' :\r
-                                       $record->details = addslashes($record->details);\r
-                                       break;\r
-                               case 'hotpot_questions' :\r
-                                       $record->name = addslashes($record->name);\r
-                                       hotpot_update_string_id_list($table, $record, 'TEXT', $new);\r
-                                       break;\r
-                               case 'hotpot_responses' :\r
-                                       hotpot_update_string_id_list($table, $record, 'correct', $new);\r
-                                       hotpot_update_string_id_list($table, $record, 'ignored', $new);\r
-                                       hotpot_update_string_id_list($table, $record, 'wrong', $new);\r
-                                       break;\r
-                               case 'hotpot_strings' :\r
-                                       $record->string = addslashes($record->string);\r
-                                       break;\r
-                       }\r
-                       // update foreign keys, if any\r
-                       foreach ($foreignkeys as $oldkey=>$key) {\r
-                               // transfer (and update) key\r
-                               $value = $record->$oldkey;\r
-                               if (isset($new[$key][$value])) {\r
-                                       $record->$key = $new[$key][$value];\r
-                               } else {\r
-                                       // foreign key could not be updated\r
-                                       $ok = hotpot_update_print_warning($key, $value, $oldtable, $record->id) && $ok;\r
-                                       unset($record->id);\r
-                               }\r
-                       }\r
-                       if ($ok && isset($record->id)) {\r
-                               // store and remove old primary key\r
-                               $id = $record->id;\r
-                               unset($record->id);\r
-                               // add the updated record and store the new id\r
-                               $new[$primarykey][$id] = insert_record($table, $record, true);\r
-                               // check id is numeric\r
-                               if (!is_numeric($new[$primarykey][$id])) {\r
-                                       hotpot_update_print("<li>Record could not added to $table table ($oldtable id=$id)</li>\n");\r
-                                       //$ok = false;\r
-                               }\r
-                       }\r
-                       $i++;\r
-                       hotpot_update_print_progress($i);\r
-               }\r
-               // finish progress report\r
-               hotpot_update_print_ok($ok);\r
-       }\r
-       return $ok;\r
-}\r
-function hotpot_update_course_modules($oldmodulename, $modulename, &$new) {\r
-       $ok = true;\r
-       $oldmoduleid = get_field('modules', 'id', 'name', $oldmodulename);\r
-       $moduleid = get_field('modules', 'id', 'name', $modulename);\r
-       if (is_numeric($oldmoduleid) && is_numeric($moduleid)) {\r
-               // get module records\r
-               if ($records = get_records('course_modules', 'module', $oldmoduleid)) {\r
-                       // start progress report\r
-                       $count = count($records);\r
-                       hotpot_update_print("Updating $count course modules from &quot;$oldmodulename&quot; to &quot;$modulename&quot; ... ");\r
-                       // update foreign keys in all $records\r
-                       foreach ($records as $record) {\r
-                               // update instance\r
-                               $instance = $record->instance;\r
-                               if (isset($new[$modulename][$instance])) {\r
-                                       $record->instance = $new[$modulename][$instance];\r
-                               } else if ($record->deleted) {\r
-                                       unset($record->id);\r
-                               } else {\r
-                                       // could not find new id of course module\r
-                                       $ok = hotpot_update_print_warning("$modulename instance", $instance, 'course_modules', $record->id) && $ok;\r
-                                       unset($record->id);\r
-                               }\r
-                               // update module id\r
-                               if ($ok && isset($record->id)) {\r
-                                       $record->module = $moduleid;\r
-                                       $ok = update_record('course_modules', $record);\r
-                               }\r
-                       }\r
-                       // finish progress report\r
-                       hotpot_update_print_ok($ok);\r
-               }\r
-               // update logs\r
-               $ok = $ok && hotpot_update_logs($oldmodulename, $modulename, $moduleid, $new);\r
-       }\r
-       return $ok;\r
-}\r
-function hotpot_update_logs($oldmodulename, $modulename, $moduleid, &$new) {\r
-       $table = 'log';\r
-       $ok = true;\r
-       // get log records for the oldmodule\r
-       if ($records = get_records($table, 'module', $oldmodulename)) {\r
-               // start progress report\r
-               $i = 0;\r
-               $count = count($records);\r
-               hotpot_update_print("Updating $count log records ... ");\r
-               // update foreign keys in all $records\r
-               foreach ($records as $record) {\r
-                       // update course module name\r
-                       $record->module = $modulename;\r
-                       // check if module id was given (usually it is)\r
-                       if ($record->cmid) {\r
-                               // update course module id, if necessary\r
-                               if (isset($new[$modulename][$record->cmid])) {\r
-                                       $record->cmid = $new[$modulename][$record->cmid];\r
-                               } else {\r
-                                       // could not update course module id\r
-                                       $ok = hotpot_update_print_warning('cmid', $record->cmid, 'log', $record->id) && $ok;\r
-                                       unset($record->id);\r
-                               }\r
-                               // update url and info\r
-                               switch ($record->action) {\r
-                                       case "add":\r
-                                       case "update":\r
-                                       case "view":\r
-                                               $record->url = "view.php?id=".$record->cmid;\r
-                                               $record->info = $moduleid;\r
-                                               break;\r
-                                       case "view all":\r
-                                               // do nothing\r
-                                               break;\r
-                                       case "report":\r
-                                               $record->url = "report.php?id=".$record->cmid;\r
-                                               $record->info = $moduleid;\r
-                                               break;\r
-                                       case "attempt":\r
-                                       case "submit":\r
-                                       case "review": \r
-                                               $id = substr(strrchr($record->url,"="),1);\r
-                                               if (isset($new->attempt[$id])) { \r
-                                                       $id = $new->attempt[$id];\r
-                                               }\r
-                                               $record->url = "review.php?id=".$record->cmid."&attempt=$id";\r
-                                               $record->info = $moduleid;\r
-                                               break;\r
-                                       default:\r
-                                               // unknown log action\r
-                                               $ok = hotpot_update_print_warning('action', $record->action, 'log', $record->id) && $ok;\r
-                                               unset($record->id);\r
-                               } // end switch\r
-                       }\r
-                       if (isset($record->id)) {\r
-                               $ok = $ok && update_record($table, $record);\r
-                       }\r
-                       $i++;\r
-                       hotpot_update_print_progress($i);\r
-               } // end foreach\r
-               // finish progress report\r
-               hotpot_update_print_ok($ok);\r
-       }\r
-       return $ok;\r
-}\r
-function hotpot_update_fields($table, $feedback=false) {\r
-       global $CFG, $db;\r
-       $ok = true;\r
-       // check the table exists\r
-       if (hotpot_db_table_exists($table)) {\r
-               switch ($table) {\r
-                       case 'hotpot' :\r
-                               // == ADD ==\r
-                               hotpot_db_update_field_type($table, '', 'location',     'INTEGER', 4, 'UNSIGNED', 'NOT NULL', 0);\r
-                               hotpot_db_update_field_type($table, '', 'navigation',   'INTEGER', 4, 'UNSIGNED', 'NOT NULL', 1);\r
-                               hotpot_db_update_field_type($table, '', 'outputformat', 'INTEGER', 4, 'UNSIGNED', 'NOT NULL', 1);\r
-                               hotpot_db_update_field_type($table, '', 'shownextquiz', 'INTEGER', 4, 'UNSIGNED', 'NOT NULL', 0);\r
-                               hotpot_db_update_field_type($table, '', 'forceplugins', 'INTEGER', 4, 'UNSIGNED', 'NOT NULL', 0);\r
-                               hotpot_db_update_field_type($table, '', 'password',     'VARCHAR', 255, '',       'NOT NULL', '');\r
-                               hotpot_db_update_field_type($table, '', 'subnet',       'VARCHAR', 255, '',       'NOT NULL', '');\r
-                               // == ALTER ==\r
-                               hotpot_db_update_field_type($table, 'summary',   'summary',   'TEXT',    '',  '', 'NOT NULL', '');\r
-                               hotpot_db_update_field_type($table, 'reference', 'reference', 'VARCHAR', 255, '', 'NOT NULL', '');\r
-                               // == REMOVE ==\r
-                               hotpot_db_remove_field($table, 'intro');\r
-                               hotpot_db_remove_field($table, 'attemptonlast');\r
-                               hotpot_db_remove_field($table, 'sumgrades');\r
-                               hotpot_db_set_table_comment($table, 'details about Hot Potatoes quizzes');\r
-                       break;\r
-                       case 'hotpot_events' :\r
-                               // == ADD ==\r
-                               hotpot_db_update_field_type($table, '', 'hotpot',     'INTEGER', 10, 'UNSIGNED', 'NOT NULL');\r
-                               hotpot_db_update_field_type($table, '', 'attempt',    'INTEGER', 6,  'UNSIGNED', 'NOT NULL');\r
-                               hotpot_db_update_field_type($table, '', 'details',    'TEXT',    '', '', '', '');\r
-                               hotpot_db_update_field_type($table, '', 'timestart',  'INTEGER', 10, 'UNSIGNED', 'NOT NULL', 0);\r
-                               hotpot_db_update_field_type($table, '', 'timefinish', 'INTEGER', 10, 'UNSIGNED', 'NOT NULL', 0);\r
-                               // == ALTER ==\r
-                               hotpot_db_update_field_type($table, 'score',     'score',      'INTEGER', 6,  'UNSIGNED', 'NULL');\r
-                               hotpot_db_update_field_type($table, 'wrong',     'penalties',  'INTEGER', 6,  'UNSIGNED', 'NULL');\r
-                               hotpot_db_update_field_type($table, 'starttime', 'starttime',  'INTEGER', 10, 'UNSIGNED', 'NULL');\r
-                               hotpot_db_update_field_type($table, 'endtime',   'endtime',    'INTEGER', 10, 'UNSIGNED', 'NULL');\r
-                               // save and switch off SQL message echo\r
-                               $debug = $db->debug;\r
-                               $db->debug = $feedback;\r
-                               // get array mapping course module ids to hotpot ids\r
-                               $hotpotmoduleid = get_field('modules', 'id', 'name', 'hotpot');\r
-                               $coursemodules = get_records('course_modules', 'module', $hotpotmoduleid, 'id', 'id, instance');\r
-                               // get all event records\r
-                               if (hotpot_db_field_exists($table, 'hotpotid')) {\r
-                                       $records = get_records($table, '', '', 'userid,hotpotid,time');\r
-                               } else {\r
-                                       $records = false; // table has already been updated\r
-                               }\r
-                               if ($records) {\r
-                                       $count = count($records);\r
-                                       hotpot_update_print("Updating $count records in $table ... ");\r
-                                       $ids = array_keys($records);\r
-                                       foreach ($ids as $i=>$id) {\r
-                                               // reference to current record\r
-                                               $record = &$records[$id];\r
-                                               // set timestart and timefinish (the times recorded by Moodle)\r
-                                               if (empty($record->timestart) && $record->time) {\r
-                                                       $record->timestart = $record->time;\r
-                                               }\r
-                                               if (empty($record->timefinish) && $record->timestart) {\r
-                                                       if ($record->starttime && $record->endtime) {\r
-                                                               $duration = ($record->endtime - $record->starttime);\r
-                                                       } else {\r
-                                                               if (($i+1)>=$count) {\r
-                                                                       $nextrecord = NULL;\r
-                                                               } else {\r
-                                                                       $nextrecord = &$records[$ids[$i+1]];\r
-                                                               }\r
-                                                               if (isset($nextrecord) && $nextrecord->userid==$record->userid && $nextrecord->hotpotid==$record->hotpotid) {\r
-                                                                       $duration = $nextrecord->time - $record->time;\r
-                                                               } else {\r
-                                                                       $duration = NULL;\r
-                                                               }\r
-                                                       }\r
-                                                       if (isset($duration)) {\r
-                                                               $record->timefinish = $record->timestart + $duration;\r
-                                                       }\r
-                                               }\r
-                                               // unset score and penalties, if quiz was abandoned\r
-                                               if (empty($record->endtime) || (empty($record->penalties) && empty($record->score))) {\r
-                                                       unset($record->score);\r
-                                                       unset($record->penalties);\r
-                                               }\r
-                                               // get last (=previous) record\r
-                                               if ($i==0) {\r
-                                                       $lastrecord = NULL;\r
-                                               } else {\r
-                                                       $lastrecord = &$records[$ids[$i-1]];\r
-                                               }\r
-                                               // increment or reset $attempt number\r
-                                               if (isset($lastrecord) && $lastrecord->userid==$record->userid && $lastrecord->hotpotid==$record->hotpotid) {\r
-                                                       $attempt++;\r
-                                               } else {\r
-                                                       $attempt = 1;\r
-                                               }\r
-                                               // set $record->$attempt, if necessary\r
-                                               if (empty($record->attempt) || $record->attempt<$attempt) {\r
-                                                       $record->attempt = $attempt;\r
-                                               } else {\r
-                                                       $attempt = $record->attempt;\r
-                                               }\r
-                                               // set hotpot id and update record\r
-                                               if (isset($record->hotpotid) && isset($record->id)) {\r
-                                                       if (isset($coursemodules[$record->hotpotid])) {\r
-                                                               $record->hotpot = $coursemodules[$record->hotpotid]->instance;\r
-                                                               hotpot_db_update_record($table, $record, true);\r
-                                                       } else {\r
-                                                               // hotpotid is invalid (shouldn't happen)\r
-                                                               $ok = hotpot_update_print_warning('hotpotid', $record->hotpotid, $table, $record->id) && $ok;\r
-                                                               delete_records($table, 'id', $record->id);\r
-                                                       }\r
-                                               } else {\r
-                                                               // empty record (shouldn't happen)\r
-                                               }\r
-                                               hotpot_update_print_progress($i);\r
-                                       }\r
-                                       // finish progress report\r
-                                       hotpot_update_print_ok($ok);\r
-                               }\r
-                               // restore SQL message echo setting\r
-                               $db->debug = $debug;\r
-                               // == REMOVE ==\r
-                               hotpot_db_remove_field($table, 'hotpotid');\r
-                               hotpot_db_remove_field($table, 'course');\r
-                               hotpot_db_remove_field($table, 'time');\r
-                               hotpot_db_remove_field($table, 'event');\r
-                               hotpot_db_set_table_comment($table, 'details about Hot Potatoes quiz attempts');\r
-                       break;\r
-                       case 'hotpotatoes' :\r
-                               // == ALTER ==\r
-                               hotpot_db_update_field_type($table, 'intro', 'summary', 'TEXT', '', '', '', 'NULL');\r
-                       break;\r
-               }\r
-       }\r
-       return $ok;\r
-}\r
-function hotpot_update_string_id_list($table, &$record, $field, &$new) {\r
-       $ok = true;\r
-       if (isset($record->$field)) {\r
-               $oldids = explode(',', $record->$field);\r
-               $newids = array();\r
-               foreach ($oldids as $id) {\r
-                       if (isset($new['string'][$id])) {\r
-                               $newids[] = $new['string'][$id];\r
-                       } else if (is_numeric($id)) {\r
-                               // string id could not be updated\r
-                               $ok = hotpot_update_print_warning("string id in $field", $id, $table, $record->id) && $ok;\r
-                       } else {\r
-                               // ignore non-numeric ids (e.g. blanks)\r
-                       }\r
-               }\r
-               if ($ok) {\r
-                       $record->$field = implode(',', $newids);\r
-               }\r
-       }\r
-       return $ok;\r
-}\r
-///////////////////////////\r
-//     print functions\r
-///////////////////////////\r
-function hotpot_update_print($msg=false, $n=300) {\r
-       // this function prints $msg and flush output buffer\r
-       if ($msg) {\r
-               if (is_string($msg)) {\r
-                       print $msg;\r
-               } else {\r
-                       print strftime("%X", time());\r
-               }\r
-       }\r
-       // fill output buffer\r
-       if ($n) {\r
-               print str_repeat(" ", $n);\r
-       }\r
-       // some browser's require newline to flush\r
-       print "\n";\r
-       // flush PHP's output buffer\r
-       flush();\r
-}\r
-function hotpot_update_print_progress($i) {\r
-       if ($i%10==0) {\r
-               $msg = '.';\r
-               hotpot_update_print($msg);\r
-       }\r
-}\r
-function hotpot_update_print_ok($ok) {\r
-       if ($ok) {\r
-               hotpot_update_print('<font color="green">'.get_string('success')."</font><br />\n");\r
-       } else {\r
-               hotpot_update_print('<font color="red">'.get_string('error')."</font><br />\n");\r
-       }\r
-}\r
-function hotpot_update_print_warning($field, $value, $table, $id) {\r
-       hotpot_update_print("<li><b>Warning:</b> invalid $field field (value=$value) in $table (id=$id)</li>\n");\r
-       return true;\r
-}\r
-///////////////////////////\r
-//     database functions\r
-///////////////////////////\r
-function hotpot_db_index_exists($table, $index, $feedback=false) {\r
-       global $CFG, $db;\r
-       $exists = false;\r
-       // save and switch off SQL message echo\r
-       $debug = $db->debug;\r
-       $db->debug = $feedback;\r
-       switch (strtolower($CFG->dbtype)) {\r
-               case 'mysql' : \r
-                       $rs = $db->Execute("SHOW INDEX FROM `$table`");\r
-                       if ($rs && $rs->RecordCount()>0) {\r
-                               $records = $rs->GetArray();\r
-                               foreach ($records as $record) {\r
-                                       if (isset($record['Key_name']) && $record['Key_name']==$index) {\r
-                                               $exists = true;\r
-                                               break;\r
-                                       }\r
-                               }\r
-                       }\r
-               break;\r
-               case 'postgres7' :\r
-                       $rs = $db->Execute("SELECT relname FROM pg_class WHERE relname = '$index' AND relkind='i'");\r
-                       if ($rs && $rs->RecordCount()>0) {\r
-                               $exists = true;\r
-                       }\r
-               break;\r
-       }\r
-       // restore SQL message echo\r
-       $db->debug = $debug;\r
-       return $exists;\r
-}\r
-function hotpot_db_delete_index($table, $index, $feedback=false) {\r
-       global $CFG, $db;\r
-       $ok = true;\r
-       // check index exists\r
-       if (hotpot_db_index_exists($table, $index)) {\r
-               switch (strtolower($CFG->dbtype)) {\r
-                       case 'mysql' : \r
-                               $sql = "ALTER TABLE `$table` DROP INDEX `$index`";\r
-                       break;\r
-                       case 'postgres7' :\r
-                               $sql = "DROP INDEX $index";\r
-                       break;\r
-                       default: // unknown database type\r
-                               $sql = '';\r
-                       break;\r
-               }\r
-               if ($sql) {\r
-                       // save and switch off SQL message echo\r
-                       $debug = $db->debug;\r
-                       $db->debug = $feedback;\r
-                       $ok = $db->Execute($sql) ? true : false;\r
-                       // restore SQL message echo\r
-                       $db->debug = $debug;\r
-               } else { // unknown database type\r
-                       $ok = false;\r
-               }\r
-       }\r
-       return $ok;\r
-}\r
-function hotpot_db_add_index($table, $field, $length='') {\r
-       global $CFG, $db;\r
-\r
-       if (strtolower($CFG->dbtype)=='postgres7') {\r
-               $index = "{$CFG->prefix}{$table}_{$field}_idx";\r
-       } else {\r
-               // mysql (and others)\r
-               $index = "{$table}_{$field}_idx";\r
-       }\r
-       $table = "{$CFG->prefix}$table";\r
-\r
-       // delete $index if it already exists\r
-       $ok = hotpot_db_delete_index($table, $index);\r
-\r
-       switch (strtolower($CFG->dbtype)) {\r
-               case 'mysql' :\r
-                       $length = empty($length) ? '' : " ($length)";\r
-                       $ok = $ok && $db->Execute("ALTER TABLE `$table` ADD INDEX `$index` (`$field`$length)");\r
-               break;\r
-               case 'postgres7' :\r
-                       if ($length) {\r
-                               $field = "SUBSTR($field,$length)";\r
-                       }\r
-                       $ok = $ok && $db->Execute("CREATE INDEX $index ON $table ($field)");\r
-               break;\r
-               default: // unknown database type\r
-                       $ok = false;\r
-               break;\r
-       }\r
-       return $ok;\r
-}\r
-function hotpot_db_table_exists($table, $feedback=false) {\r
-       return hotpot_db_object_exists($table, '', $feedback);\r
-}\r
-function hotpot_db_field_exists($table, $field, $feedback=false) {\r
-       return \r
-               hotpot_db_object_exists($table, '', $feedback) &&\r
-               hotpot_db_object_exists($table, $field, $feedback)\r
-       ;\r
-}\r
-function hotpot_db_object_exists($table, $field='', $feedback=false) {\r
-       global $CFG,$db;\r
-       // expand table name\r
-       $table = "{$CFG->prefix}$table";\r
-       // set $sql\r
-       switch (strtolower($CFG->dbtype)) {\r
-               case 'mysql' : \r
-                       if (empty($field)) {\r
-                               $sql = "SHOW TABLES LIKE '$table'";\r
-                       } else {\r
-                               $sql = "SHOW COLUMNS FROM `$table` LIKE '$field'";\r
-                       }\r
-               break;\r
-               case 'postgres7' :\r
-                       if (empty($field)) {\r
-                               $sql = "SELECT relname FROM pg_class WHERE relname = '$table' AND relkind='r'";\r
-                       } else {\r
-                               $sql = "\r
-                                       SELECT attname FROM pg_attribute WHERE attname = '$field' \r
-                                       AND attrelid = (SELECT oid FROM pg_class WHERE relname = '$table')\r
-                               ";\r
-                       }\r
-               break;\r
-       }\r
-       // save and switch off SQL message echo\r
-       $debug = $db->debug;\r
-       $db->debug = $feedback;\r
-       // execute sql\r
-       $rs = $db->Execute($sql);\r
-       // restore SQL message echo setting\r
-       $db->debug = $debug;\r
-       // report error if required\r
-       if (empty($rs) && isset($CFG->debug) and $CFG->debug > 7) {\r
-               notify($db->ErrorMsg()."<br /><br />$sql");\r
-       }\r
-       return ($rs && $rs->RecordCount()>0);\r
-}\r
-function hotpot_db_remove_table($table, $feedback=true) {\r
-       global $CFG;\r
-       if (hotpot_db_table_exists($table)) {\r
-               $ok = execute_sql("DROP TABLE {$CFG->prefix}$table", $feedback);\r
-       } else {\r
-               $ok = true;\r
-       }\r
-       return $ok;\r
-}\r
-function hotpot_db_rename_table($oldtable, $table, $feedback=true) {\r
-       global $CFG;\r
-       if (hotpot_db_table_exists($oldtable)) {\r
-               $ok = execute_sql("ALTER TABLE {$CFG->prefix}$oldtable RENAME TO {$CFG->prefix}$table", $feedback);\r
-       } else {\r
-               $ok = true;\r
-       }\r
-       return $ok;\r
-}\r
-function hotpot_db_append_table($oldtable, $table, $feedback=true) {\r
-       global $CFG, $db;\r
-       if (hotpot_db_table_exists($oldtable)) {\r
-               if (hotpot_db_table_exists($table)) {\r
-                       // expand table names\r
-                       $table = "{$CFG->prefix}$table";\r
-                       $oldtable = "{$CFG->prefix}$oldtable";\r
-                       // get field info\r
-                       $fields = $db->MetaColumns($table);\r
-                       $oldfields = $db->MetaColumns($oldtable);\r
-                       $fieldnames = array();\r
-                       if (!empty($fields) || !empty($oldfields)) {\r
-                               foreach ($fields as $field) {\r
-                                       if ($field->name!='id' && isset($oldfields[strtoupper($field->name)])) {\r
-                                               $fieldnames[] = $field->name;\r
-                                       }\r
-                               }\r
-                       }\r
-                       $fieldnames = implode(',', $fieldnames);\r
-                       if (empty($fieldnames)) {\r
-                               $ok = false;\r
-                       } else {\r
-                               switch (strtolower($CFG->dbtype)) {\r
-                                       case 'mysql':\r
-                                               $ok = execute_sql("INSERT INTO `$table` ($fieldnames) SELECT $fieldnames FROM `$oldtable` WHERE 1");\r
-                                               break;\r
-                                       case 'postgres7':\r
-                                               $ok = execute_sql("INSERT INTO $table ($fieldnames) SELECT $fieldnames FROM $oldtable");\r
-                                               break;\r
-                                       default:\r
-                                               $ok = false;\r
-                                               break;\r
-                               }\r
-                       }\r
-               } else { // $table does not exist\r
-                       $ok = hotpot_db_rename_table($oldtable, $table, $feedback);\r
-               }\r
-       } else { // $oldtable does not exist\r
-               $ok = hotpot_db_table_exists($table, $feedback);\r
-       }\r
-       return $ok;\r
-}\r
-function hotpot_db_set_table_comment($table, $comment, $feedback=true) {\r
-       global $CFG;\r
-       $ok = true;\r
-       switch (strtolower($CFG->dbtype)) {\r
-               case 'mysql' :\r
-                       $ok = execute_sql("ALTER TABLE {$CFG->prefix}$table COMMENT='$comment'");\r
-                       break;\r
-               case 'postgres7' :\r
-                       $ok = execute_sql("COMMENT ON TABLE {$CFG->prefix}$table IS '$comment'");\r
-                       break;\r
-       }\r
-       return $ok;\r
-}\r
-function hotpot_db_remove_field($table, $field, $feedback=true) {\r
-       global $CFG;\r
-       if (hotpot_db_field_exists($table, $field)) {\r
-               $ok = execute_sql("ALTER TABLE {$CFG->prefix}$table DROP COLUMN $field", $feedback);\r
-       } else {\r
-               $ok = true;\r
-       }\r
-       return $ok;\r
-}\r
-function hotpot_db_update_field_type($table, $oldfield, $field, $type, $size, $unsigned, $notnull, $default=NULL, $after=NULL) {\r
-       $ok = true;\r
-       global $CFG,$db;\r
-       // check validity of arguments, and adjust if necessary\r
-       if ($oldfield && !hotpot_db_field_exists($table, $oldfield)) {\r
-               $oldfield = '';\r
-       }\r
-       if (empty($oldfield) && hotpot_db_field_exists($table, $field)) {\r
-               $oldfield = $field;\r
-       } \r
-       if (is_string($unsigned)) {\r
-               $unsigned = (strtoupper($unsigned)=='UNSIGNED');\r
-       }\r
-       if (is_string($notnull)) {\r
-               $notnull = (strtoupper($notnull)=='NOT NULL');\r
-       }\r
-       if (isset($default)) {\r
-               if (!is_numeric($default) && strtoupper($default)!='NULL' && !preg_match("|^'.*'$|", $default)) {\r
-                       $default = "'$default'";\r
-               }\r
-       }\r
-       // set full table name\r
-       $table = "{$CFG->prefix}$table";\r
-       // update the field in the database\r
-       switch (strtolower($CFG->dbtype)) {\r
-               case 'mysql':\r
-                       // optimize integer types\r
-                       switch (strtoupper($type)) {\r
-                               case 'TEXT':\r
-                                       $size = '';\r
-                                       $unsigned = false;\r
-                               break;\r
-                               case 'INTEGER' :\r
-                                       if (!is_numeric($size)) {\r
-                                               $size = '';\r
-                                       } else if ($size <= 4) {\r
-                                               $type = "TINYINT";   // 1 byte\r
-                                       } else if ($size <= 6) {\r
-                                               $type = "SMALLINT";  // 2 bytes\r
-                                       } else if ($size <= 8) {\r
-                                               $type = "MEDIUMINT"; // 3 bytes\r
-                                       } else if ($size <= 10) {\r
-                                               $type = "INTEGER";   // 4 bytes (=INT)\r
-                                       } else if ($size > 10) {\r
-                                               $type = "BIGINT";    // 8 bytes\r
-                                       }\r
-                               break;\r
-                               case 'VARCHAR':\r
-                                       $unsigned = false;\r
-                               break;\r
-                       }\r
-                       // set action\r
-                       if (empty($oldfield)) {\r
-                               $action = "ADD";\r
-                       } else {\r
-                               $action = "CHANGE `$oldfield`";\r
-                       }\r
-                       // set fieldtype\r
-                       $fieldtype = $type;\r
-                       if ($size) {\r
-                               $fieldtype .= "($size)";\r
-                       }\r
-                       if ($unsigned) {\r
-                               $fieldtype .= ' UNSIGNED';\r
-                       }\r
-                       if ($notnull) {\r
-                               $fieldtype .= ' NOT NULL';\r
-                       }\r
-                       if (isset($default)) {\r
-                               $fieldtype .= " DEFAULT $default";\r
-                       }\r
-                       if (!empty($after)) {\r
-                               $fieldtype .= " AFTER `$after`";\r
-                       }\r
-                       $ok = $ok && execute_sql("ALTER TABLE `$table` $action `$field` $fieldtype");\r
-               break;\r
-               case 'postgres7':\r
-                       // get db version\r
-                       $dbinfo = $db->ServerInfo();\r
-                       $dbversion = substr($dbinfo['version'],0,3);\r
-                       // prevent conflicts with reserved words\r
-                       $tmpfield = "\"temporary_{$field}_".time()."\"";\r
-                       $oldfield = "\"$oldfield\"";\r
-                       $field    = "\"$field\"";\r
-                       switch (strtoupper($type)) {\r
-                               case "INTEGER":\r
-                                       if (!is_numeric($size)) {\r
-                                               $fieldtype = "INTEGER";\r
-                                       } else if ($size <= 4) {\r
-                                               $fieldtype = "INT2"; // 2 bytes\r
-                                       } else if ($size <= 10) {\r
-                                               $fieldtype = "INT4"; // 4 bytes (=INTEGER)\r
-                                       } else if ($size > 10) {\r
-                                               $fieldtype = "INT8"; // 8 bytes\r
-                                       }\r
-                               break;\r
-                               case "VARCHAR":\r
-                                       $fieldtype = "VARCHAR($size)";\r
-                               break;\r
-                               default:\r
-                                       $fieldtype = $type;\r
-                       }\r
-                       // start transaction\r
-                       execute_sql("BEGIN");\r
-                       // create temporary field\r
-                       execute_sql("ALTER TABLE $table ADD COLUMN $tmpfield $fieldtype");\r
-                       // set default\r
-                       if (isset($default)) {\r
-                               execute_sql("UPDATE $table SET $tmpfield = $default");\r
-                               execute_sql("ALTER TABLE $table ALTER COLUMN $tmpfield SET DEFAULT $default");\r
-                       } else {\r
-                               execute_sql("ALTER TABLE $table ALTER COLUMN $tmpfield DROP DEFAULT");\r
-                       }\r
-                       // set not null\r
-                       if ($dbversion >= "7.3") {\r
-                               $notnull = ($notnull ? "SET NOT NULL" : "DROP NOT NULL");\r
-                               execute_sql("ALTER TABLE $table ALTER COLUMN $tmpfield $notnull");\r
-                       } else {\r
-                               execute_sql("\r
-                                       UPDATE pg_attribute SET attnotnull=".($notnull ? 'TRUE' : 'FALSE')." \r
-                                       WHERE attname = $tmpfield\r
-                                       AND attrelid = (SELECT oid FROM pg_class WHERE relname = '$table')\r
-                               ");\r
-                       }\r
-                       // transfer $oldfield values, if necessary\r
-                       if ( $oldfield != '""' ) {\r
-                               execute_sql("UPDATE $table SET $tmpfield = CAST ($oldfield AS $fieldtype)");\r
-                               execute_sql("ALTER TABLE $table DROP COLUMN $oldfield");\r
-                       }\r
-                       // rename $tmpfield to $field\r
-                       execute_sql("ALTER TABLE $table RENAME COLUMN $tmpfield TO $field");\r
-                       // do the transaction\r
-                       execute_sql("COMMIT");\r
-                       // reclaim disk space (must be done outside transaction)\r
-                       if ($oldfield != '""' && $dbversion >= "7.3") {\r
-                               execute_sql("UPDATE $table SET $field = $field");\r
-                               execute_sql("VACUUM FULL $table");\r
-                       }\r
-               break;\r
-       } // end switch $CGF->dbtype\r
-       return $ok;\r
-}\r
-function hotpot_db_update_record($table, $record, $forcenull=false) {\r
-       global $CFG, $db;\r
-       $ok = true;\r
-       // set full table name\r
-       $table = "{$CFG->prefix}$table";\r
-       // get field names\r
-       $fields = $db->MetaColumns($table);\r
-       if (empty($fields)) {\r
-               $ok = false;\r
-       } else {\r
-               // get values\r
-               $values = array();\r
-               foreach ($fields as $field) {\r
-                       $fieldname = $field->name;\r
-                       if ($fieldname!='id' && ($forcenull || isset($record->$fieldname))) {\r
-                               $value = isset($record->$fieldname) ? "'".$record->$fieldname."'" : 'NULL';\r
-                               $values[] = "$fieldname = $value";\r
-                       }\r
-               }\r
-               $values = implode(',', $values);\r
-               // update values (if there are any)\r
-               if ($values) {\r
-                       $sql = "UPDATE $table SET $values WHERE id='$record->id'";\r
-                       $rs = $db->Execute($sql);\r
-                       if (empty($rs)) {\r
-                               $ok = false;\r
-                               if (isset($CFG->debug) and $CFG->debug > 7) {\r
-                                       notify($db->ErrorMsg()."<br /><br />$sql");\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-       return $ok;\r
-}\r
-function hotpot_rm($target, $output=true) {\r
-       $ok = true;\r
-       if (!empty($target)) {\r
-               if (is_file($target)) {\r
-                       if ($output) {\r
-                               print "removing file: $target ... ";\r
-                       }\r
-                       $ok = @unlink($target);\r
-               } else if (is_dir($target)) {\r
-                       $dir = dir($target);\r
-                       while(false !== ($entry = $dir->read())) {\r
-                               if ($entry!='.' && $entry!='..') {\r
-                                       $ok = $ok && hotpot_rm($target.DIRECTORY_SEPARATOR.$entry, $output);\r
-                               }\r
-                       }\r
-                       $dir->close();\r
-                       if ($output) {\r
-                               print "removing folder: $target ... ";\r
-                       }\r
-                       $ok = $ok && @rmdir($target);\r
-               } else { // not a file or directory (probably doesn't exist)\r
-                       $output = false;\r
-               }\r
-               if ($output) {\r
-                       if ($ok) {\r
-                               print '<font color="green">OK</font><br />';\r
-                       } else {\r
-                               print '<font color="red">Failed</font><br />';\r
-                       }\r
-               }\r
-       }\r
-       return $ok;\r
-}\r
-function hotpot_flush($n=0, $time=false) {\r
-       if ($time) {\r
-               $t = strftime("%X",time());\r
-       } else {\r
-               $t = "";\r
-       }\r
-       echo str_repeat(" ", $n) . $t . "\n";\r
-       flush();\r
-}\r
-?>\r
+<?PHP
+function hotpot_update_to_v2_1_18() {
+       $ok = true;
+
+       // remove all orphan records (there shouldn't be any, but if there are they can mess up the utfdbmigrate)
+
+       $ok = $ok && hotpot_remove_orphans('hotpot_attempts', 'hotpot', 'hotpot');
+       $ok = $ok && hotpot_remove_orphans('hotpot_questions', 'hotpot', 'hotpot');
+       $ok = $ok && hotpot_remove_orphans('hotpot_responses', 'attempt', 'hotpot_attempts');
+       $ok = $ok && hotpot_remove_orphans('hotpot_responses', 'question', 'hotpot_questions');
+       $ok = $ok && hotpot_remove_orphans('hotpot_details', 'attempt', 'hotpot_attempts');
+
+       return $ok;
+}
+function hotpot_remove_orphans($secondarytable, $secondarykeyfield, $primarytable, $primarykeyfield='id') {
+       global $CFG,$db;
+       $ok = true;
+
+       // save and switch off SQL message echo
+       $debug = $db->debug;
+       $db->debug = false;
+
+       $records = get_records_sql("
+               SELECT 
+                       t2.$secondarykeyfield, t2.$secondarykeyfield
+               FROM 
+                       {$CFG->prefix}$secondarytable AS t2 LEFT JOIN {$CFG->prefix}$primarytable AS t1 
+                       ON (t2.$secondarykeyfield = t1.$primarykeyfield)
+               WHERE 
+                       t1.$primarykeyfield IS NULL
+               ORDER BY 
+                       t2.$secondarykeyfield
+       ");
+
+       // restore SQL message echo setting
+       $db->debug = $debug;
+
+       if ($records) {
+               $ids = implode(',', array_keys($records));
+               print 'removing '.count($ids).' orphan record(s) from {$CFG->prefix}$secondarytable (key=$secondarykeyfield) ...<br>';
+               $ok = $ok && execute_sql("DELETE FROM {$CFG->prefix}$secondarytable WHERE $secondarykeyfield IN ($ids)");
+       }
+
+       return $ok;
+}
+function hotpot_update_to_v2_1_17() {
+       global $CFG;
+       $ok = true;
+
+       // convert and disable null values on certain numeric fields
+
+       $ok = $ok && hotpot_denull_int_field('hotpot_attempts', 'starttime', '10');
+       $ok = $ok && hotpot_denull_int_field('hotpot_attempts', 'endtime', '10');
+       $ok = $ok && hotpot_denull_int_field('hotpot_attempts', 'score', '6');
+       $ok = $ok && hotpot_denull_int_field('hotpot_attempts', 'penalties',  '6');
+       $ok = $ok && hotpot_denull_int_field('hotpot_attempts', 'timestart', '10');
+       $ok = $ok && hotpot_denull_int_field('hotpot_attempts', 'timefinish', '10');
+       $ok = $ok && hotpot_denull_int_field('hotpot_attempts', 'clickreportid', '10');
+
+       $ok = $ok && hotpot_denull_int_field('hotpot_questions', 'type', '4');
+       $ok = $ok && hotpot_denull_int_field('hotpot_questions', 'text', '10');
+
+       $ok = $ok && hotpot_denull_int_field('hotpot_responses', 'weighting', '6');
+       $ok = $ok && hotpot_denull_int_field('hotpot_responses', 'score', '6');
+       $ok = $ok && hotpot_denull_int_field('hotpot_responses', 'hints', '6');
+       $ok = $ok && hotpot_denull_int_field('hotpot_responses', 'clues', '6');
+       $ok = $ok && hotpot_denull_int_field('hotpot_responses', 'checks', '6');
+       return $ok;
+}
+function hotpot_denull_int_field($table, $field, $size) {
+       global $CFG;
+       $ok = true;
+
+       $ok = $ok && execute_sql("UPDATE {$CFG->prefix}$table SET $field=0 WHERE $field IS NULL");
+       $ok = $ok && hotpot_db_update_field_type($table, $field, $field, 'INTEGER', $size, 'UNSIGNED', 'NOT NULL', 0);
+
+       return $ok;
+}
+function hotpot_update_to_v2_1_16() {
+       global $CFG;
+       $ok = true;
+
+       // settings for the "hotpot_questions_name_idx" index
+       $length = 20;
+       $field = 'name';
+       $table = 'hotpot_questions';
+       $index = "{$table}_{$field}_idx";
+
+       // remove the index
+       hotpot_db_delete_index("{$CFG->prefix}$table", $index);
+       hotpot_db_delete_index("{$CFG->prefix}$table", "{$CFG->prefix}$index");
+
+       // make sure type of 'name' is a text field (not varchar 255)
+       $ok = $ok && hotpot_db_update_field_type($table, $field, $field, 'TEXT',   '',  '', 'NOT NULL', '');
+
+       // restore the index
+       $ok = $ok && hotpot_db_add_index($table, $field, $length);
+
+       if (strtolower($CFG->dbtype)=='mysql') {
+
+               // set default values on certain VARCHAR(255) fields
+               $varchar_fields = array(
+                       'hotpot.studentfeedbackurl',
+                       'hotpot_responses.correct',
+                       'hotpot_responses.wrong',
+                       'hotpot_responses.ignored'
+               );
+               foreach ($varchar_fields as $varchar_field) {
+                       list ($table, $field) = explode('.', $varchar_field);
+                       execute_sql("UPDATE {$CFG->prefix}$table SET $field='' WHERE $field IS NULL");
+                       $ok = $ok && hotpot_db_update_field_type($table, $field, $field, 'VARCHAR', 255, '', 'NOT NULL', '');
+               }
+
+               // remove $CFG->prefix from all index names
+               $ok = $ok && hotpot_index_remove_prefix('hotpot_attempts', 'hotpot');
+               $ok = $ok && hotpot_index_remove_prefix('hotpot_attempts', 'userid');
+               $ok = $ok && hotpot_index_remove_prefix('hotpot_details', 'attempt');
+               $ok = $ok && hotpot_index_remove_prefix('hotpot_questions', 'hotpot');
+               //$ok = $ok && hotpot_index_remove_prefix('hotpot_questions', 'name', 20);
+               $ok = $ok && hotpot_index_remove_prefix('hotpot_responses', 'attempt');
+               $ok = $ok && hotpot_index_remove_prefix('hotpot_responses', 'question');
+               $ok = $ok && hotpot_index_remove_prefix('hotpot_strings', 'string', 20);
+       }
+       return $ok;
+}
+function hotpot_index_remove_prefix($table, $field, $length=0) {
+       global $CFG;
+       $index = "{$table}_{$field}_idx";
+       hotpot_db_delete_index("{$CFG->prefix}$table", "{$CFG->prefix}$index");
+       hotpot_db_delete_index("{$CFG->prefix}$table", $index);
+       return hotpot_db_add_index($table, $field, $length);
+}
+
+function hotpot_update_to_v2_1_8() {
+       global $CFG;
+       $ok = true;
+       if (strtolower($CFG->dbtype)=='postgres7') {
+               // add, delete and rename certain fields and indexes
+               // that were not correctly setup by postgres7.sql
+
+               // hotpot
+               $table = 'hotpot';
+               if (hotpot_db_field_exists($table, 'microreporting')) {
+                       $ok = $ok && hotpot_db_update_field_type($table, 'microreporting', 'clickreporting', 'INTEGER', 4, 'UNSIGNED', 'NOT NULL', '0');
+               }
+       }
+       return $ok;
+}
+function hotpot_update_to_v2_1_6() {
+       global $CFG;
+       $ok = true;
+
+       if (strtolower($CFG->dbtype)=='postgres7') {
+               // add, delete and rename certain fields and indexes
+               // that were not correctly setup by postgres7.sql
+
+               // hotpot
+               $table = 'hotpot';
+               if (hotpot_db_field_exists($table, 'studentfeedback') && !hotpot_db_field_exists($table, 'studentfeedbackurl')) {
+                       $ok = $ok && hotpot_db_update_field_type($table, 'studentfeedback', 'studentfeedbackurl', 'VARCHAR', 255, '', 'NULL');
+                       $ok = $ok && hotpot_db_update_field_type($table, '', 'studentfeedback', 'INTEGER', 4, 'UNSIGNED', 'NOT NULL', '0');
+               }
+
+               // hotpot_attempts
+               $table = 'hotpot_attempts';
+               $ok = $ok && hotpot_db_remove_field($table, 'groupid');
+               if (hotpot_db_field_exists($table, 'microreportid') && !hotpot_db_field_exists($table, 'clickreportid')) {
+                       $ok = $ok && hotpot_db_update_field_type($table, 'microreportid', 'clickreportid', 'INTEGER', 10, 'UNSIGNED', 'NULL');
+               }
+
+               // hotpot_questions (add index on question "name")
+               $table = 'hotpot_questions';
+               $field = 'name';
+               $index = "{$table}_{$field}_idx";
+               if (!hotpot_db_index_exists("{$CFG->prefix}$table", "{$CFG->prefix}$index")) {
+                       hotpot_db_add_index($table, $field, '20');
+               }
+
+               // hotpot_strings (add index on "string")
+               $table = "hotpot_strings";
+               $field = 'string';
+               $index = "{$table}_{$field}_idx";
+               if (!hotpot_db_index_exists("{$CFG->prefix}$table", "{$CFG->prefix}$index")) {
+                       hotpot_db_add_index($table, $field, '20');
+               }
+       }
+
+       return $ok;
+}
+function hotpot_update_to_v2_1_2() {
+       global $CFG, $db;
+       $ok = true;
+
+       // save and switch off SQL message echo
+       $debug = $db->debug;
+       $db->debug = false;
+
+       // extract info about attempts by each user on each hotpot (cases where 
+       // the user has only one attempt, or no "in progess" attempt are ignored)
+       $rs = $db->Execute("
+               SELECT userid, hotpot, COUNT(*), MIN(status)
+               FROM {$CFG->prefix}hotpot_attempts
+               GROUP BY userid, hotpot
+               HAVING COUNT(*)>1 AND MIN(status)=1
+       ");
+       if ($rs && $rs->RecordCount()) {
+               $records = $rs->GetArray();
+
+               // start message to browser
+               print "adjusting status of ".count($records)." &quot;in progress&quot; attempts ... ";
+
+               // loop through records
+               foreach ($records as $record) {
+
+                       // get all attempts by this user at this hotpot
+                       $attempts = get_records_sql("
+                               SELECT id, userid, hotpot, score, timestart, timefinish, status 
+                               FROM {$CFG->prefix}hotpot_attempts 
+                               WHERE userid = ".$record['userid']." AND hotpot=".$record['hotpot']."
+                               ORDER BY timestart DESC, id DESC
+                       ");
+
+                       unset($previous_timestart);
+
+                       foreach ($attempts as $attempt) {
+                               // if this attempt has a status of "in progress" and is not 
+                               // the most recent one in the group, set the status to "abandoned"
+                               if ($attempt->status==1 && isset($previous_timestart)) {
+                                       $values = 'status=3';
+                                       if (empty($attempt->score)) {
+                                               $values .= ',score=0';
+                                       }
+                                       if (empty($attempt->timefinish)) {
+                                               $values .= ",timefinish=$previous_timestart";
+                                       }
+                                       execute_sql("UPDATE {$CFG->prefix}hotpot_attempts SET $values WHERE id=$attempt->id", false);
+                                       print ".";
+                                       hotpot_flush(300);
+                               }
+                               $previous_timestart = $attempt->timestart;
+                       } // end foreach $attempts
+               } // end foreach $records
+
+               // finish message to browser
+               print $ok ? get_string('success') : 'failed';
+               print "<br />\n";
+       }
+
+       // restore SQL message echo setting
+       $db->debug = $debug;
+
+       return $ok;
+}
+function hotpot_update_to_v2_1() {
+       global $CFG, $db;
+       $ok = true;
+       // hotpot_questions: reduce size of "type" field to "4"
+       $ok = $ok && hotpot_db_update_field_type('hotpot_questions', 'type', 'type', 'INTEGER', 4,  'UNSIGNED', 'NULL');
+       // hotpot_questions: change type of "name" field to "text"
+       $ok = $ok && hotpot_db_update_field_type('hotpot_questions', 'name', 'name', 'TEXT',   '',  '', 'NOT NULL', '');
+       // hotpot_questions: nullify empty and non-numeric (shouldn't be any) values in "text" field
+       switch (strtolower($CFG->dbtype)) {
+               case 'mysql' : 
+                       $NOT_REGEXP = 'NOT REGEXP';
+               break;
+               case 'postgres7' :
+                       $NOT_REGEXP = '!~';
+               break;
+               default:
+                       $NOT_REGEXP = '';
+               break;
+       }
+       if ($NOT_REGEXP) {
+               $ok = $ok && execute_sql("UPDATE {$CFG->prefix}hotpot_questions SET text=NULL WHERE text $NOT_REGEXP '^[0-9]+$'");
+       }
+       // hotpot_questions: change type of "text" field to "INT(10)"
+       $ok = $ok && hotpot_db_update_field_type('hotpot_questions', 'text', 'text', 'INTEGER', 10, 'UNSIGNED', 'NULL');
+       // hotpot_attempts
+       // hotpot_attempts: move "details" to separate table
+       $table = 'hotpot_details';
+       if (hotpot_db_table_exists($table)) {
+               // do nothing
+       } else {
+               $ok = $ok && hotpot_create_table($table);
+               switch (strtolower($CFG->dbtype)) {
+                       case 'mysql' : 
+                       case 'postgres7' :
+                               $sql = "
+                                       INSERT INTO {$CFG->prefix}$table (attempt, details) 
+                                       SELECT a.id AS attempt, a.details AS details
+                                               FROM {$CFG->prefix}hotpot_attempts AS a
+                                               WHERE 
+                                                       a.details IS NOT NULL AND a.details <> ''
+                                                       AND a.details LIKE '<?xml%' AND a.details LIKE '%</hpjsresult>'
+                               ";
+                       break;
+                       default:
+                               $sql = '';
+                       break;
+               }
+               if ($sql) {
+                       $ok = $ok && execute_sql($sql);
+               }
+       }
+       // hotpot_attempts: remove the "details" field
+       $ok = $ok && hotpot_db_remove_field('hotpot_attempts', 'details');
+       // hotpot_attempts: create and set status field (1=in-progress, 2=timed-out, 3=abandoned, 4=completed)
+       $ok = $ok && hotpot_db_update_field_type('hotpot_attempts', '', 'status', 'INTEGER', 4, 'UNSIGNED', 'NOT NULL', 1);
+       $ok = $ok && execute_sql("UPDATE {$CFG->prefix}hotpot_attempts SET status=1 WHERE timefinish=0 AND SCORE IS NULL");
+       $ok = $ok && execute_sql("UPDATE {$CFG->prefix}hotpot_attempts SET status=3 WHERE timefinish>0 AND SCORE IS NULL");
+       $ok = $ok && execute_sql("UPDATE {$CFG->prefix}hotpot_attempts SET status=4 WHERE timefinish>0 AND SCORE IS NOT NULL");
+       // hotpot_attempts: create and set clickreport fields
+       $ok = $ok && hotpot_db_update_field_type('hotpot', '', 'clickreporting', 'INTEGER', 4, 'UNSIGNED', 'NOT NULL', 0);
+       $ok = $ok && hotpot_db_update_field_type('hotpot_attempts', '', 'clickreportid', 'INTEGER', 10, 'UNSIGNED', 'NULL');
+       $ok = $ok && execute_sql("UPDATE {$CFG->prefix}hotpot_attempts SET clickreportid=id WHERE clickreportid IS NULL");
+       // hotpot_attempts: create and set studentfeedback field (0=none, 1=formmail, 2=moodleforum, 3=moodlemessaging)
+       $ok = $ok && hotpot_db_update_field_type('hotpot', '', 'studentfeedback', 'INTEGER', 4, 'UNSIGNED', 'NOT NULL', '0');
+       $ok = $ok && hotpot_db_update_field_type('hotpot', '', 'studentfeedbackurl', 'VARCHAR', 255, '', 'NULL');
+       // add indexes
+       $ok = $ok && hotpot_db_add_index('hotpot_attempts', 'hotpot');
+       $ok = $ok && hotpot_db_add_index('hotpot_attempts', 'userid');
+       $ok = $ok && hotpot_db_add_index('hotpot_details', 'attempt');
+       $ok = $ok && hotpot_db_add_index('hotpot_questions', 'name', 20);
+       $ok = $ok && hotpot_db_add_index('hotpot_questions', 'hotpot');
+       $ok = $ok && hotpot_db_add_index('hotpot_responses', 'attempt');
+       $ok = $ok && hotpot_db_add_index('hotpot_responses', 'question');
+       $ok = $ok && hotpot_db_add_index('hotpot_strings', 'string', 20);
+       // hotpot_string: correct double-encoded HTML entities
+       $ok = $ok && execute_sql("
+               UPDATE {$CFG->prefix}hotpot_strings 
+               SET string = REPLACE(string, '&amp;','&') 
+               WHERE string LIKE '%&amp;#%' 
+               AND (string LIKE '<' OR string LIKE '>')
+       ");
+       // hotpot_question: remove questions which refer to deleted hotpots
+       if ($ok) {
+               // try and get all hotpot records
+               if ($records = get_records('hotpot')) {
+                       $ids = implode(',', array_keys($records));
+                       $sql = "DELETE FROM {$CFG->prefix}hotpot_questions WHERE hotpot NOT IN ($ids)";
+               } else {
+                       // remove all question records (because there are no valid hotpot ids)
+                       $sql = "TRUNCATE {$CFG->prefix}hotpot_questions";
+               }
+               print "Removing unused question records ...";
+               execute_sql($sql);
+       }
+       if ($ok) {
+               // remove old 'v6' templates folder (replaced by 'template' folder)
+               $ds = DIRECTORY_SEPARATOR;
+               $dir = "mod{$ds}hotpot{$ds}v6";
+               print "removing old templates ($dir) ... ";
+               if (hotpot_rm("$CFG->dirroot{$ds}$dir", false)) {
+                       print get_string('success');
+               } else {
+                       print "failed<br>Please remove '$CFG->dirroot{$ds}$dir' manually";
+               }
+               print "<br />\n";
+       }
+       return $ok;
+}
+function hotpot_update_to_v2_from_v1() {
+       global $CFG;
+       $ok = true;
+       // remove, alter and add fields in database
+       $table = 'hotpot';
+       if (hotpot_db_table_exists($table)) {
+               $ok = $ok && hotpot_update_fields($table);
+       } else {
+               $ok = $ok && hotpot_create_table($table);
+       }
+       $table = 'hotpot_attempts';
+       $oldtable = 'hotpot_events';
+       if (hotpot_db_table_exists($oldtable)) {
+               $ok = $ok && hotpot_update_fields($oldtable);
+               $ok = $ok && hotpot_db_append_table($oldtable, $table);
+       } else {
+               $ok = $ok && hotpot_create_table($table);
+       }
+       // create new tables (from mysql.sql)
+       $ok = $ok && hotpot_create_table('hotpot_questions');
+       $ok = $ok && hotpot_create_table('hotpot_responses');
+       $ok = $ok && hotpot_create_table('hotpot_strings');
+       // remove redundant scripts
+       $files = array('coursefiles.php', 'details.php', 'dummy.html', 'hotpot.php', 'hotpot2db.php');
+       foreach ($files as $file) {
+               $filepath = "$CFG->dirroot/mod/hotpot/$file";
+               if (file_exists($filepath)) {
+                       @unlink($filepath); // don't worry about errors
+               }
+       }
+       return $ok;
+}
+function hotpot_update_to_v2_from_hotpotatoes() {
+       global $CFG;
+       $ok = true; // hope for the best!
+       // check we have the minimum required hotpot module
+       $minimum = 2005031400; 
+       $module = get_record("modules", "name", "hotpot");
+       if (empty($module) || $module->version<$minimum) {
+               if ($module) {
+                       print ("<p>The update to the HotPotatoes module requires at least version $minimum of the HotPot module.</p>");
+                       print ("<p>The current version of the HotPot module on this site is $module->version.</p>");
+               }
+               print ("<p>Please install the latest version of the HotPot module and then try the update again.</p>");
+               $ok = false;
+       } else {
+               // arrays to map foreign keys
+               $new = array();
+               $new['hotpot'] = array();
+               $new['attempt'] = array();
+               $new['question'] = array();
+               $new['string'] = array();
+               // save and switch off SQL message echo
+               global $db;
+               $debug = $db->debug;
+               $db->debug = false;
+               // import hotpotatoes (and save old ids)
+               $ok = $ok && hotpot_update_fields('hotpotatoes');
+               $ok = $ok && hotpot_transfer_records('hotpotatoes', 'hotpot', array(), 'hotpot', $new);
+               // update course modules and logs
+               $ok = $ok && hotpot_update_course_modules('hotpotatoes', 'hotpot', $new);
+               // import hotpotatoes_strings (and save old ids)
+               $ok = $ok && hotpot_transfer_records('hotpotatoes_strings', 'hotpot_strings', array(), 'string', $new);
+               // import hotpotatoes_attempts (and save old ids)
+               $ok = $ok && hotpot_transfer_records('hotpotatoes_attempts', 'hotpot_attempts', array('hotpotatoes'=>'hotpot'), 'attempt', $new);
+               // import hotpotatoes_questions (and save old ids)
+               $ok = $ok && hotpot_transfer_records('hotpotatoes_questions', 'hotpot_questions', array('hotpotatoes'=>'hotpot'), 'question', $new);
+               // import hotpotatoes_responses
+               $ok = $ok && hotpot_transfer_records('hotpotatoes_responses', 'hotpot_responses', array('attempt'=>'attempt', 'question'=>'question'), 'response', $new);
+               // restore SQL message echo setting
+               $db->debug = $debug;
+               // remove the hotpotatoes tables, if the update went ok
+               if ($ok) {
+               //      hotpot_db_remove_table('hotpotatoes');
+               //      hotpot_db_remove_table('hotpotatoes_attempts');
+               //      hotpot_db_remove_table('hotpotatoes_questions');
+               //      hotpot_db_remove_table('hotpotatoes_responses');
+               //      hotpot_db_remove_table('hotpotatoes_strings');
+               }
+               // hide the hotpotatoes module (see admin/modules.php))
+               if ($ok && ($module = get_record("modules", "name", "hotpotatoes"))) {
+                       set_field("modules", "visible", "0", "id", $module->id);
+                       print '<p>All HotPotatoes activities have been imported to the HotPot module.<br />'."\n";
+                       print 'The HotPotatoes module has been hidden and can safely be deleted from this Moodle site.<br />'."\n";
+                       print ' &nbsp; &nbsp; <a href="'.$CFG->wwwroot.'/admin/modules.php">Configuration -> Modules</A>, then click &quot;Delete&quot; for &quot;Hot Potatoes XML Quiz&quot;</p>'."\n";
+               }
+       }
+       if ($ok) {
+               print '<p align="center">Thank you for using the HotPotatoes module.<br />';
+               print 'The HotPotatoes module has been replaced by<br />version 2 of the HotPot module. Enjoy!</p>';
+       }
+       return $ok;
+}
+function hotpot_create_table($table) {
+       global $CFG;
+       $ok = true;
+       static $sql;
+       if (empty($sql)) { // first time only
+               $filepath = "$CFG->dirroot/mod/hotpot/db/$CFG->dbtype.sql";
+               if (function_exists('file_get_contents')) {
+                       $sql = file_get_contents($filepath);
+               } else { // PHP < 4.3
+                       $sql = file($filepath);
+                       if (is_array($sql)) {
+                                $sql = implode('', $sql);
+                       }
+               }
+               if(empty($sql)) { // $sql==false
+                        $sql = '';
+               }
+       }
+       // check table does not already exist
+       if (!hotpot_db_table_exists($table)) {
+               // extract and execute all CREATE statements relating to this table
+               if (preg_match_all("/CREATE (TABLE|INDEX)(\s[^;]*)? prefix_{$table}(\s[^;]*)?;/s", $sql, $strings)) {
+                       foreach ($strings[0] as $string) {
+                               $ok = $ok && modify_database('', $string);
+                       }
+               } else {
+                       // no CREATE statements found for this $table
+                       $ok = false;
+               }
+       }
+       return $ok;
+}
+function hotpot_transfer_records($oldtable, $table, $foreignkeys, $primarykey, &$new) {
+       global $db;
+       $ok = true;
+       // get the records, if any
+       if (hotpot_db_table_exists($oldtable) && ($records = get_records($oldtable))) {
+               // start progress report
+               $i = 0;
+               $count = count($records);
+               hotpot_update_print("Transferring $count records from &quot;$oldtable&quot; to &quot;$table&quot; ... ");
+               // transfer all $records
+               foreach ($records as $record) {
+                       switch ($table) {
+                               case 'hotpot' :
+                                       $record->summary = addslashes($record->summary);
+                                       break;
+                               case 'hotpot_attempts' :
+                                       $record->details = addslashes($record->details);
+                                       break;
+                               case 'hotpot_questions' :
+                                       $record->name = addslashes($record->name);
+                                       hotpot_update_string_id_list($table, $record, 'TEXT', $new);
+                                       break;
+                               case 'hotpot_responses' :
+                                       hotpot_update_string_id_list($table, $record, 'correct', $new);
+                                       hotpot_update_string_id_list($table, $record, 'ignored', $new);
+                                       hotpot_update_string_id_list($table, $record, 'wrong', $new);
+                                       break;
+                               case 'hotpot_strings' :
+                                       $record->string = addslashes($record->string);
+                                       break;
+                       }
+                       // update foreign keys, if any
+                       foreach ($foreignkeys as $oldkey=>$key) {
+                               // transfer (and update) key
+                               $value = $record->$oldkey;
+                               if (isset($new[$key][$value])) {
+                                       $record->$key = $new[$key][$value];
+                               } else {
+                                       // foreign key could not be updated
+                                       $ok = hotpot_update_print_warning($key, $value, $oldtable, $record->id) && $ok;
+                                       unset($record->id);
+                               }
+                       }
+                       if ($ok && isset($record->id)) {
+                               // store and remove old primary key
+                               $id = $record->id;
+                               unset($record->id);
+                               // add the updated record and store the new id
+                               $new[$primarykey][$id] = insert_record($table, $record, true);
+                               // check id is numeric
+                               if (!is_numeric($new[$primarykey][$id])) {
+                                       hotpot_update_print("<li>Record could not added to $table table ($oldtable id=$id)</li>\n");
+                                       //$ok = false;
+                               }
+                       }
+                       $i++;
+                       hotpot_update_print_progress($i);
+               }
+               // finish progress report
+               hotpot_update_print_ok($ok);
+       }
+       return $ok;
+}
+function hotpot_update_course_modules($oldmodulename, $modulename, &$new) {
+       $ok = true;
+       $oldmoduleid = get_field('modules', 'id', 'name', $oldmodulename);
+       $moduleid = get_field('modules', 'id', 'name', $modulename);
+       if (is_numeric($oldmoduleid) && is_numeric($moduleid)) {
+               // get module records
+               if ($records = get_records('course_modules', 'module', $oldmoduleid)) {
+                       // start progress report
+                       $count = count($records);
+                       hotpot_update_print("Updating $count course modules from &quot;$oldmodulename&quot; to &quot;$modulename&quot; ... ");
+                       // update foreign keys in all $records
+                       foreach ($records as $record) {
+                               // update instance
+                               $instance = $record->instance;
+                               if (isset($new[$modulename][$instance])) {
+                                       $record->instance = $new[$modulename][$instance];
+                               } else if ($record->deleted) {
+                                       unset($record->id);
+                               } else {
+                                       // could not find new id of course module
+                                       $ok = hotpot_update_print_warning("$modulename instance", $instance, 'course_modules', $record->id) && $ok;
+                                       unset($record->id);
+                               }
+                               // update module id
+                               if ($ok && isset($record->id)) {
+                                       $record->module = $moduleid;
+                                       $ok = update_record('course_modules', $record);
+                               }
+                       }
+                       // finish progress report
+                       hotpot_update_print_ok($ok);
+               }
+               // update logs
+               $ok = $ok && hotpot_update_logs($oldmodulename, $modulename, $moduleid, $new);
+       }
+       return $ok;
+}
+function hotpot_update_logs($oldmodulename, $modulename, $moduleid, &$new) {
+       $table = 'log';
+       $ok = true;
+       // get log records for the oldmodule
+       if ($records = get_records($table, 'module', $oldmodulename)) {
+               // start progress report
+               $i = 0;
+               $count = count($records);
+               hotpot_update_print("Updating $count log records ... ");
+               // update foreign keys in all $records
+               foreach ($records as $record) {
+                       // update course module name
+                       $record->module = $modulename;
+                       // check if module id was given (usually it is)
+                       if ($record->cmid) {
+                               // update course module id, if necessary
+                               if (isset($new[$modulename][$record->cmid])) {
+                                       $record->cmid = $new[$modulename][$record->cmid];
+                               } else {
+                                       // could not update course module id
+                                       $ok = hotpot_update_print_warning('cmid', $record->cmid, 'log', $record->id) && $ok;
+                                       unset($record->id);
+                               }
+                               // update url and info
+                               switch ($record->action) {
+                                       case "add":
+                                       case "update":
+                                       case "view":
+                                               $record->url = "view.php?id=".$record->cmid;
+                                               $record->info = $moduleid;
+                                               break;
+                                       case "view all":
+                                               // do nothing
+                                               break;
+                                       case "report":
+                                               $record->url = "report.php?id=".$record->cmid;
+                                               $record->info = $moduleid;
+                                               break;
+                                       case "attempt":
+                                       case "submit":
+                                       case "review": 
+                                               $id = substr(strrchr($record->url,"="),1);
+                                               if (isset($new->attempt[$id])) { 
+                                                       $id = $new->attempt[$id];
+                                               }
+                                               $record->url = "review.php?id=".$record->cmid."&attempt=$id";
+                                               $record->info = $moduleid;
+                                               break;
+                                       default:
+                                               // unknown log action
+                                               $ok = hotpot_update_print_warning('action', $record->action, 'log', $record->id) && $ok;
+                                               unset($record->id);
+                               } // end switch
+                       }
+                       if (isset($record->id)) {
+                               $ok = $ok && update_record($table, $record);
+                       }
+                       $i++;
+                       hotpot_update_print_progress($i);
+               } // end foreach
+               // finish progress report
+               hotpot_update_print_ok($ok);
+       }
+       return $ok;
+}
+function hotpot_update_fields($table, $feedback=false) {
+       global $CFG, $db;
+       $ok = true;
+       // check the table exists
+       if (hotpot_db_table_exists($table)) {
+               switch ($table) {
+                       case 'hotpot' :
+                               // == ADD ==
+                               hotpot_db_update_field_type($table, '', 'location',     'INTEGER', 4, 'UNSIGNED', 'NOT NULL', 0);
+                               hotpot_db_update_field_type($table, '', 'navigation',   'INTEGER', 4, 'UNSIGNED', 'NOT NULL', 1);
+                               hotpot_db_update_field_type($table, '', 'outputformat', 'INTEGER', 4, 'UNSIGNED', 'NOT NULL', 1);
+                               hotpot_db_update_field_type($table, '', 'shownextquiz', 'INTEGER', 4, 'UNSIGNED', 'NOT NULL', 0);
+                               hotpot_db_update_field_type($table, '', 'forceplugins', 'INTEGER', 4, 'UNSIGNED', 'NOT NULL', 0);
+                               hotpot_db_update_field_type($table, '', 'password',     'VARCHAR', 255, '',       'NOT NULL', '');
+                               hotpot_db_update_field_type($table, '', 'subnet',       'VARCHAR', 255, '',       'NOT NULL', '');
+                               // == ALTER ==
+                               hotpot_db_update_field_type($table, 'summary',   'summary',   'TEXT',    '',  '', 'NOT NULL', '');
+                               hotpot_db_update_field_type($table, 'reference', 'reference', 'VARCHAR', 255, '', 'NOT NULL', '');
+                               // == REMOVE ==
+                               hotpot_db_remove_field($table, 'intro');
+                               hotpot_db_remove_field($table, 'attemptonlast');
+                               hotpot_db_remove_field($table, 'sumgrades');
+                               hotpot_db_set_table_comment($table, 'details about Hot Potatoes quizzes');
+                       break;
+                       case 'hotpot_events' :
+                               // == ADD ==
+                               hotpot_db_update_field_type($table, '', 'hotpot',     'INTEGER', 10, 'UNSIGNED', 'NOT NULL');
+                               hotpot_db_update_field_type($table, '', 'attempt',    'INTEGER', 6,  'UNSIGNED', 'NOT NULL');
+                               hotpot_db_update_field_type($table, '', 'details',    'TEXT',    '', '', '', '');
+                               hotpot_db_update_field_type($table, '', 'timestart',  'INTEGER', 10, 'UNSIGNED', 'NOT NULL', 0);
+                               hotpot_db_update_field_type($table, '', 'timefinish', 'INTEGER', 10, 'UNSIGNED', 'NOT NULL', 0);
+                               // == ALTER ==
+                               hotpot_db_update_field_type($table, 'score',     'score',      'INTEGER', 6,  'UNSIGNED', 'NULL');
+                               hotpot_db_update_field_type($table, 'wrong',     'penalties',  'INTEGER', 6,  'UNSIGNED', 'NULL');
+                               hotpot_db_update_field_type($table, 'starttime', 'starttime',  'INTEGER', 10, 'UNSIGNED', 'NULL');
+                               hotpot_db_update_field_type($table, 'endtime',   'endtime',    'INTEGER', 10, 'UNSIGNED', 'NULL');
+                               // save and switch off SQL message echo
+                               $debug = $db->debug;
+                               $db->debug = $feedback;
+                               // get array mapping course module ids to hotpot ids
+                               $hotpotmoduleid = get_field('modules', 'id', 'name', 'hotpot');
+                               $coursemodules = get_records('course_modules', 'module', $hotpotmoduleid, 'id', 'id, instance');
+                               // get all event records
+                               if (hotpot_db_field_exists($table, 'hotpotid')) {
+                                       $records = get_records($table, '', '', 'userid,hotpotid,time');
+                               } else {
+                                       $records = false; // table has already been updated
+                               }
+                               if ($records) {
+                                       $count = count($records);
+                                       hotpot_update_print("Updating $count records in $table ... ");
+                                       $ids = array_keys($records);
+                                       foreach ($ids as $i=>$id) {
+                                               // reference to current record
+                                               $record = &$records[$id];
+                                               // set timestart and timefinish (the times recorded by Moodle)
+                                               if (empty($record->timestart) && $record->time) {
+                                                       $record->timestart = $record->time;
+                                               }
+                                               if (empty($record->timefinish) && $record->timestart) {
+                                                       if ($record->starttime && $record->endtime) {
+                                                               $duration = ($record->endtime - $record->starttime);
+                                                       } else {
+                                                               if (($i+1)>=$count) {
+                                                                       $nextrecord = NULL;
+                                                               } else {
+                                                                       $nextrecord = &$records[$ids[$i+1]];
+                                                               }
+                                                               if (isset($nextrecord) && $nextrecord->userid==$record->userid && $nextrecord->hotpotid==$record->hotpotid) {
+                                                                       $duration = $nextrecord->time - $record->time;
+                                                               } else {
+                                                                       $duration = NULL;
+                                                               }
+                                                       }
+                                                       if (isset($duration)) {
+                                                               $record->timefinish = $record->timestart + $duration;
+                                                       }
+                                               }
+                                               // unset score and penalties, if quiz was abandoned
+                                               if (empty($record->endtime) || (empty($record->penalties) && empty($record->score))) {
+                                                       unset($record->score);
+                                                       unset($record->penalties);
+                                               }
+                                               // get last (=previous) record
+                                               if ($i==0) {
+                                                       $lastrecord = NULL;
+                                               } else {
+                                                       $lastrecord = &$records[$ids[$i-1]];
+                                               }
+                                               // increment or reset $attempt number
+                                               if (isset($lastrecord) && $lastrecord->userid==$record->userid && $lastrecord->hotpotid==$record->hotpotid) {
+                                                       $attempt++;
+                                               } else {
+                                                       $attempt = 1;
+                                               }
+                                               // set $record->$attempt, if necessary
+                                               if (empty($record->attempt) || $record->attempt<$attempt) {
+                                                       $record->attempt = $attempt;
+                                               } else {
+                                                       $attempt = $record->attempt;
+                                               }
+                                               // set hotpot id and update record
+                                               if (isset($record->hotpotid) && isset($record->id)) {
+                                                       if (isset($coursemodules[$record->hotpotid])) {
+                                                               $record->hotpot = $coursemodules[$record->hotpotid]->instance;
+                                                               hotpot_db_update_record($table, $record, true);
+                                                       } else {
+                                                               // hotpotid is invalid (shouldn't happen)
+                                                               $ok = hotpot_update_print_warning('hotpotid', $record->hotpotid, $table, $record->id) && $ok;
+                                                               delete_records($table, 'id', $record->id);
+                                                       }
+                                               } else {
+                                                               // empty record (shouldn't happen)
+                                               }
+                                               hotpot_update_print_progress($i);
+                                       }
+                                       // finish progress report
+                                       hotpot_update_print_ok($ok);
+                               }
+                               // restore SQL message echo setting
+                               $db->debug = $debug;
+                               // == REMOVE ==
+                               hotpot_db_remove_field($table, 'hotpotid');
+                               hotpot_db_remove_field($table, 'course');
+                               hotpot_db_remove_field($table, 'time');
+                               hotpot_db_remove_field($table, 'event');
+                               hotpot_db_set_table_comment($table, 'details about Hot Potatoes quiz attempts');
+                       break;
+                       case 'hotpotatoes' :
+                               // == ALTER ==
+                               hotpot_db_update_field_type($table, 'intro', 'summary', 'TEXT', '', '', '', 'NULL');
+                       break;
+               }
+       }
+       return $ok;
+}
+function hotpot_update_string_id_list($table, &$record, $field, &$new) {
+       $ok = true;
+       if (isset($record->$field)) {
+               $oldids = explode(',', $record->$field);
+               $newids = array();
+               foreach ($oldids as $id) {
+                       if (isset($new['string'][$id])) {
+                               $newids[] = $new['string'][$id];
+                       } else if (is_numeric($id)) {
+                               // string id could not be updated
+                               $ok = hotpot_update_print_warning("string id in $field", $id, $table, $record->id) && $ok;
+                       } else {
+                               // ignore non-numeric ids (e.g. blanks)
+                       }
+               }
+               if ($ok) {
+                       $record->$field = implode(',', $newids);
+               }
+       }
+       return $ok;
+}
+///////////////////////////
+//     print functions
+///////////////////////////
+function hotpot_update_print($msg=false, $n=300) {
+       // this function prints $msg and flush output buffer
+       if ($msg) {
+               if (is_string($msg)) {
+                       print $msg;
+               } else {
+                       print strftime("%X", time());
+               }
+       }
+       // fill output buffer
+       if ($n) {
+               print str_repeat(" ", $n);
+       }
+       // some browser's require newline to flush
+       print "\n";
+       // flush PHP's output buffer
+       flush();
+}
+function hotpot_update_print_progress($i) {
+       if ($i%10==0) {
+               $msg = '.';
+               hotpot_update_print($msg);
+       }
+}
+function hotpot_update_print_ok($ok) {
+       if ($ok) {
+               hotpot_update_print('<font color="green">'.get_string('success')."</font><br />\n");
+       } else {
+               hotpot_update_print('<font color="red">'.get_string('error')."</font><br />\n");
+       }
+}
+function hotpot_update_print_warning($field, $value, $table, $id) {
+       hotpot_update_print("<li><b>Warning:</b> invalid $field field (value=$value) in $table (id=$id)</li>\n");
+       return true;
+}
+///////////////////////////
+//     database functions
+///////////////////////////
+function hotpot_db_index_exists($table, $index, $feedback=false) {
+       global $CFG, $db;
+       $exists = false;
+       // save and switch off SQL message echo
+       $debug = $db->debug;
+       $db->debug = $feedback;
+       switch (strtolower($CFG->dbtype)) {
+               case 'mysql' : 
+                       $rs = $db->Execute("SHOW INDEX FROM `$table`");
+                       if ($rs && $rs->RecordCount()>0) {
+                               $records = $rs->GetArray();
+                               foreach ($records as $record) {
+                                       if (isset($record['Key_name']) && $record['Key_name']==$index) {
+                                               $exists = true;
+                                               break;
+                                       }
+                               }
+                       }
+               break;
+               case 'postgres7' :
+                       $rs = $db->Execute("SELECT relname FROM pg_class WHERE relname = '$index' AND relkind='i'");
+                       if ($rs && $rs->RecordCount()>0) {
+                               $exists = true;
+                       }
+               break;
+       }
+       // restore SQL message echo
+       $db->debug = $debug;
+       return $exists;
+}
+function hotpot_db_delete_index($table, $index, $feedback=false) {
+       global $CFG, $db;
+       $ok = true;
+       // check index exists
+       if (hotpot_db_index_exists($table, $index)) {
+               switch (strtolower($CFG->dbtype)) {
+                       case 'mysql' : 
+                               $sql = "ALTER TABLE `$table` DROP INDEX `$index`";
+                       break;
+                       case 'postgres7' :
+                               $sql = "DROP INDEX $index";
+                       break;
+                       default: // unknown database type
+                               $sql = '';
+                       break;
+               }
+               if ($sql) {
+                       // save and switch off SQL message echo
+                       $debug = $db->debug;
+                       $db->debug = $feedback;
+                       $ok = $db->Execute($sql) ? true : false;
+                       // restore SQL message echo
+                       $db->debug = $debug;
+               } else { // unknown database type
+                       $ok = false;
+               }
+       }
+       return $ok;
+}
+function hotpot_db_add_index($table, $field, $length='') {
+       global $CFG, $db;
+
+       if (strtolower($CFG->dbtype)=='postgres7') {
+               $index = "{$CFG->prefix}{$table}_{$field}_idx";
+       } else {
+               // mysql (and others)
+               $index = "{$table}_{$field}_idx";
+       }
+       $table = "{$CFG->prefix}$table";
+
+       // delete $index if it already exists
+       $ok = hotpot_db_delete_index($table, $index);
+
+       switch (strtolower($CFG->dbtype)) {
+               case 'mysql' :
+                       $length = empty($length) ? '' : " ($length)";
+                       $ok = $ok && $db->Execute("ALTER TABLE `$table` ADD INDEX `$index` (`$field`$length)");
+               break;
+               case 'postgres7' :
+                       if ($length) {
+                               $field = "SUBSTR($field,$length)";
+                       }
+                       $ok = $ok && $db->Execute("CREATE INDEX $index ON $table ($field)");
+               break;
+               default: // unknown database type
+                       $ok = false;
+               break;
+       }
+       return $ok;
+}
+function hotpot_db_table_exists($table, $feedback=false) {
+       return hotpot_db_object_exists($table, '', $feedback);
+}
+function hotpot_db_field_exists($table, $field, $feedback=false) {
+       return 
+               hotpot_db_object_exists($table, '', $feedback) &&
+               hotpot_db_object_exists($table, $field, $feedback)
+       ;
+}
+function hotpot_db_object_exists($table, $field='', $feedback=false) {
+       global $CFG,$db;
+       // expand table name
+       $table = "{$CFG->prefix}$table";
+       // set $sql
+       switch (strtolower($CFG->dbtype)) {
+               case 'mysql' : 
+                       if (empty($field)) {
+                               $sql = "SHOW TABLES LIKE '$table'";
+                       } else {
+                               $sql = "SHOW COLUMNS FROM `$table` LIKE '$field'";
+                       }
+               break;
+               case 'postgres7' :
+                       if (empty($field)) {
+                               $sql = "SELECT relname FROM pg_class WHERE relname = '$table' AND relkind='r'";
+                       } else {
+                               $sql = "
+                                       SELECT attname FROM pg_attribute WHERE attname = '$field' 
+                                       AND attrelid = (SELECT oid FROM pg_class WHERE relname = '$table')
+                               ";
+                       }
+               break;
+       }
+       // save and switch off SQL message echo
+       $debug = $db->debug;
+       $db->debug = $feedback;
+       // execute sql
+       $rs = $db->Execute($sql);
+       // restore SQL message echo setting
+       $db->debug = $debug;
+       // report error if required
+       if (empty($rs) && isset($CFG->debug) and $CFG->debug > 7) {
+               notify($db->ErrorMsg()."<br /><br />$sql");
+       }
+       return ($rs && $rs->RecordCount()>0);
+}
+function hotpot_db_remove_table($table, $feedback=true) {
+       global $CFG;
+       if (hotpot_db_table_exists($table)) {
+               $ok = execute_sql("DROP TABLE {$CFG->prefix}$table", $feedback);
+       } else {
+               $ok = true;
+       }
+       return $ok;
+}
+function hotpot_db_rename_table($oldtable, $table, $feedback=true) {
+       global $CFG;
+       if (hotpot_db_table_exists($oldtable)) {
+               $ok = execute_sql("ALTER TABLE {$CFG->prefix}$oldtable RENAME TO {$CFG->prefix}$table", $feedback);
+       } else {
+               $ok = true;
+       }
+       return $ok;
+}
+function hotpot_db_append_table($oldtable, $table, $feedback=true) {
+       global $CFG, $db;
+       if (hotpot_db_table_exists($oldtable)) {
+               if (hotpot_db_table_exists($table)) {
+                       // expand table names
+                       $table = "{$CFG->prefix}$table";
+                       $oldtable = "{$CFG->prefix}$oldtable";
+                       // get field info
+                       $fields = $db->MetaColumns($table);
+                       $oldfields = $db->MetaColumns($oldtable);
+                       $fieldnames = array();
+                       if (!empty($fields) || !empty($oldfields)) {
+                               foreach ($fields as $field) {
+                                       if ($field->name!='id' && isset($oldfields[strtoupper($field->name)])) {
+                                               $fieldnames[] = $field->name;
+                                       }
+                               }
+                       }
+                       $fieldnames = implode(',', $fieldnames);
+                       if (empty($fieldnames)) {
+                               $ok = false;
+                       } else {
+                               switch (strtolower($CFG->dbtype)) {
+                                       case 'mysql':
+                                               $ok = execute_sql("INSERT INTO `$table` ($fieldnames) SELECT $fieldnames FROM `$oldtable` WHERE 1");
+                                               break;
+                                       case 'postgres7':
+                                               $ok = execute_sql("INSERT INTO $table ($fieldnames) SELECT $fieldnames FROM $oldtable");
+                                               break;
+                                       default:
+                                               $ok = false;
+                                               break;
+                               }
+                       }
+               } else { // $table does not exist
+                       $ok = hotpot_db_rename_table($oldtable, $table, $feedback);
+               }
+       } else { // $oldtable does not exist
+               $ok = hotpot_db_table_exists($table, $feedback);
+       }
+       return $ok;
+}
+function hotpot_db_set_table_comment($table, $comment, $feedback=true) {
+       global $CFG;
+       $ok = true;
+       switch (strtolower($CFG->dbtype)) {
+               case 'mysql' :
+                       $ok = execute_sql("ALTER TABLE {$CFG->prefix}$table COMMENT='$comment'");
+                       break;
+               case 'postgres7' :
+                       $ok = execute_sql("COMMENT ON TABLE {$CFG->prefix}$table IS '$comment'");
+                       break;
+       }
+       return $ok;
+}
+function hotpot_db_remove_field($table, $field, $feedback=true) {
+       global $CFG;
+       if (hotpot_db_field_exists($table, $field)) {
+               $ok = execute_sql("ALTER TABLE {$CFG->prefix}$table DROP COLUMN $field", $feedback);
+       } else {
+               $ok = true;
+       }
+       return $ok;
+}
+function hotpot_db_update_field_type($table, $oldfield, $field, $type, $size, $unsigned, $notnull, $default=NULL, $after=NULL) {
+       $ok = true;
+       global $CFG,$db;
+       // check validity of arguments, and adjust if necessary
+       if ($oldfield && !hotpot_db_field_exists($table, $oldfield)) {
+               $oldfield = '';
+       }
+       if (empty($oldfield) && hotpot_db_field_exists($table, $field)) {
+               $oldfield = $field;
+       } 
+       if (is_string($unsigned)) {
+               $unsigned = (strtoupper($unsigned)=='UNSIGNED');
+       }
+       if (is_string($notnull)) {
+               $notnull = (strtoupper($notnull)=='NOT NULL');
+       }
+       if (isset($default)) {
+               if (!is_numeric($default) && strtoupper($default)!='NULL' && !preg_match("|^'.*'$|", $default)) {
+                       $default = "'$default'";
+               }
+       }
+       // set full table name
+       $table = "{$CFG->prefix}$table";
+       // update the field in the database
+       switch (strtolower($CFG->dbtype)) {
+               case 'mysql':
+                       // optimize integer types
+                       switch (strtoupper($type)) {
+                               case 'TEXT':
+                                       $size = '';
+                                       $unsigned = false;
+                               break;
+                               case 'INTEGER' :
+                                       if (!is_numeric($size)) {
+                                               $size = '';
+                                       } else if ($size <= 4) {
+                                               $type = "TINYINT";   // 1 byte
+                                       } else if ($size <= 6) {
+                                               $type = "SMALLINT";  // 2 bytes
+                                       } else if ($size <= 8) {
+                                               $type = "MEDIUMINT"; // 3 bytes
+                                       } else if ($size <= 10) {
+                                               $type = "INTEGER";   // 4 bytes (=INT)
+                                       } else if ($size > 10) {
+                                               $type = "BIGINT";    // 8 bytes
+                                       }
+                               break;
+                               case 'VARCHAR':
+                                       $unsigned = false;
+                               break;
+                       }
+                       // set action
+                       if (empty($oldfield)) {
+                               $action = "ADD";
+                       } else {
+                               $action = "CHANGE `$oldfield`";
+                       }
+                       // set fieldtype
+                       $fieldtype = $type;
+                       if ($size) {
+                               $fieldtype .= "($size)";
+                       }
+                       if ($unsigned) {
+                               $fieldtype .= ' UNSIGNED';
+                       }
+                       if ($notnull) {
+                               $fieldtype .= ' NOT NULL';
+                       }
+                       if (isset($default)) {
+                               $fieldtype .= " DEFAULT $default";
+                       }
+                       if (!empty($after)) {
+                               $fieldtype .= " AFTER `$after`";
+                       }
+                       $ok = $ok && execute_sql("ALTER TABLE `$table` $action `$field` $fieldtype");
+               break;
+               case 'postgres7':
+                       // get db version
+                       $dbinfo = $db->ServerInfo();
+                       $dbversion = substr($dbinfo['version'],0,3);
+                       // prevent conflicts with reserved words
+                       $tmpfield = "\"temporary_{$field}_".time()."\"";
+                       $oldfield = "\"$oldfield\"";
+                       $field    = "\"$field\"";
+                       switch (strtoupper($type)) {
+                               case "INTEGER":
+                                       if (!is_numeric($size)) {
+                                               $fieldtype = "INTEGER";
+                                       } else if ($size <= 4) {
+                                               $fieldtype = "INT2"; // 2 bytes
+                                       } else if ($size <= 10) {
+                                               $fieldtype = "INT4"; // 4 bytes (=INTEGER)
+                                       } else if ($size > 10) {
+                                               $fieldtype = "INT8"; // 8 bytes
+                                       }
+                               break;
+                               case "VARCHAR":
+                                       $fieldtype = "VARCHAR($size)";
+                               break;
+                               default:
+                                       $fieldtype = $type;
+                       }
+                       // start transaction
+                       execute_sql("BEGIN");
+                       // create temporary field
+                       execute_sql("ALTER TABLE $table ADD COLUMN $tmpfield $fieldtype");
+                       // set default
+                       if (isset($default)) {
+                               execute_sql("UPDATE $table SET $tmpfield = $default");
+                               execute_sql("ALTER TABLE $table ALTER COLUMN $tmpfield SET DEFAULT $default");
+                       } else {
+                               execute_sql("ALTER TABLE $table ALTER COLUMN $tmpfield DROP DEFAULT");
+                       }
+                       // set not null
+                       if ($dbversion >= "7.3") {
+                               $notnull = ($notnull ? "SET NOT NULL" : "DROP NOT NULL");
+                               execute_sql("ALTER TABLE $table ALTER COLUMN $tmpfield $notnull");
+                       } else {
+                               execute_sql("
+                                       UPDATE pg_attribute SET attnotnull=".($notnull ? 'TRUE' : 'FALSE')." 
+                                       WHERE attname = $tmpfield
+                                       AND attrelid = (SELECT oid FROM pg_class WHERE relname = '$table')
+                               ");
+                       }
+                       // transfer $oldfield values, if necessary
+                       if ( $oldfield != '""' ) {
+                               execute_sql("UPDATE $table SET $tmpfield = CAST ($oldfield AS $fieldtype)");
+                               execute_sql("ALTER TABLE $table DROP COLUMN $oldfield");
+                       }
+                       // rename $tmpfield to $field
+                       execute_sql("ALTER TABLE $table RENAME COLUMN $tmpfield TO $field");
+                       // do the transaction
+                       execute_sql("COMMIT");
+                       // reclaim disk space (must be done outside transaction)
+                       if ($oldfield != '""' && $dbversion >= "7.3") {
+                               execute_sql("UPDATE $table SET $field = $field");
+                               execute_sql("VACUUM FULL $table");
+                       }
+               break;
+       } // end switch $CGF->dbtype
+       return $ok;
+}
+function hotpot_db_update_record($table, $record, $forcenull=false) {
+       global $CFG, $db;
+       $ok = true;
+       // set full table name
+       $table = "{$CFG->prefix}$table";
+       // get field names
+       $fields = $db->MetaColumns($table);
+       if (empty($fields)) {
+               $ok = false;
+       } else {
+               // get values
+               $values = array();
+               foreach ($fields as $field) {
+                       $fieldname = $field->name;
+                       if ($fieldname!='id' && ($forcenull || isset($record->$fieldname))) {
+                               $value = isset($record->$fieldname) ? "'".$record->$fieldname."'" : 'NULL';
+                               $values[] = "$fieldname = $value";
+                       }
+               }
+               $values = implode(',', $values);
+               // update values (if there are any)
+               if ($values) {
+                       $sql = "UPDATE $table SET $values WHERE id='$record->id'";
+                       $rs = $db->Execute($sql);
+                       if (empty($rs)) {
+                               $ok = false;
+                               if (isset($CFG->debug) and $CFG->debug > 7) {
+                                       notify($db->ErrorMsg()."<br /><br />$sql");
+                               }
+                       }
+               }
+       }
+       return $ok;
+}
+function hotpot_rm($target, $output=true) {
+       $ok = true;
+       if (!empty($target)) {
+               if (is_file($target)) {
+                       if ($output) {
+                               print "removing file: $target ... ";
+                       }
+                       $ok = @unlink($target);
+               } else if (is_dir($target)) {
+                       $dir = dir($target);
+                       while(false !== ($entry = $dir->read())) {
+                               if ($entry!='.' && $entry!='..') {
+                                       $ok = $ok && hotpot_rm($target.DIRECTORY_SEPARATOR.$entry, $output);
+                               }
+                       }
+                       $dir->close();
+                       if ($output) {
+                               print "removing folder: $target ... ";
+                       }
+                       $ok = $ok && @rmdir($target);
+               } else { // not a file or directory (probably doesn't exist)
+                       $output = false;
+               }
+               if ($output) {
+                       if ($ok) {
+                               print '<font color="green">OK</font><br />';
+                       } else {
+                               print '<font color="red">Failed</font><br />';
+                       }
+               }
+       }
+       return $ok;
+}
+function hotpot_flush($n=0, $time=false) {
+       if ($time) {
+               $t = strftime("%X",time());
+       } else {
+               $t = "";
+       }
+       echo str_repeat(" ", $n) . $t . "\n";
+       flush();
+}
+?>