diff options
author | Jürg Billeter <j@bitron.ch> | 2010-05-17 13:02:11 +0200 |
---|---|---|
committer | Martyn Russell <martyn@lanedo.com> | 2010-05-20 16:17:45 +0100 |
commit | 2e6088a94a8e5c7d29f3fca68e576e577d3a3ae4 (patch) | |
tree | bc2fd0e417643807104a1f7ecfd14e01aa1f4fa7 | |
parent | f0bc7768ca1072a5adba24e9ac4382b6d9762fc2 (diff) | |
download | tracker-2e6088a94a8e5c7d29f3fca68e576e577d3a3ae4.tar.gz |
SPARQL: Fix variable handling in scalar subqueries
Scalar subqueries may only capture variables of very specific outer
scopes.
-rw-r--r-- | src/libtracker-data/tracker-sparql-pattern.vala | 32 | ||||
-rw-r--r-- | src/libtracker-data/tracker-sparql-query.vala | 17 | ||||
-rw-r--r-- | tests/libtracker-data/algebra/two-nested-opt-alt.rq | 2 | ||||
-rw-r--r-- | tests/libtracker-data/algebra/two-nested-opt.rq | 2 |
4 files changed, 24 insertions, 29 deletions
diff --git a/src/libtracker-data/tracker-sparql-pattern.vala b/src/libtracker-data/tracker-sparql-pattern.vala index 552d423a1..008faf0be 100644 --- a/src/libtracker-data/tracker-sparql-pattern.vala +++ b/src/libtracker-data/tracker-sparql-pattern.vala @@ -266,7 +266,7 @@ class Tracker.Sparql.Pattern : Object { set_location (select_variables_location); // report use of undefined variables - foreach (var variable in context.var_map.get_values ()) { + foreach (var variable in context.var_set.get_keys ()) { if (variable.binding == null) { throw get_error ("use of undefined variable `%s'".printf (variable.name)); } @@ -277,7 +277,7 @@ class Tracker.Sparql.Pattern : Object { bool first = true; if (accept (SparqlTokenType.STAR)) { - foreach (var variable in context.var_map.get_values ()) { + foreach (var variable in context.var_set.get_keys ()) { if (!first) { sql.append (", "); } else { @@ -1091,30 +1091,30 @@ class Tracker.Sparql.Pattern : Object { if (triple_context != null) { binding_list = triple_context.var_bindings.lookup (variable); } - if (binding_list == null && context.in_scalar_subquery) { - // in scalar subquery: check variables of outer queries - var parent_context = context.parent_context; - while (parent_context != null) { - var outer_var = parent_context.var_map.lookup (variable.name); - if (outer_var != null && outer_var.binding != null) { + if (binding_list == null && variable.binding != null) { + // might be in scalar subquery: check variables of outer queries + var current_context = context; + while (current_context != null) { + // only allow access to variables of immediate parent context of the subquery + // allowing access to other variables leads to invalid SQL or wrong results + if (current_context.scalar_subquery && current_context.parent_context.var_set.lookup (variable) != 0) { // capture outer variable var binding = new VariableBinding (); - binding.data_type = outer_var.binding.data_type; + binding.data_type = variable.binding.data_type; binding.variable = context.get_variable (variable.name); - binding.type = outer_var.binding.type; - binding.sql_expression = outer_var.sql_expression; + binding.type = variable.binding.type; + binding.sql_expression = variable.sql_expression; binding_list = new VariableBindingList (); if (triple_context != null) { - triple_context.variables.append (binding.variable); - triple_context.var_bindings.insert (binding.variable, binding_list); + triple_context.variables.append (variable); + triple_context.var_bindings.insert (variable, binding_list); } - context.var_set.insert (binding.variable, VariableState.BOUND); + context.var_set.insert (variable, VariableState.BOUND); binding_list.list.append (binding); - binding.variable.binding = binding; break; } - parent_context = parent_context.parent_context; + current_context = current_context.parent_context; } } return binding_list; diff --git a/src/libtracker-data/tracker-sparql-query.vala b/src/libtracker-data/tracker-sparql-query.vala index 3659ae6c1..07fe90f95 100644 --- a/src/libtracker-data/tracker-sparql-query.vala +++ b/src/libtracker-data/tracker-sparql-query.vala @@ -113,7 +113,7 @@ namespace Tracker.Sparql { // Keep track of used sql identifiers to avoid using the same for multiple SPARQL variables public HashTable<string,bool> used_sql_identifiers; - public bool in_scalar_subquery; + public bool scalar_subquery; public Context (Context? parent_context = null) { this.parent_context = parent_context; @@ -129,7 +129,6 @@ namespace Tracker.Sparql { var_map = parent_context.var_map; predicate_variable_map = parent_context.predicate_variable_map; used_sql_identifiers = parent_context.used_sql_identifiers; - in_scalar_subquery = parent_context.in_scalar_subquery; } } @@ -138,10 +137,10 @@ namespace Tracker.Sparql { this.var_set = new HashTable<Variable,int>.full (direct_hash, direct_equal, g_object_unref, null); select_var_set = new HashTable<Variable,int>.full (direct_hash, direct_equal, g_object_unref, null); - var_map = new HashTable<string,Variable>.full (str_hash, str_equal, g_free, g_object_unref); + var_map = parent_context.var_map; predicate_variable_map = new HashTable<Variable,PredicateVariable>.full (direct_hash, direct_equal, g_object_unref, g_object_unref); used_sql_identifiers = new HashTable<string,bool>.full (str_hash, str_equal, g_free, null); - in_scalar_subquery = true; + scalar_subquery = true; } internal unowned Variable get_variable (string name) { @@ -485,16 +484,12 @@ public class Tracker.Sparql.Query : Object { DBResultSet? execute_select () throws DBInterfaceError, SparqlError, DateError { // SELECT query - context = new Context (); - // build SQL var sql = new StringBuilder (); pattern.translate_select (sql); expect (SparqlTokenType.EOF); - context = context.parent_context; - return exec_sql (sql.str); } @@ -589,7 +584,7 @@ public class Tracker.Sparql.Query : Object { // build SQL sql.append ("SELECT "); bool first = true; - foreach (var variable in context.var_map.get_values ()) { + foreach (var variable in context.var_set.get_keys ()) { if (!first) { sql.append (", "); } else { @@ -632,10 +627,10 @@ public class Tracker.Sparql.Query : Object { // get values of all variables to be bound var var_value_map = new HashTable<string,string>.full (str_hash, str_equal, g_free, g_free); int var_idx = 0; - foreach (string var_name in context.var_map.get_keys ()) { + foreach (var variable in context.var_set.get_keys ()) { Value value; result_set._get_value (var_idx++, out value); - var_value_map.insert (var_name, get_string_for_value (value)); + var_value_map.insert (variable.name, get_string_for_value (value)); } set_location (template_location); diff --git a/tests/libtracker-data/algebra/two-nested-opt-alt.rq b/tests/libtracker-data/algebra/two-nested-opt-alt.rq index 3c6820deb..82125a298 100644 --- a/tests/libtracker-data/algebra/two-nested-opt-alt.rq +++ b/tests/libtracker-data/algebra/two-nested-opt-alt.rq @@ -2,7 +2,7 @@ PREFIX : <http://example/> ## The nested optional example, rewritten to a form that is the same ## for the SPARQL algebra and the declarative semantics. -SELECT * +SELECT ?v ?w { :x1 :p ?v . OPTIONAL { :x3 :q ?w } diff --git a/tests/libtracker-data/algebra/two-nested-opt.rq b/tests/libtracker-data/algebra/two-nested-opt.rq index 71b40469d..39d351b2d 100644 --- a/tests/libtracker-data/algebra/two-nested-opt.rq +++ b/tests/libtracker-data/algebra/two-nested-opt.rq @@ -1,6 +1,6 @@ PREFIX : <http://example/> -SELECT * +SELECT ?v ?w { :x1 :p ?v . OPTIONAL |