MediaWiki
REL1_21
|
00001 <?php 00024 require_once( __DIR__ . '/../../maintenance/Maintenance.php' ); 00025 00033 abstract class DatabaseUpdater { 00034 00040 protected $updates = array(); 00041 00047 protected $updatesSkipped = array(); 00048 00053 protected $extensionUpdates = array(); 00054 00060 protected $db; 00061 00062 protected $shared = false; 00063 00068 protected $postDatabaseUpdateMaintenance = array( 00069 'DeleteDefaultMessages', 00070 'PopulateRevisionLength', 00071 'PopulateRevisionSha1', 00072 'PopulateImageSha1', 00073 'FixExtLinksProtocolRelative', 00074 'PopulateFilearchiveSha1', 00075 ); 00076 00082 protected $fileHandle = null; 00083 00089 protected $skipSchema = false; 00090 00094 protected $wgContentHandlerUseDB = true; 00095 00103 protected function __construct( DatabaseBase &$db, $shared, Maintenance $maintenance = null ) { 00104 $this->db = $db; 00105 $this->db->setFlag( DBO_DDLMODE ); // For Oracle's handling of schema files 00106 $this->shared = $shared; 00107 if ( $maintenance ) { 00108 $this->maintenance = $maintenance; 00109 $this->fileHandle = $maintenance->fileHandle; 00110 } else { 00111 $this->maintenance = new FakeMaintenance; 00112 } 00113 $this->maintenance->setDB( $db ); 00114 $this->initOldGlobals(); 00115 $this->loadExtensions(); 00116 wfRunHooks( 'LoadExtensionSchemaUpdates', array( $this ) ); 00117 } 00118 00123 private function initOldGlobals() { 00124 global $wgExtNewTables, $wgExtNewFields, $wgExtPGNewFields, 00125 $wgExtPGAlteredFields, $wgExtNewIndexes, $wgExtModifiedFields; 00126 00127 # For extensions only, should be populated via hooks 00128 # $wgDBtype should be checked to specifiy the proper file 00129 $wgExtNewTables = array(); // table, dir 00130 $wgExtNewFields = array(); // table, column, dir 00131 $wgExtPGNewFields = array(); // table, column, column attributes; for PostgreSQL 00132 $wgExtPGAlteredFields = array(); // table, column, new type, conversion method; for PostgreSQL 00133 $wgExtNewIndexes = array(); // table, index, dir 00134 $wgExtModifiedFields = array(); // table, index, dir 00135 } 00136 00140 private function loadExtensions() { 00141 if ( !defined( 'MEDIAWIKI_INSTALL' ) ) { 00142 return; // already loaded 00143 } 00144 $vars = Installer::getExistingLocalSettings(); 00145 if ( !$vars ) { 00146 return; // no LocalSettings found 00147 } 00148 if ( !isset( $vars['wgHooks'] ) || !isset( $vars['wgHooks']['LoadExtensionSchemaUpdates'] ) ) { 00149 return; 00150 } 00151 global $wgHooks, $wgAutoloadClasses; 00152 $wgHooks['LoadExtensionSchemaUpdates'] = $vars['wgHooks']['LoadExtensionSchemaUpdates']; 00153 $wgAutoloadClasses = $wgAutoloadClasses + $vars['wgAutoloadClasses']; 00154 } 00155 00163 public static function newForDB( &$db, $shared = false, $maintenance = null ) { 00164 $type = $db->getType(); 00165 if( in_array( $type, Installer::getDBTypes() ) ) { 00166 $class = ucfirst( $type ) . 'Updater'; 00167 return new $class( $db, $shared, $maintenance ); 00168 } else { 00169 throw new MWException( __METHOD__ . ' called for unsupported $wgDBtype' ); 00170 } 00171 } 00172 00178 public function getDB() { 00179 return $this->db; 00180 } 00181 00187 public function output( $str ) { 00188 if ( $this->maintenance->isQuiet() ) { 00189 return; 00190 } 00191 global $wgCommandLineMode; 00192 if( !$wgCommandLineMode ) { 00193 $str = htmlspecialchars( $str ); 00194 } 00195 echo $str; 00196 flush(); 00197 } 00198 00212 public function addExtensionUpdate( array $update ) { 00213 $this->extensionUpdates[] = $update; 00214 } 00215 00225 public function addExtensionTable( $tableName, $sqlPath ) { 00226 $this->extensionUpdates[] = array( 'addTable', $tableName, $sqlPath, true ); 00227 } 00228 00236 public function addExtensionIndex( $tableName, $indexName, $sqlPath ) { 00237 $this->extensionUpdates[] = array( 'addIndex', $tableName, $indexName, $sqlPath, true ); 00238 } 00239 00248 public function addExtensionField( $tableName, $columnName, $sqlPath ) { 00249 $this->extensionUpdates[] = array( 'addField', $tableName, $columnName, $sqlPath, true ); 00250 } 00251 00260 public function dropExtensionField( $tableName, $columnName, $sqlPath ) { 00261 $this->extensionUpdates[] = array( 'dropField', $tableName, $columnName, $sqlPath, true ); 00262 } 00263 00273 public function dropExtensionIndex( $tableName, $indexName, $sqlPath ) { 00274 $this->extensionUpdates[] = array( 'dropIndex', $tableName, $indexName, $sqlPath, true ); 00275 } 00276 00284 public function dropExtensionTable( $tableName, $sqlPath ) { 00285 $this->extensionUpdates[] = array( 'dropTable', $tableName, $sqlPath, true ); 00286 } 00287 00299 public function renameExtensionIndex( $tableName, $oldIndexName, $newIndexName, $sqlPath, $skipBothIndexExistWarning = false ) { 00300 $this->extensionUpdates[] = array( 'renameIndex', $tableName, $oldIndexName, $newIndexName, $skipBothIndexExistWarning, $sqlPath, true ); 00301 } 00302 00310 public function modifyExtensionField( $tableName, $fieldName, $sqlPath) { 00311 $this->extensionUpdates[] = array( 'modifyField', $tableName, $fieldName, $sqlPath, true ); 00312 } 00313 00321 public function tableExists( $tableName ) { 00322 return ( $this->db->tableExists( $tableName, __METHOD__ ) ); 00323 } 00324 00334 public function addPostDatabaseUpdateMaintenance( $class ) { 00335 $this->postDatabaseUpdateMaintenance[] = $class; 00336 } 00337 00343 protected function getExtensionUpdates() { 00344 return $this->extensionUpdates; 00345 } 00346 00352 public function getPostDatabaseUpdateMaintenance() { 00353 return $this->postDatabaseUpdateMaintenance; 00354 } 00355 00361 private function writeSchemaUpdateFile( $schemaUpdate = array() ) { 00362 $updates = $this->updatesSkipped; 00363 $this->updatesSkipped = array(); 00364 00365 foreach( $updates as $funcList ) { 00366 $func = $funcList[0]; 00367 $arg = $funcList[1]; 00368 $origParams = $funcList[2]; 00369 call_user_func_array( $func, $arg ); 00370 flush(); 00371 $this->updatesSkipped[] = $origParams; 00372 } 00373 } 00374 00380 public function doUpdates( $what = array( 'core', 'extensions', 'stats' ) ) { 00381 global $wgVersion, $wgLocalisationCacheConf; 00382 00383 $this->db->begin( __METHOD__ ); 00384 $what = array_flip( $what ); 00385 $this->skipSchema = isset( $what['noschema'] ) || $this->fileHandle !== null; 00386 if ( isset( $what['core'] ) ) { 00387 $this->runUpdates( $this->getCoreUpdateList(), false ); 00388 } 00389 if ( isset( $what['extensions'] ) ) { 00390 $this->runUpdates( $this->getOldGlobalUpdates(), false ); 00391 $this->runUpdates( $this->getExtensionUpdates(), true ); 00392 } 00393 00394 if ( isset( $what['stats'] ) ) { 00395 $this->checkStats(); 00396 } 00397 00398 if ( isset( $what['purge'] ) ) { 00399 $this->purgeCache(); 00400 00401 if ( $wgLocalisationCacheConf['manualRecache'] ) { 00402 $this->rebuildLocalisationCache(); 00403 } 00404 } 00405 00406 $this->setAppliedUpdates( $wgVersion, $this->updates ); 00407 00408 if( $this->fileHandle ) { 00409 $this->skipSchema = false; 00410 $this->writeSchemaUpdateFile(); 00411 $this->setAppliedUpdates( "$wgVersion-schema", $this->updatesSkipped ); 00412 } 00413 00414 $this->db->commit( __METHOD__ ); 00415 } 00416 00424 private function runUpdates( array $updates, $passSelf ) { 00425 $updatesDone = array(); 00426 $updatesSkipped = array(); 00427 foreach ( $updates as $params ) { 00428 $origParams = $params; 00429 $func = array_shift( $params ); 00430 if( !is_array( $func ) && method_exists( $this, $func ) ) { 00431 $func = array( $this, $func ); 00432 } elseif ( $passSelf ) { 00433 array_unshift( $params, $this ); 00434 } 00435 $ret = call_user_func_array( $func, $params ); 00436 flush(); 00437 if( $ret !== false ) { 00438 $updatesDone[] = $origParams; 00439 } else { 00440 $updatesSkipped[] = array( $func, $params, $origParams ); 00441 } 00442 } 00443 $this->updatesSkipped = array_merge( $this->updatesSkipped, $updatesSkipped ); 00444 $this->updates = array_merge( $this->updates, $updatesDone ); 00445 } 00446 00451 protected function setAppliedUpdates( $version, $updates = array() ) { 00452 $this->db->clearFlag( DBO_DDLMODE ); 00453 if( !$this->canUseNewUpdatelog() ) { 00454 return; 00455 } 00456 $key = "updatelist-$version-" . time(); 00457 $this->db->insert( 'updatelog', 00458 array( 'ul_key' => $key, 'ul_value' => serialize( $updates ) ), 00459 __METHOD__ ); 00460 $this->db->setFlag( DBO_DDLMODE ); 00461 } 00462 00471 public function updateRowExists( $key ) { 00472 $row = $this->db->selectRow( 00473 'updatelog', 00474 '1', 00475 array( 'ul_key' => $key ), 00476 __METHOD__ 00477 ); 00478 return (bool)$row; 00479 } 00480 00488 public function insertUpdateRow( $key, $val = null ) { 00489 $this->db->clearFlag( DBO_DDLMODE ); 00490 $values = array( 'ul_key' => $key ); 00491 if( $val && $this->canUseNewUpdatelog() ) { 00492 $values['ul_value'] = $val; 00493 } 00494 $this->db->insert( 'updatelog', $values, __METHOD__, 'IGNORE' ); 00495 $this->db->setFlag( DBO_DDLMODE ); 00496 } 00497 00506 protected function canUseNewUpdatelog() { 00507 return $this->db->tableExists( 'updatelog', __METHOD__ ) && 00508 $this->db->fieldExists( 'updatelog', 'ul_value', __METHOD__ ); 00509 } 00510 00519 protected function doTable( $name ) { 00520 global $wgSharedDB, $wgSharedTables; 00521 00522 // Don't bother to check $wgSharedTables if there isn't a shared database 00523 // or the user actually also wants to do updates on the shared database. 00524 if ( $wgSharedDB === null || $this->shared ) { 00525 return true; 00526 } 00527 00528 return !in_array( $name, $wgSharedTables ); 00529 } 00530 00539 protected function getOldGlobalUpdates() { 00540 global $wgExtNewFields, $wgExtNewTables, $wgExtModifiedFields, 00541 $wgExtNewIndexes; 00542 00543 $updates = array(); 00544 00545 foreach ( $wgExtNewTables as $tableRecord ) { 00546 $updates[] = array( 00547 'addTable', $tableRecord[0], $tableRecord[1], true 00548 ); 00549 } 00550 00551 foreach ( $wgExtNewFields as $fieldRecord ) { 00552 $updates[] = array( 00553 'addField', $fieldRecord[0], $fieldRecord[1], 00554 $fieldRecord[2], true 00555 ); 00556 } 00557 00558 foreach ( $wgExtNewIndexes as $fieldRecord ) { 00559 $updates[] = array( 00560 'addIndex', $fieldRecord[0], $fieldRecord[1], 00561 $fieldRecord[2], true 00562 ); 00563 } 00564 00565 foreach ( $wgExtModifiedFields as $fieldRecord ) { 00566 $updates[] = array( 00567 'modifyField', $fieldRecord[0], $fieldRecord[1], 00568 $fieldRecord[2], true 00569 ); 00570 } 00571 00572 return $updates; 00573 } 00574 00583 abstract protected function getCoreUpdateList(); 00584 00590 public function copyFile( $filename ) { 00591 $this->db->sourceFile( $filename, false, false, false, 00592 array( $this, 'appendLine' ) 00593 ); 00594 } 00595 00606 public function appendLine( $line ) { 00607 $line = rtrim( $line ) . ";\n"; 00608 if( fwrite( $this->fileHandle, $line ) === false ) { 00609 throw new MWException( "trouble writing file" ); 00610 } 00611 return false; 00612 } 00613 00622 protected function applyPatch( $path, $isFullPath = false, $msg = null ) { 00623 if ( $msg === null ) { 00624 $msg = "Applying $path patch"; 00625 } 00626 if ( $this->skipSchema ) { 00627 $this->output( "...skipping schema change ($msg).\n" ); 00628 return false; 00629 } 00630 00631 $this->output( "$msg ..." ); 00632 00633 if ( !$isFullPath ) { 00634 $path = $this->db->patchPath( $path ); 00635 } 00636 if( $this->fileHandle !== null ) { 00637 $this->copyFile( $path ); 00638 } else { 00639 $this->db->sourceFile( $path ); 00640 } 00641 $this->output( "done.\n" ); 00642 return true; 00643 } 00644 00653 protected function addTable( $name, $patch, $fullpath = false ) { 00654 if ( !$this->doTable( $name ) ) { 00655 return true; 00656 } 00657 00658 if ( $this->db->tableExists( $name, __METHOD__ ) ) { 00659 $this->output( "...$name table already exists.\n" ); 00660 } else { 00661 return $this->applyPatch( $patch, $fullpath, "Creating $name table" ); 00662 } 00663 return true; 00664 } 00665 00675 protected function addField( $table, $field, $patch, $fullpath = false ) { 00676 if ( !$this->doTable( $table ) ) { 00677 return true; 00678 } 00679 00680 if ( !$this->db->tableExists( $table, __METHOD__ ) ) { 00681 $this->output( "...$table table does not exist, skipping new field patch.\n" ); 00682 } elseif ( $this->db->fieldExists( $table, $field, __METHOD__ ) ) { 00683 $this->output( "...have $field field in $table table.\n" ); 00684 } else { 00685 return $this->applyPatch( $patch, $fullpath, "Adding $field field to table $table" ); 00686 } 00687 return true; 00688 } 00689 00699 protected function addIndex( $table, $index, $patch, $fullpath = false ) { 00700 if ( !$this->doTable( $table ) ) { 00701 return true; 00702 } 00703 00704 if ( !$this->db->tableExists( $table, __METHOD__ ) ) { 00705 $this->output( "...skipping: '$table' table doesn't exist yet.\n" ); 00706 } else if ( $this->db->indexExists( $table, $index, __METHOD__ ) ) { 00707 $this->output( "...index $index already set on $table table.\n" ); 00708 } else { 00709 return $this->applyPatch( $patch, $fullpath, "Adding index $index to table $table" ); 00710 } 00711 return true; 00712 } 00713 00723 protected function dropField( $table, $field, $patch, $fullpath = false ) { 00724 if ( !$this->doTable( $table ) ) { 00725 return true; 00726 } 00727 00728 if ( $this->db->fieldExists( $table, $field, __METHOD__ ) ) { 00729 return $this->applyPatch( $patch, $fullpath, "Table $table contains $field field. Dropping" ); 00730 } else { 00731 $this->output( "...$table table does not contain $field field.\n" ); 00732 } 00733 return true; 00734 } 00735 00745 protected function dropIndex( $table, $index, $patch, $fullpath = false ) { 00746 if ( !$this->doTable( $table ) ) { 00747 return true; 00748 } 00749 00750 if ( $this->db->indexExists( $table, $index, __METHOD__ ) ) { 00751 return $this->applyPatch( $patch, $fullpath, "Dropping $index index from table $table" ); 00752 } else { 00753 $this->output( "...$index key doesn't exist.\n" ); 00754 } 00755 return true; 00756 } 00757 00769 protected function renameIndex( $table, $oldIndex, $newIndex, $skipBothIndexExistWarning, $patch, $fullpath = false ) { 00770 if ( !$this->doTable( $table ) ) { 00771 return true; 00772 } 00773 00774 // First requirement: the table must exist 00775 if ( !$this->db->tableExists( $table, __METHOD__ ) ) { 00776 $this->output( "...skipping: '$table' table doesn't exist yet.\n" ); 00777 return true; 00778 } 00779 00780 // Second requirement: the new index must be missing 00781 if ( $this->db->indexExists( $table, $newIndex, __METHOD__ ) ) { 00782 $this->output( "...index $newIndex already set on $table table.\n" ); 00783 if ( !$skipBothIndexExistWarning && $this->db->indexExists( $table, $oldIndex, __METHOD__ ) ) { 00784 $this->output( "...WARNING: $oldIndex still exists, despite it has been renamed into $newIndex (which also exists).\n" . 00785 " $oldIndex should be manually removed if not needed anymore.\n" ); 00786 } 00787 return true; 00788 } 00789 00790 // Third requirement: the old index must exist 00791 if ( !$this->db->indexExists( $table, $oldIndex, __METHOD__ ) ) { 00792 $this->output( "...skipping: index $oldIndex doesn't exist.\n" ); 00793 return true; 00794 } 00795 00796 // Requirements have been satisfied, patch can be applied 00797 return $this->applyPatch( $patch, $fullpath, "Renaming index $oldIndex into $newIndex to table $table" ); 00798 } 00799 00811 public function dropTable( $table, $patch = false, $fullpath = false ) { 00812 if ( !$this->doTable( $table ) ) { 00813 return true; 00814 } 00815 00816 if ( $this->db->tableExists( $table, __METHOD__ ) ) { 00817 $msg = "Dropping table $table"; 00818 00819 if ( $patch === false ) { 00820 $this->output( "$msg ..." ); 00821 $this->db->dropTable( $table, __METHOD__ ); 00822 $this->output( "done.\n" ); 00823 } 00824 else { 00825 return $this->applyPatch( $patch, $fullpath, $msg ); 00826 } 00827 } else { 00828 $this->output( "...$table doesn't exist.\n" ); 00829 } 00830 return true; 00831 } 00832 00842 public function modifyField( $table, $field, $patch, $fullpath = false ) { 00843 if ( !$this->doTable( $table ) ) { 00844 return true; 00845 } 00846 00847 $updateKey = "$table-$field-$patch"; 00848 if ( !$this->db->tableExists( $table, __METHOD__ ) ) { 00849 $this->output( "...$table table does not exist, skipping modify field patch.\n" ); 00850 } elseif ( !$this->db->fieldExists( $table, $field, __METHOD__ ) ) { 00851 $this->output( "...$field field does not exist in $table table, skipping modify field patch.\n" ); 00852 } elseif( $this->updateRowExists( $updateKey ) ) { 00853 $this->output( "...$field in table $table already modified by patch $patch.\n" ); 00854 } else { 00855 $this->insertUpdateRow( $updateKey ); 00856 return $this->applyPatch( $patch, $fullpath, "Modifying $field field of table $table" ); 00857 } 00858 return true; 00859 } 00860 00864 public function purgeCache() { 00865 global $wgLocalisationCacheConf; 00866 # We can't guarantee that the user will be able to use TRUNCATE, 00867 # but we know that DELETE is available to us 00868 $this->output( "Purging caches..." ); 00869 $this->db->delete( 'objectcache', '*', __METHOD__ ); 00870 if ( $wgLocalisationCacheConf['manualRecache'] ) { 00871 $this->rebuildLocalisationCache(); 00872 } 00873 MessageBlobStore::clear(); 00874 $this->output( "done.\n" ); 00875 } 00876 00880 protected function checkStats() { 00881 $this->output( "...site_stats is populated..." ); 00882 $row = $this->db->selectRow( 'site_stats', '*', array( 'ss_row_id' => 1 ), __METHOD__ ); 00883 if ( $row === false ) { 00884 $this->output( "data is missing! rebuilding...\n" ); 00885 } elseif ( isset( $row->site_stats ) && $row->ss_total_pages == -1 ) { 00886 $this->output( "missing ss_total_pages, rebuilding...\n" ); 00887 } else { 00888 $this->output( "done.\n" ); 00889 return; 00890 } 00891 SiteStatsInit::doAllAndCommit( $this->db ); 00892 } 00893 00894 # Common updater functions 00895 00899 protected function doActiveUsersInit() { 00900 $activeUsers = $this->db->selectField( 'site_stats', 'ss_active_users', false, __METHOD__ ); 00901 if ( $activeUsers == -1 ) { 00902 $activeUsers = $this->db->selectField( 'recentchanges', 00903 'COUNT( DISTINCT rc_user_text )', 00904 array( 'rc_user != 0', 'rc_bot' => 0, "rc_log_type != 'newusers'" ), __METHOD__ 00905 ); 00906 $this->db->update( 'site_stats', 00907 array( 'ss_active_users' => intval( $activeUsers ) ), 00908 array( 'ss_row_id' => 1 ), __METHOD__, array( 'LIMIT' => 1 ) 00909 ); 00910 } 00911 $this->output( "...ss_active_users user count set...\n" ); 00912 } 00913 00917 protected function doLogUsertextPopulation() { 00918 if ( !$this->updateRowExists( 'populate log_usertext' ) ) { 00919 $this->output( 00920 "Populating log_user_text field, printing progress markers. For large\n" . 00921 "databases, you may want to hit Ctrl-C and do this manually with\n" . 00922 "maintenance/populateLogUsertext.php.\n" ); 00923 00924 $task = $this->maintenance->runChild( 'PopulateLogUsertext' ); 00925 $task->execute(); 00926 $this->output( "done.\n" ); 00927 } 00928 } 00929 00933 protected function doLogSearchPopulation() { 00934 if ( !$this->updateRowExists( 'populate log_search' ) ) { 00935 $this->output( 00936 "Populating log_search table, printing progress markers. For large\n" . 00937 "databases, you may want to hit Ctrl-C and do this manually with\n" . 00938 "maintenance/populateLogSearch.php.\n" ); 00939 00940 $task = $this->maintenance->runChild( 'PopulateLogSearch' ); 00941 $task->execute(); 00942 $this->output( "done.\n" ); 00943 } 00944 } 00945 00949 protected function doUpdateTranscacheField() { 00950 if ( $this->updateRowExists( 'convert transcache field' ) ) { 00951 $this->output( "...transcache tc_time already converted.\n" ); 00952 return true; 00953 } 00954 00955 return $this->applyPatch( 'patch-tc-timestamp.sql', false, 00956 "Converting tc_time from UNIX epoch to MediaWiki timestamp" ); 00957 } 00958 00962 protected function doCollationUpdate() { 00963 global $wgCategoryCollation; 00964 if ( $this->db->fieldExists( 'categorylinks', 'cl_collation', __METHOD__ ) ) { 00965 if ( $this->db->selectField( 00966 'categorylinks', 00967 'COUNT(*)', 00968 'cl_collation != ' . $this->db->addQuotes( $wgCategoryCollation ), 00969 __METHOD__ 00970 ) == 0 ) { 00971 $this->output( "...collations up-to-date.\n" ); 00972 return; 00973 } 00974 00975 $this->output( "Updating category collations..." ); 00976 $task = $this->maintenance->runChild( 'UpdateCollation' ); 00977 $task->execute(); 00978 $this->output( "...done.\n" ); 00979 } 00980 } 00981 00985 protected function doMigrateUserOptions() { 00986 if( $this->db->tableExists( 'user_properties' ) ) { 00987 $cl = $this->maintenance->runChild( 'ConvertUserOptions', 'convertUserOptions.php' ); 00988 $cl->execute(); 00989 $this->output( "done.\n" ); 00990 } 00991 } 00992 00996 protected function rebuildLocalisationCache() { 01000 $cl = $this->maintenance->runChild( 'RebuildLocalisationCache', 'rebuildLocalisationCache.php' ); 01001 $this->output( "Rebuilding localisation cache...\n" ); 01002 $cl->setForce(); 01003 $cl->execute(); 01004 $this->output( "done.\n" ); 01005 } 01006 01011 protected function disableContentHandlerUseDB() { 01012 global $wgContentHandlerUseDB; 01013 01014 if( $wgContentHandlerUseDB ) { 01015 $this->output( "Turning off Content Handler DB fields for this part of upgrade.\n" ); 01016 $this->holdContentHandlerUseDB = $wgContentHandlerUseDB; 01017 $wgContentHandlerUseDB = false; 01018 } 01019 } 01020 01024 protected function enableContentHandlerUseDB() { 01025 global $wgContentHandlerUseDB; 01026 01027 if( $this->holdContentHandlerUseDB ) { 01028 $this->output( "Content Handler DB fields should be usable now.\n" ); 01029 $wgContentHandlerUseDB = $this->holdContentHandlerUseDB; 01030 } 01031 } 01032 }