aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--RELEASE-NOTES3
-rw-r--r--includes/Article.php36
-rw-r--r--includes/Database.php2
-rw-r--r--includes/Image.php2
-rw-r--r--includes/LinkCache.php186
-rw-r--r--includes/LinksUpdate.php119
-rw-r--r--includes/Parser.php4
-rw-r--r--includes/SpecialBrokenRedirects.php20
-rw-r--r--includes/SpecialDeadendpages.php6
-rw-r--r--includes/SpecialDisambiguations.php15
-rw-r--r--includes/SpecialDoubleRedirects.php28
-rw-r--r--includes/SpecialLog.php4
-rw-r--r--includes/SpecialLonelypages.php17
-rw-r--r--includes/SpecialRecentchangeslinked.php43
-rw-r--r--includes/SpecialWantedpages.php32
-rw-r--r--includes/SpecialWhatlinkshere.php62
-rw-r--r--includes/SquidUpdate.php34
-rw-r--r--includes/Title.php197
-rw-r--r--maintenance/convertUtf8.php2
-rw-r--r--maintenance/refreshLinks.inc5
-rw-r--r--maintenance/remove-brokenlinks.php58
-rw-r--r--maintenance/tables.sql21
-rw-r--r--maintenance/updaters.inc42
23 files changed, 434 insertions, 504 deletions
diff --git a/RELEASE-NOTES b/RELEASE-NOTES
index 7bddb27562b2..3e183e5edafa 100644
--- a/RELEASE-NOTES
+++ b/RELEASE-NOTES
@@ -214,6 +214,9 @@ Various bugfixes, small features, and a few experimental things:
* The #p-nav id in MonoBook is now #p-navigation
* Putting $4 in msg:userstatstext will now give the percentage of
admnistrators out of normal users.
+* links and brokenlinks tables merged to pagelinks; this will reduce pain
+ dealing with moves and deletes of widely-linked pages.
+
=== Caveats ===
diff --git a/includes/Article.php b/includes/Article.php
index 2262be271d28..b02b7679df96 100644
--- a/includes/Article.php
+++ b/includes/Article.php
@@ -1789,20 +1789,9 @@ class Article {
Article::onArticleDelete( $this->mTitle );
- # Insert broken links
- $brokenLinks = array();
- foreach ( $linksTo as $titleObj ) {
- # Get article ID. Efficient because it was loaded into the cache by getLinksTo().
- $linkID = $titleObj->getArticleID();
- $brokenLinks[] = array( 'bl_from' => $linkID, 'bl_to' => $t );
- }
- $dbw->insert( 'brokenlinks', $brokenLinks, $fname, 'IGNORE' );
-
- # Delete live links
- $dbw->delete( 'links', array( 'l_to' => $id ) );
- $dbw->delete( 'links', array( 'l_from' => $id ) );
+ # Delete outgoing links
+ $dbw->delete( 'pagelinks', array( 'pl_from' => $id ) );
$dbw->delete( 'imagelinks', array( 'il_from' => $id ) );
- $dbw->delete( 'brokenlinks', array( 'bl_from' => $id ) );
$dbw->delete( 'categorylinks', array( 'cl_from' => $id ) );
# Log the deletion
@@ -2195,7 +2184,8 @@ class Article {
function onArticleCreate($title_obj) {
global $wgUseSquid, $wgPostCommitUpdateList;
- $titles = $title_obj->getBrokenLinksTo();
+ $title_obj->touchLinks();
+ $titles = $title_obj->getLinksTo();
# Purge squid
if ( $wgUseSquid ) {
@@ -2208,11 +2198,12 @@ class Article {
}
# Clear persistent link cache
- LinkCache::linksccClearBrokenLinksTo( $title_obj->getPrefixedDBkey() );
+ LinkCache::linksccClearLinksTo( $title_obj );
}
function onArticleDelete($title_obj) {
- LinkCache::linksccClearLinksTo( $title_obj->getArticleID() );
+ $title_obj->touchLinks();
+ LinkCache::linksccClearLinksTo( $title_obj );
}
function onArticleEdit($title_obj) {
LinkCache::linksccClearPage( $title_obj->getArticleID() );
@@ -2319,15 +2310,16 @@ class Article {
$id = $this->mTitle->getArticleID();
$db =& wfGetDB( DB_SLAVE );
- $page = $db->tableName( 'page' );
- $links = $db->tableName( 'links' );
- $sql = "SELECT page_title ".
- "FROM $page,$links WHERE l_to=page_id AND l_from={$id} and page_namespace=".NS_TEMPLATE;
- $res = $db->query( $sql, "Article:getUsedTemplates" );
+ $res = $db->select( array( 'pagelinks' ),
+ array( 'pl_title' ),
+ array(
+ 'pl_from' => $id,
+ 'pl_namespace' => NS_TEMPLATE ),
+ 'Article:getUsedTemplates' );
if ( false !== $res ) {
if ( $db->numRows( $res ) ) {
while ( $row = $db->fetchObject( $res ) ) {
- $result[] = $row->page_title;
+ $result[] = $row->pl_title;
}
}
}
diff --git a/includes/Database.php b/includes/Database.php
index e69e49b9e816..8b9858a4e23b 100644
--- a/includes/Database.php
+++ b/includes/Database.php
@@ -430,7 +430,7 @@ class Database {
* Prepare & execute an SQL statement, quoting and inserting arguments
* in the appropriate places.
* @param string $query
- * @param string $args (default null)
+ * @param string $args ...
*/
function safeQuery( $query, $args = null ) {
$prepared = $this->prepare( $query, 'Database::safeQuery' );
diff --git a/includes/Image.php b/includes/Image.php
index 6b53b5cf2e2f..4882e23bc905 100644
--- a/includes/Image.php
+++ b/includes/Image.php
@@ -1369,7 +1369,7 @@ class Image
if ( $db->numRows( $res ) ) {
while ( $row = $db->fetchObject( $res ) ) {
if ( $titleObj = Title::makeTitle( $row->page_namespace, $row->page_title ) ) {
- $wgLinkCache->addGoodLink( $row->page_id, $titleObj->getPrefixedDBkey() );
+ $wgLinkCache->addGoodLinkObj( $row->page_id, $titleObj );
$retVal[] = $titleObj;
}
}
diff --git a/includes/LinkCache.php b/includes/LinkCache.php
index 5853f16f228f..35e486bf9231 100644
--- a/includes/LinkCache.php
+++ b/includes/LinkCache.php
@@ -12,6 +12,7 @@
define ('LINKCACHE_GOOD', 0);
define ('LINKCACHE_BAD', 1);
define ('LINKCACHE_IMAGE', 2);
+define ('LINKCACHE_PAGE', 3);
/**
* @package MediaWiki
@@ -20,8 +21,9 @@ define ('LINKCACHE_IMAGE', 2);
class LinkCache {
// Increment $mClassVer whenever old serialized versions of this class
// becomes incompatible with the new version.
- /* private */ var $mClassVer = 2;
+ /* private */ var $mClassVer = 3;
+ /* private */ var $mPageLinks;
/* private */ var $mGoodLinks, $mBadLinks, $mActive;
/* private */ var $mImageLinks, $mCategoryLinks;
/* private */ var $mPreFilled, $mOldGoodLinks, $mOldBadLinks;
@@ -36,6 +38,7 @@ class LinkCache {
$this->mActive = true;
$this->mPreFilled = false;
$this->mForUpdate = false;
+ $this->mPageLinks = array();
$this->mGoodLinks = array();
$this->mBadLinks = array();
$this->mImageLinks = array();
@@ -63,15 +66,19 @@ class LinkCache {
return array_key_exists( $title, $this->mBadLinks );
}
- function addGoodLink( $id, $title ) {
+ function addGoodLinkObj( $id, $title ) {
if ( $this->mActive ) {
- $this->mGoodLinks[$title] = $id;
+ $dbkey = $title->getPrefixedDbKey();
+ $this->mGoodLinks[$dbkey] = $id;
+ $this->mPageLinks[$dbkey] = $title;
}
}
- function addBadLink( $title ) {
- if ( $this->mActive && ( ! $this->isBadLink( $title ) ) ) {
- $this->mBadLinks[$title] = 1;
+ function addBadLinkObj( $title ) {
+ $dbkey = $title->getPrefixedDbKey();
+ if ( $this->mActive && ( ! $this->isBadLink( $dbkey ) ) ) {
+ $this->mBadLinks[$dbkey] = 1;
+ $this->mPageLinks[$dbkey] = $title;
}
}
@@ -104,6 +111,7 @@ class LinkCache {
function suspend() { $this->mActive = false; }
function resume() { $this->mActive = true; }
+ function getPageLinks() { return $this->mPageLinks; }
function getGoodLinks() { return $this->mGoodLinks; }
function getBadLinks() { return array_keys( $this->mBadLinks ); }
function getImageLinks() { return $this->mImageLinks; }
@@ -156,18 +164,24 @@ class LinkCache {
$wgMemc->add( $key, $id, 3600*24 );
}
- if ( 0 == $id ) { $this->addBadLink( $title ); }
- else { $this->addGoodLink( $id, $title ); }
+ if( 0 == $id ) {
+ $this->addBadLinkObj( $nt );
+ } else {
+ $this->addGoodLinkObj( $id, $nt );
+ }
wfProfileOut( $fname );
return $id;
}
+ /**
+ * Bulk-check the pagelinks and page arrays for existence info.
+ * @param Title $fromtitle
+ */
function preFill( &$fromtitle ) {
global $wgEnablePersistentLC;
$fname = 'LinkCache::preFill';
wfProfileIn( $fname );
- # Note -- $fromtitle is a Title *object*
$this->suspend();
$id = $fromtitle->getArticleID();
@@ -194,24 +208,24 @@ class LinkCache {
}
$page = $db->tableName( 'page' );
- $links = $db->tableName( 'links' );
+ $pagelinks = $db->tableName( 'pagelinks' );
- $sql = "SELECT page_id,page_namespace,page_title
- FROM $page,$links
- WHERE page_id=l_to AND l_from=$id $options";
+ $sql = "SELECT page_id,pl_namespace,pl_title
+ FROM $pagelinks
+ LEFT JOIN $page
+ ON pl_namespace=page_namespace AND pl_title=page_title
+ WHERE pl_from=$id $options";
$res = $db->query( $sql, $fname );
while( $s = $db->fetchObject( $res ) ) {
- $this->addGoodLink( $s->page_id,
- Title::makeName( $s->page_namespace, $s->page_title )
- );
- }
-
- $res = $db->select( 'brokenlinks', array( 'bl_to' ), array( 'bl_from' => $id ), $fname, array( $options ) );
- while( $s = $db->fetchObject( $res ) ) {
- $this->addBadLink( $s->bl_to );
+ $title = Title::makeTitle( $s->pl_namespace, $s->pl_title );
+ if( $s->page_id ) {
+ $this->addGoodLinkObj( $s->page_id, $title );
+ } else {
+ $this->addBadLinkObj( $title );
+ }
}
-
- $this->mOldBadLinks = $this->mBadLinks;
+ $this->mOldPageLinks = $this->mPageLinks;
+ $this->mOldBadLinks = $this->mBadLinks;
$this->mOldGoodLinks = $this->mGoodLinks;
$this->mPreFilled = true;
@@ -246,6 +260,24 @@ class LinkCache {
function getImageDeletions() {
return array_diff_assoc( $this->mOldImageLinks, $this->mImageLinks );
}
+
+ function getPageAdditions() {
+ $set = array_diff( array_keys( $this->mPageLinks ), array_keys( $this->mOldPageLinks ) );
+ $out = array();
+ foreach( $set as $key ) {
+ $out[$key] = $this->mPageLinks[$key];
+ }
+ return $out;
+ }
+
+ function getPageDeletions() {
+ $set = array_diff( array_keys( $this->mOldPageLinks ), array_keys( $this->mPageLinks ) );
+ $out = array();
+ foreach( $set as $key ) {
+ $out[$key] = $this->mOldPageLinks[$key];
+ }
+ return $out;
+ }
/**
* Parameters:
@@ -275,6 +307,12 @@ class LinkCache {
$del = $this->getBadDeletions();
$add = $this->getBadAdditions();
break;
+ case LINKCACHE_PAGE:
+ $old =& $this->mOldPageLinks;
+ $cur =& $this->mPageLinks;
+ $del = $this->getPageDeletions();
+ $add = $this->getPageAdditions();
+ break;
default: # LINKCACHE_IMAGE
return false;
}
@@ -286,6 +324,7 @@ class LinkCache {
* Clears cache but leaves old preFill copies alone
*/
function clear() {
+ $this->mPageLinks = array();
$this->mGoodLinks = array();
$this->mBadLinks = array();
$this->mImageLinks = array();
@@ -319,6 +358,7 @@ class LinkCache {
}
$cc = @unserialize( $cacheobj );
if( isset( $cc->mClassVer ) and ($cc->mClassVer == $this->mClassVer ) ){
+ $this->mOldPageLinks = $this->mPageLinks = $cc->mPageLinks;
$this->mOldGoodLinks = $this->mGoodLinks = $cc->mGoodLinks;
$this->mOldBadLinks = $this->mBadLinks = $cc->mBadLinks;
$this->mPreFilled = true;
@@ -345,17 +385,21 @@ class LinkCache {
/**
* Delete linkscc rows which link to here
- * @param $pid is a page id
+ * @param $title The page linked to
* @static
*/
- function linksccClearLinksTo( $pid ){
+ function linksccClearLinksTo( $title ){
global $wgEnablePersistentLC;
if ( $wgEnablePersistentLC ) {
$fname = 'LinkCache::linksccClearLinksTo';
$pid = intval( $pid );
$dbw =& wfGetDB( DB_MASTER );
# Delete linkscc rows which link to here
- $dbw->deleteJoin( 'linkscc', 'links', 'lcc_pageid', 'l_from', array( 'l_to' => $pid ), $fname );
+ $dbw->deleteJoin( 'linkscc', 'pagelinks', 'lcc_pageid', 'pl_from',
+ array(
+ 'pl_namespace' => $title->getNamespace(),
+ 'pl-title' => $title->getDbKey() ),
+ $fname );
# Delete linkscc row representing this page
$dbw->delete( 'linkscc', array( 'lcc_pageid' => $pid ), $fname);
}
@@ -363,21 +407,6 @@ class LinkCache {
}
/**
- * Delete linkscc rows with broken links to here
- * @param $title is a prefixed db title for example like Title->getPrefixedDBkey() returns.
- * @static
- */
- function linksccClearBrokenLinksTo( $title ){
- global $wgEnablePersistentLC;
- $fname = 'LinkCache::linksccClearBrokenLinksTo';
-
- if ( $wgEnablePersistentLC ) {
- $dbw =& wfGetDB( DB_MASTER );
- $dbw->deleteJoin( 'linkscc', 'brokenlinks', 'lcc_pageid', 'bl_from', array( 'bl_to' => $title ), $fname );
- }
- }
-
- /**
* @param $pid is a page id
* @static
*/
@@ -404,6 +433,12 @@ class LinkBatch {
*/
var $data = array();
+ function LinkBatch( $arr = array() ) {
+ foreach( $arr as $item ) {
+ $this->addObj( $item );
+ }
+ }
+
function addObj( $title ) {
$this->add( $title->getNamespace(), $title->getDBkey() );
}
@@ -433,9 +468,45 @@ class LinkBatch {
// This is very similar to Parser::replaceLinkHolders
$dbr = wfGetDB( DB_SLAVE );
$page = $dbr->tableName( 'page' );
- $sql = "SELECT page_id, page_namespace, page_title FROM $page WHERE ";
- $first = true;
+ $sql = "SELECT page_id, page_namespace, page_title FROM $page WHERE "
+ . $this->constructSet( 'page', $dbr );
+ // Do query
+ $res = $dbr->query( $sql, $fname );
+
+ // Process results
+ // For each returned entry, add it to the list of good links, and remove it from $remaining
+
+ $remaining = $this->data;
+ while ( $row = $dbr->fetchObject( $res ) ) {
+ $title = Title::makeTitle( $row->page_namespace, $row->page_title );
+ $cache->addGoodLinkObj( $row->page_id, $title );
+ unset( $remaining[$row->page_namespace][$row->page_title] );
+ }
+ $dbr->freeResult( $res );
+
+ // The remaining links in $data are bad links, register them as such
+ foreach ( $remaining as $ns => $dbkeys ) {
+ foreach ( $dbkeys as $dbkey => $nothing ) {
+ $title = Title::makeTitle( $ns, $dbkey );
+ $cache->addBadLinkObj( $title );
+ }
+ }
+
+ wfProfileOut( $fname );
+ }
+
+ /**
+ * Construct a WHERE clause which will match all the given titles.
+ * Give the appropriate table's field name prefix ('page', 'pl', etc).
+ *
+ * @param string $prefix
+ * @return string
+ * @access public
+ */
+ function constructSet( $prefix, $db ) {
+ $first = true;
+ $sql = '';
foreach ( $this->data as $ns => $dbkeys ) {
if ( !count( $dbkeys ) ) {
continue;
@@ -446,7 +517,7 @@ class LinkBatch {
} else {
$sql .= ' OR ';
}
- $sql .= "(page_namespace=$ns AND page_title IN (";
+ $sql .= "({$prefix}_namespace=$ns AND {$prefix}_title IN (";
$firstTitle = true;
foreach( $dbkeys as $dbkey => $nothing ) {
@@ -455,35 +526,12 @@ class LinkBatch {
} else {
$sql .= ',';
}
- $sql .= $dbr->addQuotes( $dbkey );
+ $sql .= $db->addQuotes( $dbkey );
}
$sql .= '))';
}
-
- // Do query
- $res = $dbr->query( $sql, $fname );
-
- // Process results
- // For each returned entry, add it to the list of good links, and remove it from $remaining
-
- $remaining = $this->data;
- while ( $row = $dbr->fetchObject( $res ) ) {
- $title = Title::makeTitle( $row->page_namespace, $row->page_title );
- $cache->addGoodLink( $row->page_id, $title->getPrefixedDBkey() );
- unset( $remaining[$row->page_namespace][$row->page_title] );
- }
- $dbr->freeResult( $res );
-
- // The remaining links in $data are bad links, register them as such
- foreach ( $remaining as $ns => $dbkeys ) {
- foreach ( $dbkeys as $dbkey => $nothing ) {
- $title = Title::makeTitle( $ns, $dbkey );
- $cache->addBadLink( $title->getPrefixedText() );
- }
- }
-
- wfProfileOut( $fname );
+ return $sql;
}
}
diff --git a/includes/LinksUpdate.php b/includes/LinksUpdate.php
index 47f01f50d7ad..617b2f9ea8ee 100644
--- a/includes/LinksUpdate.php
+++ b/includes/LinksUpdate.php
@@ -43,66 +43,43 @@ class LinksUpdate {
$add = array();
$dbw =& wfGetDB( DB_MASTER );
- $links = $dbw->tableName( 'links' );
- $brokenlinks = $dbw->tableName( 'brokenlinks' );
+ $pagelinks = $dbw->tableName( 'pagelinks' );
$imagelinks = $dbw->tableName( 'imagelinks' );
$categorylinks = $dbw->tableName( 'categorylinks' );
#------------------------------------------------------------------------------
# Good links
- if ( $wgLinkCache->incrementalSetup( LINKCACHE_GOOD, $del, $add ) ) {
+ if ( $wgLinkCache->incrementalSetup( LINKCACHE_PAGE, $del, $add ) ) {
# Delete where necessary
if ( count( $del ) ) {
- $dbw->delete('links',array('l_from'=>$this->mId, 'l_to'=> $del),$fname);
+ $batch = new LinkBatch( $del );
+ $set = $batch->constructSet( 'pl', $dbw );
+ $sql = "DELETE FROM $pagelinks WHERE pl_from={$this->mId} AND ($set)";
+ $dbw->query( $sql, $fname );
}
} else {
# Delete everything
- $dbw->delete( 'links', array( 'l_from' => $this->mId ), $fname );
+ $dbw->delete( 'pagelinks', array( 'pl_from' => $this->mId ), $fname );
# Get the addition list
$add = $wgLinkCache->getGoodLinks();
}
# Do the insertion
- if ( 0 != count( $add ) ) {
- $arr=array();
- foreach($add as $lt=>$lid)
+ if( 0 != count( $add ) ) {
+ $arr = array();
+ foreach( $add as $lt => $target ) {
array_push( $arr, array(
- 'l_from' => $this->mId,
- 'l_to' => $lid ) );
+ 'pl_from' => $this->mId,
+ 'pl_namespace' => $target->getNamespace(),
+ 'pl_title' => $target->getDbKey() ) );
+ }
+
# The link cache was constructed without FOR UPDATE, so there may be collisions
# Ignoring for now, I'm not sure if that causes problems or not, but I'm fairly
# sure it's better than without IGNORE
- $dbw->insert( 'links', $arr, $fname, array( 'IGNORE' ) );
- }
-
- #------------------------------------------------------------------------------
- # Bad links
-
- if ( $wgLinkCache->incrementalSetup( LINKCACHE_BAD, $del, $add ) ) {
- # Delete where necessary
- if ( count( $del ) ) {
- $dbw->delete('brokenlinks',array('bl_from'=>$this->mId, 'bl_to'=> $del),$fname);
- }
- } else {
- # Delete all
- $dbw->delete( 'brokenlinks', array( 'bl_from' => $this->mId ),$fname );
-
- # Get addition list
- $add = $wgLinkCache->getBadLinks();
- }
-
- # Do additions
- $sql = '';
- if ( 0 != count ( $add ) ) {
- $arr = array();
- foreach( $add as $blt ) {
- array_push( $arr, array(
- 'bl_from' => $this->mId,
- 'bl_to' => $blt ) );
- }
- $dbw->insert( 'brokenlinks', $arr, $fname, array( 'IGNORE' ) );
+ $dbw->insert( 'pagelinks', $arr, $fname, array( 'IGNORE' ) );
}
#------------------------------------------------------------------------------
@@ -196,8 +173,6 @@ class LinksUpdate {
}
}
- $this->fixBrokenLinks();
-
wfProfileOut( $fname );
}
@@ -213,37 +188,24 @@ class LinksUpdate {
$dbw =& wfGetDB( DB_MASTER );
- $links = $dbw->tableName( 'links' );
- $brokenlinks = $dbw->tableName( 'brokenlinks' );
+ $pagelinks = $dbw->tableName( 'pagelinks' );
$imagelinks = $dbw->tableName( 'imagelinks' );
$categorylinks = $dbw->tableName( 'categorylinks' );
- $dbw->delete('links', array('l_from'=>$this->mId),$fname);
+ $dbw->delete('pagelinks', array('pl_from'=>$this->mId),$fname);
- $a = $wgLinkCache->getGoodLinks();
+ $a = $wgLinkCache->getPageLinks();
if ( 0 != count( $a ) ) {
$arr = array();
- foreach( $a as $lt => $lid ) {
+ foreach( $a as $lt => $target ) {
array_push( $arr, array(
- 'l_from' => $this->mId,
- 'l_to' => $lid ) );
+ 'pl_from' => $this->mId,
+ 'pl_namespace' => $target->getNamespace(),
+ 'pl_title' => $target->getTitle() ) );
}
- $dbw->insert( 'links', $arr, $fname, array( 'IGNORE' ) );
+ $dbw->insert( 'pagelinks', $arr, $fname, array( 'IGNORE' ) );
}
- $dbw->delete('brokenlinks', array('bl_from'=>$this->mId),$fname);
-
- $a = $wgLinkCache->getBadLinks();
- if ( 0 != count ( $a ) ) {
- $arr = array();
- foreach( $a as $blt ) {
- array_push($arr,array(
- 'bl_from' => $this->mId,
- 'bl_to' => $blt));
- }
- $dbw->insert( 'brokenlinks', $arr, $fname, array( 'IGNORE' ) );
- }
-
$dbw->delete('imagelinks', array('il_from'=>$this->mId),$fname);
$a = $wgLinkCache->getImageLinks();
@@ -280,40 +242,7 @@ class LinksUpdate {
$dbw->insert( 'categorylinks', $arr, $fname, array( 'IGNORE' ) );
}
}
- $this->fixBrokenLinks();
wfProfileOut( $fname );
}
-
- /**
- * Update any brokenlinks *to* this page
- * Call for a newly created page, or just to make sure state is consistent
- */
- function fixBrokenLinks() {
- $fname = 'LinksUpdate::fixBrokenLinks';
-
- $dbw =& wfGetDB( DB_MASTER );
- $page = $dbw->tableName( 'page' );
- $links = $dbw->tableName( 'links' );
-
- $res = $dbw->select( 'brokenlinks', array( 'bl_from' ), array( 'bl_to' => $this->mTitle ),
- $fname, 'FOR UPDATE' );
- if ( 0 == $dbw->numRows( $res ) ) { return; }
-
- $arr=array();
- $toucharr=array();
- while ( $row = $dbw->fetchObject( $res ) ) {
- array_push( $arr, array(
- 'l_from' => $row->bl_from,
- 'l_to' => $this->mId ) );
- $toucharr[]=$row->bl_from;
- }
-
- # Ignore errors. If a link existed in both the brokenlinks table and the links
- # table, that's an error which can be fixed at this stage by simply ignoring collisions
- $dbw->insert( 'links', $arr, $fname, array( 'IGNORE' ) );
- $dbw->update( 'page', /* SET */ array( 'page_touched' => $dbw->timestamp() ),
- /* WHERE */ array( 'page_id' => $toucharr ),$fname);
- $dbw->delete( 'brokenlinks', array( 'bl_to' => $this->mTitle ), $fname );
- }
}
?>
diff --git a/includes/Parser.php b/includes/Parser.php
index abd62c63a978..292776844878 100644
--- a/includes/Parser.php
+++ b/includes/Parser.php
@@ -2911,7 +2911,7 @@ class Parser
while ( $s = $dbr->fetchObject($res) ) {
$title = Title::makeTitle( $s->page_namespace, $s->page_title );
$pdbk = $title->getPrefixedDBkey();
- $wgLinkCache->addGoodLink( $s->page_id, $pdbk );
+ $wgLinkCache->addGoodLinkObj( $s->page_id, $title );
if ( $threshold > 0 ) {
$size = $s->page_len;
@@ -2935,7 +2935,7 @@ class Parser
$searchkey = "<!--LINK $key-->";
$title = $this->mLinkHolders['titles'][$key];
if ( empty( $colours[$pdbk] ) ) {
- $wgLinkCache->addBadLink( $pdbk );
+ $wgLinkCache->addBadLinkObj( $title );
$colours[$pdbk] = 0;
$wgOutputReplace[$searchkey] = $sk->makeBrokenLinkObj( $title,
$this->mLinkHolders['texts'][$key],
diff --git a/includes/SpecialBrokenRedirects.php b/includes/SpecialBrokenRedirects.php
index 98fcc7c4efa9..61716eb67626 100644
--- a/includes/SpecialBrokenRedirects.php
+++ b/includes/SpecialBrokenRedirects.php
@@ -31,11 +31,19 @@ class BrokenRedirectsPage extends PageQueryPage {
function getSQL() {
$dbr =& wfGetDB( DB_SLAVE );
- extract( $dbr->tableNames( 'page', 'brokenlinks' ) );
+ extract( $dbr->tableNames( 'page', 'pagelinks' ) );
- $sql = "SELECT 'BrokenRedirects' as type, page_namespace as namespace," .
- "page_title as title, bl_to FROM $brokenlinks,$page " .
- 'WHERE page_is_redirect=1 AND bl_from=page_id ';
+ $sql = "SELECT 'BrokenRedirects' AS type,
+ p1.page_namespace AS namespace,
+ p1.page_title AS title,
+ pl_namespace,
+ pl_title
+ FROM $pagelinks, $page AS p1
+ LEFT JOIN $page AS p2
+ ON pl_namespace=p2.page_namespace AND pl_title=p2.page_title
+ WHERE p1.page_is_redirect=1
+ AND pl_from=p1.page_id
+ AND p2.page_namespace IS NULL";
return $sql;
}
@@ -45,8 +53,8 @@ class BrokenRedirectsPage extends PageQueryPage {
function formatResult( $skin, $result ) {
$fromObj = Title::makeTitle( $result->namespace, $result->title );
- if ( isset( $result->bl_to ) ) {
- $toObj = Title::newFromText( $result->bl_to );
+ if ( isset( $result->pl_title ) ) {
+ $toObj = Title::makeTitle( $result->pl_namespace, $result->pl_title );
} else {
$blinks = $fromObj->getBrokenLinksFrom();
if ( $blinks ) {
diff --git a/includes/SpecialDeadendpages.php b/includes/SpecialDeadendpages.php
index 3329e33ac6d2..286460d812b1 100644
--- a/includes/SpecialDeadendpages.php
+++ b/includes/SpecialDeadendpages.php
@@ -44,10 +44,10 @@ class DeadendPagesPage extends PageQueryPage {
*/
function getSQL() {
$dbr =& wfGetDB( DB_SLAVE );
- extract( $dbr->tableNames( 'page', 'links' ) );
+ extract( $dbr->tableNames( 'page', 'pagelinks' ) );
return "SELECT 'Deadendpages' as type, page_namespace AS namespace, page_title as title, page_title AS value " .
- "FROM $page LEFT JOIN $links ON page_id = l_from " .
- "WHERE l_from IS NULL " .
+ "FROM $page LEFT JOIN $pagelinks ON page_id = pl_from " .
+ "WHERE pl_from IS NULL " .
"AND page_namespace = 0 " .
"AND page_is_redirect = 0";
}
diff --git a/includes/SpecialDisambiguations.php b/includes/SpecialDisambiguations.php
index 2522e6668a4f..10a329490b62 100644
--- a/includes/SpecialDisambiguations.php
+++ b/includes/SpecialDisambiguations.php
@@ -34,20 +34,19 @@ class DisambiguationsPage extends PageQueryPage {
function getSQL() {
$dbr =& wfGetDB( DB_SLAVE );
- extract( $dbr->tableNames( 'page', 'links' ) );
+ extract( $dbr->tableNames( 'page', 'pagelinks' ) );
$dp = Title::newFromText(wfMsgForContent("disambiguationspage"));
+ $id = $dp->getArticleId();
$dns = $dp->getNamespace();
$dtitle = $dbr->addQuotes( $dp->getDBkey() );
$sql = "SELECT 'Disambiguations' as type,"
- . " pa.page_namespace AS namespace, pa.page_title AS title"
- . " FROM {$links} as la, {$links} as lb, {$page} as pa, {$page} as pb"
- . " WHERE pb.page_namespace = $dns"
- . " AND pb.page_title = $dtitle"
- . " AND la.l_from = lb.l_to"
- . " AND pa.page_id = lb.l_from"
- . " AND pb.page_id = lb.l_to" ;
+ . " pl_namespace AS namespace, pl_title AS title"
+ . " FROM {$pagelinks}, {$page}"
+ . " WHERE page_namespace = $dns"
+ . " AND page_title = $dtitle"
+ . " AND pl_from=page_id";
return $sql;
}
diff --git a/includes/SpecialDoubleRedirects.php b/includes/SpecialDoubleRedirects.php
index 9c0563e5ab8e..316984461059 100644
--- a/includes/SpecialDoubleRedirects.php
+++ b/includes/SpecialDoubleRedirects.php
@@ -31,18 +31,20 @@ class DoubleRedirectsPage extends PageQueryPage {
function getSQL() {
$dbr =& wfGetDB( DB_SLAVE );
- extract( $dbr->tableNames( 'page', 'links' ) );
+ extract( $dbr->tableNames( 'page', 'pagelinks' ) );
$sql = "SELECT 'DoubleRedirects' as type," .
" pa.page_namespace as namespace, pa.page_title as title," .
" pb.page_namespace as nsb, pb.page_title as tb," .
" pc.page_namespace as nsc, pc.page_title as tc" .
- " FROM $links AS la, $links AS lb, $page AS pa, $page AS pb, $page AS pc" .
+ " FROM $pagelinks AS la, $pagelinks AS lb, $page AS pa, $page AS pb, $page AS pc" .
" WHERE pa.page_is_redirect=1 AND pb.page_is_redirect=1" .
- " AND la.l_from=pa.page_id" .
- " AND la.l_to=pb.page_id" .
- " AND lb.l_from=pb.page_id" .
- " AND lb.l_to=pc.page_id";
+ " AND la.pl_from=pa.page_id" .
+ " AND la.pl_namespace=pb.page_namespace" .
+ " AND la.pl_title=pb.page_title" .
+ " AND lb.pl_from=pb.page_id" .
+ " AND lb.pl_namespace=pc.page_namespace" .
+ " AND lb.pl_title=pc.page_title";
return $sql;
}
@@ -56,18 +58,20 @@ class DoubleRedirectsPage extends PageQueryPage {
if ( $result && !isset( $result->nsb ) ) {
$dbr =& wfGetDB( DB_SLAVE );
- extract( $dbr->tableNames( 'page', 'links' ) );
+ extract( $dbr->tableNames( 'page', 'pagelinks' ) );
$encTitle = $dbr->addQuotes( $result->title );
$sql = "SELECT pa.page_namespace as namespace, pa.page_title as title," .
" pb.page_namespace as nsb, pb.page_title as tb," .
" pc.page_namespace as nsc, pc.page_title as tc" .
- " FROM $links AS la, $links AS lb, $page AS pa, $page AS pb, $page AS pc" .
+ " FROM $pagelinks AS la, $pagelinks AS lb, $page AS pa, $page AS pb, $page AS pc" .
" WHERE pa.page_is_redirect=1 AND pb.page_is_redirect=1" .
- " AND la.l_from=pa.page_id" .
- " AND la.l_to=pb.page_id" .
- " AND lb.l_from=pb.page_id" .
- " AND lb.l_to=pc.page_id" .
+ " AND la.pl_from=pa.page_id" .
+ " AND la.pl_namespace=pb.page_namespace" .
+ " AND la.pl_title=pb.page_title" .
+ " AND lb.pl_from=pb.page_id" .
+ " AND lb.pl_namespace=pc.page_namespace" .
+ " AND lb.pl_title=pc.page_title" .
" AND pa.page_namespace={$result->namespace}" .
" AND pa.page_title=$encTitle";
$res = $dbr->query( $sql, $fname );
diff --git a/includes/SpecialLog.php b/includes/SpecialLog.php
index 9d91f7fe825f..bfaee33ec173 100644
--- a/includes/SpecialLog.php
+++ b/includes/SpecialLog.php
@@ -300,9 +300,9 @@ class LogViewer {
// Enter the existence or non-existence of this page into the link cache,
// for faster makeLinkObj() in LogPage::actionText()
if( $s->page_id ) {
- $wgLinkCache->addGoodLink( $s->page_id, $title->getPrefixedText() );
+ $wgLinkCache->addGoodLinkObj( $s->page_id, $title );
} else {
- $wgLinkCache->addBadLink( $title->getPrefixedText() );
+ $wgLinkCache->addBadLinkObj( $title );
}
$userLink = $this->skin->makeLinkObj( $user, htmlspecialchars( $s->user_name ) );
diff --git a/includes/SpecialLonelypages.php b/includes/SpecialLonelypages.php
index 6f0f73f7c54f..a143f1494a93 100644
--- a/includes/SpecialLonelypages.php
+++ b/includes/SpecialLonelypages.php
@@ -32,11 +32,20 @@ class LonelyPagesPage extends PageQueryPage {
function getSQL() {
$dbr =& wfGetDB( DB_SLAVE );
- extract( $dbr->tableNames( 'page', 'links' ) );
+ extract( $dbr->tableNames( 'page', 'pagelinks' ) );
+
+ return
+ "SELECT 'Lonelypages' AS type,
+ page_namespace AS namespace,
+ page_title AS title,
+ page_title AS value
+ FROM $page
+ LEFT JOIN $pagelinks
+ ON page_namespace=pl_namespace AND page_title=pl_title
+ WHERE pl_namespace IS NULL
+ AND page_namespace=".NS_MAIN."
+ AND page_is_redirect=0";
- return "SELECT 'Lonelypages' as type, page_namespace AS namespace, page_title AS title, page_title AS value " .
- "FROM $page LEFT JOIN $links ON page_id=l_to ".
- 'WHERE l_to IS NULL AND page_namespace='.NS_MAIN.' AND page_is_redirect=0';
}
}
diff --git a/includes/SpecialRecentchangeslinked.php b/includes/SpecialRecentchangeslinked.php
index 86ec1b9ef744..2717d63c0064 100644
--- a/includes/SpecialRecentchangeslinked.php
+++ b/includes/SpecialRecentchangeslinked.php
@@ -62,22 +62,43 @@ function wfSpecialRecentchangeslinked( $par = NULL ) {
$cmq = 'AND rev_minor_edit=0';
} else { $cmq = ''; }
- extract( $dbr->tableNames( 'categorylinks', 'links', 'revision', 'page' ) );
+ extract( $dbr->tableNames( 'categorylinks', 'pagelinks', 'revision', 'page' ) );
// If target is a Category, use categorylinks and invert from and to
if( $nt->getNamespace() == NS_CATEGORY ) {
$catkey = $dbr->addQuotes( $nt->getDBKey() );
- $sql = "SELECT page_id,page_namespace,page_title,rev_user,rev_comment," .
- "rev_user_text,rev_timestamp,rev_minor_edit,page_is_new FROM $categorylinks, $revision, $page " .
- "WHERE rev_timestamp > '{$cutoff}' {$cmq} AND cl_from=page_id AND cl_to=$catkey " .
- "GROUP BY page_id,page_namespace,page_title,rev_user,rev_comment,rev_user_text," .
- "rev_timestamp,rev_minor_edit,page_is_new ORDER BY rev_timestamp DESC LIMIT {$limit}";
+ $sql =
+ "SELECT page_id,page_namespace,page_title,rev_user,rev_comment,
+ rev_user_text,rev_timestamp,rev_minor_edit,
+ page_is_new
+ FROM $categorylinks, $revision, $page
+ WHERE rev_timestamp > '{$cutoff}'
+ {$cmq}
+ AND rev_page=page_id
+ AND cl_from=page_id
+ AND cl_to=$catkey
+GROUP BY page_id,page_namespace,page_title,
+ rev_user,rev_comment,rev_user_text,rev_timestamp,rev_minor_edit,
+ page_is_new
+ORDER BY rev_timestamp DESC
+ LIMIT {$limit}";
} else {
- $sql = "SELECT page_id,page_namespace,page_title,rev_user,rev_comment," .
- "rev_user_text,rev_timestamp,rev_minor_edit,page_is_new FROM $links, $revision, $page " .
- "WHERE rev_timestamp > '{$cutoff}' {$cmq} AND l_to=page_id AND l_from=$id " .
- "GROUP BY page_id,page_namespace,page_title,rev_user,rev_comment,rev_user_text," .
- "rev_timestamp,rev_minor_edit,page_is_new ORDER BY rev_timestamp DESC LIMIT {$limit}";
+ $sql =
+ "SELECT page_id,page_namespace,page_title,
+ rev_user,rev_comment,rev_user_text,rev_timestamp,rev_minor_edit,
+ page_is_new
+ FROM $pagelinks, $revision, $page
+ WHERE rev_timestamp > '{$cutoff}'
+ {$cmq}
+ AND rev_page=page_id
+ AND pl_namespace=page_namespace
+ AND pl_title=page_title
+ AND pl_from=$id
+GROUP BY page_id,page_namespace,page_title,
+ rev_user,rev_comment,rev_user_text,rev_timestamp,rev_minor_edit,
+ page_is_new
+ORDER BY rev_timestamp DESC
+ LIMIT {$limit}";
}
$res = $dbr->query( $sql, $fname );
diff --git a/includes/SpecialWantedpages.php b/includes/SpecialWantedpages.php
index 1cbd8bb9fc0a..2f16efb5a95d 100644
--- a/includes/SpecialWantedpages.php
+++ b/includes/SpecialWantedpages.php
@@ -28,30 +28,28 @@ class WantedPagesPage extends QueryPage {
function getSQL() {
$dbr =& wfGetDB( DB_SLAVE );
- $brokenlinks = $dbr->tableName( 'brokenlinks' );
-
- # We cheat and return the full-text from bl_to in the title.
- # In the future, a pre-parsed name will be available.
- $agrvalue=$dbr->aggregateValue('COUNT(DISTINCT bl_from)');
+ $pagelinks = $dbr->tableName( 'pagelinks' );
+ $page = $dbr->tableName( 'page' );
return
- "SELECT 'Wantedpages' as type,
- 0 as namespace,
- bl_to as title,
- COUNT(DISTINCT bl_from) as value
- FROM $brokenlinks
- GROUP BY bl_to
- HAVING $agrvalue > 1";
+ "SELECT 'Wantedpages' AS type,
+ pl_namespace AS namespace,
+ pl_title AS title,
+ COUNT(*) AS value
+ FROM $pagelinks
+ LEFT JOIN $page
+ ON pl_namespace=page_namespace AND pl_title=page_title
+ WHERE page_namespace IS NULL
+ GROUP BY pl_namespace,pl_title
+ HAVING COUNT(*) > 1";
}
function formatResult( $skin, $result ) {
global $wgContLang;
- $nt = Title::newFromDBkey( $result->title );
- $text = $wgContLang->convert( $result->title );
- if( is_null( $nt ) ) {
- return "<!-- Bad title '" . htmlspecialchars( $result->title ) . "' -->";
- }
+ $nt = Title::makeTitle( $result->namespace, $result->title );
+ $text = $wgContLang->convert( $nt->getPrefixedText() );
$plink = $skin->makeBrokenLink( $nt->getPrefixedText(), $text );
+
$nl = wfMsg( "nlinks", $result->value );
$nlink = $skin->makeKnownLink( $wgContLang->specialPage( "Whatlinkshere" ), $nl,
"target=" . $nt->getPrefixedURL() );
diff --git a/includes/SpecialWhatlinkshere.php b/includes/SpecialWhatlinkshere.php
index ac1dec0e1115..81e8faa6660f 100644
--- a/includes/SpecialWhatlinkshere.php
+++ b/includes/SpecialWhatlinkshere.php
@@ -29,7 +29,6 @@ function wfSpecialWhatlinkshere($par = NULL) {
$wgOut->setPagetitle( $nt->getPrefixedText() );
$wgOut->setSubtitle( wfMsg( 'linklistsub' ) );
- $id = $nt->getArticleID();
$sk = $wgUser->getSkin();
$isredir = ' (' . wfMsg( 'isredirect' ) . ")\n";
@@ -38,53 +37,22 @@ function wfSpecialWhatlinkshere($par = NULL) {
$specialTitle = Title::makeTitle( NS_SPECIAL, 'Whatlinkshere' );
$wgOut->addHTML( wfViewPrevNext( $offset, $limit, $specialTitle, 'target=' . urlencode( $target ) ) );
- $dbr =& wfGetDB( DB_SLAVE );
- extract( $dbr->tableNames( 'page', 'brokenlinks', 'links' ) );
-
- if ( 0 == $id ) {
- $sql = "SELECT page_id,page_namespace,page_title,page_is_redirect FROM $brokenlinks,$page WHERE bl_to='" .
- $dbr->strencode( $nt->getPrefixedDBkey() ) . "' AND bl_from=page_id " .
- $dbr->limitResult( $limit, $offset );
- $res = $dbr->query( $sql, $fname );
-
- if ( 0 == $dbr->numRows( $res ) ) {
- $wgOut->addHTML( wfMsg( 'nolinkshere' ) );
- } else {
- $wgOut->addHTML( wfMsg( 'linkshere' ) );
- $wgOut->addHTML( "\n<ul>" );
-
- while ( $row = $dbr->fetchObject( $res ) ) {
- $nt = Title::makeTitle( $row->page_namespace, $row->page_title );
- if( !$nt ) {
- continue;
- }
- $link = $sk->makeKnownLinkObj( $nt, '', 'redirect=no' );
- $wgOut->addHTML( "<li>{$link}" );
-
- if ( $row->page_is_redirect ) {
- $wgOut->addHTML( $isredir );
- wfShowIndirectLinks( 1, $row->page_id, 500 );
- }
- $wgOut->addHTML( "</li>\n" );
- }
- $wgOut->addHTML( "</ul>\n" );
- $dbr->freeResult( $res );
- }
- } else {
- wfShowIndirectLinks( 0, $id, $limit, $offset );
- }
+ wfShowIndirectLinks( 0, $nt, $limit, $offset );
$wgOut->addHTML( wfViewPrevNext( $offset, $limit, $specialTitle, 'target=' . urlencode( $target ) ) );
}
/**
- *
+ * @param int $level
+ * @param Title $target
+ * @param int $limit
+ * @param int $offset
+ * @access private
*/
-function wfShowIndirectLinks( $level, $lid, $limit, $offset = 0 ) {
+function wfShowIndirectLinks( $level, $target, $limit, $offset = 0 ) {
global $wgOut, $wgUser;
$fname = 'wfShowIndirectLinks';
$dbr =& wfGetDB( DB_READ );
- extract( $dbr->tableNames( 'links','page' ) );
if ( $level == 0 ) {
$limitSql = $dbr->limitResult( $limit, $offset );
@@ -92,8 +60,14 @@ function wfShowIndirectLinks( $level, $lid, $limit, $offset = 0 ) {
$limitSql = "LIMIT $limit";
}
- $sql = "SELECT page_id,page_namespace,page_title,page_is_redirect FROM $links,$page WHERE l_to={$lid} AND l_from=page_id $limitSql";
- $res = $dbr->query( $sql, $fname );
+ $res = $dbr->select( array( 'pagelinks', 'page' ),
+ array( 'page_id', 'page_namespace', 'page_title', 'page_is_redirect' ),
+ array(
+ 'pl_from=page_id',
+ 'pl_namespace' => $target->getNamespace(),
+ 'pl_title' => $target->getDbKey() ),
+ $fname,
+ $limitSql );
if ( 0 == $dbr->numRows( $res ) ) {
if ( 0 == $level ) {
@@ -110,10 +84,6 @@ function wfShowIndirectLinks( $level, $lid, $limit, $offset = 0 ) {
$wgOut->addHTML( '<ul>' );
while ( $row = $dbr->fetchObject( $res ) ) {
$nt = Title::makeTitle( $row->page_namespace, $row->page_title );
- if( !$nt ) {
- $wgOut->addHTML( '<!-- bad backlink: ' . htmlspecialchars( $row->l_from ) . " -->\n" );
- continue;
- }
if ( $row->page_is_redirect ) {
$extra = 'redirect=no';
@@ -127,7 +97,7 @@ function wfShowIndirectLinks( $level, $lid, $limit, $offset = 0 ) {
if ( $row->page_is_redirect ) {
$wgOut->addHTML( $isredir );
if ( $level < 2 ) {
- wfShowIndirectLinks( $level + 1, $row->page_id, 500 );
+ wfShowIndirectLinks( $level + 1, $nt, 500 );
}
}
$wgOut->addHTML( "</li>\n" );
diff --git a/includes/SquidUpdate.php b/includes/SquidUpdate.php
index 484f26dec453..91769b2a1d53 100644
--- a/includes/SquidUpdate.php
+++ b/includes/SquidUpdate.php
@@ -35,8 +35,13 @@ class SquidUpdate {
$links = $dbr->tableName( 'links' );
$page = $dbr->tableName( 'page' );
- $sql = "SELECT page_namespace,page_title FROM $links,$page WHERE l_to={$id} and l_from=page_id" ;
- $res = $dbr->query( $sql, $fname ) ;
+ $res = $dbr->select( array( 'links', 'page' ),
+ array( 'page_namespace', 'page_title' ),
+ array(
+ 'pl_namespace' => $title->getNamespace(),
+ 'pl_title' => $title->getDbKey(),
+ 'pl_from=page_id' ),
+ $fname );
$blurlArr = $title->getSquidURLs();
if ( $dbr->numRows( $res ) <= $this->mMaxTitles ) {
while ( $BL = $dbr->fetchObject ( $res ) )
@@ -51,31 +56,6 @@ class SquidUpdate {
return new SquidUpdate( $blurlArr );
}
- /* static */ function newFromBrokenLinksTo( &$title ) {
- $fname = 'SquidUpdate::newFromBrokenLinksTo';
- wfProfileIn( $fname );
-
- # Get a list of URLs linking to this (currently non-existent) page
- $dbr =& wfGetDB( DB_SLAVE );
- $brokenlinks = $dbr->tableName( 'brokenlinks' );
- $page = $dbr->tableName( 'page' );
- $encTitle = $dbr->addQuotes( $title->getPrefixedDBkey() );
-
- $sql = "SELECT page_namespace,page_title FROM $brokenlinks,$cur WHERE bl_to={$encTitle} AND bl_from=page_id";
- $res = $dbr->query( $sql, $fname );
- $blurlArr = array();
- if ( $dbr->numRows( $res ) <= $this->mMaxTitles ) {
- while ( $BL = $dbr->fetchObject( $res ) )
- {
- $tobj = Title::makeTitle( $BL->page_namespace, $BL->page_title );
- $blurlArr[] = $tobj->getInternalURL();
- }
- }
- $dbr->freeResult( $res );
- wfProfileOut( $fname );
- return new SquidUpdate( $blurlArr );
- }
-
/* static */ function newFromTitles( &$titles, $urlArr = array() ) {
foreach ( $titles as $title ) {
$urlArr[] = $title->getInternalURL();
diff --git a/includes/Title.php b/includes/Title.php
index a5e119f073cf..6810ee9e6795 100644
--- a/includes/Title.php
+++ b/includes/Title.php
@@ -1355,16 +1355,21 @@ class Title {
} else {
$db =& wfGetDB( DB_SLAVE );
}
- $page = $db->tableName( 'page' );
- $links = $db->tableName( 'links' );
-
- $sql = "SELECT page_namespace,page_title,page_id FROM $page,$links WHERE l_from=page_id AND l_to={$id} $options";
- $res = $db->query( $sql, 'Title::getLinksTo' );
+
+ $res = $db->select( array( 'page', 'pagelinks' ),
+ array( 'page_namespace', 'page_title', 'page_id' ),
+ array(
+ 'pl_from=page_id',
+ 'pl_namespace' => $this->getNamespace(),
+ 'pl_title' => $this->getDbKey() ),
+ 'Title::getLinksTo',
+ $options );
+
$retVal = array();
if ( $db->numRows( $res ) ) {
while ( $row = $db->fetchObject( $res ) ) {
if ( $titleObj = Title::makeTitle( $row->page_namespace, $row->page_title ) ) {
- $wgLinkCache->addGoodLink( $row->page_id, $titleObj->getPrefixedDBkey() );
+ $wgLinkCache->addGoodLinkObj( $row->page_id, $titleObj );
$retVal[] = $titleObj;
}
}
@@ -1374,42 +1379,6 @@ class Title {
}
/**
- * Get an array of Title objects linking to this non-existent title.
- * - Also stores the IDs in the link cache.
- *
- * @param string $options may be FOR UPDATE
- * @return array the Title objects linking here
- * @access public
- */
- function getBrokenLinksTo( $options = '' ) {
- global $wgLinkCache;
-
- if ( $options ) {
- $db =& wfGetDB( DB_MASTER );
- } else {
- $db =& wfGetDB( DB_SLAVE );
- }
- $page = $db->tableName( 'page' );
- $brokenlinks = $db->tableName( 'brokenlinks' );
- $encTitle = $db->strencode( $this->getPrefixedDBkey() );
-
- $sql = "SELECT page_namespace,page_title,page_id FROM $brokenlinks,$page " .
- "WHERE bl_from=page_id AND bl_to='$encTitle' $options";
- $res = $db->query( $sql, "Title::getBrokenLinksTo" );
- $retVal = array();
- if ( $db->numRows( $res ) ) {
- while ( $row = $db->fetchObject( $res ) ) {
- $titleObj = Title::makeTitle( $row->page_namespace, $row->page_title );
- $wgLinkCache->addGoodLink( $row->page_id, $titleObj->getPrefixedDBkey() );
- $retVal[] = $titleObj;
- }
- }
- $db->freeResult( $res );
- return $retVal;
- }
-
-
- /**
* Get an array of Title objects referring to non-existent articles linked from this page
*
* @param string $options may be FOR UPDATE
@@ -1424,16 +1393,25 @@ class Title {
} else {
$db =& wfGetDB( DB_SLAVE );
}
- $page = $db->tableName( 'page' );
- $brokenlinks = $db->tableName( 'brokenlinks' );
- $id = $this->getArticleID();
-
- $sql = "SELECT bl_to FROM $brokenlinks WHERE bl_from=$id $options";
- $res = $db->query( $sql, "Title::getBrokenLinksFrom" );
+
+ $res = $db->safeQuery(
+ "SELECT pl_namespace, pl_title
+ FROM !
+ LEFT JOIN !
+ ON pl_namespace=page_namespace
+ AND pl_title=page_title
+ WHERE pl_from=?
+ AND page_namespace IS NULL
+ !",
+ $db->tableName( 'pagelinks' ),
+ $db->tableName( 'page' ),
+ $this->getArticleId(),
+ $options );
+
$retVal = array();
if ( $db->numRows( $res ) ) {
while ( $row = $db->fetchObject( $res ) ) {
- $retVal[] = Title::newFromText( $row->bl_to );
+ $retVal[] = Title::makeTitle( $row->pl_namespace, $row->pl_title );
}
}
$db->freeResult( $res );
@@ -1631,54 +1609,19 @@ class Title {
$log = new LogPage( 'move' );
$log->addEntry( 'move_redir', $this, $reason, array( 1 => $nt->getPrefixedText() ) );
- # Swap links
-
- # Load titles and IDs
- $linksToOld = $this->getLinksTo( 'FOR UPDATE' );
- $linksToNew = $nt->getLinksTo( 'FOR UPDATE' );
-
- # Delete them all
- $sql = "DELETE FROM $links WHERE l_to=$oldid OR l_to=$newid";
- $dbw->query( $sql, $fname );
-
- # Reinsert
- if ( count( $linksToOld ) || count( $linksToNew )) {
- $sql = "INSERT INTO $links (l_from,l_to) VALUES ";
- $first = true;
-
- # Insert links to old title
- foreach ( $linksToOld as $linkTitle ) {
- if ( $first ) {
- $first = false;
- } else {
- $sql .= ',';
- }
- $id = $linkTitle->getArticleID();
- $sql .= "($id,$newid)";
- }
-
- # Insert links to new title
- foreach ( $linksToNew as $linkTitle ) {
- if ( $first ) {
- $first = false;
- } else {
- $sql .= ',';
- }
- $id = $linkTitle->getArticleID();
- $sql .= "($id, $oldid)";
- }
-
- $dbw->query( $sql, $fname );
- }
-
# Now, we record the link from the redirect to the new title.
# It should have no other outgoing links...
- $dbw->delete( 'links', array( 'l_from' => $newid ) );
- $dbw->insert( 'links', array( 'l_from' => $newid, 'l_to' => $oldid ) );
+ $dbw->delete( 'pagelinks', array( 'pl_from' => $newid ), $fname );
+ $dbw->insert( 'pagelinks',
+ array(
+ 'pl_from' => $newid,
+ 'pl_namespace' => $this->getNamespace(),
+ 'pl_title' => $this->getDbKey() ),
+ $fname );
# Clear linkscc
- LinkCache::linksccClearLinksTo( $oldid );
- LinkCache::linksccClearLinksTo( $newid );
+ LinkCache::linksccClearLinksTo( $this );
+ LinkCache::linksccClearLinksTo( $nt );
# Purge squid
if ( $wgUseSquid ) {
@@ -1749,17 +1692,17 @@ class Title {
# Purge squid and linkscc as per article creation
Article::onArticleCreate( $nt );
- # Any text links to the old title must be reassigned to the redirect
- $dbw->update( 'links', array( 'l_to' => $newid ), array( 'l_to' => $oldid ), $fname );
- LinkCache::linksccClearLinksTo( $oldid );
-
# Record the just-created redirect's linking to the page
- $dbw->insert( 'links', array( 'l_from' => $newid, 'l_to' => $oldid ), $fname );
+ $dbw->insert( 'pagelinks',
+ array(
+ 'pl_from' => $newid,
+ 'pl_namespace' => $this->getNamespace(),
+ 'pl_title' => $this->getTitle() ),
+ $fname );
# Non-existent target may have had broken links to it; these must
- # now be removed and made into good links.
- $update = new LinksUpdate( $oldid, $nt->getPrefixedDBkey() );
- $update->fixBrokenLinks();
+ # now be touched to update link coloring.
+ $nt->touchLinks();
# Purge old title from squid
# The new title, and links to the new title, are purged in Article::onArticleCreate()
@@ -1849,21 +1792,13 @@ class Title {
$article->updateRevisionOn( $dbw, $revision, 0 );
# Link table
- if ( $dest->getArticleID() ) {
- $dbw->insert( 'links',
- array(
- 'l_to' => $dest->getArticleID(),
- 'l_from' => $newid
- ), $fname
- );
- } else {
- $dbw->insert( 'brokenlinks',
- array(
- 'bl_to' => $dest->getPrefixedDBkey(),
- 'bl_from' => $newid
- ), $fname
- );
- }
+ $dbw->insert( 'pagelinks',
+ array(
+ 'pl_from' => $newid,
+ 'pl_namespace' => $dest->getNamespace(),
+ 'pl_title' => $dest->getDbKey()
+ ), $fname
+ );
Article::onArticleCreate( $this );
return true;
@@ -2015,5 +1950,35 @@ class Title {
return ( 0 == $this->mNamespace && "" == $this->mDbkeyform )
|| NS_SPECIAL == $this->mNamespace || NS_IMAGE == $this->mNamespace;
}
+
+ /**
+ * Update page_touched timestamps on pages linking to this title.
+ * In principal, this could be backgrounded and could also do squid
+ * purging.
+ */
+ function touchLinks() {
+ $fname = 'Title::touchLinks';
+
+ $dbw =& wfGetDB( DB_MASTER );
+
+ $res = $dbw->select( 'pagelinks',
+ array( 'pl_from' ),
+ array(
+ 'pl_namespace' => $this->getNamespace(),
+ 'pl_title' => $this->getDbKey() ),
+ $fname );
+ if ( 0 == $dbw->numRows( $res ) ) {
+ return;
+ }
+
+ $arr = array();
+ $toucharr = array();
+ while( $row = $dbw->fetchObject( $res ) ) {
+ $toucharr[] = $row->pl_from;
+ }
+
+ $dbw->update( 'page', /* SET */ array( 'page_touched' => $dbw->timestamp() ),
+ /* WHERE */ array( 'page_id' => $toucharr ),$fname);
+ }
}
?>
diff --git a/maintenance/convertUtf8.php b/maintenance/convertUtf8.php
index 8e9c5cc804ed..14096cf1510a 100644
--- a/maintenance/convertUtf8.php
+++ b/maintenance/convertUtf8.php
@@ -156,7 +156,7 @@ class UtfUpdater {
$this->convertTable( 'recentchanges', 'rc_id',
array( 'rc_user_text', 'rc_title', 'rc_comment' ) );
- $this->convertTable( 'brokenlinks', 'bl_to' );
+ $this->convertTable( 'pagelinks', 'pl_title' );
$this->convertTable( 'categorylinks', 'cl_to' );
$this->convertTable( 'imagelinks', 'il_to' );
$this->convertTable( 'watchlist', 'wl_title' );
diff --git a/maintenance/refreshLinks.inc b/maintenance/refreshLinks.inc
index d788892b71da..b7e1a23420e2 100644
--- a/maintenance/refreshLinks.inc
+++ b/maintenance/refreshLinks.inc
@@ -14,9 +14,9 @@ function refreshLinks( $start ) {
$dbw =& wfGetDB( DB_MASTER );
- $end = $dbw->selectField( 'cur', 'max(cur_id)', false );
+ $end = $dbw->selectField( 'page', 'max(page_id)', false );
- print("Refreshing link table. Starting from cur_id $start of $end.\n");
+ print("Refreshing link table. Starting from page_id $start of $end.\n");
# Don't generate TeX PNGs (lack of a sensible current directory causes errors anyway)
$wgUser->setOption("math", 3);
@@ -65,7 +65,6 @@ function refreshLinks( $start ) {
$linksUpdate = new LinksUpdate( $id, $wgTitle->getPrefixedDBkey() );
$linksUpdate->doDumbUpdate();
- $linksUpdate->fixBrokenLinks();
$dbw->query("COMMIT");
}
}
diff --git a/maintenance/remove-brokenlinks.php b/maintenance/remove-brokenlinks.php
deleted file mode 100644
index a4a139ee39c5..000000000000
--- a/maintenance/remove-brokenlinks.php
+++ /dev/null
@@ -1,58 +0,0 @@
-<?php
-/**
- * Remove spurious brokenlinks
- * @package MediaWiki
- * @subpackage Maintenance
- */
-
-/** */
-require_once( "commandLine.inc" );
-require_once( "./rebuildrecentchanges.inc" );
-$wgTitle = Title::newFromText( "Rebuild brokenlinks script" );
-
-$n = 0;
-
-echo "Checking for broken brokenlinks...\n";
-
-$dbw =& wfGetDB( DB_MASTER );
-extract( $dbw->tableNames( 'brokenlinks', 'cur', 'linkscc' ) );
-
-$res = $dbw->select( 'cur', array( 'cur_namespace', 'cur_title', 'cur_id' ), false );
-
-while( $s = $dbw->fetchObject( $res ) ) {
- $n++;
- if(($n % 500) == 0) {
- echo "$n\n";
- }
- $title = Title::makeTitle( $s->cur_namespace, $s->cur_title );
- if($title) {
- $t = $title->getPrefixedDBKey();
- $tt = $dbw->strencode( $t );
- $any = false;
- $sql2 = "SELECT bl_from,cur_id,cur_namespace,cur_title FROM $brokenlinks,$cur " .
- "WHERE bl_to='$tt' AND cur_id=bl_from";
- $res2 = $dbw->query( $sql2 );
- while( $s = $dbw->fetchObject( $res2 ) ) {
- $from = Title::makeTitle( $s->cur_namespace, $s->cur_title );
- $xt = $from->getPrefixedText();
- echo "Found bad brokenlink to [[$t]] from page #$s->cur_id [[$xt]]!\n";
- $any = true;
- }
- $dbw->freeResult( $res2 );
- if($any) {
- echo "Removing brokenlinks to [[$t]]...\n";
- $sql3 = "DELETE FROM $brokenlinks WHERE bl_to='$tt'";
- $res3 = $dbw->query( $sql3 );
- #echo "-- $sql3\n";
- }
- } else {
- echo "Illegal title?! Namespace $s->cur_namespace, title '$s->cur_title'\n";
- }
-}
-echo "Done at $n.\n\n";
-
-echo "Clearing linkscc table...\n";
-$sql4 = "DELETE FROM $linkscc";
-wfQuery( $sql4, DB_MASTER );
-
-?>
diff --git a/maintenance/tables.sql b/maintenance/tables.sql
index 919b822cc67d..00416f374172 100644
--- a/maintenance/tables.sql
+++ b/maintenance/tables.sql
@@ -368,6 +368,27 @@ CREATE TABLE /*$wgDBprefix*/brokenlinks (
) TYPE=InnoDB;
+
+--
+-- Track page-to-page hyperlinks within the wiki.
+--
+CREATE TABLE /*$wgDBprefix*/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;
+
+
--
-- Track links to images *used inline*
-- We don't distinguish live from broken links here, so
diff --git a/maintenance/updaters.inc b/maintenance/updaters.inc
index ce2935e26e34..54abac4bf614 100644
--- a/maintenance/updaters.inc
+++ b/maintenance/updaters.inc
@@ -507,6 +507,46 @@ function do_namespace_size_on( $table, $prefix ) {
}
}
+function do_pagelinks_update() {
+ global $wgDatabase;
+ if( $wgDatabase->tableExists( 'pagelinks' ) ) {
+ echo "...already have pagelinks table.\n";
+ } else {
+ echo "Converting links and brokenlinks tables to pagelinks... ";
+ dbsource( "maintenance/archives/patch-pagelinks.sql", $wgDatabase );
+ echo "ok\n";
+ flush();
+
+ global $wgCanonicalNamespaceNames;
+ foreach( $wgCanonicalNamespaceNames as $ns => $name ) {
+ if( $ns != 0 ) {
+ do_pagelinks_namespace( $ns );
+ }
+ }
+ }
+}
+
+function do_pagelinks_namespace( $namespace ) {
+ global $wgDatabase, $wgContLang;
+
+ $ns = IntVal( $namespace );
+ echo "Cleaning up broken links for namespace $ns... ";
+
+ $pagelinks = $wgDatabase->tableName( 'pagelinks' );
+ $name = $wgContLang->getNsText( $ns );
+ $prefix = $wgDatabase->strencode( $name );
+ $likeprefix = str_replace( '_', '\\_', $prefix);
+
+ $sql = "UPDATE $pagelinks
+ SET pl_namespace=$ns,
+ pl_title=TRIM(LEADING '$prefix:' FROM pl_title)
+ WHERE pl_namespace=0
+ AND pl_title LIKE '$likeprefix:%'";
+
+ $wgDatabase->query( $sql, 'do_pagelinks_namespace' );
+ echo "ok\n";
+}
+
function do_all_updates() {
global $wgNewTables, $wgNewFields, $wgRenamedTables;
@@ -545,6 +585,8 @@ function do_all_updates() {
do_inverse_timestamp(); flush();
do_text_id(); flush();
do_namespace_size(); flush();
+
+ do_pagelinks_update(); flush();
initialiseMessages(); flush();
}