From e6eb11bb1168236cbaba0263d322170dc2c7bdcd Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Fri, 29 Apr 2011 00:03:49 -0400 Subject: [PATCH 1/7] [ticket/10003] Ported d7d96223e7bae7cd60b13c6e7896d95838c3633c to db_tools. PHPBB3-10003 --- phpBB/includes/db/db_tools.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/phpBB/includes/db/db_tools.php b/phpBB/includes/db/db_tools.php index f4b181c6ad..f22ddc2ee8 100644 --- a/phpBB/includes/db/db_tools.php +++ b/phpBB/includes/db/db_tools.php @@ -1371,24 +1371,29 @@ class phpbb_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': case 'mssqlnative': + // 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 if (version_compare($this->db->sql_server_info(true), '8.0', '>=')) { $statements[] = 'ALTER TABLE ' . $table_name . ' ADD COLUMN "' . $column_name . '" ' . $column_data['column_type_sql']; @@ -2120,4 +2125,4 @@ class phpbb_db_tools } } -?> \ No newline at end of file +?> From 3cb1b90ca6afcf0533f8f398f2a3f4066b697ed3 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Fri, 29 Apr 2011 00:34:24 -0400 Subject: [PATCH 2/7] [ticket/10003] Ported 96a30afcca3ebd832c9b3083bb5c9a9f2a2dc54b to db_tools. This change is somewhat questionable, maybe it should be reviewed. PHPBB3-10003 --- phpBB/includes/db/db_tools.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/phpBB/includes/db/db_tools.php b/phpBB/includes/db/db_tools.php index f22ddc2ee8..d9ff811e34 100644 --- a/phpBB/includes/db/db_tools.php +++ b/phpBB/includes/db/db_tools.php @@ -681,10 +681,12 @@ 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) + // 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, true); + 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 { From 9f34aa0b79456f5d2d60f62361f483c76a3f89dd Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Fri, 29 Apr 2011 00:39:36 -0400 Subject: [PATCH 3/7] [ticket/10003] Ported 54c22ae52a0e18232cac8fed342ea52f2e2a793d to db_tools. This diff applied cleanly. PHPBB3-10003 --- phpBB/includes/db/db_tools.php | 110 ++++++++++++++++++++++++++++++++- 1 file changed, 109 insertions(+), 1 deletion(-) diff --git a/phpBB/includes/db/db_tools.php b/phpBB/includes/db/db_tools.php index d9ff811e34..a793a2f313 100644 --- a/phpBB/includes/db/db_tools.php +++ b/phpBB/includes/db/db_tools.php @@ -697,7 +697,8 @@ class phpbb_db_tools { if ($column_exists) { - $sqlite_data[$table]['change_columns'][] = $result; + continue; +// $sqlite_data[$table]['change_columns'][] = $result; } else { @@ -719,6 +720,11 @@ class phpbb_db_tools { foreach ($indexes as $index_name) { + if (!$this->sql_index_exists($table, $index_name)) + { + continue; + } + $result = $this->sql_index_drop($table, $index_name); if ($this->return_statements) @@ -779,6 +785,11 @@ class phpbb_db_tools { foreach ($index_array as $index_name => $column) { + if ($this->sql_index_exists($table, $index_name)) + { + continue; + } + $result = $this->sql_create_unique_index($table, $index_name, $column); if ($this->return_statements) @@ -796,6 +807,11 @@ class phpbb_db_tools { foreach ($index_array as $index_name => $column) { + if ($this->sql_index_exists($table, $index_name)) + { + continue; + } + $result = $this->sql_create_index($table, $index_name, $column); if ($this->return_statements) @@ -1104,6 +1120,98 @@ class phpbb_db_tools } } + /** + * Check if a specified index exists in table + * + * @param string $table_name Table to check the index at + * @param string $index_name The index name to check + * + * @return bool True if index exists, else false + */ + function sql_index_exists($table_name, $index_name) + { + if ($this->sql_layer == 'mssql') + { + $sql = "EXEC sp_statistics '$table_name'"; + $result = $this->db->sql_query($sql); + + while ($row = $this->db->sql_fetchrow($result)) + { + if ($row['TYPE'] == 3) + { + if (strtolower($row['INDEX_NAME']) == strtolower($index_name)) + { + $this->db->sql_freeresult($result); + return true; + } + } + } + $this->db->sql_freeresult($result); + + return false; + } + + switch ($this->sql_layer) + { + case 'firebird': + $sql = "SELECT LOWER(RDB\$INDEX_NAME) as index_name + FROM RDB\$INDICES + WHERE RDB\$RELATION_NAME = " . strtoupper($table_name) . " + AND RDB\$UNIQUE_FLAG IS NULL + AND RDB\$FOREIGN_KEY IS NULL"; + $col = 'index_name'; + break; + + case 'postgres': + $sql = "SELECT ic.relname as index_name + FROM pg_class bc, pg_class ic, pg_index i + WHERE (bc.oid = i.indrelid) + AND (ic.oid = i.indexrelid) + AND (bc.relname = '" . $table_name . "') + AND (i.indisunique != 't') + AND (i.indisprimary != 't')"; + $col = 'index_name'; + break; + + case 'mysql_40': + case 'mysql_41': + $sql = 'SHOW KEYS + FROM ' . $table_name; + $col = 'Key_name'; + break; + + case 'oracle': + $sql = "SELECT index_name + FROM user_indexes + WHERE table_name = '" . $table_name . "' + AND generated = 'N'"; + break; + + case 'sqlite': + $sql = "PRAGMA index_info('" . $table_name . "');"; + $col = 'name'; + break; + } + + $result = $this->db->sql_query($sql); + while ($row = $this->db->sql_fetchrow($result)) + { + if (($this->sql_layer == 'mysql_40' || $this->sql_layer == 'mysql_41') && !$row['Non_unique']) + { + continue; + } + + if (strtolower($row[$col]) == strtolower($index_name)) + { + $this->db->sql_freeresult($result); + return true; + } + } + $this->db->sql_freeresult($result); + + return false; + } + /** * Private method for performing sql statements (either execute them or return them) * @access private From 761e3dd36f3b42fdaac99ba76f8d214b47983c05 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Fri, 29 Apr 2011 01:07:46 -0400 Subject: [PATCH 4/7] [ticket/10003] Ported 023760c8b2402418310a3717db8349cac0342e42 to db_tools. This was painful. Git wanted to patch hunks in wrong places. Hopefully I got it right. PHPBB3-10003 --- phpBB/includes/db/db_tools.php | 143 +++++++++++++++++++++++++++++++-- 1 file changed, 137 insertions(+), 6 deletions(-) diff --git a/phpBB/includes/db/db_tools.php b/phpBB/includes/db/db_tools.php index a793a2f313..f72498af9b 100644 --- a/phpBB/includes/db/db_tools.php +++ b/phpBB/includes/db/db_tools.php @@ -785,7 +785,7 @@ class phpbb_db_tools { foreach ($index_array as $index_name => $column) { - if ($this->sql_index_exists($table, $index_name)) + if ($this->sql_unique_index_exists($table, $index_name)) { continue; } @@ -1121,7 +1121,7 @@ class phpbb_db_tools } /** - * Check if a specified index exists in table + * Check if a specified index exists in table. Does not return PRIMARY KEY and UNIQUE indexes. * * @param string $table_name Table to check the index at * @param string $index_name The index name to check @@ -1156,7 +1156,7 @@ class phpbb_db_tools case 'firebird': $sql = "SELECT LOWER(RDB\$INDEX_NAME) as index_name FROM RDB\$INDICES - WHERE RDB\$RELATION_NAME = " . strtoupper($table_name) . " + WHERE RDB\$RELATION_NAME = '" . strtoupper($table_name) . "' AND RDB\$UNIQUE_FLAG IS NULL AND RDB\$FOREIGN_KEY IS NULL"; $col = 'index_name'; @@ -1183,12 +1183,14 @@ class phpbb_db_tools case 'oracle': $sql = "SELECT index_name FROM user_indexes - WHERE table_name = '" . $table_name . "' - AND generated = 'N'"; + WHERE table_name = '" . strtoupper($table_name) . "' + AND generated = 'N' + AND uniqueness = 'NONUNIQUE'"; + $col = 'index_name'; break; case 'sqlite': - $sql = "PRAGMA index_info('" . $table_name . "');"; + $sql = "PRAGMA index_list('" . $table_name . "');"; $col = 'name'; break; } @@ -1201,6 +1203,135 @@ class phpbb_db_tools continue; } + // These DBMS prefix index name with the table name + switch ($this->sql_layer) + { + case 'firebird': + case 'oracle': + case 'postgres': + case 'sqlite': + $row[$col] = substr($row[$col], strlen($table_name) + 1); + break; + } + + if (strtolower($row[$col]) == strtolower($index_name)) + { + $this->db->sql_freeresult($result); + return true; + } + } + $this->db->sql_freeresult($result); + + return false; + } + + /** + * Check if a specified index exists in table. Does not return PRIMARY KEY and UNIQUE indexes. + * + * @param string $table_name Table to check the index at + * @param string $index_name The index name to check + * + * @return bool True if index exists, else false + */ + function sql_unique_index_exists($table_name, $index_name) + { + if ($this->sql_layer == 'mssql') + { + $sql = "EXEC sp_statistics '$table_name'"; + $result = $this->db->sql_query($sql); + + while ($row = $this->db->sql_fetchrow($result)) + { + // Usually NON_UNIQUE is the column we want to check, but we allow for both + if ($row['TYPE'] == 3) + { + if (strtolower($row['INDEX_NAME']) == strtolower($index_name)) + { + $this->db->sql_freeresult($result); + return true; + } + } + } + $this->db->sql_freeresult($result); + return false; + } + + switch ($this->sql_layer) + { + case 'firebird': + $sql = "SELECT LOWER(RDB\$INDEX_NAME) as index_name + FROM RDB\$INDICES + WHERE RDB\$RELATION_NAME = '" . strtoupper($table_name) . "' + AND RDB\$UNIQUE_FLAG IS NOT NULL + AND RDB\$FOREIGN_KEY IS NULL"; + $col = 'index_name'; + break; + + case 'postgres': + $sql = "SELECT ic.relname as index_name, i.indisunique + FROM pg_class bc, pg_class ic, pg_index i + WHERE (bc.oid = i.indrelid) + AND (ic.oid = i.indexrelid) + AND (bc.relname = '" . $table_name . "') + AND (i.indisprimary != 't')"; + $col = 'index_name'; + break; + + case 'mysql_40': + case 'mysql_41': + $sql = 'SHOW KEYS + FROM ' . $table_name; + $col = 'Key_name'; + break; + + case 'oracle': + $sql = "SELECT index_name, table_owner + FROM user_indexes + WHERE table_name = '" . strtoupper($table_name) . "' + AND generated = 'N' + AND uniqueness = 'UNIQUE' + AND index_name LIKE 'U_%'"; + $col = 'index_name'; + break; + + case 'sqlite': + $sql = "PRAGMA index_list('" . $table_name . "') WHERE unique = 1;"; + $col = 'name'; + break; + } + + $result = $this->db->sql_query($sql); + while ($row = $this->db->sql_fetchrow($result)) + { + if (($this->sql_layer == 'mysql_40' || $this->sql_layer == 'mysql_41') && ($row['Non_unique'] || $row[$col] == 'PRIMARY')) + { + continue; + } + + if ($this->sql_layer == 'sqlite' && !$row['unique']) + { + continue; + } + + if ($this->sql_layer == 'postgres' && $row['indisunique'] != 't') + { + continue; + } + + // These DBMS prefix index name with the table name + switch ($this->sql_layer) + { + case 'oracle': + $row[$col] = substr($row[$col], strlen('U_' . $row['table_owner']) + 1); + break; + + case 'firebird': + case 'postgres': + case 'sqlite': + $row[$col] = substr($row[$col], strlen($table_name) + 1); + break; + } + if (strtolower($row[$col]) == strtolower($index_name)) { $this->db->sql_freeresult($result); From 55ff5da70b6598218b032725f73de7c4f94a7c89 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Fri, 29 Apr 2011 01:25:46 -0400 Subject: [PATCH 5/7] [ticket/10003] Ported 5553cfc2ed81ba9eb571804c431def962720b39e to db_tools. The diff in database_update was only partially relevant. PHPBB3-10003 --- phpBB/includes/db/db_tools.php | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/phpBB/includes/db/db_tools.php b/phpBB/includes/db/db_tools.php index f72498af9b..01061c77b1 100644 --- a/phpBB/includes/db/db_tools.php +++ b/phpBB/includes/db/db_tools.php @@ -1289,13 +1289,12 @@ class phpbb_db_tools FROM user_indexes WHERE table_name = '" . strtoupper($table_name) . "' AND generated = 'N' - AND uniqueness = 'UNIQUE' - AND index_name LIKE 'U_%'"; + AND uniqueness = 'UNIQUE'"; $col = 'index_name'; break; case 'sqlite': - $sql = "PRAGMA index_list('" . $table_name . "') WHERE unique = 1;"; + $sql = "PRAGMA index_list('" . $table_name . "');"; $col = 'name'; break; } @@ -1322,7 +1321,15 @@ class phpbb_db_tools switch ($this->sql_layer) { case 'oracle': - $row[$col] = substr($row[$col], strlen('U_' . $row['table_owner']) + 1); + // Two cases here... prefixed with U_[table_owner] and not prefixed with table_name + if (strpos($row[$col], 'U_') === 0) + { + $row[$col] = substr($row[$col], strlen('U_' . $row['table_owner']) + 1); + } + else if (strpos($row[$col], strtoupper($table_name)) === 0) + { + $row[$col] = substr($row[$col], strlen($table_name) + 1); + } break; case 'firebird': @@ -2203,6 +2210,7 @@ class phpbb_db_tools } else { + // TODO: try to change pkey without removing trigger, generator or constraints. ATM this query may fail. $statements[] = 'ALTER TABLE ' . $table_name . ' ALTER COLUMN "' . strtoupper($column_name) . '" TYPE ' . ' ' . $column_data['column_type_sql_type']; } break; From 85549fad8324afc6e9358e98d75b8fdcc5faa416 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Fri, 29 Apr 2011 01:46:01 -0400 Subject: [PATCH 6/7] [ticket/10003] Ported 1802b9ff9286a7fc24493e71b3432816cbdbfcd8 to db_tools. Most of it was already in db_tools, these changes could have applied to code that did not exist in db_tools at the time of the commit. PHPBB3-10003 --- phpBB/includes/db/db_tools.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/phpBB/includes/db/db_tools.php b/phpBB/includes/db/db_tools.php index 01061c77b1..fd09ccde3f 100644 --- a/phpBB/includes/db/db_tools.php +++ b/phpBB/includes/db/db_tools.php @@ -1130,7 +1130,7 @@ class phpbb_db_tools */ function sql_index_exists($table_name, $index_name) { - if ($this->sql_layer == 'mssql') + if ($this->sql_layer == 'mssql' || $this->sql_layer == 'mssqlnative') { $sql = "EXEC sp_statistics '$table_name'"; $result = $this->db->sql_query($sql); @@ -1235,7 +1235,7 @@ class phpbb_db_tools */ function sql_unique_index_exists($table_name, $index_name) { - if ($this->sql_layer == 'mssql') + if ($this->sql_layer == 'mssql' || $this->sql_layer == 'mssqlnative') { $sql = "EXEC sp_statistics '$table_name'"; $result = $this->db->sql_query($sql); From 1e2c19f4b443692b18a3a167dc464f63b19da47f Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Fri, 29 Apr 2011 02:16:02 -0400 Subject: [PATCH 7/7] [ticket/10003] Delete EOL at EOF for the benefit of 3.0 modifications. PHPBB3-10003 --- phpBB/includes/db/db_tools.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpBB/includes/db/db_tools.php b/phpBB/includes/db/db_tools.php index fd09ccde3f..483ceee043 100644 --- a/phpBB/includes/db/db_tools.php +++ b/phpBB/includes/db/db_tools.php @@ -2374,4 +2374,4 @@ class phpbb_db_tools } } -?> +?> \ No newline at end of file