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 
24 #include "xmmspriv/xmms_medialib.h"
25 
26 
27 /* Internal helper structures */
28 
29 typedef struct {
30  xmms_medialib_session_t *session;
31  guint collid;
33 } coll_dbwrite_t;
34 
35 
36 static xmmsv_coll_t *xmms_collection_dbread_operator (xmms_medialib_session_t *session, gint id, xmmsv_coll_type_t type);
37 static guint xmms_collection_dbwrite_operator (xmms_medialib_session_t *session, guint collid, xmmsv_coll_t *coll);
38 
39 static void dbwrite_operator (void *key, void *value, void *udata);
40 static void dbwrite_coll_attributes (const char *key, xmmsv_t *value, void *udata);
41 static void dbwrite_strip_tmpprops (void *key, void *value, void *udata);
42 
43 static gint value_get_dict_int (xmmsv_t *val, const gchar *key);
44 static 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  */
52 void
54 {
55  gint i;
56  xmms_medialib_session_t *session;
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  */
84 void
86 {
87  xmmsv_coll_t *coll = NULL;
88  xmms_medialib_session_t *session;
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  */
147 static xmmsv_coll_t *
148 xmms_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  */
229 static guint
230 xmms_collection_dbwrite_operator (xmms_medialib_session_t *session,
231  guint collid, xmmsv_coll_t *coll)
232 {
233  gchar query[128];
234  xmms_medialib_entry_t entry;
235  xmmsv_list_iter_t *it;
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);
278  xmmsv_list_iter_valid (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. */
300 static void
301 dbwrite_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. */
328 static void
329 dbwrite_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. */
353 static void
354 dbwrite_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. */
362 static gint
363 value_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. */
371 static const gchar *
372 value_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 xmmsv_list_iter_first(xmmsv_list_iter_t *it)
Rewind the iterator to the start of the list.
Definition: value.c:1523
G_BEGIN_DECLS typedef gint32 xmms_medialib_entry_t
Definition: xmms_medialib.h:86
struct xmmsv_list_iter_St xmmsv_list_iter_t
Definition: xmmsv_list.h:69
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
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.
Definition: collection.c:1503
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_t
Definition: xmmsv_general.h:48
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
xmmsv_coll_t * xmmsv_coll_ref(xmmsv_coll_t *coll)
Increases the references for the xmmsv_coll_t.
Definition: coll.c:61
int xmmsv_coll_attribute_remove(xmmsv_coll_t *coll, const char *key)
Remove an attribute from the given collection.
Definition: coll.c:481
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
xmmsv_coll_type_t
GList * xmms_medialib_select(xmms_medialib_session_t *session, const gchar *query, xmms_error_t *error)
Get a list of GHashTables &#39;s that matches the query.
Definition: medialib.c:1380
struct xmmsv_St * xmmsv_coll_operands_get(xmmsv_coll_t *coll)
Definition: coll.c:437
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
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
struct xmmsv_St * xmmsv_coll_idlist_get(xmmsv_coll_t *coll)
Return the list of ids stored in the collection.
Definition: coll.c:429
xmms_collection_namespace_id_t
void xmmsv_list_iter_next(xmmsv_list_iter_t *it)
Advance the iterator to the next element in the list.
Definition: value.c:1553
int xmmsv_dict_entry_get_int(xmmsv_t *val, const char *key, int32_t *r)
void xmmsv_list_iter_explicit_destroy(xmmsv_list_iter_t *it)
Explicitly free list iterator.
Definition: value.c:1478
struct xmmsv_coll_St xmmsv_coll_t
Definition: xmmsv_coll.h:28
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.
Definition: collection.c:1393
void xmms_collection_dag_save(xmms_coll_dag_t *dag)
Save the collection DAG in the database.
Definition: collserial.c:53
int xmmsv_dict_entry_get_string(xmmsv_t *val, const char *key, const char **r)
#define XMMS_COLLSERIAL_ATTR_ID
gchar * sqlite_prepare_string(const gchar *input)
Definition: sqlite.c:809
xmmsv_coll_t * xmmsv_coll_new(xmmsv_coll_type_t type)
Allocate a new collection of the given type.
Definition: coll.c:78
struct xmmsv_St * xmmsv_coll_attributes_get(xmmsv_coll_t *coll)
Definition: coll.c:445
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
void xmmsv_coll_add_operand(xmmsv_coll_t *coll, xmmsv_coll_t *op)
Add the operand to the given collection.
Definition: coll.c:195
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
struct xmms_medialib_session_St xmms_medialib_session_t
Definition: xmms_medialib.h:87
#define XMMS_COLLECTION_NUM_NAMESPACES
void xmms_collection_dag_restore(xmms_coll_dag_t *dag)
Restore the collection DAG from the database.
Definition: collserial.c:85
#define xmms_medialib_begin_write()
#define xmms_medialib_begin()
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_get_string(const xmmsv_t *val, const char **r)
Retrieves a string from the value.
Definition: value.c:863
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.
Definition: collection.c:1373
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
int xmmsv_list_iter_entry_int(xmmsv_list_iter_t *it, int32_t *val)
xmmsv_coll_type_t xmmsv_coll_get_type(xmmsv_coll_t *coll)
Return the type of the collection.
Definition: coll.c:367
void xmms_medialib_end(xmms_medialib_session_t *session)
Definition: medialib.c:425
int xmmsv_get_coll(const xmmsv_t *val, xmmsv_coll_t **coll)
Retrieves a collection from the value.
Definition: value.c:883
struct xmms_coll_dag_St xmms_coll_dag_t
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