From 59c6e92429c1c42c6e06d60e85766901810b338e Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Thu, 11 Mar 2004 09:06:13 +0000 Subject: [PATCH] Some changes to the link tables. They now all use a key on cur_id for the *_from column instead of strings, and have a unique index to force prevent any duplicate entries. There's not yet a clean step in the update script, so just clear out your links tables (patch-linktables.sql) and rebuild them with refreshLinks.php. This saves trouble in a number of places where we can now do joins with the link tables to get other info (such as cur_is_redirect!) as well as the name, and fewer bits need to be juggled on page renaming, as outgoing links no longer have to be changed (cur_id remains the same when a page is renamed). rebuildLinks.inc and some of the tools in the 'maintenance page' still need to be updated to work with the new setup. (Special:Maintenance needs a *lot* of cleanup in general. It's kind of a catch-all of vaguely defined features which suck performance like a hydroelectric dam.) Also I've slipped in some extra debug code. And, I think 'indexes.sql' is a big waste of time and should all be moved into tables.sql. Building indexes separately doesn't help on InnoDB and won't do anything on MyISAM either if you're just going to replace the table after it's built with an imported one from a dump which creates it with indexes. --- includes/Article.php | 17 ++--- includes/Database.php | 17 ++++- includes/ImagePage.php | 8 +-- includes/LinkCache.php | 36 +++++----- includes/LinksUpdate.php | 21 +++--- includes/Parser.php | 12 ++-- includes/ParserCache.php | 2 +- includes/SpecialDeadendpages.php | 2 +- includes/SpecialMaintenance.php | 5 +- includes/SpecialMovepage.php | 29 +++----- includes/SpecialRecentchangeslinked.php | 11 ++- includes/SpecialWhatlinkshere.php | 42 ++++-------- includes/SquidUpdate.php | 30 ++++---- maintenance/archives/patch-linktables.sql | 48 +++++++++++++ maintenance/archives/patch-list.txt | 5 ++ maintenance/indexes.sql | 16 ++--- maintenance/rebuildlinks.inc | 2 + maintenance/tables.sql | 83 ++++++++++++++--------- 18 files changed, 222 insertions(+), 164 deletions(-) create mode 100644 maintenance/archives/patch-linktables.sql diff --git a/includes/Article.php b/includes/Article.php index 7e83b96822..9d49d75b20 100644 --- a/includes/Article.php +++ b/includes/Article.php @@ -843,11 +843,11 @@ class Article { wfPurgeSquidServers($urlArr); /* prepare the list of urls to purge */ - $sql = "SELECT l_from FROM links WHERE l_to={$id}" ; + $sql = "SELECT cur_namespace,cur_title FROM links,cur WHERE l_to={$id} and l_from=cur_id" ; $res = wfQuery ( $sql, DB_READ ) ; while ( $BL = wfFetchObject ( $res ) ) { - $tobj = Title::newFromDBkey( $BL->l_from) ; + $tobj = Title::MakeTitle( $BL->cur_namespace, $BL->cur_title ) ; $blurlArr[] = $tobj->getInternalURL(); } wfFreeResult ( $res ) ; @@ -899,18 +899,15 @@ class Article { $res = wfQuery( $sql, DB_READ, $fname ); $sql = "INSERT INTO brokenlinks (bl_from,bl_to) VALUES "; - $now = wfTimestampNow(); + $now = wfTimestampNow(); $sql2 = "UPDATE cur SET cur_touched='{$now}' WHERE cur_id IN ("; $first = true; while ( $s = wfFetchObject( $res ) ) { - $nt = Title::newFromDBkey( $s->l_from ); - $lid = $nt->getArticleID(); - if ( ! $first ) { $sql .= ","; $sql2 .= ","; } $first = false; - $sql .= "({$lid},'{$t}')"; - $sql2 .= "{$lid}"; + $sql .= "({$s->l_from},'{$t}')"; + $sql2 .= "{$s->l_from}"; } $sql2 .= ")"; if ( ! $first ) { @@ -922,10 +919,10 @@ class Article { $sql = "DELETE FROM links WHERE l_to={$id}"; wfQuery( $sql, DB_WRITE, $fname ); - $sql = "DELETE FROM links WHERE l_from='{$t}'"; + $sql = "DELETE FROM links WHERE l_from={$id}"; wfQuery( $sql, DB_WRITE, $fname ); - $sql = "DELETE FROM imagelinks WHERE il_from='{$t}'"; + $sql = "DELETE FROM imagelinks WHERE il_from={$d}"; wfQuery( $sql, DB_WRITE, $fname ); $sql = "DELETE FROM brokenlinks WHERE bl_from={$id}"; diff --git a/includes/Database.php b/includes/Database.php index 8acd3d7511..99422a3fd4 100644 --- a/includes/Database.php +++ b/includes/Database.php @@ -186,8 +186,21 @@ class Database { } function freeResult( $res ) { mysql_free_result( $res ); } - function fetchObject( $res ) { return mysql_fetch_object( $res ); } - function numRows( $res ) { return mysql_num_rows( $res ); } + function fetchObject( $res ) { + @$row = mysql_fetch_object( $res ); + # FIXME: HACK HACK HACK HACK debug + if( mysql_errno() ) { + wfDebugDieBacktrace( "SQL error: " . htmlspecialchars( mysql_error() ) ); + } + return $row; + } + function numRows( $res ) { + @$n = mysql_num_rows( $res ); + if( mysql_errno() ) { + wfDebugDieBacktrace( "SQL error: " . htmlspecialchars( mysql_error() ) ); + } + return $n; + } function numFields( $res ) { return mysql_num_fields( $res ); } function fieldName( $res, $n ) { return mysql_field_name( $res, $n ); } function insertId() { return mysql_insert_id( $this->mConn ); } diff --git a/includes/ImagePage.php b/includes/ImagePage.php index 4eef270023..b3630fcc6a 100644 --- a/includes/ImagePage.php +++ b/includes/ImagePage.php @@ -95,8 +95,8 @@ class ImagePage extends Article { $wgOut->addHTML( "

