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_int (coll_query_t *query, gint 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);
235 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,
"(");
266 query_append_string (query,
" OR ");
268 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 (");
315 query_append_string (query,
",");
319 query_append_int (query, entry);
323 query_append_string (query,
")");
328 XMMS_DBG (
"Cannot append invalid collection operator!");
329 g_assert_not_reached ();
344 static coll_query_alias_t *
345 query_make_alias (coll_query_t *query,
const gchar *field, gboolean optional)
347 coll_query_alias_t *alias;
348 alias = g_hash_table_lookup (query->aliases, field);
352 gchar *fieldkey = g_strdup (field);
354 alias = g_new (coll_query_alias_t, 1);
355 alias->optional = optional;
358 if (strcmp (field,
"id") == 0) {
364 if (query->alias_base == NULL &&
367 query->alias_base = fieldkey;
369 alias->id = query->alias_count;
370 query->alias_count++;
374 g_hash_table_insert (query->aliases, fieldkey, alias);
377 }
else if (!alias->optional && optional) {
378 alias->optional = optional;
384 static coll_query_alias_t *
385 query_get_alias (coll_query_t *query,
const gchar *field)
387 return g_hash_table_lookup (query->aliases, field);
392 canonical_field_name (
const gchar *field) {
395 }
else if (*field ==
'~') {
408 return (target_name != NULL && strcmp (target_name,
"All Media") == 0);
412 query_append_int (coll_query_t *query, gint i)
414 g_string_append_printf (query->conditions,
"%d", i);
418 query_append_string (coll_query_t *query,
const gchar *s)
420 g_string_append (query->conditions, s);
424 query_append_protect_string (coll_query_t *query, gchar *s)
428 query_append_string (query, preps);
454 xmms_collection_append_to_query (dag, op, query);
458 query_append_string (query,
"1");
463 query_append_intersect_operand (coll_query_t *query,
xmms_coll_dag_t *dag,
472 if (!operator_is_allmedia (op)) {
473 query_append_string (query,
" AND ");
474 xmms_collection_append_to_query (dag, op, query);
482 gchar *key, gchar *value, gboolean case_sens)
484 coll_query_alias_t *alias;
495 alias = query_make_alias (query, key, optional);
502 query_string_append_alias (query->conditions, alias,
505 query_append_string (query,
"(");
506 query_string_append_alias (query->conditions, alias,
508 query_append_string (query,
" COLLATE NOCASE)");
512 query_append_string (query,
"=");
515 query_append_string (query,
" GLOB ");
517 query_append_string (query,
" LIKE ");
522 temp = g_strdup(value);
523 for (i = 0; temp[i]; i++) {
525 case '*': temp[i] =
'%';
break;
526 case '?': temp[i] =
'_';
break;
530 query_append_protect_string (query, temp);
533 query_append_protect_string (query, value);
540 query_string_append_alias (query->conditions, alias,
543 query_append_string (query,
" < ");
545 query_append_string (query,
" > ");
547 query_append_string (query, value);
551 query_string_append_alias (query->conditions, alias,
553 query_append_string (query,
" is not null");
558 g_assert_not_reached ();
565 query_string_append_joins (gpointer key, gpointer val, gpointer udata)
569 coll_query_alias_t *alias;
572 qstring = (GString*)udata;
573 alias = (coll_query_alias_t*)val;
576 if (alias->optional) {
577 g_string_append_printf (qstring,
" LEFT");
580 g_string_append_printf (qstring,
581 " JOIN Media AS m%u ON m0.id=m%u.id AND m%u.key='%s' AND" 582 " xmms_source_pref (m%u.source) = " 583 "(SELECT MIN (xmms_source_pref (n.source)) FROM Media AS n" 584 " WHERE n.id = m0.id AND n.key = '%s')",
585 alias->id, alias->id, alias->id, field, alias->id, field);
591 query_string_append_alias_list (coll_query_t *query, GString *qstring,
594 coll_query_alias_t *alias;
597 gboolean first = TRUE;
604 const gchar *field, *canon_field;
607 canon_field = canonical_field_name (field);
609 if (first) first = FALSE;
611 g_string_append (qstring,
", ");
614 if (canon_field != NULL) {
615 alias = query_get_alias (query, canon_field);
617 query_string_append_alias (qstring, alias,
621 if (strcmp(canon_field,
"id") == 0) {
622 g_string_append (qstring,
"m0.id");
624 g_string_append_printf (qstring,
625 "(SELECT IFNULL (intval, value) " 626 "FROM Media WHERE id = m0.id AND key='%s' AND " 627 "xmms_source_pref (source) = " 628 "(SELECT MIN (xmms_source_pref (n.source)) " 629 "FROM Media AS n WHERE n.id = m0.id AND " 631 canon_field, canon_field);
639 g_string_append (qstring,
" DESC");
640 }
else if (*field ==
'~') {
642 g_string_append (qstring, field + 1);
648 query_string_append_fetch (coll_query_t *query, GString *qstring)
650 coll_query_alias_t *alias;
653 gboolean first = TRUE;
663 alias = query_make_alias (query, name, TRUE);
665 if (first) first = FALSE;
667 g_string_append (qstring,
", ");
670 query_string_append_alias (qstring, alias,
672 g_string_append_printf (qstring,
" AS %s", name);
677 query_string_append_alias (GString *qstring, coll_query_alias_t *alias,
680 switch (alias->type) {
684 g_string_append_printf (qstring,
"m%u.value", alias->id);
687 g_string_append_printf (qstring,
"m%u.intval", alias->id);
690 g_string_append_printf (qstring,
"IFNULL (m%u.intval, m%u.value)",
691 alias->id, alias->id);
697 g_string_append (qstring,
"m0.id");
void xmmsv_list_iter_first(xmmsv_list_iter_t *it)
Rewind the iterator to the start of the list.
struct xmmsv_list_iter_St xmmsv_list_iter_t
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.
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.
int xmmsv_get_list_iter(const xmmsv_t *val, xmmsv_list_iter_t **it)
Retrieves a list iterator from a list xmmsv_t.
struct xmmsv_St * xmmsv_coll_operands_get(xmmsv_coll_t *coll)
struct xmmsv_St * xmmsv_coll_idlist_get(xmmsv_coll_t *coll)
Return the list of ids stored in the collection.
void xmmsv_list_iter_next(xmmsv_list_iter_t *it)
Advance the iterator to the next element in the list.
void xmmsv_list_iter_explicit_destroy(xmmsv_list_iter_t *it)
Explicitly free list iterator.
struct xmmsv_coll_St xmmsv_coll_t
int xmmsv_list_get(xmmsv_t *listv, int pos, xmmsv_t **val)
Get the element at the given position in the list xmmsv_t.
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)
gchar * sqlite_prepare_string(const gchar *input)
int xmmsv_list_get_size(xmmsv_t *listv)
Return the size of the list.
#define XMMS_DBG(fmt,...)
int xmmsv_list_iter_valid(xmmsv_list_iter_t *it)
Check whether the iterator is valid and points to a valid element.
int xmmsv_get_string(const xmmsv_t *val, const char **r)
Retrieves a string from the value.
int xmmsv_list_iter_entry(xmmsv_list_iter_t *it, xmmsv_t **val)
Get the element currently pointed at by the iterator.
int xmmsv_list_iter_entry_int(xmmsv_list_iter_t *it, int32_t *val)
int xmmsv_list_get_coll(xmmsv_t *v, int pos, xmmsv_coll_t **val)
#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.
int xmmsv_get_coll(const xmmsv_t *val, xmmsv_coll_t **coll)
Retrieves a collection from the value.
struct xmms_coll_dag_St xmms_coll_dag_t