37 } coll_query_params_t;
55 coll_query_params_t *params;
64 static coll_query_t* init_query (coll_query_params_t *params);
65 static void add_fetch_group_aliases (coll_query_t *query, coll_query_params_t *params);
66 static void destroy_query (coll_query_t* query);
67 static GString* xmms_collection_gen_query (coll_query_t *query);
70 static void query_append_uint (coll_query_t *query, guint i);
71 static void query_append_string (coll_query_t *query,
const gchar *s);
72 static void query_append_protect_string (coll_query_t *query, gchar *s);
75 static void query_append_filter (coll_query_t *query,
xmmsv_coll_type_t type, gchar *key, gchar *value, gboolean case_sens);
76 static void query_string_append_joins (gpointer key, gpointer val, gpointer udata);
77 static void query_string_append_alias_list (coll_query_t *query, GString *qstring,
xmmsv_t *fields);
78 static void query_string_append_fetch (coll_query_t *query, GString *qstring);
79 static void query_string_append_alias (GString *qstring, coll_query_alias_t *alias,
coll_query_value_type_t type);
81 static const gchar *canonical_field_name (
const gchar *field);
83 static coll_query_alias_t *query_make_alias (coll_query_t *query,
const gchar *field, gboolean optional);
84 static coll_query_alias_t *query_get_alias (coll_query_t *query,
const gchar *field);
98 guint limit_start, guint limit_len,
103 coll_query_params_t params = { limit_start, limit_len, order, fetch, group };
105 query = init_query (¶ms);
106 xmms_collection_append_to_query (dag, coll, query);
107 add_fetch_group_aliases (query, ¶ms);
109 qstring = xmms_collection_gen_query (query);
111 destroy_query (query);
119 init_query (coll_query_params_t *params)
123 query = g_new (coll_query_t, 1);
128 query->aliases = g_hash_table_new_full (g_str_hash, g_str_equal,
131 query->alias_count = 1;
132 query->alias_base = NULL;
133 query->conditions = g_string_new (NULL);
134 query->params = params;
140 append_each_alias (
xmmsv_t *value,
void *udata)
143 coll_query_t *query = (coll_query_t *) udata;
145 query_make_alias (query, name, TRUE);
149 add_fetch_group_aliases (coll_query_t *query, coll_query_params_t *params)
158 destroy_query (coll_query_t* query)
160 g_hash_table_destroy (query->aliases);
161 g_string_free (query->conditions, TRUE);
168 xmms_collection_gen_query (coll_query_t *query)
173 if (query->alias_base == NULL) {
178 if (query->conditions->len > 0) {
179 g_string_append (query->conditions,
" AND ");
181 g_string_append_printf (query->conditions,
182 "xmms_source_pref (m0.source) = "
183 "(SELECT MIN (xmms_source_pref (n.source)) FROM Media AS n "
184 "WHERE n.id = m0.id AND n.key = '%s')",
189 qstring = g_string_new (
"SELECT DISTINCT ");
190 query_string_append_fetch (query, qstring);
191 g_string_append (qstring,
" FROM Media AS m0");
192 g_hash_table_foreach (query->aliases, query_string_append_joins, qstring);
195 g_string_append_printf (qstring,
" WHERE m0.key='%s'", query->alias_base);
196 if (query->conditions->len > 0) {
197 g_string_append_printf (qstring,
" AND %s", query->conditions->str);
202 g_string_append (qstring,
" GROUP BY ");
203 query_string_append_alias_list (query, qstring, query->params->group);
209 g_string_append (qstring,
" ORDER BY ");
210 query_string_append_alias_list (query, qstring, query->params->order);
214 if (query->params->limit_len != 0) {
215 if (query->params->limit_start ) {
216 g_string_append_printf (qstring,
" LIMIT %u,%u",
217 query->params->limit_start,
218 query->params->limit_len);
220 g_string_append_printf (qstring,
" LIMIT %u",
221 query->params->limit_len);
236 gchar *attr1, *attr2, *attr3;
244 if (!operator_is_allmedia (coll)) {
245 query_append_operand (query, dag, coll);
248 query_append_string (query,
"1");
255 query_append_string (query,
"(");
264 query_append_string (query,
" OR ");
266 query_append_string (query,
" AND ");
272 xmms_collection_append_to_query (dag, op, query);
276 query_append_string (query,
")");
280 query_append_string (query,
"NOT ");
281 query_append_operand (query, dag, coll);
292 case_sens = (attr3 != NULL && strcmp (attr3,
"true") == 0);
294 query_append_string (query,
"(");
295 query_append_filter (query, type, attr1, attr2, case_sens);
297 query_append_intersect_operand (query, dag, coll);
298 query_append_string (query,
")");
305 query_append_string (query,
"m0.id IN (");
306 for (i = 0; idlist[i] != 0; ++i) {
308 query_append_string (query,
",");
310 query_append_uint (query, idlist[i]);
312 query_append_string (query,
")");
317 XMMS_DBG (
"Cannot append invalid collection operator!");
318 g_assert_not_reached ();
333 static coll_query_alias_t *
334 query_make_alias (coll_query_t *query,
const gchar *field, gboolean optional)
336 coll_query_alias_t *alias;
337 alias = g_hash_table_lookup (query->aliases, field);
341 gchar *fieldkey = g_strdup (field);
343 alias = g_new (coll_query_alias_t, 1);
344 alias->optional = optional;
347 if (strcmp (field,
"id") == 0) {
353 if (query->alias_base == NULL &&
356 query->alias_base = fieldkey;
358 alias->id = query->alias_count;
359 query->alias_count++;
363 g_hash_table_insert (query->aliases, fieldkey, alias);
366 }
else if (!alias->optional && optional) {
367 alias->optional = optional;
373 static coll_query_alias_t *
374 query_get_alias (coll_query_t *query,
const gchar *field)
376 return g_hash_table_lookup (query->aliases, field);
381 canonical_field_name (
const gchar *field) {
384 }
else if (*field ==
'~') {
397 return (target_name != NULL && strcmp (target_name,
"All Media") == 0);
401 query_append_uint (coll_query_t *query, guint i)
403 g_string_append_printf (query->conditions,
"%u", i);
407 query_append_string (coll_query_t *query,
const gchar *s)
409 g_string_append (query->conditions, s);
413 query_append_protect_string (coll_query_t *query, gchar *s)
417 query_append_string (query, preps);
443 xmms_collection_append_to_query (dag, op, query);
447 query_append_string (query,
"1");
452 query_append_intersect_operand (coll_query_t *query,
xmms_coll_dag_t *dag,
461 if (!operator_is_allmedia (op)) {
462 query_append_string (query,
" AND ");
463 xmms_collection_append_to_query (dag, op, query);
471 gchar *key, gchar *value, gboolean case_sens)
473 coll_query_alias_t *alias;
484 alias = query_make_alias (query, key, optional);
491 query_string_append_alias (query->conditions, alias,
494 query_append_string (query,
"(");
495 query_string_append_alias (query->conditions, alias,
497 query_append_string (query,
" COLLATE NOCASE)");
501 query_append_string (query,
"=");
504 query_append_string (query,
" GLOB ");
506 query_append_string (query,
" LIKE ");
511 temp = g_strdup(value);
512 for (i = 0; temp[i]; i++) {
514 case '*': temp[i] =
'%';
break;
515 case '?': temp[i] =
'_';
break;
519 query_append_protect_string (query, temp);
522 query_append_protect_string (query, value);
529 query_string_append_alias (query->conditions, alias,
532 query_append_string (query,
" < ");
534 query_append_string (query,
" > ");
536 query_append_string (query, value);
540 query_string_append_alias (query->conditions, alias,
542 query_append_string (query,
" is not null");
547 g_assert_not_reached ();
554 query_string_append_joins (gpointer key, gpointer val, gpointer udata)
558 coll_query_alias_t *alias;
561 qstring = (GString*)udata;
562 alias = (coll_query_alias_t*)val;
565 if (alias->optional) {
566 g_string_append_printf (qstring,
" LEFT");
569 g_string_append_printf (qstring,
570 " JOIN Media AS m%u ON m0.id=m%u.id AND m%u.key='%s' AND"
571 " xmms_source_pref (m%u.source) = "
572 "(SELECT MIN (xmms_source_pref (n.source)) FROM Media AS n"
573 " WHERE n.id = m0.id AND n.key = '%s')",
574 alias->id, alias->id, alias->id, field, alias->id, field);
580 query_string_append_alias_list (coll_query_t *query, GString *qstring,
583 coll_query_alias_t *alias;
586 gboolean first = TRUE;
593 const gchar *field, *canon_field;
596 canon_field = canonical_field_name (field);
598 if (first) first = FALSE;
600 g_string_append (qstring,
", ");
603 if (canon_field != NULL) {
604 alias = query_get_alias (query, canon_field);
606 query_string_append_alias (qstring, alias,
610 if (strcmp(canon_field,
"id") == 0) {
611 g_string_append (qstring,
"m0.id");
613 g_string_append_printf (qstring,
614 "(SELECT IFNULL (intval, value) "
615 "FROM Media WHERE id = m0.id AND key='%s' AND "
616 "xmms_source_pref (source) = "
617 "(SELECT MIN (xmms_source_pref (n.source)) "
618 "FROM Media AS n WHERE n.id = m0.id AND "
620 canon_field, canon_field);
628 g_string_append (qstring,
" DESC");
629 }
else if (*field ==
'~') {
631 g_string_append (qstring, field + 1);
637 query_string_append_fetch (coll_query_t *query, GString *qstring)
639 coll_query_alias_t *alias;
642 gboolean first = TRUE;
652 alias = query_make_alias (query, name, TRUE);
654 if (first) first = FALSE;
656 g_string_append (qstring,
", ");
659 query_string_append_alias (qstring, alias,
661 g_string_append_printf (qstring,
" AS %s", name);
666 query_string_append_alias (GString *qstring, coll_query_alias_t *alias,
669 switch (alias->type) {
673 g_string_append_printf (qstring,
"m%u.value", alias->id);
676 g_string_append_printf (qstring,
"m%u.intval", alias->id);
679 g_string_append_printf (qstring,
"IFNULL (m%u.intval, m%u.value)",
680 alias->id, alias->id);
686 g_string_append (qstring,
"m0.id");
int xmmsv_coll_attribute_get(xmmsv_coll_t *coll, const char *key, char **value)
Retrieve the value of the attribute of the given collection.
xmms_collection_namespace_id_t xmms_collection_get_namespace_id(const gchar *namespace)
Find the namespace id corresponding to a namespace string.
int xmmsv_list_get(xmmsv_t *listv, int pos, xmmsv_t **val)
Get the element at the given position in the list xmmsv_t.
int xmmsv_get_list_iter(const xmmsv_t *val, xmmsv_list_iter_t **it)
Retrieves a list iterator from a list xmmsv_t.
int xmmsv_list_iter_entry(xmmsv_list_iter_t *it, xmmsv_t **val)
Get the element currently pointed at by the iterator.
void xmmsv_list_iter_first(xmmsv_list_iter_t *it)
Rewind the iterator to the start of the list.
xmmsv_coll_t * xmms_collection_get_pointer(xmms_coll_dag_t *dag, const gchar *collname, guint nsid)
Find the collection structure corresponding to the given name in the given namespace.
struct xmmsv_St * xmmsv_coll_operands_get(xmmsv_coll_t *coll)
int xmmsv_list_get_coll(xmmsv_t *v, int pos, xmmsv_coll_t **val)
void xmmsv_list_iter_explicit_destroy(xmmsv_list_iter_t *it)
Explicitly free list iterator.
int xmmsv_get_coll(const xmmsv_t *val, xmmsv_coll_t **coll)
Retrieves a collection from the value.
struct xmmsv_coll_St xmmsv_coll_t
int xmmsv_list_get_size(xmmsv_t *listv)
Return the size of the list.
GString * xmms_collection_get_query(xmms_coll_dag_t *dag, xmmsv_coll_t *coll, guint limit_start, guint limit_len, xmmsv_t *order, xmmsv_t *fetch, xmmsv_t *group)
void xmmsv_list_iter_next(xmmsv_list_iter_t *it)
Advance the iterator to the next element in the list.
gchar * sqlite_prepare_string(const gchar *input)
#define XMMS_DBG(fmt,...)
int xmmsv_get_string(const xmmsv_t *val, const char **r)
Retrieves a string from the value.
uint32_t * xmmsv_coll_get_idlist(xmmsv_coll_t *coll)
Return the list of ids stored in the collection.
#define XMMS_COLLQUERY_DEFAULT_BASE
xmmsv_coll_type_t xmmsv_coll_get_type(xmmsv_coll_t *coll)
Return the type of the collection.
int xmmsv_list_foreach(xmmsv_t *listv, xmmsv_list_foreach_func func, void *user_data)
Apply a function to each element in the list, in sequential order.
struct xmmsv_list_iter_St xmmsv_list_iter_t
int xmmsv_list_iter_valid(xmmsv_list_iter_t *it)
Check whether the iterator is valid and points to a valid element.
struct xmms_coll_dag_St xmms_coll_dag_t