" . wfMsg( "imagelinks" ) . "

\n" ); - $sql = "SELECT il_from FROM imagelinks WHERE il_to='" . - wfStrencode( $this->mTitle->getDBkey() ) . "'"; + $sql = "SELECT cur_namespace,cur_title FROM imagelinks,cur WHERE il_to='" . + wfStrencode( $this->mTitle->getDBkey() ) . "' AND il_from=cur_id"; $res = wfQuery( $sql, DB_READ, "Article::imageLinks" ); if ( 0 == wfNumRows( $res ) ) { @@ -107,8 +107,8 @@ class ImagePage extends Article { $sk = $wgUser->getSkin(); while ( $s = wfFetchObject( $res ) ) { - $name = $s->il_from; - $link = $sk->makeKnownLink( $name, "" ); + $name = Title::MakeTitle( $s->cur_namespace, $s->cur_title ); + $link = $sk->makeKnownLinkObj( $name, "" ); $wgOut->addHTML( "
  • {$link}
  • \n" ); } $wgOut->addHTML( "\n" ); diff --git a/includes/LinkCache.php b/includes/LinkCache.php index f4c50c0a43..93721af41d 100644 --- a/includes/LinkCache.php +++ b/includes/LinkCache.php @@ -148,17 +148,26 @@ class LinkCache { $fname = "LinkCache::preFill"; wfProfileIn( $fname ); # Note -- $fromtitle is a Title *object* - $dbkeyfrom = wfStrencode( $fromtitle->getPrefixedDBKey() ); + $this->suspend(); + $id = $fromtitle->getArticleID(); + $this->resume(); + + if( $id == 0 ) { + wfDebug( "$fname - got id 0 for title '" . $fromtitle->getPrefixedDBkey() . "'\n" ); + wfProfileOut( $fname ); + return; + } + if ( $wgEnablePersistentLC ) { - if( $this->fillFromLinkscc( $dbkeyfrom ) ){ + if( $this->fillFromLinkscc( $id ) ){ return; } } $sql = "SELECT cur_id,cur_namespace,cur_title FROM cur,links - WHERE cur_id=l_to AND l_from='{$dbkeyfrom}'"; + WHERE cur_id=l_to AND l_from=$id"; $res = wfQuery( $sql, DB_READ, $fname ); while( $s = wfFetchObject( $res ) ) { $this->addGoodLink( $s->cur_id, @@ -166,16 +175,6 @@ class LinkCache { ); } - $this->suspend(); - $id = $fromtitle->getArticleID(); - $this->resume(); - - if( $id == 0 ) { - wfDebug( "$fname - got id 0 for title '" . $fromtitle->getPrefixedDBkey() . "'\n" ); - wfProfileOut( $fname ); - return; - } - $sql = "SELECT bl_to FROM brokenlinks WHERE bl_from='{$id}'"; @@ -264,8 +263,9 @@ class LinkCache { $this->mImageLinks = array(); } - /* private */ function fillFromLinkscc( $dbkeyfrom ){ - $res = wfQuery("SELECT lcc_cacheobj FROM linkscc WHERE lcc_title = '{$dbkeyfrom}'", + /* private */ function fillFromLinkscc( $id ){ + $id = IntVal( $id ); + $res = wfQuery("SELECT lcc_cacheobj FROM linkscc WHERE lcc_pageid = $id", DB_READ); $row = wfFetchObject( $res ); if( $row == FALSE) @@ -297,15 +297,15 @@ class LinkCache { } else { $ser = wfStrencode( serialize( $this ) ); } - wfQuery("REPLACE INTO linkscc(lcc_pageid,lcc_title,lcc_cacheobj) " . - "VALUES({$pid}, '{$dbkeyfrom}', '{$ser}')", DB_WRITE); + wfQuery("REPLACE INTO linkscc(lcc_pageid,lcc_cacheobj) " . + "VALUES({$pid}, '{$ser}')", DB_WRITE); } # $pid is a page id /* static */ function linksccClearLinksTo( $pid ){ $pid = intval( $pid ); wfQuery("DELETE linkscc FROM linkscc,links ". - "WHERE lcc_title=links.l_from AND l_to={$pid}", DB_WRITE); + "WHERE lcc_pageid=links.l_from AND l_to={$pid}", DB_WRITE); wfQuery("DELETE FROM linkscc WHERE lcc_pageid='{$pid}'", DB_WRITE); } diff --git a/includes/LinksUpdate.php b/includes/LinksUpdate.php index aebadd706a..fe39d36563 100644 --- a/includes/LinksUpdate.php +++ b/includes/LinksUpdate.php @@ -38,13 +38,13 @@ class LinksUpdate { if ( $wgLinkCache->incrementalSetup( LINKCACHE_GOOD, $del, $add ) ) { # Delete where necessary if ( count( $del ) ) { - $sql = "DELETE FROM links WHERE l_from='{$this->mTitleEnc}' AND l_to IN(". + $sql = "DELETE FROM links WHERE l_from={$this->mId} AND l_to IN(". implode( ",", $del ) . ")"; wfQuery( $sql, DB_WRITE, $fname ); } } else { # Delete everything - $sql = "DELETE FROM links WHERE l_from='{$this->mTitleEnc}'"; + $sql = "DELETE FROM links WHERE l_from={$this->mId}"; wfQuery( $sql, DB_WRITE, $fname ); # Get the addition list @@ -61,7 +61,7 @@ class LinksUpdate { if ( ! $first ) { $sql .= ","; } $first = false; - $sql .= "('{$this->mTitleEnc}',{$lid})"; + $sql .= "({$this->mId},{$lid})"; } } if ( "" != $sql ) { @@ -106,7 +106,7 @@ class LinksUpdate { #------------------------------------------------------------------------------ # Image links - $sql = "DELETE FROM imagelinks WHERE il_from='{$this->mTitleEnc}'"; + $sql = "DELETE FROM imagelinks WHERE il_from='{$this->mId}'"; wfQuery( $sql, DB_WRITE, $fname ); # Get addition list @@ -128,7 +128,7 @@ class LinksUpdate { if ( ! $first ) { $sql .= ","; } $first = false; - $sql .= "('{$this->mTitleEnc}','{$iname}')"; + $sql .= "({$this->mId},'{$iname}')"; } } if ( "" != $sql ) { wfQuery( $sql, DB_WRITE, $fname ); } @@ -156,7 +156,7 @@ class LinksUpdate { wfQuery( $sql, DB_WRITE, $fname ); } - $sql = "DELETE FROM links WHERE l_from='{$this->mTitleEnc}'"; + $sql = "DELETE FROM links WHERE l_from={$this->mId}"; wfQuery( $sql, DB_WRITE, $fname ); $a = $wgLinkCache->getGoodLinks(); @@ -168,7 +168,7 @@ class LinksUpdate { if ( ! $first ) { $sql .= ","; } $first = false; - $sql .= "('{$this->mTitleEnc}',{$lid})"; + $sql .= "({$this->mId},{$lid})"; } } if ( "" != $sql ) { wfQuery( $sql, DB_WRITE, $fname ); } @@ -191,7 +191,7 @@ class LinksUpdate { } if ( "" != $sql ) { wfQuery( $sql, DB_WRITE, $fname ); } - $sql = "DELETE FROM imagelinks WHERE il_from='{$this->mTitleEnc}'"; + $sql = "DELETE FROM imagelinks WHERE il_from={$this->mId}"; wfQuery( $sql, DB_WRITE, $fname ); $a = $wgLinkCache->getImageLinks(); @@ -204,7 +204,7 @@ class LinksUpdate { if ( ! $first ) { $sql .= ","; } $first = false; - $sql .= "('{$this->mTitleEnc}','{$iname}')"; + $sql .= "({$this->mId},'{$iname}')"; } } if ( "" != $sql ) { wfQuery( $sql, DB_WRITE, $fname ); } @@ -234,9 +234,8 @@ class LinksUpdate { while ( $row = wfFetchObject( $res ) ) { if ( ! $first ) { $sql .= ","; $sql2 .= ","; } $first = false; - $nl = wfStrencode( Title::nameOf( $row->bl_from ) ); - $sql .= "('{$nl}',{$this->mId})"; + $sql .= "({$row->bl_from},{$this->mId})"; $sql2 .= $row->bl_from; } $sql2 .= ")"; diff --git a/includes/Parser.php b/includes/Parser.php index 435b406117..360c1267c0 100644 --- a/includes/Parser.php +++ b/includes/Parser.php @@ -200,7 +200,7 @@ class Parser $doesexist = false ; if ( $doesexist ) { - $sql = "SELECT l_from FROM links WHERE l_to={$id}" ; + $sql = "SELECT cur_title,cur_namespace FROM cur,links WHERE l_to={$id} AND l_from=cur_id"; } else { $sql = "SELECT cur_title,cur_namespace FROM cur,brokenlinks WHERE bl_to={$id} AND bl_from=cur_id" ; } @@ -211,13 +211,9 @@ class Parser # $t = new Title ; # $t->newFromDBkey ( $x->l_from ) ; # $t = $t->getText() ; - if ( $doesexist ) { - $t = $x->l_from ; - } else { - $t = $wgLang->getNsText ( $x->cur_namespace ) ; - if ( $t != "" ) $t .= ":" ; - $t .= $x->cur_title ; - } + $t = $wgLang->getNsText ( $x->cur_namespace ) ; + if ( $t != "" ) $t .= ":" ; + $t .= $x->cur_title ; $y = explode ( ":" , $t , 2 ) ; if ( count ( $y ) == 2 && $y[0] == $cat ) { diff --git a/includes/ParserCache.php b/includes/ParserCache.php index c7d934be99..70b994365c 100644 --- a/includes/ParserCache.php +++ b/includes/ParserCache.php @@ -44,7 +44,7 @@ class ParserCache function clearLinksTo( $pid ){ $pid = intval( $pid ); wfQuery("DELETE parsercache FROM parsercache,links ". - "WHERE pc_title=links.l_from AND l_to={$pid}", DB_WRITE); + "WHERE pc_pageid=links.l_from AND l_to={$pid}", DB_WRITE); wfQuery("DELETE FROM parsercache WHERE pc_pageid='{$pid}'", DB_WRITE); } diff --git a/includes/SpecialDeadendpages.php b/includes/SpecialDeadendpages.php index 08d16c96d3..34105db619 100644 --- a/includes/SpecialDeadendpages.php +++ b/includes/SpecialDeadendpages.php @@ -16,7 +16,7 @@ class DeadendPagesPage extends PageQueryPage { function getSQL( $offset, $limit ) { return "SELECT cur_title " . - "FROM cur LEFT JOIN links ON cur_title = l_from " . + "FROM cur LEFT JOIN links ON cur_id = l_from " . "WHERE l_from IS NULL " . "AND cur_namespace = 0 " . "ORDER BY cur_title " . diff --git a/includes/SpecialMaintenance.php b/includes/SpecialMaintenance.php index dc8a9fecc9..7b8fc49323 100644 --- a/includes/SpecialMaintenance.php +++ b/includes/SpecialMaintenance.php @@ -95,7 +95,9 @@ function wfSpecialDisambiguations() list( $limit, $offset ) = wfCheckLimits(); $dp = wfStrencode( wfMsg("disambiguationspage") ); - + + die( "wfSpecialDisambiguation is broken. Link tables have changed...\n" ); + $sql = "SELECT la.l_from,la.l_to," . " lb.l_from AS source,lb.l_to AS dest," . " c.cur_id, c.cur_title AS dt" @@ -142,6 +144,7 @@ function wfSpecialDoubleRedirects() list( $limit, $offset ) = wfCheckLimits(); + die( "wfSpecialDoubleRedirects() is broken for now; link tables are changed." ); $sql = "SELECT l_from,l_to,cb.cur_text AS rt,cb.cur_title AS ti FROM links,cur AS ca, cur AS cb WHERE ca.cur_is_redirect=1 AND cb.cur_is_redirect=1 AND l_to=cb.cur_id AND l_from=ca.cur_title AND ca.cur_namespace=0 LIMIT {$offset}, {$limit}" ; $res = wfQuery( $sql, DB_READ, $fname ); diff --git a/includes/SpecialMovepage.php b/includes/SpecialMovepage.php index 6ac9d340a8..ad66cb188e 100644 --- a/includes/SpecialMovepage.php +++ b/includes/SpecialMovepage.php @@ -340,32 +340,29 @@ class MovePageForm { RecentChange::notifyMove( $now, $this->ot, $this->nt, $wgUser, $mt ); - # The only link from here should be the old redirect - - $sql = "DELETE FROM links WHERE l_from='{$this->nft}'"; - wfQuery( $sql, DB_WRITE, $fname ); - - $sql = "UPDATE links SET l_from='{$this->nft}' WHERE l_from='{$this->oft}'"; - wfQuery( $sql, DB_WRITE, $fname ); - # Swap links. Using MAXINT as a temp; if there's ever an article # with id 4294967295, this will fail, but I think that's pretty safe + # FIXME: LOCK TABLE + # Reassign links to the old title to LIMBO $sql = "UPDATE links SET l_to=4294967295 WHERE l_to={$this->oldid}"; wfQuery( $sql, DB_WRITE, $fname ); + # Reassign links to the new title to the old title $sql = "UPDATE links SET l_to={$this->oldid} WHERE l_to={$this->newid}"; wfQuery( $sql, DB_WRITE, $fname ); + # Reassign links from LIMBO to the new title. Ah, clear as mud! $sql = "UPDATE links SET l_to={$this->newid} WHERE l_to=4294967295"; wfQuery( $sql, DB_WRITE, $fname ); # Note: the insert below must be after the updates above! - $sql = "INSERT INTO links (l_from,l_to) VALUES ('{$this->oft}',{$this->oldid})"; + # Now, we record the link from the redirect to the new title. + # It should have no other outgoing links... + $sql = "DELETE FROM links WHERE l_from={$this->newid}"; wfQuery( $sql, DB_WRITE, $fname ); - - $sql = "UPDATE imagelinks SET il_from='{$this->nft}' WHERE il_from='{$this->oft}'"; + $sql = "INSERT INTO links (l_from,l_to) VALUES ({$this->newid},{$this->oldid})"; wfQuery( $sql, DB_WRITE, $fname ); } @@ -406,22 +403,18 @@ class MovePageForm { RecentChange::notifyMove( $now, $this->ot, $this->nt, $wgUser, $comment ); Article::onArticleCreate( $this->nt ); - $sql = "UPDATE links SET l_from='{$this->nft}' WHERE l_from='{$this->oft}'"; - wfQuery( $sql, DB_WRITE, $fname ); - + # Any text links to the old title must be reassigned to the redirect $sql = "UPDATE links SET l_to={$this->newid} WHERE l_to={$this->oldid}"; wfQuery( $sql, DB_WRITE, $fname ); - $sql = "INSERT INTO links (l_from,l_to) VALUES ('{$this->oft}',{$this->oldid})"; + # Record the just-created redirect's linking to the page + $sql = "INSERT INTO links (l_from,l_to) VALUES ({$this->newid},{$this->oldid})"; wfQuery( $sql, DB_WRITE, $fname ); # Non-existent target may have had broken links to it; these must # now be removed and made into good links. $update = new LinksUpdate( $this->oldid, $this->nft ); $update->fixBrokenLinks(); - - $sql = "UPDATE imagelinks SET il_from='{$this->nft}' WHERE il_from='{$this->oft}'"; - wfQuery( $sql, DB_WRITE, $fname ); } function updateWatchlists() diff --git a/includes/SpecialRecentchangeslinked.php b/includes/SpecialRecentchangeslinked.php index ddb66acf1a..1a505885f1 100644 --- a/includes/SpecialRecentchangeslinked.php +++ b/includes/SpecialRecentchangeslinked.php @@ -18,6 +18,12 @@ function wfSpecialRecentchangeslinked( $par = NULL ) return; } $nt = Title::newFromURL( $target ); + if( !$nt ) { + $wgOut->errorpage( "notargettitle", "notargettext" ); + return; + } + $id = $nt->getArticleId(); + $wgOut->setSubtitle( wfMsg( "rclsub", $nt->getPrefixedText() ) ); if ( ! $days ) { @@ -44,9 +50,8 @@ function wfSpecialRecentchangeslinked( $par = NULL ) $sql = "SELECT cur_id,cur_namespace,cur_title,cur_user,cur_comment," . "cur_user_text,cur_timestamp,cur_minor_edit,cur_is_new FROM links, cur " . - "WHERE cur_timestamp > '{$cutoff}' {$cmq} AND l_to=cur_id AND l_from='" . - wfStrencode( $nt->getPrefixedDBkey() ) . "' GROUP BY cur_id " . - "ORDER BY inverse_timestamp LIMIT {$limit}"; + "WHERE cur_timestamp > '{$cutoff}' {$cmq} AND l_to=cur_id AND l_from=$id " . + "GROUP BY cur_id ORDER BY inverse_timestamp LIMIT {$limit}"; $res = wfQuery( $sql, DB_READ, $fname ); $note = wfMsg( "rcnote", $limit, $days ); diff --git a/includes/SpecialWhatlinkshere.php b/includes/SpecialWhatlinkshere.php index 1876d939a5..af4e8a0710 100644 --- a/includes/SpecialWhatlinkshere.php +++ b/includes/SpecialWhatlinkshere.php @@ -27,8 +27,8 @@ function wfSpecialWhatlinkshere($par = NULL) $isredir = " (" . wfMsg( "isredirect" ) . ")\n"; if ( 0 == $id ) { - $sql = "SELECT bl_from FROM brokenlinks WHERE bl_to='" . - wfStrencode( $nt->getPrefixedDBkey() ) . "' LIMIT 500"; + $sql = "SELECT cur_id,cur_namespace,cur_title,cur_is_redirect FROM brokenlinks,cur WHERE bl_to='" . + wfStrencode( $nt->getPrefixedDBkey() ) . "' AND bl_from=cur_id LIMIT 500"; $res = wfQuery( $sql, DB_READ, $fname ); if ( 0 == wfNumRows( $res ) ) { @@ -38,19 +38,16 @@ function wfSpecialWhatlinkshere($par = NULL) $wgOut->addHTML( "\n