XMMS2

src/xmms/collserial.c

Go to the documentation of this file.
00001 /*  XMMS2 - X Music Multiplexer System
00002  *  Copyright (C) 2003-2009 XMMS2 Team
00003  *
00004  *  PLUGINS ARE NOT CONSIDERED TO BE DERIVED WORK !!!
00005  *
00006  *  This library is free software; you can redistribute it and/or
00007  *  modify it under the terms of the GNU Lesser General Public
00008  *  License as published by the Free Software Foundation; either
00009  *  version 2.1 of the License, or (at your option) any later version.
00010  *
00011  *  This library is distributed in the hope that it will be useful,
00012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  *  Lesser General Public License for more details.
00015  */
00016 
00017 
00018 /** @file
00019  *  Functions to serialize (save/restore) collections.
00020  */
00021 
00022 #include "xmmspriv/xmms_collserial.h"
00023 #include "xmmspriv/xmms_collection.h"
00024 #include "xmmspriv/xmms_medialib.h"
00025 
00026 
00027 /* Internal helper structures */
00028 
00029 typedef struct {
00030     xmms_medialib_session_t *session;
00031     guint collid;
00032     xmms_collection_namespace_id_t nsid;
00033 } coll_dbwrite_t;
00034 
00035 
00036 static xmmsv_coll_t *xmms_collection_dbread_operator (xmms_medialib_session_t *session, gint id, xmmsv_coll_type_t type);
00037 static guint xmms_collection_dbwrite_operator (xmms_medialib_session_t *session, guint collid, xmmsv_coll_t *coll);
00038 
00039 static void dbwrite_operator (void *key, void *value, void *udata);
00040 static void dbwrite_coll_attributes (const char *key, xmmsv_t *value, void *udata);
00041 static void dbwrite_strip_tmpprops (void *key, void *value, void *udata);
00042 
00043 static gint value_get_dict_int (xmmsv_t *val, const gchar *key);
00044 static const gchar *value_get_dict_string (xmmsv_t *val, const gchar *key);
00045 
00046 
00047 
00048 /** Save the collection DAG in the database.
00049  *
00050  * @param dag  The collection DAG to save.
00051  */
00052 void
00053 xmms_collection_dag_save (xmms_coll_dag_t *dag)
00054 {
00055     gint i;
00056     xmms_medialib_session_t *session;
00057 
00058     session = xmms_medialib_begin_write ();
00059 
00060     /* Empty Collection* tables */
00061     xmms_medialib_select (session, "DELETE FROM CollectionAttributes", NULL);
00062     xmms_medialib_select (session, "DELETE FROM CollectionConnections", NULL);
00063     xmms_medialib_select (session, "DELETE FROM CollectionIdlists", NULL);
00064     xmms_medialib_select (session, "DELETE FROM CollectionLabels", NULL);
00065     xmms_medialib_select (session, "DELETE FROM CollectionOperators", NULL);
00066 
00067     /* Write all collections in all namespaces */
00068     coll_dbwrite_t dbinfos = { session, 1, 0 }; /* ids start at 1 */
00069     for (i = 0; i < XMMS_COLLECTION_NUM_NAMESPACES; ++i) {
00070         dbinfos.nsid = i;
00071         xmms_collection_foreach_in_namespace (dag, i, dbwrite_operator, &dbinfos);
00072     }
00073 
00074     xmms_collection_foreach_in_namespace (dag, XMMS_COLLECTION_NSID_ALL,
00075                                           dbwrite_strip_tmpprops, NULL);
00076 
00077     xmms_medialib_end (session);
00078 }
00079 
00080 /** Restore the collection DAG from the database.
00081  *
00082  * @param dag  The collection DAG to restore to.
00083  */
00084 void
00085 xmms_collection_dag_restore (xmms_coll_dag_t *dag)
00086 {
00087     xmmsv_coll_t *coll = NULL;
00088     xmms_medialib_session_t *session;
00089     xmmsv_t *cmdval;
00090     const gchar *query;
00091     GList *res;
00092     gint previd;
00093 
00094     session = xmms_medialib_begin ();
00095 
00096     /* Fetch all label-coll_operator for all namespaces, register in table */
00097     query = "SELECT op.id AS id, lbl.name AS label, "
00098             "       lbl.namespace AS nsid, op.type AS type "
00099             "FROM CollectionOperators AS op, CollectionLabels as lbl "
00100             "WHERE op.id=lbl.collid "
00101             "ORDER BY id";
00102     res = xmms_medialib_select (session, query, NULL);
00103 
00104     previd = -1;
00105 
00106     while (res) {
00107         gint id, type, nsid;
00108         const gchar *label;
00109 
00110         cmdval = (xmmsv_t*) res->data;
00111         id = value_get_dict_int (cmdval, "id");
00112         type = value_get_dict_int (cmdval, "type");
00113         nsid = value_get_dict_int (cmdval, "nsid");
00114         label = value_get_dict_string (cmdval, "label");
00115 
00116         /* Do not duplicate operator if same id */
00117         if (previd < 0 || id != previd) {
00118             coll = xmms_collection_dbread_operator (session, id, type);
00119             previd = id;
00120         }
00121         else {
00122             xmmsv_coll_ref (coll);  /* New label references the coll */
00123         }
00124 
00125         xmms_collection_dag_replace (dag, nsid, g_strdup (label), coll);
00126 
00127         xmmsv_unref (cmdval);
00128         res = g_list_delete_link (res, res);
00129     }
00130 
00131     xmms_medialib_end (session);
00132 
00133     /* FIXME: validate ? */
00134 
00135     /* Link references in collections to actual operators */
00136     xmms_collection_apply_to_all_collections (dag, bind_all_references, NULL);
00137 }
00138 
00139 /** Given a collection id, query the DB to build the corresponding
00140  *  collection DAG.
00141  *
00142  * @param session  The medialib session connected to the DB.
00143  * @param id  The id of the collection to create.
00144  * @param type  The type of the collection operator.
00145  * @return  The created collection DAG.
00146  */
00147 static xmmsv_coll_t *
00148 xmms_collection_dbread_operator (xmms_medialib_session_t *session,
00149                                  gint id, xmmsv_coll_type_t type)
00150 {
00151     xmmsv_coll_t *coll;
00152     xmmsv_coll_t *op;
00153     GList *res;
00154     GList *n;
00155     xmmsv_t *cmdval;
00156     gchar query[256];
00157 
00158     coll = xmmsv_coll_new (type);
00159 
00160     /* Retrieve the attributes */
00161     g_snprintf (query, sizeof (query),
00162                 "SELECT attr.key AS key, attr.value AS value "
00163                 "FROM CollectionOperators AS op, CollectionAttributes AS attr "
00164                 "WHERE op.id=%d AND attr.collid=op.id", id);
00165 
00166     res = xmms_medialib_select (session, query, NULL);
00167     for (n = res; n; n = n->next) {
00168         const gchar *key, *value;
00169 
00170         cmdval = (xmmsv_t*) n->data;
00171         key = value_get_dict_string (cmdval, "key");
00172         value = value_get_dict_string (cmdval, "value");
00173         xmmsv_coll_attribute_set (coll, key, value);
00174 
00175         xmmsv_unref (n->data);
00176     }
00177     g_list_free (res);
00178 
00179     /* Retrieve the idlist */
00180     g_snprintf (query, sizeof (query),
00181                 "SELECT idl.mid AS mid "
00182                 "FROM CollectionOperators AS op, CollectionIdlists AS idl "
00183                 "WHERE op.id=%d AND idl.collid=op.id "
00184                 "ORDER BY idl.position", id);
00185 
00186     res = xmms_medialib_select (session, query, NULL);
00187     for (n = res; n; n = n->next) {
00188 
00189         cmdval = (xmmsv_t *) n->data;
00190         xmmsv_coll_idlist_append (coll, value_get_dict_int (cmdval, "mid"));
00191 
00192         xmmsv_unref (cmdval);
00193     }
00194     g_list_free (res);
00195 
00196     /* Retrieve the operands */
00197     g_snprintf (query, sizeof (query),
00198                 "SELECT op.id AS id, op.type AS type "
00199                 "FROM CollectionOperators AS op, CollectionConnections AS conn "
00200                 "WHERE conn.to_id=%d AND conn.from_id=op.id", id);
00201 
00202     res = xmms_medialib_select (session, query, NULL);
00203     for (n = res; n; n = n->next) {
00204         gint _id;
00205         gint type;
00206 
00207         cmdval = (xmmsv_t *) n->data;
00208         _id = value_get_dict_int (cmdval, "id");
00209         type = value_get_dict_int (cmdval, "type");
00210 
00211         op = xmms_collection_dbread_operator (session, _id, type);
00212         xmmsv_coll_add_operand (coll, op);
00213 
00214         xmmsv_coll_unref (op);
00215         xmmsv_unref (cmdval);
00216     }
00217     g_list_free (res);
00218 
00219     return coll;
00220 }
00221 
00222 /** Write the given operator to the database under the given id.
00223  *
00224  * @param session  The medialib session connected to the DB.
00225  * @param collid  The id under which to save the collection.
00226  * @param coll  The structure of the collection to save.
00227  * @return  The next free collection id.
00228  */
00229 static guint
00230 xmms_collection_dbwrite_operator (xmms_medialib_session_t *session,
00231                                   guint collid, xmmsv_coll_t *coll)
00232 {
00233     gchar query[128];
00234     guint *idlist;
00235     gint i;
00236     xmmsv_coll_t *op;
00237     xmmsv_t *attrs;
00238     gint newid, nextid;
00239     coll_dbwrite_t dbwrite_infos = { session, collid, 0 };
00240 
00241     /* Write operator */
00242     g_snprintf (query, sizeof (query),
00243                 "INSERT INTO CollectionOperators VALUES(%d, %d)",
00244                 collid, xmmsv_coll_get_type (coll));
00245 
00246     xmms_medialib_select (session, query, NULL);
00247 
00248     /* Write attributes */
00249     attrs = xmmsv_coll_attributes_get (coll);
00250     xmmsv_dict_foreach (attrs, dbwrite_coll_attributes, &dbwrite_infos);
00251     attrs = NULL; /* no unref needed. */
00252 
00253     /* Write idlist */
00254     idlist = xmmsv_coll_get_idlist (coll);
00255     for (i = 0; idlist[i] != 0; i++) {
00256         g_snprintf (query, sizeof (query),
00257                     "INSERT INTO CollectionIdlists VALUES(%d, %d, %d)",
00258                     collid, i, idlist[i]);
00259 
00260         xmms_medialib_select (session, query, NULL);
00261     }
00262 
00263     /* Save operands and connections (don't recurse in ref operand) */
00264     newid = collid + 1;
00265     if (xmmsv_coll_get_type (coll) != XMMS_COLLECTION_TYPE_REFERENCE) {
00266         xmmsv_t *tmp;
00267         xmmsv_list_iter_t *iter;
00268 
00269         xmmsv_get_list_iter (xmmsv_coll_operands_get (coll), &iter);
00270 
00271         for (xmmsv_list_iter_first (iter);
00272              xmmsv_list_iter_valid (iter);
00273              xmmsv_list_iter_next (iter)) {
00274 
00275             xmmsv_list_iter_entry (iter, &tmp);
00276             xmmsv_get_coll (tmp, &op);
00277 
00278             nextid = xmms_collection_dbwrite_operator (session, newid, op);
00279             g_snprintf (query, sizeof (query),
00280                         "INSERT INTO CollectionConnections VALUES(%d, %d)",
00281                         newid, collid);
00282             xmms_medialib_select (session, query, NULL);
00283             newid = nextid;
00284         }
00285         xmmsv_list_iter_explicit_destroy (iter);
00286     }
00287 
00288     /* return next available id */
00289     return newid;
00290 }
00291 
00292 /* For all label-operator pairs, write the operator and all its
00293  * operands to the DB recursively. */
00294 static void
00295 dbwrite_operator (void *key, void *value, void *udata)
00296 {
00297     gchar *query;
00298     gchar *label = key;
00299     xmmsv_coll_t *coll = value;
00300     coll_dbwrite_t *dbinfos = udata;
00301     gchar *esc_label;
00302     gint serial_id;
00303 
00304     /* Only serialize each operator once, get previous id if exists */
00305     if (!xmms_collection_get_int_attr (coll, XMMS_COLLSERIAL_ATTR_ID, &serial_id)) {
00306         serial_id = dbinfos->collid;
00307         dbinfos->collid = xmms_collection_dbwrite_operator (dbinfos->session,
00308                                                             dbinfos->collid, coll);
00309         xmms_collection_set_int_attr (coll, XMMS_COLLSERIAL_ATTR_ID, serial_id);
00310     }
00311 
00312     esc_label = sqlite_prepare_string (label);
00313     query = g_strdup_printf ("INSERT INTO CollectionLabels VALUES(%d, %d, %s)",
00314                              serial_id, dbinfos->nsid, esc_label);
00315     xmms_medialib_select (dbinfos->session, query, NULL);
00316 
00317     g_free (query);
00318     g_free (esc_label);
00319 }
00320 
00321 /* Write all attributes of a collection to the DB. */
00322 static void
00323 dbwrite_coll_attributes (const char *key, xmmsv_t *value, void *udata)
00324 {
00325     gchar *query;
00326     coll_dbwrite_t *dbwrite_infos = udata;
00327     gchar *esc_key;
00328     gchar *esc_val;
00329     const gchar *s;
00330     int r;
00331 
00332     r = xmmsv_get_string (value, &s);
00333     g_return_if_fail (r);
00334 
00335     esc_key = sqlite_prepare_string (key);
00336     esc_val = sqlite_prepare_string (s);
00337     query = g_strdup_printf ("INSERT INTO CollectionAttributes VALUES(%d, %s, %s)",
00338                              dbwrite_infos->collid, esc_key, esc_val);
00339     xmms_medialib_select (dbwrite_infos->session, query, NULL);
00340 
00341     g_free (query);
00342     g_free (esc_key);
00343     g_free (esc_val);
00344 }
00345 
00346 /* Remove all temp utility properties used to write collections to the DB. */
00347 static void
00348 dbwrite_strip_tmpprops (void *key, void *value, void *udata)
00349 {
00350     xmmsv_coll_t *coll = value;
00351     xmmsv_coll_attribute_remove (coll, XMMS_COLLSERIAL_ATTR_ID);
00352 }
00353 
00354 
00355 /* Extract the int value out of a xmmsv_t object. */
00356 static gint
00357 value_get_dict_int (xmmsv_t *val, const gchar *key)
00358 {
00359     gint i;
00360     xmmsv_dict_entry_get_int (val, key, &i);
00361     return i;
00362 }
00363 
00364 /* Extract the string value out of a xmmsv_t object. */
00365 static const gchar *
00366 value_get_dict_string (xmmsv_t *val, const gchar *key)
00367 {
00368     const gchar *s;
00369     xmmsv_dict_entry_get_string (val, key, &s);
00370     return s;
00371 }