diff --git a/e107_handlers/db_table_admin_class.php b/e107_handlers/db_table_admin_class.php
index e812a8a0e..14137c765 100644
--- a/e107_handlers/db_table_admin_class.php
+++ b/e107_handlers/db_table_admin_class.php
@@ -11,513 +11,559 @@
| GNU General Public License (http://gnu.org).
|
| $Source: /cvs_backup/e107_0.8/e107_handlers/db_table_admin_class.php,v $
-| $Revision: 1.6 $
-| $Date: 2008-11-02 14:54:44 $
-| $Author: e107steved $
+| $Revision: 1.7 $
+| $Date: 2008-12-20 00:55:29 $
+| $Author: mcfly_e107 $
+----------------------------------------------------------------------------+
*/
/*
Database utilities for admin tasks:
- Get structure of a table from a database
- Get structure of a table from a file
- First level parse of table structure
- Parse of field definitions part of table structure
- Comparison of two structures, including generation of MySQL to make them the same
- Some crude printing utilities
-
+Get structure of a table from a database
+Get structure of a table from a file
+First level parse of table structure
+Parse of field definitions part of table structure
+Comparison of two structures, including generation of MySQL to make them the same
+Some crude printing utilities
+
Note: there are some uncommented 'echo' statements which are intentional to highlight that something's gone wrong! (not that it should, of course)
*/
class db_table_admin
{
- var $file_buffer = ''; // Contents of a file
- var $last_file = '';
-
-// Get list of fields and keys for a table - return FALSE if unsuccessful
-// Return as for get_table_def
- function get_current_table($table_name, $prefix = "")
- {
- global $sql;
+ var $file_buffer = ''; // Contents of a file
+ var $last_file = '';
- if (!$prefix) $prefix = MPREFIX;
-// echo "Get table structure for: {$table_name}, prefix: {$prefix}
";
- $sql->db_Select_gen('SET SQL_QUOTE_SHOW_CREATE = 1');
- $qry = 'SHOW CREATE TABLE `'.$prefix.$table_name."`";
- if (!($z = $sql->db_Select_gen($qry))) return FALSE;
- $row = $sql->db_Fetch();
- $tmp = str_replace("`", "", stripslashes($row[1])).';'; // Add semicolon to work with our parser
- $count = preg_match_all("#CREATE\s+?TABLE\s+?`{0,1}({$prefix}{$table_name})`{0,1}\s+?\((.*?)\)\s+?(?:TYPE|ENGINE)\s*\=\s*(.*?);#is",$tmp,$matches,PREG_SET_ORDER);
- if ($count === FALSE) return "Error occurred";
- if (!$count) return "No matches";
- return $matches;
- }
-
-
-// Routine to do first-level parse of table structure
-//---------------------------------------------------
-// Given the name of a file, returns an array, with each element being a table creation definition.
-// Tracks the last file read - only reads it once
-// If the file name is an empty string, uses a previously read/set buffer
-// If a table name is given, returns only that table's info; otherwise returns a list of all tables
-// The table name must include a prefix where appropriate (although not required with standard E107 table definition files)
-// Each element is itself an array:
-// [0] - The complete string which creates a table (unless a prefix needs adding to the table name), including terminating ';'
-// [1] - The table name. Any backticks are stripped
-// [2] - Field definitions, with the surrounding (...) stripped
-// [3] - The 'TYPE' field ('TYPE=' is stripped) and any AUTO-INCREMENT definition or other text.
-// function get_table_def($table_name='',$file_name = e_ADMIN."sql/core_sql.php")
- function get_table_def($table_name='',$file_name ="")
- {
- if ($file_name != '')
- { // Read in and buffer a new file (if we've not already got one)
- if ($this->last_file != $file_name)
- {
- if (!is_readable($file_name)) return "No file";
- $temp = file_get_contents($file_name);
- // Strip any php header
- $this->file_buffer = preg_replace("#\<\?php.*?\?\>#mis",'',$temp);
- $this->last_file = $file_name;
- }
- }
- if (!$table_name) $table_name = '\w+?';
- // Regex should be identical to that in get_current_table (apart from the source text variable name)
- $count = preg_match_all("#CREATE\s+?TABLE\s+?`{0,1}({$table_name})`{0,1}\s+?\((.*?)\)\s+?(?:TYPE|ENGINE)\s*\=\s*(.*?);#is",$this->file_buffer,$matches,PREG_SET_ORDER);
- if ($count === FALSE) return "Error occurred";
- if (!$count) return "No matches";
- return $matches;
- }
-
-
-// Parses the block of lines which make up the field and index definitions
-// Returns an array where each entry is the definitions of a field or index
- function parse_field_defs($text)
- {
- $ans = array();
- $text = str_replace("\r","\n",$text);
- $field_lines = explode("\n",$text);
- foreach ($field_lines as $fv)
+ // Get list of fields and keys for a table - return FALSE if unsuccessful
+ // Return as for get_table_def
+ function get_current_table($table_name, $prefix = "")
{
- unset($defs);
- $fv = trim(str_replace(' ',' ',$fv));
- if (substr($fv,-1) == ',') $fv = trim(substr($fv,0,-1));
-// echo "Line: ".$fv."
";
- if ($fv)
- {
- $fd = explode(' ',$fv);
- switch (strtoupper($fd[0]))
- {
- case 'PRIMARY' :
- if (strtoupper($fd[1]) == 'KEY')
- $defs['type'] = 'pkey';
- $defs['name'] = $fd[2];
- break;
- case 'UNIQUE' :
- if (count($fd) < 3)
+ global $sql;
+
+ if (!$prefix) { $prefix = MPREFIX; }
+ // echo "Get table structure for: {$table_name}, prefix: {$prefix}
";
+ $sql->db_Select_gen('SET SQL_QUOTE_SHOW_CREATE = 1');
+ $qry = 'SHOW CREATE TABLE `'.$prefix.$table_name."`";
+ if (!($z = $sql->db_Select_gen($qry))) { return FALSE; }
+ $row = $sql->db_Fetch();
+ $tmp = str_replace("`", "", stripslashes($row[1])).';'; // Add semicolon to work with our parser
+ $count = preg_match_all("#CREATE\s+?TABLE\s+?`{0,1}({$prefix}{$table_name})`{0,1}\s+?\((.*?)\)\s+?(?:TYPE|ENGINE)\s*\=\s*(.*?);#is",$tmp,$matches,PREG_SET_ORDER);
+ if ($count === FALSE) { return "Error occurred";}
+ if (!$count) { return "No matches"; }
+ return $matches;
+ }
+
+
+ // Routine to do first-level parse of table structure
+ //---------------------------------------------------
+ // Given the name of a file, returns an array, with each element being a table creation definition.
+ // Tracks the last file read - only reads it once
+ // If the file name is an empty string, uses a previously read/set buffer
+ // If a table name is given, returns only that table's info; otherwise returns a list of all tables
+ // The table name must include a prefix where appropriate (although not required with standard E107 table definition files)
+ // Each element is itself an array:
+ // [0] - The complete string which creates a table (unless a prefix needs adding to the table name), including terminating ';'
+ // [1] - The table name. Any backticks are stripped
+ // [2] - Field definitions, with the surrounding (...) stripped
+ // [3] - The 'TYPE' field ('TYPE=' is stripped) and any AUTO-INCREMENT definition or other text.
+ // function get_table_def($table_name='',$file_name = e_ADMIN."sql/core_sql.php")
+ function get_table_def($table_name='',$file_name ="")
+ {
+ if ($file_name != '')
+ { // Read in and buffer a new file (if we've not already got one)
+ if ($this->last_file != $file_name)
{
- echo "Truncated definition after UNIQUE {$i}: ".$fd[1]."
";
+ if (!is_readable($file_name)) { return "No file"; }
+ $temp = file_get_contents($file_name);
+ // Strip any php header
+ $this->file_buffer = preg_replace("#\<\?php.*?\?\>#mis",'',$temp);
+ $this->last_file = $file_name;
}
- elseif (strtoupper($fd[1]) == 'KEY')
+ }
+ if (!$table_name) { $table_name = '\w+?'; }
+ // Regex should be identical to that in get_current_table (apart from the source text variable name)
+ $count = preg_match_all("#CREATE\s+?TABLE\s+?`{0,1}({$table_name})`{0,1}\s+?\((.*?)\)\s+?(?:TYPE|ENGINE)\s*\=\s*(.*?);#is",$this->file_buffer,$matches,PREG_SET_ORDER);
+ if ($count === false) { return "Error occurred"; }
+ if (!$count) { return "No matches"; }
+ return $matches;
+ }
+
+
+ // Parses the block of lines which make up the field and index definitions
+ // Returns an array where each entry is the definitions of a field or index
+ function parse_field_defs($text)
+ {
+ $ans = array();
+ $text = str_replace("\r","\n",$text);
+ $field_lines = explode("\n",$text);
+ foreach ($field_lines as $fv)
+ {
+ unset($defs);
+ $fv = trim(str_replace(' ',' ',$fv));
+ if (substr($fv,-1) == ',') { $fv = trim(substr($fv,0,-1)); }
+ // echo "Line: ".$fv."
";
+ if ($fv)
{
- $defs['type'] = 'ukey';
- $defs['name'] = $fd[2];
- if (isset($fd[3])) $defs['keyfield'] = $fd[3]; else $defs['keyfield'] = '['.$fd[2].']';
+ $fd = explode(' ',$fv);
+ switch (strtoupper($fd[0]))
+ {
+ case 'PRIMARY' :
+ if (strtoupper($fd[1]) == 'KEY')
+ $defs['type'] = 'pkey';
+ $defs['name'] = $fd[2];
+ break;
+ case 'UNIQUE' :
+ if (count($fd) < 3)
+ {
+ echo "Truncated definition after UNIQUE {$i}: ".$fd[1]."
";
+ }
+ elseif (strtoupper($fd[1]) == 'KEY')
+ {
+ $defs['type'] = 'ukey';
+ $defs['name'] = $fd[2];
+ if (isset($fd[3])) $defs['keyfield'] = $fd[3]; else $defs['keyfield'] = '['.$fd[2].']';
+ }
+ else
+ {
+ echo "Unrecognised word after UNIQUE in definition {$i}: ".$fd[1]."
";
+ }
+ break;
+ case 'KEY' :
+ $defs['type'] = 'key';
+ $defs['name'] = $fd[1];
+ if (isset($fd[2])) {
+ $defs['keyfield'] = $fd[2];
+ }
+ else
+ {
+ $defs['keyfield'] = '['.$fd[1].']';
+ }
+ break;
+ default : // Must be a DB field name
+ $defs['type'] = 'field';
+ $defs['name'] = $fd[0];
+ $defs['fieldtype'] = $fd[1];
+ $i = 2; // First unused field
+ if ((strpos($fd[1],'int') === 0) || (strpos($fd[1],'tinyint') === 0) || (strpos($fd[1],'smallint') === 0) || (strpos($fd[1],'bigint') === 0))
+ {
+ if (isset($fd[2]) && (strtoupper($fd[2]) == 'UNSIGNED'))
+ {
+ $defs['vartype'] = $fd[2];
+ $i++;
+ }
+ }
+ while ($i < count($fd))
+ {
+ switch(strtoupper($fd[$i]))
+ {
+ case 'NOT' :
+ if (isset($fd[$i+1]) && strtoupper($fd[$i+1]) == 'NULL')
+ {
+ $i++;
+ $defs['nulltype'] = 'NOT NULL';
+ }
+ else
+ { // Syntax error
+ echo "Unrecognised word in definition {$i} after 'NOT': ".$fd[$i+1]."
";
+ }
+ break;
+ case 'DEFAULT' :
+ if (isset($fd[$i+1]))
+ {
+ $i++;
+ $defs['default'] = $fd[$i];
+ }
+ break;
+ case 'COLLATE' :
+ $i++; // Just skip over - we ignore collation
+ break;
+ case 'AUTO_INCREMENT' :
+ $defs['autoinc'] = TRUE;
+ break;
+ default :
+ echo "Unknown definition {$i}: ".$fd[$i]."
";
+ }
+ $i++;
+ }
+ }
+ if (count($defs) > 1)
+ {
+ $ans[] = $defs;
+ }
+ else
+ {
+ echo "Partial definition
";
+ }
+ }
+ }
+ if (!count($ans)) { return FALSE; }
+ return $ans;
+ }
+
+
+
+ // Utility routine - given our array-based definition, create a string MySQL field definition
+ function make_def($list)
+ {
+ switch ($list['type'])
+ {
+ case 'key' :
+ return 'KEY '.$list['name'].' ('.str_replace(array('(',')'),'',$list['keyfield']).')';
+ case 'ukey' :
+ return 'UNIQUE KEY '.$list['name'].' ('.$list['name'].')';
+ case 'pkey' :
+ return 'PRIMARY KEY ('.$list['name'].')';
+ case 'field' : // Require a field - got a key. so add a field at the end
+ $def = $list['name'];
+ if (isset($list['fieldtype'])) { $def .= ' '.$list['fieldtype']; }
+ if (isset($list['vartype'])) { $def .= ' '.$list['vartype']; }
+ if (isset($list['nulltype'])) { $def .= ' '.$list['nulltype']; }
+ if (isset($list['default'])) { $def .= ' default '.$list['default']; }
+ if (varsettrue($list['autoinc'])) { $def .= ' auto_increment'; }
+ return $def;
+ }
+ return "Cannot generate definition for: ".$list['type'].' '.$list['name'];
+ }
+
+
+ // Compare two field/index lists as generated by parse_field_defs
+ // If $stop_on_error is TRUE, returns TRUE if the same, false if different
+ // Return a text list of differences, plus an array of MySQL queries to fix
+ // List1 is the reference, List 2 is the actual
+ // This version looks ahead on a failed match, and moves a field up in the table if already defined - should retain as much as possible
+ function compare_field_lists($list1, $list2, $stop_on_error=FALSE)
+ {
+ $i = 0; // Counts records in list1 (required format)
+ $j = 0; // Counts records in $created_list (our 'table so far' list)
+ $error_list = array(); // Free text list of differences
+ $change_list = array(); // MySQL statements to implement changes
+ $created_list = array(); // List of field defs that we build up (just names)
+ while ($i < count($list1))
+ {
+ if (count($list2) == 0)
+ { // Missing field at end
+ if ($stop_on_error) { return FALSE; }
+ $error_list[] = 'Missing field at end: '.$list1[$i]['name'];
+ $change_list[] = 'ADD '.$this->make_def($list1[$i]);
+ $created_list[$j] = $list1[$i]['name'];
+ $j++;
+ }
+ elseif ($list1[$i]['type'] == $list2[0]['type'])
+ { // Worth doing a compare - fields are same type
+ // echo $i.': compare - '.$list1[$i]['name'].', '.$list2[0]['name'].'
';
+ if (strcasecmp($list1[$i]['name'],$list2[0]['name']) != 0)
+ { // Names differ, so need to add or subtract a field.
+ // echo $i.': names differ - '.$list1[$i]['name'].', '.$list2[0]['name'].'
';
+ if ($stop_on_error) { return FALSE; }
+ $found = FALSE;
+ for ($k = $i+1; $k < count($list1); $k++)
+ {
+ // echo "Compare ".$list1[$k]['name'].' with '.$list2[0]['name'];
+ if (strcasecmp($list1[$k]['name'],$list2[0]['name']) == 0)
+ { // Field in list2 found later in list1; do nothing
+ // echo " - match
";
+ $found = TRUE;
+ break;
+ }
+ // echo " - no match
";
+ }
+
+ if (!$found)
+ { // Field in existing DB no longer required
+ $error_list[] = 'Obsolete field: '.$list2[0]['name'];
+ $change_list[] = 'DROP '.($list2[0]['type'] == 'field' ? '' : 'INDEX ').$list2[0]['name'];
+ array_shift($list2);
+ continue;
+ }
+
+ $found = FALSE;
+ for ($k = 0; $k < count($list2); $k++)
+ {
+ // echo "Compare ".$list1[$i]['name'].' with '.$list2[$k]['name'];
+ if (strcasecmp($list1[$i]['name'],$list2[$k]['name']) == 0)
+ { // Field found; we need to move it up
+ // echo " - match
";
+ $found = TRUE;
+ break;
+ }
+ // echo " - no match
";
+ }
+ if ($found)
+ {
+ $error_list[] = 'Field out of position: '.$list2[$k]['name'];
+ $change_list[] = 'MODIFY '.$this->make_def($list1[$i]).(count($created_list) ? ' AFTER '.$created_list[count($created_list)-1] : ' FIRST');
+ array_splice($list2,$k,1); // Finished with this element - delete it, and renumber the keys
+ $created_list[$j] = $list1[$i]['name'];
+ $j++;
+ // The above also amends any parameters as necessary
+ }
+ else
+ { // Need to insert a field
+ $error_list[] = 'Missing field: '.$list1[$i]['name'].' (found: '.$list2[0]['type'].' '.$list2[0]['name'].')';
+ switch ($list1[$i]['type'])
+ {
+ case 'key' :
+ case 'ukey' :
+ case 'pkey' : // Require a key
+ $change_list[] = 'ADD '.$this->make_def($list1[$i]);
+ $error_list[] = 'Missing index: '.$list1[$i]['name'];
+ $created_list[$j] = $list1[$i]['name'];
+ $j++;
+ break;
+
+ case 'field' :
+ $change_list[] = 'ADD '.$this->make_def($list1[$i]).(count($created_list) ? ' AFTER '.$created_list[count($created_list)-1] : ' FIRST');
+ $error_list[] = 'Missing field: '.$list1[$i]['name'].' (found: '.$list2[0]['type'].' '.$list2[0]['name'].')';
+ $created_list[$j] = $list1[$i]['name'];
+ $j++;
+ break;
+ }
+ }
+ }
+ else
+ { // Field/index is present as required; may be changes though
+ // Any difference and we need to update the table
+ // echo $i.': name match - '.$list1[$i]['name'].'
';
+ foreach ($list1[$i] as $fi => $v)
+ {
+ $t = $list2[0][$fi];
+ if (stripos($v,'varchar') !== FALSE) { $v = substr($v,3); } // Treat char, varchar the same
+ if (stripos($t,'varchar') !== FALSE) { $t = substr($t,3); } // Treat char, varchar the same
+ if (strcasecmp($t , $v) !== 0)
+ {
+ if ($stop_on_error) { return FALSE; }
+ $error_list[] = 'Incorrect definition: '.$fi.' = '.$v;
+ $change_list[] = 'MODIFY '.$this->make_def($list1[$i]);
+ break;
+ }
+ }
+ array_shift($list2);
+ $created_list[$j] = $list1[$i]['name'];
+ $j++;
+ }
}
else
+ { // Field type has changed. We know fields come before indexes. So something's missing
+ // echo $i.': types differ - '.$list1[$i]['type'].' '.$list1[$i]['name'].', '.$list2[$k]['type'].' '.$list2[$k]['name'].'
';
+ if ($stop_on_error) { return FALSE; }
+ switch ($list1[$i]['type'])
+ {
+ case 'key' :
+ case 'ukey' :
+ case 'pkey' : // Require a key - got a field, or a key of a different type
+ while ((count($list2)>0) && ($list2[0]['type'] == 'field'))
+ {
+ $error_list[] = 'Extra field: '.$list2[0]['name'];
+ $change_list[] = 'DROP '.$list2[0]['name'];
+ array_shift($list2);
+ }
+ if ((count($list2) == 0) || ($list1[$i]['type'] != $list2[0]['type']))
+ { // need to add a key
+ $change_list[] = 'ADD '.$this->make_def($list1[$i]);
+ $error_list[] = 'Missing index: '.$list1[$i]['name'];
+ $created_list[$j] = $list1[$i]['name'];
+ $j++;
+ }
+ break;
+
+ case 'field' : // Require a field - got a key. so add a field at the end
+ $error_list[] = 'Missing field: '.$list1[$i]['name'].' (found: '.$list2[0]['type'].' '.$list2[0]['name'].')';
+ $change_list[] = 'ADD '.$this->make_def($list1[$i]);
+ break;
+
+ default :
+ $error_list[] = 'Unknown field type: '.$list1[$i]['type'];
+ $change_list[] = ''; // Null entry to keep them in step
+ }
+ } // End - missing or extra field
+
+ $i++; // On to next field
+ }
+ if (count($list2))
+ { // Surplus fields in actual table
+ // Echo count($list2)." fields at end to delete
";
+ foreach ($list2 as $f)
{
- echo "Unrecognised word after UNIQUE in definition {$i}: ".$fd[1]."
";
- }
- break;
- case 'KEY' :
- $defs['type'] = 'key';
- $defs['name'] = $fd[1];
- if (isset($fd[2])) $defs['keyfield'] = $fd[2]; else $defs['keyfield'] = '['.$fd[1].']';
- break;
- default : // Must be a DB field name
- $defs['type'] = 'field';
- $defs['name'] = $fd[0];
- $defs['fieldtype'] = $fd[1];
- $i = 2; // First unused field
- if ((strpos($fd[1],'int') === 0) || (strpos($fd[1],'tinyint') === 0) || (strpos($fd[1],'smallint') === 0) || (strpos($fd[1],'bigint') === 0))
- {
- if (isset($fd[2]) && (strtoupper($fd[2]) == 'UNSIGNED'))
- {
- $defs['vartype'] = $fd[2];
- $i++;
- }
- }
- while ($i < count($fd))
- {
- switch(strtoupper($fd[$i]))
- {
- case 'NOT' :
- if (isset($fd[$i+1]) && strtoupper($fd[$i+1]) == 'NULL')
- {
- $i++;
- $defs['nulltype'] = 'NOT NULL';
- }
- else
- { // Syntax error
- echo "Unrecognised word in definition {$i} after 'NOT': ".$fd[$i+1]."
";
- }
- break;
- case 'DEFAULT' :
- if (isset($fd[$i+1]))
- {
- $i++;
- $defs['default'] = $fd[$i];
- }
- break;
- case 'COLLATE' :
- $i++; // Just skip over - we ignore collation
- break;
- case 'AUTO_INCREMENT' :
- $defs['autoinc'] = TRUE;
- break;
- default :
- echo "Unknown definition {$i}: ".$fd[$i]."
";
- }
- $i++;
+ switch ($f['type'])
+ {
+ case 'key' :
+ case 'ukey' :
+ case 'pkey' : // Require a key - got a field
+ $error_list[] = 'Extra index: '.$list2[0]['name'];
+ $change_list[] = 'DROP INDEX '.$list2[0]['name'];
+ break;
+ case 'field' :
+ $error_list[] = 'Extra field: '.$list2[0]['name'];
+ $change_list[] = 'DROP '.$list2[0]['name'];
+ break;
+ }
}
}
- if (count($defs) > 1) $ans[] = $defs; else echo "Partial definition
";
- }
+ if ($stop_on_error) return TRUE; // If doing a simple comparison and we get to here, all matches
+ return array($error_list, $change_list);
}
- if (!count($ans)) return FALSE;
- return $ans;
- }
-
-
- // Utility routine - given our array-based definition, create a string MySQL field definition
- function make_def($list)
- {
- switch ($list['type'])
+ function make_changes_list($result)
{
- case 'key' :
- return 'KEY '.$list['name'].' ('.str_replace(array('(',')'),'',$list['keyfield']).')';
- case 'ukey' :
- return 'UNIQUE KEY '.$list['name'].' ('.$list['name'].')';
- case 'pkey' :
- return 'PRIMARY KEY ('.$list['name'].')';
- case 'field' : // Require a field - got a key. so add a field at the end
- $def = $list['name'];
- if (isset($list['fieldtype'])) $def .= ' '.$list['fieldtype'];
- if (isset($list['vartype'])) $def .= ' '.$list['vartype'];
- if (isset($list['nulltype'])) $def .= ' '.$list['nulltype'];
- if (isset($list['default'])) $def .= ' default '.$list['default'];
- if (varsettrue($list['autoinc'])) $def .= ' auto_increment';
- return $def;
+ if (!is_array($result)) { return "Not an array
"; }
+ $text = "
";
+ for ($i = 0; $i < count($result[0]); $i++)
+ {
+ $text .= "{$result[0][$i]} | ";
+ $text .= "{$result[1][$i]} | ";
+ $text .= "
\n";
+ }
+ $text .= "
";
+ return $text;
}
- return "Cannot generate definition for: ".$list['type'].' '.$list['name'];
- }
-
- // Compare two field/index lists as generated by parse_field_defs
- // If $stop_on_error is TRUE, returns TRUE if the same, false if different
- // Return a text list of differences, plus an array of MySQL queries to fix
- // List1 is the reference, List 2 is the actual
- // This version looks ahead on a failed match, and moves a field up in the table if already defined - should retain as much as possible
- function compare_field_lists($list1, $list2, $stop_on_error=FALSE)
- {
- $i = 0; // Counts records in list1 (required format)
- $j = 0; // Counts records in $created_list (our 'table so far' list)
- $error_list = array(); // Free text list of differences
- $change_list = array(); // MySQL statements to implement changes
- $created_list = array(); // List of field defs that we build up (just names)
- while ($i < count($list1))
+
+ // Return a table of info from the output of get_table_def
+ function make_table_list($result)
{
- if (count($list2) == 0)
- { // Missing field at end
- if ($stop_on_error) return FALSE;
- $error_list[] = 'Missing field at end: '.$list1[$i]['name'];
- $change_list[] = 'ADD '.$this->make_def($list1[$i]);
- $created_list[$j] = $list1[$i]['name'];
- $j++;
- }
- elseif ($list1[$i]['type'] == $list2[0]['type'])
- { // Worth doing a compare - fields are same type
-// echo $i.': compare - '.$list1[$i]['name'].', '.$list2[0]['name'].'
';
- if (strcasecmp($list1[$i]['name'],$list2[0]['name']) != 0)
- { // Names differ, so need to add or subtract a field.
-// echo $i.': names differ - '.$list1[$i]['name'].', '.$list2[0]['name'].'
';
- if ($stop_on_error) return FALSE;
- $found = FALSE;
- for ($k = $i+1; $k < count($list1); $k++)
- {
-// echo "Compare ".$list1[$k]['name'].' with '.$list2[0]['name'];
- if (strcasecmp($list1[$k]['name'],$list2[0]['name']) == 0)
- { // Field in list2 found later in list1; do nothing
-// echo " - match
";
- $found = TRUE;
- break;
- }
-// echo " - no match
";
- }
+ if (!is_array($result)) { return "Not an array
"; }
+ $text = "";
+ for ($i = 0; $i < count($result); $i++)
+ {
+ $text .= "{$result[$i][0]} | ";
+ $text .= "{$result[$i][1]} | ";
+ $text .= "{$result[$i][2]} | ";
+ $text .= "{$result[$i][3]} |
\n";
+ }
+ $text .= "
";
+ return $text;
+ }
- if (!$found)
- { // Field in existing DB no longer required
- $error_list[] = 'Obsolete field: '.$list2[0]['name'];
- $change_list[] = 'DROP '.($list2[0]['type'] == 'field' ? '' : 'INDEX ').$list2[0]['name'];
- array_shift($list2);
- continue;
- }
- $found = FALSE;
- for ($k = 0; $k < count($list2); $k++)
- {
-// echo "Compare ".$list1[$i]['name'].' with '.$list2[$k]['name'];
- if (strcasecmp($list1[$i]['name'],$list2[$k]['name']) == 0)
- { // Field found; we need to move it up
-// echo " - match
";
- $found = TRUE;
- break;
- }
-// echo " - no match
";
- }
- if ($found)
- {
- $error_list[] = 'Field out of position: '.$list2[$k]['name'];
- $change_list[] = 'MODIFY '.$this->make_def($list1[$i]).(count($created_list) ? ' AFTER '.$created_list[count($created_list)-1] : ' FIRST');
- array_splice($list2,$k,1); // Finished with this element - delete it, and renumber the keys
- $created_list[$j] = $list1[$i]['name'];
- $j++;
- // The above also amends any parameters as necessary
- }
- else
- { // Need to insert a field
- $error_list[] = 'Missing field: '.$list1[$i]['name'].' (found: '.$list2[0]['type'].' '.$list2[0]['name'].')';
- switch ($list1[$i]['type'])
+ // Return a table of info from the output of parse_field_defs()
+ function make_field_list($fields)
+ {
+ $text = "";
+ foreach ($fields as $f)
+ {
+ switch($f['type'])
{
- case 'key' :
- case 'ukey' :
- case 'pkey' : // Require a key
- $change_list[] = 'ADD '.$this->make_def($list1[$i]);
- $error_list[] = 'Missing index: '.$list1[$i]['name'];
- $created_list[$j] = $list1[$i]['name'];
- $j++;
+ case 'pkey' :
+ $text .= "PRIMARY KEY | {$f['name']} | |
";
break;
-
- case 'field' :
- $change_list[] = 'ADD '.$this->make_def($list1[$i]).(count($created_list) ? ' AFTER '.$created_list[count($created_list)-1] : ' FIRST');
- $error_list[] = 'Missing field: '.$list1[$i]['name'].' (found: '.$list2[0]['type'].' '.$list2[0]['name'].')';
- $created_list[$j] = $list1[$i]['name'];
- $j++;
+ case 'ukey' :
+ $text .= "UNIQUE KEY | {$f['name']} | {$f['keyfield']} |
";
break;
+ case 'key' :
+ $text .= "KEY | {$f['name']} | {$f['keyfield']} |
";
+ break;
+ case 'field' :
+ $text .= "FIELD | {$f['name']} | {$f['fieldtype']}";
+ if (isset($f['vartype'])) { $text .= " ".$f['vartype']; }
+ $text .= " | ";
+ if (isset($f['nulltype']))
+ {
+ $text .= "{$f['nulltype']} | ";
+ }
+ else
+ {
+ $text .= " | ";
+ }
+ if (isset($f['default']))
+ {
+ $text .= "default {$f['default']} | ";
+ }
+ elseif (isset($f['autoinc']))
+ {
+ $text .= "AUTO_INCREMENT | ";
+ }
+ else
+ {
+ $text .= " | ";
+ }
+ $text .= "
";
+ break;
+ default :
+ $text .= "!!Unknown!! | {$f['type']} | |
";
}
- }
+ }
+ $text .= "
--Ends--
";
+ return $text;
+ }
+
+
+
+
+ //--------------------------------------------------
+ // Update a table to required structure
+ //--------------------------------------------------
+
+ // $newStructure is an array element as returned from get_table_def()
+ // If $mlUpdate is TRUE, applies same query to all tables of same language
+ // Return TRUE on success.
+ // Return text string if $justCheck is TRUE and changes needed
+ // Return text string on most failures
+ // Return FALSE on certain failures (generally indicative of code/system problems)
+ function update_table_structure($newStructure, $justCheck=FALSE, $makeNewifNotExist = TRUE, $mlUpdate = FALSE)
+ {
+ global $sql;
+ // Pull out table name
+ $tableName = $newStructure[1];
+ if (!$sql->db_Table_exists($tableName))
+ {
+ if ($makeNewifNotExist === FALSE) { return 'Table doesn\'t exist'; }
+ if ($sql->db_Select_gen($newStructure[0])) { return TRUE; }
+ return 'Error creating new table: '.$tableName;
+ }
+ $reqFields = $this->parse_field_defs($newStructure[2]); // Required field definitions
+ if (E107_DBG_FILLIN8) { echo "Required table structure:
".$this->make_field_list($reqFields); }
+
+ if ((($actualDefs = $this->get_current_table($tableName)) === FALSE) || !is_array($actualDefs)) // Get actual table definition (Adds current default prefix)
+ {
+ return "Couldn't get table structure: {$tableName}
";
}
else
- { // Field/index is present as required; may be changes though
- // Any difference and we need to update the table
-// echo $i.': name match - '.$list1[$i]['name'].'
';
- foreach ($list1[$i] as $fi => $v)
- {
- $t = $list2[0][$fi];
- if (stripos($v,'varchar') !== FALSE) $v = substr($v,3); // Treat char, varchar the same
- if (stripos($t,'varchar') !== FALSE) $t = substr($t,3); // Treat char, varchar the same
- if (strcasecmp($t , $v) !== 0)
- {
- if ($stop_on_error) return FALSE;
- $error_list[] = 'Incorrect definition: '.$fi.' = '.$v;
- $change_list[] = 'MODIFY '.$this->make_def($list1[$i]);
- break;
- }
- }
- array_shift($list2);
- $created_list[$j] = $list1[$i]['name'];
- $j++;
- }
- }
- else
- { // Field type has changed. We know fields come before indexes. So something's missing
-// echo $i.': types differ - '.$list1[$i]['type'].' '.$list1[$i]['name'].', '.$list2[$k]['type'].' '.$list2[$k]['name'].'
';
- if ($stop_on_error) return FALSE;
- switch ($list1[$i]['type'])
{
- case 'key' :
- case 'ukey' :
- case 'pkey' : // Require a key - got a field, or a key of a different type
- while ((count($list2)>0) && ($list2[0]['type'] == 'field'))
- {
- $error_list[] = 'Extra field: '.$list2[0]['name'];
- $change_list[] = 'DROP '.$list2[0]['name'];
- array_shift($list2);
- }
- if ((count($list2) == 0) || ($list1[$i]['type'] != $list2[0]['type']))
- { // need to add a key
- $change_list[] = 'ADD '.$this->make_def($list1[$i]);
- $error_list[] = 'Missing index: '.$list1[$i]['name'];
- $created_list[$j] = $list1[$i]['name'];
- $j++;
- }
- break;
+ // echo $db_parser->make_table_list($actual_defs);
+ $actualFields = $this->parse_field_defs($actualDefs[0][2]); // Split into field definitions
+ if (E107_DBG_FILLIN8) { echo 'Actual table structure:
'.$this->make_field_list($actualFields); }
- case 'field' : // Require a field - got a key. so add a field at the end
- $error_list[] = 'Missing field: '.$list1[$i]['name'].' (found: '.$list2[0]['type'].' '.$list2[0]['name'].')';
- $change_list[] = 'ADD '.$this->make_def($list1[$i]);
- break;
-
- default :
- $error_list[] = 'Unknown field type: '.$list1[$i]['type'];
- $change_list[] = ''; // Null entry to keep them in step
- }
- } // End - missing or extra field
-
- $i++; // On to next field
+ $diffs = $this->compare_field_lists($reqFields,$actualFields); // Work out any differences
+ if (count($diffs[0]))
+ { // Changes needed
+ if ($justCheck) { return 'Field changes rqd; table: '.$tableName.'
'; }
+ // Do the changes here
+ if (E107_DBG_FILLIN8) { echo "List of changes found:
".$this->make_changes_list($diffs); }
+ $qry = 'ALTER TABLE '.MPREFIX.$tableName.' '.implode(', ',$diffs[1]);
+ if (E107_DBG_FILLIN8) { echo 'Update Query used: '.$qry.'
'; }
+ if ($mlUpdate)
+ {
+ $ret = $sql->db_Query_all($qry); // Returns TRUE = success, FALSE = fail
+ }
+ else
+ {
+ $ret = $sql->db_Select_gen($qry);
+ }
+ if ($ret === FALSE)
+ {
+ return $sql->dbError() ;
+ }
+ }
+ return TRUE; // Success even if no changes required
+ }
+ return FALSE;
}
- if (count($list2))
- { // Surplus fields in actual table
-// Echo count($list2)." fields at end to delete
";
- foreach ($list2 as $f)
- {
- switch ($f['type'])
+
+
+ function createTable($pathToSqlFile='', $tableName='', $addPrefix=true, $renameTable='')
+ {
+ $e107 = e107::getInstance();
+ $tmp = $this->get_table_def($tableName, $pathToSqlFile);
+ $createText = $tmp[0][0];
+ $newTableName = ($renameTable ? $renameTable : $tableName);
+ if($addPrefix) { $newTableName = MPREFIX.$newTableName; }
+ if($newTableName != $tableName)
{
- case 'key' :
- case 'ukey' :
- case 'pkey' : // Require a key - got a field
- $error_list[] = 'Extra index: '.$list2[0]['name'];
- $change_list[] = 'DROP INDEX '.$list2[0]['name'];
- break;
- case 'field' :
- $error_list[] = 'Extra field: '.$list2[0]['name'];
- $change_list[] = 'DROP '.$list2[0]['name'];
- break;
+ $createText = preg_replace('#create +table +(\w*?) +#i', 'CREATE TABLE '.$newTableName.' ', $createText);
}
- }
+ return $e107->sql->db_Select_gen($createText);
}
- if ($stop_on_error) return TRUE; // If doing a simple comparison and we get to here, all matches
- return array($error_list, $change_list);
- }
- function make_changes_list($result)
- {
- if (!is_array($result)) return "Not an array
";
- $text = "";
- for ($i = 0; $i < count($result[0]); $i++)
- {
- $text .= "{$result[0][$i]} | ";
- $text .= "{$result[1][$i]} | ";
- $text .= "
\n";
- }
- $text .= "
";
- return $text;
- }
-
-
- // Return a table of info from the output of get_table_def
- function make_table_list($result)
- {
- if (!is_array($result)) return "Not an array
";
- $text = "";
- for ($i = 0; $i < count($result); $i++)
- {
- $text .= "{$result[$i][0]} | ";
- $text .= "{$result[$i][1]} | ";
- $text .= "{$result[$i][2]} | ";
- $text .= "{$result[$i][3]} |
\n";
- }
- $text .= "
";
- return $text;
- }
-
-
- // Return a table of info from the output of parse_field_defs()
- function make_field_list($fields)
- {
- $text = "";
- foreach ($fields as $f)
- {
- switch($f['type'])
- {
- case 'pkey' :
- $text .= "PRIMARY KEY | {$f['name']} | |
";
- break;
- case 'ukey' :
- $text .= "UNIQUE KEY | {$f['name']} | {$f['keyfield']} |
";
- break;
- case 'key' :
- $text .= "KEY | {$f['name']} | {$f['keyfield']} |
";
- break;
- case 'field' :
- $text .= "FIELD | {$f['name']} | {$f['fieldtype']}";
- if (isset($f['vartype'])) $text .= " ".$f['vartype'];
- $text .= " | ";
- if (isset($f['nulltype'])) $text .= "{$f['nulltype']} | "; else $text .= " | ";
- if (isset($f['default'])) $text .= "default {$f['default']} | "; elseif
- (isset($f['autoinc'])) $text .= "AUTO_INCREMENT | "; else $text .= " | ";
- $text .= "
";
- break;
- default :
- $text .= "!!Unknown!! | {$f['type']} | |
";
- }
- }
- $text .= "
--Ends--
";
- return $text;
- }
-
-
-
-
- //--------------------------------------------------
- // Update a table to required structure
- //--------------------------------------------------
-
- // $newStructure is an array element as returned from get_table_def()
- // If $mlUpdate is TRUE, applies same query to all tables of same language
- // Return TRUE on success.
- // Return text string if $justCheck is TRUE and changes needed
- // Return text string on most failures
- // Return FALSE on certain failures (generally indicative of code/system problems)
- function update_table_structure($newStructure, $justCheck=FALSE, $makeNewifNotExist = TRUE, $mlUpdate = FALSE)
- {
- global $sql;
- // Pull out table name
- $tableName = $newStructure[1];
- if (!$sql->db_Table_exists($tableName))
- {
- if ($makeNewifNotExist === FALSE) return 'Table doesn\'t exist';
- if ($sql->db_Select_gen($newStructure[0])) return TRUE;
- return 'Error creating new table: '.$tableName;
- }
- $reqFields = $this->parse_field_defs($newStructure[2]); // Required field definitions
- if (E107_DBG_FILLIN8) echo "Required table structure:
".$this->make_field_list($reqFields);
-
- if ((($actualDefs = $this->get_current_table($tableName)) === FALSE) || !is_array($actualDefs)) // Get actual table definition (Adds current default prefix)
- {
- return "Couldn't get table structure: {$tableName}
";
- }
- else
- {
-// echo $db_parser->make_table_list($actual_defs);
- $actualFields = $this->parse_field_defs($actualDefs[0][2]); // Split into field definitions
- if (E107_DBG_FILLIN8) echo 'Actual table structure:
'.$this->make_field_list($actualFields);
-
- $diffs = $this->compare_field_lists($reqFields,$actualFields); // Work out any differences
- if (count($diffs[0]))
- { // Changes needed
- if ($justCheck) return 'Field changes rqd; table: '.$tableName.'
';
- // Do the changes here
- if (E107_DBG_FILLIN8) echo "List of changes found:
".$this->make_changes_list($diffs);
- $qry = 'ALTER TABLE '.MPREFIX.$tableName.' '.implode(', ',$diffs[1]);
- if (E107_DBG_FILLIN8) echo 'Update Query used: '.$qry.'
';
- if ($mlUpdate)
- {
- $ret = $sql->db_Query_all($qry); // Returns TRUE = success, FALSE = fail
- }
- else
- {
- $ret = $sql->db_Select_gen($qry);
- }
- if ($ret === FALSE)
- {
- return $sql->dbError() ;
- }
- }
- return TRUE; // Success even if no changes required
- }
- return FALSE;
- }
}
diff --git a/e107_plugins/forum/forum_update.php b/e107_plugins/forum/forum_update.php
index 8cd0da74c..1581342eb 100644
--- a/e107_plugins/forum/forum_update.php
+++ b/e107_plugins/forum/forum_update.php
@@ -11,8 +11,8 @@
| GNU General Public License (http://gnu.org).
|
| $Source: /cvs_backup/e107_0.8/e107_plugins/forum/forum_update.php,v $
-| $Revision: 1.4 $
-| $Date: 2008-12-19 21:56:37 $
+| $Revision: 1.5 $
+| $Date: 2008-12-20 00:55:29 $
| $Author: mcfly_e107 $
+----------------------------------------------------------------------------+
*/
@@ -67,10 +67,9 @@ $stepParms = (isset($stepParms) ? $stepParms : '');
if(function_exists('step'.$currentStep))
{
- call_user_func('step'.$currentStep, $stepParms);
+ $result = call_user_func('step'.$currentStep, $stepParms);
}
-
require(e_ADMIN.'footer.php');
exit;
@@ -91,7 +90,7 @@ function step1()
";
foreach($f->error['attach'] as $e)
{
- $errorText .= '** '.$e.'
';
+ $text .= '** '.$e.'
';
}
$text .= "
@@ -131,19 +130,105 @@ function step2()
return;
}
- if($sql = file_get_contents(e_PLUGIN.'forum/forum_sql.php'))
+ require_once(e_HANDLER.'db_table_admin_class.php');
+ $db = new db_table_admin;
+
+ $tabList = array('forum' => 'forum_new', 'forum_thread' => '', 'forum_post' => '', 'forum_track' => '');
+ $ret = '';
+ $failed = false;
+ $text = '';
+ foreach($tabList as $name => $rename)
{
- echo $sql;
+ $text .= 'Creating table '.($rename ? $rename : $name).' -> ';
+ $result = $db->createTable(e_PLUGIN.'forum/forum_sql.php', $name, true, $rename);
+ if($result)
+ {
+ $text .= 'Success
';
+ }
+ else
+ {
+ $text .= 'Failed
';
+ $failed = true;
+ }
+ }
+ if($failed)
+ {
+ $text .= "
+
+ Creation of table(s) failed. You can not continue until these are create successfully!
+ ";
}
else
{
- echo 'failed';
+ $text .= "
+
+
+ ";
}
+ $e107->ns->tablerender('Step 2: Forum table creation', $text);
+}
+function step3()
+{
+ $e107 = e107::getInstance();
+ $stepCaption = 'Step 3: Extended user field creation';
+ if(!isset($_POST['create_extended']))
+ {
+ $text = "
+ This step will create the new extended user fields required for the new forum code:
+ * user_plugin_forum_posts (to track number of posts for each user)
+ * user_plugin_forum_viewed (to track threads viewed by each user
+
+
+ ";
+ $e107->ns->tablerender($stepCaption, $text);
+ return;
+ }
+ require_once(e_HANDLER.'user_extended_class.php');
+ $ue = new e107_user_extended;
+ $fieldList = array(
+ 'plugin_forum_posts' => EUF_INTEGER,
+ 'plugin_forum_viewed' => EUF_TEXTAREA
+ );
+ $failed = false;
+ foreach($fieldList as $fieldName => $fieldType)
+ {
+ $text .= 'Creating extended user field user_'.$fieldName.' -> ';
+ $result = $ue->user_extended_add_system($fieldName, $fieldType);
+ if($result)
+ {
+ $text .= 'Success
';
+ }
+ else
+ {
+ $text .= 'Failed
';
+ $failed = true;
+ }
+ }
+ if($failed)
+ {
+ $text .= '
+
+ Creation of extended field(s) failed. You can not continue until these are create successfully!
+ ';
+ }
+ else
+ {
+ $text .= "
+
+
+ ";
+ }
+ $e107->ns->tablerender($stepCaption, $text);
}
-//print_a($f->error);
class forumUpgrade
{
@@ -156,7 +241,6 @@ class forumUpgrade
$this->getUpdateInfo();
}
-
function checkAttachmentDirs()
{
$dirs = array(