XMMS2
collserial.c
Go to the documentation of this file.
1 /* XMMS2 - X Music Multiplexer System
2  * Copyright (C) 2003-2009 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  guint *idlist;
235  gint i;
236  xmmsv_coll_t *op;
237  xmmsv_t *attrs;
238  gint newid, nextid;
239  coll_dbwrite_t dbwrite_infos = { session, collid, 0 };
240 
241  /* Write operator */
242  g_snprintf (query, sizeof (query),
243  "INSERT INTO CollectionOperators VALUES(%d, %d)",
244  collid, xmmsv_coll_get_type (coll));
245 
246  xmms_medialib_select (session, query, NULL);
247 
248  /* Write attributes */
249  attrs = xmmsv_coll_attributes_get (coll);
250  xmmsv_dict_foreach (attrs, dbwrite_coll_attributes, &dbwrite_infos);
251  attrs = NULL; /* no unref needed. */
252 
253  /* Write idlist */
254  idlist = xmmsv_coll_get_idlist (coll);
255  for (i = 0; idlist[i] != 0; i++) {
256  g_snprintf (query, sizeof (query),
257  "INSERT INTO CollectionIdlists VALUES(%d, %d, %d)",
258  collid, i, idlist[i]);
259 
260  xmms_medialib_select (session, query, NULL);
261  }
262 
263  /* Save operands and connections (don't recurse in ref operand) */
264  newid = collid + 1;
266  xmmsv_t *tmp;
267  xmmsv_list_iter_t *iter;
268 
270 
271  for (xmmsv_list_iter_first (iter);
272  xmmsv_list_iter_valid (iter);
273  xmmsv_list_iter_next (iter)) {
274 
275  xmmsv_list_iter_entry (iter, &tmp);
276  xmmsv_get_coll (tmp, &op);
277 
278  nextid = xmms_collection_dbwrite_operator (session, newid, op);
279  g_snprintf (query, sizeof (query),
280  "INSERT INTO CollectionConnections VALUES(%d, %d)",
281  newid, collid);
282  xmms_medialib_select (session, query, NULL);
283  newid = nextid;
284  }
286  }
287 
288  /* return next available id */
289  return newid;
290 }
291 
292 /* For all label-operator pairs, write the operator and all its
293  * operands to the DB recursively. */
294 static void
295 dbwrite_operator (void *key, void *value, void *udata)
296 {
297  gchar *query;
298  gchar *label = key;
299  xmmsv_coll_t *coll = value;
300  coll_dbwrite_t *dbinfos = udata;
301  gchar *esc_label;
302  gint serial_id;
303 
304  /* Only serialize each operator once, get previous id if exists */
305  if (!xmms_collection_get_int_attr (coll, XMMS_COLLSERIAL_ATTR_ID, &serial_id)) {
306  serial_id = dbinfos->collid;
307  dbinfos->collid = xmms_collection_dbwrite_operator (dbinfos->session,
308  dbinfos->collid, coll);
310  }
311 
312  esc_label = sqlite_prepare_string (label);
313  query = g_strdup_printf ("INSERT INTO CollectionLabels VALUES(%d, %d, %s)",
314  serial_id, dbinfos->nsid, esc_label);
315  xmms_medialib_select (dbinfos->session, query, NULL);
316 
317  g_free (query);
318  g_free (esc_label);
319 }
320 
321 /* Write all attributes of a collection to the DB. */
322 static void
323 dbwrite_coll_attributes (const char *key, xmmsv_t *value, void *udata)
324 {
325  gchar *query;
326  coll_dbwrite_t *dbwrite_infos = udata;
327  gchar *esc_key;
328  gchar *esc_val;
329  const gchar *s;
330  int r;
331 
332  r = xmmsv_get_string (value, &s);
333  g_return_if_fail (r);
334 
335  esc_key = sqlite_prepare_string (key);
336  esc_val = sqlite_prepare_string (s);
337  query = g_strdup_printf ("INSERT INTO CollectionAttributes VALUES(%d, %s, %s)",
338  dbwrite_infos->collid, esc_key, esc_val);
339  xmms_medialib_select (dbwrite_infos->session, query, NULL);
340 
341  g_free (query);
342  g_free (esc_key);
343  g_free (esc_val);
344 }
345 
346 /* Remove all temp utility properties used to write collections to the DB. */
347 static void
348 dbwrite_strip_tmpprops (void *key, void *value, void *udata)
349 {
350  xmmsv_coll_t *coll = value;
352 }
353 
354 
355 /* Extract the int value out of a xmmsv_t object. */
356 static gint
357 value_get_dict_int (xmmsv_t *val, const gchar *key)
358 {
359  gint i;
360  xmmsv_dict_entry_get_int (val, key, &i);
361  return i;
362 }
363 
364 /* Extract the string value out of a xmmsv_t object. */
365 static const gchar *
366 value_get_dict_string (xmmsv_t *val, const gchar *key)
367 {
368  const gchar *s;
369  xmmsv_dict_entry_get_string (val, key, &s);
370  return s;
371 }
struct xmmsv_St xmmsv_t
Definition: xmmsv.h:51
int xmmsv_coll_idlist_append(xmmsv_coll_t *coll, unsigned int id)
Append a value to the idlist.
Definition: coll.c:275
int xmmsv_dict_entry_get_int(xmmsv_t *val, const char *key, int32_t *r)
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:301
int xmmsv_dict_entry_get_string(xmmsv_t *val, const char *key, const char **r)
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:1559
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:918
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:1487
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:512
xmmsv_coll_t * xmmsv_coll_ref(xmmsv_coll_t *coll)
Increases the references for the xmmsv_coll_t.
Definition: coll.c:66
void xmmsv_list_iter_first(xmmsv_list_iter_t *it)
Rewind the iterator to the start of the list.
Definition: value.c:1515
int xmmsv_coll_attribute_remove(xmmsv_coll_t *coll, const char *key)
Remove an attribute from the given collection.
Definition: coll.c:533
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:1422
struct xmmsv_St * xmmsv_coll_operands_get(xmmsv_coll_t *coll)
Definition: coll.c:489
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:952
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:1845
xmms_collection_namespace_id_t
void xmmsv_list_iter_explicit_destroy(xmmsv_list_iter_t *it)
Explicitly free list iterator.
Definition: value.c:1470
int xmmsv_get_coll(const xmmsv_t *val, xmmsv_coll_t **coll)
Retrieves a collection from the value.
Definition: value.c:875
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:1449
void xmmsv_list_iter_next(xmmsv_list_iter_t *it)
Advance the iterator to the next element in the list.
Definition: value.c:1545
void xmms_collection_dag_save(xmms_coll_dag_t *dag)
Save the collection DAG in the database.
Definition: collserial.c:53
#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:83
struct xmmsv_St * xmmsv_coll_attributes_get(xmmsv_coll_t *coll)
Definition: coll.c:497
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:980
void xmmsv_coll_add_operand(xmmsv_coll_t *coll, xmmsv_coll_t *op)
Add the operand to the given collection.
Definition: coll.c:218
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:912
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_get_string(const xmmsv_t *val, const char **r)
Retrieves a string from the value.
Definition: value.c:855
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:1429
uint32_t * xmmsv_coll_get_idlist(xmmsv_coll_t *coll)
Return the list of ids stored in the 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:464
void xmms_medialib_end(xmms_medialib_session_t *session)
Definition: medialib.c:470
struct xmmsv_list_iter_St xmmsv_list_iter_t
Definition: xmmsv.h:53
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:1504
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:147