|
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 4 |
|
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 Extra parameters. Currently only 'engine', the desired MySQL storage engine, is used. |
|
90
|
|
|
* @param string $if_exists What to do if the table exists. |
|
91
|
|
|
* @param string $error |
|
92
|
|
|
* @return boolean Whether or not the operation was successful |
|
93
|
|
|
*/ |
|
94
|
|
|
function smf_db_create_table($table_name, $columns, $indexes = array(), $parameters = array(), $if_exists = 'ignore', $error = 'fatal') |
|
|
|
|
|
|
95
|
|
|
{ |
|
96
|
|
|
global $reservedTables, $smcFunc, $db_package_log, $db_prefix, $db_character_set; |
|
97
|
|
|
|
|
98
|
|
|
static $engines = array(); |
|
99
|
|
|
|
|
100
|
|
|
// Strip out the table name, we might not need it in some cases |
|
101
|
|
|
$real_prefix = preg_match('~^(`?)(.+?)\\1\\.(.*?)$~', $db_prefix, $match) === 1 ? $match[3] : $db_prefix; |
|
102
|
|
|
|
|
103
|
|
|
// With or without the database name, the fullname looks like this. |
|
104
|
|
|
$full_table_name = str_replace('{db_prefix}', $real_prefix, $table_name); |
|
105
|
|
|
$table_name = str_replace('{db_prefix}', $db_prefix, $table_name); |
|
106
|
|
|
|
|
107
|
|
|
// First - no way do we touch SMF tables. |
|
108
|
|
|
if (in_array(strtolower($table_name), $reservedTables)) |
|
109
|
|
|
return false; |
|
110
|
|
|
|
|
111
|
|
|
// Log that we'll want to remove this on uninstall. |
|
112
|
|
|
$db_package_log[] = array('remove_table', $table_name); |
|
113
|
|
|
|
|
114
|
|
|
// Slightly easier on MySQL than the others... |
|
115
|
|
|
$tables = $smcFunc['db_list_tables'](); |
|
116
|
|
View Code Duplication |
if (in_array($full_table_name, $tables)) |
|
117
|
|
|
{ |
|
118
|
|
|
// This is a sad day... drop the table? If not, return false (error) by default. |
|
119
|
|
|
if ($if_exists == 'overwrite') |
|
120
|
|
|
$smcFunc['db_drop_table']($table_name); |
|
121
|
|
|
else |
|
122
|
|
|
return $if_exists == 'ignore'; |
|
123
|
|
|
} |
|
124
|
|
|
|
|
125
|
|
|
// Righty - let's do the damn thing! |
|
126
|
|
|
$table_query = 'CREATE TABLE ' . $table_name . "\n" . '('; |
|
127
|
|
|
foreach ($columns as $column) |
|
128
|
|
|
$table_query .= "\n\t" . smf_db_create_query_column($column) . ','; |
|
129
|
|
|
|
|
130
|
|
|
// Loop through the indexes next... |
|
131
|
|
|
foreach ($indexes as $index) |
|
132
|
|
|
{ |
|
133
|
|
|
$columns = implode(',', $index['columns']); |
|
134
|
|
|
|
|
135
|
|
|
// Is it the primary? |
|
136
|
|
|
if (isset($index['type']) && $index['type'] == 'primary') |
|
137
|
|
|
$table_query .= "\n\t" . 'PRIMARY KEY (' . implode(',', $index['columns']) . '),'; |
|
138
|
|
|
else |
|
139
|
|
|
{ |
|
140
|
|
|
if (empty($index['name'])) |
|
141
|
|
|
$index['name'] = implode('_', $index['columns']); |
|
142
|
|
|
$table_query .= "\n\t" . (isset($index['type']) && $index['type'] == 'unique' ? 'UNIQUE' : 'KEY') . ' ' . $index['name'] . ' (' . $columns . '),'; |
|
143
|
|
|
} |
|
144
|
|
|
} |
|
145
|
|
|
|
|
146
|
|
|
// No trailing commas! |
|
147
|
|
View Code Duplication |
if (substr($table_query, -1) == ',') |
|
148
|
|
|
$table_query = substr($table_query, 0, -1); |
|
149
|
|
|
|
|
150
|
|
|
// Which engine do we want here? |
|
151
|
|
|
if (empty($engines)) |
|
152
|
|
|
{ |
|
153
|
|
|
// Figure out which engines we have |
|
154
|
|
|
$get_engines = $smcFunc['db_query']('', 'SHOW ENGINES', array()); |
|
155
|
|
|
|
|
156
|
|
View Code Duplication |
while ($row = $smcFunc['db_fetch_assoc']($get_engines)) |
|
157
|
|
|
{ |
|
158
|
|
|
if ($row['Support'] == 'YES' || $row['Support'] == 'DEFAULT') |
|
159
|
|
|
$engines[] = $row['Engine']; |
|
160
|
|
|
} |
|
161
|
|
|
|
|
162
|
|
|
$smcFunc['db_free_result']($get_engines); |
|
163
|
|
|
} |
|
164
|
|
|
|
|
165
|
|
|
// If we don't have this engine, or didn't specify one, default to InnoDB or MyISAM |
|
166
|
|
|
// depending on which one is available |
|
167
|
|
|
if (!isset($parameters['engine']) || !in_array($parameters['engine'], $engines)) |
|
168
|
|
|
{ |
|
169
|
|
|
$parameters['engine'] = in_array('InnoDB', $engines) ? 'InnoDB' : 'MyISAM'; |
|
170
|
|
|
} |
|
171
|
|
|
|
|
172
|
|
|
$table_query .= ') ENGINE=' . $parameters['engine']; |
|
173
|
|
|
if (!empty($db_character_set) && $db_character_set == 'utf8') |
|
174
|
|
|
$table_query .= ' DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci'; |
|
175
|
|
|
|
|
176
|
|
|
// Create the table! |
|
177
|
|
|
$smcFunc['db_query']('', $table_query, |
|
178
|
|
|
array( |
|
179
|
|
|
'security_override' => true, |
|
180
|
|
|
) |
|
181
|
|
|
); |
|
182
|
|
|
|
|
183
|
|
|
return true; |
|
184
|
|
|
} |
|
185
|
|
|
|
|
186
|
|
|
/** |
|
187
|
|
|
* Drop a table. |
|
188
|
|
|
* |
|
189
|
|
|
* @param string $table_name The name of the table to drop |
|
190
|
|
|
* @param array $parameters Not used at the moment |
|
191
|
|
|
* @param string $error |
|
192
|
|
|
* @return boolean Whether or not the operation was successful |
|
193
|
|
|
*/ |
|
194
|
|
|
function smf_db_drop_table($table_name, $parameters = array(), $error = 'fatal') |
|
|
|
|
|
|
195
|
|
|
{ |
|
196
|
|
|
global $reservedTables, $smcFunc, $db_prefix; |
|
197
|
|
|
|
|
198
|
|
|
// After stripping away the database name, this is what's left. |
|
199
|
|
|
$real_prefix = preg_match('~^(`?)(.+?)\\1\\.(.*?)$~', $db_prefix, $match) === 1 ? $match[3] : $db_prefix; |
|
200
|
|
|
|
|
201
|
|
|
// Get some aliases. |
|
202
|
|
|
$full_table_name = str_replace('{db_prefix}', $real_prefix, $table_name); |
|
203
|
|
|
$table_name = str_replace('{db_prefix}', $db_prefix, $table_name); |
|
204
|
|
|
|
|
205
|
|
|
// God no - dropping one of these = bad. |
|
206
|
|
|
if (in_array(strtolower($table_name), $reservedTables)) |
|
207
|
|
|
return false; |
|
208
|
|
|
|
|
209
|
|
|
// Does it exist? |
|
210
|
|
|
if (in_array($full_table_name, $smcFunc['db_list_tables']())) |
|
211
|
|
|
{ |
|
212
|
|
|
$query = 'DROP TABLE ' . $table_name; |
|
213
|
|
|
$smcFunc['db_query']('', |
|
214
|
|
|
$query, |
|
215
|
|
|
array( |
|
216
|
|
|
'security_override' => true, |
|
217
|
|
|
) |
|
218
|
|
|
); |
|
219
|
|
|
|
|
220
|
|
|
return true; |
|
221
|
|
|
} |
|
222
|
|
|
|
|
223
|
|
|
// Otherwise do 'nout. |
|
224
|
|
|
return false; |
|
225
|
|
|
} |
|
226
|
|
|
|
|
227
|
|
|
/** |
|
228
|
|
|
* This function adds a column. |
|
229
|
|
|
* |
|
230
|
|
|
* @param string $table_name The name of the table to add the column to |
|
231
|
|
|
* @param array $column_info An array of column info ({@see smf_db_create_table}) |
|
232
|
|
|
* @param array $parameters Not used? |
|
233
|
|
|
* @param string $if_exists What to do if the column exists. If 'update', column is updated. |
|
234
|
|
|
* @param string $error |
|
235
|
|
|
* @return boolean Whether or not the operation was successful |
|
236
|
|
|
*/ |
|
237
|
|
|
function smf_db_add_column($table_name, $column_info, $parameters = array(), $if_exists = 'update', $error = 'fatal') |
|
|
|
|
|
|
238
|
|
|
{ |
|
239
|
|
|
global $smcFunc, $db_package_log, $db_prefix; |
|
240
|
|
|
|
|
241
|
|
|
$table_name = str_replace('{db_prefix}', $db_prefix, $table_name); |
|
242
|
|
|
|
|
243
|
|
|
// Log that we will want to uninstall this! |
|
244
|
|
|
$db_package_log[] = array('remove_column', $table_name, $column_info['name']); |
|
245
|
|
|
|
|
246
|
|
|
// Does it exist - if so don't add it again! |
|
247
|
|
|
$columns = $smcFunc['db_list_columns']($table_name, false); |
|
248
|
|
View Code Duplication |
foreach ($columns as $column) |
|
249
|
|
|
if ($column == $column_info['name']) |
|
250
|
|
|
{ |
|
251
|
|
|
// If we're going to overwrite then use change column. |
|
252
|
|
|
if ($if_exists == 'update') |
|
253
|
|
|
return $smcFunc['db_change_column']($table_name, $column_info['name'], $column_info); |
|
254
|
|
|
else |
|
255
|
|
|
return false; |
|
256
|
|
|
} |
|
257
|
|
|
|
|
258
|
|
|
// Get the specifics... |
|
259
|
|
|
$column_info['size'] = isset($column_info['size']) && is_numeric($column_info['size']) ? $column_info['size'] : null; |
|
260
|
|
|
|
|
261
|
|
|
// Now add the thing! |
|
262
|
|
|
$query = ' |
|
263
|
|
|
ALTER TABLE ' . $table_name . ' |
|
264
|
|
|
ADD ' . smf_db_create_query_column($column_info) . (empty($column_info['auto']) ? '' : ' primary key'); |
|
265
|
|
|
$smcFunc['db_query']('', $query, |
|
266
|
|
|
array( |
|
267
|
|
|
'security_override' => true, |
|
268
|
|
|
) |
|
269
|
|
|
); |
|
270
|
|
|
|
|
271
|
|
|
return true; |
|
272
|
|
|
} |
|
273
|
|
|
|
|
274
|
|
|
/** |
|
275
|
|
|
* Removes a column. |
|
276
|
|
|
* |
|
277
|
|
|
* @param string $table_name The name of the table to drop the column from |
|
278
|
|
|
* @param string $column_name The name of the column to drop |
|
279
|
|
|
* @param array $parameters Not used? |
|
280
|
|
|
* @param string $error |
|
281
|
|
|
* @return boolean Whether or not the operation was successful |
|
282
|
|
|
*/ |
|
283
|
|
|
function smf_db_remove_column($table_name, $column_name, $parameters = array(), $error = 'fatal') |
|
|
|
|
|
|
284
|
|
|
{ |
|
285
|
|
|
global $smcFunc, $db_prefix; |
|
286
|
|
|
|
|
287
|
|
|
$table_name = str_replace('{db_prefix}', $db_prefix, $table_name); |
|
288
|
|
|
|
|
289
|
|
|
// Does it exist? |
|
290
|
|
|
$columns = $smcFunc['db_list_columns']($table_name, true); |
|
291
|
|
|
foreach ($columns as $column) |
|
292
|
|
|
if ($column['name'] == $column_name) |
|
293
|
|
|
{ |
|
294
|
|
|
$smcFunc['db_query']('', ' |
|
295
|
|
|
ALTER TABLE ' . $table_name . ' |
|
296
|
|
|
DROP COLUMN ' . $column_name, |
|
297
|
|
|
array( |
|
298
|
|
|
'security_override' => true, |
|
299
|
|
|
) |
|
300
|
|
|
); |
|
301
|
|
|
|
|
302
|
|
|
return true; |
|
303
|
|
|
} |
|
304
|
|
|
|
|
305
|
|
|
// If here we didn't have to work - joy! |
|
306
|
|
|
return false; |
|
307
|
|
|
} |
|
308
|
|
|
|
|
309
|
|
|
/** |
|
310
|
|
|
* Change a column. |
|
311
|
|
|
* |
|
312
|
|
|
* @param string $table_name The name of the table this column is in |
|
313
|
|
|
* @param string $old_column The name of the column we want to change |
|
314
|
|
|
* @param array $column_info An array of info about the "new" column definition (see {@link smf_db_create_table()}) |
|
315
|
|
|
* @return bool |
|
316
|
|
|
*/ |
|
317
|
|
|
function smf_db_change_column($table_name, $old_column, $column_info) |
|
318
|
|
|
{ |
|
319
|
|
|
global $smcFunc, $db_prefix; |
|
320
|
|
|
|
|
321
|
|
|
$table_name = str_replace('{db_prefix}', $db_prefix, $table_name); |
|
322
|
|
|
|
|
323
|
|
|
// Check it does exist! |
|
324
|
|
|
$columns = $smcFunc['db_list_columns']($table_name, true); |
|
325
|
|
|
$old_info = null; |
|
326
|
|
|
foreach ($columns as $column) |
|
327
|
|
|
if ($column['name'] == $old_column) |
|
328
|
|
|
$old_info = $column; |
|
329
|
|
|
|
|
330
|
|
|
// Nothing? |
|
331
|
|
|
if ($old_info == null) |
|
332
|
|
|
return false; |
|
333
|
|
|
|
|
334
|
|
|
// Get the right bits. |
|
335
|
|
|
if (!isset($column_info['name'])) |
|
336
|
|
|
$column_info['name'] = $old_column; |
|
337
|
|
|
if (!isset($column_info['default'])) |
|
338
|
|
|
$column_info['default'] = $old_info['default']; |
|
339
|
|
|
if (!isset($column_info['null'])) |
|
340
|
|
|
$column_info['null'] = $old_info['null']; |
|
341
|
|
|
if (!isset($column_info['auto'])) |
|
342
|
|
|
$column_info['auto'] = $old_info['auto']; |
|
343
|
|
|
if (!isset($column_info['type'])) |
|
344
|
|
|
$column_info['type'] = $old_info['type']; |
|
345
|
|
|
if (!isset($column_info['size']) || !is_numeric($column_info['size'])) |
|
346
|
|
|
$column_info['size'] = $old_info['size']; |
|
347
|
|
|
if (!isset($column_info['unsigned']) || !in_array($column_info['type'], array('int', 'tinyint', 'smallint', 'mediumint', 'bigint'))) |
|
348
|
|
|
$column_info['unsigned'] = ''; |
|
349
|
|
|
|
|
350
|
|
|
list ($type, $size) = $smcFunc['db_calculate_type']($column_info['type'], $column_info['size']); |
|
351
|
|
|
|
|
352
|
|
|
// Allow for unsigned integers (mysql only) |
|
353
|
|
|
$unsigned = in_array($type, array('int', 'tinyint', 'smallint', 'mediumint', 'bigint')) && !empty($column_info['unsigned']) ? 'unsigned ' : ''; |
|
354
|
|
|
|
|
355
|
|
|
if ($size !== null) |
|
356
|
|
|
$type = $type . '(' . $size . ')'; |
|
357
|
|
|
|
|
358
|
|
|
$smcFunc['db_query']('', ' |
|
359
|
|
|
ALTER TABLE ' . $table_name . ' |
|
360
|
|
|
CHANGE COLUMN `' . $old_column . '` `' . $column_info['name'] . '` ' . $type . ' ' . (!empty($unsigned) ? $unsigned : '') . (empty($column_info['null']) ? 'NOT NULL' : '') . ' ' . |
|
361
|
|
|
(!isset($column_info['default']) ? '' : 'default \'' . $smcFunc['db_escape_string']($column_info['default']) . '\'') . ' ' . |
|
362
|
|
|
(empty($column_info['auto']) ? '' : 'auto_increment') . ' ', |
|
363
|
|
|
array( |
|
364
|
|
|
'security_override' => true, |
|
365
|
|
|
) |
|
366
|
|
|
); |
|
367
|
|
|
} |
|
368
|
|
|
|
|
369
|
|
|
/** |
|
370
|
|
|
* Add an index. |
|
371
|
|
|
* |
|
372
|
|
|
* @param string $table_name The name of the table to add the index to |
|
373
|
|
|
* @param array $index_info An array of index info (see {@link smf_db_create_table()}) |
|
374
|
|
|
* @param array $parameters Not used? |
|
375
|
|
|
* @param string $if_exists What to do if the index exists. If 'update', the definition will be updated. |
|
376
|
|
|
* @param string $error |
|
377
|
|
|
* @return boolean Whether or not the operation was successful |
|
|
|
|
|
|
378
|
|
|
*/ |
|
379
|
|
|
function smf_db_add_index($table_name, $index_info, $parameters = array(), $if_exists = 'update', $error = 'fatal') |
|
|
|
|
|
|
380
|
|
|
{ |
|
381
|
|
|
global $smcFunc, $db_package_log, $db_prefix; |
|
382
|
|
|
|
|
383
|
|
|
$table_name = str_replace('{db_prefix}', $db_prefix, $table_name); |
|
384
|
|
|
|
|
385
|
|
|
// No columns = no index. |
|
386
|
|
|
if (empty($index_info['columns'])) |
|
387
|
|
|
return false; |
|
388
|
|
|
$columns = implode(',', $index_info['columns']); |
|
389
|
|
|
|
|
390
|
|
|
// No name - make it up! |
|
391
|
|
View Code Duplication |
if (empty($index_info['name'])) |
|
392
|
|
|
{ |
|
393
|
|
|
// No need for primary. |
|
394
|
|
|
if (isset($index_info['type']) && $index_info['type'] == 'primary') |
|
395
|
|
|
$index_info['name'] = ''; |
|
396
|
|
|
else |
|
397
|
|
|
$index_info['name'] = implode('_', $index_info['columns']); |
|
398
|
|
|
} |
|
399
|
|
|
|
|
400
|
|
|
// Log that we are going to want to remove this! |
|
401
|
|
|
$db_package_log[] = array('remove_index', $table_name, $index_info['name']); |
|
402
|
|
|
|
|
403
|
|
|
// Let's get all our indexes. |
|
404
|
|
|
$indexes = $smcFunc['db_list_indexes']($table_name, true); |
|
405
|
|
|
// Do we already have it? |
|
406
|
|
|
foreach ($indexes as $index) |
|
407
|
|
|
{ |
|
408
|
|
|
if ($index['name'] == $index_info['name'] || ($index['type'] == 'primary' && isset($index_info['type']) && $index_info['type'] == 'primary')) |
|
409
|
|
|
{ |
|
410
|
|
|
// If we want to overwrite simply remove the current one then continue. |
|
411
|
|
|
if ($if_exists != 'update' || $index['type'] == 'primary') |
|
412
|
|
|
return false; |
|
413
|
|
|
else |
|
414
|
|
|
$smcFunc['db_remove_index']($table_name, $index_info['name']); |
|
415
|
|
|
} |
|
416
|
|
|
} |
|
417
|
|
|
|
|
418
|
|
|
// If we're here we know we don't have the index - so just add it. |
|
419
|
|
|
if (!empty($index_info['type']) && $index_info['type'] == 'primary') |
|
420
|
|
|
{ |
|
421
|
|
|
$smcFunc['db_query']('', ' |
|
422
|
|
|
ALTER TABLE ' . $table_name . ' |
|
423
|
|
|
ADD PRIMARY KEY (' . $columns . ')', |
|
424
|
|
|
array( |
|
425
|
|
|
'security_override' => true, |
|
426
|
|
|
) |
|
427
|
|
|
); |
|
428
|
|
|
} |
|
429
|
|
|
else |
|
430
|
|
|
{ |
|
431
|
|
|
$smcFunc['db_query']('', ' |
|
432
|
|
|
ALTER TABLE ' . $table_name . ' |
|
433
|
|
|
ADD ' . (isset($index_info['type']) && $index_info['type'] == 'unique' ? 'UNIQUE' : 'INDEX') . ' ' . $index_info['name'] . ' (' . $columns . ')', |
|
434
|
|
|
array( |
|
435
|
|
|
'security_override' => true, |
|
436
|
|
|
) |
|
437
|
|
|
); |
|
438
|
|
|
} |
|
439
|
|
|
} |
|
440
|
|
|
|
|
441
|
|
|
/** |
|
442
|
|
|
* Remove an index. |
|
443
|
|
|
* |
|
444
|
|
|
* @param string $table_name The name of the table to remove the index from |
|
445
|
|
|
* @param string $index_name The name of the index to remove |
|
446
|
|
|
* @param array $parameters Not used? |
|
447
|
|
|
* @param string $error |
|
448
|
|
|
* @return boolean Whether or not the operation was successful |
|
449
|
|
|
*/ |
|
450
|
|
|
function smf_db_remove_index($table_name, $index_name, $parameters = array(), $error = 'fatal') |
|
|
|
|
|
|
451
|
|
|
{ |
|
452
|
|
|
global $smcFunc, $db_prefix; |
|
453
|
|
|
|
|
454
|
|
|
$table_name = str_replace('{db_prefix}', $db_prefix, $table_name); |
|
455
|
|
|
|
|
456
|
|
|
// Better exist! |
|
457
|
|
|
$indexes = $smcFunc['db_list_indexes']($table_name, true); |
|
458
|
|
|
|
|
459
|
|
View Code Duplication |
foreach ($indexes as $index) |
|
460
|
|
|
{ |
|
461
|
|
|
// If the name is primary we want the primary key! |
|
462
|
|
|
if ($index['type'] == 'primary' && $index_name == 'primary') |
|
463
|
|
|
{ |
|
464
|
|
|
// Dropping primary key? |
|
465
|
|
|
$smcFunc['db_query']('', ' |
|
466
|
|
|
ALTER TABLE ' . $table_name . ' |
|
467
|
|
|
DROP PRIMARY KEY', |
|
468
|
|
|
array( |
|
469
|
|
|
'security_override' => true, |
|
470
|
|
|
) |
|
471
|
|
|
); |
|
472
|
|
|
|
|
473
|
|
|
return true; |
|
474
|
|
|
} |
|
475
|
|
|
if ($index['name'] == $index_name) |
|
476
|
|
|
{ |
|
477
|
|
|
// Drop the bugger... |
|
478
|
|
|
$smcFunc['db_query']('', ' |
|
479
|
|
|
ALTER TABLE ' . $table_name . ' |
|
480
|
|
|
DROP INDEX ' . $index_name, |
|
481
|
|
|
array( |
|
482
|
|
|
'security_override' => true, |
|
483
|
|
|
) |
|
484
|
|
|
); |
|
485
|
|
|
|
|
486
|
|
|
return true; |
|
487
|
|
|
} |
|
488
|
|
|
} |
|
489
|
|
|
|
|
490
|
|
|
// Not to be found ;( |
|
491
|
|
|
return false; |
|
492
|
|
|
} |
|
493
|
|
|
|
|
494
|
|
|
/** |
|
495
|
|
|
* Get the schema formatted name for a type. |
|
496
|
|
|
* |
|
497
|
|
|
* @param string $type_name The data type (int, varchar, smallint, etc.) |
|
498
|
|
|
* @param int $type_size The size (8, 255, etc.) |
|
|
|
|
|
|
499
|
|
|
* @param boolean $reverse |
|
500
|
|
|
* @return array An array containing the appropriate type and size for this DB type |
|
|
|
|
|
|
501
|
|
|
*/ |
|
502
|
|
|
function smf_db_calculate_type($type_name, $type_size = null, $reverse = false) |
|
503
|
|
|
{ |
|
504
|
|
|
// MySQL is actually the generic baseline. |
|
505
|
|
|
|
|
506
|
|
|
$type_name = strtolower($type_name); |
|
507
|
|
|
// Generic => Specific. |
|
508
|
|
|
if (!$reverse) |
|
509
|
|
|
{ |
|
510
|
|
|
$types = array( |
|
511
|
|
|
'inet' => 'varbinary', |
|
512
|
|
|
); |
|
513
|
|
|
} |
|
514
|
|
|
else |
|
515
|
|
|
{ |
|
516
|
|
|
$types = array( |
|
517
|
|
|
'varbinary' => 'inet', |
|
518
|
|
|
); |
|
519
|
|
|
} |
|
520
|
|
|
|
|
521
|
|
|
// Got it? Change it! |
|
522
|
|
|
if (isset($types[$type_name])) |
|
523
|
|
|
{ |
|
524
|
|
|
if ($type_name == 'inet' && !$reverse) |
|
525
|
|
|
{ |
|
526
|
|
|
$type_size = 16; |
|
527
|
|
|
$type_name = 'varbinary'; |
|
528
|
|
|
} |
|
529
|
|
|
elseif ($type_name == 'varbinary' && $reverse && $type_size == 16) |
|
530
|
|
|
{ |
|
531
|
|
|
$type_name = 'inet'; |
|
532
|
|
|
$type_size = null; |
|
533
|
|
|
} |
|
534
|
|
|
elseif ($type_name == 'varbinary') |
|
535
|
|
|
$type_name = 'varbinary'; |
|
536
|
|
|
else |
|
537
|
|
|
$type_name = $types[$type_name]; |
|
538
|
|
|
} |
|
539
|
|
|
|
|
540
|
|
|
return array($type_name, $type_size); |
|
541
|
|
|
} |
|
542
|
|
|
|
|
543
|
|
|
/** |
|
544
|
|
|
* Get table structure. |
|
545
|
|
|
* |
|
546
|
|
|
* @param string $table_name The name of the table |
|
547
|
|
|
* @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()} |
|
548
|
|
|
*/ |
|
549
|
|
|
function smf_db_table_structure($table_name) |
|
550
|
|
|
{ |
|
551
|
|
|
global $smcFunc, $db_prefix; |
|
552
|
|
|
|
|
553
|
|
|
$table_name = str_replace('{db_prefix}', $db_prefix, $table_name); |
|
554
|
|
|
|
|
555
|
|
|
// Find the table engine and add that to the info as well |
|
556
|
|
|
$table_status = $smcFunc['db_query']('', ' |
|
557
|
|
|
SHOW TABLE STATUS |
|
558
|
|
|
LIKE {string:table}', |
|
559
|
|
|
array( |
|
560
|
|
|
'table' => strtr($table_name, array('_' => '\\_', '%' => '\\%')) |
|
561
|
|
|
) |
|
562
|
|
|
); |
|
563
|
|
|
|
|
564
|
|
|
// Only one row, so no need for a loop... |
|
565
|
|
|
$row = $smcFunc['db_fetch_assoc']($table_status); |
|
566
|
|
|
|
|
567
|
|
|
$smcFunc['db_free_result']($table_status); |
|
568
|
|
|
|
|
569
|
|
|
return array( |
|
570
|
|
|
'name' => $table_name, |
|
571
|
|
|
'columns' => $smcFunc['db_list_columns']($table_name, true), |
|
572
|
|
|
'indexes' => $smcFunc['db_list_indexes']($table_name, true), |
|
573
|
|
|
'engine' => $row['Engine'], |
|
574
|
|
|
); |
|
575
|
|
|
} |
|
576
|
|
|
|
|
577
|
|
|
/** |
|
578
|
|
|
* Return column information for a table. |
|
579
|
|
|
* |
|
580
|
|
|
* @param string $table_name The name of the table to get column info for |
|
581
|
|
|
* @param bool $detail Whether or not to return detailed info. If true, returns the column info. If false, just returns the column names. |
|
582
|
|
|
* @param array $parameters Not used? |
|
583
|
|
|
* @return array An array of column names or detailed column info, depending on $detail |
|
584
|
|
|
*/ |
|
585
|
|
|
function smf_db_list_columns($table_name, $detail = false, $parameters = array()) |
|
|
|
|
|
|
586
|
|
|
{ |
|
587
|
|
|
global $smcFunc, $db_prefix; |
|
588
|
|
|
|
|
589
|
|
|
$table_name = str_replace('{db_prefix}', $db_prefix, $table_name); |
|
590
|
|
|
|
|
591
|
|
|
$result = $smcFunc['db_query']('', ' |
|
592
|
|
|
SHOW FIELDS |
|
593
|
|
|
FROM {raw:table_name}', |
|
594
|
|
|
array( |
|
595
|
|
|
'table_name' => substr($table_name, 0, 1) == '`' ? $table_name : '`' . $table_name . '`', |
|
596
|
|
|
) |
|
597
|
|
|
); |
|
598
|
|
|
$columns = array(); |
|
599
|
|
|
while ($row = $smcFunc['db_fetch_assoc']($result)) |
|
600
|
|
|
{ |
|
601
|
|
|
if (!$detail) |
|
602
|
|
|
{ |
|
603
|
|
|
$columns[] = $row['Field']; |
|
604
|
|
|
} |
|
605
|
|
|
else |
|
606
|
|
|
{ |
|
607
|
|
|
// Is there an auto_increment? |
|
608
|
|
|
$auto = strpos($row['Extra'], 'auto_increment') !== false ? true : false; |
|
609
|
|
|
|
|
610
|
|
|
// Can we split out the size? |
|
611
|
|
|
if (preg_match('~(.+?)\s*\((\d+)\)(?:(?:\s*)?(unsigned))?~i', $row['Type'], $matches) === 1) |
|
612
|
|
|
{ |
|
613
|
|
|
$type = $matches[1]; |
|
614
|
|
|
$size = $matches[2]; |
|
615
|
|
|
if (!empty($matches[3]) && $matches[3] == 'unsigned') |
|
616
|
|
|
$unsigned = true; |
|
617
|
|
|
} |
|
618
|
|
|
else |
|
619
|
|
|
{ |
|
620
|
|
|
$type = $row['Type']; |
|
621
|
|
|
$size = null; |
|
622
|
|
|
} |
|
623
|
|
|
|
|
624
|
|
|
$columns[$row['Field']] = array( |
|
625
|
|
|
'name' => $row['Field'], |
|
626
|
|
|
'null' => $row['Null'] != 'YES' ? false : true, |
|
627
|
|
|
'default' => isset($row['Default']) ? $row['Default'] : null, |
|
628
|
|
|
'type' => $type, |
|
629
|
|
|
'size' => $size, |
|
630
|
|
|
'auto' => $auto, |
|
631
|
|
|
); |
|
632
|
|
|
|
|
633
|
|
|
if (isset($unsigned)) |
|
634
|
|
|
{ |
|
635
|
|
|
$columns[$row['Field']]['unsigned'] = $unsigned; |
|
636
|
|
|
unset($unsigned); |
|
637
|
|
|
} |
|
638
|
|
|
} |
|
639
|
|
|
} |
|
640
|
|
|
$smcFunc['db_free_result']($result); |
|
641
|
|
|
|
|
642
|
|
|
return $columns; |
|
643
|
|
|
} |
|
644
|
|
|
|
|
645
|
|
|
/** |
|
646
|
|
|
* Get index information. |
|
647
|
|
|
* |
|
648
|
|
|
* @param string $table_name The name of the table to get indexes for |
|
649
|
|
|
* @param bool $detail Whether or not to return detailed info. |
|
650
|
|
|
* @param array $parameters Not used? |
|
651
|
|
|
* @return array An array of index names or a detailed array of index info, depending on $detail |
|
652
|
|
|
*/ |
|
653
|
|
|
function smf_db_list_indexes($table_name, $detail = false, $parameters = array()) |
|
|
|
|
|
|
654
|
|
|
{ |
|
655
|
|
|
global $smcFunc, $db_prefix; |
|
656
|
|
|
|
|
657
|
|
|
$table_name = str_replace('{db_prefix}', $db_prefix, $table_name); |
|
658
|
|
|
|
|
659
|
|
|
$result = $smcFunc['db_query']('', ' |
|
660
|
|
|
SHOW KEYS |
|
661
|
|
|
FROM {raw:table_name}', |
|
662
|
|
|
array( |
|
663
|
|
|
'table_name' => substr($table_name, 0, 1) == '`' ? $table_name : '`' . $table_name . '`', |
|
664
|
|
|
) |
|
665
|
|
|
); |
|
666
|
|
|
$indexes = array(); |
|
667
|
|
|
while ($row = $smcFunc['db_fetch_assoc']($result)) |
|
668
|
|
|
{ |
|
669
|
|
|
if (!$detail) |
|
670
|
|
|
$indexes[] = $row['Key_name']; |
|
671
|
|
|
else |
|
672
|
|
|
{ |
|
673
|
|
|
// What is the type? |
|
674
|
|
|
if ($row['Key_name'] == 'PRIMARY') |
|
675
|
|
|
$type = 'primary'; |
|
676
|
|
|
elseif (empty($row['Non_unique'])) |
|
677
|
|
|
$type = 'unique'; |
|
678
|
|
|
elseif (isset($row['Index_type']) && $row['Index_type'] == 'FULLTEXT') |
|
679
|
|
|
$type = 'fulltext'; |
|
680
|
|
|
else |
|
681
|
|
|
$type = 'index'; |
|
682
|
|
|
|
|
683
|
|
|
// This is the first column we've seen? |
|
684
|
|
|
if (empty($indexes[$row['Key_name']])) |
|
685
|
|
|
{ |
|
686
|
|
|
$indexes[$row['Key_name']] = array( |
|
687
|
|
|
'name' => $row['Key_name'], |
|
688
|
|
|
'type' => $type, |
|
689
|
|
|
'columns' => array(), |
|
690
|
|
|
); |
|
691
|
|
|
} |
|
692
|
|
|
|
|
693
|
|
|
// Is it a partial index? |
|
694
|
|
|
if (!empty($row['Sub_part'])) |
|
695
|
|
|
$indexes[$row['Key_name']]['columns'][] = $row['Column_name'] . '(' . $row['Sub_part'] . ')'; |
|
696
|
|
|
else |
|
697
|
|
|
$indexes[$row['Key_name']]['columns'][] = $row['Column_name']; |
|
698
|
|
|
} |
|
699
|
|
|
} |
|
700
|
|
|
$smcFunc['db_free_result']($result); |
|
701
|
|
|
|
|
702
|
|
|
return $indexes; |
|
703
|
|
|
} |
|
704
|
|
|
|
|
705
|
|
|
/** |
|
706
|
|
|
* Creates a query for a column |
|
707
|
|
|
* |
|
708
|
|
|
* @param array $column An array of column info |
|
709
|
|
|
* @return string The column definition |
|
710
|
|
|
*/ |
|
711
|
|
|
function smf_db_create_query_column($column) |
|
712
|
|
|
{ |
|
713
|
|
|
global $smcFunc; |
|
714
|
|
|
|
|
715
|
|
|
// Auto increment is easy here! |
|
716
|
|
|
if (!empty($column['auto'])) |
|
717
|
|
|
{ |
|
718
|
|
|
$default = 'auto_increment'; |
|
719
|
|
|
} |
|
720
|
|
View Code Duplication |
elseif (isset($column['default']) && $column['default'] !== null) |
|
721
|
|
|
$default = 'default \'' . $smcFunc['db_escape_string']($column['default']) . '\''; |
|
722
|
|
|
else |
|
723
|
|
|
$default = ''; |
|
724
|
|
|
|
|
725
|
|
|
// Sort out the size... and stuff... |
|
726
|
|
|
$column['size'] = isset($column['size']) && is_numeric($column['size']) ? $column['size'] : null; |
|
727
|
|
|
list ($type, $size) = $smcFunc['db_calculate_type']($column['type'], $column['size']); |
|
728
|
|
|
|
|
729
|
|
|
// Allow unsigned integers (mysql only) |
|
730
|
|
|
$unsigned = in_array($type, array('int', 'tinyint', 'smallint', 'mediumint', 'bigint')) && !empty($column['unsigned']) ? 'unsigned ' : ''; |
|
731
|
|
|
|
|
732
|
|
|
if ($size !== null) |
|
733
|
|
|
$type = $type . '(' . $size . ')'; |
|
734
|
|
|
|
|
735
|
|
|
// Now just put it together! |
|
736
|
|
|
return '`' . $column['name'] . '` ' . $type . ' ' . (!empty($unsigned) ? $unsigned : '') . (!empty($column['null']) ? '' : 'NOT NULL') . ' ' . $default; |
|
737
|
|
|
} |
|
738
|
|
|
|
|
739
|
|
|
?> |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.