00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "midgard/midgard_collector.h"
00020 #include "midgard/types.h"
00021 #include "midgard/query_builder.h"
00022 #include "midgard/midgard_object.h"
00023 #include "midgard_core_query_builder.h"
00024 #include "midgard_mysql.h"
00025
00026 struct _MidgardCollectorPrivate{
00027 const gchar *typename;
00028 GType type;
00029 const gchar *domain;
00030 GValue *domain_value;
00031 const gchar *keyname;
00032 GValue *keyname_value;
00033 MidgardQueryBuilder *builder;
00034 MidgardObjectClass *klass;
00035 GList *values;
00036 GHashTable *keyshash;
00037 };
00038
00039
00040
00041
00042
00043 static const gchar *_collector_find_class_property(
00044 MidgardCollector *self, const gchar *propname)
00045 {
00046 if(g_str_equal(propname, "guid"))
00047 return g_strdup_printf(
00048 "%s.guid",
00049 midgard_object_class_get_table(
00050 self->private->klass));
00051
00052 GParamSpec *pspec = g_object_class_find_property(
00053 G_OBJECT_CLASS(self->private->klass), propname);
00054 if(!pspec){
00055 g_warning("Invalid property name '%s' for '%s' class",
00056 propname,
00057 self->private->typename);
00058 return NULL;
00059 }
00060 return g_strdup(g_param_spec_get_nick(pspec));
00061 }
00062
00063 static void _unset_subkey_value(gpointer value)
00064 {
00065 g_value_unset((GValue *)value);
00066 g_free(value);
00067 }
00068
00069
00070 MidgardCollector *midgard_collector_new(
00071 MidgardConnection *mgd, const gchar *typename,
00072 const gchar *domain, GValue *value)
00073 {
00074 g_assert(mgd);
00075 g_assert(typename);
00076 g_assert(domain);
00077 g_assert(value);
00078
00079 MidgardCollector *self =
00080 (MidgardCollector *)g_object_new(MIDGARD_TYPE_COLLECTOR, NULL);
00081
00082 self->private->klass =
00083 MIDGARD_OBJECT_GET_CLASS_BY_NAME(typename);
00084
00085 const gchar *nick =
00086 _collector_find_class_property(self, domain);
00087 if(!nick) {
00088 if(value){
00089 g_value_unset(value);
00090 g_free(value);
00091 }
00092 return NULL;
00093 }
00094 g_free((gchar *)nick);
00095
00096 self->private->typename = (const gchar *) g_strdup(typename);
00097 self->private->type = g_type_from_name(typename);
00098 self->private->domain = (const gchar*) g_strdup(domain);
00099 self->private->domain_value = value;
00100 self->private->keyname = NULL;
00101 self->private->keyname_value = NULL;
00102
00103
00104 self->private->builder = midgard_query_builder_new(
00105 mgd->mgd, typename);
00106 midgard_query_builder_add_constraint(self->private->builder,
00107 domain,
00108 "=", value);
00109 g_value_unset(value);
00110 g_free(value);
00111
00112 self->private->values = NULL;
00113 self->private->keyshash = g_hash_table_new(NULL, NULL);
00114
00115 return self;
00116 }
00117
00118
00119 gboolean midgard_collector_set_key_property(
00120 MidgardCollector *self, const gchar *key, GValue *value)
00121 {
00122 g_assert(self != NULL);
00123
00124 const gchar *nick =
00125 _collector_find_class_property(self, key);
00126 if(!nick)
00127 return FALSE;
00128
00129 gchar *sql_field = g_strconcat(nick, " AS midgard_collector_key", NULL);
00130 g_free((gchar *)nick);
00131 self->private->values = g_list_prepend(self->private->values,
00132 sql_field);
00133
00134 self->private->keyname = (const gchar*) g_strdup(key);
00135
00136
00137 if(value){
00138 midgard_query_builder_add_constraint(
00139 self->private->builder,
00140 key,
00141 "=", value);
00142 self->private->keyname_value = value;
00143 }
00144
00145 return TRUE;
00146 }
00147
00148
00149 gboolean midgard_collector_add_value_property(
00150 MidgardCollector *self, const gchar *value)
00151 {
00152 g_assert(self);
00153
00154 if(!self->private->keyname){
00155 g_warning("Collector's key is not set. Call set_key_property method");
00156 return FALSE;
00157 }
00158
00159 const gchar *nick =
00160 _collector_find_class_property(self, value);
00161 if(!nick)
00162 return FALSE;
00163
00164 gchar *sql_field = g_strconcat(nick, " AS ", value, NULL);
00165 g_free((gchar *)nick);
00166 self->private->values = g_list_prepend(self->private->values,
00167 sql_field);
00168
00169 return TRUE;
00170 }
00171
00172
00173 gboolean midgard_collector_set(
00174 MidgardCollector *collector,
00175 const gchar *key, const gchar *subkey, GValue *value)
00176 {
00177 g_assert(collector);
00178 GQuark keyquark = g_quark_from_string(key);
00179
00180 if(subkey == NULL){
00181 g_hash_table_insert(collector->private->keyshash,
00182 (gpointer)keyquark,
00183 NULL);
00184 return TRUE;
00185 }
00186
00187 const gchar *nick =
00188 _collector_find_class_property(collector, subkey);
00189 if(!nick)
00190 return FALSE;
00191 g_free((gchar *)nick);
00192
00193 GQuark subkeyquark = g_quark_from_string(subkey);
00194 GHashTable *valueshash =
00195 g_hash_table_lookup(collector->private->keyshash, (gpointer)keyquark);
00196
00197 if(valueshash == NULL){
00198 valueshash = g_hash_table_new_full(NULL, NULL,
00199 NULL, _unset_subkey_value);
00200 }
00201
00202 g_hash_table_insert(valueshash, (gpointer)subkeyquark, (gpointer)value);
00203 g_hash_table_insert(collector->private->keyshash,
00204 (gpointer)keyquark,
00205 valueshash);
00206 return TRUE;
00207 }
00208
00209
00210 GHashTable *midgard_collector_get(
00211 MidgardCollector *self, const gchar *key)
00212 {
00213 g_assert(self);
00214
00215 if(!self->private->keyname){
00216 g_warning("Collector's key is not set. Call set_key_property method");
00217 return FALSE;
00218 }
00219
00220 return g_hash_table_lookup(self->private->keyshash,
00221 (gpointer)g_quark_from_string(key));
00222 }
00223
00224
00225 GValue *midgard_collector_get_subkey(
00226 MidgardCollector *self, const gchar *key, const gchar *subkey)
00227 {
00228 g_assert(self);
00229
00230 const gchar *nick;
00231 nick = _collector_find_class_property(self, subkey);
00232 if(!nick)
00233 return NULL;
00234
00235 g_free((gchar *)nick);
00236
00237 if(self->private->keyshash == NULL){
00238 g_warning("Collector's key set with NULL value");
00239 return NULL;
00240 }
00241
00242 GHashTable *valueshash =
00243 g_hash_table_lookup(self->private->keyshash,
00244 (gpointer)g_quark_from_string(key));
00245
00246 if(!valueshash) {
00247 g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG,
00248 "midgard_collector: No subkeys associated with the given '%s' key",
00249 key);
00250 return NULL;
00251 }
00252
00253 GValue *value = g_hash_table_lookup(valueshash,
00254 (gpointer)g_quark_from_string(subkey));
00255
00256 return value;
00257 }
00258
00259 void _get_collection_keys(gpointer key, gpointer value,
00260 gpointer userdata)
00261 {
00262 GList **list = userdata;
00263 *list = g_list_prepend(*list,
00264 (gchar *)g_quark_to_string((GQuark) key));
00265 }
00266
00267 static void _merge_hashvalues(
00268 gpointer key, gpointer val, gpointer userdata)
00269 {
00270 GValue *value = (GValue *) val;
00271 GHashTable *hashvalues = (GHashTable *) userdata;
00272 GValue *new_value = g_new0(GValue, 1);
00273 g_value_init(new_value, G_VALUE_TYPE(value));
00274 g_value_copy(value, new_value);
00275
00276 g_hash_table_insert(hashvalues, key, (gpointer)new_value);
00277 }
00278
00279
00280 gboolean midgard_collector_merge(
00281 MidgardCollector *self, MidgardCollector *mc,
00282 gboolean overwrite)
00283 {
00284 g_assert(self);
00285 g_assert(mc);
00286
00287 if(!MIDGARD_COLLECTOR(mc)){
00288 g_warning("Second argument is not an instance of midgard_collector class!");
00289 return FALSE;
00290 }
00291
00292 guint i = 0;
00293 const gchar **keys =
00294 midgard_collector_list_keys(mc);
00295 GHashTable *self_hashvalues, *mc_hashvalues;
00296
00297 if(!keys) return FALSE;
00298
00299 while(keys[i] != NULL) {
00300
00301 self_hashvalues =
00302 midgard_collector_get(self, keys[i]);
00303 if((self_hashvalues && overwrite) ||
00304 (self_hashvalues == NULL)){
00305
00306 mc_hashvalues =
00307 midgard_collector_get(mc, keys[i]);
00308
00309 if(!self_hashvalues)
00310 self_hashvalues =
00311 g_hash_table_new_full(NULL, NULL,
00312 NULL, _unset_subkey_value);
00313 g_hash_table_foreach(mc_hashvalues,
00314 _merge_hashvalues, self_hashvalues);
00315 g_hash_table_insert(self->private->keyshash,
00316 (gpointer)g_quark_from_string(keys[i]),
00317 self_hashvalues);
00318 }
00319 i++;
00320 }
00321 g_free((gchar *)keys);
00322 return TRUE;
00323 }
00324
00325
00326 const gchar **midgard_collector_list_keys(
00327 MidgardCollector *self)
00328 {
00329 g_assert(self);
00330
00331 guint i = 0, hash_size = g_hash_table_size(self->private->keyshash);
00332 const gchar **keys = g_new(const gchar *, hash_size+1);
00333 GList *list = NULL;
00334
00335 g_hash_table_foreach(self->private->keyshash,
00336 _get_collection_keys, &list);
00337
00338 if(list) {
00339
00340 list = g_list_reverse(list);
00341 for(; list; list = list->next){
00342 keys[i] = list->data;
00343 i++;
00344 }
00345 keys[i] = NULL;
00346 g_list_free(list);
00347 return keys;
00348 }
00349
00350 g_free(keys);
00351 return NULL;
00352 }
00353
00354
00355 gboolean midgard_collector_remove_key(
00356 MidgardCollector *self, const gchar *key)
00357 {
00358 g_assert(self);
00359 g_assert(self);
00360
00361 GQuark keyquark = g_quark_from_string(key);
00362
00363 GHashTable *valueshash =
00364 g_hash_table_lookup(self->private->keyshash,
00365 (gpointer)keyquark);
00366 if(!valueshash)
00367 return FALSE;
00368
00369 g_hash_table_destroy(valueshash);
00370
00371 return g_hash_table_remove(self->private->keyshash,
00372 (gpointer)keyquark);
00373 }
00374
00375
00376 void midgard_collector_destroy(
00377 MidgardCollector *self)
00378 {
00379 g_assert(self);
00380 g_object_unref(self);
00381 }
00382
00383
00384
00385
00386 gboolean midgard_collector_add_constraint(
00387 MidgardCollector *self, const gchar *name,
00388 const gchar *op, const GValue *value)
00389 {
00390 g_assert(self);
00391 return MIDGARD_QUERY_BUILDER_GET_CLASS(
00392 self->private->builder)->add_constraint(
00393 self->private->builder, name,
00394 op, value);
00395 }
00396
00397 gboolean midgard_collector_begin_group(
00398 MidgardCollector *self, const gchar *type)
00399 {
00400 g_assert(self);
00401 return MIDGARD_QUERY_BUILDER_GET_CLASS(
00402 self->private->builder)->begin_group(
00403 self->private->builder, type);
00404 }
00405
00406 gboolean midgard_collector_end_group(
00407 MidgardCollector *self)
00408 {
00409 g_assert(self);
00410 return MIDGARD_QUERY_BUILDER_GET_CLASS(
00411 self->private->builder)->end_group(
00412 self->private->builder);
00413 }
00414
00415 gboolean midgard_collector_add_order(
00416 MidgardCollector *self,
00417 const gchar *name, const gchar *dir)
00418 {
00419 g_assert(self);
00420 return MIDGARD_QUERY_BUILDER_GET_CLASS(
00421 self->private->builder)->add_order(
00422 self->private->builder, name, dir);
00423 }
00424
00425 void midgard_collector_set_offset(
00426 MidgardCollector *self, guint offset)
00427 {
00428 g_assert(self);
00429 MIDGARD_QUERY_BUILDER_GET_CLASS(
00430 self->private->builder)->set_offset(
00431 self->private->builder, offset);
00432 }
00433
00434 void midgard_collector_set_limit(
00435 MidgardCollector *self, guint limit)
00436 {
00437 g_assert(self);
00438 MIDGARD_QUERY_BUILDER_GET_CLASS(
00439 self->private->builder)->set_limit(
00440 self->private->builder, limit);
00441 }
00442
00443 void midgard_collector_unset_languages(
00444 MidgardCollector *self)
00445 {
00446 g_assert(self);
00447 MIDGARD_QUERY_BUILDER_GET_CLASS(
00448 self->private->builder)->unset_languages(
00449 self->private->builder);
00450 }
00451
00452 void midgard_collector_count(
00453 MidgardCollector *self)
00454 {
00455 g_assert(self);
00456 return;
00457 }
00458
00459 gboolean midgard_collector_execute(
00460 MidgardCollector *self)
00461 {
00462 g_assert(self);
00463
00464 if(!self->private->keyname){
00465 g_warning("Collector's key is not set. Call set_key_property method");
00466 return FALSE;
00467 }
00468
00469 if(!self->private->values)
00470 return FALSE;
00471
00472 GList *list =
00473 g_list_reverse(self->private->values);
00474 GString *sgs = g_string_new("");
00475 guint i = 0;
00476 for( ; list; list = list->next){
00477 if(i > 0)
00478 g_string_append(sgs, ", ");
00479 g_string_append(sgs, list->data);
00480 i++;
00481 }
00482
00483 gchar *select = g_string_free(sgs, FALSE);
00484 gchar *sql = _midgard_core_qb_get_sql(
00485 self->private->builder, MQB_SELECT_FIELD,
00486 select);
00487
00488 g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "query=%s", sql);
00489 if(!sql)
00490 return FALSE;
00491
00492 gint sq = mysql_query(self->private->builder->mgd->msql->mysql, sql);
00493
00494 if (sq != 0) {
00495 g_warning("\n\nQUERY: \n %s \n\n FAILED: \n %s",
00496 sql,
00497 mysql_error(self->private->builder->mgd->msql->mysql));
00498 g_free(sql);
00499 return FALSE;
00500 }
00501 g_free(sql);
00502
00503 i = 0;
00504 guint ret_rows, ret_fields, j;
00505 MYSQL_ROW row;
00506 MYSQL_FIELD *field;
00507 MYSQL_RES *results = mysql_store_result(self->private->builder->mgd->msql->mysql);
00508 GParamSpec *pspec;
00509
00510
00511 if (!results)
00512 return FALSE;
00513
00514 if ((ret_rows = mysql_num_rows(results)) == 0) {
00515 mysql_free_result(results);
00516 return FALSE;
00517 }
00518
00519 for(i = 0; i < ret_rows; i++){
00520 row = mysql_fetch_row(results);
00521 ret_fields = mysql_num_fields(results);
00522
00523 for (j = 0; j < ret_fields; j++){
00524 field = mysql_fetch_field_direct(results, j);
00525
00526 if ((pspec = g_object_class_find_property(
00527 (GObjectClass *)self->private->klass,
00528 field->name)) != NULL) {
00529
00530 GValue *pval = g_new0(GValue, 1);
00531 g_value_init(pval, pspec->value_type);
00532 switch(pspec->value_type){
00533
00534 case G_TYPE_STRING:
00535 g_value_set_string(pval, (gchar *)row[j]);
00536 break;
00537
00538 case G_TYPE_UINT:
00539 g_value_set_uint(pval, atoi(row[j]));
00540 break;
00541
00542 case G_TYPE_INT:
00543 g_value_set_int(pval, atoi(row[j]));
00544 break;
00545
00546 case G_TYPE_FLOAT:
00547 g_value_set_float(pval, g_ascii_strtod(row[j], NULL));
00548 break;
00549
00550 case G_TYPE_BOOLEAN:
00551 g_value_set_boolean(pval, atoi(row[j]));
00552 break;
00553 }
00554 midgard_collector_set(self,
00555 (gchar *) row[0],
00556 field->name,
00557 pval);
00558
00559 } else if (ret_fields == 1){
00560
00561 midgard_collector_set(self,
00562 (gchar *) row[0],
00563 NULL,
00564 NULL);
00565 }
00566 }
00567 }
00568
00569 mysql_free_result(results);
00570 return TRUE;
00571 }
00572
00573
00574
00575 static void _midgard_collector_instance_init(
00576 GTypeInstance *instance, gpointer g_class)
00577 {
00578 MidgardCollector *self = (MidgardCollector *) instance;
00579 self->private = g_new(MidgardCollectorPrivate, 1);
00580
00581 self->private->domain = NULL;
00582 self->private->domain_value = NULL;
00583 self->private->typename = NULL;
00584 self->private->type = 0;
00585 self->private->klass = NULL;
00586 }
00587
00588 static gboolean _destroy_collector_hash(
00589 gpointer key, gpointer value, gpointer user_data)
00590 {
00591 GHashTable *valueshash = (GHashTable *) value;
00592 g_hash_table_destroy(valueshash);
00593
00594 return TRUE;
00595 }
00596
00597 static void _midgard_collector_finalize(GObject *object)
00598 {
00599 g_assert(object != NULL);
00600
00601 MidgardCollector *self = (MidgardCollector *) object;
00602
00603 if(self->private->keyshash)
00604 g_hash_table_foreach_remove(self->private->keyshash,
00605 _destroy_collector_hash,
00606 NULL);
00607
00608
00609 g_free((gchar *)self->private->typename);
00610 g_free((gchar *)self->private->domain);
00611 g_free((gchar *)self->private->keyname);
00612
00613 if(self->private->keyname_value) {
00614 g_value_unset(self->private->keyname_value);
00615 g_free(self->private->keyname_value);
00616 }
00617
00618 g_object_unref(self->private->builder);
00619
00620 GList *list = self->private->values;
00621 for( ; list; list = list->next){
00622 g_free(list->data);
00623 }
00624 g_list_free(list);
00625
00626 g_free(self->private);
00627 }
00628
00629 static void _midgard_collector_class_init(
00630 gpointer g_class, gpointer g_class_data)
00631 {
00632 GObjectClass *gobject_class = G_OBJECT_CLASS (g_class);
00633 MidgardCollectorClass *klass = MIDGARD_COLLECTOR_CLASS (g_class);
00634
00635 gobject_class->finalize = _midgard_collector_finalize;
00636 klass->set_key_property = midgard_collector_set_key_property;
00637 klass->add_value_property = midgard_collector_add_value_property;
00638 klass->set = midgard_collector_set;
00639 klass->get = midgard_collector_get;
00640 klass->get_subkey = midgard_collector_get_subkey;
00641 klass->merge = midgard_collector_merge;
00642 klass->list_keys = midgard_collector_list_keys;
00643 klass->remove_key = midgard_collector_remove_key;
00644 klass->destroy = midgard_collector_destroy;
00645 klass->add_constraint = midgard_collector_add_constraint;
00646 klass->begin_group = midgard_collector_begin_group;
00647 klass->end_group = midgard_collector_end_group;
00648 klass->add_order = midgard_collector_add_order;
00649 klass->set_offset = midgard_collector_set_offset;
00650 klass->set_limit = midgard_collector_set_limit;
00651 klass->unset_languages = midgard_collector_unset_languages;
00652 klass->count = midgard_collector_count;
00653 klass->execute = midgard_collector_execute;
00654 }
00655
00656 GType midgard_collector_get_type(void)
00657 {
00658 static GType type = 0;
00659 if (type == 0) {
00660 static const GTypeInfo info = {
00661 sizeof (MidgardCollectorClass),
00662 NULL,
00663 NULL,
00664 (GClassInitFunc) _midgard_collector_class_init,
00665 NULL,
00666 NULL,
00667 sizeof (MidgardCollector),
00668 0,
00669 (GInstanceInitFunc) _midgard_collector_instance_init
00670 };
00671 type = g_type_register_static (MIDGARD_TYPE_QUERY_BUILDER,
00672 "midgard_collector",
00673 &info, 0);
00674 }
00675 return type;
00676 }