Index: trunk/extensions/SemanticMediaWiki/includes/SMW_QueryProcessor.php |
— | — | @@ -217,8 +217,11 @@ |
218 | 218 | $this->m_label = ''; |
219 | 219 | $this->m_curstring = $querystring; |
220 | 220 | $this->m_sepstack = array(); |
221 | | - $setNS = true; |
| 221 | + $setNS = false; |
222 | 222 | $result = $this->getSubqueryDescription($setNS, $this->m_label); |
| 223 | + if (!$setNS) { // add default namespaces if applicable |
| 224 | + $result = $this->addDescription($result, $this->m_defaultns); |
| 225 | + } |
223 | 226 | wfProfileOut('SMWQueryParser::getQueryDescription (SMW)'); |
224 | 227 | return $result; |
225 | 228 | } |
— | — | @@ -252,7 +255,7 @@ |
253 | 256 | * "<q>...</q>". Recursively calls similar methods and returns NULL upon error. |
254 | 257 | * |
255 | 258 | * The call-by-ref parameter $setNS is a boolean. Its input specifies whether |
256 | | - * the query should set the current default namespace if no namespace restricitons |
| 259 | + * the query should set the current default namespace if no namespace restrictions |
257 | 260 | * were given. If false, the calling super-query is happy to set the required |
258 | 261 | * NS-restrictions by itself if needed. Otherwise the subquery has to impose the defaults. |
259 | 262 | * This is so, since outermost queries and subqueries of disjunctions will have to set |
— | — | @@ -380,8 +383,8 @@ |
381 | 384 | */ |
382 | 385 | protected function getLinkDescription(&$setNS, &$label) { |
383 | 386 | // This method is called when we encountered an opening '[['. The following |
384 | | - // block could be a Category-statement, fixed object, relation or attribute |
385 | | - // statements, or according print statements. |
| 387 | + // block could be a Category-statement, fixed object, property statements, |
| 388 | + // or according print statements. |
386 | 389 | $chunk = $this->readChunk(); |
387 | 390 | if ($chunk == $this->m_categoryprefix) { // category statement |
388 | 391 | return $this->getCategoryDescription($setNS, $label); |
Index: trunk/extensions/SemanticMediaWiki/includes/storage/SMW_SQLStore.php |
— | — | @@ -1220,19 +1220,30 @@ |
1221 | 1221 | * Make a (temporary) table that contains the lower closure of the given category |
1222 | 1222 | * wrt. the category table. |
1223 | 1223 | */ |
1224 | | - protected function getCategoryTable($catname, &$db) { |
| 1224 | + protected function getCategoryTable($cats, &$db) { |
1225 | 1225 | wfProfileIn("SMWSQLStore::getCategoryTable (SMW)"); |
1226 | 1226 | global $wgDBname, $smwgQSubcategoryDepth; |
1227 | 1227 | |
| 1228 | + $sqlvalues = ''; |
| 1229 | + $hashkey = ''; |
| 1230 | + foreach ($cats as $cat) { |
| 1231 | + if ($sqlvalues != '') { |
| 1232 | + $sqlvalues .= ', '; |
| 1233 | + } |
| 1234 | + $sqlvalues .= '(' . $db->addQuotes($cat->getDBKey()) . ')'; |
| 1235 | + $hashkey .= ']' . $cat->getDBKey(); |
| 1236 | + } |
| 1237 | + |
1228 | 1238 | $tablename = 'cats' . SMWSQLStore::$m_tablenum++; |
1229 | 1239 | $this->m_usedtables[] = $tablename; |
1230 | 1240 | $db->query( 'CREATE TEMPORARY TABLE ' . $tablename . |
1231 | 1241 | '( title VARCHAR(255) NOT NULL ) |
1232 | 1242 | TYPE=MEMORY', 'SMW::getCategoryTable' ); |
1233 | | - if (array_key_exists($catname, SMWSQLStore::$m_categorytables)) { // just copy known result |
| 1243 | + $db->query( 'ALTER TABLE ' . $tablename . ' ADD PRIMARY KEY ( title )' ); |
| 1244 | + if (array_key_exists($hashkey, SMWSQLStore::$m_categorytables)) { // just copy known result |
1234 | 1245 | $db->query("INSERT INTO $tablename (title) SELECT " . |
1235 | | - SMWSQLStore::$m_categorytables[$catname] . |
1236 | | - '.title FROM ' . SMWSQLStore::$m_categorytables[$catname], |
| 1246 | + SMWSQLStore::$m_categorytables[$hashkey] . |
| 1247 | + '.title FROM ' . SMWSQLStore::$m_categorytables[$hashkey], |
1237 | 1248 | 'SMW::getCategoryTable'); |
1238 | 1249 | wfProfileOut("SMWSQLStore::getCategoryTable (SMW)"); |
1239 | 1250 | return $tablename; |
— | — | @@ -1250,8 +1261,8 @@ |
1251 | 1262 | |
1252 | 1263 | $pagetable = $db->tableName('page'); |
1253 | 1264 | $cltable = $db->tableName('categorylinks'); |
1254 | | - $db->query("INSERT INTO $tablename (title) VALUES (" . $db->addQuotes($catname) . ')', 'SMW::getCategoryTable'); |
1255 | | - $db->query("INSERT INTO $tmpnew (title) VALUES (" . $db->addQuotes($catname) . ')', 'SMW::getCategoryTable'); |
| 1265 | + $db->query("INSERT INTO $tablename (title) VALUES " . $sqlvalues, 'SMW::getCategoryTable'); |
| 1266 | + $db->query("INSERT INTO $tmpnew (title) VALUES " . $sqlvalues, 'SMW::getCategoryTable'); |
1256 | 1267 | |
1257 | 1268 | /// TODO: avoid duplicate results? |
1258 | 1269 | for ($i=0; $i<$smwgQSubcategoryDepth; $i++) { |
— | — | @@ -1260,18 +1271,18 @@ |
1261 | 1272 | $cltable.cl_to=$tmpnew.title AND |
1262 | 1273 | $pagetable.page_namespace=" . NS_CATEGORY . " AND |
1263 | 1274 | $pagetable.page_id=$cltable.cl_from", 'SMW::getCategoryTable'); |
| 1275 | + $db->query("INSERT IGNORE INTO $tablename (title) SELECT $tmpres.title |
| 1276 | + FROM $tmpres", 'SMW::getCategoryTable'); |
1264 | 1277 | if ($db->affectedRows() == 0) { // no change, exit loop |
1265 | 1278 | continue; |
1266 | 1279 | } |
1267 | | - $db->query("INSERT INTO $tablename (title) SELECT $tmpres.title |
1268 | | - FROM $tmpres", 'SMW::getCategoryTable'); |
1269 | 1280 | $db->query('TRUNCATE TABLE ' . $tmpnew, 'SMW::getCategoryTable'); // empty "new" table |
1270 | 1281 | $tmpname = $tmpnew; |
1271 | 1282 | $tmpnew = $tmpres; |
1272 | 1283 | $tmpres = $tmpname; |
1273 | 1284 | } |
1274 | 1285 | |
1275 | | - SMWSQLStore::$m_categorytables[$catname] = $tablename; |
| 1286 | + SMWSQLStore::$m_categorytables[$hashkey] = $tablename; |
1276 | 1287 | $db->query('DROP TABLE smw_newcats', 'SMW::getCategoryTable'); |
1277 | 1288 | $db->query('DROP TABLE smw_rescats', 'SMW::getCategoryTable'); |
1278 | 1289 | wfProfileOut("SMWSQLStore::getCategoryTable (SMW)"); |
— | — | @@ -1291,6 +1302,7 @@ |
1292 | 1303 | $db->query( 'CREATE TEMPORARY TABLE ' . $tablename . |
1293 | 1304 | '( title VARCHAR(255) NOT NULL ) |
1294 | 1305 | TYPE=MEMORY', 'SMW::getPropertyTable' ); |
| 1306 | + $db->query( 'ALTER TABLE ' . $tablename . ' ADD PRIMARY KEY ( title )' ); |
1295 | 1307 | if (array_key_exists($propname, SMWSQLStore::$m_propertytables)) { // just copy known result |
1296 | 1308 | $db->query("INSERT INTO $tablename (title) SELECT " . |
1297 | 1309 | SMWSQLStore::$m_propertytables[$propname] . |
— | — | @@ -1322,8 +1334,11 @@ |
1323 | 1335 | if ($db->affectedRows() == 0) { // no change, exit loop |
1324 | 1336 | continue; |
1325 | 1337 | } |
1326 | | - $db->query("INSERT INTO $tablename (title) SELECT $tmpres.title |
| 1338 | + $db->query("INSERT IGNORE INTO $tablename (title) SELECT $tmpres.title |
1327 | 1339 | FROM $tmpres", 'SMW::getCategoryTable'); |
| 1340 | + if ($db->affectedRows() == 0) { // no change, exit loop |
| 1341 | + continue; |
| 1342 | + } |
1328 | 1343 | $db->query('TRUNCATE TABLE ' . $tmpnew, 'SMW::getPropertyTable'); // empty "new" table |
1329 | 1344 | $tmpname = $tmpnew; |
1330 | 1345 | $tmpnew = $tmpres; |
— | — | @@ -1531,11 +1546,16 @@ |
1532 | 1547 | if ($table = $this->addJoin('CATS', $from, $db, $curtables, $nary_pos)) { |
1533 | 1548 | global $smwgQSubcategoryDepth; |
1534 | 1549 | if ($smwgQSubcategoryDepth > 0) { |
1535 | | - $ct = $this->getCategoryTable($description->getCategory()->getDBKey(), $db); |
| 1550 | + $ct = $this->getCategoryTable($description->getCategories(), $db); |
1536 | 1551 | $from = '`' . $ct . '`, ' . $from; |
1537 | 1552 | $where = "$ct.title=" . $table . '.cl_to'; |
1538 | 1553 | } else { |
1539 | | - $where .= $table . '.cl_to=' . $db->addQuotes($description->getCategory()->getDBKey()); |
| 1554 | + foreach ($description->getCategories() as $cat) { |
| 1555 | + if ($subwhere != '') { |
| 1556 | + $subwhere .= ' OR '; |
| 1557 | + } |
| 1558 | + $subwhere .= '(' . $table . '.cl_to=' . $db->addQuotes($description->getCategories()->getDBKey()) . ')'; |
| 1559 | + } |
1540 | 1560 | } |
1541 | 1561 | } |
1542 | 1562 | } elseif ($description instanceof SMWNamespaceDescription) { |
Index: trunk/extensions/SemanticMediaWiki/includes/storage/SMW_Description.php |
— | — | @@ -229,32 +229,72 @@ |
230 | 230 | } |
231 | 231 | |
232 | 232 | /** |
233 | | - * Description of a single class, i.e. a wiki category. |
234 | | - * Corresponds to atomic concepts in OWL and to classes in RDF. |
| 233 | + * Description of a single class, i.e. a wiki category, or of a disjunction |
| 234 | + * of such classes. Corresponds to (disjunctions of) atomic concepts in OWL and |
| 235 | + * to (unions of) classes in RDF. |
235 | 236 | */ |
236 | 237 | class SMWClassDescription extends SMWDescription { |
237 | | - protected $m_title; |
| 238 | + protected $m_titles; |
238 | 239 | |
239 | | - public function SMWClassDescription(Title $category) { |
240 | | - $this->m_title = $category; |
| 240 | + public function SMWClassDescription($content) { |
| 241 | + if ($content instanceof Title) { |
| 242 | + $this->m_titles = array($content); |
| 243 | + } elseif (is_array($content)) { |
| 244 | + $this->m_titles = $content; |
| 245 | + } |
241 | 246 | } |
242 | 247 | |
243 | | - public function getCategory() { |
244 | | - return $this->m_title; |
| 248 | + public function addDescription(SMWClassDescription $description) { |
| 249 | + $this->m_titles = array_merge($this->m_titles, $description->getCategories()); |
245 | 250 | } |
246 | 251 | |
| 252 | + public function getCategories() { |
| 253 | + return $this->m_titles; |
| 254 | + } |
| 255 | + |
247 | 256 | public function getQueryString() { |
248 | | - if ($this->m_title !== NULL) { |
249 | | - return '[[' . $this->m_title->getPrefixedText() . ']]'; |
250 | | - } else { |
251 | | - return ''; |
| 257 | + $first = true; |
| 258 | + foreach ($this->m_titles as $cat) { |
| 259 | + if ($first) { |
| 260 | + $result = '[[' . $cat->getPrefixedText(); |
| 261 | + $first = false; |
| 262 | + } else { |
| 263 | + $result .= '||' . $cat->getText(); |
| 264 | + } |
252 | 265 | } |
| 266 | + return $result . ']]'; |
253 | 267 | } |
254 | 268 | |
255 | 269 | public function isSingleton() { |
256 | 270 | return false; |
257 | 271 | } |
258 | 272 | |
| 273 | + public function getSize() { |
| 274 | + global $smwgQSubcategoryDepth; |
| 275 | + if ($smwgQSubcategoryDepth > 0) { |
| 276 | + return 1; // disj. of cats should not cause much effort if we compute cat-hierarchies anyway! |
| 277 | + } else { |
| 278 | + return count($this->m_titles); |
| 279 | + } |
| 280 | + } |
| 281 | + |
| 282 | + public function prune(&$maxsize, &$maxdepth, &$log) { |
| 283 | + if ($maxsize >= $this->getSize()) { |
| 284 | + $maxsize = $maxsize - $this->getSize(); |
| 285 | + return $this; |
| 286 | + } elseif ( $maxsize <= 0 ) { |
| 287 | + $log[] = $this->getQueryString(); |
| 288 | + $result = new SMWThingDescription(); |
| 289 | + } else { |
| 290 | + $result = new SMWClassDescription(array_slice($this->m_titles, 0, $maxsize)); |
| 291 | + $rest = new SMWClassDescription(array_slice($this->m_titles, $maxsize)); |
| 292 | + $log[] = $rest->getQueryString(); |
| 293 | + $maxsize = 0; |
| 294 | + } |
| 295 | + $result->setPrintRequests($this->getPrintRequests()); |
| 296 | + return $result; |
| 297 | + } |
| 298 | + |
259 | 299 | } |
260 | 300 | |
261 | 301 | /** |
— | — | @@ -352,8 +392,8 @@ |
353 | 393 | /** |
354 | 394 | * Description of an ordered list of SMWDescription objects, used as |
355 | 395 | * values for some n-ary property. NULL values are to be used for |
356 | | - * Corresponds to the built-in support for n-ary properties, i.e. |
357 | | - * can be viewed as a macro in OWL and RDF. |
| 396 | + * unspecifed values. Corresponds to the built-in support for n-ary |
| 397 | + * properties, i.e. can be viewed as a macro in OWL and RDF. |
358 | 398 | */ |
359 | 399 | class SMWValueList extends SMWDescription { |
360 | 400 | protected $m_descriptions; |
— | — | @@ -556,6 +596,8 @@ |
557 | 597 | */ |
558 | 598 | class SMWDisjunction extends SMWDescription { |
559 | 599 | protected $m_descriptions; |
| 600 | + protected $m_classdesc = NULL; // contains a single class description if any such disjunct was given; |
| 601 | + // disjunctive classes are aggregated therein |
560 | 602 | protected $m_true = false; // used if disjunction is trivially true already |
561 | 603 | |
562 | 604 | public function SMWDisjunction($descriptions = array()) { |
— | — | @@ -572,9 +614,20 @@ |
573 | 615 | if ($description instanceof SMWThingDescription) { |
574 | 616 | $this->m_true = true; |
575 | 617 | $this->m_descriptions = array(); // no conditions any more |
| 618 | + $this->m_catdesc = NULL; |
576 | 619 | } |
577 | 620 | if (!$this->m_true) { |
578 | | - $this->m_descriptions[] = $description; |
| 621 | + if ($description instanceof SMWClassDescription) { |
| 622 | + if ($this->m_classdesc === NULL) { // first class description |
| 623 | + $this->m_classdesc = $description; |
| 624 | + $this->m_descriptions[] = $description; |
| 625 | + } else { |
| 626 | + $this->m_classdesc->addDescription($description); |
| 627 | + } |
| 628 | + } else { |
| 629 | + $this->m_descriptions[] = $description; |
| 630 | + } |
| 631 | + |
579 | 632 | } |
580 | 633 | } |
581 | 634 | |
— | — | @@ -675,7 +728,7 @@ |
676 | 729 | } |
677 | 730 | |
678 | 731 | public function getQueryString() { |
679 | | - return '[[' . $this->m_property->getText() . ':=' . $this->m_description->getQueryString() . ']]'; |
| 732 | + return '[[' . $this->m_property->getText() . '::' . $this->m_description->getQueryString() . ']]'; |
680 | 733 | } |
681 | 734 | |
682 | 735 | public function isSingleton() { |