Index: trunk/extensions/SemanticMediaWiki/includes/storage/SMW_SQLStore2.php |
— | — | @@ -5,7 +5,7 @@ |
6 | 6 | * |
7 | 7 | * @author Markus Krötzsch |
8 | 8 | * @author Jeroen De Dauw |
9 | | - * |
| 9 | + * |
10 | 10 | * @file |
11 | 11 | * @ingroup SMWStore |
12 | 12 | */ |
— | — | @@ -145,10 +145,10 @@ |
146 | 146 | |
147 | 147 | public function getSemanticData( $subject, $filter = false ) { |
148 | 148 | wfProfileIn( "SMWSQLStore2::getSemanticData (SMW)" ); |
149 | | - |
| 149 | + |
150 | 150 | // Do not clear the cache when called recursively. |
151 | | - self::$in_getSemanticData++; |
152 | | - |
| 151 | + self::$in_getSemanticData++; |
| 152 | + |
153 | 153 | // *** Find out if this subject exists ***// |
154 | 154 | if ( $subject instanceof Title ) { ///TODO: can this still occur? |
155 | 155 | $sid = $this->getSMWPageID( $subject->getDBkey(), $subject->getNamespace(), $subject->getInterwiki() ); |
— | — | @@ -161,20 +161,20 @@ |
162 | 162 | } else { |
163 | 163 | $sid = 0; |
164 | 164 | } |
165 | | - |
| 165 | + |
166 | 166 | if ( $sid == 0 ) { // no data, safe our time |
167 | 167 | /// NOTE: we consider redirects for getting $sid, so $sid == 0 also means "no redirects" |
168 | 168 | self::$in_getSemanticData--; |
169 | 169 | wfProfileOut( "SMWSQLStore2::getSemanticData (SMW)" ); |
170 | 170 | return isset( $svalue ) ? ( new SMWSemanticData( $svalue ) ):null; |
171 | 171 | } |
172 | | - |
| 172 | + |
173 | 173 | // *** Prepare the cache ***// |
174 | 174 | if ( !array_key_exists( $sid, $this->m_semdata ) ) { // new cache entry |
175 | 175 | $this->m_semdata[$sid] = new SMWSemanticData( $svalue, false ); |
176 | 176 | $this->m_sdstate[$sid] = array(); |
177 | 177 | } |
178 | | - |
| 178 | + |
179 | 179 | if ( ( count( $this->m_semdata ) > 20 ) && ( self::$in_getSemanticData == 1 ) ) { |
180 | 180 | // prevent memory leak; |
181 | 181 | // It is not so easy to find the sweet spot between cache size and performance gains (both memory and time), |
— | — | @@ -182,49 +182,49 @@ |
183 | 183 | $this->m_semdata = array( $sid => $this->m_semdata[$sid] ); |
184 | 184 | $this->m_sdstate = array( $sid => $this->m_sdstate[$sid] ); |
185 | 185 | } |
186 | | - |
| 186 | + |
187 | 187 | // *** Read the data ***// |
188 | 188 | foreach ( self::getPropertyTables() as $tid => $proptable ) { |
189 | 189 | if ( array_key_exists( $tid, $this->m_sdstate[$sid] ) ) continue; |
190 | | - |
| 190 | + |
191 | 191 | if ( $filter !== false ) { |
192 | 192 | $relevant = false; |
193 | | - |
| 193 | + |
194 | 194 | foreach ( $filter as $typeid ) { |
195 | 195 | $relevant = $relevant || self::tableFitsType( $tid, $typeid ); |
196 | 196 | } |
197 | | - |
| 197 | + |
198 | 198 | if ( !$relevant ) continue; |
199 | 199 | } |
200 | | - |
| 200 | + |
201 | 201 | $data = $this->fetchSemanticData( $sid, $svalue, $proptable ); |
202 | | - |
| 202 | + |
203 | 203 | foreach ( $data as $d ) { |
204 | 204 | $this->m_semdata[$sid]->addPropertyStubValue( reset( $d ), end( $d ) ); |
205 | 205 | } |
206 | | - |
| 206 | + |
207 | 207 | $this->m_sdstate[$sid][$tid] = true; |
208 | 208 | } |
209 | 209 | |
210 | 210 | self::$in_getSemanticData--; |
211 | | - |
| 211 | + |
212 | 212 | wfProfileOut( "SMWSQLStore2::getSemanticData (SMW)" ); |
213 | | - |
| 213 | + |
214 | 214 | return $this->m_semdata[$sid]; |
215 | 215 | } |
216 | 216 | |
217 | 217 | /** |
218 | | - * |
| 218 | + * |
219 | 219 | * @param $subject |
220 | 220 | * @param SMWPropertyValue $property |
221 | 221 | * @param SMWRequestOptions $requestoptions |
222 | 222 | * @param string $outputformat |
223 | | - * |
| 223 | + * |
224 | 224 | * @return array |
225 | 225 | */ |
226 | 226 | public function getPropertyValues( $subject, SMWPropertyValue $property, $requestoptions = null, $outputformat = '' ) { |
227 | 227 | wfProfileIn( "SMWSQLStore2::getPropertyValues (SMW)" ); |
228 | | - |
| 228 | + |
229 | 229 | if ( $property->isInverse() ) { // inverses are working differently |
230 | 230 | $noninverse = clone $property; |
231 | 231 | $noninverse->setInverse( false ); |
— | — | @@ -232,31 +232,31 @@ |
233 | 233 | } elseif ( $subject !== null ) { // subject given, use semantic data cache: |
234 | 234 | $sd = $this->getSemanticData( $subject, array( $property->getPropertyTypeID() ) ); |
235 | 235 | $result = $this->applyRequestOptions( $sd->getPropertyValues( $property ), $requestoptions ); |
236 | | - |
| 236 | + |
237 | 237 | if ( $outputformat != '' ) { // reformat cached values |
238 | 238 | $newres = array(); |
239 | | - |
| 239 | + |
240 | 240 | foreach ( $result as $dv ) { |
241 | 241 | $ndv = clone $dv; |
242 | 242 | $ndv->setOutputFormat( $outputformat ); |
243 | 243 | $newres[] = $ndv; |
244 | 244 | } |
245 | | - |
| 245 | + |
246 | 246 | $result = $newres; |
247 | 247 | } |
248 | 248 | } else { // no subject given, get all values for the given property |
249 | 249 | $pid = $this->getSMWPropertyID( $property ); |
250 | 250 | $tableid = self::findPropertyTableID( $property ); |
251 | | - |
| 251 | + |
252 | 252 | if ( ( $pid == 0 ) || ( $tableid == '' ) ) { |
253 | 253 | wfProfileOut( "SMWSQLStore2::getPropertyValues (SMW)" ); |
254 | 254 | return array(); |
255 | 255 | } |
256 | | - |
| 256 | + |
257 | 257 | $proptables = self::getPropertyTables(); |
258 | 258 | $data = $this->fetchSemanticData( $pid, $property, $proptables[$tableid], false, $requestoptions ); |
259 | 259 | $result = array(); |
260 | | - |
| 260 | + |
261 | 261 | foreach ( $data as $dbkeys ) { |
262 | 262 | $dv = SMWDataValueFactory::newPropertyObjectValue( $property ); |
263 | 263 | if ( $outputformat != '' ) $dv->setOutputFormat( $outputformat ); |
— | — | @@ -264,9 +264,9 @@ |
265 | 265 | $result[] = $dv; |
266 | 266 | } |
267 | 267 | } |
268 | | - |
| 268 | + |
269 | 269 | wfProfileOut( "SMWSQLStore2::getPropertyValues (SMW)" ); |
270 | | - |
| 270 | + |
271 | 271 | return $result; |
272 | 272 | } |
273 | 273 | |
— | — | @@ -295,20 +295,20 @@ |
296 | 296 | * |
297 | 297 | * @todo Maybe share DB handler; asking for it seems to take quite some time and we do not want |
298 | 298 | * to change it in one call. |
299 | | - * |
| 299 | + * |
300 | 300 | * @param $id |
301 | 301 | * @param $object |
302 | 302 | * @param $proptable |
303 | 303 | * @param boolean $issubject |
304 | 304 | * @param SMWRequestOptions $requestoptions |
305 | | - * |
| 305 | + * |
306 | 306 | * @return array |
307 | 307 | */ |
308 | 308 | protected function fetchSemanticData( $id, $object, $proptable, $issubject = true, $requestoptions = null ) { |
309 | 309 | // stop if there is not enough data: |
310 | 310 | // properties always need to be given as object, subjects at least if !$proptable->idsubject |
311 | 311 | if ( ( $id == 0 ) || ( ( $object === null ) && ( !$issubject || !$proptable->idsubject ) ) ) return array(); |
312 | | - |
| 312 | + |
313 | 313 | wfProfileIn( "SMWSQLStore2::fetchSemanticData-" . $proptable->name . " (SMW)" ); |
314 | 314 | $result = array(); |
315 | 315 | $db = wfGetDB( DB_SLAVE ); |
— | — | @@ -317,7 +317,7 @@ |
318 | 318 | $from = $db->tableName( $proptable->name ); // always use actual table |
319 | 319 | $select = ''; |
320 | 320 | $where = ''; |
321 | | - |
| 321 | + |
322 | 322 | if ( $issubject != 0 ) { // restrict subject, select property |
323 | 323 | $where .= ( $proptable->idsubject ) ? 's_id=' . $db->addQuotes( $id ) : |
324 | 324 | 's_title=' . $db->addQuotes( $object->getDBkey() ) . |
— | — | @@ -331,36 +331,36 @@ |
332 | 332 | } elseif ( !$proptable->fixedproperty ) { // restrict property, but don't select subject |
333 | 333 | $where .= 'p_id=' . $db->addQuotes( $id ); |
334 | 334 | } |
335 | | - |
| 335 | + |
336 | 336 | $valuecount = 0; |
337 | 337 | $pagevalues = array(); // collect indices of page-type components of this table (typically at most 1) |
338 | 338 | $usedistinct = true; // use DISTINCT option only if no text blobs are among values |
339 | 339 | $selectvalues = array(); // array for all values to be selected, kept to help finding value and label fields below |
340 | | - |
| 340 | + |
341 | 341 | foreach ( $proptable->objectfields as $fieldname => $typeid ) { // now add select entries for object column(s) |
342 | 342 | if ( $typeid == 'p' ) { // Special case: page id, use smw_id table to insert 4 page-specific values instead of internal id |
343 | 343 | $from .= ' INNER JOIN ' . $db->tableName( 'smw_ids' ) . " AS o$valuecount ON $fieldname=o$valuecount.smw_id"; |
344 | 344 | $select .= ( ( $select != '' ) ? ',' : '' ) . "$fieldname AS id$valuecount"; |
345 | | - |
| 345 | + |
346 | 346 | $selectvalues[$valuecount] = "o$valuecount.smw_title"; |
347 | 347 | $selectvalues[$valuecount + 1] = "o$valuecount.smw_namespace"; |
348 | 348 | $selectvalues[$valuecount + 2] = "o$valuecount.smw_iw"; |
349 | 349 | $selectvalues[$valuecount + 3] = "o$valuecount.smw_sortkey"; |
350 | | - |
| 350 | + |
351 | 351 | $pagevalues[] = $valuecount; |
352 | 352 | $valuecount += 3; |
353 | 353 | } else { // Just use value as given. |
354 | 354 | $selectvalues[$valuecount] = $fieldname; |
355 | 355 | } |
356 | | - |
| 356 | + |
357 | 357 | if ( $typeid == 'l' ) $usedistinct = false; |
358 | 358 | $valuecount++; |
359 | 359 | } |
360 | | - |
| 360 | + |
361 | 361 | foreach ( $selectvalues as $index => $field ) { |
362 | 362 | $select .= ( ( $select != '' ) ? ',' : '' ) . "$field AS v$index"; |
363 | 363 | } |
364 | | - |
| 364 | + |
365 | 365 | if ( !$issubject ) { // Needed to apply sorting/string matching in query; only with fixed property. |
366 | 366 | list( $sig, $valueIndex, $labelIndex ) = self::getTypeSignature( $object->getPropertyTypeID() ); |
367 | 367 | $valuecolumn = ( array_key_exists( $valueIndex, $selectvalues ) ) ? $selectvalues[$valueIndex] : ''; |
— | — | @@ -374,14 +374,14 @@ |
375 | 375 | $res = $db->select( $from, $select, $where, 'SMW::getSemanticData', |
376 | 376 | ( $usedistinct ? $this->getSQLOptions( $requestoptions, $valuecolumn ) + array( 'DISTINCT' ) : |
377 | 377 | $this->getSQLOptions( $requestoptions, $valuecolumn ) ) ); |
378 | | - |
| 378 | + |
379 | 379 | while ( $row = $db->fetchObject( $res ) ) { |
380 | 380 | if ( !$issubject ) { |
381 | 381 | $propertyname = 'fixed'; // irrelevant, but use this to check if the data is good |
382 | 382 | } elseif ( !$proptable->fixedproperty ) { // use joined or predefined property name |
383 | 383 | if ( $proptable->specpropsonly ) { |
384 | 384 | $propertyname = array_search( $row->p_id, self::$special_ids ); |
385 | | - |
| 385 | + |
386 | 386 | if ( $propertyname === false ) { // unknown property that uses a special type, maybe by some extension; look it up in the DB |
387 | 387 | // NOTE: this is just an emergency fallback but not a fast solution; extensions may prefer to use non-special datatypes for new properties! |
388 | 388 | $propertyname = $db->selectField( 'smw_ids', 'smw_title', array( 'smw_id' => $row->p_id ), 'SMW::getSemanticData-LatePropertyFetch' ); |
— | — | @@ -392,68 +392,68 @@ |
393 | 393 | } else { // use fixed property name |
394 | 394 | $propertyname = $proptable->fixedproperty; |
395 | 395 | } |
396 | | - |
| 396 | + |
397 | 397 | $valuekeys = array(); |
398 | 398 | reset( $pagevalues ); |
399 | | - |
| 399 | + |
400 | 400 | for ( $i = 0; $i < $valuecount; $i++ ) { // read the value fields from the current row |
401 | 401 | $fieldname = "v$i"; |
402 | 402 | $newvalue = $row->$fieldname; |
403 | | - |
| 403 | + |
404 | 404 | if ( $i === current( $pagevalues ) ) { // special check for pages to filter out internal objects |
405 | 405 | $iwfield = 'v' . ( $i + 2 ); |
406 | 406 | $iw = $row->$iwfield; |
407 | | - |
| 407 | + |
408 | 408 | if ( ( $iw == SMW_SQL2_SMWIW ) && ( $valuecount == 4 ) && ( $object !== null ) ) { |
409 | 409 | // read container objects recursively; but only if proptable is of form "p" |
410 | 410 | // also avoid (hypothetical) double recursion by requiring $object!==null |
411 | 411 | $i += 3; // skip other page fields of this bnode |
412 | 412 | $oidfield = 'id' . current( $pagevalues ); |
413 | | - |
| 413 | + |
414 | 414 | $newvalue = array(); |
415 | | - |
| 415 | + |
416 | 416 | foreach ( self::getPropertyTables() as $tid => $pt ) { // just read all |
417 | 417 | $newvalue = array_merge( $newvalue, $this->fetchSemanticData( $row->$oidfield, null, $pt ) ); |
418 | 418 | } |
419 | 419 | } elseif ( ( $iw != '' ) && ( $iw { 0 } == ' : ' ) ) { // other internal object, maybe a DB inconsistency; ignore row |
420 | 420 | $propertyname = ''; |
421 | 421 | } |
422 | | - |
| 422 | + |
423 | 423 | next( $pagevalues ); |
424 | 424 | } |
425 | | - |
| 425 | + |
426 | 426 | $valuekeys[] = $newvalue; |
427 | 427 | } |
428 | | - |
| 428 | + |
429 | 429 | if ( $propertyname != '' ) $result[] = $issubject ? array( $propertyname, $valuekeys ):$valuekeys; |
430 | 430 | } |
431 | | - |
| 431 | + |
432 | 432 | $db->freeResult( $res ); |
433 | 433 | wfProfileOut( "SMWSQLStore2::fetchSemanticData-" . $proptable->name . " (SMW)" ); |
434 | | - |
| 434 | + |
435 | 435 | return $result; |
436 | 436 | } |
437 | | - |
| 437 | + |
438 | 438 | /** |
439 | 439 | * returns an array of SMWWikiPageValue. |
440 | | - * |
| 440 | + * |
441 | 441 | * @param SMWPropertyValue $property |
442 | 442 | * @param $value |
443 | 443 | * @param SMWRequestOptions $requestoptions |
444 | | - * |
| 444 | + * |
445 | 445 | * @return array |
446 | 446 | */ |
447 | 447 | public function getPropertySubjects( SMWPropertyValue $property, $value, $requestoptions = null ) { |
448 | 448 | /// TODO: should we share code with #ask query computation here? Just use queries? |
449 | 449 | wfProfileIn( "SMWSQLStore2::getPropertySubjects (SMW)" ); |
450 | | - |
| 450 | + |
451 | 451 | if ( $property->isInverse() ) { // inverses are working differently |
452 | 452 | $noninverse = clone $property; |
453 | 453 | $noninverse->setInverse( false ); |
454 | | - |
| 454 | + |
455 | 455 | $result = $this->getPropertyValues( $value, $noninverse, $requestoptions ); |
456 | 456 | wfProfileOut( "SMWSQLStore2::getPropertySubjects (SMW)" ); |
457 | | - |
| 457 | + |
458 | 458 | return $result; |
459 | 459 | } |
460 | 460 | |
— | — | @@ -461,19 +461,19 @@ |
462 | 462 | $select = $where = $from = ''; |
463 | 463 | $pid = $this->getSMWPropertyID( $property ); |
464 | 464 | $tableid = self::findPropertyTableID( $property ); |
465 | | - |
| 465 | + |
466 | 466 | if ( ( $tableid == '' ) && ( $value !== null ) ) { // maybe a type-polymorphic property like _1; use value to find type |
467 | 467 | $tableid = self::findTypeTableID( $value->getTypeID() ); |
468 | 468 | } |
469 | | - |
| 469 | + |
470 | 470 | if ( ( $pid == 0 ) || ( $tableid == '' ) || ( ( $value !== null ) && ( !$value->isValid() ) ) ) { |
471 | 471 | return array(); |
472 | 472 | } |
473 | | - |
| 473 | + |
474 | 474 | $proptables = self::getPropertyTables(); |
475 | 475 | $proptable = $proptables[$tableid]; |
476 | 476 | $db = wfGetDB( DB_SLAVE ); |
477 | | - |
| 477 | + |
478 | 478 | if ( $proptable->idsubject ) { // join in smw_ids to get title data |
479 | 479 | $from = $db->tableName( 'smw_ids' ) . " INNER JOIN " . $db->tableName( $proptable->name ) . " AS t1 ON t1.s_id=smw_id"; |
480 | 480 | $select = 'smw_title AS title, smw_namespace AS namespace, smw_sortkey'; |
— | — | @@ -481,11 +481,11 @@ |
482 | 482 | $from = $db->tableName( $proptable->name ) . " AS t1"; |
483 | 483 | $select = 's_title AS title, s_namespace AS namespace, s_title AS smw_sortkey'; |
484 | 484 | } |
485 | | - |
| 485 | + |
486 | 486 | if ( $proptable->fixedproperty == false ) { |
487 | 487 | $where .= ( $where ? ' AND ' : '' ) . "t1.p_id=" . $db->addQuotes( $pid ); |
488 | 488 | } |
489 | | - |
| 489 | + |
490 | 490 | $this->prepareValueQuery( $from, $where, $proptable, $value, 1 ); |
491 | 491 | |
492 | 492 | // *** Now execute the query and read the results ***// |
— | — | @@ -494,14 +494,14 @@ |
495 | 495 | $where . $this->getSQLConditions( $requestoptions, 'smw_sortkey', 'smw_sortkey', $where != '' ), |
496 | 496 | 'SMW::getPropertySubjects', |
497 | 497 | $this->getSQLOptions( $requestoptions, 'smw_sortkey' ) ); |
498 | | - |
| 498 | + |
499 | 499 | while ( $row = $db->fetchObject( $res ) ) { |
500 | 500 | $result[] = SMWWikiPageValue::makePage( $row->title, $row->namespace, $row->smw_sortkey ); |
501 | 501 | } |
502 | | - |
| 502 | + |
503 | 503 | $db->freeResult( $res ); |
504 | 504 | wfProfileOut( "SMWSQLStore2::getPropertySubjects (SMW)" ); |
505 | | - |
| 505 | + |
506 | 506 | return $result; |
507 | 507 | } |
508 | 508 | |
— | — | @@ -514,8 +514,8 @@ |
515 | 515 | * queried. |
516 | 516 | * |
517 | 517 | * @todo Maybe do something about redirects. The old code was |
518 | | - * $oid = $this->getSMWPageID($value->getDBkey(),$value->getNamespace(),$value->getInterwiki(),false); |
519 | | - * |
| 518 | + * $oid = $this->getSMWPageID($value->getDBkey(),$value->getNamespace(),$value->getInterwiki(),false); |
| 519 | + * |
520 | 520 | * @param $from |
521 | 521 | * @param $where |
522 | 522 | * @param $proptable |
— | — | @@ -524,23 +524,23 @@ |
525 | 525 | */ |
526 | 526 | protected function prepareValueQuery( &$from, &$where, $proptable, $value, $tableindex = 1 ) { |
527 | 527 | $db = wfGetDB( DB_SLAVE ); |
528 | | - |
| 528 | + |
529 | 529 | if ( $value instanceof SMWContainerValue ) { // recursive handling of containers |
530 | 530 | $joinfield = "t$tableindex." . reset( array_keys( $proptable->objectfields ) ); // this must be a type 'p' object |
531 | 531 | $proptables = self::getPropertyTables(); |
532 | | - |
| 532 | + |
533 | 533 | foreach ( $value->getData()->getProperties() as $subproperty ) { |
534 | 534 | $tableid = self::findPropertyTableID( $subproperty ); |
535 | | - |
| 535 | + |
536 | 536 | if ( ( $tableid == '' ) && ( $value !== null ) ) { // maybe a type-polymorphic property like _1; use value to find type |
537 | 537 | $tableid = self::findTypeTableID( reset( $value->getData()->getPropertyValues( $subproperty ) )->getTypeID() ); |
538 | 538 | } |
539 | | - |
| 539 | + |
540 | 540 | $subproptable = $proptables[$tableid]; |
541 | | - |
| 541 | + |
542 | 542 | foreach ( $value->getData()->getPropertyValues( $subproperty ) as $subvalue ) { |
543 | 543 | $tableindex++; |
544 | | - |
| 544 | + |
545 | 545 | if ( $subproptable->idsubject ) { // simply add property table to check values |
546 | 546 | $from .= " INNER JOIN " . $db->tableName( $subproptable->name ) . " AS t$tableindex ON t$tableindex.s_id=$joinfield"; |
547 | 547 | } else { // exotic case with table that uses subject title+namespace in container object (should never happen in SMW core) |
— | — | @@ -548,21 +548,21 @@ |
549 | 549 | " INNER JOIN " . $db->tableName( $subproptable->name ) . " AS t$tableindex ON " . |
550 | 550 | "t$tableindex.s_title=ids$tableindex.smw_title AND t$tableindex.s_namespace=ids$tableindex.smw_namespace"; |
551 | 551 | } |
552 | | - |
| 552 | + |
553 | 553 | if ( $subproptable->fixedproperty == false ) { // the ID we get should be !=0, so no point in filtering the converse |
554 | 554 | $where .= ( $where ? ' AND ' : '' ) . "t$tableindex.p_id=" . $db->addQuotes( $this->getSMWPropertyID( $subproperty ) ); |
555 | 555 | } |
556 | | - |
| 556 | + |
557 | 557 | $this->prepareValueQuery( $from, $where, $subproptable, $subvalue, $tableindex ); |
558 | 558 | } |
559 | 559 | } |
560 | 560 | } elseif ( $value !== null ) { // add conditions for given value |
561 | 561 | $dbkeys = $value->getDBkeys(); |
562 | 562 | $i = 0; |
563 | | - |
| 563 | + |
564 | 564 | foreach ( $proptable->objectfields as $fieldname => $typeid ) { |
565 | 565 | if ( $i >= count( $dbkeys ) ) break; |
566 | | - |
| 566 | + |
567 | 567 | if ( $typeid == 'p' ) { // Special case: page id, resolve this in advance |
568 | 568 | $oid = $this->getSMWPageID( $dbkeys[$i], $dbkeys[$i + 1], $dbkeys[$i + 2] ); |
569 | 569 | $i += 3; // skip these additional values (sortkey not needed here) |
— | — | @@ -570,15 +570,15 @@ |
571 | 571 | } elseif ( $typeid != 'l' ) { // plain value, but not a text blob |
572 | 572 | $where .= ( $where ? ' AND ' : '' ) . "t$tableindex.$fieldname=" . $db->addQuotes( $dbkeys[$i] ); |
573 | 573 | } |
574 | | - |
| 574 | + |
575 | 575 | $i++; |
576 | 576 | } |
577 | 577 | } |
578 | 578 | } |
579 | 579 | |
580 | 580 | /** |
581 | | - * |
582 | | - * |
| 581 | + * |
| 582 | + * |
583 | 583 | * @param SMWPropertyValue $property |
584 | 584 | * @param SMWRequestOptions $requestoptions |
585 | 585 | */ |
— | — | @@ -586,20 +586,20 @@ |
587 | 587 | wfProfileIn( "SMWSQLStore2::getAllPropertySubjects (SMW)" ); |
588 | 588 | $result = $this->getPropertySubjects( $property, null, $requestoptions ); |
589 | 589 | wfProfileOut( "SMWSQLStore2::getAllPropertySubjects (SMW)" ); |
590 | | - |
| 590 | + |
591 | 591 | return $result; |
592 | 592 | } |
593 | 593 | |
594 | 594 | /** |
595 | 595 | * @todo Restrict this function to SMWWikiPageValue subjects. |
596 | | - * |
| 596 | + * |
597 | 597 | * @param $subject |
598 | 598 | * @param SMWRequestOptions $requestoptions |
599 | 599 | */ |
600 | 600 | public function getProperties( $subject, $requestoptions = null ) { |
601 | 601 | wfProfileIn( "SMWSQLStore2::getProperties (SMW)" ); |
602 | 602 | $sid = $this->getSMWPageID( $subject->getDBkey(), $subject->getNamespace(), $subject->getInterwiki() ); |
603 | | - |
| 603 | + |
604 | 604 | if ( $sid == 0 ) { // no id, no page, no properties |
605 | 605 | wfProfileOut( "SMWSQLStore2::getProperties (SMW)" ); |
606 | 606 | return array(); |
— | — | @@ -607,7 +607,7 @@ |
608 | 608 | |
609 | 609 | $db = wfGetDB( DB_SLAVE ); |
610 | 610 | $result = array(); |
611 | | - |
| 611 | + |
612 | 612 | if ( $requestoptions !== null ) { // potentially need to get more results, since options apply to union |
613 | 613 | $suboptions = clone $requestoptions; |
614 | 614 | $suboptions->limit = $requestoptions->limit + $requestoptions->offset; |
— | — | @@ -615,10 +615,10 @@ |
616 | 616 | } else { |
617 | 617 | $suboptions = null; |
618 | 618 | } |
619 | | - |
| 619 | + |
620 | 620 | foreach ( self::getPropertyTables() as $tid => $proptable ) { |
621 | 621 | $from = $db->tableName( $proptable->name ); |
622 | | - |
| 622 | + |
623 | 623 | if ( $proptable->idsubject ) { |
624 | 624 | $where = 's_id=' . $db->addQuotes( $sid ); |
625 | 625 | } elseif ( $subject->getInterwiki() == '' ) { |
— | — | @@ -626,30 +626,30 @@ |
627 | 627 | } else { // subjects with non-emtpy interwiki cannot have properties |
628 | 628 | continue; |
629 | 629 | } |
630 | | - |
| 630 | + |
631 | 631 | if ( $proptable->fixedproperty == false ) { // select all properties |
632 | 632 | $from .= " INNER JOIN " . $db->tableName( 'smw_ids' ) . " ON smw_id=p_id"; |
633 | 633 | $res = $db->select( $from, 'DISTINCT smw_title,smw_sortkey', // select sortkey since it might be used in ordering (needed by Postgres) |
634 | 634 | $where . $this->getSQLConditions( $suboptions, 'smw_sortkey', 'smw_sortkey' ), |
635 | 635 | 'SMW::getProperties', $this->getSQLOptions( $suboptions, 'smw_sortkey' ) ); |
636 | | - |
| 636 | + |
637 | 637 | while ( $row = $db->fetchObject( $res ) ) { |
638 | 638 | $result[] = SMWPropertyValue::makeProperty( $row->smw_title ); |
639 | 639 | } |
640 | 640 | } else { // just check if subject occurs in table |
641 | 641 | $res = $db->select( $from, '*', $where, 'SMW::getProperties', array( 'LIMIT' => 1 ) ); |
642 | | - |
| 642 | + |
643 | 643 | if ( $db->numRows( $res ) > 0 ) { |
644 | 644 | $result[] = SMWPropertyValue::makeProperty( $proptable->fixedproperty ); |
645 | 645 | } |
646 | 646 | } |
647 | | - |
| 647 | + |
648 | 648 | $db->freeResult( $res ); |
649 | 649 | } |
650 | | - |
| 650 | + |
651 | 651 | $result = $this->applyRequestOptions( $result, $requestoptions ); // apply options to overall result |
652 | 652 | wfProfileOut( "SMWSQLStore2::getProperties (SMW)" ); |
653 | | - |
| 653 | + |
654 | 654 | return $result; |
655 | 655 | } |
656 | 656 | |
— | — | @@ -662,38 +662,38 @@ |
663 | 663 | * property to the type of the queried data. So values with the same DB keys |
664 | 664 | * can be confused. This is a minor issue now since no code is known to use |
665 | 665 | * this function in cases where this occurs. |
666 | | - * |
| 666 | + * |
667 | 667 | * @param SMWDataValue $value |
668 | 668 | * @param SMWRequestOptions $requestoptions |
669 | 669 | */ |
670 | 670 | public function getInProperties( SMWDataValue $value, $requestoptions = null ) { |
671 | 671 | wfProfileIn( "SMWSQLStore2::getInProperties (SMW)" ); |
672 | | - |
| 672 | + |
673 | 673 | $db = wfGetDB( DB_SLAVE ); |
674 | 674 | $result = array(); |
675 | 675 | $typeid = $value->getTypeID(); |
676 | 676 | |
677 | 677 | // Potentially need to get more results, since options apply to union. |
678 | | - if ( $requestoptions !== null ) { |
| 678 | + if ( $requestoptions !== null ) { |
679 | 679 | $suboptions = clone $requestoptions; |
680 | 680 | $suboptions->limit = $requestoptions->limit + $requestoptions->offset; |
681 | 681 | $suboptions->offset = 0; |
682 | 682 | } else { |
683 | 683 | $suboptions = null; |
684 | 684 | } |
685 | | - |
| 685 | + |
686 | 686 | foreach ( self::getPropertyTables() as $tid => $proptable ) { |
687 | 687 | if ( !$this->tableFitsType( $tid, $typeid ) ) continue; |
688 | 688 | $select = $where = $from = ''; |
689 | | - |
| 689 | + |
690 | 690 | if ( $proptable->fixedproperty == false ) { // join smw_ids to get property titles |
691 | 691 | $from = $db->tableName( 'smw_ids' ) . " INNER JOIN " . $db->tableName( $proptable->name ) . " AS t1 ON t1.p_id=smw_id"; |
692 | 692 | $this->prepareValueQuery( $from, $where, $proptable, $value, 1 ); |
693 | | - |
| 693 | + |
694 | 694 | $res = $db->select( $from, 'DISTINCT smw_title,smw_sortkey', // select sortkey since it might be used in ordering (needed by Postgres) |
695 | 695 | $where . $this->getSQLConditions( $suboptions, 'smw_sortkey', 'smw_sortkey', $where != '' ), |
696 | 696 | 'SMW::getInProperties', $this->getSQLOptions( $suboptions, 'smw_sortkey' ) ); |
697 | | - |
| 697 | + |
698 | 698 | while ( $row = $db->fetchObject( $res ) ) { |
699 | 699 | $result[] = SMWPropertyValue::makeProperty( $row->smw_title ); |
700 | 700 | } |
— | — | @@ -701,17 +701,17 @@ |
702 | 702 | $from = $db->tableName( $proptable->name ) . " AS t1"; |
703 | 703 | $this->prepareValueQuery( $from, $where, $proptable, $value, 1 ); |
704 | 704 | $res = $db->select( $from, '*', $where, 'SMW::getProperties', array( 'LIMIT' => 1 ) ); |
705 | | - |
| 705 | + |
706 | 706 | if ( $db->numRows( $res ) > 0 ) { |
707 | 707 | $result[] = SMWPropertyValue::makeProperty( $proptable->fixedproperty ); |
708 | 708 | } |
709 | 709 | } |
710 | 710 | $db->freeResult( $res ); |
711 | 711 | } |
712 | | - |
| 712 | + |
713 | 713 | $result = $this->applyRequestOptions( $result, $requestoptions ); // apply options to overall result |
714 | 714 | wfProfileOut( "SMWSQLStore2::getInProperties (SMW)" ); |
715 | | - |
| 715 | + |
716 | 716 | return $result; |
717 | 717 | } |
718 | 718 | |
— | — | @@ -720,17 +720,17 @@ |
721 | 721 | public function deleteSubject( Title $subject ) { |
722 | 722 | wfProfileIn( 'SMWSQLStore2::deleteSubject (SMW)' ); |
723 | 723 | wfRunHooks( 'SMWSQLStore2::deleteSubjectBefore', array( $this, $subject ) ); |
724 | | - |
| 724 | + |
725 | 725 | $this->deleteSemanticData( SMWWikiPageValue::makePageFromTitle( $subject ) ); |
726 | 726 | $this->updateRedirects( $subject->getDBkey(), $subject->getNamespace() ); // also delete redirects, may trigger update jobs! |
727 | | - |
| 727 | + |
728 | 728 | if ( $subject->getNamespace() == SMW_NS_CONCEPT ) { // make sure to clear caches |
729 | 729 | $db = wfGetDB( DB_MASTER ); |
730 | 730 | $id = $this->getSMWPageID( $subject->getDBkey(), $subject->getNamespace(), $subject->getInterwiki(), false ); |
731 | 731 | $db->delete( 'smw_conc2', array( 's_id' => $id ), 'SMW::deleteSubject::Conc2' ); |
732 | 732 | $db->delete( 'smw_conccache', array( 'o_id' => $id ), 'SMW::deleteSubject::Conccache' ); |
733 | 733 | } |
734 | | - |
| 734 | + |
735 | 735 | ///FIXME: if a property page is deleted, more pages may need to be updated by jobs! |
736 | 736 | ///TODO: who is responsible for these updates? Some update jobs are currently created in SMW_Hooks, some internally in the store |
737 | 737 | ///TODO: Possibly delete ID here (at least for non-properties/categories, if not used in any place in rels2) |
— | — | @@ -742,11 +742,11 @@ |
743 | 743 | public function updateData( SMWSemanticData $data ) { |
744 | 744 | wfProfileIn( "SMWSQLStore2::updateData (SMW)" ); |
745 | 745 | wfRunHooks( 'SMWSQLStore2::updateDataBefore', array( $this, $data ) ); |
746 | | - |
| 746 | + |
747 | 747 | $subject = $data->getSubject(); |
748 | 748 | $this->deleteSemanticData( $subject ); |
749 | 749 | $redirects = $data->getPropertyValues( SMWPropertyValue::makeProperty( '_REDI' ) ); |
750 | | - |
| 750 | + |
751 | 751 | if ( count( $redirects ) > 0 ) { |
752 | 752 | $redirect = end( $redirects ); // at most one redirect per page |
753 | 753 | $this->updateRedirects( $subject->getDBkey(), $subject->getNamespace(), $redirect->getDBkey(), $redirect->getNameSpace() ); |
— | — | @@ -755,7 +755,7 @@ |
756 | 756 | } else { |
757 | 757 | $this->updateRedirects( $subject->getDBkey(), $subject->getNamespace() ); |
758 | 758 | } |
759 | | - |
| 759 | + |
760 | 760 | // always make an ID (pages without ID cannot be in query results, not even in fixed value queries!): |
761 | 761 | $sid = $this->makeSMWPageID( $subject->getDBkey(), $subject->getNamespace(), '', true, $subject->getSortkey() ); |
762 | 762 | $updates = array(); // collect data for bulk updates; format: tableid => updatearray |
— | — | @@ -771,7 +771,7 @@ |
772 | 772 | if ( $subject->getNamespace() == SMW_NS_CONCEPT ) { |
773 | 773 | $property = SMWPropertyValue::makeProperty( '_CONC' ); |
774 | 774 | $concept_desc = end( $data->getPropertyValues( $property ) ); |
775 | | - |
| 775 | + |
776 | 776 | if ( ( $concept_desc !== null ) && ( $concept_desc->isValid() ) ) { |
777 | 777 | $up_conc2 = array( |
778 | 778 | 'concept_txt' => $concept_desc->getConceptText(), |
— | — | @@ -789,14 +789,14 @@ |
790 | 790 | 'concept_depth' => - 1 |
791 | 791 | ); |
792 | 792 | } |
793 | | - |
| 793 | + |
794 | 794 | $row = $db->selectRow( |
795 | 795 | 'smw_conc2', |
796 | 796 | array( 'cache_date', 'cache_count' ), |
797 | 797 | array( 's_id' => $sid ), |
798 | 798 | 'SMWSQLStore2Queries::updateConst2Data' |
799 | 799 | ); |
800 | | - |
| 800 | + |
801 | 801 | if ( ( $row === false ) && ( $up_conc2['concept_txt'] != '' ) ) { // insert newly given data |
802 | 802 | $up_conc2['s_id'] = $sid; |
803 | 803 | $db->insert( 'smw_conc2', $up_conc2, 'SMW::updateConc2Data' ); |
— | — | @@ -821,7 +821,7 @@ |
822 | 822 | * |
823 | 823 | * The function returns the id that was used for writing. Especially, any newly created |
824 | 824 | * internal id is returned. |
825 | | - * |
| 825 | + * |
826 | 826 | * @param $updates |
827 | 827 | * @param SMWSemanticData $data |
828 | 828 | * @param $pageid |
— | — | @@ -830,21 +830,21 @@ |
831 | 831 | $subject = $data->getSubject(); |
832 | 832 | $sid = ( $subject !== null ) ? $pageid:$this->makeSMWBnodeID( $pageid ); |
833 | 833 | $proptables = self::getPropertyTables(); |
834 | | - |
| 834 | + |
835 | 835 | foreach ( $data->getProperties() as $property ) { |
836 | 836 | $tableid = self::findPropertyTableID( $property ); |
837 | | - |
| 837 | + |
838 | 838 | if ( !$tableid ) { // happens when table is not determined by property; use values to find type |
839 | 839 | $dv = reset( $data->getPropertyValues( $property ) ); |
840 | 840 | $tableid = self::findTypeTableID( $dv->getTypeID() ); |
841 | 841 | } |
842 | | - |
| 842 | + |
843 | 843 | if ( !$tableid ) { // can't store this data, sorry |
844 | 844 | return $sid; |
845 | 845 | } |
846 | | - |
| 846 | + |
847 | 847 | $proptable = $proptables[$tableid]; |
848 | | - |
| 848 | + |
849 | 849 | foreach ( $data->getPropertyValues( $property ) as $dv ) { |
850 | 850 | if ( !$dv->isValid() || ( $tableid == 'smw_redi2' ) ) continue; |
851 | 851 | // errors are already recorded separately, no need to store them here; |
— | — | @@ -855,7 +855,7 @@ |
856 | 856 | if ( $proptable->fixedproperty == false ) { |
857 | 857 | $uvals['p_id'] = $this->makeSMWPropertyID( $property ); |
858 | 858 | } |
859 | | - |
| 859 | + |
860 | 860 | if ( $dv instanceof SMWContainerValue ) { // process subobjects recursively |
861 | 861 | $bnode = $this->prepareDBUpdates( $updates, $dv->getData(), $pageid ); |
862 | 862 | // Note: tables for container objects MUST have objectfields == array(<somename> => 'p') |
— | — | @@ -864,7 +864,7 @@ |
865 | 865 | } else { |
866 | 866 | $dbkeys = $dv->getDBkeys(); |
867 | 867 | reset( $dbkeys ); |
868 | | - |
| 868 | + |
869 | 869 | foreach ( $proptable->objectfields as $fieldname => $typeid ) { |
870 | 870 | if ( $typeid != 'p' ) { |
871 | 871 | $uvals[$fieldname] = current( $dbkeys ); |
— | — | @@ -875,15 +875,15 @@ |
876 | 876 | $sortkey = next( $dbkeys ); // not used; sortkeys are not set on writing objects |
877 | 877 | $uvals[$fieldname] = $this->makeSMWPageID( $title, $namespace, $iw ); |
878 | 878 | } |
879 | | - |
| 879 | + |
880 | 880 | next( $dbkeys ); |
881 | 881 | } |
882 | 882 | } |
883 | | - |
| 883 | + |
884 | 884 | if ( !array_key_exists( $proptable->name, $updates ) ) { |
885 | 885 | $updates[$proptable->name] = array(); |
886 | 886 | } |
887 | | - |
| 887 | + |
888 | 888 | $updates[$proptable->name][] = $uvals; |
889 | 889 | } |
890 | 890 | } |
— | — | @@ -912,7 +912,7 @@ |
913 | 913 | * not possible to move it reliably in all cases: we cannot distinguish an |
914 | 914 | * unset sortkey from one that was set to the name of oldtitle. Maybe use |
915 | 915 | * update jobs right away? |
916 | | - * |
| 916 | + * |
917 | 917 | * @param Title $oldtitle |
918 | 918 | * @param Title $newtitle |
919 | 919 | * @param $pageid |
— | — | @@ -921,7 +921,7 @@ |
922 | 922 | public function changeTitle( Title $oldtitle, Title $newtitle, $pageid, $redirid = 0 ) { |
923 | 923 | global $smwgQEqualitySupport; |
924 | 924 | wfProfileIn( "SMWSQLStore2::changeTitle (SMW)" ); |
925 | | - |
| 925 | + |
926 | 926 | // get IDs but do not resolve redirects: |
927 | 927 | $sid = $this->getSMWPageID( $oldtitle->getDBkey(), $oldtitle->getNamespace(), '', false ); |
928 | 928 | $tid = $this->getSMWPageID( $newtitle->getDBkey(), $newtitle->getNamespace(), '', false ); |
— | — | @@ -936,7 +936,7 @@ |
937 | 937 | } else { // make new (target) id for use in redirect table |
938 | 938 | $sid = $this->makeSMWPageID( $newtitle->getDBkey(), $newtitle->getNamespace(), '' ); |
939 | 939 | } // at this point, $sid is the id of the target page (according to smw_ids) |
940 | | - |
| 940 | + |
941 | 941 | $this->makeSMWPageID( $oldtitle->getDBkey(), $oldtitle->getNamespace(), SMW_SQL2_SMWREDIIW ); // make redirect id for oldtitle |
942 | 942 | $db->insert( 'smw_redi2', array( 's_title' => $oldtitle->getDBkey(), 's_namespace' => $oldtitle->getNamespace(), 'o_id' => $sid ), |
943 | 943 | 'SMWSQLStore2::changeTitle' ); |
— | — | @@ -954,12 +954,12 @@ |
955 | 955 | // Delete any existing data from new title: |
956 | 956 | $this->deleteSemanticData( SMWWikiPageValue::makePageFromTitle( $newtitle ) ); // $newtitle should not have data, but let's be sure |
957 | 957 | $this->updateRedirects( $newtitle->getDBkey(), $newtitle->getNamespace() ); // may trigger update jobs! |
958 | | - |
| 958 | + |
959 | 959 | // Move all data of old title to new position: |
960 | 960 | if ( $sid != 0 ) { |
961 | 961 | $this->changeSMWPageID( $sid, $tid, $oldtitle->getNamespace(), $newtitle->getNamespace(), true, false ); |
962 | 962 | } |
963 | | - |
| 963 | + |
964 | 964 | // Now write a redirect from old title to new one; this also updates references in other tables as needed. |
965 | 965 | /// TODO: may not be optimal for the standard case that newtitle existed and redirected to oldtitle (PERFORMANCE) |
966 | 966 | $this->updateRedirects( $oldtitle->getDBkey(), $oldtitle->getNamespace(), $newtitle->getDBkey(), $newtitle->getNamespace() ); |
— | — | @@ -973,11 +973,11 @@ |
974 | 974 | wfProfileIn( 'SMWSQLStore2::getQueryResult (SMW)' ); |
975 | 975 | global $smwgIP; |
976 | 976 | include_once( "$smwgIP/includes/storage/SMW_SQLStore2_Queries.php" ); |
977 | | - |
| 977 | + |
978 | 978 | $qe = new SMWSQLStore2QueryEngine( $this, wfGetDB( DB_SLAVE ) ); |
979 | 979 | $result = $qe->getQueryResult( $query ); |
980 | 980 | wfProfileOut( 'SMWSQLStore2::getQueryResult (SMW)' ); |
981 | | - |
| 981 | + |
982 | 982 | return $result; |
983 | 983 | } |
984 | 984 | |
— | — | @@ -992,7 +992,7 @@ |
993 | 993 | $db = wfGetDB( DB_SLAVE ); |
994 | 994 | // the query needs to do the filtering of internal properties, else LIMIT is wrong |
995 | 995 | $queries = array(); |
996 | | - |
| 996 | + |
997 | 997 | foreach ( self::getPropertyTables() as $proptable ) { |
998 | 998 | if ( $proptable->fixedproperty == false ) { |
999 | 999 | $queries[] = 'SELECT smw_id, smw_title, COUNT(*) as count, smw_sortkey FROM ' . |
— | — | @@ -1000,24 +1000,24 @@ |
1001 | 1001 | $db->addQuotes( '' ) . ' OR smw_iw=' . $db->addQuotes( SMW_SQL2_SMWPREDEFIW ) . ' GROUP BY smw_id,smw_title,smw_sortkey'; |
1002 | 1002 | } // else: properties with special tables are ignored for now; maybe fix in the future |
1003 | 1003 | } |
1004 | | - |
| 1004 | + |
1005 | 1005 | $query = '(' . implode( ') UNION (', $queries ) . ') ORDER BY smw_sortkey'; |
1006 | 1006 | // The following line is possible in MW 1.6 and above only: |
1007 | 1007 | // $query = $db->unionQueries($queries, false) . ' ORDER BY smw_sortkey'; // should probably use $db->makeSelectOptions() |
1008 | 1008 | if ( $requestoptions->limit > 0 ) { |
1009 | 1009 | $query = $db->limitResult( $query, $requestoptions->limit, ( $requestoptions->offset > 0 ) ? $requestoptions->offset:0 ); |
1010 | 1010 | } |
1011 | | - |
| 1011 | + |
1012 | 1012 | $res = $db->query( $query, 'SMW::getPropertySubjects' ); |
1013 | 1013 | $result = array(); |
1014 | | - |
| 1014 | + |
1015 | 1015 | while ( $row = $db->fetchObject( $res ) ) { |
1016 | 1016 | $result[] = array( SMWPropertyValue::makeProperty( $row->smw_title ), $row->count ); |
1017 | 1017 | } |
1018 | | - |
| 1018 | + |
1019 | 1019 | $db->freeResult( $res ); |
1020 | 1020 | wfProfileOut( "SMWSQLStore2::getPropertiesSpecial (SMW)" ); |
1021 | | - |
| 1021 | + |
1022 | 1022 | return $result; |
1023 | 1023 | } |
1024 | 1024 | |
— | — | @@ -1030,7 +1030,7 @@ |
1031 | 1031 | */ |
1032 | 1032 | public function getUnusedPropertiesSpecial( $requestoptions = null ) { |
1033 | 1033 | global $wgDBtype; |
1034 | | - |
| 1034 | + |
1035 | 1035 | wfProfileIn( "SMWSQLStore2::getUnusedPropertiesSpecial (SMW)" ); |
1036 | 1036 | $db = wfGetDB( DB_SLAVE ); |
1037 | 1037 | $fname = 'SMW::getUnusedPropertySubjects'; |
— | — | @@ -1053,17 +1053,17 @@ |
1054 | 1054 | } else { // MySQL: use temporary in-memory table |
1055 | 1055 | $sql = "CREATE TEMPORARY TABLE " . $smw_tmp_unusedprops . "( title VARCHAR(255) ) TYPE=MEMORY"; |
1056 | 1056 | } |
1057 | | - |
| 1057 | + |
1058 | 1058 | $db->query( $sql, $fname ); |
1059 | 1059 | |
1060 | 1060 | $db->insertSelect( $smw_tmp_unusedprops, 'page', array( 'title' => 'page_title' ), |
1061 | 1061 | array( "page_namespace" => SMW_NS_PROPERTY ), $fname ); |
1062 | 1062 | |
1063 | 1063 | $smw_ids = $db->tableName( 'smw_ids' ); |
1064 | | - |
| 1064 | + |
1065 | 1065 | // all predefined properties are assumed to be used: |
1066 | 1066 | $db->deleteJoin( $smw_tmp_unusedprops, $smw_ids, 'title', 'smw_title', array( 'smw_iw' => SMW_SQL2_SMWPREDEFIW ), $fname ); |
1067 | | - |
| 1067 | + |
1068 | 1068 | // all tables occurring in some property table are used: |
1069 | 1069 | foreach ( self::getPropertyTables() as $proptable ) { |
1070 | 1070 | if ( $proptable->fixedproperty == false ) { // MW does not seem to have a suitable wrapper for this |
— | — | @@ -1071,11 +1071,11 @@ |
1072 | 1072 | " INNER JOIN $smw_ids ON p_id=smw_id WHERE title=smw_title AND smw_iw=" . $db->addQuotes( '' ), $fname ); |
1073 | 1073 | } // else: todo |
1074 | 1074 | } |
1075 | | - |
| 1075 | + |
1076 | 1076 | // properties that have subproperties are considered to be used |
1077 | 1077 | $proptables = self::getPropertyTables(); |
1078 | 1078 | $subtable = $proptables[self::findTypeTableID( '__sup' )]; // find the subproperty table, but consider its signature to be known |
1079 | | - |
| 1079 | + |
1080 | 1080 | // (again we have no fitting MW wrapper here:) |
1081 | 1081 | $db->query( "DELETE $smw_tmp_unusedprops.* FROM $smw_tmp_unusedprops," . $db->tableName( $subtable->name ) . |
1082 | 1082 | " INNER JOIN $smw_ids ON o_id=smw_id WHERE title=smw_title", $fname ); |
— | — | @@ -1088,18 +1088,18 @@ |
1089 | 1089 | $options = $this->getSQLOptions( $requestoptions, 'title' ); |
1090 | 1090 | $options['ORDER BY'] = 'title'; |
1091 | 1091 | $res = $db->select( $smw_tmp_unusedprops, 'title', '', $fname, $options ); |
1092 | | - |
| 1092 | + |
1093 | 1093 | $result = array(); |
1094 | | - |
| 1094 | + |
1095 | 1095 | while ( $row = $db->fetchObject( $res ) ) { |
1096 | 1096 | $result[] = SMWPropertyValue::makeProperty( $row->title ); |
1097 | 1097 | } |
1098 | | - |
| 1098 | + |
1099 | 1099 | $db->freeResult( $res ); |
1100 | 1100 | |
1101 | 1101 | $db->query( "DROP TEMPORARY table $smw_tmp_unusedprops", $fname ); |
1102 | 1102 | wfProfileOut( "SMWSQLStore2::getUnusedPropertiesSpecial (SMW)" ); |
1103 | | - |
| 1103 | + |
1104 | 1104 | return $result; |
1105 | 1105 | } |
1106 | 1106 | |
— | — | @@ -1107,22 +1107,22 @@ |
1108 | 1108 | * Implementation of SMWStore::getWantedPropertiesSpecial(). Like all |
1109 | 1109 | * WantedFoo specials, this function is very resource intensive and needs |
1110 | 1110 | * to be cached on medium/large wikis. |
1111 | | - * |
| 1111 | + * |
1112 | 1112 | * @param SMWRequestOptions $requestoptions |
1113 | | - * |
| 1113 | + * |
1114 | 1114 | * @return array |
1115 | 1115 | */ |
1116 | 1116 | public function getWantedPropertiesSpecial( $requestoptions = null ) { |
1117 | 1117 | global $smwgPDefaultType; |
1118 | | - |
| 1118 | + |
1119 | 1119 | wfProfileIn( "SMWSQLStore2::getWantedPropertiesSpecial (SMW)" ); |
1120 | | - |
| 1120 | + |
1121 | 1121 | // Note that Wanted Properties must have the default type. |
1122 | 1122 | $proptables = self::getPropertyTables(); |
1123 | 1123 | $proptable = $proptables[self::findTypeTableID( $smwgPDefaultType )]; |
1124 | | - |
| 1124 | + |
1125 | 1125 | $result = array(); |
1126 | | - |
| 1126 | + |
1127 | 1127 | if ( $proptable->fixedproperty == false ) { // anything else would be crazy, but let's fail gracefully even if the whole world is crazy |
1128 | 1128 | $db = wfGetDB( DB_SLAVE ); |
1129 | 1129 | $options = $this->getSQLOptions( $requestoptions, 'title' ); |
— | — | @@ -1132,24 +1132,24 @@ |
1133 | 1133 | $db->addQuotes( SMW_NS_PROPERTY ) . ' AND page_title=smw_title)', |
1134 | 1134 | 'smw_title, COUNT(*) as count', 'smw_id > 50 AND page_id IS NULL GROUP BY smw_title', |
1135 | 1135 | 'SMW::getWantedPropertiesSpecial', $options ); |
1136 | | - |
| 1136 | + |
1137 | 1137 | while ( $row = $db->fetchObject( $res ) ) { |
1138 | 1138 | $result[] = array( SMWPropertyValue::makeProperty( $row->smw_title ), $row->count ); |
1139 | 1139 | } |
1140 | 1140 | } |
1141 | | - |
| 1141 | + |
1142 | 1142 | wfProfileOut( "SMWSQLStore2::getWantedPropertiesSpecial (SMW)" ); |
1143 | | - |
| 1143 | + |
1144 | 1144 | return $result; |
1145 | 1145 | } |
1146 | 1146 | |
1147 | 1147 | public function getStatistics() { |
1148 | 1148 | wfProfileIn( 'SMWSQLStore2::getStatistics (SMW)' ); |
1149 | | - |
| 1149 | + |
1150 | 1150 | $db = wfGetDB( DB_SLAVE ); |
1151 | 1151 | $result = array(); |
1152 | 1152 | $proptables = self::getPropertyTables(); |
1153 | | - |
| 1153 | + |
1154 | 1154 | // count number of declared properties by counting "has type" annotations |
1155 | 1155 | $typeprop = SMWPropertyValue::makeProperty( '_TYPE' ); |
1156 | 1156 | $typetable = $proptables[self::findPropertyTableID( $typeprop )]; |
— | — | @@ -1157,12 +1157,12 @@ |
1158 | 1158 | $row = $db->fetchObject( $res ); |
1159 | 1159 | $result['DECLPROPS'] = $row->count; |
1160 | 1160 | $db->freeResult( $res ); |
1161 | | - |
| 1161 | + |
1162 | 1162 | // count property uses by counting rows in property tables, |
1163 | 1163 | // count used properties by counting distinct properties in each table |
1164 | 1164 | $result['PROPUSES'] = 0; |
1165 | 1165 | $result['USEDPROPS'] = 0; |
1166 | | - |
| 1166 | + |
1167 | 1167 | foreach ( self::getPropertyTables() as $proptable ) { |
1168 | 1168 | /// Note: subproperties that are part of container values are counted individually; |
1169 | 1169 | /// It does not seem to be important to filter them by adding more conditions. |
— | — | @@ -1170,7 +1170,7 @@ |
1171 | 1171 | $row = $db->fetchObject( $res ); |
1172 | 1172 | $result['PROPUSES'] += $row->count; |
1173 | 1173 | $db->freeResult( $res ); |
1174 | | - |
| 1174 | + |
1175 | 1175 | if ( $proptable->fixedproperty == false ) { |
1176 | 1176 | $res = $db->select( $proptable->name, 'COUNT(DISTINCT(p_id)) AS count', '', 'SMW::getStatistics' ); |
1177 | 1177 | $row = $db->fetchObject( $res ); |
— | — | @@ -1179,7 +1179,7 @@ |
1180 | 1180 | $res = $db->select( $proptable->name, '*', '', 'SMW::getStatistics', array( 'LIMIT' => 1 ) ); |
1181 | 1181 | if ( $db->numRows( $res ) > 0 ) $result['USEDPROPS']++; |
1182 | 1182 | } |
1183 | | - |
| 1183 | + |
1184 | 1184 | $db->freeResult( $res ); |
1185 | 1185 | } |
1186 | 1186 | |
— | — | @@ -1192,12 +1192,12 @@ |
1193 | 1193 | public function setup( $verbose = true ) { |
1194 | 1194 | $this->reportProgress( "Setting up standard database configuration for SMW ...\n\n", $verbose ); |
1195 | 1195 | $this->reportProgress( "Selected storage engine is \"SMWSQLStore2\" (or an extension thereof)\n\n", $verbose ); |
1196 | | - |
| 1196 | + |
1197 | 1197 | $db = wfGetDB( DB_MASTER ); |
1198 | | - |
| 1198 | + |
1199 | 1199 | $this->setupTables( $verbose, $db ); |
1200 | 1200 | $this->setupPredefinedProperties( $verbose, $db ); |
1201 | | - |
| 1201 | + |
1202 | 1202 | return true; |
1203 | 1203 | } |
1204 | 1204 | |
— | — | @@ -1228,9 +1228,9 @@ |
1229 | 1229 | */ |
1230 | 1230 | protected function setupTables( $verbose, $db ) { |
1231 | 1231 | global $wgDBtype; |
1232 | | - |
| 1232 | + |
1233 | 1233 | $reportTo = $verbose ? $this : null; // Use $this to report back from static SMWSQLHelpers. |
1234 | | - |
| 1234 | + |
1235 | 1235 | // Repeatedly used DB field types defined here for convenience. |
1236 | 1236 | $dbtypes = array( |
1237 | 1237 | 't' => SMWSQLHelpers::getStandardDBType( 'title' ), |
— | — | @@ -1245,7 +1245,7 @@ |
1246 | 1246 | ); |
1247 | 1247 | |
1248 | 1248 | $smw_spec2 = $db->tableName( 'smw_spec2' ); |
1249 | | - |
| 1249 | + |
1250 | 1250 | // DB update: field renaming between SMW 1.3 and SMW 1.4. |
1251 | 1251 | if ( ( $db->tableExists( $smw_spec2 ) ) && ( $db->fieldExists( $smw_spec2, 'sp_id', 'SMWSQLStore2::setup' ) ) ) { |
1252 | 1252 | if ( $wgDBtype == 'postgres' ) { |
— | — | @@ -1268,7 +1268,7 @@ |
1269 | 1269 | $db, |
1270 | 1270 | $reportTo |
1271 | 1271 | ); |
1272 | | - |
| 1272 | + |
1273 | 1273 | SMWSQLHelpers::setupIndex( 'smw_ids', array( 'smw_id', 'smw_title,smw_namespace,smw_iw', 'smw_sortkey' ), $db ); |
1274 | 1274 | |
1275 | 1275 | // Set up concept cache: member elements (s)->concepts (o) |
— | — | @@ -1281,9 +1281,9 @@ |
1282 | 1282 | $db, |
1283 | 1283 | $reportTo |
1284 | 1284 | ); |
1285 | | - |
| 1285 | + |
1286 | 1286 | SMWSQLHelpers::setupIndex( 'smw_conccache', array( 'o_id' ), $db ); |
1287 | | - |
| 1287 | + |
1288 | 1288 | // Set up concept descriptions. |
1289 | 1289 | SMWSQLHelpers::setupTable( |
1290 | 1290 | 'smw_conc2', |
— | — | @@ -1300,7 +1300,7 @@ |
1301 | 1301 | $db, |
1302 | 1302 | $reportTo |
1303 | 1303 | ); |
1304 | | - |
| 1304 | + |
1305 | 1305 | SMWSQLHelpers::setupIndex( 'smw_conc2', array( 's_id' ), $db ); |
1306 | 1306 | |
1307 | 1307 | // Set up all property tables as defined: |
— | — | @@ -1311,14 +1311,14 @@ |
1312 | 1312 | |
1313 | 1313 | /** |
1314 | 1314 | * Sets up the property tables. |
1315 | | - * |
| 1315 | + * |
1316 | 1316 | * @param array $dbtypes |
1317 | 1317 | * @param $db |
1318 | 1318 | * @param $reportTo SMWSQLStore2 or null |
1319 | 1319 | */ |
1320 | 1320 | protected function setupPropertyTables( array $dbtypes, $db, $reportTo ) { |
1321 | 1321 | $addedCustomTypeSignatures = false; |
1322 | | - |
| 1322 | + |
1323 | 1323 | foreach ( self::getPropertyTables() as $proptable ) { |
1324 | 1324 | if ( $proptable->idsubject ) { |
1325 | 1325 | $fieldarray = array( 's_id' => $dbtypes['p'] . ' NOT NULL' ); |
— | — | @@ -1327,32 +1327,32 @@ |
1328 | 1328 | $fieldarray = array( 's_title' => $dbtypes['t'] . ' NOT NULL', 's_namespace' => $dbtypes['n'] . ' NOT NULL' ); |
1329 | 1329 | $indexes = array( 's_title,s_namespace' ); |
1330 | 1330 | } |
1331 | | - |
| 1331 | + |
1332 | 1332 | if ( !$proptable->fixedproperty ) { |
1333 | 1333 | $fieldarray['p_id'] = $dbtypes['p'] . ' NOT NULL'; |
1334 | 1334 | $indexes[] = 'p_id'; |
1335 | 1335 | } |
1336 | | - |
| 1336 | + |
1337 | 1337 | foreach ( $proptable->objectfields as $fieldname => $typeid ) { |
1338 | 1338 | // If the type signature is not recognized and the custom signatures have not been added, add them. |
1339 | 1339 | if ( !$addedCustomTypeSignatures && !array_key_exists( $typeid, $dbtypes ) ) { |
1340 | 1340 | wfRunHooks( 'SMWCustomSQLStoreFieldType', array( &$dbtypes ) ); |
1341 | 1341 | $addedCustomTypeSignatures = true; |
1342 | 1342 | } |
1343 | | - |
| 1343 | + |
1344 | 1344 | // Only add the type when the signature was recognized, otherwise ignore it silently. |
1345 | 1345 | if ( array_key_exists( $typeid, $dbtypes ) ) { |
1346 | 1346 | $fieldarray[$fieldname] = $dbtypes[$typeid]; |
1347 | 1347 | } |
1348 | 1348 | } |
1349 | | - |
| 1349 | + |
1350 | 1350 | $indexes = array_merge( $indexes, $proptable->indexes ); |
1351 | | - |
| 1351 | + |
1352 | 1352 | SMWSQLHelpers::setupTable( $proptable->name, $fieldarray, $db, $reportTo ); |
1353 | | - SMWSQLHelpers::setupIndex( $proptable->name, $indexes, $db ); |
1354 | | - } |
| 1353 | + SMWSQLHelpers::setupIndex( $proptable->name, $indexes, $db ); |
| 1354 | + } |
1355 | 1355 | } |
1356 | | - |
| 1356 | + |
1357 | 1357 | /** |
1358 | 1358 | * Create some initial DB entries for important built-in properties. Having the DB contents predefined |
1359 | 1359 | * allows us to safe DB calls when certain data is needed. At the same time, the entries in the DB |
— | — | @@ -1360,16 +1360,16 @@ |
1361 | 1361 | */ |
1362 | 1362 | protected function setupPredefinedProperties( $verbose, $db ) { |
1363 | 1363 | global $wgDBtype; |
1364 | | - |
| 1364 | + |
1365 | 1365 | $this->reportProgress( "Setting up internal property indices ...\n", $verbose ); |
1366 | | - |
| 1366 | + |
1367 | 1367 | // Check if we already have this structure |
1368 | 1368 | $borderiw = $db->selectField( 'smw_ids', 'smw_iw', 'smw_id=' . $db->addQuotes( 50 ) ); |
1369 | | - |
| 1369 | + |
1370 | 1370 | if ( $borderiw != SMW_SQL2_SMWBORDERIW ) { |
1371 | 1371 | $this->reportProgress( " ... allocating space for internal properties...\n", $verbose ); |
1372 | 1372 | $this->moveSMWPageID( 50 ); // make sure position 50 is empty |
1373 | | - |
| 1373 | + |
1374 | 1374 | $db->insert( 'smw_ids', array( |
1375 | 1375 | 'smw_id' => 50, |
1376 | 1376 | 'smw_title' => '', |
— | — | @@ -1380,20 +1380,20 @@ |
1381 | 1381 | ); // put dummy "border element" on index 50 |
1382 | 1382 | |
1383 | 1383 | $this->reportProgress( ' ', $verbose ); |
1384 | | - |
| 1384 | + |
1385 | 1385 | for ( $i = 0; $i < 50; $i++ ) { // make way for built-in ids |
1386 | 1386 | $this->moveSMWPageID( $i ); |
1387 | 1387 | $this->reportProgress( '.', $verbose ); |
1388 | 1388 | } |
1389 | | - |
| 1389 | + |
1390 | 1390 | $this->reportProgress( " done.\n", $verbose ); |
1391 | 1391 | } else { |
1392 | 1392 | $this->reportProgress( " ... space for internal properties already allocated.\n", $verbose ); |
1393 | 1393 | } |
1394 | | - |
| 1394 | + |
1395 | 1395 | // now write actual properties; do that each time, it is cheap enough and we can update sortkeys by current language |
1396 | 1396 | $this->reportProgress( " ... writing entries for internal properties.", $verbose ); |
1397 | | - |
| 1397 | + |
1398 | 1398 | foreach ( self::$special_ids as $prop => $id ) { |
1399 | 1399 | $p = SMWPropertyValue::makeProperty( $prop ); |
1400 | 1400 | $db->replace( 'smw_ids', array( 'smw_id' ), array( |
— | — | @@ -1405,40 +1405,40 @@ |
1406 | 1406 | ), 'SMW::setup' |
1407 | 1407 | ); |
1408 | 1408 | } |
1409 | | - |
| 1409 | + |
1410 | 1410 | $this->reportProgress( " done.\n", $verbose ); |
1411 | | - |
| 1411 | + |
1412 | 1412 | if ( $wgDBtype == 'postgres' ) { |
1413 | 1413 | $this->reportProgress( " ... updating smw_ids_smw_id_seq sequence accordingly.\n", $verbose ); |
1414 | | - |
| 1414 | + |
1415 | 1415 | $max = $db->selectField( 'smw_ids', 'max(smw_id)', array(), __METHOD__ ); |
1416 | 1416 | $max += 1; |
1417 | | - |
| 1417 | + |
1418 | 1418 | $db->query( "ALTER SEQUENCE smw_ids_smw_id_seq RESTART WITH {$max}", __METHOD__ ); |
1419 | 1419 | } |
1420 | | - |
| 1420 | + |
1421 | 1421 | $this->reportProgress( "Internal properties initialised successfully.\n", $verbose ); |
1422 | 1422 | } |
1423 | 1423 | |
1424 | 1424 | public function drop( $verbose = true ) { |
1425 | 1425 | global $wgDBtype; |
1426 | | - |
| 1426 | + |
1427 | 1427 | $this->reportProgress( "Deleting all database content and tables generated by SMW ...\n\n", $verbose ); |
1428 | 1428 | $db = wfGetDB( DB_MASTER ); |
1429 | 1429 | $tables = array( 'smw_ids', 'smw_conc2', 'smw_conccache' ); |
1430 | | - |
| 1430 | + |
1431 | 1431 | foreach ( self::getPropertyTables() as $proptable ) { |
1432 | 1432 | $tables[] = $proptable->name; |
1433 | 1433 | } |
1434 | | - |
| 1434 | + |
1435 | 1435 | foreach ( $tables as $table ) { |
1436 | 1436 | $name = $db->tableName( $table ); |
1437 | 1437 | $db->query( 'DROP TABLE' . ( $wgDBtype == 'postgres' ? '' : ' IF EXISTS' ) . $name, 'SMWSQLStore2::drop' ); |
1438 | 1438 | $this->reportProgress( " ... dropped table $name.\n", $verbose ); |
1439 | 1439 | } |
1440 | | - |
| 1440 | + |
1441 | 1441 | $this->reportProgress( "All data removed successfully.\n", $verbose ); |
1442 | | - |
| 1442 | + |
1443 | 1443 | return true; |
1444 | 1444 | } |
1445 | 1445 | |
— | — | @@ -1448,20 +1448,20 @@ |
1449 | 1449 | |
1450 | 1450 | // update by MediaWiki page id --> make sure we get all pages |
1451 | 1451 | $tids = array(); |
1452 | | - |
| 1452 | + |
1453 | 1453 | for ( $i = $index; $i < $index + $count; $i++ ) { // array of ids |
1454 | 1454 | $tids[] = $i; |
1455 | 1455 | } |
1456 | | - |
| 1456 | + |
1457 | 1457 | $titles = Title::newFromIDs( $tids ); |
1458 | | - |
| 1458 | + |
1459 | 1459 | foreach ( $titles as $title ) { |
1460 | 1460 | // set $wgTitle, in case semantic data is set based |
1461 | 1461 | // on values not originating from the page (such as |
1462 | 1462 | // via the External Data extension) |
1463 | 1463 | global $wgTitle; |
1464 | 1464 | $wgTitle = $title; |
1465 | | - |
| 1465 | + |
1466 | 1466 | if ( ( $namespaces == false ) || ( in_array( $title->getNamespace(), $namespaces ) ) ) { |
1467 | 1467 | $updatejobs[] = new SMWUpdateJob( $title ); |
1468 | 1468 | $emptyrange = false; |
— | — | @@ -1472,16 +1472,16 @@ |
1473 | 1473 | $db = wfGetDB( DB_SLAVE ); |
1474 | 1474 | $res = $db->select( 'smw_ids', array( 'smw_id', 'smw_title', 'smw_namespace', 'smw_iw' ), |
1475 | 1475 | "smw_id >= $index AND smw_id < " . $db->addQuotes( $index + $count ), __METHOD__ ); |
1476 | | - |
| 1476 | + |
1477 | 1477 | foreach ( $res as $row ) { |
1478 | 1478 | $emptyrange = false; // note this even if no jobs were created |
1479 | | - |
| 1479 | + |
1480 | 1480 | if ( ( $namespaces != false ) && ( !in_array( $row->smw_namespace, $namespaces ) ) ) continue; |
1481 | | - |
| 1481 | + |
1482 | 1482 | if ( ( $row->smw_iw == '' ) || ( $row->smw_iw == SMW_SQL2_SMWREDIIW ) ) { // objects representing pages in the wiki, even special pages |
1483 | 1483 | // TODO: special treament of redirects needed, since the store will not act on redirects that did not change according to its records |
1484 | 1484 | $title = Title::makeTitle( $row->smw_namespace, $row->smw_title ); |
1485 | | - |
| 1485 | + |
1486 | 1486 | if ( !$title->exists() ) { |
1487 | 1487 | $updatejobs[] = new SMWUpdateJob( $title ); |
1488 | 1488 | } |
— | — | @@ -1500,19 +1500,19 @@ |
1501 | 1501 | $job->run(); |
1502 | 1502 | } |
1503 | 1503 | } |
1504 | | - |
| 1504 | + |
1505 | 1505 | $nextpos = $index + $count; |
1506 | | - |
| 1506 | + |
1507 | 1507 | if ( $emptyrange ) { // nothing found, check if there will be more pages later on |
1508 | 1508 | $next1 = $db->selectField( 'page', 'page_id', "page_id >= $nextpos", __METHOD__, array( 'ORDER BY' => "page_id ASC" ) ); |
1509 | 1509 | $next2 = $db->selectField( 'smw_ids', 'smw_id', "smw_id >= $nextpos", __METHOD__, array( 'ORDER BY' => "smw_id ASC" ) ); |
1510 | 1510 | $nextpos = ( ( $next2 != 0 ) && ( $next2 < $next1 ) ) ? $next2:$next1; |
1511 | 1511 | } |
1512 | | - |
| 1512 | + |
1513 | 1513 | $max1 = $db->selectField( 'page', 'MAX(page_id)', '', __METHOD__ ); |
1514 | 1514 | $max2 = $db->selectField( 'smw_ids', 'MAX(smw_id)', '', __METHOD__ ); |
1515 | 1515 | $index = $nextpos ? $nextpos: - 1; |
1516 | | - |
| 1516 | + |
1517 | 1517 | return ( $index > 0 ) ? $index / max( $max1, $max2 ) : 1; |
1518 | 1518 | } |
1519 | 1519 | |
— | — | @@ -1527,14 +1527,14 @@ |
1528 | 1528 | public function refreshConceptCache( $concept ) { |
1529 | 1529 | wfProfileIn( 'SMWSQLStore2::refreshConceptCache (SMW)' ); |
1530 | 1530 | global $smwgIP; |
1531 | | - |
| 1531 | + |
1532 | 1532 | include_once( "$smwgIP/includes/storage/SMW_SQLStore2_Queries.php" ); |
1533 | | - |
| 1533 | + |
1534 | 1534 | $qe = new SMWSQLStore2QueryEngine( $this, wfGetDB( DB_MASTER ) ); |
1535 | 1535 | $result = $qe->refreshConceptCache( $concept ); |
1536 | | - |
| 1536 | + |
1537 | 1537 | wfProfileOut( 'SMWSQLStore2::refreshConceptCache (SMW)' ); |
1538 | | - |
| 1538 | + |
1539 | 1539 | return $result; |
1540 | 1540 | } |
1541 | 1541 | |
— | — | @@ -1546,14 +1546,14 @@ |
1547 | 1547 | public function deleteConceptCache( $concept ) { |
1548 | 1548 | wfProfileIn( 'SMWSQLStore2::deleteConceptCache (SMW)' ); |
1549 | 1549 | global $smwgIP; |
1550 | | - |
| 1550 | + |
1551 | 1551 | include_once( "$smwgIP/includes/storage/SMW_SQLStore2_Queries.php" ); |
1552 | | - |
| 1552 | + |
1553 | 1553 | $qe = new SMWSQLStore2QueryEngine( $this, wfGetDB( DB_MASTER ) ); |
1554 | 1554 | $result = $qe->deleteConceptCache( $concept ); |
1555 | | - |
| 1555 | + |
1556 | 1556 | wfProfileOut( 'SMWSQLStore2::deleteConceptCache (SMW)' ); |
1557 | | - |
| 1557 | + |
1558 | 1558 | return $result; |
1559 | 1559 | } |
1560 | 1560 | |
— | — | @@ -1569,17 +1569,17 @@ |
1570 | 1570 | */ |
1571 | 1571 | public function getConceptCacheStatus( $concept ) { |
1572 | 1572 | wfProfileIn( 'SMWSQLStore2::getConceptCacheStatus (SMW)' ); |
1573 | | - |
| 1573 | + |
1574 | 1574 | $db = wfGetDB( DB_SLAVE ); |
1575 | 1575 | $cid = $this->getSMWPageID( $concept->getDBkey(), $concept->getNamespace(), '', false ); |
1576 | | - |
| 1576 | + |
1577 | 1577 | $row = $db->selectRow( 'smw_conc2', |
1578 | 1578 | array( 'concept_txt', 'concept_features', 'concept_size', 'concept_depth', 'cache_date', 'cache_count' ), |
1579 | 1579 | array( 's_id' => $cid ), 'SMWSQLStore2::getConceptCacheStatus (SMW)' ); |
1580 | | - |
| 1580 | + |
1581 | 1581 | if ( $row !== false ) { |
1582 | 1582 | $result = array( 'size' => $row->concept_size, 'depth' => $row->concept_depth, 'features' => $row->concept_features ); |
1583 | | - |
| 1583 | + |
1584 | 1584 | if ( $row->cache_date ) { |
1585 | 1585 | $result['status'] = 'full'; |
1586 | 1586 | $result['date'] = $row->cache_date; |
— | — | @@ -1590,9 +1590,9 @@ |
1591 | 1591 | } else { |
1592 | 1592 | $result = array( 'status' => 'no' ); |
1593 | 1593 | } |
1594 | | - |
| 1594 | + |
1595 | 1595 | wfProfileOut( 'SMWSQLStore2::getConceptCacheStatus (SMW)' ); |
1596 | | - |
| 1596 | + |
1597 | 1597 | return $result; |
1598 | 1598 | } |
1599 | 1599 | |
— | — | @@ -1606,21 +1606,21 @@ |
1607 | 1607 | */ |
1608 | 1608 | protected function getSQLOptions( $requestoptions, $valuecol = '' ) { |
1609 | 1609 | $sql_options = array(); |
1610 | | - |
| 1610 | + |
1611 | 1611 | if ( $requestoptions !== null ) { |
1612 | 1612 | if ( $requestoptions->limit > 0 ) { |
1613 | 1613 | $sql_options['LIMIT'] = $requestoptions->limit; |
1614 | 1614 | } |
1615 | | - |
| 1615 | + |
1616 | 1616 | if ( $requestoptions->offset > 0 ) { |
1617 | 1617 | $sql_options['OFFSET'] = $requestoptions->offset; |
1618 | 1618 | } |
1619 | | - |
| 1619 | + |
1620 | 1620 | if ( ( $valuecol != '' ) && ( $requestoptions->sort ) ) { |
1621 | 1621 | $sql_options['ORDER BY'] = $requestoptions->ascending ? $valuecol : $valuecol . ' DESC'; |
1622 | 1622 | } |
1623 | 1623 | } |
1624 | | - |
| 1624 | + |
1625 | 1625 | return $sql_options; |
1626 | 1626 | } |
1627 | 1627 | |
— | — | @@ -1628,20 +1628,20 @@ |
1629 | 1629 | * Transform input parameters into a suitable string of additional SQL conditions. |
1630 | 1630 | * The parameter $valuecol defines the string name of the column to which |
1631 | 1631 | * value restrictions etc. are to be applied. |
1632 | | - * |
| 1632 | + * |
1633 | 1633 | * @param $requestoptions object with options |
1634 | 1634 | * @param $valuecol name of SQL column to which conditions apply |
1635 | 1635 | * @param $labelcol name of SQL column to which string conditions apply, if any |
1636 | 1636 | * @param $addand Boolean to indicate whether the string should begin with " AND " if non-empty |
1637 | | - * |
| 1637 | + * |
1638 | 1638 | * @return string |
1639 | 1639 | */ |
1640 | 1640 | protected function getSQLConditions( $requestoptions, $valuecol = '', $labelcol = '', $addand = true ) { |
1641 | 1641 | $sql_conds = ''; |
1642 | | - |
| 1642 | + |
1643 | 1643 | if ( $requestoptions !== null ) { |
1644 | 1644 | $db = wfGetDB( DB_SLAVE ); /// TODO avoid doing this here again, all callers should have one |
1645 | | - |
| 1645 | + |
1646 | 1646 | if ( ( $valuecol != '' ) && ( $requestoptions->boundary !== null ) ) { // Apply value boundary. |
1647 | 1647 | if ( $requestoptions->ascending ) { |
1648 | 1648 | $op = $requestoptions->include_boundary ? ' >= ' : ' > '; |
— | — | @@ -1650,22 +1650,22 @@ |
1651 | 1651 | } |
1652 | 1652 | $sql_conds .= ( $addand ? ' AND ' : '' ) . $valuecol . $op . $db->addQuotes( $requestoptions->boundary ); |
1653 | 1653 | } |
1654 | | - |
| 1654 | + |
1655 | 1655 | if ( $labelcol != '' ) { // Apply string conditions. |
1656 | 1656 | foreach ( $requestoptions->getStringConditions() as $strcond ) { |
1657 | 1657 | $string = str_replace( '_', '\_', $strcond->string ); |
1658 | | - |
| 1658 | + |
1659 | 1659 | switch ( $strcond->condition ) { |
1660 | 1660 | case SMWStringCondition::STRCOND_PRE: $string .= '%'; break; |
1661 | 1661 | case SMWStringCondition::STRCOND_POST: $string = '%' . $string; break; |
1662 | 1662 | case SMWStringCondition::STRCOND_MID: $string = '%' . $string . '%'; break; |
1663 | 1663 | } |
1664 | | - |
| 1664 | + |
1665 | 1665 | $sql_conds .= ( ( $addand || ( $sql_conds != '' ) ) ? ' AND ' : '' ) . $labelcol . ' LIKE ' . $db->addQuotes( $string ); |
1666 | 1666 | } |
1667 | 1667 | } |
1668 | 1668 | } |
1669 | | - |
| 1669 | + |
1670 | 1670 | return $sql_conds; |
1671 | 1671 | } |
1672 | 1672 | |
— | — | @@ -1678,30 +1678,30 @@ |
1679 | 1679 | */ |
1680 | 1680 | protected function applyRequestOptions( $data, $requestoptions ) { |
1681 | 1681 | wfProfileIn( "SMWSQLStore2::applyRequestOptions (SMW)" ); |
1682 | | - |
| 1682 | + |
1683 | 1683 | if ( ( count( $data ) == 0 ) || ( $requestoptions === null ) ) { |
1684 | 1684 | wfProfileOut( "SMWSQLStore2::applyRequestOptions (SMW)" ); |
1685 | 1685 | return $data; |
1686 | 1686 | } |
1687 | | - |
| 1687 | + |
1688 | 1688 | $result = array(); |
1689 | 1689 | $sortres = array(); |
1690 | | - |
| 1690 | + |
1691 | 1691 | list( $sig, $valueIndex, $labelIndex ) = self::getTypeSignature( reset( $data )->getTypeID() ); |
1692 | | - |
| 1692 | + |
1693 | 1693 | $numeric = ( ( $valueIndex >= 0 ) && ( strlen( $sig ) > $valueIndex ) && |
1694 | 1694 | ( ( $sig { $valueIndex } != 'f' ) || ( $sig { $valueIndex } != 'n' ) ) ); |
1695 | 1695 | $i = 0; |
1696 | | - |
| 1696 | + |
1697 | 1697 | foreach ( $data as $item ) { |
1698 | 1698 | $ok = true; // keep datavalue only if this remains true |
1699 | 1699 | $keys = $item->getDBkeys(); |
1700 | 1700 | $value = array_key_exists( $valueIndex, $keys ) ? $keys[$valueIndex] : ''; |
1701 | 1701 | $label = array_key_exists( $labelIndex, $keys ) ? $keys[$labelIndex] : ''; |
1702 | | - |
| 1702 | + |
1703 | 1703 | if ( $requestoptions->boundary !== null ) { // apply value boundary |
1704 | 1704 | $strc = $numeric ? 0 : strcmp( $value, $requestoptions->boundary ); |
1705 | | - |
| 1705 | + |
1706 | 1706 | if ( $requestoptions->ascending ) { |
1707 | 1707 | if ( $requestoptions->include_boundary ) { |
1708 | 1708 | $ok = $numeric ? ( $value >= $requestoptions->boundary ) : ( $strc >= 0 ); |
— | — | @@ -1716,7 +1716,7 @@ |
1717 | 1717 | } |
1718 | 1718 | } |
1719 | 1719 | } |
1720 | | - |
| 1720 | + |
1721 | 1721 | foreach ( $requestoptions->getStringConditions() as $strcond ) { // apply string conditions |
1722 | 1722 | switch ( $strcond->condition ) { |
1723 | 1723 | case SMWStringCondition::STRCOND_PRE: |
— | — | @@ -1730,40 +1730,40 @@ |
1731 | 1731 | break; |
1732 | 1732 | } |
1733 | 1733 | } |
1734 | | - |
| 1734 | + |
1735 | 1735 | if ( $ok ) { |
1736 | 1736 | $result[$i] = $item; |
1737 | 1737 | $sortres[$i] = $value; // we cannot use $value as key: it is not unique if there are units! |
1738 | 1738 | $i++; |
1739 | 1739 | } |
1740 | 1740 | } |
1741 | | - |
| 1741 | + |
1742 | 1742 | if ( $requestoptions->sort ) { |
1743 | 1743 | $flag = $numeric ? SORT_NUMERIC:SORT_LOCALE_STRING; |
1744 | | - |
| 1744 | + |
1745 | 1745 | if ( $requestoptions->ascending ) { |
1746 | 1746 | asort( $sortres, $flag ); |
1747 | 1747 | } else { |
1748 | 1748 | arsort( $sortres, $flag ); |
1749 | 1749 | } |
1750 | | - |
| 1750 | + |
1751 | 1751 | $newres = array(); |
1752 | | - |
| 1752 | + |
1753 | 1753 | foreach ( $sortres as $key => $value ) { |
1754 | 1754 | $newres[] = $result[$key]; |
1755 | 1755 | } |
1756 | | - |
| 1756 | + |
1757 | 1757 | $result = $newres; |
1758 | 1758 | } |
1759 | | - |
| 1759 | + |
1760 | 1760 | if ( $requestoptions->limit > 0 ) { |
1761 | 1761 | $result = array_slice( $result, $requestoptions->offset, $requestoptions->limit ); |
1762 | 1762 | } else { |
1763 | 1763 | $result = array_slice( $result, $requestoptions->offset ); |
1764 | 1764 | } |
1765 | | - |
| 1765 | + |
1766 | 1766 | wfProfileOut( "SMWSQLStore2::applyRequestOptions (SMW)" ); |
1767 | | - |
| 1767 | + |
1768 | 1768 | return $result; |
1769 | 1769 | } |
1770 | 1770 | |
— | — | @@ -1776,7 +1776,7 @@ |
1777 | 1777 | if ( ob_get_level() == 0 ) { // be sure to have some buffer, otherwise some PHPs complain |
1778 | 1778 | ob_start(); |
1779 | 1779 | } |
1780 | | - |
| 1780 | + |
1781 | 1781 | print $msg; |
1782 | 1782 | ob_flush(); |
1783 | 1783 | flush(); |
— | — | @@ -1800,7 +1800,7 @@ |
1801 | 1801 | $dv = SMWDataValueFactory::newTypeIDValue( $typeid ); |
1802 | 1802 | self::$type_signatures[$typeid] = array( $dv->getSignature(), $dv->getValueIndex(), $dv->getLabelIndex() ); |
1803 | 1803 | } |
1804 | | - |
| 1804 | + |
1805 | 1805 | return self::$type_signatures[$typeid]; |
1806 | 1806 | } |
1807 | 1807 | |
— | — | @@ -1811,10 +1811,10 @@ |
1812 | 1812 | */ |
1813 | 1813 | public static function tableFitsSignature( $tableid, $signature ) { |
1814 | 1814 | $proptables = self::getPropertyTables(); |
1815 | | - |
| 1815 | + |
1816 | 1816 | $tablesig = str_replace( 'p', 'tnwt', $proptables[$tableid]->getFieldSignature() ); // expand internal page type to single fields |
1817 | 1817 | $valuesig = reset( $signature ); |
1818 | | - |
| 1818 | + |
1819 | 1819 | return ( $valuesig == substr( $tablesig, 0, strlen( $valuesig ) ) ); |
1820 | 1820 | } |
1821 | 1821 | |
— | — | @@ -1834,17 +1834,17 @@ |
1835 | 1835 | public static function findTypeTableID( $typeid ) { |
1836 | 1836 | if ( !array_key_exists( $typeid, self::$property_table_ids ) ) { |
1837 | 1837 | $signature = self::getTypeSignature( $typeid ); |
1838 | | - |
| 1838 | + |
1839 | 1839 | foreach ( self::getPropertyTables() as $tid => $proptable ) { |
1840 | 1840 | if ( self::tableFitsSignature( $tid, $signature ) ) { |
1841 | 1841 | self::$property_table_ids[$typeid] = $tid; |
1842 | 1842 | return $tid; |
1843 | 1843 | } |
1844 | 1844 | } |
1845 | | - |
| 1845 | + |
1846 | 1846 | self::$property_table_ids[$typeid] = ''; // No matching table found. |
1847 | 1847 | } |
1848 | | - |
| 1848 | + |
1849 | 1849 | return self::$property_table_ids[$typeid]; |
1850 | 1850 | } |
1851 | 1851 | |
— | — | @@ -1855,19 +1855,19 @@ |
1856 | 1856 | public static function findPropertyTableID( $property ) { |
1857 | 1857 | if ( self::$fixed_prop_tables === null ) { // Build lookup array once. |
1858 | 1858 | self::$fixed_prop_tables = array(); |
1859 | | - |
| 1859 | + |
1860 | 1860 | foreach ( self::getPropertyTables() as $tid => $proptable ) { |
1861 | 1861 | if ( $proptable->fixedproperty != false ) { |
1862 | 1862 | self::$fixed_prop_tables[$proptable->fixedproperty] = $tid; |
1863 | 1863 | } |
1864 | 1864 | } |
1865 | 1865 | } |
1866 | | - |
| 1866 | + |
1867 | 1867 | $propertykey = ( $property->isUserDefined() ) ? $property->getDBkey():$property->getPropertyId(); |
1868 | | - |
| 1868 | + |
1869 | 1869 | if ( array_key_exists( $propertykey, self::$fixed_prop_tables ) ) { |
1870 | 1870 | $signature = self::getTypeSignature( $property->getPropertyTypeID() ); |
1871 | | - |
| 1871 | + |
1872 | 1872 | if ( self::tableFitsSignature( SMWSQLStore2::$fixed_prop_tables[$propertykey], $signature ) ) { |
1873 | 1873 | return self::$fixed_prop_tables[$propertykey]; |
1874 | 1874 | } |
— | — | @@ -1896,46 +1896,46 @@ |
1897 | 1897 | */ |
1898 | 1898 | public function getSMWPageIDandSort( $title, $namespace, $iw, &$sort, $canonical ) { |
1899 | 1899 | global $smwgQEqualitySupport; |
1900 | | - |
| 1900 | + |
1901 | 1901 | wfProfileIn( 'SMWSQLStore2::getSMWPageID (SMW)' ); |
1902 | | - |
| 1902 | + |
1903 | 1903 | $ckey = "$iw $namespace $title C"; |
1904 | 1904 | $nkey = "$iw $namespace $title -"; |
1905 | 1905 | $key = ( $canonical ? $ckey:$nkey ); |
1906 | | - |
| 1906 | + |
1907 | 1907 | if ( array_key_exists( $key, $this->m_ids ) ) { |
1908 | 1908 | wfProfileOut( 'SMWSQLStore2::getSMWPageID (SMW)' ); |
1909 | 1909 | return $this->m_ids[$key]; |
1910 | 1910 | } |
1911 | | - |
| 1911 | + |
1912 | 1912 | if ( count( $this->m_ids ) > 1500 ) { // prevent memory leak in very long PHP runs |
1913 | 1913 | $this->m_ids = array(); |
1914 | 1914 | } |
1915 | | - |
| 1915 | + |
1916 | 1916 | $db = wfGetDB( DB_SLAVE ); |
1917 | 1917 | $id = 0; |
1918 | | - |
| 1918 | + |
1919 | 1919 | if ( $iw != '' ) { // external page; no need to think about redirects |
1920 | 1920 | $res = $db->select( 'smw_ids', array( 'smw_id', 'smw_sortkey' ), |
1921 | 1921 | array( 'smw_title' => $title, 'smw_namespace' => $namespace, 'smw_iw' => $iw ), |
1922 | 1922 | 'SMW::getSMWPageID', array( 'LIMIT' => 1 ) ); |
1923 | | - |
| 1923 | + |
1924 | 1924 | if ( $row = $db->fetchObject( $res ) ) { |
1925 | 1925 | $id = $row->smw_id; |
1926 | 1926 | $sort = $row->smw_sortkey; |
1927 | 1927 | } |
1928 | | - |
| 1928 | + |
1929 | 1929 | $this->m_ids[ $canonical ? $nkey:$ckey ] = $id; // unique id, make sure cache for canonical+non-cacnonical gets filled |
1930 | 1930 | } else { // check for potential redirects also |
1931 | 1931 | $res = $db->select( 'smw_ids', array( 'smw_id', 'smw_iw', 'smw_sortkey' ), |
1932 | 1932 | 'smw_title=' . $db->addQuotes( $title ) . ' AND smw_namespace=' . $db->addQuotes( $namespace ) . |
1933 | 1933 | ' AND (smw_iw=' . $db->addQuotes( '' ) . ' OR smw_iw=' . $db->addQuotes( SMW_SQL2_SMWREDIIW ) . ')', |
1934 | 1934 | 'SMW::getSMWPageID', array( 'LIMIT' => 1 ) ); |
1935 | | - |
| 1935 | + |
1936 | 1936 | if ( $row = $db->fetchObject( $res ) ) { |
1937 | 1937 | $id = $row->smw_id; // set id in any case, the below check for properties will use even the redirect id in emergency |
1938 | 1938 | $sort = $row->smw_sortkey; |
1939 | | - |
| 1939 | + |
1940 | 1940 | if ( ( $row->smw_iw == '' ) ) { // the id found is unique (canonical and non-canonical); fill cache also for the case *not* asked for |
1941 | 1941 | $this->m_ids[ $canonical ? $nkey:$ckey ] = $id; // (the other cache is filled below) |
1942 | 1942 | } elseif ( $canonical && ( $smwgQEqualitySupport != SMW_EQ_NONE ) ) { // get redirect alias |
— | — | @@ -1949,21 +1949,21 @@ |
1950 | 1950 | 's_title=' . $db->addQuotes( $title ) . ' AND s_namespace=' . $db->addQuotes( $namespace ), |
1951 | 1951 | 'SMW::getSMWPageID', array( 'LIMIT' => 1 ) ); |
1952 | 1952 | } |
1953 | | - |
| 1953 | + |
1954 | 1954 | if ( $row = $db->fetchObject( $res2 ) ) { |
1955 | 1955 | $id = $row->o_id; |
1956 | 1956 | } |
1957 | | - |
| 1957 | + |
1958 | 1958 | $db->freeResult( $res2 ); |
1959 | 1959 | } |
1960 | 1960 | } |
1961 | 1961 | } |
1962 | | - |
| 1962 | + |
1963 | 1963 | $db->freeResult( $res ); |
1964 | 1964 | |
1965 | 1965 | $this->m_ids[$key] = $id; |
1966 | 1966 | wfProfileOut( 'SMWSQLStore2::getSMWPageID (SMW)' ); |
1967 | | - |
| 1967 | + |
1968 | 1968 | return $id; |
1969 | 1969 | } |
1970 | 1970 | |
— | — | @@ -1979,21 +1979,21 @@ |
1980 | 1980 | */ |
1981 | 1981 | protected function makeSMWPageID( $title, $namespace, $iw, $canonical = true, $sortkey = '' ) { |
1982 | 1982 | wfProfileIn( 'SMWSQLStore2::makeSMWPageID (SMW)' ); |
1983 | | - |
| 1983 | + |
1984 | 1984 | $oldsort = ''; |
1985 | 1985 | $id = $this->getSMWPageIDandSort( $title, $namespace, $iw, $oldsort, $canonical ); |
1986 | | - |
| 1986 | + |
1987 | 1987 | if ( $id == 0 ) { |
1988 | 1988 | $db = wfGetDB( DB_MASTER ); |
1989 | 1989 | $sortkey = $sortkey ? $sortkey:( str_replace( '_', ' ', $title ) ); |
1990 | | - |
| 1990 | + |
1991 | 1991 | $db->insert( 'smw_ids', |
1992 | 1992 | array( 'smw_id' => $db->nextSequenceValue( 'smw_ids_smw_id_seq' ), |
1993 | 1993 | 'smw_title' => $title, |
1994 | 1994 | 'smw_namespace' => $namespace, |
1995 | 1995 | 'smw_iw' => $iw, |
1996 | 1996 | 'smw_sortkey' => $sortkey ), 'SMW::makeSMWPageID' ); |
1997 | | - |
| 1997 | + |
1998 | 1998 | $id = $db->insertId(); |
1999 | 1999 | $this->m_ids["$iw $namespace $title -"] = $id; // fill that cache, even if canonical was given |
2000 | 2000 | // This ID is also authorative for the canonical version. |
— | — | @@ -2004,9 +2004,9 @@ |
2005 | 2005 | $db = wfGetDB( DB_MASTER ); |
2006 | 2006 | $db->update( 'smw_ids', array( 'smw_sortkey' => $sortkey ), array( 'smw_id' => $id ), 'SMW::makeSMWPageID' ); |
2007 | 2007 | } |
2008 | | - |
| 2008 | + |
2009 | 2009 | wfProfileOut( 'SMWSQLStore2::makeSMWPageID (SMW)' ); |
2010 | | - |
| 2010 | + |
2011 | 2011 | return $id; |
2012 | 2012 | } |
2013 | 2013 | |
— | — | @@ -2058,13 +2058,13 @@ |
2059 | 2059 | public function cacheSMWPageID( $id, $title, $namespace, $iw ) { |
2060 | 2060 | $ckey = "$iw $namespace $title C"; |
2061 | 2061 | $nkey = "$iw $namespace $title -"; |
2062 | | - |
| 2062 | + |
2063 | 2063 | if ( count( $this->m_ids ) > 1500 ) { // prevent memory leak in very long PHP runs |
2064 | 2064 | $this->m_ids = array(); |
2065 | 2065 | } |
2066 | | - |
| 2066 | + |
2067 | 2067 | $this->m_ids[$nkey] = $id; |
2068 | | - |
| 2068 | + |
2069 | 2069 | if ( $iw != SMW_SQL2_SMWREDIIW ) { |
2070 | 2070 | $this->m_ids[$ckey] = $id; |
2071 | 2071 | } |
— | — | @@ -2083,14 +2083,14 @@ |
2084 | 2084 | */ |
2085 | 2085 | protected function makeSMWBnodeID( $sid ) { |
2086 | 2086 | $db = wfGetDB( DB_MASTER ); |
2087 | | - |
| 2087 | + |
2088 | 2088 | // check if there is an unused bnode to take: |
2089 | 2089 | $res = $db->select( 'smw_ids', 'smw_id', array( 'smw_title' => '', 'smw_namespace' => 0, 'smw_iw' => SMW_SQL2_SMWIW ), |
2090 | 2090 | 'SMW::makeSMWBnodeID', array( 'LIMIT' => 1 ) ); |
2091 | | - |
| 2091 | + |
2092 | 2092 | $id = ( $row = $db->fetchObject( $res ) ) ? $row->smw_id:0; |
2093 | 2093 | $db->freeResult( $res ); |
2094 | | - |
| 2094 | + |
2095 | 2095 | // claim that bnode: |
2096 | 2096 | if ( $id != 0 ) { |
2097 | 2097 | $db->update( 'smw_ids', array( 'smw_namespace' => $sid ), |
— | — | @@ -2098,7 +2098,7 @@ |
2099 | 2099 | 'smw_title' => '', |
2100 | 2100 | 'smw_namespace' => 0, |
2101 | 2101 | 'smw_iw' => SMW_SQL2_SMWIW ), 'SMW::makeSMWBnodeID', array( 'LIMIT' => 1 ) ); |
2102 | | - |
| 2102 | + |
2103 | 2103 | if ( $db->affectedRows() == 0 ) { // Oops, someone was faster (collisions are possible here, no locks) |
2104 | 2104 | $id = 0; // fallback: make a new node (TODO: we could also repeat to try another ID) |
2105 | 2105 | } |
— | — | @@ -2110,10 +2110,10 @@ |
2111 | 2111 | 'smw_title' => '', |
2112 | 2112 | 'smw_namespace' => $sid, |
2113 | 2113 | 'smw_iw' => SMW_SQL2_SMWIW ), 'SMW::makeSMWBnodeID' ); |
2114 | | - |
| 2114 | + |
2115 | 2115 | $id = $db->insertId(); |
2116 | 2116 | } |
2117 | | - |
| 2117 | + |
2118 | 2118 | return $id; |
2119 | 2119 | } |
2120 | 2120 | |
— | — | @@ -2132,16 +2132,16 @@ |
2133 | 2133 | $row = $db->selectRow( 'smw_ids', |
2134 | 2134 | array( 'smw_id', 'smw_namespace', 'smw_title', 'smw_iw', 'smw_sortkey' ), |
2135 | 2135 | array( 'smw_id' => $curid ), 'SMWSQLStore2::moveSMWPageID' ); |
2136 | | - |
| 2136 | + |
2137 | 2137 | if ( $row === false ) return; // no id at current position, ignore |
2138 | | - |
| 2138 | + |
2139 | 2139 | if ( $targetid == 0 ) { // append new id |
2140 | 2140 | $db->insert( 'smw_ids', array( 'smw_id' => $db->nextSequenceValue( 'smw_ids_smw_id_seq' ), |
2141 | 2141 | 'smw_title' => $row->smw_title, |
2142 | 2142 | 'smw_namespace' => $row->smw_namespace, |
2143 | 2143 | 'smw_iw' => $row->smw_iw, |
2144 | 2144 | 'smw_sortkey' => $row->smw_sortkey ), 'SMW::moveSMWPageID' ); |
2145 | | - |
| 2145 | + |
2146 | 2146 | $targetid = $db->insertId(); |
2147 | 2147 | } else { // change to given id |
2148 | 2148 | $db->insert( 'smw_ids', array( 'smw_id' => $targetid, |
— | — | @@ -2150,7 +2150,7 @@ |
2151 | 2151 | 'smw_iw' => $row->smw_iw, |
2152 | 2152 | 'smw_sortkey' => $row->smw_sortkey ), 'SMW::moveSMWPageID' ); |
2153 | 2153 | } |
2154 | | - |
| 2154 | + |
2155 | 2155 | $db->delete( 'smw_ids', array( 'smw_id' => $curid ), 'SMWSQLStore2::moveSMWPageID' ); |
2156 | 2156 | $this->changeSMWPageID( $curid, $targetid, $row->smw_namespace, $row->smw_namespace ); |
2157 | 2157 | } |
— | — | @@ -2172,31 +2172,31 @@ |
2173 | 2173 | * @param $sdata boolean stating whether to update subject references |
2174 | 2174 | * @param $podata boolean stating if to update property/object references |
2175 | 2175 | */ |
2176 | | - protected function changeSMWPageID( $oldid, $newid, $oldnamespace = - 1, $newnamespace = - 1, $sdata = true, $podata = true ) { |
| 2176 | + protected function changeSMWPageID( $oldid, $newid, $oldnamespace = -1, $newnamespace = -1, $sdata = true, $podata = true ) { |
2177 | 2177 | $fname = 'SMW::changeSMWPageID'; |
2178 | 2178 | $db = wfGetDB( DB_MASTER ); |
2179 | | - |
| 2179 | + |
2180 | 2180 | // Update bnode references that use namespace field to store ids: |
2181 | 2181 | if ( $sdata ) { // bnodes are part of the data of a subject |
2182 | 2182 | $db->update( 'smw_ids', array( 'smw_namespace' => $newid ), |
2183 | 2183 | array( 'smw_title' => '', 'smw_namespace' => $oldid, 'smw_iw' => SMW_SQL2_SMWIW ), $fname ); |
2184 | 2184 | } |
2185 | | - |
| 2185 | + |
2186 | 2186 | // change all id entries in property tables: |
2187 | 2187 | foreach ( self::getPropertyTables() as $proptable ) { |
2188 | 2188 | if ( $sdata && $proptable->idsubject ) { |
2189 | 2189 | $db->update( $proptable->name, array( 's_id' => $newid ), array( 's_id' => $oldid ), $fname ); |
2190 | 2190 | } |
2191 | | - |
| 2191 | + |
2192 | 2192 | if ( $podata ) { |
2193 | | - if ( ( ( $oldnamespace == - 1 ) || ( $oldnamespace == SMW_NS_PROPERTY ) ) && ( $proptable->fixedproperty == false ) ) { |
2194 | | - if ( ( $newnamespace == - 1 ) || ( $newnamespace == SMW_NS_PROPERTY ) ) { |
| 2193 | + if ( ( ( $oldnamespace == -1 ) || ( $oldnamespace == SMW_NS_PROPERTY ) ) && ( $proptable->fixedproperty == false ) ) { |
| 2194 | + if ( ( $newnamespace == -1 ) || ( $newnamespace == SMW_NS_PROPERTY ) ) { |
2195 | 2195 | $db->update( $proptable->name, array( 'p_id' => $newid ), array( 'p_id' => $oldid ), $fname ); |
2196 | 2196 | } else { |
2197 | 2197 | $db->delete( $proptable->name, array( 'p_id' => $oldid ), $fname ); |
2198 | 2198 | } |
2199 | 2199 | } |
2200 | | - |
| 2200 | + |
2201 | 2201 | foreach ( $proptable->objectfields as $fieldname => $type ) { |
2202 | 2202 | if ( $type == 'p' ) { |
2203 | 2203 | $db->update( $proptable->name, array( $fieldname => $newid ), array( $fieldname => $oldid ), $fname ); |
— | — | @@ -2205,8 +2205,8 @@ |
2206 | 2206 | } |
2207 | 2207 | } |
2208 | 2208 | // change id entries in concept-related tables: |
2209 | | - if ( $sdata && ( ( $oldnamespace == - 1 ) || ( $oldnamespace == SMW_NS_CONCEPT ) ) ) { |
2210 | | - if ( ( $newnamespace == - 1 ) || ( $newnamespace == SMW_NS_CONCEPT ) ) { |
| 2209 | + if ( $sdata && ( ( $oldnamespace == -1 ) || ( $oldnamespace == SMW_NS_CONCEPT ) ) ) { |
| 2210 | + if ( ( $newnamespace == -1 ) || ( $newnamespace == SMW_NS_CONCEPT ) ) { |
2211 | 2211 | $db->update( 'smw_conc2', array( 's_id' => $newid ), array( 's_id' => $oldid ), $fname ); |
2212 | 2212 | $db->update( 'smw_conccache', array( 's_id' => $newid ), array( 's_id' => $oldid ), $fname ); |
2213 | 2213 | } else { |
— | — | @@ -2225,23 +2225,23 @@ |
2226 | 2226 | */ |
2227 | 2227 | protected function deleteSemanticData( SMWWikiPageValue $subject ) { |
2228 | 2228 | $db = wfGetDB( DB_MASTER ); |
2229 | | - |
| 2229 | + |
2230 | 2230 | $fname = 'SMW::deleteSemanticData'; |
2231 | 2231 | $id = $this->getSMWPageID( $subject->getDBkey(), $subject->getNamespace(), $subject->getInterwiki(), false ); |
2232 | | - |
| 2232 | + |
2233 | 2233 | if ( $id == 0 ) return; // not (directly) used anywhere yet, maybe a redirect but we do not care here |
2234 | | - |
| 2234 | + |
2235 | 2235 | foreach ( self::getPropertyTables() as $proptable ) { |
2236 | 2236 | if ( $proptable->idsubject ) { |
2237 | 2237 | $db->delete( $proptable->name, array( 's_id' => $id ), $fname ); |
2238 | | - } elseif ( $proptable->name != 'smw_redi' ) { /// NOTE: redirects are handled by updateRedirects(), not here! |
| 2238 | + } elseif ( $proptable->name != 'smw_redi2' ) { /// NOTE: redirects are handled by updateRedirects(), not here! |
2239 | 2239 | $db->delete( $proptable->name, array( 's_title' => $subject->getDBkey(), 's_namespace' => $subject->getNamespace() ), $fname ); |
2240 | 2240 | } |
2241 | 2241 | } |
2242 | | - |
| 2242 | + |
2243 | 2243 | // also find bnodes used by this ID ... |
2244 | 2244 | $res = $db->select( 'smw_ids', 'smw_id', array( 'smw_title' => '', 'smw_namespace' => $id, 'smw_iw' => SMW_SQL2_SMWIW ), $fname ); |
2245 | | - |
| 2245 | + |
2246 | 2246 | // ... and delete them as well |
2247 | 2247 | while ( $row = $db->fetchObject( $res ) ) { |
2248 | 2248 | foreach ( self::getPropertyTables() as $proptable ) { |
— | — | @@ -2250,21 +2250,21 @@ |
2251 | 2251 | } |
2252 | 2252 | } |
2253 | 2253 | } |
2254 | | - |
| 2254 | + |
2255 | 2255 | $db->freeResult( $res ); |
2256 | | - |
| 2256 | + |
2257 | 2257 | // free all affected bnodes in one call: |
2258 | 2258 | $db->update( 'smw_ids', array( 'smw_namespace' => 0 ), array( 'smw_title' => '', 'smw_namespace' => $id, 'smw_iw' => SMW_SQL2_SMWIW ), $fname ); |
2259 | | - |
| 2259 | + |
2260 | 2260 | wfRunHooks( 'smwDeleteSemanticData', array( $subject ) ); |
2261 | 2261 | } |
2262 | 2262 | |
2263 | 2263 | /** |
2264 | 2264 | * Helper method to write information about some redirect. Various updates |
2265 | | - * can be necessary if redirects are resolved as identities SMW. The title |
2266 | | - * and namespace of the affected page and of its updated redirect target |
2267 | | - * are given. The target can be empty ('') to delete any redirect. Returns |
2268 | | - * the canonical ID that is now to be used for the subject. |
| 2265 | + * can be necessary if redirects are resolved as identities in SMW. The |
| 2266 | + * title and namespace of the affected page and of its updated redirect |
| 2267 | + * target are given. The target can be empty ('') to delete any redirect. |
| 2268 | + * Returns the canonical ID that is now to be used for the subject. |
2269 | 2269 | * |
2270 | 2270 | * This method does not change the ids of the affected pages, and thus it |
2271 | 2271 | * is not concerned with updates of the data that is currently stored for |
— | — | @@ -2275,7 +2275,7 @@ |
2276 | 2276 | * changes here. Keeping the redirect structure consistent is important, |
2277 | 2277 | * and errors in this code can go unnoticed for quite some time. |
2278 | 2278 | */ |
2279 | | - protected function updateRedirects( $subject_t, $subject_ns, $curtarget_t = '', $curtarget_ns = - 1 ) { |
| 2279 | + protected function updateRedirects( $subject_t, $subject_ns, $curtarget_t = '', $curtarget_ns = -1 ) { |
2280 | 2280 | global $smwgQEqualitySupport, $smwgEnableUpdateJobs; |
2281 | 2281 | $fname = 'SMW::updateRedirects'; |
2282 | 2282 | |
— | — | @@ -2284,7 +2284,7 @@ |
2285 | 2285 | /// NOTE: $sid can be 0 here; this is useful to know since it means that fewer table updates are needed |
2286 | 2286 | $new_tid = $curtarget_t ? ( $this->makeSMWPageID( $curtarget_t, $curtarget_ns, '', false ) ):0; // real id of new target, if given |
2287 | 2287 | $db = wfGetDB( DB_SLAVE ); |
2288 | | - |
| 2288 | + |
2289 | 2289 | $res = $db->select( array( 'smw_redi2' ), 'o_id', array( 's_title' => $subject_t, 's_namespace' => $subject_ns ), $fname, array( 'LIMIT' => 1 ) ); |
2290 | 2290 | $old_tid = ( $row = $db->fetchObject( $res ) ) ? $row->o_id:0; // real id of old target, if any |
2291 | 2291 | $db->freeResult( $res ); |
— | — | @@ -2296,7 +2296,7 @@ |
2297 | 2297 | |
2298 | 2298 | // *** Make relevant changes in property tables (don't write the new redirect yet) ***// |
2299 | 2299 | $db = wfGetDB( DB_MASTER ); // now we need to write something |
2300 | | - |
| 2300 | + |
2301 | 2301 | if ( ( $old_tid == 0 ) && ( $sid != 0 ) && ( $smwgQEqualitySupport != SMW_EQ_NONE ) ) { // new redirect |
2302 | 2302 | // $smwgQEqualitySupport requires us to change all tables' page references from $sid to $new_tid. |
2303 | 2303 | // Since references must not be 0, we don't have to do this is $sid == 0. |
— | — | @@ -2307,10 +2307,10 @@ |
2308 | 2308 | if ( $smwgEnableUpdateJobs && ( $smwgQEqualitySupport != SMW_EQ_NONE ) ) { |
2309 | 2309 | // entries that refer to old target may in fact refer to subject, but we don't know which: schedule affected pages for update |
2310 | 2310 | $jobs = array(); |
2311 | | - |
| 2311 | + |
2312 | 2312 | foreach ( self::getPropertyTables() as $proptable ) { |
2313 | 2313 | if ( $proptable->name == 'smw_redi2' ) continue; // can safely be skipped |
2314 | | - |
| 2314 | + |
2315 | 2315 | if ( $proptable->idsubject ) { |
2316 | 2316 | $from = $db->tableName( $proptable->name ) . ' INNER JOIN ' . $db->tableName( 'smw_ids' ) . ' ON s_id=smw_id'; |
2317 | 2317 | $select = 'DISTINCT smw_title AS title,smw_namespace AS namespace'; |
— | — | @@ -2318,25 +2318,25 @@ |
2319 | 2319 | $from = $db->tableName( $proptable->name ); |
2320 | 2320 | $select = 'DISTINCT s_title AS title,s_namespace AS namespace'; |
2321 | 2321 | } |
2322 | | - |
| 2322 | + |
2323 | 2323 | if ( ( $subject_ns == SMW_NS_PROPERTY ) && ( $proptable->fixedproperty == false ) ) { |
2324 | 2324 | $res = $db->select( $from, $select, array( 'p_id' => $old_tid ), $fname ); |
2325 | | - |
| 2325 | + |
2326 | 2326 | while ( $row = $db->fetchObject( $res ) ) { |
2327 | 2327 | $jobs[] = new SMWUpdateJob( Title::makeTitle( $row->namespace, $row->title ) ); |
2328 | 2328 | } |
2329 | | - |
| 2329 | + |
2330 | 2330 | $db->freeResult( $res ); |
2331 | 2331 | } |
2332 | | - |
| 2332 | + |
2333 | 2333 | foreach ( $proptable->objectfields as $fieldname => $type ) { |
2334 | 2334 | if ( $type == 'p' ) { |
2335 | 2335 | $res = $db->select( $from, $select, array( $fieldname => $old_tid ), $fname ); |
2336 | | - |
| 2336 | + |
2337 | 2337 | while ( $row = $db->fetchObject( $res ) ) { |
2338 | 2338 | $jobs[] = new SMWUpdateJob( Title::makeTitle( $row->namespace, $row->title ) ); |
2339 | 2339 | } |
2340 | | - |
| 2340 | + |
2341 | 2341 | $db->freeResult( $res ); |
2342 | 2342 | } |
2343 | 2343 | } |
— | — | @@ -2358,23 +2358,23 @@ |
2359 | 2359 | $db->update( 'smw_ids', array( 'smw_iw' => SMW_SQL2_SMWREDIIW ), array( 'smw_id' => $sid ), $fname ); |
2360 | 2360 | } |
2361 | 2361 | } |
2362 | | - |
| 2362 | + |
2363 | 2363 | $db->insert( 'smw_redi2', array( 's_title' => $subject_t, 's_namespace' => $subject_ns, 'o_id' => $new_tid ), $fname ); |
2364 | 2364 | $this->m_ids[" $subject_ns $subject_t C"] = $new_tid; // "iw" is empty here |
2365 | 2365 | } else { // delete old redirect |
2366 | 2366 | // This case implies $old_tid != 0 (or we would have new_tid == old_tid above). |
2367 | 2367 | // Therefore $subject had a redirect, and it must also have an ID. This shows that $sid != 0 here. |
2368 | 2368 | $this->m_ids[" $subject_ns $subject_t C"] = $sid; // "iw" is empty here |
2369 | | - |
| 2369 | + |
2370 | 2370 | if ( $smwgQEqualitySupport != SMW_EQ_NONE ) { // mark subject as non-redirect |
2371 | 2371 | $db->update( 'smw_ids', array( 'smw_iw' => '' ), array( 'smw_id' => $sid ), $fname ); |
2372 | 2372 | } |
2373 | 2373 | } |
2374 | | - |
| 2374 | + |
2375 | 2375 | // *** Flush some caches to be safe, though they are not essential in program runs with redirect updates ***// |
2376 | 2376 | unset( $this->m_semdata[$sid] ); unset( $this->m_semdata[$new_tid] ); unset( $this->m_semdata[$old_tid] ); |
2377 | 2377 | unset( $this->m_sdstate[$sid] ); unset( $this->m_sdstate[$new_tid] ); unset( $this->m_sdstate[$old_tid] ); |
2378 | | - |
| 2378 | + |
2379 | 2379 | return ( $new_tid == 0 ) ? $sid : $new_tid; |
2380 | 2380 | } |
2381 | 2381 | |
— | — | @@ -2401,12 +2401,12 @@ |
2402 | 2402 | * used in SMWDataValue::getSignature()! |
2403 | 2403 | * |
2404 | 2404 | * @todo Add a hook for registering additional or modifying given tables. |
2405 | | - * |
| 2405 | + * |
2406 | 2406 | * @return array of SMWSQLStore2Table |
2407 | 2407 | */ |
2408 | 2408 | public static function getPropertyTables() { |
2409 | 2409 | if ( count( self::$prop_tables ) > 0 ) return self::$prop_tables; // don't initialise twice |
2410 | | - |
| 2410 | + |
2411 | 2411 | self::$prop_tables['smw_rels2'] = new SMWSQLStore2Table( 'smw_rels2', |
2412 | 2412 | array( 'o_id' => 'p' ), |
2413 | 2413 | array( 'o_id' ) ); |