[tracker/wip/carlosg/sparql-parser-ng: 39/50] libtracker-data: Support parameter bindings



commit 216a7d1dfd1cd02702e48d391c341148aedeee87
Author: Carlos Garnacho <carlosg gnome org>
Date:   Sun Oct 14 11:23:35 2018 +0200

    libtracker-data: Support parameter bindings
    
    Those relate to PARAMETERIZED_VAR, and allow binding values through it at
    query preparation time.

 src/libtracker-data/tracker-data-query.c   |   2 +-
 src/libtracker-data/tracker-sparql-types.c |  69 ++++++++++++++++-
 src/libtracker-data/tracker-sparql-types.h |  31 +++++++-
 src/libtracker-data/tracker-sparql.c       | 114 +++++++++++++++++++++++++----
 src/libtracker-data/tracker-sparql.h       |   1 +
 src/libtracker-direct/tracker-direct.c     |   2 +-
 6 files changed, 199 insertions(+), 20 deletions(-)
---
diff --git a/src/libtracker-data/tracker-data-query.c b/src/libtracker-data/tracker-data-query.c
index aebfacf61..2694d6d0b 100644
--- a/src/libtracker-data/tracker-data-query.c
+++ b/src/libtracker-data/tracker-data-query.c
@@ -176,7 +176,7 @@ tracker_data_query_sparql_cursor (TrackerDataManager  *manager,
 
        sparql_query = tracker_sparql_new (manager, query);
 
-       cursor = tracker_sparql_execute_cursor (sparql_query, error);
+       cursor = tracker_sparql_execute_cursor (sparql_query, NULL, error);
 
        g_object_unref (sparql_query);
 
diff --git a/src/libtracker-data/tracker-sparql-types.c b/src/libtracker-data/tracker-sparql-types.c
index d48ed886e..1c6125f0f 100644
--- a/src/libtracker-data/tracker-sparql-types.c
+++ b/src/libtracker-data/tracker-sparql-types.c
@@ -25,7 +25,8 @@
 enum {
        TOKEN_TYPE_NONE,
        TOKEN_TYPE_LITERAL,
-       TOKEN_TYPE_VARIABLE
+       TOKEN_TYPE_VARIABLE,
+       TOKEN_TYPE_PARAMETER,
 };
 
 /* Helper structs */
@@ -188,11 +189,21 @@ tracker_token_variable_init (TrackerToken    *token,
        token->content.var = variable;
 }
 
+void
+tracker_token_parameter_init (TrackerToken *token,
+                             const gchar  *parameter)
+{
+       token->type = TOKEN_TYPE_PARAMETER;
+       token->content.parameter = g_strdup (parameter);
+}
+
 void
 tracker_token_unset (TrackerToken *token)
 {
        if (token->type == TOKEN_TYPE_LITERAL)
                g_clear_pointer (&token->content.literal, g_free);
+       else if (token->type == TOKEN_TYPE_PARAMETER)
+               g_clear_pointer (&token->content.parameter, g_free);
        token->type = TOKEN_TYPE_NONE;
 }
 
@@ -218,6 +229,14 @@ tracker_token_get_variable (TrackerToken *token)
        return NULL;
 }
 
+const gchar *
+tracker_token_get_parameter (TrackerToken *token)
+{
+       if (token->type == TOKEN_TYPE_PARAMETER)
+               return token->content.parameter;
+       return NULL;
+}
+
 const gchar *
 tracker_token_get_idstring (TrackerToken *token)
 {
@@ -419,6 +438,45 @@ tracker_literal_binding_new (const gchar      *literal,
        return binding;
 }
 
+/* Parameter binding */
+G_DEFINE_TYPE (TrackerParameterBinding, tracker_parameter_binding, TRACKER_TYPE_LITERAL_BINDING)
+
+static void
+tracker_parameter_binding_finalize (GObject *object)
+{
+       TrackerParameterBinding *binding = TRACKER_PARAMETER_BINDING (object);
+
+       g_free (binding->name);
+
+       G_OBJECT_CLASS (tracker_parameter_binding_parent_class)->finalize (object);
+}
+
+static void
+tracker_parameter_binding_class_init (TrackerParameterBindingClass *klass)
+{
+       GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+       object_class->finalize = tracker_parameter_binding_finalize;
+}
+
+static void
+tracker_parameter_binding_init (TrackerParameterBinding *binding)
+{
+}
+
+TrackerBinding *
+tracker_parameter_binding_new (const gchar      *name,
+                              TrackerDataTable *table)
+{
+       TrackerBinding *binding;
+
+       binding = g_object_new (TRACKER_TYPE_PARAMETER_BINDING, NULL);
+       binding->table = table;
+       TRACKER_PARAMETER_BINDING (binding)->name = g_strdup (name);
+
+       return binding;
+}
+
 /* Variable binding */
 G_DEFINE_TYPE (TrackerVariableBinding, tracker_variable_binding, TRACKER_TYPE_BINDING)
 
@@ -592,6 +650,15 @@ tracker_select_context_new (void)
        return g_object_new (TRACKER_TYPE_SELECT_CONTEXT, NULL);
 }
 
