From: Meik S. <acy...@ph...> - 2009-09-24 15:36:53
|
Author: acydburn Date: Thu Sep 24 16:36:05 2009 New Revision: 10185 Log: I think i need to check other DBMS more often. :/ - fix index check for sqlite, firebird and oracle - add check for unique index - fix changing default value for column in mssql (add constraint) Modified: branches/phpBB-3_0_0/phpBB/includes/db/db_tools.php branches/phpBB-3_0_0/phpBB/install/database_update.php Modified: branches/phpBB-3_0_0/phpBB/includes/db/db_tools.php ============================================================================== *** branches/phpBB-3_0_0/phpBB/includes/db/db_tools.php (original) --- branches/phpBB-3_0_0/phpBB/includes/db/db_tools.php Thu Sep 24 16:36:05 2009 *************** *** 1190,1200 **** // For hexadecimal values do not use single quotes if (strpos($column_data[1], '0x') === 0) { ! $sql_default .= 'DEFAULT (' . $column_data[1] . ') '; } else { ! $sql_default .= 'DEFAULT (' . ((is_numeric($column_data[1])) ? $column_data[1] : "'{$column_data[1]}'") . ') '; } } --- 1190,1202 ---- // For hexadecimal values do not use single quotes if (strpos($column_data[1], '0x') === 0) { ! $return_array['default'] = 'DEFAULT (' . $column_data[1] . ') '; ! $sql_default .= $return_array['default']; } else { ! $return_array['default'] = 'DEFAULT (' . ((is_numeric($column_data[1])) ? $column_data[1] : "'{$column_data[1]}'") . ') '; ! $sql_default .= $return_array['default']; } } *************** *** 1781,1787 **** 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'; --- 1783,1789 ---- 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'; *************** *** 1808,1815 **** case 'oracle': $sql = "SELECT index_name FROM user_indexes ! WHERE table_name = '" . $table_name . "' ! AND generated = 'N'"; $col = 'index_name'; break; --- 1810,1818 ---- case 'oracle': $sql = "SELECT index_name FROM user_indexes ! WHERE table_name = '" . strtoupper($table_name) . "' ! AND generated = 'N' ! AND uniqueness = 'NONUNIQUE'"; $col = 'index_name'; break; *************** *** 1870,1875 **** --- 1873,1899 ---- case 'mssql': $statements[] = 'ALTER TABLE [' . $table_name . '] ALTER COLUMN [' . $column_name . '] ' . $column_data['column_type_sql']; + + if (!empty($column_data['default'])) + { + // Using TRANSACT-SQL for this statement because we do not want to have colliding data if statements are executed at a later stage + $statements[] = "DECLARE @drop_default_name VARCHAR(100), @cmd VARCHAR(1000) + SET @drop_default_name = + (SELECT so.name FROM sysobjects so + JOIN sysconstraints sc ON so.id = sc.constid + WHERE object_name(so.parent_obj) = '{$table_name}' + AND so.xtype = 'D' + AND sc.colid = (SELECT colid FROM syscolumns + WHERE id = object_id('{$table_name}') + AND name = '{$column_name}')) + IF @drop_default_name <> '' + BEGIN + SET @cmd = 'ALTER TABLE [{$table_name}] DROP CONSTRAINT [' + @drop_default_name + ']' + EXEC(@cmd) + END + SET @cmd = 'ALTER TABLE [{$table_name}] ADD CONSTRAINT [DF_{$table_name}_{$column_name}_1] {$column_data['default']} FOR [{$column_name}]' + EXEC(@cmd)"; + } break; case 'mysql_40': Modified: branches/phpBB-3_0_0/phpBB/install/database_update.php ============================================================================== *** branches/phpBB-3_0_0/phpBB/install/database_update.php (original) --- branches/phpBB-3_0_0/phpBB/install/database_update.php Thu Sep 24 16:36:05 2009 *************** *** 2003,2009 **** { foreach ($index_array as $index_name => $column) { ! if ($this->sql_index_exists($table, $index_name)) { continue; } --- 2003,2009 ---- { foreach ($index_array as $index_name => $column) { ! if ($this->sql_unique_index_exists($table, $index_name)) { continue; } *************** *** 2338,2344 **** } /** ! * 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 --- 2338,2344 ---- } /** ! * 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 *************** *** 2373,2379 **** 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'; --- 2373,2379 ---- 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'; *************** *** 2400,2411 **** 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; } --- 2400,2413 ---- case 'oracle': $sql = "SELECT index_name FROM user_indexes ! WHERE table_name = '" . strtoupper($table_name) . "' ! AND generated = 'N' ! AND uniqueness = 'NONUNIQUE'"; ! $col = 'index_name'; break; case 'sqlite': ! $sql = "PRAGMA index_list('" . $table_name . "');"; $col = 'name'; break; } *************** *** 2418,2423 **** --- 2420,2554 ---- 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 UNIQUE 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_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); *************** *** 2562,2572 **** // For hexadecimal values do not use single quotes if (strpos($column_data[1], '0x') === 0) { ! $sql_default .= 'DEFAULT (' . $column_data[1] . ') '; } else { ! $sql_default .= 'DEFAULT (' . ((is_numeric($column_data[1])) ? $column_data[1] : "'{$column_data[1]}'") . ') '; } } --- 2693,2705 ---- // For hexadecimal values do not use single quotes if (strpos($column_data[1], '0x') === 0) { ! $return_array['default'] = 'DEFAULT (' . $column_data[1] . ') '; ! $sql_default .= $return_array['default']; } else { ! $return_array['default'] = 'DEFAULT (' . ((is_numeric($column_data[1])) ? $column_data[1] : "'{$column_data[1]}'") . ') '; ! $sql_default .= $return_array['default']; } } *************** *** 3086,3091 **** --- 3219,3245 ---- case 'mssql': $statements[] = 'ALTER TABLE [' . $table_name . '] ALTER COLUMN [' . $column_name . '] ' . $column_data['column_type_sql']; + + if (!empty($column_data['default'])) + { + // Using TRANSACT-SQL for this statement because we do not want to have colliding data if statements are executed at a later stage + $statements[] = "DECLARE @drop_default_name VARCHAR(100), @cmd VARCHAR(1000) + SET @drop_default_name = + (SELECT so.name FROM sysobjects so + JOIN sysconstraints sc ON so.id = sc.constid + WHERE object_name(so.parent_obj) = '{$table_name}' + AND so.xtype = 'D' + AND sc.colid = (SELECT colid FROM syscolumns + WHERE id = object_id('{$table_name}') + AND name = '{$column_name}')) + IF @drop_default_name <> '' + BEGIN + SET @cmd = 'ALTER TABLE [{$table_name}] DROP CONSTRAINT [' + @drop_default_name + ']' + EXEC(@cmd) + END + SET @cmd = 'ALTER TABLE [{$table_name}] ADD CONSTRAINT [DF_{$table_name}_{$column_name}_1] {$column_data['default']} FOR [{$column_name}]' + EXEC(@cmd)"; + } break; case 'mysql_40': |