summaryrefslogtreecommitdiff
path: root/maintenance
diff options
context:
space:
mode:
Diffstat (limited to 'maintenance')
-rw-r--r--maintenance/7zip.inc2
-rw-r--r--maintenance/Doxyfile7
-rw-r--r--maintenance/Maintenance.php60
-rw-r--r--maintenance/Makefile4
-rw-r--r--maintenance/README10
-rw-r--r--maintenance/archives/patch-archive-ar_content_format.sql2
-rw-r--r--maintenance/archives/patch-archive-ar_content_model.sql2
-rw-r--r--maintenance/archives/patch-archive-user-index.sql2
-rw-r--r--maintenance/archives/patch-backlinkindexes.sql8
-rw-r--r--maintenance/archives/patch-category.sql2
-rw-r--r--maintenance/archives/patch-categorylinks.sql12
-rw-r--r--maintenance/archives/patch-categorylinksindex.sql6
-rw-r--r--maintenance/archives/patch-drop-ss_admins.sql2
-rw-r--r--maintenance/archives/patch-externallinks.sql2
-rw-r--r--maintenance/archives/patch-fa_deleted.sql2
-rw-r--r--maintenance/archives/patch-fa_sha1.sql4
-rw-r--r--maintenance/archives/patch-filearchive-user-index.sql2
-rw-r--r--maintenance/archives/patch-filearchive.sql14
-rw-r--r--maintenance/archives/patch-hitcounter.sql2
-rw-r--r--maintenance/archives/patch-image-user-index.sql6
-rw-r--r--maintenance/archives/patch-img_media_mime-index.sql4
-rw-r--r--maintenance/archives/patch-img_media_type.sql4
-rw-r--r--maintenance/archives/patch-img_sha1.sql4
-rw-r--r--maintenance/archives/patch-indexes.sql6
-rw-r--r--maintenance/archives/patch-interwiki.sql6
-rw-r--r--maintenance/archives/patch-ipb_anon_only.sql14
-rw-r--r--maintenance/archives/patch-ipb_by_text.sql2
-rw-r--r--maintenance/archives/patch-ipb_deleted.sql2
-rw-r--r--maintenance/archives/patch-ipb_range_start.sql10
-rw-r--r--maintenance/archives/patch-iwlinks.sql4
-rw-r--r--maintenance/archives/patch-job.sql2
-rw-r--r--maintenance/archives/patch-job_attempts.sql4
-rw-r--r--maintenance/archives/patch-job_token.sql9
-rw-r--r--maintenance/archives/patch-langlinks.sql2
-rw-r--r--maintenance/archives/patch-linktables.sql10
-rw-r--r--maintenance/archives/patch-log_search-rename-index.sql4
-rw-r--r--maintenance/archives/patch-log_user_text.sql2
-rw-r--r--maintenance/archives/patch-logging-times-index.sql6
-rw-r--r--maintenance/archives/patch-logging.sql10
-rw-r--r--maintenance/archives/patch-mime_minor_length.sql4
-rw-r--r--maintenance/archives/patch-msg_resource.sql2
-rw-r--r--maintenance/archives/patch-oi_metadata.sql6
-rw-r--r--maintenance/archives/patch-oldimage-user-index.sql6
-rw-r--r--maintenance/archives/patch-page-page_content_model.sql2
-rw-r--r--maintenance/archives/patch-page_props-propname-page-index.sql4
-rw-r--r--maintenance/archives/patch-pagelinks.sql6
-rw-r--r--maintenance/archives/patch-parsercache.sql2
-rw-r--r--maintenance/archives/patch-pl-tl-il-unique.sql4
-rw-r--r--maintenance/archives/patch-querycache.sql6
-rw-r--r--maintenance/archives/patch-querycachetwo.sql6
-rw-r--r--maintenance/archives/patch-rc_deleted.sql2
-rw-r--r--maintenance/archives/patch-rc_id.sql2
-rw-r--r--maintenance/archives/patch-rc_ip.sql2
-rw-r--r--maintenance/archives/patch-rc_moved.sql4
-rw-r--r--maintenance/archives/patch-redirect.sql2
-rw-r--r--maintenance/archives/patch-rename-iwl_prefix.sql2
-rw-r--r--maintenance/archives/patch-restructure.sql3
-rw-r--r--maintenance/archives/patch-revision-rev_content_format.sql2
-rw-r--r--maintenance/archives/patch-revision-rev_content_model.sql2
-rw-r--r--maintenance/archives/patch-searchindex.sql6
-rw-r--r--maintenance/archives/patch-sites.sql71
-rw-r--r--maintenance/archives/patch-templatelinks.sql5
-rw-r--r--maintenance/archives/patch-testrun.sql8
-rw-r--r--maintenance/archives/patch-ufg_group-length-increase-255.sql2
-rw-r--r--maintenance/archives/patch-ufg_group-length-increase.sql2
-rw-r--r--maintenance/archives/patch-ug_group-length-increase-255.sql2
-rw-r--r--maintenance/archives/patch-ug_group-length-increase.sql2
-rw-r--r--maintenance/archives/patch-uploadstash-us_props.sql2
-rw-r--r--maintenance/archives/patch-uploadstash.sql15
-rw-r--r--maintenance/archives/patch-user-realname.sql2
-rw-r--r--maintenance/archives/patch-user_former_groups.sql4
-rw-r--r--maintenance/archives/patch-user_groups.sql4
-rw-r--r--maintenance/archives/patch-user_properties.sql4
-rw-r--r--maintenance/archives/patch-user_rights.sql4
-rw-r--r--maintenance/archives/upgradeLogging.php7
-rw-r--r--maintenance/backupPrefetch.inc4
-rw-r--r--maintenance/backupTextPass.inc4
-rw-r--r--maintenance/benchmarks/Benchmarker.php2
-rw-r--r--maintenance/benchmarks/bench_strtr_str_replace.php4
-rw-r--r--maintenance/benchmarks/bench_wfBaseConvert.php77
-rw-r--r--maintenance/changePassword.php2
-rw-r--r--maintenance/checkAutoLoader.php63
-rw-r--r--maintenance/checkBadRedirects.php2
-rw-r--r--maintenance/checkSyntax.php1
-rw-r--r--maintenance/cleanupPreferences.php104
-rw-r--r--maintenance/cleanupSpam.php14
-rw-r--r--maintenance/cleanupTitles.php2
-rw-r--r--maintenance/cleanupUploadStash.php98
-rw-r--r--maintenance/clearCacheStats.php (renamed from maintenance/clear_stats.php)4
-rw-r--r--maintenance/clearInterwikiCache.php (renamed from maintenance/clear_interwiki_cache.php)0
-rw-r--r--maintenance/compareParsers.php15
-rw-r--r--maintenance/convertUserOptions.php2
-rw-r--r--maintenance/copyFileBackend.php21
-rw-r--r--maintenance/createAndPromote.php81
-rw-r--r--maintenance/cssjanus/README24
-rw-r--r--maintenance/deleteArchivedFiles.inc11
-rw-r--r--maintenance/deleteArchivedRevisions.inc2
-rw-r--r--maintenance/deleteEqualMessages.php186
-rw-r--r--maintenance/deleteOldRevisions.php38
-rw-r--r--maintenance/deleteOrphanedRevisions.php3
-rw-r--r--maintenance/dev/includes/router.php2
-rw-r--r--maintenance/doMaintenance.php12
-rw-r--r--maintenance/dumpIterator.php2
-rw-r--r--maintenance/dumpLinks.php1
-rw-r--r--maintenance/dumpTextPass.php2
-rw-r--r--maintenance/edit.php4
-rw-r--r--maintenance/eval.php4
-rw-r--r--maintenance/fileOpPerfTest.php22
-rw-r--r--maintenance/findHooks.php7
-rw-r--r--maintenance/fixDoubleRedirects.php20
-rw-r--r--maintenance/fixSlaveDesync.php2
-rw-r--r--maintenance/formatInstallDoc.php2
-rw-r--r--maintenance/fuzz-tester.php24
-rw-r--r--maintenance/generateSitemap.php26
-rw-r--r--maintenance/getConfiguration.php89
-rw-r--r--maintenance/getText.php6
-rw-r--r--maintenance/hiphop/make18
-rw-r--r--maintenance/hiphop/run-server4
-rw-r--r--maintenance/ibm_db2/foreignkeys.sql102
-rw-r--r--maintenance/ibm_db2/patch-categorylinks-better-collation.sql21
-rw-r--r--maintenance/ibm_db2/patch-change_tag-indexes.sql5
-rw-r--r--maintenance/ibm_db2/patch-change_tag.sql8
-rw-r--r--maintenance/ibm_db2/patch-change_tag_summary.sql7
-rw-r--r--maintenance/ibm_db2/patch-change_valid_tag.sql3
-rw-r--r--maintenance/ibm_db2/patch-cl_collation-field.sql1
-rw-r--r--maintenance/ibm_db2/patch-cl_sortkey_prefix-field.sql1
-rw-r--r--maintenance/ibm_db2/patch-cl_type-field.sql1
-rw-r--r--maintenance/ibm_db2/patch-external_user.sql7
-rw-r--r--maintenance/ibm_db2/patch-ipb_allow_usertalk.sql23
-rw-r--r--maintenance/ibm_db2/patch-iw_api-field.sql1
-rw-r--r--maintenance/ibm_db2/patch-iw_api_and_wikiid.sql8
-rw-r--r--maintenance/ibm_db2/patch-iw_wikiid-field.sql1
-rw-r--r--maintenance/ibm_db2/patch-iwlinks.sql7
-rw-r--r--maintenance/ibm_db2/patch-l10n_cache.sql8
-rw-r--r--maintenance/ibm_db2/patch-log_search-rename-index.sql8
-rw-r--r--maintenance/ibm_db2/patch-log_search.sql8
-rw-r--r--maintenance/ibm_db2/patch-log_user_text.sql17
-rw-r--r--maintenance/ibm_db2/patch-module_deps.sql6
-rw-r--r--maintenance/ibm_db2/patch-msg_resource.sql8
-rw-r--r--maintenance/ibm_db2/patch-msg_resource_links.sql6
-rw-r--r--maintenance/ibm_db2/patch-rd_interwiki.sql8
-rw-r--r--maintenance/ibm_db2/patch-ss_active_users.sql11
-rw-r--r--maintenance/ibm_db2/patch-ul_value.sql3
-rw-r--r--maintenance/ibm_db2/patch-uq61_msg_resource_links.sql7
-rw-r--r--maintenance/ibm_db2/patch-uq81_msg_resource.sql7
-rw-r--r--maintenance/ibm_db2/patch-uq96_module_deps.sql7
-rw-r--r--maintenance/ibm_db2/patch-user_properties.sql10
-rw-r--r--maintenance/ibm_db2/tables.sql930
-rw-r--r--maintenance/importDump.php14
-rw-r--r--maintenance/importImages.inc8
-rw-r--r--maintenance/importImages.php55
-rw-r--r--maintenance/importSiteScripts.php3
-rw-r--r--maintenance/importTextFile.php3
-rw-r--r--maintenance/initSiteStats.php (renamed from maintenance/initStats.php)4
-rw-r--r--maintenance/install.php27
-rw-r--r--maintenance/jsduck/MetaTags.rb53
-rw-r--r--maintenance/jsduck/categories.json54
-rw-r--r--maintenance/jsduck/config.json18
-rw-r--r--maintenance/jsduck/eg-iframe.html20
-rw-r--r--maintenance/jsduck/external.js26
-rw-r--r--maintenance/jsparse.php2
-rw-r--r--maintenance/lag.php4
-rw-r--r--maintenance/language/StatOutputs.php4
-rw-r--r--maintenance/language/checkLanguage.inc6
-rw-r--r--maintenance/language/generateCollationData.php102
-rw-r--r--maintenance/language/generateNormalizerData.php6
-rw-r--r--maintenance/language/langmemusage.php11
-rw-r--r--maintenance/language/languages.inc11
-rw-r--r--maintenance/language/messageTypes.inc8
-rw-r--r--maintenance/language/messages.inc103
-rw-r--r--maintenance/language/validate.php4
-rw-r--r--maintenance/language/zhtable/Makefile2
-rw-r--r--maintenance/language/zhtable/Makefile.py391
-rw-r--r--maintenance/language/zhtable/README33
-rw-r--r--maintenance/language/zhtable/simp2trad.manual372
-rw-r--r--maintenance/language/zhtable/simp2trad_noconvert.manual139
-rw-r--r--maintenance/language/zhtable/simp2trad_supp_set.manual2
-rw-r--r--maintenance/language/zhtable/simpphrases.manual2239
-rw-r--r--maintenance/language/zhtable/simpphrases_exclude.manual21
-rw-r--r--maintenance/language/zhtable/toCN.manual275
-rw-r--r--maintenance/language/zhtable/toHK.manual2300
-rw-r--r--maintenance/language/zhtable/toSG.manual21
-rw-r--r--maintenance/language/zhtable/toSimp.manual166
-rw-r--r--maintenance/language/zhtable/toTW.manual411
-rw-r--r--maintenance/language/zhtable/toTrad.manual186
-rw-r--r--maintenance/language/zhtable/trad2simp.manual153
-rw-r--r--maintenance/language/zhtable/trad2simp_noconvert.manual5
-rw-r--r--maintenance/language/zhtable/trad2simp_supp_set.manual3
-rw-r--r--maintenance/language/zhtable/tradphrases.manual4311
-rw-r--r--maintenance/language/zhtable/tradphrases_exclude.manual330
-rw-r--r--maintenance/locking/LockServerDaemon.php15
-rw-r--r--maintenance/mcc.php73
-rw-r--r--maintenance/mctest.php22
-rw-r--r--maintenance/mergeMessageFileList.php8
-rw-r--r--maintenance/migrateUserGroup.php31
-rw-r--r--maintenance/minify.php2
-rw-r--r--maintenance/mssql/tables.sql30
-rw-r--r--maintenance/mwdocgen.php14
-rw-r--r--maintenance/mwjsduck-gen2
-rw-r--r--maintenance/namespaceDupes.php5
-rw-r--r--maintenance/nextJobDB.php148
-rw-r--r--maintenance/oracle/alterSharedConstraints.php23
-rw-r--r--maintenance/oracle/archives/patch-archive-ar_content_format.sql3
-rw-r--r--maintenance/oracle/archives/patch-archive-ar_content_model.sql3
-rw-r--r--maintenance/oracle/archives/patch-cat_hidden.sql4
-rw-r--r--maintenance/oracle/archives/patch-fa_sha1.sql5
-rw-r--r--maintenance/oracle/archives/patch-job_attempts.sql4
-rw-r--r--maintenance/oracle/archives/patch-job_token.sql12
-rw-r--r--maintenance/oracle/archives/patch-page-page_content_model.sql3
-rw-r--r--maintenance/oracle/archives/patch-rc_moved.sql4
-rw-r--r--maintenance/oracle/archives/patch-revision-rev_content_format.sql3
-rw-r--r--maintenance/oracle/archives/patch-revision-rev_content_model.sql3
-rw-r--r--maintenance/oracle/archives/patch-sites.sql34
-rw-r--r--maintenance/oracle/archives/patch-ss_admins.sql4
-rw-r--r--maintenance/oracle/archives/patch-testrun.sql2
-rw-r--r--maintenance/oracle/archives/patch-ufg_group-length-increase-255.sql (renamed from maintenance/oracle/archives/patch-ufg_group-length-increase.sql)2
-rw-r--r--maintenance/oracle/archives/patch-ug_group-length-increase-255.sql (renamed from maintenance/oracle/archives/patch-ug_group-length-increase.sql)2
-rw-r--r--maintenance/oracle/archives/patch-uploadstash-us_props.sql4
-rw-r--r--maintenance/oracle/archives/patch-user_former_groups.sql2
-rw-r--r--maintenance/oracle/tables.sql71
-rw-r--r--maintenance/orphans.php4
-rw-r--r--maintenance/parse.php2
-rw-r--r--maintenance/populateFilearchiveSha1.php107
-rw-r--r--maintenance/populateLogUsertext.php1
-rw-r--r--maintenance/populateRevisionLength.php15
-rw-r--r--maintenance/populateRevisionSha1.php13
-rw-r--r--maintenance/postgres/archives/patch-sites.sql31
-rw-r--r--maintenance/postgres/archives/patch-testrun.sql2
-rw-r--r--maintenance/postgres/tables.sql122
-rw-r--r--maintenance/preprocessDump.php9
-rw-r--r--maintenance/preprocessorFuzzTest.php18
-rw-r--r--maintenance/protect.php1
-rw-r--r--maintenance/proxyCheck.php (renamed from maintenance/proxy_check.php)2
-rw-r--r--maintenance/purgeList.php94
-rw-r--r--maintenance/purgeParserCache.php16
-rw-r--r--maintenance/reassignEdits.php1
-rw-r--r--maintenance/rebuildLocalisationCache.php9
-rw-r--r--maintenance/rebuildrecentchanges.php17
-rw-r--r--maintenance/rebuildtextindex.php27
-rw-r--r--maintenance/refreshFileHeaders.php93
-rw-r--r--maintenance/refreshImageMetadata.php2
-rw-r--r--maintenance/refreshLinks.php45
-rw-r--r--maintenance/removeUnusedAccounts.php15
-rw-r--r--maintenance/renderDump.php6
-rw-r--r--maintenance/runJobs.php73
-rw-r--r--maintenance/showCacheStats.php (renamed from maintenance/stats.php)4
-rw-r--r--maintenance/showJobs.php25
-rw-r--r--maintenance/showSiteStats.php (renamed from maintenance/showStats.php)9
-rw-r--r--maintenance/sql.php34
-rw-r--r--maintenance/sqlite.inc2
-rw-r--r--maintenance/sqlite/archives/patch-drop-ss_admins.sql22
-rw-r--r--maintenance/sqlite/archives/patch-job_token.sql8
-rw-r--r--maintenance/sqlite/archives/patch-profiling.sql12
-rw-r--r--maintenance/sqlite/archives/patch-rc_moved.sql46
-rw-r--r--maintenance/sqlite/archives/patch-rename-iwl_prefix.sql2
-rw-r--r--maintenance/sqlite/archives/patch-sites.sql71
-rw-r--r--maintenance/sqlite/archives/patch-ufg_group-length-increase-255.sql (renamed from maintenance/sqlite/archives/patch-ufg_group-length-increase.sql)10
-rw-r--r--maintenance/sqlite/archives/patch-ug_group-length-increase-255.sql (renamed from maintenance/sqlite/archives/patch-ug_group-length-increase.sql)2
-rw-r--r--maintenance/sqlite/archives/searchindex-fts3.sql4
-rw-r--r--maintenance/sqlite/archives/searchindex-no-fts.sql2
-rw-r--r--maintenance/storage/blobs.sql3
-rw-r--r--maintenance/storage/checkStorage.php8
-rw-r--r--maintenance/storage/compressOld.php9
-rw-r--r--maintenance/storage/drop_content_model_info.sql7
-rw-r--r--maintenance/storage/dumpRev.php9
-rw-r--r--maintenance/storage/fixBug20757.php14
-rwxr-xr-xmaintenance/storage/make-blobs4
-rw-r--r--maintenance/storage/moveToExternal.php4
-rw-r--r--maintenance/storage/orphanStats.php11
-rw-r--r--maintenance/storage/recompressTracked.php43
-rw-r--r--maintenance/storage/resolveStubs.php5
-rw-r--r--maintenance/storage/storageTypeStats.php1
-rw-r--r--maintenance/storage/testCompression.php8
-rw-r--r--maintenance/storage/trackBlobs.php10
-rw-r--r--maintenance/syncFileBackend.php48
-rw-r--r--maintenance/tables.sql155
-rw-r--r--maintenance/term/MWTerm.php7
-rw-r--r--maintenance/update.php60
-rw-r--r--maintenance/updateCollation.php65
-rw-r--r--maintenance/updateSearchIndex.php16
-rw-r--r--maintenance/updateSpecialPages.php2
-rw-r--r--maintenance/upgrade1_5.php1337
-rw-r--r--maintenance/userDupes.inc12
-rw-r--r--maintenance/userOptions.inc8
-rw-r--r--maintenance/userOptions.php1
-rw-r--r--maintenance/waitForSlave.php1
286 files changed, 14318 insertions, 3668 deletions
diff --git a/maintenance/7zip.inc b/maintenance/7zip.inc
index 6bb06668..590cad23 100644
--- a/maintenance/7zip.inc
+++ b/maintenance/7zip.inc
@@ -32,7 +32,7 @@
* @ingroup Maintenance
*/
class SevenZipStream {
- var $stream;
+ protected $stream;
private function stripPath( $path ) {
$prefix = 'mediawiki.compress.7z://';
diff --git a/maintenance/Doxyfile b/maintenance/Doxyfile
index e3ba4e5a..e6862acd 100644
--- a/maintenance/Doxyfile
+++ b/maintenance/Doxyfile
@@ -62,7 +62,8 @@ ALIASES = "type{1}=<b> \1 </b>:" \
"protected=\access protected" \
"public=\access public" \
"copyright=\note" \
- "license=\note"
+ "license=\note" \
+ "codeCoverageIgnore="
OPTIMIZE_OUTPUT_FOR_C = NO
OPTIMIZE_OUTPUT_JAVA = NO
OPTIMIZE_FOR_FORTRAN = NO
@@ -171,7 +172,9 @@ FILE_PATTERNS = *.c \
*.PHP5 \
*.M \
*.MM \
- *.PY
+ *.PY \
+ *.txt \
+ README
RECURSIVE = YES
EXCLUDE_SYMLINKS = YES
EXCLUDE_PATTERNS = LocalSettings.php AdminSettings.php StartProfiler.php .svn */.git/* {{EXCLUDE_PATTERNS}}
diff --git a/maintenance/Maintenance.php b/maintenance/Maintenance.php
index 69d11313..a13453df 100644
--- a/maintenance/Maintenance.php
+++ b/maintenance/Maintenance.php
@@ -109,6 +109,12 @@ abstract class Maintenance {
private $mDb = null;
/**
+ * Used when creating separate schema files.
+ * @var resource
+ */
+ public $fileHandle;
+
+ /**
* List of all the core maintenance scripts. This is added
* to scripts added by extensions in $wgMaintenanceScripts
* and returned by getMaintenanceScripts()
@@ -336,7 +342,7 @@ abstract class Maintenance {
*/
protected function error( $err, $die = 0 ) {
$this->outputChanneled( false );
- if ( php_sapi_name() == 'cli' ) {
+ if ( PHP_SAPI == 'cli' ) {
fwrite( STDERR, $err . "\n" );
} else {
print $err;
@@ -482,19 +488,11 @@ abstract class Maintenance {
$this->error( 'Cannot get command line arguments, register_argc_argv is set to false', true );
}
- if ( version_compare( phpversion(), '5.2.4' ) >= 0 ) {
- // Send PHP warnings and errors to stderr instead of stdout.
- // This aids in diagnosing problems, while keeping messages
- // out of redirected output.
- if ( ini_get( 'display_errors' ) ) {
- ini_set( 'display_errors', 'stderr' );
- }
-
- // Don't touch the setting on earlier versions of PHP,
- // as setting it would disable output if you'd wanted it.
-
- // Note that exceptions are also sent to stderr when
- // command-line mode is on, regardless of PHP version.
+ // Send PHP warnings and errors to stderr instead of stdout.
+ // This aids in diagnosing problems, while keeping messages
+ // out of redirected output.
+ if ( ini_get( 'display_errors' ) ) {
+ ini_set( 'display_errors', 'stderr' );
}
$this->loadParamsAndArgs();
@@ -515,8 +513,11 @@ abstract class Maintenance {
define( 'MEDIAWIKI', true );
$wgCommandLineMode = true;
+
# Turn off output buffering if it's on
- @ob_end_flush();
+ while( ob_get_level() > 0 ) {
+ ob_end_flush();
+ }
$this->validateParamsAndArgs();
}
@@ -922,7 +923,7 @@ abstract class Maintenance {
if ( !is_readable( $settingsFile ) ) {
$this->error( "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.", true );
}
$wgCommandLineMode = true;
return $settingsFile;
@@ -938,13 +939,9 @@ abstract class Maintenance {
$dbw = $this->getDB( DB_MASTER );
$dbw->begin( __METHOD__ );
- $tbl_arc = $dbw->tableName( 'archive' );
- $tbl_rev = $dbw->tableName( 'revision' );
- $tbl_txt = $dbw->tableName( 'text' );
-
# Get "active" text records from the revisions table
$this->output( 'Searching for active text records in revisions table...' );
- $res = $dbw->query( "SELECT DISTINCT rev_text_id FROM $tbl_rev" );
+ $res = $dbw->select( 'revision', 'rev_text_id', array(), __METHOD__, array( 'DISTINCT' ) );
foreach ( $res as $row ) {
$cur[] = $row->rev_text_id;
}
@@ -952,16 +949,19 @@ abstract class Maintenance {
# Get "active" text records from the archive table
$this->output( 'Searching for active text records in archive table...' );
- $res = $dbw->query( "SELECT DISTINCT ar_text_id FROM $tbl_arc" );
+ $res = $dbw->select( 'archive', 'ar_text_id', array(), __METHOD__, array( 'DISTINCT' ) );
foreach ( $res as $row ) {
- $cur[] = $row->ar_text_id;
+ # old pre-MW 1.5 records can have null ar_text_id's.
+ if ( $row->ar_text_id !== null ) {
+ $cur[] = $row->ar_text_id;
+ }
}
$this->output( "done.\n" );
# Get the IDs of all text records not in these sets
$this->output( 'Searching for inactive text records...' );
- $set = implode( ', ', $cur );
- $res = $dbw->query( "SELECT old_id FROM $tbl_txt WHERE old_id NOT IN ( $set )" );
+ $cond = 'old_id NOT IN ( ' . $dbw->makeList( $cur ) . ' )';
+ $res = $dbw->select( 'text', 'old_id', array( $cond ), __METHOD__, array( 'DISTINCT' ) );
$old = array();
foreach ( $res as $row ) {
$old[] = $row->old_id;
@@ -975,8 +975,7 @@ abstract class Maintenance {
# Delete as appropriate
if ( $delete && $count ) {
$this->output( 'Deleting...' );
- $set = implode( ', ', $old );
- $dbw->query( "DELETE FROM $tbl_txt WHERE old_id IN ( $set )" );
+ $dbw->delete( 'text', array( 'old_id' => $old ), __METHOD__ );
$this->output( "done.\n" );
}
@@ -1068,7 +1067,7 @@ abstract class Maintenance {
*/
private function lockSearchindex( &$db ) {
$write = array( 'searchindex' );
- $read = array( 'page', 'revision', 'text', 'interwiki', 'l10n_cache' );
+ $read = array( 'page', 'revision', 'text', 'interwiki', 'l10n_cache', 'user' );
$db->lockTables( $read, $write, __CLASS__ . '::' . __METHOD__ );
}
@@ -1144,7 +1143,8 @@ abstract class Maintenance {
$title = $titleObj->getPrefixedDBkey();
$this->output( "$title..." );
# Update searchindex
- $u = new SearchUpdate( $pageId, $titleObj->getText(), $rev->getText() );
+ # TODO: pass the Content object to SearchUpdate, let the search engine decide how to deal with it.
+ $u = new SearchUpdate( $pageId, $titleObj->getText(), $rev->getContent()->getTextForSearchIndex() );
$u->doUpdate();
$this->output( "\n" );
}
@@ -1208,7 +1208,7 @@ abstract class Maintenance {
$encPrompt = wfEscapeShellArg( $prompt );
$command = "read -er -p $encPrompt && echo \"\$REPLY\"";
$encCommand = wfEscapeShellArg( $command );
- $line = wfShellExec( "$bash -c $encCommand", $retval );
+ $line = wfShellExec( "$bash -c $encCommand", $retval, array(), array( 'walltime' => 0 ) );
if ( $retval == 0 ) {
return $line;
diff --git a/maintenance/Makefile b/maintenance/Makefile
index 30b568dc..25554751 100644
--- a/maintenance/Makefile
+++ b/maintenance/Makefile
@@ -8,7 +8,9 @@ test:
doc:
php mwdocgen.php --all
- @echo 'Doc generation done. Look at ./docs/html/'
+ ./mwjsduck-gen
+ @echo 'PHP documentation (by Doxygen) in ./docs/html/'
+ @echo 'JS documentation (by JSDuck) in ./docs/js/'
man:
php mwdocgen.php --all --generate-man
diff --git a/maintenance/README b/maintenance/README
index d6e76917..5cb6f5f5 100644
--- a/maintenance/README
+++ b/maintenance/README
@@ -56,15 +56,15 @@ installations.
importDump.php
XML dump importer
-
+
importImages.php
Import images into the wiki
-
+
importTextFile.php
Import the contents of a text file into a wiki page
moveBatch.php
- Move a batch of pages
+ Move a batch of pages
namespaceDupes.php
Check articles name to see if they conflict with new/existing namespaces
@@ -93,7 +93,7 @@ installations.
runJobs.php
Immediately complete all jobs in the job queue
- stats.php
+ showCacheStats.php
Show all statistics stored in the cache
undelete.php
@@ -106,4 +106,4 @@ installations.
Update pages restriction to the new schema
userOptions.php
- Change user options \ No newline at end of file
+ Change user options
diff --git a/maintenance/archives/patch-archive-ar_content_format.sql b/maintenance/archives/patch-archive-ar_content_format.sql
new file mode 100644
index 00000000..81f9fca8
--- /dev/null
+++ b/maintenance/archives/patch-archive-ar_content_format.sql
@@ -0,0 +1,2 @@
+ALTER TABLE /*$wgDBprefix*/archive
+ ADD ar_content_format varbinary(64) DEFAULT NULL;
diff --git a/maintenance/archives/patch-archive-ar_content_model.sql b/maintenance/archives/patch-archive-ar_content_model.sql
new file mode 100644
index 00000000..1a8b630e
--- /dev/null
+++ b/maintenance/archives/patch-archive-ar_content_model.sql
@@ -0,0 +1,2 @@
+ALTER TABLE /*$wgDBprefix*/archive
+ ADD ar_content_model varbinary(32) DEFAULT NULL;
diff --git a/maintenance/archives/patch-archive-user-index.sql b/maintenance/archives/patch-archive-user-index.sql
index 62baa2dd..997b4a97 100644
--- a/maintenance/archives/patch-archive-user-index.sql
+++ b/maintenance/archives/patch-archive-user-index.sql
@@ -1,4 +1,4 @@
-- Adds a user,timestamp index to the archive table
-- Used for browsing deleted contributions and renames
-ALTER TABLE /*$wgDBprefix*/archive
+ALTER TABLE /*$wgDBprefix*/archive
ADD INDEX usertext_timestamp ( ar_user_text , ar_timestamp );
diff --git a/maintenance/archives/patch-backlinkindexes.sql b/maintenance/archives/patch-backlinkindexes.sql
index 5facd9ea..22cc5871 100644
--- a/maintenance/archives/patch-backlinkindexes.sql
+++ b/maintenance/archives/patch-backlinkindexes.sql
@@ -1,10 +1,10 @@
---
+--
-- patch-backlinkindexes.sql
---
+--
-- Per bug 6440 / http://bugzilla.wikimedia.org/show_bug.cgi?id=6440
--
-- Improve performance of the "what links here"-type queries
---
+--
ALTER TABLE /*$wgDBprefix*/pagelinks
DROP INDEX pl_namespace,
@@ -13,7 +13,7 @@ ALTER TABLE /*$wgDBprefix*/pagelinks
ALTER TABLE /*$wgDBprefix*/templatelinks
DROP INDEX tl_namespace,
ADD INDEX tl_namespace(tl_namespace, tl_title, tl_from);
-
+
ALTER TABLE /*$wgDBprefix*/imagelinks
DROP INDEX il_to,
ADD INDEX il_to(il_to, il_from);
diff --git a/maintenance/archives/patch-category.sql b/maintenance/archives/patch-category.sql
index 416500c3..97a5690d 100644
--- a/maintenance/archives/patch-category.sql
+++ b/maintenance/archives/patch-category.sql
@@ -8,7 +8,7 @@ CREATE TABLE /*$wgDBprefix*/category (
cat_files int signed NOT NULL default 0,
cat_hidden tinyint(1) unsigned NOT NULL default 0,
-
+
PRIMARY KEY (cat_id),
UNIQUE KEY (cat_title),
diff --git a/maintenance/archives/patch-categorylinks.sql b/maintenance/archives/patch-categorylinks.sql
index 02168d7f..0af0cf91 100644
--- a/maintenance/archives/patch-categorylinks.sql
+++ b/maintenance/archives/patch-categorylinks.sql
@@ -6,7 +6,7 @@
CREATE TABLE /*$wgDBprefix*/categorylinks (
-- Key to page_id of the page defined as a category member.
cl_from int unsigned NOT NULL default '0',
-
+
-- Name of the category.
-- This is also the page_title of the category's description page;
-- all such pages are in namespace 14 (NS_CATEGORY).
@@ -17,20 +17,20 @@ CREATE TABLE /*$wgDBprefix*/categorylinks (
-- isn't always ideal, but collations seem to be an exciting
-- and dangerous new world in MySQL...
--
- -- Truncate so that the cl_sortkey key fits in 1000 bytes
+ -- Truncate so that the cl_sortkey key fits in 1000 bytes
-- (MyISAM 5 with server_character_set=utf8)
cl_sortkey varchar(70) binary NOT NULL default '',
-
+
-- This isn't really used at present. Provided for an optional
-- sorting method by approximate addition time.
cl_timestamp timestamp NOT NULL,
-
+
UNIQUE KEY cl_from(cl_from,cl_to),
-
+
-- This key is trouble. It's incomplete, AND it's too big
-- when collation is set to UTF-8. Bleeeacch!
KEY cl_sortkey(cl_to,cl_sortkey),
-
+
-- Not really used?
KEY cl_timestamp(cl_to,cl_timestamp)
diff --git a/maintenance/archives/patch-categorylinksindex.sql b/maintenance/archives/patch-categorylinksindex.sql
index 8a9ff123..24ad84fe 100644
--- a/maintenance/archives/patch-categorylinksindex.sql
+++ b/maintenance/archives/patch-categorylinksindex.sql
@@ -1,10 +1,10 @@
---
+--
-- patch-categorylinksindex.sql
---
+--
-- Per bug 10280 / http://bugzilla.wikimedia.org/show_bug.cgi?id=10280
--
-- Improve enum continuation performance of the what pages belong to a category query
---
+--
ALTER TABLE /*$wgDBprefix*/categorylinks
DROP INDEX cl_sortkey,
diff --git a/maintenance/archives/patch-drop-ss_admins.sql b/maintenance/archives/patch-drop-ss_admins.sql
new file mode 100644
index 00000000..13c3d3b0
--- /dev/null
+++ b/maintenance/archives/patch-drop-ss_admins.sql
@@ -0,0 +1,2 @@
+-- field is deprecated and no longer updated as of 1.5
+ALTER TABLE /*_*/site_stats DROP COLUMN ss_admins; \ No newline at end of file
diff --git a/maintenance/archives/patch-externallinks.sql b/maintenance/archives/patch-externallinks.sql
index 0a4768ca..fc5017db 100644
--- a/maintenance/archives/patch-externallinks.sql
+++ b/maintenance/archives/patch-externallinks.sql
@@ -5,7 +5,7 @@ CREATE TABLE /*$wgDBprefix*/externallinks (
el_from int(8) unsigned NOT NULL default '0',
el_to blob NOT NULL,
el_index blob NOT NULL,
-
+
KEY (el_from, el_to(40)),
KEY (el_to(60), el_from),
KEY (el_index(60))
diff --git a/maintenance/archives/patch-fa_deleted.sql b/maintenance/archives/patch-fa_deleted.sql
index 3483f8cf..7ab65239 100644
--- a/maintenance/archives/patch-fa_deleted.sql
+++ b/maintenance/archives/patch-fa_deleted.sql
@@ -1,3 +1,3 @@
-- Adding fa_deleted field for additional content suppression
-ALTER TABLE /*$wgDBprefix*/filearchive
+ALTER TABLE /*$wgDBprefix*/filearchive
ADD fa_deleted tinyint unsigned NOT NULL default '0';
diff --git a/maintenance/archives/patch-fa_sha1.sql b/maintenance/archives/patch-fa_sha1.sql
new file mode 100644
index 00000000..931bc44d
--- /dev/null
+++ b/maintenance/archives/patch-fa_sha1.sql
@@ -0,0 +1,4 @@
+-- Add fa_sha1 and related index
+ALTER TABLE /*$wgDBprefix*/filearchive
+ ADD COLUMN fa_sha1 varbinary(32) NOT NULL default '';
+CREATE INDEX /*i*/fa_sha1 ON /*$wgDBprefix*/filearchive (fa_sha1(10));
diff --git a/maintenance/archives/patch-filearchive-user-index.sql b/maintenance/archives/patch-filearchive-user-index.sql
index c79000ad..0d8c3ab1 100644
--- a/maintenance/archives/patch-filearchive-user-index.sql
+++ b/maintenance/archives/patch-filearchive-user-index.sql
@@ -1,5 +1,5 @@
-- Adding index to sort by uploader
-ALTER TABLE /*$wgDBprefix*/filearchive
+ALTER TABLE /*$wgDBprefix*/filearchive
ADD INDEX fa_user_timestamp (fa_user_text,fa_timestamp),
-- Remove useless, incomplete index
DROP INDEX fa_deleted_user;
diff --git a/maintenance/archives/patch-filearchive.sql b/maintenance/archives/patch-filearchive.sql
index 587a2ab4..f75da8be 100644
--- a/maintenance/archives/patch-filearchive.sql
+++ b/maintenance/archives/patch-filearchive.sql
@@ -4,30 +4,30 @@
CREATE TABLE /*$wgDBprefix*/filearchive (
-- Unique row id
fa_id int not null auto_increment,
-
+
-- Original base filename; key to image.img_name, page.page_title, etc
fa_name varchar(255) binary NOT NULL default '',
-
+
-- Filename of archived file, if an old revision
fa_archive_name varchar(255) binary default '',
-
+
-- Which storage bin (directory tree or object store) the file data
-- is stored in. Should be 'deleted' for files that have been deleted;
-- any other bin is not yet in use.
fa_storage_group varbinary(16),
-
+
-- SHA-1 of the file contents plus extension, used as a key for storage.
-- eg 8f8a562add37052a1848ff7771a2c515db94baa9.jpg
--
-- If NULL, the file was missing at deletion time or has been purged
-- from the archival storage.
fa_storage_key varbinary(64) default '',
-
+
-- Deletion information, if this file is deleted.
fa_deleted_user int,
fa_deleted_timestamp binary(14) default '',
fa_deleted_reason text,
-
+
-- Duped fields from image
fa_size int unsigned default '0',
fa_width int default '0',
@@ -41,7 +41,7 @@ CREATE TABLE /*$wgDBprefix*/filearchive (
fa_user int unsigned default '0',
fa_user_text varchar(255) binary default '',
fa_timestamp binary(14) default '',
-
+
PRIMARY KEY (fa_id),
INDEX (fa_name, fa_timestamp), -- pick out by image name
INDEX (fa_storage_group, fa_storage_key), -- pick out dupe files
diff --git a/maintenance/archives/patch-hitcounter.sql b/maintenance/archives/patch-hitcounter.sql
index 50e56e0c..c87c9592 100644
--- a/maintenance/archives/patch-hitcounter.sql
+++ b/maintenance/archives/patch-hitcounter.sql
@@ -1,5 +1,5 @@
--
--- hitcounter table is used to buffer page hits before they are periodically
+-- hitcounter table is used to buffer page hits before they are periodically
-- counted and added to the cur_counter column in the cur table.
-- December 2003
--
diff --git a/maintenance/archives/patch-image-user-index.sql b/maintenance/archives/patch-image-user-index.sql
index db56b221..a74d7bd5 100644
--- a/maintenance/archives/patch-image-user-index.sql
+++ b/maintenance/archives/patch-image-user-index.sql
@@ -1,8 +1,8 @@
---
+--
-- image-user-index.sql
---
+--
-- Add user/timestamp index to current image versions
---
+--
ALTER TABLE /*$wgDBprefix*/image
ADD INDEX img_usertext_timestamp (img_user_text,img_timestamp);
diff --git a/maintenance/archives/patch-img_media_mime-index.sql b/maintenance/archives/patch-img_media_mime-index.sql
new file mode 100644
index 00000000..bfaf84f9
--- /dev/null
+++ b/maintenance/archives/patch-img_media_mime-index.sql
@@ -0,0 +1,4 @@
+-- New index on image table to allow searches for types i.e. video webm
+-- Added 2013-01-08
+
+CREATE INDEX /*i*/img_media_mime ON /*_*/image (img_media_type,img_major_mime,img_minor_mime);
diff --git a/maintenance/archives/patch-img_media_type.sql b/maintenance/archives/patch-img_media_type.sql
index 857eb98e..87b8c2f5 100644
--- a/maintenance/archives/patch-img_media_type.sql
+++ b/maintenance/archives/patch-img_media_type.sql
@@ -4,11 +4,11 @@
ALTER TABLE /*$wgDBprefix*/image ADD (
-- Media type as defined by the MEDIATYPE_xxx constants
img_media_type ENUM("UNKNOWN", "BITMAP", "DRAWING", "AUDIO", "VIDEO", "MULTIMEDIA", "OFFICE", "TEXT", "EXECUTABLE", "ARCHIVE") default NULL,
-
+
-- major part of a MIME media type as defined by IANA
-- see http://www.iana.org/assignments/media-types/
img_major_mime ENUM("unknown", "application", "audio", "image", "text", "video", "message", "model", "multipart") NOT NULL default "unknown",
-
+
-- minor part of a MIME media type as defined by IANA
-- the minor parts are not required to adher to any standard
-- but should be consistent throughout the database
diff --git a/maintenance/archives/patch-img_sha1.sql b/maintenance/archives/patch-img_sha1.sql
index 35950f58..0a375c4f 100644
--- a/maintenance/archives/patch-img_sha1.sql
+++ b/maintenance/archives/patch-img_sha1.sql
@@ -1,8 +1,8 @@
-- Add img_sha1, oi_sha1 and related indexes
ALTER TABLE /*$wgDBprefix*/image
ADD COLUMN img_sha1 varbinary(32) NOT NULL default '',
- ADD INDEX img_sha1 (img_sha1);
+ ADD INDEX img_sha1 (img_sha1(10));
ALTER TABLE /*$wgDBprefix*/oldimage
ADD COLUMN oi_sha1 varbinary(32) NOT NULL default '',
- ADD INDEX oi_sha1 (oi_sha1);
+ ADD INDEX oi_sha1 (oi_sha1(10));
diff --git a/maintenance/archives/patch-indexes.sql b/maintenance/archives/patch-indexes.sql
index c56838fd..c24d9953 100644
--- a/maintenance/archives/patch-indexes.sql
+++ b/maintenance/archives/patch-indexes.sql
@@ -1,8 +1,8 @@
---
+--
-- patch-indexes.sql
---
+--
-- Fix up table indexes; new to stable release in November 2003
---
+--
ALTER TABLE IF EXISTS /*$wgDBprefix*/links
DROP INDEX l_from,
diff --git a/maintenance/archives/patch-interwiki.sql b/maintenance/archives/patch-interwiki.sql
index 321765b9..57b79456 100644
--- a/maintenance/archives/patch-interwiki.sql
+++ b/maintenance/archives/patch-interwiki.sql
@@ -5,16 +5,16 @@
CREATE TABLE /*$wgDBprefix*/interwiki (
-- The interwiki prefix, (e.g. "Meatball", or the language prefix "de")
iw_prefix varchar(32) NOT NULL,
-
+
-- The URL of the wiki, with "$1" as a placeholder for an article name.
-- Any spaces in the name will be transformed to underscores before
-- insertion.
iw_url blob NOT NULL,
-
+
-- A boolean value indicating whether the wiki is in this project
-- (used, for example, to detect redirect loops)
iw_local BOOL NOT NULL,
-
+
UNIQUE KEY iw_prefix (iw_prefix)
) /*$wgDBTableOptions*/;
diff --git a/maintenance/archives/patch-ipb_anon_only.sql b/maintenance/archives/patch-ipb_anon_only.sql
index fcd257c7..bb39c1d9 100644
--- a/maintenance/archives/patch-ipb_anon_only.sql
+++ b/maintenance/archives/patch-ipb_anon_only.sql
@@ -1,9 +1,9 @@
--- Add extra option fields to the ipblocks table, add some extra indexes,
--- convert infinity values in ipb_expiry to something that sorts better,
--- extend ipb_address and range fields, add a unique index for block conflict
+-- Add extra option fields to the ipblocks table, add some extra indexes,
+-- convert infinity values in ipb_expiry to something that sorts better,
+-- extend ipb_address and range fields, add a unique index for block conflict
-- detection.
--- Conflicts in the new unique index can be handled by creating a new
+-- Conflicts in the new unique index can be handled by creating a new
-- table and inserting into it instead of doing an ALTER TABLE.
@@ -22,7 +22,7 @@ CREATE TABLE /*$wgDBprefix*/ipblocks_newunique (
ipb_expiry varbinary(14) NOT NULL default '',
ipb_range_start tinyblob NOT NULL,
ipb_range_end tinyblob NOT NULL,
-
+
PRIMARY KEY ipb_id (ipb_id),
UNIQUE INDEX ipb_address_unique (ipb_address(255), ipb_user, ipb_auto),
INDEX ipb_user (ipb_user),
@@ -32,8 +32,8 @@ CREATE TABLE /*$wgDBprefix*/ipblocks_newunique (
) /*$wgDBTableOptions*/;
-INSERT IGNORE INTO /*$wgDBprefix*/ipblocks_newunique
- (ipb_id, ipb_address, ipb_user, ipb_by, ipb_reason, ipb_timestamp, ipb_auto, ipb_expiry, ipb_range_start, ipb_range_end, ipb_anon_only, ipb_create_account)
+INSERT IGNORE INTO /*$wgDBprefix*/ipblocks_newunique
+ (ipb_id, ipb_address, ipb_user, ipb_by, ipb_reason, ipb_timestamp, ipb_auto, ipb_expiry, ipb_range_start, ipb_range_end, ipb_anon_only, ipb_create_account)
SELECT ipb_id, ipb_address, ipb_user, ipb_by, ipb_reason, ipb_timestamp, ipb_auto, ipb_expiry, ipb_range_start, ipb_range_end, 0 , ipb_user=0
FROM /*$wgDBprefix*/ipblocks;
diff --git a/maintenance/archives/patch-ipb_by_text.sql b/maintenance/archives/patch-ipb_by_text.sql
index c0b620d3..e809d102 100644
--- a/maintenance/archives/patch-ipb_by_text.sql
+++ b/maintenance/archives/patch-ipb_by_text.sql
@@ -4,7 +4,7 @@
ALTER TABLE /*$wgDBprefix*/ipblocks
ADD ipb_by_text varchar(255) binary NOT NULL default '';
-UPDATE /*$wgDBprefix*/ipblocks
+UPDATE /*$wgDBprefix*/ipblocks
JOIN /*$wgDBprefix*/user ON ipb_by = user_id
SET ipb_by_text = user_name
WHERE ipb_by != 0; \ No newline at end of file
diff --git a/maintenance/archives/patch-ipb_deleted.sql b/maintenance/archives/patch-ipb_deleted.sql
index fad94778..b12ddaaa 100644
--- a/maintenance/archives/patch-ipb_deleted.sql
+++ b/maintenance/archives/patch-ipb_deleted.sql
@@ -1,3 +1,3 @@
-- Adding ipb_deleted field for hiding usernames
-ALTER TABLE /*$wgDBprefix*/ipblocks
+ALTER TABLE /*$wgDBprefix*/ipblocks
ADD ipb_deleted bool NOT NULL default 0;
diff --git a/maintenance/archives/patch-ipb_range_start.sql b/maintenance/archives/patch-ipb_range_start.sql
index 64a906d4..84cba8f6 100644
--- a/maintenance/archives/patch-ipb_range_start.sql
+++ b/maintenance/archives/patch-ipb_range_start.sql
@@ -1,5 +1,5 @@
-- Add the range handling fields
-ALTER TABLE /*$wgDBprefix*/ipblocks
+ALTER TABLE /*$wgDBprefix*/ipblocks
ADD ipb_range_start tinyblob NOT NULL default '',
ADD ipb_range_end tinyblob NOT NULL default '',
ADD INDEX ipb_range (ipb_range_start(8), ipb_range_end(8));
@@ -7,15 +7,15 @@ ALTER TABLE /*$wgDBprefix*/ipblocks
-- Initialise fields
-- Only range blocks match ipb_address LIKE '%/%', this fact is used in the code already
-UPDATE /*$wgDBprefix*/ipblocks
- SET
- ipb_range_start = LPAD(HEX(
+UPDATE /*$wgDBprefix*/ipblocks
+ SET
+ ipb_range_start = LPAD(HEX(
(SUBSTRING_INDEX(ipb_address, '.', 1) << 24)
+ (SUBSTRING_INDEX(SUBSTRING_INDEX(ipb_address, '.', 2), '.', -1) << 16)
+ (SUBSTRING_INDEX(SUBSTRING_INDEX(ipb_address, '.', 3), '.', -1) << 24)
+ (SUBSTRING_INDEX(SUBSTRING_INDEX(ipb_address, '/', 1), '.', -1)) ), 8, '0' ),
- ipb_range_end = LPAD(HEX(
+ ipb_range_end = LPAD(HEX(
(SUBSTRING_INDEX(ipb_address, '.', 1) << 24)
+ (SUBSTRING_INDEX(SUBSTRING_INDEX(ipb_address, '.', 2), '.', -1) << 16)
+ (SUBSTRING_INDEX(SUBSTRING_INDEX(ipb_address, '.', 3), '.', -1) << 24)
diff --git a/maintenance/archives/patch-iwlinks.sql b/maintenance/archives/patch-iwlinks.sql
index 89b34cb1..b7bd3f13 100644
--- a/maintenance/archives/patch-iwlinks.sql
+++ b/maintenance/archives/patch-iwlinks.sql
@@ -1,10 +1,10 @@
---
+--
-- Track inline interwiki links
--
CREATE TABLE /*_*/iwlinks (
-- page_id of the referring page
iwl_from int unsigned NOT NULL default 0,
-
+
-- Interwiki prefix code of the target
iwl_prefix varbinary(20) NOT NULL default '',
diff --git a/maintenance/archives/patch-job.sql b/maintenance/archives/patch-job.sql
index c9199efb..662f5d27 100644
--- a/maintenance/archives/patch-job.sql
+++ b/maintenance/archives/patch-job.sql
@@ -1,7 +1,7 @@
-- Jobs performed by parallel apache threads or a command-line daemon
CREATE TABLE /*_*/job (
job_id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT,
-
+
-- Command name
-- Limited to 60 to prevent key length overflow
job_cmd varbinary(60) NOT NULL default '',
diff --git a/maintenance/archives/patch-job_attempts.sql b/maintenance/archives/patch-job_attempts.sql
new file mode 100644
index 00000000..47b73e81
--- /dev/null
+++ b/maintenance/archives/patch-job_attempts.sql
@@ -0,0 +1,4 @@
+ALTER TABLE /*_*/job
+ ADD COLUMN job_attempts integer unsigned NOT NULL default 0;
+
+CREATE INDEX /*i*/job_cmd_token_id ON /*_*/job (job_cmd,job_token,job_id);
diff --git a/maintenance/archives/patch-job_token.sql b/maintenance/archives/patch-job_token.sql
new file mode 100644
index 00000000..080fa97c
--- /dev/null
+++ b/maintenance/archives/patch-job_token.sql
@@ -0,0 +1,9 @@
+ALTER TABLE /*_*/job
+ ADD COLUMN job_random integer unsigned NOT NULL default 0,
+ ADD COLUMN job_token varbinary(32) NOT NULL default '',
+ ADD COLUMN job_token_timestamp varbinary(14) NULL default NULL,
+ ADD COLUMN job_sha1 varbinary(32) NOT NULL default '';
+
+CREATE INDEX /*i*/job_sha1 ON /*_*/job (job_sha1);
+CREATE INDEX /*i*/job_cmd_token ON /*_*/job (job_cmd,job_token,job_random);
+
diff --git a/maintenance/archives/patch-langlinks.sql b/maintenance/archives/patch-langlinks.sql
index ffff07c0..5594acd5 100644
--- a/maintenance/archives/patch-langlinks.sql
+++ b/maintenance/archives/patch-langlinks.sql
@@ -1,7 +1,7 @@
CREATE TABLE /*$wgDBprefix*/langlinks (
-- page_id of the referring page
ll_from int unsigned NOT NULL default '0',
-
+
-- Language code of the target
ll_lang varbinary(20) NOT NULL default '',
diff --git a/maintenance/archives/patch-linktables.sql b/maintenance/archives/patch-linktables.sql
index b15878c3..d53d2ea3 100644
--- a/maintenance/archives/patch-linktables.sql
+++ b/maintenance/archives/patch-linktables.sql
@@ -6,13 +6,13 @@ DROP TABLE IF EXISTS /*$wgDBprefix*/links;
CREATE TABLE /*$wgDBprefix*/links (
-- Key to the page_id of the page containing the link.
l_from int unsigned NOT NULL default '0',
-
+
-- Key to the page_id of the link target.
-- An unfortunate consequence of this is that rename
-- operations require changing the links entries for
-- all links to the moved page.
l_to int unsigned NOT NULL default '0',
-
+
UNIQUE KEY l_from(l_from,l_to),
KEY (l_to)
@@ -27,7 +27,7 @@ DROP TABLE IF EXISTS /*$wgDBprefix*/brokenlinks;
CREATE TABLE /*$wgDBprefix*/brokenlinks (
-- Key to the page_id of the page containing the link.
bl_from int unsigned NOT NULL default '0',
-
+
-- Text of the target page title ("namesapce:title").
-- Unfortunately this doesn't split the namespace index
-- key and therefore can't easily be joined to anything.
@@ -46,12 +46,12 @@ DROP TABLE IF EXISTS /*$wgDBprefix*/imagelinks;
CREATE TABLE /*$wgDBprefix*/imagelinks (
-- Key to page_id of the page containing the image / media link.
il_from int unsigned NOT NULL default '0',
-
+
-- Filename of target image.
-- This is also the page_title of the file's description page;
-- all such pages are in namespace 6 (NS_FILE).
il_to varchar(255) binary NOT NULL default '',
-
+
UNIQUE KEY il_from(il_from,il_to),
KEY (il_to)
diff --git a/maintenance/archives/patch-log_search-rename-index.sql b/maintenance/archives/patch-log_search-rename-index.sql
index 41e051d8..7e1113e6 100644
--- a/maintenance/archives/patch-log_search-rename-index.sql
+++ b/maintenance/archives/patch-log_search-rename-index.sql
@@ -1,7 +1,7 @@
-- 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,
+ALTER TABLE /*_*/log_search
+ DROP PRIMARY KEY,
ADD UNIQUE INDEX ls_field_val (ls_field,ls_value,ls_log_id);
diff --git a/maintenance/archives/patch-log_user_text.sql b/maintenance/archives/patch-log_user_text.sql
index 9a783d87..12ca75e5 100644
--- a/maintenance/archives/patch-log_user_text.sql
+++ b/maintenance/archives/patch-log_user_text.sql
@@ -1,4 +1,4 @@
-ALTER TABLE /*$wgDBprefix*/logging
+ALTER TABLE /*$wgDBprefix*/logging
ADD log_user_text varchar(255) binary NOT NULL default '',
ADD log_page int unsigned NULL,
CHANGE log_type log_type varbinary(32) NOT NULL,
diff --git a/maintenance/archives/patch-logging-times-index.sql b/maintenance/archives/patch-logging-times-index.sql
index e66ceec4..5f24f5c3 100644
--- a/maintenance/archives/patch-logging-times-index.sql
+++ b/maintenance/archives/patch-logging-times-index.sql
@@ -1,8 +1,8 @@
---
+--
-- patch-logging-times-index.sql
---
+--
-- Add a very humble index on logging times
---
+--
ALTER TABLE /*$wgDBprefix*/logging
ADD INDEX times (log_timestamp);
diff --git a/maintenance/archives/patch-logging.sql b/maintenance/archives/patch-logging.sql
index b5cfdf72..79df0dd4 100644
--- a/maintenance/archives/patch-logging.sql
+++ b/maintenance/archives/patch-logging.sql
@@ -7,21 +7,21 @@ CREATE TABLE /*$wgDBprefix*/logging (
-- action field, but only the type controls categorization.
log_type varbinary(10) NOT NULL default '',
log_action varbinary(10) NOT NULL default '',
-
+
-- Timestamp. Duh.
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,
-
+
-- 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,
log_title varchar(255) binary NOT NULL default '',
-
+
-- Freeform text. Interpreted as edit history comments.
log_comment varchar(255) NOT NULL default '',
-
+
-- LF separated list of miscellaneous parameters
log_params blob NOT NULL,
diff --git a/maintenance/archives/patch-mime_minor_length.sql b/maintenance/archives/patch-mime_minor_length.sql
index 8b63d1f0..88dd64cf 100644
--- a/maintenance/archives/patch-mime_minor_length.sql
+++ b/maintenance/archives/patch-mime_minor_length.sql
@@ -3,8 +3,8 @@ ALTER TABLE /*_*/filearchive
ALTER TABLE /*_*/image
MODIFY COLUMN img_minor_mime varbinary(100) NOT NULL default "unknown";
-
+
ALTER TABLE /*_*/oldimage
MODIFY COLUMN oi_minor_mime varbinary(100) NOT NULL default "unknown";
-
+
INSERT INTO /*_*/updatelog(ul_key) VALUES ('mime_minor_length');
diff --git a/maintenance/archives/patch-msg_resource.sql b/maintenance/archives/patch-msg_resource.sql
index f4f35339..9fa05d2a 100644
--- a/maintenance/archives/patch-msg_resource.sql
+++ b/maintenance/archives/patch-msg_resource.sql
@@ -2,7 +2,7 @@
CREATE TABLE /*_*/msg_resource (
-- Resource name
mr_resource varbinary(255) NOT NULL,
- -- Language code
+ -- Language code
mr_lang varbinary(32) NOT NULL,
-- JSON blob. This is an incomplete JSON object, i.e. without the wrapping {}
mr_blob mediumblob NOT NULL,
diff --git a/maintenance/archives/patch-oi_metadata.sql b/maintenance/archives/patch-oi_metadata.sql
index bc848878..df043c55 100644
--- a/maintenance/archives/patch-oi_metadata.sql
+++ b/maintenance/archives/patch-oi_metadata.sql
@@ -1,10 +1,10 @@
---
+--
-- patch-oi_metadata.sql
---
+--
-- Add data to allow for direct reference to old images
-- Some re-indexing here.
-- Old images can be included into pages effeciently now.
---
+--
ALTER TABLE /*$wgDBprefix*/oldimage
DROP INDEX oi_name,
diff --git a/maintenance/archives/patch-oldimage-user-index.sql b/maintenance/archives/patch-oldimage-user-index.sql
index 949625eb..2c7f8071 100644
--- a/maintenance/archives/patch-oldimage-user-index.sql
+++ b/maintenance/archives/patch-oldimage-user-index.sql
@@ -1,8 +1,8 @@
---
+--
-- oldimage-user-index.sql
---
+--
-- Add user/timestamp index to old image versions
---
+--
ALTER TABLE /*$wgDBprefix*/oldimage
ADD INDEX oi_usertext_timestamp (oi_user_text,oi_timestamp);
diff --git a/maintenance/archives/patch-page-page_content_model.sql b/maintenance/archives/patch-page-page_content_model.sql
new file mode 100644
index 00000000..30434d93
--- /dev/null
+++ b/maintenance/archives/patch-page-page_content_model.sql
@@ -0,0 +1,2 @@
+ALTER TABLE /*$wgDBprefix*/page
+ ADD page_content_model varbinary(32) DEFAULT NULL;
diff --git a/maintenance/archives/patch-page_props-propname-page-index.sql b/maintenance/archives/patch-page_props-propname-page-index.sql
new file mode 100644
index 00000000..822fa04d
--- /dev/null
+++ b/maintenance/archives/patch-page_props-propname-page-index.sql
@@ -0,0 +1,4 @@
+--
+-- Creates the pp_propname_page index on page_props
+--
+CREATE UNIQUE INDEX /*i*/pp_propname_page ON /*_*/page_props (pp_propname, pp_page);
diff --git a/maintenance/archives/patch-pagelinks.sql b/maintenance/archives/patch-pagelinks.sql
index 118592fb..cea89b52 100644
--- a/maintenance/archives/patch-pagelinks.sql
+++ b/maintenance/archives/patch-pagelinks.sql
@@ -1,7 +1,7 @@
--
-- Create the new pagelinks table to merge links and brokenlinks data,
-- and populate it.
---
+--
-- Unlike the old links and brokenlinks, these records will not need to be
-- altered when target pages are created, deleted, or renamed. This should
-- reduce the amount of severe database frustration that happens when widely-
@@ -19,14 +19,14 @@
CREATE TABLE /*$wgDBprefix*/pagelinks (
-- Key to the page_id of the page containing the link.
pl_from int unsigned NOT NULL default '0',
-
+
-- Key to page_namespace/page_title of the target page.
-- The target page may or may not exist, and due to renames
-- and deletions may refer to different page records as time
-- goes by.
pl_namespace int NOT NULL default '0',
pl_title varchar(255) binary NOT NULL default '',
-
+
UNIQUE KEY pl_from(pl_from,pl_namespace,pl_title),
KEY (pl_namespace,pl_title)
diff --git a/maintenance/archives/patch-parsercache.sql b/maintenance/archives/patch-parsercache.sql
index 395a81bd..5fe241c3 100644
--- a/maintenance/archives/patch-parsercache.sql
+++ b/maintenance/archives/patch-parsercache.sql
@@ -1,5 +1,5 @@
--
--- parsercache table, for cacheing complete parsed articles
+-- parsercache table, for cacheing complete parsed articles
-- before they are imbedded in the skin.
--
diff --git a/maintenance/archives/patch-pl-tl-il-unique.sql b/maintenance/archives/patch-pl-tl-il-unique.sql
index 186a2036..a3566705 100644
--- a/maintenance/archives/patch-pl-tl-il-unique.sql
+++ b/maintenance/archives/patch-pl-tl-il-unique.sql
@@ -1,6 +1,6 @@
---
+--
-- patch-pl-tl-il-unique-index.sql
---
+--
-- Make reorderings of UNIQUE indices UNIQUE as well
DROP INDEX /*i*/pl_namespace ON /*_*/pagelinks;
diff --git a/maintenance/archives/patch-querycache.sql b/maintenance/archives/patch-querycache.sql
index e6da79cc..8e1a5188 100644
--- a/maintenance/archives/patch-querycache.sql
+++ b/maintenance/archives/patch-querycache.sql
@@ -3,14 +3,14 @@
CREATE TABLE /*$wgDBprefix*/querycache (
-- A key name, generally the base name of of the special page.
qc_type varbinary(32) NOT NULL,
-
+
-- Some sort of stored value. Sizes, counts...
qc_value int unsigned NOT NULL default '0',
-
+
-- Target namespace+title
qc_namespace int NOT NULL default '0',
qc_title varchar(255) binary NOT NULL default '',
-
+
KEY (qc_type,qc_value)
) /*$wgDBTableOptions*/;
diff --git a/maintenance/archives/patch-querycachetwo.sql b/maintenance/archives/patch-querycachetwo.sql
index 01623bc7..79131310 100644
--- a/maintenance/archives/patch-querycachetwo.sql
+++ b/maintenance/archives/patch-querycachetwo.sql
@@ -3,14 +3,14 @@
CREATE TABLE /*$wgDBprefix*/querycachetwo (
-- A key name, generally the base name of of the special page.
qcc_type varbinary(32) NOT NULL,
-
+
-- Some sort of stored value. Sizes, counts...
qcc_value int unsigned NOT NULL default '0',
-
+
-- Target namespace+title
qcc_namespace int NOT NULL default '0',
qcc_title varchar(255) binary NOT NULL default '',
-
+
-- Target namespace+title2
qcc_namespacetwo int NOT NULL default '0',
qcc_titletwo varchar(255) binary NOT NULL default '',
diff --git a/maintenance/archives/patch-rc_deleted.sql b/maintenance/archives/patch-rc_deleted.sql
index 04ead974..f4bbd0f9 100644
--- a/maintenance/archives/patch-rc_deleted.sql
+++ b/maintenance/archives/patch-rc_deleted.sql
@@ -1,6 +1,6 @@
-- Adding rc_deleted field for revisiondelete
-- Add rc_logid to match log_id
-ALTER TABLE /*$wgDBprefix*/recentchanges
+ALTER TABLE /*$wgDBprefix*/recentchanges
ADD rc_deleted tinyint unsigned NOT NULL default '0',
ADD rc_logid int unsigned NOT NULL default '0',
ADD rc_log_type varbinary(255) NULL default NULL,
diff --git a/maintenance/archives/patch-rc_id.sql b/maintenance/archives/patch-rc_id.sql
index 3b023753..28caee0e 100644
--- a/maintenance/archives/patch-rc_id.sql
+++ b/maintenance/archives/patch-rc_id.sql
@@ -1,6 +1,6 @@
-- Primary key in recentchanges
-ALTER TABLE /*$wgDBprefix*/recentchanges
+ALTER TABLE /*$wgDBprefix*/recentchanges
ADD rc_id int NOT NULL auto_increment,
ADD PRIMARY KEY rc_id (rc_id);
diff --git a/maintenance/archives/patch-rc_ip.sql b/maintenance/archives/patch-rc_ip.sql
index 6b0b0534..4d93300f 100644
--- a/maintenance/archives/patch-rc_ip.sql
+++ b/maintenance/archives/patch-rc_ip.sql
@@ -1,6 +1,6 @@
-- Adding the rc_ip field for logging of IP addresses in recentchanges
-ALTER TABLE /*$wgDBprefix*/recentchanges
+ALTER TABLE /*$wgDBprefix*/recentchanges
ADD rc_ip varbinary(40) NOT NULL default '',
ADD INDEX rc_ip (rc_ip);
diff --git a/maintenance/archives/patch-rc_moved.sql b/maintenance/archives/patch-rc_moved.sql
new file mode 100644
index 00000000..2fa1de6b
--- /dev/null
+++ b/maintenance/archives/patch-rc_moved.sql
@@ -0,0 +1,4 @@
+-- rc_moved_to_ns and rc_moved_to_title is no longer used, delete the fields
+
+ALTER TABLE /*$wgDBprefix*/recentchanges DROP COLUMN rc_moved_to_ns,
+ DROP COLUMN rc_moved_to_title;
diff --git a/maintenance/archives/patch-redirect.sql b/maintenance/archives/patch-redirect.sql
index 5d7218bc..d2957df4 100644
--- a/maintenance/archives/patch-redirect.sql
+++ b/maintenance/archives/patch-redirect.sql
@@ -1,7 +1,7 @@
--
-- Create the new redirect table.
-- For each redirect, this table contains exactly one row defining its target
---
+--
CREATE TABLE /*$wgDBprefix*/redirect (
-- Key to the page_id of the redirect page
rd_from int unsigned NOT NULL default '0',
diff --git a/maintenance/archives/patch-rename-iwl_prefix.sql b/maintenance/archives/patch-rename-iwl_prefix.sql
index 4b11b36b..4a410037 100644
--- a/maintenance/archives/patch-rename-iwl_prefix.sql
+++ b/maintenance/archives/patch-rename-iwl_prefix.sql
@@ -1,4 +1,4 @@
---
+--
-- Recreates the iwl_prefix index for the iwlinks table
--
CREATE UNIQUE INDEX /*i*/iwl_prefix_title_from ON /*_*/iwlinks (iwl_prefix, iwl_title, iwl_from);
diff --git a/maintenance/archives/patch-restructure.sql b/maintenance/archives/patch-restructure.sql
index 7b638483..a5bc3e52 100644
--- a/maintenance/archives/patch-restructure.sql
+++ b/maintenance/archives/patch-restructure.sql
@@ -38,7 +38,6 @@ CREATE TABLE /*$wgDBprefix*/revision (
rev_minor_edit tinyint unsigned NOT NULL default '0',
rev_deleted tinyint unsigned NOT NULL default '0',
-
PRIMARY KEY rev_page_id (rev_page, rev_id),
UNIQUE INDEX rev_id (rev_id),
INDEX rev_timestamp (rev_timestamp),
@@ -53,7 +52,7 @@ CREATE TABLE /*$wgDBprefix*/revision (
-- old_id int(8) unsigned NOT NULL auto_increment,
-- old_text mediumtext NOT NULL,
-- old_flags tinyblob NOT NULL,
---
+--
-- PRIMARY KEY old_id (old_id)
-- );
diff --git a/maintenance/archives/patch-revision-rev_content_format.sql b/maintenance/archives/patch-revision-rev_content_format.sql
new file mode 100644
index 00000000..22aeb8a7
--- /dev/null
+++ b/maintenance/archives/patch-revision-rev_content_format.sql
@@ -0,0 +1,2 @@
+ALTER TABLE /*$wgDBprefix*/revision
+ ADD rev_content_format varbinary(64) DEFAULT NULL;
diff --git a/maintenance/archives/patch-revision-rev_content_model.sql b/maintenance/archives/patch-revision-rev_content_model.sql
new file mode 100644
index 00000000..1ba05721
--- /dev/null
+++ b/maintenance/archives/patch-revision-rev_content_model.sql
@@ -0,0 +1,2 @@
+ALTER TABLE /*$wgDBprefix*/revision
+ ADD rev_content_model varbinary(32) DEFAULT NULL;
diff --git a/maintenance/archives/patch-searchindex.sql b/maintenance/archives/patch-searchindex.sql
index 9b635a8f..36507a2b 100644
--- a/maintenance/archives/patch-searchindex.sql
+++ b/maintenance/archives/patch-searchindex.sql
@@ -10,13 +10,13 @@ DROP TABLE IF EXISTS /*$wgDBprefix*/searchindex;
CREATE TABLE /*$wgDBprefix*/searchindex (
-- Key to page_id
si_page int unsigned NOT NULL,
-
+
-- Munged version of title
si_title varchar(255) NOT NULL default '',
-
+
-- Munged version of body text
si_text mediumtext NOT NULL,
-
+
UNIQUE KEY (si_page)
) ENGINE=MyISAM;
diff --git a/maintenance/archives/patch-sites.sql b/maintenance/archives/patch-sites.sql
new file mode 100644
index 00000000..88392748
--- /dev/null
+++ b/maintenance/archives/patch-sites.sql
@@ -0,0 +1,71 @@
+-- Patch to add the sites and site_identifiers tables.
+-- Licence: GNU GPL v2+
+-- Author: Jeroen De Dauw < jeroendedauw@gmail.com >
+
+
+-- Holds all the sites known to the wiki.
+CREATE TABLE IF NOT EXISTS /*_*/sites (
+-- Numeric id of the site
+ site_id INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
+
+ -- Global identifier for the site, ie 'enwiktionary'
+ site_global_key varbinary(32) NOT NULL,
+
+ -- Type of the site, ie 'mediawiki'
+ site_type varbinary(32) NOT NULL,
+
+ -- Group of the site, ie 'wikipedia'
+ site_group varbinary(32) NOT NULL,
+
+ -- Source of the site data, ie 'local', 'wikidata', 'my-magical-repo'
+ site_source varbinary(32) NOT NULL,
+
+ -- Language code of the sites primary language.
+ site_language varbinary(32) NOT NULL,
+
+ -- Protocol of the site, ie 'http://', 'irc://', '//'
+ -- This field is an index for lookups and is build from type specific data in site_data.
+ site_protocol varbinary(32) NOT NULL,
+
+ -- Domain of the site in reverse order, ie 'org.mediawiki.www.'
+ -- This field is an index for lookups and is build from type specific data in site_data.
+ site_domain VARCHAR(255) NOT NULL,
+
+ -- Type dependent site data.
+ site_data BLOB NOT NULL,
+
+ -- If site.tld/path/key:pageTitle should forward users to the page on
+ -- the actual site, where "key" is the local identifier.
+ site_forward bool NOT NULL,
+
+ -- Type dependent site config.
+ -- For instance if template transclusion should be allowed if it's a MediaWiki.
+ site_config BLOB NOT NULL
+) /*$wgDBTableOptions*/;
+
+CREATE UNIQUE INDEX /*i*/sites_global_key ON /*_*/sites (site_global_key);
+CREATE INDEX /*i*/sites_type ON /*_*/sites (site_type);
+CREATE INDEX /*i*/sites_group ON /*_*/sites (site_group);
+CREATE INDEX /*i*/sites_source ON /*_*/sites (site_source);
+CREATE INDEX /*i*/sites_language ON /*_*/sites (site_language);
+CREATE INDEX /*i*/sites_protocol ON /*_*/sites (site_protocol);
+CREATE INDEX /*i*/sites_domain ON /*_*/sites (site_domain);
+CREATE INDEX /*i*/sites_forward ON /*_*/sites (site_forward);
+
+
+
+-- Links local site identifiers to their corresponding site.
+CREATE TABLE IF NOT EXISTS /*_*/site_identifiers (
+ -- Key on site.site_id
+ si_site INT UNSIGNED NOT NULL,
+
+ -- local key type, ie 'interwiki' or 'langlink'
+ si_type varbinary(32) NOT NULL,
+
+ -- local key value, ie 'en' or 'wiktionary'
+ si_key varbinary(32) NOT NULL
+) /*$wgDBTableOptions*/;
+
+CREATE UNIQUE INDEX /*i*/site_ids_type ON /*_*/site_identifiers (si_type, si_key);
+CREATE INDEX /*i*/site_ids_site ON /*_*/site_identifiers (si_site);
+CREATE INDEX /*i*/site_ids_key ON /*_*/site_identifiers (si_key); \ No newline at end of file
diff --git a/maintenance/archives/patch-templatelinks.sql b/maintenance/archives/patch-templatelinks.sql
index a545b34e..086b6a1b 100644
--- a/maintenance/archives/patch-templatelinks.sql
+++ b/maintenance/archives/patch-templatelinks.sql
@@ -4,16 +4,15 @@
CREATE TABLE /*$wgDBprefix*/templatelinks (
-- Key to the page_id of the page containing the link.
tl_from int unsigned NOT NULL default '0',
-
+
-- Key to page_namespace/page_title of the target page.
-- The target page may or may not exist, and due to renames
-- and deletions may refer to different page records as time
-- goes by.
tl_namespace int NOT NULL default '0',
tl_title varchar(255) binary NOT NULL default '',
-
+
UNIQUE KEY tl_from(tl_from,tl_namespace,tl_title),
KEY (tl_namespace,tl_title)
-
) /*$wgDBTableOptions*/;
diff --git a/maintenance/archives/patch-testrun.sql b/maintenance/archives/patch-testrun.sql
index 8591d81d..6699b554 100644
--- a/maintenance/archives/patch-testrun.sql
+++ b/maintenance/archives/patch-testrun.sql
@@ -12,13 +12,13 @@ drop table if exists /*$wgDBprefix*/testrun;
create table /*$wgDBprefix*/testrun (
tr_id int not null auto_increment,
-
+
tr_date char(14) binary,
tr_mw_version blob,
tr_php_version blob,
tr_db_version blob,
tr_uname blob,
-
+
primary key (tr_id)
) engine=InnoDB;
@@ -26,10 +26,10 @@ create table /*$wgDBprefix*/testitem (
ti_run int not null,
ti_name varchar(255),
ti_success bool,
-
+
unique key (ti_run, ti_name),
key (ti_run, ti_success),
-
+
foreign key (ti_run) references /*$wgDBprefix*/testrun(tr_id)
on delete cascade
) engine=InnoDB;
diff --git a/maintenance/archives/patch-ufg_group-length-increase-255.sql b/maintenance/archives/patch-ufg_group-length-increase-255.sql
new file mode 100644
index 00000000..4b7f0d38
--- /dev/null
+++ b/maintenance/archives/patch-ufg_group-length-increase-255.sql
@@ -0,0 +1,2 @@
+ALTER TABLE /*_*/user_former_groups
+ MODIFY COLUMN ufg_group varbinary(255) NOT NULL default '';
diff --git a/maintenance/archives/patch-ufg_group-length-increase.sql b/maintenance/archives/patch-ufg_group-length-increase.sql
deleted file mode 100644
index e24cba02..00000000
--- a/maintenance/archives/patch-ufg_group-length-increase.sql
+++ /dev/null
@@ -1,2 +0,0 @@
-ALTER TABLE /*_*/user_former_groups
- MODIFY COLUMN ufg_group varbinary(32) NOT NULL default '';
diff --git a/maintenance/archives/patch-ug_group-length-increase-255.sql b/maintenance/archives/patch-ug_group-length-increase-255.sql
new file mode 100644
index 00000000..79e17ac0
--- /dev/null
+++ b/maintenance/archives/patch-ug_group-length-increase-255.sql
@@ -0,0 +1,2 @@
+ALTER TABLE /*_*/user_groups
+ MODIFY COLUMN ug_group varbinary(255) NOT NULL default '';
diff --git a/maintenance/archives/patch-ug_group-length-increase.sql b/maintenance/archives/patch-ug_group-length-increase.sql
deleted file mode 100644
index e944a858..00000000
--- a/maintenance/archives/patch-ug_group-length-increase.sql
+++ /dev/null
@@ -1,2 +0,0 @@
-ALTER TABLE /*_*/user_groups
- MODIFY COLUMN ug_group varbinary(32) NOT NULL default '';
diff --git a/maintenance/archives/patch-uploadstash-us_props.sql b/maintenance/archives/patch-uploadstash-us_props.sql
new file mode 100644
index 00000000..d64515a8
--- /dev/null
+++ b/maintenance/archives/patch-uploadstash-us_props.sql
@@ -0,0 +1,2 @@
+ALTER TABLE /*$wgDBprefix*/uploadstash
+ ADD COLUMN us_props blob;
diff --git a/maintenance/archives/patch-uploadstash.sql b/maintenance/archives/patch-uploadstash.sql
index 2512076f..14eaeab0 100644
--- a/maintenance/archives/patch-uploadstash.sql
+++ b/maintenance/archives/patch-uploadstash.sql
@@ -1,10 +1,10 @@
--
--- Store information about newly uploaded files before they're
+-- Store information about newly uploaded files before they're
-- moved into the actual filestore
--
CREATE TABLE /*_*/uploadstash (
us_id int unsigned NOT NULL PRIMARY KEY auto_increment,
-
+
-- the user who uploaded the file.
us_user int unsigned NOT NULL,
@@ -14,16 +14,16 @@ CREATE TABLE /*_*/uploadstash (
-- the original path
us_orig_path varchar(255) NOT NULL,
-
+
-- the temporary path at which the file is actually stored
us_path varchar(255) NOT NULL,
-
+
-- which type of upload the file came from (sometimes)
us_source_type varchar(50),
-
+
-- the date/time on which the file was added
us_timestamp varbinary(14) not null,
-
+
us_status varchar(50) not null,
-- file properties from File::getPropsFromPath. these may prove unnecessary.
@@ -33,12 +33,11 @@ CREATE TABLE /*_*/uploadstash (
us_sha1 varchar(31) NOT NULL,
us_mime varchar(255),
-- Media type as defined by the MEDIATYPE_xxx constants, should duplicate definition in the image table
- us_media_type ENUM("UNKNOWN", "BITMAP", "DRAWING", "AUDIO", "VIDEO", "MULTIMEDIA", "OFFICE", "TEXT", "EXECUTABLE", "ARCHIVE") default NULL,
+ us_media_type ENUM("UNKNOWN", "BITMAP", "DRAWING", "AUDIO", "VIDEO", "MULTIMEDIA", "OFFICE", "TEXT", "EXECUTABLE", "ARCHIVE") default NULL,
-- image-specific properties
us_image_width int unsigned,
us_image_height int unsigned,
us_image_bits smallint unsigned
-
) /*$wgDBTableOptions*/;
-- sometimes there's a delete for all of a user's stuff.
diff --git a/maintenance/archives/patch-user-realname.sql b/maintenance/archives/patch-user-realname.sql
index 96edaa43..de7cee75 100644
--- a/maintenance/archives/patch-user-realname.sql
+++ b/maintenance/archives/patch-user-realname.sql
@@ -1,5 +1,5 @@
-- Add a 'real name' field where users can specify the name they want
-- used for author attribution or other places that real names matter.
-ALTER TABLE user
+ALTER TABLE user
ADD (user_real_name varchar(255) binary NOT NULL default '');
diff --git a/maintenance/archives/patch-user_former_groups.sql b/maintenance/archives/patch-user_former_groups.sql
index ef56db06..b043196d 100644
--- a/maintenance/archives/patch-user_former_groups.sql
+++ b/maintenance/archives/patch-user_former_groups.sql
@@ -1,9 +1,9 @@
--- Stores the groups the user has once belonged to.
+-- Stores the groups the user has once belonged to.
-- The user may still belong these groups. Check user_groups.
CREATE TABLE /*_*/user_former_groups (
-- Key to user_id
ufg_user int unsigned NOT NULL default 0,
- ufg_group varbinary(32) NOT NULL default ''
+ ufg_group varbinary(255) NOT NULL default ''
) /*$wgDBTableOptions*/;
CREATE UNIQUE INDEX /*i*/ufg_user_group ON /*_*/user_former_groups (ufg_user,ufg_group);
diff --git a/maintenance/archives/patch-user_groups.sql b/maintenance/archives/patch-user_groups.sql
index c3740332..1683cf2a 100644
--- a/maintenance/archives/patch-user_groups.sql
+++ b/maintenance/archives/patch-user_groups.sql
@@ -9,7 +9,7 @@
CREATE TABLE /*$wgDBprefix*/user_groups (
-- Key to user_id
ug_user int unsigned NOT NULL default '0',
-
+
-- Group names are short symbolic string keys.
-- The set of group names is open-ended, though in practice
-- only some predefined ones are likely to be used.
@@ -19,7 +19,7 @@ CREATE TABLE /*$wgDBprefix*/user_groups (
-- permissions of any group they're explicitly in, plus
-- the implicit '*' and 'user' groups.
ug_group varbinary(16) NOT NULL default '',
-
+
PRIMARY KEY (ug_user,ug_group),
KEY (ug_group)
) /*$wgDBTableOptions*/;
diff --git a/maintenance/archives/patch-user_properties.sql b/maintenance/archives/patch-user_properties.sql
index e30e00dc..85b00616 100644
--- a/maintenance/archives/patch-user_properties.sql
+++ b/maintenance/archives/patch-user_properties.sql
@@ -10,10 +10,10 @@
CREATE TABLE /*_*/user_properties(
-- Foreign key to user.user_id
up_user int not null,
-
+
-- Name of the option being saved. This is indexed for bulk lookup.
up_property varbinary(32) not null,
-
+
-- Property value as a string.
up_value blob
) /*$wgDBTableOptions*/;
diff --git a/maintenance/archives/patch-user_rights.sql b/maintenance/archives/patch-user_rights.sql
index 9866654c..4947cb1f 100644
--- a/maintenance/archives/patch-user_rights.sql
+++ b/maintenance/archives/patch-user_rights.sql
@@ -8,10 +8,10 @@
CREATE TABLE /*$wgDBprefix*/user_rights (
-- Key to user_id
ur_user int unsigned NOT NULL,
-
+
-- Comma-separated list of permission keys
ur_rights tinyblob NOT NULL,
-
+
UNIQUE KEY ur_user (ur_user)
) /*$wgDBTableOptions*/;
diff --git a/maintenance/archives/upgradeLogging.php b/maintenance/archives/upgradeLogging.php
index 2c28011b..f0806458 100644
--- a/maintenance/archives/upgradeLogging.php
+++ b/maintenance/archives/upgradeLogging.php
@@ -34,9 +34,9 @@ class UpdateLogging {
/**
* @var DatabaseBase
*/
- var $dbw;
- var $batchSize = 1000;
- var $minTs = false;
+ public $dbw;
+ public $batchSize = 1000;
+ public $minTs = false;
function execute() {
$this->dbw = wfGetDB( DB_MASTER );
@@ -211,4 +211,3 @@ EOT;
$ul = new UpdateLogging;
$ul->execute();
-
diff --git a/maintenance/backupPrefetch.inc b/maintenance/backupPrefetch.inc
index 0e12a1ce..cc0a7e17 100644
--- a/maintenance/backupPrefetch.inc
+++ b/maintenance/backupPrefetch.inc
@@ -48,9 +48,9 @@ class BaseDump {
var $infiles = null;
function BaseDump( $infile ) {
- $this->infiles = explode(';',$infile);
+ $this->infiles = explode( ';', $infile );
$this->reader = new XMLReader();
- $infile = array_shift($this->infiles);
+ $infile = array_shift( $this->infiles );
if (defined( 'LIBXML_PARSEHUGE' ) ) {
$this->reader->open( $infile, null, LIBXML_PARSEHUGE );
}
diff --git a/maintenance/backupTextPass.inc b/maintenance/backupTextPass.inc
index f1f09546..0b8b3445 100644
--- a/maintenance/backupTextPass.inc
+++ b/maintenance/backupTextPass.inc
@@ -169,7 +169,7 @@ class TextPassDumper extends BackupDumper {
$this->xmlwriterobj = new XmlDumpWriter();
$input = fopen( $this->input, "rt" );
- $result = $this->readDump( $input );
+ $this->readDump( $input );
if ( $this->spawnProc ) {
$this->closeSpawn();
@@ -294,7 +294,7 @@ class TextPassDumper extends BackupDumper {
}
function setTimeExceeded() {
- $this->timeExceeded = True;
+ $this->timeExceeded = true;
}
function checkIfTimeExceeded() {
diff --git a/maintenance/benchmarks/Benchmarker.php b/maintenance/benchmarks/Benchmarker.php
index c198e0ff..98b35b53 100644
--- a/maintenance/benchmarks/Benchmarker.php
+++ b/maintenance/benchmarks/Benchmarker.php
@@ -75,7 +75,7 @@ abstract class Benchmarker extends Maintenance {
}
}
- public function getFormattedResults( ) {
+ public function getFormattedResults() {
$ret = '';
foreach( $this->results as $res ) {
// show function with args
diff --git a/maintenance/benchmarks/bench_strtr_str_replace.php b/maintenance/benchmarks/bench_strtr_str_replace.php
index 9fa7c8e3..10c5cd0b 100644
--- a/maintenance/benchmarks/bench_strtr_str_replace.php
+++ b/maintenance/benchmarks/bench_strtr_str_replace.php
@@ -26,11 +26,11 @@
require_once( __DIR__ . '/Benchmarker.php' );
function bfNormalizeTitleStrTr( $str ) {
- return strtr( $str, '_', ' ' );
+ return strtr( $str, '_', ' ' );
}
function bfNormalizeTitleStrReplace( $str ) {
- return str_replace( '_', ' ', $str );
+ return str_replace( '_', ' ', $str );
}
/**
diff --git a/maintenance/benchmarks/bench_wfBaseConvert.php b/maintenance/benchmarks/bench_wfBaseConvert.php
new file mode 100644
index 00000000..a1e5c6a4
--- /dev/null
+++ b/maintenance/benchmarks/bench_wfBaseConvert.php
@@ -0,0 +1,77 @@
+<?php
+/**
+ * Benchmark for wfBaseConvert
+ *
+ * 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
+ * @author Tyler Romeo
+ */
+
+require_once( __DIR__ . '/Benchmarker.php' );
+
+/**
+ * Maintenance script that benchmarks wfBaseConvert().
+ *
+ * @ingroup Benchmark
+ */
+class bench_wfBaseConvert extends Benchmarker {
+
+ public function __construct() {
+ parent::__construct();
+ $this->mDescription = "Benchmark for wfBaseConvert.";
+ $this->addOption( "inbase", "Input base", false, true );
+ $this->addOption( "outbase", "Output base", false, true );
+ $this->addOption( "length", "Size in digits to generate for input", false, true );
+ }
+
+ public function execute() {
+ $inbase = $this->getOption( "inbase", 36 );
+ $outbase = $this->getOption( "outbase", 16 );
+ $length = $this->getOption( "length", 128 );
+ $number = self::makeRandomNumber( $inbase, $length );
+
+ $this->bench( array(
+ array(
+ 'function' => 'wfBaseConvert',
+ 'args' => array( $number, $inbase, $outbase, 0, true, 'php' )
+ ),
+ array(
+ 'function' => 'wfBaseConvert',
+ 'args' => array( $number, $inbase, $outbase, 0, true, 'bcmath' )
+ ),
+ array(
+ 'function' => 'wfBaseConvert',
+ 'args' => array( $number, $inbase, $outbase, 0, true, 'gmp' )
+ ),
+ ));
+
+ $this->output( $this->getFormattedResults() );
+ }
+
+ protected static function makeRandomNumber( $base, $length ) {
+ $baseChars = "0123456789abcdefghijklmnopqrstuvwxyz";
+ $res = "";
+ for( $i = 0; $i < $length; $i++ ) {
+ $res .= $baseChars[mt_rand(0, $base - 1)];
+ }
+ return $res;
+ }
+}
+
+$maintClass = 'bench_wfBaseConvert';
+require_once( RUN_MAINTENANCE_IF_MAIN );
diff --git a/maintenance/changePassword.php b/maintenance/changePassword.php
index f276fc16..861610b7 100644
--- a/maintenance/changePassword.php
+++ b/maintenance/changePassword.php
@@ -46,7 +46,7 @@ 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->error( "A \"user\" or \"userid\" must be set to change the password for", true );
}
if ( !$user || !$user->getId() ) {
$this->error( "No such user: " . $this->getOption( 'user' ), true );
diff --git a/maintenance/checkAutoLoader.php b/maintenance/checkAutoLoader.php
deleted file mode 100644
index 8d0e442b..00000000
--- a/maintenance/checkAutoLoader.php
+++ /dev/null
@@ -1,63 +0,0 @@
-<?php
-/**
- * Check the autoloader
- *
- * 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 classes definitions in the autoloader.
- *
- * @ingroup Maintenance
- */
-class CheckAutoLoader extends Maintenance {
- public function __construct() {
- parent::__construct();
- $this->mDescription = "AutoLoader sanity checks";
- }
- public function execute() {
- global $wgAutoloadLocalClasses, $IP;
- $files = array_unique( $wgAutoloadLocalClasses );
-
- foreach ( $files as $file ) {
- if ( function_exists( 'parsekit_compile_file' ) ) {
- $parseInfo = parsekit_compile_file( "$IP/$file" );
- $classes = array_keys( $parseInfo['class_table'] );
- } else {
- $contents = file_get_contents( "$IP/$file" );
- $m = array();
- preg_match_all( '/\n\s*class\s+([a-zA-Z0-9_]+)/', $contents, $m, PREG_PATTERN_ORDER );
- $classes = $m[1];
- }
- foreach ( $classes as $class ) {
- if ( !isset( $wgAutoloadLocalClasses[$class] ) ) {
- // printf( "%-50s Unlisted, in %s\n", $class, $file );
- $this->output( "\t'$class' => '$file',\n" );
- } elseif ( $wgAutoloadLocalClasses[$class] !== $file ) {
- $this->output( "$class: Wrong file: found in $file, listed in " . $wgAutoloadLocalClasses[$class] . "\n" );
- }
- }
- }
- }
-}
-
-$maintClass = "CheckAutoLoader";
-require_once( RUN_MAINTENANCE_IF_MAIN );
diff --git a/maintenance/checkBadRedirects.php b/maintenance/checkBadRedirects.php
index 670b93de..4ba7e66b 100644
--- a/maintenance/checkBadRedirects.php
+++ b/maintenance/checkBadRedirects.php
@@ -50,7 +50,7 @@ class CheckBadRedirects extends Maintenance {
$title = Title::makeTitle( $row->page_namespace, $row->page_title );
$rev = Revision::newFromId( $row->page_latest );
if ( $rev ) {
- $target = Title::newFromRedirect( $rev->getText() );
+ $target = $rev->getContent()->getRedirectTarget();
if ( !$target ) {
$this->output( $title->getPrefixedText() . "\n" );
}
diff --git a/maintenance/checkSyntax.php b/maintenance/checkSyntax.php
index 0a22f58c..1e44e239 100644
--- a/maintenance/checkSyntax.php
+++ b/maintenance/checkSyntax.php
@@ -368,4 +368,3 @@ class CheckSyntax extends Maintenance {
$maintClass = "CheckSyntax";
require_once( RUN_MAINTENANCE_IF_MAIN );
-
diff --git a/maintenance/cleanupPreferences.php b/maintenance/cleanupPreferences.php
index f37af775..c0a526b7 100644
--- a/maintenance/cleanupPreferences.php
+++ b/maintenance/cleanupPreferences.php
@@ -1,52 +1,52 @@
-<?php
-/**
- * Remove hidden 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
- * 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
- * @author TyA <tya.wiki@gmail.com>
- * @see [[bugzilla:30976]]
- * @ingroup Maintenance
- */
-
-require_once( __DIR__ . '/Maintenance.php' );
-
-/**
- * Maintenance script that removes hidden preferences from the database.
- *
- * @ingroup Maintenance
- */
-class CleanupPreferences extends Maintenance {
- public function execute() {
- global $wgHiddenPrefs;
-
- $dbw = wfGetDB( DB_MASTER );
- $dbw->begin();
- foreach( $wgHiddenPrefs as $item ) {
- $dbw->delete(
- 'user_properties',
- array( 'up_property' => $item ),
- __METHOD__
- );
- };
- $dbw->commit();
- $this->output( "Finished!\n" );
- }
-}
-
-$maintClass = 'CleanupPreferences'; // Tells it to run the class
-require_once( RUN_MAINTENANCE_IF_MAIN );
+<?php
+/**
+ * Remove hidden 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
+ * 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
+ * @author TyA <tya.wiki@gmail.com>
+ * @see [[bugzilla:30976]]
+ * @ingroup Maintenance
+ */
+
+require_once( __DIR__ . '/Maintenance.php' );
+
+/**
+ * Maintenance script that removes hidden preferences from the database.
+ *
+ * @ingroup Maintenance
+ */
+class CleanupPreferences extends Maintenance {
+ public function execute() {
+ global $wgHiddenPrefs;
+
+ $dbw = wfGetDB( DB_MASTER );
+ $dbw->begin( __METHOD__ );
+ foreach( $wgHiddenPrefs as $item ) {
+ $dbw->delete(
+ 'user_properties',
+ array( 'up_property' => $item ),
+ __METHOD__
+ );
+ };
+ $dbw->commit( __METHOD__ );
+ $this->output( "Finished!\n" );
+ }
+}
+
+$maintClass = 'CleanupPreferences'; // Tells it to run the class
+require_once( RUN_MAINTENANCE_IF_MAIN );
diff --git a/maintenance/cleanupSpam.php b/maintenance/cleanupSpam.php
index e20bcd87..a41423ae 100644
--- a/maintenance/cleanupSpam.php
+++ b/maintenance/cleanupSpam.php
@@ -44,7 +44,7 @@ class CleanupSpam extends Maintenance {
$username = wfMessage( 'spambot_username' )->text();
$wgUser = User::newFromName( $username );
if ( !$wgUser ) {
- $this->error( "Invalid username", true );
+ $this->error( "Invalid username specified in 'spambot_username' message: $username", true );
}
// Create the user if necessary
if ( !$wgUser->getId() ) {
@@ -103,7 +103,8 @@ class CleanupSpam extends Maintenance {
$rev = Revision::newFromTitle( $title );
$currentRevId = $rev->getId();
- while ( $rev && ( $rev->isDeleted( Revision::DELETED_TEXT ) || LinkFilter::matchEntry( $rev->getText() , $domain ) ) ) {
+ while ( $rev && ( $rev->isDeleted( Revision::DELETED_TEXT )
+ || LinkFilter::matchEntry( $rev->getContent( Revision::RAW ), $domain ) ) ) {
$rev = $rev->getPrevious();
}
@@ -117,8 +118,10 @@ class CleanupSpam extends Maintenance {
$page = WikiPage::factory( $title );
if ( $rev ) {
// Revert to this revision
+ $content = $rev->getContent( Revision::RAW );
+
$this->output( "reverting\n" );
- $page->doEdit( $rev->getText(), wfMessage( 'spam_reverting', $domain )->inContentLanguage()->text(),
+ $page->doEditContent( $content, wfMessage( 'spam_reverting', $domain )->inContentLanguage()->text(),
EDIT_UPDATE, $rev->getId() );
} elseif ( $this->hasOption( 'delete' ) ) {
// Didn't find a non-spammy revision, blank the page
@@ -126,8 +129,11 @@ class CleanupSpam extends Maintenance {
$page->doDeleteArticle( wfMessage( 'spam_deleting', $domain )->inContentLanguage()->text() );
} else {
// Didn't find a non-spammy revision, blank the page
+ $handler = ContentHandler::getForTitle( $title );
+ $content = $handler->makeEmptyContent();
+
$this->output( "blanking\n" );
- $page->doEdit( '', wfMessage( 'spam_blanking', $domain )->inContentLanguage()->text() );
+ $page->doEditContent( $content, wfMessage( 'spam_blanking', $domain )->inContentLanguage()->text() );
}
$dbw->commit( __METHOD__ );
}
diff --git a/maintenance/cleanupTitles.php b/maintenance/cleanupTitles.php
index ad2577aa..66f9e87f 100644
--- a/maintenance/cleanupTitles.php
+++ b/maintenance/cleanupTitles.php
@@ -114,7 +114,7 @@ class TitleCleanup extends TableCleanup {
protected function moveInconsistentPage( $row, $title ) {
if ( $title->exists() || $title->getInterwiki() || !$title->canExist() ) {
if ( $title->getInterwiki() || !$title->canExist() ) {
- $prior = $title->getPrefixedDbKey();
+ $prior = $title->getPrefixedDBkey();
} else {
$prior = $title->getDBkey();
}
diff --git a/maintenance/cleanupUploadStash.php b/maintenance/cleanupUploadStash.php
index cc329461..441e8ae3 100644
--- a/maintenance/cleanupUploadStash.php
+++ b/maintenance/cleanupUploadStash.php
@@ -41,50 +41,98 @@ class UploadStashCleanup extends Maintenance {
}
public function execute() {
+ global $wgUploadStashMaxAge;
+
$repo = RepoGroup::singleton()->getLocalRepo();
+ $tempRepo = $repo->getTempRepo();
$dbr = $repo->getSlaveDb();
// how far back should this look for files to delete?
- global $wgUploadStashMaxAge;
+ $cutoff = time() - $wgUploadStashMaxAge;
$this->output( "Getting list of files to clean up...\n" );
$res = $dbr->select(
'uploadstash',
'us_key',
- 'us_timestamp < ' . $dbr->addQuotes( $dbr->timestamp( time() - $wgUploadStashMaxAge ) ),
+ 'us_timestamp < ' . $dbr->addQuotes( $dbr->timestamp( $cutoff ) ),
__METHOD__
);
- if( !is_object( $res ) || $res->numRows() == 0 ) {
- $this->output( "No files to cleanup!\n" );
- // nothing to do.
- return;
- }
+ // Delete all registered stash files...
+ if ( $res->numRows() == 0 ) {
+ $this->output( "No stashed files to cleanup according to the DB.\n" );
+ } else {
+ // finish the read before starting writes.
+ $keys = array();
+ foreach( $res as $row ) {
+ array_push( $keys, $row->us_key );
+ }
+
+ $this->output( 'Removing ' . count( $keys ) . " file(s)...\n" );
+ // this could be done some other, more direct/efficient way, but using
+ // UploadStash's own methods means it's less likely to fall accidentally
+ // out-of-date someday
+ $stash = new UploadStash( $repo );
- // finish the read before starting writes.
- $keys = array();
- foreach( $res as $row ) {
- array_push( $keys, $row->us_key );
+ $i = 0;
+ foreach( $keys as $key ) {
+ $i++;
+ try {
+ $stash->getFile( $key, true );
+ $stash->removeFileNoAuth( $key );
+ } catch ( UploadStashBadPathException $ex ) {
+ $this->output( "Failed removing stashed upload with key: $key\n" );
+ } catch ( UploadStashZeroLengthFileException $ex ) {
+ $this->output( "Failed removing stashed upload with key: $key\n" );
+ }
+ if ( $i % 100 == 0 ) {
+ $this->output( "$i\n" );
+ }
+ }
+ $this->output( "$i done\n" );
}
- $this->output( 'Removing ' . count($keys) . " file(s)...\n" );
- // this could be done some other, more direct/efficient way, but using
- // UploadStash's own methods means it's less likely to fall accidentally
- // out-of-date someday
- $stash = new UploadStash( $repo );
+ // Delete all the corresponding thumbnails...
+ $dir = $tempRepo->getZonePath( 'thumb' );
+ $iterator = $tempRepo->getBackend()->getFileList( array( 'dir' => $dir ) );
+ $this->output( "Deleting old thumbnails...\n" );
+ $i = 0;
+ foreach ( $iterator as $file ) {
+ if ( wfTimestamp( TS_UNIX, $tempRepo->getFileTimestamp( "$dir/$file" ) ) < $cutoff ) {
+ $status = $tempRepo->quickPurge( "$dir/$file" );
+ if ( !$status->isOK() ) {
+ $this->error( print_r( $status->getErrorsArray(), true ) );
+ }
+ if ( ( ++$i % 100 ) == 0 ) {
+ $this->output( "$i\n" );
+ }
+ }
+ }
+ $this->output( "$i done\n" );
+ // Apparently lots of stash files are not registered in the DB...
+ $dir = $tempRepo->getZonePath( 'public' );
+ $iterator = $tempRepo->getBackend()->getFileList( array( 'dir' => $dir ) );
+ $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
+ }
$i = 0;
- foreach( $keys as $key ) {
- $i++;
- try {
- $stash->getFile( $key, true );
- $stash->removeFileNoAuth( $key );
- } catch ( UploadStashBadPathException $ex ) {
- $this->output( "Failed removing stashed upload with key: $key\n" );
+ foreach ( $iterator as $file ) {
+ // Absolute sanity check for stashed files and file segments
+ if ( !preg_match( '#(^\d{14}!|\.\d+\.\w+\.\d+$)#', basename( $file ) ) ) {
+ $this->output( "Skipped non-stash $file\n" );
+ continue;
}
- if ( $i % 100 == 0 ) {
- $this->output( "$i\n" );
+ if ( wfTimestamp( TS_UNIX, $tempRepo->getFileTimestamp( "$dir/$file" ) ) < $cutoff ) {
+ $status = $tempRepo->quickPurge( "$dir/$file" );
+ if ( !$status->isOK() ) {
+ $this->error( print_r( $status->getErrorsArray(), true ) );
+ }
+ if ( ( ++$i % 100 ) == 0 ) {
+ $this->output( "$i\n" );
+ }
}
}
$this->output( "$i done\n" );
diff --git a/maintenance/clear_stats.php b/maintenance/clearCacheStats.php
index 4581d532..7a0d664a 100644
--- a/maintenance/clear_stats.php
+++ b/maintenance/clearCacheStats.php
@@ -28,7 +28,7 @@ require_once( __DIR__ . '/Maintenance.php' );
*
* @ingroup Maintenance
*/
-class clear_stats extends Maintenance {
+class ClearCacheStats extends Maintenance {
public function __construct() {
parent::__construct();
@@ -56,5 +56,5 @@ class clear_stats extends Maintenance {
}
}
-$maintClass = "clear_stats";
+$maintClass = "ClearCacheStats";
require_once( RUN_MAINTENANCE_IF_MAIN );
diff --git a/maintenance/clear_interwiki_cache.php b/maintenance/clearInterwikiCache.php
index 88769df2..88769df2 100644
--- a/maintenance/clear_interwiki_cache.php
+++ b/maintenance/clearInterwikiCache.php
diff --git a/maintenance/compareParsers.php b/maintenance/compareParsers.php
index a3337173..1f3ac1c3 100644
--- a/maintenance/compareParsers.php
+++ b/maintenance/compareParsers.php
@@ -114,15 +114,24 @@ class CompareParsers extends DumpIterator {
$parser1 = new $parser1Name();
$parser2 = new $parser2Name();
- $output1 = $parser1->parse( $rev->getText(), $title, $this->options );
- $output2 = $parser2->parse( $rev->getText(), $title, $this->options );
+ $content = $rev->getContent();
+
+ if ( $content->getModel() !== CONTENT_MODEL_WIKITEXT ) {
+ $this->error( "Page {$title->getPrefixedText()} does not contain wikitext but {$content->getModel()}\n" );
+ return;
+ }
+
+ $text = strval( $content->getNativeData() );
+
+ $output1 = $parser1->parse( $text, $title, $this->options );
+ $output2 = $parser2->parse( $text, $title, $this->options );
if ( $output1->getText() != $output2->getText() ) {
$this->failed++;
$this->error( "Parsing for {$title->getPrefixedText()} differs\n" );
if ( $this->saveFailed ) {
- file_put_contents( $this->saveFailed . '/' . rawurlencode( $title->getPrefixedText() ) . ".txt", $rev->getText());
+ file_put_contents( $this->saveFailed . '/' . rawurlencode( $title->getPrefixedText() ) . ".txt", $text );
}
if ( $this->showDiff ) {
$this->output( wfDiff( $this->stripParameters( $output1->getText() ), $this->stripParameters( $output2->getText() ), '' ) );
diff --git a/maintenance/convertUserOptions.php b/maintenance/convertUserOptions.php
index 7c9ca269..e2223e1a 100644
--- a/maintenance/convertUserOptions.php
+++ b/maintenance/convertUserOptions.php
@@ -56,7 +56,7 @@ class ConvertUserOptions extends Maintenance {
array( 'LIMIT' => 50, 'FOR UPDATE' )
);
$id = $this->convertOptionBatch( $res, $dbw );
- $dbw->commit();
+ $dbw->commit( __METHOD__ );
wfWaitForSlaves();
diff --git a/maintenance/copyFileBackend.php b/maintenance/copyFileBackend.php
index aebdee17..f2c4ac54 100644
--- a/maintenance/copyFileBackend.php
+++ b/maintenance/copyFileBackend.php
@@ -134,6 +134,21 @@ class CopyFileBackend extends Maintenance {
$ops = array();
$fsFiles = array();
$copiedRel = array(); // for output message
+
+ // Download the batch of source files into backend cache...
+ if ( $this->hasOption( 'missingonly' ) ) {
+ $srcPaths = array();
+ foreach ( $srcPathsRel as $srcPathRel ) {
+ $srcPaths[] = $src->getRootStoragePath() . "/$backendRel/$srcPathRel";
+ }
+ $t_start = microtime( true );
+ $fsFiles = $src->getLocalReferenceMulti( array( 'srcs' => $srcPaths, 'latest' => 1 ) );
+ $ellapsed_ms = floor( ( microtime( true ) - $t_start ) * 1000 );
+ $this->output( "\nDownloaded these file(s) [{$ellapsed_ms}ms]:\n" .
+ implode( "\n", $srcPaths ) . "\n\n" );
+ }
+
+ // Determine what files need to be copied over...
foreach ( $srcPathsRel as $srcPathRel ) {
$srcPath = $src->getRootStoragePath() . "/$backendRel/$srcPathRel";
$dstPath = $dst->getRootStoragePath() . "/$backendRel/$srcPathRel";
@@ -144,8 +159,9 @@ class CopyFileBackend extends Maintenance {
$this->output( "Already have $srcPathRel.\n" );
continue; // assume already copied...
}
- // Note: getLocalReference() is fast for FS backends
- $fsFile = $src->getLocalReference( array( 'src' => $srcPath, 'latest' => 1 ) );
+ $fsFile = array_key_exists( $srcPath, $fsFiles )
+ ? $fsFiles[$srcPath]
+ : $src->getLocalReference( array( 'src' => $srcPath, 'latest' => 1 ) );
if ( !$fsFile ) {
$this->error( "Could not get local copy of $srcPath.", 1 ); // die
} elseif ( !$fsFile->exists() ) {
@@ -167,6 +183,7 @@ class CopyFileBackend extends Maintenance {
$copiedRel[] = $srcPathRel;
}
+ // Copy in the batch of source files...
$t_start = microtime( true );
$status = $dst->doQuickOperations( $ops, array( 'bypassReadOnly' => 1 ) );
if ( !$status->isOK() ) {
diff --git a/maintenance/createAndPromote.php b/maintenance/createAndPromote.php
index ad5333fc..81fbbb3d 100644
--- a/maintenance/createAndPromote.php
+++ b/maintenance/createAndPromote.php
@@ -20,6 +20,7 @@
* @file
* @ingroup Maintenance
* @author Rob Church <robchur@gmail.com>
+ * @author Pablo Castellano <pablo@anche.no>
*/
require_once( __DIR__ . '/Maintenance.php' );
@@ -31,50 +32,82 @@ require_once( __DIR__ . '/Maintenance.php' );
*/
class CreateAndPromote extends Maintenance {
+ static $permitRoles = array( 'sysop', 'bureaucrat' );
+
public function __construct() {
parent::__construct();
- $this->mDescription = "Create a new user account";
- $this->addOption( "sysop", "Grant the account sysop rights" );
- $this->addOption( "bureaucrat", "Grant the account bureaucrat rights" );
+ $this->mDescription = "Create a new user account and/or grant it additional rights";
+ $this->addOption( "force", "If acccount exists already, just grant it rights or change password." );
+ foreach( self::$permitRoles as $role ) {
+ $this->addOption( $role, "Add the account to the {$role} group" );
+ }
$this->addArg( "username", "Username of new user" );
- $this->addArg( "password", "Password to set" );
+ $this->addArg( "password", "Password to set (not required if --force is used)", false);
}
public function execute() {
$username = $this->getArg( 0 );
$password = $this->getArg( 1 );
-
- $this->output( wfWikiID() . ": Creating and promoting User:{$username}..." );
+ $force = $this->hasOption( 'force' );
+ $inGroups = array();
$user = User::newFromName( $username );
if ( !is_object( $user ) ) {
$this->error( "invalid username.", true );
- } elseif ( 0 != $user->idForName() ) {
- $this->error( "account exists.", true );
}
- # Try to set the password
- try {
- $user->setPassword( $password );
- } catch ( PasswordError $pwe ) {
- $this->error( $pwe->getText(), true );
+ $exists = ( 0 !== $user->idForName() );
+
+ if ( $exists && !$force ) {
+ $this->error( "Account exists. Perhaps you want the --force option?", true );
+ } else if ( !$exists && !$password ) {
+ $this->error( "Argument <password> required!", false );
+ $this->maybeHelp( true );
+ } else if ( $exists ) {
+ $inGroups = $user->getGroups();
}
- # Insert the account into the database
- $user->addToDatabase();
- $user->saveSettings();
+ $promotions = array_diff( array_filter( self::$permitRoles, array( $this, 'hasOption' ) ), $inGroups );
- # Promote user
- if ( $this->hasOption( 'sysop' ) ) {
- $user->addGroup( 'sysop' );
+ if ( $exists && !$password && count( $promotions ) === 0 ) {
+ $this->output( "Account exists and nothing to do.\n" );
+ return;
+ } else if ( count( $promotions ) !== 0 ) {
+ $promoText = "User:{$username} into " . implode( ', ', $promotions ) . "...\n";
+ if ( $exists ) {
+ $this->output( wfWikiID() . ": Promoting $promoText" );
+ } else {
+ $this->output( wfWikiID() . ": Creating and promoting $promoText" );
+ }
}
- if ( $this->hasOption( 'bureaucrat' ) ) {
- $user->addGroup( 'bureaucrat' );
+
+ if ( $password ) {
+ # Try to set the password
+ try {
+ $user->setPassword( $password );
+ if ( $exists ) {
+ $this->output( "Password set.\n" );
+ $user->saveSettings();
+ }
+ } catch ( PasswordError $pwe ) {
+ $this->error( $pwe->getText(), true );
+ }
}
- # Increment site_stats.ss_users
- $ssu = new SiteStatsUpdate( 0, 0, 0, 0, 1 );
- $ssu->doUpdate();
+ if ( !$exists ) {
+ # Insert the account into the database
+ $user->addToDatabase();
+ $user->saveSettings();
+ }
+
+ # Promote user
+ array_map( array( $user, 'addGroup' ), $promotions );
+
+ if ( !$exists ) {
+ # Increment site_stats.ss_users
+ $ssu = new SiteStatsUpdate( 0, 0, 0, 0, 1 );
+ $ssu->doUpdate();
+ }
$this->output( "done.\n" );
}
diff --git a/maintenance/cssjanus/README b/maintenance/cssjanus/README
index 9b922156..1b96d1a2 100644
--- a/maintenance/cssjanus/README
+++ b/maintenance/cssjanus/README
@@ -8,18 +8,18 @@ Author: `Lindsey Simon <elsigh@google.com>`
CSSJanus is CSS parser utility designed to aid the conversion of a website's
layout from left-to-right(LTR) to right-to-left(RTL). The script was born out of
-a need to convert CSS for RTL languages when tables are not being used for layout (since tables will automatically reorder TD's in RTL).
+a need to convert CSS for RTL languages when tables are not being used for layout (since tables will automatically reorder TD's in RTL).
CSSJanus will change most of the obvious CSS property names and their values as
-well as some not-so-obvious ones (cursor, background-position %, etc...).
-The script is designed to offer flexibility to account for cases when you do
+well as some not-so-obvious ones (cursor, background-position %, etc...).
+The script is designed to offer flexibility to account for cases when you do
not want to change certain rules which exist to account for bidirectional text
display bugs, as well as situations where you may or may not want to flip annotations inside of the background url string.
-Note that you can disable CSSJanus from running on an entire class or any
+Note that you can disable CSSJanus from running on an entire class or any
rule within a class by prepending a /* @noflip */ comment before the rule(s)
you want CSSJanus to ignore.
CSSJanus itself is not always enough to make a website that works in a LTR
-language context work in a RTL language all the way, but it is a start.
+language context work in a RTL language all the way, but it is a start.
==Getting the code==
@@ -31,7 +31,7 @@ Check out the latest development version anonymously with:
{{{
$ svn checkout http://cssjanus.googlecode.com/svn/trunk/ cssjanus
-}}}
+}}}
==Using==
@@ -41,13 +41,13 @@ Flags:
--swap_left_right_in_url: Fixes "left"/"right" string within urls.
Ex: ./cssjanus.py --swap_left_right_in_url < file.css > file_rtl.css
--swap_ltr_rtl_in_url: Fixes "ltr"/"rtl" string within urls.
- Ex: ./cssjanus.py --swap_ltr_rtl_in_url < file.css > file_rtl.css
-
+ Ex: ./cssjanus.py --swap_ltr_rtl_in_url < file.css > file_rtl.css
+
If you'd like to make use of the webapp version of cssjanus, you'll need to
download the Google App Engine SDK
http://code.google.com/appengine/downloads.html
and also drop a "django" directory into this directory, with the latest svn
-from django. You should be good to go with that setup. Please let me know
+from django. You should be good to go with that setup. Please let me know
otherwise.
==Bugs, Patches==
@@ -76,13 +76,13 @@ Thanks to Jens Meiert for the German translation.
{{{
Copyright 2008 Google Inc. All Rights Reserved.
-
+
Licensed under the Apache License, Version 2.0 (the 'License');
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
-
+
http://www.apache.org/licenses/LICENSE-2.0
-
+
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an 'AS IS' BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
diff --git a/maintenance/deleteArchivedFiles.inc b/maintenance/deleteArchivedFiles.inc
index e638b17c..792ee6c6 100644
--- a/maintenance/deleteArchivedFiles.inc
+++ b/maintenance/deleteArchivedFiles.inc
@@ -27,7 +27,7 @@
* @ingroup Maintenance
*/
class DeleteArchivedFilesImplementation {
- static public function doDelete( $output, $force ) {
+ public static function doDelete( $output, $force ) {
# Data should come off the master, wrapped in a transaction
$dbw = wfGetDB( DB_MASTER );
$dbw->begin( __METHOD__ );
@@ -35,14 +35,19 @@ class DeleteArchivedFilesImplementation {
$repo = RepoGroup::singleton()->getLocalRepo();
# Get "active" revisions from the filearchive table
$output->handleOutput( "Searching for and deleting archived files...\n" );
- $res = $dbw->query( "SELECT fa_id,fa_storage_group,fa_storage_key FROM $tbl_arch" );
+ $res = $dbw->query( "SELECT fa_id,fa_storage_group,fa_storage_key,fa_sha1 FROM $tbl_arch" );
$count = 0;
foreach ( $res as $row ) {
$key = $row->fa_storage_key;
$group = $row->fa_storage_group;
$id = $row->fa_id;
$path = $repo->getZonePath( 'deleted' ) . '/' . $repo->getDeletedHashPath( $key ) . $key;
- $sha1 = substr( $key, 0, strcspn( $key, '.' ) );
+ if( isset( $row->fa_sha1 ) ) {
+ $sha1 = $row->fa_sha1;
+ } else {
+ // old row, populate from key
+ $sha1 = LocalRepo::getHashFromKey( $key );
+ }
// Check if the file is used anywhere...
$inuse = $dbw->selectField( 'oldimage', '1',
array( 'oi_sha1' => $sha1,
diff --git a/maintenance/deleteArchivedRevisions.inc b/maintenance/deleteArchivedRevisions.inc
index 414d41ad..dd8e3dd4 100644
--- a/maintenance/deleteArchivedRevisions.inc
+++ b/maintenance/deleteArchivedRevisions.inc
@@ -36,7 +36,7 @@ class DeleteArchivedRevisionsImplementation {
* purgeRedundantText(). See Maintenance for a description of
* those methods.
*/
- static public function doDelete( $maint ) {
+ public static function doDelete( $maint ) {
$dbw = wfGetDB( DB_MASTER );
$dbw->begin( __METHOD__ );
diff --git a/maintenance/deleteEqualMessages.php b/maintenance/deleteEqualMessages.php
new file mode 100644
index 00000000..7048140b
--- /dev/null
+++ b/maintenance/deleteEqualMessages.php
@@ -0,0 +1,186 @@
+<?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 Maintenance
+ */
+
+require_once( __DIR__ . '/Maintenance.php' );
+
+/**
+ * Maintenance script that deletes all pages in the MediaWiki namespace
+ * of which the content is equal to the system default.
+ *
+ * @ingroup Maintenance
+ */
+class DeleteEqualMessages extends Maintenance {
+ public function __construct() {
+ parent::__construct();
+ $this->mDescription = "Deletes all pages in the MediaWiki namespace that are equal to the default message";
+ $this->addOption( 'delete', 'Actually delete the pages (default: dry run)' );
+ $this->addOption( 'delete-talk', 'Don\'t leave orphaned talk pages behind during deletion' );
+ $this->addOption( 'lang-code', 'Check for subpages of this language code (default: root page against content language). ' .
+ 'Use value "*" to run for all mwfile language code subpages (including the base pages that override content language).', false, true );
+ }
+
+ /**
+ * @param string|bool $langCode See --lang-code option.
+ */
+ protected function fetchMessageInfo( $langCode, array &$messageInfo ) {
+ global $wgUser, $wgContLang;
+
+ if ( $langCode ) {
+ $this->output( "\n... fetching message info for language: $langCode" );
+ $nonContLang = true;
+ } else {
+ $this->output( "\n... fetching message info for content language" );
+ $langCode = $wgContLang->getCode();
+ $nonContLang = false;
+ }
+
+ /* Based on SpecialAllmessages::reallyDoQuery #filter=modified */
+
+ $l10nCache = Language::getLocalisationCache();
+ $messageNames = $l10nCache->getSubitemList( 'en', 'messages' );
+ // Normalise message names for NS_MEDIAWIKI page_title
+ $messageNames = array_map( array( $wgContLang, 'ucfirst' ), $messageNames );
+
+ $statuses = AllmessagesTablePager::getCustomisedStatuses( $messageNames, $langCode, $nonContLang );
+ // getCustomisedStatuses is stripping the sub page from the page titles, add it back
+ $titleSuffix = $nonContLang ? "/$langCode" : '';
+
+ foreach ( $messageNames as $key ) {
+ $customised = isset( $statuses['pages'][$key] );
+ if ( $customised ) {
+ $actual = wfMessage( $key )->inLanguage( $langCode )->plain();
+ $default = wfMessage( $key )->inLanguage( $langCode )->useDatabase( false )->plain();
+
+ $messageInfo['relevantPages']++;
+ if ( $actual === $default ) {
+ $hasTalk = isset( $statuses['talks'][$key] );
+ $messageInfo['results'][] = array(
+ 'title' => $key . $titleSuffix,
+ 'hasTalk' => $hasTalk,
+ );
+ $messageInfo['equalPages']++;
+ if ( $hasTalk ) {
+ $messageInfo['equalPagesTalks']++;
+ }
+ }
+ }
+ }
+ }
+
+ public function execute() {
+ $doDelete = $this->hasOption( 'delete' );
+ $doDeleteTalk = $this->hasOption( 'delete-talk' );
+ $langCode = $this->getOption( 'lang-code' );
+
+ $messageInfo = array(
+ 'relevantPages' => 0,
+ 'equalPages' => 0,
+ 'equalPagesTalks' => 0,
+ 'results' => array(),
+ );
+
+ $this->output( 'Checking for pages with default message...' );
+
+ // Load message information
+ if ( $langCode ) {
+ $langCodes = Language::fetchLanguageNames( null, 'mwfile' );
+ if ( $langCode === '*' ) {
+ // All valid lang-code subpages in NS_MEDIAWIKI that
+ // override the messsages in that language
+ foreach ( $langCodes as $key => $value ) {
+ $this->fetchMessageInfo( $key, $messageInfo );
+ }
+ // Lastly, the base pages in NS_MEDIAWIKI that override
+ // messages in content language
+ $this->fetchMessageInfo( false, $messageInfo );
+ } else {
+ if ( !isset( $langCodes[$langCode] ) ) {
+ $this->error( 'Invalid language code: ' . $langCode, 1 );
+ }
+ $this->fetchMessageInfo( $langCode, $messageInfo );
+ }
+ } else {
+ $this->fetchMessageInfo( false, $messageInfo );
+ }
+
+ if ( $messageInfo['equalPages'] === 0 ) {
+ // No more equal messages left
+ $this->output( "\ndone.\n" );
+ return;
+ }
+
+ $this->output( "\n{$messageInfo['relevantPages']} pages in the MediaWiki namespace override messages." );
+ $this->output( "\n{$messageInfo['equalPages']} pages are equal to the default message (+ {$messageInfo['equalPagesTalks']} talk pages).\n" );
+
+ if ( !$doDelete ) {
+ $list = '';
+ foreach ( $messageInfo['results'] as $result ) {
+ $title = Title::makeTitle( NS_MEDIAWIKI, $result['title'] );
+ $list .= "* [[$title]]\n";
+ if ( $result['hasTalk'] ) {
+ $title = Title::makeTitle( NS_MEDIAWIKI_TALK, $result['title'] );
+ $list .= "* [[$title]]\n";
+ }
+ }
+ $this->output( "\nList:\n$list\nRun the script again with --delete to delete these pages" );
+ if ( $messageInfo['equalPagesTalks'] !== 0 ) {
+ $this->output( " (include --delete-talk to also delete the talk pages)" );
+ }
+ $this->output( "\n" );
+ return;
+ }
+
+ $user = User::newFromName( 'MediaWiki default' );
+ if ( !$user ) {
+ $this->error( "Invalid username", true );
+ }
+ $wgUser = $user;
+
+ // Hide deletions from RecentChanges
+ $user->addGroup( 'bot' );
+
+ // Handle deletion
+ $this->output( "\n...deleting equal messages (this may take a long time!)..." );
+ $dbw = wfGetDB( DB_MASTER );
+ foreach ( $messageInfo['results'] as $result ) {
+ wfWaitForSlaves();
+ $dbw->ping();
+ $dbw->begin( __METHOD__ );
+ $title = Title::makeTitle( NS_MEDIAWIKI, $result['title'] );
+ $this->output( "\n* [[$title]]" );
+ $page = WikiPage::factory( $title );
+ $error = ''; // Passed by ref
+ $page->doDeleteArticle( 'No longer required', false, 0, false, $error, $user );
+ if ( $result['hasTalk'] && $doDeleteTalk ) {
+ $title = Title::makeTitle( NS_MEDIAWIKI_TALK, $result['title'] );
+ $this->output( "\n* [[$title]]" );
+ $page = WikiPage::factory( $title );
+ $error = ''; // Passed by ref
+ $page->doDeleteArticle( 'Orphaned talk page of no longer required message', false, 0, false, $error, $user );
+ }
+ $dbw->commit( __METHOD__ );
+ }
+ $this->output( "\n\ndone!\n" );
+ }
+}
+
+$maintClass = "DeleteEqualMessages";
+require_once( RUN_MAINTENANCE_IF_MAIN );
diff --git a/maintenance/deleteOldRevisions.php b/maintenance/deleteOldRevisions.php
index 6a3e211b..114aefd7 100644
--- a/maintenance/deleteOldRevisions.php
+++ b/maintenance/deleteOldRevisions.php
@@ -48,48 +48,45 @@ class DeleteOldRevisions extends Maintenance {
$dbw = wfGetDB( DB_MASTER );
$dbw->begin( __METHOD__ );
- $tbl_pag = $dbw->tableName( 'page' );
- $tbl_rev = $dbw->tableName( 'revision' );
-
- $pageIdClause = '';
- $revPageClause = '';
+ $pageConds = array();
+ $revConds = array();
# If a list of page_ids was provided, limit results to that set of page_ids
- if ( sizeof( $args ) > 0 ) {
- $pageIdList = implode( ',', $args );
- $pageIdClause = " WHERE page_id IN ({$pageIdList})";
- $revPageClause = " AND rev_page IN ({$pageIdList})";
- $this->output( "Limiting to {$tbl_pag}.page_id IN ({$pageIdList})\n" );
+ if ( count( $args ) > 0 ) {
+ $pageConds['page_id'] = $args;
+ $revConds['rev_page'] = $args;
+ $this->output( "Limiting to page IDs " . implode( ',', $args ) . "\n" );
}
# Get "active" revisions from the page table
$this->output( "Searching for active revisions..." );
- $res = $dbw->query( "SELECT page_latest FROM $tbl_pag{$pageIdClause}" );
- $cur = array();
+ $res = $dbw->select( 'page', 'page_latest', $pageConds, __METHOD__ );
+ $latestRevs = array();
foreach ( $res as $row ) {
- $cur[] = $row->page_latest;
+ $latestRevs[] = $row->page_latest;
}
$this->output( "done.\n" );
# Get all revisions that aren't in this set
- $old = array();
$this->output( "Searching for inactive revisions..." );
- $set = implode( ', ', $cur );
- $res = $dbw->query( "SELECT rev_id FROM $tbl_rev WHERE rev_id NOT IN ( $set ){$revPageClause}" );
+ if ( count( $latestRevs ) > 0 ) {
+ $revConds[] = 'rev_id NOT IN (' . $dbw->makeList( $latestRevs ) . ')';
+ }
+ $res = $dbw->select( 'revision', 'rev_id', $revConds, __METHOD__ );
+ $oldRevs = array();
foreach ( $res as $row ) {
- $old[] = $row->rev_id;
+ $oldRevs[] = $row->rev_id;
}
$this->output( "done.\n" );
# Inform the user of what we're going to do
- $count = count( $old );
+ $count = count( $oldRevs );
$this->output( "$count old revisions found.\n" );
# Delete as appropriate
if ( $delete && $count ) {
$this->output( "Deleting..." );
- $set = implode( ', ', $old );
- $dbw->query( "DELETE FROM $tbl_rev WHERE rev_id IN ( $set )" );
+ $dbw->delete( 'revision', array( 'rev_id' => $oldRevs ), __METHOD__ );
$this->output( "done.\n" );
}
@@ -104,4 +101,3 @@ class DeleteOldRevisions extends Maintenance {
$maintClass = "DeleteOldRevisions";
require_once( RUN_MAINTENANCE_IF_MAIN );
-
diff --git a/maintenance/deleteOrphanedRevisions.php b/maintenance/deleteOrphanedRevisions.php
index 5dc7567f..f0da9a82 100644
--- a/maintenance/deleteOrphanedRevisions.php
+++ b/maintenance/deleteOrphanedRevisions.php
@@ -61,7 +61,7 @@ class DeleteOrphanedRevisions extends Maintenance {
# Nothing to do?
if ( $report || $count == 0 ) {
- $dbw->commit();
+ $dbw->commit( __METHOD__ );
exit( 0 );
}
@@ -91,4 +91,3 @@ class DeleteOrphanedRevisions extends Maintenance {
$maintClass = "DeleteOrphanedRevisions";
require_once( RUN_MAINTENANCE_IF_MAIN );
-
diff --git a/maintenance/dev/includes/router.php b/maintenance/dev/includes/router.php
index ac96f459..1d5070b1 100644
--- a/maintenance/dev/includes/router.php
+++ b/maintenance/dev/includes/router.php
@@ -21,7 +21,7 @@
* @file
*/
-if ( php_sapi_name() != 'cli-server' ) {
+if ( PHP_SAPI != 'cli-server' ) {
die( "This script can only be run by php's cli-server sapi." );
}
diff --git a/maintenance/doMaintenance.php b/maintenance/doMaintenance.php
index 2bb2a0f4..15b00167 100644
--- a/maintenance/doMaintenance.php
+++ b/maintenance/doMaintenance.php
@@ -111,8 +111,18 @@ try {
// Potentially debug globals
$maintenance->globals();
+
+ // Perform deferred updates.
+ DeferredUpdates::doUpdates( 'commit' );
+
+ // log profiling info
+ wfLogProfilingData();
+
+ // Commit and close up!
+ $factory = wfGetLBFactory();
+ $factory->commitMasterChanges();
+ $factory->shutdown();
} catch ( MWException $mwe ) {
echo( $mwe->getText() );
exit( 1 );
}
-
diff --git a/maintenance/dumpIterator.php b/maintenance/dumpIterator.php
index 3657f960..870d6321 100644
--- a/maintenance/dumpIterator.php
+++ b/maintenance/dumpIterator.php
@@ -168,7 +168,7 @@ class SearchDump extends DumpIterator {
* @param $rev Revision
*/
public function processRevision( $rev ) {
- if ( preg_match( $this->getOption( 'regex' ), $rev->getText() ) ) {
+ if ( preg_match( $this->getOption( 'regex' ), $rev->getContent()->getTextForSearchIndex() ) ) {
$this->output( $rev->getTitle() . " matches at edit from " . $rev->getTimestamp() . "\n" );
}
}
diff --git a/maintenance/dumpLinks.php b/maintenance/dumpLinks.php
index 153fdd79..08aae295 100644
--- a/maintenance/dumpLinks.php
+++ b/maintenance/dumpLinks.php
@@ -76,4 +76,3 @@ class DumpLinks extends Maintenance {
$maintClass = "DumpLinks";
require_once( RUN_MAINTENANCE_IF_MAIN );
-
diff --git a/maintenance/dumpTextPass.php b/maintenance/dumpTextPass.php
index 72d7d97c..2e0d03b1 100644
--- a/maintenance/dumpTextPass.php
+++ b/maintenance/dumpTextPass.php
@@ -64,5 +64,3 @@ Options:
ENDS
);
}
-
-
diff --git a/maintenance/edit.php b/maintenance/edit.php
index 59df5e88..93fc3e79 100644
--- a/maintenance/edit.php
+++ b/maintenance/edit.php
@@ -68,10 +68,11 @@ class EditCLI extends Maintenance {
# Read the text
$text = $this->getStdin( Maintenance::STDIN_ALL );
+ $content = ContentHandler::makeContent( $text, $wgTitle );
# Do the edit
$this->output( "Saving... " );
- $status = $page->doEdit( $text, $summary,
+ $status = $page->doEditContent( $content, $summary,
( $minor ? EDIT_MINOR : 0 ) |
( $bot ? EDIT_FORCE_BOT : 0 ) |
( $autoSummary ? EDIT_AUTOSUMMARY : 0 ) |
@@ -92,4 +93,3 @@ class EditCLI extends Maintenance {
$maintClass = "EditCLI";
require_once( RUN_MAINTENANCE_IF_MAIN );
-
diff --git a/maintenance/eval.php b/maintenance/eval.php
index 5aefe1c9..95f46ffa 100644
--- a/maintenance/eval.php
+++ b/maintenance/eval.php
@@ -43,7 +43,7 @@ if ( isset( $options['d'] ) ) {
}
if ( $d > 1 ) {
$lb = wfGetLB();
- $serverCount = $lb->getServerCount();
+ $serverCount = $lb->getServerCount();
for ( $i = 0; $i < $serverCount; $i++ ) {
$server = $lb->getServerInfo( $i );
$server['flags'] |= DBO_DEBUG;
@@ -80,5 +80,3 @@ while ( ( $line = Maintenance::readconsole() ) !== false ) {
}
print "\n";
-
-
diff --git a/maintenance/fileOpPerfTest.php b/maintenance/fileOpPerfTest.php
index 501bcfc3..008d7686 100644
--- a/maintenance/fileOpPerfTest.php
+++ b/maintenance/fileOpPerfTest.php
@@ -21,7 +21,6 @@
* @ingroup Maintenance
*/
-$initialTime = microtime( true );
$wgProfiler = array( 'class' => 'ProfilerSimpleText' );
error_reporting( E_ALL );
@@ -40,7 +39,8 @@ class TestFileOpPerformance extends Maintenance {
$this->addOption( 'b2', 'Backend 2', false, true );
$this->addOption( 'srcdir', 'File source directory', true, true );
$this->addOption( 'maxfiles', 'Max files', false, true );
- $this->addOption( 'quick', 'Avoid operation pre-checks' );
+ $this->addOption( 'quick', 'Avoid operation pre-checks (use doQuickOperations())' );
+ $this->addOption( 'parallelize', '"parallelize" flag for doOperations()', false, true );
}
public function execute() {
@@ -54,7 +54,8 @@ class TestFileOpPerformance extends Maintenance {
$profiler = Profiler::instance();
$profiler->setTemplated( true );
- $profiler->logData(); // prints
+
+ //NOTE: as of MW1.21, $profiler->logData() is called implicitly by doMaintenance.php.
}
protected function doPerfTest( FileBackend $backend ) {
@@ -95,8 +96,13 @@ class TestFileOpPerformance extends Maintenance {
$method = $this->hasOption( 'quick' ) ? 'doQuickOperations' : 'doOperations';
+ $opts = array( 'force' => 1 );
+ if ( $this->hasOption( 'parallelize' ) ) {
+ $opts['parallelize'] = ( $this->getOption( 'parallelize' ) === 'true' );
+ }
+
$start = microtime( true );
- $status = $backend->$method( $ops1, array( 'force' => 1 ) );
+ $status = $backend->$method( $ops1, $opts );
$e = ( microtime( true ) - $start ) * 1000;
if ( $status->getErrorsArray() ) {
print_r( $status->getErrorsArray() );
@@ -105,7 +111,7 @@ class TestFileOpPerformance extends Maintenance {
$this->output( $backend->getName() . ": Stored " . count( $ops1 ) . " files in $e ms.\n" );
$start = microtime( true );
- $backend->$method( $ops2, array( 'force' => 1 ) );
+ $backend->$method( $ops2, $opts );
$e = ( microtime( true ) - $start ) * 1000;
if ( $status->getErrorsArray() ) {
print_r( $status->getErrorsArray() );
@@ -114,7 +120,7 @@ class TestFileOpPerformance extends Maintenance {
$this->output( $backend->getName() . ": Copied " . count( $ops2 ) . " files in $e ms.\n" );
$start = microtime( true );
- $backend->$method( $ops3, array( 'force' => 1 ) );
+ $backend->$method( $ops3, $opts );
$e = ( microtime( true ) - $start ) * 1000;
if ( $status->getErrorsArray() ) {
print_r( $status->getErrorsArray() );
@@ -123,7 +129,7 @@ class TestFileOpPerformance extends Maintenance {
$this->output( $backend->getName() . ": Moved " . count( $ops3 ) . " files in $e ms.\n" );
$start = microtime( true );
- $backend->$method( $ops4, array( 'force' => 1 ) );
+ $backend->$method( $ops4, $opts );
$e = ( microtime( true ) - $start ) * 1000;
if ( $status->getErrorsArray() ) {
print_r( $status->getErrorsArray() );
@@ -132,7 +138,7 @@ class TestFileOpPerformance extends Maintenance {
$this->output( $backend->getName() . ": Deleted " . count( $ops4 ) . " files in $e ms.\n" );
$start = microtime( true );
- $backend->$method( $ops5, array( 'force' => 1 ) );
+ $backend->$method( $ops5, $opts );
$e = ( microtime( true ) - $start ) * 1000;
if ( $status->getErrorsArray() ) {
print_r( $status->getErrorsArray() );
diff --git a/maintenance/findHooks.php b/maintenance/findHooks.php
index e273c545..778da5a1 100644
--- a/maintenance/findHooks.php
+++ b/maintenance/findHooks.php
@@ -64,6 +64,7 @@ class FindHooks extends Maintenance {
$IP . '/includes/actions/',
$IP . '/includes/api/',
$IP . '/includes/cache/',
+ $IP . '/includes/content/',
$IP . '/includes/context/',
$IP . '/includes/db/',
$IP . '/includes/diff/',
@@ -114,7 +115,7 @@ class FindHooks extends Maintenance {
*/
private function getHooksFromDoc( $doc ) {
if ( $this->hasOption( 'online' ) ) {
- return $this->getHooksFromOnlineDoc( );
+ return $this->getHooksFromOnlineDoc();
} else {
return $this->getHooksFromLocalDoc( $doc );
}
@@ -136,7 +137,7 @@ class FindHooks extends Maintenance {
* Get hooks from www.mediawiki.org using the API
* @return array of documented hooks
*/
- private function getHooksFromOnlineDoc( ) {
+ private function getHooksFromOnlineDoc() {
// All hooks
$allhookdata = Http::get( 'http://www.mediawiki.org/w/api.php?action=query&list=categorymembers&cmtitle=Category:MediaWiki_hooks&cmlimit=500&format=php' );
$allhookdata = unserialize( $allhookdata );
@@ -170,7 +171,7 @@ class FindHooks extends Maintenance {
private function getHooksFromFile( $file ) {
$content = file_get_contents( $file );
$m = array();
- preg_match_all( '/(?:wfRunHooks|Hooks\:\:run)\(\s*([\'"])(.*?)\1/', $content, $m );
+ preg_match_all( '/(?:wfRunHooks|Hooks\:\:run|ContentHandler\:\:runLegacyHooks)\(\s*([\'"])(.*?)\1/', $content, $m );
return $m[2];
}
diff --git a/maintenance/fixDoubleRedirects.php b/maintenance/fixDoubleRedirects.php
index 6f017eca..19b97777 100644
--- a/maintenance/fixDoubleRedirects.php
+++ b/maintenance/fixDoubleRedirects.php
@@ -55,7 +55,12 @@ class FixDoubleRedirects extends Maintenance {
$dbr = wfGetDB( DB_SLAVE );
- $tables = array( 'redirect', 'pa' => 'page', 'pb' => 'page' );
+ // See also SpecialDoubleRedirects
+ $tables = array(
+ 'redirect',
+ 'pa' => 'page',
+ 'pb' => 'page',
+ );
$fields = array(
'pa.page_namespace AS pa_namespace',
'pa.page_title AS pa_title',
@@ -66,6 +71,7 @@ class FixDoubleRedirects extends Maintenance {
'rd_from = pa.page_id',
'rd_namespace = pb.page_namespace',
'rd_title = pb.page_title',
+ '(rd_interwiki IS NULL OR rd_interwiki = "")', // bug 40352
'pb.page_is_redirect' => 1,
);
@@ -83,12 +89,18 @@ class FixDoubleRedirects extends Maintenance {
}
$jobs = array();
+ $processedTitles = "\n";
$n = 0;
foreach ( $res as $row ) {
$titleA = Title::makeTitle( $row->pa_namespace, $row->pa_title );
$titleB = Title::makeTitle( $row->pb_namespace, $row->pb_title );
- $job = new DoubleRedirectJob( $titleA, array( 'reason' => 'maintenance', 'redirTitle' => $titleB->getPrefixedDBkey() ) );
+ $processedTitles .= "* [[$titleA]]\n";
+
+ $job = new DoubleRedirectJob( $titleA, array(
+ 'reason' => 'maintenance',
+ 'redirTitle' => $titleB->getPrefixedDBkey()
+ ) );
if ( !$async ) {
$success = ( $dryrun ? true : $job->run() );
@@ -112,12 +124,12 @@ class FixDoubleRedirects extends Maintenance {
if ( count( $jobs ) ) {
$this->queueJobs( $jobs, $dryrun );
}
- $this->output( "$n double redirects processed.\n" );
+ $this->output( "$n double redirects processed" . $processedTitles . "\n" );
}
protected function queueJobs( $jobs, $dryrun = false ) {
$this->output( "Queuing batch of " . count( $jobs ) . " double redirects.\n" );
- Job::batchInsert( $dryrun ? array() : $jobs );
+ JobQueueGroup::singleton()->push( $dryrun ? array() : $jobs );
}
}
diff --git a/maintenance/fixSlaveDesync.php b/maintenance/fixSlaveDesync.php
index 8bf556f0..ab7603de 100644
--- a/maintenance/fixSlaveDesync.php
+++ b/maintenance/fixSlaveDesync.php
@@ -67,7 +67,7 @@ class FixSlaveDesync extends Maintenance {
$dbw = wfGetDB( DB_MASTER );
$masterIDs = array();
$res = $dbw->select( 'page', array( 'page_id', 'page_latest' ), array( 'page_id<6054123' ), __METHOD__ );
- $this->output( "Number of pages: " . $dbw->numRows( $res ) . "\n" );
+ $this->output( "Number of pages: " . $res->numRows() . "\n" );
foreach ( $res as $row ) {
$masterIDs[$row->page_id] = $row->page_latest;
if ( !( ++$n % 10000 ) ) {
diff --git a/maintenance/formatInstallDoc.php b/maintenance/formatInstallDoc.php
index 600ca976..691ed80c 100644
--- a/maintenance/formatInstallDoc.php
+++ b/maintenance/formatInstallDoc.php
@@ -76,5 +76,3 @@ class MaintenanceFormatInstallDoc extends Maintenance {
$maintClass = 'MaintenanceFormatInstallDoc';
require_once( RUN_MAINTENANCE_IF_MAIN );
-
-
diff --git a/maintenance/fuzz-tester.php b/maintenance/fuzz-tester.php
index 1c96a571..4c039807 100644
--- a/maintenance/fuzz-tester.php
+++ b/maintenance/fuzz-tester.php
@@ -747,7 +747,7 @@ class wikiFuzz {
/**
** Randomly returns one element of the input array.
*/
- static public function chooseInput( array $input ) {
+ public static function chooseInput( array $input ) {
$randindex = wikiFuzz::randnum( count( $input ) - 1 );
return $input[$randindex];
}
@@ -761,7 +761,7 @@ class wikiFuzz {
* @param $start int
* @return int
*/
- static public function randnum( $finish, $start = 0 ) {
+ public static function randnum( $finish, $start = 0 ) {
return mt_rand( $start, $finish );
}
@@ -769,7 +769,7 @@ class wikiFuzz {
* Returns a mix of random text and random wiki syntax.
* @return string
*/
- static private function randstring() {
+ private static function randstring() {
$thestring = "";
for ( $i = 0; $i < 40; $i++ ) {
@@ -801,7 +801,7 @@ class wikiFuzz {
* or random data from "other".
* @return string
*/
- static private function makestring() {
+ private static function makestring() {
$what = wikiFuzz::randnum( 2 );
if ( $what == 0 ) {
return wikiFuzz::randstring();
@@ -818,7 +818,7 @@ class wikiFuzz {
* @param $matches
* @return string
*/
- static private function stringEscape( $matches ) {
+ private static function stringEscape( $matches ) {
return sprintf( "\\x%02x", ord( $matches[1] ) );
}
@@ -828,7 +828,7 @@ class wikiFuzz {
* @param $str string
* @return string
*/
- static public function makeTitleSafe( $str ) {
+ public static function makeTitleSafe( $str ) {
$legalTitleChars = " %!\"$&'()*,\\-.\\/0-9:;=?@A-Z\\\\^_`a-z~\\x80-\\xFF";
return preg_replace_callback(
"/([^$legalTitleChars])/", 'wikiFuzz::stringEscape',
@@ -839,7 +839,7 @@ class wikiFuzz {
** Returns a string of fuzz text.
* @return string
*/
- static private function loop() {
+ private static function loop() {
switch ( wikiFuzz::randnum( 3 ) ) {
case 1: // an opening tag, with parameters.
$string = "";
@@ -868,7 +868,7 @@ class wikiFuzz {
* Returns one of the three styles of random quote: ', ", and nothing.
* @return string
*/
- static private function getRandQuote() {
+ private static function getRandQuote() {
switch ( wikiFuzz::randnum( 3 ) ) {
case 1 : return "'";
case 2 : return "\"";
@@ -881,7 +881,7 @@ class wikiFuzz {
* @param $maxtypes int
* @return string
*/
- static public function makeFuzz( $maxtypes = 2 ) {
+ public static function makeFuzz( $maxtypes = 2 ) {
$page = "";
for ( $k = 0; $k < $maxtypes; $k++ ) {
$page .= wikiFuzz::loop();
@@ -1490,7 +1490,7 @@ class specialBlockmeTest extends pageTest {
function __construct() {
$this->pagePath = "index.php?title=Special:Blockme";
- $this->params = array ( );
+ $this->params = array ();
// sometimes we specify "ip", and sometimes we don't.
if ( wikiFuzz::randnum( 1 ) == 0 ) {
@@ -2041,7 +2041,7 @@ class api extends pageTest {
}
// Adds all the elements to the array, using the specified prefix.
- private static function addListParams( &$array, $prefix, $elements ) {
+ private static function addListParams( &$array, $prefix, $elements ) {
foreach ( $elements as $element ) {
$array[$prefix . $element] = self::getParamDetails( $element );
}
@@ -2709,5 +2709,3 @@ for ( $count = 0; true; $count++ ) {
break;
}
}
-
-
diff --git a/maintenance/generateSitemap.php b/maintenance/generateSitemap.php
index f3a5d875..adea97ea 100644
--- a/maintenance/generateSitemap.php
+++ b/maintenance/generateSitemap.php
@@ -44,7 +44,7 @@ class GenerateSitemap extends Maintenance {
*
* @var int
*/
- var $url_limit;
+ public $url_limit;
/**
* The maximum size of a sitemap file
@@ -53,77 +53,77 @@ class GenerateSitemap extends Maintenance {
*
* @var int
*/
- var $size_limit;
+ public $size_limit;
/**
* The path to prepend to the filename
*
* @var string
*/
- var $fspath;
+ public $fspath;
/**
* The URL path to prepend to filenames in the index; should resolve to the same directory as $fspath
*
* @var string
*/
- var $urlpath;
+ public $urlpath;
/**
* Whether or not to use compression
*
* @var bool
*/
- var $compress;
+ public $compress;
/**
* Whether or not to include redirection pages
*
* @var bool
*/
- var $skipRedirects;
+ public $skipRedirects;
/**
* The number of entries to save in each sitemap file
*
* @var array
*/
- var $limit = array();
+ public $limit = array();
/**
* Key => value entries of namespaces and their priorities
*
* @var array
*/
- var $priorities = array();
+ public $priorities = array();
/**
* A one-dimensional array of namespaces in the wiki
*
* @var array
*/
- var $namespaces = array();
+ public $namespaces = array();
/**
* When this sitemap batch was generated
*
* @var string
*/
- var $timestamp;
+ public $timestamp;
/**
* A database slave object
*
* @var object
*/
- var $dbr;
+ public $dbr;
/**
* A resource pointing to the sitemap index file
*
* @var resource
*/
- var $findex;
+ public $findex;
/**
@@ -131,7 +131,7 @@ class GenerateSitemap extends Maintenance {
*
* @var resource
*/
- var $file;
+ public $file;
/**
* Identifier to use in filenames, default $wgDBname
diff --git a/maintenance/getConfiguration.php b/maintenance/getConfiguration.php
new file mode 100644
index 00000000..83b5b029
--- /dev/null
+++ b/maintenance/getConfiguration.php
@@ -0,0 +1,89 @@
+<?php
+/**
+ * Print serialized output of MediaWiki config vars
+ *
+ * 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 Tim Starling
+ * @author Antoine Musso
+ */
+
+require_once( __DIR__ . '/Maintenance.php' );
+
+/**
+ * Print serialized output of MediaWiki config vars
+ *
+ * @ingroup Maintenance
+ */
+class GetConfiguration extends Maintenance {
+ public function __construct() {
+ parent::__construct();
+ $this->mDescription = "Get serialized MediaWiki site configuration";
+ $this->addOption( 'settings', 'Space-separated list of wg* variables', true, true );
+ $this->addOption( 'format', 'PHP or JSON', true, true );
+ $this->addOption( 'wiki', 'Wiki ID', true, true );
+ }
+
+ public function execute() {
+ $res = array();
+ foreach ( explode( ' ', $this->getOption( 'settings' ) ) as $name ) {
+ if ( !preg_match( '/^wg[A-Z]/', $name ) ) {
+ throw new MWException( "Variable '$name' does start with 'wg'." );
+ } elseif ( !isset( $GLOBALS[$name] ) ) {
+ throw new MWException( "Variable '$name' is not set." );
+ } elseif ( !$this->isAllowedVariable( $GLOBALS[$name] ) ) {
+ throw new MWException( "Variable '$name' includes non-array, non-scalar, items." );
+ }
+ $res[$name] = $GLOBALS[$name];
+ }
+
+ $out = null;
+ switch( $this->getOption( 'format' ) ) {
+ case 'PHP':
+ $out = serialize( $res );
+ break;
+ case 'JSON':
+ $out = FormatJson::encode( $res );
+ break;
+ default:
+ throw new MWException( "Invalid serialization format given." );
+ }
+ if ( !is_string( $out ) ) {
+ throw new MWException( "Failed to serialize the requested settings." );
+ }
+
+ $this->output( $out . "\n" );
+ }
+
+ private function isAllowedVariable( $value ) {
+ if ( is_array( $value ) ) {
+ foreach ( $value as $k => $v ) {
+ if ( !$this->isAllowedVariable( $v ) ) {
+ return false;
+ }
+ }
+ return true;
+ } elseif ( is_scalar( $value ) ) {
+ return true;
+ }
+ return false;
+ }
+}
+
+$maintClass = "GetConfiguration";
+require_once( RUN_MAINTENANCE_IF_MAIN );
diff --git a/maintenance/getText.php b/maintenance/getText.php
index 3e2f8540..f6adfe2b 100644
--- a/maintenance/getText.php
+++ b/maintenance/getText.php
@@ -52,12 +52,12 @@ class GetTextMaint extends Maintenance {
$titleText = $title->getPrefixedText();
$this->error( "Page $titleText does not exist.\n", true );
}
- $text = $rev->getText( $this->hasOption( 'show-private' ) ? Revision::RAW : Revision::FOR_PUBLIC );
- if ( $text === false ) {
+ $content = $rev->getContent( $this->hasOption( 'show-private' ) ? Revision::RAW : Revision::FOR_PUBLIC );
+ if ( $content === false ) {
$titleText = $title->getPrefixedText();
$this->error( "Couldn't extract the text from $titleText.\n", true );
}
- $this->output( $text );
+ $this->output( $content->serialize() );
}
}
diff --git a/maintenance/hiphop/make b/maintenance/hiphop/make
index 2fa70dcb..13e3163a 100644
--- a/maintenance/hiphop/make
+++ b/maintenance/hiphop/make
@@ -1,4 +1,4 @@
-#!/usr/bin/hphpi -f
+#!/usr/bin/hphpi -f
<?php
define( 'MW_CONFIG_CALLBACK', 'MakeHipHop::noConfigNeeded' );
@@ -41,7 +41,7 @@ class MakeHipHop extends Maintenance {
unlink( "$buildDir/source" );
}
- # With the CentOS RPMs, you just get g++44, no g++, so we have to
+ # With the CentOS RPMs, you just get g++44, no g++, so we have to
# use the environment
if ( isset( $_ENV['CXX'] ) ) {
$cxx = $_ENV['CXX'];
@@ -49,7 +49,7 @@ class MakeHipHop extends Maintenance {
$cxx = 'g++';
}
- # Create a function that provides the HipHop compiler version, and
+ # Create a function that provides the HipHop compiler version, and
# doesn't exist when MediaWiki is invoked in interpreter mode.
$version = str_replace( PHP_EOL, ' ', trim( `hphp --version` ) );
file_put_contents(
@@ -94,7 +94,7 @@ class MakeHipHop extends Maintenance {
$this->checkVolatileClasses( $outDir );
# Copy the generated C++ files into the source directory for cmake
- $iter = new RecursiveIteratorIterator(
+ $iter = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator( $outDir ),
RecursiveIteratorIterator::SELF_FIRST );
$sourceFiles = array();
@@ -148,14 +148,14 @@ class MakeHipHop extends Maintenance {
}
# Do our own version of $HPHP_HOME/bin/run.sh, which isn't so broken.
- # HipHop's RELEASE mode seems to be stuck always on, so symbols get
- # stripped. Also we will try keeping the generated .o files instead of
+ # HipHop's RELEASE mode seems to be stuck always on, so symbols get
+ # stripped. Also we will try keeping the generated .o files instead of
# throwing away hours of CPU time every time you make a typo.
chdir( $persistentDir );
if ( $regenerateMakefile ) {
- copy( $_ENV['HPHP_HOME'] . '/bin/CMakeLists.base.txt',
+ copy( $_ENV['HPHP_HOME'] . '/bin/CMakeLists.base.txt',
"$persistentDir/CMakeLists.txt" );
if ( file_exists( "$persistentDir/CMakeCache.txt" ) ) {
@@ -165,7 +165,7 @@ class MakeHipHop extends Maintenance {
$cmd = 'cmake' .
" -D CMAKE_BUILD_TYPE:string=" . wfEscapeShellArg( $GLOBALS['wgHipHopBuildType'] ) .
' -D PROGRAM_NAME:string=mediawiki-hphp';
-
+
if ( file_exists( '/usr/bin/ccache' ) ) {
$cmd .= ' -D CMAKE_CXX_COMPILER:string=ccache' .
' -D CMAKE_CXX_COMPILER_ARG1:string=' . wfEscapeShellArg( $cxx );
@@ -179,7 +179,7 @@ class MakeHipHop extends Maintenance {
# Determine appropriate make concurrency
# Compilation can take a lot of memory, let's assume that that is limiting.
$procs = $this->getNumProcs();
-
+
# Run make. This is the slow step.
passthru( 'make -j' . wfEscapeShellArg( $procs ) );
diff --git a/maintenance/hiphop/run-server b/maintenance/hiphop/run-server
index 1c4b51f4..1adfe29f 100644
--- a/maintenance/hiphop/run-server
+++ b/maintenance/hiphop/run-server
@@ -33,10 +33,10 @@ class RunHipHopServer extends Maintenance {
$sourceBase = realpath( "$IP/.." );
}
- passthru(
+ passthru(
'cd ' . wfEscapeShellArg( $sourceBase ) . " && " .
'MW_INSTALL_PATH=' . wfEscapeShellArg( $IP ) . ' ' .
- wfEscapeShellArg(
+ wfEscapeShellArg(
"$buildDir/persistent/mediawiki-hphp",
'-c', "$thisDir/server.conf",
'-v', "Server.SourceRoot=$sourceBase",
diff --git a/maintenance/ibm_db2/foreignkeys.sql b/maintenance/ibm_db2/foreignkeys.sql
deleted file mode 100644
index 4f1450d9..00000000
--- a/maintenance/ibm_db2/foreignkeys.sql
+++ /dev/null
@@ -1,102 +0,0 @@
--- good
-ALTER TABLE user_groups ADD CONSTRAINT USER_GROUPS_FK1 FOREIGN KEY (ug_user) REFERENCES user(user_id) ON DELETE CASCADE
-;
-
--- good
-ALTER TABLE user_newtalk ADD CONSTRAINT USER_NEWTALK_FK1 FOREIGN KEY (user_id) REFERENCES user(user_id) ON DELETE CASCADE
-;
-
--- referenced value not found
-ALTER TABLE revision ADD CONSTRAINT REVISION_PAGE_FK FOREIGN KEY (rev_page) REFERENCES page(page_id) ON DELETE CASCADE
-;
--- referenced value not found
-ALTER TABLE revision ADD CONSTRAINT REVISION_USER_FK FOREIGN KEY (rev_user) REFERENCES user(user_id) ON DELETE RESTRICT
-;
-
--- good
-ALTER TABLE page_restrictions ADD CONSTRAINT PAGE_RESTRICTIONS_PAGE_FK FOREIGN KEY (pr_page) REFERENCES page(page_id) ON DELETE CASCADE
-;
-
--- good
-ALTER TABLE page_props ADD CONSTRAINT PAGE_PROPS_PAGE_FK FOREIGN KEY (pp_page) REFERENCES page(page_id) ON DELETE CASCADE
-;
-
--- cannot contain null values
--- ALTER TABLE archive ADD CONSTRAINT ARCHIVE_USER_FK FOREIGN KEY (ar_user) REFERENCES user(user_id) ON DELETE SET NULL
---;
-
--- referenced value not found
-ALTER TABLE redirect ADD CONSTRAINT REDIRECT_FROM_FK FOREIGN KEY (rd_from) REFERENCES page(page_id) ON DELETE CASCADE
-;
-
--- referenced value not found
-ALTER TABLE pagelinks ADD CONSTRAINT PAGELINKS_FROM_FK FOREIGN KEY (pl_from) REFERENCES page(page_id) ON DELETE CASCADE
-;
-
--- good
-ALTER TABLE templatelinks ADD CONSTRAINT TEMPLATELINKS_FROM_FK FOREIGN KEY (tl_from) REFERENCES page(page_id) ON DELETE CASCADE
-;
-
--- good
-ALTER TABLE imagelinks ADD CONSTRAINT IMAGELINKS_FROM_FK FOREIGN KEY (il_from) REFERENCES page(page_id) ON DELETE CASCADE
-;
-
--- good
-ALTER TABLE categorylinks ADD CONSTRAINT CATEGORYLINKS_FROM_FK FOREIGN KEY (cl_from) REFERENCES page(page_id) ON DELETE CASCADE
-;
-
--- good
-ALTER TABLE externallinks ADD CONSTRAINT EXTERNALLINKS_FROM_FK FOREIGN KEY (el_from) REFERENCES page(page_id) ON DELETE CASCADE
-;
-
--- good
-ALTER TABLE langlinks ADD CONSTRAINT LANGLINKS_FROM_FK FOREIGN KEY (ll_from) REFERENCES page(page_id) ON DELETE CASCADE
-;
-
--- cannot contain null values
--- ALTER TABLE ipblocks ADD CONSTRAINT IPBLOCKS_USER_FK FOREIGN KEY (ipb_user) REFERENCES user(user_id) ON DELETE SET NULL
---;
-
--- good
-ALTER TABLE ipblocks ADD CONSTRAINT IPBLOCKS_BY_FK FOREIGN KEY (ipb_by) REFERENCES user(user_id) ON DELETE CASCADE
-;
-
--- cannot contain null values
--- ALTER TABLE image ADD CONSTRAINT IMAGE_USER_FK FOREIGN KEY (img_user) REFERENCES user(user_id) ON DELETE SET NULL
---;
-
--- cannot contain null values
--- ALTER TABLE oldimage ADD CONSTRAINT OLDIMAGE_USER_FK FOREIGN KEY (oi_user) REFERENCES user(user_id) ON DELETE SET NULL
---;
-
--- good
-ALTER TABLE oldimage ADD CONSTRAINT OLDIMAGE_NAME_FK FOREIGN KEY (oi_name) REFERENCES image(img_name) ON DELETE CASCADE
-;
-
--- cannot contain null values
--- ALTER TABLE filearchive ADD CONSTRAINT FILEARCHIVE_DELETED_USER_FK FOREIGN KEY (fa_deleted_user) REFERENCES user(user_id) ON DELETE SET NULL
---;
-
--- cannot contain null values
--- ALTER TABLE filearchive ADD CONSTRAINT FILEARCHIVE_USER_FK FOREIGN KEY (fa_user) REFERENCES user(user_id) ON DELETE SET NULL
---;
-
--- cannot contain null values
--- ALTER TABLE recentchanges ADD CONSTRAINT RECENTCHANGES_USER_FK FOREIGN KEY (rc_user) REFERENCES user(user_id) ON DELETE SET NULL
---;
-
--- cannot contain null values
--- ALTER TABLE recentchanges ADD CONSTRAINT RECENTCHANGES_CUR_ID_FK FOREIGN KEY (rc_cur_id) REFERENCES page(page_id) ON DELETE SET NULL
---;
-
--- good
-ALTER TABLE watchlist ADD CONSTRAINT WATCHLIST_USER_FK FOREIGN KEY (wl_user) REFERENCES user(user_id) ON DELETE CASCADE
-;
-
--- cannot contain null values
--- ALTER TABLE protected_titles ADD CONSTRAINT PROTECTED_TITLES_USER_FK FOREIGN KEY (pt_user) REFERENCES user(user_id) ON DELETE SET NULL
---;
-
--- cannot contain null values
--- ALTER TABLE logging ADD CONSTRAINT LOGGING_USER_FK FOREIGN KEY (log_user) REFERENCES user(user_id) ON DELETE SET NULL
---; \ No newline at end of file
diff --git a/maintenance/ibm_db2/patch-categorylinks-better-collation.sql b/maintenance/ibm_db2/patch-categorylinks-better-collation.sql
deleted file mode 100644
index 312583ac..00000000
--- a/maintenance/ibm_db2/patch-categorylinks-better-collation.sql
+++ /dev/null
@@ -1,21 +0,0 @@
---
--- patch-categorylinks-better-collation.sql
---
---
--- Track category inclusions *used inline*
--- This tracks a single level of category membership
--- (folksonomic tagging, really).
---
-CREATE TABLE categorylinks (
- cl_from BIGINT NOT NULL DEFAULT 0,
- -- REFERENCES page(page_id) ON DELETE CASCADE,
- cl_to VARCHAR(255) NOT NULL,
- -- cl_sortkey has to be at least 86 wide
- -- in order to be compatible with the old MySQL schema from MW 1.10
- --cl_sortkey VARCHAR(86),
- cl_sortkey VARCHAR(230) FOR BIT DATA NOT NULL ,
- cl_sortkey_prefix VARCHAR(255) FOR BIT DATA NOT NULL ,
- cl_timestamp TIMESTAMP(3) NOT NULL,
- cl_collation VARCHAR(32) FOR BIT DATA NOT NULL ,
- cl_type VARCHAR(6) FOR BIT DATA NOT NULL
-);
diff --git a/maintenance/ibm_db2/patch-change_tag-indexes.sql b/maintenance/ibm_db2/patch-change_tag-indexes.sql
deleted file mode 100644
index 1621a038..00000000
--- a/maintenance/ibm_db2/patch-change_tag-indexes.sql
+++ /dev/null
@@ -1,5 +0,0 @@
-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);
--- Covering index, so we can pull all the info only out of the index.
-CREATE INDEX change_tag_tag_id ON change_tag (ct_tag,ct_rc_id,ct_rev_id,ct_log_id);
diff --git a/maintenance/ibm_db2/patch-change_tag.sql b/maintenance/ibm_db2/patch-change_tag.sql
deleted file mode 100644
index 3b6f9d54..00000000
--- a/maintenance/ibm_db2/patch-change_tag.sql
+++ /dev/null
@@ -1,8 +0,0 @@
--- A table to track tags for revisions, logs and recent changes.
-CREATE TABLE change_tag (
- ct_rc_id INTEGER,
- ct_log_id INTEGER,
- ct_rev_id INTEGER,
- ct_tag varchar(255) NOT NULL,
- ct_params CLOB(64K) INLINE LENGTH 4096
-);
diff --git a/maintenance/ibm_db2/patch-change_tag_summary.sql b/maintenance/ibm_db2/patch-change_tag_summary.sql
deleted file mode 100644
index 768cbfaa..00000000
--- a/maintenance/ibm_db2/patch-change_tag_summary.sql
+++ /dev/null
@@ -1,7 +0,0 @@
--- Rollup table to pull a LIST of tags simply
-CREATE TABLE tag_summary (
- ts_rc_id INTEGER,
- ts_log_id INTEGER,
- ts_rev_id INTEGER,
- ts_tags CLOB(64K) INLINE LENGTH 4096 NOT NULL
-);
diff --git a/maintenance/ibm_db2/patch-change_valid_tag.sql b/maintenance/ibm_db2/patch-change_valid_tag.sql
deleted file mode 100644
index 9bdcbc92..00000000
--- a/maintenance/ibm_db2/patch-change_valid_tag.sql
+++ /dev/null
@@ -1,3 +0,0 @@
-CREATE TABLE valid_tag (
- vt_tag varchar(255) NOT NULL PRIMARY KEY
-);
diff --git a/maintenance/ibm_db2/patch-cl_collation-field.sql b/maintenance/ibm_db2/patch-cl_collation-field.sql
deleted file mode 100644
index 6999dace..00000000
--- a/maintenance/ibm_db2/patch-cl_collation-field.sql
+++ /dev/null
@@ -1 +0,0 @@
-ALTER TABLE categorylinks ADD cl_collation VARCHAR(32) FOR BIT DATA NOT NULL
diff --git a/maintenance/ibm_db2/patch-cl_sortkey_prefix-field.sql b/maintenance/ibm_db2/patch-cl_sortkey_prefix-field.sql
deleted file mode 100644
index 58b78147..00000000
--- a/maintenance/ibm_db2/patch-cl_sortkey_prefix-field.sql
+++ /dev/null
@@ -1 +0,0 @@
-ALTER TABLE categorylinks ADD cl_sortkey_prefix VARCHAR(255) FOR BIT DATA NOT NULL
diff --git a/maintenance/ibm_db2/patch-cl_type-field.sql b/maintenance/ibm_db2/patch-cl_type-field.sql
deleted file mode 100644
index 5952c989..00000000
--- a/maintenance/ibm_db2/patch-cl_type-field.sql
+++ /dev/null
@@ -1 +0,0 @@
-ALTER TABLE categorylinks ADD cl_type VARCHAR(6) FOR BIT DATA NOT NULL
diff --git a/maintenance/ibm_db2/patch-external_user.sql b/maintenance/ibm_db2/patch-external_user.sql
deleted file mode 100644
index 96cb8237..00000000
--- a/maintenance/ibm_db2/patch-external_user.sql
+++ /dev/null
@@ -1,7 +0,0 @@
-CREATE TABLE external_user (
- -- Foreign key to user_id
- eu_local_id BIGINT NOT NULL PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (START WITH 1),
-
- -- Some opaque identifier provided by the external database
- eu_external_id VARCHAR(255) NOT NULL
-);
diff --git a/maintenance/ibm_db2/patch-ipb_allow_usertalk.sql b/maintenance/ibm_db2/patch-ipb_allow_usertalk.sql
deleted file mode 100644
index 6274bb22..00000000
--- a/maintenance/ibm_db2/patch-ipb_allow_usertalk.sql
+++ /dev/null
@@ -1,23 +0,0 @@
-CREATE TABLE ipblocks (
- ipb_id INTEGER NOT NULL PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (START WITH 1),
- --DEFAULT nextval('ipblocks_ipb_id_val'),
- ipb_address VARCHAR(1024),
- ipb_user BIGINT NOT NULL DEFAULT 0,
- -- REFERENCES user(user_id) ON DELETE SET NULL,
- ipb_by BIGINT NOT NULL DEFAULT 0,
- -- REFERENCES user(user_id) ON DELETE CASCADE,
- ipb_by_text VARCHAR(255) NOT NULL DEFAULT '',
- ipb_reason VARCHAR(1024) NOT NULL,
- ipb_timestamp TIMESTAMP(3) NOT NULL,
- ipb_auto SMALLINT NOT NULL DEFAULT 0,
- ipb_anon_only SMALLINT NOT NULL DEFAULT 0,
- ipb_create_account SMALLINT NOT NULL DEFAULT 1,
- ipb_enable_autoblock SMALLINT NOT NULL DEFAULT 1,
- ipb_expiry TIMESTAMP(3) NOT NULL,
- ipb_range_start VARCHAR(1024),
- ipb_range_end VARCHAR(1024),
- ipb_deleted SMALLINT NOT NULL DEFAULT 0,
- ipb_block_email SMALLINT NOT NULL DEFAULT 0,
- ipb_allow_usertalk SMALLINT NOT NULL DEFAULT 0
-
-);
diff --git a/maintenance/ibm_db2/patch-iw_api-field.sql b/maintenance/ibm_db2/patch-iw_api-field.sql
deleted file mode 100644
index dd732a58..00000000
--- a/maintenance/ibm_db2/patch-iw_api-field.sql
+++ /dev/null
@@ -1 +0,0 @@
-ALTER TABLE interwiki ADD iw_api CLOB(64K) INLINE LENGTH 4096 NOT NULL
diff --git a/maintenance/ibm_db2/patch-iw_api_and_wikiid.sql b/maintenance/ibm_db2/patch-iw_api_and_wikiid.sql
deleted file mode 100644
index 1b1e3592..00000000
--- a/maintenance/ibm_db2/patch-iw_api_and_wikiid.sql
+++ /dev/null
@@ -1,8 +0,0 @@
-CREATE TABLE interwiki (
- iw_prefix VARCHAR(32) NOT NULL UNIQUE,
- iw_url CLOB(64K) INLINE LENGTH 4096 NOT NULL,
- iw_api CLOB(64K) INLINE LENGTH 4096 NOT NULL,
- iw_wikiid varchar(64) NOT NULL,
- iw_local SMALLINT NOT NULL,
- iw_trans SMALLINT NOT NULL DEFAULT 0
-);
diff --git a/maintenance/ibm_db2/patch-iw_wikiid-field.sql b/maintenance/ibm_db2/patch-iw_wikiid-field.sql
deleted file mode 100644
index fe49e3c0..00000000
--- a/maintenance/ibm_db2/patch-iw_wikiid-field.sql
+++ /dev/null
@@ -1 +0,0 @@
-ALTER TABLE interwiki ADD iw_wikiid varchar(64) NOT NULL
diff --git a/maintenance/ibm_db2/patch-iwlinks.sql b/maintenance/ibm_db2/patch-iwlinks.sql
deleted file mode 100644
index 2902512f..00000000
--- a/maintenance/ibm_db2/patch-iwlinks.sql
+++ /dev/null
@@ -1,7 +0,0 @@
-CREATE TABLE "IWLINKS"
-(
-"IWL_FROM" INT NOT NULL ,
-"IWL_PREFIX" VARCHAR(20) FOR BIT DATA NOT NULL ,
-"IWL_TITLE" VARCHAR(255) FOR BIT DATA NOT NULL
-)
-;
diff --git a/maintenance/ibm_db2/patch-l10n_cache.sql b/maintenance/ibm_db2/patch-l10n_cache.sql
deleted file mode 100644
index 49ebed2b..00000000
--- a/maintenance/ibm_db2/patch-l10n_cache.sql
+++ /dev/null
@@ -1,8 +0,0 @@
-CREATE TABLE l10n_cache (
- -- Language code
- lc_lang VARCHAR(32) NOT NULL,
- -- Cache key
- lc_key VARCHAR(255) NOT NULL,
- -- Value
- lc_value CLOB(16M) INLINE LENGTH 4096 NOT NULL
-);
diff --git a/maintenance/ibm_db2/patch-log_search-rename-index.sql b/maintenance/ibm_db2/patch-log_search-rename-index.sql
deleted file mode 100644
index a6a696e1..00000000
--- a/maintenance/ibm_db2/patch-log_search-rename-index.sql
+++ /dev/null
@@ -1,8 +0,0 @@
-CREATE TABLE log_search (
- -- The type of ID (rev ID, log ID, rev TIMESTAMP(3), username)
- ls_field VARCHAR(32) FOR BIT DATA NOT NULL,
- -- The value of the ID
- ls_value varchar(255) NOT NULL,
- -- Key to log_id
- ls_log_id BIGINT NOT NULL default 0
-);
diff --git a/maintenance/ibm_db2/patch-log_search.sql b/maintenance/ibm_db2/patch-log_search.sql
deleted file mode 100644
index a6a696e1..00000000
--- a/maintenance/ibm_db2/patch-log_search.sql
+++ /dev/null
@@ -1,8 +0,0 @@
-CREATE TABLE log_search (
- -- The type of ID (rev ID, log ID, rev TIMESTAMP(3), username)
- ls_field VARCHAR(32) FOR BIT DATA NOT NULL,
- -- The value of the ID
- ls_value varchar(255) NOT NULL,
- -- Key to log_id
- ls_log_id BIGINT NOT NULL default 0
-);
diff --git a/maintenance/ibm_db2/patch-log_user_text.sql b/maintenance/ibm_db2/patch-log_user_text.sql
deleted file mode 100644
index 3534057a..00000000
--- a/maintenance/ibm_db2/patch-log_user_text.sql
+++ /dev/null
@@ -1,17 +0,0 @@
-CREATE TABLE logging (
- log_id BIGINT NOT NULL PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (START WITH 1),
- --PRIMARY KEY DEFAULT nextval('log_log_id_seq'),
- log_type VARCHAR(32) NOT NULL,
- log_action VARCHAR(32) NOT NULL,
- log_timestamp TIMESTAMP(3) NOT NULL,
- log_user BIGINT NOT NULL DEFAULT 0,
- -- REFERENCES user(user_id) ON DELETE SET NULL,
- -- Name of the user who performed this action
- log_user_text VARCHAR(255) NOT NULL default '',
- log_namespace SMALLINT NOT NULL,
- log_title VARCHAR(255) NOT NULL,
- log_page BIGINT,
- log_comment VARCHAR(255),
- log_params CLOB(64K) INLINE LENGTH 4096,
- log_deleted SMALLINT NOT NULL DEFAULT 0
-);
diff --git a/maintenance/ibm_db2/patch-module_deps.sql b/maintenance/ibm_db2/patch-module_deps.sql
deleted file mode 100644
index 5058d1f5..00000000
--- a/maintenance/ibm_db2/patch-module_deps.sql
+++ /dev/null
@@ -1,6 +0,0 @@
-CREATE TABLE "MODULE_DEPS" (
-"MD_MODULE" VARCHAR(255) FOR BIT DATA NOT NULL ,
-"MD_SKIN" VARCHAR(32) FOR BIT DATA NOT NULL ,
-"MD_DEPS" CLOB(16M) INLINE LENGTH 4096 NOT NULL
-)
-;
diff --git a/maintenance/ibm_db2/patch-msg_resource.sql b/maintenance/ibm_db2/patch-msg_resource.sql
deleted file mode 100644
index 58b3dd6c..00000000
--- a/maintenance/ibm_db2/patch-msg_resource.sql
+++ /dev/null
@@ -1,8 +0,0 @@
-CREATE TABLE "MSG_RESOURCE"
-(
-"MR_RESOURCE" VARCHAR(255) FOR BIT DATA NOT NULL ,
-"MR_LANG" VARCHAR(32) FOR BIT DATA NOT NULL ,
-"MR_BLOB" BLOB NOT NULL ,
-"MR_TIMESTAMP" TIMESTAMP(3) NOT NULL
-)
-;
diff --git a/maintenance/ibm_db2/patch-msg_resource_links.sql b/maintenance/ibm_db2/patch-msg_resource_links.sql
deleted file mode 100644
index 4c0ff918..00000000
--- a/maintenance/ibm_db2/patch-msg_resource_links.sql
+++ /dev/null
@@ -1,6 +0,0 @@
-CREATE TABLE "MSG_RESOURCE_LINKS"
-(
-"MRL_RESOURCE" VARCHAR(255) FOR BIT DATA NOT NULL ,
-"MRL_MESSAGE" VARCHAR(255) FOR BIT DATA NOT NULL
-)
-;
diff --git a/maintenance/ibm_db2/patch-rd_interwiki.sql b/maintenance/ibm_db2/patch-rd_interwiki.sql
deleted file mode 100644
index c162548c..00000000
--- a/maintenance/ibm_db2/patch-rd_interwiki.sql
+++ /dev/null
@@ -1,8 +0,0 @@
-CREATE TABLE redirect (
- rd_from BIGINT NOT NULL PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (START WITH 1),
- --REFERENCES page(page_id) ON DELETE CASCADE,
- rd_namespace SMALLINT NOT NULL DEFAULT 0,
- rd_title VARCHAR(255) NOT NULL DEFAULT '',
- rd_interwiki varchar(32),
- rd_fragment VARCHAR(255)
-);
diff --git a/maintenance/ibm_db2/patch-ss_active_users.sql b/maintenance/ibm_db2/patch-ss_active_users.sql
deleted file mode 100644
index f0e6d145..00000000
--- a/maintenance/ibm_db2/patch-ss_active_users.sql
+++ /dev/null
@@ -1,11 +0,0 @@
-CREATE TABLE site_stats (
- ss_row_id BIGINT NOT NULL UNIQUE,
- ss_total_views BIGINT DEFAULT 0,
- ss_total_edits BIGINT DEFAULT 0,
- ss_good_articles BIGINT 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
-);
diff --git a/maintenance/ibm_db2/patch-ul_value.sql b/maintenance/ibm_db2/patch-ul_value.sql
deleted file mode 100644
index cd00f8e0..00000000
--- a/maintenance/ibm_db2/patch-ul_value.sql
+++ /dev/null
@@ -1,3 +0,0 @@
-CREATE TABLE updatelog (
- ul_key VARCHAR(255) NOT NULL PRIMARY KEY
-);
diff --git a/maintenance/ibm_db2/patch-uq61_msg_resource_links.sql b/maintenance/ibm_db2/patch-uq61_msg_resource_links.sql
deleted file mode 100644
index d9185c0a..00000000
--- a/maintenance/ibm_db2/patch-uq61_msg_resource_links.sql
+++ /dev/null
@@ -1,7 +0,0 @@
-CREATE UNIQUE INDEX "UQ61_MSG_RESOURCE_LINKS" ON "MSG_RESOURCE_LINKS"
-(
-"MRL_MESSAGE",
-"MRL_RESOURCE"
-)
-ALLOW REVERSE SCANS
-;
diff --git a/maintenance/ibm_db2/patch-uq81_msg_resource.sql b/maintenance/ibm_db2/patch-uq81_msg_resource.sql
deleted file mode 100644
index 8ed85379..00000000
--- a/maintenance/ibm_db2/patch-uq81_msg_resource.sql
+++ /dev/null
@@ -1,7 +0,0 @@
-CREATE UNIQUE INDEX "UQ81_MSG_RESOURCE" ON "MSG_RESOURCE"
-(
-"MR_RESOURCE"
-,"MR_LANG"
-)
-ALLOW REVERSE SCANS
-;
diff --git a/maintenance/ibm_db2/patch-uq96_module_deps.sql b/maintenance/ibm_db2/patch-uq96_module_deps.sql
deleted file mode 100644
index e0cc879a..00000000
--- a/maintenance/ibm_db2/patch-uq96_module_deps.sql
+++ /dev/null
@@ -1,7 +0,0 @@
-CREATE UNIQUE INDEX "UQ96_MODULE_DEPS" ON "MODULE_DEPS"
-(
-"MD_MODULE"
-,"MD_SKIN"
-)
-ALLOW REVERSE SCANS
-;
diff --git a/maintenance/ibm_db2/patch-user_properties.sql b/maintenance/ibm_db2/patch-user_properties.sql
deleted file mode 100644
index 72dcd792..00000000
--- a/maintenance/ibm_db2/patch-user_properties.sql
+++ /dev/null
@@ -1,10 +0,0 @@
-CREATE TABLE user_properties (
- -- Foreign key to user.user_id
- up_user BIGINT NOT NULL,
-
- -- Name of the option being saved. This is indexed for bulk lookup.
- up_property VARCHAR(32) FOR BIT DATA NOT NULL,
-
- -- Property value as a string.
- up_value CLOB(64K) INLINE LENGTH 4096
-);
diff --git a/maintenance/ibm_db2/tables.sql b/maintenance/ibm_db2/tables.sql
deleted file mode 100644
index caad9251..00000000
--- a/maintenance/ibm_db2/tables.sql
+++ /dev/null
@@ -1,930 +0,0 @@
--- IBM DB2
-
--- SQL to create the initial tables for the MediaWiki database.
--- This is read and executed by the install script; you should
--- not have to run it by itself unless doing a manual install.
-
--- Notes:
--- * DB2 will convert all table and column names to all caps internally.
--- * DB2 has a 32k limit on SQL filesize, so it may be necessary
--- to split this into two files soon.
-
-
-CREATE TABLE user (
- -- Needs to start with 0
- user_id BIGINT
- PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (START WITH 0),
- user_name VARCHAR(255) NOT NULL UNIQUE,
- user_real_name VARCHAR(255),
- user_password VARCHAR(1024),
- user_newpassword VARCHAR(1024),
- user_newpass_time TIMESTAMP(3),
- user_token VARCHAR(255),
- user_email VARCHAR(1024),
- user_email_token VARCHAR(255),
- user_email_token_expires TIMESTAMP(3),
- user_email_authenticated TIMESTAMP(3),
- -- obsolete, replace by user_properties table
- -- user_options CLOB(64K) INLINE LENGTH 4096,
- user_touched TIMESTAMP(3),
- user_registration TIMESTAMP(3),
- user_editcount INTEGER
-);
-CREATE INDEX user_email_token_idx
- ON user (user_email_token);
-CREATE UNIQUE INDEX user_include_idx
- ON user (user_id)
- INCLUDE (user_name, user_real_name, user_password, user_newpassword,
- user_newpass_time, user_token,
- user_email, user_email_token, user_email_token_expires,
- user_email_authenticated,
- user_touched, user_registration, user_editcount);
-CREATE UNIQUE INDEX user_email
- ON user (user_email);
-
-
-
--- Create a dummy user to satisfy fk contraints especially with revisions
-INSERT INTO user(
- user_name, user_real_name, user_password, user_newpassword, user_newpass_time,
- user_email, user_email_authenticated, user_token, user_registration, user_editcount
-)
-VALUES (
- 'Anonymous', '', NULL, NULL, CURRENT_TIMESTAMP,
- NULL, NULL, NULL, CURRENT_TIMESTAMP, 0
-);
-
-
-
-CREATE TABLE user_groups (
- ug_user BIGINT NOT NULL DEFAULT 0,
- -- REFERENCES user(user_id) ON DELETE CASCADE,
- ug_group VARCHAR(255) NOT NULL
-);
-CREATE INDEX user_groups_unique
- ON user_groups (ug_user, ug_group);
-
-
-
-CREATE TABLE user_newtalk (
- -- registered users key
- user_id BIGINT NOT NULL DEFAULT 0,
- -- REFERENCES user(user_id) ON DELETE CASCADE,
- -- anonymous users key
- user_ip VARCHAR(40),
- user_last_timestamp TIMESTAMP(3)
-);
-CREATE INDEX user_newtalk_id_idx
- ON user_newtalk (user_id);
-CREATE INDEX user_newtalk_ip_idx
- ON user_newtalk (user_ip);
-CREATE UNIQUE INDEX user_newtalk_include_idx
- ON user_newtalk (user_id, user_ip)
- INCLUDE (user_last_timestamp);
-
-
-
-CREATE TABLE page (
- page_id BIGINT
- PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (START WITH 1),
- page_namespace SMALLINT NOT NULL,
- page_title VARCHAR(255) NOT NULL,
- page_restrictions VARCHAR(1024),
- page_counter BIGINT NOT NULL DEFAULT 0,
- page_is_redirect SMALLINT NOT NULL DEFAULT 0,
- page_is_new SMALLINT NOT NULL DEFAULT 0,
- page_random NUMERIC(15,14) NOT NULL,
- page_touched TIMESTAMP(3),
- page_latest BIGINT NOT NULL, -- FK?
- page_len BIGINT NOT NULL
-);
-CREATE UNIQUE INDEX page_unique_name
- ON page (page_namespace, page_title);
-CREATE INDEX page_random_idx
- ON page (page_random);
-CREATE INDEX page_len_idx
- ON page (page_len);
-CREATE UNIQUE INDEX page_id_include
- ON page (page_id)
- INCLUDE (page_namespace, page_title, page_restrictions, page_counter, page_is_redirect, page_is_new, page_random, page_touched, page_latest, page_len);
-CREATE UNIQUE INDEX page_name_include
- ON page (page_namespace, page_title)
- INCLUDE (page_id, page_restrictions, page_counter, page_is_redirect, page_is_new, page_random, page_touched, page_latest, page_len);
-
-
-
-CREATE TABLE revision (
- rev_id BIGINT
- PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (START WITH 1),
- rev_page BIGINT NOT NULL DEFAULT 0,
- -- REFERENCES page (page_id) ON DELETE CASCADE,
- rev_text_id BIGINT, -- FK
- rev_comment VARCHAR(1024),
- rev_user BIGINT NOT NULL DEFAULT 0,
- -- REFERENCES user(user_id) ON DELETE RESTRICT,
- rev_user_text VARCHAR(255) NOT NULL,
- rev_timestamp TIMESTAMP(3) NOT NULL,
- rev_minor_edit SMALLINT NOT NULL DEFAULT 0,
- rev_deleted SMALLINT NOT NULL DEFAULT 0,
- rev_len BIGINT,
- rev_parent_id BIGINT DEFAULT NULL,
- rev_sha1 VARCHAR(255) NOT NULL DEFAULT ''
-);
-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);
-CREATE INDEX rev_user_idx
- ON revision (rev_user);
-CREATE INDEX rev_user_text_idx
- ON revision (rev_user_text);
-
-
-
-CREATE TABLE text ( -- replaces reserved word 'text'
- old_id INTEGER
- PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (START WITH 1),
- old_text CLOB(16M) INLINE LENGTH 4096,
- old_flags VARCHAR(1024)
-);
-
-
-
-CREATE TABLE page_restrictions (
- pr_id BIGINT
- PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (START WITH 1),
- pr_page INTEGER NOT NULL DEFAULT 0,
- --(used to be nullable)
- -- REFERENCES page (page_id) ON DELETE CASCADE,
- pr_type VARCHAR(60) NOT NULL,
- pr_level VARCHAR(60) NOT NULL,
- pr_cascade SMALLINT NOT NULL,
- pr_user INTEGER,
- pr_expiry TIMESTAMP(3)
- --PRIMARY KEY (pr_page, pr_type)
-);
---ALTER TABLE page_restrictions ADD CONSTRAINT page_restrictions_pk PRIMARY KEY (pr_page, pr_type);
-CREATE UNIQUE INDEX pr_pagetype
- ON page_restrictions (pr_page, pr_type);
-CREATE INDEX pr_typelevel
- ON page_restrictions (pr_type, pr_level);
-CREATE INDEX pr_level
- ON page_restrictions (pr_level);
-CREATE INDEX pr_cascade
- ON page_restrictions (pr_cascade);
-
-
-
-CREATE TABLE page_props (
- pp_page INTEGER NOT NULL DEFAULT 0,
- -- REFERENCES page (page_id) ON DELETE CASCADE,
- pp_propname VARCHAR(255) NOT NULL,
- pp_value CLOB(64K) INLINE LENGTH 4096 NOT NULL,
- PRIMARY KEY (pp_page, pp_propname)
-);
-CREATE INDEX page_props_propname
- ON page_props (pp_propname);
-
-
-
-CREATE TABLE archive (
- ar_namespace SMALLINT NOT NULL,
- ar_title VARCHAR(255) NOT NULL,
- ar_text CLOB(16M) INLINE LENGTH 4096,
- ar_comment VARCHAR(1024),
- ar_user BIGINT NOT NULL,
- -- no foreign keys in MySQL
- -- REFERENCES user(user_id) ON DELETE SET NULL,
- ar_user_text VARCHAR(255) NOT NULL,
- ar_timestamp TIMESTAMP(3) NOT NULL,
- ar_minor_edit SMALLINT NOT NULL DEFAULT 0,
- ar_flags VARCHAR(1024),
- ar_rev_id INTEGER,
- ar_text_id INTEGER,
- ar_deleted SMALLINT NOT NULL DEFAULT 0,
- ar_len INTEGER,
- ar_page_id INTEGER,
- ar_parent_id INTEGER,
- ar_sha1 VARCHAR(255) NOT NULL DEFAULT ''
-);
-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 TABLE redirect (
- rd_from BIGINT NOT NULL
- PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (START WITH 1),
- --REFERENCES page(page_id) ON DELETE CASCADE,
- rd_namespace SMALLINT NOT NULL DEFAULT 0,
- rd_title VARCHAR(255) NOT NULL DEFAULT '',
- rd_interwiki VARCHAR(32),
- rd_fragment VARCHAR(255)
-);
-CREATE INDEX redirect_ns_title
- ON redirect (rd_namespace, rd_title, rd_from);
-
-
-CREATE TABLE pagelinks (
- pl_from BIGINT NOT NULL DEFAULT 0,
- -- REFERENCES page(page_id) ON DELETE CASCADE,
- pl_namespace SMALLINT NOT NULL,
- pl_title VARCHAR(255) NOT NULL
-);
-CREATE UNIQUE INDEX pagelink_unique
- ON pagelinks (pl_from, pl_namespace, pl_title);
-
-
-
-CREATE TABLE templatelinks (
- tl_from BIGINT NOT NULL DEFAULT 0,
- -- REFERENCES page(page_id) ON DELETE CASCADE,
- tl_namespace SMALLINT NOT NULL,
- tl_title VARCHAR(255) NOT NULL
-);
-CREATE UNIQUE INDEX templatelinks_unique
- ON templatelinks (tl_namespace, tl_title, tl_from);
-CREATE UNIQUE INDEX tl_from_idx
- ON templatelinks (tl_from, tl_namespace, tl_title);
-
-
-
-CREATE TABLE imagelinks (
- il_from BIGINT NOT NULL DEFAULT 0,
- -- REFERENCES page(page_id) ON DELETE CASCADE,
- il_to VARCHAR(255) NOT NULL
-);
-CREATE UNIQUE INDEX il_from_idx
- ON imagelinks (il_to, il_from);
-CREATE UNIQUE INDEX il_to_idx
- ON imagelinks (il_from, il_to);
-
-
-
-CREATE TABLE categorylinks (
- cl_from BIGINT NOT NULL DEFAULT 0,
- -- REFERENCES page(page_id) ON DELETE CASCADE,
- cl_to VARCHAR(255) NOT NULL,
- -- cl_sortkey has to be at least 86 wide
- -- in order to be compatible with the old MySQL schema from MW 1.10
- --cl_sortkey VARCHAR(86),
- cl_sortkey VARCHAR(230) FOR BIT DATA NOT NULL,
- cl_sortkey_prefix VARCHAR(255) FOR BIT DATA NOT NULL,
- cl_timestamp TIMESTAMP(3) NOT NULL,
- cl_collation VARCHAR(32) FOR BIT DATA NOT NULL,
- cl_type VARCHAR(6) FOR BIT DATA NOT NULL
-);
-CREATE UNIQUE INDEX cl_from
- ON categorylinks (cl_from, cl_to);
-CREATE INDEX cl_sortkey
- ON categorylinks (cl_to, cl_sortkey, cl_from);
-
-
-
-CREATE TABLE externallinks (
- el_from BIGINT NOT NULL DEFAULT 0,
- -- REFERENCES page(page_id) ON DELETE CASCADE,
- el_to VARCHAR(1024) NOT NULL,
- el_index VARCHAR(1024) NOT NULL
-);
-CREATE INDEX externallinks_from_to
- ON externallinks (el_from, el_to);
-CREATE INDEX externallinks_index
- ON externallinks (el_index);
-
-
-
---
--- Track external user accounts, if ExternalAuth is used
---
-CREATE TABLE external_user (
- -- Foreign key to user_id
- eu_local_id BIGINT NOT NULL
- PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (START WITH 1),
-
- -- Some opaque identifier provided by the external database
- eu_external_id VARCHAR(255) NOT NULL
-);
-CREATE UNIQUE INDEX eu_external_id_idx
- ON external_user (eu_external_id)
- INCLUDE (eu_local_id);
-CREATE UNIQUE INDEX eu_local_id_idx
- ON external_user (eu_local_id)
- INCLUDE (eu_external_id);
-
-
-
-CREATE TABLE langlinks (
- ll_from BIGINT NOT NULL DEFAULT 0,
- -- REFERENCES page (page_id) ON DELETE CASCADE,
- ll_lang VARCHAR(20),
- ll_title VARCHAR(255)
-);
-CREATE UNIQUE INDEX langlinks_unique
- ON langlinks (ll_from, ll_lang);
-CREATE INDEX langlinks_lang_title
- ON langlinks (ll_lang, ll_title);
-
-
-
-CREATE TABLE site_stats (
- ss_row_id BIGINT NOT NULL UNIQUE,
- ss_total_views BIGINT DEFAULT 0,
- ss_total_edits BIGINT DEFAULT 0,
- ss_good_articles BIGINT 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
-);
-
-
-
-CREATE TABLE hitcounter (
- hc_id BIGINT NOT NULL
-);
-
-
-
-CREATE TABLE ipblocks (
- ipb_id INTEGER NOT NULL
- PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (START WITH 1),
- ipb_address VARCHAR(1024),
- ipb_user BIGINT NOT NULL DEFAULT 0,
- -- REFERENCES user(user_id) ON DELETE SET NULL,
- ipb_by BIGINT NOT NULL DEFAULT 0,
- -- REFERENCES user(user_id) ON DELETE CASCADE,
- ipb_by_text VARCHAR(255) NOT NULL DEFAULT '',
- ipb_reason VARCHAR(1024) NOT NULL,
- ipb_timestamp TIMESTAMP(3) NOT NULL,
- ipb_auto SMALLINT NOT NULL DEFAULT 0,
- ipb_anon_only SMALLINT NOT NULL DEFAULT 0,
- ipb_create_account SMALLINT NOT NULL DEFAULT 1,
- ipb_enable_autoblock SMALLINT NOT NULL DEFAULT 1,
- ipb_expiry TIMESTAMP(3) NOT NULL,
- ipb_range_start VARCHAR(1024),
- ipb_range_end VARCHAR(1024),
- ipb_deleted SMALLINT NOT NULL DEFAULT 0,
- ipb_block_email SMALLINT NOT NULL DEFAULT 0,
- ipb_allow_usertalk SMALLINT NOT NULL DEFAULT 0,
- ipb_parent_block_id INTEGER DEFAULT NULL
- -- REFERENCES ipblocks(ipb_id) ON DELETE SET NULL
-
-);
-CREATE INDEX ipb_address
- ON ipblocks (ipb_address);
-CREATE INDEX ipb_user
- ON ipblocks (ipb_user);
-CREATE INDEX ipb_range
- ON ipblocks (ipb_range_start, ipb_range_end);
-
-
-
-CREATE TABLE image (
- img_name VARCHAR(255) NOT NULL
- PRIMARY KEY,
- img_size BIGINT NOT NULL,
- img_width INTEGER NOT NULL,
- img_height INTEGER NOT NULL,
- img_metadata CLOB(16M) INLINE LENGTH 4096 NOT NULL DEFAULT '',
- img_bits SMALLINT,
- img_media_type VARCHAR(255),
- img_major_mime VARCHAR(255) DEFAULT 'unknown',
- img_minor_mime VARCHAR(32) DEFAULT 'unknown',
- img_description VARCHAR(1024) NOT NULL DEFAULT '',
- img_user BIGINT NOT NULL DEFAULT 0,
- -- REFERENCES user(user_id) ON DELETE SET NULL,
- img_user_text VARCHAR(255) NOT NULL DEFAULT '',
- img_timestamp TIMESTAMP(3),
- img_sha1 VARCHAR(255) NOT NULL DEFAULT ''
-);
-CREATE INDEX img_size_idx
- ON image (img_size);
-CREATE INDEX img_timestamp_idx
- ON image (img_timestamp);
-CREATE INDEX img_sha1
- ON image (img_sha1);
-
-
-CREATE TABLE oldimage (
- oi_name VARCHAR(255) NOT NULL DEFAULT '',
- oi_archive_name VARCHAR(255) NOT NULL,
- oi_size BIGINT NOT NULL,
- oi_width INTEGER NOT NULL,
- oi_height INTEGER NOT NULL,
- oi_bits SMALLINT NOT NULL,
- oi_description VARCHAR(1024),
- oi_user BIGINT NOT NULL DEFAULT 0,
- -- REFERENCES user(user_id) ON DELETE SET NULL,
- oi_user_text VARCHAR(255) NOT NULL,
- oi_timestamp TIMESTAMP(3) NOT NULL,
- oi_metadata CLOB(16M) INLINE LENGTH 4096 NOT NULL DEFAULT '',
- oi_media_type VARCHAR(255),
- oi_major_mime VARCHAR(255) NOT NULL DEFAULT 'unknown',
- oi_minor_mime VARCHAR(255) NOT NULL DEFAULT 'unknown',
- oi_deleted SMALLINT NOT NULL DEFAULT 0,
- oi_sha1 VARCHAR(255) NOT NULL DEFAULT ''
- --FOREIGN KEY (oi_name) REFERENCES image(img_name) ON DELETE CASCADE
-);
-CREATE INDEX oi_name_timestamp
- ON oldimage (oi_name, oi_timestamp);
-CREATE INDEX oi_name_archive_name
- ON oldimage (oi_name, oi_archive_name);
-CREATE INDEX oi_sha1
- ON oldimage (oi_sha1);
-
-
-
-CREATE TABLE filearchive (
- fa_id INTEGER NOT NULL
- PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (START WITH 1),
- fa_name VARCHAR(255) NOT NULL,
- fa_archive_name VARCHAR(255),
- fa_storage_group VARCHAR(255),
- fa_storage_key VARCHAR(64) DEFAULT '',
- fa_deleted_user BIGINT NOT NULL DEFAULT 0,
- -- REFERENCES user(user_id) ON DELETE SET NULL,
- fa_deleted_timestamp TIMESTAMP(3) NOT NULL,
- fa_deleted_reason VARCHAR(255),
- fa_size BIGINT NOT NULL,
- fa_width INTEGER NOT NULL,
- fa_height INTEGER NOT NULL,
- fa_metadata CLOB(16M) INLINE LENGTH 4096 NOT NULL DEFAULT '',
- fa_bits SMALLINT,
- fa_media_type VARCHAR(255),
- fa_major_mime VARCHAR(255) DEFAULT 'unknown',
- fa_minor_mime VARCHAR(255) DEFAULT 'unknown',
- fa_description VARCHAR(1024) NOT NULL,
- fa_user BIGINT NOT NULL DEFAULT 0,
- -- REFERENCES user(user_id) ON DELETE SET NULL,
- fa_user_text VARCHAR(255) NOT NULL,
- fa_timestamp TIMESTAMP(3),
- fa_deleted SMALLINT NOT NULL DEFAULT 0
-);
-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);
-CREATE INDEX fa_nouser
- ON filearchive (fa_deleted_user);
-
-
-
-CREATE TABLE recentchanges (
- rc_id INTEGER NOT NULL
- PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (START WITH 1),
- rc_timestamp TIMESTAMP(3) NOT NULL,
- rc_cur_time TIMESTAMP(3) NOT NULL,
- rc_user BIGINT NOT NULL DEFAULT 0,
- -- REFERENCES user(user_id) ON DELETE SET NULL,
- rc_user_text VARCHAR(255) NOT NULL,
- rc_namespace SMALLINT NOT NULL,
- rc_title VARCHAR(255) NOT NULL,
- rc_comment VARCHAR(255),
- rc_minor SMALLINT NOT NULL DEFAULT 0,
- rc_bot SMALLINT NOT NULL DEFAULT 0,
- rc_new SMALLINT NOT NULL DEFAULT 0,
- rc_cur_id BIGINT NOT NULL DEFAULT 0,
- -- REFERENCES page(page_id) ON DELETE SET NULL,
- rc_this_oldid BIGINT NOT NULL,
- rc_last_oldid BIGINT NOT NULL,
- rc_type SMALLINT NOT NULL DEFAULT 0,
- rc_moved_to_ns SMALLINT,
- rc_moved_to_title VARCHAR(255),
- rc_patrolled SMALLINT NOT NULL DEFAULT 0,
- rc_ip VARCHAR(40), -- was CIDR type
- rc_old_len INTEGER,
- rc_new_len INTEGER,
- rc_deleted SMALLINT NOT NULL DEFAULT 0,
- rc_logid BIGINT NOT NULL DEFAULT 0,
- rc_log_type VARCHAR(255),
- rc_log_action VARCHAR(255),
- rc_params CLOB(64K) INLINE LENGTH 4096
-
-);
-CREATE INDEX rc_timestamp
- ON recentchanges (rc_timestamp);
-CREATE INDEX rc_namespace_title
- ON recentchanges (rc_namespace, rc_title);
-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);
-
-
-
-CREATE TABLE watchlist (
- wl_user BIGINT NOT NULL DEFAULT 0,
- -- REFERENCES user(user_id) ON DELETE CASCADE,
- wl_namespace SMALLINT NOT NULL DEFAULT 0,
- wl_title VARCHAR(255) NOT NULL,
- wl_notificationtimestamp TIMESTAMP(3)
-);
-CREATE UNIQUE INDEX wl_user_namespace_title
- ON watchlist (wl_namespace, wl_title, wl_user);
-
-
-
-CREATE TABLE interwiki (
- iw_prefix VARCHAR(32) NOT NULL UNIQUE,
- iw_url CLOB(64K) INLINE LENGTH 4096 NOT NULL,
- iw_api CLOB(64K) INLINE LENGTH 4096 NOT NULL,
- iw_wikiid VARCHAR(64) NOT NULL,
- iw_local SMALLINT NOT NULL,
- iw_trans SMALLINT NOT NULL DEFAULT 0
-);
-
-
-
-CREATE TABLE querycache (
- qc_type VARCHAR(255) NOT NULL,
- qc_value BIGINT NOT NULL,
- qc_namespace INTEGER NOT NULL,
- qc_title VARCHAR(255) NOT NULL
-);
-CREATE INDEX querycache_type_value
- ON querycache (qc_type, qc_value);
-
-
-
-CREATE TABLE querycache_info (
- qci_type VARCHAR(255) UNIQUE NOT NULL,
- qci_timestamp TIMESTAMP(3)
-);
-
-
-
-CREATE TABLE querycachetwo (
- qcc_type VARCHAR(255) NOT NULL,
- qcc_value BIGINT NOT NULL DEFAULT 0,
- qcc_namespace INTEGER NOT NULL DEFAULT 0,
- qcc_title VARCHAR(255) NOT NULL DEFAULT '',
- qcc_namespacetwo INTEGER NOT NULL DEFAULT 0,
- qcc_titletwo VARCHAR(255) NOT NULL DEFAULT ''
-);
-CREATE INDEX querycachetwo_type_value
- ON querycachetwo (qcc_type, qcc_value);
-CREATE INDEX querycachetwo_title
- ON querycachetwo (qcc_type, qcc_namespace, qcc_title);
-CREATE INDEX querycachetwo_titletwo
- ON querycachetwo (qcc_type, qcc_namespacetwo, qcc_titletwo);
-
-
-
-CREATE TABLE objectcache (
- keyname VARCHAR(255) NOT NULL UNIQUE, -- was nullable
- value CLOB(16M) INLINE LENGTH 4096 NOT NULL DEFAULT '',
- exptime TIMESTAMP(3) NOT NULL
-);
-CREATE INDEX objectcacache_exptime
- ON objectcache (exptime);
-
-
-
-CREATE TABLE transcache (
- tc_url VARCHAR(255) NOT NULL UNIQUE,
- tc_contents CLOB(64K) INLINE LENGTH 4096 NOT NULL,
- tc_time TIMESTAMP(3) NOT NULL
-);
-
-
-
-CREATE TABLE logging (
- log_id BIGINT NOT NULL
- PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (START WITH 1),
- log_type VARCHAR(32) NOT NULL,
- log_action VARCHAR(32) NOT NULL,
- log_timestamp TIMESTAMP(3) NOT NULL,
- log_user BIGINT NOT NULL DEFAULT 0,
- -- REFERENCES user(user_id) ON DELETE SET NULL,
- -- Name of the user who performed this action
- log_user_text VARCHAR(255) NOT NULL DEFAULT '',
- log_namespace SMALLINT NOT NULL,
- log_title VARCHAR(255) NOT NULL,
- log_page BIGINT,
- log_comment VARCHAR(255),
- log_params CLOB(64K) INLINE LENGTH 4096,
- log_deleted SMALLINT NOT NULL DEFAULT 0
-);
-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_page_time
- ON logging (log_namespace, log_title, log_timestamp);
-CREATE INDEX log_user_type_time
- ON logging (log_user, log_type, log_timestamp);
-CREATE INDEX log_page_id_time
- ON logging (log_page, log_timestamp);
-CREATE UNIQUE INDEX type_action
- ON logging (log_type, log_action, log_timestamp);
-
-
-
-CREATE TABLE trackbacks (
- tb_id INTEGER NOT NULL
- PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (START WITH 1),
- -- foreign key also in MySQL
- tb_page INTEGER,
- -- REFERENCES page(page_id) ON DELETE CASCADE,
- tb_title VARCHAR(255) NOT NULL,
- tb_url CLOB(64K) INLINE LENGTH 4096 NOT NULL,
- tb_ex CLOB(64K) INLINE LENGTH 4096,
- tb_name VARCHAR(255)
-);
-CREATE INDEX trackback_page
- ON trackbacks (tb_page);
-
-
-
-CREATE TABLE job (
- job_id BIGINT NOT NULL
- PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (START WITH 1),
- job_cmd VARCHAR(255) NOT NULL,
- job_namespace SMALLINT NOT NULL,
- job_title VARCHAR(255) NOT NULL,
- job_params CLOB(64K) INLINE LENGTH 4096 NOT NULL
-);
-CREATE INDEX job_cmd_namespace_title
- ON job (job_cmd, job_namespace, job_title);
-
-
-
---TODO
---CREATE FUNCTION add_interwiki (TEXT, INT, SMALLINT) RETURNS INT LANGUAGE SQL AS
---$mw$
--- INSERT INTO interwiki (iw_prefix, iw_url, iw_local) VALUES ($1,$2,$3);
--- SELECT 1;
---$mw$;
-
-
-
--- hack implementation
--- should be replaced with OmniFind, Contains(), etc
-CREATE TABLE searchindex (
- si_page BIGINT NOT NULL,
- si_title VARCHAR(255) NOT NULL DEFAULT '',
- si_text CLOB NOT NULL
-);
-
-
-
--- This table is not used unless profiling is turned on
-CREATE TABLE profiling (
- pf_count INTEGER NOT NULL DEFAULT 0,
- pf_time NUMERIC(18,10) NOT NULL DEFAULT 0,
- pf_memory NUMERIC(18,10) NOT NULL DEFAULT 0,
- pf_name VARCHAR(255) NOT NULL,
- pf_server VARCHAR(255)
-);
-CREATE UNIQUE INDEX pf_name_server
- ON profiling (pf_name, pf_server);
-
-
-
-CREATE TABLE protected_titles (
- pt_namespace INTEGER NOT NULL,
- pt_title VARCHAR(255) NOT NULL,
- pt_user BIGINT NOT NULL DEFAULT 0,
- -- REFERENCES user(user_id) ON DELETE SET NULL,
- pt_reason VARCHAR(1024),
- pt_timestamp TIMESTAMP(3) NOT NULL,
- pt_expiry TIMESTAMP(3),
- pt_create_perm VARCHAR(60) NOT NULL DEFAULT ''
-);
-CREATE UNIQUE INDEX protected_titles_unique
- ON protected_titles (pt_namespace, pt_title);
-
-
-
-CREATE TABLE updatelog (
- ul_key VARCHAR(255) NOT NULL
- PRIMARY KEY
-);
-
-
-
-CREATE TABLE category (
- cat_id INTEGER NOT NULL
- PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (START WITH 1),
- cat_title VARCHAR(255) NOT NULL,
- cat_pages INTEGER NOT NULL DEFAULT 0,
- cat_subcats INTEGER NOT NULL DEFAULT 0,
- cat_files INTEGER NOT NULL DEFAULT 0,
- cat_hidden SMALLINT NOT NULL DEFAULT 0
-);
-CREATE UNIQUE INDEX category_title
- ON category (cat_title);
-CREATE INDEX category_pages
- ON category (cat_pages);
-
-
-
--- A table to track tags for revisions, logs and recent changes.
-CREATE TABLE change_tag (
- ct_rc_id INTEGER,
- ct_log_id INTEGER,
- ct_rev_id INTEGER,
- ct_tag VARCHAR(255) NOT NULL,
- ct_params CLOB(64K) INLINE LENGTH 4096
-);
-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);
--- Covering index, so we can pull all the info only out of the index.
-CREATE INDEX change_tag_tag_id
- ON change_tag (ct_tag, ct_rc_id, ct_rev_id, ct_log_id);
-
-
-
--- Rollup table to pull a LIST of tags simply
-CREATE TABLE tag_summary (
- ts_rc_id INTEGER,
- ts_log_id INTEGER,
- ts_rev_id INTEGER,
- ts_tags CLOB(64K) INLINE LENGTH 4096 NOT NULL
-);
-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);
-
-
-
-CREATE TABLE valid_tag (
- vt_tag VARCHAR(255) NOT NULL
- PRIMARY KEY
-);
-
-
-
---
--- User preferences and perhaps other fun stuff. :)
--- Replaces the old user.user_options blob, with a couple nice properties:
---
--- 1) We only store non-default settings, so changes to the DEFAULTs
--- are now reflected for everybody, not just new accounts.
--- 2) We can more easily do bulk lookups, statistics, or modifications of
--- saved options since it's a sane table structure.
---
-CREATE TABLE user_properties (
- -- Foreign key to user.user_id
- up_user BIGINT NOT NULL,
- -- Name of the option being saved. This is indexed for bulk lookup.
- up_property VARCHAR(255) FOR BIT DATA NOT NULL,
- -- Property value as a string.
- up_value CLOB(64K) INLINE LENGTH 4096
-);
-CREATE UNIQUE INDEX user_properties_user_property
- ON user_properties (up_user, up_property);
-CREATE INDEX user_properties_property
- ON user_properties (up_property);
-
-CREATE TABLE log_search (
- -- The type of ID (rev ID, log ID, rev TIMESTAMP(3), username)
- ls_field VARCHAR(32) FOR BIT DATA NOT NULL,
- -- The value of the ID
- ls_value VARCHAR(255) NOT NULL,
- -- Key to log_id
- ls_log_id BIGINT NOT NULL DEFAULT 0
-);
-CREATE UNIQUE INDEX ls_field_val
- ON log_search (ls_field, ls_value, ls_log_id);
-CREATE INDEX ls_log_id
- ON log_search (ls_log_id);
-
-
-
--- Table for storing localisation data
-CREATE TABLE l10n_cache (
- -- Language code
- lc_lang VARCHAR(32) NOT NULL,
- -- Cache key
- lc_key VARCHAR(255) NOT NULL,
- -- Value
- lc_value CLOB(16M) INLINE LENGTH 4096 NOT NULL
-);
-CREATE INDEX lc_lang_key
- ON l10n_cache (lc_lang, lc_key);
-
-
-
-CREATE TABLE msg_resource_links
-(
- mrl_resource VARCHAR(255) FOR BIT DATA NOT NULL,
- mrl_message VARCHAR(255) FOR BIT DATA NOT NULL
-);
-CREATE UNIQUE INDEX uq61_msg_resource_links
- ON msg_resource_links (mrl_message, mrl_resource);
--- All DB2 indexes DEFAULT to allowing reverse scans
-
-
-
-CREATE TABLE msg_resource
-(
- mr_resource VARCHAR(255) FOR BIT DATA NOT NULL,
- mr_lang VARCHAR(32) FOR BIT DATA NOT NULL,
- mr_blob CLOB(64K) INLINE LENGTH 4096 NOT NULL,
- mr_timestamp TIMESTAMP(3) NOT NULL
-);
-CREATE UNIQUE INDEX uq81_msg_resource
- ON msg_resource (mr_resource, mr_lang);
--- All DB2 indexes DEFAULT to allowing reverse scans
-
-
-
-CREATE TABLE module_deps (
- md_module VARCHAR(255) FOR BIT DATA NOT NULL,
- md_skin VARCHAR(32) FOR BIT DATA NOT NULL,
- md_deps CLOB(16M) INLINE LENGTH 4096 NOT NULL
-);
-CREATE UNIQUE INDEX uq96_module_deps
- ON module_deps (md_module, md_skin);
--- All DB2 indexes DEFAULT to allowing reverse scans
-
-
-
-CREATE TABLE iwlinks
-(
- iwl_from INTEGER NOT NULL,
- iwl_prefix VARCHAR(20) FOR BIT DATA NOT NULL,
- iwl_title VARCHAR(255) FOR BIT DATA NOT NULL
-);
-
-
-
---
--- Store information about newly uploaded files before they're
--- moved into the actual filestore
---
-CREATE TABLE uploadstash (
- us_id BIGINT NOT NULL
- PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (START WITH 1),
- -- the user who uploaded the file.
- us_user BIGINT NOT NULL,
- -- file key. this is how applications actually search for the file.
- -- this might go away, or become the primary key.
- us_key VARCHAR(255) NOT NULL,
- -- the original path
- us_orig_path VARCHAR(255) NOT NULL,
- -- the temporary path at which the file is actually stored
- us_path VARCHAR(255) NOT NULL,
- -- which type of upload the file came from (sometimes)
- us_source_type VARCHAR(50),
- -- the date/time on which the file was added
- us_timestamp TIMESTAMP(3) NOT NULL,
- us_status VARCHAR(50) NOT NULL,
- -- file properties from File::getPropsFromPath. these may prove unnecessary.
- --
- us_size BIGINT NOT NULL,
- -- this hash comes from File::sha1Base36(), and is 31 characters
- us_sha1 VARCHAR(31) NOT NULL,
- us_mime VARCHAR(255),
- -- Media type as defined by the MEDIATYPE_xxx constants, should duplicate definition in the image table
- us_media_type VARCHAR(30)
- CONSTRAINT my_constraint
- CHECK (
- us_media_type in (
- 'UNKNOWN', 'BITMAP', 'DRAWING', 'AUDIO', 'VIDEO', 'MULTIMEDIA',
- 'OFFICE', 'TEXT', 'EXECUTABLE', 'ARCHIVE'
- )
- ) DEFAULT NULL,
- -- image-specific properties
- us_image_width BIGINT,
- us_image_height BIGINT,
- us_image_bits INTEGER
-);
--- sometimes there's a delete for all of a user's stuff.
-CREATE INDEX us_user
- ON uploadstash (us_user);
--- pick out files by key, enforce key UNIQUEness
-CREATE UNIQUE INDEX us_key
- ON uploadstash (us_key);
--- the abandoned upload cleanup script needs this
-CREATE INDEX us_timestamp
- ON uploadstash (us_timestamp);
-
-
-
--- Stores the groups the user has once belonged to.
--- The user may still belong these groups. Check user_groups.
-CREATE TABLE user_former_groups (
- ufg_user BIGINT NOT NULL DEFAULT 0,
- ufg_group VARCHAR(16) FOR BIT DATA NOT NULL
-);
-CREATE UNIQUE INDEX ufg_user_group
- ON user_former_groups (ufg_user, ufg_group);
diff --git a/maintenance/importDump.php b/maintenance/importDump.php
index f51d7ad7..904b6247 100644
--- a/maintenance/importDump.php
+++ b/maintenance/importDump.php
@@ -32,13 +32,13 @@ require_once( __DIR__ . '/Maintenance.php' );
* @ingroup Maintenance
*/
class BackupReader extends Maintenance {
- var $reportingInterval = 100;
- var $pageCount = 0;
- var $revCount = 0;
- var $dryRun = false;
- var $uploads = false;
- var $imageBasePath = false;
- var $nsFilter = false;
+ public $reportingInterval = 100;
+ public $pageCount = 0;
+ public $revCount = 0;
+ public $dryRun = false;
+ public $uploads = false;
+ public $imageBasePath = false;
+ public $nsFilter = false;
function __construct() {
parent::__construct();
diff --git a/maintenance/importImages.inc b/maintenance/importImages.inc
index ac5d1443..2b3d5514 100644
--- a/maintenance/importImages.inc
+++ b/maintenance/importImages.inc
@@ -28,9 +28,10 @@
*
* @param $dir string Path to directory to search
* @param $exts Array of extensions to search for
+ * @param $recurse Bool Search subdirectories recursively
* @return mixed Array of filenames on success, or false on failure
*/
-function findFiles( $dir, $exts ) {
+function findFiles( $dir, $exts, $recurse = false ) {
if ( is_dir( $dir ) ) {
$dhl = opendir( $dir );
if ( $dhl ) {
@@ -38,8 +39,11 @@ function findFiles( $dir, $exts ) {
while ( ( $file = readdir( $dhl ) ) !== false ) {
if ( is_file( $dir . '/' . $file ) ) {
list( /* $name */, $ext ) = splitFilename( $dir . '/' . $file );
- if ( array_search( strtolower( $ext ), $exts ) !== false )
+ 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;
diff --git a/maintenance/importImages.php b/maintenance/importImages.php
index 8d92383d..782f502d 100644
--- a/maintenance/importImages.php
+++ b/maintenance/importImages.php
@@ -31,7 +31,10 @@
* @author Mij <mij@bitchx.it>
*/
-$optionsWithArgs = array( 'extensions', 'comment', 'comment-file', 'comment-ext', 'user', 'license', 'sleep', 'limit', 'from', 'source-wiki-url' );
+$optionsWithArgs = array(
+ 'extensions', 'comment', 'comment-file', 'comment-ext', 'summary', 'user',
+ 'license', 'sleep', 'limit', 'from', 'source-wiki-url', 'timestamp',
+);
require_once( __DIR__ . '/commandLine.inc' );
require_once( __DIR__ . '/importImages.inc' );
$processed = $added = $ignored = $skipped = $overwritten = $failed = 0;
@@ -61,7 +64,7 @@ $extensions = isset( $options['extensions'] )
: $wgFileExtensions;
# Search the path provided for candidates for import
-$files = findFiles( $dir, $extensions );
+$files = findFiles( $dir, $extensions, isset( $options['search-recursively'] ) );
# Initialise the user for this operation
$user = isset( $options['user'] )
@@ -98,6 +101,8 @@ if ( $limit ) {
$limit = (int)$limit;
}
+$timestamp = isset( $options['timestamp'] ) ? $options['timestamp'] : false;
+
# Get the upload comment. Provide a default one in case there's no comment given.
$comment = 'Importing image file';
@@ -112,6 +117,8 @@ if ( isset( $options['comment-file'] ) ) {
$commentExt = isset( $options['comment-ext'] ) ? $options['comment-ext'] : false;
+$summary = isset( $options['summary'] ) ? $options['summary'] : '';
+
# Get the license specifier
$license = isset( $options['license'] ) ? $options['license'] : '';
@@ -230,9 +237,14 @@ if ( $count > 0 ) {
}
}
+ $commentText = SpecialUpload::getInitialPageText( $commentText, $license );
+ if ( !$summary ) {
+ $summary = $commentText;
+ }
+
if ( isset( $options['dry'] ) ) {
echo( "done.\n" );
- } elseif ( $image->recordUpload( $archive->value, $commentText, $license ) ) {
+ } elseif ( $image->recordUpload2( $archive->value, $summary, $commentText, false, $timestamp ) ) {
# We're done!
echo( "done.\n" );
@@ -314,25 +326,28 @@ USAGE: php importImages.php [options] <dir>
<dir> : Path to the directory containing images to be imported
Options:
---extensions=<exts> Comma-separated list of allowable extensions, defaults to \$wgFileExtensions
---overwrite Overwrite existing images with the same name (default is to skip them)
---limit=<num> Limit the number of images to process. Ignored or skipped images are not counted.
---from=<name> Ignore all files until the one with the given name. Useful for resuming
- aborted imports. <name> should be the file's canonical database form.
---skip-dupes Skip images that were already uploaded under a different name (check SHA1)
---sleep=<sec> Sleep between files. Useful mostly for debugging.
---user=<username> Set username of uploader, default 'Maintenance script'
---check-userblock Check if the user got blocked during import.
---comment=<text> Set upload summary comment, default 'Importing image file'.
---comment-file=<file> Set upload summary comment the the content of <file>.
---comment-ext=<ext> Causes the comment for each file to be loaded from a file with the same name
- but the extension <ext>. If a global comment is also given, it is appended.
---license=<code> Use an optional license template
---dry Dry run, don't import anything
+--extensions=<exts> Comma-separated list of allowable extensions, defaults to \$wgFileExtensions
+--overwrite Overwrite existing images with the same name (default is to skip them)
+--limit=<num> Limit the number of images to process. Ignored or skipped images are not counted.
+--from=<name> Ignore all files until the one with the given name. Useful for resuming
+ aborted imports. <name> should be the file's canonical database form.
+--skip-dupes Skip images that were already uploaded under a different name (check SHA1)
+--search-recursively Search recursively for files in subdirectories
+--sleep=<sec> Sleep between files. Useful mostly for debugging.
+--user=<username> Set username of uploader, default 'Maintenance script'
+--check-userblock Check if the user got blocked during import.
+--comment=<text> Set file description, default 'Importing image file'.
+--comment-file=<file> Set description to the content of <file>.
+--comment-ext=<ext> Causes the description for each file to be loaded from a file with the same name
+ but the extension <ext>. If a global description is also given, it is appended.
+--license=<code> Use an optional license template
+--dry Dry run, don't import anything
--protect=<protect> Specify the protect value (autoconfirmed,sysop)
+--summary=<summary> Upload summary, description will be used if not provided
+--timestamp=<timestamp> Override upload time/date, all MediaWiki timestamp formats are accepted
--unprotect Unprotects all uploaded images
---source-wiki-url if specified, take User and Comment data for each imported file from this URL.
- For example, --source-wiki-url="http://en.wikipedia.org/"
+--source-wiki-url If specified, take User and Comment data for each imported file from this URL.
+ For example, --source-wiki-url="http://en.wikipedia.org/"
TEXT;
exit( 1 );
diff --git a/maintenance/importSiteScripts.php b/maintenance/importSiteScripts.php
index e369cb15..fabc6dc6 100644
--- a/maintenance/importSiteScripts.php
+++ b/maintenance/importSiteScripts.php
@@ -62,7 +62,8 @@ class ImportSiteScripts extends Maintenance {
$text = Http::get( $url );
$wikiPage = WikiPage::factory( $title );
- $wikiPage->doEdit( $text, "Importing from $url", 0, false, $user );
+ $content = ContentHandler::makeContent( $text, $wikiPage->getTitle() );
+ $wikiPage->doEditContent( $content, "Importing from $url", 0, false, $user );
}
}
diff --git a/maintenance/importTextFile.php b/maintenance/importTextFile.php
index adb50635..c04989c0 100644
--- a/maintenance/importTextFile.php
+++ b/maintenance/importTextFile.php
@@ -56,7 +56,8 @@ if ( count( $args ) < 1 || isset( $options['help'] ) ) {
echo( "\nPerforming edit..." );
$page = WikiPage::factory( $title );
- $page->doEdit( $text, $comment, $flags, false, $user );
+ $content = ContentHandler::makeContent( $text, $title );
+ $page->doEditContent( $content, $comment, $flags, false, $user );
echo( "done.\n" );
} else {
diff --git a/maintenance/initStats.php b/maintenance/initSiteStats.php
index 5d8b8866..19906592 100644
--- a/maintenance/initStats.php
+++ b/maintenance/initSiteStats.php
@@ -30,7 +30,7 @@ require_once( __DIR__ . '/Maintenance.php' );
*
* @ingroup Maintenance
*/
-class InitStats extends Maintenance {
+class InitSiteStats extends Maintenance {
public function __construct() {
parent::__construct();
$this->mDescription = "Re-initialise the site statistics tables";
@@ -84,5 +84,5 @@ class InitStats extends Maintenance {
}
}
-$maintClass = "InitStats";
+$maintClass = "InitSiteStats";
require_once( RUN_MAINTENANCE_IF_MAIN );
diff --git a/maintenance/install.php b/maintenance/install.php
index 762bb94f..935a2966 100644
--- a/maintenance/install.php
+++ b/maintenance/install.php
@@ -22,9 +22,8 @@
*/
if ( !function_exists( 'version_compare' ) || ( version_compare( phpversion(), '5.3.2' ) < 0 ) ) {
- echo "You are using PHP version " . phpversion() . " but MediaWiki needs PHP 5.3.2 or higher. ABORTING.\n" .
- "Check if you have a newer php executable with a different name, such as php5.\n";
- die( 1 );
+ require_once( dirname( __FILE__ ) . '/../includes/PHPVersionError.php' );
+ wfPHPVersionError( 'cli' );
}
define( 'MW_CONFIG_CALLBACK', 'Installer::overrideConfig' );
@@ -45,7 +44,8 @@ class CommandLineInstaller extends Maintenance {
$this->addArg( 'name', 'The name of the wiki', true);
$this->addArg( 'admin', 'The username of the wiki administrator (WikiSysop)', true );
- $this->addOption( 'pass', 'The password for the wiki administrator.', true, true );
+ $this->addOption( 'pass', 'The password for the wiki administrator.', false, true );
+ $this->addOption( 'passfile', 'An alternative way to provide pass option, as the contents of this file', false, true );
/* $this->addOption( 'email', 'The email for the wiki administrator', false, true ); */
$this->addOption( 'scriptpath', 'The relative path of the wiki in the web server (/wiki)', false, true );
@@ -77,6 +77,9 @@ class CommandLineInstaller extends Maintenance {
$dbpassfile = $this->getOption( 'dbpassfile', false );
if ( $dbpassfile !== false ) {
+ if ( $this->getOption( 'dbpass', false ) !== false ) {
+ $this->error( 'WARNING: You provide the options "dbpass" and "dbpassfile". The content of "dbpassfile" overwrites "dbpass".' );
+ }
wfSuppressWarnings();
$dbpass = file_get_contents( $dbpassfile );
wfRestoreWarnings();
@@ -86,6 +89,22 @@ class CommandLineInstaller extends Maintenance {
$this->mOptions['dbpass'] = trim( $dbpass, "\r\n" );
}
+ $passfile = $this->getOption( 'passfile', false );
+ if ( $passfile !== false ) {
+ if ( $this->getOption( 'pass', false ) !== false ) {
+ $this->error( 'WARNING: You provide the options "pass" and "passfile". The content of "passfile" overwrites "pass".' );
+ }
+ wfSuppressWarnings();
+ $pass = file_get_contents( $passfile );
+ wfRestoreWarnings();
+ if ( $pass === false ) {
+ $this->error( "Couldn't open $passfile", true );
+ }
+ $this->mOptions['pass'] = str_replace( array( "\n", "\r" ), "", $pass );
+ } elseif ( $this->getOption( 'pass', false ) === false ) {
+ $this->error( 'You need to provide the option "pass" or "passfile"', true );
+ }
+
$installer =
InstallerOverrides::getCliInstaller( $siteName, $adminName, $this->mOptions );
diff --git a/maintenance/jsduck/MetaTags.rb b/maintenance/jsduck/MetaTags.rb
new file mode 100644
index 00000000..84e40213
--- /dev/null
+++ b/maintenance/jsduck/MetaTags.rb
@@ -0,0 +1,53 @@
+# See also:
+# - https://github.com/senchalabs/jsduck/wiki/Tags
+# - https://github.com/senchalabs/jsduck/wiki/Custom-tags
+require 'jsduck/meta_tag'
+
+class ContextTag < JsDuck::MetaTag
+ def initialize
+ @name = 'context'
+ end
+
+ # @param tags All matches of this tag on one class.
+ def to_html(tags)
+ return '<h3 class="pa">Context</h3>' + render_long_context(tags.last)
+ end
+
+ def render_long_context(tag)
+ if tag =~ /\A([^\s]+)/m
+ name = $1
+ return format("`this` : {@link #{name}}")
+ end
+ end
+end
+
+class SeeTag < JsDuck::MetaTag
+ def initialize
+ @name = 'see'
+ @multiline = true
+ end
+
+ # @param tags All matches of this tag on one class.
+ def to_html(tags)
+ doc = []
+ doc << '<h3 class="pa">Related</h3>'
+ doc << [
+ '<ul>',
+ tags.map {|tag| render_long_see(tag) },
+ '</ul>',
+ ]
+ doc
+ end
+
+ def render_long_see(tag)
+ if tag =~ /\A([^\s]+)( .*)?\Z/m
+ name = $1
+ doc = $2 ? ': ' + $2 : ''
+ return [
+ '<li>',
+ format("{@link #{name}} #{doc}"),
+ '</li>'
+ ]
+ end
+ end
+end
diff --git a/maintenance/jsduck/categories.json b/maintenance/jsduck/categories.json
new file mode 100644
index 00000000..4a8ba8c3
--- /dev/null
+++ b/maintenance/jsduck/categories.json
@@ -0,0 +1,54 @@
+[
+ {
+ "name": "MediaWiki",
+ "groups": [
+ {
+ "name": "Base",
+ "classes": [
+ "mw",
+ "mw.Map",
+ "mw.Message",
+ "mw.loader",
+ "mw.html",
+ "mw.html.Cdata",
+ "mw.html.Raw"
+ ]
+ },
+ {
+ "name": "General",
+ "classes": [
+ "mw.Title",
+ "mw.notification",
+ "mw.util",
+ "mw.plugin.notify"
+ ]
+ },
+ {
+ "name": "API",
+ "classes": ["mw.Api*"]
+ }
+ ]
+ },
+ {
+ "name": "jQuery",
+ "groups": [
+ {
+ "name": "Core",
+ "classes": ["jQuery", "jQuery.Event", "jQuery.Promise", "jQuery.Deferred", "jQuery.jqXHR"]
+ },
+ {
+ "name": "Plugins",
+ "classes": ["jQuery.plugin.*"]
+ }
+ ]
+ },
+ {
+ "name": "Misc",
+ "groups": [
+ {
+ "name": "Native",
+ "classes": ["Array", "Boolean", "Date", "Function", "Number", "Object", "RegExp", "String"]
+ }
+ ]
+ }
+]
diff --git a/maintenance/jsduck/config.json b/maintenance/jsduck/config.json
new file mode 100644
index 00000000..c4705d8f
--- /dev/null
+++ b/maintenance/jsduck/config.json
@@ -0,0 +1,18 @@
+{
+ "--title": "MediaWiki Code Documentation",
+ "--categories": "./categories.json",
+ "--meta-tags": "./MetaTags.rb",
+ "--warnings": ["-no_doc"],
+ "--builtin-classes": true,
+ "--output": "../../docs/js",
+ "--": [
+ "./external.js",
+ "../../resources/mediawiki/mediawiki.js",
+ "../../resources/mediawiki/mediawiki.util.js",
+ "../../resources/mediawiki/mediawiki.Title.js",
+ "../../resources/mediawiki/mediawiki.notify.js",
+ "../../resources/mediawiki/mediawiki.notification.js",
+ "../../resources/mediawiki.api",
+ "../../resources/jquery/jquery.localize.js"
+ ]
+} \ No newline at end of file
diff --git a/maintenance/jsduck/eg-iframe.html b/maintenance/jsduck/eg-iframe.html
new file mode 100644
index 00000000..f53b4044
--- /dev/null
+++ b/maintenance/jsduck/eg-iframe.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>MediaWiki Examples</title>
+ <script>
+ function loadInlineExample(code, options, callback) {
+ try {
+ document.body.innerHTML = '';
+ eval(code);
+ callback && callback(true);
+ } catch (e) {
+ document.body.innerHTML = document.createTextNode(e);
+ callback && callback(false, e);
+ }
+ }
+ </script>
+</head>
+<body></body>
+</html>
diff --git a/maintenance/jsduck/external.js b/maintenance/jsduck/external.js
new file mode 100644
index 00000000..8ab102f4
--- /dev/null
+++ b/maintenance/jsduck/external.js
@@ -0,0 +1,26 @@
+/**
+ * @class jQuery
+ */
+
+/**
+ * @method ajax
+ * @return {jqXHR}
+ */
+
+/**
+ * @class jQuery.Event
+ */
+
+/**
+ * @class jQuery.Promise
+ */
+
+/**
+ * @class jQuery.Deferred
+ * @mixins jQuery.Promise
+ */
+
+/**
+ * @class jQuery.jqXHR
+ * @alternateClassName jqXHR
+ */
diff --git a/maintenance/jsparse.php b/maintenance/jsparse.php
index ceafc390..1a2e121c 100644
--- a/maintenance/jsparse.php
+++ b/maintenance/jsparse.php
@@ -29,7 +29,7 @@ require_once( __DIR__ . '/Maintenance.php' );
* @ingroup Maintenance
*/
class JSParseHelper extends Maintenance {
- var $errs = 0;
+ public $errs = 0;
public function __construct() {
parent::__construct();
diff --git a/maintenance/lag.php b/maintenance/lag.php
index 3ad0864f..3df11692 100644
--- a/maintenance/lag.php
+++ b/maintenance/lag.php
@@ -51,7 +51,7 @@ class DatabaseLag extends Maintenance {
unset( $lags[0] );
echo gmdate( 'H:i:s' ) . ' ';
foreach ( $lags as $lag ) {
- printf( "%-12s " , $lag === false ? 'false' : $lag );
+ printf( "%-12s ", $lag === false ? 'false' : $lag );
}
echo "\n";
sleep( 5 );
@@ -61,7 +61,7 @@ class DatabaseLag extends Maintenance {
$lags = $lb->getLagTimes();
foreach ( $lags as $i => $lag ) {
$name = $lb->getServerName( $i );
- $this->output( sprintf( "%-20s %s\n" , $name, $lag === false ? 'false' : $lag ) );
+ $this->output( sprintf( "%-20s %s\n", $name, $lag === false ? 'false' : $lag ) );
}
}
}
diff --git a/maintenance/language/StatOutputs.php b/maintenance/language/StatOutputs.php
index d77029e7..20fb4778 100644
--- a/maintenance/language/StatOutputs.php
+++ b/maintenance/language/StatOutputs.php
@@ -60,7 +60,7 @@ class wikiStatsOutput extends statsOutput {
echo ', as well as the following languages that are not intended for system message translations, usually because they redirect to other language codes: ' . implode( ', ', $dummyCodes );
}
echo ".\n\n"; # dot to end sentence
- echo '{| class="sortable wikitable" border="2" cellpadding="4" cellspacing="0" style="background-color: #F9F9F9; border: 1px #AAAAAA solid; border-collapse: collapse; clear:both;" width="100%"' . "\n";
+ echo '{| class="sortable wikitable" border="2" style="background-color: #F9F9F9; border: 1px #AAAAAA solid; border-collapse: collapse; clear:both; width:100%;"' . "\n";
}
function footer() {
echo "|}\n";
@@ -96,7 +96,7 @@ class wikiStatsOutput extends statsOutput {
$color = $red . $green . $blue;
$percent = parent::formatPercent( $subset, $total, $revert, $accuracy );
- return 'bgcolor="#' . $color . '"|' . $percent;
+ return 'style="background-color:#' . $color . ';"|' . $percent;
}
}
diff --git a/maintenance/language/checkLanguage.inc b/maintenance/language/checkLanguage.inc
index 11b00e14..1860f4a5 100644
--- a/maintenance/language/checkLanguage.inc
+++ b/maintenance/language/checkLanguage.inc
@@ -43,7 +43,7 @@ class CheckLanguageCLI {
* Constructor.
* @param $options array Options for script.
*/
- public function __construct( Array $options ) {
+ public function __construct( array $options ) {
if ( isset( $options['help'] ) ) {
echo $this->help();
exit(1);
@@ -305,6 +305,7 @@ ENDS;
/**
* Check a language.
* @param $code string The language code.
+ * @throws MWException
* @return array The results.
*/
protected function checkLanguage( $code ) {
@@ -484,7 +485,7 @@ class CheckExtensionsCLI extends CheckLanguageCLI {
* @param $options array Options for script.
* @param $extension string The extension name (or names).
*/
- public function __construct( Array $options, $extension ) {
+ public function __construct( array $options, $extension ) {
if ( isset( $options['help'] ) ) {
echo $this->help();
exit(1);
@@ -641,6 +642,7 @@ ENDS;
/**
* Check a language and show the results.
* @param $code string The language code.
+ * @throws MWException
*/
protected function checkLanguage( $code ) {
foreach( $this->extensions as $extension ) {
diff --git a/maintenance/language/generateCollationData.php b/maintenance/language/generateCollationData.php
index e34d9a13..12823c0c 100644
--- a/maintenance/language/generateCollationData.php
+++ b/maintenance/language/generateCollationData.php
@@ -30,19 +30,19 @@ require_once( __DIR__ .'/../Maintenance.php' );
*/
class GenerateCollationData extends Maintenance {
/** The directory with source data files in it */
- var $dataDir;
+ public $dataDir;
/** The primary weights, indexed by codepoint */
- var $weights;
+ public $weights;
/**
* A hashtable keyed by codepoint, where presence indicates that a character
* has a decomposition mapping. This makes it non-preferred for group header
* selection.
*/
- var $mappedChars;
+ public $mappedChars;
- var $debugOutFile;
+ public $debugOutFile;
/**
* Important tertiary weights from UTS #10 section 7.2
@@ -61,18 +61,80 @@ class GenerateCollationData extends Maintenance {
public function execute() {
$this->dataDir = $this->getOption( 'data-dir', '.' );
- if ( !file_exists( "{$this->dataDir}/allkeys.txt" ) ) {
- $this->error( "Unable to find allkeys.txt. Please download it from " .
- "http://www.unicode.org/Public/UCA/latest/allkeys.txt and specify " .
- "its location with --data-dir=<DIR>" );
- exit( 1 );
- }
- if ( !file_exists( "{$this->dataDir}/ucd.all.grouped.xml" ) ) {
- $this->error( "Unable to find ucd.all.grouped.xml. Please download it " .
- "from http://www.unicode.org/Public/6.0.0/ucdxml/ucd.all.grouped.zip " .
- "and specify its location with --data-dir=<DIR>" );
+
+ $allkeysPresent = file_exists( "{$this->dataDir}/allkeys.txt" );
+ $ucdallPresent = file_exists( "{$this->dataDir}/ucd.all.grouped.xml" );
+
+ // As of January 2013, these links work for all versions of Unicode
+ // between 5.1 and 6.2, inclusive.
+ $allkeysURL = "http://www.unicode.org/Public/UCA/<Unicode version>/allkeys.txt";
+ $ucdallURL = "http://www.unicode.org/Public/<Unicode version>/ucdxml/ucd.all.grouped.zip";
+
+ if ( !$allkeysPresent || !$ucdallPresent ) {
+ $icuVersion = IcuCollation::getICUVersion();
+ $unicodeVersion = IcuCollation::getUnicodeVersionForICU();
+
+ $error = "";
+
+ if ( !$allkeysPresent ) {
+ $error .= "Unable to find allkeys.txt. "
+ . "Download it and specify its location with --data-dir=<DIR>. "
+ . "\n\n";
+ }
+ if ( !$ucdallPresent ) {
+ $error .= "Unable to find ucd.all.grouped.xml. "
+ . "Download it, unzip, and specify its location with --data-dir=<DIR>. "
+ . "\n\n";
+ }
+
+ $versionKnown = false;
+ if ( !$icuVersion ) {
+ // Unknown version - either very old intl,
+ // or PHP < 5.3.7 which does not expose this information
+ $error .= "As MediaWiki could not determine the version of ICU library used by your PHP's "
+ . "intl extension it can't suggest which file version to download. "
+ . "This can be caused by running a very old version of intl or PHP < 5.3.7. "
+ . "If you are sure everything is all right, find out the ICU version "
+ . "by running phpinfo(), check what is the Unicode version it is using "
+ . "at http://site.icu-project.org/download, then try finding appropriate data file(s) at:";
+ } elseif ( version_compare( $icuVersion, "4.0", "<" ) ) {
+ // Extra old version
+ $error .= "You are using outdated version of ICU ($icuVersion), intended for "
+ . ( $unicodeVersion ? "Unicode $unicodeVersion" : "an unknown version of Unicode" )
+ . "; this file might not be avalaible for it, and it's not supported by MediaWiki. "
+ ." You are on your own; consider upgrading PHP's intl extension or try "
+ . "one of the files available at:";
+ } elseif ( version_compare( $icuVersion, "51.0", ">=" ) ) {
+ // Extra recent version
+ $error .= "You are using ICU $icuVersion, released after this script was last updated. "
+ . "Check what is the Unicode version it is using at http://site.icu-project.org/download . "
+ . "It can't be guaranteed everything will work, but appropriate file(s) should "
+ . "be available at:";
+ } else {
+ // ICU 4.0 to 50.x
+ $versionKnown = true;
+ $error .= "You are using ICU $icuVersion, intended for "
+ . ( $unicodeVersion ? "Unicode $unicodeVersion" : "an unknown version of Unicode" )
+ . ". Appropriate file(s) should be available at:";
+ }
+ $error .= "\n";
+
+ if ( $versionKnown && $unicodeVersion ) {
+ $allkeysURL = str_replace( "<Unicode version>", "$unicodeVersion.0", $allkeysURL );
+ $ucdallURL = str_replace( "<Unicode version>", "$unicodeVersion.0", $ucdallURL );
+ }
+
+ if ( !$allkeysPresent ) {
+ $error .= "* $allkeysURL\n";
+ }
+ if ( !$ucdallPresent ) {
+ $error .= "* $ucdallURL\n";
+ }
+
+ $this->error( $error );
exit( 1 );
}
+
$debugOutFileName = $this->getOption( 'debug-output' );
if ( $debugOutFileName ) {
$this->debugOutFile = fopen( $debugOutFileName, 'w' );
@@ -285,12 +347,12 @@ class GenerateCollationData extends Maintenance {
}
class UcdXmlReader {
- var $fileName;
- var $callback;
- var $groupAttrs;
- var $xml;
- var $blocks = array();
- var $currentBlock;
+ public $fileName;
+ public $callback;
+ public $groupAttrs;
+ public $xml;
+ public $blocks = array();
+ public $currentBlock;
function __construct( $fileName ) {
$this->fileName = $fileName;
diff --git a/maintenance/language/generateNormalizerData.php b/maintenance/language/generateNormalizerData.php
index 54dfa39a..c03162c4 100644
--- a/maintenance/language/generateNormalizerData.php
+++ b/maintenance/language/generateNormalizerData.php
@@ -21,10 +21,10 @@
* @ingroup MaintenanceLanguage
*/
-require_once( __DIR__ . '/../Maintenance.php' );
-
require_once( __DIR__ . '/../../includes/normal/UtfNormalUtil.php' );
+require_once( __DIR__ . '/../Maintenance.php' );
+
/**
* Generates normalizer data files for Arabic and Malayalam.
* For NFC see includes/normal.
@@ -32,7 +32,7 @@ require_once( __DIR__ . '/../../includes/normal/UtfNormalUtil.php' );
* @ingroup MaintenanceLanguage
*/
class GenerateNormalizerData extends Maintenance {
- var $dataFile;
+ public $dataFile;
public function __construct() {
parent::__construct();
diff --git a/maintenance/language/langmemusage.php b/maintenance/language/langmemusage.php
index 2323638e..ad29efb2 100644
--- a/maintenance/language/langmemusage.php
+++ b/maintenance/language/langmemusage.php
@@ -1,7 +1,6 @@
<?php
/**
- * Dumb program that tries to get the memory usage
- * for each language file.
+ * Dumb program that tries to get the memory usage for each language file.
*
* 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
@@ -18,6 +17,7 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* http://www.gnu.org/copyleft/gpl.html
*
+ * @file
* @ingroup MaintenanceLanguage
*/
@@ -25,6 +25,11 @@
require_once( __DIR__ . '/../Maintenance.php' );
require_once( __DIR__ . '/languages.inc' );
+/**
+ * Maintenance script that tries to get the memory usage for each language file.
+ *
+ * @ingroup MaintenanceLanguage
+ */
class LangMemUsage extends Maintenance {
public function __construct() {
@@ -41,7 +46,7 @@ class LangMemUsage extends Maintenance {
$memlast = $memstart = memory_get_usage();
$this->output( "Base memory usage: $memstart\n" );
-
+
foreach ( $langtool->getLanguages() as $langcode ) {
Language::factory( $langcode );
$memstep = memory_get_usage();
diff --git a/maintenance/language/languages.inc b/maintenance/language/languages.inc
index b76f921d..dcd9b9b4 100644
--- a/maintenance/language/languages.inc
+++ b/maintenance/language/languages.inc
@@ -508,7 +508,7 @@ class languages {
if ( isset( $messages[$key] ) ) {
- $messages[$key] = implode( $messages[$key],", " );
+ $messages[$key] = implode( $messages[$key], ", " );
}
}
return $messages;
@@ -581,14 +581,14 @@ class languages {
# Check default namespace name
if( isset( $this->mNamespaceNames[$code][NS_PROJECT_TALK] ) ) {
$default = $this->mNamespaceNames[$code][NS_PROJECT_TALK];
- if ( strpos( $default, '$1' ) === FALSE ) {
+ if ( strpos( $default, '$1' ) === false ) {
$namespaces[$default] = 'default';
}
}
# Check namespace aliases
foreach( $this->mNamespaceAliases[$code] as $key => $value ) {
- if ( $value == NS_PROJECT_TALK && strpos( $key, '$1' ) === FALSE ) {
+ if ( $value == NS_PROJECT_TALK && strpos( $key, '$1' ) === false ) {
$namespaces[$key] = '';
}
}
@@ -739,9 +739,8 @@ class extensionLanguages extends languages {
function __construct( MessageGroup $group ) {
$this->mMessageGroup = $group;
- $bools = $this->mMessageGroup->getBools();
- $this->mIgnoredMessages = $bools['ignored'];
- $this->mOptionalMessages = $bools['optional'];
+ $this->mIgnoredMessages = $this->mMessageGroup->getIgnored();
+ $this->mOptionalMessages = $this->mMessageGroup->getOptional();
}
/**
diff --git a/maintenance/language/messageTypes.inc b/maintenance/language/messageTypes.inc
index ce1dbb9b..66cc1dcc 100644
--- a/maintenance/language/messageTypes.inc
+++ b/maintenance/language/messageTypes.inc
@@ -181,6 +181,7 @@ $wgIgnoredMessages = array(
'deadendpages-summary',
'protectedpages-summary',
'disambiguations-summary',
+ 'pageswithprop-summary',
'doubleredirects-summary',
'lonelypages-summary',
'unusedtemplates-summary',
@@ -214,10 +215,11 @@ $wgIgnoredMessages = array(
'1movedto2',
'1movedto2_redir',
'move-redirect-suppressed',
- // 'newuserlog-byemail',
'newuserlog-create-entry',
'newuserlog-create2-entry',
'newuserlog-autocreate-entry',
+ 'rightslogentry',
+ 'rightslogentry-autopromote',
'suppressedarticle',
'deletedarticle',
// 'uploadedimage',
@@ -365,6 +367,7 @@ $wgOptionalMessages = array(
'exif-maxaperturevalue-value',
'exif-subjectnewscode-value',
'booksources-isbn',
+ 'protect-summary-desc',
'sp-contributions-explain',
'sorbs',
'video-dims',
@@ -467,6 +470,7 @@ $wgOptionalMessages = array(
'backlinksubtitle',
'prefs-registration-date-time',
'prefs-memberingroups-type',
+ 'userrights-groupsmember-type',
'shared-repo-name-wikimediacommons',
'usermessage-template',
'filepage.css',
@@ -479,6 +483,8 @@ $wgOptionalMessages = array(
'categoryviewer-pagedlinks',
'undelete-revisionrow',
'pageinfo-redirects-value',
+ 'created', // @deprecated. Remove in MediaWiki 1.23.
+ 'changed', // @deprecated. Remove in MediaWiki 1.23.
);
/** EXIF messages, which may be set as optional in several checks, but are generally mandatory */
diff --git a/maintenance/language/messages.inc b/maintenance/language/messages.inc
index baa0c96e..c2d5847d 100644
--- a/maintenance/language/messages.inc
+++ b/maintenance/language/messages.inc
@@ -167,6 +167,7 @@ $wgMessageStructure = array(
'newwindow',
'cancel',
'moredotdotdot',
+ 'morenotlisted',
'mypage',
'mytalk',
'anontalk',
@@ -178,7 +179,6 @@ $wgMessageStructure = array(
'qbbrowse',
'qbedit',
'qbpageoptions',
- 'qbpageinfo',
'qbmyoptions',
'qbspecialpages',
'faq',
@@ -204,6 +204,7 @@ $wgMessageStructure = array(
'variants',
),
'miscellaneous2' => array(
+ 'navigation-heading',
'errorpagetitle',
'returnto',
'tagline',
@@ -426,7 +427,8 @@ $wgMessageStructure = array(
),
'login' => array(
'logouttext',
- 'welcomecreation',
+ 'welcomeuser',
+ 'welcomecreation-msg',
'yourname',
'yourpassword',
'yourpasswordagain',
@@ -512,6 +514,7 @@ $wgMessageStructure = array(
'php-mail-error',
'php-mail-error-unknown',
'user-mail-no-addy',
+ 'user-mail-no-body',
),
'resetpass' => array(
'resetpass',
@@ -529,6 +532,7 @@ $wgMessageStructure = array(
'resetpass-submit-cancel',
'resetpass-wrong-oldpass',
'resetpass-temp-password',
+ 'resetpass-abort-generic',
),
'passwordreset' => array(
'passwordreset',
@@ -558,6 +562,7 @@ $wgMessageStructure = array(
'changeemail-oldemail',
'changeemail-newemail',
'changeemail-none',
+ 'changeemail-password',
'changeemail-submit',
'changeemail-cancel',
),
@@ -670,7 +675,6 @@ $wgMessageStructure = array(
'hiddencategories',
'edittools',
'edittools-upload',
- 'nocreatetitle',
'nocreatetext',
'nocreate-loggedin',
'sectioneditnotsupported-title',
@@ -689,6 +693,15 @@ $wgMessageStructure = array(
'addsection-preload',
'addsection-editintro',
'defaultmessagetext',
+ 'content-failed-to-parse',
+ 'invalid-content-data',
+ 'content-not-allowed-here',
+ ),
+ 'contentmodels' => array(
+ 'content-model-wikitext',
+ 'content-model-text',
+ 'content-model-javascript',
+ 'content-model-css',
),
'parserwarnings' => array(
'expensive-parserfunction-warning',
@@ -1079,6 +1092,7 @@ $wgMessageStructure = array(
'saveusergroups',
'userrights-groupsmember',
'userrights-groupsmember-auto',
+ 'userrights-groupsmember-type',
'userrights-groups-help',
'userrights-reason',
'userrights-no-interwiki',
@@ -1177,12 +1191,13 @@ $wgMessageStructure = array(
'right-sendemail',
'right-passwordreset',
),
+ 'newuserlog' => array(
+ 'newuserlogpage',
+ 'newuserlogpagetext',
+ ),
'rightslog' => array(
'rightslog',
'rightslogtext',
- 'rightslogentry',
- 'rightslogentry-autopromote',
- 'rightsnone',
),
'action' => array(
'action-read',
@@ -1387,6 +1402,7 @@ $wgMessageStructure = array(
'backend-fail-notsame',
'backend-fail-invalidpath',
'backend-fail-delete',
+ 'backend-fail-describe',
'backend-fail-alreadyexists',
'backend-fail-store',
'backend-fail-copy',
@@ -1622,6 +1638,14 @@ $wgMessageStructure = array(
'disambiguationspage',
'disambiguations-text',
),
+ 'pageswithprop' => array(
+ 'pageswithprop',
+ 'pageswithprop-summary',
+ 'pageswithprop-legend',
+ 'pageswithprop-text',
+ 'pageswithprop-prop',
+ 'pageswithprop-submit',
+ ),
'doubleredirects' => array(
'doubleredirects',
'doubleredirects-summary',
@@ -1833,10 +1857,6 @@ $wgMessageStructure = array(
'activeusers-submit',
'activeusers-noresult',
),
- 'newuserlog' => array(
- 'newuserlogpage',
- 'newuserlogpagetext',
- ),
'listgrouprights' => array(
'listgrouprights',
'listgrouprights-summary',
@@ -1934,15 +1954,23 @@ $wgMessageStructure = array(
'enotif' => array(
'enotif_mailer',
'enotif_reset',
- 'enotif_newpagetext',
'enotif_impersonal_salutation',
- 'changed',
- 'created',
- 'enotif_subject',
+ 'enotif_subject_deleted',
+ 'enotif_subject_created',
+ 'enotif_subject_moved',
+ 'enotif_subject_restored',
+ 'enotif_subject_changed',
+ 'enotif_body_intro_deleted',
+ 'enotif_body_intro_created',
+ 'enotif_body_intro_moved',
+ 'enotif_body_intro_restored',
+ 'enotif_body_intro_changed',
'enotif_lastvisited',
'enotif_lastdiff',
'enotif_anon_editor',
'enotif_body',
+ 'created',
+ 'changed',
),
'delete' => array(
'deletepage',
@@ -2000,6 +2028,8 @@ $wgMessageStructure = array(
'prot_1movedto2',
'protect-badnamespace-title',
'protect-badnamespace-text',
+ 'protect-norestrictiontypes-text',
+ 'protect-norestrictiontypes-title',
'protect-legend',
'protectcomment',
'protectexpiry',
@@ -2015,6 +2045,7 @@ $wgMessageStructure = array(
'protect-fallback',
'protect-level-autoconfirmed',
'protect-level-sysop',
+ 'protect-summary-desc',
'protect-summary-cascade',
'protect-expiring',
'protect-expiring-local',
@@ -2335,6 +2366,7 @@ $wgMessageStructure = array(
'immobile-target-namespace-iw',
'immobile-source-page',
'immobile-target-page',
+ 'bad-target-model',
'immobile_namespace',
'imagenocrossnamespace',
'nonfile-cannot-move-to-file',
@@ -2436,6 +2468,7 @@ $wgMessageStructure = array(
'import-error-interwiki',
'import-error-special',
'import-error-invalid',
+ 'import-error-unserialize',
'import-options-wrong',
'import-rootpage-invalid',
'import-rootpage-nosubpage',
@@ -2451,7 +2484,6 @@ $wgMessageStructure = array(
'javaccripttest' => array(
'javascripttest',
'javascripttest-backlink',
- 'javascripttest-disabled',
'javascripttest-title',
'javascripttest-pagetext-noframework',
'javascripttest-pagetext-unknownframework',
@@ -2673,11 +2705,13 @@ $wgMessageStructure = array(
'pageinfo-default-sort',
'pageinfo-length',
'pageinfo-article-id',
+ 'pageinfo-language',
'pageinfo-robot-policy',
'pageinfo-robot-index',
'pageinfo-robot-noindex',
'pageinfo-views',
'pageinfo-watchers',
+ 'pageinfo-few-watchers',
'pageinfo-redirects-name',
'pageinfo-redirects-value',
'pageinfo-subpages-name',
@@ -2693,7 +2727,20 @@ $wgMessageStructure = array(
'pageinfo-magic-words',
'pageinfo-hidden-categories',
'pageinfo-templates',
+ 'pageinfo-transclusions',
'pageinfo-footer',
+ 'pageinfo-toolboxlink',
+ 'pageinfo-redirectsto',
+ 'pageinfo-redirectsto-info',
+ 'pageinfo-contentpage',
+ 'pageinfo-contentpage-yes',
+ 'pageinfo-protect-cascading',
+ 'pageinfo-protect-cascading-yes',
+ 'pageinfo-protect-cascading-from',
+ 'pageinfo-category-info',
+ 'pageinfo-category-pages',
+ 'pageinfo-category-subcats',
+ 'pageinfo-category-files'
),
'skin' => array(
'skinname-standard',
@@ -2717,6 +2764,8 @@ $wgMessageStructure = array(
'markedaspatrollederror',
'markedaspatrollederrortext',
'markedaspatrollederror-noautopatrol',
+ 'markedaspatrollednotify',
+ 'markedaspatrollederrornotify',
),
'patrol-log' => array(
'patrol-log-page',
@@ -2748,6 +2797,7 @@ $wgMessageStructure = array(
'file-nohires',
'svg-long-desc',
'svg-long-desc-animated',
+ 'svg-long-error',
'show-big-image',
'show-big-image-preview',
'show-big-image-other',
@@ -2782,7 +2832,10 @@ $wgMessageStructure = array(
'minutes',
'hours',
'days',
+ 'months',
+ 'years',
'ago',
+ 'just-now',
),
'badimagelist' => array(
'bad_image_list',
@@ -3343,6 +3396,7 @@ $wgMessageStructure = array(
'scarytransclusion' => array(
'scarytranscludedisabled',
'scarytranscludefailed',
+ 'scarytranscludefailed-httpstatus',
'scarytranscludetoolong',
),
'deleteconflict' => array(
@@ -3552,6 +3606,7 @@ $wgMessageStructure = array(
'version-license',
'version-poweredby-credits',
'version-poweredby-others',
+ 'version-credits-summary',
'version-license-info',
'version-software',
'version-software-product',
@@ -3690,8 +3745,12 @@ $wgMessageStructure = array(
'logentry-newusers-newusers',
'logentry-newusers-create',
'logentry-newusers-create2',
+ 'logentry-newusers-byemail',
'logentry-newusers-autocreate',
- 'newuserlog-byemail',
+ 'logentry-rights-rights',
+ 'logentry-rights-rights-legacy',
+ 'logentry-rights-autopromote',
+ 'rightsnone',
),
'logging-irc' => array(
'revdelete-logentry',
@@ -3712,7 +3771,6 @@ $wgMessageStructure = array(
'1movedto2',
'1movedto2_redir',
'move-redirect-suppressed',
- // 'newuserlog-byemail',
'newuserlog-create-entry',
'newuserlog-create2-entry',
'newuserlog-autocreate-entry',
@@ -3720,6 +3778,8 @@ $wgMessageStructure = array(
'deletedarticle',
// 'uploadedimage',
// 'overwroteimage',
+ 'rightslogentry',
+ 'rightslogentry-autopromote',
),
'feedback' => array(
'feedback-bugornote',
@@ -3772,6 +3832,7 @@ $wgMessageStructure = array(
'api-error-ok-but-empty',
'api-error-overwrite',
'api-error-stashfailed',
+ 'api-error-publishfailed',
'api-error-timeout',
'api-error-unclassified',
'api-error-unknown-code',
@@ -3792,13 +3853,16 @@ $wgMessageStructure = array(
'duration-centuries',
'duration-millennia'
),
+ 'rotation' => array(
+ 'rotate-comment',
+ ),
);
/** Comments for each block */
$wgBlockComments = array(
'sidebar' => "The sidebar for MonoBook is generated from this message, lines that do not
begin with * or ** are discarded, furthermore lines that do begin with ** and
-do not contain | are also discarded, but do not depend on this behaviour for
+do not contain | are also discarded, but do not depend on this behavior for
future releases. Also note that since each list value is wrapped in a unique
XHTML id it should only appear once and include characters that are legal
XHTML id names.",
@@ -3829,6 +3893,7 @@ XHTML id names.",
'toolbar' => 'Edit page toolbar',
'edit' => 'Edit pages',
'parserwarnings' => 'Parser/template warnings',
+ 'contentmodels' => 'Content models',
'undo' => '"Undo" feature',
'cantcreateaccount' => 'Account creation failure',
'history' => 'History pages',
@@ -3875,6 +3940,7 @@ XHTML id names.",
'randomredirect' => 'Random redirect',
'statistics' => 'Statistics',
'disambiguations' => '',
+ 'pageswithprop' => '',
'doubleredirects' => '',
'brokenredirects' => '',
'withoutinterwiki' => '',
@@ -4031,4 +4097,5 @@ Variants for Chinese language",
'apierrors' => 'API errors',
'duration' => 'Durations',
'cachedspecial' => 'SpecialCachedPage',
+ 'rotation' => 'Image rotation',
);
diff --git a/maintenance/language/validate.php b/maintenance/language/validate.php
index 751e744d..4f00496f 100644
--- a/maintenance/language/validate.php
+++ b/maintenance/language/validate.php
@@ -21,6 +21,10 @@
* @ingroup MaintenanceLanguage
*/
+if ( PHP_SAPI != 'cli' ) {
+ die( "Run me from the command line please.\n" );
+}
+
if ( !isset( $argv[1] ) ) {
print "Usage: php {$argv[0]} <filename>\n";
exit( 1 );
diff --git a/maintenance/language/zhtable/Makefile b/maintenance/language/zhtable/Makefile
new file mode 100644
index 00000000..9d3637fc
--- /dev/null
+++ b/maintenance/language/zhtable/Makefile
@@ -0,0 +1,2 @@
+../../../includes/ZhConversion.php: Makefile.py $(wildcard *.manual)
+ ./Makefile.py
diff --git a/maintenance/language/zhtable/Makefile.py b/maintenance/language/zhtable/Makefile.py
new file mode 100644
index 00000000..7e197945
--- /dev/null
+++ b/maintenance/language/zhtable/Makefile.py
@@ -0,0 +1,391 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# @author Philip
+import tarfile as tf
+import zipfile as zf
+import os, re, shutil, sys, platform
+
+pyversion = platform.python_version()
+islinux = platform.system().lower() == 'linux'
+
+if pyversion[:3] in ['2.6', '2.7']:
+ import urllib as urllib_request
+ import codecs
+ open = codecs.open
+ _unichr = unichr
+ if sys.maxunicode < 0x10000:
+ def unichr(i):
+ if i < 0x10000:
+ return _unichr(i)
+ else:
+ return _unichr( 0xD7C0 + ( i>>10 ) ) + _unichr( 0xDC00 + ( i & 0x3FF ) )
+elif pyversion[:2] == '3.':
+ import urllib.request as urllib_request
+ unichr = chr
+
+def unichr2( *args ):
+ return [unichr( int( i.split('<')[0][2:], 16 ) ) for i in args]
+
+def unichr3( *args ):
+ return [unichr( int( i[2:7], 16 ) ) for i in args if i[2:7]]
+
+# DEFINE
+UNIHAN_VER = '6.2.0'
+SF_MIRROR = 'dfn'
+SCIM_TABLES_VER = '0.5.11'
+SCIM_PINYIN_VER = '0.5.92'
+LIBTABE_VER = '0.2.3'
+# END OF DEFINE
+
+def download( url, dest ):
+ if os.path.isfile( dest ):
+ print( 'File %s is up to date.' % dest )
+ return
+ global islinux
+ if islinux:
+ # we use wget instead urlretrieve under Linux,
+ # because wget could display details like download progress
+ os.system( 'wget %s -O %s' % ( url, dest ) )
+ else:
+ print( 'Downloading from [%s] ...' % url )
+ urllib_request.urlretrieve( url, dest )
+ print( 'Download complete.\n' )
+ return
+
+def uncompress( fp, member, encoding = 'U8' ):
+ name = member.rsplit( '/', 1 )[-1]
+ print( 'Extracting %s ...' % name )
+ fp.extract( member )
+ shutil.move( member, name )
+ if '/' in member:
+ shutil.rmtree( member.split( '/', 1 )[0] )
+ return open( name, 'rb', encoding, 'ignore' )
+
+unzip = lambda path, member, encoding = 'U8': \
+ uncompress( zf.ZipFile( path ), member, encoding )
+
+untargz = lambda path, member, encoding = 'U8': \
+ uncompress( tf.open( path, 'r:gz' ), member, encoding )
+
+def parserCore( fp, pos, beginmark = None, endmark = None ):
+ if beginmark and endmark:
+ start = False
+ else: start = True
+ mlist = set()
+ for line in fp:
+ if beginmark and line.startswith( beginmark ):
+ start = True
+ continue
+ elif endmark and line.startswith( endmark ):
+ break
+ if start and not line.startswith( '#' ):
+ elems = line.split()
+ if len( elems ) < 2:
+ continue
+ elif len( elems[0] ) > 1 and \
+ len( elems[pos] ) > 1: # words only
+ mlist.add( elems[pos] )
+ return mlist
+
+def tablesParser( path, name ):
+ """ Read file from scim-tables and parse it. """
+ global SCIM_TABLES_VER
+ src = 'scim-tables-%s/tables/zh/%s' % ( SCIM_TABLES_VER, name )
+ fp = untargz( path, src, 'U8' )
+ return parserCore( fp, 1, 'BEGIN_TABLE', 'END_TABLE' )
+
+ezbigParser = lambda path: tablesParser( path, 'EZ-Big.txt.in' )
+wubiParser = lambda path: tablesParser( path, 'Wubi.txt.in' )
+zrmParser = lambda path: tablesParser( path, 'Ziranma.txt.in' )
+
+def phraseParser( path ):
+ """ Read phrase_lib.txt and parse it. """
+ global SCIM_PINYIN_VER
+ src = 'scim-pinyin-%s/data/phrase_lib.txt' % SCIM_PINYIN_VER
+ dst = 'phrase_lib.txt'
+ fp = untargz( path, src, 'U8' )
+ return parserCore( fp, 0 )
+
+def tsiParser( path ):
+ """ Read tsi.src and parse it. """
+ src = 'libtabe/tsi-src/tsi.src'
+ dst = 'tsi.src'
+ fp = untargz( path, src, 'big5hkscs' )
+ return parserCore( fp, 0 )
+
+def unihanParser( path ):
+ """ Read Unihan_Variants.txt and parse it. """
+ fp = unzip( path, 'Unihan_Variants.txt', 'U8' )
+ t2s = dict()
+ s2t = dict()
+ for line in fp:
+ if line.startswith( '#' ):
+ continue
+ else:
+ elems = line.split()
+ if len( elems ) < 3:
+ continue
+ type = elems.pop( 1 )
+ elems = unichr2( *elems )
+ if type == 'kTraditionalVariant':
+ s2t[elems[0]] = elems[1:]
+ elif type == 'kSimplifiedVariant':
+ t2s[elems[0]] = elems[1:]
+ fp.close()
+ return ( t2s, s2t )
+
+def applyExcludes( mlist, path ):
+ """ Apply exclude rules from path to mlist. """
+ excludes = open( path, 'rb', 'U8' ).read().split()
+ excludes = [word.split( '#' )[0].strip() for word in excludes]
+ excludes = '|'.join( excludes )
+ excptn = re.compile( '.*(?:%s).*' % excludes )
+ diff = [mword for mword in mlist if excptn.search( mword )]
+ mlist.difference_update( diff )
+ return mlist
+
+def charManualTable( path ):
+ fp = open( path, 'rb', 'U8' )
+ ret = {}
+ for line in fp:
+ elems = line.split( '#' )[0].split( '|' )
+ elems = unichr3( *elems )
+ if len( elems ) > 1:
+ ret[elems[0]] = elems[1:]
+ return ret
+
+def toManyRules( src_table ):
+ tomany = set()
+ for ( f, t ) in src_table.iteritems():
+ for i in range( 1, len( t ) ):
+ tomany.add( t[i] )
+ return tomany
+
+def removeRules( path, table ):
+ fp = open( path, 'rb', 'U8' )
+ texc = list()
+ for line in fp:
+ elems = line.split( '=>' )
+ f = t = elems[0].strip()
+ if len( elems ) == 2:
+ t = elems[1].strip()
+ f = f.strip('"').strip("'")
+ t = t.strip('"').strip("'")
+ if f:
+ try:
+ table.pop( f )
+ except:
+ pass
+ if t:
+ texc.append( t )
+ texcptn = re.compile( '^(?:%s)$' % '|'.join( texc ) )
+ for (tmp_f, tmp_t) in table.copy().iteritems():
+ if texcptn.match( tmp_t ):
+ table.pop( tmp_f )
+ return table
+
+def customRules( path ):
+ fp = open( path, 'rb', 'U8' )
+ ret = dict()
+ for line in fp:
+ elems = line.split( '#' )[0].split()
+ if len( elems ) > 1:
+ ret[elems[0]] = elems[1]
+ return ret
+
+def dictToSortedList( src_table, pos ):
+ return sorted( src_table.items(), key = lambda m: m[pos] )
+
+def translate( text, conv_table ):
+ i = 0
+ while i < len( text ):
+ for j in range( len( text ) - i, 0, -1 ):
+ f = text[i:][:j]
+ t = conv_table.get( f )
+ if t:
+ text = text[:i] + t + text[i:][j:]
+ i += len(t) - 1
+ break
+ i += 1
+ return text
+
+def manualWordsTable( path, conv_table, reconv_table ):
+ fp = open( path, 'rb', 'U8' )
+ reconv_table = {}
+ wordlist = [line.split( '#' )[0].strip() for line in fp]
+ wordlist = list( set( wordlist ) )
+ wordlist.sort( key = len, reverse = True )
+ while wordlist:
+ word = wordlist.pop()
+ new_word = translate( word, conv_table )
+ rcv_word = translate( word, reconv_table )
+ if word != rcv_word:
+ reconv_table[word] = word
+ reconv_table[new_word] = word
+ return reconv_table
+
+def defaultWordsTable( src_wordlist, src_tomany, char_conv_table, char_reconv_table ):
+ wordlist = list( src_wordlist )
+ wordlist.sort( key = len, reverse = True )
+ word_conv_table = {}
+ word_reconv_table = {}
+ conv_table = char_conv_table.copy()
+ reconv_table = char_reconv_table.copy()
+ tomanyptn = re.compile( '(?:%s)' % '|'.join( src_tomany ) )
+ while wordlist:
+ conv_table.update( word_conv_table )
+ reconv_table.update( word_reconv_table )
+ word = wordlist.pop()
+ new_word_len = word_len = len( word )
+ while new_word_len == word_len:
+ add = False
+ test_word = translate( word, reconv_table )
+ new_word = translate( word, conv_table )
+ if not reconv_table.get( new_word ) \
+ and ( test_word != word \
+ or ( tomanyptn.search( word ) \
+ and word != translate( new_word, reconv_table ) ) ):
+ word_conv_table[word] = new_word
+ word_reconv_table[new_word] = word
+ try:
+ word = wordlist.pop()
+ except IndexError:
+ break
+ new_word_len = len(word)
+ return word_reconv_table
+
+def PHPArray( table ):
+ lines = ['\'%s\' => \'%s\',' % (f, t) for (f, t) in table if f and t]
+ return '\n'.join(lines)
+
+def main():
+ #Get Unihan.zip:
+ url = 'http://www.unicode.org/Public/%s/ucd/Unihan.zip' % UNIHAN_VER
+ han_dest = 'Unihan.zip'
+ download( url, han_dest )
+
+ # Get scim-tables-$(SCIM_TABLES_VER).tar.gz:
+ url = 'http://%s.dl.sourceforge.net/sourceforge/scim/scim-tables-%s.tar.gz' % ( SF_MIRROR, SCIM_TABLES_VER )
+ tbe_dest = 'scim-tables-%s.tar.gz' % SCIM_TABLES_VER
+ download( url, tbe_dest )
+
+ # Get scim-pinyin-$(SCIM_PINYIN_VER).tar.gz:
+ url = 'http://%s.dl.sourceforge.net/sourceforge/scim/scim-pinyin-%s.tar.gz' % ( SF_MIRROR, SCIM_PINYIN_VER )
+ pyn_dest = 'scim-pinyin-%s.tar.gz' % SCIM_PINYIN_VER
+ download( url, pyn_dest )
+
+ # Get libtabe-$(LIBTABE_VER).tgz:
+ url = 'http://%s.dl.sourceforge.net/sourceforge/libtabe/libtabe-%s.tgz' % ( SF_MIRROR, LIBTABE_VER )
+ lbt_dest = 'libtabe-%s.tgz' % LIBTABE_VER
+ download( url, lbt_dest )
+
+ # Unihan.txt
+ ( t2s_1tomany, s2t_1tomany ) = unihanParser( han_dest )
+
+ t2s_1tomany.update( charManualTable( 'trad2simp.manual' ) )
+ s2t_1tomany.update( charManualTable( 'simp2trad.manual' ) )
+
+ t2s_1to1 = dict( [( f, t[0] ) for ( f, t ) in t2s_1tomany.iteritems()] )
+ s2t_1to1 = dict( [( f, t[0] ) for ( f, t ) in s2t_1tomany.iteritems()] )
+
+ s_tomany = toManyRules( t2s_1tomany )
+ t_tomany = toManyRules( s2t_1tomany )
+
+ # noconvert rules
+ t2s_1to1 = removeRules( 'trad2simp_noconvert.manual', t2s_1to1 )
+ s2t_1to1 = removeRules( 'simp2trad_noconvert.manual', s2t_1to1 )
+
+ # the supper set for word to word conversion
+ t2s_1to1_supp = t2s_1to1.copy()
+ s2t_1to1_supp = s2t_1to1.copy()
+ t2s_1to1_supp.update( customRules( 'trad2simp_supp_set.manual' ) )
+ s2t_1to1_supp.update( customRules( 'simp2trad_supp_set.manual' ) )
+
+ # word to word manual rules
+ t2s_word2word_manual = manualWordsTable( 'simpphrases.manual', s2t_1to1_supp, t2s_1to1_supp )
+ t2s_word2word_manual.update( customRules( 'toSimp.manual' ) )
+ s2t_word2word_manual = manualWordsTable( 'tradphrases.manual', t2s_1to1_supp, s2t_1to1_supp )
+ s2t_word2word_manual.update( customRules( 'toTrad.manual' ) )
+
+ # word to word rules from input methods
+ t_wordlist = set()
+ s_wordlist = set()
+ t_wordlist.update( ezbigParser( tbe_dest ),
+ tsiParser( lbt_dest ) )
+ s_wordlist.update( wubiParser( tbe_dest ),
+ zrmParser( tbe_dest ),
+ phraseParser( pyn_dest ) )
+
+ # exclude
+ s_wordlist = applyExcludes( s_wordlist, 'simpphrases_exclude.manual' )
+ t_wordlist = applyExcludes( t_wordlist, 'tradphrases_exclude.manual' )
+
+ s2t_supp = s2t_1to1_supp.copy()
+ s2t_supp.update( s2t_word2word_manual )
+ t2s_supp = t2s_1to1_supp.copy()
+ t2s_supp.update( t2s_word2word_manual )
+
+ # parse list to dict
+ t2s_word2word = defaultWordsTable( s_wordlist, s_tomany, s2t_1to1_supp, t2s_supp )
+ t2s_word2word.update( t2s_word2word_manual )
+ s2t_word2word = defaultWordsTable( t_wordlist, t_tomany, t2s_1to1_supp, s2t_supp )
+ s2t_word2word.update( s2t_word2word_manual )
+
+ # Final tables
+ # sorted list toHans
+ t2s_1to1 = dict( [( f, t ) for ( f, t ) in t2s_1to1.iteritems() if f != t] )
+ toHans = dictToSortedList( t2s_1to1, 0 ) + dictToSortedList( t2s_word2word, 1 )
+ # sorted list toHant
+ s2t_1to1 = dict( [( f, t ) for ( f, t ) in s2t_1to1.iteritems() if f != t] )
+ toHant = dictToSortedList( s2t_1to1, 0 ) + dictToSortedList( s2t_word2word, 1 )
+ # sorted list toCN
+ toCN = dictToSortedList( customRules( 'toCN.manual' ), 1 )
+ # sorted list toHK
+ toHK = dictToSortedList( customRules( 'toHK.manual' ), 1 )
+ # sorted list toSG
+ toSG = dictToSortedList( customRules( 'toSG.manual' ), 1 )
+ # sorted list toTW
+ toTW = dictToSortedList( customRules( 'toTW.manual' ), 1 )
+
+ # Get PHP Array
+ php = '''<?php
+/**
+ * Simplified / Traditional Chinese conversion tables
+ *
+ * Automatically generated using code and data in includes/zhtable/
+ * Do not modify directly!
+ *
+ * @file
+ */
+
+$zh2Hant = array(\n'''
+ php += PHPArray( toHant ) \
+ + '\n);\n\n$zh2Hans = array(\n' \
+ + PHPArray( toHans ) \
+ + '\n);\n\n$zh2TW = array(\n' \
+ + PHPArray( toTW ) \
+ + '\n);\n\n$zh2HK = array(\n' \
+ + PHPArray( toHK ) \
+ + '\n);\n\n$zh2CN = array(\n' \
+ + PHPArray( toCN ) \
+ + '\n);\n\n$zh2SG = array(\n' \
+ + PHPArray( toSG ) \
+ + '\n);\n'
+
+ f = open( os.path.join( '..', '..', '..', 'includes', 'ZhConversion.php' ), 'wb', encoding = 'utf8' )
+ print ('Writing ZhConversion.php ... ')
+ f.write( php )
+ f.close()
+
+ # Remove temporary files
+ print ('Deleting temporary files ... ')
+ os.remove('EZ-Big.txt.in')
+ os.remove('phrase_lib.txt')
+ os.remove('tsi.src')
+ os.remove('Unihan_Variants.txt')
+ os.remove('Wubi.txt.in')
+ os.remove('Ziranma.txt.in')
+
+
+if __name__ == '__main__':
+ main()
diff --git a/maintenance/language/zhtable/README b/maintenance/language/zhtable/README
new file mode 100644
index 00000000..7e3f87e2
--- /dev/null
+++ b/maintenance/language/zhtable/README
@@ -0,0 +1,33 @@
+The various .manual files contains special mappings not included in the
+unihan database, and phrases not included in the SCIM package.
+
+- simp2trad.manual: Simplified to Traditional character mapping. Most
+ data adapted from
+
+ 冯寿忠,“非对称繁简字”对照表, 《语文建设通讯》1997-9第53期.
+ /http://www.yywzw.com/jt/feng/fengb01.htm
+
+- trad2simp.manual: Traditional to Simplified character mapping.
+
+- simp2trad_noconvert.manual: Do not convert the chars as inapporiate.
+
+- trad2simp_noconvert.manual: Do not convert the chars as inapporiate.
+
+- tradphrases.manual: Phrases in Traditional Chinese. A portition is obtained
+ from the TongWen package (http://tongwen.mozdev.org/)
+
+- simpphrases.manual: Phrases in Simplified Chinese.
+
+- tradphrases_exclude.manual: Excluding several phrases from
+ the SCIM phrases as inappoiated.
+
+- simpphrases_exclude.manual: Excluding several phrases from
+ the SCIM phrases as inapporated.
+
+- toTrad.manual, toSimp.manual: Special phrase mappings that
+ tradphrases.manual or simphrases.manual cannot be handled.
+
+- toTW.manual, toCN.manual, toSG.manual and toHK.manual: Special phrase
+ mappings.
+
+zhengzhu at gmail dot com & shinjiman at gmail dot com
diff --git a/maintenance/language/zhtable/simp2trad.manual b/maintenance/language/zhtable/simp2trad.manual
new file mode 100644
index 00000000..1b84f8e7
--- /dev/null
+++ b/maintenance/language/zhtable/simp2trad.manual
@@ -0,0 +1,372 @@
+U+03CE0㳠|U+06FBE澾|
+U+0447D䑽|U+26A99𦪙|
+U+0497A䥺|U+091FE釾|
+U+0497D䥽|U+093FA鏺|
+U+04983䦃|U+0942F鐯|
+U+04985䦅|U+09425鐥|
+U+04B6A䭪|U+297AF𩞯|
+U+04C9F䲟|U+09BA3鮣|
+U+04CA0䲠|U+09C06鰆|
+U+04CA1䲡|U+09C0C鰌|
+U+04CA2䲢|U+09C27鰧|
+U+04CA3䲣|U+04C77䱷|
+U+04DAE䶮|U+09F91龑|
+U+04E07万|U+0842C萬|U+04E07万|
+U+04E0E与|U+08207與|U+04E0E与|
+U+04E11丑|U+04E11丑|U+0919C醜|
+U+04E2A个|U+0500B個|U+07B87箇|
+U+04E30丰|U+08C50豐|U+04E30丰|
+U+04E3A为|U+070BA為|U+07232爲|
+U+04E48么|U+04E48么|U+09EBD麽|U+05E7A幺|U+09EBC麼|
+U+04E86了|U+04E86了|U+077AD瞭|
+U+04E8E于|U+065BC於|U+04E8E于|
+U+04E91云|U+096F2雲|U+04E91云|
+U+04EA7产|U+07522產|U+07523産|
+U+04EC6仆|U+04EC6仆|U+050D5僕|
+U+04EC7仇|U+04EC7仇|U+08B8E讎|
+U+04ED1仑|U+04F96侖|U+05D19崙|
+U+04EF7价|U+050F9價|U+04EF7价|
+U+04F17众|U+0773E眾|U+08846衆|
+U+04F19伙|U+04F19伙|U+05925夥|
+U+04F2A伪|U+0507D偽|U+050DE僞|
+U+04F53体|U+09AD4體|U+04F53体|
+U+04F59余|U+04F59余|U+09918餘|
+U+04F63佣|U+04F63佣|U+050AD傭|
+U+0501F借|U+0501F借|U+085C9藉|
+U+0513F儿|U+05152兒|U+0513F儿|
+U+0514B克|U+0514B克|U+0524B剋|
+U+0515A党|U+09EE8黨|U+0515A党|
+U+051AC冬|U+051AC冬|U+09F15鼕|
+U+051B2冲|U+06C96沖|U+0885D衝|
+U+051C6准|U+051C6准|U+06E96準|
+U+051E0几|U+05E7E幾|U+051E0几|
+U+051EB凫|U+09CE7鳧|U+09CEC鳬|
+U+051FA出|U+051FA出|U+09F63齣|
+U+05212划|U+05283劃|U+05212划|
+U+0522B别|U+05225別|U+05F46彆|
+U+0522E刮|U+0522E刮|U+098B3颳|
+U+05236制|U+05236制|U+088FD製|
+U+05343千|U+05343千|U+097C6韆|
+U+05347升|U+05347升|U+06607昇|U+0965E陞|
+U+0535C卜|U+0535C卜|U+08514蔔|
+U+05360占|U+05360占|U+04F54佔|
+U+05364卤|U+09E75鹵|U+06EF7滷|
+U+05377卷|U+05377卷|U+06372捲|
+U+0537A卺|U+05DF9巹|
+U+05382厂|U+05EE0廠|U+05382厂|
+U+05386历|U+06B77歷|U+066C6曆|U+053A4厤|
+U+05395厕|U+05EC1廁|U+053A0厠|
+U+05398厘|U+05398厘|U+091D0釐|
+U+053D1发|U+0767C發|U+09AEE髮|
+U+053EA只|U+053EA只|U+096BB隻|
+U+053F0台|U+053F0台|U+081FA臺|U+06AAF檯|U+098B1颱|
+U+053F6叶|U+08449葉|U+053F6叶|
+U+05401吁|U+05401吁|U+07C72籲|
+U+05408合|U+05408合|U+095A4閤|
+U+0540A吊|U+0540A吊|U+05F14弔|
+U+0540C同|U+0540C同|U+08855衕|
+U+0540E后|U+05F8C後|U+0540E后|
+U+05411向|U+05411向|U+056AE嚮|U+066CF曏|
+U+0542F启|U+0555F啟|U+05553啓|
+U+05446呆|U+05446呆|U+07343獃|
+U+054B8咸|U+054B8咸|U+09E79鹹|
+U+054C4哄|U+054C4哄|U+09B28鬨|
+U+05582喂|U+05582喂|U+09935餵|
+U+056DE回|U+056DE回|U+08FF4迴|
+U+056E2团|U+05718團|U+07CF0糰|
+U+056F0困|U+056F0困|U+0774F睏|
+U+05742坂|U+05742坂|U+0962A阪|
+U+0574F坏|U+058DE壞|U+0574F坏|
+U+0575B坛|U+058C7壇|U+07F48罈|
+U+057FC埼|U+057FC埼|U+07895碕|
+U+05899墙|U+07246牆|U+058BB墻|
+U+058F3壳|U+06BBC殼|U+06BBB殻|
+U+0590D复|U+05FA9復|U+08907複|
+U+05956奖|U+0734E獎|U+0596C奬|
+U+05978奸|U+05978奸|U+059E6姦|
+U+059AB妫|U+05AAF媯|U+05B00嬀|
+U+059DC姜|U+059DC姜|U+08591薑|
+U+05B81宁|U+05BE7寧|U+05B81宁|
+U+05BB6家|U+05BB6家|U+050A2傢|
+U+05C3D尽|U+076E1盡|U+05118儘|
+U+05CB3岳|U+05CB3岳|U+05DBD嶽|
+U+05E03布|U+05E03布|U+04F48佈|
+U+05E18帘|U+07C3E簾|U+05E18帘|
+U+05E5E幞|U+08946襆|
+U+05E72干|U+05E72干|U+04E7E乾|U+05E79幹|U+069A6榦|
+U+05E76并|U+04E26並|U+04F75併|
+U+05E78幸|U+05E78幸|U+05016倖|
+U+05E7F广|U+05EE3廣|U+05E7F广|
+U+05E84庄|U+05E84庄|U+0838A莊|
+U+05EB5庵|U+05EB5庵|U+083F4菴|
+U+05F25弥|U+05F4C彌|U+07030瀰|
+U+05F53当|U+07576當|U+05679噹|
+U+05F55录|U+09304錄|U+09332録|
+U+05F69彩|U+05F69彩|U+07DB5綵|
+U+05F81征|U+05F81征|U+05FB5徵|
+U+05FA1御|U+05FA1御|U+079A6禦|
+U+05FD7志|U+05FD7志|U+08A8C誌|
+U+06076恶|U+060E1惡|U+05641噁|
+U+060AB悫|U+06128愨|U+06164慤|
+U+0613F愿|U+09858願|U+0613F愿|
+U+0621A戚|U+0621A戚|U+0617C慼|U+093DA鏚|
+U+0624D才|U+0624D才|U+07E94纔|
+U+0624E扎|U+0624E扎|U+07D2E紮|
+U+06258托|U+06258托|U+08A17託|
+U+06298折|U+06298折|U+0647A摺|
+U+062C5担|U+064D4擔|U+062C5担|
+U+062FC拼|U+062FC拼|U+062DA拚|
+U+06328挨|U+06328挨|U+06371捱|
+U+0633D挽|U+0633D挽|U+08F13輓|
+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+066F2曲|U+066F2曲|U+09EAF麯|U+09EB4麯|
+U+0672F术|U+08853術|U+0672E朮|
+U+06731朱|U+06731朱|U+07843硃|
+U+06734朴|U+06734朴|U+06A38樸|
+U+0676F杯|U+0676F杯|U+076C3盃|
+U+0677E松|U+0677E松|U+09B06鬆|
+U+0677F板|U+0677F板|U+095C6闆|
+U+06781极|U+06975極|U+06781极|
+U+067DC柜|U+06AC3櫃|U+067DC柜|
+U+06817栗|U+06817栗|U+06144慄|
+U+06881梁|U+06881梁|U+06A11樑|
+U+068F1棱|U+068F1棱|U+07A1C稜|
+U+06B32欲|U+06B32欲|U+0617E慾|
+U+06C47汇|U+0532F匯|U+06ED9滙|U+05F59彙|
+U+06C84沄|U+06C84沄|U+06F90澐|
+U+06C88沈|U+06C88沈|U+0700B瀋|
+U+06CA9沩|U+06E88溈|U+06F59潙|
+U+06CE8注|U+06CE8注|U+08A3B註|
+U+06D82涂|U+05857塗|U+06D82涂|
+U+06D8C涌|U+06D8C涌|U+06E67湧|
+U+06DC0淀|U+06DC0淀|U+06FB1澱|
+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+0753B画|U+0756B畫|U+07575畵|
+U+075C7症|U+075C7症|U+07665癥|
+U+07618瘘|U+0763A瘺|U+0763B瘻|
+U+0786E确|U+078BA確|U+0786E确|
+U+07877硷|U+07906礆|U+09E7C鹼|
+U+079CB秋|U+079CB秋|U+097A6鞦|
+U+079CD种|U+07A2E種|U+079CD种|
+U+07A57穗|U+07A57穗|U+07E50繐|
+U+07AD6竖|U+08C4E豎|U+07AEA竪|
+U+07B51筑|U+07BC9築|U+07B51筑|
+U+07B7E签|U+07C3D簽|U+07C64籤|
+U+07CFB系|U+07CFB系|U+07E6B繫|U+04FC2係|
+U+07D2F累|U+07D2F累|U+07E8D纍|
+U+07EA4纤|U+07E96纖|U+07E34縴|
+U+07EBF线|U+07DDA線|U+07DAB綫|
+U+07EDD绝|U+07D55絕|U+07D76絶|
+U+07EE3绣|U+07D89綉|U+07E61繡|
+U+07EE6绦|U+07D5B絛|U+07E27縧|
+U+07EF1绱|U+07DD4緔|U+0979D鞝|
+U+07EF7绷|U+07DB3綳|U+07E43繃|
+U+07EFF绿|U+07DA0綠|U+07DD1緑|
+U+07F30缰|U+097C1韁|U+07E6E繮|
+U+07FA1羡|U+07FA8羨|
+U+080DC胜|U+052DD勝|U+080DC胜|
+U+080E1胡|U+080E1胡|U+09B0D鬍|U+0885A衚|
+U+0810F脏|U+081DF臟|U+09AD2髒|
+U+0814A腊|U+081D8臘|U+0814A腊|
+U+081F4致|U+081F4致|U+07DFB緻|
+U+0820D舍|U+0820D舍|U+06368捨|
+U+082B8芸|U+082B8芸|U+08553蕓|
+U+082CE苎|U+082E7苧|
+U+082CF苏|U+08607蘇|U+056CC囌|U+07C64甦|
+U+082E7苧|U+085B4薴|
+U+082F9苹|U+0860B蘋|U+082F9苹|
+U+08303范|U+08303范|U+07BC4範|
+U+0836F药|U+0846F葯|U+085E5藥|
+U+083B7获|U+07372獲|U+07A6B穫|
+U+083BC莼|U+08493蒓|U+084F4蓴|
+U+08499蒙|U+08499蒙|U+077C7矇|U+06FDB濛|U+061DE懞|
+U+084D1蓑|U+084D1蓑|U+07C11簑|
+U+08511蔑|U+08511蔑|U+0884A衊|
+U+08574蕴|U+0860A蘊|U+085F4藴|
+U+0866B虫|U+087F2蟲|U+0866B虫|
+U+08721蜡|U+0881F蠟|U+08721蜡|
+U+0874E蝎|U+0880D蠍|
+U+08868表|U+08868表|U+09336錶|
+U+08BF4说|U+08AAA說|U+08AAC説|
+U+08C23谣|U+08B20謠|U+08B21謡|
+U+08C2B谫|U+08B7E譾|U+08B2D謭|
+U+08C37谷|U+08C37谷|U+07A40穀|
+U+08D43赃|U+08D13贓|U+08D1C贜|
+U+08D4D赍|U+09F4E齎|U+08CEB賫|
+U+08D5D赝|U+08D17贗|U+08D0B贋|
+U+08D5E赞|U+08D0A贊|U+08B9A讚|
+U+08F9F辟|U+08F9F辟|U+095E2闢|
+U+09002适|U+09069適|U+09002适|
+U+090C1郁|U+090C1郁|U+09B31鬱|
+U+0915D酝|U+0919E醞|U+09196醖|
+U+09170酰|U+09170酰|U+091AF醯|
+U+09178酸|U+09178酸|U+075E0痠|
+U+091C7采|U+091C7采|U+063A1採|U+057F0埰|
+U+091CC里|U+091CC里|U+088E1裡|U+088CF裏|
+U+093AD鎭|U+093AE鎮|
+U+0949F钟|U+0937E鍾|U+09418鐘|
+U+094A9钩|U+09264鉤|U+0920E鈎|
+U+094B5钵|U+07F3D缽|U+09262鉢|
+U+094F2铲|U+093DF鏟|U+05277剷|
+U+09508锈|U+092B9銹|U+093FD鏽|
+U+09510锐|U+092B3銳|U+092ED鋭|
+U+09528锨|U+06774杴|U+09341鍁|
+U+0954C镌|U+0942B鐫|U+093B8鎸|
+U+09562镢|U+09481钁|U+0941D鐝|
+U+09605阅|U+095B1閱|U+095B2閲|
+U+096C7雇|U+096C7雇|U+050F1僱|
+U+096D5雕|U+096D5雕|U+09D70鵰|
+U+09709霉|U+09709霉|U+09EF4黴|
+U+09762面|U+09762面|U+09EB5麵|U+09EAA麪|U+09EAB麫|
+U+097B2鞲|U+097DD韝|
+U+0987B须|U+09808須|U+09B1A鬚|
+U+09893颓|U+09839頹|U+0983D頽|
+U+0989C颜|U+0984F顏|U+09854顔|
+U+09965饥|U+098E2飢|U+09951饑|
+U+09980馀|U+09918餘|
+U+09986馆|U+09928館|U+08218舘|
+U+09A82骂|U+07F75罵|U+099E1駡|
+U+09C87鲇|U+09BF0鯰|U+09B8E鮎|
+U+09C9E鲞|U+09BD7鯗|U+09B9D鮝|
+U+09CC4鳄|U+09C77鱷|U+09C10鰐|
+U+09E21鸡|U+096DE雞|U+09DC4鷄|
+U+09E5A鹚|U+09DBF鶿|U+09DC0鷀|
+U+09E6E鹮|U+04D09䴉|
+U+09F44齄|U+09F47齇|
+U+20BB6𠮶|U+055F0嗰|
+U+26216𦈖|U+04308䌈|
+U+28C3E𨰾|U+093B7鎷|
+U+28C3F𨰿|U+091F3釳|
+U+28C40𨱀|U+2895B𨥛|
+U+28C41𨱁|U+09220鈠|
+U+28C42𨱂|U+0920B鈋|
+U+28C43𨱃|U+09232鈲|
+U+28C44𨱄|U+0922F鈯|
+U+28C45𨱅|U+09241鉁|
+U+28C47𨱇|U+092B6銶|
+U+28C48𨱈|U+092C9鋉|
+U+28C49𨱉|U+09344鍄|
+U+28C4A𨱊|U+289F1𨧱|
+U+28C4B𨱋|U+09302錂|
+U+28C4C𨱌|U+093C6鏆|
+U+28C4D𨱍|U+093AF鎯|
+U+28C4E𨱎|U+0936E鍮|
+U+28C4F𨱏|U+0939D鎝|
+U+28C50𨱐|U+28AD2𨫒|
+U+28C52𨱒|U+093C9鏉|
+U+28C53𨱓|U+0940E鐎|
+U+28C54𨱔|U+0940F鐏|
+U+28C55𨱕|U+28B82𨮂|
+U+28E02𨸂|U+0958D閍|
+U+28E03𨸃|U+09590閐|
+U+293FC𩏼|U+04A8F䪏|
+U+293FD𩏽|U+293EA𩏪|
+U+293FE𩏾|U+293A2𩎢|
+U+293FF𩏿|U+04A98䪘|
+U+29400𩐀|U+04A97䪗|
+U+29595𩖕|U+294E3𩓣|
+U+29596𩖖|U+09843顃|
+U+29597𩖗|U+04AF4䫴|
+U+29665𩙥|U+098B0颰|
+U+29666𩙦|U+295C0𩗀|
+U+29667𩙧|U+295E1𩗡|
+U+29668𩙨|U+29639𩘹|
+U+29669𩙩|U+29600𩘀|
+U+2966A𩙪|U+098B7颷|
+U+2966B𩙫|U+098BE颾|
+U+2966C𩙬|U+2963A𩘺|
+U+2966D𩙭|U+2961D𩘝|
+U+2966E𩙮|U+04B18䬘|
+U+2966F𩙯|U+04B1D䬝|
+U+29670𩙰|U+29648𩙈|
+U+29805𩠅|U+297D0𩟐|
+U+29806𩠆|U+29726𩜦|
+U+29807𩠇|U+04B40䭀|
+U+29808𩠈|U+04B43䭃|
+U+2980B𩠋|U+29754𩝔|
+U+2980C𩠌|U+09938餸|
+U+299E6𩧦|U+2987A𩡺|
+U+299E8𩧨|U+099CE駎|
+U+299E9𩧩|U+2990A𩤊|
+U+299EA𩧪|U+04BBE䮾|
+U+299EB𩧫|U+099DA駚|
+U+299EC𩧬|U+298A1𩢡|
+U+299ED𩧭|U+04B7F䭿|
+U+299EE𩧮|U+298BE𩢾|
+U+299EF𩧯|U+09A4B驋|
+U+299F0𩧰|U+04B9D䮝|
+U+299F1𩧱|U+29949𩥉|
+U+299F2𩧲|U+099E7駧|
+U+299F3𩧳|U+298B8𩢸|
+U+299F4𩧴|U+099E9駩|
+U+299F5𩧵|U+298B4𩢴|
+U+299F6𩧶|U+298CF𩣏|
+U+299FA𩧺|U+099F6駶|
+U+299FB𩧻|U+298F5𩣵|
+U+299FC𩧼|U+298FA𩣺|
+U+299FF𩧿|U+04BA0䮠|
+U+29A00𩨀|U+09A14騔|
+U+29A01𩨁|U+04B9E䮞|
+U+29A03𩨃|U+09A1D騝|
+U+29A04𩨄|U+09A2A騪|
+U+29A05𩨅|U+29938𩤸|
+U+29A06𩨆|U+29919𩤙|
+U+29A08𩨈|U+09A1F騟|
+U+29A09𩨉|U+29932𩤲|
+U+29A0A𩨊|U+09A1A騚|
+U+29A0B𩨋|U+29944𩥄|
+U+29A0C𩨌|U+29951𩥑|
+U+29A0D𩨍|U+29947𩥇|
+U+29A0F𩨏|U+04BB3䮳|
+U+29A10𩨐|U+299C6𩧆|
+U+29F79𩽹|U+09B65魥|
+U+29F7A𩽺|U+29D69𩵩|
+U+29F7B𩽻|U+29D79𩵹|
+U+29F7C𩽼|U+09BF6鯶|
+U+29F7D𩽽|U+29DB1𩶱|
+U+29F7E𩽾|U+09B9F鮟|
+U+29F7F𩽿|U+29DB0𩶰|
+U+29F80𩾀|U+09B95鮕|
+U+29F81𩾁|U+09BC4鯄|
+U+29F83𩾃|U+09BB8鮸|
+U+29F84𩾄|U+29DF0𩷰|
+U+29F85𩾅|U+29E03𩸃|
+U+29F86𩾆|U+29E26𩸦|
+U+29F87𩾇|U+09BF1鯱|
+U+29F88𩾈|U+04C59䱙|
+U+29F8A𩾊|U+04C6C䱬|
+U+29F8B𩾋|U+04C70䱰|
+U+29F8C𩾌|U+09C47鱇|
+U+29F8C𩾌|U+09C47鱇|
+U+29F8E𩾎|U+29F47𩽇|
+U+2A242𪉂|U+04CB0䲰|
+U+2A243𪉃|U+09CFC鳼|
+U+2A244𪉄|U+29FEA𩿪|
+U+2A245𪉅|U+2A026𪀦|
+U+2A246𪉆|U+09D32鴲|
+U+2A248𪉈|U+09D1C鴜|
+U+2A249𪉉|U+2A048𪁈|
+U+2A24A𪉊|U+09DE8鷨|
+U+2A24B𪉋|U+2A03E𪀾|
+U+2A24C𪉌|U+2A056𪁖|
+U+2A24D𪉍|U+09D5A鵚|
+U+2A24E𪉎|U+2A086𪂆|
+U+2A24F𪉏|U+2A0CF𪃏|
+U+2A250𪉐|U+2A0CD𪃍|
+U+2A251𪉑|U+09DD4鷔|
+U+2A252𪉒|U+2A115𪄕|
+U+2A254𪉔|U+2A106𪄆|
+U+2A255𪉕|U+2A1F3𪇳|
+U+2A388𪎈|U+04D2C䴬|
+U+2A389𪎉|U+09EB2麲|
+U+2A38A𪎊|U+09EA8麨|
+U+2A38B𪎋|U+04D34䴴|
+U+2A38C𪎌|U+09EB3麳|
+U+2A68F𪚏|U+2A600𪘀|
+U+2A690𪚐|U+2A62F𪘯|
diff --git a/maintenance/language/zhtable/simp2trad_noconvert.manual b/maintenance/language/zhtable/simp2trad_noconvert.manual
new file mode 100644
index 00000000..a46560a7
--- /dev/null
+++ b/maintenance/language/zhtable/simp2trad_noconvert.manual
@@ -0,0 +1,139 @@
+著
+竈
+彞
+=>"余"
+=>"𫗭"
+=>"𪨧"
+=>"𫚭"
+=>"𫔀"
+=>"𫊻"
+=>"𫋌"
+=>"蚃"
+=>"𩾂"
+=>"𫚜"
+=>"𫚢"
+=>"𧉰"
+=>"䙌"
+=>"𫊮"
+=>"𫋇"
+=>"𫉄"
+=>"𫘛"
+=>"𫘜"
+=>"𫘝"
+=>"𫘟"
+=>"𩧨"
+=>"𩧫"
+=>"𫘞"
+=>"𫘠"
+=>"𩧲"
+=>"𩧴"
+=>"𫘡"
+=>"𩧺"
+=>"𫘣"
+=>"𫘤"
+=>"𫘧"
+=>"𫘥"
+=>"𫘦"
+=>"𩨀"
+=>"𩨊"
+=>"𫘩"
+=>"𩨃"
+=>"𫘪"
+=>"𫘪"
+=>"𫘫"
+=>"𫘬"
+=>"𩨈"
+=>"𫘨"
+=>"𩨄"
+=>"𫘭"
+=>"𩧯"
+=>"𫘯"
+=>"𫘰"
+=>"𫘱"
+=>"𫘽"
+=>"𫚉"
+=>"𩽹"
+=>"𫚌"
+=>"𫚍"
+=>"𫚒"
+=>"𫚑"
+=>"𫚖"
+=>"𩽾"
+=>"䲟"
+=>"𫚓"
+=>"𫚗"
+=>"𫚔"
+=>"𫚛"
+=>"𩾃"
+=>"𫚚"
+=>"𩾁"
+=>"𫚙"
+=>"𫚡"
+=>"𫚞"
+=>"𩾇"
+=>"𩽼"
+=>"𫚣"
+=>"䲠"
+=>"䲡"
+=>"𫚊"
+=>"𫚥"
+=>"𫚕"
+=>"𫚤"
+=>"䲢"
+=>"𫚦"
+=>"𫚧"
+=>"𫚋"
+=>"𩾌"
+=>"𫚪"
+=>"𫚫"
+=>"𫚈"
+=>"𫚭"
+=>"𫛛"
+=>"𪉃"
+=>"𫛚"
+=>"𫛜"
+=>"𫛞"
+=>"𫛝"
+=>"𫛤"
+=>"𫛡"
+=>"𫁡"
+=>"𪉈"
+=>"𫛣"
+=>"𫛦"
+=>"𪉆"
+=>"𫛩"
+=>"𫛪"
+=>"𫛥"
+=>"𪉍"
+=>"𫛭"
+=>"𫛨"
+=>"𫛳"
+=>"𫛱"
+=>"𫛲"
+=>"𫛵"
+=>"𫛶"
+=>"𫛸"
+=>"𫛷"
+=>"𫛯"
+=>"𫛫"
+=>"𫛽"
+=>"𫜀"
+=>"𪉑"
+=>"𫜃"
+=>"𫛴"
+=>"𪉊"
+=>"𫜁"
+=>"𫜄"
+=>"𫛢"
+=>"𫛟"
+=>"𪎊"
+=>"𤿲"
+=>"𪎉"
+=>"𪎌"
+=>"𫜑"
+=>"𫜩"
+=>"𫜪"
+=>"𫜭"
+=>"𫜬"
+=>"𫜮"
+=>"𫜰"
diff --git a/maintenance/language/zhtable/simp2trad_supp_set.manual b/maintenance/language/zhtable/simp2trad_supp_set.manual
new file mode 100644
index 00000000..a5038a5d
--- /dev/null
+++ b/maintenance/language/zhtable/simp2trad_supp_set.manual
@@ -0,0 +1,2 @@
+余 餘
+着 著 \ No newline at end of file
diff --git a/maintenance/language/zhtable/simpphrases.manual b/maintenance/language/zhtable/simpphrases.manual
new file mode 100644
index 00000000..d8602fec
--- /dev/null
+++ b/maintenance/language/zhtable/simpphrases.manual
@@ -0,0 +1,2239 @@
+乾上乾下
+乾为天
+乾为阳
+乾九
+乾乾
+乾亨
+乾仪
+乾位
+乾健
+乾元
+乾光
+乾兴
+乾冈
+乾刘
+乾刚
+乾化
+乾卦
+乾县
+乾台
+乾吉
+乾启
+乾命
+乾和
+乾嘉
+乾图
+乾坤
+乾城
+乾基
+乾始
+乾姓
+乾宁
+乾宅
+乾宇
+乾安
+乾定
+乾封
+乾居
+乾岗
+乾巛
+乾州
+乾式
+乾录
+乾律
+乾德
+乾心
+乾文
+乾断
+乾方
+乾施
+乾旦
+乾明
+乾昧
+乾晖
+乾景
+乾晷
+乾曜
+乾构
+乾枢
+乾栋
+乾步
+乾氏
+乾泉
+乾清宫
+乾渥
+乾灵
+乾男
+乾皋
+乾盛世
+乾矢
+乾祐
+乾穹
+乾窦
+乾竺
+乾笃
+乾符
+乾策
+乾精
+乾红
+乾纲
+乾纽
+乾络
+乾统
+乾维
+乾罗
+乾花
+乾荫
+乾行
+乾衡
+乾覆
+乾象
+乾象历
+乾贞
+乾贶
+乾车
+乾轴
+乾造
+乾道
+乾鉴
+乾钧
+乾闼
+乾陀
+乾陵
+乾隆
+乾音
+乾顾
+乾风
+乾首
+乾马
+乾鹄
+乾鹊
+乾龙
+乾,健也
+乾,天也
+乾健也
+乾天也
+坤乾
+天道为乾
+尼乾陀
+康乾
+张法乾
+旋乾转坤
+易·乾
+《易乾
+周易乾
+易经·乾
+易经乾
+李乾德
+萧乾
+郭子乾
+雍乾
+乾务
+乾沓和
+乾沓婆
+乾通
+乾忠
+乾淳
+李乾顺
+黄润乾
+男性为乾
+男为乾
+阳为乾
+乾一组
+乾一坛
+陈乾生
+陈公乾生
+字乾生
+不着痕迹
+不着边际
+与着
+与著书
+与著作
+与著名
+与著录
+与著称
+与著者
+与著述
+丑着
+丑著书
+丑著作
+丑著名
+丑著录
+丑著称
+丑著者
+丑著述
+临着
+临著书
+临著作
+临著名
+临著录
+临著称
+临著者
+临著述
+丽着
+丽著书
+丽著作
+丽著名
+丽著录
+丽著称
+丽著者
+丽著述
+乐着
+乐著书
+乐著作
+乐著名
+乐著录
+乐著称
+乐著者
+乐著述
+乘着
+乘著书
+乘著作
+乘著名
+乘著录
+乘著称
+乘著者
+乘著述
+争着
+争著书
+争著作
+争著名
+争著录
+争著称
+争著者
+争著述
+亮着
+亮著书
+亮著作
+亮著名
+亮著录
+亮著称
+亮著者
+亮著述
+仗着
+仗著书
+仗著作
+仗著名
+仗著录
+仗著称
+仗著者
+仗著述
+代表着
+代表著书
+代表著作
+代表著名
+代表著录
+代表著称
+代表著者
+代表著述
+伴着
+伴著书
+伴著作
+伴著名
+伴著录
+伴著称
+伴著者
+伴著述
+低着
+低著书
+低著作
+低著名
+低著录
+低著称
+低著者
+低著述
+住着
+住著书
+住著作
+住著名
+住著录
+住著称
+住著者
+住著述
+侧着
+侧著书
+侧著作
+侧著名
+侧著录
+侧著称
+侧著者
+侧著述
+保障着
+保障著书
+保障著作
+保障著名
+保障著录
+保障著称
+保障著者
+保障著述
+信着
+信著书
+信著作
+信著名
+信著录
+信著称
+信著者
+信著述
+候着
+候著书
+候著作
+候著名
+候著录
+候著称
+候著者
+候著述
+借着
+借著书
+借著作
+借著名
+借著录
+借著称
+借著者
+借著述
+做着
+做著书
+做著作
+做著名
+做著录
+做著称
+做著者
+做著述
+偷着
+偷著书
+偷著作
+偷著名
+偷著录
+偷著称
+偷著者
+偷著述
+光着
+光著书
+光著作
+光著名
+光著录
+光著称
+光著者
+光著述
+关着
+关著书
+关著作
+关著名
+关著录
+关著称
+关著者
+关著述
+冀着
+冀著书
+冀著作
+冀著名
+冀著录
+冀著称
+冀著者
+冀著述
+冒着
+冒著书
+冒著作
+冒著名
+冒著录
+冒著称
+冒著者
+冒著述
+写着
+写著书
+写著作
+写著名
+写著录
+写著称
+写著者
+写著述
+凉着
+凉著书
+凉著作
+凉著名
+凉著录
+凉著称
+凉著者
+凉著述
+制着
+制著书
+制著作
+制著名
+制著录
+制著称
+制著者
+制著述
+刻着
+刻著书
+刻著作
+刻著名
+刻著录
+刻著称
+刻著者
+刻著述
+办着
+办著书
+办著作
+办著名
+办著录
+办著称
+办著者
+办著述
+动着
+动著书
+动著作
+动著名
+动著录
+动著称
+动著者
+动著述
+努力着
+努力著书
+努力著作
+努力著名
+努力著录
+努力著称
+努力著者
+努力著述
+努着
+努著书
+努著作
+努著名
+努著录
+努著称
+努著者
+努著述
+印着
+印著书
+印著作
+印著名
+印著录
+印著称
+印著者
+印著述
+压着
+压著书
+压著作
+压著名
+压著录
+压著称
+压著者
+压著述
+去着
+去著书
+去著作
+去著名
+去著录
+去著称
+去著者
+去著述
+受着
+受著书
+受著作
+受著名
+受著录
+受著称
+受著者
+受著述
+变着
+变著书
+变著作
+变著名
+变著录
+变著称
+变著者
+变著述
+叫着
+叫著书
+叫著作
+叫著名
+叫著录
+叫著称
+叫著者
+叫著述
+向着
+向著书
+向著作
+向著名
+向著录
+向著称
+向著者
+向著述
+含着
+含著书
+含著作
+含著名
+含著录
+含著称
+含著者
+含著述
+听得着
+听不着
+听着
+听著书
+听著作
+听著名
+听著录
+听著称
+听著者
+听著述
+吹着
+吹著书
+吹著作
+吹著名
+吹著录
+吹著称
+吹著者
+吹著述
+味着
+味著书
+味著作
+味著名
+味著录
+味著称
+味著者
+味著述
+响着
+响著书
+响著作
+响著名
+响著录
+响著称
+响著者
+响著述
+哭着
+哭著书
+哭著作
+哭著名
+哭著录
+哭著称
+哭著者
+哭著述
+唱着
+唱著书
+唱著作
+唱著名
+唱著录
+唱著称
+唱著者
+唱著述
+喝着
+喝著书
+喝著作
+喝著名
+喝著录
+喝著称
+喝著者
+喝著述
+嚷着
+嚷著书
+嚷著作
+嚷著名
+嚷著录
+嚷著称
+嚷著者
+嚷著述
+因着
+因著书
+因著作
+因著名
+因著录
+因著称
+因著者
+因著述
+困着
+困著书
+困著作
+困著名
+困著录
+困著称
+困著者
+困著述
+围着
+围著书
+围著作
+围著名
+围著录
+围著称
+围著者
+围著述
+在着
+在著书
+在著作
+在著名
+在著录
+在著称
+在著者
+在著述
+坐着
+坐著书
+坐著作
+坐著名
+坐著录
+坐著称
+坐著者
+坐著述
+备着
+备著书
+备著作
+备著名
+备著录
+备著称
+备著者
+备著述
+夹着
+夹著书
+夹著作
+夹著名
+夹著录
+夹著称
+夹著者
+夹著述
+孤着
+孤著书
+孤著作
+孤著名
+孤著录
+孤著称
+孤著者
+孤著述
+学着
+学著书
+学著作
+学著名
+学著录
+学著称
+学著者
+学著述
+守着
+守著书
+守著作
+守著名
+守著录
+守著称
+守著者
+守著述
+定着
+定著书
+定著作
+定著名
+定著录
+定著称
+定著者
+定著述
+对着
+对著书
+对著作
+对著名
+对著录
+对著称
+对著者
+对著述
+寻着
+寻著书
+寻著作
+寻著名
+寻著录
+寻著称
+寻著者
+寻著述
+展着
+展著书
+展著作
+展著名
+展著录
+展著称
+展著者
+展著述
+带着
+带著书
+带著作
+带著名
+带著录
+带著称
+带著者
+带著述
+帮着
+帮著书
+帮著作
+帮著名
+帮著录
+帮著称
+帮著者
+帮著述
+应着
+应著书
+应著作
+应著名
+应著录
+应著称
+应著者
+应著述
+康着
+康著书
+康著作
+康著名
+康著录
+康著称
+康著者
+康著述
+开着
+开著书
+开著作
+开著名
+开著录
+开著称
+开著者
+开著述
+当着
+当著书
+当著作
+当著名
+当著录
+当著称
+当著者
+当著述
+待着
+待著书
+待著作
+待著名
+待著录
+待著称
+待著者
+待著述
+得着
+得著书
+得著作
+得著名
+得著录
+得著称
+得著者
+得著述
+循着
+循著书
+循著作
+循著名
+循著录
+循著称
+循著者
+循著述
+心着
+心著书
+心著作
+心著名
+心著录
+心著称
+心著者
+心著述
+忍着
+忍著书
+忍著作
+忍著名
+忍著录
+忍著称
+忍著者
+忍著述
+志着
+志著书
+志著作
+志著名
+志著录
+志著称
+志著者
+志著述
+忙着
+忙著书
+忙著作
+忙著名
+忙著录
+忙著称
+忙著者
+忙著述
+怀着
+怀著书
+怀著作
+怀著名
+怀著录
+怀著称
+怀著者
+怀著述
+急着
+急著书
+急著作
+急著名
+急著录
+急著称
+急著者
+急著述
+性着
+性著书
+性著作
+性著名
+性著录
+性著称
+性著者
+性著述
+恋着
+恋著书
+恋著作
+恋著名
+恋著录
+恋著称
+恋著者
+恋著述
+悠着
+悠著书
+悠著作
+悠著名
+悠著录
+悠著称
+悠著者
+悠著述
+惯着
+惯著书
+惯著作
+惯著名
+惯著录
+惯著称
+惯著者
+惯著述
+想着
+想著书
+想著作
+想著名
+想著录
+想著称
+想著者
+想著述
+战着
+战著书
+战著作
+战著名
+战著录
+战著称
+战著者
+战著述
+戴着
+戴著书
+戴著作
+戴著名
+戴著录
+戴著称
+戴著者
+戴著述
+扎着
+扎著书
+扎著作
+扎著名
+扎著录
+扎著称
+扎著者
+扎著述
+打着
+打著书
+打著作
+打著名
+打著录
+打著称
+打著者
+打著述
+扛着
+扛著书
+扛著作
+扛著名
+扛著录
+扛著称
+扛著者
+扛著述
+找得着
+找不着
+抓着
+抓著作
+抓著名
+抓著录
+抓著称
+抓著者
+抓著述
+披着
+披著书
+披著作
+披著名
+披著录
+披著称
+披著者
+披著述
+抬着
+抬著作
+抬著名
+抬著录
+抬著称
+抬著者
+抬著述
+抱着
+抱著作
+抱著名
+抱著录
+抱著称
+抱著者
+抱著述
+拉着
+拉著书
+拉著作
+拉著名
+拉著录
+拉著称
+拉著者
+拉著述
+拎着
+拎著作
+拎著名
+拎著录
+拎著称
+拎著者
+拎著述
+拖着
+拖著作
+拖著名
+拖著录
+拖著称
+拖著者
+拖著述
+拼着
+拼著作
+拼著名
+拼著录
+拼著称
+拼著者
+拼著述
+拿着
+拿著作
+拿著名
+拿著录
+拿著称
+拿著者
+拿著述
+持着
+持著作
+持著名
+持著录
+持著称
+持著者
+持著述
+挑着
+挑著作
+挑著名
+挑著录
+挑著称
+挑著者
+挑著述
+挡着
+挡著作
+挡著名
+挡著录
+挡著称
+挡著者
+挡著述
+挣着
+挣著书
+挣著作
+挣著名
+挣著录
+挣著称
+挣著者
+挣著述
+挥着
+挥著作
+挥著名
+挥著录
+挥著称
+挥著者
+挥著述
+挨着
+挨著作
+挨著名
+挨著录
+挨著称
+挨著者
+挨著述
+捆着
+捆著作
+捆著名
+捆著录
+捆著称
+捆著者
+捆著述
+据着
+据著书
+据著作
+据著名
+据著录
+据著称
+据著者
+据著述
+掖着
+掖著作
+掖著名
+掖著录
+掖著称
+掖著者
+掖著述
+接着
+接著作
+接著名
+接著录
+接著称
+接著者
+接著述
+揉着
+揉著书
+揉著作
+揉著名
+揉著录
+揉著称
+揉著者
+揉著述
+提着
+提著作
+提著名
+提著录
+提著称
+提著者
+提著述
+搂着
+搂著作
+搂著名
+搂著录
+搂著称
+搂著者
+搂著述
+摆着
+摆著作
+摆著名
+摆著录
+摆著称
+摆著者
+摆著述
+撼着
+撼著书
+撼著作
+撼著名
+撼著录
+撼著称
+撼著者
+撼著述
+敞着
+敞著作
+敞著名
+敞著录
+敞著称
+敞著者
+敞著述
+数着
+数著作
+数著名
+数著录
+数著称
+数著者
+数著述
+斗着
+斗著书
+斗著作
+斗著名
+斗著录
+斗著称
+斗著者
+斗著述
+斥着
+斥著书
+斥著作
+斥著名
+斥著录
+斥著称
+斥著者
+斥著述
+昂着
+昂著书
+昂著作
+昂著名
+昂著录
+昂著称
+昂著者
+昂著述
+映着
+映著书
+映著作
+映著名
+映著录
+映著称
+映著者
+映著述
+晃着
+晃著作
+晃著名
+晃著录
+晃著称
+晃著者
+晃著述
+暗着
+暗著书
+暗著作
+暗著名
+暗著录
+暗著称
+暗著者
+暗著述
+有着
+有著书
+有著作
+有著名
+有著录
+有著称
+有著者
+有著述
+望着
+望著作
+望著名
+望著录
+望著称
+望著者
+望著述
+朝着
+朝著作
+朝著名
+朝著录
+朝著称
+朝著者
+朝著述
+本着
+本著书
+本著作
+本著名
+本著录
+本著称
+本著者
+本著述
+杀着
+杀著书
+杀著作
+杀著名
+杀著录
+杀著称
+杀著者
+杀著述
+杂着
+杂著书
+杂著作
+杂著名
+杂著录
+杂著称
+杂著者
+杂著述
+来着
+来著书
+来著作
+来著名
+来著录
+来著称
+来著者
+来著述
+枕着
+枕著作
+枕著名
+枕著录
+枕著称
+枕著者
+枕著述
+梦着
+梦著书
+梦著作
+梦著名
+梦著录
+梦著称
+梦著者
+梦著述
+梳着
+梳著作
+梳著名
+梳著录
+梳著称
+梳著者
+梳著述
+求着
+求著书
+求著作
+求著名
+求著录
+求著称
+求著者
+求著述
+沉着
+沉著书
+沉著作
+沉著名
+沉著录
+沉著称
+沉著者
+沉著述
+沿着
+沿著书
+沿著作
+沿著名
+沿著录
+沿著称
+沿著者
+沿著述
+活着
+活著书
+活著作
+活著名
+活著录
+活著称
+活著者
+活著述
+流着
+流著书
+流著作
+流著名
+流著录
+流著称
+流著者
+流著述
+浮着
+浮著书
+浮著作
+浮著名
+浮著录
+浮著称
+浮著者
+浮著述
+润着
+润著书
+润著作
+润著名
+润著录
+润著称
+润著者
+润著述
+涵着
+涵著书
+涵著作
+涵著名
+涵著录
+涵著称
+涵著者
+涵著述
+渴着
+渴著书
+渴著作
+渴著名
+渴著录
+渴著称
+渴著者
+渴著述
+溢着
+溢著书
+溢著作
+溢著名
+溢著录
+溢著称
+溢著者
+溢著述
+演着
+演著书
+演著作
+演著名
+演著录
+演著称
+演著者
+演著述
+漫着
+漫著书
+漫著作
+漫著名
+漫著录
+漫著称
+漫著者
+漫著述
+点着
+点著作
+点著名
+点著录
+点著称
+点著者
+点著述
+烧着
+烧著作
+烧著名
+烧著录
+烧著称
+烧著者
+烧著述
+照着
+照著书
+照著作
+照著名
+照著录
+照著称
+照著者
+照著述
+爱着
+爱著书
+爱著作
+爱著名
+爱著录
+爱著称
+爱著者
+爱著述
+牵着
+牵著书
+牵著作
+牵著名
+牵著录
+牵著称
+牵著者
+牵著述
+犯得着
+犯不着
+独着
+独著书
+独著作
+独著名
+独著录
+独著称
+独著者
+独著述
+猜着
+猜着书
+猜著作
+猜著名
+猜著录
+猜著称
+猜著者
+猜著述
+甜着
+甜著书
+甜著作
+甜著名
+甜著录
+甜著称
+甜著者
+甜著述
+用得着
+用不着
+用着
+用著书
+用著作
+用著名
+用著录
+用著称
+用著者
+用著述
+留着
+留着书
+留著作
+留著名
+留著录
+留著称
+留著者
+留著述
+疑着
+疑著书
+疑著作
+疑著名
+疑著录
+疑著称
+疑著者
+疑著述
+皱着
+皱著书
+皱著作
+皱著名
+皱著录
+皱著称
+皱著者
+皱著述
+盛着
+盛著书
+盛著作
+盛著名
+盛著录
+盛著称
+盛著者
+盛著述
+盯着
+盯着书
+盯著作
+盯著名
+盯著录
+盯著称
+盯著者
+盯著述
+盾着
+盾著书
+盾著作
+盾著名
+盾著录
+盾著称
+盾著者
+盾著述
+看得着
+看不着
+看着
+看着书
+看著作
+看著名
+看著录
+看著称
+看著者
+看著述
+瞧着
+瞧着书
+瞧著作
+瞧著名
+瞧著录
+瞧著称
+瞧著者
+瞧著述
+着业
+着丝
+着么
+着人
+着什么急
+着他
+着令
+着位
+着体
+着你
+着便
+着凉
+着力
+着劲
+着号
+着呢
+着哩
+着地
+着墨
+着声
+着处
+着她
+着妳
+着姓
+着它
+着定
+着实
+着己
+着帐
+着床
+着庸
+着式
+着录
+着心
+着志
+着忙
+着急
+着恼
+着惊
+着想
+着意
+着慌
+着我
+着手
+着抹
+着摸
+着撰
+着数
+着明
+着末
+着极
+着格
+着棋
+着槁
+着气
+着法
+着浅
+着火
+着然
+着甚
+着生
+着疑
+着白
+着相
+着眼
+着着
+着祂
+着积
+着稿
+着笔
+着籍
+着紧
+着緑
+着绊
+着绩
+着绯
+着绿
+着肉
+着脚
+着舰
+着色
+着节
+着花
+着莫
+着落
+着藁
+着衣
+着装
+着要
+着警
+着趣
+着边
+着迷
+着迹
+着重
+着録
+着闻
+着陆
+着雝
+着鞭
+着题
+着魔
+睡得着
+睡不着
+睡着
+睡著书
+睡著作
+睡著名
+睡著录
+睡著称
+睡著者
+睡著述
+瞒着
+瞒著书
+瞒著作
+瞒著名
+瞒著录
+瞒著称
+瞒著者
+瞒著述
+瞪着
+瞪著书
+瞪著作
+瞪著名
+瞪著录
+瞪著称
+瞪著者
+瞪著述
+福着
+福著书
+福著作
+福著名
+福著录
+福著称
+福著者
+福著述
+空着
+空著书
+空著作
+空著名
+空著录
+空著称
+空著者
+空著述
+穿着
+穿著书
+穿著作
+穿著名
+穿著录
+穿著称
+穿著者
+穿著述
+竖着
+竖著书
+竖著作
+竖著名
+竖著录
+竖著称
+竖著者
+竖著述
+站着
+站著书
+站著作
+站著名
+站著录
+站著称
+站著者
+站著述
+笑着
+笑著书
+笑著作
+笑著名
+笑著录
+笑著称
+笑著者
+笑著述
+管着
+管著书
+管著作
+管著名
+管著录
+管著称
+管著者
+管著述
+绑着
+绑著书
+绑著作
+绑著名
+绑著录
+绑著称
+绑著者
+绑著述
+绕着
+绕著书
+绕著作
+绕著名
+绕著录
+绕著称
+绕著者
+绕著述
+缠着
+缠著书
+缠著作
+缠著名
+缠著录
+缠著称
+缠著者
+缠著述
+罩着
+罩著书
+罩著作
+罩著名
+罩著录
+罩著称
+罩著者
+罩著述
+美着
+美著书
+美著作
+美著名
+美著录
+美著称
+美著者
+美著述
+耀着
+耀著书
+耀著作
+耀著名
+耀著录
+耀著称
+耀著者
+耀著述
+考着
+考著书
+考著作
+考著名
+考著录
+考著称
+考著者
+考著述
+背着
+背著书
+背著作
+背著名
+背著录
+背著称
+背著者
+背著述
+胶着
+胶著书
+胶著作
+胶著名
+胶著录
+胶著称
+胶著者
+胶著述
+艺着
+艺著书
+艺著作
+艺著名
+艺著录
+艺著称
+艺著者
+艺著述
+苦着
+苦著书
+苦著作
+苦著名
+苦著录
+苦著称
+苦著者
+苦著述
+获着
+获著书
+获著作
+获著名
+获著录
+获著称
+获著者
+获著述
+落着
+落著书
+落著作
+落著名
+落著录
+落著称
+落著者
+落著述
+蒙着
+蒙著书
+蒙著作
+蒙著名
+蒙著录
+蒙著称
+蒙著者
+蒙著述
+藏着
+藏著书
+藏著作
+藏著名
+藏著录
+藏著称
+藏著者
+藏著述
+蘸着
+蘸著书
+蘸著作
+蘸著名
+蘸著录
+蘸著称
+蘸著者
+蘸著述
+行着
+行著书
+行著作
+行著名
+行著录
+行著称
+行著者
+行著述
+衣着
+衣著书
+衣著作
+衣著名
+衣著录
+衣著称
+衣著者
+衣著述
+装着
+装著书
+装著作
+装著名
+装著录
+装著称
+装著者
+装著述
+裹着
+裹著书
+裹著作
+裹著名
+裹著录
+裹著称
+裹著者
+裹著述
+见着
+见著书
+见著作
+见著名
+见著录
+见著称
+见著者
+见著述
+记着
+记著书
+记著作
+记著名
+记著录
+记著称
+记著者
+记著述
+试着
+试著书
+试著作
+试著名
+试著录
+试著称
+试著者
+试著述
+语着
+语著书
+语著作
+语著名
+语著录
+语著称
+语著者
+语著述
+豫着
+豫著书
+豫著作
+豫著名
+豫著录
+豫著称
+豫著者
+豫著述
+贞着
+贞著书
+贞著作
+贞著名
+贞著录
+贞著称
+贞著者
+贞著述
+走着
+走著书
+走著作
+走著名
+走著录
+走著称
+走著者
+走著述
+赶着
+赶著书
+赶著作
+赶著名
+赶著录
+赶著称
+赶著者
+赶著述
+趴着
+趴著书
+趴著作
+趴著名
+趴著录
+趴著称
+趴著者
+趴著述
+跃着
+跃著书
+跃著作
+跃著名
+跃著录
+跃著称
+跃著者
+跃著述
+跑着
+跑著书
+跑著作
+跑著名
+跑著录
+跑著称
+跑著者
+跑著述
+跟着
+跟著书
+跟著作
+跟著名
+跟著录
+跟著称
+跟著者
+跟著述
+跪着
+跪著书
+跪著作
+跪著名
+跪著录
+跪著称
+跪著者
+跪著述
+跳着
+跳著书
+跳著作
+跳著名
+跳著录
+跳著称
+跳著者
+跳著述
+踏着
+踏著书
+踏著作
+踏著名
+踏著录
+踏著称
+踏著者
+踏著述
+踩着
+踩著书
+踩著作
+踩著名
+踩著录
+踩著称
+踩著者
+踩著述
+身着
+身著书
+身著作
+身著名
+身著录
+身著称
+身著者
+身著述
+躺着
+躺著书
+躺著作
+躺著名
+躺著录
+躺著称
+躺著者
+躺著述
+转着
+转著书
+转著作
+转著名
+转著录
+转著称
+转著者
+转著述
+载着
+载著书
+载著作
+载著名
+载著录
+载著称
+载著者
+载著述
+达着
+达著书
+达著作
+达著名
+达著录
+达著称
+达著者
+达著述
+远着
+远著书
+远著作
+远著名
+远著录
+远著称
+远著者
+远著述
+连着
+连著书
+连著作
+连著名
+连著录
+连著称
+连著者
+连著述
+追着
+追著书
+追著作
+追著名
+追著录
+追著称
+追著者
+追著述
+逆着
+逆著书
+逆著作
+逆著名
+逆著录
+逆著称
+逆著者
+逆著述
+逼着
+逼著书
+逼著作
+逼著名
+逼著录
+逼著称
+逼著者
+逼著述
+遇着
+遇著书
+遇著作
+遇著名
+遇著录
+遇著称
+遇著者
+遇著述
+配着
+配著书
+配著作
+配著名
+配著录
+配著称
+配著者
+配著述
+酿着
+酿著书
+酿著作
+酿著名
+酿著录
+酿著称
+酿著者
+酿著述
+铺着
+铺著书
+铺著作
+铺著名
+铺著录
+铺著称
+铺著者
+铺著述
+闭着
+闭著书
+闭著作
+闭著名
+闭著录
+闭著称
+闭著者
+闭著述
+闲着
+闲著书
+闲著作
+闲著名
+闲著录
+闲著称
+闲著者
+闲著述
+附着
+附著书
+附著作
+附著名
+附著录
+附著称
+附著者
+附著述
+陋着
+陋著书
+陋著作
+陋著名
+陋著录
+陋著称
+陋著者
+陋著述
+陪着
+陪著书
+陪著作
+陪著名
+陪著录
+陪著称
+陪著者
+陪著述
+随着
+随著书
+随著作
+随著名
+随著录
+随著称
+随著者
+随著述
+隔着
+隔著书
+隔著作
+隔著名
+隔著录
+隔著称
+隔著者
+隔著述
+雅着
+雅著书
+雅著作
+雅著名
+雅著录
+雅著称
+雅著者
+雅著述
+顶着
+顶著书
+顶著作
+顶著名
+顶著录
+顶著称
+顶著者
+顶著述
+顺着
+顺著书
+顺著作
+顺著名
+顺著录
+顺著称
+顺著者
+顺著述
+领着
+领著书
+领著作
+领著名
+领著录
+领著称
+领著者
+领著述
+飘着
+飘著书
+飘著作
+飘著名
+飘著录
+飘著称
+飘著者
+飘著述
+驾着
+驾著书
+驾著作
+驾著名
+驾著录
+驾著称
+驾著者
+驾著述
+骂着
+骂著书
+骂著作
+骂著名
+骂著录
+骂著称
+骂著者
+骂著述
+骑着
+骑著书
+骑著作
+骑著名
+骑著录
+骑著称
+骑著者
+骑著述
+骗着
+骗著书
+骗著作
+骗著名
+骗著录
+骗著称
+骗著者
+骗著述
+高着
+高著书
+高著作
+高著名
+高著录
+高著称
+高著者
+高著述
+髭着
+髭著书
+髭著作
+髭著名
+髭著录
+髭著称
+髭著者
+髭著述
+黏着
+黏著书
+黏著作
+黏著名
+黏著录
+黏著称
+黏著者
+黏著述
+新著龙虎门
+护着
+护著书
+护著作
+护著名
+护著录
+护著称
+护著者
+护著述
+保护着
+爱护着
+庇护着
+传着
+传著书
+传著作
+传著名
+传著录
+传著称
+传著者
+传著述
+标志着
+流露着
+靠着
+靠著作
+靠著名
+靠著录
+靠著称
+靠著者
+靠著述
+玩着
+迫着
+吃得着
+吃不着
+吃着
+闻得着
+闻不着
+闻着
+嗅得着
+嗅不着
+嗅着
+警戒着
+於乎
+於戏
+魏徵
+柳诒徵
+於姓
+於氏
+於夫罗
+於梨华
+卷舌
+樊於期
+於菟
+於潜县
+石碁镇
+因著《
+因著〈
+李泽钜
+於祥玉
+於崇文
+於世成
+於乙宇同
+於宇同
+朴於宇同
+於哲
+於除鞬
+於志贺
+覆蓋
+五箇山
+麽麽
+幺厮
+幺半群
+幺元
+幺爹
+幺叔
+幺舅
+幺爸
+幺妈
+幺姨
+幺娘
+幺妹
+幺小
+幺姓
+姓幺
+幺氏
+麽氏
+幺蛾子
+幺麽
+幺麽小丑
+幺凤
+幺二三
+幺篇
+幺谦
+麴义
+麴英
+麯崇裕
+阿部正瞭
+醯酱
+醯鸡
+醯醋
+醯醢
+醯壶
+苧烯
+近角聪信
+米泽瑠美
+峯岸南
+僧伽吒
+王道乾
+後姓
diff --git a/maintenance/language/zhtable/simpphrases_exclude.manual b/maintenance/language/zhtable/simpphrases_exclude.manual
new file mode 100644
index 00000000..3e9d3ecc
--- /dev/null
+++ b/maintenance/language/zhtable/simpphrases_exclude.manual
@@ -0,0 +1,21 @@
+整飭
+後
+谘
+彷佛
+三番四复
+三复
+藉
+关於
+对於
+属於
+至於
+夥计
+薹
+嚇
+醣
+捱
+簑
+樑
+摺叠
+餗
+安甯 \ No newline at end of file
diff --git a/maintenance/language/zhtable/toCN.manual b/maintenance/language/zhtable/toCN.manual
new file mode 100644
index 00000000..243f61b0
--- /dev/null
+++ b/maintenance/language/zhtable/toCN.manual
@@ -0,0 +1,275 @@
+」 ”
+「 “
+『 ‘
+』 ’
+記憶體 内存
+預設 默认
+串列 串行
+串列加速器 串列加速器
+乙太網 以太网
+點陣圖 位图
+常式 例程
+光碟 光盘
+光碟機 光驱
+全形 全角
+載入 加载
+半形 半角
+變數 变量
+雜訊 噪声
+因數 因子
+功能變數名稱 域名
+音效卡 声卡
+字型大小 字号
+字型檔 字库
+欄位 字段
+字元 字符
+字元济 字元济
+字元濟 字元济
+字元会 字元会
+字元會 字元会
+存檔 存盘
+定址 寻址
+章節附註 尾注
+非同步 异步
+匯流排 总线
+括弧 括号
+介面 接口
+控制項 控件
+許可權 权限
+碟片 盘片
+矽片 硅片
+矽谷 硅谷
+硬碟 硬盘
+磁碟 磁盘
+磁軌 磁道
+程式控制 程控
+遠程控制 远程控制
+远程控制 远程控制
+運算元 算子
+演算法 算法
+晶片 芯片
+晶元 芯片
+片語 词组
+軟碟機 软驱
+快閃記憶體 快闪存储器
+滑鼠 鼠标
+滑鼠蛇 滑鼠蛇
+二進位 二进制
+滿二進位 满二进位
+六進位 六进制
+滿六進位 满六进位
+滿十六進位 满十六进位
+八進位 八进制
+滿八進位 满八进位
+十進位 十进制
+滿十進位 满十进位
+16進位 16进位
+滿16進位 满16进位
+二進位制 二进位制
+六進位制 六进位制
+八進位制 八进位制
+十進位制 十进位制
+16進位制 16进位制
+互動式 交互式
+優先順序 优先级
+感測 传感
+攜帶型 便携式
+資訊理論 信息论
+迴圈 循环
+防寫 写保护
+解析度 分辨率
+伺服器 服务器
+等於 等于
+區域網 局域网
+巨集 宏
+掃瞄器 扫瞄仪
+寬頻 宽带
+資料庫 数据库
+萬曆 万历
+永曆 永历
+辭彙 词汇
+母音 元音
+字母 字母
+頭槌 头球
+進球 入球
+顆進球 粒入球
+射門 打门
+蓋火鍋 火锅盖帽
+印表機 打印机
+打印機 打印机
+位元組 字节
+字節 字节
+列印 打印
+打印 打印
+硬體 硬件
+二極體 二极管
+二極管 二极管
+三極體 三极管
+三極管 三极管
+軟體 软件
+軟件 软件
+網路 网络
+網絡 网络
+人工智慧 人工智能
+太空梭 航天飞机
+穿梭機 航天飞机
+網際網路 互联网
+互聯網 互联网
+機械人 机器人
+機器人 机器人
+行動電話 移动电话
+流動電話 移动电话
+調制解調器 调制解调器
+數據機 调制解调器
+短訊 短信
+簡訊 短信
+烏茲別克 乌兹别克斯坦
+葉門 也门
+伯利茲 伯利兹
+貝里斯 伯利兹
+維德角 佛得角
+克羅埃西亞 克罗地亚
+甘比亞 冈比亚
+幾內亞比索 几内亚比绍
+列支敦斯登 列支敦士登
+賴比瑞亞 利比里亚
+迦納 加纳
+加彭 加蓬
+波札那 博茨瓦纳
+盧安達 卢旺达
+瓜地馬拉 危地马拉
+厄瓜多爾 厄瓜多尔
+厄瓜多尔 厄瓜多尔
+厄瓜多 厄瓜多尔
+厄利垂亞 厄立特里亚
+吉布地 吉布提
+哈薩克 哈萨克斯坦
+哥斯大黎加 哥斯达黎加
+吐瓦魯 图瓦卢
+土庫曼 土库曼斯坦
+聖露西亞 圣卢西亚
+聖吉斯納域斯 圣基茨和尼维斯
+聖克里斯多福及尼維斯 圣基茨和尼维斯
+聖文森及格瑞那丁 圣文森特和格林纳丁斯
+聖馬利諾 圣马力诺
+蓋亞那 圭亚那
+坦尚尼亞 坦桑尼亚
+衣索匹亞 埃塞俄比亚
+衣索比亞 埃塞俄比亚
+吉里巴斯 基里巴斯
+塔吉克 塔吉克斯坦
+塞拉利昂 塞拉利昂
+塞普勒斯 塞浦路斯
+塞席爾 塞舌尔
+多米尼克 多米尼加国
+安地卡及巴布達 安提瓜和巴布达
+尼日利亞 尼日利亚
+尼日利亚 尼日利亚
+奈及利亞 尼日利亚
+尼日爾 尼日尔
+尼日尔 尼日尔
+巴貝多 巴巴多斯
+巴布亞紐幾內亞 巴布亚新几内亚
+布基納法索 布基纳法索
+布吉納法索 布基纳法索
+蒲隆地 布隆迪
+帛琉 帕劳
+義大利 意大利
+索羅門群島 所罗门群岛
+汶萊 文莱
+史瓦濟蘭 斯威士兰
+斯洛維尼亞 斯洛文尼亚
+紐西蘭 新西兰
+格瑞那達 格林纳达
+茅利塔尼亞 毛里塔尼亚
+毛里裘斯 毛里求斯
+模里西斯 毛里求斯
+沙地阿拉伯 沙特阿拉伯
+沙烏地阿拉伯 沙特阿拉伯
+波士尼亞赫塞哥維納 波斯尼亚和黑塞哥维那
+辛巴威 津巴布韦
+宏都拉斯 洪都拉斯
+千里達托貝哥 特立尼达和托巴哥
+諾魯 瑙鲁
+萬那杜 瓦努阿图
+溫納圖 瓦努阿图
+葛摩 科摩罗
+象牙海岸 科特迪瓦
+突尼西亞 突尼斯
+索馬利亞 索马里
+寮國 老挝
+肯雅 肯尼亚
+肯亞 肯尼亚
+蘇利南 苏里南
+莫三比克 莫桑比克
+賴索托 莱索托
+貝南 贝宁
+尚比亞 赞比亚
+亞塞拜然 阿塞拜疆
+阿拉伯聯合大公國 阿拉伯联合酋长国
+南韓 韩国
+馬爾地夫 马尔代夫
+馬爾他 马耳他
+馬利共和國 马里共和国
+即食麵 方便面
+快速面 方便面
+速食麵 方便面
+泡麵 方便面
+笨豬跳 蹦极跳
+绑紧跳 蹦极跳
+冷盤 凉菜
+冷菜 凉菜
+散钱 零钱
+谐星 笑星
+夜学 夜校
+华乐 民乐
+中樂 民乐
+軍中樂園 军中乐园
+华乐街 华乐街
+屋价 房价
+計程車 出租车
+單車 自行车
+節慶 节日
+芝士 乾酪
+狗隻 犬只
+士多啤梨 草莓
+忌廉 奶油
+桌球 台球
+撞球 台球
+衞生 卫生
+衛生 卫生
+賓士 奔驰
+平治 奔驰
+平治之亂 平治之乱
+平治之乱 平治之乱
+積架 捷豹
+福斯 大众
+福士 大众
+萬事得 马自达
+寶獅 标志
+拿破崙 拿破仑
+布殊 布什
+布希 布什
+布希亞 布希亚
+布希亚 布希亚
+柯林頓 克林顿
+海珊 侯赛因
+梵谷 凡高
+大衛碧咸 大卫·贝克汉姆
+米高奧雲 迈克尔·欧文
+卡佩雅蒂 珍妮弗·卡普里亚蒂
+沙芬 马拉特·萨芬
+舒麥加 迈克尔·舒马赫
+希特拉 希特勒
+黛安娜 戴安娜
+榴槤 榴莲
+榴梿 榴莲
+矽 硅
+矽肺 矽肺
+矽塵 矽尘
+矽尘 矽尘
+矽鋼 矽钢
+矽钢 矽钢
+侏儸紀 侏罗纪
+甚麽 什么
+甚麼 什么
diff --git a/maintenance/language/zhtable/toHK.manual b/maintenance/language/zhtable/toHK.manual
new file mode 100644
index 00000000..1f7fe7d0
--- /dev/null
+++ b/maintenance/language/zhtable/toHK.manual
@@ -0,0 +1,2300 @@
+” 」
+“ 「
+‘ 『
+’ 』
+鉤 鈎
+衛 衞
+凶殺 兇殺
+凶殘 兇殘
+緝凶 緝兇
+買凶 買兇
+印表機 打印機
+字节 位元組
+字節 位元組
+列印 打印
+硬件 硬件
+硬體 硬件
+二極體 二極管
+三極體 三極管
+軟體 軟件
+網路 網絡
+人工智慧 人工智能
+航天飞机 穿梭機
+太空梭 穿梭機
+因特网 互聯網
+網際網路 互聯網
+机器人 機械人
+機器人 機械人
+移动电话 流動電話
+行動電話 流動電話
+數據機 調制解調器
+短信 短訊
+簡訊 短訊
+查德 乍得
+葉門 也門
+貝里斯 伯利茲
+維德角 佛得角
+克羅埃西亞 克羅地亞
+甘比亞 岡比亞
+幾內亞比索 幾內亞比紹
+列支敦斯登 列支敦士登
+賴比瑞亞 利比里亞
+迦納 加納
+加彭 加蓬
+波札那 博茨瓦納
+盧安達 盧旺達
+瓜地馬拉 危地馬拉
+厄瓜多尔 厄瓜多爾
+厄瓜多爾 厄瓜多爾
+厄瓜多 厄瓜多爾
+厄利垂亞 厄立特里亞
+吉布地 吉布堤
+哥斯大黎加 哥斯達黎加
+吐瓦魯 圖瓦盧
+聖露西亞 聖盧西亞
+圣基茨和尼维斯 聖吉斯納域斯
+聖克里斯多福及尼維斯 聖吉斯納域斯
+聖文森及格瑞那丁 聖文森特和格林納丁斯
+聖馬利諾 聖馬力諾
+蓋亞那 圭亞那
+坦尚尼亞 坦桑尼亞
+衣索匹亞 埃塞俄比亞
+衣索比亞 埃塞俄比亞
+吉里巴斯 基里巴斯
+塞普勒斯 塞浦路斯
+塞席爾 塞舌爾
+安地卡及巴布達 安提瓜和巴布達
+尼日利亚 尼日利亞
+尼日利亞 尼日利亞
+奈及利亞 尼日利亞
+尼日尔 尼日爾
+尼日爾 尼日爾
+尼日 尼日爾
+巴貝多 巴巴多斯
+巴布亞紐幾內亞 巴布亞新畿內亞
+布吉納法索 布基納法索
+蒲隆地 布隆迪
+帕劳 帛琉
+義大利 意大利
+索羅門群島 所羅門群島
+文莱 汶萊
+史瓦濟蘭 斯威士蘭
+斯洛維尼亞 斯洛文尼亞
+紐西蘭 新西蘭
+格瑞那達 格林納達
+茅利塔尼亞 毛里塔尼亞
+毛里求斯 毛里裘斯
+模里西斯 毛里裘斯
+沙地阿拉伯 沙特阿拉伯
+沙烏地阿拉伯 沙特阿拉伯
+波士尼亞赫塞哥維納 波斯尼亞黑塞哥維那
+辛巴威 津巴布韋
+宏都拉斯 洪都拉斯
+千里達托貝哥 特立尼達和多巴哥
+諾魯 瑙魯
+萬那杜 瓦努阿圖
+葛摩 科摩羅
+索馬利亞 索馬里
+寮國 老撾
+肯尼亚 肯雅
+肯亞 肯雅
+莫三比克 莫桑比克
+賴索托 萊索托
+貝南 貝寧
+尚比亞 贊比亞
+亞塞拜然 阿塞拜疆
+阿拉伯聯合大公國 阿拉伯聯合酋長國
+馬爾地夫 馬爾代夫
+馬利共和國 馬里共和國
+方便面 即食麵
+快速面 即食麵
+速食麵 即食麵
+泡麵 即食麵
+土豆 馬鈴薯
+土豆网 土豆網
+土豆網 土豆網
+华乐 中樂
+民乐 中樂
+計程車 的士
+出租车 的士
+公車 巴士
+公車上書 公車上書
+自行车 單車
+犬只 狗隻
+台球 桌球
+撞球 桌球
+冰淇淋 雪糕
+賓士 平治
+捷豹 積架
+福斯 福士
+雪铁龙 先進
+雪鐵龍 先進
+沃尓沃 富豪
+马自达 萬事得
+馬自達 萬事得
+寶獅 標致
+布什 布殊
+布希 布殊
+布希亞 布希亞
+布希亚 布希亞
+柯林頓 克林頓
+萨达姆 薩達姆
+海珊 侯賽因
+大卫·贝克汉姆 大衛碧咸
+迈克尔·欧文 米高奧雲
+珍妮弗·卡普里亚蒂 卡佩雅蒂
+马拉特·萨芬 沙芬
+迈克尔·舒马赫 舒麥加
+希特勒 希特拉
+狄安娜 戴安娜
+黛安娜 戴安娜
+颁布 頒佈
+頒布 頒佈
+挨著 挨着
+愛著 愛着
+暗著 暗着
+昂著 昂着
+擺著 擺着
+伴著 伴着
+辦著 辦着
+幫著 幫着
+綁著 綁着
+抱著 抱着
+背著 背着
+備著 備着
+本著 本着
+逼著 逼着
+閉著 閉着
+變著 變着
+猜著 猜着
+踩著 踩着
+藏著 藏着
+側著 側着
+纏著 纏着
+敞著 敞着
+唱著 唱着
+朝著 朝着
+沉著 沉着
+乘著 乘着
+持著 持着
+斥著 斥着
+醜著 醜着
+穿著 穿着
+吹著 吹着
+達著 達着
+打著 打着
+待著 待着
+帶著 帶着
+戴著 戴着
+當著 當着
+擋著 擋着
+得著 得着
+瞪著 瞪着
+低著 低着
+點著 點着
+盯著 盯着
+頂著 頂着
+定著 定着
+動著 動着
+鬥著 鬥着
+獨著 獨着
+對著 對着
+盾著 盾着
+犯得著 犯得着
+犯不著 犯不着
+福著 福着
+趕著 趕着
+高著 高着
+隔著 隔着
+跟著 跟着
+孤著 孤着
+關著 關着
+管著 管着
+慣著 慣着
+光著 光着
+跪著 跪着
+裹著 裹着
+撼著 撼着
+喝著 喝着
+候著 候着
+懷著 懷着
+晃著 晃着
+揮著 揮着
+活著 活着
+獲著 獲着
+獲著 獲着
+急著 急着
+記著 記着
+冀著 冀着
+夾著 夾着
+駕著 駕着
+見著 見着
+閑著 閑着
+叫著 叫着
+接著 接着
+借著 借着
+借著 借着
+據著 據着
+開著 開着
+看得著 看得着
+看不著 看不着
+看著 看着
+康著 康着
+扛著 扛着
+考著 考着
+渴著 渴着
+刻著 刻着
+空著 空着
+哭著 哭着
+苦著 苦着
+捆著 捆着
+困著 困着
+拉著 拉着
+來著 來着
+樂著 樂着
+努力著 努力着
+麗著 麗着
+連著 連着
+戀著 戀着
+涼著 涼着
+亮著 亮着
+臨著 臨着
+拎著 拎着
+領著 領着
+流著 流着
+留著 留着
+摟著 摟着
+陋著 陋着
+落著 落着
+罵著 罵着
+瞞著 瞞着
+漫著 漫着
+忙著 忙着
+冒著 冒着
+美著 美着
+夢著 夢着
+蒙著 蒙着
+拿著 拿着
+逆著 逆着
+釀著 釀着
+努著 努着
+趴著 趴着
+跑著 跑着
+陪著 陪着
+配著 配着
+披著 披着
+騙著 騙着
+飄著 飄着
+拼著 拼着
+鋪著 鋪着
+騎著 騎着
+牽著 牽着
+求著 求着
+去著 去着
+嚷著 嚷着
+繞著 繞着
+忍著 忍着
+揉著 揉着
+潤著 潤着
+燒著 燒着
+身著 身着
+沉著 沉着
+盛著 盛着
+試著 試着
+守著 守着
+受著 受着
+梳著 梳着
+豎著 豎着
+數著 數着
+睡得著 睡得着
+睡不著 睡不着
+睡著 睡着
+順著 順着
+隨著 隨着
+踏著 踏着
+抬著 抬着
+躺著 躺着
+提著 提着
+甜著 甜着
+挑著 挑着
+跳著 跳着
+聽得著 聽得着
+聽不著 聽不着
+聽著 聽着
+偷著 偷着
+拖著 拖着
+望著 望着
+圍著 圍着
+味著 味着
+想著 想着
+響著 響着
+向著 向着
+笑著 笑着
+心著 心着
+信著 信着
+行著 行着
+性著 性着
+學著 學着
+尋著 尋着
+循著 循着
+壓著 壓着
+雅著 雅着
+沿著 沿着
+耀著 耀着
+掖著 掖着
+衣著 衣着
+疑著 疑着
+溢著 溢着
+藝著 藝着
+因著 因着
+印著 印着
+應著 應着
+映著 映着
+用得著 用得着
+用不著 用不着
+用著 用着
+悠著 悠着
+有著 有着
+與著 與着
+語著 語着
+豫著 豫着
+遠著 遠着
+躍著 躍着
+雜著 雜着
+載著 載着
+在著 在着
+紮著 紮着
+展著 展着
+站著 站着
+戰著 戰着
+蘸著 蘸着
+仗著 仗着
+找得著 找得着
+找不著 找不着
+照著 照着
+罩著 罩着
+貞著 貞着
+枕著 枕着
+爭著 爭着
+掙著 掙着
+制著 制着
+志著 志着
+皺著 皺着
+住著 住着
+抓著 抓着
+轉著 轉着
+裝著 裝着
+追著 追着
+髭著 髭着
+走著 走着
+坐著 坐着
+做著 做着
+含著 含着
+涵著 涵着
+演著 演着
+保障著 保障着
+黏著 黏着
+膠著 膠着
+附著 附着
+代表著 代表着
+浮著 浮着
+寫著 寫着
+遇著 遇着
+殺著 殺着
+著筆 着筆
+著鞭 着鞭
+著法 着法
+著火 着火
+著急 着急
+著艦 着艦
+著腳 着腳
+著她 着她
+著緊 着緊
+著力 着力
+著涼 着涼
+著陸 着陸
+著錄 着錄
+著落 着落
+著忙 着忙
+著迷 着迷
+著墨 着墨
+著妳 着妳
+著你 着你
+著色 着色
+著什麼急 着什麼急
+著實 着實
+著手 着手
+著數 着數
+著絲 着絲
+著他 着他
+著它 着它
+著祂 着祂
+著我 着我
+著想 着想
+著眼 着眼
+著衣 着衣
+著意 着意
+著重 着重
+著重 着重
+著裝 着裝
+著地 着地
+不著邊際 不着邊際
+不著痕跡 不着痕跡
+挨著作 挨著作
+挨著者 挨著者
+挨著名 挨著名
+挨著述 挨著述
+挨著稱 挨著稱
+挨著錄 挨著錄
+愛著作 愛著作
+愛著者 愛著者
+愛著名 愛著名
+愛著述 愛著述
+愛著稱 愛著稱
+愛著錄 愛著錄
+愛著書 愛著書
+暗著作 暗著作
+暗著者 暗著者
+暗著名 暗著名
+暗著述 暗著述
+暗著稱 暗著稱
+暗著錄 暗著錄
+暗著書 暗著書
+昂著作 昂著作
+昂著者 昂著者
+昂著名 昂著名
+昂著述 昂著述
+昂著稱 昂著稱
+昂著錄 昂著錄
+昂著書 昂著書
+擺著作 擺著作
+擺著者 擺著者
+擺著名 擺著名
+擺著述 擺著述
+擺著稱 擺著稱
+擺著錄 擺著錄
+伴著作 伴著作
+伴著者 伴著者
+伴著名 伴著名
+伴著述 伴著述
+伴著稱 伴著稱
+伴著錄 伴著錄
+伴著書 伴著書
+辦著作 辦著作
+辦著者 辦著者
+辦著名 辦著名
+辦著述 辦著述
+辦著稱 辦著稱
+辦著錄 辦著錄
+辦著書 辦著書
+幫著作 幫著作
+幫著者 幫著者
+幫著名 幫著名
+幫著述 幫著述
+幫著稱 幫著稱
+幫著錄 幫著錄
+幫著書 幫著書
+綁著作 綁著作
+綁著者 綁著者
+綁著名 綁著名
+綁著述 綁著述
+綁著稱 綁著稱
+綁著錄 綁著錄
+綁著書 綁著書
+抱著作 抱著作
+抱著者 抱著者
+抱著名 抱著名
+抱著述 抱著述
+抱著稱 抱著稱
+抱著錄 抱著錄
+背著作 背著作
+背著者 背著者
+背著名 背著名
+背著述 背著述
+背著稱 背著稱
+背著錄 背著錄
+背著書 背著書
+備著作 備著作
+備著者 備著者
+備著名 備著名
+備著述 備著述
+備著稱 備著稱
+備著錄 備著錄
+備著書 備著書
+本著作 本著作
+本著者 本著者
+本著名 本著名
+本著述 本著述
+本著稱 本著稱
+本著錄 本著錄
+本著書 本著書
+逼著作 逼著作
+逼著者 逼著者
+逼著名 逼著名
+逼著述 逼著述
+逼著稱 逼著稱
+逼著錄 逼著錄
+逼著書 逼著書
+閉著作 閉著作
+閉著者 閉著者
+閉著名 閉著名
+閉著述 閉著述
+閉著稱 閉著稱
+閉著錄 閉著錄
+閉著書 閉著書
+變著作 變著作
+變著者 變著者
+變著名 變著名
+變著述 變著述
+變著稱 變著稱
+變著錄 變著錄
+變著書 變著書
+猜著作 猜著作
+猜著者 猜著者
+猜著名 猜著名
+猜著述 猜著述
+猜著稱 猜著稱
+猜著錄 猜著錄
+猜著書 猜著書
+踩著作 踩著作
+踩著者 踩著者
+踩著名 踩著名
+踩著述 踩著述
+踩著稱 踩著稱
+踩著錄 踩著錄
+踩著書 踩著書
+藏著作 藏著作
+藏著者 藏著者
+藏著名 藏著名
+藏著述 藏著述
+藏著稱 藏著稱
+藏著錄 藏著錄
+藏著書 藏著書
+側著作 側著作
+側著者 側著者
+側著名 側著名
+側著述 側著述
+側著稱 側著稱
+側著錄 側著錄
+側著書 側著書
+纏著作 纏著作
+纏著者 纏著者
+纏著名 纏著名
+纏著述 纏著述
+纏著稱 纏著稱
+纏著錄 纏著錄
+纏著書 纏著書
+敞著作 敞著作
+敞著者 敞著者
+敞著名 敞著名
+敞著述 敞著述
+敞著稱 敞著稱
+敞著錄 敞著錄
+唱著作 唱著作
+唱著者 唱著者
+唱著名 唱著名
+唱著述 唱著述
+唱著稱 唱著稱
+唱著錄 唱著錄
+唱著書 唱著書
+朝著作 朝著作
+朝著者 朝著者
+朝著名 朝著名
+朝著述 朝著述
+朝著稱 朝著稱
+朝著錄 朝著錄
+沉著作 沉著作
+沉著者 沉著者
+沉著名 沉著名
+沉著述 沉著述
+沉著稱 沉著稱
+沉著錄 沉著錄
+沉著書 沉著書
+乘著作 乘著作
+乘著者 乘著者
+乘著名 乘著名
+乘著述 乘著述
+乘著稱 乘著稱
+乘著錄 乘著錄
+乘著書 乘著書
+持著作 持著作
+持著者 持著者
+持著名 持著名
+持著述 持著述
+持著稱 持著稱
+持著錄 持著錄
+斥著作 斥著作
+斥著者 斥著者
+斥著名 斥著名
+斥著述 斥著述
+斥著稱 斥著稱
+斥著錄 斥著錄
+斥著書 斥著書
+醜著作 醜著作
+醜著者 醜著者
+醜著名 醜著名
+醜著述 醜著述
+醜著稱 醜著稱
+醜著錄 醜著錄
+醜著書 醜著書
+穿著作 穿著作
+穿著者 穿著者
+穿著名 穿著名
+穿著述 穿著述
+穿著稱 穿著稱
+穿著錄 穿著錄
+穿著書 穿著書
+吹著作 吹著作
+吹著者 吹著者
+吹著名 吹著名
+吹著述 吹著述
+吹著稱 吹著稱
+吹著錄 吹著錄
+吹著書 吹著書
+達著作 達著作
+達著者 達著者
+達著名 達著名
+達著述 達著述
+達著稱 達著稱
+達著錄 達著錄
+達著書 達著書
+打著作 打著作
+打著者 打著者
+打著名 打著名
+打著述 打著述
+打著稱 打著稱
+打著錄 打著錄
+打著書 打著書
+待著作 待著作
+待著者 待著者
+待著名 待著名
+待著述 待著述
+待著稱 待著稱
+待著錄 待著錄
+待著書 待著書
+帶著作 帶著作
+帶著者 帶著者
+帶著名 帶著名
+帶著述 帶著述
+帶著稱 帶著稱
+帶著錄 帶著錄
+帶著書 帶著書
+戴著作 戴著作
+戴著者 戴著者
+戴著名 戴著名
+戴著述 戴著述
+戴著稱 戴著稱
+戴著錄 戴著錄
+戴著書 戴著書
+當著作 當著作
+當著者 當著者
+當著名 當著名
+當著述 當著述
+當著稱 當著稱
+當著錄 當著錄
+當著書 當著書
+擋著作 擋著作
+擋著者 擋著者
+擋著名 擋著名
+擋著述 擋著述
+擋著稱 擋著稱
+擋著錄 擋著錄
+得著作 得著作
+得著者 得著者
+得著名 得著名
+得著述 得著述
+得著稱 得著稱
+得著錄 得著錄
+得著書 得著書
+瞪著作 瞪著作
+瞪著者 瞪著者
+瞪著名 瞪著名
+瞪著述 瞪著述
+瞪著稱 瞪著稱
+瞪著錄 瞪著錄
+瞪著書 瞪著書
+低著作 低著作
+低著者 低著者
+低著名 低著名
+低著述 低著述
+低著稱 低著稱
+低著錄 低著錄
+低著書 低著書
+點著作 點著作
+點著者 點著者
+點著名 點著名
+點著述 點著述
+點著稱 點著稱
+點著錄 點著錄
+點著書 點著書
+盯著作 盯著作
+盯著者 盯著者
+盯著名 盯著名
+盯著述 盯著述
+盯著稱 盯著稱
+盯著錄 盯著錄
+盯著書 盯著書
+頂著作 頂著作
+頂著者 頂著者
+頂著名 頂著名
+頂著述 頂著述
+頂著稱 頂著稱
+頂著錄 頂著錄
+頂著書 頂著書
+定著作 定著作
+定著者 定著者
+定著名 定著名
+定著述 定著述
+定著稱 定著稱
+定著錄 定著錄
+定著書 定著書
+動著作 動著作
+動著者 動著者
+動著名 動著名
+動著述 動著述
+動著稱 動著稱
+動著錄 動著錄
+動著書 動著書
+鬥著作 鬥著作
+鬥著者 鬥著者
+鬥著名 鬥著名
+鬥著述 鬥著述
+鬥著稱 鬥著稱
+鬥著錄 鬥著錄
+鬥著書 鬥著書
+獨著作 獨著作
+獨著者 獨著者
+獨著名 獨著名
+獨著述 獨著述
+獨著稱 獨著稱
+獨著錄 獨著錄
+獨著書 獨著書
+對著作 對著作
+對著者 對著者
+對著名 對著名
+對著述 對著述
+對著稱 對著稱
+對著錄 對著錄
+對著書 對著書
+盾著作 盾著作
+盾著者 盾著者
+盾著名 盾著名
+盾著述 盾著述
+盾著稱 盾著稱
+盾著錄 盾著錄
+盾著書 盾著書
+犯不著作 犯不著作
+犯不著者 犯不著者
+犯不著名 犯不著名
+犯不著述 犯不著述
+犯不著稱 犯不著稱
+犯不著錄 犯不著錄
+犯不著書 犯不著書
+福著作 福著作
+福著者 福著者
+福著名 福著名
+福著述 福著述
+福著稱 福著稱
+福著錄 福著錄
+福著書 福著書
+趕著作 趕著作
+趕著者 趕著者
+趕著名 趕著名
+趕著述 趕著述
+趕著稱 趕著稱
+趕著錄 趕著錄
+趕著書 趕著書
+高著作 高著作
+高著者 高著者
+高著名 高著名
+高著述 高著述
+高著稱 高著稱
+高著錄 高著錄
+高著書 高著書
+隔著作 隔著作
+隔著者 隔著者
+隔著名 隔著名
+隔著述 隔著述
+隔著稱 隔著稱
+隔著錄 隔著錄
+隔著書 隔著書
+跟著作 跟著作
+跟著者 跟著者
+跟著名 跟著名
+跟著述 跟著述
+跟著稱 跟著稱
+跟著錄 跟著錄
+跟著書 跟著書
+孤著作 孤著作
+孤著者 孤著者
+孤著名 孤著名
+孤著述 孤著述
+孤著稱 孤著稱
+孤著錄 孤著錄
+孤著書 孤著書
+關著作 關著作
+關著者 關著者
+關著名 關著名
+關著述 關著述
+關著稱 關著稱
+關著錄 關著錄
+關著書 關著書
+管著作 管著作
+管著者 管著者
+管著名 管著名
+管著述 管著述
+管著稱 管著稱
+管著錄 管著錄
+管著書 管著書
+慣著作 慣著作
+慣著者 慣著者
+慣著名 慣著名
+慣著述 慣著述
+慣著稱 慣著稱
+慣著錄 慣著錄
+慣著書 慣著書
+光著作 光著作
+光著者 光著者
+光著名 光著名
+光著述 光著述
+光著稱 光著稱
+光著錄 光著錄
+光著書 光著書
+跪著作 跪著作
+跪著者 跪著者
+跪著名 跪著名
+跪著述 跪著述
+跪著稱 跪著稱
+跪著錄 跪著錄
+跪著書 跪著書
+裹著作 裹著作
+裹著者 裹著者
+裹著名 裹著名
+裹著述 裹著述
+裹著稱 裹著稱
+裹著錄 裹著錄
+裹著書 裹著書
+撼著作 撼著作
+撼著者 撼著者
+撼著名 撼著名
+撼著述 撼著述
+撼著稱 撼著稱
+撼著錄 撼著錄
+撼著書 撼著書
+喝著作 喝著作
+喝著者 喝著者
+喝著名 喝著名
+喝著述 喝著述
+喝著稱 喝著稱
+喝著錄 喝著錄
+喝著書 喝著書
+候著作 候著作
+候著者 候著者
+候著名 候著名
+候著述 候著述
+候著稱 候著稱
+候著錄 候著錄
+候著書 候著書
+懷著作 懷著作
+懷著者 懷著者
+懷著名 懷著名
+懷著述 懷著述
+懷著稱 懷著稱
+懷著錄 懷著錄
+懷著書 懷著書
+晃著作 晃著作
+晃著者 晃著者
+晃著名 晃著名
+晃著述 晃著述
+晃著稱 晃著稱
+晃著錄 晃著錄
+揮著作 揮著作
+揮著者 揮著者
+揮著名 揮著名
+揮著述 揮著述
+揮著稱 揮著稱
+揮著錄 揮著錄
+活著作 活著作
+活著者 活著者
+活著名 活著名
+活著述 活著述
+活著稱 活著稱
+活著錄 活著錄
+活著書 活著書
+獲著作 獲著作
+獲著者 獲著者
+獲著名 獲著名
+獲著述 獲著述
+獲著稱 獲著稱
+獲著錄 獲著錄
+獲著書 獲著書
+獲著作 獲著作
+獲著者 獲著者
+獲著名 獲著名
+獲著述 獲著述
+獲著稱 獲著稱
+獲著錄 獲著錄
+獲著書 獲著書
+急著作 急著作
+急著者 急著者
+急著名 急著名
+急著述 急著述
+急著稱 急著稱
+急著錄 急著錄
+急著書 急著書
+記著作 記著作
+記著者 記著者
+記著名 記著名
+記著述 記著述
+記著稱 記著稱
+記著錄 記著錄
+記著書 記著書
+冀著作 冀著作
+冀著者 冀著者
+冀著名 冀著名
+冀著述 冀著述
+冀著稱 冀著稱
+冀著錄 冀著錄
+冀著書 冀著書
+夾著作 夾著作
+夾著者 夾著者
+夾著名 夾著名
+夾著述 夾著述
+夾著稱 夾著稱
+夾著錄 夾著錄
+夾著書 夾著書
+駕著作 駕著作
+駕著者 駕著者
+駕著名 駕著名
+駕著述 駕著述
+駕著稱 駕著稱
+駕著錄 駕著錄
+駕著書 駕著書
+見著作 見著作
+見著者 見著者
+見著名 見著名
+見著述 見著述
+見著稱 見著稱
+見著錄 見著錄
+見著書 見著書
+閑著作 閑著作
+閑著者 閑著者
+閑著名 閑著名
+閑著述 閑著述
+閑著稱 閑著稱
+閑著錄 閑著錄
+閑著書 閑著書
+叫著作 叫著作
+叫著者 叫著者
+叫著名 叫著名
+叫著述 叫著述
+叫著稱 叫著稱
+叫著錄 叫著錄
+叫著書 叫著書
+接著作 接著作
+接著者 接著者
+接著名 接著名
+接著述 接著述
+接著稱 接著稱
+接著錄 接著錄
+借著作 借著作
+借著者 借著者
+借著名 借著名
+借著述 借著述
+借著稱 借著稱
+借著錄 借著錄
+借著書 借著書
+借著作 借著作
+借著者 借著者
+借著名 借著名
+借著述 借著述
+借著稱 借著稱
+借著錄 借著錄
+借著書 借著書
+據著作 據著作
+據著者 據著者
+據著名 據著名
+據著述 據著述
+據著稱 據著稱
+據著錄 據著錄
+據著書 據著書
+開著作 開著作
+開著者 開著者
+開著名 開著名
+開著述 開著述
+開著稱 開著稱
+開著錄 開著錄
+開著書 開著書
+看著作 看著作
+看著者 看著者
+看著名 看著名
+看著述 看著述
+看著稱 看著稱
+看著錄 看著錄
+看著書 看著書
+康著作 康著作
+康著者 康著者
+康著名 康著名
+康著述 康著述
+康著稱 康著稱
+康著錄 康著錄
+康著書 康著書
+扛著作 扛著作
+扛著者 扛著者
+扛著名 扛著名
+扛著述 扛著述
+扛著稱 扛著稱
+扛著錄 扛著錄
+扛著書 扛著書
+考著作 考著作
+考著者 考著者
+考著名 考著名
+考著述 考著述
+考著稱 考著稱
+考著錄 考著錄
+考著書 考著書
+渴著作 渴著作
+渴著者 渴著者
+渴著名 渴著名
+渴著述 渴著述
+渴著稱 渴著稱
+渴著錄 渴著錄
+渴著書 渴著書
+刻著作 刻著作
+刻著者 刻著者
+刻著名 刻著名
+刻著述 刻著述
+刻著稱 刻著稱
+刻著錄 刻著錄
+刻著書 刻著書
+空著作 空著作
+空著者 空著者
+空著名 空著名
+空著述 空著述
+空著稱 空著稱
+空著錄 空著錄
+空著書 空著書
+哭著作 哭著作
+哭著者 哭著者
+哭著名 哭著名
+哭著述 哭著述
+哭著稱 哭著稱
+哭著錄 哭著錄
+哭著書 哭著書
+苦著作 苦著作
+苦著者 苦著者
+苦著名 苦著名
+苦著述 苦著述
+苦著稱 苦著稱
+苦著錄 苦著錄
+苦著書 苦著書
+捆著作 捆著作
+捆著者 捆著者
+捆著名 捆著名
+捆著述 捆著述
+捆著稱 捆著稱
+捆著錄 捆著錄
+困著作 困著作
+困著者 困著者
+困著名 困著名
+困著述 困著述
+困著稱 困著稱
+困著錄 困著錄
+困著書 困著書
+拉著作 拉著作
+拉著者 拉著者
+拉著名 拉著名
+拉著述 拉著述
+拉著稱 拉著稱
+拉著錄 拉著錄
+拉著書 拉著書
+來著作 來著作
+來著者 來著者
+來著名 來著名
+來著述 來著述
+來著稱 來著稱
+來著錄 來著錄
+來著書 來著書
+樂著作 樂著作
+樂著者 樂著者
+樂著名 樂著名
+樂著述 樂著述
+樂著稱 樂著稱
+樂著錄 樂著錄
+樂著書 樂著書
+努力著作 努力著作
+努力著者 努力著者
+努力著名 努力著名
+努力著述 努力著述
+努力著稱 努力著稱
+努力著錄 努力著錄
+努力著書 努力著書
+麗著作 麗著作
+麗著者 麗著者
+麗著名 麗著名
+麗著述 麗著述
+麗著稱 麗著稱
+麗著錄 麗著錄
+麗著書 麗著書
+連著作 連著作
+連著者 連著者
+連著名 連著名
+連著述 連著述
+連著稱 連著稱
+連著錄 連著錄
+連著書 連著書
+戀著作 戀著作
+戀著者 戀著者
+戀著名 戀著名
+戀著述 戀著述
+戀著稱 戀著稱
+戀著錄 戀著錄
+戀著書 戀著書
+涼著作 涼著作
+涼著者 涼著者
+涼著名 涼著名
+涼著述 涼著述
+涼著稱 涼著稱
+涼著錄 涼著錄
+涼著書 涼著書
+亮著作 亮著作
+亮著者 亮著者
+亮著名 亮著名
+亮著述 亮著述
+亮著稱 亮著稱
+亮著錄 亮著錄
+亮著書 亮著書
+臨著作 臨著作
+臨著者 臨著者
+臨著名 臨著名
+臨著述 臨著述
+臨著稱 臨著稱
+臨著錄 臨著錄
+臨著書 臨著書
+拎著作 拎著作
+拎著者 拎著者
+拎著名 拎著名
+拎著述 拎著述
+拎著稱 拎著稱
+拎著錄 拎著錄
+領著作 領著作
+領著者 領著者
+領著名 領著名
+領著述 領著述
+領著稱 領著稱
+領著錄 領著錄
+領著書 領著書
+流著作 流著作
+流著者 流著者
+流著名 流著名
+流著述 流著述
+流著稱 流著稱
+流著錄 流著錄
+流著書 流著書
+留著作 留著作
+留著者 留著者
+留著名 留著名
+留著述 留著述
+留著稱 留著稱
+留著錄 留著錄
+留著書 留著書
+摟著作 摟著作
+摟著者 摟著者
+摟著名 摟著名
+摟著述 摟著述
+摟著稱 摟著稱
+摟著錄 摟著錄
+陋著作 陋著作
+陋著者 陋著者
+陋著名 陋著名
+陋著述 陋著述
+陋著稱 陋著稱
+陋著錄 陋著錄
+陋著書 陋著書
+落著作 落著作
+落著者 落著者
+落著名 落著名
+落著述 落著述
+落著稱 落著稱
+落著錄 落著錄
+落著書 落著書
+罵著作 罵著作
+罵著者 罵著者
+罵著名 罵著名
+罵著述 罵著述
+罵著稱 罵著稱
+罵著錄 罵著錄
+罵著書 罵著書
+瞞著作 瞞著作
+瞞著者 瞞著者
+瞞著名 瞞著名
+瞞著述 瞞著述
+瞞著稱 瞞著稱
+瞞著錄 瞞著錄
+瞞著書 瞞著書
+漫著作 漫著作
+漫著者 漫著者
+漫著名 漫著名
+漫著述 漫著述
+漫著稱 漫著稱
+漫著錄 漫著錄
+漫著書 漫著書
+忙著作 忙著作
+忙著者 忙著者
+忙著名 忙著名
+忙著述 忙著述
+忙著稱 忙著稱
+忙著錄 忙著錄
+忙著書 忙著書
+冒著作 冒著作
+冒著者 冒著者
+冒著名 冒著名
+冒著述 冒著述
+冒著稱 冒著稱
+冒著錄 冒著錄
+冒著書 冒著書
+美著作 美著作
+美著者 美著者
+美著名 美著名
+美著述 美著述
+美著稱 美著稱
+美著錄 美著錄
+美著書 美著書
+夢著作 夢著作
+夢著者 夢著者
+夢著名 夢著名
+夢著述 夢著述
+夢著稱 夢著稱
+夢著錄 夢著錄
+夢著書 夢著書
+蒙著作 蒙著作
+蒙著者 蒙著者
+蒙著名 蒙著名
+蒙著述 蒙著述
+蒙著稱 蒙著稱
+蒙著錄 蒙著錄
+蒙著書 蒙著書
+拿著作 拿著作
+拿著者 拿著者
+拿著名 拿著名
+拿著述 拿著述
+拿著稱 拿著稱
+拿著錄 拿著錄
+逆著作 逆著作
+逆著者 逆著者
+逆著名 逆著名
+逆著述 逆著述
+逆著稱 逆著稱
+逆著錄 逆著錄
+逆著書 逆著書
+釀著作 釀著作
+釀著者 釀著者
+釀著名 釀著名
+釀著述 釀著述
+釀著稱 釀著稱
+釀著錄 釀著錄
+釀著書 釀著書
+努著作 努著作
+努著者 努著者
+努著名 努著名
+努著述 努著述
+努著稱 努著稱
+努著錄 努著錄
+努著書 努著書
+趴著作 趴著作
+趴著者 趴著者
+趴著名 趴著名
+趴著述 趴著述
+趴著稱 趴著稱
+趴著錄 趴著錄
+趴著書 趴著書
+跑著作 跑著作
+跑著者 跑著者
+跑著名 跑著名
+跑著述 跑著述
+跑著稱 跑著稱
+跑著錄 跑著錄
+跑著書 跑著書
+陪著作 陪著作
+陪著者 陪著者
+陪著名 陪著名
+陪著述 陪著述
+陪著稱 陪著稱
+陪著錄 陪著錄
+陪著書 陪著書
+配著作 配著作
+配著者 配著者
+配著名 配著名
+配著述 配著述
+配著稱 配著稱
+配著錄 配著錄
+配著書 配著書
+披著作 披著作
+披著者 披著者
+披著名 披著名
+披著述 披著述
+披著稱 披著稱
+披著錄 披著錄
+披著書 披著書
+騙著作 騙著作
+騙著者 騙著者
+騙著名 騙著名
+騙著述 騙著述
+騙著稱 騙著稱
+騙著錄 騙著錄
+騙著書 騙著書
+飄著作 飄著作
+飄著者 飄著者
+飄著名 飄著名
+飄著述 飄著述
+飄著稱 飄著稱
+飄著錄 飄著錄
+飄著書 飄著書
+拼著作 拼著作
+拼著者 拼著者
+拼著名 拼著名
+拼著述 拼著述
+拼著稱 拼著稱
+拼著錄 拼著錄
+鋪著作 鋪著作
+鋪著者 鋪著者
+鋪著名 鋪著名
+鋪著述 鋪著述
+鋪著稱 鋪著稱
+鋪著錄 鋪著錄
+鋪著書 鋪著書
+騎著作 騎著作
+騎著者 騎著者
+騎著名 騎著名
+騎著述 騎著述
+騎著稱 騎著稱
+騎著錄 騎著錄
+騎著書 騎著書
+牽著作 牽著作
+牽著者 牽著者
+牽著名 牽著名
+牽著述 牽著述
+牽著稱 牽著稱
+牽著錄 牽著錄
+牽著書 牽著書
+求著作 求著作
+求著者 求著者
+求著名 求著名
+求著述 求著述
+求著稱 求著稱
+求著錄 求著錄
+求著書 求著書
+去著作 去著作
+去著者 去著者
+去著名 去著名
+去著述 去著述
+去著稱 去著稱
+去著錄 去著錄
+去著書 去著書
+嚷著作 嚷著作
+嚷著者 嚷著者
+嚷著名 嚷著名
+嚷著述 嚷著述
+嚷著稱 嚷著稱
+嚷著錄 嚷著錄
+嚷著書 嚷著書
+繞著作 繞著作
+繞著者 繞著者
+繞著名 繞著名
+繞著述 繞著述
+繞著稱 繞著稱
+繞著錄 繞著錄
+繞著書 繞著書
+忍著作 忍著作
+忍著者 忍著者
+忍著名 忍著名
+忍著述 忍著述
+忍著稱 忍著稱
+忍著錄 忍著錄
+忍著書 忍著書
+揉著作 揉著作
+揉著者 揉著者
+揉著名 揉著名
+揉著述 揉著述
+揉著稱 揉著稱
+揉著錄 揉著錄
+揉著書 揉著書
+潤著作 潤著作
+潤著者 潤著者
+潤著名 潤著名
+潤著述 潤著述
+潤著稱 潤著稱
+潤著錄 潤著錄
+潤著書 潤著書
+燒著作 燒著作
+燒著者 燒著者
+燒著名 燒著名
+燒著述 燒著述
+燒著稱 燒著稱
+燒著錄 燒著錄
+燒著書 燒著書
+身著作 身著作
+身著者 身著者
+身著名 身著名
+身著述 身著述
+身著稱 身著稱
+身著錄 身著錄
+身著書 身著書
+沉著作 沉著作
+沉著者 沉著者
+沉著名 沉著名
+沉著述 沉著述
+沉著稱 沉著稱
+沉著錄 沉著錄
+沉著書 沉著書
+盛著作 盛著作
+盛著者 盛著者
+盛著名 盛著名
+盛著述 盛著述
+盛著稱 盛著稱
+盛著錄 盛著錄
+盛著書 盛著書
+試著作 試著作
+試著者 試著者
+試著名 試著名
+試著述 試著述
+試著稱 試著稱
+試著錄 試著錄
+試著書 試著書
+守著作 守著作
+守著者 守著者
+守著名 守著名
+守著述 守著述
+守著稱 守著稱
+守著錄 守著錄
+守著書 守著書
+受著作 受著作
+受著者 受著者
+受著名 受著名
+受著述 受著述
+受著稱 受著稱
+受著錄 受著錄
+受著書 受著書
+梳著作 梳著作
+梳著者 梳著者
+梳著名 梳著名
+梳著述 梳著述
+梳著稱 梳著稱
+梳著錄 梳著錄
+豎著作 豎著作
+豎著者 豎著者
+豎著名 豎著名
+豎著述 豎著述
+豎著稱 豎著稱
+豎著錄 豎著錄
+豎著書 豎著書
+數著作 數著作
+數著者 數著者
+數著名 數著名
+數著述 數著述
+數著稱 數著稱
+數著錄 數著錄
+睡著作 睡著作
+睡著者 睡著者
+睡著名 睡著名
+睡著述 睡著述
+睡著稱 睡著稱
+睡著錄 睡著錄
+睡著書 睡著書
+順著作 順著作
+順著者 順著者
+順著名 順著名
+順著述 順著述
+順著稱 順著稱
+順著錄 順著錄
+順著書 順著書
+隨著作 隨著作
+隨著者 隨著者
+隨著名 隨著名
+隨著述 隨著述
+隨著稱 隨著稱
+隨著錄 隨著錄
+隨著書 隨著書
+踏著作 踏著作
+踏著者 踏著者
+踏著名 踏著名
+踏著述 踏著述
+踏著稱 踏著稱
+踏著錄 踏著錄
+抬著作 抬著作
+抬著者 抬著者
+抬著名 抬著名
+抬著述 抬著述
+抬著稱 抬著稱
+抬著錄 抬著錄
+躺著作 躺著作
+躺著者 躺著者
+躺著名 躺著名
+躺著述 躺著述
+躺著稱 躺著稱
+躺著錄 躺著錄
+躺著書 躺著書
+提著作 提著作
+提著者 提著者
+提著名 提著名
+提著述 提著述
+提著稱 提著稱
+提著錄 提著錄
+甜著作 甜著作
+甜著者 甜著者
+甜著名 甜著名
+甜著述 甜著述
+甜著稱 甜著稱
+甜著錄 甜著錄
+甜著書 甜著書
+挑著作 挑著作
+挑著者 挑著者
+挑著名 挑著名
+挑著述 挑著述
+挑著稱 挑著稱
+挑著錄 挑著錄
+跳著作 跳著作
+跳著者 跳著者
+跳著名 跳著名
+跳著述 跳著述
+跳著稱 跳著稱
+跳著錄 跳著錄
+跳著書 跳著書
+聽著作 聽著作
+聽著者 聽著者
+聽著名 聽著名
+聽著述 聽著述
+聽著稱 聽著稱
+聽著錄 聽著錄
+聽著書 聽著書
+偷著作 偷著作
+偷著者 偷著者
+偷著名 偷著名
+偷著述 偷著述
+偷著稱 偷著稱
+偷著錄 偷著錄
+偷著書 偷著書
+拖著作 拖著作
+拖著者 拖著者
+拖著名 拖著名
+拖著述 拖著述
+拖著稱 拖著稱
+拖著錄 拖著錄
+望著作 望著作
+望著者 望著者
+望著名 望著名
+望著述 望著述
+望著稱 望著稱
+望著錄 望著錄
+望著書 望著書
+圍著作 圍著作
+圍著者 圍著者
+圍著名 圍著名
+圍著述 圍著述
+圍著稱 圍著稱
+圍著錄 圍著錄
+圍著書 圍著書
+味著作 味著作
+味著者 味著者
+味著名 味著名
+味著述 味著述
+味著稱 味著稱
+味著錄 味著錄
+味著書 味著書
+想著作 想著作
+想著者 想著者
+想著名 想著名
+想著述 想著述
+想著稱 想著稱
+想著錄 想著錄
+想著書 想著書
+響著作 響著作
+響著者 響著者
+響著名 響著名
+響著述 響著述
+響著稱 響著稱
+響著錄 響著錄
+響著書 響著書
+向著作 向著作
+向著者 向著者
+向著名 向著名
+向著述 向著述
+向著稱 向著稱
+向著錄 向著錄
+向著書 向著書
+笑著作 笑著作
+笑著者 笑著者
+笑著名 笑著名
+笑著述 笑著述
+笑著稱 笑著稱
+笑著錄 笑著錄
+笑著書 笑著書
+心著作 心著作
+心著者 心著者
+心著名 心著名
+心著述 心著述
+心著稱 心著稱
+心著錄 心著錄
+心著書 心著書
+信著作 信著作
+信著者 信著者
+信著名 信著名
+信著述 信著述
+信著稱 信著稱
+信著錄 信著錄
+信著書 信著書
+行著作 行著作
+行著者 行著者
+行著名 行著名
+行著述 行著述
+行著稱 行著稱
+行著錄 行著錄
+行著書 行著書
+性著作 性著作
+性著者 性著者
+性著名 性著名
+性著述 性著述
+性著稱 性著稱
+性著錄 性著錄
+性著書 性著書
+學著作 學著作
+學著者 學著者
+學著名 學著名
+學著述 學著述
+學著稱 學著稱
+學著錄 學著錄
+學著書 學著書
+尋著作 尋著作
+尋著者 尋著者
+尋著名 尋著名
+尋著述 尋著述
+尋著稱 尋著稱
+尋著錄 尋著錄
+尋著書 尋著書
+循著作 循著作
+循著者 循著者
+循著名 循著名
+循著述 循著述
+循著稱 循著稱
+循著錄 循著錄
+循著書 循著書
+壓著作 壓著作
+壓著者 壓著者
+壓著名 壓著名
+壓著述 壓著述
+壓著稱 壓著稱
+壓著錄 壓著錄
+壓著書 壓著書
+雅著作 雅著作
+雅著者 雅著者
+雅著名 雅著名
+雅著述 雅著述
+雅著稱 雅著稱
+雅著錄 雅著錄
+雅著書 雅著書
+沿著作 沿著作
+沿著者 沿著者
+沿著名 沿著名
+沿著述 沿著述
+沿著稱 沿著稱
+沿著錄 沿著錄
+沿著書 沿著書
+耀著作 耀著作
+耀著者 耀著者
+耀著名 耀著名
+耀著述 耀著述
+耀著稱 耀著稱
+耀著錄 耀著錄
+耀著書 耀著書
+掖著作 掖著作
+掖著者 掖著者
+掖著名 掖著名
+掖著述 掖著述
+掖著稱 掖著稱
+掖著錄 掖著錄
+衣著作 衣著作
+衣著者 衣著者
+衣著名 衣著名
+衣著述 衣著述
+衣著稱 衣著稱
+衣著錄 衣著錄
+衣著書 衣著書
+疑著作 疑著作
+疑著者 疑著者
+疑著名 疑著名
+疑著述 疑著述
+疑著稱 疑著稱
+疑著錄 疑著錄
+疑著書 疑著書
+溢著作 溢著作
+溢著者 溢著者
+溢著名 溢著名
+溢著述 溢著述
+溢著稱 溢著稱
+溢著錄 溢著錄
+溢著書 溢著書
+藝著作 藝著作
+藝著者 藝著者
+藝著名 藝著名
+藝著述 藝著述
+藝著稱 藝著稱
+藝著錄 藝著錄
+藝著書 藝著書
+因著作 因著作
+因著者 因著者
+因著名 因著名
+因著述 因著述
+因著稱 因著稱
+因著錄 因著錄
+因著書 因著書
+印著作 印著作
+印著者 印著者
+印著名 印著名
+印著述 印著述
+印著稱 印著稱
+印著錄 印著錄
+印著書 印著書
+應著作 應著作
+應著者 應著者
+應著名 應著名
+應著述 應著述
+應著稱 應著稱
+應著錄 應著錄
+應著書 應著書
+映著作 映著作
+映著者 映著者
+映著名 映著名
+映著述 映著述
+映著稱 映著稱
+映著錄 映著錄
+映著書 映著書
+用著作 用著作
+用著者 用著者
+用著名 用著名
+用著述 用著述
+用著稱 用著稱
+用著錄 用著錄
+用著書 用著書
+悠著作 悠著作
+悠著者 悠著者
+悠著名 悠著名
+悠著述 悠著述
+悠著稱 悠著稱
+悠著錄 悠著錄
+悠著書 悠著書
+有著作 有著作
+有著者 有著者
+有著名 有著名
+有著述 有著述
+有著稱 有著稱
+有著錄 有著錄
+有著書 有著書
+與著作 與著作
+與著者 與著者
+與著名 與著名
+與著述 與著述
+與著稱 與著稱
+與著錄 與著錄
+與著書 與著書
+語著作 語著作
+語著者 語著者
+語著名 語著名
+語著述 語著述
+語著稱 語著稱
+語著錄 語著錄
+語著書 語著書
+豫著作 豫著作
+豫著者 豫著者
+豫著名 豫著名
+豫著述 豫著述
+豫著稱 豫著稱
+豫著錄 豫著錄
+豫著書 豫著書
+遠著作 遠著作
+遠著者 遠著者
+遠著名 遠著名
+遠著述 遠著述
+遠著稱 遠著稱
+遠著錄 遠著錄
+遠著書 遠著書
+躍著作 躍著作
+躍著者 躍著者
+躍著名 躍著名
+躍著述 躍著述
+躍著稱 躍著稱
+躍著錄 躍著錄
+躍著書 躍著書
+雜著作 雜著作
+雜著者 雜著者
+雜著名 雜著名
+雜著述 雜著述
+雜著稱 雜著稱
+雜著錄 雜著錄
+雜著書 雜著書
+載著作 載著作
+載著者 載著者
+載著名 載著名
+載著述 載著述
+載著稱 載著稱
+載著錄 載著錄
+載著書 載著書
+在著作 在著作
+在著者 在著者
+在著名 在著名
+在著述 在著述
+在著稱 在著稱
+在著錄 在著錄
+在著書 在著書
+紮著作 紮著作
+紮著者 紮著者
+紮著名 紮著名
+紮著述 紮著述
+紮著稱 紮著稱
+紮著錄 紮著錄
+紮著書 紮著書
+展著作 展著作
+展著者 展著者
+展著名 展著名
+展著述 展著述
+展著稱 展著稱
+展著錄 展著錄
+展著書 展著書
+站著作 站著作
+站著者 站著者
+站著名 站著名
+站著述 站著述
+站著稱 站著稱
+站著錄 站著錄
+站著書 站著書
+戰著作 戰著作
+戰著者 戰著者
+戰著名 戰著名
+戰著述 戰著述
+戰著稱 戰著稱
+戰著錄 戰著錄
+戰著書 戰著書
+蘸著作 蘸著作
+蘸著者 蘸著者
+蘸著名 蘸著名
+蘸著述 蘸著述
+蘸著稱 蘸著稱
+蘸著錄 蘸著錄
+蘸著書 蘸著書
+仗著作 仗著作
+仗著者 仗著者
+仗著名 仗著名
+仗著述 仗著述
+仗著稱 仗著稱
+仗著錄 仗著錄
+仗著書 仗著書
+照著作 照著作
+照著者 照著者
+照著名 照著名
+照著述 照著述
+照著稱 照著稱
+照著錄 照著錄
+照著書 照著書
+罩著作 罩著作
+罩著者 罩著者
+罩著名 罩著名
+罩著述 罩著述
+罩著稱 罩著稱
+罩著錄 罩著錄
+罩著書 罩著書
+貞著作 貞著作
+貞著者 貞著者
+貞著名 貞著名
+貞著述 貞著述
+貞著稱 貞著稱
+貞著錄 貞著錄
+貞著書 貞著書
+枕著作 枕著作
+枕著者 枕著者
+枕著名 枕著名
+枕著述 枕著述
+枕著稱 枕著稱
+枕著錄 枕著錄
+爭著作 爭著作
+爭著者 爭著者
+爭著名 爭著名
+爭著述 爭著述
+爭著稱 爭著稱
+爭著錄 爭著錄
+爭著書 爭著書
+掙著作 掙著作
+掙著者 掙著者
+掙著名 掙著名
+掙著述 掙著述
+掙著稱 掙著稱
+掙著錄 掙著錄
+掙著書 掙著書
+制著作 制著作
+制著者 制著者
+制著名 制著名
+制著述 制著述
+制著稱 制著稱
+制著錄 制著錄
+制著書 制著書
+志著作 志著作
+志著者 志著者
+志著名 志著名
+志著述 志著述
+志著稱 志著稱
+志著錄 志著錄
+志著書 志著書
+皺著作 皺著作
+皺著者 皺著者
+皺著名 皺著名
+皺著述 皺著述
+皺著稱 皺著稱
+皺著錄 皺著錄
+皺著書 皺著書
+住著作 住著作
+住著者 住著者
+住著名 住著名
+住著述 住著述
+住著稱 住著稱
+住著錄 住著錄
+住著書 住著書
+抓著作 抓著作
+抓著者 抓著者
+抓著名 抓著名
+抓著述 抓著述
+抓著稱 抓著稱
+抓著錄 抓著錄
+轉著作 轉著作
+轉著者 轉著者
+轉著名 轉著名
+轉著述 轉著述
+轉著稱 轉著稱
+轉著錄 轉著錄
+轉著書 轉著書
+裝著作 裝著作
+裝著者 裝著者
+裝著名 裝著名
+裝著述 裝著述
+裝著稱 裝著稱
+裝著錄 裝著錄
+裝著書 裝著書
+追著作 追著作
+追著者 追著者
+追著名 追著名
+追著述 追著述
+追著稱 追著稱
+追著錄 追著錄
+追著書 追著書
+髭著作 髭著作
+髭著者 髭著者
+髭著名 髭著名
+髭著述 髭著述
+髭著稱 髭著稱
+髭著錄 髭著錄
+髭著書 髭著書
+走著作 走著作
+走著者 走著者
+走著名 走著名
+走著述 走著述
+走著稱 走著稱
+走著錄 走著錄
+走著書 走著書
+坐著作 坐著作
+坐著者 坐著者
+坐著名 坐著名
+坐著述 坐著述
+坐著稱 坐著稱
+坐著錄 坐著錄
+坐著書 坐著書
+做著作 做著作
+做著者 做著者
+做著名 做著名
+做著述 做著述
+做著稱 做著稱
+做著錄 做著錄
+做著書 做著書
+含著作 含著作
+含著者 含著者
+含著名 含著名
+含著述 含著述
+含著稱 含著稱
+含著錄 含著錄
+含著書 含著書
+涵著作 涵著作
+涵著者 涵著者
+涵著名 涵著名
+涵著述 涵著述
+涵著稱 涵著稱
+涵著錄 涵著錄
+涵著書 涵著書
+演著作 演著作
+演著者 演著者
+演著名 演著名
+演著述 演著述
+演著稱 演著稱
+演著錄 演著錄
+演著書 演著書
+保障著作 保障著作
+保障著者 保障著者
+保障著名 保障著名
+保障著述 保障著述
+保障著稱 保障著稱
+保障著錄 保障著錄
+保障著書 保障著書
+黏著作 黏著作
+黏著者 黏著者
+黏著名 黏著名
+黏著述 黏著述
+黏著稱 黏著稱
+黏著錄 黏著錄
+黏著書 黏著書
+膠著作 膠著作
+膠著者 膠著者
+膠著名 膠著名
+膠著述 膠著述
+膠著稱 膠著稱
+膠著錄 膠著錄
+膠著書 膠著書
+附著作 附著作
+附著者 附著者
+附著名 附著名
+附著述 附著述
+附著稱 附著稱
+附著錄 附著錄
+附著書 附著書
+代表著作 代表著作
+代表著者 代表著者
+代表著名 代表著名
+代表著述 代表著述
+代表著稱 代表著稱
+代表著錄 代表著錄
+代表著書 代表著書
+浮著作 浮著作
+浮著者 浮著者
+浮著名 浮著名
+浮著述 浮著述
+浮著稱 浮著稱
+浮著錄 浮著錄
+浮著書 浮著書
+寫著作 寫著作
+寫著者 寫著者
+寫著名 寫著名
+寫著述 寫著述
+寫著稱 寫著稱
+寫著錄 寫著錄
+寫著書 寫著書
+遇著作 遇著作
+遇著者 遇著者
+遇著名 遇著名
+遇著述 遇著述
+遇著稱 遇著稱
+遇著錄 遇著錄
+遇著書 遇著書
+殺著作 殺著作
+殺著者 殺著者
+殺著名 殺著名
+殺著述 殺著述
+殺著稱 殺著稱
+殺著錄 殺著錄
+殺著書 殺著書
+標誌著 標誌着
+幹著 幹着
+干着 幹着
+干着急 干着急
+流露著 流露着
+靠著 靠着
+靠著作 靠著作
+靠著名 靠著名
+靠著錄 靠著錄
+靠著录 靠著錄
+靠著稱 靠著稱
+靠著称 靠著稱
+靠著者 靠著者
+靠著述 靠著述
+新著龍虎門 新著龍虎門
+迫著 迫着
+心繫著 心繫着
+藉著 藉着
+吃得著 吃得着
+吃不著 吃不着
+吃著 吃着
+聞得著 闻得着
+聞不著 闻不着
+聞著 闻着
+嗅得著 嗅得着
+嗅不著 嗅不着
+嗅著 嗅着
+警戒著 警戒着
+榴莲 榴槤
+榴蓮 榴槤
+发布 發佈
+發布 發佈
+掛鉤 掛鈎
+鉤心鬥角 鈎心鬥角
+咤 咤
+叱吒 叱咤
+叱咤 叱咤
+醯 酰
+醯醬 醯醬
+醯雞 醯雞
+醯酱 醯醬
+醯鸡 醯雞
+醯醋 醯醋
+醯醢 醯醢
+醯壶 醯壺
+醯壺 醯壺
+菸 煙
+雪裡紅 雪裏紅
+雪裡蕻 雪裏蕻
+雪里蕻 雪裏蕻
+雪里红 雪裏紅
+森林裡 森林裏
+森林里 森林裏
+日子裡 日子裏
+日子里 日子裏
+故事裡 故事裏
+故事里 故事裏
+領域裡 領域裏
+领域里 領域裏
+時間裡 時間裏
+时间里 時間裏
+深淵裡 深淵裏
+深渊里 深渊裏
+醫院裡 醫院裏
+医院里 医院裏
+春假裡 春假裏
+春假里 春假裏
+暑假裡 暑假裏
+暑假里 暑假裏
+秋假裡 秋假裏
+秋假里 秋假裏
+寒假裡 寒假裏
+寒假里 寒假裏
+春天裡 春天裏
+春天里 春天裏
+夏天裡 夏天裏
+夏天里 夏天裏
+秋天裡 秋天裏
+秋天里 秋天裏
+冬天裡 冬天裏
+冬天里 冬天裏
+春日裡 春日裏
+夏日裡 夏日裏
+秋日裡 秋日裏
+冬日裡 冬日裏
+春日里 春日裏
+夏日里 夏日裏
+秋日里 秋日裏
+冬日里 冬日裏
+嘴裡 嘴裏
+嘴里 嘴裏
+心裡 心裏
+心里 心裏
+皮裡陽秋 皮裏陽秋
+皮里阳秋 皮裏陽秋
+肚裡 肚裏
+肚里 肚裏
+苦裡 苦裏
+苦里 苦裏
+裡勾外連 裏勾外連
+里勾外连 裏勾外連
+裡面 裏面
+里面 裏面
+這裡 這裏
+這里 這裏
+點裡 點裏
+点里 點裏
+中文裡 中文裏
+中文里 中文裏
+山洞里 山洞裏
+山洞裡 山洞裏
+近角聪信 近角聰信
+近角聰信 近角聰信
+世界里 世界裏
+世界裡 世界裏
+眼睛里 眼睛裏
+眼睛裡 眼睛裏
+百科裡 百科裏
+百科里 百科裏
+歷史裡 歷史裏
+历史里 歷史裏
+戲裡 戲裏
+戏里 戲裏
+作品裡 作品裏
+作品里 作品裏
+專輯裡 專輯裏
+专辑里 專輯裏
+年代裡 年代裏
+年代里 年代裏
+棺材裡 棺材裏
+棺材里 棺材裏
+學裡 學裏
+学里 學裏
+獄裡 獄裏
+狱里 獄裏
+館裡 館裏
+馆里 館裏
+系列裡 系列裏
+系列里 系列裏
+村子裡 村子裏
+村子里 村子裏
+分布 分佈
+分布于 分佈於
+分布於 分佈於
+想象 想像
+無線電視 無綫電視
+无线电视 無綫電視
+無線收費 無綫收費
+无线收费 無綫收費
+無線節目 無綫節目
+无线节目 無綫節目
+無線劇集 無綫劇集
+无线剧集 無綫劇集
+東鐵線 東鐵綫
+东铁线 東鐵綫
+觀塘線 觀塘綫
+观塘线 觀塘綫
+荃灣線 荃灣綫
+荃湾线 荃灣綫
+港島線 港島綫
+港岛线 港島綫
+東涌線 東涌綫
+东涌线 東涌綫
+將軍澳線 將軍澳綫
+将军澳线 將軍澳綫
+西鐵線 西鐵綫
+西铁线 西鐵綫
+馬鞍山線 馬鞍山綫
+马鞍山线 馬鞍山綫
+迪士尼線 迪士尼綫
+迪士尼线 迪士尼綫
+沙田至中環線 沙田至中環綫
+沙田至中环线 沙田至中環綫
+沙中線 沙中綫
+沙中线 沙中綫
+北環線 北環綫
+北环线 北環綫
+機場快線 機場快綫
+机场快线 機場快綫
+505線 505綫
+505线 505綫
+507線 507綫
+507线 507綫
+610線 610綫
+610线 610綫
+614線 614綫
+614线 614綫
+614P線 614P綫
+614P线 614P綫
+615線 615綫
+615线 615綫
+615P線 615P綫
+615P线 615P綫
+705線 705綫
+705线 705綫
+706線 706綫
+706线 706綫
+751線 751綫
+751线 751綫
+751P線 751P綫
+751P线 751P綫
+761P線 761P綫
+761P线 761P綫
diff --git a/maintenance/language/zhtable/toSG.manual b/maintenance/language/zhtable/toSG.manual
new file mode 100644
index 00000000..2d39aa35
--- /dev/null
+++ b/maintenance/language/zhtable/toSG.manual
@@ -0,0 +1,21 @@
+」 ”
+「 “
+『 ‘
+』 ’
+方便面 快速面
+速食麵 快速面
+即食麵 快速面
+泡麵 快速面
+蹦极跳 绑紧跳
+笨豬跳 绑紧跳
+凉菜 冷菜
+冷盤 冷菜
+零钱 散钱
+散紙 散钱
+笑星 谐星
+夜校 夜学
+民乐 华乐
+住房 住屋
+房价 屋价
+榴莲 榴梿
+榴蓮 榴梿 \ No newline at end of file
diff --git a/maintenance/language/zhtable/toSimp.manual b/maintenance/language/zhtable/toSimp.manual
new file mode 100644
index 00000000..e22447a6
--- /dev/null
+++ b/maintenance/language/zhtable/toSimp.manual
@@ -0,0 +1,166 @@
+乾县 乾县
+萧乾 萧乾
+乾断 乾断
+乾图 乾图
+乾纲 乾纲
+乾红 乾红
+乾清宫 乾清宫
+乾仪 乾仪
+乾兴 乾兴
+乾冈 乾冈
+乾刘 乾刘
+乾刚 乾刚
+乾启 乾启
+乾宁 乾宁
+乾岗 乾岗
+乾录 乾录
+乾晖 乾晖
+乾构 乾构
+乾枢 乾枢
+乾栋 乾栋
+乾灵 乾灵
+乾窦 乾窦
+乾笃 乾笃
+乾纽 乾纽
+乾络 乾络
+乾统 乾统
+乾维 乾维
+乾罗 乾罗
+乾荫 乾荫
+乾象历 乾象历
+乾贞 乾贞
+乾贶 乾贶
+乾车 乾车
+乾轴 乾轴
+乾鉴 乾鉴
+乾钧 乾钧
+乾闼 乾闼
+乾顾 乾顾
+乾风 乾风
+乾马 乾马
+乾鹄 乾鹄
+乾鹊 乾鹊
+乾龙 乾龙
+张法乾 张法乾
+旋乾转坤 旋乾转坤
+天道为乾 天道为乾
+易经·乾 易经·乾
+易经乾 易经乾
+乾务 乾务
+黄润乾 黄润乾
+男性为乾 男性为乾
+男为乾 男为乾
+阳为乾 阳为乾
+男性为乾 男性为乾
+男性爲乾 男性为乾
+男为乾 男为乾
+男爲乾 男为乾
+阳为乾 阳为乾
+陽爲乾 阳为乾
+乾一组 乾一组
+乾一坛 乾一坛
+陈乾生 陈乾生
+陈公乾生 陈公乾生
+柳诒徵 柳诒徵
+於夫罗 於夫罗
+於梨华 於梨华
+於潜县 於潜县
+於志贺 於志贺
+憑藉 凭借
+藉端 借端
+藉故 借故
+藉口 借口
+藉助 借助
+藉手 借手
+藉詞 借词
+藉機 借机
+藉此 借此
+藉由 借由
+藉著 借着
+藉着 借着
+沈積 沉积
+沈船 沉船
+沈默 沉默
+沈沒 沉没
+彷彿 仿佛
+項鍊 项链
+肘手鍊足 肘手链足
+鍊子 链子
+鍊條 链条
+拉鍊 拉链
+鉸鍊 铰链
+鍊鎖 链锁
+鎖鍊 锁链
+鐵鍊 铁链
+金鍊 金链
+銀鍊 银链
+鍊錘 链锤
+洗鍊 洗练
+石碁镇 石碁镇
+反覆 反复
+回覆 回复
+答覆 答复
+反反覆覆 反反复复
+重覆 重复
+覆核 复核
+覆查 复查
+鬱姓 鬱姓
+鬱氏 鬱氏
+侏儸紀 侏罗纪
+夥計 伙计
+吳其濬 吴其濬
+吴其濬 吴其濬
+乾泉水 干泉水
+么半群 幺半群
+么元 幺元
+么爹 幺爹
+么叔 幺叔
+么舅 幺舅
+么爸 幺爸
+么媽 幺妈
+么姨 幺姨
+么娘 幺娘
+么孃 幺娘
+幺孃 幺娘
+么妹 幺妹
+么小 幺小
+么姓 幺姓
+么氏 幺氏
+么蛾子 幺蛾子
+幺厮 幺厮
+睪丸 睾丸
+附睪 附睾
+隱睪 隱睾
+麼麼 麽麽
+么麼 幺麽
+么麼小丑 幺麽小丑
+么鳳 幺凤
+么二三 幺二三
+么篇 幺篇
+么謙 幺谦
+这么 这么
+麴义 麴义
+乾乾淨淨 干干净净
+乾乾脆脆 干干脆脆
+肉乾乾 肉干干
+魚乾乾 鱼干干
+於于同 於于同
+於乙于同 於乙于同
+閻懷禮 闫怀礼
+醯酱 醯酱
+醯鸡 醯鸡
+醯壶 醯壶
+苧烯 苧烯
+李乾顺 李乾顺
+幹著 干着
+氾濫 泛滥
+显著 显著
+顯著 显著
+標誌著 标志着
+近角聪信 近角聪信
+修鍊 修炼
+米泽瑠美 米泽瑠美
+太閤 太阁
+候覆 候复
+待覆 待复
+批覆 批复
diff --git a/maintenance/language/zhtable/toTW.manual b/maintenance/language/zhtable/toTW.manual
new file mode 100644
index 00000000..1a14e99a
--- /dev/null
+++ b/maintenance/language/zhtable/toTW.manual
@@ -0,0 +1,411 @@
+” 」
+“ 「
+‘ 『
+’ 』
+着 著
+鈎 鉤
+钩 鉤
+衞 衛
+元凶 元凶
+元兇 元凶
+凶器 凶器
+兇器 凶器
+凶徒 凶徒
+兇徒 凶徒
+凶手 凶手
+兇手 凶手
+凶案 凶案
+兇案 凶案
+凶残 凶殘
+凶殘 凶殘
+兇殘 凶殘
+凶杀 凶殺
+凶殺 凶殺
+兇殺 凶殺
+疑凶 疑凶
+疑兇 疑凶
+真凶 真凶
+真兇 真凶
+缉凶 緝凶
+緝凶 緝凶
+緝兇 緝凶
+行凶 行凶
+行兇 行凶
+行凶后 行凶後
+行凶後 行凶後
+行兇後 行凶後
+买凶 買凶
+買凶 買凶
+買兇 買凶
+追凶 追凶
+追兇 追凶
+逞凶斗狠 逞凶鬥狠
+逞凶鬥狠 逞凶鬥狠
+逞兇鬥狠 逞凶鬥狠
+复苏 復甦
+復蘇 復甦
+缺省 預設
+串行 串列
+串列加速器 串列加速器
+以太网 乙太網
+位图 點陣圖
+例程 常式
+光标 游標
+光盘 光碟
+光驱 光碟機
+全角 全形
+加载 載入
+半角 半形
+变量 變數
+噪声 雜訊
+脱机 離線
+声卡 音效卡
+老字号 老字號
+连字号 連字號
+字号 字型大小
+字库 字型檔
+字段 欄位
+字符 字元
+字符集 字符集
+存盘 存檔
+寻址 定址
+尾注 章節附註
+异步 非同步
+总线 匯流排
+括号 括弧
+接口 介面
+控件 控制項
+权限 許可權
+盘片 碟片
+硅片 矽片
+硅谷 矽谷
+硬盘 硬碟
+磁盘 磁碟
+磁道 磁軌
+程控 程式控制
+远程控制 遠程控制
+遠程控制 遠程控制
+行程控制 行程控制
+流程控制 流程控制
+端口 埠
+算子 運算元
+算法 演算法
+芯片 晶片
+芯片 晶元
+词组 片語
+译码 解碼
+软驱 軟碟機
+快闪存储器 快閃記憶體
+闪存 快閃記憶體
+鼠标 滑鼠
+进制 進位
+交互式 互動式
+仿真 模擬
+优先级 優先順序
+传感 感測
+便携式 攜帶型
+信息论 資訊理論
+写保护 防寫
+分辨率 解析度
+服务器 伺服器
+等于 等於
+局域网 區域網
+扫瞄仪 掃瞄器
+宽带 寬頻
+数据库 資料庫
+奶酪 乳酪
+手电 手電筒
+手电筒 手電筒
+万历 萬曆
+永历 永曆
+词汇 辭彙
+习用 慣用
+元音 母音
+新纪元 新紀元
+新紀元 新紀元
+宋元 宋元
+头球 頭槌
+入球 進球
+粒入球 顆進球
+打门 射門
+火锅盖帽 蓋火鍋
+打印机 印表機
+打印機 印表機
+字节 位元組
+字節 位元組
+打印 列印
+打印 列印
+硬件 硬體
+硬件 硬體
+二极管 二極體
+二極管 二極體
+三极管 三極體
+三極管 三極體
+软件 軟體
+軟件 軟體
+网络 網路
+網絡 網路
+人工智能 人工智慧
+航天飞机 太空梭
+航天大学 航天大學
+穿梭機 太空梭
+因特网 網際網路
+互聯網 網際網路
+机器人 機器人
+機械人 機器人
+移动电话 行動電話
+流動電話 行動電話
+调制解调器 數據機
+調制解調器 數據機
+短信 簡訊
+短訊 簡訊
+乌兹别克斯坦 烏茲別克
+乍得 查德
+乍得 查德
+也门 葉門
+也門 葉門
+伯利兹 貝里斯
+伯利茲 貝里斯
+佛得角 維德角
+克罗地亚 克羅埃西亞
+克羅地亞 克羅埃西亞
+冈比亚 甘比亞
+岡比亞 甘比亞
+几内亚比绍 幾內亞比索
+幾內亞比紹 幾內亞比索
+列支敦士登 列支敦斯登
+列支敦士登 列支敦斯登
+利比里亚 賴比瑞亞
+利比里亞 賴比瑞亞
+加纳 迦納
+加納 迦納
+加蓬 加彭
+加蓬 加彭
+博茨瓦纳 波札那
+博茨瓦納 波札那
+卡塔尔 卡達
+卡塔爾 卡達
+卢旺达 盧安達
+盧旺達 盧安達
+危地马拉 瓜地馬拉
+危地馬拉 瓜地馬拉
+厄瓜多尔 厄瓜多
+厄瓜多爾 厄瓜多
+厄立特里亚 厄利垂亞
+厄立特里亞 厄利垂亞
+吉布提 吉布地
+吉布堤 吉布地
+哈萨克斯坦 哈薩克
+哥斯达黎加 哥斯大黎加
+哥斯達黎加 哥斯大黎加
+图瓦卢 吐瓦魯
+圖瓦盧 吐瓦魯
+土库曼斯坦 土庫曼
+圣卢西亚 聖露西亞
+聖盧西亞 聖露西亞
+圣基茨和尼维斯 聖克里斯多福及尼維斯
+聖吉斯納域斯 聖克里斯多福及尼維斯
+圣文森特和格林纳丁斯 聖文森及格瑞那丁
+聖文森特和格林納丁斯 聖文森及格瑞那丁
+圣马力诺 聖馬利諾
+聖馬力諾 聖馬利諾
+圭亚那 蓋亞那
+圭亞那 蓋亞那
+坦桑尼亚 坦尚尼亞
+坦桑尼亞 坦尚尼亞
+埃塞俄比亚 衣索比亞
+埃塞俄比亞 衣索比亞
+基里巴斯 吉里巴斯
+基里巴斯 吉里巴斯
+塔吉克斯坦 塔吉克
+塞拉利昂 獅子山
+塞拉利昂 獅子山
+塞浦路斯 塞普勒斯
+塞浦路斯 塞普勒斯
+塞舌尔 塞席爾
+塞舌爾 塞席爾
+多米尼加共和国 多明尼加
+多米尼加共和國 多明尼加
+多明尼加共和國 多明尼加
+多米尼加国 多米尼克
+多明尼加國 多米尼克
+安提瓜和巴布达 安地卡及巴布達
+安提瓜和巴布達 安地卡及巴布達
+尼日利亚 奈及利亞
+尼日利亞 奈及利亞
+尼日尔 尼日
+尼日爾 尼日
+巴巴多斯 巴貝多
+巴布亚新几内亚 巴布亞紐幾內亞
+巴布亞新畿內亞 巴布亞紐幾內亞
+布基纳法索 布吉納法索
+布基納法索 布吉納法索
+布隆迪 蒲隆地
+布隆迪 蒲隆地
+帕劳 帛琉
+意大利 義大利
+所罗门群岛 索羅門群島
+所羅門群島 索羅門群島
+文莱 汶萊
+斯威士兰 史瓦濟蘭
+斯威士蘭 史瓦濟蘭
+斯洛文尼亚 斯洛維尼亞
+斯洛文尼亞 斯洛維尼亞
+新西兰 紐西蘭
+新西蘭 紐西蘭
+格林纳达 格瑞那達
+格林納達 格瑞那達
+格鲁吉亚 喬治亞
+格魯吉亞 喬治亞
+佐治亚 喬治亞
+佐治亞 喬治亞
+毛里塔尼亚 茅利塔尼亞
+毛里塔尼亞 茅利塔尼亞
+毛里求斯 模里西斯
+毛里裘斯 模里西斯
+沙特阿拉伯 沙烏地阿拉伯
+沙地阿拉伯 沙烏地阿拉伯
+波斯尼亚和黑塞哥维那 波士尼亞赫塞哥維納
+波斯尼亞黑塞哥維那 波士尼亞赫塞哥維納
+津巴布韦 辛巴威
+津巴布韋 辛巴威
+洪都拉斯 宏都拉斯
+洪都拉斯 宏都拉斯
+特立尼达和托巴哥 千里達托貝哥
+特立尼達和多巴哥 千里達托貝哥
+瑙鲁 諾魯
+瑙魯 諾魯
+瓦努阿图 萬那杜
+瓦努阿圖 萬那杜
+溫納圖萬 那杜
+科摩罗 葛摩
+科摩羅 葛摩
+科特迪瓦 象牙海岸
+突尼斯 突尼西亞
+索马里 索馬利亞
+索馬里 索馬利亞
+老挝 寮國
+老撾 寮國
+肯尼亚 肯亞
+肯雅 肯亞
+苏里南 蘇利南
+莫桑比克 莫三比克
+莱索托 賴索托
+萊索托 賴索托
+贝宁 貝南
+貝寧 貝南
+赞比亚 尚比亞
+贊比亞 尚比亞
+阿塞拜疆 亞塞拜然
+阿拉伯联合酋长国 阿拉伯聯合大公國
+阿拉伯聯合酋長國 阿拉伯聯合大公國
+马尔代夫 馬爾地夫
+馬爾代夫 馬爾地夫
+马耳他 馬爾他
+马里共和国 馬利共和國
+馬里共和國 馬利共和國
+方便面 速食麵
+快速面 速食麵
+即食麵 速食麵
+薯仔 土豆
+土豆网 土豆網
+土豆網 土豆網
+蹦极跳 笨豬跳
+绑紧跳 笨豬跳
+冷菜 冷盤
+凉菜 冷盤
+出租车 計程車
+台球 撞球
+桌球 撞球
+卫生 衛生
+衞生 衛生
+平治之亂 平治之亂
+平治之乱 平治之亂
+平治 賓士
+奔驰 賓士
+積架 捷豹
+雪铁龙 雪鐵龍
+萬事得 馬自達
+拿破仑 拿破崙
+拿破侖 拿破崙
+布什 布希
+布殊 布希
+克林顿 柯林頓
+克林頓 柯林頓
+侯赛因 海珊
+侯賽因 海珊
+凡高 梵谷
+狄安娜 黛安娜
+戴安娜 黛安娜
+颁布 頒布
+頒佈 頒布
+彩带 彩帶
+彩排 彩排
+彩楼 彩樓
+彩牌楼 彩牌樓
+彩球 綵球
+彩绸 綵綢
+彩线 綵線
+彩船 綵船
+彩衣 綵衣
+结彩 結綵
+戏彩娱亲 戲綵娛親
+剪彩 剪綵
+榴莲 榴槤
+榴蓮 榴槤
+掛鈎 掛鉤
+挂钩 掛鉤
+鈎心鬥角 鉤心鬥角
+钩心斗角 鉤心鬥角
+酰 醯
+雪裏紅 雪裡紅
+雪裏蕻 雪裡蕻
+森林裏 森林裡
+日子裏 日子裡
+故事裏 故事裡
+領域裏 領域裡
+時間裏 時間裡
+深淵裏 深淵裡
+醫院裏 醫院裡
+春假裏 春假裡
+暑假裏 暑假裡
+秋假裏 秋假裡
+寒假裏 寒假裡
+春天裏 春天裡
+夏天裏 夏天裡
+秋天裏 秋天裡
+冬天裏 冬天裡
+春日裏 春日裡
+夏日裏 夏日裡
+秋日裏 秋日裡
+冬日裏 冬日裡
+百科裏 百科裡
+歷史裏 歷史裡
+戲裏 戲裡
+作品裏 作品裡
+專輯裏 專輯裡
+年代裏 年代裡
+棺材裏 棺材裡
+嘴裏 嘴裡
+心裏 心裡
+皮裏陽秋 皮裡陽秋
+肚裏 肚裡
+苦裏 苦裡
+裏勾外連 裡勾外連
+裏面 裡面
+這裏 這裡
+點裏 點裡
+中文裏 中文裡
+山洞裏 山洞裡
+世界裏 世界裡
+眼睛裏 眼睛裡
+學裏 學裡
+獄裏 獄裡
+館裏 館裡
+系列裏 系列裡
+村子裏 村子裡
+青霉素 青黴素
+想象 想像
+锎 鉲
+信道 信道
+綫 線
diff --git a/maintenance/language/zhtable/toTrad.manual b/maintenance/language/zhtable/toTrad.manual
new file mode 100644
index 00000000..b0efd28e
--- /dev/null
+++ b/maintenance/language/zhtable/toTrad.manual
@@ -0,0 +1,186 @@
+手塚治虫 手塚治虫
+校仇 校讎
+仇校 讎校
+仇夷 讎夷
+仇問 讎問
+無言不仇 無言不讎
+視如寇仇 視如寇讎
+往日無仇 往日無讎
+近日無仇 近日無讎
+李連杰 李連杰
+周杰倫 周杰倫
+寶曆 寶曆
+涂謹申 涂謹申
+涂鴻欽 涂鴻欽
+涂壯勳 涂壯勳
+於姓 於姓
+於氏 於氏
+於夫羅 於夫羅
+於梨華 於梨華
+鄭凱云 鄭凱云
+筑陽 筑陽
+筑後 筑後
+采石磯 采石磯
+采石之戰 采石之戰
+張三丰 張三丰
+丰韻 丰韻
+丰儀 丰儀
+丰標不凡 丰標不凡
+干細胞 幹細胞
+干熱 乾熱
+二里頭 二里頭
+水里鄉 水里鄉
+蒙胧 朦朧
+酒曲 酒麴
+呆里呆气 呆裡呆氣
+拜托 拜託
+委托书 委託書
+委托 委託
+挽詞 輓詞
+挽聯 輓聯
+挽詩 輓詩
+於夫罗 於夫羅
+府干預 府干預
+府干擾 府干擾
+分布圖 分布圖
+頁面 頁面
+面條目 面條目
+黃鈺筑 黃鈺筑
+仿佛 彷彿
+凶殘 兇殘
+凶殺 兇殺
+緝凶 緝兇
+行凶後 行兇後
+買凶 買兇
+逞凶鬥狠 逞兇鬥狠
+合著者 合著者
+答复 答覆
+反复 反覆
+索馬里 索馬里
+洗练 洗鍊
+朝乾夕惕 朝乾夕惕
+乾象曆 乾象曆
+乾象历 乾象曆
+不好干預 不好干預
+不干預 不干預
+不干擾 不干擾
+不干牠 不干牠
+矽谷 矽谷
+范文瀾 范文瀾
+發表 發表
+機械系 機械系
+頂多 頂多
+馬占山 馬占山
+叱咤樂壇 叱咤樂壇
+闫怀礼 閆懷禮
+变髒 變髒
+薴烯 薴烯
+后豐 后豐
+于謙 于謙
+詩云 詩云
+鄭凱云 鄭凱云
+云為 云為
+古書云 古書云
+古語云 古語云
+經有云 經有云
+語有云 語有云
+显著标志 顯著標志
+占領 佔領
+采納 採納
+風采 風采
+于樂 于樂
+于軍 于軍
+于堅 于堅
+于帥 于帥
+于濤 于濤
+于贈 于贈
+于會泳 于會泳
+于偉國 于偉國
+于光遠 于光遠
+于鳳至 于鳳至
+于台煙 于台煙
+于國楨 于國楨
+于大寶 于大寶
+于學忠 于學忠
+于小偉 于小偉
+于山國 于山國
+于幼軍 于幼軍
+于廣洲 于廣洲
+于從濂 于從濂
+于志寧 于志寧
+于成龍 于成龍
+于明濤 于明濤
+于根偉 于根偉
+于樹潔 于樹潔
+于正昇 于正昇
+于漢超 于漢超
+于洪區 于洪區
+于湘蘭 于湘蘭
+于蔭霖 于蔭霖
+于遠偉 于遠偉
+于都縣 于都縣
+于震寰 于震寰
+于震環 于震環
+于非闇 于非闇
+于風政 于風政
+于鳳桐 于鳳桐
+于默奧 于默奧
+于爾岑 于爾岑
+于默奧 于默奧
+于貝爾 于貝爾
+于爾根 于爾根
+于雙戈 于雙戈
+于澤爾 于澤爾
+于斯達爾 于斯達爾
+于爾里克 于爾里克
+于奇庫杜克 于奇庫杜克
+于韋斯屈萊 于韋斯屈萊
+于克-蘭多縣 于克-蘭多縣
+于斯納爾斯貝里 于斯納爾斯貝里
+夏于喬 夏于喬
+涂澤民 涂澤民
+涂長望 涂長望
+涂敏恆 涂敏恆
+台历 枱曆
+艷后 艷后
+廢后 廢后
+后髮座 后髮座
+后髮星系團 后髮星系團
+后髮FK型星 后髮FK型星
+后海灣 后海灣
+賈后 賈后
+賢后 賢后
+呂后 呂后
+蟻后 蟻后
+馬格里布 馬格里布
+佳里鎮 佳里鎮
+埔裡社撫墾局 埔裏社撫墾局
+埔裏社撫墾局 埔裏社撫墾局
+有只採 有只採
+任何表達 任何表達
+會干擾 會干擾
+党項 党項
+余三勝 余三勝
+簡筑翎 簡筑翎
+楊雅筑 楊雅筑
+杰威爾音樂 杰威爾音樂
+尸羅精舍 尸羅精舍
+索馬里 索馬里
+騰格里 騰格里
+村里長 村里長
+進制 進制
+模范三軍 模范三軍
+黃詩杰 黃詩杰
+陳冲 陳冲
+劉佳怜 劉佳怜
+范賢惠 范賢惠
+于國治 于國治
+于楓 于楓
+黎吉雲 黎吉雲
+于飛島 于飛島
+鄉愿 鄉愿
+奇迹 奇蹟
+候复 候覆
+待复 待覆
+批复 批覆
+划槳 划槳
diff --git a/maintenance/language/zhtable/trad2simp.manual b/maintenance/language/zhtable/trad2simp.manual
new file mode 100644
index 00000000..747a240a
--- /dev/null
+++ b/maintenance/language/zhtable/trad2simp.manual
@@ -0,0 +1,153 @@
+U+04E99亙|U+04E98亘|
+U+04F48佈|U+05E03布|
+U+04F48佈|U+05E03布|
+U+04F54佔|U+05360占|
+U+05016倖|U+05E78幸|
+U+050A2傢|U+05BB6家|
+U+050F1僱|U+096C7雇|
+U+05138儸|U+03469㑩|U+07F57罗|
+U+05147兇|U+051F6凶|
+U+05277剷|U+094F2铲|
+U+052F3勳|U+052CB勋|
+U+0537D卽|U+05373即|
+U+053A4厤|U+05386历|
+U+055AB喫|U+05403吃|
+U+05641噁|U+06076恶|
+U+05690嚐|U+05C1D尝|
+U+056A5嚥|U+054BD咽|
+U+056AE嚮|U+05411向|
+U+056CC囌|U+082CF苏|
+U+0585A塚|U+051A2冢|
+U+058B0墰|U+0575B坛|
+U+058DC壜|U+0575B坛|
+U+05925夥|U+04F19伙|
+U+05BC0寀|U+091C7采|
+U+05D11崑|U+06606昆|
+U+05D19崙|U+04ED1仑|
+U+05D57嵗|U+05C81岁|
+U+05DBD嶽|U+05CB3岳|
+U+05DD6巖|U+05CA9岩|
+U+05DF9巹|U+0537A卺|
+U+05F14弔|U+0540A吊|
+U+05F46彆|U+0522B别|
+U+0617C慼|U+0621A戚|
+U+0617E慾|U+06B32欲|
+U+061DE懞|U+08499蒙|
+U+062DA拚|U+062FC拼|
+U+06331挱|U+06332挲|
+U+06371捱|U+06328挨|
+U+06372捲|U+05377卷|
+U+0647A摺|U+06298折|
+U+065C2旂|U+065D7旗|
+U+065E3旣|U+065E2既|
+U+06607昇|U+05347升|
+U+0672E朮|U+0672F术|
+U+068CA棊|U+068CB棋|
+U+069A6榦|U+05E72干|
+U+069D3槓|U+06760杠|
+U+06A11樑|U+06881梁|
+U+06B05欅|U+06989榉|
+U+06B4E歎|U+053F9叹|
+U+06BAD殭|U+050F5僵|
+U+06C59汙|U+06C61污|
+U+06CDD泝|U+06EAF溯|
+U+06D29洩|U+06CC4泄|
+U+06DD2淒|U+051C4凄|
+U+06DE8淨|U+051C0净|
+U+06DE9淩|U+051CC凌|
+U+06E67湧|U+06D8C涌|
+U+06ED9滙|U+06C47汇|
+U+06F90澐|U+06C84沄|
+U+06FBE澾|U+03CE0㳠|
+U+06FDB濛|U+06FDB濛|U+08499蒙|
+U+07030瀰|U+05F25弥|
+U+071EC燬|U+06BC1毁|
+U+07232爲|U+04E3A为|
+U+07343獃|U+05446呆|
+U+07515甕|U+074EE瓮|
+U+07526甦|U+082CF苏|
+U+0752F甯|U+05B81宁|
+U+0756B畫|U+0753B画|U+05212划|
+U+07575畵|U+0753B画|U+05212划|
+U+075E0痠|U+09178酸|
+U+07652癒|U+06108愈|
+U+07661癡|U+075F4痴|
+U+076C3盃|U+0676F杯|
+U+0771E眞|U+0771F真|
+U+077AD瞭|U+04E86了|
+U+077C7矇|U+08499蒙|
+U+07843硃|U+06731朱|
+U+07895碕|U+057FC埼|
+U+07958祘|U+07B97算|
+U+07A1C稜|U+068F1棱|
+U+07B87箇|U+04E2A个|
+U+07C11簑|U+084D1蓑|
+U+07C64籤|U+07B7E签|
+U+07C72籲|U+05401吁|
+U+07CF0糰|U+056E2团|
+U+07D2E紮|U+0624E扎|
+U+07DAB綫|U+07EBF线|
+U+07DB5綵|U+05F69彩|U+0433D䌽|
+U+07E34縴|U+07EA4纤|
+U+07E50繐|U+07A57穗|
+U+07E94纔|U+0624D才|
+U+07F4E罎|U+0575B坛|
+U+07FA8羨|U+07FA1羡|
+U+08123脣|U+05507唇|
+U+081E5臥|U+05367卧|
+U+08218舘|U+09986馆|
+U+083F4菴|U+05EB5庵|
+U+08457著|U+08457著|U+07740着|
+U+08518蔘|U+053C2参|
+U+08591薑|U+059DC姜|
+U+085C9藉|U+085C9藉|U+0501F借|
+U+0880D蠍|U+0874E蝎|
+U+0884A衊|U+08511蔑|
+U+088CF裏|U+091CC里|
+U+08946襆|U+05E5E幞|
+U+08986覆|U+08986覆|U+0590D复|
+U+08A17託|U+06258托|U+08BAC讬|
+U+08AEE諮|U+054A8咨|U+08C18谘|
+U+08B6D譭|U+06BC1毁|
+U+08B8E讎|U+04EC7仇|
+U+08B9A讚|U+08D5E赞|
+U+08C54豔|U+08273艳|
+U+08FF4迴|U+056DE回|
+U+09031週|U+05468周|
+U+0904A遊|U+06E38游|
+U+09061遡|U+06EAF溯|
+U+091A3醣|U+07CD6糖|
+U+091AF醯|U+09170酰|
+U+0934A鍊|U+070BC炼|U+094FE链|
+U+0938C鎌|U+09570镰|
+U+093AD鎭|U+093AE镇|
+U+093DA鏚|U+0621A戚|
+U+09451鑑|U+09274鉴|
+U+0955F镟|U+065CB旋|
+U+09592閒|U+095F2闲|
+U+095A4閤|U+05408合|
+U+095E2闢|U+08F9F辟|
+U+0962A阪|U+0962A阪|U+05742坂|
+U+0965E陞|U+05347升|
+U+097A6鞦|U+079CB秋|U+097A7鞧|
+U+097C6韆|U+05343千|
+U+097DD韝|U+097B2鞲|
+U+09858願|U+0613F愿|
+U+098F1飱|U+098E7飧|
+U+09918餘|U+04F59余|U+09980馀|
+U+09931餱|U+07CC7糇|
+U+09935餵|U+05582喂|
+U+09B28鬨|U+054C4哄|
+U+09D70鵰|U+096D5雕|U+05F6B彫|
+U+09E7C鹼|U+078B1碱|U+07877硷|
+U+09EAA麪|U+09762面|
+U+09EAB麫|U+09762面|
+U+09EAF麯|U+066F2曲|
+U+09EB4麴|U+066F2曲|U+09EB4麴|
+U+09EF4黴|U+09709霉|
+U+09F15鼕|U+051AC冬|
+U+09F47齇|U+09F44齄|
+U+09F63齣|U+051FA出|
+U+09F91龑|U+04DAE䶮|
+U+21ED5𡻕|U+05C81岁|
+U+298F5𩣵|U+299FB𩧻|
diff --git a/maintenance/language/zhtable/trad2simp_noconvert.manual b/maintenance/language/zhtable/trad2simp_noconvert.manual
new file mode 100644
index 00000000..052bab69
--- /dev/null
+++ b/maintenance/language/zhtable/trad2simp_noconvert.manual
@@ -0,0 +1,5 @@
+"余"=>
+碁
+藉
+=>"獃"
+𫚭
diff --git a/maintenance/language/zhtable/trad2simp_supp_set.manual b/maintenance/language/zhtable/trad2simp_supp_set.manual
new file mode 100644
index 00000000..d1728f0a
--- /dev/null
+++ b/maintenance/language/zhtable/trad2simp_supp_set.manual
@@ -0,0 +1,3 @@
+著 着
+藉 借
+濛 蒙 \ No newline at end of file
diff --git a/maintenance/language/zhtable/tradphrases.manual b/maintenance/language/zhtable/tradphrases.manual
new file mode 100644
index 00000000..e20ca05b
--- /dev/null
+++ b/maintenance/language/zhtable/tradphrases.manual
@@ -0,0 +1,4311 @@
+零隻
+〇隻
+一隻
+二隻
+兩隻
+三隻
+四隻
+五隻
+六隻
+七隻
+八隻
+九隻
+0隻
+1隻
+2隻
+3隻
+4隻
+5隻
+6隻
+7隻
+8隻
+9隻
+0隻
+1隻
+2隻
+3隻
+4隻
+5隻
+6隻
+7隻
+8隻
+9隻
+0只支援
+1只支援
+2只支援
+3只支援
+4只支援
+5只支援
+6只支援
+7只支援
+8只支援
+9只支援
+0只支持
+1只支持
+2只支持
+3只支持
+4只支持
+5只支持
+6只支持
+7只支持
+8只支持
+9只支持
+百隻
+千隻
+萬隻
+億隻
+最多
+至多
+頂多
+多隻
+0多隻
+0多隻
+零多隻
+十多隻
+百多隻
+千多隻
+萬多隻
+億多隻
+這只能
+這只可
+這只在
+這只是
+這只需
+這只會
+這只用
+那只能
+那只可
+那只在
+那只是
+那只需
+那只會
+那只用
+多只能
+多只可
+多只在
+多只有
+多只是
+多只需
+多只會
+多只用
+大只能
+大只可
+大只在
+大只有
+大只是
+大只需
+大只會
+小只能
+小只可
+小只在
+小只有
+小只是
+小只需
+小只會
+隻身
+形單影隻
+首隻
+數天後
+幾天後
+多天後
+零天後
+一天後
+二天後
+兩天後
+三天後
+四天後
+五天後
+六天後
+七天後
+八天後
+九天後
+十天後
+百天後
+千天後
+萬天後
+億天後
+0天後
+1天後
+2天後
+3天後
+4天後
+5天後
+6天後
+7天後
+8天後
+9天後
+0天後
+1天後
+2天後
+3天後
+4天後
+5天後
+6天後
+7天後
+8天後
+9天後
+天後來
+天後天
+天後半
+後印
+萬象
+並存著
+乾絲
+乾著急
+乾魚
+魚乾
+乾梅
+糕乾
+黃乾黑瘦
+馬乾
+香乾
+趲幹
+謀幹
+詞幹
+蟶乾
+薄幹
+腦幹
+營幹
+老乾
+老幹部
+管幹
+盲幹
+煨乾
+海乾
+乾漆
+淚乾
+沒幹
+沒乾沒淨
+枝不得大於榦
+杯乾
+打幹
+打乾噦
+徐幹
+府幹
+乾館
+乾顙
+幹革命
+乾霍亂
+乾雷
+乾阿奶
+乾量
+乾醋
+乾逼
+乾貨
+乾衣
+幹蠱
+乾虔
+乾落
+幹營生
+乾茶錢
+乾茨臘
+乾苔
+乾花
+乾肥
+乾耗
+幹缺
+乾繃
+乾結
+乾餱
+乾篾片
+乾稿
+乾禮
+乾瞪眼
+乾白兒
+乾疥
+乾生子
+乾生受
+幹父之蠱
+乾熬
+乾燈盞
+乾濕
+乾澀
+幹濟
+乾沒
+乾死
+乾村沙
+乾暖
+乾料
+乾敲梆子不賣油
+乾支支
+乾支剌
+乾擦
+乾撇下
+乾撂台
+乾折
+乾急
+幹當
+乾式
+乾屎橛
+幹家
+乾奴才
+幹頭
+乾塢
+乾圓潔淨
+乾回付
+乾啼
+乾哭
+乾噦
+乾咽
+乾和
+幹吏
+乾吊著下巴
+乾號
+乾颱
+乾卦
+乾剝剝
+乾刻版
+乾芻
+幹人
+乾產
+乾喬
+夯幹
+大目乾連
+國之楨榦
+唇乾
+單幹
+勾幹
+豆乾
+果乾
+如果幹
+乾麵
+乾柴
+枯乾
+晒乾
+顛乾倒坤
+強幹
+乾著
+乾眼
+幹的停當
+乾巴
+偎乾
+眼乾
+偷雞不著
+几絲
+划著
+划著走
+別著
+刮著
+千絲萬縷
+參合
+參考價值
+參與
+參與人員
+參與制
+參與感
+參與者
+參觀團
+參觀團體
+參閱
+吃著不盡
+合著
+吊帶褲
+吊掛著
+吊著
+吊褲
+吊褲帶
+向著
+嚴絲合縫
+回絲
+回著
+塗著
+壟斷價格
+壟斷資產
+壟斷集團
+姜絲
+帶團參加
+干著急
+幾絲
+彆著
+怎麼著
+憑藉著
+憑藉
+接著說
+擔著
+擔負著
+敘說著
+斗轉參橫
+旋繞著
+板著臉
+正當著
+沈著
+沖著
+派團參加
+涂著
+湊合著
+瀰漫著
+為著
+煙斗絲
+率團參加
+畫著
+當著
+發著
+直接參与
+睡著了
+秋褲
+積极參与
+積极參加
+簽著
+系著
+絕對參照
+絲來線去
+絲布
+絲板
+絲瓜布
+絲絨布
+絲線
+絲織廠
+絲蟲
+緊繃著
+繃著
+繃著臉
+繃著臉兒
+繫著
+罵著
+肉絲麵
+背向著
+菌絲體
+著兒
+著書立說
+著色軟體
+著重指出
+著錄
+著錄規則
+薑絲
+藉著
+蘊含著
+蘊涵著
+衝著
+被覆著
+覆著
+覆蓋著
+反覆
+訴說著
+說著
+請參閱
+謝絕參觀
+豎著
+豐濱
+豐濱鄉
+豐度
+象徵著
+這麼著
+那麼著
+配合著
+醞釀著
+錄著
+鍛鍊出
+關係著
+雞絲
+雞絲麵
+面朝著
+面臨著
+颳著
+髮絲
+斷髮
+不斷發
+判斷發
+評斷發
+買斷發
+賣斷發
+打斷發
+披頭散髮
+髮禁
+鬥著
+鬧著玩兒
+鯰魚
+世界盃
+其次辟地
+開闢
+闢地
+精闢
+別闢
+另闢
+闢佛
+闢田
+闢築
+闢謠
+闢辟
+透闢
+墾闢
+翕闢
+軒闢
+闢建
+闢室
+各闢
+增闢
+闢邪以律
+錶盤
+錶板
+錶帶
+錶針
+錶蒙子
+袋錶
+腕錶
+碼錶
+錶冠
+魔錶
+彆口氣
+彆強
+皺彆
+一彆頭
+并州
+併兼
+併產
+併骨
+併網
+併線
+併流
+逼併
+併名
+併當
+併火
+併肩子
+併除
+併疊
+忙併
+打併
+簡併
+並發表
+並發現
+並發展
+並發動
+並發布
+火並非
+舉手表
+揮手表
+併一不二
+連三併四
+相併
+撤併
+數罪併罰
+催併
+狂併潮
+薝蔔
+提摩太後書
+當家纔知柴米價
+剛纔一載
+裏海
+骨頭裡掙出來的錢纔做得肉
+恰纔
+遠縣纔至
+別日南鴻纔北去
+然身死纔數月耳
+纔得兩年
+纔則
+纔此
+你纔子發昏
+纔可容顏十五餘
+不採
+披榛採蘭
+謬採虛聲
+採樵人
+回採
+觀採
+開採
+揪採
+樵採
+採訪
+採辦
+採補
+採買
+採風問俗
+採納
+採獵
+採蓮
+採錄
+採購
+採光
+採礦
+採花
+採集
+採擷
+採掘
+採芹人
+採取
+採選
+採摭
+採摘
+採珠
+採種
+採茶
+採石
+採拾
+採收
+採生折割
+採樹種
+採擇
+採藥
+採薇
+採用
+盜採
+採信
+採行
+採證
+採菊
+博採
+採空採穗
+採挖
+採鐵
+採金
+採氣
+採油
+採煤
+採鹽
+採區
+採運
+採風
+官地為寀
+寮寀
+蔘綏
+個人# “個人參數”不是“個人蔘數”
+人蔘
+蕭蔘
+人參與
+人參選
+人參觀
+人參考
+人參展
+人參加
+人參議
+人參謀
+人參酌
+人參照
+人參政
+人參戰
+人參拜
+人參閱
+人參禪
+人參贊
+人參見
+人參透
+人參看
+東衝西突
+天克地衝
+六衝
+撞陣衝軍
+衝波
+衝風
+衝頭陣
+衝堅陷陣
+衝陷
+衝心
+衝州撞府
+衝殺
+衝然
+衝盹
+左衝右突
+虫部
+手塚治虫
+群醜
+百拙千醜
+大醜
+地醜德齊
+丟醜
+亮醜
+揭醜
+倛醜
+嫌好道醜
+醜巴怪
+醜末
+醜婦
+醜地
+醜頭怪臉
+醜女效顰
+醜剌剌
+醜話
+醜媳
+醜吒
+醜聲遠播
+醜夷
+弄醜
+露醜
+摧堅獲醜
+謷醜
+不嫌母醜
+一爭兩醜
+惡直醜正
+很醜
+醜男
+醜斃了
+醜奴兒
+醜言
+醜徒
+醜雜
+醜儕
+醜沮
+醜辭
+醜比
+醜辱
+醜逆
+醜史
+醜賊生
+醜婆子
+出乖弄醜
+出乖露醜
+獲匪其醜
+乙丑
+丁丑
+己丑
+辛丑
+癸丑
+丑時
+丑日
+丑月
+丑年
+文丑
+武丑
+女丑
+小丑
+大丑
+丑婆子
+丑旦
+丑角
+丑三
+丑表功
+公孫丑
+么麼小丑
+齣電影
+齣電視
+齣動畫
+齣節目
+齣卡通
+齣戲
+齣劇
+平平當當
+滿滿當當
+當當丁丁
+丁丁當當
+停停當當
+快快當當
+咯噹
+啷噹
+党參
+党進
+党太尉
+党項
+撲鼕
+洗髮
+牽一髮
+白發其事
+后髮座
+后髮星系團
+后髮FK型星
+波髮藻
+辮髮
+逋髮
+抿髮
+髮漂
+髮匪
+髮腳
+髮癬
+髮釵
+髮飾
+髮紗
+髮上指冠
+髮上沖冠
+髮乳
+髮引千鈞
+髮踴沖冠
+董氏封髮
+胎髮
+禿妃之髮
+捉髮
+綠髮
+括髮
+髡髮
+鵠髮
+截髮
+解髮佯狂
+淨髮
+秋髮
+噙齒戴髮
+青山一髮
+晞髮
+細不容髮
+心細如髮
+祝髮
+擢髮
+齒髮
+齒危髮秀
+沖冠髮怒
+甩髮
+絲髮
+絲恩髮怨
+蒜髮
+算髮
+有髮頭陀寺
+髮箋
+髮屋
+櫛髮工
+鬒髮
+模范棒棒堂
+模范三軍
+模范七棒
+模范14棒
+模范21棒
+顏範
+儀範
+典範
+坤範
+壼範
+容範
+懿範
+明範
+格範
+模範
+樣範
+母範
+洪範
+淑範
+遺範
+科範
+立範
+貽範
+道範
+閨範
+閫範
+雅範
+霽範
+鴻範
+沒樣範
+錢範
+銅範
+金範
+範金
+垂範
+範性形變
+範字
+有事之無範
+置言成範
+吾爲之範我馳驅
+天地為範
+範數
+丰采
+丰標不凡
+丰神
+丰茸
+丰儀
+丰度
+丰情
+丰韵
+子之丰兮
+艸木丰丰
+張三丰
+復始
+複分析
+複輔音
+複元音
+複平面
+複函數
+複流
+反複製
+複對數
+顛覆
+答覆
+覆沒
+覆亡
+覆水難收
+翻雲覆雨
+覆雨翻雲
+覆轍
+覆巢之下無完卵
+覆蓋
+覆命
+天翻地覆
+天覆地載
+撥穀
+扁擬穀盜蟲
+不穀
+辟穀
+米穀
+田穀
+脫穀機
+年穀
+礱穀機
+孤寡不穀
+穀米
+穀旦
+穀圭
+穀貴餓農
+穀食
+穀日
+館穀
+禾穀
+積穀
+嘉穀
+嚼穀
+九穀
+戩穀
+錢穀
+息穀
+殖穀
+川穀
+曬穀
+臧穀亡羊
+種穀
+颳雪
+刮風下雪倒便宜
+广部
+亂鬨不過來
+斗鬨
+亂鬨
+開鬨
+花鬨
+鬨動
+交鬨
+喧鬨
+起鬨
+內鬨
+於後
+猜三划五
+划龍舟
+南迴線
+南迴鐵路
+北迴線
+北迴鐵路
+文匯報
+河流匯集
+品彙
+博彙
+滙豐
+伙頭
+方几
+伏几
+高几
+雪窗螢几
+燕几
+隱几
+饑饉
+乾薑
+毛薑
+薑母
+薑湯
+薑桂
+薑是老的辣
+吃薑
+薑老辣
+野薑
+咬薑呷醋
+薑蓉
+薑黃
+狐藉虎威
+滑藉
+藉寇兵
+藉箸代籌
+藉手
+藉此
+龍捲
+捲舌
+夸父
+夸克
+夸特
+夸毗
+夸麗
+夸姣
+夸人
+夸容
+大言非夸
+言大而夸
+睏覺
+愛睏
+纍堆
+纍紲
+纍臣
+纍瓦結繩
+湘纍
+印纍綬若
+灕湘
+灕然
+澤滲灕而下降
+裏勾外連
+裏手
+水里鄉
+水里溪
+水里濁水溪
+二里頭
+年歷史
+西歷史
+國歷史
+國歷代
+國歷任
+國歷屆
+國歷經
+國歷來
+新歷史
+夏歷史
+百花曆
+寶曆
+穆罕默德曆
+大明曆
+大曆
+台曆
+太初曆
+通曆
+曆本
+曆命
+曆紀
+曆始
+曆室
+曆日
+曆尾
+曆元
+律曆志
+官曆
+回曆
+巧曆
+慶曆
+朱理安曆
+長曆
+藏曆
+四分曆
+三統曆
+額我略曆
+埃及曆
+伊斯蘭教曆
+合曆
+玉曆
+農民曆
+桌曆
+商曆
+周曆
+大衍曆
+皇極曆
+儒略改革曆
+希伯來曆
+格里曆
+格里高利曆
+共和曆
+掛曆
+曆獄
+天文曆表
+日心曆表
+地心曆表
+復活節曆表
+月球曆表
+伊爾汗曆表
+延曆
+共和歷史
+厤物之意
+爰定祥厤
+白黴
+黴黧
+黴黑
+麴黴
+蒙霧露
+懞懞懂懂
+懞直
+老懞
+放懞掙
+矇著
+矇聵
+矇瞍
+矇事
+矇頭轉
+矇松雨
+藏矇歌兒
+矇著鍋兒
+朦朧
+濛濛細雨
+濛汜
+冥濛
+溟濛
+淡濛濛
+凌濛初
+涳濛
+灰濛濛
+澒濛
+瀰山遍野
+瀰瀰
+冷麵
+撈麵
+煮麵
+炆麵
+煎麵
+泡麵
+食麵
+公仔麵
+方便麵
+白粉麵
+棒子麵
+麵缸
+麵坯兒
+麵碼兒
+麵坊
+麵湯
+麵疙瘩
+麵館
+麵漿
+甜水麵
+麵人兒
+麵塑
+捏麵人
+趕麵棍
+擀麵
+過水麵
+蕎麥麵
+巧婦做不得無麵餺飥
+削麵
+小米麵
+壯麵
+吃板刀麵
+吃辣麵
+扯麵
+搋麵
+重羅麵
+雜麵
+雜合麵兒
+溲麵
+索麵
+一鍋麵
+伊府麵
+藥麵兒
+意大利麵
+湯下麵
+茶麵
+麵糰
+冷面相
+糞穢衊面
+湟潦生苹
+食野之苹
+苹縈
+青苹
+青蘋果
+僕僕
+有僕
+冉有僕
+屢顧爾僕
+僕少
+僕雖罷駑
+僕夫
+僕僮
+僕吏
+僕姑
+僕固懷恩
+僕程
+僕使
+僕憎
+僕歐
+僕射
+太僕
+僮僕
+金僕姑
+僕婢
+樸實
+樸訥
+樸念仁
+白樸
+抱素懷樸
+抱朴而長吟兮
+樸鄙
+樸馬
+樸父
+樸陋
+樸魯
+樸厚
+樸學
+樸質
+樸拙
+樸重
+樸素
+樸樕
+樸野
+反樸
+古樸
+胡樸安
+返樸
+渾樸
+儉樸
+簡樸
+拙樸
+斫雕為樸
+斲雕為樸
+質樸
+誠樸
+純樸
+曾樸
+郁樸
+棫樸
+敦樸
+樸鈍
+樸直
+見素抱樸
+掣籤
+標籤
+書籤
+發籤
+粉籤子
+路籤
+更籤
+好籤
+火籤
+籤幐
+籤押
+照入籤
+制籤
+抽公籤
+瑤籤
+藥籤
+萬籤插架
+雲笈七籤
+上簽名
+上簽字
+上簽收
+上簽寫
+下簽名
+下簽字
+下簽收
+下簽寫
+犖确
+磽确
+确瘠
+言辯而确
+數與虜确
+關弓與我确
+拚捨
+廣捨
+齊王捨牛
+捨墮
+捨實
+棄捨
+捨安就危
+施舍之道
+瀋河
+瀋水
+瀋州
+瀋山線
+瀋吉線
+墨沈
+瀋海鐵路
+遼瀋
+胜肽
+胜鍵
+雙胜類
+兀朮
+白朮
+蒼朮
+赤朮
+朮赤
+髼鬆
+皮鬆
+濛鬆雨
+發鬆
+翻鬆
+浮鬆
+弄鬆
+精鬆
+懈鬆
+鬆蛋
+鬆寬
+鬆氣
+鬆一口氣
+鬆元音
+鬆喉
+囉囉囌囌
+囉囌
+骨罈
+罈騞
+餵驢
+剪牡丹喂牛
+鹹粥
+鹹食
+鹹潟
+鹹嘴淡舌
+鹽打怎麼鹹
+鹹派
+鹹批
+錦綉花園
+籲天
+勃鬱
+怫鬱
+氣鬱
+沉鬱
+神荼鬱壘
+躁鬱
+蒼鬱
+漚鬱
+伊鬱
+壹鬱
+悒鬱
+氤鬱
+湮鬱
+陰鬱
+泱鬱
+坱鬱
+滃鬱
+蓊鬱
+紆鬱
+鬱勃
+鬱陶
+鬱律
+鬱壘
+鬱火
+鬱積
+鬱金
+鬱江
+鬱血
+鬱蒸
+鬱症
+鬱沉沉
+鬱熱
+鬱塞
+鬱伊
+鬱邑
+鬱挹
+鬱堙不偶
+鬱泱
+鬱蓊
+鬱紆
+鬱燠
+肝鬱
+鬱卒
+鬱鬱不平
+鬱鬱不樂
+鬱鬱寡歡
+鬱鬱蔥蔥
+鬱鬱而終
+愿樸
+愿而恭
+許愿起經
+北嶽
+嶽麓
+但云
+胡云
+詩云
+注云
+鄭凱云
+云乎
+云然
+云為
+對摺
+網誌
+標標致致
+澄澹精致
+呆緻緻
+光緻緻
+工緻
+功緻
+縝緻
+堅緻
+种放
+种師道
+种師中
+後庄
+舊庄
+正官庄
+龜山庄
+寶山庄
+冬山庄
+員山庄
+松山庄
+厂部
+閤府
+佈道
+剪綵
+衝量
+衝車
+書獃子
+相干
+府干預
+府干涉
+府干政
+府干擾
+府干犯
+府干卿
+一干人
+未乾
+未干涉
+抹乾
+餅乾
+拭乾
+擦乾
+晾乾
+烘乾
+肉乾
+菜乾
+腐乾
+乾脆
+乾淨
+乾燥
+乾旱
+乾涸
+乾洗
+乾女
+乾等
+乾糧
+乾枯
+乾薪
+乾爹
+乾粉
+乾爽
+乾兒
+乾子
+乾渴
+乾股
+乾果
+乾草
+乾菜
+乾笑
+乾餾
+乾電
+乾飯
+乾冰
+乾嘔
+乾材
+乾媽
+乾季
+葡萄乾
+提子乾
+蘿蔔乾
+蘋果乾
+芒果乾
+菠蘿乾
+鳳梨乾
+豆腐乾
+果子乾
+龍眼乾
+乾乾淨淨
+乾柴烈火
+乾乾兒的
+桑乾
+撈乾
+搭乾鋪
+揩乾
+敢幹
+幹探
+幹事
+幹什麼
+幹細胞
+悶著頭兒幹
+配水幹管
+繐幃飄井幹
+站乾岸兒
+秋陰入井幹
+沒梢幹
+楨幹
+據榦而窺井底
+井榦摧敗
+杰特
+李連杰
+周杰倫
+杰倫
+姜文杰
+稜鏡
+稜角
+稜台
+稜錐
+觚稜
+稜子
+稜層
+稜柱
+盧稜伽
+波稜菜
+菠稜菜
+稜縫
+稜等登
+稜稜
+嶒稜
+蹭稜子
+稜體
+二不稜登
+有稜有角
+威稜
+負債纍纍
+傷痕纍纍
+儒略曆
+伊斯蘭曆
+酒麴
+昇平
+爾冬陞
+澹臺
+拜託
+委託
+輓曲
+敬輓
+万俟
+万旗
+鬚鯨
+鬚鯊
+兇手
+兇徒
+兇案
+兇器
+兇殺
+兇殘
+行兇
+緝兇
+追兇
+真兇
+疑兇
+買兇
+元兇
+叶韻
+叶音
+叶恭弘
+叶 恭弘
+叶 恭弘
+於1
+於2
+於3
+於4
+於5
+於6
+於7
+於8
+於9
+於0
+於1
+於2
+於3
+於4
+於5
+於6
+於7
+於8
+於9
+於0
+於一
+於二
+於三
+於四
+於五
+於六
+於七
+於八
+於九
+於十
+於半
+於夫羅
+於梨華
+置於
+佈於
+散於
+播於
+國於
+敗於
+於一役
+畢於
+畢業於
+寒於
+任於
+拘於
+插於
+中於
+於市
+於野
+敏於
+聽於
+短於
+成於
+樊於期
+淡於
+於陸
+於密
+於盡
+禍於
+格於
+猛於
+施於
+於牆
+於物
+於己
+於你
+於我
+於他
+於她
+於它
+於祂
+拒人於
+拒於
+潰於
+窮於
+相於
+形於
+半於
+於始
+於終
+詢於
+美於
+醜於
+好於
+坏於
+強於
+弱於
+差於
+劣於
+於美
+於醜
+於好
+於坏
+於強
+於弱
+於差
+於劣
+於垂
+染指於
+於火
+存十一於千百
+存於
+於勤
+隱於
+藏於
+嚴於
+寬於
+於幕
+給於
+於穆
+於呼哀哉
+於時
+於該
+危於
+於伏
+於何
+於家
+於國
+於潛縣
+於焉
+於徵
+離於
+於畢
+麗於
+下於
+亞於
+同於
+屑於
+絕於
+致於
+於行
+遜於
+任教於
+教於
+自於
+來於
+附於
+於人
+於世
+阻於
+於民
+於盲
+於色
+囿於
+直於
+建於
+都於
+於農
+於樂
+於前
+役於
+於心
+於法
+於事
+助於
+害於
+損於
+益於
+從於
+隨於
+順於
+汲於
+溺於
+迷於
+醉於
+行於
+泥於
+身於
+足於
+溢於
+於衷
+畏於
+視於
+衷於
+狃於
+疲於
+通於
+於途
+老於
+耿於
+於懷
+服於
+臻於
+匿於
+因於
+似於
+遷於
+怒於
+心於
+集於
+容於
+髒詞
+髒心
+新紮
+紙紮
+紮鐵
+紮寨
+一紮
+兩紮
+三紮
+四紮
+五紮
+六紮
+七紮
+八紮
+九紮
+十紮
+百紮
+千紮
+萬紮
+佔1
+佔2
+佔3
+佔4
+佔5
+佔6
+佔7
+佔8
+佔9
+佔0
+佔1
+佔2
+佔3
+佔4
+佔5
+佔6
+佔7
+佔8
+佔9
+佔0
+佔零
+佔〇
+佔一
+佔二
+佔兩
+佔三
+佔四
+佔五
+佔六
+佔七
+佔八
+佔九
+佔十
+佔百
+佔千
+佔万
+佔億
+佔超過
+佔不足
+佔至少
+佔少
+佔至多
+佔半
+佔多
+佔大
+佔小
+佔中
+佔東
+佔西
+佔南
+佔北
+佔平均
+佔總
+獨佔鰲頭
+所佔
+市佔
+佔率
+市佔率
+佔市場
+佔世界
+佔全
+佔國內
+佔美
+佔台
+佔香
+佔澳
+佔加
+佔新
+佔馬
+佔印
+佔英
+佔法
+佔德
+佔葡
+佔俄
+佔蘇
+佔缺
+佔A
+佔B
+佔C
+佔D
+佔E
+佔F
+佔G
+佔H
+佔I
+佔J
+佔K
+佔L
+佔M
+佔N
+佔O
+佔P
+佔Q
+佔R
+佔S
+佔T
+佔U
+佔V
+佔W
+佔X
+佔Y
+佔Z
+佔a
+佔b
+佔c
+佔d
+佔e
+佔f
+佔g
+佔h
+佔i
+佔j
+佔k
+佔l
+佔m
+佔n
+佔o
+佔p
+佔q
+佔r
+佔s
+佔t
+佔u
+佔v
+佔w
+佔x
+佔y
+佔z
+佔A
+佔B
+佔C
+佔D
+佔E
+佔F
+佔G
+佔H
+佔I
+佔J
+佔K
+佔L
+佔M
+佔N
+佔O
+佔P
+佔Q
+佔R
+佔S
+佔T
+佔U
+佔V
+佔W
+佔X
+佔Y
+佔Z
+佔a
+佔b
+佔c
+佔d
+佔e
+佔f
+佔g
+佔h
+佔i
+佔j
+佔k
+佔l
+佔m
+佔n
+佔o
+佔p
+佔q
+佔r
+佔s
+佔t
+佔u
+佔v
+佔w
+佔x
+佔y
+佔z
+佔不佔
+不佔
+佔了
+佔穩
+佔資源
+佔人便宜
+佔頭
+佔道
+佔屋
+佔網
+佔床
+佔座
+佔分
+佔飯
+佔個位
+佔後
+佔著
+佔山
+馬占山
+佔比
+佔停車
+佔哺乳
+佔下風
+少佔
+多佔
+費佔
+佔查
+佔壓
+佔優
+佔劣
+穩佔
+佔整體
+佔局部
+日佔
+美佔
+英佔
+德佔
+法佔
+俄佔
+葡佔
+西佔
+奧佔
+意佔
+義佔
+地佔
+佔場
+佔耕
+狂佔
+徵佔
+圈佔
+已佔
+佔囁
+佔主
+佔次
+寡佔
+佔去
+將佔
+將占卜
+要佔
+要占卜
+會佔
+會占卜
+占卜
+夢有五不占
+占有五不驗
+誌異
+筑前
+筑後
+筑紫
+筑波
+筑州
+筑肥
+筑西
+筑北
+肥筑方言
+筑邦
+筑陽
+南筑
+批准的
+核准的
+為準
+準直
+擺鐘
+編鐘
+碰鐘
+鳴鐘
+晨鐘
+鐘體
+飯後鐘
+盜鐘
+一天鐘
+撞鐘
+殿鐘自鳴
+天文鐘
+天文學鐘
+洛鐘東應
+亮鐘
+郘鐘
+歌鐘
+鐘不撞不鳴
+毀鐘為鐸
+洪鐘
+擊鐘
+警世鐘
+竊鐘掩耳
+琴鐘
+見鐘不打
+釁鐘
+朝鐘
+木鐘
+鐘不扣不鳴
+鐘鳴
+鐘塔
+鐘漏
+鐘琴
+鐘磬
+鐘形蟲
+鐘乳洞
+鐘乳石
+鐘在寺裡
+詩鐘
+懸鐘
+山崩鐘應
+坐鐘
+宗周鐘
+塞耳盜鐘
+二缶鐘惑
+口鐘
+鐘的
+的鐘
+這鐘
+叩鐘
+音聲如鐘
+應鐘
+原子鐘
+泳氣鐘
+電子鐘
+電子鐘錶
+石英鐘錶
+石英鐘
+鐘錶王
+鐘律
+看鐘
+看錶
+看表面
+鐵鐘
+看下鐘
+看下錶
+瞅下鐘
+瞅下錶
+拿下鐘
+拿下錶
+鐘不敲不響
+對準鐘
+對準鐘錶
+對準錶
+鐘錶快
+鐘快
+錶快
+鐘錶慢
+鐘慢
+錶慢
+響鐘
+鐘敲
+大本鐘敲
+大笨鐘敲
+世紀鐘錶
+世紀鐘
+錶王
+鐘王
+鐘錶
+古鐘
+古鐘錶
+鐘面
+鐘表面
+南京鐘
+南京鐘錶
+造鐘錶
+造鐘
+九龍表行
+鐘錶行
+鐘行
+錶行
+小型鐘表面
+小型鐘面
+小型鐘錶
+小型鐘
+中型鐘表面
+中型鐘面
+中型鐘錶
+中型鐘
+大型鐘表面
+大型鐘面
+大型鐘錶
+大型鐘
+鐘匠
+深山何處鐘
+下課鐘
+上課鐘
+老爺鐘
+萬年曆錶
+個鐘
+個鐘錶
+喜歡鐘
+喜歡鐘錶
+喜歡錶
+大鐘
+佛鐘
+鐘壁
+鐘腰
+鐘口
+鐘身
+鐘模
+鐘頂
+鐘紐
+鐘座
+他鐘
+寺鐘
+座鐘
+盜鐘
+大笨鐘
+大本鐘
+鐘錶歷史
+錶的歷史
+鐘錶的歷史
+點多鐘
+點半鐘
+分多鐘
+刻多鐘
+分半鐘
+刻半鐘
+教學鐘
+操作鐘
+南屏晚鐘
+敲鐘
+瞧著鐘
+瞧著鐘錶
+瞧著錶
+警報鐘
+猶如鐘
+猶如鐘錶
+猶如錶
+舊鐘錶
+繁鐘
+四面鐘
+更鐘
+警示鐘
+鐘差
+任何鐘錶
+任何鐘
+任何錶
+任何表示
+任何表達
+任何表演
+選手表現
+選手表達
+選手表示
+選手表明
+選手表決
+分子鐘
+飛行鐘
+鐘罩
+主鐘差
+花鐘
+磬鐘
+主鐘曲線
+鐘速
+紅鐘
+各類鐘
+打著鐘
+鐘意
+衛星鐘
+該鐘
+錶轉
+鐘調
+調鐘錶
+調錶
+原鐘
+鐘錶速
+件鐘
+鐘發音
+逆鐘
+拂鐘無聲
+鐘不空則啞
+看著鐘錶
+看著鐘
+看著錶
+晚鐘
+潛水鐘錶
+潛水鐘
+潛水錶
+樂器鐘
+鐘左右
+埋頭尋鐘錶
+埋頭尋鐘
+埋頭尋錶
+鐘陳列
+驚鐘
+望著鐘錶
+望著鐘
+望著錶
+鐘錶停
+鐘停
+銫鐘
+數字鐘錶
+數字鐘
+顯示鐘錶
+顯示鐘
+顯示錶
+坐如鐘
+錶停
+西周鐘
+東周鐘
+錶速
+機械鐘錶
+機械鐘
+機械錶
+之鐘
+鐘形
+架鐘
+順鐘向
+逆鐘向
+遺傳鐘
+鬧錶
+華嚴鐘
+懷鐘
+生物鐘
+鐘錶的
+錶的嘀嗒
+的鐘錶
+嘀嗒的錶
+鐘好
+鐘太
+鐘不
+鐘有
+鐘盤
+鐘錶盤
+鐘沒
+鐘被
+制鐘
+布穀鳥鐘
+咕咕鐘
+拉克施爾德鐘
+鐘上
+鐘下
+摸鐘
+舊鐘
+舊錶
+台鐘
+鐘響
+叩鐘
+計時錶
+防水錶
+射鵰
+神鵰
+神雕像
+采石磯
+采石之戰
+采石之役
+聊齋志異
+部落發
+角落發
+村落發
+蛇髮女妖
+畢生發展
+對華發動
+中美發表
+尸魂界
+樹樑
+屋樑
+樑柱
+柱樑
+下樑
+上梁山
+昇陽
+僥倖
+夏遊
+秋遊
+冬遊
+黑奴籲天錄
+林郁方
+讚歌
+編餘
+餘墨
+唾餘
+餘韻
+歸餘
+公餘
+寬餘
+餘糧
+餘慶
+餘殃
+餘燼
+劫餘
+結餘
+燼餘
+淨餘
+餕餘
+餘暉
+餘輝
+羨餘
+餘悸
+心餘
+刑餘
+緒餘
+血餘
+朱慶餘
+諸餘
+餘論
+茶餘
+廚餘
+餘裕
+餘氣
+詩餘
+詞餘
+餘僇
+餘辜
+餘責
+餘罪
+無餘
+耳餘
+餘烈
+餘思
+鹽餘
+嬴餘
+贏餘
+王餘魚
+紆餘
+餘波
+餘杯
+餘步
+餘妙
+餘音
+餘聲
+餘明
+餘風
+餘黨
+餘毒
+餘桃
+餘桶
+餘利
+餘瀝
+餘膏
+餘光
+餘杭
+餘竅
+餘缺
+餘暇
+餘閒
+餘羨
+餘響
+餘興
+餘蓄
+餘緒
+餘珍
+餘眾
+餘酲
+餘喘
+餘食
+餘熱
+餘刃
+餘閏
+餘存
+餘業
+餘姚
+餘蔭
+餘映
+餘外
+餘威
+餘味
+餘溫
+餘勇
+多餘
+剩餘
+餘生
+餘歡
+有餘
+一餘
+二餘
+兩餘
+三餘
+四餘
+五餘
+六餘
+七餘
+八餘
+九餘
+十餘
+百餘
+千餘
+萬餘
+億餘
+兆餘
+0餘
+1餘
+2餘
+3餘
+4餘
+5餘
+6餘
+7餘
+8餘
+9餘
+0餘
+1餘
+2餘
+3餘
+4餘
+5餘
+6餘
+7餘
+8餘
+9餘
+余姓
+余光生
+余光中
+余思敏
+余威德
+余子明
+余三勝
+崑山
+崑曲
+崑腔
+崑調
+崑劇
+崑蘇
+蘇崑
+分布圖
+一干家中
+星期後
+不准你
+不准我
+不准他
+不准她
+不准它
+不准誰
+不准許
+准不准你
+准不准我
+准不准他
+准不准她
+准不准它
+准不准誰
+准不准許
+依依不捨
+戀戀不捨
+窮追不捨
+緊追不捨
+鍥而不捨
+稜登
+前言不答後語
+繃扒弔拷
+不弔
+不通弔慶
+陪弔
+盆弔
+屁股大弔了心
+撇弔
+憑弔
+門弔兒
+伐罪弔民
+打出弔入
+搗鬼弔白
+弔膀子
+弔民
+弔民伐罪
+弔奠
+弔頭
+弔古
+弔古尋幽
+弔詭
+弔詭矜奇
+弔客
+弔拷
+弔拷繃扒
+弔扣
+弔賀迎送
+弔鶴
+弔喉
+弔謊
+弔祭
+弔腳兒事
+弔頸
+弔橋
+弔取
+弔孝
+弔紙
+弔者大悅
+弔場
+弔書
+弔詞
+弔死問孤
+弔死問疾
+弔撒
+弔喪
+弔喪問疾
+弔腰撒跨
+弔唁
+弔宴
+弔喭
+弔影
+弔慰
+弔文
+弔問
+頭巾弔在水裡
+提心弔膽
+弄鬼弔猴
+管人弔腳兒事
+開弔
+鶴弔
+昊天不弔
+花馬弔嘴
+會弔
+吉凶慶弔
+蟣蝨相弔
+祭弔
+祭弔文
+青蠅弔客
+慶弔
+形影相弔
+哀弔
+一弔
+唁弔
+於水
+安於
+迫於
+罷於
+蹪於
+於敝
+於過
+甚於
+等於
+定於
+利於
+對於
+推舟於陸
+退藏於密
+歸於
+難於
+移禍於
+生於
+立於
+多於
+勝於
+傳於
+流於
+過於
+關於
+毀於
+基於
+急於
+嫁禍於
+借聽於聾
+見於
+鑒於
+謹於心
+求道於盲
+始於
+於藍
+出於
+輕於
+行百里者半於九十
+幸於
+怠於
+詢於芻蕘
+止於
+至於
+拙於
+忠於
+終於
+重於
+垂於
+善於
+死於
+屬於
+浮於
+在於
+厝薪於火
+易於
+精於
+由於
+於此
+燕巢於幕
+於菟
+於乎
+於戲
+於邑
+補於
+位於
+於今
+於是
+於是乎
+於斯
+寓於
+月離於畢
+月麗於箕
+源於
+且於
+長於
+短於
+現於
+較於
+於之
+分布於
+分散於
+優於
+早於
+晚於
+感於
+鬼谷子
+于美人
+緊緻
+冗餘
+曰云
+若干
+徵婚
+鬥鬨
+事有鬥巧
+歹鬥
+鬥茶
+鬥鴨
+爭奇鬥妍
+誇能鬥智
+春香鬥學
+鬥引
+鬥彩
+鬥武
+鬥悶
+鬥牙拌齒
+鬥幌子
+鬥腳
+雞吵鵝鬥
+辯鬥
+廝鬥
+誇多鬥靡
+臨潼鬥寶
+鬥趣
+撩鬥
+傲霜鬥雪
+賭鬥
+搬鬥
+鬥爭鬥合
+鬥疊
+鬥文
+耍鬥
+鬥巧
+油鬥
+蚊動牛鬥
+卵與石鬥
+挑鬥
+爭奇鬥異
+鬥葉子
+鬥分子
+爭妍鬥奇
+不鬥
+鬥心眼
+鬥頭
+挌鬥
+好鬥
+鬥合
+拚鬥
+兩虎共鬥
+兩鼠鬥穴
+鬥犀臺
+鬥牙鬥齒
+惡鬥
+鬥勝
+鬥富
+鬥艦
+鬥葉兒
+鬥彆氣
+鬥話
+鬥牌
+鬥百草
+鬥打
+鬥犬
+鬥風
+鬥雪紅
+鬥暴
+鬥閑氣
+龍鬥虎傷
+殷師牛鬥
+二虎相鬥
+鬥力
+爭紅鬥紫
+鬥麗
+鬥狠
+鬥飣
+虎鬥
+引鬥
+爭妍鬥豔
+轉鬥千里
+鬥而鑄兵
+困鬥
+好勇鬥狠
+爭奇鬥豔
+使其鬥
+鬥地主
+石樑
+木樑
+藏歷史
+頁面
+方面
+表面
+面條目
+課餘
+節餘
+盈餘
+病餘
+餘地
+餘力
+餘子
+餘事
+扶餘國
+腐餘
+富餘
+之餘
+餘澤
+流風餘俗
+流風餘韻
+淋餘土
+餘一
+餘二
+餘三
+餘四
+餘五
+餘六
+餘七
+餘八
+餘九
+餘十
+零餘
+〇餘
+餘零
+餘〇
+餘1
+餘2
+餘3
+餘4
+餘5
+餘6
+餘7
+餘8
+餘9
+餘0
+餘1
+餘2
+餘3
+餘4
+餘5
+餘6
+餘7
+餘8
+餘9
+餘0
+餘數
+其餘
+尸居餘氣
+賸餘
+餘孽
+殘餘
+業餘
+餘割
+餘款
+餘角
+餘切
+餘霞
+餘下
+餘弦
+餘震
+餘貾
+餘額
+禹餘糧
+餘人
+編余
+病余
+餘俗
+餘倍
+同餘
+大讚
+唄讚
+褒讚
+謬讚
+誄讚
+祝讚
+詩讚
+賞讚
+讚唄
+飛紮
+紮裹
+紮腳
+紮詐
+紮囮
+住紮
+佔畢
+佔頭籌
+佔高枝兒
+隱佔
+憑摺
+沒摺至
+大摺兒
+大週摺
+火摺子
+裝摺
+變徵
+談徵
+納徵
+流徵
+柳詒徵
+固徵
+貴徵
+考徵
+咎徵
+杞宋無徵
+休徵
+徵辟
+徵名責實
+徵發
+徵風召雨
+徵答
+徵啟
+徵選
+徵招
+徵士
+徵庸
+之徵
+瑞徵
+三徵七辟
+額徵
+有徵
+有征服
+有征戰
+有征伐
+有征討
+無徵不信
+文徵明
+徵跡
+徵車
+徵效
+徵怪
+徵聖
+徵咎
+徵吏
+徵令
+本徵
+船鐘
+黃鈺筑
+齊莊
+鴻案相莊
+項莊
+韋莊
+鍋莊
+鄭莊公
+通莊
+蒙莊
+端莊
+票莊
+矜莊
+楚莊問鼎
+楚莊絕纓
+整莊
+打路莊板
+莊騷
+莊語
+莊舄越吟
+莊房
+莊客
+莊農
+平泉莊
+布莊
+香山庄
+寶莊
+坐莊
+周莊王
+發莊
+卞莊
+包莊
+剔莊貨
+劉克莊
+冷莊子
+石家莊
+卞莊子
+新莊市
+當準
+憑準
+沒準
+蜂準
+推情準理
+寇準
+合準
+準保
+準譜
+準分子
+準點
+一個準
+準擬
+準貨幣
+準軍事
+準式
+認準
+三準
+鵝準
+有準
+崑崙
+鎌倉
+請君入甕
+甕安
+痊癒
+治癒
+病癒
+大病初癒
+癒合
+槓桿
+宣洩
+圖鑑
+諮詢
+勳章
+張勳
+趙治勳
+殭屍
+有栖川
+兇惡
+兇狠
+兇猛
+兇橫
+兇悍
+兇險
+兇相
+兇犯
+嫌兇
+兇嫌
+兇疑
+兇刀
+兇槍
+很兇
+兇巴巴
+行兇前
+凝鍊
+鍊貧
+鍊度
+鍊形
+鍊師
+鍊石
+鍊字
+鍊冶
+細鍊
+陳鍊
+闖鍊
+鍊汞
+淬鍊
+鋼之鍊金術師
+索馬里
+范登堡
+世田谷
+製漿
+三統歷史
+伊斯蘭教歷史
+伊斯蘭歷史
+儒略改革歷史
+儒略歷史
+公歷史
+台歷史
+合歷史
+周歷史
+商歷史
+四分歷史
+回歷史
+埃及歷史
+大明歷史
+大歷史
+大衍歷史
+太初歷史
+官歷史
+寶歷史
+巧歷史
+希伯來歷史
+弘歷史
+慶歷史
+日歷史
+星歷史
+月歷史
+朱理安歷史
+桌歷史
+永歷史
+玉歷史
+百花歷史
+皇歷史
+皇極歷史
+穆罕默德歷史
+算歷史
+紀歷史
+舊歷史
+航海歷史
+萬歷史
+行事歷史
+農歷史
+農民歷史
+通歷史
+長歷史
+陰歷史
+陽歷史
+額我略歷史
+黃歷史
+天曆
+天歷史
+美醜
+獻醜
+出醜
+家醜
+遮醜
+醜八怪
+醜名
+醜詆
+醜態
+醜女
+醜類
+醜陋
+醜虜
+醜化
+醜劇
+醜媳婦
+醜小鴨
+醜行
+醜事
+醜聲
+醜人
+醜惡
+醜丫頭
+醜聞
+醜語
+母醜
+一齣子
+齣兒
+賣獃
+發獃
+大獃
+獃獃
+獃等
+獃頭
+獃腦
+獃根
+獃磕
+獃憨獃
+獃話
+獃氣
+獃想
+獃性
+獃滯
+獃著
+獃痴
+獃串了皮
+獃事
+獃人
+獃子
+好獃
+占便宜的是獃
+阿獃
+丰標
+丰姿
+丰韻
+鵰翎
+鵰心雁爪
+鵰鶚
+雙鵰
+撲鼕鼕
+普鼕鼕
+鼕鼕鼓
+令人髮指
+爆發指數
+開發
+剪其髮
+吐哺捉髮
+吐哺握髮
+含齒戴髮
+大金髮苔
+寸髮千金
+心長髮短
+戴髮含齒
+拔髮
+拔鬚
+揪髮
+揪鬚
+整髮用品
+斷髮文身
+滿頭洋髮
+燙一個髮
+燙一次髮
+燙個髮
+燙完髮
+燙次髮
+理一個髮
+理一次髮
+理個髮
+理完髮
+理次髮
+細如髮
+繫於一髮
+膚髮
+皮膚
+生華髮
+蒼髮
+被髮佯狂
+被髮入山
+被髮左衽
+被髮纓冠
+被髮陽狂
+身體髮膚
+髒髮
+髮光可鑑
+髮已霜白
+髮油
+髮為血之本
+髮網
+髮踊沖冠
+髮際
+黃髮
+齒落髮白
+剷頭
+剷刈
+口燥唇乾
+舌乾唇焦
+花菴詞選
+渾箇
+箇中原因
+箇中理由
+箇中高手
+箇中好手
+箇中強手
+箇中滋味
+箇中奧秘
+箇中奧妙
+箇中玄機
+箇中消息
+箇中資訊
+箇中訊息
+對表達
+對表現
+對表演
+對表揚
+對表中
+對表明
+不準確
+並不準確
+一伙頭
+一伙食
+一半只
+一干弟兄
+一干弟子
+一干部下
+一斗斗
+一面食
+萬一只
+上面糊
+不克自制
+不准沒
+不加自制
+不占凶吉
+不占卜
+不占吉凶
+不占算
+不好干涉
+不好干預
+不干預
+不干涉
+不干休
+不干犯
+不干擾
+不干你
+不干我
+不干他
+不干她
+不干它
+不干事
+不斗膽
+不每只
+不采聲
+專向往
+丰容
+之一只
+之二只
+之八九只
+也斗了膽
+事情干脆
+事都干脆
+二只得
+亦云
+人云
+以自制
+們斗了膽
+你斗了膽
+其一只
+其二只
+其八九只
+內面包
+內面包的
+准保護
+准保釋
+几上
+几淨窗明
+几凳
+几子
+几旁
+几椅
+几榻
+几面上
+出征收
+擊扑
+划一槳
+划了一會
+划到岸
+划到江心
+前面店
+千只可
+千只夠
+千只怕
+千只能
+千只足夠
+半只可
+半只夠
+占了卜
+口干冒
+口干政
+口干涉
+口干犯
+口干預
+古書云
+古語云
+只占卜
+只占吉
+只占神問卜
+只占算
+只身上已
+只身上無
+只身上有
+只身上沒
+只身上的
+只身世
+只身為
+只身份
+只身體
+只身前
+只身受
+只身後
+只身子
+只身形
+只身影
+只身心
+只身旁
+只身材
+只身段
+只身邊
+只身首
+只身高
+只采聲
+可自制
+台子女
+台子孫
+台布景
+台面前
+合府上
+後面店
+向往常
+向往日
+向往時
+向往來
+唯一只
+喂了一聲
+喜向往
+四出徵收
+四面包
+多半只
+好斗大
+好斗室
+好斗笠
+好斗篷
+好斗膽
+好斗蓬
+家具體
+家具備
+家具有
+小几
+尸利
+尸祿
+尸臣
+尸鳩
+已占卜
+已占算
+并迭
+所云
+所云云
+所占卜
+所占星
+所占算
+手表決
+手表態
+手表明
+手表演
+手表現
+手表示
+手表達
+手表露
+手表面
+才干休
+才干戈
+才干擾
+才干政
+才干涉
+才干預
+扎好底子
+扎好根
+扑撻
+打吨
+折向往
+拉面上
+拉面具
+拉面前
+拉面巾
+拉面無
+拉面皮
+拉面罩
+拉面色
+拉面部
+捉奸黨
+捉奸徒
+捉奸細
+捉奸賊
+敢情欲
+敢斗了膽
+敲扑
+方向往
+望了望
+桌几
+每每只
+法自制
+洒滌
+洒淅
+洒濯
+洒然
+灘涂
+特制住
+特制定
+特制止
+特制訂
+百只可
+百只夠
+百只怕
+百只足夠
+皮制服
+相克制
+相克服
+短几
+石几
+秒表明
+秒表示
+窗明几亮
+竹几
+精制伏
+精制住
+精制服
+經有云
+給我干脆
+編制法
+能干休
+能干戈
+能干擾
+能干政
+能干涉
+能干預
+能自制
+自制一下
+自制下來
+自制不
+自制之力
+自制之能
+自制他
+自制伏
+自制你
+自制地
+自制她
+自制情
+自制我
+自制服
+自制的能
+自制能力
+船只得
+船只有
+船只能
+草荐
+荐居
+荐臻
+荐饑
+要自制
+語有云
+跌扑
+轉向往
+酒帘
+裡面包
+金表態
+金表情
+金表揚
+金表明
+金表演
+金表現
+金表示
+金表達
+金表露
+金表面
+長几
+隆准許
+雄斗斗
+面包住
+面包辦
+面包廂
+面包含
+面包圍
+面包容
+面包庇
+面包紮
+面包抄
+面包括
+面包攬
+面包涵
+面包管
+面包羅
+面包著
+面包藏
+面包裝
+面包裹
+面包起
+面店舖
+面粉碎
+面粉紅
+面食麵
+面食飯
+顛顛仆仆
+高干擾
+高干預
+高度自制
+黃金表
+天后宮
+一吊錢
+不食乾腊
+傳位于四太子
+儉确之教
+党懷英
+八蜡
+憑几
+南宮适
+大蜡
+子云
+分子雲
+小价
+歲聿云暮
+崖广
+恕乏价催
+悲筑
+折子戲
+揮杆
+搤肮拊背
+文采郁郁
+木杆
+洪适
+球杆
+腊之以為餌
+腊毒
+蜡月
+蜡祭
+言云
+宜云
+貴价
+郁郁菲菲
+馬杆
+造麯
+麴生
+麴秀才
+麴塵
+麴櫱
+大麴
+黃麴毒素
+酒醴麴櫱
+麴道士
+麴錢
+麴車
+麴院
+鼠麴草
+不乾不淨
+生發生
+必須
+須根據
+·范
+、剋制
+,剋制
+。剋制
+!剋制
+?剋制
+;剋制
+:剋制
+不剋制
+也剋制
+了剋制
+他剋制
+們剋制
+剋制不了
+剋制不住
+力剋制
+力求剋制
+可以剋制
+和剋制
+在剋制
+地剋制
+夠剋制
+她剋制
+你剋制
+您剋制
+就剋制
+彼此剋制
+得剋制
+快剋制
+想剋制
+意剋制
+應剋制
+我剋制
+才剋制
+於剋制
+易剋制
+無法剋制
+的剋制
+盡量剋制
+而剋制
+能剋制
+與剋制
+著剋制
+要剋制
+軍隊剋制
+空投佈雷
+火箭佈雷
+海灣佈雷
+空中佈雷
+海上佈雷
+佈雷的
+佈雷,
+佈雷、
+佈雷。
+佈雷;
+佈雷艦
+佈雷艇
+佈雷速度
+佈雷封鎖
+滿拚自盡
+拚生盡死
+拚卻
+拚老命
+拚絕
+成於思
+單單於
+積澱
+澱積
+澱北片
+澱解物
+澱謂之滓
+淺澱
+堙澱
+茂都澱
+並曰入澱
+澱乃不耕之地
+藍澱
+皆可作澱
+澱山
+海淀山後
+澱澱
+掛鈎
+薴悴
+絡腮鬍
+落腮鬍
+山羊鬍
+幸運鬍
+刮鬍
+剃鬍
+吹鬍
+蓄鬍
+白鬍
+長鬍
+鬍髯
+髯鬍
+髭鬍
+鬚鬍
+范文瀾
+范文同
+范文正公
+范文程
+范文芳
+范文藤
+范文虎
+范文照
+發表
+乾重
+若干
+鈎心鬥角
+若干
+乾重
+全面包圍
+全面包裹
+機械系
+體系
+心理
+複分解
+鹰鵰
+叱咤903
+叱咤MY903
+叱咤My903
+叱咤樂壇
+叱咤咤
+叱咤叱咤叱咤咤
+叱咤叱叱咤
+正在叱咤
+空餘
+變髒
+天地志狼
+薴烯
+阿斯圖里亞斯
+雙折射
+心繫家
+心繫國
+心繫祖
+心繫北
+心繫京
+心繫南
+心繫西
+心繫東
+心繫四
+心繫川
+心繫浙
+心繫汶
+心繫廣
+心繫湖
+心繫山
+心繫台
+心繫江
+心繫昌
+心繫香
+心繫澳
+心繫港
+心繫泰
+心繫健
+心繫天
+心繫地
+心繫大
+心繫小
+心繫全
+心繫眾
+心繫奧
+心繫世
+心繫中
+心繫高
+心繫災
+心繫非
+心繫群
+心繫新
+心繫沈
+心繫唐
+心繫黃
+心繫乔
+心繫阮
+心繫父
+心繫母
+心繫病
+心繫故
+心繫哪
+心繫中
+心繫英
+心繫美
+心繫日
+心繫德
+心繫功
+心繫曉
+心繫神
+心繫萬
+心繫的
+心繫在
+心繫兩
+心繫社
+心繫曼
+心繫彼
+心繫風
+心繫募
+心繫一
+心繫何
+心繫困
+心繫輸
+心繫人
+心繫民
+心繫十
+心繫百
+心繫千
+心繫和
+心繫選
+心繫囑
+心繫我
+心繫你
+心繫您
+心繫他
+心繫她
+心繫它
+心繫伊
+心繫長
+心繫舞
+心繫蘭
+心繫五
+心繫生
+心繫婦
+心繫幼
+心繫茶
+心繫動
+心繫沙
+心繫林
+心繫摩
+心繫农
+心繫慈
+心繫麥
+心繫貧
+心繫富
+心繫遠
+心繫近
+心繫宣
+心繫傳
+心繫紅
+心繫老
+心繫重
+心繫震
+心繫妻
+心繫夫
+心繫女
+心繫子
+心繫著
+重回
+挑大樑
+扛大樑
+后豐
+製得
+限制
+控制
+製取
+第四出局
+心臟
+肝臟
+脾臟
+肺臟
+腎臟
+參與
+浮誇
+星巴克
+于謙
+于寘
+淳于
+于禁
+于敏中
+註:# 不作“注:”
+呆呆獸
+劃為# 不作“划為”
+併為一體
+併為一家
+一個# 避免“個裡”的錯誤
+兩個
+二個
+三個
+四個
+五個
+六個
+七個
+八個
+九個
+十個
+百個
+千個
+萬個
+億個
+兆個
+零個
+云:# 不作“雲:”
+電子表格
+雪裡紅
+雪裡蕻
+森林裡
+日子裡
+故事裡
+領域裡
+時間裡
+深淵裡
+醫院裡
+春假裡
+暑假裡
+秋假裡
+寒假裡
+春天裡
+夏天裡
+秋天裡
+冬天裡
+春日裡
+夏日裡
+秋日裡
+冬日裡
+嘴裡
+心裡
+皮裡陽秋
+肚裡
+苦裡
+裡勾外連
+裡面
+這裡
+中文裡
+山洞裡
+世界裡
+眼睛裡
+首發
+夸脫
+誰幹的
+鐘螺
+風采
+代碼表
+編碼表
+字碼表
+電碼表
+科斗
+佔領
+灕水
+點裡
+這只是
+這只不
+這只容
+這只允
+這只採
+這只用
+有只是
+有只不
+有只容
+有只允
+有只採
+有只用
+葉叶琹
+胡子昂
+包括
+特别致
+分别致
+會上簽訂
+會上簽署
+周一 # (及以下)避免“周一齣版”的錯誤
+周二
+周三
+周四
+周五
+周六
+韶山沖
+總裁制
+于丹
+于樂
+于冕
+于軍
+于吉
+于堅
+于姓
+于氏
+于娜
+于娟
+于山
+于帥
+于慧
+于振
+于敏
+于斌
+于晴
+于波
+于濤
+于衡
+于贈
+于越
+于靖
+于勒
+于格
+于仁泰
+于會泳
+于偉國
+于佳卉
+于光遠
+于克勒
+于凌奎
+于鳳至
+于化虎
+于占元
+于台煙
+于品海
+于國楨
+于大寶
+于天仁
+于子千
+于孔兼
+于學忠
+于家堡
+于小偉
+于小彤
+于山國
+于幼軍
+于廣洲
+于康震
+于式枚
+于從濂
+于德海
+于志寧
+于慎行
+于成龍
+于振武
+于明濤
+于是之
+于晨楠
+于根偉
+于樹潔
+于欣源
+于正昇
+于正昌
+于永波
+于漢超
+于江震
+于洪區
+于浩威
+于海洋
+于湘蘭
+于特森
+于玉立
+于秀敏
+于素秋
+于若木
+于蔭霖
+于西翰
+于遠偉
+于道泉
+于都縣
+于震寰
+于震環
+于非闇
+于風政
+于鳳桐
+于默奧
+于家堡
+于爾岑
+于默奧
+于貝爾
+于爾根
+于雙戈
+于里察
+于澤爾
+于斯塔德
+于斯達爾
+于爾里克
+于奇庫杜克
+于韋斯屈萊
+于克-蘭多縣
+于斯納爾斯貝里
+夏于喬
+涂姓
+涂坤
+涂天相
+涂序瑄
+涂澤民
+涂紹煃
+涂羽卿
+涂逢年
+涂長望
+涂謹申
+涂鴻欽
+涂壯勳
+涂醒哲
+涂善妮
+涂敏恆
+總裁制
+故云
+強制作用
+鬱南
+西米谷
+一出生
+二出生
+三出生
+四出生
+五出生
+六出生
+七出生
+八出生
+九出生
+十出生
+一出版
+二出版
+三出版
+四出版
+五出版
+六出版
+七出版
+八出版
+九出版
+十出版
+一出刊
+二出刊
+三出刊
+四出刊
+五出刊
+六出刊
+七出刊
+八出刊
+九出刊
+十出刊
+一出逃
+二出逃
+三出逃
+四出逃
+五出逃
+六出逃
+七出逃
+八出逃
+九出逃
+十出逃
+一出口
+二出口
+三出口
+四出口
+五出口
+六出口
+七出口
+八出口
+九出口
+十出口
+一出祁山
+二出祁山
+三出祁山
+四出祁山
+五出祁山
+六出祁山
+七出祁山
+八出祁山
+九出祁山
+十出祁山
+鬱林
+饑荒
+免徵
+亞美尼亞曆
+百科裡
+歷史裡
+戲裡
+作品裡
+專輯裡
+年代裡
+棺材裡
+注釋
+月面
+路面
+修杰楷
+修杰麟
+學裡
+獄裡
+館裡
+系列裡
+村子裡
+艷后
+廢后
+妖后
+后海灣
+仙后
+賈后
+賢后
+蜂后
+皇后
+王后
+王侯后
+母后
+武后
+歌后
+影后
+封后
+太后
+天后
+呂后
+后里
+后街
+后羿
+后稷
+后座
+后平路
+后安路
+后土
+后北街
+后冠
+望后石
+后角
+蟻后
+后妃
+大周后
+小周后
+染殿后
+准三后
+風后
+后母戊
+風後,
+人如風後入江雲
+中風後
+屏風後
+颱風後
+颳風後
+整風後
+打風後
+遇風後
+聞風後
+逆風後
+順風後
+大風後
+馬格里布
+伊里布
+劃入
+中庄子
+埔裏社撫墾局
+懸掛
+僱傭
+四捨六入
+宿舍
+會干擾
+代表
+高清愿
+瓷製
+竹製
+絲製
+莜麵
+劃入
+簡筑翎
+楊雅筑
+魔杰座
+杰威爾音樂
+彭于晏
+尸羅精舍
+索馬里 # (及以下)避免里海=>裏海的轉換
+西西里
+騰格里
+阿里
+村里長
+進制
+黃詩杰
+陳冲
+何杰
+劉佳怜
+于小惠
+于品海
+于耘婕
+于洋
+于澄
+于光新
+范賢惠
+于國治
+于楓
+于熙珍
+涂善妮
+邱于庭
+熊杰
+卜云吉
+黎吉雲
+于飛島
+代表
+水無怜奈
+傲遊 # 浏览器名
+夏于喬
+賭后
+后海灣
+立后綜
+甲后路
+劉芸后
+謝華后
+趙惠后
+趙威后
+聖后
+陳有后
+許虬
+網遊
+狄志杰
+伊適杰
+于冠華
+于台煙
+于雲鶴
+于忠肅集
+于友澤
+于和偉
+于來山
+于樂
+于天龍
+于謹
+于榮光
+電波鐘
+余三勝
+掛名
+啟發式
+舞后
+甄后
+郭后
+0年 # 協助分詞
+1年
+2年
+3年
+4年
+5年
+6年
+7年
+8年
+9年
+0年
+1年
+2年
+3年
+4年
+5年
+6年
+7年
+8年
+9年
+〇年
+零年
+一年
+兩年
+二年
+三年
+四年
+五年
+六年
+七年
+八年
+九年
+十年
+百年
+千年
+萬年
+億年
+周后
+0周後
+1周後
+2周後
+3周後
+4周後
+5周後
+6周後
+7周後
+8周後
+9周後
+0周後
+1周後
+2周後
+3周後
+4周後
+5周後
+6周後
+7周後
+8周後
+9周後
+零周後
+〇周後
+一周後
+二周後
+兩周後
+三周後
+四周後
+五周後
+六周後
+七周後
+八周後
+九周後
+十周後
+百周後
+千周後
+萬周後
+億周後
+幾周後
+多周後
+前往
+后瑞站
+帝后臺
+新井里美
+樗里子
+伊達里子
+濱田里佳子
+尊后
+叶志穗
+叶不二子
+于立成
+山谷道
+李志喜
+于欣
+于少保
+于海
+於海邊
+於海上
+于凌辰
+于魁智
+于鬯
+于仲文
+于再清
+于震
+於震前
+於震后
+於震中
+固定制
+毗婆尸佛
+尸棄佛
+划船
+划不來
+划拳
+划槳
+划動
+划艇
+划行
+划算
+總裁制
+恒生
+嚴云農
+手裏劍
+秦莊襄王
+伊東怜
+衛後莊公
+餘量
+並行
+郁郁青青
+協防
+對表格
+對表示
+對表達
+對表演
+對表明
+了然後
+戴表元
+張樂于張徐
+余力為
+葉叶琴
+万俟
+幾個
+澀谷區
+協調
+選手
+併發症
+併發重症
+併發模式
+併發型模式
+金色長髮
+紅色長髮
+一頭長髮
+的長髮
+黑色長髮
+前天
+昨天
+今天
+明天
+後天
+數學家
+科學家
+物理學家
+化學家
+生物學家
+天文學家
+游離
+子晳
+紅后假說
+書面
+不只
+高涌泉
+請求
+考試
+測試
+筆試
+口試
+冰冷
+王田里
+后姓
+台州
+田庄英雄
+計劃
+抑制劑
diff --git a/maintenance/language/zhtable/tradphrases_exclude.manual b/maintenance/language/zhtable/tradphrases_exclude.manual
new file mode 100644
index 00000000..e6abb4e1
--- /dev/null
+++ b/maintenance/language/zhtable/tradphrases_exclude.manual
@@ -0,0 +1,330 @@
+三國誌
+聊齋誌異
+北迴
+南迴
+併排
+併進
+併在
+併成
+衝衝
+臺
+著
+佈
+纔
+采
+着
+借
+甦
+荐
+担
+可憐虫
+一齣
+上弔
+弔車
+弔橋
+弔嗓子
+弔床
+弔架
+弔桶
+弔桿
+弔橋
+弔燈
+弔環
+弔籃
+弔胃口
+弔臂
+弔銷
+形影相弔
+被髮
+散髮
+長髮
+髮毛
+髮端
+周而複始
+答複
+複興
+複舊
+顛複
+修複
+報複
+複活
+反複
+迴首
+彙總
+饑餓
+饑不擇食
+饑荒
+憑藉
+藉故
+藉口
+藉端
+藉詞
+藉酒
+蛋捲
+行李捲
+克裡
+纍纍
+華裡
+裡海
+瞭解
+明瞭
+發黴
+矇蔽
+矇住
+濛濛
+矇矇
+下麵
+白麵
+切麵
+和麵
+過水麵
+復甦
+複蘇
+甦醒
+体
+繫數
+遊擊
+馥鬱
+鬱鬱
+改製
+獃住
+獃氣
+獃子
+獃頭獃腦
+儘量
+希腊
+腊肉
+瞭如
+昇
+武鬆
+赤鬆
+黑鬆
+鬆林
+鬆科
+鬆濤
+鬆毛蟲
+鬆節油
+濕地鬆
+尼克鬆
+紮伊爾
+阿布紮比
+阿紮尼亞
+利比裡亞
+斯裡蘭卡
+烏蘇裡江
+加裡寧
+歐幾裡得
+格裡
+巴裡
+居裡
+卡裡
+墨索裡尼
+底裡
+裡人
+裡加
+裡裡
+馬裡
+裡拉
+阿裡
+裡斯
+鄰裡
+鄉裡
+百裡
+特裡
+海裡
+三元裡
+漏鬥
+春捲
+採邑
+嚮日
+佔城
+水錶
+名錶
+錶面
+彆腳
+併力
+併列
+併為
+豐富多採
+採採
+尼採
+小醜
+辛醜
+整齣
+嚴複
+枯幹
+干著急
+單於
+攻剋
+剋服
+闢邪
+釐米
+後樑
+石樑
+木樑
+舊莊
+介係詞
+介繫詞
+餘年
+大阪
+阪田
+豪杰
+七拚八湊
+一捲
+十捲
+上捲
+下捲
+加捲
+不捨
+不識檯舉
+稜登
+半弔子
+分布圖
+星鬥
+筋鬥
+斗鬨
+料鬥
+煙鬥
+熨鬥
+笆鬥
+箕鬥
+金鬥
+門鬥
+風鬥
+鬥子
+鬥笠
+老板娘
+剋制
+洋麵
+病癥
+製裁
+台製
+石家庄
+酒盃
+積极
+殭尸
+上梁不正
+項鍊
+鍊子
+鍊條
+拉鍊
+鉸鍊
+鍊鎖
+鐵鍊
+鍛鍊
+鍊乳
+鍊丹
+至于
+浮于
+附于
+次于
+于人
+助于
+行于
+于衷
+于事
+低于
+大于
+高于
+等于
+位于
+用于
+答覆
+複蓋
+反覆
+藉藉
+蘊藉
+蹈藉
+醞藉
+氆氌
+慰藉
+文藉
+枕藉
+狼藉
+別隻
+鼕鼕
+矇松雨
+佈雷
+丰度
+剪彩
+脣
+菴
+公裡
+箇中
+樑子
+樑書
+讚成
+讚同
+鐘表店
+精採
+鞭尸
+尸身
+尸首
+行尸走肉
+裹尸
+慼慼
+痠
+簑
+捱
+朝乾夕惕
+大曲酒
+神麴
+便于
+偏于
+勇于
+居于
+常見于
+強加于
+從事于
+忙于
+敢于
+服務于
+服從于
+樂于
+歸罪于
+歸諸于
+活動于
+瀕于
+苦于
+莫過于
+處于
+適于
+乾和
+鉤
+高陞
+大胆
+託福
+繫系
+酰
+醯
+大樑
+光採
+鍾錶
+複原
+參与
+浮夸
+剋日
+羡
+旅游
+穀風
+復讎
+避暑山庄
+遊牧
+烟草
+征
+占領
+入夥
+懸挂
+註釋
+浮遊
+冶鍊
+裡子
+裡外
+單隻
+聯係
+那裏
+殺虫藥
+好家伙
+姦污
+併發
+衚衕
diff --git a/maintenance/locking/LockServerDaemon.php b/maintenance/locking/LockServerDaemon.php
index 689c9309..01fbac72 100644
--- a/maintenance/locking/LockServerDaemon.php
+++ b/maintenance/locking/LockServerDaemon.php
@@ -23,7 +23,7 @@
* @ingroup LockManager Maintenance
*/
-if ( php_sapi_name() !== 'cli' ) {
+if ( PHP_SAPI !== 'cli' ) {
die( "This is not a valid entry point.\n" );
}
error_reporting( E_ALL );
@@ -39,6 +39,8 @@ LockServerDaemon::init(
/**
* Simple lock server daemon that accepts lock/unlock requests
+ *
+ * @ingroup LockManager Maintenance
*/
class LockServerDaemon {
/** @var resource */
@@ -66,6 +68,8 @@ class LockServerDaemon {
/**
* @params $config Array
+ * @param array $config
+ * @throws Exception
* @return LockServerDaemon
*/
public static function init( array $config ) {
@@ -75,9 +79,9 @@ class LockServerDaemon {
foreach ( array( 'address', 'port', 'authKey' ) as $par ) {
if ( !isset( $config[$par] ) ) {
die( "Usage: php LockServerDaemon.php " .
- "--address <address> --port <port> --authkey <key> " .
+ "--address <address> --port <port> --authKey <key> " .
"[--lockTimeout <seconds>] " .
- "[--maxLocks <integer>] [--maxClients <integer>] [--maxBacklog <integer>]"
+ "[--maxLocks <integer>] [--maxClients <integer>] [--maxBacklog <integer>]\n"
);
}
}
@@ -111,6 +115,7 @@ class LockServerDaemon {
}
/**
+ * @throws Exception
* @return void
*/
protected function setupServerSocket() {
@@ -237,7 +242,9 @@ class LockServerDaemon {
$m = explode( ':', $data ); // <session, key, command, type, values>
if ( count( $m ) == 5 ) {
list( $session, $key, $command, $type, $values ) = $m;
- if ( sha1( $session . $command . $type . $values . $this->authKey ) !== $key ) {
+ $goodKey = hash_hmac( 'sha1',
+ "{$session}\n{$command}\n{$type}\n{$values}", $this->authKey );
+ if ( $goodKey !== $key ) {
return 'BAD_KEY';
} elseif ( strlen( $session ) !== 32 ) {
return 'BAD_SESSION';
diff --git a/maintenance/mcc.php b/maintenance/mcc.php
index e07e62db..6ff8a176 100644
--- a/maintenance/mcc.php
+++ b/maintenance/mcc.php
@@ -25,11 +25,62 @@
/** */
require_once( __DIR__ . '/commandLine.inc' );
-$mcc = new MWMemcached( array( 'persistent' => true/*, 'debug' => true*/ ) );
-$mcc->set_servers( $wgMemCachedServers );
-# $mcc->set_debug( true );
+$options = getopt( '', array( 'debug', 'help', 'cache:' ) );
-function mccShowHelp( $command ) {
+$debug = isset( $options['debug'] );
+$help = isset( $options['help'] );
+$cache = isset( $options['cache'] ) ? $options['cache'] : null;
+
+if ( $help ) {
+ mccShowUsage();
+ exit( 0 );
+}
+$mcc = new MWMemcached( array(
+ 'persistent' => true,
+ 'debug' => $debug,
+) );
+
+if ( $cache ) {
+ if ( !isset( $wgObjectCaches[$cache] ) ) {
+ print "MediaWiki isn't configured with a cache named '$cache'";
+ exit( 1 );
+ }
+ $servers = $wgObjectCaches[$cache]['servers'];
+} elseif ( $wgMainCacheType === CACHE_MEMCACHED ) {
+ $mcc->set_servers( $wgMemCachedServers );
+} elseif( isset( $wgObjectCaches[$wgMainCacheType]['servers'] ) ) {
+ $mcc->set_servers( $wgObjectCaches[$wgMainCacheType]['servers'] );
+} else {
+ print "MediaWiki isn't configured for Memcached usage\n";
+ exit( 1 );
+}
+
+/**
+ * Show this command line tool usage.
+ */
+function mccShowUsage() {
+ echo <<<EOF
+Usage:
+ mcc.php [--debug]
+ mcc.php --help
+
+MemCached Command (mcc) is an interactive command tool that let you interact
+with the MediaWiki memcached cache.
+
+Options:
+ --debug Set debug mode on the memcached connection.
+ --help This help screen.
+
+Interactive commands:
+
+EOF;
+ print "\t";
+ print str_replace( "\n", "\n\t", mccGetHelp( false ) );
+ print "\n";
+}
+
+function mccGetHelp( $command ) {
+ $output = '';
$commandList = array(
'get' => 'grabs something',
'getsock' => 'lists sockets',
@@ -48,13 +99,15 @@ function mccShowHelp( $command ) {
if ( $command === 'fullhelp' ) {
$max_cmd_len = max( array_map( 'strlen', array_keys( $commandList ) ) );
foreach ( $commandList as $cmd => $desc ) {
- printf( "%-{$max_cmd_len}s: %s\n", $cmd, $desc );
+ $output .= sprintf( "%-{$max_cmd_len}s: %s\n", $cmd, $desc );
}
} elseif ( isset( $commandList[$command] ) ) {
- print "$command: $commandList[$command]\n";
+ $output .= "$command: $commandList[$command]\n";
} else {
- print "$command: command does not exist or no help for it\n";
+ $output .= "$command: command does not exist or no help for it\n";
}
+
+ return $output;
}
do {
@@ -72,8 +125,8 @@ do {
switch ( $command ) {
case 'help':
// show an help message
- mccShowHelp( array_shift( $args ) );
- break;
+ print mccGetHelp( array_shift( $args ) );
+ break;
case 'get':
$sub = '';
@@ -93,7 +146,7 @@ do {
} else {
var_dump( $res );
}
- break;
+ break;
case 'getsock':
$res = $mcc->get( $args[0] );
diff --git a/maintenance/mctest.php b/maintenance/mctest.php
index 691b832b..469feca2 100644
--- a/maintenance/mctest.php
+++ b/maintenance/mctest.php
@@ -36,18 +36,32 @@ class mcTest extends Maintenance {
$this->mDescription = "Makes several 'set', 'incr' and 'get' requests on every"
. " memcached server and shows a report";
$this->addOption( 'i', 'Number of iterations', false, true );
+ $this->addOption( 'cache', 'Use servers from this $wgObjectCaches store', false, true );
$this->addArg( 'server[:port]', 'Memcached server to test, with optional port', false );
}
public function execute() {
- global $wgMemCachedServers, $wgMemCachedTimeout;
+ global $wgMainCacheType, $wgMemCachedTimeout, $wgObjectCaches;
+ $cache = $this->getOption( 'cache' );
$iterations = $this->getOption( 'i', 100 );
- if ( $this->hasArg() ) {
- $wgMemCachedServers = array( $this->getArg() );
+ if ( $cache ) {
+ if ( !isset( $wgObjectCaches[$cache] ) ) {
+ $this->error( "MediaWiki isn't configured with a cache named '$cache'", 1 );
+ }
+ $servers = $wgObjectCaches[$cache]['servers'];
+ } elseif ( $this->hasArg() ) {
+ $servers = array( $this->getArg() );
+ } elseif ( $wgMainCacheType === CACHE_MEMCACHED ) {
+ global $wgMemCachedServers;
+ $servers = $wgMemCachedServers ;
+ } elseif ( isset( $wgObjectCaches[$wgMainCacheType]['servers'] ) ) {
+ $servers = $wgObjectCaches[$wgMainCacheType]['servers'];
+ } else {
+ $this->error( "MediaWiki isn't configured for Memcached usage", 1 );
}
- foreach ( $wgMemCachedServers as $server ) {
+ foreach ( $servers as $server ) {
$this->output( $server . " ", $server );
$mcc = new MemCachedClientforWiki( array(
'persistant' => true,
diff --git a/maintenance/mergeMessageFileList.php b/maintenance/mergeMessageFileList.php
index cea64333..62596b20 100644
--- a/maintenance/mergeMessageFileList.php
+++ b/maintenance/mergeMessageFileList.php
@@ -82,6 +82,9 @@ class MergeMessageFileList extends Maintenance {
if ( $this->hasOption( 'output' ) ) {
$mmfl['output'] = $this->getOption( 'output' );
}
+ if ( $this->hasOption( 'quiet' ) ) {
+ $mmfl['quiet'] = true;
+ }
}
}
@@ -92,7 +95,9 @@ foreach ( $mmfl['setupFiles'] as $fileName ) {
continue;
}
$fileName = str_replace( '$IP', $IP, $fileName );
- fwrite( STDERR, "Loading data from $fileName\n" );
+ if ( empty( $mmfl['quiet'] ) ) {
+ fwrite( STDERR, "Loading data from $fileName\n" );
+ }
include_once( $fileName );
}
fwrite( STDERR, "\n" );
@@ -120,4 +125,3 @@ if ( isset( $mmfl['output'] ) ) {
} else {
echo $s;
}
-
diff --git a/maintenance/migrateUserGroup.php b/maintenance/migrateUserGroup.php
index 496af723..f3e5957c 100644
--- a/maintenance/migrateUserGroup.php
+++ b/maintenance/migrateUserGroup.php
@@ -55,7 +55,9 @@ class MigrateUserGroup extends Maintenance {
$blockEnd = $start + $this->mBatchSize - 1;
// Migrate users over in batches...
while ( $blockEnd <= $end ) {
+ $affected = 0;
$this->output( "Doing users $blockStart to $blockEnd\n" );
+
$dbw->begin( __METHOD__ );
$dbw->update( 'user_groups',
array( 'ug_group' => $newGroup ),
@@ -64,19 +66,42 @@ class MigrateUserGroup extends Maintenance {
__METHOD__,
array( 'IGNORE' )
);
- $count += $dbw->affectedRows();
+ $affected += $dbw->affectedRows();
+ // Delete rows that the UPDATE operation above had to ignore.
+ // This happens when a user is in both the old and new group.
+ // Updating the row for the old group membership failed since
+ // user/group is UNIQUE.
$dbw->delete( 'user_groups',
array( 'ug_group' => $oldGroup,
"ug_user BETWEEN $blockStart AND $blockEnd" ),
__METHOD__
);
- $count += $dbw->affectedRows();
+ $affected += $dbw->affectedRows();
$dbw->commit( __METHOD__ );
+
+ // Clear cache for the affected users (bug 40340)
+ if ( $affected > 0 ) {
+ // XXX: This also invalidates cache of unaffected users that
+ // were in the new group and not in the group.
+ $res = $dbw->select( 'user_groups', 'ug_user',
+ array( 'ug_group' => $newGroup,
+ "ug_user BETWEEN $blockStart AND $blockEnd" ),
+ __METHOD__
+ );
+ if ( $res !== false ) {
+ foreach ( $res as $row ) {
+ $user = User::newFromId( $row->ug_user );
+ $user->invalidateCache();
+ }
+ }
+ }
+
+ $count += $affected;
$blockStart += $this->mBatchSize;
$blockEnd += $this->mBatchSize;
wfWaitForSlaves();
}
- $this->output( "Done! $count user(s) in group '$oldGroup' are now in '$newGroup' instead.\n" );
+ $this->output( "Done! $count users in group '$oldGroup' are now in '$newGroup' instead.\n" );
}
}
diff --git a/maintenance/minify.php b/maintenance/minify.php
index 9f5a909d..0846a64c 100644
--- a/maintenance/minify.php
+++ b/maintenance/minify.php
@@ -29,7 +29,7 @@ require_once( __DIR__ . '/Maintenance.php' );
* @ingroup Maintenance
*/
class MinifyScript extends Maintenance {
- var $outDir;
+ public $outDir;
public function __construct() {
parent::__construct();
diff --git a/maintenance/mssql/tables.sql b/maintenance/mssql/tables.sql
index a0c3d17b..ad996175 100644
--- a/maintenance/mssql/tables.sql
+++ b/maintenance/mssql/tables.sql
@@ -76,10 +76,10 @@ CREATE TABLE /*$wgDBprefix*/user_newtalk (
CREATE INDEX /*$wgDBprefix*/user_group_id ON /*$wgDBprefix*/user_newtalk([user_id]);
CREATE INDEX /*$wgDBprefix*/user_ip ON /*$wgDBprefix*/user_newtalk(user_ip);
---
+--
-- User preferences and other fun stuff
-- replaces old user.user_options BLOB
---
+--
CREATE TABLE /*$wgDBprefix*/user_properties (
up_user INT NOT NULL,
up_property NVARCHAR(32) NOT NULL,
@@ -157,7 +157,7 @@ CREATE TABLE /*$wgDBprefix*/text (
-- The fields generally correspond to the page, revision, and text
-- fields, with several caveats.
-- Cannot reasonably create views on this table, due to the presence of TEXT
--- columns.
+-- columns.
CREATE TABLE /*$wgDBprefix*/archive (
ar_namespace SMALLINT NOT NULL DEFAULT 0,
ar_title NVARCHAR(255) NOT NULL DEFAULT '',
@@ -234,7 +234,7 @@ CREATE INDEX /*$wgDBprefix*/cl_sortkey ON /*$wgDBprefix*/categorylinks(cl_to,c
CREATE INDEX /*$wgDBprefix*/cl_timestamp ON /*$wgDBprefix*/categorylinks(cl_to,cl_timestamp);
--;
---
+--
-- Track all existing categories. Something is a category if 1) it has an en-
-- try somewhere in categorylinks, or 2) it once did. Categories might not
-- have corresponding pages, so they need to be tracked separately.
@@ -279,16 +279,16 @@ CREATE TABLE /*$wgDBprefix*/valid_tag (
vt_tag varchar(255) NOT NULL PRIMARY KEY
);
---
+--
-- Table for storing localisation data
---
+--
CREATE TABLE /*$wgDBprefix*/l10n_cache (
-- language code
lc_lang NVARCHAR(32) NOT NULL,
-
+
-- cache key
lc_key NVARCHAR(255) NOT NULL,
-
+
-- Value
lc_value TEXT NOT NULL DEFAULT '',
);
@@ -305,9 +305,9 @@ CREATE TABLE /*$wgDBprefix*/externallinks (
-- Maximum key length ON SQL Server is 900 bytes
CREATE INDEX /*$wgDBprefix*/externallinks_index ON /*$wgDBprefix*/externallinks(el_index);
---
+--
-- Track external user accounts, if ExternalAuth is used
---
+--
CREATE TABLE /*$wgDBprefix*/external_user (
-- Foreign key to user_id
eu_local_id INT NOT NULL PRIMARY KEY,
@@ -327,16 +327,16 @@ CREATE TABLE /*$wgDBprefix*/langlinks (
);
CREATE UNIQUE INDEX /*$wgDBprefix*/langlinks_reverse_key ON /*$wgDBprefix*/langlinks(ll_lang,ll_title);
---
+--
-- Track inline interwiki links
---
+--
CREATE TABLE /*$wgDBprefix*/iwlinks (
-- page_id of the referring page
iwl_from INT NOT NULL DEFAULT 0,
-
+
-- Interwiki prefix code of the target
iwl_prefix NVARCHAR(20) NOT NULL DEFAULT '',
-
+
-- Title of the target, including namespace
iwl_title NVARCHAR(255) NOT NULL DEFAULT '',
);
@@ -728,7 +728,7 @@ CREATE TABLE /*$wgDBprefix*/updatelog (
PRIMARY KEY (ul_key)
);
--- NOTE To enable full text indexing on SQL 2008 you need to create an account FDH$MSSQLSERVER
+-- NOTE To enable full text indexing on SQL 2008 you need to create an account FDH$MSSQLSERVER
-- AND assign a password for the FDHOST process to run under
-- Once you have assigned a password to that account, you need to run the following stored procedure
-- replacing XXXXX with the password you used.
diff --git a/maintenance/mwdocgen.php b/maintenance/mwdocgen.php
index 37e626ba..4fad7a7f 100644
--- a/maintenance/mwdocgen.php
+++ b/maintenance/mwdocgen.php
@@ -43,7 +43,7 @@
# Variables / Configuration
#
-if ( php_sapi_name() != 'cli' ) {
+if ( PHP_SAPI != 'cli' ) {
echo 'Run "' . __FILE__ . '" from the command line.';
die( -1 );
}
@@ -116,8 +116,7 @@ function readaline( $prompt = '' ) {
* @param $doxyGenerateMan Boolean
* @return string
*/
-function generateConfigFile( $doxygenTemplate, $outputDirectory, $stripFromPath, $currentVersion, $input, $exclude, $excludePatterns, $doxyGenerateMan ) {
- global $doxygenInputFilter;
+function generateConfigFile( $doxygenTemplate, $outputDirectory, $stripFromPath, $currentVersion, $input, $exclude, $excludePatterns, $doxyGenerateMan, $doxygenInputFilter ) {
$template = file_get_contents( $doxygenTemplate );
// Replace template placeholders by correct values.
@@ -134,7 +133,7 @@ function generateConfigFile( $doxygenTemplate, $outputDirectory, $stripFromPath,
);
$tmpCfg = str_replace( array_keys( $replacements ), array_values( $replacements ), $template );
$tmpFileName = tempnam( wfTempDir(), 'mwdocgen-' );
- file_put_contents( $tmpFileName , $tmpCfg ) or die( "Could not write doxygen configuration to file $tmpFileName\n" );
+ file_put_contents( $tmpFileName, $tmpCfg ) or die( "Could not write doxygen configuration to file $tmpFileName\n" );
return $tmpFileName;
}
@@ -248,7 +247,7 @@ case 6:
$excludedPaths = $mwPath . join( " $mwPath", $mwExcludePaths );
print "EXCLUDE: $excludedPaths\n\n";
-$generatedConf = generateConfigFile( $doxygenTemplate, $doxyOutput, $mwPath, $doxyVersion, $input, $excludedPaths, $excludePatterns, $doxyGenerateMan );
+$generatedConf = generateConfigFile( $doxygenTemplate, $doxyOutput, $mwPath, $doxyVersion, $input, $excludedPaths, $excludePatterns, $doxyGenerateMan, $doxygenInputFilter );
$command = $doxygenBin . ' ' . $generatedConf;
echo <<<TEXT
@@ -261,7 +260,8 @@ $command
TEXT;
-passthru( $command );
+$exitcode = 1;
+passthru( $command, $exitcode );
echo <<<TEXT
---------------------------------------------------
@@ -271,3 +271,5 @@ Check above for possible errors.
You might want to delete the temporary file $generatedConf
TEXT;
+
+exit( $exitcode );
diff --git a/maintenance/mwjsduck-gen b/maintenance/mwjsduck-gen
new file mode 100644
index 00000000..fbd428f1
--- /dev/null
+++ b/maintenance/mwjsduck-gen
@@ -0,0 +1,2 @@
+#!/usr/bin/env sh
+jsduck --config=$(cd $(dirname $0)/..; pwd)/maintenance/jsduck/config.json && echo 'JSDuck execution finished.'
diff --git a/maintenance/namespaceDupes.php b/maintenance/namespaceDupes.php
index 4197a355..6067a826 100644
--- a/maintenance/namespaceDupes.php
+++ b/maintenance/namespaceDupes.php
@@ -147,14 +147,13 @@ class NamespaceConflictChecker extends Maintenance {
/**
* Get the interwiki list
*
- * @todo Needs to respect interwiki cache!
* @return Array
*/
private function getInterwikiList() {
- $result = $this->db->select( 'interwiki', array( 'iw_prefix' ) );
+ $result = Interwiki::getAllPrefixes();
$prefixes = array();
foreach ( $result as $row ) {
- $prefixes[] = $row->iw_prefix;
+ $prefixes[] = $row['iw_prefix'];
}
return $prefixes;
}
diff --git a/maintenance/nextJobDB.php b/maintenance/nextJobDB.php
index e66e981b..1be5146e 100644
--- a/maintenance/nextJobDB.php
+++ b/maintenance/nextJobDB.php
@@ -18,7 +18,6 @@
* http://www.gnu.org/copyleft/gpl.html
*
* @file
- * @todo Make this work on PostgreSQL and maybe other database servers
* @ingroup Maintenance
*/
@@ -33,127 +32,86 @@ class nextJobDB extends Maintenance {
public function __construct() {
parent::__construct();
$this->mDescription = "Pick a database that has pending jobs";
- $this->addOption( 'type', "The type of job to search for", false, true );
+ $this->addOption( 'type', "Search by job type", false, true );
+ $this->addOption( 'types', "Space separated list of job types to search for", false, true );
}
public function execute() {
- global $wgMemc;
- $type = $this->getOption( 'type', false );
+ global $wgJobTypesExcludedFromDefaultQueue;
- $memcKey = 'jobqueue:dbs:v2';
- $pendingDBs = $wgMemc->get( $memcKey );
-
- // If the cache entry wasn't present, or in 1% of cases otherwise,
- // regenerate the cache.
- if ( !$pendingDBs || mt_rand( 0, 100 ) == 0 ) {
- $pendingDBs = $this->getPendingDbs();
- $wgMemc->set( $memcKey, $pendingDBs, 300 );
+ // job type required/picked
+ if ( $this->hasOption( 'types' ) ) {
+ $types = explode( ' ', $this->getOption( 'types' ) );
+ } elseif ( $this->hasOption( 'type' ) ) {
+ $types = array( $this->getOption( 'type' ) );
+ } else {
+ $types = false;
}
- if ( !$pendingDBs ) {
- return;
+ // Handle any required periodic queue maintenance
+ $this->executeReadyPeriodicTasks();
+
+ // Get all the queues with jobs in them
+ $pendingDBs = JobQueueAggregator::singleton()->getAllReadyWikiQueues();
+ if ( !count( $pendingDBs ) ) {
+ return; // no DBs with jobs or cache is both empty and locked
}
do {
$again = false;
- if ( $type === false ) {
- $candidates = call_user_func_array( 'array_merge', $pendingDBs );
- } elseif ( isset( $pendingDBs[$type] ) ) {
- $candidates = $pendingDBs[$type];
- } else {
- $candidates = array();
- }
- if ( !$candidates ) {
- return;
- }
-
- $candidates = array_values( $candidates );
- $db = $candidates[ mt_rand( 0, count( $candidates ) - 1 ) ];
- if ( !$this->checkJob( $type, $db ) ) {
- // This job is not available in the current database. Remove it from
- // the cache.
- if ( $type === false ) {
- foreach ( $pendingDBs as $type2 => $dbs ) {
- $pendingDBs[$type2] = array_diff( $pendingDBs[$type2], array( $db ) );
+ $candidates = array(); // list of (type, db)
+ // Flatten the tree of candidates into a flat list so that a random
+ // item can be selected, weighing each queue (type/db tuple) equally.
+ foreach ( $pendingDBs as $type => $dbs ) {
+ if (
+ ( is_array( $types ) && in_array( $type, $types ) ) ||
+ ( $types === false && !in_array( $type, $wgJobTypesExcludedFromDefaultQueue ) )
+ ) {
+ foreach ( $dbs as $db ) {
+ $candidates[] = array( $type, $db );
}
- } else {
- $pendingDBs[$type] = array_diff( $pendingDBs[$type], array( $db ) );
}
+ }
+ if ( !count( $candidates ) ) {
+ return; // no jobs for this type
+ }
- $wgMemc->set( $memcKey, $pendingDBs, 300 );
+ list( $type, $db ) = $candidates[mt_rand( 0, count( $candidates ) - 1 )];
+ if ( JobQueueGroup::singleton( $db )->isQueueDeprioritized( $type ) ) {
+ $pendingDBs[$type] = array_diff( $pendingDBs[$type], array( $db ) );
$again = true;
}
} while ( $again );
- $this->output( $db . "\n" );
- }
-
- /**
- * Check if the specified database has a job of the specified type in it.
- * The type may be false to indicate "all".
- * @param $type string
- * @param $dbName string
- * @return bool
- */
- function checkJob( $type, $dbName ) {
- $lb = wfGetLB( $dbName );
- $db = $lb->getConnection( DB_MASTER, array(), $dbName );
- if ( $type === false ) {
- $conds = Job::defaultQueueConditions( );
+ if ( $this->hasOption( 'types' ) ) {
+ $this->output( $db . " " . $type . "\n" );
} else {
- $conds = array( 'job_cmd' => $type );
+ $this->output( $db . "\n" );
}
-
-
- $exists = (bool) $db->selectField( 'job', '1', $conds, __METHOD__ );
- $lb->reuseConnection( $db );
- return $exists;
}
/**
- * Get all databases that have a pending job
- * @return array
+ * Do all ready periodic jobs for all databases every 5 minutes (and .1% of the time)
+ * @return integer
*/
- private function getPendingDbs() {
- global $wgLocalDatabases;
- $pendingDBs = array();
- # Cross-reference DBs by master DB server
- $dbsByMaster = array();
- foreach ( $wgLocalDatabases as $db ) {
- $lb = wfGetLB( $db );
- $dbsByMaster[$lb->getServerName( 0 )][] = $db;
- }
-
- foreach ( $dbsByMaster as $dbs ) {
- $dbConn = wfGetDB( DB_MASTER, array(), $dbs[0] );
-
- # Padding row for MySQL bug
- $pad = str_repeat( '-', 40 );
- $sql = "(SELECT '$pad' as db, '$pad' as job_cmd)";
- foreach ( $dbs as $wikiId ) {
- if ( $sql != '' ) {
- $sql .= ' UNION ';
+ private function executeReadyPeriodicTasks() {
+ global $wgLocalDatabases, $wgMemc;
+
+ $count = 0;
+ $memcKey = 'jobqueue:periodic:lasttime';
+ $timestamp = (int)$wgMemc->get( $memcKey ); // UNIX timestamp or 0
+ if ( ( time() - $timestamp ) > 300 || mt_rand( 0, 999 ) == 0 ) { // 5 minutes
+ if ( $wgMemc->add( "$memcKey:rebuild", 1, 1800 ) ) { // lock
+ foreach ( $wgLocalDatabases as $db ) {
+ $count += JobQueueGroup::singleton( $db )->executeReadyPeriodicTasks();
}
-
- list( $dbName, $tablePrefix ) = wfSplitWikiID( $wikiId );
- $dbConn->tablePrefix( $tablePrefix );
- $jobTable = $dbConn->tableName( 'job' );
-
- $sql .= "(SELECT DISTINCT '$wikiId' as db, job_cmd FROM $dbName.$jobTable GROUP BY job_cmd)";
- }
- $res = $dbConn->query( $sql, __METHOD__ );
- $first = true;
- foreach ( $res as $row ) {
- if ( $first ) {
- // discard padding row
- $first = false;
- continue;
- }
- $pendingDBs[$row->job_cmd][] = $row->db;
+ $wgMemc->set( $memcKey, time() );
+ $wgMemc->delete( "$memcKey:rebuild" ); // unlock
}
}
- return $pendingDBs;
+
+ return $count;
}
}
diff --git a/maintenance/oracle/alterSharedConstraints.php b/maintenance/oracle/alterSharedConstraints.php
index e222314d..a46c5e1f 100644
--- a/maintenance/oracle/alterSharedConstraints.php
+++ b/maintenance/oracle/alterSharedConstraints.php
@@ -15,13 +15,14 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* http://www.gnu.org/copyleft/gpl.html
*
+ * @file
* @ingroup Maintenance
*/
/**
* When using shared tables that are referenced by foreign keys on local
* tables you have to change the constraints on local tables.
- *
+ *
* The shared tables have to have GRANT REFERENCE on shared tables to local schema
* i.e.: GRANT REFERENCES (user_id) ON mwuser TO hubclient;
*/
@@ -40,12 +41,12 @@ class AlterSharedConstraints extends Maintenance {
public function execute() {
global $wgSharedDB, $wgSharedTables, $wgSharedPrefix, $wgDBprefix;
-
+
if ( $wgSharedDB == null ) {
$this->output( "Database sharing is not enabled\n" );
return;
}
-
+
$dbw = wfGetDB( DB_MASTER );
foreach ( $wgSharedTables as $table ) {
$stable = $dbw->tableNameInternal($table);
@@ -54,7 +55,7 @@ class AlterSharedConstraints extends Maintenance {
} else {
$ltable = "{$wgDBprefix}{$stable}" ;
}
-
+
$result = $dbw->query( "SELECT uc.constraint_name, uc.table_name, ucc.column_name, uccpk.table_name pk_table_name, uccpk.column_name pk_column_name, uc.delete_rule, uc.deferrable, uc.deferred
FROM user_constraints uc, user_cons_columns ucc, user_cons_columns uccpk
WHERE uc.constraint_type = 'R'
@@ -62,9 +63,9 @@ class AlterSharedConstraints extends Maintenance {
AND uccpk.constraint_name = uc.r_constraint_name
AND uccpk.table_name = '$ltable'" );
while (($row = $result->fetchRow()) !== false) {
-
+
$this->output( "Altering {$row['constraint_name']} ...");
-
+
try {
$dbw->query( "ALTER TABLE {$row['table_name']} DROP CONSTRAINT {$wgDBprefix}{$row['constraint_name']}" );
} catch (DBQueryError $exdb) {
@@ -72,13 +73,13 @@ class AlterSharedConstraints extends Maintenance {
throw $exdb;
}
}
-
+
$deleteRule = $row['delete_rule'] == 'NO ACTION' ? '' : "ON DELETE {$row['delete_rule']}";
- $dbw->query( "ALTER TABLE {$row['table_name']} ADD CONSTRAINT {$wgDBprefix}{$row['constraint_name']}
- FOREIGN KEY ({$row['column_name']})
- REFERENCES {$wgSharedDB}.$stable({$row['pk_column_name']})
+ $dbw->query( "ALTER TABLE {$row['table_name']} ADD CONSTRAINT {$wgDBprefix}{$row['constraint_name']}
+ FOREIGN KEY ({$row['column_name']})
+ REFERENCES {$wgSharedDB}.$stable({$row['pk_column_name']})
{$deleteRule} {$row['deferrable']} INITIALLY {$row['deferred']}" );
-
+
$this->output( "DONE\n" );
}
}
diff --git a/maintenance/oracle/archives/patch-archive-ar_content_format.sql b/maintenance/oracle/archives/patch-archive-ar_content_format.sql
new file mode 100644
index 00000000..0c0c0d94
--- /dev/null
+++ b/maintenance/oracle/archives/patch-archive-ar_content_format.sql
@@ -0,0 +1,3 @@
+define mw_prefix='{$wgDBprefix}';
+
+ALTER TABLE &mw_prefix.archive ADD ar_content_format VARCHAR2(64);
diff --git a/maintenance/oracle/archives/patch-archive-ar_content_model.sql b/maintenance/oracle/archives/patch-archive-ar_content_model.sql
new file mode 100644
index 00000000..d18fc9e4
--- /dev/null
+++ b/maintenance/oracle/archives/patch-archive-ar_content_model.sql
@@ -0,0 +1,3 @@
+define mw_prefix='{$wgDBprefix}';
+
+ALTER TABLE &mw_prefix.archive ADD ar_content_model VARCHAR2(32);
diff --git a/maintenance/oracle/archives/patch-cat_hidden.sql b/maintenance/oracle/archives/patch-cat_hidden.sql
new file mode 100644
index 00000000..d1649c7c
--- /dev/null
+++ b/maintenance/oracle/archives/patch-cat_hidden.sql
@@ -0,0 +1,4 @@
+define mw_prefix='{$wgDBprefix}';
+
+ALTER TABLE &mw_prefix.category DROP COLUMN cat_hidden;
+
diff --git a/maintenance/oracle/archives/patch-fa_sha1.sql b/maintenance/oracle/archives/patch-fa_sha1.sql
new file mode 100644
index 00000000..70c9e60c
--- /dev/null
+++ b/maintenance/oracle/archives/patch-fa_sha1.sql
@@ -0,0 +1,5 @@
+define mw_prefix='{$wgDBprefix}';
+
+ALTER TABLE &mw_prefix.filearchive ADD fa_sha1 VARCHAR2(32);
+CREATE INDEX &mw_prefix.filearchive_i05 ON &mw_prefix.filearchive (fa_sha1);
+
diff --git a/maintenance/oracle/archives/patch-job_attempts.sql b/maintenance/oracle/archives/patch-job_attempts.sql
new file mode 100644
index 00000000..b05c8779
--- /dev/null
+++ b/maintenance/oracle/archives/patch-job_attempts.sql
@@ -0,0 +1,4 @@
+define mw_prefix='{$wgDBprefix}';
+
+ALTER TABLE &mw_prefix.job ADD job_attempts NUMBER DEFAULT 0 NOT NULL;
+CREATE INDEX &mw_prefix.job_i05 ON &mw_prefix.job (job_attempts);
diff --git a/maintenance/oracle/archives/patch-job_token.sql b/maintenance/oracle/archives/patch-job_token.sql
new file mode 100644
index 00000000..1a730e95
--- /dev/null
+++ b/maintenance/oracle/archives/patch-job_token.sql
@@ -0,0 +1,12 @@
+define mw_prefix='{$wgDBprefix}';
+
+ALTER TABLE &mw_prefix.job ADD (
+ job_random NUMBER DEFAULT 0 NOT NULL,
+ job_token VARCHAR2(32),
+ job_token_timestamp TIMESTAMP(6) WITH TIME ZONE,
+ job_sha1 VARCHAR2(32)
+);
+
+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);
+
diff --git a/maintenance/oracle/archives/patch-page-page_content_model.sql b/maintenance/oracle/archives/patch-page-page_content_model.sql
new file mode 100644
index 00000000..e5839d9a
--- /dev/null
+++ b/maintenance/oracle/archives/patch-page-page_content_model.sql
@@ -0,0 +1,3 @@
+define mw_prefix='{$wgDBprefix}';
+
+ALTER TABLE &mw_prefix.page ADD page_content_model VARCHAR2(32);
diff --git a/maintenance/oracle/archives/patch-rc_moved.sql b/maintenance/oracle/archives/patch-rc_moved.sql
new file mode 100644
index 00000000..2a71315d
--- /dev/null
+++ b/maintenance/oracle/archives/patch-rc_moved.sql
@@ -0,0 +1,4 @@
+define mw_prefix='{$wgDBprefix}';
+
+ALTER TABLE &mw_prefix.recentchanges DROP ( rc_moved_to_ns, rc_moved_to_title );
+
diff --git a/maintenance/oracle/archives/patch-revision-rev_content_format.sql b/maintenance/oracle/archives/patch-revision-rev_content_format.sql
new file mode 100644
index 00000000..ebde71c9
--- /dev/null
+++ b/maintenance/oracle/archives/patch-revision-rev_content_format.sql
@@ -0,0 +1,3 @@
+define mw_prefix='{$wgDBprefix}';
+
+ALTER TABLE &mw_prefix.revision ADD rev_content_format VARCHAR2(64);
diff --git a/maintenance/oracle/archives/patch-revision-rev_content_model.sql b/maintenance/oracle/archives/patch-revision-rev_content_model.sql
new file mode 100644
index 00000000..dd226423
--- /dev/null
+++ b/maintenance/oracle/archives/patch-revision-rev_content_model.sql
@@ -0,0 +1,3 @@
+define mw_prefix='{$wgDBprefix}';
+
+ALTER TABLE &mw_prefix.revision ADD rev_content_model VARCHAR2(32);
diff --git a/maintenance/oracle/archives/patch-sites.sql b/maintenance/oracle/archives/patch-sites.sql
new file mode 100644
index 00000000..868b210f
--- /dev/null
+++ b/maintenance/oracle/archives/patch-sites.sql
@@ -0,0 +1,34 @@
+define mw_prefix='{$wgDBprefix}';
+
+CREATE SEQUENCE sites_site_id_seq MINVALUE 0 START WITH 0;
+CREATE TABLE &mw_prefix.sites (
+ site_id NUMBER NOT NULL,
+ site_global_key VARCHAR2(32) NOT NULL,
+ site_type VARCHAR2(32) NOT NULL,
+ site_group VARCHAR2(32) NOT NULL,
+ site_source VARCHAR2(32) NOT NULL,
+ site_language VARCHAR2(32) NOT NULL,
+ site_protocol VARCHAR2(32) NOT NULL,
+ site_domain VARCHAR2(255) NOT NULL,
+ site_data BLOB NOT NULL,
+ site_forward NUMBER(1) NOT NULL,
+ site_config BLOB NOT NULL
+);
+ALTER TABLE &mw_prefix.sites ADD CONSTRAINT &mw_prefix.sites_pk PRIMARY KEY (site_id);
+CREATE UNIQUE INDEX &mw_prefix.sites_u01 ON &mw_prefix.sites (site_global_key);
+CREATE INDEX &mw_prefix.sites_i01 ON &mw_prefix.sites (site_type);
+CREATE INDEX &mw_prefix.sites_i02 ON &mw_prefix.sites (site_group);
+CREATE INDEX &mw_prefix.sites_i03 ON &mw_prefix.sites (site_source);
+CREATE INDEX &mw_prefix.sites_i04 ON &mw_prefix.sites (site_language);
+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);
+
+CREATE TABLE &mw_prefix.site_identifiers (
+ si_site NUMBER NOT NULL,
+ si_type VARCHAR2(32) NOT NULL,
+ si_key VARCHAR2(32) NOT NULL
+);
+CREATE UNIQUE INDEX &mw_prefix.site_identifiers_u01 ON &mw_prefix.site_identifiers (si_type, si_key);
+CREATE INDEX &mw_prefix.site_identifiers_i01 ON &mw_prefix.site_identifiers (si_site);
+CREATE INDEX &mw_prefix.site_identifiers_i02 ON &mw_prefix.site_identifiers (si_key);
diff --git a/maintenance/oracle/archives/patch-ss_admins.sql b/maintenance/oracle/archives/patch-ss_admins.sql
new file mode 100644
index 00000000..c2e9242e
--- /dev/null
+++ b/maintenance/oracle/archives/patch-ss_admins.sql
@@ -0,0 +1,4 @@
+define mw_prefix='{$wgDBprefix}';
+
+ALTER TABLE &mw_prefix.site_stats DROP COLUMN ss_admins;
+
diff --git a/maintenance/oracle/archives/patch-testrun.sql b/maintenance/oracle/archives/patch-testrun.sql
index 6e3e1b7c..84facabc 100644
--- a/maintenance/oracle/archives/patch-testrun.sql
+++ b/maintenance/oracle/archives/patch-testrun.sql
@@ -25,7 +25,7 @@ BEFORE UPDATE FOR EACH ROW
ON &mw_prefix.testrun
BEGIN
SELECT testrun_tr_id_seq.NEXTVAL into :NEW.tr_id FROM dual;
-END;
+END;
CREATE TABLE /*$wgDBprefix*/testitem (
ti_run NUMBER NOT NULL REFERENCES &mw_prefix.testrun (tr_id) ON DELETE CASCADE,
diff --git a/maintenance/oracle/archives/patch-ufg_group-length-increase.sql b/maintenance/oracle/archives/patch-ufg_group-length-increase-255.sql
index a48b8bff..6a4a7517 100644
--- a/maintenance/oracle/archives/patch-ufg_group-length-increase.sql
+++ b/maintenance/oracle/archives/patch-ufg_group-length-increase-255.sql
@@ -2,7 +2,7 @@ define mw_prefix='{$wgDBprefix}';
/*$mw$*/
BEGIN
- EXECUTE IMMEDIATE 'ALTER TABLE &mw_prefix.user_former_groups MODIFY ufg_group VARCHAR2(32) NOT NULL';
+ EXECUTE IMMEDIATE 'ALTER TABLE &mw_prefix.user_former_groups MODIFY ufg_group VARCHAR2(255) NOT NULL';
EXCEPTION WHEN OTHERS THEN
IF (SQLCODE = -01442) THEN NULL; ELSE RAISE; END IF;
END;
diff --git a/maintenance/oracle/archives/patch-ug_group-length-increase.sql b/maintenance/oracle/archives/patch-ug_group-length-increase-255.sql
index 89e55329..00a5e7b2 100644
--- a/maintenance/oracle/archives/patch-ug_group-length-increase.sql
+++ b/maintenance/oracle/archives/patch-ug_group-length-increase-255.sql
@@ -2,7 +2,7 @@ define mw_prefix='{$wgDBprefix}';
/*$mw$*/
BEGIN
- EXECUTE IMMEDIATE 'ALTER TABLE &mw_prefix.user_groups MODIFY ug_group VARCHAR2(32) NOT NULL';
+ EXECUTE IMMEDIATE 'ALTER TABLE &mw_prefix.user_groups MODIFY ug_group VARCHAR2(255) NOT NULL';
EXCEPTION WHEN OTHERS THEN
IF (SQLCODE = -01442) THEN NULL; ELSE RAISE; END IF;
END;
diff --git a/maintenance/oracle/archives/patch-uploadstash-us_props.sql b/maintenance/oracle/archives/patch-uploadstash-us_props.sql
new file mode 100644
index 00000000..8962dc7c
--- /dev/null
+++ b/maintenance/oracle/archives/patch-uploadstash-us_props.sql
@@ -0,0 +1,4 @@
+define mw_prefix='{$wgDBprefix}';
+
+ALTER TABLE &mw_prefix.uploadstash ADD us_props BLOB;
+
diff --git a/maintenance/oracle/archives/patch-user_former_groups.sql b/maintenance/oracle/archives/patch-user_former_groups.sql
index 59147eb2..c14824eb 100644
--- a/maintenance/oracle/archives/patch-user_former_groups.sql
+++ b/maintenance/oracle/archives/patch-user_former_groups.sql
@@ -2,7 +2,7 @@ define mw_prefix='{$wgDBprefix}';
CREATE TABLE &mw_prefix.user_former_groups (
ufg_user NUMBER DEFAULT 0 NOT NULL,
- ufg_group VARCHAR2(16) NOT NULL
+ ufg_group VARCHAR2(255) NOT NULL
);
ALTER TABLE &mw_prefix.user_former_groups ADD CONSTRAINT &mw_prefix.user_former_groups_fk1 FOREIGN KEY (ufg_user) REFERENCES &mw_prefix.mwuser(user_id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED;
CREATE UNIQUE INDEX &mw_prefix.user_former_groups_u01 ON &mw_prefix.user_former_groups (ufg_user,ufg_group);
diff --git a/maintenance/oracle/tables.sql b/maintenance/oracle/tables.sql
index 26600eba..ba69da1b 100644
--- a/maintenance/oracle/tables.sql
+++ b/maintenance/oracle/tables.sql
@@ -31,7 +31,7 @@ INSERT INTO &mw_prefix.mwuser
CREATE TABLE &mw_prefix.user_groups (
ug_user NUMBER DEFAULT 0 NOT NULL,
- ug_group VARCHAR2(32) NOT NULL
+ ug_group VARCHAR2(255) NOT NULL
);
ALTER TABLE &mw_prefix.user_groups ADD CONSTRAINT &mw_prefix.user_groups_fk1 FOREIGN KEY (ug_user) REFERENCES &mw_prefix.mwuser(user_id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED;
CREATE UNIQUE INDEX &mw_prefix.user_groups_u01 ON &mw_prefix.user_groups (ug_user,ug_group);
@@ -39,7 +39,7 @@ CREATE INDEX &mw_prefix.user_groups_i01 ON &mw_prefix.user_groups (ug_group);
CREATE TABLE &mw_prefix.user_former_groups (
ufg_user NUMBER DEFAULT 0 NOT NULL,
- ufg_group VARCHAR2(16) NOT NULL
+ ufg_group VARCHAR2(255) NOT NULL
);
ALTER TABLE &mw_prefix.user_former_groups ADD CONSTRAINT &mw_prefix.user_former_groups_fk1 FOREIGN KEY (ufg_user) REFERENCES &mw_prefix.mwuser(user_id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED;
CREATE UNIQUE INDEX &mw_prefix.user_former_groups_u01 ON &mw_prefix.user_former_groups (ufg_user,ufg_group);
@@ -73,7 +73,8 @@ CREATE TABLE &mw_prefix.page (
page_random NUMBER(15,14) NOT NULL,
page_touched TIMESTAMP(6) WITH TIME ZONE,
page_latest NUMBER DEFAULT 0 NOT NULL, -- FK?
- page_len NUMBER DEFAULT 0 NOT NULL
+ page_len NUMBER DEFAULT 0 NOT NULL,
+ page_content_model VARCHAR2(32)
);
ALTER TABLE &mw_prefix.page ADD CONSTRAINT &mw_prefix.page_pk PRIMARY KEY (page_id);
CREATE UNIQUE INDEX &mw_prefix.page_u01 ON &mw_prefix.page (page_namespace,page_title);
@@ -83,7 +84,7 @@ CREATE INDEX &mw_prefix.page_i03 ON &mw_prefix.page (page_is_redirect, page_name
-- Create a dummy page to satisfy fk contraints especially with revisions
INSERT INTO &mw_prefix.page
- VALUES (0, 0, ' ', NULL, 0, 0, 0, 0, current_timestamp, 0, 0);
+ VALUES (0, 0, ' ', NULL, 0, 0, 0, 0, current_timestamp, 0, 0, NULL);
/*$mw$*/
CREATE TRIGGER &mw_prefix.page_set_random BEFORE INSERT ON &mw_prefix.page
@@ -106,7 +107,9 @@ CREATE TABLE &mw_prefix.revision (
rev_deleted CHAR(1) DEFAULT '0' NOT NULL,
rev_len NUMBER NULL,
rev_parent_id NUMBER DEFAULT NULL,
- rev_sha1 VARCHAR2(32) NULL
+ rev_sha1 VARCHAR2(32) NULL,
+ rev_content_model VARCHAR2(32),
+ rev_content_format VARCHAR2(64)
);
ALTER TABLE &mw_prefix.revision ADD CONSTRAINT &mw_prefix.revision_pk PRIMARY KEY (rev_id);
ALTER TABLE &mw_prefix.revision ADD CONSTRAINT &mw_prefix.revision_fk1 FOREIGN KEY (rev_page) REFERENCES &mw_prefix.page(page_id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED;
@@ -142,7 +145,9 @@ CREATE TABLE &mw_prefix.archive (
ar_len NUMBER,
ar_page_id NUMBER,
ar_parent_id NUMBER,
- ar_sha1 VARCHAR2(32) NULL
+ ar_sha1 VARCHAR2(32),
+ ar_content_model VARCHAR2(32),
+ ar_content_format VARCHAR2(64)
);
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;
CREATE INDEX &mw_prefix.archive_i01 ON &mw_prefix.archive (ar_namespace,ar_title,ar_timestamp);
@@ -197,8 +202,7 @@ CREATE TABLE &mw_prefix.category (
cat_title VARCHAR2(255) NOT NULL,
cat_pages NUMBER DEFAULT 0 NOT NULL,
cat_subcats NUMBER DEFAULT 0 NOT NULL,
- cat_files NUMBER DEFAULT 0 NOT NULL,
- cat_hidden NUMBER DEFAULT 0 NOT NULL
+ cat_files NUMBER DEFAULT 0 NOT NULL
);
ALTER TABLE &mw_prefix.category ADD CONSTRAINT &mw_prefix.category_pk PRIMARY KEY (cat_id);
CREATE UNIQUE INDEX &mw_prefix.category_u01 ON &mw_prefix.category (cat_title);
@@ -246,7 +250,6 @@ CREATE TABLE &mw_prefix.site_stats (
ss_total_pages NUMBER DEFAULT -1,
ss_users NUMBER DEFAULT -1,
ss_active_users NUMBER DEFAULT -1,
- ss_admins NUMBER DEFAULT -1,
ss_images NUMBER DEFAULT 0
);
CREATE UNIQUE INDEX &mw_prefix.site_stats_u01 ON &mw_prefix.site_stats (ss_row_id);
@@ -358,7 +361,8 @@ CREATE TABLE &mw_prefix.filearchive (
fa_user NUMBER DEFAULT 0 NOT NULL,
fa_user_text VARCHAR2(255) NOT NULL,
fa_timestamp TIMESTAMP(6) WITH TIME ZONE,
- fa_deleted NUMBER DEFAULT 0 NOT NULL
+ fa_deleted NUMBER DEFAULT 0 NOT NULL,
+ fa_sha1 VARCHAR2(32)
);
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;
@@ -367,6 +371,7 @@ CREATE INDEX &mw_prefix.filearchive_i01 ON &mw_prefix.filearchive (fa_name, fa_t
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.filearchive_i05 ON &mw_prefix.filearchive (fa_sha1);
CREATE SEQUENCE uploadstash_us_id_seq;
CREATE TABLE &mw_prefix.uploadstash (
@@ -385,7 +390,8 @@ CREATE TABLE &mw_prefix.uploadstash (
us_media_type VARCHAR2(32) DEFAULT NULL,
us_image_width NUMBER,
us_image_height NUMBER,
- us_image_bits NUMBER
+ us_image_bits NUMBER,
+ us_props BLOB
);
ALTER TABLE &mw_prefix.uploadstash ADD CONSTRAINT &mw_prefix.uploadstash_pk PRIMARY KEY (us_id);
ALTER TABLE &mw_prefix.uploadstash ADD CONSTRAINT &mw_prefix.uploadstash_fk1 FOREIGN KEY (us_user) REFERENCES &mw_prefix.mwuser(user_id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED;
@@ -523,11 +529,19 @@ CREATE TABLE &mw_prefix.job (
job_namespace NUMBER DEFAULT 0 NOT NULL,
job_title VARCHAR2(255) NOT NULL,
job_timestamp TIMESTAMP(6) WITH TIME ZONE NULL,
- job_params CLOB NOT NULL
+ job_params CLOB NOT NULL,
+ job_random NUMBER DEFAULT 0 NOT NULL,
+ job_token VARCHAR2(32),
+ job_token_timestamp TIMESTAMP(6) WITH TIME ZONE,
+ job_sha1 VARCHAR2(32),
+ job_attempts NUMBER DEFAULT 0 NOT NULL
);
ALTER TABLE &mw_prefix.job ADD CONSTRAINT &mw_prefix.job_pk PRIMARY KEY (job_id);
CREATE INDEX &mw_prefix.job_i01 ON &mw_prefix.job (job_cmd, job_namespace, job_title);
CREATE INDEX &mw_prefix.job_i02 ON &mw_prefix.job (job_timestamp);
+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);
CREATE TABLE &mw_prefix.querycache_info (
qci_type VARCHAR2(32) NOT NULL,
@@ -667,6 +681,39 @@ CREATE TABLE &mw_prefix.module_deps (
);
CREATE UNIQUE INDEX &mw_prefix.module_deps_u01 ON &mw_prefix.module_deps (md_module, md_skin);
+CREATE SEQUENCE sites_site_id_seq MINVALUE 0 START WITH 0;
+CREATE TABLE &mw_prefix.sites (
+ site_id NUMBER NOT NULL,
+ site_global_key VARCHAR2(32) NOT NULL,
+ site_type VARCHAR2(32) NOT NULL,
+ site_group VARCHAR2(32) NOT NULL,
+ site_source VARCHAR2(32) NOT NULL,
+ site_language VARCHAR2(32) NOT NULL,
+ site_protocol VARCHAR2(32) NOT NULL,
+ site_domain VARCHAR2(255) NOT NULL,
+ site_data BLOB NOT NULL,
+ site_forward NUMBER(1) NOT NULL,
+ site_config BLOB NOT NULL
+);
+ALTER TABLE &mw_prefix.sites ADD CONSTRAINT &mw_prefix.sites_pk PRIMARY KEY (site_id);
+CREATE UNIQUE INDEX &mw_prefix.sites_u01 ON &mw_prefix.sites (site_global_key);
+CREATE INDEX &mw_prefix.sites_i01 ON &mw_prefix.sites (site_type);
+CREATE INDEX &mw_prefix.sites_i02 ON &mw_prefix.sites (site_group);
+CREATE INDEX &mw_prefix.sites_i03 ON &mw_prefix.sites (site_source);
+CREATE INDEX &mw_prefix.sites_i04 ON &mw_prefix.sites (site_language);
+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);
+
+CREATE TABLE &mw_prefix.site_identifiers (
+ si_site NUMBER NOT NULL,
+ si_type VARCHAR2(32) NOT NULL,
+ si_key VARCHAR2(32) NOT NULL
+);
+CREATE UNIQUE INDEX &mw_prefix.site_identifiers_u01 ON &mw_prefix.site_identifiers (si_type, si_key);
+CREATE INDEX &mw_prefix.site_identifiers_i01 ON &mw_prefix.site_identifiers (si_site);
+CREATE INDEX &mw_prefix.site_identifiers_i02 ON &mw_prefix.site_identifiers (si_key);
+
-- do not prefix this table as it breaks parserTests
CREATE TABLE wiki_field_info_full (
table_name VARCHAR2(35) NOT NULL,
diff --git a/maintenance/orphans.php b/maintenance/orphans.php
index 78f98f5a..3b1a9b0e 100644
--- a/maintenance/orphans.php
+++ b/maintenance/orphans.php
@@ -87,7 +87,7 @@ class Orphans extends Maintenance {
FROM $revision LEFT OUTER JOIN $page ON rev_page=page_id
WHERE page_id IS NULL
" );
- $orphans = $dbw->numRows( $result );
+ $orphans = $result->numRows();
if ( $orphans > 0 ) {
global $wgContLang;
$this->output( "$orphans orphan revisions...\n" );
@@ -139,7 +139,7 @@ class Orphans extends Maintenance {
FROM $page LEFT OUTER JOIN $revision ON page_latest=rev_id
WHERE rev_id IS NULL
" );
- $widows = $dbw->numRows( $result );
+ $widows = $result->numRows();
if ( $widows > 0 ) {
$this->output( "$widows childless pages...\n" );
$this->output( sprintf( "%10s %11s %2s %s\n", 'page_id', 'page_latest', 'ns', 'page_title' ) );
diff --git a/maintenance/parse.php b/maintenance/parse.php
index b0ab6244..58e76b0a 100644
--- a/maintenance/parse.php
+++ b/maintenance/parse.php
@@ -109,7 +109,7 @@ class CLIParser extends Maintenance {
*
* @return Title object
*/
- protected function getTitle( ) {
+ protected function getTitle() {
$title =
$this->getOption( 'title' )
? $this->getOption( 'title' )
diff --git a/maintenance/populateFilearchiveSha1.php b/maintenance/populateFilearchiveSha1.php
new file mode 100644
index 00000000..27e692d1
--- /dev/null
+++ b/maintenance/populateFilearchiveSha1.php
@@ -0,0 +1,107 @@
+<?php
+/**
+ * Optional upgrade script to populate the fa_sha1 field
+ *
+ * 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( dirname( __FILE__ ) . '/Maintenance.php' );
+
+/**
+ * Maintenance script to populate the fa_sha1 field.
+ *
+ * @ingroup Maintenance
+ * @since 1.21
+ */
+class PopulateFilearchiveSha1 extends LoggedUpdateMaintenance {
+ public function __construct() {
+ parent::__construct();
+ $this->mDescription = "Populate the fa_sha1 field from fa_storage_key";
+ }
+
+ protected function getUpdateKey() {
+ return 'populate fa_sha1';
+ }
+
+ protected function updateSkippedMessage() {
+ return 'fa_sha1 column of filearchive table already populated.';
+ }
+
+ public function doDBUpdates() {
+ $startTime = microtime( true );
+ $dbw = wfGetDB( DB_MASTER );
+ $table = 'filearchive';
+ $conds = array( 'fa_sha1' => '', 'fa_storage_key IS NOT NULL' );
+
+ if ( !$dbw->fieldExists( $table, 'fa_sha1', __METHOD__ ) ) {
+ $this->output( "fa_sha1 column does not exist\n\n", true );
+ return false;
+ }
+
+ $this->output( "Populating fa_sha1 field from fa_storage_key\n" );
+ $endId = $dbw->selectField( $table, 'MAX(fa_id)', false, __METHOD__ );
+
+ $batchSize = $this->mBatchSize;
+ $done = 0;
+
+ do {
+ $res = $dbw->select(
+ $table,
+ array( 'fa_id', 'fa_storage_key' ),
+ $conds,
+ __METHOD__,
+ array( 'LIMIT' => $batchSize )
+ );
+
+ $i = 0;
+ foreach ( $res as $row ) {
+ if ( $row->fa_storage_key == '' ) {
+ // Revision was missing pre-deletion
+ continue;
+ }
+ $sha1 = LocalRepo::getHashFromKey( $row->fa_storage_key );
+ $dbw->update( $table,
+ array( 'fa_sha1' => $sha1 ),
+ array( 'fa_id' => $row->fa_id ),
+ __METHOD__
+ );
+ $lastId = $row->fa_id;
+ $i++;
+ }
+
+ $done += $i;
+ if( $i !== $batchSize ) {
+ break;
+ }
+
+ // print status and let slaves catch up
+ $this->output( sprintf(
+ "id %d done (up to %d), %5.3f%% \r", $lastId, $endId, $lastId / $endId * 100 ) );
+ wfWaitForSlaves();
+ } while( true );
+
+ $processingTime = microtime( true ) - $startTime;
+ $this->output( sprintf( "\nDone %d files in %.1f seconds\n", $done, $processingTime ) );
+
+ return true; // we only updated *some* files, don't log
+ }
+}
+
+$maintClass = "PopulateFilearchiveSha1";
+require_once( RUN_MAINTENANCE_IF_MAIN );
diff --git a/maintenance/populateLogUsertext.php b/maintenance/populateLogUsertext.php
index 059b6fe2..fa9d512f 100644
--- a/maintenance/populateLogUsertext.php
+++ b/maintenance/populateLogUsertext.php
@@ -83,4 +83,3 @@ class PopulateLogUsertext extends LoggedUpdateMaintenance {
$maintClass = "PopulateLogUsertext";
require_once( RUN_MAINTENANCE_IF_MAIN );
-
diff --git a/maintenance/populateRevisionLength.php b/maintenance/populateRevisionLength.php
index 6c835f4e..7c529d53 100644
--- a/maintenance/populateRevisionLength.php
+++ b/maintenance/populateRevisionLength.php
@@ -48,7 +48,11 @@ class PopulateRevisionLength extends LoggedUpdateMaintenance {
$db = $this->getDB( DB_MASTER );
if ( !$db->tableExists( 'revision' ) ) {
$this->error( "revision table does not exist", true );
+ } else if ( !$db->fieldExists( 'revision', 'rev_sha1', __METHOD__ ) ) {
+ $this->output( "rev_sha1 column does not exist\n\n", true );
+ return false;
}
+
$this->output( "Populating rev_len column\n" );
$start = $db->selectField( 'revision', 'MIN(rev_id)', false, __METHOD__ );
@@ -63,10 +67,11 @@ class PopulateRevisionLength extends LoggedUpdateMaintenance {
$blockEnd = intval( $start ) + $this->mBatchSize - 1;
$count = 0;
$missing = 0;
+ $fields = Revision::selectFields();
while ( $blockStart <= $end ) {
$this->output( "...doing rev_id from $blockStart to $blockEnd\n" );
$res = $db->select( 'revision',
- Revision::selectFields(),
+ $fields,
array( "rev_id >= $blockStart",
"rev_id <= $blockEnd",
"rev_len IS NULL" ),
@@ -74,16 +79,16 @@ class PopulateRevisionLength extends LoggedUpdateMaintenance {
# Go through and update rev_len from these rows.
foreach ( $res as $row ) {
$rev = new Revision( $row );
- $text = $rev->getRawText();
- if ( !is_string( $text ) ) {
+ $content = $rev->getContent();
+ if ( !$content ) {
# This should not happen, but sometimes does (bug 20757)
- $this->output( "Text of revision {$row->rev_id} unavailable!\n" );
+ $this->output( "Content of revision {$row->rev_id} unavailable!\n" );
$missing++;
}
else {
# Update the row...
$db->update( 'revision',
- array( 'rev_len' => strlen( $text ) ),
+ array( 'rev_len' => $content->getSize() ),
array( 'rev_id' => $row->rev_id ),
__METHOD__ );
$count++;
diff --git a/maintenance/populateRevisionSha1.php b/maintenance/populateRevisionSha1.php
index 2e14d31e..113eef49 100644
--- a/maintenance/populateRevisionSha1.php
+++ b/maintenance/populateRevisionSha1.php
@@ -48,6 +48,9 @@ class PopulateRevisionSha1 extends LoggedUpdateMaintenance {
$this->error( "revision table does not exist", true );
} elseif ( !$db->tableExists( 'archive' ) ) {
$this->error( "archive table does not exist", true );
+ } else if ( !$db->fieldExists( 'revision', 'rev_sha1', __METHOD__ ) ) {
+ $this->output( "rev_sha1 column does not exist\n\n", true );
+ return false;
}
$this->output( "Populating rev_sha1 column\n" );
@@ -143,14 +146,14 @@ class PopulateRevisionSha1 extends LoggedUpdateMaintenance {
$rev = ( $table === 'archive' )
? Revision::newFromArchiveRow( $row )
: new Revision( $row );
- $text = $rev->getRawText();
+ $text = $rev->getSerializedData();
} catch ( MWException $e ) {
- $this->output( "Text of revision with {$idCol}={$row->$idCol} unavailable!\n" );
+ $this->output( "Data of revision with {$idCol}={$row->$idCol} unavailable!\n" );
return false; // bug 22624?
}
if ( !is_string( $text ) ) {
# This should not happen, but sometimes does (bug 20757)
- $this->output( "Text of revision with {$idCol}={$row->$idCol} unavailable!\n" );
+ $this->output( "Data of revision with {$idCol}={$row->$idCol} unavailable!\n" );
return false;
} else {
$db->update( $table,
@@ -174,10 +177,10 @@ class PopulateRevisionSha1 extends LoggedUpdateMaintenance {
$this->output( "Text of revision with timestamp {$row->ar_timestamp} unavailable!\n" );
return false; // bug 22624?
}
- $text = $rev->getRawText();
+ $text = $rev->getSerializedData();
if ( !is_string( $text ) ) {
# This should not happen, but sometimes does (bug 20757)
- $this->output( "Text of revision with timestamp {$row->ar_timestamp} unavailable!\n" );
+ $this->output( "Data of revision with timestamp {$row->ar_timestamp} unavailable!\n" );
return false;
} else {
# Archive table as no PK, but (NS,title,time) should be near unique.
diff --git a/maintenance/postgres/archives/patch-sites.sql b/maintenance/postgres/archives/patch-sites.sql
new file mode 100644
index 00000000..a4f9ed9e
--- /dev/null
+++ b/maintenance/postgres/archives/patch-sites.sql
@@ -0,0 +1,31 @@
+CREATE SEQUENCE sites_site_id_seq;
+CREATE TABLE sites (
+ site_id INTEGER NOT NULL PRIMARY KEY DEFAULT nextval('sites_site_id_seq'),
+ site_global_key TEXT NOT NULL,
+ site_type TEXT NOT NULL,
+ site_group TEXT NOT NULL,
+ site_source TEXT NOT NULL,
+ site_language TEXT NOT NULL,
+ site_protocol TEXT NOT NULL,
+ site_domain TEXT NOT NULL,
+ site_data TEXT NOT NULL,
+ site_forward SMALLINT NOT NULL,
+ site_config TEXT NOT NULL
+);
+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);
+CREATE INDEX site_source ON sites (site_source);
+CREATE INDEX site_language ON sites (site_language);
+CREATE INDEX site_protocol ON sites (site_protocol);
+CREATE INDEX site_domain ON sites (site_domain);
+CREATE INDEX site_forward ON sites (site_forward);
+
+CREATE TABLE site_identifiers (
+ si_site INTEGER NOT NULL,
+ si_type TEXT NOT NULL,
+ si_key TEXT NOT NULL
+);
+CREATE UNIQUE INDEX si_type_key ON site_identifiers (si_type, si_key);
+CREATE INDEX si_site ON site_identifiers (si_site);
+CREATE INDEX si_key ON site_identifiers (si_key);
diff --git a/maintenance/postgres/archives/patch-testrun.sql b/maintenance/postgres/archives/patch-testrun.sql
index c15300b5..a131b5da 100644
--- a/maintenance/postgres/archives/patch-testrun.sql
+++ b/maintenance/postgres/archives/patch-testrun.sql
@@ -26,5 +26,5 @@ CREATE TABLE testitem (
ti_run INTEGER NOT NULL REFERENCES testrun(tr_id) ON DELETE CASCADE,
ti_name TEXT NOT NULL,
ti_success SMALLINT NOT NULL
-);
+);
CREATE UNIQUE INDEX testitem_uniq ON testitem(ti_run, ti_name);
diff --git a/maintenance/postgres/tables.sql b/maintenance/postgres/tables.sql
index 3ac19cb4..9cbabfdf 100644
--- a/maintenance/postgres/tables.sql
+++ b/maintenance/postgres/tables.sql
@@ -79,7 +79,8 @@ CREATE TABLE page (
page_random NUMERIC(15,14) NOT NULL DEFAULT RANDOM(),
page_touched TIMESTAMPTZ,
page_latest INTEGER NOT NULL, -- FK?
- page_len INTEGER NOT NULL
+ page_len INTEGER NOT NULL,
+ page_content_model TEXT
);
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;
@@ -104,18 +105,20 @@ CREATE TRIGGER page_deleted AFTER DELETE ON page
CREATE SEQUENCE revision_rev_id_seq;
CREATE TABLE revision (
- rev_id INTEGER NOT NULL UNIQUE DEFAULT nextval('revision_rev_id_seq'),
- rev_page INTEGER NULL REFERENCES page (page_id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
- rev_text_id INTEGER NULL, -- FK
- rev_comment TEXT,
- rev_user INTEGER NOT NULL REFERENCES mwuser(user_id) ON DELETE RESTRICT DEFERRABLE INITIALLY DEFERRED,
- rev_user_text TEXT NOT NULL,
- rev_timestamp TIMESTAMPTZ NOT NULL,
- rev_minor_edit SMALLINT NOT NULL DEFAULT 0,
- rev_deleted SMALLINT NOT NULL DEFAULT 0,
- rev_len INTEGER NULL,
- rev_parent_id INTEGER NULL,
- rev_sha1 TEXT NOT NULL DEFAULT ''
+ rev_id INTEGER NOT NULL UNIQUE DEFAULT nextval('revision_rev_id_seq'),
+ rev_page INTEGER NULL REFERENCES page (page_id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
+ rev_text_id INTEGER NULL, -- FK
+ rev_comment TEXT,
+ rev_user INTEGER NOT NULL REFERENCES mwuser(user_id) ON DELETE RESTRICT DEFERRABLE INITIALLY DEFERRED,
+ rev_user_text TEXT NOT NULL,
+ rev_timestamp TIMESTAMPTZ NOT NULL,
+ rev_minor_edit SMALLINT NOT NULL DEFAULT 0,
+ rev_deleted SMALLINT NOT NULL DEFAULT 0,
+ rev_len INTEGER NULL,
+ rev_parent_id INTEGER NULL,
+ rev_sha1 TEXT NOT NULL DEFAULT '',
+ rev_content_model TEXT,
+ rev_content_format TEXT
);
CREATE UNIQUE INDEX revision_unique ON revision (rev_page, rev_id);
CREATE INDEX rev_text_id_idx ON revision (rev_text_id);
@@ -151,24 +154,27 @@ CREATE TABLE page_props (
);
ALTER TABLE page_props ADD CONSTRAINT page_props_pk PRIMARY KEY (pp_page,pp_propname);
CREATE INDEX page_props_propname ON page_props (pp_propname);
+CREATE UNIQUE INDEX pp_propname_page ON page_props (pp_propname,pp_page);
CREATE TABLE archive (
- 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,
- ar_user INTEGER NULL REFERENCES mwuser(user_id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED,
- ar_user_text TEXT NOT NULL,
- 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_deleted SMALLINT NOT NULL DEFAULT 0,
- ar_len INTEGER NULL
+ 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,
+ ar_user INTEGER NULL REFERENCES mwuser(user_id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED,
+ ar_user_text TEXT NOT NULL,
+ 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_deleted SMALLINT NOT NULL DEFAULT 0,
+ ar_len INTEGER NULL,
+ ar_content_model TEXT,
+ ar_content_format TEXT
);
CREATE INDEX archive_name_title_timestamp ON archive (ar_namespace,ar_title,ar_timestamp);
CREATE INDEX archive_user_text ON archive (ar_user_text);
@@ -353,12 +359,14 @@ CREATE TABLE filearchive (
fa_user INTEGER NULL REFERENCES mwuser(user_id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED,
fa_user_text TEXT NOT NULL,
fa_timestamp TIMESTAMPTZ,
- fa_deleted SMALLINT NOT NULL DEFAULT 0
+ fa_deleted SMALLINT NOT NULL DEFAULT 0,
+ fa_sha1 TEXT NOT NULL DEFAULT ''
);
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);
CREATE INDEX fa_nouser ON filearchive (fa_deleted_user);
+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');
@@ -516,13 +524,21 @@ CREATE INDEX ls_log_id ON log_search (ls_log_id);
CREATE SEQUENCE job_job_id_seq;
CREATE TABLE job (
- job_id INTEGER NOT NULL PRIMARY KEY DEFAULT nextval('job_job_id_seq'),
- job_cmd TEXT NOT NULL,
- job_namespace SMALLINT NOT NULL,
- job_title TEXT NOT NULL,
- job_timestamp TIMESTAMPTZ,
- job_params TEXT NOT NULL
-);
+ job_id INTEGER NOT NULL PRIMARY KEY DEFAULT nextval('job_job_id_seq'),
+ job_cmd TEXT NOT NULL,
+ job_namespace SMALLINT NOT NULL,
+ job_title TEXT NOT NULL,
+ job_timestamp TIMESTAMPTZ,
+ job_params TEXT NOT NULL,
+ job_random INTEGER NOT NULL DEFAULT 0,
+ job_attempts INTEGER NOT NULL DEFAULT 0,
+ job_token TEXT NOT NULL DEFAULT '',
+ job_token_timestamp TIMESTAMPTZ,
+ job_sha1 TEXT NOT NULL DEFAULT ''
+);
+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);
CREATE INDEX job_cmd_namespace_title ON job (job_cmd, job_namespace, job_title);
CREATE INDEX job_timestamp_idx ON job (job_timestamp);
@@ -684,3 +700,35 @@ CREATE TABLE module_deps (
md_deps TEXT NOT NULL
);
CREATE UNIQUE INDEX md_module_skin ON module_deps (md_module, md_skin);
+
+CREATE SEQUENCE sites_site_id_seq;
+CREATE TABLE sites (
+ site_id INTEGER NOT NULL PRIMARY KEY DEFAULT nextval('sites_site_id_seq'),
+ site_global_key TEXT NOT NULL,
+ site_type TEXT NOT NULL,
+ site_group TEXT NOT NULL,
+ site_source TEXT NOT NULL,
+ site_language TEXT NOT NULL,
+ site_protocol TEXT NOT NULL,
+ site_domain TEXT NOT NULL,
+ site_data TEXT NOT NULL,
+ site_forward SMALLINT NOT NULL,
+ site_config TEXT NOT NULL
+);
+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);
+CREATE INDEX site_source ON sites (site_source);
+CREATE INDEX site_language ON sites (site_language);
+CREATE INDEX site_protocol ON sites (site_protocol);
+CREATE INDEX site_domain ON sites (site_domain);
+CREATE INDEX site_forward ON sites (site_forward);
+
+CREATE TABLE site_identifiers (
+ si_site INTEGER NOT NULL,
+ si_type TEXT NOT NULL,
+ si_key TEXT NOT NULL
+);
+CREATE UNIQUE INDEX si_type_key ON site_identifiers (si_type, si_key);
+CREATE INDEX si_site ON site_identifiers (si_site);
+CREATE INDEX si_key ON site_identifiers (si_key);
diff --git a/maintenance/preprocessDump.php b/maintenance/preprocessDump.php
index 5952fd96..bb3d68b0 100644
--- a/maintenance/preprocessDump.php
+++ b/maintenance/preprocessDump.php
@@ -78,8 +78,14 @@ class PreprocessDump extends DumpIterator {
* @param $rev Revision
*/
public function processRevision( $rev ) {
+ $content = $rev->getContent( Revision::RAW );
+
+ if ( $content->getModel() !== CONTENT_MODEL_WIKITEXT ) {
+ return;
+ }
+
try {
- $this->mPreprocessor->preprocessToObj( $rev->getText(), 0 );
+ $this->mPreprocessor->preprocessToObj( strval( $content->getNativeData() ), 0 );
}
catch(Exception $e) {
$this->error("Caught exception " . $e->getMessage() . " in " . $rev->getTitle()->getPrefixedText() );
@@ -89,4 +95,3 @@ class PreprocessDump extends DumpIterator {
$maintClass = "PreprocessDump";
require_once( RUN_MAINTENANCE_IF_MAIN );
-
diff --git a/maintenance/preprocessorFuzzTest.php b/maintenance/preprocessorFuzzTest.php
index a53bc88c..49c7aee3 100644
--- a/maintenance/preprocessorFuzzTest.php
+++ b/maintenance/preprocessorFuzzTest.php
@@ -26,7 +26,7 @@ require_once( __DIR__ . '/commandLine.inc' );
$wgHooks['BeforeParserFetchTemplateAndtitle'][] = 'PPFuzzTester::templateHook';
class PPFuzzTester {
- var $hairs = array(
+ public $hairs = array(
'[[', ']]', '{{', '{{', '}}', '}}', '{{{', '}}}',
'<', '>', '<nowiki', '<gallery', '</nowiki>', '</gallery>', '<nOwIkI>', '</NoWiKi>',
'<!--' , '-->',
@@ -39,12 +39,12 @@ class PPFuzzTester {
// extensions
// '<ref>', '</ref>', '<references/>',
);
- var $minLength = 0;
- var $maxLength = 20;
- var $maxTemplates = 5;
- // var $outputTypes = array( 'OT_HTML', 'OT_WIKI', 'OT_PREPROCESS' );
- var $entryPoints = array( 'testSrvus', 'testPst', 'testPreprocess' );
- var $verbose = false;
+ public $minLength = 0;
+ public $maxLength = 20;
+ public $maxTemplates = 5;
+ // public $outputTypes = array( 'OT_HTML', 'OT_WIKI', 'OT_PREPROCESS' );
+ public $entryPoints = array( 'testSrvus', 'testPst', 'testPreprocess' );
+ public $verbose = false;
static $currentTest = false;
function execute() {
@@ -140,7 +140,7 @@ class PPFuzzTester {
}
class PPFuzzTest {
- var $templates, $mainText, $title, $entryPoint, $output;
+ public $templates, $mainText, $title, $entryPoint, $output;
function __construct( $tester ) {
global $wgMaxSigChars;
@@ -219,7 +219,7 @@ class PPFuzzTest {
}
class PPFuzzUser extends User {
- var $ppfz_test, $mDataLoaded;
+ public $ppfz_test, $mDataLoaded;
function load() {
if ( $this->mDataLoaded ) {
diff --git a/maintenance/protect.php b/maintenance/protect.php
index 2f6aa1ae..ff13bd6e 100644
--- a/maintenance/protect.php
+++ b/maintenance/protect.php
@@ -58,6 +58,7 @@ class Protect extends Maintenance {
$this->error( "Invalid username", true );
}
+ // @todo FIXME: This is reset 7 lines down.
$restrictions = array( 'edit' => $protection, 'move' => $protection );
$t = Title::newFromText( $this->getArg() );
diff --git a/maintenance/proxy_check.php b/maintenance/proxyCheck.php
index 10892c42..2ccf703e 100644
--- a/maintenance/proxy_check.php
+++ b/maintenance/proxyCheck.php
@@ -21,7 +21,7 @@
* @ingroup Maintenance
*/
-if( php_sapi_name() != 'cli' ) {
+if( PHP_SAPI != 'cli' ) {
die( 1 );
}
diff --git a/maintenance/purgeList.php b/maintenance/purgeList.php
index 4b3c3821..b72c417e 100644
--- a/maintenance/purgeList.php
+++ b/maintenance/purgeList.php
@@ -32,22 +32,27 @@ class PurgeList extends Maintenance {
public function __construct() {
parent::__construct();
$this->mDescription = "Send purge requests for listed pages to squid";
- $this->addOption( 'purge', 'Whether to update page_touched.' , false, false );
+ $this->addOption( 'purge', 'Whether to update page_touched.', false, false );
$this->addOption( 'namespace', 'Namespace number', false, true );
+ $this->addOption( 'all', 'Purge all pages', false, false );
+ $this->addOption( 'delay', 'Number of seconds to delay between each purge', false, true );
+ $this->addOption( 'verbose', 'Show more output', false, false, 'v' );
$this->setBatchSize( 100 );
}
public function execute() {
- if( $this->hasOption( 'namespace' ) ) {
- $this->purgeNamespace();
+ if ( $this->hasOption( 'all' ) ) {
+ $this->purgeNamespace( false );
+ } elseif ( $this->hasOption( 'namespace' ) ) {
+ $this->purgeNamespace( intval( $this->getOption( 'namespace') ) );
} else {
- $this->purgeList();
+ $this->doPurge();
}
$this->output( "Done!\n" );
}
/** Purge URL coming from stdin */
- private function purgeList() {
+ private function doPurge() {
$stdin = $this->getStdin();
$urls = array();
@@ -69,56 +74,41 @@ class PurgeList extends Maintenance {
}
}
}
+ $this->output( "Purging " . count( $urls ). " urls\n" );
$this->sendPurgeRequest( $urls );
}
- /** Purge a namespace given by --namespace */
- private function purgeNamespace() {
+ /** Purge a namespace or all pages */
+ private function purgeNamespace( $namespace = false ) {
$dbr = wfGetDB( DB_SLAVE );
- $ns = $dbr->addQuotes( $this->getOption( 'namespace') );
-
- $result = $dbr->select(
- array( 'page' ),
- array( 'page_namespace', 'page_title' ),
- array( "page_namespace = $ns" ),
- __METHOD__,
- array( 'ORDER BY' => 'page_id' )
- );
-
- $start = 0;
- $end = $dbr->numRows( $result );
- $this->output( "Will purge $end pages from namespace $ns\n" );
-
- # Do remaining chunk
- $end += $this->mBatchSize - 1;
- $blockStart = $start;
- $blockEnd = $start + $this->mBatchSize - 1;
-
- while( $blockEnd <= $end ) {
- # Select pages we will purge:
- $result = $dbr->select(
- array( 'page' ),
- array( 'page_namespace', 'page_title' ),
- array( "page_namespace = $ns" ),
+ $startId = 0;
+ if ( $namespace === false ) {
+ $conds = array();
+ } else {
+ $conds = array( 'page_namespace' => $namespace );
+ }
+ while ( true ) {
+ $res = $dbr->select( 'page',
+ array( 'page_id', 'page_namespace', 'page_title' ),
+ $conds + array( 'page_id > ' . $dbr->addQuotes( $startId ) ),
__METHOD__,
- array( # conditions
- 'ORDER BY' => 'page_id',
- 'LIMIT' => $this->mBatchSize,
- 'OFFSET' => $blockStart,
+ array(
+ 'LIMIT' => $this->mBatchSize,
+ 'ORDER BY' => 'page_id'
+
)
);
- # Initialize/reset URLs to be purged
+ if ( !$res->numRows() ) {
+ break;
+ }
$urls = array();
- foreach( $result as $row ) {
+ foreach ( $res as $row ) {
$title = Title::makeTitle( $row->page_namespace, $row->page_title );
$url = $title->getInternalUrl();
$urls[] = $url;
+ $startId = $row->page_id;
}
-
$this->sendPurgeRequest( $urls );
-
- $blockStart += $this->mBatchSize;
- $blockEnd += $this->mBatchSize;
}
}
@@ -127,9 +117,23 @@ class PurgeList extends Maintenance {
* @param $urls array List of URLS to purge from squids
*/
private function sendPurgeRequest( $urls ) {
- $this->output( "Purging " . count( $urls ). " urls\n" );
- $u = new SquidUpdate( $urls );
- $u->doUpdate();
+ if ( $this->hasOption( 'delay' ) ) {
+ $delay = floatval( $this->getOption( 'delay' ) );
+ foreach ( $urls as $url ) {
+ if ( $this->hasOption( 'verbose' ) ) {
+ $this->output( $url . "\n" );
+ }
+ $u = new SquidUpdate( array( $url ) );
+ $u->doUpdate();
+ usleep( $delay * 1e6 );
+ }
+ } else {
+ if ( $this->hasOption( 'verbose' ) ) {
+ $this->output( implode( "\n", $urls ) . "\n" );
+ }
+ $u = new SquidUpdate( $urls );
+ $u->doUpdate();
+ }
}
}
diff --git a/maintenance/purgeParserCache.php b/maintenance/purgeParserCache.php
index 1c417980..e21dd176 100644
--- a/maintenance/purgeParserCache.php
+++ b/maintenance/purgeParserCache.php
@@ -30,7 +30,7 @@ require( __DIR__ . '/Maintenance.php' );
* @ingroup Maintenance
*/
class PurgeParserCache extends Maintenance {
- var $lastProgress;
+ public $lastProgress;
function __construct() {
parent::__construct();
@@ -52,21 +52,19 @@ class PurgeParserCache extends Maintenance {
global $wgParserCacheExpireTime;
$date = wfTimestamp( TS_MW, time() + $wgParserCacheExpireTime - intval( $inputAge ) );
} else {
- echo "Must specify either --expiredate or --age\n";
- exit( 1 );
+ $this->error( "Must specify either --expiredate or --age", 1 );
}
$english = Language::factory( 'en' );
- echo "Deleting objects expiring before " . $english->timeanddate( $date ) . "\n";
+ $this->output( "Deleting objects expiring before " . $english->timeanddate( $date ) . "\n" );
$pc = wfGetParserCacheStorage();
$success = $pc->deleteObjectsExpiringBefore( $date, array( $this, 'showProgress' ) );
if ( !$success ) {
- echo "\nCannot purge this kind of parser cache.\n";
- exit( 1 );
+ $this->error( "\nCannot purge this kind of parser cache.", 1 );
}
$this->showProgress( 100 );
- echo "\nDone\n";
+ $this->output( "\nDone\n" );
}
function showProgress( $percent ) {
@@ -77,8 +75,8 @@ class PurgeParserCache extends Maintenance {
$this->lastProgress = $percentString;
$stars = floor( $percent / 2 );
- echo '[' . str_repeat( '*', $stars ), str_repeat( '.', 50 - $stars ) . '] ' .
- "$percentString%\r";
+ $this->output( '[' . str_repeat( '*', $stars ) . str_repeat( '.', 50 - $stars ) . '] ' .
+ "$percentString%\r" );
}
}
diff --git a/maintenance/reassignEdits.php b/maintenance/reassignEdits.php
index a91abf93..2d79f363 100644
--- a/maintenance/reassignEdits.php
+++ b/maintenance/reassignEdits.php
@@ -180,4 +180,3 @@ class ReassignEdits extends Maintenance {
$maintClass = "ReassignEdits";
require_once( RUN_MAINTENANCE_IF_MAIN );
-
diff --git a/maintenance/rebuildLocalisationCache.php b/maintenance/rebuildLocalisationCache.php
index 83849de6..db77564b 100644
--- a/maintenance/rebuildLocalisationCache.php
+++ b/maintenance/rebuildLocalisationCache.php
@@ -53,6 +53,15 @@ class RebuildLocalisationCache extends Maintenance {
return '1000M';
}
+ public function finalSetup() {
+ # This script needs to be run to build the inital l10n cache. But if
+ # $wgLanguageCode is not 'en', it won't be able to run because there is
+ # no l10n cache. Break the cycle by forcing $wgLanguageCode = 'en'.
+ global $wgLanguageCode;
+ $wgLanguageCode = 'en';
+ return parent::finalSetup();
+ }
+
public function execute() {
global $wgLocalisationCacheConf;
diff --git a/maintenance/rebuildrecentchanges.php b/maintenance/rebuildrecentchanges.php
index 0278f72c..bfaaab54 100644
--- a/maintenance/rebuildrecentchanges.php
+++ b/maintenance/rebuildrecentchanges.php
@@ -218,24 +218,17 @@ class RebuildRecentchanges extends Maintenance {
* DOCUMENT ME!
*/
private function rebuildRecentChangesTablePass4() {
- global $wgGroupPermissions, $wgUseRCPatrol;
+ global $wgUseRCPatrol;
$dbw = wfGetDB( DB_MASTER );
list( $recentchanges, $usergroups, $user ) = $dbw->tableNamesN( 'recentchanges', 'user_groups', 'user' );
- $botgroups = $autopatrolgroups = array();
- foreach ( $wgGroupPermissions as $group => $rights ) {
- if ( isset( $rights['bot'] ) && $rights['bot'] ) {
- $botgroups[] = $dbw->addQuotes( $group );
- }
- if ( $wgUseRCPatrol && isset( $rights['autopatrol'] ) && $rights['autopatrol'] ) {
- $autopatrolgroups[] = $dbw->addQuotes( $group );
- }
- }
+ $botgroups = User::getGroupsWithPermission( 'bot' );
+ $autopatrolgroups = $wgUseRCPatrol ? User::getGroupsWithPermission( 'autopatrol' ) : array();
# Flag our recent bot edits
if ( !empty( $botgroups ) ) {
- $botwhere = implode( ',', $botgroups );
+ $botwhere = $dbw->makeList( $botgroups );
$botusers = array();
$this->output( "Flagging bot account edits...\n" );
@@ -259,7 +252,7 @@ class RebuildRecentchanges extends Maintenance {
global $wgMiserMode;
# Flag our recent autopatrolled edits
if ( !$wgMiserMode && !empty( $autopatrolgroups ) ) {
- $patrolwhere = implode( ',', $autopatrolgroups );
+ $patrolwhere = $dbw->makeList( $autopatrolgroups );
$patrolusers = array();
$this->output( "Flagging auto-patrolled edits...\n" );
diff --git a/maintenance/rebuildtextindex.php b/maintenance/rebuildtextindex.php
index 41b245f8..534b7ca1 100644
--- a/maintenance/rebuildtextindex.php
+++ b/maintenance/rebuildtextindex.php
@@ -92,22 +92,37 @@ class RebuildTextIndex extends Maintenance {
$this->output( "Rebuilding index fields for {$count} pages...\n" );
$n = 0;
+ $fields = array_merge(
+ Revision::selectPageFields(),
+ Revision::selectFields(),
+ Revision::selectTextFields()
+ );
+
while ( $n < $count ) {
if ( $n ) {
$this->output( $n . "\n" );
}
$end = $n + self::RTI_CHUNK_SIZE - 1;
- $res = $this->db->select( array( 'page', 'revision', 'text' ),
- array( 'page_id', 'page_namespace', 'page_title', 'old_flags', 'old_text' ),
+ $res = $this->db->select( array( 'page', 'revision', 'text' ), $fields,
array( "page_id BETWEEN $n AND $end", 'page_latest = rev_id', 'rev_text_id = old_id' ),
__METHOD__
- );
+ );
foreach ( $res as $s ) {
- $revtext = Revision::getRevisionText( $s );
- $u = new SearchUpdate( $s->page_id, $s->page_title, $revtext );
- $u->doUpdate();
+ try {
+ $title = Title::makeTitle( $s->page_namespace, $s->page_title );
+
+ $rev = new Revision( $s );
+ $content = $rev->getContent();
+ $text = $content->getTextForSearchIndex();
+
+ $u = new SearchUpdate( $s->page_id, $title, $text );
+ $u->doUpdate();
+ } catch ( MWContentSerializationException $ex ) {
+ $this->output( "Failed to deserialize content of revision {$s->rev_id} of page "
+ . "`" . $title->getPrefixedDBkey() . "`!\n" );
+ }
}
$n += self::RTI_CHUNK_SIZE;
}
diff --git a/maintenance/refreshFileHeaders.php b/maintenance/refreshFileHeaders.php
new file mode 100644
index 00000000..74f0f35d
--- /dev/null
+++ b/maintenance/refreshFileHeaders.php
@@ -0,0 +1,93 @@
+<?php
+/**
+ * Refresh file headers from metadata.
+ *
+ * Usage: php refreshFileHeaders.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
+ * @author Aaron Schulz
+ * @ingroup Maintenance
+ */
+
+require_once( __DIR__ . '/Maintenance.php' );
+
+/**
+ * Maintenance script to refresh file headers from metadata
+ *
+ * @ingroup Maintenance
+ */
+class RefreshFileHeaders extends Maintenance {
+ function __construct() {
+ parent::__construct();
+ $this->mDescription = 'Script to update file HTTP headers';
+ $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->setBatchSize( 200 );
+ }
+
+ public function execute() {
+ $repo = RepoGroup::singleton()->getLocalRepo();
+ $start = str_replace( ' ', '_', $this->getOption( 'start', '' ) ); // page on img_name
+ $end = str_replace( ' ', '_', $this->getOption( 'end', '' ) ); // page on img_name
+
+ $count = 0;
+ $dbr = wfGetDB( DB_SLAVE );
+ do {
+ $conds = array( "img_name > {$dbr->addQuotes( $start )}" );
+ if ( strlen( $end ) ) {
+ $conds[] = "img_name <= {$dbr->addQuotes( $end )}";
+ }
+ $res = $dbr->select( 'image', '*', $conds,
+ __METHOD__, array( 'LIMIT' => $this->mBatchSize, 'ORDER BY' => 'img_name ASC' ) );
+ foreach ( $res as $row ) {
+ $file = $repo->newFileFromRow( $row );
+ $headers = $file->getStreamHeaders();
+ if ( count( $headers ) ) {
+ $this->updateFileHeaders( $file, $headers );
+ }
+ // Do all of the older file versions...
+ foreach ( $file->getHistory() as $oldFile ) {
+ $headers = $oldFile->getStreamHeaders();
+ if ( count( $headers ) ) {
+ $this->updateFileHeaders( $oldFile, $headers );
+ }
+ }
+ if ( $this->hasOption( 'verbose' ) ) {
+ $this->output( "Updated headers for file '{$row->img_name}'.\n" );
+ }
+ ++$count;
+ $start = $row->img_name; // advance
+ }
+ } while ( $res->numRows() > 0 );
+
+ $this->output( "Done. Updated headers for $count file(s).\n" );
+ }
+
+ protected function updateFileHeaders( File $file, array $headers ) {
+ $status = $file->getRepo()->getBackend()->describe( array(
+ 'src' => $file->getPath(), 'headers' => $headers
+ ) );
+ if ( !$status->isGood() ) {
+ $this->error( "Encountered error: " . print_r( $status, true ) );
+ }
+ }
+}
+
+$maintClass = 'RefreshFileHeaders';
+require_once( RUN_MAINTENANCE_IF_MAIN );
diff --git a/maintenance/refreshImageMetadata.php b/maintenance/refreshImageMetadata.php
index 12da7a8b..55f5b4aa 100644
--- a/maintenance/refreshImageMetadata.php
+++ b/maintenance/refreshImageMetadata.php
@@ -53,7 +53,7 @@ class RefreshImageMetadata extends Maintenance {
$this->addOption( 'start', 'Name of file to start with', false, true );
$this->addOption( 'end', 'Name of file to end with', false, true );
- $this->addOption( 'mime', '(Inefficient!) Only refresh files with this mime type. Can accept wild-card image/*' , false, true );
+ $this->addOption( 'mime', '(Inefficient!) Only refresh files with this mime type. Can accept wild-card image/*', false, true );
$this->addOption( 'metadata-contains', '(Inefficient!) Only refresh files where the img_metadata field contains this string. Can be used if its known a specific property was being extracted incorrectly.', false, true );
}
diff --git a/maintenance/refreshLinks.php b/maintenance/refreshLinks.php
index 3d9270b8..7b255664 100644
--- a/maintenance/refreshLinks.php
+++ b/maintenance/refreshLinks.php
@@ -105,7 +105,7 @@ class RefreshLinks extends Maintenance {
array(),
array( 'redirect' => array( "LEFT JOIN", "page_id=rd_from" ) )
);
- $num = $dbr->numRows( $res );
+ $num = $res->numRows();
$this->output( "Refreshing $num old redirects from $start...\n" );
$i = 0;
@@ -126,7 +126,7 @@ class RefreshLinks extends Maintenance {
"page_id >= $start" ),
__METHOD__
);
- $num = $dbr->numRows( $res );
+ $num = $res->numRows();
$this->output( "$num new articles...\n" );
$i = 0;
@@ -176,8 +176,16 @@ class RefreshLinks extends Maintenance {
}
/**
- * Update the redirect entry for a given page
- * @param $id int The page_id of the redirect
+ * Update the redirect entry for a given page.
+ *
+ * This methods bypasses the "redirect" table to get the redirect target,
+ * and parses the page's content to fetch it. This allows to be sure that
+ * the redirect target is up to date and valid.
+ * This is particularly useful when modifying namespaces to be sure the
+ * entry in the "redirect" table points to the correct page and not to an
+ * invalid one.
+ *
+ * @param $id int The page ID to check
*/
private function fixRedirect( $id ) {
$page = WikiPage::newFromID( $id );
@@ -191,14 +199,25 @@ class RefreshLinks extends Maintenance {
return;
}
- $rt = $page->getRedirectTarget();
+ $rt = null;
+ $content = $page->getContent( Revision::RAW );
+ if ( $content !== null ) {
+ $rt = $content->getUltimateRedirectTarget();
+ }
if ( $rt === null ) {
// The page is not a redirect
// Delete any redirect table entry for it
- $dbw->delete( 'redirect', array( 'rd_from' => $id ),
- __METHOD__ );
+ $dbw->delete( 'redirect', array( 'rd_from' => $id ), __METHOD__ );
+ $fieldValue = 0;
+ } else {
+ $page->insertRedirectEntry( $rt );
+ $fieldValue = 1;
}
+
+ // Update the page table to be sure it is an a consistent state
+ $dbw->update( 'page', array( 'page_is_redirect' => $fieldValue ),
+ array( 'page_id' => $id ), __METHOD__ );
}
/**
@@ -206,8 +225,6 @@ class RefreshLinks extends Maintenance {
* @param $id int The page_id
*/
public static function fixLinksFromArticle( $id ) {
- global $wgParser, $wgContLang;
-
$page = WikiPage::newFromID( $id );
LinkCache::singleton()->clear();
@@ -216,18 +233,16 @@ class RefreshLinks extends Maintenance {
return;
}
- $text = $page->getRawText();
- if ( $text === false ) {
+ $content = $page->getContent( Revision::RAW );
+ if ( $content === null ) {
return;
}
$dbw = wfGetDB( DB_MASTER );
$dbw->begin( __METHOD__ );
- $options = ParserOptions::newFromUserAndLang( new User, $wgContLang );
- $parserOutput = $wgParser->parse( $text, $page->getTitle(), $options, true, true, $page->getLatest() );
- $update = new LinksUpdate( $page->getTitle(), $parserOutput, false );
- $update->doUpdate();
+ $updates = $content->getSecondaryDataUpdates( $page->getTitle() );
+ DataUpdate::runUpdates( $updates );
$dbw->commit( __METHOD__ );
}
diff --git a/maintenance/removeUnusedAccounts.php b/maintenance/removeUnusedAccounts.php
index 8bc27c18..b4528ca0 100644
--- a/maintenance/removeUnusedAccounts.php
+++ b/maintenance/removeUnusedAccounts.php
@@ -77,6 +77,8 @@ class RemoveUnusedAccounts extends Maintenance {
$this->output( "\nDeleting inactive accounts..." );
$dbw = wfGetDB( DB_MASTER );
$dbw->delete( 'user', array( 'user_id' => $del ), __METHOD__ );
+ $dbw->delete( 'logging', array( 'log_user' => $del ), __METHOD__ );
+ $dbw->delete( 'recentchanges', array( 'rc_user' => $del ), __METHOD__ );
$this->output( "done.\n" );
# Update the site_stats.ss_users field
$users = $dbw->selectField( 'user', 'COUNT(*)', array(), __METHOD__ );
@@ -97,8 +99,13 @@ class RemoveUnusedAccounts extends Maintenance {
*/
private function isInactiveAccount( $id, $master = false ) {
$dbo = wfGetDB( $master ? DB_MASTER : DB_SLAVE );
- $checks = array( 'revision' => 'rev', 'archive' => 'ar', 'logging' => 'log',
- 'image' => 'img', 'oldimage' => 'oi', 'filearchive' => 'fa' );
+ $checks = array(
+ 'revision' => 'rev',
+ 'archive' => 'ar',
+ 'image' => 'img',
+ 'oldimage' => 'oi',
+ 'filearchive' => 'fa'
+ );
$count = 0;
$dbo->begin( __METHOD__ );
@@ -106,6 +113,10 @@ class RemoveUnusedAccounts extends Maintenance {
$conds = array( $fprefix . '_user' => $id );
$count += (int)$dbo->selectField( $table, 'COUNT(*)', $conds, __METHOD__ );
}
+
+ $conds = array( 'log_user' => $id, 'log_type != ' . $dbo->addQuotes( 'newusers' ) );
+ $count += (int)$dbo->selectField( 'logging', 'COUNT(*)', $conds, __METHOD__ );
+
$dbo->commit( __METHOD__ );
return $count == 0;
diff --git a/maintenance/renderDump.php b/maintenance/renderDump.php
index 24bedfa4..2ba2b3dc 100644
--- a/maintenance/renderDump.php
+++ b/maintenance/renderDump.php
@@ -80,8 +80,6 @@ class DumpRenderer extends Maintenance {
* @param $rev Revision
*/
public function handleRevision( $rev ) {
- global $wgParserConf;
-
$title = $rev->getTitle();
if ( !$title ) {
$this->error( "Got bogus revision with null title!" );
@@ -100,10 +98,10 @@ class DumpRenderer extends Maintenance {
$this->output( sprintf( "%s\n", $filename, $display ) );
$user = new User();
- $parser = new $wgParserConf['class']();
$options = ParserOptions::newFromUser( $user );
- $output = $parser->parse( $rev->getText(), $title, $options );
+ $content = $rev->getContent();
+ $output = $content->getParserOutput( $title, null, $options );
file_put_contents( $filename,
"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" " .
diff --git a/maintenance/runJobs.php b/maintenance/runJobs.php
index e909bc06..b1be714c 100644
--- a/maintenance/runJobs.php
+++ b/maintenance/runJobs.php
@@ -52,6 +52,11 @@ class RunJobs extends Maintenance {
public function execute() {
global $wgTitle;
+
+ if ( wfReadOnly() ) {
+ $this->error( "Unable to run jobs; the wiki is in read-only mode.", 1 ); // die
+ }
+
if ( $this->hasOption( 'procs' ) ) {
$procs = intval( $this->getOption( 'procs' ) );
if ( $procs < 1 || $procs > 1000 ) {
@@ -68,44 +73,64 @@ class RunJobs extends Maintenance {
$type = $this->getOption( 'type', false );
$wgTitle = Title::newFromText( 'RunJobs.php' );
$dbw = wfGetDB( DB_MASTER );
- $n = 0;
+ $jobsRun = 0; // counter
- if ( $type === false ) {
- $conds = Job::defaultQueueConditions( );
- } else {
- $conds = array( 'job_cmd' => $type );
+ $group = JobQueueGroup::singleton();
+ // Handle any required periodic queue maintenance
+ $count = $group->executeReadyPeriodicTasks();
+ if ( $count > 0 ) {
+ $this->runJobsLog( "Executed $count periodic queue task(s)." );
}
- while ( $dbw->selectField( 'job', 'job_id', $conds, 'runJobs.php' ) ) {
- $offset = 0;
- for ( ; ; ) {
- $job = !$type ? Job::pop( $offset ) : Job::pop_type( $type );
+ $lastTime = time();
+ do {
+ $job = ( $type === false )
+ ? $group->pop( JobQueueGroup::TYPE_DEFAULT, JobQueueGroup::USE_CACHE )
+ : $group->pop( $type ); // job from a single queue
+ if ( $job ) { // found a job
+ ++$jobsRun;
+ $this->runJobsLog( $job->toString() . " STARTING" );
- if ( !$job ) {
- break;
+ // Run the job...
+ $t = microtime( true );
+ try {
+ $status = $job->run();
+ $error = $job->getLastError();
+ } catch ( MWException $e ) {
+ $status = false;
+ $error = get_class( $e ) . ': ' . $e->getMessage();
+ }
+ $timeMs = intval( ( microtime( true ) - $t ) * 1000 );
+
+ // Mark the job as done on success or when the job cannot be retried
+ if ( $status !== false || !$job->allowRetries() ) {
+ $group->ack( $job ); // done
}
- wfWaitForSlaves();
- $t = microtime( true );
- $offset = $job->id;
- $this->runJobsLog( $job->toString() . " STARTING" );
- $status = $job->run();
- $t = microtime( true ) - $t;
- $timeMs = intval( $t * 1000 );
if ( !$status ) {
- $this->runJobsLog( $job->toString() . " t=$timeMs error={$job->error}" );
+ $this->runJobsLog( $job->toString() . " t=$timeMs error={$error}" );
} else {
$this->runJobsLog( $job->toString() . " t=$timeMs good" );
}
- if ( $maxJobs && ++$n > $maxJobs ) {
- break 2;
+ // Break out if we hit the job count or wall time limits...
+ if ( $maxJobs && $jobsRun >= $maxJobs ) {
+ break;
+ } elseif ( $maxTime && ( time() - $startTime ) > $maxTime ) {
+ break;
}
- if ( $maxTime && time() - $startTime > $maxTime ) {
- break 2;
+
+ // Don't let any of the main DB slaves get backed up
+ $timePassed = time() - $lastTime;
+ if ( $timePassed >= 5 || $timePassed < 0 ) {
+ wfWaitForSlaves();
+ }
+ // Don't let any queue slaves/backups fall behind
+ if ( $jobsRun > 0 && ( $jobsRun % 100 ) == 0 ) {
+ $group->waitForBackups();
}
}
- }
+ } while ( $job ); // stop when there are no jobs
}
/**
diff --git a/maintenance/stats.php b/maintenance/showCacheStats.php
index be448f99..8f238680 100644
--- a/maintenance/stats.php
+++ b/maintenance/showCacheStats.php
@@ -28,7 +28,7 @@ require_once( __DIR__ . '/Maintenance.php' );
*
* @ingroup Maintenance
*/
-class CacheStats extends Maintenance {
+class ShowCacheStats extends Maintenance {
public function __construct() {
$this->mDescription = "Show statistics from the cache";
@@ -102,5 +102,5 @@ class CacheStats extends Maintenance {
}
}
-$maintClass = "CacheStats";
+$maintClass = "ShowCacheStats";
require_once( RUN_MAINTENANCE_IF_MAIN );
diff --git a/maintenance/showJobs.php b/maintenance/showJobs.php
index 1dceb790..8b49517f 100644
--- a/maintenance/showJobs.php
+++ b/maintenance/showJobs.php
@@ -39,21 +39,24 @@ class ShowJobs extends Maintenance {
$this->mDescription = "Show number of jobs waiting in master database";
$this->addOption( 'group', 'Show number of jobs per job type' );
}
+
public function execute() {
- $dbw = wfGetDB( DB_MASTER );
+ $group = JobQueueGroup::singleton();
if ( $this->hasOption( 'group' ) ) {
- $res = $dbw->select(
- 'job',
- array( 'job_cmd', 'count(*) as count' ),
- array(),
- __METHOD__,
- array( 'GROUP BY' => 'job_cmd' )
- );
- foreach ( $res as $row ) {
- $this->output( $row->job_cmd . ': ' . $row->count . "\n" );
+ foreach ( $group->getQueueTypes() as $type ) {
+ $queue = $group->get( $type );
+ $pending = $queue->getSize();
+ $claimed = $queue->getAcquiredCount();
+ if ( ( $pending + $claimed ) > 0 ) {
+ $this->output( "{$type}: $pending queued; $claimed acquired\n" );
+ }
}
} else {
- $this->output( $dbw->selectField( 'job', 'count(*)', '', __METHOD__ ) . "\n" );
+ $count = 0;
+ foreach ( $group->getQueueTypes() as $type ) {
+ $count += $group->get( $type )->getSize();
+ }
+ $this->output( "$count\n" );
}
}
}
diff --git a/maintenance/showStats.php b/maintenance/showSiteStats.php
index 982c7cbb..e7359b2f 100644
--- a/maintenance/showStats.php
+++ b/maintenance/showSiteStats.php
@@ -22,7 +22,7 @@
* @file
* @ingroup Maintenance
* @author Antoine Musso <hashar at free dot fr>
- * Based on initStats.php by:
+ * Based on initSiteStats.php by:
* @author Brion Vibber
* @author Rob Church <robchur@gmail.com>
*
@@ -36,7 +36,7 @@ require_once( __DIR__ . '/Maintenance.php' );
*
* @ingroup Maintenance
*/
-class ShowStats extends Maintenance {
+class ShowSiteStats extends Maintenance {
public function __construct() {
parent::__construct();
$this->mDescription = "Show the cached statistics";
@@ -59,7 +59,7 @@ class ShowStats extends Maintenance {
$max_length_value = $max_length_desc = 0;
foreach ( $fields as $field => $desc ) {
$max_length_value = max( $max_length_value, strlen( $stats->$field ) );
- $max_length_desc = max( $max_length_desc , strlen( $desc ) ) ;
+ $max_length_desc = max( $max_length_desc, strlen( $desc ) ) ;
}
// Show them
@@ -69,6 +69,5 @@ class ShowStats extends Maintenance {
}
}
-$maintClass = "ShowStats";
+$maintClass = "ShowSiteStats";
require_once( RUN_MAINTENANCE_IF_MAIN );
-
diff --git a/maintenance/sql.php b/maintenance/sql.php
index 04e98d91..11699909 100644
--- a/maintenance/sql.php
+++ b/maintenance/sql.php
@@ -33,13 +33,19 @@ class MwSql extends Maintenance {
public function __construct() {
parent::__construct();
$this->mDescription = "Send SQL queries to a MediaWiki database";
+ $this->addOption( 'cluster', 'Use an external cluster by name', false, true );
}
public function execute() {
- $dbw = wfGetDB( DB_MASTER );
- if ( $this->hasArg() ) {
- $fileName = $this->getArg();
- $file = fopen( $fileName, 'r' );
+ // Get a DB handle (with this wiki's DB select) from the appropriate load balancer
+ if ( $this->hasOption( 'cluster' ) ) {
+ $lb = wfGetLBFactory()->getExternalLB( $this->getOption( 'cluster' ) );
+ $dbw = $lb->getConnection( DB_MASTER ); // master for external LB
+ } else {
+ $dbw = wfGetDB( DB_MASTER ); // master for primary LB for this wiki
+ }
+ if ( $this->hasArg( 0 ) ) {
+ $file = fopen( $this->getArg( 0 ), 'r' );
if ( !$file ) {
$this->error( "Unable to open input file", true );
}
@@ -63,26 +69,39 @@ class MwSql extends Maintenance {
}
$wholeLine = '';
- while ( ( $line = Maintenance::readconsole() ) !== false ) {
+ $newPrompt = '> ';
+ $prompt = $newPrompt;
+ while ( ( $line = Maintenance::readconsole( $prompt ) ) !== false ) {
+ if( !$line ) {
+ # User simply pressed return key
+ continue;
+ }
$done = $dbw->streamStatementEnd( $wholeLine, $line );
$wholeLine .= $line;
if ( !$done ) {
+ $wholeLine .= ' ';
+ $prompt = ' -> ';
continue;
}
if ( $useReadline ) {
- readline_add_history( $wholeLine );
+ # Delimiter is eated by streamStatementEnd, we add it
+ # up in the history (bug 37020)
+ readline_add_history( $wholeLine . $dbw->getDelimiter() );
readline_write_history( $historyFile );
}
try{
$res = $dbw->query( $wholeLine );
$this->sqlPrintResult( $res, $dbw );
+ $prompt = $newPrompt;
$wholeLine = '';
} catch (DBQueryError $e) {
- $this->error( $e, true );
+ $doDie = ! Maintenance::posix_isatty( 0 );
+ $this->error( $e, $doDie );
}
}
+ wfWaitForSlaves();
}
/**
@@ -93,6 +112,7 @@ class MwSql extends Maintenance {
public function sqlPrintResult( $res, $db ) {
if ( !$res ) {
// Do nothing
+ return;
} elseif ( is_object( $res ) && $res->numRows() ) {
foreach ( $res as $row ) {
$this->output( print_r( $row, true ) );
diff --git a/maintenance/sqlite.inc b/maintenance/sqlite.inc
index a8a1fce6..16568ac7 100644
--- a/maintenance/sqlite.inc
+++ b/maintenance/sqlite.inc
@@ -43,6 +43,8 @@ class Sqlite {
* Checks given files for correctness of SQL syntax. MySQL DDL will be converted to
* SQLite-compatible during processing.
* Will throw exceptions on SQL errors
+ * @param $files
+ * @throws MWException
* @return mixed true if no error or error string in case of errors
*/
public static function checkSqlSyntax( $files ) {
diff --git a/maintenance/sqlite/archives/patch-drop-ss_admins.sql b/maintenance/sqlite/archives/patch-drop-ss_admins.sql
new file mode 100644
index 00000000..9951e17e
--- /dev/null
+++ b/maintenance/sqlite/archives/patch-drop-ss_admins.sql
@@ -0,0 +1,22 @@
+-- field is deprecated and no longer updated as of 1.5
+CREATE TABLE /*_*/site_stats_tmp (
+ ss_row_id int unsigned NOT NULL,
+ ss_total_views bigint unsigned default 0,
+ ss_total_edits bigint unsigned default 0,
+ ss_good_articles bigint unsigned default 0,
+ ss_total_pages bigint default '-1',
+ ss_users bigint default '-1',
+ ss_active_users bigint default '-1',
+ ss_images int default 0
+) /*$wgDBTableOptions*/;
+
+INSERT INTO /*_*/site_stats_tmp
+ SELECT ss_row_id, ss_total_views, ss_total_edits, ss_good_articles,
+ ss_total_pages, ss_users, ss_active_users, ss_images
+ FROM /*_*/site_stats;
+
+DROP TABLE /*_*/site_stats;
+
+ALTER TABLE /*_*/site_stats_tmp RENAME TO /*_*/site_stats;
+
+CREATE UNIQUE INDEX /*i*/ss_row_id ON /*_*/site_stats (ss_row_id); \ No newline at end of file
diff --git a/maintenance/sqlite/archives/patch-job_token.sql b/maintenance/sqlite/archives/patch-job_token.sql
new file mode 100644
index 00000000..4e4d28fd
--- /dev/null
+++ b/maintenance/sqlite/archives/patch-job_token.sql
@@ -0,0 +1,8 @@
+ALTER TABLE /*_*/job ADD COLUMN job_random integer unsigned NOT NULL default 0;
+ALTER TABLE /*_*/job ADD COLUMN job_token varbinary(32) NOT NULL default '';
+ALTER TABLE /*_*/job ADD COLUMN job_sha1 varbinary(32) NOT NULL default '';
+ALTER TABLE /*_*/job ADD COLUMN job_token_timestamp varbinary(14) NULL default NULL;
+
+CREATE INDEX /*i*/job_sha1 ON /*_*/job (job_sha1);
+CREATE INDEX /*i*/job_cmd_token ON /*_*/job (job_cmd,job_token,job_random);
+
diff --git a/maintenance/sqlite/archives/patch-profiling.sql b/maintenance/sqlite/archives/patch-profiling.sql
new file mode 100644
index 00000000..4a07283c
--- /dev/null
+++ b/maintenance/sqlite/archives/patch-profiling.sql
@@ -0,0 +1,12 @@
+-- profiling table
+-- This is optional
+
+CREATE TABLE /*_*/profiling (
+ pf_count int NOT NULL default 0,
+ pf_time float NOT NULL default 0,
+ pf_memory float NOT NULL default 0,
+ pf_name varchar(255) NOT NULL default '',
+ pf_server varchar(30) NOT NULL default ''
+);
+
+CREATE UNIQUE INDEX /*i*/pf_name_server ON /*_*/profiling (pf_name, pf_server);
diff --git a/maintenance/sqlite/archives/patch-rc_moved.sql b/maintenance/sqlite/archives/patch-rc_moved.sql
new file mode 100644
index 00000000..70248d54
--- /dev/null
+++ b/maintenance/sqlite/archives/patch-rc_moved.sql
@@ -0,0 +1,46 @@
+-- rc_moved_to_ns and rc_moved_to_title is no longer used, delete the fields
+
+CREATE TABLE /*_*/recentchanges_tmp (
+ rc_id int NOT NULL PRIMARY KEY AUTO_INCREMENT,
+ rc_timestamp varbinary(14) NOT NULL default '',
+ rc_cur_time varbinary(14) NOT NULL default '',
+ rc_user int unsigned NOT NULL default 0,
+ rc_user_text varchar(255) binary NOT NULL,
+ rc_namespace int NOT NULL default 0,
+ rc_title varchar(255) binary NOT NULL default '',
+ rc_comment varchar(255) binary NOT NULL default '',
+ 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_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 INTO /*_*/recentchanges_tmp
+ SELECT rc_id, rc_timestamp, rc_cur_time, rc_user, rc_user_text, rc_namespace, rc_title, rc_comment,
+ rc_minor, rc_bot, rc_new, rc_cur_id, rc_this_oldid, rc_last_oldid, rc_type, 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_user_text ON /*_*/recentchanges (rc_user_text, rc_timestamp);
diff --git a/maintenance/sqlite/archives/patch-rename-iwl_prefix.sql b/maintenance/sqlite/archives/patch-rename-iwl_prefix.sql
index 851a6b37..fd4c9ec7 100644
--- a/maintenance/sqlite/archives/patch-rename-iwl_prefix.sql
+++ b/maintenance/sqlite/archives/patch-rename-iwl_prefix.sql
@@ -1,4 +1,4 @@
---
+--
-- Recreates the iwl_prefix for the iwlinks table
--
DROP INDEX IF EXISTS /*i*/iwl_prefix;
diff --git a/maintenance/sqlite/archives/patch-sites.sql b/maintenance/sqlite/archives/patch-sites.sql
new file mode 100644
index 00000000..88392748
--- /dev/null
+++ b/maintenance/sqlite/archives/patch-sites.sql
@@ -0,0 +1,71 @@
+-- Patch to add the sites and site_identifiers tables.
+-- Licence: GNU GPL v2+
+-- Author: Jeroen De Dauw < jeroendedauw@gmail.com >
+
+
+-- Holds all the sites known to the wiki.
+CREATE TABLE IF NOT EXISTS /*_*/sites (
+-- Numeric id of the site
+ site_id INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
+
+ -- Global identifier for the site, ie 'enwiktionary'
+ site_global_key varbinary(32) NOT NULL,
+
+ -- Type of the site, ie 'mediawiki'
+ site_type varbinary(32) NOT NULL,
+
+ -- Group of the site, ie 'wikipedia'
+ site_group varbinary(32) NOT NULL,
+
+ -- Source of the site data, ie 'local', 'wikidata', 'my-magical-repo'
+ site_source varbinary(32) NOT NULL,
+
+ -- Language code of the sites primary language.
+ site_language varbinary(32) NOT NULL,
+
+ -- Protocol of the site, ie 'http://', 'irc://', '//'
+ -- This field is an index for lookups and is build from type specific data in site_data.
+ site_protocol varbinary(32) NOT NULL,
+
+ -- Domain of the site in reverse order, ie 'org.mediawiki.www.'
+ -- This field is an index for lookups and is build from type specific data in site_data.
+ site_domain VARCHAR(255) NOT NULL,
+
+ -- Type dependent site data.
+ site_data BLOB NOT NULL,
+
+ -- If site.tld/path/key:pageTitle should forward users to the page on
+ -- the actual site, where "key" is the local identifier.
+ site_forward bool NOT NULL,
+
+ -- Type dependent site config.
+ -- For instance if template transclusion should be allowed if it's a MediaWiki.
+ site_config BLOB NOT NULL
+) /*$wgDBTableOptions*/;
+
+CREATE UNIQUE INDEX /*i*/sites_global_key ON /*_*/sites (site_global_key);
+CREATE INDEX /*i*/sites_type ON /*_*/sites (site_type);
+CREATE INDEX /*i*/sites_group ON /*_*/sites (site_group);
+CREATE INDEX /*i*/sites_source ON /*_*/sites (site_source);
+CREATE INDEX /*i*/sites_language ON /*_*/sites (site_language);
+CREATE INDEX /*i*/sites_protocol ON /*_*/sites (site_protocol);
+CREATE INDEX /*i*/sites_domain ON /*_*/sites (site_domain);
+CREATE INDEX /*i*/sites_forward ON /*_*/sites (site_forward);
+
+
+
+-- Links local site identifiers to their corresponding site.
+CREATE TABLE IF NOT EXISTS /*_*/site_identifiers (
+ -- Key on site.site_id
+ si_site INT UNSIGNED NOT NULL,
+
+ -- local key type, ie 'interwiki' or 'langlink'
+ si_type varbinary(32) NOT NULL,
+
+ -- local key value, ie 'en' or 'wiktionary'
+ si_key varbinary(32) NOT NULL
+) /*$wgDBTableOptions*/;
+
+CREATE UNIQUE INDEX /*i*/site_ids_type ON /*_*/site_identifiers (si_type, si_key);
+CREATE INDEX /*i*/site_ids_site ON /*_*/site_identifiers (si_site);
+CREATE INDEX /*i*/site_ids_key ON /*_*/site_identifiers (si_key); \ No newline at end of file
diff --git a/maintenance/sqlite/archives/patch-ufg_group-length-increase.sql b/maintenance/sqlite/archives/patch-ufg_group-length-increase-255.sql
index c6dcea5e..edd0a3dc 100644
--- a/maintenance/sqlite/archives/patch-ufg_group-length-increase.sql
+++ b/maintenance/sqlite/archives/patch-ufg_group-length-increase-255.sql
@@ -1,11 +1,11 @@
-CREATE TABLE /*_*/user_former_groups_tmp (
- ug_user int unsigned NOT NULL default 0,
- ug_group varbinary(32) NOT NULL default ''
+ CREATE TABLE /*_*/user_former_groups_tmp (
+ ufg_user int unsigned NOT NULL default 0,
+ ufg_group varbinary(255) NOT NULL default ''
) /*$wgDBTableOptions*/;
INSERT INTO /*_*/user_former_groups_tmp
- SELECT ug_user, ug_group
- FROM /*_*/user_groups;
+ SELECT ufg_user, ufg_group
+ FROM /*_*/user_former_groups;
DROP TABLE /*_*/user_former_groups;
diff --git a/maintenance/sqlite/archives/patch-ug_group-length-increase.sql b/maintenance/sqlite/archives/patch-ug_group-length-increase-255.sql
index 5e810937..3daeb7c6 100644
--- a/maintenance/sqlite/archives/patch-ug_group-length-increase.sql
+++ b/maintenance/sqlite/archives/patch-ug_group-length-increase-255.sql
@@ -1,6 +1,6 @@
CREATE TABLE /*_*/user_groups_tmp (
ug_user int unsigned NOT NULL default 0,
- ug_group varbinary(32) NOT NULL default ''
+ ug_group varbinary(255) NOT NULL default ''
) /*$wgDBTableOptions*/;
INSERT INTO /*_*/user_groups_tmp
diff --git a/maintenance/sqlite/archives/searchindex-fts3.sql b/maintenance/sqlite/archives/searchindex-fts3.sql
index 28554c02..2a370940 100644
--- a/maintenance/sqlite/archives/searchindex-fts3.sql
+++ b/maintenance/sqlite/archives/searchindex-fts3.sql
@@ -1,7 +1,7 @@
-- Patch that introduces fulltext search capabilities to SQLite schema
-- Requires that SQLite must be compiled with FTS3 module (comes with core amalgamation).
-- See http://sqlite.org/fts3.html for details of syntax.
--- Will fail if FTS3 is not present,
+-- Will fail if FTS3 is not present,
DROP TABLE IF EXISTS /*_*/searchindex;
CREATE VIRTUAL TABLE /*_*/searchindex USING FTS3(
-- Key to page_id
@@ -10,7 +10,7 @@ CREATE VIRTUAL TABLE /*_*/searchindex USING FTS3(
-- Munged version of title
si_title,
-
+
-- Munged version of body text
si_text
);
diff --git a/maintenance/sqlite/archives/searchindex-no-fts.sql b/maintenance/sqlite/archives/searchindex-no-fts.sql
index bc014b3d..16247ffe 100644
--- a/maintenance/sqlite/archives/searchindex-no-fts.sql
+++ b/maintenance/sqlite/archives/searchindex-no-fts.sql
@@ -17,7 +17,7 @@ CREATE TABLE /*_*/searchindex (
-- Munged version of title
si_title TEXT,
-
+
-- Munged version of body text
si_text TEXT
);
diff --git a/maintenance/storage/blobs.sql b/maintenance/storage/blobs.sql
index 623dd7bf..979e68a9 100644
--- a/maintenance/storage/blobs.sql
+++ b/maintenance/storage/blobs.sql
@@ -4,5 +4,4 @@ CREATE TABLE /*$wgDBprefix*/blobs (
blob_id integer UNSIGNED NOT NULL AUTO_INCREMENT,
blob_text longblob,
PRIMARY KEY (blob_id)
-) ENGINE=MyISAM MAX_ROWS=100000000 AVG_ROW_LENGTH=100000;
-
+) ENGINE=InnoDB;
diff --git a/maintenance/storage/checkStorage.php b/maintenance/storage/checkStorage.php
index 6c669bfa..fd9393f2 100644
--- a/maintenance/storage/checkStorage.php
+++ b/maintenance/storage/checkStorage.php
@@ -38,14 +38,16 @@ if ( !defined( 'MEDIAWIKI' ) ) {
// ----------------------------------------------------------------------------------
/**
+ * Maintenance script to do various checks on external storage.
+ *
* @ingroup Maintenance ExternalStorage
*/
class CheckStorage {
const CONCAT_HEADER = 'O:27:"concatenatedgziphistoryblob"';
- var $oldIdMap, $errors;
- var $dbStore = null;
+ public $oldIdMap, $errors;
+ public $dbStore = null;
- var $errorDescriptions = array(
+ public $errorDescriptions = array(
'restore text' => 'Damaged text, need to be restored from a backup',
'restore revision' => 'Damaged revision row, need to be restored from a backup',
'unfixable' => 'Unexpected errors with no automated fixing method',
diff --git a/maintenance/storage/compressOld.php b/maintenance/storage/compressOld.php
index 4594db71..d6362834 100644
--- a/maintenance/storage/compressOld.php
+++ b/maintenance/storage/compressOld.php
@@ -43,6 +43,11 @@
require_once( __DIR__ . '/../Maintenance.php' );
+/**
+ * Maintenance script that compress the text of a wiki.
+ *
+ * @ingroup Maintenance ExternalStorage
+ */
class CompressOld extends Maintenance {
/**
* @todo document
@@ -110,7 +115,7 @@ class CompressOld extends Maintenance {
do {
$res = $dbw->select( 'text', array( 'old_id','old_flags','old_text' ),
"old_id>=$start", __METHOD__, array( 'ORDER BY' => 'old_id', 'LIMIT' => $chunksize, 'FOR UPDATE' ) );
- if( $dbw->numRows( $res ) == 0 ) {
+ if( $res->numRows() == 0 ) {
break;
}
$last = $start;
@@ -251,7 +256,7 @@ class CompressOld extends Maintenance {
$pageRes = $dbr->select( 'page',
array('page_id', 'page_namespace', 'page_title','page_latest'),
$pageConds + array('page_id' => $pageId), __METHOD__ );
- if ( $dbr->numRows( $pageRes ) == 0 ) {
+ if ( $pageRes->numRows() == 0 ) {
continue;
}
$pageRow = $dbr->fetchObject( $pageRes );
diff --git a/maintenance/storage/drop_content_model_info.sql b/maintenance/storage/drop_content_model_info.sql
new file mode 100644
index 00000000..7bd9aba9
--- /dev/null
+++ b/maintenance/storage/drop_content_model_info.sql
@@ -0,0 +1,7 @@
+ALTER TABLE /*$wgDBprefix*/archive DROP COLUMN ar_content_model;
+ALTER TABLE /*$wgDBprefix*/archive DROP COLUMN ar_content_format;
+
+ALTER TABLE /*$wgDBprefix*/revision DROP COLUMN rev_content_model;
+ALTER TABLE /*$wgDBprefix*/revision DROP COLUMN rev_content_format;
+
+ALTER TABLE /*$wgDBprefix*/page DROP COLUMN page_content_model;
diff --git a/maintenance/storage/dumpRev.php b/maintenance/storage/dumpRev.php
index 6020f22e..39f08f9d 100644
--- a/maintenance/storage/dumpRev.php
+++ b/maintenance/storage/dumpRev.php
@@ -1,5 +1,7 @@
<?php
/**
+ * Get the text of a revision, resolving external storage if needed.
+ *
* 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
@@ -15,11 +17,18 @@
* 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 that gets the text of a revision,
+ * resolving external storage if needed.
+ *
+ * @ingroup Maintenance ExternalStorage
+ */
class DumpRev extends Maintenance {
public function __construct() {
parent::__construct();
diff --git a/maintenance/storage/fixBug20757.php b/maintenance/storage/fixBug20757.php
index 52ee825c..30cbcf1a 100644
--- a/maintenance/storage/fixBug20757.php
+++ b/maintenance/storage/fixBug20757.php
@@ -23,11 +23,16 @@
require_once( __DIR__ . '/../Maintenance.php' );
+/**
+ * Maintenance script to fix bug 20757.
+ *
+ * @ingroup Maintenance ExternalStorage
+ */
class FixBug20757 extends Maintenance {
- var $batchSize = 10000;
- var $mapCache = array();
- var $mapCacheSize = 0;
- var $maxMapCacheSize = 1000000;
+ public $batchSize = 10000;
+ public $mapCache = array();
+ public $mapCacheSize = 0;
+ public $maxMapCacheSize = 1000000;
function __construct() {
parent::__construct();
@@ -344,4 +349,3 @@ class FixBug20757 extends Maintenance {
$maintClass = 'FixBug20757';
require_once( RUN_MAINTENANCE_IF_MAIN );
-
diff --git a/maintenance/storage/make-blobs b/maintenance/storage/make-blobs
index 36cf9ced..16dcb672 100755
--- a/maintenance/storage/make-blobs
+++ b/maintenance/storage/make-blobs
@@ -6,11 +6,9 @@ if [ -z $2 ];then
fi
if [ -z $3 ]; then
table=blobs
-else
+else
table=$3
fi
echo "CREATE DATABASE $2" | mysql -u wikiadmin -p`wikiadmin_pass` -h $1 && \
sed "s/blobs\>/$table/" blobs.sql | mysql -u wikiadmin -p`wikiadmin_pass` -h $1 $2
-
-
diff --git a/maintenance/storage/moveToExternal.php b/maintenance/storage/moveToExternal.php
index 2dcc25c2..1049e0cc 100644
--- a/maintenance/storage/moveToExternal.php
+++ b/maintenance/storage/moveToExternal.php
@@ -25,7 +25,7 @@ define( 'REPORTING_INTERVAL', 1 );
if ( !defined( 'MEDIAWIKI' ) ) {
require_once( __DIR__ . '/../commandLine.inc' );
- require_once( __DIR__ . '/../../includes/ExternalStoreDB.php' );
+ require_once( __DIR__ . '/../../includes/externalstore/ExternalStoreDB.php' );
require_once( 'resolveStubs.php' );
$fname = 'moveToExternal';
@@ -124,5 +124,3 @@ function moveToExternal( $cluster, $maxID, $minID = 1 ) {
}
}
}
-
-
diff --git a/maintenance/storage/orphanStats.php b/maintenance/storage/orphanStats.php
index 82ee135b..4e246287 100644
--- a/maintenance/storage/orphanStats.php
+++ b/maintenance/storage/orphanStats.php
@@ -1,7 +1,6 @@
<?php
-
/**
- * Show some statistics on the blob_orphans table, created with trackBlobs.php
+ * Show some statistics on the blob_orphans table, created with trackBlobs.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
@@ -18,10 +17,18 @@
* 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 that shows some statistics on the blob_orphans table,
+ * created with trackBlobs.php.
+ *
+ * @ingroup Maintenance ExternalStorage
+ */
class OrphanStats extends Maintenance {
public function __construct() {
parent::__construct();
diff --git a/maintenance/storage/recompressTracked.php b/maintenance/storage/recompressTracked.php
index 4098077f..030a147e 100644
--- a/maintenance/storage/recompressTracked.php
+++ b/maintenance/storage/recompressTracked.php
@@ -42,20 +42,26 @@ Options:
$job = RecompressTracked::newFromCommandLine( $args, $options );
$job->execute();
+/**
+ * Maintenance script that moves blobs indexed by trackBlobs.php to a specified
+ * list of destination clusters, and recompresses them in the process.
+ *
+ * @ingroup Maintenance ExternalStorage
+ */
class RecompressTracked {
- var $destClusters;
- var $batchSize = 1000;
- var $orphanBatchSize = 1000;
- var $reportingInterval = 10;
- var $numProcs = 1;
- var $useDiff, $pageBlobClass, $orphanBlobClass;
- var $slavePipes, $slaveProcs, $prevSlaveId;
- var $copyOnly = false;
- var $isChild = false;
- var $slaveId = false;
- var $noCount = false;
- var $debugLog, $infoLog, $criticalLog;
- var $store;
+ public $destClusters;
+ public $batchSize = 1000;
+ public $orphanBatchSize = 1000;
+ public $reportingInterval = 10;
+ public $numProcs = 1;
+ public $useDiff, $pageBlobClass, $orphanBlobClass;
+ public $slavePipes, $slaveProcs, $prevSlaveId;
+ public $copyOnly = false;
+ public $isChild = false;
+ public $slaveId = false;
+ public $noCount = false;
+ public $debugLog, $infoLog, $criticalLog;
+ public $store;
static $optionsWithArgs = array( 'procs', 'slave-id', 'debug-log', 'info-log', 'critical-log' );
static $cmdLineOptionMap = array(
@@ -517,7 +523,7 @@ class RecompressTracked {
*
* Write the new URL to the text table and set the bt_moved flag.
*
- * This is done in a single transaction to provide restartable behaviour
+ * This is done in a single transaction to provide restartable behavior
* without data loss.
*
* The transaction is kept short to reduce locking.
@@ -670,10 +676,10 @@ class RecompressTracked {
* Class to represent a recompression operation for a single CGZ blob
*/
class CgzCopyTransaction {
- var $parent;
- var $blobClass;
- var $cgz;
- var $referrers;
+ public $parent;
+ public $blobClass;
+ public $cgz;
+ public $referrers;
/**
* Create a transaction from a RecompressTracked object
@@ -803,4 +809,3 @@ class CgzCopyTransaction {
}
}
}
-
diff --git a/maintenance/storage/resolveStubs.php b/maintenance/storage/resolveStubs.php
index 7e288e13..414eab81 100644
--- a/maintenance/storage/resolveStubs.php
+++ b/maintenance/storage/resolveStubs.php
@@ -1,7 +1,7 @@
<?php
/**
- * Script to convert history stubs that point to an external row to direct
- * external pointers.
+ * Convert history stubs that point to an external row to direct external
+ * pointers.
*
* 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
@@ -110,4 +110,3 @@ function resolveStub( $id, $stubText, $flags ) {
), $fname
);
}
-
diff --git a/maintenance/storage/storageTypeStats.php b/maintenance/storage/storageTypeStats.php
index 1afecc4e..3187c318 100644
--- a/maintenance/storage/storageTypeStats.php
+++ b/maintenance/storage/storageTypeStats.php
@@ -113,4 +113,3 @@ SQL;
$maintClass = 'StorageTypeStats';
require_once( RUN_MAINTENANCE_IF_MAIN );
-
diff --git a/maintenance/storage/testCompression.php b/maintenance/storage/testCompression.php
index 998ebe48..e13e1b10 100644
--- a/maintenance/storage/testCompression.php
+++ b/maintenance/storage/testCompression.php
@@ -1,5 +1,7 @@
<?php
/**
+ * Test revision text compression and decompression.
+ *
* 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
@@ -16,8 +18,7 @@
* http://www.gnu.org/copyleft/gpl.html
*
* @file
- * @ingroup Maintenance
- * @see wfWaitForSlaves()
+ * @ingroup Maintenance ExternalStorage
*/
$optionsWithArgs = array( 'start', 'limit', 'type' );
@@ -65,7 +66,7 @@ $uncompressedSize = 0;
$t = -microtime( true );
foreach ( $res as $row ) {
$revision = new Revision( $row );
- $text = $revision->getText();
+ $text = $revision->getSerializedData();
$uncompressedSize += strlen( $text );
$hashes[$row->rev_id] = md5( $text );
$keys[$row->rev_id] = $blob->addItem( $text );
@@ -98,4 +99,3 @@ foreach ( $keys as $id => $key ) {
}
$t += microtime( true );
printf( "Decompression time: %5.2f ms\n", $t * 1000 );
-
diff --git a/maintenance/storage/trackBlobs.php b/maintenance/storage/trackBlobs.php
index 214168a8..2f3c8c6a 100644
--- a/maintenance/storage/trackBlobs.php
+++ b/maintenance/storage/trackBlobs.php
@@ -37,12 +37,12 @@ $tracker->run();
echo "All done.\n";
class TrackBlobs {
- var $clusters, $textClause;
- var $doBlobOrphans;
- var $trackedBlobs = array();
+ public $clusters, $textClause;
+ public $doBlobOrphans;
+ public $trackedBlobs = array();
- var $batchSize = 1000;
- var $reportingInterval = 10;
+ public $batchSize = 1000;
+ public $reportingInterval = 10;
function __construct( $clusters ) {
$this->clusters = $clusters;
diff --git a/maintenance/syncFileBackend.php b/maintenance/syncFileBackend.php
index a29647b5..158019b7 100644
--- a/maintenance/syncFileBackend.php
+++ b/maintenance/syncFileBackend.php
@@ -34,21 +34,50 @@ class SyncFileBackend extends Maintenance {
parent::__construct();
$this->mDescription = "Sync one file backend with another using the journal";
$this->addOption( 'src', 'Name of backend to sync from', true, true );
- $this->addOption( 'dst', 'Name of destination backend to sync', true, true );
+ $this->addOption( 'dst', 'Name of destination backend to sync', false, true );
$this->addOption( 'start', 'Starting journal ID', false, true );
$this->addOption( 'end', 'Ending journal ID', false, true );
$this->addOption( 'posdir', 'Directory to read/record journal positions', false, true );
+ $this->addOption( 'posdump', 'Just dump current journal position into the position dir.' );
+ $this->addOption( 'postime', 'For position dumps, get the ID at this time', false, true );
$this->addOption( 'verbose', 'Verbose mode', false, false, 'v' );
$this->setBatchSize( 50 );
}
public function execute() {
$src = FileBackendGroup::singleton()->get( $this->getOption( 'src' ) );
- $dst = FileBackendGroup::singleton()->get( $this->getOption( 'dst' ) );
$posDir = $this->getOption( 'posdir' );
$posFile = $posDir ? $posDir . '/' . wfWikiID() : false;
+ if ( $this->hasOption( 'posdump' ) ) {
+ // Just dump the current position into the specified position dir
+ if ( !$this->hasOption( 'posdir' ) ) {
+ $this->error( "Param posdir required!", 1 );
+ }
+ if ( $this->hasOption( 'postime' ) ) {
+ $id = (int)$src->getJournal()->getPositionAtTime( $this->getOption( 'postime' ) );
+ $this->output( "Requested journal position is $id.\n" );
+ } else {
+ $id = (int)$src->getJournal()->getCurrentPosition();
+ $this->output( "Current journal position is $id.\n" );
+ }
+ if ( file_put_contents( $posFile, $id, LOCK_EX ) !== false ) {
+ $this->output( "Saved journal position file.\n" );
+ } else {
+ $this->output( "Could not save journal position file.\n" );
+ }
+ if ( $this->isQuiet() ) {
+ print $id; // give a single machine-readable number
+ }
+ return;
+ }
+
+ if ( !$this->hasOption( 'dst' ) ) {
+ $this->error( "Param dst required!", 1 );
+ }
+ $dst = FileBackendGroup::singleton()->get( $this->getOption( 'dst' ) );
+
$start = $this->getOption( 'start', 0 );
if ( !$start && $posFile && is_dir( $posDir ) ) {
$start = is_file( $posFile )
@@ -67,8 +96,15 @@ class SyncFileBackend extends Maintenance {
$this->output( "Ending journal position is $end.\n" );
}
+ // Periodically update the position file
+ $callback = function( $pos ) use ( $startFromPosFile, $posFile, $start ) {
+ if ( $startFromPosFile && $pos >= $start ) { // successfully advanced
+ file_put_contents( $posFile, $pos, LOCK_EX );
+ }
+ };
+
// Actually sync the dest backend with the reference backend
- $lastOKPos = $this->syncBackends( $src, $dst, $start, $end );
+ $lastOKPos = $this->syncBackends( $src, $dst, $start, $end, $callback );
// Update the sync position file
if ( $startFromPosFile && $lastOKPos >= $start ) { // successfully advanced
@@ -102,9 +138,12 @@ class SyncFileBackend extends Maintenance {
* @param $dst FileBackend
* @param $start integer Starting journal position
* @param $end integer Starting journal position
+ * @param $callback Closure Callback to update any position file
* @return integer|false Journal entry ID or false if there are none
*/
- protected function syncBackends( FileBackend $src, FileBackend $dst, $start, $end ) {
+ protected function syncBackends(
+ FileBackend $src, FileBackend $dst, $start, $end, Closure $callback
+ ) {
$lastOKPos = 0; // failed
$first = true; // first batch
@@ -135,6 +174,7 @@ class SyncFileBackend extends Maintenance {
$status = $this->syncFileBatch( array_keys( $pathsInBatch ), $src, $dst );
if ( $status->isOK() ) {
$lastOKPos = max( $lastOKPos, $lastPosInBatch );
+ $callback( $lastOKPos ); // update position file
} else {
$this->error( print_r( $status->getErrorsArray(), true ) );
break; // no gaps; everything up to $lastPos must be OK
diff --git a/maintenance/tables.sql b/maintenance/tables.sql
index 52b835fd..72b4eb6c 100644
--- a/maintenance/tables.sql
+++ b/maintenance/tables.sql
@@ -86,10 +86,12 @@ CREATE TABLE /*_*/user (
-- Same with passwords.
user_email tinytext NOT NULL,
- -- This is a timestamp which is updated when a user
- -- logs in, logs out, changes preferences, or performs
- -- some other action requiring HTML cache invalidation
- -- to ensure that the UI is updated.
+ -- If the browser sends an If-Modified-Since header, a 304 response is
+ -- suppressed if the value in this field for the current user is later than
+ -- the value in the IMS header. That is, this field is an invalidation timestamp
+ -- for the browser cache of logged-in users. Among other things, it is used
+ -- to prevent pages generated for a previously logged in user from being
+ -- displayed after a session expiry followed by a fresh login.
user_touched binary(14) NOT NULL default '',
-- A pseudorandomly generated value that is stored in
@@ -152,7 +154,7 @@ CREATE TABLE /*_*/user_groups (
-- with particular permissions. A user will have the combined
-- permissions of any group they're explicitly in, plus
-- the implicit '*' and 'user' groups.
- ug_group varbinary(32) NOT NULL default ''
+ ug_group varbinary(255) NOT NULL default ''
) /*$wgDBTableOptions*/;
CREATE UNIQUE INDEX /*i*/ug_user_group ON /*_*/user_groups (ug_user,ug_group);
@@ -164,7 +166,7 @@ CREATE INDEX /*i*/ug_group ON /*_*/user_groups (ug_group);
CREATE TABLE /*_*/user_former_groups (
-- Key to user_id
ufg_user int unsigned NOT NULL default 0,
- ufg_group varbinary(32) NOT NULL default ''
+ ufg_group varbinary(255) NOT NULL default ''
) /*$wgDBTableOptions*/;
CREATE UNIQUE INDEX /*i*/ufg_user_group ON /*_*/user_former_groups (ufg_user,ufg_group);
@@ -260,7 +262,10 @@ CREATE TABLE /*_*/page (
page_latest int unsigned NOT NULL,
-- Uncompressed length in bytes of the page's current source text.
- page_len int unsigned NOT NULL
+ page_len int unsigned NOT NULL,
+
+ -- content model, see CONTENT_MODEL_XXX constants
+ page_content_model varbinary(32) DEFAULT NULL
) /*$wgDBTableOptions*/;
CREATE UNIQUE INDEX /*i*/name_title ON /*_*/page (page_namespace,page_title);
@@ -316,7 +321,13 @@ CREATE TABLE /*_*/revision (
rev_parent_id int unsigned default NULL,
-- SHA-1 text content hash in base-36
- rev_sha1 varbinary(32) NOT NULL default ''
+ rev_sha1 varbinary(32) NOT NULL default '',
+
+ -- content model, see CONTENT_MODEL_XXX constants
+ rev_content_model varbinary(32) DEFAULT NULL,
+
+ -- content format, see CONTENT_FORMAT_XXX constants
+ rev_content_format varbinary(64) DEFAULT NULL
) /*$wgDBTableOptions*/ MAX_ROWS=10000000 AVG_ROW_LENGTH=1024;
-- In case tables are created as MyISAM, use row hints for MySQL <5.0 to avoid 4GB limit
@@ -427,7 +438,14 @@ CREATE TABLE /*_*/archive (
ar_parent_id int unsigned default NULL,
-- SHA-1 text content hash in base-36
- ar_sha1 varbinary(32) NOT NULL default ''
+ ar_sha1 varbinary(32) NOT NULL default '',
+
+ -- content model, see CONTENT_MODEL_XXX constants
+ ar_content_model varbinary(32) DEFAULT NULL,
+
+ -- content format, see CONTENT_FORMAT_XXX constants
+ ar_content_format varbinary(64) DEFAULT NULL
+
) /*$wgDBTableOptions*/;
CREATE INDEX /*i*/name_title_timestamp ON /*_*/archive (ar_namespace,ar_title,ar_timestamp);
@@ -544,10 +562,10 @@ CREATE UNIQUE INDEX /*i*/cl_from ON /*_*/categorylinks (cl_from,cl_to);
-- callers won't be using an index: fix this?
CREATE INDEX /*i*/cl_sortkey ON /*_*/categorylinks (cl_to,cl_type,cl_sortkey,cl_from);
--- Not really used?
+-- Used by the API (and some extensions)
CREATE INDEX /*i*/cl_timestamp ON /*_*/categorylinks (cl_to,cl_timestamp);
--- For finding rows with outdated collation
+-- FIXME: Not used, delete this
CREATE INDEX /*i*/cl_collation ON /*_*/categorylinks (cl_collation);
--
@@ -689,9 +707,6 @@ CREATE TABLE /*_*/site_stats (
-- Number of users that still edit
ss_active_users bigint default '-1',
- -- Deprecated, no longer updated as of 1.5
- ss_admins int default '-1',
-
-- Number of images, equivalent to SELECT COUNT(*) FROM image
ss_images int default 0
) /*$wgDBTableOptions*/;
@@ -846,7 +861,9 @@ CREATE INDEX /*i*/img_size ON /*_*/image (img_size);
-- Used by Special:Newimages and Special:ListFiles
CREATE INDEX /*i*/img_timestamp ON /*_*/image (img_timestamp);
-- Used in API and duplicate search
-CREATE INDEX /*i*/img_sha1 ON /*_*/image (img_sha1);
+CREATE INDEX /*i*/img_sha1 ON /*_*/image (img_sha1(10));
+-- Used to get media of one type
+CREATE INDEX /*i*/img_media_mime ON /*_*/image (img_media_type,img_major_mime,img_minor_mime);
--
@@ -884,7 +901,7 @@ CREATE INDEX /*i*/oi_usertext_timestamp ON /*_*/oldimage (oi_user_text,oi_timest
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));
-CREATE INDEX /*i*/oi_sha1 ON /*_*/oldimage (oi_sha1);
+CREATE INDEX /*i*/oi_sha1 ON /*_*/oldimage (oi_sha1(10));
--
@@ -932,7 +949,10 @@ CREATE TABLE /*_*/filearchive (
fa_timestamp binary(14) default '',
-- Visibility of deleted revisions, bitfield
- fa_deleted tinyint unsigned NOT NULL default 0
+ fa_deleted tinyint unsigned NOT NULL default 0,
+
+ -- sha1 hash of file content
+ fa_sha1 varbinary(32) NOT NULL default ''
) /*$wgDBTableOptions*/;
-- pick out by image name
@@ -943,6 +963,8 @@ 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);
+-- find file by sha1, 10 bytes will be enough for hashes to be indexed
+CREATE INDEX /*i*/fa_sha1 ON /*_*/filearchive (fa_sha1(10));
--
@@ -976,8 +998,10 @@ CREATE TABLE /*_*/uploadstash (
-- chunk counter starts at 0, current offset is stored in us_size
us_chunk_inx int unsigned NULL,
- -- file properties from File::getPropsFromPath. these may prove unnecessary.
- --
+ -- Serialized file properties from File::getPropsFromPath
+ us_props blob,
+
+ -- file size in bytes
us_size int unsigned NOT NULL,
-- this hash comes from File::sha1Base36(), and is 31 characters
us_sha1 varchar(31) NOT NULL,
@@ -1045,10 +1069,6 @@ CREATE TABLE /*_*/recentchanges (
-- The type of change entry (RC_EDIT,RC_NEW,RC_LOG)
rc_type tinyint unsigned NOT NULL default 0,
- -- These may no longer be used, with the new move log.
- rc_moved_to_ns tinyint unsigned NOT NULL default 0,
- rc_moved_to_title varchar(255) binary NOT NULL default '',
-
-- 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.
@@ -1228,7 +1248,8 @@ CREATE TABLE /*_*/logging (
-- Freeform text. Interpreted as edit history comments.
log_comment varchar(255) NOT NULL default '',
- -- LF separated list of miscellaneous parameters
+ -- miscellaneous parameters:
+ -- LF separated list (old system) or serialized PHP array (new system)
log_params blob NOT NULL,
-- rev_deleted for logs
@@ -1275,9 +1296,27 @@ CREATE TABLE /*_*/job (
-- Any other parameters to the command
-- Stored as a PHP serialized array, or an empty string if there are no parameters
- job_params blob NOT NULL
+ job_params blob NOT NULL,
+
+ -- Random, non-unique, number used for job acquisition (for lock concurrency)
+ job_random integer unsigned NOT NULL default 0,
+
+ -- The number of times this job has been locked
+ job_attempts integer unsigned NOT NULL default 0,
+
+ -- Field that conveys process locks on rows via process UUIDs
+ job_token varbinary(32) NOT NULL default '',
+
+ -- Timestamp when the job was locked
+ job_token_timestamp varbinary(14) NULL default NULL,
+
+ -- Base 36 SHA1 of the job parameters relevant to detecting duplicates
+ job_sha1 varbinary(32) NOT NULL default ''
) /*$wgDBTableOptions*/;
+CREATE INDEX /*i*/job_sha1 ON /*_*/job (job_sha1);
+CREATE INDEX /*i*/job_cmd_token ON /*_*/job (job_cmd,job_token,job_random);
+CREATE INDEX /*i*/job_cmd_token_id ON /*_*/job (job_cmd,job_token,job_id);
CREATE INDEX /*i*/job_cmd ON /*_*/job (job_cmd, job_namespace, job_title, job_params(128));
CREATE INDEX /*i*/job_timestamp ON /*_*/job (job_timestamp);
@@ -1382,6 +1421,7 @@ CREATE TABLE /*_*/page_props (
) /*$wgDBTableOptions*/;
CREATE UNIQUE INDEX /*i*/pp_page_propname ON /*_*/page_props (pp_page,pp_propname);
+CREATE UNIQUE INDEX /*i*/pp_propname_page ON /*_*/page_props (pp_propname,pp_page);
-- A table to log updates, one text key row per update.
@@ -1479,4 +1519,69 @@ CREATE TABLE /*_*/module_deps (
) /*$wgDBTableOptions*/;
CREATE UNIQUE INDEX /*i*/md_module_skin ON /*_*/module_deps (md_module, md_skin);
+-- Holds all the sites known to the wiki.
+CREATE TABLE /*_*/sites (
+-- Numeric id of the site
+ site_id INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
+
+ -- Global identifier for the site, ie 'enwiktionary'
+ site_global_key varbinary(32) NOT NULL,
+
+ -- Type of the site, ie 'mediawiki'
+ site_type varbinary(32) NOT NULL,
+
+ -- Group of the site, ie 'wikipedia'
+ site_group varbinary(32) NOT NULL,
+
+ -- Source of the site data, ie 'local', 'wikidata', 'my-magical-repo'
+ site_source varbinary(32) NOT NULL,
+
+ -- Language code of the sites primary language.
+ site_language varbinary(32) NOT NULL,
+
+ -- Protocol of the site, ie 'http://', 'irc://', '//'
+ -- This field is an index for lookups and is build from type specific data in site_data.
+ site_protocol varbinary(32) NOT NULL,
+
+ -- Domain of the site in reverse order, ie 'org.mediawiki.www.'
+ -- This field is an index for lookups and is build from type specific data in site_data.
+ site_domain VARCHAR(255) NOT NULL,
+
+ -- Type dependent site data.
+ site_data BLOB NOT NULL,
+
+ -- If site.tld/path/key:pageTitle should forward users to the page on
+ -- the actual site, where "key" is the local identifier.
+ site_forward bool NOT NULL,
+
+ -- Type dependent site config.
+ -- For instance if template transclusion should be allowed if it's a MediaWiki.
+ site_config BLOB NOT NULL
+) /*$wgDBTableOptions*/;
+
+CREATE UNIQUE INDEX /*i*/sites_global_key ON /*_*/sites (site_global_key);
+CREATE INDEX /*i*/sites_type ON /*_*/sites (site_type);
+CREATE INDEX /*i*/sites_group ON /*_*/sites (site_group);
+CREATE INDEX /*i*/sites_source ON /*_*/sites (site_source);
+CREATE INDEX /*i*/sites_language ON /*_*/sites (site_language);
+CREATE INDEX /*i*/sites_protocol ON /*_*/sites (site_protocol);
+CREATE INDEX /*i*/sites_domain ON /*_*/sites (site_domain);
+CREATE INDEX /*i*/sites_forward ON /*_*/sites (site_forward);
+
+-- Links local site identifiers to their corresponding site.
+CREATE TABLE /*_*/site_identifiers (
+ -- Key on site.site_id
+ si_site INT UNSIGNED NOT NULL,
+
+ -- local key type, ie 'interwiki' or 'langlink'
+ si_type varbinary(32) NOT NULL,
+
+ -- local key value, ie 'en' or 'wiktionary'
+ si_key varbinary(32) NOT NULL
+) /*$wgDBTableOptions*/;
+
+CREATE UNIQUE INDEX /*i*/site_ids_type ON /*_*/site_identifiers (si_type, si_key);
+CREATE INDEX /*i*/site_ids_site ON /*_*/site_identifiers (si_site);
+CREATE INDEX /*i*/site_ids_key ON /*_*/site_identifiers (si_key);
+
-- vim: sw=2 sts=2 et
diff --git a/maintenance/term/MWTerm.php b/maintenance/term/MWTerm.php
index ca0f95d2..c52f07cc 100644
--- a/maintenance/term/MWTerm.php
+++ b/maintenance/term/MWTerm.php
@@ -19,12 +19,14 @@
* http://www.gnu.org/copyleft/gpl.html
*
* @file
- * @ingroup Testing
+ * @ingroup Maintenance Testing
* @todo Fixme: Make this more generic
*/
/**
* Terminal that supports ANSI escape sequences.
+ *
+ * @ingroup Maintenance Testing
*/
class AnsiTermColorer {
function __construct() {
@@ -56,6 +58,8 @@ class AnsiTermColorer {
/**
* A colour-less terminal
+ *
+ * @ingroup Maintenance Testing
*/
class DummyTermColorer {
public function color( $color ) {
@@ -66,4 +70,3 @@ class DummyTermColorer {
return '';
}
}
-
diff --git a/maintenance/update.php b/maintenance/update.php
index 877f1366..f69a9b0d 100644
--- a/maintenance/update.php
+++ b/maintenance/update.php
@@ -26,9 +26,8 @@
*/
if ( !function_exists( 'version_compare' ) || ( version_compare( phpversion(), '5.3.2' ) < 0 ) ) {
- echo "You are using PHP version " . phpversion() . " but MediaWiki needs PHP 5.3.2 or higher. ABORTING.\n" .
- "Check if you have a newer php executable with a different name, such as php5.\n";
- die( 1 );
+ require( dirname( __FILE__ ) . '/../includes/PHPVersionError.php' );
+ wfPHPVersionError( 'cli' );
}
$wgUseMasterForMaintenance = true;
@@ -40,7 +39,6 @@ require_once( __DIR__ . '/Maintenance.php' );
* @ingroup Maintenance
*/
class UpdateMediaWiki extends Maintenance {
-
function __construct() {
parent::__construct();
$this->mDescription = "MediaWiki database updater";
@@ -48,6 +46,8 @@ class UpdateMediaWiki extends Maintenance {
$this->addOption( 'quick', 'Skip 5 second countdown before starting' );
$this->addOption( 'doshared', 'Also update shared tables' );
$this->addOption( 'nopurge', 'Do not purge the objectcache table after updates' );
+ $this->addOption( 'noschema', 'Only do the updates that are not done during schema updates' );
+ $this->addOption( 'schema', 'Output SQL to do the schema updates instead of doing them. Works even when $wgAllowSchemaUpdates is false', false, true );
$this->addOption( 'force', 'Override when $wgAllowSchemaUpdates disables this script' );
}
@@ -83,10 +83,24 @@ class UpdateMediaWiki extends Maintenance {
function execute() {
global $wgVersion, $wgTitle, $wgLang, $wgAllowSchemaUpdates;
- if( !$wgAllowSchemaUpdates && !$this->hasOption( 'force' ) ) {
+ 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"
- . "probably ask for some help in performing your schema updates.\n\n"
- . "If you know what you are doing, you can continue with --force", true );
+ . "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 );
+ }
+
+ $this->fileHandle = null;
+ if( substr( $this->getOption( 'schema' ), 0, 2 ) === "--" ) {
+ $this->error( "The --schema option requires a file as an argument.\n", true );
+ } else if( $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 );
+ }
}
$wgLang = Language::factory( 'en' );
@@ -108,6 +122,9 @@ class UpdateMediaWiki extends Maintenance {
$db = wfGetDB( DB_MASTER );
$this->output( "Going to run database updates for " . wfWikiID() . "\n" );
+ if( $db->getType() === 'sqlite' ) {
+ $this->output( "Using SQLite file: '{$db->mDatabaseFile}'\n" );
+ }
$this->output( "Depending on the size of your database this may take a while!\n" );
if ( !$this->hasOption( 'quick' ) ) {
@@ -117,21 +134,40 @@ class UpdateMediaWiki extends Maintenance {
$shared = $this->hasOption( 'doshared' );
- $updates = array( 'core', 'extensions', 'stats' );
- if( !$this->hasOption('nopurge') ) {
- $updates[] = 'purge';
+ $updates = array( 'core', 'extensions' );
+ if( !$this->hasOption('schema') ) {
+ if( $this->hasOption('noschema') ) {
+ $updates[] = 'noschema';
+ }
+ $updates[] = 'stats';
+
+ if( !$this->hasOption('nopurge') ) {
+ $updates[] = 'purge';
+ }
}
$updater = DatabaseUpdater::newForDb( $db, $shared, $this );
$updater->doUpdates( $updates );
foreach( $updater->getPostDatabaseUpdateMaintenance() as $maint ) {
- if ( $updater->updateRowExists( $maint ) ) {
+ $child = $this->runChild( $maint );
+
+ // LoggedUpdateMaintenance is checking the updatelog itself
+ $isLoggedUpdate = is_a( $child, 'LoggedUpdateMaintenance' );
+
+ if ( !$isLoggedUpdate && $updater->updateRowExists( $maint ) ) {
continue;
}
+
$child = $this->runChild( $maint );
$child->execute();
- $updater->insertUpdateRow( $maint );
+ if ( !$isLoggedUpdate ) {
+ $updater->insertUpdateRow( $maint );
+ }
+ }
+
+ if( !$this->hasOption('nopurge') ) {
+ $updater->purgeCache();
}
$this->output( "\nDone.\n" );
diff --git a/maintenance/updateCollation.php b/maintenance/updateCollation.php
index b732508f..a76a1ee6 100644
--- a/maintenance/updateCollation.php
+++ b/maintenance/updateCollation.php
@@ -35,10 +35,10 @@ require_once( __DIR__ . '/Maintenance.php' );
* @ingroup Maintenance
*/
class UpdateCollation extends Maintenance {
- const BATCH_SIZE = 50; // Number of rows to process in one batch
+ const BATCH_SIZE = 10000; // Number of rows to process in one batch
const SYNC_INTERVAL = 20; // Wait for slaves after this many batches
- var $sizeHistogram = array();
+ public $sizeHistogram = array();
public function __construct() {
parent::__construct();
@@ -68,7 +68,7 @@ TEXT;
}
public function execute() {
- global $wgCategoryCollation, $wgMiserMode;
+ global $wgCategoryCollation;
$dbw = $this->getDB( DB_MASTER );
$force = $this->getOption( 'force' );
@@ -82,10 +82,13 @@ TEXT;
$collation = Collation::singleton();
}
- $options = array( 'LIMIT' => self::BATCH_SIZE, 'STRAIGHT_JOIN' );
+ $options = array(
+ 'LIMIT' => self::BATCH_SIZE,
+ 'ORDER BY' => 'cl_to, cl_type, cl_from',
+ 'STRAIGHT_JOIN',
+ );
if ( $force || $dryRun ) {
- $options['ORDER BY'] = 'cl_from, cl_to';
$collationConds = array();
} else {
if ( $this->hasOption( 'previous-collation' ) ) {
@@ -96,20 +99,20 @@ TEXT;
);
}
- if ( !$wgMiserMode ) {
+ $count = $dbw->estimateRowCount(
+ 'categorylinks',
+ '*',
+ $collationConds,
+ __METHOD__
+ );
+ // Improve estimate if feasible
+ if ( $count < 1000000 ) {
$count = $dbw->selectField(
'categorylinks',
'COUNT(*)',
$collationConds,
__METHOD__
);
- } else {
- $count = $dbw->estimateRowCount(
- 'categorylinks',
- '*',
- $collationConds,
- __METHOD__
- );
}
if ( $count == 0 ) {
$this->output( "Collations up-to-date.\n" );
@@ -126,7 +129,7 @@ TEXT;
$res = $dbw->select(
array( 'categorylinks', 'page' ),
array( 'cl_from', 'cl_to', 'cl_sortkey_prefix', 'cl_collation',
- 'cl_sortkey', 'page_namespace', 'page_title'
+ 'cl_sortkey', 'cl_type', 'page_namespace', 'page_title'
),
array_merge( $collationConds, $batchConds, array( 'cl_from = page_id' ) ),
__METHOD__,
@@ -186,12 +189,8 @@ TEXT;
$dbw->commit( __METHOD__ );
}
- if ( ( $force || $dryRun ) && $row ) {
- $encFrom = $dbw->addQuotes( $row->cl_from );
- $encTo = $dbw->addQuotes( $row->cl_to );
- $batchConds = array(
- "(cl_from = $encFrom AND cl_to > $encTo) " .
- " OR cl_from > $encFrom" );
+ if ( $row ) {
+ $batchConds = array( $this->getBatchCondition( $row ) );
}
$count += $res->numRows();
@@ -212,6 +211,32 @@ TEXT;
}
}
+ /**
+ * Return an SQL expression selecting rows which sort above the given row,
+ * assuming an ordering of cl_to, cl_type, cl_from
+ */
+ function getBatchCondition( $row ) {
+ $dbw = $this->getDB( DB_MASTER );
+ $fields = array( 'cl_to', 'cl_type', 'cl_from' );
+ $first = true;
+ $cond = false;
+ $prefix = false;
+ foreach ( $fields as $field ) {
+ $encValue = $dbw->addQuotes( $row->$field );
+ $inequality = "$field > $encValue";
+ $equality = "$field = $encValue";
+ if ( $first ) {
+ $cond = $inequality;
+ $prefix = $equality;
+ $first = false;
+ } else {
+ $cond .= " OR ($prefix AND $inequality)";
+ $prefix .= " AND $equality";
+ }
+ }
+ return $cond;
+ }
+
function updateSortKeySizeHistogram( $key ) {
$length = strlen( $key );
if ( !isset( $this->sizeHistogram[$length] ) ) {
diff --git a/maintenance/updateSearchIndex.php b/maintenance/updateSearchIndex.php
index 2a71e7ed..ac784847 100644
--- a/maintenance/updateSearchIndex.php
+++ b/maintenance/updateSearchIndex.php
@@ -96,9 +96,9 @@ class UpdateSearchIndex extends Maintenance {
$end = $dbw->timestamp( $end );
$page = $dbw->tableName( 'page' );
- $sql = "SELECT rc_cur_id,rc_type,rc_moved_to_ns,rc_moved_to_title FROM $recentchanges
+ $sql = "SELECT rc_cur_id FROM $recentchanges
JOIN $page ON rc_cur_id=page_id AND rc_this_oldid=page_latest
- WHERE rc_timestamp BETWEEN '$start' AND '$end'
+ WHERE rc_type != " . RC_LOG . " AND rc_timestamp BETWEEN '$start' AND '$end'
";
$res = $dbw->query( $sql, __METHOD__ );
@@ -108,17 +108,7 @@ class UpdateSearchIndex extends Maintenance {
}
public function searchIndexUpdateCallback( $dbw, $row ) {
- if ( $row->rc_type == RC_MOVE || $row->rc_type == RC_MOVE_OVER_REDIRECT ) {
- # Rename searchindex entry
- $titleObj = Title::makeTitle( $row->rc_moved_to_ns, $row->rc_moved_to_title );
- $title = $titleObj->getPrefixedDBkey();
- $this->output( "$title..." );
- $u = new SearchUpdate( $row->rc_cur_id, $title, false );
- $u->doUpdate();
- $this->output( "\n" );
- } elseif ( $row->rc_type !== RC_LOG ) {
- $this->updateSearchIndexForPage( $dbw, $row->rc_cur_id );
- }
+ $this->updateSearchIndexForPage( $dbw, $row->rc_cur_id );
}
}
diff --git a/maintenance/updateSpecialPages.php b/maintenance/updateSpecialPages.php
index 3f1a90bb..f92f67aa 100644
--- a/maintenance/updateSpecialPages.php
+++ b/maintenance/updateSpecialPages.php
@@ -47,10 +47,10 @@ class UpdateSpecialPages extends Maintenance {
$this->error( "Uncallable function $call!" );
continue;
}
+ $this->output( sprintf( '%-30s ', $special ) );
$t1 = explode( ' ', microtime() );
call_user_func( $call, $dbw );
$t2 = explode( ' ', microtime() );
- $this->output( sprintf( '%-30s ', $special ) );
$elapsed = ( $t2[0] - $t1[0] ) + ( $t2[1] - $t1[1] );
$hours = intval( $elapsed / 3600 );
$minutes = intval( $elapsed % 3600 / 60 );
diff --git a/maintenance/upgrade1_5.php b/maintenance/upgrade1_5.php
deleted file mode 100644
index 1e268de3..00000000
--- a/maintenance/upgrade1_5.php
+++ /dev/null
@@ -1,1337 +0,0 @@
-<?php
-/**
- * Alternate 1.4 -> 1.5 schema upgrade.
- * This does only the main tables + UTF-8 and is designed to allow upgrades to
- * interleave with other updates on the replication stream so that large wikis
- * can be upgraded without disrupting other services.
- *
- * Note: this script DOES NOT apply every update, nor will it probably handle
- * much older versions, etc.
- * Run this, FOLLOWED BY update.php, for upgrading from 1.4.5 release to 1.5.
- *
- * 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' );
-
-define( 'MW_UPGRADE_COPY', false );
-define( 'MW_UPGRADE_ENCODE', true );
-define( 'MW_UPGRADE_NULL', null );
-define( 'MW_UPGRADE_CALLBACK', null ); // for self-documentation only
-
-/**
- * @ingroup Maintenance
- */
-class FiveUpgrade extends Maintenance {
-
- /**
- * @var DatabaseBase
- */
- protected $db;
-
- function __construct() {
- parent::__construct();
-
- $this->mDescription = 'Script for upgrades from 1.4 to 1.5 (NOT 1.15) in very special cases.';
-
- $this->addOption( 'upgrade', 'Really run the script' );
- $this->addOption( 'noimage', '' );
- $this->addOption( 'step', 'Only do a specific step', false, true );
- }
-
- public function getDbType() {
- return Maintenance::DB_ADMIN;
- }
-
- public function execute() {
- $this->output( "ATTENTION: This script is for upgrades from 1.4 to 1.5 (NOT 1.15) in very special cases.\n" );
- $this->output( "Use update.php for usual updates.\n" );
-
- if ( !$this->hasOption( 'upgrade' ) ) {
- $this->output( "Please run this script with --upgrade key to actually run the updater.\n" );
- return;
- }
-
- $this->setMembers();
-
- $tables = array(
- 'page',
- 'links',
- 'user',
- 'image',
- 'oldimage',
- 'watchlist',
- 'logging',
- 'archive',
- 'imagelinks',
- 'categorylinks',
- 'ipblocks',
- 'recentchanges',
- 'querycache'
- );
-
- foreach ( $tables as $table ) {
- if ( $this->doing( $table ) ) {
- $method = 'upgrade' . ucfirst( $table );
- $this->$method();
- }
- }
-
- if ( $this->doing( 'cleanup' ) ) {
- $this->upgradeCleanup();
- }
- }
-
- protected function setMembers() {
- $this->conversionTables = $this->prepareWindows1252();
-
- $this->loadBalancers = array();
- $this->dbw = wfGetDB( DB_MASTER );
- $this->dbr = $this->streamConnection();
-
- $this->cleanupSwaps = array();
- $this->emailAuth = false; # don't preauthenticate emails
- $this->step = $this->getOption( 'step', null );
- }
-
- function doing( $step ) {
- return is_null( $this->step ) || $step == $this->step;
- }
-
- /**
- * Open a connection to the master server with the admin rights.
- * @return DatabaseBase
- * @access private
- */
- function newConnection() {
- $lb = wfGetLBFactory()->newMainLB();
- $db = $lb->getConnection( DB_MASTER );
-
- $this->loadBalancers[] = $lb;
- return $db;
- }
-
- /**
- * Commit transactions and close the connections when we're done...
- */
- function close() {
- foreach ( $this->loadBalancers as $lb ) {
- $lb->commitMasterChanges();
- $lb->closeAll();
- }
- }
-
- /**
- * Open a second connection to the master server, with buffering off.
- * This will let us stream large datasets in and write in chunks on the
- * other end.
- * @return DatabaseBase
- * @access private
- */
- function streamConnection() {
- $timeout = 3600 * 24;
- $db = $this->newConnection();
- $db->bufferResults( false );
- if ( $db->getType() == 'mysql' ) {
- $db->query( "SET net_read_timeout=$timeout" );
- $db->query( "SET net_write_timeout=$timeout" );
- }
- return $db;
- }
-
- /**
- * Prepare a conversion array for converting Windows Code Page 1252 to
- * UTF-8. This should provide proper conversion of text that was miscoded
- * as Windows-1252 by naughty user-agents, and doesn't rely on an outside
- * iconv library.
- *
- * @return array
- * @access private
- */
- function prepareWindows1252() {
- # Mappings from:
- # http://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP1252.TXT
- static $cp1252 = array(
- 0x80 => 0x20AC, # EURO SIGN
- 0x81 => 0xFFFD, # REPLACEMENT CHARACTER (no mapping)
- 0x82 => 0x201A, # SINGLE LOW-9 QUOTATION MARK
- 0x83 => 0x0192, # LATIN SMALL LETTER F WITH HOOK
- 0x84 => 0x201E, # DOUBLE LOW-9 QUOTATION MARK
- 0x85 => 0x2026, # HORIZONTAL ELLIPSIS
- 0x86 => 0x2020, # DAGGER
- 0x87 => 0x2021, # DOUBLE DAGGER
- 0x88 => 0x02C6, # MODIFIER LETTER CIRCUMFLEX ACCENT
- 0x89 => 0x2030, # PER MILLE SIGN
- 0x8A => 0x0160, # LATIN CAPITAL LETTER S WITH CARON
- 0x8B => 0x2039, # SINGLE LEFT-POINTING ANGLE QUOTATION MARK
- 0x8C => 0x0152, # LATIN CAPITAL LIGATURE OE
- 0x8D => 0xFFFD, # REPLACEMENT CHARACTER (no mapping)
- 0x8E => 0x017D, # LATIN CAPITAL LETTER Z WITH CARON
- 0x8F => 0xFFFD, # REPLACEMENT CHARACTER (no mapping)
- 0x90 => 0xFFFD, # REPLACEMENT CHARACTER (no mapping)
- 0x91 => 0x2018, # LEFT SINGLE QUOTATION MARK
- 0x92 => 0x2019, # RIGHT SINGLE QUOTATION MARK
- 0x93 => 0x201C, # LEFT DOUBLE QUOTATION MARK
- 0x94 => 0x201D, # RIGHT DOUBLE QUOTATION MARK
- 0x95 => 0x2022, # BULLET
- 0x96 => 0x2013, # EN DASH
- 0x97 => 0x2014, # EM DASH
- 0x98 => 0x02DC, # SMALL TILDE
- 0x99 => 0x2122, # TRADE MARK SIGN
- 0x9A => 0x0161, # LATIN SMALL LETTER S WITH CARON
- 0x9B => 0x203A, # SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
- 0x9C => 0x0153, # LATIN SMALL LIGATURE OE
- 0x9D => 0xFFFD, # REPLACEMENT CHARACTER (no mapping)
- 0x9E => 0x017E, # LATIN SMALL LETTER Z WITH CARON
- 0x9F => 0x0178, # LATIN CAPITAL LETTER Y WITH DIAERESIS
- );
- $pairs = array();
- for ( $i = 0; $i < 0x100; $i++ ) {
- $unicode = isset( $cp1252[$i] ) ? $cp1252[$i] : $i;
- $pairs[chr( $i )] = codepointToUtf8( $unicode );
- }
- return $pairs;
- }
-
- /**
- * Convert from 8-bit Windows-1252 to UTF-8 if necessary.
- * @param string $text
- * @return string
- * @access private
- */
- function conv( $text ) {
- global $wgUseLatin1;
- return is_null( $text )
- ? null
- : ( $wgUseLatin1
- ? strtr( $text, $this->conversionTables )
- : $text );
- }
-
- /**
- * Dump timestamp and message to output
- * @param $message String
- * @access private
- */
- function log( $message ) {
- $this->output( wfWikiID() . ' ' . wfTimestamp( TS_DB ) . ': ' . $message . "\n" );
- }
-
- /**
- * Initialize the chunked-insert system.
- * Rows will be inserted in chunks of the given number, rather
- * than in a giant INSERT...SELECT query, to keep the serialized
- * MySQL database replication from getting hung up. This way other
- * things can be going on during conversion without waiting for
- * slaves to catch up as badly.
- *
- * @param int $chunksize Number of rows to insert at once
- * @param int $final Total expected number of rows / id of last row,
- * used for progress reports.
- * @param string $table to insert on
- * @param string $fname function name to report in SQL
- * @access private
- */
- function setChunkScale( $chunksize, $final, $table, $fname ) {
- $this->chunkSize = $chunksize;
- $this->chunkFinal = $final;
- $this->chunkCount = 0;
- $this->chunkStartTime = microtime( true );
- $this->chunkOptions = array( 'IGNORE' );
- $this->chunkTable = $table;
- $this->chunkFunction = $fname;
- }
-
- /**
- * Chunked inserts: perform an insert if we've reached the chunk limit.
- * Prints a progress report with estimated completion time.
- * @param array &$chunk -- This will be emptied if an insert is done.
- * @param int $key A key identifier to use in progress estimation in
- * place of the number of rows inserted. Use this if
- * you provided a max key number instead of a count
- * as the final chunk number in setChunkScale()
- * @access private
- */
- function addChunk( &$chunk, $key = null ) {
- if ( count( $chunk ) >= $this->chunkSize ) {
- $this->insertChunk( $chunk );
-
- $this->chunkCount += count( $chunk );
- $now = microtime( true );
- $delta = $now - $this->chunkStartTime;
- $rate = $this->chunkCount / $delta;
-
- if ( is_null( $key ) ) {
- $completed = $this->chunkCount;
- } else {
- $completed = $key;
- }
- $portion = $completed / $this->chunkFinal;
-
- $estimatedTotalTime = $delta / $portion;
- $eta = $this->chunkStartTime + $estimatedTotalTime;
-
- printf( "%s: %6.2f%% done on %s; ETA %s [%d/%d] %.2f/sec\n",
- wfTimestamp( TS_DB, intval( $now ) ),
- $portion * 100.0,
- $this->chunkTable,
- wfTimestamp( TS_DB, intval( $eta ) ),
- $completed,
- $this->chunkFinal,
- $rate );
- flush();
-
- $chunk = array();
- }
- }
-
- /**
- * Chunked inserts: perform an insert unconditionally, at the end, and log.
- * @param array &$chunk -- This will be emptied if an insert is done.
- * @access private
- */
- function lastChunk( &$chunk ) {
- $n = count( $chunk );
- if ( $n > 0 ) {
- $this->insertChunk( $chunk );
- }
- $this->log( "100.00% done on $this->chunkTable (last chunk $n rows)." );
- }
-
- /**
- * Chunked inserts: perform an insert.
- * @param array &$chunk -- This will be emptied if an insert is done.
- * @access private
- */
- function insertChunk( &$chunk ) {
- // Give slaves a chance to catch up
- wfWaitForSlaves();
- $this->dbw->insert( $this->chunkTable, $chunk, $this->chunkFunction, $this->chunkOptions );
- }
-
- /**
- * Helper function for copyTable array_filter
- * @param $x
- * @return bool
- */
- static private function notUpgradeNull( $x ) {
- return $x !== MW_UPGRADE_NULL;
- }
-
- /**
- * Copy and transcode a table to table_temp.
- * @param string $name Base name of the source table
- * @param string $tabledef CREATE TABLE definition, w/ $1 for the name
- * @param array $fields set of destination fields to these constants:
- * MW_UPGRADE_COPY - straight copy
- * MW_UPGRADE_ENCODE - for old Latin1 wikis, conv to UTF-8
- * MW_UPGRADE_NULL - just put NULL
- * @param $callback callback An optional callback to modify the data
- * or perform other processing. Func should be
- * ( object $row, array $copy ) and return $copy
- * @access private
- */
- function copyTable( $name, $tabledef, $fields, $callback = null ) {
- $name_temp = $name . '_temp';
- $this->log( "Migrating $name table to $name_temp..." );
-
- $table_temp = $this->dbw->tableName( $name_temp );
-
- // Create temporary table; we're going to copy everything in there,
- // then at the end rename the final tables into place.
- $def = str_replace( '$1', $table_temp, $tabledef );
- $this->dbw->query( $def, __METHOD__ );
-
- $numRecords = $this->dbw->selectField( $name, 'COUNT(*)', '', __METHOD__ );
- $this->setChunkScale( 100, $numRecords, $name_temp, __METHOD__ );
-
- // Pull all records from the second, streaming database connection.
- $sourceFields = array_keys( array_filter( $fields, 'FiveUpgrade::notUpgradeNull' ) );
- $result = $this->dbr->select( $name,
- $sourceFields,
- '',
- __METHOD__ );
-
- $add = array();
- foreach ( $result as $row ) {
- $copy = array();
- foreach ( $fields as $field => $source ) {
- if ( $source === MW_UPGRADE_COPY ) {
- $copy[$field] = $row->$field;
- } elseif ( $source === MW_UPGRADE_ENCODE ) {
- $copy[$field] = $this->conv( $row->$field );
- } elseif ( $source === MW_UPGRADE_NULL ) {
- $copy[$field] = null;
- } else {
- $this->log( "Unknown field copy type: $field => $source" );
- }
- }
- if ( is_callable( $callback ) ) {
- $copy = call_user_func( $callback, $row, $copy );
- }
- $add[] = $copy;
- $this->addChunk( $add );
- }
- $this->lastChunk( $add );
-
- $this->log( "Done converting $name." );
- $this->cleanupSwaps[] = $name;
- }
-
- function upgradePage() {
- $chunksize = 100;
-
- if ( $this->dbw->tableExists( 'page' ) ) {
- $this->error( 'Page table already exists.', true );
- }
-
- $this->log( "Checking cur table for unique title index and applying if necessary" );
- $this->checkDupes();
-
- $this->log( "...converting from cur/old to page/revision/text DB structure." );
-
- list ( $cur, $old, $page, $revision, $text ) = $this->dbw->tableNamesN( 'cur', 'old', 'page', 'revision', 'text' );
-
- $this->log( "Creating page and revision tables..." );
- $this->dbw->query( "CREATE TABLE $page (
- page_id int(8) unsigned NOT NULL auto_increment,
- page_namespace int NOT NULL,
- page_title varchar(255) binary NOT NULL,
- page_restrictions tinyblob NOT NULL default '',
- page_counter bigint(20) unsigned NOT NULL default '0',
- page_is_redirect tinyint(1) unsigned NOT NULL default '0',
- page_is_new tinyint(1) unsigned NOT NULL default '0',
- page_random real unsigned NOT NULL,
- page_touched char(14) binary NOT NULL default '',
- page_latest int(8) unsigned NOT NULL,
- page_len int(8) unsigned NOT NULL,
-
- PRIMARY KEY page_id (page_id),
- UNIQUE INDEX name_title (page_namespace,page_title),
- INDEX (page_random),
- INDEX (page_len)
- ) TYPE=InnoDB", __METHOD__ );
- $this->dbw->query( "CREATE TABLE $revision (
- rev_id int(8) unsigned NOT NULL auto_increment,
- rev_page int(8) unsigned NOT NULL,
- rev_text_id int(8) unsigned NOT NULL,
- rev_comment tinyblob NOT NULL default '',
- rev_user int(5) unsigned NOT NULL default '0',
- rev_user_text varchar(255) binary NOT NULL default '',
- rev_timestamp char(14) binary NOT NULL default '',
- rev_minor_edit tinyint(1) unsigned NOT NULL default '0',
- rev_deleted tinyint(1) unsigned NOT NULL default '0',
-
- PRIMARY KEY rev_page_id (rev_page, rev_id),
- UNIQUE INDEX rev_id (rev_id),
- INDEX rev_timestamp (rev_timestamp),
- INDEX page_timestamp (rev_page,rev_timestamp),
- INDEX user_timestamp (rev_user,rev_timestamp),
- INDEX usertext_timestamp (rev_user_text,rev_timestamp)
- ) TYPE=InnoDB", __METHOD__ );
-
- $maxold = intval( $this->dbw->selectField( 'old', 'max(old_id)', '', __METHOD__ ) );
- $this->log( "Last old record is {$maxold}" );
-
- global $wgLegacySchemaConversion;
- if ( $wgLegacySchemaConversion ) {
- // Create HistoryBlobCurStub entries.
- // Text will be pulled from the leftover 'cur' table at runtime.
- echo "......Moving metadata from cur; using blob references to text in cur table.\n";
- $cur_text = "concat('O:18:\"historyblobcurstub\":1:{s:6:\"mCurId\";i:',cur_id,';}')";
- $cur_flags = "'object'";
- } else {
- // Copy all cur text in immediately: this may take longer but avoids
- // having to keep an extra table around.
- echo "......Moving text from cur.\n";
- $cur_text = 'cur_text';
- $cur_flags = "''";
- }
-
- $maxcur = $this->dbw->selectField( 'cur', 'max(cur_id)', '', __METHOD__ );
- $this->log( "Last cur entry is $maxcur" );
-
- /**
- * Copy placeholder records for each page's current version into old
- * Don't do any conversion here; text records are converted at runtime
- * based on the flags (and may be originally binary!) while the meta
- * fields will be converted in the old -> rev and cur -> page steps.
- */
- $this->setChunkScale( $chunksize, $maxcur, 'old', __METHOD__ );
- $result = $this->dbr->query(
- "SELECT cur_id, cur_namespace, cur_title, $cur_text AS text, cur_comment,
- cur_user, cur_user_text, cur_timestamp, cur_minor_edit, $cur_flags AS flags
- FROM $cur
- ORDER BY cur_id", __METHOD__ );
- $add = array();
- foreach ( $result as $row ) {
- $add[] = array(
- 'old_namespace' => $row->cur_namespace,
- 'old_title' => $row->cur_title,
- 'old_text' => $row->text,
- 'old_comment' => $row->cur_comment,
- 'old_user' => $row->cur_user,
- 'old_user_text' => $row->cur_user_text,
- 'old_timestamp' => $row->cur_timestamp,
- 'old_minor_edit' => $row->cur_minor_edit,
- 'old_flags' => $row->flags );
- $this->addChunk( $add, $row->cur_id );
- }
- $this->lastChunk( $add );
-
- /**
- * Copy revision metadata from old into revision.
- * We'll also do UTF-8 conversion of usernames and comments.
- */
- # $newmaxold = $this->dbw->selectField( 'old', 'max(old_id)', '', __METHOD__ );
- # $this->setChunkScale( $chunksize, $newmaxold, 'revision', __METHOD__ );
- # $countold = $this->dbw->selectField( 'old', 'count(old_id)', '', __METHOD__ );
- $countold = $this->dbw->selectField( 'old', 'max(old_id)', '', __METHOD__ );
- $this->setChunkScale( $chunksize, $countold, 'revision', __METHOD__ );
-
- $this->log( "......Setting up revision table." );
- $result = $this->dbr->query(
- "SELECT old_id, cur_id, old_comment, old_user, old_user_text,
- old_timestamp, old_minor_edit
- FROM $old,$cur WHERE old_namespace=cur_namespace AND old_title=cur_title",
- __METHOD__ );
-
- $add = array();
- foreach ( $result as $row ) {
- $add[] = array(
- 'rev_id' => $row->old_id,
- 'rev_page' => $row->cur_id,
- 'rev_text_id' => $row->old_id,
- 'rev_comment' => $this->conv( $row->old_comment ),
- 'rev_user' => $row->old_user,
- 'rev_user_text' => $this->conv( $row->old_user_text ),
- 'rev_timestamp' => $row->old_timestamp,
- 'rev_minor_edit' => $row->old_minor_edit );
- $this->addChunk( $add );
- }
- $this->lastChunk( $add );
-
-
- /**
- * Copy page metadata from cur into page.
- * We'll also do UTF-8 conversion of titles.
- */
- $this->log( "......Setting up page table." );
- $this->setChunkScale( $chunksize, $maxcur, 'page', __METHOD__ );
- $result = $this->dbr->query( "
- SELECT cur_id, cur_namespace, cur_title, cur_restrictions, cur_counter, cur_is_redirect, cur_is_new,
- cur_random, cur_touched, rev_id, LENGTH(cur_text) AS len
- FROM $cur,$revision
- WHERE cur_id=rev_page AND rev_timestamp=cur_timestamp AND rev_id > {$maxold}
- ORDER BY cur_id", __METHOD__ );
- $add = array();
- foreach ( $result as $row ) {
- $add[] = array(
- 'page_id' => $row->cur_id,
- 'page_namespace' => $row->cur_namespace,
- 'page_title' => $this->conv( $row->cur_title ),
- 'page_restrictions' => $row->cur_restrictions,
- 'page_counter' => $row->cur_counter,
- 'page_is_redirect' => $row->cur_is_redirect,
- 'page_is_new' => $row->cur_is_new,
- 'page_random' => $row->cur_random,
- 'page_touched' => $this->dbw->timestamp(),
- 'page_latest' => $row->rev_id,
- 'page_len' => $row->len );
- # $this->addChunk( $add, $row->cur_id );
- $this->addChunk( $add );
- }
- $this->lastChunk( $add );
-
- $this->log( "...done with cur/old -> page/revision." );
- }
-
- function upgradeLinks() {
- $chunksize = 200;
- list ( $links, $brokenlinks, $pagelinks, $cur ) = $this->dbw->tableNamesN( 'links', 'brokenlinks', 'pagelinks', 'cur' );
-
- $this->log( 'Checking for interwiki table change in case of bogus items...' );
- if ( $this->dbw->fieldExists( 'interwiki', 'iw_trans' ) ) {
- $this->log( 'interwiki has iw_trans.' );
- } else {
- global $IP;
- $this->log( 'adding iw_trans...' );
- $this->dbw->sourceFile( $IP . '/maintenance/archives/patch-interwiki-trans.sql' );
- $this->log( 'added iw_trans.' );
- }
-
- $this->log( 'Creating pagelinks table...' );
- $this->dbw->query( "
-CREATE TABLE $pagelinks (
- -- Key to the page_id of the page containing the link.
- pl_from int(8) unsigned NOT NULL default '0',
-
- -- Key to page_namespace/page_title of the target page.
- -- The target page may or may not exist, and due to renames
- -- and deletions may refer to different page records as time
- -- goes by.
- pl_namespace int NOT NULL default '0',
- pl_title varchar(255) binary NOT NULL default '',
-
- UNIQUE KEY pl_from(pl_from,pl_namespace,pl_title),
- KEY (pl_namespace,pl_title)
-
-) TYPE=InnoDB" );
-
- $this->log( 'Importing live links -> pagelinks' );
- $nlinks = $this->dbw->selectField( 'links', 'count(*)', '', __METHOD__ );
- if ( $nlinks ) {
- $this->setChunkScale( $chunksize, $nlinks, 'pagelinks', __METHOD__ );
- $result = $this->dbr->query( "
- SELECT l_from,cur_namespace,cur_title
- FROM $links, $cur
- WHERE l_to=cur_id", __METHOD__ );
- $add = array();
- foreach ( $result as $row ) {
- $add[] = array(
- 'pl_from' => $row->l_from,
- 'pl_namespace' => $row->cur_namespace,
- 'pl_title' => $this->conv( $row->cur_title ) );
- $this->addChunk( $add );
- }
- $this->lastChunk( $add );
- } else {
- $this->log( 'no links!' );
- }
-
- $this->log( 'Importing brokenlinks -> pagelinks' );
- $nbrokenlinks = $this->dbw->selectField( 'brokenlinks', 'count(*)', '', __METHOD__ );
- if ( $nbrokenlinks ) {
- $this->setChunkScale( $chunksize, $nbrokenlinks, 'pagelinks', __METHOD__ );
- $result = $this->dbr->query(
- "SELECT bl_from, bl_to FROM $brokenlinks",
- __METHOD__ );
- $add = array();
- foreach ( $result as $row ) {
- $pagename = $this->conv( $row->bl_to );
- $title = Title::newFromText( $pagename );
- if ( is_null( $title ) ) {
- $this->log( "** invalid brokenlink: $row->bl_from -> '$pagename' (converted from '$row->bl_to')" );
- } else {
- $add[] = array(
- 'pl_from' => $row->bl_from,
- 'pl_namespace' => $title->getNamespace(),
- 'pl_title' => $title->getDBkey() );
- $this->addChunk( $add );
- }
- }
- $this->lastChunk( $add );
- } else {
- $this->log( 'no brokenlinks!' );
- }
-
- $this->log( 'Done with links.' );
- }
-
- function userDupeCallback( $str ) {
- echo $str;
- }
-
- function upgradeUser() {
- // Apply unique index, if necessary:
- $duper = new UserDupes( $this->dbw, array( $this, 'userDupeCallback' ) );
- if ( $duper->hasUniqueIndex() ) {
- $this->log( "Already have unique user_name index." );
- } else {
- $this->log( "Clearing user duplicates..." );
- if ( !$duper->clearDupes() ) {
- $this->log( "WARNING: Duplicate user accounts, may explode!" );
- }
- }
-
- $tabledef = <<<END
-CREATE TABLE $1 (
- user_id int(5) unsigned NOT NULL auto_increment,
- user_name varchar(255) binary NOT NULL default '',
- user_real_name varchar(255) binary NOT NULL default '',
- user_password tinyblob NOT NULL default '',
- user_newpassword tinyblob NOT NULL default '',
- user_email tinytext NOT NULL default '',
- user_options blob NOT NULL default '',
- user_touched char(14) binary NOT NULL default '',
- user_token char(32) binary NOT NULL default '',
- user_email_authenticated CHAR(14) BINARY,
- user_email_token CHAR(32) BINARY,
- user_email_token_expires CHAR(14) BINARY,
-
- PRIMARY KEY user_id (user_id),
- UNIQUE INDEX user_name (user_name),
- INDEX (user_email_token)
-
-) TYPE=InnoDB
-END;
- $fields = array(
- 'user_id' => MW_UPGRADE_COPY,
- 'user_name' => MW_UPGRADE_ENCODE,
- 'user_real_name' => MW_UPGRADE_ENCODE,
- 'user_password' => MW_UPGRADE_COPY,
- 'user_newpassword' => MW_UPGRADE_COPY,
- 'user_email' => MW_UPGRADE_ENCODE,
- 'user_options' => MW_UPGRADE_ENCODE,
- 'user_touched' => MW_UPGRADE_CALLBACK,
- 'user_token' => MW_UPGRADE_COPY,
- 'user_email_authenticated' => MW_UPGRADE_CALLBACK,
- 'user_email_token' => MW_UPGRADE_NULL,
- 'user_email_token_expires' => MW_UPGRADE_NULL );
- $this->copyTable( 'user', $tabledef, $fields,
- array( &$this, 'userCallback' ) );
- }
-
- function userCallback( $row, $copy ) {
- $now = $this->dbw->timestamp();
- $copy['user_touched'] = $now;
- $copy['user_email_authenticated'] = $this->emailAuth ? $now : null;
- return $copy;
- }
-
- function upgradeImage() {
- $tabledef = <<<END
-CREATE TABLE $1 (
- img_name varchar(255) binary NOT NULL default '',
- img_size int(8) unsigned NOT NULL default '0',
- img_width int(5) NOT NULL default '0',
- img_height int(5) NOT NULL default '0',
- img_metadata mediumblob NOT NULL,
- img_bits int(3) 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") NOT NULL default "unknown",
- img_minor_mime varchar(32) NOT NULL default "unknown",
- img_description tinyblob NOT NULL default '',
- img_user int(5) unsigned NOT NULL default '0',
- img_user_text varchar(255) binary NOT NULL default '',
- img_timestamp char(14) binary NOT NULL default '',
-
- PRIMARY KEY img_name (img_name),
- INDEX img_size (img_size),
- INDEX img_timestamp (img_timestamp)
-) TYPE=InnoDB
-END;
- $fields = array(
- 'img_name' => MW_UPGRADE_ENCODE,
- 'img_size' => MW_UPGRADE_COPY,
- 'img_width' => MW_UPGRADE_CALLBACK,
- 'img_height' => MW_UPGRADE_CALLBACK,
- 'img_metadata' => MW_UPGRADE_CALLBACK,
- 'img_bits' => MW_UPGRADE_CALLBACK,
- 'img_media_type' => MW_UPGRADE_CALLBACK,
- 'img_major_mime' => MW_UPGRADE_CALLBACK,
- 'img_minor_mime' => MW_UPGRADE_CALLBACK,
- 'img_description' => MW_UPGRADE_ENCODE,
- 'img_user' => MW_UPGRADE_COPY,
- 'img_user_text' => MW_UPGRADE_ENCODE,
- 'img_timestamp' => MW_UPGRADE_COPY );
- $this->copyTable( 'image', $tabledef, $fields,
- array( &$this, 'imageCallback' ) );
- }
-
- function imageCallback( $row, $copy ) {
- if ( !$this->hasOption( 'noimage' ) ) {
- // Fill in the new image info fields
- $info = $this->imageInfo( $row->img_name );
-
- $copy['img_width' ] = $info['width'];
- $copy['img_height' ] = $info['height'];
- $copy['img_metadata' ] = ""; // loaded on-demand
- $copy['img_bits' ] = $info['bits'];
- $copy['img_media_type'] = $info['media'];
- $copy['img_major_mime'] = $info['major'];
- $copy['img_minor_mime'] = $info['minor'];
- }
-
- // If doing UTF8 conversion the file must be renamed
- $this->renameFile( $row->img_name, 'wfImageDir' );
-
- return $copy;
- }
-
- function imageInfo( $filename ) {
- $info = array(
- 'width' => 0,
- 'height' => 0,
- 'bits' => 0,
- 'media' => '',
- 'major' => '',
- 'minor' => '' );
-
- $magic = MimeMagic::singleton();
- $mime = $magic->guessMimeType( $filename, true );
- list( $info['major'], $info['minor'] ) = explode( '/', $mime );
-
- $info['media'] = $magic->getMediaType( $filename, $mime );
-
- $image = UnregisteredLocalFile::newFromPath( $filename, $mime );
-
- $info['width'] = $image->getWidth();
- $info['height'] = $image->getHeight();
-
- $gis = $image->getImageSize( $filename );
- if ( isset( $gis['bits'] ) ) {
- $info['bits'] = $gis['bits'];
- }
-
- return $info;
- }
-
-
- /**
- * Truncate a table.
- * @param string $table The table name to be truncated
- */
- function clearTable( $table ) {
- print "Clearing $table...\n";
- $tableName = $this->db->tableName( $table );
- $this->db->query( "TRUNCATE $tableName" );
- }
-
- /**
- * Rename a given image or archived image file to the converted filename,
- * leaving a symlink for URL compatibility.
- *
- * @param $oldname string pre-conversion filename
- * @param $subdirCallback string
- * @param $basename string pre-conversion base filename for dir hashing, if an archive
- * @return bool|string
- * @access private
- */
- function renameFile( $oldname, $subdirCallback = 'wfImageDir', $basename = null ) {
- $newname = $this->conv( $oldname );
- if ( $newname == $oldname ) {
- // No need to rename; another field triggered this row.
- return false;
- }
-
- if ( is_null( $basename ) ) $basename = $oldname;
- $ubasename = $this->conv( $basename );
- $oldpath = call_user_func( $subdirCallback, $basename ) . '/' . $oldname;
- $newpath = call_user_func( $subdirCallback, $ubasename ) . '/' . $newname;
-
- $this->log( "$oldpath -> $newpath" );
- if ( rename( $oldpath, $newpath ) ) {
- $relpath = wfRelativePath( $newpath, dirname( $oldpath ) );
- if ( !symlink( $relpath, $oldpath ) ) {
- $this->log( "... symlink failed!" );
- }
- return $newname;
- } else {
- $this->log( "... rename failed!" );
- return false;
- }
- }
-
- function upgradeOldImage() {
- $tabledef = <<<END
-CREATE TABLE $1 (
- -- Base filename: key to image.img_name
- oi_name varchar(255) binary NOT NULL default '',
-
- -- Filename of the archived file.
- -- This is generally a timestamp and '!' prepended to the base name.
- oi_archive_name varchar(255) binary NOT NULL default '',
-
- -- Other fields as in image...
- oi_size int(8) unsigned NOT NULL default 0,
- oi_width int(5) NOT NULL default 0,
- oi_height int(5) NOT NULL default 0,
- oi_bits int(3) NOT NULL default 0,
- oi_description tinyblob NOT NULL default '',
- oi_user int(5) unsigned NOT NULL default '0',
- oi_user_text varchar(255) binary NOT NULL default '',
- oi_timestamp char(14) binary NOT NULL default '',
-
- INDEX oi_name (oi_name(10))
-
-) TYPE=InnoDB;
-END;
- $fields = array(
- 'oi_name' => MW_UPGRADE_ENCODE,
- 'oi_archive_name' => MW_UPGRADE_ENCODE,
- 'oi_size' => MW_UPGRADE_COPY,
- 'oi_width' => MW_UPGRADE_CALLBACK,
- 'oi_height' => MW_UPGRADE_CALLBACK,
- 'oi_bits' => MW_UPGRADE_CALLBACK,
- 'oi_description' => MW_UPGRADE_ENCODE,
- 'oi_user' => MW_UPGRADE_COPY,
- 'oi_user_text' => MW_UPGRADE_ENCODE,
- 'oi_timestamp' => MW_UPGRADE_COPY );
- $this->copyTable( 'oldimage', $tabledef, $fields,
- array( &$this, 'oldimageCallback' ) );
- }
-
- function oldimageCallback( $row, $copy ) {
- global $options;
- if ( !isset( $options['noimage'] ) ) {
- // Fill in the new image info fields
- $info = $this->imageInfo( $row->oi_archive_name, 'wfImageArchiveDir', $row->oi_name );
- $copy['oi_width' ] = $info['width' ];
- $copy['oi_height'] = $info['height'];
- $copy['oi_bits' ] = $info['bits' ];
- }
-
- // If doing UTF8 conversion the file must be renamed
- $this->renameFile( $row->oi_archive_name, 'wfImageArchiveDir', $row->oi_name );
-
- return $copy;
- }
-
-
- function upgradeWatchlist() {
- $chunksize = 100;
-
- list ( $watchlist, $watchlist_temp ) = $this->dbw->tableNamesN( 'watchlist', 'watchlist_temp' );
-
- $this->log( 'Migrating watchlist table to watchlist_temp...' );
- $this->dbw->query(
-"CREATE TABLE $watchlist_temp (
- -- Key to user_id
- wl_user int(5) unsigned NOT NULL,
-
- -- Key to page_namespace/page_title
- -- Note that users may watch patches which do not exist yet,
- -- or existed in the past but have been deleted.
- wl_namespace int NOT NULL default '0',
- wl_title varchar(255) binary NOT NULL default '',
-
- -- Timestamp when user was last sent a notification e-mail;
- -- cleared when the user visits the page.
- -- FIXME: add proper null support etc
- wl_notificationtimestamp varchar(14) binary NOT NULL default '0',
-
- UNIQUE KEY (wl_user, wl_namespace, wl_title),
- KEY namespace_title (wl_namespace,wl_title)
-
-) TYPE=InnoDB;", __METHOD__ );
-
- // Fix encoding for Latin-1 upgrades, add some fields,
- // and double article to article+talk pairs
- $numwatched = $this->dbw->selectField( 'watchlist', 'count(*)', '', __METHOD__ );
-
- $this->setChunkScale( $chunksize, $numwatched * 2, 'watchlist_temp', __METHOD__ );
- $result = $this->dbr->select( 'watchlist',
- array(
- 'wl_user',
- 'wl_namespace',
- 'wl_title' ),
- '',
- __METHOD__ );
-
- $add = array();
- foreach ( $result as $row ) {
- $add[] = array(
- 'wl_user' => $row->wl_user,
- 'wl_namespace' => MWNamespace::getSubject( $row->wl_namespace ),
- 'wl_title' => $this->conv( $row->wl_title ),
- 'wl_notificationtimestamp' => '0' );
- $this->addChunk( $add );
-
- $add[] = array(
- 'wl_user' => $row->wl_user,
- 'wl_namespace' => MWNamespace::getTalk( $row->wl_namespace ),
- 'wl_title' => $this->conv( $row->wl_title ),
- 'wl_notificationtimestamp' => '0' );
- $this->addChunk( $add );
- }
- $this->lastChunk( $add );
-
- $this->log( 'Done converting watchlist.' );
- $this->cleanupSwaps[] = 'watchlist';
- }
-
- function upgradeLogging() {
- $tabledef = <<<ENDS
-CREATE TABLE $1 (
- -- Symbolic keys for the general log type and the action type
- -- within the log. The output format will be controlled by the
- -- action field, but only the type controls categorization.
- log_type char(10) NOT NULL default '',
- log_action char(10) NOT NULL default '',
-
- -- Timestamp. Duh.
- log_timestamp char(14) NOT NULL default '19700101000000',
-
- -- The user who performed this action; key to user_id
- log_user int unsigned NOT NULL 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,
- log_title varchar(255) binary NOT NULL default '',
-
- -- Freeform text. Interpreted as edit history comments.
- log_comment varchar(255) NOT NULL default '',
-
- -- LF separated list of miscellaneous parameters
- log_params blob NOT NULL default '',
-
- KEY type_time (log_type, log_timestamp),
- KEY user_time (log_user, log_timestamp),
- KEY page_time (log_namespace, log_title, log_timestamp)
-
-) TYPE=InnoDB
-ENDS;
- $fields = array(
- 'log_type' => MW_UPGRADE_COPY,
- 'log_action' => MW_UPGRADE_COPY,
- 'log_timestamp' => MW_UPGRADE_COPY,
- 'log_user' => MW_UPGRADE_COPY,
- 'log_namespace' => MW_UPGRADE_COPY,
- 'log_title' => MW_UPGRADE_ENCODE,
- 'log_comment' => MW_UPGRADE_ENCODE,
- 'log_params' => MW_UPGRADE_ENCODE );
- $this->copyTable( 'logging', $tabledef, $fields );
- }
-
- function upgradeArchive() {
- $tabledef = <<<ENDS
-CREATE TABLE $1 (
- ar_namespace int NOT NULL default '0',
- ar_title varchar(255) binary NOT NULL default '',
- ar_text mediumblob NOT NULL default '',
-
- ar_comment tinyblob NOT NULL default '',
- ar_user int(5) unsigned NOT NULL default '0',
- ar_user_text varchar(255) binary NOT NULL,
- ar_timestamp char(14) binary NOT NULL default '',
- ar_minor_edit tinyint(1) NOT NULL default '0',
-
- ar_flags tinyblob NOT NULL default '',
-
- ar_rev_id int(8) unsigned,
- ar_text_id int(8) unsigned,
-
- KEY name_title_timestamp (ar_namespace,ar_title,ar_timestamp)
-
-) TYPE=InnoDB
-ENDS;
- $fields = array(
- 'ar_namespace' => MW_UPGRADE_COPY,
- 'ar_title' => MW_UPGRADE_ENCODE,
- 'ar_text' => MW_UPGRADE_COPY,
- 'ar_comment' => MW_UPGRADE_ENCODE,
- 'ar_user' => MW_UPGRADE_COPY,
- 'ar_user_text' => MW_UPGRADE_ENCODE,
- 'ar_timestamp' => MW_UPGRADE_COPY,
- 'ar_minor_edit' => MW_UPGRADE_COPY,
- 'ar_flags' => MW_UPGRADE_COPY,
- 'ar_rev_id' => MW_UPGRADE_NULL,
- 'ar_text_id' => MW_UPGRADE_NULL );
- $this->copyTable( 'archive', $tabledef, $fields );
- }
-
- function upgradeImagelinks() {
- global $wgUseLatin1;
- if ( $wgUseLatin1 ) {
- $tabledef = <<<ENDS
-CREATE TABLE $1 (
- -- Key to page_id of the page containing the image / media link.
- il_from int(8) unsigned NOT NULL default '0',
-
- -- Filename of target image.
- -- This is also the page_title of the file's description page;
- -- all such pages are in namespace 6 (NS_FILE).
- il_to varchar(255) binary NOT NULL default '',
-
- UNIQUE KEY il_from(il_from,il_to),
- KEY (il_to)
-
-) TYPE=InnoDB
-ENDS;
- $fields = array(
- 'il_from' => MW_UPGRADE_COPY,
- 'il_to' => MW_UPGRADE_ENCODE );
- $this->copyTable( 'imagelinks', $tabledef, $fields );
- }
- }
-
- function upgradeCategorylinks() {
- global $wgUseLatin1;
- if ( $wgUseLatin1 ) {
- $tabledef = <<<ENDS
-CREATE TABLE $1 (
- cl_from int(8) unsigned NOT NULL default '0',
- cl_to varchar(255) binary NOT NULL default '',
- cl_sortkey varchar(86) binary NOT NULL default '',
- cl_timestamp timestamp NOT NULL,
-
- UNIQUE KEY cl_from(cl_from,cl_to),
- KEY cl_sortkey(cl_to,cl_sortkey),
- KEY cl_timestamp(cl_to,cl_timestamp)
-) TYPE=InnoDB
-ENDS;
- $fields = array(
- 'cl_from' => MW_UPGRADE_COPY,
- 'cl_to' => MW_UPGRADE_ENCODE,
- 'cl_sortkey' => MW_UPGRADE_ENCODE,
- 'cl_timestamp' => MW_UPGRADE_COPY );
- $this->copyTable( 'categorylinks', $tabledef, $fields );
- }
- }
-
- function upgradeIpblocks() {
- global $wgUseLatin1;
- if ( $wgUseLatin1 ) {
- $tabledef = <<<ENDS
-CREATE TABLE $1 (
- ipb_id int(8) NOT NULL auto_increment,
- ipb_address varchar(40) binary NOT NULL default '',
- ipb_user int(8) unsigned NOT NULL default '0',
- ipb_by int(8) unsigned NOT NULL default '0',
- ipb_reason tinyblob NOT NULL default '',
- ipb_timestamp char(14) binary NOT NULL default '',
- ipb_auto tinyint(1) NOT NULL default '0',
- ipb_expiry char(14) binary NOT NULL default '',
-
- PRIMARY KEY ipb_id (ipb_id),
- INDEX ipb_address (ipb_address),
- INDEX ipb_user (ipb_user)
-
-) TYPE=InnoDB
-ENDS;
- $fields = array(
- 'ipb_id' => MW_UPGRADE_COPY,
- 'ipb_address' => MW_UPGRADE_COPY,
- 'ipb_user' => MW_UPGRADE_COPY,
- 'ipb_by' => MW_UPGRADE_COPY,
- 'ipb_reason' => MW_UPGRADE_ENCODE,
- 'ipb_timestamp' => MW_UPGRADE_COPY,
- 'ipb_auto' => MW_UPGRADE_COPY,
- 'ipb_expiry' => MW_UPGRADE_COPY );
- $this->copyTable( 'ipblocks', $tabledef, $fields );
- }
- }
-
- function upgradeRecentchanges() {
- // There's a format change in the namespace field
- $tabledef = <<<ENDS
-CREATE TABLE $1 (
- rc_id int(8) NOT NULL auto_increment,
- rc_timestamp varchar(14) binary NOT NULL default '',
- rc_cur_time varchar(14) binary NOT NULL default '',
-
- rc_user int(10) unsigned NOT NULL default '0',
- rc_user_text varchar(255) binary NOT NULL default '',
-
- rc_namespace int NOT NULL default '0',
- rc_title varchar(255) binary NOT NULL default '',
-
- rc_comment varchar(255) binary NOT NULL default '',
- rc_minor tinyint(3) unsigned NOT NULL default '0',
-
- rc_bot tinyint(3) unsigned NOT NULL default '0',
- rc_new tinyint(3) unsigned NOT NULL default '0',
-
- rc_cur_id int(10) unsigned NOT NULL default '0',
- rc_this_oldid int(10) unsigned NOT NULL default '0',
- rc_last_oldid int(10) unsigned NOT NULL default '0',
-
- rc_type tinyint(3) unsigned NOT NULL default '0',
- rc_moved_to_ns tinyint(3) unsigned NOT NULL default '0',
- rc_moved_to_title varchar(255) binary NOT NULL default '',
-
- rc_patrolled tinyint(3) unsigned NOT NULL default '0',
-
- rc_ip char(15) NOT NULL default '',
-
- PRIMARY KEY rc_id (rc_id),
- INDEX rc_timestamp (rc_timestamp),
- INDEX rc_namespace_title (rc_namespace, rc_title),
- INDEX rc_cur_id (rc_cur_id),
- INDEX new_name_timestamp(rc_new,rc_namespace,rc_timestamp),
- INDEX rc_ip (rc_ip)
-
-) TYPE=InnoDB
-ENDS;
- $fields = array(
- 'rc_id' => MW_UPGRADE_COPY,
- 'rc_timestamp' => MW_UPGRADE_COPY,
- 'rc_cur_time' => MW_UPGRADE_COPY,
- 'rc_user' => MW_UPGRADE_COPY,
- 'rc_user_text' => MW_UPGRADE_ENCODE,
- 'rc_namespace' => MW_UPGRADE_COPY,
- 'rc_title' => MW_UPGRADE_ENCODE,
- 'rc_comment' => MW_UPGRADE_ENCODE,
- 'rc_minor' => MW_UPGRADE_COPY,
- 'rc_bot' => MW_UPGRADE_COPY,
- 'rc_new' => MW_UPGRADE_COPY,
- 'rc_cur_id' => MW_UPGRADE_COPY,
- 'rc_this_oldid' => MW_UPGRADE_COPY,
- 'rc_last_oldid' => MW_UPGRADE_COPY,
- 'rc_type' => MW_UPGRADE_COPY,
- 'rc_moved_to_ns' => MW_UPGRADE_COPY,
- 'rc_moved_to_title' => MW_UPGRADE_ENCODE,
- 'rc_patrolled' => MW_UPGRADE_COPY,
- 'rc_ip' => MW_UPGRADE_COPY );
- $this->copyTable( 'recentchanges', $tabledef, $fields );
- }
-
- function upgradeQuerycache() {
- // There's a format change in the namespace field
- $tabledef = <<<ENDS
-CREATE TABLE $1 (
- -- A key name, generally the base name of of the special page.
- qc_type char(32) NOT NULL,
-
- -- Some sort of stored value. Sizes, counts...
- qc_value int(5) unsigned NOT NULL default '0',
-
- -- Target namespace+title
- qc_namespace int NOT NULL default '0',
- qc_title char(255) binary NOT NULL default '',
-
- KEY (qc_type,qc_value)
-
-) TYPE=InnoDB
-ENDS;
- $fields = array(
- 'qc_type' => MW_UPGRADE_COPY,
- 'qc_value' => MW_UPGRADE_COPY,
- 'qc_namespace' => MW_UPGRADE_COPY,
- 'qc_title' => MW_UPGRADE_ENCODE );
- $this->copyTable( 'querycache', $tabledef, $fields );
- }
-
- /**
- * Check for duplicate rows in "cur" table and move duplicates entries in
- * "old" table.
- *
- * This was in cleanupDupes.inc before.
- */
- function checkDupes() {
- $dbw = wfGetDB( DB_MASTER );
- if ( $dbw->indexExists( 'cur', 'name_title' ) &&
- $dbw->indexUnique( 'cur', 'name_title' ) ) {
- echo wfWikiID() . ": cur table has the current unique index; no duplicate entries.\n";
- return;
- } elseif ( $dbw->indexExists( 'cur', 'name_title_dup_prevention' ) ) {
- echo wfWikiID() . ": cur table has a temporary name_title_dup_prevention unique index; no duplicate entries.\n";
- return;
- }
-
- echo wfWikiID() . ": cur table has the old non-unique index and may have duplicate entries.\n";
-
- $dbw = wfGetDB( DB_MASTER );
- $cur = $dbw->tableName( 'cur' );
- $old = $dbw->tableName( 'old' );
- $dbw->query( "LOCK TABLES $cur WRITE, $old WRITE" );
- echo "Checking for duplicate cur table entries... (this may take a while on a large wiki)\n";
- $res = $dbw->query( <<<END
-SELECT cur_namespace,cur_title,count(*) as c,min(cur_id) as id
- FROM $cur
- GROUP BY cur_namespace,cur_title
-HAVING c > 1
-END
- );
- $n = $dbw->numRows( $res );
- echo "Found $n titles with duplicate entries.\n";
- if ( $n > 0 ) {
- echo "Correcting...\n";
- foreach ( $res as $row ) {
- $ns = intval( $row->cur_namespace );
- $title = $dbw->addQuotes( $row->cur_title );
-
- # Get the first responding ID; that'll be the one we keep.
- $id = $dbw->selectField( 'cur', 'cur_id', array(
- 'cur_namespace' => $row->cur_namespace,
- 'cur_title' => $row->cur_title ) );
-
- echo "$ns:$row->cur_title (canonical ID $id)\n";
- if ( $id != $row->id ) {
- echo " ** minimum ID $row->id; ";
- $timeMin = $dbw->selectField( 'cur', 'cur_timestamp', array(
- 'cur_id' => $row->id ) );
- $timeFirst = $dbw->selectField( 'cur', 'cur_timestamp', array(
- 'cur_id' => $id ) );
- if ( $timeMin == $timeFirst ) {
- echo "timestamps match at $timeFirst; ok\n";
- } else {
- echo "timestamps don't match! min: $timeMin, first: $timeFirst; ";
- if ( $timeMin > $timeFirst ) {
- $id = $row->id;
- echo "keeping minimum: $id\n";
- } else {
- echo "keeping first: $id\n";
- }
- }
- }
-
- $dbw->query( <<<END
-INSERT
- INTO $old
- (old_namespace, old_title, old_text,
- old_comment, old_user, old_user_text,
- old_timestamp, old_minor_edit, old_flags,
- inverse_timestamp)
-SELECT cur_namespace, cur_title, cur_text,
- cur_comment, cur_user, cur_user_text,
- cur_timestamp, cur_minor_edit, '',
- inverse_timestamp
- FROM $cur
- WHERE cur_namespace=$ns
- AND cur_title=$title
- AND cur_id != $id
-END
- );
- $dbw->query( <<<END
-DELETE
- FROM $cur
- WHERE cur_namespace=$ns
- AND cur_title=$title
- AND cur_id != $id
-END
- );
- }
- }
- $dbw->query( 'UNLOCK TABLES' );
- echo "Done.\n";
- }
-
- /**
- * Rename all our temporary tables into final place.
- * We've left things in place so a read-only wiki can continue running
- * on the old code during all this.
- */
- function upgradeCleanup() {
- $this->renameTable( 'old', 'text' );
-
- foreach ( $this->cleanupSwaps as $table ) {
- $this->swap( $table );
- }
- }
-
- function renameTable( $from, $to ) {
- $this->log( "Renaming $from to $to..." );
-
- $fromtable = $this->dbw->tableName( $from );
- $totable = $this->dbw->tableName( $to );
- $this->dbw->query( "ALTER TABLE $fromtable RENAME TO $totable" );
- }
-
- function swap( $base ) {
- $this->renameTable( $base, "{$base}_old" );
- $this->renameTable( "{$base}_temp", $base );
- }
-
-}
-
-$maintClass = 'FiveUpgrade';
-require_once( RUN_MAINTENANCE_IF_MAIN );
diff --git a/maintenance/userDupes.inc b/maintenance/userDupes.inc
index 31bae8ed..be45a111 100644
--- a/maintenance/userDupes.inc
+++ b/maintenance/userDupes.inc
@@ -26,13 +26,17 @@
/**
* Look for duplicate user table entries and optionally prune them.
+ *
+ * This is still used by our MysqlUpdater at:
+ * includes/installer/MysqlUpdater.php
+ *
* @ingroup Maintenance
*/
class UserDupes {
- var $db;
- var $reassigned;
- var $trimmed;
- var $failed;
+ private $db;
+ private $reassigned;
+ private $trimmed;
+ private $failed;
private $outputCallback;
function __construct( &$database, $outputCallback ) {
diff --git a/maintenance/userOptions.inc b/maintenance/userOptions.inc
index 2a066579..cbe6b057 100644
--- a/maintenance/userOptions.inc
+++ b/maintenance/userOptions.inc
@@ -108,7 +108,7 @@ class userOptions {
return false;
}
- $this->{ $this->mMode } ( );
+ $this->{ $this->mMode } ();
return true;
}
@@ -117,7 +117,7 @@ class userOptions {
#
/** List default options and their value */
- private function LISTER( ) {
+ private function LISTER() {
$def = User::getDefaultOptions();
ksort( $def );
$maxOpt = 0;
@@ -130,7 +130,7 @@ class userOptions {
}
/** List options usage */
- private function USAGER( ) {
+ private function USAGER() {
$ret = array();
$defaultOptions = User::getDefaultOptions();
@@ -181,7 +181,7 @@ class userOptions {
/** Change our users options */
- private function CHANGER( ) {
+ private function CHANGER() {
$this->warn();
// We list user by user_id from one of the slave database
diff --git a/maintenance/userOptions.php b/maintenance/userOptions.php
index 2181e44d..1e1f24b5 100644
--- a/maintenance/userOptions.php
+++ b/maintenance/userOptions.php
@@ -33,4 +33,3 @@ $uo = new userOptions( $options, $args );
$uo->run();
print "Done.\n";
-
diff --git a/maintenance/waitForSlave.php b/maintenance/waitForSlave.php
index 655be43d..df83928b 100644
--- a/maintenance/waitForSlave.php
+++ b/maintenance/waitForSlave.php
@@ -31,6 +31,7 @@ require_once( __DIR__ . '/Maintenance.php' );
*/
class WaitForSlave extends Maintenance {
public function __construct() {
+ parent::__construct();
$this->addArg( 'maxlag', 'How long to wait for the slaves, default 10 seconds', false );
}
public function execute() {