[tracker/wip/carlosg/bindings-in-service: 3/6] libtracker-data: Add hidden columns to pass parameters



commit d6edbd0eca6c7849addff41eb39a8ba704fbf8bf
Author: Carlos Garnacho <carlosg gnome org>
Date:   Mon May 4 19:24:49 2020 +0200

    libtracker-data: Add hidden columns to pass parameters
    
    Support a total of 50 parameters (in name/value column pairs), we
    use those as input parameters to the virtual table. With this
    proxying, the upper SQL query may then do likewise via these
    hidden columns.
    
    This will allow ~var parameters to work within SERVICE{} graph
    patterns.

 src/libtracker-data/tracker-vtab-service.c | 95 +++++++++++++++++++++++++++---
 1 file changed, 87 insertions(+), 8 deletions(-)
---
diff --git a/src/libtracker-data/tracker-vtab-service.c b/src/libtracker-data/tracker-vtab-service.c
index 0311b67f3..caa6197c5 100644
--- a/src/libtracker-data/tracker-vtab-service.c
+++ b/src/libtracker-data/tracker-vtab-service.c
@@ -25,11 +25,13 @@
 #include <libtracker-sparql/tracker-sparql.h>
 
 #define N_VARIABLES 100
+#define N_PARAMETERS 50
 #define COL_SERVICE 0
 #define COL_QUERY 1
 #define COL_SILENT 2
 #define COL_LAST 3
