XMMS2
collserial.c
Go to the documentation of this file.
1/* XMMS2 - X Music Multiplexer System
2 * Copyright (C) 2003-2011 XMMS2 Team
3 *
4 * PLUGINS ARE NOT CONSIDERED TO BE DERIVED WORK !!!
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 */
16
17
18/** @file
19 * Functions to serialize (save/restore) collections.
20 */
21
25
26
27/* Internal helper structures */
28
29typedef struct {
31 guint collid;
33} coll_dbwrite_t;
34
35
36static xmmsv_coll_t *xmms_collection_dbread_operator (xmms_medialib_session_t *session, gint id, xmmsv_coll_type_t type);
37static guint xmms_collection_dbwrite_operator (xmms_medialib_session_t *session, guint collid, xmmsv_coll_t *coll);
38
39static void dbwrite_operator (void *key, void *value, void *udata);
40static void dbwrite_coll_attributes (const char *key, xmmsv_t *value, void *udata);
41static void dbwrite_strip_tmpprops (void *key, void *value, void *udata);
42
43static gint value_get_dict_int (xmmsv_t *val, const gchar *key);
44static const gchar *value_get_dict_string (xmmsv_t *val, const gchar *key);
45
46
47
48/** Save the collection DAG in the database.
49 *
50 * @param dag The collection DAG to save.
51 */
52void
54{
55 gint i;
57
58 session = xmms_medialib_begin_write ();
59
60 /* Empty Collection* tables */
61 xmms_medialib_select (session, "DELETE FROM CollectionAttributes", NULL);
62 xmms_medialib_select (session, "DELETE FROM CollectionConnections", NULL);
63 xmms_medialib_select (session, "DELETE FROM CollectionIdlists", NULL);
64 xmms_medialib_select (session, "DELETE FROM CollectionLabels", NULL);
65 xmms_medialib_select (session, "DELETE FROM CollectionOperators", NULL);
66
67 /* Write all collections in all namespaces */
68 coll_dbwrite_t dbinfos = { session, 1, 0 }; /* ids start at 1 */
69 for (i = 0; i < XMMS_COLLECTION_NUM_NAMESPACES; ++i) {
70 dbinfos.nsid = i;
71 xmms_collection_foreach_in_namespace (dag, i, dbwrite_operator, &dbinfos);
72 }
73
75 dbwrite_strip_tmpprops, NULL);
76
77 xmms_medialib_end (session);
78}
79
80/** Restore the collection DAG from the database.
81 *
82 * @param dag The collection DAG to restore to.
83 */
84void
86{
87 xmmsv_coll_t *coll = NULL;
89 xmmsv_t *cmdval;
90 const gchar *query;
91 GList *res;
92 gint previd;
93
94 session = xmms_medialib_begin ();
95
96 /* Fetch all label-coll_operator for all namespaces, register in table */
97 query = "SELECT op.id AS id, lbl.name AS label, "
98 " lbl.namespace AS nsid, op.type AS type "
99 "FROM CollectionOperators AS op, CollectionLabels as lbl "
100 "WHERE op.id=lbl.collid "
101 "ORDER BY id";
102 res = xmms_medialib_select (session, query, NULL);
103
104 previd = -1;
105
106 while (res) {
107 gint id, type, nsid;
108 const gchar *label;
109
110 cmdval = (xmmsv_t*) res->data;
111 id = value_get_dict_int (cmdval, "id");
112 type = value_get_dict_int (cmdval, "type");
113 nsid = value_get_dict_int (cmdval, "nsid");
114 label = value_get_dict_string (cmdval, "label");
115
116 /* Do not duplicate operator if same id */
117 if (previd < 0 || id != previd) {
118 coll = xmms_collection_dbread_operator (session, id, type);
119 previd = id;
120 }
121 else {
122 xmmsv_coll_ref (coll); /* New label references the coll */
123 }
124
125 xmms_collection_dag_replace (dag, nsid, g_strdup (label), coll);
126
127 xmmsv_unref (cmdval);
128 res = g_list_delete_link (res, res);
129 }
130
131 xmms_medialib_end (session);
132
133 /* FIXME: validate ? */
134
135 /* Link references in collections to actual operators */
137}
138
139/** Given a collection id, query the DB to build the corresponding
140 * collection DAG.
141 *
142 * @param session The medialib session connected to the DB.
143 * @param id The id of the collection to create.
144 * @param type The type of the collection operator.
145 * @return The created collection DAG.
146 */
147static xmmsv_coll_t *
148xmms_collection_dbread_operator (xmms_medialib_session_t *session,
149 gint id, xmmsv_coll_type_t type)
150{
151 xmmsv_coll_t *coll;
152 xmmsv_coll_t *op;
153 GList *res;
154 GList *n;
155 xmmsv_t *cmdval;
156 gchar query[256];
157
158 coll = xmmsv_coll_new (type);
159
160 /* Retrieve the attributes */
161 g_snprintf (query, sizeof (query),
162 "SELECT attr.key AS key, attr.value AS value "
163 "FROM CollectionOperators AS op, CollectionAttributes AS attr "
164 "WHERE op.id=%d AND attr.collid=op.id", id);
165
166 res = xmms_medialib_select (session, query, NULL);
167 for (n = res; n; n = n->next) {
168 const gchar *key, *value;
169
170 cmdval = (xmmsv_t*) n->data;
171 key = value_get_dict_string (cmdval, "key");
172 value = value_get_dict_string (cmdval, "value");
173 xmmsv_coll_attribute_set (coll, key, value);
174
175 xmmsv_unref (n->data);
176 }
177 g_list_free (res);
178
179 /* Retrieve the idlist */
180 g_snprintf (query, sizeof (query),
181 "SELECT idl.mid AS mid "
182 "FROM CollectionOperators AS op, CollectionIdlists AS idl "
183 "WHERE op.id=%d AND idl.collid=op.id "
184 "ORDER BY idl.position", id);
185
186 res = xmms_medialib_select (session, query, NULL);
187 for (n = res; n; n = n->next) {
188
189 cmdval = (xmmsv_t *) n->data;
190 xmmsv_coll_idlist_append (coll, value_get_dict_int (cmdval, "mid"));
191
192 xmmsv_unref (cmdval);
193 }
194 g_list_free (res);
195
196 /* Retrieve the operands */
197 g_snprintf (query, sizeof (query),
198 "SELECT op.id AS id, op.type AS type "
199 "FROM CollectionOperators AS op, CollectionConnections AS conn "
200 "WHERE conn.to_id=%d AND conn.from_id=op.id", id);
201
202 res = xmms_medialib_select (session, query, NULL);
203 for (n = res; n; n = n->next) {
204 gint _id;
205 gint type;
206
207 cmdval = (xmmsv_t *) n->data;
208 _id = value_get_dict_int (cmdval, "id");
209 type = value_get_dict_int (cmdval, "type");
210
211 op = xmms_collection_dbread_operator (session, _id, type);
212 xmmsv_coll_add_operand (coll, op);
213
214 xmmsv_coll_unref (op);
215 xmmsv_unref (cmdval);
216 }
217 g_list_free (res);
218
219 return coll;
220}
221
222/** Write the given operator to the database under the given id.
223 *
224 * @param session The medialib session connected to the DB.
225 * @param collid The id under which to save the collection.
226 * @param coll The structure of the collection to save.
227 * @return The next free collection id.
228 */
229static guint
230xmms_collection_dbwrite_operator (xmms_medialib_session_t *session,
231 guint collid, xmmsv_coll_t *coll)
232{
233 gchar query[128];
236 gint i;
237 xmmsv_coll_t *op;
238 xmmsv_t *attrs;
239 gint newid, nextid;
240 coll_dbwrite_t dbwrite_infos = { session, collid, 0 };
241
242 /* Write operator */
243 g_snprintf (query, sizeof (query),
244 "INSERT INTO CollectionOperators VALUES(%d, %d)",
245 collid, xmmsv_coll_get_type (coll));
246
247 xmms_medialib_select (session, query, NULL);
248
249 /* Write attributes */
250 attrs = xmmsv_coll_attributes_get (coll);
251 xmmsv_dict_foreach (attrs, dbwrite_coll_attributes, &dbwrite_infos);
252 attrs = NULL; /* no unref needed. */
253
254 /* Write idlist */
256 for (xmmsv_list_iter_first (it), i = 0;
258 xmmsv_list_iter_next (it), i++) {
259
260 xmmsv_list_iter_entry_int (it, &entry);
261 g_snprintf (query, sizeof (query),
262 "INSERT INTO CollectionIdlists VALUES(%d, %d, %d)",
263 collid, i, entry);
264
265 xmms_medialib_select (session, query, NULL);
266 }
268
269 /* Save operands and connections (don't recurse in ref operand) */
270 newid = collid + 1;
272 xmmsv_t *tmp;
273 xmmsv_list_iter_t *iter;
274
276
277 for (xmmsv_list_iter_first (iter);
279 xmmsv_list_iter_next (iter)) {
280
281 xmmsv_list_iter_entry (iter, &tmp);
282 xmmsv_get_coll (tmp, &op);
283
284 nextid = xmms_collection_dbwrite_operator (session, newid, op);
285 g_snprintf (query, sizeof (query),
286 "INSERT INTO CollectionConnections VALUES(%d, %d)",
287 newid, collid);
288 xmms_medialib_select (session, query, NULL);
289 newid = nextid;
290 }
292 }
293
294 /* return next available id */
295 return newid;
296}
297
298/* For all label-operator pairs, write the operator and all its
299 * operands to the DB recursively. */
300static void
301dbwrite_operator (void *key, void *value, void *udata)
302{
303 gchar *query;
304 gchar *label = key;
305 xmmsv_coll_t *coll = value;
306 coll_dbwrite_t *dbinfos = udata;
307 gchar *esc_label;
308 gint serial_id;
309
310 /* Only serialize each operator once, get previous id if exists */
311 if (!xmms_collection_get_int_attr (coll, XMMS_COLLSERIAL_ATTR_ID, &serial_id)) {
312 serial_id = dbinfos->collid;
313 dbinfos->collid = xmms_collection_dbwrite_operator (dbinfos->session,
314 dbinfos->collid, coll);
316 }
317
318 esc_label = sqlite_prepare_string (label);
319 query = g_strdup_printf ("INSERT INTO CollectionLabels VALUES(%d, %d, %s)",
320 serial_id, dbinfos->nsid, esc_label);
321 xmms_medialib_select (dbinfos->session, query, NULL);
322
323 g_free (query);
324 g_free (esc_label);
325}
326
327/* Write all attributes of a collection to the DB. */
328static void
329dbwrite_coll_attributes (const char *key, xmmsv_t *value, void *udata)
330{
331 gchar *query;
332 coll_dbwrite_t *dbwrite_infos = udata;
333 gchar *esc_key;
334 gchar *esc_val;
335 const gchar *s;
336 int r;
337
338 r = xmmsv_get_string (value, &s);
339 g_return_if_fail (r);
340
341 esc_key = sqlite_prepare_string (key);
342 esc_val = sqlite_prepare_string (s);
343 query = g_strdup_printf ("INSERT INTO CollectionAttributes VALUES(%d, %s, %s)",
344 dbwrite_infos->collid, esc_key, esc_val);
345 xmms_medialib_select (dbwrite_infos->session, query, NULL);
346
347 g_free (query);
348 g_free (esc_key);
349 g_free (esc_val);
350}
351
352/* Remove all temp utility properties used to write collections to the DB. */
353static void
354dbwrite_strip_tmpprops (void *key, void *value, void *udata)
355{
356 xmmsv_coll_t *coll = value;
358}
359
360
361/* Extract the int value out of a xmmsv_t object. */
362static gint
363value_get_dict_int (xmmsv_t *val, const gchar *key)
364{
365 gint i;
366 xmmsv_dict_entry_get_int (val, key, &i);
367 return i;
368}
369
370/* Extract the string value out of a xmmsv_t object. */
371static const gchar *
372value_get_dict_string (xmmsv_t *val, const gchar *key)
373{
374 const gchar *s;
375 xmmsv_dict_entry_get_string (val, key, &s);
376 return s;
377}
void xmms_collection_foreach_in_namespace(xmms_coll_dag_t *dag, guint nsid, GHFunc f, void *udata)
Apply a function to all the collections in a given namespace.
void bind_all_references(xmms_coll_dag_t *dag, xmmsv_coll_t *coll, xmmsv_coll_t *parent, void *udata)
If a reference, add the operator of the pointed collection as an operand.
void xmms_collection_apply_to_all_collections(xmms_coll_dag_t *dag, FuncApplyToColl f, void *udata)
Apply a function of type FuncApplyToColl to all the collections in all namespaces.
void xmms_collection_dag_save(xmms_coll_dag_t *dag)
Save the collection DAG in the database.
Definition collserial.c:53
void xmms_collection_dag_restore(xmms_coll_dag_t *dag)
Restore the collection DAG from the database.
Definition collserial.c:85
struct xmmsv_St * xmmsv_coll_idlist_get(xmmsv_coll_t *coll)
Return the list of ids stored in the collection.
Definition coll.c:429
int xmmsv_coll_attribute_remove(xmmsv_coll_t *coll, const char *key)
Remove an attribute from the given collection.
Definition coll.c:481
xmmsv_coll_type_t xmmsv_coll_get_type(xmmsv_coll_t *coll)
Return the type of the collection.
Definition coll.c:367
xmmsv_coll_t * xmmsv_coll_ref(xmmsv_coll_t *coll)
Increases the references for the xmmsv_coll_t.
Definition coll.c:61
struct xmmsv_St * xmmsv_coll_operands_get(xmmsv_coll_t *coll)
Definition coll.c:437
void xmmsv_coll_unref(xmmsv_coll_t *coll)
Decreases the references for the xmmsv_coll_t When the number of references reaches 0 it will be free...
Definition coll.c:140
void xmmsv_coll_attribute_set(xmmsv_coll_t *coll, const char *key, const char *value)
Set an attribute in the given collection.
Definition coll.c:460
int xmmsv_coll_idlist_append(xmmsv_coll_t *coll, int id)
Append a value to the idlist.
Definition coll.c:252
struct xmmsv_St * xmmsv_coll_attributes_get(xmmsv_coll_t *coll)
Definition coll.c:445
xmmsv_coll_t * xmmsv_coll_new(xmmsv_coll_type_t type)
Allocate a new collection of the given type.
Definition coll.c:78
void xmmsv_coll_add_operand(xmmsv_coll_t *coll, xmmsv_coll_t *op)
Add the operand to the given collection.
Definition coll.c:195
gboolean xmms_collection_set_int_attr(xmmsv_coll_t *coll, const gchar *attrname, gint newval)
Set the attribute of a collection as an integer.
Definition collection.c:926
gboolean xmms_collection_get_int_attr(xmmsv_coll_t *coll, const gchar *attrname, gint *val)
Extract an attribute from a collection as an integer.
Definition collection.c:898
void xmms_collection_dag_replace(xmms_coll_dag_t *dag, xmms_collection_namespace_id_t nsid, gchar *key, xmmsv_coll_t *newcoll)
Update the DAG to update the value of the pair with the given key.
Definition collection.c:858
int xmmsv_dict_foreach(xmmsv_t *dictv, xmmsv_dict_foreach_func func, void *user_data)
Apply a function to each key-element pair in the list.
Definition value.c:1853
int xmmsv_dict_entry_get_string(xmmsv_t *val, const char *key, const char **r)
int xmmsv_dict_entry_get_int(xmmsv_t *val, const char *key, int32_t *r)
int xmmsv_get_list_iter(const xmmsv_t *val, xmmsv_list_iter_t **it)
Retrieves a list iterator from a list xmmsv_t.
Definition value.c:926
void xmmsv_list_iter_next(xmmsv_list_iter_t *it)
Advance the iterator to the next element in the list.
Definition value.c:1553
struct xmmsv_list_iter_St xmmsv_list_iter_t
Definition xmmsv_list.h:69
int xmmsv_list_iter_entry(xmmsv_list_iter_t *it, xmmsv_t **val)
Get the element currently pointed at by the iterator.
Definition value.c:1495
void xmmsv_list_iter_first(xmmsv_list_iter_t *it)
Rewind the iterator to the start of the list.
Definition value.c:1523
void xmmsv_list_iter_explicit_destroy(xmmsv_list_iter_t *it)
Explicitly free list iterator.
Definition value.c:1478
int xmmsv_list_iter_valid(xmmsv_list_iter_t *it)
Check whether the iterator is valid and points to a valid element.
Definition value.c:1512
int xmmsv_list_iter_entry_int(xmmsv_list_iter_t *it, int32_t *val)
GList * xmms_medialib_select(xmms_medialib_session_t *session, const gchar *query, xmms_error_t *error)
Get a list of GHashTables 's that matches the query.
Definition medialib.c:1380
void xmms_medialib_end(xmms_medialib_session_t *session)
Definition medialib.c:425
gchar * sqlite_prepare_string(const gchar *input)
Definition sqlite.c:809
void xmmsv_unref(xmmsv_t *val)
Decreases the references for the xmmsv_t When the number of references reaches 0 it will be freed.
Definition value.c:303
int xmmsv_get_coll(const xmmsv_t *val, xmmsv_coll_t **coll)
Retrieves a collection from the value.
Definition value.c:883
int xmmsv_get_string(const xmmsv_t *val, const char **r)
Retrieves a string from the value.
Definition value.c:863
struct xmmsv_St xmmsv_t
#define xmms_medialib_begin_write()
#define xmms_medialib_begin()
struct xmms_medialib_session_St xmms_medialib_session_t
G_BEGIN_DECLS typedef gint32 xmms_medialib_entry_t
#define XMMS_COLLECTION_NUM_NAMESPACES
xmms_collection_namespace_id_t
@ XMMS_COLLECTION_NSID_ALL
struct xmms_coll_dag_St xmms_coll_dag_t
#define XMMS_COLLSERIAL_ATTR_ID
xmmsv_coll_type_t
@ XMMS_COLLECTION_TYPE_REFERENCE
struct xmmsv_coll_St xmmsv_coll_t
Definition xmmsv_coll.h:28