-<?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)." "in progress" 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, '&','&') \r
- WHERE string LIKE '%&#%' \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 ' <a href="'.$CFG->wwwroot.'/admin/modules.php">Configuration -> Modules</A>, then click "Delete" for "Hot Potatoes XML Quiz"</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 "$oldtable" to "$table" ... ");\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 "$oldmodulename" to "$modulename" ... ");\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)." "in progress" 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, '&','&')
+ WHERE string LIKE '%&#%'
+ 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 ' <a href="'.$CFG->wwwroot.'/admin/modules.php">Configuration -> Modules</A>, then click "Delete" for "Hot Potatoes XML Quiz"</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 "$oldtable" to "$table" ... ");
+ // 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 "$oldmodulename" to "$modulename" ... ");
+ // 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();
+}
+?>