[tracker/subqueries] SPARQL: Scalar subqueries



commit e113020139a2bfe5d9d17f18783833e2581ddf55
Author: Jürg Billeter <j bitron ch>
Date:   Fri Dec 4 19:04:38 2009 +0100

    SPARQL: Scalar subqueries

 src/libtracker-data/tracker-sparql-query.vala |  114 ++++++++++++++++++++-----
 1 files changed, 94 insertions(+), 20 deletions(-)
---
diff --git a/src/libtracker-data/tracker-sparql-query.vala b/src/libtracker-data/tracker-sparql-query.vala
index fd6cd09..2049ae9 100644
--- a/src/libtracker-data/tracker-sparql-query.vala
+++ b/src/libtracker-data/tracker-sparql-query.vala
@@ -48,6 +48,18 @@ public class Tracker.SparqlQuery : Object {
 		public PropertyType data_type;
 		public DataTable table;
 		public string sql_db_column_name;
+		public string sql_expression {
+			get {
+				if (this._sql_expression == null) {
+					this._sql_expression = "\"%s\".\"%s\"".printf (table.sql_query_tablename, sql_db_column_name);
+				}
+				return this._sql_expression;
+			}
+			set {
+				this._sql_expression = value;
+			}
+		}
+		string? _sql_expression;
 	}
 
 	// Represents a mapping of a SPARQL literal to a SQL table and column
