aboutsummaryrefslogtreecommitdiffstats
path: root/phpBB/install/database_update.php
diff options
context:
space:
mode:
Diffstat (limited to 'phpBB/install/database_update.php')
-rw-r--r--phpBB/install/database_update.php809
1 files changed, 761 insertions, 48 deletions
diff --git a/phpBB/install/database_update.php b/phpBB/install/database_update.php
index c66ac859cf..41983400fc 100644
--- a/phpBB/install/database_update.php
+++ b/phpBB/install/database_update.php
@@ -8,11 +8,14 @@
*
*/
-$updates_to_version = '3.0.5';
+$updates_to_version = '3.0.6-RC1';
// Enter any version to update from to test updates. The version within the db will not be updated.
$debug_from_version = false;
+// Which oldest version does this updater support?
+$oldest_from_version = '3.0.0';
+
// Return if we "just include it" to find out for which version the database update is responsible for
if (defined('IN_PHPBB') && defined('IN_INSTALL'))
{
@@ -219,6 +222,33 @@ if (empty($config['dbms_version']))
set_config('dbms_version', $db->sql_server_info(true));
}
+// Firebird update from Firebord 2.0 to 2.1+ required?
+if ($db->sql_layer == 'firebird')
+{
+ // We do not trust any PHP5 function enabled, we will simply test for a function new in 2.1
+ $db->sql_return_on_error(true);
+
+ $sql = 'SELECT 1 FROM RDB$DATABASE
+ WHERE BIN_AND(10, 1) = 0';
+ $result = $db->sql_query($sql);
+
+ if (!$result || $db->sql_error_triggered)
+ {
+ echo '<br /><br />';
+ echo '<h1>' . $lang['ERROR'] . '</h1><br />';
+
+ echo '<p>' . $lang['FIREBIRD_DBMS_UPDATE_REQUIRED'] . '</p>';
+
+ _print_footer();
+
+ exit_handler();
+ exit;
+ }
+
+ $db->sql_freeresult($result);
+ $db->sql_return_on_error(false);
+}
+
// MySQL update from MySQL 3.x/4.x to > 4.1.x required?
if ($db->sql_layer == 'mysql' || $db->sql_layer == 'mysql4' || $db->sql_layer == 'mysqli')
{
@@ -246,28 +276,25 @@ if ($db->sql_layer == 'mysql' || $db->sql_layer == 'mysql4' || $db->sql_layer ==
echo '<h1>' . $lang['ERROR'] . '</h1><br />';
echo '<p>' . sprintf($lang['MYSQL_SCHEMA_UPDATE_REQUIRED'], $config['dbms_version'], $db->sql_server_info(true)) . '</p>';
-?>
- </div>
- </div>
- <span class="corners-bottom"><span></span></span>
- </div>
- </div>
- </div>
-
- <div id="page-footer">
- Powered by <a href="http://www.phpbb.com/">phpBB</a> &copy; 2000, 2002, 2005, 2007 phpBB Group
- </div>
-</div>
-</body>
-</html>
-<?php
+ _print_footer();
exit_handler();
exit;
}
}
+// Now check if the user wants to update from a version we no longer support updates from
+if (version_compare($current_version, $oldest_from_version, '<'))
+{
+ echo '<br /><br /><h1>' . $lang['ERROR'] . '</h1><br />';
+ echo '<p>' . sprintf($lang['DB_UPDATE_NOT_SUPPORTED'], $oldest_from_version, $current_version) . '</p>';
+
+ _print_footer();
+ exit_handler();
+ exit;
+}
+
// If the latest version and the current version are 'unequal', we will update the version_update_from, else we do not update anything.
if ($inline_update)
{
@@ -452,8 +479,21 @@ add_log('admin', 'LOG_UPDATE_DATABASE', $orig_version, $updates_to_version);
// Now we purge the session table as well as all cache files
$cache->purge();
-?>
+_print_footer();
+
+garbage_collection();
+
+if (function_exists('exit_handler'))
+{
+ exit_handler();
+}
+/**
+* Print out footer
+*/
+function _print_footer()
+{
+ echo <<<EOF
</div>
</div>
<span class="corners-bottom"><span></span></span>
@@ -468,14 +508,7 @@ $cache->purge();
</body>
</html>
-
-<?php
-
-garbage_collection();
-
-if (function_exists('exit_handler'))
-{
- exit_handler();
+EOF;
}
/**
@@ -497,7 +530,7 @@ function _sql($sql, &$errored, &$error_ary, $echo_dot = true)
{
$errored = true;
$error_ary['sql'][] = $db->sql_error_sql;
- $error_ary['error_code'][] = $db->_sql_error();
+ $error_ary['error_code'][] = $db->sql_error_returned;
}
$db->sql_return_on_error(false);
@@ -542,6 +575,130 @@ function _write_result($no_updates, $errored, $error_ary)
}
}
+function _add_modules($modules_to_install)
+{
+ global $phpbb_root_path, $phpEx, $db;
+
+ include_once($phpbb_root_path . 'includes/acp/acp_modules.' . $phpEx);
+
+ $_module = new acp_modules();
+
+ foreach ($modules_to_install as $module_mode => $module_data)
+ {
+ $_module->module_class = $module_data['class'];
+
+ // Determine parent id first
+ $sql = 'SELECT module_id
+ FROM ' . MODULES_TABLE . "
+ WHERE module_class = '" . $db->sql_escape($module_data['class']) . "'
+ AND module_langname = '" . $db->sql_escape($module_data['cat']) . "'
+ AND module_mode = ''
+ AND module_basename = ''";
+ $result = $db->sql_query($sql);
+
+ // There may be more than one categories with the same name
+ $categories = array();
+ while ($row = $db->sql_fetchrow($result))
+ {
+ $categories[] = (int) $row['module_id'];
+ }
+ $db->sql_freeresult($result);
+
+ if (!sizeof($categories))
+ {
+ continue;
+ }
+
+ // Add the module to all categories found
+ foreach ($categories as $parent_id)
+ {
+ // Check if the module already exists
+ $sql = 'SELECT *
+ FROM ' . MODULES_TABLE . "
+ WHERE module_basename = '" . $db->sql_escape($module_data['base']) . "'
+ AND module_class = '" . $db->sql_escape($module_data['class']) . "'
+ AND module_langname = '" . $db->sql_escape($module_data['title']) . "'
+ AND module_mode = '" . $db->sql_escape($module_mode) . "'
+ AND module_auth = '" . $db->sql_escape($module_data['auth']) . "'
+ AND parent_id = {$parent_id}";
+ $result = $db->sql_query($sql);
+ $row = $db->sql_fetchrow($result);
+ $db->sql_freeresult($result);
+
+ // If it exists, we simply continue with the next category
+ if ($row)
+ {
+ continue;
+ }
+
+ // Build the module sql row
+ $module_row = array(
+ 'module_basename' => $module_data['base'],
+ 'module_enabled' => (isset($module_data['enabled'])) ? (int) $module_data['enabled'] : 1,
+ 'module_display' => (isset($module_data['display'])) ? (int) $module_data['display'] : 1,
+ 'parent_id' => $parent_id,
+ 'module_class' => $module_data['class'],
+ 'module_langname' => $module_data['title'],
+ 'module_mode' => $module_mode,
+ 'module_auth' => $module_data['auth'],
+ );
+
+ $_module->update_module_data($module_row, true);
+
+ // Ok, do we need to re-order the module, move it up or down?
+ if (!isset($module_data['after']))
+ {
+ continue;
+ }
+
+ $after_mode = $module_data['after'][0];
+ $after_langname = $module_data['after'][1];
+
+ // First of all, get the module id for the module this one has to be placed after
+ $sql = 'SELECT left_id
+ FROM ' . MODULES_TABLE . "
+ WHERE module_class = '" . $db->sql_escape($module_data['class']) . "'
+ AND module_basename = '" . $db->sql_escape($module_data['base']) . "'
+ AND module_langname = '" . $db->sql_escape($after_langname) . "'
+ AND module_mode = '" . $db->sql_escape($after_mode) . "'
+ AND parent_id = '{$parent_id}'";
+ $result = $db->sql_query($sql);
+ $first_left_id = (int) $db->sql_fetchfield('left_id');
+ $db->sql_freeresult($result);
+
+ if (!$first_left_id)
+ {
+ continue;
+ }
+
+ // Ok, count the number of modules between $after_mode and the added module
+ $sql = 'SELECT COUNT(module_id) as num_modules
+ FROM ' . MODULES_TABLE . "
+ WHERE module_class = '" . $db->sql_escape($module_data['class']) . "'
+ AND parent_id = {$parent_id}
+ AND left_id BETWEEN {$first_left_id} AND {$module_row['left_id']}
+ GROUP BY left_id
+ ORDER BY left_id";
+ $result = $db->sql_query($sql);
+ $steps = (int) $db->sql_fetchfield('num_modules');
+ $db->sql_freeresult($result);
+
+ // We need to substract 2
+ $steps -= 2;
+
+ if ($steps <= 0)
+ {
+ continue;
+ }
+
+ // Ok, move module up $num_modules times. ;)
+ $_module->move_module_by($module_row, 'move_up', $steps);
+ }
+ }
+
+ $_module->remove_cache_file();
+}
+
/****************************************************************************
* ADD YOUR DATABASE SCHEMA CHANGES HERE *
*****************************************************************************/
@@ -677,6 +834,52 @@ function database_update_info()
// No changes from 3.0.5-RC1 to 3.0.5
'3.0.5-RC1' => array(),
+
+ // Changes from 3.0.5 to 3.0.6-RC1
+ '3.0.5' => array(
+ 'add_columns' => array(
+ CONFIRM_TABLE => array(
+ 'attempts' => array('UINT', 0),
+ ),
+ USERS_TABLE => array(
+ 'user_new' => array('BOOL', 1),
+ 'user_reminded' => array('TINT:4', 0),
+ 'user_reminded_time'=> array('TIMESTAMP', 0),
+ ),
+ GROUPS_TABLE => array(
+ 'group_skip_auth' => array('BOOL', 0, 'after' => 'group_founder_manage'),
+ ),
+ PRIVMSGS_TABLE => array(
+ 'message_reported' => array('BOOL', 0),
+ ),
+ REPORTS_TABLE => array(
+ 'pm_id' => array('UINT', 0),
+ ),
+ PROFILE_FIELDS_TABLE => array(
+ 'field_show_on_vt' => array('BOOL', 0),
+ ),
+ FORUMS_TABLE => array(
+ 'forum_options' => array('UINT:20', 0),
+ ),
+ ),
+ 'change_columns' => array(
+ USERS_TABLE => array(
+ 'user_options' => array('UINT:11', 230271),
+ ),
+ ),
+ 'add_index' => array(
+ LOG_TABLE => array(
+ 'log_time' => array('log_time'),
+ ),
+ REPORTS_TABLE => array(
+ 'post_id' => array('post_id'),
+ 'pm_id' => array('pm_id'),
+ ),
+ POSTS_TABLE => array(
+ 'post_username' => array('post_username'),
+ ),
+ ),
+ ),
);
}
@@ -903,7 +1106,6 @@ function change_database_data(&$no_updates, $version)
set_config('captcha_gd_wave', 0);
set_config('captcha_gd_3d_noise', 1);
set_config('captcha_gd_fonts', 1);
-
set_config('confirm_refresh', 1);
// Maximum number of keywords
@@ -940,6 +1142,7 @@ function change_database_data(&$no_updates, $version)
WHERE bot_agent = 'ichiro/2'";
_sql($sql, $errored, $error_ary);
+
// Before we are able to add a unique key to auth_option, we need to remove duplicate entries
// We get duplicate entries first
@@ -1012,6 +1215,297 @@ function change_database_data(&$no_updates, $version)
// No changes from 3.0.5-RC1 to 3.0.5
case '3.0.5-RC1':
break;
+
+ // Changes from 3.0.5 to 3.0.6-RC1
+ case '3.0.5':
+ // Let's see if the GD Captcha can be enabled... we simply look for what *is* enabled...
+ if (!empty($config['captcha_gd']) && !isset($config['captcha_plugin']))
+ {
+ set_config('captcha_plugin', 'phpbb_captcha_gd');
+ }
+ else if (!isset($config['captcha_plugin']))
+ {
+ set_config('captcha_plugin', 'phpbb_captcha_nogd');
+ }
+
+ // Entries for the Feed Feature
+ set_config('feed_enable', '0');
+ set_config('feed_limit', '10');
+
+ set_config('feed_overall_forums', '1');
+ set_config('feed_overall_forums_limit', '15');
+
+ set_config('feed_overall_topics', '0');
+ set_config('feed_overall_topics_limit', '15');
+
+ set_config('feed_forum', '1');
+ set_config('feed_topic', '1');
+ set_config('feed_item_statistics', '1');
+
+ // Entries for smiley pagination
+ set_config('smilies_per_page', '50');
+
+ // Entry for reporting PMs
+ set_config('allow_pm_report', '1');
+
+ // Install modules
+ $modules_to_install = array(
+ 'feed' => array(
+ 'base' => 'board',
+ 'class' => 'acp',
+ 'title' => 'ACP_FEED_SETTINGS',
+ 'auth' => 'acl_a_board',
+ 'cat' => 'ACP_BOARD_CONFIGURATION',
+ 'after' => array('signature', 'ACP_SIGNATURE_SETTINGS')
+ ),
+ 'warnings' => array(
+ 'base' => 'users',
+ 'class' => 'acp',
+ 'title' => 'ACP_USER_WARNINGS',
+ 'auth' => 'acl_a_user',
+ 'display' => 0,
+ 'cat' => 'ACP_CAT_USERS',
+ 'after' => array('feedback', 'ACP_USER_FEEDBACK')
+ ),
+ 'send_statistics' => array(
+ 'base' => 'send_statistics',
+ 'class' => 'acp',
+ 'title' => 'ACP_SEND_STATISTICS',
+ 'auth' => 'acl_a_server',
+ 'cat' => 'ACP_SERVER_CONFIGURATION'
+ ),
+ 'setting_forum_copy' => array(
+ 'base' => 'permissions',
+ 'class' => 'acp',
+ 'title' => 'ACP_FORUM_PERMISSIONS_COPY',
+ 'auth' => 'acl_a_fauth && acl_a_authusers && acl_a_authgroups && acl_a_mauth',
+ 'cat' => 'ACP_FORUM_BASED_PERMISSIONS',
+ 'after' => array('setting_forum_local', 'ACP_FORUM_PERMISSIONS')
+ ),
+ 'pm_reports' => array(
+ 'base' => 'pm_reports',
+ 'class' => 'mcp',
+ 'title' => 'MCP_PM_REPORTS_OPEN',
+ 'auth' => 'aclf_m_report',
+ 'cat' => 'MCP_REPORTS'
+ ),
+ 'pm_reports_closed' => array(
+ 'base' => 'pm_reports',
+ 'class' => 'mcp',
+ 'title' => 'MCP_PM_REPORTS_CLOSED',
+ 'auth' => 'aclf_m_report',
+ 'cat' => 'MCP_REPORTS'
+ ),
+ 'pm_report_details' => array(
+ 'base' => 'pm_reports',
+ 'class' => 'mcp',
+ 'title' => 'MCP_PM_REPORT_DETAILS',
+ 'auth' => 'aclf_m_report',
+ 'cat' => 'MCP_REPORTS'
+ ),
+ );
+
+ _add_modules($modules_to_install);
+
+ // Add newly_registered group... but check if it already exists (we always supported running the updater on any schema)
+ $sql = 'SELECT group_id
+ FROM ' . GROUPS_TABLE . "
+ WHERE group_name = 'NEWLY_REGISTERED'";
+ $result = $db->sql_query($sql);
+ $group_id = (int) $db->sql_fetchfield('group_id');
+ $db->sql_freeresult($result);
+
+ if (!$group_id)
+ {
+ $sql = 'INSERT INTO ' . GROUPS_TABLE . " (group_name, group_type, group_founder_manage, group_colour, group_legend, group_avatar, group_desc, group_desc_uid, group_max_recipients) VALUES ('NEWLY_REGISTERED', 3, 0, '', 0, '', '', '', 5)";
+ _sql($sql, $errored, $error_ary);
+
+ $group_id = $db->sql_nextid();
+ }
+
+ // Insert new user role... at the end of the chain
+ $sql = 'SELECT role_id
+ FROM ' . ACL_ROLES_TABLE . "
+ WHERE role_name = 'ROLE_USER_NEW_MEMBER'
+ AND role_type = 'u_'";
+ $result = $db->sql_query($sql);
+ $u_role = (int) $db->sql_fetchfield('role_id');
+ $db->sql_freeresult($result);
+
+ if (!$u_role)
+ {
+ $sql = 'SELECT MAX(role_order) as max_order_id
+ FROM ' . ACL_ROLES_TABLE . "
+ WHERE role_type = 'u_'";
+ $result = $db->sql_query($sql);
+ $next_order_id = (int) $db->sql_fetchfield('max_order_id');
+ $db->sql_freeresult($result);
+
+ $next_order_id++;
+
+ $sql = 'INSERT INTO ' . ACL_ROLES_TABLE . " (role_name, role_description, role_type, role_order) VALUES ('ROLE_USER_NEW_MEMBER', 'ROLE_DESCRIPTION_USER_NEW_MEMBER', 'u_', $next_order_id)";
+ _sql($sql, $errored, $error_ary);
+ $u_role = $db->sql_nextid();
+
+ if (!$errored)
+ {
+ // Now add the correct data to the roles...
+ // The standard role says that new users are not able to send a PM, Mass PM, are not able to PM groups
+ $sql = 'INSERT INTO ' . ACL_ROLES_DATA_TABLE . " (role_id, auth_option_id, auth_setting) SELECT $u_role, auth_option_id, 0 FROM " . ACL_OPTIONS_TABLE . " WHERE auth_option LIKE 'u_%' AND auth_option IN ('u_sendpm', 'u_masspm', 'u_masspm_group')";
+ _sql($sql, $errored, $error_ary);
+
+ // Add user role to group
+ $sql = 'INSERT INTO ' . ACL_GROUPS_TABLE . " (group_id, forum_id, auth_option_id, auth_role_id, auth_setting) VALUES ($group_id, 0, 0, $u_role, 0)";
+ _sql($sql, $errored, $error_ary);
+ }
+ }
+
+ // Insert new forum role
+ $sql = 'SELECT role_id
+ FROM ' . ACL_ROLES_TABLE . "
+ WHERE role_name = 'ROLE_FORUM_NEW_MEMBER'
+ AND role_type = 'f_'";
+ $result = $db->sql_query($sql);
+ $f_role = (int) $db->sql_fetchfield('role_id');
+ $db->sql_freeresult($result);
+
+ if (!$f_role)
+ {
+ $sql = 'SELECT MAX(role_order) as max_order_id
+ FROM ' . ACL_ROLES_TABLE . "
+ WHERE role_type = 'f_'";
+ $result = $db->sql_query($sql);
+ $next_order_id = (int) $db->sql_fetchfield('max_order_id');
+ $db->sql_freeresult($result);
+
+ $next_order_id++;
+
+ $sql = 'INSERT INTO ' . ACL_ROLES_TABLE . " (role_name, role_description, role_type, role_order) VALUES ('ROLE_FORUM_NEW_MEMBER', 'ROLE_DESCRIPTION_FORUM_NEW_MEMBER', 'f_', $next_order_id)";
+ _sql($sql, $errored, $error_ary);
+ $f_role = $db->sql_nextid();
+
+ if (!$errored)
+ {
+ $sql = 'INSERT INTO ' . ACL_ROLES_DATA_TABLE . " (role_id, auth_option_id, auth_setting) SELECT $f_role, auth_option_id, 0 FROM " . ACL_OPTIONS_TABLE . " WHERE auth_option LIKE 'f_%' AND auth_option IN ('f_noapprove')";
+ _sql($sql, $errored, $error_ary);
+ }
+ }
+
+ // Set every members user_new column to 0 (old users) only if there is no one yet (this makes sure we do not execute this more than once)
+ $sql = 'SELECT 1
+ FROM ' . USERS_TABLE . '
+ WHERE user_new = 0';
+ $result = $db->sql_query_limit($sql, 1);
+ $row = $db->sql_fetchrow($result);
+ $db->sql_freeresult($result);
+
+ if (!$row)
+ {
+ $sql = 'UPDATE ' . USERS_TABLE . ' SET user_new = 0';
+ _sql($sql, $errored, $error_ary);
+ }
+
+ // Newly registered users limit
+ if (!isset($config['new_member_post_limit']))
+ {
+ set_config('new_member_post_limit', (!empty($config['enable_queue_trigger'])) ? $config['queue_trigger_posts'] : 0);
+ }
+
+ if (!isset($config['new_member_group_default']))
+ {
+ set_config('new_member_group_default', 0);
+ }
+
+ // To mimick the old "feature" we will assign the forum role to every forum, regardless of the setting (this makes sure there are no "this does not work!!!! YUO!!!" posts...
+ // Check if the role is already assigned...
+ $sql = 'SELECT forum_id
+ FROM ' . ACL_GROUPS_TABLE . '
+ WHERE group_id = ' . $group_id . '
+ AND auth_role_id = ' . $f_role;
+ $result = $db->sql_query($sql);
+ $is_options = (int) $db->sql_fetchfield('forum_id');
+ $db->sql_freeresult($result);
+
+ // Not assigned at all... :/
+ if (!$is_options)
+ {
+ // Get postable forums
+ $sql = 'SELECT forum_id
+ FROM ' . FORUMS_TABLE . '
+ WHERE forum_type != ' . FORUM_LINK;
+ $result = $db->sql_query($sql);
+
+ while ($row = $db->sql_fetchrow($result))
+ {
+ _sql('INSERT INTO ' . ACL_GROUPS_TABLE . ' (group_id, forum_id, auth_option_id, auth_role_id, auth_setting) VALUES (' . $group_id . ', ' . (int) $row['forum_id'] . ', 0, ' . $f_role . ', 0)', $errored, $error_ary);
+ }
+ $db->sql_freeresult($result);
+ }
+
+ // Clear permissions...
+ include_once($phpbb_root_path . 'includes/acp/auth.' . $phpEx);
+ $auth_admin = new auth_admin();
+ $auth_admin->acl_clear_prefetch();
+
+ if (!isset($config['allow_avatar']))
+ {
+ if ($config['allow_avatar_upload'] || $config['allow_avatar_local'] || $config['allow_avatar_remote'])
+ {
+ set_config('allow_avatar', '1');
+ }
+ else
+ {
+ set_config('allow_avatar', '0');
+ }
+ }
+
+ if (!isset($config['allow_avatar_remote_upload']))
+ {
+ if ($config['allow_avatar_remote'] && $config['allow_avatar_upload'])
+ {
+ set_config('allow_avatar_remote_upload', '1');
+ }
+ else
+ {
+ set_config('allow_avatar_remote_upload', '0');
+ }
+ }
+
+ // Minimum number of characters
+ if (!isset($config['min_post_chars']))
+ {
+ set_config('min_post_chars', '1');
+ }
+
+ if (!isset($config['allow_quick_reply']))
+ {
+ set_config('allow_quick_reply', '1');
+ }
+
+ // Set every members user_options column to enable
+ // bbcode, smilies and URLs for signatures by default
+ $sql = 'SELECT user_options
+ FROM ' . USERS_TABLE . '
+ WHERE user_type IN (' . USER_NORMAL . ', ' . USER_FOUNDER . ')';
+ $result = $db->sql_query_limit($sql, 1);
+ $user_option = (int) $db->sql_fetchfield('user_options');
+ $db->sql_freeresult($result);
+
+ // Check if we already updated the database by checking bit 15 which we used to store the sig_bbcode option
+ if (!($user_option & 1 << 15))
+ {
+ // 229376 is the added value to enable all three signature options
+ $sql = 'UPDATE ' . USERS_TABLE . ' SET user_options = user_options + 229376';
+ _sql($sql, $errored, $error_ary);
+ }
+
+ if (!isset($config['delete_time']))
+ {
+ set_config('delete_time', $config['edit_time']);
+ }
+
+ $no_updates = false;
+ break;
}
}
@@ -1340,6 +1834,14 @@ class updater_db_tools
}
$statements = array();
+ $sqlite = false;
+
+ // For SQLite we need to perform the schema changes in a much more different way
+ if ($this->db->sql_layer == 'sqlite' && $this->return_statements)
+ {
+ $sqlite_data = array();
+ $sqlite = true;
+ }
// Change columns?
if (!empty($schema_changes['change_columns']))
@@ -1349,16 +1851,27 @@ class updater_db_tools
foreach ($columns as $column_name => $column_data)
{
// If the column exists we change it, else we add it ;)
- if ($this->sql_column_exists($table, $column_name))
+ if ($column_exists = $this->sql_column_exists($table, $column_name))
{
- $result = $this->sql_column_change($table, $column_name, $column_data);
+ $result = $this->sql_column_change($table, $column_name, $column_data, true);
}
else
{
- $result = $this->sql_column_add($table, $column_name, $column_data);
+ $result = $this->sql_column_add($table, $column_name, $column_data, true);
}
- if ($this->return_statements)
+ if ($sqlite)
+ {
+ if ($column_exists)
+ {
+ $sqlite_data[$table]['change_columns'][] = $result;
+ }
+ else
+ {
+ $sqlite_data[$table]['add_columns'][] = $result;
+ }
+ }
+ else if ($this->return_statements)
{
$statements = array_merge($statements, $result);
}
@@ -1373,17 +1886,30 @@ class updater_db_tools
{
foreach ($columns as $column_name => $column_data)
{
- // Only add the column if it does not exist yet, else change it (to be consistent)
- if ($this->sql_column_exists($table, $column_name))
+ // Only add the column if it does not exist yet
+ if ($column_exists = $this->sql_column_exists($table, $column_name))
{
- $result = $this->sql_column_change($table, $column_name, $column_data);
+ continue;
+ // This is commented out here because it can take tremendous time on updates
+// $result = $this->sql_column_change($table, $column_name, $column_data, true);
}
else
{
- $result = $this->sql_column_add($table, $column_name, $column_data);
+ $result = $this->sql_column_add($table, $column_name, $column_data, true);
}
- if ($this->return_statements)
+ if ($sqlite)
+ {
+ if ($column_exists)
+ {
+ $sqlite_data[$table]['change_columns'][] = $result;
+ }
+ else
+ {
+ $sqlite_data[$table]['add_columns'][] = $result;
+ }
+ }
+ else if ($this->return_statements)
{
$statements = array_merge($statements, $result);
}
@@ -1418,9 +1944,13 @@ class updater_db_tools
// Only remove the column if it exists...
if ($this->sql_column_exists($table, $column))
{
- $result = $this->sql_column_remove($table, $column);
+ $result = $this->sql_column_remove($table, $column, true);
- if ($this->return_statements)
+ if ($sqlite)
+ {
+ $sqlite_data[$table]['drop_columns'][] = $result;
+ }
+ else if ($this->return_statements)
{
$statements = array_merge($statements, $result);
}
@@ -1434,9 +1964,13 @@ class updater_db_tools
{
foreach ($schema_changes['add_primary_keys'] as $table => $columns)
{
- $result = $this->sql_create_primary_key($table, $columns);
+ $result = $this->sql_create_primary_key($table, $columns, true);
- if ($this->return_statements)
+ if ($sqlite)
+ {
+ $sqlite_data[$table]['primary_key'] = $result;
+ }
+ else if ($this->return_statements)
{
$statements = array_merge($statements, $result);
}
@@ -1477,6 +2011,147 @@ class updater_db_tools
}
}
+ if ($sqlite)
+ {
+ foreach ($sqlite_data as $table_name => $sql_schema_changes)
+ {
+ // Create temporary table with original data
+ $statements[] = 'begin';
+
+ $sql = "SELECT sql
+ FROM sqlite_master
+ WHERE type = 'table'
+ AND name = '{$table_name}'
+ ORDER BY type DESC, name;";
+ $result = $this->db->sql_query($sql);
+
+ if (!$result)
+ {
+ continue;
+ }
+
+ $row = $this->db->sql_fetchrow($result);
+ $this->db->sql_freeresult($result);
+
+ // Create a backup table and populate it, destroy the existing one
+ $statements[] = preg_replace('#CREATE\s+TABLE\s+"?' . $table_name . '"?#i', 'CREATE TEMPORARY TABLE ' . $table_name . '_temp', $row['sql']);
+ $statements[] = 'INSERT INTO ' . $table_name . '_temp SELECT * FROM ' . $table_name;
+ $statements[] = 'DROP TABLE ' . $table_name;
+
+ // Get the columns...
+ preg_match('#\((.*)\)#s', $row['sql'], $matches);
+
+ $plain_table_cols = trim($matches[1]);
+ $new_table_cols = preg_split('/,(?![\s\w]+\))/m', $plain_table_cols);
+ $column_list = array();
+
+ foreach ($new_table_cols as $declaration)
+ {
+ $entities = preg_split('#\s+#', trim($declaration));
+ if ($entities[0] == 'PRIMARY')
+ {
+ continue;
+ }
+ $column_list[] = $entities[0];
+ }
+
+ // note down the primary key notation because sqlite only supports adding it to the end for the new table
+ $primary_key = false;
+ $_new_cols = array();
+
+ foreach ($new_table_cols as $key => $declaration)
+ {
+ $entities = preg_split('#\s+#', trim($declaration));
+ if ($entities[0] == 'PRIMARY')
+ {
+ $primary_key = $declaration;
+ continue;
+ }
+ $_new_cols[] = $declaration;
+ }
+
+ $new_table_cols = $_new_cols;
+
+ // First of all... change columns
+ if (!empty($sql_schema_changes['change_columns']))
+ {
+ foreach ($sql_schema_changes['change_columns'] as $column_sql)
+ {
+ foreach ($new_table_cols as $key => $declaration)
+ {
+ $entities = preg_split('#\s+#', trim($declaration));
+ if (strpos($column_sql, $entities[0] . ' ') === 0)
+ {
+ $new_table_cols[$key] = $column_sql;
+ }
+ }
+ }
+ }
+
+ if (!empty($sql_schema_changes['add_columns']))
+ {
+ foreach ($sql_schema_changes['add_columns'] as $column_sql)
+ {
+ $new_table_cols[] = $column_sql;
+ }
+ }
+
+ // Now drop them...
+ if (!empty($sql_schema_changes['drop_columns']))
+ {
+ foreach ($sql_schema_changes['drop_columns'] as $column_name)
+ {
+ // Remove from column list...
+ $new_column_list = array();
+ foreach ($column_list as $key => $value)
+ {
+ if ($value === $column_name)
+ {
+ continue;
+ }
+
+ $new_column_list[] = $value;
+ }
+
+ $column_list = $new_column_list;
+
+ // Remove from table...
+ $_new_cols = array();
+ foreach ($new_table_cols as $key => $declaration)
+ {
+ $entities = preg_split('#\s+#', trim($declaration));
+ if (strpos($column_name . ' ', $entities[0] . ' ') === 0)
+ {
+ continue;
+ }
+ $_new_cols[] = $declaration;
+ }
+ $new_table_cols = $_new_cols;
+ }
+ }
+
+ // Primary key...
+ if (!empty($sql_schema_changes['primary_key']))
+ {
+ $new_table_cols[] = 'PRIMARY KEY (' . implode(', ', $sql_schema_changes['primary_key']) . ')';
+ }
+ // Add a new one or the old primary key
+ else if ($primary_key !== false)
+ {
+ $new_table_cols[] = $primary_key;
+ }
+
+ $columns = implode(',', $column_list);
+
+ // create a new table and fill it up. destroy the temp one
+ $statements[] = 'CREATE TABLE ' . $table_name . ' (' . implode(',', $new_table_cols) . ');';
+ $statements[] = 'INSERT INTO ' . $table_name . ' (' . $columns . ') SELECT ' . $columns . ' FROM ' . $table_name . '_temp;';
+ $statements[] = 'DROP TABLE ' . $table_name . '_temp';
+
+ $statements[] = 'commit';
+ }
+ }
+
if ($this->return_statements)
{
return $statements;
@@ -1561,7 +2236,7 @@ class updater_db_tools
case 'oracle':
$sql = "SELECT column_name
FROM user_tab_columns
- WHERE table_name = '{$table}'";
+ WHERE LOWER(table_name) = '" . strtolower($table) . "'";
$result = $this->db->sql_query($sql);
while ($row = $this->db->sql_fetchrow($result))
{
@@ -1579,7 +2254,7 @@ class updater_db_tools
case 'firebird':
$sql = "SELECT RDB\$FIELD_NAME as FNAME
FROM RDB\$RELATION_FIELDS
- WHERE RDB\$RELATION_NAME = '{$table}'";
+ WHERE RDB\$RELATION_NAME = '" . strtoupper($table) . "'";
$result = $this->db->sql_query($sql);
while ($row = $this->db->sql_fetchrow($result))
{
@@ -1732,10 +2407,12 @@ class updater_db_tools
{
case 'firebird':
$sql .= " {$column_type} ";
+ $return_array['column_type_sql_type'] = " {$column_type} ";
if (!is_null($column_data[1]))
{
$sql .= 'DEFAULT ' . ((is_numeric($column_data[1])) ? $column_data[1] : "'{$column_data[1]}'") . ' ';
+ $return_array['column_type_sql_default'] = ((is_numeric($column_data[1])) ? $column_data[1] : "'{$column_data[1]}'") . ' ';
}
$sql .= 'NOT NULL';
@@ -1889,7 +2566,7 @@ class updater_db_tools
/**
* Add new column
*/
- function sql_column_add($table_name, $column_name, $column_data)
+ function sql_column_add($table_name, $column_name, $column_data, $inline = false)
{
$column_data = $this->sql_prepare_column_data($table_name, $column_name, $column_data);
$statements = array();
@@ -1897,27 +2574,38 @@ class updater_db_tools
switch ($this->sql_layer)
{
case 'firebird':
+ // Does not support AFTER statement, only POSITION (and there you need the column position)
$statements[] = 'ALTER TABLE ' . $table_name . ' ADD "' . strtoupper($column_name) . '" ' . $column_data['column_type_sql'];
break;
case 'mssql':
+ // Does not support AFTER, only through temporary table
$statements[] = 'ALTER TABLE [' . $table_name . '] ADD [' . $column_name . '] ' . $column_data['column_type_sql_default'];
break;
case 'mysql_40':
case 'mysql_41':
- $statements[] = 'ALTER TABLE `' . $table_name . '` ADD COLUMN `' . $column_name . '` ' . $column_data['column_type_sql'];
+ $after = (!empty($column_data['after'])) ? ' AFTER ' . $column_data['after'] : '';
+ $statements[] = 'ALTER TABLE `' . $table_name . '` ADD COLUMN `' . $column_name . '` ' . $column_data['column_type_sql'] . $after;
break;
case 'oracle':
+ // Does not support AFTER, only through temporary table
$statements[] = 'ALTER TABLE ' . $table_name . ' ADD ' . $column_name . ' ' . $column_data['column_type_sql'];
break;
case 'postgres':
+ // Does not support AFTER, only through temporary table
$statements[] = 'ALTER TABLE ' . $table_name . ' ADD COLUMN "' . $column_name . '" ' . $column_data['column_type_sql'];
break;
case 'sqlite':
+
+ if ($inline && $this->return_statements)
+ {
+ return $column_name . ' ' . $column_data['column_type_sql'];
+ }
+
if (version_compare(sqlite_libversion(), '3.0') == -1)
{
$sql = "SELECT sql
@@ -1982,7 +2670,7 @@ class updater_db_tools
/**
* Drop column
*/
- function sql_column_remove($table_name, $column_name)
+ function sql_column_remove($table_name, $column_name, $inline = false)
{
$statements = array();
@@ -2010,6 +2698,12 @@ class updater_db_tools
break;
case 'sqlite':
+
+ if ($inline && $this->return_statements)
+ {
+ return $column_name;
+ }
+
if (version_compare(sqlite_libversion(), '3.0') == -1)
{
$sql = "SELECT sql
@@ -2103,7 +2797,7 @@ class updater_db_tools
/**
* Add primary key
*/
- function sql_create_primary_key($table_name, $column)
+ function sql_create_primary_key($table_name, $column, $inline = false)
{
$statements = array();
@@ -2130,6 +2824,12 @@ class updater_db_tools
break;
case 'sqlite':
+
+ if ($inline && $this->return_statements)
+ {
+ return $column;
+ }
+
$sql = "SELECT sql
FROM sqlite_master
WHERE type = 'table'
@@ -2243,7 +2943,7 @@ class updater_db_tools
/**
* Change column type (not name!)
*/
- function sql_column_change($table_name, $column_name, $column_data)
+ function sql_column_change($table_name, $column_name, $column_data, $inline = false)
{
$column_data = $this->sql_prepare_column_data($table_name, $column_name, $column_data);
$statements = array();
@@ -2252,7 +2952,15 @@ class updater_db_tools
{
case 'firebird':
// Change type...
- $statements[] = 'ALTER TABLE ' . $table_name . ' ALTER COLUMN "' . strtoupper($column_name) . '" TYPE ' . ' ' . $column_data['column_type_sql'];
+ if (!empty($column_data['column_type_sql_default']))
+ {
+ $statements[] = 'ALTER TABLE ' . $table_name . ' ALTER COLUMN "' . strtoupper($column_name) . '" TYPE ' . ' ' . $column_data['column_type_sql_type'];
+ $statements[] = 'ALTER TABLE ' . $table_name . ' ALTER COLUMN "' . strtoupper($column_name) . '" SET DEFAULT ' . ' ' . $column_data['column_type_sql_default'];
+ }
+ else
+ {
+ $statements[] = 'ALTER TABLE ' . $table_name . ' ALTER COLUMN "' . strtoupper($column_name) . '" TYPE ' . ' ' . $column_data['column_type_sql'];
+ }
break;
case 'mssql':
@@ -2333,6 +3041,11 @@ class updater_db_tools
case 'sqlite':
+ if ($inline && $this->return_statements)
+ {
+ return $column_name . ' ' . $column_data['column_type_sql'];
+ }
+
$sql = "SELECT sql
FROM sqlite_master
WHERE type = 'table'