SimpleMachines /
SMF2.1
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
| 1 | <?php |
||
| 2 | |||
| 3 | /** |
||
| 4 | * This file contains database functionality specifically designed for packages (mods) to utilize. |
||
| 5 | * |
||
| 6 | * Simple Machines Forum (SMF) |
||
| 7 | * |
||
| 8 | * @package SMF |
||
| 9 | * @author Simple Machines http://www.simplemachines.org |
||
| 10 | * @copyright 2017 Simple Machines and individual contributors |
||
| 11 | * @license http://www.simplemachines.org/about/smf/license.php BSD |
||
| 12 | * |
||
| 13 | * @version 2.1 Beta 3 |
||
| 14 | */ |
||
| 15 | |||
| 16 | if (!defined('SMF')) |
||
| 17 | die('No direct access...'); |
||
| 18 | |||
| 19 | /** |
||
| 20 | * Add the file functions to the $smcFunc array. |
||
| 21 | */ |
||
| 22 | View Code Duplication | function db_packages_init() |
|
| 23 | { |
||
| 24 | global $smcFunc, $reservedTables, $db_package_log, $db_prefix; |
||
| 25 | |||
| 26 | if (!isset($smcFunc['db_create_table']) || $smcFunc['db_create_table'] != 'smf_db_create_table') |
||
| 27 | { |
||
| 28 | $smcFunc += array( |
||
| 29 | 'db_add_column' => 'smf_db_add_column', |
||
| 30 | 'db_add_index' => 'smf_db_add_index', |
||
| 31 | 'db_calculate_type' => 'smf_db_calculate_type', |
||
| 32 | 'db_change_column' => 'smf_db_change_column', |
||
| 33 | 'db_create_table' => 'smf_db_create_table', |
||
| 34 | 'db_drop_table' => 'smf_db_drop_table', |
||
| 35 | 'db_table_structure' => 'smf_db_table_structure', |
||
| 36 | 'db_list_columns' => 'smf_db_list_columns', |
||
| 37 | 'db_list_indexes' => 'smf_db_list_indexes', |
||
| 38 | 'db_remove_column' => 'smf_db_remove_column', |
||
| 39 | 'db_remove_index' => 'smf_db_remove_index', |
||
| 40 | ); |
||
| 41 | $db_package_log = array(); |
||
| 42 | } |
||
| 43 | |||
| 44 | // We setup an array of SMF tables we can't do auto-remove on - in case a mod writer cocks it up! |
||
| 45 | $reservedTables = array('admin_info_files', 'approval_queue', 'attachments', 'ban_groups', 'ban_items', |
||
| 46 | 'board_permissions', 'boards', 'calendar', 'calendar_holidays', 'categories', |
||
| 47 | 'custom_fields', 'group_moderators', 'log_actions', 'log_activity', 'log_banned', 'log_boards', |
||
| 48 | 'log_digest', 'log_errors', 'log_floodcontrol', 'log_group_requests', 'log_mark_read', |
||
| 49 | 'log_notify', 'log_online', 'log_packages', 'log_polls', 'log_reported', 'log_reported_comments', |
||
| 50 | 'log_scheduled_tasks', 'log_search_messages', 'log_search_results', 'log_search_subjects', |
||
| 51 | 'log_search_topics', 'log_topics', 'mail_queue', 'membergroups', 'members', 'message_icons', |
||
| 52 | 'messages', 'moderators', 'package_servers', 'permission_profiles', 'permissions', 'personal_messages', |
||
| 53 | 'pm_recipients', 'poll_choices', 'polls', 'scheduled_tasks', 'sessions', 'settings', 'smileys', |
||
| 54 | 'themes', 'topics'); |
||
| 55 | foreach ($reservedTables as $k => $table_name) |
||
| 56 | $reservedTables[$k] = strtolower($db_prefix . $table_name); |
||
| 57 | |||
| 58 | // We in turn may need the extra stuff. |
||
| 59 | db_extend('extra'); |
||
| 60 | } |
||
| 61 | |||
| 62 | /** |
||
| 63 | * This function can be used to create a table without worrying about schema |
||
| 64 | * compatibilities across supported database systems. |
||
| 65 | * - If the table exists will, by default, do nothing. |
||
| 66 | * - Builds table with columns as passed to it - at least one column must be sent. |
||
| 67 | * The columns array should have one sub-array for each column - these sub arrays contain: |
||
| 68 | * 'name' = Column name |
||
| 69 | * 'type' = Type of column - values from (smallint, mediumint, int, text, varchar, char, tinytext, mediumtext, largetext) |
||
| 70 | * 'size' => Size of column (If applicable) - for example 255 for a large varchar, 10 for an int etc. |
||
| 71 | * If not set SMF will pick a size. |
||
| 72 | * - 'default' = Default value - do not set if no default required. |
||
| 73 | * - 'null' => Can it be null (true or false) - if not set default will be false. |
||
| 74 | * - 'auto' => Set to true to make it an auto incrementing column. Set to a numerical value to set from what |
||
| 75 | * it should begin counting. |
||
| 76 | * - Adds indexes as specified within indexes parameter. Each index should be a member of $indexes. Values are: |
||
| 77 | * - 'name' => Index name (If left empty SMF will generate). |
||
| 78 | * - 'type' => Type of index. Choose from 'primary', 'unique' or 'index'. If not set will default to 'index'. |
||
| 79 | * - 'columns' => Array containing columns that form part of key - in the order the index is to be created. |
||
| 80 | * - parameters: (None yet) |
||
| 81 | * - if_exists values: |
||
| 82 | * - 'ignore' will do nothing if the table exists. (And will return true) |
||
| 83 | * - 'overwrite' will drop any existing table of the same name. |
||
| 84 | * - 'error' will return false if the table already exists. |
||
| 85 | * |
||
| 86 | * @param string $table_name The name of the table to create |
||
| 87 | * @param array $columns An array of column info in the specified format |
||
| 88 | * @param array $indexes An array of index info in the specified format |
||
| 89 | * @param array $parameters Currently not used |
||
| 90 | * @param string $if_exists What to do if the table exists. |
||
| 91 | * @param string $error |
||
| 92 | */ |
||
| 93 | function smf_db_create_table($table_name, $columns, $indexes = array(), $parameters = array(), $if_exists = 'ignore', $error = 'fatal') |
||
| 94 | { |
||
| 95 | global $reservedTables, $smcFunc, $db_package_log, $db_prefix; |
||
| 96 | |||
| 97 | // Strip out the table name, we might not need it in some cases |
||
| 98 | $real_prefix = preg_match('~^("?)(.+?)\\1\\.(.*?)$~', $db_prefix, $match) === 1 ? $match[3] : $db_prefix; |
||
| 99 | |||
| 100 | // With or without the database name, the fullname looks like this. |
||
| 101 | $full_table_name = str_replace('{db_prefix}', $real_prefix, $table_name); |
||
| 102 | $table_name = str_replace('{db_prefix}', $db_prefix, $table_name); |
||
| 103 | |||
| 104 | // First - no way do we touch SMF tables. |
||
| 105 | if (in_array(strtolower($table_name), $reservedTables)) |
||
| 106 | return false; |
||
| 107 | |||
| 108 | // Log that we'll want to remove this on uninstall. |
||
| 109 | $db_package_log[] = array('remove_table', $table_name); |
||
| 110 | |||
| 111 | // This... my friends... is a function in a half - let's start by checking if the table exists! |
||
| 112 | $tables = $smcFunc['db_list_tables'](); |
||
| 113 | View Code Duplication | if (in_array($full_table_name, $tables)) |
|
| 114 | { |
||
| 115 | // This is a sad day... drop the table? If not, return false (error) by default. |
||
| 116 | if ($if_exists == 'overwrite') |
||
| 117 | $smcFunc['db_drop_table']($table_name); |
||
| 118 | else |
||
| 119 | return $if_exists == 'ignore'; |
||
| 120 | } |
||
| 121 | |||
| 122 | // If we've got this far - good news - no table exists. We can build our own! |
||
| 123 | $smcFunc['db_transaction']('begin'); |
||
| 124 | $table_query = 'CREATE TABLE ' . $table_name . "\n" . '('; |
||
| 125 | foreach ($columns as $column) |
||
| 126 | { |
||
| 127 | // If we have an auto increment do it! |
||
| 128 | if (!empty($column['auto'])) |
||
| 129 | { |
||
| 130 | $smcFunc['db_query']('', ' |
||
| 131 | CREATE SEQUENCE ' . $table_name . '_seq', |
||
| 132 | array( |
||
| 133 | 'security_override' => true, |
||
| 134 | ) |
||
| 135 | ); |
||
| 136 | $default = 'default nextval(\'' . $table_name . '_seq\')'; |
||
| 137 | } |
||
| 138 | View Code Duplication | elseif (isset($column['default']) && $column['default'] !== null) |
|
| 139 | $default = 'default \'' . $smcFunc['db_escape_string']($column['default']) . '\''; |
||
| 140 | else |
||
| 141 | $default = ''; |
||
| 142 | |||
| 143 | // Sort out the size... |
||
| 144 | $column['size'] = isset($column['size']) && is_numeric($column['size']) ? $column['size'] : null; |
||
| 145 | list ($type, $size) = $smcFunc['db_calculate_type']($column['type'], $column['size']); |
||
| 146 | if ($size !== null) |
||
| 147 | $type = $type . '(' . $size . ')'; |
||
| 148 | |||
| 149 | // Now just put it together! |
||
| 150 | $table_query .= "\n\t\"" . $column['name'] . '" ' . $type . ' ' . (!empty($column['null']) ? '' : 'NOT NULL') . ' ' . $default . ','; |
||
| 151 | } |
||
| 152 | |||
| 153 | // Loop through the indexes a sec... |
||
| 154 | $index_queries = array(); |
||
| 155 | foreach ($indexes as $index) |
||
| 156 | { |
||
| 157 | $columns = implode(',', $index['columns']); |
||
| 158 | |||
| 159 | // Primary goes in the table... |
||
| 160 | if (isset($index['type']) && $index['type'] == 'primary') |
||
| 161 | $table_query .= "\n\t" . 'PRIMARY KEY (' . implode(',', $index['columns']) . '),'; |
||
| 162 | else |
||
| 163 | { |
||
| 164 | if (empty($index['name'])) |
||
| 165 | $index['name'] = implode('_', $index['columns']); |
||
| 166 | $index_queries[] = 'CREATE ' . (isset($index['type']) && $index['type'] == 'unique' ? 'UNIQUE' : '') . ' INDEX ' . $table_name . '_' . $index['name'] . ' ON ' . $table_name . ' (' . $columns . ')'; |
||
| 167 | } |
||
| 168 | } |
||
| 169 | |||
| 170 | // No trailing commas! |
||
| 171 | View Code Duplication | if (substr($table_query, -1) == ',') |
|
| 172 | $table_query = substr($table_query, 0, -1); |
||
| 173 | |||
| 174 | $table_query .= ')'; |
||
| 175 | |||
| 176 | // Create the table! |
||
| 177 | $smcFunc['db_query']('', $table_query, |
||
| 178 | array( |
||
| 179 | 'security_override' => true, |
||
| 180 | ) |
||
| 181 | ); |
||
| 182 | // And the indexes... |
||
| 183 | foreach ($index_queries as $query) |
||
| 184 | $smcFunc['db_query']('', $query, |
||
| 185 | array( |
||
| 186 | 'security_override' => true, |
||
| 187 | ) |
||
| 188 | ); |
||
| 189 | |||
| 190 | // Go, go power rangers! |
||
| 191 | $smcFunc['db_transaction']('commit'); |
||
| 192 | |||
| 193 | return true; |
||
| 194 | } |
||
| 195 | |||
| 196 | /** |
||
| 197 | * Drop a table and its associated sequences. |
||
| 198 | * |
||
| 199 | * @param string $table_name The name of the table to drop |
||
| 200 | * @param array $parameters Not used at the moment |
||
| 201 | * @param string $error |
||
| 202 | * @return boolean Whether or not the operation was successful |
||
| 203 | */ |
||
| 204 | function smf_db_drop_table($table_name, $parameters = array(), $error = 'fatal') |
||
| 205 | { |
||
| 206 | global $reservedTables, $smcFunc, $db_prefix; |
||
| 207 | |||
| 208 | // After stripping away the database name, this is what's left. |
||
| 209 | $real_prefix = preg_match('~^("?)(.+?)\\1\\.(.*?)$~', $db_prefix, $match) === 1 ? $match[3] : $db_prefix; |
||
| 210 | |||
| 211 | // Get some aliases. |
||
| 212 | $full_table_name = str_replace('{db_prefix}', $real_prefix, $table_name); |
||
| 213 | $table_name = str_replace('{db_prefix}', $db_prefix, $table_name); |
||
| 214 | |||
| 215 | // God no - dropping one of these = bad. |
||
| 216 | if (in_array(strtolower($table_name), $reservedTables)) |
||
| 217 | return false; |
||
| 218 | |||
| 219 | // Does it exist? |
||
| 220 | if (in_array($full_table_name, $smcFunc['db_list_tables']())) |
||
| 221 | { |
||
| 222 | // We can then drop the table. |
||
| 223 | $smcFunc['db_transaction']('begin'); |
||
| 224 | |||
| 225 | // the table |
||
| 226 | $table_query = 'DROP TABLE ' . $table_name; |
||
| 227 | |||
| 228 | // and the assosciated sequence, if any |
||
| 229 | $sequence_query = 'DROP SEQUENCE IF EXISTS ' . $table_name . '_seq'; |
||
| 230 | |||
| 231 | // drop them |
||
| 232 | $smcFunc['db_query']('', |
||
| 233 | $table_query, |
||
| 234 | array( |
||
| 235 | 'security_override' => true, |
||
| 236 | ) |
||
| 237 | ); |
||
| 238 | $smcFunc['db_query']('', |
||
| 239 | $sequence_query, |
||
| 240 | array( |
||
| 241 | 'security_override' => true, |
||
| 242 | ) |
||
| 243 | ); |
||
| 244 | |||
| 245 | $smcFunc['db_transaction']('commit'); |
||
| 246 | |||
| 247 | return true; |
||
| 248 | } |
||
| 249 | |||
| 250 | // Otherwise do 'nout. |
||
| 251 | return false; |
||
| 252 | } |
||
| 253 | |||
| 254 | /** |
||
| 255 | * This function adds a column. |
||
| 256 | * |
||
| 257 | * @param string $table_name The name of the table to add the column to |
||
| 258 | * @param array $column_info An array of column info (see {@link smf_db_create_table()}) |
||
| 259 | * @param array $parameters Not used? |
||
| 260 | * @param string $if_exists What to do if the column exists. If 'update', column is updated. |
||
| 261 | * @param string $error |
||
| 262 | * @return boolean Whether or not the operation was successful |
||
| 263 | */ |
||
| 264 | function smf_db_add_column($table_name, $column_info, $parameters = array(), $if_exists = 'update', $error = 'fatal') |
||
| 265 | { |
||
| 266 | global $smcFunc, $db_package_log, $db_prefix; |
||
| 267 | |||
| 268 | $table_name = str_replace('{db_prefix}', $db_prefix, $table_name); |
||
| 269 | |||
| 270 | // Log that we will want to uninstall this! |
||
| 271 | $db_package_log[] = array('remove_column', $table_name, $column_info['name']); |
||
| 272 | |||
| 273 | // Does it exist - if so don't add it again! |
||
| 274 | $columns = $smcFunc['db_list_columns']($table_name, false); |
||
| 275 | View Code Duplication | foreach ($columns as $column) |
|
| 276 | if ($column == $column_info['name']) |
||
| 277 | { |
||
| 278 | // If we're going to overwrite then use change column. |
||
| 279 | if ($if_exists == 'update') |
||
| 280 | return $smcFunc['db_change_column']($table_name, $column_info['name'], $column_info); |
||
| 281 | else |
||
| 282 | return false; |
||
| 283 | } |
||
| 284 | |||
| 285 | // Get the specifics... |
||
| 286 | $column_info['size'] = isset($column_info['size']) && is_numeric($column_info['size']) ? $column_info['size'] : null; |
||
| 287 | list ($type, $size) = $smcFunc['db_calculate_type']($column_info['type'], $column_info['size']); |
||
| 288 | if ($size !== null) |
||
| 289 | $type = $type . '(' . $size . ')'; |
||
| 290 | |||
| 291 | // Now add the thing! |
||
| 292 | $query = ' |
||
| 293 | ALTER TABLE ' . $table_name . ' |
||
| 294 | ADD COLUMN ' . $column_info['name'] . ' ' . $type; |
||
| 295 | $smcFunc['db_query']('', $query, |
||
| 296 | array( |
||
| 297 | 'security_override' => true, |
||
| 298 | ) |
||
| 299 | ); |
||
| 300 | |||
| 301 | // If there's more attributes they need to be done via a change on PostgreSQL. |
||
| 302 | unset($column_info['type'], $column_info['size']); |
||
| 303 | |||
| 304 | if (count($column_info) != 1) |
||
| 305 | return $smcFunc['db_change_column']($table_name, $column_info['name'], $column_info); |
||
| 306 | else |
||
| 307 | return true; |
||
| 308 | } |
||
| 309 | |||
| 310 | /** |
||
| 311 | * Removes a column. |
||
| 312 | * |
||
| 313 | * @param string $table_name The name of the table to drop the column from |
||
| 314 | * @param string $column_name The name of the column to drop |
||
| 315 | * @param array $parameters Not used? |
||
| 316 | * @param string $error |
||
| 317 | * @return boolean Whether or not the operation was successful |
||
| 318 | */ |
||
| 319 | function smf_db_remove_column($table_name, $column_name, $parameters = array(), $error = 'fatal') |
||
| 320 | { |
||
| 321 | global $smcFunc, $db_prefix; |
||
| 322 | |||
| 323 | $table_name = str_replace('{db_prefix}', $db_prefix, $table_name); |
||
| 324 | |||
| 325 | // Does it exist? |
||
| 326 | $columns = $smcFunc['db_list_columns']($table_name, true); |
||
| 327 | foreach ($columns as $column) |
||
| 328 | if ($column['name'] == $column_name) |
||
| 329 | { |
||
| 330 | // If there is an auto we need remove it! |
||
| 331 | if ($column['auto']) |
||
| 332 | $smcFunc['db_query']('', |
||
| 333 | 'DROP SEQUENCE ' . $table_name . '_seq', |
||
| 334 | array( |
||
| 335 | 'security_override' => true, |
||
| 336 | ) |
||
| 337 | ); |
||
| 338 | |||
| 339 | $smcFunc['db_query']('', ' |
||
| 340 | ALTER TABLE ' . $table_name . ' |
||
| 341 | DROP COLUMN ' . $column_name, |
||
| 342 | array( |
||
| 343 | 'security_override' => true, |
||
| 344 | ) |
||
| 345 | ); |
||
| 346 | |||
| 347 | return true; |
||
| 348 | } |
||
| 349 | |||
| 350 | // If here we didn't have to work - joy! |
||
| 351 | return false; |
||
| 352 | } |
||
| 353 | |||
| 354 | /** |
||
| 355 | * Change a column. |
||
| 356 | * |
||
| 357 | * @param string $table_name The name of the table this column is in |
||
| 358 | * @param string $old_column The name of the column we want to change |
||
| 359 | * @param array $column_info An array of info about the "new" column definition (see {@link smf_db_create_table()}) |
||
| 360 | * @return bool |
||
| 361 | */ |
||
| 362 | function smf_db_change_column($table_name, $old_column, $column_info) |
||
|
0 ignored issues
–
show
|
|||
| 363 | { |
||
| 364 | global $smcFunc, $db_prefix; |
||
| 365 | |||
| 366 | $table_name = str_replace('{db_prefix}', $db_prefix, $table_name); |
||
| 367 | |||
| 368 | // Check it does exist! |
||
| 369 | $columns = $smcFunc['db_list_columns']($table_name, true); |
||
| 370 | $old_info = null; |
||
| 371 | foreach ($columns as $column) |
||
| 372 | if ($column['name'] == $old_column) |
||
| 373 | $old_info = $column; |
||
| 374 | |||
| 375 | // Nothing? |
||
| 376 | if ($old_info == null) |
||
| 377 | return false; |
||
| 378 | |||
| 379 | // Now we check each bit individually and ALTER as required. |
||
| 380 | if (isset($column_info['name']) && $column_info['name'] != $old_column) |
||
| 381 | { |
||
| 382 | $smcFunc['db_query']('', ' |
||
| 383 | ALTER TABLE ' . $table_name . ' |
||
| 384 | RENAME COLUMN ' . $old_column . ' TO ' . $column_info['name'], |
||
| 385 | array( |
||
| 386 | 'security_override' => true, |
||
| 387 | ) |
||
| 388 | ); |
||
| 389 | } |
||
| 390 | // Different default? |
||
| 391 | View Code Duplication | if (isset($column_info['default']) && $column_info['default'] != $old_info['default']) |
|
| 392 | { |
||
| 393 | $action = $column_info['default'] !== null ? 'SET DEFAULT \'' . $smcFunc['db_escape_string']($column_info['default']) . '\'' : 'DROP DEFAULT'; |
||
| 394 | $smcFunc['db_query']('', ' |
||
| 395 | ALTER TABLE ' . $table_name . ' |
||
| 396 | ALTER COLUMN ' . $column_info['name'] . ' ' . $action, |
||
| 397 | array( |
||
| 398 | 'security_override' => true, |
||
| 399 | ) |
||
| 400 | ); |
||
| 401 | } |
||
| 402 | // Is it null - or otherwise? |
||
| 403 | if (isset($column_info['null']) && $column_info['null'] != $old_info['null']) |
||
| 404 | { |
||
| 405 | $action = $column_info['null'] ? 'DROP' : 'SET'; |
||
| 406 | $smcFunc['db_transaction']('begin'); |
||
| 407 | View Code Duplication | if (!$column_info['null']) |
|
| 408 | { |
||
| 409 | // We have to set it to something if we are making it NOT NULL. And we must comply with the current column format. |
||
| 410 | $setTo = isset($column_info['default']) ? $column_info['default'] : (strpos($old_info['type'], 'int') !== false ? 0 : ''); |
||
| 411 | $smcFunc['db_query']('', ' |
||
| 412 | UPDATE ' . $table_name . ' |
||
| 413 | SET ' . $column_info['name'] . ' = \'' . $setTo . '\' |
||
| 414 | WHERE ' . $column_info['name'] . ' IS NULL', |
||
| 415 | array( |
||
| 416 | 'security_override' => true, |
||
| 417 | ) |
||
| 418 | ); |
||
| 419 | } |
||
| 420 | $smcFunc['db_query']('', ' |
||
| 421 | ALTER TABLE ' . $table_name . ' |
||
| 422 | ALTER COLUMN ' . $column_info['name'] . ' ' . $action . ' NOT NULL', |
||
| 423 | array( |
||
| 424 | 'security_override' => true, |
||
| 425 | ) |
||
| 426 | ); |
||
| 427 | $smcFunc['db_transaction']('commit'); |
||
| 428 | } |
||
| 429 | // What about a change in type? |
||
| 430 | if (isset($column_info['type']) && ($column_info['type'] != $old_info['type'] || (isset($column_info['size']) && $column_info['size'] != $old_info['size']))) |
||
| 431 | { |
||
| 432 | $column_info['size'] = isset($column_info['size']) && is_numeric($column_info['size']) ? $column_info['size'] : null; |
||
| 433 | list ($type, $size) = $smcFunc['db_calculate_type']($column_info['type'], $column_info['size']); |
||
| 434 | if ($size !== null) |
||
| 435 | $type = $type . '(' . $size . ')'; |
||
| 436 | |||
| 437 | // The alter is a pain. |
||
| 438 | $smcFunc['db_transaction']('begin'); |
||
| 439 | $smcFunc['db_query']('', ' |
||
| 440 | ALTER TABLE ' . $table_name . ' |
||
| 441 | ADD COLUMN ' . $column_info['name'] . '_tempxx ' . $type, |
||
| 442 | array( |
||
| 443 | 'security_override' => true, |
||
| 444 | ) |
||
| 445 | ); |
||
| 446 | $smcFunc['db_query']('', ' |
||
| 447 | UPDATE ' . $table_name . ' |
||
| 448 | SET ' . $column_info['name'] . '_tempxx = CAST(' . $column_info['name'] . ' AS ' . $type . ')', |
||
| 449 | array( |
||
| 450 | 'security_override' => true, |
||
| 451 | ) |
||
| 452 | ); |
||
| 453 | $smcFunc['db_query']('', ' |
||
| 454 | ALTER TABLE ' . $table_name . ' |
||
| 455 | DROP COLUMN ' . $column_info['name'], |
||
| 456 | array( |
||
| 457 | 'security_override' => true, |
||
| 458 | ) |
||
| 459 | ); |
||
| 460 | $smcFunc['db_query']('', ' |
||
| 461 | ALTER TABLE ' . $table_name . ' |
||
| 462 | RENAME COLUMN ' . $column_info['name'] . '_tempxx TO ' . $column_info['name'], |
||
| 463 | array( |
||
| 464 | 'security_override' => true, |
||
| 465 | ) |
||
| 466 | ); |
||
| 467 | $smcFunc['db_transaction']('commit'); |
||
| 468 | } |
||
| 469 | // Finally - auto increment?! |
||
| 470 | if (isset($column_info['auto']) && $column_info['auto'] != $old_info['auto']) |
||
| 471 | { |
||
| 472 | // Are we removing an old one? |
||
| 473 | if ($old_info['auto']) |
||
| 474 | { |
||
| 475 | // Alter the table first - then drop the sequence. |
||
| 476 | $smcFunc['db_query']('', ' |
||
| 477 | ALTER TABLE ' . $table_name . ' |
||
| 478 | ALTER COLUMN ' . $column_info['name'] . ' SET DEFAULT \'0\'', |
||
| 479 | array( |
||
| 480 | 'security_override' => true, |
||
| 481 | ) |
||
| 482 | ); |
||
| 483 | $smcFunc['db_query']('', ' |
||
| 484 | DROP SEQUENCE ' . $table_name . '_seq', |
||
| 485 | array( |
||
| 486 | 'security_override' => true, |
||
| 487 | ) |
||
| 488 | ); |
||
| 489 | } |
||
| 490 | // Otherwise add it! |
||
| 491 | else |
||
| 492 | { |
||
| 493 | $smcFunc['db_query']('', ' |
||
| 494 | CREATE SEQUENCE ' . $table_name . '_seq', |
||
| 495 | array( |
||
| 496 | 'security_override' => true, |
||
| 497 | ) |
||
| 498 | ); |
||
| 499 | $smcFunc['db_query']('', ' |
||
| 500 | ALTER TABLE ' . $table_name . ' |
||
| 501 | ALTER COLUMN ' . $column_info['name'] . ' SET DEFAULT nextval(\'' . $table_name . '_seq\')', |
||
| 502 | array( |
||
| 503 | 'security_override' => true, |
||
| 504 | ) |
||
| 505 | ); |
||
| 506 | } |
||
| 507 | } |
||
| 508 | |||
| 509 | return true; |
||
| 510 | } |
||
| 511 | |||
| 512 | /** |
||
| 513 | * Add an index. |
||
| 514 | * |
||
| 515 | * @param string $table_name The name of the table to add the index to |
||
| 516 | * @param array $index_info An array of index info (see {@link smf_db_create_table()}) |
||
| 517 | * @param array $parameters Not used? |
||
| 518 | * @param string $if_exists What to do if the index exists. If 'update', the definition will be updated. |
||
| 519 | * @param string $error |
||
| 520 | * @return boolean Whether or not the operation was successful |
||
| 521 | */ |
||
| 522 | function smf_db_add_index($table_name, $index_info, $parameters = array(), $if_exists = 'update', $error = 'fatal') |
||
| 523 | { |
||
| 524 | global $smcFunc, $db_package_log, $db_prefix; |
||
| 525 | |||
| 526 | $table_name = str_replace('{db_prefix}', $db_prefix, $table_name); |
||
| 527 | |||
| 528 | // No columns = no index. |
||
| 529 | if (empty($index_info['columns'])) |
||
| 530 | return false; |
||
| 531 | $columns = implode(',', $index_info['columns']); |
||
| 532 | |||
| 533 | // No name - make it up! |
||
| 534 | if (empty($index_info['name'])) |
||
| 535 | { |
||
| 536 | // No need for primary. |
||
| 537 | if (isset($index_info['type']) && $index_info['type'] == 'primary') |
||
| 538 | $index_info['name'] = ''; |
||
| 539 | else |
||
| 540 | $index_info['name'] = $table_name . implode('_', $index_info['columns']); |
||
| 541 | } |
||
| 542 | else |
||
| 543 | $index_info['name'] = $table_name . $index_info['name']; |
||
| 544 | |||
| 545 | // Log that we are going to want to remove this! |
||
| 546 | $db_package_log[] = array('remove_index', $table_name, $index_info['name']); |
||
| 547 | |||
| 548 | // Let's get all our indexes. |
||
| 549 | $indexes = $smcFunc['db_list_indexes']($table_name, true); |
||
| 550 | // Do we already have it? |
||
| 551 | foreach ($indexes as $index) |
||
| 552 | { |
||
| 553 | if ($index['name'] == $index_info['name'] || ($index['type'] == 'primary' && isset($index_info['type']) && $index_info['type'] == 'primary')) |
||
| 554 | { |
||
| 555 | // If we want to overwrite simply remove the current one then continue. |
||
| 556 | if ($if_exists != 'update' || $index['type'] == 'primary') |
||
| 557 | return false; |
||
| 558 | else |
||
| 559 | $smcFunc['db_remove_index']($table_name, $index_info['name']); |
||
| 560 | } |
||
| 561 | } |
||
| 562 | |||
| 563 | // If we're here we know we don't have the index - so just add it. |
||
| 564 | if (!empty($index_info['type']) && $index_info['type'] == 'primary') |
||
| 565 | { |
||
| 566 | $smcFunc['db_query']('', ' |
||
| 567 | ALTER TABLE ' . $table_name . ' |
||
| 568 | ADD PRIMARY KEY (' . $columns . ')', |
||
| 569 | array( |
||
| 570 | 'security_override' => true, |
||
| 571 | ) |
||
| 572 | ); |
||
| 573 | } |
||
| 574 | else |
||
| 575 | { |
||
| 576 | $smcFunc['db_query']('', ' |
||
| 577 | CREATE ' . (isset($index_info['type']) && $index_info['type'] == 'unique' ? 'UNIQUE' : '') . ' INDEX ' . $index_info['name'] . ' ON ' . $table_name . ' (' . $columns . ')', |
||
| 578 | array( |
||
| 579 | 'security_override' => true, |
||
| 580 | ) |
||
| 581 | ); |
||
| 582 | } |
||
| 583 | } |
||
| 584 | |||
| 585 | /** |
||
| 586 | * Remove an index. |
||
| 587 | * |
||
| 588 | * @param string $table_name The name of the table to remove the index from |
||
| 589 | * @param string $index_name The name of the index to remove |
||
| 590 | * @param array $parameters Not used? |
||
| 591 | * @param string $error |
||
| 592 | * @return boolean Whether or not the operation was successful |
||
| 593 | */ |
||
| 594 | function smf_db_remove_index($table_name, $index_name, $parameters = array(), $error = 'fatal') |
||
| 595 | { |
||
| 596 | global $smcFunc, $db_prefix; |
||
| 597 | |||
| 598 | $table_name = str_replace('{db_prefix}', $db_prefix, $table_name); |
||
| 599 | |||
| 600 | // Better exist! |
||
| 601 | $indexes = $smcFunc['db_list_indexes']($table_name, true); |
||
| 602 | if ($index_name != 'primary') |
||
| 603 | $index_name = $table_name . '_' . $index_name; |
||
| 604 | |||
| 605 | View Code Duplication | foreach ($indexes as $index) |
|
| 606 | { |
||
| 607 | // If the name is primary we want the primary key! |
||
| 608 | if ($index['type'] == 'primary' && $index_name == 'primary') |
||
| 609 | { |
||
| 610 | // Dropping primary key is odd... |
||
| 611 | $smcFunc['db_query']('', ' |
||
| 612 | ALTER TABLE ' . $table_name . ' |
||
| 613 | DROP CONSTRAINT ' . $index['name'], |
||
| 614 | array( |
||
| 615 | 'security_override' => true, |
||
| 616 | ) |
||
| 617 | ); |
||
| 618 | |||
| 619 | return true; |
||
| 620 | } |
||
| 621 | if ($index['name'] == $index_name) |
||
| 622 | { |
||
| 623 | // Drop the bugger... |
||
| 624 | $smcFunc['db_query']('', ' |
||
| 625 | DROP INDEX ' . $index_name, |
||
| 626 | array( |
||
| 627 | 'security_override' => true, |
||
| 628 | ) |
||
| 629 | ); |
||
| 630 | |||
| 631 | return true; |
||
| 632 | } |
||
| 633 | } |
||
| 634 | |||
| 635 | // Not to be found ;( |
||
| 636 | return false; |
||
| 637 | } |
||
| 638 | |||
| 639 | /** |
||
| 640 | * Get the schema formatted name for a type. |
||
| 641 | * |
||
| 642 | * @param string $type_name The data type (int, varchar, smallint, etc.) |
||
| 643 | * @param int $type_size The size (8, 255, etc.) |
||
| 644 | * @param boolean $reverse If true, returns specific types for a generic type |
||
| 645 | * @return array An array containing the appropriate type and size for this DB type |
||
| 646 | */ |
||
| 647 | function smf_db_calculate_type($type_name, $type_size = null, $reverse = false) |
||
| 648 | { |
||
| 649 | // Let's be sure it's lowercase MySQL likes both, others no. |
||
| 650 | $type_name = strtolower($type_name); |
||
| 651 | // Generic => Specific. |
||
| 652 | if (!$reverse) |
||
| 653 | { |
||
| 654 | $types = array( |
||
| 655 | 'varchar' => 'character varying', |
||
| 656 | 'char' => 'character', |
||
| 657 | 'mediumint' => 'int', |
||
| 658 | 'tinyint' => 'smallint', |
||
| 659 | 'tinytext' => 'character varying', |
||
| 660 | 'mediumtext' => 'text', |
||
| 661 | 'largetext' => 'text', |
||
| 662 | 'inet' => 'inet', |
||
| 663 | 'time' => 'time without time zone', |
||
| 664 | 'datetime' => 'timestamp without time zone', |
||
| 665 | 'timestamp' => 'timestamp without time zone', |
||
| 666 | ); |
||
| 667 | } |
||
| 668 | else |
||
| 669 | { |
||
| 670 | $types = array( |
||
| 671 | 'character varying' => 'varchar', |
||
| 672 | 'character' => 'char', |
||
| 673 | 'integer' => 'int', |
||
| 674 | 'inet' => 'inet', |
||
| 675 | 'time without time zone' => 'time', |
||
| 676 | 'timestamp without time zone' => 'datetime', |
||
| 677 | 'numeric' => 'decimal', |
||
| 678 | ); |
||
| 679 | } |
||
| 680 | |||
| 681 | // Got it? Change it! |
||
| 682 | if (isset($types[$type_name])) |
||
| 683 | { |
||
| 684 | if ($type_name == 'tinytext') |
||
| 685 | $type_size = 255; |
||
| 686 | $type_name = $types[$type_name]; |
||
| 687 | } |
||
| 688 | |||
| 689 | // Only char fields got size |
||
| 690 | if (strpos($type_name, 'char') === false) |
||
| 691 | $type_size = null; |
||
| 692 | |||
| 693 | |||
| 694 | return array($type_name, $type_size); |
||
| 695 | } |
||
| 696 | |||
| 697 | /** |
||
| 698 | * Get table structure. |
||
| 699 | * |
||
| 700 | * @param string $table_name The name of the table |
||
| 701 | * @return array An array of table structure - the name, the column info from {@link smf_db_list_columns()} and the index info from {@link smf_db_list_indexes()} |
||
| 702 | */ |
||
| 703 | function smf_db_table_structure($table_name) |
||
|
0 ignored issues
–
show
The function
smf_db_table_structure() has been defined more than once; this definition is ignored, only the first definition in Sources/DbPackages-mysql.php (L549-575) is considered.
This check looks for functions that have already been defined in other files. Some Codebases, like WordPress, make a practice of defining functions multiple times. This
may lead to problems with the detection of function parameters and types. If you really
need to do this, you can mark the duplicate definition with the /**
* @ignore
*/
function getUser() {
}
function getUser($id, $realm) {
}
See also the PhpDoc documentation for @ignore. Loading history...
|
|||
| 704 | { |
||
| 705 | global $smcFunc, $db_prefix; |
||
| 706 | |||
| 707 | $table_name = str_replace('{db_prefix}', $db_prefix, $table_name); |
||
| 708 | |||
| 709 | return array( |
||
| 710 | 'name' => $table_name, |
||
| 711 | 'columns' => $smcFunc['db_list_columns']($table_name, true), |
||
| 712 | 'indexes' => $smcFunc['db_list_indexes']($table_name, true), |
||
| 713 | ); |
||
| 714 | } |
||
| 715 | |||
| 716 | /** |
||
| 717 | * Return column information for a table. |
||
| 718 | * |
||
| 719 | * @param string $table_name The name of the table to get column info for |
||
| 720 | * @param bool $detail Whether or not to return detailed info. If true, returns the column info. If false, just returns the column names. |
||
| 721 | * @param array $parameters Not used? |
||
| 722 | * @return array An array of column names or detailed column info, depending on $detail |
||
| 723 | */ |
||
| 724 | function smf_db_list_columns($table_name, $detail = false, $parameters = array()) |
||
| 725 | { |
||
| 726 | global $smcFunc, $db_prefix; |
||
| 727 | |||
| 728 | $table_name = str_replace('{db_prefix}', $db_prefix, $table_name); |
||
| 729 | |||
| 730 | $result = $smcFunc['db_query']('', ' |
||
| 731 | SELECT column_name, column_default, is_nullable, data_type, character_maximum_length |
||
| 732 | FROM information_schema.columns |
||
| 733 | WHERE table_name = \'' . $table_name . '\' |
||
| 734 | ORDER BY ordinal_position', |
||
| 735 | array( |
||
| 736 | 'security_override' => true, |
||
| 737 | ) |
||
| 738 | ); |
||
| 739 | $columns = array(); |
||
| 740 | while ($row = $smcFunc['db_fetch_assoc']($result)) |
||
| 741 | { |
||
| 742 | if (!$detail) |
||
| 743 | { |
||
| 744 | $columns[] = $row['column_name']; |
||
| 745 | } |
||
| 746 | else |
||
| 747 | { |
||
| 748 | $auto = false; |
||
| 749 | // What is the default? |
||
| 750 | if (preg_match('~nextval\(\'(.+?)\'(.+?)*\)~i', $row['column_default'], $matches) != 0) |
||
| 751 | { |
||
| 752 | $default = null; |
||
| 753 | $auto = true; |
||
| 754 | } |
||
| 755 | elseif (trim($row['column_default']) != '') |
||
| 756 | $default = strpos($row['column_default'], '::') === false ? $row['column_default'] : substr($row['column_default'], 0, strpos($row['column_default'], '::')); |
||
| 757 | else |
||
| 758 | $default = null; |
||
| 759 | |||
| 760 | // Make the type generic. |
||
| 761 | list ($type, $size) = $smcFunc['db_calculate_type']($row['data_type'], $row['character_maximum_length'], true); |
||
| 762 | |||
| 763 | $columns[$row['column_name']] = array( |
||
| 764 | 'name' => $row['column_name'], |
||
| 765 | 'null' => $row['is_nullable'] ? true : false, |
||
| 766 | 'default' => $default, |
||
| 767 | 'type' => $type, |
||
| 768 | 'size' => $size, |
||
| 769 | 'auto' => $auto, |
||
| 770 | ); |
||
| 771 | } |
||
| 772 | } |
||
| 773 | $smcFunc['db_free_result']($result); |
||
| 774 | |||
| 775 | return $columns; |
||
| 776 | } |
||
| 777 | |||
| 778 | /** |
||
| 779 | * Get index information. |
||
| 780 | * |
||
| 781 | * @param string $table_name The name of the table to get indexes for |
||
| 782 | * @param bool $detail Whether or not to return detailed info. |
||
| 783 | * @param array $parameters Not used? |
||
| 784 | * @return array An array of index names or a detailed array of index info, depending on $detail |
||
| 785 | */ |
||
| 786 | function smf_db_list_indexes($table_name, $detail = false, $parameters = array()) |
||
| 787 | { |
||
| 788 | global $smcFunc, $db_prefix; |
||
| 789 | |||
| 790 | $table_name = str_replace('{db_prefix}', $db_prefix, $table_name); |
||
| 791 | |||
| 792 | $result = $smcFunc['db_query']('', ' |
||
| 793 | SELECT CASE WHEN i.indisprimary THEN 1 ELSE 0 END AS is_primary, |
||
| 794 | CASE WHEN i.indisunique THEN 1 ELSE 0 END AS is_unique, |
||
| 795 | c2.relname AS name, |
||
| 796 | pg_get_indexdef(i.indexrelid) AS inddef |
||
| 797 | FROM pg_class AS c, pg_class AS c2, pg_index AS i |
||
| 798 | WHERE c.relname = \'' . $table_name . '\' |
||
| 799 | AND c.oid = i.indrelid |
||
| 800 | AND i.indexrelid = c2.oid', |
||
| 801 | array( |
||
| 802 | 'security_override' => true, |
||
| 803 | ) |
||
| 804 | ); |
||
| 805 | $indexes = array(); |
||
| 806 | while ($row = $smcFunc['db_fetch_assoc']($result)) |
||
| 807 | { |
||
| 808 | // Try get the columns that make it up. |
||
| 809 | if (preg_match('~\(([^\)]+?)\)~i', $row['inddef'], $matches) == 0) |
||
| 810 | continue; |
||
| 811 | |||
| 812 | $columns = explode(',', $matches[1]); |
||
| 813 | |||
| 814 | if (empty($columns)) |
||
| 815 | continue; |
||
| 816 | |||
| 817 | foreach ($columns as $k => $v) |
||
| 818 | $columns[$k] = trim($v); |
||
| 819 | |||
| 820 | // Fix up the name to be consistent cross databases |
||
| 821 | if (substr($row['name'], -5) == '_pkey' && $row['is_primary'] == 1) |
||
| 822 | $row['name'] = 'PRIMARY'; |
||
| 823 | else |
||
| 824 | $row['name'] = str_replace($table_name . '_', '', $row['name']); |
||
| 825 | |||
| 826 | if (!$detail) |
||
| 827 | $indexes[] = $row['name']; |
||
| 828 | else |
||
| 829 | { |
||
| 830 | $indexes[$row['name']] = array( |
||
| 831 | 'name' => $row['name'], |
||
| 832 | 'type' => $row['is_primary'] ? 'primary' : ($row['is_unique'] ? 'unique' : 'index'), |
||
| 833 | 'columns' => $columns, |
||
| 834 | ); |
||
| 835 | } |
||
| 836 | } |
||
| 837 | $smcFunc['db_free_result']($result); |
||
| 838 | |||
| 839 | return $indexes; |
||
| 840 | } |
||
| 841 | |||
| 842 | ?> |
This check looks for functions that have already been defined in other files.
Some Codebases, like WordPress, make a practice of defining functions multiple times. This may lead to problems with the detection of function parameters and types. If you really need to do this, you can mark the duplicate definition with the
@ignoreannotation.See also the PhpDoc documentation for @ignore.