summaryrefslogtreecommitdiff
path: root/www/wiki/maintenance
diff options
context:
space:
mode:
authorYaco <franco@reevo.org>2019-07-31 14:50:50 -0300
committerYaco <franco@reevo.org>2019-07-31 14:50:50 -0300
commit3848848fc3bc2db035c824f1453635949505d76e (patch)
tree71fd898ebb220e7ba034cf2bc1bf708fdd0d6219 /www/wiki/maintenance
parent2dfe0b926fe5c6c4f27ad1f9bc1c1377cb091111 (diff)
ACTUALIZA MW a 1.31.3, SMW a 3.0.2 y extensiones menores
Diffstat (limited to 'www/wiki/maintenance')
-rw-r--r--www/wiki/maintenance/7zip.inc2
-rw-r--r--www/wiki/maintenance/Maintenance.php168
-rw-r--r--www/wiki/maintenance/addRFCandPMIDInterwiki.php2
-rw-r--r--www/wiki/maintenance/addSite.php2
-rw-r--r--www/wiki/maintenance/archives/patch-actor-table.sql57
-rw-r--r--www/wiki/maintenance/archives/patch-ar_rev_id-not-null.sql3
-rw-r--r--www/wiki/maintenance/archives/patch-content.sql21
-rw-r--r--www/wiki/maintenance/archives/patch-content_models.sql10
-rw-r--r--www/wiki/maintenance/archives/patch-drop-ar_text.sql7
-rw-r--r--www/wiki/maintenance/archives/patch-drop-user_newtalk.sql3
-rw-r--r--www/wiki/maintenance/archives/patch-image-img_description_id.sql7
-rw-r--r--www/wiki/maintenance/archives/patch-log_search-rename-index.sql7
-rw-r--r--www/wiki/maintenance/archives/patch-nullable-ar_text.sql13
-rw-r--r--www/wiki/maintenance/archives/patch-pl-tl-il-unique.sql11
-rw-r--r--www/wiki/maintenance/archives/patch-recentchanges-nttindex.sql11
-rw-r--r--www/wiki/maintenance/archives/patch-rev_text_id-default.sql10
-rw-r--r--www/wiki/maintenance/archives/patch-site_stats-modify.sql7
-rw-r--r--www/wiki/maintenance/archives/patch-slot-origin.sql15
-rw-r--r--www/wiki/maintenance/archives/patch-slot_roles.sql10
-rw-r--r--www/wiki/maintenance/archives/patch-slots.sql25
-rw-r--r--www/wiki/maintenance/archives/patch-user-newtalk-userid-unsigned.sql1
-rw-r--r--www/wiki/maintenance/archives/upgradeLogging.php6
-rw-r--r--www/wiki/maintenance/attachLatest.php2
-rw-r--r--www/wiki/maintenance/backup.inc42
-rw-r--r--www/wiki/maintenance/backupPrefetch.inc219
-rw-r--r--www/wiki/maintenance/benchmarks/Benchmarker.php44
-rw-r--r--www/wiki/maintenance/benchmarks/README10
-rw-r--r--www/wiki/maintenance/benchmarks/README.md15
-rw-r--r--www/wiki/maintenance/benchmarks/bench_HTTP_HTTPS.php2
-rw-r--r--www/wiki/maintenance/benchmarks/bench_Wikimedia_base_convert.php2
-rw-r--r--www/wiki/maintenance/benchmarks/bench_delete_truncate.php2
-rw-r--r--www/wiki/maintenance/benchmarks/bench_if_switch.php2
-rw-r--r--www/wiki/maintenance/benchmarks/bench_strtr_str_replace.php2
-rw-r--r--www/wiki/maintenance/benchmarks/bench_utf8_title_check.php6
-rw-r--r--www/wiki/maintenance/benchmarks/bench_wfIsWindows.php2
-rw-r--r--www/wiki/maintenance/benchmarks/benchmarkCSSMin.php6
-rw-r--r--www/wiki/maintenance/benchmarks/benchmarkHooks.php2
-rw-r--r--www/wiki/maintenance/benchmarks/benchmarkJSMinPlus.php8
-rw-r--r--www/wiki/maintenance/benchmarks/benchmarkLruHash.php20
-rw-r--r--www/wiki/maintenance/benchmarks/benchmarkParse.php4
-rw-r--r--www/wiki/maintenance/benchmarks/benchmarkPurge.php4
-rw-r--r--www/wiki/maintenance/benchmarks/benchmarkSanitizer.php99
-rw-r--r--www/wiki/maintenance/benchmarks/benchmarkTidy.php8
-rw-r--r--www/wiki/maintenance/cdb.php5
-rw-r--r--www/wiki/maintenance/changePassword.php8
-rw-r--r--www/wiki/maintenance/checkBadRedirects.php2
-rw-r--r--www/wiki/maintenance/checkComposerLockUpToDate.php12
-rw-r--r--www/wiki/maintenance/checkImages.php8
-rw-r--r--www/wiki/maintenance/checkLess.php4
-rw-r--r--www/wiki/maintenance/checkSyntax.php349
-rw-r--r--www/wiki/maintenance/checkUsernames.php4
-rw-r--r--www/wiki/maintenance/cleanupAncientTables.php2
-rw-r--r--www/wiki/maintenance/cleanupBlocks.php29
-rw-r--r--www/wiki/maintenance/cleanupCaps.php2
-rw-r--r--www/wiki/maintenance/cleanupEmptyCategories.php6
-rw-r--r--www/wiki/maintenance/cleanupImages.php2
-rw-r--r--www/wiki/maintenance/cleanupInvalidDbKeys.php4
-rw-r--r--www/wiki/maintenance/cleanupPreferences.php129
-rw-r--r--www/wiki/maintenance/cleanupRemovedModules.php4
-rw-r--r--www/wiki/maintenance/cleanupSpam.php18
-rw-r--r--www/wiki/maintenance/cleanupTitles.php14
-rw-r--r--www/wiki/maintenance/cleanupUploadStash.php8
-rw-r--r--www/wiki/maintenance/cleanupUsersWithNoId.php212
-rw-r--r--www/wiki/maintenance/cleanupWatchlist.php2
-rw-r--r--www/wiki/maintenance/clearInterwikiCache.php4
-rw-r--r--www/wiki/maintenance/commandLine.inc17
-rw-r--r--www/wiki/maintenance/compareParserCache.php9
-rw-r--r--www/wiki/maintenance/compareParsers.php4
-rw-r--r--www/wiki/maintenance/convertExtensionToRegistration.php27
-rw-r--r--www/wiki/maintenance/convertLinks.php2
-rw-r--r--www/wiki/maintenance/convertUserOptions.php4
-rw-r--r--www/wiki/maintenance/copyFileBackend.php28
-rw-r--r--www/wiki/maintenance/copyJobQueue.php8
-rw-r--r--www/wiki/maintenance/createAndPromote.php10
-rw-r--r--www/wiki/maintenance/createCommonPasswordCdb.php8
-rw-r--r--www/wiki/maintenance/deleteArchivedFiles.php2
-rw-r--r--www/wiki/maintenance/deleteArchivedRevisions.php2
-rw-r--r--www/wiki/maintenance/deleteAutoPatrolLogs.php198
-rw-r--r--www/wiki/maintenance/deleteBatch.php9
-rw-r--r--www/wiki/maintenance/deleteDefaultMessages.php18
-rw-r--r--www/wiki/maintenance/deleteEqualMessages.php6
-rw-r--r--www/wiki/maintenance/deleteOldRevisions.php2
-rw-r--r--www/wiki/maintenance/deleteOrphanedRevisions.php2
-rw-r--r--www/wiki/maintenance/deleteRevision.php111
-rw-r--r--www/wiki/maintenance/deleteSelfExternals.php7
-rw-r--r--www/wiki/maintenance/dev/README4
-rwxr-xr-xwww/wiki/maintenance/dev/installphp.sh29
-rw-r--r--www/wiki/maintenance/dictionary/mediawiki.dic2
-rw-r--r--www/wiki/maintenance/doMaintenance.php38
-rw-r--r--www/wiki/maintenance/dumpBackup.php4
-rw-r--r--www/wiki/maintenance/dumpCategoriesAsRdf.php40
-rw-r--r--www/wiki/maintenance/dumpIterator.php13
-rw-r--r--www/wiki/maintenance/dumpLinks.php2
-rw-r--r--www/wiki/maintenance/dumpTextPass.php18
-rw-r--r--www/wiki/maintenance/dumpUploads.php2
-rw-r--r--www/wiki/maintenance/edit.php10
-rw-r--r--www/wiki/maintenance/eraseArchivedFile.php18
-rw-r--r--www/wiki/maintenance/exportSites.php6
-rw-r--r--www/wiki/maintenance/fetchText.php2
-rw-r--r--www/wiki/maintenance/fileOpPerfTest.php2
-rw-r--r--www/wiki/maintenance/findDeprecated.php7
-rw-r--r--www/wiki/maintenance/findHooks.php8
-rw-r--r--www/wiki/maintenance/findMissingFiles.php9
-rw-r--r--www/wiki/maintenance/findOrphanedFiles.php8
-rw-r--r--www/wiki/maintenance/fixDefaultJsonContentPages.php6
-rw-r--r--www/wiki/maintenance/fixDoubleRedirects.php4
-rw-r--r--www/wiki/maintenance/fixExtLinksProtocolRelative.php2
-rw-r--r--www/wiki/maintenance/fixTimestamps.php8
-rw-r--r--www/wiki/maintenance/fixUserRegistration.php16
-rw-r--r--www/wiki/maintenance/formatInstallDoc.php8
-rw-r--r--www/wiki/maintenance/generateJsonI18n.php18
-rw-r--r--www/wiki/maintenance/generateLocalAutoload.php4
-rw-r--r--www/wiki/maintenance/generateSitemap.php14
-rw-r--r--www/wiki/maintenance/getConfiguration.php6
-rw-r--r--www/wiki/maintenance/getLagTimes.php2
-rw-r--r--www/wiki/maintenance/getReplicaServer.php2
-rw-r--r--www/wiki/maintenance/getText.php8
-rw-r--r--www/wiki/maintenance/hhvm/makeRepo.php8
-rwxr-xr-xwww/wiki/maintenance/hhvm/run-server2
-rwxr-xr-xwww/wiki/maintenance/hiphop/run-server28
-rw-r--r--www/wiki/maintenance/hiphop/server.conf30
-rw-r--r--www/wiki/maintenance/importDump.php24
-rw-r--r--www/wiki/maintenance/importImages.inc137
-rw-r--r--www/wiki/maintenance/importImages.php16
-rw-r--r--www/wiki/maintenance/importSiteScripts.php2
-rw-r--r--www/wiki/maintenance/importSites.php2
-rw-r--r--www/wiki/maintenance/importTextFiles.php8
-rw-r--r--www/wiki/maintenance/initEditCount.php114
-rw-r--r--www/wiki/maintenance/initSiteStats.php2
-rw-r--r--www/wiki/maintenance/initUserPreference.php4
-rw-r--r--www/wiki/maintenance/install.php16
-rw-r--r--www/wiki/maintenance/interwiki.list40
-rw-r--r--www/wiki/maintenance/interwiki.sql40
-rw-r--r--www/wiki/maintenance/invalidateUserSessions.php10
-rw-r--r--www/wiki/maintenance/jsduck/categories.json10
-rw-r--r--www/wiki/maintenance/jsparse.php6
-rw-r--r--www/wiki/maintenance/lag.php2
-rw-r--r--www/wiki/maintenance/language/StatOutputs.php8
-rw-r--r--www/wiki/maintenance/language/alltrans.php2
-rw-r--r--www/wiki/maintenance/language/checkLanguage.inc7
-rw-r--r--www/wiki/maintenance/language/date-formats.php2
-rw-r--r--www/wiki/maintenance/language/digit2html.php4
-rw-r--r--www/wiki/maintenance/language/dumpMessages.php2
-rw-r--r--www/wiki/maintenance/language/generateCollationData.php19
-rw-r--r--www/wiki/maintenance/language/generateNormalizerDataAr.php11
-rw-r--r--www/wiki/maintenance/language/generateNormalizerDataMl.php2
-rw-r--r--www/wiki/maintenance/language/langmemusage.php4
-rw-r--r--www/wiki/maintenance/language/languages.inc2
-rw-r--r--www/wiki/maintenance/language/listVariants.php2
-rw-r--r--www/wiki/maintenance/language/transstat.php2
-rw-r--r--www/wiki/maintenance/language/zhtable/simp2trad.manual186
-rw-r--r--www/wiki/maintenance/language/zhtable/toCN.manual11
-rw-r--r--www/wiki/maintenance/language/zhtable/toHK.manual16
-rw-r--r--www/wiki/maintenance/language/zhtable/toSimp.manual11
-rw-r--r--www/wiki/maintenance/language/zhtable/toTW.manual7
-rw-r--r--www/wiki/maintenance/language/zhtable/toTrad.manual21
-rw-r--r--www/wiki/maintenance/language/zhtable/trad2simp.manual179
-rw-r--r--www/wiki/maintenance/language/zhtable/tradphrases.manual45
-rw-r--r--www/wiki/maintenance/language/zhtable/tradphrases_exclude.manual3
-rw-r--r--www/wiki/maintenance/makeTestEdits.php6
-rw-r--r--www/wiki/maintenance/manageJobs.php6
-rw-r--r--www/wiki/maintenance/mctest.php6
-rw-r--r--www/wiki/maintenance/mergeMessageFileList.php51
-rw-r--r--www/wiki/maintenance/migrateActors.php550
-rw-r--r--www/wiki/maintenance/migrateArchiveText.php159
-rw-r--r--www/wiki/maintenance/migrateComments.php9
-rw-r--r--www/wiki/maintenance/migrateFileRepoLayout.php15
-rw-r--r--www/wiki/maintenance/migrateUserGroup.php20
-rw-r--r--www/wiki/maintenance/minify.php19
-rw-r--r--www/wiki/maintenance/moveBatch.php10
-rw-r--r--www/wiki/maintenance/mssql/archives/patch-actor-table.sql53
-rw-r--r--www/wiki/maintenance/mssql/archives/patch-ar_rev_id-not-null.sql1
-rw-r--r--www/wiki/maintenance/mssql/archives/patch-comment-table.sql57
-rw-r--r--www/wiki/maintenance/mssql/archives/patch-content.sql21
-rw-r--r--www/wiki/maintenance/mssql/archives/patch-content_models.sql11
-rw-r--r--www/wiki/maintenance/mssql/archives/patch-drop-ar_text.sql21
-rw-r--r--www/wiki/maintenance/mssql/archives/patch-image-img_description_id.sql6
-rw-r--r--www/wiki/maintenance/mssql/archives/patch-rc_patrolled_type.sql22
-rw-r--r--www/wiki/maintenance/mssql/archives/patch-rev_text_id-default.sql10
-rw-r--r--www/wiki/maintenance/mssql/archives/patch-site_stats-modify.sql32
-rw-r--r--www/wiki/maintenance/mssql/archives/patch-slot-origin.sql14
-rw-r--r--www/wiki/maintenance/mssql/archives/patch-slot_roles.sql10
-rw-r--r--www/wiki/maintenance/mssql/archives/patch-slots.sql25
-rw-r--r--www/wiki/maintenance/mssql/archives/patch-user_groups-ug_expiry.sql4
-rw-r--r--www/wiki/maintenance/mssql/tables.sql250
-rw-r--r--www/wiki/maintenance/mwdoc-filter.php2
-rw-r--r--www/wiki/maintenance/mwdocgen.php8
-rw-r--r--www/wiki/maintenance/namespaceDupes.php2
-rw-r--r--www/wiki/maintenance/nukeNS.php4
-rw-r--r--www/wiki/maintenance/nukePage.php2
-rw-r--r--www/wiki/maintenance/oracle/alterSharedConstraints.php2
-rw-r--r--www/wiki/maintenance/oracle/archives/patch-actor-table.sql64
-rw-r--r--www/wiki/maintenance/oracle/archives/patch-ar_rev_id-not-null.sql5
-rw-r--r--www/wiki/maintenance/oracle/archives/patch-auto_increment_triggers.sql30
-rw-r--r--www/wiki/maintenance/oracle/archives/patch-comment-table.sql68
-rw-r--r--www/wiki/maintenance/oracle/archives/patch-content.sql18
-rw-r--r--www/wiki/maintenance/oracle/archives/patch-content_models.sql18
-rw-r--r--www/wiki/maintenance/oracle/archives/patch-drop-ar_text.sql7
-rw-r--r--www/wiki/maintenance/oracle/archives/patch-externallinks-el_index_60.sql2
-rw-r--r--www/wiki/maintenance/oracle/archives/patch-image-img_description_id.sql7
-rw-r--r--www/wiki/maintenance/oracle/archives/patch-recentchanges-nttindex.sql4
-rw-r--r--www/wiki/maintenance/oracle/archives/patch-site_stats-modify.sql7
-rw-r--r--www/wiki/maintenance/oracle/archives/patch-slot-origin.sql14
-rw-r--r--www/wiki/maintenance/oracle/archives/patch-slot_roles.sql17
-rw-r--r--www/wiki/maintenance/oracle/archives/patch-slots.sql10
-rw-r--r--www/wiki/maintenance/oracle/tables.sql237
-rw-r--r--www/wiki/maintenance/oracle/user.sql2
-rw-r--r--www/wiki/maintenance/orphans.php18
-rw-r--r--www/wiki/maintenance/pageExists.php4
-rw-r--r--www/wiki/maintenance/parse.php2
-rw-r--r--www/wiki/maintenance/patchSql.php2
-rw-r--r--www/wiki/maintenance/populateArchiveRevId.php177
-rw-r--r--www/wiki/maintenance/populateBacklinkNamespace.php17
-rw-r--r--www/wiki/maintenance/populateCategory.php2
-rw-r--r--www/wiki/maintenance/populateContentModel.php22
-rw-r--r--www/wiki/maintenance/populateFilearchiveSha1.php6
-rw-r--r--www/wiki/maintenance/populateImageSha1.php8
-rw-r--r--www/wiki/maintenance/populateIpChanges.php22
-rw-r--r--www/wiki/maintenance/populateLogSearch.php111
-rw-r--r--www/wiki/maintenance/populateLogUsertext.php27
-rw-r--r--www/wiki/maintenance/populatePPSortKey.php6
-rw-r--r--www/wiki/maintenance/populateParentId.php13
-rw-r--r--www/wiki/maintenance/populateRecentChangesSource.php19
-rw-r--r--www/wiki/maintenance/populateRevisionLength.php46
-rw-r--r--www/wiki/maintenance/populateRevisionSha1.php41
-rw-r--r--www/wiki/maintenance/postgres/archives/patch-actor-table.sql24
-rw-r--r--www/wiki/maintenance/postgres/archives/patch-ar_rev_id-not-null.sql3
-rw-r--r--www/wiki/maintenance/postgres/archives/patch-content-table.sql8
-rw-r--r--www/wiki/maintenance/postgres/archives/patch-content_models-table.sql7
-rw-r--r--www/wiki/maintenance/postgres/archives/patch-drop-ar_text.sql8
-rw-r--r--www/wiki/maintenance/postgres/archives/patch-site_stats-modify.sql7
-rw-r--r--www/wiki/maintenance/postgres/archives/patch-slot_roles-table.sql7
-rw-r--r--www/wiki/maintenance/postgres/archives/patch-slots-table.sql9
-rw-r--r--www/wiki/maintenance/postgres/archives/patch-ts2pagetitle.sql4
-rw-r--r--www/wiki/maintenance/postgres/tables.sql154
-rw-r--r--www/wiki/maintenance/preprocessDump.php4
-rw-r--r--www/wiki/maintenance/protect.php6
-rw-r--r--www/wiki/maintenance/pruneFileCache.php10
-rw-r--r--www/wiki/maintenance/purgeChangedFiles.php4
-rw-r--r--www/wiki/maintenance/purgeChangedPages.php4
-rw-r--r--www/wiki/maintenance/purgeExpiredUserrights.php49
-rw-r--r--www/wiki/maintenance/purgeList.php4
-rw-r--r--www/wiki/maintenance/purgeModuleDeps.php4
-rw-r--r--www/wiki/maintenance/purgeOldText.php2
-rw-r--r--www/wiki/maintenance/purgePage.php2
-rw-r--r--www/wiki/maintenance/purgeParserCache.php6
-rw-r--r--www/wiki/maintenance/reassignEdits.php103
-rw-r--r--www/wiki/maintenance/rebuildFileCache.php47
-rw-r--r--www/wiki/maintenance/rebuildImages.php13
-rw-r--r--www/wiki/maintenance/rebuildLocalisationCache.php4
-rw-r--r--www/wiki/maintenance/rebuildSitesCache.php4
-rw-r--r--www/wiki/maintenance/rebuildall.php8
-rw-r--r--www/wiki/maintenance/rebuildmessages.php2
-rw-r--r--www/wiki/maintenance/rebuildrecentchanges.php177
-rw-r--r--www/wiki/maintenance/rebuildtextindex.php33
-rw-r--r--www/wiki/maintenance/recountCategories.php12
-rw-r--r--www/wiki/maintenance/refreshFileHeaders.php48
-rw-r--r--www/wiki/maintenance/refreshImageMetadata.php22
-rw-r--r--www/wiki/maintenance/refreshLinks.php18
-rw-r--r--www/wiki/maintenance/removeInvalidEmails.php4
-rw-r--r--www/wiki/maintenance/removeUnusedAccounts.php98
-rw-r--r--www/wiki/maintenance/renameDbPrefix.php4
-rw-r--r--www/wiki/maintenance/renderDump.php5
-rw-r--r--www/wiki/maintenance/resetUserEmail.php6
-rw-r--r--www/wiki/maintenance/resetUserTokens.php9
-rwxr-xr-xwww/wiki/maintenance/resources/update-oojs.sh2
-rwxr-xr-xwww/wiki/maintenance/resources/update-ooui.sh (renamed from www/wiki/maintenance/resources/update-oojs-ui.sh)53
-rw-r--r--www/wiki/maintenance/rollbackEdits.php28
-rw-r--r--www/wiki/maintenance/runBatchedQuery.php2
-rw-r--r--www/wiki/maintenance/runJobs.php9
-rw-r--r--www/wiki/maintenance/shell.php4
-rw-r--r--www/wiki/maintenance/showJobs.php2
-rw-r--r--www/wiki/maintenance/showSiteStats.php2
-rw-r--r--www/wiki/maintenance/sql.php33
-rw-r--r--www/wiki/maintenance/sqlite.php8
-rw-r--r--www/wiki/maintenance/sqlite/archives/initial-indexes.sql2
-rw-r--r--www/wiki/maintenance/sqlite/archives/patch-actor-table.sql368
-rw-r--r--www/wiki/maintenance/sqlite/archives/patch-ar_rev_id-not-null.sql47
-rw-r--r--www/wiki/maintenance/sqlite/archives/patch-drop-ar_text.sql44
-rw-r--r--www/wiki/maintenance/sqlite/archives/patch-image-img_description_id.sql47
-rw-r--r--www/wiki/maintenance/sqlite/archives/patch-imagelinks-fix-pk.sql4
-rw-r--r--www/wiki/maintenance/sqlite/archives/patch-log_search-rename-index.sql1
-rw-r--r--www/wiki/maintenance/sqlite/archives/patch-pagelinks-fix-pk.sql4
-rw-r--r--www/wiki/maintenance/sqlite/archives/patch-recentchanges-nttindex.sql10
-rw-r--r--www/wiki/maintenance/sqlite/archives/patch-rev_text_id-default.sql53
-rw-r--r--www/wiki/maintenance/sqlite/archives/patch-site_stats-modify.sql35
-rw-r--r--www/wiki/maintenance/sqlite/archives/patch-slot-origin.sql34
-rw-r--r--www/wiki/maintenance/sqlite/archives/patch-templatelinks-fix-pk.sql4
-rw-r--r--www/wiki/maintenance/storage/checkStorage.php79
-rw-r--r--www/wiki/maintenance/storage/compressOld.php10
-rw-r--r--www/wiki/maintenance/storage/dumpRev.php4
-rw-r--r--www/wiki/maintenance/storage/fixBug20757.php351
-rw-r--r--www/wiki/maintenance/storage/fixT22757.php18
-rw-r--r--www/wiki/maintenance/storage/moveToExternal.php2
-rw-r--r--www/wiki/maintenance/storage/orphanStats.php11
-rw-r--r--www/wiki/maintenance/storage/recompressTracked.php11
-rw-r--r--www/wiki/maintenance/storage/resolveStubs.php2
-rw-r--r--www/wiki/maintenance/storage/storageTypeStats.php4
-rw-r--r--www/wiki/maintenance/storage/testCompression.php14
-rw-r--r--www/wiki/maintenance/storage/trackBlobs.php29
-rw-r--r--www/wiki/maintenance/syncFileBackend.php10
-rw-r--r--www/wiki/maintenance/tables.sql298
-rw-r--r--www/wiki/maintenance/term/MWTerm.php12
-rw-r--r--www/wiki/maintenance/tidyUpBug37714.php2
-rw-r--r--www/wiki/maintenance/undelete.php6
-rwxr-xr-xwww/wiki/maintenance/update.php39
-rw-r--r--www/wiki/maintenance/updateArticleCount.php2
-rw-r--r--www/wiki/maintenance/updateCollation.php24
-rw-r--r--www/wiki/maintenance/updateDoubleWidthSearch.php4
-rw-r--r--www/wiki/maintenance/updateExtensionJsonSchema.php6
-rw-r--r--www/wiki/maintenance/updateRestrictions.php22
-rw-r--r--www/wiki/maintenance/updateSearchIndex.php2
-rw-r--r--www/wiki/maintenance/updateSpecialPages.php36
-rw-r--r--www/wiki/maintenance/userOptions.inc292
-rw-r--r--www/wiki/maintenance/userOptions.php180
-rw-r--r--www/wiki/maintenance/validateRegistrationFile.php6
-rw-r--r--www/wiki/maintenance/view.php8
-rw-r--r--www/wiki/maintenance/wrapOldPasswords.php8
318 files changed, 6163 insertions, 3097 deletions
diff --git a/www/wiki/maintenance/7zip.inc b/www/wiki/maintenance/7zip.inc
index 751a1311..9c1093be 100644
--- a/www/wiki/maintenance/7zip.inc
+++ b/www/wiki/maintenance/7zip.inc
@@ -93,4 +93,4 @@ class SevenZipStream {
}
}
-stream_wrapper_register( 'mediawiki.compress.7z', 'SevenZipStream' );
+stream_wrapper_register( 'mediawiki.compress.7z', SevenZipStream::class );
diff --git a/www/wiki/maintenance/Maintenance.php b/www/wiki/maintenance/Maintenance.php
index ecbbb851..13fee9c6 100644
--- a/www/wiki/maintenance/Maintenance.php
+++ b/www/wiki/maintenance/Maintenance.php
@@ -25,6 +25,7 @@
require_once __DIR__ . '/../includes/PHPVersionCheck.php';
wfEntryPointCheck( 'cli' );
+use MediaWiki\Shell\Shell;
use Wikimedia\Rdbms\DBReplicationWaitError;
/**
@@ -34,6 +35,10 @@ use Wikimedia\Rdbms\DBReplicationWaitError;
// Define this so scripts can easily find doMaintenance.php
define( 'RUN_MAINTENANCE_IF_MAIN', __DIR__ . '/doMaintenance.php' );
+
+/**
+ * @deprecated since 1.31
+ */
define( 'DO_MAINTENANCE', RUN_MAINTENANCE_IF_MAIN ); // original name, harmless
$maintClass = false;
@@ -50,7 +55,6 @@ use Wikimedia\Rdbms\IMaintainableDatabase;
* is the execute() method. See docs/maintenance.txt for more info
* and a quick demo of how to use it.
*
- * @author Chad Horohoe <chad@anyonecanedit.org>
* @since 1.16
* @ingroup Maintenance
*/
@@ -183,7 +187,7 @@ abstract class Maintenance {
if ( $count < 2 ) {
return false; // sanity
}
- if ( $bt[0]['class'] !== 'Maintenance' || $bt[0]['function'] !== 'shouldExecute' ) {
+ if ( $bt[0]['class'] !== self::class || $bt[0]['function'] !== 'shouldExecute' ) {
return false; // last call should be to this function
}
$includeFuncs = [ 'require_once', 'require', 'include', 'include_once' ];
@@ -308,6 +312,17 @@ abstract class Maintenance {
}
/**
+ * Returns batch size
+ *
+ * @since 1.31
+ *
+ * @return int|null
+ */
+ protected function getBatchSize() {
+ return $this->mBatchSize;
+ }
+
+ /**
* Set the batch size.
* @param int $s The number of operations to do in a batch
*/
@@ -371,6 +386,15 @@ abstract class Maintenance {
* @param mixed $channel Unique identifier for the channel. See function outputChanneled.
*/
protected function output( $out, $channel = null ) {
+ // This is sometimes called very early, before Setup.php is included.
+ if ( class_exists( MediaWikiServices::class ) ) {
+ // Try to periodically flush buffered metrics to avoid OOMs
+ $stats = MediaWikiServices::getInstance()->getStatsdDataFactory();
+ if ( $stats->getDataCount() > 1000 ) {
+ MediaWiki::emitBufferedStatsdData( $stats, $this->getConfig() );
+ }
+ }
+
if ( $this->mQuiet ) {
return;
}
@@ -387,19 +411,34 @@ abstract class Maintenance {
* Throw an error to the user. Doesn't respect --quiet, so don't use
* this for non-error output
* @param string $err The error to display
- * @param int $die If > 0, go ahead and die out using this int as the code
+ * @param int $die Deprecated since 1.31, use Maintenance::fatalError() instead
*/
protected function error( $err, $die = 0 ) {
+ if ( intval( $die ) !== 0 ) {
+ wfDeprecated( __METHOD__ . '( $err, $die )', '1.31' );
+ $this->fatalError( $err, intval( $die ) );
+ }
$this->outputChanneled( false );
- if ( PHP_SAPI == 'cli' ) {
+ if (
+ ( PHP_SAPI == 'cli' || PHP_SAPI == 'phpdbg' ) &&
+ !defined( 'MW_PHPUNIT_TEST' )
+ ) {
fwrite( STDERR, $err . "\n" );
} else {
print $err;
}
- $die = intval( $die );
- if ( $die > 0 ) {
- die( $die );
- }
+ }
+
+ /**
+ * Output a message and terminate the current script.
+ *
+ * @param string $msg Error message
+ * @param int $exitCode PHP exit status. Should be in range 1-254.
+ * @since 1.31
+ */
+ protected function fatalError( $msg, $exitCode = 1 ) {
+ $this->error( $msg );
+ exit( $exitCode );
}
private $atLineStart = true;
@@ -474,12 +513,16 @@ abstract class Maintenance {
$this->addOption(
'memory-limit',
'Set a specific memory limit for the script, '
- . '"max" for no limit or "default" to avoid changing it'
+ . '"max" for no limit or "default" to avoid changing it',
+ false,
+ true
);
$this->addOption( 'server', "The protocol and server name to use in URLs, e.g. " .
"http://en.wikipedia.org. This is sometimes necessary because " .
"server name detection may fail in command line scripts.", false, true );
$this->addOption( 'profiler', 'Profiler output format (usually "text")', false, true );
+ // This is named --mwdebug, because --debug would conflict in the phpunit.php CLI script.
+ $this->addOption( 'mwdebug', 'Enable built-in MediaWiki development settings', false, true );
# Save generic options to display them separately in help
$this->mGenericParameters = $this->mParams;
@@ -548,7 +591,7 @@ abstract class Maintenance {
$joined = implode( ', ', $missing );
$msg = "The following extensions are required to be installed "
. "for this script to run: $joined. Please enable them and then try again.";
- $this->error( $msg, 1 );
+ $this->fatalError( $msg );
}
}
@@ -569,36 +612,41 @@ abstract class Maintenance {
$lbFactory->setAgentName(
mb_strlen( $agent ) > 15 ? mb_substr( $agent, 0, 15 ) . '...' : $agent
);
- self::setLBFactoryTriggers( $lbFactory );
+ self::setLBFactoryTriggers( $lbFactory, $this->getConfig() );
}
/**
* @param LBFactory $LBFactory
+ * @param Config $config
* @since 1.28
*/
- public static function setLBFactoryTriggers( LBFactory $LBFactory ) {
+ public static function setLBFactoryTriggers( LBFactory $LBFactory, Config $config ) {
+ $services = MediaWikiServices::getInstance();
+ $stats = $services->getStatsdDataFactory();
// Hook into period lag checks which often happen in long-running scripts
- $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
+ $lbFactory = $services->getDBLoadBalancerFactory();
$lbFactory->setWaitForReplicationListener(
__METHOD__,
- function () {
- global $wgCommandLineMode;
+ function () use ( $stats, $config ) {
// Check config in case of JobRunner and unit tests
- if ( $wgCommandLineMode ) {
+ if ( $config->get( 'CommandLineMode' ) ) {
DeferredUpdates::tryOpportunisticExecute( 'run' );
}
+ // Try to periodically flush buffered metrics to avoid OOMs
+ MediaWiki::emitBufferedStatsdData( $stats, $config );
}
);
// Check for other windows to run them. A script may read or do a few writes
// to the master but mostly be writing to something else, like a file store.
$lbFactory->getMainLB()->setTransactionListener(
__METHOD__,
- function ( $trigger ) {
- global $wgCommandLineMode;
+ function ( $trigger ) use ( $stats, $config ) {
// Check config in case of JobRunner and unit tests
- if ( $wgCommandLineMode && $trigger === IDatabase::TRIGGER_COMMIT ) {
+ if ( $config->get( 'CommandLineMode' ) && $trigger === IDatabase::TRIGGER_COMMIT ) {
DeferredUpdates::tryOpportunisticExecute( 'run' );
}
+ // Try to periodically flush buffered metrics to avoid OOMs
+ MediaWiki::emitBufferedStatsdData( $stats, $config );
}
);
}
@@ -637,21 +685,22 @@ abstract class Maintenance {
* Do some sanity checking and basic setup
*/
public function setup() {
- global $IP, $wgCommandLineMode, $wgRequestTime;
+ global $IP, $wgCommandLineMode;
# Abort if called from a web server
- if ( isset( $_SERVER ) && isset( $_SERVER['REQUEST_METHOD'] ) ) {
- $this->error( 'This script must be run from the command line', true );
+ # wfIsCLI() is not available yet
+ if ( PHP_SAPI !== 'cli' && PHP_SAPI !== 'phpdbg' ) {
+ $this->fatalError( 'This script must be run from the command line' );
}
if ( $IP === null ) {
- $this->error( "\$IP not set, aborting!\n" .
- '(Did you forget to call parent::__construct() in your maintenance script?)', 1 );
+ $this->fatalError( "\$IP not set, aborting!\n" .
+ '(Did you forget to call parent::__construct() in your maintenance script?)' );
}
# Make sure we can handle script parameters
if ( !defined( 'HPHP_VERSION' ) && !ini_get( 'register_argc_argv' ) ) {
- $this->error( 'Cannot get command line arguments, register_argc_argv is set to false', true );
+ $this->fatalError( 'Cannot get command line arguments, register_argc_argv is set to false' );
}
// Send PHP warnings and errors to stderr instead of stdout.
@@ -673,8 +722,6 @@ abstract class Maintenance {
# But sometimes this doesn't seem to be the case.
ini_set( 'max_execution_time', 0 );
- $wgRequestTime = microtime( true );
-
# Define us as being in MediaWiki
define( 'MEDIAWIKI', true );
@@ -969,7 +1016,7 @@ abstract class Maintenance {
// ... append parameters ...
if ( $this->mParams ) {
- $output .= " [--" . implode( array_keys( $this->mParams ), "|--" ) . "]";
+ $output .= " [--" . implode( "|--", array_keys( $this->mParams ) ) . "]";
}
// ... and append arguments.
@@ -1109,6 +1156,11 @@ abstract class Maintenance {
MediaWikiServices::getInstance()->getDBLoadBalancerFactory()->destroy();
}
+ # Apply debug settings
+ if ( $this->hasOption( 'mwdebug' ) ) {
+ require __DIR__ . '/../includes/DevelopmentSettings.php';
+ }
+
// Per-script profiling; useful for debugging
$this->activateProfiler();
@@ -1116,9 +1168,9 @@ abstract class Maintenance {
$wgShowSQLErrors = true;
- MediaWiki\suppressWarnings();
+ Wikimedia\suppressWarnings();
set_time_limit( 0 );
- MediaWiki\restoreWarnings();
+ Wikimedia\restoreWarnings();
$this->adjustMemoryLimit();
}
@@ -1163,12 +1215,18 @@ abstract class Maintenance {
}
define( 'MW_DB', $bits[0] );
define( 'MW_PREFIX', $bits[1] );
+ } elseif ( isset( $this->mOptions['server'] ) ) {
+ // Provide the option for site admins to detect and configure
+ // multiple wikis based on server names. This offers --server
+ // as alternative to --wiki.
+ // See https://www.mediawiki.org/wiki/Manual:Wiki_family
+ $_SERVER['SERVER_NAME'] = $this->mOptions['server'];
}
if ( !is_readable( $settingsFile ) ) {
- $this->error( "A copy of your installation's LocalSettings.php\n" .
+ $this->fatalError( "A copy of your installation's LocalSettings.php\n" .
"must exist and be readable in the source directory.\n" .
- "Use --conf to specify it.", true );
+ "Use --conf to specify it." );
}
$wgCommandLineMode = true;
@@ -1244,7 +1302,7 @@ abstract class Maintenance {
* This function has the same parameters as wfGetDB()
*
* @param int $db DB index (DB_REPLICA/DB_MASTER)
- * @param array $groups default: empty array
+ * @param string|string[] $groups default: empty array
* @param string|bool $wiki default: current wiki
* @return IMaintainableDatabase
*/
@@ -1417,6 +1475,32 @@ abstract class Maintenance {
}
/**
+ * Count down from $seconds to zero on the terminal, with a one-second pause
+ * between showing each number. If the maintenance script is in quiet mode,
+ * this function does nothing.
+ *
+ * @since 1.31
+ *
+ * @codeCoverageIgnore
+ * @param int $seconds
+ */
+ protected function countDown( $seconds ) {
+ if ( $this->isQuiet() ) {
+ return;
+ }
+ for ( $i = $seconds; $i >= 0; $i-- ) {
+ if ( $i != $seconds ) {
+ $this->output( str_repeat( "\x08", strlen( $i + 1 ) ) );
+ }
+ $this->output( $i );
+ if ( $i ) {
+ sleep( 1 );
+ }
+ }
+ $this->output( "\n" );
+ }
+
+ /**
* Wrapper for posix_isatty()
* We default as considering stdin a tty (for nice readline methods)
* but treating stout as not a tty to avoid color codes
@@ -1444,13 +1528,7 @@ abstract class Maintenance {
}
if ( $isatty && function_exists( 'readline' ) ) {
- $resp = readline( $prompt );
- if ( $resp === null ) {
- // Workaround for https://github.com/facebook/hhvm/issues/4776
- return false;
- } else {
- return $resp;
- }
+ return readline( $prompt );
} else {
if ( $isatty ) {
$st = self::readlineEmulation( $prompt );
@@ -1476,7 +1554,7 @@ abstract class Maintenance {
* @return string
*/
private static function readlineEmulation( $prompt ) {
- $bash = Installer::locateExecutableInDefaultPaths( [ 'bash' ] );
+ $bash = ExecutableFinder::findInDefaultPaths( 'bash' );
if ( !wfIsWindows() && $bash ) {
$retval = false;
$encPrompt = wfEscapeShellArg( $prompt );
@@ -1524,12 +1602,12 @@ abstract class Maintenance {
// something that can do the relevant syscalls. There are a few
// options. Linux and Mac OS X both have "stty size" which does the
// job directly.
- $retval = false;
- $size = wfShellExec( 'stty size', $retval );
- if ( $retval !== 0 ) {
+ $result = Shell::command( 'stty', 'size' )
+ ->execute();
+ if ( $result->getExitCode() !== 0 ) {
return $default;
}
- if ( !preg_match( '/^(\d+) (\d+)$/', $size, $m ) ) {
+ if ( !preg_match( '/^(\d+) (\d+)$/', $result->getStdout(), $m ) ) {
return $default;
}
return [ intval( $m[2] ), intval( $m[1] ) ];
diff --git a/www/wiki/maintenance/addRFCandPMIDInterwiki.php b/www/wiki/maintenance/addRFCandPMIDInterwiki.php
index b21bfbb7..409afb5f 100644
--- a/www/wiki/maintenance/addRFCandPMIDInterwiki.php
+++ b/www/wiki/maintenance/addRFCandPMIDInterwiki.php
@@ -91,5 +91,5 @@ class AddRFCAndPMIDInterwiki extends LoggedUpdateMaintenance {
}
}
-$maintClass = 'AddRFCAndPMIDInterwiki';
+$maintClass = AddRFCAndPMIDInterwiki::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/addSite.php b/www/wiki/maintenance/addSite.php
index 04158aee..4953343f 100644
--- a/www/wiki/maintenance/addSite.php
+++ b/www/wiki/maintenance/addSite.php
@@ -88,5 +88,5 @@ class AddSite extends Maintenance {
}
}
-$maintClass = 'AddSite';
+$maintClass = AddSite::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/archives/patch-actor-table.sql b/www/wiki/maintenance/archives/patch-actor-table.sql
new file mode 100644
index 00000000..fdd95e80
--- /dev/null
+++ b/www/wiki/maintenance/archives/patch-actor-table.sql
@@ -0,0 +1,57 @@
+--
+-- patch-actor-table.sql
+--
+-- T167246. Add an `actor` table and various columns (and temporary tables) to reference it.
+
+CREATE TABLE /*_*/actor (
+ actor_id bigint unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT,
+ actor_user int unsigned,
+ actor_name varchar(255) binary NOT NULL
+) /*$wgDBTableOptions*/;
+CREATE UNIQUE INDEX /*i*/actor_user ON /*_*/actor (actor_user);
+CREATE UNIQUE INDEX /*i*/actor_name ON /*_*/actor (actor_name);
+
+CREATE TABLE /*_*/revision_actor_temp (
+ revactor_rev int unsigned NOT NULL,
+ revactor_actor bigint unsigned NOT NULL,
+ revactor_timestamp binary(14) NOT NULL default '',
+ revactor_page int unsigned NOT NULL,
+ PRIMARY KEY (revactor_rev, revactor_actor)
+) /*$wgDBTableOptions*/;
+CREATE UNIQUE INDEX /*i*/revactor_rev ON /*_*/revision_actor_temp (revactor_rev);
+CREATE INDEX /*i*/actor_timestamp ON /*_*/revision_actor_temp (revactor_actor,revactor_timestamp);
+CREATE INDEX /*i*/page_actor_timestamp ON /*_*/revision_actor_temp (revactor_page,revactor_actor,revactor_timestamp);
+
+ALTER TABLE /*_*/archive
+ ALTER COLUMN ar_user_text SET DEFAULT '',
+ ADD COLUMN ar_actor bigint unsigned NOT NULL DEFAULT 0 AFTER ar_user_text;
+CREATE INDEX /*i*/ar_actor_timestamp ON /*_*/archive (ar_actor,ar_timestamp);
+
+ALTER TABLE /*_*/ipblocks
+ ADD COLUMN ipb_by_actor bigint unsigned NOT NULL DEFAULT 0 AFTER ipb_by_text;
+
+ALTER TABLE /*_*/image
+ ALTER COLUMN img_user_text SET DEFAULT '',
+ ADD COLUMN img_actor bigint unsigned NOT NULL DEFAULT 0 AFTER img_user_text;
+CREATE INDEX /*i*/img_actor_timestamp ON /*_*/image (img_actor, img_timestamp);
+
+ALTER TABLE /*_*/oldimage
+ ALTER COLUMN oi_user_text SET DEFAULT '',
+ ADD COLUMN oi_actor bigint unsigned NOT NULL DEFAULT 0 AFTER oi_user_text;
+CREATE INDEX /*i*/oi_actor_timestamp ON /*_*/oldimage (oi_actor,oi_timestamp);
+
+ALTER TABLE /*_*/filearchive
+ ALTER COLUMN fa_user_text SET DEFAULT '',
+ ADD COLUMN fa_actor bigint unsigned NOT NULL DEFAULT 0 AFTER fa_user_text;
+CREATE INDEX /*i*/fa_actor_timestamp ON /*_*/filearchive (fa_actor,fa_timestamp);
+
+ALTER TABLE /*_*/recentchanges
+ ALTER COLUMN rc_user_text SET DEFAULT '',
+ ADD COLUMN rc_actor bigint unsigned NOT NULL DEFAULT 0 AFTER rc_user_text;
+CREATE INDEX /*i*/rc_ns_actor ON /*_*/recentchanges (rc_namespace, rc_actor);
+CREATE INDEX /*i*/rc_actor ON /*_*/recentchanges (rc_actor, rc_timestamp);
+
+ALTER TABLE /*_*/logging
+ ADD COLUMN log_actor bigint unsigned NOT NULL DEFAULT 0 AFTER log_user_text;
+CREATE INDEX /*i*/actor_time ON /*_*/logging (log_actor, log_timestamp);
+CREATE INDEX /*i*/log_actor_type_time ON /*_*/logging (log_actor, log_type, log_timestamp);
diff --git a/www/wiki/maintenance/archives/patch-ar_rev_id-not-null.sql b/www/wiki/maintenance/archives/patch-ar_rev_id-not-null.sql
new file mode 100644
index 00000000..8418f20d
--- /dev/null
+++ b/www/wiki/maintenance/archives/patch-ar_rev_id-not-null.sql
@@ -0,0 +1,3 @@
+-- T182678: Make ar_rev_id not nullable
+ALTER TABLE /*_*/archive
+ CHANGE COLUMN ar_rev_id ar_rev_id int unsigned NOT NULL;
diff --git a/www/wiki/maintenance/archives/patch-content.sql b/www/wiki/maintenance/archives/patch-content.sql
new file mode 100644
index 00000000..2cc4de8c
--- /dev/null
+++ b/www/wiki/maintenance/archives/patch-content.sql
@@ -0,0 +1,21 @@
+--
+-- The content table represents content objects. It's primary purpose is to provide the necessary
+-- meta-data for loading and interpreting a serialized data blob to create a content object.
+--
+CREATE TABLE /*_*/content (
+
+ -- ID of the content object
+ content_id bigint unsigned PRIMARY KEY AUTO_INCREMENT,
+
+ -- Nominal size of the content object (not necessarily of the serialized blob)
+ content_size int unsigned NOT NULL,
+
+ -- Nominal hash of the content object (not necessarily of the serialized blob)
+ content_sha1 varbinary(32) NOT NULL,
+
+ -- reference to model_id
+ content_model smallint unsigned NOT NULL,
+
+ -- URL-like address of the content blob
+ content_address varbinary(255) NOT NULL
+) /*$wgDBTableOptions*/; \ No newline at end of file
diff --git a/www/wiki/maintenance/archives/patch-content_models.sql b/www/wiki/maintenance/archives/patch-content_models.sql
new file mode 100644
index 00000000..12c4c5bb
--- /dev/null
+++ b/www/wiki/maintenance/archives/patch-content_models.sql
@@ -0,0 +1,10 @@
+--
+-- Normalization table for content model names
+--
+CREATE TABLE /*_*/content_models (
+ model_id smallint PRIMARY KEY AUTO_INCREMENT,
+ model_name varbinary(64) NOT NULL
+) /*$wgDBTableOptions*/;
+
+-- Index for looking of the internal ID of for a name
+CREATE UNIQUE INDEX /*i*/model_name ON /*_*/content_models (model_name); \ No newline at end of file
diff --git a/www/wiki/maintenance/archives/patch-drop-ar_text.sql b/www/wiki/maintenance/archives/patch-drop-ar_text.sql
new file mode 100644
index 00000000..6dae71e3
--- /dev/null
+++ b/www/wiki/maintenance/archives/patch-drop-ar_text.sql
@@ -0,0 +1,7 @@
+-- T33223: Remove obsolete ar_text and ar_flags columns
+-- (and make ar_text_id not nullable and default 0)
+
+ALTER TABLE /*_*/archive
+ DROP COLUMN ar_text,
+ DROP COLUMN ar_flags,
+ CHANGE COLUMN ar_text_id ar_text_id int unsigned NOT NULL DEFAULT 0;
diff --git a/www/wiki/maintenance/archives/patch-drop-user_newtalk.sql b/www/wiki/maintenance/archives/patch-drop-user_newtalk.sql
deleted file mode 100644
index 6ec84fb3..00000000
--- a/www/wiki/maintenance/archives/patch-drop-user_newtalk.sql
+++ /dev/null
@@ -1,3 +0,0 @@
--- Patch for email authentication T.Gries/M.Arndt 27.11.2004
--- Table user_newtalk is dropped, as the table watchlist is now also used for storing user_talk-page notifications
-DROP TABLE /*$wgDBprefix*/user_newtalk;
diff --git a/www/wiki/maintenance/archives/patch-image-img_description_id.sql b/www/wiki/maintenance/archives/patch-image-img_description_id.sql
new file mode 100644
index 00000000..d098c80b
--- /dev/null
+++ b/www/wiki/maintenance/archives/patch-image-img_description_id.sql
@@ -0,0 +1,7 @@
+--
+-- patch-image-img_description_id.sql
+--
+-- T188132. Add `img_description_id` to the `image` table.
+
+ALTER TABLE /*_*/image
+ ADD COLUMN img_description_id bigint unsigned NOT NULL DEFAULT 0 AFTER img_description;
diff --git a/www/wiki/maintenance/archives/patch-log_search-rename-index.sql b/www/wiki/maintenance/archives/patch-log_search-rename-index.sql
deleted file mode 100644
index 7e1113e6..00000000
--- a/www/wiki/maintenance/archives/patch-log_search-rename-index.sql
+++ /dev/null
@@ -1,7 +0,0 @@
--- Rename the primary unique index from PRIMARY to ls_field_val
--- This is for MySQL only and is necessary only for databases which were updated
--- between MW 1.16 development revisions r50567 and r51465.
-ALTER TABLE /*_*/log_search
- DROP PRIMARY KEY,
- ADD UNIQUE INDEX ls_field_val (ls_field,ls_value,ls_log_id);
-
diff --git a/www/wiki/maintenance/archives/patch-nullable-ar_text.sql b/www/wiki/maintenance/archives/patch-nullable-ar_text.sql
new file mode 100644
index 00000000..b62ebfac
--- /dev/null
+++ b/www/wiki/maintenance/archives/patch-nullable-ar_text.sql
@@ -0,0 +1,13 @@
+--
+-- patch-nullable-ar_text.sql
+--
+-- This patch is provided as an example for people not using update.php.
+-- You need to make a change like this before running a version of MediaWiki
+-- containing Gerrit change 5ca2d4a551, then you can run maintenance/migrateArchiveText.php
+-- and apply patch-drop-ar_text.sql at your leisure.
+--
+-- See also T33223.
+
+ALTER TABLE /*_*/archive
+ MODIFY COLUMN ar_text mediumblob NULL,
+ MODIFY COLUMN ar_flags tinyblob NULL;
diff --git a/www/wiki/maintenance/archives/patch-pl-tl-il-unique.sql b/www/wiki/maintenance/archives/patch-pl-tl-il-unique.sql
deleted file mode 100644
index a3566705..00000000
--- a/www/wiki/maintenance/archives/patch-pl-tl-il-unique.sql
+++ /dev/null
@@ -1,11 +0,0 @@
---
--- patch-pl-tl-il-unique-index.sql
---
--- Make reorderings of UNIQUE indices UNIQUE as well
-
-DROP INDEX /*i*/pl_namespace ON /*_*/pagelinks;
-CREATE UNIQUE INDEX /*i*/pl_namespace ON /*_*/pagelinks (pl_namespace, pl_title, pl_from);
-DROP INDEX /*i*/tl_namespace ON /*_*/templatelinks;
-CREATE UNIQUE INDEX /*i*/tl_namespace ON /*_*/templatelinks (tl_namespace, tl_title, tl_from);
-DROP INDEX /*i*/il_to ON /*_*/imagelinks;
-CREATE UNIQUE INDEX /*i*/il_to ON /*_*/imagelinks (il_to, il_from);
diff --git a/www/wiki/maintenance/archives/patch-recentchanges-nttindex.sql b/www/wiki/maintenance/archives/patch-recentchanges-nttindex.sql
new file mode 100644
index 00000000..11794e80
--- /dev/null
+++ b/www/wiki/maintenance/archives/patch-recentchanges-nttindex.sql
@@ -0,0 +1,11 @@
+--
+-- patch-recentchanges-nttindex.sql
+--
+-- Per task T57377
+--
+-- Improve performance API queries to ask for a certain pages
+--
+
+
+DROP INDEX /*i*/rc_namespace_title ON /*_*/recentchanges;
+CREATE INDEX /*i*/rc_namespace_title_timestamp ON /*_*/recentchanges (rc_namespace, rc_title, rc_timestamp);
diff --git a/www/wiki/maintenance/archives/patch-rev_text_id-default.sql b/www/wiki/maintenance/archives/patch-rev_text_id-default.sql
new file mode 100644
index 00000000..dc6e4c66
--- /dev/null
+++ b/www/wiki/maintenance/archives/patch-rev_text_id-default.sql
@@ -0,0 +1,10 @@
+--
+-- Adds a default value to the rev_text_id field in the revision table.
+-- This is to allow the Multi Content Revisions migration to happen where
+-- rows will have to be added to the revision table with no rev_text_id.
+--
+-- 2018-03-12
+--
+
+ALTER TABLE /*$wgDBprefix*/revision
+ ALTER COLUMN rev_text_id SET DEFAULT 0; \ No newline at end of file
diff --git a/www/wiki/maintenance/archives/patch-site_stats-modify.sql b/www/wiki/maintenance/archives/patch-site_stats-modify.sql
new file mode 100644
index 00000000..c70dd001
--- /dev/null
+++ b/www/wiki/maintenance/archives/patch-site_stats-modify.sql
@@ -0,0 +1,7 @@
+ALTER TABLE /*_*/site_stats
+ ALTER ss_total_edits SET DEFAULT NULL,
+ ALTER ss_good_articles SET DEFAULT NULL,
+ MODIFY COLUMN ss_total_pages bigint unsigned DEFAULT NULL,
+ MODIFY COLUMN ss_users bigint unsigned DEFAULT NULL,
+ MODIFY COLUMN ss_active_users bigint unsigned DEFAULT NULL,
+ MODIFY COLUMN ss_images bigint unsigned DEFAULT NULL;
diff --git a/www/wiki/maintenance/archives/patch-slot-origin.sql b/www/wiki/maintenance/archives/patch-slot-origin.sql
new file mode 100644
index 00000000..ee069231
--- /dev/null
+++ b/www/wiki/maintenance/archives/patch-slot-origin.sql
@@ -0,0 +1,15 @@
+--
+-- Replace slot_inherited with slot_origin.
+--
+-- NOTE: There is no release that has slot_inherited. This is only needed to transition between
+-- snapshot versions of 1.30.
+--
+-- NOTE: No code that writes to the slots table was merged yet, the table is assumed to be empty.
+--
+DROP INDEX /*i*/slot_role_inherited ON /*_*/slots;
+
+ALTER TABLE /*_*/slots
+ DROP COLUMN slot_inherited,
+ ADD COLUMN slot_origin bigint unsigned NOT NULL;
+
+CREATE INDEX /*i*/slot_revision_origin_role ON /*_*/slots (slot_revision_id, slot_origin, slot_role_id);
diff --git a/www/wiki/maintenance/archives/patch-slot_roles.sql b/www/wiki/maintenance/archives/patch-slot_roles.sql
new file mode 100644
index 00000000..0b13caa8
--- /dev/null
+++ b/www/wiki/maintenance/archives/patch-slot_roles.sql
@@ -0,0 +1,10 @@
+--
+-- Normalization table for role names
+--
+CREATE TABLE /*_*/slot_roles (
+ role_id smallint PRIMARY KEY AUTO_INCREMENT,
+ role_name varbinary(64) NOT NULL
+) /*$wgDBTableOptions*/;
+
+-- Index for looking of the internal ID of for a name
+CREATE UNIQUE INDEX /*i*/role_name ON /*_*/slot_roles (role_name); \ No newline at end of file
diff --git a/www/wiki/maintenance/archives/patch-slots.sql b/www/wiki/maintenance/archives/patch-slots.sql
new file mode 100644
index 00000000..5fafe6d3
--- /dev/null
+++ b/www/wiki/maintenance/archives/patch-slots.sql
@@ -0,0 +1,25 @@
+--
+-- Slots represent an n:m relation between revisions and content objects.
+-- A content object can have a specific "role" in one or more revisions.
+-- Each revision can have multiple content objects, each having a different role.
+--
+CREATE TABLE /*_*/slots (
+
+ -- reference to rev_id
+ slot_revision_id bigint unsigned NOT NULL,
+
+ -- reference to role_id
+ slot_role_id smallint unsigned NOT NULL,
+
+ -- reference to content_id
+ slot_content_id bigint unsigned NOT NULL,
+
+ -- The revision ID of the revision that originated the slot's content.
+ -- To find revisions that changed slots, look for slot_origin = slot_revision_id.
+ slot_origin bigint unsigned NOT NULL,
+
+ PRIMARY KEY ( slot_revision_id, slot_role_id )
+) /*$wgDBTableOptions*/;
+
+-- Index for finding revisions that modified a specific slot
+CREATE INDEX /*i*/slot_revision_origin_role ON /*_*/slots (slot_revision_id, slot_origin, slot_role_id);
diff --git a/www/wiki/maintenance/archives/patch-user-newtalk-userid-unsigned.sql b/www/wiki/maintenance/archives/patch-user-newtalk-userid-unsigned.sql
deleted file mode 100644
index a83e03b9..00000000
--- a/www/wiki/maintenance/archives/patch-user-newtalk-userid-unsigned.sql
+++ /dev/null
@@ -1 +0,0 @@
-ALTER TABLE /*_*/user_newtalk MODIFY user_id int unsigned NOT NULL default 0;
diff --git a/www/wiki/maintenance/archives/upgradeLogging.php b/www/wiki/maintenance/archives/upgradeLogging.php
index 13362e09..bcf70230 100644
--- a/www/wiki/maintenance/archives/upgradeLogging.php
+++ b/www/wiki/maintenance/archives/upgradeLogging.php
@@ -132,13 +132,13 @@ EOT;
*/
function sync( $srcTable, $dstTable ) {
$batchSize = 1000;
- $minTs = $this->dbw->selectField( $srcTable, 'MIN(log_timestamp)', false, __METHOD__ );
+ $minTs = $this->dbw->selectField( $srcTable, 'MIN(log_timestamp)', '', __METHOD__ );
$minTsUnix = wfTimestamp( TS_UNIX, $minTs );
$numRowsCopied = 0;
while ( true ) {
- $maxTs = $this->dbw->selectField( $srcTable, 'MAX(log_timestamp)', false, __METHOD__ );
- $copyPos = $this->dbw->selectField( $dstTable, 'MAX(log_timestamp)', false, __METHOD__ );
+ $maxTs = $this->dbw->selectField( $srcTable, 'MAX(log_timestamp)', '', __METHOD__ );
+ $copyPos = $this->dbw->selectField( $dstTable, 'MAX(log_timestamp)', '', __METHOD__ );
$maxTsUnix = wfTimestamp( TS_UNIX, $maxTs );
$copyPosUnix = wfTimestamp( TS_UNIX, $copyPos );
diff --git a/www/wiki/maintenance/attachLatest.php b/www/wiki/maintenance/attachLatest.php
index 36060d83..897972c7 100644
--- a/www/wiki/maintenance/attachLatest.php
+++ b/www/wiki/maintenance/attachLatest.php
@@ -88,5 +88,5 @@ class AttachLatest extends Maintenance {
}
}
-$maintClass = "AttachLatest";
+$maintClass = AttachLatest::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/backup.inc b/www/wiki/maintenance/backup.inc
index 60b8a7a9..0fdd417f 100644
--- a/www/wiki/maintenance/backup.inc
+++ b/www/wiki/maintenance/backup.inc
@@ -25,8 +25,8 @@
*/
require_once __DIR__ . '/Maintenance.php';
-require_once __DIR__ . '/../includes/export/DumpFilter.php';
+use MediaWiki\MediaWikiServices;
use Wikimedia\Rdbms\LoadBalancer;
use Wikimedia\Rdbms\IDatabase;
@@ -83,15 +83,15 @@ class BackupDumper extends Maintenance {
$this->stderr = fopen( "php://stderr", "wt" );
// Built-in output and filter plugins
- $this->registerOutput( 'file', 'DumpFileOutput' );
- $this->registerOutput( 'gzip', 'DumpGZipOutput' );
- $this->registerOutput( 'bzip2', 'DumpBZip2Output' );
- $this->registerOutput( 'dbzip2', 'DumpDBZip2Output' );
- $this->registerOutput( '7zip', 'Dump7ZipOutput' );
+ $this->registerOutput( 'file', DumpFileOutput::class );
+ $this->registerOutput( 'gzip', DumpGZipOutput::class );
+ $this->registerOutput( 'bzip2', DumpBZip2Output::class );
+ $this->registerOutput( 'dbzip2', DumpDBZip2Output::class );
+ $this->registerOutput( '7zip', Dump7ZipOutput::class );
- $this->registerFilter( 'latest', 'DumpLatestFilter' );
- $this->registerFilter( 'notalk', 'DumpNotalkFilter' );
- $this->registerFilter( 'namespace', 'DumpNamespaceFilter' );
+ $this->registerFilter( 'latest', DumpLatestFilter::class );
+ $this->registerFilter( 'notalk', DumpNotalkFilter::class );
+ $this->registerFilter( 'namespace', DumpNamespaceFilter::class );
// These three can be specified multiple times
$this->addOption( 'plugin', 'Load a dump plugin class. Specify as <class>[:<file>].',
@@ -324,7 +324,8 @@ class BackupDumper extends Maintenance {
return $this->forcedDb;
}
- $this->lb = wfGetLBFactory()->newMainLB();
+ $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
+ $this->lb = $lbFactory->newMainLB();
$db = $this->lb->getConnection( DB_REPLICA, 'dump' );
// Discourage the server from disconnecting us if it takes a long time
@@ -419,25 +420,4 @@ class BackupDumper extends Maintenance {
fwrite( $this->stderr, $string . "\n" );
}
}
-
- function fatalError( $msg ) {
- $this->error( "$msg\n", 1 );
- }
-}
-
-class ExportProgressFilter extends DumpFilter {
- function __construct( &$sink, &$progress ) {
- parent::__construct( $sink );
- $this->progress = $progress;
- }
-
- function writeClosePage( $string ) {
- parent::writeClosePage( $string );
- $this->progress->reportPage();
- }
-
- function writeRevision( $rev, $string ) {
- parent::writeRevision( $rev, $string );
- $this->progress->revCount();
- }
}
diff --git a/www/wiki/maintenance/backupPrefetch.inc b/www/wiki/maintenance/backupPrefetch.inc
deleted file mode 100644
index 6a2d3bf6..00000000
--- a/www/wiki/maintenance/backupPrefetch.inc
+++ /dev/null
@@ -1,219 +0,0 @@
-<?php
-/**
- * Helper class for the --prefetch option of dumpTextPass.php
- *
- * Copyright © 2005 Brion Vibber <brion@pobox.com>
- * https://www.mediawiki.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup Maintenance
- */
-
-/**
- * Readahead helper for making large MediaWiki data dumps;
- * reads in a previous XML dump to sequentially prefetch text
- * records already normalized and decompressed.
- *
- * This can save load on the external database servers, hopefully.
- *
- * Assumes that dumps will be recorded in the canonical order:
- * - ascending by page_id
- * - ascending by rev_id within each page
- * - text contents are immutable and should not change once
- * recorded, so the previous dump is a reliable source
- *
- * @ingroup Maintenance
- */
-class BaseDump {
- /** @var XMLReader */
- protected $reader = null;
- protected $atEnd = false;
- protected $atPageEnd = false;
- protected $lastPage = 0;
- protected $lastRev = 0;
- protected $infiles = null;
-
- public function __construct( $infile ) {
- $this->infiles = explode( ';', $infile );
- $this->reader = new XMLReader();
- $infile = array_shift( $this->infiles );
- if ( defined( 'LIBXML_PARSEHUGE' ) ) {
- $this->reader->open( $infile, null, LIBXML_PARSEHUGE );
- } else {
- $this->reader->open( $infile );
- }
- }
-
- /**
- * Attempts to fetch the text of a particular page revision
- * from the dump stream. May return null if the page is
- * unavailable.
- *
- * @param int $page ID number of page to read
- * @param int $rev ID number of revision to read
- * @return string|null
- */
- function prefetch( $page, $rev ) {
- $page = intval( $page );
- $rev = intval( $rev );
- while ( $this->lastPage < $page && !$this->atEnd ) {
- $this->debug( "BaseDump::prefetch at page $this->lastPage, looking for $page" );
- $this->nextPage();
- }
- if ( $this->lastPage > $page || $this->atEnd ) {
- $this->debug( "BaseDump::prefetch already past page $page "
- . "looking for rev $rev [$this->lastPage, $this->lastRev]" );
-
- return null;
- }
- while ( $this->lastRev < $rev && !$this->atEnd && !$this->atPageEnd ) {
- $this->debug( "BaseDump::prefetch at page $this->lastPage, rev $this->lastRev, "
- . "looking for $page, $rev" );
- $this->nextRev();
- }
- if ( $this->lastRev == $rev && !$this->atEnd ) {
- $this->debug( "BaseDump::prefetch hit on $page, $rev [$this->lastPage, $this->lastRev]" );
-
- return $this->nextText();
- } else {
- $this->debug( "BaseDump::prefetch already past rev $rev on page $page "
- . "[$this->lastPage, $this->lastRev]" );
-
- return null;
- }
- }
-
- function debug( $str ) {
- wfDebug( $str . "\n" );
- // global $dumper;
- // $dumper->progress( $str );
- }
-
- /**
- * @access private
- */
- function nextPage() {
- if ( $this->skipTo( 'page', 'mediawiki' ) ) {
- if ( $this->skipTo( 'id' ) ) {
- $this->lastPage = intval( $this->nodeContents() );
- $this->lastRev = 0;
- $this->atPageEnd = false;
- }
- } else {
- $this->close();
- if ( count( $this->infiles ) ) {
- $infile = array_shift( $this->infiles );
- $this->reader->open( $infile );
- $this->atEnd = false;
- }
- }
- }
-
- /**
- * @access private
- */
- function nextRev() {
- if ( $this->skipTo( 'revision' ) ) {
- if ( $this->skipTo( 'id' ) ) {
- $this->lastRev = intval( $this->nodeContents() );
- }
- } else {
- $this->atPageEnd = true;
- }
- }
-
- /**
- * @access private
- * @return string
- */
- function nextText() {
- $this->skipTo( 'text' );
-
- return strval( $this->nodeContents() );
- }
-
- /**
- * @access private
- * @param string $name
- * @param string $parent
- * @return bool|null
- */
- function skipTo( $name, $parent = 'page' ) {
- if ( $this->atEnd ) {
- return false;
- }
- while ( $this->reader->read() ) {
- if ( $this->reader->nodeType == XMLReader::ELEMENT
- && $this->reader->name == $name
- ) {
- return true;
- }
- if ( $this->reader->nodeType == XMLReader::END_ELEMENT
- && $this->reader->name == $parent
- ) {
- $this->debug( "BaseDump::skipTo found </$parent> searching for <$name>" );
-
- return false;
- }
- }
-
- return $this->close();
- }
-
- /**
- * Shouldn't something like this be built-in to XMLReader?
- * Fetches text contents of the current element, assuming
- * no sub-elements or such scary things.
- *
- * @return string
- * @access private
- */
- function nodeContents() {
- if ( $this->atEnd ) {
- return null;
- }
- if ( $this->reader->isEmptyElement ) {
- return "";
- }
- $buffer = "";
- while ( $this->reader->read() ) {
- switch ( $this->reader->nodeType ) {
- case XMLReader::TEXT:
- // case XMLReader::WHITESPACE:
- case XMLReader::SIGNIFICANT_WHITESPACE:
- $buffer .= $this->reader->value;
- break;
- case XMLReader::END_ELEMENT:
- return $buffer;
- }
- }
-
- return $this->close();
- }
-
- /**
- * @access private
- * @return null
- */
- function close() {
- $this->reader->close();
- $this->atEnd = true;
-
- return null;
- }
-}
diff --git a/www/wiki/maintenance/benchmarks/Benchmarker.php b/www/wiki/maintenance/benchmarks/Benchmarker.php
index 832da4db..e1eef07e 100644
--- a/www/wiki/maintenance/benchmarks/Benchmarker.php
+++ b/www/wiki/maintenance/benchmarks/Benchmarker.php
@@ -26,7 +26,11 @@
* @ingroup Benchmark
*/
+use Wikimedia\RunningStat;
+
+// @codeCoverageIgnoreStart
require_once __DIR__ . '/../Maintenance.php';
+// @codeCoverageIgnoreEnd
/**
* Base class for benchmark scripts.
@@ -66,7 +70,7 @@ abstract class Benchmarker extends Maintenance {
}
// Run benchmarks
- $times = [];
+ $stat = new RunningStat();
for ( $i = 0; $i < $count; $i++ ) {
$t = microtime( true );
call_user_func_array( $bench['function'], $bench['args'] );
@@ -74,20 +78,8 @@ abstract class Benchmarker extends Maintenance {
if ( $verbose ) {
$this->verboseRun( $i );
}
- $times[] = $t;
- }
-
- // Collect metrics
- sort( $times, SORT_NUMERIC );
- $min = $times[0];
- $max = end( $times );
- if ( $count % 2 ) {
- $median = $times[ ( $count - 1 ) / 2 ];
- } else {
- $median = ( $times[$count / 2] + $times[$count / 2 - 1] ) / 2;
+ $stat->addObservation( $t );
}
- $total = array_sum( $times );
- $mean = $total / $count;
// Name defaults to name of called function
if ( is_string( $key ) ) {
@@ -106,12 +98,13 @@ abstract class Benchmarker extends Maintenance {
$this->addResult( [
'name' => $name,
- 'count' => $count,
- 'total' => $total,
- 'min' => $min,
- 'median' => $median,
- 'mean' => $mean,
- 'max' => $max,
+ 'count' => $stat->getCount(),
+ // Get rate per second from mean (in ms)
+ 'rate' => $stat->getMean() == 0 ? INF : ( 1.0 / ( $stat->getMean() / 1000.0 ) ),
+ 'total' => $stat->getMean() * $stat->getCount(),
+ 'mean' => $stat->getMean(),
+ 'max' => $stat->max,
+ 'stddev' => $stat->getStdDev(),
'usage' => [
'mem' => memory_get_usage( true ),
'mempeak' => memory_get_peak_usage( true ),
@@ -135,12 +128,15 @@ abstract class Benchmarker extends Maintenance {
public function addResult( $res ) {
$ret = sprintf( "%s\n %' 6s: %d\n",
$res['name'],
- 'times',
+ 'count',
$res['count']
);
-
- foreach ( [ 'total', 'min', 'median', 'mean', 'max' ] as $metric ) {
- $ret .= sprintf( " %' 6s: %6.2fms\n",
+ $ret .= sprintf( " %' 6s: %8.1f/s\n",
+ 'rate',
+ $res['rate']
+ );
+ foreach ( [ 'total', 'mean', 'max', 'stddev' ] as $metric ) {
+ $ret .= sprintf( " %' 6s: %8.2fms\n",
$metric,
$res[$metric]
);
diff --git a/www/wiki/maintenance/benchmarks/README b/www/wiki/maintenance/benchmarks/README
deleted file mode 100644
index 27da9def..00000000
--- a/www/wiki/maintenance/benchmarks/README
+++ /dev/null
@@ -1,10 +0,0 @@
-This directory hold several benchmarking scripts used as a proof of speed
-or to track PHP performances over time.
-
-To get somehow accurate result, you might want to bound the PHP process
-to a specific CPU with `taskset` and raise its priority with `nice`. Example:
-
- $ taskset 1 nice -n-10 php bench_wfIsWindows.php
-
-australia-untidy.html.gz contains representative input text for
-benchmarkTidy.php. It needs to be decompressed before use.
diff --git a/www/wiki/maintenance/benchmarks/README.md b/www/wiki/maintenance/benchmarks/README.md
new file mode 100644
index 00000000..b411c526
--- /dev/null
+++ b/www/wiki/maintenance/benchmarks/README.md
@@ -0,0 +1,15 @@
+This directory hold several benchmarking scripts used track performances of
+MediaWiki and/or PHP.
+
+## Consistency
+
+On Linux, use of `taskset` and `nice` can help get more consistent results.
+
+For example:
+
+ $ taskset 1 nice -n-10 php bench_wfIsWindows.php
+
+## Fixtures
+
+* australia-untidy.html.gz: Representative input text for benchmarkTidy.php.
+ It needs to be decompressed before use.
diff --git a/www/wiki/maintenance/benchmarks/bench_HTTP_HTTPS.php b/www/wiki/maintenance/benchmarks/bench_HTTP_HTTPS.php
index 0e3cd73d..5e1feb73 100644
--- a/www/wiki/maintenance/benchmarks/bench_HTTP_HTTPS.php
+++ b/www/wiki/maintenance/benchmarks/bench_HTTP_HTTPS.php
@@ -59,5 +59,5 @@ class BenchHttpHttps extends Benchmarker {
}
}
-$maintClass = 'BenchHttpHttps';
+$maintClass = BenchHttpHttps::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/benchmarks/bench_Wikimedia_base_convert.php b/www/wiki/maintenance/benchmarks/bench_Wikimedia_base_convert.php
index 86bcc8a3..f9b3a74e 100644
--- a/www/wiki/maintenance/benchmarks/bench_Wikimedia_base_convert.php
+++ b/www/wiki/maintenance/benchmarks/bench_Wikimedia_base_convert.php
@@ -73,5 +73,5 @@ class BenchWikimediaBaseConvert extends Benchmarker {
}
}
-$maintClass = 'BenchWikimediaBaseConvert';
+$maintClass = BenchWikimediaBaseConvert::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/benchmarks/bench_delete_truncate.php b/www/wiki/maintenance/benchmarks/bench_delete_truncate.php
index 0a999ecc..794b743e 100644
--- a/www/wiki/maintenance/benchmarks/bench_delete_truncate.php
+++ b/www/wiki/maintenance/benchmarks/bench_delete_truncate.php
@@ -101,5 +101,5 @@ class BenchmarkDeleteTruncate extends Benchmarker {
}
}
-$maintClass = 'BenchmarkDeleteTruncate';
+$maintClass = BenchmarkDeleteTruncate::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/benchmarks/bench_if_switch.php b/www/wiki/maintenance/benchmarks/bench_if_switch.php
index 843ef7cd..5f661f2d 100644
--- a/www/wiki/maintenance/benchmarks/bench_if_switch.php
+++ b/www/wiki/maintenance/benchmarks/bench_if_switch.php
@@ -106,5 +106,5 @@ class BenchIfSwitch extends Benchmarker {
}
}
-$maintClass = 'BenchIfSwitch';
+$maintClass = BenchIfSwitch::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/benchmarks/bench_strtr_str_replace.php b/www/wiki/maintenance/benchmarks/bench_strtr_str_replace.php
index 55c7159b..2c065f6c 100644
--- a/www/wiki/maintenance/benchmarks/bench_strtr_str_replace.php
+++ b/www/wiki/maintenance/benchmarks/bench_strtr_str_replace.php
@@ -70,5 +70,5 @@ class BenchStrtrStrReplace extends Benchmarker {
}
}
-$maintClass = 'BenchStrtrStrReplace';
+$maintClass = BenchStrtrStrReplace::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/benchmarks/bench_utf8_title_check.php b/www/wiki/maintenance/benchmarks/bench_utf8_title_check.php
index 3091de62..b13b8632 100644
--- a/www/wiki/maintenance/benchmarks/bench_utf8_title_check.php
+++ b/www/wiki/maintenance/benchmarks/bench_utf8_title_check.php
@@ -37,7 +37,7 @@ class BenchUtf8TitleCheck extends Benchmarker {
public function __construct() {
parent::__construct();
- // @codingStandardsIgnoreStart Ignore long line warnings.
+ // phpcs:disable Generic.Files.LineLength
$this->data = [
"",
"United States of America", // 7bit ASCII
@@ -59,7 +59,7 @@ class BenchUtf8TitleCheck extends Benchmarker {
. "Sara%20Sidle%7CSofia%20Curtis%7CS%C3%A9rie%20t%C3%A9l%C3%A9vis%C3%A9e%7CWallace%20Langham%7C"
. "Warrick%20Brown%7CWendy%20Simms%7C%C3%89tats-Unis"
];
- // @codingStandardsIgnoreEnd
+ // phpcs:enable
$this->addDescription( "Benchmark for using a regexp vs. mb_check_encoding " .
"to check for UTF-8 encoding." );
@@ -110,5 +110,5 @@ class BenchUtf8TitleCheck extends Benchmarker {
}
}
-$maintClass = 'BenchUtf8TitleCheck';
+$maintClass = BenchUtf8TitleCheck::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/benchmarks/bench_wfIsWindows.php b/www/wiki/maintenance/benchmarks/bench_wfIsWindows.php
index 960ef0e8..6943182b 100644
--- a/www/wiki/maintenance/benchmarks/bench_wfIsWindows.php
+++ b/www/wiki/maintenance/benchmarks/bench_wfIsWindows.php
@@ -64,5 +64,5 @@ class BenchWfIsWindows extends Benchmarker {
}
}
-$maintClass = 'BenchWfIsWindows';
+$maintClass = BenchWfIsWindows::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/benchmarks/benchmarkCSSMin.php b/www/wiki/maintenance/benchmarks/benchmarkCSSMin.php
index 3eaa88dc..a7d998d2 100644
--- a/www/wiki/maintenance/benchmarks/benchmarkCSSMin.php
+++ b/www/wiki/maintenance/benchmarks/benchmarkCSSMin.php
@@ -52,11 +52,11 @@ class BenchmarkCSSMin extends Benchmarker {
$this->bench( [
"minify ($filename)" => [
- 'function' => [ 'CSSMin', 'minify' ],
+ 'function' => [ CSSMin::class, 'minify' ],
'args' => [ $css ]
],
"remap ($filename)" => [
- 'function' => [ 'CSSMin', 'remap' ],
+ 'function' => [ CSSMin::class, 'remap' ],
'args' => [ $css, dirname( $file ), 'https://example.org/test/', true ]
],
] );
@@ -72,5 +72,5 @@ class BenchmarkCSSMin extends Benchmarker {
}
}
-$maintClass = 'BenchmarkCSSMin';
+$maintClass = BenchmarkCSSMin::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/benchmarks/benchmarkHooks.php b/www/wiki/maintenance/benchmarks/benchmarkHooks.php
index d49fa1d4..0bfe0394 100644
--- a/www/wiki/maintenance/benchmarks/benchmarkHooks.php
+++ b/www/wiki/maintenance/benchmarks/benchmarkHooks.php
@@ -69,5 +69,5 @@ class BenchmarkHooks extends Benchmarker {
}
}
-$maintClass = 'BenchmarkHooks';
+$maintClass = BenchmarkHooks::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/benchmarks/benchmarkJSMinPlus.php b/www/wiki/maintenance/benchmarks/benchmarkJSMinPlus.php
index dc925160..3aa7af71 100644
--- a/www/wiki/maintenance/benchmarks/benchmarkJSMinPlus.php
+++ b/www/wiki/maintenance/benchmarks/benchmarkJSMinPlus.php
@@ -37,11 +37,11 @@ class BenchmarkJSMinPlus extends Benchmarker {
}
public function execute() {
- MediaWiki\suppressWarnings();
+ Wikimedia\suppressWarnings();
$content = file_get_contents( $this->getOption( 'file' ) );
- MediaWiki\restoreWarnings();
+ Wikimedia\restoreWarnings();
if ( $content === false ) {
- $this->error( 'Unable to open input file', 1 );
+ $this->fatalError( 'Unable to open input file' );
}
$filename = basename( $this->getOption( 'file' ) );
@@ -58,5 +58,5 @@ class BenchmarkJSMinPlus extends Benchmarker {
}
}
-$maintClass = 'BenchmarkJSMinPlus';
+$maintClass = BenchmarkJSMinPlus::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/benchmarks/benchmarkLruHash.php b/www/wiki/maintenance/benchmarks/benchmarkLruHash.php
index 1541f827..6b1fcd36 100644
--- a/www/wiki/maintenance/benchmarks/benchmarkLruHash.php
+++ b/www/wiki/maintenance/benchmarks/benchmarkLruHash.php
@@ -32,8 +32,7 @@ class BenchmarkLruHash extends Benchmarker {
public function __construct() {
parent::__construct();
$this->addDescription( 'Benchmarks HashBagOStuff and MapCacheLRU.' );
- $this->addOption( 'construct', 'Run construct only', false, false );
- $this->addOption( 'fill', 'Run fill only', false, false );
+ $this->addOption( 'method', 'One of "construct" or "set". Default: [All]', false, true );
}
public function execute() {
@@ -46,27 +45,26 @@ class BenchmarkLruHash extends Benchmarker {
// 1000 keys (1...500, 500...1)
$keys = array_merge( $exampleKeys, array_reverse( $exampleKeys ) );
- $fill = $this->hasOption( 'fill' ) || !$this->hasOption( 'construct' );
- $construct = $this->hasOption( 'construct' ) || !$this->hasOption( 'fill' );
+ $method = $this->getOption( 'method' );
$benches = [];
- if ( $construct ) {
- $benches['HashBagOStuff-construct'] = [
+ if ( !$method || $method === 'construct' ) {
+ $benches['HashBagOStuff::__construct'] = [
'function' => function () use ( $max ) {
$obj = new HashBagOStuff( [ 'maxKeys' => $max ] );
},
];
- $benches['MapCacheLRU-construct'] = [
+ $benches['MapCacheLRU::__construct'] = [
'function' => function () use ( $max ) {
$obj = new MapCacheLRU( $max );
},
];
}
- if ( $fill ) {
- // For the fill bechmark, ensure object creation is not measured.
+ if ( !$method || $method === 'set' ) {
+ // For the set bechmark, do object creation in setup (not measured)
$hObj = null;
- $benches['HashBagOStuff-fill'] = [
+ $benches['HashBagOStuff::set'] = [
'setup' => function () use ( &$hObj, $max ) {
$hObj = new HashBagOStuff( [ 'maxKeys' => $max ] );
},
@@ -77,7 +75,7 @@ class BenchmarkLruHash extends Benchmarker {
}
];
$mObj = null;
- $benches['MapCacheLRU-fill'] = [
+ $benches['MapCacheLRU::set'] = [
'setup' => function () use ( &$mObj, $max ) {
$mObj = new MapCacheLRU( $max );
},
diff --git a/www/wiki/maintenance/benchmarks/benchmarkParse.php b/www/wiki/maintenance/benchmarks/benchmarkParse.php
index 1753250b..3a79ad3e 100644
--- a/www/wiki/maintenance/benchmarks/benchmarkParse.php
+++ b/www/wiki/maintenance/benchmarks/benchmarkParse.php
@@ -106,7 +106,7 @@ class BenchmarkParse extends Maintenance {
$loops = $this->getOption( 'loops', 1 );
if ( $loops < 1 ) {
- $this->error( 'Invalid number of loops specified', true );
+ $this->fatalError( 'Invalid number of loops specified' );
}
$startUsage = getrusage();
$startTime = microtime( true );
@@ -188,5 +188,5 @@ class BenchmarkParse extends Maintenance {
}
}
-$maintClass = 'BenchmarkParse';
+$maintClass = BenchmarkParse::class;
require RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/benchmarks/benchmarkPurge.php b/www/wiki/maintenance/benchmarks/benchmarkPurge.php
index e006cf53..cbab6775 100644
--- a/www/wiki/maintenance/benchmarks/benchmarkPurge.php
+++ b/www/wiki/maintenance/benchmarks/benchmarkPurge.php
@@ -37,7 +37,7 @@ class BenchmarkPurge extends Benchmarker {
public function execute() {
global $wgUseSquid, $wgSquidServers;
if ( !$wgUseSquid ) {
- $this->error( "Squid purge benchmark doesn't do much without squid support on.", true );
+ $this->fatalError( "Squid purge benchmark doesn't do much without squid support on." );
} else {
$this->output( "There are " . count( $wgSquidServers ) . " defined squid servers:\n" );
if ( $this->hasOption( 'count' ) ) {
@@ -114,5 +114,5 @@ class BenchmarkPurge extends Benchmarker {
}
}
-$maintClass = "BenchmarkPurge";
+$maintClass = BenchmarkPurge::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/benchmarks/benchmarkSanitizer.php b/www/wiki/maintenance/benchmarks/benchmarkSanitizer.php
new file mode 100644
index 00000000..c264750b
--- /dev/null
+++ b/www/wiki/maintenance/benchmarks/benchmarkSanitizer.php
@@ -0,0 +1,99 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Benchmark
+ */
+
+require_once __DIR__ . '/Benchmarker.php';
+
+/**
+ * Maintenance script that benchmarks Sanitizer methods.
+ *
+ * @ingroup Benchmark
+ */
+class BenchmarkSanitizer extends Benchmarker {
+ public function __construct() {
+ parent::__construct();
+ $this->addDescription( 'Benchmark for Sanitizer methods.' );
+ $this->addOption( 'method', 'One of "validateEmail", "encodeAttribute", '
+ . '"safeEncodeAttribute", "removeHTMLtags", or "stripAllTags". '
+ . 'Default: (All)', false, true );
+ }
+
+ public function execute() {
+ $textWithHtmlSm = 'Before <wrap><in>and</in> another <unclose> <in>word</in></wrap>.';
+ $textWithHtmlLg = str_repeat(
+ // 28K (28 chars * 1000)
+ wfRandomString( 3 ) . ' <tag>' . wfRandomString( 5 ) . '</tag> ' . wfRandomString( 7 ),
+ 1000
+ );
+
+ $method = $this->getOption( 'method' );
+ $benches = [];
+
+ if ( !$method || $method === 'validateEmail' ) {
+ $benches['Sanitizer::validateEmail (valid)'] = function () {
+ Sanitizer::validateEmail( 'user@example.org' );
+ };
+ $benches['Sanitizer::validateEmail (invalid)'] = function () {
+ Sanitizer::validateEmail( 'username@example! org' );
+ };
+ }
+ if ( !$method || $method === 'encodeAttribute' ) {
+ $benches['Sanitizer::encodeAttribute (simple)'] = function () {
+ Sanitizer::encodeAttribute( 'simple' );
+ };
+ $benches['Sanitizer::encodeAttribute (special)'] = function () {
+ Sanitizer::encodeAttribute( ":'\"\n https://example" );
+ };
+ }
+ if ( !$method || $method === 'safeEncodeAttribute' ) {
+ $benches['Sanitizer::safeEncodeAttribute (simple)'] = function () {
+ Sanitizer::safeEncodeAttribute( 'simple' );
+ };
+ $benches['Sanitizer::safeEncodeAttribute (special)'] = function () {
+ Sanitizer::safeEncodeAttribute( ":'\"\n https://example" );
+ };
+ }
+ if ( !$method || $method === 'removeHTMLtags' ) {
+ $sm = strlen( $textWithHtmlSm );
+ $lg = round( strlen( $textWithHtmlLg ) / 1000 ) . 'K';
+ $benches["Sanitizer::removeHTMLtags (input: $sm)"] = function () use ( $textWithHtmlSm ) {
+ Sanitizer::removeHTMLtags( $textWithHtmlSm );
+ };
+ $benches["Sanitizer::removeHTMLtags (input: $lg)"] = function () use ( $textWithHtmlLg ) {
+ Sanitizer::removeHTMLtags( $textWithHtmlLg );
+ };
+ }
+ if ( !$method || $method === 'stripAllTags' ) {
+ $sm = strlen( $textWithHtmlSm );
+ $lg = round( strlen( $textWithHtmlLg ) / 1000 ) . 'K';
+ $benches["Sanitizer::stripAllTags (input: $sm)"] = function () use ( $textWithHtmlSm ) {
+ Sanitizer::stripAllTags( $textWithHtmlSm );
+ };
+ $benches["Sanitizer::stripAllTags (input: $lg)"] = function () use ( $textWithHtmlLg ) {
+ Sanitizer::stripAllTags( $textWithHtmlLg );
+ };
+ }
+
+ $this->bench( $benches );
+ }
+}
+
+$maintClass = BenchmarkSanitizer::class;
+require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/benchmarks/benchmarkTidy.php b/www/wiki/maintenance/benchmarks/benchmarkTidy.php
index 14791745..f2939b33 100644
--- a/www/wiki/maintenance/benchmarks/benchmarkTidy.php
+++ b/www/wiki/maintenance/benchmarks/benchmarkTidy.php
@@ -15,19 +15,19 @@ class BenchmarkTidy extends Maintenance {
public function execute() {
$html = file_get_contents( $this->getOption( 'file' ) );
if ( $html === false ) {
- $this->error( "Unable to open input file", 1 );
+ $this->fatalError( "Unable to open input file" );
}
if ( $this->hasOption( 'driver' ) || $this->hasOption( 'tidy-config' ) ) {
$config = json_decode( $this->getOption( 'tidy-config', '{}' ), true );
if ( !is_array( $config ) ) {
- $this->error( "Invalid JSON tidy config", 1 );
+ $this->fatalError( "Invalid JSON tidy config" );
}
$config += [ 'driver' => $this->getOption( 'driver', 'RemexHtml' ) ];
$driver = MWTidy::factory( $config );
} else {
$driver = MWTidy::singleton();
if ( !$driver ) {
- $this->error( "Tidy disabled or not installed", 1 );
+ $this->fatalError( "Tidy disabled or not installed" );
}
}
@@ -74,5 +74,5 @@ class BenchmarkTidy extends Maintenance {
}
}
-$maintClass = 'BenchmarkTidy';
+$maintClass = BenchmarkTidy::class;
require RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/cdb.php b/www/wiki/maintenance/cdb.php
index bff2c13f..0870d6d4 100644
--- a/www/wiki/maintenance/cdb.php
+++ b/www/wiki/maintenance/cdb.php
@@ -21,8 +21,9 @@
* @todo document
* @ingroup Maintenance
*/
-use \Cdb\Exception as CdbException;
-use \Cdb\Reader as CdbReader;
+
+use Cdb\Exception as CdbException;
+use Cdb\Reader as CdbReader;
require_once __DIR__ . '/commandLine.inc';
diff --git a/www/wiki/maintenance/changePassword.php b/www/wiki/maintenance/changePassword.php
index 9fa66324..316004bd 100644
--- a/www/wiki/maintenance/changePassword.php
+++ b/www/wiki/maintenance/changePassword.php
@@ -46,10 +46,10 @@ class ChangePassword extends Maintenance {
} elseif ( $this->hasOption( "userid" ) ) {
$user = User::newFromId( $this->getOption( 'userid' ) );
} else {
- $this->error( "A \"user\" or \"userid\" must be set to change the password for", true );
+ $this->fatalError( "A \"user\" or \"userid\" must be set to change the password for" );
}
if ( !$user || !$user->getId() ) {
- $this->error( "No such user: " . $this->getOption( 'user' ), true );
+ $this->fatalError( "No such user: " . $this->getOption( 'user' ) );
}
$password = $this->getOption( 'password' );
try {
@@ -64,10 +64,10 @@ class ChangePassword extends Maintenance {
$user->saveSettings();
$this->output( "Password set for " . $user->getName() . "\n" );
} catch ( PasswordError $pwe ) {
- $this->error( $pwe->getText(), true );
+ $this->fatalError( $pwe->getText() );
}
}
}
-$maintClass = "ChangePassword";
+$maintClass = ChangePassword::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/checkBadRedirects.php b/www/wiki/maintenance/checkBadRedirects.php
index 6eafc96e..b22432a0 100644
--- a/www/wiki/maintenance/checkBadRedirects.php
+++ b/www/wiki/maintenance/checkBadRedirects.php
@@ -60,5 +60,5 @@ class CheckBadRedirects extends Maintenance {
}
}
-$maintClass = "CheckBadRedirects";
+$maintClass = CheckBadRedirects::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/checkComposerLockUpToDate.php b/www/wiki/maintenance/checkComposerLockUpToDate.php
index e5b4c13e..69f16f50 100644
--- a/www/wiki/maintenance/checkComposerLockUpToDate.php
+++ b/www/wiki/maintenance/checkComposerLockUpToDate.php
@@ -24,9 +24,8 @@ class CheckComposerLockUpToDate extends Maintenance {
// Maybe they're using mediawiki/vendor?
$lockLocation = "$IP/vendor/composer.lock";
if ( !file_exists( $lockLocation ) ) {
- $this->error(
- 'Could not find composer.lock file. Have you run "composer install --no-dev"?',
- 1
+ $this->fatalError(
+ 'Could not find composer.lock file. Have you run "composer install --no-dev"?'
);
}
}
@@ -51,10 +50,9 @@ class CheckComposerLockUpToDate extends Maintenance {
}
}
if ( $found ) {
- $this->error(
+ $this->fatalError(
'Error: your composer.lock file is not up to date. ' .
- 'Run "composer update --no-dev" to install newer dependencies',
- 1
+ 'Run "composer update --no-dev" to install newer dependencies'
);
} else {
// We couldn't find any out-of-date dependencies, so assume everything is ok!
@@ -63,5 +61,5 @@ class CheckComposerLockUpToDate extends Maintenance {
}
}
-$maintClass = 'CheckComposerLockUpToDate';
+$maintClass = CheckComposerLockUpToDate::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/checkImages.php b/www/wiki/maintenance/checkImages.php
index 3e573930..f858f030 100644
--- a/www/wiki/maintenance/checkImages.php
+++ b/www/wiki/maintenance/checkImages.php
@@ -43,9 +43,11 @@ class CheckImages extends Maintenance {
$numGood = 0;
$repo = RepoGroup::singleton()->getLocalRepo();
+ $fileQuery = LocalFile::getQueryInfo();
do {
- $res = $dbr->select( 'image', '*', [ 'img_name > ' . $dbr->addQuotes( $start ) ],
- __METHOD__, [ 'LIMIT' => $this->mBatchSize ] );
+ $res = $dbr->select( $fileQuery['tables'], $fileQuery['fields'],
+ [ 'img_name > ' . $dbr->addQuotes( $start ) ],
+ __METHOD__, [ 'LIMIT' => $this->getBatchSize() ], $fileQuery['joins'] );
foreach ( $res as $row ) {
$numImages++;
$start = $row->img_name;
@@ -80,5 +82,5 @@ class CheckImages extends Maintenance {
}
}
-$maintClass = "CheckImages";
+$maintClass = CheckImages::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/checkLess.php b/www/wiki/maintenance/checkLess.php
index 8416c8ab..55ffcb83 100644
--- a/www/wiki/maintenance/checkLess.php
+++ b/www/wiki/maintenance/checkLess.php
@@ -43,7 +43,7 @@ class CheckLess extends Maintenance {
self::requireTestsAutoloader();
// If phpunit isn't available by autoloader try pulling it in
- if ( !class_exists( 'PHPUnit_Framework_TestCase' ) ) {
+ if ( !class_exists( 'PHPUnit\\Framework\\TestCase' ) ) {
require_once 'PHPUnit/Autoload.php';
}
@@ -62,5 +62,5 @@ class CheckLess extends Maintenance {
}
}
-$maintClass = 'CheckLess';
+$maintClass = CheckLess::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/checkSyntax.php b/www/wiki/maintenance/checkSyntax.php
deleted file mode 100644
index 3910f29d..00000000
--- a/www/wiki/maintenance/checkSyntax.php
+++ /dev/null
@@ -1,349 +0,0 @@
-<?php
-/**
- * Check syntax of all PHP files in MediaWiki
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup Maintenance
- */
-
-require_once __DIR__ . '/Maintenance.php';
-
-/**
- * Maintenance script to check syntax of all PHP files in MediaWiki.
- *
- * @ingroup Maintenance
- */
-class CheckSyntax extends Maintenance {
-
- // List of files we're going to check
- private $mFiles = [], $mFailures = [], $mWarnings = [];
- private $mIgnorePaths = [], $mNoStyleCheckPaths = [];
-
- public function __construct() {
- parent::__construct();
- $this->addDescription( 'Check syntax for all PHP files in MediaWiki' );
- $this->addOption( 'with-extensions', 'Also recurse the extensions folder' );
- $this->addOption(
- 'path',
- 'Specific path (file or directory) to check, either with absolute path or '
- . 'relative to the root of this MediaWiki installation',
- false,
- true
- );
- $this->addOption(
- 'list-file',
- 'Text file containing list of files or directories to check',
- false,
- true
- );
- $this->addOption(
- 'modified',
- 'Check only files that were modified (requires Git command-line client)'
- );
- $this->addOption( 'syntax-only', 'Check for syntax validity only, skip code style warnings' );
- }
-
- public function getDbType() {
- return Maintenance::DB_NONE;
- }
-
- public function execute() {
- $this->buildFileList();
-
- $this->output( "Checking syntax (using php -l, this can take a long time)\n" );
- foreach ( $this->mFiles as $f ) {
- $this->checkFileWithCli( $f );
- if ( !$this->hasOption( 'syntax-only' ) ) {
- $this->checkForMistakes( $f );
- }
- }
- $this->output( "\nDone! " . count( $this->mFiles ) . " files checked, " .
- count( $this->mFailures ) . " failures and " . count( $this->mWarnings ) .
- " warnings found\n" );
- }
-
- /**
- * Build the list of files we'll check for syntax errors
- */
- private function buildFileList() {
- global $IP;
-
- $this->mIgnorePaths = [
- ];
-
- $this->mNoStyleCheckPaths = [
- // Third-party code we don't care about
- "/activemq_stomp/",
- "EmailPage/PHPMailer",
- "FCKeditor/fckeditor/",
- '\bphplot-',
- "/svggraph/",
- "\bjsmin.php$",
- "PEAR/File_Ogg/",
- "QPoll/Excel/",
- "/geshi/",
- "/smarty/",
- ];
-
- if ( $this->hasOption( 'path' ) ) {
- $path = $this->getOption( 'path' );
- if ( !$this->addPath( $path ) ) {
- $this->error( "Error: can't find file or directory $path\n", true );
- }
-
- return; // process only this path
- } elseif ( $this->hasOption( 'list-file' ) ) {
- $file = $this->getOption( 'list-file' );
- MediaWiki\suppressWarnings();
- $f = fopen( $file, 'r' );
- MediaWiki\restoreWarnings();
- if ( !$f ) {
- $this->error( "Can't open file $file\n", true );
- }
- $path = trim( fgets( $f ) );
- while ( $path ) {
- $this->addPath( $path );
- }
- fclose( $f );
-
- return;
- } elseif ( $this->hasOption( 'modified' ) ) {
- $this->output( "Retrieving list from Git... " );
- $files = $this->getGitModifiedFiles( $IP );
- $this->output( "done\n" );
- foreach ( $files as $file ) {
- if ( $this->isSuitableFile( $file ) && !is_dir( $file ) ) {
- $this->mFiles[] = $file;
- }
- }
-
- return;
- }
-
- $this->output( 'Building file list...', 'listfiles' );
-
- // Only check files in these directories.
- // Don't just put $IP, because the recursive dir thingie goes into all subdirs
- $dirs = [
- $IP . '/includes',
- $IP . '/mw-config',
- $IP . '/languages',
- $IP . '/maintenance',
- $IP . '/skins',
- ];
- if ( $this->hasOption( 'with-extensions' ) ) {
- $dirs[] = $IP . '/extensions';
- }
-
- foreach ( $dirs as $d ) {
- $this->addDirectoryContent( $d );
- }
-
- // Manually add two user-editable files that are usually sources of problems
- if ( file_exists( "$IP/LocalSettings.php" ) ) {
- $this->mFiles[] = "$IP/LocalSettings.php";
- }
-
- $this->output( 'done.', 'listfiles' );
- }
-
- /**
- * Returns a list of tracked files in a Git work tree differing from the master branch.
- * @param string $path Path to the repository
- * @return array Resulting list of changed files
- */
- private function getGitModifiedFiles( $path ) {
- global $wgMaxShellMemory;
-
- if ( !is_dir( "$path/.git" ) ) {
- $this->error( "Error: Not a Git repository!\n", true );
- }
-
- // git diff eats memory.
- $oldMaxShellMemory = $wgMaxShellMemory;
- if ( $wgMaxShellMemory < 1024000 ) {
- $wgMaxShellMemory = 1024000;
- }
-
- $ePath = wfEscapeShellArg( $path );
-
- // Find an ancestor in common with master (rather than just using its HEAD)
- // to prevent files only modified there from showing up in the list.
- $cmd = "cd $ePath && git merge-base master HEAD";
- $retval = 0;
- $output = wfShellExec( $cmd, $retval );
- if ( $retval !== 0 ) {
- $this->error( "Error retrieving base SHA1 from Git!\n", true );
- }
-
- // Find files in the working tree that changed since then.
- $eBase = wfEscapeShellArg( rtrim( $output, "\n" ) );
- $cmd = "cd $ePath && git diff --name-only --diff-filter AM $eBase";
- $retval = 0;
- $output = wfShellExec( $cmd, $retval );
- if ( $retval !== 0 ) {
- $this->error( "Error retrieving list from Git!\n", true );
- }
-
- $wgMaxShellMemory = $oldMaxShellMemory;
-
- $arr = [];
- $filename = strtok( $output, "\n" );
- while ( $filename !== false ) {
- if ( $filename !== '' ) {
- $arr[] = "$path/$filename";
- }
- $filename = strtok( "\n" );
- }
-
- return $arr;
- }
-
- /**
- * Returns true if $file is of a type we can check
- * @param string $file
- * @return bool
- */
- private function isSuitableFile( $file ) {
- $file = str_replace( '\\', '/', $file );
- $ext = pathinfo( $file, PATHINFO_EXTENSION );
- if ( $ext != 'php' && $ext != 'inc' && $ext != 'php5' ) {
- return false;
- }
- foreach ( $this->mIgnorePaths as $regex ) {
- $m = [];
- if ( preg_match( "~{$regex}~", $file, $m ) ) {
- return false;
- }
- }
-
- return true;
- }
-
- /**
- * Add given path to file list, searching it in include path if needed
- * @param string $path
- * @return bool
- */
- private function addPath( $path ) {
- global $IP;
-
- return $this->addFileOrDir( $path ) || $this->addFileOrDir( "$IP/$path" );
- }
-
- /**
- * Add given file to file list, or, if it's a directory, add its content
- * @param string $path
- * @return bool
- */
- private function addFileOrDir( $path ) {
- if ( is_dir( $path ) ) {
- $this->addDirectoryContent( $path );
- } elseif ( file_exists( $path ) ) {
- $this->mFiles[] = $path;
- } else {
- return false;
- }
-
- return true;
- }
-
- /**
- * Add all suitable files in given directory or its subdirectories to the file list
- *
- * @param string $dir Directory to process
- */
- private function addDirectoryContent( $dir ) {
- $iterator = new RecursiveIteratorIterator(
- new RecursiveDirectoryIterator( $dir ),
- RecursiveIteratorIterator::SELF_FIRST
- );
- foreach ( $iterator as $file ) {
- if ( $this->isSuitableFile( $file->getRealPath() ) ) {
- $this->mFiles[] = $file->getRealPath();
- }
- }
- }
-
- /**
- * Check a file for syntax errors using php -l
- * @param string $file Path to a file to check for syntax errors
- * @return bool
- */
- private function checkFileWithCli( $file ) {
- $res = exec( 'php -l ' . wfEscapeShellArg( $file ) );
- if ( strpos( $res, 'No syntax errors detected' ) === false ) {
- $this->mFailures[$file] = $res;
- $this->output( $res . "\n" );
-
- return false;
- }
-
- return true;
- }
-
- /**
- * Check a file for non-fatal coding errors, such as byte-order marks in the beginning
- * or pointless ?> closing tags at the end.
- *
- * @param string $file String Path to a file to check for errors
- */
- private function checkForMistakes( $file ) {
- foreach ( $this->mNoStyleCheckPaths as $regex ) {
- $m = [];
- if ( preg_match( "~{$regex}~", $file, $m ) ) {
- return;
- }
- }
-
- $text = file_get_contents( $file );
- $tokens = token_get_all( $text );
-
- $this->checkEvilToken( $file, $tokens, '@', 'Error supression operator (@)' );
- $this->checkRegex( $file, $text, '/^[\s\r\n]+<\?/', 'leading whitespace' );
- $this->checkRegex( $file, $text, '/\?>[\s\r\n]*$/', 'trailing ?>' );
- $this->checkRegex( $file, $text, '/^[\xFF\xFE\xEF]/', 'byte-order mark' );
- }
-
- private function checkRegex( $file, $text, $regex, $desc ) {
- if ( !preg_match( $regex, $text ) ) {
- return;
- }
-
- if ( !isset( $this->mWarnings[$file] ) ) {
- $this->mWarnings[$file] = [];
- }
- $this->mWarnings[$file][] = $desc;
- $this->output( "Warning in file $file: $desc found.\n" );
- }
-
- private function checkEvilToken( $file, $tokens, $evilToken, $desc ) {
- if ( !in_array( $evilToken, $tokens ) ) {
- return;
- }
-
- if ( !isset( $this->mWarnings[$file] ) ) {
- $this->mWarnings[$file] = [];
- }
- $this->mWarnings[$file][] = $desc;
- $this->output( "Warning in file $file: $desc found.\n" );
- }
-}
-
-$maintClass = "CheckSyntax";
-require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/checkUsernames.php b/www/wiki/maintenance/checkUsernames.php
index e6d95477..6c1343aa 100644
--- a/www/wiki/maintenance/checkUsernames.php
+++ b/www/wiki/maintenance/checkUsernames.php
@@ -50,7 +50,7 @@ class CheckUsernames extends Maintenance {
__METHOD__,
[
'ORDER BY' => 'user_id',
- 'LIMIT' => $this->mBatchSize,
+ 'LIMIT' => $this->getBatchSize(),
]
);
@@ -65,5 +65,5 @@ class CheckUsernames extends Maintenance {
}
}
-$maintClass = "CheckUsernames";
+$maintClass = CheckUsernames::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/cleanupAncientTables.php b/www/wiki/maintenance/cleanupAncientTables.php
index add967ad..bcf4af21 100644
--- a/www/wiki/maintenance/cleanupAncientTables.php
+++ b/www/wiki/maintenance/cleanupAncientTables.php
@@ -110,5 +110,5 @@ class CleanupAncientTables extends Maintenance {
}
}
-$maintClass = "CleanupAncientTables";
+$maintClass = CleanupAncientTables::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/cleanupBlocks.php b/www/wiki/maintenance/cleanupBlocks.php
index 7a3034fb..cbf00841 100644
--- a/www/wiki/maintenance/cleanupBlocks.php
+++ b/www/wiki/maintenance/cleanupBlocks.php
@@ -39,12 +39,14 @@ class CleanupBlocks extends Maintenance {
public function execute() {
$db = $this->getDB( DB_MASTER );
+ $blockQuery = Block::getQueryInfo();
$max = $db->selectField( 'ipblocks', 'MAX(ipb_user)' );
// Step 1: Clean up any duplicate user blocks
- for ( $from = 1; $from <= $max; $from += $this->mBatchSize ) {
- $to = min( $max, $from + $this->mBatchSize - 1 );
+ $batchSize = $this->getBatchSize();
+ for ( $from = 1; $from <= $max; $from += $batchSize ) {
+ $to = min( $max, $from + $batchSize - 1 );
$this->output( "Cleaning up duplicate ipb_user ($from-$to of $max)\n" );
$delete = [];
@@ -53,8 +55,8 @@ class CleanupBlocks extends Maintenance {
'ipblocks',
[ 'ipb_user' ],
[
- "ipb_user >= $from",
- "ipb_user <= $to",
+ "ipb_user >= " . (int)$from,
+ "ipb_user <= " . (int)$to,
],
__METHOD__,
[
@@ -65,11 +67,14 @@ class CleanupBlocks extends Maintenance {
foreach ( $res as $row ) {
$bestBlock = null;
$res2 = $db->select(
- 'ipblocks',
- '*',
+ $blockQuery['tables'],
+ $blockQuery['fields'],
[
'ipb_user' => $row->ipb_user,
- ]
+ ],
+ __METHOD__,
+ [],
+ $blockQuery['joins']
);
foreach ( $res2 as $row2 ) {
$block = Block::newFromRow( $row2 );
@@ -114,8 +119,8 @@ class CleanupBlocks extends Maintenance {
}
// Step 2: Update the user name in any blocks where it doesn't match
- for ( $from = 1; $from <= $max; $from += $this->mBatchSize ) {
- $to = min( $max, $from + $this->mBatchSize - 1 );
+ for ( $from = 1; $from <= $max; $from += $batchSize ) {
+ $to = min( $max, $from + $batchSize - 1 );
$this->output( "Cleaning up mismatched user name ($from-$to of $max)\n" );
$res = $db->select(
@@ -123,8 +128,8 @@ class CleanupBlocks extends Maintenance {
[ 'ipb_id', 'user_name' ],
[
'ipb_user = user_id',
- "ipb_user >= $from",
- "ipb_user <= $to",
+ "ipb_user >= " . (int)$from,
+ "ipb_user <= " . (int)$to,
'ipb_address != user_name',
],
__METHOD__
@@ -143,5 +148,5 @@ class CleanupBlocks extends Maintenance {
}
}
-$maintClass = "CleanupBlocks";
+$maintClass = CleanupBlocks::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/cleanupCaps.php b/www/wiki/maintenance/cleanupCaps.php
index 2da45ca1..546825bf 100644
--- a/www/wiki/maintenance/cleanupCaps.php
+++ b/www/wiki/maintenance/cleanupCaps.php
@@ -169,5 +169,5 @@ class CapsCleanup extends TableCleanup {
}
}
-$maintClass = "CapsCleanup";
+$maintClass = CapsCleanup::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/cleanupEmptyCategories.php b/www/wiki/maintenance/cleanupEmptyCategories.php
index 86722238..786c20a5 100644
--- a/www/wiki/maintenance/cleanupEmptyCategories.php
+++ b/www/wiki/maintenance/cleanupEmptyCategories.php
@@ -109,7 +109,7 @@ TEXT
__METHOD__,
[
'ORDER BY' => 'page_title',
- 'LIMIT' => $this->mBatchSize,
+ 'LIMIT' => $this->getBatchSize(),
],
[
'category' => [ 'LEFT JOIN', 'page_title = cat_title' ],
@@ -161,7 +161,7 @@ TEXT
__METHOD__,
[
'ORDER BY' => 'cat_title',
- 'LIMIT' => $this->mBatchSize,
+ 'LIMIT' => $this->getBatchSize(),
],
[
'page' => [ 'LEFT JOIN', [
@@ -199,5 +199,5 @@ TEXT
}
}
-$maintClass = 'CleanupEmptyCategories';
+$maintClass = CleanupEmptyCategories::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/cleanupImages.php b/www/wiki/maintenance/cleanupImages.php
index e0da027f..fbdc7c20 100644
--- a/www/wiki/maintenance/cleanupImages.php
+++ b/www/wiki/maintenance/cleanupImages.php
@@ -220,5 +220,5 @@ class ImageCleanup extends TableCleanup {
}
}
-$maintClass = "ImageCleanup";
+$maintClass = ImageCleanup::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/cleanupInvalidDbKeys.php b/www/wiki/maintenance/cleanupInvalidDbKeys.php
index b487f896..54ed3aad 100644
--- a/www/wiki/maintenance/cleanupInvalidDbKeys.php
+++ b/www/wiki/maintenance/cleanupInvalidDbKeys.php
@@ -161,7 +161,7 @@ TEXT
$titleField . $dbr->buildLike( $percent, '_' ),
], LIST_OR ) ],
__METHOD__,
- [ 'LIMIT' => $this->mBatchSize ]
+ [ 'LIMIT' => $this->getBatchSize() ]
);
$this->outputStatus( "Number of invalid rows: " . $res->numRows() . "\n" );
@@ -307,5 +307,5 @@ TEXT
}
}
-$maintClass = 'CleanupInvalidDbKeys';
+$maintClass = CleanupInvalidDbKeys::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/cleanupPreferences.php b/www/wiki/maintenance/cleanupPreferences.php
index 6e58ae97..b24d72dd 100644
--- a/www/wiki/maintenance/cleanupPreferences.php
+++ b/www/wiki/maintenance/cleanupPreferences.php
@@ -1,6 +1,6 @@
<?php
/**
- * Remove hidden preferences from the database.
+ * Clean up user preferences from the database.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -19,6 +19,7 @@
*
* @file
* @author TyA <tya.wiki@gmail.com>
+ * @author Chad <chad@wikimedia.org>
* @see https://phabricator.wikimedia.org/T32976
* @ingroup Maintenance
*/
@@ -26,27 +27,131 @@
require_once __DIR__ . '/Maintenance.php';
/**
- * Maintenance script that removes hidden preferences from the database.
+ * Maintenance script that removes bogus preferences from the database.
*
* @ingroup Maintenance
*/
class CleanupPreferences extends Maintenance {
+ public function __construct() {
+ parent::__construct();
+ $this->mDescription = 'Clean up hidden preferences, removed preferences, and normalizes values';
+ $this->setBatchSize( 50 );
+ $this->addOption( 'dry-run', 'Print debug info instead of actually deleting' );
+ $this->addOption( 'hidden', 'Drop hidden preferences ($wgHiddenPrefs)' );
+ $this->addOption( 'unknown',
+ 'Drop unknown preferences (not in $wgDefaultUserOptions or prefixed with "userjs-")' );
+ // TODO: actually implement this
+ // $this->addOption( 'bogus', 'Drop preferences that have invalid/unaccepted values' );
+ }
+
+ /**
+ * We will do this in three passes
+ * 1) The easiest is to drop the hidden preferences from the database. We
+ * don't actually want them
+ * 2) Drop preference keys that we don't know about. They could've been
+ * removed from core, provided by a now-disabled extension, or the result
+ * of a bug. We don't want them.
+ * 3) TODO: Normalize accepted preference values. This is the biggest part of the work.
+ * For each preference we know about, iterate over it and if it's got a
+ * limited set of accepted values (so it's not text, basically), make sure
+ * all values are in that range. Drop ones that aren't.
+ */
public function execute() {
- global $wgHiddenPrefs;
+ global $wgHiddenPrefs, $wgDefaultUserOptions;
$dbw = $this->getDB( DB_MASTER );
- $this->beginTransaction( $dbw, __METHOD__ );
- foreach ( $wgHiddenPrefs as $item ) {
- $dbw->delete(
+ $didWork = false;
+ $hidden = $this->hasOption( 'hidden' );
+ $unknown = $this->hasOption( 'unknown' );
+ $bogus = $this->hasOption( 'bogus' );
+
+ if ( !$hidden && !$unknown && !$bogus ) {
+ $this->output( "Did not select one of --hidden, --unknown or --bogus, exiting\n" );
+ return;
+ }
+
+ // Remove hidden prefs. Iterate over them to avoid the IN on a large table
+ if ( $hidden ) {
+ if ( !$wgHiddenPrefs ) {
+ $this->output( "No hidden preferences, skipping\n" );
+ }
+ foreach ( $wgHiddenPrefs as $hiddenPref ) {
+ $this->deleteByWhere(
+ $dbw,
+ 'Dropping hidden preferences',
+ [ 'up_property' => $hiddenPref ]
+ );
+ }
+ }
+
+ // Remove unknown preferences. Special-case 'userjs-' as we can't control those names.
+ if ( $unknown ) {
+ $where = [
+ 'up_property NOT' . $dbw->buildLike( 'userjs-', $dbw->anyString() ),
+ 'up_property NOT IN (' . $dbw->makeList( array_keys( $wgDefaultUserOptions ) ) . ')',
+ ];
+ // Allow extensions to add to the where clause to prevent deletion of their own prefs.
+ Hooks::run( 'DeleteUnknownPreferences', [ &$where, $dbw ] );
+ $this->deleteByWhere( $dbw, 'Dropping unknown preferences', $where );
+ }
+
+ // Something something phase 3
+ if ( $bogus ) {
+ }
+ }
+
+ /**
+ *
+ */
+ private function deleteByWhere( $dbw, $startMessage, $where ) {
+ $this->output( $startMessage . "...\n" );
+ $total = 0;
+ while ( true ) {
+ $res = $dbw->select(
'user_properties',
- [ 'up_property' => $item ],
- __METHOD__
+ '*', // The table lacks a primary key, so select the whole row
+ $where,
+ __METHOD__,
+ [ 'LIMIT' => $this->mBatchSize ]
);
- };
- $this->commitTransaction( $dbw, __METHOD__ );
- $this->output( "Finished!\n" );
+
+ $numRows = $res->numRows();
+ $total += $numRows;
+ if ( $res->numRows() <= 0 ) {
+ // All done!
+ $this->output( "DONE! (handled $total entries)\n" );
+ break;
+ }
+
+ // Progress or something
+ $this->output( "..doing $numRows entries\n" );
+
+ // Delete our batch, then wait
+ foreach ( $res as $row ) {
+ if ( $this->hasOption( 'dry-run' ) ) {
+ $this->output(
+ " DRY RUN, would drop: " .
+ "[up_user] => '{$row->up_user}' " .
+ "[up_property] => '{$row->up_property}' " .
+ "[up_value] => '{$row->up_value}'\n"
+ );
+ continue;
+ }
+ $this->beginTransaction( $dbw, __METHOD__ );
+ $dbw->delete(
+ 'user_properties',
+ [
+ 'up_user' => $row->up_user,
+ 'up_property' => $row->up_property,
+ 'up_value' => $row->up_value,
+ ],
+ __METHOD__
+ );
+ $this->commitTransaction( $dbw, __METHOD__ );
+ }
+ }
}
}
-$maintClass = 'CleanupPreferences'; // Tells it to run the class
+$maintClass = CleanupPreferences::class; // Tells it to run the class
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/cleanupRemovedModules.php b/www/wiki/maintenance/cleanupRemovedModules.php
index dbaf6438..63838d25 100644
--- a/www/wiki/maintenance/cleanupRemovedModules.php
+++ b/www/wiki/maintenance/cleanupRemovedModules.php
@@ -57,7 +57,7 @@ class CleanupRemovedModules extends Maintenance {
$modDeps = $dbw->tableName( 'module_deps' );
$i = 1;
- foreach ( array_chunk( $rows, $this->mBatchSize ) as $chunk ) {
+ foreach ( array_chunk( $rows, $this->getBatchSize() ) as $chunk ) {
// WHERE ( mod=A AND skin=A ) OR ( mod=A AND skin=B) ..
$conds = array_map( function ( stdClass $row ) use ( $dbw ) {
return $dbw->makeList( (array)$row, IDatabase::LIST_AND );
@@ -77,5 +77,5 @@ class CleanupRemovedModules extends Maintenance {
}
}
-$maintClass = 'CleanupRemovedModules';
+$maintClass = CleanupRemovedModules::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/cleanupSpam.php b/www/wiki/maintenance/cleanupSpam.php
index 4e47cfba..038b28ce 100644
--- a/www/wiki/maintenance/cleanupSpam.php
+++ b/www/wiki/maintenance/cleanupSpam.php
@@ -47,16 +47,15 @@ class CleanupSpam extends Maintenance {
$username = wfMessage( 'spambot_username' )->text();
$wgUser = User::newSystemUser( $username );
if ( !$wgUser ) {
- $this->error( "Invalid username specified in 'spambot_username' message: $username", true );
- }
- // Create the user if necessary
- if ( !$wgUser->getId() ) {
- $wgUser->addToDatabase();
+ $this->fatalError( "Invalid username specified in 'spambot_username' message: $username" );
}
+ // Hack: Grant bot rights so we don't flood RecentChanges
+ $wgUser->addGroup( 'bot' );
+
$spec = $this->getArg();
$like = LinkFilter::makeLikeArray( $spec );
if ( !$like ) {
- $this->error( "Not a valid hostname specification: $spec", true );
+ $this->fatalError( "Not a valid hostname specification: $spec" );
}
if ( $this->hasOption( 'all' ) ) {
@@ -131,7 +130,7 @@ class CleanupSpam extends Maintenance {
$page->doEditContent(
$content,
wfMessage( 'spam_reverting', $domain )->inContentLanguage()->text(),
- EDIT_UPDATE,
+ EDIT_UPDATE | EDIT_FORCE_BOT,
$rev->getId()
);
} elseif ( $this->hasOption( 'delete' ) ) {
@@ -148,7 +147,8 @@ class CleanupSpam extends Maintenance {
$this->output( "blanking\n" );
$page->doEditContent(
$content,
- wfMessage( 'spam_blanking', $domain )->inContentLanguage()->text()
+ wfMessage( 'spam_blanking', $domain )->inContentLanguage()->text(),
+ EDIT_UPDATE | EDIT_FORCE_BOT
);
}
$this->commitTransaction( $dbw, __METHOD__ );
@@ -156,5 +156,5 @@ class CleanupSpam extends Maintenance {
}
}
-$maintClass = "CleanupSpam";
+$maintClass = CleanupSpam::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/cleanupTitles.php b/www/wiki/maintenance/cleanupTitles.php
index 50e17d8d..5b441f90 100644
--- a/www/wiki/maintenance/cleanupTitles.php
+++ b/www/wiki/maintenance/cleanupTitles.php
@@ -137,7 +137,8 @@ class TitleCleanup extends TableCleanup {
|| $title->getInterwiki()
|| !$title->canExist()
) {
- if ( $title->getInterwiki() || !$title->canExist() ) {
+ $titleImpossible = $title->getInterwiki() || !$title->canExist();
+ if ( $titleImpossible ) {
$prior = $title->getPrefixedDBkey();
} else {
$prior = $title->getDBkey();
@@ -155,7 +156,12 @@ class TitleCleanup extends TableCleanup {
$ns = 0;
}
- $clean = 'Broken/' . $prior;
+ if ( !$titleImpossible && !$title->exists() ) {
+ // Looks like the current title, after cleaning it up, is valid and available
+ $clean = $prior;
+ } else {
+ $clean = 'Broken/' . $prior;
+ }
$verified = Title::makeTitleSafe( $ns, $clean );
if ( !$verified || $verified->exists() ) {
$blah = "Broken/id:" . $row->page_id;
@@ -165,7 +171,7 @@ class TitleCleanup extends TableCleanup {
$title = $verified;
}
if ( is_null( $title ) ) {
- $this->error( "Something awry; empty title.", true );
+ $this->fatalError( "Something awry; empty title." );
}
$ns = $title->getNamespace();
$dest = $title->getDBkey();
@@ -189,5 +195,5 @@ class TitleCleanup extends TableCleanup {
}
}
-$maintClass = "TitleCleanup";
+$maintClass = TitleCleanup::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/cleanupUploadStash.php b/www/wiki/maintenance/cleanupUploadStash.php
index 95bbe3d3..61cd9c24 100644
--- a/www/wiki/maintenance/cleanupUploadStash.php
+++ b/www/wiki/maintenance/cleanupUploadStash.php
@@ -103,7 +103,7 @@ class UploadStashCleanup extends Maintenance {
foreach ( $iterator as $file ) {
if ( wfTimestamp( TS_UNIX, $tempRepo->getFileTimestamp( "$dir/$file" ) ) < $cutoff ) {
$batch[] = [ 'op' => 'delete', 'src' => "$dir/$file" ];
- if ( count( $batch ) >= $this->mBatchSize ) {
+ if ( count( $batch ) >= $this->getBatchSize() ) {
$this->doOperations( $tempRepo, $batch );
$i += count( $batch );
$batch = [];
@@ -122,14 +122,14 @@ class UploadStashCleanup extends Maintenance {
$iterator = $tempRepo->getBackend()->getFileList( [ 'dir' => $dir, 'adviseStat' => 1 ] );
$this->output( "Deleting orphaned temp files...\n" );
if ( strpos( $dir, '/local-temp' ) === false ) { // sanity check
- $this->error( "Temp repo is not using the temp container.", 1 ); // die
+ $this->fatalError( "Temp repo is not using the temp container." );
}
$i = 0;
$batch = []; // operation batch
foreach ( $iterator as $file ) {
if ( wfTimestamp( TS_UNIX, $tempRepo->getFileTimestamp( "$dir/$file" ) ) < $cutoff ) {
$batch[] = [ 'op' => 'delete', 'src' => "$dir/$file" ];
- if ( count( $batch ) >= $this->mBatchSize ) {
+ if ( count( $batch ) >= $this->getBatchSize() ) {
$this->doOperations( $tempRepo, $batch );
$i += count( $batch );
$batch = [];
@@ -152,5 +152,5 @@ class UploadStashCleanup extends Maintenance {
}
}
-$maintClass = "UploadStashCleanup";
+$maintClass = UploadStashCleanup::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/cleanupUsersWithNoId.php b/www/wiki/maintenance/cleanupUsersWithNoId.php
new file mode 100644
index 00000000..b2fdf2f9
--- /dev/null
+++ b/www/wiki/maintenance/cleanupUsersWithNoId.php
@@ -0,0 +1,212 @@
+<?php
+/**
+ * Cleanup tables that have valid usernames with no user ID
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Maintenance
+ */
+
+use Wikimedia\Rdbms\IDatabase;
+
+require_once __DIR__ . '/Maintenance.php';
+
+/**
+ * Maintenance script that cleans up tables that have valid usernames with no
+ * user ID.
+ *
+ * @ingroup Maintenance
+ * @since 1.31
+ */
+class CleanupUsersWithNoId extends LoggedUpdateMaintenance {
+ private $prefix, $table, $assign;
+ private $triedCreations = [];
+
+ public function __construct() {
+ parent::__construct();
+ $this->addDescription( 'Cleans up tables that have valid usernames with no user ID' );
+ $this->addOption( 'prefix', 'Interwiki prefix to apply to the usernames', true, true, 'p' );
+ $this->addOption( 'table', 'Only clean up this table', false, true );
+ $this->addOption( 'assign', 'Assign edits to existing local users if they exist', false, false );
+ $this->setBatchSize( 100 );
+ }
+
+ protected function getUpdateKey() {
+ return __CLASS__;
+ }
+
+ protected function doDBUpdates() {
+ $this->prefix = $this->getOption( 'prefix' );
+ $this->table = $this->getOption( 'table', null );
+ $this->assign = $this->getOption( 'assign' );
+
+ $this->cleanup(
+ 'revision', 'rev_id', 'rev_user', 'rev_user_text',
+ [ 'rev_user' => 0 ], [ 'rev_timestamp', 'rev_id' ]
+ );
+ $this->cleanup(
+ 'archive', 'ar_id', 'ar_user', 'ar_user_text',
+ [], [ 'ar_id' ]
+ );
+ $this->cleanup(
+ 'logging', 'log_id', 'log_user', 'log_user_text',
+ [ 'log_user' => 0 ], [ 'log_timestamp', 'log_id' ]
+ );
+ $this->cleanup(
+ 'image', 'img_name', 'img_user', 'img_user_text',
+ [ 'img_user' => 0 ], [ 'img_timestamp', 'img_name' ]
+ );
+ $this->cleanup(
+ 'oldimage', [ 'oi_name', 'oi_timestamp' ], 'oi_user', 'oi_user_text',
+ [], [ 'oi_name', 'oi_timestamp' ]
+ );
+ $this->cleanup(
+ 'filearchive', 'fa_id', 'fa_user', 'fa_user_text',
+ [], [ 'fa_id' ]
+ );
+ $this->cleanup(
+ 'ipblocks', 'ipb_id', 'ipb_by', 'ipb_by_text',
+ [], [ 'ipb_id' ]
+ );
+ $this->cleanup(
+ 'recentchanges', 'rc_id', 'rc_user', 'rc_user_text',
+ [], [ 'rc_id' ]
+ );
+
+ return true;
+ }
+
+ /**
+ * Calculate a "next" condition and progress display string
+ * @param IDatabase $dbw
+ * @param string[] $indexFields Fields in the index being ordered by
+ * @param object $row Database row
+ * @return array [ string $next, string $display ]
+ */
+ private function makeNextCond( $dbw, $indexFields, $row ) {
+ $next = '';
+ $display = [];
+ for ( $i = count( $indexFields ) - 1; $i >= 0; $i-- ) {
+ $field = $indexFields[$i];
+ $display[] = $field . '=' . $row->$field;
+ $value = $dbw->addQuotes( $row->$field );
+ if ( $next === '' ) {
+ $next = "$field > $value";
+ } else {
+ $next = "$field > $value OR $field = $value AND ($next)";
+ }
+ }
+ $display = implode( ' ', array_reverse( $display ) );
+ return [ $next, $display ];
+ }
+
+ /**
+ * Cleanup a table
+ *
+ * @param string $table Table to migrate
+ * @param string|string[] $primaryKey Primary key of the table.
+ * @param string $idField User ID field name
+ * @param string $nameField User name field name
+ * @param array $conds Query conditions
+ * @param string[] $orderby Fields to order by
+ */
+ protected function cleanup(
+ $table, $primaryKey, $idField, $nameField, array $conds, array $orderby
+ ) {
+ if ( $this->table !== null && $this->table !== $table ) {
+ return;
+ }
+
+ $primaryKey = (array)$primaryKey;
+ $pkFilter = array_flip( $primaryKey );
+ $this->output(
+ "Beginning cleanup of $table\n"
+ );
+
+ $dbw = $this->getDB( DB_MASTER );
+ $next = '1=1';
+ $countAssigned = 0;
+ $countPrefixed = 0;
+ while ( true ) {
+ // Fetch the rows needing update
+ $res = $dbw->select(
+ $table,
+ array_merge( $primaryKey, [ $idField, $nameField ], $orderby ),
+ array_merge( $conds, [ $next ] ),
+ __METHOD__,
+ [
+ 'ORDER BY' => $orderby,
+ 'LIMIT' => $this->mBatchSize,
+ ]
+ );
+ if ( !$res->numRows() ) {
+ break;
+ }
+
+ // Update the existing rows
+ foreach ( $res as $row ) {
+ $name = $row->$nameField;
+ if ( $row->$idField || !User::isUsableName( $name ) ) {
+ continue;
+ }
+
+ $id = 0;
+ if ( $this->assign ) {
+ $id = (int)User::idFromName( $name );
+ if ( !$id ) {
+ // See if any extension wants to create it.
+ if ( !isset( $this->triedCreations[$name] ) ) {
+ $this->triedCreations[$name] = true;
+ if ( !Hooks::run( 'ImportHandleUnknownUser', [ $name ] ) ) {
+ $id = (int)User::idFromName( $name, User::READ_LATEST );
+ }
+ }
+ }
+ }
+ if ( $id ) {
+ $set = [ $idField => $id ];
+ $counter = &$countAssigned;
+ } else {
+ $set = [ $nameField => substr( $this->prefix . '>' . $name, 0, 255 ) ];
+ $counter = &$countPrefixed;
+ }
+
+ $dbw->update(
+ $table,
+ $set,
+ array_intersect_key( (array)$row, $pkFilter ) + [
+ $idField => 0,
+ $nameField => $name,
+ ],
+ __METHOD__
+ );
+ $counter += $dbw->affectedRows();
+ }
+
+ list( $next, $display ) = $this->makeNextCond( $dbw, $orderby, $row );
+ $this->output( "... $display\n" );
+ wfWaitForSlaves();
+ }
+
+ $this->output(
+ "Completed cleanup, assigned $countAssigned and prefixed $countPrefixed row(s)\n"
+ );
+ }
+}
+
+$maintClass = CleanupUsersWithNoId::class;
+require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/cleanupWatchlist.php b/www/wiki/maintenance/cleanupWatchlist.php
index 9728ac5d..64d39dd6 100644
--- a/www/wiki/maintenance/cleanupWatchlist.php
+++ b/www/wiki/maintenance/cleanupWatchlist.php
@@ -95,5 +95,5 @@ class WatchlistCleanup extends TableCleanup {
}
}
-$maintClass = "WatchlistCleanup";
+$maintClass = WatchlistCleanup::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/clearInterwikiCache.php b/www/wiki/maintenance/clearInterwikiCache.php
index ce19974e..8579f0f4 100644
--- a/www/wiki/maintenance/clearInterwikiCache.php
+++ b/www/wiki/maintenance/clearInterwikiCache.php
@@ -38,7 +38,7 @@ class ClearInterwikiCache extends Maintenance {
public function execute() {
global $wgLocalDatabases, $wgMemc;
$dbr = $this->getDB( DB_REPLICA );
- $res = $dbr->select( 'interwiki', [ 'iw_prefix' ], false );
+ $res = $dbr->select( 'interwiki', [ 'iw_prefix' ], '', __METHOD__ );
$prefixes = [];
foreach ( $res as $row ) {
$prefixes[] = $row->iw_prefix;
@@ -54,5 +54,5 @@ class ClearInterwikiCache extends Maintenance {
}
}
-$maintClass = "ClearInterwikiCache";
+$maintClass = ClearInterwikiCache::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/commandLine.inc b/www/wiki/maintenance/commandLine.inc
index 206e0467..8232d529 100644
--- a/www/wiki/maintenance/commandLine.inc
+++ b/www/wiki/maintenance/commandLine.inc
@@ -23,10 +23,9 @@
require_once __DIR__ . '/Maintenance.php';
-// @codingStandardsIgnoreStart MediaWiki.NamingConventions.ValidGlobalName.wgPrefix
-global $optionsWithArgs;
-global $optionsWithoutArgs;
-// @codingStandardsIgnoreEnd
+// phpcs:ignore MediaWiki.NamingConventions.ValidGlobalName.wgPrefix
+global $optionsWithArgs, $optionsWithoutArgs;
+
if ( !isset( $optionsWithArgs ) ) {
$optionsWithArgs = [];
}
@@ -36,9 +35,9 @@ if ( !isset( $optionsWithoutArgs ) ) {
class CommandLineInc extends Maintenance {
public function __construct() {
- // @codingStandardsIgnoreStart MediaWiki.NamingConventions.ValidGlobalName.wgPrefix
+ // phpcs:ignore MediaWiki.NamingConventions.ValidGlobalName.wgPrefix
global $optionsWithArgs, $optionsWithoutArgs;
- // @codingStandardsIgnoreEnd
+
parent::__construct();
foreach ( $optionsWithArgs as $name ) {
$this->addOption( $name, '', false, true );
@@ -60,13 +59,13 @@ class CommandLineInc extends Maintenance {
}
public function execute() {
- // @codingStandardsIgnoreStart MediaWiki.NamingConventions.ValidGlobalName.wgPrefix
+ // phpcs:ignore MediaWiki.NamingConventions.ValidGlobalName.wgPrefix
global $args, $options;
- // @codingStandardsIgnoreEnd
+
$args = $this->mArgs;
$options = $this->mOptions;
}
}
-$maintClass = 'CommandLineInc';
+$maintClass = CommandLineInc::class;
require RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/compareParserCache.php b/www/wiki/maintenance/compareParserCache.php
index 504c7d7a..b12974b0 100644
--- a/www/wiki/maintenance/compareParserCache.php
+++ b/www/wiki/maintenance/compareParserCache.php
@@ -45,7 +45,12 @@ class CompareParserCache extends Maintenance {
$withdiff = 0;
$parserCache = MediaWikiServices::getInstance()->getParserCache();
while ( $pages-- > 0 ) {
- $row = $dbr->selectRow( 'page', '*',
+ $row = $dbr->selectRow( 'page',
+ // @todo Title::selectFields() or Title::getQueryInfo() or something
+ [
+ 'page_namespace', 'page_title', 'page_id',
+ 'page_len', 'page_is_redirect', 'page_latest',
+ ],
[
'page_namespace' => $this->getOption( 'namespace' ),
'page_is_redirect' => 0,
@@ -103,5 +108,5 @@ class CompareParserCache extends Maintenance {
}
}
-$maintClass = "CompareParserCache";
+$maintClass = CompareParserCache::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/compareParsers.php b/www/wiki/maintenance/compareParsers.php
index f2540c7a..fe6e604d 100644
--- a/www/wiki/maintenance/compareParsers.php
+++ b/www/wiki/maintenance/compareParsers.php
@@ -97,7 +97,7 @@ class CompareParsers extends DumpIterator {
if ( $this->hasOption( 'tidy' ) ) {
global $wgUseTidy;
if ( !$wgUseTidy ) {
- $this->error( 'Tidy was requested but $wgUseTidy is not set in LocalSettings.php', true );
+ $this->fatalError( 'Tidy was requested but $wgUseTidy is not set in LocalSettings.php' );
}
$this->options->setTidy( true );
}
@@ -185,5 +185,5 @@ class CompareParsers extends DumpIterator {
}
}
-$maintClass = "CompareParsers";
+$maintClass = CompareParsers::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/convertExtensionToRegistration.php b/www/wiki/maintenance/convertExtensionToRegistration.php
index 05549495..4ae95587 100644
--- a/www/wiki/maintenance/convertExtensionToRegistration.php
+++ b/www/wiki/maintenance/convertExtensionToRegistration.php
@@ -63,7 +63,7 @@ class ConvertExtensionToRegistration extends Maintenance {
}
protected function getAllGlobals() {
- $processor = new ReflectionClass( 'ExtensionProcessor' );
+ $processor = new ReflectionClass( ExtensionProcessor::class );
$settings = $processor->getProperty( 'globalSettings' );
$settings->setAccessible( true );
return array_merge( $settings->getValue(), $this->formerGlobals );
@@ -82,7 +82,7 @@ class ConvertExtensionToRegistration extends Maintenance {
unset( $var );
$arg = $this->getArg( 0 );
if ( !is_file( $arg ) ) {
- $this->error( "$arg is not a file.", true );
+ $this->fatalError( "$arg is not a file." );
}
require $arg;
unset( $arg );
@@ -144,6 +144,11 @@ class ConvertExtensionToRegistration extends Maintenance {
unset( $this->json[$key] );
}
}
+ // Set a requirement on the MediaWiki version that the current MANIFEST_VERSION
+ // was introduced in.
+ $out['requires'] = [
+ ExtensionRegistry::MEDIAWIKI_CORE => ExtensionRegistry::MANIFEST_VERSION_MW_VERSION
+ ];
$out += $this->json;
// Put this at the bottom
$out['manifest_version'] = ExtensionRegistry::MANIFEST_VERSION;
@@ -160,14 +165,14 @@ class ConvertExtensionToRegistration extends Maintenance {
protected function handleExtensionFunctions( $realName, $value ) {
foreach ( $value as $func ) {
if ( $func instanceof Closure ) {
- $this->error( "Error: Closures cannot be converted to JSON. " .
- "Please move your extension function somewhere else.", 1
+ $this->fatalError( "Error: Closures cannot be converted to JSON. " .
+ "Please move your extension function somewhere else."
);
}
// check if $func exists in the global scope
if ( function_exists( $func ) ) {
- $this->error( "Error: Global functions cannot be converted to JSON. " .
- "Please move your extension function ($func) into a class.", 1
+ $this->fatalError( "Error: Global functions cannot be converted to JSON. " .
+ "Please move your extension function ($func) into a class."
);
}
}
@@ -239,14 +244,14 @@ class ConvertExtensionToRegistration extends Maintenance {
}
foreach ( $handlers as $func ) {
if ( $func instanceof Closure ) {
- $this->error( "Error: Closures cannot be converted to JSON. " .
- "Please move the handler for $hookName somewhere else.", 1
+ $this->fatalError( "Error: Closures cannot be converted to JSON. " .
+ "Please move the handler for $hookName somewhere else."
);
}
// Check if $func exists in the global scope
if ( function_exists( $func ) ) {
- $this->error( "Error: Global functions cannot be converted to JSON. " .
- "Please move the handler for $hookName inside a class.", 1
+ $this->fatalError( "Error: Global functions cannot be converted to JSON. " .
+ "Please move the handler for $hookName inside a class."
);
}
}
@@ -303,5 +308,5 @@ class ConvertExtensionToRegistration extends Maintenance {
}
}
-$maintClass = 'ConvertExtensionToRegistration';
+$maintClass = ConvertExtensionToRegistration::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/convertLinks.php b/www/wiki/maintenance/convertLinks.php
index 54c0edae..8cd02976 100644
--- a/www/wiki/maintenance/convertLinks.php
+++ b/www/wiki/maintenance/convertLinks.php
@@ -302,5 +302,5 @@ class ConvertLinks extends Maintenance {
}
}
-$maintClass = "ConvertLinks";
+$maintClass = ConvertLinks::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/convertUserOptions.php b/www/wiki/maintenance/convertUserOptions.php
index 675d0695..c1a096fd 100644
--- a/www/wiki/maintenance/convertUserOptions.php
+++ b/www/wiki/maintenance/convertUserOptions.php
@@ -61,7 +61,7 @@ class ConvertUserOptions extends Maintenance {
__METHOD__,
[
'ORDER BY' => 'user_id',
- 'LIMIT' => $this->mBatchSize,
+ 'LIMIT' => $this->getBatchSize(),
]
);
$id = $this->convertOptionBatch( $res, $dbw );
@@ -120,5 +120,5 @@ class ConvertUserOptions extends Maintenance {
}
}
-$maintClass = "ConvertUserOptions";
+$maintClass = ConvertUserOptions::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/copyFileBackend.php b/www/wiki/maintenance/copyFileBackend.php
index 4f625fc6..3c7ffba5 100644
--- a/www/wiki/maintenance/copyFileBackend.php
+++ b/www/wiki/maintenance/copyFileBackend.php
@@ -81,7 +81,7 @@ class CopyFileBackend extends Maintenance {
'adviseStat' => true // avoid HEADs
] );
if ( $srcPathsRel === null ) {
- $this->error( "Could not list files in $container.", 1 ); // die
+ $this->fatalError( "Could not list files in $container." );
}
}
@@ -93,7 +93,7 @@ class CopyFileBackend extends Maintenance {
'adviseStat' => true // avoid HEADs
] );
if ( $dstPathsRel === null ) {
- $this->error( "Could not list files in $container.", 1 ); // die
+ $this->fatalError( "Could not list files in $container." );
}
$this->statCache = [];
foreach ( $dstPathsRel as $dstPathRel ) {
@@ -109,11 +109,11 @@ class CopyFileBackend extends Maintenance {
foreach ( $srcPathsRel as $srcPathRel ) {
// Check up on the rate file periodically to adjust the concurrency
if ( $rateFile && ( !$count || ( $count % 500 ) == 0 ) ) {
- $this->mBatchSize = max( 1, (int)file_get_contents( $rateFile ) );
- $this->output( "\tBatch size is now {$this->mBatchSize}.\n" );
+ $this->setBatchSize( max( 1, (int)file_get_contents( $rateFile ) ) );
+ $this->output( "\tBatch size is now {$this->getBatchSize()}.\n" );
}
$batchPaths[$srcPathRel] = 1; // remove duplicates
- if ( count( $batchPaths ) >= $this->mBatchSize ) {
+ if ( count( $batchPaths ) >= $this->getBatchSize() ) {
$this->copyFileBatch( array_keys( $batchPaths ), $backendRel, $src, $dst );
$batchPaths = []; // done
}
@@ -136,11 +136,11 @@ class CopyFileBackend extends Maintenance {
foreach ( $delPathsRel as $delPathRel ) {
// Check up on the rate file periodically to adjust the concurrency
if ( $rateFile && ( !$count || ( $count % 500 ) == 0 ) ) {
- $this->mBatchSize = max( 1, (int)file_get_contents( $rateFile ) );
- $this->output( "\tBatch size is now {$this->mBatchSize}.\n" );
+ $this->setBatchSize( max( 1, (int)file_get_contents( $rateFile ) ) );
+ $this->output( "\tBatch size is now {$this->getBatchSize()}.\n" );
}
$batchPaths[$delPathRel] = 1; // remove duplicates
- if ( count( $batchPaths ) >= $this->mBatchSize ) {
+ if ( count( $batchPaths ) >= $this->getBatchSize() ) {
$this->delFileBatch( array_keys( $batchPaths ), $backendRel, $dst );
$batchPaths = []; // done
}
@@ -174,12 +174,12 @@ class CopyFileBackend extends Maintenance {
$srcPathsRel = $src->getFileList( [
'dir' => $src->getRootStoragePath() . "/$backendRel" ] );
if ( $srcPathsRel === null ) {
- $this->error( "Could not list files in source container.", 1 ); // die
+ $this->fatalError( "Could not list files in source container." );
}
$dstPathsRel = $dst->getFileList( [
'dir' => $dst->getRootStoragePath() . "/$backendRel" ] );
if ( $dstPathsRel === null ) {
- $this->error( "Could not list files in destination container.", 1 ); // die
+ $this->fatalError( "Could not list files in destination container." );
}
// Get the list of destination files
$relFilesDstSha1 = [];
@@ -263,7 +263,7 @@ class CopyFileBackend extends Maintenance {
$status = $dst->prepare( [ 'dir' => dirname( $dstPath ), 'bypassReadOnly' => 1 ] );
if ( !$status->isOK() ) {
$this->error( print_r( $status->getErrorsArray(), true ) );
- $this->error( "$wikiId: Could not copy $srcPath to $dstPath.", 1 ); // die
+ $this->fatalError( "$wikiId: Could not copy $srcPath to $dstPath." );
}
$ops[] = [ 'op' => 'store',
'src' => $fsFile->getPath(), 'dst' => $dstPath, 'overwrite' => 1 ];
@@ -280,7 +280,7 @@ class CopyFileBackend extends Maintenance {
$elapsed_ms = floor( ( microtime( true ) - $t_start ) * 1000 );
if ( !$status->isOK() ) {
$this->error( print_r( $status->getErrorsArray(), true ) );
- $this->error( "$wikiId: Could not copy file batch.", 1 ); // die
+ $this->fatalError( "$wikiId: Could not copy file batch." );
} elseif ( count( $copiedRel ) ) {
$this->output( "\n\tCopied these file(s) [{$elapsed_ms}ms]:\n\t" .
implode( "\n\t", $copiedRel ) . "\n\n" );
@@ -317,7 +317,7 @@ class CopyFileBackend extends Maintenance {
$elapsed_ms = floor( ( microtime( true ) - $t_start ) * 1000 );
if ( !$status->isOK() ) {
$this->error( print_r( $status->getErrorsArray(), true ) );
- $this->error( "$wikiId: Could not delete file batch.", 1 ); // die
+ $this->fatalError( "$wikiId: Could not delete file batch." );
} elseif ( count( $deletedRel ) ) {
$this->output( "\n\tDeleted these file(s) [{$elapsed_ms}ms]:\n\t" .
implode( "\n\t", $deletedRel ) . "\n\n" );
@@ -374,5 +374,5 @@ class CopyFileBackend extends Maintenance {
}
}
-$maintClass = 'CopyFileBackend';
+$maintClass = CopyFileBackend::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/copyJobQueue.php b/www/wiki/maintenance/copyJobQueue.php
index e1d697d8..dc70e9c2 100644
--- a/www/wiki/maintenance/copyJobQueue.php
+++ b/www/wiki/maintenance/copyJobQueue.php
@@ -48,9 +48,9 @@ class CopyJobQueue extends Maintenance {
$dstKey = $this->getOption( 'dst' );
if ( !isset( $wgJobQueueMigrationConfig[$srcKey] ) ) {
- $this->error( "\$wgJobQueueMigrationConfig not set for '$srcKey'.", 1 );
+ $this->fatalError( "\$wgJobQueueMigrationConfig not set for '$srcKey'." );
} elseif ( !isset( $wgJobQueueMigrationConfig[$dstKey] ) ) {
- $this->error( "\$wgJobQueueMigrationConfig not set for '$dstKey'.", 1 );
+ $this->fatalError( "\$wgJobQueueMigrationConfig not set for '$dstKey'." );
}
$types = ( $this->getOption( 'type' ) === 'all' )
@@ -77,7 +77,7 @@ class CopyJobQueue extends Maintenance {
foreach ( $jobs as $job ) {
++$total;
$batch[] = $job;
- if ( count( $batch ) >= $this->mBatchSize ) {
+ if ( count( $batch ) >= $this->getBatchSize() ) {
$dst->push( $batch );
$totalOK += count( $batch );
$batch = [];
@@ -94,5 +94,5 @@ class CopyJobQueue extends Maintenance {
}
}
-$maintClass = 'CopyJobQueue';
+$maintClass = CopyJobQueue::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/createAndPromote.php b/www/wiki/maintenance/createAndPromote.php
index 1872716f..d3efca6f 100644
--- a/www/wiki/maintenance/createAndPromote.php
+++ b/www/wiki/maintenance/createAndPromote.php
@@ -63,15 +63,15 @@ class CreateAndPromote extends Maintenance {
$user = User::newFromName( $username );
if ( !is_object( $user ) ) {
- $this->error( "invalid username.", true );
+ $this->fatalError( "invalid username." );
}
$exists = ( 0 !== $user->idForName() );
if ( $exists && !$force ) {
- $this->error( "Account exists. Perhaps you want the --force option?", true );
+ $this->fatalError( "Account exists. Perhaps you want the --force option?" );
} elseif ( !$exists && !$password ) {
- $this->error( "Argument <password> required!", false );
+ $this->error( "Argument <password> required!" );
$this->maybeHelp( true );
} elseif ( $exists ) {
$inGroups = $user->getGroups();
@@ -133,7 +133,7 @@ class CreateAndPromote extends Maintenance {
$user->saveSettings();
}
} catch ( PasswordError $pwe ) {
- $this->error( $pwe->getText(), true );
+ $this->fatalError( $pwe->getText() );
}
}
@@ -150,5 +150,5 @@ class CreateAndPromote extends Maintenance {
}
}
-$maintClass = "CreateAndPromote";
+$maintClass = CreateAndPromote::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/createCommonPasswordCdb.php b/www/wiki/maintenance/createCommonPasswordCdb.php
index f7e0c0fb..ef5a30de 100644
--- a/www/wiki/maintenance/createCommonPasswordCdb.php
+++ b/www/wiki/maintenance/createCommonPasswordCdb.php
@@ -60,12 +60,12 @@ class GenerateCommonPassword extends Maintenance {
$outfile = $this->getArg( 1 );
if ( !is_readable( $infile ) && $infile !== 'php://stdin' ) {
- $this->error( "Cannot open input file $infile for reading", 1 );
+ $this->fatalError( "Cannot open input file $infile for reading" );
}
$file = fopen( $infile, 'r' );
if ( $file === false ) {
- $this->error( "Cannot read input file $infile", 1 );
+ $this->fatalError( "Cannot read input file $infile" );
}
try {
@@ -109,10 +109,10 @@ class GenerateCommonPassword extends Maintenance {
" (out of $i) passwords to $outfile\n"
);
} catch ( \Cdb\Exception $e ) {
- $this->error( "Error writing cdb file: " . $e->getMessage(), 2 );
+ $this->fatalError( "Error writing cdb file: " . $e->getMessage(), 2 );
}
}
}
-$maintClass = "GenerateCommonPassword";
+$maintClass = GenerateCommonPassword::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/deleteArchivedFiles.php b/www/wiki/maintenance/deleteArchivedFiles.php
index 0f33a141..d010073b 100644
--- a/www/wiki/maintenance/deleteArchivedFiles.php
+++ b/www/wiki/maintenance/deleteArchivedFiles.php
@@ -130,5 +130,5 @@ class DeleteArchivedFiles extends Maintenance {
}
}
-$maintClass = "DeleteArchivedFiles";
+$maintClass = DeleteArchivedFiles::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/deleteArchivedRevisions.php b/www/wiki/maintenance/deleteArchivedRevisions.php
index 905b5d9c..e4419518 100644
--- a/www/wiki/maintenance/deleteArchivedRevisions.php
+++ b/www/wiki/maintenance/deleteArchivedRevisions.php
@@ -61,5 +61,5 @@ class DeleteArchivedRevisions extends Maintenance {
}
}
-$maintClass = "DeleteArchivedRevisions";
+$maintClass = DeleteArchivedRevisions::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/deleteAutoPatrolLogs.php b/www/wiki/maintenance/deleteAutoPatrolLogs.php
new file mode 100644
index 00000000..c1935a76
--- /dev/null
+++ b/www/wiki/maintenance/deleteAutoPatrolLogs.php
@@ -0,0 +1,198 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+require_once __DIR__ . '/Maintenance.php';
+
+/**
+ * Remove autopatrol logs in the logging table.
+ *
+ * @ingroup Maintenance
+ */
+class DeleteAutoPatrolLogs extends Maintenance {
+
+ public function __construct() {
+ parent::__construct();
+ $this->addDescription( 'Remove autopatrol logs in the logging table' );
+ $this->addOption( 'dry-run', 'Print debug info instead of actually deleting' );
+ $this->addOption(
+ 'check-old',
+ 'Check old patrol logs (for deleting old format autopatrols).' .
+ 'Note that this will not delete rows older than 2011 (MediaWiki 1.18).'
+ );
+ $this->addOption(
+ 'before',
+ 'Timestamp to delete only before that time, all MediaWiki timestamp formats are accepted',
+ false,
+ true
+ );
+ $this->addOption(
+ 'from-id',
+ 'First row (log id) to start updating from',
+ false,
+ true
+ );
+ $this->addOption(
+ 'sleep',
+ 'Sleep time (in seconds) between every batch',
+ false,
+ true
+ );
+ $this->setBatchSize( 1000 );
+ }
+
+ public function execute() {
+ $this->setBatchSize( $this->getOption( 'batch-size', $this->getBatchSize() ) );
+
+ $sleep = (int)$this->getOption( 'sleep', 10 );
+ $fromId = $this->getOption( 'from-id', null );
+ $this->countDown( 5 );
+ while ( true ) {
+ if ( $this->hasOption( 'check-old' ) ) {
+ $rowsData = $this->getRowsOld( $fromId );
+ // We reached end of the table
+ if ( !$rowsData ) {
+ break;
+ }
+ $rows = $rowsData['rows'];
+ $fromId = $rowsData['lastId'];
+
+ // There is nothing to delete in this batch
+ if ( !$rows ) {
+ continue;
+ }
+ } else {
+ $rows = $this->getRows( $fromId );
+ if ( !$rows ) {
+ break;
+ }
+ $fromId = end( $rows );
+ }
+
+ if ( $this->hasOption( 'dry-run' ) ) {
+ $this->output( 'These rows will get deleted: ' . implode( ', ', $rows ) . "\n" );
+ } else {
+ $this->deleteRows( $rows );
+ $this->output( 'Processed up to row id ' . end( $rows ) . "\n" );
+ }
+
+ if ( $sleep > 0 ) {
+ sleep( $sleep );
+ }
+ }
+ }
+
+ private function getRows( $fromId ) {
+ $dbr = MediaWiki\MediaWikiServices::getInstance()->getDBLoadBalancer()->getConnection(
+ DB_REPLICA
+ );
+ $before = $this->getOption( 'before', false );
+
+ $conds = [
+ 'log_type' => 'patrol',
+ 'log_action' => 'autopatrol',
+ ];
+
+ if ( $fromId ) {
+ $conds[] = 'log_id > ' . $dbr->addQuotes( $fromId );
+ }
+
+ if ( $before ) {
+ $conds[] = 'log_timestamp < ' . $dbr->addQuotes( $dbr->timestamp( $before ) );
+ }
+
+ return $dbr->selectFieldValues(
+ 'logging',
+ 'log_id',
+ $conds,
+ __METHOD__,
+ [ 'LIMIT' => $this->getBatchSize() ]
+ );
+ }
+
+ private function getRowsOld( $fromId ) {
+ $dbr = MediaWiki\MediaWikiServices::getInstance()->getDBLoadBalancer()->getConnection(
+ DB_REPLICA
+ );
+ $batchSize = $this->getBatchSize();
+ $before = $this->getOption( 'before', false );
+
+ $conds = [
+ 'log_type' => 'patrol',
+ 'log_action' => 'patrol',
+ ];
+
+ if ( $fromId ) {
+ $conds[] = 'log_id > ' . $dbr->addQuotes( $fromId );
+ }
+
+ if ( $before ) {
+ $conds[] = 'log_timestamp < ' . $dbr->addQuotes( $dbr->timestamp( $before ) );
+ }
+
+ $result = $dbr->select(
+ 'logging',
+ [ 'log_id', 'log_params' ],
+ $conds,
+ __METHOD__,
+ [ 'LIMIT' => $batchSize ]
+ );
+
+ $last = null;
+ $autopatrols = [];
+ foreach ( $result as $row ) {
+ $last = $row->log_id;
+ Wikimedia\suppressWarnings();
+ $params = unserialize( $row->log_params );
+ Wikimedia\restoreWarnings();
+
+ // Skipping really old rows, before 2011
+ if ( !is_array( $params ) || !array_key_exists( '6::auto', $params ) ) {
+ continue;
+ }
+
+ $auto = $params['6::auto'];
+ if ( $auto ) {
+ $autopatrols[] = $row->log_id;
+ }
+ }
+
+ if ( $last === null ) {
+ return null;
+ }
+
+ return [ 'rows' => $autopatrols, 'lastId' => $last ];
+ }
+
+ private function deleteRows( array $rows ) {
+ $dbw = MediaWiki\MediaWikiServices::getInstance()->getDBLoadBalancer()->getConnection(
+ DB_MASTER
+ );
+
+ $dbw->delete(
+ 'logging',
+ [ 'log_id' => $rows ],
+ __METHOD__
+ );
+
+ MediaWiki\MediaWikiServices::getInstance()->getDBLoadBalancerFactory()->waitForReplication();
+ }
+
+}
+
+$maintClass = DeleteAutoPatrolLogs::class;
+require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/deleteBatch.php b/www/wiki/maintenance/deleteBatch.php
index 0020446b..0f3c5067 100644
--- a/www/wiki/maintenance/deleteBatch.php
+++ b/www/wiki/maintenance/deleteBatch.php
@@ -65,7 +65,7 @@ class DeleteBatch extends Maintenance {
$user = User::newFromName( $username );
}
if ( !$user ) {
- $this->error( "Invalid username", true );
+ $this->fatalError( "Invalid username" );
}
$wgUser = $user;
@@ -77,15 +77,14 @@ class DeleteBatch extends Maintenance {
# Setup
if ( !$file ) {
- $this->error( "Unable to read file, exiting", true );
+ $this->fatalError( "Unable to read file, exiting" );
}
$dbw = $this->getDB( DB_MASTER );
# Handle each entry
- // @codingStandardsIgnoreStart Ignore Generic.CodeAnalysis.ForLoopWithTestFunctionCall.NotAllowed
+ // phpcs:ignore Generic.CodeAnalysis.ForLoopWithTestFunctionCall
for ( $linenum = 1; !feof( $file ); $linenum++ ) {
- // @codingStandardsIgnoreEnd
$line = trim( fgets( $file ) );
if ( $line == '' ) {
continue;
@@ -124,5 +123,5 @@ class DeleteBatch extends Maintenance {
}
}
-$maintClass = "DeleteBatch";
+$maintClass = DeleteBatch::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/deleteDefaultMessages.php b/www/wiki/maintenance/deleteDefaultMessages.php
index ba8662ac..326073f1 100644
--- a/www/wiki/maintenance/deleteDefaultMessages.php
+++ b/www/wiki/maintenance/deleteDefaultMessages.php
@@ -43,13 +43,19 @@ class DeleteDefaultMessages extends Maintenance {
$this->output( "Checking existence of old default messages..." );
$dbr = $this->getDB( DB_REPLICA );
- $res = $dbr->select( [ 'page', 'revision' ],
+
+ $actorQuery = ActorMigration::newMigration()
+ ->getWhere( $dbr, 'rev_user', User::newFromName( 'MediaWiki default' ) );
+ $res = $dbr->select(
+ [ 'page', 'revision' ] + $actorQuery['tables'],
[ 'page_namespace', 'page_title' ],
[
'page_namespace' => NS_MEDIAWIKI,
- 'page_latest=rev_id',
- 'rev_user_text' => 'MediaWiki default',
- ]
+ $actorQuery['conds'],
+ ],
+ __METHOD__,
+ [],
+ [ 'revision' => [ 'JOIN', 'page_latest=rev_id' ] ] + $actorQuery['joins']
);
if ( $dbr->numRows( $res ) == 0 ) {
@@ -72,7 +78,7 @@ class DeleteDefaultMessages extends Maintenance {
// in order to hide it in RecentChanges.
$user = User::newFromName( 'MediaWiki default' );
if ( !$user ) {
- $this->error( "Invalid username", true );
+ $this->fatalError( "Invalid username" );
}
$user->addGroup( 'bot' );
$wgUser = $user;
@@ -95,5 +101,5 @@ class DeleteDefaultMessages extends Maintenance {
}
}
-$maintClass = "DeleteDefaultMessages";
+$maintClass = DeleteDefaultMessages::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/deleteEqualMessages.php b/www/wiki/maintenance/deleteEqualMessages.php
index 5fc7d184..cd9ef111 100644
--- a/www/wiki/maintenance/deleteEqualMessages.php
+++ b/www/wiki/maintenance/deleteEqualMessages.php
@@ -123,7 +123,7 @@ class DeleteEqualMessages extends Maintenance {
$this->fetchMessageInfo( false, $messageInfo );
} else {
if ( !isset( $langCodes[$langCode] ) ) {
- $this->error( 'Invalid language code: ' . $langCode, 1 );
+ $this->fatalError( 'Invalid language code: ' . $langCode );
}
$this->fetchMessageInfo( $langCode, $messageInfo );
}
@@ -164,7 +164,7 @@ class DeleteEqualMessages extends Maintenance {
$user = User::newSystemUser( 'MediaWiki default', [ 'steal' => true ] );
if ( !$user ) {
- $this->error( "Invalid username", true );
+ $this->fatalError( "Invalid username" );
}
global $wgUser;
$wgUser = $user;
@@ -202,5 +202,5 @@ class DeleteEqualMessages extends Maintenance {
}
}
-$maintClass = "DeleteEqualMessages";
+$maintClass = DeleteEqualMessages::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/deleteOldRevisions.php b/www/wiki/maintenance/deleteOldRevisions.php
index aa11cd96..fc43e220 100644
--- a/www/wiki/maintenance/deleteOldRevisions.php
+++ b/www/wiki/maintenance/deleteOldRevisions.php
@@ -99,5 +99,5 @@ class DeleteOldRevisions extends Maintenance {
}
}
-$maintClass = "DeleteOldRevisions";
+$maintClass = DeleteOldRevisions::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/deleteOrphanedRevisions.php b/www/wiki/maintenance/deleteOrphanedRevisions.php
index 4d600706..8d3f6b3e 100644
--- a/www/wiki/maintenance/deleteOrphanedRevisions.php
+++ b/www/wiki/maintenance/deleteOrphanedRevisions.php
@@ -98,5 +98,5 @@ class DeleteOrphanedRevisions extends Maintenance {
}
}
-$maintClass = "DeleteOrphanedRevisions";
+$maintClass = DeleteOrphanedRevisions::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/deleteRevision.php b/www/wiki/maintenance/deleteRevision.php
deleted file mode 100644
index 0111ac57..00000000
--- a/www/wiki/maintenance/deleteRevision.php
+++ /dev/null
@@ -1,111 +0,0 @@
-<?php
-/**
- * Delete one or more revisions by moving them to the archive table.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup Maintenance
- */
-
-require_once __DIR__ . '/Maintenance.php';
-
-/**
- * Maintenance script that deletes one or more revisions by moving them
- * to the archive table.
- *
- * @ingroup Maintenance
- */
-class DeleteRevision extends Maintenance {
-
- public function __construct() {
- parent::__construct();
- $this->addDescription( 'Delete one or more revisions by moving them to the archive table' );
- }
-
- public function execute() {
- if ( count( $this->mArgs ) == 0 ) {
- $this->error( "No revisions specified", true );
- }
-
- $this->output( "Deleting revision(s) " . implode( ',', $this->mArgs ) .
- " from " . wfWikiID() . "...\n" );
- $dbw = $this->getDB( DB_MASTER );
-
- $affected = 0;
- foreach ( $this->mArgs as $revID ) {
- $dbw->insertSelect( 'archive', [ 'page', 'revision' ],
- [
- 'ar_namespace' => 'page_namespace',
- 'ar_title' => 'page_title',
- 'ar_page_id' => 'page_id',
- 'ar_comment' => 'rev_comment',
- 'ar_user' => 'rev_user',
- 'ar_user_text' => 'rev_user_text',
- 'ar_timestamp' => 'rev_timestamp',
- 'ar_minor_edit' => 'rev_minor_edit',
- 'ar_rev_id' => 'rev_id',
- 'ar_text_id' => 'rev_text_id',
- 'ar_deleted' => 'rev_deleted',
- 'ar_len' => 'rev_len',
- ],
- [
- 'rev_id' => $revID,
- 'page_id = rev_page'
- ],
- __METHOD__
- );
- if ( !$dbw->affectedRows() ) {
- $this->output( "Revision $revID not found\n" );
- } else {
- $affected += $dbw->affectedRows();
- $pageID = $dbw->selectField(
- 'revision',
- 'rev_page',
- [ 'rev_id' => $revID ],
- __METHOD__
- );
- $pageLatest = $dbw->selectField(
- 'page',
- 'page_latest',
- [ 'page_id' => $pageID ],
- __METHOD__
- );
- $dbw->delete( 'revision', [ 'rev_id' => $revID ] );
- if ( $pageLatest == $revID ) {
- // Database integrity
- $newLatest = $dbw->selectField(
- 'revision',
- 'rev_id',
- [ 'rev_page' => $pageID ],
- __METHOD__,
- [ 'ORDER BY' => 'rev_timestamp DESC' ]
- );
- $dbw->update(
- 'page',
- [ 'page_latest' => $newLatest ],
- [ 'page_id' => $pageID ],
- __METHOD__
- );
- }
- }
- }
- $this->output( "Deleted $affected revisions\n" );
- }
-}
-
-$maintClass = "DeleteRevision";
-require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/deleteSelfExternals.php b/www/wiki/maintenance/deleteSelfExternals.php
index ed15fd13..9849dc50 100644
--- a/www/wiki/maintenance/deleteSelfExternals.php
+++ b/www/wiki/maintenance/deleteSelfExternals.php
@@ -33,7 +33,7 @@ class DeleteSelfExternals extends Maintenance {
public function __construct() {
parent::__construct();
$this->addDescription( 'Delete self-references to $wgServer from externallinks' );
- $this->mBatchSize = 1000;
+ $this->setBatchSize( 1000 );
}
public function execute() {
@@ -41,10 +41,9 @@ class DeleteSelfExternals extends Maintenance {
$this->output( "Deleting self externals from $wgServer\n" );
$db = $this->getDB( DB_MASTER );
while ( 1 ) {
- wfWaitForSlaves();
$this->commitTransaction( $db, __METHOD__ );
$q = $db->limitResult( "DELETE /* deleteSelfExternals */ FROM externallinks WHERE el_to"
- . $db->buildLike( $wgServer . '/', $db->anyString() ), $this->mBatchSize );
+ . $db->buildLike( $wgServer . '/', $db->anyString() ), $this->getBatchSize() );
$this->output( "Deleting a batch\n" );
$db->query( $q );
if ( !$db->affectedRows() ) {
@@ -54,5 +53,5 @@ class DeleteSelfExternals extends Maintenance {
}
}
-$maintClass = "DeleteSelfExternals";
+$maintClass = DeleteSelfExternals::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/dev/README b/www/wiki/maintenance/dev/README
index ca47d136..a00f52bb 100644
--- a/www/wiki/maintenance/dev/README
+++ b/www/wiki/maintenance/dev/README
@@ -1,7 +1,7 @@
maintenance/dev/ scripts can help quickly setup a local MediaWiki for development purposes.
-Wikis setup in this way are NOT meant to be publicly available. They use a development database not acceptible for use in production. Place a sqlite database in an unsafe location a real wiki should never place it in. And use predictable default logins for the initial administrator user.
+Wikis setup in this way are NOT meant to be publicly available. They use a development database not acceptable for use in production. Place a sqlite database in an unsafe location a real wiki should never place it in. And use predictable default logins for the initial administrator user.
-Running maintenance/dev/install.sh will download and install a local copy of php 5.4, install a sqlite powered instance of MW for development, and then start up a local webserver to view the wiki.
+Running maintenance/dev/install.sh will download and install a local copy of php 5.6, install a sqlite powered instance of MW for development, and then start up a local webserver to view the wiki.
After installation you can bring the webserver back up at any time you want with maintenance/dev/start.sh
diff --git a/www/wiki/maintenance/dev/installphp.sh b/www/wiki/maintenance/dev/installphp.sh
index d26ffa67..1e3d410f 100755
--- a/www/wiki/maintenance/dev/installphp.sh
+++ b/www/wiki/maintenance/dev/installphp.sh
@@ -12,13 +12,14 @@ if [ "x$PHP" != "x" -a -x "$PHP" ]; then
exit 0
fi
-TAR=php5.4-latest.tar.gz
-PHPURL="http://snaps.php.net/$TAR"
+VER=5.6.32
+TAR="php-$VER.tar.gz"
+PHPURL="https://secure.php.net/get/$TAR/from/this/mirror"
cd "$DEV"
-echo "Preparing to download and install a local copy of PHP 5.4, note that this can take some time to do."
-echo "If you wish to avoid re-doing this for uture dev installations of MediaWiki we suggest installing php in ~/.mediawiki/php"
+echo "Preparing to download and install a local copy of PHP $VER, note that this can take some time to do."
+echo "If you wish to avoid re-doing this for future dev installations of MediaWiki we suggest installing php in ~/.mediawiki/php"
echo -n "Install PHP in ~/.mediawiki/php [y/N]: "
read INSTALLINHOME
@@ -31,27 +32,27 @@ case "$INSTALLINHOME" in
;;
esac
-# Some debain-like systems bundle wget but not curl, some other systems
+# Some debian-like systems bundle wget but not curl, some other systems
# like os x bundle curl but not wget... use whatever is available
-echo -n "Downloading PHP 5.4"
+echo -n "Downloading PHP $VER"
if command -v wget &>/dev/null; then
- echo "- using wget"
- wget "$PHPURL"
+ echo " - using wget"
+ wget -O "$TAR" "$PHPURL"
elif command -v curl &>/dev/null; then
- echo "- using curl"
- curl -O "$PHPURL"
+ echo " - using curl"
+ curl "$PHPURL" -L -o "$TAR"
else
- echo "- aborting"
+ echo " - aborting"
echo "Could not find curl or wget." >&2;
exit 1;
fi
-echo "Extracting php 5.4"
+echo "Extracting php $VER"
tar -xzf "$TAR"
-cd php5.4-*/
+cd "php-$VER/"
-echo "Configuring and installing php 5.4 in $PREFIX"
+echo "Configuring and installing php $VER in $PREFIX"
./configure --prefix="$PREFIX"
make
make install
diff --git a/www/wiki/maintenance/dictionary/mediawiki.dic b/www/wiki/maintenance/dictionary/mediawiki.dic
index 7c3c95d7..ff06e49d 100644
--- a/www/wiki/maintenance/dictionary/mediawiki.dic
+++ b/www/wiki/maintenance/dictionary/mediawiki.dic
@@ -2027,7 +2027,6 @@ isminor
ismodsince
ismulti
isnew
-ispermalink
isroot
isself
isset
@@ -4585,7 +4584,6 @@ wrongpassword
x
xanalytics
xbitmap
-xcache
xcancel
xdebug
xdiff
diff --git a/www/wiki/maintenance/doMaintenance.php b/www/wiki/maintenance/doMaintenance.php
index e87e0249..f3fb32ce 100644
--- a/www/wiki/maintenance/doMaintenance.php
+++ b/www/wiki/maintenance/doMaintenance.php
@@ -21,7 +21,6 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* http://www.gnu.org/copyleft/gpl.html
*
- * @author Chad Horohoe <chad@anyonecanedit.org>
* @file
* @ingroup Maintenance
*/
@@ -35,7 +34,7 @@ if ( !defined( 'RUN_MAINTENANCE_IF_MAIN' ) ) {
// Wasn't included from the file scope, halt execution (probably wanted the class)
// If a class is using commandLine.inc (old school maintenance), they definitely
// cannot be included and will proceed with execution
-if ( !Maintenance::shouldExecute() && $maintClass != 'CommandLineInc' ) {
+if ( !Maintenance::shouldExecute() && $maintClass != CommandLineInc::class ) {
return;
}
@@ -55,27 +54,30 @@ $maintenance->setup();
// to $maintenance->mSelf. Keep that here for b/c
$self = $maintenance->getName();
-require_once "$IP/includes/PreConfigSetup.php";
-
-if ( defined( 'MW_CONFIG_CALLBACK' ) ) {
- # Use a callback function to configure MediaWiki
- call_user_func( MW_CONFIG_CALLBACK );
-} else {
- // Require the configuration (probably LocalSettings.php)
- require $maintenance->loadSettings();
+// Define how settings are loaded (e.g. LocalSettings.php)
+if ( !defined( 'MW_CONFIG_CALLBACK' ) && !defined( 'MW_CONFIG_FILE' ) ) {
+ define( 'MW_CONFIG_FILE', $maintenance->loadSettings() );
}
-if ( $maintenance->getDbType() === Maintenance::DB_NONE ) {
- if ( $wgLocalisationCacheConf['storeClass'] === false
- && ( $wgLocalisationCacheConf['store'] == 'db'
- || ( $wgLocalisationCacheConf['store'] == 'detect' && !$wgCacheDirectory ) )
- ) {
- $wgLocalisationCacheConf['storeClass'] = 'LCStoreNull';
+// Custom setup for Maintenance entry point
+if ( !defined( 'MW_SETUP_CALLBACK' ) ) {
+ function wfMaintenanceSetup() {
+ // phpcs:ignore MediaWiki.NamingConventions.ValidGlobalName.wgPrefix
+ global $maintenance, $wgLocalisationCacheConf, $wgCacheDirectory;
+ if ( $maintenance->getDbType() === Maintenance::DB_NONE ) {
+ if ( $wgLocalisationCacheConf['storeClass'] === false
+ && ( $wgLocalisationCacheConf['store'] == 'db'
+ || ( $wgLocalisationCacheConf['store'] == 'detect' && !$wgCacheDirectory ) )
+ ) {
+ $wgLocalisationCacheConf['storeClass'] = LCStoreNull::class;
+ }
+ }
+
+ $maintenance->finalSetup();
}
+ define( 'MW_SETUP_CALLBACK', 'wfMaintenanceSetup' );
}
-$maintenance->finalSetup();
-// Some last includes
require_once "$IP/includes/Setup.php";
// Initialize main config instance
diff --git a/www/wiki/maintenance/dumpBackup.php b/www/wiki/maintenance/dumpBackup.php
index 9bf12221..6bbd86d5 100644
--- a/www/wiki/maintenance/dumpBackup.php
+++ b/www/wiki/maintenance/dumpBackup.php
@@ -87,7 +87,7 @@ TEXT
} elseif ( $this->hasOption( 'revrange' ) ) {
$this->dump( WikiExporter::RANGE, $textMode );
} else {
- $this->error( 'No valid action specified.', 1 );
+ $this->fatalError( 'No valid action specified.' );
}
}
@@ -133,5 +133,5 @@ TEXT
}
}
-$maintClass = 'DumpBackup';
+$maintClass = DumpBackup::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/dumpCategoriesAsRdf.php b/www/wiki/maintenance/dumpCategoriesAsRdf.php
index ff50498f..e4bd7564 100644
--- a/www/wiki/maintenance/dumpCategoriesAsRdf.php
+++ b/www/wiki/maintenance/dumpCategoriesAsRdf.php
@@ -58,14 +58,32 @@ class DumpCategoriesAsRdf extends Maintenance {
public function getCategoryIterator( IDatabase $dbr ) {
$it = new BatchRowIterator(
$dbr,
- 'page',
+ [ 'page', 'page_props', 'category' ],
[ 'page_title' ],
- $this->mBatchSize
+ $this->getBatchSize()
);
$it->addConditions( [
'page_namespace' => NS_CATEGORY,
] );
- $it->setFetchColumns( [ 'page_title', 'page_id' ] );
+ $it->setFetchColumns( [
+ 'page_title',
+ 'page_id',
+ 'pp_propname',
+ 'cat_pages',
+ 'cat_subcats',
+ 'cat_files'
+ ] );
+ $it->addJoinConditions(
+ [
+ 'page_props' => [
+ 'LEFT JOIN', [ 'pp_propname' => 'hiddencat', 'pp_page = page_id' ]
+ ],
+ 'category' => [
+ 'LEFT JOIN', [ 'cat_title = page_title' ]
+ ]
+ ]
+
+ );
return $it;
}
@@ -80,7 +98,7 @@ class DumpCategoriesAsRdf extends Maintenance {
$dbr,
'categorylinks',
[ 'cl_from', 'cl_to' ],
- $this->mBatchSize
+ $this->getBatchSize()
);
$it->addConditions( [
'cl_type' => 'subcat',
@@ -90,13 +108,16 @@ class DumpCategoriesAsRdf extends Maintenance {
return new RecursiveIteratorIterator( $it );
}
+ /**
+ * @param int $timestamp
+ */
public function addDumpHeader( $timestamp ) {
global $wgRightsUrl;
$licenseUrl = $wgRightsUrl;
if ( substr( $licenseUrl, 0, 2 ) == '//' ) {
$licenseUrl = 'https:' . $licenseUrl;
}
- $this->rdfWriter->about( wfExpandUrl( '/categoriesDump', PROTO_CANONICAL ) )
+ $this->rdfWriter->about( $this->categoriesRdf->getDumpURI() )
->a( 'schema', 'Dataset' )
->a( 'owl', 'Ontology' )
->say( 'cc', 'license' )->is( $licenseUrl )
@@ -129,7 +150,12 @@ class DumpCategoriesAsRdf extends Maintenance {
foreach ( $this->getCategoryIterator( $dbr ) as $batch ) {
$pages = [];
foreach ( $batch as $row ) {
- $this->categoriesRdf->writeCategoryData( $row->page_title );
+ $this->categoriesRdf->writeCategoryData(
+ $row->page_title,
+ $row->pp_propname === 'hiddencat',
+ (int)$row->cat_pages - (int)$row->cat_subcats - (int)$row->cat_files,
+ (int)$row->cat_subcats
+ );
$pages[$row->page_id] = $row->page_title;
}
@@ -154,5 +180,5 @@ class DumpCategoriesAsRdf extends Maintenance {
}
}
-$maintClass = "DumpCategoriesAsRdf";
+$maintClass = DumpCategoriesAsRdf::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/dumpIterator.php b/www/wiki/maintenance/dumpIterator.php
index 6dbad949..e9a6bc58 100644
--- a/www/wiki/maintenance/dumpIterator.php
+++ b/www/wiki/maintenance/dumpIterator.php
@@ -48,7 +48,7 @@ abstract class DumpIterator extends Maintenance {
public function execute() {
if ( !( $this->hasOption( 'file' ) ^ $this->hasOption( 'dump' ) ) ) {
- $this->error( "You must provide a file or dump", true );
+ $this->fatalError( "You must provide a file or dump" );
}
$this->checkOptions();
@@ -70,13 +70,16 @@ abstract class DumpIterator extends Maintenance {
if ( $this->getOption( 'dump' ) == '-' ) {
$source = new ImportStreamSource( $this->getStdin() );
} else {
- $this->error( "Sorry, I don't support dump filenames yet. "
- . "Use - and provide it on stdin on the meantime.", true );
+ $this->fatalError( "Sorry, I don't support dump filenames yet. "
+ . "Use - and provide it on stdin on the meantime." );
}
$importer = new WikiImporter( $source, $this->getConfig() );
$importer->setRevisionCallback(
[ $this, 'handleRevision' ] );
+ $importer->setNoticeCallback( function ( $msg, $params ) {
+ echo wfMessage( $msg, $params )->text() . "\n";
+ } );
$this->from = $this->getOption( 'from', null );
$this->count = 0;
@@ -102,7 +105,7 @@ abstract class DumpIterator extends Maintenance {
if ( $this->getDbType() == Maintenance::DB_NONE ) {
global $wgUseDatabaseMessages, $wgLocalisationCacheConf, $wgHooks;
$wgUseDatabaseMessages = false;
- $wgLocalisationCacheConf['storeClass'] = 'LCStoreNull';
+ $wgLocalisationCacheConf['storeClass'] = LCStoreNull::class;
$wgHooks['InterwikiLoadPrefix'][] = 'DumpIterator::disableInterwikis';
}
}
@@ -182,5 +185,5 @@ class SearchDump extends DumpIterator {
}
}
-$maintClass = "SearchDump";
+$maintClass = SearchDump::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/dumpLinks.php b/www/wiki/maintenance/dumpLinks.php
index ff4e8945..6904953f 100644
--- a/www/wiki/maintenance/dumpLinks.php
+++ b/www/wiki/maintenance/dumpLinks.php
@@ -75,5 +75,5 @@ class DumpLinks extends Maintenance {
}
}
-$maintClass = "DumpLinks";
+$maintClass = DumpLinks::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/dumpTextPass.php b/www/wiki/maintenance/dumpTextPass.php
index 2b79b546..59a6b517 100644
--- a/www/wiki/maintenance/dumpTextPass.php
+++ b/www/wiki/maintenance/dumpTextPass.php
@@ -25,8 +25,10 @@
*/
require_once __DIR__ . '/backup.inc';
+require_once __DIR__ . '/7zip.inc';
require_once __DIR__ . '/../includes/export/WikiExporter.php';
+use MediaWiki\MediaWikiServices;
use Wikimedia\Rdbms\IMaintainableDatabase;
/**
@@ -142,8 +144,6 @@ TEXT
}
function processOptions() {
- global $IP;
-
parent::processOptions();
if ( $this->hasOption( 'buffersize' ) ) {
@@ -151,7 +151,6 @@ TEXT
}
if ( $this->hasOption( 'prefetch' ) ) {
- require_once "$IP/maintenance/backupPrefetch.inc";
$url = $this->processFileOpt( $this->getOption( 'prefetch' ) );
$this->prefetch = new BaseDump( $url );
}
@@ -220,7 +219,8 @@ TEXT
// individually retrying at different layers of code.
try {
- $this->lb = wfGetLBFactory()->newMainLB();
+ $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
+ $this->lb = $lbFactory->newMainLB();
} catch ( Exception $e ) {
throw new MWException( __METHOD__
. " rotating DB failed to obtain new load balancer (" . $e->getMessage() . ")" );
@@ -724,13 +724,13 @@ TEXT
}
private function getTextSpawned( $id ) {
- MediaWiki\suppressWarnings();
+ Wikimedia\suppressWarnings();
if ( !$this->spawnProc ) {
// First time?
$this->openSpawn();
}
$text = $this->getTextSpawnedOnce( $id );
- MediaWiki\restoreWarnings();
+ Wikimedia\restoreWarnings();
return $text;
}
@@ -776,7 +776,7 @@ TEXT
}
private function closeSpawn() {
- MediaWiki\suppressWarnings();
+ Wikimedia\suppressWarnings();
if ( $this->spawnRead ) {
fclose( $this->spawnRead );
}
@@ -793,7 +793,7 @@ TEXT
pclose( $this->spawnProc );
}
$this->spawnProc = false;
- MediaWiki\restoreWarnings();
+ Wikimedia\restoreWarnings();
}
private function getTextSpawnedOnce( $id ) {
@@ -988,5 +988,5 @@ TEXT
}
}
-$maintClass = 'TextPassDumper';
+$maintClass = TextPassDumper::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/dumpUploads.php b/www/wiki/maintenance/dumpUploads.php
index 8d63fe55..4bfc5746 100644
--- a/www/wiki/maintenance/dumpUploads.php
+++ b/www/wiki/maintenance/dumpUploads.php
@@ -124,5 +124,5 @@ By default, outputs relative paths against the parent directory of $wgUploadDire
}
}
-$maintClass = "UploadDumper";
+$maintClass = UploadDumper::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/edit.php b/www/wiki/maintenance/edit.php
index 4219ed05..60ed2523 100644
--- a/www/wiki/maintenance/edit.php
+++ b/www/wiki/maintenance/edit.php
@@ -59,7 +59,7 @@ class EditCLI extends Maintenance {
$wgUser = User::newFromName( $userName );
}
if ( !$wgUser ) {
- $this->error( "Invalid username", true );
+ $this->fatalError( "Invalid username" );
}
if ( $wgUser->isAnon() ) {
$wgUser->addToDatabase();
@@ -67,13 +67,13 @@ class EditCLI extends Maintenance {
$title = Title::newFromText( $this->getArg() );
if ( !$title ) {
- $this->error( "Invalid title", true );
+ $this->fatalError( "Invalid title" );
}
if ( $this->hasOption( 'nocreate' ) && !$title->exists() ) {
- $this->error( "Page does not exist", true );
+ $this->fatalError( "Page does not exist" );
} elseif ( $this->hasOption( 'createonly' ) && $title->exists() ) {
- $this->error( "Page already exists", true );
+ $this->fatalError( "Page already exists" );
}
$page = WikiPage::factory( $title );
@@ -103,5 +103,5 @@ class EditCLI extends Maintenance {
}
}
-$maintClass = "EditCLI";
+$maintClass = EditCLI::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/eraseArchivedFile.php b/www/wiki/maintenance/eraseArchivedFile.php
index c90056db..ef6d3d8b 100644
--- a/www/wiki/maintenance/eraseArchivedFile.php
+++ b/www/wiki/maintenance/eraseArchivedFile.php
@@ -50,16 +50,17 @@ class EraseArchivedFile extends Maintenance {
if ( $filekey === '*' ) { // all versions by name
if ( !strlen( $filename ) ) {
- $this->error( "Missing --filename parameter.", 1 );
+ $this->fatalError( "Missing --filename parameter." );
}
$afile = false;
} else { // specified version
$dbw = $this->getDB( DB_MASTER );
- $row = $dbw->selectRow( 'filearchive', '*',
+ $fileQuery = ArchivedFile::getQueryInfo();
+ $row = $dbw->selectRow( $fileQuery['tables'], $fileQuery['fields'],
[ 'fa_storage_group' => 'deleted', 'fa_storage_key' => $filekey ],
- __METHOD__ );
+ __METHOD__, [], $fileQuery['joins'] );
if ( !$row ) {
- $this->error( "No deleted file exists with key '$filekey'.", 1 );
+ $this->fatalError( "No deleted file exists with key '$filekey'." );
}
$filename = $row->fa_name;
$afile = ArchivedFile::newFromRow( $row );
@@ -67,7 +68,7 @@ class EraseArchivedFile extends Maintenance {
$file = wfLocalFile( $filename );
if ( $file->exists() ) {
- $this->error( "File '$filename' is still a public file, use the delete form.\n", 1 );
+ $this->fatalError( "File '$filename' is still a public file, use the delete form.\n" );
}
$this->output( "Purging all thumbnails for file '$filename'..." );
@@ -85,9 +86,10 @@ class EraseArchivedFile extends Maintenance {
protected function scrubAllVersions( $name ) {
$dbw = $this->getDB( DB_MASTER );
- $res = $dbw->select( 'filearchive', '*',
+ $fileQuery = ArchivedFile::getQueryInfo();
+ $res = $dbw->select( $fileQuery['tables'], $fileQuery['fields'],
[ 'fa_name' => $name, 'fa_storage_group' => 'deleted' ],
- __METHOD__ );
+ __METHOD__, [], $fileQuery['joins'] );
foreach ( $res as $row ) {
$this->scrubVersion( ArchivedFile::newFromRow( $row ) );
}
@@ -113,5 +115,5 @@ class EraseArchivedFile extends Maintenance {
}
}
-$maintClass = "EraseArchivedFile";
+$maintClass = EraseArchivedFile::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/exportSites.php b/www/wiki/maintenance/exportSites.php
index b1e4fa94..736b12b3 100644
--- a/www/wiki/maintenance/exportSites.php
+++ b/www/wiki/maintenance/exportSites.php
@@ -9,7 +9,7 @@ require_once $basePath . '/maintenance/Maintenance.php';
*
* @since 1.25
*
- * @licence GNU GPL v2+
+ * @license GNU GPL v2+
* @author Daniel Kinzler
*/
class ExportSites extends Maintenance {
@@ -37,7 +37,7 @@ class ExportSites extends Maintenance {
$handle = fopen( $file, 'w' );
if ( !$handle ) {
- $this->error( "Failed to open $file for writing.\n", 1 );
+ $this->fatalError( "Failed to open $file for writing.\n" );
}
$exporter = new SiteExporter( $handle );
@@ -52,5 +52,5 @@ class ExportSites extends Maintenance {
}
-$maintClass = 'ExportSites';
+$maintClass = ExportSites::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/fetchText.php b/www/wiki/maintenance/fetchText.php
index 9c5a3751..bc4fa31f 100644
--- a/www/wiki/maintenance/fetchText.php
+++ b/www/wiki/maintenance/fetchText.php
@@ -92,5 +92,5 @@ class FetchText extends Maintenance {
}
}
-$maintClass = "FetchText";
+$maintClass = FetchText::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/fileOpPerfTest.php b/www/wiki/maintenance/fileOpPerfTest.php
index 4b6c6194..a60942fb 100644
--- a/www/wiki/maintenance/fileOpPerfTest.php
+++ b/www/wiki/maintenance/fileOpPerfTest.php
@@ -141,5 +141,5 @@ class TestFileOpPerformance extends Maintenance {
}
}
-$maintClass = "TestFileOpPerformance";
+$maintClass = TestFileOpPerformance::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/findDeprecated.php b/www/wiki/maintenance/findDeprecated.php
index 6128d238..ae2ee421 100644
--- a/www/wiki/maintenance/findDeprecated.php
+++ b/www/wiki/maintenance/findDeprecated.php
@@ -132,6 +132,9 @@ class FindDeprecated extends Maintenance {
$this->addDescription( 'Find deprecated interfaces' );
}
+ /**
+ * @return SplFileInfo[]
+ */
public function getFiles() {
global $IP;
@@ -163,7 +166,7 @@ class FindDeprecated extends Maintenance {
}
$finder->setCurrentFile( substr( $file->getPathname(), strlen( $IP ) + 1 ) );
- $nodes = $parser->parse( $code, [ 'throwOnError' => false ] );
+ $nodes = $parser->parse( $code );
$traverser->traverse( $nodes );
if ( $i % $chunkSize === 0 ) {
@@ -199,5 +202,5 @@ class FindDeprecated extends Maintenance {
}
}
-$maintClass = 'FindDeprecated';
+$maintClass = FindDeprecated::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/findHooks.php b/www/wiki/maintenance/findHooks.php
index fd36db1d..ebb1f26c 100644
--- a/www/wiki/maintenance/findHooks.php
+++ b/www/wiki/maintenance/findHooks.php
@@ -143,7 +143,7 @@ class FindHooks extends Maintenance {
) {
$this->output( "Looks good!\n" );
} else {
- $this->error( 'The script finished with errors.', 1 );
+ $this->fatalError( 'The script finished with errors.' );
}
}
@@ -217,7 +217,7 @@ class FindHooks extends Maintenance {
$retval = [];
while ( true ) {
$json = Http::get(
- wfAppendQuery( 'http://www.mediawiki.org/w/api.php', $params ),
+ wfAppendQuery( 'https://www.mediawiki.org/w/api.php', $params ),
[],
__METHOD__
);
@@ -245,7 +245,7 @@ class FindHooks extends Maintenance {
$m = [];
preg_match_all(
// All functions which runs hooks
- '/(?:wfRunHooks|Hooks\:\:run)\s*\(\s*' .
+ '/(?:wfRunHooks|Hooks\:\:run|Hooks\:\:runWithoutAbort)\s*\(\s*' .
// First argument is the hook name as string
'([\'"])(.*?)\1' .
// Comma for second argument
@@ -349,5 +349,5 @@ class FindHooks extends Maintenance {
}
}
-$maintClass = 'FindHooks';
+$maintClass = FindHooks::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/findMissingFiles.php b/www/wiki/maintenance/findMissingFiles.php
index 4ce7ca68..4997cabb 100644
--- a/www/wiki/maintenance/findMissingFiles.php
+++ b/www/wiki/maintenance/findMissingFiles.php
@@ -37,6 +37,7 @@ class FindMissingFiles extends Maintenance {
$repo = RepoGroup::singleton()->getLocalRepo();
$dbr = $repo->getReplicaDB();
$be = $repo->getBackend();
+ $batchSize = $this->getBatchSize();
$mtime1 = $dbr->timestampOrNull( $this->getOption( 'mtimeafter', null ) );
$mtime2 = $dbr->timestampOrNull( $this->getOption( 'mtimebefore', null ) );
@@ -66,7 +67,7 @@ class FindMissingFiles extends Maintenance {
__METHOD__,
// DISTINCT causes a pointless filesort
[ 'ORDER BY' => 'name', 'GROUP BY' => 'name',
- 'LIMIT' => $this->mBatchSize ],
+ 'LIMIT' => $batchSize ],
$joinConds
);
@@ -101,7 +102,7 @@ class FindMissingFiles extends Maintenance {
$checkPaths[] = $file->getPath();
}
- foreach ( array_chunk( $checkPaths, $this->mBatchSize ) as $paths ) {
+ foreach ( array_chunk( $checkPaths, $batchSize ) as $paths ) {
$be->preloadFileStat( [ 'srcs' => $paths ] );
foreach ( $paths as $path ) {
if ( $be->fileExists( [ 'src' => $path ] ) === false ) {
@@ -110,9 +111,9 @@ class FindMissingFiles extends Maintenance {
}
}
}
- } while ( $res->numRows() >= $this->mBatchSize );
+ } while ( $res->numRows() >= $batchSize );
}
}
-$maintClass = 'FindMissingFiles';
+$maintClass = FindMissingFiles::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/findOrphanedFiles.php b/www/wiki/maintenance/findOrphanedFiles.php
index 765fbe4a..57e04e0e 100644
--- a/www/wiki/maintenance/findOrphanedFiles.php
+++ b/www/wiki/maintenance/findOrphanedFiles.php
@@ -37,7 +37,7 @@ class FindOrphanedFiles extends Maintenance {
$repo = RepoGroup::singleton()->getLocalRepo();
if ( $repo->hasSha1Storage() ) {
- $this->error( "Local repo uses SHA-1 file storage names; aborting.", 1 );
+ $this->fatalError( "Local repo uses SHA-1 file storage names; aborting." );
}
$directory = $repo->getZonePath( 'public' );
@@ -51,7 +51,7 @@ class FindOrphanedFiles extends Maintenance {
$list = $repo->getBackend()->getFileList( [ 'dir' => $directory ] );
if ( $list === null ) {
- $this->error( "Could not get file listing.", 1 );
+ $this->fatalError( "Could not get file listing." );
}
$pathBatch = [];
@@ -61,7 +61,7 @@ class FindOrphanedFiles extends Maintenance {
}
$pathBatch[] = $path;
- if ( count( $pathBatch ) >= $this->mBatchSize ) {
+ if ( count( $pathBatch ) >= $this->getBatchSize() ) {
$this->checkFiles( $repo, $pathBatch, $verbose );
$pathBatch = [];
}
@@ -151,5 +151,5 @@ class FindOrphanedFiles extends Maintenance {
}
}
-$maintClass = 'FindOrphanedFiles';
+$maintClass = FindOrphanedFiles::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/fixDefaultJsonContentPages.php b/www/wiki/maintenance/fixDefaultJsonContentPages.php
index 460b5534..cb4eddf5 100644
--- a/www/wiki/maintenance/fixDefaultJsonContentPages.php
+++ b/www/wiki/maintenance/fixDefaultJsonContentPages.php
@@ -64,12 +64,12 @@ class FixDefaultJsonContentPages extends LoggedUpdateMaintenance {
'page_id > ' . $dbr->addQuotes( $lastPage )
],
__METHOD__,
- [ 'ORDER BY' => 'page_id', 'LIMIT' => $this->mBatchSize ]
+ [ 'ORDER BY' => 'page_id', 'LIMIT' => $this->getBatchSize() ]
);
foreach ( $rows as $row ) {
$this->handleRow( $row );
}
- } while ( $rows->numRows() >= $this->mBatchSize );
+ } while ( $rows->numRows() >= $this->getBatchSize() );
}
return true;
@@ -124,5 +124,5 @@ class FixDefaultJsonContentPages extends LoggedUpdateMaintenance {
}
}
-$maintClass = 'FixDefaultJsonContentPages';
+$maintClass = FixDefaultJsonContentPages::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/fixDoubleRedirects.php b/www/wiki/maintenance/fixDoubleRedirects.php
index 8c9faca2..a76617aa 100644
--- a/www/wiki/maintenance/fixDoubleRedirects.php
+++ b/www/wiki/maintenance/fixDoubleRedirects.php
@@ -48,7 +48,7 @@ class FixDoubleRedirects extends Maintenance {
if ( $this->hasOption( 'title' ) ) {
$title = Title::newFromText( $this->getOption( 'title' ) );
if ( !$title || !$title->isRedirect() ) {
- $this->error( $title->getPrefixedText() . " is not a redirect!\n", true );
+ $this->fatalError( $title->getPrefixedText() . " is not a redirect!\n" );
}
} else {
$title = null;
@@ -136,5 +136,5 @@ class FixDoubleRedirects extends Maintenance {
}
}
-$maintClass = "FixDoubleRedirects";
+$maintClass = FixDoubleRedirects::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/fixExtLinksProtocolRelative.php b/www/wiki/maintenance/fixExtLinksProtocolRelative.php
index 97cd37e0..c70b8be7 100644
--- a/www/wiki/maintenance/fixExtLinksProtocolRelative.php
+++ b/www/wiki/maintenance/fixExtLinksProtocolRelative.php
@@ -95,5 +95,5 @@ class FixExtLinksProtocolRelative extends LoggedUpdateMaintenance {
}
}
-$maintClass = "FixExtLinksProtocolRelative";
+$maintClass = FixExtLinksProtocolRelative::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/fixTimestamps.php b/www/wiki/maintenance/fixTimestamps.php
index 796ec265..32ff985f 100644
--- a/www/wiki/maintenance/fixTimestamps.php
+++ b/www/wiki/maintenance/fixTimestamps.php
@@ -56,7 +56,7 @@ class FixTimestamps extends Maintenance {
$row = $dbw->fetchObject( $res );
if ( is_null( $row->minrev ) ) {
- $this->error( "No revisions in search period.", true );
+ $this->fatalError( "No revisions in search period." );
}
$minRev = $row->minrev;
@@ -99,14 +99,14 @@ class FixTimestamps extends Maintenance {
$numBadRevs = count( $badRevs );
if ( $numBadRevs > $numGoodRevs ) {
- $this->error(
+ $this->fatalError(
"The majority of revisions in the search interval are marked as bad.
Are you sure the offset ($offset) has the right sign? Positive means the clock
was incorrectly set forward, negative means the clock was incorrectly set back.
If the offset is right, then increase the search interval until there are enough
- good revisions to provide a majority reference.", true );
+ good revisions to provide a majority reference." );
} elseif ( $numBadRevs == 0 ) {
$this->output( "No bad revisions found.\n" );
exit( 0 );
@@ -125,5 +125,5 @@ class FixTimestamps extends Maintenance {
}
}
-$maintClass = "FixTimestamps";
+$maintClass = FixTimestamps::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/fixUserRegistration.php b/www/wiki/maintenance/fixUserRegistration.php
index 37fd44fb..e1b16829 100644
--- a/www/wiki/maintenance/fixUserRegistration.php
+++ b/www/wiki/maintenance/fixUserRegistration.php
@@ -51,7 +51,7 @@ class FixUserRegistration extends Maintenance {
],
__METHOD__,
[
- 'LIMIT' => $this->mBatchSize,
+ 'LIMIT' => $this->getBatchSize(),
'ORDER BY' => 'user_id',
]
);
@@ -59,11 +59,15 @@ class FixUserRegistration extends Maintenance {
$id = $row->user_id;
$lastId = $id;
// Get first edit time
+ $actorQuery = ActorMigration::newMigration()
+ ->getWhere( $dbw, 'rev_user', User::newFromId( $id ) );
$timestamp = $dbw->selectField(
- 'revision',
+ [ 'revision' ] + $actorQuery['tables'],
'MIN(rev_timestamp)',
- [ 'rev_user' => $id ],
- __METHOD__
+ $actorQuery['conds'],
+ __METHOD__,
+ [],
+ $actorQuery['joins']
);
// Update
if ( $timestamp !== null ) {
@@ -83,9 +87,9 @@ class FixUserRegistration extends Maintenance {
$this->output( "Waiting for replica DBs..." );
wfWaitForSlaves();
$this->output( " done.\n" );
- } while ( $res->numRows() >= $this->mBatchSize );
+ } while ( $res->numRows() >= $this->getBatchSize() );
}
}
-$maintClass = "FixUserRegistration";
+$maintClass = FixUserRegistration::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/formatInstallDoc.php b/www/wiki/maintenance/formatInstallDoc.php
index e2b3c419..dbaeb867 100644
--- a/www/wiki/maintenance/formatInstallDoc.php
+++ b/www/wiki/maintenance/formatInstallDoc.php
@@ -41,8 +41,7 @@ class MaintenanceFormatInstallDoc extends Maintenance {
$fileName = $this->getArg( 0 );
$inFile = fopen( $fileName, 'r' );
if ( !$inFile ) {
- $this->error( "Unable to open input file \"$fileName\"" );
- exit( 1 );
+ $this->fatalError( "Unable to open input file \"$fileName\"" );
}
} else {
$inFile = STDIN;
@@ -52,8 +51,7 @@ class MaintenanceFormatInstallDoc extends Maintenance {
$fileName = $this->getOption( 'outfile' );
$outFile = fopen( $fileName, 'w' );
if ( !$outFile ) {
- $this->error( "Unable to open output file \"$fileName\"" );
- exit( 1 );
+ $this->fatalError( "Unable to open output file \"$fileName\"" );
}
} else {
$outFile = STDOUT;
@@ -74,5 +72,5 @@ class MaintenanceFormatInstallDoc extends Maintenance {
}
}
-$maintClass = 'MaintenanceFormatInstallDoc';
+$maintClass = MaintenanceFormatInstallDoc::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/generateJsonI18n.php b/www/wiki/maintenance/generateJsonI18n.php
index a84f2ae5..efddfb34 100644
--- a/www/wiki/maintenance/generateJsonI18n.php
+++ b/www/wiki/maintenance/generateJsonI18n.php
@@ -55,7 +55,7 @@ class GenerateJsonI18n extends Maintenance {
if ( $extension ) {
if ( $phpfile ) {
- $this->error( "The phpfile is already specified, conflicts with --extension.", 1 );
+ $this->fatalError( "The phpfile is already specified, conflicts with --extension." );
}
$phpfile = "$IP/extensions/$extension/$extension.i18n.php";
}
@@ -101,28 +101,28 @@ class GenerateJsonI18n extends Maintenance {
$this->output( "Creating directory $jsondir.\n" );
$success = mkdir( $jsondir );
if ( !$success ) {
- $this->error( "Could not create directory $jsondir", 1 );
+ $this->fatalError( "Could not create directory $jsondir" );
}
}
if ( !is_readable( $phpfile ) ) {
- $this->error( "Error reading $phpfile", 1 );
+ $this->fatalError( "Error reading $phpfile" );
}
$messages = null;
include $phpfile;
$phpfileContents = file_get_contents( $phpfile );
if ( !isset( $messages ) ) {
- $this->error( "PHP file $phpfile does not define \$messages array", 1 );
+ $this->fatalError( "PHP file $phpfile does not define \$messages array" );
}
if ( !$messages ) {
- $this->error( "PHP file $phpfile contains an empty \$messages array. " .
- "Maybe it was already converted?", 1 );
+ $this->fatalError( "PHP file $phpfile contains an empty \$messages array. " .
+ "Maybe it was already converted?" );
}
if ( !isset( $messages['en'] ) || !is_array( $messages['en'] ) ) {
- $this->error( "PHP file $phpfile does not set language codes", 1 );
+ $this->fatalError( "PHP file $phpfile does not set language codes" );
}
foreach ( $messages as $langcode => $langmsgs ) {
@@ -142,7 +142,7 @@ class GenerateJsonI18n extends Maintenance {
FormatJson::encode( $langmsgs, "\t", FormatJson::ALL_OK ) . "\n"
);
if ( $success === false ) {
- $this->error( "FAILED to write $jsonfile", 1 );
+ $this->fatalError( "FAILED to write $jsonfile" );
}
$this->output( "$jsonfile\n" );
}
@@ -192,5 +192,5 @@ class GenerateJsonI18n extends Maintenance {
}
}
-$maintClass = "GenerateJsonI18n";
+$maintClass = GenerateJsonI18n::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/generateLocalAutoload.php b/www/wiki/maintenance/generateLocalAutoload.php
index 0c278bc1..189858c5 100644
--- a/www/wiki/maintenance/generateLocalAutoload.php
+++ b/www/wiki/maintenance/generateLocalAutoload.php
@@ -1,15 +1,17 @@
<?php
-if ( PHP_SAPI != 'cli' ) {
+if ( PHP_SAPI != 'cli' && PHP_SAPI != 'phpdbg' ) {
die( "This script can only be run from the command line.\n" );
}
+require_once __DIR__ . '/../includes/AutoLoader.php';
require_once __DIR__ . '/../includes/utils/AutoloadGenerator.php';
// Mediawiki installation directory
$base = dirname( __DIR__ );
$generator = new AutoloadGenerator( $base, 'local' );
+$generator->setExcludePaths( array_values( AutoLoader::getAutoloadNamespaces() ) );
$generator->initMediaWikiDefault();
// Write out the autoload
diff --git a/www/wiki/maintenance/generateSitemap.php b/www/wiki/maintenance/generateSitemap.php
index 26a9c399..5a2c6c7b 100644
--- a/www/wiki/maintenance/generateSitemap.php
+++ b/www/wiki/maintenance/generateSitemap.php
@@ -182,7 +182,7 @@ class GenerateSitemap extends Maintenance {
# Create directory if needed
$fspath = $this->getOption( 'fspath', getcwd() );
if ( !wfMkdirParents( $fspath, null, __METHOD__ ) ) {
- $this->error( "Can not create directory $fspath.", 1 );
+ $this->fatalError( "Can not create directory $fspath." );
}
$this->fspath = realpath( $fspath ) . DIRECTORY_SEPARATOR;
@@ -440,8 +440,8 @@ class GenerateSitemap extends Maintenance {
/**
* Get a sitemap filename
*
- * @param int $namespace The namespace
- * @param int $count The count
+ * @param int $namespace
+ * @param int $count
* @return string
*/
function sitemapFilename( $namespace, $count ) {
@@ -484,8 +484,7 @@ class GenerateSitemap extends Maintenance {
* @return string
*/
function indexEntry( $filename ) {
- return
- "\t<sitemap>\n" .
+ return "\t<sitemap>\n" .
"\t\t<loc>{$this->urlpath}$filename</loc>\n" .
"\t\t<lastmod>{$this->timestamp}</lastmod>\n" .
"\t</sitemap>\n";
@@ -518,8 +517,7 @@ class GenerateSitemap extends Maintenance {
* @return string
*/
function fileEntry( $url, $date, $priority ) {
- return
- "\t<url>\n" .
+ return "\t<url>\n" .
// T36666: $url may contain bad characters such as ampersands.
"\t\t<loc>" . htmlspecialchars( $url ) . "</loc>\n" .
"\t\t<lastmod>$date</lastmod>\n" .
@@ -557,5 +555,5 @@ class GenerateSitemap extends Maintenance {
}
}
-$maintClass = "GenerateSitemap";
+$maintClass = GenerateSitemap::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/getConfiguration.php b/www/wiki/maintenance/getConfiguration.php
index 3c679e6e..de6e87a3 100644
--- a/www/wiki/maintenance/getConfiguration.php
+++ b/www/wiki/maintenance/getConfiguration.php
@@ -64,7 +64,7 @@ class GetConfiguration extends Maintenance {
$validFormat = in_array( $format, self::$outFormats );
if ( !$validFormat ) {
- $this->error( "--format set to an unrecognized format", 0 );
+ $this->error( "--format set to an unrecognized format" );
$error_out = true;
}
@@ -101,7 +101,7 @@ class GetConfiguration extends Maintenance {
foreach ( $this->settings_list as $name ) {
if ( !preg_match( '/^wg[A-Z]/', $name ) ) {
throw new MWException( "Variable '$name' does start with 'wg'." );
- } elseif ( !isset( $GLOBALS[$name] ) ) {
+ } elseif ( !array_key_exists( $name, $GLOBALS ) ) {
throw new MWException( "Variable '$name' is not set." );
} elseif ( !$this->isAllowedVariable( $GLOBALS[$name] ) ) {
throw new MWException( "Variable '$name' includes non-array, non-scalar, items." );
@@ -192,5 +192,5 @@ class GetConfiguration extends Maintenance {
}
}
-$maintClass = "GetConfiguration";
+$maintClass = GetConfiguration::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/getLagTimes.php b/www/wiki/maintenance/getLagTimes.php
index ad2fdf88..c2c79833 100644
--- a/www/wiki/maintenance/getLagTimes.php
+++ b/www/wiki/maintenance/getLagTimes.php
@@ -75,5 +75,5 @@ class GetLagTimes extends Maintenance {
}
}
-$maintClass = "GetLagTimes";
+$maintClass = GetLagTimes::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/getReplicaServer.php b/www/wiki/maintenance/getReplicaServer.php
index 6e0a1fec..43e876ea 100644
--- a/www/wiki/maintenance/getReplicaServer.php
+++ b/www/wiki/maintenance/getReplicaServer.php
@@ -51,5 +51,5 @@ class GetSlaveServer extends Maintenance {
}
}
-$maintClass = "GetSlaveServer";
+$maintClass = GetSlaveServer::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/getText.php b/www/wiki/maintenance/getText.php
index f519a790..2e8cf770 100644
--- a/www/wiki/maintenance/getText.php
+++ b/www/wiki/maintenance/getText.php
@@ -42,13 +42,13 @@ class GetTextMaint extends Maintenance {
$titleText = $this->getArg( 0 );
$title = Title::newFromText( $titleText );
if ( !$title ) {
- $this->error( "$titleText is not a valid title.\n", true );
+ $this->fatalError( "$titleText is not a valid title.\n" );
}
$rev = Revision::newFromTitle( $title );
if ( !$rev ) {
$titleText = $title->getPrefixedText();
- $this->error( "Page $titleText does not exist.\n", true );
+ $this->fatalError( "Page $titleText does not exist.\n" );
}
$content = $rev->getContent( $this->hasOption( 'show-private' )
? Revision::RAW
@@ -56,11 +56,11 @@ class GetTextMaint extends Maintenance {
if ( $content === false ) {
$titleText = $title->getPrefixedText();
- $this->error( "Couldn't extract the text from $titleText.\n", true );
+ $this->fatalError( "Couldn't extract the text from $titleText.\n" );
}
$this->output( $content->serialize() );
}
}
-$maintClass = "GetTextMaint";
+$maintClass = GetTextMaint::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/hhvm/makeRepo.php b/www/wiki/maintenance/hhvm/makeRepo.php
index c1aa0820..cef0dadc 100644
--- a/www/wiki/maintenance/hhvm/makeRepo.php
+++ b/www/wiki/maintenance/hhvm/makeRepo.php
@@ -97,7 +97,7 @@ class HHVMMakeRepo extends Maintenance {
$tmpDir = wfTempDir() . '/mw-make-repo' . mt_rand( 0, 1 << 31 );
if ( !mkdir( $tmpDir ) ) {
- $this->error( 'Unable to create temporary directory', 1 );
+ $this->fatalError( 'Unable to create temporary directory' );
}
file_put_contents( "$tmpDir/file-list", implode( "\n", $files ) );
@@ -119,11 +119,11 @@ class HHVMMakeRepo extends Maintenance {
passthru( $cmd, $ret );
if ( $ret ) {
$this->cleanupTemp( $tmpDir );
- $this->error( "Error: HHVM returned error code $ret", 1 );
+ $this->fatalError( "Error: HHVM returned error code $ret" );
}
if ( !rename( "$tmpDir/hhvm.hhbc", $this->getOption( 'output' ) ) ) {
$this->cleanupTemp( $tmpDir );
- $this->error( "Error: unable to rename output file", 1 );
+ $this->fatalError( "Error: unable to rename output file" );
}
$this->cleanupTemp( $tmpDir );
return 0;
@@ -157,5 +157,5 @@ class HHVMMakeRepo extends Maintenance {
}
}
-$maintClass = 'HHVMMakeRepo';
+$maintClass = HHVMMakeRepo::class;
require RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/hhvm/run-server b/www/wiki/maintenance/hhvm/run-server
index 2d71b871..d84e02f2 100755
--- a/www/wiki/maintenance/hhvm/run-server
+++ b/www/wiki/maintenance/hhvm/run-server
@@ -24,5 +24,5 @@ class RunHipHopServer extends Maintenance {
exit( $ret );
}
}
-$maintClass = 'RunHipHopServer';
+$maintClass = RunHipHopServer::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/hiphop/run-server b/www/wiki/maintenance/hiphop/run-server
deleted file mode 100755
index 2d71b871..00000000
--- a/www/wiki/maintenance/hiphop/run-server
+++ /dev/null
@@ -1,28 +0,0 @@
-#!/usr/bin/hhvm -f
-<?php
-
-require __DIR__ . '/../Maintenance.php';
-
-class RunHipHopServer extends Maintenance {
- function __construct() {
- parent::__construct();
- }
-
- function execute() {
- global $IP;
-
- passthru(
- 'cd ' . wfEscapeShellArg( $IP ) . " && " .
- wfEscapeShellArg(
- 'hhvm',
- '-c', __DIR__."/server.conf",
- '--mode=server',
- '--port=8080'
- ),
- $ret
- );
- exit( $ret );
- }
-}
-$maintClass = 'RunHipHopServer';
-require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/hiphop/server.conf b/www/wiki/maintenance/hiphop/server.conf
deleted file mode 100644
index 558bdad8..00000000
--- a/www/wiki/maintenance/hiphop/server.conf
+++ /dev/null
@@ -1,30 +0,0 @@
-Log {
- Level = Warning
- UseLogFile = true
- NativeStackTrace = true
- InjectedStackTrace = true
-}
-Debug {
- FullBacktrace = true
- ServerStackTrace = true
- ServerErrorMessage = true
- TranslateSource = true
-}
-Server {
- EnableStaticContentCache = false
- EnableStaticContentFromDisk = true
- AlwaysUseRelativePath = true
-}
-VirtualHost {
- * {
- ServerName = localhost
- Pattern = .
- RewriteRules {
- * {
- pattern = ^/wiki/(.*)$
- to = /index.php?title=$1
- qsa = true
- }
- }
- }
-}
diff --git a/www/wiki/maintenance/importDump.php b/www/wiki/maintenance/importDump.php
index 206c7ee6..965906f2 100644
--- a/www/wiki/maintenance/importDump.php
+++ b/www/wiki/maintenance/importDump.php
@@ -82,12 +82,18 @@ TEXT
);
$this->addOption( 'image-base-path', 'Import files from a specified path', false, true );
$this->addOption( 'skip-to', 'Start from nth page by skipping first n-1 pages', false, true );
+ $this->addOption( 'username-interwiki', 'Use interwiki usernames with this prefix', false, true );
+ $this->addOption( 'no-local-users',
+ 'Treat all usernames as interwiki. ' .
+ 'The default is to assign edits to local users where they exist.',
+ false, false
+ );
$this->addArg( 'file', 'Dump file to import [else use stdin]', false );
}
public function execute() {
if ( wfReadOnly() ) {
- $this->error( "Wiki is in read-only mode; you'll need to disable it for import to work.", true );
+ $this->fatalError( "Wiki is in read-only mode; you'll need to disable it for import to work." );
}
$this->reportingInterval = intval( $this->getOption( 'report', 100 ) );
@@ -134,11 +140,12 @@ TEXT
if ( strval( $ns ) === $namespace && $wgContLang->getNsText( $ns ) !== false ) {
return $ns;
}
- $this->error( "Unknown namespace text / index specified: $namespace", true );
+ $this->fatalError( "Unknown namespace text / index specified: $namespace" );
}
/**
* @param Title|Revision $obj
+ * @throws MWException
* @return bool
*/
private function skippedNamespace( $obj ) {
@@ -295,11 +302,17 @@ TEXT
if ( $this->hasOption( 'no-updates' ) ) {
$importer->setNoUpdates( true );
}
+ if ( $this->hasOption( 'username-prefix' ) ) {
+ $importer->setUsernamePrefix(
+ $this->getOption( 'username-prefix' ),
+ !$this->hasOption( 'no-local-users' )
+ );
+ }
if ( $this->hasOption( 'rootpage' ) ) {
$statusRootPage = $importer->setTargetRootPage( $this->getOption( 'rootpage' ) );
if ( !$statusRootPage->isGood() ) {
// Die here so that it doesn't print "Done!"
- $this->error( $statusRootPage->getMessage()->text(), 1 );
+ $this->fatalError( $statusRootPage->getMessage()->text() );
return false;
}
}
@@ -309,6 +322,9 @@ TEXT
$this->pageCount = $nthPage - 1;
}
$importer->setPageCallback( [ $this, 'reportPage' ] );
+ $importer->setNoticeCallback( function ( $msg, $params ) {
+ echo wfMessage( $msg, $params )->text() . "\n";
+ } );
$this->importCallback = $importer->setRevisionCallback(
[ $this, 'handleRevision' ] );
$this->uploadCallback = $importer->setUploadCallback(
@@ -330,5 +346,5 @@ TEXT
}
}
-$maintClass = 'BackupReader';
+$maintClass = BackupReader::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/importImages.inc b/www/wiki/maintenance/importImages.inc
deleted file mode 100644
index fc9428d7..00000000
--- a/www/wiki/maintenance/importImages.inc
+++ /dev/null
@@ -1,137 +0,0 @@
-<?php
-/**
- * Support functions for the importImages.php script
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup Maintenance
- * @author Rob Church <robchur@gmail.com>
- * @author Mij <mij@bitchx.it>
- */
-
-/**
- * Search a directory for files with one of a set of extensions
- *
- * @param string $dir Path to directory to search
- * @param array $exts Array of extensions to search for
- * @param bool $recurse Search subdirectories recursively
- * @return array|bool Array of filenames on success, or false on failure
- */
-function findFiles( $dir, $exts, $recurse = false ) {
- if ( is_dir( $dir ) ) {
- $dhl = opendir( $dir );
- if ( $dhl ) {
- $files = [];
- while ( ( $file = readdir( $dhl ) ) !== false ) {
- if ( is_file( $dir . '/' . $file ) ) {
- list( /* $name */, $ext ) = splitFilename( $dir . '/' . $file );
- if ( array_search( strtolower( $ext ), $exts ) !== false ) {
- $files[] = $dir . '/' . $file;
- }
- } elseif ( $recurse && is_dir( $dir . '/' . $file ) && $file !== '..' && $file !== '.' ) {
- $files = array_merge( $files, findFiles( $dir . '/' . $file, $exts, true ) );
- }
- }
-
- return $files;
- } else {
- return [];
- }
- } else {
- return [];
- }
-}
-
-/**
- * Split a filename into filename and extension
- *
- * @param string $filename Filename
- * @return array
- */
-function splitFilename( $filename ) {
- $parts = explode( '.', $filename );
- $ext = $parts[count( $parts ) - 1];
- unset( $parts[count( $parts ) - 1] );
- $fname = implode( '.', $parts );
-
- return [ $fname, $ext ];
-}
-
-/**
- * Find an auxilliary file with the given extension, matching
- * the give base file path. $maxStrip determines how many extensions
- * may be stripped from the original file name before appending the
- * new extension. For example, with $maxStrip = 1 (the default),
- * file files acme.foo.bar.txt and acme.foo.txt would be auxilliary
- * files for acme.foo.bar and the extension ".txt". With $maxStrip = 2,
- * acme.txt would also be acceptable.
- *
- * @param string $file Base path
- * @param string $auxExtension The extension to be appended to the base path
- * @param int $maxStrip The maximum number of extensions to strip from the base path (default: 1)
- * @return string|bool
- */
-function findAuxFile( $file, $auxExtension, $maxStrip = 1 ) {
- if ( strpos( $auxExtension, '.' ) !== 0 ) {
- $auxExtension = '.' . $auxExtension;
- }
-
- $d = dirname( $file );
- $n = basename( $file );
-
- while ( $maxStrip >= 0 ) {
- $f = $d . '/' . $n . $auxExtension;
-
- if ( file_exists( $f ) ) {
- return $f;
- }
-
- $idx = strrpos( $n, '.' );
- if ( !$idx ) {
- break;
- }
-
- $n = substr( $n, 0, $idx );
- $maxStrip -= 1;
- }
-
- return false;
-}
-
-# @todo FIXME: Access the api in a saner way and performing just one query
-# (preferably batching files too).
-function getFileCommentFromSourceWiki( $wiki_host, $file ) {
- $url = $wiki_host . '/api.php?action=query&format=xml&titles=File:'
- . rawurlencode( $file ) . '&prop=imageinfo&&iiprop=comment';
- $body = Http::get( $url, [], __METHOD__ );
- if ( preg_match( '#<ii comment="([^"]*)" />#', $body, $matches ) == 0 ) {
- return false;
- }
-
- return html_entity_decode( $matches[1] );
-}
-
-function getFileUserFromSourceWiki( $wiki_host, $file ) {
- $url = $wiki_host . '/api.php?action=query&format=xml&titles=File:'
- . rawurlencode( $file ) . '&prop=imageinfo&&iiprop=user';
- $body = Http::get( $url, [], __METHOD__ );
- if ( preg_match( '#<ii user="([^"]*)" />#', $body, $matches ) == 0 ) {
- return false;
- }
-
- return html_entity_decode( $matches[1] );
-}
diff --git a/www/wiki/maintenance/importImages.php b/www/wiki/maintenance/importImages.php
index 625e1f70..5db1fa89 100644
--- a/www/wiki/maintenance/importImages.php
+++ b/www/wiki/maintenance/importImages.php
@@ -133,11 +133,11 @@ class ImportImages extends Maintenance {
# Check Protection
if ( $this->hasOption( 'protect' ) && $this->hasOption( 'unprotect' ) ) {
- $this->error( "Cannot specify both protect and unprotect. Only 1 is allowed.\n", 1 );
+ $this->fatalError( "Cannot specify both protect and unprotect. Only 1 is allowed.\n" );
}
if ( $this->hasOption( 'protect' ) && trim( $this->getOption( 'protect' ) ) ) {
- $this->error( "You must specify a protection option.\n", 1 );
+ $this->fatalError( "You must specify a protection option.\n" );
}
# Prepare the list of allowed extensions
@@ -170,7 +170,7 @@ class ImportImages extends Maintenance {
if ( $commentFile !== null ) {
$comment = file_get_contents( $commentFile );
if ( $comment === false || $comment === null ) {
- $this->error( "failed to read comment file: {$commentFile}\n", 1 );
+ $this->fatalError( "failed to read comment file: {$commentFile}\n" );
}
} else {
$comment = $this->getOption( 'comment', 'Importing file' );
@@ -299,13 +299,13 @@ class ImportImages extends Maintenance {
" publishing {$file} by '{$wgUser->getName()}', comment '$commentText'... "
);
} else {
- $mwProps = new MWFileProps( MimeMagic::singleton() );
+ $mwProps = new MWFileProps( MediaWiki\MediaWikiServices::getInstance()->getMimeAnalyzer() );
$props = $mwProps->getPropsFromPath( $file, true );
$flags = 0;
$publishOptions = [];
$handler = MediaHandler::getHandler( $props['mime'] );
if ( $handler ) {
- $metadata = MediaWiki\quietCall( 'unserialize', $props['metadata'] );
+ $metadata = Wikimedia\quietCall( 'unserialize', $props['metadata'] );
$publishOptions['headers'] = $handler->getContentHeaders( $metadata );
} else {
@@ -334,7 +334,7 @@ class ImportImages extends Maintenance {
$commentText,
$props,
$timestamp
- ) ) {
+ )->isOK() ) {
# We're done!
$this->output( "done.\n" );
@@ -440,7 +440,7 @@ class ImportImages extends Maintenance {
/**
* Split a filename into filename and extension
*
- * @param string $filename Filename
+ * @param string $filename
* @return array
*/
private function splitFilename( $filename ) {
@@ -519,5 +519,5 @@ class ImportImages extends Maintenance {
}
-$maintClass = 'ImportImages';
+$maintClass = ImportImages::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/importSiteScripts.php b/www/wiki/maintenance/importSiteScripts.php
index 7fdb355a..e60e7763 100644
--- a/www/wiki/maintenance/importSiteScripts.php
+++ b/www/wiki/maintenance/importSiteScripts.php
@@ -114,5 +114,5 @@ class ImportSiteScripts extends Maintenance {
}
}
-$maintClass = 'ImportSiteScripts';
+$maintClass = ImportSiteScripts::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/importSites.php b/www/wiki/maintenance/importSites.php
index 57223442..be6cc052 100644
--- a/www/wiki/maintenance/importSites.php
+++ b/www/wiki/maintenance/importSites.php
@@ -50,5 +50,5 @@ class ImportSites extends Maintenance {
}
}
-$maintClass = 'ImportSites';
+$maintClass = ImportSites::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/importTextFiles.php b/www/wiki/maintenance/importTextFiles.php
index 816e7452..c99aa155 100644
--- a/www/wiki/maintenance/importTextFiles.php
+++ b/www/wiki/maintenance/importTextFiles.php
@@ -73,7 +73,7 @@ class ImportTextFiles extends Maintenance {
$files[$filename] = file_get_contents( $filename );
}
if ( !$found ) {
- $this->error( "Fatal error: The file '$arg' does not exist!", 1 );
+ $this->fatalError( "Fatal error: The file '$arg' does not exist!" );
}
}
};
@@ -88,7 +88,7 @@ class ImportTextFiles extends Maintenance {
}
if ( !$user ) {
- $this->error( "Invalid username\n", true );
+ $this->fatalError( "Invalid username\n" );
}
if ( $user->isAnon() ) {
$user->addToDatabase();
@@ -199,10 +199,10 @@ class ImportTextFiles extends Maintenance {
$this->output( "Done! $successCount succeeded, $skipCount skipped.\n" );
if ( $exit ) {
- $this->error( "Import failed with $failCount failed pages.\n", $exit );
+ $this->fatalError( "Import failed with $failCount failed pages.\n", $exit );
}
}
}
-$maintClass = "ImportTextFiles";
+$maintClass = ImportTextFiles::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/initEditCount.php b/www/wiki/maintenance/initEditCount.php
index 96aea034..f7ef7a28 100644
--- a/www/wiki/maintenance/initEditCount.php
+++ b/www/wiki/maintenance/initEditCount.php
@@ -38,9 +38,9 @@ in the load balancer, usually indicating a replication environment.' );
}
public function execute() {
+ global $wgActorTableSchemaMigrationStage;
+
$dbw = $this->getDB( DB_MASTER );
- $user = $dbw->tableName( 'user' );
- $revision = $dbw->tableName( 'revision' );
// Autodetect mode...
if ( $this->hasOption( 'background' ) ) {
@@ -51,6 +51,17 @@ in the load balancer, usually indicating a replication environment.' );
$backgroundMode = wfGetLB()->getServerCount() > 1;
}
+ $actorQuery = ActorMigration::newMigration()->getJoin( 'rev_user' );
+
+ $needSpecialQuery = ( $wgActorTableSchemaMigrationStage !== MIGRATION_OLD &&
+ $wgActorTableSchemaMigrationStage !== MIGRATION_NEW );
+ if ( $needSpecialQuery ) {
+ foreach ( $actorQuery['joins'] as &$j ) {
+ $j[0] = 'JOIN'; // replace LEFT JOIN
+ }
+ unset( $j );
+ }
+
if ( $backgroundMode ) {
$this->output( "Using replication-friendly background mode...\n" );
@@ -62,15 +73,55 @@ in the load balancer, usually indicating a replication environment.' );
$migrated = 0;
for ( $min = 0; $min <= $lastUser; $min += $chunkSize ) {
$max = $min + $chunkSize;
- $result = $dbr->query(
- "SELECT
- user_id,
- COUNT(rev_user) AS user_editcount
- FROM $user
- LEFT OUTER JOIN $revision ON user_id=rev_user
- WHERE user_id > $min AND user_id <= $max
- GROUP BY user_id",
- __METHOD__ );
+
+ if ( $needSpecialQuery ) {
+ // Use separate subqueries to collect counts with the old
+ // and new schemas, to avoid having to do whole-table scans.
+ $result = $dbr->select(
+ [
+ 'user',
+ 'rev1' => '('
+ . $dbr->selectSQLText(
+ [ 'revision', 'revision_actor_temp' ],
+ [ 'rev_user', 'ct' => 'COUNT(*)' ],
+ [
+ "rev_user > $min AND rev_user <= $max",
+ 'revactor_rev' => null,
+ ],
+ __METHOD__,
+ [ 'GROUP BY' => 'rev_user' ],
+ [ 'revision_actor_temp' => [ 'LEFT JOIN', 'revactor_rev = rev_id' ] ]
+ ) . ')',
+ 'rev2' => '('
+ . $dbr->selectSQLText(
+ [ 'revision' ] + $actorQuery['tables'],
+ [ 'actor_user', 'ct' => 'COUNT(*)' ],
+ "actor_user > $min AND actor_user <= $max",
+ __METHOD__,
+ [ 'GROUP BY' => 'actor_user' ],
+ $actorQuery['joins']
+ ) . ')',
+ ],
+ [ 'user_id', 'user_editcount' => 'COALESCE(rev1.ct,0) + COALESCE(rev2.ct,0)' ],
+ "user_id > $min AND user_id <= $max",
+ __METHOD__,
+ [],
+ [
+ 'rev1' => [ 'LEFT JOIN', 'user_id = rev_user' ],
+ 'rev2' => [ 'LEFT JOIN', 'user_id = actor_user' ],
+ ]
+ );
+ } else {
+ $revUser = $actorQuery['fields']['rev_user'];
+ $result = $dbr->select(
+ [ 'user', 'rev' => [ 'revision' ] + $actorQuery['tables'] ],
+ [ 'user_id', 'user_editcount' => "COUNT($revUser)" ],
+ "user_id > $min AND user_id <= $max",
+ __METHOD__,
+ [ 'GROUP BY' => 'user_id' ],
+ [ 'rev' => [ 'LEFT JOIN', "user_id = $revUser" ] ] + $actorQuery['joins']
+ );
+ }
foreach ( $result as $row ) {
$dbw->update( 'user',
@@ -93,13 +144,48 @@ in the load balancer, usually indicating a replication environment.' );
}
} else {
$this->output( "Using single-query mode...\n" );
- $sql = "UPDATE $user SET user_editcount=(SELECT COUNT(*) FROM $revision WHERE rev_user=user_id)";
- $dbw->query( $sql );
+
+ $user = $dbw->tableName( 'user' );
+ if ( $needSpecialQuery ) {
+ $subquery1 = $dbw->selectSQLText(
+ [ 'revision', 'revision_actor_temp' ],
+ [ 'COUNT(*)' ],
+ [
+ 'user_id = rev_user',
+ 'revactor_rev' => null,
+ ],
+ __METHOD__,
+ [],
+ [ 'revision_actor_temp' => [ 'LEFT JOIN', 'revactor_rev = rev_id' ] ]
+ );
+ $subquery2 = $dbw->selectSQLText(
+ [ 'revision' ] + $actorQuery['tables'],
+ [ 'COUNT(*)' ],
+ 'user_id = actor_user',
+ __METHOD__,
+ [],
+ $actorQuery['joins']
+ );
+ $dbw->query(
+ "UPDATE $user SET user_editcount=($subquery1) + ($subquery2)",
+ __METHOD__
+ );
+ } else {
+ $subquery = $dbw->selectSQLText(
+ [ 'revision' ] + $actorQuery['tables'],
+ [ 'COUNT(*)' ],
+ [ 'user_id = ' . $actorQuery['fields']['rev_user'] ],
+ __METHOD__,
+ [],
+ $actorQuery['joins']
+ );
+ $dbw->query( "UPDATE $user SET user_editcount=($subquery)", __METHOD__ );
+ }
}
$this->output( "Done!\n" );
}
}
-$maintClass = "InitEditCount";
+$maintClass = InitEditCount::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/initSiteStats.php b/www/wiki/maintenance/initSiteStats.php
index b2530ce6..297544dc 100644
--- a/www/wiki/maintenance/initSiteStats.php
+++ b/www/wiki/maintenance/initSiteStats.php
@@ -78,5 +78,5 @@ class InitSiteStats extends Maintenance {
}
}
-$maintClass = "InitSiteStats";
+$maintClass = InitSiteStats::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/initUserPreference.php b/www/wiki/maintenance/initUserPreference.php
index f4da570f..1ab880ce 100644
--- a/www/wiki/maintenance/initUserPreference.php
+++ b/www/wiki/maintenance/initUserPreference.php
@@ -46,7 +46,7 @@ class InitUserPreference extends Maintenance {
$dbr,
'user_properties',
[ 'up_user', 'up_property' ],
- $this->mBatchSize
+ $this->getBatchSize()
);
$iterator->setFetchColumns( [ 'up_user', 'up_value' ] );
$iterator->addConditions( [
@@ -80,5 +80,5 @@ class InitUserPreference extends Maintenance {
}
}
-$maintClass = 'InitUserPreference'; // Tells it to run the class
+$maintClass = InitUserPreference::class; // Tells it to run the class
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/install.php b/www/wiki/maintenance/install.php
index 0b3fc843..438e9dc4 100644
--- a/www/wiki/maintenance/install.php
+++ b/www/wiki/maintenance/install.php
@@ -134,11 +134,11 @@ class CommandLineInstaller extends Maintenance {
$this->error( 'WARNING: You have provided the options "dbpass" and "dbpassfile". '
. 'The content of "dbpassfile" overrides "dbpass".' );
}
- MediaWiki\suppressWarnings();
+ Wikimedia\suppressWarnings();
$dbpass = file_get_contents( $dbpassfile ); // returns false on failure
- MediaWiki\restoreWarnings();
+ Wikimedia\restoreWarnings();
if ( $dbpass === false ) {
- $this->error( "Couldn't open $dbpassfile", true );
+ $this->fatalError( "Couldn't open $dbpassfile" );
}
$this->mOptions['dbpass'] = trim( $dbpass, "\r\n" );
}
@@ -151,15 +151,15 @@ class CommandLineInstaller extends Maintenance {
$this->error( 'WARNING: You have provided the options "pass" and "passfile". '
. 'The content of "passfile" overrides "pass".' );
}
- MediaWiki\suppressWarnings();
+ Wikimedia\suppressWarnings();
$pass = file_get_contents( $passfile ); // returns false on failure
- MediaWiki\restoreWarnings();
+ Wikimedia\restoreWarnings();
if ( $pass === false ) {
- $this->error( "Couldn't open $passfile", true );
+ $this->fatalError( "Couldn't open $passfile" );
}
$this->mOptions['pass'] = trim( $pass, "\r\n" );
} elseif ( $this->getOption( 'pass' ) === null ) {
- $this->error( 'You need to provide the option "pass" or "passfile"', true );
+ $this->fatalError( 'You need to provide the option "pass" or "passfile"' );
}
}
@@ -170,6 +170,6 @@ class CommandLineInstaller extends Maintenance {
}
}
-$maintClass = 'CommandLineInstaller';
+$maintClass = CommandLineInstaller::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/interwiki.list b/www/wiki/maintenance/interwiki.list
index fa8bf3b8..5f87e16c 100644
--- a/www/wiki/maintenance/interwiki.list
+++ b/www/wiki/maintenance/interwiki.list
@@ -1,60 +1,60 @@
# Based more or less on the public interwiki map from MeatballWiki
# Default interwiki prefixes...
-acronym|http://www.acronymfinder.com/~/search/af.aspx?string=exact&Acronym=$1|0|
+acronym|https://www.acronymfinder.com/~/search/af.aspx?string=exact&Acronym=$1|0|
advogato|http://www.advogato.org/$1|0|
-arxiv|http://www.arxiv.org/abs/$1|0|
+arxiv|https://www.arxiv.org/abs/$1|0|
c2find|http://c2.com/cgi/wiki?FindPage&value=$1|0|
-cache|http://www.google.com/search?q=cache:$1|0|
+cache|https://www.google.com/search?q=cache:$1|0|
commons|https://commons.wikimedia.org/wiki/$1|0|https://commons.wikimedia.org/w/api.php
dictionary|http://www.dict.org/bin/Dict?Database=*&Form=Dict1&Strategy=*&Query=$1|0|
-doi|http://dx.doi.org/$1|0|
+doi|https://dx.doi.org/$1|0|
drumcorpswiki|http://www.drumcorpswiki.com/$1|0|http://drumcorpswiki.com/api.php
dwjwiki|http://www.suberic.net/cgi-bin/dwj/wiki.cgi?$1|0|
elibre|http://enciclopedia.us.es/index.php/$1|0|http://enciclopedia.us.es/api.php
-emacswiki|http://www.emacswiki.org/cgi-bin/wiki.pl?$1|0|
-foldoc|http://foldoc.org/?$1|0|
-foxwiki|http://fox.wikis.com/wc.dll?Wiki~$1|0|
-freebsdman|http://www.FreeBSD.org/cgi/man.cgi?apropos=1&query=$1|0|
+emacswiki|https://www.emacswiki.org/cgi-bin/wiki.pl?$1|0|
+foldoc|https://foldoc.org/?$1|0|
+foxwiki|https://fox.wikis.com/wc.dll?Wiki~$1|0|
+freebsdman|https://www.FreeBSD.org/cgi/man.cgi?apropos=1&query=$1|0|
gentoo-wiki|http://gentoo-wiki.com/$1|0|
-google|http://www.google.com/search?q=$1|0|
-googlegroups|http://groups.google.com/groups?q=$1|0|
+google|https://www.google.com/search?q=$1|0|
+googlegroups|https://groups.google.com/groups?q=$1|0|
hammondwiki|http://www.dairiki.org/HammondWiki/$1|0|
hrwiki|http://www.hrwiki.org/wiki/$1|0|http://www.hrwiki.org/w/api.php
imdb|http://www.imdb.com/find?q=$1&tt=on|0|
-kmwiki|http://kmwiki.wikispaces.com/$1|0|
+kmwiki|https://kmwiki.wikispaces.com/$1|0|
linuxwiki|http://linuxwiki.de/$1|0|
-lojban|http://mw.lojban.org/papri/$1|0|
+lojban|https://mw.lojban.org/papri/$1|0|
lqwiki|http://wiki.linuxquestions.org/wiki/$1|0|
meatball|http://www.usemod.com/cgi-bin/mb.pl?$1|0|
mediawikiwiki|https://www.mediawiki.org/wiki/$1|0|https://www.mediawiki.org/w/api.php
memoryalpha|http://en.memory-alpha.org/wiki/$1|0|http://en.memory-alpha.org/api.php
metawiki|http://sunir.org/apps/meta.pl?$1|0|
metawikimedia|https://meta.wikimedia.org/wiki/$1|0|https://meta.wikimedia.org/w/api.php
-mozillawiki|http://wiki.mozilla.org/$1|0|https://wiki.mozilla.org/api.php
+mozillawiki|https://wiki.mozilla.org/$1|0|https://wiki.mozilla.org/api.php
mw|https://www.mediawiki.org/wiki/$1|0|https://www.mediawiki.org/w/api.php
-oeis|http://oeis.org/$1|0|
+oeis|https://oeis.org/$1|0|
openwiki|http://openwiki.com/ow.asp?$1|0|
pmid|https://www.ncbi.nlm.nih.gov/pubmed/$1?dopt=Abstract|0|
-pythoninfo|http://wiki.python.org/moin/$1|0|
+pythoninfo|https://wiki.python.org/moin/$1|0|
rfc|https://tools.ietf.org/html/rfc$1|0|
s23wiki|http://s23.org/wiki/$1|0|http://s23.org/w/api.php
seattlewireless|http://seattlewireless.net/$1|0|
-senseislibrary|http://senseis.xmp.net/?$1|0|
+senseislibrary|https://senseis.xmp.net/?$1|0|
shoutwiki|http://www.shoutwiki.com/wiki/$1|0|http://www.shoutwiki.com/w/api.php
squeak|http://wiki.squeak.org/squeak/$1|0|
tmbw|http://www.tmbw.net/wiki/$1|0|http://tmbw.net/wiki/api.php
tmnet|http://www.technomanifestos.net/?$1|0|
-theopedia|http://www.theopedia.com/$1|0|
+theopedia|https://www.theopedia.com/$1|0|
twiki|http://twiki.org/cgi-bin/view/$1|0|
-uncyclopedia|http://en.uncyclopedia.co/wiki/$1|0|http://en.uncyclopedia.co/w/api.php
-unreal|http://wiki.beyondunreal.com/$1|0|http://wiki.beyondunreal.com/w/api.php
+uncyclopedia|https://en.uncyclopedia.co/wiki/$1|0|https://en.uncyclopedia.co/w/api.php
+unreal|https://wiki.beyondunreal.com/$1|0|https://wiki.beyondunreal.com/w/api.php
usemod|http://www.usemod.com/cgi-bin/wiki.pl?$1|0|
wiki|http://c2.com/cgi/wiki?$1|0|
wikia|http://www.wikia.com/wiki/$1|0|
wikibooks|https://en.wikibooks.org/wiki/$1|0|https://en.wikibooks.org/w/api.php
wikidata|https://www.wikidata.org/wiki/$1|0|https://www.wikidata.org/w/api.php
wikif1|http://www.wikif1.org/$1|0|
-wikihow|http://www.wikihow.com/$1|0|http://www.wikihow.com/api.php
+wikihow|https://www.wikihow.com/$1|0|https://www.wikihow.com/api.php
wikinfo|http://wikinfo.co/English/index.php/$1|0|
wikimedia|https://wikimediafoundation.org/wiki/$1|0|https://wikimediafoundation.org/w/api.php
wikinews|https://en.wikinews.org/wiki/$1|0|https://en.wikinews.org/w/api.php
diff --git a/www/wiki/maintenance/interwiki.sql b/www/wiki/maintenance/interwiki.sql
index adb6cd14..9e6072b7 100644
--- a/www/wiki/maintenance/interwiki.sql
+++ b/www/wiki/maintenance/interwiki.sql
@@ -2,61 +2,61 @@
-- Default interwiki prefixes...
REPLACE INTO /*$wgDBprefix*/interwiki (iw_prefix,iw_url,iw_local,iw_api) VALUES
-('acronym','http://www.acronymfinder.com/~/search/af.aspx?string=exact&Acronym=$1',0,''),
+('acronym','https://www.acronymfinder.com/~/search/af.aspx?string=exact&Acronym=$1',0,''),
('advogato','http://www.advogato.org/$1',0,''),
-('arxiv','http://www.arxiv.org/abs/$1',0,''),
+('arxiv','https://www.arxiv.org/abs/$1',0,''),
('c2find','http://c2.com/cgi/wiki?FindPage&value=$1',0,''),
-('cache','http://www.google.com/search?q=cache:$1',0,''),
+('cache','https://www.google.com/search?q=cache:$1',0,''),
('commons','https://commons.wikimedia.org/wiki/$1',0,'https://commons.wikimedia.org/w/api.php'),
('dictionary','http://www.dict.org/bin/Dict?Database=*&Form=Dict1&Strategy=*&Query=$1',0,''),
-('doi','http://dx.doi.org/$1',0,''),
+('doi','https://dx.doi.org/$1',0,''),
('drumcorpswiki','http://www.drumcorpswiki.com/$1',0,'http://drumcorpswiki.com/api.php'),
('dwjwiki','http://www.suberic.net/cgi-bin/dwj/wiki.cgi?$1',0,''),
('elibre','http://enciclopedia.us.es/index.php/$1',0,'http://enciclopedia.us.es/api.php'),
-('emacswiki','http://www.emacswiki.org/cgi-bin/wiki.pl?$1',0,''),
-('foldoc','http://foldoc.org/?$1',0,''),
-('foxwiki','http://fox.wikis.com/wc.dll?Wiki~$1',0,''),
-('freebsdman','http://www.FreeBSD.org/cgi/man.cgi?apropos=1&query=$1',0,''),
+('emacswiki','https://www.emacswiki.org/cgi-bin/wiki.pl?$1',0,''),
+('foldoc','https://foldoc.org/?$1',0,''),
+('foxwiki','https://fox.wikis.com/wc.dll?Wiki~$1',0,''),
+('freebsdman','https://www.FreeBSD.org/cgi/man.cgi?apropos=1&query=$1',0,''),
('gentoo-wiki','http://gentoo-wiki.com/$1',0,''),
-('google','http://www.google.com/search?q=$1',0,''),
-('googlegroups','http://groups.google.com/groups?q=$1',0,''),
+('google','https://www.google.com/search?q=$1',0,''),
+('googlegroups','https://groups.google.com/groups?q=$1',0,''),
('hammondwiki','http://www.dairiki.org/HammondWiki/$1',0,''),
('hrwiki','http://www.hrwiki.org/wiki/$1',0,'http://www.hrwiki.org/w/api.php'),
('imdb','http://www.imdb.com/find?q=$1&tt=on',0,''),
-('kmwiki','http://kmwiki.wikispaces.com/$1',0,''),
+('kmwiki','https://kmwiki.wikispaces.com/$1',0,''),
('linuxwiki','http://linuxwiki.de/$1',0,''),
-('lojban','http://www.lojban.org/tiki/tiki-index.php?page=$1',0,''),
+('lojban','https://www.lojban.org/tiki/tiki-index.php?page=$1',0,''),
('lqwiki','http://wiki.linuxquestions.org/wiki/$1',0,''),
('meatball','http://www.usemod.com/cgi-bin/mb.pl?$1',0,''),
('mediawikiwiki','https://www.mediawiki.org/wiki/$1',0,'https://www.mediawiki.org/w/api.php'),
('memoryalpha','http://en.memory-alpha.org/wiki/$1',0,'http://en.memory-alpha.org/api.php'),
('metawiki','http://sunir.org/apps/meta.pl?$1',0,''),
('metawikimedia','https://meta.wikimedia.org/wiki/$1',0,'https://meta.wikimedia.org/w/api.php'),
-('mozillawiki','http://wiki.mozilla.org/$1',0,'https://wiki.mozilla.org/api.php'),
+('mozillawiki','https://wiki.mozilla.org/$1',0,'https://wiki.mozilla.org/api.php'),
('mw','https://www.mediawiki.org/wiki/$1',0,'https://www.mediawiki.org/w/api.php'),
-('oeis','http://oeis.org/$1',0,''),
+('oeis','https://oeis.org/$1',0,''),
('openwiki','http://openwiki.com/ow.asp?$1',0,''),
('pmid', 'https://www.ncbi.nlm.nih.gov/pubmed/$1?dopt=Abstract',0,''),
-('pythoninfo','http://wiki.python.org/moin/$1',0,''),
+('pythoninfo','https://wiki.python.org/moin/$1',0,''),
('rfc','https://tools.ietf.org/html/rfc$1',0,''),
('s23wiki','http://s23.org/wiki/$1',0,'http://s23.org/w/api.php'),
('seattlewireless','http://seattlewireless.net/$1',0,''),
-('senseislibrary','http://senseis.xmp.net/?$1',0,''),
+('senseislibrary','https://senseis.xmp.net/?$1',0,''),
('shoutwiki','http://www.shoutwiki.com/wiki/$1',0,'http://www.shoutwiki.com/w/api.php'),
('squeak','http://wiki.squeak.org/squeak/$1',0,''),
('tmbw','http://www.tmbw.net/wiki/$1',0,'http://tmbw.net/wiki/api.php'),
('tmnet','http://www.technomanifestos.net/?$1',0,''),
-('theopedia','http://www.theopedia.com/$1',0,''),
+('theopedia','https://www.theopedia.com/$1',0,''),
('twiki','http://twiki.org/cgi-bin/view/$1',0,''),
-('uncyclopedia','http://en.uncyclopedia.co/wiki/$1',0,'http://en.uncyclopedia.co/w/api.php'),
-('unreal','http://wiki.beyondunreal.com/$1',0,'http://wiki.beyondunreal.com/w/api.php'),
+('uncyclopedia','https://en.uncyclopedia.co/wiki/$1',0,'https://en.uncyclopedia.co/w/api.php'),
+('unreal','https://wiki.beyondunreal.com/$1',0,'https://wiki.beyondunreal.com/w/api.php'),
('usemod','http://www.usemod.com/cgi-bin/wiki.pl?$1',0,''),
('wiki','http://c2.com/cgi/wiki?$1',0,''),
('wikia','http://www.wikia.com/wiki/$1',0,''),
('wikibooks','https://en.wikibooks.org/wiki/$1',0,'https://en.wikibooks.org/w/api.php'),
('wikidata','https://www.wikidata.org/wiki/$1',0,'https://www.wikidata.org/w/api.php'),
('wikif1','http://www.wikif1.org/$1',0,''),
-('wikihow','http://www.wikihow.com/$1',0,'http://www.wikihow.com/api.php'),
+('wikihow','https://www.wikihow.com/$1',0,'https://www.wikihow.com/api.php'),
('wikinfo','http://wikinfo.co/English/index.php/$1',0,''),
('wikimedia','https://wikimediafoundation.org/wiki/$1',0,'https://wikimediafoundation.org/w/api.php'),
('wikinews','https://en.wikinews.org/wiki/$1',0,'https://en.wikinews.org/w/api.php'),
diff --git a/www/wiki/maintenance/invalidateUserSessions.php b/www/wiki/maintenance/invalidateUserSessions.php
index 11e3372c..8d877a52 100644
--- a/www/wiki/maintenance/invalidateUserSessions.php
+++ b/www/wiki/maintenance/invalidateUserSessions.php
@@ -49,9 +49,9 @@ class InvalidateUserSesssions extends Maintenance {
$file = $this->getOption( 'file' );
if ( $username === null && $file === null ) {
- $this->error( 'Either --user or --file is required', 1 );
+ $this->fatalError( 'Either --user or --file is required' );
} elseif ( $username !== null && $file !== null ) {
- $this->error( 'Cannot use both --user and --file', 1 );
+ $this->fatalError( 'Cannot use both --user and --file' );
}
if ( $username !== null ) {
@@ -60,7 +60,7 @@ class InvalidateUserSesssions extends Maintenance {
$usernames = is_readable( $file ) ?
file( $file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES ) : false;
if ( $usernames === false ) {
- $this->error( "Could not open $file", 2 );
+ $this->fatalError( "Could not open $file", 2 );
}
}
@@ -83,12 +83,12 @@ class InvalidateUserSesssions extends Maintenance {
. str_replace( [ "\r", "\n" ], ' ', $e->getMessage() ) . "\n" );
}
- if ( $i % $this->mBatchSize ) {
+ if ( $i % $this->getBatchSize() ) {
$lbFactory->waitForReplication();
}
}
}
}
-$maintClass = "InvalidateUserSesssions";
+$maintClass = InvalidateUserSesssions::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/jsduck/categories.json b/www/wiki/maintenance/jsduck/categories.json
index 899d80da..bebee85f 100644
--- a/www/wiki/maintenance/jsduck/categories.json
+++ b/www/wiki/maintenance/jsduck/categories.json
@@ -23,6 +23,7 @@
"mw.Title",
"mw.Uri",
"mw.RegExp",
+ "mw.String",
"mw.messagePoster.*",
"mw.notification",
"mw.Notification_",
@@ -34,7 +35,8 @@
"mw.cookie",
"mw.experiments",
"mw.viewport",
- "mw.htmlform.*"
+ "mw.htmlform.*",
+ "mw.visibleTimeout"
]
},
{
@@ -54,12 +56,6 @@
]
},
{
- "name": "Page",
- "classes": [
- "mw.page*"
- ]
- },
- {
"name": "Interfaces",
"classes": [
"mw.Feedback*",
diff --git a/www/wiki/maintenance/jsparse.php b/www/wiki/maintenance/jsparse.php
index 49b945cb..661ec986 100644
--- a/www/wiki/maintenance/jsparse.php
+++ b/www/wiki/maintenance/jsparse.php
@@ -47,9 +47,9 @@ class JSParseHelper extends Maintenance {
$parser = new JSParser();
foreach ( $files as $filename ) {
- MediaWiki\suppressWarnings();
+ Wikimedia\suppressWarnings();
$js = file_get_contents( $filename );
- MediaWiki\restoreWarnings();
+ Wikimedia\restoreWarnings();
if ( $js === false ) {
$this->output( "$filename ERROR: could not read file\n" );
$this->errs++;
@@ -73,5 +73,5 @@ class JSParseHelper extends Maintenance {
}
}
-$maintClass = "JSParseHelper";
+$maintClass = JSParseHelper::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/lag.php b/www/wiki/maintenance/lag.php
index fa2bd54e..f041e15c 100644
--- a/www/wiki/maintenance/lag.php
+++ b/www/wiki/maintenance/lag.php
@@ -68,5 +68,5 @@ class DatabaseLag extends Maintenance {
}
}
-$maintClass = "DatabaseLag";
+$maintClass = DatabaseLag::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/language/StatOutputs.php b/www/wiki/maintenance/language/StatOutputs.php
index 15ccb2db..723ea62c 100644
--- a/www/wiki/maintenance/language/StatOutputs.php
+++ b/www/wiki/maintenance/language/StatOutputs.php
@@ -26,9 +26,9 @@
/** A general output object. Need to be overridden */
class StatsOutput {
function formatPercent( $subset, $total, $revert = false, $accuracy = 2 ) {
- MediaWiki\suppressWarnings();
+ Wikimedia\suppressWarnings();
$return = sprintf( '%.' . $accuracy . 'f%%', 100 * $subset / $total );
- MediaWiki\restoreWarnings();
+ Wikimedia\restoreWarnings();
return $return;
}
@@ -92,9 +92,9 @@ class WikiStatsOutput extends StatsOutput {
}
function formatPercent( $subset, $total, $revert = false, $accuracy = 2 ) {
- MediaWiki\suppressWarnings();
+ Wikimedia\suppressWarnings();
$v = round( 255 * $subset / $total );
- MediaWiki\restoreWarnings();
+ Wikimedia\restoreWarnings();
if ( $revert ) {
# Weigh reverse with factor 20 so coloring takes effect more quickly as
diff --git a/www/wiki/maintenance/language/alltrans.php b/www/wiki/maintenance/language/alltrans.php
index 931718f5..684f4d2e 100644
--- a/www/wiki/maintenance/language/alltrans.php
+++ b/www/wiki/maintenance/language/alltrans.php
@@ -43,5 +43,5 @@ class AllTrans extends Maintenance {
}
}
-$maintClass = "AllTrans";
+$maintClass = AllTrans::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/language/checkLanguage.inc b/www/wiki/maintenance/language/checkLanguage.inc
index 9e9fd3ee..007ced15 100644
--- a/www/wiki/maintenance/language/checkLanguage.inc
+++ b/www/wiki/maintenance/language/checkLanguage.inc
@@ -332,9 +332,8 @@ ENDS;
return $blacklist;
}
- // @codingStandardsIgnoreStart Ignore that globals should have a "wg" prefix.
+ // phpcs:ignore MediaWiki.NamingConventions.ValidGlobalName.wgPrefix
global $checkBlacklist;
- // @codingStandardsIgnoreEnd
$blacklist = $checkBlacklist;
@@ -517,7 +516,7 @@ ENDS;
$tableRows = implode( "\n|-\n", $rows );
$version = SpecialVersion::getVersion( 'nodb' );
- // @codingStandardsIgnoreStart Long line.
+ // phpcs:disable Generic.Files.LineLength
echo <<<EOL
'''Check results are for:''' <code>$version</code>
@@ -529,7 +528,7 @@ $tableRows
$detailText
EOL;
- // @codingStandardsIgnoreEnd
+ // phpcs:enable
}
/**
diff --git a/www/wiki/maintenance/language/date-formats.php b/www/wiki/maintenance/language/date-formats.php
index 2142c245..f93c506a 100644
--- a/www/wiki/maintenance/language/date-formats.php
+++ b/www/wiki/maintenance/language/date-formats.php
@@ -78,5 +78,5 @@ class DateFormats extends Maintenance {
}
}
-$maintClass = "DateFormats";
+$maintClass = DateFormats::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/language/digit2html.php b/www/wiki/maintenance/language/digit2html.php
index bb1f3d24..f1e74ad9 100644
--- a/www/wiki/maintenance/language/digit2html.php
+++ b/www/wiki/maintenance/language/digit2html.php
@@ -57,7 +57,7 @@ class Digit2Html extends Maintenance {
$this->output( "OK\n\$digitTransformTable = [\n" );
foreach ( $digitTransformTable as $latin => $translation ) {
- $htmlent = utf8ToHexSequence( $translation );
+ $htmlent = bin2hex( $translation );
$this->output( "'$latin' => '$translation', # &#x$htmlent;\n" );
}
$this->output( "];\n" );
@@ -65,5 +65,5 @@ class Digit2Html extends Maintenance {
}
}
-$maintClass = "Digit2Html";
+$maintClass = Digit2Html::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/language/dumpMessages.php b/www/wiki/maintenance/language/dumpMessages.php
index 37c87a8a..543ee063 100644
--- a/www/wiki/maintenance/language/dumpMessages.php
+++ b/www/wiki/maintenance/language/dumpMessages.php
@@ -48,5 +48,5 @@ class DumpMessages extends Maintenance {
}
}
-$maintClass = "DumpMessages";
+$maintClass = DumpMessages::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/language/generateCollationData.php b/www/wiki/maintenance/language/generateCollationData.php
index ccfece01..fafc1c6c 100644
--- a/www/wiki/maintenance/language/generateCollationData.php
+++ b/www/wiki/maintenance/language/generateCollationData.php
@@ -131,16 +131,14 @@ class GenerateCollationData extends Maintenance {
$error .= "* $ucdallURL\n";
}
- $this->error( $error );
- exit( 1 );
+ $this->fatalError( $error );
}
$debugOutFileName = $this->getOption( 'debug-output' );
if ( $debugOutFileName ) {
$this->debugOutFile = fopen( $debugOutFileName, 'w' );
if ( !$this->debugOutFile ) {
- $this->error( "Unable to open debug output file for writing" );
- exit( 1 );
+ $this->fatalError( "Unable to open debug output file for writing" );
}
}
$this->loadUcd();
@@ -205,14 +203,12 @@ class GenerateCollationData extends Maintenance {
function generateFirstChars() {
$file = fopen( "{$this->dataDir}/allkeys.txt", 'r' );
if ( !$file ) {
- $this->error( "Unable to open allkeys.txt" );
- exit( 1 );
+ $this->fatalError( "Unable to open allkeys.txt" );
}
global $IP;
$outFile = fopen( "$IP/serialized/first-letters-root.ser", 'w' );
if ( !$outFile ) {
- $this->error( "Unable to open output file first-letters-root.ser" );
- exit( 1 );
+ $this->fatalError( "Unable to open output file first-letters-root.ser" );
}
$goodTertiaryChars = [];
@@ -327,11 +323,6 @@ class GenerateCollationData extends Maintenance {
$headerChars[] = $char;
if ( $primaryCollator->compare( $char, $prevChar ) <= 0 ) {
$numOutOfOrder++;
- /*
- printf( "Out of order: U+%05X > U+%05X\n",
- utf8ToCodepoint( $prevChar ),
- utf8ToCodepoint( $char ) );
- */
}
$prevChar = $char;
@@ -468,5 +459,5 @@ class UcdXmlReader {
}
}
-$maintClass = 'GenerateCollationData';
+$maintClass = GenerateCollationData::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/language/generateNormalizerDataAr.php b/www/wiki/maintenance/language/generateNormalizerDataAr.php
index 34903de1..90ca41e2 100644
--- a/www/wiki/maintenance/language/generateNormalizerDataAr.php
+++ b/www/wiki/maintenance/language/generateNormalizerDataAr.php
@@ -46,22 +46,19 @@ class GenerateNormalizerDataAr extends Maintenance {
if ( !$this->hasOption( 'unicode-data-file' ) ) {
$dataFile = 'UnicodeData.txt';
if ( !file_exists( $dataFile ) ) {
- $this->error( "Unable to find UnicodeData.txt. Please specify " .
+ $this->fatalError( "Unable to find UnicodeData.txt. Please specify " .
"its location with --unicode-data-file=<FILE>" );
- exit( 1 );
}
} else {
$dataFile = $this->getOption( 'unicode-data-file' );
if ( !file_exists( $dataFile ) ) {
- $this->error( 'Unable to find the specified data file.' );
- exit( 1 );
+ $this->fatalError( 'Unable to find the specified data file.' );
}
}
$file = fopen( $dataFile, 'r' );
if ( !$file ) {
- $this->error( 'Unable to open the data file.' );
- exit( 1 );
+ $this->fatalError( 'Unable to open the data file.' );
}
// For the file format, see http://www.unicode.org/reports/tr44/
@@ -130,5 +127,5 @@ class GenerateNormalizerDataAr extends Maintenance {
}
}
-$maintClass = 'GenerateNormalizerDataAr';
+$maintClass = GenerateNormalizerDataAr::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/language/generateNormalizerDataMl.php b/www/wiki/maintenance/language/generateNormalizerDataMl.php
index a84ffb0e..664f06ce 100644
--- a/www/wiki/maintenance/language/generateNormalizerDataMl.php
+++ b/www/wiki/maintenance/language/generateNormalizerDataMl.php
@@ -66,5 +66,5 @@ class GenerateNormalizerDataMl extends Maintenance {
}
}
-$maintClass = 'GenerateNormalizerDataMl';
+$maintClass = GenerateNormalizerDataMl::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/language/langmemusage.php b/www/wiki/maintenance/language/langmemusage.php
index 7c16602e..6f2c6ad5 100644
--- a/www/wiki/maintenance/language/langmemusage.php
+++ b/www/wiki/maintenance/language/langmemusage.php
@@ -40,7 +40,7 @@ class LangMemUsage extends Maintenance {
public function execute() {
if ( !function_exists( 'memory_get_usage' ) ) {
- $this->error( "You must compile PHP with --enable-memory-limit", true );
+ $this->fatalError( "You must compile PHP with --enable-memory-limit" );
}
$langtool = new Languages();
@@ -61,5 +61,5 @@ class LangMemUsage extends Maintenance {
}
}
-$maintClass = "LangMemUsage";
+$maintClass = LangMemUsage::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/language/languages.inc b/www/wiki/maintenance/language/languages.inc
index ad80af53..c8fb629e 100644
--- a/www/wiki/maintenance/language/languages.inc
+++ b/www/wiki/maintenance/language/languages.inc
@@ -558,7 +558,7 @@ class Languages {
}
if ( isset( $messages[$key] ) ) {
- $messages[$key] = implode( $messages[$key], ", " );
+ $messages[$key] = implode( ", ", $messages[$key] );
}
}
diff --git a/www/wiki/maintenance/language/listVariants.php b/www/wiki/maintenance/language/listVariants.php
index e8d0e768..4098e0cd 100644
--- a/www/wiki/maintenance/language/listVariants.php
+++ b/www/wiki/maintenance/language/listVariants.php
@@ -69,5 +69,5 @@ class ListVariants extends Maintenance {
}
}
-$maintClass = 'ListVariants';
+$maintClass = ListVariants::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/language/transstat.php b/www/wiki/maintenance/language/transstat.php
index 72029523..986fa62b 100644
--- a/www/wiki/maintenance/language/transstat.php
+++ b/www/wiki/maintenance/language/transstat.php
@@ -42,7 +42,7 @@ if ( !isset( $options['output'] ) ) {
$options['output'] = 'wiki';
}
-/** Print a usage message*/
+/** Print a usage message */
function showUsage() {
print <<<TEXT
Usage: php transstat.php [--help] [--output=csv|text|wiki]
diff --git a/www/wiki/maintenance/language/zhtable/simp2trad.manual b/www/wiki/maintenance/language/zhtable/simp2trad.manual
index 9fee611c..e81eec0b 100644
--- a/www/wiki/maintenance/language/zhtable/simp2trad.manual
+++ b/www/wiki/maintenance/language/zhtable/simp2trad.manual
@@ -1,3 +1,5 @@
+U+04724䜤|U+09FC1鿁|
+U+04CA4䲤|U+09FD0鿐|
U+04E07万|U+0842C萬|U+04E07万|
U+04E0E与|U+08207與|U+04E0E与|
U+04E11丑|U+04E11丑|U+0919C醜|
@@ -112,6 +114,7 @@ U+0636E据|U+064DA據|U+0636E据|
U+06597斗|U+06597斗|U+09B25鬥|
U+065CB旋|U+065CB旋|U+0955F镟|
U+065D7旗|U+065D7旗|U+065C2旂|
+U+06606昆|U+06606昆|U+05D11崑|U+05D10崐|
U+066F2曲|U+066F2曲|U+09EAF麯|U+09EB4麯|
U+0672F术|U+08853術|U+0672E朮|
U+06731朱|U+06731朱|U+07843硃|
@@ -138,8 +141,8 @@ U+06E16渖|U+0700B瀋|
U+06E38游|U+06E38游|U+0904A遊|
U+06EAF溯|U+06EAF溯|U+06CDD泝|
U+06F13漓|U+06F13漓|U+07055灕|
-U+070BC炼|U+07149煉|U+0934A鍊|
U+07096炖|U+071C9燉|
+U+070BC炼|U+07149煉|U+0934A鍊|
U+0753B画|U+0756B畫|U+07575畵|
U+075C7症|U+075C7症|U+07665癥|
U+07618瘘|U+0763A瘺|U+0763B瘻|
@@ -165,6 +168,7 @@ U+07EFF绿|U+07DA0綠|U+07DD1緑|
U+07F10缐|U+07DDA線|
U+07F30缰|U+097C1韁|U+07E6E繮|
U+07FA1羡|U+07FA8羨|
+U+080C4胄|U+080C4胄|U+05191冑|
U+080DC胜|U+052DD勝|U+080DC胜|
U+080E1胡|U+080E1胡|U+09B0D鬍|U+0885A衚|
U+0810F脏|U+09AD2髒|U+081DF臟|
@@ -212,10 +216,10 @@ U+09528锨|U+06774杴|U+09341鍁|
U+0954B镋|U+09482钂|U+093B2鎲|
U+0954C镌|U+0942B鐫|U+093B8鎸|
U+09562镢|U+09481钁|U+0941D鐝|
+U+095F2闲|U+09592閒|U+09591閑|
U+09605阅|U+095B1閱|U+095B2閲|
U+096C7雇|U+096C7雇|U+050F1僱|
U+096D5雕|U+096D5雕|U+09D70鵰|
-U+095F2闲|U+09592閒|U+09591閑|
U+09709霉|U+09709霉|U+09EF4黴|
U+09762面|U+09762面|U+09EB5麵|U+09EAA麪|U+09EAB麫|
U+0987B须|U+09808須|U+09B1A鬚|
@@ -225,11 +229,185 @@ U+09965饥|U+098E2飢|U+09951饑|
U+09980馀|U+09918餘|
U+09986馆|U+09928館|U+08218舘|
U+09A82骂|U+07F75罵|U+099E1駡|
-U+09CC1鳁|U+09C2E鰮|
U+09C87鲇|U+09BF0鯰|U+09B8E鮎|
U+09C9E鲞|U+09BD7鯗|U+09B9D鮝|
+U+09CC1鳁|U+09C2E鰮|
U+09CC4鳄|U+09C77鱷|U+09C10鰐|
U+09E21鸡|U+096DE雞|U+09DC4鷄|
U+09E5A鹚|U+09DBF鶿|U+09DC0鷀|
U+09EB9麹|U+09EB4麴|
-U+080C4胄|U+080C4胄|U+05191冑|
+U+09FCE鿎|U+040EE䃮|
+U+09FCF鿏|U+04951䥑|
+U+09FD2鿒|U+09FD3鿓|
+U+09FD4鿔|U+093B6鎶|
+U+235CB𣗋|U+06B13欓|
+U+23C97𣲗|U+06E4B湋|
+U+23C98𣲘|U+06F55潕|
+U+23E23𣸣|U+06FC6濆|
+U+24A7D𤩽|U+074DB瓛|
+U+26221𦈡|U+07E7B繻|
+U+2677C𦝼|U+081A2膢|
+U+28408𨐈|U+08F04輄|
+U+28C47𨱇|U+092B6銶|
+U+28C4F𨱏|U+0939D鎝|
+U+28C51𨱑|U+09404鐄|
+U+28C54𨱔|U+0940F鐏|
+U+29F7E𩽾|U+09B9F鮟|
+U+29F83𩾃|U+09BB8鮸|
+U+29F8C𩾌|U+09C47鱇|
+U+2A7DD𪟝|U+052E3勣|
+U+2A8FB𪣻|U+0587F塿|
+U+2AA36𪨶|U+08F0B輋|
+U+2AA58𪩘|U+05DD8巘|
+U+2AFA2𪾢|U+0774D睍|
+U+2B127𫄧|U+07D96綖|
+U+2B128𫄨|U+07D7A絺|
+U+2B137𫄷|U+07E76繶|
+U+2B138𫄸|U+07E81纁|
+U+2B1ED𫇭|U+0853F蔿|
+U+2B300𫌀|U+08940襀|
+U+2B363𫍣|U+08A77詷|
+U+2B36F𫍯|U+08AF4諴|
+U+2B372𫍲|U+08B0F謏|
+U+2B37D𫍽|U+08B5E譞|
+U+2B404𫐄|U+08ECF軏|
+U+2B410𫐐|U+08F17輗|
+U+2B413𫐓|U+08F2E輮|
+U+2B461𫑡|U+09133鄳|
+U+2B4E7𫓧|U+09207鈇|
+U+2B4EF𫓯|U+09288銈|
+U+2B4F6𫓶|U+092D7鋗|
+U+2B4F9𫓹|U+09324錤|
+U+2B50D𫔍|U+09407鐇|
+U+2B50E𫔎|U+0940D鐍|
+U+2B536𫔶|U+095D1闑|
+U+2B5AE𫖮|U+09857顗|
+U+2B5AF𫖯|U+0982B頫|
+U+2B5B3𫖳|U+09835頵|
+U+2B5E7𫗧|U+09917餗|
+U+2B5F4𫗴|U+09958饘|
+U+2B61C𫘜|U+099BC馼|
+U+2B61D𫘝|U+099C3駃|
+U+2B626𫘦|U+09A0A騊|
+U+2B627𫘧|U+09A04騄|
+U+2B628𫘨|U+09A20騠|
+U+2B62A𫘪|U+09A35騵|
+U+2B62C𫘬|U+09A31騱|
+U+2B695𫚕|U+09C24鰤|
+U+2B696𫚖|U+09B86鮆|
+U+2B6AD𫚭|U+09C72鱲|
+U+2B6ED𫛭|U+09D5F鵟|
+U+2B7A9𫞩|U+0748A璊|
+U+2B7C5𫟅|U+07DA1綡|
+U+2B7E6𫟦|U+04875䡵|
+U+2B7F9𫟹|U+09277鉷|
+U+2B7FC𫟼|U+0943D鐽|
+U+2B806𫠆|U+0980D頍|
+U+2B80A𫠊|U+04B84䮄|
+U+2B81C𫠜|U+09F6F齯|
+U+2B8B8𫢸|U+050E4僤|
+U+2BAC7𫫇|U+05641噁|
+U+2BB5F𫭟|U+05878塸|
+U+2BB62𫭢|U+057E8埨|
+U+2BB7C𫭼|U+2144D𡑍|
+U+2BB83𫮃|U+058A0墠|
+U+2BC1B𫰛|U+05A19娙|
+U+2BD77𫵷|U+03823㠣|
+U+2BD87𫶇|U+05D7D嵽|
+U+2BDF7𫷷|U+05EDE廞|
+U+2BE29𫸩|U+05F44彄|
+U+2C029𬀩|U+06690暐|
+U+2C02A𬀪|U+0665B晛|
+U+2C0A9𬂩|U+0689C梜|
+U+2C0CA𬃊|U+06ACD櫍|
+U+2C1D5𬇕|U+06FAB澫|
+U+2C1D9𬇙|U+06D7F浿|
+U+2C1F9𬇹|U+06F0D漍|
+U+2C27C𬉼|U+071B0熰|
+U+2C288𬊈|U+071D6燖|
+U+2C2A4𬊤|U+071C0燀|
+U+2C35B𬍛|U+074C5瓅|
+U+2C361𬍡|U+07497璗|
+U+2C364𬍤|U+07495璕|
+U+2C488𬒈|U+07910礐|
+U+2C497𬒗|U+255FD𥗽|
+U+2C542𬕂|U+07BE2篢|
+U+2C613𬘓|U+07D03紃|
+U+2C618𬘘|U+07D1E紞|
+U+2C621𬘡|U+07D6A絪|
+U+2C629𬘩|U+07D8E綎|
+U+2C62B𬘫|U+07D84綄|
+U+2C62C𬘬|U+07DAA綪|
+U+2C62D𬘭|U+07D9D綝|
+U+2C62F𬘯|U+07DA7綧|
+U+2C642𬙂|U+07E2F縯|
+U+2C64A𬙊|U+07E86纆|
+U+2C64B𬙋|U+07E95纕|
+U+2C72C𬜬|U+08504蔄|
+U+2C72F𬜯|U+044E3䓣|
+U+2C79F𬞟|U+0860B蘋|
+U+2C7C1𬟁|U+08649虉|
+U+2C7FD𬟽|U+08740蝀|
+U+2C8D9𬣙|U+08A0F訏|
+U+2C8DE𬣞|U+08A5D詝|
+U+2C8E1𬣡|U+08AD3諓|
+U+2C8F3𬣳|U+08A6A詪|
+U+2C907𬤇|U+08AF2諲|
+U+2C90A𬤊|U+08ADF諟|
+U+2C91D𬤝|U+08B53譓|
+U+2CA02𬨂|U+08EDD軝|
+U+2CA0E𬨎|U+08F36輶|
+U+2CA7D𬩽|U+09129鄩|
+U+2CAA9𬪩|U+091B2醲|
+U+2CB29𬬩|U+091F4釴|
+U+2CB2D𬬭|U+09300錀|
+U+2CB2E𬬮|U+092F9鋹|
+U+2CB31𬬱|U+091FF釿|
+U+2CB38𬬸|U+09265鉥|
+U+2CB39𬬹|U+0926E鉮|
+U+2CB3B𬬻|U+0946A鑪|
+U+2CB3F𬬿|U+0924A鉊|
+U+2CB41𬭁|U+09267鉧|
+U+2CB4A𬭊|U+289C0𨧀|
+U+2CB4E𬭎|U+092D0鋐|
+U+2CB5A𬭚|U+0931E錞|
+U+2CB5B𬭛|U+28A0F𨨏|
+U+2CB64𬭤|U+0936D鍭|
+U+2CB69𬭩|U+09393鎓|
+U+2CB6C𬭬|U+093CF鏏|
+U+2CB6F𬭯|U+04955䥕|
+U+2CB73𬭳|U+28B4E𨭎|
+U+2CB76𬭶|U+28B46𨭆|
+U+2CB78𬭸|U+093FB鏻|
+U+2CB7C𬭼|U+09429鐩|
+U+2CBB1𬮱|U+095C9闉|
+U+2CBBF𬮿|U+09691隑|
+U+2CBC0𬯀|U+096AE隮|
+U+2CBCE𬯎|U+096A4隤|
+U+2CC56𬱖|U+09814頔|
+U+2CC5F𬱟|U+09820頠|
+U+2CCF5𬳵|U+099D3駓|
+U+2CCF6𬳶|U+099C9駉|
+U+2CCFD𬳽|U+099EA駪|
+U+2CCFF𬳿|U+099FC駼|
+U+2CD02𬴂|U+09A11騑|
+U+2CD03𬴃|U+09A1E騞|
+U+2CD0A𬴊|U+09A4E驎|
+U+2CD8B𬶋|U+09B88鮈|
+U+2CD8D𬶍|U+09B80鮀|
+U+2CD8F𬶏|U+09BA0鮠|
+U+2CD90𬶐|U+09BA1鮡|
+U+2CD9F𬶟|U+09BFB鯻|
+U+2CDA0𬶠|U+09C0A鰊|
+U+2CDA8𬶨|U+09C40鱀|
+U+2CDAD𬶭|U+09C36鰶|
+U+2CDAE𬶮|U+09C5A鱚|
+U+2CDD5𬷕|U+09D4F鵏|
+U+2CE18𬸘|U+09DA0鶠|
+U+2CE1A𬸚|U+09E11鸑|
+U+2CE23𬸣|U+09DB1鶱|
+U+2CE26𬸦|U+09DDF鷟|
+U+2CE2A𬸪|U+09DED鷭|
+U+2CE7C𬹼|U+09F58齘|
+U+2CE88𬺈|U+09F6E齮|
+U+2CE93𬺓|U+09F7C齼|
diff --git a/www/wiki/maintenance/language/zhtable/toCN.manual b/www/wiki/maintenance/language/zhtable/toCN.manual
index a63149e6..24531235 100644
--- a/www/wiki/maintenance/language/zhtable/toCN.manual
+++ b/www/wiki/maintenance/language/zhtable/toCN.manual
@@ -75,6 +75,7 @@
逕寄 径寄
逕啟 径启
逕迎 径迎
+逕流 径流
徵狀 症状
報帳 报账
本帳 本账
@@ -2189,6 +2190,11 @@
收錄著 收录着
促著 促着
咬著 咬着
+埋著 埋着
+憑著 凭着
+憑著名 凭著名
+憑著作 凭著作
+憑著者 凭著者
三十六著 三十六着
走為上著 走为上着
記憶體 内存
@@ -2249,7 +2255,6 @@
巨集 宏
掃瞄器 扫描仪
資料庫 数据库
-母音 元音
印表機 打印机
位元組 字节
列印 打印
@@ -2499,6 +2504,7 @@
托巴哥 多巴哥
多明尼加 多米尼加
斯堪地那維亞 斯堪的纳维亚
+加泰隆尼亞 加泰罗尼亚
頻寬 带宽
數位相機 数码相机
數位照相機 数码照相机
@@ -2672,6 +2678,8 @@ A型肝炎 甲型肝炎
庫德人 库尔德人
希拉蕊 希拉里
希拉莉 希拉里
+文翠珊 特蕾莎·梅
+德蕾莎·梅伊 特蕾莎·梅
麻薩諸塞 马萨诸塞
東南亞國家協會 东南亚国家联盟
獨立國協 独联体
@@ -2682,3 +2690,4 @@ A型肝炎 甲型肝炎
塑膠袋 塑料袋
烏龍麵 乌冬面
披索 比索
+真人騷 真人秀
diff --git a/www/wiki/maintenance/language/zhtable/toHK.manual b/www/wiki/maintenance/language/zhtable/toHK.manual
index b71764ad..e85a5120 100644
--- a/www/wiki/maintenance/language/zhtable/toHK.manual
+++ b/www/wiki/maintenance/language/zhtable/toHK.manual
@@ -105,10 +105,7 @@
彩球 綵球
彩绸 綵綢
彩綢 綵綢
-彩线 綵綫
-彩線 綵線
彩船 綵船
-彩衣 綵衣
结彩 結綵
結彩 結綵
戏彩娱亲 戲綵娛親
@@ -2596,6 +2593,11 @@
紀錄著 紀錄着
收錄著 收錄着
咬著 咬着
+埋著 埋着
+憑著 憑着
+憑著名 憑著名
+憑著作 憑著作
+憑著者 憑著者
三十六著 三十六着
走為上著 走為上着
鬧著 鬧着
@@ -2854,7 +2856,7 @@
得克萨斯 德克薩斯
蒙特婁 蒙特利爾
紐賓士域 紐賓士域
-默多克 梅鐸
+加泰隆尼亞 加泰羅尼亞
梅鐸 梅鐸
麦克尔 米高
迈克尔 米高
@@ -2971,9 +2973,6 @@ IP地址 IP位址
埃博拉 伊波拉
哥特式 哥德式
正體中文 繁體中文
-板球 木球
-籃板球 籃板球
-篮板球 籃板球
智慧財產權 知識產權
智財權 知識產權
首席执行官 行政總裁
@@ -3035,6 +3034,8 @@ IP地址 IP位址
程序员 程式設計師
昂山素季 昂山素姬
翁山蘇姬 昂山素姬
+德蕾莎·梅伊 文翠珊
+特蕾莎·梅 文翠珊
西洋棋 國際象棋
隐私 私隱
隱私 私隱
@@ -3053,3 +3054,4 @@ IP地址 IP位址
人行道 行人路
塑料袋 膠袋
烏龍麵 烏冬麵
+真人秀 真人騷
diff --git a/www/wiki/maintenance/language/zhtable/toSimp.manual b/www/wiki/maintenance/language/zhtable/toSimp.manual
index 56400c35..2a7f0acb 100644
--- a/www/wiki/maintenance/language/zhtable/toSimp.manual
+++ b/www/wiki/maintenance/language/zhtable/toSimp.manual
@@ -104,10 +104,12 @@
鐵鍊 铁链
金鍊 金链
銀鍊 银链
+雪鍊 雪链
鍊錘 链锤
洗鍊 洗练
手鍊 手链
鍊表 链表
+鍊狀 链状
反覆 反复
回覆 回复
答覆 答复
@@ -177,14 +179,6 @@
碁圣 碁圣
慇懃 殷勤
慇勤 殷勤
-崑崙 昆仑
-崑山 昆山
-崑劇 昆剧
-崑曲 昆曲
-崑腔 昆腔
-崑蘇 昆苏
-崑調 昆调
-崑島 昆岛
諠譁 喧哗
慫慂 怂恿
陈元扞 陈元扞
@@ -268,7 +262,6 @@
爾冬陞 尔冬升
內聯陞 内联升
同陞和 同升和
-拿破崙 拿破仑
酒麴 酒曲
麴黴 曲霉
造麴 造曲
diff --git a/www/wiki/maintenance/language/zhtable/toTW.manual b/www/wiki/maintenance/language/zhtable/toTW.manual
index 16e27516..1798437b 100644
--- a/www/wiki/maintenance/language/zhtable/toTW.manual
+++ b/www/wiki/maintenance/language/zhtable/toTW.manual
@@ -535,6 +535,8 @@
斯堪的纳维亚 斯堪地那維亞
斯堪的納維亞 斯堪地那維亞
圣佩德罗苏拉 汕埠
+加泰罗尼亚 加泰隆尼亞
+加泰羅尼亞 加泰隆尼亞
麦克尔 麥可
迈克尔 麥可
魯賓斯·巴里切羅 魯本·巴瑞切羅
@@ -750,6 +752,8 @@ IP地址 IP位址
數碼技術 數位技術
数字信号 數位訊號
數碼訊號 數位訊號
+数字音乐 數位音樂
+數碼音樂 數位音樂
数字化 數位化
數碼化 數位化
移动网络 行動網路
@@ -772,6 +776,8 @@ IP地址 IP位址
連結他 連結他
昂山素季 翁山蘇姬
昂山素姬 翁山蘇姬
+特蕾莎·梅 德蕾莎·梅伊
+文翠珊 德蕾莎·梅伊
国际象棋 西洋棋
國際象棋 西洋棋
私隱 隱私
@@ -788,3 +794,4 @@ IP地址 IP位址
塑料袋 塑膠袋
触摸屏 觸控螢幕
乌冬面 烏龍麵
+真人騷 真人秀
diff --git a/www/wiki/maintenance/language/zhtable/toTrad.manual b/www/wiki/maintenance/language/zhtable/toTrad.manual
index 1d536154..c2fcb162 100644
--- a/www/wiki/maintenance/language/zhtable/toTrad.manual
+++ b/www/wiki/maintenance/language/zhtable/toTrad.manual
@@ -19,6 +19,7 @@
陳杰 陳杰
黃杰 黃杰
謝杰 謝杰
+博杰普爾 博杰普爾
寶曆 寶曆
涂謹申 涂謹申
涂鴻欽 涂鴻欽
@@ -154,6 +155,12 @@
葉陽后 葉陽后
后庄 后庄
後庄 後庄
+龜山庄 龜山庄
+寶山庄 寶山庄
+員山庄 員山庄
+舊庄 舊庄
+庄內 庄內
+庄内地方 庄內地方
后蒼 后蒼
馬格里布 馬格里布
佳里鎮 佳里鎮
@@ -187,24 +194,11 @@
佣鈿 佣鈿
阁府 閤府
太阁 太閤
-昆仑 崑崙
-昆山 崑山
-昆剧 崑劇
-昆曲 崑曲
-昆腔 崑腔
-昆苏 崑蘇
-昆调 崑調
-昆冈 崑岡
-西昆 西崑
-苏昆 蘇崑
苏醒 甦醒
复苏 復甦
苹果 蘋果
苹果干 蘋果乾
苹婆 蘋婆
-龜山庄 龜山庄
-寶山庄 寶山庄
-員山庄 員山庄
昵称 暱稱
單于 單于
鮮于 鮮于
@@ -304,7 +298,6 @@
陈升 陳昇
尔冬升 爾冬陞
南宮适 南宮适
-舊庄 舊庄
拿破仑 拿破崙
冗余 冗餘
课余 課餘
diff --git a/www/wiki/maintenance/language/zhtable/trad2simp.manual b/www/wiki/maintenance/language/zhtable/trad2simp.manual
index 1912bcf2..9a57047b 100644
--- a/www/wiki/maintenance/language/zhtable/trad2simp.manual
+++ b/www/wiki/maintenance/language/zhtable/trad2simp.manual
@@ -8,6 +8,7 @@ U+0362D㘭|U+05773坳|
U+0375B㝛|U+05BBF宿|
U+03760㝠|U+051A5冥|
U+03800㠀|U+05C9B岛|
+U+03823㠣|U+2BD77𫵷|
U+0382F㠯|U+04EE5以|
U+03836㠶|U+05E06帆|
U+0384C㡌|U+05E3D帽|
@@ -31,8 +32,10 @@ U+03F1D㼝|U+07897碗|
U+03F5E㽞|U+07559留|
U+03FDC㿜|U+0762A瘪|
U+04039䀹|U+25174𥅴|
+U+040EE䃮|U+09FCE鿎|
U+04230䈰|U+07B72筲|
U+04280䊀|U+07CCA糊|
+U+044E3䓣|U+2C72F𬜯|
U+045EC䗬|U+08702蜂|
U+0460F䘏|U+06064恤|
U+04611䘑|U+08109脉|
@@ -42,9 +45,13 @@ U+046E1䛡|U+08BDD话|
U+04754䝔|U+0737E獾|
U+04800䠀|U+08E5A蹚|
U+04836䠶|U+05C04射|
+U+04875䡵|U+2B7E6𫟦|
+U+04951䥑|U+09FCF鿏|
+U+04955䥕|U+2CB6F𬭯|
U+04965䥥|U+09570镰|
U+04B03䬃|U+098D2飒|
U+04B7E䭾|U+09A6E驮|
+U+04B84䮄|U+2B80A𫠊|
U+04C1F䰟|U+09B42魂|
U+04CD8䳘|U+09E45鹅|
U+04D8A䶊|U+08844衄|
@@ -68,6 +75,7 @@ U+0509A傚|U+06548效|
U+050A2傢|U+05BB6家|
U+050CA僊|U+04ED9仙|
U+050CD働|U+052A8动|
+U+050E4僤|U+2B8B8𫢸|
U+050F1僱|U+096C7雇|
U+0510C儌|U+04FA5侥|
U+05138儸|U+03469㑩|U+07F57罗|
@@ -95,6 +103,7 @@ U+052B9効|U+06548效|
U+052C5勅|U+06555敕|
U+052CC勌|U+05026倦|
U+052D1勑|U+06555敕|
+U+052E3勣|U+2A7DD𪟝|
U+052E6勦|U+0527F剿|
U+052F3勳|U+052CB勋|
U+0531F匟|U+07095炕|
@@ -125,6 +134,7 @@ U+05605嘅|U+06168慨|
U+05611嘑|U+0547C呼|
U+05620嘠|U+0560E嘎|
U+05637嘷|U+055E5嗥|
+U+05641噁|U+2BAC7𫫇|
U+05649噉|U+05556啖|
U+05690嚐|U+05C1D尝|
U+056A5嚥|U+054BD咽|
@@ -136,10 +146,14 @@ U+05705圅|U+051FD函|
U+0577F坿|U+09644附|
U+0579C垜|U+0579B垛|
U+057BB垻|U+0575D坝|
+U+057E8埨|U+2BB62𫭢|
U+0585A塚|U+051A2冢|
U+0585F塟|U+0846C葬|
U+05872塲|U+0573A场|
+U+05878塸|U+2BB5F𫭟|
+U+0587F塿|U+2A8FB𪣻|
U+05896墖|U+05854塔|
+U+058A0墠|U+2BB83𫮃|
U+058B0墰|U+0575B坛|
U+058BB墻|U+05899墙|
U+058CE壎|U+057D9埙|
@@ -155,6 +169,7 @@ U+059C9姉|U+059CA姊|
U+059D9姙|U+0598A妊|
U+059EA姪|U+04F84侄|
U+059F8姸|U+0598D妍|
+U+05A19娙|U+2BC1B𫰛|
U+05A63婣|U+059FB姻|
U+05A6C婬|U+06DEB淫|
U+05A8D媍|U+05987妇|
@@ -182,11 +197,15 @@ U+05C5B屛|U+05C4F屏|
U+05C6D屭|U+05C43屃|
U+05C85岅|U+05742坂|
U+05CDD峝|U+05CD2峒|
+U+05D11崑|U+06606昆|
+U+05D19崙|U+04ED1仑|
U+05D57嵗|U+05C81岁|
+U+05D7D嵽|U+2BD87𫶇|
U+05D83嶃|U+05D2D崭|
U+05DBD嶽|U+05CB3岳|
U+05DD6巖|U+05CA9岩|
U+05DD7巗|U+05CA9岩|
+U+05DD8巘|U+2AA58𪩘|
U+05DF5巵|U+0536E卮|
U+05E00帀|U+0531D匝|
U+05E0B帋|U+07EB8纸|
@@ -199,10 +218,12 @@ U+05EBB庻|U+05EB6庶|
U+05EBD庽|U+05BD3寓|
U+05ED0廐|U+053A9厩|
U+05ED5廕|U+0836B荫|
+U+05EDE廞|U+2BDF7𫷷|
U+05EF5廵|U+05DE1巡|
U+05EF9廹|U+08FEB迫|
U+05EFB廻|U+056DE回|
U+05F14弔|U+0540A吊|
+U+05F44彄|U+2BE29𫸩|
U+05F46彆|U+0522B别|
U+05F6B彫|U+096D5雕|
U+05F83徃|U+05F80往|
@@ -266,6 +287,8 @@ U+065F9旹|U+065F6时|
U+065FE旾|U+06625春|
U+06607昇|U+06607昇|U+05347升|
U+0662C昬|U+0660F昏|
+U+0665B晛|U+2C02A𬀪|
+U+06690暐|U+2C029𬀩|
U+066B1暱|U+06635昵|
U+066E1曡|U+053E0叠|
U+0671E朞|U+0671F期|
@@ -282,6 +305,7 @@ U+06830栰|U+07B4F筏|
U+06852桒|U+06851桑|
U+0686E桮|U+0676F杯|
U+0687A桺|U+067F3柳|
+U+0689C梜|U+2C0A9𬂩|
U+068CA棊|U+068CB棋|
U+06917椗|U+07887碇|
U+06936椶|U+068D5棕|
@@ -294,7 +318,9 @@ U+069D5槕|U+0684C桌|
U+06A11樑|U+06881梁|
U+06A5C橜|U+06A5B橛|
U+06AC8櫈|U+051F3凳|
+U+06ACD櫍|U+2C0CA𬃊|
U+06B05欅|U+06989榉|
+U+06B13欓|U+235CB𣗋|
U+06B1D欝|U+090C1郁|
U+06B35欵|U+06B3E款|
U+06B4E歎|U+053F9叹|
@@ -312,23 +338,29 @@ U+06C5A汚|U+06C61污|
U+06C88瀋|U+06C88沈|U+0700B渖|
U+06CDD泝|U+06EAF溯|
U+06D29洩|U+06CC4泄|
+U+06D7F浿|U+2C1D9𬇙|
U+06D96涖|U+08385莅|
U+06DD2淒|U+051C4凄|
U+06DDB淛|U+06D59浙|
U+06DE8淨|U+051C0净|
U+06DE9淩|U+051CC凌|
+U+06E4B湋|U+23C97𣲗|
U+06E67湧|U+06D8C涌|
U+06E7C湼|U+06D85涅|
U+06EBC溼|U+06E7F湿|
U+06ED9滙|U+06C47汇|
U+06EDB滛|U+06DEB淫|
U+06EF7滷|U+05364卤|
+U+06F0D漍|U+2C1F9𬇹|
U+06F44潄|U+06F31漱|
U+06F55潕|U+23C98𣲘|
+U+06F55潕|U+23C98𣲘|
U+06F59潙|U+06CA9沩|
U+06F81澁|U+06DA9涩|
U+06F90澐|U+06C84沄|
+U+06FAB澫|U+2C1D5𬇕|
U+06FBE澾|U+03CE0㳠|
+U+06FC6濆|U+23E23𣸣|
U+06FC7濇|U+06DA9涩|
U+06FDB濛|U+06FDB濛|U+08499蒙|
U+06FF6濶|U+09614阔|
@@ -338,8 +370,11 @@ U+070D6烖|U+0707E灾|
U+07151煑|U+0716E煮|
U+07157煗|U+06696暖|
U+07188熈|U+07199熙|
+U+071B0熰|U+2C27C𬉼|
+U+071C0燀|U+2C2A4𬊤|
U+071C4燄|U+07130焰|
U+071C9燉|U+07096炖|U+071C9燉|
+U+071D6燖|U+2C288𬊈|
U+071EC燬|U+06BC1毁|
U+071FB燻|U+0718F熏|
U+07217爗|U+070E8烨|
@@ -363,7 +398,12 @@ U+07416琖|U+076CF盏|
U+07431琱|U+096D5雕|
U+07447瑇|U+073B3玳|
U+0746F瑯|U+07405琅|
+U+0748A璊|U+2B7A9𫞩|
+U+07495璕|U+2C364𬍤|
+U+07497璗|U+2C361𬍡|
U+074A2璢|U+07460瑠|
+U+074C5瓅|U+2C35B𬍛|
+U+074DB瓛|U+24A7D𤩽|
U+0750E甎|U+07816砖|
U+07515甕|U+074EE瓮|
U+07516甖|U+07F42罂|
@@ -402,6 +442,7 @@ U+076CC盌|U+07897碗|
U+0770E眎|U+089C6视|
U+0771E眞|U+0771F真|
U+07721眡|U+089C6视|
+U+0774D睍|U+2AFA2𪾢|
U+07760睠|U+07737眷|
U+0776A睪|U+0777E睾|
U+07787瞇|U+0772F眯|
@@ -415,6 +456,7 @@ U+07881碁|U+068CB棋|
U+078AA碪|U+07827砧|
U+078DF磟|U+0788C碌|
U+07906礆|U+078B1碱|
+U+07910礐|U+2C488𬒈|
U+0792E礮|U+070AE炮|
U+07955祕|U+079D8秘|
U+07958祘|U+07B97算|
@@ -444,6 +486,7 @@ U+07B87箇|U+04E2A个|
U+07B92箒|U+05E1A帚|
U+07BA0箠|U+068F0棰|
U+07BDB篛|U+07BAC箬|
+U+07BE2篢|U+2C542𬕂|
U+07C11簑|U+084D1蓑|
U+07C12簒|U+07BE1篡|
U+07C2E簮|U+07C2A簪|
@@ -455,13 +498,24 @@ U+07C83粃|U+079D5秕|
U+07CA7粧|U+05986妆|
U+07CC9糉|U+07CBD粽|
U+07CF0糰|U+056E2团|
+U+07D03紃|U+2C613𬘓|
+U+07D1E紞|U+2C618𬘘|
U+07D25紥|U+0624E扎|
U+07D2E紮|U+0624E扎|
U+07D43絃|U+05F26弦|
U+07D4F絏|U+07EC1绁|
+U+07D6A絪|U+2C621𬘡|
U+07D76絶|U+07EDD绝|
+U+07D7A絺|U+2B128𫄨|
+U+07D84綄|U+2C62B𬘫|
U+07D89綉|U+07EE3绣|
+U+07D8E綎|U+2C629𬘩|
U+07D91綑|U+06346捆|
+U+07D96綖|U+2B127𫄧|
+U+07D9D綝|U+2C62D𬘭|
+U+07DA1綡|U+2B7C5𫟅|
+U+07DA7綧|U+2C62F𬘯|
+U+07DAA綪|U+2C62C𬘬|
U+07DAB綫|U+07EBF线|
U+07DB5綵|U+05F69彩|U+0433D䌽|
U+07DD0緐|U+07E41繁|
@@ -472,13 +526,19 @@ U+07DDC緜|U+07EF5绵|
U+07DE5緥|U+08913褓|
U+07DFC緼|U+07F0A缊|
U+07E27縧|U+07EE6绦|
+U+07E2F縯|U+2C642𬙂|
U+07E34縴|U+07EA4纤|
U+07E50繐|U+07A57穗|
U+07E56繖|U+04F1E伞|
U+07E59繙|U+07FFB翻|
U+07E66繦|U+08941襁|
U+07E6E繮|U+07F30缰|
+U+07E76繶|U+2B137𫄷|
+U+07E7B繻|U+26221𦈡|
+U+07E81纁|U+2B138𫄸|
+U+07E86纆|U+2C64A𬙊|
U+07E94纔|U+0624D才|
+U+07E95纕|U+2C64B𬙋|
U+07F47罇|U+06A3D樽|
U+07F4B罋|U+074EE瓮|
U+07F4E罎|U+0575B坛|
@@ -502,6 +562,7 @@ U+08117脗|U+0543B吻|
U+08123脣|U+05507唇|
U+08141腁|U+080FC胼|
U+08193膓|U+080A0肠|
+U+081A2膢|U+2677C𦝼|
U+081C8臈|U+0814A腊|
U+081CB臋|U+081C0臀|
U+081D5臕|U+08198膘|
@@ -527,9 +588,11 @@ U+08493蒓|U+083BC莼|
U+084C6蓆|U+05E2D席|
U+084E1蓡|U+053C2参|
U+084F4蓴|U+083BC莼|
+U+08504蔄|U+2C72C𬜬|
U+08514蔔|U+0535C卜|
U+08515蔕|U+08482蒂|
U+08518蔘|U+053C2参|
+U+0853F蔿|U+2B1ED𫇭|
U+0855A蕚|U+0843C萼|
U+0857F蕿|U+08431萱|
U+08591薑|U+059DC姜|
@@ -537,14 +600,17 @@ U+085C9藉|U+085C9藉|U+0501F借|
U+085F4藴|U+08574蕴|
U+085F7藷|U+085AF薯|
U+085FC藼|U+08431萱|
+U+0860B蘋|U+2C79F𬞟|
U+08610蘐|U+08431萱|
U+08613蘓|U+082CF苏|
U+08624蘤|U+082B1花|
+U+08649虉|U+2C7C1𬟁|
U+08698蚘|U+086D4蛔|
U+086D5蛕|U+086D4蛔|
U+0870B蜋|U+08782螂|
U+08716蜖|U+086D4蛔|
U+08728蜨|U+08776蝶|
+U+08740蝀|U+2C7FD𬟽|
U+08768蝨|U+08671虱|
U+0876F蝯|U+0733F猿|
U+08771蝱|U+0867B虻|
@@ -569,6 +635,7 @@ U+088CC裌|U+088B7袷|
U+088CF裏|U+091CC里|
U+088E0裠|U+088D9裙|
U+0892D褭|U+08885袅|
+U+08940襀|U+2B300𫌀|
U+08943襃|U+08912褒|
U+0894D襍|U+06742杂|
U+08986覆|U+08986覆|U+0590D复|
@@ -578,19 +645,30 @@ U+0898A覊|U+07F81羁|
U+08994覔|U+089C5觅|
U+089A9覩|U+07779睹|
U+089DD觝|U+062B5抵|
+U+08A0F訏|U+2C8D9𬣙|
U+08A17託|U+06258托|U+08BAC讬|
U+08A3C証|U+08BC1证|
+U+08A5D詝|U+2C8DE𬣞|
+U+08A6A詪|U+2C8F3𬣳|
U+08A76詶|U+0916C酬|
+U+08A77詷|U+2B363𫍣|
U+08A96誖|U+06096悖|
U+08AAC説|U+08BF4说|
+U+08AD3諓|U+2C8E1𬣡|
+U+08ADF諟|U+2C90A𬤊|
U+08AEE諮|U+08C18谘|U+054A8咨|
+U+08AF2諲|U+2C907𬤇|
+U+08AF4諴|U+2B36F𫍯|
U+08B0C謌|U+06B4C歌|
+U+08B0F謏|U+2B372𫍲|
U+08B21謡|U+08C23谣|
U+08B2D謭|U+08C2B谫|
U+08B41譁|U+054D7哗|
U+08B46譆|U+0563B嘻|
U+08B4C譌|U+08BB9讹|
+U+08B53譓|U+2C91D𬤝|
U+08B54譔|U+064B0撰|
+U+08B5E譞|U+2B37D𫍽|
U+08B5F譟|U+0566A噪|
U+08B6D譭|U+06BC1毁|
U+08B81讁|U+08C2A谪|
@@ -624,8 +702,15 @@ U+08E98躘|U+28001𨀁|
U+08EAD躭|U+0803D耽|
U+08EB3躳|U+08EAC躬|
U+08EB6躶|U+088F8裸|
+U+08ECF軏|U+2B404𫐄|
+U+08EDD軝|U+2CA02𬨂|
+U+08F04輄|U+28408𨐈|
+U+08F0B輋|U+2AA36𪨶|
+U+08F17輗|U+2B410𫐐|
U+08F19輙|U+08F84辄|
U+08F2D輭|U+08F6F软|
+U+08F2E輮|U+2B413𫐓|
+U+08F36輶|U+2CA0E𬨎|
U+08F3C輼|U+08F92辒|
U+08FA0辠|U+07F6A罪|
U+08FA2辢|U+08FA3辣|
@@ -642,6 +727,8 @@ U+09049遉|U+04FA6侦|
U+0904A遊|U+06E38游|
U+09061遡|U+06EAF溯|
U+0906F遯|U+09041遁|
+U+09129鄩|U+2CA7D𬩽|
+U+09133鄳|U+2B461𫑡|
U+09156酖|U+09E29鸩|
U+09167酧|U+0916C酬|
U+09183醃|U+0814C腌|
@@ -649,36 +736,66 @@ U+09186醆|U+076CF盏|
U+09195醕|U+09187醇|
U+091A3醣|U+07CD6糖|
U+091AF醯|U+09170酰|
+U+091B2醲|U+2CAA9𬪩|
U+091BB醻|U+0916C酬|
U+091BC醼|U+05BB4宴|
U+091E6釦|U+06263扣|
U+091EC釬|U+0710A焊|
+U+091F4釴|U+2CB29𬬩|
+U+091FF釿|U+2CB31𬬱|
U+09205鈅|U+094A5钥|
+U+09207鈇|U+2B4E7𫓧|
U+0920E鈎|U+094A9钩|
U+09244鉄|U+094C1铁|
U+09246鉆|U+094BB钻|
+U+0924A鉊|U+2CB3F𬬿|
U+09262鉢|U+094B5钵|
+U+09265鉥|U+2CB38𬬸|
+U+09267鉧|U+2CB41𬭁|
+U+0926E鉮|U+2CB39𬬹|
+U+09277鉷|U+2B7F9𫟹|
+U+09288銈|U+2B4EF𫓯|
U+092B2銲|U+0710A焊|
+U+092B6銶|U+28C47𨱇|
+U+092D0鋐|U+2CB4E𬭎|
+U+092D7鋗|U+2B4F6𫓶|
U+092ED鋭|U+09510锐|
+U+092F9鋹|U+2CB2E𬬮|
+U+09300錀|U+2CB2D𬬭|
+U+0931E錞|U+2CB5A𬭚|
+U+09324錤|U+2B4F9𫓹|
U+09332録|U+05F55录|
U+09341鍁|U+09528锨|
U+0934A鍊|U+070BC炼|U+094FE链|
U+0936B鍫|U+09539锹|
+U+0936D鍭|U+2CB64𬭤|
U+09373鍳|U+09274鉴|
U+0937E鍾|U+0953A锺|U+0949F钟|
U+0938C鎌|U+09570镰|
+U+09393鎓|U+2CB69𬭩|
U+09397鎗|U+067AA枪|
U+0939A鎚|U+09524锤|
+U+0939D鎝|U+28C4F𨱏|
U+093AD鎭|U+093AE镇|
U+093AD鎭|U+09547镇|
+U+093B6鎶|U+09FD4鿔|
U+093B8鎸|U+0954C镌|
U+093BB鎻|U+09501锁|
+U+093CF鏏|U+2CB6C𬭬|
U+093DA鏚|U+0621A戚|
+U+093FB鏻|U+2CB78𬭸|
+U+09404鐄|U+28C51𨱑|
+U+09407鐇|U+2B50D𫔍|
+U+0940D鐍|U+2B50E𫔎|
+U+0940F鐏|U+28C54𨱔|
U+0941D鐝|U+09562镢|
+U+09429鐩|U+2CB7C𬭼|
+U+0943D鐽|U+2B7FC𫟼|
U+09451鑑|U+09274鉴|
U+0945A鑚|U+094BB钻|
U+0945B鑛|U+077FF矿|
U+09464鑤|U+05228刨|
+U+0946A鑪|U+2CB3B𬬻|
U+09475鑵|U+07F50罐|
U+09482钂|U+0954B镋|
U+09592閒|U+095F2闲|
@@ -687,6 +804,8 @@ U+095A4閤|U+09601阁|U+05408合|
U+095A7閧|U+054C4哄|
U+095B2閲|U+09605阅|
U+095C7闇|U+06697暗|
+U+095C9闉|U+2CBB1𬮱|
+U+095D1闑|U+2B536𫔶|
U+095DA闚|U+07AA5窥|
U+095E2闢|U+08F9F辟|
U+09628阨|U+05384厄|
@@ -699,8 +818,11 @@ U+0967B陻|U+05819堙|
U+0967F陿|U+072ED狭|
U+09682隂|U+09634阴|
U+09684隄|U+05824堤|
+U+09691隑|U+2CBBF𬮿|
U+09696隖|U+0575E坞|
U+096A3隣|U+090BB邻|
+U+096A4隤|U+2CBCE𬯎|
+U+096AE隮|U+2CBC0𬯀|
U+096B7隷|U+096B6隶|
U+0976D靭|U+097E7韧|
U+09771靱|U+097E7韧|
@@ -711,12 +833,18 @@ U+097C6韆|U+05343千|
U+097C8韈|U+0889C袜|
U+097E4韤|U+0889C袜|
U+097EE韮|U+097ED韭|
+U+0980D頍|U+2B806𫠆|
+U+09814頔|U+2CC56𬱖|
U+0981F頟|U+0989D额|
+U+09820頠|U+2CC5F𬱟|
+U+0982B頫|U+2B5AF𫖯|
+U+09835頵|U+2B5B3𫖳|
U+0983C頼|U+08D56赖|
U+0983D頽|U+09893颓|
U+09847顇|U+060B4悴|
U+0984B顋|U+0816E腮|
U+09854顔|U+0989C颜|
+U+09857顗|U+2B5AE𫖮|
U+09858願|U+0613F愿|
U+09866顦|U+06194憔|
U+098C3飃|U+098D8飘|
@@ -725,6 +853,7 @@ U+098E4飤|U+09972饲|
U+098F1飱|U+098E7飧|
U+09901餁|U+0996A饪|
U+09908餈|U+07CCD糍|
+U+09917餗|U+2B5E7𫗧|
U+09918餘|U+09980馀|U+04F59余|
U+09935餵|U+05582喂|
U+09939餹|U+07CD6糖|
@@ -732,11 +861,26 @@ U+0993B餻|U+07CD5糕|
U+0993D餽|U+09988馈|
U+0994D饍|U+081B3膳|
U+09951饑|U+09965饥|
+U+09958饘|U+2B5F4𫗴|
U+0995D饝|U+0998D馍|
+U+099BC馼|U+2B61C𫘜|
+U+099C3駃|U+2B61D𫘝|
U+099C8駈|U+09A71驱|
+U+099C9駉|U+2CCF6𬳶|
+U+099D3駓|U+2CCF5𬳵|
U+099E1駡|U+09A82骂|
+U+099EA駪|U+2CCFD𬳽|
+U+099FC駼|U+2CCFF𬳿|
+U+09A04騄|U+2B627𫘧|
+U+09A0A騊|U+2B626𫘦|
U+09A10騐|U+09A8C验|
+U+09A11騑|U+2CD02𬴂|
+U+09A1E騞|U+2CD03𬴃|
+U+09A20騠|U+2B628𫘨|
U+09A23騣|U+09B03鬃|
+U+09A31騱|U+2B62C𫘬|
+U+09A35騵|U+2B62A𫘪|
+U+09A4E驎|U+2CD0A𬴊|
U+09A58驘|U+09AA1骡|
U+09ABD骽|U+0817F腿|
U+09ABE骾|U+09CA0鲠|
@@ -748,22 +892,44 @@ U+09B26鬦|U+06597斗|
U+09B28鬨|U+054C4哄|
U+09B2A鬪|U+06597斗|
U+09B30鬰|U+090C1郁|
+U+09B80鮀|U+2CD8D𬶍|
+U+09B86鮆|U+2B696𫚖|
+U+09B88鮈|U+2CD8B𬶋|
U+09B8E鮎|U+09C87鲇|
U+09B9D鮝|U+09C9E鲞|
+U+09B9F鮟|U+29F7E𩽾|
+U+09BA0鮠|U+2CD8F𬶏|
+U+09BA1鮡|U+2CD90𬶐|
+U+09BB8鮸|U+29F83𩾃|
U+09BF0鯰|U+09CB6鲶|U+09C87鲇|
+U+09BFB鯻|U+2CD9F𬶟|
+U+09C0A鰊|U+2CDA0𬶠|
U+09C10鰐|U+09CC4鳄|
U+09C1B鰛|U+09CC1鳁|
+U+09C24鰤|U+2B695𫚕|
U+09C2E鰮|U+09CC1鳁|
+U+09C36鰶|U+2CDAD𬶭|
+U+09C40鱀|U+2CDA8𬶨|
+U+09C47鱇|U+29F8C𩾌|
+U+09C5A鱚|U+2CDAE𬶮|
+U+09C72鱲|U+2B6AD𫚭|
U+09CEC鳬|U+051EB凫|
U+09D08鴈|U+096C1雁|
+U+09D4F鵏|U+2CDD5𬷕|
U+09D5E鵞|U+09E45鹅|
+U+09D5F鵟|U+2B6ED𫛭|
U+09D70鵰|U+096D5雕|U+05F6B彫|
U+09D76鵶|U+09E26鸦|
+U+09DA0鶠|U+2CE18𬸘|
+U+09DB1鶱|U+2CE23𬸣|
U+09DC0鷀|U+09E5A鹚|
U+09DC4鷄|U+09E21鸡|
+U+09DDF鷟|U+2CE26𬸦|
+U+09DED鷭|U+2CE2A𬸪|
U+09DF0鷰|U+071D5燕|
U+09DF4鷴|U+09E47鹇|
U+09E0E鸎|U+083BA莺|
+U+09E11鸑|U+2CE1A𬸚|
U+09E7B鹻|U+078B1碱|
U+09E7C鹼|U+078B1碱|U+07877硷|
U+09EAA麪|U+09762面|
@@ -776,12 +942,20 @@ U+09F03鼃|U+086D9蛙|
U+09F07鼇|U+09CCC鳌|
U+09F08鼈|U+09CD6鳖|
U+09F15鼕|U+0549A咚|
+U+09F58齘|U+2CE7C𬹼|
U+09F63齣|U+051FA出|
U+09F67齧|U+0556E啮|
U+09F69齩|U+054AC咬|
+U+09F6E齮|U+2CE88𬺈|
+U+09F6F齯|U+2B81C𫠜|
+U+09F7C齼|U+2CE93𬺓|
+U+09FC1鿁|U+04724䜤|
+U+09FD0鿐|U+04CA4䲤|
+U+09FD3鿓|U+09FD2鿒|
U+20542𠕂|U+0518D再|
U+20545𠕅|U+0518D再|
U+207B0𠞰|U+0527F剿|
+U+2144D𡑍|U+2BB7C𫭼|
U+21681𡚁|U+05F0A弊|
U+21A25𡨥|U+05BC7寇|
U+21ED5𡻕|U+05C81岁|
@@ -790,10 +964,15 @@ U+242EE𤋮|U+07199熙|
U+24A0F𤨏|U+07410琐|
U+24C48𤱈|U+04EA9亩|
U+24EA5𤺥|U+07629瘩|
+U+255FD𥗽|U+2C497𬒗|
U+262B1𦊱|U+06302挂|
U+26351𦍑|U+07F8C羌|
U+26548𦕈|U+07707眇|
U+26D4F𦵏|U+0846C葬|
+U+289C0𨧀|U+2CB4A𬭊|
+U+28A0F𨨏|U+2CB5B𬭛|
+U+28B46𨭆|U+2CB76𬭶|
+U+28B4E𨭎|U+2CB73𬭳|
U+28F7B𨽻|U+096B6隶|
U+294D0𩓐|U+08116脖|
U+295D7𩗗|U+098D3飓|
diff --git a/www/wiki/maintenance/language/zhtable/tradphrases.manual b/www/wiki/maintenance/language/zhtable/tradphrases.manual
index c5d5fd73..d153930a 100644
--- a/www/wiki/maintenance/language/zhtable/tradphrases.manual
+++ b/www/wiki/maintenance/language/zhtable/tradphrases.manual
@@ -250,10 +250,8 @@
乾哭
乾噦
乾咽
-乾和
幹吏
乾號
-乾颱
乾卦
乾剝剝
乾刻版
@@ -292,11 +290,13 @@
髮絲
斷髮
不斷發
+中斷發
判斷發
評斷發
買斷發
賣斷發
打斷發
+假發票
披頭散髮
髮禁
世界盃
@@ -790,6 +790,9 @@
咬薑呷醋
薑蓉
薑黃
+嫩薑
+酸薑
+薑啤
狐藉虎威
滑藉
藉寇兵
@@ -1184,6 +1187,7 @@
蓬鬆鬆
輕鬆鬆
鬆鬆地
+鬆耦合
囉囉囌囌
囉囌
骨罈
@@ -1286,6 +1290,7 @@
田庄英雄
本庄
庄司
+街庄
厂部
衝量
衝車
@@ -1412,6 +1417,10 @@
謝杰
正杰
柳斌杰
+修杰楷
+修杰麟
+熊杰
+博杰普爾
稜鏡
稜角
稜台
@@ -2050,6 +2059,12 @@
徵吏
徵令
本徵
+吉徵
+凶徵
+免徵
+體徵
+表徵
+綜合徵
黃鈺筑
當準
憑準
@@ -2171,6 +2186,7 @@
埃及歷史
大明歷史
大歷史
+大歷險
大衍歷史
太初歷史
官歷史
@@ -2398,6 +2414,7 @@
尸佼
尸子
尸羅
+帛尸梨
尸羅精舍
毗婆尸佛
尸棄佛
@@ -2876,8 +2893,6 @@
注釋
月面
路面
-修杰楷
-修杰麟
學裡
獄裡
館裡
@@ -2981,6 +2996,8 @@
編碼表
字碼表
電碼表
+碼碼表
+碼表示
科斗
灕水
這只不
@@ -3123,7 +3140,6 @@
鬱南
鬱林
饑荒
-免徵
艷后
廢后
妖后
@@ -3229,7 +3245,6 @@
于楓
于熙珍
邱于庭
-熊杰
卜云吉
黎吉雲
代表
@@ -3488,8 +3503,6 @@
製衣
巨製
窗簾
-吉徵
-凶徵
臟腑
臟胸
弄髒胸
@@ -3570,9 +3583,7 @@
角牴
扼肮
搤肮
-嫩薑
-酸薑
-薑啤
+薑酮
騰湧
草蓆
竹蓆
@@ -3612,8 +3623,6 @@
強制
改制成
考試制度
-體徵
-綜合徵
价川
商標准許
批准確定
@@ -3720,3 +3729,13 @@
關系統
關系所
關系科
+崑崙
+崑山
+崑劇
+崑曲
+崑腔
+崑蘇
+崑調
+崑岡
+西崑
+蘇崑
diff --git a/www/wiki/maintenance/language/zhtable/tradphrases_exclude.manual b/www/wiki/maintenance/language/zhtable/tradphrases_exclude.manual
index 3ab14eb1..eaea6805 100644
--- a/www/wiki/maintenance/language/zhtable/tradphrases_exclude.manual
+++ b/www/wiki/maintenance/language/zhtable/tradphrases_exclude.manual
@@ -778,3 +778,6 @@
箇舊
條幹
檯布
+髮姐
+崙
+鬆起
diff --git a/www/wiki/maintenance/makeTestEdits.php b/www/wiki/maintenance/makeTestEdits.php
index ca2f7c51..d4ce931f 100644
--- a/www/wiki/maintenance/makeTestEdits.php
+++ b/www/wiki/maintenance/makeTestEdits.php
@@ -40,7 +40,7 @@ class MakeTestEdits extends Maintenance {
public function execute() {
$user = User::newFromName( $this->getOption( 'user' ) );
if ( !$user->getId() ) {
- $this->error( "No such user exists.", 1 );
+ $this->fatalError( "No such user exists." );
}
$count = $this->getOption( 'count' );
@@ -55,7 +55,7 @@ class MakeTestEdits extends Maintenance {
$page->doEditContent( $content, $summary, 0, false, $user );
$this->output( "Edited $title\n" );
- if ( $i && ( $i % $this->mBatchSize ) == 0 ) {
+ if ( $i && ( $i % $this->getBatchSize() ) == 0 ) {
wfWaitForSlaves();
}
}
@@ -64,5 +64,5 @@ class MakeTestEdits extends Maintenance {
}
}
-$maintClass = "MakeTestEdits";
+$maintClass = MakeTestEdits::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/manageJobs.php b/www/wiki/maintenance/manageJobs.php
index 32333b76..488c9153 100644
--- a/www/wiki/maintenance/manageJobs.php
+++ b/www/wiki/maintenance/manageJobs.php
@@ -48,7 +48,7 @@ class ManageJobs extends Maintenance {
} elseif ( $action === 'repush-abandoned' ) {
$this->repushAbandoned( $queue );
} else {
- $this->error( "Invalid action '$action'.", 1 );
+ $this->fatalError( "Invalid action '$action'." );
}
}
@@ -82,7 +82,7 @@ class ManageJobs extends Maintenance {
$queue->push( $job );
++$count;
- if ( ( $count % $this->mBatchSize ) == 0 ) {
+ if ( ( $count % $this->getBatchSize() ) == 0 ) {
$queue->waitForBackups();
}
}
@@ -93,5 +93,5 @@ class ManageJobs extends Maintenance {
}
}
-$maintClass = "ManageJobs";
+$maintClass = ManageJobs::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/mctest.php b/www/wiki/maintenance/mctest.php
index 60f94a5f..c976bd70 100644
--- a/www/wiki/maintenance/mctest.php
+++ b/www/wiki/maintenance/mctest.php
@@ -47,7 +47,7 @@ class McTest extends Maintenance {
$iterations = $this->getOption( 'i', 100 );
if ( $cache ) {
if ( !isset( $wgObjectCaches[$cache] ) ) {
- $this->error( "MediaWiki isn't configured with a cache named '$cache'", 1 );
+ $this->fatalError( "MediaWiki isn't configured with a cache named '$cache'" );
}
$servers = $wgObjectCaches[$cache]['servers'];
} elseif ( $this->hasArg() ) {
@@ -58,7 +58,7 @@ class McTest extends Maintenance {
} elseif ( isset( $wgObjectCaches[$wgMainCacheType]['servers'] ) ) {
$servers = $wgObjectCaches[$wgMainCacheType]['servers'];
} else {
- $this->error( "MediaWiki isn't configured for Memcached usage", 1 );
+ $this->fatalError( "MediaWiki isn't configured for Memcached usage" );
}
# find out the longest server string to nicely align output later on
@@ -102,5 +102,5 @@ class McTest extends Maintenance {
}
}
-$maintClass = "McTest";
+$maintClass = McTest::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/mergeMessageFileList.php b/www/wiki/maintenance/mergeMessageFileList.php
index bb476313..51c41db3 100644
--- a/www/wiki/maintenance/mergeMessageFileList.php
+++ b/www/wiki/maintenance/mergeMessageFileList.php
@@ -26,7 +26,7 @@
define( 'MW_NO_EXTENSION_MESSAGES', 1 );
require_once __DIR__ . '/Maintenance.php';
-$maintClass = 'MergeMessageFileList';
+$maintClass = MergeMessageFileList::class;
$mmfl = false;
/**
@@ -52,17 +52,16 @@ class MergeMessageFileList extends Maintenance {
}
public function execute() {
- // @codingStandardsIgnoreStart Ignore error: Global variable "$mmfl" is lacking 'wg' prefix
+ // phpcs:ignore MediaWiki.NamingConventions.ValidGlobalName.wgPrefix
global $mmfl;
- // @codingStandardsIgnoreEnd
global $wgExtensionEntryPointListFiles;
if ( !count( $wgExtensionEntryPointListFiles )
&& !$this->hasOption( 'list-file' )
&& !$this->hasOption( 'extensions-dir' )
) {
- $this->error( "Either --list-file or --extensions-dir must be provided if " .
- "\$wgExtensionEntryPointListFiles is not set", 1 );
+ $this->fatalError( "Either --list-file or --extensions-dir must be provided if " .
+ "\$wgExtensionEntryPointListFiles is not set" );
}
$mmfl = [ 'setupFiles' => [] ];
@@ -80,29 +79,29 @@ class MergeMessageFileList extends Maintenance {
$extdirs = explode( ':', $extdir );
$entries = [];
foreach ( $extdirs as $extdir ) {
- $entries = array_merge( $entries, scandir( $extdir ) );
- }
- foreach ( $entries as $extname ) {
- if ( $extname == '.' || $extname == '..' || !is_dir( "$extdir/$extname" ) ) {
- continue;
- }
- $possibilities = [
- "$extdir/$extname/extension.json",
- "$extdir/$extname/skin.json",
- "$extdir/$extname/$extname.php"
- ];
- $found = false;
- foreach ( $possibilities as $extfile ) {
- if ( file_exists( $extfile ) ) {
- $mmfl['setupFiles'][] = $extfile;
- $found = true;
- break;
+ $entries = scandir( $extdir );
+ foreach ( $entries as $extname ) {
+ if ( $extname == '.' || $extname == '..' || !is_dir( "$extdir/$extname" ) ) {
+ continue;
+ }
+ $possibilities = [
+ "$extdir/$extname/extension.json",
+ "$extdir/$extname/skin.json",
+ "$extdir/$extname/$extname.php"
+ ];
+ $found = false;
+ foreach ( $possibilities as $extfile ) {
+ if ( file_exists( $extfile ) ) {
+ $mmfl['setupFiles'][] = $extfile;
+ $found = true;
+ break;
+ }
}
- }
- if ( !$found ) {
- $this->error( "Extension {$extname} in {$extdir} lacks expected entry point: " .
- "extension.json, skin.json, or {$extname}.php." );
+ if ( !$found ) {
+ $this->error( "Extension {$extname} in {$extdir} lacks expected entry point: " .
+ "extension.json, skin.json, or {$extname}.php." );
+ }
}
}
}
diff --git a/www/wiki/maintenance/migrateActors.php b/www/wiki/maintenance/migrateActors.php
new file mode 100644
index 00000000..edd5dda0
--- /dev/null
+++ b/www/wiki/maintenance/migrateActors.php
@@ -0,0 +1,550 @@
+<?php
+/**
+ * Migrate actors from pre-1.31 columns to the 'actor' table
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Maintenance
+ */
+
+use Wikimedia\Rdbms\IDatabase;
+
+require_once __DIR__ . '/Maintenance.php';
+
+/**
+ * Maintenance script that migrates actors from pre-1.31 columns to the
+ * 'actor' table
+ *
+ * @ingroup Maintenance
+ */
+class MigrateActors extends LoggedUpdateMaintenance {
+ public function __construct() {
+ parent::__construct();
+ $this->addDescription( 'Migrates actors from pre-1.31 columns to the \'actor\' table' );
+ $this->setBatchSize( 100 );
+ }
+
+ protected function getUpdateKey() {
+ return __CLASS__;
+ }
+
+ protected function doDBUpdates() {
+ global $wgActorTableSchemaMigrationStage;
+
+ if ( $wgActorTableSchemaMigrationStage < MIGRATION_WRITE_NEW ) {
+ $this->output(
+ "...cannot update while \$wgActorTableSchemaMigrationStage < MIGRATION_WRITE_NEW\n"
+ );
+ return false;
+ }
+
+ $this->output( "Creating actor entries for all registered users\n" );
+ $end = 0;
+ $dbw = $this->getDB( DB_MASTER );
+ $max = $dbw->selectField( 'user', 'MAX(user_id)', '', __METHOD__ );
+ $count = 0;
+ while ( $end < $max ) {
+ $start = $end + 1;
+ $end = min( $start + $this->mBatchSize, $max );
+ $this->output( "... $start - $end\n" );
+ $dbw->insertSelect(
+ 'actor',
+ 'user',
+ [ 'actor_user' => 'user_id', 'actor_name' => 'user_name' ],
+ [ "user_id >= $start", "user_id <= $end" ],
+ __METHOD__,
+ [ 'IGNORE' ],
+ [ 'ORDER BY' => [ 'user_id' ] ]
+ );
+ $count += $dbw->affectedRows();
+ wfWaitForSlaves();
+ }
+ $this->output( "Completed actor creation, added $count new actor(s)\n" );
+
+ $errors = 0;
+ $errors += $this->migrateToTemp(
+ 'revision', 'rev_id', [ 'revactor_timestamp' => 'rev_timestamp', 'revactor_page' => 'rev_page' ],
+ 'rev_user', 'rev_user_text', 'revactor_rev', 'revactor_actor'
+ );
+ $errors += $this->migrate( 'archive', 'ar_id', 'ar_user', 'ar_user_text', 'ar_actor' );
+ $errors += $this->migrate( 'ipblocks', 'ipb_id', 'ipb_by', 'ipb_by_text', 'ipb_by_actor' );
+ $errors += $this->migrate( 'image', 'img_name', 'img_user', 'img_user_text', 'img_actor' );
+ $errors += $this->migrate(
+ 'oldimage', [ 'oi_name', 'oi_timestamp' ], 'oi_user', 'oi_user_text', 'oi_actor'
+ );
+ $errors += $this->migrate( 'filearchive', 'fa_id', 'fa_user', 'fa_user_text', 'fa_actor' );
+ $errors += $this->migrate( 'recentchanges', 'rc_id', 'rc_user', 'rc_user_text', 'rc_actor' );
+ $errors += $this->migrate( 'logging', 'log_id', 'log_user', 'log_user_text', 'log_actor' );
+
+ $errors += $this->migrateLogSearch();
+
+ return $errors === 0;
+ }
+
+ /**
+ * Calculate a "next" condition and a display string
+ * @param IDatabase $dbw
+ * @param string[] $primaryKey Primary key of the table.
+ * @param object $row Database row
+ * @return array [ string $next, string $display ]
+ */
+ private function makeNextCond( $dbw, $primaryKey, $row ) {
+ $next = '';
+ $display = [];
+ for ( $i = count( $primaryKey ) - 1; $i >= 0; $i-- ) {
+ $field = $primaryKey[$i];
+ $display[] = $field . '=' . $row->$field;
+ $value = $dbw->addQuotes( $row->$field );
+ if ( $next === '' ) {
+ $next = "$field > $value";
+ } else {
+ $next = "$field > $value OR $field = $value AND ($next)";
+ }
+ }
+ $display = implode( ' ', array_reverse( $display ) );
+ return [ $next, $display ];
+ }
+
+ /**
+ * Add actors for anons in a set of rows
+ * @param IDatabase $dbw
+ * @param string $nameField
+ * @param object[] &$rows
+ * @param array &$complainedAboutUsers
+ * @param int &$countErrors
+ * @return int Count of actors inserted
+ */
+ private function addActorsForRows(
+ IDatabase $dbw, $nameField, array &$rows, array &$complainedAboutUsers, &$countErrors
+ ) {
+ $needActors = [];
+ $countActors = 0;
+
+ $keep = [];
+ foreach ( $rows as $index => $row ) {
+ $keep[$index] = true;
+ if ( $row->actor_id === null ) {
+ // All registered users should have an actor_id already. So
+ // if we have a usable name here, it means they didn't run
+ // maintenance/cleanupUsersWithNoId.php
+ $name = $row->$nameField;
+ if ( User::isUsableName( $name ) ) {
+ if ( !isset( $complainedAboutUsers[$name] ) ) {
+ $complainedAboutUsers[$name] = true;
+ $this->error(
+ "User name \"$name\" is usable, cannot create an anonymous actor for it."
+ . " Run maintenance/cleanupUsersWithNoId.php to fix this situation.\n"
+ );
+ }
+ unset( $keep[$index] );
+ $countErrors++;
+ } else {
+ $needActors[$name] = 0;
+ }
+ }
+ }
+ $rows = array_intersect_key( $rows, $keep );
+
+ if ( $needActors ) {
+ $dbw->insert(
+ 'actor',
+ array_map( function ( $v ) {
+ return [
+ 'actor_name' => $v,
+ ];
+ }, array_keys( $needActors ) ),
+ __METHOD__
+ );
+ $countActors += $dbw->affectedRows();
+
+ $res = $dbw->select(
+ 'actor',
+ [ 'actor_id', 'actor_name' ],
+ [ 'actor_name' => array_keys( $needActors ) ],
+ __METHOD__
+ );
+ foreach ( $res as $row ) {
+ $needActors[$row->actor_name] = $row->actor_id;
+ }
+ foreach ( $rows as $row ) {
+ if ( $row->actor_id === null ) {
+ $row->actor_id = $needActors[$row->$nameField];
+ }
+ }
+ }
+
+ return $countActors;
+ }
+
+ /**
+ * Migrate actors in a table.
+ *
+ * Assumes any row with the actor field non-zero have already been migrated.
+ * Blanks the name field when migrating.
+ *
+ * @param string $table Table to migrate
+ * @param string|string[] $primaryKey Primary key of the table.
+ * @param string $userField User ID field name
+ * @param string $nameField User name field name
+ * @param string $actorField Actor field name
+ * @return int Number of errors
+ */
+ protected function migrate( $table, $primaryKey, $userField, $nameField, $actorField ) {
+ $complainedAboutUsers = [];
+
+ $primaryKey = (array)$primaryKey;
+ $pkFilter = array_flip( $primaryKey );
+ $this->output(
+ "Beginning migration of $table.$userField and $table.$nameField to $table.$actorField\n"
+ );
+ wfWaitForSlaves();
+
+ $dbw = $this->getDB( DB_MASTER );
+ $next = '1=1';
+ $countUpdated = 0;
+ $countActors = 0;
+ $countErrors = 0;
+ while ( true ) {
+ // Fetch the rows needing update
+ $res = $dbw->select(
+ [ $table, 'actor' ],
+ array_merge( $primaryKey, [ $userField, $nameField, 'actor_id' ] ),
+ [
+ $actorField => 0,
+ $next,
+ ],
+ __METHOD__,
+ [
+ 'ORDER BY' => $primaryKey,
+ 'LIMIT' => $this->mBatchSize,
+ ],
+ [
+ 'actor' => [
+ 'LEFT JOIN',
+ "$userField != 0 AND actor_user = $userField OR "
+ . "($userField = 0 OR $userField IS NULL) AND actor_name = $nameField"
+ ]
+ ]
+ );
+ if ( !$res->numRows() ) {
+ break;
+ }
+
+ // Insert new actors for rows that need one
+ $rows = iterator_to_array( $res );
+ $lastRow = end( $rows );
+ $countActors += $this->addActorsForRows(
+ $dbw, $nameField, $rows, $complainedAboutUsers, $countErrors
+ );
+
+ // Update the existing rows
+ foreach ( $rows as $row ) {
+ if ( !$row->actor_id ) {
+ list( , $display ) = $this->makeNextCond( $dbw, $primaryKey, $row );
+ $this->error(
+ "Could not make actor for row with $display "
+ . "$userField={$row->$userField} $nameField={$row->$nameField}\n"
+ );
+ $countErrors++;
+ continue;
+ }
+ $dbw->update(
+ $table,
+ [
+ $actorField => $row->actor_id,
+ $nameField => '',
+ ],
+ array_intersect_key( (array)$row, $pkFilter ) + [
+ $actorField => 0
+ ],
+ __METHOD__
+ );
+ $countUpdated += $dbw->affectedRows();
+ }
+
+ list( $next, $display ) = $this->makeNextCond( $dbw, $primaryKey, $lastRow );
+ $this->output( "... $display\n" );
+ wfWaitForSlaves();
+ }
+
+ $this->output(
+ "Completed migration, updated $countUpdated row(s) with $countActors new actor(s), "
+ . "$countErrors error(s)\n"
+ );
+ return $countErrors;
+ }
+
+ /**
+ * Migrate actors in a table to a temporary table.
+ *
+ * Assumes the new table is named "{$table}_actor_temp", and it has two
+ * columns, in order, being the primary key of the original table and the
+ * actor ID field.
+ * Blanks the name field when migrating.
+ *
+ * @param string $table Table to migrate
+ * @param string $primaryKey Primary key of the table.
+ * @param array $extra Extra fields to copy
+ * @param string $userField User ID field name
+ * @param string $nameField User name field name
+ * @param string $newPrimaryKey Primary key of the new table.
+ * @param string $actorField Actor field name
+ */
+ protected function migrateToTemp(
+ $table, $primaryKey, $extra, $userField, $nameField, $newPrimaryKey, $actorField
+ ) {
+ $complainedAboutUsers = [];
+
+ $newTable = $table . '_actor_temp';
+ $this->output(
+ "Beginning migration of $table.$userField and $table.$nameField to $newTable.$actorField\n"
+ );
+ wfWaitForSlaves();
+
+ $dbw = $this->getDB( DB_MASTER );
+ $next = [];
+ $countUpdated = 0;
+ $countActors = 0;
+ $countErrors = 0;
+ while ( true ) {
+ // Fetch the rows needing update
+ $res = $dbw->select(
+ [ $table, $newTable, 'actor' ],
+ [ $primaryKey, $userField, $nameField, 'actor_id' ] + $extra,
+ [ $newPrimaryKey => null ] + $next,
+ __METHOD__,
+ [
+ 'ORDER BY' => $primaryKey,
+ 'LIMIT' => $this->mBatchSize,
+ ],
+ [
+ $newTable => [ 'LEFT JOIN', "{$primaryKey}={$newPrimaryKey}" ],
+ 'actor' => [
+ 'LEFT JOIN',
+ "$userField != 0 AND actor_user = $userField OR "
+ . "($userField = 0 OR $userField IS NULL) AND actor_name = $nameField"
+ ]
+ ]
+ );
+ if ( !$res->numRows() ) {
+ break;
+ }
+
+ // Insert new actors for rows that need one
+ $rows = iterator_to_array( $res );
+ $lastRow = end( $rows );
+ $countActors += $this->addActorsForRows(
+ $dbw, $nameField, $rows, $complainedAboutUsers, $countErrors
+ );
+
+ // Update rows
+ if ( $rows ) {
+ $inserts = [];
+ $updates = [];
+ foreach ( $rows as $row ) {
+ if ( !$row->actor_id ) {
+ list( , $display ) = $this->makeNextCond( $dbw, [ $primaryKey ], $row );
+ $this->error(
+ "Could not make actor for row with $display "
+ . "$userField={$row->$userField} $nameField={$row->$nameField}\n"
+ );
+ $countErrors++;
+ continue;
+ }
+ $ins = [
+ $newPrimaryKey => $row->$primaryKey,
+ $actorField => $row->actor_id,
+ ];
+ foreach ( $extra as $to => $from ) {
+ $ins[$to] = $row->$to; // It's aliased
+ }
+ $inserts[] = $ins;
+ $updates[] = $row->$primaryKey;
+ }
+ $this->beginTransaction( $dbw, __METHOD__ );
+ $dbw->insert( $newTable, $inserts, __METHOD__ );
+ $dbw->update( $table, [ $nameField => '' ], [ $primaryKey => $updates ], __METHOD__ );
+ $countUpdated += $dbw->affectedRows();
+ $this->commitTransaction( $dbw, __METHOD__ );
+ }
+
+ // Calculate the "next" condition
+ list( $n, $display ) = $this->makeNextCond( $dbw, [ $primaryKey ], $lastRow );
+ $next = [ $n ];
+ $this->output( "... $display\n" );
+ }
+
+ $this->output(
+ "Completed migration, updated $countUpdated row(s) with $countActors new actor(s), "
+ . "$countErrors error(s)\n"
+ );
+ return $countErrors;
+ }
+
+ /**
+ * Migrate actors in the log_search table.
+ * @return int Number of errors
+ */
+ protected function migrateLogSearch() {
+ $complainedAboutUsers = [];
+
+ $primaryKey = [ 'ls_field', 'ls_value' ];
+ $pkFilter = array_flip( $primaryKey );
+ $this->output( "Beginning migration of log_search\n" );
+ wfWaitForSlaves();
+
+ $dbw = $this->getDB( DB_MASTER );
+ $countUpdated = 0;
+ $countActors = 0;
+ $countErrors = 0;
+
+ $next = '1=1';
+ while ( true ) {
+ // Fetch the rows needing update
+ $res = $dbw->select(
+ [ 'log_search', 'actor' ],
+ [ 'ls_field', 'ls_value', 'actor_id' ],
+ [
+ 'ls_field' => 'target_author_id',
+ $next,
+ ],
+ __METHOD__,
+ [
+ 'DISTINCT',
+ 'ORDER BY' => [ 'ls_value' ],
+ 'LIMIT' => $this->mBatchSize,
+ ],
+ [ 'actor' => [ 'LEFT JOIN', 'ls_value = ' . $dbw->buildStringCast( 'actor_user' ) ] ]
+ );
+ if ( !$res->numRows() ) {
+ break;
+ }
+
+ // Update the rows
+ $del = [];
+ foreach ( $res as $row ) {
+ $lastRow = $row;
+ if ( !$row->actor_id ) {
+ list( , $display ) = $this->makeNextCond( $dbw, $primaryKey, $row );
+ $this->error( "No actor for row with $display\n" );
+ $countErrors++;
+ continue;
+ }
+ $dbw->update(
+ 'log_search',
+ [
+ 'ls_field' => 'target_author_actor',
+ 'ls_value' => $row->actor_id,
+ ],
+ [
+ 'ls_field' => $row->ls_field,
+ 'ls_value' => $row->ls_value,
+ ],
+ __METHOD__,
+ [ 'IGNORE' ]
+ );
+ $countUpdated += $dbw->affectedRows();
+ $del[] = $row->ls_value;
+ }
+ if ( $del ) {
+ $dbw->delete(
+ 'log_search', [ 'ls_field' => 'target_author_id', 'ls_value' => $del ], __METHOD__
+ );
+ $countUpdated += $dbw->affectedRows();
+ }
+
+ list( $next, $display ) = $this->makeNextCond( $dbw, $primaryKey, $lastRow );
+ $this->output( "... $display\n" );
+ wfWaitForSlaves();
+ }
+
+ $next = '1=1';
+ while ( true ) {
+ // Fetch the rows needing update
+ $res = $dbw->select(
+ [ 'log_search', 'actor' ],
+ [ 'ls_field', 'ls_value', 'actor_id' ],
+ [
+ 'ls_field' => 'target_author_ip',
+ $next,
+ ],
+ __METHOD__,
+ [
+ 'DISTINCT',
+ 'ORDER BY' => [ 'ls_value' ],
+ 'LIMIT' => $this->mBatchSize,
+ ],
+ [ 'actor' => [ 'LEFT JOIN', 'ls_value = actor_name' ] ]
+ );
+ if ( !$res->numRows() ) {
+ break;
+ }
+
+ // Insert new actors for rows that need one
+ $rows = iterator_to_array( $res );
+ $lastRow = end( $rows );
+ $countActors += $this->addActorsForRows(
+ $dbw, 'ls_value', $rows, $complainedAboutUsers, $countErrors
+ );
+
+ // Update the rows
+ $del = [];
+ foreach ( $rows as $row ) {
+ if ( !$row->actor_id ) {
+ list( , $display ) = $this->makeNextCond( $dbw, $primaryKey, $row );
+ $this->error( "Could not make actor for row with $display\n" );
+ $countErrors++;
+ continue;
+ }
+ $dbw->update(
+ 'log_search',
+ [
+ 'ls_field' => 'target_author_actor',
+ 'ls_value' => $row->actor_id,
+ ],
+ [
+ 'ls_field' => $row->ls_field,
+ 'ls_value' => $row->ls_value,
+ ],
+ __METHOD__,
+ [ 'IGNORE' ]
+ );
+ $countUpdated += $dbw->affectedRows();
+ $del[] = $row->ls_value;
+ }
+ if ( $del ) {
+ $dbw->delete(
+ 'log_search', [ 'ls_field' => 'target_author_ip', 'ls_value' => $del ], __METHOD__
+ );
+ $countUpdated += $dbw->affectedRows();
+ }
+
+ list( $next, $display ) = $this->makeNextCond( $dbw, $primaryKey, $lastRow );
+ $this->output( "... $display\n" );
+ wfWaitForSlaves();
+ }
+
+ $this->output(
+ "Completed migration, updated $countUpdated row(s) with $countActors new actor(s), "
+ . "$countErrors error(s)\n"
+ );
+ return $countErrors;
+ }
+}
+
+$maintClass = "MigrateActors";
+require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/migrateArchiveText.php b/www/wiki/maintenance/migrateArchiveText.php
new file mode 100644
index 00000000..b2b14cbd
--- /dev/null
+++ b/www/wiki/maintenance/migrateArchiveText.php
@@ -0,0 +1,159 @@
+<?php
+/**
+ * Migrate archive.ar_text and ar_flags to modern storage
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Maintenance
+ */
+
+require_once __DIR__ . '/Maintenance.php';
+
+/**
+ * Maintenance script that migrates archive.ar_text and ar_flags to text storage
+ *
+ * @ingroup Maintenance
+ * @since 1.31
+ */
+class MigrateArchiveText extends LoggedUpdateMaintenance {
+ public function __construct() {
+ parent::__construct();
+ $this->addDescription(
+ 'Migrates content from pre-1.5 ar_text and ar_flags columns to text storage'
+ );
+ $this->addOption(
+ 'replace-missing',
+ "For rows with missing or unloadable data, throw away whatever is there and\n"
+ . "mark them as \"error\" in the database."
+ );
+ }
+
+ /**
+ * Sets whether a run of this maintenance script has the force parameter set
+ * @param bool $forced
+ */
+ public function setForce( $forced = true ) {
+ $this->mOptions['force'] = $forced;
+ }
+
+ protected function getUpdateKey() {
+ return __CLASS__;
+ }
+
+ protected function doDBUpdates() {
+ global $wgDefaultExternalStore;
+
+ $replaceMissing = $this->hasOption( 'replace-missing' );
+ $batchSize = $this->getBatchSize();
+
+ $dbr = $this->getDB( DB_REPLICA, [ 'vslow' ] );
+ $dbw = $this->getDB( DB_MASTER );
+ if ( !$dbr->fieldExists( 'archive', 'ar_text', __METHOD__ ) ||
+ !$dbw->fieldExists( 'archive', 'ar_text', __METHOD__ )
+ ) {
+ $this->output( "No ar_text field, so nothing to migrate.\n" );
+ return true;
+ }
+
+ $this->output( "Migrating ar_text to modern storage...\n" );
+ $last = 0;
+ $count = 0;
+ $errors = 0;
+ while ( true ) {
+ $res = $dbr->select(
+ 'archive',
+ [ 'ar_id', 'ar_text', 'ar_flags' ],
+ [
+ 'ar_text_id' => null,
+ "ar_id > $last",
+ ],
+ __METHOD__,
+ [ 'LIMIT' => $batchSize, 'ORDER BY' => [ 'ar_id' ] ]
+ );
+ $numRows = $res->numRows();
+
+ foreach ( $res as $row ) {
+ $last = $row->ar_id;
+
+ // Recompress the text (and store in external storage, if
+ // applicable) if it's not already in external storage.
+ if ( !in_array( 'external', explode( ',', $row->ar_flags ), true ) ) {
+ $data = Revision::getRevisionText( $row, 'ar_' );
+ if ( $data !== false ) {
+ $flags = Revision::compressRevisionText( $data );
+
+ if ( $wgDefaultExternalStore ) {
+ $data = ExternalStore::insertToDefault( $data );
+ if ( !$data ) {
+ throw new MWException( "Unable to store text to external storage" );
+ }
+ if ( $flags ) {
+ $flags .= ',';
+ }
+ $flags .= 'external';
+ }
+ } elseif ( $replaceMissing ) {
+ $this->error( "Replacing missing data for row ar_id=$row->ar_id" );
+ $data = 'Missing data in migrateArchiveText.php on ' . date( 'c' );
+ $flags = 'error';
+ } else {
+ $this->error( "No data for row ar_id=$row->ar_id" );
+ $errors++;
+ continue;
+ }
+ } else {
+ $flags = $row->ar_flags;
+ $data = $row->ar_text;
+ }
+
+ $this->beginTransaction( $dbw, __METHOD__ );
+ $dbw->insert(
+ 'text',
+ [ 'old_text' => $data, 'old_flags' => $flags ],
+ __METHOD__
+ );
+ $id = $dbw->insertId();
+ $dbw->update(
+ 'archive',
+ [ 'ar_text_id' => $id, 'ar_text' => '', 'ar_flags' => '' ],
+ [ 'ar_id' => $row->ar_id, 'ar_text_id' => null ],
+ __METHOD__
+ );
+ $count += $dbw->affectedRows();
+ $this->commitTransaction( $dbw, __METHOD__ );
+ }
+
+ if ( $numRows < $batchSize ) {
+ // We must have reached the end
+ break;
+ }
+
+ $this->output( "... $last\n" );
+ // $this->commitTransaction() already waited for replication; no need to re-wait here
+ }
+
+ $this->output( "Completed ar_text migration, $count rows updated, $errors missing data.\n" );
+ if ( $errors ) {
+ $this->output( "Run with --replace-missing to overwrite missing data with an error message.\n" );
+ }
+
+ return $errors === 0;
+ }
+}
+
+$maintClass = MigrateArchiveText::class;
+require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/migrateComments.php b/www/wiki/maintenance/migrateComments.php
index 4af6a2ad..cdecab03 100644
--- a/www/wiki/maintenance/migrateComments.php
+++ b/www/wiki/maintenance/migrateComments.php
@@ -162,7 +162,7 @@ class MigrateComments extends LoggedUpdateMaintenance {
__METHOD__,
[
'ORDER BY' => $primaryKey,
- 'LIMIT' => $this->mBatchSize,
+ 'LIMIT' => $this->getBatchSize(),
]
);
if ( !$res->numRows() ) {
@@ -205,7 +205,7 @@ class MigrateComments extends LoggedUpdateMaintenance {
$next = "$field > $value OR $field = $value AND ($next)";
}
}
- $prompt = join( ' ', array_reverse( $prompt ) );
+ $prompt = implode( ' ', array_reverse( $prompt ) );
$this->output( "... $prompt\n" );
wfWaitForSlaves();
}
@@ -248,7 +248,7 @@ class MigrateComments extends LoggedUpdateMaintenance {
__METHOD__,
[
'ORDER BY' => $primaryKey,
- 'LIMIT' => $this->mBatchSize,
+ 'LIMIT' => $this->getBatchSize(),
],
[ $newTable => [ 'LEFT JOIN', "{$primaryKey}={$newPrimaryKey}" ] ]
);
@@ -282,7 +282,6 @@ class MigrateComments extends LoggedUpdateMaintenance {
// Calculate the "next" condition
$next = [ $primaryKey . ' > ' . $dbw->addQuotes( $row->$primaryKey ) ];
$this->output( "... {$row->$primaryKey}\n" );
- wfWaitForSlaves();
}
$this->output(
@@ -291,5 +290,5 @@ class MigrateComments extends LoggedUpdateMaintenance {
}
}
-$maintClass = "MigrateComments";
+$maintClass = MigrateComments::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/migrateFileRepoLayout.php b/www/wiki/maintenance/migrateFileRepoLayout.php
index f771fff7..6188ea14 100644
--- a/www/wiki/maintenance/migrateFileRepoLayout.php
+++ b/www/wiki/maintenance/migrateFileRepoLayout.php
@@ -43,11 +43,11 @@ class MigrateFileRepoLayout extends Maintenance {
public function execute() {
$oldLayout = $this->getOption( 'oldlayout' );
if ( !in_array( $oldLayout, [ 'name', 'sha1' ] ) ) {
- $this->error( "Invalid old layout.", 1 );
+ $this->fatalError( "Invalid old layout." );
}
$newLayout = $this->getOption( 'newlayout' );
if ( !in_array( $newLayout, [ 'name', 'sha1' ] ) ) {
- $this->error( "Invalid new layout.", 1 );
+ $this->fatalError( "Invalid new layout." );
}
$since = $this->getOption( 'since' );
@@ -69,6 +69,7 @@ class MigrateFileRepoLayout extends Maintenance {
$conds[] = 'img_timestamp >= ' . $dbw->addQuotes( $dbw->timestamp( $since ) );
}
+ $batchSize = $this->getBatchSize();
$batch = [];
$lastName = '';
do {
@@ -76,7 +77,7 @@ class MigrateFileRepoLayout extends Maintenance {
[ 'img_name', 'img_sha1' ],
array_merge( [ 'img_name > ' . $dbw->addQuotes( $lastName ) ], $conds ),
__METHOD__,
- [ 'LIMIT' => $this->mBatchSize, 'ORDER BY' => 'img_name' ]
+ [ 'LIMIT' => $batchSize, 'ORDER BY' => 'img_name' ]
);
foreach ( $res as $row ) {
@@ -143,7 +144,7 @@ class MigrateFileRepoLayout extends Maintenance {
'src' => $spath, 'dst' => $dpath, 'img' => $ofile->getArchiveName() ];
}
- if ( count( $batch ) >= $this->mBatchSize ) {
+ if ( count( $batch ) >= $batchSize ) {
$this->runBatch( $batch, $be );
$batch = [];
}
@@ -166,7 +167,7 @@ class MigrateFileRepoLayout extends Maintenance {
$res = $dbw->select( 'filearchive', [ 'fa_storage_key', 'fa_id', 'fa_name' ],
array_merge( [ 'fa_id > ' . $dbw->addQuotes( $lastId ) ], $conds ),
__METHOD__,
- [ 'LIMIT' => $this->mBatchSize, 'ORDER BY' => 'fa_id' ]
+ [ 'LIMIT' => $batchSize, 'ORDER BY' => 'fa_id' ]
);
foreach ( $res as $row ) {
@@ -201,7 +202,7 @@ class MigrateFileRepoLayout extends Maintenance {
$batch[] = [ 'op' => 'copy', 'src' => $spath, 'dst' => $dpath,
'overwriteSame' => true, 'img' => "(ID {$row->fa_id}) {$row->fa_name}" ];
- if ( count( $batch ) >= $this->mBatchSize ) {
+ if ( count( $batch ) >= $batchSize ) {
$this->runBatch( $batch, $be );
$batch = [];
}
@@ -234,5 +235,5 @@ class MigrateFileRepoLayout extends Maintenance {
}
}
-$maintClass = 'MigrateFileRepoLayout';
+$maintClass = MigrateFileRepoLayout::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/migrateUserGroup.php b/www/wiki/maintenance/migrateUserGroup.php
index 597a876d..bf8d071c 100644
--- a/www/wiki/maintenance/migrateUserGroup.php
+++ b/www/wiki/maintenance/migrateUserGroup.php
@@ -42,17 +42,18 @@ class MigrateUserGroup extends Maintenance {
$oldGroup = $this->getArg( 0 );
$newGroup = $this->getArg( 1 );
$dbw = $this->getDB( DB_MASTER );
+ $batchSize = $this->getBatchSize();
$start = $dbw->selectField( 'user_groups', 'MIN(ug_user)',
[ 'ug_group' => $oldGroup ], __FUNCTION__ );
$end = $dbw->selectField( 'user_groups', 'MAX(ug_user)',
[ 'ug_group' => $oldGroup ], __FUNCTION__ );
if ( $start === null ) {
- $this->error( "Nothing to do - no users in the '$oldGroup' group", true );
+ $this->fatalError( "Nothing to do - no users in the '$oldGroup' group" );
}
# Do remaining chunk
- $end += $this->mBatchSize - 1;
+ $end += $batchSize - 1;
$blockStart = $start;
- $blockEnd = $start + $this->mBatchSize - 1;
+ $blockEnd = $start + $batchSize - 1;
// Migrate users over in batches...
while ( $blockEnd <= $end ) {
$affected = 0;
@@ -62,7 +63,7 @@ class MigrateUserGroup extends Maintenance {
$dbw->update( 'user_groups',
[ 'ug_group' => $newGroup ],
[ 'ug_group' => $oldGroup,
- "ug_user BETWEEN $blockStart AND $blockEnd" ],
+ "ug_user BETWEEN " . (int)$blockStart . " AND " . (int)$blockEnd ],
__METHOD__,
[ 'IGNORE' ]
);
@@ -73,7 +74,7 @@ class MigrateUserGroup extends Maintenance {
// user/group is UNIQUE.
$dbw->delete( 'user_groups',
[ 'ug_group' => $oldGroup,
- "ug_user BETWEEN $blockStart AND $blockEnd" ],
+ "ug_user BETWEEN " . (int)$blockStart . " AND " . (int)$blockEnd ],
__METHOD__
);
$affected += $dbw->affectedRows();
@@ -85,7 +86,7 @@ class MigrateUserGroup extends Maintenance {
// were in the new group and not in the group.
$res = $dbw->select( 'user_groups', 'ug_user',
[ 'ug_group' => $newGroup,
- "ug_user BETWEEN $blockStart AND $blockEnd" ],
+ "ug_user BETWEEN " . (int)$blockStart . " AND " . (int)$blockEnd ],
__METHOD__
);
if ( $res !== false ) {
@@ -97,13 +98,12 @@ class MigrateUserGroup extends Maintenance {
}
$count += $affected;
- $blockStart += $this->mBatchSize;
- $blockEnd += $this->mBatchSize;
- wfWaitForSlaves();
+ $blockStart += $batchSize;
+ $blockEnd += $batchSize;
}
$this->output( "Done! $count users in group '$oldGroup' are now in '$newGroup' instead.\n" );
}
}
-$maintClass = "MigrateUserGroup";
+$maintClass = MigrateUserGroup::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/minify.php b/www/wiki/maintenance/minify.php
index 16e4d1c9..ddae17d9 100644
--- a/www/wiki/maintenance/minify.php
+++ b/www/wiki/maintenance/minify.php
@@ -48,14 +48,12 @@ class MinifyScript extends Maintenance {
public function execute() {
if ( !count( $this->mArgs ) ) {
- $this->error( "minify.php: At least one input file must be specified." );
- exit( 1 );
+ $this->fatalError( "minify.php: At least one input file must be specified." );
}
if ( $this->hasOption( 'outfile' ) ) {
if ( count( $this->mArgs ) > 1 ) {
- $this->error( '--outfile may only be used with a single input file.' );
- exit( 1 );
+ $this->fatalError( '--outfile may only be used with a single input file.' );
}
// Minify one file
@@ -77,7 +75,7 @@ class MinifyScript extends Maintenance {
}
if ( !file_exists( $inPath ) ) {
- $this->error( "File does not exist: $arg", true );
+ $this->fatalError( "File does not exist: $arg" );
}
$extension = $this->getExtension( $inName );
@@ -95,8 +93,7 @@ class MinifyScript extends Maintenance {
public function getExtension( $fileName ) {
$dotPos = strrpos( $fileName, '.' );
if ( $dotPos === false ) {
- $this->error( "No file extension, cannot determine type: $fileName" );
- exit( 1 );
+ $this->fatalError( "No file extension, cannot determine type: $fileName" );
}
return substr( $fileName, $dotPos + 1 );
@@ -108,13 +105,11 @@ class MinifyScript extends Maintenance {
$inText = file_get_contents( $inPath );
if ( $inText === false ) {
- $this->error( "Unable to open file $inPath for reading." );
- exit( 1 );
+ $this->fatalError( "Unable to open file $inPath for reading." );
}
$outFile = fopen( $outPath, 'w' );
if ( !$outFile ) {
- $this->error( "Unable to open file $outPath for writing." );
- exit( 1 );
+ $this->fatalError( "Unable to open file $outPath for writing." );
}
switch ( $extension ) {
@@ -134,5 +129,5 @@ class MinifyScript extends Maintenance {
}
}
-$maintClass = 'MinifyScript';
+$maintClass = MinifyScript::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/moveBatch.php b/www/wiki/maintenance/moveBatch.php
index d578a496..6d14f8af 100644
--- a/www/wiki/maintenance/moveBatch.php
+++ b/www/wiki/maintenance/moveBatch.php
@@ -73,7 +73,7 @@ class MoveBatch extends Maintenance {
# Setup
if ( !$file ) {
- $this->error( "Unable to read file, exiting", true );
+ $this->fatalError( "Unable to read file, exiting" );
}
if ( $user === false ) {
$wgUser = User::newSystemUser( 'Move page script', [ 'steal' => true ] );
@@ -81,14 +81,13 @@ class MoveBatch extends Maintenance {
$wgUser = User::newFromName( $user );
}
if ( !$wgUser ) {
- $this->error( "Invalid username", true );
+ $this->fatalError( "Invalid username" );
}
# Setup complete, now start
$dbw = $this->getDB( DB_MASTER );
- // @codingStandardsIgnoreStart Ignore avoid function calls in a FOR loop test part warning
+ // phpcs:ignore Generic.CodeAnalysis.ForLoopWithTestFunctionCall
for ( $linenum = 1; !feof( $file ); $linenum++ ) {
- // @codingStandardsIgnoreEnd
$line = fgets( $file );
if ( $line === false ) {
break;
@@ -118,10 +117,9 @@ class MoveBatch extends Maintenance {
if ( $interval ) {
sleep( $interval );
}
- wfWaitForSlaves();
}
}
}
-$maintClass = "MoveBatch";
+$maintClass = MoveBatch::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/mssql/archives/patch-actor-table.sql b/www/wiki/maintenance/mssql/archives/patch-actor-table.sql
new file mode 100644
index 00000000..b26ad44a
--- /dev/null
+++ b/www/wiki/maintenance/mssql/archives/patch-actor-table.sql
@@ -0,0 +1,53 @@
+--
+-- patch-actor-table.sql
+--
+-- T167246. Add an `actor` table and various columns (and temporary tables) to reference it.
+
+CREATE TABLE /*_*/actor (
+ actor_id bigint unsigned NOT NULL CONSTRAINT PK_actor PRIMARY KEY IDENTITY(0,1),
+ actor_user int unsigned,
+ actor_name nvarchar(255) NOT NULL
+);
+CREATE UNIQUE INDEX /*i*/actor_user ON /*_*/actor (actor_user);
+CREATE UNIQUE INDEX /*i*/actor_name ON /*_*/actor (actor_name);
+
+-- Dummy
+INSERT INTO /*_*/actor (actor_name) VALUES ('##Anonymous##');
+
+CREATE TABLE /*_*/revision_actor_temp (
+ revactor_rev int unsigned NOT NULL CONSTRAINT FK_revactor_rev FOREIGN KEY REFERENCES /*_*/revision(rev_id) ON DELETE CASCADE,
+ revactor_actor bigint unsigned NOT NULL,
+ revactor_timestamp varchar(14) NOT NULL CONSTRAINT DF_revactor_timestamp DEFAULT '',
+ revactor_page int unsigned NOT NULL,
+ CONSTRAINT PK_revision_actor_temp PRIMARY KEY (revactor_rev, revactor_actor)
+);
+CREATE UNIQUE INDEX /*i*/revactor_rev ON /*_*/revision_actor_temp (revactor_rev);
+CREATE INDEX /*i*/actor_timestamp ON /*_*/revision_actor_temp (revactor_actor,revactor_timestamp);
+CREATE INDEX /*i*/page_actor_timestamp ON /*_*/revision_actor_temp (revactor_page,revactor_actor,revactor_timestamp);
+
+ALTER TABLE /*_*/archive ADD CONSTRAINT DF_ar_user_text DEFAULT '' FOR ar_user_text;
+ALTER TABLE /*_*/archive ADD ar_actor bigint unsigned NOT NULL CONSTRAINT DF_ar_actor DEFAULT 0;
+CREATE INDEX /*i*/ar_actor_timestamp ON /*_*/archive (ar_actor,ar_timestamp);
+
+ALTER TABLE /*_*/ipblocks ADD ipb_by_actor bigint unsigned NOT NULL CONSTRAINT DF_ipb_by_actor DEFAULT 0;
+
+ALTER TABLE /*_*/image ADD CONSTRAINT DF_img_user_text DEFAULT '' FOR img_user_text;
+ALTER TABLE /*_*/image ADD img_actor bigint unsigned NOT NULL CONSTRAINT DF_img_actor DEFAULT 0;
+CREATE INDEX /*i*/img_actor_timestamp ON /*_*/image (img_actor, img_timestamp);
+
+ALTER TABLE /*_*/oldimage ADD CONSTRAINT DF_oi_user_text DEFAULT '' FOR oi_user_text;
+ALTER TABLE /*_*/oldimage ADD oi_actor bigint unsigned NOT NULL CONSTRAINT DF_oi_actor DEFAULT 0;
+CREATE INDEX /*i*/oi_actor_timestamp ON /*_*/oldimage (oi_actor,oi_timestamp);
+
+ALTER TABLE /*_*/filearchive ADD CONSTRAINT DF_fa_user_text DEFAULT '' FOR fa_user_text;
+ALTER TABLE /*_*/filearchive ADD fa_actor bigint unsigned NOT NULL CONSTRAINT DF_fa_actor DEFAULT 0;
+CREATE INDEX /*i*/fa_actor_timestamp ON /*_*/filearchive (fa_actor,fa_timestamp);
+
+ALTER TABLE /*_*/recentchanges ADD CONSTRAINT DF_rc_user_text DEFAULT '' FOR rc_user_text;
+ALTER TABLE /*_*/recentchanges ADD rc_actor bigint unsigned NOT NULL CONSTRAINT DF_rc_actor DEFAULT 0;
+CREATE INDEX /*i*/rc_ns_actor ON /*_*/recentchanges (rc_namespace, rc_actor);
+CREATE INDEX /*i*/rc_actor ON /*_*/recentchanges (rc_actor, rc_timestamp);
+
+ALTER TABLE /*_*/logging ADD log_actor bigint unsigned NOT NULL CONSTRAINT DF_log_actor DEFAULT 0;
+CREATE INDEX /*i*/actor_time ON /*_*/logging (log_actor, log_timestamp);
+CREATE INDEX /*i*/log_actor_type_time ON /*_*/logging (log_actor, log_type, log_timestamp);
diff --git a/www/wiki/maintenance/mssql/archives/patch-ar_rev_id-not-null.sql b/www/wiki/maintenance/mssql/archives/patch-ar_rev_id-not-null.sql
new file mode 100644
index 00000000..d287f49c
--- /dev/null
+++ b/www/wiki/maintenance/mssql/archives/patch-ar_rev_id-not-null.sql
@@ -0,0 +1 @@
+ALTER TABLE /*_*/archive ALTER COLUMN ar_rev_id INT NOT NULL;
diff --git a/www/wiki/maintenance/mssql/archives/patch-comment-table.sql b/www/wiki/maintenance/mssql/archives/patch-comment-table.sql
new file mode 100644
index 00000000..f4c2a900
--- /dev/null
+++ b/www/wiki/maintenance/mssql/archives/patch-comment-table.sql
@@ -0,0 +1,57 @@
+--
+-- patch-comment-table.sql
+--
+-- T166732. Add a `comment` table and various columns (and temporary tables) to reference it.
+
+CREATE TABLE /*_*/comment (
+ comment_id bigint unsigned NOT NULL PRIMARY KEY IDENTITY(0,1),
+ comment_hash INT NOT NULL,
+ comment_text nvarchar(max) NOT NULL,
+ comment_data nvarchar(max)
+);
+CREATE INDEX /*i*/comment_hash ON /*_*/comment (comment_hash);
+
+-- dummy row for FKs. Hash is intentionally wrong so CommentStore won't match it.
+INSERT INTO /*_*/comment (comment_hash, comment_text) VALUES (-1, '** dummy **');
+
+
+CREATE TABLE /*_*/revision_comment_temp (
+ revcomment_rev INT NOT NULL CONSTRAINT FK_revcomment_rev FOREIGN KEY REFERENCES /*_*/revision(rev_id) ON DELETE CASCADE,
+ revcomment_comment_id bigint unsigned NOT NULL CONSTRAINT FK_revcomment_comment_id FOREIGN KEY REFERENCES /*_*/comment(comment_id),
+ CONSTRAINT PK_revision_comment_temp PRIMARY KEY (revcomment_rev, revcomment_comment_id)
+);
+CREATE UNIQUE INDEX /*i*/revcomment_rev ON /*_*/revision_comment_temp (revcomment_rev);
+
+
+CREATE TABLE /*_*/image_comment_temp (
+ imgcomment_name nvarchar(255) NOT NULL CONSTRAINT FK_imgcomment_name FOREIGN KEY REFERENCES /*_*/image(imgcomment_name) ON DELETE CASCADE,
+ imgcomment_description_id bigint unsigned NOT NULL CONSTRAINT FK_imgcomment_description_id FOREIGN KEY REFERENCES /*_*/comment(comment_id),
+ CONSTRAINT PK_image_comment_temp PRIMARY KEY (imgcomment_name, imgcomment_description_id)
+);
+CREATE UNIQUE INDEX /*i*/imgcomment_name ON /*_*/image_comment_temp (imgcomment_name);
+
+
+ALTER TABLE /*_*/revision ADD CONSTRAINT DF_rev_comment DEFAULT '' FOR rev_comment;
+
+ALTER TABLE /*_*/archive ADD CONSTRAINT DF_ar_comment DEFAULT '' FOR ar_comment;
+ALTER TABLE /*_*/archive ADD ar_comment_id bigint unsigned NOT NULL CONSTRAINT DF_ar_comment_id DEFAULT 0 CONSTRAINT FK_ar_comment_id FOREIGN KEY REFERENCES /*_*/comment(comment_id);
+
+ALTER TABLE /*_*/ipblocks ADD CONSTRAINT DF_ipb_reason DEFAULT '' FOR ipb_reason;
+ALTER TABLE /*_*/ipblocks ADD ipb_reason_id bigint unsigned NOT NULL CONSTRAINT DF_ipb_reason_id DEFAULT 0 CONSTRAINT FK_ipb_reason_id FOREIGN KEY REFERENCES /*_*/comment(comment_id);
+
+ALTER TABLE /*_*/image ADD CONSTRAINT DF_img_description DEFAULT '' FOR img_description;
+
+ALTER TABLE /*_*/oldimage ADD CONSTRAINT DF_oi_description DEFAULT '' FOR oi_description;
+ALTER TABLE /*_*/oldimage ADD oi_description_id bigint unsigned NOT NULL CONSTRAINT DF_oi_description_id DEFAULT 0 CONSTRAINT FK_oi_description_id FOREIGN KEY REFERENCES /*_*/comment(comment_id);
+
+ALTER TABLE /*_*/filearchive ADD CONSTRAINT DF_fa_deleted_reason DEFAULT '' FOR fa_deleted_reason;
+ALTER TABLE /*_*/filearchive ADD fa_deleted_reason_id bigint unsigned NOT NULL CONSTRAINT DF_fa_deleted_reason_id DEFAULT 0 CONSTRAINT FK_fa_deleted_reason_id FOREIGN KEY REFERENCES /*_*/comment(comment_id);
+ALTER TABLE /*_*/filearchive ADD CONSTRAINT DF_fa_description DEFAULT '' FOR fa_description;
+ALTER TABLE /*_*/filearchive ADD fa_description_id bigint unsigned NOT NULL CONSTRAINT DF_fa_description_id DEFAULT 0 CONSTRAINT FK_fa_description_id FOREIGN KEY REFERENCES /*_*/comment(comment_id);
+
+ALTER TABLE /*_*/recentchanges ADD rc_comment_id bigint unsigned NOT NULL CONSTRAINT DF_rc_comment_id DEFAULT 0 CONSTRAINT FK_rc_comment_id FOREIGN KEY REFERENCES /*_*/comment(comment_id);
+
+ALTER TABLE /*_*/logging ADD log_comment_id bigint unsigned NOT NULL CONSTRAINT DF_log_comment_id DEFAULT 0 CONSTRAINT FK_log_comment_id FOREIGN KEY REFERENCES /*_*/comment(comment_id);
+
+ALTER TABLE /*_*/protected_titles ADD CONSTRAINT DF_pt_reason DEFAULT '' FOR pt_reason;
+ALTER TABLE /*_*/protected_titles ADD pt_reason_id bigint unsigned NOT NULL CONSTRAINT DF_pt_reason_id DEFAULT 0 CONSTRAINT FK_pt_reason_id FOREIGN KEY REFERENCES /*_*/comment(comment_id);
diff --git a/www/wiki/maintenance/mssql/archives/patch-content.sql b/www/wiki/maintenance/mssql/archives/patch-content.sql
new file mode 100644
index 00000000..c5b079ab
--- /dev/null
+++ b/www/wiki/maintenance/mssql/archives/patch-content.sql
@@ -0,0 +1,21 @@
+--
+-- The content table represents content objects. It's primary purpose is to provide the necessary
+-- meta-data for loading and interpreting a serialized data blob to create a content object.
+--
+CREATE TABLE /*_*/content (
+
+ -- ID of the content object
+ content_id bigint unsigned NOT NULL CONSTRAINT PK_content PRIMARY KEY IDENTITY,
+
+ -- Nominal size of the content object (not necessarily of the serialized blob)
+ content_size int unsigned NOT NULL,
+
+ -- Nominal hash of the content object (not necessarily of the serialized blob)
+ content_sha1 varchar(32) NOT NULL,
+
+ -- reference to model_id
+ content_model smallint unsigned NOT NULL CONSTRAINT FK_content_content_models FOREIGN KEY REFERENCES /*_*/content_models(model_id),
+
+ -- URL-like address of the content blob
+ content_address nvarchar(255) NOT NULL
+); \ No newline at end of file
diff --git a/www/wiki/maintenance/mssql/archives/patch-content_models.sql b/www/wiki/maintenance/mssql/archives/patch-content_models.sql
new file mode 100644
index 00000000..b94de0b3
--- /dev/null
+++ b/www/wiki/maintenance/mssql/archives/patch-content_models.sql
@@ -0,0 +1,11 @@
+
+--
+-- Normalization table for content model names
+--
+CREATE TABLE /*_*/content_models (
+ model_id smallint NOT NULL CONSTRAINT PK_content_models PRIMARY KEY IDENTITY,
+ model_name nvarchar(64) NOT NULL
+);
+
+-- Index for looking of the internal ID of for a name
+CREATE UNIQUE INDEX /*i*/model_name ON /*_*/content_models (model_name); \ No newline at end of file
diff --git a/www/wiki/maintenance/mssql/archives/patch-drop-ar_text.sql b/www/wiki/maintenance/mssql/archives/patch-drop-ar_text.sql
new file mode 100644
index 00000000..c9b975cc
--- /dev/null
+++ b/www/wiki/maintenance/mssql/archives/patch-drop-ar_text.sql
@@ -0,0 +1,21 @@
+DECLARE @sql nvarchar(max),
+ @id sysname;--
+
+SET @sql = 'ALTER TABLE /*_*/archive DROP CONSTRAINT ';--
+
+SELECT @id = df.name
+FROM sys.default_constraints df
+JOIN sys.columns c
+ ON c.object_id = df.parent_object_id
+ AND c.column_id = df.parent_column_id
+WHERE
+ df.parent_object_id = OBJECT_ID('/*_*/archive')
+ AND ( c.name = 'ar_text' OR c.name = 'ar_flags' );--
+
+SET @sql = @sql + @id;--
+
+EXEC sp_executesql @sql;--
+
+ALTER TABLE /*_*/archive DROP COLUMN ar_text;
+ALTER TABLE /*_*/archive DROP COLUMN ar_flags;
+ALTER TABLE /*_*/archive ALTER COLUMN ar_text_id INT NOT NULL CONSTRAINT DF_ar_text_id DEFAULT 0;
diff --git a/www/wiki/maintenance/mssql/archives/patch-image-img_description_id.sql b/www/wiki/maintenance/mssql/archives/patch-image-img_description_id.sql
new file mode 100644
index 00000000..bc51b529
--- /dev/null
+++ b/www/wiki/maintenance/mssql/archives/patch-image-img_description_id.sql
@@ -0,0 +1,6 @@
+--
+-- patch-image-img_description_id.sql
+--
+-- T188132. Add `img_description_id` to the `image` table.
+
+ALTER TABLE /*_*/image ADD img_description_id bigint NOT NULL CONSTRAINT DF_img_description_id DEFAULT 0 CONSTRAINT FK_img_description_id FOREIGN KEY REFERENCES /*_*/comment(comment_id);
diff --git a/www/wiki/maintenance/mssql/archives/patch-rc_patrolled_type.sql b/www/wiki/maintenance/mssql/archives/patch-rc_patrolled_type.sql
new file mode 100644
index 00000000..c8c77559
--- /dev/null
+++ b/www/wiki/maintenance/mssql/archives/patch-rc_patrolled_type.sql
@@ -0,0 +1,22 @@
+DECLARE @cname sysname;--
+
+SELECT @cname = dc.name
+FROM sys.default_constraints dc
+JOIN sys.columns c
+ ON c.object_id = dc.parent_object_id
+ AND c.column_id = dc.parent_column_id
+WHERE
+ c.name = 'rc_patrolled'
+ AND c.object_id = OBJECT_ID('/*_*/recentchanges', 'U');--
+
+IF @cname IS NOT NULL
+BEGIN;--
+ DECLARE @sql nvarchar(max);--
+ SET @sql = N'ALTER TABLE /*_*/recentchanges DROP CONSTRAINT ' + @cname;--
+ EXEC sp_executesql @sql;--
+END;--
+
+DROP INDEX /*i*/rc_name_type_patrolled_timestamp ON /*_*/recentchanges;--
+ALTER TABLE /*_*/recentchanges ALTER COLUMN rc_patrolled tinyint NOT NULL;--
+ALTER TABLE /*_*/recentchanges ADD CONSTRAINT DF_rc_patrolled DEFAULT 0 FOR rc_patrolled;--
+CREATE INDEX /*i*/rc_name_type_patrolled_timestamp ON /*_*/recentchanges (rc_namespace, rc_type, rc_patrolled, rc_timestamp); \ No newline at end of file
diff --git a/www/wiki/maintenance/mssql/archives/patch-rev_text_id-default.sql b/www/wiki/maintenance/mssql/archives/patch-rev_text_id-default.sql
new file mode 100644
index 00000000..0c9d48a3
--- /dev/null
+++ b/www/wiki/maintenance/mssql/archives/patch-rev_text_id-default.sql
@@ -0,0 +1,10 @@
+--
+-- Adds a default value to the rev_text_id field in the revision table.
+-- This is to allow the Multi Content Revisions migration to happen where
+-- rows will have to be added to the revision table with no rev_text_id.
+--
+-- 2018-03-12
+--
+
+ALTER TABLE /*_*/revision
+ ADD CONSTRAINT DF_rev_text_id DEFAULT 0 FOR rev_text_id; \ No newline at end of file
diff --git a/www/wiki/maintenance/mssql/archives/patch-site_stats-modify.sql b/www/wiki/maintenance/mssql/archives/patch-site_stats-modify.sql
new file mode 100644
index 00000000..b2de9483
--- /dev/null
+++ b/www/wiki/maintenance/mssql/archives/patch-site_stats-modify.sql
@@ -0,0 +1,32 @@
+/* Delete old default constraints */
+DECLARE @sql nvarchar(max)
+SET @sql=''
+
+/* IMHO: A DBMS where you have to do THIS to change a default value sucks. */
+SELECT @sql= @sql + 'ALTER TABLE site_stats DROP CONSTRAINT ' + df.name + '; '
+FROM sys.default_constraints df
+JOIN sys.columns c
+ ON c.object_id = df.parent_object_id
+ AND c.column_id = df.parent_column_id
+WHERE
+ df.parent_object_id = OBJECT_ID('site_stats');--
+
+EXEC sp_executesql @sql;
+
+/* Change data type of ss_images from int to bigint.
+ * All other fields (except ss_row_id) already are bigint.
+ * This MUST happen before adding new constraints. */
+ALTER TABLE site_stats ALTER COLUMN ss_images bigint;
+
+/* Add new default constraints.
+ * Don't ask me why I have to repeat ALTER TABLE site_stats
+ * instead of using commas, for some reason SQL Server 2016
+ * didn't accept it in any other way. Maybe I just don't know
+ * enough about mssql, but this works.
+ */
+ALTER TABLE site_stats ADD CONSTRAINT col_ss_total_edits DEFAULT NULL FOR ss_total_edits;
+ALTER TABLE site_stats ADD CONSTRAINT col_ss_good_article DEFAULT NULL FOR ss_good_articles;
+ALTER TABLE site_stats ADD CONSTRAINT col_ss_total_pages DEFAULT NULL FOR ss_total_pages;
+ALTER TABLE site_stats ADD CONSTRAINT col_ss_users DEFAULT NULL FOR ss_users;
+ALTER TABLE site_stats ADD CONSTRAINT col_ss_active_users DEFAULT NULL FOR ss_active_users;
+ALTER TABLE site_stats ADD CONSTRAINT col_ss_images DEFAULT NULL FOR ss_images;
diff --git a/www/wiki/maintenance/mssql/archives/patch-slot-origin.sql b/www/wiki/maintenance/mssql/archives/patch-slot-origin.sql
new file mode 100644
index 00000000..bba3be4c
--- /dev/null
+++ b/www/wiki/maintenance/mssql/archives/patch-slot-origin.sql
@@ -0,0 +1,14 @@
+--
+-- Replace slot_inherited with slot_origin.
+--
+-- NOTE: There is no release that has slot_inherited. This is only needed to transition between
+-- snapshot versions of 1.30.
+--
+-- NOTE: No code that writes to the slots table was merge yet, the table is assumed to be empty.
+--
+DROP INDEX /*i*/slot_role_inherited ON /*_*/slots;
+
+ALTER TABLE /*_*/slots DROP CONSTRAINT DF_slot_inherited, COLUMN slot_inherited;
+ALTER TABLE /*_*/slots ADD COLUMN slot_origin bigint NOT NULL;
+
+CREATE INDEX /*i*/slot_revision_origin_role ON /*_*/slots (slot_revision_id, slot_origin, slot_role_id);
diff --git a/www/wiki/maintenance/mssql/archives/patch-slot_roles.sql b/www/wiki/maintenance/mssql/archives/patch-slot_roles.sql
new file mode 100644
index 00000000..228510cd
--- /dev/null
+++ b/www/wiki/maintenance/mssql/archives/patch-slot_roles.sql
@@ -0,0 +1,10 @@
+--
+-- Normalization table for role names
+--
+CREATE TABLE /*_*/slot_roles (
+ role_id smallint NOT NULL CONSTRAINT PK_slot_roles PRIMARY KEY IDENTITY,
+ role_name nvarchar(64) NOT NULL
+);
+
+-- Index for looking of the internal ID of for a name
+CREATE UNIQUE INDEX /*i*/role_name ON /*_*/slot_roles (role_name); \ No newline at end of file
diff --git a/www/wiki/maintenance/mssql/archives/patch-slots.sql b/www/wiki/maintenance/mssql/archives/patch-slots.sql
new file mode 100644
index 00000000..e9ec7c31
--- /dev/null
+++ b/www/wiki/maintenance/mssql/archives/patch-slots.sql
@@ -0,0 +1,25 @@
+--
+-- Slots represent an n:m relation between revisions and content objects.
+-- A content object can have a specific "role" in one or more revisions.
+-- Each revision can have multiple content objects, each having a different role.
+--
+CREATE TABLE /*_*/slots (
+
+ -- reference to rev_id
+ slot_revision_id bigint unsigned NOT NULL,
+
+ -- reference to role_id
+ slot_role_id smallint unsigned NOT NULL CONSTRAINT FK_slots_slot_role FOREIGN KEY REFERENCES slot_roles(role_id),
+
+ -- reference to content_id
+ slot_content_id bigint unsigned NOT NULL CONSTRAINT FK_slots_content_id FOREIGN KEY REFERENCES content(content_id),
+
+ -- The revision ID of the revision that originated the slot's content.
+ -- To find revisions that changed slots, look for slot_origin = slot_revision_id.
+ slot_origin bigint unsigned NOT NULL,
+
+ CONSTRAINT PK_slots PRIMARY KEY (slot_revision_id, slot_role_id)
+);
+
+-- Index for finding revisions that modified a specific slot
+CREATE INDEX /*i*/slot_revision_origin_role ON /*_*/slots (slot_revision_id, slot_origin, slot_role_id);
diff --git a/www/wiki/maintenance/mssql/archives/patch-user_groups-ug_expiry.sql b/www/wiki/maintenance/mssql/archives/patch-user_groups-ug_expiry.sql
index 371d80b2..4bafc8b2 100644
--- a/www/wiki/maintenance/mssql/archives/patch-user_groups-ug_expiry.sql
+++ b/www/wiki/maintenance/mssql/archives/patch-user_groups-ug_expiry.sql
@@ -1,6 +1,6 @@
-- Primary key and expiry column in user_groups table
DROP INDEX IF EXISTS /*i*/ug_user_group ON /*_*/user_groups;
-ALTER TABLE /*_*/tag_summary ADD CONSTRAINT pk_user_groups PRIMARY KEY(ug_user, ug_group);
-ALTER TABLE /*_*/tag_summary ADD ug_expiry varchar(14) DEFAULT NULL;
+ALTER TABLE /*_*/user_groups ADD CONSTRAINT pk_user_groups PRIMARY KEY(ug_user, ug_group);
+ALTER TABLE /*_*/user_groups ADD ug_expiry varchar(14) DEFAULT NULL;
CREATE INDEX /*i*/ug_expiry ON /*_*/user_groups(ug_expiry);
diff --git a/www/wiki/maintenance/mssql/tables.sql b/www/wiki/maintenance/mssql/tables.sql
index 119cd5b8..67746f04 100644
--- a/www/wiki/maintenance/mssql/tables.sql
+++ b/www/wiki/maintenance/mssql/tables.sql
@@ -55,6 +55,23 @@ CREATE INDEX /*i*/user_email ON /*_*/mwuser (user_email);
INSERT INTO /*_*/mwuser (user_name) VALUES ('##Anonymous##');
--
+-- The "actor" table associates user names or IP addresses with integers for
+-- the benefit of other tables that need to refer to either logged-in or
+-- logged-out users. If something can only ever be done by logged-in users, it
+-- can refer to the user table directly.
+--
+CREATE TABLE /*_*/actor (
+ actor_id bigint unsigned NOT NULL CONSTRAINT PK_actor PRIMARY KEY IDENTITY(0,1),
+ actor_user int unsigned,
+ actor_name nvarchar(255) NOT NULL
+);
+CREATE UNIQUE INDEX /*i*/actor_user ON /*_*/actor (actor_user);
+CREATE UNIQUE INDEX /*i*/actor_name ON /*_*/actor (actor_name);
+
+-- Insert a dummy actor to represent no actor
+INSERT INTO /*_*/actor (actor_name) VALUES ('##Anonymous##');
+
+--
-- User permissions have been broken out to a separate table;
-- this allows sites with a shared user table to have different
-- permissions assigned to a user in each project.
@@ -118,6 +135,28 @@ CREATE TABLE /*_*/bot_passwords (
--
+-- Edits, blocks, and other actions typically have a textual comment describing
+-- the action. They are stored here to reduce the size of the main tables, and
+-- to allow for deduplication.
+--
+-- Deduplication is currently best-effort to avoid locking on inserts that
+-- would be required for strict deduplication. There MAY be multiple rows with
+-- the same comment_text and comment_data.
+--
+CREATE TABLE /*_*/comment (
+ comment_id bigint unsigned NOT NULL PRIMARY KEY IDENTITY(0,1),
+ comment_hash INT NOT NULL,
+ comment_text nvarchar(max) NOT NULL,
+ comment_data nvarchar(max)
+);
+-- Index used for deduplication.
+CREATE INDEX /*i*/comment_hash ON /*_*/comment (comment_hash);
+
+-- dummy row for FKs. Hash is intentionally wrong so CommentStore won't match it.
+INSERT INTO /*_*/comment (comment_hash, comment_text) VALUES (-1, '** dummy **');
+
+
+--
-- Core of the wiki: each page has an entry here which identifies
-- it by title and contains some essential metadata.
--
@@ -152,8 +191,8 @@ INSERT INTO /*_*/page (page_namespace, page_title, page_restrictions, page_lates
CREATE TABLE /*_*/revision (
rev_id INT NOT NULL UNIQUE IDENTITY(0,1),
rev_page INT NOT NULL REFERENCES /*_*/page(page_id) ON DELETE CASCADE,
- rev_text_id INT NOT NULL, -- FK added later
- rev_comment NVARCHAR(255) NOT NULL,
+ rev_text_id INT NOT NULL CONSTRAINT DF_rev_text_id DEFAULT 0, -- FK added later
+ rev_comment NVARCHAR(255) NOT NULL CONSTRAINT DF_rev_comment DEFAULT '',
rev_user INT REFERENCES /*_*/mwuser(user_id) ON DELETE SET NULL,
rev_user_text NVARCHAR(255) NOT NULL DEFAULT '',
rev_timestamp varchar(14) NOT NULL default '',
@@ -178,6 +217,31 @@ INSERT INTO /*_*/revision (rev_page,rev_text_id,rev_comment,rev_user,rev_len) VA
ALTER TABLE /*_*/page ADD CONSTRAINT FK_page_latest_page_id FOREIGN KEY (page_latest) REFERENCES /*_*/revision(rev_id);
--
+-- Temporary tables to avoid blocking on an alter of revision.
+--
+-- On large wikis like the English Wikipedia, altering the revision table is a
+-- months-long process. This table is being created to avoid such an alter, and
+-- will be merged back into revision in the future.
+--
+CREATE TABLE /*_*/revision_comment_temp (
+ revcomment_rev INT NOT NULL CONSTRAINT FK_revcomment_rev FOREIGN KEY REFERENCES /*_*/revision(rev_id) ON DELETE CASCADE,
+ revcomment_comment_id bigint unsigned NOT NULL CONSTRAINT FK_revcomment_comment_id FOREIGN KEY REFERENCES /*_*/comment(comment_id),
+ CONSTRAINT PK_revision_comment_temp PRIMARY KEY (revcomment_rev, revcomment_comment_id)
+);
+CREATE UNIQUE INDEX /*i*/revcomment_rev ON /*_*/revision_comment_temp (revcomment_rev);
+
+CREATE TABLE /*_*/revision_actor_temp (
+ revactor_rev int unsigned NOT NULL CONSTRAINT FK_revactor_rev FOREIGN KEY REFERENCES /*_*/revision(rev_id) ON DELETE CASCADE,
+ revactor_actor bigint unsigned NOT NULL,
+ revactor_timestamp varchar(14) NOT NULL CONSTRAINT DF_revactor_timestamp DEFAULT '',
+ revactor_page int unsigned NOT NULL,
+ CONSTRAINT PK_revision_actor_temp PRIMARY KEY (revactor_rev, revactor_actor)
+);
+CREATE UNIQUE INDEX /*i*/revactor_rev ON /*_*/revision_actor_temp (revactor_rev);
+CREATE INDEX /*i*/actor_timestamp ON /*_*/revision_actor_temp (revactor_actor,revactor_timestamp);
+CREATE INDEX /*i*/page_actor_timestamp ON /*_*/revision_actor_temp (revactor_page,revactor_actor,revactor_timestamp);
+
+--
-- Holds TEXT of individual page revisions.
--
-- Field names are a holdover from the 'old' revisions table in
@@ -206,15 +270,15 @@ CREATE TABLE /*_*/archive (
ar_id int NOT NULL PRIMARY KEY IDENTITY,
ar_namespace SMALLINT NOT NULL DEFAULT 0,
ar_title NVARCHAR(255) NOT NULL DEFAULT '',
- ar_text NVARCHAR(MAX) NOT NULL,
- ar_comment NVARCHAR(255) NOT NULL,
+ ar_comment NVARCHAR(255) NOT NULL CONSTRAINT DF_ar_comment DEFAULT '',
+ ar_comment_id bigint unsigned NOT NULL CONSTRAINT DF_ar_comment_id DEFAULT 0 CONSTRAINT FK_ar_comment_id FOREIGN KEY REFERENCES /*_*/comment(comment_id),
ar_user INT CONSTRAINT ar_user__user_id__fk FOREIGN KEY REFERENCES /*_*/mwuser(user_id),
- ar_user_text NVARCHAR(255) NOT NULL,
+ ar_user_text NVARCHAR(255) NOT NULL CONSTRAINT DF_ar_user_text DEFAULT '',
+ ar_actor bigint unsigned NOT NULL CONSTRAINT DF_ar_actor DEFAULT 0,
ar_timestamp varchar(14) NOT NULL default '',
ar_minor_edit BIT NOT NULL DEFAULT 0,
- ar_flags NVARCHAR(255) NOT NULL,
- ar_rev_id INT NULL, -- NOT a FK, the row gets deleted from revision and moved here
- ar_text_id INT CONSTRAINT ar_text_id__old_id__fk FOREIGN KEY REFERENCES /*_*/text(old_id) ON DELETE CASCADE,
+ ar_rev_id INT NOT NULL, -- NOT a FK, the row gets deleted from revision and moved here
+ ar_text_id INT NOT NULL CONSTRAINT DF_ar_text_id DEFAULT 0 CONSTRAINT ar_text_id__old_id__fk FOREIGN KEY REFERENCES /*_*/text(old_id) ON DELETE CASCADE,
ar_deleted TINYINT NOT NULL DEFAULT 0,
ar_len INT,
ar_page_id INT NULL, -- NOT a FK, the row gets deleted from page and moved here
@@ -225,10 +289,82 @@ CREATE TABLE /*_*/archive (
);
CREATE INDEX /*i*/name_title_timestamp ON /*_*/archive (ar_namespace,ar_title,ar_timestamp);
CREATE INDEX /*i*/ar_usertext_timestamp ON /*_*/archive (ar_user_text,ar_timestamp);
+CREATE INDEX /*i*/ar_actor_timestamp ON /*_*/archive (ar_actor,ar_timestamp);
CREATE INDEX /*i*/ar_revid ON /*_*/archive (ar_rev_id);
--
+-- Slots represent an n:m relation between revisions and content objects.
+-- A content object can have a specific "role" in one or more revisions.
+-- Each revision can have multiple content objects, each having a different role.
+--
+CREATE TABLE /*_*/slots (
+
+ -- reference to rev_id
+ slot_revision_id bigint unsigned NOT NULL,
+
+ -- reference to role_id
+ slot_role_id smallint unsigned NOT NULL CONSTRAINT FK_slots_slot_role FOREIGN KEY REFERENCES slot_roles(role_id),
+
+ -- reference to content_id
+ slot_content_id bigint unsigned NOT NULL CONSTRAINT FK_slots_content_id FOREIGN KEY REFERENCES content(content_id),
+
+ -- The revision ID of the revision that originated the slot's content.
+ -- To find revisions that changed slots, look for slot_origin = slot_revision_id.
+ slot_origin bigint NOT NULL,
+
+ CONSTRAINT PK_slots PRIMARY KEY (slot_revision_id, slot_role_id)
+);
+
+-- Index for finding revisions that modified a specific slot
+CREATE INDEX /*i*/slot_revision_origin_role ON /*_*/slots (slot_revision_id, slot_origin, slot_role_id);
+
+--
+-- The content table represents content objects. It's primary purpose is to provide the necessary
+-- meta-data for loading and interpreting a serialized data blob to create a content object.
+--
+CREATE TABLE /*_*/content (
+
+ -- ID of the content object
+ content_id bigint unsigned NOT NULL CONSTRAINT PK_content PRIMARY KEY IDENTITY,
+
+ -- Nominal size of the content object (not necessarily of the serialized blob)
+ content_size int unsigned NOT NULL,
+
+ -- Nominal hash of the content object (not necessarily of the serialized blob)
+ content_sha1 varchar(32) NOT NULL,
+
+ -- reference to model_id
+ content_model smallint unsigned NOT NULL CONSTRAINT FK_content_content_models FOREIGN KEY REFERENCES /*_*/content_models(model_id),
+
+ -- URL-like address of the content blob
+ content_address nvarchar(255) NOT NULL
+);
+
+--
+-- Normalization table for role names
+--
+CREATE TABLE /*_*/slot_roles (
+ role_id smallint NOT NULL CONSTRAINT PK_slot_roles PRIMARY KEY IDENTITY,
+ role_name nvarchar(64) NOT NULL
+);
+
+-- Index for looking of the internal ID of for a name
+CREATE UNIQUE INDEX /*i*/role_name ON /*_*/slot_roles (role_name);
+
+--
+-- Normalization table for content model names
+--
+CREATE TABLE /*_*/content_models (
+ model_id smallint NOT NULL CONSTRAINT PK_content_models PRIMARY KEY IDENTITY,
+ model_name nvarchar(64) NOT NULL
+);
+
+-- Index for looking of the internal ID of for a name
+CREATE UNIQUE INDEX /*i*/model_name ON /*_*/content_models (model_name);
+
+
+--
-- Track page-to-page hyperlinks within the wiki.
--
CREATE TABLE /*_*/pagelinks (
@@ -453,26 +589,22 @@ CREATE TABLE /*_*/site_stats (
ss_row_id int NOT NULL CONSTRAINT /*i*/ss_row_id PRIMARY KEY,
-- Total number of edits performed.
- ss_total_edits bigint default 0,
+ ss_total_edits bigint default NULL,
- -- An approximate count of pages matching the following criteria:
- -- * in namespace 0
- -- * not a redirect
- -- * contains the text '[['
- -- See Article::isCountable() in includes/Article.php
- ss_good_articles bigint default 0,
+ -- See SiteStatsInit::articles().
+ ss_good_articles bigint default NULL,
- -- Total pages, theoretically equal to SELECT COUNT(*) FROM page; except faster
- ss_total_pages bigint default '-1',
+ -- Total pages, theoretically equal to SELECT COUNT(*) FROM page.
+ ss_total_pages bigint default NULL,
- -- Number of users, theoretically equal to SELECT COUNT(*) FROM user;
- ss_users bigint default '-1',
+ -- Number of users, theoretically equal to SELECT COUNT(*) FROM user.
+ ss_users bigint default NULL,
- -- Number of users that still edit
- ss_active_users bigint default '-1',
+ -- Number of users that still edit.
+ ss_active_users bigint default NULL,
- -- Number of images, equivalent to SELECT COUNT(*) FROM image
- ss_images int default 0
+ -- Number of images, equivalent to SELECT COUNT(*) FROM image.
+ ss_images bigint default NULL
);
@@ -493,11 +625,18 @@ CREATE TABLE /*_*/ipblocks (
-- User ID who made the block.
ipb_by int REFERENCES /*_*/mwuser(user_id) ON DELETE CASCADE,
+ -- Actor ID who made the block.
+ ipb_by_actor bigint unsigned NOT NULL CONSTRAINT DF_ipb_by_actor DEFAULT 0,
+
-- User name of blocker
ipb_by_text nvarchar(255) NOT NULL default '',
-- Text comment made by blocker.
- ipb_reason nvarchar(255) NOT NULL,
+ ipb_reason nvarchar(255) NOT NULL CONSTRAINT DF_ipb_reason DEFAULT '',
+
+ -- Key to comment_id. Text comment made by blocker.
+ -- ("DEFAULT 0" is temporary, signaling that ipb_reason should be used)
+ ipb_reason_id bigint unsigned NOT NULL CONSTRAINT DF_ipb_reason_id DEFAULT 0 CONSTRAINT FK_ipb_reason_id FOREIGN KEY REFERENCES /*_*/comment(comment_id),
-- Creation (or refresh) date in standard YMDHMS form.
-- IP blocks expire automatically.
@@ -594,11 +733,13 @@ CREATE TABLE /*_*/image (
-- Description field as entered by the uploader.
-- This is displayed in image upload history and logs.
- img_description nvarchar(255) NOT NULL,
+ img_description nvarchar(255) NOT NULL CONSTRAINT DF_img_description DEFAULT '',
+ img_description_id bigint NOT NULL CONSTRAINT DF_img_description_id DEFAULT 0 CONSTRAINT FK_img_description_id FOREIGN KEY REFERENCES /*_*/comment(comment_id),
-- user_id and user_name of uploader.
img_user int REFERENCES /*_*/mwuser(user_id) ON DELETE SET NULL,
- img_user_text nvarchar(255) NOT NULL,
+ img_user_text nvarchar(255) NOT NULL CONSTRAINT DF_img_user_text DEFAULT '',
+ img_actor bigint unsigned NOT NULL CONSTRAINT DF_img_actor DEFAULT 0,
-- Time of the upload.
img_timestamp nvarchar(14) NOT NULL default '',
@@ -611,6 +752,7 @@ CREATE TABLE /*_*/image (
);
CREATE INDEX /*i*/img_usertext_timestamp ON /*_*/image (img_user_text,img_timestamp);
+CREATE INDEX /*i*/img_actor_timestamp ON /*_*/image (img_actor, img_timestamp);
-- Used by Special:ListFiles for sort-by-size
CREATE INDEX /*i*/img_size ON /*_*/image (img_size);
-- Used by Special:Newimages and Special:ListFiles
@@ -620,6 +762,20 @@ CREATE INDEX /*i*/img_sha1 ON /*_*/image (img_sha1);
-- Used to get media of one type
CREATE INDEX /*i*/img_media_mime ON /*_*/image (img_media_type,img_major_mime,img_minor_mime);
+--
+-- Temporary table to avoid blocking on an alter of image.
+--
+-- On large wikis like Wikimedia Commons, altering the image table is a
+-- months-long process. This table is being created to avoid such an alter, and
+-- will be merged back into image in the future.
+--
+CREATE TABLE /*_*/image_comment_temp (
+ imgcomment_name nvarchar(255) NOT NULL CONSTRAINT FK_imgcomment_name FOREIGN KEY REFERENCES /*_*/image(imgcomment_name) ON DELETE CASCADE,
+ imgcomment_description_id bigint unsigned NOT NULL CONSTRAINT FK_imgcomment_description_id FOREIGN KEY REFERENCES /*_*/comment(comment_id),
+ CONSTRAINT PK_image_comment_temp PRIMARY KEY (imgcomment_name, imgcomment_description_id)
+);
+CREATE UNIQUE INDEX /*i*/imgcomment_name ON /*_*/image_comment_temp (imgcomment_name);
+
--
-- Previous revisions of uploaded files.
@@ -640,9 +796,11 @@ CREATE TABLE /*_*/oldimage (
oi_width int NOT NULL default 0,
oi_height int NOT NULL default 0,
oi_bits int NOT NULL default 0,
- oi_description nvarchar(255) NOT NULL,
+ oi_description nvarchar(255) NOT NULL CONSTRAINT DF_oi_description DEFAULT '',
+ oi_description_id bigint unsigned NOT NULL CONSTRAINT DF_oi_description_id DEFAULT 0 CONSTRAINT FK_oi_description_id FOREIGN KEY REFERENCES /*_*/comment(comment_id),
oi_user int REFERENCES /*_*/mwuser(user_id),
- oi_user_text nvarchar(255) NOT NULL,
+ oi_user_text nvarchar(255) NOT NULL CONSTRAINT DF_oi_user_text DEFAULT '',
+ oi_actor bigint unsigned NOT NULL CONSTRAINT DF_oi_actor DEFAULT 0,
oi_timestamp varchar(14) NOT NULL default '',
oi_metadata varbinary(max) NOT NULL,
@@ -657,6 +815,7 @@ CREATE TABLE /*_*/oldimage (
);
CREATE INDEX /*i*/oi_usertext_timestamp ON /*_*/oldimage (oi_user_text,oi_timestamp);
+CREATE INDEX /*i*/oi_actor_timestamp ON /*_*/oldimage (oi_actor,oi_timestamp);
CREATE INDEX /*i*/oi_name_timestamp ON /*_*/oldimage (oi_name,oi_timestamp);
CREATE INDEX /*i*/oi_sha1 ON /*_*/oldimage (oi_sha1);
@@ -689,7 +848,8 @@ CREATE TABLE /*_*/filearchive (
-- Deletion information, if this file is deleted.
fa_deleted_user int,
fa_deleted_timestamp varchar(14) default '',
- fa_deleted_reason nvarchar(max),
+ fa_deleted_reason nvarchar(max) CONSTRAINT DF_fa_deleted_reason DEFAULT '',
+ fa_deleted_reason_id bigint unsigned NOT NULL CONSTRAINT DF_fa_deleted_reason_id DEFAULT 0 CONSTRAINT FK_fa_deleted_reason_id FOREIGN KEY REFERENCES /*_*/comment(comment_id),
-- Duped fields from image
fa_size int default 0,
@@ -700,9 +860,11 @@ CREATE TABLE /*_*/filearchive (
fa_media_type varchar(16) default null,
fa_major_mime varchar(16) not null default 'unknown',
fa_minor_mime nvarchar(100) default 'unknown',
- fa_description nvarchar(255),
+ fa_description nvarchar(255) CONSTRAINT DF_fa_description DEFAULT '',
+ fa_description_id bigint unsigned NOT NULL CONSTRAINT DF_fa_description DEFAULT 0 CONSTRAINT FK_fa_description FOREIGN KEY REFERENCES /*_*/comment(comment_id),
fa_user int default 0 REFERENCES /*_*/mwuser(user_id) ON DELETE SET NULL,
- fa_user_text nvarchar(255),
+ fa_user_text nvarchar(255) CONSTRAINT DF_fa_user_text DEFAULT '',
+ fa_actor bigint unsigned NOT NULL CONSTRAINT DF_fa_actor DEFAULT 0,
fa_timestamp varchar(14) default '',
-- Visibility of deleted revisions, bitfield
@@ -723,6 +885,7 @@ CREATE INDEX /*i*/fa_storage_group ON /*_*/filearchive (fa_storage_group, fa_sto
CREATE INDEX /*i*/fa_deleted_timestamp ON /*_*/filearchive (fa_deleted_timestamp);
-- sort by uploader
CREATE INDEX /*i*/fa_user_timestamp ON /*_*/filearchive (fa_user_text,fa_timestamp);
+CREATE INDEX /*i*/fa_actor_timestamp ON /*_*/filearchive (fa_actor,fa_timestamp);
-- find file by sha1, 10 bytes will be enough for hashes to be indexed
CREATE INDEX /*i*/fa_sha1 ON /*_*/filearchive (fa_sha1);
@@ -795,7 +958,8 @@ CREATE TABLE /*_*/recentchanges (
-- As in revision
rc_user int NOT NULL default 0 CONSTRAINT rc_user__user_id__fk FOREIGN KEY REFERENCES /*_*/mwuser(user_id),
- rc_user_text nvarchar(255) NOT NULL,
+ rc_user_text nvarchar(255) NOT NULL CONSTRAINT DF_rc_user_text DEFAULT '',
+ rc_actor bigint unsigned NOT NULL CONSTRAINT DF_rc_actor DEFAULT 0,
-- When pages are renamed, their RC entries do _not_ change.
rc_namespace int NOT NULL default 0,
@@ -803,6 +967,7 @@ CREATE TABLE /*_*/recentchanges (
-- as in revision...
rc_comment nvarchar(255) NOT NULL default '',
+ rc_comment_id bigint unsigned NOT NULL CONSTRAINT DF_rc_comment_id DEFAULT 0 CONSTRAINT FK_rc_comment_id FOREIGN KEY REFERENCES /*_*/comment(comment_id),
rc_minor bit NOT NULL default 0,
-- Edits by user accounts with the 'bot' rights key are
@@ -834,8 +999,9 @@ CREATE TABLE /*_*/recentchanges (
-- If the Recent Changes Patrol option is enabled,
-- users may mark edits as having been reviewed to
-- remove a warning flag on the RC list.
- -- A value of 1 indicates the page has been reviewed.
- rc_patrolled bit NOT NULL default 0,
+ -- A value of 1 indicates the page has been reviewed manually.
+ -- A value of 2 indicates the page has been automatically reviewed.
+ rc_patrolled tinyint NOT NULL CONSTRAINT DF_rc_patrolled DEFAULT 0,
-- Recorded IP address the edit was made from, if the
-- $wgPutIPinRC option is enabled.
@@ -860,12 +1026,14 @@ CREATE TABLE /*_*/recentchanges (
);
CREATE INDEX /*i*/rc_timestamp ON /*_*/recentchanges (rc_timestamp);
-CREATE INDEX /*i*/rc_namespace_title ON /*_*/recentchanges (rc_namespace, rc_title);
+CREATE INDEX /*i*/rc_namespace_title_timestamp ON /*_*/recentchanges (rc_namespace, rc_title, rc_timestamp);
CREATE INDEX /*i*/rc_cur_id ON /*_*/recentchanges (rc_cur_id);
CREATE INDEX /*i*/new_name_timestamp ON /*_*/recentchanges (rc_new,rc_namespace,rc_timestamp);
CREATE INDEX /*i*/rc_ip ON /*_*/recentchanges (rc_ip);
CREATE INDEX /*i*/rc_ns_usertext ON /*_*/recentchanges (rc_namespace, rc_user_text);
CREATE INDEX /*i*/rc_user_text ON /*_*/recentchanges (rc_user_text, rc_timestamp);
+CREATE INDEX /*i*/rc_ns_actor ON /*_*/recentchanges (rc_namespace, rc_actor);
+CREATE INDEX /*i*/rc_actor ON /*_*/recentchanges (rc_actor, rc_timestamp);
CREATE INDEX /*i*/rc_name_type_patrolled_timestamp ON /*_*/recentchanges (rc_namespace, rc_type, rc_patrolled, rc_timestamp);
@@ -997,6 +1165,9 @@ CREATE TABLE /*_*/logging (
-- Name of the user who performed this action
log_user_text nvarchar(255) NOT NULL default '',
+ -- The actor who performed this action
+ log_actor bigint unsigned NOT NULL CONSTRAINT DF_log_actor DEFAULT 0,
+
-- Key to the page affected. Where a user is the target,
-- this will point to the user page.
log_namespace int NOT NULL default 0,
@@ -1006,6 +1177,10 @@ CREATE TABLE /*_*/logging (
-- Freeform text. Interpreted as edit history comments.
log_comment nvarchar(255) NOT NULL default '',
+ -- Key to comment_id. Comment summarizing the change.
+ -- ("DEFAULT 0" is temporary, signaling that log_comment should be used)
+ log_comment_id bigint unsigned NOT NULL CONSTRAINT DF_log_comment_id DEFAULT 0 CONSTRAINT FK_log_comment_id FOREIGN KEY REFERENCES /*_*/comment(comment_id),
+
-- miscellaneous parameters:
-- LF separated list (old system) or serialized PHP array (new system)
log_params nvarchar(max) NOT NULL,
@@ -1023,6 +1198,8 @@ CREATE INDEX /*i*/log_page_id_time ON /*_*/logging (log_page,log_timestamp);
CREATE INDEX /*i*/type_action ON /*_*/logging (log_type, log_action, log_timestamp);
CREATE INDEX /*i*/log_user_text_type_time ON /*_*/logging (log_user_text, log_type, log_timestamp);
CREATE INDEX /*i*/log_user_text_time ON /*_*/logging (log_user_text, log_timestamp);
+CREATE INDEX /*i*/actor_time ON /*_*/logging (log_actor, log_timestamp);
+CREATE INDEX /*i*/log_actor_type_time ON /*_*/logging (log_actor, log_type, log_timestamp);
INSERT INTO /*_*/logging (log_user,log_page,log_params) VALUES(0,0,'');
@@ -1166,7 +1343,8 @@ CREATE TABLE /*_*/protected_titles (
pt_namespace int NOT NULL,
pt_title nvarchar(255) NOT NULL,
pt_user int REFERENCES /*_*/mwuser(user_id) ON DELETE SET NULL,
- pt_reason nvarchar(255),
+ pt_reason nvarchar(255) CONSTRAINT DF_pt_reason DEFAULT '',
+ pt_reason_id bigint unsigned NOT NULL CONSTRAINT DF_pt_reason_id DEFAULT 0 CONSTRAINT FK_pt_reason_id FOREIGN KEY REFERENCES /*_*/comment(comment_id),
pt_timestamp varchar(14) NOT NULL,
pt_expiry varchar(14) NOT NULL,
pt_create_perm nvarchar(60) NOT NULL
diff --git a/www/wiki/maintenance/mwdoc-filter.php b/www/wiki/maintenance/mwdoc-filter.php
index feaad12a..89fc44bd 100644
--- a/www/wiki/maintenance/mwdoc-filter.php
+++ b/www/wiki/maintenance/mwdoc-filter.php
@@ -39,7 +39,7 @@
*/
// Warning: Converting this to a Maintenance script may reduce performance.
-if ( PHP_SAPI != 'cli' ) {
+if ( PHP_SAPI != 'cli' && PHP_SAPI != 'phpdbg' ) {
die( "This filter can only be run from the command line.\n" );
}
diff --git a/www/wiki/maintenance/mwdocgen.php b/www/wiki/maintenance/mwdocgen.php
index 43041a43..2d6a0beb 100644
--- a/www/wiki/maintenance/mwdocgen.php
+++ b/www/wiki/maintenance/mwdocgen.php
@@ -138,8 +138,7 @@ class MWDocGen extends Maintenance {
$tmpFile = tempnam( wfTempDir(), 'MWDocGen-' );
if ( file_put_contents( $tmpFile, $conf ) === false ) {
- $this->error( "Could not write doxygen configuration to file $tmpFile\n",
- /** exit code: */ 1 );
+ $this->fatalError( "Could not write doxygen configuration to file $tmpFile\n" );
}
$command = $this->doxygen . ' ' . $tmpFile;
@@ -161,11 +160,10 @@ TEXT
);
if ( $exitcode !== 0 ) {
- $this->error( "Something went wrong (exit: $exitcode)\n",
- $exitcode );
+ $this->fatalError( "Something went wrong (exit: $exitcode)\n", $exitcode );
}
}
}
-$maintClass = 'MWDocGen';
+$maintClass = MWDocGen::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/namespaceDupes.php b/www/wiki/maintenance/namespaceDupes.php
index 84d45335..3c839216 100644
--- a/www/wiki/maintenance/namespaceDupes.php
+++ b/www/wiki/maintenance/namespaceDupes.php
@@ -616,5 +616,5 @@ class NamespaceConflictChecker extends Maintenance {
}
}
-$maintClass = "NamespaceConflictChecker";
+$maintClass = NamespaceConflictChecker::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/nukeNS.php b/www/wiki/maintenance/nukeNS.php
index e735aed0..ee1f59c1 100644
--- a/www/wiki/maintenance/nukeNS.php
+++ b/www/wiki/maintenance/nukeNS.php
@@ -88,7 +88,7 @@ class NukeNS extends Maintenance {
$dbw->query( "DELETE FROM $tbl_pag WHERE page_id = $id" );
$this->commitTransaction( $dbw, __METHOD__ );
// Delete revisions as appropriate
- $child = $this->runChild( 'NukePage', 'nukePage.php' );
+ $child = $this->runChild( NukePage::class, 'nukePage.php' );
$child->deleteRevisions( $revs );
$this->purgeRedundantText( true );
$n_deleted++;
@@ -118,5 +118,5 @@ class NukeNS extends Maintenance {
}
}
-$maintClass = "NukeNS";
+$maintClass = NukeNS::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/nukePage.php b/www/wiki/maintenance/nukePage.php
index e27324a7..baead947 100644
--- a/www/wiki/maintenance/nukePage.php
+++ b/www/wiki/maintenance/nukePage.php
@@ -115,5 +115,5 @@ class NukePage extends Maintenance {
}
}
-$maintClass = "NukePage";
+$maintClass = NukePage::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/oracle/alterSharedConstraints.php b/www/wiki/maintenance/oracle/alterSharedConstraints.php
index ed412dae..7f997cb6 100644
--- a/www/wiki/maintenance/oracle/alterSharedConstraints.php
+++ b/www/wiki/maintenance/oracle/alterSharedConstraints.php
@@ -93,5 +93,5 @@ class AlterSharedConstraints extends Maintenance {
}
}
-$maintClass = "AlterSharedConstraints";
+$maintClass = AlterSharedConstraints::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/oracle/archives/patch-actor-table.sql b/www/wiki/maintenance/oracle/archives/patch-actor-table.sql
new file mode 100644
index 00000000..93c7531b
--- /dev/null
+++ b/www/wiki/maintenance/oracle/archives/patch-actor-table.sql
@@ -0,0 +1,64 @@
+--
+-- patch-actor-table.sql
+--
+-- T167246. Add an `actor` table and various columns (and temporary tables) to reference it.
+
+define mw_prefix='{$wgDBprefix}';
+
+CREATE SEQUENCE actor_actor_id_seq;
+CREATE TABLE &mw_prefix.actor (
+ actor_id NUMBER NOT NULL,
+ actor_user NUMBER,
+ actor_name VARCHAR2(255) NOT NULL
+);
+
+ALTER TABLE &mw_prefix.actor ADD CONSTRAINT &mw_prefix.actor_pk PRIMARY KEY (actor_id);
+
+/*$mw$*/
+CREATE TRIGGER &mw_prefix.actor_seq_trg BEFORE INSERT ON &mw_prefix.actor
+ FOR EACH ROW WHEN (new.actor_id IS NULL)
+BEGIN
+ &mw_prefix.lastval_pkg.setLastval(actor_actor_id_seq.nextval, :new.actor_id);
+END;
+/*$mw$*/
+
+-- Create a dummy actor to satisfy fk contraints
+INSERT INTO &mw_prefix.actor (actor_id, actor_name) VALUES (0,'##Anonymous##');
+
+CREATE TABLE &mw_prefix.revision_actor_temp (
+ revactor_rev NUMBER NOT NULL,
+ revactor_actor NUMBER NOT NULL,
+ revactor_timestamp TIMESTAMP(6) WITH TIME ZONE NOT NULL,
+ revactor_page NUMBER NOT NULL
+);
+ALTER TABLE &mw_prefix.revision_actor_temp ADD CONSTRAINT &mw_prefix.revision_actor_temp_pk PRIMARY KEY (revactor_rev, revactor_actor);
+CREATE UNIQUE INDEX &mw_prefix.revactor_rev ON &mw_prefix.revision_actor_temp (revactor_rev);
+CREATE INDEX &mw_prefix.actor_timestamp ON &mw_prefix.revision_actor_temp (revactor_actor,revactor_timestamp);
+CREATE INDEX &mw_prefix.page_actor_timestamp ON &mw_prefix.revision_actor_temp (revactor_page,revactor_actor,revactor_timestamp);
+
+ALTER TABLE &mw_prefix.archive ALTER COLUMN ar_user_text VARCHAR2(255) NULL;
+ALTER TABLE &mw_prefix.archive ADD COLUMN ar_actor NUMBER DEFAULT 0 NOT NULL;
+CREATE INDEX &mw_prefix.ar_actor_timestamp ON &mw_prefix.archive (ar_actor,ar_timestamp);
+
+ALTER TABLE &mw_prefix.ipblocks ADD COLUMN ipb_by_actor NUMBER DEFUALT 0 NOT NULL;
+
+ALTER TABLE &mw_prefix.image ALTER COLUMN img_user_text VARCHAR2(255) NULL;
+ALTER TABLE &mw_prefix.image ADD COLUMN img_actor NUMBER DEFAULT 0 NOT NULL;
+CREATE INDEX &mw_prefix.img_actor_timestamp ON &mw_prefix.image (img_actor, img_timestamp);
+
+ALTER TABLE &mw_prefix.oldimage ALTER COLUMN oi_user_text VARCHAR2(255) NULL;
+ALTER TABLE &mw_prefix.oldimage ADD COLUMN oi_actor NUMBER DEFAULT 0 NOT NULL;
+CREATE INDEX &mw_prefix.oi_actor_timestamp ON &mw_prefix.oldimage (oi_actor,oi_timestamp);
+
+ALTER TABLE &mw_prefix.filearchive ALTER COLUMN fa_user_text VARCHAR2(255) NULL;
+ALTER TABLE &mw_prefix.filearchive ADD COLUMN fa_actor NUMBER DEFAULT 0 NOT NULL;
+CREATE INDEX &mw_prefix.fa_actor_timestamp ON &mw_prefix.filearchive (fa_actor,fa_timestamp);
+
+ALTER TABLE &mw_prefix.recentchanges ALTER COLUMN rc_user_text VARCHAR2(255) NULL;
+ALTER TABLE &mw_prefix.recentchanges ADD COLUMN rc_actor NUMBER DEFAULT 0 NOT NULL;
+CREATE INDEX &mw_prefix.rc_ns_actor ON &mw_prefix.recentchanges (rc_namespace, rc_actor);
+CREATE INDEX &mw_prefix.rc_actor ON &mw_prefix.recentchanges (rc_actor, rc_timestamp);
+
+ALTER TABLE &mw_prefix.logging ADD COLUMN log_actor NUMBER DEFAULT 0 NOT NULL;
+CREATE INDEX &mw_prefix.actor_time ON &mw_prefix.logging (log_actor, log_timestamp);
+CREATE INDEX &mw_prefix.log_actor_type_time ON &mw_prefix.logging (log_actor, log_type, log_timestamp);
diff --git a/www/wiki/maintenance/oracle/archives/patch-ar_rev_id-not-null.sql b/www/wiki/maintenance/oracle/archives/patch-ar_rev_id-not-null.sql
new file mode 100644
index 00000000..56f15988
--- /dev/null
+++ b/www/wiki/maintenance/oracle/archives/patch-ar_rev_id-not-null.sql
@@ -0,0 +1,5 @@
+-- T182678: Make ar_rev_id not nullable
+
+define mw_prefix='{$wgDBprefix}';
+
+ALTER TABLE &mw_prefix.archive MODIFY ar_rev_id NUMBER NOT NULL;
diff --git a/www/wiki/maintenance/oracle/archives/patch-auto_increment_triggers.sql b/www/wiki/maintenance/oracle/archives/patch-auto_increment_triggers.sql
index 6b471b04..62a2f4fb 100644
--- a/www/wiki/maintenance/oracle/archives/patch-auto_increment_triggers.sql
+++ b/www/wiki/maintenance/oracle/archives/patch-auto_increment_triggers.sql
@@ -24,7 +24,7 @@ END;
/*$mw$*/
/*$mw$*/
-CREATE TRIGGER &mw_prefix.mwuser_default_user_id BEFORE INSERT ON &mw_prefix.mwuser
+CREATE TRIGGER &mw_prefix.mwuser_seq_trg BEFORE INSERT ON &mw_prefix.mwuser
FOR EACH ROW WHEN (new.user_id IS NULL)
BEGIN
&mw_prefix.lastval_pkg.setLastval(user_user_id_seq.nextval, :new.user_id);
@@ -32,7 +32,7 @@ END;
/*$mw$*/
/*$mw$*/
-CREATE TRIGGER &mw_prefix.page_default_page_id BEFORE INSERT ON &mw_prefix.page
+CREATE TRIGGER &mw_prefix.page_seq_trg BEFORE INSERT ON &mw_prefix.page
FOR EACH ROW WHEN (new.page_id IS NULL)
BEGIN
&mw_prefix.lastval_pkg.setLastval(page_page_id_seq.nextval, :new.page_id);
@@ -40,7 +40,7 @@ END;
/*$mw$*/
/*$mw$*/
-CREATE TRIGGER &mw_prefix.revision_default_rev_id BEFORE INSERT ON &mw_prefix.revision
+CREATE TRIGGER &mw_prefix.revision_seq_trg BEFORE INSERT ON &mw_prefix.revision
FOR EACH ROW WHEN (new.rev_id IS NULL)
BEGIN
&mw_prefix.lastval_pkg.setLastval(revision_rev_id_seq.nextval, :new.rev_id);
@@ -48,7 +48,7 @@ END;
/*$mw$*/
/*$mw$*/
-CREATE TRIGGER &mw_prefix.text_default_old_id BEFORE INSERT ON &mw_prefix.text
+CREATE TRIGGER &mw_prefix.pagecontent_seq_trg BEFORE INSERT ON &mw_prefix.pagecontent
FOR EACH ROW WHEN (new.old_id IS NULL)
BEGIN
&mw_prefix.lastval_pkg.setLastval(text_old_id_seq.nextval, :new.old_id);
@@ -56,7 +56,7 @@ END;
/*$mw$*/
/*$mw$*/
-CREATE TRIGGER &mw_prefix.archive_default_ar_id BEFORE INSERT ON &mw_prefix.archive
+CREATE TRIGGER &mw_prefix.archive_seq_trg BEFORE INSERT ON &mw_prefix.archive
FOR EACH ROW WHEN (new.ar_id IS NULL)
BEGIN
&mw_prefix.lastval_pkg.setLastval(archive_ar_id_seq.nextval, :new.ar_id);
@@ -64,7 +64,7 @@ END;
/*$mw$*/
/*$mw$*/
-CREATE TRIGGER &mw_prefix.category_default_cat_id BEFORE INSERT ON &mw_prefix.category
+CREATE TRIGGER &mw_prefix.category_seq_trg BEFORE INSERT ON &mw_prefix.category
FOR EACH ROW WHEN (new.cat_id IS NULL)
BEGIN
&mw_prefix.lastval_pkg.setLastval(category_cat_id_seq.nextval, :new.cat_id);
@@ -72,7 +72,7 @@ END;
/*$mw$*/
/*$mw$*/
-CREATE TRIGGER &mw_prefix.externallinks_default_el_id BEFORE INSERT ON &mw_prefix.externallinks
+CREATE TRIGGER &mw_prefix.externallinks_seq_trg BEFORE INSERT ON &mw_prefix.externallinks
FOR EACH ROW WHEN (new.el_id IS NULL)
BEGIN
&mw_prefix.lastval_pkg.setLastval(externallinks_el_id_seq.nextval, :new.el_id);
@@ -80,7 +80,7 @@ END;
/*$mw$*/
/*$mw$*/
-CREATE TRIGGER &mw_prefix.ipblocks_default_ipb_id BEFORE INSERT ON &mw_prefix.ipblocks
+CREATE TRIGGER &mw_prefix.ipblocks_seq_trg BEFORE INSERT ON &mw_prefix.ipblocks
FOR EACH ROW WHEN (new.ipb_id IS NULL)
BEGIN
&mw_prefix.lastval_pkg.setLastval(ipblocks_ipb_id_seq.nextval, :new.ipb_id);
@@ -88,7 +88,7 @@ END;
/*$mw$*/
/*$mw$*/
-CREATE TRIGGER &mw_prefix.filearchive_default_fa_id BEFORE INSERT ON &mw_prefix.filearchive
+CREATE TRIGGER &mw_prefix.filearchive_seq_trg BEFORE INSERT ON &mw_prefix.filearchive
FOR EACH ROW WHEN (new.fa_id IS NULL)
BEGIN
&mw_prefix.lastval_pkg.setLastval(filearchive_fa_id_seq.nextval, :new.fa_id);
@@ -96,7 +96,7 @@ END;
/*$mw$*/
/*$mw$*/
-CREATE TRIGGER &mw_prefix.uploadstash_default_us_id BEFORE INSERT ON &mw_prefix.uploadstash
+CREATE TRIGGER &mw_prefix.uploadstash_seq_trg BEFORE INSERT ON &mw_prefix.uploadstash
FOR EACH ROW WHEN (new.us_id IS NULL)
BEGIN
&mw_prefix.lastval_pkg.setLastval(uploadstash_us_id_seq.nextval, :new.us_id);
@@ -104,7 +104,7 @@ END;
/*$mw$*/
/*$mw$*/
-CREATE TRIGGER &mw_prefix.recentchanges_default_rc_id BEFORE INSERT ON &mw_prefix.recentchanges
+CREATE TRIGGER &mw_prefix.recentchanges_seq_trg BEFORE INSERT ON &mw_prefix.recentchanges
FOR EACH ROW WHEN (new.rc_id IS NULL)
BEGIN
&mw_prefix.lastval_pkg.setLastval(recentchanges_rc_id_seq.nextval, :new.rc_id);
@@ -112,7 +112,7 @@ END;
/*$mw$*/
/*$mw$*/
-CREATE TRIGGER &mw_prefix.logging_default_log_id BEFORE INSERT ON &mw_prefix.logging
+CREATE TRIGGER &mw_prefix.logging_seq_trg BEFORE INSERT ON &mw_prefix.logging
FOR EACH ROW WHEN (new.log_id IS NULL)
BEGIN
&mw_prefix.lastval_pkg.setLastval(logging_log_id_seq.nextval, :new.log_id);
@@ -120,7 +120,7 @@ END;
/*$mw$*/
/*$mw$*/
-CREATE TRIGGER &mw_prefix.job_default_job_id BEFORE INSERT ON &mw_prefix.job
+CREATE TRIGGER &mw_prefix.job_seq_trg BEFORE INSERT ON &mw_prefix.job
FOR EACH ROW WHEN (new.job_id IS NULL)
BEGIN
&mw_prefix.lastval_pkg.setLastval(job_job_id_seq.nextval, :new.job_id);
@@ -128,7 +128,7 @@ END;
/*$mw$*/
/*$mw$*/
-CREATE TRIGGER &mw_prefix.page_restrictions_default_pr_id BEFORE INSERT ON &mw_prefix.page_restrictions
+CREATE TRIGGER &mw_prefix.page_restrictions_seq_trg BEFORE INSERT ON &mw_prefix.page_restrictions
FOR EACH ROW WHEN (new.pr_id IS NULL)
BEGIN
&mw_prefix.lastval_pkg.setLastval(page_restrictions_pr_id_seq.nextval, :new.pr_id);
@@ -136,7 +136,7 @@ END;
/*$mw$*/
/*$mw$*/
-CREATE TRIGGER &mw_prefix.sites_default_site_id BEFORE INSERT ON &mw_prefix.sites
+CREATE TRIGGER &mw_prefix.sites_seq_trg BEFORE INSERT ON &mw_prefix.sites
FOR EACH ROW WHEN (new.site_id IS NULL)
BEGIN
&mw_prefix.lastval_pkg.setLastval(sites_site_id_seq.nextval, :new.site_id);
diff --git a/www/wiki/maintenance/oracle/archives/patch-comment-table.sql b/www/wiki/maintenance/oracle/archives/patch-comment-table.sql
new file mode 100644
index 00000000..cfe944fc
--- /dev/null
+++ b/www/wiki/maintenance/oracle/archives/patch-comment-table.sql
@@ -0,0 +1,68 @@
+--
+-- patch-comment-table.sql
+--
+-- T166732. Add a `comment` table and various columns (and temporary tables) to reference it.
+
+CREATE SEQUENCE comment_comment_id_seq;
+CREATE TABLE &mw_prefix."COMMENT" (
+ comment_id NUMBER NOT NULL,
+ comment_hash NUMBER NOT NULL,
+ comment_text CLOB,
+ comment_data CLOB
+);
+CREATE INDEX &mw_prefix.comment_hash ON &mw_prefix."COMMENT" (comment_hash);
+/*$mw$*/
+CREATE TRIGGER &mw_prefix.comment_seq_trg BEFORE INSERT ON &mw_prefix."COMMENT"
+ FOR EACH ROW WHEN (new.comment_id IS NULL)
+BEGIN
+ &mw_prefix.lastval_pkg.setLastval(comment_comment_id_seq.nextval, :new.comment_id);
+END;
+/*$mw$*/
+
+-- dummy row for FKs. Hash is intentionally wrong so CommentStore won't match it.
+INSERT INTO &mw_prefix."COMMENT" (comment_hash, comment_text) VALUES (-1, '** dummy **');
+
+
+CREATE TABLE &mw_prefix.revision_comment_temp (
+ revcomment_rev NUMBER NOT NULL,
+ revcomment_comment_id NUMBER NOT NULL
+);
+ALTER TABLE &mw_prefix.revision_comment_temp ADD CONSTRAINT &mw_prefix.revision_comment_temp_pk PRIMARY KEY (revcomment_rev, revcomment_comment_id);
+ALTER TABLE &mw_prefix.revision_comment_temp ADD CONSTRAINT &mw_prefix.revision_comment_temp_fk1 FOREIGN KEY (revcomment_rev) REFERENCES &mw_prefix.revision(rev_id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED;
+ALTER TABLE &mw_prefix.revision_comment_temp ADD CONSTRAINT &mw_prefix.revision_comment_temp_fk2 FOREIGN KEY (revcomment_comment_id) REFERENCES &mw_prefix."COMMENT"(comment_id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED;
+CREATE UNIQUE INDEX &mw_prefix.revcomment_rev ON &mw_prefix.revision_comment_temp (revcomment_rev);
+
+
+CREATE TABLE &mw_prefix.image_comment_temp (
+ imgcomment_name VARCHAR2(255) NOT NULL,
+ imgcomment_description_id NUMBER NOT NULL
+);
+ALTER TABLE &mw_prefix.image_comment_temp ADD CONSTRAINT &mw_prefix.image_comment_temp_pk PRIMARY KEY (imgcomment_name, imgcomment_description_id);
+ALTER TABLE &mw_prefix.image_comment_temp ADD CONSTRAINT &mw_prefix.image_comment_temp_fk1 FOREIGN KEY (imgcomment_name) REFERENCES &mw_prefix.image(img_name) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED;
+ALTER TABLE &mw_prefix.image_comment_temp ADD CONSTRAINT &mw_prefix.image_comment_temp_fk2 FOREIGN KEY (imgcomment_description_id) REFERENCES &mw_prefix."COMMENT"(comment_id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED;
+CREATE UNIQUE INDEX &mw_prefix.imgcomment_name ON &mw_prefix.image_comment_temp (imgcomment_name);
+
+
+ALTER TABLE &mw_prefix.archive ADD COLUMN ar_comment_id NUMBER DEFAULT 0 NOT NULL;
+ALTER TABLE &mw_prefix.archive ADD CONSTRAINT &mw_prefix.archive_fk2 FOREIGN KEY (ar_comment_id) REFERENCES &mw_prefix."COMMENT"(comment_id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED;
+
+ALTER TABLE &mw_prefix.ipblocks ALTER COLUMN ipb_reason VARCHAR2(255) NULL;
+ALTER TABLE &mw_prefix.ipblocks ADD COLUMN ipb_reason_id NUMBER DEFAULT 0 NOT NULL;
+ALTER TABLE &mw_prefix.ipblocks ADD CONSTRAINT &mw_prefix.ipblocks_fk3 FOREIGN KEY (ipb_reason_id) REFERENCES &mw_prefix."COMMENT"(comment_id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED;
+
+ALTER TABLE &mw_prefix.oldimage ADD COLUMN oi_description_id NUMBER DEFAULT 0 NOT NULL;
+ALTER TABLE &mw_prefix.oldimage ADD CONSTRAINT &mw_prefix.oldimage_fk3 FOREIGN KEY (oi_description_id) REFERENCES &mw_prefix."COMMENT"(comment_id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED;
+
+ALTER TABLE &mw_prefix.filearchive ADD COLUMN fa_deleted_reason_id NUMBER DEFAULT 0 NOT NULL;
+ALTER TABLE &mw_prefix.filearchive ADD COLUMN fa_description_id NUMBER DEFAULT 0 NOT NULL;
+ALTER TABLE &mw_prefix.filearchive ADD CONSTRAINT &mw_prefix.filearchive_fk3 FOREIGN KEY (fa_deleted_reason_id) REFERENCES &mw_prefix."COMMENT"(comment_id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED;
+ALTER TABLE &mw_prefix.filearchive ADD CONSTRAINT &mw_prefix.filearchive_fk4 FOREIGN KEY (fa_description_id) REFERENCES &mw_prefix."COMMENT"(comment_id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED;
+
+ALTER TABLE &mw_prefix.recentchanges ADD COLUMN rc_comment_id NUMBER DEFAULT 0 NOT NULL;
+ALTER TABLE &mw_prefix.recentchanges ADD CONSTRAINT &mw_prefix.recentchanges_fk3 FOREIGN KEY (rc_comment_id) REFERENCES &mw_prefix."COMMENT"(comment_id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED;
+
+ALTER TABLE &mw_prefix.logging ADD COLUMN log_comment_id NUMBER DEFAULT 0 NOT NULL;
+ALTER TABLE &mw_prefix.logging ADD CONSTRAINT &mw_prefix.logging_fk2 FOREIGN KEY (log_comment_id) REFERENCES &mw_prefix."COMMENT"(comment_id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED;
+
+ALTER TABLE &mw_prefix.protected_titles ADD COLUMN pt_reason_id NUMBER DEFAULT 0 NOT NULL;
+ALTER TABLE &mw_prefix.protected_titles ADD CONSTRAINT &mw_prefix.protected_titles_fk1 FOREIGN KEY (pt_reason_id) REFERENCES &mw_prefix."COMMENT"(comment_id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED;
diff --git a/www/wiki/maintenance/oracle/archives/patch-content.sql b/www/wiki/maintenance/oracle/archives/patch-content.sql
new file mode 100644
index 00000000..17d76ae6
--- /dev/null
+++ b/www/wiki/maintenance/oracle/archives/patch-content.sql
@@ -0,0 +1,18 @@
+CREATE SEQUENCE content_content_id_seq;
+CREATE TABLE &mw_prefix.content (
+ content_id NUMBER NOT NULL,
+ content_size NUMBER NOT NULL,
+ content_sha1 VARCHAR2(32) NOT NULL,
+ content_model NUMBER NOT NULL,
+ content_address VARCHAR2(255) NOT NULL
+);
+
+ALTER TABLE &mw_prefix.content ADD CONSTRAINT &mw_prefix.content_pk PRIMARY KEY (content_id);
+
+/*$mw$*/
+CREATE TRIGGER &mw_prefix.content_seq_trg BEFORE INSERT ON &mw_prefix.content
+ FOR EACH ROW WHEN (new.content_id IS NULL)
+BEGIN
+ &mw_prefix.lastval_pkg.setLastval(content_content_id_seq.nextval, :new.content_id);
+END;
+/*$mw$*/ \ No newline at end of file
diff --git a/www/wiki/maintenance/oracle/archives/patch-content_models.sql b/www/wiki/maintenance/oracle/archives/patch-content_models.sql
new file mode 100644
index 00000000..49b91271
--- /dev/null
+++ b/www/wiki/maintenance/oracle/archives/patch-content_models.sql
@@ -0,0 +1,18 @@
+CREATE SEQUENCE content_models_model_id_seq;
+CREATE TABLE &mw_prefix.content_models (
+ model_id NUMBER NOT NULL,
+ model_name VARCHAR2(64) NOT NULL
+);
+
+
+ALTER TABLE &mw_prefix.content_models ADD CONSTRAINT &mw_prefix.content_models_pk PRIMARY KEY (model_id);
+
+CREATE UNIQUE INDEX &mw_prefix.model_name_u01 ON &mw_prefix.content_models (model_name);
+
+/*$mw$*/
+CREATE TRIGGER &mw_prefix.content_models_seq_trg BEFORE INSERT ON &mw_prefix.content_models
+ FOR EACH ROW WHEN (new.model_id IS NULL)
+BEGIN
+ &mw_prefix.lastval_pkg.setLastval(content_models_model_id_seq.nextval, :new.model_id);
+END;
+/*$mw$*/ \ No newline at end of file
diff --git a/www/wiki/maintenance/oracle/archives/patch-drop-ar_text.sql b/www/wiki/maintenance/oracle/archives/patch-drop-ar_text.sql
new file mode 100644
index 00000000..40b04786
--- /dev/null
+++ b/www/wiki/maintenance/oracle/archives/patch-drop-ar_text.sql
@@ -0,0 +1,7 @@
+-- T33223: Remove obsolete ar_text and ar_flags columns
+-- (and make ar_text_id not nullable and default 0)
+
+define mw_prefix='{$wgDBprefix}';
+
+ALTER TABLE &mw_prefix.archive DROP (ar_text, ar_flags);
+ALTER TABLE &mw_prefix.archive MODIFY ar_text_id NUMBER DEFAULT 0 NOT NULL;
diff --git a/www/wiki/maintenance/oracle/archives/patch-externallinks-el_index_60.sql b/www/wiki/maintenance/oracle/archives/patch-externallinks-el_index_60.sql
index c4b906d1..39680ef3 100644
--- a/www/wiki/maintenance/oracle/archives/patch-externallinks-el_index_60.sql
+++ b/www/wiki/maintenance/oracle/archives/patch-externallinks-el_index_60.sql
@@ -1,5 +1,5 @@
define mw_prefix='{$wgDBprefix}';
-ALTER TABLE &mw_prefix.externallinks ADD el_index_60 VARBINARY(60) NOT NULL DEFAULT '';
+ALTER TABLE &mw_prefix.externallinks ADD el_index_60 VARCHAR2(60);
CREATE INDEX &mw_prefix.externallinks_i04 ON &mw_prefix.externallinks (el_index_60, el_id);
CREATE INDEX &mw_prefix.externallinks_i05 ON &mw_prefix.externallinks (el_from, el_index_60, el_id);
diff --git a/www/wiki/maintenance/oracle/archives/patch-image-img_description_id.sql b/www/wiki/maintenance/oracle/archives/patch-image-img_description_id.sql
new file mode 100644
index 00000000..5995b242
--- /dev/null
+++ b/www/wiki/maintenance/oracle/archives/patch-image-img_description_id.sql
@@ -0,0 +1,7 @@
+--
+-- patch-image-img_description_id.sql
+--
+-- T188132. Add `img_description_id` to the `image` table.
+
+ALTER TABLE &mw_prefix.image ADD ( img_description_id NUMBER DEFAULT 0 NOT NULL );
+ALTER TABLE &mw_prefix.image ADD CONSTRAINT &mw_prefix.oldimage_fk2 FOREIGN KEY (img_description_id) REFERENCES &mw_prefix."COMMENT"(comment_id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED;
diff --git a/www/wiki/maintenance/oracle/archives/patch-recentchanges-nttindex.sql b/www/wiki/maintenance/oracle/archives/patch-recentchanges-nttindex.sql
new file mode 100644
index 00000000..e24082bf
--- /dev/null
+++ b/www/wiki/maintenance/oracle/archives/patch-recentchanges-nttindex.sql
@@ -0,0 +1,4 @@
+define mw_prefix='{$wgDBprefix}';
+
+DROP INDEX IF EXISTS &mw_prefix.recentchanges_i02;
+CREATE INDEX &mw_prefix.recentchanges_i09 ON &mw_prefix.recentchanges (rc_namespace, rc_title, rc_timestamp);
diff --git a/www/wiki/maintenance/oracle/archives/patch-site_stats-modify.sql b/www/wiki/maintenance/oracle/archives/patch-site_stats-modify.sql
new file mode 100644
index 00000000..1c784d9b
--- /dev/null
+++ b/www/wiki/maintenance/oracle/archives/patch-site_stats-modify.sql
@@ -0,0 +1,7 @@
+ALTER TABLE /*_*/site_stats
+ ALTER ss_total_edits SET DEFAULT NULL,
+ ALTER ss_good_articles SET DEFAULT NULL,
+ ALTER ss_total_pages SET DEFAULT NULL,
+ ALTER ss_users SET DEFAULT NULL,
+ ALTER ss_active_users SET DEFAULT NULL,
+ ALTER ss_images SET DEFAULT NULL;
diff --git a/www/wiki/maintenance/oracle/archives/patch-slot-origin.sql b/www/wiki/maintenance/oracle/archives/patch-slot-origin.sql
new file mode 100644
index 00000000..1b398cd5
--- /dev/null
+++ b/www/wiki/maintenance/oracle/archives/patch-slot-origin.sql
@@ -0,0 +1,14 @@
+--
+-- Replace slot_inherited with slot_origin.
+--
+-- NOTE: There is no release that has slot_inherited. This is only needed to transition between
+-- snapshot versions of 1.30.
+--
+-- NOTE: No code that writes to the slots table was merge yet, the table is assumed to be empty.
+--
+DROP INDEX &mw_prefix.slot_role_inherited;
+
+ALTER TABLE &mw_prefix.slots DROP COLUMN slot_inherited;
+ALTER TABLE &mw_prefix.slots ADD ( slot_origin NUMBER NOT NULL );
+
+CREATE INDEX &mw_prefix.slot_revision_origin_role ON &mw_prefix.slots (slot_revision_id, slot_origin, slot_role_id);
diff --git a/www/wiki/maintenance/oracle/archives/patch-slot_roles.sql b/www/wiki/maintenance/oracle/archives/patch-slot_roles.sql
new file mode 100644
index 00000000..960cfbf0
--- /dev/null
+++ b/www/wiki/maintenance/oracle/archives/patch-slot_roles.sql
@@ -0,0 +1,17 @@
+CREATE SEQUENCE slot_roles_role_id_seq;
+CREATE TABLE &mw_prefix.slot_roles (
+ role_id NUMBER NOT NULL,
+ role_name VARCHAR2(64) NOT NULL
+);
+
+ALTER TABLE &mw_prefix.slot_roles ADD CONSTRAINT &mw_prefix.slot_roles_pk PRIMARY KEY (role_id);
+
+CREATE UNIQUE INDEX &mw_prefix.role_name_u01 ON &mw_prefix.slot_roles (role_name);
+
+/*$mw$*/
+CREATE TRIGGER &mw_prefix.slot_roles_seq_trg BEFORE INSERT ON &mw_prefix.slot_roles
+ FOR EACH ROW WHEN (new.role_id IS NULL)
+BEGIN
+ &mw_prefix.lastval_pkg.setLastval(slot_roles_role_id_seq.nextval, :new.role_id);
+END;
+/*$mw$*/ \ No newline at end of file
diff --git a/www/wiki/maintenance/oracle/archives/patch-slots.sql b/www/wiki/maintenance/oracle/archives/patch-slots.sql
new file mode 100644
index 00000000..fde35d5a
--- /dev/null
+++ b/www/wiki/maintenance/oracle/archives/patch-slots.sql
@@ -0,0 +1,10 @@
+CREATE TABLE &mw_prefix.slots (
+ slot_revision_id NUMBER NOT NULL,
+ slot_role_id NUMBER NOT NULL,
+ slot_content_id NUMBER NOT NULL,
+ slot_origin NUMBER NOT NULL
+);
+
+ALTER TABLE &mw_prefix.slots ADD CONSTRAINT &mw_prefix.slots_pk PRIMARY KEY (slot_revision_id, slot_role_id);
+
+CREATE INDEX &mw_prefix.slot_revision_origin_role ON &mw_prefix.slots (slot_revision_id, slot_origin, slot_role_id);
diff --git a/www/wiki/maintenance/oracle/tables.sql b/www/wiki/maintenance/oracle/tables.sql
index e6e2e565..87039fb0 100644
--- a/www/wiki/maintenance/oracle/tables.sql
+++ b/www/wiki/maintenance/oracle/tables.sql
@@ -48,7 +48,7 @@ CREATE UNIQUE INDEX &mw_prefix.mwuser_u01 ON &mw_prefix.mwuser (user_name);
CREATE INDEX &mw_prefix.mwuser_i01 ON &mw_prefix.mwuser (user_email_token);
CREATE INDEX &mw_prefix.mwuser_i02 ON &mw_prefix.mwuser (user_email, user_name);
/*$mw$*/
-CREATE TRIGGER &mw_prefix.mwuser_default_user_id BEFORE INSERT ON &mw_prefix.mwuser
+CREATE TRIGGER &mw_prefix.mwuser_seq_trg BEFORE INSERT ON &mw_prefix.mwuser
FOR EACH ROW WHEN (new.user_id IS NULL)
BEGIN
&mw_prefix.lastval_pkg.setLastval(user_user_id_seq.nextval, :new.user_id);
@@ -60,6 +60,26 @@ INSERT INTO &mw_prefix.mwuser
(user_id, user_name, user_options, user_touched, user_registration, user_editcount)
VALUES (0,'Anonymous','', current_timestamp, current_timestamp,0);
+CREATE SEQUENCE actor_actor_id_seq;
+CREATE TABLE &mw_prefix.actor (
+ actor_id NUMBER NOT NULL,
+ actor_user NUMBER,
+ actor_name VARCHAR2(255) NOT NULL
+);
+
+ALTER TABLE &mw_prefix.actor ADD CONSTRAINT &mw_prefix.actor_pk PRIMARY KEY (actor_id);
+
+/*$mw$*/
+CREATE TRIGGER &mw_prefix.actor_seq_trg BEFORE INSERT ON &mw_prefix.actor
+ FOR EACH ROW WHEN (new.actor_id IS NULL)
+BEGIN
+ &mw_prefix.lastval_pkg.setLastval(actor_actor_id_seq.nextval, :new.actor_id);
+END;
+/*$mw$*/
+
+-- Create a dummy actor to satisfy fk contraints
+INSERT INTO &mw_prefix.actor (actor_id, actor_name) VALUES (0,'##Anonymous##');
+
CREATE TABLE &mw_prefix.user_groups (
ug_user NUMBER DEFAULT 0 NOT NULL,
ug_group VARCHAR2(255) NOT NULL,
@@ -116,7 +136,7 @@ CREATE INDEX &mw_prefix.page_i01 ON &mw_prefix.page (page_random);
CREATE INDEX &mw_prefix.page_i02 ON &mw_prefix.page (page_len);
CREATE INDEX &mw_prefix.page_i03 ON &mw_prefix.page (page_is_redirect, page_namespace, page_len);
/*$mw$*/
-CREATE TRIGGER &mw_prefix.page_default_page_id BEFORE INSERT ON &mw_prefix.page
+CREATE TRIGGER &mw_prefix.page_seq_trg BEFORE INSERT ON &mw_prefix.page
FOR EACH ROW WHEN (new.page_id IS NULL)
BEGIN
&mw_prefix.lastval_pkg.setLastval(page_page_id_seq.nextval, :new.page_id);
@@ -135,6 +155,25 @@ BEGIN
END;
/*$mw$*/
+CREATE SEQUENCE comment_comment_id_seq;
+CREATE TABLE &mw_prefix."COMMENT" (
+ comment_id NUMBER NOT NULL,
+ comment_hash NUMBER NOT NULL,
+ comment_text CLOB,
+ comment_data CLOB
+);
+CREATE INDEX &mw_prefix.comment_hash ON &mw_prefix."COMMENT" (comment_hash);
+/*$mw$*/
+CREATE TRIGGER &mw_prefix.comment_seq_trg BEFORE INSERT ON &mw_prefix."COMMENT"
+ FOR EACH ROW WHEN (new.comment_id IS NULL)
+BEGIN
+ &mw_prefix.lastval_pkg.setLastval(comment_comment_id_seq.nextval, :new.comment_id);
+END;
+/*$mw$*/
+
+-- dummy row for FKs. Hash is intentionally wrong so CommentStore won't match it.
+INSERT INTO &mw_prefix."COMMENT" (comment_hash, comment_text) VALUES (-1, '** dummy **');
+
CREATE SEQUENCE revision_rev_id_seq;
CREATE TABLE &mw_prefix.revision (
rev_id NUMBER NOT NULL,
@@ -162,13 +201,33 @@ CREATE INDEX &mw_prefix.revision_i03 ON &mw_prefix.revision (rev_user,rev_timest
CREATE INDEX &mw_prefix.revision_i04 ON &mw_prefix.revision (rev_user_text,rev_timestamp);
CREATE INDEX &mw_prefix.revision_i05 ON &mw_prefix.revision (rev_page,rev_user,rev_timestamp);
/*$mw$*/
-CREATE TRIGGER &mw_prefix.revision_default_rev_id BEFORE INSERT ON &mw_prefix.revision
+CREATE TRIGGER &mw_prefix.revision_seq_trg BEFORE INSERT ON &mw_prefix.revision
FOR EACH ROW WHEN (new.rev_id IS NULL)
BEGIN
&mw_prefix.lastval_pkg.setLastval(revision_rev_id_seq.nextval, :new.rev_id);
END;
/*$mw$*/
+CREATE TABLE &mw_prefix.revision_comment_temp (
+ revcomment_rev NUMBER NOT NULL,
+ revcomment_comment_id NUMBER NOT NULL
+);
+ALTER TABLE &mw_prefix.revision_comment_temp ADD CONSTRAINT &mw_prefix.revision_comment_temp_pk PRIMARY KEY (revcomment_rev, revcomment_comment_id);
+ALTER TABLE &mw_prefix.revision_comment_temp ADD CONSTRAINT &mw_prefix.revision_comment_temp_fk1 FOREIGN KEY (revcomment_rev) REFERENCES &mw_prefix.revision(rev_id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED;
+ALTER TABLE &mw_prefix.revision_comment_temp ADD CONSTRAINT &mw_prefix.revision_comment_temp_fk2 FOREIGN KEY (revcomment_comment_id) REFERENCES &mw_prefix."COMMENT"(comment_id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED;
+CREATE UNIQUE INDEX &mw_prefix.revcomment_rev ON &mw_prefix.revision_comment_temp (revcomment_rev);
+
+CREATE TABLE &mw_prefix.revision_actor_temp (
+ revactor_rev NUMBER NOT NULL,
+ revactor_actor NUMBER NOT NULL,
+ revactor_timestamp TIMESTAMP(6) WITH TIME ZONE NOT NULL,
+ revactor_page NUMBER NOT NULL
+);
+ALTER TABLE &mw_prefix.revision_actor_temp ADD CONSTRAINT &mw_prefix.revision_actor_temp_pk PRIMARY KEY (revactor_rev, revactor_actor);
+CREATE UNIQUE INDEX &mw_prefix.revactor_rev ON &mw_prefix.revision_actor_temp (revactor_rev);
+CREATE INDEX &mw_prefix.actor_timestamp ON &mw_prefix.revision_actor_temp (revactor_actor,revactor_timestamp);
+CREATE INDEX &mw_prefix.page_actor_timestamp ON &mw_prefix.revision_actor_temp (revactor_page,revactor_actor,revactor_timestamp);
+
CREATE SEQUENCE text_old_id_seq;
CREATE TABLE &mw_prefix.pagecontent ( -- replaces reserved word 'text'
old_id NUMBER NOT NULL,
@@ -177,7 +236,7 @@ CREATE TABLE &mw_prefix.pagecontent ( -- replaces reserved word 'text'
);
ALTER TABLE &mw_prefix.pagecontent ADD CONSTRAINT &mw_prefix.pagecontent_pk PRIMARY KEY (old_id);
/*$mw$*/
-CREATE TRIGGER &mw_prefix.text_default_old_id BEFORE INSERT ON &mw_prefix.text
+CREATE TRIGGER &mw_prefix.pagecontent_seq_trg BEFORE INSERT ON &mw_prefix.pagecontent
FOR EACH ROW WHEN (new.old_id IS NULL)
BEGIN
&mw_prefix.lastval_pkg.setLastval(text_old_id_seq.nextval, :new.old_id);
@@ -189,15 +248,15 @@ CREATE TABLE &mw_prefix.archive (
ar_id NUMBER NOT NULL,
ar_namespace NUMBER DEFAULT 0 NOT NULL,
ar_title VARCHAR2(255) NOT NULL,
- ar_text CLOB,
ar_comment VARCHAR2(255),
+ ar_comment_id NUMBER DEFAULT 0 NOT NULL,
ar_user NUMBER DEFAULT 0 NOT NULL,
- ar_user_text VARCHAR2(255) NOT NULL,
+ ar_user_text VARCHAR2(255) NULL,
+ ar_actor NUMBER DEFAULT 0 NOT NULL,
ar_timestamp TIMESTAMP(6) WITH TIME ZONE NOT NULL,
ar_minor_edit CHAR(1) DEFAULT '0' NOT NULL,
- ar_flags VARCHAR2(255),
- ar_rev_id NUMBER,
- ar_text_id NUMBER,
+ ar_rev_id NUMBER NOT NULL,
+ ar_text_id NUMBER DEFAULT 0 NOT NULL,
ar_deleted CHAR(1) DEFAULT '0' NOT NULL,
ar_len NUMBER,
ar_page_id NUMBER,
@@ -208,17 +267,91 @@ CREATE TABLE &mw_prefix.archive (
);
ALTER TABLE &mw_prefix.archive ADD CONSTRAINT &mw_prefix.archive_pk PRIMARY KEY (ar_id);
ALTER TABLE &mw_prefix.archive ADD CONSTRAINT &mw_prefix.archive_fk1 FOREIGN KEY (ar_user) REFERENCES &mw_prefix.mwuser(user_id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED;
+ALTER TABLE &mw_prefix.archive ADD CONSTRAINT &mw_prefix.archive_fk2 FOREIGN KEY (ar_comment_id) REFERENCES &mw_prefix."COMMENT"(comment_id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED;
CREATE INDEX &mw_prefix.archive_i01 ON &mw_prefix.archive (ar_namespace,ar_title,ar_timestamp);
CREATE INDEX &mw_prefix.archive_i02 ON &mw_prefix.archive (ar_user_text,ar_timestamp);
+CREATE INDEX &mw_prefix.ar_actor_timestamp ON &mw_prefix.archive (ar_actor,ar_timestamp);
CREATE INDEX &mw_prefix.archive_i03 ON &mw_prefix.archive (ar_rev_id);
/*$mw$*/
-CREATE TRIGGER &mw_prefix.archive_default_ar_id BEFORE INSERT ON &mw_prefix.archive
+CREATE TRIGGER &mw_prefix.archive_seq_trg BEFORE INSERT ON &mw_prefix.archive
FOR EACH ROW WHEN (new.ar_id IS NULL)
BEGIN
&mw_prefix.lastval_pkg.setLastval(archive_ar_id_seq.nextval, :new.ar_id);
END;
/*$mw$*/
+
+CREATE TABLE &mw_prefix.slots (
+ slot_revision_id NUMBER NOT NULL,
+ slot_role_id NUMBER NOT NULL,
+ slot_content_id NUMBER NOT NULL,
+ slot_origin NUMBER NOT NULL
+);
+
+ALTER TABLE &mw_prefix.slots ADD CONSTRAINT &mw_prefix.slots_pk PRIMARY KEY (slot_revision_id, slot_role_id);
+
+CREATE INDEX &mw_prefix.slot_revision_origin_role ON &mw_prefix.slots (slot_revision_id, slot_origin, slot_role_id);
+
+
+CREATE SEQUENCE content_content_id_seq;
+CREATE TABLE &mw_prefix.content (
+ content_id NUMBER NOT NULL,
+ content_size NUMBER NOT NULL,
+ content_sha1 VARCHAR2(32) NOT NULL,
+ content_model NUMBER NOT NULL,
+ content_address VARCHAR2(255) NOT NULL
+);
+
+ALTER TABLE &mw_prefix.content ADD CONSTRAINT &mw_prefix.content_pk PRIMARY KEY (content_id);
+
+/*$mw$*/
+CREATE TRIGGER &mw_prefix.content_seq_trg BEFORE INSERT ON &mw_prefix.content
+ FOR EACH ROW WHEN (new.content_id IS NULL)
+BEGIN
+ &mw_prefix.lastval_pkg.setLastval(content_content_id_seq.nextval, :new.content_id);
+END;
+/*$mw$*/
+
+
+CREATE SEQUENCE slot_roles_role_id_seq;
+CREATE TABLE &mw_prefix.slot_roles (
+ role_id NUMBER NOT NULL,
+ role_name VARCHAR2(64) NOT NULL
+);
+
+ALTER TABLE &mw_prefix.slot_roles ADD CONSTRAINT &mw_prefix.slot_roles_pk PRIMARY KEY (role_id);
+
+CREATE UNIQUE INDEX &mw_prefix.role_name_u01 ON &mw_prefix.slot_roles (role_name);
+
+/*$mw$*/
+CREATE TRIGGER &mw_prefix.slot_roles_seq_trg BEFORE INSERT ON &mw_prefix.slot_roles
+ FOR EACH ROW WHEN (new.role_id IS NULL)
+BEGIN
+ &mw_prefix.lastval_pkg.setLastval(slot_roles_role_id_seq.nextval, :new.role_id);
+END;
+/*$mw$*/
+
+
+CREATE SEQUENCE content_models_model_id_seq;
+CREATE TABLE &mw_prefix.content_models (
+ model_id NUMBER NOT NULL,
+ model_name VARCHAR2(64) NOT NULL
+);
+
+
+ALTER TABLE &mw_prefix.content_models ADD CONSTRAINT &mw_prefix.content_models_pk PRIMARY KEY (model_id);
+
+CREATE UNIQUE INDEX &mw_prefix.model_name_u01 ON &mw_prefix.content_models (model_name);
+
+/*$mw$*/
+CREATE TRIGGER &mw_prefix.content_models_seq_trg BEFORE INSERT ON &mw_prefix.content_models
+ FOR EACH ROW WHEN (new.model_id IS NULL)
+BEGIN
+ &mw_prefix.lastval_pkg.setLastval(content_models_model_id_seq.nextval, :new.model_id);
+END;
+/*$mw$*/
+
+
CREATE TABLE &mw_prefix.pagelinks (
pl_from NUMBER NOT NULL,
pl_namespace NUMBER DEFAULT 0 NOT NULL,
@@ -273,7 +406,7 @@ ALTER TABLE &mw_prefix.category ADD CONSTRAINT &mw_prefix.category_pk PRIMARY KE
CREATE UNIQUE INDEX &mw_prefix.category_u01 ON &mw_prefix.category (cat_title);
CREATE INDEX &mw_prefix.category_i01 ON &mw_prefix.category (cat_pages);
/*$mw$*/
-CREATE TRIGGER &mw_prefix.category_default_cat_id BEFORE INSERT ON &mw_prefix.category
+CREATE TRIGGER &mw_prefix.category_seq_trg BEFORE INSERT ON &mw_prefix.category
FOR EACH ROW WHEN (new.cat_id IS NULL)
BEGIN
&mw_prefix.lastval_pkg.setLastval(category_cat_id_seq.nextval, :new.cat_id);
@@ -286,7 +419,7 @@ CREATE TABLE &mw_prefix.externallinks (
el_from NUMBER NOT NULL,
el_to VARCHAR2(2048) NOT NULL,
el_index VARCHAR2(2048) NOT NULL,
- el_index_60 VARBINARY(60) NOT NULL DEFAULT ''
+ el_index_60 VARCHAR2(60)
);
ALTER TABLE &mw_prefix.externallinks ADD CONSTRAINT &mw_prefix.externallinks_pk PRIMARY KEY (el_id);
ALTER TABLE &mw_prefix.externallinks ADD CONSTRAINT &mw_prefix.externallinks_fk1 FOREIGN KEY (el_from) REFERENCES &mw_prefix.page(page_id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED;
@@ -296,7 +429,7 @@ CREATE INDEX &mw_prefix.externallinks_i03 ON &mw_prefix.externallinks (el_index)
CREATE INDEX &mw_prefix.externallinks_i04 ON &mw_prefix.externallinks (el_index_60, el_id);
CREATE INDEX &mw_prefix.externallinks_i05 ON &mw_prefix.externallinks (el_from, el_index_60, el_id);
/*$mw$*/
-CREATE TRIGGER &mw_prefix.externallinks_default_el_id BEFORE INSERT ON &mw_prefix.externallinks
+CREATE TRIGGER &mw_prefix.externallinks_seq_trg BEFORE INSERT ON &mw_prefix.externallinks
FOR EACH ROW WHEN (new.el_id IS NULL)
BEGIN
&mw_prefix.lastval_pkg.setLastval(externallinks_el_id_seq.nextval, :new.el_id);
@@ -322,12 +455,12 @@ CREATE UNIQUE INDEX &mw_prefix.iwlinks_ui02 ON &mw_prefix.iwlinks (iwl_prefix, i
CREATE TABLE &mw_prefix.site_stats (
ss_row_id NUMBER NOT NULL PRIMARY KEY,
- ss_total_edits NUMBER DEFAULT 0,
- ss_good_articles NUMBER DEFAULT 0,
- ss_total_pages NUMBER DEFAULT -1,
- ss_users NUMBER DEFAULT -1,
- ss_active_users NUMBER DEFAULT -1,
- ss_images NUMBER DEFAULT 0
+ ss_total_edits NUMBER DEFAULT NULL,
+ ss_good_articles NUMBER DEFAULT NULL,
+ ss_total_pages NUMBER DEFAULT NULL,
+ ss_users NUMBER DEFAULT NULL,
+ ss_active_users NUMBER DEFAULT NULL,
+ ss_images NUMBER DEFAULT NULL
);
CREATE SEQUENCE ipblocks_ipb_id_seq;
@@ -337,7 +470,9 @@ CREATE TABLE &mw_prefix.ipblocks (
ipb_user NUMBER DEFAULT 0 NOT NULL,
ipb_by NUMBER DEFAULT 0 NOT NULL,
ipb_by_text VARCHAR2(255) NULL,
- ipb_reason VARCHAR2(255) NOT NULL,
+ ipb_by_actor NUMBER DEFUALT 0 NOT NULL,
+ ipb_reason VARCHAR2(255) NULL,
+ ipb_reason_id NUMBER DEFAULT 0 NOT NULL,
ipb_timestamp TIMESTAMP(6) WITH TIME ZONE NOT NULL,
ipb_auto CHAR(1) DEFAULT '0' NOT NULL,
ipb_anon_only CHAR(1) DEFAULT '0' NOT NULL,
@@ -354,6 +489,7 @@ CREATE TABLE &mw_prefix.ipblocks (
ALTER TABLE &mw_prefix.ipblocks ADD CONSTRAINT &mw_prefix.ipblocks_pk PRIMARY KEY (ipb_id);
ALTER TABLE &mw_prefix.ipblocks ADD CONSTRAINT &mw_prefix.ipblocks_fk1 FOREIGN KEY (ipb_user) REFERENCES &mw_prefix.mwuser(user_id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED;
ALTER TABLE &mw_prefix.ipblocks ADD CONSTRAINT &mw_prefix.ipblocks_fk2 FOREIGN KEY (ipb_by) REFERENCES &mw_prefix.mwuser(user_id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED;
+ALTER TABLE &mw_prefix.ipblocks ADD CONSTRAINT &mw_prefix.ipblocks_fk3 FOREIGN KEY (ipb_reason_id) REFERENCES &mw_prefix."COMMENT"(comment_id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED;
CREATE UNIQUE INDEX &mw_prefix.ipblocks_u01 ON &mw_prefix.ipblocks (ipb_address, ipb_user, ipb_auto, ipb_anon_only);
CREATE INDEX &mw_prefix.ipblocks_i01 ON &mw_prefix.ipblocks (ipb_user);
CREATE INDEX &mw_prefix.ipblocks_i02 ON &mw_prefix.ipblocks (ipb_range_start, ipb_range_end);
@@ -361,7 +497,7 @@ CREATE INDEX &mw_prefix.ipblocks_i03 ON &mw_prefix.ipblocks (ipb_timestamp);
CREATE INDEX &mw_prefix.ipblocks_i04 ON &mw_prefix.ipblocks (ipb_expiry);
CREATE INDEX &mw_prefix.ipblocks_i05 ON &mw_prefix.ipblocks (ipb_parent_block_id);
/*$mw$*/
-CREATE TRIGGER &mw_prefix.ipblocks_default_ipb_id BEFORE INSERT ON &mw_prefix.ipblocks
+CREATE TRIGGER &mw_prefix.ipblocks_seq_trg BEFORE INSERT ON &mw_prefix.ipblocks
FOR EACH ROW WHEN (new.ipb_id IS NULL)
BEGIN
&mw_prefix.lastval_pkg.setLastval(ipblocks_ipb_id_seq.nextval, :new.ipb_id);
@@ -379,17 +515,30 @@ CREATE TABLE &mw_prefix.image (
img_major_mime VARCHAR2(32) DEFAULT 'unknown',
img_minor_mime VARCHAR2(100) DEFAULT 'unknown',
img_description VARCHAR2(255),
+ img_description_id NUMBER DEFAULT 0 NOT NULL,
img_user NUMBER DEFAULT 0 NOT NULL,
- img_user_text VARCHAR2(255) NOT NULL,
+ img_user_text VARCHAR2(255) NULL,
+ img_actor NUMBER DEFAULT 0 NOT NULL,
img_timestamp TIMESTAMP(6) WITH TIME ZONE,
img_sha1 VARCHAR2(32)
);
ALTER TABLE &mw_prefix.image ADD CONSTRAINT &mw_prefix.image_pk PRIMARY KEY (img_name);
ALTER TABLE &mw_prefix.image ADD CONSTRAINT &mw_prefix.image_fk1 FOREIGN KEY (img_user) REFERENCES &mw_prefix.mwuser(user_id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED;
+ALTER TABLE &mw_prefix.image ADD CONSTRAINT &mw_prefix.image_fk2 FOREIGN KEY (img_description_id) REFERENCES &mw_prefix."COMMENT"(comment_id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED;
CREATE INDEX &mw_prefix.image_i01 ON &mw_prefix.image (img_user_text,img_timestamp);
CREATE INDEX &mw_prefix.image_i02 ON &mw_prefix.image (img_size);
CREATE INDEX &mw_prefix.image_i03 ON &mw_prefix.image (img_timestamp);
CREATE INDEX &mw_prefix.image_i04 ON &mw_prefix.image (img_sha1);
+CREATE INDEX &mw_prefix.img_actor_timestamp ON &mw_prefix.image (img_actor, img_timestamp);
+
+CREATE TABLE &mw_prefix.image_comment_temp (
+ imgcomment_name VARCHAR2(255) NOT NULL,
+ imgcomment_description_id NUMBER NOT NULL
+);
+ALTER TABLE &mw_prefix.image_comment_temp ADD CONSTRAINT &mw_prefix.image_comment_temp_pk PRIMARY KEY (imgcomment_name, imgcomment_description_id);
+ALTER TABLE &mw_prefix.image_comment_temp ADD CONSTRAINT &mw_prefix.image_comment_temp_fk1 FOREIGN KEY (imgcomment_name) REFERENCES &mw_prefix.image(img_name) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED;
+ALTER TABLE &mw_prefix.image_comment_temp ADD CONSTRAINT &mw_prefix.image_comment_temp_fk2 FOREIGN KEY (imgcomment_description_id) REFERENCES &mw_prefix."COMMENT"(comment_id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED;
+CREATE UNIQUE INDEX &mw_prefix.imgcomment_name ON &mw_prefix.image_comment_temp (imgcomment_name);
CREATE TABLE &mw_prefix.oldimage (
@@ -400,8 +549,10 @@ CREATE TABLE &mw_prefix.oldimage (
oi_height NUMBER DEFAULT 0 NOT NULL,
oi_bits NUMBER DEFAULT 0 NOT NULL,
oi_description VARCHAR2(255),
+ oi_description_id NUMBER DEFAULT 0 NOT NULL,
oi_user NUMBER DEFAULT 0 NOT NULL,
- oi_user_text VARCHAR2(255) NOT NULL,
+ oi_user_text VARCHAR2(255) NULL,
+ oi_actor NUMBER DEFAULT 0 NOT NULL,
oi_timestamp TIMESTAMP(6) WITH TIME ZONE NOT NULL,
oi_metadata CLOB,
oi_media_type VARCHAR2(32) DEFAULT NULL,
@@ -412,7 +563,9 @@ CREATE TABLE &mw_prefix.oldimage (
);
ALTER TABLE &mw_prefix.oldimage ADD CONSTRAINT &mw_prefix.oldimage_fk1 FOREIGN KEY (oi_name) REFERENCES &mw_prefix.image(img_name) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED;
ALTER TABLE &mw_prefix.oldimage ADD CONSTRAINT &mw_prefix.oldimage_fk2 FOREIGN KEY (oi_user) REFERENCES &mw_prefix.mwuser(user_id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED;
+ALTER TABLE &mw_prefix.oldimage ADD CONSTRAINT &mw_prefix.oldimage_fk3 FOREIGN KEY (oi_description_id) REFERENCES &mw_prefix."COMMENT"(comment_id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED;
CREATE INDEX &mw_prefix.oldimage_i01 ON &mw_prefix.oldimage (oi_user_text,oi_timestamp);
+CREATE INDEX &mw_prefix.oi_actor_timestamp ON &mw_prefix.oldimage (oi_actor,oi_timestamp);
CREATE INDEX &mw_prefix.oldimage_i02 ON &mw_prefix.oldimage (oi_name,oi_timestamp);
CREATE INDEX &mw_prefix.oldimage_i03 ON &mw_prefix.oldimage (oi_name,oi_archive_name);
CREATE INDEX &mw_prefix.oldimage_i04 ON &mw_prefix.oldimage (oi_sha1);
@@ -428,6 +581,7 @@ CREATE TABLE &mw_prefix.filearchive (
fa_deleted_user NUMBER DEFAULT 0 NOT NULL,
fa_deleted_timestamp TIMESTAMP(6) WITH TIME ZONE NOT NULL,
fa_deleted_reason CLOB,
+ fa_deleted_reason_id NUMBER DEFAULT 0 NOT NULL,
fa_size NUMBER DEFAULT 0 NOT NULL,
fa_width NUMBER DEFAULT 0 NOT NULL,
fa_height NUMBER DEFAULT 0 NOT NULL,
@@ -437,8 +591,10 @@ CREATE TABLE &mw_prefix.filearchive (
fa_major_mime VARCHAR2(32) DEFAULT 'unknown',
fa_minor_mime VARCHAR2(100) DEFAULT 'unknown',
fa_description VARCHAR2(255),
+ fa_description_id NUMBER DEFAULT 0 NOT NULL,
fa_user NUMBER DEFAULT 0 NOT NULL,
- fa_user_text VARCHAR2(255) NOT NULL,
+ fa_user_text VARCHAR2(255) NULL,
+ fa_actor NUMBER DEFAULT 0 NOT NULL,
fa_timestamp TIMESTAMP(6) WITH TIME ZONE,
fa_deleted NUMBER DEFAULT 0 NOT NULL,
fa_sha1 VARCHAR2(32)
@@ -446,13 +602,16 @@ CREATE TABLE &mw_prefix.filearchive (
ALTER TABLE &mw_prefix.filearchive ADD CONSTRAINT &mw_prefix.filearchive_pk PRIMARY KEY (fa_id);
ALTER TABLE &mw_prefix.filearchive ADD CONSTRAINT &mw_prefix.filearchive_fk1 FOREIGN KEY (fa_deleted_user) REFERENCES &mw_prefix.mwuser(user_id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED;
ALTER TABLE &mw_prefix.filearchive ADD CONSTRAINT &mw_prefix.filearchive_fk2 FOREIGN KEY (fa_user) REFERENCES &mw_prefix.mwuser(user_id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED;
+ALTER TABLE &mw_prefix.filearchive ADD CONSTRAINT &mw_prefix.filearchive_fk3 FOREIGN KEY (fa_deleted_reason_id) REFERENCES &mw_prefix."COMMENT"(comment_id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED;
+ALTER TABLE &mw_prefix.filearchive ADD CONSTRAINT &mw_prefix.filearchive_fk4 FOREIGN KEY (fa_description_id) REFERENCES &mw_prefix."COMMENT"(comment_id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED;
CREATE INDEX &mw_prefix.filearchive_i01 ON &mw_prefix.filearchive (fa_name, fa_timestamp);
CREATE INDEX &mw_prefix.filearchive_i02 ON &mw_prefix.filearchive (fa_storage_group, fa_storage_key);
CREATE INDEX &mw_prefix.filearchive_i03 ON &mw_prefix.filearchive (fa_deleted_timestamp);
CREATE INDEX &mw_prefix.filearchive_i04 ON &mw_prefix.filearchive (fa_user_text,fa_timestamp);
+CREATE INDEX &mw_prefix.fa_actor_timestamp ON &mw_prefix.filearchive (fa_actor,fa_timestamp);
CREATE INDEX &mw_prefix.filearchive_i05 ON &mw_prefix.filearchive (fa_sha1);
/*$mw$*/
-CREATE TRIGGER &mw_prefix.filearchive_default_fa_id BEFORE INSERT ON &mw_prefix.filearchive
+CREATE TRIGGER &mw_prefix.filearchive_seq_trg BEFORE INSERT ON &mw_prefix.filearchive
FOR EACH ROW WHEN (new.fa_id IS NULL)
BEGIN
&mw_prefix.lastval_pkg.setLastval(filearchive_fa_id_seq.nextval, :new.fa_id);
@@ -485,7 +644,7 @@ CREATE INDEX &mw_prefix.uploadstash_i01 ON &mw_prefix.uploadstash (us_user);
CREATE INDEX &mw_prefix.uploadstash_i02 ON &mw_prefix.uploadstash (us_timestamp);
CREATE UNIQUE INDEX &mw_prefix.uploadstash_u01 ON &mw_prefix.uploadstash (us_key);
/*$mw$*/
-CREATE TRIGGER &mw_prefix.uploadstash_default_us_id BEFORE INSERT ON &mw_prefix.uploadstash
+CREATE TRIGGER &mw_prefix.uploadstash_seq_trg BEFORE INSERT ON &mw_prefix.uploadstash
FOR EACH ROW WHEN (new.us_id IS NULL)
BEGIN
&mw_prefix.lastval_pkg.setLastval(uploadstash_us_id_seq.nextval, :new.us_id);
@@ -498,10 +657,12 @@ CREATE TABLE &mw_prefix.recentchanges (
rc_timestamp TIMESTAMP(6) WITH TIME ZONE NOT NULL,
rc_cur_time TIMESTAMP(6) WITH TIME ZONE,
rc_user NUMBER DEFAULT 0 NOT NULL,
- rc_user_text VARCHAR2(255) NOT NULL,
+ rc_user_text VARCHAR2(255) NULL,
+ rc_actor NUMBER DEFAULT 0 NOT NULL,
rc_namespace NUMBER DEFAULT 0 NOT NULL,
rc_title VARCHAR2(255) NOT NULL,
rc_comment VARCHAR2(255),
+ rc_comment_id NUMBER DEFAULT 0 NOT NULL,
rc_minor CHAR(1) DEFAULT '0' NOT NULL,
rc_bot CHAR(1) DEFAULT '0' NOT NULL,
rc_new CHAR(1) DEFAULT '0' NOT NULL,
@@ -523,16 +684,19 @@ CREATE TABLE &mw_prefix.recentchanges (
ALTER TABLE &mw_prefix.recentchanges ADD CONSTRAINT &mw_prefix.recentchanges_pk PRIMARY KEY (rc_id);
ALTER TABLE &mw_prefix.recentchanges ADD CONSTRAINT &mw_prefix.recentchanges_fk1 FOREIGN KEY (rc_user) REFERENCES &mw_prefix.mwuser(user_id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED;
ALTER TABLE &mw_prefix.recentchanges ADD CONSTRAINT &mw_prefix.recentchanges_fk2 FOREIGN KEY (rc_cur_id) REFERENCES &mw_prefix.page(page_id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED;
+ALTER TABLE &mw_prefix.recentchanges ADD CONSTRAINT &mw_prefix.recentchanges_fk3 FOREIGN KEY (rc_comment_id) REFERENCES &mw_prefix."COMMENT"(comment_id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED;
CREATE INDEX &mw_prefix.recentchanges_i01 ON &mw_prefix.recentchanges (rc_timestamp);
-CREATE INDEX &mw_prefix.recentchanges_i02 ON &mw_prefix.recentchanges (rc_namespace, rc_title);
+CREATE INDEX &mw_prefix.recentchanges_i09 ON &mw_prefix.recentchanges (rc_namespace, rc_title, rc_timestamp);
CREATE INDEX &mw_prefix.recentchanges_i03 ON &mw_prefix.recentchanges (rc_cur_id);
CREATE INDEX &mw_prefix.recentchanges_i04 ON &mw_prefix.recentchanges (rc_new,rc_namespace,rc_timestamp);
CREATE INDEX &mw_prefix.recentchanges_i05 ON &mw_prefix.recentchanges (rc_ip);
CREATE INDEX &mw_prefix.recentchanges_i06 ON &mw_prefix.recentchanges (rc_namespace, rc_user_text);
CREATE INDEX &mw_prefix.recentchanges_i07 ON &mw_prefix.recentchanges (rc_user_text, rc_timestamp);
+CREATE INDEX &mw_prefix.rc_ns_actor ON &mw_prefix.recentchanges (rc_namespace, rc_actor);
+CREATE INDEX &mw_prefix.rc_actor ON &mw_prefix.recentchanges (rc_actor, rc_timestamp);
CREATE INDEX &mw_prefix.recentchanges_i08 ON &mw_prefix.recentchanges (rc_namespace, rc_type, rc_patrolled, rc_timestamp);
/*$mw$*/
-CREATE TRIGGER &mw_prefix.recentchanges_default_rc_id BEFORE INSERT ON &mw_prefix.recentchanges
+CREATE TRIGGER &mw_prefix.recentchanges_seq_trg BEFORE INSERT ON &mw_prefix.recentchanges
FOR EACH ROW WHEN (new.rc_id IS NULL)
BEGIN
&mw_prefix.lastval_pkg.setLastval(recentchanges_rc_id_seq.nextval, :new.rc_id);
@@ -600,15 +764,18 @@ CREATE TABLE &mw_prefix.logging (
log_timestamp TIMESTAMP(6) WITH TIME ZONE NOT NULL,
log_user NUMBER DEFAULT 0 NOT NULL,
log_user_text VARCHAR2(255),
+ log_actor NUMBER DEFAULT 0 NOT NULL,
log_namespace NUMBER DEFAULT 0 NOT NULL,
log_title VARCHAR2(255) NOT NULL,
log_page NUMBER,
log_comment VARCHAR2(255),
+ log_comment_id NUMBER DEFAULT 0 NOT NULL,
log_params CLOB,
log_deleted CHAR(1) DEFAULT '0' NOT NULL
);
ALTER TABLE &mw_prefix.logging ADD CONSTRAINT &mw_prefix.logging_pk PRIMARY KEY (log_id);
ALTER TABLE &mw_prefix.logging ADD CONSTRAINT &mw_prefix.logging_fk1 FOREIGN KEY (log_user) REFERENCES &mw_prefix.mwuser(user_id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED;
+ALTER TABLE &mw_prefix.logging ADD CONSTRAINT &mw_prefix.logging_fk2 FOREIGN KEY (log_comment_id) REFERENCES &mw_prefix."COMMENT"(comment_id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED;
CREATE INDEX &mw_prefix.logging_i01 ON &mw_prefix.logging (log_type, log_timestamp);
CREATE INDEX &mw_prefix.logging_i02 ON &mw_prefix.logging (log_user, log_timestamp);
CREATE INDEX &mw_prefix.logging_i03 ON &mw_prefix.logging (log_namespace, log_title, log_timestamp);
@@ -616,8 +783,10 @@ CREATE INDEX &mw_prefix.logging_i04 ON &mw_prefix.logging (log_timestamp);
CREATE INDEX &mw_prefix.logging_i05 ON &mw_prefix.logging (log_type, log_action, log_timestamp);
CREATE INDEX &mw_prefix.logging_i06 ON &mw_prefix.logging (log_user_text, log_type, log_timestamp);
CREATE INDEX &mw_prefix.logging_i07 ON &mw_prefix.logging (log_user_text, log_timestamp);
+CREATE INDEX &mw_prefix.actor_time ON &mw_prefix.logging (log_actor, log_timestamp);
+CREATE INDEX &mw_prefix.log_actor_type_time ON &mw_prefix.logging (log_actor, log_type, log_timestamp);
/*$mw$*/
-CREATE TRIGGER &mw_prefix.logging_default_log_id BEFORE INSERT ON &mw_prefix.logging
+CREATE TRIGGER &mw_prefix.logging_seq_trg BEFORE INSERT ON &mw_prefix.logging
FOR EACH ROW WHEN (new.log_id IS NULL)
BEGIN
&mw_prefix.lastval_pkg.setLastval(logging_log_id_seq.nextval, :new.log_id);
@@ -654,7 +823,7 @@ CREATE INDEX &mw_prefix.job_i03 ON &mw_prefix.job (job_sha1);
CREATE INDEX &mw_prefix.job_i04 ON &mw_prefix.job (job_cmd,job_token,job_random);
CREATE INDEX &mw_prefix.job_i05 ON &mw_prefix.job (job_attempts);
/*$mw$*/
-CREATE TRIGGER &mw_prefix.job_default_job_id BEFORE INSERT ON &mw_prefix.job
+CREATE TRIGGER &mw_prefix.job_seq_trg BEFORE INSERT ON &mw_prefix.job
FOR EACH ROW WHEN (new.job_id IS NULL)
BEGIN
&mw_prefix.lastval_pkg.setLastval(job_job_id_seq.nextval, :new.job_id);
@@ -706,7 +875,7 @@ CREATE INDEX &mw_prefix.page_restrictions_i01 ON &mw_prefix.page_restrictions (p
CREATE INDEX &mw_prefix.page_restrictions_i02 ON &mw_prefix.page_restrictions (pr_level);
CREATE INDEX &mw_prefix.page_restrictions_i03 ON &mw_prefix.page_restrictions (pr_cascade);
/*$mw$*/
-CREATE TRIGGER &mw_prefix.page_restrictions_default_pr_id BEFORE INSERT ON &mw_prefix.page_restrictions
+CREATE TRIGGER &mw_prefix.page_restrictions_seq_trg BEFORE INSERT ON &mw_prefix.page_restrictions
FOR EACH ROW WHEN (new.pr_id IS NULL)
BEGIN
&mw_prefix.lastval_pkg.setLastval(page_restrictions_pr_id_seq.nextval, :new.pr_id);
@@ -718,10 +887,12 @@ CREATE TABLE &mw_prefix.protected_titles (
pt_title VARCHAR2(255) NOT NULL,
pt_user NUMBER NOT NULL,
pt_reason VARCHAR2(255),
+ pt_reason_id NUMBER DEFAULT 0 NOT NULL,
pt_timestamp TIMESTAMP(6) WITH TIME ZONE NOT NULL,
pt_expiry VARCHAR2(14) NOT NULL,
pt_create_perm VARCHAR2(60) NOT NULL
);
+ALTER TABLE &mw_prefix.protected_titles ADD CONSTRAINT &mw_prefix.protected_titles_fk1 FOREIGN KEY (pt_reason_id) REFERENCES &mw_prefix."COMMENT"(comment_id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED;
CREATE UNIQUE INDEX &mw_prefix.protected_titles_u01 ON &mw_prefix.protected_titles (pt_namespace,pt_title);
CREATE INDEX &mw_prefix.protected_titles_i01 ON &mw_prefix.protected_titles (pt_timestamp);
@@ -821,7 +992,7 @@ CREATE INDEX &mw_prefix.sites_i05 ON &mw_prefix.sites (site_protocol);
CREATE INDEX &mw_prefix.sites_i06 ON &mw_prefix.sites (site_domain);
CREATE INDEX &mw_prefix.sites_i07 ON &mw_prefix.sites (site_forward);
/*$mw$*/
-CREATE TRIGGER &mw_prefix.sites_default_site_id BEFORE INSERT ON &mw_prefix.sites
+CREATE TRIGGER &mw_prefix.sites_seq_trg BEFORE INSERT ON &mw_prefix.sites
FOR EACH ROW WHEN (new.site_id IS NULL)
BEGIN
&mw_prefix.lastval_pkg.setLastval(sites_site_id_seq.nextval, :new.site_id);
diff --git a/www/wiki/maintenance/oracle/user.sql b/www/wiki/maintenance/oracle/user.sql
index 57688eae..0a36ac4c 100644
--- a/www/wiki/maintenance/oracle/user.sql
+++ b/www/wiki/maintenance/oracle/user.sql
@@ -14,3 +14,5 @@ grant create synonym to &wiki_user.;
grant create table to &wiki_user.;
grant create sequence to &wiki_user.;
grant create trigger to &wiki_user.;
+grant create type to &wiki_user.;
+grant create procedure to &wiki_user.;
diff --git a/www/wiki/maintenance/orphans.php b/www/wiki/maintenance/orphans.php
index 644fb958..7acf6d82 100644
--- a/www/wiki/maintenance/orphans.php
+++ b/www/wiki/maintenance/orphans.php
@@ -75,23 +75,25 @@ class Orphans extends Maintenance {
*/
private function checkOrphans( $fix ) {
$dbw = $this->getDB( DB_MASTER );
- $commentStore = new CommentStore( 'rev_comment' );
+ $commentStore = CommentStore::getStore();
if ( $fix ) {
$this->lockTables( $dbw );
}
- $commentQuery = $commentStore->getJoin();
+ $commentQuery = $commentStore->getJoin( 'rev_comment' );
+ $actorQuery = ActorMigration::newMigration()->getJoin( 'rev_user' );
$this->output( "Checking for orphan revision table entries... "
. "(this may take a while on a large wiki)\n" );
$result = $dbw->select(
- [ 'revision', 'page' ] + $commentQuery['tables'],
- [ 'rev_id', 'rev_page', 'rev_timestamp', 'rev_user_text' ] + $commentQuery['fields'],
+ [ 'revision', 'page' ] + $commentQuery['tables'] + $actorQuery['tables'],
+ [ 'rev_id', 'rev_page', 'rev_timestamp' ] + $commentQuery['fields'] + $actorQuery['fields'],
[ 'page_id' => null ],
__METHOD__,
[],
[ 'page' => [ 'LEFT JOIN', [ 'rev_page=page_id' ] ] ] + $commentQuery['joins']
+ + $actorQuery['joins']
);
$orphans = $result->numRows();
if ( $orphans > 0 ) {
@@ -104,7 +106,7 @@ class Orphans extends Maintenance {
) );
foreach ( $result as $row ) {
- $comment = $commentStore->getComment( $row )->text;
+ $comment = $commentStore->getComment( 'rev_comment', $row )->text;
if ( $comment !== '' ) {
$comment = '(' . $wgContLang->truncate( $comment, 40 ) . ')';
}
@@ -202,8 +204,8 @@ class Orphans extends Maintenance {
$result2 = $dbw->query( "
SELECT MAX(rev_timestamp) as max_timestamp
FROM $revision
- WHERE rev_page=$row->page_id
- " );
+ WHERE rev_page=" . (int)( $row->page_id )
+ );
$row2 = $dbw->fetchObject( $result2 );
if ( $row2 ) {
if ( $row->rev_timestamp != $row2->max_timestamp ) {
@@ -252,5 +254,5 @@ class Orphans extends Maintenance {
}
}
-$maintClass = "Orphans";
+$maintClass = Orphans::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/pageExists.php b/www/wiki/maintenance/pageExists.php
index b631005f..dc9bbdac 100644
--- a/www/wiki/maintenance/pageExists.php
+++ b/www/wiki/maintenance/pageExists.php
@@ -45,9 +45,9 @@ class PageExists extends Maintenance {
$code = 1;
}
$this->output( $text );
- $this->error( '', $code );
+ exit( $code );
}
}
-$maintClass = "PageExists";
+$maintClass = PageExists::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/parse.php b/www/wiki/maintenance/parse.php
index 6279a348..b87a716f 100644
--- a/www/wiki/maintenance/parse.php
+++ b/www/wiki/maintenance/parse.php
@@ -140,5 +140,5 @@ class CLIParser extends Maintenance {
}
}
-$maintClass = "CLIParser";
+$maintClass = CLIParser::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/patchSql.php b/www/wiki/maintenance/patchSql.php
index bc211409..3ba962f9 100644
--- a/www/wiki/maintenance/patchSql.php
+++ b/www/wiki/maintenance/patchSql.php
@@ -66,5 +66,5 @@ class PatchSql extends Maintenance {
}
}
-$maintClass = "PatchSql";
+$maintClass = PatchSql::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/populateArchiveRevId.php b/www/wiki/maintenance/populateArchiveRevId.php
new file mode 100644
index 00000000..b8b9e688
--- /dev/null
+++ b/www/wiki/maintenance/populateArchiveRevId.php
@@ -0,0 +1,177 @@
+<?php
+/**
+ * Populate ar_rev_id in pre-1.5 rows
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Maintenance
+ */
+
+use Wikimedia\Rdbms\IDatabase;
+
+require_once __DIR__ . '/Maintenance.php';
+
+/**
+ * Maintenance script that populares archive.ar_rev_id in old rows
+ *
+ * @ingroup Maintenance
+ * @since 1.31
+ */
+class PopulateArchiveRevId extends LoggedUpdateMaintenance {
+ public function __construct() {
+ parent::__construct();
+ $this->addDescription( 'Populate ar_rev_id in pre-1.5 rows' );
+ $this->setBatchSize( 100 );
+ }
+
+ protected function getUpdateKey() {
+ return __CLASS__;
+ }
+
+ protected function doDBUpdates() {
+ $this->output( "Populating ar_rev_id...\n" );
+ $dbw = $this->getDB( DB_MASTER );
+
+ // Quick exit if there are no rows needing updates.
+ $any = $dbw->selectField(
+ 'archive',
+ 'ar_id',
+ [ 'ar_rev_id' => null ],
+ __METHOD__
+ );
+ if ( !$any ) {
+ $this->output( "Completed ar_rev_id population, 0 rows updated.\n" );
+ return true;
+ }
+
+ $rev = $this->makeDummyRevisionRow( $dbw );
+ $count = 0;
+ while ( true ) {
+ wfWaitForSlaves();
+
+ $arIds = $dbw->selectFieldValues(
+ 'archive',
+ 'ar_id',
+ [ 'ar_rev_id' => null ],
+ __METHOD__,
+ [ 'LIMIT' => $this->getBatchSize(), 'ORDER BY' => [ 'ar_id' ] ]
+ );
+ if ( !$arIds ) {
+ $this->output( "Completed ar_rev_id population, $count rows updated.\n" );
+ return true;
+ }
+
+ try {
+ $updates = $dbw->doAtomicSection( __METHOD__, function ( $dbw, $fname ) use ( $arIds, $rev ) {
+ // Create new rev_ids by inserting dummy rows into revision and then deleting them.
+ $dbw->insert( 'revision', array_fill( 0, count( $arIds ), $rev ), $fname );
+ $revIds = $dbw->selectFieldValues(
+ 'revision',
+ 'rev_id',
+ [ 'rev_timestamp' => $rev['rev_timestamp'] ],
+ $fname
+ );
+ if ( !is_array( $revIds ) ) {
+ throw new UnexpectedValueException( 'Failed to insert dummy revisions' );
+ }
+ if ( count( $revIds ) !== count( $arIds ) ) {
+ throw new UnexpectedValueException(
+ 'Tried to insert ' . count( $arIds ) . ' dummy revisions, but found '
+ . count( $revIds ) . ' matching rows.'
+ );
+ }
+ $dbw->delete( 'revision', [ 'rev_id' => $revIds ], $fname );
+
+ return array_combine( $arIds, $revIds );
+ } );
+ } catch ( UnexpectedValueException $ex ) {
+ $this->fatalError( $ex->getMessage() );
+ }
+
+ foreach ( $updates as $arId => $revId ) {
+ $dbw->update(
+ 'archive',
+ [ 'ar_rev_id' => $revId ],
+ [ 'ar_id' => $arId, 'ar_rev_id' => null ],
+ __METHOD__
+ );
+ $count += $dbw->affectedRows();
+ }
+
+ $min = min( array_keys( $updates ) );
+ $max = max( array_keys( $updates ) );
+ $this->output( " ... $min-$max\n" );
+ }
+ }
+
+ /**
+ * Construct a dummy revision table row to use for reserving IDs
+ *
+ * The row will have a wildly unlikely timestamp, and possibly a generic
+ * user and comment, but will otherwise be derived from a revision on the
+ * wiki's main page.
+ *
+ * @param IDatabase $dbw
+ * @return array
+ */
+ private function makeDummyRevisionRow( IDatabase $dbw ) {
+ $ts = $dbw->timestamp( '11111111111111' );
+ $mainPage = Title::newMainPage();
+ if ( !$mainPage ) {
+ $this->fatalError( 'Main page does not exist' );
+ }
+ $pageId = $mainPage->getArticleId();
+ if ( !$pageId ) {
+ $this->fatalError( $mainPage->getPrefixedText() . ' has no ID' );
+ }
+ $rev = $dbw->selectRow(
+ 'revision',
+ '*',
+ [ 'rev_page' => $pageId ],
+ __METHOD__,
+ [ 'ORDER BY' => 'rev_timestamp ASC' ]
+ );
+ if ( !$rev ) {
+ $this->fatalError( $mainPage->getPrefixedText() . ' has no revisions' );
+ }
+ unset( $rev->rev_id );
+ $rev = (array)$rev;
+ $rev['rev_timestamp'] = $ts;
+ if ( isset( $rev['rev_user'] ) ) {
+ $rev['rev_user'] = 0;
+ $rev['rev_user_text'] = '0.0.0.0';
+ }
+ if ( isset( $rev['rev_comment'] ) ) {
+ $rev['rev_comment'] = 'Dummy row';
+ }
+
+ $any = $dbw->selectField(
+ 'revision',
+ 'rev_id',
+ [ 'rev_timestamp' => $ts ],
+ __METHOD__
+ );
+ if ( $any ) {
+ $this->fatalError( "... Why does your database contain a revision dated $ts?" );
+ }
+
+ return $rev;
+ }
+}
+
+$maintClass = "PopulateArchiveRevId";
+require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/populateBacklinkNamespace.php b/www/wiki/maintenance/populateBacklinkNamespace.php
index 295dacda..e2fd8b5a 100644
--- a/www/wiki/maintenance/populateBacklinkNamespace.php
+++ b/www/wiki/maintenance/populateBacklinkNamespace.php
@@ -52,21 +52,22 @@ class PopulateBacklinkNamespace extends LoggedUpdateMaintenance {
$start = $this->getOption( 'lastUpdatedId' );
if ( !$start ) {
- $start = $db->selectField( 'page', 'MIN(page_id)', false, __METHOD__ );
+ $start = $db->selectField( 'page', 'MIN(page_id)', '', __METHOD__ );
}
if ( !$start ) {
$this->output( "Nothing to do." );
return false;
}
- $end = $db->selectField( 'page', 'MAX(page_id)', false, __METHOD__ );
+ $end = $db->selectField( 'page', 'MAX(page_id)', '', __METHOD__ );
+ $batchSize = $this->getBatchSize();
# Do remaining chunk
- $end += $this->mBatchSize - 1;
+ $end += $batchSize - 1;
$blockStart = $start;
- $blockEnd = $start + $this->mBatchSize - 1;
+ $blockEnd = $start + $batchSize - 1;
while ( $blockEnd <= $end ) {
$this->output( "...doing page_id from $blockStart to $blockEnd\n" );
- $cond = "page_id BETWEEN $blockStart AND $blockEnd";
+ $cond = "page_id BETWEEN " . (int)$blockStart . " AND " . (int)$blockEnd;
$res = $db->select( 'page', [ 'page_id', 'page_namespace' ], $cond, __METHOD__ );
foreach ( $res as $row ) {
$db->update( 'pagelinks',
@@ -85,13 +86,13 @@ class PopulateBacklinkNamespace extends LoggedUpdateMaintenance {
__METHOD__
);
}
- $blockStart += $this->mBatchSize - 1;
- $blockEnd += $this->mBatchSize - 1;
+ $blockStart += $batchSize - 1;
+ $blockEnd += $batchSize - 1;
wfWaitForSlaves();
}
return true;
}
}
-$maintClass = "PopulateBacklinkNamespace";
+$maintClass = PopulateBacklinkNamespace::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/populateCategory.php b/www/wiki/maintenance/populateCategory.php
index 5dccdd65..f2a00078 100644
--- a/www/wiki/maintenance/populateCategory.php
+++ b/www/wiki/maintenance/populateCategory.php
@@ -150,5 +150,5 @@ TEXT
}
}
-$maintClass = "PopulateCategory";
+$maintClass = PopulateCategory::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/populateContentModel.php b/www/wiki/maintenance/populateContentModel.php
index 74a918ae..8d64dae3 100644
--- a/www/wiki/maintenance/populateContentModel.php
+++ b/www/wiki/maintenance/populateContentModel.php
@@ -51,7 +51,7 @@ class PopulateContentModel extends Maintenance {
$ns = $this->getOption( 'ns' );
if ( !ctype_digit( $ns ) && $ns !== 'all' ) {
- $this->error( 'Invalid namespace', 1 );
+ $this->fatalError( 'Invalid namespace' );
}
$ns = $ns === 'all' ? 'all' : (int)$ns;
$table = $this->getOption( 'table' );
@@ -64,12 +64,12 @@ class PopulateContentModel extends Maintenance {
$this->populatePage( $dbw, $ns );
break;
default:
- $this->error( "Invalid table name: $table", 1 );
+ $this->fatalError( "Invalid table name: $table" );
}
}
protected function clearCache( $page_id, $rev_id ) {
- $contentModelKey = $this->wanCache->makeKey( 'page', 'content-model', $rev_id );
+ $contentModelKey = $this->wanCache->makeKey( 'page-content-model', $rev_id );
$revisionKey =
$this->wanCache->makeGlobalKey( 'revision', $this->wikiId, $page_id, $rev_id );
@@ -97,6 +97,7 @@ class PopulateContentModel extends Maintenance {
$toSave = [];
$lastId = 0;
$nsCondition = $ns === 'all' ? [] : [ 'page_namespace' => $ns ];
+ $batchSize = $this->getBatchSize();
do {
$rows = $dbw->select(
'page',
@@ -106,20 +107,20 @@ class PopulateContentModel extends Maintenance {
'page_id > ' . $dbw->addQuotes( $lastId ),
] + $nsCondition,
__METHOD__,
- [ 'LIMIT' => $this->mBatchSize, 'ORDER BY' => 'page_id ASC' ]
+ [ 'LIMIT' => $batchSize, 'ORDER BY' => 'page_id ASC' ]
);
$this->output( "Fetched {$rows->numRows()} rows.\n" );
foreach ( $rows as $row ) {
$title = Title::newFromRow( $row );
$model = ContentHandler::getDefaultModelFor( $title );
$toSave[$model][] = $row->page_id;
- if ( count( $toSave[$model] ) >= $this->mBatchSize ) {
+ if ( count( $toSave[$model] ) >= $batchSize ) {
$this->updatePageRows( $dbw, $toSave[$model], $model );
unset( $toSave[$model] );
}
$lastId = $row->page_id;
}
- } while ( $rows->numRows() >= $this->mBatchSize );
+ } while ( $rows->numRows() >= $batchSize );
foreach ( $toSave as $model => $pages ) {
$this->updatePageRows( $dbw, $pages, $model );
}
@@ -168,6 +169,7 @@ class PopulateContentModel extends Maintenance {
$toSave = [];
$idsToClear = [];
$lastId = 0;
+ $batchSize = $this->getBatchSize();
do {
$rows = $dbw->select(
$selectTables,
@@ -181,7 +183,7 @@ class PopulateContentModel extends Maintenance {
"$key > " . $dbw->addQuotes( $lastId ),
] + $where,
__METHOD__,
- [ 'LIMIT' => $this->mBatchSize, 'ORDER BY' => "$key ASC" ],
+ [ 'LIMIT' => $batchSize, 'ORDER BY' => "$key ASC" ],
$join_conds
);
$this->output( "Fetched {$rows->numRows()} rows.\n" );
@@ -232,12 +234,12 @@ class PopulateContentModel extends Maintenance {
}
}
- if ( count( $toSave[$defaultModel] ) >= $this->mBatchSize ) {
+ if ( count( $toSave[$defaultModel] ) >= $batchSize ) {
$this->updateRevisionOrArchiveRows( $dbw, $toSave[$defaultModel], $defaultModel, $table );
unset( $toSave[$defaultModel] );
}
}
- } while ( $rows->numRows() >= $this->mBatchSize );
+ } while ( $rows->numRows() >= $batchSize );
foreach ( $toSave as $model => $ids ) {
$this->updateRevisionOrArchiveRows( $dbw, $ids, $model, $table );
}
@@ -248,5 +250,5 @@ class PopulateContentModel extends Maintenance {
}
}
-$maintClass = 'PopulateContentModel';
+$maintClass = PopulateContentModel::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/populateFilearchiveSha1.php b/www/wiki/maintenance/populateFilearchiveSha1.php
index 7557a42f..ef57640b 100644
--- a/www/wiki/maintenance/populateFilearchiveSha1.php
+++ b/www/wiki/maintenance/populateFilearchiveSha1.php
@@ -56,9 +56,9 @@ class PopulateFilearchiveSha1 extends LoggedUpdateMaintenance {
}
$this->output( "Populating fa_sha1 field from fa_storage_key\n" );
- $endId = $dbw->selectField( $table, 'MAX(fa_id)', false, __METHOD__ );
+ $endId = $dbw->selectField( $table, 'MAX(fa_id)', '', __METHOD__ );
- $batchSize = $this->mBatchSize;
+ $batchSize = $this->getBatchSize();
$done = 0;
do {
@@ -104,5 +104,5 @@ class PopulateFilearchiveSha1 extends LoggedUpdateMaintenance {
}
}
-$maintClass = "PopulateFilearchiveSha1";
+$maintClass = PopulateFilearchiveSha1::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/populateImageSha1.php b/www/wiki/maintenance/populateImageSha1.php
index b581d661..212a20de 100644
--- a/www/wiki/maintenance/populateImageSha1.php
+++ b/www/wiki/maintenance/populateImageSha1.php
@@ -76,9 +76,7 @@ class PopulateImageSha1 extends LoggedUpdateMaintenance {
__METHOD__
);
if ( !$res ) {
- $this->error( "No such file: $file", true );
-
- return false;
+ $this->fatalError( "No such file: $file" );
}
$this->output( "Populating img_sha1 field for specified files\n" );
} else {
@@ -119,7 +117,7 @@ class PopulateImageSha1 extends LoggedUpdateMaintenance {
$numRows = $res->numRows();
$i = 0;
foreach ( $res as $row ) {
- if ( $i % $this->mBatchSize == 0 ) {
+ if ( $i % $this->getBatchSize() == 0 ) {
$this->output( sprintf(
"Done %d of %d, %5.3f%% \r", $i, $numRows, $i / $numRows * 100 ) );
wfWaitForSlaves();
@@ -180,5 +178,5 @@ class PopulateImageSha1 extends LoggedUpdateMaintenance {
}
}
-$maintClass = "PopulateImageSha1";
+$maintClass = PopulateImageSha1::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/populateIpChanges.php b/www/wiki/maintenance/populateIpChanges.php
index ac456507..6e88dfae 100644
--- a/www/wiki/maintenance/populateIpChanges.php
+++ b/www/wiki/maintenance/populateIpChanges.php
@@ -65,7 +65,7 @@ TEXT
$dbw = $this->getDB( DB_MASTER );
if ( !$dbw->tableExists( 'ip_changes' ) ) {
- $this->error( 'ip_changes table does not exist', true );
+ $this->fatalError( 'ip_changes table does not exist' );
}
$lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
@@ -75,7 +75,7 @@ TEXT
$start = $this->getOption( 'rev-id', 0 );
$end = $maxRevId > 0
? $maxRevId
- : $dbw->selectField( 'revision', 'MAX(rev_id)', false, __METHOD__ );
+ : $dbw->selectField( 'revision', 'MAX(rev_id)', '', __METHOD__ );
if ( empty( $end ) ) {
$this->output( "No revisions found, aborting.\n" );
@@ -88,13 +88,19 @@ TEXT
$this->output( "Copying IP revisions to ip_changes, from rev_id $start to rev_id $end\n" );
+ $actorMigration = ActorMigration::newMigration();
+ $actorQuery = $actorMigration->getJoin( 'rev_user' );
+ $revUserIsAnon = $actorMigration->isAnon( $actorQuery['fields']['rev_user'] );
+
while ( $blockStart <= $end ) {
- $blockEnd = min( $blockStart + $this->mBatchSize, $end );
+ $blockEnd = min( $blockStart + $this->getBatchSize(), $end );
$rows = $dbr->select(
- 'revision',
- [ 'rev_id', 'rev_timestamp', 'rev_user_text' ],
- [ "rev_id BETWEEN $blockStart AND $blockEnd", 'rev_user' => 0 ],
- __METHOD__
+ [ 'revision' ] + $actorQuery['tables'],
+ [ 'rev_id', 'rev_timestamp', 'rev_user_text' => $actorQuery['fields']['rev_user_text'] ],
+ [ "rev_id BETWEEN " . (int)$blockStart . " AND " . (int)$blockEnd, $revUserIsAnon ],
+ __METHOD__,
+ [],
+ $actorQuery['joins']
);
$numRows = $rows->numRows();
@@ -143,5 +149,5 @@ TEXT
}
}
-$maintClass = "PopulateIpChanges";
+$maintClass = PopulateIpChanges::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/populateLogSearch.php b/www/wiki/maintenance/populateLogSearch.php
index 1b07407e..589be48f 100644
--- a/www/wiki/maintenance/populateLogSearch.php
+++ b/www/wiki/maintenance/populateLogSearch.php
@@ -53,33 +53,38 @@ class PopulateLogSearch extends LoggedUpdateMaintenance {
}
protected function doDBUpdates() {
+ global $wgActorTableSchemaMigrationStage;
+
+ $batchSize = $this->getBatchSize();
$db = $this->getDB( DB_MASTER );
if ( !$db->tableExists( 'log_search' ) ) {
$this->error( "log_search does not exist" );
return false;
}
- $start = $db->selectField( 'logging', 'MIN(log_id)', false, __FUNCTION__ );
+ $start = $db->selectField( 'logging', 'MIN(log_id)', '', __FUNCTION__ );
if ( !$start ) {
$this->output( "Nothing to do.\n" );
return true;
}
- $end = $db->selectField( 'logging', 'MAX(log_id)', false, __FUNCTION__ );
+ $end = $db->selectField( 'logging', 'MAX(log_id)', '', __FUNCTION__ );
# Do remaining chunk
- $end += $this->mBatchSize - 1;
+ $end += $batchSize - 1;
$blockStart = $start;
- $blockEnd = $start + $this->mBatchSize - 1;
+ $blockEnd = $start + $batchSize - 1;
$delTypes = [ 'delete', 'suppress' ]; // revisiondelete types
while ( $blockEnd <= $end ) {
$this->output( "...doing log_id from $blockStart to $blockEnd\n" );
- $cond = "log_id BETWEEN $blockStart AND $blockEnd";
- $res = $db->select( 'logging', '*', $cond, __FUNCTION__ );
+ $cond = "log_id BETWEEN " . (int)$blockStart . " AND " . (int)$blockEnd;
+ $res = $db->select(
+ 'logging', [ 'log_id', 'log_type', 'log_action', 'log_params' ], $cond, __FUNCTION__
+ );
foreach ( $res as $row ) {
- // RevisionDelete logs - revisions
if ( LogEventsList::typeAction( $row, $delTypes, 'revision' ) ) {
+ // RevisionDelete logs - revisions
$params = LogPage::extractParams( $row->log_params );
// Param format: <urlparam> <item CSV> [<ofield> <nfield>]
if ( count( $params ) < 2 ) {
@@ -104,30 +109,31 @@ class PopulateLogSearch extends LoggedUpdateMaintenance {
$log = new LogPage( $row->log_type );
// Add item relations...
$log->addRelations( $field, $items, $row->log_id );
- // Determine what table to query...
+ // Query item author relations...
$prefix = substr( $field, 0, strpos( $field, '_' ) ); // db prefix
if ( !isset( self::$tableMap[$prefix] ) ) {
continue; // bad row?
}
- $table = self::$tableMap[$prefix];
- $userField = $prefix . '_user';
- $userTextField = $prefix . '_user_text';
- // Add item author relations...
- $userIds = $userIPs = [];
- $sres = $db->select( $table,
- [ $userField, $userTextField ],
- [ $field => $items ]
- );
- foreach ( $sres as $srow ) {
- if ( $srow->$userField > 0 ) {
- $userIds[] = intval( $srow->$userField );
- } elseif ( $srow->$userTextField != '' ) {
- $userIPs[] = $srow->$userTextField;
+ $tables = [ self::$tableMap[$prefix] ];
+ $fields = [];
+ $joins = [];
+ if ( $wgActorTableSchemaMigrationStage < MIGRATION_NEW ) {
+ $fields['userid'] = $prefix . '_user';
+ $fields['username'] = $prefix . '_user_text';
+ }
+ if ( $wgActorTableSchemaMigrationStage > MIGRATION_OLD ) {
+ if ( $prefix === 'rev' ) {
+ $tables[] = 'revision_actor_temp';
+ $joins['revision_actor_temp'] = [
+ $wgActorTableSchemaMigrationStage === MIGRATION_NEW ? 'JOIN' : 'LEFT JOIN',
+ 'rev_id = revactor_rev',
+ ];
+ $fields['actorid'] = 'revactor_actor';
+ } else {
+ $fields['actorid'] = $prefix . '_actor';
}
}
- // Add item author relations...
- $log->addRelations( 'target_author_id', $userIds, $row->log_id );
- $log->addRelations( 'target_author_ip', $userIPs, $row->log_id );
+ $sres = $db->select( $tables, $fields, [ $field => $items ], __METHOD__, [], $joins );
} elseif ( LogEventsList::typeAction( $row, $delTypes, 'event' ) ) {
// RevisionDelete logs - log events
$params = LogPage::extractParams( $row->log_params );
@@ -139,25 +145,52 @@ class PopulateLogSearch extends LoggedUpdateMaintenance {
$log = new LogPage( $row->log_type );
// Add item relations...
$log->addRelations( 'log_id', $items, $row->log_id );
- // Add item author relations...
- $userIds = $userIPs = [];
- $sres = $db->select( 'logging',
- [ 'log_user', 'log_user_text' ],
- [ 'log_id' => $items ]
- );
- foreach ( $sres as $srow ) {
- if ( $srow->log_user > 0 ) {
- $userIds[] = intval( $srow->log_user );
- } elseif ( IP::isIPAddress( $srow->log_user_text ) ) {
- $userIPs[] = $srow->log_user_text;
+ // Query item author relations...
+ $fields = [];
+ if ( $wgActorTableSchemaMigrationStage < MIGRATION_NEW ) {
+ $fields['userid'] = 'log_user';
+ $fields['username'] = 'log_user_text';
+ }
+ if ( $wgActorTableSchemaMigrationStage > MIGRATION_OLD ) {
+ $fields['actorid'] = 'log_actor';
+ }
+
+ $sres = $db->select( 'logging', $fields, [ 'log_id' => $items ], __METHOD__ );
+ } else {
+ continue;
+ }
+
+ // Add item author relations...
+ $userIds = $userIPs = $userActors = [];
+ foreach ( $sres as $srow ) {
+ if ( $wgActorTableSchemaMigrationStage < MIGRATION_NEW ) {
+ if ( $srow->userid > 0 ) {
+ $userIds[] = intval( $srow->userid );
+ } elseif ( $srow->username != '' ) {
+ $userIPs[] = $srow->username;
}
}
+ if ( $wgActorTableSchemaMigrationStage > MIGRATION_OLD ) {
+ if ( $srow->actorid ) {
+ $userActors[] = intval( $srow->actorid );
+ } elseif ( $srow->userid > 0 ) {
+ $userActors[] = User::newFromId( $srow->userid )->getActorId( $db );
+ } else {
+ $userActors[] = User::newFromName( $srow->username, false )->getActorId( $db );
+ }
+ }
+ }
+ // Add item author relations...
+ if ( $wgActorTableSchemaMigrationStage <= MIGRATION_WRITE_BOTH ) {
$log->addRelations( 'target_author_id', $userIds, $row->log_id );
$log->addRelations( 'target_author_ip', $userIPs, $row->log_id );
}
+ if ( $wgActorTableSchemaMigrationStage >= MIGRATION_WRITE_BOTH ) {
+ $log->addRelations( 'target_author_actor', $userActors, $row->log_id );
+ }
}
- $blockStart += $this->mBatchSize;
- $blockEnd += $this->mBatchSize;
+ $blockStart += $batchSize;
+ $blockEnd += $batchSize;
wfWaitForSlaves();
}
$this->output( "Done populating log_search table.\n" );
@@ -166,5 +199,5 @@ class PopulateLogSearch extends LoggedUpdateMaintenance {
}
}
-$maintClass = "PopulateLogSearch";
+$maintClass = PopulateLogSearch::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/populateLogUsertext.php b/www/wiki/maintenance/populateLogUsertext.php
index dd120fe0..3c0bba97 100644
--- a/www/wiki/maintenance/populateLogUsertext.php
+++ b/www/wiki/maintenance/populateLogUsertext.php
@@ -48,22 +48,32 @@ class PopulateLogUsertext extends LoggedUpdateMaintenance {
}
protected function doDBUpdates() {
+ $batchSize = $this->getBatchSize();
$db = $this->getDB( DB_MASTER );
- $start = $db->selectField( 'logging', 'MIN(log_id)', false, __METHOD__ );
+ $start = $db->selectField( 'logging', 'MIN(log_id)', '', __METHOD__ );
if ( !$start ) {
$this->output( "Nothing to do.\n" );
return true;
}
- $end = $db->selectField( 'logging', 'MAX(log_id)', false, __METHOD__ );
+ $end = $db->selectField( 'logging', 'MAX(log_id)', '', __METHOD__ );
+
+ // If this is being run during an upgrade from 1.16 or earlier, this
+ // will be run before the actor table change and should continue. But
+ // if it's being run on a new installation, the field won't exist to be populated.
+ if ( !$db->fieldInfo( 'logging', 'log_user_text' ) ) {
+ $this->output( "No log_user_text field, nothing to do.\n" );
+ return true;
+ }
# Do remaining chunk
- $end += $this->mBatchSize - 1;
+ $end += $batchSize - 1;
$blockStart = $start;
- $blockEnd = $start + $this->mBatchSize - 1;
+ $blockEnd = $start + $batchSize - 1;
while ( $blockEnd <= $end ) {
$this->output( "...doing log_id from $blockStart to $blockEnd\n" );
- $cond = "log_id BETWEEN $blockStart AND $blockEnd AND log_user = user_id";
+ $cond = "log_id BETWEEN " . (int)$blockStart . " AND " . (int)$blockEnd .
+ " AND log_user = user_id";
$res = $db->select( [ 'logging', 'user' ],
[ 'log_id', 'user_name' ], $cond, __METHOD__ );
@@ -73,9 +83,8 @@ class PopulateLogUsertext extends LoggedUpdateMaintenance {
[ 'log_id' => $row->log_id ], __METHOD__ );
}
$this->commitTransaction( $db, __METHOD__ );
- $blockStart += $this->mBatchSize;
- $blockEnd += $this->mBatchSize;
- wfWaitForSlaves();
+ $blockStart += $batchSize;
+ $blockEnd += $batchSize;
}
$this->output( "Done populating log_user_text field.\n" );
@@ -83,5 +92,5 @@ class PopulateLogUsertext extends LoggedUpdateMaintenance {
}
}
-$maintClass = "PopulateLogUsertext";
+$maintClass = PopulateLogUsertext::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/populatePPSortKey.php b/www/wiki/maintenance/populatePPSortKey.php
index 7e3c2c3d..1ba70549 100644
--- a/www/wiki/maintenance/populatePPSortKey.php
+++ b/www/wiki/maintenance/populatePPSortKey.php
@@ -23,8 +23,6 @@
require_once __DIR__ . '/Maintenance.php';
-use Wikimedia\Rdbms\IDatabase;
-
/**
* Usage:
* populatePPSortKey.php
@@ -59,7 +57,7 @@ class PopulatePPSortKey extends LoggedUpdateMaintenance {
__METHOD__,
[
'ORDER BY' => 'pp_page, pp_propname',
- 'LIMIT' => $this->mBatchSize
+ 'LIMIT' => $this->getBatchSize()
]
);
@@ -102,5 +100,5 @@ class PopulatePPSortKey extends LoggedUpdateMaintenance {
}
}
-$maintClass = 'PopulatePPSortKey';
+$maintClass = PopulatePPSortKey::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/populateParentId.php b/www/wiki/maintenance/populateParentId.php
index 457033a4..2ef58b7c 100644
--- a/www/wiki/maintenance/populateParentId.php
+++ b/www/wiki/maintenance/populateParentId.php
@@ -46,6 +46,7 @@ class PopulateParentId extends LoggedUpdateMaintenance {
}
protected function doDBUpdates() {
+ $batchSize = $this->getBatchSize();
$db = $this->getDB( DB_MASTER );
if ( !$db->tableExists( 'revision' ) ) {
$this->error( "revision table does not exist" );
@@ -53,8 +54,8 @@ class PopulateParentId extends LoggedUpdateMaintenance {
return false;
}
$this->output( "Populating rev_parent_id column\n" );
- $start = $db->selectField( 'revision', 'MIN(rev_id)', false, __FUNCTION__ );
- $end = $db->selectField( 'revision', 'MAX(rev_id)', false, __FUNCTION__ );
+ $start = $db->selectField( 'revision', 'MIN(rev_id)', '', __FUNCTION__ );
+ $end = $db->selectField( 'revision', 'MAX(rev_id)', '', __FUNCTION__ );
if ( is_null( $start ) || is_null( $end ) ) {
$this->output( "...revision table seems to be empty, nothing to do.\n" );
@@ -62,7 +63,7 @@ class PopulateParentId extends LoggedUpdateMaintenance {
}
# Do remaining chunk
$blockStart = intval( $start );
- $blockEnd = intval( $start ) + $this->mBatchSize - 1;
+ $blockEnd = intval( $start ) + $batchSize - 1;
$count = 0;
$changed = 0;
while ( $blockStart <= $end ) {
@@ -116,8 +117,8 @@ class PopulateParentId extends LoggedUpdateMaintenance {
__METHOD__ );
$count++;
}
- $blockStart += $this->mBatchSize;
- $blockEnd += $this->mBatchSize;
+ $blockStart += $batchSize;
+ $blockEnd += $batchSize;
wfWaitForSlaves();
}
$this->output( "rev_parent_id population complete ... {$count} rows [{$changed} changed]\n" );
@@ -126,5 +127,5 @@ class PopulateParentId extends LoggedUpdateMaintenance {
}
}
-$maintClass = "PopulateParentId";
+$maintClass = PopulateParentId::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/populateRecentChangesSource.php b/www/wiki/maintenance/populateRecentChangesSource.php
index 5d5da89a..8a56d7d8 100644
--- a/www/wiki/maintenance/populateRecentChangesSource.php
+++ b/www/wiki/maintenance/populateRecentChangesSource.php
@@ -41,32 +41,31 @@ class PopulateRecentChangesSource extends LoggedUpdateMaintenance {
protected function doDBUpdates() {
$dbw = $this->getDB( DB_MASTER );
+ $batchSize = $this->getBatchSize();
if ( !$dbw->fieldExists( 'recentchanges', 'rc_source' ) ) {
$this->error( 'rc_source field in recentchanges table does not exist.' );
}
- $start = $dbw->selectField( 'recentchanges', 'MIN(rc_id)', false, __METHOD__ );
+ $start = $dbw->selectField( 'recentchanges', 'MIN(rc_id)', '', __METHOD__ );
if ( !$start ) {
$this->output( "Nothing to do.\n" );
return true;
}
- $end = $dbw->selectField( 'recentchanges', 'MAX(rc_id)', false, __METHOD__ );
- $end += $this->mBatchSize - 1;
+ $end = $dbw->selectField( 'recentchanges', 'MAX(rc_id)', '', __METHOD__ );
+ $end += $batchSize - 1;
$blockStart = $start;
- $blockEnd = $start + $this->mBatchSize - 1;
+ $blockEnd = $start + $batchSize - 1;
$updatedValues = $this->buildUpdateCondition( $dbw );
while ( $blockEnd <= $end ) {
- $cond = "rc_id BETWEEN $blockStart AND $blockEnd";
-
$dbw->update(
'recentchanges',
[ $updatedValues ],
[
"rc_source = ''",
- "rc_id BETWEEN $blockStart AND $blockEnd"
+ "rc_id BETWEEN " . (int)$blockStart . " AND " . (int)$blockEnd
],
__METHOD__
);
@@ -74,8 +73,8 @@ class PopulateRecentChangesSource extends LoggedUpdateMaintenance {
$this->output( "." );
wfWaitForSlaves();
- $blockStart += $this->mBatchSize;
- $blockEnd += $this->mBatchSize;
+ $blockStart += $batchSize;
+ $blockEnd += $batchSize;
}
$this->output( "\nDone.\n" );
@@ -105,5 +104,5 @@ class PopulateRecentChangesSource extends LoggedUpdateMaintenance {
}
}
-$maintClass = "PopulateRecentChangesSource";
+$maintClass = PopulateRecentChangesSource::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/populateRevisionLength.php b/www/wiki/maintenance/populateRevisionLength.php
index a9457c2a..dcb89d19 100644
--- a/www/wiki/maintenance/populateRevisionLength.php
+++ b/www/wiki/maintenance/populateRevisionLength.php
@@ -21,6 +21,8 @@
* @ingroup Maintenance
*/
+use Wikimedia\Rdbms\IDatabase;
+
require_once __DIR__ . '/Maintenance.php';
/**
@@ -44,9 +46,9 @@ class PopulateRevisionLength extends LoggedUpdateMaintenance {
public function doDBUpdates() {
$dbw = $this->getDB( DB_MASTER );
if ( !$dbw->tableExists( 'revision' ) ) {
- $this->error( "revision table does not exist", true );
+ $this->fatalError( "revision table does not exist" );
} elseif ( !$dbw->tableExists( 'archive' ) ) {
- $this->error( "archive table does not exist", true );
+ $this->fatalError( "archive table does not exist" );
} elseif ( !$dbw->fieldExists( 'revision', 'rev_len', __METHOD__ ) ) {
$this->output( "rev_len column does not exist\n\n", true );
@@ -54,10 +56,10 @@ class PopulateRevisionLength extends LoggedUpdateMaintenance {
}
$this->output( "Populating rev_len column\n" );
- $rev = $this->doLenUpdates( 'revision', 'rev_id', 'rev', Revision::selectFields() );
+ $rev = $this->doLenUpdates( 'revision', 'rev_id', 'rev', Revision::getQueryInfo() );
$this->output( "Populating ar_len column\n" );
- $ar = $this->doLenUpdates( 'archive', 'ar_id', 'ar', Revision::selectArchiveFields() );
+ $ar = $this->doLenUpdates( 'archive', 'ar_id', 'ar', Revision::getArchiveQueryInfo() );
$this->output( "rev_len and ar_len population complete "
. "[$rev revision rows, $ar archive rows].\n" );
@@ -69,14 +71,15 @@ class PopulateRevisionLength extends LoggedUpdateMaintenance {
* @param string $table
* @param string $idCol
* @param string $prefix
- * @param array $fields
+ * @param array $queryInfo
* @return int
*/
- protected function doLenUpdates( $table, $idCol, $prefix, $fields ) {
+ protected function doLenUpdates( $table, $idCol, $prefix, $queryInfo ) {
$dbr = $this->getDB( DB_REPLICA );
$dbw = $this->getDB( DB_MASTER );
- $start = $dbw->selectField( $table, "MIN($idCol)", false, __METHOD__ );
- $end = $dbw->selectField( $table, "MAX($idCol)", false, __METHOD__ );
+ $batchSize = $this->getBatchSize();
+ $start = $dbw->selectField( $table, "MIN($idCol)", '', __METHOD__ );
+ $end = $dbw->selectField( $table, "MAX($idCol)", '', __METHOD__ );
if ( !$start || !$end ) {
$this->output( "...$table table seems to be empty.\n" );
@@ -85,20 +88,28 @@ class PopulateRevisionLength extends LoggedUpdateMaintenance {
# Do remaining chunks
$blockStart = intval( $start );
- $blockEnd = intval( $start ) + $this->mBatchSize - 1;
+ $blockEnd = intval( $start ) + $batchSize - 1;
$count = 0;
while ( $blockStart <= $end ) {
$this->output( "...doing $idCol from $blockStart to $blockEnd\n" );
$res = $dbr->select(
- $table,
- $fields,
+ $queryInfo['tables'],
+ $queryInfo['fields'],
[
"$idCol >= $blockStart",
"$idCol <= $blockEnd",
- "{$prefix}_len IS NULL"
+ $dbr->makeList( [
+ "{$prefix}_len IS NULL",
+ $dbr->makeList( [
+ "{$prefix}_len = 0",
+ "{$prefix}_sha1 != " . $dbr->addQuotes( 'phoiac9h4m842xq45sp7s6u21eteeq1' ), // sha1( "" )
+ ], IDatabase::LIST_AND )
+ ], IDatabase::LIST_OR )
],
- __METHOD__
+ __METHOD__,
+ [],
+ $queryInfo['joins']
);
if ( $res->numRows() > 0 ) {
@@ -112,9 +123,8 @@ class PopulateRevisionLength extends LoggedUpdateMaintenance {
$this->commitTransaction( $dbw, __METHOD__ );
}
- $blockStart += $this->mBatchSize;
- $blockEnd += $this->mBatchSize;
- wfWaitForSlaves();
+ $blockStart += $batchSize;
+ $blockEnd += $batchSize;
}
return $count;
@@ -134,7 +144,7 @@ class PopulateRevisionLength extends LoggedUpdateMaintenance {
? Revision::newFromArchiveRow( $row )
: new Revision( $row );
- $content = $rev->getContent();
+ $content = $rev->getContent( Revision::RAW );
if ( !$content ) {
# This should not happen, but sometimes does (T22757)
$id = $row->$idCol;
@@ -154,5 +164,5 @@ class PopulateRevisionLength extends LoggedUpdateMaintenance {
}
}
-$maintClass = "PopulateRevisionLength";
+$maintClass = PopulateRevisionLength::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/populateRevisionSha1.php b/www/wiki/maintenance/populateRevisionSha1.php
index fb97e910..9662044a 100644
--- a/www/wiki/maintenance/populateRevisionSha1.php
+++ b/www/wiki/maintenance/populateRevisionSha1.php
@@ -45,9 +45,9 @@ class PopulateRevisionSha1 extends LoggedUpdateMaintenance {
$db = $this->getDB( DB_MASTER );
if ( !$db->tableExists( 'revision' ) ) {
- $this->error( "revision table does not exist", true );
+ $this->fatalError( "revision table does not exist" );
} elseif ( !$db->tableExists( 'archive' ) ) {
- $this->error( "archive table does not exist", true );
+ $this->fatalError( "archive table does not exist" );
} elseif ( !$db->fieldExists( 'revision', 'rev_sha1', __METHOD__ ) ) {
$this->output( "rev_sha1 column does not exist\n\n", true );
@@ -55,10 +55,10 @@ class PopulateRevisionSha1 extends LoggedUpdateMaintenance {
}
$this->output( "Populating rev_sha1 column\n" );
- $rc = $this->doSha1Updates( 'revision', 'rev_id', 'rev' );
+ $rc = $this->doSha1Updates( 'revision', 'rev_id', Revision::getQueryInfo(), 'rev' );
$this->output( "Populating ar_sha1 column\n" );
- $ac = $this->doSha1Updates( 'archive', 'ar_rev_id', 'ar' );
+ $ac = $this->doSha1Updates( 'archive', 'ar_rev_id', Revision::getArchiveQueryInfo(), 'ar' );
$this->output( "Populating ar_sha1 column legacy rows\n" );
$ac += $this->doSha1LegacyUpdates();
@@ -71,13 +71,15 @@ class PopulateRevisionSha1 extends LoggedUpdateMaintenance {
/**
* @param string $table
* @param string $idCol
+ * @param array $queryInfo
* @param string $prefix
* @return int Rows changed
*/
- protected function doSha1Updates( $table, $idCol, $prefix ) {
+ protected function doSha1Updates( $table, $idCol, $queryInfo, $prefix ) {
$db = $this->getDB( DB_MASTER );
- $start = $db->selectField( $table, "MIN($idCol)", false, __METHOD__ );
- $end = $db->selectField( $table, "MAX($idCol)", false, __METHOD__ );
+ $batchSize = $this->getBatchSize();
+ $start = $db->selectField( $table, "MIN($idCol)", '', __METHOD__ );
+ $end = $db->selectField( $table, "MAX($idCol)", '', __METHOD__ );
if ( !$start || !$end ) {
$this->output( "...$table table seems to be empty.\n" );
@@ -86,14 +88,16 @@ class PopulateRevisionSha1 extends LoggedUpdateMaintenance {
$count = 0;
# Do remaining chunk
- $end += $this->mBatchSize - 1;
+ $end += $batchSize - 1;
$blockStart = $start;
- $blockEnd = $start + $this->mBatchSize - 1;
+ $blockEnd = $start + $batchSize - 1;
while ( $blockEnd <= $end ) {
$this->output( "...doing $idCol from $blockStart to $blockEnd\n" );
- $cond = "$idCol BETWEEN $blockStart AND $blockEnd
- AND $idCol IS NOT NULL AND {$prefix}_sha1 = ''";
- $res = $db->select( $table, '*', $cond, __METHOD__ );
+ $cond = "$idCol BETWEEN " . (int)$blockStart . " AND " . (int)$blockEnd .
+ " AND $idCol IS NOT NULL AND {$prefix}_sha1 = ''";
+ $res = $db->select(
+ $queryInfo['tables'], $queryInfo['fields'], $cond, __METHOD__, [], $queryInfo['joins']
+ );
$this->beginTransaction( $db, __METHOD__ );
foreach ( $res as $row ) {
@@ -103,9 +107,8 @@ class PopulateRevisionSha1 extends LoggedUpdateMaintenance {
}
$this->commitTransaction( $db, __METHOD__ );
- $blockStart += $this->mBatchSize;
- $blockEnd += $this->mBatchSize;
- wfWaitForSlaves();
+ $blockStart += $batchSize;
+ $blockEnd += $batchSize;
}
return $count;
@@ -117,8 +120,9 @@ class PopulateRevisionSha1 extends LoggedUpdateMaintenance {
protected function doSha1LegacyUpdates() {
$count = 0;
$db = $this->getDB( DB_MASTER );
- $res = $db->select( 'archive', '*',
- [ 'ar_rev_id IS NULL', 'ar_sha1' => '' ], __METHOD__ );
+ $arQuery = Revision::getArchiveQueryInfo();
+ $res = $db->select( $arQuery['tables'], $arQuery['fields'],
+ [ 'ar_rev_id IS NULL', 'ar_sha1' => '' ], __METHOD__, [], $arQuery['joins'] );
$updateSize = 0;
$this->beginTransaction( $db, __METHOD__ );
@@ -130,7 +134,6 @@ class PopulateRevisionSha1 extends LoggedUpdateMaintenance {
$updateSize = 0;
$this->commitTransaction( $db, __METHOD__ );
$this->output( "Commited row with ar_timestamp={$row->ar_timestamp}\n" );
- wfWaitForSlaves();
$this->beginTransaction( $db, __METHOD__ );
}
}
@@ -212,5 +215,5 @@ class PopulateRevisionSha1 extends LoggedUpdateMaintenance {
}
}
-$maintClass = "PopulateRevisionSha1";
+$maintClass = PopulateRevisionSha1::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/postgres/archives/patch-actor-table.sql b/www/wiki/maintenance/postgres/archives/patch-actor-table.sql
new file mode 100644
index 00000000..68e5d26b
--- /dev/null
+++ b/www/wiki/maintenance/postgres/archives/patch-actor-table.sql
@@ -0,0 +1,24 @@
+--
+-- patch-actor-table.sql
+--
+-- T167246. Add an `actor` table and various columns (and temporary tables) to reference it.
+
+CREATE SEQUENCE actor_actor_id_seq;
+CREATE TABLE actor (
+ actor_id INTEGER NOT NULL PRIMARY KEY DEFAULT nextval('actor_actor_id_seq'),
+ actor_user INTEGER,
+ actor_name TEXT NOT NULL
+);
+CREATE UNIQUE INDEX actor_user ON actor (actor_user);
+CREATE UNIQUE INDEX actor_name ON actor (actor_name);
+
+CREATE TABLE revision_actor_temp (
+ revactor_rev INTEGER NOT NULL,
+ revactor_actor INTEGER NOT NULL,
+ revactor_timestamp TIMESTAMPTZ NOT NULL,
+ revactor_page INTEGER NULL REFERENCES page (page_id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
+ PRIMARY KEY (revactor_rev, revactor_actor)
+);
+CREATE UNIQUE INDEX revactor_rev ON revision_actor_temp (revactor_rev);
+CREATE INDEX rev_actor_timestamp ON revision_actor_temp (revactor_actor,revactor_timestamp);
+CREATE INDEX rev_page_actor_timestamp ON revision_actor_temp (revactor_page,revactor_actor,revactor_timestamp);
diff --git a/www/wiki/maintenance/postgres/archives/patch-ar_rev_id-not-null.sql b/www/wiki/maintenance/postgres/archives/patch-ar_rev_id-not-null.sql
new file mode 100644
index 00000000..1a090e9c
--- /dev/null
+++ b/www/wiki/maintenance/postgres/archives/patch-ar_rev_id-not-null.sql
@@ -0,0 +1,3 @@
+-- T182678: Make ar_rev_id not nullable
+ALTER TABLE archive
+ ALTER COLUMN ar_rev_id SET NOT NULL;
diff --git a/www/wiki/maintenance/postgres/archives/patch-content-table.sql b/www/wiki/maintenance/postgres/archives/patch-content-table.sql
new file mode 100644
index 00000000..268db8bb
--- /dev/null
+++ b/www/wiki/maintenance/postgres/archives/patch-content-table.sql
@@ -0,0 +1,8 @@
+CREATE SEQUENCE content_content_id_seq;
+CREATE TABLE content (
+ content_id INTEGER NOT NULL PRIMARY KEY DEFAULT nextval('content_content_id_seq'),
+ content_size INTEGER NOT NULL,
+ content_sha1 TEXT NOT NULL,
+ content_model SMALLINT NOT NULL,
+ content_address TEXT NOT NULL
+);
diff --git a/www/wiki/maintenance/postgres/archives/patch-content_models-table.sql b/www/wiki/maintenance/postgres/archives/patch-content_models-table.sql
new file mode 100644
index 00000000..c2509d24
--- /dev/null
+++ b/www/wiki/maintenance/postgres/archives/patch-content_models-table.sql
@@ -0,0 +1,7 @@
+CREATE SEQUENCE content_models_model_id_seq;
+CREATE TABLE content_models (
+ model_id SMALLINT NOT NULL PRIMARY KEY DEFAULT nextval('content_models_model_id_seq'),
+ model_name TEXT NOT NULL
+);
+
+CREATE UNIQUE INDEX model_name ON content_models (model_name); \ No newline at end of file
diff --git a/www/wiki/maintenance/postgres/archives/patch-drop-ar_text.sql b/www/wiki/maintenance/postgres/archives/patch-drop-ar_text.sql
new file mode 100644
index 00000000..bd0a6b81
--- /dev/null
+++ b/www/wiki/maintenance/postgres/archives/patch-drop-ar_text.sql
@@ -0,0 +1,8 @@
+-- T33223: Remove obsolete ar_text and ar_flags columns
+-- (and make ar_text_id not nullable and default 0)
+
+ALTER TABLE archive
+ DROP COLUMN ar_text,
+ DROP COLUMN ar_flags,
+ ALTER COLUMN ar_text_id SET DEFAULT 0,
+ ALTER COLUMN ar_text_id SET NOT NULL;
diff --git a/www/wiki/maintenance/postgres/archives/patch-site_stats-modify.sql b/www/wiki/maintenance/postgres/archives/patch-site_stats-modify.sql
new file mode 100644
index 00000000..1c784d9b
--- /dev/null
+++ b/www/wiki/maintenance/postgres/archives/patch-site_stats-modify.sql
@@ -0,0 +1,7 @@
+ALTER TABLE /*_*/site_stats
+ ALTER ss_total_edits SET DEFAULT NULL,
+ ALTER ss_good_articles SET DEFAULT NULL,
+ ALTER ss_total_pages SET DEFAULT NULL,
+ ALTER ss_users SET DEFAULT NULL,
+ ALTER ss_active_users SET DEFAULT NULL,
+ ALTER ss_images SET DEFAULT NULL;
diff --git a/www/wiki/maintenance/postgres/archives/patch-slot_roles-table.sql b/www/wiki/maintenance/postgres/archives/patch-slot_roles-table.sql
new file mode 100644
index 00000000..3e71abaf
--- /dev/null
+++ b/www/wiki/maintenance/postgres/archives/patch-slot_roles-table.sql
@@ -0,0 +1,7 @@
+CREATE SEQUENCE slot_roles_role_id_seq;
+CREATE TABLE slot_roles (
+ role_id SMALLINT NOT NULL PRIMARY KEY DEFAULT nextval('slot_roles_role_id_seq'),
+ role_name TEXT NOT NULL
+);
+
+CREATE UNIQUE INDEX role_name ON slot_roles (role_name); \ No newline at end of file
diff --git a/www/wiki/maintenance/postgres/archives/patch-slots-table.sql b/www/wiki/maintenance/postgres/archives/patch-slots-table.sql
new file mode 100644
index 00000000..514921f4
--- /dev/null
+++ b/www/wiki/maintenance/postgres/archives/patch-slots-table.sql
@@ -0,0 +1,9 @@
+CREATE TABLE slots (
+ slot_revision_id INTEGER NOT NULL,
+ slot_role_id SMALLINT NOT NULL,
+ slot_content_id INTEGER NOT NULL,
+ slot_origin INTEGER NOT NULL,
+ PRIMARY KEY (slot_revision_id, slot_role_id)
+);
+
+CREATE INDEX slot_revision_origin_role ON slots (slot_revision_id, slot_origin, slot_role_id);
diff --git a/www/wiki/maintenance/postgres/archives/patch-ts2pagetitle.sql b/www/wiki/maintenance/postgres/archives/patch-ts2pagetitle.sql
index 4ac985e3..a770c912 100644
--- a/www/wiki/maintenance/postgres/archives/patch-ts2pagetitle.sql
+++ b/www/wiki/maintenance/postgres/archives/patch-ts2pagetitle.sql
@@ -4,9 +4,9 @@ LANGUAGE plpgsql AS
$mw$
BEGIN
IF TG_OP = 'INSERT' THEN
- NEW.titlevector = to_tsvector('default',REPLACE(NEW.page_title,'/',' '));
+ NEW.titlevector = to_tsvector(REPLACE(NEW.page_title,'/',' '));
ELSIF NEW.page_title != OLD.page_title THEN
- NEW.titlevector := to_tsvector('default',REPLACE(NEW.page_title,'/',' '));
+ NEW.titlevector := to_tsvector(REPLACE(NEW.page_title,'/',' '));
END IF;
RETURN NEW;
END;
diff --git a/www/wiki/maintenance/postgres/tables.sql b/www/wiki/maintenance/postgres/tables.sql
index da9c8648..53026acf 100644
--- a/www/wiki/maintenance/postgres/tables.sql
+++ b/www/wiki/maintenance/postgres/tables.sql
@@ -10,6 +10,7 @@ BEGIN;
SET client_min_messages = 'ERROR';
DROP SEQUENCE IF EXISTS user_user_id_seq CASCADE;
+DROP SEQUENCE IF EXISTS actor_actor_id_seq CASCADE;
DROP SEQUENCE IF EXISTS page_page_id_seq CASCADE;
DROP SEQUENCE IF EXISTS revision_rev_id_seq CASCADE;
DROP SEQUENCE IF EXISTS comment_comment_id_seq CASCADE;
@@ -52,12 +53,23 @@ CREATE TABLE mwuser ( -- replace reserved word 'user'
user_editcount INTEGER,
user_password_expires TIMESTAMPTZ NULL
);
+ALTER SEQUENCE user_user_id_seq OWNED BY mwuser.user_id;
CREATE INDEX user_email_token_idx ON mwuser (user_email_token);
-- Create a dummy user to satisfy fk contraints especially with revisions
INSERT INTO mwuser
VALUES (DEFAULT,'Anonymous','',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,now(),now());
+CREATE SEQUENCE actor_actor_id_seq;
+CREATE TABLE actor (
+ actor_id INTEGER NOT NULL PRIMARY KEY DEFAULT nextval('actor_actor_id_seq'),
+ actor_user INTEGER,
+ actor_name TEXT NOT NULL
+);
+ALTER SEQUENCE actor_actor_id_seq OWNED BY actor.actor_id;
+CREATE UNIQUE INDEX actor_user ON actor (actor_user);
+CREATE UNIQUE INDEX actor_name ON actor (actor_name);
+
CREATE TABLE user_groups (
ug_user INTEGER NULL REFERENCES mwuser(user_id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
ug_group TEXT NOT NULL,
@@ -107,6 +119,7 @@ CREATE TABLE page (
page_content_model TEXT,
page_lang TEXT DEFAULT NULL
);
+ALTER SEQUENCE page_page_id_seq OWNED BY page.page_id;
CREATE UNIQUE INDEX page_unique_name ON page (page_namespace, page_title);
CREATE INDEX page_main_title ON page (page_title text_pattern_ops) WHERE page_namespace = 0;
CREATE INDEX page_talk_title ON page (page_title text_pattern_ops) WHERE page_namespace = 1;
@@ -134,8 +147,8 @@ CREATE TABLE revision (
rev_page INTEGER NULL REFERENCES page (page_id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
rev_text_id INTEGER NULL, -- FK
rev_comment TEXT NOT NULL DEFAULT '',
- rev_user INTEGER NOT NULL REFERENCES mwuser(user_id) ON DELETE RESTRICT DEFERRABLE INITIALLY DEFERRED,
- rev_user_text TEXT NOT NULL,
+ rev_user INTEGER NOT NULL DEFAULT 0 REFERENCES mwuser(user_id) ON DELETE RESTRICT DEFERRABLE INITIALLY DEFERRED,
+ rev_user_text TEXT NOT NULL DEFAULT '',
rev_timestamp TIMESTAMPTZ NOT NULL,
rev_minor_edit SMALLINT NOT NULL DEFAULT 0,
rev_deleted SMALLINT NOT NULL DEFAULT 0,
@@ -145,6 +158,7 @@ CREATE TABLE revision (
rev_content_model TEXT,
rev_content_format TEXT
);
+ALTER SEQUENCE revision_rev_id_seq OWNED BY revision.rev_id;
CREATE UNIQUE INDEX revision_unique ON revision (rev_page, rev_id);
CREATE INDEX rev_text_id_idx ON revision (rev_text_id);
CREATE INDEX rev_timestamp_idx ON revision (rev_timestamp);
@@ -158,14 +172,24 @@ CREATE TABLE revision_comment_temp (
);
CREATE UNIQUE INDEX revcomment_rev ON revision_comment_temp (revcomment_rev);
-CREATE SEQUENCE ip_changes_ipc_rev_id_seq;
+CREATE TABLE revision_actor_temp (
+ revactor_rev INTEGER NOT NULL,
+ revactor_actor INTEGER NOT NULL,
+ revactor_timestamp TIMESTAMPTZ NOT NULL,
+ revactor_page INTEGER NULL REFERENCES page (page_id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
+ PRIMARY KEY (revactor_rev, revactor_actor)
+);
+CREATE UNIQUE INDEX revactor_rev ON revision_actor_temp (revactor_rev);
+CREATE INDEX rev_actor_timestamp ON revision_actor_temp (revactor_actor,revactor_timestamp);
+CREATE INDEX rev_page_actor_timestamp ON revision_actor_temp (revactor_page,revactor_actor,revactor_timestamp);
+CREATE SEQUENCE ip_changes_ipc_rev_id_seq;
CREATE TABLE ip_changes (
ipc_rev_id INTEGER PRIMARY KEY NOT NULL DEFAULT nextval('ip_changes_ipc_rev_id_seq'),
ipc_rev_timestamp TIMESTAMPTZ NOT NULL,
ipc_hex BYTEA NOT NULL DEFAULT ''
);
-
+ALTER SEQUENCE ip_changes_ipc_rev_id_seq OWNED BY ip_changes.ipc_rev_id;
CREATE INDEX ipc_rev_timestamp ON ip_changes (ipc_rev_timestamp);
CREATE INDEX ipc_hex_time ON ip_changes (ipc_hex,ipc_rev_timestamp);
@@ -175,6 +199,7 @@ CREATE TABLE pagecontent ( -- replaces reserved word 'text'
old_text TEXT,
old_flags TEXT
);
+ALTER SEQUENCE text_old_id_seq OWNED BY pagecontent.old_id;
CREATE SEQUENCE comment_comment_id_seq;
@@ -184,6 +209,7 @@ CREATE TABLE comment (
comment_text TEXT NOT NULL,
comment_data TEXT
);
+ALTER SEQUENCE comment_comment_id_seq OWNED BY comment.comment_id;
CREATE INDEX comment_hash ON comment (comment_hash);
@@ -197,6 +223,7 @@ CREATE TABLE page_restrictions (
pr_user INTEGER NULL,
pr_expiry TIMESTAMPTZ NULL
);
+ALTER SEQUENCE page_restrictions_pr_id_seq OWNED BY page_restrictions.pr_id;
ALTER TABLE page_restrictions ADD CONSTRAINT page_restrictions_pk PRIMARY KEY (pr_page,pr_type);
CREATE TABLE page_props (
@@ -215,26 +242,69 @@ CREATE TABLE archive (
ar_id INTEGER NOT NULL PRIMARY KEY DEFAULT nextval('archive_ar_id_seq'),
ar_namespace SMALLINT NOT NULL,
ar_title TEXT NOT NULL,
- ar_text TEXT, -- technically should be bytea, but not used anymore
ar_page_id INTEGER NULL,
ar_parent_id INTEGER NULL,
ar_sha1 TEXT NOT NULL DEFAULT '',
ar_comment TEXT NOT NULL DEFAULT '',
ar_comment_id INTEGER NOT NULL DEFAULT 0,
- ar_user INTEGER NULL REFERENCES mwuser(user_id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED,
- ar_user_text TEXT NOT NULL,
+ ar_user INTEGER NOT NULL DEFAULT 0 REFERENCES mwuser(user_id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED,
+ ar_user_text TEXT NOT NULL DEFAULT '',
+ ar_actor INTEGER NOT NULL DEFAULT 0,
ar_timestamp TIMESTAMPTZ NOT NULL,
ar_minor_edit SMALLINT NOT NULL DEFAULT 0,
- ar_flags TEXT,
- ar_rev_id INTEGER,
- ar_text_id INTEGER,
+ ar_rev_id INTEGER NOT NULL,
+ ar_text_id INTEGER NOT NULL DEFAULT 0,
ar_deleted SMALLINT NOT NULL DEFAULT 0,
ar_len INTEGER NULL,
ar_content_model TEXT,
ar_content_format TEXT
);
+ALTER SEQUENCE archive_ar_id_seq OWNED BY archive.ar_id;
CREATE INDEX archive_name_title_timestamp ON archive (ar_namespace,ar_title,ar_timestamp);
CREATE INDEX archive_user_text ON archive (ar_user_text);
+CREATE INDEX archive_actor ON archive (ar_actor);
+
+
+CREATE TABLE slots (
+ slot_revision_id INTEGER NOT NULL,
+ slot_role_id SMALLINT NOT NULL,
+ slot_content_id INTEGER NOT NULL,
+ slot_origin INTEGER NOT NULL,
+ PRIMARY KEY (slot_revision_id, slot_role_id)
+);
+
+CREATE INDEX slot_revision_origin_role ON slots (slot_revision_id, slot_origin, slot_role_id);
+
+
+CREATE SEQUENCE content_content_id_seq;
+CREATE TABLE content (
+ content_id INTEGER NOT NULL PRIMARY KEY DEFAULT nextval('content_content_id_seq'),
+ content_size INTEGER NOT NULL,
+ content_sha1 TEXT NOT NULL,
+ content_model SMALLINT NOT NULL,
+ content_address TEXT NOT NULL
+);
+ALTER SEQUENCE content_content_id_seq OWNED BY content.content_id;
+
+
+CREATE SEQUENCE slot_roles_role_id_seq;
+CREATE TABLE slot_roles (
+ role_id SMALLINT NOT NULL PRIMARY KEY DEFAULT nextval('slot_roles_role_id_seq'),
+ role_name TEXT NOT NULL
+);
+ALTER SEQUENCE slot_roles_role_id_seq OWNED BY slot_roles.role_id;
+
+CREATE UNIQUE INDEX role_name ON slot_roles (role_name);
+
+
+CREATE SEQUENCE content_models_model_id_seq;
+CREATE TABLE content_models (
+ model_id SMALLINT NOT NULL PRIMARY KEY DEFAULT nextval('content_models_model_id_seq'),
+ model_name TEXT NOT NULL
+);
+ALTER SEQUENCE content_models_model_id_seq OWNED BY content_models.model_id;
+
+CREATE UNIQUE INDEX model_name ON content_models (model_name);
CREATE TABLE redirect (
@@ -292,6 +362,7 @@ CREATE TABLE externallinks (
el_index TEXT NOT NULL,
el_index_60 BYTEA NOT NULL DEFAULT ''
);
+ALTER SEQUENCE externallinks_el_id_seq OWNED BY externallinks.el_id;
CREATE INDEX externallinks_from_to ON externallinks (el_from,el_to);
CREATE INDEX externallinks_index ON externallinks (el_index);
CREATE INDEX el_index_60 ON externallinks (el_index_60, el_id);
@@ -308,13 +379,13 @@ CREATE INDEX langlinks_lang_title ON langlinks (ll_lang,ll_title);
CREATE TABLE site_stats (
ss_row_id INTEGER NOT NULL PRIMARY KEY DEFAULT 0,
- ss_total_edits INTEGER DEFAULT 0,
- ss_good_articles INTEGER DEFAULT 0,
- ss_total_pages INTEGER DEFAULT -1,
- ss_users INTEGER DEFAULT -1,
- ss_active_users INTEGER DEFAULT -1,
- ss_admins INTEGER DEFAULT -1,
- ss_images INTEGER DEFAULT 0
+ ss_total_edits INTEGER DEFAULT NULL,
+ ss_good_articles INTEGER DEFAULT NULL,
+ ss_total_pages INTEGER DEFAULT NULL,
+ ss_users INTEGER DEFAULT NULL,
+ ss_active_users INTEGER DEFAULT NULL,
+ ss_admins INTEGER DEFAULT NULL,
+ ss_images INTEGER DEFAULT NULL
);
@@ -323,8 +394,9 @@ CREATE TABLE ipblocks (
ipb_id INTEGER NOT NULL PRIMARY KEY DEFAULT nextval('ipblocks_ipb_id_seq'),
ipb_address TEXT NULL,
ipb_user INTEGER NULL REFERENCES mwuser(user_id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED,
- ipb_by INTEGER NOT NULL REFERENCES mwuser(user_id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
+ ipb_by INTEGER NOT NULL DEFAULT 0 REFERENCES mwuser(user_id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
ipb_by_text TEXT NOT NULL DEFAULT '',
+ ipb_by_actor INTEGER NOT NULL DEFAULT 0,
ipb_reason TEXT NOT NULL DEFAULT '',
ipb_reason_id INTEGER NOT NULL DEFAULT 0,
ipb_timestamp TIMESTAMPTZ NOT NULL,
@@ -339,8 +411,8 @@ CREATE TABLE ipblocks (
ipb_block_email SMALLINT NOT NULL DEFAULT 0,
ipb_allow_usertalk SMALLINT NOT NULL DEFAULT 0,
ipb_parent_block_id INTEGER NULL REFERENCES ipblocks(ipb_id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED
-
);
+ALTER SEQUENCE ipblocks_ipb_id_seq OWNED BY ipblocks.ipb_id;
CREATE UNIQUE INDEX ipb_address_unique ON ipblocks (ipb_address,ipb_user,ipb_auto,ipb_anon_only);
CREATE INDEX ipb_user ON ipblocks (ipb_user);
CREATE INDEX ipb_range ON ipblocks (ipb_range_start,ipb_range_end);
@@ -358,8 +430,10 @@ CREATE TABLE image (
img_major_mime TEXT DEFAULT 'unknown',
img_minor_mime TEXT DEFAULT 'unknown',
img_description TEXT NOT NULL DEFAULT '',
- img_user INTEGER NULL REFERENCES mwuser(user_id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED,
- img_user_text TEXT NOT NULL,
+ img_description_id INTEGER NOT NULL DEFAULT 0,
+ img_user INTEGER NOT NULL DEFAULT 0 REFERENCES mwuser(user_id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED,
+ img_user_text TEXT NOT NULL DEFAULT '',
+ img_actor INTEGER NOT NULL DEFAULT 0,
img_timestamp TIMESTAMPTZ,
img_sha1 TEXT NOT NULL DEFAULT ''
);
@@ -383,8 +457,9 @@ CREATE TABLE oldimage (
oi_bits SMALLINT NULL,
oi_description TEXT NOT NULL DEFAULT '',
oi_description_id INTEGER NOT NULL DEFAULT 0,
- oi_user INTEGER NULL REFERENCES mwuser(user_id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED,
- oi_user_text TEXT NOT NULL,
+ oi_user INTEGER NOT NULL DEFAULT 0 REFERENCES mwuser(user_id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED,
+ oi_user_text TEXT NOT NULL DEFAULT '',
+ oi_actor INTEGER NOT NULL DEFAULT 0,
oi_timestamp TIMESTAMPTZ NULL,
oi_metadata BYTEA NOT NULL DEFAULT '',
oi_media_type TEXT NULL,
@@ -420,12 +495,14 @@ CREATE TABLE filearchive (
fa_minor_mime TEXT DEFAULT 'unknown',
fa_description TEXT NOT NULL DEFAULT '',
fa_description_id INTEGER NOT NULL DEFAULT 0,
- fa_user INTEGER NULL REFERENCES mwuser(user_id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED,
- fa_user_text TEXT NOT NULL,
+ fa_user INTEGER NOT NULL DEFAULT 0 REFERENCES mwuser(user_id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED,
+ fa_user_text TEXT NOT NULL DEFAULT '',
+ fa_actor INTEGER NOT NULL DEFAULT 0,
fa_timestamp TIMESTAMPTZ,
fa_deleted SMALLINT NOT NULL DEFAULT 0,
fa_sha1 TEXT NOT NULL DEFAULT ''
);
+ALTER SEQUENCE filearchive_fa_id_seq OWNED BY filearchive.fa_id;
CREATE INDEX fa_name_time ON filearchive (fa_name, fa_timestamp);
CREATE INDEX fa_dupe ON filearchive (fa_storage_group, fa_storage_key);
CREATE INDEX fa_notime ON filearchive (fa_deleted_timestamp);
@@ -434,7 +511,6 @@ CREATE INDEX fa_sha1 ON filearchive (fa_sha1);
CREATE SEQUENCE uploadstash_us_id_seq;
CREATE TYPE media_type AS ENUM ('UNKNOWN','BITMAP','DRAWING','AUDIO','VIDEO','MULTIMEDIA','OFFICE','TEXT','EXECUTABLE','ARCHIVE','3D');
-
CREATE TABLE uploadstash (
us_id INTEGER PRIMARY KEY NOT NULL DEFAULT nextval('uploadstash_us_id_seq'),
us_user INTEGER,
@@ -454,6 +530,7 @@ CREATE TABLE uploadstash (
us_image_height INTEGER,
us_image_bits SMALLINT
);
+ALTER SEQUENCE uploadstash_us_id_seq OWNED BY uploadstash.us_id;
CREATE INDEX us_user_idx ON uploadstash (us_user);
CREATE UNIQUE INDEX us_key_idx ON uploadstash (us_key);
@@ -465,8 +542,9 @@ CREATE TABLE recentchanges (
rc_id INTEGER NOT NULL PRIMARY KEY DEFAULT nextval('recentchanges_rc_id_seq'),
rc_timestamp TIMESTAMPTZ NOT NULL,
rc_cur_time TIMESTAMPTZ NULL,
- rc_user INTEGER NULL REFERENCES mwuser(user_id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED,
- rc_user_text TEXT NOT NULL,
+ rc_user INTEGER NOT NULL DEFAULT 0 REFERENCES mwuser(user_id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED,
+ rc_user_text TEXT NOT NULL DEFAULT '',
+ rc_actor INTEGER NOT NULL DEFAULT 0,
rc_namespace SMALLINT NOT NULL,
rc_title TEXT NOT NULL,
rc_comment TEXT NOT NULL DEFAULT '',
@@ -489,9 +567,10 @@ CREATE TABLE recentchanges (
rc_log_action TEXT,
rc_params TEXT
);
+ALTER SEQUENCE recentchanges_rc_id_seq OWNED BY recentchanges.rc_id;
CREATE INDEX rc_timestamp ON recentchanges (rc_timestamp);
CREATE INDEX rc_timestamp_bot ON recentchanges (rc_timestamp) WHERE rc_bot = 0;
-CREATE INDEX rc_namespace_title ON recentchanges (rc_namespace, rc_title);
+CREATE INDEX rc_namespace_title_timestamp ON recentchanges (rc_namespace, rc_title, rc_timestamp);
CREATE INDEX rc_cur_id ON recentchanges (rc_cur_id);
CREATE INDEX new_name_timestamp ON recentchanges (rc_new, rc_namespace, rc_timestamp);
CREATE INDEX rc_ip ON recentchanges (rc_ip);
@@ -506,6 +585,7 @@ CREATE TABLE watchlist (
wl_title TEXT NOT NULL,
wl_notificationtimestamp TIMESTAMPTZ
);
+ALTER SEQUENCE watchlist_wl_id_seq OWNED BY watchlist.wl_id;
CREATE UNIQUE INDEX wl_user_namespace_title ON watchlist (wl_namespace, wl_title, wl_user);
CREATE INDEX wl_user ON watchlist (wl_user);
CREATE INDEX wl_user_notificationtimestamp ON watchlist (wl_user, wl_notificationtimestamp);
@@ -566,7 +646,8 @@ CREATE TABLE logging (
log_type TEXT NOT NULL,
log_action TEXT NOT NULL,
log_timestamp TIMESTAMPTZ NOT NULL,
- log_user INTEGER REFERENCES mwuser(user_id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED,
+ log_user INTEGER NOT NULL DEFAULT 0 REFERENCES mwuser(user_id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED,
+ log_actor INTEGER NOT NULL DEFAULT 0,
log_namespace SMALLINT NOT NULL,
log_title TEXT NOT NULL,
log_comment TEXT NOT NULL DEFAULT '',
@@ -576,14 +657,18 @@ CREATE TABLE logging (
log_user_text TEXT NOT NULL DEFAULT '',
log_page INTEGER
);
+ALTER SEQUENCE logging_log_id_seq OWNED BY logging.log_id;
CREATE INDEX logging_type_name ON logging (log_type, log_timestamp);
CREATE INDEX logging_user_time ON logging (log_timestamp, log_user);
+CREATE INDEX logging_actor_time_backwards ON logging (log_timestamp, log_actor);
CREATE INDEX logging_page_time ON logging (log_namespace, log_title, log_timestamp);
CREATE INDEX logging_times ON logging (log_timestamp);
CREATE INDEX logging_user_type_time ON logging (log_user, log_type, log_timestamp);
+CREATE INDEX logging_actor_type_time ON logging (log_actor, log_type, log_timestamp);
CREATE INDEX logging_page_id_time ON logging (log_page, log_timestamp);
CREATE INDEX logging_user_text_type_time ON logging (log_user_text, log_type, log_timestamp);
CREATE INDEX logging_user_text_time ON logging (log_user_text, log_timestamp);
+CREATE INDEX logging_actor_time ON logging (log_actor, log_timestamp);
CREATE TABLE log_search (
ls_field TEXT NOT NULL,
@@ -608,6 +693,7 @@ CREATE TABLE job (
job_token_timestamp TIMESTAMPTZ,
job_sha1 TEXT NOT NULL DEFAULT ''
);
+ALTER SEQUENCE job_job_id_seq OWNED BY job.job_id;
CREATE INDEX job_sha1 ON job (job_sha1);
CREATE INDEX job_cmd_token ON job (job_cmd, job_token, job_random);
CREATE INDEX job_cmd_token_id ON job (job_cmd, job_token, job_id);
@@ -615,7 +701,6 @@ CREATE INDEX job_cmd_namespace_title ON job (job_cmd, job_namespace, job_title);
CREATE INDEX job_timestamp_idx ON job (job_timestamp);
-- Tsearch2 2 stuff. Will fail if we don't have proper access to the tsearch2 tables
--- Version 8.3 or higher only. Previous versions would need another parmeter for to_tsvector.
-- Make sure you also change patch-tsearch2funcs.sql if the funcs below change.
ALTER TABLE page ADD titlevector tsvector;
@@ -651,9 +736,6 @@ $mw$;
CREATE TRIGGER ts2_page_text BEFORE INSERT OR UPDATE ON pagecontent
FOR EACH ROW EXECUTE PROCEDURE ts2_page_text();
--- These are added by the setup script due to version compatibility issues
--- If using 8.1, we switch from "gin" to "gist"
-
CREATE INDEX ts2_page_title ON page USING gin(titlevector);
CREATE INDEX ts2_page_text ON pagecontent USING gin(textvector);
@@ -701,6 +783,7 @@ CREATE TABLE category (
cat_files INTEGER NOT NULL DEFAULT 0,
cat_hidden SMALLINT NOT NULL DEFAULT 0
);
+ALTER SEQUENCE category_cat_id_seq OWNED BY category.cat_id;
CREATE UNIQUE INDEX category_title ON category(cat_title);
CREATE INDEX category_pages ON category(cat_pages);
@@ -713,6 +796,7 @@ CREATE TABLE change_tag (
ct_tag TEXT NOT NULL,
ct_params TEXT NULL
);
+ALTER SEQUENCE change_tag_ct_id_seq OWNED BY change_tag.ct_id;
CREATE UNIQUE INDEX change_tag_rc_tag ON change_tag(ct_rc_id,ct_tag);
CREATE UNIQUE INDEX change_tag_log_tag ON change_tag(ct_log_id,ct_tag);
CREATE UNIQUE INDEX change_tag_rev_tag ON change_tag(ct_rev_id,ct_tag);
@@ -726,6 +810,7 @@ CREATE TABLE tag_summary (
ts_rev_id INTEGER NULL,
ts_tags TEXT NOT NULL
);
+ALTER SEQUENCE tag_summary_ts_id_seq OWNED BY tag_summary.ts_id;
CREATE UNIQUE INDEX tag_summary_rc_id ON tag_summary(ts_rc_id);
CREATE UNIQUE INDEX tag_summary_log_id ON tag_summary(ts_log_id);
CREATE UNIQUE INDEX tag_summary_rev_id ON tag_summary(ts_rev_id);
@@ -779,6 +864,7 @@ CREATE TABLE sites (
site_forward SMALLINT NOT NULL,
site_config TEXT NOT NULL
);
+ALTER SEQUENCE sites_site_id_seq OWNED BY sites.site_id;
CREATE UNIQUE INDEX site_global_key ON sites (site_global_key);
CREATE INDEX site_type ON sites (site_type);
CREATE INDEX site_group ON sites (site_group);
diff --git a/www/wiki/maintenance/preprocessDump.php b/www/wiki/maintenance/preprocessDump.php
index 17d97b05..d540e8f9 100644
--- a/www/wiki/maintenance/preprocessDump.php
+++ b/www/wiki/maintenance/preprocessDump.php
@@ -67,7 +67,7 @@ class PreprocessDump extends DumpIterator {
} elseif ( isset( $wgParserConf['preprocessorClass'] ) ) {
$name = $wgParserConf['preprocessorClass'];
} else {
- $name = 'Preprocessor_DOM';
+ $name = Preprocessor_DOM::class;
}
$wgParser->firstCallInit();
@@ -94,5 +94,5 @@ class PreprocessDump extends DumpIterator {
}
}
-$maintClass = "PreprocessDump";
+$maintClass = PreprocessDump::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/protect.php b/www/wiki/maintenance/protect.php
index f6bb2532..b47476a5 100644
--- a/www/wiki/maintenance/protect.php
+++ b/www/wiki/maintenance/protect.php
@@ -59,7 +59,7 @@ class Protect extends Maintenance {
$user = User::newFromName( $userName );
}
if ( !$user ) {
- $this->error( "Invalid username", true );
+ $this->fatalError( "Invalid username" );
}
// @todo FIXME: This is reset 7 lines down.
@@ -67,7 +67,7 @@ class Protect extends Maintenance {
$t = Title::newFromText( $this->getArg() );
if ( !$t ) {
- $this->error( "Invalid title", true );
+ $this->fatalError( "Invalid title" );
}
$restrictions = [];
@@ -89,5 +89,5 @@ class Protect extends Maintenance {
}
}
-$maintClass = "Protect";
+$maintClass = Protect::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/pruneFileCache.php b/www/wiki/maintenance/pruneFileCache.php
index 8e6978d5..74298cb9 100644
--- a/www/wiki/maintenance/pruneFileCache.php
+++ b/www/wiki/maintenance/pruneFileCache.php
@@ -43,25 +43,25 @@ class PruneFileCache extends Maintenance {
global $wgUseFileCache, $wgFileCacheDirectory;
if ( !$wgUseFileCache ) {
- $this->error( "Nothing to do -- \$wgUseFileCache is disabled.", true );
+ $this->fatalError( "Nothing to do -- \$wgUseFileCache is disabled." );
}
$age = $this->getOption( 'agedays' );
if ( !ctype_digit( $age ) ) {
- $this->error( "Non-integer 'age' parameter given.", true );
+ $this->fatalError( "Non-integer 'age' parameter given." );
}
// Delete items with a TS older than this
$this->minSurviveTimestamp = time() - ( 86400 * $age );
$dir = $wgFileCacheDirectory;
if ( !is_dir( $dir ) ) {
- $this->error( "Nothing to do -- \$wgFileCacheDirectory directory not found.", true );
+ $this->fatalError( "Nothing to do -- \$wgFileCacheDirectory directory not found." );
}
$subDir = $this->getOption( 'subdir' );
if ( $subDir !== null ) {
if ( !is_dir( "$dir/$subDir" ) ) {
- $this->error( "The specified subdirectory `$subDir` does not exist.", true );
+ $this->fatalError( "The specified subdirectory `$subDir` does not exist." );
}
$this->output( "Pruning `$dir/$subDir` directory...\n" );
$this->prune_directory( "$dir/$subDir", 'report' );
@@ -107,5 +107,5 @@ class PruneFileCache extends Maintenance {
}
}
-$maintClass = "PruneFileCache";
+$maintClass = PruneFileCache::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/purgeChangedFiles.php b/www/wiki/maintenance/purgeChangedFiles.php
index 3c0fc7e5..7d5d40b3 100644
--- a/www/wiki/maintenance/purgeChangedFiles.php
+++ b/www/wiki/maintenance/purgeChangedFiles.php
@@ -200,7 +200,7 @@ class PurgeChangedFiles extends Maintenance {
$this->verbose( "Purged file {$row->log_title}; {$type} @{$row->log_timestamp}.\n" );
- if ( $this->hasOption( 'sleep-per-batch' ) && ++$bSize > $this->mBatchSize ) {
+ if ( $this->hasOption( 'sleep-per-batch' ) && ++$bSize > $this->getBatchSize() ) {
$bSize = 0;
// sleep-per-batch is milliseconds, usleep wants micro seconds.
usleep( 1000 * (int)$this->getOption( 'sleep-per-batch' ) );
@@ -258,5 +258,5 @@ class PurgeChangedFiles extends Maintenance {
}
}
-$maintClass = "PurgeChangedFiles";
+$maintClass = PurgeChangedFiles::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/purgeChangedPages.php b/www/wiki/maintenance/purgeChangedPages.php
index cf65c693..22020e7d 100644
--- a/www/wiki/maintenance/purgeChangedPages.php
+++ b/www/wiki/maintenance/purgeChangedPages.php
@@ -79,7 +79,7 @@ class PurgeChangedPages extends Maintenance {
$stuckCount = 0; // loop breaker
while ( true ) {
// Adjust bach size if we are stuck in a second that had many changes
- $bSize = $this->mBatchSize + ( $stuckCount * $this->mBatchSize );
+ $bSize = ( $stuckCount + 1 ) * $this->getBatchSize();
$res = $dbr->select(
[ 'page', 'revision' ],
@@ -190,5 +190,5 @@ class PurgeChangedPages extends Maintenance {
}
}
-$maintClass = "PurgeChangedPages";
+$maintClass = PurgeChangedPages::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/purgeExpiredUserrights.php b/www/wiki/maintenance/purgeExpiredUserrights.php
new file mode 100644
index 00000000..ee40f5f4
--- /dev/null
+++ b/www/wiki/maintenance/purgeExpiredUserrights.php
@@ -0,0 +1,49 @@
+<?php
+/**
+ * Remove expired userrights from user_groups table and move them to former_user_groups
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @copyright GPLv2 http://www.gnu.org/copyleft/gpl.html
+ * @author Eddie Greiner-Petter <wikimedia.org at eddie-sh.de>
+ * @ingroup Maintenance
+ */
+
+require_once __DIR__ . '/Maintenance.php';
+
+/*
+ * Maintenance script to move expired userrights to user_former_groups
+ *
+ * @since 1.31
+ */
+
+class PurgeExpiredUserrights extends Maintenance {
+ public function __construct() {
+ parent::__construct();
+ $this->addDescription( 'Move expired userrights from user_groups to former_user_groups table.' );
+ }
+
+ public function execute() {
+ $this->output( "Purging expired user rights...\n" );
+ $res = UserGroupMembership::purgeExpired();
+ if ( $res === false ) {
+ $this->output( "Purging failed.\n" );
+ } else {
+ $this->output( "$res rows purged.\n" );
+ }
+ }
+}
+
+$maintClass = PurgeExpiredUserrights::class;
+require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/purgeList.php b/www/wiki/maintenance/purgeList.php
index 5ca7918e..16a62f40 100644
--- a/www/wiki/maintenance/purgeList.php
+++ b/www/wiki/maintenance/purgeList.php
@@ -99,7 +99,7 @@ class PurgeList extends Maintenance {
$conds + [ 'page_id > ' . $dbr->addQuotes( $startId ) ],
__METHOD__,
[
- 'LIMIT' => $this->mBatchSize,
+ 'LIMIT' => $this->getBatchSize(),
'ORDER BY' => 'page_id'
]
@@ -143,5 +143,5 @@ class PurgeList extends Maintenance {
}
}
-$maintClass = "PurgeList";
+$maintClass = PurgeList::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/purgeModuleDeps.php b/www/wiki/maintenance/purgeModuleDeps.php
index feeeb65b..3b256293 100644
--- a/www/wiki/maintenance/purgeModuleDeps.php
+++ b/www/wiki/maintenance/purgeModuleDeps.php
@@ -48,7 +48,7 @@ class PurgeModuleDeps extends Maintenance {
$modDeps = $dbw->tableName( 'module_deps' );
$i = 1;
- foreach ( array_chunk( $rows, $this->mBatchSize ) as $chunk ) {
+ foreach ( array_chunk( $rows, $this->getBatchSize() ) as $chunk ) {
// WHERE ( mod=A AND skin=A ) OR ( mod=A AND skin=B) ..
$conds = array_map( function ( stdClass $row ) use ( $dbw ) {
return $dbw->makeList( (array)$row, IDatabase::LIST_AND );
@@ -68,5 +68,5 @@ class PurgeModuleDeps extends Maintenance {
}
}
-$maintClass = 'PurgeModuleDeps';
+$maintClass = PurgeModuleDeps::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/purgeOldText.php b/www/wiki/maintenance/purgeOldText.php
index 1b78c7d9..65d25c98 100644
--- a/www/wiki/maintenance/purgeOldText.php
+++ b/www/wiki/maintenance/purgeOldText.php
@@ -41,5 +41,5 @@ class PurgeOldText extends Maintenance {
}
}
-$maintClass = "PurgeOldText";
+$maintClass = PurgeOldText::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/purgePage.php b/www/wiki/maintenance/purgePage.php
index 44d390ea..df1403c6 100644
--- a/www/wiki/maintenance/purgePage.php
+++ b/www/wiki/maintenance/purgePage.php
@@ -74,5 +74,5 @@ class PurgePage extends Maintenance {
}
}
-$maintClass = "PurgePage";
+$maintClass = PurgePage::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/purgeParserCache.php b/www/wiki/maintenance/purgeParserCache.php
index da2d850e..dcd6d13d 100644
--- a/www/wiki/maintenance/purgeParserCache.php
+++ b/www/wiki/maintenance/purgeParserCache.php
@@ -60,7 +60,7 @@ class PurgeParserCache extends Maintenance {
} elseif ( $inputAge !== null ) {
$date = wfTimestamp( TS_MW, time() + $wgParserCacheExpireTime - intval( $inputAge ) );
} else {
- $this->error( "Must specify either --expiredate or --age", 1 );
+ $this->fatalError( "Must specify either --expiredate or --age" );
return;
}
$this->usleep = 1e3 * $this->getOption( 'msleep', 0 );
@@ -72,7 +72,7 @@ class PurgeParserCache extends Maintenance {
$pc = MediaWikiServices::getInstance()->getParserCache()->getCacheStorage();
$success = $pc->deleteObjectsExpiringBefore( $date, [ $this, 'showProgressAndWait' ] );
if ( !$success ) {
- $this->error( "\nCannot purge this kind of parser cache.", 1 );
+ $this->fatalError( "\nCannot purge this kind of parser cache." );
}
$this->showProgressAndWait( 100 );
$this->output( "\nDone\n" );
@@ -93,5 +93,5 @@ class PurgeParserCache extends Maintenance {
}
}
-$maintClass = 'PurgeParserCache';
+$maintClass = PurgeParserCache::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/reassignEdits.php b/www/wiki/maintenance/reassignEdits.php
index 7a0e4fc0..44589016 100644
--- a/www/wiki/maintenance/reassignEdits.php
+++ b/www/wiki/maintenance/reassignEdits.php
@@ -20,9 +20,11 @@
* @file
* @ingroup Maintenance
* @author Rob Church <robchur@gmail.com>
- * @licence GNU General Public Licence 2.0 or later
+ * @license GNU General Public Licence 2.0 or later
*/
+use Wikimedia\Rdbms\IDatabase;
+
require_once __DIR__ . '/Maintenance.php';
/**
@@ -74,27 +76,35 @@ class ReassignEdits extends Maintenance {
* @return int Number of entries changed, or that would be changed
*/
private function doReassignEdits( &$from, &$to, $rc = false, $report = false ) {
+ global $wgActorTableSchemaMigrationStage;
+
$dbw = $this->getDB( DB_MASTER );
$this->beginTransaction( $dbw, __METHOD__ );
# Count things
$this->output( "Checking current edits..." );
+ $revQueryInfo = ActorMigration::newMigration()->getWhere( $dbw, 'rev_user', $from );
$res = $dbw->select(
- 'revision',
+ [ 'revision' ] + $revQueryInfo['tables'],
'COUNT(*) AS count',
- $this->userConditions( $from, 'rev_user', 'rev_user_text' ),
- __METHOD__
+ $revQueryInfo['conds'],
+ __METHOD__,
+ [],
+ $revQueryInfo['joins']
);
$row = $dbw->fetchObject( $res );
$cur = $row->count;
$this->output( "found {$cur}.\n" );
$this->output( "Checking deleted edits..." );
+ $arQueryInfo = ActorMigration::newMigration()->getWhere( $dbw, 'ar_user', $from, false );
$res = $dbw->select(
- 'archive',
+ [ 'archive' ] + $arQueryInfo['tables'],
'COUNT(*) AS count',
- $this->userConditions( $from, 'ar_user', 'ar_user_text' ),
- __METHOD__
+ $arQueryInfo['conds'],
+ __METHOD__,
+ [],
+ $arQueryInfo['joins']
);
$row = $dbw->fetchObject( $res );
$del = $row->count;
@@ -103,11 +113,14 @@ class ReassignEdits extends Maintenance {
# Don't count recent changes if we're not supposed to
if ( $rc ) {
$this->output( "Checking recent changes..." );
+ $rcQueryInfo = ActorMigration::newMigration()->getWhere( $dbw, 'rc_user', $from, false );
$res = $dbw->select(
- 'recentchanges',
+ [ 'recentchanges' ] + $rcQueryInfo['tables'],
'COUNT(*) AS count',
- $this->userConditions( $from, 'rc_user', 'rc_user_text' ),
- __METHOD__
+ $rcQueryInfo['conds'],
+ __METHOD__,
+ [],
+ $rcQueryInfo['joins']
);
$row = $dbw->fetchObject( $res );
$rec = $row->count;
@@ -123,17 +136,38 @@ class ReassignEdits extends Maintenance {
if ( $total ) {
# Reassign edits
$this->output( "\nReassigning current edits..." );
- $dbw->update( 'revision', $this->userSpecification( $to, 'rev_user', 'rev_user_text' ),
- $this->userConditions( $from, 'rev_user', 'rev_user_text' ), __METHOD__ );
+ if ( $wgActorTableSchemaMigrationStage < MIGRATION_NEW ) {
+ $dbw->update(
+ 'revision',
+ [
+ 'rev_user' => $to->getId(),
+ 'rev_user_text' =>
+ $wgActorTableSchemaMigrationStage <= MIGRATION_WRITE_BOTH ? $to->getName() : ''
+ ],
+ $from->isLoggedIn()
+ ? [ 'rev_user' => $from->getId() ] : [ 'rev_user_text' => $from->getName() ],
+ __METHOD__
+ );
+ }
+ if ( $wgActorTableSchemaMigrationStage > MIGRATION_OLD ) {
+ $dbw->update(
+ 'revision_actor_temp',
+ [ 'revactor_actor' => $to->getActorId( $dbw ) ],
+ [ 'revactor_actor' => $from->getActorId() ],
+ __METHOD__
+ );
+ }
$this->output( "done.\nReassigning deleted edits..." );
- $dbw->update( 'archive', $this->userSpecification( $to, 'ar_user', 'ar_user_text' ),
- $this->userConditions( $from, 'ar_user', 'ar_user_text' ), __METHOD__ );
+ $dbw->update( 'archive',
+ $this->userSpecification( $dbw, $to, 'ar_user', 'ar_user_text', 'ar_actor' ),
+ [ $arQueryInfo['conds'] ], __METHOD__ );
$this->output( "done.\n" );
# Update recent changes if required
if ( $rc ) {
$this->output( "Updating recent changes..." );
- $dbw->update( 'recentchanges', $this->userSpecification( $to, 'rc_user', 'rc_user_text' ),
- $this->userConditions( $from, 'rc_user', 'rc_user_text' ), __METHOD__ );
+ $dbw->update( 'recentchanges',
+ $this->userSpecification( $dbw, $to, 'rc_user', 'rc_user_text', 'rc_actor' ),
+ [ $rcQueryInfo['conds'] ], __METHOD__ );
$this->output( "done.\n" );
}
}
@@ -145,31 +179,30 @@ class ReassignEdits extends Maintenance {
}
/**
- * Return the most efficient set of user conditions
- * i.e. a user => id mapping, or a user_text => text mapping
- *
- * @param User $user User for the condition
- * @param string $idfield Field name containing the identifier
- * @param string $utfield Field name containing the user text
- * @return array
- */
- private function userConditions( &$user, $idfield, $utfield ) {
- return $user->getId()
- ? [ $idfield => $user->getId() ]
- : [ $utfield => $user->getName() ];
- }
-
- /**
* Return user specifications
* i.e. user => id, user_text => text
*
+ * @param IDatabase $dbw Database handle
* @param User $user User for the spec
* @param string $idfield Field name containing the identifier
* @param string $utfield Field name containing the user text
+ * @param string $acfield Field name containing the actor ID
* @return array
*/
- private function userSpecification( &$user, $idfield, $utfield ) {
- return [ $idfield => $user->getId(), $utfield => $user->getName() ];
+ private function userSpecification( IDatabase $dbw, &$user, $idfield, $utfield, $acfield ) {
+ global $wgActorTableSchemaMigrationStage;
+
+ $ret = [];
+ if ( $wgActorTableSchemaMigrationStage < MIGRATION_NEW ) {
+ $ret += [
+ $idfield => $user->getId(),
+ $utfield => $wgActorTableSchemaMigrationStage <= MIGRATION_WRITE_BOTH ? $user->getName() : '',
+ ];
+ }
+ if ( $wgActorTableSchemaMigrationStage > MIGRATION_OLD ) {
+ $ret += [ $acfield => $user->getActorId( $dbw ) ];
+ }
+ return $ret;
}
/**
@@ -186,7 +219,7 @@ class ReassignEdits extends Maintenance {
} else {
$user = User::newFromName( $username );
if ( !$user ) {
- $this->error( "Invalid username", true );
+ $this->fatalError( "Invalid username" );
}
}
$user->load();
@@ -195,5 +228,5 @@ class ReassignEdits extends Maintenance {
}
}
-$maintClass = "ReassignEdits";
+$maintClass = ReassignEdits::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/rebuildFileCache.php b/www/wiki/maintenance/rebuildFileCache.php
index fe3944c8..1f89426e 100644
--- a/www/wiki/maintenance/rebuildFileCache.php
+++ b/www/wiki/maintenance/rebuildFileCache.php
@@ -57,44 +57,44 @@ class RebuildFileCache extends Maintenance {
}
public function execute() {
- global $wgRequestTime;
-
if ( !$this->enabled ) {
- $this->error( "Nothing to do -- \$wgUseFileCache is disabled.", true );
+ $this->fatalError( "Nothing to do -- \$wgUseFileCache is disabled." );
}
$start = $this->getOption( 'start', "0" );
if ( !ctype_digit( $start ) ) {
- $this->error( "Invalid value for start parameter.", true );
+ $this->fatalError( "Invalid value for start parameter." );
}
$start = intval( $start );
$end = $this->getOption( 'end', "0" );
if ( !ctype_digit( $end ) ) {
- $this->error( "Invalid value for end parameter.", true );
+ $this->fatalError( "Invalid value for end parameter." );
}
$end = intval( $end );
$this->output( "Building content page file cache from page {$start}!\n" );
$dbr = $this->getDB( DB_REPLICA );
+ $batchSize = $this->getBatchSize();
$overwrite = $this->hasOption( 'overwrite' );
$start = ( $start > 0 )
? $start
- : $dbr->selectField( 'page', 'MIN(page_id)', false, __METHOD__ );
+ : $dbr->selectField( 'page', 'MIN(page_id)', '', __METHOD__ );
$end = ( $end > 0 )
? $end
- : $dbr->selectField( 'page', 'MAX(page_id)', false, __METHOD__ );
+ : $dbr->selectField( 'page', 'MAX(page_id)', '', __METHOD__ );
if ( !$start ) {
- $this->error( "Nothing to do.", true );
+ $this->fatalError( "Nothing to do." );
}
- $_SERVER['HTTP_ACCEPT_ENCODING'] = 'bgzip'; // hack, no real client
+ // Mock request (hack, no real client)
+ $_SERVER['HTTP_ACCEPT_ENCODING'] = 'bgzip';
# Do remaining chunk
- $end += $this->mBatchSize - 1;
+ $end += $batchSize - 1;
$blockStart = $start;
- $blockEnd = $start + $this->mBatchSize - 1;
+ $blockEnd = $start + $batchSize - 1;
$dbw = $this->getDB( DB_MASTER );
// Go through each page and save the output
@@ -103,7 +103,7 @@ class RebuildFileCache extends Maintenance {
$res = $dbr->select( 'page',
[ 'page_namespace', 'page_title', 'page_id' ],
[ 'page_namespace' => MWNamespace::getContentNamespaces(),
- "page_id BETWEEN $blockStart AND $blockEnd" ],
+ "page_id BETWEEN " . (int)$blockStart . " AND " . (int)$blockEnd ],
__METHOD__,
[ 'ORDER BY' => 'page_id ASC', 'USE INDEX' => 'PRIMARY' ]
);
@@ -139,24 +139,29 @@ class RebuildFileCache extends Maintenance {
}
}
- MediaWiki\suppressWarnings(); // header notices
- // Cache ?action=view
- $wgRequestTime = microtime( true ); # T24852
+ Wikimedia\suppressWarnings(); // header notices
+
+ // 1. Cache ?action=view
+ // Be sure to reset the mocked request time (T24852)
+ $_SERVER['REQUEST_TIME_FLOAT'] = microtime( true );
ob_start();
$article->view();
$context->getOutput()->output();
$context->getOutput()->clearHTML();
$viewHtml = ob_get_clean();
$viewCache->saveToFileCache( $viewHtml );
- // Cache ?action=history
- $wgRequestTime = microtime( true ); # T24852
+
+ // 2. Cache ?action=history
+ // Be sure to reset the mocked request time (T24852)
+ $_SERVER['REQUEST_TIME_FLOAT'] = microtime( true );
ob_start();
Action::factory( 'history', $article, $context )->show();
$context->getOutput()->output();
$context->getOutput()->clearHTML();
$historyHtml = ob_get_clean();
$historyCache->saveToFileCache( $historyHtml );
- MediaWiki\restoreWarnings();
+
+ Wikimedia\restoreWarnings();
if ( $rebuilt ) {
$this->output( "Re-cached page '$title' (id {$row->page_id})..." );
@@ -171,12 +176,12 @@ class RebuildFileCache extends Maintenance {
}
$this->commitTransaction( $dbw, __METHOD__ ); // commit any changes (just for sanity)
- $blockStart += $this->mBatchSize;
- $blockEnd += $this->mBatchSize;
+ $blockStart += $batchSize;
+ $blockEnd += $batchSize;
}
$this->output( "Done!\n" );
}
}
-$maintClass = "RebuildFileCache";
+$maintClass = RebuildFileCache::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/rebuildImages.php b/www/wiki/maintenance/rebuildImages.php
index 109350cd..713492a2 100644
--- a/www/wiki/maintenance/rebuildImages.php
+++ b/www/wiki/maintenance/rebuildImages.php
@@ -125,12 +125,14 @@ class ImageBuilder extends Maintenance {
flush();
}
- function buildTable( $table, $key, $callback ) {
+ function buildTable( $table, $key, $queryInfo, $callback ) {
$count = $this->dbw->selectField( $table, 'count(*)', '', __METHOD__ );
$this->init( $count, $table );
$this->output( "Processing $table...\n" );
- $result = $this->getDB( DB_REPLICA )->select( $table, '*', [], __METHOD__ );
+ $result = $this->getDB( DB_REPLICA )->select(
+ $queryInfo['tables'], $queryInfo['fields'], [], __METHOD__, [], $queryInfo['joins']
+ );
foreach ( $result as $row ) {
$update = call_user_func( $callback, $row, null );
@@ -145,7 +147,7 @@ class ImageBuilder extends Maintenance {
function buildImage() {
$callback = [ $this, 'imageCallback' ];
- $this->buildTable( 'image', 'img_name', $callback );
+ $this->buildTable( 'image', 'img_name', LocalFile::getQueryInfo(), $callback );
}
function imageCallback( $row, $copy ) {
@@ -157,7 +159,8 @@ class ImageBuilder extends Maintenance {
}
function buildOldImage() {
- $this->buildTable( 'oldimage', 'oi_archive_name', [ $this, 'oldimageCallback' ] );
+ $this->buildTable( 'oldimage', 'oi_archive_name', OldLocalFile::getQueryInfo(),
+ [ $this, 'oldimageCallback' ] );
}
function oldimageCallback( $row, $copy ) {
@@ -230,5 +233,5 @@ class ImageBuilder extends Maintenance {
}
}
-$maintClass = 'ImageBuilder';
+$maintClass = ImageBuilder::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/rebuildLocalisationCache.php b/www/wiki/maintenance/rebuildLocalisationCache.php
index 48602de0..4213d5f8 100644
--- a/www/wiki/maintenance/rebuildLocalisationCache.php
+++ b/www/wiki/maintenance/rebuildLocalisationCache.php
@@ -92,7 +92,7 @@ class RebuildLocalisationCache extends Maintenance {
explode( ',', $this->getOption( 'lang' ) ) );
# Bailed out if nothing is left
if ( count( $codes ) == 0 ) {
- $this->error( 'None of the languages specified exists.', 1 );
+ $this->fatalError( 'None of the languages specified exists.' );
}
} else {
# By default get all languages
@@ -177,5 +177,5 @@ class RebuildLocalisationCache extends Maintenance {
}
}
-$maintClass = "RebuildLocalisationCache";
+$maintClass = RebuildLocalisationCache::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/rebuildSitesCache.php b/www/wiki/maintenance/rebuildSitesCache.php
index 230e86d4..41fd8636 100644
--- a/www/wiki/maintenance/rebuildSitesCache.php
+++ b/www/wiki/maintenance/rebuildSitesCache.php
@@ -55,7 +55,7 @@ class RebuildSitesCache extends Maintenance {
$jsonFile = $this->getConfig()->get( 'SitesCacheFile' );
if ( $jsonFile === false ) {
- $this->error( 'Error: No file set in configuration for SitesCacheFile.', 1 );
+ $this->fatalError( 'Error: No file set in configuration for SitesCacheFile.' );
}
}
@@ -64,5 +64,5 @@ class RebuildSitesCache extends Maintenance {
}
-$maintClass = "RebuildSitesCache";
+$maintClass = RebuildSitesCache::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/rebuildall.php b/www/wiki/maintenance/rebuildall.php
index 95822ca2..30a5dd42 100644
--- a/www/wiki/maintenance/rebuildall.php
+++ b/www/wiki/maintenance/rebuildall.php
@@ -44,24 +44,24 @@ class RebuildAll extends Maintenance {
if ( $this->getDB( DB_REPLICA )->getType() != 'postgres' ) {
$this->output( "** Rebuilding fulltext search index (if you abort "
. "this will break searching; run this script again to fix):\n" );
- $rebuildText = $this->runChild( 'RebuildTextIndex', 'rebuildtextindex.php' );
+ $rebuildText = $this->runChild( RebuildTextIndex::class, 'rebuildtextindex.php' );
$rebuildText->execute();
}
// Rebuild RC
$this->output( "\n\n** Rebuilding recentchanges table:\n" );
- $rebuildRC = $this->runChild( 'RebuildRecentchanges', 'rebuildrecentchanges.php' );
+ $rebuildRC = $this->runChild( RebuildRecentchanges::class, 'rebuildrecentchanges.php' );
$rebuildRC->execute();
// Rebuild link tables
$this->output( "\n\n** Rebuilding links tables -- this can take a long time. "
. "It should be safe to abort via ctrl+C if you get bored.\n" );
- $rebuildLinks = $this->runChild( 'RefreshLinks', 'refreshLinks.php' );
+ $rebuildLinks = $this->runChild( RefreshLinks::class, 'refreshLinks.php' );
$rebuildLinks->execute();
$this->output( "Done.\n" );
}
}
-$maintClass = "RebuildAll";
+$maintClass = RebuildAll::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/rebuildmessages.php b/www/wiki/maintenance/rebuildmessages.php
index a47e50d9..88eaf673 100644
--- a/www/wiki/maintenance/rebuildmessages.php
+++ b/www/wiki/maintenance/rebuildmessages.php
@@ -53,5 +53,5 @@ class RebuildMessages extends Maintenance {
}
}
-$maintClass = "RebuildMessages";
+$maintClass = RebuildMessages::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/rebuildrecentchanges.php b/www/wiki/maintenance/rebuildrecentchanges.php
index a2cf3c5b..dc8bf290 100644
--- a/www/wiki/maintenance/rebuildrecentchanges.php
+++ b/www/wiki/maintenance/rebuildrecentchanges.php
@@ -24,7 +24,9 @@
*/
require_once __DIR__ . '/Maintenance.php';
+
use MediaWiki\MediaWikiServices;
+use Wikimedia\Rdbms\ILBFactory;
/**
* Maintenance script that rebuilds recent changes from scratch.
@@ -61,14 +63,15 @@ class RebuildRecentchanges extends Maintenance {
( $this->hasOption( 'from' ) && !$this->hasOption( 'to' ) ) ||
( !$this->hasOption( 'from' ) && $this->hasOption( 'to' ) )
) {
- $this->error( "Both 'from' and 'to' must be given, or neither", 1 );
+ $this->fatalError( "Both 'from' and 'to' must be given, or neither" );
}
- $this->rebuildRecentChangesTablePass1();
- $this->rebuildRecentChangesTablePass2();
- $this->rebuildRecentChangesTablePass3();
- $this->rebuildRecentChangesTablePass4();
- $this->rebuildRecentChangesTablePass5();
+ $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
+ $this->rebuildRecentChangesTablePass1( $lbFactory );
+ $this->rebuildRecentChangesTablePass2( $lbFactory );
+ $this->rebuildRecentChangesTablePass3( $lbFactory );
+ $this->rebuildRecentChangesTablePass4( $lbFactory );
+ $this->rebuildRecentChangesTablePass5( $lbFactory );
if ( !( $this->hasOption( 'from' ) && $this->hasOption( 'to' ) ) ) {
$this->purgeFeeds();
}
@@ -78,10 +81,9 @@ class RebuildRecentchanges extends Maintenance {
/**
* Rebuild pass 1: Insert `recentchanges` entries for page revisions.
*/
- private function rebuildRecentChangesTablePass1() {
+ private function rebuildRecentChangesTablePass1( ILBFactory $lbFactory ) {
$dbw = $this->getDB( DB_MASTER );
- $revCommentStore = new CommentStore( 'rev_comment' );
- $rcCommentStore = new CommentStore( 'rc_comment' );
+ $commentStore = CommentStore::getStore();
if ( $this->hasOption( 'from' ) && $this->hasOption( 'to' ) ) {
$this->cutoffFrom = wfTimestamp( TS_UNIX, $this->getOption( 'from' ) );
@@ -109,20 +111,19 @@ class RebuildRecentchanges extends Maintenance {
'rc_timestamp < ' . $dbw->addQuotes( $dbw->timestamp( $this->cutoffTo ) )
]
);
- foreach ( array_chunk( $rcids, $this->mBatchSize ) as $rcidBatch ) {
+ foreach ( array_chunk( $rcids, $this->getBatchSize() ) as $rcidBatch ) {
$dbw->delete( 'recentchanges', [ 'rc_id' => $rcidBatch ], __METHOD__ );
- wfGetLBFactory()->waitForReplication();
+ $lbFactory->waitForReplication();
}
$this->output( "Loading from page and revision tables...\n" );
- $commentQuery = $revCommentStore->getJoin();
+ $commentQuery = $commentStore->getJoin( 'rev_comment' );
+ $actorQuery = ActorMigration::newMigration()->getJoin( 'rev_user' );
$res = $dbw->select(
- [ 'revision', 'page' ] + $commentQuery['tables'],
+ [ 'revision', 'page' ] + $commentQuery['tables'] + $actorQuery['tables'],
[
'rev_timestamp',
- 'rev_user',
- 'rev_user_text',
'rev_minor_edit',
'rev_id',
'rev_deleted',
@@ -130,7 +131,7 @@ class RebuildRecentchanges extends Maintenance {
'page_title',
'page_is_new',
'page_id'
- ] + $commentQuery['fields'],
+ ] + $commentQuery['fields'] + $actorQuery['fields'],
[
'rev_timestamp > ' . $dbw->addQuotes( $dbw->timestamp( $this->cutoffFrom ) ),
'rev_timestamp < ' . $dbw->addQuotes( $dbw->timestamp( $this->cutoffTo ) )
@@ -139,19 +140,19 @@ class RebuildRecentchanges extends Maintenance {
[ 'ORDER BY' => 'rev_timestamp DESC' ],
[
'page' => [ 'JOIN', 'rev_page=page_id' ],
- ] + $commentQuery['joins']
+ ] + $commentQuery['joins'] + $actorQuery['joins']
);
$this->output( "Inserting from page and revision tables...\n" );
$inserted = 0;
+ $actorMigration = ActorMigration::newMigration();
foreach ( $res as $row ) {
- $comment = $revCommentStore->getComment( $row );
+ $comment = $commentStore->getComment( 'rev_comment', $row );
+ $user = User::newFromAnyId( $row->rev_user, $row->rev_user_text, $row->rev_actor );
$dbw->insert(
'recentchanges',
[
'rc_timestamp' => $row->rev_timestamp,
- 'rc_user' => $row->rev_user,
- 'rc_user_text' => $row->rev_user_text,
'rc_namespace' => $row->page_namespace,
'rc_title' => $row->page_title,
'rc_minor' => $row->rev_minor_edit,
@@ -163,11 +164,12 @@ class RebuildRecentchanges extends Maintenance {
'rc_type' => $row->page_is_new ? RC_NEW : RC_EDIT,
'rc_source' => $row->page_is_new ? RecentChange::SRC_NEW : RecentChange::SRC_EDIT,
'rc_deleted' => $row->rev_deleted
- ] + $rcCommentStore->insert( $dbw, $comment ),
+ ] + $commentStore->insert( $dbw, 'rc_comment', $comment )
+ + $actorMigration->getInsertValues( $dbw, 'rc_user', $user ),
__METHOD__
);
- if ( ( ++$inserted % $this->mBatchSize ) == 0 ) {
- wfGetLBFactory()->waitForReplication();
+ if ( ( ++$inserted % $this->getBatchSize() ) == 0 ) {
+ $lbFactory->waitForReplication();
}
}
}
@@ -176,7 +178,7 @@ class RebuildRecentchanges extends Maintenance {
* Rebuild pass 2: Enhance entries for page revisions with references to the previous revision
* (rc_last_oldid, rc_new etc.) and size differences (rc_old_len, rc_new_len).
*/
- private function rebuildRecentChangesTablePass2() {
+ private function rebuildRecentChangesTablePass2( ILBFactory $lbFactory ) {
$dbw = $this->getDB( DB_MASTER );
$this->output( "Updating links and size differences...\n" );
@@ -256,8 +258,8 @@ class RebuildRecentchanges extends Maintenance {
$lastOldId = intval( $obj->rc_this_oldid );
$lastSize = $size;
- if ( ( ++$updated % $this->mBatchSize ) == 0 ) {
- wfGetLBFactory()->waitForReplication();
+ if ( ( ++$updated % $this->getBatchSize() ) == 0 ) {
+ $lbFactory->waitForReplication();
}
}
}
@@ -266,22 +268,20 @@ class RebuildRecentchanges extends Maintenance {
/**
* Rebuild pass 3: Insert `recentchanges` entries for action logs.
*/
- private function rebuildRecentChangesTablePass3() {
+ private function rebuildRecentChangesTablePass3( ILBFactory $lbFactory ) {
global $wgLogTypes, $wgLogRestrictions;
$dbw = $this->getDB( DB_MASTER );
- $logCommentStore = new CommentStore( 'log_comment' );
- $rcCommentStore = new CommentStore( 'rc_comment' );
+ $commentStore = CommentStore::getStore();
$this->output( "Loading from user, page, and logging tables...\n" );
- $commentQuery = $logCommentStore->getJoin();
+ $commentQuery = $commentStore->getJoin( 'log_comment' );
+ $actorQuery = ActorMigration::newMigration()->getJoin( 'log_user' );
$res = $dbw->select(
- [ 'user', 'logging', 'page' ] + $commentQuery['tables'],
+ [ 'logging', 'page' ] + $commentQuery['tables'] + $actorQuery['tables'],
[
'log_timestamp',
- 'log_user',
- 'user_name',
'log_namespace',
'log_title',
'page_id',
@@ -290,11 +290,10 @@ class RebuildRecentchanges extends Maintenance {
'log_id',
'log_params',
'log_deleted'
- ] + $commentQuery['fields'],
+ ] + $commentQuery['fields'] + $actorQuery['fields'],
[
'log_timestamp > ' . $dbw->addQuotes( $dbw->timestamp( $this->cutoffFrom ) ),
'log_timestamp < ' . $dbw->addQuotes( $dbw->timestamp( $this->cutoffTo ) ),
- 'log_user=user_id',
// Some logs don't go in RC since they are private.
// @FIXME: core/extensions also have spammy logs that don't go in RC.
'log_type' => array_diff( $wgLogTypes, array_keys( $wgLogRestrictions ) ),
@@ -304,20 +303,20 @@ class RebuildRecentchanges extends Maintenance {
[
'page' =>
[ 'LEFT JOIN', [ 'log_namespace=page_namespace', 'log_title=page_title' ] ]
- ] + $commentQuery['joins']
+ ] + $commentQuery['joins'] + $actorQuery['joins']
);
$field = $dbw->fieldInfo( 'recentchanges', 'rc_cur_id' );
$inserted = 0;
+ $actorMigration = ActorMigration::newMigration();
foreach ( $res as $row ) {
- $comment = $logCommentStore->getComment( $row );
+ $comment = $commentStore->getComment( 'log_comment', $row );
+ $user = User::newFromAnyId( $row->log_user, $row->log_user_text, $row->log_actor );
$dbw->insert(
'recentchanges',
[
'rc_timestamp' => $row->log_timestamp,
- 'rc_user' => $row->log_user,
- 'rc_user_text' => $row->user_name,
'rc_namespace' => $row->log_namespace,
'rc_title' => $row->log_title,
'rc_minor' => 0,
@@ -336,12 +335,13 @@ class RebuildRecentchanges extends Maintenance {
'rc_logid' => $row->log_id,
'rc_params' => $row->log_params,
'rc_deleted' => $row->log_deleted
- ] + $rcCommentStore->insert( $dbw, $comment ),
+ ] + $commentStore->insert( $dbw, 'rc_comment', $comment )
+ + $actorMigration->getInsertValues( $dbw, 'rc_user', $user ),
__METHOD__
);
- if ( ( ++$inserted % $this->mBatchSize ) == 0 ) {
- wfGetLBFactory()->waitForReplication();
+ if ( ( ++$inserted % $this->getBatchSize() ) == 0 ) {
+ $lbFactory->waitForReplication();
}
}
}
@@ -349,13 +349,12 @@ class RebuildRecentchanges extends Maintenance {
/**
* Rebuild pass 4: Mark bot and autopatrolled entries.
*/
- private function rebuildRecentChangesTablePass4() {
+ private function rebuildRecentChangesTablePass4( ILBFactory $lbFactory ) {
global $wgUseRCPatrol, $wgMiserMode;
$dbw = $this->getDB( DB_MASTER );
- list( $recentchanges, $usergroups, $user ) =
- $dbw->tableNamesN( 'recentchanges', 'user_groups', 'user' );
+ $userQuery = User::getQueryInfo();
# @FIXME: recognize other bot account groups (not the same as users with 'bot' rights)
# @NOTE: users with 'bot' rights choose when edits are bot edits or not. That information
@@ -365,69 +364,91 @@ class RebuildRecentchanges extends Maintenance {
# Flag our recent bot edits
if ( $botgroups ) {
- $botwhere = $dbw->makeList( $botgroups );
-
$this->output( "Flagging bot account edits...\n" );
# Find all users that are bots
- $sql = "SELECT DISTINCT user_name FROM $usergroups, $user " .
- "WHERE ug_group IN($botwhere) AND user_id = ug_user";
- $res = $dbw->query( $sql, __METHOD__ );
+ $res = $dbw->select(
+ array_merge( [ 'user_groups' ], $userQuery['tables'] ),
+ $userQuery['fields'],
+ [ 'ug_group' => $botgroups ],
+ __METHOD__,
+ [ 'DISTINCT' ],
+ [ 'user_groups' => [ 'JOIN', 'user_id = ug_user' ] ] + $userQuery['joins']
+ );
$botusers = [];
foreach ( $res as $obj ) {
- $botusers[] = $obj->user_name;
+ $botusers[] = User::newFromRow( $obj );
}
# Fill in the rc_bot field
if ( $botusers ) {
- $rcids = $dbw->selectFieldValues(
- 'recentchanges',
- 'rc_id',
- [
- 'rc_user_text' => $botusers,
- "rc_timestamp > " . $dbw->addQuotes( $dbw->timestamp( $this->cutoffFrom ) ),
- "rc_timestamp < " . $dbw->addQuotes( $dbw->timestamp( $this->cutoffTo ) )
- ],
- __METHOD__
- );
+ $actorQuery = ActorMigration::newMigration()->getWhere( $dbw, 'rc_user', $botusers, false );
+ $rcids = [];
+ foreach ( $actorQuery['orconds'] as $cond ) {
+ $rcids = array_merge( $rcids, $dbw->selectFieldValues(
+ [ 'recentchanges' ] + $actorQuery['tables'],
+ 'rc_id',
+ [
+ "rc_timestamp > " . $dbw->addQuotes( $dbw->timestamp( $this->cutoffFrom ) ),
+ "rc_timestamp < " . $dbw->addQuotes( $dbw->timestamp( $this->cutoffTo ) ),
+ $cond,
+ ],
+ __METHOD__,
+ [],
+ $actorQuery['joins']
+ ) );
+ }
+ $rcids = array_values( array_unique( $rcids ) );
- foreach ( array_chunk( $rcids, $this->mBatchSize ) as $rcidBatch ) {
+ foreach ( array_chunk( $rcids, $this->getBatchSize() ) as $rcidBatch ) {
$dbw->update(
'recentchanges',
[ 'rc_bot' => 1 ],
[ 'rc_id' => $rcidBatch ],
__METHOD__
);
- wfGetLBFactory()->waitForReplication();
+ $lbFactory->waitForReplication();
}
}
}
# Flag our recent autopatrolled edits
if ( !$wgMiserMode && $autopatrolgroups ) {
- $patrolwhere = $dbw->makeList( $autopatrolgroups );
$patrolusers = [];
$this->output( "Flagging auto-patrolled edits...\n" );
# Find all users in RC with autopatrol rights
- $sql = "SELECT DISTINCT user_name FROM $usergroups, $user " .
- "WHERE ug_group IN($patrolwhere) AND user_id = ug_user";
- $res = $dbw->query( $sql, __METHOD__ );
+ $res = $dbw->select(
+ array_merge( [ 'user_groups' ], $userQuery['tables'] ),
+ $userQuery['fields'],
+ [ 'ug_group' => $autopatrolgroups ],
+ __METHOD__,
+ [ 'DISTINCT' ],
+ [ 'user_groups' => [ 'JOIN', 'user_id = ug_user' ] ] + $userQuery['joins']
+ );
foreach ( $res as $obj ) {
- $patrolusers[] = $dbw->addQuotes( $obj->user_name );
+ $patrolusers[] = User::newFromRow( $obj );
}
# Fill in the rc_patrolled field
if ( $patrolusers ) {
- $patrolwhere = implode( ',', $patrolusers );
- $sql2 = "UPDATE $recentchanges SET rc_patrolled=1 " .
- "WHERE rc_user_text IN($patrolwhere) " .
- "AND rc_timestamp > " . $dbw->addQuotes( $dbw->timestamp( $this->cutoffFrom ) ) . ' ' .
- "AND rc_timestamp < " . $dbw->addQuotes( $dbw->timestamp( $this->cutoffTo ) );
- $dbw->query( $sql2 );
+ $actorQuery = ActorMigration::newMigration()->getWhere( $dbw, 'rc_user', $patrolusers, false );
+ foreach ( $actorQuery['orconds'] as $cond ) {
+ $dbw->update(
+ 'recentchanges',
+ [ 'rc_patrolled' => 1 ],
+ [
+ $cond,
+ 'rc_timestamp > ' . $dbw->addQuotes( $dbw->timestamp( $this->cutoffFrom ) ),
+ 'rc_timestamp < ' . $dbw->addQuotes( $dbw->timestamp( $this->cutoffTo ) ),
+ ],
+ __METHOD__
+ );
+ $lbFactory->waitForReplication();
+ }
}
}
}
@@ -436,7 +457,7 @@ class RebuildRecentchanges extends Maintenance {
* Rebuild pass 5: Delete duplicate entries where we generate both a page revision and a log entry
* for a single action (upload only, at the moment, but potentially also move, protect, ...).
*/
- private function rebuildRecentChangesTablePass5() {
+ private function rebuildRecentChangesTablePass5( ILBFactory $lbFactory ) {
$dbw = wfGetDB( DB_MASTER );
$this->output( "Removing duplicate revision and logging entries...\n" );
@@ -474,8 +495,8 @@ class RebuildRecentchanges extends Maintenance {
__METHOD__
);
- if ( ( ++$updates % $this->mBatchSize ) == 0 ) {
- wfGetLBFactory()->waitForReplication();
+ if ( ( ++$updates % $this->getBatchSize() ) == 0 ) {
+ $lbFactory->waitForReplication();
}
}
}
@@ -495,5 +516,5 @@ class RebuildRecentchanges extends Maintenance {
}
}
-$maintClass = "RebuildRecentchanges";
+$maintClass = RebuildRecentchanges::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/rebuildtextindex.php b/www/wiki/maintenance/rebuildtextindex.php
index faa4d962..900a52a5 100644
--- a/www/wiki/maintenance/rebuildtextindex.php
+++ b/www/wiki/maintenance/rebuildtextindex.php
@@ -56,17 +56,17 @@ class RebuildTextIndex extends Maintenance {
// Shouldn't be needed for Postgres
$this->db = $this->getDB( DB_MASTER );
if ( $this->db->getType() == 'postgres' ) {
- $this->error( "This script is not needed when using Postgres.\n", true );
+ $this->fatalError( "This script is not needed when using Postgres.\n" );
}
if ( $this->db->getType() == 'sqlite' ) {
if ( !DatabaseSqlite::getFulltextSearchModule() ) {
- $this->error( "Your version of SQLite module for PHP doesn't "
- . "support full-text search (FTS3).\n", true );
+ $this->fatalError( "Your version of SQLite module for PHP doesn't "
+ . "support full-text search (FTS3).\n" );
}
if ( !$this->db->checkForEnabledSearch() ) {
- $this->error( "Your database schema is not configured for "
- . "full-text search support. Run update.php.\n", true );
+ $this->fatalError( "Your database schema is not configured for "
+ . "full-text search support. Run update.php.\n" );
}
}
@@ -93,11 +93,7 @@ class RebuildTextIndex extends Maintenance {
$this->output( "Rebuilding index fields for {$count} pages...\n" );
$n = 0;
- $fields = array_merge(
- Revision::selectPageFields(),
- Revision::selectFields(),
- Revision::selectTextFields()
- );
+ $revQuery = Revision::getQueryInfo( [ 'page', 'text' ] );
while ( $n < $count ) {
if ( $n ) {
@@ -105,9 +101,13 @@ class RebuildTextIndex extends Maintenance {
}
$end = $n + self::RTI_CHUNK_SIZE - 1;
- $res = $this->db->select( [ 'page', 'revision', 'text' ], $fields,
+ $res = $this->db->select(
+ $revQuery['tables'],
+ $revQuery['fields'],
[ "page_id BETWEEN $n AND $end", 'page_latest = rev_id', 'rev_text_id = old_id' ],
- __METHOD__
+ __METHOD__,
+ [],
+ $revQuery['joins']
);
foreach ( $res as $s ) {
@@ -145,9 +145,10 @@ class RebuildTextIndex extends Maintenance {
private function createMysqlTextIndex() {
$searchindex = $this->db->tableName( 'searchindex' );
$this->output( "\nRebuild the index...\n" );
- $sql = "ALTER TABLE $searchindex ADD FULLTEXT si_title (si_title), " .
- "ADD FULLTEXT si_text (si_text)";
- $this->db->query( $sql, __METHOD__ );
+ foreach ( [ 'si_title', 'si_text' ] as $field ) {
+ $sql = "ALTER TABLE $searchindex ADD FULLTEXT $field ($field)";
+ $this->db->query( $sql, __METHOD__ );
+ }
}
/**
@@ -160,5 +161,5 @@ class RebuildTextIndex extends Maintenance {
}
}
-$maintClass = "RebuildTextIndex";
+$maintClass = RebuildTextIndex::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/recountCategories.php b/www/wiki/maintenance/recountCategories.php
index a4bfa989..7e8f0636 100644
--- a/www/wiki/maintenance/recountCategories.php
+++ b/www/wiki/maintenance/recountCategories.php
@@ -75,7 +75,7 @@ TEXT
public function execute() {
$this->mode = $this->getOption( 'mode' );
if ( !in_array( $this->mode, [ 'pages', 'subcats', 'files' ] ) ) {
- $this->error( 'Please specify a valid mode: one of "pages", "subcats" or "files".', 1 );
+ $this->fatalError( 'Please specify a valid mode: one of "pages", "subcats" or "files".' );
}
$this->minimumId = intval( $this->getOption( 'begin', 0 ) );
@@ -97,8 +97,8 @@ TEXT
}
protected function doWork() {
- $this->output( "Finding up to {$this->mBatchSize} drifted rows " .
- "starting at cat_id {$this->minimumId}...\n" );
+ $this->output( "Finding up to {$this->getBatchSize()} drifted rows " .
+ "starting at cat_id {$this->getBatchSize()}...\n" );
$countingConds = [ 'cl_to = cat_title' ];
if ( $this->mode === 'subcats' ) {
@@ -124,7 +124,7 @@ TEXT
"cat_{$this->mode} != ($countingSubquery)"
],
__METHOD__,
- [ 'LIMIT' => $this->mBatchSize ]
+ [ 'LIMIT' => $this->getBatchSize() ]
);
if ( !$idsToUpdate ) {
return false;
@@ -156,7 +156,7 @@ TEXT
[ "cat_{$this->mode}" => $row->count ],
[
'cat_id' => $row->cat_id,
- "cat_{$this->mode} != {$row->count}",
+ "cat_{$this->mode} != " . (int)( $row->count ),
],
__METHOD__ );
$affectedRows += $dbw->affectedRows();
@@ -168,5 +168,5 @@ TEXT
}
}
-$maintClass = 'RecountCategories';
+$maintClass = RecountCategories::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/refreshFileHeaders.php b/www/wiki/maintenance/refreshFileHeaders.php
index bca1c964..db8a19a1 100644
--- a/www/wiki/maintenance/refreshFileHeaders.php
+++ b/www/wiki/maintenance/refreshFileHeaders.php
@@ -37,6 +37,15 @@ class RefreshFileHeaders extends Maintenance {
$this->addOption( 'verbose', 'Output information about each file.', false, false, 'v' );
$this->addOption( 'start', 'Name of file to start with', false, true );
$this->addOption( 'end', 'Name of file to end with', false, true );
+ $this->addOption( 'media_type', 'Media type to filter for', false, true );
+ $this->addOption( 'major_mime', 'Major mime type to filter for', false, true );
+ $this->addOption( 'minor_mime', 'Minor mime type to filter for', false, true );
+ $this->addOption(
+ 'refreshContentType',
+ 'Set true to refresh file content type from mime data in db',
+ false,
+ false
+ );
$this->setBatchSize( 200 );
}
@@ -44,10 +53,18 @@ class RefreshFileHeaders extends Maintenance {
$repo = RepoGroup::singleton()->getLocalRepo();
$start = str_replace( ' ', '_', $this->getOption( 'start', '' ) ); // page on img_name
$end = str_replace( ' ', '_', $this->getOption( 'end', '' ) ); // page on img_name
+ // filter by img_media_type
+ $media_type = str_replace( ' ', '_', $this->getOption( 'media_type', '' ) );
+ // filter by img_major_mime
+ $major_mime = str_replace( ' ', '_', $this->getOption( 'major_mime', '' ) );
+ // filter by img_minor_mime
+ $minor_mime = str_replace( ' ', '_', $this->getOption( 'minor_mime', '' ) );
$count = 0;
$dbr = $this->getDB( DB_REPLICA );
+ $fileQuery = LocalFile::getQueryInfo();
+
do {
$conds = [ "img_name > {$dbr->addQuotes( $start )}" ];
@@ -55,8 +72,28 @@ class RefreshFileHeaders extends Maintenance {
$conds[] = "img_name <= {$dbr->addQuotes( $end )}";
}
- $res = $dbr->select( 'image', '*', $conds,
- __METHOD__, [ 'LIMIT' => $this->mBatchSize, 'ORDER BY' => 'img_name ASC' ] );
+ if ( strlen( $media_type ) ) {
+ $conds[] = "img_media_type = {$dbr->addQuotes( $media_type )}";
+ }
+
+ if ( strlen( $major_mime ) ) {
+ $conds[] = "img_major_mime = {$dbr->addQuotes( $major_mime )}";
+ }
+
+ if ( strlen( $minor_mime ) ) {
+ $conds[] = "img_minor_mime = {$dbr->addQuotes( $minor_mime )}";
+ }
+
+ $res = $dbr->select( $fileQuery['tables'],
+ $fileQuery['fields'],
+ $conds,
+ __METHOD__,
+ [
+ 'LIMIT' => $this->getBatchSize(),
+ 'ORDER BY' => 'img_name ASC'
+ ],
+ $fileQuery['joins']
+ );
if ( $res->numRows() > 0 ) {
$row1 = $res->current();
@@ -69,6 +106,9 @@ class RefreshFileHeaders extends Maintenance {
foreach ( $res as $row ) {
$file = $repo->newFileFromRow( $row );
$headers = $file->getContentHeaders();
+ if ( $this->getOption( 'refreshContentType', false ) ) {
+ $headers['Content-Type'] = $row->img_major_mime . '/' . $row->img_minor_mime;
+ }
if ( count( $headers ) ) {
$backendOperations[] = [
@@ -98,7 +138,7 @@ class RefreshFileHeaders extends Maintenance {
$this->output( "Updating headers for {$backendOperationsCount} file(s).\n" );
$this->updateFileHeaders( $repo, $backendOperations );
- } while ( $res->numRows() === $this->mBatchSize );
+ } while ( $res->numRows() === $this->getBatchSize() );
$this->output( "Done. Updated headers for $count file(s).\n" );
}
@@ -112,5 +152,5 @@ class RefreshFileHeaders extends Maintenance {
}
}
-$maintClass = 'RefreshFileHeaders';
+$maintClass = RefreshFileHeaders::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/refreshImageMetadata.php b/www/wiki/maintenance/refreshImageMetadata.php
index f6e9e9c3..65db94da 100644
--- a/www/wiki/maintenance/refreshImageMetadata.php
+++ b/www/wiki/maintenance/refreshImageMetadata.php
@@ -106,8 +106,9 @@ class RefreshImageMetadata extends Maintenance {
$error = 0;
$dbw = $this->getDB( DB_MASTER );
- if ( $this->mBatchSize <= 0 ) {
- $this->error( "Batch size is too low...", 12 );
+ $batchSize = $this->getBatchSize();
+ if ( $batchSize <= 0 ) {
+ $this->fatalError( "Batch size is too low...", 12 );
}
$repo = RepoGroup::singleton()->getLocalRepo();
@@ -120,17 +121,20 @@ class RefreshImageMetadata extends Maintenance {
}
$options = [
- 'LIMIT' => $this->mBatchSize,
+ 'LIMIT' => $batchSize,
'ORDER BY' => 'img_name ASC',
];
+ $fileQuery = LocalFile::getQueryInfo();
+
do {
$res = $dbw->select(
- 'image',
- '*',
+ $fileQuery['tables'],
+ $fileQuery['fields'],
array_merge( $conds, $conds2 ),
__METHOD__,
- $options
+ $options,
+ $fileQuery['joins']
);
if ( $res->numRows() > 0 ) {
@@ -191,7 +195,7 @@ class RefreshImageMetadata extends Maintenance {
}
$conds2 = [ 'img_name > ' . $dbw->addQuotes( $row->img_name ) ];
wfWaitForSlaves();
- } while ( $res->numRows() === $this->mBatchSize );
+ } while ( $res->numRows() === $batchSize );
$total = $upgraded + $leftAlone;
if ( $force ) {
@@ -251,10 +255,10 @@ class RefreshImageMetadata extends Maintenance {
}
if ( $brokenOnly && $force ) {
- $this->error( 'Cannot use --broken-only and --force together. ', 2 );
+ $this->fatalError( 'Cannot use --broken-only and --force together. ', 2 );
}
}
}
-$maintClass = 'RefreshImageMetadata';
+$maintClass = RefreshImageMetadata::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/refreshLinks.php b/www/wiki/maintenance/refreshLinks.php
index b099aff4..49f1cd12 100644
--- a/www/wiki/maintenance/refreshLinks.php
+++ b/www/wiki/maintenance/refreshLinks.php
@@ -70,7 +70,7 @@ class RefreshLinks extends Maintenance {
if ( ( $category = $this->getOption( 'category', false ) ) !== false ) {
$title = Title::makeTitleSafe( NS_CATEGORY, $category );
if ( !$title ) {
- $this->error( "'$category' is an invalid category name!\n", true );
+ $this->fatalError( "'$category' is an invalid category name!\n" );
}
$this->refreshCategory( $title );
} elseif ( ( $category = $this->getOption( 'tracking-category', false ) ) !== false ) {
@@ -80,9 +80,9 @@ class RefreshLinks extends Maintenance {
$redir = $this->hasOption( 'redirects-only' );
$oldRedir = $this->hasOption( 'old-redirects-only' );
$this->doRefreshLinks( $start, $new, $end, $redir, $oldRedir );
- $this->deleteLinksFromNonexistent( null, null, $this->mBatchSize, $dfnChunkSize );
+ $this->deleteLinksFromNonexistent( null, null, $this->getBatchSize(), $dfnChunkSize );
} else {
- $this->deleteLinksFromNonexistent( $start, $end, $this->mBatchSize, $dfnChunkSize );
+ $this->deleteLinksFromNonexistent( $start, $end, $this->getBatchSize(), $dfnChunkSize );
}
}
@@ -170,8 +170,8 @@ class RefreshLinks extends Maintenance {
}
} else {
if ( !$end ) {
- $maxPage = $dbr->selectField( 'page', 'max(page_id)', false );
- $maxRD = $dbr->selectField( 'redirect', 'max(rd_from)', false );
+ $maxPage = $dbr->selectField( 'page', 'max(page_id)', '', __METHOD__ );
+ $maxRD = $dbr->selectField( 'redirect', 'max(rd_from)', '', __METHOD__ );
$end = max( $maxPage, $maxRD );
}
$this->output( "Refreshing redirects table.\n" );
@@ -456,7 +456,7 @@ class RefreshLinks extends Maintenance {
__METHOD__,
[
'ORDER BY' => [ 'cl_timestamp', 'cl_from' ],
- 'LIMIT' => $this->mBatchSize,
+ 'LIMIT' => $this->getBatchSize(),
]
);
@@ -470,7 +470,7 @@ class RefreshLinks extends Maintenance {
self::fixLinksFromArticle( $row->page_id );
}
- } while ( $res->numRows() == $this->mBatchSize );
+ } while ( $res->numRows() == $this->getBatchSize() );
}
/**
@@ -485,9 +485,9 @@ class RefreshLinks extends Maintenance {
if ( isset( $cats[$categoryKey] ) ) {
return $cats[$categoryKey]['cats'];
}
- $this->error( "Unknown tracking category {$categoryKey}\n", true );
+ $this->fatalError( "Unknown tracking category {$categoryKey}\n" );
}
}
-$maintClass = 'RefreshLinks';
+$maintClass = RefreshLinks::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/removeInvalidEmails.php b/www/wiki/maintenance/removeInvalidEmails.php
index 1034005a..ec68ef2e 100644
--- a/www/wiki/maintenance/removeInvalidEmails.php
+++ b/www/wiki/maintenance/removeInvalidEmails.php
@@ -36,7 +36,7 @@ class RemoveInvalidEmails extends Maintenance {
'user_email_authenticated IS NULL'
],
__METHOD__,
- [ 'LIMIT' => $this->mBatchSize ]
+ [ 'LIMIT' => $this->getBatchSize() ]
);
$count = $rows->numRows();
$badIds = [];
@@ -74,5 +74,5 @@ class RemoveInvalidEmails extends Maintenance {
}
}
-$maintClass = 'RemoveInvalidEmails';
+$maintClass = RemoveInvalidEmails::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/removeUnusedAccounts.php b/www/wiki/maintenance/removeUnusedAccounts.php
index c750784e..3fa30cbd 100644
--- a/www/wiki/maintenance/removeUnusedAccounts.php
+++ b/www/wiki/maintenance/removeUnusedAccounts.php
@@ -39,13 +39,27 @@ class RemoveUnusedAccounts extends Maintenance {
}
public function execute() {
+ global $wgActorTableSchemaMigrationStage;
+
$this->output( "Remove unused accounts\n\n" );
# Do an initial scan for inactive accounts and report the result
$this->output( "Checking for unused user accounts...\n" );
- $del = [];
+ $delUser = [];
+ $delActor = [];
$dbr = $this->getDB( DB_REPLICA );
- $res = $dbr->select( 'user', [ 'user_id', 'user_name', 'user_touched' ], '', __METHOD__ );
+ if ( $wgActorTableSchemaMigrationStage > MIGRATION_OLD ) {
+ $res = $dbr->select(
+ [ 'user', 'actor' ],
+ [ 'user_id', 'user_name', 'user_touched', 'actor_id' ],
+ '',
+ __METHOD__,
+ [],
+ [ 'actor' => [ 'LEFT JOIN', 'user_id = actor_user' ] ]
+ );
+ } else {
+ $res = $dbr->select( 'user', [ 'user_id', 'user_name', 'user_touched' ], '', __METHOD__ );
+ }
if ( $this->hasOption( 'ignore-groups' ) ) {
$excludedGroups = explode( ',', $this->getOption( 'ignore-groups' ) );
} else {
@@ -53,7 +67,7 @@ class RemoveUnusedAccounts extends Maintenance {
}
$touched = $this->getOption( 'ignore-touched', "1" );
if ( !ctype_digit( $touched ) ) {
- $this->error( "Please put a valid positive integer on the --ignore-touched parameter.", true );
+ $this->fatalError( "Please put a valid positive integer on the --ignore-touched parameter." );
}
$touchedSeconds = 86400 * $touched;
foreach ( $res as $row ) {
@@ -61,27 +75,49 @@ class RemoveUnusedAccounts extends Maintenance {
# group or if it's touched within the $touchedSeconds seconds.
$instance = User::newFromId( $row->user_id );
if ( count( array_intersect( $instance->getEffectiveGroups(), $excludedGroups ) ) == 0
- && $this->isInactiveAccount( $row->user_id, true )
+ && $this->isInactiveAccount( $row->user_id, $row->actor_id ?? null, true )
&& wfTimestamp( TS_UNIX, $row->user_touched ) < wfTimestamp( TS_UNIX, time() - $touchedSeconds )
) {
# Inactive; print out the name and flag it
- $del[] = $row->user_id;
+ $delUser[] = $row->user_id;
+ if ( isset( $row->actor_id ) && $row->actor_id ) {
+ $delActor[] = $row->actor_id;
+ }
$this->output( $row->user_name . "\n" );
}
}
- $count = count( $del );
+ $count = count( $delUser );
$this->output( "...found {$count}.\n" );
# If required, go back and delete each marked account
if ( $count > 0 && $this->hasOption( 'delete' ) ) {
$this->output( "\nDeleting unused accounts..." );
$dbw = $this->getDB( DB_MASTER );
- $dbw->delete( 'user', [ 'user_id' => $del ], __METHOD__ );
- $dbw->delete( 'user_groups', [ 'ug_user' => $del ], __METHOD__ );
- $dbw->delete( 'user_former_groups', [ 'ufg_user' => $del ], __METHOD__ );
- $dbw->delete( 'user_properties', [ 'up_user' => $del ], __METHOD__ );
- $dbw->delete( 'logging', [ 'log_user' => $del ], __METHOD__ );
- $dbw->delete( 'recentchanges', [ 'rc_user' => $del ], __METHOD__ );
+ $dbw->delete( 'user', [ 'user_id' => $delUser ], __METHOD__ );
+ if ( $wgActorTableSchemaMigrationStage > MIGRATION_OLD ) {
+ # Keep actor rows referenced from ipblocks
+ $keep = $dbw->selectFieldValues(
+ 'ipblocks', 'ipb_by_actor', [ 'ipb_by_actor' => $delActor ], __METHOD__
+ );
+ $del = array_diff( $delActor, $keep );
+ if ( $del ) {
+ $dbw->delete( 'actor', [ 'actor_id' => $del ], __METHOD__ );
+ }
+ if ( $keep ) {
+ $dbw->update( 'actor', [ 'actor_user' => 0 ], [ 'actor_id' => $keep ], __METHOD__ );
+ }
+ }
+ $dbw->delete( 'user_groups', [ 'ug_user' => $delUser ], __METHOD__ );
+ $dbw->delete( 'user_former_groups', [ 'ufg_user' => $delUser ], __METHOD__ );
+ $dbw->delete( 'user_properties', [ 'up_user' => $delUser ], __METHOD__ );
+ if ( $wgActorTableSchemaMigrationStage > MIGRATION_OLD ) {
+ $dbw->delete( 'logging', [ 'log_actor' => $delActor ], __METHOD__ );
+ $dbw->delete( 'recentchanges', [ 'rc_actor' => $delActor ], __METHOD__ );
+ }
+ if ( $wgActorTableSchemaMigrationStage < MIGRATION_NEW ) {
+ $dbw->delete( 'logging', [ 'log_user' => $delUser ], __METHOD__ );
+ $dbw->delete( 'recentchanges', [ 'rc_user' => $delUser ], __METHOD__ );
+ }
$this->output( "done.\n" );
# Update the site_stats.ss_users field
$users = $dbw->selectField( 'user', 'COUNT(*)', [], __METHOD__ );
@@ -102,10 +138,11 @@ class RemoveUnusedAccounts extends Maintenance {
* (No edits, no deleted edits, no log entries, no current/old uploads)
*
* @param int $id User's ID
+ * @param int|null $actor User's actor ID
* @param bool $master Perform checking on the master
* @return bool
*/
- private function isInactiveAccount( $id, $master = false ) {
+ private function isInactiveAccount( $id, $actor, $master = false ) {
$dbo = $this->getDB( $master ? DB_MASTER : DB_REPLICA );
$checks = [
'revision' => 'rev',
@@ -116,14 +153,37 @@ class RemoveUnusedAccounts extends Maintenance {
];
$count = 0;
+ $migration = ActorMigration::newMigration();
+
+ $user = User::newFromAnyId( $id, null, $actor );
+
$this->beginTransaction( $dbo, __METHOD__ );
- foreach ( $checks as $table => $fprefix ) {
- $conds = [ $fprefix . '_user' => $id ];
- $count += (int)$dbo->selectField( $table, 'COUNT(*)', $conds, __METHOD__ );
+ foreach ( $checks as $table => $prefix ) {
+ $actorQuery = $migration->getWhere(
+ $dbo, $prefix . '_user', $user, $prefix !== 'oi' && $prefix !== 'fa'
+ );
+ $count += (int)$dbo->selectField(
+ [ $table ] + $actorQuery['tables'],
+ 'COUNT(*)',
+ $actorQuery['conds'],
+ __METHOD__,
+ [],
+ $actorQuery['joins']
+ );
}
- $conds = [ 'log_user' => $id, 'log_type != ' . $dbo->addQuotes( 'newusers' ) ];
- $count += (int)$dbo->selectField( 'logging', 'COUNT(*)', $conds, __METHOD__ );
+ $actorQuery = $migration->getWhere( $dbo, 'log_user', $user, false );
+ $count += (int)$dbo->selectField(
+ [ 'logging' ] + $actorQuery['tables'],
+ 'COUNT(*)',
+ [
+ $actorQuery['conds'],
+ 'log_type != ' . $dbo->addQuotes( 'newusers' )
+ ],
+ __METHOD__,
+ [],
+ $actorQuery['joins']
+ );
$this->commitTransaction( $dbo, __METHOD__ );
@@ -131,5 +191,5 @@ class RemoveUnusedAccounts extends Maintenance {
}
}
-$maintClass = "RemoveUnusedAccounts";
+$maintClass = RemoveUnusedAccounts::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/renameDbPrefix.php b/www/wiki/maintenance/renameDbPrefix.php
index 2772f04b..af8a2802 100644
--- a/www/wiki/maintenance/renameDbPrefix.php
+++ b/www/wiki/maintenance/renameDbPrefix.php
@@ -62,7 +62,7 @@ class RenameDbPrefix extends Maintenance {
}
if ( $old === false || $new === false ) {
- $this->error( "Invalid prefix!", true );
+ $this->fatalError( "Invalid prefix!" );
}
if ( $old === $new ) {
$this->output( "Same prefix. Nothing to rename!\n", true );
@@ -90,5 +90,5 @@ class RenameDbPrefix extends Maintenance {
}
}
-$maintClass = "RenameDbPrefix";
+$maintClass = RenameDbPrefix::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/renderDump.php b/www/wiki/maintenance/renderDump.php
index 68a371c3..cc5ae596 100644
--- a/www/wiki/maintenance/renderDump.php
+++ b/www/wiki/maintenance/renderDump.php
@@ -66,6 +66,9 @@ class DumpRenderer extends Maintenance {
$importer->setRevisionCallback(
[ $this, 'handleRevision' ] );
+ $importer->setNoticeCallback( function ( $msg, $params ) {
+ echo wfMessage( $msg, $params )->text() . "\n";
+ } );
$importer->doImport();
@@ -120,5 +123,5 @@ class DumpRenderer extends Maintenance {
}
}
-$maintClass = "DumpRenderer";
+$maintClass = DumpRenderer::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/resetUserEmail.php b/www/wiki/maintenance/resetUserEmail.php
index 8d0873f1..d6b4b790 100644
--- a/www/wiki/maintenance/resetUserEmail.php
+++ b/www/wiki/maintenance/resetUserEmail.php
@@ -48,12 +48,12 @@ class ResetUserEmail extends Maintenance {
$user = User::newFromName( $userName );
}
if ( !$user || !$user->getId() || !$user->loadFromId() ) {
- $this->error( "Error: user '$userName' does not exist\n", 1 );
+ $this->fatalError( "Error: user '$userName' does not exist\n" );
}
$email = $this->getArg( 1 );
if ( !Sanitizer::validateEmail( $email ) ) {
- $this->error( "Error: email '$email' is not valid\n", 1 );
+ $this->fatalError( "Error: email '$email' is not valid\n" );
}
// Code from https://wikitech.wikimedia.org/wiki/Password_reset
@@ -68,5 +68,5 @@ class ResetUserEmail extends Maintenance {
}
}
-$maintClass = 'ResetUserEmail';
+$maintClass = ResetUserEmail::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/resetUserTokens.php b/www/wiki/maintenance/resetUserTokens.php
index 481da980..284db2c2 100644
--- a/www/wiki/maintenance/resetUserTokens.php
+++ b/www/wiki/maintenance/resetUserTokens.php
@@ -64,11 +64,10 @@ class ResetUserTokens extends Maintenance {
$this->output( "\n" );
$this->output( "Abort with control-c in the next five seconds "
. "(skip this countdown with --nowarn) ... " );
- wfCountDown( 5 );
+ $this->countDown( 5 );
}
// We list user by user_id from one of the replica DBs
- // We list user by user_id from one of the slave database
$dbr = $this->getDB( DB_REPLICA );
$where = [];
@@ -80,7 +79,7 @@ class ResetUserTokens extends Maintenance {
$maxid = $dbr->selectField( 'user', 'MAX(user_id)', [], __METHOD__ );
$min = 0;
- $max = $this->mBatchSize;
+ $max = $this->getBatchSize();
do {
$result = $dbr->select( 'user',
@@ -99,7 +98,7 @@ class ResetUserTokens extends Maintenance {
}
$min = $max;
- $max = $min + $this->mBatchSize;
+ $max = $min + $this->getBatchSize();
wfWaitForSlaves();
} while ( $min <= $maxid );
@@ -116,5 +115,5 @@ class ResetUserTokens extends Maintenance {
}
}
-$maintClass = "ResetUserTokens";
+$maintClass = ResetUserTokens::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/resources/update-oojs.sh b/www/wiki/maintenance/resources/update-oojs.sh
index 267bd961..f99bb7d7 100755
--- a/www/wiki/maintenance/resources/update-oojs.sh
+++ b/www/wiki/maintenance/resources/update-oojs.sh
@@ -52,7 +52,7 @@ COMMITMSG=$(cat <<END
Update OOjs to v$OOJS_VERSION
Release notes:
- https://phabricator.wikimedia.org/diffusion/GOJS/browse/master/History.md;v$OOJS_VERSION
+ https://gerrit.wikimedia.org/r/plugins/gitiles/oojs/core/+/v$OOJS_VERSION/History.md
END
)
diff --git a/www/wiki/maintenance/resources/update-oojs-ui.sh b/www/wiki/maintenance/resources/update-ooui.sh
index 799af4ca..231001de 100755
--- a/www/wiki/maintenance/resources/update-oojs-ui.sh
+++ b/www/wiki/maintenance/resources/update-ooui.sh
@@ -1,6 +1,6 @@
#!/bin/bash -eu
-# This script generates a commit that updates our copy of OOjs UI
+# This script generates a commit that updates our copy of OOUI
if [ -n "${2:-}" ]
then
@@ -11,7 +11,7 @@ fi
REPO_DIR=$(cd "$(dirname $0)/../.."; pwd) # Root dir of the git repo working tree
TARGET_DIR="resources/lib/oojs-ui" # Destination relative to the root of the repo
-NPM_DIR=$(mktemp -d 2>/dev/null || mktemp -d -t 'update-oojs-ui') # e.g. /tmp/update-oojs-ui.rI0I5Vir
+NPM_DIR=$(mktemp -d 2>/dev/null || mktemp -d -t 'update-ooui') # e.g. /tmp/update-ooui.rI0I5Vir
# Prepare working tree
cd "$REPO_DIR"
@@ -20,7 +20,7 @@ git checkout composer.json
git reset -- $TARGET_DIR
git checkout -- $TARGET_DIR
git fetch origin
-git checkout -B upstream-oojs-ui origin/master
+git checkout -B upstream-ooui origin/master
# Fetch upstream version
cd $NPM_DIR
@@ -31,19 +31,18 @@ else
npm install oojs-ui
fi
-OOJSUI_VERSION=$(node -e 'console.log(require("./node_modules/oojs-ui/package.json").version);')
-if [ "$OOJSUI_VERSION" == "" ]
+OOUI_VERSION=$(node -e 'console.log(require("./node_modules/oojs-ui/package.json").version);')
+if [ "$OOUI_VERSION" == "" ]
then
- echo 'Could not find OOjs UI version'
+ echo 'Could not find OOUI version'
exit 1
fi
# Copy files, picking the necessary ones from source and distribution
rm -r "$REPO_DIR/$TARGET_DIR"
-mkdir -p "$REPO_DIR/$TARGET_DIR/i18n"
-mkdir -p "$REPO_DIR/$TARGET_DIR/images"
-mkdir -p "$REPO_DIR/$TARGET_DIR/themes/wikimediaui/images"
-mkdir -p "$REPO_DIR/$TARGET_DIR/themes/apex/images"
+
+# Core and thematic code and styling
+mkdir -p "$REPO_DIR/$TARGET_DIR"
cp ./node_modules/oojs-ui/dist/oojs-ui-core.js{,.map} "$REPO_DIR/$TARGET_DIR"
cp ./node_modules/oojs-ui/dist/oojs-ui-core-{wikimediaui,apex}.css "$REPO_DIR/$TARGET_DIR"
cp ./node_modules/oojs-ui/dist/oojs-ui-widgets.js{,.map} "$REPO_DIR/$TARGET_DIR"
@@ -53,14 +52,38 @@ cp ./node_modules/oojs-ui/dist/oojs-ui-toolbars-{wikimediaui,apex}.css "$REPO_DI
cp ./node_modules/oojs-ui/dist/oojs-ui-windows.js{,.map} "$REPO_DIR/$TARGET_DIR"
cp ./node_modules/oojs-ui/dist/oojs-ui-windows-{wikimediaui,apex}.css "$REPO_DIR/$TARGET_DIR"
cp ./node_modules/oojs-ui/dist/oojs-ui-{wikimediaui,apex}.js{,.map} "$REPO_DIR/$TARGET_DIR"
+
+# i18n
+mkdir -p "$REPO_DIR/$TARGET_DIR/i18n"
cp -R ./node_modules/oojs-ui/dist/i18n "$REPO_DIR/$TARGET_DIR"
+
+# Core images (currently two .cur files)
+mkdir -p "$REPO_DIR/$TARGET_DIR/images"
cp -R ./node_modules/oojs-ui/dist/images "$REPO_DIR/$TARGET_DIR"
-cp -R ./node_modules/oojs-ui/dist/themes/wikimediaui/images "$REPO_DIR/$TARGET_DIR/themes/wikimediaui"
+
+# WikimediaUI theme icons, indicators, and textures
+mkdir -p "$REPO_DIR/$TARGET_DIR/themes/wikimediaui/images/icons"
+cp ./node_modules/oojs-ui/dist/themes/wikimediaui/images/icons/*.{svg,png} "$REPO_DIR/$TARGET_DIR/themes/wikimediaui/images/icons"
+mkdir -p "$REPO_DIR/$TARGET_DIR/themes/wikimediaui/images/indicators"
+cp ./node_modules/oojs-ui/dist/themes/wikimediaui/images/indicators/*.{svg,png} "$REPO_DIR/$TARGET_DIR/themes/wikimediaui/images/indicators"
+mkdir -p "$REPO_DIR/$TARGET_DIR/themes/wikimediaui/images/textures"
+cp ./node_modules/oojs-ui/dist/themes/wikimediaui/images/textures/*.{gif,svg} "$REPO_DIR/$TARGET_DIR/themes/wikimediaui/images/textures"
+
cp ./node_modules/oojs-ui/src/themes/wikimediaui/*.json "$REPO_DIR/$TARGET_DIR/themes/wikimediaui"
-cp -R ./node_modules/oojs-ui/dist/themes/apex/images "$REPO_DIR/$TARGET_DIR/themes/apex"
+
+# Apex theme icons, indicators, and textures
+mkdir -p "$REPO_DIR/$TARGET_DIR/themes/apex"
cp ./node_modules/oojs-ui/src/themes/apex/*.json "$REPO_DIR/$TARGET_DIR/themes/apex"
+
+# WikimediaUI LESS variables for sharing
cp ./node_modules/oojs-ui/dist/wikimedia-ui-base.less "$REPO_DIR/$TARGET_DIR"
+# Misc stuff
+cp ./node_modules/oojs-ui/dist/AUTHORS.txt "$REPO_DIR/$TARGET_DIR"
+cp ./node_modules/oojs-ui/dist/History.md "$REPO_DIR/$TARGET_DIR"
+cp ./node_modules/oojs-ui/dist/LICENSE-MIT "$REPO_DIR/$TARGET_DIR"
+cp ./node_modules/oojs-ui/dist/README.md "$REPO_DIR/$TARGET_DIR"
+
# Clean up temporary area
rm -rf "$NPM_DIR"
@@ -68,15 +91,15 @@ rm -rf "$NPM_DIR"
cd $REPO_DIR
COMMITMSG=$(cat <<END
-Update OOjs UI to v$OOJSUI_VERSION
+Update OOUI to v$OOUI_VERSION
Release notes:
- https://phabricator.wikimedia.org/diffusion/GOJU/browse/master/History.md;v$OOJSUI_VERSION
+ https://phabricator.wikimedia.org/diffusion/GOJU/browse/master/History.md;v$OOUI_VERSION
END
)
# Update composer.json as well
-composer require oojs/oojs-ui $OOJSUI_VERSION --no-update
+composer require oojs/oojs-ui $OOUI_VERSION --no-update
# Stage deletion, modification and creation of files. Then commit.
git add --update $TARGET_DIR
diff --git a/www/wiki/maintenance/rollbackEdits.php b/www/wiki/maintenance/rollbackEdits.php
index 5ad7d4e1..878eb9b0 100644
--- a/www/wiki/maintenance/rollbackEdits.php
+++ b/www/wiki/maintenance/rollbackEdits.php
@@ -50,7 +50,7 @@ class RollbackEdits extends Maintenance {
$user = $this->getOption( 'user' );
$username = User::isIP( $user ) ? $user : User::getCanonicalName( $user );
if ( !$username ) {
- $this->error( 'Invalid username', true );
+ $this->fatalError( 'Invalid username' );
}
$bot = $this->hasOption( 'bot' );
@@ -91,25 +91,31 @@ class RollbackEdits extends Maintenance {
/**
* Get all pages that should be rolled back for a given user
- * @param string $user A name to check against rev_user_text
+ * @param string $user A name to check against
* @return array
*/
private function getRollbackTitles( $user ) {
$dbr = $this->getDB( DB_REPLICA );
$titles = [];
- $results = $dbr->select(
- [ 'page', 'revision' ],
- [ 'page_namespace', 'page_title' ],
- [ 'page_latest = rev_id', 'rev_user_text' => $user ],
- __METHOD__
- );
- foreach ( $results as $row ) {
- $titles[] = Title::makeTitle( $row->page_namespace, $row->page_title );
+ $actorQuery = ActorMigration::newMigration()
+ ->getWhere( $dbr, 'rev_user', User::newFromName( $user, false ) );
+ foreach ( $actorQuery['orconds'] as $cond ) {
+ $results = $dbr->select(
+ [ 'page', 'revision' ] + $actorQuery['tables'],
+ [ 'page_namespace', 'page_title' ],
+ [ $cond ],
+ __METHOD__,
+ [],
+ [ 'revision' => [ 'JOIN', 'page_latest = rev_id' ] ] + $actorQuery['joins']
+ );
+ foreach ( $results as $row ) {
+ $titles[] = Title::makeTitle( $row->page_namespace, $row->page_title );
+ }
}
return $titles;
}
}
-$maintClass = 'RollbackEdits';
+$maintClass = RollbackEdits::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/runBatchedQuery.php b/www/wiki/maintenance/runBatchedQuery.php
index b0a2b924..64eca950 100644
--- a/www/wiki/maintenance/runBatchedQuery.php
+++ b/www/wiki/maintenance/runBatchedQuery.php
@@ -111,5 +111,5 @@ class BatchedQueryRunner extends Maintenance {
}
}
-$maintClass = "BatchedQueryRunner";
+$maintClass = BatchedQueryRunner::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/runJobs.php b/www/wiki/maintenance/runJobs.php
index 2e011fec..51c52be6 100644
--- a/www/wiki/maintenance/runJobs.php
+++ b/www/wiki/maintenance/runJobs.php
@@ -25,6 +25,9 @@ require_once __DIR__ . '/Maintenance.php';
use MediaWiki\Logger\LoggerFactory;
+// So extensions (and other code) can check whether they're running in job mode
+define( 'MEDIAWIKI_JOB_RUNNER', true );
+
/**
* Maintenance script that runs pending jobs.
*
@@ -39,7 +42,7 @@ class RunJobs extends Maintenance {
$this->addOption( 'type', 'Type of job to run', false, true );
$this->addOption( 'procs', 'Number of processes to use', false, true );
$this->addOption( 'nothrottle', 'Ignore job throttling configuration', false, false );
- $this->addOption( 'result', 'Set to JSON to print only a JSON response', false, true );
+ $this->addOption( 'result', 'Set to "json" to print only a JSON response', false, true );
$this->addOption( 'wait', 'Wait for new jobs instead of exiting', false, false );
}
@@ -56,7 +59,7 @@ class RunJobs extends Maintenance {
if ( $this->hasOption( 'procs' ) ) {
$procs = intval( $this->getOption( 'procs' ) );
if ( $procs < 1 || $procs > 1000 ) {
- $this->error( "Invalid argument to --procs", true );
+ $this->fatalError( "Invalid argument to --procs" );
} elseif ( $procs != 1 ) {
$fc = new ForkController( $procs );
if ( $fc->start() != 'child' ) {
@@ -115,5 +118,5 @@ class RunJobs extends Maintenance {
}
}
-$maintClass = "RunJobs";
+$maintClass = RunJobs::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/shell.php b/www/wiki/maintenance/shell.php
index 65c353a2..c8a8a452 100644
--- a/www/wiki/maintenance/shell.php
+++ b/www/wiki/maintenance/shell.php
@@ -58,7 +58,7 @@ class MediaWikiShell extends Maintenance {
public function execute() {
if ( !class_exists( \Psy\Shell::class ) ) {
- $this->error( 'PsySH not found. Please run composer with the --dev option.', 1 );
+ $this->fatalError( 'PsySH not found. Please run composer with the --dev option.' );
}
$traverser = new \PhpParser\NodeTraverser();
@@ -96,5 +96,5 @@ class MediaWikiShell extends Maintenance {
}
-$maintClass = 'MediaWikiShell';
+$maintClass = MediaWikiShell::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/showJobs.php b/www/wiki/maintenance/showJobs.php
index 0c68032e..b2fde8ed 100644
--- a/www/wiki/maintenance/showJobs.php
+++ b/www/wiki/maintenance/showJobs.php
@@ -105,5 +105,5 @@ class ShowJobs extends Maintenance {
}
}
-$maintClass = "ShowJobs";
+$maintClass = ShowJobs::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/showSiteStats.php b/www/wiki/maintenance/showSiteStats.php
index 5a151651..08f009bd 100644
--- a/www/wiki/maintenance/showSiteStats.php
+++ b/www/wiki/maintenance/showSiteStats.php
@@ -74,5 +74,5 @@ class ShowSiteStats extends Maintenance {
}
}
-$maintClass = "ShowSiteStats";
+$maintClass = ShowSiteStats::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/sql.php b/www/wiki/maintenance/sql.php
index 36e55f3e..e8b74481 100644
--- a/www/wiki/maintenance/sql.php
+++ b/www/wiki/maintenance/sql.php
@@ -24,6 +24,7 @@
require_once __DIR__ . '/Maintenance.php';
+use MediaWiki\MediaWikiServices;
use Wikimedia\Rdbms\ResultWrapper;
use Wikimedia\Rdbms\IDatabase;
use Wikimedia\Rdbms\DBQueryError;
@@ -40,6 +41,7 @@ class MwSql extends Maintenance {
'Takes a file name containing SQL as argument or runs interactively.' );
$this->addOption( 'query',
'Run a single query instead of running interactively', false, true );
+ $this->addOption( 'json', 'Output the results as JSON instead of PHP objects' );
$this->addOption( 'cluster', 'Use an external cluster by name', false, true );
$this->addOption( 'wikidb',
'The database wiki ID to use if not the current one', false, true );
@@ -53,10 +55,11 @@ class MwSql extends Maintenance {
// We wan't to allow "" for the wikidb, meaning don't call select_db()
$wiki = $this->hasOption( 'wikidb' ) ? $this->getOption( 'wikidb' ) : false;
// Get the appropriate load balancer (for this wiki)
+ $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
if ( $this->hasOption( 'cluster' ) ) {
- $lb = wfGetLBFactory()->getExternalLB( $this->getOption( 'cluster' ) );
+ $lb = $lbFactory->getExternalLB( $this->getOption( 'cluster' ) );
} else {
- $lb = wfGetLB( $wiki );
+ $lb = $lbFactory->getMainLB( $wiki );
}
// Figure out which server to use
$replicaDB = $this->getOption( 'replicadb', $this->getOption( 'slave', '' ) );
@@ -72,7 +75,7 @@ class MwSql extends Maintenance {
}
}
if ( $index === null ) {
- $this->error( "No replica DB server configured with the name '$replicaDB'.", 1 );
+ $this->fatalError( "No replica DB server configured with the name '$replicaDB'." );
}
} else {
$index = DB_MASTER;
@@ -81,7 +84,7 @@ class MwSql extends Maintenance {
/** @var IDatabase $db DB handle for the appropriate cluster/wiki */
$db = $lb->getConnection( $index, [], $wiki );
if ( $replicaDB != '' && $db->getLBInfo( 'master' ) !== null ) {
- $this->error( "The server selected ({$db->getServer()}) is not a replica DB.", 1 );
+ $this->fatalError( "The server selected ({$db->getServer()}) is not a replica DB." );
}
if ( $index === DB_MASTER ) {
@@ -92,12 +95,12 @@ class MwSql extends Maintenance {
if ( $this->hasArg( 0 ) ) {
$file = fopen( $this->getArg( 0 ), 'r' );
if ( !$file ) {
- $this->error( "Unable to open input file", true );
+ $this->fatalError( "Unable to open input file" );
}
$error = $db->sourceStream( $file, null, [ $this, 'sqlPrintResult' ] );
if ( $error !== true ) {
- $this->error( $error, true );
+ $this->fatalError( $error );
} else {
exit( 0 );
}
@@ -157,13 +160,17 @@ class MwSql extends Maintenance {
$res = $db->query( $line );
$this->sqlPrintResult( $res, $db );
} catch ( DBQueryError $e ) {
- $this->error( $e, $dieOnError );
+ if ( $dieOnError ) {
+ $this->fatalError( $e );
+ } else {
+ $this->error( $e );
+ }
}
}
/**
* Print the results, callback for $db->sourceStream()
- * @param ResultWrapper|bool $res The results object
+ * @param ResultWrapper|bool $res
* @param IDatabase $db
*/
public function sqlPrintResult( $res, $db ) {
@@ -171,9 +178,15 @@ class MwSql extends Maintenance {
// Do nothing
return;
} elseif ( is_object( $res ) && $res->numRows() ) {
+ $out = '';
foreach ( $res as $row ) {
- $this->output( print_r( $row, true ) );
+ $out .= print_r( $row, true );
+ $rows[] = $row;
+ }
+ if ( $this->hasOption( 'json' ) ) {
+ $out = json_encode( $rows, JSON_PRETTY_PRINT );
}
+ $this->output( $out . "\n" );
} else {
$affected = $db->affectedRows();
$this->output( "Query OK, $affected row(s) affected\n" );
@@ -188,5 +201,5 @@ class MwSql extends Maintenance {
}
}
-$maintClass = "MwSql";
+$maintClass = MwSql::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/sqlite.php b/www/wiki/maintenance/sqlite.php
index e74a86cf..bfd4d971 100644
--- a/www/wiki/maintenance/sqlite.php
+++ b/www/wiki/maintenance/sqlite.php
@@ -83,7 +83,7 @@ class SqliteMaintenance extends Maintenance {
private function vacuum() {
$prevSize = filesize( $this->db->getDbFilePath() );
if ( $prevSize == 0 ) {
- $this->error( "Can't vacuum an empty database.\n", true );
+ $this->fatalError( "Can't vacuum an empty database.\n" );
}
$this->output( 'VACUUM: ' );
@@ -117,12 +117,12 @@ class SqliteMaintenance extends Maintenance {
$this->db->query( 'BEGIN IMMEDIATE TRANSACTION', __METHOD__ );
$ourFile = $this->db->getDbFilePath();
$this->output( " Copying database file $ourFile to $fileName... " );
- MediaWiki\suppressWarnings( false );
+ Wikimedia\suppressWarnings();
if ( !copy( $ourFile, $fileName ) ) {
$err = error_get_last();
$this->error( " {$err['message']}" );
}
- MediaWiki\suppressWarnings( true );
+ Wikimedia\restoreWarnings();
$this->output( " Releasing lock...\n" );
$this->db->query( 'COMMIT TRANSACTION', __METHOD__ );
}
@@ -142,5 +142,5 @@ class SqliteMaintenance extends Maintenance {
}
}
-$maintClass = "SqliteMaintenance";
+$maintClass = SqliteMaintenance::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/sqlite/archives/initial-indexes.sql b/www/wiki/maintenance/sqlite/archives/initial-indexes.sql
index 2d0c9eea..f6c55fcb 100644
--- a/www/wiki/maintenance/sqlite/archives/initial-indexes.sql
+++ b/www/wiki/maintenance/sqlite/archives/initial-indexes.sql
@@ -441,7 +441,7 @@ CREATE INDEX /*i*/fa_group_key ON /*_*/filearchive (fa_storage_group, fa_storage
CREATE INDEX /*i*/fa_deleted_timestamp ON /*_*/filearchive (fa_deleted_timestamp);
CREATE INDEX /*i*/fa_user_timestamp ON /*_*/filearchive (fa_user_text,fa_timestamp);
CREATE INDEX /*i*/rc_timestamp ON /*_*/recentchanges (rc_timestamp);
-CREATE INDEX /*i*/rc_namespace_title ON /*_*/recentchanges (rc_namespace, rc_title);
+CREATE INDEX /*i*/rc_namespace_title_timestamp ON /*_*/recentchanges (rc_namespace, rc_title, rc_timestamp);
CREATE INDEX /*i*/rc_cur_id ON /*_*/recentchanges (rc_cur_id);
CREATE INDEX /*i*/new_name_timestamp ON /*_*/recentchanges (rc_new,rc_namespace,rc_timestamp);
CREATE INDEX /*i*/rc_ip ON /*_*/recentchanges (rc_ip);
diff --git a/www/wiki/maintenance/sqlite/archives/patch-actor-table.sql b/www/wiki/maintenance/sqlite/archives/patch-actor-table.sql
new file mode 100644
index 00000000..d9a018ef
--- /dev/null
+++ b/www/wiki/maintenance/sqlite/archives/patch-actor-table.sql
@@ -0,0 +1,368 @@
+--
+-- patch-actor-table.sql
+--
+-- T167246. Add an `actor` table and various columns (and temporary tables) to reference it.
+-- Sigh, sqlite, such trouble just to change the default value of a column.
+
+CREATE TABLE /*_*/actor (
+ actor_id bigint unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT,
+ actor_user int unsigned,
+ actor_name varchar(255) binary NOT NULL
+) /*$wgDBTableOptions*/;
+CREATE UNIQUE INDEX /*i*/actor_user ON /*_*/actor (actor_user);
+CREATE UNIQUE INDEX /*i*/actor_name ON /*_*/actor (actor_name);
+
+CREATE TABLE /*_*/revision_actor_temp (
+ revactor_rev int unsigned NOT NULL,
+ revactor_actor bigint unsigned NOT NULL,
+ revactor_timestamp binary(14) NOT NULL default '',
+ revactor_page int unsigned NOT NULL,
+ PRIMARY KEY (revactor_rev, revactor_actor)
+) /*$wgDBTableOptions*/;
+CREATE UNIQUE INDEX /*i*/revactor_rev ON /*_*/revision_actor_temp (revactor_rev);
+CREATE INDEX /*i*/actor_timestamp ON /*_*/revision_actor_temp (revactor_actor,revactor_timestamp);
+CREATE INDEX /*i*/page_actor_timestamp ON /*_*/revision_actor_temp (revactor_page,revactor_actor,revactor_timestamp);
+
+BEGIN;
+
+DROP TABLE IF EXISTS /*_*/archive_tmp;
+CREATE TABLE /*_*/archive_tmp (
+ ar_id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT,
+ ar_namespace int NOT NULL default 0,
+ ar_title varchar(255) binary NOT NULL default '',
+ ar_comment varbinary(767) NOT NULL default '',
+ ar_comment_id bigint unsigned NOT NULL DEFAULT 0,
+ ar_user int unsigned NOT NULL default 0,
+ ar_user_text varchar(255) binary NOT NULL DEFAULT '',
+ ar_actor bigint unsigned NOT NULL DEFAULT 0,
+ ar_timestamp binary(14) NOT NULL default '',
+ ar_minor_edit tinyint NOT NULL default 0,
+ ar_rev_id int unsigned,
+ ar_text_id int unsigned NOT NULL default 0,
+ ar_deleted tinyint unsigned NOT NULL default 0,
+ ar_len int unsigned,
+ ar_page_id int unsigned,
+ ar_parent_id int unsigned default NULL,
+ ar_sha1 varbinary(32) NOT NULL default '',
+ ar_content_model varbinary(32) DEFAULT NULL,
+ ar_content_format varbinary(64) DEFAULT NULL
+) /*$wgDBTableOptions*/;
+
+INSERT OR IGNORE INTO /*_*/archive_tmp (
+ ar_id, ar_namespace, ar_title, ar_comment, ar_user, ar_user_text,
+ ar_timestamp, ar_minor_edit, ar_rev_id, ar_text_id, ar_deleted, ar_len,
+ ar_page_id, ar_parent_id, ar_sha1, ar_content_model, ar_content_format)
+ SELECT
+ ar_id, ar_namespace, ar_title, ar_comment, ar_user, ar_user_text,
+ ar_timestamp, ar_minor_edit, ar_rev_id, ar_text_id, ar_deleted, ar_len,
+ ar_page_id, ar_parent_id, ar_sha1, ar_content_model, ar_content_format
+ FROM /*_*/archive;
+
+DROP TABLE /*_*/archive;
+ALTER TABLE /*_*/archive_tmp RENAME TO /*_*/archive;
+CREATE INDEX /*i*/name_title_timestamp ON /*_*/archive (ar_namespace,ar_title,ar_timestamp);
+CREATE INDEX /*i*/ar_usertext_timestamp ON /*_*/archive (ar_user_text,ar_timestamp);
+CREATE INDEX /*i*/ar_revid ON /*_*/archive (ar_rev_id);
+CREATE INDEX /*i*/ar_actor_timestamp ON /*_*/archive (ar_actor,ar_timestamp);
+
+COMMIT;
+
+BEGIN;
+
+DROP TABLE IF EXISTS ipblocks_tmp;
+CREATE TABLE /*_*/ipblocks_tmp (
+ ipb_id int NOT NULL PRIMARY KEY AUTO_INCREMENT,
+ ipb_address tinyblob NOT NULL,
+ ipb_user int unsigned NOT NULL default 0,
+ ipb_by int unsigned NOT NULL default 0,
+ ipb_by_text varchar(255) binary NOT NULL default '',
+ ipb_by_actor bigint unsigned NOT NULL DEFAULT 0,
+ ipb_reason varbinary(767) NOT NULL default '',
+ ipb_reason_id bigint unsigned NOT NULL DEFAULT 0,
+ ipb_timestamp binary(14) NOT NULL default '',
+ ipb_auto bool NOT NULL default 0,
+ ipb_anon_only bool NOT NULL default 0,
+ ipb_create_account bool NOT NULL default 1,
+ ipb_enable_autoblock bool NOT NULL default '1',
+ ipb_expiry varbinary(14) NOT NULL default '',
+ ipb_range_start tinyblob NOT NULL,
+ ipb_range_end tinyblob NOT NULL,
+ ipb_deleted bool NOT NULL default 0,
+ ipb_block_email bool NOT NULL default 0,
+ ipb_allow_usertalk bool NOT NULL default 0,
+ ipb_parent_block_id int default NULL
+) /*$wgDBTableOptions*/;
+
+INSERT OR IGNORE INTO /*_*/ipblocks_tmp (
+ ipb_id, ipb_address, ipb_user, ipb_by, ipb_by_text, ipb_reason,
+ ipb_timestamp, ipb_auto, ipb_anon_only, ipb_create_account,
+ ipb_enable_autoblock, ipb_expiry, ipb_range_start, ipb_range_end,
+ ipb_deleted, ipb_block_email, ipb_allow_usertalk, ipb_parent_block_id)
+ SELECT
+ ipb_id, ipb_address, ipb_user, ipb_by, ipb_by_text, ipb_reason,
+ ipb_timestamp, ipb_auto, ipb_anon_only, ipb_create_account,
+ ipb_enable_autoblock, ipb_expiry, ipb_range_start, ipb_range_end,
+ ipb_deleted, ipb_block_email, ipb_allow_usertalk, ipb_parent_block_id
+ FROM /*_*/ipblocks;
+
+DROP TABLE /*_*/ipblocks;
+ALTER TABLE /*_*/ipblocks_tmp RENAME TO /*_*/ipblocks;
+CREATE UNIQUE INDEX /*i*/ipb_address ON /*_*/ipblocks (ipb_address(255), ipb_user, ipb_auto, ipb_anon_only);
+CREATE INDEX /*i*/ipb_user ON /*_*/ipblocks (ipb_user);
+CREATE INDEX /*i*/ipb_range ON /*_*/ipblocks (ipb_range_start(8), ipb_range_end(8));
+CREATE INDEX /*i*/ipb_timestamp ON /*_*/ipblocks (ipb_timestamp);
+CREATE INDEX /*i*/ipb_expiry ON /*_*/ipblocks (ipb_expiry);
+CREATE INDEX /*i*/ipb_parent_block_id ON /*_*/ipblocks (ipb_parent_block_id);
+
+COMMIT;
+
+BEGIN;
+
+DROP TABLE IF EXISTS /*_*/image_tmp;
+CREATE TABLE /*_*/image_tmp (
+ img_name varchar(255) binary NOT NULL default '' PRIMARY KEY,
+ img_size int unsigned NOT NULL default 0,
+ img_width int NOT NULL default 0,
+ img_height int NOT NULL default 0,
+ img_metadata mediumblob NOT NULL,
+ img_bits int NOT NULL default 0,
+ img_media_type ENUM("UNKNOWN", "BITMAP", "DRAWING", "AUDIO", "VIDEO", "MULTIMEDIA", "OFFICE", "TEXT", "EXECUTABLE", "ARCHIVE") default NULL,
+ img_major_mime ENUM("unknown", "application", "audio", "image", "text", "video", "message", "model", "multipart", "chemical") NOT NULL default "unknown",
+ img_minor_mime varbinary(100) NOT NULL default "unknown",
+ img_description varbinary(767) NOT NULL default '',
+ img_description_id bigint unsigned NOT NULL DEFAULT 0,
+ img_user int unsigned NOT NULL default 0,
+ img_user_text varchar(255) binary NOT NULL DEFAULT '',
+ img_actor bigint unsigned NOT NULL DEFAULT 0,
+ img_timestamp varbinary(14) NOT NULL default '',
+ img_sha1 varbinary(32) NOT NULL default ''
+) /*$wgDBTableOptions*/;
+
+INSERT OR IGNORE INTO /*_*/image_tmp (
+ img_name, img_size, img_width, img_height, img_metadata, img_bits,
+ img_media_type, img_major_mime, img_minor_mime, img_description,
+ img_description_id, img_user, img_user_text, img_timestamp, img_sha1)
+ SELECT
+ img_name, img_size, img_width, img_height, img_metadata, img_bits,
+ img_media_type, img_major_mime, img_minor_mime, img_description,
+ img_description_id, img_user, img_user_text, img_timestamp, img_sha1
+ FROM /*_*/image;
+
+DROP TABLE /*_*/image;
+ALTER TABLE /*_*/image_tmp RENAME TO /*_*/image;
+CREATE INDEX /*i*/img_user_timestamp ON /*_*/image (img_user,img_timestamp);
+CREATE INDEX /*i*/img_usertext_timestamp ON /*_*/image (img_user_text,img_timestamp);
+CREATE INDEX /*i*/img_actor_timestamp ON /*_*/image (img_actor,img_timestamp);
+CREATE INDEX /*i*/img_size ON /*_*/image (img_size);
+CREATE INDEX /*i*/img_timestamp ON /*_*/image (img_timestamp);
+CREATE INDEX /*i*/img_sha1 ON /*_*/image (img_sha1(10));
+CREATE INDEX /*i*/img_media_mime ON /*_*/image (img_media_type,img_major_mime,img_minor_mime);
+
+COMMIT;
+
+BEGIN;
+
+DROP TABLE IF EXISTS /*_*/oldimage_tmp;
+CREATE TABLE /*_*/oldimage_tmp (
+ oi_name varchar(255) binary NOT NULL default '',
+ oi_archive_name varchar(255) binary NOT NULL default '',
+ oi_size int unsigned NOT NULL default 0,
+ oi_width int NOT NULL default 0,
+ oi_height int NOT NULL default 0,
+ oi_bits int NOT NULL default 0,
+ oi_description varbinary(767) NOT NULL default '',
+ oi_description_id bigint unsigned NOT NULL DEFAULT 0,
+ oi_user int unsigned NOT NULL default 0,
+ oi_user_text varchar(255) binary NOT NULL DEFAULT '',
+ oi_actor bigint unsigned NOT NULL DEFAULT 0,
+ oi_timestamp binary(14) NOT NULL default '',
+ oi_metadata mediumblob NOT NULL,
+ oi_media_type ENUM("UNKNOWN", "BITMAP", "DRAWING", "AUDIO", "VIDEO", "MULTIMEDIA", "OFFICE", "TEXT", "EXECUTABLE", "ARCHIVE") default NULL,
+ oi_major_mime ENUM("unknown", "application", "audio", "image", "text", "video", "message", "model", "multipart", "chemical") NOT NULL default "unknown",
+ oi_minor_mime varbinary(100) NOT NULL default "unknown",
+ oi_deleted tinyint unsigned NOT NULL default 0,
+ oi_sha1 varbinary(32) NOT NULL default ''
+) /*$wgDBTableOptions*/;
+
+INSERT OR IGNORE INTO /*_*/oldimage_tmp (
+ oi_name, oi_archive_name, oi_size, oi_width, oi_height, oi_bits,
+ oi_description, oi_user, oi_user_text, oi_timestamp, oi_metadata,
+ oi_media_type, oi_major_mime, oi_minor_mime, oi_deleted, oi_sha1)
+ SELECT
+ oi_name, oi_archive_name, oi_size, oi_width, oi_height, oi_bits,
+ oi_description, oi_user, oi_user_text, oi_timestamp, oi_metadata,
+ oi_media_type, oi_major_mime, oi_minor_mime, oi_deleted, oi_sha1
+ FROM /*_*/oldimage;
+
+DROP TABLE /*_*/oldimage;
+ALTER TABLE /*_*/oldimage_tmp RENAME TO /*_*/oldimage;
+CREATE INDEX /*i*/oi_usertext_timestamp ON /*_*/oldimage (oi_user_text,oi_timestamp);
+CREATE INDEX /*i*/oi_name_timestamp ON /*_*/oldimage (oi_name,oi_timestamp);
+CREATE INDEX /*i*/oi_name_archive_name ON /*_*/oldimage (oi_name,oi_archive_name(14));
+CREATE INDEX /*i*/oi_sha1 ON /*_*/oldimage (oi_sha1(10));
+CREATE INDEX /*i*/oi_actor_timestamp ON /*_*/oldimage (oi_actor,oi_timestamp);
+
+COMMIT;
+
+BEGIN;
+
+DROP TABLE IF EXISTS /*_*/filearchive_tmp;
+CREATE TABLE /*_*/filearchive_tmp (
+ fa_id int NOT NULL PRIMARY KEY AUTO_INCREMENT,
+ fa_name varchar(255) binary NOT NULL default '',
+ fa_archive_name varchar(255) binary default '',
+ fa_storage_group varbinary(16),
+ fa_storage_key varbinary(64) default '',
+ fa_deleted_user int,
+ fa_deleted_timestamp binary(14) default '',
+ fa_deleted_reason varbinary(767) default '',
+ fa_deleted_reason_id bigint unsigned NOT NULL DEFAULT 0,
+ fa_size int unsigned default 0,
+ fa_width int default 0,
+ fa_height int default 0,
+ fa_metadata mediumblob,
+ fa_bits int default 0,
+ fa_media_type ENUM("UNKNOWN", "BITMAP", "DRAWING", "AUDIO", "VIDEO", "MULTIMEDIA", "OFFICE", "TEXT", "EXECUTABLE", "ARCHIVE") default NULL,
+ fa_major_mime ENUM("unknown", "application", "audio", "image", "text", "video", "message", "model", "multipart", "chemical") default "unknown",
+ fa_minor_mime varbinary(100) default "unknown",
+ fa_description varbinary(767) default '',
+ fa_description_id bigint unsigned NOT NULL DEFAULT 0,
+ fa_user int unsigned default 0,
+ fa_user_text varchar(255) binary DEFAULT '',
+ fa_actor bigint unsigned NOT NULL DEFAULT 0,
+ fa_timestamp binary(14) default '',
+ fa_deleted tinyint unsigned NOT NULL default 0,
+ fa_sha1 varbinary(32) NOT NULL default ''
+) /*$wgDBTableOptions*/;
+
+INSERT OR IGNORE INTO /*_*/filearchive_tmp (
+ fa_id, fa_name, fa_archive_name, fa_storage_group, fa_storage_key,
+ fa_deleted_user, fa_deleted_timestamp, fa_deleted_reason, fa_size,
+ fa_width, fa_height, fa_metadata, fa_bits, fa_media_type, fa_major_mime,
+ fa_minor_mime, fa_description, fa_user, fa_user_text, fa_timestamp,
+ fa_deleted, fa_sha1)
+ SELECT
+ fa_id, fa_name, fa_archive_name, fa_storage_group, fa_storage_key,
+ fa_deleted_user, fa_deleted_timestamp, fa_deleted_reason, fa_size,
+ fa_width, fa_height, fa_metadata, fa_bits, fa_media_type, fa_major_mime,
+ fa_minor_mime, fa_description, fa_user, fa_user_text, fa_timestamp,
+ fa_deleted, fa_sha1
+ FROM /*_*/filearchive;
+
+DROP TABLE /*_*/filearchive;
+ALTER TABLE /*_*/filearchive_tmp RENAME TO /*_*/filearchive;
+CREATE INDEX /*i*/fa_name ON /*_*/filearchive (fa_name, fa_timestamp);
+CREATE INDEX /*i*/fa_storage_group ON /*_*/filearchive (fa_storage_group, fa_storage_key);
+CREATE INDEX /*i*/fa_deleted_timestamp ON /*_*/filearchive (fa_deleted_timestamp);
+CREATE INDEX /*i*/fa_user_timestamp ON /*_*/filearchive (fa_user_text,fa_timestamp);
+CREATE INDEX /*i*/fa_sha1 ON /*_*/filearchive (fa_sha1(10));
+CREATE INDEX /*i*/fa_actor_timestamp ON /*_*/filearchive (fa_actor,fa_timestamp);
+
+COMMIT;
+
+BEGIN;
+
+DROP TABLE IF EXISTS /*_*/logging_tmp;
+CREATE TABLE /*_*/logging_tmp (
+ log_id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT,
+ log_type varbinary(32) NOT NULL default '',
+ log_action varbinary(32) NOT NULL default '',
+ log_timestamp binary(14) NOT NULL default '19700101000000',
+ log_user int unsigned NOT NULL default 0,
+ log_user_text varchar(255) binary NOT NULL default '',
+ log_actor bigint unsigned NOT NULL DEFAULT 0,
+ log_namespace int NOT NULL default 0,
+ log_title varchar(255) binary NOT NULL default '',
+ log_page int unsigned NULL,
+ log_comment varbinary(767) NOT NULL default '',
+ log_comment_id bigint unsigned NOT NULL DEFAULT 0,
+ log_params blob NOT NULL,
+ log_deleted tinyint unsigned NOT NULL default 0
+) /*$wgDBTableOptions*/;
+
+INSERT OR IGNORE INTO /*_*/logging_tmp (
+ log_id, log_type, log_action, log_timestamp, log_user, log_user_text,
+ log_namespace, log_title, log_page, log_comment, log_comment_id,
+ log_params, log_deleted)
+ SELECT
+ log_id, log_type, log_action, log_timestamp, log_user, log_user_text,
+ log_namespace, log_title, log_page, log_comment, log_comment_id,
+ log_params, log_deleted
+ FROM /*_*/logging;
+
+DROP TABLE /*_*/logging;
+ALTER TABLE /*_*/logging_tmp RENAME TO /*_*/logging;
+CREATE INDEX /*i*/type_time ON /*_*/logging (log_type, log_timestamp);
+CREATE INDEX /*i*/user_time ON /*_*/logging (log_user, log_timestamp);
+CREATE INDEX /*i*/actor_time ON /*_*/logging (log_actor, log_timestamp);
+CREATE INDEX /*i*/page_time ON /*_*/logging (log_namespace, log_title, log_timestamp);
+CREATE INDEX /*i*/times ON /*_*/logging (log_timestamp);
+CREATE INDEX /*i*/log_user_type_time ON /*_*/logging (log_user, log_type, log_timestamp);
+CREATE INDEX /*i*/log_actor_type_time ON /*_*/logging (log_actor, log_type, log_timestamp);
+CREATE INDEX /*i*/log_page_id_time ON /*_*/logging (log_page,log_timestamp);
+CREATE INDEX /*i*/type_action ON /*_*/logging (log_type, log_action, log_timestamp);
+CREATE INDEX /*i*/log_user_text_type_time ON /*_*/logging (log_user_text, log_type, log_timestamp);
+CREATE INDEX /*i*/log_user_text_time ON /*_*/logging (log_user_text, log_timestamp);
+
+COMMIT;
+
+BEGIN;
+
+DROP TABLE IF EXISTS /*_*/recentchanges_tmp;
+CREATE TABLE /*_*/recentchanges_tmp (
+ rc_id int NOT NULL PRIMARY KEY AUTO_INCREMENT,
+ rc_timestamp varbinary(14) NOT NULL default '',
+ rc_user int unsigned NOT NULL default 0,
+ rc_user_text varchar(255) binary NOT NULL DEFAULT '',
+ rc_actor bigint unsigned NOT NULL DEFAULT 0,
+ rc_namespace int NOT NULL default 0,
+ rc_title varchar(255) binary NOT NULL default '',
+ rc_comment varbinary(767) NOT NULL default '',
+ rc_comment_id bigint unsigned NOT NULL DEFAULT 0,
+ rc_minor tinyint unsigned NOT NULL default 0,
+ rc_bot tinyint unsigned NOT NULL default 0,
+ rc_new tinyint unsigned NOT NULL default 0,
+ rc_cur_id int unsigned NOT NULL default 0,
+ rc_this_oldid int unsigned NOT NULL default 0,
+ rc_last_oldid int unsigned NOT NULL default 0,
+ rc_type tinyint unsigned NOT NULL default 0,
+ rc_source varchar(16) binary not null default '',
+ rc_patrolled tinyint unsigned NOT NULL default 0,
+ rc_ip varbinary(40) NOT NULL default '',
+ rc_old_len int,
+ rc_new_len int,
+ rc_deleted tinyint unsigned NOT NULL default 0,
+ rc_logid int unsigned NOT NULL default 0,
+ rc_log_type varbinary(255) NULL default NULL,
+ rc_log_action varbinary(255) NULL default NULL,
+ rc_params blob NULL
+) /*$wgDBTableOptions*/;
+
+INSERT OR IGNORE INTO /*_*/recentchanges_tmp (
+ rc_id, rc_timestamp, rc_user, rc_user_text, rc_namespace, rc_title,
+ rc_comment, rc_comment_id, rc_minor, rc_bot, rc_new, rc_cur_id,
+ rc_this_oldid, rc_last_oldid, rc_type, rc_source, rc_patrolled, rc_ip,
+ rc_old_len, rc_new_len, rc_deleted, rc_logid, rc_log_type, rc_log_action,
+ rc_params)
+ SELECT
+ rc_id, rc_timestamp, rc_user, rc_user_text, rc_namespace, rc_title,
+ rc_comment, rc_comment_id, rc_minor, rc_bot, rc_new, rc_cur_id,
+ rc_this_oldid, rc_last_oldid, rc_type, rc_source, rc_patrolled, rc_ip,
+ rc_old_len, rc_new_len, rc_deleted, rc_logid, rc_log_type, rc_log_action,
+ rc_params
+ FROM /*_*/recentchanges;
+
+DROP TABLE /*_*/recentchanges;
+ALTER TABLE /*_*/recentchanges_tmp RENAME TO /*_*/recentchanges;
+CREATE INDEX /*i*/rc_timestamp ON /*_*/recentchanges (rc_timestamp);
+CREATE INDEX /*i*/rc_namespace_title ON /*_*/recentchanges (rc_namespace, rc_title);
+CREATE INDEX /*i*/rc_cur_id ON /*_*/recentchanges (rc_cur_id);
+CREATE INDEX /*i*/new_name_timestamp ON /*_*/recentchanges (rc_new,rc_namespace,rc_timestamp);
+CREATE INDEX /*i*/rc_ip ON /*_*/recentchanges (rc_ip);
+CREATE INDEX /*i*/rc_ns_usertext ON /*_*/recentchanges (rc_namespace, rc_user_text);
+CREATE INDEX /*i*/rc_ns_actor ON /*_*/recentchanges (rc_namespace, rc_actor);
+CREATE INDEX /*i*/rc_user_text ON /*_*/recentchanges (rc_user_text, rc_timestamp);
+CREATE INDEX /*i*/rc_actor ON /*_*/recentchanges (rc_actor, rc_timestamp);
+CREATE INDEX /*i*/rc_name_type_patrolled_timestamp ON /*_*/recentchanges (rc_namespace, rc_type, rc_patrolled, rc_timestamp);
+
+COMMIT;
diff --git a/www/wiki/maintenance/sqlite/archives/patch-ar_rev_id-not-null.sql b/www/wiki/maintenance/sqlite/archives/patch-ar_rev_id-not-null.sql
new file mode 100644
index 00000000..86507516
--- /dev/null
+++ b/www/wiki/maintenance/sqlite/archives/patch-ar_rev_id-not-null.sql
@@ -0,0 +1,47 @@
+-- T182678: Make ar_rev_id not nullable
+
+BEGIN;
+
+DROP TABLE IF EXISTS /*_*/archive_tmp;
+CREATE TABLE /*_*/archive_tmp (
+ ar_id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT,
+ ar_namespace int NOT NULL default 0,
+ ar_title varchar(255) binary NOT NULL default '',
+ ar_comment varbinary(767) NOT NULL default '',
+ ar_comment_id bigint unsigned NOT NULL DEFAULT 0,
+ ar_user int unsigned NOT NULL default 0,
+ ar_user_text varchar(255) binary NOT NULL DEFAULT '',
+ ar_actor bigint unsigned NOT NULL DEFAULT 0,
+ ar_timestamp binary(14) NOT NULL default '',
+ ar_minor_edit tinyint NOT NULL default 0,
+ ar_rev_id int unsigned NOT NULL,
+ ar_text_id int unsigned NOT NULL default 0,
+ ar_deleted tinyint unsigned NOT NULL default 0,
+ ar_len int unsigned,
+ ar_page_id int unsigned,
+ ar_parent_id int unsigned default NULL,
+ ar_sha1 varbinary(32) NOT NULL default '',
+ ar_content_model varbinary(32) DEFAULT NULL,
+ ar_content_format varbinary(64) DEFAULT NULL
+) /*$wgDBTableOptions*/;
+
+INSERT OR IGNORE INTO /*_*/archive_tmp (
+ ar_id, ar_namespace, ar_title, ar_comment, ar_comment_id, ar_user,
+ ar_user_text, ar_actor, ar_timestamp, ar_minor_edit, ar_rev_id,
+ ar_text_id, ar_deleted, ar_len, ar_page_id, ar_parent_id, ar_sha1,
+ ar_content_model, ar_content_format)
+ SELECT
+ ar_id, ar_namespace, ar_title, ar_comment, ar_comment_id, ar_user,
+ ar_user_text, ar_actor, ar_timestamp, ar_minor_edit, ar_rev_id,
+ ar_text_id, ar_deleted, ar_len, ar_page_id, ar_parent_id, ar_sha1,
+ ar_content_model, ar_content_format
+ FROM /*_*/archive;
+
+DROP TABLE /*_*/archive;
+ALTER TABLE /*_*/archive_tmp RENAME TO /*_*/archive;
+CREATE INDEX /*i*/name_title_timestamp ON /*_*/archive (ar_namespace,ar_title,ar_timestamp);
+CREATE INDEX /*i*/ar_usertext_timestamp ON /*_*/archive (ar_user_text,ar_timestamp);
+CREATE INDEX /*i*/ar_actor_timestamp ON /*_*/archive (ar_actor,ar_timestamp);
+CREATE INDEX /*i*/ar_revid ON /*_*/archive (ar_rev_id);
+
+COMMIT;
diff --git a/www/wiki/maintenance/sqlite/archives/patch-drop-ar_text.sql b/www/wiki/maintenance/sqlite/archives/patch-drop-ar_text.sql
new file mode 100644
index 00000000..67bbece4
--- /dev/null
+++ b/www/wiki/maintenance/sqlite/archives/patch-drop-ar_text.sql
@@ -0,0 +1,44 @@
+-- T33223: Remove obsolete ar_text and ar_flags columns
+-- (and make ar_text_id not nullable and default 0)
+
+BEGIN;
+
+DROP TABLE IF EXISTS /*_*/archive_tmp;
+CREATE TABLE /*_*/archive_tmp (
+ ar_id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT,
+ ar_namespace int NOT NULL default 0,
+ ar_title varchar(255) binary NOT NULL default '',
+ ar_comment varbinary(767) NOT NULL default '',
+ ar_comment_id bigint unsigned NOT NULL DEFAULT 0,
+ ar_user int unsigned NOT NULL default 0,
+ ar_user_text varchar(255) binary NOT NULL,
+ ar_timestamp binary(14) NOT NULL default '',
+ ar_minor_edit tinyint NOT NULL default 0,
+ ar_rev_id int unsigned,
+ ar_text_id int unsigned NOT NULL default 0,
+ ar_deleted tinyint unsigned NOT NULL default 0,
+ ar_len int unsigned,
+ ar_page_id int unsigned,
+ ar_parent_id int unsigned default NULL,
+ ar_sha1 varbinary(32) NOT NULL default '',
+ ar_content_model varbinary(32) DEFAULT NULL,
+ ar_content_format varbinary(64) DEFAULT NULL
+) /*$wgDBTableOptions*/;
+
+INSERT OR IGNORE INTO /*_*/archive_tmp (
+ ar_id, ar_namespace, ar_title, ar_comment, ar_user, ar_user_text,
+ ar_timestamp, ar_minor_edit, ar_rev_id, ar_text_id, ar_deleted, ar_len,
+ ar_page_id, ar_parent_id, ar_sha1, ar_content_model, ar_content_format)
+ SELECT
+ ar_id, ar_namespace, ar_title, ar_comment, ar_user, ar_user_text,
+ ar_timestamp, ar_minor_edit, ar_rev_id, ar_text_id, ar_deleted, ar_len,
+ ar_page_id, ar_parent_id, ar_sha1, ar_content_model, ar_content_format
+ FROM /*_*/archive;
+
+DROP TABLE /*_*/archive;
+ALTER TABLE /*_*/archive_tmp RENAME TO /*_*/archive;
+CREATE INDEX /*i*/name_title_timestamp ON /*_*/archive (ar_namespace,ar_title,ar_timestamp);
+CREATE INDEX /*i*/ar_usertext_timestamp ON /*_*/archive (ar_user_text,ar_timestamp);
+CREATE INDEX /*i*/ar_revid ON /*_*/archive (ar_rev_id);
+
+COMMIT;
diff --git a/www/wiki/maintenance/sqlite/archives/patch-image-img_description_id.sql b/www/wiki/maintenance/sqlite/archives/patch-image-img_description_id.sql
new file mode 100644
index 00000000..dd8959e0
--- /dev/null
+++ b/www/wiki/maintenance/sqlite/archives/patch-image-img_description_id.sql
@@ -0,0 +1,47 @@
+--
+-- patch-image-img_description_id.sql
+--
+-- T188132. Add `img_description_id` to the `image` table.
+
+BEGIN;
+
+DROP TABLE IF EXISTS /*_*/image_tmp;
+CREATE TABLE /*_*/image_tmp (
+ img_name varchar(255) binary NOT NULL default '' PRIMARY KEY,
+ img_size int unsigned NOT NULL default 0,
+ img_width int NOT NULL default 0,
+ img_height int NOT NULL default 0,
+ img_metadata mediumblob NOT NULL,
+ img_bits int NOT NULL default 0,
+ img_media_type ENUM("UNKNOWN", "BITMAP", "DRAWING", "AUDIO", "VIDEO", "MULTIMEDIA", "OFFICE", "TEXT", "EXECUTABLE", "ARCHIVE", "3D") default NULL,
+ img_major_mime ENUM("unknown", "application", "audio", "image", "text", "video", "message", "model", "multipart", "chemical") NOT NULL default "unknown",
+ img_minor_mime varbinary(100) NOT NULL default "unknown",
+ img_description varbinary(767) NOT NULL default '',
+ img_description_id bigint unsigned NOT NULL DEFAULT 0,
+ img_user int unsigned NOT NULL default 0,
+ img_user_text varchar(255) binary NOT NULL default '',
+ img_timestamp varbinary(14) NOT NULL default '',
+ img_sha1 varbinary(32) NOT NULL default ''
+) /*$wgDBTableOptions*/;
+
+
+INSERT OR IGNORE INTO /*_*/image_tmp (
+ img_name, img_size, img_width, img_height, img_metadata, img_bits,
+ img_media_type, img_major_mime, img_minor_mime, img_description, img_user,
+ img_user_text, img_timestamp, img_sha1)
+ SELECT
+ img_name, img_size, img_width, img_height, img_metadata, img_bits,
+ img_media_type, img_major_mime, img_minor_mime, img_description, img_user,
+ img_user_text, img_timestamp, img_sha1
+ FROM /*_*/image;
+
+DROP TABLE /*_*/image;
+ALTER TABLE /*_*/image_tmp RENAME TO /*_*/image;
+CREATE INDEX /*i*/img_user_timestamp ON /*_*/image (img_user,img_timestamp);
+CREATE INDEX /*i*/img_usertext_timestamp ON /*_*/image (img_user_text,img_timestamp);
+CREATE INDEX /*i*/img_size ON /*_*/image (img_size);
+CREATE INDEX /*i*/img_timestamp ON /*_*/image (img_timestamp);
+CREATE INDEX /*i*/img_sha1 ON /*_*/image (img_sha1(10));
+CREATE INDEX /*i*/img_media_mime ON /*_*/image (img_media_type,img_major_mime,img_minor_mime);
+
+COMMIT;
diff --git a/www/wiki/maintenance/sqlite/archives/patch-imagelinks-fix-pk.sql b/www/wiki/maintenance/sqlite/archives/patch-imagelinks-fix-pk.sql
index b48bea53..3a37f415 100644
--- a/www/wiki/maintenance/sqlite/archives/patch-imagelinks-fix-pk.sql
+++ b/www/wiki/maintenance/sqlite/archives/patch-imagelinks-fix-pk.sql
@@ -11,8 +11,8 @@ CREATE TABLE /*_*/imagelinks_tmp (
PRIMARY KEY (il_from,il_to)
) /*$wgDBTableOptions*/;
-INSERT INTO /*_*/imagelinks_tmp
- SELECT * FROM /*_*/imagelinks;
+INSERT INTO /*_*/imagelinks_tmp (il_from, il_from_namespace, il_to)
+ SELECT il_from, il_from_namespace, il_to FROM /*_*/imagelinks;
DROP TABLE /*_*/imagelinks;
diff --git a/www/wiki/maintenance/sqlite/archives/patch-log_search-rename-index.sql b/www/wiki/maintenance/sqlite/archives/patch-log_search-rename-index.sql
deleted file mode 100644
index 4b98a0f2..00000000
--- a/www/wiki/maintenance/sqlite/archives/patch-log_search-rename-index.sql
+++ /dev/null
@@ -1 +0,0 @@
-CREATE UNIQUE INDEX ls_field_val ON /*_*/log_search (ls_field,ls_value,ls_log_id);
diff --git a/www/wiki/maintenance/sqlite/archives/patch-pagelinks-fix-pk.sql b/www/wiki/maintenance/sqlite/archives/patch-pagelinks-fix-pk.sql
index 0e845865..40fd51fa 100644
--- a/www/wiki/maintenance/sqlite/archives/patch-pagelinks-fix-pk.sql
+++ b/www/wiki/maintenance/sqlite/archives/patch-pagelinks-fix-pk.sql
@@ -13,8 +13,8 @@ CREATE TABLE /*_*/pagelinks_tmp (
PRIMARY KEY (pl_from,pl_namespace,pl_title)
) /*$wgDBTableOptions*/;
-INSERT INTO /*_*/pagelinks_tmp
- SELECT * FROM /*_*/pagelinks;
+INSERT INTO /*_*/pagelinks_tmp (pl_from, pl_from_namespace, pl_namespace, pl_title)
+ SELECT pl_from, pl_from_namespace, pl_namespace, pl_title FROM /*_*/pagelinks;
DROP TABLE /*_*/pagelinks;
diff --git a/www/wiki/maintenance/sqlite/archives/patch-recentchanges-nttindex.sql b/www/wiki/maintenance/sqlite/archives/patch-recentchanges-nttindex.sql
new file mode 100644
index 00000000..36840668
--- /dev/null
+++ b/www/wiki/maintenance/sqlite/archives/patch-recentchanges-nttindex.sql
@@ -0,0 +1,10 @@
+--
+-- patch-recentchanges-nttindex.sql
+--
+-- Per task T57377
+--
+-- Improve performance API queries to ask for a certain pages
+--
+
+DROP INDEX IF EXISTS /*i*/rc_namespace_title;
+CREATE INDEX IF NOT EXISTS /*i*/rc_namespace_title_timestamp ON /*_*/recentchanges (rc_namespace, rc_title, rc_timestamp);
diff --git a/www/wiki/maintenance/sqlite/archives/patch-rev_text_id-default.sql b/www/wiki/maintenance/sqlite/archives/patch-rev_text_id-default.sql
new file mode 100644
index 00000000..c8e032b4
--- /dev/null
+++ b/www/wiki/maintenance/sqlite/archives/patch-rev_text_id-default.sql
@@ -0,0 +1,53 @@
+--
+-- Adds a default value to the rev_text_id field in the revision table.
+-- This is to allow the Multi Content Revisions migration to happen where
+-- rows will have to be added to the revision table with no rev_text_id.
+--
+-- 2018-03-12
+--
+
+BEGIN TRANSACTION;
+
+DROP TABLE IF EXISTS /*_*/revision_tmp;
+
+CREATE TABLE /*_*/revision_tmp (
+ rev_id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT,
+ rev_page int unsigned NOT NULL,
+ rev_text_id int unsigned NOT NULL default 0,
+ rev_comment varbinary(767) NOT NULL default '',
+ rev_user int unsigned NOT NULL default 0,
+ rev_user_text varchar(255) binary NOT NULL default '',
+ rev_timestamp binary(14) NOT NULL default '',
+ rev_minor_edit tinyint unsigned NOT NULL default 0,
+ rev_deleted tinyint unsigned NOT NULL default 0,
+ rev_len int unsigned,
+ rev_parent_id int unsigned default NULL,
+ rev_sha1 varbinary(32) NOT NULL default '',
+ rev_content_model varbinary(32) DEFAULT NULL,
+ rev_content_format varbinary(64) DEFAULT NULL
+
+) /*$wgDBTableOptions*/ MAX_ROWS=10000000 AVG_ROW_LENGTH=1024;
+
+INSERT OR IGNORE INTO /*_*/revision_tmp (
+ rev_id, rev_page, rev_text_id, rev_comment, rev_user, rev_user_text,
+ rev_timestamp, rev_minor_edit, rev_deleted, rev_len, rev_parent_id,
+ rev_sha1, rev_content_model, rev_content_format
+ )
+ SELECT
+ rev_id, rev_page, rev_text_id, rev_comment, rev_user, rev_user_text,
+ rev_timestamp, rev_minor_edit, rev_deleted, rev_len, rev_parent_id,
+ rev_sha1, rev_content_model, rev_content_format
+ FROM /*_*/revision;
+
+DROP TABLE /*_*/revision;
+
+ALTER TABLE /*_*/revision_tmp RENAME TO /*_*/revision;
+
+CREATE INDEX /*i*/rev_page_id ON /*_*/revision (rev_page, rev_id);
+CREATE INDEX /*i*/rev_timestamp ON /*_*/revision (rev_timestamp);
+CREATE INDEX /*i*/page_timestamp ON /*_*/revision (rev_page,rev_timestamp);
+CREATE INDEX /*i*/user_timestamp ON /*_*/revision (rev_user,rev_timestamp);
+CREATE INDEX /*i*/usertext_timestamp ON /*_*/revision (rev_user_text,rev_timestamp);
+CREATE INDEX /*i*/page_user_timestamp ON /*_*/revision (rev_page,rev_user,rev_timestamp);
+
+COMMIT;
diff --git a/www/wiki/maintenance/sqlite/archives/patch-site_stats-modify.sql b/www/wiki/maintenance/sqlite/archives/patch-site_stats-modify.sql
new file mode 100644
index 00000000..8d267a62
--- /dev/null
+++ b/www/wiki/maintenance/sqlite/archives/patch-site_stats-modify.sql
@@ -0,0 +1,35 @@
+DROP TABLE IF EXISTS /*_*/site_stats_tmp;
+
+-- Create the temporary table. The following part
+-- is copied & pasted from the changed tables.sql
+-- file besides having an other table name.
+CREATE TABLE /*_*/site_stats_tmp (
+ ss_row_id int unsigned NOT NULL PRIMARY KEY,
+ ss_total_edits bigint unsigned default NULL,
+ ss_good_articles bigint unsigned default NULL,
+ ss_total_pages bigint unsigned default NULL,
+ ss_users bigint unsigned default NULL,
+ ss_active_users bigint unsigned default NULL,
+ ss_images bigint unsigned default NULL
+) /*$wgDBTableOptions*/;
+
+-- Move the data from the old to the new table
+INSERT OR IGNORE INTO /*_*/site_stats_tmp (
+ ss_row_id,
+ ss_total_edits,
+ ss_good_articles,
+ ss_total_pages,
+ ss_active_users,
+ ss_images
+) SELECT
+ ss_row_id,
+ ss_total_edits,
+ ss_good_articles,
+ ss_total_pages,
+ ss_active_users,
+ ss_images
+FROM /*_*/site_stats;
+
+DROP TABLE /*_*/site_stats;
+
+ALTER TABLE /*_*/site_stats_tmp RENAME TO /*_*/site_stats;
diff --git a/www/wiki/maintenance/sqlite/archives/patch-slot-origin.sql b/www/wiki/maintenance/sqlite/archives/patch-slot-origin.sql
new file mode 100644
index 00000000..f6d8ebf8
--- /dev/null
+++ b/www/wiki/maintenance/sqlite/archives/patch-slot-origin.sql
@@ -0,0 +1,34 @@
+--
+-- Replace slot_inherited with slot_origin.
+--
+-- NOTE: There is no release that has slot_inherited. This is only needed to transition between
+-- snapshot versions of 1.30.
+--
+-- NOTE: No code that writes to the slots table was merge yet, the table is assumed to be empty.
+--
+BEGIN TRANSACTION;
+
+DROP TABLE /*_*/slots;
+
+CREATE TABLE /*_*/slots (
+
+ -- reference to rev_id
+ slot_revision_id bigint unsigned NOT NULL,
+
+ -- reference to role_id
+ slot_role_id smallint unsigned NOT NULL,
+
+ -- reference to content_id
+ slot_content_id bigint unsigned NOT NULL,
+
+ -- The revision ID of the revision that originated the slot's content.
+ -- To find revisions that changed slots, look for slot_origin = slot_revision_id.
+ slot_origin bigint unsigned NOT NULL,
+
+ PRIMARY KEY ( slot_revision_id, slot_role_id )
+) /*$wgDBTableOptions*/;
+
+-- Index for finding revisions that modified a specific slot
+CREATE INDEX /*i*/slot_revision_origin_role ON /*_*/slots (slot_revision_id, slot_origin, slot_role_id);
+
+COMMIT TRANSACTION; \ No newline at end of file
diff --git a/www/wiki/maintenance/sqlite/archives/patch-templatelinks-fix-pk.sql b/www/wiki/maintenance/sqlite/archives/patch-templatelinks-fix-pk.sql
index 5f09f60d..e9bbab8e 100644
--- a/www/wiki/maintenance/sqlite/archives/patch-templatelinks-fix-pk.sql
+++ b/www/wiki/maintenance/sqlite/archives/patch-templatelinks-fix-pk.sql
@@ -13,8 +13,8 @@ CREATE TABLE /*_*/templatelinks_tmp (
PRIMARY KEY (tl_from,tl_namespace,tl_title)
) /*$wgDBTableOptions*/;
-INSERT INTO /*_*/templatelinks_tmp
- SELECT * FROM /*_*/templatelinks;
+INSERT INTO /*_*/templatelinks_tmp (tl_from, tl_from_namespace, tl_namespace, tl_title)
+ SELECT tl_from, tl_from_namespace, tl_namespace, tl_title FROM /*_*/templatelinks;
DROP TABLE /*_*/templatelinks;
diff --git a/www/wiki/maintenance/storage/checkStorage.php b/www/wiki/maintenance/storage/checkStorage.php
index 9045870d..f05be364 100644
--- a/www/wiki/maintenance/storage/checkStorage.php
+++ b/www/wiki/maintenance/storage/checkStorage.php
@@ -65,7 +65,7 @@ class CheckStorage {
} else {
print "Checking...\n";
}
- $maxRevId = $dbr->selectField( 'revision', 'MAX(rev_id)', false, __METHOD__ );
+ $maxRevId = $dbr->selectField( 'revision', 'MAX(rev_id)', '', __METHOD__ );
$chunkSize = 1000;
$flagStats = [];
$objectStats = [];
@@ -100,8 +100,12 @@ class CheckStorage {
$missingTextRows = array_flip( $this->oldIdMap );
$externalRevs = [];
$objectRevs = [];
- $res = $dbr->select( 'text', [ 'old_id', 'old_flags' ],
- 'old_id IN (' . implode( ',', $this->oldIdMap ) . ')', __METHOD__ );
+ $res = $dbr->select(
+ 'text',
+ [ 'old_id', 'old_flags' ],
+ [ 'old_id' => $this->oldIdMap ],
+ __METHOD__
+ );
foreach ( $res as $row ) {
/**
* @var $flags int
@@ -134,41 +138,48 @@ class CheckStorage {
// This is a known bug from 2004
// It's safe to just erase the old_flags field
if ( $fix ) {
- $this->error( 'fixed', "Warning: old_flags set to 0", $id );
+ $this->addError( 'fixed', "Warning: old_flags set to 0", $id );
$dbw = wfGetDB( DB_MASTER );
$dbw->ping();
$dbw->update( 'text', [ 'old_flags' => '' ],
[ 'old_id' => $id ], __METHOD__ );
echo "Fixed\n";
} else {
- $this->error( 'fixable', "Warning: old_flags set to 0", $id );
+ $this->addError( 'fixable', "Warning: old_flags set to 0", $id );
}
} elseif ( count( array_diff( $flagArray, $knownFlags ) ) ) {
- $this->error( 'unfixable', "Error: invalid flags field \"$flags\"", $id );
+ $this->addError( 'unfixable', "Error: invalid flags field \"$flags\"", $id );
}
}
$dbr->freeResult( $res );
// Output errors for any missing text rows
foreach ( $missingTextRows as $oldId => $revId ) {
- $this->error( 'restore revision', "Error: missing text row", $oldId );
+ $this->addError( 'restore revision', "Error: missing text row", $oldId );
}
// Verify external revisions
$externalConcatBlobs = [];
$externalNormalBlobs = [];
if ( count( $externalRevs ) ) {
- $res = $dbr->select( 'text', [ 'old_id', 'old_flags', 'old_text' ],
- [ 'old_id IN (' . implode( ',', $externalRevs ) . ')' ], __METHOD__ );
+ $res = $dbr->select(
+ 'text',
+ [ 'old_id', 'old_flags', 'old_text' ],
+ [ 'old_id' => $externalRevs ],
+ __METHOD__
+ );
foreach ( $res as $row ) {
$urlParts = explode( '://', $row->old_text, 2 );
if ( count( $urlParts ) !== 2 || $urlParts[1] == '' ) {
- $this->error( 'restore text', "Error: invalid URL \"{$row->old_text}\"", $row->old_id );
+ $this->addError( 'restore text', "Error: invalid URL \"{$row->old_text}\"", $row->old_id );
continue;
}
list( $proto, ) = $urlParts;
if ( $proto != 'DB' ) {
- $this->error( 'restore text', "Error: invalid external protocol \"$proto\"", $row->old_id );
+ $this->addError(
+ 'restore text',
+ "Error: invalid external protocol \"$proto\"",
+ $row->old_id );
continue;
}
$path = explode( '/', $row->old_text );
@@ -197,14 +208,19 @@ class CheckStorage {
$blobsTable = $this->dbStore->getTable( $extDb );
$res = $extDb->select( $blobsTable,
[ 'blob_id' ],
- [ 'blob_id IN( ' . implode( ',', $blobIds ) . ')' ], __METHOD__ );
+ [ 'blob_id' => $blobIds ],
+ __METHOD__
+ );
foreach ( $res as $row ) {
unset( $xBlobIds[$row->blob_id] );
}
$extDb->freeResult( $res );
// Print errors for missing blobs rows
foreach ( $xBlobIds as $blobId => $oldId ) {
- $this->error( 'restore text', "Error: missing target $blobId for one-part ES URL", $oldId );
+ $this->addError(
+ 'restore text',
+ "Error: missing target $blobId for one-part ES URL",
+ $oldId );
}
}
}
@@ -218,20 +234,20 @@ class CheckStorage {
$res = $dbr->select(
'text',
[ 'old_id', 'old_flags', "LEFT(old_text, $headerLength) AS header" ],
- [ 'old_id IN (' . implode( ',', $objectRevs ) . ')' ],
+ [ 'old_id' => $objectRevs ],
__METHOD__
);
foreach ( $res as $row ) {
$oldId = $row->old_id;
$matches = [];
if ( !preg_match( '/^O:(\d+):"(\w+)"/', $row->header, $matches ) ) {
- $this->error( 'restore text', "Error: invalid object header", $oldId );
+ $this->addError( 'restore text', "Error: invalid object header", $oldId );
continue;
}
$className = strtolower( $matches[2] );
if ( strlen( $className ) != $matches[1] ) {
- $this->error(
+ $this->addError(
'restore text',
"Error: invalid object header, wrong class name length",
$oldId
@@ -249,13 +265,13 @@ class CheckStorage {
case 'historyblobstub':
case 'historyblobcurstub':
if ( strlen( $row->header ) == $headerLength ) {
- $this->error( 'unfixable', "Error: overlong stub header", $oldId );
- continue;
+ $this->addError( 'unfixable', "Error: overlong stub header", $oldId );
+ break;
}
$stubObj = unserialize( $row->header );
if ( !is_object( $stubObj ) ) {
- $this->error( 'restore text', "Error: unable to unserialize stub object", $oldId );
- continue;
+ $this->addError( 'restore text', "Error: unable to unserialize stub object", $oldId );
+ break;
}
if ( $className == 'historyblobstub' ) {
$concatBlobs[$stubObj->mOldId][] = $oldId;
@@ -264,7 +280,7 @@ class CheckStorage {
}
break;
default:
- $this->error( 'unfixable', "Error: unrecognised object class \"$className\"", $oldId );
+ $this->addError( 'unfixable', "Error: unrecognised object class \"$className\"", $oldId );
}
}
$dbr->freeResult( $res );
@@ -277,7 +293,7 @@ class CheckStorage {
$res = $dbr->select(
'text',
[ 'old_id', 'old_flags', "LEFT(old_text, $headerLength) AS header" ],
- [ 'old_id IN (' . implode( ',', array_keys( $concatBlobs ) ) . ')' ],
+ [ 'old_id' => array_keys( $concatBlobs ) ],
__METHOD__
);
foreach ( $res as $row ) {
@@ -287,7 +303,7 @@ class CheckStorage {
if ( in_array( 'object', $flags ) ) {
$urlParts = explode( '/', $row->header );
if ( $urlParts[0] != 'DB:' ) {
- $this->error(
+ $this->addError(
'unfixable',
"Error: unrecognised external storage type \"{$urlParts[0]}",
$row->old_id
@@ -303,7 +319,7 @@ class CheckStorage {
);
}
} else {
- $this->error(
+ $this->addError(
'unfixable',
"Error: invalid flags \"{$row->old_flags}\" on concat bulk row {$row->old_id}",
$concatBlobs[$row->old_id] );
@@ -312,7 +328,7 @@ class CheckStorage {
substr( $row->header, 0, strlen( self::CONCAT_HEADER ) ),
self::CONCAT_HEADER
) ) {
- $this->error(
+ $this->addError(
'restore text',
"Error: Incorrect object header for concat bulk row {$row->old_id}",
$concatBlobs[$row->old_id]
@@ -357,7 +373,7 @@ class CheckStorage {
}
}
- function error( $type, $msg, $ids ) {
+ function addError( $type, $msg, $ids ) {
if ( is_array( $ids ) && count( $ids ) == 1 ) {
$ids = reset( $ids );
}
@@ -396,10 +412,12 @@ class CheckStorage {
$headerLength = strlen( self::CONCAT_HEADER );
$res = $extDb->select( $blobsTable,
[ 'blob_id', "LEFT(blob_text, $headerLength) AS header" ],
- [ 'blob_id IN( ' . implode( ',', $blobIds ) . ')' ], __METHOD__ );
+ [ 'blob_id' => $blobIds ],
+ __METHOD__
+ );
foreach ( $res as $row ) {
if ( strcasecmp( $row->header, self::CONCAT_HEADER ) ) {
- $this->error(
+ $this->addError(
'restore text',
"Error: invalid header on target $cluster/{$row->blob_id} of two-part ES URL",
$oldIds[$row->blob_id]
@@ -411,7 +429,7 @@ class CheckStorage {
// Print errors for missing blobs rows
foreach ( $oldIds as $blobId => $oldIds2 ) {
- $this->error(
+ $this->addError(
'restore text',
"Error: missing target $cluster/$blobId for two-part ES URL",
$oldIds2
@@ -475,6 +493,9 @@ class CheckStorage {
MediaWikiServices::getInstance()->getMainConfig()
);
$importer->setRevisionCallback( [ $this, 'importRevision' ] );
+ $importer->setNoticeCallback( function ( $msg, $params ) {
+ echo wfMessage( $msg, $params )->text() . "\n";
+ } );
$importer->doImport();
}
diff --git a/www/wiki/maintenance/storage/compressOld.php b/www/wiki/maintenance/storage/compressOld.php
index c17ce99c..a67e261e 100644
--- a/www/wiki/maintenance/storage/compressOld.php
+++ b/www/wiki/maintenance/storage/compressOld.php
@@ -103,8 +103,8 @@ class CompressOld extends Maintenance {
public function execute() {
global $wgDBname;
if ( !function_exists( "gzdeflate" ) ) {
- $this->error( "You must enable zlib support in PHP to compress old revisions!\n" .
- "Please see http://www.php.net/manual/en/ref.zlib.php\n", true );
+ $this->fatalError( "You must enable zlib support in PHP to compress old revisions!\n" .
+ "Please see http://www.php.net/manual/en/ref.zlib.php\n" );
}
$type = $this->getOption( 'type', 'concat' );
@@ -361,10 +361,9 @@ class CompressOld extends Maintenance {
$usedChunk = false;
$primaryOldid = $revs[$i]->rev_text_id;
- // @codingStandardsIgnoreStart Ignore avoid function calls in a FOR loop test part warning
# Get the text of each revision and add it to the object
+ // phpcs:ignore Generic.CodeAnalysis.ForLoopWithTestFunctionCall
for ( $j = 0; $j < $thisChunkSize && $chunk->isHappy(); $j++ ) {
- // @codingStandardsIgnoreEnd
$oldid = $revs[$i + $j]->rev_text_id;
# Get text
@@ -463,7 +462,6 @@ class CompressOld extends Maintenance {
$this->output( "/" );
$this->commitTransaction( $dbw, __METHOD__ );
$i += $thisChunkSize;
- wfWaitForSlaves();
}
$this->output( "\n" );
}
@@ -472,5 +470,5 @@ class CompressOld extends Maintenance {
}
}
-$maintClass = 'CompressOld';
+$maintClass = CompressOld::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/storage/dumpRev.php b/www/wiki/maintenance/storage/dumpRev.php
index 437bfcde..5a537aa6 100644
--- a/www/wiki/maintenance/storage/dumpRev.php
+++ b/www/wiki/maintenance/storage/dumpRev.php
@@ -43,7 +43,7 @@ class DumpRev extends Maintenance {
[ 'old_id=rev_text_id', 'rev_id' => $this->getArg() ]
);
if ( !$row ) {
- $this->error( "Row not found", true );
+ $this->fatalError( "Row not found" );
}
$flags = explode( ',', $row->old_flags );
@@ -84,5 +84,5 @@ class DumpRev extends Maintenance {
}
}
-$maintClass = "DumpRev";
+$maintClass = DumpRev::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/storage/fixBug20757.php b/www/wiki/maintenance/storage/fixBug20757.php
deleted file mode 100644
index 0ea52cab..00000000
--- a/www/wiki/maintenance/storage/fixBug20757.php
+++ /dev/null
@@ -1,351 +0,0 @@
-<?php
-/**
- * Script to fix bug 20757.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup Maintenance ExternalStorage
- */
-
-require_once __DIR__ . '/../Maintenance.php';
-
-/**
- * Maintenance script to fix bug 20757.
- *
- * @ingroup Maintenance ExternalStorage
- */
-class FixBug20757 extends Maintenance {
- public $batchSize = 10000;
- public $mapCache = [];
- public $mapCacheSize = 0;
- public $maxMapCacheSize = 1000000;
-
- function __construct() {
- parent::__construct();
- $this->addDescription( 'Script to fix bug 20757 assuming that blob_tracking is intact' );
- $this->addOption( 'dry-run', 'Report only' );
- $this->addOption( 'start', 'old_id to start at', false, true );
- }
-
- function execute() {
- $dbr = $this->getDB( DB_SLAVE );
- $dbw = $this->getDB( DB_MASTER );
-
- $dryRun = $this->getOption( 'dry-run' );
- if ( $dryRun ) {
- print "Dry run only.\n";
- }
-
- $startId = $this->getOption( 'start', 0 );
- $numGood = 0;
- $numFixed = 0;
- $numBad = 0;
-
- $totalRevs = $dbr->selectField( 'text', 'MAX(old_id)', false, __METHOD__ );
-
- if ( $dbr->getType() == 'mysql' ) {
- // In MySQL 4.1+, the binary field old_text has a non-working LOWER() function
- $lowerLeft = 'LOWER(CONVERT(LEFT(old_text,22) USING latin1))';
- }
-
- while ( true ) {
- print "ID: $startId / $totalRevs\r";
-
- $res = $dbr->select(
- 'text',
- [ 'old_id', 'old_flags', 'old_text' ],
- [
- 'old_id > ' . intval( $startId ),
- 'old_flags LIKE \'%object%\' AND old_flags NOT LIKE \'%external%\'',
- "$lowerLeft = 'o:15:\"historyblobstub\"'",
- ],
- __METHOD__,
- [
- 'ORDER BY' => 'old_id',
- 'LIMIT' => $this->batchSize,
- ]
- );
-
- if ( !$res->numRows() ) {
- break;
- }
-
- $secondaryIds = [];
- $stubs = [];
-
- foreach ( $res as $row ) {
- $startId = $row->old_id;
-
- // Basic sanity checks
- $obj = unserialize( $row->old_text );
- if ( $obj === false ) {
- print "{$row->old_id}: unrecoverable: cannot unserialize\n";
- ++$numBad;
- continue;
- }
-
- if ( !is_object( $obj ) ) {
- print "{$row->old_id}: unrecoverable: unserialized to type " .
- gettype( $obj ) . ", possible double-serialization\n";
- ++$numBad;
- continue;
- }
-
- if ( strtolower( get_class( $obj ) ) !== 'historyblobstub' ) {
- print "{$row->old_id}: unrecoverable: unexpected object class " .
- get_class( $obj ) . "\n";
- ++$numBad;
- continue;
- }
-
- // Process flags
- $flags = explode( ',', $row->old_flags );
- if ( in_array( 'utf-8', $flags ) || in_array( 'utf8', $flags ) ) {
- $legacyEncoding = false;
- } else {
- $legacyEncoding = true;
- }
-
- // Queue the stub for future batch processing
- $id = intval( $obj->mOldId );
- $secondaryIds[] = $id;
- $stubs[$row->old_id] = [
- 'legacyEncoding' => $legacyEncoding,
- 'secondaryId' => $id,
- 'hash' => $obj->mHash,
- ];
- }
-
- $secondaryIds = array_unique( $secondaryIds );
-
- if ( !count( $secondaryIds ) ) {
- continue;
- }
-
- // Run the batch query on blob_tracking
- $res = $dbr->select(
- 'blob_tracking',
- '*',
- [
- 'bt_text_id' => $secondaryIds,
- ],
- __METHOD__
- );
- $trackedBlobs = [];
- foreach ( $res as $row ) {
- $trackedBlobs[$row->bt_text_id] = $row;
- }
-
- // Process the stubs
- foreach ( $stubs as $primaryId => $stub ) {
- $secondaryId = $stub['secondaryId'];
- if ( !isset( $trackedBlobs[$secondaryId] ) ) {
- // No tracked blob. Work out what went wrong
- $secondaryRow = $dbr->selectRow(
- 'text',
- [ 'old_flags', 'old_text' ],
- [ 'old_id' => $secondaryId ],
- __METHOD__
- );
- if ( !$secondaryRow ) {
- print "$primaryId: unrecoverable: secondary row is missing\n";
- ++$numBad;
- } elseif ( $this->isUnbrokenStub( $stub, $secondaryRow ) ) {
- // Not broken yet, and not in the tracked clusters so it won't get
- // broken by the current RCT run.
- ++$numGood;
- } elseif ( strpos( $secondaryRow->old_flags, 'external' ) !== false ) {
- print "$primaryId: unrecoverable: secondary gone to {$secondaryRow->old_text}\n";
- ++$numBad;
- } else {
- print "$primaryId: unrecoverable: miscellaneous corruption of secondary row\n";
- ++$numBad;
- }
- unset( $stubs[$primaryId] );
- continue;
- }
- $trackRow = $trackedBlobs[$secondaryId];
-
- // Check that the specified text really is available in the tracked source row
- $url = "DB://{$trackRow->bt_cluster}/{$trackRow->bt_blob_id}/{$stub['hash']}";
- $text = ExternalStore::fetchFromURL( $url );
- if ( $text === false ) {
- print "$primaryId: unrecoverable: source text missing\n";
- ++$numBad;
- unset( $stubs[$primaryId] );
- continue;
- }
- if ( md5( $text ) !== $stub['hash'] ) {
- print "$primaryId: unrecoverable: content hashes do not match\n";
- ++$numBad;
- unset( $stubs[$primaryId] );
- continue;
- }
-
- // Find the page_id and rev_id
- // The page is probably the same as the page of the secondary row
- $pageId = intval( $trackRow->bt_page );
- if ( !$pageId ) {
- $revId = $pageId = 0;
- } else {
- $revId = $this->findTextIdInPage( $pageId, $primaryId );
- if ( !$revId ) {
- // Actually an orphan
- $pageId = $revId = 0;
- }
- }
-
- $newFlags = $stub['legacyEncoding'] ? 'external' : 'external,utf-8';
-
- if ( !$dryRun ) {
- // Reset the text row to point to the original copy
- $this->beginTransaction( $dbw, __METHOD__ );
- $dbw->update(
- 'text',
- // SET
- [
- 'old_flags' => $newFlags,
- 'old_text' => $url
- ],
- // WHERE
- [ 'old_id' => $primaryId ],
- __METHOD__
- );
-
- // Add a blob_tracking row so that the new reference can be recompressed
- // without needing to run trackBlobs.php again
- $dbw->insert( 'blob_tracking',
- [
- 'bt_page' => $pageId,
- 'bt_rev_id' => $revId,
- 'bt_text_id' => $primaryId,
- 'bt_cluster' => $trackRow->bt_cluster,
- 'bt_blob_id' => $trackRow->bt_blob_id,
- 'bt_cgz_hash' => $stub['hash'],
- 'bt_new_url' => null,
- 'bt_moved' => 0,
- ],
- __METHOD__
- );
- $this->commitTransaction( $dbw, __METHOD__ );
- $this->waitForSlaves();
- }
-
- print "$primaryId: resolved to $url\n";
- ++$numFixed;
- }
- }
-
- print "\n";
- print "Fixed: $numFixed\n";
- print "Unrecoverable: $numBad\n";
- print "Good stubs: $numGood\n";
- }
-
- function waitForSlaves() {
- static $iteration = 0;
- ++$iteration;
- if ( ++$iteration > 50 == 0 ) {
- wfWaitForSlaves();
- $iteration = 0;
- }
- }
-
- function findTextIdInPage( $pageId, $textId ) {
- $ids = $this->getRevTextMap( $pageId );
- if ( !isset( $ids[$textId] ) ) {
- return null;
- } else {
- return $ids[$textId];
- }
- }
-
- function getRevTextMap( $pageId ) {
- if ( !isset( $this->mapCache[$pageId] ) ) {
- // Limit cache size
- while ( $this->mapCacheSize > $this->maxMapCacheSize ) {
- $key = key( $this->mapCache );
- $this->mapCacheSize -= count( $this->mapCache[$key] );
- unset( $this->mapCache[$key] );
- }
-
- $dbr = $this->getDB( DB_SLAVE );
- $map = [];
- $res = $dbr->select( 'revision',
- [ 'rev_id', 'rev_text_id' ],
- [ 'rev_page' => $pageId ],
- __METHOD__
- );
- foreach ( $res as $row ) {
- $map[$row->rev_text_id] = $row->rev_id;
- }
- $this->mapCache[$pageId] = $map;
- $this->mapCacheSize += count( $map );
- }
-
- return $this->mapCache[$pageId];
- }
-
- /**
- * This is based on part of HistoryBlobStub::getText().
- * Determine if the text can be retrieved from the row in the normal way.
- * @param array $stub
- * @param stdClass $secondaryRow
- * @return bool
- */
- function isUnbrokenStub( $stub, $secondaryRow ) {
- $flags = explode( ',', $secondaryRow->old_flags );
- $text = $secondaryRow->old_text;
- if ( in_array( 'external', $flags ) ) {
- $url = $text;
- MediaWiki\suppressWarnings();
- list( /* $proto */, $path ) = explode( '://', $url, 2 );
- MediaWiki\restoreWarnings();
-
- if ( $path == "" ) {
- return false;
- }
- $text = ExternalStore::fetchFromURL( $url );
- }
- if ( !in_array( 'object', $flags ) ) {
- return false;
- }
-
- if ( in_array( 'gzip', $flags ) ) {
- $obj = unserialize( gzinflate( $text ) );
- } else {
- $obj = unserialize( $text );
- }
-
- if ( !is_object( $obj ) ) {
- // Correct for old double-serialization bug.
- $obj = unserialize( $obj );
- }
-
- if ( !is_object( $obj ) ) {
- return false;
- }
-
- $obj->uncompress();
- $text = $obj->getItem( $stub['hash'] );
-
- return $text !== false;
- }
-}
-
-$maintClass = 'FixBug20757';
-require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/storage/fixT22757.php b/www/wiki/maintenance/storage/fixT22757.php
index e8bd23d4..6bc2f988 100644
--- a/www/wiki/maintenance/storage/fixT22757.php
+++ b/www/wiki/maintenance/storage/fixT22757.php
@@ -55,7 +55,7 @@ class FixT22757 extends Maintenance {
$numFixed = 0;
$numBad = 0;
- $totalRevs = $dbr->selectField( 'text', 'MAX(old_id)', false, __METHOD__ );
+ $totalRevs = $dbr->selectField( 'text', 'MAX(old_id)', '', __METHOD__ );
// In MySQL 4.1+, the binary field old_text has a non-working LOWER() function
$lowerLeft = 'LOWER(CONVERT(LEFT(old_text,22) USING latin1))';
@@ -240,7 +240,6 @@ class FixT22757 extends Maintenance {
__METHOD__
);
$this->commitTransaction( $dbw, __METHOD__ );
- $this->waitForSlaves();
}
print "$primaryId: resolved to $url\n";
@@ -254,15 +253,6 @@ class FixT22757 extends Maintenance {
print "Good stubs: $numGood\n";
}
- function waitForSlaves() {
- static $iteration = 0;
- ++$iteration;
- if ( ++$iteration > 50 == 0 ) {
- wfWaitForSlaves();
- $iteration = 0;
- }
- }
-
function findTextIdInPage( $pageId, $textId ) {
$ids = $this->getRevTextMap( $pageId );
if ( !isset( $ids[$textId] ) ) {
@@ -310,9 +300,9 @@ class FixT22757 extends Maintenance {
$text = $secondaryRow->old_text;
if ( in_array( 'external', $flags ) ) {
$url = $text;
- MediaWiki\suppressWarnings();
+ Wikimedia\suppressWarnings();
list( /* $proto */, $path ) = explode( '://', $url, 2 );
- MediaWiki\restoreWarnings();
+ Wikimedia\restoreWarnings();
if ( $path == "" ) {
return false;
@@ -345,5 +335,5 @@ class FixT22757 extends Maintenance {
}
}
-$maintClass = 'FixT22757';
+$maintClass = FixT22757::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/storage/moveToExternal.php b/www/wiki/maintenance/storage/moveToExternal.php
index e1179920..9bb554c6 100644
--- a/www/wiki/maintenance/storage/moveToExternal.php
+++ b/www/wiki/maintenance/storage/moveToExternal.php
@@ -41,7 +41,7 @@ if ( !defined( 'MEDIAWIKI' ) ) {
if ( isset( $options['e'] ) ) {
$maxID = $options['e'];
} else {
- $maxID = $dbw->selectField( 'text', 'MAX(old_id)', false, $fname );
+ $maxID = $dbw->selectField( 'text', 'MAX(old_id)', '', $fname );
}
$minID = isset( $options['s'] ) ? $options['s'] : 1;
diff --git a/www/wiki/maintenance/storage/orphanStats.php b/www/wiki/maintenance/storage/orphanStats.php
index d7d0b84c..219b47c4 100644
--- a/www/wiki/maintenance/storage/orphanStats.php
+++ b/www/wiki/maintenance/storage/orphanStats.php
@@ -23,6 +23,8 @@
require_once __DIR__ . '/../Maintenance.php';
+use MediaWiki\MediaWikiServices;
+
/**
* Maintenance script that shows some statistics on the blob_orphans table,
* created with trackBlobs.php.
@@ -37,7 +39,8 @@ class OrphanStats extends Maintenance {
}
protected function &getDB( $cluster, $groups = [], $wiki = false ) {
- $lb = wfGetLBFactory()->getExternalLB( $cluster );
+ $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
+ $lb = $lbFactory->getExternalLB( $cluster );
return $lb->getConnection( DB_REPLICA );
}
@@ -45,9 +48,9 @@ class OrphanStats extends Maintenance {
public function execute() {
$dbr = $this->getDB( DB_REPLICA );
if ( !$dbr->tableExists( 'blob_orphans' ) ) {
- $this->error( "blob_orphans doesn't seem to exist, need to run trackBlobs.php first", true );
+ $this->fatalError( "blob_orphans doesn't seem to exist, need to run trackBlobs.php first" );
}
- $res = $dbr->select( 'blob_orphans', '*', false, __METHOD__ );
+ $res = $dbr->select( 'blob_orphans', '*', '', __METHOD__ );
$num = 0;
$totalSize = 0;
@@ -80,5 +83,5 @@ class OrphanStats extends Maintenance {
}
}
-$maintClass = "OrphanStats";
+$maintClass = OrphanStats::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/storage/recompressTracked.php b/www/wiki/maintenance/storage/recompressTracked.php
index c5dd53b1..49b8e0a6 100644
--- a/www/wiki/maintenance/storage/recompressTracked.php
+++ b/www/wiki/maintenance/storage/recompressTracked.php
@@ -114,8 +114,8 @@ class RecompressTracked {
$GLOBALS['wgDebugLogPrefix'] = "RCT {$this->replicaId}: ";
}
$this->pageBlobClass = function_exists( 'xdiff_string_bdiff' ) ?
- 'DiffHistoryBlob' : 'ConcatenatedGzipHistoryBlob';
- $this->orphanBlobClass = 'ConcatenatedGzipHistoryBlob';
+ DiffHistoryBlob::class : ConcatenatedGzipHistoryBlob::class;
+ $this->orphanBlobClass = ConcatenatedGzipHistoryBlob::class;
}
function debug( $msg ) {
@@ -236,9 +236,9 @@ class RecompressTracked {
[ 'file', 'php://stdout', 'w' ],
[ 'file', 'php://stderr', 'w' ]
];
- MediaWiki\suppressWarnings();
+ Wikimedia\suppressWarnings();
$proc = proc_open( "$cmd --replica-id $i", $spec, $pipes );
- MediaWiki\restoreWarnings();
+ Wikimedia\restoreWarnings();
if ( !$proc ) {
$this->critical( "Error opening replica DB process: $cmd" );
exit( 1 );
@@ -643,7 +643,8 @@ class RecompressTracked {
* @return Database
*/
function getExtDB( $cluster ) {
- $lb = wfGetLBFactory()->getExternalLB( $cluster );
+ $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
+ $lb = $lbFactory->getExternalLB( $cluster );
return $lb->getConnection( DB_MASTER );
}
diff --git a/www/wiki/maintenance/storage/resolveStubs.php b/www/wiki/maintenance/storage/resolveStubs.php
index 8ca8bb29..f9ec3987 100644
--- a/www/wiki/maintenance/storage/resolveStubs.php
+++ b/www/wiki/maintenance/storage/resolveStubs.php
@@ -38,7 +38,7 @@ function resolveStubs() {
$fname = 'resolveStubs';
$dbr = wfGetDB( DB_REPLICA );
- $maxID = $dbr->selectField( 'text', 'MAX(old_id)', false, $fname );
+ $maxID = $dbr->selectField( 'text', 'MAX(old_id)', '', $fname );
$blockSize = 10000;
$numBlocks = intval( $maxID / $blockSize ) + 1;
diff --git a/www/wiki/maintenance/storage/storageTypeStats.php b/www/wiki/maintenance/storage/storageTypeStats.php
index c23f5086..9ba3d1b9 100644
--- a/www/wiki/maintenance/storage/storageTypeStats.php
+++ b/www/wiki/maintenance/storage/storageTypeStats.php
@@ -25,7 +25,7 @@ class StorageTypeStats extends Maintenance {
function execute() {
$dbr = $this->getDB( DB_REPLICA );
- $endId = $dbr->selectField( 'text', 'MAX(old_id)', false, __METHOD__ );
+ $endId = $dbr->selectField( 'text', 'MAX(old_id)', '', __METHOD__ );
if ( !$endId ) {
echo "No text rows!\n";
exit( 1 );
@@ -111,5 +111,5 @@ SQL;
}
}
-$maintClass = 'StorageTypeStats';
+$maintClass = StorageTypeStats::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/storage/testCompression.php b/www/wiki/maintenance/storage/testCompression.php
index 90d8d031..c3ed4fce 100644
--- a/www/wiki/maintenance/storage/testCompression.php
+++ b/www/wiki/maintenance/storage/testCompression.php
@@ -45,19 +45,21 @@ if ( isset( $options['limit'] ) ) {
$limit = 1000;
$untilHappy = true;
}
-$type = isset( $options['type'] ) ? $options['type'] : 'ConcatenatedGzipHistoryBlob';
+$type = isset( $options['type'] ) ? $options['type'] : ConcatenatedGzipHistoryBlob::class;
$dbr = $this->getDB( DB_REPLICA );
+$revQuery = Revision::getQueryInfo( [ 'page', 'text' ] );
$res = $dbr->select(
- [ 'page', 'revision', 'text' ],
- '*',
+ $revQuery['tables'],
+ $revQuery['fields'],
[
'page_namespace' => $title->getNamespace(),
'page_title' => $title->getDBkey(),
- 'page_id=rev_page',
'rev_timestamp > ' . $dbr->addQuotes( $dbr->timestamp( $start ) ),
- 'rev_text_id=old_id'
- ], __FILE__, [ 'LIMIT' => $limit ]
+ ],
+ __FILE__,
+ [ 'LIMIT' => $limit ],
+ $revQuery['joins']
);
$blob = new $type;
diff --git a/www/wiki/maintenance/storage/trackBlobs.php b/www/wiki/maintenance/storage/trackBlobs.php
index b4514ecb..36b6f5b4 100644
--- a/www/wiki/maintenance/storage/trackBlobs.php
+++ b/www/wiki/maintenance/storage/trackBlobs.php
@@ -22,6 +22,7 @@
* @see wfWaitForSlaves()
*/
+use MediaWiki\MediaWikiServices;
use Wikimedia\Rdbms\DBConnectionError;
require __DIR__ . '/../commandLine.inc';
@@ -86,25 +87,6 @@ class TrackBlobs {
exit( 1 );
}
- // Scan the archive table for HistoryBlobStub objects or external flags (T24624)
- $flags = $dbr->selectField( 'archive', 'ar_flags',
- 'ar_flags LIKE \'%external%\' OR (' .
- 'ar_flags LIKE \'%object%\' ' .
- 'AND LOWER(CONVERT(LEFT(ar_text,22) USING latin1)) = \'o:15:"historyblobstub"\' )',
- __METHOD__
- );
-
- if ( strpos( $flags, 'external' ) !== false ) {
- echo "Integrity check failed: found external storage pointers in your archive table.\n" .
- "Run normaliseArchiveTable.php to fix this.\n";
- exit( 1 );
- } elseif ( $flags ) {
- echo "Integrity check failed: found HistoryBlobStub objects in your archive table.\n" .
- "These objects are probably already broken, continuing would make them\n" .
- "unrecoverable. Run \"normaliseArchiveTable.php --fix-cgz-bug\" to fix this.\n";
- exit( 1 );
- }
-
echo "Integrity check OK\n";
}
@@ -153,7 +135,7 @@ class TrackBlobs {
$textClause = $this->getTextClause();
$startId = 0;
- $endId = $dbr->selectField( 'revision', 'MAX(rev_id)', false, __METHOD__ );
+ $endId = $dbr->selectField( 'revision', 'MAX(rev_id)', '', __METHOD__ );
$batchesDone = 0;
$rowsInserted = 0;
@@ -229,7 +211,7 @@ class TrackBlobs {
$textClause = $this->getTextClause( $this->clusters );
$startId = 0;
- $endId = $dbr->selectField( 'text', 'MAX(old_id)', false, __METHOD__ );
+ $endId = $dbr->selectField( 'text', 'MAX(old_id)', '', __METHOD__ );
$rowsInserted = 0;
$batchesDone = 0;
@@ -317,7 +299,8 @@ class TrackBlobs {
foreach ( $this->clusters as $cluster ) {
echo "Searching for orphan blobs in $cluster...\n";
- $lb = wfGetLBFactory()->getExternalLB( $cluster );
+ $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
+ $lb = $lbFactory->getExternalLB( $cluster );
try {
$extDB = $lb->getConnection( DB_REPLICA );
} catch ( DBConnectionError $e ) {
@@ -339,7 +322,7 @@ class TrackBlobs {
$startId = 0;
$batchesDone = 0;
$actualBlobs = gmp_init( 0 );
- $endId = $extDB->selectField( $table, 'MAX(blob_id)', false, __METHOD__ );
+ $endId = $extDB->selectField( $table, 'MAX(blob_id)', '', __METHOD__ );
// Build a bitmap of actual blob rows
while ( true ) {
diff --git a/www/wiki/maintenance/syncFileBackend.php b/www/wiki/maintenance/syncFileBackend.php
index 82149a6d..49627c3e 100644
--- a/www/wiki/maintenance/syncFileBackend.php
+++ b/www/wiki/maintenance/syncFileBackend.php
@@ -54,7 +54,7 @@ class SyncFileBackend extends Maintenance {
if ( $this->hasOption( 'posdump' ) ) {
// Just dump the current position into the specified position dir
if ( !$this->hasOption( 'posdir' ) ) {
- $this->error( "Param posdir required!", 1 );
+ $this->fatalError( "Param posdir required!" );
}
if ( $this->hasOption( 'postime' ) ) {
$id = (int)$src->getJournal()->getPositionAtTime( $this->getOption( 'postime' ) );
@@ -76,7 +76,7 @@ class SyncFileBackend extends Maintenance {
}
if ( !$this->hasOption( 'dst' ) ) {
- $this->error( "Param dst required!", 1 );
+ $this->fatalError( "Param dst required!" );
}
$dst = FileBackendGroup::singleton()->get( $this->getOption( 'dst' ) );
@@ -156,12 +156,12 @@ class SyncFileBackend extends Maintenance {
$first = true; // first batch
if ( $start > $end ) { // sanity
- $this->error( "Error: given starting ID greater than ending ID.", 1 );
+ $this->fatalError( "Error: given starting ID greater than ending ID." );
}
$next = null;
do {
- $limit = min( $this->mBatchSize, $end - $start + 1 ); // don't go pass ending ID
+ $limit = min( $this->getBatchSize(), $end - $start + 1 ); // don't go pass ending ID
$this->output( "Doing id $start to " . ( $start + $limit - 1 ) . "...\n" );
$entries = $src->getJournal()->getChangeEntries( $start, $limit, $next );
@@ -303,5 +303,5 @@ class SyncFileBackend extends Maintenance {
}
}
-$maintClass = "SyncFileBackend";
+$maintClass = SyncFileBackend::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/tables.sql b/www/wiki/maintenance/tables.sql
index 1813f6cd..df3264a4 100644
--- a/www/wiki/maintenance/tables.sql
+++ b/www/wiki/maintenance/tables.sql
@@ -141,6 +141,28 @@ CREATE INDEX /*i*/user_email ON /*_*/user (user_email(50));
--
+-- The "actor" table associates user names or IP addresses with integers for
+-- the benefit of other tables that need to refer to either logged-in or
+-- logged-out users. If something can only ever be done by logged-in users, it
+-- can refer to the user table directly.
+--
+CREATE TABLE /*_*/actor (
+ -- Unique ID to identify each actor
+ actor_id bigint unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT,
+
+ -- Key to user.user_id, or NULL for anonymous edits.
+ actor_user int unsigned,
+
+ -- Text username or IP address
+ actor_name varchar(255) binary NOT NULL
+) /*$wgDBTableOptions*/;
+
+-- User IDs and names must be unique.
+CREATE UNIQUE INDEX /*i*/actor_user ON /*_*/actor (actor_user);
+CREATE UNIQUE INDEX /*i*/actor_name ON /*_*/actor (actor_name);
+
+
+--
-- User permissions have been broken out to a separate table;
-- this allows sites with a shared user table to have different
-- permissions assigned to a user in each project.
@@ -343,7 +365,10 @@ CREATE TABLE /*_*/revision (
-- It's possible for multiple revisions to use the same text,
-- for instance revisions where only metadata is altered
-- or a rollback to a previous version.
- rev_text_id int unsigned NOT NULL,
+ -- @deprecated since 1.31. If rows in the slots table with slot_revision_id = rev_id
+ -- exist, this field should be ignored (and may be 0) in favor of the
+ -- corresponding data from the slots and content tables
+ rev_text_id int unsigned NOT NULL default 0,
-- Text comment summarizing the change. Deprecated in favor of
-- revision_comment_temp.revcomment_comment_id.
@@ -351,9 +376,11 @@ CREATE TABLE /*_*/revision (
-- Key to user.user_id of the user who made this edit.
-- Stores 0 for anonymous edits and for some mass imports.
+ -- Deprecated in favor of revision_actor_temp.revactor_actor.
rev_user int unsigned NOT NULL default 0,
-- Text username or IP address of the editor.
+ -- Deprecated in favor of revision_actor_temp.revactor_actor.
rev_user_text varchar(255) binary NOT NULL default '',
-- Timestamp of when revision was created
@@ -377,9 +404,14 @@ CREATE TABLE /*_*/revision (
rev_sha1 varbinary(32) NOT NULL default '',
-- content model, see CONTENT_MODEL_XXX constants
+ -- @deprecated since 1.31. If rows in the slots table with slot_revision_id = rev_id
+ -- exist, this field should be ignored (and may be NULL) in favor of the
+ -- corresponding data from the slots and content tables
rev_content_model varbinary(32) DEFAULT NULL,
-- content format, see CONTENT_FORMAT_XXX constants
+ -- @deprecated since 1.31. If rows in the slots table with slot_revision_id = rev_id
+ -- exist, this field should be ignored (and may be NULL).
rev_content_format varbinary(64) DEFAULT NULL
) /*$wgDBTableOptions*/ MAX_ROWS=10000000 AVG_ROW_LENGTH=1024;
@@ -426,6 +458,29 @@ CREATE TABLE /*_*/revision_comment_temp (
CREATE UNIQUE INDEX /*i*/revcomment_rev ON /*_*/revision_comment_temp (revcomment_rev);
--
+-- Temporary table to avoid blocking on an alter of revision.
+--
+-- On large wikis like the English Wikipedia, altering the revision table is a
+-- months-long process. This table is being created to avoid such an alter, and
+-- will be merged back into revision in the future.
+--
+CREATE TABLE /*_*/revision_actor_temp (
+ -- Key to rev_id
+ revactor_rev int unsigned NOT NULL,
+ -- Key to actor_id
+ revactor_actor bigint unsigned NOT NULL,
+ -- Copy fields from revision for indexes
+ revactor_timestamp binary(14) NOT NULL default '',
+ revactor_page int unsigned NOT NULL,
+ PRIMARY KEY (revactor_rev, revactor_actor)
+) /*$wgDBTableOptions*/;
+-- Ensure uniqueness
+CREATE UNIQUE INDEX /*i*/revactor_rev ON /*_*/revision_actor_temp (revactor_rev);
+-- Match future indexes on revision
+CREATE INDEX /*i*/actor_timestamp ON /*_*/revision_actor_temp (revactor_actor,revactor_timestamp);
+CREATE INDEX /*i*/page_actor_timestamp ON /*_*/revision_actor_temp (revactor_page,revactor_actor,revactor_timestamp);
+
+--
-- Every time an edit by a logged out user is saved,
-- a row is created in ip_changes. This stores
-- the IP as a hex representation so that we can more
@@ -525,79 +580,81 @@ CREATE INDEX /*i*/comment_hash ON /*_*/comment (comment_hash);
--
--- Holding area for deleted articles, which may be viewed
--- or restored by admins through the Special:Undelete interface.
--- The fields generally correspond to the page, revision, and text
--- fields, with several caveats.
+-- Archive area for deleted pages and their revisions.
+-- These may be viewed (and restored) by admins through the Special:Undelete interface.
--
CREATE TABLE /*_*/archive (
-- Primary key
ar_id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT,
+
+ -- Copied from page_namespace
ar_namespace int NOT NULL default 0,
+ -- Copied from page_title
ar_title varchar(255) binary NOT NULL default '',
- -- Newly deleted pages will not store text in this table,
- -- but will reference the separately existing text rows.
- -- This field is retained for backwards compatibility,
- -- so old archived pages will remain accessible after
- -- upgrading from 1.4 to 1.5.
- -- Text may be gzipped or otherwise funky.
- ar_text mediumblob NOT NULL,
-
-- Basic revision stuff...
ar_comment varbinary(767) NOT NULL default '', -- Deprecated in favor of ar_comment_id
ar_comment_id bigint unsigned NOT NULL DEFAULT 0, -- ("DEFAULT 0" is temporary, signaling that ar_comment should be used)
- ar_user int unsigned NOT NULL default 0,
- ar_user_text varchar(255) binary NOT NULL,
+ ar_user int unsigned NOT NULL default 0, -- Deprecated in favor of ar_actor
+ ar_user_text varchar(255) binary NOT NULL DEFAULT '', -- Deprecated in favor of ar_actor
+ ar_actor bigint unsigned NOT NULL DEFAULT 0, -- ("DEFAULT 0" is temporary, signaling that ar_user/ar_user_text should be used)
ar_timestamp binary(14) NOT NULL default '',
ar_minor_edit tinyint NOT NULL default 0,
- -- See ar_text note.
- ar_flags tinyblob NOT NULL,
-
- -- When revisions are deleted, their unique rev_id is stored
- -- here so it can be retained after undeletion. This is necessary
- -- to retain permalinks to given revisions after accidental delete
- -- cycles or messy operations like history merges.
+ -- Copied from rev_id.
--
- -- Old entries from 1.4 will be NULL here, and a new rev_id will
- -- be created on undeletion for those revisions.
- ar_rev_id int unsigned,
-
- -- For newly deleted revisions, this is the text.old_id key to the
- -- actual stored text. To avoid breaking the block-compression scheme
- -- and otherwise making storage changes harder, the actual text is
- -- *not* deleted from the text table, merely hidden by removal of the
- -- page and revision entries.
+ -- @since 1.5 Entries from 1.4 will be NULL here. When restoring
+ -- archive rows from before 1.5, a new rev_id is created.
+ ar_rev_id int unsigned NOT NULL,
+
+ -- Copied from rev_text_id, references text.old_id.
+ -- To avoid breaking the block-compression scheme and otherwise making
+ -- storage changes harder, the actual text is *not* deleted from the
+ -- text storage. Instead, it is merely hidden from public view, by removal
+ -- of the page and revision entries.
--
- -- Old entries deleted under 1.2-1.4 will have NULL here, and their
- -- ar_text and ar_flags fields will be used to create a new text
- -- row upon undeletion.
- ar_text_id int unsigned,
-
- -- rev_deleted for archives
+ -- @deprecated since 1.31. If rows in the slots table with slot_revision_id = ar_rev_id
+ -- exist, this field should be ignored (and may be 0) in favor of the
+ -- corresponding data from the slots and content tables
+ ar_text_id int unsigned NOT NULL DEFAULT 0,
+
+ -- Copied from rev_deleted. Although this may be raised during deletion.
+ -- Users with the "suppressrevision" right may "archive" and "suppress"
+ -- content in a single action.
+ -- @since 1.10
ar_deleted tinyint unsigned NOT NULL default 0,
- -- Length of this revision in bytes
+ -- Copied from rev_len, length of this revision in bytes.
+ -- @since 1.10
ar_len int unsigned,
- -- Reference to page_id. Useful for sysadmin fixing of large pages
- -- merged together in the archives, or for cleanly restoring a page
- -- at its original ID number if possible.
+ -- Copied from page_id. Restoration will attempt to use this as page ID if
+ -- no current page with the same name exists. Otherwise, the revisions will
+ -- be restored under the current page. Can be used for manual undeletion by
+ -- developers if multiple pages by the same name were archived.
--
- -- Will be NULL for pages deleted prior to 1.11.
+ -- @since 1.11 Older entries will have NULL.
ar_page_id int unsigned,
- -- Original previous revision
+ -- Copied from rev_parent_id.
+ -- @since 1.13
ar_parent_id int unsigned default NULL,
- -- SHA-1 text content hash in base-36
+ -- Copied from rev_sha1, SHA-1 text content hash in base-36
+ -- @since 1.19
ar_sha1 varbinary(32) NOT NULL default '',
- -- content model, see CONTENT_MODEL_XXX constants
+ -- Copied from rev_content_model, see CONTENT_MODEL_XXX constants
+ -- @since 1.21
+ -- @deprecated since 1.31. If rows in the slots table with slot_revision_id = ar_rev_id
+ -- exist, this field should be ignored (and may be NULL) in favor of the
+ -- corresponding data from the slots and content tables
ar_content_model varbinary(32) DEFAULT NULL,
- -- content format, see CONTENT_FORMAT_XXX constants
+ -- Copied from rev_content_format, see CONTENT_FORMAT_XXX constants
+ -- @since 1.21
+ -- @deprecated since 1.31. If rows in the slots table with slot_revision_id = ar_rev_id
+ -- exist, this field should be ignored (and may be NULL).
ar_content_format varbinary(64) DEFAULT NULL
) /*$wgDBTableOptions*/;
@@ -606,11 +663,83 @@ CREATE INDEX /*i*/name_title_timestamp ON /*_*/archive (ar_namespace,ar_title,ar
-- Index for Special:DeletedContributions
CREATE INDEX /*i*/ar_usertext_timestamp ON /*_*/archive (ar_user_text,ar_timestamp);
+CREATE INDEX /*i*/ar_actor_timestamp ON /*_*/archive (ar_actor,ar_timestamp);
-- Index for linking archive rows with tables that normally link with revision
-- rows, such as change_tag.
CREATE INDEX /*i*/ar_revid ON /*_*/archive (ar_rev_id);
+--
+-- Slots represent an n:m relation between revisions and content objects.
+-- A content object can have a specific "role" in one or more revisions.
+-- Each revision can have multiple content objects, each having a different role.
+--
+CREATE TABLE /*_*/slots (
+
+ -- reference to rev_id or ar_rev_id
+ slot_revision_id bigint unsigned NOT NULL,
+
+ -- reference to role_id
+ slot_role_id smallint unsigned NOT NULL,
+
+ -- reference to content_id
+ slot_content_id bigint unsigned NOT NULL,
+
+ -- The revision ID of the revision that originated the slot's content.
+ -- To find revisions that changed slots, look for slot_origin = slot_revision_id.
+ slot_origin bigint unsigned NOT NULL,
+
+ PRIMARY KEY ( slot_revision_id, slot_role_id )
+) /*$wgDBTableOptions*/;
+
+-- Index for finding revisions that modified a specific slot
+CREATE INDEX /*i*/slot_revision_origin_role ON /*_*/slots (slot_revision_id, slot_origin, slot_role_id);
+
+--
+-- The content table represents content objects. It's primary purpose is to provide the necessary
+-- meta-data for loading and interpreting a serialized data blob to create a content object.
+--
+CREATE TABLE /*_*/content (
+
+ -- ID of the content object
+ content_id bigint unsigned PRIMARY KEY AUTO_INCREMENT,
+
+ -- Nominal size of the content object (not necessarily of the serialized blob)
+ content_size int unsigned NOT NULL,
+
+ -- Nominal hash of the content object (not necessarily of the serialized blob)
+ content_sha1 varbinary(32) NOT NULL,
+
+ -- reference to model_id. Note the content format isn't specified; it should
+ -- be assumed to be in the default format for the model unless auto-detected
+ -- otherwise.
+ content_model smallint unsigned NOT NULL,
+
+ -- URL-like address of the content blob
+ content_address varbinary(255) NOT NULL
+) /*$wgDBTableOptions*/;
+
+--
+-- Normalization table for role names
+--
+CREATE TABLE /*_*/slot_roles (
+ role_id smallint PRIMARY KEY AUTO_INCREMENT,
+ role_name varbinary(64) NOT NULL
+) /*$wgDBTableOptions*/;
+
+-- Index for looking of the internal ID of for a name
+CREATE UNIQUE INDEX /*i*/role_name ON /*_*/slot_roles (role_name);
+
+--
+-- Normalization table for content model names
+--
+CREATE TABLE /*_*/content_models (
+ model_id smallint PRIMARY KEY AUTO_INCREMENT,
+ model_name varbinary(64) NOT NULL
+) /*$wgDBTableOptions*/;
+
+-- Index for looking of the internal ID of for a name
+CREATE UNIQUE INDEX /*i*/model_name ON /*_*/content_models (model_name);
--
-- Track page-to-page hyperlinks within the wiki.
@@ -870,26 +999,22 @@ CREATE TABLE /*_*/site_stats (
ss_row_id int unsigned NOT NULL PRIMARY KEY,
-- Total number of edits performed.
- ss_total_edits bigint unsigned default 0,
+ ss_total_edits bigint unsigned default NULL,
- -- An approximate count of pages matching the following criteria:
- -- * in namespace 0
- -- * not a redirect
- -- * contains the text '[['
- -- See Article::isCountable() in includes/Article.php
- ss_good_articles bigint unsigned default 0,
+ -- See SiteStatsInit::articles().
+ ss_good_articles bigint unsigned default NULL,
- -- Total pages, theoretically equal to SELECT COUNT(*) FROM page; except faster
- ss_total_pages bigint default '-1',
+ -- Total pages, theoretically equal to SELECT COUNT(*) FROM page.
+ ss_total_pages bigint unsigned default NULL,
- -- Number of users, theoretically equal to SELECT COUNT(*) FROM user;
- ss_users bigint default '-1',
+ -- Number of users, theoretically equal to SELECT COUNT(*) FROM user.
+ ss_users bigint unsigned default NULL,
- -- Number of users that still edit
- ss_active_users bigint default '-1',
+ -- Number of users that still edit.
+ ss_active_users bigint unsigned default NULL,
- -- Number of images, equivalent to SELECT COUNT(*) FROM image
- ss_images int default 0
+ -- Number of images, equivalent to SELECT COUNT(*) FROM image.
+ ss_images bigint unsigned default NULL
) /*$wgDBTableOptions*/;
--
@@ -907,10 +1032,13 @@ CREATE TABLE /*_*/ipblocks (
ipb_user int unsigned NOT NULL default 0,
-- User ID who made the block.
- ipb_by int unsigned NOT NULL default 0,
+ ipb_by int unsigned NOT NULL default 0, -- Deprecated in favor of ipb_by_actor
-- User name of blocker
- ipb_by_text varchar(255) binary NOT NULL default '',
+ ipb_by_text varchar(255) binary NOT NULL default '', -- Deprecated in favor of ipb_by_actor
+
+ -- Actor who made the block.
+ ipb_by_actor bigint unsigned NOT NULL DEFAULT 0, -- ("DEFAULT 0" is temporary, signaling that ipb_by/ipb_by_text should be used)
-- Text comment made by blocker. Deprecated in favor of ipb_reason_id
ipb_reason varbinary(767) NOT NULL default '',
@@ -1024,12 +1152,19 @@ CREATE TABLE /*_*/image (
-- Description field as entered by the uploader.
-- This is displayed in image upload history and logs.
- -- Deprecated in favor of image_comment_temp.imgcomment_description_id.
+ -- Deprecated in favor of img_description_id.
img_description varbinary(767) NOT NULL default '',
+ img_description_id bigint unsigned NOT NULL DEFAULT 0, -- ("DEFAULT 0" is temporary, signaling that img_description should be used)
+
-- user_id and user_name of uploader.
+ -- Deprecated in favor of img_actor.
img_user int unsigned NOT NULL default 0,
- img_user_text varchar(255) binary NOT NULL,
+ img_user_text varchar(255) binary NOT NULL DEFAULT '',
+
+ -- actor_id of the uploader.
+ -- ("DEFAULT 0" is temporary, signaling that img_user/img_user_text should be used)
+ img_actor bigint unsigned NOT NULL DEFAULT 0,
-- Time of the upload.
img_timestamp varbinary(14) NOT NULL default '',
@@ -1041,6 +1176,7 @@ CREATE TABLE /*_*/image (
-- Used by Special:Newimages and ApiQueryAllImages
CREATE INDEX /*i*/img_user_timestamp ON /*_*/image (img_user,img_timestamp);
CREATE INDEX /*i*/img_usertext_timestamp ON /*_*/image (img_user_text,img_timestamp);
+CREATE INDEX /*i*/img_actor_timestamp ON /*_*/image (img_actor,img_timestamp);
-- Used by Special:ListFiles for sort-by-size
CREATE INDEX /*i*/img_size ON /*_*/image (img_size);
-- Used by Special:Newimages and Special:ListFiles
@@ -1088,8 +1224,9 @@ CREATE TABLE /*_*/oldimage (
oi_bits int NOT NULL default 0,
oi_description varbinary(767) NOT NULL default '', -- Deprecated.
oi_description_id bigint unsigned NOT NULL DEFAULT 0, -- ("DEFAULT 0" is temporary, signaling that oi_description should be used)
- oi_user int unsigned NOT NULL default 0,
- oi_user_text varchar(255) binary NOT NULL,
+ oi_user int unsigned NOT NULL default 0, -- Deprecated in favor of oi_actor
+ oi_user_text varchar(255) binary NOT NULL DEFAULT '', -- Deprecated in favor of oi_actor
+ oi_actor bigint unsigned NOT NULL DEFAULT 0, -- ("DEFAULT 0" is temporary, signaling that oi_user/oi_user_text should be used)
oi_timestamp binary(14) NOT NULL default '',
oi_metadata mediumblob NOT NULL,
@@ -1101,6 +1238,7 @@ CREATE TABLE /*_*/oldimage (
) /*$wgDBTableOptions*/;
CREATE INDEX /*i*/oi_usertext_timestamp ON /*_*/oldimage (oi_user_text,oi_timestamp);
+CREATE INDEX /*i*/oi_actor_timestamp ON /*_*/oldimage (oi_actor,oi_timestamp);
CREATE INDEX /*i*/oi_name_timestamp ON /*_*/oldimage (oi_name,oi_timestamp);
-- oi_archive_name truncated to 14 to avoid key length overflow
CREATE INDEX /*i*/oi_name_archive_name ON /*_*/oldimage (oi_name,oi_archive_name(14));
@@ -1149,8 +1287,9 @@ CREATE TABLE /*_*/filearchive (
fa_minor_mime varbinary(100) default "unknown",
fa_description varbinary(767) default '', -- Deprecated
fa_description_id bigint unsigned NOT NULL DEFAULT 0, -- ("DEFAULT 0" is temporary, signaling that fa_description should be used)
- fa_user int unsigned default 0,
- fa_user_text varchar(255) binary,
+ fa_user int unsigned default 0, -- Deprecated in favor of fa_actor
+ fa_user_text varchar(255) binary DEFAULT '', -- Deprecated in favor of fa_actor
+ fa_actor bigint unsigned NOT NULL DEFAULT 0, -- ("DEFAULT 0" is temporary, signaling that fa_user/fa_user_text should be used)
fa_timestamp binary(14) default '',
-- Visibility of deleted revisions, bitfield
@@ -1168,6 +1307,7 @@ CREATE INDEX /*i*/fa_storage_group ON /*_*/filearchive (fa_storage_group, fa_sto
CREATE INDEX /*i*/fa_deleted_timestamp ON /*_*/filearchive (fa_deleted_timestamp);
-- sort by uploader
CREATE INDEX /*i*/fa_user_timestamp ON /*_*/filearchive (fa_user_text,fa_timestamp);
+CREATE INDEX /*i*/fa_actor_timestamp ON /*_*/filearchive (fa_actor,fa_timestamp);
-- find file by sha1, 10 bytes will be enough for hashes to be indexed
CREATE INDEX /*i*/fa_sha1 ON /*_*/filearchive (fa_sha1(10));
@@ -1238,8 +1378,9 @@ CREATE TABLE /*_*/recentchanges (
rc_timestamp varbinary(14) NOT NULL default '',
-- As in revision
- rc_user int unsigned NOT NULL default 0,
- rc_user_text varchar(255) binary NOT NULL,
+ rc_user int unsigned NOT NULL default 0, -- Deprecated in favor of rc_actor
+ rc_user_text varchar(255) binary NOT NULL DEFAULT '', -- Deprecated in favor of rc_actor
+ rc_actor bigint unsigned NOT NULL DEFAULT 0, -- ("DEFAULT 0" is temporary, signaling that rc_user/rc_user_text should be used)
-- When pages are renamed, their RC entries do _not_ change.
rc_namespace int NOT NULL default 0,
@@ -1308,7 +1449,7 @@ CREATE TABLE /*_*/recentchanges (
CREATE INDEX /*i*/rc_timestamp ON /*_*/recentchanges (rc_timestamp);
-- Special:Watchlist
-CREATE INDEX /*i*/rc_namespace_title ON /*_*/recentchanges (rc_namespace, rc_title);
+CREATE INDEX /*i*/rc_namespace_title_timestamp ON /*_*/recentchanges (rc_namespace, rc_title, rc_timestamp);
-- Special:Recentchangeslinked when finding changes in pages linked from a page
CREATE INDEX /*i*/rc_cur_id ON /*_*/recentchanges (rc_cur_id);
@@ -1322,9 +1463,11 @@ CREATE INDEX /*i*/rc_ip ON /*_*/recentchanges (rc_ip);
-- Probably intended for Special:NewPages namespace filter
CREATE INDEX /*i*/rc_ns_usertext ON /*_*/recentchanges (rc_namespace, rc_user_text);
+CREATE INDEX /*i*/rc_ns_actor ON /*_*/recentchanges (rc_namespace, rc_actor);
-- SiteStats active user count, Special:ActiveUsers, Special:NewPages user filter
CREATE INDEX /*i*/rc_user_text ON /*_*/recentchanges (rc_user_text, rc_timestamp);
+CREATE INDEX /*i*/rc_actor ON /*_*/recentchanges (rc_actor, rc_timestamp);
-- ApiQueryRecentChanges (T140108)
CREATE INDEX /*i*/rc_name_type_patrolled_timestamp ON /*_*/recentchanges (rc_namespace, rc_type, rc_patrolled, rc_timestamp);
@@ -1464,10 +1607,13 @@ CREATE TABLE /*_*/logging (
log_timestamp binary(14) NOT NULL default '19700101000000',
-- The user who performed this action; key to user_id
- log_user int unsigned NOT NULL default 0,
+ log_user int unsigned NOT NULL default 0, -- Deprecated in favor of log_actor
-- Name of the user who performed this action
- log_user_text varchar(255) binary NOT NULL default '',
+ log_user_text varchar(255) binary NOT NULL default '', -- Deprecated in favor of log_actor
+
+ -- The actor who performed this action
+ log_actor bigint unsigned NOT NULL DEFAULT 0, -- ("DEFAULT 0" is temporary, signaling that log_user/log_user_text should be used)
-- Key to the page affected. Where a user is the target,
-- this will point to the user page.
@@ -1496,6 +1642,7 @@ CREATE INDEX /*i*/type_time ON /*_*/logging (log_type, log_timestamp);
-- Special:Log performer filter
CREATE INDEX /*i*/user_time ON /*_*/logging (log_user, log_timestamp);
+CREATE INDEX /*i*/actor_time ON /*_*/logging (log_actor, log_timestamp);
-- Special:Log title filter, log extract
CREATE INDEX /*i*/page_time ON /*_*/logging (log_namespace, log_title, log_timestamp);
@@ -1505,6 +1652,7 @@ CREATE INDEX /*i*/times ON /*_*/logging (log_timestamp);
-- Special:Log filter by performer and type
CREATE INDEX /*i*/log_user_type_time ON /*_*/logging (log_user, log_type, log_timestamp);
+CREATE INDEX /*i*/log_actor_type_time ON /*_*/logging (log_actor, log_type, log_timestamp);
-- Apparently just used for a few maintenance pages (findMissingFiles.php, Flow).
-- Could be removed?
@@ -1697,7 +1845,7 @@ CREATE TABLE /*_*/change_tag (
ct_rev_id int unsigned NULL,
-- Tag applied
ct_tag varchar(255) NOT NULL,
- -- Parameters for the tag, presently unused
+ -- Parameters for the tag; used by some extensions
ct_params blob NULL
) /*$wgDBTableOptions*/;
diff --git a/www/wiki/maintenance/term/MWTerm.php b/www/wiki/maintenance/term/MWTerm.php
index d90d0695..ec8aeb01 100644
--- a/www/wiki/maintenance/term/MWTerm.php
+++ b/www/wiki/maintenance/term/MWTerm.php
@@ -20,13 +20,21 @@
*
* @file
* @ingroup Maintenance Testing
+ */
+
+/**
+ * @defgroup TermColorer TermColorer
+ * @ingroup Maintenance Testing
* @todo Fixme: Make this more generic
+ *
+ * Set of classes to help with test output and such. Right now pretty specific
+ * to the parser tests but could be more useful one day :)
*/
/**
* Terminal that supports ANSI escape sequences.
*
- * @ingroup Maintenance Testing
+ * @ingroup TermColorer
*/
class AnsiTermColorer {
function __construct() {
@@ -59,7 +67,7 @@ class AnsiTermColorer {
/**
* A colour-less terminal
*
- * @ingroup Maintenance Testing
+ * @ingroup TermColorer
*/
class DummyTermColorer {
public function color( $color ) {
diff --git a/www/wiki/maintenance/tidyUpBug37714.php b/www/wiki/maintenance/tidyUpBug37714.php
index 9d7cc0e9..0dd0341d 100644
--- a/www/wiki/maintenance/tidyUpBug37714.php
+++ b/www/wiki/maintenance/tidyUpBug37714.php
@@ -44,5 +44,5 @@ class TidyUpBug37714 extends Maintenance {
}
}
-$maintClass = 'TidyUpBug37714';
+$maintClass = TidyUpBug37714::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/undelete.php b/www/wiki/maintenance/undelete.php
index c2d5c2c2..e9b2abd0 100644
--- a/www/wiki/maintenance/undelete.php
+++ b/www/wiki/maintenance/undelete.php
@@ -41,7 +41,7 @@ class Undelete extends Maintenance {
$title = Title::newFromText( $pageName );
if ( !$title ) {
- $this->error( "Invalid title", true );
+ $this->fatalError( "Invalid title" );
}
if ( $user === false ) {
$wgUser = User::newSystemUser( 'Command line script', [ 'steal' => true ] );
@@ -49,7 +49,7 @@ class Undelete extends Maintenance {
$wgUser = User::newFromName( $user );
}
if ( !$wgUser ) {
- $this->error( "Invalid username", true );
+ $this->fatalError( "Invalid username" );
}
$archive = new PageArchive( $title, RequestContext::getMain()->getConfig() );
$this->output( "Undeleting " . $title->getPrefixedDBkey() . '...' );
@@ -58,5 +58,5 @@ class Undelete extends Maintenance {
}
}
-$maintClass = "Undelete";
+$maintClass = Undelete::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/update.php b/www/wiki/maintenance/update.php
index 52e90175..2a1feb46 100755
--- a/www/wiki/maintenance/update.php
+++ b/www/wiki/maintenance/update.php
@@ -66,53 +66,54 @@ class UpdateMediaWiki extends Maintenance {
list( $pcreVersion ) = explode( ' ', PCRE_VERSION, 2 );
if ( version_compare( $pcreVersion, $minimumPcreVersion, '<' ) ) {
- $this->error(
+ $this->fatalError(
"PCRE $minimumPcreVersion or later is required.\n" .
"Your PHP binary is linked with PCRE $pcreVersion.\n\n" .
"More information:\n" .
"https://www.mediawiki.org/wiki/Manual:Errors_and_symptoms/PCRE\n\n" .
- "ABORTING.\n",
- true );
+ "ABORTING.\n" );
}
$test = new PhpXmlBugTester();
if ( !$test->ok ) {
- $this->error(
+ $this->fatalError(
"Your system has a combination of PHP and libxml2 versions that is buggy\n" .
"and can cause hidden data corruption in MediaWiki and other web apps.\n" .
"Upgrade to libxml2 2.7.3 or later.\n" .
- "ABORTING (see https://bugs.php.net/bug.php?id=45996).\n",
- true );
+ "ABORTING (see https://bugs.php.net/bug.php?id=45996).\n" );
}
}
function execute() {
- global $wgVersion, $wgLang, $wgAllowSchemaUpdates;
+ global $wgVersion, $wgLang, $wgAllowSchemaUpdates, $wgMessagesDirs;
if ( !$wgAllowSchemaUpdates
&& !( $this->hasOption( 'force' )
|| $this->hasOption( 'schema' )
|| $this->hasOption( 'noschema' ) )
) {
- $this->error( "Do not run update.php on this wiki. If you're seeing this you should\n"
+ $this->fatalError( "Do not run update.php on this wiki. If you're seeing this you should\n"
. "probably ask for some help in performing your schema updates or use\n"
. "the --noschema and --schema options to get an SQL file for someone\n"
. "else to inspect and run.\n\n"
- . "If you know what you are doing, you can continue with --force\n", true );
+ . "If you know what you are doing, you can continue with --force\n" );
}
$this->fileHandle = null;
if ( substr( $this->getOption( 'schema' ), 0, 2 ) === "--" ) {
- $this->error( "The --schema option requires a file as an argument.\n", true );
+ $this->fatalError( "The --schema option requires a file as an argument.\n" );
} elseif ( $this->hasOption( 'schema' ) ) {
$file = $this->getOption( 'schema' );
$this->fileHandle = fopen( $file, "w" );
if ( $this->fileHandle === false ) {
$err = error_get_last();
- $this->error( "Problem opening the schema file for writing: $file\n\t{$err['message']}", true );
+ $this->fatalError( "Problem opening the schema file for writing: $file\n\t{$err['message']}" );
}
}
+ // T206765: We need to load the installer i18n files as some of errors come installer/updater code
+ $wgMessagesDirs['MediawikiInstaller'] = dirname( __DIR__ ) . '/includes/installer/i18n';
+
$lang = Language::factory( 'en' );
// Set global language to ensure localised errors are in English (T22633)
RequestContext::getMain()->setLanguage( $lang );
@@ -128,12 +129,12 @@ class UpdateMediaWiki extends Maintenance {
$this->compatChecks();
} else {
$this->output( "Skipping compatibility checks, proceed at your own risk (Ctrl+C to abort)\n" );
- wfCountDown( 5 );
+ $this->countDown( 5 );
}
// Check external dependencies are up to date
if ( !$this->hasOption( 'skip-external-dependencies' ) ) {
- $composerLockUpToDate = $this->runChild( 'CheckComposerLockUpToDate' );
+ $composerLockUpToDate = $this->runChild( CheckComposerLockUpToDate::class );
$composerLockUpToDate->execute();
} else {
$this->output(
@@ -152,7 +153,7 @@ class UpdateMediaWiki extends Maintenance {
if ( !$status->isOK() ) {
// This might output some wikitext like <strong> but it should be comprehensible
$text = $status->getWikiText();
- $this->error( $text, 1 );
+ $this->fatalError( $text );
}
$this->output( "Going to run database updates for " . wfWikiID() . "\n" );
@@ -165,18 +166,16 @@ class UpdateMediaWiki extends Maintenance {
if ( !$this->hasOption( 'quick' ) ) {
$this->output( "Abort with control-c in the next five seconds "
. "(skip this countdown with --quick) ... " );
- wfCountDown( 5 );
+ $this->countDown( 5 );
}
$time1 = microtime( true );
$badPhpUnit = dirname( __DIR__ ) . '/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php';
if ( file_exists( $badPhpUnit ) ) {
- // @codingStandardsIgnoreStart Generic.Files.LineLength.TooLong
// Bad versions of the file are:
// https://raw.githubusercontent.com/sebastianbergmann/phpunit/c820f915bfae34e5a836f94967a2a5ea5ef34f21/src/Util/PHP/eval-stdin.php
// https://raw.githubusercontent.com/sebastianbergmann/phpunit/3aaddb1c5bd9b9b8d070b4cf120e71c36fd08412/src/Util/PHP/eval-stdin.php
- // @codingStandardsIgnoreEnd
$md5 = md5_file( $badPhpUnit );
if ( $md5 === '120ac49800671dc383b6f3709c25c099'
|| $md5 === '28af792cb38fc9a1b236b91c1aad2876'
@@ -237,13 +236,13 @@ class UpdateMediaWiki extends Maintenance {
# This needs to be disabled early since extensions will try to use the l10n
# cache from $wgExtensionFunctions (T22471)
$wgLocalisationCacheConf = [
- 'class' => 'LocalisationCache',
- 'storeClass' => 'LCStoreNull',
+ 'class' => LocalisationCache::class,
+ 'storeClass' => LCStoreNull::class,
'storeDirectory' => false,
'manualRecache' => false,
];
}
}
-$maintClass = 'UpdateMediaWiki';
+$maintClass = UpdateMediaWiki::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/updateArticleCount.php b/www/wiki/maintenance/updateArticleCount.php
index 213195df..c72e74fb 100644
--- a/www/wiki/maintenance/updateArticleCount.php
+++ b/www/wiki/maintenance/updateArticleCount.php
@@ -69,5 +69,5 @@ class UpdateArticleCount extends Maintenance {
}
}
-$maintClass = "UpdateArticleCount";
+$maintClass = UpdateArticleCount::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/updateCollation.php b/www/wiki/maintenance/updateCollation.php
index 84fc2d20..d88d5e96 100644
--- a/www/wiki/maintenance/updateCollation.php
+++ b/www/wiki/maintenance/updateCollation.php
@@ -200,7 +200,11 @@ TEXT
$this->updateSortKeySizeHistogram( $newSortKey );
}
- if ( !$dryRun ) {
+ if ( $dryRun ) {
+ // Add 1 to the count if the sortkey was changed. (Note that this doesn't count changes in
+ // other fields, if any, those usually only happen when upgrading old MediaWikis.)
+ $count += ( $row->cl_sortkey !== $newSortKey );
+ } else {
$dbw->update(
'categorylinks',
[
@@ -213,6 +217,7 @@ TEXT
[ 'cl_from' => $row->cl_from, 'cl_to' => $row->cl_to ],
__METHOD__
);
+ $count++;
}
if ( $row ) {
$batchConds = [ $this->getBatchCondition( $row, $dbw ) ];
@@ -222,17 +227,16 @@ TEXT
$this->commitTransaction( $dbw, __METHOD__ );
}
- $count += $res->numRows();
- $this->output( "$count done.\n" );
-
- if ( !$dryRun && ++$batchCount % self::SYNC_INTERVAL == 0 ) {
- $this->output( "Waiting for replica DBs ... " );
- wfWaitForSlaves();
- $this->output( "done\n" );
+ if ( $dryRun ) {
+ $this->output( "$count rows would be updated so far.\n" );
+ } else {
+ $this->output( "$count done.\n" );
}
} while ( $res->numRows() == self::BATCH_SIZE );
- $this->output( "$count rows processed\n" );
+ if ( !$dryRun ) {
+ $this->output( "$count rows processed\n" );
+ }
if ( $verboseStats ) {
$this->output( "\n" );
@@ -344,5 +348,5 @@ TEXT
}
}
-$maintClass = "UpdateCollation";
+$maintClass = UpdateCollation::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/updateDoubleWidthSearch.php b/www/wiki/maintenance/updateDoubleWidthSearch.php
index cb2f125e..810af57f 100644
--- a/www/wiki/maintenance/updateDoubleWidthSearch.php
+++ b/www/wiki/maintenance/updateDoubleWidthSearch.php
@@ -53,7 +53,7 @@ class UpdateDoubleWidthSearch extends Maintenance {
$dbw = $this->getDB( DB_MASTER );
if ( $dbw->getType() !== 'mysql' ) {
- $this->error( "This change is only needed on MySQL, quitting.\n", true );
+ $this->fatalError( "This change is only needed on MySQL, quitting.\n" );
}
$res = $this->findRows( $dbw );
@@ -77,5 +77,5 @@ class UpdateDoubleWidthSearch extends Maintenance {
}
}
-$maintClass = "UpdateDoubleWidthSearch";
+$maintClass = UpdateDoubleWidthSearch::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/updateExtensionJsonSchema.php b/www/wiki/maintenance/updateExtensionJsonSchema.php
index 427769f1..6233d5b8 100644
--- a/www/wiki/maintenance/updateExtensionJsonSchema.php
+++ b/www/wiki/maintenance/updateExtensionJsonSchema.php
@@ -14,12 +14,12 @@ class UpdateExtensionJsonSchema extends Maintenance {
public function execute() {
$filename = $this->getArg( 0 );
if ( !is_readable( $filename ) ) {
- $this->error( "Error: Unable to read $filename", 1 );
+ $this->fatalError( "Error: Unable to read $filename" );
}
$json = FormatJson::decode( file_get_contents( $filename ), true );
if ( $json === null ) {
- $this->error( "Error: Invalid JSON", 1 );
+ $this->fatalError( "Error: Invalid JSON" );
}
if ( !isset( $json['manifest_version'] ) ) {
@@ -65,5 +65,5 @@ class UpdateExtensionJsonSchema extends Maintenance {
}
}
-$maintClass = 'UpdateExtensionJsonSchema';
+$maintClass = UpdateExtensionJsonSchema::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/updateRestrictions.php b/www/wiki/maintenance/updateRestrictions.php
index 2f3fc365..668ba790 100644
--- a/www/wiki/maintenance/updateRestrictions.php
+++ b/www/wiki/maintenance/updateRestrictions.php
@@ -41,24 +41,26 @@ class UpdateRestrictions extends Maintenance {
public function execute() {
$db = $this->getDB( DB_MASTER );
+ $batchSize = $this->getBatchSize();
if ( !$db->tableExists( 'page_restrictions' ) ) {
- $this->error( "page_restrictions table does not exist", true );
+ $this->fatalError( "page_restrictions table does not exist" );
}
- $start = $db->selectField( 'page', 'MIN(page_id)', false, __METHOD__ );
+ $start = $db->selectField( 'page', 'MIN(page_id)', '', __METHOD__ );
if ( !$start ) {
- $this->error( "Nothing to do.", true );
+ $this->fatalError( "Nothing to do." );
}
- $end = $db->selectField( 'page', 'MAX(page_id)', false, __METHOD__ );
+ $end = $db->selectField( 'page', 'MAX(page_id)', '', __METHOD__ );
# Do remaining chunk
- $end += $this->mBatchSize - 1;
+ $end += $batchSize - 1;
$blockStart = $start;
- $blockEnd = $start + $this->mBatchSize - 1;
+ $blockEnd = $start + $batchSize - 1;
$encodedExpiry = 'infinity';
while ( $blockEnd <= $end ) {
$this->output( "...doing page_id from $blockStart to $blockEnd out of $end\n" );
- $cond = "page_id BETWEEN $blockStart AND $blockEnd AND page_restrictions !=''";
+ $cond = "page_id BETWEEN " . (int)$blockStart . " AND " . (int)$blockEnd .
+ " AND page_restrictions !=''";
$res = $db->select(
'page',
[ 'page_id', 'page_namespace', 'page_restrictions' ],
@@ -105,8 +107,8 @@ class UpdateRestrictions extends Maintenance {
throw new MWException( "Deadlock loop failed wtf :(" );
}
}
- $blockStart += $this->mBatchSize - 1;
- $blockEnd += $this->mBatchSize - 1;
+ $blockStart += $batchSize - 1;
+ $blockEnd += $batchSize - 1;
wfWaitForSlaves();
}
$this->output( "...removing dead rows from page_restrictions\n" );
@@ -124,5 +126,5 @@ class UpdateRestrictions extends Maintenance {
}
}
-$maintClass = "UpdateRestrictions";
+$maintClass = UpdateRestrictions::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/updateSearchIndex.php b/www/wiki/maintenance/updateSearchIndex.php
index cdb7d9f7..af2d8287 100644
--- a/www/wiki/maintenance/updateSearchIndex.php
+++ b/www/wiki/maintenance/updateSearchIndex.php
@@ -121,5 +121,5 @@ class UpdateSearchIndex extends Maintenance {
}
}
-$maintClass = "UpdateSearchIndex";
+$maintClass = UpdateSearchIndex::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/updateSpecialPages.php b/www/wiki/maintenance/updateSpecialPages.php
index 5ea38282..1c6f9b33 100644
--- a/www/wiki/maintenance/updateSpecialPages.php
+++ b/www/wiki/maintenance/updateSpecialPages.php
@@ -72,7 +72,7 @@ class UpdateSpecialPages extends Maintenance {
$queryPage = $specialObj;
} else {
$class = get_class( $specialObj );
- $this->error( "$class is not an instance of QueryPage.\n", 1 );
+ $this->fatalError( "$class is not an instance of QueryPage.\n" );
die;
}
@@ -101,16 +101,7 @@ class UpdateSpecialPages extends Maintenance {
$this->output( sprintf( "%.2fs\n", $seconds ) );
}
# Reopen any connections that have closed
- if ( !wfGetLB()->pingAll() ) {
- $this->output( "\n" );
- do {
- $this->error( "Connection failed, reconnecting in 10 seconds..." );
- sleep( 10 );
- } while ( !wfGetLB()->pingAll() );
- $this->output( "Reconnected\n\n" );
- }
- # Wait for the replica DB to catch up
- wfWaitForSlaves();
+ $this->reopenAndWaitForReplicas();
} else {
$this->output( "cheap, skipped\n" );
}
@@ -121,6 +112,25 @@ class UpdateSpecialPages extends Maintenance {
}
}
+ /**
+ * Re-open any closed db connection, and wait for replicas
+ *
+ * Queries that take a really long time, might cause the
+ * mysql connection to "go away"
+ */
+ private function reopenAndWaitForReplicas() {
+ if ( !wfGetLB()->pingAll() ) {
+ $this->output( "\n" );
+ do {
+ $this->error( "Connection failed, reconnecting in 10 seconds..." );
+ sleep( 10 );
+ } while ( !wfGetLB()->pingAll() );
+ $this->output( "Reconnected\n\n" );
+ }
+ # Wait for the replica DB to catch up
+ wfWaitForSlaves();
+ }
+
public function doSpecialPageCacheUpdates( $dbw ) {
global $wgSpecialPageCacheUpdates;
@@ -154,11 +164,11 @@ class UpdateSpecialPages extends Maintenance {
}
$this->output( sprintf( "%.2fs\n", $seconds ) );
# Wait for the replica DB to catch up
- wfWaitForSlaves();
+ $this->reopenAndWaitForReplicas();
}
}
}
}
-$maintClass = "UpdateSpecialPages";
+$maintClass = UpdateSpecialPages::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/userOptions.inc b/www/wiki/maintenance/userOptions.inc
deleted file mode 100644
index 8ac7f919..00000000
--- a/www/wiki/maintenance/userOptions.inc
+++ /dev/null
@@ -1,292 +0,0 @@
-<?php
-/**
- * Helper class for userOptions.php script.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup Maintenance
- */
-
-// Options we will use
-$options = [ 'list', 'nowarn', 'quiet', 'usage', 'dry' ];
-$optionsWithArgs = [ 'old', 'new' ];
-
-require_once __DIR__ . '/commandLine.inc';
-
-/**
- * @ingroup Maintenance
- */
-class UserOptions {
- public $mQuick;
- public $mQuiet;
- public $mDry;
- public $mAnOption;
- public $mOldValue;
- public $mNewValue;
-
- private $mMode, $mReady;
-
- /**
- * Constructor. Will show usage and exit if script options are not correct
- * @param array $opts
- * @param array $args
- */
- function __construct( $opts, $args ) {
- if ( !$this->checkOpts( $opts, $args ) ) {
- self::showUsageAndExit();
- } else {
- $this->mReady = $this->initializeOpts( $opts, $args );
- }
- }
-
- /**
- * This is used to check options. Only needed on construction
- *
- * @param array $opts
- * @param array $args
- *
- * @return bool
- */
- private function checkOpts( $opts, $args ) {
- // The three possible ways to run the script:
- $list = isset( $opts['list'] );
- $usage = isset( $opts['usage'] ) && ( count( $args ) <= 1 );
- $change = isset( $opts['old'] ) && isset( $opts['new'] ) && ( count( $args ) <= 1 );
-
- // We want only one of them
- $isValid = ( ( $list + $usage + $change ) == 1 );
-
- return $isValid;
- }
-
- /**
- * load script options in the object
- *
- * @param array $opts
- * @param array $args
- *
- * @return bool
- */
- private function initializeOpts( $opts, $args ) {
- $this->mQuick = isset( $opts['nowarn'] );
- $this->mQuiet = isset( $opts['quiet'] );
- $this->mDry = isset( $opts['dry'] );
-
- // Set object properties, specially 'mMode' used by run()
- if ( isset( $opts['list'] ) ) {
- $this->mMode = 'LISTER';
- } elseif ( isset( $opts['usage'] ) ) {
- $this->mMode = 'USAGER';
- $this->mAnOption = isset( $args[0] ) ? $args[0] : false;
- } elseif ( isset( $opts['old'] ) && isset( $opts['new'] ) ) {
- $this->mMode = 'CHANGER';
- $this->mOldValue = $opts['old'];
- $this->mNewValue = $opts['new'];
- $this->mAnOption = $args[0];
- } else {
- die( "There is a bug in the software, this should never happen\n" );
- }
-
- return true;
- }
-
- /**
- * Dumb stuff to run a mode.
- * @return bool
- */
- public function run() {
- if ( !$this->mReady ) {
- return false;
- }
-
- $this->{$this->mMode}();
-
- return true;
- }
-
- /**
- * List default options and their value
- */
- private function LISTER() {
- $def = User::getDefaultOptions();
- ksort( $def );
- $maxOpt = 0;
- foreach ( $def as $opt => $value ) {
- $maxOpt = max( $maxOpt, strlen( $opt ) );
- }
- foreach ( $def as $opt => $value ) {
- printf( "%-{$maxOpt}s: %s\n", $opt, $value );
- }
- }
-
- /**
- * List options usage
- */
- private function USAGER() {
- $ret = [];
- $defaultOptions = User::getDefaultOptions();
-
- // We list user by user_id from one of the replica DBs
- $dbr = wfGetDB( DB_REPLICA );
- $result = $dbr->select( 'user',
- [ 'user_id' ],
- [],
- __METHOD__
- );
-
- foreach ( $result as $id ) {
- $user = User::newFromId( $id->user_id );
-
- // Get the options and update stats
- if ( $this->mAnOption ) {
- if ( !array_key_exists( $this->mAnOption, $defaultOptions ) ) {
- print "Invalid user option. Use --list to see valid choices\n";
- exit;
- }
-
- $userValue = $user->getOption( $this->mAnOption );
- if ( $userValue <> $defaultOptions[$this->mAnOption] ) {
- // @codingStandardsIgnoreStart Ignore silencing errors is discouraged warning
- @$ret[$this->mAnOption][$userValue]++;
- // @codingStandardsIgnoreEnd
- }
- } else {
-
- foreach ( $defaultOptions as $name => $defaultValue ) {
- $userValue = $user->getOption( $name );
- if ( $userValue <> $defaultValue ) {
- // @codingStandardsIgnoreStart Ignore silencing errors is discouraged warning
- @$ret[$name][$userValue]++;
- // @codingStandardsIgnoreEnd
- }
- }
- }
- }
-
- foreach ( $ret as $optionName => $usageStats ) {
- print "Usage for <$optionName> (default: '{$defaultOptions[$optionName]}'):\n";
- foreach ( $usageStats as $value => $count ) {
- print " $count user(s): '$value'\n";
- }
- print "\n";
- }
- }
-
- /**
- * Change our users options
- */
- private function CHANGER() {
- $this->warn();
-
- // We list user by user_id from one of the replica DBs
- $dbr = wfGetDB( DB_REPLICA );
- $result = $dbr->select( 'user',
- [ 'user_id' ],
- [],
- __METHOD__
- );
-
- foreach ( $result as $id ) {
- $user = User::newFromId( $id->user_id );
-
- $curValue = $user->getOption( $this->mAnOption );
- $username = $user->getName();
-
- if ( $curValue == $this->mOldValue ) {
- if ( !$this->mQuiet ) {
- print "Setting {$this->mAnOption} for $username from '{$this->mOldValue}' " .
- "to '{$this->mNewValue}'): ";
- }
-
- // Change value
- $user->setOption( $this->mAnOption, $this->mNewValue );
-
- // Will not save the settings if run with --dry
- if ( !$this->mDry ) {
- $user->saveSettings();
- }
- if ( !$this->mQuiet ) {
- print " OK\n";
- }
- } elseif ( !$this->mQuiet ) {
- print "Not changing '$username' using <{$this->mAnOption}> = '$curValue'\n";
- }
- }
- }
-
- /**
- * Return an array of option names
- * @return array
- */
- public static function getDefaultOptionsNames() {
- $def = User::getDefaultOptions();
- $ret = [];
- foreach ( $def as $optname => $defaultValue ) {
- array_push( $ret, $optname );
- }
-
- return $ret;
- }
-
- public static function showUsageAndExit() {
- print <<<USAGE
-
-This script pass through all users and change one of their options.
-The new option is NOT validated.
-
-Usage:
- php userOptions.php --list
- php userOptions.php [user option] --usage
- php userOptions.php [options] <user option> --old <old value> --new <new value>
-
-Switchs:
- --list : list available user options and their default value
-
- --usage : report all options statistics or just one if you specify it.
-
- --old <old value> : the value to look for
- --new <new value> : new value to update users with
-
-Options:
- --nowarn: hides the 5 seconds warning
- --quiet : do not print what is happening
- --dry : do not save user settings back to database
-
-USAGE;
- exit( 0 );
- }
-
- /**
- * The warning message and countdown
- * @return bool
- */
- public function warn() {
- if ( $this->mQuick ) {
- return true;
- }
-
- print <<<WARN
-The script is about to change the skin for ALL USERS in the database.
-Users with option <$this->mAnOption> = '$this->mOldValue' will be made to use '$this->mNewValue'.
-
-Abort with control-c in the next five seconds....
-WARN;
- wfCountDown( 5 );
-
- return true;
- }
-}
diff --git a/www/wiki/maintenance/userOptions.php b/www/wiki/maintenance/userOptions.php
index 53db48cd..4c9dcb46 100644
--- a/www/wiki/maintenance/userOptions.php
+++ b/www/wiki/maintenance/userOptions.php
@@ -24,12 +24,180 @@
* @author Antoine Musso <hashar at free dot fr>
*/
-// This is a command line script, load tools and parse args
-require_once 'userOptions.inc';
+require_once __DIR__ . '/Maintenance.php';
-// Load up our tool system, exit with usage() if options are not fine
-$uo = new UserOptions( $options, $args );
+/**
+ * @ingroup Maintenance
+ */
+class UserOptionsMaintenance extends Maintenance {
+
+ function __construct() {
+ parent::__construct();
+
+ $this->addDescription( 'Pass through all users and change one of their options.
+The new option is NOT validated.' );
+
+ $this->addOption( 'list', 'List available user options and their default value' );
+ $this->addOption( 'usage', 'Report all options statistics or just one if you specify it' );
+ $this->addOption( 'old', 'The value to look for', false, true );
+ $this->addOption( 'new', 'Rew value to update users with', false, true );
+ $this->addOption( 'nowarn', 'Hides the 5 seconds warning' );
+ $this->addOption( 'dry', 'Do not save user settings back to database' );
+ $this->addArg( 'option name', 'Name of the option to change or provide statistics about', false );
+ }
+
+ /**
+ * Do the actual work
+ */
+ public function execute() {
+ if ( $this->hasOption( 'list' ) ) {
+ $this->listAvailableOptions();
+ } elseif ( $this->hasOption( 'usage' ) ) {
+ $this->showUsageStats();
+ } elseif ( $this->hasOption( 'old' )
+ && $this->hasOption( 'new' )
+ && $this->hasArg( 0 )
+ ) {
+ $this->updateOptions();
+ } else {
+ $this->maybeHelp( /* force = */ true );
+ }
+ }
+
+ /**
+ * List default options and their value
+ */
+ private function listAvailableOptions() {
+ $def = User::getDefaultOptions();
+ ksort( $def );
+ $maxOpt = 0;
+ foreach ( $def as $opt => $value ) {
+ $maxOpt = max( $maxOpt, strlen( $opt ) );
+ }
+ foreach ( $def as $opt => $value ) {
+ $this->output( sprintf( "%-{$maxOpt}s: %s\n", $opt, $value ) );
+ }
+ }
+
+ /**
+ * List options usage
+ */
+ private function showUsageStats() {
+ $option = $this->getArg( 0 );
+
+ $ret = [];
+ $defaultOptions = User::getDefaultOptions();
+
+ // We list user by user_id from one of the replica DBs
+ $dbr = wfGetDB( DB_REPLICA );
+ $result = $dbr->select( 'user',
+ [ 'user_id' ],
+ [],
+ __METHOD__
+ );
+
+ foreach ( $result as $id ) {
+ $user = User::newFromId( $id->user_id );
+
+ // Get the options and update stats
+ if ( $option ) {
+ if ( !array_key_exists( $option, $defaultOptions ) ) {
+ $this->fatalError( "Invalid user option. Use --list to see valid choices\n" );
+ }
+
+ $userValue = $user->getOption( $option );
+ if ( $userValue <> $defaultOptions[$option] ) {
+ // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
+ @$ret[$option][$userValue]++;
+ }
+ } else {
+
+ foreach ( $defaultOptions as $name => $defaultValue ) {
+ $userValue = $user->getOption( $name );
+ if ( $userValue != $defaultValue ) {
+ // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
+ @$ret[$name][$userValue]++;
+ }
+ }
+ }
+ }
+
+ foreach ( $ret as $optionName => $usageStats ) {
+ $this->output( "Usage for <$optionName> (default: '{$defaultOptions[$optionName]}'):\n" );
+ foreach ( $usageStats as $value => $count ) {
+ $this->output( " $count user(s): '$value'\n" );
+ }
+ print "\n";
+ }
+ }
+
+ /**
+ * Change our users options
+ */
+ private function updateOptions() {
+ $dryRun = $this->hasOption( 'dry' );
+ $option = $this->getArg( 0 );
+ $from = $this->getOption( 'old' );
+ $to = $this->getOption( 'new' );
+
+ if ( !$dryRun ) {
+ $this->warn( $option, $from, $to );
+ }
+
+ // We list user by user_id from one of the replica DBs
+ // @todo: getting all users in one query does not scale
+ $dbr = wfGetDB( DB_REPLICA );
+ $result = $dbr->select( 'user',
+ [ 'user_id' ],
+ [],
+ __METHOD__
+ );
+
+ foreach ( $result as $id ) {
+ $user = User::newFromId( $id->user_id );
+
+ $curValue = $user->getOption( $option );
+ $username = $user->getName();
+
+ if ( $curValue == $from ) {
+ $this->output( "Setting {$option} for $username from '{$from}' to '{$to}'): " );
+
+ // Change value
+ $user->setOption( $option, $to );
+
+ // Will not save the settings if run with --dry
+ if ( !$dryRun ) {
+ $user->saveSettings();
+ }
+ $this->output( " OK\n" );
+ } else {
+ $this->output( "Not changing '$username' using <{$option}> = '$curValue'\n" );
+ }
+ }
+ }
+
+ /**
+ * The warning message and countdown
+ *
+ * @param string $option
+ * @param string $from
+ * @param string $to
+ */
+ private function warn( $option, $from, $to ) {
+ if ( $this->hasOption( 'nowarn' ) ) {
+ return;
+ }
+
+ $this->output( <<<WARN
+The script is about to change the options for ALL USERS in the database.
+Users with option <$option> = '$from' will be made to use '$to'.
-$uo->run();
+Abort with control-c in the next five seconds....
+WARN
+ );
+ $this->countDown( 5 );
+ }
+}
-print "Done.\n";
+$maintClass = UserOptionsMaintenance::class;
+require RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/validateRegistrationFile.php b/www/wiki/maintenance/validateRegistrationFile.php
index aa1f668d..4b07796d 100644
--- a/www/wiki/maintenance/validateRegistrationFile.php
+++ b/www/wiki/maintenance/validateRegistrationFile.php
@@ -9,7 +9,7 @@ class ValidateRegistrationFile extends Maintenance {
}
public function execute() {
$validator = new ExtensionJsonValidator( function ( $msg ) {
- $this->error( $msg, 1 );
+ $this->fatalError( $msg );
} );
$validator->checkDependencies();
$path = $this->getArg( 0 );
@@ -17,10 +17,10 @@ class ValidateRegistrationFile extends Maintenance {
$validator->validate( $path );
$this->output( "$path validates against the schema!\n" );
} catch ( ExtensionJsonValidationError $e ) {
- $this->error( $e->getMessage(), 1 );
+ $this->fatalError( $e->getMessage() );
}
}
}
-$maintClass = 'ValidateRegistrationFile';
+$maintClass = ValidateRegistrationFile::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/view.php b/www/wiki/maintenance/view.php
index af7eb2d9..952b8253 100644
--- a/www/wiki/maintenance/view.php
+++ b/www/wiki/maintenance/view.php
@@ -38,22 +38,22 @@ class ViewCLI extends Maintenance {
public function execute() {
$title = Title::newFromText( $this->getArg() );
if ( !$title ) {
- $this->error( "Invalid title", true );
+ $this->fatalError( "Invalid title" );
}
$page = WikiPage::factory( $title );
$content = $page->getContent( Revision::RAW );
if ( !$content ) {
- $this->error( "Page has no content", true );
+ $this->fatalError( "Page has no content" );
}
if ( !$content instanceof TextContent ) {
- $this->error( "Non-text content models not supported", true );
+ $this->fatalError( "Non-text content models not supported" );
}
$this->output( $content->getNativeData() );
}
}
-$maintClass = "ViewCLI";
+$maintClass = ViewCLI::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/www/wiki/maintenance/wrapOldPasswords.php b/www/wiki/maintenance/wrapOldPasswords.php
index 1dbad184..1fc0f37a 100644
--- a/www/wiki/maintenance/wrapOldPasswords.php
+++ b/www/wiki/maintenance/wrapOldPasswords.php
@@ -51,12 +51,12 @@ class WrapOldPasswords extends Maintenance {
// Check that type exists and is a layered type
if ( !isset( $typeInfo[$layeredType] ) ) {
- $this->error( 'Undefined password type', true );
+ $this->fatalError( 'Undefined password type' );
}
$passObj = $passwordFactory->newFromType( $layeredType );
if ( !$passObj instanceof LayeredParameterizedPassword ) {
- $this->error( 'Layered parameterized password type must be used.', true );
+ $this->fatalError( 'Layered parameterized password type must be used.' );
}
// Extract the first layer type
@@ -81,7 +81,7 @@ class WrapOldPasswords extends Maintenance {
__METHOD__,
[
'ORDER BY' => 'user_id',
- 'LIMIT' => $this->mBatchSize,
+ 'LIMIT' => $this->getBatchSize(),
'LOCK IN SHARE MODE',
]
);
@@ -121,5 +121,5 @@ class WrapOldPasswords extends Maintenance {
}
}
-$maintClass = "WrapOldPasswords";
+$maintClass = WrapOldPasswords::class;
require_once RUN_MAINTENANCE_IF_MAIN;