Index: trunk/extensions/SemanticMediaWiki/includes/SMW_QueryProcessor.php |
— | — | @@ -581,7 +581,7 @@ |
582 | 582 | } |
583 | 583 | break; |
584 | 584 | case '+': // wildcard |
585 | | - $vd = new SMWValueDescription(NULL, SMW_CMP_ANY); |
| 585 | + $vd = new SMWValueDescription(SMWDataValueFactory::newAttributeObjectValue($att), SMW_CMP_ANY); |
586 | 586 | break; |
587 | 587 | default: // fixed value, possibly with comparator addons |
588 | 588 | // for now, treat comparators only if placed before whole value: |
— | — | @@ -601,7 +601,7 @@ |
602 | 602 | } |
603 | 603 | } |
604 | 604 | // TODO: needs extension for n-ary values |
605 | | - $dv = SMWDataValueFactory::newAttributeValue($att->getText(), $value); |
| 605 | + $dv = SMWDataValueFactory::newAttributeObjectValue($att, $value); |
606 | 606 | if (!$dv->isValid()) { |
607 | 607 | $this->m_error = $dv->getError(); |
608 | 608 | $vd = new SMWValueDescription(NULL, SMW_CMP_ANY); |
Index: trunk/extensions/SemanticMediaWiki/includes/SMW_OldDataValue.php |
— | — | @@ -302,7 +302,11 @@ |
303 | 303 | |
304 | 304 | public function setOutputFormat($formatstring) { |
305 | 305 | // interpret new output format as the desired unit for united quantities |
306 | | - $this->setDesiredUnits(array($formatstring)); |
| 306 | + if ($formatstring != '') { |
| 307 | + $this->setDesiredUnits(array($formatstring)); |
| 308 | + } else { |
| 309 | + $this->setDesiredUnits(array()); |
| 310 | + } |
307 | 311 | } |
308 | 312 | |
309 | 313 | |
Index: trunk/extensions/SemanticMediaWiki/includes/storage/SMW_Description.php |
— | — | @@ -98,7 +98,7 @@ |
99 | 99 | |
100 | 100 | public function getTypeID() { |
101 | 101 | if ($this->m_typeid === false) { |
102 | | - $dv = SMWDataValueFactory::newAttributeValue($this->m_title->getText()); |
| 102 | + $dv = SMWDataValueFactory::newAttributeObjectValue($this->m_title); |
103 | 103 | $this->m_typeid = $dv->getTypeID(); |
104 | 104 | } |
105 | 105 | return $this->m_typeid; |
— | — | @@ -277,7 +277,7 @@ |
278 | 278 | protected $m_datavalue; |
279 | 279 | protected $m_comparator; |
280 | 280 | |
281 | | - public function SMWValueDescription($datavalue, $comparator = SMW_CMP_EQ) { |
| 281 | + public function SMWValueDescription(SMWDataValue $datavalue, $comparator = SMW_CMP_EQ) { |
282 | 282 | $this->m_datavalue = $datavalue; // might be NULL for SMW_CMP_ANY |
283 | 283 | $this->m_comparator = $comparator; |
284 | 284 | } |
Index: trunk/extensions/SemanticMediaWiki/includes/storage/SMW_SQLStore.php |
— | — | @@ -172,45 +172,47 @@ |
173 | 173 | $db =& wfGetDB( DB_MASTER ); // TODO: can we use SLAVE here? Is '=&' needed in PHP5? |
174 | 174 | $result = array(); |
175 | 175 | |
176 | | - // take care of "normal" attributes first |
177 | | - $value_column = 'value_xsd'; |
178 | | - if ( ($requestoptions !== NULL) && ($requestoptions->boundary !== NULL) && ($requestoptions->boundary->isNumeric()) ) { |
179 | | - $value_column = 'value_num'; |
| 176 | + $id = SMWDataValueFactory::getAttributeObjectTypeID($attribute); |
| 177 | + switch ($id) { |
| 178 | + case 'text': // long text attribute |
| 179 | + $res = $db->select( $db->tableName('smw_longstrings'), |
| 180 | + 'value_blob', |
| 181 | + 'subject_id=' . $db->addQuotes($subject->getArticleID()) . |
| 182 | + ' AND attribute_title=' . $db->addQuotes($attribute->getDBkey()), |
| 183 | + 'SMW::getAttributeValues', $this->getSQLOptions($requestoptions) ); |
| 184 | + if($db->numRows( $res ) > 0) { |
| 185 | + while($row = $db->fetchObject($res)) { |
| 186 | + $dv = SMWDataValueFactory::newAttributeObjectValue($attribute); |
| 187 | + $dv->setOutputFormat($outputformat); |
| 188 | + $dv->setXSDValue($row->value_blob, ''); |
| 189 | + $result[] = $dv; |
| 190 | + } |
| 191 | + } |
| 192 | + $db->freeResult($res); |
| 193 | + break; |
| 194 | + default: // all others |
| 195 | + if ( ($requestoptions !== NULL) && ($requestoptions->boundary !== NULL) && |
| 196 | + ($requestoptions->boundary->isNumeric()) ) { |
| 197 | + $value_column = 'value_num'; |
| 198 | + } else { |
| 199 | + $value_column = 'value_xsd'; |
| 200 | + } |
| 201 | + $sql = 'subject_id=' . $db->addQuotes($subject->getArticleID()) . |
| 202 | + ' AND attribute_title=' . $db->addQuotes($attribute->getDBkey()) . |
| 203 | + $this->getSQLConditions($requestoptions,$value_column,'value_xsd'); |
| 204 | + $res = $db->select( $db->tableName('smw_attributes'), |
| 205 | + 'value_unit, value_xsd', |
| 206 | + $sql, 'SMW::getAttributeValues', $this->getSQLOptions($requestoptions,$value_column) ); |
| 207 | + if($db->numRows( $res ) > 0) { |
| 208 | + while($row = $db->fetchObject($res)) { |
| 209 | + $dv = SMWDataValueFactory::newAttributeObjectValue($attribute); |
| 210 | + $dv->setOutputFormat($outputformat); |
| 211 | + $dv->setXSDValue($row->value_xsd, $row->value_unit); |
| 212 | + $result[] = $dv; |
| 213 | + } |
| 214 | + } |
| 215 | + $db->freeResult($res); |
180 | 216 | } |
181 | | - $sql = 'subject_id=' . $db->addQuotes($subject->getArticleID()) . |
182 | | - ' AND attribute_title=' . $db->addQuotes($attribute->getDBkey()) . |
183 | | - $this->getSQLConditions($requestoptions,$value_column,'value_xsd'); |
184 | | - $res = $db->select( $db->tableName('smw_attributes'), |
185 | | - 'value_unit, value_datatype, value_xsd', |
186 | | - $sql, 'SMW::getAttributeValues', $this->getSQLOptions($requestoptions,$value_column) ); |
187 | | - if($db->numRows( $res ) > 0) { |
188 | | - while($row = $db->fetchObject($res)) { |
189 | | - $dv = SMWDataValueFactory::newTypehandlerValue(SMWTypeHandlerFactory::getTypeHandlerByID($row->value_datatype)); |
190 | | - $dv->setAttribute($attribute->getText()); |
191 | | - $dv->setOutputFormat($outputformat); |
192 | | - $dv->setXSDValue($row->value_xsd, $row->value_unit); |
193 | | - $result[] = $dv; |
194 | | - } |
195 | | - } |
196 | | - $db->freeResult($res); |
197 | | - |
198 | | - // finally, look for long strings |
199 | | - $res = $db->select( $db->tableName('smw_longstrings'), |
200 | | - 'value_blob', |
201 | | - 'subject_id=' . $db->addQuotes($subject->getArticleID()) . |
202 | | - ' AND attribute_title=' . $db->addQuotes($attribute->getDBkey()), |
203 | | - 'SMW::getAttributeValues', $this->getSQLOptions($requestoptions,$value_column) ); |
204 | | - if($db->numRows( $res ) > 0) { |
205 | | - while($row = $db->fetchObject($res)) { |
206 | | - $dv = SMWDataValueFactory::newTypehandlerValue(SMWTypeHandlerFactory::getTypeHandlerByID('text')); |
207 | | - $dv->setAttribute($attribute->getText()); |
208 | | - $dv->setOutputFormat($outputformat); |
209 | | - $dv->setXSDValue($row->value_blob, ''); |
210 | | - $result[] = $dv; |
211 | | - } |
212 | | - } |
213 | | - $db->freeResult($res); |
214 | | - |
215 | 217 | return $result; |
216 | 218 | } |
217 | 219 | |
— | — | @@ -246,25 +248,32 @@ |
247 | 249 | $this->getSQLConditions($requestoptions,'subject_title','subject_title'); |
248 | 250 | |
249 | 251 | $result = array(); |
250 | | - $res = $db->select( $db->tableName('smw_attributes'), |
251 | | - 'DISTINCT subject_id', |
252 | | - $sql, 'SMW::getAllAttributeSubjects', $this->getSQLOptions($requestoptions,'subject_title') ); |
253 | | - if($db->numRows( $res ) > 0) { |
254 | | - while($row = $db->fetchObject($res)) { |
255 | | - $result[] = Title::newFromId($row->subject_id); |
256 | | - } |
| 252 | + $id = SMWDataValueFactory::getAttributeObjectTypeID($attribute); |
| 253 | + switch ($id) { |
| 254 | + case 'text': |
| 255 | + $res = $db->select( $db->tableName('smw_longstrings'), |
| 256 | + 'DISTINCT subject_id', |
| 257 | + $sql, 'SMW::getAllAttributeSubjects', |
| 258 | + $this->getSQLOptions($requestoptions,'subject_title') ); |
| 259 | + if($db->numRows( $res ) > 0) { |
| 260 | + while($row = $db->fetchObject($res)) { |
| 261 | + $result[] = Title::newFromId($row->subject_id); |
| 262 | + } |
| 263 | + } |
| 264 | + $db->freeResult($res); |
| 265 | + break; |
| 266 | + default: |
| 267 | + $res = $db->select( $db->tableName('smw_attributes'), |
| 268 | + 'DISTINCT subject_id', |
| 269 | + $sql, 'SMW::getAllAttributeSubjects', |
| 270 | + $this->getSQLOptions($requestoptions,'subject_title') ); |
| 271 | + if($db->numRows( $res ) > 0) { |
| 272 | + while($row = $db->fetchObject($res)) { |
| 273 | + $result[] = Title::newFromId($row->subject_id); |
| 274 | + } |
| 275 | + } |
| 276 | + $db->freeResult($res); |
257 | 277 | } |
258 | | - $db->freeResult($res); |
259 | | - $res = $db->select( $db->tableName('smw_longstrings'), |
260 | | - 'DISTINCT subject_id', |
261 | | - $sql, 'SMW::getAllAttributeSubjects', $this->getSQLOptions($requestoptions,'subject_title') ); |
262 | | - if($db->numRows( $res ) > 0) { |
263 | | - while($row = $db->fetchObject($res)) { |
264 | | - $result[] = Title::newFromId($row->subject_id); |
265 | | - } |
266 | | - } |
267 | | - $db->freeResult($res); |
268 | | - |
269 | 278 | return $result; |
270 | 279 | } |
271 | 280 | |
— | — | @@ -533,7 +542,6 @@ |
534 | 543 | * Probably the query parser (e.g. it can distinguish subqueries from other nested constructs that |
535 | 544 | * are not "subqueries" from a user perspective, it also has a good insight in the query structure for |
536 | 545 | * applying structural limits) |
537 | | - * TODO: implement namespace restrictions |
538 | 546 | * TODO: we now have sorting even for subquery conditions. Does this work? Is it slow/problematic? |
539 | 547 | * NOTE: we do not support category wildcards, as they have no useful semantics in OWL/RDFS/LP/whatever |
540 | 548 | */ |
— | — | @@ -676,7 +684,7 @@ |
677 | 685 | value_datatype VARCHAR(31) NOT NULL, |
678 | 686 | value_xsd VARCHAR(255) NOT NULL, |
679 | 687 | value_num DOUBLE |
680 | | - ) TYPE=innodb'; |
| 688 | + ) TYPE=innodb'; /// TODO: remove value_datatype column completely |
681 | 689 | $res = $db->query( $sql, $fname ); |
682 | 690 | } |
683 | 691 | |
— | — | @@ -827,6 +835,12 @@ |
828 | 836 | $from .= ' INNER JOIN ' . $db->tableName('smw_attributes') . ' AS ' . $curtables['ATTS'] . ' ON ' . $curtables['ATTS'] . '.subject_id=' . $curtables['PAGE'] . '.page_id'; |
829 | 837 | return true; |
830 | 838 | } |
| 839 | + } elseif ($tablename == 'TEXT') { |
| 840 | + if ($this->addInnerJoin('PAGE', $from, $db, $curtables)) { // try to add PAGE |
| 841 | + $curtables['TEXT'] = 'txt' . $this->m_tablenum++; |
| 842 | + $from .= ' INNER JOIN ' . $db->tableName('smw_longstrings') . ' AS ' . $curtables['TEXT'] . ' ON ' . $curtables['TEXT'] . '.subject_id=' . $curtables['PAGE'] . '.page_id'; |
| 843 | + return true; |
| 844 | + } |
831 | 845 | } |
832 | 846 | return false; |
833 | 847 | } |
— | — | @@ -886,28 +900,33 @@ |
887 | 901 | $description->getIndividual()->getNamespace(); |
888 | 902 | } |
889 | 903 | } elseif ($description instanceof SMWValueDescription) { |
890 | | - if ( $this->addInnerJoin('ATTS', $from, $db, $curtables) ) { |
891 | | - switch ($description->getComparator()) { |
892 | | - case SMW_CMP_EQ: $op = '='; break; |
893 | | - case SMW_CMP_LEQ: $op = '<='; break; |
894 | | - case SMW_CMP_GEQ: $op = '>='; break; |
895 | | - case SMW_CMP_NEQ: $op = '!='; break; |
896 | | - case SMW_CMP_ANY: default: $op = NULL; break; |
897 | | - } |
898 | | - if ($op !== NULL) { |
899 | | - if ($description->getDatavalue()->isNumeric()) { |
900 | | - $valuefield = 'value_num'; |
901 | | - $value = $description->getDatavalue()->getNumericValue(); |
902 | | - } else { |
903 | | - $valuefield = 'value_xsd'; |
904 | | - $value = $description->getDatavalue()->getXSDValue(); |
| 904 | + switch ($description->getDatavalue()->getTypeID()) { |
| 905 | + case 'text': // actually this should not happen; we cannot do anything here |
| 906 | + break; |
| 907 | + default: |
| 908 | + if ( $this->addInnerJoin('ATTS', $from, $db, $curtables) ) { |
| 909 | + switch ($description->getComparator()) { |
| 910 | + case SMW_CMP_EQ: $op = '='; break; |
| 911 | + case SMW_CMP_LEQ: $op = '<='; break; |
| 912 | + case SMW_CMP_GEQ: $op = '>='; break; |
| 913 | + case SMW_CMP_NEQ: $op = '!='; break; |
| 914 | + case SMW_CMP_ANY: default: $op = NULL; break; |
| 915 | + } |
| 916 | + if ($op !== NULL) { |
| 917 | + if ($description->getDatavalue()->isNumeric()) { |
| 918 | + $valuefield = 'value_num'; |
| 919 | + $value = $description->getDatavalue()->getNumericValue(); |
| 920 | + } else { |
| 921 | + $valuefield = 'value_xsd'; |
| 922 | + $value = $description->getDatavalue()->getXSDValue(); |
| 923 | + } |
| 924 | + ///TODO: implement check for unit |
| 925 | + $where .= $curtables['ATTS'] . '.' . $valuefield . $op . $db->addQuotes($value); |
| 926 | + if ($sort != '') { |
| 927 | + $this->m_sortfield = $curtables['ATTS'] . '.' . $valuefield; |
| 928 | + } |
| 929 | + } |
905 | 930 | } |
906 | | - ///TODO: implement check for unit |
907 | | - $where .= $curtables['ATTS'] . '.' . $valuefield . $op . $db->addQuotes($value); |
908 | | - if ($sort != '') { |
909 | | - $this->m_sortfield = $curtables['ATTS'] . '.' . $valuefield; |
910 | | - } |
911 | | - } |
912 | 931 | } |
913 | 932 | } elseif ($description instanceof SMWConjunction) { |
914 | 933 | foreach ($description->getDescriptions() as $subdesc) { |
— | — | @@ -950,13 +969,24 @@ |
951 | 970 | } |
952 | 971 | } |
953 | 972 | } elseif ($description instanceof SMWSomeAttribute) { |
954 | | - if ($this->addInnerJoin('ATTS', $from, $db, $curtables)) { |
955 | | - $where .= $curtables['ATTS'] . '.attribute_title=' . |
956 | | - $db->addQuotes($description->getAttribute()->getDBKey()); |
957 | | - $this->createSQLQuery($description->getDescription(), $from, $subwhere, $db, $curtables, ($this->m_sortkey == $description->getAttribute()->getDBKey()) ); |
958 | | - if ( $subwhere != '') { |
959 | | - $where .= ' AND (' . $subwhere . ')'; |
960 | | - } |
| 973 | + $id = SMWDataValueFactory::getAttributeObjectTypeID($description->getAttribute()); |
| 974 | + switch ($id) { |
| 975 | + case 'text': |
| 976 | + if ($this->addInnerJoin('TEXT', $from, $db, $curtables)) { |
| 977 | + $where .= $curtables['TEXT'] . '.attribute_title=' . |
| 978 | + $db->addQuotes($description->getAttribute()->getDBKey()); |
| 979 | + // no recursion: we do not support further conditions on text-type values |
| 980 | + } |
| 981 | + break; |
| 982 | + default: |
| 983 | + if ($this->addInnerJoin('ATTS', $from, $db, $curtables)) { |
| 984 | + $where .= $curtables['ATTS'] . '.attribute_title=' . |
| 985 | + $db->addQuotes($description->getAttribute()->getDBKey()); |
| 986 | + $this->createSQLQuery($description->getDescription(), $from, $subwhere, $db, $curtables, ($this->m_sortkey == $description->getAttribute()->getDBKey()) ); |
| 987 | + if ( $subwhere != '') { |
| 988 | + $where .= ' AND (' . $subwhere . ')'; |
| 989 | + } |
| 990 | + } |
961 | 991 | } |
962 | 992 | } |
963 | 993 | |
Index: trunk/extensions/SemanticMediaWiki/includes/SMW_DataValueFactory.php |
— | — | @@ -18,11 +18,16 @@ |
19 | 19 | static private $m_valueclasses = array(); |
20 | 20 | |
21 | 21 | /** |
22 | | - * Cache for type labels, indexed by attribute name (both without namespace prefix). |
| 22 | + * Cache for type specifications (right now strings), indexed by attribute name (both without namespace prefix). |
23 | 23 | */ |
24 | | - static private $m_attributelabels = array('Testnary' => 'String;Integer;Wikipage;Date'); ///DEBUG |
| 24 | + static private $m_typelabels = array('Testnary' => 'String;Integer;Wikipage;Date'); ///DEBUG |
25 | 25 | |
26 | 26 | /** |
| 27 | + * Cache for type ids, indexed by attribute name (without namespace prefix). |
| 28 | + */ |
| 29 | + static private $m_typeids = array(); |
| 30 | + |
| 31 | + /** |
27 | 32 | * Was code for handling n-ary properties already included? |
28 | 33 | */ |
29 | 34 | static private $m_naryincluded = false; |
— | — | @@ -33,14 +38,31 @@ |
34 | 39 | * can be set later on. |
35 | 40 | */ |
36 | 41 | static public function newAttributeValue($attstring, $value=false) { |
37 | | - if(!array_key_exists($attstring,SMWDataValueFactory::$m_attributelabels)) { |
| 42 | + if(!array_key_exists($attstring,SMWDataValueFactory::$m_typelabels)) { |
38 | 43 | $atitle = Title::newFromText($attstring, SMW_NS_ATTRIBUTE); |
39 | 44 | if ($atitle !== NULL) { |
40 | | - $typearray = smwfGetStore()->getSpecialValues($atitle,SMW_SP_HAS_TYPE); |
41 | | - } else { $typearray = Array(); } |
| 45 | + return SMWDataValueFactory::newAttributeObjectValue($atitle,$value); |
| 46 | + } else { |
| 47 | + return new SMWOldDataValue(new SMWErrorTypeHandler(wfMsgForContent('smw_notype'))); |
| 48 | + } |
| 49 | + } |
| 50 | + return SMWDataValueFactory::newTypedValue(SMWDataValueFactory::$m_typelabels[$attstring], $value); |
| 51 | + } |
42 | 52 | |
| 53 | + /** |
| 54 | + * Create a value from a string supplied by a user for a given attribute title. |
| 55 | + * If no value is given, an empty container is created, the value of which |
| 56 | + * can be set later on. |
| 57 | + */ |
| 58 | + static public function newAttributeObjectValue(Title $att, $value=false) { |
| 59 | + $attstring = $att->getText(); |
| 60 | + if(!array_key_exists($attstring,SMWDataValueFactory::$m_typelabels)) { |
| 61 | + $typearray = smwfGetStore()->getSpecialValues($att,SMW_SP_HAS_TYPE); |
43 | 62 | if (count($typearray)==1) { |
44 | | - SMWDataValueFactory::$m_attributelabels[$attstring] = $typearray[0]; |
| 63 | + SMWDataValueFactory::$m_typelabels[$attstring] = $typearray[0]; |
| 64 | + $result = SMWDataValueFactory::newTypedValue(SMWDataValueFactory::$m_typelabels[$attstring], $value); |
| 65 | + SMWDataValueFactory::$m_typeids[$attstring] = $result->getTypeID(); // also cache typeid |
| 66 | + return $result; |
45 | 67 | } elseif (count($typearray)==0) { |
46 | 68 | ///TODO |
47 | 69 | return new SMWOldDataValue(new SMWErrorTypeHandler(wfMsgForContent('smw_notype'))); |
— | — | @@ -49,7 +71,7 @@ |
50 | 72 | return new SMWOldDataValue(new SMWErrorTypeHandler(wfMsgForContent('smw_manytypes'))); |
51 | 73 | } |
52 | 74 | } |
53 | | - return SMWDataValueFactory::newTypedValue(SMWDataValueFactory::$m_attributelabels[$attstring], $value); |
| 75 | + return SMWDataValueFactory::newTypedValue(SMWDataValueFactory::$m_typelabels[$attstring], $value); |
54 | 76 | } |
55 | 77 | |
56 | 78 | /** |
— | — | @@ -134,6 +156,18 @@ |
135 | 157 | } |
136 | 158 | |
137 | 159 | /** |
| 160 | + * Quickly get the type id of some attribute without necessarily making another datavalue. |
| 161 | + */ |
| 162 | + static public function getAttributeObjectTypeID(Title $att) { |
| 163 | + $attstring = $att->getText(); |
| 164 | + if (array_key_exists($attstring, SMWDataValueFactory::$m_typeids)) { |
| 165 | + return SMWDataValueFactory::$m_typeids[$attstring]; |
| 166 | + } else { |
| 167 | + return SMWDataValueFactory::newAttributeObjectValue($att)->getTypeID(); // this also triggers caching |
| 168 | + } |
| 169 | + } |
| 170 | + |
| 171 | + /** |
138 | 172 | * Create a value from a user-supplied string for which a type handler is known |
139 | 173 | * If no value is given, an empty container is created, the value of which |
140 | 174 | * can be set later on. |