r35800 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r35799‎ | r35800 | r35801 >
Date:16:25, 3 June 2008
Author:mkroetzsch
Status:old
Tags:
Comment:
Further progress in new storage implementation: querying now almost complete (hierarchies not supported yet),
much more efficient, full support for disjunctions (if enabled), full equality support at almost no cost.
Modified paths:
  • /trunk/extensions/SemanticMediaWiki/includes/storage/SMW_SQLStore2.php (modified) (history)
  • /trunk/extensions/SemanticMediaWiki/includes/storage/SMW_SQLStore2_Queries.php (modified) (history)

Diff [purge]

Index: trunk/extensions/SemanticMediaWiki/includes/storage/SMW_SQLStore2_Queries.php
@@ -61,171 +61,166 @@
6262 /**
6363 * The new SQL store's implementation of query answering.
6464 *
65 - * TODO: we now have sorting even for subquery conditions. Does this work? Is it slow/problematic?
66 - * NOTE: we do not support category wildcards, as they have no useful semantics in OWL/RDFS/LP/whatever
 65+ * NOTE: we do not support category wildcards as they have no useful semantics in OWL/RDFS/LP/Whatever
6766 */
6867 public function getQueryResult(SMWQuery $query) {
6968 global $smwgQSortingSupport;
70 - $prs = $query->getDescription()->getPrintrequests(); // ignore print requests at deeper levels
7169 if ($query->querymode == SMWQuery::MODE_NONE) { // don't query, but return something to printer
72 - $result = new SMWQueryResult($prs, $query, false);
 70+ $result = new SMWQueryResult($query->getDescription()->getPrintrequests(), $query, false);
7371 return $result;
7472 }
 73+ $this->m_queries = array();
 74+ $this->m_querylog = array();
 75+ SMWSQLStore2Query::$qnum = 0;
7576 $this->m_sortkeys = $query->sortkeys;
76 -
 77+ // manually make final root query (to retrieve namespace,title):
 78+ $rootid = SMWSQLStore2Query::$qnum;
 79+ $qobj = new SMWSQLStore2Query();
 80+ $qobj->jointable = 'smw_ids';
 81+ $qobj->joinfield = "$qobj->alias.smw_id";
 82+ // build query dependency tree:
7783 $qid = $this->compileQueries($query->getDescription());
78 - $sql_options = array( 'LIMIT' => $query->getLimit() + 1, 'OFFSET' => $query->getOffset() );
79 - $this->applyOrderConditions($query,$qid,$sql_options);
80 - $qobj = new SMWSQLStore2Query();
81 - $qobj->components = array($qid => 'ids.smw_id');
82 - $this->executeQueries($qobj);
83 -
84 - // debug:
85 - $result = ' ' . str_replace('[','[',$query->getDescription()->getQueryString()) . "\n\n";
86 - $result .= 'SELECT DISTINCT ids.smw_title,ids.smw_namespace FROM smw_ids AS ids' . $qobj->from . (($qobj->where=='')?'':' WHERE ') . $qobj->where . ";";
87 - foreach ($this->m_querylog as $table => $log) {
88 - $result .= "\n\n<b>Temporary table $table</b>";
89 - foreach ($log as $q) {
90 - $result .= "\n\n$q";
91 - }
 84+ if ($qid >= 0) { // append to root
 85+ $qobj->components = array($qid => "$qobj->alias.smw_id");
 86+ $qobj->sortfields = $this->m_queries[$qid]->sortfields;
9287 }
 88+ $this->m_queries[$rootid] = $qobj;
9389
94 - $res = $this->m_dbs->select($this->m_dbs->tableName('smw_ids') . ' AS ids' . $qobj->from, 'DISTINCT ids.smw_title as t,ids.smw_namespace as ns', $qobj->where, 'SMW::getQueryResult', $sql_options);
95 -
96 - // debug:
97 - while ($row = $this->m_dbs->fetchObject($res)) {
98 - $result .= "\n\n$row->t ($row->ns)";
 90+ $this->applyOrderConditions($query,$rootid); // may extend query if needed for sorting
 91+ $this->executeQueries($this->m_queries[$rootid]); // execute query tree, resolve all dependencies
 92+ /// TODO: the above needs to know whether we are in debug mode or not
 93+ switch ($query->querymode) {
 94+ case SMWQuery::MODE_DEBUG:
 95+ $result = $this->getDebugQueryResult($query,$rootid);
 96+ break;
 97+ case SMWQuery::MODE_COUNT:
 98+ $result = $this->getCountQueryResult($query,$rootid);
 99+ break;
 100+ default:
 101+ $result = $this->getInstanceQueryResult($query,$rootid);
 102+ break;
99103 }
100 - $count=0;
101 -// $result = new SMWQueryResult($prs, $query, ($count > $query->getLimit()) );
102 -
103104 // finally, free temporary tables
104105 foreach ($this->m_querylog as $table => $log) {
105106 $this->m_dbs->query("DROP TEMPORARY TABLE $table", 'SMW::getQueryResult');
106107 }
107 -
108108 return $result;
 109+ }
109110
110 -
111 - /// Old code below, unused now
112 -
113 - // Build main query
114 - $this->m_usedtables = array();
115 - $this->m_sortkeys = $query->sortkeys;
116 - $this->m_sortfields = array();
117 - foreach ($this->m_sortkeys as $key => $order) {
118 - $this->m_sortfields[$key] = false; // no field found yet
 111+ /**
 112+ * Using a preprocessed internal query description referenced by $rootid, compute
 113+ * the proper debug output for the given query.
 114+ */
 115+ protected function getDebugQueryResult($query,$rootid) {
 116+ $qobj = $this->m_queries[$rootid];
 117+ $sql_options = $this->getSQLOptions($query,$rootid);
 118+ list( $startOpts, $useIndex, $tailOpts ) = $this->m_dbs->makeSelectOptions( $sql_options );
 119+ $result = '<div style="border: 1px dotted black; background: #A1FB00; padding: 20px; ">' .
 120+ '<b>Generated Wiki-Query</b><br />' .
 121+ str_replace('[', '&#x005B;', $query->getDescription()->getQueryString()) . '<br />' .
 122+ '<b>Query-Size: </b>' . $query->getDescription()->getSize() . '<br />' .
 123+ '<b>Query-Depth: </b>' . $query->getDescription()->getDepth() . '<br />';
 124+ if ($qobj->joinfield !== '') {
 125+ $result .= '<b>SQL query</b><br />' .
 126+ "SELECT DISTINCT $qobj->alias.smw_title AS t,$qobj->alias.smw_namespace AS ns FROM " .
 127+ "$qobj->jointable AS $qobj->alias" . $qobj->from . (($qobj->where=='')?'':' WHERE ') .
 128+ $qobj->where . "$tailOpts LIMIT " . $sql_options['LIMIT'] . ' OFFSET ' .
 129+ $sql_options['OFFSET'] . ';';
 130+ } else {
 131+ $result .= '<b>Empty result, no SQL query created.</b>';
119132 }
 133+ $errors = '';
 134+ foreach ($query->getErrors() as $error) {
 135+ $errors .= $error . '<br />';
 136+ }
 137+ $result .= ($errors)?"<br /><b>Errors and warnings:</b><br />$errors":'<br /><b>No errors or warnings.</b>';
 138+ $auxtables = '';
 139+ foreach ($this->m_querylog as $table => $log) {
 140+ $auxtables .= "\n\n<b>Temporary table $table</b>";
 141+ foreach ($log as $q) {
 142+ $auxtables .= "\n\n$q";
 143+ }
 144+ }
 145+ $result .= ($auxtables)?"<br /><b>Auxilliary tables used:</b><br />$auxtables":'<br /><b>No auxilliary tables used.</b>';
 146+ $result .= '</div>';
 147+ return $result;
 148+ }
120149
121 - $pagetable = $db->tableName('page');
122 - $from = $pagetable;
123 - $where = '';
124 - $curtables = array('PAGE' => $from);
125 - $this->createSQLQuery($query->getDescription(), $from, $where, $db, $curtables);
126 -
127 - // Prepare SQL options
128 - $sql_options = array();
129 - $sql_options['LIMIT'] = $query->getLimit() + 1;
130 - $sql_options['OFFSET'] = $query->getOffset();
131 - if ( $smwgQSortingSupport ) {
132 -
 150+ /**
 151+ * Using a preprocessed internal query description referenced by $rootid, compute
 152+ * the proper counting output for the given query.
 153+ */
 154+ protected function getCountQueryResult($query,$rootid) {
 155+ $qobj = $this->m_queries[$rootid];
 156+ if ($qobj->joinfield === '') { // empty result, no query needed
 157+ return 0;
133158 }
 159+ $sql_options = array( 'LIMIT' => $query->getLimit() + 1, 'OFFSET' => $query->getOffset() );
 160+ $res = $this->m_dbs->select($this->m_dbs->tableName($qobj->jointable) . " AS $qobj->alias" . $qobj->from, "COUNT(DISTINCT $qobj->alias.smw_id) AS count", $qobj->where, 'SMW::getQueryResult', $sql_options);
 161+ $row = $this->m_dbs->fetchObject($res);
 162+ $count = $row->count;
 163+ $this->m_dbs->freeResult($res);
 164+ return $count;
 165+ }
134166
135 - // Execute query and format result as array
136 - if ($query->querymode == SMWQuery::MODE_COUNT) {
137 - $res = $db->select($from,
138 - "COUNT(DISTINCT $pagetable.page_id) AS count",
139 - $where,
140 - 'SMW::getQueryResult',
141 - $sql_options );
142 - $row = $db->fetchObject($res);
143 - $count = $row->count;
144 - $db->freeResult($res);
145 - wfProfileOut('SMWSQLStore2::getQueryResult (SMW)');
146 - return $count;
147 - // TODO: report query errors?
148 - } elseif ($query->querymode == SMWQuery::MODE_DEBUG) { /// TODO: internationalise
149 - list( $startOpts, $useIndex, $tailOpts ) = $db->makeSelectOptions( $sql_options );
150 - $result = '<div style="border: 1px dotted black; background: #A1FB00; padding: 20px; ">' .
151 - '<b>Generated Wiki-Query</b><br />' .
152 - str_replace('[', '&#x005B;', $query->getDescription()->getQueryString()) . '<br />' .
153 - '<b>Query-Size: </b>' . $query->getDescription()->getSize() . '<br />' .
154 - '<b>Query-Depth: </b>' . $query->getDescription()->getDepth() . '<br />' .
155 - '<b>SQL-Query</b><br />' .
156 - "SELECT DISTINCT $pagetable.page_title as title, $pagetable.page_namespace as namespace" .
157 - ' FROM ' . $from . ' WHERE ' . $where . $tailOpts . '<br />' .
158 - '<b>SQL-Query options</b><br />';
159 - foreach ($sql_options as $key => $value) {
160 - $result .= " $key=$value";
161 - }
162 - $result .= '<br /><b>Errors and Warnings</b><br />';
163 - foreach ($query->getErrors() as $error) {
164 - $result .= $error . '<br />';
165 - }
166 - $result .= '<br /><b>Auxilliary tables used</b><br />';
167 - foreach ($this->m_usedtables as $tablename) {
168 - $result .= $tablename . ': ';
169 - $res = $db->query( "SELECT title FROM $tablename", 'SMW::getQueryResult:DEBUG');
170 - while ( $row = $db->fetchObject($res) ) {
171 - $result .= $row->title . ', ';
172 - }
173 - $result .= '<br />';
174 - }
175 - $result .= '</div>';
 167+ /**
 168+ * Using a preprocessed internal query description referenced by $rootid, compute
 169+ * the proper result instance output for the given query.
 170+ */
 171+ protected function getInstanceQueryResult($query,$rootid) {
 172+ $qobj = $this->m_queries[$rootid];
 173+ if ($qobj->joinfield === '') { // empty result, no query needed
 174+ $result = new SMWQueryResult($query->getDescription()->getPrintrequests(), $query, false);
176175 return $result;
177 - } // else: continue
 176+ }
 177+ $sql_options = $this->getSQLOptions($query,$rootid);
 178+ $res = $this->m_dbs->select($this->m_dbs->tableName($qobj->jointable) . " AS $qobj->alias" . $qobj->from, "DISTINCT $qobj->alias.smw_title AS t,$qobj->alias.smw_namespace AS ns", $qobj->where, 'SMW::getQueryResult', $sql_options);
178179
179 - $res = $db->select($from,
180 - "DISTINCT $pagetable.page_title as title, $pagetable.page_namespace as namespace, $pagetable.page_id as id",
181 - $where,
182 - 'SMW::getQueryResult',
183 - $sql_options );
184 -
185180 $qr = array();
186181 $count = 0;
187 - while ( ($count<$query->getLimit()) && ($row = $db->fetchObject($res)) ) {
 182+ while ( ($count < $query->getLimit()) && ($row = $this->m_dbs->fetchObject($res)) ) {
188183 $count++;
189 - //$qr[] = Title::newFromText($row->title, $row->namespace);
190184 $v = SMWDataValueFactory::newTypeIDValue('_wpg');
191 - $v->setValues($row->title, $row->namespace, $row->id);
 185+ $v->setValues($row->t, $row->ns);
192186 $qr[] = $v;
193187 }
194 - if ($db->fetchObject($res)) {
 188+ if ($this->m_dbs->fetchObject($res)) {
195189 $count++;
196190 }
197 - $db->freeResult($res);
 191+ $this->m_dbs->freeResult($res);
198192
199193 // Create result by executing print statements for everything that was fetched
200 - ///TODO: use limit (and offset?) values for printouts?
 194+ ///TODO: limit (and offset?) values for printouts?
 195+ $prs = $query->getDescription()->getPrintrequests();
201196 $result = new SMWQueryResult($prs, $query, ($count > $query->getLimit()) );
202197 foreach ($qr as $qt) {
203198 $row = array();
204199 foreach ($prs as $pr) {
205200 switch ($pr->getMode()) {
206 - case SMW_PRINT_THIS:
207 - $row[] = new SMWResultArray(array($qt), $pr);
208 - break;
209 - case SMW_PRINT_CATS:
210 - $row[] = new SMWResultArray($this->getSpecialValues($qt->getTitle(),SMW_SP_INSTANCE_OF), $pr);
211 - break;
212 - case SMW_PRINT_PROP:
213 - $row[] = new SMWResultArray($this->getPropertyValues($qt->getTitle(),$pr->getTitle(), NULL, $pr->getOutputFormat()), $pr);
214 - break;
215 - case SMW_PRINT_CCAT:
216 - $cats = $this->getSpecialValues($qt->getTitle(),SMW_SP_INSTANCE_OF);
217 - $found = '0';
218 - foreach ($cats as $cat) {
219 - if ($cat->getDBkey() == $pr->getTitle()->getDBkey()) {
220 - $found = '1';
221 - break;
222 - }
 201+ case SMW_PRINT_THIS:
 202+ $row[] = new SMWResultArray(array($qt), $pr);
 203+ break;
 204+ case SMW_PRINT_CATS:
 205+ $row[] = new SMWResultArray($this->m_store->getSpecialValues($qt->getTitle(),SMW_SP_INSTANCE_OF), $pr);
 206+ break;
 207+ case SMW_PRINT_PROP:
 208+ $row[] = new SMWResultArray($this->m_store->getPropertyValues($qt->getTitle(),$pr->getTitle(), NULL, $pr->getOutputFormat()), $pr);
 209+ break;
 210+ case SMW_PRINT_CCAT:
 211+ $cats = $this->m_store->getSpecialValues($qt->getTitle(),SMW_SP_INSTANCE_OF);
 212+ $found = '0';
 213+ foreach ($cats as $cat) {
 214+ if ($cat->getDBkey() == $pr->getTitle()->getDBkey()) {
 215+ $found = '1';
 216+ break;
223217 }
224 - $dv = SMWDataValueFactory::newTypeIDValue('_boo');
225 - $dv->setOutputFormat($pr->getOutputFormat());
226 - $dv->setXSDValue($found);
 218+ }
 219+ $dv = SMWDataValueFactory::newTypeIDValue('_boo');
 220+ $dv->setOutputFormat($pr->getOutputFormat());
 221+ $dv->setXSDValue($found);
227222 // $dv = SMWDataValueFactory::newTypeIDValue('_str',$found . ' Format:' . $pr->getOutputFormat() . '!');
228 - $row[] = new SMWResultArray(array($dv), $pr);
229 - break;
 223+ $row[] = new SMWResultArray(array($dv), $pr);
 224+ break;
230225 }
231226 }
232227 $result->addRow($row);
@@ -266,7 +261,7 @@
267262 $query->where .= " AND $aw";
268263 }
269264 if ( array_key_exists($description->getProperty()->getDBkey(), $this->m_sortkeys) ) {
270 - $sortfield = $query->alias . (SMWDataValueFactory::newTypeIDValue($typeid)->isNumeric())?'value_num':'value_xsd';
 265+ $sortfield = "$query->alias." . (SMWDataValueFactory::newTypeIDValue($typeid)->isNumeric()?'value_num':'value_xsd');
271266 }
272267 }
273268 if ($sortfield) {
@@ -326,6 +321,11 @@
327322 if ($qid >= 0) {
328323 $this->m_queries[$qid] = $query;
329324 }
 325+ if ($query->type != SMW_SQL2_DISJUNCTION) { // sortkeys are killed by disjunctions (not all parts may have them), preprocessing might try to push disjunctions downwards to safe sortkey
 326+ foreach ($query->components as $cid => $field) {
 327+ $query->sortfields = array_merge($this->m_queries[$cid]->sortfields,$query->sortfields);
 328+ }
 329+ }
330330 return $qid;
331331 }
332332
@@ -373,37 +373,58 @@
374374 */
375375 protected function executeQueries(SMWSQLStore2Query &$query) {
376376 switch ($query->type) {
377 - case SMW_SQL2_TABLE: case SMW_SQL2_VALUE:
 377+ case SMW_SQL2_TABLE: // normal query with conjunctive subcondition
378378 foreach ($query->components as $qid => $joinfield) {
379379 $subquery = $this->m_queries[$qid];
380380 $this->executeQueries($subquery);
381381 if ($subquery->jointable != '') { // join with jointable.joinfield
382382 $query->from .= ' INNER JOIN ' . $subquery->jointable . " AS $subquery->alias ON $joinfield=" . $subquery->joinfield;
383 - } elseif ($subquery->joinfield != '') { // require joinfield as "value" via WHERE
 383+ } elseif ($subquery->joinfield !== '') { // require joinfield as "value" via WHERE
384384 $query->where .= (($query->where == '')?'':' AND ') . "$joinfield=" . $subquery->joinfield;
385 - } // else: no usable output from subquery, ignore
 385+ } else { // interpret empty joinfields as impossible condition (empty result)
 386+ $query->joinfield = ''; // make whole query false
 387+ $query->jointable = '';
 388+ $query->where = '';
 389+ $query->from = '';
 390+ break;
 391+ }
386392 if ($subquery->where != '') {
387393 $query->where .= (($query->where == '')?'':' AND ') . $subquery->where;
388394 }
389 - foreach ($subquery->sortfields as $propkey => $field) {
390 - $query->sortfields[$propkey] = $field; // all fieldnames are kept unchanged and remain available in query result
391 - }
392395 $query->from .= $subquery->from;
393396 }
394397 $query->components = array();
395398 break;
396399 case SMW_SQL2_CONJUNCTION:
397 - // pick one subquery as anchor point ...
 400+ // pick one subquery with jointable as anchor point ...
398401 reset($query->components);
399 - $key = key($query->components);
400 - $result = $this->m_queries[$key];
401 - unset($query->components[$key]);
402 - $this->executeQueries($result); // execute it first (may change jointable and joinfield, e.g. when making temporary tables
403 - // ... and append to this query the remaining queries
404 - foreach ($query->components as $qid => $joinfield) {
405 - $result->components[$qid] = $result->joinfield;
 402+ $key = false;
 403+ foreach ($query->components as $qkey => $qid) {
 404+ if ($this->m_queries[$qkey]->jointable != '') {
 405+ $key = $qkey;
 406+ break;
 407+ }
406408 }
407 - $this->executeQueries($result); // second execute, now incorporating remaining conditions
 409+ if ($key !== false) {
 410+ $result = $this->m_queries[$key];
 411+ unset($query->components[$key]);
 412+ $this->executeQueries($result); // execute it first (may change jointable and joinfield, e.g. when making temporary tables)
 413+ // ... and append to this query the remaining queries
 414+ foreach ($query->components as $qid => $joinfield) {
 415+ $result->components[$qid] = $result->joinfield;
 416+ }
 417+ $this->executeQueries($result); // second execute, now incorporating remaining conditions
 418+ } else { // only fixed values in conjunction, make a new value without joining
 419+ $key = $qkey;
 420+ $result = $this->m_queries[$key];
 421+ unset($query->components[$key]);
 422+ foreach ($query->components as $qid => $joinfield) {
 423+ if ($result->joinfield != $this->m_queries[$qid]->joinfield) {
 424+ $result->joinfield = ''; // all other values should already be ''
 425+ break;
 426+ }
 427+ }
 428+ }
408429 $query = $result;
409430 break;
410431 case SMW_SQL2_DISJUNCTION:
@@ -413,14 +434,25 @@
414435 foreach ($query->components as $qid => $joinfield) {
415436 $subquery = $this->m_queries[$qid];
416437 $this->executeQueries($subquery);
417 - $sql = "INSERT IGNORE INTO $query->alias SELECT $subquery->joinfield FROM $subquery->jointable AS $subquery->alias $subquery->from WHERE $subquery->where ";
418 - $this->m_querylog[$query->alias][] = $sql;
419 - $this->m_dbs->query($sql , 'SMW::executeQueries');
 438+ $sql = '';
 439+ if ($subquery->jointable != '') {
 440+ $sql = "INSERT IGNORE INTO $query->alias SELECT $subquery->joinfield FROM $subquery->jointable AS $subquery->alias $subquery->from WHERE $subquery->where ";
 441+ } elseif ($subquery->joinfield !== '') {
 442+ /// NOTE: this works only for single "unconditional" values without further
 443+ /// WHERE or FROM. The execution must take care of not creating any others.
 444+ $sql = "INSERT IGNORE INTO $query->alias (id) VALUES (" . $this->m_dbs->addQuotes($subquery->joinfield) . ')';
 445+ } // else: // interpret empty joinfields as impossible condition (empty result), ignore
 446+ if ($sql) {
 447+ $this->m_querylog[$query->alias][] = $sql;
 448+ $this->m_dbs->query($sql , 'SMW::executeQueries');
 449+ }
420450 }
421451 $query->jointable = $query->alias;
422452 $query->joinfield = "$query->alias.id";
 453+ $query->sortfields = array(); // make sure we got no sortfields
423454 /// TODO: currently this eliminates sortkeys, possibly keep them (needs different temp table format though, maybe not such a good thing to do)
424455 break;
 456+ case SMW_SQL2_VALUE: break; // nothing to do
425457 }
426458 }
427459
@@ -560,53 +592,65 @@
561593 }
562594
563595 /**
564 - * This function modifies the given query object ID $qid and array of SQL $options to
565 - * account for the ordering conditions in the SMWQuery $query.
 596+ * This function modifies the given query object at $qid to account for all ordering conditions
 597+ * in the SMWQuery $query. It is always required that $qid is the id of a query that joins with
 598+ * smw_ids so that the field alias.smw_title is $available for default sorting.
566599 */
567 - protected function applyOrderConditions($query, &$qid, &$options) {
 600+ protected function applyOrderConditions($query, $qid) {
568601 global $smwgQSortingSupport;
569602 if ( !$smwgQSortingSupport ) {
570603 return;
571604 }
572605 $qobj = $this->m_queries[$qid];
573 -// $extraproperties = array(); // collect required extra property descriptions
574 -// foreach ($this->m_sortkeys as $key => $order) {
575 -// if ($this->m_sortfields[$key] == false) { // find missing property to sort by
576 -// if ($key == '') { // sort by first column (page titles)
577 -// $this->m_sortfields[$key] = "$pagetable.page_title";
578 -// } else { // try to extend query
579 -// $extrawhere = '';
580 -// $sorttitle = Title::newFromText($key, SMW_NS_PROPERTY);
581 -// if ($sorttitle !== NULL) { // careful, Title creation might still fail!
582 -// $extraproperties[] = new SMWSomeProperty($sorttitle, new SMWThingDescription());
583 -// }
584 -// }
585 -// }
586 -// }
587 -// if (count($extraproperties) > 0) {
588 -// if (count($extraproperties) == 1) {
589 -// $desc = end($extraproperties);
590 -// } else {
591 -// $desc = new SMWConjunction($extraproperties);
592 -// }
593 -// $this->createSQLQuery($desc, $from, $extrawhere, $db, $curtables);
594 -// if ($extrawhere != '') {
595 -// if ($where != '') {
596 -// $where = "($where) AND ";
597 -// }
598 -// $where .= "($extrawhere)";
599 -// }
600 -// }
 606+ // (1) collect required extra property descriptions:
 607+ $extraproperties = array();
 608+ foreach ($this->m_sortkeys as $propkey => $order) {
 609+ if (!array_key_exists($propkey,$qobj->sortfields)) { // find missing property to sort by
 610+ if ($propkey == '') { // sort by first result column (page titles)
 611+ $qobj->sortfields[$propkey] = "$qobj->alias.smw_title";
 612+ } else { // try to extend query
 613+ $extrawhere = '';
 614+ $sorttitle = Title::newFromText($propkey, SMW_NS_PROPERTY);
 615+ if ($sorttitle !== NULL) { // careful, Title creation might still fail!
 616+ $extraproperties[] = new SMWSomeProperty($sorttitle, new SMWThingDescription());
 617+ }
 618+ }
 619+ }
 620+ }
 621+ // (2) compile according conditions and hack them into $qobj:
 622+ if (count($extraproperties) > 0) {
 623+ $desc = new SMWConjunction($extraproperties);
 624+ $newqid = $this->compileQueries($desc);
 625+ $newqobj = $this->m_queries[$newqid]; // this is always an SMW_SQL2_CONJUNCTION ...
 626+ foreach ($newqobj->components as $cid => $field) { // ... so just re-wire its dependencies
 627+ $qobj->components[$cid] = $qobj->joinfield;
 628+ $qobj->sortfields = array_merge($qobj->sortfields, $this->m_queries[$cid]->sortfields);
 629+ }
 630+ $this->m_queries[$qid] = $qobj;
 631+ }
 632+ }
 633+
 634+ /**
 635+ * Get a SQL option array for the given query and preprocessed query object at given id.
 636+ */
 637+ protected function getSQLOptions($query,$rootid) {
 638+ global $smwgQSortingSupport;
 639+ $result = array( 'LIMIT' => $query->getLimit() + 1, 'OFFSET' => $query->getOffset() );
 640+ // build ORDER BY options using discovered sorting fields:
 641+ if ($smwgQSortingSupport) {
 642+ $qobj = $this->m_queries[$rootid];
601643 foreach ($this->m_sortkeys as $propkey => $order) {
602644 if (array_key_exists($propkey,$qobj->sortfields)) { // field successfully added
603 - if (!array_key_exists('ORDER BY', $options)) {
604 - $options['ORDER BY'] = '';
 645+ if (!array_key_exists('ORDER BY', $result)) {
 646+ $result['ORDER BY'] = '';
605647 } else {
606 - $options['ORDER BY'] .= ', ';
 648+ $result['ORDER BY'] .= ', ';
607649 }
608 - $options['ORDER BY'] .= $qobj->sortfields[$propkey] . " $order ";
 650+ $result['ORDER BY'] .= $qobj->sortfields[$propkey] . " $order ";
609651 }
610652 }
 653+ }
 654+ return $result;
611655 }
612656
613657 }
\ No newline at end of file
Index: trunk/extensions/SemanticMediaWiki/includes/storage/SMW_SQLStore2.php
@@ -36,27 +36,6 @@
3737 /// Like SMWSQLStore2::m_semdata, but containing flags indicating completeness of the SMWSemanticData objs
3838 protected $m_sdstate = array();
3939
40 -
41 - /**
42 - * Global counter to prevent clashes between table aliases.
43 - */
44 -// static protected $m_tablenum = 0;
45 - /**
46 - * Array of names of virtual tables that hold the lower closure of certain
47 - * categories wrt. hierarchy.
48 - */
49 -// static protected $m_categorytables = array();
50 - /**
51 - * Array of names of virtual tables that hold the lower closure of certain
52 - * categories wrt. hierarchy.
53 - */
54 -// static protected $m_propertytables = array();
55 - /**
56 - * Record all virtual tables used for a single operation (especially query) to produce debug output.
57 - */
58 -// protected $m_usedtables;
59 -
60 -
6140 ///// Reading methods /////
6241
6342 function getSemanticData($subject, $filter = false) {

Status & tagging log