+TrackerVariable *
+tracker_select_context_lookup_variable (TrackerSelectContext *context,
+                                        const gchar          *name)
+{
+       if (!context->variables)
+               return NULL;
+       return g_hash_table_lookup (context->variables, name);
+}
+
 TrackerVariable *
 tracker_select_context_ensure_variable (TrackerSelectContext *context,
                                         const gchar          *name)
diff --git a/src/libtracker-data/tracker-sparql-types.h b/src/libtracker-data/tracker-sparql-types.h
index 6fdd0cbe7..1df06764c 100644
--- a/src/libtracker-data/tracker-sparql-types.h
+++ b/src/libtracker-data/tracker-sparql-types.h
@@ -31,6 +31,10 @@
 #define TRACKER_LITERAL_BINDING(o)    (G_TYPE_CHECK_INSTANCE_CAST ((o), TRACKER_TYPE_LITERAL_BINDING, 
TrackerLiteralBinding))
 #define TRACKER_IS_LITERAL_BINDING(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), TRACKER_TYPE_LITERAL_BINDING))
 
+#define TRACKER_TYPE_PARAMETER_BINDING  (tracker_parameter_binding_get_type ())
+#define TRACKER_PARAMETER_BINDING(o)    (G_TYPE_CHECK_INSTANCE_CAST ((o), TRACKER_TYPE_PARAMETER_BINDING, 
TrackerParameterBinding))
+#define TRACKER_IS_PARAMETER_BINDING(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), TRACKER_TYPE_PARAMETER_BINDING))
+
 #define TRACKER_TYPE_VARIABLE_BINDING  (tracker_variable_binding_get_type ())
 #define TRACKER_VARIABLE_BINDING(o)    (G_TYPE_CHECK_INSTANCE_CAST ((o), TRACKER_TYPE_VARIABLE_BINDING, 
TrackerVariableBinding))
 #define TRACKER_IS_VARIABLE_BINDING(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), TRACKER_TYPE_VARIABLE_BINDING))
@@ -51,6 +55,8 @@ typedef struct _TrackerBinding TrackerBinding;
 typedef struct _TrackerBindingClass TrackerBindingClass;
 typedef struct _TrackerLiteralBinding TrackerLiteralBinding;
 typedef struct _TrackerLiteralBindingClass TrackerLiteralBindingClass;
+typedef struct _TrackerParameterBinding TrackerParameterBinding;
+typedef struct _TrackerParameterBindingClass TrackerParameterBindingClass;
 typedef struct _TrackerVariableBinding TrackerVariableBinding;
 typedef struct _TrackerVariableBindingClass TrackerVariableBindingClass;
 typedef struct _TrackerContext TrackerContext;
@@ -95,6 +101,16 @@ struct _TrackerLiteralBindingClass {
        TrackerBindingClass parent_class;
 };
 