@@ -256,6 +268,8 @@ public class Tracker.SparqlQuery : Object {
 	List<Variable> pattern_variables;
 	HashTable<Variable,VariableBindingList> pattern_var_map;
 
+	HashTable<string,Variable> outer_var_map;
+
 	// All SPARQL variables within a subgraph pattern (used by UNION)
 	HashTable<Variable,int> subgraph_var_set;
 
@@ -555,9 +569,31 @@ public class Tracker.SparqlQuery : Object {
 		return stmt.execute ();
 	}
 
+	void skip_bracketted_expression () throws SparqlError {
+		expect (SparqlTokenType.OPEN_PARENS);
+		while (true) {
+			switch (current ()) {
+			case SparqlTokenType.OPEN_PARENS:
+				// skip nested bracketted expression
+				skip_bracketted_expression ();
+				continue;
+			case SparqlTokenType.CLOSE_PARENS:
+				break;
+			default:
+				next ();
+				continue;
+			}
+			break;
+		}
+		expect (SparqlTokenType.CLOSE_PARENS);
+	}
+
 	void skip_select_variables () throws SparqlError {
 		while (true) {
 			switch (current ()) {
+			case SparqlTokenType.OPEN_PARENS:
+				skip_bracketted_expression ();
+				continue;
 			case SparqlTokenType.FROM:
 			case SparqlTokenType.WHERE:
 			case SparqlTokenType.OPEN_BRACE:
@@ -1750,6 +1786,27 @@ public class Tracker.SparqlQuery : Object {
 
 	PropertyType translate_bracketted_expression (StringBuilder sql) throws SparqlError {
 		expect (SparqlTokenType.OPEN_PARENS);
+
+		if (current () == SparqlTokenType.SELECT) {
+			// FIXME ensure that inner variables are only exported if selected
+
+			outer_var_map = var_map;
+			var outer_predicate_variable_map = predicate_variable_map;
+			var outer_used_sql_identifiers = used_sql_identifiers;
+			begin_query ();
+
+			sql.append ("(");
+			translate_select (sql, true);
+			sql.append (")");
+
+			var_map = outer_var_map;
+			predicate_variable_map = outer_predicate_variable_map;
+			used_sql_identifiers = outer_used_sql_identifiers;
+
+			expect (SparqlTokenType.CLOSE_PARENS);
+			return PropertyType.UNKNOWN;
+		}
+
 		var optype = translate_expression (sql);
 		expect (SparqlTokenType.CLOSE_PARENS);
 		return optype;
@@ -2012,7 +2069,7 @@ public class Tracker.SparqlQuery : Object {
 			foreach (VariableBinding binding in pattern_var_map.lookup (variable).list) {
 				string name;
 				if (binding.table != null) {
-					name = "\"%s\".\"%s\"".printf (binding.table.sql_query_tablename, binding.sql_db_column_name);
+					name = binding.sql_expression;
 				} else {
 					// simple optional with inverse functional property
 					// always first in loop as variable is required to be unbound
@@ -2055,11 +2112,7 @@ public class Tracker.SparqlQuery : Object {
 				sql.append (" WHERE ");
 				first_where = false;
 			}
-			sql.append ("\"");
-			sql.append (binding.table.sql_query_tablename);
-			sql.append ("\".\"");
-			sql.append (binding.sql_db_column_name);
-			sql.append ("\"");
+			sql.append (binding.sql_expression);
 			if (binding.is_fts_match) {
 				// parameters do not work with fts MATCH
 				string escaped_literal = string.joinv ("''", binding.literal.split ("'"));
@@ -2465,6 +2518,30 @@ public class Tracker.SparqlQuery : Object {
 		subgraph_var_set = old_subgraph_var_set;
 	}
 
+	VariableBindingList? get_variable_binding_list (Variable variable) {
+		var binding_list = pattern_var_map.lookup (variable);
+		if (binding_list == null && outer_var_map != null) {
+			// in scalar subquery: check variables of outer query
+			var outer_var = outer_var_map.lookup (variable.name);
+			if (outer_var != null) {
+				// capture outer variable
+				var binding = new VariableBinding ();
+				binding.data_type = outer_var.binding.data_type;
+				binding.variable = get_variable (variable.name);
+				binding.type = outer_var.binding.type;
+				binding.sql_expression = outer_var.sql_expression;
+				binding_list = new VariableBindingList ();
+				pattern_variables.append (binding.variable);
+				pattern_var_map.insert (binding.variable, binding_list);
+
+				subgraph_var_set.insert (binding.variable, VariableState.BOUND);
+				binding_list.list.append (binding);
+				binding.variable.binding = binding;
+			}
+		}
+		return binding_list;
+	}
+
 	void parse_object (StringBuilder sql, bool in_simple_optional = false) throws SparqlError {
 		bool object_is_var;
 		string object = parse_var_or_term (sql, out object_is_var);
@@ -2544,10 +2621,10 @@ public class Tracker.SparqlQuery : Object {
 					// need to use table and column name for object, can't refer to variable in nested select
 					var object_binding = pattern_var_map.lookup (get_variable (object)).list.data;
 
-					sql.append_printf ("(SELECT ID FROM \"%s\" WHERE \"%s\" = \"%s\".\"%s\") AS %s, ",
+					sql.append_printf ("(SELECT ID FROM \"%s\" WHERE \"%s\" = %s) AS %s, ",
 						db_table,
 						prop.name,
-						object_binding.table.sql_query_tablename, object_binding.sql_db_column_name,
+						object_binding.sql_expression,
 						binding.variable.sql_expression);
 
 					subgraph_var_set.insert (binding.variable, VariableState.OPTIONAL);
@@ -2586,15 +2663,14 @@ public class Tracker.SparqlQuery : Object {
 			binding.variable = get_variable (current_predicate);
 			binding.table = table;
 			binding.sql_db_column_name = "predicate";
-			var binding_list = pattern_var_map.lookup (binding.variable);
+			var binding_list = get_variable_binding_list (binding.variable);
 			if (binding_list == null) {
 				binding_list = new VariableBindingList ();
 				pattern_variables.append (binding.variable);
 				pattern_var_map.insert (binding.variable, binding_list);
 
-				sql.append_printf ("\"%s\".\"%s\" AS %s, ",
-					binding.table.sql_query_tablename,
-					binding.sql_db_column_name,
+				sql.append_printf ("%s AS %s, ",
+					binding.sql_expression,
 					binding.variable.sql_expression);
 
 				subgraph_var_set.insert (binding.variable, VariableState.BOUND);
@@ -2617,15 +2693,14 @@ public class Tracker.SparqlQuery : Object {
 				} else {
 					binding.sql_db_column_name = "ID";
 				}
-				var binding_list = pattern_var_map.lookup (binding.variable);
+				var binding_list = get_variable_binding_list (binding.variable);
 				if (binding_list == null) {
 					binding_list = new VariableBindingList ();
 					pattern_variables.append (binding.variable);
 					pattern_var_map.insert (binding.variable, binding_list);
 
-					sql.append_printf ("\"%s\".\"%s\" AS %s, ",
-						binding.table.sql_query_tablename,
-						binding.sql_db_column_name,
+					sql.append_printf ("%s AS %s, ",
+						binding.sql_expression,
 						binding.variable.sql_expression);
 
 					subgraph_var_set.insert (binding.variable, VariableState.BOUND);
@@ -2668,15 +2743,14 @@ public class Tracker.SparqlQuery : Object {
 					binding.maybe_null = true;
 				}
 
-				var binding_list = pattern_var_map.lookup (binding.variable);
+				var binding_list = get_variable_binding_list (binding.variable);
 				if (binding_list == null) {
 					binding_list = new VariableBindingList ();
 					pattern_variables.append (binding.variable);
 					pattern_var_map.insert (binding.variable, binding_list);
 
-					sql.append_printf ("\"%s\".\"%s\" AS %s, ",
-						binding.table.sql_query_tablename,
-						binding.sql_db_column_name,
+					sql.append_printf ("%s AS %s, ",
+						binding.sql_expression,
 						binding.variable.sql_expression);
 
 					VariableState state;



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