XMMS2

src/xmms/collquery.c

Go to the documentation of this file.
00001 /*  XMMS2 - X Music Multiplexer System
00002  *  Copyright (C) 2003-2009 XMMS2 Team
00003  *
00004  *  PLUGINS ARE NOT CONSIDERED TO BE DERIVED WORK !!!
00005  *
00006  *  This library is free software; you can redistribute it and/or
00007  *  modify it under the terms of the GNU Lesser General Public
00008  *  License as published by the Free Software Foundation; either
00009  *  version 2.1 of the License, or (at your option) any later version.
00010  *
00011  *  This library is distributed in the hope that it will be useful,
00012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  *  Lesser General Public License for more details.
00015  */
00016 
00017 
00018 /** @file
00019  *  Functions to build an SQL query from a collection.
00020  */
00021 
00022 #include <string.h>
00023 #include <glib.h>
00024 
00025 #include "xmmspriv/xmms_collquery.h"
00026 #include "xmms/xmms_log.h"
00027 
00028 
00029 /* Query structures */
00030 
00031 typedef struct {
00032     guint limit_start;
00033     guint limit_len;
00034     xmmsv_t *order;
00035     xmmsv_t *fetch;
00036     xmmsv_t *group;
00037 } coll_query_params_t;
00038 
00039 typedef enum {
00040     XMMS_QUERY_ALIAS_ID,
00041     XMMS_QUERY_ALIAS_PROP,
00042 } coll_query_alias_type_t;
00043 
00044 typedef struct {
00045     coll_query_alias_type_t type;
00046     guint id;
00047     gboolean optional;
00048 } coll_query_alias_t;
00049 
00050 typedef struct {
00051     GHashTable *aliases;
00052     guint alias_count;
00053     gchar *alias_base;
00054     GString *conditions;
00055     coll_query_params_t *params;
00056 } coll_query_t;
00057 
00058 typedef enum {
00059     COLL_QUERY_VALUE_TYPE_STRING,
00060     COLL_QUERY_VALUE_TYPE_INT,
00061     COLL_QUERY_VALUE_TYPE_BOTH
00062 } coll_query_value_type_t;
00063 
00064 static coll_query_t* init_query (coll_query_params_t *params);
00065 static void add_fetch_group_aliases (coll_query_t *query, coll_query_params_t *params);
00066 static void destroy_query (coll_query_t* query);
00067 static GString* xmms_collection_gen_query (coll_query_t *query);
00068 static void xmms_collection_append_to_query (xmms_coll_dag_t *dag, xmmsv_coll_t *coll, coll_query_t *query);
00069 
00070 static void query_append_uint (coll_query_t *query, guint i);
00071 static void query_append_string (coll_query_t *query, const gchar *s);
00072 static void query_append_protect_string (coll_query_t *query, gchar *s);
00073 static void query_append_operand (coll_query_t *query, xmms_coll_dag_t *dag, xmmsv_coll_t *coll);
00074 static void query_append_intersect_operand (coll_query_t *query, xmms_coll_dag_t *dag, xmmsv_coll_t *coll);
00075 static void query_append_filter (coll_query_t *query, xmmsv_coll_type_t type, gchar *key, gchar *value, gboolean case_sens);
00076 static void query_string_append_joins (gpointer key, gpointer val, gpointer udata);
00077 static void query_string_append_alias_list (coll_query_t *query, GString *qstring, xmmsv_t *fields);
00078 static void query_string_append_fetch (coll_query_t *query, GString *qstring);
00079 static void query_string_append_alias (GString *qstring, coll_query_alias_t *alias, coll_query_value_type_t type);
00080 
00081 static const gchar *canonical_field_name (const gchar *field);
00082 static gboolean operator_is_allmedia (xmmsv_coll_t *op);
00083 static coll_query_alias_t *query_make_alias (coll_query_t *query, const gchar *field, gboolean optional);
00084 static coll_query_alias_t *query_get_alias (coll_query_t *query, const gchar *field);
00085 
00086 
00087 
00088 /** @defgroup CollectionQuery CollectionQuery
00089   * @ingroup XMMSServer
00090   * @brief This module generates queries from collections.
00091   *
00092   * @{
00093   */
00094 
00095 /* Generate a query string from a collection and query parameters. */
00096 GString*
00097 xmms_collection_get_query (xmms_coll_dag_t *dag, xmmsv_coll_t *coll,
00098                            guint limit_start, guint limit_len,
00099                            xmmsv_t *order, xmmsv_t *fetch, xmmsv_t *group)
00100 {
00101     GString *qstring;
00102     coll_query_t *query;
00103     coll_query_params_t params = { limit_start, limit_len, order, fetch, group };
00104 
00105     query = init_query (&params);
00106     xmms_collection_append_to_query (dag, coll, query);
00107     add_fetch_group_aliases (query, &params);
00108 
00109     qstring = xmms_collection_gen_query (query);
00110 
00111     destroy_query (query);
00112 
00113     return qstring;
00114 }
00115 
00116 
00117 /* Initialize a query structure */
00118 static coll_query_t*
00119 init_query (coll_query_params_t *params)
00120 {
00121     coll_query_t *query;
00122 
00123     query = g_new (coll_query_t, 1);
00124     if (query == NULL) {
00125         return NULL;
00126     }
00127 
00128     query->aliases = g_hash_table_new_full (g_str_hash, g_str_equal,
00129                                             g_free, g_free);
00130 
00131     query->alias_count = 1;
00132     query->alias_base = NULL;
00133     query->conditions = g_string_new (NULL);
00134     query->params = params;
00135 
00136     return query;
00137 }
00138 
00139 static void
00140 append_each_alias (xmmsv_t *value, void *udata)
00141 {
00142     const gchar *name;
00143     coll_query_t *query = (coll_query_t *) udata;
00144     xmmsv_get_string (value, &name);
00145     query_make_alias (query, name, TRUE);
00146 }
00147 
00148 static void
00149 add_fetch_group_aliases (coll_query_t *query, coll_query_params_t *params)
00150 {
00151     /* Prepare aliases for the group/fetch fields */
00152     xmmsv_list_foreach (query->params->group, append_each_alias, query);
00153     xmmsv_list_foreach (query->params->fetch, append_each_alias, query);
00154 }
00155 
00156 /* Free a coll_query_t object */
00157 static void
00158 destroy_query (coll_query_t* query)
00159 {
00160     g_hash_table_destroy (query->aliases);
00161     g_string_free (query->conditions, TRUE);
00162     g_free (query);
00163 }
00164 
00165 
00166 /* Generate a query string from a query structure. */
00167 static GString*
00168 xmms_collection_gen_query (coll_query_t *query)
00169 {
00170     GString *qstring;
00171 
00172     /* If no alias base yet (m0), select the default base property */
00173     if (query->alias_base == NULL) {
00174         query_make_alias (query, XMMS_COLLQUERY_DEFAULT_BASE, FALSE);
00175     } else {
00176         /* We are actually interested in the property of m0...
00177            Let's make sure it comes from a good source. */
00178         if (query->conditions->len > 0) {
00179             g_string_append (query->conditions, " AND ");
00180         }
00181         g_string_append_printf (query->conditions,
00182             "xmms_source_pref (m0.source) = "
00183             "(SELECT MIN (xmms_source_pref (n.source)) FROM Media AS n "
00184              "WHERE n.id = m0.id AND n.key = '%s')",
00185             query->alias_base);
00186     }
00187 
00188     /* Append select and joins */
00189     qstring = g_string_new ("SELECT DISTINCT ");
00190     query_string_append_fetch (query, qstring);
00191     g_string_append (qstring, " FROM Media AS m0");
00192     g_hash_table_foreach (query->aliases, query_string_append_joins, qstring);
00193 
00194     /* Append conditions */
00195     g_string_append_printf (qstring, " WHERE m0.key='%s'", query->alias_base);
00196     if (query->conditions->len > 0) {
00197         g_string_append_printf (qstring, " AND %s", query->conditions->str);
00198     }
00199 
00200     /* Append grouping */
00201     if (xmmsv_list_get_size (query->params->group) > 0) {
00202         g_string_append (qstring, " GROUP BY ");
00203         query_string_append_alias_list (query, qstring, query->params->group);
00204     }
00205 
00206     /* Append ordering */
00207     /* FIXME: Ordering is Teh Broken (source?) */
00208     if (xmmsv_list_get_size (query->params->order) > 0) {
00209         g_string_append (qstring, " ORDER BY ");
00210         query_string_append_alias_list (query, qstring, query->params->order);
00211     }
00212 
00213     /* Append limit */
00214     if (query->params->limit_len != 0) {
00215         if (query->params->limit_start ) {
00216             g_string_append_printf (qstring, " LIMIT %u,%u",
00217                                     query->params->limit_start,
00218                                     query->params->limit_len);
00219         } else {
00220             g_string_append_printf (qstring, " LIMIT %u",
00221                                     query->params->limit_len);
00222         }
00223     }
00224 
00225     return qstring;
00226 }
00227 
00228 /* Recursively append conditions corresponding to the given collection to the query. */
00229 static void
00230 xmms_collection_append_to_query (xmms_coll_dag_t *dag, xmmsv_coll_t *coll,
00231                                  coll_query_t *query)
00232 {
00233     gint i;
00234     xmmsv_coll_t *op;
00235     guint *idlist;
00236     gchar *attr1, *attr2, *attr3;
00237     gboolean case_sens;
00238     xmmsv_list_iter_t *iter;
00239     xmmsv_t *tmp;
00240 
00241     xmmsv_coll_type_t type = xmmsv_coll_get_type (coll);
00242     switch (type) {
00243     case XMMS_COLLECTION_TYPE_REFERENCE:
00244         if (!operator_is_allmedia (coll)) {
00245             query_append_operand (query, dag, coll);
00246         } else {
00247             /* FIXME: Hackish solution to append a ref to All Media */
00248             query_append_string (query, "1");
00249         }
00250         break;
00251 
00252     case XMMS_COLLECTION_TYPE_UNION:
00253     case XMMS_COLLECTION_TYPE_INTERSECTION:
00254         i = 0;
00255         query_append_string (query, "(");
00256 
00257         xmmsv_get_list_iter (xmmsv_coll_operands_get (coll), &iter);
00258 
00259         for (xmmsv_list_iter_first (iter);
00260              xmmsv_list_iter_valid (iter);
00261              xmmsv_list_iter_next (iter)) {
00262             if (i != 0) {
00263                 if (type == XMMS_COLLECTION_TYPE_UNION)
00264                     query_append_string (query, " OR ");
00265                 else
00266                     query_append_string (query, " AND ");
00267             } else {
00268                 i = 1;
00269             }
00270             xmmsv_list_iter_entry (iter, &tmp);
00271             xmmsv_get_coll (tmp, &op);
00272             xmms_collection_append_to_query (dag, op, query);
00273         }
00274         xmmsv_list_iter_explicit_destroy (iter);
00275 
00276         query_append_string (query, ")");
00277         break;
00278 
00279     case XMMS_COLLECTION_TYPE_COMPLEMENT:
00280         query_append_string (query, "NOT ");
00281         query_append_operand (query, dag, coll);
00282         break;
00283 
00284     case XMMS_COLLECTION_TYPE_HAS:
00285     case XMMS_COLLECTION_TYPE_EQUALS:
00286     case XMMS_COLLECTION_TYPE_MATCH:
00287     case XMMS_COLLECTION_TYPE_SMALLER:
00288     case XMMS_COLLECTION_TYPE_GREATER:
00289         xmmsv_coll_attribute_get (coll, "field", &attr1);
00290         xmmsv_coll_attribute_get (coll, "value", &attr2);
00291         xmmsv_coll_attribute_get (coll, "case-sensitive", &attr3);
00292         case_sens = (attr3 != NULL && strcmp (attr3, "true") == 0);
00293 
00294         query_append_string (query, "(");
00295         query_append_filter (query, type, attr1, attr2, case_sens);
00296 
00297         query_append_intersect_operand (query, dag, coll);
00298         query_append_string (query, ")");
00299         break;
00300 
00301     case XMMS_COLLECTION_TYPE_IDLIST:
00302     case XMMS_COLLECTION_TYPE_QUEUE:
00303     case XMMS_COLLECTION_TYPE_PARTYSHUFFLE:
00304         idlist = xmmsv_coll_get_idlist (coll);
00305         query_append_string (query, "m0.id IN (");
00306         for (i = 0; idlist[i] != 0; ++i) {
00307             if (i != 0) {
00308                 query_append_string (query, ",");
00309             }
00310             query_append_uint (query, idlist[i]);
00311         }
00312         query_append_string (query, ")");
00313         break;
00314 
00315     /* invalid type */
00316     default:
00317         XMMS_DBG ("Cannot append invalid collection operator!");
00318         g_assert_not_reached ();
00319         break;
00320     }
00321 
00322 }
00323 
00324 
00325 /** Register a (unique) field alias in the query structure and return
00326  * the corresponding alias pointer.
00327  *
00328  * @param query  The query object to insert the alias in.
00329  * @param field  The name of the property that will correspond to the alias.
00330  * @param optional  Whether the property can be optional (i.e. LEFT JOIN)
00331  * @return  The alias pointer.
00332  */
00333 static coll_query_alias_t *
00334 query_make_alias (coll_query_t *query, const gchar *field, gboolean optional)
00335 {
00336     coll_query_alias_t *alias;
00337     alias = g_hash_table_lookup (query->aliases, field);
00338 
00339     /* Insert in the hashtable */
00340     if (alias == NULL) {
00341         gchar *fieldkey = g_strdup (field);
00342 
00343         alias = g_new (coll_query_alias_t, 1);
00344         alias->optional = optional;
00345         alias->id = 0;
00346 
00347         if (strcmp (field, "id") == 0) {
00348             alias->type = XMMS_QUERY_ALIAS_ID;
00349         } else {
00350             alias->type = XMMS_QUERY_ALIAS_PROP;
00351 
00352             /* Found a base */
00353             if (query->alias_base == NULL &&
00354                 (!optional || strcmp (field, XMMS_COLLQUERY_DEFAULT_BASE) == 0)) {
00355                 alias->id = 0;
00356                 query->alias_base = fieldkey;
00357             } else {
00358                 alias->id = query->alias_count;
00359                 query->alias_count++;
00360             }
00361         }
00362 
00363         g_hash_table_insert (query->aliases, fieldkey, alias);
00364 
00365     /* If was not optional but now is, update */
00366     } else if (!alias->optional && optional) {
00367         alias->optional = optional;
00368     }
00369 
00370     return alias;
00371 }
00372 
00373 static coll_query_alias_t *
00374 query_get_alias (coll_query_t *query, const gchar *field)
00375 {
00376     return g_hash_table_lookup (query->aliases, field);
00377 }
00378 
00379 /* Find the canonical name of a field (strip flags, if any) */
00380 static const gchar *
00381 canonical_field_name (const gchar *field) {
00382     if (*field == '-') {
00383         field++;
00384     } else if (*field == '~') {
00385         field = NULL;
00386     }
00387     return field;
00388 }
00389 
00390 
00391 /* Determine whether the given operator is a reference to "All Media" */
00392 static gboolean
00393 operator_is_allmedia (xmmsv_coll_t *op)
00394 {
00395     gchar *target_name;
00396     xmmsv_coll_attribute_get (op, "reference", &target_name);
00397     return (target_name != NULL && strcmp (target_name, "All Media") == 0);
00398 }
00399 
00400 static void
00401 query_append_uint (coll_query_t *query, guint i)
00402 {
00403     g_string_append_printf (query->conditions, "%u", i);
00404 }
00405 
00406 static void
00407 query_append_string (coll_query_t *query, const gchar *s)
00408 {
00409     g_string_append (query->conditions, s);
00410 }
00411 
00412 static void
00413 query_append_protect_string (coll_query_t *query, gchar *s)
00414 {
00415     gchar *preps;
00416     if ((preps = sqlite_prepare_string (s)) != NULL) {  /* FIXME: Return oom error */
00417         query_append_string (query, preps);
00418         g_free (preps);
00419     }
00420 }
00421 
00422 static void
00423 query_append_operand (coll_query_t *query, xmms_coll_dag_t *dag, xmmsv_coll_t *coll)
00424 {
00425     xmmsv_coll_t *op = NULL;
00426     gchar *target_name;
00427     gchar *target_ns;
00428     guint  target_nsid;
00429 
00430     if (!xmmsv_list_get_coll (xmmsv_coll_operands_get (coll), 0, &op)) {
00431 
00432         /* Ref'd coll not saved as operand, look for it */
00433         if (xmmsv_coll_attribute_get (coll, "reference", &target_name) &&
00434             xmmsv_coll_attribute_get (coll, "namespace", &target_ns)) {
00435 
00436             target_nsid = xmms_collection_get_namespace_id (target_ns);
00437             op = xmms_collection_get_pointer (dag, target_name, target_nsid);
00438         }
00439     }
00440 
00441     /* Append reference operator */
00442     if (op != NULL) {
00443         xmms_collection_append_to_query (dag, op, query);
00444 
00445     /* Cannot find reference, append dummy TRUE */
00446     } else {
00447         query_append_string (query, "1");
00448     }
00449 }
00450 
00451 static void
00452 query_append_intersect_operand (coll_query_t *query, xmms_coll_dag_t *dag,
00453                                 xmmsv_coll_t *coll)
00454 {
00455     xmmsv_coll_t *op;
00456     xmmsv_t *tmp;
00457 
00458     if (xmmsv_list_get (xmmsv_coll_operands_get (coll), 0, &tmp)) {
00459         xmmsv_get_coll (tmp, &op);
00460 
00461         if (!operator_is_allmedia (op)) {
00462             query_append_string (query, " AND ");
00463             xmms_collection_append_to_query (dag, op, query);
00464         }
00465     }
00466 }
00467 
00468 /* Append a filtering clause on the field value, depending on the operator type. */
00469 static void
00470 query_append_filter (coll_query_t *query, xmmsv_coll_type_t type,
00471                      gchar *key, gchar *value, gboolean case_sens)
00472 {
00473     coll_query_alias_t *alias;
00474     gboolean optional;
00475     gchar *temp;
00476     gint i;
00477 
00478     if (type == XMMS_COLLECTION_TYPE_HAS) {
00479         optional = TRUE;
00480     } else {
00481         optional = FALSE;
00482     }
00483 
00484     alias = query_make_alias (query, key, optional);
00485 
00486     switch (type) {
00487     /* escape strings */
00488     case XMMS_COLLECTION_TYPE_EQUALS:
00489     case XMMS_COLLECTION_TYPE_MATCH:
00490         if (case_sens) {
00491             query_string_append_alias (query->conditions, alias,
00492                                        COLL_QUERY_VALUE_TYPE_STRING);
00493         } else {
00494             query_append_string (query, "(");
00495             query_string_append_alias (query->conditions, alias,
00496                                        COLL_QUERY_VALUE_TYPE_STRING);
00497             query_append_string (query, " COLLATE NOCASE)");
00498         }
00499 
00500         if (type == XMMS_COLLECTION_TYPE_EQUALS) {
00501             query_append_string (query, "=");
00502         } else {
00503             if (case_sens) {
00504                 query_append_string (query, " GLOB ");
00505             } else {
00506                 query_append_string (query, " LIKE ");
00507             }
00508         }
00509 
00510         if (type == XMMS_COLLECTION_TYPE_MATCH && !case_sens) {
00511             temp = g_strdup(value);
00512             for (i = 0; temp[i]; i++) {
00513                 switch (temp[i]) {
00514                     case '*': temp[i] = '%'; break;
00515                     case '?': temp[i] = '_'; break;
00516                     default :                break;
00517                 }
00518             }
00519             query_append_protect_string (query, temp);
00520             g_free(temp);
00521         } else {
00522             query_append_protect_string (query, value);
00523         }
00524         break;
00525 
00526     /* do not escape numerical values */
00527     case XMMS_COLLECTION_TYPE_SMALLER:
00528     case XMMS_COLLECTION_TYPE_GREATER:
00529         query_string_append_alias (query->conditions, alias,
00530                                    COLL_QUERY_VALUE_TYPE_INT);
00531         if (type == XMMS_COLLECTION_TYPE_SMALLER) {
00532             query_append_string (query, " < ");
00533         } else {
00534             query_append_string (query, " > ");
00535         }
00536         query_append_string (query, value);
00537         break;
00538 
00539     case XMMS_COLLECTION_TYPE_HAS:
00540         query_string_append_alias (query->conditions, alias,
00541                                    COLL_QUERY_VALUE_TYPE_STRING);
00542         query_append_string (query, " is not null");
00543         break;
00544 
00545     /* Called with invalid type? */
00546     default:
00547         g_assert_not_reached ();
00548         break;
00549     }
00550 }
00551 
00552 /* Append SELECT joins to the argument string for each alias of the hashtable. */
00553 static void
00554 query_string_append_joins (gpointer key, gpointer val, gpointer udata)
00555 {
00556     gchar *field;
00557     GString *qstring;
00558     coll_query_alias_t *alias;
00559 
00560     field = key;
00561     qstring = (GString*)udata;
00562     alias = (coll_query_alias_t*)val;
00563 
00564     if ((alias->id > 0) && (alias->type == XMMS_QUERY_ALIAS_PROP)) {
00565         if (alias->optional) {
00566             g_string_append_printf (qstring, " LEFT");
00567         }
00568 
00569         g_string_append_printf (qstring,
00570             " JOIN Media AS m%u ON m0.id=m%u.id AND m%u.key='%s' AND"
00571             " xmms_source_pref (m%u.source) = "
00572                 "(SELECT MIN (xmms_source_pref (n.source)) FROM Media AS n"
00573                 " WHERE n.id = m0.id AND n.key = '%s')",
00574             alias->id, alias->id, alias->id, field, alias->id, field);
00575     }
00576 }
00577 
00578 /* Given a list of fields, append the corresponding aliases to the argument string. */
00579 static void
00580 query_string_append_alias_list (coll_query_t *query, GString *qstring,
00581                                 xmmsv_t *fields)
00582 {
00583     coll_query_alias_t *alias;
00584     xmmsv_list_iter_t *it;
00585     xmmsv_t *valstr;
00586     gboolean first = TRUE;
00587 
00588     for (xmmsv_get_list_iter (fields, &it);
00589          xmmsv_list_iter_valid (it);
00590          xmmsv_list_iter_next (it)) {
00591 
00592         /* extract string from cmdval_t */
00593         const gchar *field, *canon_field;
00594         xmmsv_list_iter_entry (it, &valstr);
00595         xmmsv_get_string (valstr, &field);
00596         canon_field = canonical_field_name (field);
00597 
00598         if (first) first = FALSE;
00599         else {
00600             g_string_append (qstring, ", ");
00601         }
00602 
00603         if (canon_field != NULL) {
00604             alias = query_get_alias (query, canon_field);
00605             if (alias != NULL) {
00606                 query_string_append_alias (qstring, alias,
00607                                            COLL_QUERY_VALUE_TYPE_BOTH);
00608             } else {
00609                 if (*field != '~') {
00610                     if (strcmp(canon_field, "id") == 0) {
00611                         g_string_append (qstring, "m0.id");
00612                     } else {
00613                         g_string_append_printf (qstring,
00614                             "(SELECT IFNULL (intval, value) "
00615                              "FROM Media WHERE id = m0.id AND key='%s' AND "
00616                              "xmms_source_pref (source) = "
00617                               "(SELECT MIN (xmms_source_pref (n.source)) "
00618                                "FROM Media AS n WHERE n.id = m0.id AND "
00619                                                      "n.key = '%s'))",
00620                             canon_field, canon_field);
00621                     }
00622                 }
00623             }
00624         }
00625 
00626         /* special prefix for ordering */
00627         if (*field == '-') {
00628             g_string_append (qstring, " DESC");
00629         } else if (*field == '~') {
00630             /* FIXME: Temporary hack to allow custom ordering functions */
00631             g_string_append (qstring, field + 1);
00632         }
00633     }
00634 }
00635 
00636 static void
00637 query_string_append_fetch (coll_query_t *query, GString *qstring)
00638 {
00639     coll_query_alias_t *alias;
00640     xmmsv_list_iter_t *it;
00641     xmmsv_t *valstr;
00642     gboolean first = TRUE;
00643     const gchar *name;
00644 
00645     for (xmmsv_get_list_iter (query->params->fetch, &it);
00646          xmmsv_list_iter_valid (it);
00647          xmmsv_list_iter_next (it)) {
00648 
00649         /* extract string from cmdval_t */
00650         xmmsv_list_iter_entry (it, &valstr);
00651         xmmsv_get_string (valstr, &name);
00652         alias = query_make_alias (query, name, TRUE);
00653 
00654         if (first) first = FALSE;
00655         else {
00656             g_string_append (qstring, ", ");
00657         }
00658 
00659         query_string_append_alias (qstring, alias,
00660                                    COLL_QUERY_VALUE_TYPE_BOTH);
00661         g_string_append_printf (qstring, " AS %s", name);
00662     }
00663 }
00664 
00665 static void
00666 query_string_append_alias (GString *qstring, coll_query_alias_t *alias,
00667                            coll_query_value_type_t type)
00668 {
00669     switch (alias->type) {
00670     case XMMS_QUERY_ALIAS_PROP:
00671         switch (type) {
00672         case COLL_QUERY_VALUE_TYPE_STRING:
00673             g_string_append_printf (qstring, "m%u.value", alias->id);
00674             break;
00675         case COLL_QUERY_VALUE_TYPE_INT:
00676             g_string_append_printf (qstring, "m%u.intval", alias->id);
00677             break;
00678         case COLL_QUERY_VALUE_TYPE_BOTH:
00679             g_string_append_printf (qstring, "IFNULL (m%u.intval, m%u.value)",
00680                                     alias->id, alias->id);
00681             break;
00682         }
00683         break;
00684 
00685     case XMMS_QUERY_ALIAS_ID:
00686         g_string_append (qstring, "m0.id");
00687         break;
00688 
00689     default:
00690         break;
00691     }
00692 }
00693 
00694 /**
00695  * @}
00696  */