[tracker/exists: 1/2] SPARQL: Add support for EXISTS and NOT EXISTS



commit 27295e61425fb02c94f30416c29d3f37c2a1cc60
Author: Jürg Billeter <j bitron ch>
Date:   Mon Jul 12 11:58:43 2010 +0200

    SPARQL: Add support for EXISTS and NOT EXISTS

 src/libtracker-data/tracker-sparql-expression.vala |   12 ++++++
 src/libtracker-data/tracker-sparql-pattern.vala    |   38 ++++++++++++++++++++
 src/libtracker-data/tracker-sparql-scanner.vala    |   12 ++++++
 3 files changed, 62 insertions(+), 0 deletions(-)
---
diff --git a/src/libtracker-data/tracker-sparql-expression.vala b/src/libtracker-data/tracker-sparql-expression.vala
index ea5052f..4325fcd 100644
--- a/src/libtracker-data/tracker-sparql-expression.vala
+++ b/src/libtracker-data/tracker-sparql-expression.vala
@@ -224,6 +224,12 @@ class Tracker.Sparql.Expression : Object {
 		expect (SparqlTokenType.CLOSE_PARENS);
 	}
 
+	void translate_exists (StringBuilder sql) throws SparqlError {
+		sql.append ("(");
+		pattern.translate_exists (sql);
+		sql.append (")");
+	}
+
 	internal static void append_expression_as_string (StringBuilder sql, string expression, PropertyType type) {
 		long begin = sql.len;
 		sql.append (expression);
@@ -920,6 +926,10 @@ class Tracker.Sparql.Expression : Object {
 		case SparqlTokenType.REGEX:
 			translate_regex (sql);
 			return PropertyType.BOOLEAN;
+		case SparqlTokenType.EXISTS:
+		case SparqlTokenType.NOT:
+			translate_exists (sql);
+			return PropertyType.BOOLEAN;
 		case SparqlTokenType.COUNT:
 			next ();
 			sql.append ("COUNT(");
@@ -1185,6 +1195,8 @@ class Tracker.Sparql.Expression : Object {
 		case SparqlTokenType.ISBLANK:
 		case SparqlTokenType.ISLITERAL:
 		case SparqlTokenType.REGEX:
+		case SparqlTokenType.EXISTS:
+		case SparqlTokenType.NOT:
 			return translate_primary_expression (sql);
 		default:
 			return translate_bracketted_expression (sql);
diff --git a/src/libtracker-data/tracker-sparql-pattern.vala b/src/libtracker-data/tracker-sparql-pattern.vala
index 39e4db5..c0d8f5d 100644
--- a/src/libtracker-data/tracker-sparql-pattern.vala
+++ b/src/libtracker-data/tracker-sparql-pattern.vala
@@ -416,6 +416,44 @@ class Tracker.Sparql.Pattern : Object {
 		return result;
 	}
 
+	internal void translate_exists (StringBuilder sql) throws SparqlError {
+		bool not = accept (SparqlTokenType.NOT);
+		expect (SparqlTokenType.EXISTS);
+
+		SelectContext result;
+		result = new SelectContext.subquery (context);
+		context = result;
+
+		var pattern_sql = new StringBuilder ();
+
+		sql.append ("SELECT ");
+
+		var pattern = translate_group_graph_pattern (pattern_sql);
+		foreach (var key in pattern.var_set.get_keys ()) {
+			context.var_set.insert (key, VariableState.BOUND);
+		}
+
+		// report use of undefined variables
+		foreach (var variable in context.var_set.get_keys ()) {
+			if (variable.binding == null) {
+				throw get_error ("use of undefined variable `%s'".printf (variable.name));
+			}
+		}
+
+		if (not) {
+			// NOT EXISTS
+			sql.append ("COUNT(1) = 0");
+		} else {
+			// EXISTS
+			sql.append ("COUNT(1) > 0");
+		}
+
+		// select from results of WHERE clause
+		sql.append (" FROM (");
+		sql.append (pattern_sql.str);
+		sql.append (")");
+	}
+
 	internal string parse_var_or_term (StringBuilder? sql, out bool is_var) throws SparqlError {
 		string result = "";
 		is_var = false;
diff --git a/src/libtracker-data/tracker-sparql-scanner.vala b/src/libtracker-data/tracker-sparql-scanner.vala
index a42c60e..d803045 100644
--- a/src/libtracker-data/tracker-sparql-scanner.vala
+++ b/src/libtracker-data/tracker-sparql-scanner.vala
@@ -98,6 +98,10 @@ public class Tracker.SparqlScanner : Object {
 					break;
 				}
 				break;
+			case 'N':
+			case 'n':
+				if (matches (begin, "NOT")) return SparqlTokenType.NOT;
+				break;
 			case 'S':
 			case 's':
 				switch (begin[1]) {
@@ -236,6 +240,10 @@ public class Tracker.SparqlScanner : Object {
 			case 'd':
 				if (matches (begin, "DELETE")) return SparqlTokenType.DELETE;
 				break;
+			case 'E':
+			case 'e':
+				if (matches (begin, "EXISTS")) return SparqlTokenType.EXISTS;
+				break;
 			case 'F':
 			case 'f':
 				if (matches (begin, "FILTER")) return SparqlTokenType.FILTER;
@@ -822,6 +830,7 @@ public enum Tracker.SparqlTokenType {
 	DOUBLE_CIRCUMFLEX,
 	DROP,
 	EOF,
+	EXISTS,
 	FALSE,
 	FILTER,
 	FROM,
@@ -843,6 +852,7 @@ public enum Tracker.SparqlTokenType {
 	MIN,
 	MINUS,
 	NAMED,
+	NOT,
 	OFFSET,
 	OP_AND,
 	OP_EQ,
@@ -910,6 +920,7 @@ public enum Tracker.SparqlTokenType {
 		case DOUBLE_CIRCUMFLEX: return "`^^'";
 		case DROP: return "`DROP'";
 		case EOF: return "end of file";
+		case EXISTS: return "`EXISTS'";
 		case FALSE: return "`false'";
 		case FILTER: return "`FILTER'";
 		case FROM: return "`FROM'";
@@ -931,6 +942,7 @@ public enum Tracker.SparqlTokenType {
 		case MIN: return "`MIN'";
 		case MINUS: return "`-'";
 		case NAMED: return "`NAMED'";
+		case NOT: return "`NOT'";
 		case OFFSET: return "`OFFSET'";
 		case OP_AND: return "`&&'";
 		case OP_EQ: return "`='";



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]