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



commit ad89d40dc8c85710e5ab3b262cf2b62eaa2ff425
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 | 46 +++++++++++++++++++
 src/libtracker-data/tracker-sparql-types.h | 22 +++++++++
 src/libtracker-data/tracker-sparql.c       | 74 ++++++++++++++++++++++++++----
 src/libtracker-data/tracker-sparql.h       |  1 +
 src/libtracker-direct/tracker-direct.c     |  2 +-
 6 files changed, 137 insertions(+), 10 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..c79216635 100644
--- a/src/libtracker-data/tracker-sparql-types.c
+++ b/src/libtracker-data/tracker-sparql-types.c
@@ -419,6 +419,43 @@ 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)
+{
+       TrackerBinding *binding;
+
+       binding = g_object_new (TRACKER_TYPE_PARAMETER_BINDING, NULL);
+       TRACKER_PARAMETER_BINDING (binding)->name = g_strdup (name);
+
+       return binding;
+}
+
 /* Variable binding */
 G_DEFINE_TYPE (TrackerVariableBinding, tracker_variable_binding, TRACKER_TYPE_BINDING)
 
@@ -592,6 +629,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..d7269818a 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;
@@ -225,6 +241,10 @@ 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);
+
 /* Variable binding */
 GType            tracker_variable_binding_get_type (void) G_GNUC_CONST;
 TrackerBinding * tracker_variable_binding_new (TrackerVariable  *variable,
@@ -298,6 +318,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..986f75463 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);
+       } 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) &&
@@ -2682,7 +2695,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 +5929,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 +5952,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 +5975,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 +5998,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 +6020,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 +6030,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 +6329,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 +6366,7 @@ static TrackerDBStatement *
 prepare_query (TrackerDBInterface    *iface,
                TrackerStringBuilder  *str,
                GPtrArray             *literals,
+              GHashTable            *parameters,
                gboolean               cached,
                GError               **error)
 {
@@ -6352,7 +6392,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 +6459,7 @@ prepare_query (TrackerDBInterface    *iface,
 
 TrackerSparqlCursor *
 tracker_sparql_execute_cursor (TrackerSparql  *sparql,
+                               GHashTable     *parameters,
                                GError        **error)
 {
        TrackerDBStatement *stmt;
@@ -6423,6 +6480,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]