XMMS2
|
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 }