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 | * Some static helper functions that SMW uses for setting up |
||
5 | * SQL databases. |
||
6 | * |
||
7 | * @author Markus Krötzsch |
||
8 | * @author Marcel Gsteiger |
||
9 | * @author Jeroen De Dauw |
||
10 | * |
||
11 | * @ingroup SMWStore |
||
12 | */ |
||
13 | class SMWSQLHelpers { |
||
14 | |||
15 | /** |
||
16 | * Database backends often have different types that need to be used |
||
17 | * repeatedly in (Semantic) MediaWiki. This function provides the |
||
18 | * preferred type (as a string) for various common kinds of columns. |
||
19 | * The input is one of the following strings: 'id' (page id numbers or |
||
20 | * similar), 'title' (title strings or similar), 'namespace' (namespace |
||
21 | * numbers), 'blob' (longer text blobs), 'iw' (interwiki prefixes). |
||
22 | * |
||
23 | * @param string $input |
||
24 | * @return string|false SQL type declaration |
||
25 | */ |
||
26 | 3 | static public function getStandardDBType( $input ) { |
|
27 | 3 | global $wgDBtype; |
|
28 | |||
29 | switch ( $input ) { |
||
30 | 3 | case 'id': |
|
31 | 3 | return $wgDBtype == 'postgres' ? 'SERIAL' : ($wgDBtype == 'sqlite' ? 'INTEGER' :'INT(8) UNSIGNED'); // like page_id in MW page table |
|
32 | 3 | case 'namespace': |
|
33 | 3 | return $wgDBtype == 'postgres' ? 'BIGINT' : 'INT(11)'; // like page_namespace in MW page table |
|
34 | 3 | case 'title': |
|
35 | 3 | return $wgDBtype == 'postgres' ? 'TEXT' : 'VARBINARY(255)'; // like page_title in MW page table |
|
36 | 3 | case 'iw': |
|
37 | 3 | return ($wgDBtype == 'postgres' || $wgDBtype == 'sqlite') ? 'TEXT' : 'VARBINARY(32)'; // like iw_prefix in MW interwiki table |
|
38 | 3 | case 'blob': |
|
39 | 3 | return $wgDBtype == 'postgres' ? 'BYTEA' : 'MEDIUMBLOB'; // larger blobs of character data, usually not subject to SELECT conditions |
|
40 | } |
||
41 | |||
42 | return false; |
||
43 | } |
||
44 | |||
45 | /** |
||
46 | * Generic creation and updating function for database tables. Ideally, it |
||
47 | * would be able to modify a table's signature in arbitrary ways, but it will |
||
48 | * fail for some changes. Its string-based interface is somewhat too |
||
49 | * impoverished for a permanent solution. It would be possible to go for update |
||
50 | * scripts (specific to each change) in the style of MediaWiki instead. |
||
51 | * |
||
52 | * Make sure the table of the given name has the given fields, provided |
||
53 | * as an array with entries fieldname => typeparams. typeparams should be |
||
54 | * in a normalised form and order to match to existing values. |
||
55 | * |
||
56 | * The function returns an array that includes all columns that have been |
||
57 | * changed. For each such column, the array contains an entry |
||
58 | * columnname => action, where action is one of 'up', 'new', or 'del' |
||
59 | * |
||
60 | * If progress reports during this operation are desired, then the parameter $reportTo should |
||
61 | * be given an object that has a method reportProgress(string) for doing so. |
||
62 | * |
||
63 | * @note The function partly ignores the order in which fields are set up. |
||
64 | * Only if the type of some field changes will its order be adjusted explicitly. |
||
65 | * |
||
66 | * @param string $tableName The table name. Does not need to have been passed to DatabaseBase->tableName yet. |
||
67 | * @param array $columns The fields and their types the table should have. |
||
68 | * @param DatabaseBase or Database $db |
||
69 | * @param object $reportTo Object to report back to. |
||
70 | */ |
||
71 | 3 | public static function setupTable( $rawTableName, array $fields, $db, $reportTo = null ) { |
|
72 | 3 | $tableName = $db->tableName( $rawTableName ); |
|
73 | |||
74 | 3 | self::reportProgress( "Checking table $tableName ...\n", $reportTo ); |
|
75 | |||
76 | 3 | if ( $db->tableExists( $rawTableName ) === false ) { // create new table |
|
77 | 2 | self::reportProgress( " Table not found, now creating...\n", $reportTo ); |
|
78 | 2 | self::createTable( $tableName, $fields, $db ); |
|
79 | 2 | self::reportProgress( " ... done.\n", $reportTo ); |
|
80 | } else { |
||
81 | 2 | self::reportProgress( " Table already exists, checking structure ...\n", $reportTo ); |
|
82 | 2 | self::updateTable( $tableName, $fields, $db, $reportTo ); |
|
83 | 2 | self::reportProgress( " ... done.\n", $reportTo ); |
|
84 | } |
||
85 | 3 | } |
|
86 | |||
87 | /** |
||
88 | * Creates a new database table with the specified fields. |
||
89 | * |
||
90 | * @param string $tableName The table name. |
||
91 | * @param array $columns The fields and their types the table should have. |
||
92 | * @param DatabaseBase|Database $db |
||
93 | */ |
||
94 | 2 | private static function createTable( $tableName, array $fields, $db ) { |
|
95 | 2 | global $wgDBtype, $wgDBname; |
|
96 | |||
97 | 2 | $sql = 'CREATE TABLE ' . ( ( $wgDBtype == 'postgres' || $wgDBtype == 'sqlite' ) ? '' : "`$wgDBname`." ) . $tableName . ' ('; |
|
98 | |||
99 | 2 | $fieldSql = array(); |
|
100 | |||
101 | 2 | foreach ( $fields as $fieldName => $fieldType ) { |
|
102 | 2 | $fieldSql[] = "$fieldName $fieldType"; |
|
103 | } |
||
104 | |||
105 | 2 | $sql .= implode( ',', $fieldSql ) . ') '; |
|
106 | |||
107 | 2 | if ( $wgDBtype != 'postgres' && $wgDBtype != 'sqlite' ) { |
|
108 | // This replacement is needed for compatibility, see http://bugs.mysql.com/bug.php?id=17501 |
||
109 | 2 | $sql .= str_replace( 'TYPE', 'ENGINE', $GLOBALS['wgDBTableOptions'] ); |
|
110 | } |
||
111 | |||
112 | 2 | $db->query( $sql, __METHOD__ ); |
|
113 | 2 | } |
|
114 | |||
115 | /** |
||
116 | * Update a table given an array of field names and field types. |
||
117 | * |
||
118 | * @param string $tableName The table name. |
||
119 | * @param array $columns The fields and their types the table should have. |
||
120 | * @param DatabaseBase|Database $db |
||
121 | * @param object $reportTo Object to report back to. |
||
122 | */ |
||
123 | 2 | private static function updateTable( $tableName, array $fields, $db, $reportTo ) { |
|
124 | 2 | global $wgDBtype; |
|
125 | |||
126 | 2 | $currentFields = self::getFields( $tableName, $db, $reportTo ); |
|
127 | |||
128 | 2 | $isPostgres = $wgDBtype == 'postgres'; |
|
129 | |||
130 | 2 | if ( !$isPostgres ) { |
|
131 | 2 | $position = 'FIRST'; |
|
132 | } |
||
133 | |||
134 | // Loop through all the field definitions, and handle each definition for either postgres or MySQL. |
||
135 | 2 | foreach ( $fields as $fieldName => $fieldType ) { |
|
136 | 2 | if ( $isPostgres ) { |
|
137 | self::updatePostgresField( $tableName, $fieldName, $fieldType, $currentFields, $db, $reportTo ); |
||
138 | } else { |
||
139 | 2 | self::updateMySqlField( $tableName, $fieldName, $fieldType, $currentFields, $db, $reportTo, $position ); |
|
140 | 2 | $position = "AFTER $fieldName"; |
|
141 | } |
||
142 | |||
143 | 2 | $currentFields[$fieldName] = false; |
|
144 | } |
||
145 | |||
146 | // The updated fields have their value set to false, so if a field has a value |
||
147 | // that differs from false, it's an obsolete one that should be removed. |
||
148 | 2 | foreach ( $currentFields as $fieldName => $value ) { |
|
149 | 2 | if ( $value !== false ) { |
|
150 | self::reportProgress( " ... deleting obsolete field $fieldName ... ", $reportTo ); |
||
151 | |||
152 | if ( $isPostgres ) { |
||
153 | $db->query( 'ALTER TABLE "' . $tableName . '" DROP COLUMN "' . $fieldName . '"', __METHOD__ ); |
||
154 | } elseif ( $wgDBtype == 'sqlite' ) { |
||
155 | // DROP COLUMN not supported in Sqlite3 |
||
156 | self::reportProgress( " ... deleting obsolete field $fieldName not possible in SQLLite ... you could delete and reinitialize the tables to remove obsolete data, or just keep it ... ", $reportTo ); |
||
157 | } else { |
||
158 | $db->query( "ALTER TABLE $tableName DROP COLUMN `$fieldName`", __METHOD__ ); |
||
159 | } |
||
160 | |||
161 | 2 | self::reportProgress( "done.\n", $reportTo ); |
|
162 | } |
||
163 | } |
||
164 | 2 | } |
|
165 | |||
166 | /** |
||
167 | * Returns an array of fields (as keys) and their types (as values). |
||
168 | * |
||
169 | * @param string $tableName The table name. |
||
170 | * @param DatabaseBase|Database $db |
||
171 | * @param object $reportTo to report back to. |
||
172 | * |
||
173 | * @return array |
||
174 | */ |
||
175 | 2 | private static function getFields( $tableName, $db, $reportTo ) { |
|
176 | 2 | global $wgDBtype; |
|
177 | |||
178 | 2 | if ( $wgDBtype == 'postgres' ) { |
|
179 | $tableName = str_replace( '"', '', $tableName ); |
||
180 | // Use the data dictionary in postgresql to get an output comparable to DESCRIBE. |
||
181 | $sql = <<<EOT |
||
182 | SELECT |
||
183 | a.attname as "Field", |
||
184 | upper(pg_catalog.format_type(a.atttypid, a.atttypmod)) as "Type", |
||
185 | (SELECT substring(pg_catalog.pg_get_expr(d.adbin, d.adrelid) for 128) |
||
186 | FROM pg_catalog.pg_attrdef d |
||
187 | WHERE d.adrelid = a.attrelid AND d.adnum = a.attnum AND a.atthasdef) as "Extra", |
||
188 | case when a.attnotnull THEN 'NO'::text else 'YES'::text END as "Null", a.attnum |
||
189 | FROM pg_catalog.pg_attribute a |
||
190 | WHERE a.attrelid = ( |
||
191 | SELECT c.oid |
||
192 | FROM pg_catalog.pg_class c |
||
193 | LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace |
||
194 | WHERE c.relname ~ '^($tableName)$' |
||
195 | AND pg_catalog.pg_table_is_visible(c.oid) |
||
196 | LIMIT 1 |
||
197 | ) AND a.attnum > 0 AND NOT a.attisdropped |
||
198 | ORDER BY a.attnum |
||
199 | EOT; |
||
200 | 2 | } elseif ( $wgDBtype == 'sqlite' ) { // SQLite |
|
201 | $sql = 'PRAGMA table_info(' . $tableName . ')'; |
||
202 | } else { // MySQL |
||
203 | 2 | $sql = 'DESCRIBE ' . $tableName; |
|
204 | } |
||
205 | |||
206 | 2 | $res = $db->query( $sql, __METHOD__ ); |
|
207 | 2 | $curfields = array(); |
|
208 | |||
209 | 2 | foreach ( $res as $row ) { |
|
210 | 2 | if ( $wgDBtype == 'postgres' ) { // postgresql |
|
211 | $type = strtoupper( $row->Type ); |
||
212 | |||
213 | if ( preg_match( '/^nextval\\(.+\\)/i', $row->Extra ) ) { |
||
214 | $type = 'SERIAL NOT NULL'; |
||
215 | } elseif ( $row->Null != 'YES' ) { |
||
216 | $type .= ' NOT NULL'; |
||
217 | } |
||
218 | 2 | } elseif ( $wgDBtype == 'sqlite' ) { // SQLite |
|
219 | $row->Field = $row->name; |
||
220 | $row->Type = $row->type; |
||
221 | $type = $row->type; |
||
222 | if ( $row->notnull == '1' ) { |
||
223 | $type .= ' NOT NULL'; |
||
224 | } |
||
225 | if ( $row->pk == '1' ) { |
||
226 | $type .= ' PRIMARY KEY AUTOINCREMENT'; |
||
227 | } |
||
228 | } else { // mysql |
||
229 | 2 | $type = strtoupper( $row->Type ); |
|
230 | |||
231 | 2 | if ( substr( $type, 0, 8 ) == 'VARCHAR(' ) { |
|
232 | $type .= ' binary'; // just assume this to be the case for VARCHAR, though DESCRIBE will not tell us |
||
233 | } |
||
234 | |||
235 | 2 | if ( $row->Null != 'YES' ) { |
|
236 | 2 | $type .= ' NOT NULL'; |
|
237 | } |
||
238 | |||
239 | 2 | if ( $row->Key == 'PRI' ) { /// FIXME: updating "KEY" is not possible, the below query will fail in this case. |
|
240 | 2 | $type .= ' KEY'; |
|
241 | } |
||
242 | |||
243 | 2 | if ( $row->Extra == 'auto_increment' ) { |
|
244 | 2 | $type .= ' AUTO_INCREMENT'; |
|
245 | } |
||
246 | } |
||
247 | |||
248 | 2 | $curfields[$row->Field] = $type; |
|
249 | } |
||
250 | |||
251 | 2 | return $curfields; |
|
252 | } |
||
253 | |||
254 | /** |
||
255 | * Update a single field given it's name and type and an array of |
||
256 | * current fields. Postgres version. |
||
257 | * |
||
258 | * @param string $tableName The table name. |
||
259 | * @param string $name The field name. |
||
260 | * @param string $type The field type and attributes. |
||
261 | * @param array $currentFields List of fields as they have been found in the database. |
||
262 | * @param DatabaseBase|Database $db |
||
263 | * @param object $reportTo Object to report back to. |
||
264 | */ |
||
265 | private static function updatePostgresField( $tableName, $name, $type, array $currentFields, $db, $reportTo ) { |
||
266 | $keypos = strpos( $type, ' PRIMARY KEY' ); |
||
267 | |||
268 | if ( $keypos > 0 ) { |
||
269 | $type = substr( $type, 0, $keypos ); |
||
270 | } |
||
271 | |||
272 | $type = strtoupper( $type ); |
||
273 | |||
274 | if ( !array_key_exists( $name, $currentFields ) ) { |
||
275 | self::reportProgress( " ... creating field $name ... ", $reportTo ); |
||
276 | |||
277 | $db->query( "ALTER TABLE $tableName ADD \"" . $name . "\" $type", __METHOD__ ); |
||
278 | |||
279 | self::reportProgress( "done.\n", $reportTo ); |
||
280 | } elseif ( $currentFields[$name] != $type ) { |
||
281 | self::reportProgress( " ... changing type of field $name from '$currentFields[$name]' to '$type' ... ", $reportTo ); |
||
282 | |||
283 | $notnullposnew = strpos( $type, ' NOT NULL' ); |
||
284 | if ( $notnullposnew > 0 ) { |
||
285 | $type = substr( $type, 0, $notnullposnew ); |
||
286 | } |
||
287 | |||
288 | $notnullposold = strpos( $currentFields[$name], ' NOT NULL' ); |
||
289 | $typeold = strtoupper( ( $notnullposold > 0 ) ? substr( $currentFields[$name], 0, $notnullposold ) : $currentFields[$name] ); |
||
290 | |||
291 | if ( $typeold != $type ) { |
||
292 | $sql = "ALTER TABLE " . $tableName . " ALTER COLUMN \"" . $name . "\" TYPE " . $type; |
||
293 | $db->query( $sql, __METHOD__ ); |
||
294 | } |
||
295 | |||
296 | if ( $notnullposold != $notnullposnew ) { |
||
297 | $sql = "ALTER TABLE " . $tableName . " ALTER COLUMN \"" . $name . "\" " . ( $notnullposnew > 0 ? 'SET' : 'DROP' ) . " NOT NULL"; |
||
298 | $db->query( $sql, __METHOD__ ); |
||
299 | } |
||
300 | |||
301 | self::reportProgress( "done.\n", $reportTo ); |
||
302 | } else { |
||
303 | self::reportProgress( " ... field $name is fine.\n", $reportTo ); |
||
304 | } |
||
305 | } |
||
306 | |||
307 | /** |
||
308 | * Update a single field given it's name and type and an array of |
||
309 | * current fields. MySQL version. |
||
310 | * |
||
311 | * @param string $tableName The table name. |
||
312 | * @param string $name The field name. |
||
313 | * @param string $type The field type and attributes. |
||
314 | * @param array $currentFields List of fields as they have been found in the database. |
||
315 | * @param DatabaseBase|Database $db |
||
316 | * @param object $reportTo Object to report back to. |
||
317 | * @param string $position |
||
318 | */ |
||
319 | 2 | private static function updateMySqlField( $tableName, $name, $type, array $currentFields, $db, $reportTo, $position ) { |
|
320 | 2 | if ( !array_key_exists( $name, $currentFields ) ) { |
|
321 | self::reportProgress( " ... creating field $name ... ", $reportTo ); |
||
322 | |||
323 | $db->query( "ALTER TABLE $tableName ADD `$name` $type $position", __METHOD__ ); |
||
324 | $result[$name] = 'new'; |
||
325 | |||
326 | self::reportProgress( "done.\n", $reportTo ); |
||
327 | 2 | } elseif ( $currentFields[$name] != $type ) { |
|
328 | self::reportProgress( " ... changing type of field $name from '$currentFields[$name]' to '$type' ... ", $reportTo ); |
||
329 | |||
330 | // To avoid Error: 1068 Multiple primary key defined when a PRIMARY is involved |
||
331 | if ( strpos( $type, 'AUTO_INCREMENT' ) !== false ) { |
||
332 | $db->query( "ALTER TABLE $tableName DROP PRIMARY KEY", __METHOD__ ); |
||
333 | } |
||
334 | |||
335 | $db->query( "ALTER TABLE $tableName CHANGE `$name` `$name` $type $position", __METHOD__ ); |
||
336 | $result[$name] = 'up'; |
||
337 | self::reportProgress( "done.\n", $reportTo ); |
||
338 | } else { |
||
339 | 2 | self::reportProgress( " ... field $name is fine.\n", $reportTo ); |
|
340 | } |
||
341 | 2 | } |
|
342 | |||
343 | /** |
||
344 | * Make sure that each of the column descriptions in the given array is |
||
345 | * indexed by *one* index in the given DB table. |
||
346 | * |
||
347 | * @param string $tableName table name. Does not need to have been passed to DatabaseBase->tableName yet. |
||
0 ignored issues
–
show
|
|||
348 | * @param array $indexes array of strings, each a comma separated list with column names to index |
||
349 | * @param DatabaseBase|Database $db DatabaseBase or Database |
||
350 | * @param object $reportTo object to report messages to; since 1.8 |
||
351 | */ |
||
352 | 3 | public static function setupIndex( $rawTableName, array $indexes, $db, $reportTo = null ) { |
|
353 | 3 | global $wgDBtype; |
|
354 | |||
355 | 3 | $tableName = $wgDBtype == 'postgres' ? $db->tableName( $rawTableName, 'raw' ) : $db->tableName( $rawTableName ); |
|
356 | |||
357 | 3 | self::reportProgress( "Checking index structures for table $tableName ...\n", $reportTo ); |
|
358 | |||
359 | // First remove obsolete indexes. |
||
360 | 3 | $oldIndexes = self::getIndexInfo( $db, $tableName ); |
|
361 | 3 | if ( $wgDBtype == 'sqlite' ) { // SQLite |
|
362 | /// TODO We do not currently get the right column definitions in |
||
363 | /// SQLLite; hence we can only drop all indexes. Wasteful. |
||
364 | foreach ( $oldIndexes as $key => $index ) { |
||
0 ignored issues
–
show
The expression
$oldIndexes of type false|array is not guaranteed to be traversable. How about adding an additional type check?
There are different options of fixing this problem.
Loading history...
|
|||
365 | self::dropIndex( $db, $key, $tableName, $key, $reportTo ); |
||
366 | } |
||
367 | } else { |
||
368 | 3 | foreach ( $oldIndexes as $key => $indexColumn ) { |
|
369 | 3 | $id = array_search( $indexColumn, $indexes ); |
|
370 | 3 | if ( $id !== false || $key == 'PRIMARY' ) { |
|
371 | 3 | self::reportProgress( " ... index $indexColumn is fine.\n", $reportTo ); |
|
372 | 3 | unset( $indexes[$id] ); |
|
373 | } else { // Duplicate or unrequired index. |
||
374 | 3 | self::dropIndex( $db, $key, $tableName, $indexColumn, $reportTo ); |
|
375 | } |
||
376 | } |
||
377 | } |
||
378 | |||
379 | // Add new indexes. |
||
380 | 3 | foreach ( $indexes as $key => $index ) { |
|
381 | // If the index is an array, it contains the column |
||
382 | // name as first element, and index type as second one. |
||
383 | 3 | if ( is_array( $index ) ) { |
|
384 | 3 | $columns = $index[0]; |
|
385 | 3 | $type = count( $index ) > 1 ? $index[1] : 'INDEX'; |
|
386 | } else { |
||
387 | 2 | $columns = $index; |
|
388 | 2 | $type = 'INDEX'; |
|
389 | } |
||
390 | |||
391 | 3 | self::createIndex( $db, $type, "{$tableName}_index{$key}", $tableName, $columns, $reportTo ); |
|
392 | } |
||
393 | |||
394 | 3 | self::reportProgress( " ... done.\n", $reportTo ); |
|
395 | |||
396 | 3 | return true; |
|
397 | } |
||
398 | |||
399 | /** |
||
400 | * Get the information about all indexes of a table. The result is an |
||
401 | * array of format indexname => indexcolumns. The latter is a comma |
||
402 | * separated list. |
||
403 | * |
||
404 | * @since 1.8 |
||
405 | * @param DatabaseBase|Database $db database handler |
||
406 | * @param string $tableName name of table |
||
407 | * @return array indexname => columns |
||
408 | */ |
||
409 | 3 | private static function getIndexInfo( $db, $tableName ) { |
|
410 | 3 | global $wgDBtype; |
|
0 ignored issues
–
show
Compatibility
Best Practice
introduced
by
Use of
global functionality is not recommended; it makes your code harder to test, and less reusable.
Instead of relying on 1. Pass all data via parametersfunction myFunction($a, $b) {
// Do something
}
2. Create a class that maintains your stateclass MyClass {
private $a;
private $b;
public function __construct($a, $b) {
$this->a = $a;
$this->b = $b;
}
public function myFunction() {
// Do something
}
}
Loading history...
|
|||
411 | |||
412 | 3 | $indexes = array(); |
|
413 | 3 | if ( $wgDBtype == 'postgres' ) { // postgresql |
|
414 | $sql = "SELECT i.relname AS indexname," |
||
415 | . " pg_get_indexdef(i.oid) AS indexdef, " |
||
416 | . " replace(substring(pg_get_indexdef(i.oid) from E'\\\\((.*)\\\\)'), ' ' , '') AS indexcolumns" |
||
417 | . " FROM pg_index x" |
||
418 | . " JOIN pg_class c ON c.oid = x.indrelid" |
||
419 | . " JOIN pg_class i ON i.oid = x.indexrelid" |
||
420 | . " LEFT JOIN pg_namespace n ON n.oid = c.relnamespace" |
||
421 | . " LEFT JOIN pg_tablespace t ON t.oid = i.reltablespace" |
||
422 | . " WHERE c.relkind = 'r'::\"char\" AND i.relkind = 'i'::\"char\"" |
||
423 | . " AND c.relname = '" . $tableName . "'" |
||
424 | . " AND NOT pg_get_indexdef(i.oid) ~ '^CREATE UNIQUE INDEX'"; |
||
425 | $res = $db->query( $sql, __METHOD__ ); |
||
426 | |||
427 | if ( !$res ) { |
||
428 | return false; |
||
429 | } |
||
430 | |||
431 | foreach ( $res as $row ) { |
||
432 | $indexes[$row->indexname] = $row->indexcolumns; |
||
433 | } |
||
434 | 3 | } elseif ( $wgDBtype == 'sqlite' ) { // SQLite |
|
435 | $res = $db->query( 'PRAGMA index_list(' . $tableName . ')', __METHOD__ ); |
||
436 | |||
437 | if ( !$res ) { |
||
438 | return false; |
||
439 | } |
||
440 | |||
441 | foreach ( $res as $row ) { |
||
442 | /// FIXME The value should not be $row->name below?! |
||
443 | if ( !array_key_exists( $row->name, $indexes ) ) { |
||
444 | $indexes[$row->name] = $row->name; |
||
445 | } else { |
||
446 | $indexes[$row->name] .= ',' . $row->name; |
||
447 | } |
||
448 | } |
||
449 | } else { // MySQL and default |
||
450 | 3 | $res = $db->query( 'SHOW INDEX FROM ' . $tableName, __METHOD__ ); |
|
451 | |||
452 | 3 | if ( !$res ) { |
|
453 | return false; |
||
454 | } |
||
455 | |||
456 | 3 | foreach ( $res as $row ) { |
|
457 | 3 | if ( !array_key_exists( $row->Key_name, $indexes ) ) { |
|
458 | 3 | $indexes[$row->Key_name] = $row->Column_name; |
|
459 | } else { |
||
460 | 3 | $indexes[$row->Key_name] .= ',' . $row->Column_name; |
|
461 | } |
||
462 | } |
||
463 | } |
||
464 | |||
465 | 3 | return $indexes; |
|
466 | } |
||
467 | |||
468 | /** |
||
469 | * Drop an index using the suitable SQL for various RDBMS. |
||
470 | * |
||
471 | * @since 1.8 |
||
472 | * @param DatabaseBase|Database $db database handler |
||
473 | * @param string $indexName name fo the index as in DB |
||
474 | * @param string $tableName name of the table (not relevant in all DBMSs) |
||
475 | * @param string $columns list of column names to index, comma |
||
476 | * separated; only for reporting |
||
477 | * @param object $reportTo to report messages to |
||
478 | */ |
||
479 | 2 | private static function dropIndex( $db, $indexName, $tableName, $columns, $reportTo = null ) { |
|
480 | 2 | global $wgDBtype; |
|
0 ignored issues
–
show
Compatibility
Best Practice
introduced
by
Use of
global functionality is not recommended; it makes your code harder to test, and less reusable.
Instead of relying on 1. Pass all data via parametersfunction myFunction($a, $b) {
// Do something
}
2. Create a class that maintains your stateclass MyClass {
private $a;
private $b;
public function __construct($a, $b) {
$this->a = $a;
$this->b = $b;
}
public function myFunction() {
// Do something
}
}
Loading history...
|
|||
481 | |||
482 | 2 | self::reportProgress( " ... removing index $columns ...", $reportTo ); |
|
483 | 2 | if ( $wgDBtype == 'postgres' ) { // postgresql |
|
484 | $db->query( 'DROP INDEX IF EXISTS ' . $indexName, __METHOD__ ); |
||
485 | 2 | } elseif ( $wgDBtype == 'sqlite' ) { // SQLite |
|
486 | $db->query( 'DROP INDEX ' . $indexName, __METHOD__ ); |
||
487 | } else { // MySQL and default |
||
488 | 2 | $db->query( 'DROP INDEX ' . $indexName . ' ON ' . $tableName, __METHOD__ ); |
|
489 | } |
||
490 | 2 | self::reportProgress( "done.\n", $reportTo ); |
|
491 | 2 | } |
|
492 | |||
493 | /** |
||
494 | * Create an index using the suitable SQL for various RDBMS. |
||
495 | * |
||
496 | * @since 1.8 |
||
497 | * @param DatabaseBase|Database $db Database handler |
||
498 | * @param string $type "INDEX", "UNIQUE" or similar |
||
499 | * @param string $indexName name fo the index as in DB |
||
500 | * @param string $tableName name of the table |
||
501 | * @param array $columns list of column names to index, comma separated |
||
502 | * @param object $reportTo object to report messages to |
||
503 | */ |
||
504 | 3 | private static function createIndex( $db, $type, $indexName, $tableName, $columns, $reportTo = null ) { |
|
505 | 3 | global $wgDBtype; |
|
0 ignored issues
–
show
Compatibility
Best Practice
introduced
by
Use of
global functionality is not recommended; it makes your code harder to test, and less reusable.
Instead of relying on 1. Pass all data via parametersfunction myFunction($a, $b) {
// Do something
}
2. Create a class that maintains your stateclass MyClass {
private $a;
private $b;
public function __construct($a, $b) {
$this->a = $a;
$this->b = $b;
}
public function myFunction() {
// Do something
}
}
Loading history...
|
|||
506 | |||
507 | 3 | self::reportProgress( " ... creating new index $columns ...", $reportTo ); |
|
508 | 3 | if ( $wgDBtype == 'postgres' ) { // postgresql |
|
509 | if ( $db->indexInfo( $tableName, $indexName ) === false ) { |
||
510 | $db->query( "CREATE $type $indexName ON $tableName ($columns)", __METHOD__ ); |
||
511 | } |
||
512 | 3 | } elseif ( $wgDBtype == 'sqlite' ) { // SQLite |
|
513 | $db->query( "CREATE $type $indexName ON $tableName ($columns)", __METHOD__ ); |
||
514 | } else { // MySQL and default |
||
515 | 3 | $db->query( "ALTER TABLE $tableName ADD $type ($columns)", __METHOD__ ); |
|
516 | } |
||
517 | 3 | self::reportProgress( "done.\n", $reportTo ); |
|
518 | 3 | } |
|
519 | |||
520 | /** |
||
521 | * Reports the given message to the reportProgress method of the |
||
522 | * $receiver. |
||
523 | * |
||
524 | * @param string $msg |
||
525 | * @param object $receiver |
||
526 | */ |
||
527 | 3 | private static function reportProgress( $msg, $receiver ) { |
|
528 | 3 | if ( !is_null( $receiver ) ) { |
|
529 | $receiver->reportProgress( $msg ); |
||
530 | } |
||
531 | 3 | } |
|
532 | |||
533 | } |
||
534 |
This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.
Consider the following example. The parameter
$ireland
is not defined by the methodfinale(...)
.The most likely cause is that the parameter was changed, but the annotation was not.