[tracker/rtcom: 3/5] SPARQL: Fix variable handling in scalar subqueries
- From: Jürg Billeter <juergbi src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [tracker/rtcom: 3/5] SPARQL: Fix variable handling in scalar subqueries
- Date: Tue, 18 May 2010 14:00:25 +0000 (UTC)
commit 704a68466874da6dea71db0b49a5598eaafeeb31
Author: Jürg Billeter <j bitron ch>
Date: Mon May 17 13:02:11 2010 +0200
SPARQL: Fix variable handling in scalar subqueries
Scalar subqueries may only capture variables of very specific outer
scopes.
src/libtracker-data/tracker-sparql-pattern.vala | 32 ++++++++++----------
src/libtracker-data/tracker-sparql-query.vala | 17 ++++-------
.../libtracker-data/algebra/two-nested-opt-alt.rq | 2 +-
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 552d423..008faf0 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 4cf5cbd..0a9867b 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) {
@@ -525,16 +524,12 @@ public class Tracker.Sparql.Query : Object {
string get_select_query () 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 sql.str;
}
@@ -645,7 +640,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 {
@@ -688,10 +683,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 3c6820d..82125a2 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 71b4046..39d351b 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
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]