database abstraction
[lhc/web/wiklou.git] / includes / LinksUpdate.php
1 <?php
2 # See deferred.doc
3
4 class LinksUpdate {
5
6 /* private */ var $mId, $mTitle;
7
8 function LinksUpdate( $id, $title )
9 {
10 $this->mId = $id;
11 $this->mTitle = $title;
12 }
13
14
15 function doUpdate()
16 {
17 global $wgUseBetterLinksUpdate, $wgLinkCache, $wgDBtransactions;
18 global $wgEnablePersistentLC, $wgUseCategoryMagic;
19
20 /* Update link tables with outgoing links from an updated article */
21 /* Relies on the 'link cache' to be filled out */
22
23 $fname = "LinksUpdate::doUpdate";
24 wfProfileIn( $fname );
25
26 $del = array();
27 $add = array();
28
29 $dbw =& wfGetDB( DB_MASTER );
30 $links = $dbw->tableName( 'links' );
31 $brokenlinks = $dbw->tableName( 'brokenlinks' );
32 $imagelinks = $dbw->tableName( 'imagelinks' );
33 $categorylinks = $dbw->tableName( 'categorylinks' );
34
35 #------------------------------------------------------------------------------
36 # Good links
37
38 if ( $wgLinkCache->incrementalSetup( LINKCACHE_GOOD, $del, $add ) ) {
39 # Delete where necessary
40 if ( count( $del ) ) {
41 $sql = "DELETE FROM $links WHERE l_from={$this->mId} AND l_to IN(".
42 implode( ",", $del ) . ")";
43 $dbw->query( $sql, $fname );
44 }
45 } else {
46 # Delete everything
47 $dbw->delete( 'links', array( 'l_from' => $this->mId ), $fname );
48
49 # Get the addition list
50 $add = $wgLinkCache->getGoodLinks();
51 }
52
53 # Do the insertion
54 $sql = "";
55 if ( 0 != count( $add ) ) {
56 $arr=array();
57 foreach($add as $lt=>$lid)
58 array_push($arr,array(
59 'l_from'=>$this->mId,
60 'l_to'=>$lid));
61 # The link cache was constructed without FOR UPDATE, so there may be collisions
62 # Ignoring for now, I'm not sure if that causes problems or not, but I'm fairly
63 # sure it's better than without IGNORE
64 $dbw->insertArray($links,$arr,array('IGNORE'));
65 }
66
67 #------------------------------------------------------------------------------
68 # Bad links
69
70 if ( $wgLinkCache->incrementalSetup( LINKCACHE_BAD, $del, $add ) ) {
71 # Delete where necessary
72 if ( count( $del ) ) {
73 $sql = "DELETE FROM $brokenlinks WHERE bl_from={$this->mId} AND bl_to IN(";
74 $first = true;
75 foreach( $del as $badTitle ) {
76 if ( $first ) {
77 $first = false;
78 } else {
79 $sql .= ",";
80 }
81 $sql .= $dbw->addQuotes( $badTitle );
82 }
83 $sql .= ")";
84 $dbw->query( $sql, $fname );
85 }
86 } else {
87 # Delete all
88 $dbw->delete( 'brokenlinks', array( 'bl_from' => $this->mId ) );
89
90 # Get addition list
91 $add = $wgLinkCache->getBadLinks();
92 }
93
94 # Do additions
95 $sql = "";
96 if ( 0 != count ( $add ) ) {
97 $arr=array();
98 foreach( $add as $blt ) {
99 $blt = $dbw->strencode( $blt );
100 array_push($arr,array(
101 'bl_from'=>$this->mId,
102 'bl_to'=>$blt));
103 }
104 $dbw->insertArray($brokenlinks,$arr,array('IGNORE'));
105 $dbw->query( $sql, $fname );
106 }
107
108 #------------------------------------------------------------------------------
109 # Image links
110 $sql = "DELETE FROM $imagelinks WHERE il_from='{$this->mId}'";
111 $dbw->query( $sql, $fname );
112
113 # Get addition list
114 $add = $wgLinkCache->getImageLinks();
115
116 # Do the insertion
117 $sql = "";
118 $image = Namespace::getImage();
119 if ( 0 != count ( $add ) ) {
120 $sql = "INSERT IGNORE INTO $imagelinks (il_from,il_to) VALUES ";
121 $first = true;
122 foreach( $add as $iname => $val ) {
123 # FIXME: Change all this to avoid unnecessary duplication
124 $nt = Title::makeTitle( $image, $iname );
125 if( !$nt ) continue;
126 $nt->invalidateCache();
127
128 $iname = $dbw->strencode( $iname );
129 if ( ! $first ) { $sql .= ","; }
130 $first = false;
131
132 $sql .= "({$this->mId},'{$iname}')";
133 }
134 }
135 if ( "" != $sql ) {
136 $dbw->query( $sql, $fname );
137 }
138
139 #------------------------------------------------------------------------------
140 # Category links
141 if( $wgUseCategoryMagic ) {
142 $sql = "DELETE FROM $categorylinks WHERE cl_from='{$this->mId}'";
143 $dbw->query( $sql, $fname );
144
145 # Get addition list
146 $add = $wgLinkCache->getCategoryLinks();
147
148 # Do the insertion
149 $sql = "";
150 if ( 0 != count ( $add ) ) {
151 $sql = "INSERT IGNORE INTO $categorylinks (cl_from,cl_to,cl_sortkey) VALUES ";
152 $first = true;
153 foreach( $add as $cname => $sortkey ) {
154 # FIXME: Change all this to avoid unnecessary duplication
155 $nt = Title::makeTitle( NS_CATEGORY, $cname );
156 if( !$nt ) continue;
157 $nt->invalidateCache();
158
159 if ( ! $first ) { $sql .= ","; }
160 $first = false;
161
162 $sql .= "({$this->mId},'" . $dbw->strencode( $cname ) .
163 "','" . $dbw->strencode( $sortkey ) . "')";
164 }
165 }
166 if ( "" != $sql ) {
167 $dbw->query( $sql, $fname );
168 }
169 }
170
171 $this->fixBrokenLinks();
172
173 wfProfileOut( $fname );
174 }
175
176 function doDumbUpdate()
177 {
178 # Old inefficient update function
179 # Used for rebuilding the link table
180 global $wgLinkCache, $wgDBtransactions, $wgUseCategoryMagic;
181 $fname = "LinksUpdate::doDumbUpdate";
182 wfProfileIn( $fname );
183
184
185 $dbw =& wfGetDB( DB_MASTER );
186 $links = $dbw->tableName( 'links' );
187 $brokenlinks = $dbw->tableName( 'brokenlinks' );
188 $imagelinks = $dbw->tableName( 'imagelinks' );
189 $categorylinks = $dbw->tableName( 'categorylinks' );
190
191 $sql = "DELETE FROM $links WHERE l_from={$this->mId}";
192 $dbw->query( $sql, $fname );
193
194 $a = $wgLinkCache->getGoodLinks();
195 $sql = "";
196 if ( 0 != count( $a ) ) {
197 $sql = "INSERT IGNORE INTO $links (l_from,l_to) VALUES ";
198 $first = true;
199 foreach( $a as $lt => $lid ) {
200 if ( ! $first ) { $sql .= ","; }
201 $first = false;
202
203 $sql .= "({$this->mId},{$lid})";
204 }
205 }
206 if ( "" != $sql ) {
207 $dbw->query( $sql, $fname );
208 }
209
210 $sql = "DELETE FROM $brokenlinks WHERE bl_from={$this->mId}";
211 $dbw->query( $sql, $fname );
212
213 $a = $wgLinkCache->getBadLinks();
214 $sql = "";
215 if ( 0 != count ( $a ) ) {
216 $sql = "INSERT IGNORE INTO $brokenlinks (bl_from,bl_to) VALUES ";
217 $first = true;
218 foreach( $a as $blt ) {
219 $blt = $dbw->strencode( $blt );
220 if ( ! $first ) { $sql .= ","; }
221 $first = false;
222
223 $sql .= "({$this->mId},'{$blt}')";
224 }
225 }
226 if ( "" != $sql ) {
227 $dbw->query( $sql, $fname );
228 }
229
230 $sql = "DELETE FROM $imagelinks WHERE il_from={$this->mId}";
231 $dbw->query( $sql, $fname );
232
233 $a = $wgLinkCache->getImageLinks();
234 $sql = "";
235 if ( 0 != count ( $a ) ) {
236 $sql = "INSERT IGNORE INTO $imagelinks (il_from,il_to) VALUES ";
237 $first = true;
238 foreach( $a as $iname => $val ) {
239 $iname = $dbw->strencode( $iname );
240 if ( ! $first ) { $sql .= ","; }
241 $first = false;
242
243 $sql .= "({$this->mId},'{$iname}')";
244 }
245 }
246 if ( "" != $sql ) {
247 $dbw->query( $sql, $fname );
248 }
249
250 if( $wgUseCategoryMagic ) {
251 $sql = "DELETE FROM $categorylinks WHERE cl_from='{$this->mId}'";
252 $dbw->query( $sql, $fname );
253
254 # Get addition list
255 $add = $wgLinkCache->getCategoryLinks();
256
257 # Do the insertion
258 $sql = "";
259 if ( 0 != count ( $add ) ) {
260 $sql = "INSERT IGNORE INTO $categorylinks (cl_from,cl_to,cl_sortkey) VALUES ";
261 $first = true;
262 foreach( $add as $cname => $sortkey ) {
263 # FIXME: Change all this to avoid unnecessary duplication
264 $nt = Title::makeTitle( NS_CATEGORY, $cname );
265 if( !$nt ) continue;
266 $nt->invalidateCache();
267
268 if ( ! $first ) { $sql .= ","; }
269 $first = false;
270
271 $sql .= "({$this->mId},'" . $dbw->strencode( $cname ) .
272 "','" . $dbw->strencode( $sortkey ) . "')";
273 }
274 }
275 if ( "" != $sql ) {
276 $dbw->query( $sql, $fname );
277 }
278 }
279 $this->fixBrokenLinks();
280 wfProfileOut( $fname );
281 }
282
283 function fixBrokenLinks() {
284 /* Update any brokenlinks *to* this page */
285 /* Call for a newly created page, or just to make sure state is consistent */
286 $fname = "LinksUpdate::fixBrokenLinks";
287
288 $dbw =& wfGetDB( DB_MASTER );
289 $cur = $dbw->tableName( 'cur' );
290 $links = $dbw->tableName( 'links' );
291
292 $res = $dbw->select( 'brokenlinks', array( 'bl_from' ), array( 'bl_to' => $this->mTitle ),
293 $fname, 'FOR UPDATE' );
294 if ( 0 == $dbw->numRows( $res ) ) { return; }
295
296 # Ignore errors. If a link existed in both the brokenlinks table and the links
297 # table, that's an error which can be fixed at this stage by simply ignoring collisions
298 $sql = "INSERT IGNORE INTO $links (l_from,l_to) VALUES ";
299 $now = wfTimestampNow();
300 $sql2 = "UPDATE $cur SET cur_touched='{$now}' WHERE cur_id IN (";
301 $first = true;
302 while ( $row = $dbw->fetchObject( $res ) ) {
303 if ( ! $first ) { $sql .= ","; $sql2 .= ","; }
304 $first = false;
305
306 $sql .= "({$row->bl_from},{$this->mId})";
307 $sql2 .= $row->bl_from;
308 }
309 $sql2 .= ")";
310 $dbw->query( $sql, $fname );
311 $dbw->query( $sql2, $fname );
312
313 $dbw->delete( 'brokenlinks', array( 'bl_to' => $this->mTitle ), $fname );
314 }
315 }
316
317 ?>