[tracker/wip/carlosg/unbound-vars: 2/3] libtracker-data: Handle unbound variables in resultsets




commit fc69eaa2d7825cce696541f6824021df00593b32
Author: Carlos Garnacho <carlosg gnome org>
Date:   Sat Aug 29 14:28:08 2020 +0200

    libtracker-data: Handle unbound variables in resultsets
    
    We error out on undefined variables, SPARQL 1.1 does not seem to have
    a problem with that, and e.g. https://www.w3.org/TR/sparql11-query/#emptyGroupPattern
    specifically says this query is valid:
    
      SELECT ?x WHERE { }
    
    Soften our restriction so these queries work as specified in the docs.

 src/libtracker-data/tracker-sparql.c | 82 ++++++++++++++++++++++++------------
 1 file changed, 54 insertions(+), 28 deletions(-)
---
diff --git a/src/libtracker-data/tracker-sparql.c b/src/libtracker-data/tracker-sparql.c
index 91382f5db..d372ccfc7 100644
--- a/src/libtracker-data/tracker-sparql.c
+++ b/src/libtracker-data/tracker-sparql.c
@@ -2672,40 +2672,53 @@ translate_SelectClause (TrackerSparql  *sparql,
        } else {
                do {
                        TrackerVariable *var;
-                       TrackerBinding *binding;
 
                        if (_check_in_rule (sparql, NAMED_RULE_Var)) {
+                               gchar *name;
+                               gboolean found;
+
                                if (!first)
                                        _append_string (sparql, ", ");
 
                                _call_rule (sparql, NAMED_RULE_Var, error);
-                               var = _last_node_variable (sparql);
-
-                               if (!tracker_variable_has_bindings (var)) {
-                                       _raise (PARSE, "Undefined variable", var->name);
-                               }
-
-                               binding = TRACKER_BINDING (tracker_variable_get_sample_binding (var));
+                               name = _dup_last_string (sparql);
 
                                str = _append_placeholder (sparql);
                                old = tracker_sparql_swap_builder (sparql, str);
 
-                               _append_string_printf (sparql, "%s ",
-                                                      tracker_variable_get_sql_expression (var));
+                               found = tracker_context_lookup_variable_by_name 
(sparql->current_state.context,
+                                                                                name);
+                               var = _last_node_variable (sparql);
+
+                               if (found) {
+                                       _append_string_printf (sparql, "%s ",
+                                                              tracker_variable_get_sql_expression (var));
 
-                               if (sparql->current_state.select_context == sparql->context)
-                                       convert_expression_to_string (sparql, binding->data_type);
+                                       if (sparql->current_state.select_context == sparql->context)
+                                               convert_expression_to_string (sparql, 
sparql->current_state.expression_type);
 
-                               select_context->type = binding->data_type;
+                                       select_context->type = sparql->current_state.expression_type;
+                               } else {
+                                       _append_string (sparql, "NULL ");
+                                       select_context->type = TRACKER_PROPERTY_TYPE_UNKNOWN;
+                               }
 
                                if (_accept (sparql, RULE_TYPE_LITERAL, LITERAL_AS)) {
-                                       if (!handle_as (sparql, binding->data_type, error))
+                                       if (!handle_as (sparql, select_context->type, error)) {
+                                               g_free (name);
                                                return FALSE;
+                                       }
                                } else {
-                                       tracker_sparql_add_select_var (sparql, var->name, binding->data_type);
+                                       if (!found) {
+                                               _append_string_printf (sparql, "AS %s ",
+                                                                      tracker_variable_get_sql_expression 
(var));
+                                       }
+
+                                       tracker_sparql_add_select_var (sparql, name, select_context->type);
                                }
 
                                tracker_sparql_swap_builder (sparql, old);
+                               g_free (name);
                        } else {
                                gboolean parens = FALSE;
 
@@ -2990,9 +3003,6 @@ translate_SelectQuery (TrackerSparql  *sparql,
 
        _call_rule (sparql, NAMED_RULE_WhereClause, error);
 
-       if (!_check_undefined_variables (sparql, TRACKER_SELECT_CONTEXT (sparql->context), error))
-               return FALSE;
-
        _call_rule (sparql, NAMED_RULE_SolutionModifier, error);
 
        tracker_sparql_swap_builder (sparql, old);
@@ -7020,14 +7030,20 @@ translate_Var (TrackerSparql  *sparql,
            _accept (sparql, RULE_TYPE_TERMINAL, TERMINAL_TYPE_VAR2)) {
                if (sparql->current_state.type == TRACKER_SPARQL_TYPE_SELECT ||
                    sparql->current_state.type == TRACKER_SPARQL_TYPE_CONSTRUCT) {
-                       TrackerVariableBinding *binding;
+                       TrackerVariableBinding *binding = NULL;
                        TrackerVariable *var;
+                       gchar *name;
 
                        /* Ensure the variable is referenced in the context */
-                       var = _extract_node_variable (sparql->current_state.prev_node,
-                                                     sparql);
+                       name = _dup_last_string (sparql);
+                       var = tracker_select_context_lookup_variable (TRACKER_SELECT_CONTEXT 
(sparql->context),
+                                                                     name);
+                       g_free (name);
 
-                       binding = tracker_variable_get_sample_binding (var);
+                       sparql->current_state.expression_type = TRACKER_PROPERTY_TYPE_UNKNOWN;
+
+                       if (var)
+                               binding = tracker_variable_get_sample_binding (var);
 
                        if (binding)
                                sparql->current_state.expression_type = TRACKER_BINDING (binding)->data_type;
@@ -7348,6 +7364,7 @@ translate_PrimaryExpression (TrackerSparql  *sparql,
        TrackerGrammarNamedRule rule;
        TrackerBinding *binding;
        TrackerVariable *variable;
+       gchar *name;
 
        /* PrimaryExpression ::= BrackettedExpression | BuiltInCall | iriOrFunction | RDFLiteral | 
NumericLiteral | BooleanLiteral | Var
         */
@@ -7366,14 +7383,23 @@ translate_PrimaryExpression (TrackerSparql  *sparql,
                break;
        case NAMED_RULE_Var:
                _call_rule (sparql, rule, error);
-               variable = _last_node_variable (sparql);
-               _append_variable_sql (sparql, variable);
+               name = _dup_last_string (sparql);
 
-               /* If the variable is bound, propagate the binding data type */
-               if (tracker_variable_has_bindings (variable)) {
-                       binding = TRACKER_BINDING (tracker_variable_get_sample_binding (variable));
-                       sparql->current_state.expression_type = binding->data_type;
+               if (tracker_context_lookup_variable_by_name (sparql->current_state.context,
+                                                            name)) {
+                       variable = _last_node_variable (sparql);
+                       _append_variable_sql (sparql, variable);
+
+                       /* If the variable is bound, propagate the binding data type */
+                       if (tracker_variable_has_bindings (variable)) {
+                               binding = TRACKER_BINDING (tracker_variable_get_sample_binding (variable));
+                               sparql->current_state.expression_type = binding->data_type;
+                       }
+               } else {
+                       _append_string (sparql, "NULL ");
                }
+
+               g_free (name);
                break;
        case NAMED_RULE_RDFLiteral:
                _call_rule (sparql, rule, error);


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