summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJürg Billeter <j@bitron.ch>2010-05-17 13:02:11 +0200
committerMartyn Russell <martyn@lanedo.com>2010-05-20 16:17:45 +0100
commit2e6088a94a8e5c7d29f3fca68e576e577d3a3ae4 (patch)
treebc2fd0e417643807104a1f7ecfd14e01aa1f4fa7
parentf0bc7768ca1072a5adba24e9ac4382b6d9762fc2 (diff)
downloadtracker-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.vala32
-rw-r--r--src/libtracker-data/tracker-sparql-query.vala17
-rw-r--r--tests/libtracker-data/algebra/two-nested-opt-alt.rq2
-rw-r--r--tests/libtracker-data/algebra/two-nested-opt.rq2
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