MediaWiki REL1_34
MysqlUpdater.php
Go to the documentation of this file.
1<?php
26
35 protected function getCoreUpdateList() {
36 return [
37 [ 'disableContentHandlerUseDB' ],
38
39 // 1.2
40 [ 'addField', 'ipblocks', 'ipb_id', 'patch-ipblocks.sql' ],
41 [ 'addField', 'ipblocks', 'ipb_expiry', 'patch-ipb_expiry.sql' ],
42 [ 'doInterwikiUpdate' ],
43 [ 'doIndexUpdate' ],
44 [ 'addField', 'recentchanges', 'rc_type', 'patch-rc_type.sql' ],
45 [ 'addIndex', 'recentchanges', 'new_name_timestamp', 'patch-rc-newindex.sql' ],
46
47 // 1.3
48 [ 'addField', 'user', 'user_real_name', 'patch-user-realname.sql' ],
49 [ 'addTable', 'querycache', 'patch-querycache.sql' ],
50 [ 'addTable', 'objectcache', 'patch-objectcache.sql' ],
51 [ 'addTable', 'categorylinks', 'patch-categorylinks.sql' ],
52 [ 'doOldLinksUpdate' ],
53 [ 'doFixAncientImagelinks' ],
54 [ 'addField', 'recentchanges', 'rc_ip', 'patch-rc_ip.sql' ],
55
56 // 1.4
57 [ 'addIndex', 'image', 'PRIMARY', 'patch-image_name_primary.sql' ],
58 [ 'addField', 'recentchanges', 'rc_id', 'patch-rc_id.sql' ],
59 [ 'addField', 'recentchanges', 'rc_patrolled', 'patch-rc-patrol.sql' ],
60 [ 'addTable', 'logging', 'patch-logging.sql' ],
61 [ 'addField', 'user', 'user_token', 'patch-user_token.sql' ],
62 [ 'addField', 'watchlist', 'wl_notificationtimestamp', 'patch-email-notification.sql' ],
63 [ 'doWatchlistUpdate' ],
64 [ 'dropField', 'user', 'user_emailauthenticationtimestamp',
65 'patch-email-authentication.sql' ],
66
67 // 1.5
68 [ 'doSchemaRestructuring' ],
69 [ 'addField', 'logging', 'log_params', 'patch-log_params.sql' ],
70 [ 'checkBin', 'logging', 'log_title', 'patch-logging-title.sql', ],
71 [ 'addField', 'archive', 'ar_rev_id', 'patch-archive-rev_id.sql' ],
72 [ 'addField', 'page', 'page_len', 'patch-page_len.sql' ],
73 [ 'dropField', 'revision', 'inverse_timestamp', 'patch-inverse_timestamp.sql' ],
74 [ 'addField', 'revision', 'rev_text_id', 'patch-rev_text_id.sql' ],
75 [ 'addField', 'revision', 'rev_deleted', 'patch-rev_deleted.sql' ],
76 [ 'addField', 'image', 'img_width', 'patch-img_width.sql' ],
77 [ 'addField', 'image', 'img_metadata', 'patch-img_metadata.sql' ],
78 [ 'addField', 'user', 'user_email_token', 'patch-user_email_token.sql' ],
79 [ 'addField', 'archive', 'ar_text_id', 'patch-archive-text_id.sql' ],
80 [ 'doNamespaceSize' ],
81 [ 'addField', 'image', 'img_media_type', 'patch-img_media_type.sql' ],
82 [ 'doPagelinksUpdate' ],
83 [ 'dropField', 'image', 'img_type', 'patch-drop_img_type.sql' ],
84 [ 'doUserUniqueUpdate' ],
85 [ 'doUserGroupsUpdate' ],
86 [ 'addField', 'site_stats', 'ss_total_pages', 'patch-ss_total_articles.sql' ],
87 [ 'addTable', 'user_newtalk', 'patch-usernewtalk.sql' ],
88 [ 'addField', 'interwiki', 'iw_trans', 'patch-interwiki-trans.sql' ],
89
90 // 1.6
91 [ 'doWatchlistNull' ],
92 [ 'addIndex', 'logging', 'times', 'patch-logging-times-index.sql' ],
93 [ 'addField', 'ipblocks', 'ipb_range_start', 'patch-ipb_range_start.sql' ],
94 [ 'doPageRandomUpdate' ],
95 [ 'addField', 'user', 'user_registration', 'patch-user_registration.sql' ],
96 [ 'doTemplatelinksUpdate' ],
97 [ 'addTable', 'externallinks', 'patch-externallinks.sql' ],
98 [ 'addTable', 'job', 'patch-job.sql' ],
99 [ 'addField', 'site_stats', 'ss_images', 'patch-ss_images.sql' ],
100 [ 'addTable', 'langlinks', 'patch-langlinks.sql' ],
101 [ 'addTable', 'querycache_info', 'patch-querycacheinfo.sql' ],
102 [ 'addTable', 'filearchive', 'patch-filearchive.sql' ],
103 [ 'addField', 'ipblocks', 'ipb_anon_only', 'patch-ipb_anon_only.sql' ],
104 [ 'ifNoActorTable', 'addIndex', 'recentchanges', 'rc_ns_usertext',
105 'patch-recentchanges-utindex.sql' ],
106 [ 'ifNoActorTable', 'addIndex', 'recentchanges', 'rc_user_text',
107 'patch-rc_user_text-index.sql' ],
108
109 // 1.9
110 [ 'addField', 'user', 'user_newpass_time', 'patch-user_newpass_time.sql' ],
111 [ 'addTable', 'redirect', 'patch-redirect.sql' ],
112 [ 'addTable', 'querycachetwo', 'patch-querycachetwo.sql' ],
113 [ 'addField', 'ipblocks', 'ipb_enable_autoblock', 'patch-ipb_optional_autoblock.sql' ],
114 [ 'doBacklinkingIndicesUpdate' ],
115 [ 'addField', 'recentchanges', 'rc_old_len', 'patch-rc_len.sql' ],
116 [ 'addField', 'user', 'user_editcount', 'patch-user_editcount.sql' ],
117
118 // 1.10
119 [ 'doRestrictionsUpdate' ],
120 [ 'addField', 'logging', 'log_id', 'patch-log_id.sql' ],
121 [ 'addField', 'revision', 'rev_parent_id', 'patch-rev_parent_id.sql' ],
122 [ 'addField', 'page_restrictions', 'pr_id', 'patch-page_restrictions_sortkey.sql' ],
123 [ 'addField', 'revision', 'rev_len', 'patch-rev_len.sql' ],
124 [ 'addField', 'recentchanges', 'rc_deleted', 'patch-rc_deleted.sql' ],
125 [ 'addField', 'logging', 'log_deleted', 'patch-log_deleted.sql' ],
126 [ 'addField', 'archive', 'ar_deleted', 'patch-ar_deleted.sql' ],
127 [ 'addField', 'ipblocks', 'ipb_deleted', 'patch-ipb_deleted.sql' ],
128 [ 'addField', 'filearchive', 'fa_deleted', 'patch-fa_deleted.sql' ],
129 [ 'addField', 'archive', 'ar_len', 'patch-ar_len.sql' ],
130
131 // 1.11
132 [ 'addField', 'ipblocks', 'ipb_block_email', 'patch-ipb_emailban.sql' ],
133 [ 'doCategorylinksIndicesUpdate' ],
134 [ 'addField', 'oldimage', 'oi_metadata', 'patch-oi_metadata.sql' ],
135 [ 'ifNoActorTable', 'addIndex', 'archive', 'usertext_timestamp',
136 'patch-archive-user-index.sql' ],
137 [ 'ifNoActorTable', 'addIndex', 'image', 'img_usertext_timestamp',
138 'patch-image-user-index.sql' ],
139 [ 'ifNoActorTable', 'addIndex', 'oldimage', 'oi_usertext_timestamp',
140 'patch-oldimage-user-index.sql' ],
141 [ 'addField', 'archive', 'ar_page_id', 'patch-archive-page_id.sql' ],
142 [ 'addField', 'image', 'img_sha1', 'patch-img_sha1.sql' ],
143
144 // 1.12
145 [ 'addTable', 'protected_titles', 'patch-protected_titles.sql' ],
146
147 // 1.13
148 [ 'ifNoActorTable', 'addField', 'ipblocks', 'ipb_by_text', 'patch-ipb_by_text.sql' ],
149 [ 'addTable', 'page_props', 'patch-page_props.sql' ],
150 [ 'addTable', 'updatelog', 'patch-updatelog.sql' ],
151 [ 'addTable', 'category', 'patch-category.sql' ],
152 [ 'doCategoryPopulation' ],
153 [ 'addField', 'archive', 'ar_parent_id', 'patch-ar_parent_id.sql' ],
154 [ 'addField', 'user_newtalk', 'user_last_timestamp', 'patch-user_last_timestamp.sql' ],
155 [ 'doPopulateParentId' ],
156 [ 'checkBin', 'protected_titles', 'pt_title', 'patch-pt_title-encoding.sql', ],
157 [ 'doMaybeProfilingMemoryUpdate' ],
158 [ 'ifNoActorTable', 'doFilearchiveIndicesUpdate' ],
159
160 // 1.14
161 [ 'addField', 'site_stats', 'ss_active_users', 'patch-ss_active_users.sql' ],
162 [ 'doActiveUsersInit' ],
163 [ 'addField', 'ipblocks', 'ipb_allow_usertalk', 'patch-ipb_allow_usertalk.sql' ],
164
165 // 1.15
166 [ 'addTable', 'change_tag', 'patch-change_tag.sql' ],
167
168 // 1.16
169 [ 'addTable', 'user_properties', 'patch-user_properties.sql' ],
170 [ 'addTable', 'log_search', 'patch-log_search.sql' ],
171 [ 'ifNoActorTable', 'addField', 'logging', 'log_user_text', 'patch-log_user_text.sql' ],
172 # listed separately from the previous update because 1.16 was released without this update
173 [ 'ifNoActorTable', 'doLogUsertextPopulation' ],
174 [ 'doLogSearchPopulation' ],
175 [ 'addTable', 'l10n_cache', 'patch-l10n_cache.sql' ],
176 [ 'dropIndex', 'change_tag', 'ct_rc_id', 'patch-change_tag-indexes.sql' ],
177 [ 'addField', 'redirect', 'rd_interwiki', 'patch-rd_interwiki.sql' ],
178 [ 'doUpdateMimeMinorField' ],
179
180 // 1.17
181 [ 'addTable', 'iwlinks', 'patch-iwlinks.sql' ],
182 [ 'addIndex', 'iwlinks', 'iwl_prefix_title_from', 'patch-rename-iwl_prefix.sql' ],
183 [ 'addField', 'updatelog', 'ul_value', 'patch-ul_value.sql' ],
184 [ 'addField', 'interwiki', 'iw_api', 'patch-iw_api_and_wikiid.sql' ],
185 [ 'dropIndex', 'iwlinks', 'iwl_prefix', 'patch-kill-iwl_prefix.sql' ],
186 [ 'addField', 'categorylinks', 'cl_collation', 'patch-categorylinks-better-collation.sql' ],
187 [ 'doClFieldsUpdate' ],
188 [ 'addTable', 'module_deps', 'patch-module_deps.sql' ],
189 [ 'dropIndex', 'archive', 'ar_page_revid', 'patch-archive_kill_ar_page_revid.sql' ],
190 [ 'addIndexIfNoneExist',
191 'archive', [ 'ar_revid', 'ar_revid_uniq' ], 'patch-archive_ar_revid.sql' ],
192 [ 'doLangLinksLengthUpdate' ],
193
194 // 1.18
195 [ 'doUserNewTalkTimestampNotNull' ],
196 [ 'addIndex', 'user', 'user_email', 'patch-user_email_index.sql' ],
197 [ 'modifyField', 'user_properties', 'up_property', 'patch-up_property.sql' ],
198 [ 'addTable', 'uploadstash', 'patch-uploadstash.sql' ],
199 [ 'addTable', 'user_former_groups', 'patch-user_former_groups.sql' ],
200
201 // 1.19
202 [ 'addField', 'revision', 'rev_sha1', 'patch-rev_sha1.sql' ],
203 [ 'doMigrateUserOptions' ],
204 [ 'dropField', 'user', 'user_options', 'patch-drop-user_options.sql' ],
205 [ 'addField', 'archive', 'ar_sha1', 'patch-ar_sha1.sql' ],
206 [ 'addIndex', 'page', 'page_redirect_namespace_len',
207 'patch-page_redirect_namespace_len.sql' ],
208 [ 'addField', 'uploadstash', 'us_chunk_inx', 'patch-uploadstash_chunk.sql' ],
209 [ 'addfield', 'job', 'job_timestamp', 'patch-jobs-add-timestamp.sql' ],
210
211 // 1.20
212 [ 'addIndex', 'revision', 'page_user_timestamp', 'patch-revision-user-page-index.sql' ],
213 [ 'addField', 'ipblocks', 'ipb_parent_block_id', 'patch-ipb-parent-block-id.sql' ],
214 [ 'addIndex', 'ipblocks', 'ipb_parent_block_id', 'patch-ipb-parent-block-id-index.sql' ],
215 [ 'dropField', 'category', 'cat_hidden', 'patch-cat_hidden.sql' ],
216
217 // 1.21
218 [ 'addField', 'revision', 'rev_content_format', 'patch-revision-rev_content_format.sql' ],
219 [ 'addField', 'revision', 'rev_content_model', 'patch-revision-rev_content_model.sql' ],
220 [ 'addField', 'archive', 'ar_content_format', 'patch-archive-ar_content_format.sql' ],
221 [ 'addField', 'archive', 'ar_content_model', 'patch-archive-ar_content_model.sql' ],
222 [ 'addField', 'page', 'page_content_model', 'patch-page-page_content_model.sql' ],
223 [ 'enableContentHandlerUseDB' ],
224 [ 'dropField', 'site_stats', 'ss_admins', 'patch-drop-ss_admins.sql' ],
225 [ 'dropField', 'recentchanges', 'rc_moved_to_title', 'patch-rc_moved.sql' ],
226 [ 'addTable', 'sites', 'patch-sites.sql' ],
227 [ 'addField', 'filearchive', 'fa_sha1', 'patch-fa_sha1.sql' ],
228 [ 'addField', 'job', 'job_token', 'patch-job_token.sql' ],
229 [ 'addField', 'job', 'job_attempts', 'patch-job_attempts.sql' ],
230 [ 'doEnableProfiling' ],
231 [ 'addField', 'uploadstash', 'us_props', 'patch-uploadstash-us_props.sql' ],
232 [ 'modifyField', 'user_groups', 'ug_group', 'patch-ug_group-length-increase-255.sql' ],
233 [ 'modifyField', 'user_former_groups', 'ufg_group',
234 'patch-ufg_group-length-increase-255.sql' ],
235 [ 'addIndex', 'page_props', 'pp_propname_page',
236 'patch-page_props-propname-page-index.sql' ],
237 [ 'addIndex', 'image', 'img_media_mime', 'patch-img_media_mime-index.sql' ],
238
239 // 1.22
240 [ 'doIwlinksIndexNonUnique' ],
241 [ 'addIndex', 'iwlinks', 'iwl_prefix_from_title',
242 'patch-iwlinks-from-title-index.sql' ],
243 [ 'addField', 'archive', 'ar_id', 'patch-archive-ar_id.sql' ],
244 [ 'addField', 'externallinks', 'el_id', 'patch-externallinks-el_id.sql' ],
245
246 // 1.23
247 [ 'addField', 'recentchanges', 'rc_source', 'patch-rc_source.sql' ],
248 [ 'ifNoActorTable', 'addIndex', 'logging', 'log_user_text_type_time',
249 'patch-logging_user_text_type_time_index.sql' ],
250 [ 'ifNoActorTable', 'addIndex', 'logging', 'log_user_text_time',
251 'patch-logging_user_text_time_index.sql' ],
252 [ 'addField', 'page', 'page_links_updated', 'patch-page_links_updated.sql' ],
253 [ 'addField', 'user', 'user_password_expires', 'patch-user_password_expire.sql' ],
254
255 // 1.24
256 [ 'addField', 'page_props', 'pp_sortkey', 'patch-pp_sortkey.sql' ],
257 [ 'dropField', 'recentchanges', 'rc_cur_time', 'patch-drop-rc_cur_time.sql' ],
258 [ 'addIndex', 'watchlist', 'wl_user_notificationtimestamp',
259 'patch-watchlist-user-notificationtimestamp-index.sql' ],
260 [ 'addField', 'page', 'page_lang', 'patch-page_lang.sql' ],
261 [ 'addField', 'pagelinks', 'pl_from_namespace', 'patch-pl_from_namespace.sql' ],
262 [ 'addField', 'templatelinks', 'tl_from_namespace', 'patch-tl_from_namespace.sql' ],
263 [ 'addField', 'imagelinks', 'il_from_namespace', 'patch-il_from_namespace.sql' ],
264 [ 'modifyField', 'image', 'img_major_mime',
265 'patch-img_major_mime-chemical.sql' ],
266 [ 'modifyField', 'oldimage', 'oi_major_mime',
267 'patch-oi_major_mime-chemical.sql' ],
268 [ 'modifyField', 'filearchive', 'fa_major_mime',
269 'patch-fa_major_mime-chemical.sql' ],
270
271 // 1.25
272 // note this patch covers other _comment and _description fields too
273 [ 'doExtendCommentLengths' ],
274
275 // 1.26
276 [ 'dropTable', 'hitcounter' ],
277 [ 'dropField', 'site_stats', 'ss_total_views', 'patch-drop-ss_total_views.sql' ],
278 [ 'dropField', 'page', 'page_counter', 'patch-drop-page_counter.sql' ],
279
280 // 1.27
281 [ 'dropTable', 'msg_resource_links' ],
282 [ 'dropTable', 'msg_resource' ],
283 [ 'addTable', 'bot_passwords', 'patch-bot_passwords.sql' ],
284 [ 'addField', 'watchlist', 'wl_id', 'patch-watchlist-wl_id.sql' ],
285 [ 'dropIndex', 'categorylinks', 'cl_collation', 'patch-kill-cl_collation_index.sql' ],
286 [ 'addIndex', 'categorylinks', 'cl_collation_ext',
287 'patch-add-cl_collation_ext_index.sql' ],
288 [ 'doCollationUpdate' ],
289
290 // 1.28
291 [ 'addIndex', 'recentchanges', 'rc_name_type_patrolled_timestamp',
292 'patch-add-rc_name_type_patrolled_timestamp_index.sql' ],
293 [ 'doRevisionPageRevIndexNonUnique' ],
294 [ 'doNonUniquePlTlIl' ],
295 [ 'addField', 'change_tag', 'ct_id', 'patch-change_tag-ct_id.sql' ],
296 [ 'modifyField', 'recentchanges', 'rc_ip', 'patch-rc_ip_modify.sql' ],
297 [ 'ifNoActorTable', 'addIndex', 'archive', 'usertext_timestamp',
298 'patch-rename-ar_usertext_timestamp.sql' ],
299
300 // 1.29
301 [ 'addField', 'externallinks', 'el_index_60', 'patch-externallinks-el_index_60.sql' ],
302 [ 'dropIndex', 'user_groups', 'ug_user_group', 'patch-user_groups-primary-key.sql' ],
303 [ 'addField', 'user_groups', 'ug_expiry', 'patch-user_groups-ug_expiry.sql' ],
304 [ 'ifNoActorTable', 'addIndex', 'image', 'img_user_timestamp', 'patch-image-user-index-2.sql' ],
305
306 // 1.30
307 [ 'modifyField', 'image', 'img_media_type', 'patch-add-3d.sql' ],
308 [ 'addTable', 'ip_changes', 'patch-ip_changes.sql' ],
309 [ 'renameIndex', 'categorylinks', 'cl_from', 'PRIMARY', false,
310 'patch-categorylinks-fix-pk.sql' ],
311 [ 'renameIndex', 'templatelinks', 'tl_from', 'PRIMARY', false,
312 'patch-templatelinks-fix-pk.sql' ],
313 [ 'renameIndex', 'pagelinks', 'pl_from', 'PRIMARY', false, 'patch-pagelinks-fix-pk.sql' ],
314 [ 'renameIndex', 'text', 'old_id', 'PRIMARY', false, 'patch-text-fix-pk.sql' ],
315 [ 'renameIndex', 'imagelinks', 'il_from', 'PRIMARY', false, 'patch-imagelinks-fix-pk.sql' ],
316 [ 'renameIndex', 'iwlinks', 'iwl_from', 'PRIMARY', false, 'patch-iwlinks-fix-pk.sql' ],
317 [ 'renameIndex', 'langlinks', 'll_from', 'PRIMARY', false, 'patch-langlinks-fix-pk.sql' ],
318 [ 'renameIndex', 'log_search', 'ls_field_val', 'PRIMARY', false, 'patch-log_search-fix-pk.sql' ],
319 [ 'renameIndex', 'module_deps', 'md_module_skin', 'PRIMARY', false,
320 'patch-module_deps-fix-pk.sql' ],
321 [ 'renameIndex', 'objectcache', 'keyname', 'PRIMARY', false, 'patch-objectcache-fix-pk.sql' ],
322 [ 'renameIndex', 'querycache_info', 'qci_type', 'PRIMARY', false,
323 'patch-querycache_info-fix-pk.sql' ],
324 [ 'renameIndex', 'site_stats', 'ss_row_id', 'PRIMARY', false, 'patch-site_stats-fix-pk.sql' ],
325 [ 'renameIndex', 'user_former_groups', 'ufg_user_group', 'PRIMARY', false,
326 'patch-user_former_groups-fix-pk.sql' ],
327 [ 'renameIndex', 'user_properties', 'user_properties_user_property', 'PRIMARY', false,
328 'patch-user_properties-fix-pk.sql' ],
329 [ 'addTable', 'comment', 'patch-comment-table.sql' ],
330 [ 'addTable', 'revision_comment_temp', 'patch-revision_comment_temp-table.sql' ],
331 // image_comment_temp is no longer needed when upgrading to MW 1.31 or newer,
332 // as it is dropped later in the update process as part of 'migrateImageCommentTemp'.
333 // File kept on disk and the updater entry here for historical purposes.
334 // [ 'addTable', 'image_comment_temp', 'patch-image_comment_temp-table.sql' ],
335 [ 'addField', 'archive', 'ar_comment_id', 'patch-archive-ar_comment_id.sql' ],
336 [ 'addField', 'filearchive', 'fa_description_id', 'patch-filearchive-fa_description_id.sql' ],
337 [ 'modifyField', 'image', 'img_description', 'patch-image-img_description-default.sql' ],
338 [ 'addField', 'ipblocks', 'ipb_reason_id', 'patch-ipblocks-ipb_reason_id.sql' ],
339 [ 'addField', 'logging', 'log_comment_id', 'patch-logging-log_comment_id.sql' ],
340 [ 'addField', 'oldimage', 'oi_description_id', 'patch-oldimage-oi_description_id.sql' ],
341 [ 'addField', 'protected_titles', 'pt_reason_id', 'patch-protected_titles-pt_reason_id.sql' ],
342 [ 'addField', 'recentchanges', 'rc_comment_id', 'patch-recentchanges-rc_comment_id.sql' ],
343 [ 'modifyField', 'revision', 'rev_comment', 'patch-revision-rev_comment-default.sql' ],
344
345 // This field was added in 1.31, but is put here so it can be used by 'migrateComments'
346 [ 'addField', 'image', 'img_description_id', 'patch-image-img_description_id.sql' ],
347
348 [ 'migrateComments' ],
349 [ 'renameIndex', 'l10n_cache', 'lc_lang_key', 'PRIMARY', false,
350 'patch-l10n_cache-primary-key.sql' ],
351 [ 'doUnsignedSyncronisation' ],
352
353 // 1.31
354 [ 'addTable', 'slots', 'patch-slots.sql' ],
355 [ 'addField', 'slots', 'slot_origin', 'patch-slot-origin.sql' ],
356 [ 'addTable', 'content', 'patch-content.sql' ],
357 [ 'addTable', 'slot_roles', 'patch-slot_roles.sql' ],
358 [ 'addTable', 'content_models', 'patch-content_models.sql' ],
359 [ 'migrateArchiveText' ],
360 [ 'addTable', 'actor', 'patch-actor-table.sql' ],
361 [ 'addTable', 'revision_actor_temp', 'patch-revision_actor_temp-table.sql' ],
362 [ 'addField', 'archive', 'ar_actor', 'patch-archive-ar_actor.sql' ],
363 [ 'addField', 'ipblocks', 'ipb_by_actor', 'patch-ipblocks-ipb_by_actor.sql' ],
364 [ 'addField', 'image', 'img_actor', 'patch-image-img_actor.sql' ],
365 [ 'addField', 'oldimage', 'oi_actor', 'patch-oldimage-oi_actor.sql' ],
366 [ 'addField', 'filearchive', 'fa_actor', 'patch-filearchive-fa_actor.sql' ],
367 [ 'addField', 'recentchanges', 'rc_actor', 'patch-recentchanges-rc_actor.sql' ],
368 [ 'addField', 'logging', 'log_actor', 'patch-logging-log_actor.sql' ],
369 [ 'migrateActors' ],
370 [ 'modifyField', 'revision', 'rev_text_id', 'patch-rev_text_id-default.sql' ],
371 [ 'modifyTable', 'site_stats', 'patch-site_stats-modify.sql' ],
372 [ 'populateArchiveRevId' ],
373 [ 'addIndex', 'recentchanges', 'rc_namespace_title_timestamp',
374 'patch-recentchanges-nttindex.sql' ],
375
376 // 1.32
377 [ 'addTable', 'change_tag_def', 'patch-change_tag_def.sql' ],
378 [ 'populateExternallinksIndex60' ],
379 [ 'modifyfield', 'externallinks', 'el_index_60',
380 'patch-externallinks-el_index_60-drop-default.sql' ],
381 [ 'runMaintenance', DeduplicateArchiveRevId::class, 'maintenance/deduplicateArchiveRevId.php' ],
382 [ 'addField', 'change_tag', 'ct_tag_id', 'patch-change_tag-tag_id.sql' ],
383 [ 'addIndex', 'archive', 'ar_revid_uniq', 'patch-archive-ar_rev_id-unique.sql' ],
384 [ 'populateContentTables' ],
385 [ 'addIndex', 'logging', 'log_type_action', 'patch-logging-log-type-action-index.sql' ],
386 [ 'dropIndex', 'logging', 'type_action', 'patch-logging-drop-type-action-index.sql' ],
387 [ 'renameIndex', 'interwiki', 'iw_prefix', 'PRIMARY', false, 'patch-interwiki-fix-pk.sql' ],
388 [ 'renameIndex', 'page_props', 'pp_page_propname', 'PRIMARY', false,
389 'patch-page_props-fix-pk.sql' ],
390 [ 'renameIndex', 'protected_titles', 'pt_namespace_title', 'PRIMARY', false,
391 'patch-protected_titles-fix-pk.sql' ],
392 [ 'renameIndex', 'site_identifiers', 'site_ids_type', 'PRIMARY', false,
393 'patch-site_identifiers-fix-pk.sql' ],
394 [ 'addIndex', 'recentchanges', 'rc_this_oldid', 'patch-recentchanges-rc_this_oldid-index.sql' ],
395 [ 'dropTable', 'transcache' ],
396 [ 'runMaintenance', PopulateChangeTagDef::class, 'maintenance/populateChangeTagDef.php' ],
397 [ 'addIndex', 'change_tag', 'change_tag_rc_tag_id',
398 'patch-change_tag-change_tag_rc_tag_id.sql' ],
399 [ 'addField', 'ipblocks', 'ipb_sitewide', 'patch-ipb_sitewide.sql' ],
400 [ 'addTable', 'ipblocks_restrictions', 'patch-ipblocks_restrictions-table.sql' ],
401 [ 'migrateImageCommentTemp' ],
402
403 // 1,33
404 [ 'dropField', 'change_tag', 'ct_tag', 'patch-drop-ct_tag.sql' ],
405 [ 'dropTable', 'valid_tag' ],
406 [ 'dropTable', 'tag_summary' ],
407 [ 'dropField', 'archive', 'ar_comment', 'patch-archive-drop-ar_comment.sql' ],
408 [ 'dropField', 'ipblocks', 'ipb_reason', 'patch-ipblocks-drop-ipb_reason.sql' ],
409 [ 'dropField', 'image', 'img_description', 'patch-image-drop-img_description.sql' ],
410 [ 'dropField', 'oldimage', 'oi_description', 'patch-oldimage-drop-oi_description.sql' ],
411 [ 'dropField', 'filearchive', 'fa_description', 'patch-filearchive-drop-fa_description.sql' ],
412 [ 'dropField', 'recentchanges', 'rc_comment', 'patch-recentchanges-drop-rc_comment.sql' ],
413 [ 'dropField', 'logging', 'log_comment', 'patch-logging-drop-log_comment.sql' ],
414 [ 'dropField', 'protected_titles', 'pt_reason', 'patch-protected_titles-drop-pt_reason.sql' ],
415 [ 'modifyTable', 'job', 'patch-job-params-mediumblob.sql' ],
416
417 // 1.34
418 [ 'dropIndex', 'archive', 'ar_usertext_timestamp',
419 'patch-drop-archive-ar_usertext_timestamp.sql' ],
420 [ 'dropIndex', 'archive', 'usertext_timestamp', 'patch-drop-archive-usertext_timestamp.sql' ],
421 [ 'dropField', 'archive', 'ar_user', 'patch-drop-archive-user-fields.sql' ],
422 [ 'dropField', 'ipblocks', 'ip_by', 'patch-drop-ipblocks-user-fields.sql' ],
423 [ 'dropField', 'image', 'img_user', 'patch-drop-image-user-fields.sql' ],
424 [ 'dropField', 'oldimage', 'oi_user', 'patch-drop-oldimage-user-fields.sql' ],
425 [ 'dropField', 'filearchive', 'fa_user', 'patch-drop-filearchive-user-fields.sql' ],
426 [ 'dropField', 'recentchanges', 'rc_user', 'patch-drop-recentchanges-user-fields.sql' ],
427 [ 'dropField', 'logging', 'log_user', 'patch-drop-logging-user-fields.sql' ],
428 [ 'addIndex', 'user_newtalk', 'un_user_ip', 'patch-rename-mysql-user_newtalk-indexes.sql' ],
429 ];
430 }
431
441 protected function checkBin( $table, $field, $patchFile ) {
442 if ( !$this->doTable( $table ) ) {
443 return true;
444 }
445
447 $fieldInfo = $this->db->fieldInfo( $table, $field );
448 if ( $fieldInfo->isBinary() ) {
449 $this->output( "...$table table has correct $field encoding.\n" );
450 } else {
451 $this->applyPatch( $patchFile, false, "Fixing $field encoding on $table table" );
452 }
453 }
454
463 protected function indexHasField( $table, $index, $field ) {
464 if ( !$this->doTable( $table ) ) {
465 return true;
466 }
467
468 $info = $this->db->indexInfo( $table, $index, __METHOD__ );
469 if ( $info ) {
470 foreach ( $info as $row ) {
471 if ( $row->Column_name == $field ) {
472 $this->output( "...index $index on table $table includes field $field.\n" );
473
474 return true;
475 }
476 }
477 }
478 $this->output( "...index $index on table $table has no field $field; added.\n" );
479
480 return false;
481 }
482
486 protected function doInterwikiUpdate() {
487 global $IP;
488
489 if ( !$this->doTable( 'interwiki' ) ) {
490 return;
491 }
492
493 if ( $this->db->tableExists( "interwiki", __METHOD__ ) ) {
494 $this->output( "...already have interwiki table\n" );
495
496 return;
497 }
498
499 $this->applyPatch( 'patch-interwiki.sql', false, 'Creating interwiki table' );
500 $this->applyPatch(
501 "$IP/maintenance/interwiki.sql",
502 true,
503 'Adding default interwiki definitions'
504 );
505 }
506
510 protected function doIndexUpdate() {
511 $meta = $this->db->fieldInfo( 'recentchanges', 'rc_timestamp' );
512 if ( $meta === false ) {
513 throw new MWException( 'Missing rc_timestamp field of recentchanges table. Should not happen.' );
514 }
515 if ( $meta->isMultipleKey() ) {
516 $this->output( "...indexes seem up to 20031107 standards.\n" );
517
518 return;
519 }
520
521 $this->applyPatch( 'patch-indexes.sql', true, "Updating indexes to 20031107" );
522 }
523
524 protected function doOldLinksUpdate() {
525 $cl = $this->maintenance->runChild( ConvertLinks::class );
526 $cl->execute();
527 }
528
529 protected function doFixAncientImagelinks() {
530 $info = $this->db->fieldInfo( 'imagelinks', 'il_from' );
531 if ( !$info || $info->type() !== 'string' ) {
532 $this->output( "...il_from OK\n" );
533
534 return;
535 }
536
537 $applied = $this->applyPatch(
538 'patch-fix-il_from.sql',
539 false,
540 'Fixing ancient broken imagelinks table.'
541 );
542
543 if ( $applied ) {
544 $this->output( "NOTE: you will have to run maintenance/refreshLinks.php after this." );
545 }
546 }
547
551 function doWatchlistUpdate() {
552 $talk = $this->db->selectField( 'watchlist', 'count(*)', 'wl_namespace & 1', __METHOD__ );
553 $nontalk = $this->db->selectField(
554 'watchlist',
555 'count(*)',
556 'NOT (wl_namespace & 1)',
557 __METHOD__
558 );
559 if ( $talk == $nontalk ) {
560 $this->output( "...watchlist talk page rows already present.\n" );
561
562 return;
563 }
564
565 $insertOpts = [ 'IGNORE' ];
566 $selectOpts = [];
567
568 // If wl_id exists, make insertSelect() more replication-safe by
569 // ordering on that column. If not, hint that it should be safe anyway.
570 if ( $this->db->fieldExists( 'watchlist', 'wl_id', __METHOD__ ) ) {
571 $selectOpts['ORDER BY'] = 'wl_id';
572 } else {
573 $insertOpts[] = 'NO_AUTO_COLUMNS';
574 }
575
576 $this->output( "Adding missing watchlist talk page rows... " );
577 $this->db->insertSelect( 'watchlist', 'watchlist',
578 [
579 'wl_user' => 'wl_user',
580 'wl_namespace' => 'wl_namespace | 1',
581 'wl_title' => 'wl_title',
582 'wl_notificationtimestamp' => 'wl_notificationtimestamp'
583 ], [ 'NOT (wl_namespace & 1)' ], __METHOD__, $insertOpts, $selectOpts );
584 $this->output( "done.\n" );
585
586 $this->output( "Adding missing watchlist subject page rows... " );
587 $this->db->insertSelect( 'watchlist', 'watchlist',
588 [
589 'wl_user' => 'wl_user',
590 'wl_namespace' => 'wl_namespace & ~1',
591 'wl_title' => 'wl_title',
592 'wl_notificationtimestamp' => 'wl_notificationtimestamp'
593 ], [ 'wl_namespace & 1' ], __METHOD__, $insertOpts, $selectOpts );
594 $this->output( "done.\n" );
595 }
596
598 if ( $this->db->tableExists( 'page', __METHOD__ ) ) {
599 $this->output( "...page table already exists.\n" );
600
601 return;
602 }
603
604 $this->output( "...converting from cur/old to page/revision/text DB structure.\n" );
605 $this->output( wfTimestamp( TS_DB ) );
606 $this->output( "......checking for duplicate entries.\n" );
607
608 list( $cur, $old, $page, $revision, $text ) = $this->db->tableNamesN(
609 'cur',
610 'old',
611 'page',
612 'revision',
613 'text'
614 );
615
616 $rows = $this->db->query( "
617 SELECT cur_title, cur_namespace, COUNT(cur_namespace) AS c
618 FROM $cur
619 GROUP BY cur_title, cur_namespace
620 HAVING c>1",
621 __METHOD__
622 );
623
624 if ( $rows->numRows() > 0 ) {
625 $this->output( wfTimestamp( TS_DB ) );
626 $this->output( "......<b>Found duplicate entries</b>\n" );
627 $this->output( sprintf( "<b> %-60s %3s %5s</b>\n", 'Title', 'NS', 'Count' ) );
628 $duplicate = [];
629 foreach ( $rows as $row ) {
630 if ( !isset( $duplicate[$row->cur_namespace] ) ) {
631 $duplicate[$row->cur_namespace] = [];
632 }
633
634 $duplicate[$row->cur_namespace][] = $row->cur_title;
635 $this->output( sprintf(
636 " %-60s %3s %5s\n",
637 $row->cur_title, $row->cur_namespace,
638 $row->c
639 ) );
640 }
641 $sql = "SELECT cur_title, cur_namespace, cur_id, cur_timestamp FROM $cur WHERE ";
642 $dupeTitles = [];
643 foreach ( $duplicate as $ns => $titles ) {
644 $dupeTitles[] = "( cur_namespace = {$ns} AND cur_title in ("
645 . $this->db->makeList( $titles ) . ") ) \n";
646 }
647 $sql .= $this->db->makeList( $dupeTitles, IDatabase::LIST_OR );
648 # By sorting descending, the most recent entry will be the first in the list.
649 # All following entries will be deleted by the next while-loop.
650 $sql .= 'ORDER BY cur_namespace, cur_title, cur_timestamp DESC';
651
652 $rows = $this->db->query( $sql, __METHOD__ );
653
654 $prev_title = $prev_namespace = false;
655 $deleteId = [];
656
657 foreach ( $rows as $row ) {
658 if ( $prev_title == $row->cur_title && $prev_namespace == $row->cur_namespace ) {
659 $deleteId[] = (int)$row->cur_id;
660 }
661 $prev_title = $row->cur_title;
662 $prev_namespace = $row->cur_namespace;
663 }
664 $sql = "DELETE FROM $cur WHERE cur_id IN ( " . implode( ',', $deleteId ) . ')';
665 $this->db->query( $sql, __METHOD__ );
666 $this->output( wfTimestamp( TS_DB ) );
667 $this->output( "......<b>Deleted</b> " . $this->db->affectedRows() . " records.\n" );
668 }
669
670 $this->output( wfTimestamp( TS_DB ) );
671 $this->output( "......Creating tables.\n" );
672 $this->db->query( "CREATE TABLE $page (
673 page_id int(8) unsigned NOT NULL auto_increment,
674 page_namespace int NOT NULL,
675 page_title varchar(255) binary NOT NULL,
676 page_restrictions tinyblob NOT NULL,
677 page_is_redirect tinyint(1) unsigned NOT NULL default '0',
678 page_is_new tinyint(1) unsigned NOT NULL default '0',
679 page_random real unsigned NOT NULL,
680 page_touched char(14) binary NOT NULL default '',
681 page_latest int(8) unsigned NOT NULL,
682 page_len int(8) unsigned NOT NULL,
683
684 PRIMARY KEY page_id (page_id),
685 UNIQUE INDEX name_title (page_namespace,page_title),
686 INDEX (page_random),
687 INDEX (page_len)
688 ) ENGINE=InnoDB", __METHOD__ );
689 $this->db->query( "CREATE TABLE $revision (
690 rev_id int(8) unsigned NOT NULL auto_increment,
691 rev_page int(8) unsigned NOT NULL,
692 rev_comment tinyblob NOT NULL,
693 rev_user int(5) unsigned NOT NULL default '0',
694 rev_user_text varchar(255) binary NOT NULL default '',
695 rev_timestamp char(14) binary NOT NULL default '',
696 rev_minor_edit tinyint(1) unsigned NOT NULL default '0',
697 rev_deleted tinyint(1) unsigned NOT NULL default '0',
698 rev_len int(8) unsigned,
699 rev_parent_id int(8) unsigned default NULL,
700 PRIMARY KEY rev_page_id (rev_page, rev_id),
701 UNIQUE INDEX rev_id (rev_id),
702 INDEX rev_timestamp (rev_timestamp),
703 INDEX page_timestamp (rev_page,rev_timestamp),
704 INDEX user_timestamp (rev_user,rev_timestamp),
705 INDEX usertext_timestamp (rev_user_text,rev_timestamp)
706 ) ENGINE=InnoDB", __METHOD__ );
707
708 $this->output( wfTimestamp( TS_DB ) );
709 $this->output( "......Locking tables.\n" );
710 $this->db->query(
711 "LOCK TABLES $page WRITE, $revision WRITE, $old WRITE, $cur WRITE",
712 __METHOD__
713 );
714
715 $maxold = intval( $this->db->selectField( 'old', 'max(old_id)', '', __METHOD__ ) );
716 $this->output( wfTimestamp( TS_DB ) );
717 $this->output( "......maxold is {$maxold}\n" );
718
719 $this->output( wfTimestamp( TS_DB ) );
722 // Create HistoryBlobCurStub entries.
723 // Text will be pulled from the leftover 'cur' table at runtime.
724 $this->output( "......Moving metadata from cur; using blob references to text in cur table.\n" );
725 $cur_text = "concat('O:18:\"historyblobcurstub\":1:{s:6:\"mCurId\";i:',cur_id,';}')";
726 $cur_flags = "'object'";
727 } else {
728 // Copy all cur text in immediately: this may take longer but avoids
729 // having to keep an extra table around.
730 $this->output( "......Moving text from cur.\n" );
731 $cur_text = 'cur_text';
732 $cur_flags = "''";
733 }
734 $this->db->query(
735 "INSERT INTO $old (old_namespace, old_title, old_text, old_comment, old_user,
736 old_user_text, old_timestamp, old_minor_edit, old_flags)
737 SELECT cur_namespace, cur_title, $cur_text, cur_comment, cur_user, cur_user_text,
738 cur_timestamp, cur_minor_edit, $cur_flags
739 FROM $cur",
740 __METHOD__
741 );
742
743 $this->output( wfTimestamp( TS_DB ) );
744 $this->output( "......Setting up revision table.\n" );
745 $this->db->query(
746 "INSERT INTO $revision (rev_id, rev_page, rev_comment, rev_user,
747 rev_user_text, rev_timestamp, rev_minor_edit)
748 SELECT old_id, cur_id, old_comment, old_user, old_user_text,
749 old_timestamp, old_minor_edit
750 FROM $old,$cur WHERE old_namespace=cur_namespace AND old_title=cur_title",
751 __METHOD__
752 );
753
754 $this->output( wfTimestamp( TS_DB ) );
755 $this->output( "......Setting up page table.\n" );
756 $this->db->query(
757 "INSERT INTO $page (page_id, page_namespace, page_title,
758 page_restrictions, page_is_redirect, page_is_new, page_random,
759 page_touched, page_latest, page_len)
760 SELECT cur_id, cur_namespace, cur_title, cur_restrictions,
761 cur_is_redirect, cur_is_new, cur_random, cur_touched, rev_id, LENGTH(cur_text)
762 FROM $cur,$revision
763 WHERE cur_id=rev_page AND rev_timestamp=cur_timestamp AND rev_id > {$maxold}",
764 __METHOD__
765 );
766
767 $this->output( wfTimestamp( TS_DB ) );
768 $this->output( "......Unlocking tables.\n" );
769 $this->db->query( "UNLOCK TABLES", __METHOD__ );
770
771 $this->output( wfTimestamp( TS_DB ) );
772 $this->output( "......Renaming old.\n" );
773 $this->db->query( "ALTER TABLE $old RENAME TO $text", __METHOD__ );
774
775 $this->output( wfTimestamp( TS_DB ) );
776 $this->output( "...done.\n" );
777 }
778
779 protected function doNamespaceSize() {
780 $tables = [
781 'page' => 'page',
782 'archive' => 'ar',
783 'recentchanges' => 'rc',
784 'watchlist' => 'wl',
785 'querycache' => 'qc',
786 'logging' => 'log',
787 ];
788 foreach ( $tables as $table => $prefix ) {
789 $field = $prefix . '_namespace';
790
791 $tablename = $this->db->tableName( $table );
792 $result = $this->db->query( "SHOW COLUMNS FROM $tablename LIKE '$field'", __METHOD__ );
793 $info = $this->db->fetchObject( $result );
794
795 if ( substr( $info->Type, 0, 3 ) == 'int' ) {
796 $this->output( "...$field is already a full int ($info->Type).\n" );
797 } else {
798 $this->output( "Promoting $field from $info->Type to int... " );
799 $this->db->query( "ALTER TABLE $tablename MODIFY $field int NOT NULL", __METHOD__ );
800 $this->output( "done.\n" );
801 }
802 }
803 }
804
805 protected function doPagelinksUpdate() {
806 if ( $this->db->tableExists( 'pagelinks', __METHOD__ ) ) {
807 $this->output( "...already have pagelinks table.\n" );
808
809 return;
810 }
811
812 $this->applyPatch(
813 'patch-pagelinks.sql',
814 false,
815 'Converting links and brokenlinks tables to pagelinks'
816 );
817
818 foreach (
819 MediaWikiServices::getInstance()->getContentLanguage()->getNamespaces() as $ns => $name
820 ) {
821 if ( $ns == 0 ) {
822 continue;
823 }
824
825 $this->output( "Cleaning up broken links for namespace $ns... " );
826 $this->db->update( 'pagelinks',
827 [
828 'pl_namespace' => $ns,
829 "pl_title = TRIM(LEADING {$this->db->addQuotes( "$name:" )} FROM pl_title)",
830 ],
831 [
832 'pl_namespace' => 0,
833 'pl_title' . $this->db->buildLike( "$name:", $this->db->anyString() ),
834 ],
835 __METHOD__
836 );
837 $this->output( "done.\n" );
838 }
839 }
840
841 protected function doUserUniqueUpdate() {
842 if ( !$this->doTable( 'user' ) ) {
843 return true;
844 }
845
846 $duper = new UserDupes( $this->db, [ $this, 'output' ] );
847 if ( $duper->hasUniqueIndex() ) {
848 $this->output( "...already have unique user_name index.\n" );
849
850 return;
851 }
852
853 if ( !$duper->clearDupes() ) {
854 $this->output( "WARNING: This next step will probably fail due to unfixed duplicates...\n" );
855 }
856 $this->applyPatch( 'patch-user_nameindex.sql', false, "Adding unique index on user_name" );
857 }
858
859 protected function doUserGroupsUpdate() {
860 if ( !$this->doTable( 'user_groups' ) ) {
861 return true;
862 }
863
864 if ( $this->db->tableExists( 'user_groups', __METHOD__ ) ) {
865 $info = $this->db->fieldInfo( 'user_groups', 'ug_group' );
866 if ( $info->type() == 'int' ) {
867 $oldug = $this->db->tableName( 'user_groups' );
868 $newug = $this->db->tableName( 'user_groups_bogus' );
869 $this->output( "user_groups table exists but is in bogus intermediate " .
870 "format. Renaming to $newug... " );
871 $this->db->query( "ALTER TABLE $oldug RENAME TO $newug", __METHOD__ );
872 $this->output( "done.\n" );
873
874 $this->applyPatch( 'patch-user_groups.sql', false, "Re-adding fresh user_groups table" );
875
876 $this->output( "***\n" );
877 $this->output( "*** WARNING: You will need to manually fix up user " .
878 "permissions in the user_groups\n" );
879 $this->output( "*** table. Old 1.5 alpha versions did some pretty funky stuff...\n" );
880 $this->output( "***\n" );
881 } else {
882 $this->output( "...user_groups table exists and is in current format.\n" );
883 }
884
885 return;
886 }
887
888 $this->applyPatch( 'patch-user_groups.sql', false, "Adding user_groups table" );
889
890 if ( !$this->db->tableExists( 'user_rights', __METHOD__ ) ) {
891 if ( $this->db->fieldExists( 'user', 'user_rights', __METHOD__ ) ) {
892 $this->applyPatch(
893 'patch-user_rights.sql',
894 false,
895 'Upgrading from a 1.3 or older database? Breaking out user_rights for conversion'
896 );
897 } else {
898 $this->output( "*** WARNING: couldn't locate user_rights table or field for upgrade.\n" );
899 $this->output( "*** You may need to manually configure some sysops by manipulating\n" );
900 $this->output( "*** the user_groups table.\n" );
901
902 return;
903 }
904 }
905
906 $this->output( "Converting user_rights table to user_groups... " );
907 $result = $this->db->select( 'user_rights',
908 [ 'ur_user', 'ur_rights' ],
909 [ "ur_rights != ''" ],
910 __METHOD__ );
911
912 foreach ( $result as $row ) {
913 $groups = array_unique(
914 array_map( 'trim',
915 explode( ',', $row->ur_rights ) ) );
916
917 foreach ( $groups as $group ) {
918 $this->db->insert( 'user_groups',
919 [
920 'ug_user' => $row->ur_user,
921 'ug_group' => $group ],
922 __METHOD__ );
923 }
924 }
925 $this->output( "done.\n" );
926 }
927
932 protected function doWatchlistNull() {
933 $info = $this->db->fieldInfo( 'watchlist', 'wl_notificationtimestamp' );
934 if ( !$info ) {
935 return;
936 }
937 if ( $info->isNullable() ) {
938 $this->output( "...wl_notificationtimestamp is already nullable.\n" );
939
940 return;
941 }
942
943 $this->applyPatch(
944 'patch-watchlist-null.sql',
945 false,
946 'Making wl_notificationtimestamp nullable'
947 );
948 }
949
955 protected function doPageRandomUpdate() {
956 $page = $this->db->tableName( 'page' );
957 $this->db->query( "UPDATE $page SET page_random = RAND() WHERE page_random = 0", __METHOD__ );
958 $rows = $this->db->affectedRows();
959
960 if ( $rows ) {
961 $this->output( "Set page_random to a random value on $rows rows where it was set to 0\n" );
962 } else {
963 $this->output( "...no page_random rows needed to be set\n" );
964 }
965 }
966
967 protected function doTemplatelinksUpdate() {
968 if ( $this->db->tableExists( 'templatelinks', __METHOD__ ) ) {
969 $this->output( "...templatelinks table already exists\n" );
970
971 return;
972 }
973
974 $this->applyPatch( 'patch-templatelinks.sql', false, "Creating templatelinks table" );
975
976 $this->output( "Populating...\n" );
977 $services = MediaWikiServices::getInstance();
978 if ( $services->getDBLoadBalancer()->getServerCount() > 1 ) {
979 // Slow, replication-friendly update
980 $res = $this->db->select( 'pagelinks', [ 'pl_from', 'pl_namespace', 'pl_title' ],
981 [ 'pl_namespace' => NS_TEMPLATE ], __METHOD__ );
982 $count = 0;
983 foreach ( $res as $row ) {
984 $count = ( $count + 1 ) % 100;
985 if ( $count == 0 ) {
986 $lbFactory = $services->getDBLoadBalancerFactory();
987 $lbFactory->waitForReplication( [
988 'domain' => $lbFactory->getLocalDomainID(),
990 ] );
991 }
992 $this->db->insert( 'templatelinks',
993 [
994 'tl_from' => $row->pl_from,
995 'tl_namespace' => $row->pl_namespace,
996 'tl_title' => $row->pl_title,
997 ], __METHOD__
998 );
999 }
1000 } else {
1001 // Fast update
1002 $this->db->insertSelect( 'templatelinks', 'pagelinks',
1003 [
1004 'tl_from' => 'pl_from',
1005 'tl_namespace' => 'pl_namespace',
1006 'tl_title' => 'pl_title'
1007 ], [
1008 'pl_namespace' => 10
1009 ], __METHOD__,
1010 [ 'NO_AUTO_COLUMNS' ] // There's no "tl_id" auto-increment field
1011 );
1012 }
1013 $this->output( "Done. Please run maintenance/refreshLinks.php for a more " .
1014 "thorough templatelinks update.\n" );
1015 }
1016
1017 protected function doBacklinkingIndicesUpdate() {
1018 if ( !$this->indexHasField( 'pagelinks', 'pl_namespace', 'pl_from' ) ||
1019 !$this->indexHasField( 'templatelinks', 'tl_namespace', 'tl_from' ) ||
1020 !$this->indexHasField( 'imagelinks', 'il_to', 'il_from' )
1021 ) {
1022 $this->applyPatch( 'patch-backlinkindexes.sql', false, "Updating backlinking indices" );
1023 }
1024 }
1025
1031 protected function doRestrictionsUpdate() {
1032 if ( $this->db->tableExists( 'page_restrictions', __METHOD__ ) ) {
1033 $this->output( "...page_restrictions table already exists.\n" );
1034
1035 return;
1036 }
1037
1038 $this->applyPatch(
1039 'patch-page_restrictions.sql',
1040 false,
1041 'Creating page_restrictions table (1/2)'
1042 );
1043 $this->applyPatch(
1044 'patch-page_restrictions_sortkey.sql',
1045 false,
1046 'Creating page_restrictions table (2/2)'
1047 );
1048 $this->output( "done.\n" );
1049
1050 $this->output( "Migrating old restrictions to new table...\n" );
1051 $task = $this->maintenance->runChild( UpdateRestrictions::class );
1052 $task->execute();
1053 }
1054
1055 protected function doCategorylinksIndicesUpdate() {
1056 if ( !$this->indexHasField( 'categorylinks', 'cl_sortkey', 'cl_from' ) ) {
1057 $this->applyPatch( 'patch-categorylinksindex.sql', false, "Updating categorylinks Indices" );
1058 }
1059 }
1060
1061 protected function doCategoryPopulation() {
1062 if ( $this->updateRowExists( 'populate category' ) ) {
1063 $this->output( "...category table already populated.\n" );
1064
1065 return;
1066 }
1067
1068 $this->output(
1069 "Populating category table, printing progress markers. " .
1070 "For large databases, you\n" .
1071 "may want to hit Ctrl-C and do this manually with maintenance/\n" .
1072 "populateCategory.php.\n"
1073 );
1074 $task = $this->maintenance->runChild( PopulateCategory::class );
1075 $task->execute();
1076 $this->output( "Done populating category table.\n" );
1077 }
1078
1079 protected function doPopulateParentId() {
1080 if ( !$this->updateRowExists( 'populate rev_parent_id' ) ) {
1081 $this->output(
1082 "Populating rev_parent_id fields, printing progress markers. For large\n" .
1083 "databases, you may want to hit Ctrl-C and do this manually with\n" .
1084 "maintenance/populateParentId.php.\n" );
1085
1086 $task = $this->maintenance->runChild( PopulateParentId::class );
1087 $task->execute();
1088 }
1089 }
1090
1091 protected function doMaybeProfilingMemoryUpdate() {
1092 if ( !$this->doTable( 'profiling' ) ) {
1093 return true;
1094 }
1095
1096 if ( !$this->db->tableExists( 'profiling', __METHOD__ ) ) {
1097 return true;
1098 } elseif ( $this->db->fieldExists( 'profiling', 'pf_memory', __METHOD__ ) ) {
1099 $this->output( "...profiling table has pf_memory field.\n" );
1100
1101 return true;
1102 }
1103
1104 return $this->applyPatch(
1105 'patch-profiling-memory.sql',
1106 false,
1107 'Adding pf_memory field to table profiling'
1108 );
1109 }
1110
1111 protected function doFilearchiveIndicesUpdate() {
1112 $info = $this->db->indexInfo( 'filearchive', 'fa_user_timestamp', __METHOD__ );
1113 if ( !$info ) {
1114 $this->applyPatch( 'patch-filearchive-user-index.sql', false, "Updating filearchive indices" );
1115 }
1116
1117 return true;
1118 }
1119
1120 protected function doNonUniquePlTlIl() {
1121 $info = $this->db->indexInfo( 'pagelinks', 'pl_namespace' );
1122 if ( is_array( $info ) && $info[0]->Non_unique ) {
1123 $this->output( "...pl_namespace, tl_namespace, il_to indices are already non-UNIQUE.\n" );
1124
1125 return true;
1126 }
1127 if ( $this->skipSchema ) {
1128 $this->output( "...skipping schema change (making pl_namespace, tl_namespace " .
1129 "and il_to indices non-UNIQUE).\n" );
1130
1131 return false;
1132 }
1133
1134 return $this->applyPatch(
1135 'patch-pl-tl-il-nonunique.sql',
1136 false,
1137 'Making pl_namespace, tl_namespace and il_to indices non-UNIQUE'
1138 );
1139 }
1140
1141 protected function doUpdateMimeMinorField() {
1142 if ( $this->updateRowExists( 'mime_minor_length' ) ) {
1143 $this->output( "...*_mime_minor fields are already long enough.\n" );
1144
1145 return;
1146 }
1147
1148 $this->applyPatch(
1149 'patch-mime_minor_length.sql',
1150 false,
1151 'Altering all *_mime_minor fields to 100 bytes in size'
1152 );
1153 }
1154
1155 protected function doClFieldsUpdate() {
1156 if ( $this->updateRowExists( 'cl_fields_update' ) ) {
1157 $this->output( "...categorylinks up-to-date.\n" );
1158
1159 return;
1160 }
1161
1162 $this->applyPatch(
1163 'patch-categorylinks-better-collation2.sql',
1164 false,
1165 'Updating categorylinks (again)'
1166 );
1167 }
1168
1169 protected function doLangLinksLengthUpdate() {
1170 $langlinks = $this->db->tableName( 'langlinks' );
1171 $res = $this->db->query( "SHOW COLUMNS FROM $langlinks LIKE 'll_lang'" );
1172 $row = $this->db->fetchObject( $res );
1173
1174 if ( $row && $row->Type == "varbinary(10)" ) {
1175 $this->applyPatch(
1176 'patch-langlinks-ll_lang-20.sql',
1177 false,
1178 'Updating length of ll_lang in langlinks'
1179 );
1180 } else {
1181 $this->output( "...ll_lang is up-to-date.\n" );
1182 }
1183 }
1184
1185 protected function doUserNewTalkTimestampNotNull() {
1186 if ( !$this->doTable( 'user_newtalk' ) ) {
1187 return true;
1188 }
1189
1190 $info = $this->db->fieldInfo( 'user_newtalk', 'user_last_timestamp' );
1191 if ( $info === false ) {
1192 return;
1193 }
1194 if ( $info->isNullable() ) {
1195 $this->output( "...user_last_timestamp is already nullable.\n" );
1196
1197 return;
1198 }
1199
1200 $this->applyPatch(
1201 'patch-user-newtalk-timestamp-null.sql',
1202 false,
1203 'Making user_last_timestamp nullable'
1204 );
1205 }
1206
1207 protected function doIwlinksIndexNonUnique() {
1208 $info = $this->db->indexInfo( 'iwlinks', 'iwl_prefix_title_from' );
1209 if ( is_array( $info ) && $info[0]->Non_unique ) {
1210 $this->output( "...iwl_prefix_title_from index is already non-UNIQUE.\n" );
1211
1212 return true;
1213 }
1214 if ( $this->skipSchema ) {
1215 $this->output( "...skipping schema change (making iwl_prefix_title_from index non-UNIQUE).\n" );
1216
1217 return false;
1218 }
1219
1220 return $this->applyPatch(
1221 'patch-iwl_prefix_title_from-non-unique.sql',
1222 false,
1223 'Making iwl_prefix_title_from index non-UNIQUE'
1224 );
1225 }
1226
1227 protected function doUnsignedSyncronisation() {
1228 $sync = [
1229 [ 'table' => 'bot_passwords', 'field' => 'bp_user' ],
1230 [ 'table' => 'change_tag', 'field' => 'ct_log_id' ],
1231 [ 'table' => 'change_tag', 'field' => 'ct_rev_id' ],
1232 [ 'table' => 'page_restrictions', 'field' => 'pr_user' ],
1233 [ 'table' => 'user_newtalk', 'field' => 'user_id' ],
1234 [ 'table' => 'user_properties', 'field' => 'up_user' ],
1235 ];
1236
1237 foreach ( $sync as $s ) {
1238 if ( !$this->doTable( $s['table'] ) ) {
1239 continue;
1240 }
1241
1242 $info = $this->db->fieldInfo( $s['table'], $s['field'] );
1243 if ( $info === false ) {
1244 continue;
1245 }
1246 $fullName = "{$s['table']}.{$s['field']}";
1247 if ( $info->isUnsigned() ) {
1248 $this->output( "...$fullName is already unsigned int.\n" );
1249
1250 continue;
1251 }
1252
1253 $this->applyPatch(
1254 "patch-{$s['table']}-{$s['field']}-unsigned.sql",
1255 false,
1256 "Making $fullName into an unsigned int"
1257 );
1258 }
1259
1260 return true;
1261 }
1262
1263 protected function doRevisionPageRevIndexNonUnique() {
1264 if ( !$this->doTable( 'revision' ) ) {
1265 return true;
1266 } elseif ( !$this->db->indexExists( 'revision', 'rev_page_id' ) ) {
1267 $this->output( "...rev_page_id index not found on revision.\n" );
1268 return true;
1269 }
1270
1271 if ( !$this->db->indexUnique( 'revision', 'rev_page_id' ) ) {
1272 $this->output( "...rev_page_id index already non-unique.\n" );
1273 return true;
1274 }
1275
1276 return $this->applyPatch(
1277 'patch-revision-page-rev-index-nonunique.sql',
1278 false,
1279 'Making rev_page_id index non-unique'
1280 );
1281 }
1282
1283 protected function doExtendCommentLengths() {
1284 $table = $this->db->tableName( 'revision' );
1285 $res = $this->db->query( "SHOW COLUMNS FROM $table LIKE 'rev_comment'" );
1286 $row = $this->db->fetchObject( $res );
1287
1288 if ( $row && ( $row->Type !== "varbinary(767)" || $row->Default !== "" ) ) {
1289 $this->applyPatch(
1290 'patch-editsummary-length.sql',
1291 false,
1292 'Extending edit summary lengths (and setting defaults)'
1293 );
1294 } else {
1295 $this->output( "...comment fields are up to date.\n" );
1296 }
1297 }
1298
1299 public function getSchemaVars() {
1300 global $wgDBTableOptions;
1301
1302 $vars = [];
1303 $vars['wgDBTableOptions'] = str_replace( 'TYPE', 'ENGINE', $wgDBTableOptions );
1304 $vars['wgDBTableOptions'] = str_replace(
1305 'CHARSET=mysql4',
1306 'CHARSET=binary',
1307 $vars['wgDBTableOptions']
1308 );
1309
1310 return $vars;
1311 }
1312}
$wgLegacySchemaConversion
If set to true, the MediaWiki 1.4 to 1.5 schema conversion will create stub reference rows in the tex...
$wgDBTableOptions
MySQL table options to use during installation or update.
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
$IP
Definition WebStart.php:41
Class for handling database updates.
updateRowExists( $key)
Helper function: check if the given key is present in the updatelog table.
output( $str)
Output some text.
applyPatch( $path, $isFullPath=false, $msg=null)
Applies a SQL patch.
doTable( $name)
Returns whether updates should be executed on the database table $name.
MediaWiki exception.
MediaWikiServices is the service locator for the application scope of MediaWiki.
doWatchlistNull()
Make sure wl_notificationtimestamp can be NULL, and update old broken items.
doInterwikiUpdate()
Check that interwiki table exists; if it doesn't source it.
getSchemaVars()
Get appropriate schema variables in the current database connection.
doRestrictionsUpdate()
Adding page_restrictions table, obsoleting page.page_restrictions.
checkBin( $table, $field, $patchFile)
1.4 betas were missing the 'binary' marker from logging.log_title, which causes a collation mismatch ...
doIndexUpdate()
Check that proper indexes are in place.
getCoreUpdateList()
Get an array of updates to perform on the database.
doRevisionPageRevIndexNonUnique()
indexHasField( $table, $index, $field)
Check whether an index contain a field.
doPageRandomUpdate()
Set page_random field to a random value where it is equals to 0.
doWatchlistUpdate()
Check if we need to add talk page rows to the watchlist.
doUserNewTalkTimestampNotNull()
Look for duplicate user table entries and optionally prune them.
Definition userDupes.inc:37
const NS_TEMPLATE
Definition Defines.php:79
Basic database interface for live and lazy-loaded relation database handles.
Definition IDatabase.php:38