* 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 '&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
@@ -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

Reply via email to