These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | use SMW\DataTypeRegistry; |
||
4 | use SMW\DIWikiPage; |
||
5 | use SMW\SQLStore\TableDefinition; |
||
6 | |||
7 | /** |
||
8 | * Class to provide all basic read methods for SMWSQLStore3. |
||
9 | * |
||
10 | * @author Markus Krötzsch |
||
11 | * @author Jeroen De Dauw |
||
12 | * @author Nischay Nahata |
||
13 | * |
||
14 | * @since 1.8 |
||
15 | * @ingroup SMWStore |
||
16 | */ |
||
17 | class SMWSQLStore3Readers { |
||
18 | |||
19 | /** |
||
20 | * The store used by this store reader |
||
21 | * |
||
22 | * @since 1.8 |
||
23 | * @var SMWSQLStore3 |
||
24 | */ |
||
25 | private $store; |
||
26 | |||
27 | /** |
||
28 | * >0 while getSemanticData runs, used to prevent nested calls from clearing the cache |
||
29 | * while another call runs and is about to fill it with data |
||
30 | * |
||
31 | * @var int |
||
32 | */ |
||
33 | private static $in_getSemanticData = 0; |
||
34 | |||
35 | 6 | public function __construct( SMWSQLStore3 $parentStore ) { |
|
36 | 6 | $this->store = $parentStore; |
|
37 | 6 | } |
|
38 | |||
39 | /** |
||
40 | * @see SMWStore::getSemanticData() |
||
41 | * @since 1.8 |
||
42 | * |
||
43 | * @param DIWikiPage $subject |
||
44 | * @param string[]|bool $filter |
||
45 | */ |
||
46 | 223 | public function getSemanticData( DIWikiPage $subject, $filter = false ) { |
|
47 | |||
48 | // *** Find out if this subject exists ***// |
||
49 | 223 | $sortKey = ''; |
|
50 | |||
51 | 223 | $sid = $this->store->smwIds->getSMWPageIDandSort( |
|
52 | 223 | $subject->getDBkey(), |
|
53 | 223 | $subject->getNamespace(), |
|
54 | 223 | $subject->getInterwiki(), |
|
55 | 223 | $subject->getSubobjectName(), |
|
56 | $sortKey, |
||
57 | 223 | true, |
|
58 | 223 | true |
|
59 | ); |
||
60 | |||
61 | // Ensures that a cached item to contain an expected sortKey when |
||
62 | // for example the ID was just created and the sortKey from the DB |
||
63 | // is empty otherwise the DB wins over the invoked sortKey |
||
64 | 223 | if ( !$sortKey ) { |
|
65 | 218 | $sortKey = $subject->getSortKey(); |
|
66 | } |
||
67 | |||
68 | 223 | $subject->setSortKey( $sortKey ); |
|
69 | |||
70 | 223 | if ( $sid == 0 ) { |
|
71 | // We consider redirects for getting $sid, |
||
72 | // so $sid == 0 also means "no redirects". |
||
73 | 218 | return new SMWSemanticData( $subject ); |
|
74 | } |
||
75 | |||
76 | 215 | $propertyTableHashes = $this->store->smwIds->getPropertyTableHashes( $sid ); |
|
77 | |||
78 | 215 | foreach ( $this->store->getPropertyTables() as $tid => $proptable ) { |
|
79 | 215 | if ( !array_key_exists( $proptable->getName(), $propertyTableHashes ) ) { |
|
80 | 215 | continue; |
|
81 | } |
||
82 | |||
83 | 205 | if ( $filter !== false ) { |
|
84 | 3 | $relevant = false; |
|
85 | 3 | foreach ( $filter as $typeId ) { |
|
86 | 3 | $diType = DataTypeRegistry::getInstance()->getDataItemId( $typeId ); |
|
87 | 3 | $relevant = $relevant || ( $proptable->getDiType() == $diType ); |
|
88 | 3 | if ( $relevant ) { |
|
89 | 3 | break; |
|
90 | } |
||
91 | } |
||
92 | 3 | if ( !$relevant ) { |
|
93 | 3 | continue; |
|
94 | } |
||
95 | } |
||
96 | |||
97 | 205 | $this->getSemanticDataFromTable( $sid, $subject, $proptable ); |
|
98 | } |
||
99 | |||
100 | // Note: the sortkey is always set but belongs to no property table, |
||
101 | // hence no entry in $this->store->m_sdstate[$sid] is made. |
||
102 | 215 | self::$in_getSemanticData++; |
|
103 | 215 | $this->initSemanticDataCache( $sid, $subject ); |
|
104 | 215 | $this->store->m_semdata[$sid]->addPropertyStubValue( '_SKEY', array( '', $sortKey ) ); |
|
105 | 215 | self::$in_getSemanticData--; |
|
106 | |||
107 | 215 | return $this->store->m_semdata[$sid]; |
|
108 | } |
||
109 | |||
110 | /** |
||
111 | * Helper method to make sure there is a cache entry for the data about |
||
112 | * the given subject with the given ID. |
||
113 | * |
||
114 | * @todo The management of this cache should be revisited. |
||
115 | * |
||
116 | * @since 1.8 |
||
117 | * |
||
118 | * @param int $subjectId |
||
119 | * @param DIWikiPage $subject |
||
120 | */ |
||
121 | 219 | private function initSemanticDataCache( $subjectId, DIWikiPage $subject ) { |
|
122 | |||
123 | // *** Prepare the cache ***// |
||
124 | 219 | if ( !array_key_exists( $subjectId, $this->store->m_semdata ) ) { // new cache entry |
|
125 | 120 | $this->store->m_semdata[$subjectId] = new SMWSql3StubSemanticData( $subject, $this->store, false ); |
|
126 | 120 | $this->store->m_sdstate[$subjectId] = array(); |
|
127 | } |
||
128 | |||
129 | // Issue #622 |
||
130 | // If a redirect was cached preceding this request and points to the same |
||
131 | // subject id ensure that in all cases the requested subject matches with |
||
132 | // the selected DB id |
||
133 | 219 | if ( $this->store->m_semdata[$subjectId]->getSubject()->getHash() !== $subject->getHash() ) { |
|
134 | 24 | $this->store->m_semdata[$subjectId] = new SMWSql3StubSemanticData( $subject, $this->store, false ); |
|
135 | 24 | $this->store->m_sdstate[$subjectId] = array(); |
|
136 | } |
||
137 | |||
138 | 219 | if ( ( count( $this->store->m_semdata ) > 20 ) && ( self::$in_getSemanticData == 1 ) ) { |
|
139 | // prevent memory leak; |
||
140 | // It is not so easy to find the sweet spot between cache size and performance gains (both memory and time), |
||
141 | // The value of 20 was chosen by profiling runtimes for large inline queries and heavily annotated pages. |
||
142 | // However, things might have changed in the meantime ... |
||
143 | 15 | $this->store->m_semdata = array( $subjectId => $this->store->m_semdata[$subjectId] ); |
|
144 | 15 | $this->store->m_sdstate = array( $subjectId => $this->store->m_sdstate[$subjectId] ); |
|
145 | } |
||
146 | 219 | } |
|
147 | |||
148 | /** |
||
149 | * Fetch the data storder about one subject in one particular table. |
||
150 | * |
||
151 | * @param integer $sid |
||
152 | * @param DIWikiPage $subject |
||
153 | * @param TableDefinition $proptable |
||
154 | * |
||
155 | * @return SMWSemanticData |
||
156 | */ |
||
157 | 209 | private function getSemanticDataFromTable( $sid, DIWikiPage $subject, TableDefinition $proptable ) { |
|
158 | // Do not clear the cache when called recursively. |
||
159 | 209 | self::$in_getSemanticData++; |
|
160 | |||
161 | 209 | $this->initSemanticDataCache( $sid, $subject ); |
|
162 | |||
163 | 209 | if ( array_key_exists( $proptable->getName(), $this->store->m_sdstate[$sid] ) ) { |
|
164 | 205 | self::$in_getSemanticData--; |
|
165 | 205 | return $this->store->m_semdata[$sid]; |
|
166 | } |
||
167 | |||
168 | // *** Read the data ***// |
||
169 | 101 | $data = $this->fetchSemanticData( $sid, $subject, $proptable ); |
|
170 | 101 | foreach ( $data as $d ) { |
|
171 | 51 | $this->store->m_semdata[$sid]->addPropertyStubValue( reset( $d ), end( $d ) ); |
|
172 | } |
||
173 | 101 | $this->store->m_sdstate[$sid][$proptable->getName()] = true; |
|
174 | |||
175 | 101 | self::$in_getSemanticData--; |
|
176 | 101 | return $this->store->m_semdata[$sid]; |
|
177 | } |
||
178 | |||
179 | /** |
||
180 | * @see SMWStore::getPropertyValues |
||
181 | * |
||
182 | * @todo Retrieving all sortkeys (values for _SKEY with $subject null) |
||
183 | * is not supported. An empty array will be given. |
||
184 | * |
||
185 | * @since 1.8 |
||
186 | * |
||
187 | * @param $subject mixed DIWikiPage or null |
||
188 | * @param $property SMWDIProperty |
||
189 | * @param $requestOptions SMWRequestOptions |
||
190 | * |
||
191 | * @return SMWDataItem[] |
||
192 | */ |
||
193 | 183 | public function getPropertyValues( $subject, SMWDIProperty $property, $requestOptions = null ) { |
|
194 | |||
195 | 183 | if ( $property->isInverse() ) { // inverses are working differently |
|
196 | 3 | $noninverse = new SMW\DIProperty( $property->getKey(), false ); |
|
197 | 3 | $result = $this->getPropertySubjects( $noninverse, $subject, $requestOptions ); |
|
198 | 183 | } elseif ( !is_null( $subject ) ) { // subject given, use semantic data cache |
|
199 | 183 | $sid = $this->store->smwIds->getSMWPageID( $subject->getDBkey(), |
|
200 | 183 | $subject->getNamespace(), $subject->getInterwiki(), |
|
201 | 183 | $subject->getSubobjectName(), true ); |
|
202 | 183 | if ( $sid == 0 ) { |
|
203 | 152 | $result = array(); |
|
204 | 159 | } elseif ( $property->getKey() == '_SKEY' ) { |
|
205 | 4 | $this->store->smwIds->getSMWPageIDandSort( $subject->getDBkey(), |
|
206 | 4 | $subject->getNamespace(), $subject->getInterwiki(), |
|
207 | 4 | $subject->getSubobjectName(), $sortKey, true ); |
|
208 | 4 | $sortKeyDi = new SMWDIBlob( $sortKey ); |
|
209 | 4 | $result = $this->store->applyRequestOptions( array( $sortKeyDi ), $requestOptions ); |
|
210 | } else { |
||
211 | 159 | $propTableId = $this->store->findPropertyTableID( $property ); |
|
212 | 159 | $proptables = $this->store->getPropertyTables(); |
|
213 | |||
214 | 159 | if ( !isset( $proptables[$propTableId] ) ) { |
|
215 | return array(); |
||
216 | } |
||
217 | |||
218 | 159 | $sd = $this->getSemanticDataFromTable( $sid, $subject, $proptables[$propTableId] ); |
|
219 | 183 | $result = $this->store->applyRequestOptions( $sd->getPropertyValues( $property ), $requestOptions ); |
|
220 | } |
||
221 | } else { // no subject given, get all values for the given property |
||
222 | 1 | $pid = $this->store->smwIds->getSMWPropertyID( $property ); |
|
223 | 1 | $tableid = $this->store->findPropertyTableID( $property ); |
|
224 | |||
225 | 1 | if ( ( $pid == 0 ) || ( $tableid === '' ) ) { |
|
226 | return array(); |
||
227 | } |
||
228 | |||
229 | 1 | $proptables = $this->store->getPropertyTables(); |
|
230 | 1 | $data = $this->fetchSemanticData( $pid, $property, $proptables[$tableid], false, $requestOptions ); |
|
231 | 1 | $result = array(); |
|
232 | 1 | $propertyTypeId = $property->findPropertyTypeID(); |
|
233 | 1 | $propertyDiId = DataTypeRegistry::getInstance()->getDataItemId( $propertyTypeId ); |
|
234 | |||
235 | 1 | foreach ( $data as $dbkeys ) { |
|
236 | try { |
||
237 | 1 | $diHandler = $this->store->getDataItemHandlerForDIType( $propertyDiId ); |
|
238 | 1 | $result[] = $diHandler->dataItemFromDBKeys( $dbkeys ); |
|
239 | 1 | } catch ( SMWDataItemException $e ) { |
|
240 | // maybe type assignment changed since data was stored; |
||
241 | // don't worry, but we can only drop the data here |
||
242 | } |
||
243 | } |
||
244 | } |
||
245 | |||
246 | |||
247 | 183 | return $result; |
|
248 | } |
||
249 | |||
250 | /** |
||
251 | * Helper function for reading all data for from a given property table |
||
252 | * (specified by an SMWSQLStore3Table object), based on certain |
||
253 | * restrictions. The function can filter data based on the subject (1) |
||
254 | * or on the property it belongs to (2) -- but one of those must be |
||
255 | * done. The Boolean $issubject is true for (1) and false for (2). |
||
256 | * |
||
257 | * In case (1), the first two parameters are taken to refer to a |
||
258 | * subject; in case (2) they are taken to refer to a property. In any |
||
259 | * case, the retrieval is limited to the specified $proptable. The |
||
260 | * parameters are an internal $id (of a subject or property), and an |
||
261 | * $object (being an DIWikiPage or SMWDIProperty). Moreover, when |
||
262 | * filtering by property, it is assumed that the given $proptable |
||
263 | * belongs to the property: if it is a table with fixed property, it |
||
264 | * will not be checked that this is the same property as the one that |
||
265 | * was given in $object. |
||
266 | * |
||
267 | * In case (1), the result in general is an array of pairs (arrays of |
||
268 | * size 2) consisting of a property key (string), and DB keys (array if |
||
269 | * many, string if one) from which a datvalue object for this value can |
||
270 | * be built. It is possible that some of the DB keys are based on |
||
271 | * internal objects; these will be represented by similar result arrays |
||
272 | * of (recursive calls of) fetchSemanticData(). |
||
273 | * |
||
274 | * In case (2), the result is simply an array of DB keys (array) |
||
275 | * without the property keys. Container objects will be encoded with |
||
276 | * nested arrays like in case (1). |
||
277 | * |
||
278 | * @todo Maybe share DB handler; asking for it seems to take quite some |
||
279 | * time and we do not want to change it in one call. |
||
280 | * |
||
281 | * @param integer $id |
||
282 | * @param SMWDataItem $object |
||
283 | * @param TableDefinition $propTable |
||
284 | * @param boolean $isSubject |
||
285 | * @param SMWRequestOptions $requestOptions |
||
286 | * |
||
287 | * @return array |
||
288 | */ |
||
289 | 102 | private function fetchSemanticData( $id, SMWDataItem $object = null, TableDefinition $propTable, $isSubject = true, SMWRequestOptions $requestOptions = null ) { |
|
290 | // stop if there is not enough data: |
||
291 | // properties always need to be given as object, |
||
292 | // subjects at least if !$proptable->idsubject |
||
293 | 102 | if ( ( $id == 0 ) || |
|
294 | 102 | ( is_null( $object ) && ( !$isSubject || !$propTable->usesIdSubject() ) ) ) { |
|
295 | return array(); |
||
296 | } |
||
297 | |||
298 | 102 | $result = array(); |
|
299 | 102 | $db = $this->store->getConnection(); |
|
300 | |||
301 | 102 | $diHandler = $this->store->getDataItemHandlerForDIType( $propTable->getDiType() ); |
|
302 | |||
303 | // *** First build $from, $select, and $where for the DB query ***// |
||
304 | 102 | $from = $db->tableName( $propTable->getName() ); // always use actual table |
|
305 | |||
306 | 102 | $select = ''; |
|
307 | 102 | $where = ''; |
|
308 | |||
309 | 102 | if ( $isSubject ) { // restrict subject, select property |
|
310 | 101 | $where .= ( $propTable->usesIdSubject() ) ? 's_id=' . $db->addQuotes( $id ) : |
|
311 | 26 | 's_title=' . $db->addQuotes( $object->getDBkey() ) . |
|
312 | 101 | ' AND s_namespace=' . $db->addQuotes( $object->getNamespace() ); |
|
313 | 101 | if ( !$propTable->isFixedPropertyTable() ) { // select property name |
|
314 | 66 | $from .= ' INNER JOIN ' . $db->tableName( SMWSql3SmwIds::TABLE_NAME ) . ' AS p ON p_id=p.smw_id'; |
|
315 | 101 | $select .= 'p.smw_title as prop'; |
|
316 | } // else: fixed property, no select needed |
||
317 | 1 | } elseif ( !$propTable->isFixedPropertyTable() ) { // restrict property only |
|
318 | 1 | $where .= 'p_id=' . $db->addQuotes( $id ); |
|
319 | } |
||
320 | |||
321 | 102 | $valuecount = 0; |
|
322 | // Don't use DISTINCT for value of one subject: |
||
323 | 102 | $usedistinct = !$isSubject; |
|
324 | |||
325 | 102 | $valueField = $diHandler->getIndexField(); |
|
326 | 102 | $labelField = $diHandler->getLabelField(); |
|
327 | 102 | $fields = $diHandler->getFetchFields(); |
|
328 | 102 | foreach ( $fields as $fieldname => $typeid ) { // select object column(s) |
|
329 | 102 | if ( $typeid == 'p' ) { // get data from ID table |
|
330 | 59 | $from .= ' INNER JOIN ' . $db->tableName( SMWSql3SmwIds::TABLE_NAME ) . " AS o$valuecount ON $fieldname=o$valuecount.smw_id"; |
|
331 | 59 | $select .= ( ( $select !== '' ) ? ',' : '' ) . |
|
332 | 59 | "$fieldname AS id$valuecount" . |
|
333 | 59 | ",o$valuecount.smw_title AS v$valuecount" . |
|
334 | 59 | ",o$valuecount.smw_namespace AS v" . ( $valuecount + 1 ) . |
|
335 | 59 | ",o$valuecount.smw_iw AS v" . ( $valuecount + 2 ) . |
|
336 | 59 | ",o$valuecount.smw_sortkey AS v" . ( $valuecount + 3 ) . |
|
337 | 59 | ",o$valuecount.smw_subobject AS v" . ( $valuecount + 4 ); |
|
338 | |||
339 | 59 | if ( $valueField == $fieldname ) { |
|
340 | 59 | $valueField = "o$valuecount.smw_sortkey"; |
|
341 | } |
||
342 | 59 | if ( $labelField == $fieldname ) { |
|
343 | 59 | $labelField = "o$valuecount.smw_sortkey"; |
|
344 | } |
||
345 | |||
346 | 59 | $valuecount += 4; |
|
347 | } else { |
||
348 | 96 | $select .= ( ( $select !== '' ) ? ',' : '' ) . |
|
349 | 96 | "$fieldname AS v$valuecount"; |
|
350 | } |
||
351 | |||
352 | 102 | $valuecount += 1; |
|
353 | } |
||
354 | |||
355 | 102 | if ( !$isSubject ) { // Apply sorting/string matching; only with given property |
|
356 | 1 | $where .= $this->store->getSQLConditions( $requestOptions, $valueField, $labelField, $where !== '' ); |
|
357 | } else { |
||
358 | 101 | $valueField = ''; |
|
359 | } |
||
360 | |||
361 | // *** Now execute the query and read the results ***// |
||
362 | 102 | $res = $db->select( $from, $select, $where, __METHOD__, |
|
363 | 102 | ( $usedistinct ? |
|
364 | 1 | $this->store->getSQLOptions( $requestOptions, $valueField ) + array( 'DISTINCT' ) : |
|
365 | 102 | $this->store->getSQLOptions( $requestOptions, $valueField ) |
|
366 | ) ); |
||
367 | |||
368 | 102 | foreach ( $res as $row ) { |
|
369 | |||
370 | 52 | $valueHash = ''; |
|
371 | |||
372 | 52 | if ( $isSubject ) { // use joined or predefined property name |
|
373 | 51 | $propertykey = $propTable->isFixedPropertyTable() ? $propTable->getFixedProperty() : $row->prop; |
|
374 | 51 | $valueHash = $propertykey; |
|
375 | } |
||
376 | |||
377 | // Use enclosing array only for results with many values: |
||
378 | 52 | if ( $valuecount > 1 ) { |
|
379 | 47 | $valuekeys = array(); |
|
380 | 47 | for ( $i = 0; $i < $valuecount; $i += 1 ) { // read the value fields from the current row |
|
381 | 47 | $fieldname = "v$i"; |
|
382 | 47 | $valuekeys[] = $row->$fieldname; |
|
383 | } |
||
384 | } else { |
||
385 | 51 | $valuekeys = $row->v0; |
|
386 | } |
||
387 | |||
388 | // #Issue 615 |
||
389 | // If the iw field contains a redirect marker then remove it |
||
390 | 52 | if ( isset( $valuekeys[2] ) && ( $valuekeys[2] === SMW_SQL3_SMWREDIIW || $valuekeys[2] === SMW_SQL3_SMWDELETEIW ) ) { |
|
391 | 5 | $valuekeys[2] = ''; |
|
392 | } |
||
393 | |||
394 | // The valueHash prevents from inserting duplicate entries of the same content |
||
395 | 52 | $valueHash = $valuecount > 1 ? md5( $valueHash . implode( '#', $valuekeys ) ) : md5( $valueHash . $valuekeys ); |
|
396 | |||
397 | // Filter out any accidentally retrieved internal things (interwiki starts with ":"): |
||
398 | 52 | if ( $valuecount < 3 || implode( '', $fields ) != 'p' || |
|
399 | 52 | $valuekeys[2] === '' || $valuekeys[2]{0} != ':' ) { |
|
400 | |||
401 | 52 | if ( isset( $result[$valueHash] ) ) { |
|
402 | wfDebugLog( 'smw', __METHOD__ . " Duplicate entry for {$propertykey} with " . ( is_array( $valuekeys ) ? implode( ',', $valuekeys ) : $valuekeys ) . "\n" ); |
||
403 | } |
||
404 | |||
405 | 52 | $result[$valueHash] = $isSubject ? array( $propertykey, $valuekeys ) : $valuekeys; |
|
406 | } |
||
407 | } |
||
408 | |||
409 | 102 | $db->freeResult( $res ); |
|
410 | |||
411 | 102 | return $result; |
|
412 | } |
||
413 | |||
414 | /** |
||
415 | * @see SMWStore::getPropertySubjects |
||
416 | * |
||
417 | * @todo This method cannot retrieve subjects for sortkeys, i.e., for |
||
418 | * property _SKEY. Only empty arrays will be returned there. |
||
419 | * |
||
420 | * @param SMWDIProperty $property |
||
421 | * @param SMWDataItem|null $value |
||
422 | * @param SMWRequestOptions|null $requestOptions |
||
423 | * |
||
424 | * @return array of DIWikiPage |
||
425 | */ |
||
426 | 129 | public function getPropertySubjects( SMWDIProperty $property, SMWDataItem $value = null, SMWRequestOptions $requestOptions = null ) { |
|
427 | /// TODO: should we share code with #ask query computation here? Just use queries? |
||
428 | |||
429 | 129 | if ( $property->isInverse() ) { // inverses are working differently |
|
430 | $noninverse = new SMW\DIProperty( $property->getKey(), false ); |
||
431 | $result = $this->getPropertyValues( $value, $noninverse, $requestOptions ); |
||
432 | return $result; |
||
433 | } |
||
434 | |||
435 | // #1222, Filter those where types don't match (e.g property = _txt |
||
436 | // and value = _wpg) |
||
437 | 129 | if ( $value !== null && DataTypeRegistry::getInstance()->getDataItemId( $property->findPropertyTypeID() ) !== $value->getDIType() ) { |
|
438 | 1 | return array(); |
|
439 | } |
||
440 | |||
441 | // First build $select, $from, and $where for the DB query |
||
442 | 129 | $where = $from = ''; |
|
0 ignored issues
–
show
|
|||
443 | 129 | $pid = $this->store->smwIds->getSMWPropertyID( $property ); |
|
444 | 129 | $tableid = $this->store->findPropertyTableID( $property ); |
|
445 | |||
446 | 129 | if ( ( $pid == 0 ) || ( $tableid === '' ) ) { |
|
447 | 118 | return array(); |
|
448 | } |
||
449 | |||
450 | 129 | $proptables = $this->store->getPropertyTables(); |
|
451 | 129 | $proptable = $proptables[$tableid]; |
|
452 | 129 | $db = $this->store->getConnection(); |
|
453 | |||
454 | 129 | if ( $proptable->usesIdSubject() ) { // join with ID table to get title data |
|
455 | 129 | $from = $db->tableName( SMWSql3SmwIds::TABLE_NAME ) . " INNER JOIN " . $db->tableName( $proptable->getName() ) . " AS t1 ON t1.s_id=smw_id"; |
|
456 | 129 | $select = 'smw_title, smw_namespace, smw_iw, smw_sortkey, smw_subobject'; |
|
457 | } else { // no join needed, title+namespace as given in proptable |
||
458 | 3 | $from = $db->tableName( $proptable->getName() ) . " AS t1"; |
|
459 | 3 | $select = 's_title AS smw_title, s_namespace AS smw_namespace, \'\' AS smw_iw, s_title AS smw_sortkey, \'\' AS smw_subobject'; |
|
460 | } |
||
461 | |||
462 | 129 | if ( !$proptable->isFixedPropertyTable() ) { |
|
463 | 125 | $where .= ( $where ? ' AND ' : '' ) . "t1.p_id=" . $db->addQuotes( $pid ); |
|
464 | } |
||
465 | |||
466 | 129 | $this->prepareValueQuery( $from, $where, $proptable, $value, 1 ); |
|
467 | |||
468 | // *** Now execute the query and read the results ***// |
||
469 | 129 | $result = array(); |
|
470 | |||
471 | 129 | if ( !$proptable->isFixedPropertyTable() ) { |
|
472 | 125 | if ( $where !== '' && strpos( SMW_SQL3_SMWIW_OUTDATED, $where ) === false ) { |
|
473 | 125 | $where .= " AND smw_iw!=" . $db->addQuotes( SMW_SQL3_SMWIW_OUTDATED ) . " AND smw_iw!=" . $db->addQuotes( SMW_SQL3_SMWDELETEIW ); |
|
474 | } else { |
||
475 | $where .= " smw_iw!=" . $db->addQuotes( SMW_SQL3_SMWIW_OUTDATED ) . " AND smw_iw!=" . $db->addQuotes( SMW_SQL3_SMWDELETEIW ); |
||
476 | } |
||
477 | } |
||
478 | |||
479 | 129 | $res = $db->select( $from, 'DISTINCT ' . $select, |
|
480 | 129 | $where . $this->store->getSQLConditions( $requestOptions, 'smw_sortkey', 'smw_sortkey', $where !== '' ), |
|
481 | 129 | __METHOD__, $this->store->getSQLOptions( $requestOptions, 'smw_sortkey' ) ); |
|
482 | |||
483 | 129 | $diHandler = $this->store->getDataItemHandlerForDIType( SMWDataItem::TYPE_WIKIPAGE ); |
|
484 | |||
485 | 129 | foreach ( $res as $row ) { |
|
486 | try { |
||
487 | 12 | if ( $row->smw_iw === '' || $row->smw_iw{0} != ':' ) { // filter special objects |
|
488 | 12 | $result[] = $diHandler->dataItemFromDBKeys( array_values( (array)$row ) ); |
|
489 | } |
||
490 | 12 | } catch ( SMWDataItemException $e ) { |
|
491 | // silently drop data, should be extremely rare and will usually fix itself at next edit |
||
492 | } |
||
493 | } |
||
494 | |||
495 | 129 | $db->freeResult( $res ); |
|
496 | |||
497 | 129 | return $result; |
|
498 | } |
||
499 | |||
500 | |||
501 | /** |
||
502 | * Helper function to compute from and where strings for a DB query so that |
||
503 | * only rows of the given value object match. The parameter $tableindex |
||
504 | * counts that tables used in the query to avoid duplicate table names. The |
||
505 | * parameter $proptable provides the SMWSQLStore3Table object that is |
||
506 | * queried. |
||
507 | * |
||
508 | * @todo Maybe do something about redirects. The old code was |
||
509 | * $oid = $this->store->smwIds->getSMWPageID($value->getDBkey(),$value->getNamespace(),$value->getInterwiki(),false); |
||
510 | * |
||
511 | * @note This method cannot handle DIContainer objects with sortkey |
||
512 | * properties correctly. This should never occur, but it would be good |
||
513 | * to fail in a more controlled way if it ever does. |
||
514 | * |
||
515 | * @param string $from |
||
516 | * @param string $where |
||
517 | * @param TableDefinition $propTable |
||
518 | * @param SMWDataItem $value |
||
519 | * @param integer $tableIndex |
||
520 | */ |
||
521 | 132 | private function prepareValueQuery( &$from, &$where, TableDefinition $propTable, $value, $tableIndex = 1 ) { |
|
522 | 132 | $db = $this->store->getConnection(); |
|
523 | |||
524 | 132 | if ( $value instanceof SMWDIContainer ) { // recursive handling of containers |
|
525 | $keys = array_keys( $propTable->getFields( $this->store ) ); |
||
526 | $joinfield = "t$tableIndex." . reset( $keys ); // this must be a type 'p' object |
||
527 | $proptables = $this->store->getPropertyTables(); |
||
528 | $semanticData = $value->getSemanticData(); |
||
529 | |||
530 | foreach ( $semanticData->getProperties() as $subproperty ) { |
||
531 | $tableid = $this->store->findPropertyTableID( $subproperty ); |
||
532 | $subproptable = $proptables[$tableid]; |
||
533 | |||
534 | foreach ( $semanticData->getPropertyValues( $subproperty ) as $subvalue ) { |
||
535 | $tableIndex++; |
||
536 | |||
537 | if ( $subproptable->usesIdSubject() ) { // simply add property table to check values |
||
538 | $from .= " INNER JOIN " . $db->tableName( $subproptable->getName() ) . " AS t$tableIndex ON t$tableIndex.s_id=$joinfield"; |
||
539 | } else { // exotic case with table that uses subject title+namespace in container object (should never happen in SMW core) |
||
540 | $from .= " INNER JOIN " . $db->tableName( SMWSql3SmwIds::TABLE_NAME ) . " AS ids$tableIndex ON ids$tableIndex.smw_id=$joinfield" . |
||
541 | " INNER JOIN " . $db->tableName( $subproptable->getName() ) . " AS t$tableIndex ON " . |
||
542 | "t$tableIndex.s_title=ids$tableIndex.smw_title AND t$tableIndex.s_namespace=ids$tableIndex.smw_namespace"; |
||
543 | } |
||
544 | |||
545 | if ( !$subproptable->isFixedPropertyTable() ) { // the ID we get should be !=0, so no point in filtering the converse |
||
546 | $where .= ( $where ? ' AND ' : '' ) . "t$tableIndex.p_id=" . $db->addQuotes( $this->store->smwIds->getSMWPropertyID( $subproperty ) ); |
||
547 | } |
||
548 | |||
549 | $this->prepareValueQuery( $from, $where, $subproptable, $subvalue, $tableIndex ); |
||
550 | } |
||
551 | } |
||
552 | 132 | } elseif ( !is_null( $value ) ) { // add conditions for given value |
|
553 | 131 | $diHandler = $this->store->getDataItemHandlerForDIType( $value->getDIType() ); |
|
554 | 131 | foreach ( $diHandler->getWhereConds( $value ) as $fieldname => $value ) { |
|
555 | 131 | $where .= ( $where ? ' AND ' : '' ) . "t$tableIndex.$fieldname=" . $db->addQuotes( $value ); |
|
556 | } |
||
557 | } |
||
558 | 132 | } |
|
559 | |||
560 | /** |
||
561 | * @see SMWStore::getAllPropertySubjects |
||
562 | * |
||
563 | * @param SMWDIProperty $property |
||
564 | * @param SMWRequestOptions $requestOptions |
||
565 | * |
||
566 | * @return array of DIWikiPage |
||
567 | */ |
||
568 | 125 | public function getAllPropertySubjects( SMWDIProperty $property, SMWRequestOptions $requestOptions = null ) { |
|
569 | 125 | $result = $this->getPropertySubjects( $property, null, $requestOptions ); |
|
570 | |||
571 | 125 | return $result; |
|
572 | } |
||
573 | |||
574 | /** |
||
575 | * @see Store::getProperties |
||
576 | * |
||
577 | * @param DIWikiPage $subject |
||
578 | * @param SMWRequestOptions|null $requestOptions |
||
579 | * |
||
580 | * @return SMWDataItem[] |
||
581 | */ |
||
582 | 1 | public function getProperties( DIWikiPage $subject, SMWRequestOptions $requestOptions = null ) { |
|
583 | 1 | $sid = $this->store->smwIds->getSMWPageID( |
|
584 | 1 | $subject->getDBkey(), |
|
585 | 1 | $subject->getNamespace(), |
|
586 | 1 | $subject->getInterwiki(), |
|
587 | 1 | $subject->getSubobjectName() |
|
588 | ); |
||
589 | |||
590 | 1 | if ( $sid == 0 ) { // no id, no page, no properties |
|
591 | 1 | return array(); |
|
592 | } |
||
593 | |||
594 | $db = $this->store->getConnection(); |
||
595 | $result = array(); |
||
596 | |||
597 | // potentially need to get more results, since options apply to union |
||
598 | if ( $requestOptions !== null ) { |
||
599 | $suboptions = clone $requestOptions; |
||
600 | $suboptions->limit = $requestOptions->limit + $requestOptions->offset; |
||
601 | $suboptions->offset = 0; |
||
602 | } else { |
||
603 | $suboptions = null; |
||
604 | } |
||
605 | |||
606 | foreach ( $this->store->getPropertyTables() as $propertyTable ) { |
||
607 | if ( $propertyTable->usesIdSubject() ) { |
||
608 | $where = 's_id=' . $db->addQuotes( $sid ); |
||
609 | } elseif ( $subject->getInterwiki() === '' ) { |
||
610 | $where = 's_title=' . $db->addQuotes( $subject->getDBkey() ) . ' AND s_namespace=' . $db->addQuotes( $subject->getNamespace() ); |
||
611 | } else { // subjects with non-emtpy interwiki cannot have properties |
||
612 | continue; |
||
613 | } |
||
614 | |||
615 | if ( $propertyTable->isFixedPropertyTable() ) { |
||
616 | // just check if subject occurs in table |
||
617 | $res = $db->select( |
||
618 | $propertyTable->getName(), |
||
619 | '*', |
||
620 | $where, |
||
621 | __METHOD__, |
||
622 | array( 'LIMIT' => 1 ) |
||
623 | ); |
||
624 | |||
625 | if ( $db->numRows( $res ) > 0 ) { |
||
626 | $result[] = new SMW\DIProperty( $propertyTable->getFixedProperty() ); |
||
627 | } |
||
628 | |||
629 | |||
630 | } else { |
||
631 | // select all properties |
||
632 | $from = $db->tableName( $propertyTable->getName() ); |
||
633 | |||
634 | $from .= " INNER JOIN " . $db->tableName( SMWSql3SmwIds::TABLE_NAME ) . " ON smw_id=p_id"; |
||
635 | $res = $db->select( $from, 'DISTINCT smw_title,smw_sortkey', |
||
636 | // (select sortkey since it might be used in ordering (needed by Postgres)) |
||
637 | $where . $this->store->getSQLConditions( $suboptions, 'smw_sortkey', 'smw_sortkey' ), |
||
638 | __METHOD__, $this->store->getSQLOptions( $suboptions, 'smw_sortkey' ) ); |
||
639 | foreach ( $res as $row ) { |
||
640 | $result[] = new SMW\DIProperty( $row->smw_title ); |
||
641 | } |
||
642 | } |
||
643 | |||
644 | $db->freeResult( $res ); |
||
645 | } |
||
646 | |||
647 | // apply options to overall result |
||
648 | $result = $this->store->applyRequestOptions( $result, $requestOptions ); |
||
649 | |||
650 | |||
651 | return $result; |
||
652 | } |
||
653 | |||
654 | /** |
||
655 | * Implementation of SMWStore::getInProperties(). This function is meant to |
||
656 | * be used for finding properties that link to wiki pages. |
||
657 | * |
||
658 | * @since 1.8 |
||
659 | * @see SMWStore::getInProperties |
||
660 | * |
||
661 | * @param SMWDataItem $value |
||
662 | * @param SMWRequestOptions|null $requestOptions |
||
663 | * |
||
664 | * @return array of SMWWikiPageValue |
||
665 | */ |
||
666 | 15 | public function getInProperties( SMWDataItem $value, SMWRequestOptions $requestOptions = null ) { |
|
667 | |||
668 | 15 | $db = $this->store->getConnection(); |
|
669 | 15 | $result = array(); |
|
670 | |||
671 | // Potentially need to get more results, since options apply to union. |
||
672 | 15 | if ( $requestOptions !== null ) { |
|
673 | 4 | $subOptions = clone $requestOptions; |
|
674 | 4 | $subOptions->limit = $requestOptions->limit + $requestOptions->offset; |
|
675 | 4 | $subOptions->offset = 0; |
|
676 | } else { |
||
677 | 11 | $subOptions = null; |
|
678 | } |
||
679 | |||
680 | 15 | $diType = $value->getDIType(); |
|
681 | |||
682 | 15 | foreach ( $this->store->getPropertyTables() as $proptable ) { |
|
683 | 15 | if ( $diType != $proptable->getDiType() ) { |
|
684 | 15 | continue; |
|
685 | } |
||
686 | |||
687 | 15 | $where = $from = ''; |
|
0 ignored issues
–
show
$from is not used, you could remove the assignment.
This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently. $myVar = 'Value';
$higher = false;
if (rand(1, 6) > 3) {
$higher = true;
} else {
$higher = false;
}
Both the
Loading history...
|
|||
688 | 15 | if ( !$proptable->isFixedPropertyTable() ) { // join ID table to get property titles |
|
689 | 15 | $from = $db->tableName( SMWSql3SmwIds::TABLE_NAME ) . " INNER JOIN " . $db->tableName( $proptable->getName() ) . " AS t1 ON t1.p_id=smw_id"; |
|
690 | 15 | $this->prepareValueQuery( $from, $where, $proptable, $value, 1 ); |
|
691 | |||
692 | 15 | $where .= " AND smw_iw!=" . $db->addQuotes( SMW_SQL3_SMWIW_OUTDATED ) . " AND smw_iw!=" . $db->addQuotes( SMW_SQL3_SMWDELETEIW ); |
|
693 | |||
694 | 15 | $res = $db->select( $from, 'DISTINCT smw_title,smw_sortkey,smw_iw', |
|
695 | // select sortkey since it might be used in ordering (needed by Postgres) |
||
696 | 15 | $where . $this->store->getSQLConditions( $subOptions, 'smw_sortkey', 'smw_sortkey', $where !== '' ), |
|
697 | 15 | __METHOD__, $this->store->getSQLOptions( $subOptions, 'smw_sortkey' ) ); |
|
698 | |||
699 | 15 | foreach ( $res as $row ) { |
|
700 | try { |
||
701 | 3 | $result[] = new SMW\DIProperty( $row->smw_title ); |
|
702 | 15 | } catch (SMWDataItemException $e) { |
|
703 | // has been observed to happen (empty property title); cause unclear; ignore this data |
||
704 | } |
||
705 | } |
||
706 | } else { |
||
707 | 15 | $from = $db->tableName( $proptable->getName() ) . " AS t1"; |
|
708 | 15 | $this->prepareValueQuery( $from, $where, $proptable, $value, 1 ); |
|
709 | 15 | $res = $db->select( $from, '*', $where, __METHOD__, array( 'LIMIT' => 1 ) ); |
|
710 | |||
711 | 15 | if ( $db->numRows( $res ) > 0 ) { |
|
712 | 8 | $result[] = new SMW\DIProperty( $proptable->getFixedProperty() ); |
|
713 | } |
||
714 | } |
||
715 | 15 | $db->freeResult( $res ); |
|
716 | } |
||
717 | |||
718 | 15 | $result = $this->store->applyRequestOptions( $result, $requestOptions ); // apply options to overall result |
|
719 | |||
720 | 15 | return $result; |
|
721 | } |
||
722 | |||
723 | } |
||
724 |
This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.
Both the
$myVar
assignment in line 1 and the$higher
assignment in line 2 are dead. The first because$myVar
is never used and the second because$higher
is always overwritten for every possible time line.