* 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.
The patch is
--- a/extensions/SemanticMediaWiki/includes/SMW_QueryProcessor.php
+++ b/extensions/SemanticMediaWiki/includes/SMW_QueryProcessor.php
@@ -296,6 +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 '<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
+ case '</n>':
+ break;
case '||': case '': case '</q>': // finish
disjunction and maybe subquery
if ($this->m_defaultns !== NULL) { //
possibly add namespace restrictions
if ( $hasNamespaces &&
!$mustSetNS) {
@@ -738,7 +746,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 '<n>' . $this->m_description->getQueryString() .
'</n>';
+ }
+
+ 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
@@ -1687,6 +1687,18 @@ class SMWSQLStore extends SMWStore {
$subwhere = '';
}
}
+ } elseif ($description instanceof SMWNegation) {
+ $intpagetable = $db->tableName('page');
+ $intfrom = $intpagetable;
+ $intwhere = '';
+ $intcurtables = array('PAGE' => $intfrom);
+ $this->createSQLQuery($description->getDescription(),
$intfrom, $subwhere, $db, $intcurtables, $nary_pos);
+ if ($subwhere != '') {
+ if ($where != '') {
+ $where .= ' AND ';
+ }
+ $where .= 'NOT EXISTS (SELECT 1 FROM
'.$intfrom.' WHERE ' . $subwhere . ')';
+ }
} elseif ($description instanceof SMWSomeProperty) {
$id =
SMWDataValueFactory::getPropertyObjectTypeID($description->getProperty());
$sort = false;
Unfortunately, in the limited time I had, I couldn't get the code to
output correct SQL, so I just hope that someone can pick up the pieces
and rework it into something functioning. I'm also not really sure what
should be passed to createSQLQuery.
I took the very simple query <ask><n>[[Motto::+]]</n></ask>, which
should output every page for which that attribute is not defined.
The SQL is
SELECT DISTINCT `page`.page_title as title, `page`.page_namespace as
namespace FROM `page` WHERE ((`page`.page_namespace='0') OR
(`page`.page_namespace='6')) AND (NOT EXISTS (SELECT 1 FROM `prop1`,
`page` INNER JOIN `smw_attributes` AS att0 ON
^^^^^^
att0.subject_id=`page`.page_id WHERE prop1.title=att0.attribute_title))
ORDER BY `page`.page_title ASC
The marked part is the problem. The inner SELECT should use the `page`
from the outer query. But if this declaration is omitted, the SQL
becomes invalid (because of the LEFT JOIN). Therefore, the LEFT JOIN
should be changed to a simple SELECT with a condition in this case.
So the query should be
SELECT DISTINCT `page`.page_title as title, `page`.page_namespace as
namespace FROM `page` WHERE ((`page`.page_namespace='0') OR
(`page`.page_namespace='6')) AND (NOT EXISTS (SELECT 1 FROM `prop1`,
`smw_attributes` AS att0 WHERE
att0.subject_id=`page`.page_id AND prop1.title=att0.attribute_title))
ORDER BY `page`.page_title ASC
Not sure how to do this with the current code.
Any suggestions?
Thomas
-------------------------------------------------------------------------
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