-#define COL_FIRST_VARIABLE COL_LAST
+#define COL_FIRST_PARAMETER COL_LAST
+#define COL_FIRST_VARIABLE (COL_LAST + (N_PARAMETERS * 2))
 
 typedef struct {
        sqlite3 *db;
@@ -46,6 +48,7 @@ typedef struct {
        TrackerServiceVTab *vtab;
        TrackerSparqlConnection *conn;
        TrackerSparqlCursor *sparql_cursor;
+       GHashTable *parameter_columns;
        gchar *service;
        gchar *query;
        guint64 rowid;
@@ -80,6 +83,7 @@ tracker_service_cursor_free (gpointer data)
 {
        TrackerServiceCursor *cursor = data;
 
+       g_clear_pointer (&cursor->parameter_columns, g_hash_table_unref);
        g_free (cursor->service);
        g_free (cursor->query);
        g_clear_object (&cursor->conn);
@@ -111,6 +115,11 @@ service_create (sqlite3            *db,
                         "query TEXT HIDDEN, "
                         "silent INTEGER HIDDEN");
 
+       for (i = 0; i < N_PARAMETERS; i++) {
+               g_string_append_printf (str, ", valuename%d TEXT HIDDEN", i);
+               g_string_append_printf (str, ", value%d TEXT HIDDEN", i);
+       }
+
        for (i = 0; i < N_VARIABLES; i++)
                g_string_append_printf (str, ", col%d TEXT", i);
 
@@ -141,9 +150,7 @@ service_best_index (sqlite3_vtab       *vtab,
                if (!info->aConstraint[i].usable)
                        continue;
 
-               if (info->aConstraint[i].iColumn != COL_SERVICE &&
-                   info->aConstraint[i].iColumn != COL_QUERY &&
-                   info->aConstraint[i].iColumn != COL_SILENT) {
+               if (info->aConstraint[i].iColumn > COL_FIRST_VARIABLE) {
                        info->aConstraintUsage[i].argvIndex = -1;
                        continue;
                }
@@ -204,6 +211,32 @@ service_close (sqlite3_vtab_cursor *vtab_cursor)
        return SQLITE_OK;
 }
 
+static void
+apply_statement_parameters (TrackerSparqlStatement *statement,
+                            GHashTable             *names,
+                            GHashTable             *values)
+{
+       GHashTableIter iter;
+       sqlite3_value *name, *value;
+       gpointer key;
+
+       if (!names || !values)
+               return;
+
+       g_hash_table_iter_init (&iter, names);
+
+       while (g_hash_table_iter_next (&iter, &key, (gpointer *) &name)) {
+               value = g_hash_table_lookup (values, key);
+               if (!value)
+                       continue;
+
+               /* FIXME: Handle other types better */
+               tracker_sparql_statement_bind_string (statement,
+                                                     sqlite3_value_text (name),
+                                                     sqlite3_value_text (value));
+       }
+}
+
 static int
 service_filter (sqlite3_vtab_cursor  *vtab_cursor,
                int                   idx,
@@ -214,6 +247,7 @@ service_filter (sqlite3_vtab_cursor  *vtab_cursor,
        TrackerServiceCursor *cursor = (TrackerServiceCursor *) vtab_cursor;
        const ConstraintData *constraints = (const ConstraintData *) idx_str;
        TrackerSparqlStatement *statement;
+       GHashTable *names = NULL, *values = NULL;
        gchar *uri_scheme = NULL;
        GError *error = NULL;
        gint i;
@@ -222,16 +256,46 @@ service_filter (sqlite3_vtab_cursor  *vtab_cursor,
        cursor->rowid = 0;
 
        for (i = 0; i < argc; i++) {
-               if (constraints[i].column == COL_SERVICE)
+               if (constraints[i].column == COL_SERVICE) {
                        cursor->service = g_strdup (sqlite3_value_text (argv[i]));
-               if (constraints[i].column == COL_QUERY)
+               } else if (constraints[i].column == COL_QUERY) {
                        cursor->query = g_strdup (sqlite3_value_text (argv[i]));
-               if (constraints[i].column == COL_SILENT)
+               } if (constraints[i].column == COL_SILENT) {
                        cursor->silent = !!sqlite3_value_int (argv[i]);
+               } else if (constraints[i].column >= COL_FIRST_PARAMETER &&
+                          constraints[i].column < COL_FIRST_VARIABLE) {
+                       guint param_num;
+
+                       if (!names)
+                               names = g_hash_table_new (NULL, NULL);
+                       if (!values)
+                               values = g_hash_table_new (NULL, NULL);
+                       if (!cursor->parameter_columns)
+                               cursor->parameter_columns = g_hash_table_new_full (NULL, NULL, NULL,
+                                                                                  (GDestroyNotify) 
sqlite3_value_free);
+
+                       if ((constraints[i].column - COL_FIRST_PARAMETER) % 2 == 0) {
+                               /* Parameter name */
+                               param_num = (constraints[i].column - COL_FIRST_PARAMETER) / 2;
+                               g_hash_table_insert (names,
+                                                    GUINT_TO_POINTER (param_num),
+                                                    argv[i]);
+                       } else {
+                               /* Parameter value */
+                               param_num = (constraints[i].column - COL_FIRST_PARAMETER - 1) / 2;
+                               g_hash_table_insert (values,
+                                                    GUINT_TO_POINTER (param_num),
+                                                    argv[i]);
+                       }
+
+                       g_hash_table_insert (cursor->parameter_columns,
+                                            GINT_TO_POINTER (constraints[i].column),
+                                            sqlite3_value_dup (argv[i]));
+               }
        }
 
        if (!cursor->service || !cursor->query)
-               return SQLITE_ERROR;
+               goto fail;
 
        uri_scheme = g_uri_parse_scheme (cursor->service);
        if (g_strcmp0 (uri_scheme, "dbus") == 0) {
@@ -280,6 +344,7 @@ service_filter (sqlite3_vtab_cursor  *vtab_cursor,
        if (error)
                goto fail;
 
+       apply_statement_parameters (statement, names, values);
        cursor->sparql_cursor = tracker_sparql_statement_execute (statement,
                                                                  NULL,
                                                                  &error);
@@ -299,6 +364,8 @@ service_filter (sqlite3_vtab_cursor  *vtab_cursor,
        return SQLITE_OK;
 
 fail:
+       g_clear_pointer (&names, g_hash_table_unref);
+       g_clear_pointer (&values, g_hash_table_unref);
        g_free (uri_scheme);
 
        if (cursor->silent) {
@@ -349,6 +416,18 @@ service_column (sqlite3_vtab_cursor *vtab_cursor,
                sqlite3_result_text (context, cursor->query, -1, NULL);
        } else if (n_col == COL_SILENT) {
                sqlite3_result_int (context, cursor->silent);
+       } else if (n_col >= COL_FIRST_PARAMETER &&
+                  n_col < COL_FIRST_VARIABLE) {
+               sqlite3_value *value = NULL;
+
+               if (cursor->parameter_columns)
+                       value = g_hash_table_lookup (cursor->parameter_columns,
+                                                    GINT_TO_POINTER (n_col));
+
+               if (value)
+                       sqlite3_result_value (context, value);
+               else
+                       sqlite3_result_null (context);
        } else if (n_col >= COL_FIRST_VARIABLE &&
                   n_col < COL_FIRST_VARIABLE + N_VARIABLES) {
                gint query_col = n_col - COL_FIRST_VARIABLE;


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