+/* Represents a mapping of a SPARQL parameter variable to a user-provided value */
+struct _TrackerParameterBinding {
+       TrackerLiteralBinding parent_instance;
+       gchar *name;
+};
+
+struct _TrackerParameterBindingClass {
+       TrackerLiteralBindingClass parent_class;
+};
+
 /* Represents a mapping of a SPARQL variable to a SQL table and column */
 struct _TrackerVariableBinding {
        TrackerBinding parent_instance;
@@ -117,6 +133,7 @@ struct _TrackerToken {
        guint type;
        union {
                gchar *literal;
+               gchar *parameter;
                TrackerVariable *var;
        } content;
 };
@@ -225,6 +242,11 @@ GType            tracker_literal_binding_get_type (void) G_GNUC_CONST;
 TrackerBinding * tracker_literal_binding_new (const gchar      *literal,
                                              TrackerDataTable *table);
 
+/* Parameter binding */
+GType            tracker_parameter_binding_get_type (void) G_GNUC_CONST;
+TrackerBinding * tracker_parameter_binding_new (const gchar      *name,
+                                               TrackerDataTable *table);
+
 /* Variable binding */
 GType            tracker_variable_binding_get_type (void) G_GNUC_CONST;
 TrackerBinding * tracker_variable_binding_new (TrackerVariable  *variable,
@@ -249,15 +271,18 @@ TrackerVariableBinding * tracker_variable_get_sample_binding (TrackerVariable *v
 
 /* Token */
 void tracker_token_literal_init  (TrackerToken    *token,
-                                  const gchar     *literal);
+                                 const gchar     *literal);
 void tracker_token_variable_init (TrackerToken    *token,
                                   TrackerVariable *variable);
-void tracker_token_unset         (TrackerToken *token);
+void tracker_token_parameter_init (TrackerToken   *token,
+                                  const gchar    *pameter);
+void tracker_token_unset (TrackerToken *token);
 
 gboolean           tracker_token_is_empty     (TrackerToken *token);
 const gchar      * tracker_token_get_literal  (TrackerToken *token);
 TrackerVariable  * tracker_token_get_variable (TrackerToken *token);
 const gchar      * tracker_token_get_idstring (TrackerToken *token);
+const gchar      * tracker_token_get_parameter (TrackerToken *token);
 
 /* Predicate variable */
 TrackerPredicateVariable *tracker_predicate_variable_new (void);
@@ -298,6 +323,8 @@ gboolean tracker_context_lookup_variable_ref (TrackerContext  *context,
 /* Select context */
 GType            tracker_select_context_get_type (void) G_GNUC_CONST;
 TrackerContext * tracker_select_context_new (void);
+TrackerVariable * tracker_select_context_lookup_variable (TrackerSelectContext *context,
+                                                          const gchar          *name);
 TrackerVariable * tracker_select_context_ensure_variable (TrackerSelectContext *context,
                                                          const gchar          *name);
 TrackerVariable * tracker_select_context_add_generated_variable (TrackerSelectContext *context);
diff --git a/src/libtracker-data/tracker-sparql.c b/src/libtracker-data/tracker-sparql.c
index 600d1c776..54e48a1d2 100644
--- a/src/libtracker-data/tracker-sparql.c
+++ b/src/libtracker-data/tracker-sparql.c
@@ -60,6 +60,7 @@ static gboolean helper_translate_time (TrackerSparql  *sparql,
 static TrackerDBStatement * prepare_query (TrackerDBInterface    *iface,
                                            TrackerStringBuilder  *str,
                                            GPtrArray             *literals,
+                                           GHashTable            *parameters,
                                            gboolean               cached,
                                            GError               **error);
 static inline TrackerVariable * _ensure_variable (TrackerSparql *sparql,
@@ -119,6 +120,8 @@ struct _TrackerSparql
        gboolean silent;
        gboolean cacheable;
 
+       GHashTable *parameters;
+
        struct {
                TrackerContext *context;
                TrackerContext *select_context;
@@ -151,6 +154,7 @@ tracker_sparql_finalize (GObject *object)
 
        g_object_unref (sparql->data_manager);
        g_hash_table_destroy (sparql->prefix_map);
+       g_hash_table_destroy (sparql->parameters);
 
        if (sparql->sql)
                tracker_string_builder_free (sparql->sql);
@@ -555,6 +559,7 @@ _extract_node_string (TrackerParserNode *node,
                switch (rule->data.terminal) {
                case TERMINAL_TYPE_VAR1:
                case TERMINAL_TYPE_VAR2:
+               case TERMINAL_TYPE_PARAMETERIZED_VAR:
                        add_start = 1;
                        break;
                case TERMINAL_TYPE_STRING_LITERAL1:
@@ -618,14 +623,22 @@ _dup_last_string (TrackerSparql *sparql)
 static inline TrackerBinding *
 _convert_terminal (TrackerSparql *sparql)
 {
+       const TrackerGrammarRule *rule;
        TrackerBinding *binding;
        gchar *str;
 
        str = _dup_last_string (sparql);
        g_assert (str != NULL);
 
-       binding = tracker_literal_binding_new (str, NULL);
-       tracker_binding_set_data_type (binding, sparql->current_state.expression_type);
+       rule = tracker_parser_node_get_rule (sparql->current_state.prev_node);
+
+       if (tracker_grammar_rule_is_a (rule, RULE_TYPE_TERMINAL, TERMINAL_TYPE_PARAMETERIZED_VAR)) {
+               binding = tracker_parameter_binding_new (str, NULL);
+       } else {
+               binding = tracker_literal_binding_new (str, NULL);
+               tracker_binding_set_data_type (binding, sparql->current_state.expression_type);
+       }
+
        g_free (str);
 
        return binding;
@@ -669,18 +682,18 @@ _ensure_variable (TrackerSparql *sparql,
        TrackerVariable *var;
 
        var = tracker_select_context_ensure_variable (TRACKER_SELECT_CONTEXT (sparql->context),
-                                                     name);
+                                                     name);
        tracker_context_add_variable_ref (sparql->current_state.context, var);
 
        return var;
 }
 
 static inline TrackerVariable *
-_extract_node_variable (TrackerParserNode *node,
-                       TrackerSparql     *sparql)
+_extract_node_variable (TrackerParserNode  *node,
+                        TrackerSparql      *sparql)
 {
        const TrackerGrammarRule *rule = tracker_parser_node_get_rule (node);
-       TrackerVariable *variable;
+       TrackerVariable *variable = NULL;
        gchar *str;
 
        if (!tracker_grammar_rule_is_a (rule, RULE_TYPE_TERMINAL, TERMINAL_TYPE_VAR1) &&
@@ -722,6 +735,8 @@ _init_token (TrackerToken      *token,
                        value = g_hash_table_lookup (sparql->solution_var_map, str);
                        tracker_token_literal_init (token, value);
                }
+       } else if (tracker_grammar_rule_is_a (rule, RULE_TYPE_TERMINAL, TERMINAL_TYPE_PARAMETERIZED_VAR)) {
+               tracker_token_parameter_init (token, str);
        } else {
                tracker_token_literal_init (token, str);
        }
@@ -911,7 +926,7 @@ _add_quad (TrackerSparql  *sparql,
        triple_context = TRACKER_TRIPLE_CONTEXT (sparql->current_state.context);
        ontologies = tracker_data_manager_get_ontologies (sparql->data_manager);
 
-       if (!tracker_token_get_variable (predicate)) {
+       if (tracker_token_get_literal (predicate)) {
                gboolean share_table = TRUE;
                const gchar *db_table;
 
@@ -1030,7 +1045,7 @@ _add_quad (TrackerSparql  *sparql,
                                                                  db_table);
                        new_table = TRUE;
                }
-       } else {
+       } else if (tracker_token_get_variable (predicate)) {
                TrackerPredicateVariable *pred_var;
 
                /* Variable in predicate */
@@ -1061,15 +1076,23 @@ _add_quad (TrackerSparql  *sparql,
                tracker_binding_set_db_column_name (binding, "predicate");
                _add_binding (sparql, binding);
                g_object_unref (binding);
+       } else {
+               /* The parser disallows parameter predicates */
+               g_assert_not_reached ();
        }
 
        if (new_table) {
                if (tracker_token_get_variable (subject)) {
                        variable = tracker_token_get_variable (subject);
                        binding = tracker_variable_binding_new (variable, subject_type, table);
-               } else {
+               } else if (tracker_token_get_literal (subject)) {
                        binding = tracker_literal_binding_new (tracker_token_get_literal (subject),
                                                               table);
+               } else if (tracker_token_get_parameter (subject)) {
+                       binding = tracker_parameter_binding_new (tracker_token_get_parameter (subject),
+                                                                table);
+               } else {
+                       g_assert_not_reached ();
                }
 
                tracker_binding_set_data_type (binding, TRACKER_PROPERTY_TYPE_RESOURCE);
@@ -1134,7 +1157,14 @@ _add_quad (TrackerSparql  *sparql,
                _add_binding (sparql, binding);
                g_object_unref (binding);
        } else if (is_fts) {
-               binding = tracker_literal_binding_new (tracker_token_get_literal (object), table);
+               if (tracker_token_get_literal (object)) {
+                       binding = tracker_literal_binding_new (tracker_token_get_literal (object), table);
+               } else if (tracker_token_get_parameter (object)) {
+                       binding = tracker_parameter_binding_new (tracker_token_get_parameter (object), table);
+               } else {
+                       g_assert_not_reached ();
+               }
+
                tracker_binding_set_db_column_name (binding, "fts5");
                _add_binding (sparql, binding);
                g_object_unref (binding);
@@ -1175,8 +1205,13 @@ _add_quad (TrackerSparql  *sparql,
                        }
                }
        } else {
-               binding = tracker_literal_binding_new (tracker_token_get_literal (object),
-                                                      table);
+               if (tracker_token_get_literal (object)) {
+                       binding = tracker_literal_binding_new (tracker_token_get_literal (object), table);
+               } else if (tracker_token_get_parameter (object)) {
+                       binding = tracker_parameter_binding_new (tracker_token_get_parameter (object), table);
+               } else {
+                       g_assert_not_reached ();
+               }
 
                if (tracker_token_get_variable (predicate)) {
                        tracker_binding_set_db_column_name (binding, "object");
@@ -1195,8 +1230,12 @@ _add_quad (TrackerSparql  *sparql,
                        variable = tracker_token_get_variable (graph);
                        binding = tracker_variable_binding_new (variable, NULL, table);
                        tracker_variable_binding_set_nullable (TRACKER_VARIABLE_BINDING (binding), TRUE);
-               } else {
+               } else if (tracker_token_get_literal (graph)) {
                        binding = tracker_literal_binding_new (tracker_token_get_literal (graph), table);
+               } else if (tracker_token_get_parameter (graph)) {
+                       binding = tracker_parameter_binding_new (tracker_token_get_parameter (graph), table);
+               } else {
+                       g_assert_not_reached ();
                }
 
                tracker_binding_set_data_type (binding, TRACKER_PROPERTY_TYPE_RESOURCE);
@@ -2682,7 +2721,7 @@ get_solution_for_pattern (TrackerSparql      *sparql,
        iface = tracker_data_manager_get_writable_db_interface (sparql->data_manager);
        stmt = prepare_query (iface, sparql->sql,
                              TRACKER_SELECT_CONTEXT (sparql->context)->literal_bindings,
-                             FALSE,
+                             NULL, FALSE,
                              error);
        g_clear_object (&sparql->context);
 
@@ -5916,12 +5955,17 @@ translate_NumericLiteralUnsigned (TrackerSparql  *sparql,
                                   GError        **error)
 {
        /* NumericLiteralUnsigned ::= INTEGER | DECIMAL | DOUBLE
+        *
+        * TRACKER EXTENSION:
+        * The terminal PARAMETERIZED_VAR is additionally accepted
         */
        if (_accept (sparql, RULE_TYPE_TERMINAL, TERMINAL_TYPE_INTEGER)) {
                sparql->current_state.expression_type = TRACKER_PROPERTY_TYPE_INTEGER;
        } else if (_accept (sparql, RULE_TYPE_TERMINAL, TERMINAL_TYPE_DOUBLE) ||
                   _accept (sparql, RULE_TYPE_TERMINAL, TERMINAL_TYPE_DECIMAL)) {
                sparql->current_state.expression_type = TRACKER_PROPERTY_TYPE_DOUBLE;
+       } else if (_accept (sparql, RULE_TYPE_TERMINAL, TERMINAL_TYPE_PARAMETERIZED_VAR)) {
+               sparql->current_state.expression_type = TRACKER_PROPERTY_TYPE_UNKNOWN;
        } else {
                g_assert_not_reached ();
        }
@@ -5934,12 +5978,17 @@ translate_NumericLiteralPositive (TrackerSparql  *sparql,
                                   GError        **error)
 {
        /* NumericLiteralPositive ::= INTEGER_POSITIVE | DECIMAL_POSITIVE | DOUBLE_POSITIVE
+        *
+        * TRACKER EXTENSION:
+        * The terminal PARAMETERIZED_VAR is additionally accepted
         */
        if (_accept (sparql, RULE_TYPE_TERMINAL, TERMINAL_TYPE_INTEGER_POSITIVE)) {
                sparql->current_state.expression_type = TRACKER_PROPERTY_TYPE_INTEGER;
        } else if (_accept (sparql, RULE_TYPE_TERMINAL, TERMINAL_TYPE_DECIMAL_POSITIVE) ||
                   _accept (sparql, RULE_TYPE_TERMINAL, TERMINAL_TYPE_DOUBLE_POSITIVE)) {
                sparql->current_state.expression_type = TRACKER_PROPERTY_TYPE_DOUBLE;
+       } else if (_accept (sparql, RULE_TYPE_TERMINAL, TERMINAL_TYPE_PARAMETERIZED_VAR)) {
+               sparql->current_state.expression_type = TRACKER_PROPERTY_TYPE_UNKNOWN;
        } else {
                g_assert_not_reached ();
        }
@@ -5952,12 +6001,17 @@ translate_NumericLiteralNegative (TrackerSparql  *sparql,
                                   GError        **error)
 {
        /* NumericLiteralNegative ::= INTEGER_NEGATIVE | DECIMAL_NEGATIVE | DOUBLE_NEGATIVE
+        *
+        * TRACKER EXTENSION:
+        * The terminal PARAMETERIZED_VAR is additionally accepted
         */
        if (_accept (sparql, RULE_TYPE_TERMINAL, TERMINAL_TYPE_INTEGER_NEGATIVE)) {
                sparql->current_state.expression_type = TRACKER_PROPERTY_TYPE_INTEGER;
        } else if (_accept (sparql, RULE_TYPE_TERMINAL, TERMINAL_TYPE_DECIMAL_NEGATIVE) ||
                   _accept (sparql, RULE_TYPE_TERMINAL, TERMINAL_TYPE_DOUBLE_NEGATIVE)) {
                sparql->current_state.expression_type = TRACKER_PROPERTY_TYPE_DOUBLE;
+       } else if (_accept (sparql, RULE_TYPE_TERMINAL, TERMINAL_TYPE_PARAMETERIZED_VAR)) {
+               sparql->current_state.expression_type = TRACKER_PROPERTY_TYPE_UNKNOWN;
        } else {
                g_assert_not_reached ();
        }
@@ -5970,11 +6024,16 @@ translate_BooleanLiteral (TrackerSparql  *sparql,
                           GError        **error)
 {
        /* BooleanLiteral ::= 'true' | 'false'
+        *
+        * TRACKER EXTENSION:
+        * The terminal PARAMETERIZED_VAR is additionally accepted
         */
        if (_accept (sparql, RULE_TYPE_LITERAL, LITERAL_TRUE) ||
            _accept (sparql, RULE_TYPE_LITERAL, LITERAL_FALSE)) {
                sparql->current_state.expression_type = TRACKER_PROPERTY_TYPE_BOOLEAN;
                return TRUE;
+       } else if (_accept (sparql, RULE_TYPE_TERMINAL, TERMINAL_TYPE_PARAMETERIZED_VAR)) {
+               sparql->current_state.expression_type = TRACKER_PROPERTY_TYPE_UNKNOWN;
        } else {
                g_assert_not_reached ();
        }
@@ -5987,6 +6046,9 @@ translate_String (TrackerSparql  *sparql,
                   GError        **error)
 {
        /* String ::= STRING_LITERAL1 | STRING_LITERAL2 | STRING_LITERAL_LONG1 | STRING_LITERAL_LONG2
+        *
+        * TRACKER EXTENSION:
+        * The terminal PARAMETERIZED_VAR is additionally accepted
         */
        if (_accept (sparql, RULE_TYPE_TERMINAL, TERMINAL_TYPE_STRING_LITERAL1) ||
            _accept (sparql, RULE_TYPE_TERMINAL, TERMINAL_TYPE_STRING_LITERAL2) ||
@@ -5994,6 +6056,8 @@ translate_String (TrackerSparql  *sparql,
            _accept (sparql, RULE_TYPE_TERMINAL, TERMINAL_TYPE_STRING_LITERAL_LONG2)) {
                sparql->current_state.expression_type = TRACKER_PROPERTY_TYPE_STRING;
                return TRUE;
+       } else if (_accept (sparql, RULE_TYPE_TERMINAL, TERMINAL_TYPE_PARAMETERIZED_VAR)) {
+               sparql->current_state.expression_type = TRACKER_PROPERTY_TYPE_UNKNOWN;
        } else {
                g_assert_not_reached ();
        }
@@ -6291,6 +6355,7 @@ tracker_sparql_init (TrackerSparql *sparql)
 {
        sparql->prefix_map = g_hash_table_new_full (g_str_hash, g_str_equal,
                                                    g_free, g_free);
+       sparql->parameters = g_hash_table_new (g_str_hash, g_str_equal);
        sparql->var_names = g_ptr_array_new_with_free_func (g_free);
        sparql->var_types = g_array_new (FALSE, FALSE, sizeof (TrackerPropertyType));
        sparql->cacheable = TRUE;
@@ -6327,6 +6392,7 @@ static TrackerDBStatement *
 prepare_query (TrackerDBInterface    *iface,
                TrackerStringBuilder  *str,
                GPtrArray             *literals,
+              GHashTable            *parameters,
                gboolean               cached,
                GError               **error)
 {
@@ -6352,7 +6418,23 @@ prepare_query (TrackerDBInterface    *iface,
                binding = g_ptr_array_index (literals, i);
                prop_type = TRACKER_BINDING (binding)->data_type;
 
-               if (prop_type == TRACKER_PROPERTY_TYPE_BOOLEAN) {
+               if (TRACKER_IS_PARAMETER_BINDING (binding)) {
+                       const gchar *name;
+                       GValue *value = NULL;
+
+                       name = TRACKER_PARAMETER_BINDING (binding)->name;
+
+                       if (parameters)
+                               value = g_hash_table_lookup (parameters, name);
+
+                       if (value) {
+                               tracker_db_statement_bind_value (stmt, i, value);
+                       } else {
+                               g_set_error (error, TRACKER_SPARQL_ERROR,
+                                            TRACKER_SPARQL_ERROR_TYPE,
+                                            "Parameter '%s' has no given value", name);
+                       }
+               } else if (prop_type == TRACKER_PROPERTY_TYPE_BOOLEAN) {
                        if (g_str_equal (binding->literal, "1") ||
                            g_ascii_strcasecmp (binding->literal, "true") == 0) {
                                tracker_db_statement_bind_int (stmt, i, 1);
@@ -6403,6 +6485,7 @@ prepare_query (TrackerDBInterface    *iface,
 
 TrackerSparqlCursor *
 tracker_sparql_execute_cursor (TrackerSparql  *sparql,
+                               GHashTable     *parameters,
                                GError        **error)
 {
        TrackerDBStatement *stmt;
@@ -6423,6 +6506,7 @@ tracker_sparql_execute_cursor (TrackerSparql  *sparql,
        iface = tracker_data_manager_get_db_interface (sparql->data_manager);
        stmt = prepare_query (iface, sparql->sql,
                              TRACKER_SELECT_CONTEXT (sparql->context)->literal_bindings,
+                             parameters,
                              sparql->cacheable,
                              error);
        if (!stmt)
diff --git a/src/libtracker-data/tracker-sparql.h b/src/libtracker-data/tracker-sparql.h
index bf0b3b137..e86665c51 100644
--- a/src/libtracker-data/tracker-sparql.h
+++ b/src/libtracker-data/tracker-sparql.h
@@ -36,6 +36,7 @@ TrackerSparql *       tracker_sparql_new (TrackerDataManager *manager,
                                           const gchar        *sparql);
 
 TrackerSparqlCursor * tracker_sparql_execute_cursor (TrackerSparql  *sparql,
+                                                     GHashTable     *parameters,
                                                      GError        **error);
 
 TrackerSparql * tracker_sparql_new_update (TrackerDataManager *manager,
diff --git a/src/libtracker-direct/tracker-direct.c b/src/libtracker-direct/tracker-direct.c
index 66409991b..c5d3e5c94 100644
--- a/src/libtracker-direct/tracker-direct.c
+++ b/src/libtracker-direct/tracker-direct.c
@@ -437,7 +437,7 @@ tracker_direct_connection_query (TrackerSparqlConnection  *self,
 
        g_mutex_lock (&priv->mutex);
        query = tracker_sparql_new (priv->data_manager, sparql);
-       cursor = tracker_sparql_execute_cursor (query, error);
+       cursor = tracker_sparql_execute_cursor (query, NULL, error);
        g_object_unref (query);
 
        if (cursor)


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