XMMS2
|
00001 /* XMMS2 - X Music Multiplexer System 00002 * Copyright (C) 2003-2011 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_int (coll_query_t *query, gint 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 (¶ms); 00106 xmms_collection_append_to_query (dag, coll, query); 00107 add_fetch_group_aliases (query, ¶ms); 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 xmmsv_coll_t *op; 00234 xmms_medialib_entry_t entry; 00235 gchar *attr1, *attr2, *attr3; 00236 gboolean case_sens; 00237 xmmsv_list_iter_t *iter; 00238 xmmsv_t *tmp; 00239 gboolean first; 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 first = TRUE; 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 (first) { 00263 first = FALSE; 00264 } else { 00265 if (type == XMMS_COLLECTION_TYPE_UNION) 00266 query_append_string (query, " OR "); 00267 else 00268 query_append_string (query, " AND "); 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 first = TRUE; 00305 query_append_string (query, "m0.id IN ("); 00306 00307 xmmsv_get_list_iter (xmmsv_coll_idlist_get (coll), &iter); 00308 for (xmmsv_list_iter_first (iter); 00309 xmmsv_list_iter_valid (iter); 00310 xmmsv_list_iter_next (iter)) { 00311 00312 if (first) { 00313 first = FALSE; 00314 } else { 00315 query_append_string (query, ","); 00316 } 00317 00318 xmmsv_list_iter_entry_int (iter, &entry); 00319 query_append_int (query, entry); 00320 } 00321 xmmsv_list_iter_explicit_destroy (iter); 00322 00323 query_append_string (query, ")"); 00324 break; 00325 00326 /* invalid type */ 00327 default: 00328 XMMS_DBG ("Cannot append invalid collection operator!"); 00329 g_assert_not_reached (); 00330 break; 00331 } 00332 00333 } 00334 00335 00336 /** Register a (unique) field alias in the query structure and return 00337 * the corresponding alias pointer. 00338 * 00339 * @param query The query object to insert the alias in. 00340 * @param field The name of the property that will correspond to the alias. 00341 * @param optional Whether the property can be optional (i.e. LEFT JOIN) 00342 * @return The alias pointer. 00343 */ 00344 static coll_query_alias_t * 00345 query_make_alias (coll_query_t *query, const gchar *field, gboolean optional) 00346 { 00347 coll_query_alias_t *alias; 00348 alias = g_hash_table_lookup (query->aliases, field); 00349 00350 /* Insert in the hashtable */ 00351 if (alias == NULL) { 00352 gchar *fieldkey = g_strdup (field); 00353 00354 alias = g_new (coll_query_alias_t, 1); 00355 alias->optional = optional; 00356 alias->id = 0; 00357 00358 if (strcmp (field, "id") == 0) { 00359 alias->type = XMMS_QUERY_ALIAS_ID; 00360 } else { 00361 alias->type = XMMS_QUERY_ALIAS_PROP; 00362 00363 /* Found a base */ 00364 if (query->alias_base == NULL && 00365 (!optional || strcmp (field, XMMS_COLLQUERY_DEFAULT_BASE) == 0)) { 00366 alias->id = 0; 00367 query->alias_base = fieldkey; 00368 } else { 00369 alias->id = query->alias_count; 00370 query->alias_count++; 00371 } 00372 } 00373 00374 g_hash_table_insert (query->aliases, fieldkey, alias); 00375 00376 /* If was not optional but now is, update */ 00377 } else if (!alias->optional && optional) { 00378 alias->optional = optional; 00379 } 00380 00381 return alias; 00382 } 00383 00384 static coll_query_alias_t * 00385 query_get_alias (coll_query_t *query, const gchar *field) 00386 { 00387 return g_hash_table_lookup (query->aliases, field); 00388 } 00389 00390 /* Find the canonical name of a field (strip flags, if any) */ 00391 static const gchar * 00392 canonical_field_name (const gchar *field) { 00393 if (*field == '-') { 00394 field++; 00395 } else if (*field == '~') { 00396 field = NULL; 00397 } 00398 return field; 00399 } 00400 00401 00402 /* Determine whether the given operator is a reference to "All Media" */ 00403 static gboolean 00404 operator_is_allmedia (xmmsv_coll_t *op) 00405 { 00406 gchar *target_name; 00407 xmmsv_coll_attribute_get (op, "reference", &target_name); 00408 return (target_name != NULL && strcmp (target_name, "All Media") == 0); 00409 } 00410 00411 static void 00412 query_append_int (coll_query_t *query, gint i) 00413 { 00414 g_string_append_printf (query->conditions, "%d", i); 00415 } 00416 00417 static void 00418 query_append_string (coll_query_t *query, const gchar *s) 00419 { 00420 g_string_append (query->conditions, s); 00421 } 00422 00423 static void 00424 query_append_protect_string (coll_query_t *query, gchar *s) 00425 { 00426 gchar *preps; 00427 if ((preps = sqlite_prepare_string (s)) != NULL) { /* FIXME: Return oom error */ 00428 query_append_string (query, preps); 00429 g_free (preps); 00430 } 00431 } 00432 00433 static void 00434 query_append_operand (coll_query_t *query, xmms_coll_dag_t *dag, xmmsv_coll_t *coll) 00435 { 00436 xmmsv_coll_t *op = NULL; 00437 gchar *target_name; 00438 gchar *target_ns; 00439 guint target_nsid; 00440 00441 if (!xmmsv_list_get_coll (xmmsv_coll_operands_get (coll), 0, &op)) { 00442 00443 /* Ref'd coll not saved as operand, look for it */ 00444 if (xmmsv_coll_attribute_get (coll, "reference", &target_name) && 00445 xmmsv_coll_attribute_get (coll, "namespace", &target_ns)) { 00446 00447 target_nsid = xmms_collection_get_namespace_id (target_ns); 00448 op = xmms_collection_get_pointer (dag, target_name, target_nsid); 00449 } 00450 } 00451 00452 /* Append reference operator */ 00453 if (op != NULL) { 00454 xmms_collection_append_to_query (dag, op, query); 00455 00456 /* Cannot find reference, append dummy TRUE */ 00457 } else { 00458 query_append_string (query, "1"); 00459 } 00460 } 00461 00462 static void 00463 query_append_intersect_operand (coll_query_t *query, xmms_coll_dag_t *dag, 00464 xmmsv_coll_t *coll) 00465 { 00466 xmmsv_coll_t *op; 00467 xmmsv_t *tmp; 00468 00469 if (xmmsv_list_get (xmmsv_coll_operands_get (coll), 0, &tmp)) { 00470 xmmsv_get_coll (tmp, &op); 00471 00472 if (!operator_is_allmedia (op)) { 00473 query_append_string (query, " AND "); 00474 xmms_collection_append_to_query (dag, op, query); 00475 } 00476 } 00477 } 00478 00479 /* Append a filtering clause on the field value, depending on the operator type. */ 00480 static void 00481 query_append_filter (coll_query_t *query, xmmsv_coll_type_t type, 00482 gchar *key, gchar *value, gboolean case_sens) 00483 { 00484 coll_query_alias_t *alias; 00485 gboolean optional; 00486 gchar *temp; 00487 gint i; 00488 00489 if (type == XMMS_COLLECTION_TYPE_HAS) { 00490 optional = TRUE; 00491 } else { 00492 optional = FALSE; 00493 } 00494 00495 alias = query_make_alias (query, key, optional); 00496 00497 switch (type) { 00498 /* escape strings */ 00499 case XMMS_COLLECTION_TYPE_EQUALS: 00500 case XMMS_COLLECTION_TYPE_MATCH: 00501 if (case_sens) { 00502 query_string_append_alias (query->conditions, alias, 00503 COLL_QUERY_VALUE_TYPE_STRING); 00504 } else { 00505 query_append_string (query, "("); 00506 query_string_append_alias (query->conditions, alias, 00507 COLL_QUERY_VALUE_TYPE_STRING); 00508 query_append_string (query, " COLLATE NOCASE)"); 00509 } 00510 00511 if (type == XMMS_COLLECTION_TYPE_EQUALS) { 00512 query_append_string (query, "="); 00513 } else { 00514 if (case_sens) { 00515 query_append_string (query, " GLOB "); 00516 } else { 00517 query_append_string (query, " LIKE "); 00518 } 00519 } 00520 00521 if (type == XMMS_COLLECTION_TYPE_MATCH && !case_sens) { 00522 temp = g_strdup(value); 00523 for (i = 0; temp[i]; i++) { 00524 switch (temp[i]) { 00525 case '*': temp[i] = '%'; break; 00526 case '?': temp[i] = '_'; break; 00527 default : break; 00528 } 00529 } 00530 query_append_protect_string (query, temp); 00531 g_free(temp); 00532 } else { 00533 query_append_protect_string (query, value); 00534 } 00535 break; 00536 00537 /* do not escape numerical values */ 00538 case XMMS_COLLECTION_TYPE_SMALLER: 00539 case XMMS_COLLECTION_TYPE_GREATER: 00540 query_string_append_alias (query->conditions, alias, 00541 COLL_QUERY_VALUE_TYPE_INT); 00542 if (type == XMMS_COLLECTION_TYPE_SMALLER) { 00543 query_append_string (query, " < "); 00544 } else { 00545 query_append_string (query, " > "); 00546 } 00547 query_append_string (query, value); 00548 break; 00549 00550 case XMMS_COLLECTION_TYPE_HAS: 00551 query_string_append_alias (query->conditions, alias, 00552 COLL_QUERY_VALUE_TYPE_STRING); 00553 query_append_string (query, " is not null"); 00554 break; 00555 00556 /* Called with invalid type? */ 00557 default: 00558 g_assert_not_reached (); 00559 break; 00560 } 00561 } 00562 00563 /* Append SELECT joins to the argument string for each alias of the hashtable. */ 00564 static void 00565 query_string_append_joins (gpointer key, gpointer val, gpointer udata) 00566 { 00567 gchar *field; 00568 GString *qstring; 00569 coll_query_alias_t *alias; 00570 00571 field = key; 00572 qstring = (GString*)udata; 00573 alias = (coll_query_alias_t*)val; 00574 00575 if ((alias->id > 0) && (alias->type == XMMS_QUERY_ALIAS_PROP)) { 00576 if (alias->optional) { 00577 g_string_append_printf (qstring, " LEFT"); 00578 } 00579 00580 g_string_append_printf (qstring, 00581 " JOIN Media AS m%u ON m0.id=m%u.id AND m%u.key='%s' AND" 00582 " xmms_source_pref (m%u.source) = " 00583 "(SELECT MIN (xmms_source_pref (n.source)) FROM Media AS n" 00584 " WHERE n.id = m0.id AND n.key = '%s')", 00585 alias->id, alias->id, alias->id, field, alias->id, field); 00586 } 00587 } 00588 00589 /* Given a list of fields, append the corresponding aliases to the argument string. */ 00590 static void 00591 query_string_append_alias_list (coll_query_t *query, GString *qstring, 00592 xmmsv_t *fields) 00593 { 00594 coll_query_alias_t *alias; 00595 xmmsv_list_iter_t *it; 00596 xmmsv_t *valstr; 00597 gboolean first = TRUE; 00598 00599 for (xmmsv_get_list_iter (fields, &it); 00600 xmmsv_list_iter_valid (it); 00601 xmmsv_list_iter_next (it)) { 00602 00603 /* extract string from cmdval_t */ 00604 const gchar *field, *canon_field; 00605 xmmsv_list_iter_entry (it, &valstr); 00606 xmmsv_get_string (valstr, &field); 00607 canon_field = canonical_field_name (field); 00608 00609 if (first) first = FALSE; 00610 else { 00611 g_string_append (qstring, ", "); 00612 } 00613 00614 if (canon_field != NULL) { 00615 alias = query_get_alias (query, canon_field); 00616 if (alias != NULL) { 00617 query_string_append_alias (qstring, alias, 00618 COLL_QUERY_VALUE_TYPE_BOTH); 00619 } else { 00620 if (*field != '~') { 00621 if (strcmp(canon_field, "id") == 0) { 00622 g_string_append (qstring, "m0.id"); 00623 } else { 00624 g_string_append_printf (qstring, 00625 "(SELECT IFNULL (intval, value) " 00626 "FROM Media WHERE id = m0.id AND key='%s' AND " 00627 "xmms_source_pref (source) = " 00628 "(SELECT MIN (xmms_source_pref (n.source)) " 00629 "FROM Media AS n WHERE n.id = m0.id AND " 00630 "n.key = '%s'))", 00631 canon_field, canon_field); 00632 } 00633 } 00634 } 00635 } 00636 00637 /* special prefix for ordering */ 00638 if (*field == '-') { 00639 g_string_append (qstring, " DESC"); 00640 } else if (*field == '~') { 00641 /* FIXME: Temporary hack to allow custom ordering functions */ 00642 g_string_append (qstring, field + 1); 00643 } 00644 } 00645 } 00646 00647 static void 00648 query_string_append_fetch (coll_query_t *query, GString *qstring) 00649 { 00650 coll_query_alias_t *alias; 00651 xmmsv_list_iter_t *it; 00652 xmmsv_t *valstr; 00653 gboolean first = TRUE; 00654 const gchar *name; 00655 00656 for (xmmsv_get_list_iter (query->params->fetch, &it); 00657 xmmsv_list_iter_valid (it); 00658 xmmsv_list_iter_next (it)) { 00659 00660 /* extract string from cmdval_t */ 00661 xmmsv_list_iter_entry (it, &valstr); 00662 xmmsv_get_string (valstr, &name); 00663 alias = query_make_alias (query, name, TRUE); 00664 00665 if (first) first = FALSE; 00666 else { 00667 g_string_append (qstring, ", "); 00668 } 00669 00670 query_string_append_alias (qstring, alias, 00671 COLL_QUERY_VALUE_TYPE_BOTH); 00672 g_string_append_printf (qstring, " AS %s", name); 00673 } 00674 } 00675 00676 static void 00677 query_string_append_alias (GString *qstring, coll_query_alias_t *alias, 00678 coll_query_value_type_t type) 00679 { 00680 switch (alias->type) { 00681 case XMMS_QUERY_ALIAS_PROP: 00682 switch (type) { 00683 case COLL_QUERY_VALUE_TYPE_STRING: 00684 g_string_append_printf (qstring, "m%u.value", alias->id); 00685 break; 00686 case COLL_QUERY_VALUE_TYPE_INT: 00687 g_string_append_printf (qstring, "m%u.intval", alias->id); 00688 break; 00689 case COLL_QUERY_VALUE_TYPE_BOTH: 00690 g_string_append_printf (qstring, "IFNULL (m%u.intval, m%u.value)", 00691 alias->id, alias->id); 00692 break; 00693 } 00694 break; 00695 00696 case XMMS_QUERY_ALIAS_ID: 00697 g_string_append (qstring, "m0.id"); 00698 break; 00699 00700 default: 00701 break; 00702 } 00703 } 00704 00705 /** 00706 * @} 00707 */