diff options
author | Meik Sievertsen <acydburn@phpbb.com> | 2009-07-08 13:52:18 +0000 |
---|---|---|
committer | Meik Sievertsen <acydburn@phpbb.com> | 2009-07-08 13:52:18 +0000 |
commit | 55e15b4c8eea94f226a0169284bb51d7d9bcbcd4 (patch) | |
tree | 33ed37ef688271eb61aa40681a1867f772cc7654 | |
parent | 51885a2734bea8f77e9be0f536942fb6bf305163 (diff) | |
download | forums-55e15b4c8eea94f226a0169284bb51d7d9bcbcd4.tar forums-55e15b4c8eea94f226a0169284bb51d7d9bcbcd4.tar.gz forums-55e15b4c8eea94f226a0169284bb51d7d9bcbcd4.tar.bz2 forums-55e15b4c8eea94f226a0169284bb51d7d9bcbcd4.tar.xz forums-55e15b4c8eea94f226a0169284bb51d7d9bcbcd4.zip |
Fix database updater and db tools to support multiple column changes/additions/removals with SQLite
git-svn-id: file:///svn/phpbb/branches/phpBB-3_0_0@9735 89ea8834-ac86-4346-8a33-228a782c2dd0
-rw-r--r-- | phpBB/docs/CHANGELOG.html | 1 | ||||
-rw-r--r-- | phpBB/includes/db/db_tools.php | 246 | ||||
-rw-r--r-- | phpBB/install/database_update.php | 238 |
3 files changed, 450 insertions, 35 deletions
diff --git a/phpBB/docs/CHANGELOG.html b/phpBB/docs/CHANGELOG.html index 3438944736..36da6e67e8 100644 --- a/phpBB/docs/CHANGELOG.html +++ b/phpBB/docs/CHANGELOG.html @@ -148,6 +148,7 @@ <li>[Fix] View end of ban in MCP and ACP when user is banned by duration (Bug #47815 - Patch by Pyramide)</li> <li>[Fix] Display user's posts count in private message when it is equal to 0 (prosilver). (Bug #40155 - Patch by rxu)</li> <li>[Fix] Disable word-censor option in UCP lacks the config-setting (Bug #47575 - Patch by 00mohgta7)</li> + <li>[Fix] Fix database updater and db tools to support multiple column changes/additions/removals with SQLite</li> <li>[Change] Change the data format of the default file ACM to be more secure from tampering and have better performance.</li> <li>[Change] Add index on log_time to the log table to prevent slowdown on boards with many log entries. (Bug #44665 - Patch by bantu)</li> <li>[Change] Template engine now permits to a limited extent variable includes.</li> diff --git a/phpBB/includes/db/db_tools.php b/phpBB/includes/db/db_tools.php index 7ea70f341d..ddc633c6d1 100644 --- a/phpBB/includes/db/db_tools.php +++ b/phpBB/includes/db/db_tools.php @@ -347,6 +347,11 @@ class phpbb_db_tools // holds the DDL for a column $columns = $statements = array(); + if ($this->sql_table_exists($table_name)) + { + return $this->_sql_run_sql($statements); + } + // Begin transaction $statements[] = 'begin'; @@ -580,6 +585,14 @@ class phpbb_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'])) @@ -589,16 +602,27 @@ class phpbb_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); } @@ -614,16 +638,27 @@ class phpbb_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)) + 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); } @@ -658,9 +693,13 @@ class phpbb_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); } @@ -674,9 +713,13 @@ class phpbb_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); } @@ -717,6 +760,147 @@ class phpbb_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; @@ -1131,7 +1315,7 @@ class phpbb_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(); @@ -1160,6 +1344,12 @@ class phpbb_db_tools 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 @@ -1224,7 +1414,7 @@ class phpbb_db_tools /** * Drop column */ - function sql_column_remove($table_name, $column_name) + function sql_column_remove($table_name, $column_name, $inline = false) { $statements = array(); @@ -1252,6 +1442,12 @@ class phpbb_db_tools break; case 'sqlite': + + if ($inline && $this->return_statements) + { + return $column_name; + } + if (version_compare(sqlite_libversion(), '3.0') == -1) { $sql = "SELECT sql @@ -1294,7 +1490,7 @@ class phpbb_db_tools $columns = implode(',', $column_list); - $new_table_cols = $new_table_cols = preg_replace('/' . $column_name . '[^,]+(?:,|$)/m', '', $new_table_cols); + $new_table_cols = preg_replace('/' . $column_name . '[^,]+(?:,|$)/m', '', $new_table_cols); // create a new table and fill it up. destroy the temp one $statements[] = 'CREATE TABLE ' . $table_name . ' (' . $new_table_cols . ');'; @@ -1349,6 +1545,11 @@ class phpbb_db_tools { $statements = array(); + if (!$this->sql_table_exists($table_name)) + { + return $this->_sql_run_sql($statements); + } + // the most basic operation, get rid of the table $statements[] = 'DROP TABLE ' . $table_name; @@ -1407,7 +1608,7 @@ class phpbb_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(); @@ -1434,6 +1635,12 @@ class phpbb_db_tools break; case 'sqlite': + + if ($inline && $this->return_statements) + { + return $column; + } + $sql = "SELECT sql FROM sqlite_master WHERE type = 'table' @@ -1641,7 +1848,7 @@ class phpbb_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(); @@ -1739,6 +1946,11 @@ class phpbb_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' diff --git a/phpBB/install/database_update.php b/phpBB/install/database_update.php index 85b9623ffe..d7398ea953 100644 --- a/phpBB/install/database_update.php +++ b/phpBB/install/database_update.php @@ -11,7 +11,7 @@ $updates_to_version = '3.0.6-dev'; // Enter any version to update from to test updates. The version within the db will not be updated. -$debug_from_version = false; +$debug_from_version = '3.0.5'; // Which oldest version does this updater supports? $oldest_from_version = '3.0.0'; @@ -1292,7 +1292,7 @@ function change_database_data(&$no_updates, $version) $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)) { @@ -1631,6 +1631,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'])) @@ -1640,16 +1648,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); } @@ -1665,16 +1684,27 @@ 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)) + 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); } @@ -1709,9 +1739,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); } @@ -1725,9 +1759,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); } @@ -1768,6 +1806,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; @@ -2182,7 +2361,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(); @@ -2216,6 +2395,12 @@ class updater_db_tools 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 @@ -2280,7 +2465,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(); @@ -2308,6 +2493,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 @@ -2401,7 +2592,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(); @@ -2428,6 +2619,12 @@ class updater_db_tools break; case 'sqlite': + + if ($inline && $this->return_statements) + { + return $column; + } + $sql = "SELECT sql FROM sqlite_master WHERE type = 'table' @@ -2541,7 +2738,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(); @@ -2639,6 +2836,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' |