| File: | build-analysis/../src/xmms/medialib_query_result.c |
| Warning: | line 321, column 12 Function call argument is an uninitialized value |
| 1 | /* XMMS2 - X Music Multiplexer System | |||
| 2 | * Copyright (C) 2003-2017 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 | #include <xmmspriv/xmms_fetch_info.h> | |||
| 18 | #include <xmmspriv/xmms_fetch_spec.h> | |||
| 19 | #include "s4.h" | |||
| 20 | ||||
| 21 | #include <glib.h> | |||
| 22 | #include <glib/gstdio.h> | |||
| 23 | ||||
| 24 | xmmsv_t *xmms_medialib_query_to_xmmsv (s4_resultset_t *set, xmms_fetch_spec_t *spec); | |||
| 25 | ||||
| 26 | typedef struct { | |||
| 27 | gint64 sum; | |||
| 28 | gint n; | |||
| 29 | } avg_data_t; | |||
| 30 | ||||
| 31 | typedef struct { | |||
| 32 | xmmsv_t *data; | |||
| 33 | gint n; | |||
| 34 | } random_data_t; | |||
| 35 | ||||
| 36 | typedef struct { | |||
| 37 | GHashTable *ht; | |||
| 38 | xmmsv_t *list; | |||
| 39 | } set_data_t; | |||
| 40 | ||||
| 41 | static xmmsv_t * | |||
| 42 | aggregate_first (xmmsv_t *current, gint int_value, const gchar *str_value) | |||
| 43 | { | |||
| 44 | if (current != NULL((void*)0)) { | |||
| 45 | return current; | |||
| 46 | } | |||
| 47 | ||||
| 48 | if (str_value != NULL((void*)0)) { | |||
| 49 | current = xmmsv_new_string (str_value); | |||
| 50 | } else { | |||
| 51 | current = xmmsv_new_int (int_value); | |||
| 52 | } | |||
| 53 | ||||
| 54 | return current; | |||
| 55 | } | |||
| 56 | ||||
| 57 | static xmmsv_t * | |||
| 58 | aggregate_list (xmmsv_t *current, gint int_value, const gchar *str_value) | |||
| 59 | { | |||
| 60 | if (current == NULL((void*)0)) { | |||
| 61 | current = xmmsv_new_list (); | |||
| 62 | } | |||
| 63 | ||||
| 64 | if (str_value != NULL((void*)0)) { | |||
| 65 | xmmsv_list_append_string (current, str_value); | |||
| 66 | } else { | |||
| 67 | xmmsv_list_append_int (current, int_value); | |||
| 68 | } | |||
| 69 | ||||
| 70 | return current; | |||
| 71 | } | |||
| 72 | ||||
| 73 | static xmmsv_t * | |||
| 74 | aggregate_set (xmmsv_t *current, gint int_value, const gchar *str_value) | |||
| 75 | { | |||
| 76 | set_data_t *data; | |||
| 77 | xmmsv_t *value; | |||
| 78 | gpointer key; | |||
| 79 | guint length; | |||
| 80 | ||||
| 81 | if (current == NULL((void*)0)) { | |||
| 82 | set_data_t init = { | |||
| 83 | .ht = g_hash_table_new (NULL((void*)0), NULL((void*)0)), | |||
| 84 | .list = xmmsv_new_list () | |||
| 85 | }; | |||
| 86 | current = xmmsv_new_bin ((guchar *) &init, sizeof (set_data_t)); | |||
| 87 | } | |||
| 88 | ||||
| 89 | xmmsv_get_bin (current, (const guchar **) &data, &length); | |||
| 90 | ||||
| 91 | if (str_value != NULL((void*)0)) { | |||
| 92 | value = xmmsv_new_string (str_value); | |||
| 93 | key = (gpointer) str_value; | |||
| 94 | } else { | |||
| 95 | value = xmmsv_new_int (int_value); | |||
| 96 | key = GINT_TO_POINTER (int_value)((gpointer) (glong) (int_value)); | |||
| 97 | } | |||
| 98 | ||||
| 99 | if (g_hash_table_lookup (data->ht, key) == NULL((void*)0)) { | |||
| 100 | g_hash_table_insert (data->ht, key, value); | |||
| 101 | xmmsv_list_append (data->list, value); | |||
| 102 | } | |||
| 103 | ||||
| 104 | xmmsv_unref (value); | |||
| 105 | ||||
| 106 | return current; | |||
| 107 | } | |||
| 108 | ||||
| 109 | static xmmsv_t * | |||
| 110 | aggregate_sum (xmmsv_t *current, gint int_value, const gchar *str_value) | |||
| 111 | { | |||
| 112 | int64_t old_value = 0; | |||
| 113 | ||||
| 114 | if (str_value != NULL((void*)0)) { | |||
| 115 | /* 'sum' only applies to numbers */ | |||
| 116 | return current; | |||
| 117 | } | |||
| 118 | ||||
| 119 | if (current != NULL((void*)0)) { | |||
| 120 | xmmsv_get_int64 (current, &old_value); | |||
| 121 | } | |||
| 122 | ||||
| 123 | return xmmsv_new_int (old_value + int_value); | |||
| 124 | } | |||
| 125 | ||||
| 126 | static xmmsv_t * | |||
| 127 | aggregate_min (xmmsv_t *current, gint int_value, const gchar *str_value) | |||
| 128 | { | |||
| 129 | gint old_value; | |||
| 130 | ||||
| 131 | if (str_value != NULL((void*)0)) { | |||
| 132 | /* 'min' only applies to numbers */ | |||
| 133 | return current; | |||
| 134 | } | |||
| 135 | ||||
| 136 | if (current == NULL((void*)0)) { | |||
| 137 | return xmmsv_new_int (int_value); | |||
| 138 | } | |||
| 139 | ||||
| 140 | xmmsv_get_intxmmsv_get_int32 (current, &old_value); | |||
| 141 | ||||
| 142 | if (old_value > int_value) { | |||
| 143 | return xmmsv_new_int (int_value); | |||
| 144 | } | |||
| 145 | ||||
| 146 | return current; | |||
| 147 | } | |||
| 148 | ||||
| 149 | static xmmsv_t * | |||
| 150 | aggregate_max (xmmsv_t *current, gint int_value, const gchar *str_value) | |||
| 151 | { | |||
| 152 | gint old_value; | |||
| 153 | ||||
| 154 | if (str_value != NULL((void*)0)) { | |||
| 155 | /* 'max' only applies to numbers */ | |||
| 156 | return current; | |||
| 157 | } | |||
| 158 | ||||
| 159 | if (current == NULL((void*)0)) { | |||
| 160 | return xmmsv_new_int (int_value); | |||
| 161 | } | |||
| 162 | ||||
| 163 | xmmsv_get_intxmmsv_get_int32 (current, &old_value); | |||
| 164 | ||||
| 165 | if (old_value < int_value) { | |||
| 166 | return xmmsv_new_int (int_value); | |||
| 167 | } | |||
| 168 | ||||
| 169 | return current; | |||
| 170 | } | |||
| 171 | ||||
| 172 | static xmmsv_t * | |||
| 173 | aggregate_random (xmmsv_t *current, gint int_value, const gchar *str_value) | |||
| 174 | { | |||
| 175 | random_data_t *data; | |||
| 176 | guint length; | |||
| 177 | ||||
| 178 | if (current == NULL((void*)0)) { | |||
| 179 | random_data_t init = { 0 }; | |||
| 180 | current = xmmsv_new_bin ((guchar *) &init, sizeof (random_data_t)); | |||
| 181 | } | |||
| 182 | ||||
| 183 | xmmsv_get_bin (current, (const guchar **) &data, &length); | |||
| 184 | ||||
| 185 | data->n++; | |||
| 186 | ||||
| 187 | if (g_random_int_range (0, data->n) == 0) { | |||
| 188 | if (data->data != NULL((void*)0)) { | |||
| 189 | xmmsv_unref (data->data); | |||
| 190 | } | |||
| 191 | ||||
| 192 | if (str_value != NULL((void*)0)) { | |||
| 193 | data->data = xmmsv_new_string (str_value); | |||
| 194 | } else { | |||
| 195 | data->data = xmmsv_new_int (int_value); | |||
| 196 | } | |||
| 197 | } | |||
| 198 | ||||
| 199 | return current; | |||
| 200 | } | |||
| 201 | ||||
| 202 | static xmmsv_t * | |||
| 203 | aggregate_average (xmmsv_t *current, gint int_value, const gchar *str_value) | |||
| 204 | { | |||
| 205 | avg_data_t *data; | |||
| 206 | guint length; | |||
| 207 | ||||
| 208 | if (current == NULL((void*)0)) { | |||
| 209 | avg_data_t init = { 0 }; | |||
| 210 | current = xmmsv_new_bin ((guchar *) &init, sizeof (avg_data_t)); | |||
| 211 | } | |||
| 212 | ||||
| 213 | xmmsv_get_bin (current, (const guchar **) &data, &length); | |||
| 214 | ||||
| 215 | if (str_value == NULL((void*)0)) { | |||
| 216 | data->n++; | |||
| 217 | data->sum += int_value; | |||
| 218 | } | |||
| 219 | ||||
| 220 | return current; | |||
| 221 | } | |||
| 222 | ||||
| 223 | /* Converts an S4 result (a column) into an xmmsv values */ | |||
| 224 | static void * | |||
| 225 | result_to_xmmsv (xmmsv_t *ret, gint32 id, const s4_result_t *res, | |||
| 226 | xmms_fetch_spec_t *spec) | |||
| 227 | { | |||
| 228 | static xmmsv_t * (*aggregate_functions[AGGREGATE_END])(xmmsv_t *c, gint i, const gchar *s) = { | |||
| 229 | aggregate_first, | |||
| 230 | aggregate_sum, | |||
| 231 | aggregate_max, | |||
| 232 | aggregate_min, | |||
| 233 | aggregate_set, | |||
| 234 | aggregate_list, | |||
| 235 | aggregate_random, | |||
| 236 | aggregate_average | |||
| 237 | }; | |||
| 238 | const s4_val_t *val; | |||
| 239 | xmmsv_t *dict, *current; | |||
| 240 | const gchar *str_value, *key = NULL((void*)0); | |||
| 241 | gint32 i, int_value; | |||
| ||||
| 242 | xmmsv_t *newval; | |||
| 243 | ||||
| 244 | g_return_val_if_fail (spec->data.metadata.get_size > 0, ret)do{ if (spec->data.metadata.get_size > 0) { } else { g_return_if_fail_warning ("core", ((const char*) (__func__)), "spec->data.metadata.get_size > 0" ); return (ret); }; }while (0); | |||
| 245 | g_return_val_if_fail (spec->data.metadata.get_size <= METADATA_END, ret)do{ if (spec->data.metadata.get_size <= METADATA_END) { } else { g_return_if_fail_warning ("core", ((const char*) (__func__ )), "spec->data.metadata.get_size <= METADATA_END"); return (ret); }; }while (0); | |||
| 246 | g_return_val_if_fail (spec->data.metadata.aggr_func >= 0, ret)do{ if (spec->data.metadata.aggr_func >= 0) { } else { g_return_if_fail_warning ("core", ((const char*) (__func__)), "spec->data.metadata.aggr_func >= 0" ); return (ret); }; }while (0); | |||
| 247 | g_return_val_if_fail (spec->data.metadata.aggr_func < AGGREGATE_END, ret)do{ if (spec->data.metadata.aggr_func < AGGREGATE_END) { } else { g_return_if_fail_warning ("core", ((const char*) (__func__ )), "spec->data.metadata.aggr_func < AGGREGATE_END"); return (ret); }; }while (0); | |||
| 248 | ||||
| 249 | /* Loop through all the values the column has */ | |||
| 250 | while (res != NULL((void*)0)) { | |||
| 251 | dict = ret; | |||
| 252 | current = ret; | |||
| 253 | ||||
| 254 | /* Loop through the list of what to get ("key", "source", ..) */ | |||
| 255 | for (i = 0; i < spec->data.metadata.get_size; i++) { | |||
| 256 | str_value = NULL((void*)0); | |||
| 257 | int_value = 0; | |||
| 258 | ||||
| 259 | /* Fill str_value with the correct value if it is a string | |||
| 260 | * or int_value if it is an integer | |||
| 261 | */ | |||
| 262 | switch (spec->data.metadata.get[i]) { | |||
| 263 | case METADATA_KEY: | |||
| 264 | str_value = s4_result_get_key (res); | |||
| 265 | break; | |||
| 266 | case METADATA_SOURCE: | |||
| 267 | str_value = s4_result_get_src (res); | |||
| 268 | if (str_value == NULL((void*)0)) | |||
| 269 | str_value = "server"; | |||
| 270 | break; | |||
| 271 | case METADATA_ID: | |||
| 272 | int_value = id; | |||
| 273 | break; | |||
| 274 | case METADATA_VALUE: | |||
| 275 | val = s4_result_get_val (res); | |||
| 276 | ||||
| 277 | if (!s4_val_get_int (val, &int_value)) { | |||
| 278 | s4_val_get_str (val, &str_value); | |||
| 279 | } | |||
| 280 | break; | |||
| 281 | default: | |||
| 282 | g_assert_not_reached ()do { g_assertion_message_expr ("core", "../src/xmms/medialib_query_result.c" , 282, ((const char*) (__func__)), ((void*)0)); } while (0); | |||
| 283 | } | |||
| 284 | ||||
| 285 | /* If this is not the last property to get we use this property | |||
| 286 | * as a key in a dict | |||
| 287 | */ | |||
| 288 | if (i < (spec->data.metadata.get_size - 1)) { | |||
| 289 | /* Convert integers to strings */ | |||
| 290 | if (str_value == NULL((void*)0)) { | |||
| 291 | /* Big enough to hold 2^32 with minus sign */ | |||
| 292 | gchar buf[12]; | |||
| 293 | g_sprintf (buf, "%i", int_value); | |||
| 294 | key = buf; | |||
| 295 | } else { | |||
| 296 | key = str_value; | |||
| 297 | } | |||
| 298 | ||||
| 299 | /* Make sure the root dict exists */ | |||
| 300 | if (dict == NULL((void*)0)) { | |||
| 301 | ret = dict = xmmsv_new_dict (); | |||
| 302 | } | |||
| 303 | ||||
| 304 | /* If this dict contains dicts we have to create a new | |||
| 305 | * dict if one does not exists for the key yet | |||
| 306 | */ | |||
| 307 | if (!xmmsv_dict_get (dict, key, ¤t)) | |||
| 308 | current = NULL((void*)0); | |||
| 309 | ||||
| 310 | if (i < (spec->data.metadata.get_size - 2)) { | |||
| 311 | if (current == NULL((void*)0)) { | |||
| 312 | current = xmmsv_new_dict (); | |||
| 313 | xmmsv_dict_set (dict, key, current); | |||
| 314 | xmmsv_unref (current); | |||
| 315 | } | |||
| 316 | dict = current; | |||
| 317 | } | |||
| 318 | } | |||
| 319 | } | |||
| 320 | ||||
| 321 | newval = aggregate_functions[spec->data.metadata.aggr_func](current, int_value, str_value); | |||
| ||||
| 322 | ||||
| 323 | /* Update the previous dict (if there is one) */ | |||
| 324 | if (newval != current) { | |||
| 325 | if (i > 1) { | |||
| 326 | xmmsv_dict_set (dict, key, newval); | |||
| 327 | xmmsv_unref (newval); | |||
| 328 | } else { | |||
| 329 | ret = newval; | |||
| 330 | if (current != NULL((void*)0)) { | |||
| 331 | xmmsv_unref (current); | |||
| 332 | } | |||
| 333 | } | |||
| 334 | } | |||
| 335 | ||||
| 336 | res = s4_result_next (res); | |||
| 337 | } | |||
| 338 | ||||
| 339 | return ret; | |||
| 340 | } | |||
| 341 | ||||
| 342 | /* Converts the temporary value returned by result_to_xmmsv into the real value */ | |||
| 343 | static xmmsv_t * | |||
| 344 | aggregate_data (xmmsv_t *value, aggregate_function_t aggr_func) | |||
| 345 | { | |||
| 346 | const random_data_t *random_data; | |||
| 347 | const avg_data_t *avg_data; | |||
| 348 | const set_data_t *set_data; | |||
| 349 | gconstpointer data; | |||
| 350 | xmmsv_t *ret; | |||
| 351 | guint len; | |||
| 352 | ||||
| 353 | ret = NULL((void*)0); | |||
| 354 | data = NULL((void*)0); | |||
| 355 | ||||
| 356 | if (value != NULL((void*)0) && xmmsv_is_type (value, XMMSV_TYPE_BIN)) | |||
| 357 | xmmsv_get_bin (value, (const guchar **) &data, &len); | |||
| 358 | ||||
| 359 | switch (aggr_func) { | |||
| 360 | case AGGREGATE_FIRST: | |||
| 361 | case AGGREGATE_MIN: | |||
| 362 | case AGGREGATE_MAX: | |||
| 363 | case AGGREGATE_SUM: | |||
| 364 | if (value != NULL((void*)0)) { | |||
| 365 | ret = xmmsv_ref (value); | |||
| 366 | } else { | |||
| 367 | ret = xmmsv_new_none (); | |||
| 368 | } | |||
| 369 | break; | |||
| 370 | case AGGREGATE_LIST: | |||
| 371 | if (value != NULL((void*)0)) { | |||
| 372 | ret = xmmsv_ref (value); | |||
| 373 | } else { | |||
| 374 | ret = xmmsv_new_list (); | |||
| 375 | } | |||
| 376 | break; | |||
| 377 | case AGGREGATE_RANDOM: | |||
| 378 | random_data = data; | |||
| 379 | if (random_data != NULL((void*)0)) { | |||
| 380 | ret = random_data->data; | |||
| 381 | } else { | |||
| 382 | ret = xmmsv_new_none (); | |||
| 383 | } | |||
| 384 | break; | |||
| 385 | case AGGREGATE_SET: | |||
| 386 | set_data = data; | |||
| 387 | if (set_data != NULL((void*)0)) { | |||
| 388 | g_hash_table_destroy (set_data->ht); | |||
| 389 | ret = set_data->list; | |||
| 390 | } else { | |||
| 391 | ret = xmmsv_new_list (); | |||
| 392 | } | |||
| 393 | break; | |||
| 394 | case AGGREGATE_AVG: | |||
| 395 | avg_data = data; | |||
| 396 | if (avg_data != NULL((void*)0)) { | |||
| 397 | ret = xmmsv_new_float (avg_data->n ? avg_data->sum * 1.0 / avg_data->n : 0); | |||
| 398 | } else { | |||
| 399 | ret = xmmsv_new_none (); | |||
| 400 | } | |||
| 401 | break; | |||
| 402 | default: | |||
| 403 | g_assert_not_reached ()do { g_assertion_message_expr ("core", "../src/xmms/medialib_query_result.c" , 403, ((const char*) (__func__)), ((void*)0)); } while (0); | |||
| 404 | } | |||
| 405 | ||||
| 406 | if (value != NULL((void*)0)) { | |||
| 407 | xmmsv_unref (value); | |||
| 408 | } | |||
| 409 | ||||
| 410 | return ret; | |||
| 411 | } | |||
| 412 | ||||
| 413 | /* Applies an aggregation function to the leafs in an xmmsv dict tree */ | |||
| 414 | static xmmsv_t * | |||
| 415 | aggregate_result (xmmsv_t *val, gint depth, aggregate_function_t aggr_func) | |||
| 416 | { | |||
| 417 | xmmsv_dict_iter_t *it; | |||
| 418 | ||||
| 419 | if (depth == 0) { | |||
| 420 | return aggregate_data (val, aggr_func); | |||
| 421 | } | |||
| 422 | ||||
| 423 | if (val == NULL((void*)0) && depth > 0) { | |||
| 424 | return xmmsv_new_dict(); | |||
| 425 | } | |||
| 426 | ||||
| 427 | /* If it's a dict we call this function recursively on all its values */ | |||
| 428 | xmmsv_get_dict_iter (val, &it); | |||
| 429 | ||||
| 430 | while (xmmsv_dict_iter_valid (it)) { | |||
| 431 | xmmsv_t *entry; | |||
| 432 | ||||
| 433 | xmmsv_dict_iter_pair (it, NULL((void*)0), &entry); | |||
| 434 | xmmsv_ref (entry); | |||
| 435 | ||||
| 436 | entry = aggregate_result (entry, depth - 1, aggr_func); | |||
| 437 | xmmsv_dict_iter_set (it, entry); | |||
| 438 | xmmsv_unref (entry); | |||
| 439 | ||||
| 440 | xmmsv_dict_iter_next (it); | |||
| 441 | } | |||
| 442 | ||||
| 443 | return val; | |||
| 444 | } | |||
| 445 | ||||
| 446 | /* Converts an S4 resultset to an xmmsv using the fetch specification */ | |||
| 447 | static xmmsv_t * | |||
| 448 | metadata_to_xmmsv (s4_resultset_t *set, xmms_fetch_spec_t *spec) | |||
| 449 | { | |||
| 450 | const s4_resultrow_t *row; | |||
| 451 | xmmsv_t *ret = NULL((void*)0); | |||
| 452 | gint i; | |||
| 453 | ||||
| 454 | /* Loop over the rows in the resultset */ | |||
| 455 | for (i = 0; s4_resultset_get_row (set, i, &row); i++) { | |||
| 456 | gint32 id, j; | |||
| 457 | ||||
| 458 | s4_val_get_int (s4_result_get_val (s4_resultset_get_result (set, i, 0)), &id); | |||
| 459 | for (j = 0; j < spec->data.metadata.col_count; j++) { | |||
| 460 | const s4_result_t *res; | |||
| 461 | ||||
| 462 | if (s4_resultrow_get_col (row, spec->data.metadata.cols[j], &res)) { | |||
| 463 | ret = result_to_xmmsv (ret, id, res, spec); | |||
| 464 | } | |||
| 465 | } | |||
| 466 | } | |||
| 467 | ||||
| 468 | return aggregate_result (ret, spec->data.metadata.get_size - 1, | |||
| 469 | spec->data.metadata.aggr_func); | |||
| 470 | } | |||
| 471 | ||||
| 472 | ||||
| 473 | /* Divides an S4 set into a list of smaller sets with | |||
| 474 | * the same values for the cluster attributes | |||
| 475 | */ | |||
| 476 | static void | |||
| 477 | cluster_set (s4_resultset_t *set, xmms_fetch_spec_t *spec, | |||
| 478 | GHashTable *table, GList **list) | |||
| 479 | { | |||
| 480 | const s4_resultrow_t *row; | |||
| 481 | gint position; | |||
| 482 | ||||
| 483 | /* Run through all the rows in the result set. | |||
| 484 | * Uses a hash table to find the correct cluster to put the row in | |||
| 485 | */ | |||
| 486 | for (position = 0; s4_resultset_get_row (set, position, &row); position++) { | |||
| 487 | s4_resultset_t *cluster; | |||
| 488 | const s4_result_t *res; | |||
| 489 | const gchar *value = spec->data.cluster.fallback; | |||
| 490 | gchar buf[12]; | |||
| 491 | ||||
| 492 | if (spec->data.cluster.type == CLUSTER_BY_POSITION) { | |||
| 493 | g_snprintf (buf, sizeof (buf), "%i", position); | |||
| 494 | value = buf; | |||
| 495 | } else if (s4_resultrow_get_col (row, spec->data.cluster.column, &res)) { | |||
| 496 | const s4_val_t *val = s4_result_get_val (res); | |||
| 497 | if (!s4_val_get_str (val, &value)) { | |||
| 498 | gint32 ival; | |||
| 499 | s4_val_get_int (val, &ival); | |||
| 500 | g_snprintf (buf, sizeof (buf), "%i", ival); | |||
| 501 | value = buf; | |||
| 502 | } | |||
| 503 | } | |||
| 504 | ||||
| 505 | if (value == NULL((void*)0)) { | |||
| 506 | /* value not found, and no fallback provided */ | |||
| 507 | continue; | |||
| 508 | } | |||
| 509 | ||||
| 510 | cluster = g_hash_table_lookup (table, value); | |||
| 511 | if (cluster == NULL((void*)0)) { | |||
| 512 | cluster = s4_resultset_create (s4_resultset_get_colcount (set)); | |||
| 513 | g_hash_table_insert (table, g_strdup (value), cluster); | |||
| 514 | *list = g_list_prepend (*list, cluster); | |||
| 515 | } | |||
| 516 | s4_resultset_add_row (cluster, row); | |||
| 517 | } | |||
| 518 | } | |||
| 519 | ||||
| 520 | static GList * | |||
| 521 | cluster_list (s4_resultset_t *set, xmms_fetch_spec_t *spec) | |||
| 522 | { | |||
| 523 | GHashTable *table; | |||
| 524 | GList *list = NULL((void*)0); | |||
| 525 | ||||
| 526 | table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL((void*)0)); | |||
| 527 | cluster_set (set, spec, table, &list); | |||
| 528 | g_hash_table_destroy (table); | |||
| 529 | ||||
| 530 | return g_list_reverse (list); | |||
| 531 | } | |||
| 532 | ||||
| 533 | static GHashTable * | |||
| 534 | cluster_dict (s4_resultset_t *set, xmms_fetch_spec_t *spec) | |||
| 535 | { | |||
| 536 | GHashTable *table; | |||
| 537 | GList *list = NULL((void*)0); | |||
| 538 | ||||
| 539 | table = g_hash_table_new_full (g_str_hash, g_str_equal, | |||
| 540 | g_free, (GDestroyNotify) s4_resultset_free); | |||
| 541 | ||||
| 542 | cluster_set (set, spec, table, &list); | |||
| 543 | g_list_free (list); | |||
| 544 | ||||
| 545 | return table; | |||
| 546 | } | |||
| 547 | ||||
| 548 | static xmmsv_t * | |||
| 549 | convert_ghashtable_to_xmmsv (GHashTable *table, xmms_fetch_spec_t *spec) | |||
| 550 | { | |||
| 551 | GHashTableIter iter; | |||
| 552 | s4_resultset_t *value; | |||
| 553 | const gchar *key; | |||
| 554 | xmmsv_t *ret; | |||
| 555 | ||||
| 556 | g_hash_table_iter_init (&iter, table); | |||
| 557 | ||||
| 558 | ret = xmmsv_new_dict (); | |||
| 559 | ||||
| 560 | while (g_hash_table_iter_next (&iter, (gpointer *) &key, (gpointer *) &value)) { | |||
| 561 | xmmsv_t *converted; | |||
| 562 | ||||
| 563 | if (value == NULL((void*)0)) { | |||
| 564 | continue; | |||
| 565 | } | |||
| 566 | ||||
| 567 | converted = xmms_medialib_query_to_xmmsv (value, spec); | |||
| 568 | xmmsv_dict_set (ret, key, converted); | |||
| 569 | xmmsv_unref (converted); | |||
| 570 | } | |||
| 571 | ||||
| 572 | if (xmmsv_dict_get_size (ret) == 0) { | |||
| 573 | xmmsv_unref (ret); | |||
| 574 | ret = NULL((void*)0); | |||
| 575 | } | |||
| 576 | ||||
| 577 | return ret; | |||
| 578 | } | |||
| 579 | ||||
| 580 | /* Converts an S4 resultset into an xmmsv_t, based on the fetch specification */ | |||
| 581 | xmmsv_t * | |||
| 582 | xmms_medialib_query_to_xmmsv (s4_resultset_t *set, xmms_fetch_spec_t *spec) | |||
| 583 | { | |||
| 584 | GHashTable *set_table; | |||
| 585 | GList *sets; | |||
| 586 | xmmsv_t *val, *ret = NULL((void*)0); | |||
| 587 | gint i; | |||
| 588 | ||||
| 589 | switch (spec->type) { | |||
| 590 | case FETCH_COUNT: | |||
| 591 | ret = xmmsv_new_int (s4_resultset_get_rowcount (set)); | |||
| 592 | break; | |||
| 593 | case FETCH_METADATA: | |||
| 594 | ret = metadata_to_xmmsv (set, spec); | |||
| 595 | break; | |||
| 596 | case FETCH_ORGANIZE: | |||
| 597 | ret = xmmsv_new_dict (); | |||
| 598 | ||||
| 599 | for (i = 0; i < spec->data.organize.count; i++) { | |||
| 600 | val = xmms_medialib_query_to_xmmsv (set, spec->data.organize.data[i]); | |||
| 601 | if (val != NULL((void*)0)) { | |||
| 602 | xmmsv_dict_set (ret, spec->data.organize.keys[i], val); | |||
| 603 | xmmsv_unref (val); | |||
| 604 | } | |||
| 605 | } | |||
| 606 | break; | |||
| 607 | case FETCH_CLUSTER_LIST: | |||
| 608 | sets = cluster_list (set, spec); | |||
| 609 | ret = xmmsv_new_list (); | |||
| 610 | for (; sets != NULL((void*)0); sets = g_list_delete_link (sets, sets)) { | |||
| 611 | set = sets->data; | |||
| 612 | ||||
| 613 | val = xmms_medialib_query_to_xmmsv (set, spec->data.cluster.data); | |||
| 614 | if (val != NULL((void*)0)) { | |||
| 615 | xmmsv_list_append (ret, val); | |||
| 616 | xmmsv_unref (val); | |||
| 617 | } | |||
| 618 | s4_resultset_free (set); | |||
| 619 | } | |||
| 620 | break; | |||
| 621 | case FETCH_CLUSTER_DICT: | |||
| 622 | set_table = cluster_dict (set, spec); | |||
| 623 | ret = convert_ghashtable_to_xmmsv (set_table, spec->data.cluster.data); | |||
| 624 | ||||
| 625 | g_hash_table_destroy (set_table); | |||
| 626 | break; | |||
| 627 | default: | |||
| 628 | g_assert_not_reached ()do { g_assertion_message_expr ("core", "../src/xmms/medialib_query_result.c" , 628, ((const char*) (__func__)), ((void*)0)); } while (0); | |||
| 629 | } | |||
| 630 | ||||
| 631 | return ret; | |||
| 632 | } |