* Thomas Bleher <[EMAIL PROTECTED]> [2007-11-15 20:36]:
> * Thomas Bleher <[EMAIL PROTECTED]> [2007-11-14 08:48]:
> > 1) Implement negations in queries - then I could ask "(NOT maxTeilnehmer <=
> >    9) AND (NOT minTeilnehmer >= 11)". I used this solution with SMW 0.7
> >    (patch below), but looking at the 1.0RC2 code, I'm not quite sure how
> >    to implement it cleanly.
> 
> I looked at the code again and tried to implement negation support. The
> patch below adds a <n> </n> pair which negates the query in between. It
> also adds a SMWNegation class (derived from SMWDescription), which
> encapsulates the negation.

OK, I took another stab at this, and in my limited tests the code works
correctly now :)

The code is online at http://pwiki.j-crew.de/wiki/Test, feel free to
play around with it (it's just a test-wiki).

Technical details:
To work around the problems with INNER JOINs and negations, all INNER
JOINs of the form "SELECT a INNER JOIN b ON a.c=b.d" are replaced by
"SELECT a,b WHERE a.c=b.d". This may not be the most elegant solution,
but the only workable I found.

To make this work, addJoin now has an additional $where parameter.

Beware: I still don't understand all the internals of query processing,
so no guarantees for this code. I would really appreciate it if someone
more knowledgeable than me would look over the code.

Regards,
Thomas

--- a/extensions/SemanticMediaWiki/includes/SMW_QueryProcessor.php
+++ b/extensions/SemanticMediaWiki/includes/SMW_QueryProcessor.php
@@ -296,7 +296,14 @@ class SMWQueryParser {
 					$conjunction = $this->addDescription($conjunction, $this->getSubqueryDescription($setsubNS, $label));
 					/// TODO: print requests from subqueries currently are ignored, should be moved down
 				break;
-				case '||': case '': case '</q>': // finish disjunction and maybe subquery
+				case '<n>': // negated subquery
+					$this->pushDelimiter('</n>');
+					$setsubsubNS = false;
+					$sublabel = '';
+					$conjunction = $this->addDescription($conjunction, new SMWNegation($this->getSubqueryDescription($setsubsubNS, $sublabel)));
+					/// TODO: print requests from negations currently are ignored, should be moved down
+				break;
+				case '||': case '': case '</q>': case '</n>': // finish disjunction and maybe subquery
 					if ($this->m_defaultns !== NULL) { // possibly add namespace restrictions
 						if ( $hasNamespaces && !$mustSetNS) {
 							// add ns restrictions to all earlier conjunctions (all of which did not have them yet)
@@ -323,6 +330,13 @@ class SMWQueryParser {
 							$this->m_errors[] = wfMsgForContent('smw_toomanyclosing', $chunk);
 							return NULL;
 						}
+					} elseif ($chunk == '</n>') {
+						if ($this->popDelimiter('</n>')) {
+							$continue = false; // leave the loop
+						} else {
+							$this->m_errors[] = wfMsgForContent('smw_toomanyclosing', $chunk);
+							return NULL;
+						}
 					} elseif ($chunk == '') {
 						$continue = false;
 					}
@@ -489,6 +503,18 @@ class SMWQueryParser {
 					}
 					$chunk = $this->readChunk();
 				break;
+				case '<n>': // subquery, set default namespaces
+					if ($typeid == '_wpg') {
+						$this->pushDelimiter('</n>');
+						$setsubNS = true;
+						$sublabel = '';
+						$innerdesc = $this->addDescription($innerdesc, new SMWNegation($this->getSubqueryDescription($setsubNS, $sublabel)), false);
+					} else { // no subqueries allowed for non-pages
+						$this->m_errors[] = wfMsgForContent('smw_valuesubquery', $propertyname);
+						$innerdesc = $this->addDescription($innerdesc, new SMWThingDescription(), false);
+					}
+					$chunk = $this->readChunk();
+				break;
 				default: //normal object value or print statement
 					// read value(s), possibly with inner [[...]]
 					$open = 1;
@@ -738,7 +764,7 @@ class SMWQueryParser {
 	 */
 	protected function readChunk($stoppattern = '', $consume=true) {
 		if ($stoppattern == '') {
-			$stoppattern = '\[\[|\]\]|::|:=|<q>|<\/q>|^' . $this->m_categoryprefix . '|\|\||\|';
+			$stoppattern = '\[\[|\]\]|::|:=|<q>|<\/q>|<n>|<\/n>|^' . $this->m_categoryprefix . '|\|\||\|';
 		}
 		$chunks = preg_split('/[\s]*(' . $stoppattern . ')[\s]*/', $this->m_curstring, 2, PREG_SPLIT_DELIM_CAPTURE);
 		if (count($chunks) == 1) { // no matches anymore, strip spaces and finish
--- a/extensions/SemanticMediaWiki/includes/storage/SMW_Description.php
+++ b/extensions/SemanticMediaWiki/includes/storage/SMW_Description.php
@@ -763,3 +763,31 @@ class SMWSomeProperty extends SMWDescription {
 	}
 }
 
+/**
+ * Description of a negation of a description.
+ */
+class SMWNegation extends SMWDescription {
+	protected $m_description;
+
+	public function SMWNegation(SMWDescription $description) {
+		$this->m_description = $description;
+	}
+
+	public function getDescription() {
+		return $this->m_description;
+	}
+
+
+	public function getQueryString() {
+		return '&lt;n&gt;' . $this->m_description->getQueryString() . '&lt;/n&gt;';
+	}
+
+	public function isSingleton() {
+		return false;
+	}
+
+	public function getDepth() {
+		return $this->m_description->getDepth() + 1;
+	}
+
+}
--- a/extensions/SemanticMediaWiki/includes/storage/SMW_SQLStore.php
+++ b/extensions/SemanticMediaWiki/includes/storage/SMW_SQLStore.php
@@ -352,7 +352,8 @@ class SMWSQLStore extends SMWStore {
 		case '__nry':
 			$values = $value->getDVs();
 			$narytable = $db->tableName('smw_nary');
-			$where = "$narytable.attribute_title=" . $db->addQuotes($property->getDBKey());
+			if ($where != '') $where .= ' AND ';
+			$where .= "$narytable.attribute_title=" . $db->addQuotes($property->getDBKey());
 			$from = $narytable;
 			$count = 0;
 			foreach ($values as $dv) {
@@ -364,14 +365,14 @@ class SMWSQLStore extends SMWStore {
 				case '_txt': // not supported
 				break;
 				case '_wpg':
-					$from .= ' INNER JOIN ' . $db->tableName('smw_nary_relations') . ' AS nary' . $count .
-					         " ON ($narytable.subject_id=nary$count.subject_id AND $narytable.nary_key=nary$count.nary_key)";
+					$from .= ', ' . $db->tableName('smw_nary_relations') . ' AS nary' . $count;
+					$where .= " AND ($narytable.subject_id=nary$count.subject_id AND $narytable.nary_key=nary$count.nary_key)";
 					$where .= " AND nary$count.object_title=" . $db->addQuotes($dv->getDBKey()) .
 					          " AND nary$count.object_namespace=" . $db->addQuotes($dv->getNamespace());
 				break;
 				default:
-					$from .= ' INNER JOIN ' . $db->tableName('smw_nary_attributes') . ' AS nary' . $count .
-					         " ON ($narytable.subject_id=nary$count.subject_id AND $narytable.nary_key=nary$count.nary_key)";
+					$from .= ', ' . $db->tableName('smw_nary_attributes') . ' AS nary' . $count;
+					$where .= " AND ($narytable.subject_id=nary$count.subject_id AND $narytable.nary_key=nary$count.nary_key)";
 					$where .= " AND nary$count.value_xsd=" . $db->addQuotes($dv->getXSDValue()) .
 					          " AND nary$count.value_unit=" . $db->addQuotes($dv->getUnit());
 				}
@@ -1234,11 +1235,11 @@ class SMWSQLStore extends SMWStore {
 	 * relevant page id. This can be a field from a (possibly auxilliary) page table or
 	 * from one of SMW's relation tables. If no field is available, return false.
 	 */
-	protected function getCurrentIDField(&$from, &$db, &$curtables, $nary_pos = '') {
+	protected function getCurrentIDField(&$from, &$where, &$db, &$curtables, $nary_pos = '') {
 		$id = false;
-		if ($this->addJoin('pRELS', $from, $db, $curtables, $nary_pos)) {
+		if ($this->addJoin('pRELS', $from, $where, $db, $curtables, $nary_pos)) {
 			$id = $curtables['pRELS'] . '.object_id';
-		} elseif ($this->addJoin('PAGE', $from, $db, $curtables, $nary_pos)) { // fallback
+		} elseif ($this->addJoin('PAGE', $from, $where, $db, $curtables, $nary_pos)) { // fallback
 			$id = $curtables['PAGE'] . '.page_id';
 		}
 		return $id;
@@ -1408,83 +1409,95 @@ class SMWSQLStore extends SMWStore {
 	 * That's all. The method can be read and modified case by case, each of which is
 	 * rather short and completely independent from the other cases.
 	 */
-	protected function addJoin($tablename, &$from, &$db, &$curtables, $nary_pos = '') {
+	protected function addJoin($tablename, &$from, &$where, &$db, &$curtables, $nary_pos = '') {
 		global $smwgQEqualitySupport;
 		if (array_key_exists($tablename, $curtables)) { // table already present
 			return $curtables[$tablename];
 		}
 
 		if ($tablename == 'PAGE') {
-			if ($this->addJoin('pRELS', $from, $db, $curtables, $nary_pos)) {
+			if ($this->addJoin('pRELS', $from, $where, $db, $curtables, $nary_pos)) {
 				$curtables['PAGE'] = 'p' . SMWSQLStore::$m_tablenum++;
-				$from .= ' INNER JOIN ' . $db->tableName('page') . ' AS ' . $curtables['PAGE'] . ' ON (' .
+				$from .= ', ' . $db->tableName('page') . ' AS ' . $curtables['PAGE'];
+				if ($where != '') $where .= ' AND ';
+				$where .= '(' .
 				           $curtables['PAGE'] . '.page_title=' . $curtables['pRELS'] . '.object_title AND ' .
 				           $curtables['PAGE'] . '.page_namespace=' . $curtables['pRELS'] . '.object_namespace)';
 				return $curtables['PAGE'];
 			}
 		} elseif ($tablename == 'CATS') {
-			if ($id = $this->getCurrentIDField($from, $db, $curtables, $nary_pos)) {
+			if ($id = $this->getCurrentIDField($from, $where, $db, $curtables, $nary_pos)) {
 				$curtables['CATS'] = 'cl' . SMWSQLStore::$m_tablenum++;
 				$cond = $curtables['CATS'] . '.cl_from=' . $id;
 				/// TODO: slow, introduce another parameter to activate this
 				if ($smwgQEqualitySupport && (array_key_exists('pRELS', $curtables))) {
 					// only do this at inner queries (pRELS set)
-					$this->addJoin('REDIPAGE', $from, $db, $curtables, $nary_pos);
+					$this->addJoin('REDIPAGE', $from, $where, $db, $curtables, $nary_pos);
 					$cond = '((' . $cond . ') OR (' .
 					  $curtables['REDIPAGE'] . '.page_id=' . $curtables['CATS'] . '.cl_from))';
 				}
-				$from .= ' INNER JOIN ' . $db->tableName('categorylinks') . ' AS ' . $curtables['CATS'] . ' ON ' . $cond;
+				$from .= ', ' . $db->tableName('categorylinks') . ' AS ' . $curtables['CATS'];
+				if ($where != '') $where .= ' AND ';
+				$where .= $cond;
 				return $curtables['CATS'];
 			}
 		} elseif ($tablename == 'RELS') {
-			if ($id = $this->getCurrentIDField($from, $db, $curtables, $nary_pos)) {
+			if ($id = $this->getCurrentIDField($from, $where, $db, $curtables, $nary_pos)) {
 				$curtables['RELS'] = 'rel' . SMWSQLStore::$m_tablenum++;
 				$cond = $curtables['RELS'] . '.subject_id=' . $id;
 				/// TODO: slow, introduce another parameter to activate this
 				if ($smwgQEqualitySupport && (array_key_exists('pRELS', $curtables))) {
 					// only do this at inner queries (pRELS set)
-					$this->addJoin('REDIRECT', $from, $db, $curtables, $nary_pos);
+					$this->addJoin('REDIRECT', $from, $where, $db, $curtables, $nary_pos);
 					$cond = '((' . $cond . ') OR (' .
 					  $curtables['REDIRECT'] . '.rd_title=' . $curtables['RELS'] . '.subject_title AND ' .
 					  $curtables['REDIRECT'] . '.rd_namespace=' . $curtables['RELS'] . '.subject_namespace))';
 				}
-				$from .= ' INNER JOIN ' . $db->tableName('smw_relations') . ' AS ' . $curtables['RELS'] . ' ON ' . $cond;
+				$from .= ', ' . $db->tableName('smw_relations') . ' AS ' . $curtables['RELS'];
+				if ($where != '') $where .= ' AND ';
+				$where .= $cond;
 				return $curtables['RELS'];
 			}
 		} elseif ($tablename == 'ATTS') {
-			if ($id = $this->getCurrentIDField($from, $db, $curtables, $nary_pos)) {
+			if ($id = $this->getCurrentIDField($from, $where, $db, $curtables, $nary_pos)) {
 				$curtables['ATTS'] = 'att' . SMWSQLStore::$m_tablenum++;
 				$cond = $curtables['ATTS'] . '.subject_id=' . $id;
 				/// TODO: slow, introduce another parameter to activate this
 				if ($smwgQEqualitySupport && (array_key_exists('pRELS', $curtables))) {
 					// only do this at inner queries (pREL set)
-					$this->addJoin('REDIRECT', $from, $db, $curtables, $nary_pos);
+					$this->addJoin('REDIRECT', $from, $where, $db, $curtables, $nary_pos);
 					$cond = '((' . $cond . ') OR (' .
 					  $curtables['REDIRECT'] . '.rd_title=' . $curtables['ATTS'] . '.subject_title AND ' .
 					  $curtables['REDIRECT'] . '.rd_namespace=' . $curtables['ATTS'] . '.subject_namespace))';
 				}
-				$from .= ' INNER JOIN ' . $db->tableName('smw_attributes') . ' AS ' . $curtables['ATTS'] . ' ON ' . $cond;
+				$from .= ', ' . $db->tableName('smw_attributes') . ' AS ' . $curtables['ATTS'];
+				if ($where != '') $where .= ' AND ';
+				$where .= $cond;
 				return $curtables['ATTS'];
 			}
 		} elseif ($tablename == 'TEXT') {
-			if ($id = $this->getCurrentIDField($from, $db, $curtables, $nary_pos)) {
+			if ($id = $this->getCurrentIDField($from, $where, $db, $curtables, $nary_pos)) {
 				$curtables['TEXT'] = 'txt' . SMWSQLStore::$m_tablenum++;
-				$from .= ' INNER JOIN ' . $db->tableName('smw_longstrings') . ' AS ' . $curtables['TEXT'] . ' ON ' . $curtables['TEXT'] . '.subject_id=' . $id;
+				$from .= ', ' . $db->tableName('smw_longstrings') . ' AS ' . $curtables['TEXT'];
+				if ($where != '') $where .= ' AND ';
+				$where .= $curtables['TEXT'] . '.subject_id=' . $id;
 				return $curtables['TEXT'];
 			}
 		} elseif ($tablename == 'NARY') {
-			if ($id = $this->getCurrentIDField($from, $db, $curtables, $nary_pos)) {
+			if ($id = $this->getCurrentIDField($from, $where, $db, $curtables, $nary_pos)) {
 				$curtables['NARY'] = 'nary' . SMWSQLStore::$m_tablenum++;
 				$cond = $curtables['NARY'] . '.subject_id=' . $id;
 				/// TODO: slow, introduce another parameter to activate this
 				if ($smwgQEqualitySupport && (array_key_exists('pRELS', $curtables))) {
 					// only do this at inner queries (pRELS set)
-					$this->addJoin('REDIRECT', $from, $db, $curtables, $nary_pos);
+					$this->addJoin('REDIRECT', $from, $where, $db, $curtables, $nary_pos);
 					$cond = '((' . $cond . ') OR (' .
 					  $curtables['REDIRECT'] . '.rd_title=' . $curtables['RELS'] . '.subject_title AND ' .
 					  $curtables['REDIRECT'] . '.rd_namespace=' . $curtables['RELS'] . '.subject_namespace))';
 				}
-				$from .= ' INNER JOIN ' . $db->tableName('smw_nary') . ' AS ' . $curtables['NARY'] . ' ON ' . $cond;
+				$from .= ', ' . $db->tableName('smw_nary') . ' AS ' . $curtables['NARY'];
+				if ($where != '') $where .= ' AND ';
+				$where .= $cond;
 				return $curtables['NARY'];
 			}
 		} elseif ($tablename == 'pATTS') {
@@ -1494,8 +1507,10 @@ class SMWSQLStore extends SMWStore {
 				        $curtables['pATTS'] . '.subject_id=' . $curtables['pNARY'] . '.subject_id AND ' .
 				        $curtables['pATTS'] . '.nary_key=' . $curtables['pNARY'] . '.nary_key AND ' .
 				        $curtables['pATTS'] . '.nary_pos=' . $db->addQuotes($nary_pos) . ')';
-				$from .= ' INNER JOIN ' . $db->tableName('smw_nary_attributes') . ' AS ' .
-				         $curtables['pATTS'] . ' ON ' . $cond;
+				$from .= ', ' . $db->tableName('smw_nary_attributes') . ' AS ' .
+				         $curtables['pATTS'];
+				if ($where != '') $where .= ' AND ';
+				$where .= $cond;
 				return $curtables['pATTS'];
 			}
 		} elseif ($tablename == 'pRELS') {
@@ -1505,7 +1520,9 @@ class SMWSQLStore extends SMWStore {
 				        $curtables['pRELS'] . '.subject_id=' . $curtables['pNARY'] . '.subject_id AND ' .
 				        $curtables['pRELS'] . '.nary_key=' . $curtables['pNARY'] . '.nary_key AND ' .
 				        $curtables['pRELS'] . '.nary_pos=' . $db->addQuotes($nary_pos) . ')';
-				$from .= ' INNER JOIN ' . $db->tableName('smw_nary_relations') . ' AS ' . $curtables['pRELS'] . ' ON ' . $cond;
+				$from .= ', ' . $db->tableName('smw_nary_relations') . ' AS ' . $curtables['pRELS'];
+				if ($where != '') $where .= ' AND ';
+				$where .= $cond;
 				return $curtables['pRELS'];
 			}
 		} elseif ($tablename == 'pTEXT') {
@@ -1515,17 +1532,19 @@ class SMWSQLStore extends SMWStore {
 				        $curtables['pTEXT'] . '.subject_id=' . $curtables['pNARY'] . '.subject_id AND ' .
 				        $curtables['pTEXT'] . '.nary_key=' . $curtables['pNARY'] . '.nary_key AND ' .
 				        $curtables['pTEXT'] . '.nary_pos=' . $db->addQuotes($nary_pos) . ')';
-				$from .= ' INNER JOIN ' . $db->tableName('smw_nary_longstrings') . ' AS ' . $curtables['pTEXT'] . ' ON ' . $cond;
+				$from .= ', ' . $db->tableName('smw_nary_longstrings') . ' AS ' . $curtables['pTEXT'];
+				if ($where != '') $where .= ' AND ';
+				$where .= $cond;
 				return $curtables['pTEXT'];
 			}
 		} elseif ($tablename == 'REDIRECT') {
-			if ($id = $this->getCurrentIDField($from, $db, $curtables, $nary_pos)) {
+			if ($id = $this->getCurrentIDField($from, $where, $db, $curtables, $nary_pos)) {
 				$curtables['REDIRECT'] = 'rd' . SMWSQLStore::$m_tablenum++;
 				$from .= ' LEFT JOIN ' . $db->tableName('redirect') . ' AS ' . $curtables['REDIRECT'] . ' ON ' . $curtables['REDIRECT'] . '.rd_from=' . $id;
 				return $curtables['REDIRECT'];
 			}
 		} elseif ($tablename == 'REDIPAGE') { // +another copy of page for getting ids of redirect targets; *ouch*
-			if ($this->addJoin('REDIRECT', $from, $db, $curtables, $nary_pos)) {
+			if ($this->addJoin('REDIRECT', $from, $where, $db, $curtables, $nary_pos)) {
 				$curtables['REDIPAGE'] = 'rp' . SMWSQLStore::$m_tablenum++;
 				$from .= ' LEFT JOIN ' . $db->tableName('page') . ' AS ' . $curtables['REDIPAGE'] . ' ON (' .
 				         $curtables['REDIRECT'] . '.rd_title=' . $curtables['REDIPAGE'] . '.page_title AND ' .
@@ -1570,12 +1589,13 @@ class SMWSQLStore extends SMWStore {
 		if ($description instanceof SMWThingDescription) {
 			// nothing to check
 		} elseif ($description instanceof SMWClassDescription) {
-			if ($table = $this->addJoin('CATS', $from, $db, $curtables, $nary_pos)) {
+			if ($table = $this->addJoin('CATS', $from, $where, $db, $curtables, $nary_pos)) {
 				global $smwgQSubcategoryDepth;
 				if ($smwgQSubcategoryDepth > 0) {
 					$ct = $this->getCategoryTable($description->getCategories(), $db);
 					$from = '`' . $ct . '`, ' . $from;
-					$where = "$ct.title=" . $table . '.cl_to';
+					if ($where != '') $where .= ' AND ';
+					$where .= " $ct.title=" . $table . '.cl_to ';
 				} else {
 					foreach ($description->getCategories() as $cat) {
 						if ($subwhere != '') {
@@ -1590,15 +1610,17 @@ class SMWSQLStore extends SMWStore {
 				}
 			}
 		} elseif ($description instanceof SMWNamespaceDescription) {
-			if ($table = $this->addJoin('pRELS', $from, $db, $curtables, $nary_pos)) {
+			if ($table = $this->addJoin('pRELS', $from, $where, $db, $curtables, $nary_pos)) {
+				if ($where != '') $where .= ' AND ';
 				$where .=  $table . '.object_namespace=' . $db->addQuotes($description->getNamespace());
-			} elseif ($table = $this->addJoin('PAGE', $from, $db, $curtables, $nary_pos)) {
+			} elseif ($table = $this->addJoin('PAGE', $from, $where, $db, $curtables, $nary_pos)) {
+				if ($where != '') $where .= ' AND ';
 				$where .=  $table . '.page_namespace=' . $db->addQuotes($description->getNamespace());
 			}
 		} elseif ($description instanceof SMWValueDescription) {
 			switch ($description->getDatavalue()->getTypeID()) {
 				case '_txt': // possibly pull in longstring table (for naries)
-					$this->addJoin('pTEXT', $from, $db, $curtables, $nary_pos);
+					$this->addJoin('pTEXT', $from, $where, $db, $curtables, $nary_pos);
 				break;
 				case '_wpg':
 					global $smwgQEqualitySupport;
@@ -1607,24 +1629,26 @@ class SMWSQLStore extends SMWStore {
 					} else {
 						$page = $description->getDatavalue();
 					}
-					if ($table = $this->addJoin('pRELS', $from, $db, $curtables, $nary_pos)) {
+					if ($table = $this->addJoin('pRELS', $from, $where, $db, $curtables, $nary_pos)) {
 						$cond = $table . '.object_title=' .
 						        $db->addQuotes($page->getDBKey()) . ' AND ' .
 						        $table . '.object_namespace=' . $page->getNamespace();
 						if ( $smwgQEqualitySupport &&
-						     ($this->addJoin('REDIRECT', $from, $db, $curtables, $nary_pos)) ) {
+						     ($this->addJoin('REDIRECT', $from, $where, $db, $curtables, $nary_pos)) ) {
 							$cond = '(' . $cond . ') OR (' .
 							   $curtables['REDIRECT'] . '.rd_title=' . $db->addQuotes($page->getDBKey()) . ' AND ' .
 							   $curtables['REDIRECT'] . '.rd_namespace=' . $page->getNamespace() . ')';
 						}
+						if ($where != '') $where .= ' AND ';
 						$where .= $cond;
-					} elseif ($table = $this->addJoin('PAGE', $from, $db, $curtables, $nary_pos)) {
+					} elseif ($table = $this->addJoin('PAGE', $from, $where, $db, $curtables, $nary_pos)) {
+						if ($where != '') $where .= ' AND ';
 						$where .= $table . '.page_title=' . $db->addQuotes($page->getDBKey()) . ' AND ' .
 						          $table . '.page_namespace=' . $page->getNamespace();
 					}
 				break;
 				default:
-					if ( $table = $this->addJoin('pATTS', $from, $db, $curtables, $nary_pos) ) {
+					if ( $table = $this->addJoin('pATTS', $from, $where, $db, $curtables, $nary_pos) ) {
 						switch ($description->getComparator()) {
 							case SMW_CMP_LEQ: $op = '<='; break;
 							case SMW_CMP_GEQ: $op = '>='; break;
@@ -1638,6 +1662,7 @@ class SMWSQLStore extends SMWStore {
 							$valuefield = 'value_xsd';
 							$value = $description->getDatavalue()->getXSDValue();
 						}
+						if ($where != '') $where .= ' AND ';
 						///TODO: implement check for unit
 						$where .= $table . '.' .  $valuefield . $op . $db->addQuotes($value);
 					}
@@ -1664,7 +1689,7 @@ class SMWSQLStore extends SMWStore {
 				if ( array_key_exists('PAGE', $curtables) ) {
 					$nexttables['PAGE'] = $curtables['PAGE'];
 				}
-				if ($this->addJoin('pRELS', $from, $db, $curtables, $nary_pos)) {
+				if ($this->addJoin('pRELS', $from, $where, $db, $curtables, $nary_pos)) {
 					$nexttables['pRELS'] = $curtables['pRELS'];
 				}
 				$this->createSQLQuery($subdesc, $from, $subwhere, $db, $nexttables, $nary_pos);
@@ -1687,6 +1712,16 @@ class SMWSQLStore extends SMWStore {
 					$subwhere = '';
 				}
 			}
+		} elseif ($description instanceof SMWNegation) {
+			$intfrom = $db->tableName('page');
+			$intwhere = '';
+			$this->createSQLQuery($description->getDescription(), $intfrom, $subwhere, $db, $curtables, $nary_pos);
+			if ($subwhere != '') {
+				if ($where != '') $where .= ' AND ';
+				// $intfrom includes `page`, but we want to take the page ref from the outer query, so we remove it from the inner one
+				$cleansed_from = str_replace($db->tableName('page').',', '', $intfrom);
+				$where .= 'NOT EXISTS (SELECT 1 FROM '.$cleansed_from.' WHERE ' . $subwhere . ')';
+			}
 		} elseif ($description instanceof SMWSomeProperty) {
 			$id = SMWDataValueFactory::getPropertyObjectTypeID($description->getProperty());
 			$sort = false;
@@ -1721,12 +1756,13 @@ class SMWSQLStore extends SMWStore {
 						}
 					}
 			}
-			if ($table = $this->addJoin($tablename, $from, $db, $curtables, $nary_pos)) {
+			if ($table = $this->addJoin($tablename, $from, $where, $db, $curtables, $nary_pos)) {
 				global $smwgQSubpropertyDepth;
 				if ($smwgQSubpropertyDepth > 0) {
 					$pt = $this->getPropertyTable($description->getProperty()->getDBKey(), $db);
 					$from = '`' . $pt . '`, ' . $from;
-					$where = "$pt.title=" . $table . '.' . $pcolumn;
+					if ($where != '') $where .= ' AND ';
+					$where .= "$pt.title=" . $table . '.' . $pcolumn;
 				} else {
 					$where .= $table . '.' . $pcolumn . '=' .
 					          $db->addQuotes($description->getProperty()->getDBKey());
@@ -1739,7 +1775,8 @@ class SMWSQLStore extends SMWStore {
 						$this->m_sortfield = "$table.$sort";
 					}
 					if ( $subwhere != '') {
-						$where .= ' AND (' . $subwhere . ')';
+						if ($where != '') $where .= ' AND ';
+						$where .= '(' . $subwhere . ')';
 					}
 				}
 			}
-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
_______________________________________________
Semediawiki-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/semediawiki-devel

Reply via email to