+ /**
+ * Drop an index from an existing table
+ *
+ * @param $table String: Name of the table to modify
+ * @param $index String: Name of the old index
+ * @param $patch String: Path to the patch file
+ * @param $fullpath Boolean: Whether to treat $patch path as a relative or not
+ */
+ protected function dropIndex( $table, $index, $patch, $fullpath = false ) {
+ if ( $this->db->indexExists( $table, $index, __METHOD__ ) ) {
+ $this->output( "Dropping $index index from table $table... " );
+ $this->applyPatch( $patch, $fullpath );
+ $this->output( "done.\n" );
+ } else {
+ $this->output( "...$index key doesn't exist.\n" );
+ }
+ }
+
+ /**
+ * @param $table string
+ * @param $patch string
+ * @param $fullpath bool
+ */
+ protected function dropTable( $table, $patch, $fullpath = false ) {
+ if ( $this->db->tableExists( $table, __METHOD__ ) ) {
+ $this->output( "Dropping table $table... " );
+ $this->applyPatch( $patch, $fullpath );
+ $this->output( "done.\n" );
+ } else {
+ $this->output( "...$table doesn't exist.\n" );
+ }
+ }
+
+ /**
+ * Modify an existing field
+ *
+ * @param $table String: name of the table to which the field belongs
+ * @param $field String: name of the field to modify
+ * @param $patch String: path to the patch file
+ * @param $fullpath Boolean: whether to treat $patch path as a relative or not
+ */
+ public function modifyField( $table, $field, $patch, $fullpath = false ) {
+ $updateKey = "$table-$field-$patch";
+ if ( !$this->db->tableExists( $table, __METHOD__ ) ) {
+ $this->output( "...$table table does not exist, skipping modify field patch.\n" );
+ } elseif ( !$this->db->fieldExists( $table, $field, __METHOD__ ) ) {
+ $this->output( "...$field field does not exist in $table table, skipping modify field patch.\n" );
+ } elseif( $this->updateRowExists( $updateKey ) ) {
+ $this->output( "...$field in table $table already modified by patch $patch.\n" );
+ } else {
+ $this->output( "Modifying $field field of table $table..." );
+ $this->applyPatch( $patch, $fullpath );
+ $this->insertUpdateRow( $updateKey );
+ $this->output( "done.\n" );
+ }
+ }
+
+ /**
+ * Purge the objectcache table
+ */
+ protected function purgeCache() {
+ # We can't guarantee that the user will be able to use TRUNCATE,
+ # but we know that DELETE is available to us
+ $this->output( "Purging caches..." );
+ $this->db->delete( 'objectcache', '*', __METHOD__ );
+ $this->output( "done.\n" );
+ }
+
+ /**
+ * Check the site_stats table is not properly populated.
+ */
+ protected function checkStats() {
+ $this->output( "...site_stats is populated..." );
+ $row = $this->db->selectRow( 'site_stats', '*', array( 'ss_row_id' => 1 ), __METHOD__ );
+ if ( $row === false ) {
+ $this->output( "data is missing! rebuilding...\n" );
+ } elseif ( isset( $row->site_stats ) && $row->ss_total_pages == -1 ) {
+ $this->output( "missing ss_total_pages, rebuilding...\n" );
+ } else {
+ $this->output( "done.\n" );
+ return;
+ }
+ SiteStatsInit::doAllAndCommit( $this->db );
+ }
+
+ # Common updater functions
+
+ /**
+ * Sets the number of active users in the site_stats table
+ */
+ protected function doActiveUsersInit() {
+ $activeUsers = $this->db->selectField( 'site_stats', 'ss_active_users', false, __METHOD__ );
+ if ( $activeUsers == -1 ) {
+ $activeUsers = $this->db->selectField( 'recentchanges',
+ 'COUNT( DISTINCT rc_user_text )',
+ array( 'rc_user != 0', 'rc_bot' => 0, "rc_log_type != 'newusers'" ), __METHOD__
+ );
+ $this->db->update( 'site_stats',
+ array( 'ss_active_users' => intval( $activeUsers ) ),
+ array( 'ss_row_id' => 1 ), __METHOD__, array( 'LIMIT' => 1 )
+ );
+ }
+ $this->output( "...ss_active_users user count set...\n" );
+ }
+
+ /**
+ * Populates the log_user_text field in the logging table
+ */
+ protected function doLogUsertextPopulation() {
+ if ( !$this->updateRowExists( 'populate log_usertext' ) ) {
+ $this->output(
+ "Populating log_user_text field, printing progress markers. For large\n" .
+ "databases, you may want to hit Ctrl-C and do this manually with\n" .
+ "maintenance/populateLogUsertext.php.\n" );
+
+ $task = $this->maintenance->runChild( 'PopulateLogUsertext' );
+ $task->execute();
+ $this->output( "done.\n" );
+ }
+ }
+
+ /**
+ * Migrate log params to new table and index for searching
+ */
+ protected function doLogSearchPopulation() {
+ if ( !$this->updateRowExists( 'populate log_search' ) ) {
+ $this->output(
+ "Populating log_search table, printing progress markers. For large\n" .
+ "databases, you may want to hit Ctrl-C and do this manually with\n" .
+ "maintenance/populateLogSearch.php.\n" );
+
+ $task = $this->maintenance->runChild( 'PopulateLogSearch' );
+ $task->execute();
+ $this->output( "done.\n" );
+ }
+ }
+
+ /**
+ * Updates the timestamps in the transcache table
+ */
+ protected function doUpdateTranscacheField() {
+ if ( $this->updateRowExists( 'convert transcache field' ) ) {
+ $this->output( "...transcache tc_time already converted.\n" );
+ return;
+ }
+
+ $this->output( "Converting tc_time from UNIX epoch to MediaWiki timestamp... " );
+ $this->applyPatch( 'patch-tc-timestamp.sql' );
+ $this->output( "done.\n" );
+ }
+
+ /**
+ * Update CategoryLinks collation
+ */
+ protected function doCollationUpdate() {
+ global $wgCategoryCollation;
+ if ( $this->db->selectField(
+ 'categorylinks',
+ 'COUNT(*)',
+ 'cl_collation != ' . $this->db->addQuotes( $wgCategoryCollation ),
+ __METHOD__
+ ) == 0 ) {
+ $this->output( "...collations up-to-date.\n" );
+ return;
+ }
+
+ $this->output( "Updating category collations..." );
+ $task = $this->maintenance->runChild( 'UpdateCollation' );
+ $task->execute();
+ $this->output( "...done.\n" );
+ }
+
+ /**
+ * Migrates user options from the user table blob to user_properties
+ */
+ protected function doMigrateUserOptions() {
+ $cl = $this->maintenance->runChild( 'ConvertUserOptions', 'convertUserOptions.php' );
+ $cl->execute();
+ $this->output( "done.\n" );
+ }
+
+ /**
+ * Rebuilds the localisation cache
+ */
+ protected function rebuildLocalisationCache() {
+ /**
+ * @var $cl RebuildLocalisationCache
+ */
+ $cl = $this->maintenance->runChild( 'RebuildLocalisationCache', 'rebuildLocalisationCache.php' );
+ $this->output( "Rebuilding localisation cache...\n" );
+ $cl->setForce();
+ $cl->execute();
+ $this->output( "done.\n" );